@agimon-ai/po-hook 0.0.0-alpha.2 → 0.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/dist/authoring.cjs +2 -2
- package/dist/authoring.cjs.map +1 -1
- package/dist/authoring.d.mts +1 -1
- package/dist/authoring.d.mts.map +1 -1
- package/dist/authoring.mjs +2 -2
- package/dist/authoring.mjs.map +1 -1
- package/dist/extensions/mcp.cjs.map +1 -1
- package/dist/extensions/mcp.d.mts +1 -1
- package/dist/extensions/mcp.mjs.map +1 -1
- package/dist/extensions/server.cjs +13 -13
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.d.mts +1 -1
- package/dist/extensions/server.mjs +18 -18
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/{hookModules-DSheklXp.cjs → hookModules-BCecT6-e.cjs} +5 -5
- package/dist/hookModules-BCecT6-e.cjs.map +1 -0
- package/dist/{hookModules-GoRDG8mg.mjs → hookModules-ClLNr9FP.mjs} +7 -7
- package/dist/hookModules-ClLNr9FP.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.mts +9 -9
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -2
- package/llms.txt +2 -2
- package/package.json +10 -10
- package/src/prompts/po-author-hook/SKILL.md +2 -2
- package/dist/hookModules-DSheklXp.cjs.map +0 -1
- package/dist/hookModules-GoRDG8mg.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.mjs","names":["rootSession","hookAgentEnd","hookAgentSettled","hookBeforeAgentStart","hookSessionShutdown","hookSessionStart","hookToolCall","hookToolResult","resourcePoAuthorHook"],"sources":["../../src/constants/hookHandlers.ts","../../src/services/hookDispatch/index.ts","../../src/services/hookRuntime/type.ts","../../src/services/hookRuntime/index.ts","../../src/services/serverHooks/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/agent-end.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/agent-settled.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/before-agent-start.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-start.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/tool-call.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/tool-result.server.ts","../../src/constants/hook.ts","../../src/extensions/workspaces/sessions/(backend)/resource/po-author-hook.server.ts","../../generated/server.ts"],"sourcesContent":["export const STATUS_PREFIX = 'repository-hooks';\nexport const FAILURE_MESSAGE_TYPE = 'repository-hook-failure';\nexport const CONTEXT_MESSAGE_TYPE = 'repository-hook-context';\n/** A Stop hook refused the stop; its reason sends the agent back to work. */\nexport const STOP_BLOCK_MESSAGE_TYPE = 'repository-hook-stop-block';\nexport const STEER = { deliverAs: 'steer' } as const;\n/** Starts a new turn on a settled agent, so a refused stop is not a silent one. */\nexport const FOLLOW_UP_TURN = { deliverAs: 'followUp', triggerTurn: true } as const;\n/** Adds a message to a settled agent's conversation without starting a turn. */\nexport const NO_TURN = { triggerTurn: false } as const;\n/**\n * How many stops in a row a Stop hook may refuse before the agent is left to\n * stop. A hook that never lets go would otherwise send it back forever.\n */\nexport const MAX_STOP_REFUSALS = 5;\n/** Claude's Stop hook input field: true when the agent is already continuing because of a Stop hook. */\nexport const STOP_HOOK_ACTIVE_FIELD = 'stop_hook_active';\nexport const BLOCKED_BY_HOOK = 'Blocked by repository hook';\nexport const SUBAGENT_ENVIRONMENT_FLAG = 'PI_SUBAGENT_CHILD';\nexport const CONTEXT_SEPARATOR = '\\n\\n';\n","import type { ToolResultEvent } from '@earendil-works/pi-coding-agent';\n\nimport { BLOCKED_BY_HOOK, CONTEXT_SEPARATOR } from '../../constants/hookHandlers';\nimport { HOOK_EVENT } from '../../constants/hooks';\nimport type { HookFailure, HookToolEvent, ResolvedHook } from '../../types/hooks';\nimport {\n additionalContextsFrom,\n decisionReason,\n hookFailureMessage,\n isDenied,\n toolResultMessages,\n} from '../hookDecisions';\nimport { sessionHookPayload, toolHookPayload } from '../hookPayload';\nimport { selectRegistryHooks } from '../hookRegistry';\nimport type { HookSession } from '../hookRuntime/type';\nimport { selectPluginHooks } from '../pluginHooks';\nimport type { HookDispatchRequest, HookDispatchResult, HookDispatchScope } from './type';\n\nfunction isJson(value: unknown, ancestors = new Set<object>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || ancestors.has(value)) return false;\n ancestors.add(value);\n const valid =\n (Array.isArray(value) || Object.getPrototypeOf(value) === Object.prototype) &&\n Object.values(value).every((entry) => isJson(entry, ancestors));\n ancestors.delete(value);\n return valid;\n}\n\nfunction commandFailure(row: ResolvedHook, error: unknown): HookFailure {\n return {\n command: row.hook.command ?? row.hook.module,\n message: error instanceof Error ? error.message : String(error),\n reason: 'hook_execution',\n };\n}\n\n/** Registry rows interleave command and module bindings, followed by plugin commands. */\nexport async function dispatchHooks(\n session: HookSession,\n scope: HookDispatchScope,\n request: HookDispatchRequest,\n): Promise<HookDispatchResult> {\n const signal = scope.operationSignal ? AbortSignal.any([scope.signal, scope.operationSignal]) : scope.signal;\n signal.throwIfAborted();\n const harness = session.config().harness;\n const plugins = await session.documents.plugins(harness.pluginHooks);\n const registry =\n request.eventName === HOOK_EVENT.sessionEnd\n ? { entries: [], failure: undefined }\n : await session.documents.registry(scope.repoRoot);\n signal.throwIfAborted();\n const event = request.event;\n const toolName = event && 'toolName' in event ? event.toolName : undefined;\n const hooks = [\n ...selectRegistryHooks(registry.entries, {\n event: request.eventName,\n toolName,\n allowedGroups: harness.hookGroups,\n inSubagent: scope.isSubagent,\n }),\n ...selectPluginHooks(plugins.documents, request.eventName, toolName),\n ];\n const decisions: HookDispatchResult['decisions'] = [];\n const failures = [...(registry.failure ? [registry.failure] : []), ...plugins.failures];\n let toolCall: HookDispatchResult['toolCall'];\n let patchedResult = false;\n for (const [index, row] of hooks.entries()) {\n signal.throwIfAborted();\n request.progress?.(index, hooks.length);\n if (row.hook.command === undefined) {\n if (!event) continue;\n let proposed: typeof event;\n try {\n proposed = structuredClone(event);\n } catch (error) {\n failures.push(commandFailure(row, error));\n continue;\n }\n const outcome = await session.modules.invoke(row, proposed, scope, scope.operationSignal);\n signal.throwIfAborted();\n if (outcome.failure) {\n failures.push(outcome.failure);\n continue;\n }\n // A failed or late invocation cannot mutate live tool input or output.\n try {\n if (event.type === 'tool_call' && proposed.type === 'tool_call') {\n if (\n typeof proposed.input !== 'object' ||\n proposed.input === null ||\n Array.isArray(proposed.input) ||\n !isJson(proposed.input)\n ) {\n throw new Error('Hook tool input must be a JSON object.');\n }\n const input = structuredClone(proposed.input);\n for (const key of Object.keys(event.input)) delete (event.input as Record<string, unknown>)[key];\n Object.assign(event.input, input);\n if (outcome.result && 'block' in outcome.result && outcome.result.block) {\n toolCall = { block: true, reason: outcome.result.reason ?? BLOCKED_BY_HOOK };\n break;\n }\n } else if (event.type === 'tool_result' && outcome.result) {\n const patch = structuredClone(outcome.result);\n if ('content' in patch && patch.content !== undefined) event.content = patch.content;\n if ('details' in patch) event.details = patch.details;\n if ('isError' in patch && patch.isError !== undefined) event.isError = patch.isError;\n patchedResult = true;\n }\n } catch (error) {\n failures.push(commandFailure(row, error));\n }\n continue;\n }\n const payload =\n event && 'toolName' in event\n ? toolHookPayload(event as HookToolEvent, request.eventName, scope.repoRoot, scope.sessionId, {\n parentSessionId: scope.parentSessionId,\n agent: scope.agent,\n })\n : sessionHookPayload(scope.sessionId, scope.repoRoot);\n // The catch covers hook execution only. Readiness, host effects and abort errors propagate.\n let outcome;\n try {\n outcome = await session.runner.run(\n row.hook,\n { ...payload, ...request.extraPayload },\n {\n repoRoot: scope.repoRoot,\n pluginRoot: row.root,\n },\n );\n } catch (error) {\n failures.push(commandFailure(row, error));\n continue;\n }\n signal.throwIfAborted();\n if (outcome.failure) failures.push(outcome.failure);\n if (!outcome.decision) continue;\n decisions.push(outcome.decision);\n if (event?.type === 'tool_result') {\n const messages = toolResultMessages([outcome.decision]);\n if (messages.length > 0)\n event.content = [...event.content, { type: 'text', text: messages.join(CONTEXT_SEPARATOR) }];\n if (isDenied(outcome.decision)) event.isError = true;\n patchedResult ||= messages.length > 0 || isDenied(outcome.decision);\n }\n if (isDenied(outcome.decision)) {\n if (event?.type === 'tool_call')\n toolCall = {\n block: true,\n reason: decisionReason(outcome.decision) ?? BLOCKED_BY_HOOK,\n };\n break;\n }\n }\n if (event?.type === 'tool_call' && !toolCall) {\n const context = additionalContextsFrom(decisions).join(CONTEXT_SEPARATOR);\n if (context) toolCall = { block: true, reason: context };\n }\n if (event?.type === 'tool_result' && failures.length > 0) {\n event.content = [...event.content, { type: 'text', text: hookFailureMessage(failures) }];\n patchedResult = true;\n }\n return {\n decisions,\n failures,\n ...(toolCall ? { toolCall } : {}),\n ...(event?.type === 'tool_result' && patchedResult\n ? {\n toolResult: {\n content: (event as ToolResultEvent).content,\n details: (event as ToolResultEvent).details,\n isError: event.isError,\n },\n }\n : {}),\n };\n}\n","import type { DoomConfigContext } from '@agimon-ai/po-config/types';\nimport type { DoomChildSessionHooks } from '@agimon-ai/po-core/childSession';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport type { HookContext } from '../../types/hookModule';\nimport type { HookDocumentReader, HookRunner } from '../../types/hooks';\nimport type { HookTelemetry } from '../../types/telemetry';\nimport type { HookModules } from '../hookModules/type';\n\nexport const DOOM_HOOK_SESSION_SERVICE = 'doom/hook-session';\nexport interface HookExtensionOptions {\n telemetry?: HookTelemetry;\n runner?: HookRunner;\n documents?: HookDocumentReader;\n}\n\n/** One host session owns its module registry and lifetime; children borrow only immutable config. */\nexport interface HookSession {\n config(): DoomConfigContext;\n prepare(isSubagent?: boolean): Promise<void>;\n readonly runner: HookRunner;\n readonly documents: HookDocumentReader;\n readonly modules: HookModules;\n readonly signal: AbortSignal;\n readonly parentContext?: Omit<HookContext, 'signal'>;\n}\n\n/** One dependency-complete Hook runtime owned by a reactive Cordis fiber. */\nexport interface HookRuntime {\n readonly session: HookSession;\n readonly childHooks: DoomChildSessionHooks;\n isCurrent(): boolean;\n}\n\nexport type HookRuntimeResolver = () => HookRuntime | undefined;\n\nexport interface HookRuntimeBinding extends HookRuntime {\n dispose(): Promise<void>;\n}\nexport interface HookBinding {\n readonly plugin: (this: void, context: Context) => void;\n readonly runtime: HookRuntimeResolver;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'doom/hook-session': HookRuntime;\n }\n}\n","import { requireDoomConfigContext } from '@agimon-ai/po-config/piContext';\nimport type { DoomConfigContext } from '@agimon-ai/po-config/types';\nimport { DOOM_CHILD_SESSION_HOOKS_SERVICE, type DoomChildSessionHooks } from '@agimon-ai/po-core/childSession';\nimport { DOOM_CONFIG_SERVICE } from '@agimon-ai/po-core/config';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ToolCallEvent, ToolResultEvent } from '@earendil-works/pi-coding-agent';\n\nimport { HOOK_EVENT } from '../../constants/hooks';\nimport type { HookContext, JsonValue } from '../../types/hookModule';\nimport type { HookTelemetry } from '../../types/telemetry';\nimport { hookFailureMessage } from '../hookDecisions';\nimport { dispatchHooks } from '../hookDispatch';\nimport { createHookDocumentReader } from '../hookDocuments';\nimport { createHookModules } from '../hookModules';\nimport { createBashHookRunner } from '../hookRunner';\nimport { createHookTelemetry } from '../hookTelemetry';\nimport { DOOM_HOOK_SESSION_SERVICE, type HookSession } from './type';\nimport type { HookBinding, HookExtensionOptions, HookRuntimeBinding } from './type';\n\nexport function createHookSession(\n config: () => DoomConfigContext,\n options: HookExtensionOptions,\n signal: AbortSignal,\n): 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 const modules = createHookModules({ descriptor: config().harness.hookModules });\n const documents = options.documents ?? createHookDocumentReader({ telemetry: requireTelemetry() });\n let preparation: Promise<void> | undefined;\n return {\n config,\n signal,\n modules,\n prepare(isSubagent = false) {\n preparation ??= (async () => {\n const harness = config().harness;\n if (harness.hooks === false) return;\n const registry = await documents.registry(harness.root ?? process.cwd());\n // Registry read failures keep their existing advisory dispatch policy.\n if (registry.failure) return;\n const allowed = harness.hookGroups === undefined ? undefined : new Set(harness.hookGroups);\n const rows = registry.entries\n .filter((row) => row.core || !allowed || allowed.has(row.groupId))\n .filter((row) => !(isSubagent && row.skipInSubagent));\n await modules.validate(rows);\n })();\n return preparation;\n },\n runner: options.runner ?? createBashHookRunner({ telemetry: requireTelemetry() }),\n documents,\n };\n}\n\nfunction childHooksFor(parent: HookSession): DoomChildSessionHooks {\n return {\n bind(scope) {\n // Children retain their launch selection and artifacts, even if the parent reloads.\n const config = structuredClone(parent.config());\n const controller = new AbortController();\n const signal = AbortSignal.any([controller.signal, scope.signal]);\n const session = createHookSession(() => config, { runner: parent.runner, documents: parent.documents }, signal);\n let disposal: Promise<void> | undefined;\n const context = (): HookContext => {\n const sessionId = scope.sessionId();\n if (!sessionId) throw new Error('Child hook identity is unavailable before runtime startup.');\n return {\n sessionId,\n parentSessionId: scope.request.parentSessionId,\n agent: scope.request.agent,\n isSubagent: true,\n cwd: scope.request.cwd,\n repoRoot: config.harness.root ?? scope.request.cwd,\n signal,\n sendMessage: (text, delivery) => scope.sendMessage(text, delivery),\n appendCustomEntry: (type, data) => scope.appendCustomEntry(type, data),\n };\n };\n return {\n async beforeTool(event, execution) {\n await session.prepare(true);\n const native = {\n type: 'tool_call',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n input: event.args,\n } as ToolCallEvent;\n const result = await dispatchHooks(\n session,\n { ...context(), operationSignal: execution.abortSignal },\n {\n eventName: HOOK_EVENT.preToolUse,\n event: native,\n },\n );\n if (result.failures.length > 0) await scope.sendMessage(hookFailureMessage(result.failures), 'steer');\n return result.toolCall?.block\n ? { block: { reason: result.toolCall.reason ?? 'Blocked by repository hook' } }\n : { args: native.input as Record<string, JsonValue> };\n },\n async afterTool(event, execution) {\n const native = {\n type: 'tool_result',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n input: event.args,\n content: event.content,\n details: event.details,\n isError: event.isError,\n } as ToolResultEvent;\n const result = await dispatchHooks(\n session,\n { ...context(), operationSignal: execution.abortSignal },\n {\n eventName: HOOK_EVENT.postToolUse,\n event: native,\n },\n );\n return result.toolResult\n ? {\n content: result.toolResult.content,\n details: result.toolResult.details as JsonValue | undefined,\n isError: result.toolResult.isError,\n }\n : undefined;\n },\n dispose() {\n disposal ??= (async () => {\n controller.abort();\n await session.modules.dispose();\n })();\n return disposal;\n },\n };\n },\n };\n}\n\nexport function createHookRuntime(\n cordis: Context,\n options: HookExtensionOptions,\n parentContext?: Omit<HookContext, 'signal'>,\n lifetimeSignal?: AbortSignal,\n): HookRuntimeBinding {\n const controller = new AbortController();\n const signal = lifetimeSignal ? AbortSignal.any([controller.signal, lifetimeSignal]) : controller.signal;\n const session: HookSession = {\n ...createHookSession(() => requireDoomConfigContext(cordis), options, signal),\n parentContext,\n };\n let disposal: Promise<void> | undefined;\n let active = true;\n return {\n session,\n childHooks: childHooksFor(session),\n isCurrent: () => active && !signal.aborted,\n dispose() {\n active = false;\n controller.abort();\n disposal ??= session.modules.dispose();\n return disposal;\n },\n };\n}\n\nexport function createHookBinding(\n options: HookExtensionOptions,\n parentContext?: Omit<HookContext, 'signal'>,\n lifetimeSignal?: AbortSignal,\n): HookBinding {\n let runtime: HookRuntimeBinding | undefined;\n return {\n plugin(cordis) {\n cordis.inject([DOOM_CONFIG_SERVICE], (configContext) => {\n const binding = createHookRuntime(configContext, options, parentContext, lifetimeSignal);\n runtime = binding;\n configContext.provide(DOOM_CHILD_SESSION_HOOKS_SERVICE, binding.childHooks);\n configContext.provide(DOOM_HOOK_SESSION_SERVICE, binding);\n return async () => {\n if (runtime === binding) runtime = undefined;\n await binding.dispose();\n };\n });\n },\n runtime: () => runtime,\n };\n}\n","import {\n DoomHeadlessPromptAdmissionError,\n type DoomHeadlessExecutionContext,\n type DoomHeadlessHook,\n} from '@agimon-ai/po-core/headless';\nimport type { ToolCallEvent, ToolResultEvent } from '@earendil-works/pi-coding-agent';\n\nimport {\n BLOCKED_BY_HOOK,\n STATUS_PREFIX,\n SUBAGENT_ENVIRONMENT_FLAG,\n CONTEXT_SEPARATOR,\n FAILURE_MESSAGE_TYPE,\n MAX_STOP_REFUSALS,\n STOP_HOOK_ACTIVE_FIELD,\n} from '../../constants/hookHandlers';\nimport { HOOK_EVENT } from '../../constants/hooks';\nimport type { HookNativeEvent } from '../../types/hookModule';\nimport { additionalContextsFrom, decisionReason, hookFailureMessage, isDenied } from '../hookDecisions';\nimport { dispatchHooks } from '../hookDispatch';\nimport type { HookDispatchScope } from '../hookDispatch/type';\nimport type { HookRuntime, HookRuntimeResolver } from '../hookRuntime/type';\n\nfunction hookEntry(event: Readonly<Record<string, unknown>>): Record<string, unknown> {\n return { version: 1, event: typeof event.type === 'string' ? event.type : 'headless-hook', data: event };\n}\n\nfunction scopeFor(runtime: HookRuntime, execution: DoomHeadlessExecutionContext): HookDispatchScope {\n return {\n sessionId: execution.sessionId,\n isSubagent: Boolean(execution.environment[SUBAGENT_ENVIRONMENT_FLAG]),\n cwd: execution.cwd,\n repoRoot: execution.repoRoot,\n model: execution.model,\n signal: runtime.session.signal,\n operationSignal: execution.signal,\n async sendMessage(text, delivery) {\n if (!execution.session.admitPrompt)\n throw new DoomHeadlessPromptAdmissionError('The session cannot admit a hook prompt.');\n await execution.session.admitPrompt(text, delivery);\n },\n appendCustomEntry: (type, data) => execution.session.appendCustomEntry(type, data),\n };\n}\n\n/** One native owner dispatches lifecycle and tool rows for this session. */\nexport function createServerHooks(resolveRuntime: HookRuntimeResolver) {\n const startups = new WeakMap<HookRuntime, Promise<void>>();\n const shutdowns = new WeakMap<HookRuntime, Promise<void>>();\n const refusals = new WeakMap<HookRuntime, number>();\n async function runLifecycle(\n runtime: HookRuntime,\n execution: DoomHeadlessExecutionContext,\n eventName: string,\n event?: Readonly<Record<string, unknown>>,\n extraPayload?: Record<string, unknown>,\n ) {\n const key = `${STATUS_PREFIX}:${execution.sessionId}:${eventName}`;\n try {\n return await dispatchHooks(runtime.session, scopeFor(runtime, execution), {\n eventName,\n event: event as HookNativeEvent | undefined,\n extraPayload,\n progress: (index, total) =>\n execution.client.setStatus(key, `Running ${eventName} hooks (${index + 1}/${total})...`),\n });\n } finally {\n execution.client.setStatus(key, undefined);\n }\n }\n function start(\n runtime: HookRuntime,\n execution: DoomHeadlessExecutionContext,\n event: Readonly<Record<string, unknown>> = { type: 'session_start' },\n ) {\n let startup = startups.get(runtime);\n if (!startup) {\n startup = (async () => {\n const scope = scopeFor(runtime, execution);\n await runtime.session.prepare(scope.isSubagent);\n if (scope.isSubagent) return;\n const result = await runLifecycle(runtime, execution, HOOK_EVENT.sessionStart, {\n ...event,\n type: 'session_start',\n });\n if (!runtime.isCurrent()) return;\n if (result.failures.length) await scope.sendMessage(hookFailureMessage(result.failures), 'steer');\n const context = additionalContextsFrom(result.decisions).join(CONTEXT_SEPARATOR);\n if (context) await scope.sendMessage(context, 'steer');\n })();\n startups.set(runtime, startup);\n }\n return startup;\n }\n const sessionStart: DoomHeadlessHook<'session_start'> = {\n event: 'session_start',\n async handle(event, execution) {\n const runtime = resolveRuntime();\n if (runtime?.isCurrent()) await start(runtime, execution, event);\n },\n };\n const agentEnd: DoomHeadlessHook<'agent_end'> = {\n event: 'agent_end',\n async handle(event, execution) {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent() || scopeFor(runtime, execution).isSubagent) return;\n await start(runtime, execution);\n const count = refusals.get(runtime) ?? 0;\n const result = await runLifecycle(\n runtime,\n execution,\n HOOK_EVENT.stop,\n { ...event, type: 'agent_settled' },\n { [STOP_HOOK_ACTIVE_FIELD]: count > 0 },\n );\n if (!runtime.isCurrent()) return;\n const appendFailure = async (text: string) => {\n if (!execution.session.appendMessage) throw new Error('The session cannot append hook diagnostics.');\n await execution.session.appendMessage({ type: FAILURE_MESSAGE_TYPE, text });\n };\n if (result.failures.length) await appendFailure(hookFailureMessage(result.failures));\n const reason = decisionReason(result.decisions.find(isDenied));\n if (!reason) {\n refusals.set(runtime, 0);\n return;\n }\n if (count >= MAX_STOP_REFUSALS) {\n refusals.set(runtime, 0);\n await appendFailure(\n `A Stop hook refused ${String(MAX_STOP_REFUSALS)} stops in a row, so the agent stops here. Its last reason: ${reason}`,\n );\n return;\n }\n // Advance only after successful admission. Admission does not await the successor turn.\n await scopeFor(runtime, execution).sendMessage(reason, 'followUp');\n refusals.set(runtime, count + 1);\n },\n };\n const beforeAgentStart: DoomHeadlessHook<'before_agent_start'> = {\n event: 'before_agent_start',\n async handle(event, execution) {\n const runtime = resolveRuntime();\n if (runtime?.isCurrent()) await start(runtime, execution);\n await execution.session.appendCustomEntry('doom-hook', hookEntry(event));\n },\n };\n const toolCall: DoomHeadlessHook<'tool_call'> = {\n event: 'tool_call',\n async handle(event, execution) {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return;\n const scope = scopeFor(runtime, execution);\n try {\n await start(runtime, execution);\n } catch (error) {\n return { block: { reason: error instanceof Error ? error.message : String(error) } };\n }\n const native = {\n type: 'tool_call',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n input: event.args,\n } as ToolCallEvent;\n const key = `${STATUS_PREFIX}:${native.toolCallId}:pre`;\n try {\n const result = await dispatchHooks(runtime.session, scope, {\n eventName: HOOK_EVENT.preToolUse,\n event: native,\n progress: (index, total) =>\n execution.client.setStatus(key, `Running pre-tool hooks for ${native.toolName} (${index + 1}/${total})...`),\n });\n if (result.failures.length > 0) await scope.sendMessage(hookFailureMessage(result.failures), 'steer');\n return result.toolCall?.block\n ? { block: { reason: result.toolCall.reason ?? BLOCKED_BY_HOOK } }\n : { args: native.input };\n } finally {\n execution.client.setStatus(key, undefined);\n }\n },\n };\n const toolResult: DoomHeadlessHook<'tool_result'> = {\n event: 'tool_result',\n async handle(event, execution) {\n await execution.session.appendCustomEntry('doom-hook', hookEntry(event));\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return;\n await start(runtime, execution);\n const native = {\n type: 'tool_result',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n input: event.args,\n content: event.content,\n details: event.details,\n isError: event.isError,\n } as ToolResultEvent;\n const key = `${STATUS_PREFIX}:${native.toolCallId}:post`;\n try {\n const result = await dispatchHooks(runtime.session, scopeFor(runtime, execution), {\n eventName: HOOK_EVENT.postToolUse,\n event: native,\n progress: (index, total) =>\n execution.client.setStatus(\n key,\n `Running post-tool hooks for ${native.toolName} (${index + 1}/${total})...`,\n ),\n });\n return result.toolResult;\n } finally {\n execution.client.setStatus(key, undefined);\n }\n },\n };\n const agentSettled: DoomHeadlessHook<'agent_settled'> = {\n event: 'agent_settled',\n handle: (event, execution) => execution.session.appendCustomEntry('doom-hook', hookEntry(event)),\n };\n const sessionShutdown: DoomHeadlessHook<'session_shutdown'> = {\n event: 'session_shutdown',\n async handle(_event, execution) {\n const runtime = resolveRuntime();\n if (runtime?.isCurrent() && !scopeFor(runtime, execution).isSubagent) {\n let shutdown = shutdowns.get(runtime);\n if (!shutdown) {\n shutdown = runLifecycle(runtime, execution, HOOK_EVENT.sessionEnd).then(() => undefined);\n shutdowns.set(runtime, shutdown);\n }\n await shutdown;\n }\n execution.client.setStatus('doom-hook', undefined);\n },\n };\n return { sessionStart, agentEnd, beforeAgentStart, toolCall, toolResult, agentSettled, sessionShutdown };\n}\n","import { DoomHeadlessPromptAdmissionError } from '@agimon-ai/po-core/headless';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { SUBAGENT_ENVIRONMENT_FLAG } from '../../../../../constants/hookHandlers';\nimport { createHookBinding } from '../../../../../services/hookRuntime';\nimport { createServerHooks } from '../../../../../services/serverHooks';\n\nexport const createHookServerRoot = ({ agent, signal }: DoomServerPluginContext) => {\n if (!agent) throw new Error('Hook session requires the headless host.');\n const execution = agent.context;\n const binding = createHookBinding(\n {},\n {\n sessionId: execution.sessionId,\n isSubagent: Boolean(execution.environment[SUBAGENT_ENVIRONMENT_FLAG]),\n cwd: execution.cwd,\n repoRoot: execution.repoRoot,\n get model() {\n return execution.model;\n },\n async sendMessage(text, delivery) {\n if (!execution.session.admitPrompt)\n throw new DoomHeadlessPromptAdmissionError('The session cannot admit a hook prompt.');\n await execution.session.admitPrompt(text, delivery);\n },\n appendCustomEntry: (type, data) => execution.session.appendCustomEntry(type, data),\n },\n signal,\n );\n return { value: createServerHooks(binding.runtime), services: [binding.plugin] };\n};\n\nexport type HookServerScope = Awaited<ReturnType<typeof createHookServerRoot>>['value'];\n","import { defineRoot } from '@agimon-ai/po-core/extensionFile';\n\nimport { createHookServerRoot } from './_lib/serverRoot';\n\nexport default defineRoot(createHookServerRoot);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<DoomServerPluginContext, HookServerScope>) => root.agentEnd);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<DoomServerPluginContext, HookServerScope>) => root.agentSettled);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<DoomServerPluginContext, HookServerScope>) => root.beforeAgentStart);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<DoomServerPluginContext, HookServerScope>) => root.sessionShutdown);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<DoomServerPluginContext, HookServerScope>) => root.sessionStart);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<DoomServerPluginContext, HookServerScope>) => root.toolCall);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<DoomServerPluginContext, HookServerScope>) => root.toolResult);\n","export const PACKAGE_SOURCE = '@agimon-ai/po-hook';\nexport const HOOK_HELP_SKILL = {\n name: 'po-author-hook',\n description:\n 'Author Po repository or plugin hooks. Use when creating or changing .po/hooks.yaml, selecting hook groups from modes.yaml, writing hook commands, or adapting Claude Code hook payloads and decisions to Po.',\n};\n","import { defineResource } from '@agimon-ai/po-core/extensionFile';\nimport { DOOM_HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nimport { HOOK_HELP_SKILL } from '../../../../../constants/hook';\n\nexport default defineResource({\n ...HOOK_HELP_SKILL,\n when: DOOM_HELP_WHEN,\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/po-author-hook/SKILL.md'),\n read: async () => {\n const text = await readPackageResource(import.meta.url, 'src/prompts/po-author-hook/SKILL.md');\n if (!text.trim()) throw new Error('The installed hook-authoring skill is missing or unreadable.');\n return text;\n },\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/po-core/serverFacet';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport hookAgentEnd from '../src/extensions/workspaces/sessions/(backend)/hook/agent-end.server';\nimport hookAgentSettled from '../src/extensions/workspaces/sessions/(backend)/hook/agent-settled.server';\nimport hookBeforeAgentStart from '../src/extensions/workspaces/sessions/(backend)/hook/before-agent-start.server';\nimport hookSessionShutdown from '../src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/session-start.server';\nimport hookToolCall from '../src/extensions/workspaces/sessions/(backend)/hook/tool-call.server';\nimport hookToolResult from '../src/extensions/workspaces/sessions/(backend)/hook/tool-result.server';\nimport resourcePoAuthorHook from '../src/extensions/workspaces/sessions/(backend)/resource/po-author-hook.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/po-hook',\n providerOverrides: composeServerProviderOverrides(rootSession),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get hooks(): DoomServerSessionPlugin['hooks'] { return [via({ event: 'agent_end' }, at(hookAgentEnd, contextSession)), via({ event: 'agent_settled' }, at(hookAgentSettled, contextSession)), via({ event: 'before_agent_start' }, at(hookBeforeAgentStart, contextSession)), via({ event: 'session_shutdown' }, at(hookSessionShutdown, contextSession)), via({ event: 'session_start' }, at(hookSessionStart, contextSession)), via({ event: 'tool_call' }, at(hookToolCall, contextSession)), via({ event: 'tool_result' }, at(hookToolResult, contextSession))]; },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourcePoAuthorHook, contextSession)]; },\n services: [...(scopeSession.services ?? [])],\n get activities(): DoomServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.mjs","names":["rootSession","hookAgentEnd","hookAgentSettled","hookBeforeAgentStart","hookSessionShutdown","hookSessionStart","hookToolCall","hookToolResult","resourcePoAuthorHook"],"sources":["../../src/constants/hookHandlers.ts","../../src/services/hookDispatch/index.ts","../../src/services/hookRuntime/type.ts","../../src/services/hookRuntime/index.ts","../../src/services/serverHooks/index.ts","../../src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.ts","../../src/extensions/workspaces/sessions/(backend)/root.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/agent-end.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/agent-settled.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/before-agent-start.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/session-start.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/tool-call.server.ts","../../src/extensions/workspaces/sessions/(backend)/hook/tool-result.server.ts","../../src/constants/hook.ts","../../src/extensions/workspaces/sessions/(backend)/resource/po-author-hook.server.ts","../../generated/server.ts"],"sourcesContent":["export const STATUS_PREFIX = 'repository-hooks';\nexport const FAILURE_MESSAGE_TYPE = 'repository-hook-failure';\nexport const CONTEXT_MESSAGE_TYPE = 'repository-hook-context';\n/** A Stop hook refused the stop; its reason sends the agent back to work. */\nexport const STOP_BLOCK_MESSAGE_TYPE = 'repository-hook-stop-block';\nexport const STEER = { deliverAs: 'steer' } as const;\n/** Starts a new turn on a settled agent, so a refused stop is not a silent one. */\nexport const FOLLOW_UP_TURN = { deliverAs: 'followUp', triggerTurn: true } as const;\n/** Adds a message to a settled agent's conversation without starting a turn. */\nexport const NO_TURN = { triggerTurn: false } as const;\n/**\n * How many stops in a row a Stop hook may refuse before the agent is left to\n * stop. A hook that never lets go would otherwise send it back forever.\n */\nexport const MAX_STOP_REFUSALS = 5;\n/** Claude's Stop hook input field: true when the agent is already continuing because of a Stop hook. */\nexport const STOP_HOOK_ACTIVE_FIELD = 'stop_hook_active';\nexport const BLOCKED_BY_HOOK = 'Blocked by repository hook';\nexport const SUBAGENT_ENVIRONMENT_FLAG = 'PI_SUBAGENT_CHILD';\nexport const CONTEXT_SEPARATOR = '\\n\\n';\n","import type { ToolResultEvent } from '@earendil-works/pi-coding-agent';\n\nimport { BLOCKED_BY_HOOK, CONTEXT_SEPARATOR } from '../../constants/hookHandlers';\nimport { HOOK_EVENT } from '../../constants/hooks';\nimport type { HookFailure, HookToolEvent, ResolvedHook } from '../../types/hooks';\nimport {\n additionalContextsFrom,\n decisionReason,\n hookFailureMessage,\n isDenied,\n toolResultMessages,\n} from '../hookDecisions';\nimport { sessionHookPayload, toolHookPayload } from '../hookPayload';\nimport { selectRegistryHooks } from '../hookRegistry';\nimport type { HookSession } from '../hookRuntime/type';\nimport { selectPluginHooks } from '../pluginHooks';\nimport type { HookDispatchRequest, HookDispatchResult, HookDispatchScope } from './type';\n\nfunction isJson(value: unknown, ancestors = new Set<object>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || ancestors.has(value)) return false;\n ancestors.add(value);\n const valid =\n (Array.isArray(value) || Object.getPrototypeOf(value) === Object.prototype) &&\n Object.values(value).every((entry) => isJson(entry, ancestors));\n ancestors.delete(value);\n return valid;\n}\n\nfunction commandFailure(row: ResolvedHook, error: unknown): HookFailure {\n return {\n command: row.hook.command ?? row.hook.module,\n message: error instanceof Error ? error.message : String(error),\n reason: 'hook_execution',\n };\n}\n\n/** Registry rows interleave command and module bindings, followed by plugin commands. */\nexport async function dispatchHooks(\n session: HookSession,\n scope: HookDispatchScope,\n request: HookDispatchRequest,\n): Promise<HookDispatchResult> {\n const signal = scope.operationSignal ? AbortSignal.any([scope.signal, scope.operationSignal]) : scope.signal;\n signal.throwIfAborted();\n const harness = session.config().harness;\n const plugins = await session.documents.plugins(harness.pluginHooks);\n const registry =\n request.eventName === HOOK_EVENT.sessionEnd\n ? { entries: [], failure: undefined }\n : await session.documents.registry(scope.repoRoot);\n signal.throwIfAborted();\n const event = request.event;\n const toolName = event && 'toolName' in event ? event.toolName : undefined;\n const hooks = [\n ...selectRegistryHooks(registry.entries, {\n event: request.eventName,\n toolName,\n allowedGroups: harness.hookGroups,\n inSubagent: scope.isSubagent,\n }),\n ...selectPluginHooks(plugins.documents, request.eventName, toolName),\n ];\n const decisions: HookDispatchResult['decisions'] = [];\n const failures = [...(registry.failure ? [registry.failure] : []), ...plugins.failures];\n let toolCall: HookDispatchResult['toolCall'];\n let patchedResult = false;\n for (const [index, row] of hooks.entries()) {\n signal.throwIfAborted();\n request.progress?.(index, hooks.length);\n if (row.hook.command === undefined) {\n if (!event) continue;\n let proposed: typeof event;\n try {\n proposed = structuredClone(event);\n } catch (error) {\n failures.push(commandFailure(row, error));\n continue;\n }\n const outcome = await session.modules.invoke(row, proposed, scope, scope.operationSignal);\n signal.throwIfAborted();\n if (outcome.failure) {\n failures.push(outcome.failure);\n continue;\n }\n // A failed or late invocation cannot mutate live tool input or output.\n try {\n if (event.type === 'tool_call' && proposed.type === 'tool_call') {\n if (\n typeof proposed.input !== 'object' ||\n proposed.input === null ||\n Array.isArray(proposed.input) ||\n !isJson(proposed.input)\n ) {\n throw new Error('Hook tool input must be a JSON object.');\n }\n const input = structuredClone(proposed.input);\n for (const key of Object.keys(event.input)) delete (event.input as Record<string, unknown>)[key];\n Object.assign(event.input, input);\n if (outcome.result && 'block' in outcome.result && outcome.result.block) {\n toolCall = { block: true, reason: outcome.result.reason ?? BLOCKED_BY_HOOK };\n break;\n }\n } else if (event.type === 'tool_result' && outcome.result) {\n const patch = structuredClone(outcome.result);\n if ('content' in patch && patch.content !== undefined) event.content = patch.content;\n if ('details' in patch) event.details = patch.details;\n if ('isError' in patch && patch.isError !== undefined) event.isError = patch.isError;\n patchedResult = true;\n }\n } catch (error) {\n failures.push(commandFailure(row, error));\n }\n continue;\n }\n const payload =\n event && 'toolName' in event\n ? toolHookPayload(event as HookToolEvent, request.eventName, scope.repoRoot, scope.sessionId, {\n parentSessionId: scope.parentSessionId,\n agent: scope.agent,\n })\n : sessionHookPayload(scope.sessionId, scope.repoRoot);\n // The catch covers hook execution only. Readiness, host effects and abort errors propagate.\n let outcome;\n try {\n outcome = await session.runner.run(\n row.hook,\n { ...payload, ...request.extraPayload },\n {\n repoRoot: scope.repoRoot,\n pluginRoot: row.root,\n },\n );\n } catch (error) {\n failures.push(commandFailure(row, error));\n continue;\n }\n signal.throwIfAborted();\n if (outcome.failure) failures.push(outcome.failure);\n if (!outcome.decision) continue;\n decisions.push(outcome.decision);\n if (event?.type === 'tool_result') {\n const messages = toolResultMessages([outcome.decision]);\n if (messages.length > 0)\n event.content = [...event.content, { type: 'text', text: messages.join(CONTEXT_SEPARATOR) }];\n if (isDenied(outcome.decision)) event.isError = true;\n patchedResult ||= messages.length > 0 || isDenied(outcome.decision);\n }\n if (isDenied(outcome.decision)) {\n if (event?.type === 'tool_call')\n toolCall = {\n block: true,\n reason: decisionReason(outcome.decision) ?? BLOCKED_BY_HOOK,\n };\n break;\n }\n }\n if (event?.type === 'tool_call' && !toolCall) {\n const context = additionalContextsFrom(decisions).join(CONTEXT_SEPARATOR);\n if (context) toolCall = { block: true, reason: context };\n }\n if (event?.type === 'tool_result' && failures.length > 0) {\n event.content = [...event.content, { type: 'text', text: hookFailureMessage(failures) }];\n patchedResult = true;\n }\n return {\n decisions,\n failures,\n ...(toolCall ? { toolCall } : {}),\n ...(event?.type === 'tool_result' && patchedResult\n ? {\n toolResult: {\n content: (event as ToolResultEvent).content,\n details: (event as ToolResultEvent).details,\n isError: event.isError,\n },\n }\n : {}),\n };\n}\n","import type { PoConfigContext } from '@agimon-ai/po-config/types';\nimport type { PoChildSessionHooks } from '@agimon-ai/po-core/childSession';\nimport type { Context } from '@deepseek-ai/cordis';\n\nimport type { HookContext } from '../../types/hookModule';\nimport type { HookDocumentReader, HookRunner } from '../../types/hooks';\nimport type { HookTelemetry } from '../../types/telemetry';\nimport type { HookModules } from '../hookModules/type';\n\nexport const PO_HOOK_SESSION_SERVICE = 'po/hook-session';\nexport interface HookExtensionOptions {\n telemetry?: HookTelemetry;\n runner?: HookRunner;\n documents?: HookDocumentReader;\n}\n\n/** One host session owns its module registry and lifetime; children borrow only immutable config. */\nexport interface HookSession {\n config(): PoConfigContext;\n prepare(isSubagent?: boolean): Promise<void>;\n readonly runner: HookRunner;\n readonly documents: HookDocumentReader;\n readonly modules: HookModules;\n readonly signal: AbortSignal;\n readonly parentContext?: Omit<HookContext, 'signal'>;\n}\n\n/** One dependency-complete Hook runtime owned by a reactive Cordis fiber. */\nexport interface HookRuntime {\n readonly session: HookSession;\n readonly childHooks: PoChildSessionHooks;\n isCurrent(): boolean;\n}\n\nexport type HookRuntimeResolver = () => HookRuntime | undefined;\n\nexport interface HookRuntimeBinding extends HookRuntime {\n dispose(): Promise<void>;\n}\nexport interface HookBinding {\n readonly plugin: (this: void, context: Context) => void;\n readonly runtime: HookRuntimeResolver;\n}\n\ndeclare module '@deepseek-ai/cordis' {\n interface Context {\n 'po/hook-session': HookRuntime;\n }\n}\n","import { requirePoConfigContext } from '@agimon-ai/po-config/piContext';\nimport type { PoConfigContext } from '@agimon-ai/po-config/types';\nimport { PO_CHILD_SESSION_HOOKS_SERVICE, type PoChildSessionHooks } from '@agimon-ai/po-core/childSession';\nimport { PO_CONFIG_SERVICE } from '@agimon-ai/po-core/config';\nimport type { Context } from '@deepseek-ai/cordis';\nimport type { ToolCallEvent, ToolResultEvent } from '@earendil-works/pi-coding-agent';\n\nimport { HOOK_EVENT } from '../../constants/hooks';\nimport type { HookContext, JsonValue } from '../../types/hookModule';\nimport type { HookTelemetry } from '../../types/telemetry';\nimport { hookFailureMessage } from '../hookDecisions';\nimport { dispatchHooks } from '../hookDispatch';\nimport { createHookDocumentReader } from '../hookDocuments';\nimport { createHookModules } from '../hookModules';\nimport { createBashHookRunner } from '../hookRunner';\nimport { createHookTelemetry } from '../hookTelemetry';\nimport { PO_HOOK_SESSION_SERVICE, type HookSession } from './type';\nimport type { HookBinding, HookExtensionOptions, HookRuntimeBinding } from './type';\n\nexport function createHookSession(\n config: () => PoConfigContext,\n options: HookExtensionOptions,\n signal: AbortSignal,\n): 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 const modules = createHookModules({ descriptor: config().harness.hookModules });\n const documents = options.documents ?? createHookDocumentReader({ telemetry: requireTelemetry() });\n let preparation: Promise<void> | undefined;\n return {\n config,\n signal,\n modules,\n prepare(isSubagent = false) {\n preparation ??= (async () => {\n const harness = config().harness;\n if (harness.hooks === false) return;\n const registry = await documents.registry(harness.root ?? process.cwd());\n // Registry read failures keep their existing advisory dispatch policy.\n if (registry.failure) return;\n const allowed = harness.hookGroups === undefined ? undefined : new Set(harness.hookGroups);\n const rows = registry.entries\n .filter((row) => row.core || !allowed || allowed.has(row.groupId))\n .filter((row) => !(isSubagent && row.skipInSubagent));\n await modules.validate(rows);\n })();\n return preparation;\n },\n runner: options.runner ?? createBashHookRunner({ telemetry: requireTelemetry() }),\n documents,\n };\n}\n\nfunction childHooksFor(parent: HookSession): PoChildSessionHooks {\n return {\n bind(scope) {\n // Children retain their launch selection and artifacts, even if the parent reloads.\n const config = structuredClone(parent.config());\n const controller = new AbortController();\n const signal = AbortSignal.any([controller.signal, scope.signal]);\n const session = createHookSession(() => config, { runner: parent.runner, documents: parent.documents }, signal);\n let disposal: Promise<void> | undefined;\n const context = (): HookContext => {\n const sessionId = scope.sessionId();\n if (!sessionId) throw new Error('Child hook identity is unavailable before runtime startup.');\n return {\n sessionId,\n parentSessionId: scope.request.parentSessionId,\n agent: scope.request.agent,\n isSubagent: true,\n cwd: scope.request.cwd,\n repoRoot: config.harness.root ?? scope.request.cwd,\n signal,\n sendMessage: (text, delivery) => scope.sendMessage(text, delivery),\n appendCustomEntry: (type, data) => scope.appendCustomEntry(type, data),\n };\n };\n return {\n async beforeTool(event, execution) {\n await session.prepare(true);\n const native = {\n type: 'tool_call',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n input: event.args,\n } as ToolCallEvent;\n const result = await dispatchHooks(\n session,\n { ...context(), operationSignal: execution.abortSignal },\n {\n eventName: HOOK_EVENT.preToolUse,\n event: native,\n },\n );\n if (result.failures.length > 0) await scope.sendMessage(hookFailureMessage(result.failures), 'steer');\n return result.toolCall?.block\n ? { block: { reason: result.toolCall.reason ?? 'Blocked by repository hook' } }\n : { args: native.input as Record<string, JsonValue> };\n },\n async afterTool(event, execution) {\n const native = {\n type: 'tool_result',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n input: event.args,\n content: event.content,\n details: event.details,\n isError: event.isError,\n } as ToolResultEvent;\n const result = await dispatchHooks(\n session,\n { ...context(), operationSignal: execution.abortSignal },\n {\n eventName: HOOK_EVENT.postToolUse,\n event: native,\n },\n );\n return result.toolResult\n ? {\n content: result.toolResult.content,\n details: result.toolResult.details as JsonValue | undefined,\n isError: result.toolResult.isError,\n }\n : undefined;\n },\n dispose() {\n disposal ??= (async () => {\n controller.abort();\n await session.modules.dispose();\n })();\n return disposal;\n },\n };\n },\n };\n}\n\nexport function createHookRuntime(\n cordis: Context,\n options: HookExtensionOptions,\n parentContext?: Omit<HookContext, 'signal'>,\n lifetimeSignal?: AbortSignal,\n): HookRuntimeBinding {\n const controller = new AbortController();\n const signal = lifetimeSignal ? AbortSignal.any([controller.signal, lifetimeSignal]) : controller.signal;\n const session: HookSession = {\n ...createHookSession(() => requirePoConfigContext(cordis), options, signal),\n parentContext,\n };\n let disposal: Promise<void> | undefined;\n let active = true;\n return {\n session,\n childHooks: childHooksFor(session),\n isCurrent: () => active && !signal.aborted,\n dispose() {\n active = false;\n controller.abort();\n disposal ??= session.modules.dispose();\n return disposal;\n },\n };\n}\n\nexport function createHookBinding(\n options: HookExtensionOptions,\n parentContext?: Omit<HookContext, 'signal'>,\n lifetimeSignal?: AbortSignal,\n): HookBinding {\n let runtime: HookRuntimeBinding | undefined;\n return {\n plugin(cordis) {\n cordis.inject([PO_CONFIG_SERVICE], (configContext) => {\n const binding = createHookRuntime(configContext, options, parentContext, lifetimeSignal);\n runtime = binding;\n configContext.provide(PO_CHILD_SESSION_HOOKS_SERVICE, binding.childHooks);\n configContext.provide(PO_HOOK_SESSION_SERVICE, binding);\n return async () => {\n if (runtime === binding) runtime = undefined;\n await binding.dispose();\n };\n });\n },\n runtime: () => runtime,\n };\n}\n","import {\n PoHeadlessPromptAdmissionError,\n type PoHeadlessExecutionContext,\n type PoHeadlessHook,\n} from '@agimon-ai/po-core/headless';\nimport type { ToolCallEvent, ToolResultEvent } from '@earendil-works/pi-coding-agent';\n\nimport {\n BLOCKED_BY_HOOK,\n STATUS_PREFIX,\n SUBAGENT_ENVIRONMENT_FLAG,\n CONTEXT_SEPARATOR,\n FAILURE_MESSAGE_TYPE,\n MAX_STOP_REFUSALS,\n STOP_HOOK_ACTIVE_FIELD,\n} from '../../constants/hookHandlers';\nimport { HOOK_EVENT } from '../../constants/hooks';\nimport type { HookNativeEvent } from '../../types/hookModule';\nimport { additionalContextsFrom, decisionReason, hookFailureMessage, isDenied } from '../hookDecisions';\nimport { dispatchHooks } from '../hookDispatch';\nimport type { HookDispatchScope } from '../hookDispatch/type';\nimport type { HookRuntime, HookRuntimeResolver } from '../hookRuntime/type';\n\nfunction hookEntry(event: Readonly<Record<string, unknown>>): Record<string, unknown> {\n return { version: 1, event: typeof event.type === 'string' ? event.type : 'headless-hook', data: event };\n}\n\nfunction scopeFor(runtime: HookRuntime, execution: PoHeadlessExecutionContext): HookDispatchScope {\n return {\n sessionId: execution.sessionId,\n isSubagent: Boolean(execution.environment[SUBAGENT_ENVIRONMENT_FLAG]),\n cwd: execution.cwd,\n repoRoot: execution.repoRoot,\n model: execution.model,\n signal: runtime.session.signal,\n operationSignal: execution.signal,\n async sendMessage(text, delivery) {\n if (!execution.session.admitPrompt)\n throw new PoHeadlessPromptAdmissionError('The session cannot admit a hook prompt.');\n await execution.session.admitPrompt(text, delivery);\n },\n appendCustomEntry: (type, data) => execution.session.appendCustomEntry(type, data),\n };\n}\n\n/** One native owner dispatches lifecycle and tool rows for this session. */\nexport function createServerHooks(resolveRuntime: HookRuntimeResolver) {\n const startups = new WeakMap<HookRuntime, Promise<void>>();\n const shutdowns = new WeakMap<HookRuntime, Promise<void>>();\n const refusals = new WeakMap<HookRuntime, number>();\n async function runLifecycle(\n runtime: HookRuntime,\n execution: PoHeadlessExecutionContext,\n eventName: string,\n event?: Readonly<Record<string, unknown>>,\n extraPayload?: Record<string, unknown>,\n ) {\n const key = `${STATUS_PREFIX}:${execution.sessionId}:${eventName}`;\n try {\n return await dispatchHooks(runtime.session, scopeFor(runtime, execution), {\n eventName,\n event: event as HookNativeEvent | undefined,\n extraPayload,\n progress: (index, total) =>\n execution.client.setStatus(key, `Running ${eventName} hooks (${index + 1}/${total})...`),\n });\n } finally {\n execution.client.setStatus(key, undefined);\n }\n }\n function start(\n runtime: HookRuntime,\n execution: PoHeadlessExecutionContext,\n event: Readonly<Record<string, unknown>> = { type: 'session_start' },\n ) {\n let startup = startups.get(runtime);\n if (!startup) {\n startup = (async () => {\n const scope = scopeFor(runtime, execution);\n await runtime.session.prepare(scope.isSubagent);\n if (scope.isSubagent) return;\n const result = await runLifecycle(runtime, execution, HOOK_EVENT.sessionStart, {\n ...event,\n type: 'session_start',\n });\n if (!runtime.isCurrent()) return;\n if (result.failures.length) await scope.sendMessage(hookFailureMessage(result.failures), 'steer');\n const context = additionalContextsFrom(result.decisions).join(CONTEXT_SEPARATOR);\n if (context) await scope.sendMessage(context, 'steer');\n })();\n startups.set(runtime, startup);\n }\n return startup;\n }\n const sessionStart: PoHeadlessHook<'session_start'> = {\n event: 'session_start',\n async handle(event, execution) {\n const runtime = resolveRuntime();\n if (runtime?.isCurrent()) await start(runtime, execution, event);\n },\n };\n const agentEnd: PoHeadlessHook<'agent_end'> = {\n event: 'agent_end',\n async handle(event, execution) {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent() || scopeFor(runtime, execution).isSubagent) return;\n await start(runtime, execution);\n const count = refusals.get(runtime) ?? 0;\n const result = await runLifecycle(\n runtime,\n execution,\n HOOK_EVENT.stop,\n { ...event, type: 'agent_settled' },\n { [STOP_HOOK_ACTIVE_FIELD]: count > 0 },\n );\n if (!runtime.isCurrent()) return;\n const appendFailure = async (text: string) => {\n if (!execution.session.appendMessage) throw new Error('The session cannot append hook diagnostics.');\n await execution.session.appendMessage({ type: FAILURE_MESSAGE_TYPE, text });\n };\n if (result.failures.length) await appendFailure(hookFailureMessage(result.failures));\n const reason = decisionReason(result.decisions.find(isDenied));\n if (!reason) {\n refusals.set(runtime, 0);\n return;\n }\n if (count >= MAX_STOP_REFUSALS) {\n refusals.set(runtime, 0);\n await appendFailure(\n `A Stop hook refused ${String(MAX_STOP_REFUSALS)} stops in a row, so the agent stops here. Its last reason: ${reason}`,\n );\n return;\n }\n // Advance only after successful admission. Admission does not await the successor turn.\n await scopeFor(runtime, execution).sendMessage(reason, 'followUp');\n refusals.set(runtime, count + 1);\n },\n };\n const beforeAgentStart: PoHeadlessHook<'before_agent_start'> = {\n event: 'before_agent_start',\n async handle(event, execution) {\n const runtime = resolveRuntime();\n if (runtime?.isCurrent()) await start(runtime, execution);\n await execution.session.appendCustomEntry('po-hook', hookEntry(event));\n },\n };\n const toolCall: PoHeadlessHook<'tool_call'> = {\n event: 'tool_call',\n async handle(event, execution) {\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return;\n const scope = scopeFor(runtime, execution);\n try {\n await start(runtime, execution);\n } catch (error) {\n return { block: { reason: error instanceof Error ? error.message : String(error) } };\n }\n const native = {\n type: 'tool_call',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n input: event.args,\n } as ToolCallEvent;\n const key = `${STATUS_PREFIX}:${native.toolCallId}:pre`;\n try {\n const result = await dispatchHooks(runtime.session, scope, {\n eventName: HOOK_EVENT.preToolUse,\n event: native,\n progress: (index, total) =>\n execution.client.setStatus(key, `Running pre-tool hooks for ${native.toolName} (${index + 1}/${total})...`),\n });\n if (result.failures.length > 0) await scope.sendMessage(hookFailureMessage(result.failures), 'steer');\n return result.toolCall?.block\n ? { block: { reason: result.toolCall.reason ?? BLOCKED_BY_HOOK } }\n : { args: native.input };\n } finally {\n execution.client.setStatus(key, undefined);\n }\n },\n };\n const toolResult: PoHeadlessHook<'tool_result'> = {\n event: 'tool_result',\n async handle(event, execution) {\n await execution.session.appendCustomEntry('po-hook', hookEntry(event));\n const runtime = resolveRuntime();\n if (!runtime?.isCurrent()) return;\n await start(runtime, execution);\n const native = {\n type: 'tool_result',\n toolCallId: event.toolCallId,\n toolName: event.toolName,\n input: event.args,\n content: event.content,\n details: event.details,\n isError: event.isError,\n } as ToolResultEvent;\n const key = `${STATUS_PREFIX}:${native.toolCallId}:post`;\n try {\n const result = await dispatchHooks(runtime.session, scopeFor(runtime, execution), {\n eventName: HOOK_EVENT.postToolUse,\n event: native,\n progress: (index, total) =>\n execution.client.setStatus(\n key,\n `Running post-tool hooks for ${native.toolName} (${index + 1}/${total})...`,\n ),\n });\n return result.toolResult;\n } finally {\n execution.client.setStatus(key, undefined);\n }\n },\n };\n const agentSettled: PoHeadlessHook<'agent_settled'> = {\n event: 'agent_settled',\n handle: (event, execution) => execution.session.appendCustomEntry('po-hook', hookEntry(event)),\n };\n const sessionShutdown: PoHeadlessHook<'session_shutdown'> = {\n event: 'session_shutdown',\n async handle(_event, execution) {\n const runtime = resolveRuntime();\n if (runtime?.isCurrent() && !scopeFor(runtime, execution).isSubagent) {\n let shutdown = shutdowns.get(runtime);\n if (!shutdown) {\n shutdown = runLifecycle(runtime, execution, HOOK_EVENT.sessionEnd).then(() => undefined);\n shutdowns.set(runtime, shutdown);\n }\n await shutdown;\n }\n execution.client.setStatus('po-hook', undefined);\n },\n };\n return { sessionStart, agentEnd, beforeAgentStart, toolCall, toolResult, agentSettled, sessionShutdown };\n}\n","import { PoHeadlessPromptAdmissionError } from '@agimon-ai/po-core/headless';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { SUBAGENT_ENVIRONMENT_FLAG } from '../../../../../constants/hookHandlers';\nimport { createHookBinding } from '../../../../../services/hookRuntime';\nimport { createServerHooks } from '../../../../../services/serverHooks';\n\nexport const createHookServerRoot = ({ agent, signal }: PoServerPluginContext) => {\n if (!agent) throw new Error('Hook session requires the headless host.');\n const execution = agent.context;\n const binding = createHookBinding(\n {},\n {\n sessionId: execution.sessionId,\n isSubagent: Boolean(execution.environment[SUBAGENT_ENVIRONMENT_FLAG]),\n cwd: execution.cwd,\n repoRoot: execution.repoRoot,\n get model() {\n return execution.model;\n },\n async sendMessage(text, delivery) {\n if (!execution.session.admitPrompt)\n throw new PoHeadlessPromptAdmissionError('The session cannot admit a hook prompt.');\n await execution.session.admitPrompt(text, delivery);\n },\n appendCustomEntry: (type, data) => execution.session.appendCustomEntry(type, data),\n },\n signal,\n );\n return { value: createServerHooks(binding.runtime), services: [binding.plugin] };\n};\n\nexport type HookServerScope = Awaited<ReturnType<typeof createHookServerRoot>>['value'];\n","import { defineRoot } from '@agimon-ai/po-core/extensionFile';\n\nimport { createHookServerRoot } from './_lib/serverRoot';\n\nexport default defineRoot(createHookServerRoot);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<PoServerPluginContext, HookServerScope>) => root.agentEnd);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<PoServerPluginContext, HookServerScope>) => root.agentSettled);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<PoServerPluginContext, HookServerScope>) => root.beforeAgentStart);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<PoServerPluginContext, HookServerScope>) => root.sessionShutdown);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<PoServerPluginContext, HookServerScope>) => root.sessionStart);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<PoServerPluginContext, HookServerScope>) => root.toolCall);\n","import { defineHook, type WithRoot } from '@agimon-ai/po-core/extensionFile';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport type { HookServerScope } from '../_lib/serverRoot';\n\nexport default defineHook(({ root }: WithRoot<PoServerPluginContext, HookServerScope>) => root.toolResult);\n","export const PACKAGE_SOURCE = '@agimon-ai/po-hook';\nexport const HOOK_HELP_SKILL = {\n name: 'po-author-hook',\n description:\n 'Author Po repository or plugin hooks. Use when creating or changing .po/hooks.yaml, selecting hook groups from modes.yaml, writing hook commands, or adapting Claude Code hook payloads and decisions to Po.',\n};\n","import { defineResource } from '@agimon-ai/po-core/extensionFile';\nimport { PO_HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nimport { HOOK_HELP_SKILL } from '../../../../../constants/hook';\n\nexport default defineResource({\n ...HOOK_HELP_SKILL,\n when: PO_HELP_WHEN,\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/po-author-hook/SKILL.md'),\n read: async () => {\n const text = await readPackageResource(import.meta.url, 'src/prompts/po-author-hook/SKILL.md');\n if (!text.trim()) throw new Error('The installed hook-authoring skill is missing or unreadable.');\n return text;\n },\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverFacet';\nimport { composeServerProviderOverrides } from '@agimon-ai/po-core/serverFacet';\nimport { composeRootHooks } from '@agimon-ai/po-core/extensionFile';\n\nimport rootSession from '../src/extensions/workspaces/sessions/(backend)/root.server';\nimport hookAgentEnd from '../src/extensions/workspaces/sessions/(backend)/hook/agent-end.server';\nimport hookAgentSettled from '../src/extensions/workspaces/sessions/(backend)/hook/agent-settled.server';\nimport hookBeforeAgentStart from '../src/extensions/workspaces/sessions/(backend)/hook/before-agent-start.server';\nimport hookSessionShutdown from '../src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server';\nimport hookSessionStart from '../src/extensions/workspaces/sessions/(backend)/hook/session-start.server';\nimport hookToolCall from '../src/extensions/workspaces/sessions/(backend)/hook/tool-call.server';\nimport hookToolResult from '../src/extensions/workspaces/sessions/(backend)/hook/tool-result.server';\nimport resourcePoAuthorHook from '../src/extensions/workspaces/sessions/(backend)/resource/po-author-hook.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/po-hook',\n providerOverrides: composeServerProviderOverrides(rootSession),\n session: async (context) => {\n const scopeSession = await rootSession(context);\n const contextSession = { ...context, root: scopeSession.value };\n return {\n ...composeRootHooks(scopeSession),\n get hooks(): PoServerSessionPlugin['hooks'] { return [via({ event: 'agent_end' }, at(hookAgentEnd, contextSession)), via({ event: 'agent_settled' }, at(hookAgentSettled, contextSession)), via({ event: 'before_agent_start' }, at(hookBeforeAgentStart, contextSession)), via({ event: 'session_shutdown' }, at(hookSessionShutdown, contextSession)), via({ event: 'session_start' }, at(hookSessionStart, contextSession)), via({ event: 'tool_call' }, at(hookToolCall, contextSession)), via({ event: 'tool_result' }, at(hookToolResult, contextSession))]; },\n get resources(): PoServerSessionPlugin['resources'] { return [at(resourcePoAuthorHook, contextSession)]; },\n services: [...(scopeSession.services ?? [])],\n get activities(): PoServerSessionPlugin['activities'] { return [...(scopeSession.activities ?? [])]; },\n };\n },\n});\n\nexport default facet;\n"],"mappings":";;;;;;;;;AAAA,MAAa,gBAAgB;AAC7B,MAAa,uBAAuB;;AAepC,MAAa,yBAAyB;AAEtC,MAAa,4BAA4B;;;ACAzC,SAAS,OAAO,OAAgB,4BAAY,IAAI,IAAY,GAAY;CACtE,IAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW,OAAO;CACtF,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,SAAS,KAAK;CAC3D,IAAI,OAAO,UAAU,YAAY,UAAU,IAAI,KAAK,GAAG,OAAO;CAC9D,UAAU,IAAI,KAAK;CACnB,MAAM,SACH,MAAM,QAAQ,KAAK,KAAK,OAAO,eAAe,KAAK,MAAM,OAAO,cACjE,OAAO,OAAO,KAAK,CAAC,CAAC,OAAO,UAAU,OAAO,OAAO,SAAS,CAAC;CAChE,UAAU,OAAO,KAAK;CACtB,OAAO;AACT;AAEA,SAAS,eAAe,KAAmB,OAA6B;CACtE,OAAO;EACL,SAAS,IAAI,KAAK,WAAW,IAAI,KAAK;EACtC,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EAC9D,QAAQ;CACV;AACF;;AAGA,eAAsB,cACpB,SACA,OACA,SAC6B;CAC7B,MAAM,SAAS,MAAM,kBAAkB,YAAY,IAAI,CAAC,MAAM,QAAQ,MAAM,eAAe,CAAC,IAAI,MAAM;CACtG,OAAO,eAAe;CACtB,MAAM,UAAU,QAAQ,OAAO,CAAC,CAAC;CACjC,MAAM,UAAU,MAAM,QAAQ,UAAU,QAAQ,QAAQ,WAAW;CACnE,MAAM,WACJ,QAAQ,cAAc,WAAW,aAC7B;EAAE,SAAS,CAAC;EAAG,SAAS,KAAA;CAAU,IAClC,MAAM,QAAQ,UAAU,SAAS,MAAM,QAAQ;CACrD,OAAO,eAAe;CACtB,MAAM,QAAQ,QAAQ;CACtB,MAAM,WAAW,SAAS,cAAc,QAAQ,MAAM,WAAW,KAAA;CACjE,MAAM,QAAQ,CACZ,GAAG,oBAAoB,SAAS,SAAS;EACvC,OAAO,QAAQ;EACf;EACA,eAAe,QAAQ;EACvB,YAAY,MAAM;CACpB,CAAC,GACD,GAAG,kBAAkB,QAAQ,WAAW,QAAQ,WAAW,QAAQ,CACrE;CACA,MAAM,YAA6C,CAAC;CACpD,MAAM,WAAW,CAAC,GAAI,SAAS,UAAU,CAAC,SAAS,OAAO,IAAI,CAAC,GAAI,GAAG,QAAQ,QAAQ;CACtF,IAAI;CACJ,IAAI,gBAAgB;CACpB,KAAK,MAAM,CAAC,OAAO,QAAQ,MAAM,QAAQ,GAAG;EAC1C,OAAO,eAAe;EACtB,QAAQ,WAAW,OAAO,MAAM,MAAM;EACtC,IAAI,IAAI,KAAK,YAAY,KAAA,GAAW;GAClC,IAAI,CAAC,OAAO;GACZ,IAAI;GACJ,IAAI;IACF,WAAW,gBAAgB,KAAK;GAClC,SAAS,OAAO;IACd,SAAS,KAAK,eAAe,KAAK,KAAK,CAAC;IACxC;GACF;GACA,MAAM,UAAU,MAAM,QAAQ,QAAQ,OAAO,KAAK,UAAU,OAAO,MAAM,eAAe;GACxF,OAAO,eAAe;GACtB,IAAI,QAAQ,SAAS;IACnB,SAAS,KAAK,QAAQ,OAAO;IAC7B;GACF;GAEA,IAAI;IACF,IAAI,MAAM,SAAS,eAAe,SAAS,SAAS,aAAa;KAC/D,IACE,OAAO,SAAS,UAAU,YAC1B,SAAS,UAAU,QACnB,MAAM,QAAQ,SAAS,KAAK,KAC5B,CAAC,OAAO,SAAS,KAAK,GAEtB,MAAM,IAAI,MAAM,wCAAwC;KAE1D,MAAM,QAAQ,gBAAgB,SAAS,KAAK;KAC5C,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,KAAK,GAAG,OAAQ,MAAM,MAAkC;KAC5F,OAAO,OAAO,MAAM,OAAO,KAAK;KAChC,IAAI,QAAQ,UAAU,WAAW,QAAQ,UAAU,QAAQ,OAAO,OAAO;MACvE,WAAW;OAAE,OAAO;OAAM,QAAQ,QAAQ,OAAO,UAAA;MAA0B;MAC3E;KACF;IACF,OAAO,IAAI,MAAM,SAAS,iBAAiB,QAAQ,QAAQ;KACzD,MAAM,QAAQ,gBAAgB,QAAQ,MAAM;KAC5C,IAAI,aAAa,SAAS,MAAM,YAAY,KAAA,GAAW,MAAM,UAAU,MAAM;KAC7E,IAAI,aAAa,OAAO,MAAM,UAAU,MAAM;KAC9C,IAAI,aAAa,SAAS,MAAM,YAAY,KAAA,GAAW,MAAM,UAAU,MAAM;KAC7E,gBAAgB;IAClB;GACF,SAAS,OAAO;IACd,SAAS,KAAK,eAAe,KAAK,KAAK,CAAC;GAC1C;GACA;EACF;EACA,MAAM,UACJ,SAAS,cAAc,QACnB,gBAAgB,OAAwB,QAAQ,WAAW,MAAM,UAAU,MAAM,WAAW;GAC1F,iBAAiB,MAAM;GACvB,OAAO,MAAM;EACf,CAAC,IACD,mBAAmB,MAAM,WAAW,MAAM,QAAQ;EAExD,IAAI;EACJ,IAAI;GACF,UAAU,MAAM,QAAQ,OAAO,IAC7B,IAAI,MACJ;IAAE,GAAG;IAAS,GAAG,QAAQ;GAAa,GACtC;IACE,UAAU,MAAM;IAChB,YAAY,IAAI;GAClB,CACF;EACF,SAAS,OAAO;GACd,SAAS,KAAK,eAAe,KAAK,KAAK,CAAC;GACxC;EACF;EACA,OAAO,eAAe;EACtB,IAAI,QAAQ,SAAS,SAAS,KAAK,QAAQ,OAAO;EAClD,IAAI,CAAC,QAAQ,UAAU;EACvB,UAAU,KAAK,QAAQ,QAAQ;EAC/B,IAAI,OAAO,SAAS,eAAe;GACjC,MAAM,WAAW,mBAAmB,CAAC,QAAQ,QAAQ,CAAC;GACtD,IAAI,SAAS,SAAS,GACpB,MAAM,UAAU,CAAC,GAAG,MAAM,SAAS;IAAE,MAAM;IAAQ,MAAM,SAAS,KAAA,MAAsB;GAAE,CAAC;GAC7F,IAAI,SAAS,QAAQ,QAAQ,GAAG,MAAM,UAAU;GAChD,kBAAkB,SAAS,SAAS,KAAK,SAAS,QAAQ,QAAQ;EACpE;EACA,IAAI,SAAS,QAAQ,QAAQ,GAAG;GAC9B,IAAI,OAAO,SAAS,aAClB,WAAW;IACT,OAAO;IACP,QAAQ,eAAe,QAAQ,QAAQ,KAAA;GACzC;GACF;EACF;CACF;CACA,IAAI,OAAO,SAAS,eAAe,CAAC,UAAU;EAC5C,MAAM,UAAU,uBAAuB,SAAS,CAAC,CAAC,KAAA,MAAsB;EACxE,IAAI,SAAS,WAAW;GAAE,OAAO;GAAM,QAAQ;EAAQ;CACzD;CACA,IAAI,OAAO,SAAS,iBAAiB,SAAS,SAAS,GAAG;EACxD,MAAM,UAAU,CAAC,GAAG,MAAM,SAAS;GAAE,MAAM;GAAQ,MAAM,mBAAmB,QAAQ;EAAE,CAAC;EACvF,gBAAgB;CAClB;CACA,OAAO;EACL;EACA;EACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;EAC/B,GAAI,OAAO,SAAS,iBAAiB,gBACjC,EACE,YAAY;GACV,SAAU,MAA0B;GACpC,SAAU,MAA0B;GACpC,SAAS,MAAM;EACjB,EACF,IACA,CAAC;CACP;AACF;;;AC3KA,MAAa,0BAA0B;;;ACUvC,SAAgB,kBACd,QACA,SACA,QACa;CAGb,IAAI,YAAY,QAAQ;CACxB,MAAM,yBAAyC,cAAc,oBAAoB;CACjF,MAAM,UAAU,kBAAkB,EAAE,YAAY,OAAO,CAAC,CAAC,QAAQ,YAAY,CAAC;CAC9E,MAAM,YAAY,QAAQ,aAAa,yBAAyB,EAAE,WAAW,iBAAiB,EAAE,CAAC;CACjG,IAAI;CACJ,OAAO;EACL;EACA;EACA;EACA,QAAQ,aAAa,OAAO;GAC1B,iBAAiB,YAAY;IAC3B,MAAM,UAAU,OAAO,CAAC,CAAC;IACzB,IAAI,QAAQ,UAAU,OAAO;IAC7B,MAAM,WAAW,MAAM,UAAU,SAAS,QAAQ,QAAQ,QAAQ,IAAI,CAAC;IAEvE,IAAI,SAAS,SAAS;IACtB,MAAM,UAAU,QAAQ,eAAe,KAAA,IAAY,KAAA,IAAY,IAAI,IAAI,QAAQ,UAAU;IACzF,MAAM,OAAO,SAAS,QACnB,QAAQ,QAAQ,IAAI,QAAQ,CAAC,WAAW,QAAQ,IAAI,IAAI,OAAO,CAAC,CAAC,CACjE,QAAQ,QAAQ,EAAE,cAAc,IAAI,eAAe;IACtD,MAAM,QAAQ,SAAS,IAAI;GAC7B,EAAA,CAAG;GACH,OAAO;EACT;EACA,QAAQ,QAAQ,UAAU,qBAAqB,EAAE,WAAW,iBAAiB,EAAE,CAAC;EAChF;CACF;AACF;AAEA,SAAS,cAAc,QAA0C;CAC/D,OAAO,EACL,KAAK,OAAO;EAEV,MAAM,SAAS,gBAAgB,OAAO,OAAO,CAAC;EAC9C,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,SAAS,YAAY,IAAI,CAAC,WAAW,QAAQ,MAAM,MAAM,CAAC;EAChE,MAAM,UAAU,wBAAwB,QAAQ;GAAE,QAAQ,OAAO;GAAQ,WAAW,OAAO;EAAU,GAAG,MAAM;EAC9G,IAAI;EACJ,MAAM,gBAA6B;GACjC,MAAM,YAAY,MAAM,UAAU;GAClC,IAAI,CAAC,WAAW,MAAM,IAAI,MAAM,4DAA4D;GAC5F,OAAO;IACL;IACA,iBAAiB,MAAM,QAAQ;IAC/B,OAAO,MAAM,QAAQ;IACrB,YAAY;IACZ,KAAK,MAAM,QAAQ;IACnB,UAAU,OAAO,QAAQ,QAAQ,MAAM,QAAQ;IAC/C;IACA,cAAc,MAAM,aAAa,MAAM,YAAY,MAAM,QAAQ;IACjE,oBAAoB,MAAM,SAAS,MAAM,kBAAkB,MAAM,IAAI;GACvE;EACF;EACA,OAAO;GACL,MAAM,WAAW,OAAO,WAAW;IACjC,MAAM,QAAQ,QAAQ,IAAI;IAC1B,MAAM,SAAS;KACb,MAAM;KACN,YAAY,MAAM;KAClB,UAAU,MAAM;KAChB,OAAO,MAAM;IACf;IACA,MAAM,SAAS,MAAM,cACnB,SACA;KAAE,GAAG,QAAQ;KAAG,iBAAiB,UAAU;IAAY,GACvD;KACE,WAAW,WAAW;KACtB,OAAO;IACT,CACF;IACA,IAAI,OAAO,SAAS,SAAS,GAAG,MAAM,MAAM,YAAY,mBAAmB,OAAO,QAAQ,GAAG,OAAO;IACpG,OAAO,OAAO,UAAU,QACpB,EAAE,OAAO,EAAE,QAAQ,OAAO,SAAS,UAAU,6BAA6B,EAAE,IAC5E,EAAE,MAAM,OAAO,MAAmC;GACxD;GACA,MAAM,UAAU,OAAO,WAAW;IAChC,MAAM,SAAS;KACb,MAAM;KACN,YAAY,MAAM;KAClB,UAAU,MAAM;KAChB,OAAO,MAAM;KACb,SAAS,MAAM;KACf,SAAS,MAAM;KACf,SAAS,MAAM;IACjB;IACA,MAAM,SAAS,MAAM,cACnB,SACA;KAAE,GAAG,QAAQ;KAAG,iBAAiB,UAAU;IAAY,GACvD;KACE,WAAW,WAAW;KACtB,OAAO;IACT,CACF;IACA,OAAO,OAAO,aACV;KACE,SAAS,OAAO,WAAW;KAC3B,SAAS,OAAO,WAAW;KAC3B,SAAS,OAAO,WAAW;IAC7B,IACA,KAAA;GACN;GACA,UAAU;IACR,cAAc,YAAY;KACxB,WAAW,MAAM;KACjB,MAAM,QAAQ,QAAQ,QAAQ;IAChC,EAAA,CAAG;IACH,OAAO;GACT;EACF;CACF,EACF;AACF;AAEA,SAAgB,kBACd,QACA,SACA,eACA,gBACoB;CACpB,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,SAAS,iBAAiB,YAAY,IAAI,CAAC,WAAW,QAAQ,cAAc,CAAC,IAAI,WAAW;CAClG,MAAM,UAAuB;EAC3B,GAAG,wBAAwB,uBAAuB,MAAM,GAAG,SAAS,MAAM;EAC1E;CACF;CACA,IAAI;CACJ,IAAI,SAAS;CACb,OAAO;EACL;EACA,YAAY,cAAc,OAAO;EACjC,iBAAiB,UAAU,CAAC,OAAO;EACnC,UAAU;GACR,SAAS;GACT,WAAW,MAAM;GACjB,aAAa,QAAQ,QAAQ,QAAQ;GACrC,OAAO;EACT;CACF;AACF;AAEA,SAAgB,kBACd,SACA,eACA,gBACa;CACb,IAAI;CACJ,OAAO;EACL,OAAO,QAAQ;GACb,OAAO,OAAO,CAAC,iBAAiB,IAAI,kBAAkB;IACpD,MAAM,UAAU,kBAAkB,eAAe,SAAS,eAAe,cAAc;IACvF,UAAU;IACV,cAAc,QAAQ,gCAAgC,QAAQ,UAAU;IACxE,cAAc,QAAQ,yBAAyB,OAAO;IACtD,OAAO,YAAY;KACjB,IAAI,YAAY,SAAS,UAAU,KAAA;KACnC,MAAM,QAAQ,QAAQ;IACxB;GACF,CAAC;EACH;EACA,eAAe;CACjB;AACF;;;ACpKA,SAAS,UAAU,OAAmE;CACpF,OAAO;EAAE,SAAS;EAAG,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;EAAiB,MAAM;CAAM;AACzG;AAEA,SAAS,SAAS,SAAsB,WAA0D;CAChG,OAAO;EACL,WAAW,UAAU;EACrB,YAAY,QAAQ,UAAU,YAAY,0BAA0B;EACpE,KAAK,UAAU;EACf,UAAU,UAAU;EACpB,OAAO,UAAU;EACjB,QAAQ,QAAQ,QAAQ;EACxB,iBAAiB,UAAU;EAC3B,MAAM,YAAY,MAAM,UAAU;GAChC,IAAI,CAAC,UAAU,QAAQ,aACrB,MAAM,IAAI,+BAA+B,yCAAyC;GACpF,MAAM,UAAU,QAAQ,YAAY,MAAM,QAAQ;EACpD;EACA,oBAAoB,MAAM,SAAS,UAAU,QAAQ,kBAAkB,MAAM,IAAI;CACnF;AACF;;AAGA,SAAgB,kBAAkB,gBAAqC;CACrE,MAAM,2BAAW,IAAI,QAAoC;CACzD,MAAM,4BAAY,IAAI,QAAoC;CAC1D,MAAM,2BAAW,IAAI,QAA6B;CAClD,eAAe,aACb,SACA,WACA,WACA,OACA,cACA;EACA,MAAM,MAAM,GAAG,cAAc,GAAG,UAAU,UAAU,GAAG;EACvD,IAAI;GACF,OAAO,MAAM,cAAc,QAAQ,SAAS,SAAS,SAAS,SAAS,GAAG;IACxE;IACO;IACP;IACA,WAAW,OAAO,UAChB,UAAU,OAAO,UAAU,KAAK,WAAW,UAAU,UAAU,QAAQ,EAAE,GAAG,MAAM,KAAK;GAC3F,CAAC;EACH,UAAU;GACR,UAAU,OAAO,UAAU,KAAK,KAAA,CAAS;EAC3C;CACF;CACA,SAAS,MACP,SACA,WACA,QAA2C,EAAE,MAAM,gBAAgB,GACnE;EACA,IAAI,UAAU,SAAS,IAAI,OAAO;EAClC,IAAI,CAAC,SAAS;GACZ,WAAW,YAAY;IACrB,MAAM,QAAQ,SAAS,SAAS,SAAS;IACzC,MAAM,QAAQ,QAAQ,QAAQ,MAAM,UAAU;IAC9C,IAAI,MAAM,YAAY;IACtB,MAAM,SAAS,MAAM,aAAa,SAAS,WAAW,WAAW,cAAc;KAC7E,GAAG;KACH,MAAM;IACR,CAAC;IACD,IAAI,CAAC,QAAQ,UAAU,GAAG;IAC1B,IAAI,OAAO,SAAS,QAAQ,MAAM,MAAM,YAAY,mBAAmB,OAAO,QAAQ,GAAG,OAAO;IAChG,MAAM,UAAU,uBAAuB,OAAO,SAAS,CAAC,CAAC,KAAA,MAAsB;IAC/E,IAAI,SAAS,MAAM,MAAM,YAAY,SAAS,OAAO;GACvD,EAAA,CAAG;GACH,SAAS,IAAI,SAAS,OAAO;EAC/B;EACA,OAAO;CACT;CA2IA,OAAO;EAAE,cAAA;GAzIP,OAAO;GACP,MAAM,OAAO,OAAO,WAAW;IAC7B,MAAM,UAAU,eAAe;IAC/B,IAAI,SAAS,UAAU,GAAG,MAAM,MAAM,SAAS,WAAW,KAAK;GACjE;EAqIkB;EAAG,UAAA;GAlIrB,OAAO;GACP,MAAM,OAAO,OAAO,WAAW;IAC7B,MAAM,UAAU,eAAe;IAC/B,IAAI,CAAC,SAAS,UAAU,KAAK,SAAS,SAAS,SAAS,CAAC,CAAC,YAAY;IACtE,MAAM,MAAM,SAAS,SAAS;IAC9B,MAAM,QAAQ,SAAS,IAAI,OAAO,KAAK;IACvC,MAAM,SAAS,MAAM,aACnB,SACA,WACA,WAAW,MACX;KAAE,GAAG;KAAO,MAAM;IAAgB,GAClC,GAAG,yBAAyB,QAAQ,EAAE,CACxC;IACA,IAAI,CAAC,QAAQ,UAAU,GAAG;IAC1B,MAAM,gBAAgB,OAAO,SAAiB;KAC5C,IAAI,CAAC,UAAU,QAAQ,eAAe,MAAM,IAAI,MAAM,6CAA6C;KACnG,MAAM,UAAU,QAAQ,cAAc;MAAE,MAAM;MAAsB;KAAK,CAAC;IAC5E;IACA,IAAI,OAAO,SAAS,QAAQ,MAAM,cAAc,mBAAmB,OAAO,QAAQ,CAAC;IACnF,MAAM,SAAS,eAAe,OAAO,UAAU,KAAK,QAAQ,CAAC;IAC7D,IAAI,CAAC,QAAQ;KACX,SAAS,IAAI,SAAS,CAAC;KACvB;IACF;IACA,IAAI,SAAA,GAA4B;KAC9B,SAAS,IAAI,SAAS,CAAC;KACvB,MAAM,cACJ,uBAAuB,OAAA,CAAwB,EAAE,6DAA6D,QAChH;KACA;IACF;IAEA,MAAM,SAAS,SAAS,SAAS,CAAC,CAAC,YAAY,QAAQ,UAAU;IACjE,SAAS,IAAI,SAAS,QAAQ,CAAC;GACjC;EAgG4B;EAAG,kBAAA;GA7F/B,OAAO;GACP,MAAM,OAAO,OAAO,WAAW;IAC7B,MAAM,UAAU,eAAe;IAC/B,IAAI,SAAS,UAAU,GAAG,MAAM,MAAM,SAAS,SAAS;IACxD,MAAM,UAAU,QAAQ,kBAAkB,WAAW,UAAU,KAAK,CAAC;GACvE;EAwF8C;EAAG,UAAA;GArFjD,OAAO;GACP,MAAM,OAAO,OAAO,WAAW;IAC7B,MAAM,UAAU,eAAe;IAC/B,IAAI,CAAC,SAAS,UAAU,GAAG;IAC3B,MAAM,QAAQ,SAAS,SAAS,SAAS;IACzC,IAAI;KACF,MAAM,MAAM,SAAS,SAAS;IAChC,SAAS,OAAO;KACd,OAAO,EAAE,OAAO,EAAE,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,EAAE;IACrF;IACA,MAAM,SAAS;KACb,MAAM;KACN,YAAY,MAAM;KAClB,UAAU,MAAM;KAChB,OAAO,MAAM;IACf;IACA,MAAM,MAAM,GAAG,cAAc,GAAG,OAAO,WAAW;IAClD,IAAI;KACF,MAAM,SAAS,MAAM,cAAc,QAAQ,SAAS,OAAO;MACzD,WAAW,WAAW;MACtB,OAAO;MACP,WAAW,OAAO,UAChB,UAAU,OAAO,UAAU,KAAK,8BAA8B,OAAO,SAAS,IAAI,QAAQ,EAAE,GAAG,MAAM,KAAK;KAC9G,CAAC;KACD,IAAI,OAAO,SAAS,SAAS,GAAG,MAAM,MAAM,YAAY,mBAAmB,OAAO,QAAQ,GAAG,OAAO;KACpG,OAAO,OAAO,UAAU,QACpB,EAAE,OAAO,EAAE,QAAQ,OAAO,SAAS,UAAA,6BAA0B,EAAE,IAC/D,EAAE,MAAM,OAAO,MAAM;IAC3B,UAAU;KACR,UAAU,OAAO,UAAU,KAAK,KAAA,CAAS;IAC3C;GACF;EAsDwD;EAAG,YAAA;GAnD3D,OAAO;GACP,MAAM,OAAO,OAAO,WAAW;IAC7B,MAAM,UAAU,QAAQ,kBAAkB,WAAW,UAAU,KAAK,CAAC;IACrE,MAAM,UAAU,eAAe;IAC/B,IAAI,CAAC,SAAS,UAAU,GAAG;IAC3B,MAAM,MAAM,SAAS,SAAS;IAC9B,MAAM,SAAS;KACb,MAAM;KACN,YAAY,MAAM;KAClB,UAAU,MAAM;KAChB,OAAO,MAAM;KACb,SAAS,MAAM;KACf,SAAS,MAAM;KACf,SAAS,MAAM;IACjB;IACA,MAAM,MAAM,GAAG,cAAc,GAAG,OAAO,WAAW;IAClD,IAAI;KAUF,QAAO,MATc,cAAc,QAAQ,SAAS,SAAS,SAAS,SAAS,GAAG;MAChF,WAAW,WAAW;MACtB,OAAO;MACP,WAAW,OAAO,UAChB,UAAU,OAAO,UACf,KACA,+BAA+B,OAAO,SAAS,IAAI,QAAQ,EAAE,GAAG,MAAM,KACxE;KACJ,CAAC,EAAA,CACa;IAChB,UAAU;KACR,UAAU,OAAO,UAAU,KAAK,KAAA,CAAS;IAC3C;GACF;EAqBoE;EAAG,cAAA;GAlBvE,OAAO;GACP,SAAS,OAAO,cAAc,UAAU,QAAQ,kBAAkB,WAAW,UAAU,KAAK,CAAC;EAiBX;EAAG,iBAAA;GAdrF,OAAO;GACP,MAAM,OAAO,QAAQ,WAAW;IAC9B,MAAM,UAAU,eAAe;IAC/B,IAAI,SAAS,UAAU,KAAK,CAAC,SAAS,SAAS,SAAS,CAAC,CAAC,YAAY;KACpE,IAAI,WAAW,UAAU,IAAI,OAAO;KACpC,IAAI,CAAC,UAAU;MACb,WAAW,aAAa,SAAS,WAAW,WAAW,UAAU,CAAC,CAAC,WAAW,KAAA,CAAS;MACvF,UAAU,IAAI,SAAS,QAAQ;KACjC;KACA,MAAM;IACR;IACA,UAAU,OAAO,UAAU,WAAW,KAAA,CAAS;GACjD;EAEmG;CAAE;AACzG;;;AClOA,MAAa,wBAAwB,EAAE,OAAO,aAAoC;CAChF,IAAI,CAAC,OAAO,MAAM,IAAI,MAAM,0CAA0C;CACtE,MAAM,YAAY,MAAM;CACxB,MAAM,UAAU,kBACd,CAAC,GACD;EACE,WAAW,UAAU;EACrB,YAAY,QAAQ,UAAU,YAAY,0BAA0B;EACpE,KAAK,UAAU;EACf,UAAU,UAAU;EACpB,IAAI,QAAQ;GACV,OAAO,UAAU;EACnB;EACA,MAAM,YAAY,MAAM,UAAU;GAChC,IAAI,CAAC,UAAU,QAAQ,aACrB,MAAM,IAAI,+BAA+B,yCAAyC;GACpF,MAAM,UAAU,QAAQ,YAAY,MAAM,QAAQ;EACpD;EACA,oBAAoB,MAAM,SAAS,UAAU,QAAQ,kBAAkB,MAAM,IAAI;CACnF,GACA,MACF;CACA,OAAO;EAAE,OAAO,kBAAkB,QAAQ,OAAO;EAAG,UAAU,CAAC,QAAQ,MAAM;CAAE;AACjF;;;AC1BA,IAAA,sBAAe,WAAW,oBAAoB;;;ACC9C,IAAA,2BAAe,YAAY,EAAE,WAA6D,KAAK,QAAQ;;;ACAvG,IAAA,+BAAe,YAAY,EAAE,WAA6D,KAAK,YAAY;;;ACA3G,IAAA,oCAAe,YAAY,EAAE,WAA6D,KAAK,gBAAgB;;;ACA/G,IAAA,kCAAe,YAAY,EAAE,WAA6D,KAAK,eAAe;;;ACA9G,IAAA,+BAAe,YAAY,EAAE,WAA6D,KAAK,YAAY;;;ACA3G,IAAA,2BAAe,YAAY,EAAE,WAA6D,KAAK,QAAQ;;;ACAvG,IAAA,6BAAe,YAAY,EAAE,WAA6D,KAAK,UAAU;;;AECzG,IAAA,gCAAe,eAAe;CDJ5B,MAAM;CACN,aACE;CCIF,MAAM;CACN,MAAM;CACN,MAAM,oBAAoB,YAAY,KAAK,qCAAqC;CAChF,MAAM,YAAY;EAChB,MAAM,OAAO,MAAM,oBAAoB,YAAY,KAAK,qCAAqC;EAC7F,IAAI,CAAC,KAAK,KAAK,GAAG,MAAM,IAAI,MAAM,8DAA8D;EAChG,OAAO;CACT;AACF,CAAC;;;ACAD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,QAAQ,mBAAmB;CACtC,MAAM;CACN,mBAAmB,+BAA+BA,mBAAW;CAC7D,SAAS,OAAO,YAAY;EAC1B,MAAM,eAAe,MAAMA,oBAAY,OAAO;EAC9C,MAAM,iBAAiB;GAAE,GAAG;GAAS,MAAM,aAAa;EAAM;EAC9D,OAAO;GACL,GAAG,iBAAiB,YAAY;GAChC,IAAI,QAAwC;IAAE,OAAO;KAAC,IAAI,EAAE,OAAO,YAAY,GAAG,GAAGC,0BAAc,cAAc,CAAC;KAAG,IAAI,EAAE,OAAO,gBAAgB,GAAG,GAAGC,8BAAkB,cAAc,CAAC;KAAG,IAAI,EAAE,OAAO,qBAAqB,GAAG,GAAGC,mCAAsB,cAAc,CAAC;KAAG,IAAI,EAAE,OAAO,mBAAmB,GAAG,GAAGC,iCAAqB,cAAc,CAAC;KAAG,IAAI,EAAE,OAAO,gBAAgB,GAAG,GAAGC,8BAAkB,cAAc,CAAC;KAAG,IAAI,EAAE,OAAO,YAAY,GAAG,GAAGC,0BAAc,cAAc,CAAC;KAAG,IAAI,EAAE,OAAO,cAAc,GAAG,GAAGC,4BAAgB,cAAc,CAAC;IAAC;GAAG;GACniB,IAAI,YAAgD;IAAE,OAAO,CAAC,GAAGC,+BAAsB,cAAc,CAAC;GAAG;GACzG,UAAU,CAAC,GAAI,aAAa,YAAY,CAAC,CAAE;GAC3C,IAAI,aAAkD;IAAE,OAAO,CAAC,GAAI,aAAa,cAAc,CAAC,CAAE;GAAG;EACvG;CACF;AACF,CAAC"}
|
|
@@ -76,8 +76,8 @@ const REGISTRY_SOURCE_ATTRIBUTE = "repository";
|
|
|
76
76
|
//#endregion
|
|
77
77
|
//#region src/constants/telemetry.ts
|
|
78
78
|
const HOOK_TELEMETRY_EVENT = {
|
|
79
|
-
hookFailed: "
|
|
80
|
-
hookRegistryReadFailed: "
|
|
79
|
+
hookFailed: "po_pi_hook.failed",
|
|
80
|
+
hookRegistryReadFailed: "po_pi_hook.registry_read_failed"
|
|
81
81
|
};
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region src/services/toolNames/index.ts
|
|
@@ -244,7 +244,7 @@ function createHookDocumentReader(options = {}) {
|
|
|
244
244
|
};
|
|
245
245
|
return {
|
|
246
246
|
async registry(repoRoot) {
|
|
247
|
-
const candidates = (0, _agimon_ai_po_config_layeredConfig.
|
|
247
|
+
const candidates = (0, _agimon_ai_po_config_layeredConfig.poConfigCandidates)(HOOKS_FILE, repoRoot, options.homeDirectory);
|
|
248
248
|
const registryPath = candidates.map((candidate) => candidate.filePath).join(" and ");
|
|
249
249
|
try {
|
|
250
250
|
const sources = (await Promise.all(candidates.map(readSource))).filter((source) => source !== void 0);
|
|
@@ -497,7 +497,7 @@ const PACKAGE_NAME = "@agimon-ai/po-hook";
|
|
|
497
497
|
//#endregion
|
|
498
498
|
//#region src/services/hookTelemetry/index.ts
|
|
499
499
|
function createHookTelemetry(options = {}) {
|
|
500
|
-
const telemetry = (0, _agimon_ai_po_telemetry.
|
|
500
|
+
const telemetry = (0, _agimon_ai_po_telemetry.createPoTelemetry)({
|
|
501
501
|
serviceName: SERVICE_NAME,
|
|
502
502
|
packageName: PACKAGE_NAME,
|
|
503
503
|
cwd: options.cwd,
|
|
@@ -896,4 +896,4 @@ Object.defineProperty(exports, "toolResultMessages", {
|
|
|
896
896
|
}
|
|
897
897
|
});
|
|
898
898
|
|
|
899
|
-
//# sourceMappingURL=hookModules-
|
|
899
|
+
//# sourceMappingURL=hookModules-BCecT6-e.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hookModules-BCecT6-e.cjs","names":["path","fs","parseYaml","poConfigCandidates","spawnProcess","createPoTelemetry","fs","path","pathToFileURL"],"sources":["../src/constants/hookDecisions.ts","../src/services/hookDecisions/index.ts","../src/constants/hookDocuments.ts","../src/constants/telemetry.ts","../src/services/toolNames/index.ts","../src/services/hookRegistry/index.ts","../src/services/hookDocuments/index.ts","../src/constants/hookPayload.ts","../src/services/hookPayload/index.ts","../src/constants/hookRunner.ts","../src/services/hookRunner/index.ts","../src/constants/hookTelemetry.ts","../src/services/hookTelemetry/index.ts","../src/services/pluginHooks/index.ts","../src/constants/hooks.ts","../src/services/hookModules/index.ts"],"sourcesContent":["export const BLOCK_DECISION = 'block';\nexport const DENY_PERMISSION = 'deny';\n","import { BLOCK_DECISION, DENY_PERMISSION } from '../../constants/hookDecisions';\nimport type { HookDecision, HookFailure, HookOutcome } from '../../types/hooks';\n\nexport function decisionsFrom(outcomes: ReadonlyArray<HookOutcome>): HookDecision[] {\n return outcomes.flatMap((outcome) => (outcome.decision ? [outcome.decision] : []));\n}\n\nexport function failuresFrom(outcomes: ReadonlyArray<HookOutcome>): HookFailure[] {\n return outcomes.flatMap((outcome) => (outcome.failure ? [outcome.failure] : []));\n}\n\n/** Both spellings a hook may use to refuse the call it observed. */\nexport function isDenied(decision: HookDecision | undefined): boolean {\n return decision?.decision === BLOCK_DECISION || decision?.hookSpecificOutput?.permissionDecision === DENY_PERMISSION;\n}\n\nexport function decisionReason(decision: HookDecision | undefined): string | undefined {\n return decision?.reason ?? decision?.hookSpecificOutput?.reason;\n}\n\n/** Context a hook wants added to the conversation rather than used to block. */\nexport function additionalContextsFrom(decisions: ReadonlyArray<HookDecision>): string[] {\n return decisions\n .map((decision) => decision.hookSpecificOutput?.additionalContext)\n .filter((value): value is string => Boolean(value));\n}\n\n/** What a post-tool hook has to say, whichever field it said it in. */\nexport function toolResultMessages(decisions: ReadonlyArray<HookDecision>): string[] {\n return decisions\n .map((decision) => decision.hookSpecificOutput?.additionalContext ?? decisionReason(decision))\n .filter((value): value is string => Boolean(value));\n}\n\n/**\n * A guardrail that never ran looks exactly like one that passed, so the agent is\n * told which checks were missed and what its options are.\n */\nexport function hookFailureMessage(failures: ReadonlyArray<HookFailure>): string {\n return [\n 'One or more repository hooks did not complete, so their checks were not applied:',\n ...failures.map((failure) => `- ${failure.command}: ${failure.message}`),\n 'Options:',\n '- Inspect the hook command or configuration and rerun after correcting it.',\n '- Continue only if the missed advisory check is acceptable.',\n '- Ask the user before bypassing a hook that may enforce a guardrail.',\n ].join('\\n');\n}\n","export const HOOKS_FILE = 'hooks.yaml';\nexport const FILE_ENCODING = 'utf8';\nexport const FILE_NOT_FOUND_ERROR = 'ENOENT';\nexport const REGISTRY_SOURCE_ATTRIBUTE = 'repository';\n","export const HOOK_TELEMETRY_EVENT = {\n hookFailed: 'po_pi_hook.failed',\n hookRegistryReadFailed: 'po_pi_hook.registry_read_failed',\n} as const;\n","/**\n * Pi's tool names translated into the Claude names hook matchers are written\n * against.\n *\n * Hook authors write `matcher: Bash`, and Pi reports `bash`, so a matcher would\n * never fire without this. Only this direction belongs here: rewriting Claude\n * names for Pi is an agent-definition concern the harness owns.\n */\nconst PI_TO_CLAUDE = new Map([\n ['read', 'Read'],\n ['edit', 'Edit'],\n ['write', 'Write'],\n ['bash', 'Bash'],\n ['find', 'Glob'],\n ['grep', 'Grep'],\n ['subagent', 'Agent'],\n]);\n\n/** The Claude name a hook matcher expects for a tool Pi just ran. */\nexport function toClaudeToolName(tool: string): string {\n return PI_TO_CLAUDE.get(tool) ?? tool;\n}\n\n/** Whether a matcher, if the row declares one, accepts the tool that fired. */\nexport function matchesTool(matcher: string | undefined, toolName: string | undefined): boolean {\n if (!toolName || !matcher) return true;\n return new RegExp(matcher).test(toClaudeToolName(toolName));\n}\n","import path from 'node:path';\n\nimport type { HookDocumentSource, ParsedRegistrySource, RegistryEntry, ResolvedHook } from '../../types/hooks';\nimport { matchesTool } from '../toolNames';\n\n/** Which rows a dispatch keeps, once the session's selection is known. */\nexport interface RegistrySelection {\n event: string;\n toolName?: string;\n /** Selected group ids, or undefined for \"every group\", the standalone default. */\n allowedGroups?: readonly string[];\n inSubagent: boolean;\n}\n\n/**\n * Identity of a set of registry sources, for callers that cache the parse.\n *\n * Keyed on contents rather than mtime, so it stays correct for an in-place\n * rewrite and needs no invalidation hook. Reading both files is cheap; parsing\n * is what a cache built on this skips.\n */\nexport function registryCacheKey(sources: ReadonlyArray<HookDocumentSource>): string {\n return sources.map((source) => `${source.registryId ?? source.baseDirectory} ${source.text}`).join(' ');\n}\n\n/**\n * Flattens parsed registry documents into sorted rows, keeping only bindings\n * that declare a `pi` frontend.\n *\n * A later source replaces the group of the same id outright rather than merging\n * into it, so a repository that redefines a group owns it completely.\n */\nexport function registryEntries(sources: ReadonlyArray<ParsedRegistrySource>): RegistryEntry[] {\n const groups = new Map<string, RegistryEntry[]>();\n let position = 0;\n for (const source of sources) {\n for (const [groupId, group] of Object.entries(source.document.groups ?? {})) {\n const entries: RegistryEntry[] = [];\n for (const [rowIndex, hook] of (group.hooks ?? []).entries()) {\n // Every declared hook advances the position, whether or not it is kept,\n // so the sort tiebreaker stays the order the file declares them in.\n position += 1;\n if (!hook.pi) continue;\n const registryId = source.registryId ?? path.join(source.baseDirectory, '.po/hooks.yaml');\n const rowId = String(rowIndex);\n const attribution = `${registryId}: group ${groupId}, row ${rowId}, event ${hook.event}`;\n const binding = hook.pi;\n const hasCommand = binding.command !== undefined;\n const hasModule = binding.module !== undefined;\n if (hasCommand === hasModule) throw new Error(`${attribution}: declare exactly one of command or module`);\n const target = hasCommand ? binding.command : binding.module;\n if (typeof target !== 'string' || !target.trim() || target.includes('\\0')) {\n throw new Error(`${attribution}: command or module must be a nonempty string without NUL`);\n }\n if (binding.timeout !== undefined && (!Number.isFinite(binding.timeout) || binding.timeout <= 0)) {\n throw new Error(`${attribution}: timeout must be a positive finite number`);\n }\n if (hasModule && !['SessionStart', 'PreToolUse', 'PostToolUse', 'Stop'].includes(hook.event)) {\n throw new Error(`${attribution}: unsupported module event`);\n }\n entries.push({\n matcher: binding.matcher,\n timeout: binding.timeout,\n skipInSubagent: binding.skipInSubagent,\n ...(hasModule ? { module: path.resolve(source.baseDirectory, target) } : { command: target }),\n registryId,\n rowId,\n event: hook.event,\n order: hook.pi.order ?? 0,\n position,\n groupId,\n core: group.core === true,\n baseDirectory: source.baseDirectory,\n });\n }\n groups.set(groupId, entries);\n }\n }\n\n const entries = [...groups.values()].flat();\n entries.sort((left, right) => left.order - right.order || left.position - right.position);\n return entries;\n}\n\n/**\n * The rows one dispatch runs.\n *\n * Group selection changes when /mode switches mid-session, so inclusion is\n * applied per call rather than being baked into a cached parse. Core groups\n * always load; the rest are gated by the layers the harness resolved.\n */\nexport function selectRegistryHooks(\n entries: ReadonlyArray<RegistryEntry>,\n selection: RegistrySelection,\n): ResolvedHook[] {\n const allowed = selection.allowedGroups === undefined ? undefined : new Set(selection.allowedGroups);\n return entries\n .filter((entry) => entry.core || !allowed || allowed.has(entry.groupId))\n .filter((entry) => entry.event === selection.event)\n .filter((entry) => !(entry.skipInSubagent && selection.inSubagent))\n .filter((entry) => matchesTool(entry.matcher, selection.toolName))\n .map((entry) => ({\n hook:\n entry.module === undefined\n ? { command: entry.command, timeout: entry.timeout }\n : { module: entry.module, timeout: entry.timeout },\n registryId: entry.registryId,\n groupId: entry.groupId,\n rowId: entry.rowId,\n event: entry.event,\n // The declaring config's root, so a global hook can reach its own scripts\n // through CLAUDE_PLUGIN_ROOT while still running against this repository.\n root: entry.baseDirectory,\n }));\n}\n","import fs from 'node:fs';\n\nimport { poConfigCandidates } from '@agimon-ai/po-config/layeredConfig';\nimport { parse as parseYaml } from 'yaml';\n\nimport {\n HOOKS_FILE,\n FILE_ENCODING,\n FILE_NOT_FOUND_ERROR,\n REGISTRY_SOURCE_ATTRIBUTE,\n} from '../../constants/hookDocuments';\nimport { HOOK_TELEMETRY_EVENT } from '../../constants/telemetry';\nimport type {\n HookDocumentReader,\n HookDocumentSource,\n PluginDocumentRead,\n PluginHookConfig,\n PluginHookDocument,\n PluginHookSourceRef,\n RegistryDocument,\n RegistryEntry,\n RegistryRead,\n} from '../../types/hooks';\nimport { type HookTelemetry } from '../../types/telemetry';\nimport { registryCacheKey, registryEntries } from '../hookRegistry';\n\nexport interface HookDocumentReaderOptions {\n telemetry?: HookTelemetry;\n /** Where the global `.po` 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 `.po/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 {\n registryId: candidate.filePath,\n baseDirectory: candidate.baseDirectory,\n text: await readFile(candidate.filePath),\n };\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 registryId: source.registryId,\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 = poConfigCandidates(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","export const TOOL_RESULT_EVENT = 'tool_result';\n","import { TOOL_RESULT_EVENT } from '../../constants/hookPayload';\nimport type { HookPayload, HookToolEvent } from '../../types/hooks';\nimport { toClaudeToolName } from '../toolNames';\n\n/** The payload shape a Claude Code session hook is written against. */\nexport function toolHookPayload(\n event: HookToolEvent,\n hookEventName: string,\n repoRoot: string,\n sessionId: string,\n identity: { parentSessionId?: string; agent?: string } = {},\n): HookPayload {\n return {\n session_id: sessionId,\n transcript_path: '',\n cwd: repoRoot,\n hook_event_name: hookEventName,\n tool_name: toClaudeToolName(event.toolName),\n tool_input: event.input,\n ...(event.type === TOOL_RESULT_EVENT ? { tool_response: { success: !event.isError, content: event.content } } : {}),\n ...(identity.parentSessionId === undefined ? {} : { parent_session_id: identity.parentSessionId }),\n ...(identity.agent === undefined ? {} : { agent_type: identity.agent }),\n };\n}\n\n/** Session lifecycle hooks observe no tool, so they only need where and who. */\nexport function sessionHookPayload(sessionId: string, repoRoot: string): HookPayload {\n return { session_id: sessionId, cwd: repoRoot };\n}\n","export const HOOK_SHELL = '/bin/bash';\nexport const HOOK_SHELL_COMMAND_FLAG = '-c';\nexport const HOOK_TERMINATION_GRACE_MS = 2_000;\nexport const DEFAULT_HOOK_TIMEOUT_SECONDS = 10;\nexport const MILLISECONDS_PER_SECOND = 1_000;\nexport const PROCESS_NOT_FOUND_ERROR = 'ESRCH';\nexport const BROKEN_PIPE_ERROR = 'EPIPE';\nexport const WINDOWS_PLATFORM = 'win32';\nexport const UNKNOWN_EXIT_CODE = -1;\nexport const JSON_LINE_START = '{';\nexport const LINE_BREAK = /\\r?\\n/;\n","import { spawn as spawnProcess } from 'node:child_process';\n\nimport {\n HOOK_SHELL,\n HOOK_SHELL_COMMAND_FLAG,\n HOOK_TERMINATION_GRACE_MS,\n DEFAULT_HOOK_TIMEOUT_SECONDS,\n MILLISECONDS_PER_SECOND,\n PROCESS_NOT_FOUND_ERROR,\n BROKEN_PIPE_ERROR,\n WINDOWS_PLATFORM,\n UNKNOWN_EXIT_CODE,\n JSON_LINE_START,\n LINE_BREAK,\n} from '../../constants/hookRunner';\nimport { HOOK_TELEMETRY_EVENT } from '../../constants/telemetry';\nimport type {\n HookCommand,\n HookDecision,\n HookOutcome,\n HookPayload,\n HookRunOptions,\n HookRunner,\n} from '../../types/hooks';\nimport { type HookTelemetry } from '../../types/telemetry';\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 stdinError: Error | undefined;\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.stdin?.on('error', (error: Error) => {\n // Hooks may exit or close stdin without consuming the entire payload.\n // Keep this listener through settlement: a pending write can fail later.\n if (settled || timedOut || errorCode(error) === BROKEN_PIPE_ERROR) return;\n stdinError = error;\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 if (stdinError) {\n void telemetry?.recordError(HOOK_TELEMETRY_EVENT.hookFailed, stdinError, { 'hook.reason': 'stdin_failed' });\n warn(`[pi-hook] advisory hook could not write stdin: ${stdinError.message}\\n`);\n finish({ failure: { command: hook.command, message: stdinError.message, reason: 'stdin_failed' } });\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","export const SERVICE_NAME = 'po-hook';\nexport const PACKAGE_NAME = '@agimon-ai/po-hook';\n","import { createPoTelemetry, type PoTelemetry, type PoTelemetryOptions } from '@agimon-ai/po-telemetry';\n\nimport { SERVICE_NAME, PACKAGE_NAME } from '../../constants/hookTelemetry';\nimport type { HookTelemetry } from '../../types/telemetry';\n\nexport interface HookTelemetryOptions {\n cwd?: string;\n workspaceRoot?: string;\n env?: NodeJS.ProcessEnv;\n telemetryFactory?: NonNullable<PoTelemetryOptions['telemetryFactory']>;\n warn?: (message: string) => void;\n}\n\nexport function createHookTelemetry(options: HookTelemetryOptions = {}): HookTelemetry {\n const telemetry: PoTelemetry = createPoTelemetry({\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","import type { PluginHookDocument, ResolvedHook } from '../../types/hooks';\nimport { matchesTool } from '../toolNames';\n\n/**\n * The plugin hooks one dispatch runs.\n *\n * Plugin configs are the Claude Code `hooks.json` shape verbatim: an event name\n * maps to groups, each with an optional matcher and a list of commands. Order\n * follows the declaration order of the plugins the harness resolved.\n */\nexport function selectPluginHooks(\n documents: ReadonlyArray<PluginHookDocument>,\n eventName: string,\n toolName?: string,\n): ResolvedHook[] {\n const matches: ResolvedHook[] = [];\n for (const document of documents) {\n for (const group of document.config.hooks?.[eventName] ?? []) {\n if (!matchesTool(group.matcher, toolName)) continue;\n for (const hook of group.hooks ?? []) matches.push({ hook, root: document.pluginRoot });\n }\n }\n return matches;\n}\n","export const HOOK_EVENT = {\n sessionStart: 'SessionStart',\n preToolUse: 'PreToolUse',\n postToolUse: 'PostToolUse',\n stop: 'Stop',\n sessionEnd: 'SessionEnd',\n} as const;\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { DEFAULT_HOOK_TIMEOUT_SECONDS } from '../../constants/hookRunner';\nimport type {\n HookContext,\n HookHandlers,\n HookModule,\n HookModuleDescriptor,\n HookModuleResult,\n} from '../../types/hookModule';\nimport type { HookModuleOutcome, HookModules, HookModulesOptions } from './type';\n\ninterface Instance {\n lifetime: AbortController;\n queue: Promise<unknown>;\n handlers?: HookHandlers;\n quarantined: boolean;\n settled: boolean;\n disposed: boolean;\n hostEffectFailure?: { error: unknown };\n}\nfunction assertHostEffects(instance: Instance): void {\n if (instance.hostEffectFailure) throw instance.hostEffectFailure.error;\n}\nconst HANDLER_NAMES = ['tool_call', 'tool_result', 'session_start', 'agent_settled', 'dispose'] as const;\nfunction object(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\nfunction validateHandlers(value: unknown): asserts value is HookHandlers {\n if (\n !object(value) ||\n Object.entries(value).some(\n ([key, handler]) =>\n !HANDLER_NAMES.includes(key as (typeof HANDLER_NAMES)[number]) || typeof handler !== 'function',\n )\n ) {\n throw new Error('setup must return hook handlers');\n }\n}\nfunction jsonValue(value: unknown, ancestors = new Set<unknown>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || ancestors.has(value)) return false;\n if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype) return false;\n ancestors.add(value);\n const valid = Object.values(value).every((item) => jsonValue(item, ancestors));\n ancestors.delete(value);\n return valid;\n}\nfunction validResult(event: string, value: unknown): boolean {\n if (value === undefined) return true;\n if (!object(value)) return false;\n if (event === 'tool_call')\n return (\n Object.keys(value).every((key) => ['block', 'reason'].includes(key)) &&\n (value.block === undefined || typeof value.block === 'boolean') &&\n (value.reason === undefined || typeof value.reason === 'string')\n );\n if (event !== 'tool_result') return false;\n return (\n Object.keys(value).every((key) => ['content', 'details', 'isError'].includes(key)) &&\n (value.isError === undefined || typeof value.isError === 'boolean') &&\n (value.details === undefined || jsonValue(value.details)) &&\n (value.content === undefined ||\n (Array.isArray(value.content) &&\n value.content.every(\n (part) =>\n object(part) &&\n ((part.type === 'text' && typeof part.text === 'string') ||\n (part.type === 'image' && typeof part.data === 'string' && typeof part.mimeType === 'string')),\n )))\n );\n}\n\n/** One registry belongs to one session binding, never to the process. */\nexport function createHookModules(options: HookModulesOptions = {}): HookModules {\n const instances = new Map<string, Instance>();\n let descriptor: Promise<Map<string, string>> | undefined;\n let closed = false;\n let disposal: Promise<void> | undefined;\n function artifacts(): Promise<Map<string, string>> {\n descriptor ??= (async () => {\n if (!options.descriptor) return new Map<string, string>();\n const value: unknown = JSON.parse(await fs.readFile(options.descriptor.file, 'utf8'));\n if (!object(value) || value.version !== 1 || !Array.isArray(value.modules))\n throw new Error('invalid hook module descriptor');\n const result = new Map<string, string>();\n for (const entry of value.modules as HookModuleDescriptor['modules']) {\n if (\n !object(entry) ||\n typeof entry.source !== 'string' ||\n typeof entry.artifact !== 'string' ||\n !path.isAbsolute(entry.source) ||\n !path.isAbsolute(entry.artifact) ||\n !['.mjs', '.js', '.cjs'].includes(path.extname(entry.artifact)) ||\n result.has(entry.source)\n ) {\n throw new Error('invalid hook module artifact mapping');\n }\n result.set(entry.source, entry.artifact);\n }\n return result;\n })();\n return descriptor;\n }\n async function disposeInstance(instance: Instance): Promise<void> {\n if (!instance.handlers || instance.disposed) return;\n instance.disposed = true;\n await instance.handlers.dispose?.();\n }\n function contextFor(context: HookContext, instance: Instance, signal: AbortSignal): HookContext {\n function assertActive(message: boolean): void {\n if (closed || signal.aborted || instance.lifetime.signal.aborted) throw new Error('hook context revoked');\n if (message && instance.settled) throw new Error('agent_settled cannot send messages');\n }\n return {\n ...context,\n signal,\n async sendMessage(text, delivery) {\n assertActive(true);\n await context.sendMessage(text, delivery);\n },\n async appendCustomEntry(type, data) {\n assertActive(false);\n await context.appendCustomEntry(type, data);\n },\n };\n }\n return {\n async validate(rows): Promise<void> {\n for (const row of rows) {\n if (!row.module) continue;\n try {\n const artifact = (await artifacts()).get(row.module);\n if (!artifact) throw new Error('module missing from descriptor');\n const stat = await fs.stat(artifact);\n if (!stat.isFile()) throw new Error(`hook artifact is not a file: ${artifact}`);\n } catch (cause) {\n throw new Error(\n `${row.registryId ?? ''}: group ${row.groupId ?? ''}, row ${row.rowId ?? ''}, event ${row.event ?? ''}, module ${row.module}: ${cause instanceof Error ? cause.message : String(cause)}. Fix the hook module, then restart or reopen this session.`,\n { cause },\n );\n }\n }\n },\n async invoke(row, event, context, operationSignal): Promise<HookModuleOutcome> {\n const source = 'module' in row.hook ? row.hook.module : undefined;\n const failure = (error: unknown, timeout = false): HookModuleOutcome => ({\n failure: {\n command: source ?? '',\n reason: timeout ? 'timeout' : 'module_failed',\n message: `${row.registryId ?? ''}: group ${row.groupId ?? ''}, row ${row.rowId ?? ''}, event ${row.event ?? event.type}, module ${source ?? ''}: ${error instanceof Error ? error.message : String(error)}`,\n },\n });\n if (!source) return failure(new Error('not a module row'));\n if (closed || context.signal.aborted) return failure(new Error('hook session disposed'));\n const key = `${context.sessionId}\\0${source}`;\n let instance = instances.get(key);\n if (!instance) {\n instance = {\n lifetime: new AbortController(),\n queue: Promise.resolve(),\n quarantined: false,\n settled: false,\n disposed: false,\n };\n instances.set(key, instance);\n }\n const current = instance;\n const hostContext: HookContext = {\n ...context,\n async sendMessage(text, delivery) {\n try {\n await context.sendMessage(text, delivery);\n } catch (error) {\n current.hostEffectFailure = { error };\n throw error;\n }\n },\n async appendCustomEntry(type, data) {\n try {\n await context.appendCustomEntry(type, data);\n } catch (error) {\n current.hostEffectFailure = { error };\n throw error;\n }\n },\n };\n const run = async (): Promise<HookModuleOutcome> => {\n if (closed || current.quarantined || current.lifetime.signal.aborted)\n return failure(new Error('module quarantined or disposed'));\n current.hostEffectFailure = undefined;\n current.settled = event.type === 'agent_settled';\n const controller = new AbortController();\n const signal = AbortSignal.any([\n context.signal,\n current.lifetime.signal,\n controller.signal,\n ...(operationSignal ? [operationSignal] : []),\n ]);\n let timer: ReturnType<typeof setTimeout> | undefined;\n let setup = !current.handlers;\n let timedOut = false;\n const operation = (async () => {\n if (!current.handlers) {\n const artifact = (await artifacts()).get(source);\n if (!artifact) throw new Error('sync required: module missing from descriptor');\n const imported: { default?: unknown } = await import(pathToFileURL(artifact).href);\n if (signal.aborted) throw new Error('hook context aborted');\n if (!object(imported.default) || typeof imported.default.setup !== 'function')\n throw new Error('module default export must declare setup');\n const handlers = await (imported.default as unknown as HookModule).setup(\n contextFor(hostContext, current, AbortSignal.any([context.signal, current.lifetime.signal])),\n );\n validateHandlers(handlers);\n current.handlers = handlers;\n if (closed || current.quarantined || signal.aborted) {\n await disposeInstance(current);\n return undefined;\n }\n }\n setup = false;\n const ctx = contextFor(hostContext, current, signal);\n switch (event.type) {\n case 'tool_call':\n return current.handlers.tool_call?.(event, ctx);\n case 'tool_result':\n return current.handlers.tool_result?.(event, ctx);\n case 'session_start':\n return current.handlers.session_start?.(event, ctx);\n case 'agent_settled':\n return current.handlers.agent_settled?.(event, ctx);\n }\n })();\n try {\n const aborted = new Promise<never>((_, reject) => {\n const abort = () => reject(new Error(timedOut ? 'hook module timed out' : 'hook context aborted'));\n signal.addEventListener('abort', abort, { once: true });\n operation.finally(() => signal.removeEventListener('abort', abort)).catch(() => undefined);\n if (signal.aborted) abort();\n timer = setTimeout(\n () => {\n timedOut = true;\n controller.abort();\n },\n (row.hook.timeout ?? DEFAULT_HOOK_TIMEOUT_SECONDS) * 1000,\n );\n });\n const result = await Promise.race([operation, aborted]);\n assertHostEffects(current);\n if (!validResult(event.type, result))\n return { failure: { ...failure(new Error('invalid hook result')).failure!, reason: 'invalid_result' } };\n return result === undefined ? {} : { result: result as HookModuleResult };\n } catch (error) {\n assertHostEffects(current);\n if (setup || timedOut || signal.aborted) {\n current.quarantined = true;\n current.lifetime.abort();\n }\n return failure(error, timedOut);\n } finally {\n clearTimeout(timer);\n controller.abort();\n current.settled = false;\n }\n };\n const invocation = current.queue.then(run);\n // Admission failures still reject the caller, but must not poison serialization.\n current.queue = invocation.catch(() => undefined);\n return invocation;\n },\n dispose(): Promise<void> {\n disposal ??= (async () => {\n closed = true;\n for (const instance of instances.values()) instance.lifetime.abort();\n await Promise.all(\n [...instances.values()].map(async (instance) => {\n await instance.queue;\n await disposeInstance(instance);\n }),\n );\n })();\n return disposal;\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { poConfigCandidates } from "@agimon-ai/po-config/layeredConfig";
|
|
3
3
|
import { parse } from "yaml";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
|
-
import {
|
|
6
|
+
import { createPoTelemetry } from "@agimon-ai/po-telemetry";
|
|
7
7
|
import fs$1 from "node:fs/promises";
|
|
8
8
|
import { pathToFileURL } from "node:url";
|
|
9
9
|
//#endregion
|
|
@@ -51,8 +51,8 @@ const REGISTRY_SOURCE_ATTRIBUTE = "repository";
|
|
|
51
51
|
//#endregion
|
|
52
52
|
//#region src/constants/telemetry.ts
|
|
53
53
|
const HOOK_TELEMETRY_EVENT = {
|
|
54
|
-
hookFailed: "
|
|
55
|
-
hookRegistryReadFailed: "
|
|
54
|
+
hookFailed: "po_pi_hook.failed",
|
|
55
|
+
hookRegistryReadFailed: "po_pi_hook.registry_read_failed"
|
|
56
56
|
};
|
|
57
57
|
//#endregion
|
|
58
58
|
//#region src/services/toolNames/index.ts
|
|
@@ -219,7 +219,7 @@ function createHookDocumentReader(options = {}) {
|
|
|
219
219
|
};
|
|
220
220
|
return {
|
|
221
221
|
async registry(repoRoot) {
|
|
222
|
-
const candidates =
|
|
222
|
+
const candidates = poConfigCandidates(HOOKS_FILE, repoRoot, options.homeDirectory);
|
|
223
223
|
const registryPath = candidates.map((candidate) => candidate.filePath).join(" and ");
|
|
224
224
|
try {
|
|
225
225
|
const sources = (await Promise.all(candidates.map(readSource))).filter((source) => source !== void 0);
|
|
@@ -472,7 +472,7 @@ const PACKAGE_NAME = "@agimon-ai/po-hook";
|
|
|
472
472
|
//#endregion
|
|
473
473
|
//#region src/services/hookTelemetry/index.ts
|
|
474
474
|
function createHookTelemetry(options = {}) {
|
|
475
|
-
const telemetry =
|
|
475
|
+
const telemetry = createPoTelemetry({
|
|
476
476
|
serviceName: SERVICE_NAME,
|
|
477
477
|
packageName: PACKAGE_NAME,
|
|
478
478
|
cwd: options.cwd,
|
|
@@ -746,4 +746,4 @@ function createHookModules(options = {}) {
|
|
|
746
746
|
//#endregion
|
|
747
747
|
export { decisionsFrom as _, createBashHookRunner as a, isDenied as b, createHookDocumentReader as c, selectRegistryHooks as d, matchesTool as f, decisionReason as g, additionalContextsFrom as h, createHookTelemetry as i, registryCacheKey as l, HOOK_TELEMETRY_EVENT as m, HOOK_EVENT as n, sessionHookPayload as o, toClaudeToolName as p, selectPluginHooks as r, toolHookPayload as s, createHookModules as t, registryEntries as u, failuresFrom as v, toolResultMessages as x, hookFailureMessage as y };
|
|
748
748
|
|
|
749
|
-
//# sourceMappingURL=hookModules-
|
|
749
|
+
//# sourceMappingURL=hookModules-ClLNr9FP.mjs.map
|