@agimon-ai/po-hook 0.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +177 -0
  3. package/dist/apiContracts.cjs +17 -0
  4. package/dist/apiContracts.cjs.map +1 -0
  5. package/dist/apiContracts.d.mts +53 -0
  6. package/dist/apiContracts.d.mts.map +1 -0
  7. package/dist/apiContracts.mjs +13 -0
  8. package/dist/apiContracts.mjs.map +1 -0
  9. package/dist/authoring.cjs +10 -0
  10. package/dist/authoring.cjs.map +1 -0
  11. package/dist/authoring.d.mts +7 -0
  12. package/dist/authoring.d.mts.map +1 -0
  13. package/dist/authoring.mjs +9 -0
  14. package/dist/authoring.mjs.map +1 -0
  15. package/dist/extensions/mcp.cjs +26 -0
  16. package/dist/extensions/mcp.cjs.map +1 -0
  17. package/dist/extensions/mcp.d.mts +5 -0
  18. package/dist/extensions/mcp.d.mts.map +1 -0
  19. package/dist/extensions/mcp.mjs +21 -0
  20. package/dist/extensions/mcp.mjs.map +1 -0
  21. package/dist/extensions/server.cjs +611 -0
  22. package/dist/extensions/server.cjs.map +1 -0
  23. package/dist/extensions/server.d.mts +5 -0
  24. package/dist/extensions/server.d.mts.map +1 -0
  25. package/dist/extensions/server.mjs +606 -0
  26. package/dist/extensions/server.mjs.map +1 -0
  27. package/dist/hookModule-f-HwSbmi.d.mts +54 -0
  28. package/dist/hookModule-f-HwSbmi.d.mts.map +1 -0
  29. package/dist/hookModules-DSheklXp.cjs +899 -0
  30. package/dist/hookModules-DSheklXp.cjs.map +1 -0
  31. package/dist/hookModules-GoRDG8mg.mjs +749 -0
  32. package/dist/hookModules-GoRDG8mg.mjs.map +1 -0
  33. package/dist/index.cjs +23 -0
  34. package/dist/index.d.mts +362 -0
  35. package/dist/index.d.mts.map +1 -0
  36. package/dist/index.mjs +2 -0
  37. package/llms.txt +11 -0
  38. package/package.json +122 -0
  39. package/src/prompts/po-author-hook/SKILL.md +128 -0
@@ -0,0 +1,606 @@
1
+ import { a as createBashHookRunner, b as isDenied, c as createHookDocumentReader, d as selectRegistryHooks, g as decisionReason, h as additionalContextsFrom, i as createHookTelemetry, n as HOOK_EVENT, o as sessionHookPayload, r as selectPluginHooks, s as toolHookPayload, t as createHookModules, x as toolResultMessages, y as hookFailureMessage } from "../hookModules-GoRDG8mg.mjs";
2
+ import { composeServerProviderOverrides, defineServerPlugin, packageResourcePath, readPackageResource } from "@agimon-ai/po-core/serverFacet";
3
+ import { composeRootHooks, defineHook, defineResource, defineRoot } from "@agimon-ai/po-core/extensionFile";
4
+ import { DoomHeadlessPromptAdmissionError } from "@agimon-ai/po-core/headless";
5
+ import { requireDoomConfigContext } from "@agimon-ai/po-config/piContext";
6
+ import { DOOM_CHILD_SESSION_HOOKS_SERVICE } from "@agimon-ai/po-core/childSession";
7
+ import { DOOM_CONFIG_SERVICE } from "@agimon-ai/po-core/config";
8
+ import { DOOM_HELP_WHEN } from "@agimon-ai/po-core/help";
9
+ //#region src/constants/hookHandlers.ts
10
+ const STATUS_PREFIX = "repository-hooks";
11
+ const FAILURE_MESSAGE_TYPE = "repository-hook-failure";
12
+ /** Claude's Stop hook input field: true when the agent is already continuing because of a Stop hook. */
13
+ const STOP_HOOK_ACTIVE_FIELD = "stop_hook_active";
14
+ const SUBAGENT_ENVIRONMENT_FLAG = "PI_SUBAGENT_CHILD";
15
+ //#endregion
16
+ //#region src/services/hookDispatch/index.ts
17
+ function isJson(value, ancestors = /* @__PURE__ */ new Set()) {
18
+ if (value === null || typeof value === "string" || typeof value === "boolean") return true;
19
+ if (typeof value === "number") return Number.isFinite(value);
20
+ if (typeof value !== "object" || ancestors.has(value)) return false;
21
+ ancestors.add(value);
22
+ const valid = (Array.isArray(value) || Object.getPrototypeOf(value) === Object.prototype) && Object.values(value).every((entry) => isJson(entry, ancestors));
23
+ ancestors.delete(value);
24
+ return valid;
25
+ }
26
+ function commandFailure(row, error) {
27
+ return {
28
+ command: row.hook.command ?? row.hook.module,
29
+ message: error instanceof Error ? error.message : String(error),
30
+ reason: "hook_execution"
31
+ };
32
+ }
33
+ /** Registry rows interleave command and module bindings, followed by plugin commands. */
34
+ async function dispatchHooks(session, scope, request) {
35
+ const signal = scope.operationSignal ? AbortSignal.any([scope.signal, scope.operationSignal]) : scope.signal;
36
+ signal.throwIfAborted();
37
+ const harness = session.config().harness;
38
+ const plugins = await session.documents.plugins(harness.pluginHooks);
39
+ const registry = request.eventName === HOOK_EVENT.sessionEnd ? {
40
+ entries: [],
41
+ failure: void 0
42
+ } : await session.documents.registry(scope.repoRoot);
43
+ signal.throwIfAborted();
44
+ const event = request.event;
45
+ const toolName = event && "toolName" in event ? event.toolName : void 0;
46
+ const hooks = [...selectRegistryHooks(registry.entries, {
47
+ event: request.eventName,
48
+ toolName,
49
+ allowedGroups: harness.hookGroups,
50
+ inSubagent: scope.isSubagent
51
+ }), ...selectPluginHooks(plugins.documents, request.eventName, toolName)];
52
+ const decisions = [];
53
+ const failures = [...registry.failure ? [registry.failure] : [], ...plugins.failures];
54
+ let toolCall;
55
+ let patchedResult = false;
56
+ for (const [index, row] of hooks.entries()) {
57
+ signal.throwIfAborted();
58
+ request.progress?.(index, hooks.length);
59
+ if (row.hook.command === void 0) {
60
+ if (!event) continue;
61
+ let proposed;
62
+ try {
63
+ proposed = structuredClone(event);
64
+ } catch (error) {
65
+ failures.push(commandFailure(row, error));
66
+ continue;
67
+ }
68
+ const outcome = await session.modules.invoke(row, proposed, scope, scope.operationSignal);
69
+ signal.throwIfAborted();
70
+ if (outcome.failure) {
71
+ failures.push(outcome.failure);
72
+ continue;
73
+ }
74
+ try {
75
+ if (event.type === "tool_call" && proposed.type === "tool_call") {
76
+ if (typeof proposed.input !== "object" || proposed.input === null || Array.isArray(proposed.input) || !isJson(proposed.input)) throw new Error("Hook tool input must be a JSON object.");
77
+ const input = structuredClone(proposed.input);
78
+ for (const key of Object.keys(event.input)) delete event.input[key];
79
+ Object.assign(event.input, input);
80
+ if (outcome.result && "block" in outcome.result && outcome.result.block) {
81
+ toolCall = {
82
+ block: true,
83
+ reason: outcome.result.reason ?? "Blocked by repository hook"
84
+ };
85
+ break;
86
+ }
87
+ } else if (event.type === "tool_result" && outcome.result) {
88
+ const patch = structuredClone(outcome.result);
89
+ if ("content" in patch && patch.content !== void 0) event.content = patch.content;
90
+ if ("details" in patch) event.details = patch.details;
91
+ if ("isError" in patch && patch.isError !== void 0) event.isError = patch.isError;
92
+ patchedResult = true;
93
+ }
94
+ } catch (error) {
95
+ failures.push(commandFailure(row, error));
96
+ }
97
+ continue;
98
+ }
99
+ const payload = event && "toolName" in event ? toolHookPayload(event, request.eventName, scope.repoRoot, scope.sessionId, {
100
+ parentSessionId: scope.parentSessionId,
101
+ agent: scope.agent
102
+ }) : sessionHookPayload(scope.sessionId, scope.repoRoot);
103
+ let outcome;
104
+ try {
105
+ outcome = await session.runner.run(row.hook, {
106
+ ...payload,
107
+ ...request.extraPayload
108
+ }, {
109
+ repoRoot: scope.repoRoot,
110
+ pluginRoot: row.root
111
+ });
112
+ } catch (error) {
113
+ failures.push(commandFailure(row, error));
114
+ continue;
115
+ }
116
+ signal.throwIfAborted();
117
+ if (outcome.failure) failures.push(outcome.failure);
118
+ if (!outcome.decision) continue;
119
+ decisions.push(outcome.decision);
120
+ if (event?.type === "tool_result") {
121
+ const messages = toolResultMessages([outcome.decision]);
122
+ if (messages.length > 0) event.content = [...event.content, {
123
+ type: "text",
124
+ text: messages.join("\n\n")
125
+ }];
126
+ if (isDenied(outcome.decision)) event.isError = true;
127
+ patchedResult ||= messages.length > 0 || isDenied(outcome.decision);
128
+ }
129
+ if (isDenied(outcome.decision)) {
130
+ if (event?.type === "tool_call") toolCall = {
131
+ block: true,
132
+ reason: decisionReason(outcome.decision) ?? "Blocked by repository hook"
133
+ };
134
+ break;
135
+ }
136
+ }
137
+ if (event?.type === "tool_call" && !toolCall) {
138
+ const context = additionalContextsFrom(decisions).join("\n\n");
139
+ if (context) toolCall = {
140
+ block: true,
141
+ reason: context
142
+ };
143
+ }
144
+ if (event?.type === "tool_result" && failures.length > 0) {
145
+ event.content = [...event.content, {
146
+ type: "text",
147
+ text: hookFailureMessage(failures)
148
+ }];
149
+ patchedResult = true;
150
+ }
151
+ return {
152
+ decisions,
153
+ failures,
154
+ ...toolCall ? { toolCall } : {},
155
+ ...event?.type === "tool_result" && patchedResult ? { toolResult: {
156
+ content: event.content,
157
+ details: event.details,
158
+ isError: event.isError
159
+ } } : {}
160
+ };
161
+ }
162
+ //#endregion
163
+ //#region src/services/hookRuntime/type.ts
164
+ const DOOM_HOOK_SESSION_SERVICE = "doom/hook-session";
165
+ //#endregion
166
+ //#region src/services/hookRuntime/index.ts
167
+ function createHookSession(config, options, signal) {
168
+ let telemetry = options.telemetry;
169
+ const requireTelemetry = () => telemetry ??= createHookTelemetry();
170
+ const modules = createHookModules({ descriptor: config().harness.hookModules });
171
+ const documents = options.documents ?? createHookDocumentReader({ telemetry: requireTelemetry() });
172
+ let preparation;
173
+ return {
174
+ config,
175
+ signal,
176
+ modules,
177
+ prepare(isSubagent = false) {
178
+ preparation ??= (async () => {
179
+ const harness = config().harness;
180
+ if (harness.hooks === false) return;
181
+ const registry = await documents.registry(harness.root ?? process.cwd());
182
+ if (registry.failure) return;
183
+ const allowed = harness.hookGroups === void 0 ? void 0 : new Set(harness.hookGroups);
184
+ const rows = registry.entries.filter((row) => row.core || !allowed || allowed.has(row.groupId)).filter((row) => !(isSubagent && row.skipInSubagent));
185
+ await modules.validate(rows);
186
+ })();
187
+ return preparation;
188
+ },
189
+ runner: options.runner ?? createBashHookRunner({ telemetry: requireTelemetry() }),
190
+ documents
191
+ };
192
+ }
193
+ function childHooksFor(parent) {
194
+ return { bind(scope) {
195
+ const config = structuredClone(parent.config());
196
+ const controller = new AbortController();
197
+ const signal = AbortSignal.any([controller.signal, scope.signal]);
198
+ const session = createHookSession(() => config, {
199
+ runner: parent.runner,
200
+ documents: parent.documents
201
+ }, signal);
202
+ let disposal;
203
+ const context = () => {
204
+ const sessionId = scope.sessionId();
205
+ if (!sessionId) throw new Error("Child hook identity is unavailable before runtime startup.");
206
+ return {
207
+ sessionId,
208
+ parentSessionId: scope.request.parentSessionId,
209
+ agent: scope.request.agent,
210
+ isSubagent: true,
211
+ cwd: scope.request.cwd,
212
+ repoRoot: config.harness.root ?? scope.request.cwd,
213
+ signal,
214
+ sendMessage: (text, delivery) => scope.sendMessage(text, delivery),
215
+ appendCustomEntry: (type, data) => scope.appendCustomEntry(type, data)
216
+ };
217
+ };
218
+ return {
219
+ async beforeTool(event, execution) {
220
+ await session.prepare(true);
221
+ const native = {
222
+ type: "tool_call",
223
+ toolCallId: event.toolCallId,
224
+ toolName: event.toolName,
225
+ input: event.args
226
+ };
227
+ const result = await dispatchHooks(session, {
228
+ ...context(),
229
+ operationSignal: execution.abortSignal
230
+ }, {
231
+ eventName: HOOK_EVENT.preToolUse,
232
+ event: native
233
+ });
234
+ if (result.failures.length > 0) await scope.sendMessage(hookFailureMessage(result.failures), "steer");
235
+ return result.toolCall?.block ? { block: { reason: result.toolCall.reason ?? "Blocked by repository hook" } } : { args: native.input };
236
+ },
237
+ async afterTool(event, execution) {
238
+ const native = {
239
+ type: "tool_result",
240
+ toolCallId: event.toolCallId,
241
+ toolName: event.toolName,
242
+ input: event.args,
243
+ content: event.content,
244
+ details: event.details,
245
+ isError: event.isError
246
+ };
247
+ const result = await dispatchHooks(session, {
248
+ ...context(),
249
+ operationSignal: execution.abortSignal
250
+ }, {
251
+ eventName: HOOK_EVENT.postToolUse,
252
+ event: native
253
+ });
254
+ return result.toolResult ? {
255
+ content: result.toolResult.content,
256
+ details: result.toolResult.details,
257
+ isError: result.toolResult.isError
258
+ } : void 0;
259
+ },
260
+ dispose() {
261
+ disposal ??= (async () => {
262
+ controller.abort();
263
+ await session.modules.dispose();
264
+ })();
265
+ return disposal;
266
+ }
267
+ };
268
+ } };
269
+ }
270
+ function createHookRuntime(cordis, options, parentContext, lifetimeSignal) {
271
+ const controller = new AbortController();
272
+ const signal = lifetimeSignal ? AbortSignal.any([controller.signal, lifetimeSignal]) : controller.signal;
273
+ const session = {
274
+ ...createHookSession(() => requireDoomConfigContext(cordis), options, signal),
275
+ parentContext
276
+ };
277
+ let disposal;
278
+ let active = true;
279
+ return {
280
+ session,
281
+ childHooks: childHooksFor(session),
282
+ isCurrent: () => active && !signal.aborted,
283
+ dispose() {
284
+ active = false;
285
+ controller.abort();
286
+ disposal ??= session.modules.dispose();
287
+ return disposal;
288
+ }
289
+ };
290
+ }
291
+ function createHookBinding(options, parentContext, lifetimeSignal) {
292
+ let runtime;
293
+ return {
294
+ plugin(cordis) {
295
+ cordis.inject([DOOM_CONFIG_SERVICE], (configContext) => {
296
+ const binding = createHookRuntime(configContext, options, parentContext, lifetimeSignal);
297
+ runtime = binding;
298
+ configContext.provide(DOOM_CHILD_SESSION_HOOKS_SERVICE, binding.childHooks);
299
+ configContext.provide(DOOM_HOOK_SESSION_SERVICE, binding);
300
+ return async () => {
301
+ if (runtime === binding) runtime = void 0;
302
+ await binding.dispose();
303
+ };
304
+ });
305
+ },
306
+ runtime: () => runtime
307
+ };
308
+ }
309
+ //#endregion
310
+ //#region src/services/serverHooks/index.ts
311
+ function hookEntry(event) {
312
+ return {
313
+ version: 1,
314
+ event: typeof event.type === "string" ? event.type : "headless-hook",
315
+ data: event
316
+ };
317
+ }
318
+ function scopeFor(runtime, execution) {
319
+ return {
320
+ sessionId: execution.sessionId,
321
+ isSubagent: Boolean(execution.environment[SUBAGENT_ENVIRONMENT_FLAG]),
322
+ cwd: execution.cwd,
323
+ repoRoot: execution.repoRoot,
324
+ model: execution.model,
325
+ signal: runtime.session.signal,
326
+ operationSignal: execution.signal,
327
+ async sendMessage(text, delivery) {
328
+ if (!execution.session.admitPrompt) throw new DoomHeadlessPromptAdmissionError("The session cannot admit a hook prompt.");
329
+ await execution.session.admitPrompt(text, delivery);
330
+ },
331
+ appendCustomEntry: (type, data) => execution.session.appendCustomEntry(type, data)
332
+ };
333
+ }
334
+ /** One native owner dispatches lifecycle and tool rows for this session. */
335
+ function createServerHooks(resolveRuntime) {
336
+ const startups = /* @__PURE__ */ new WeakMap();
337
+ const shutdowns = /* @__PURE__ */ new WeakMap();
338
+ const refusals = /* @__PURE__ */ new WeakMap();
339
+ async function runLifecycle(runtime, execution, eventName, event, extraPayload) {
340
+ const key = `${STATUS_PREFIX}:${execution.sessionId}:${eventName}`;
341
+ try {
342
+ return await dispatchHooks(runtime.session, scopeFor(runtime, execution), {
343
+ eventName,
344
+ event,
345
+ extraPayload,
346
+ progress: (index, total) => execution.client.setStatus(key, `Running ${eventName} hooks (${index + 1}/${total})...`)
347
+ });
348
+ } finally {
349
+ execution.client.setStatus(key, void 0);
350
+ }
351
+ }
352
+ function start(runtime, execution, event = { type: "session_start" }) {
353
+ let startup = startups.get(runtime);
354
+ if (!startup) {
355
+ startup = (async () => {
356
+ const scope = scopeFor(runtime, execution);
357
+ await runtime.session.prepare(scope.isSubagent);
358
+ if (scope.isSubagent) return;
359
+ const result = await runLifecycle(runtime, execution, HOOK_EVENT.sessionStart, {
360
+ ...event,
361
+ type: "session_start"
362
+ });
363
+ if (!runtime.isCurrent()) return;
364
+ if (result.failures.length) await scope.sendMessage(hookFailureMessage(result.failures), "steer");
365
+ const context = additionalContextsFrom(result.decisions).join("\n\n");
366
+ if (context) await scope.sendMessage(context, "steer");
367
+ })();
368
+ startups.set(runtime, startup);
369
+ }
370
+ return startup;
371
+ }
372
+ return {
373
+ sessionStart: {
374
+ event: "session_start",
375
+ async handle(event, execution) {
376
+ const runtime = resolveRuntime();
377
+ if (runtime?.isCurrent()) await start(runtime, execution, event);
378
+ }
379
+ },
380
+ agentEnd: {
381
+ event: "agent_end",
382
+ async handle(event, execution) {
383
+ const runtime = resolveRuntime();
384
+ if (!runtime?.isCurrent() || scopeFor(runtime, execution).isSubagent) return;
385
+ await start(runtime, execution);
386
+ const count = refusals.get(runtime) ?? 0;
387
+ const result = await runLifecycle(runtime, execution, HOOK_EVENT.stop, {
388
+ ...event,
389
+ type: "agent_settled"
390
+ }, { [STOP_HOOK_ACTIVE_FIELD]: count > 0 });
391
+ if (!runtime.isCurrent()) return;
392
+ const appendFailure = async (text) => {
393
+ if (!execution.session.appendMessage) throw new Error("The session cannot append hook diagnostics.");
394
+ await execution.session.appendMessage({
395
+ type: FAILURE_MESSAGE_TYPE,
396
+ text
397
+ });
398
+ };
399
+ if (result.failures.length) await appendFailure(hookFailureMessage(result.failures));
400
+ const reason = decisionReason(result.decisions.find(isDenied));
401
+ if (!reason) {
402
+ refusals.set(runtime, 0);
403
+ return;
404
+ }
405
+ if (count >= 5) {
406
+ refusals.set(runtime, 0);
407
+ await appendFailure(`A Stop hook refused ${String(5)} stops in a row, so the agent stops here. Its last reason: ${reason}`);
408
+ return;
409
+ }
410
+ await scopeFor(runtime, execution).sendMessage(reason, "followUp");
411
+ refusals.set(runtime, count + 1);
412
+ }
413
+ },
414
+ beforeAgentStart: {
415
+ event: "before_agent_start",
416
+ async handle(event, execution) {
417
+ const runtime = resolveRuntime();
418
+ if (runtime?.isCurrent()) await start(runtime, execution);
419
+ await execution.session.appendCustomEntry("doom-hook", hookEntry(event));
420
+ }
421
+ },
422
+ toolCall: {
423
+ event: "tool_call",
424
+ async handle(event, execution) {
425
+ const runtime = resolveRuntime();
426
+ if (!runtime?.isCurrent()) return;
427
+ const scope = scopeFor(runtime, execution);
428
+ try {
429
+ await start(runtime, execution);
430
+ } catch (error) {
431
+ return { block: { reason: error instanceof Error ? error.message : String(error) } };
432
+ }
433
+ const native = {
434
+ type: "tool_call",
435
+ toolCallId: event.toolCallId,
436
+ toolName: event.toolName,
437
+ input: event.args
438
+ };
439
+ const key = `${STATUS_PREFIX}:${native.toolCallId}:pre`;
440
+ try {
441
+ const result = await dispatchHooks(runtime.session, scope, {
442
+ eventName: HOOK_EVENT.preToolUse,
443
+ event: native,
444
+ progress: (index, total) => execution.client.setStatus(key, `Running pre-tool hooks for ${native.toolName} (${index + 1}/${total})...`)
445
+ });
446
+ if (result.failures.length > 0) await scope.sendMessage(hookFailureMessage(result.failures), "steer");
447
+ return result.toolCall?.block ? { block: { reason: result.toolCall.reason ?? "Blocked by repository hook" } } : { args: native.input };
448
+ } finally {
449
+ execution.client.setStatus(key, void 0);
450
+ }
451
+ }
452
+ },
453
+ toolResult: {
454
+ event: "tool_result",
455
+ async handle(event, execution) {
456
+ await execution.session.appendCustomEntry("doom-hook", hookEntry(event));
457
+ const runtime = resolveRuntime();
458
+ if (!runtime?.isCurrent()) return;
459
+ await start(runtime, execution);
460
+ const native = {
461
+ type: "tool_result",
462
+ toolCallId: event.toolCallId,
463
+ toolName: event.toolName,
464
+ input: event.args,
465
+ content: event.content,
466
+ details: event.details,
467
+ isError: event.isError
468
+ };
469
+ const key = `${STATUS_PREFIX}:${native.toolCallId}:post`;
470
+ try {
471
+ return (await dispatchHooks(runtime.session, scopeFor(runtime, execution), {
472
+ eventName: HOOK_EVENT.postToolUse,
473
+ event: native,
474
+ progress: (index, total) => execution.client.setStatus(key, `Running post-tool hooks for ${native.toolName} (${index + 1}/${total})...`)
475
+ })).toolResult;
476
+ } finally {
477
+ execution.client.setStatus(key, void 0);
478
+ }
479
+ }
480
+ },
481
+ agentSettled: {
482
+ event: "agent_settled",
483
+ handle: (event, execution) => execution.session.appendCustomEntry("doom-hook", hookEntry(event))
484
+ },
485
+ sessionShutdown: {
486
+ event: "session_shutdown",
487
+ async handle(_event, execution) {
488
+ const runtime = resolveRuntime();
489
+ if (runtime?.isCurrent() && !scopeFor(runtime, execution).isSubagent) {
490
+ let shutdown = shutdowns.get(runtime);
491
+ if (!shutdown) {
492
+ shutdown = runLifecycle(runtime, execution, HOOK_EVENT.sessionEnd).then(() => void 0);
493
+ shutdowns.set(runtime, shutdown);
494
+ }
495
+ await shutdown;
496
+ }
497
+ execution.client.setStatus("doom-hook", void 0);
498
+ }
499
+ }
500
+ };
501
+ }
502
+ //#endregion
503
+ //#region src/extensions/workspaces/sessions/(backend)/_lib/serverRoot.ts
504
+ const createHookServerRoot = ({ agent, signal }) => {
505
+ if (!agent) throw new Error("Hook session requires the headless host.");
506
+ const execution = agent.context;
507
+ const binding = createHookBinding({}, {
508
+ sessionId: execution.sessionId,
509
+ isSubagent: Boolean(execution.environment[SUBAGENT_ENVIRONMENT_FLAG]),
510
+ cwd: execution.cwd,
511
+ repoRoot: execution.repoRoot,
512
+ get model() {
513
+ return execution.model;
514
+ },
515
+ async sendMessage(text, delivery) {
516
+ if (!execution.session.admitPrompt) throw new DoomHeadlessPromptAdmissionError("The session cannot admit a hook prompt.");
517
+ await execution.session.admitPrompt(text, delivery);
518
+ },
519
+ appendCustomEntry: (type, data) => execution.session.appendCustomEntry(type, data)
520
+ }, signal);
521
+ return {
522
+ value: createServerHooks(binding.runtime),
523
+ services: [binding.plugin]
524
+ };
525
+ };
526
+ //#endregion
527
+ //#region src/extensions/workspaces/sessions/(backend)/root.server.ts
528
+ var root_server_default = defineRoot(createHookServerRoot);
529
+ //#endregion
530
+ //#region src/extensions/workspaces/sessions/(backend)/hook/agent-end.server.ts
531
+ var agent_end_server_default = defineHook(({ root }) => root.agentEnd);
532
+ //#endregion
533
+ //#region src/extensions/workspaces/sessions/(backend)/hook/agent-settled.server.ts
534
+ var agent_settled_server_default = defineHook(({ root }) => root.agentSettled);
535
+ //#endregion
536
+ //#region src/extensions/workspaces/sessions/(backend)/hook/before-agent-start.server.ts
537
+ var before_agent_start_server_default = defineHook(({ root }) => root.beforeAgentStart);
538
+ //#endregion
539
+ //#region src/extensions/workspaces/sessions/(backend)/hook/session-shutdown.server.ts
540
+ var session_shutdown_server_default = defineHook(({ root }) => root.sessionShutdown);
541
+ //#endregion
542
+ //#region src/extensions/workspaces/sessions/(backend)/hook/session-start.server.ts
543
+ var session_start_server_default = defineHook(({ root }) => root.sessionStart);
544
+ //#endregion
545
+ //#region src/extensions/workspaces/sessions/(backend)/hook/tool-call.server.ts
546
+ var tool_call_server_default = defineHook(({ root }) => root.toolCall);
547
+ //#endregion
548
+ //#region src/extensions/workspaces/sessions/(backend)/hook/tool-result.server.ts
549
+ var tool_result_server_default = defineHook(({ root }) => root.toolResult);
550
+ //#endregion
551
+ //#region src/extensions/workspaces/sessions/(backend)/resource/po-author-hook.server.ts
552
+ var po_author_hook_server_default = defineResource({
553
+ name: "po-author-hook",
554
+ description: "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.",
555
+ when: DOOM_HELP_WHEN,
556
+ kind: "skill",
557
+ path: packageResourcePath(import.meta.url, "src/prompts/po-author-hook/SKILL.md"),
558
+ read: async () => {
559
+ const text = await readPackageResource(import.meta.url, "src/prompts/po-author-hook/SKILL.md");
560
+ if (!text.trim()) throw new Error("The installed hook-authoring skill is missing or unreadable.");
561
+ return text;
562
+ }
563
+ });
564
+ //#endregion
565
+ //#region generated/server.ts
566
+ const at = (value, context) => typeof value === "function" ? value(context) : value;
567
+ const via = (identity, value) => value === void 0 ? void 0 : {
568
+ ...identity,
569
+ ...value
570
+ };
571
+ const facet = defineServerPlugin({
572
+ name: "@agimon-ai/po-hook",
573
+ providerOverrides: composeServerProviderOverrides(root_server_default),
574
+ session: async (context) => {
575
+ const scopeSession = await root_server_default(context);
576
+ const contextSession = {
577
+ ...context,
578
+ root: scopeSession.value
579
+ };
580
+ return {
581
+ ...composeRootHooks(scopeSession),
582
+ get hooks() {
583
+ return [
584
+ via({ event: "agent_end" }, at(agent_end_server_default, contextSession)),
585
+ via({ event: "agent_settled" }, at(agent_settled_server_default, contextSession)),
586
+ via({ event: "before_agent_start" }, at(before_agent_start_server_default, contextSession)),
587
+ via({ event: "session_shutdown" }, at(session_shutdown_server_default, contextSession)),
588
+ via({ event: "session_start" }, at(session_start_server_default, contextSession)),
589
+ via({ event: "tool_call" }, at(tool_call_server_default, contextSession)),
590
+ via({ event: "tool_result" }, at(tool_result_server_default, contextSession))
591
+ ];
592
+ },
593
+ get resources() {
594
+ return [at(po_author_hook_server_default, contextSession)];
595
+ },
596
+ services: [...scopeSession.services ?? []],
597
+ get activities() {
598
+ return [...scopeSession.activities ?? []];
599
+ }
600
+ };
601
+ }
602
+ });
603
+ //#endregion
604
+ export { facet as default, facet };
605
+
606
+ //# sourceMappingURL=server.mjs.map