@agimon-ai/doompi-hook 0.0.1-alpha.4 → 0.0.1-alpha.5
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/package.json +6 -6
- package/dist/_virtual/_rolldown/runtime.cjs +0 -1
- package/dist/adapters/hookDocuments.cjs +0 -2
- package/dist/adapters/hookDocuments.cjs.map +0 -1
- package/dist/adapters/hookDocuments.d.cts +0 -23
- package/dist/adapters/hookDocuments.d.cts.map +0 -1
- package/dist/adapters/hookDocuments.d.mts +0 -23
- package/dist/adapters/hookDocuments.d.mts.map +0 -1
- package/dist/adapters/hookDocuments.mjs +0 -2
- package/dist/adapters/hookDocuments.mjs.map +0 -1
- package/dist/adapters/hookRunner.cjs +0 -2
- package/dist/adapters/hookRunner.cjs.map +0 -1
- package/dist/adapters/hookRunner.d.cts +0 -22
- package/dist/adapters/hookRunner.d.cts.map +0 -1
- package/dist/adapters/hookRunner.d.mts +0 -22
- package/dist/adapters/hookRunner.d.mts.map +0 -1
- package/dist/adapters/hookRunner.mjs +0 -2
- package/dist/adapters/hookRunner.mjs.map +0 -1
- package/dist/adapters/pi/extension.cjs +0 -2
- package/dist/adapters/pi/extension.cjs.map +0 -1
- package/dist/adapters/pi/extension.d.cts +0 -14
- package/dist/adapters/pi/extension.d.cts.map +0 -1
- package/dist/adapters/pi/extension.d.mts +0 -14
- package/dist/adapters/pi/extension.d.mts.map +0 -1
- package/dist/adapters/pi/extension.mjs +0 -2
- package/dist/adapters/pi/extension.mjs.map +0 -1
- package/dist/adapters/pi/hookHandlers.cjs +0 -8
- package/dist/adapters/pi/hookHandlers.cjs.map +0 -1
- package/dist/adapters/pi/hookHandlers.mjs +0 -8
- package/dist/adapters/pi/hookHandlers.mjs.map +0 -1
- package/dist/adapters/telemetry/logSinkTelemetry.cjs +0 -2
- package/dist/adapters/telemetry/logSinkTelemetry.cjs.map +0 -1
- package/dist/adapters/telemetry/logSinkTelemetry.d.cts +0 -14
- package/dist/adapters/telemetry/logSinkTelemetry.d.cts.map +0 -1
- package/dist/adapters/telemetry/logSinkTelemetry.d.mts +0 -14
- package/dist/adapters/telemetry/logSinkTelemetry.d.mts.map +0 -1
- package/dist/adapters/telemetry/logSinkTelemetry.mjs +0 -2
- package/dist/adapters/telemetry/logSinkTelemetry.mjs.map +0 -1
- package/dist/extensions/pi.cjs +0 -1
- package/dist/extensions/pi.d.cts +0 -2
- package/dist/extensions/pi.d.mts +0 -2
- package/dist/extensions/pi.mjs +0 -1
- package/dist/index.cjs +0 -1
- package/dist/index.d.cts +0 -12
- package/dist/index.d.mts +0 -12
- package/dist/index.mjs +0 -1
- package/dist/services/hookDecisions.cjs +0 -3
- package/dist/services/hookDecisions.cjs.map +0 -1
- package/dist/services/hookDecisions.d.cts +0 -19
- package/dist/services/hookDecisions.d.cts.map +0 -1
- package/dist/services/hookDecisions.d.mts +0 -19
- package/dist/services/hookDecisions.d.mts.map +0 -1
- package/dist/services/hookDecisions.mjs +0 -3
- package/dist/services/hookDecisions.mjs.map +0 -1
- package/dist/services/hookPayload.cjs +0 -2
- package/dist/services/hookPayload.cjs.map +0 -1
- package/dist/services/hookPayload.d.cts +0 -9
- package/dist/services/hookPayload.d.cts.map +0 -1
- package/dist/services/hookPayload.d.mts +0 -9
- package/dist/services/hookPayload.d.mts.map +0 -1
- package/dist/services/hookPayload.mjs +0 -2
- package/dist/services/hookPayload.mjs.map +0 -1
- package/dist/services/hookRegistry.cjs +0 -2
- package/dist/services/hookRegistry.cjs.map +0 -1
- package/dist/services/hookRegistry.d.cts +0 -37
- package/dist/services/hookRegistry.d.cts.map +0 -1
- package/dist/services/hookRegistry.d.mts +0 -37
- package/dist/services/hookRegistry.d.mts.map +0 -1
- package/dist/services/hookRegistry.mjs +0 -2
- package/dist/services/hookRegistry.mjs.map +0 -1
- package/dist/services/pluginHooks.cjs +0 -2
- package/dist/services/pluginHooks.cjs.map +0 -1
- package/dist/services/pluginHooks.d.cts +0 -13
- package/dist/services/pluginHooks.d.cts.map +0 -1
- package/dist/services/pluginHooks.d.mts +0 -13
- package/dist/services/pluginHooks.d.mts.map +0 -1
- package/dist/services/pluginHooks.mjs +0 -2
- package/dist/services/pluginHooks.mjs.map +0 -1
- package/dist/services/toolNames.cjs +0 -2
- package/dist/services/toolNames.cjs.map +0 -1
- package/dist/services/toolNames.d.cts +0 -8
- package/dist/services/toolNames.d.cts.map +0 -1
- package/dist/services/toolNames.d.mts +0 -8
- package/dist/services/toolNames.d.mts.map +0 -1
- package/dist/services/toolNames.mjs +0 -2
- package/dist/services/toolNames.mjs.map +0 -1
- package/dist/types/hooks.cjs +0 -2
- package/dist/types/hooks.cjs.map +0 -1
- package/dist/types/hooks.d.cts +0 -145
- package/dist/types/hooks.d.cts.map +0 -1
- package/dist/types/hooks.d.mts +0 -145
- package/dist/types/hooks.d.mts.map +0 -1
- package/dist/types/hooks.mjs +0 -2
- package/dist/types/hooks.mjs.map +0 -1
- package/dist/types/telemetry.cjs +0 -2
- package/dist/types/telemetry.cjs.map +0 -1
- package/dist/types/telemetry.d.cts +0 -20
- package/dist/types/telemetry.d.cts.map +0 -1
- package/dist/types/telemetry.d.mts +0 -20
- package/dist/types/telemetry.d.mts.map +0 -1
- package/dist/types/telemetry.mjs +0 -2
- package/dist/types/telemetry.mjs.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/doompi-hook",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.5",
|
|
4
4
|
"description": "Claude-Code-compatible repository and plugin hook runner for DoomPi sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -48,18 +48,18 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@deepseek-ai/cordis": "4.0.1",
|
|
50
50
|
"yaml": "2.9.0",
|
|
51
|
-
"@agimon-ai/doompi-config": "0.0.1-alpha.
|
|
52
|
-
"@agimon-ai/doompi-
|
|
53
|
-
"@agimon-ai/doompi-
|
|
51
|
+
"@agimon-ai/doompi-config": "0.0.1-alpha.27",
|
|
52
|
+
"@agimon-ai/doompi-telemetry": "0.0.1-alpha.27",
|
|
53
|
+
"@agimon-ai/doompi-extension-contracts": "0.0.1-alpha.27"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
+
"@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.26",
|
|
56
57
|
"@earendil-works/pi-coding-agent": "0.84.2",
|
|
57
58
|
"@types/node": "26.1.1",
|
|
58
59
|
"@vitest/coverage-v8": "4.1.10",
|
|
59
60
|
"tsdown": "0.22.14",
|
|
60
61
|
"typescript": "6.0.3",
|
|
61
|
-
"vitest": "4.1.10"
|
|
62
|
-
"@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.1-alpha.26"
|
|
62
|
+
"vitest": "4.1.10"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"@earendil-works/pi-coding-agent": "0.84.2"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));exports.__toESM=s;
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../types/telemetry.cjs"),n=require("../services/hookRegistry.cjs");let r=require("node:fs");r=e.__toESM(r,1);let i=require("@agimon-ai/doompi-config/layeredConfig"),a=require("yaml");function o(e){return e instanceof Error?e.message:String(e)}function s(e){return e?.code===`ENOENT`}function c(e={}){let c=e.readFile??(e=>r.default.promises.readFile(e,`utf8`)),l=e.telemetry,u=e.warn??(e=>void process.stderr.write(e)),d,f=[],p=new Map,m=async e=>{try{return{baseDirectory:e.baseDirectory,text:await c(e.filePath)}}catch(e){if(s(e))return;throw e}},h=e=>{let t=n.registryCacheKey(e);return d===t?f:(f=n.registryEntries(e.map(e=>({baseDirectory:e.baseDirectory,document:(0,a.parse)(e.text)??{}}))),d=t,f)};return{async registry(n){let r=(0,i.doomConfigCandidates)(`hooks.yaml`,n,e.homeDirectory),a=r.map(e=>e.filePath).join(` and `);try{let e=(await Promise.all(r.map(m))).filter(e=>e!==void 0);return{entries:h(e)}}catch(e){return l?.recordError(t.HOOK_TELEMETRY_EVENT.hookRegistryReadFailed,e,{"hook.registry.source":`repository`}),u(`[pi-hook] could not read ${a}: ${o(e)}\n`),{entries:[],failure:{command:a,message:o(e),reason:`registry_read`}}}},async plugins(e){let t=[],n=[];for(let r of e)try{let e=await c(r.configPath),n=p.get(r.configPath),i=n?.source===e?n.config:JSON.parse(e);p.set(r.configPath,{source:e,config:i}),t.push({pluginRoot:r.pluginRoot,config:i})}catch(e){n.push({command:r.configPath,message:o(e),reason:`plugin_config`})}return{documents:t,failures:n}}}}exports.createHookDocumentReader=c;
|
|
2
|
-
//# sourceMappingURL=hookDocuments.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hookDocuments.cjs","names":["fs","registryCacheKey","registryEntries","parseYaml","doomConfigCandidates","HOOK_TELEMETRY_EVENT"],"sources":["../../src/adapters/hookDocuments.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { doomConfigCandidates } from '@agimon-ai/doompi-config/layeredConfig';\nimport { parse as parseYaml } from 'yaml';\nimport type {\n HookDocumentReader,\n HookDocumentSource,\n PluginDocumentRead,\n PluginHookConfig,\n PluginHookDocument,\n PluginHookSourceRef,\n RegistryDocument,\n RegistryEntry,\n RegistryRead,\n} from '../types/hooks.ts';\nimport { HOOK_TELEMETRY_EVENT, type HookTelemetry } from '../types/telemetry.ts';\nimport { registryCacheKey, registryEntries } from '../services/hookRegistry.ts';\n\nconst HOOKS_FILE = 'hooks.yaml';\nconst FILE_ENCODING = 'utf8';\nconst FILE_NOT_FOUND_ERROR = 'ENOENT';\nconst REGISTRY_SOURCE_ATTRIBUTE = 'repository';\n\nexport interface HookDocumentReaderOptions {\n telemetry?: HookTelemetry;\n /** Where the global `.doom` directory lives. Defaults to the user's home. */\n homeDirectory?: string;\n readFile?: (filePath: string) => Promise<string>;\n warn?: (message: string) => void;\n}\n\nfunction reason(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction isMissingFile(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === FILE_NOT_FOUND_ERROR;\n}\n\n/**\n * Reads `.doom/hooks.yaml` from the global config directory and the repository,\n * and the plugin hook configs the harness resolved.\n *\n * Every file is re-read on every dispatch: it costs almost nothing and keeps an\n * in-place rewrite visible, which an mtime check would miss when two writes land\n * inside the same filesystem timestamp granularity. Both caches are keyed on\n * contents instead, so parsing — the expensive half — is what they skip.\n */\nexport function createHookDocumentReader(options: HookDocumentReaderOptions = {}): HookDocumentReader {\n const readFile = options.readFile ?? ((filePath: string) => fs.promises.readFile(filePath, FILE_ENCODING));\n const telemetry = options.telemetry;\n const warn = options.warn ?? ((message: string) => void process.stderr.write(message));\n let cachedRegistryKey: string | undefined;\n let cachedRegistryEntries: RegistryEntry[] = [];\n const pluginConfigCache = new Map<string, { source: string; config: PluginHookConfig }>();\n\n const readSource = async (candidate: {\n filePath: string;\n baseDirectory: string;\n }): Promise<HookDocumentSource | undefined> => {\n try {\n return { baseDirectory: candidate.baseDirectory, text: await readFile(candidate.filePath) };\n } catch (error) {\n if (isMissingFile(error)) return undefined;\n throw error;\n }\n };\n\n const parseSources = (sources: ReadonlyArray<HookDocumentSource>): RegistryEntry[] => {\n const key = registryCacheKey(sources);\n if (cachedRegistryKey === key) return cachedRegistryEntries;\n cachedRegistryEntries = registryEntries(\n sources.map((source) => ({\n baseDirectory: source.baseDirectory,\n document: (parseYaml(source.text) ?? {}) as RegistryDocument,\n })),\n );\n cachedRegistryKey = key;\n return cachedRegistryEntries;\n };\n\n return {\n async registry(repoRoot: string): Promise<RegistryRead> {\n const candidates = doomConfigCandidates(HOOKS_FILE, repoRoot, options.homeDirectory);\n // Named for the error path only. A registry absent from both locations is\n // a repository with no hooks, not a failure, so only a file that exists\n // and cannot be read or parsed reaches the catch below.\n const registryPath = candidates.map((candidate) => candidate.filePath).join(' and ');\n try {\n const sources = (await Promise.all(candidates.map(readSource))).filter(\n (source): source is HookDocumentSource => source !== undefined,\n );\n return { entries: parseSources(sources) };\n } catch (error) {\n // This empties the registry for the whole dispatch, so every repository\n // hook silently stops running rather than any one of them failing.\n void telemetry?.recordError(HOOK_TELEMETRY_EVENT.hookRegistryReadFailed, error, {\n 'hook.registry.source': REGISTRY_SOURCE_ATTRIBUTE,\n });\n warn(`[pi-hook] could not read ${registryPath}: ${reason(error)}\\n`);\n return { entries: [], failure: { command: registryPath, message: reason(error), reason: 'registry_read' } };\n }\n },\n\n async plugins(sources: readonly PluginHookSourceRef[]): Promise<PluginDocumentRead> {\n const documents: PluginHookDocument[] = [];\n const failures: PluginDocumentRead['failures'] = [];\n for (const source of sources) {\n try {\n const text = await readFile(source.configPath);\n const cached = pluginConfigCache.get(source.configPath);\n const config = cached?.source === text ? cached.config : (JSON.parse(text) as PluginHookConfig);\n pluginConfigCache.set(source.configPath, { source: text, config });\n documents.push({ pluginRoot: source.pluginRoot, config });\n } catch (error) {\n failures.push({ command: source.configPath, message: reason(error), reason: 'plugin_config' });\n }\n }\n return { documents, failures };\n },\n };\n}\n"],"mappings":"uPA8BA,SAAS,EAAO,EAAwB,CACtC,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAEA,SAAS,EAAc,EAAyB,CAC9C,OAAQ,GAA6C,OAAS,QAChE,CAWA,SAAgB,EAAyB,EAAqC,CAAC,EAAuB,CACpG,IAAM,EAAW,EAAQ,WAAc,GAAqBA,EAAAA,QAAG,SAAS,SAAS,EAAU,MAAa,GAClG,EAAY,EAAQ,UACpB,EAAO,EAAQ,OAAU,GAAoB,KAAK,QAAQ,OAAO,MAAM,CAAO,GAChF,EACA,EAAyC,CAAC,EACxC,EAAoB,IAAI,IAExB,EAAa,KAAO,IAGqB,CAC7C,GAAI,CACF,MAAO,CAAE,cAAe,EAAU,cAAe,KAAM,MAAM,EAAS,EAAU,QAAQ,CAAE,CAC5F,OAAS,EAAO,CACd,GAAI,EAAc,CAAK,EAAG,OAC1B,MAAM,CACR,CACF,EAEM,EAAgB,GAAgE,CACpF,IAAM,EAAMC,EAAAA,iBAAiB,CAAO,EASpC,OARI,IAAsB,EAAY,GACtC,EAAwBC,EAAAA,gBACtB,EAAQ,IAAK,IAAY,CACvB,cAAe,EAAO,cACtB,UAAA,EAAWC,EAAAA,MAAAA,CAAU,EAAO,IAAI,GAAK,CAAC,CACxC,EAAE,CACJ,EACA,EAAoB,EACb,EACT,EAEA,MAAO,CACL,MAAM,SAAS,EAAyC,CACtD,IAAM,GAAA,EAAaC,EAAAA,qBAAAA,CAAqB,aAAY,EAAU,EAAQ,aAAa,EAI7E,EAAe,EAAW,IAAK,GAAc,EAAU,QAAQ,CAAC,CAAC,KAAK,OAAO,EACnF,GAAI,CACF,IAAM,GAAW,MAAM,QAAQ,IAAI,EAAW,IAAI,CAAU,CAAC,EAAA,CAAG,OAC7D,GAAyC,IAAW,IAAA,EACvD,EACA,MAAO,CAAE,QAAS,EAAa,CAAO,CAAE,CAC1C,OAAS,EAAO,CAOd,OAJA,GAAgB,YAAYC,EAAAA,qBAAqB,uBAAwB,EAAO,CAC9E,uBAAwB,YAC1B,CAAC,EACD,EAAK,4BAA4B,EAAa,IAAI,EAAO,CAAK,EAAE,GAAG,EAC5D,CAAE,QAAS,CAAC,EAAG,QAAS,CAAE,QAAS,EAAc,QAAS,EAAO,CAAK,EAAG,OAAQ,eAAgB,CAAE,CAC5G,CACF,EAEA,MAAM,QAAQ,EAAsE,CAClF,IAAM,EAAkC,CAAC,EACnC,EAA2C,CAAC,EAClD,IAAK,IAAM,KAAU,EACnB,GAAI,CACF,IAAM,EAAO,MAAM,EAAS,EAAO,UAAU,EACvC,EAAS,EAAkB,IAAI,EAAO,UAAU,EAChD,EAAS,GAAQ,SAAW,EAAO,EAAO,OAAU,KAAK,MAAM,CAAI,EACzE,EAAkB,IAAI,EAAO,WAAY,CAAE,OAAQ,EAAM,QAAO,CAAC,EACjE,EAAU,KAAK,CAAE,WAAY,EAAO,WAAY,QAAO,CAAC,CAC1D,OAAS,EAAO,CACd,EAAS,KAAK,CAAE,QAAS,EAAO,WAAY,QAAS,EAAO,CAAK,EAAG,OAAQ,eAAgB,CAAC,CAC/F,CAEF,MAAO,CAAE,YAAW,UAAS,CAC/B,CACF,CACF"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { HookDocumentReader } from "../types/hooks.cjs";
|
|
2
|
-
import { HookTelemetry } from "../types/telemetry.cjs";
|
|
3
|
-
//#region src/adapters/hookDocuments.d.ts
|
|
4
|
-
interface HookDocumentReaderOptions {
|
|
5
|
-
telemetry?: HookTelemetry;
|
|
6
|
-
/** Where the global `.doom` directory lives. Defaults to the user's home. */
|
|
7
|
-
homeDirectory?: string;
|
|
8
|
-
readFile?: (filePath: string) => Promise<string>;
|
|
9
|
-
warn?: (message: string) => void;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Reads `.doom/hooks.yaml` from the global config directory and the repository,
|
|
13
|
-
* and the plugin hook configs the harness resolved.
|
|
14
|
-
*
|
|
15
|
-
* Every file is re-read on every dispatch: it costs almost nothing and keeps an
|
|
16
|
-
* in-place rewrite visible, which an mtime check would miss when two writes land
|
|
17
|
-
* inside the same filesystem timestamp granularity. Both caches are keyed on
|
|
18
|
-
* contents instead, so parsing — the expensive half — is what they skip.
|
|
19
|
-
*/
|
|
20
|
-
declare function createHookDocumentReader(options?: HookDocumentReaderOptions): HookDocumentReader;
|
|
21
|
-
//#endregion
|
|
22
|
-
export { HookDocumentReaderOptions, createHookDocumentReader };
|
|
23
|
-
//# sourceMappingURL=hookDocuments.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,23 +0,0 @@
|
|
|
1
|
-
import { HookDocumentReader } from "../types/hooks.mjs";
|
|
2
|
-
import { HookTelemetry } from "../types/telemetry.mjs";
|
|
3
|
-
//#region src/adapters/hookDocuments.d.ts
|
|
4
|
-
interface HookDocumentReaderOptions {
|
|
5
|
-
telemetry?: HookTelemetry;
|
|
6
|
-
/** Where the global `.doom` directory lives. Defaults to the user's home. */
|
|
7
|
-
homeDirectory?: string;
|
|
8
|
-
readFile?: (filePath: string) => Promise<string>;
|
|
9
|
-
warn?: (message: string) => void;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Reads `.doom/hooks.yaml` from the global config directory and the repository,
|
|
13
|
-
* and the plugin hook configs the harness resolved.
|
|
14
|
-
*
|
|
15
|
-
* Every file is re-read on every dispatch: it costs almost nothing and keeps an
|
|
16
|
-
* in-place rewrite visible, which an mtime check would miss when two writes land
|
|
17
|
-
* inside the same filesystem timestamp granularity. Both caches are keyed on
|
|
18
|
-
* contents instead, so parsing — the expensive half — is what they skip.
|
|
19
|
-
*/
|
|
20
|
-
declare function createHookDocumentReader(options?: HookDocumentReaderOptions): HookDocumentReader;
|
|
21
|
-
//#endregion
|
|
22
|
-
export { HookDocumentReaderOptions, createHookDocumentReader };
|
|
23
|
-
//# sourceMappingURL=hookDocuments.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,2 +0,0 @@
|
|
|
1
|
-
import{HOOK_TELEMETRY_EVENT as e}from"../types/telemetry.mjs";import{registryCacheKey as t,registryEntries as n}from"../services/hookRegistry.mjs";import r from"node:fs";import{doomConfigCandidates as i}from"@agimon-ai/doompi-config/layeredConfig";import{parse as a}from"yaml";function o(e){return e instanceof Error?e.message:String(e)}function s(e){return e?.code===`ENOENT`}function c(c={}){let l=c.readFile??(e=>r.promises.readFile(e,`utf8`)),u=c.telemetry,d=c.warn??(e=>void process.stderr.write(e)),f,p=[],m=new Map,h=async e=>{try{return{baseDirectory:e.baseDirectory,text:await l(e.filePath)}}catch(e){if(s(e))return;throw e}},g=e=>{let r=t(e);return f===r?p:(p=n(e.map(e=>({baseDirectory:e.baseDirectory,document:a(e.text)??{}}))),f=r,p)};return{async registry(t){let n=i(`hooks.yaml`,t,c.homeDirectory),r=n.map(e=>e.filePath).join(` and `);try{let e=(await Promise.all(n.map(h))).filter(e=>e!==void 0);return{entries:g(e)}}catch(t){return u?.recordError(e.hookRegistryReadFailed,t,{"hook.registry.source":`repository`}),d(`[pi-hook] could not read ${r}: ${o(t)}\n`),{entries:[],failure:{command:r,message:o(t),reason:`registry_read`}}}},async plugins(e){let t=[],n=[];for(let r of e)try{let e=await l(r.configPath),n=m.get(r.configPath),i=n?.source===e?n.config:JSON.parse(e);m.set(r.configPath,{source:e,config:i}),t.push({pluginRoot:r.pluginRoot,config:i})}catch(e){n.push({command:r.configPath,message:o(e),reason:`plugin_config`})}return{documents:t,failures:n}}}}export{c as createHookDocumentReader};
|
|
2
|
-
//# sourceMappingURL=hookDocuments.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hookDocuments.mjs","names":["parseYaml"],"sources":["../../src/adapters/hookDocuments.ts"],"sourcesContent":["import fs from 'node:fs';\nimport { doomConfigCandidates } from '@agimon-ai/doompi-config/layeredConfig';\nimport { parse as parseYaml } from 'yaml';\nimport type {\n HookDocumentReader,\n HookDocumentSource,\n PluginDocumentRead,\n PluginHookConfig,\n PluginHookDocument,\n PluginHookSourceRef,\n RegistryDocument,\n RegistryEntry,\n RegistryRead,\n} from '../types/hooks.ts';\nimport { HOOK_TELEMETRY_EVENT, type HookTelemetry } from '../types/telemetry.ts';\nimport { registryCacheKey, registryEntries } from '../services/hookRegistry.ts';\n\nconst HOOKS_FILE = 'hooks.yaml';\nconst FILE_ENCODING = 'utf8';\nconst FILE_NOT_FOUND_ERROR = 'ENOENT';\nconst REGISTRY_SOURCE_ATTRIBUTE = 'repository';\n\nexport interface HookDocumentReaderOptions {\n telemetry?: HookTelemetry;\n /** Where the global `.doom` directory lives. Defaults to the user's home. */\n homeDirectory?: string;\n readFile?: (filePath: string) => Promise<string>;\n warn?: (message: string) => void;\n}\n\nfunction reason(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction isMissingFile(error: unknown): boolean {\n return (error as NodeJS.ErrnoException | undefined)?.code === FILE_NOT_FOUND_ERROR;\n}\n\n/**\n * Reads `.doom/hooks.yaml` from the global config directory and the repository,\n * and the plugin hook configs the harness resolved.\n *\n * Every file is re-read on every dispatch: it costs almost nothing and keeps an\n * in-place rewrite visible, which an mtime check would miss when two writes land\n * inside the same filesystem timestamp granularity. Both caches are keyed on\n * contents instead, so parsing — the expensive half — is what they skip.\n */\nexport function createHookDocumentReader(options: HookDocumentReaderOptions = {}): HookDocumentReader {\n const readFile = options.readFile ?? ((filePath: string) => fs.promises.readFile(filePath, FILE_ENCODING));\n const telemetry = options.telemetry;\n const warn = options.warn ?? ((message: string) => void process.stderr.write(message));\n let cachedRegistryKey: string | undefined;\n let cachedRegistryEntries: RegistryEntry[] = [];\n const pluginConfigCache = new Map<string, { source: string; config: PluginHookConfig }>();\n\n const readSource = async (candidate: {\n filePath: string;\n baseDirectory: string;\n }): Promise<HookDocumentSource | undefined> => {\n try {\n return { baseDirectory: candidate.baseDirectory, text: await readFile(candidate.filePath) };\n } catch (error) {\n if (isMissingFile(error)) return undefined;\n throw error;\n }\n };\n\n const parseSources = (sources: ReadonlyArray<HookDocumentSource>): RegistryEntry[] => {\n const key = registryCacheKey(sources);\n if (cachedRegistryKey === key) return cachedRegistryEntries;\n cachedRegistryEntries = registryEntries(\n sources.map((source) => ({\n baseDirectory: source.baseDirectory,\n document: (parseYaml(source.text) ?? {}) as RegistryDocument,\n })),\n );\n cachedRegistryKey = key;\n return cachedRegistryEntries;\n };\n\n return {\n async registry(repoRoot: string): Promise<RegistryRead> {\n const candidates = doomConfigCandidates(HOOKS_FILE, repoRoot, options.homeDirectory);\n // Named for the error path only. A registry absent from both locations is\n // a repository with no hooks, not a failure, so only a file that exists\n // and cannot be read or parsed reaches the catch below.\n const registryPath = candidates.map((candidate) => candidate.filePath).join(' and ');\n try {\n const sources = (await Promise.all(candidates.map(readSource))).filter(\n (source): source is HookDocumentSource => source !== undefined,\n );\n return { entries: parseSources(sources) };\n } catch (error) {\n // This empties the registry for the whole dispatch, so every repository\n // hook silently stops running rather than any one of them failing.\n void telemetry?.recordError(HOOK_TELEMETRY_EVENT.hookRegistryReadFailed, error, {\n 'hook.registry.source': REGISTRY_SOURCE_ATTRIBUTE,\n });\n warn(`[pi-hook] could not read ${registryPath}: ${reason(error)}\\n`);\n return { entries: [], failure: { command: registryPath, message: reason(error), reason: 'registry_read' } };\n }\n },\n\n async plugins(sources: readonly PluginHookSourceRef[]): Promise<PluginDocumentRead> {\n const documents: PluginHookDocument[] = [];\n const failures: PluginDocumentRead['failures'] = [];\n for (const source of sources) {\n try {\n const text = await readFile(source.configPath);\n const cached = pluginConfigCache.get(source.configPath);\n const config = cached?.source === text ? cached.config : (JSON.parse(text) as PluginHookConfig);\n pluginConfigCache.set(source.configPath, { source: text, config });\n documents.push({ pluginRoot: source.pluginRoot, config });\n } catch (error) {\n failures.push({ command: source.configPath, message: reason(error), reason: 'plugin_config' });\n }\n }\n return { documents, failures };\n },\n };\n}\n"],"mappings":"qRA8BA,SAAS,EAAO,EAAwB,CACtC,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAC9D,CAEA,SAAS,EAAc,EAAyB,CAC9C,OAAQ,GAA6C,OAAS,QAChE,CAWA,SAAgB,EAAyB,EAAqC,CAAC,EAAuB,CACpG,IAAM,EAAW,EAAQ,WAAc,GAAqB,EAAG,SAAS,SAAS,EAAU,MAAa,GAClG,EAAY,EAAQ,UACpB,EAAO,EAAQ,OAAU,GAAoB,KAAK,QAAQ,OAAO,MAAM,CAAO,GAChF,EACA,EAAyC,CAAC,EACxC,EAAoB,IAAI,IAExB,EAAa,KAAO,IAGqB,CAC7C,GAAI,CACF,MAAO,CAAE,cAAe,EAAU,cAAe,KAAM,MAAM,EAAS,EAAU,QAAQ,CAAE,CAC5F,OAAS,EAAO,CACd,GAAI,EAAc,CAAK,EAAG,OAC1B,MAAM,CACR,CACF,EAEM,EAAgB,GAAgE,CACpF,IAAM,EAAM,EAAiB,CAAO,EASpC,OARI,IAAsB,EAAY,GACtC,EAAwB,EACtB,EAAQ,IAAK,IAAY,CACvB,cAAe,EAAO,cACtB,SAAWA,EAAU,EAAO,IAAI,GAAK,CAAC,CACxC,EAAE,CACJ,EACA,EAAoB,EACb,EACT,EAEA,MAAO,CACL,MAAM,SAAS,EAAyC,CACtD,IAAM,EAAa,EAAqB,aAAY,EAAU,EAAQ,aAAa,EAI7E,EAAe,EAAW,IAAK,GAAc,EAAU,QAAQ,CAAC,CAAC,KAAK,OAAO,EACnF,GAAI,CACF,IAAM,GAAW,MAAM,QAAQ,IAAI,EAAW,IAAI,CAAU,CAAC,EAAA,CAAG,OAC7D,GAAyC,IAAW,IAAA,EACvD,EACA,MAAO,CAAE,QAAS,EAAa,CAAO,CAAE,CAC1C,OAAS,EAAO,CAOd,OAJA,GAAgB,YAAY,EAAqB,uBAAwB,EAAO,CAC9E,uBAAwB,YAC1B,CAAC,EACD,EAAK,4BAA4B,EAAa,IAAI,EAAO,CAAK,EAAE,GAAG,EAC5D,CAAE,QAAS,CAAC,EAAG,QAAS,CAAE,QAAS,EAAc,QAAS,EAAO,CAAK,EAAG,OAAQ,eAAgB,CAAE,CAC5G,CACF,EAEA,MAAM,QAAQ,EAAsE,CAClF,IAAM,EAAkC,CAAC,EACnC,EAA2C,CAAC,EAClD,IAAK,IAAM,KAAU,EACnB,GAAI,CACF,IAAM,EAAO,MAAM,EAAS,EAAO,UAAU,EACvC,EAAS,EAAkB,IAAI,EAAO,UAAU,EAChD,EAAS,GAAQ,SAAW,EAAO,EAAO,OAAU,KAAK,MAAM,CAAI,EACzE,EAAkB,IAAI,EAAO,WAAY,CAAE,OAAQ,EAAM,QAAO,CAAC,EACjE,EAAU,KAAK,CAAE,WAAY,EAAO,WAAY,QAAO,CAAC,CAC1D,OAAS,EAAO,CACd,EAAS,KAAK,CAAE,QAAS,EAAO,WAAY,QAAS,EAAO,CAAK,EAAG,OAAQ,eAAgB,CAAC,CAC/F,CAEF,MAAO,CAAE,YAAW,UAAS,CAC/B,CACF,CACF"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const e=require("../types/telemetry.cjs");let t=require("node:child_process");const n=`ESRCH`,r=/\r?\n/;function i(e){return e instanceof Error&&`code`in e?String(e.code):void 0}function a(a={}){let o=a.spawn??t.spawn,s=a.telemetry,c=a.warn??(e=>void process.stderr.write(e)),l=(a.platform??process.platform)!==`win32`,u=(e,t)=>r=>{try{if(l&&e!==void 0){process.kill(-e,r);return}t(r)}catch(e){i(e)!==n&&process.emitWarning(`Could not signal repository hook process: ${String(e)}`)}};return{run(t,d,f){let p=t.timeout??10,m=a.env??process.env;return new Promise(a=>{let h=o(`/bin/bash`,[`-c`,t.command],{cwd:f.repoRoot,env:{...m,CLAUDE_PROJECT_DIR:f.repoRoot,CODEX_REPO_ROOT:f.repoRoot,ORIGINAL_REPO_PATH:m.ORIGINAL_REPO_PATH??f.repoRoot,...f.pluginRoot?{CLAUDE_PLUGIN_ROOT:f.pluginRoot}:{}},stdio:[`pipe`,`pipe`,`pipe`],detached:l}),g=``,_=``,v=!1,y=!1,b=!1,x=null,S,C=u(h.pid,e=>h.kill(e)),w=()=>{if(!l||h.pid===void 0)return!b;try{return process.kill(-h.pid,0),!0}catch(e){return i(e)!==n}},T=(e={})=>{v||(v=!0,clearTimeout(D),S&&clearTimeout(S),a(e))},E=()=>{let n=`Hook timed out after ${p} seconds.`;s?.recordWarning(e.HOOK_TELEMETRY_EVENT.hookFailed,n,{"hook.reason":`timeout`,"hook.exit_code":x??-1}),c(`[pi-hook] advisory hook timed out: ${t.command}\n${_}`),T({failure:{command:t.command,message:n,reason:`timeout`}})},D=setTimeout(()=>{y=!0,C(`SIGTERM`),S=setTimeout(()=>{w()&&C(`SIGKILL`),E()},2e3)},p*1e3);h.stdout?.on(`data`,e=>{g+=e.toString()}),h.stderr?.on(`data`,e=>{_+=e.toString()}),h.once(`error`,n=>{y||(s?.recordError(e.HOOK_TELEMETRY_EVENT.hookFailed,n,{"hook.reason":`spawn_failed`}),c(`[pi-hook] advisory hook failed: ${n.message}\n`),T({failure:{command:t.command,message:n.message,reason:`spawn_failed`}}))}),h.once(`exit`,n=>{if(b=!0,x=n,y)return;if(n!==0){let r=_.trim()||`Advisory hook exited with code ${n??`unknown`}`;s?.recordWarning(e.HOOK_TELEMETRY_EVENT.hookFailed,r,{"hook.reason":`non_zero_exit`,"hook.exit_code":n??-1}),c(`[pi-hook] advisory hook failed (${n}): ${t.command}\n${_}`),T({failure:{command:t.command,message:r,reason:`non_zero_exit`}});return}let i=g.trim().split(r).reverse().find(e=>e.startsWith(`{`));if(!i){T();return}try{T({decision:JSON.parse(i)})}catch(n){s?.recordWarning(e.HOOK_TELEMETRY_EVENT.hookFailed,n,{"hook.reason":`invalid_json`}),c(`[pi-hook] advisory hook returned invalid JSON: ${t.command}\n`),T({failure:{command:t.command,message:n instanceof Error?n.message:String(n),reason:`invalid_json`}})}}),h.stdin?.end(JSON.stringify(d))})}}}exports.createBashHookRunner=a;
|
|
2
|
-
//# sourceMappingURL=hookRunner.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hookRunner.cjs","names":["spawnProcess","HOOK_TELEMETRY_EVENT"],"sources":["../../src/adapters/hookRunner.ts"],"sourcesContent":["import { spawn as spawnProcess } from 'node:child_process';\nimport type {\n HookCommand,\n HookDecision,\n HookOutcome,\n HookPayload,\n HookRunOptions,\n HookRunner,\n} from '../types/hooks.ts';\nimport { HOOK_TELEMETRY_EVENT, type HookTelemetry } from '../types/telemetry.ts';\n\nconst HOOK_SHELL = '/bin/bash';\nconst HOOK_SHELL_COMMAND_FLAG = '-c';\nconst HOOK_TERMINATION_GRACE_MS = 2_000;\nconst DEFAULT_HOOK_TIMEOUT_SECONDS = 10;\nconst MILLISECONDS_PER_SECOND = 1_000;\nconst PROCESS_NOT_FOUND_ERROR = 'ESRCH';\nconst WINDOWS_PLATFORM = 'win32';\nconst UNKNOWN_EXIT_CODE = -1;\nconst JSON_LINE_START = '{';\nconst LINE_BREAK = /\\r?\\n/;\n\nexport interface BashHookRunnerOptions {\n telemetry?: HookTelemetry;\n env?: NodeJS.ProcessEnv;\n platform?: NodeJS.Platform;\n spawn?: typeof spawnProcess;\n warn?: (message: string) => void;\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return error instanceof Error && 'code' in error ? String(error.code) : undefined;\n}\n\n/**\n * Runs advisory hook commands through bash and reports what each one decided.\n *\n * A hook is a command the repository owns, so it is spawned in its own process\n * group and terminated as one: a hook that starts a server and stalls should\n * not leave the server behind when the timeout fires.\n */\nexport function createBashHookRunner(options: BashHookRunnerOptions = {}): HookRunner {\n const spawn = options.spawn ?? spawnProcess;\n const telemetry = options.telemetry;\n const warn = options.warn ?? ((message: string) => void process.stderr.write(message));\n const useProcessGroup = (options.platform ?? process.platform) !== WINDOWS_PLATFORM;\n\n const signalOwnedProcess = (\n pid: number | undefined,\n kill: (signal: NodeJS.Signals) => void,\n ): ((signal: NodeJS.Signals) => void) => {\n return (signal) => {\n try {\n if (useProcessGroup && pid !== undefined) {\n process.kill(-pid, signal);\n return;\n }\n kill(signal);\n } catch (error) {\n if (errorCode(error) !== PROCESS_NOT_FOUND_ERROR) {\n process.emitWarning(`Could not signal repository hook process: ${String(error)}`);\n }\n }\n };\n };\n\n return {\n run(hook: HookCommand, payload: HookPayload, runOptions: HookRunOptions): Promise<HookOutcome> {\n const timeoutSeconds = hook.timeout ?? DEFAULT_HOOK_TIMEOUT_SECONDS;\n const environment = options.env ?? process.env;\n return new Promise((resolve) => {\n // -c, not -lc. Hooks run on every tool call, and a login shell would\n // source the developer's profile each time: per-call latency plus hook\n // behavior that varies with their dotfiles. The child inherits the\n // environment below, so it keeps the PATH the launcher started with.\n const child = spawn(HOOK_SHELL, [HOOK_SHELL_COMMAND_FLAG, hook.command], {\n cwd: runOptions.repoRoot,\n env: {\n ...environment,\n CLAUDE_PROJECT_DIR: runOptions.repoRoot,\n CODEX_REPO_ROOT: runOptions.repoRoot,\n ORIGINAL_REPO_PATH: environment.ORIGINAL_REPO_PATH ?? runOptions.repoRoot,\n ...(runOptions.pluginRoot ? { CLAUDE_PLUGIN_ROOT: runOptions.pluginRoot } : {}),\n },\n stdio: ['pipe', 'pipe', 'pipe'],\n detached: useProcessGroup,\n });\n let stdout = '';\n let stderr = '';\n let settled = false;\n let timedOut = false;\n let childExited = false;\n let timeoutExitCode: number | null = null;\n let escalationTimer: NodeJS.Timeout | undefined;\n\n const signal = signalOwnedProcess(child.pid, (value) => child.kill(value));\n\n const ownedProcessIsAlive = (): boolean => {\n if (!useProcessGroup || child.pid === undefined) return !childExited;\n try {\n process.kill(-child.pid, 0);\n return true;\n } catch (error) {\n return errorCode(error) !== PROCESS_NOT_FOUND_ERROR;\n }\n };\n\n const finish = (outcome: HookOutcome = {}): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (escalationTimer) clearTimeout(escalationTimer);\n resolve(outcome);\n };\n\n const finishTimeout = (): void => {\n const message = `Hook timed out after ${timeoutSeconds} seconds.`;\n void telemetry?.recordWarning(HOOK_TELEMETRY_EVENT.hookFailed, message, {\n 'hook.reason': 'timeout',\n 'hook.exit_code': timeoutExitCode ?? UNKNOWN_EXIT_CODE,\n });\n warn(`[pi-hook] advisory hook timed out: ${hook.command}\\n${stderr}`);\n finish({ failure: { command: hook.command, message, reason: 'timeout' } });\n };\n\n const timer = setTimeout(() => {\n timedOut = true;\n signal('SIGTERM');\n escalationTimer = setTimeout(() => {\n if (ownedProcessIsAlive()) signal('SIGKILL');\n finishTimeout();\n }, HOOK_TERMINATION_GRACE_MS);\n }, timeoutSeconds * MILLISECONDS_PER_SECOND);\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n child.once('error', (error: Error) => {\n if (timedOut) return;\n // A guardrail that never ran is indistinguishable from one that\n // passed, which is the whole reason these are worth reporting.\n void telemetry?.recordError(HOOK_TELEMETRY_EVENT.hookFailed, error, { 'hook.reason': 'spawn_failed' });\n warn(`[pi-hook] advisory hook failed: ${error.message}\\n`);\n finish({ failure: { command: hook.command, message: error.message, reason: 'spawn_failed' } });\n });\n child.once('exit', (code: number | null) => {\n childExited = true;\n timeoutExitCode = code;\n if (timedOut) return;\n if (code !== 0) {\n const message = stderr.trim() || `Advisory hook exited with code ${code ?? 'unknown'}`;\n void telemetry?.recordWarning(HOOK_TELEMETRY_EVENT.hookFailed, message, {\n 'hook.reason': 'non_zero_exit',\n 'hook.exit_code': code ?? UNKNOWN_EXIT_CODE,\n });\n warn(`[pi-hook] advisory hook failed (${code}): ${hook.command}\\n${stderr}`);\n finish({ failure: { command: hook.command, message, reason: 'non_zero_exit' } });\n return;\n }\n const jsonLine = stdout\n .trim()\n .split(LINE_BREAK)\n .reverse()\n .find((line) => line.startsWith(JSON_LINE_START));\n if (!jsonLine) {\n finish();\n return;\n }\n try {\n finish({ decision: JSON.parse(jsonLine) as HookDecision });\n } catch (error) {\n // The hook ran and had an opinion, and it was dropped.\n void telemetry?.recordWarning(HOOK_TELEMETRY_EVENT.hookFailed, error, { 'hook.reason': 'invalid_json' });\n warn(`[pi-hook] advisory hook returned invalid JSON: ${hook.command}\\n`);\n finish({\n failure: {\n command: hook.command,\n message: error instanceof Error ? error.message : String(error),\n reason: 'invalid_json',\n },\n });\n }\n });\n child.stdin?.end(JSON.stringify(payload));\n });\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { HookRunner } from "../types/hooks.cjs";
|
|
2
|
-
import { HookTelemetry } from "../types/telemetry.cjs";
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
|
-
//#region src/adapters/hookRunner.d.ts
|
|
5
|
-
interface BashHookRunnerOptions {
|
|
6
|
-
telemetry?: HookTelemetry;
|
|
7
|
-
env?: NodeJS.ProcessEnv;
|
|
8
|
-
platform?: NodeJS.Platform;
|
|
9
|
-
spawn?: typeof spawn;
|
|
10
|
-
warn?: (message: string) => void;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Runs advisory hook commands through bash and reports what each one decided.
|
|
14
|
-
*
|
|
15
|
-
* A hook is a command the repository owns, so it is spawned in its own process
|
|
16
|
-
* group and terminated as one: a hook that starts a server and stalls should
|
|
17
|
-
* not leave the server behind when the timeout fires.
|
|
18
|
-
*/
|
|
19
|
-
declare function createBashHookRunner(options?: BashHookRunnerOptions): HookRunner;
|
|
20
|
-
//#endregion
|
|
21
|
-
export { BashHookRunnerOptions, createBashHookRunner };
|
|
22
|
-
//# sourceMappingURL=hookRunner.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,22 +0,0 @@
|
|
|
1
|
-
import { HookRunner } from "../types/hooks.mjs";
|
|
2
|
-
import { HookTelemetry } from "../types/telemetry.mjs";
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
|
-
//#region src/adapters/hookRunner.d.ts
|
|
5
|
-
interface BashHookRunnerOptions {
|
|
6
|
-
telemetry?: HookTelemetry;
|
|
7
|
-
env?: NodeJS.ProcessEnv;
|
|
8
|
-
platform?: NodeJS.Platform;
|
|
9
|
-
spawn?: typeof spawn;
|
|
10
|
-
warn?: (message: string) => void;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Runs advisory hook commands through bash and reports what each one decided.
|
|
14
|
-
*
|
|
15
|
-
* A hook is a command the repository owns, so it is spawned in its own process
|
|
16
|
-
* group and terminated as one: a hook that starts a server and stalls should
|
|
17
|
-
* not leave the server behind when the timeout fires.
|
|
18
|
-
*/
|
|
19
|
-
declare function createBashHookRunner(options?: BashHookRunnerOptions): HookRunner;
|
|
20
|
-
//#endregion
|
|
21
|
-
export { BashHookRunnerOptions, createBashHookRunner };
|
|
22
|
-
//# sourceMappingURL=hookRunner.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,2 +0,0 @@
|
|
|
1
|
-
import{HOOK_TELEMETRY_EVENT as e}from"../types/telemetry.mjs";import{spawn as t}from"node:child_process";const n=`ESRCH`,r=/\r?\n/;function i(e){return e instanceof Error&&`code`in e?String(e.code):void 0}function a(a={}){let o=a.spawn??t,s=a.telemetry,c=a.warn??(e=>void process.stderr.write(e)),l=(a.platform??process.platform)!==`win32`,u=(e,t)=>r=>{try{if(l&&e!==void 0){process.kill(-e,r);return}t(r)}catch(e){i(e)!==n&&process.emitWarning(`Could not signal repository hook process: ${String(e)}`)}};return{run(t,d,f){let p=t.timeout??10,m=a.env??process.env;return new Promise(a=>{let h=o(`/bin/bash`,[`-c`,t.command],{cwd:f.repoRoot,env:{...m,CLAUDE_PROJECT_DIR:f.repoRoot,CODEX_REPO_ROOT:f.repoRoot,ORIGINAL_REPO_PATH:m.ORIGINAL_REPO_PATH??f.repoRoot,...f.pluginRoot?{CLAUDE_PLUGIN_ROOT:f.pluginRoot}:{}},stdio:[`pipe`,`pipe`,`pipe`],detached:l}),g=``,_=``,v=!1,y=!1,b=!1,x=null,S,C=u(h.pid,e=>h.kill(e)),w=()=>{if(!l||h.pid===void 0)return!b;try{return process.kill(-h.pid,0),!0}catch(e){return i(e)!==n}},T=(e={})=>{v||(v=!0,clearTimeout(D),S&&clearTimeout(S),a(e))},E=()=>{let n=`Hook timed out after ${p} seconds.`;s?.recordWarning(e.hookFailed,n,{"hook.reason":`timeout`,"hook.exit_code":x??-1}),c(`[pi-hook] advisory hook timed out: ${t.command}\n${_}`),T({failure:{command:t.command,message:n,reason:`timeout`}})},D=setTimeout(()=>{y=!0,C(`SIGTERM`),S=setTimeout(()=>{w()&&C(`SIGKILL`),E()},2e3)},p*1e3);h.stdout?.on(`data`,e=>{g+=e.toString()}),h.stderr?.on(`data`,e=>{_+=e.toString()}),h.once(`error`,n=>{y||(s?.recordError(e.hookFailed,n,{"hook.reason":`spawn_failed`}),c(`[pi-hook] advisory hook failed: ${n.message}\n`),T({failure:{command:t.command,message:n.message,reason:`spawn_failed`}}))}),h.once(`exit`,n=>{if(b=!0,x=n,y)return;if(n!==0){let r=_.trim()||`Advisory hook exited with code ${n??`unknown`}`;s?.recordWarning(e.hookFailed,r,{"hook.reason":`non_zero_exit`,"hook.exit_code":n??-1}),c(`[pi-hook] advisory hook failed (${n}): ${t.command}\n${_}`),T({failure:{command:t.command,message:r,reason:`non_zero_exit`}});return}let i=g.trim().split(r).reverse().find(e=>e.startsWith(`{`));if(!i){T();return}try{T({decision:JSON.parse(i)})}catch(n){s?.recordWarning(e.hookFailed,n,{"hook.reason":`invalid_json`}),c(`[pi-hook] advisory hook returned invalid JSON: ${t.command}\n`),T({failure:{command:t.command,message:n instanceof Error?n.message:String(n),reason:`invalid_json`}})}}),h.stdin?.end(JSON.stringify(d))})}}}export{a as createBashHookRunner};
|
|
2
|
-
//# sourceMappingURL=hookRunner.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hookRunner.mjs","names":["spawn","spawnProcess"],"sources":["../../src/adapters/hookRunner.ts"],"sourcesContent":["import { spawn as spawnProcess } from 'node:child_process';\nimport type {\n HookCommand,\n HookDecision,\n HookOutcome,\n HookPayload,\n HookRunOptions,\n HookRunner,\n} from '../types/hooks.ts';\nimport { HOOK_TELEMETRY_EVENT, type HookTelemetry } from '../types/telemetry.ts';\n\nconst HOOK_SHELL = '/bin/bash';\nconst HOOK_SHELL_COMMAND_FLAG = '-c';\nconst HOOK_TERMINATION_GRACE_MS = 2_000;\nconst DEFAULT_HOOK_TIMEOUT_SECONDS = 10;\nconst MILLISECONDS_PER_SECOND = 1_000;\nconst PROCESS_NOT_FOUND_ERROR = 'ESRCH';\nconst WINDOWS_PLATFORM = 'win32';\nconst UNKNOWN_EXIT_CODE = -1;\nconst JSON_LINE_START = '{';\nconst LINE_BREAK = /\\r?\\n/;\n\nexport interface BashHookRunnerOptions {\n telemetry?: HookTelemetry;\n env?: NodeJS.ProcessEnv;\n platform?: NodeJS.Platform;\n spawn?: typeof spawnProcess;\n warn?: (message: string) => void;\n}\n\nfunction errorCode(error: unknown): string | undefined {\n return error instanceof Error && 'code' in error ? String(error.code) : undefined;\n}\n\n/**\n * Runs advisory hook commands through bash and reports what each one decided.\n *\n * A hook is a command the repository owns, so it is spawned in its own process\n * group and terminated as one: a hook that starts a server and stalls should\n * not leave the server behind when the timeout fires.\n */\nexport function createBashHookRunner(options: BashHookRunnerOptions = {}): HookRunner {\n const spawn = options.spawn ?? spawnProcess;\n const telemetry = options.telemetry;\n const warn = options.warn ?? ((message: string) => void process.stderr.write(message));\n const useProcessGroup = (options.platform ?? process.platform) !== WINDOWS_PLATFORM;\n\n const signalOwnedProcess = (\n pid: number | undefined,\n kill: (signal: NodeJS.Signals) => void,\n ): ((signal: NodeJS.Signals) => void) => {\n return (signal) => {\n try {\n if (useProcessGroup && pid !== undefined) {\n process.kill(-pid, signal);\n return;\n }\n kill(signal);\n } catch (error) {\n if (errorCode(error) !== PROCESS_NOT_FOUND_ERROR) {\n process.emitWarning(`Could not signal repository hook process: ${String(error)}`);\n }\n }\n };\n };\n\n return {\n run(hook: HookCommand, payload: HookPayload, runOptions: HookRunOptions): Promise<HookOutcome> {\n const timeoutSeconds = hook.timeout ?? DEFAULT_HOOK_TIMEOUT_SECONDS;\n const environment = options.env ?? process.env;\n return new Promise((resolve) => {\n // -c, not -lc. Hooks run on every tool call, and a login shell would\n // source the developer's profile each time: per-call latency plus hook\n // behavior that varies with their dotfiles. The child inherits the\n // environment below, so it keeps the PATH the launcher started with.\n const child = spawn(HOOK_SHELL, [HOOK_SHELL_COMMAND_FLAG, hook.command], {\n cwd: runOptions.repoRoot,\n env: {\n ...environment,\n CLAUDE_PROJECT_DIR: runOptions.repoRoot,\n CODEX_REPO_ROOT: runOptions.repoRoot,\n ORIGINAL_REPO_PATH: environment.ORIGINAL_REPO_PATH ?? runOptions.repoRoot,\n ...(runOptions.pluginRoot ? { CLAUDE_PLUGIN_ROOT: runOptions.pluginRoot } : {}),\n },\n stdio: ['pipe', 'pipe', 'pipe'],\n detached: useProcessGroup,\n });\n let stdout = '';\n let stderr = '';\n let settled = false;\n let timedOut = false;\n let childExited = false;\n let timeoutExitCode: number | null = null;\n let escalationTimer: NodeJS.Timeout | undefined;\n\n const signal = signalOwnedProcess(child.pid, (value) => child.kill(value));\n\n const ownedProcessIsAlive = (): boolean => {\n if (!useProcessGroup || child.pid === undefined) return !childExited;\n try {\n process.kill(-child.pid, 0);\n return true;\n } catch (error) {\n return errorCode(error) !== PROCESS_NOT_FOUND_ERROR;\n }\n };\n\n const finish = (outcome: HookOutcome = {}): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n if (escalationTimer) clearTimeout(escalationTimer);\n resolve(outcome);\n };\n\n const finishTimeout = (): void => {\n const message = `Hook timed out after ${timeoutSeconds} seconds.`;\n void telemetry?.recordWarning(HOOK_TELEMETRY_EVENT.hookFailed, message, {\n 'hook.reason': 'timeout',\n 'hook.exit_code': timeoutExitCode ?? UNKNOWN_EXIT_CODE,\n });\n warn(`[pi-hook] advisory hook timed out: ${hook.command}\\n${stderr}`);\n finish({ failure: { command: hook.command, message, reason: 'timeout' } });\n };\n\n const timer = setTimeout(() => {\n timedOut = true;\n signal('SIGTERM');\n escalationTimer = setTimeout(() => {\n if (ownedProcessIsAlive()) signal('SIGKILL');\n finishTimeout();\n }, HOOK_TERMINATION_GRACE_MS);\n }, timeoutSeconds * MILLISECONDS_PER_SECOND);\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString();\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n child.once('error', (error: Error) => {\n if (timedOut) return;\n // A guardrail that never ran is indistinguishable from one that\n // passed, which is the whole reason these are worth reporting.\n void telemetry?.recordError(HOOK_TELEMETRY_EVENT.hookFailed, error, { 'hook.reason': 'spawn_failed' });\n warn(`[pi-hook] advisory hook failed: ${error.message}\\n`);\n finish({ failure: { command: hook.command, message: error.message, reason: 'spawn_failed' } });\n });\n child.once('exit', (code: number | null) => {\n childExited = true;\n timeoutExitCode = code;\n if (timedOut) return;\n if (code !== 0) {\n const message = stderr.trim() || `Advisory hook exited with code ${code ?? 'unknown'}`;\n void telemetry?.recordWarning(HOOK_TELEMETRY_EVENT.hookFailed, message, {\n 'hook.reason': 'non_zero_exit',\n 'hook.exit_code': code ?? UNKNOWN_EXIT_CODE,\n });\n warn(`[pi-hook] advisory hook failed (${code}): ${hook.command}\\n${stderr}`);\n finish({ failure: { command: hook.command, message, reason: 'non_zero_exit' } });\n return;\n }\n const jsonLine = stdout\n .trim()\n .split(LINE_BREAK)\n .reverse()\n .find((line) => line.startsWith(JSON_LINE_START));\n if (!jsonLine) {\n finish();\n return;\n }\n try {\n finish({ decision: JSON.parse(jsonLine) as HookDecision });\n } catch (error) {\n // The hook ran and had an opinion, and it was dropped.\n void telemetry?.recordWarning(HOOK_TELEMETRY_EVENT.hookFailed, error, { 'hook.reason': 'invalid_json' });\n warn(`[pi-hook] advisory hook returned invalid JSON: ${hook.command}\\n`);\n finish({\n failure: {\n command: hook.command,\n message: error instanceof Error ? error.message : String(error),\n reason: 'invalid_json',\n },\n });\n }\n });\n child.stdin?.end(JSON.stringify(payload));\n });\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
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;
|
|
2
|
-
//# sourceMappingURL=extension.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
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,14 +0,0 @@
|
|
|
1
|
-
import { HookDocumentReader, HookRunner } from "../../types/hooks.cjs";
|
|
2
|
-
import { HookTelemetry } from "../../types/telemetry.cjs";
|
|
3
|
-
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
//#region src/adapters/pi/extension.d.ts
|
|
5
|
-
interface HookExtensionOptions {
|
|
6
|
-
telemetry?: HookTelemetry;
|
|
7
|
-
runner?: HookRunner;
|
|
8
|
-
documents?: HookDocumentReader;
|
|
9
|
-
}
|
|
10
|
-
/** The package's single standard Pi factory. */
|
|
11
|
-
declare function hookExtension(pi: ExtensionAPI, options?: HookExtensionOptions): Promise<void>;
|
|
12
|
-
//#endregion
|
|
13
|
-
export { HookExtensionOptions, hookExtension as default, hookExtension };
|
|
14
|
-
//# sourceMappingURL=extension.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,14 +0,0 @@
|
|
|
1
|
-
import { HookDocumentReader, HookRunner } from "../../types/hooks.mjs";
|
|
2
|
-
import { HookTelemetry } from "../../types/telemetry.mjs";
|
|
3
|
-
import { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
4
|
-
//#region src/adapters/pi/extension.d.ts
|
|
5
|
-
interface HookExtensionOptions {
|
|
6
|
-
telemetry?: HookTelemetry;
|
|
7
|
-
runner?: HookRunner;
|
|
8
|
-
documents?: HookDocumentReader;
|
|
9
|
-
}
|
|
10
|
-
/** The package's single standard Pi factory. */
|
|
11
|
-
declare function hookExtension(pi: ExtensionAPI, options?: HookExtensionOptions): Promise<void>;
|
|
12
|
-
//#endregion
|
|
13
|
-
export { HookExtensionOptions, hookExtension as default, hookExtension };
|
|
14
|
-
//# sourceMappingURL=extension.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,2 +0,0 @@
|
|
|
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};
|
|
2
|
-
//# sourceMappingURL=extension.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
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,8 +0,0 @@
|
|
|
1
|
-
const e=require("../../services/hookRegistry.cjs"),t=require("../../services/hookDecisions.cjs"),n=require("../../services/hookPayload.cjs"),r=require("../../services/pluginHooks.cjs"),i=require("../../types/hooks.cjs"),a=`repository-hooks`,o={deliverAs:`steer`};async function s(t,n,i,a){let o=t.config().harness,s=o.root??n.cwd,[c,l]=await Promise.all([t.documents.registry(s),t.documents.plugins(o.pluginHooks)]),u=[...e.selectRegistryHooks(c.entries,{event:i,toolName:a,allowedGroups:o.hookGroups,inSubagent:!!process.env.PI_SUBAGENT_CHILD}),...r.selectPluginHooks(l.documents,i,a)];return{repoRoot:s,sessionId:n.sessionManager.getSessionId(),hooks:u,failures:[...c.failure?[c.failure]:[],...l.failures]}}async function c(e,t,n){let i=e.config().harness,a=await e.documents.plugins(i.pluginHooks);return{repoRoot:i.root??t.cwd,sessionId:t.sessionManager.getSessionId(),hooks:r.selectPluginHooks(a.documents,n),failures:a.failures}}async function l(e,t,n,r,i,a){let o=[];try{for(let[s,c]of n.hooks.entries())t.hasUI&&t.ui.setStatus(i,`${a} (${s+1}/${n.hooks.length})...`),o.push(await e.runner.run(c.hook,r,{repoRoot:n.repoRoot,pluginRoot:c.root}))}finally{t.hasUI&&t.ui.setStatus(i,void 0)}return o}function u(e,n){return[...e.failures,...t.failuresFrom(n)]}function d(e,n){n.length!==0&&e.sendMessage({customType:`repository-hook-failure`,content:t.hookFailureMessage(n),display:!0},o)}async function f(e,r,c,f,p=()=>!0){f?.throwIfAborted();let m=await s(r,c,i.HOOK_EVENT.sessionStart);f?.throwIfAborted();let h=await l(r,c,m,n.sessionHookPayload(m.sessionId,m.repoRoot),`${a}:${m.sessionId}:start`,`Running session-start hooks`);if(f?.throwIfAborted(),!p())return;d(e,u(m,h));let g=t.additionalContextsFrom(t.decisionsFrom(h)).join(`
|
|
2
|
-
|
|
3
|
-
`);g&&e.sendMessage({customType:`repository-hook-context`,content:g,display:!0},o)}function p(e,t){e.on(`session_start`,(n,r)=>{let i=t();if(!i?.isCurrent())return;let{readiness:a,session:o}=i;return a?a.start(r,(t,n)=>f(e,o,r,t,()=>i.isCurrent()&&n())):f(e,o,r)})}function m(e,t){e.on(`before_agent_start`,async(e,n)=>{let r=t();r?.isCurrent()&&await r.readiness?.wait(n)})}function h(e,r){e.on(`tool_call`,async(o,c)=>{let f=r();if(!f?.isCurrent()||(await f.readiness?.wait(c),!f.isCurrent()))return;let p=await s(f.session,c,i.HOOK_EVENT.preToolUse,o.toolName);if(!f.isCurrent())return;let m=n.toolHookPayload(o,i.HOOK_EVENT.preToolUse,p.repoRoot,p.sessionId),h=await l(f.session,c,p,m,`${a}:${o.toolCallId}:pre`,`Running pre-tool hooks for ${o.toolName}`);if(!f.isCurrent())return;let g=t.decisionsFrom(h);d(e,u(p,h));let _=g.find(t.isDenied);if(_)return{block:!0,reason:t.decisionReason(_)??`Blocked by repository hook`};let v=t.additionalContextsFrom(g).join(`
|
|
4
|
-
|
|
5
|
-
`);return v?{block:!0,reason:v}:void 0})}function g(e,r){e.on(`tool_result`,async(e,o)=>{let c=r();if(!c?.isCurrent()||(await c.readiness?.wait(o),!c.isCurrent()))return;let d=await s(c.session,o,i.HOOK_EVENT.postToolUse,e.toolName);if(!c.isCurrent())return;let f=n.toolHookPayload(e,i.HOOK_EVENT.postToolUse,d.repoRoot,d.sessionId),p=await l(c.session,o,d,f,`${a}:${e.toolCallId}:post`,`Running post-tool hooks for ${e.toolName}`);if(!c.isCurrent())return;let m=t.decisionsFrom(p),h=u(d,p),g=t.toolResultMessages(m);if(h.length>0&&g.push(t.hookFailureMessage(h)),g.length!==0)return{content:[...e.content,{type:`text`,text:g.join(`
|
|
6
|
-
|
|
7
|
-
`)}],isError:e.isError||m.some(t.isDenied)}})}function _(e,t){e.on(`agent_settled`,async(e,r)=>{let o=t();if(!o?.isCurrent()||(await o.readiness?.wait(r),!o.isCurrent()))return;let c=await s(o.session,r,i.HOOK_EVENT.stop);o.isCurrent()&&await l(o.session,r,c,n.sessionHookPayload(c.sessionId,c.repoRoot),`${a}:${c.sessionId}:stop`,`Running stop hooks`)})}function v(e,t){return[p,m,h,g,_].map(n=>(n(e,t),()=>void 0))}async function y(e,t){let r=await c(e,t,i.HOOK_EVENT.sessionEnd);await l(e,t,r,n.sessionHookPayload(r.sessionId,r.repoRoot),`${a}:${r.sessionId}:end`,`Running session-end hooks`)}exports.registerHookHandlers=v,exports.runSessionEndHooks=y;
|
|
8
|
-
//# sourceMappingURL=hookHandlers.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hookHandlers.cjs","names":["selectRegistryHooks","selectPluginHooks","failuresFrom","hookFailureMessage","HOOK_EVENT","sessionHookPayload","additionalContextsFrom","decisionsFrom","toolHookPayload","isDenied","decisionReason","toolResultMessages"],"sources":["../../../src/adapters/pi/hookHandlers.ts"],"sourcesContent":["import type { DoomConfigContext } from '@agimon-ai/doompi-config/types';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n additionalContextsFrom,\n decisionReason,\n decisionsFrom,\n failuresFrom,\n hookFailureMessage,\n isDenied,\n toolResultMessages,\n} from '../../services/hookDecisions.ts';\nimport { sessionHookPayload, toolHookPayload } from '../../services/hookPayload.ts';\nimport { selectRegistryHooks } from '../../services/hookRegistry.ts';\nimport { selectPluginHooks } from '../../services/pluginHooks.ts';\nimport {\n HOOK_EVENT,\n type HookDocumentReader,\n type HookFailure,\n type HookOutcome,\n type HookPayload,\n type HookRunner,\n type HookToolEvent,\n type ResolvedHook,\n} from '../../types/hooks.ts';\n\nconst STATUS_PREFIX = 'repository-hooks';\nconst FAILURE_MESSAGE_TYPE = 'repository-hook-failure';\nconst CONTEXT_MESSAGE_TYPE = 'repository-hook-context';\nconst STEER = { deliverAs: 'steer' } as const;\nconst BLOCKED_BY_HOOK = 'Blocked by repository hook';\nconst SUBAGENT_ENVIRONMENT_FLAG = 'PI_SUBAGENT_CHILD';\nconst CONTEXT_SEPARATOR = '\\n\\n';\n\n/** The two collaborators a dispatch needs, both replaceable in tests. */\nexport interface HookSession {\n config(): DoomConfigContext;\n runner: HookRunner;\n documents: HookDocumentReader;\n}\n\n/** Package-scoped startup ordering supplied by the standard Pi adapter. */\nexport interface HookReadinessGate {\n start(\n context: ExtensionContext,\n operation: (signal: AbortSignal, isCurrent: () => boolean) => Promise<void>,\n ): void | Promise<void>;\n wait(context: ExtensionContext): Promise<void>;\n}\n\n/** One dependency-complete Hook runtime owned by a reactive Cordis fiber. */\nexport interface HookRuntime {\n readonly session: HookSession;\n readonly readiness?: HookReadinessGate;\n isCurrent(): boolean;\n}\n\nexport type HookRuntimeResolver = () => HookRuntime | undefined;\n\n/** Everything one dispatch resolved before it ran anything. */\ninterface HookDispatch {\n repoRoot: string;\n sessionId: string;\n hooks: ResolvedHook[];\n failures: HookFailure[];\n}\n\n/**\n * Registry rows plus plugin hooks for one event, in that order.\n *\n * Both sources are read on every dispatch because either can change mid-session:\n * /mode switches the selected groups and a plugin can rewrite its own config.\n */\nasync function resolveHooks(\n session: HookSession,\n ctx: ExtensionContext,\n eventName: string,\n toolName?: string,\n): Promise<HookDispatch> {\n const harness = session.config().harness;\n const repoRoot = harness.root ?? ctx.cwd;\n const [registry, plugins] = await Promise.all([\n session.documents.registry(repoRoot),\n session.documents.plugins(harness.pluginHooks),\n ]);\n const hooks = [\n ...selectRegistryHooks(registry.entries, {\n event: eventName,\n toolName,\n allowedGroups: harness.hookGroups,\n inSubagent: Boolean(process.env[SUBAGENT_ENVIRONMENT_FLAG]),\n }),\n ...selectPluginHooks(plugins.documents, eventName, toolName),\n ];\n return {\n repoRoot,\n sessionId: ctx.sessionManager.getSessionId(),\n hooks,\n failures: [...(registry.failure ? [registry.failure] : []), ...plugins.failures],\n };\n}\n\n/** Session end is plugin-only: the registry has no binding for it. */\nasync function resolvePluginHooks(\n session: HookSession,\n ctx: ExtensionContext,\n eventName: string,\n): Promise<HookDispatch> {\n const harness = session.config().harness;\n const plugins = await session.documents.plugins(harness.pluginHooks);\n return {\n repoRoot: harness.root ?? ctx.cwd,\n sessionId: ctx.sessionManager.getSessionId(),\n hooks: selectPluginHooks(plugins.documents, eventName),\n failures: plugins.failures,\n };\n}\n\nasync function runHooks(\n session: HookSession,\n ctx: ExtensionContext,\n dispatch: HookDispatch,\n payload: HookPayload,\n statusKey: string,\n statusLabel: string,\n): Promise<HookOutcome[]> {\n const outcomes: HookOutcome[] = [];\n try {\n for (const [index, resolved] of dispatch.hooks.entries()) {\n if (ctx.hasUI) ctx.ui.setStatus(statusKey, `${statusLabel} (${index + 1}/${dispatch.hooks.length})...`);\n outcomes.push(\n await session.runner.run(resolved.hook, payload, { repoRoot: dispatch.repoRoot, pluginRoot: resolved.root }),\n );\n }\n } finally {\n if (ctx.hasUI) ctx.ui.setStatus(statusKey, undefined);\n }\n return outcomes;\n}\n\nfunction allFailures(dispatch: HookDispatch, outcomes: ReadonlyArray<HookOutcome>): HookFailure[] {\n return [...dispatch.failures, ...failuresFrom(outcomes)];\n}\n\nfunction steerHookFailures(pi: ExtensionAPI, failures: ReadonlyArray<HookFailure>): void {\n if (failures.length === 0) return;\n pi.sendMessage({ customType: FAILURE_MESSAGE_TYPE, content: hookFailureMessage(failures), display: true }, STEER);\n}\n\nasync function runSessionStartHooks(\n pi: ExtensionAPI,\n session: HookSession,\n ctx: ExtensionContext,\n signal?: AbortSignal,\n isCurrent: () => boolean = () => true,\n): Promise<void> {\n signal?.throwIfAborted();\n const dispatch = await resolveHooks(session, ctx, HOOK_EVENT.sessionStart);\n signal?.throwIfAborted();\n const outcomes = await runHooks(\n session,\n ctx,\n dispatch,\n sessionHookPayload(dispatch.sessionId, dispatch.repoRoot),\n `${STATUS_PREFIX}:${dispatch.sessionId}:start`,\n 'Running session-start hooks',\n );\n signal?.throwIfAborted();\n if (!isCurrent()) return;\n steerHookFailures(pi, allFailures(dispatch, outcomes));\n const context = additionalContextsFrom(decisionsFrom(outcomes)).join(CONTEXT_SEPARATOR);\n if (context) pi.sendMessage({ customType: CONTEXT_MESSAGE_TYPE, content: context, display: true }, STEER);\n}\n\nfunction registerSessionStart(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('session_start', (_event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return undefined;\n const { readiness, session } = runtime;\n if (readiness) {\n return readiness.start(ctx, (signal, isReady) =>\n runSessionStartHooks(pi, session, ctx, signal, () => runtime.isCurrent() && isReady()),\n );\n }\n return runSessionStartHooks(pi, session, ctx);\n });\n}\n\nfunction registerBeforeAgentStart(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('before_agent_start', async (_event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return;\n await runtime.readiness?.wait(ctx);\n });\n}\n\nfunction registerToolCall(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('tool_call', async (event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return undefined;\n await runtime.readiness?.wait(ctx);\n if (!runtime.isCurrent()) return undefined;\n const dispatch = await resolveHooks(runtime.session, ctx, HOOK_EVENT.preToolUse, event.toolName);\n if (!runtime.isCurrent()) return undefined;\n const payload = toolHookPayload(\n event as HookToolEvent,\n HOOK_EVENT.preToolUse,\n dispatch.repoRoot,\n dispatch.sessionId,\n );\n const outcomes = await runHooks(\n runtime.session,\n ctx,\n dispatch,\n payload,\n `${STATUS_PREFIX}:${event.toolCallId}:pre`,\n `Running pre-tool hooks for ${event.toolName}`,\n );\n if (!runtime.isCurrent()) return undefined;\n const decisions = decisionsFrom(outcomes);\n steerHookFailures(pi, allFailures(dispatch, outcomes));\n const denied = decisions.find(isDenied);\n if (denied) return { block: true, reason: decisionReason(denied) ?? BLOCKED_BY_HOOK };\n const context = additionalContextsFrom(decisions).join(CONTEXT_SEPARATOR);\n return context ? { block: true, reason: context } : undefined;\n });\n}\n\nfunction registerToolResult(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('tool_result', async (event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return undefined;\n await runtime.readiness?.wait(ctx);\n if (!runtime.isCurrent()) return undefined;\n const dispatch = await resolveHooks(runtime.session, ctx, HOOK_EVENT.postToolUse, event.toolName);\n if (!runtime.isCurrent()) return undefined;\n const payload = toolHookPayload(\n event as HookToolEvent,\n HOOK_EVENT.postToolUse,\n dispatch.repoRoot,\n dispatch.sessionId,\n );\n const outcomes = await runHooks(\n runtime.session,\n ctx,\n dispatch,\n payload,\n `${STATUS_PREFIX}:${event.toolCallId}:post`,\n `Running post-tool hooks for ${event.toolName}`,\n );\n if (!runtime.isCurrent()) return undefined;\n const decisions = decisionsFrom(outcomes);\n const failures = allFailures(dispatch, outcomes);\n const messages = toolResultMessages(decisions);\n if (failures.length > 0) messages.push(hookFailureMessage(failures));\n if (messages.length === 0) return undefined;\n // The result is appended to rather than replaced, so the tool's own output\n // still reaches the model alongside whatever the hook had to say.\n return {\n content: [...event.content, { type: 'text' as const, text: messages.join(CONTEXT_SEPARATOR) }],\n isError: event.isError || decisions.some(isDenied),\n };\n });\n}\n\nfunction registerAgentSettled(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('agent_settled', async (_event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return;\n await runtime.readiness?.wait(ctx);\n if (!runtime.isCurrent()) return;\n const dispatch = await resolveHooks(runtime.session, ctx, HOOK_EVENT.stop);\n if (!runtime.isCurrent()) return;\n // skipInSubagent on the workflow-stop binding keeps subagents from closing\n // the parent's workflow step.\n await runHooks(\n runtime.session,\n ctx,\n dispatch,\n sessionHookPayload(dispatch.sessionId, dispatch.repoRoot),\n `${STATUS_PREFIX}:${dispatch.sessionId}:stop`,\n 'Running stop hooks',\n );\n });\n}\n\n/**\n * Registers the four in-session lifecycle events and returns one disposer each.\n *\n * Pi owns handler deregistration across a reload, so each disposer only has to\n * drop this package's own reference to the session.\n */\nexport function registerHookHandlers(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): Array<() => void> {\n return [\n registerSessionStart,\n registerBeforeAgentStart,\n registerToolCall,\n registerToolResult,\n registerAgentSettled,\n ].map((register) => {\n register(pi, resolveRuntime);\n return () => undefined;\n });\n}\n\n/** Runs the plugin SessionEnd hooks while the session is still usable. */\nexport async function runSessionEndHooks(session: HookSession, ctx: ExtensionContext): Promise<void> {\n const dispatch = await resolvePluginHooks(session, ctx, HOOK_EVENT.sessionEnd);\n await runHooks(\n session,\n ctx,\n dispatch,\n sessionHookPayload(dispatch.sessionId, dispatch.repoRoot),\n `${STATUS_PREFIX}:${dispatch.sessionId}:end`,\n 'Running session-end hooks',\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import{selectRegistryHooks as e}from"../../services/hookRegistry.mjs";import{additionalContextsFrom as t,decisionReason as n,decisionsFrom as r,failuresFrom as i,hookFailureMessage as a,isDenied as o,toolResultMessages as s}from"../../services/hookDecisions.mjs";import{sessionHookPayload as c,toolHookPayload as l}from"../../services/hookPayload.mjs";import{selectPluginHooks as u}from"../../services/pluginHooks.mjs";import{HOOK_EVENT as d}from"../../types/hooks.mjs";const f=`repository-hooks`,p={deliverAs:`steer`};async function m(t,n,r,i){let a=t.config().harness,o=a.root??n.cwd,[s,c]=await Promise.all([t.documents.registry(o),t.documents.plugins(a.pluginHooks)]),l=[...e(s.entries,{event:r,toolName:i,allowedGroups:a.hookGroups,inSubagent:!!process.env.PI_SUBAGENT_CHILD}),...u(c.documents,r,i)];return{repoRoot:o,sessionId:n.sessionManager.getSessionId(),hooks:l,failures:[...s.failure?[s.failure]:[],...c.failures]}}async function h(e,t,n){let r=e.config().harness,i=await e.documents.plugins(r.pluginHooks);return{repoRoot:r.root??t.cwd,sessionId:t.sessionManager.getSessionId(),hooks:u(i.documents,n),failures:i.failures}}async function g(e,t,n,r,i,a){let o=[];try{for(let[s,c]of n.hooks.entries())t.hasUI&&t.ui.setStatus(i,`${a} (${s+1}/${n.hooks.length})...`),o.push(await e.runner.run(c.hook,r,{repoRoot:n.repoRoot,pluginRoot:c.root}))}finally{t.hasUI&&t.ui.setStatus(i,void 0)}return o}function _(e,t){return[...e.failures,...i(t)]}function v(e,t){t.length!==0&&e.sendMessage({customType:`repository-hook-failure`,content:a(t),display:!0},p)}async function y(e,n,i,a,o=()=>!0){a?.throwIfAborted();let s=await m(n,i,d.sessionStart);a?.throwIfAborted();let l=await g(n,i,s,c(s.sessionId,s.repoRoot),`${f}:${s.sessionId}:start`,`Running session-start hooks`);if(a?.throwIfAborted(),!o())return;v(e,_(s,l));let u=t(r(l)).join(`
|
|
2
|
-
|
|
3
|
-
`);u&&e.sendMessage({customType:`repository-hook-context`,content:u,display:!0},p)}function b(e,t){e.on(`session_start`,(n,r)=>{let i=t();if(!i?.isCurrent())return;let{readiness:a,session:o}=i;return a?a.start(r,(t,n)=>y(e,o,r,t,()=>i.isCurrent()&&n())):y(e,o,r)})}function x(e,t){e.on(`before_agent_start`,async(e,n)=>{let r=t();r?.isCurrent()&&await r.readiness?.wait(n)})}function S(e,i){e.on(`tool_call`,async(a,s)=>{let c=i();if(!c?.isCurrent()||(await c.readiness?.wait(s),!c.isCurrent()))return;let u=await m(c.session,s,d.preToolUse,a.toolName);if(!c.isCurrent())return;let p=l(a,d.preToolUse,u.repoRoot,u.sessionId),h=await g(c.session,s,u,p,`${f}:${a.toolCallId}:pre`,`Running pre-tool hooks for ${a.toolName}`);if(!c.isCurrent())return;let y=r(h);v(e,_(u,h));let b=y.find(o);if(b)return{block:!0,reason:n(b)??`Blocked by repository hook`};let x=t(y).join(`
|
|
4
|
-
|
|
5
|
-
`);return x?{block:!0,reason:x}:void 0})}function C(e,t){e.on(`tool_result`,async(e,n)=>{let i=t();if(!i?.isCurrent()||(await i.readiness?.wait(n),!i.isCurrent()))return;let c=await m(i.session,n,d.postToolUse,e.toolName);if(!i.isCurrent())return;let u=l(e,d.postToolUse,c.repoRoot,c.sessionId),p=await g(i.session,n,c,u,`${f}:${e.toolCallId}:post`,`Running post-tool hooks for ${e.toolName}`);if(!i.isCurrent())return;let h=r(p),v=_(c,p),y=s(h);if(v.length>0&&y.push(a(v)),y.length!==0)return{content:[...e.content,{type:`text`,text:y.join(`
|
|
6
|
-
|
|
7
|
-
`)}],isError:e.isError||h.some(o)}})}function w(e,t){e.on(`agent_settled`,async(e,n)=>{let r=t();if(!r?.isCurrent()||(await r.readiness?.wait(n),!r.isCurrent()))return;let i=await m(r.session,n,d.stop);r.isCurrent()&&await g(r.session,n,i,c(i.sessionId,i.repoRoot),`${f}:${i.sessionId}:stop`,`Running stop hooks`)})}function T(e,t){return[b,x,S,C,w].map(n=>(n(e,t),()=>void 0))}async function E(e,t){let n=await h(e,t,d.sessionEnd);await g(e,t,n,c(n.sessionId,n.repoRoot),`${f}:${n.sessionId}:end`,`Running session-end hooks`)}export{T as registerHookHandlers,E as runSessionEndHooks};
|
|
8
|
-
//# sourceMappingURL=hookHandlers.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hookHandlers.mjs","names":[],"sources":["../../../src/adapters/pi/hookHandlers.ts"],"sourcesContent":["import type { DoomConfigContext } from '@agimon-ai/doompi-config/types';\nimport type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';\nimport {\n additionalContextsFrom,\n decisionReason,\n decisionsFrom,\n failuresFrom,\n hookFailureMessage,\n isDenied,\n toolResultMessages,\n} from '../../services/hookDecisions.ts';\nimport { sessionHookPayload, toolHookPayload } from '../../services/hookPayload.ts';\nimport { selectRegistryHooks } from '../../services/hookRegistry.ts';\nimport { selectPluginHooks } from '../../services/pluginHooks.ts';\nimport {\n HOOK_EVENT,\n type HookDocumentReader,\n type HookFailure,\n type HookOutcome,\n type HookPayload,\n type HookRunner,\n type HookToolEvent,\n type ResolvedHook,\n} from '../../types/hooks.ts';\n\nconst STATUS_PREFIX = 'repository-hooks';\nconst FAILURE_MESSAGE_TYPE = 'repository-hook-failure';\nconst CONTEXT_MESSAGE_TYPE = 'repository-hook-context';\nconst STEER = { deliverAs: 'steer' } as const;\nconst BLOCKED_BY_HOOK = 'Blocked by repository hook';\nconst SUBAGENT_ENVIRONMENT_FLAG = 'PI_SUBAGENT_CHILD';\nconst CONTEXT_SEPARATOR = '\\n\\n';\n\n/** The two collaborators a dispatch needs, both replaceable in tests. */\nexport interface HookSession {\n config(): DoomConfigContext;\n runner: HookRunner;\n documents: HookDocumentReader;\n}\n\n/** Package-scoped startup ordering supplied by the standard Pi adapter. */\nexport interface HookReadinessGate {\n start(\n context: ExtensionContext,\n operation: (signal: AbortSignal, isCurrent: () => boolean) => Promise<void>,\n ): void | Promise<void>;\n wait(context: ExtensionContext): Promise<void>;\n}\n\n/** One dependency-complete Hook runtime owned by a reactive Cordis fiber. */\nexport interface HookRuntime {\n readonly session: HookSession;\n readonly readiness?: HookReadinessGate;\n isCurrent(): boolean;\n}\n\nexport type HookRuntimeResolver = () => HookRuntime | undefined;\n\n/** Everything one dispatch resolved before it ran anything. */\ninterface HookDispatch {\n repoRoot: string;\n sessionId: string;\n hooks: ResolvedHook[];\n failures: HookFailure[];\n}\n\n/**\n * Registry rows plus plugin hooks for one event, in that order.\n *\n * Both sources are read on every dispatch because either can change mid-session:\n * /mode switches the selected groups and a plugin can rewrite its own config.\n */\nasync function resolveHooks(\n session: HookSession,\n ctx: ExtensionContext,\n eventName: string,\n toolName?: string,\n): Promise<HookDispatch> {\n const harness = session.config().harness;\n const repoRoot = harness.root ?? ctx.cwd;\n const [registry, plugins] = await Promise.all([\n session.documents.registry(repoRoot),\n session.documents.plugins(harness.pluginHooks),\n ]);\n const hooks = [\n ...selectRegistryHooks(registry.entries, {\n event: eventName,\n toolName,\n allowedGroups: harness.hookGroups,\n inSubagent: Boolean(process.env[SUBAGENT_ENVIRONMENT_FLAG]),\n }),\n ...selectPluginHooks(plugins.documents, eventName, toolName),\n ];\n return {\n repoRoot,\n sessionId: ctx.sessionManager.getSessionId(),\n hooks,\n failures: [...(registry.failure ? [registry.failure] : []), ...plugins.failures],\n };\n}\n\n/** Session end is plugin-only: the registry has no binding for it. */\nasync function resolvePluginHooks(\n session: HookSession,\n ctx: ExtensionContext,\n eventName: string,\n): Promise<HookDispatch> {\n const harness = session.config().harness;\n const plugins = await session.documents.plugins(harness.pluginHooks);\n return {\n repoRoot: harness.root ?? ctx.cwd,\n sessionId: ctx.sessionManager.getSessionId(),\n hooks: selectPluginHooks(plugins.documents, eventName),\n failures: plugins.failures,\n };\n}\n\nasync function runHooks(\n session: HookSession,\n ctx: ExtensionContext,\n dispatch: HookDispatch,\n payload: HookPayload,\n statusKey: string,\n statusLabel: string,\n): Promise<HookOutcome[]> {\n const outcomes: HookOutcome[] = [];\n try {\n for (const [index, resolved] of dispatch.hooks.entries()) {\n if (ctx.hasUI) ctx.ui.setStatus(statusKey, `${statusLabel} (${index + 1}/${dispatch.hooks.length})...`);\n outcomes.push(\n await session.runner.run(resolved.hook, payload, { repoRoot: dispatch.repoRoot, pluginRoot: resolved.root }),\n );\n }\n } finally {\n if (ctx.hasUI) ctx.ui.setStatus(statusKey, undefined);\n }\n return outcomes;\n}\n\nfunction allFailures(dispatch: HookDispatch, outcomes: ReadonlyArray<HookOutcome>): HookFailure[] {\n return [...dispatch.failures, ...failuresFrom(outcomes)];\n}\n\nfunction steerHookFailures(pi: ExtensionAPI, failures: ReadonlyArray<HookFailure>): void {\n if (failures.length === 0) return;\n pi.sendMessage({ customType: FAILURE_MESSAGE_TYPE, content: hookFailureMessage(failures), display: true }, STEER);\n}\n\nasync function runSessionStartHooks(\n pi: ExtensionAPI,\n session: HookSession,\n ctx: ExtensionContext,\n signal?: AbortSignal,\n isCurrent: () => boolean = () => true,\n): Promise<void> {\n signal?.throwIfAborted();\n const dispatch = await resolveHooks(session, ctx, HOOK_EVENT.sessionStart);\n signal?.throwIfAborted();\n const outcomes = await runHooks(\n session,\n ctx,\n dispatch,\n sessionHookPayload(dispatch.sessionId, dispatch.repoRoot),\n `${STATUS_PREFIX}:${dispatch.sessionId}:start`,\n 'Running session-start hooks',\n );\n signal?.throwIfAborted();\n if (!isCurrent()) return;\n steerHookFailures(pi, allFailures(dispatch, outcomes));\n const context = additionalContextsFrom(decisionsFrom(outcomes)).join(CONTEXT_SEPARATOR);\n if (context) pi.sendMessage({ customType: CONTEXT_MESSAGE_TYPE, content: context, display: true }, STEER);\n}\n\nfunction registerSessionStart(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('session_start', (_event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return undefined;\n const { readiness, session } = runtime;\n if (readiness) {\n return readiness.start(ctx, (signal, isReady) =>\n runSessionStartHooks(pi, session, ctx, signal, () => runtime.isCurrent() && isReady()),\n );\n }\n return runSessionStartHooks(pi, session, ctx);\n });\n}\n\nfunction registerBeforeAgentStart(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('before_agent_start', async (_event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return;\n await runtime.readiness?.wait(ctx);\n });\n}\n\nfunction registerToolCall(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('tool_call', async (event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return undefined;\n await runtime.readiness?.wait(ctx);\n if (!runtime.isCurrent()) return undefined;\n const dispatch = await resolveHooks(runtime.session, ctx, HOOK_EVENT.preToolUse, event.toolName);\n if (!runtime.isCurrent()) return undefined;\n const payload = toolHookPayload(\n event as HookToolEvent,\n HOOK_EVENT.preToolUse,\n dispatch.repoRoot,\n dispatch.sessionId,\n );\n const outcomes = await runHooks(\n runtime.session,\n ctx,\n dispatch,\n payload,\n `${STATUS_PREFIX}:${event.toolCallId}:pre`,\n `Running pre-tool hooks for ${event.toolName}`,\n );\n if (!runtime.isCurrent()) return undefined;\n const decisions = decisionsFrom(outcomes);\n steerHookFailures(pi, allFailures(dispatch, outcomes));\n const denied = decisions.find(isDenied);\n if (denied) return { block: true, reason: decisionReason(denied) ?? BLOCKED_BY_HOOK };\n const context = additionalContextsFrom(decisions).join(CONTEXT_SEPARATOR);\n return context ? { block: true, reason: context } : undefined;\n });\n}\n\nfunction registerToolResult(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('tool_result', async (event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return undefined;\n await runtime.readiness?.wait(ctx);\n if (!runtime.isCurrent()) return undefined;\n const dispatch = await resolveHooks(runtime.session, ctx, HOOK_EVENT.postToolUse, event.toolName);\n if (!runtime.isCurrent()) return undefined;\n const payload = toolHookPayload(\n event as HookToolEvent,\n HOOK_EVENT.postToolUse,\n dispatch.repoRoot,\n dispatch.sessionId,\n );\n const outcomes = await runHooks(\n runtime.session,\n ctx,\n dispatch,\n payload,\n `${STATUS_PREFIX}:${event.toolCallId}:post`,\n `Running post-tool hooks for ${event.toolName}`,\n );\n if (!runtime.isCurrent()) return undefined;\n const decisions = decisionsFrom(outcomes);\n const failures = allFailures(dispatch, outcomes);\n const messages = toolResultMessages(decisions);\n if (failures.length > 0) messages.push(hookFailureMessage(failures));\n if (messages.length === 0) return undefined;\n // The result is appended to rather than replaced, so the tool's own output\n // still reaches the model alongside whatever the hook had to say.\n return {\n content: [...event.content, { type: 'text' as const, text: messages.join(CONTEXT_SEPARATOR) }],\n isError: event.isError || decisions.some(isDenied),\n };\n });\n}\n\nfunction registerAgentSettled(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): void {\n pi.on('agent_settled', async (_event, ctx) => {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return;\n await runtime.readiness?.wait(ctx);\n if (!runtime.isCurrent()) return;\n const dispatch = await resolveHooks(runtime.session, ctx, HOOK_EVENT.stop);\n if (!runtime.isCurrent()) return;\n // skipInSubagent on the workflow-stop binding keeps subagents from closing\n // the parent's workflow step.\n await runHooks(\n runtime.session,\n ctx,\n dispatch,\n sessionHookPayload(dispatch.sessionId, dispatch.repoRoot),\n `${STATUS_PREFIX}:${dispatch.sessionId}:stop`,\n 'Running stop hooks',\n );\n });\n}\n\n/**\n * Registers the four in-session lifecycle events and returns one disposer each.\n *\n * Pi owns handler deregistration across a reload, so each disposer only has to\n * drop this package's own reference to the session.\n */\nexport function registerHookHandlers(pi: ExtensionAPI, resolveRuntime: HookRuntimeResolver): Array<() => void> {\n return [\n registerSessionStart,\n registerBeforeAgentStart,\n registerToolCall,\n registerToolResult,\n registerAgentSettled,\n ].map((register) => {\n register(pi, resolveRuntime);\n return () => undefined;\n });\n}\n\n/** Runs the plugin SessionEnd hooks while the session is still usable. */\nexport async function runSessionEndHooks(session: HookSession, ctx: ExtensionContext): Promise<void> {\n const dispatch = await resolvePluginHooks(session, ctx, HOOK_EVENT.sessionEnd);\n await runHooks(\n session,\n ctx,\n dispatch,\n sessionHookPayload(dispatch.sessionId, dispatch.repoRoot),\n `${STATUS_PREFIX}:${dispatch.sessionId}:end`,\n 'Running session-end hooks',\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
let e=require("@agimon-ai/doompi-telemetry");function t(t={}){let n=(0,e.createDoomTelemetry)({serviceName:`doom-pi-hook`,packageName:`@agimon-ai/doompi-hook`,cwd:t.cwd,workspaceRoot:t.workspaceRoot,env:t.env,telemetryFactory:t.telemetryFactory,warn:t.warn,enableLogs:!0,enableTraces:!0});return{recordError:(e,t,r)=>n.recordError(e,t,r),recordWarning:(e,t,r)=>n.recordWarning(e,t,r)}}exports.createHookTelemetry=t;
|
|
2
|
-
//# sourceMappingURL=logSinkTelemetry.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logSinkTelemetry.cjs","names":["createDoomTelemetry"],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"sourcesContent":["import { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { HookTelemetry } from '../../types/telemetry.ts';\n\nconst SERVICE_NAME = 'doom-pi-hook';\nconst PACKAGE_NAME = '@agimon-ai/doompi-hook';\n\nexport interface HookTelemetryOptions {\n cwd?: string;\n workspaceRoot?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;\n warn?: (message: string) => void;\n}\n\nexport function createHookTelemetry(options: HookTelemetryOptions = {}): HookTelemetry {\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: options.cwd,\n workspaceRoot: options.workspaceRoot,\n env: options.env,\n telemetryFactory: options.telemetryFactory,\n warn: options.warn,\n enableLogs: true,\n enableTraces: true,\n });\n return {\n recordError: (event, error, attributes) => telemetry.recordError(event, error, attributes),\n recordWarning: (event, error, attributes) => telemetry.recordWarning(event, error, attributes),\n };\n}\n"],"mappings":"6CAcA,SAAgB,EAAoB,EAAgC,CAAC,EAAkB,CACrF,IAAM,GAAA,EAA2BA,EAAAA,oBAAAA,CAAoB,CACnD,YAAa,eACb,YAAa,yBACb,IAAK,EAAQ,IACb,cAAe,EAAQ,cACvB,IAAK,EAAQ,IACb,iBAAkB,EAAQ,iBAC1B,KAAM,EAAQ,KACd,WAAY,GACZ,aAAc,EAChB,CAAC,EACD,MAAO,CACL,aAAc,EAAO,EAAO,IAAe,EAAU,YAAY,EAAO,EAAO,CAAU,EACzF,eAAgB,EAAO,EAAO,IAAe,EAAU,cAAc,EAAO,EAAO,CAAU,CAC/F,CACF"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { HookTelemetry } from "../../types/telemetry.cjs";
|
|
2
|
-
import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
|
|
3
|
-
//#region src/adapters/telemetry/logSinkTelemetry.d.ts
|
|
4
|
-
interface HookTelemetryOptions {
|
|
5
|
-
cwd?: string;
|
|
6
|
-
workspaceRoot?: string;
|
|
7
|
-
env?: NodeJS.ProcessEnv;
|
|
8
|
-
telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;
|
|
9
|
-
warn?: (message: string) => void;
|
|
10
|
-
}
|
|
11
|
-
declare function createHookTelemetry(options?: HookTelemetryOptions): HookTelemetry;
|
|
12
|
-
//#endregion
|
|
13
|
-
export { HookTelemetryOptions, createHookTelemetry };
|
|
14
|
-
//# sourceMappingURL=logSinkTelemetry.d.cts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,14 +0,0 @@
|
|
|
1
|
-
import { HookTelemetry } from "../../types/telemetry.mjs";
|
|
2
|
-
import { DoomTelemetryOptions } from "@agimon-ai/doompi-telemetry";
|
|
3
|
-
//#region src/adapters/telemetry/logSinkTelemetry.d.ts
|
|
4
|
-
interface HookTelemetryOptions {
|
|
5
|
-
cwd?: string;
|
|
6
|
-
workspaceRoot?: string;
|
|
7
|
-
env?: NodeJS.ProcessEnv;
|
|
8
|
-
telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;
|
|
9
|
-
warn?: (message: string) => void;
|
|
10
|
-
}
|
|
11
|
-
declare function createHookTelemetry(options?: HookTelemetryOptions): HookTelemetry;
|
|
12
|
-
//#endregion
|
|
13
|
-
export { HookTelemetryOptions, createHookTelemetry };
|
|
14
|
-
//# sourceMappingURL=logSinkTelemetry.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
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,2 +0,0 @@
|
|
|
1
|
-
import{createDoomTelemetry as e}from"@agimon-ai/doompi-telemetry";function t(t={}){let n=e({serviceName:`doom-pi-hook`,packageName:`@agimon-ai/doompi-hook`,cwd:t.cwd,workspaceRoot:t.workspaceRoot,env:t.env,telemetryFactory:t.telemetryFactory,warn:t.warn,enableLogs:!0,enableTraces:!0});return{recordError:(e,t,r)=>n.recordError(e,t,r),recordWarning:(e,t,r)=>n.recordWarning(e,t,r)}}export{t as createHookTelemetry};
|
|
2
|
-
//# sourceMappingURL=logSinkTelemetry.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logSinkTelemetry.mjs","names":[],"sources":["../../../src/adapters/telemetry/logSinkTelemetry.ts"],"sourcesContent":["import { createDoomTelemetry, type DoomTelemetry, type DoomTelemetryOptions } from '@agimon-ai/doompi-telemetry';\nimport type { HookTelemetry } from '../../types/telemetry.ts';\n\nconst SERVICE_NAME = 'doom-pi-hook';\nconst PACKAGE_NAME = '@agimon-ai/doompi-hook';\n\nexport interface HookTelemetryOptions {\n cwd?: string;\n workspaceRoot?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: NonNullable<DoomTelemetryOptions['telemetryFactory']>;\n warn?: (message: string) => void;\n}\n\nexport function createHookTelemetry(options: HookTelemetryOptions = {}): HookTelemetry {\n const telemetry: DoomTelemetry = createDoomTelemetry({\n serviceName: SERVICE_NAME,\n packageName: PACKAGE_NAME,\n cwd: options.cwd,\n workspaceRoot: options.workspaceRoot,\n env: options.env,\n telemetryFactory: options.telemetryFactory,\n warn: options.warn,\n enableLogs: true,\n enableTraces: true,\n });\n return {\n recordError: (event, error, attributes) => telemetry.recordError(event, error, attributes),\n recordWarning: (event, error, attributes) => telemetry.recordWarning(event, error, attributes),\n };\n}\n"],"mappings":"kEAcA,SAAgB,EAAoB,EAAgC,CAAC,EAAkB,CACrF,IAAM,EAA2B,EAAoB,CACnD,YAAa,eACb,YAAa,yBACb,IAAK,EAAQ,IACb,cAAe,EAAQ,cACvB,IAAK,EAAQ,IACb,iBAAkB,EAAQ,iBAC1B,KAAM,EAAQ,KACd,WAAY,GACZ,aAAc,EAChB,CAAC,EACD,MAAO,CACL,aAAc,EAAO,EAAO,IAAe,EAAU,YAAY,EAAO,EAAO,CAAU,EACzF,eAAgB,EAAO,EAAO,IAAe,EAAU,cAAc,EAAO,EAAO,CAAU,CAC/F,CACF"}
|
package/dist/extensions/pi.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("../adapters/pi/extension.cjs");exports.default=e.default,exports.hookExtension=e.default;
|
package/dist/extensions/pi.d.cts
DELETED
package/dist/extensions/pi.d.mts
DELETED
package/dist/extensions/pi.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import e from"../adapters/pi/extension.mjs";export{e as default,e as hookExtension};
|
package/dist/index.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./types/telemetry.cjs"),t=require("./services/toolNames.cjs"),n=require("./services/hookRegistry.cjs"),r=require("./adapters/hookDocuments.cjs"),i=require("./adapters/hookRunner.cjs"),a=require("./adapters/telemetry/logSinkTelemetry.cjs"),o=require("./services/hookDecisions.cjs"),s=require("./services/hookPayload.cjs"),c=require("./services/pluginHooks.cjs"),l=require("./types/hooks.cjs"),u=require("./adapters/pi/extension.cjs");exports.HOOK_EVENT=l.HOOK_EVENT,exports.HOOK_TELEMETRY_EVENT=e.HOOK_TELEMETRY_EVENT,exports.additionalContextsFrom=o.additionalContextsFrom,exports.createBashHookRunner=i.createBashHookRunner,exports.createHookDocumentReader=r.createHookDocumentReader,exports.createHookTelemetry=a.createHookTelemetry,exports.decisionReason=o.decisionReason,exports.decisionsFrom=o.decisionsFrom,exports.failuresFrom=o.failuresFrom,exports.hookExtension=u.default,exports.hookFailureMessage=o.hookFailureMessage,exports.isDenied=o.isDenied,exports.matchesTool=t.matchesTool,exports.registryCacheKey=n.registryCacheKey,exports.registryEntries=n.registryEntries,exports.selectPluginHooks=c.selectPluginHooks,exports.selectRegistryHooks=n.selectRegistryHooks,exports.sessionHookPayload=s.sessionHookPayload,exports.toClaudeToolName=t.toClaudeToolName,exports.toolHookPayload=s.toolHookPayload,exports.toolResultMessages=o.toolResultMessages;
|