@agimon-ai/doompi-hook 0.0.1-alpha.4 → 0.0.1-alpha.42

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 (52) hide show
  1. package/README.md +50 -13
  2. package/dist/adapters/hookDocuments.d.cts +2 -3
  3. package/dist/adapters/hookDocuments.d.cts.map +1 -1
  4. package/dist/adapters/hookDocuments.d.mts +2 -3
  5. package/dist/adapters/hookDocuments.d.mts.map +1 -1
  6. package/dist/adapters/hookRunner.d.cts +2 -3
  7. package/dist/adapters/hookRunner.d.cts.map +1 -1
  8. package/dist/adapters/hookRunner.d.mts +2 -3
  9. package/dist/adapters/hookRunner.d.mts.map +1 -1
  10. package/dist/adapters/pi/extension.cjs +1 -1
  11. package/dist/adapters/pi/extension.cjs.map +1 -1
  12. package/dist/adapters/pi/extension.d.cts +3 -3
  13. package/dist/adapters/pi/extension.d.cts.map +1 -1
  14. package/dist/adapters/pi/extension.d.mts +3 -3
  15. package/dist/adapters/pi/extension.d.mts.map +1 -1
  16. package/dist/adapters/pi/extension.mjs +1 -1
  17. package/dist/adapters/pi/extension.mjs.map +1 -1
  18. package/dist/adapters/telemetry/logSinkTelemetry.d.cts +2 -3
  19. package/dist/adapters/telemetry/logSinkTelemetry.d.cts.map +1 -1
  20. package/dist/adapters/telemetry/logSinkTelemetry.d.mts +2 -3
  21. package/dist/adapters/telemetry/logSinkTelemetry.d.mts.map +1 -1
  22. package/dist/services/hookDecisions.d.cts +7 -8
  23. package/dist/services/hookDecisions.d.cts.map +1 -1
  24. package/dist/services/hookDecisions.d.mts +7 -8
  25. package/dist/services/hookDecisions.d.mts.map +1 -1
  26. package/dist/services/hookPayload.d.cts +2 -3
  27. package/dist/services/hookPayload.d.cts.map +1 -1
  28. package/dist/services/hookPayload.d.mts +2 -3
  29. package/dist/services/hookPayload.d.mts.map +1 -1
  30. package/dist/services/hookRegistry.d.cts +4 -5
  31. package/dist/services/hookRegistry.d.cts.map +1 -1
  32. package/dist/services/hookRegistry.d.mts +4 -5
  33. package/dist/services/hookRegistry.d.mts.map +1 -1
  34. package/dist/services/pluginHooks.d.cts +1 -2
  35. package/dist/services/pluginHooks.d.cts.map +1 -1
  36. package/dist/services/pluginHooks.d.mts +1 -2
  37. package/dist/services/pluginHooks.d.mts.map +1 -1
  38. package/dist/services/toolNames.d.cts +2 -3
  39. package/dist/services/toolNames.d.cts.map +1 -1
  40. package/dist/services/toolNames.d.mts +2 -3
  41. package/dist/services/toolNames.d.mts.map +1 -1
  42. package/dist/types/hooks.d.cts +30 -31
  43. package/dist/types/hooks.d.cts.map +1 -1
  44. package/dist/types/hooks.d.mts +30 -31
  45. package/dist/types/hooks.d.mts.map +1 -1
  46. package/dist/types/telemetry.d.cts +6 -7
  47. package/dist/types/telemetry.d.cts.map +1 -1
  48. package/dist/types/telemetry.d.mts +6 -7
  49. package/dist/types/telemetry.d.mts.map +1 -1
  50. package/llms.txt +6 -2
  51. package/package.json +22 -13
  52. package/src/prompts/doompi-author-hook/SKILL.md +51 -0
package/README.md CHANGED
@@ -1,11 +1,21 @@
1
1
  # @agimon-ai/doompi-hook
2
2
 
3
- Claude-Code-compatible repository and plugin hooks for
3
+ Claude Code-compatible repository and plugin hooks for
4
4
  [DoomPi](https://www.npmjs.com/package/@agimon-ai/doompi) sessions.
5
5
 
6
6
  A **hook** is a shell command the repository runs at a point in the session: before a tool call,
7
7
  after one, at session start, when the agent settles, and at session end. Commands are declared in
8
- `.doom/hooks.yaml`, grouped so a mode can turn a whole family of them on or off:
8
+ `.doom/hooks.yaml`, grouped so a mode can turn a whole family of them on or off.
9
+
10
+ > **Alpha:** hook configuration and runtime contracts may change between releases.
11
+
12
+ ## Requirements
13
+
14
+ - Node.js 22.19.0 or newer
15
+ - Pi 0.85.0
16
+ - `/bin/bash`
17
+
18
+ Configure hooks in `.doom/hooks.yaml`:
9
19
 
10
20
  ```yaml
11
21
  # .doom/hooks.yaml
@@ -25,14 +35,15 @@ groups:
25
35
  skipInSubagent: true
26
36
  ```
27
37
 
28
- A group marked `core: true` always loads. Every other group loads only when the active mode selected
29
- it. The same document is read from the global `.doom` directory and from the repository, and a
30
- repository group replaces the global group of the same id outright.
38
+ A group marked `core: true` always loads. Every other group loads only when the active mode selects
39
+ it. The same document is read from the global `.doom` directory and from the repository. A
40
+ repository group replaces the global group of the same ID outright.
31
41
 
32
42
  ## Activation
33
43
 
34
- The DoomPi distribution activates this package by default. Layers only declare the `hookGroups`
35
- that should run in a major mode:
44
+ The distribution activates this package by default through the `default.packages` list written by
45
+ `doompi init` and `dpi init` in `.doom/modes.yaml`. Keep it there, or declare it in a selected layer,
46
+ for hooks to run. Layers only declare the `hookGroups` to select; they do not define the hook commands:
36
47
 
37
48
  ```yaml
38
49
  # .doom/modes.yaml
@@ -41,14 +52,16 @@ layers:
41
52
  hookGroups: [safety, workflow]
42
53
  ```
43
54
 
44
- A session with no selected `hookGroups` still runs groups marked `core: true`; other groups remain inactive.
55
+ A session with no selected `hookGroups` still runs groups marked `core: true`; other groups remain
56
+ inactive.
45
57
 
46
58
  ## What a hook sees and can say
47
59
 
48
60
  Each command is run through `/bin/bash -c` in the repository root, with the Claude Code payload for
49
- the event on stdin and `CLAUDE_PROJECT_DIR`, `CODEX_REPO_ROOT`, `ORIGINAL_REPO_PATH` and — for a
50
- hook declared by a plugin or a global config — `CLAUDE_PLUGIN_ROOT` in the environment. Tool names
51
- in the payload and in `matcher` are Claude names (`Bash`, `Write`), not Pi's.
61
+ the event on stdin. The environment includes `CLAUDE_PROJECT_DIR`, `CODEX_REPO_ROOT`, and
62
+ `ORIGINAL_REPO_PATH`. Every resolved hook also receives `CLAUDE_PLUGIN_ROOT`, set to the root that
63
+ declared its repository, personal, or plugin configuration. Tool names in the payload and in
64
+ `matcher` are Claude names (`Bash`, `Write`), not Pi's.
52
65
 
53
66
  The last stdout line that starts with `{` is read as the hook's decision:
54
67
 
@@ -70,14 +83,38 @@ indistinguishable from one that passed.
70
83
  expires, is sent `SIGTERM` and then `SIGKILL` two seconds later, so a stalled hook does not leave
71
84
  the processes it started behind.
72
85
 
73
- ## Installation
86
+ ## Help guidance
74
87
 
75
- DoomPi already includes this package. For standalone Pi installation:
88
+ While the Help minor mode is active, this package contributes `doompi-author-hook`. The prompt
89
+ covers `.doom/hooks.yaml`, group activation, commands, payloads, decisions, and verification, and
90
+ is withdrawn when the package or Help provider unloads.
91
+
92
+ ## Install
93
+
94
+ For standalone Pi installation:
76
95
 
77
96
  ```bash
78
97
  pi install npm:@agimon-ai/doompi-hook
79
98
  ```
80
99
 
100
+ ## Public API
101
+
102
+ ```ts
103
+ import { createBashHookRunner, hookExtension } from '@agimon-ai/doompi-hook';
104
+ import type { HookDecision, HookEventName } from '@agimon-ai/doompi-hook';
105
+ ```
106
+
107
+ ## Development
108
+
109
+ ```bash
110
+ pnpm build
111
+ pnpm typecheck
112
+ pnpm test
113
+ pnpm lint
114
+ ```
115
+
116
+ Maintained by [Agimon](https://agimon.ai/about).
117
+
81
118
  ## License
82
119
 
83
120
  MIT
@@ -1,7 +1,7 @@
1
1
  import { HookDocumentReader } from "../types/hooks.cjs";
2
2
  import { HookTelemetry } from "../types/telemetry.cjs";
3
3
  //#region src/adapters/hookDocuments.d.ts
4
- interface HookDocumentReaderOptions {
4
+ export interface HookDocumentReaderOptions {
5
5
  telemetry?: HookTelemetry;
6
6
  /** Where the global `.doom` directory lives. Defaults to the user's home. */
7
7
  homeDirectory?: string;
@@ -17,7 +17,6 @@ interface HookDocumentReaderOptions {
17
17
  * inside the same filesystem timestamp granularity. Both caches are keyed on
18
18
  * contents instead, so parsing — the expensive half — is what they skip.
19
19
  */
20
- declare function createHookDocumentReader(options?: HookDocumentReaderOptions): HookDocumentReader;
20
+ export declare function createHookDocumentReader(options?: HookDocumentReaderOptions): HookDocumentReader;
21
21
  //#endregion
22
- export { HookDocumentReaderOptions, createHookDocumentReader };
23
22
  //# sourceMappingURL=hookDocuments.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookDocuments.d.cts","names":[],"sources":["../../src/adapters/hookDocuments.ts"],"mappings":";;;UAsBiB;EACf,YAAY;;EAEZ;EACA,YAAY,qBAAqB;EACjC,QAAQ;;;;;;;;;;;iBAoBM,yBAAyB,UAAS,4BAAiC"}
1
+ {"version":3,"file":"hookDocuments.d.cts","names":[],"sources":["../../src/adapters/hookDocuments.ts"],"mappings":";;;iBAsBiB;EACf,YAAY;;EAEZ;EACA,YAAY,qBAAqB;EACjC,QAAQ;;;;;;;;;;;wBAoBM,yBAAyB,UAAS,4BAAiC"}
@@ -1,7 +1,7 @@
1
1
  import { HookDocumentReader } from "../types/hooks.mjs";
2
2
  import { HookTelemetry } from "../types/telemetry.mjs";
3
3
  //#region src/adapters/hookDocuments.d.ts
4
- interface HookDocumentReaderOptions {
4
+ export interface HookDocumentReaderOptions {
5
5
  telemetry?: HookTelemetry;
6
6
  /** Where the global `.doom` directory lives. Defaults to the user's home. */
7
7
  homeDirectory?: string;
@@ -17,7 +17,6 @@ interface HookDocumentReaderOptions {
17
17
  * inside the same filesystem timestamp granularity. Both caches are keyed on
18
18
  * contents instead, so parsing — the expensive half — is what they skip.
19
19
  */
20
- declare function createHookDocumentReader(options?: HookDocumentReaderOptions): HookDocumentReader;
20
+ export declare function createHookDocumentReader(options?: HookDocumentReaderOptions): HookDocumentReader;
21
21
  //#endregion
22
- export { HookDocumentReaderOptions, createHookDocumentReader };
23
22
  //# sourceMappingURL=hookDocuments.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookDocuments.d.mts","names":[],"sources":["../../src/adapters/hookDocuments.ts"],"mappings":";;;UAsBiB;EACf,YAAY;;EAEZ;EACA,YAAY,qBAAqB;EACjC,QAAQ;;;;;;;;;;;iBAoBM,yBAAyB,UAAS,4BAAiC"}
1
+ {"version":3,"file":"hookDocuments.d.mts","names":[],"sources":["../../src/adapters/hookDocuments.ts"],"mappings":";;;iBAsBiB;EACf,YAAY;;EAEZ;EACA,YAAY,qBAAqB;EACjC,QAAQ;;;;;;;;;;;wBAoBM,yBAAyB,UAAS,4BAAiC"}
@@ -2,7 +2,7 @@ import { HookRunner } from "../types/hooks.cjs";
2
2
  import { HookTelemetry } from "../types/telemetry.cjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region src/adapters/hookRunner.d.ts
5
- interface BashHookRunnerOptions {
5
+ export interface BashHookRunnerOptions {
6
6
  telemetry?: HookTelemetry;
7
7
  env?: NodeJS.ProcessEnv;
8
8
  platform?: NodeJS.Platform;
@@ -16,7 +16,6 @@ interface BashHookRunnerOptions {
16
16
  * group and terminated as one: a hook that starts a server and stalls should
17
17
  * not leave the server behind when the timeout fires.
18
18
  */
19
- declare function createBashHookRunner(options?: BashHookRunnerOptions): HookRunner;
19
+ export declare function createBashHookRunner(options?: BashHookRunnerOptions): HookRunner;
20
20
  //#endregion
21
- export { BashHookRunnerOptions, createBashHookRunner };
22
21
  //# sourceMappingURL=hookRunner.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookRunner.d.cts","names":[],"sources":["../../src/adapters/hookRunner.ts"],"mappings":";;;;UAsBiB;EACf,YAAY;EACZ,MAAM,OAAO;EACb,WAAW,OAAO;EAClB,eAAe;EACf,QAAQ;;;;;;;;;iBAcM,qBAAqB,UAAS,wBAA6B"}
1
+ {"version":3,"file":"hookRunner.d.cts","names":[],"sources":["../../src/adapters/hookRunner.ts"],"mappings":";;;;iBAsBiB;EACf,YAAY;EACZ,MAAM,OAAO;EACb,WAAW,OAAO;EAClB,eAAe;EACf,QAAQ;;;;;;;;;wBAcM,qBAAqB,UAAS,wBAA6B"}
@@ -2,7 +2,7 @@ import { HookRunner } from "../types/hooks.mjs";
2
2
  import { HookTelemetry } from "../types/telemetry.mjs";
3
3
  import { spawn } from "node:child_process";
4
4
  //#region src/adapters/hookRunner.d.ts
5
- interface BashHookRunnerOptions {
5
+ export interface BashHookRunnerOptions {
6
6
  telemetry?: HookTelemetry;
7
7
  env?: NodeJS.ProcessEnv;
8
8
  platform?: NodeJS.Platform;
@@ -16,7 +16,6 @@ interface BashHookRunnerOptions {
16
16
  * group and terminated as one: a hook that starts a server and stalls should
17
17
  * not leave the server behind when the timeout fires.
18
18
  */
19
- declare function createBashHookRunner(options?: BashHookRunnerOptions): HookRunner;
19
+ export declare function createBashHookRunner(options?: BashHookRunnerOptions): HookRunner;
20
20
  //#endregion
21
- export { BashHookRunnerOptions, createBashHookRunner };
22
21
  //# sourceMappingURL=hookRunner.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookRunner.d.mts","names":[],"sources":["../../src/adapters/hookRunner.ts"],"mappings":";;;;UAsBiB;EACf,YAAY;EACZ,MAAM,OAAO;EACb,WAAW,OAAO;EAClB,eAAe;EACf,QAAQ;;;;;;;;;iBAcM,qBAAqB,UAAS,wBAA6B"}
1
+ {"version":3,"file":"hookRunner.d.mts","names":[],"sources":["../../src/adapters/hookRunner.ts"],"mappings":";;;;iBAsBiB;EACf,YAAY;EACZ,MAAM,OAAO;EACb,WAAW,OAAO;EAClB,eAAe;EACf,QAAQ;;;;;;;;;wBAcM,qBAAqB,UAAS,wBAA6B"}
@@ -1,2 +1,2 @@
1
- const e=require("../hookDocuments.cjs"),t=require("../hookRunner.cjs"),n=require("../telemetry/logSinkTelemetry.cjs"),r=require("./hookHandlers.cjs");let i=require("@agimon-ai/doompi-extension-contracts/readiness"),a=require("@agimon-ai/doompi-extension-contracts/cordis-host"),o=require("@agimon-ai/doompi-extension-contracts/config"),s=require("@agimon-ai/doompi-config/piContext");const c=`@agimon-ai/doompi-hook`;function l(r,i){let a=i.telemetry,o=()=>a??=n.createHookTelemetry();return{config:()=>(0,s.requireDoomConfigContext)(r),runner:i.runner??t.createBashHookRunner({telemetry:o()}),documents:i.documents??e.createHookDocumentReader({telemetry:o()})}}function u(e,t){let n=l(e,t),r=!0,a=0,o;return{session:n,readiness:{start(t,n){let s=++a,l=()=>r&&s===a,u=(0,i.readDoomReadinessCoordinator)(e);if(!u)return n(new AbortController().signal,l);let d=o,f=(async()=>{d?.coordinator===u&&await d.operation.catch(()=>void 0),l()&&await u.start(c,`${t.sessionManager.getSessionId()}:${s}`,async e=>(await n(e,l),{value:void 0})).wait()})();f.catch(()=>void 0),o={sessionManager:t.sessionManager,coordinator:u,operation:f}},async wait(e){let t=o;if(t){if(t.sessionManager!==e.sessionManager)throw Error(`Hook readiness belongs to a stale Pi session.`);if(await t.operation,!r||t!==o)throw Error(`Hook readiness belongs to a stale extension generation.`)}}},isCurrent:()=>r,dispose(){r=!1,a+=1,o=void 0}}}function d(e,{pi:t,options:n}){let i;e.inject([o.DOOM_CONFIG_SERVICE],e=>{let t=u(e,n);i=t,e.effect(()=>()=>{t.dispose(),i===t&&(i=void 0)},`${c}/config-runtime`)}),e.effect(function*(){for(let e of r.registerHookHandlers(t,()=>i))yield e;yield()=>{i=void 0}},c);let a;t.on(`session_shutdown`,(e,t)=>{let n=i;if(n?.isCurrent())return a??=r.runSessionEndHooks(n.session,t),a})}async function f(e,t={}){let n=await(0,a.connectDoomCordisHost)(e,c),r=n.root.plugin(d,{pi:e,options:t});try{await r}catch(e){try{await r.dispose()}finally{await n.dispose()}throw e}let i;e.on(`session_shutdown`,()=>i??=(async()=>{try{await r.dispose()}finally{await n.dispose()}})())}exports.default=f,exports.hookExtension=f;
1
+ const e=require("../hookDocuments.cjs"),t=require("../hookRunner.cjs"),n=require("../telemetry/logSinkTelemetry.cjs"),r=require("./hookHandlers.cjs");let i=require("@agimon-ai/doompi-extension-contracts/readiness"),a=require("@agimon-ai/doompi-extension-contracts/cordis-host"),o=require("@agimon-ai/doompi-extension-contracts/config"),s=require("@agimon-ai/doompi-extension-contracts/help"),c=require("@agimon-ai/doompi-config/piContext");const l=`@agimon-ai/doompi-hook`;function u(r,i){let a=i.telemetry,o=()=>a??=n.createHookTelemetry();return{config:()=>(0,c.requireDoomConfigContext)(r),runner:i.runner??t.createBashHookRunner({telemetry:o()}),documents:i.documents??e.createHookDocumentReader({telemetry:o()})}}function d(e,t){let n=u(e,t),r=!0,a=0,o;return{session:n,readiness:{start(t,n){let s=++a,c=()=>r&&s===a,u=(0,i.readDoomReadinessCoordinator)(e);if(!u)return n(new AbortController().signal,c);let d=o,f=(async()=>{d?.coordinator===u&&await d.operation.catch(()=>void 0),c()&&await u.start(l,`${t.sessionManager.getSessionId()}:${s}`,async e=>(await n(e,c),{value:void 0})).wait()})();f.catch(()=>void 0),o={sessionManager:t.sessionManager,coordinator:u,operation:f}},async wait(e){let t=o;if(t){if(t.sessionManager!==e.sessionManager)throw Error(`Hook readiness belongs to a stale Pi session.`);if(await t.operation,!r||t!==o)throw Error(`Hook readiness belongs to a stale extension generation.`)}}},isCurrent:()=>r,dispose(){r=!1,a+=1,o=void 0}}}function f(e,{pi:t,options:n}){e.inject([s.DOOM_HELP_SERVICE],e=>{let t=(0,s.requireDoomHelpService)(e).register({source:l,moduleUrl:require("url").pathToFileURL(__filename).href,skills:[{name:`doompi-author-hook`,description:`Author DoomPi repository or plugin hooks. Use when creating or changing .doom/hooks.yaml, selecting hook groups from modes.yaml, writing hook commands, or adapting Claude Code hook payloads and decisions to DoomPi.`}]});return()=>t.dispose()});let i;e.inject([o.DOOM_CONFIG_SERVICE],e=>{let t=d(e,n);i=t,e.effect(()=>()=>{t.dispose(),i===t&&(i=void 0)},`${l}/config-runtime`)}),e.effect(function*(){for(let e of r.registerHookHandlers(t,()=>i))yield e;yield()=>{i=void 0}},l);let a;t.on(`session_shutdown`,(e,t)=>{let n=i;if(n?.isCurrent())return a??=r.runSessionEndHooks(n.session,t),a})}async function p(e,t={}){let n=await(0,a.connectDoomCordisHost)(e,l),r=n.root.plugin(f,{pi:e,options:t});try{await r}catch(e){try{await r.dispose()}finally{await n.dispose()}throw e}let i;e.on(`session_shutdown`,()=>i??=(async()=>{try{await r.dispose()}finally{await n.dispose()}})())}exports.default=p,exports.hookExtension=p;
2
2
  //# sourceMappingURL=extension.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.cjs","names":["createHookTelemetry","requireDoomConfigContext","createBashHookRunner","createHookDocumentReader","readDoomReadinessCoordinator","DOOM_CONFIG_SERVICE","registerHookHandlers","runSessionEndHooks","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import {\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_CONFIG_SERVICE } from '@agimon-ai/doompi-extension-contracts/config';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { HookDocumentReader, HookRunner } from '../../types/hooks.ts';\nimport type { HookTelemetry } from '../../types/telemetry.ts';\nimport { createHookDocumentReader } from '../hookDocuments.ts';\nimport { createBashHookRunner } from '../hookRunner.ts';\nimport { createHookTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport {\n type HookReadinessGate,\n type HookRuntime,\n type HookSession,\n registerHookHandlers,\n runSessionEndHooks,\n} from './hookHandlers.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-hook';\n\nexport interface HookExtensionOptions {\n telemetry?: HookTelemetry;\n runner?: HookRunner;\n documents?: HookDocumentReader;\n}\n\nfunction hookSession(cordis: Context, options: HookExtensionOptions): HookSession {\n // The log sink is only built if something actually reports to it, so a fully\n // stubbed session never touches the telemetry backend.\n let telemetry = options.telemetry;\n const requireTelemetry = (): HookTelemetry => (telemetry ??= createHookTelemetry());\n return {\n config: () => requireDoomConfigContext(cordis),\n runner: options.runner ?? createBashHookRunner({ telemetry: requireTelemetry() }),\n documents: options.documents ?? createHookDocumentReader({ telemetry: requireTelemetry() }),\n };\n}\n\ninterface HookPluginConfig {\n readonly pi: ExtensionAPI;\n readonly options: HookExtensionOptions;\n}\n\ninterface HookRuntimeBinding extends HookRuntime {\n dispose(): void;\n}\n\nfunction createHookRuntime(cordis: Context, options: HookExtensionOptions): HookRuntimeBinding {\n const session = hookSession(cordis, options);\n let active = true;\n let generation = 0;\n let readiness:\n | {\n readonly sessionManager: object;\n readonly coordinator: DoomReadinessCoordinator;\n readonly operation: Promise<void>;\n }\n | undefined;\n const readinessGate: HookReadinessGate = {\n start(context, operation) {\n const ownGeneration = ++generation;\n const isCurrent = (): boolean => active && ownGeneration === generation;\n const coordinator = readDoomReadinessCoordinator(cordis);\n if (!coordinator) return operation(new AbortController().signal, isCurrent);\n\n const previous = readiness;\n const readinessOperation = (async (): Promise<void> => {\n if (previous?.coordinator === coordinator) await previous.operation.catch(() => undefined);\n if (!isCurrent()) return;\n const handle = coordinator.start(\n PACKAGE_SOURCE,\n `${context.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await operation(signal, isCurrent);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void readinessOperation.catch(() => undefined);\n readiness = {\n sessionManager: context.sessionManager,\n coordinator,\n operation: readinessOperation,\n };\n return undefined;\n },\n async wait(context: ExtensionContext): Promise<void> {\n const current = readiness;\n if (!current) return;\n if (current.sessionManager !== context.sessionManager) {\n throw new Error('Hook readiness belongs to a stale Pi session.');\n }\n await current.operation;\n if (!active || current !== readiness) {\n throw new Error('Hook readiness belongs to a stale extension generation.');\n }\n },\n };\n return {\n session,\n readiness: readinessGate,\n isCurrent: () => active,\n dispose() {\n active = false;\n generation += 1;\n readiness = undefined;\n },\n };\n}\n\nfunction hookPlugin(cordis: Context, { pi, options }: HookPluginConfig): void {\n let runtime: HookRuntimeBinding | undefined;\n cordis.inject([DOOM_CONFIG_SERVICE], (configContext) => {\n const binding = createHookRuntime(configContext, options);\n runtime = binding;\n configContext.effect(\n () => () => {\n binding.dispose();\n if (runtime === binding) runtime = undefined;\n },\n `${PACKAGE_SOURCE}/config-runtime`,\n );\n });\n\n cordis.effect(function* () {\n for (const disposeRegistration of registerHookHandlers(pi, () => runtime)) yield disposeRegistration;\n yield () => {\n runtime = undefined;\n };\n }, PACKAGE_SOURCE);\n\n let shutdown: Promise<void> | undefined;\n pi.on('session_shutdown', (_event, ctx) => {\n const current = runtime;\n if (!current?.isCurrent()) return undefined;\n shutdown ??= runSessionEndHooks(current.session, ctx);\n return shutdown;\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function hookExtension(pi: ExtensionAPI, options: HookExtensionOptions = {}): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(hookPlugin, { pi, options });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nexport default hookExtension;\n"],"mappings":"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"}
1
+ {"version":3,"file":"extension.cjs","names":["createHookTelemetry","requireDoomConfigContext","createBashHookRunner","createHookDocumentReader","readDoomReadinessCoordinator","DOOM_HELP_SERVICE","requireDoomHelpService","DOOM_CONFIG_SERVICE","registerHookHandlers","runSessionEndHooks","connectDoomCordisHost"],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import {\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_CONFIG_SERVICE } from '@agimon-ai/doompi-extension-contracts/config';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { HookDocumentReader, HookRunner } from '../../types/hooks.ts';\nimport type { HookTelemetry } from '../../types/telemetry.ts';\nimport { createHookDocumentReader } from '../hookDocuments.ts';\nimport { createBashHookRunner } from '../hookRunner.ts';\nimport { createHookTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport {\n type HookReadinessGate,\n type HookRuntime,\n type HookSession,\n registerHookHandlers,\n runSessionEndHooks,\n} from './hookHandlers.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-hook';\n\nexport interface HookExtensionOptions {\n telemetry?: HookTelemetry;\n runner?: HookRunner;\n documents?: HookDocumentReader;\n}\n\nfunction hookSession(cordis: Context, options: HookExtensionOptions): HookSession {\n // The log sink is only built if something actually reports to it, so a fully\n // stubbed session never touches the telemetry backend.\n let telemetry = options.telemetry;\n const requireTelemetry = (): HookTelemetry => (telemetry ??= createHookTelemetry());\n return {\n config: () => requireDoomConfigContext(cordis),\n runner: options.runner ?? createBashHookRunner({ telemetry: requireTelemetry() }),\n documents: options.documents ?? createHookDocumentReader({ telemetry: requireTelemetry() }),\n };\n}\n\ninterface HookPluginConfig {\n readonly pi: ExtensionAPI;\n readonly options: HookExtensionOptions;\n}\n\ninterface HookRuntimeBinding extends HookRuntime {\n dispose(): void;\n}\n\nfunction createHookRuntime(cordis: Context, options: HookExtensionOptions): HookRuntimeBinding {\n const session = hookSession(cordis, options);\n let active = true;\n let generation = 0;\n let readiness:\n | {\n readonly sessionManager: object;\n readonly coordinator: DoomReadinessCoordinator;\n readonly operation: Promise<void>;\n }\n | undefined;\n const readinessGate: HookReadinessGate = {\n start(context, operation) {\n const ownGeneration = ++generation;\n const isCurrent = (): boolean => active && ownGeneration === generation;\n const coordinator = readDoomReadinessCoordinator(cordis);\n if (!coordinator) return operation(new AbortController().signal, isCurrent);\n\n const previous = readiness;\n const readinessOperation = (async (): Promise<void> => {\n if (previous?.coordinator === coordinator) await previous.operation.catch(() => undefined);\n if (!isCurrent()) return;\n const handle = coordinator.start(\n PACKAGE_SOURCE,\n `${context.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await operation(signal, isCurrent);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void readinessOperation.catch(() => undefined);\n readiness = {\n sessionManager: context.sessionManager,\n coordinator,\n operation: readinessOperation,\n };\n return undefined;\n },\n async wait(context: ExtensionContext): Promise<void> {\n const current = readiness;\n if (!current) return;\n if (current.sessionManager !== context.sessionManager) {\n throw new Error('Hook readiness belongs to a stale Pi session.');\n }\n await current.operation;\n if (!active || current !== readiness) {\n throw new Error('Hook readiness belongs to a stale extension generation.');\n }\n },\n };\n return {\n session,\n readiness: readinessGate,\n isCurrent: () => active,\n dispose() {\n active = false;\n generation += 1;\n readiness = undefined;\n },\n };\n}\n\nfunction hookPlugin(cordis: Context, { pi, options }: HookPluginConfig): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-hook',\n description:\n 'Author DoomPi repository or plugin hooks. Use when creating or changing .doom/hooks.yaml, selecting hook groups from modes.yaml, writing hook commands, or adapting Claude Code hook payloads and decisions to DoomPi.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n let runtime: HookRuntimeBinding | undefined;\n cordis.inject([DOOM_CONFIG_SERVICE], (configContext) => {\n const binding = createHookRuntime(configContext, options);\n runtime = binding;\n configContext.effect(\n () => () => {\n binding.dispose();\n if (runtime === binding) runtime = undefined;\n },\n `${PACKAGE_SOURCE}/config-runtime`,\n );\n });\n\n cordis.effect(function* () {\n for (const disposeRegistration of registerHookHandlers(pi, () => runtime)) yield disposeRegistration;\n yield () => {\n runtime = undefined;\n };\n }, PACKAGE_SOURCE);\n\n let shutdown: Promise<void> | undefined;\n pi.on('session_shutdown', (_event, ctx) => {\n const current = runtime;\n if (!current?.isCurrent()) return undefined;\n shutdown ??= runSessionEndHooks(current.session, ctx);\n return shutdown;\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function hookExtension(pi: ExtensionAPI, options: HookExtensionOptions = {}): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(hookPlugin, { pi, options });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nexport default hookExtension;\n"],"mappings":"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"}
@@ -2,13 +2,13 @@ import { HookDocumentReader, HookRunner } from "../../types/hooks.cjs";
2
2
  import { HookTelemetry } from "../../types/telemetry.cjs";
3
3
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
4
4
  //#region src/adapters/pi/extension.d.ts
5
- interface HookExtensionOptions {
5
+ export interface HookExtensionOptions {
6
6
  telemetry?: HookTelemetry;
7
7
  runner?: HookRunner;
8
8
  documents?: HookDocumentReader;
9
9
  }
10
10
  /** The package's single standard Pi factory. */
11
- declare function hookExtension(pi: ExtensionAPI, options?: HookExtensionOptions): Promise<void>;
11
+ export declare function hookExtension(pi: ExtensionAPI, options?: HookExtensionOptions): Promise<void>;
12
12
  //#endregion
13
- export { HookExtensionOptions, hookExtension as default, hookExtension };
13
+ export { hookExtension as default };
14
14
  //# sourceMappingURL=extension.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;UAwBiB;EACf,YAAY;EACZ,SAAS;EACT,YAAY;;;iBAwHQ,cAAc,IAAI,cAAc,UAAS,uBAA4B"}
1
+ {"version":3,"file":"extension.d.cts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAyBiB;EACf,YAAY;EACZ,SAAS;EACT,YAAY;;;wBAuIQ,cAAc,IAAI,cAAc,UAAS,uBAA4B"}
@@ -2,13 +2,13 @@ import { HookDocumentReader, HookRunner } from "../../types/hooks.mjs";
2
2
  import { HookTelemetry } from "../../types/telemetry.mjs";
3
3
  import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
4
4
  //#region src/adapters/pi/extension.d.ts
5
- interface HookExtensionOptions {
5
+ export interface HookExtensionOptions {
6
6
  telemetry?: HookTelemetry;
7
7
  runner?: HookRunner;
8
8
  documents?: HookDocumentReader;
9
9
  }
10
10
  /** The package's single standard Pi factory. */
11
- declare function hookExtension(pi: ExtensionAPI, options?: HookExtensionOptions): Promise<void>;
11
+ export declare function hookExtension(pi: ExtensionAPI, options?: HookExtensionOptions): Promise<void>;
12
12
  //#endregion
13
- export { HookExtensionOptions, hookExtension as default, hookExtension };
13
+ export { hookExtension as default };
14
14
  //# sourceMappingURL=extension.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;UAwBiB;EACf,YAAY;EACZ,SAAS;EACT,YAAY;;;iBAwHQ,cAAc,IAAI,cAAc,UAAS,uBAA4B"}
1
+ {"version":3,"file":"extension.d.mts","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"mappings":";;;;iBAyBiB;EACf,YAAY;EACZ,SAAS;EACT,YAAY;;;wBAuIQ,cAAc,IAAI,cAAc,UAAS,uBAA4B"}
@@ -1,2 +1,2 @@
1
- import{createHookDocumentReader as e}from"../hookDocuments.mjs";import{createBashHookRunner as t}from"../hookRunner.mjs";import{createHookTelemetry as n}from"../telemetry/logSinkTelemetry.mjs";import{registerHookHandlers as r,runSessionEndHooks as i}from"./hookHandlers.mjs";import{readDoomReadinessCoordinator as a}from"@agimon-ai/doompi-extension-contracts/readiness";import{connectDoomCordisHost as o}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_CONFIG_SERVICE as s}from"@agimon-ai/doompi-extension-contracts/config";import{requireDoomConfigContext as c}from"@agimon-ai/doompi-config/piContext";const l=`@agimon-ai/doompi-hook`;function u(r,i){let a=i.telemetry,o=()=>a??=n();return{config:()=>c(r),runner:i.runner??t({telemetry:o()}),documents:i.documents??e({telemetry:o()})}}function d(e,t){let n=u(e,t),r=!0,i=0,o;return{session:n,readiness:{start(t,n){let s=++i,c=()=>r&&s===i,u=a(e);if(!u)return n(new AbortController().signal,c);let d=o,f=(async()=>{d?.coordinator===u&&await d.operation.catch(()=>void 0),c()&&await u.start(l,`${t.sessionManager.getSessionId()}:${s}`,async e=>(await n(e,c),{value:void 0})).wait()})();f.catch(()=>void 0),o={sessionManager:t.sessionManager,coordinator:u,operation:f}},async wait(e){let t=o;if(t){if(t.sessionManager!==e.sessionManager)throw Error(`Hook readiness belongs to a stale Pi session.`);if(await t.operation,!r||t!==o)throw Error(`Hook readiness belongs to a stale extension generation.`)}}},isCurrent:()=>r,dispose(){r=!1,i+=1,o=void 0}}}function f(e,{pi:t,options:n}){let a;e.inject([s],e=>{let t=d(e,n);a=t,e.effect(()=>()=>{t.dispose(),a===t&&(a=void 0)},`${l}/config-runtime`)}),e.effect(function*(){for(let e of r(t,()=>a))yield e;yield()=>{a=void 0}},l);let o;t.on(`session_shutdown`,(e,t)=>{let n=a;if(n?.isCurrent())return o??=i(n.session,t),o})}async function p(e,t={}){let n=await o(e,l),r=n.root.plugin(f,{pi:e,options:t});try{await r}catch(e){try{await r.dispose()}finally{await n.dispose()}throw e}let i;e.on(`session_shutdown`,()=>i??=(async()=>{try{await r.dispose()}finally{await n.dispose()}})())}export{p as default,p as hookExtension};
1
+ import{createHookDocumentReader as e}from"../hookDocuments.mjs";import{createBashHookRunner as t}from"../hookRunner.mjs";import{createHookTelemetry as n}from"../telemetry/logSinkTelemetry.mjs";import{registerHookHandlers as r,runSessionEndHooks as i}from"./hookHandlers.mjs";import{readDoomReadinessCoordinator as a}from"@agimon-ai/doompi-extension-contracts/readiness";import{connectDoomCordisHost as o}from"@agimon-ai/doompi-extension-contracts/cordis-host";import{DOOM_CONFIG_SERVICE as s}from"@agimon-ai/doompi-extension-contracts/config";import{DOOM_HELP_SERVICE as c,requireDoomHelpService as l}from"@agimon-ai/doompi-extension-contracts/help";import{requireDoomConfigContext as u}from"@agimon-ai/doompi-config/piContext";const d=`@agimon-ai/doompi-hook`;function f(r,i){let a=i.telemetry,o=()=>a??=n();return{config:()=>u(r),runner:i.runner??t({telemetry:o()}),documents:i.documents??e({telemetry:o()})}}function p(e,t){let n=f(e,t),r=!0,i=0,o;return{session:n,readiness:{start(t,n){let s=++i,c=()=>r&&s===i,l=a(e);if(!l)return n(new AbortController().signal,c);let u=o,f=(async()=>{u?.coordinator===l&&await u.operation.catch(()=>void 0),c()&&await l.start(d,`${t.sessionManager.getSessionId()}:${s}`,async e=>(await n(e,c),{value:void 0})).wait()})();f.catch(()=>void 0),o={sessionManager:t.sessionManager,coordinator:l,operation:f}},async wait(e){let t=o;if(t){if(t.sessionManager!==e.sessionManager)throw Error(`Hook readiness belongs to a stale Pi session.`);if(await t.operation,!r||t!==o)throw Error(`Hook readiness belongs to a stale extension generation.`)}}},isCurrent:()=>r,dispose(){r=!1,i+=1,o=void 0}}}function m(e,{pi:t,options:n}){e.inject([c],e=>{let t=l(e).register({source:d,moduleUrl:import.meta.url,skills:[{name:`doompi-author-hook`,description:`Author DoomPi repository or plugin hooks. Use when creating or changing .doom/hooks.yaml, selecting hook groups from modes.yaml, writing hook commands, or adapting Claude Code hook payloads and decisions to DoomPi.`}]});return()=>t.dispose()});let a;e.inject([s],e=>{let t=p(e,n);a=t,e.effect(()=>()=>{t.dispose(),a===t&&(a=void 0)},`${d}/config-runtime`)}),e.effect(function*(){for(let e of r(t,()=>a))yield e;yield()=>{a=void 0}},d);let o;t.on(`session_shutdown`,(e,t)=>{let n=a;if(n?.isCurrent())return o??=i(n.session,t),o})}async function h(e,t={}){let n=await o(e,d),r=n.root.plugin(m,{pi:e,options:t});try{await r}catch(e){try{await r.dispose()}finally{await n.dispose()}throw e}let i;e.on(`session_shutdown`,()=>i??=(async()=>{try{await r.dispose()}finally{await n.dispose()}})())}export{h as default,h as hookExtension};
2
2
  //# sourceMappingURL=extension.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import {\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_CONFIG_SERVICE } from '@agimon-ai/doompi-extension-contracts/config';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { HookDocumentReader, HookRunner } from '../../types/hooks.ts';\nimport type { HookTelemetry } from '../../types/telemetry.ts';\nimport { createHookDocumentReader } from '../hookDocuments.ts';\nimport { createBashHookRunner } from '../hookRunner.ts';\nimport { createHookTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport {\n type HookReadinessGate,\n type HookRuntime,\n type HookSession,\n registerHookHandlers,\n runSessionEndHooks,\n} from './hookHandlers.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-hook';\n\nexport interface HookExtensionOptions {\n telemetry?: HookTelemetry;\n runner?: HookRunner;\n documents?: HookDocumentReader;\n}\n\nfunction hookSession(cordis: Context, options: HookExtensionOptions): HookSession {\n // The log sink is only built if something actually reports to it, so a fully\n // stubbed session never touches the telemetry backend.\n let telemetry = options.telemetry;\n const requireTelemetry = (): HookTelemetry => (telemetry ??= createHookTelemetry());\n return {\n config: () => requireDoomConfigContext(cordis),\n runner: options.runner ?? createBashHookRunner({ telemetry: requireTelemetry() }),\n documents: options.documents ?? createHookDocumentReader({ telemetry: requireTelemetry() }),\n };\n}\n\ninterface HookPluginConfig {\n readonly pi: ExtensionAPI;\n readonly options: HookExtensionOptions;\n}\n\ninterface HookRuntimeBinding extends HookRuntime {\n dispose(): void;\n}\n\nfunction createHookRuntime(cordis: Context, options: HookExtensionOptions): HookRuntimeBinding {\n const session = hookSession(cordis, options);\n let active = true;\n let generation = 0;\n let readiness:\n | {\n readonly sessionManager: object;\n readonly coordinator: DoomReadinessCoordinator;\n readonly operation: Promise<void>;\n }\n | undefined;\n const readinessGate: HookReadinessGate = {\n start(context, operation) {\n const ownGeneration = ++generation;\n const isCurrent = (): boolean => active && ownGeneration === generation;\n const coordinator = readDoomReadinessCoordinator(cordis);\n if (!coordinator) return operation(new AbortController().signal, isCurrent);\n\n const previous = readiness;\n const readinessOperation = (async (): Promise<void> => {\n if (previous?.coordinator === coordinator) await previous.operation.catch(() => undefined);\n if (!isCurrent()) return;\n const handle = coordinator.start(\n PACKAGE_SOURCE,\n `${context.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await operation(signal, isCurrent);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void readinessOperation.catch(() => undefined);\n readiness = {\n sessionManager: context.sessionManager,\n coordinator,\n operation: readinessOperation,\n };\n return undefined;\n },\n async wait(context: ExtensionContext): Promise<void> {\n const current = readiness;\n if (!current) return;\n if (current.sessionManager !== context.sessionManager) {\n throw new Error('Hook readiness belongs to a stale Pi session.');\n }\n await current.operation;\n if (!active || current !== readiness) {\n throw new Error('Hook readiness belongs to a stale extension generation.');\n }\n },\n };\n return {\n session,\n readiness: readinessGate,\n isCurrent: () => active,\n dispose() {\n active = false;\n generation += 1;\n readiness = undefined;\n },\n };\n}\n\nfunction hookPlugin(cordis: Context, { pi, options }: HookPluginConfig): void {\n let runtime: HookRuntimeBinding | undefined;\n cordis.inject([DOOM_CONFIG_SERVICE], (configContext) => {\n const binding = createHookRuntime(configContext, options);\n runtime = binding;\n configContext.effect(\n () => () => {\n binding.dispose();\n if (runtime === binding) runtime = undefined;\n },\n `${PACKAGE_SOURCE}/config-runtime`,\n );\n });\n\n cordis.effect(function* () {\n for (const disposeRegistration of registerHookHandlers(pi, () => runtime)) yield disposeRegistration;\n yield () => {\n runtime = undefined;\n };\n }, PACKAGE_SOURCE);\n\n let shutdown: Promise<void> | undefined;\n pi.on('session_shutdown', (_event, ctx) => {\n const current = runtime;\n if (!current?.isCurrent()) return undefined;\n shutdown ??= runSessionEndHooks(current.session, ctx);\n return shutdown;\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function hookExtension(pi: ExtensionAPI, options: HookExtensionOptions = {}): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(hookPlugin, { pi, options });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nexport default hookExtension;\n"],"mappings":"6mBAsBA,MAAM,EAAiB,yBAQvB,SAAS,EAAY,EAAiB,EAA4C,CAGhF,IAAI,EAAY,EAAQ,UAClB,MAAyC,IAAc,EAAoB,EACjF,MAAO,CACL,WAAc,EAAyB,CAAM,EAC7C,OAAQ,EAAQ,QAAU,EAAqB,CAAE,UAAW,EAAiB,CAAE,CAAC,EAChF,UAAW,EAAQ,WAAa,EAAyB,CAAE,UAAW,EAAiB,CAAE,CAAC,CAC5F,CACF,CAWA,SAAS,EAAkB,EAAiB,EAAmD,CAC7F,IAAM,EAAU,EAAY,EAAQ,CAAO,EACvC,EAAS,GACT,EAAa,EACb,EAiDJ,MAAO,CACL,UACA,UAAW,CA3CX,MAAM,EAAS,EAAW,CACxB,IAAM,EAAgB,EAAE,EAClB,MAA2B,GAAU,IAAkB,EACvD,EAAc,EAA6B,CAAM,EACvD,GAAI,CAAC,EAAa,OAAO,EAAU,IAAI,gBAAgB,CAAC,CAAC,OAAQ,CAAS,EAE1E,IAAM,EAAW,EACX,GAAsB,SAA2B,CACjD,GAAU,cAAgB,GAAa,MAAM,EAAS,UAAU,UAAY,IAAA,EAAS,EACpF,EAAU,GASf,MARe,EAAY,MACzB,EACA,GAAG,EAAQ,eAAe,aAAa,EAAE,GAAG,IAC5C,KAAO,KACL,MAAM,EAAU,EAAQ,CAAS,EAC1B,CAAE,MAAO,IAAA,EAAU,EAGnB,CAAC,CAAC,KAAK,CACpB,EAAA,CAAG,EAEH,EAAwB,UAAY,IAAA,EAAS,EAC7C,EAAY,CACV,eAAgB,EAAQ,eACxB,cACA,UAAW,CACb,CAEF,EACA,MAAM,KAAK,EAA0C,CACnD,IAAM,EAAU,EACX,KACL,IAAI,EAAQ,iBAAmB,EAAQ,eACrC,MAAU,MAAM,+CAA+C,EAGjE,GADA,MAAM,EAAQ,UACV,CAAC,GAAU,IAAY,EACzB,MAAU,MAAM,yDAAyD,CAJV,CAMnE,CAIuB,EACvB,cAAiB,EACjB,SAAU,CACR,EAAS,GACT,GAAc,EACd,EAAY,IAAA,EACd,CACF,CACF,CAEA,SAAS,EAAW,EAAiB,CAAE,KAAI,WAAmC,CAC5E,IAAI,EACJ,EAAO,OAAO,CAAC,CAAmB,EAAI,GAAkB,CACtD,IAAM,EAAU,EAAkB,EAAe,CAAO,EACxD,EAAU,EACV,EAAc,eACA,CACV,EAAQ,QAAQ,EACZ,IAAY,IAAS,EAAU,IAAA,GACrC,EACA,GAAG,EAAe,gBACpB,CACF,CAAC,EAED,EAAO,OAAO,WAAa,CACzB,IAAK,IAAM,KAAuB,EAAqB,MAAU,CAAO,EAAG,MAAM,EACjF,SAAY,CACV,EAAU,IAAA,EACZ,CACF,EAAG,CAAc,EAEjB,IAAI,EACJ,EAAG,GAAG,oBAAqB,EAAQ,IAAQ,CACzC,IAAM,EAAU,EACX,MAAS,UAAU,EAExB,MADA,KAAa,EAAmB,EAAQ,QAAS,CAAG,EAC7C,CACT,CAAC,CACH,CAGA,eAAsB,EAAc,EAAkB,EAAgC,CAAC,EAAkB,CACvG,IAAM,EAAa,MAAM,EAAsB,EAAI,CAAc,EAC3D,EAAQ,EAAW,KAAK,OAAO,EAAY,CAAE,KAAI,SAAQ,CAAC,EAChE,GAAI,CACF,MAAM,CACR,OAAS,EAAO,CACd,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACA,MAAM,CACR,CACA,IAAI,EACJ,EAAG,GACD,uBAEG,KAAc,SAAY,CACzB,GAAI,CACF,MAAM,EAAM,QAAQ,CACtB,QAAU,CACR,MAAM,EAAW,QAAQ,CAC3B,CACF,EAAA,CAAG,CACP,CACF"}
1
+ {"version":3,"file":"extension.mjs","names":[],"sources":["../../../src/adapters/pi/extension.ts"],"sourcesContent":["import {\n type DoomReadinessCoordinator,\n readDoomReadinessCoordinator,\n} from '@agimon-ai/doompi-extension-contracts/readiness';\nimport { connectDoomCordisHost } from '@agimon-ai/doompi-extension-contracts/cordis-host';\nimport { DOOM_CONFIG_SERVICE } from '@agimon-ai/doompi-extension-contracts/config';\nimport { DOOM_HELP_SERVICE, requireDoomHelpService } from '@agimon-ai/doompi-extension-contracts/help';\nimport { requireDoomConfigContext } from '@agimon-ai/doompi-config/piContext';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport type { HookDocumentReader, HookRunner } from '../../types/hooks.ts';\nimport type { HookTelemetry } from '../../types/telemetry.ts';\nimport { createHookDocumentReader } from '../hookDocuments.ts';\nimport { createBashHookRunner } from '../hookRunner.ts';\nimport { createHookTelemetry } from '../telemetry/logSinkTelemetry.ts';\nimport {\n type HookReadinessGate,\n type HookRuntime,\n type HookSession,\n registerHookHandlers,\n runSessionEndHooks,\n} from './hookHandlers.ts';\n\nconst PACKAGE_SOURCE = '@agimon-ai/doompi-hook';\n\nexport interface HookExtensionOptions {\n telemetry?: HookTelemetry;\n runner?: HookRunner;\n documents?: HookDocumentReader;\n}\n\nfunction hookSession(cordis: Context, options: HookExtensionOptions): HookSession {\n // The log sink is only built if something actually reports to it, so a fully\n // stubbed session never touches the telemetry backend.\n let telemetry = options.telemetry;\n const requireTelemetry = (): HookTelemetry => (telemetry ??= createHookTelemetry());\n return {\n config: () => requireDoomConfigContext(cordis),\n runner: options.runner ?? createBashHookRunner({ telemetry: requireTelemetry() }),\n documents: options.documents ?? createHookDocumentReader({ telemetry: requireTelemetry() }),\n };\n}\n\ninterface HookPluginConfig {\n readonly pi: ExtensionAPI;\n readonly options: HookExtensionOptions;\n}\n\ninterface HookRuntimeBinding extends HookRuntime {\n dispose(): void;\n}\n\nfunction createHookRuntime(cordis: Context, options: HookExtensionOptions): HookRuntimeBinding {\n const session = hookSession(cordis, options);\n let active = true;\n let generation = 0;\n let readiness:\n | {\n readonly sessionManager: object;\n readonly coordinator: DoomReadinessCoordinator;\n readonly operation: Promise<void>;\n }\n | undefined;\n const readinessGate: HookReadinessGate = {\n start(context, operation) {\n const ownGeneration = ++generation;\n const isCurrent = (): boolean => active && ownGeneration === generation;\n const coordinator = readDoomReadinessCoordinator(cordis);\n if (!coordinator) return operation(new AbortController().signal, isCurrent);\n\n const previous = readiness;\n const readinessOperation = (async (): Promise<void> => {\n if (previous?.coordinator === coordinator) await previous.operation.catch(() => undefined);\n if (!isCurrent()) return;\n const handle = coordinator.start(\n PACKAGE_SOURCE,\n `${context.sessionManager.getSessionId()}:${ownGeneration}`,\n async (signal) => {\n await operation(signal, isCurrent);\n return { value: undefined };\n },\n );\n await handle.wait();\n })();\n // Config's coordinator owns the single user-facing failure notification.\n void readinessOperation.catch(() => undefined);\n readiness = {\n sessionManager: context.sessionManager,\n coordinator,\n operation: readinessOperation,\n };\n return undefined;\n },\n async wait(context: ExtensionContext): Promise<void> {\n const current = readiness;\n if (!current) return;\n if (current.sessionManager !== context.sessionManager) {\n throw new Error('Hook readiness belongs to a stale Pi session.');\n }\n await current.operation;\n if (!active || current !== readiness) {\n throw new Error('Hook readiness belongs to a stale extension generation.');\n }\n },\n };\n return {\n session,\n readiness: readinessGate,\n isCurrent: () => active,\n dispose() {\n active = false;\n generation += 1;\n readiness = undefined;\n },\n };\n}\n\nfunction hookPlugin(cordis: Context, { pi, options }: HookPluginConfig): void {\n cordis.inject([DOOM_HELP_SERVICE], (helpContext) => {\n const contribution = requireDoomHelpService(helpContext).register({\n source: PACKAGE_SOURCE,\n moduleUrl: import.meta.url,\n skills: [\n {\n name: 'doompi-author-hook',\n description:\n 'Author DoomPi repository or plugin hooks. Use when creating or changing .doom/hooks.yaml, selecting hook groups from modes.yaml, writing hook commands, or adapting Claude Code hook payloads and decisions to DoomPi.',\n },\n ],\n });\n return () => contribution.dispose();\n });\n\n let runtime: HookRuntimeBinding | undefined;\n cordis.inject([DOOM_CONFIG_SERVICE], (configContext) => {\n const binding = createHookRuntime(configContext, options);\n runtime = binding;\n configContext.effect(\n () => () => {\n binding.dispose();\n if (runtime === binding) runtime = undefined;\n },\n `${PACKAGE_SOURCE}/config-runtime`,\n );\n });\n\n cordis.effect(function* () {\n for (const disposeRegistration of registerHookHandlers(pi, () => runtime)) yield disposeRegistration;\n yield () => {\n runtime = undefined;\n };\n }, PACKAGE_SOURCE);\n\n let shutdown: Promise<void> | undefined;\n pi.on('session_shutdown', (_event, ctx) => {\n const current = runtime;\n if (!current?.isCurrent()) return undefined;\n shutdown ??= runSessionEndHooks(current.session, ctx);\n return shutdown;\n });\n}\n\n/** The package's single standard Pi factory. */\nexport async function hookExtension(pi: ExtensionAPI, options: HookExtensionOptions = {}): Promise<void> {\n const connection = await connectDoomCordisHost(pi, PACKAGE_SOURCE);\n const fiber = connection.root.plugin(hookPlugin, { pi, options });\n try {\n await fiber;\n } catch (error) {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n throw error;\n }\n let disposal: Promise<void> | undefined;\n pi.on(\n 'session_shutdown',\n () =>\n (disposal ??= (async () => {\n try {\n await fiber.dispose();\n } finally {\n await connection.dispose();\n }\n })()),\n );\n}\n\nexport default hookExtension;\n"],"mappings":"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"}
@@ -1,14 +1,13 @@
1
1
  import { HookTelemetry } from "../../types/telemetry.cjs";
2
2
  import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
3
3
  //#region src/adapters/telemetry/logSinkTelemetry.d.ts
4
- interface HookTelemetryOptions {
4
+ export interface HookTelemetryOptions {
5
5
  cwd?: string;
6
6
  workspaceRoot?: string;
7
7
  env?: NodeJS.ProcessEnv;
8
8
  telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;
9
9
  warn?: (message: string) => void;
10
10
  }
11
- declare function createHookTelemetry(options?: HookTelemetryOptions): HookTelemetry;
11
+ export declare function createHookTelemetry(options?: HookTelemetryOptions): HookTelemetry;
12
12
  //#endregion
13
- export { HookTelemetryOptions, createHookTelemetry };
14
13
  //# sourceMappingURL=logSinkTelemetry.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logSinkTelemetry.d.cts","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"mappings":";;;UAMiB;EACf;EACA;EACA,MAAM,OAAO;EACb,mBAAmB,YAAY;EAC/B,QAAQ;;iBAGM,oBAAoB,UAAS,uBAA4B"}
1
+ {"version":3,"file":"logSinkTelemetry.d.cts","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"mappings":";;;iBAMiB;EACf;EACA;EACA,MAAM,OAAO;EACb,mBAAmB,YAAY;EAC/B,QAAQ;;wBAGM,oBAAoB,UAAS,uBAA4B"}
@@ -1,14 +1,13 @@
1
1
  import { HookTelemetry } from "../../types/telemetry.mjs";
2
2
  import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
3
3
  //#region src/adapters/telemetry/logSinkTelemetry.d.ts
4
- interface HookTelemetryOptions {
4
+ export interface HookTelemetryOptions {
5
5
  cwd?: string;
6
6
  workspaceRoot?: string;
7
7
  env?: NodeJS.ProcessEnv;
8
8
  telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;
9
9
  warn?: (message: string) => void;
10
10
  }
11
- declare function createHookTelemetry(options?: HookTelemetryOptions): HookTelemetry;
11
+ export declare function createHookTelemetry(options?: HookTelemetryOptions): HookTelemetry;
12
12
  //#endregion
13
- export { HookTelemetryOptions, createHookTelemetry };
14
13
  //# sourceMappingURL=logSinkTelemetry.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logSinkTelemetry.d.mts","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"mappings":";;;UAMiB;EACf;EACA;EACA,MAAM,OAAO;EACb,mBAAmB,YAAY;EAC/B,QAAQ;;iBAGM,oBAAoB,UAAS,uBAA4B"}
1
+ {"version":3,"file":"logSinkTelemetry.d.mts","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"mappings":";;;iBAMiB;EACf;EACA;EACA,MAAM,OAAO;EACb,mBAAmB,YAAY;EAC/B,QAAQ;;wBAGM,oBAAoB,UAAS,uBAA4B"}
@@ -1,19 +1,18 @@
1
1
  import { HookDecision, HookFailure, HookOutcome } from "../types/hooks.cjs";
2
2
  //#region src/services/hookDecisions.d.ts
3
- declare function decisionsFrom(outcomes: ReadonlyArray<HookOutcome>): HookDecision[];
4
- declare function failuresFrom(outcomes: ReadonlyArray<HookOutcome>): HookFailure[];
3
+ export declare function decisionsFrom(outcomes: ReadonlyArray<HookOutcome>): HookDecision[];
4
+ export declare function failuresFrom(outcomes: ReadonlyArray<HookOutcome>): HookFailure[];
5
5
  /** Both spellings a hook may use to refuse the call it observed. */
6
- declare function isDenied(decision: HookDecision | undefined): boolean;
7
- declare function decisionReason(decision: HookDecision | undefined): string | undefined;
6
+ export declare function isDenied(decision: HookDecision | undefined): boolean;
7
+ export declare function decisionReason(decision: HookDecision | undefined): string | undefined;
8
8
  /** Context a hook wants added to the conversation rather than used to block. */
9
- declare function additionalContextsFrom(decisions: ReadonlyArray<HookDecision>): string[];
9
+ export declare function additionalContextsFrom(decisions: ReadonlyArray<HookDecision>): string[];
10
10
  /** What a post-tool hook has to say, whichever field it said it in. */
11
- declare function toolResultMessages(decisions: ReadonlyArray<HookDecision>): string[];
11
+ export declare function toolResultMessages(decisions: ReadonlyArray<HookDecision>): string[];
12
12
  /**
13
13
  * A guardrail that never ran looks exactly like one that passed, so the agent is
14
14
  * told which checks were missed and what its options are.
15
15
  */
16
- declare function hookFailureMessage(failures: ReadonlyArray<HookFailure>): string;
16
+ export declare function hookFailureMessage(failures: ReadonlyArray<HookFailure>): string;
17
17
  //#endregion
18
- export { additionalContextsFrom, decisionReason, decisionsFrom, failuresFrom, hookFailureMessage, isDenied, toolResultMessages };
19
18
  //# sourceMappingURL=hookDecisions.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookDecisions.d.cts","names":[],"sources":["../../src/services/hookDecisions.ts"],"mappings":";;iBAKgB,cAAc,UAAU,cAAc,eAAe;iBAIrD,aAAa,UAAU,cAAc,eAAe;;iBAKpD,SAAS,UAAU;iBAInB,eAAe,UAAU;;iBAKzB,uBAAuB,WAAW,cAAc;;iBAOhD,mBAAmB,WAAW,cAAc;;;;;iBAU5C,mBAAmB,UAAU,cAAc"}
1
+ {"version":3,"file":"hookDecisions.d.cts","names":[],"sources":["../../src/services/hookDecisions.ts"],"mappings":";;wBAKgB,cAAc,UAAU,cAAc,eAAe;wBAIrD,aAAa,UAAU,cAAc,eAAe;;wBAKpD,SAAS,UAAU;wBAInB,eAAe,UAAU;;wBAKzB,uBAAuB,WAAW,cAAc;;wBAOhD,mBAAmB,WAAW,cAAc;;;;;wBAU5C,mBAAmB,UAAU,cAAc"}
@@ -1,19 +1,18 @@
1
1
  import { HookDecision, HookFailure, HookOutcome } from "../types/hooks.mjs";
2
2
  //#region src/services/hookDecisions.d.ts
3
- declare function decisionsFrom(outcomes: ReadonlyArray<HookOutcome>): HookDecision[];
4
- declare function failuresFrom(outcomes: ReadonlyArray<HookOutcome>): HookFailure[];
3
+ export declare function decisionsFrom(outcomes: ReadonlyArray<HookOutcome>): HookDecision[];
4
+ export declare function failuresFrom(outcomes: ReadonlyArray<HookOutcome>): HookFailure[];
5
5
  /** Both spellings a hook may use to refuse the call it observed. */
6
- declare function isDenied(decision: HookDecision | undefined): boolean;
7
- declare function decisionReason(decision: HookDecision | undefined): string | undefined;
6
+ export declare function isDenied(decision: HookDecision | undefined): boolean;
7
+ export declare function decisionReason(decision: HookDecision | undefined): string | undefined;
8
8
  /** Context a hook wants added to the conversation rather than used to block. */
9
- declare function additionalContextsFrom(decisions: ReadonlyArray<HookDecision>): string[];
9
+ export declare function additionalContextsFrom(decisions: ReadonlyArray<HookDecision>): string[];
10
10
  /** What a post-tool hook has to say, whichever field it said it in. */
11
- declare function toolResultMessages(decisions: ReadonlyArray<HookDecision>): string[];
11
+ export declare function toolResultMessages(decisions: ReadonlyArray<HookDecision>): string[];
12
12
  /**
13
13
  * A guardrail that never ran looks exactly like one that passed, so the agent is
14
14
  * told which checks were missed and what its options are.
15
15
  */
16
- declare function hookFailureMessage(failures: ReadonlyArray<HookFailure>): string;
16
+ export declare function hookFailureMessage(failures: ReadonlyArray<HookFailure>): string;
17
17
  //#endregion
18
- export { additionalContextsFrom, decisionReason, decisionsFrom, failuresFrom, hookFailureMessage, isDenied, toolResultMessages };
19
18
  //# sourceMappingURL=hookDecisions.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookDecisions.d.mts","names":[],"sources":["../../src/services/hookDecisions.ts"],"mappings":";;iBAKgB,cAAc,UAAU,cAAc,eAAe;iBAIrD,aAAa,UAAU,cAAc,eAAe;;iBAKpD,SAAS,UAAU;iBAInB,eAAe,UAAU;;iBAKzB,uBAAuB,WAAW,cAAc;;iBAOhD,mBAAmB,WAAW,cAAc;;;;;iBAU5C,mBAAmB,UAAU,cAAc"}
1
+ {"version":3,"file":"hookDecisions.d.mts","names":[],"sources":["../../src/services/hookDecisions.ts"],"mappings":";;wBAKgB,cAAc,UAAU,cAAc,eAAe;wBAIrD,aAAa,UAAU,cAAc,eAAe;;wBAKpD,SAAS,UAAU;wBAInB,eAAe,UAAU;;wBAKzB,uBAAuB,WAAW,cAAc;;wBAOhD,mBAAmB,WAAW,cAAc;;;;;wBAU5C,mBAAmB,UAAU,cAAc"}
@@ -1,9 +1,8 @@
1
1
  import { HookPayload, HookToolEvent } from "../types/hooks.cjs";
2
2
  //#region src/services/hookPayload.d.ts
3
3
  /** The payload shape a Claude Code session hook is written against. */
4
- declare function toolHookPayload(event: HookToolEvent, hookEventName: string, repoRoot: string, sessionId: string): HookPayload;
4
+ export declare function toolHookPayload(event: HookToolEvent, hookEventName: string, repoRoot: string, sessionId: string): HookPayload;
5
5
  /** Session lifecycle hooks observe no tool, so they only need where and who. */
6
- declare function sessionHookPayload(sessionId: string, repoRoot: string): HookPayload;
6
+ export declare function sessionHookPayload(sessionId: string, repoRoot: string): HookPayload;
7
7
  //#endregion
8
- export { sessionHookPayload, toolHookPayload };
9
8
  //# sourceMappingURL=hookPayload.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookPayload.d.cts","names":[],"sources":["../../src/services/hookPayload.ts"],"mappings":";;;iBAMgB,gBACd,OAAO,eACP,uBACA,kBACA,oBACC;;iBAaa,mBAAmB,mBAAmB,mBAAmB"}
1
+ {"version":3,"file":"hookPayload.d.cts","names":[],"sources":["../../src/services/hookPayload.ts"],"mappings":";;;wBAMgB,gBACd,OAAO,eACP,uBACA,kBACA,oBACC;;wBAaa,mBAAmB,mBAAmB,mBAAmB"}
@@ -1,9 +1,8 @@
1
1
  import { HookPayload, HookToolEvent } from "../types/hooks.mjs";
2
2
  //#region src/services/hookPayload.d.ts
3
3
  /** The payload shape a Claude Code session hook is written against. */
4
- declare function toolHookPayload(event: HookToolEvent, hookEventName: string, repoRoot: string, sessionId: string): HookPayload;
4
+ export declare function toolHookPayload(event: HookToolEvent, hookEventName: string, repoRoot: string, sessionId: string): HookPayload;
5
5
  /** Session lifecycle hooks observe no tool, so they only need where and who. */
6
- declare function sessionHookPayload(sessionId: string, repoRoot: string): HookPayload;
6
+ export declare function sessionHookPayload(sessionId: string, repoRoot: string): HookPayload;
7
7
  //#endregion
8
- export { sessionHookPayload, toolHookPayload };
9
8
  //# sourceMappingURL=hookPayload.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookPayload.d.mts","names":[],"sources":["../../src/services/hookPayload.ts"],"mappings":";;;iBAMgB,gBACd,OAAO,eACP,uBACA,kBACA,oBACC;;iBAaa,mBAAmB,mBAAmB,mBAAmB"}
1
+ {"version":3,"file":"hookPayload.d.mts","names":[],"sources":["../../src/services/hookPayload.ts"],"mappings":";;;wBAMgB,gBACd,OAAO,eACP,uBACA,kBACA,oBACC;;wBAaa,mBAAmB,mBAAmB,mBAAmB"}
@@ -1,7 +1,7 @@
1
1
  import { HookDocumentSource, ParsedRegistrySource, RegistryEntry, ResolvedHook } from "../types/hooks.cjs";
2
2
  //#region src/services/hookRegistry.d.ts
3
3
  /** Which rows a dispatch keeps, once the session's selection is known. */
4
- interface RegistrySelection {
4
+ export interface RegistrySelection {
5
5
  event: string;
6
6
  toolName?: string;
7
7
  /** Selected group ids, or undefined for "every group", the standalone default. */
@@ -15,7 +15,7 @@ interface RegistrySelection {
15
15
  * rewrite and needs no invalidation hook. Reading both files is cheap; parsing
16
16
  * is what a cache built on this skips.
17
17
  */
18
- declare function registryCacheKey(sources: ReadonlyArray<HookDocumentSource>): string;
18
+ export declare function registryCacheKey(sources: ReadonlyArray<HookDocumentSource>): string;
19
19
  /**
20
20
  * Flattens parsed registry documents into sorted rows, keeping only bindings
21
21
  * that declare a `pi` frontend.
@@ -23,7 +23,7 @@ declare function registryCacheKey(sources: ReadonlyArray<HookDocumentSource>): s
23
23
  * A later source replaces the group of the same id outright rather than merging
24
24
  * into it, so a repository that redefines a group owns it completely.
25
25
  */
26
- declare function registryEntries(sources: ReadonlyArray<ParsedRegistrySource>): RegistryEntry[];
26
+ export declare function registryEntries(sources: ReadonlyArray<ParsedRegistrySource>): RegistryEntry[];
27
27
  /**
28
28
  * The rows one dispatch runs.
29
29
  *
@@ -31,7 +31,6 @@ declare function registryEntries(sources: ReadonlyArray<ParsedRegistrySource>):
31
31
  * applied per call rather than being baked into a cached parse. Core groups
32
32
  * always load; the rest are gated by the layers the harness resolved.
33
33
  */
34
- declare function selectRegistryHooks(entries: ReadonlyArray<RegistryEntry>, selection: RegistrySelection): ResolvedHook[];
34
+ export declare function selectRegistryHooks(entries: ReadonlyArray<RegistryEntry>, selection: RegistrySelection): ResolvedHook[];
35
35
  //#endregion
36
- export { RegistrySelection, registryCacheKey, registryEntries, selectRegistryHooks };
37
36
  //# sourceMappingURL=hookRegistry.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookRegistry.d.cts","names":[],"sources":["../../src/services/hookRegistry.ts"],"mappings":";;;UAIiB;EACf;EACA;;EAEA;EACA;;;;;;;;;iBAUc,iBAAiB,SAAS,cAAc;;;;;;;;iBAWxC,gBAAgB,SAAS,cAAc,wBAAwB;;;;;;;;iBAqC/D,oBACd,SAAS,cAAc,gBACvB,WAAW,oBACV"}
1
+ {"version":3,"file":"hookRegistry.d.cts","names":[],"sources":["../../src/services/hookRegistry.ts"],"mappings":";;;iBAIiB;EACf;EACA;;EAEA;EACA;;;;;;;;;wBAUc,iBAAiB,SAAS,cAAc;;;;;;;;wBAWxC,gBAAgB,SAAS,cAAc,wBAAwB;;;;;;;;wBAqC/D,oBACd,SAAS,cAAc,gBACvB,WAAW,oBACV"}
@@ -1,7 +1,7 @@
1
1
  import { HookDocumentSource, ParsedRegistrySource, RegistryEntry, ResolvedHook } from "../types/hooks.mjs";
2
2
  //#region src/services/hookRegistry.d.ts
3
3
  /** Which rows a dispatch keeps, once the session's selection is known. */
4
- interface RegistrySelection {
4
+ export interface RegistrySelection {
5
5
  event: string;
6
6
  toolName?: string;
7
7
  /** Selected group ids, or undefined for "every group", the standalone default. */
@@ -15,7 +15,7 @@ interface RegistrySelection {
15
15
  * rewrite and needs no invalidation hook. Reading both files is cheap; parsing
16
16
  * is what a cache built on this skips.
17
17
  */
18
- declare function registryCacheKey(sources: ReadonlyArray<HookDocumentSource>): string;
18
+ export declare function registryCacheKey(sources: ReadonlyArray<HookDocumentSource>): string;
19
19
  /**
20
20
  * Flattens parsed registry documents into sorted rows, keeping only bindings
21
21
  * that declare a `pi` frontend.
@@ -23,7 +23,7 @@ declare function registryCacheKey(sources: ReadonlyArray<HookDocumentSource>): s
23
23
  * A later source replaces the group of the same id outright rather than merging
24
24
  * into it, so a repository that redefines a group owns it completely.
25
25
  */
26
- declare function registryEntries(sources: ReadonlyArray<ParsedRegistrySource>): RegistryEntry[];
26
+ export declare function registryEntries(sources: ReadonlyArray<ParsedRegistrySource>): RegistryEntry[];
27
27
  /**
28
28
  * The rows one dispatch runs.
29
29
  *
@@ -31,7 +31,6 @@ declare function registryEntries(sources: ReadonlyArray<ParsedRegistrySource>):
31
31
  * applied per call rather than being baked into a cached parse. Core groups
32
32
  * always load; the rest are gated by the layers the harness resolved.
33
33
  */
34
- declare function selectRegistryHooks(entries: ReadonlyArray<RegistryEntry>, selection: RegistrySelection): ResolvedHook[];
34
+ export declare function selectRegistryHooks(entries: ReadonlyArray<RegistryEntry>, selection: RegistrySelection): ResolvedHook[];
35
35
  //#endregion
36
- export { RegistrySelection, registryCacheKey, registryEntries, selectRegistryHooks };
37
36
  //# sourceMappingURL=hookRegistry.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hookRegistry.d.mts","names":[],"sources":["../../src/services/hookRegistry.ts"],"mappings":";;;UAIiB;EACf;EACA;;EAEA;EACA;;;;;;;;;iBAUc,iBAAiB,SAAS,cAAc;;;;;;;;iBAWxC,gBAAgB,SAAS,cAAc,wBAAwB;;;;;;;;iBAqC/D,oBACd,SAAS,cAAc,gBACvB,WAAW,oBACV"}
1
+ {"version":3,"file":"hookRegistry.d.mts","names":[],"sources":["../../src/services/hookRegistry.ts"],"mappings":";;;iBAIiB;EACf;EACA;;EAEA;EACA;;;;;;;;;wBAUc,iBAAiB,SAAS,cAAc;;;;;;;;wBAWxC,gBAAgB,SAAS,cAAc,wBAAwB;;;;;;;;wBAqC/D,oBACd,SAAS,cAAc,gBACvB,WAAW,oBACV"}