@x-code-cli/core 0.2.9 → 0.3.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 (255) hide show
  1. package/dist/agent/compression.d.ts +12 -2
  2. package/dist/agent/compression.d.ts.map +1 -1
  3. package/dist/agent/compression.js +51 -2
  4. package/dist/agent/compression.js.map +1 -1
  5. package/dist/agent/file-ingest.js +2 -2
  6. package/dist/agent/file-ingest.js.map +1 -1
  7. package/dist/agent/loop-state.d.ts +3 -2
  8. package/dist/agent/loop-state.d.ts.map +1 -1
  9. package/dist/agent/loop-state.js.map +1 -1
  10. package/dist/agent/loop.d.ts.map +1 -1
  11. package/dist/agent/loop.js +140 -9
  12. package/dist/agent/loop.js.map +1 -1
  13. package/dist/agent/memory-extractor.js +5 -5
  14. package/dist/agent/memory-extractor.js.map +1 -1
  15. package/dist/agent/plan-storage.js +1 -1
  16. package/dist/agent/plan-storage.js.map +1 -1
  17. package/dist/agent/sub-agents/index.d.ts +2 -1
  18. package/dist/agent/sub-agents/index.d.ts.map +1 -1
  19. package/dist/agent/sub-agents/index.js +1 -1
  20. package/dist/agent/sub-agents/index.js.map +1 -1
  21. package/dist/agent/sub-agents/loader.d.ts +13 -3
  22. package/dist/agent/sub-agents/loader.d.ts.map +1 -1
  23. package/dist/agent/sub-agents/loader.js +36 -9
  24. package/dist/agent/sub-agents/loader.js.map +1 -1
  25. package/dist/agent/sub-agents/registry.d.ts +18 -1
  26. package/dist/agent/sub-agents/registry.d.ts.map +1 -1
  27. package/dist/agent/sub-agents/registry.js +38 -5
  28. package/dist/agent/sub-agents/registry.js.map +1 -1
  29. package/dist/agent/sub-agents/runner.d.ts.map +1 -1
  30. package/dist/agent/sub-agents/runner.js +45 -1
  31. package/dist/agent/sub-agents/runner.js.map +1 -1
  32. package/dist/agent/sub-agents/types.d.ts +4 -1
  33. package/dist/agent/sub-agents/types.d.ts.map +1 -1
  34. package/dist/agent/system-prompt.d.ts +21 -0
  35. package/dist/agent/system-prompt.d.ts.map +1 -1
  36. package/dist/agent/system-prompt.js +68 -2
  37. package/dist/agent/system-prompt.js.map +1 -1
  38. package/dist/agent/tool-execution.d.ts.map +1 -1
  39. package/dist/agent/tool-execution.js +220 -1
  40. package/dist/agent/tool-execution.js.map +1 -1
  41. package/dist/commands/index.d.ts +6 -0
  42. package/dist/commands/index.d.ts.map +1 -0
  43. package/dist/commands/index.js +3 -0
  44. package/dist/commands/index.js.map +1 -0
  45. package/dist/commands/loader.d.ts +13 -0
  46. package/dist/commands/loader.d.ts.map +1 -0
  47. package/dist/commands/loader.js +93 -0
  48. package/dist/commands/loader.js.map +1 -0
  49. package/dist/commands/registry.d.ts +44 -0
  50. package/dist/commands/registry.d.ts.map +1 -0
  51. package/dist/commands/registry.js +102 -0
  52. package/dist/commands/registry.js.map +1 -0
  53. package/dist/commands/types.d.ts +23 -0
  54. package/dist/commands/types.d.ts.map +1 -0
  55. package/dist/commands/types.js +26 -0
  56. package/dist/commands/types.js.map +1 -0
  57. package/dist/config/index.d.ts +9 -0
  58. package/dist/config/index.d.ts.map +1 -1
  59. package/dist/config/index.js +12 -10
  60. package/dist/config/index.js.map +1 -1
  61. package/dist/hooks/bus.d.ts +54 -0
  62. package/dist/hooks/bus.d.ts.map +1 -0
  63. package/dist/hooks/bus.js +165 -0
  64. package/dist/hooks/bus.js.map +1 -0
  65. package/dist/hooks/config-schema.d.ts +854 -0
  66. package/dist/hooks/config-schema.d.ts.map +1 -0
  67. package/dist/hooks/config-schema.js +79 -0
  68. package/dist/hooks/config-schema.js.map +1 -0
  69. package/dist/hooks/executor.d.ts +16 -0
  70. package/dist/hooks/executor.d.ts.map +1 -0
  71. package/dist/hooks/executor.js +183 -0
  72. package/dist/hooks/executor.js.map +1 -0
  73. package/dist/hooks/index.d.ts +10 -0
  74. package/dist/hooks/index.d.ts.map +1 -0
  75. package/dist/hooks/index.js +6 -0
  76. package/dist/hooks/index.js.map +1 -0
  77. package/dist/hooks/registry.d.ts +23 -0
  78. package/dist/hooks/registry.d.ts.map +1 -0
  79. package/dist/hooks/registry.js +49 -0
  80. package/dist/hooks/registry.js.map +1 -0
  81. package/dist/hooks/types.d.ts +165 -0
  82. package/dist/hooks/types.d.ts.map +1 -0
  83. package/dist/hooks/types.js +25 -0
  84. package/dist/hooks/types.js.map +1 -0
  85. package/dist/hooks/variables.d.ts +22 -0
  86. package/dist/hooks/variables.d.ts.map +1 -0
  87. package/dist/hooks/variables.js +80 -0
  88. package/dist/hooks/variables.js.map +1 -0
  89. package/dist/index.d.ts +56 -1
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +37 -1
  92. package/dist/index.js.map +1 -1
  93. package/dist/knowledge/auto-memory.d.ts +1 -1
  94. package/dist/knowledge/auto-memory.d.ts.map +1 -1
  95. package/dist/knowledge/auto-memory.js +10 -10
  96. package/dist/knowledge/auto-memory.js.map +1 -1
  97. package/dist/knowledge/loader.js +12 -12
  98. package/dist/knowledge/loader.js.map +1 -1
  99. package/dist/mcp/arg-parser.d.ts +49 -0
  100. package/dist/mcp/arg-parser.d.ts.map +1 -0
  101. package/dist/mcp/arg-parser.js +357 -0
  102. package/dist/mcp/arg-parser.js.map +1 -0
  103. package/dist/mcp/client.d.ts +73 -0
  104. package/dist/mcp/client.d.ts.map +1 -0
  105. package/dist/mcp/client.js +376 -0
  106. package/dist/mcp/client.js.map +1 -0
  107. package/dist/mcp/config-schema.d.ts +64 -0
  108. package/dist/mcp/config-schema.d.ts.map +1 -0
  109. package/dist/mcp/config-schema.js +86 -0
  110. package/dist/mcp/config-schema.js.map +1 -0
  111. package/dist/mcp/config-writer.d.ts +41 -0
  112. package/dist/mcp/config-writer.d.ts.map +1 -0
  113. package/dist/mcp/config-writer.js +138 -0
  114. package/dist/mcp/config-writer.js.map +1 -0
  115. package/dist/mcp/env-safety.d.ts +12 -0
  116. package/dist/mcp/env-safety.d.ts.map +1 -0
  117. package/dist/mcp/env-safety.js +80 -0
  118. package/dist/mcp/env-safety.js.map +1 -0
  119. package/dist/mcp/expand-env.d.ts +14 -0
  120. package/dist/mcp/expand-env.d.ts.map +1 -0
  121. package/dist/mcp/expand-env.js +52 -0
  122. package/dist/mcp/expand-env.js.map +1 -0
  123. package/dist/mcp/loader.d.ts +81 -0
  124. package/dist/mcp/loader.d.ts.map +1 -0
  125. package/dist/mcp/loader.js +223 -0
  126. package/dist/mcp/loader.js.map +1 -0
  127. package/dist/mcp/name-mangling.d.ts +11 -0
  128. package/dist/mcp/name-mangling.d.ts.map +1 -0
  129. package/dist/mcp/name-mangling.js +82 -0
  130. package/dist/mcp/name-mangling.js.map +1 -0
  131. package/dist/mcp/oauth/callback-server.d.ts +25 -0
  132. package/dist/mcp/oauth/callback-server.d.ts.map +1 -0
  133. package/dist/mcp/oauth/callback-server.js +118 -0
  134. package/dist/mcp/oauth/callback-server.js.map +1 -0
  135. package/dist/mcp/oauth/provider.d.ts +80 -0
  136. package/dist/mcp/oauth/provider.d.ts.map +1 -0
  137. package/dist/mcp/oauth/provider.js +292 -0
  138. package/dist/mcp/oauth/provider.js.map +1 -0
  139. package/dist/mcp/oauth/token-storage.d.ts +42 -0
  140. package/dist/mcp/oauth/token-storage.d.ts.map +1 -0
  141. package/dist/mcp/oauth/token-storage.js +121 -0
  142. package/dist/mcp/oauth/token-storage.js.map +1 -0
  143. package/dist/mcp/permissions.d.ts +28 -0
  144. package/dist/mcp/permissions.d.ts.map +1 -0
  145. package/dist/mcp/permissions.js +105 -0
  146. package/dist/mcp/permissions.js.map +1 -0
  147. package/dist/mcp/registry.d.ts +150 -0
  148. package/dist/mcp/registry.d.ts.map +1 -0
  149. package/dist/mcp/registry.js +334 -0
  150. package/dist/mcp/registry.js.map +1 -0
  151. package/dist/mcp/resources.d.ts +7 -0
  152. package/dist/mcp/resources.d.ts.map +1 -0
  153. package/dist/mcp/resources.js +40 -0
  154. package/dist/mcp/resources.js.map +1 -0
  155. package/dist/mcp/tool-bridge.d.ts +16 -0
  156. package/dist/mcp/tool-bridge.d.ts.map +1 -0
  157. package/dist/mcp/tool-bridge.js +56 -0
  158. package/dist/mcp/tool-bridge.js.map +1 -0
  159. package/dist/mcp/trust.d.ts +31 -0
  160. package/dist/mcp/trust.d.ts.map +1 -0
  161. package/dist/mcp/trust.js +103 -0
  162. package/dist/mcp/trust.js.map +1 -0
  163. package/dist/mcp/types.d.ts +73 -0
  164. package/dist/mcp/types.d.ts.map +1 -0
  165. package/dist/mcp/types.js +13 -0
  166. package/dist/mcp/types.js.map +1 -0
  167. package/dist/permissions/session-store.d.ts +13 -2
  168. package/dist/permissions/session-store.d.ts.map +1 -1
  169. package/dist/permissions/session-store.js +264 -62
  170. package/dist/permissions/session-store.js.map +1 -1
  171. package/dist/plugins/consent.d.ts +87 -0
  172. package/dist/plugins/consent.d.ts.map +1 -0
  173. package/dist/plugins/consent.js +181 -0
  174. package/dist/plugins/consent.js.map +1 -0
  175. package/dist/plugins/enable-state.d.ts +34 -0
  176. package/dist/plugins/enable-state.d.ts.map +1 -0
  177. package/dist/plugins/enable-state.js +159 -0
  178. package/dist/plugins/enable-state.js.map +1 -0
  179. package/dist/plugins/installer.d.ts +64 -0
  180. package/dist/plugins/installer.d.ts.map +1 -0
  181. package/dist/plugins/installer.js +416 -0
  182. package/dist/plugins/installer.js.map +1 -0
  183. package/dist/plugins/integration.d.ts +91 -0
  184. package/dist/plugins/integration.d.ts.map +1 -0
  185. package/dist/plugins/integration.js +233 -0
  186. package/dist/plugins/integration.js.map +1 -0
  187. package/dist/plugins/loader.d.ts +69 -0
  188. package/dist/plugins/loader.d.ts.map +1 -0
  189. package/dist/plugins/loader.js +243 -0
  190. package/dist/plugins/loader.js.map +1 -0
  191. package/dist/plugins/manifest.d.ts +23 -0
  192. package/dist/plugins/manifest.d.ts.map +1 -0
  193. package/dist/plugins/manifest.js +143 -0
  194. package/dist/plugins/manifest.js.map +1 -0
  195. package/dist/plugins/marketplace.d.ts +100 -0
  196. package/dist/plugins/marketplace.d.ts.map +1 -0
  197. package/dist/plugins/marketplace.js +529 -0
  198. package/dist/plugins/marketplace.js.map +1 -0
  199. package/dist/plugins/paths.d.ts +44 -0
  200. package/dist/plugins/paths.d.ts.map +1 -0
  201. package/dist/plugins/paths.js +89 -0
  202. package/dist/plugins/paths.js.map +1 -0
  203. package/dist/plugins/refresh.d.ts +61 -0
  204. package/dist/plugins/refresh.d.ts.map +1 -0
  205. package/dist/plugins/refresh.js +98 -0
  206. package/dist/plugins/refresh.js.map +1 -0
  207. package/dist/plugins/registry.d.ts +40 -0
  208. package/dist/plugins/registry.d.ts.map +1 -0
  209. package/dist/plugins/registry.js +80 -0
  210. package/dist/plugins/registry.js.map +1 -0
  211. package/dist/plugins/types.d.ts +225 -0
  212. package/dist/plugins/types.d.ts.map +1 -0
  213. package/dist/plugins/types.js +16 -0
  214. package/dist/plugins/types.js.map +1 -0
  215. package/dist/plugins/user-config.d.ts +22 -0
  216. package/dist/plugins/user-config.d.ts.map +1 -0
  217. package/dist/plugins/user-config.js +96 -0
  218. package/dist/plugins/user-config.js.map +1 -0
  219. package/dist/providers/cache-control.d.ts +9 -0
  220. package/dist/providers/cache-control.d.ts.map +1 -1
  221. package/dist/providers/cache-control.js +31 -4
  222. package/dist/providers/cache-control.js.map +1 -1
  223. package/dist/skills/loader.d.ts +19 -0
  224. package/dist/skills/loader.d.ts.map +1 -0
  225. package/dist/skills/loader.js +197 -0
  226. package/dist/skills/loader.js.map +1 -0
  227. package/dist/skills/registry.d.ts +74 -0
  228. package/dist/skills/registry.d.ts.map +1 -0
  229. package/dist/skills/registry.js +136 -0
  230. package/dist/skills/registry.js.map +1 -0
  231. package/dist/skills/settings.d.ts +13 -0
  232. package/dist/skills/settings.d.ts.map +1 -0
  233. package/dist/skills/settings.js +100 -0
  234. package/dist/skills/settings.js.map +1 -0
  235. package/dist/tools/activate-skill.d.ts +5 -0
  236. package/dist/tools/activate-skill.d.ts.map +1 -0
  237. package/dist/tools/activate-skill.js +33 -0
  238. package/dist/tools/activate-skill.js.map +1 -0
  239. package/dist/tools/index.d.ts +1 -1
  240. package/dist/tools/todo-write.d.ts +1 -1
  241. package/dist/tools/web-fetch.d.ts.map +1 -1
  242. package/dist/tools/web-fetch.js +2 -1
  243. package/dist/tools/web-fetch.js.map +1 -1
  244. package/dist/types/index.d.ts +46 -1
  245. package/dist/types/index.d.ts.map +1 -1
  246. package/dist/types/index.js.map +1 -1
  247. package/dist/utils.d.ts +23 -2
  248. package/dist/utils.d.ts.map +1 -1
  249. package/dist/utils.js +76 -20
  250. package/dist/utils.js.map +1 -1
  251. package/dist/version.d.ts +2 -0
  252. package/dist/version.d.ts.map +1 -0
  253. package/dist/version.js +47 -0
  254. package/dist/version.js.map +1 -0
  255. package/package.json +2 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-schema.d.ts","sourceRoot":"","sources":["../../src/hooks/config-schema.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAgB5C,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAcb,CAAA;AAEhB,qBAAa,oBAAqB,SAAQ,KAAK;aAG3B,WAAW,EAAE,MAAM;gBADnC,OAAO,EAAE,MAAM,EACC,WAAW,EAAE,MAAM;CAKtC;AAED;+DAC+D;AAC/D,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,UAAU,CA0B7E"}
@@ -0,0 +1,79 @@
1
+ // @x-code-cli/core — hooks.json zod schema
2
+ //
3
+ // Validates a `HookConfig` whether it came from a hooks.json file on
4
+ // disk or an inline manifest object. Same schema both paths — keeps the
5
+ // failure mode identical so plugin authors don't get different errors
6
+ // depending on which form they used.
7
+ //
8
+ // Bad regex in `matcher` is NOT a schema error — it'd be inconvenient
9
+ // to require authors to author / test their regex against zod's strict
10
+ // mode. The bus catches RegExp construction errors at emit time and
11
+ // degrades to "matches every tool" (logged for support).
12
+ import { z } from 'zod';
13
+ const hookEntrySchema = z.object({
14
+ matcher: z.string().optional(),
15
+ command: z.string().min(1),
16
+ // Platform-specific overrides. Optional; missing on a platform falls
17
+ // back to `command`. We deliberately don't enforce that at least one
18
+ // of them is set — the base command is always required.
19
+ commandWindows: z.string().min(1).optional(),
20
+ commandDarwin: z.string().min(1).optional(),
21
+ commandLinux: z.string().min(1).optional(),
22
+ timeout: z.number().int().positive().max(30_000).optional(),
23
+ description: z.string().optional(),
24
+ failurePolicy: z.enum(['allow', 'block']).optional(),
25
+ });
26
+ export const hookConfigSchema = z
27
+ .object({
28
+ SessionStart: z.array(hookEntrySchema).optional(),
29
+ UserPromptSubmit: z.array(hookEntrySchema).optional(),
30
+ PreToolUse: z.array(hookEntrySchema).optional(),
31
+ PostToolUse: z.array(hookEntrySchema).optional(),
32
+ PreCompact: z.array(hookEntrySchema).optional(),
33
+ PostCompact: z.array(hookEntrySchema).optional(),
34
+ SubagentStart: z.array(hookEntrySchema).optional(),
35
+ SubagentStop: z.array(hookEntrySchema).optional(),
36
+ TurnComplete: z.array(hookEntrySchema).optional(),
37
+ SessionEnd: z.array(hookEntrySchema).optional(),
38
+ })
39
+ // Unknown keys are tolerated for forward compat (future event names).
40
+ .passthrough();
41
+ export class HookConfigParseError extends Error {
42
+ sourceLabel;
43
+ constructor(message, sourceLabel) {
44
+ super(message);
45
+ this.sourceLabel = sourceLabel;
46
+ this.name = 'HookConfigParseError';
47
+ }
48
+ }
49
+ /** Validate an already-parsed-object form. Used for inline manifest
50
+ * configs and for the body of hooks.json after JSON.parse. */
51
+ export function parseHookConfig(raw, sourceLabel) {
52
+ const result = hookConfigSchema.safeParse(raw);
53
+ if (!result.success) {
54
+ const issues = result.error.issues.map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`).join('; ');
55
+ throw new HookConfigParseError(`invalid hooks config — ${issues}`, sourceLabel);
56
+ }
57
+ // Strip unknown future keys at the type boundary — passthrough kept
58
+ // them on the runtime object, but our HookConfig type only knows the
59
+ // ten events.
60
+ const known = {};
61
+ for (const k of [
62
+ 'SessionStart',
63
+ 'UserPromptSubmit',
64
+ 'PreToolUse',
65
+ 'PostToolUse',
66
+ 'PreCompact',
67
+ 'PostCompact',
68
+ 'SubagentStart',
69
+ 'SubagentStop',
70
+ 'TurnComplete',
71
+ 'SessionEnd',
72
+ ]) {
73
+ const arr = result.data[k];
74
+ if (Array.isArray(arr))
75
+ known[k] = arr;
76
+ }
77
+ return known;
78
+ }
79
+ //# sourceMappingURL=config-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-schema.js","sourceRoot":"","sources":["../../src/hooks/config-schema.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,sEAAsE;AACtE,qCAAqC;AACrC,EAAE;AACF,sEAAsE;AACtE,uEAAuE;AACvE,oEAAoE;AACpE,yDAAyD;AACzD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,qEAAqE;IACrE,qEAAqE;IACrE,wDAAwD;IACxD,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC5C,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC3C,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;IAC3D,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAClC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC;KAC9B,MAAM,CAAC;IACN,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IACjD,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IACrD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IAC/C,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IAChD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IAC/C,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IAChD,aAAa,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IAClD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IACjD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;IACjD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE;CAChD,CAAC;IACF,sEAAsE;KACrE,WAAW,EAAE,CAAA;AAEhB,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAG3B;IAFlB,YACE,OAAe,EACC,WAAmB;QAEnC,KAAK,CAAC,OAAO,CAAC,CAAA;QAFE,gBAAW,GAAX,WAAW,CAAQ;QAGnC,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAA;IACpC,CAAC;CACF;AAED;+DAC+D;AAC/D,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,WAAmB;IAC/D,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;IAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzG,MAAM,IAAI,oBAAoB,CAAC,0BAA0B,MAAM,EAAE,EAAE,WAAW,CAAC,CAAA;IACjF,CAAC;IACD,oEAAoE;IACpE,qEAAqE;IACrE,cAAc;IACd,MAAM,KAAK,GAAe,EAAE,CAAA;IAC5B,KAAK,MAAM,CAAC,IAAI;QACd,cAAc;QACd,kBAAkB;QAClB,YAAY;QACZ,aAAa;QACb,YAAY;QACZ,aAAa;QACb,eAAe;QACf,cAAc;QACd,cAAc;QACd,YAAY;KACJ,EAAE,CAAC;QACX,MAAM,GAAG,GAAI,MAAM,CAAC,IAAgC,CAAC,CAAC,CAAC,CAAA;QACvD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAA2B,CAAA;IAChE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { HookDecision, HookEvent, RegisteredHook } from './types.js';
2
+ export interface ExecuteHookOptions {
3
+ /** Cancels the hook child process when fired. Agent loop's abort
4
+ * signal flows through here so Esc during a slow hook kills it
5
+ * promptly. */
6
+ signal?: AbortSignal;
7
+ /** Override the default 5s timeout. Per-hook `entry.timeout` still
8
+ * wins when both are set. Both are capped at 30s. */
9
+ defaultTimeoutMs?: number;
10
+ }
11
+ /** Run one hook against one event. Returns the parsed decision (default
12
+ * allow on anything unexpected). Never throws unless the caller's
13
+ * AbortSignal fires — abort is the one error worth bubbling because
14
+ * the caller's loop is already shutting down. */
15
+ export declare function executeHook(hook: RegisteredHook, event: HookEvent, opts?: ExecuteHookOptions): Promise<HookDecision>;
16
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/hooks/executor.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAmB,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAwB1F,MAAM,WAAW,kBAAkB;IACjC;;oBAEgB;IAChB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB;0DACsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;;kDAGkD;AAClD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,SAAS,EAChB,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAiEvB"}
@@ -0,0 +1,183 @@
1
+ // @x-code-cli/core — Hook command executor
2
+ //
3
+ // Spawns a hook's shell command, writes the event JSON on stdin, reads
4
+ // the decision JSON from stdout. The whole protocol is line-oriented:
5
+ // one JSON object in, one JSON object out (or empty stdout = default
6
+ // allow). Anything else on stdout is ignored — common pattern for hooks
7
+ // that just want to log to stderr without influencing the agent.
8
+ //
9
+ // Failure handling is deliberately permissive (default `failurePolicy:
10
+ // 'allow'`): a broken hook must never wedge the agent loop. Non-zero
11
+ // exit, timeout, or crash all degrade to `allow` and log a debug
12
+ // breadcrumb. The `block` policy is opt-in and reserved for hooks the
13
+ // plugin author has explicitly designed as gating hooks.
14
+ //
15
+ // AbortSignal propagation: passed to execa's `cancelSignal` so the
16
+ // child process is SIGKILL'd when the user hits Esc mid-hook. Same
17
+ // machinery the shell tool uses.
18
+ import { execa } from 'execa';
19
+ import { getPluginUserConfigEnv } from '../plugins/user-config.js';
20
+ import { debugLog } from '../utils.js';
21
+ import { buildVariableContext, expandVariables } from './variables.js';
22
+ /** Return the command appropriate for the current OS. Plugin authors
23
+ * set `command` as a portable default and may add `commandWindows` /
24
+ * `commandDarwin` / `commandLinux` to handle per-OS differences (e.g.
25
+ * shebang line, executable name, quoting). Unknown platforms (freebsd,
26
+ * sunos, aix) fall through to the base. */
27
+ function pickPlatformCommand(entry) {
28
+ switch (process.platform) {
29
+ case 'win32':
30
+ return entry.commandWindows ?? entry.command;
31
+ case 'darwin':
32
+ return entry.commandDarwin ?? entry.command;
33
+ case 'linux':
34
+ return entry.commandLinux ?? entry.command;
35
+ default:
36
+ return entry.command;
37
+ }
38
+ }
39
+ const DEFAULT_TIMEOUT_MS = 5_000;
40
+ const MAX_TIMEOUT_MS = 30_000;
41
+ /** Run one hook against one event. Returns the parsed decision (default
42
+ * allow on anything unexpected). Never throws unless the caller's
43
+ * AbortSignal fires — abort is the one error worth bubbling because
44
+ * the caller's loop is already shutting down. */
45
+ export async function executeHook(hook, event, opts = {}) {
46
+ const timeoutMs = Math.min(hook.entry.timeout ?? opts.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS);
47
+ const vars = buildVariableContext({
48
+ pluginDir: hook.pluginDir,
49
+ cwd: event.session.cwd,
50
+ pluginId: hook.pluginId,
51
+ });
52
+ const expandedCommand = expandVariables(pickPlatformCommand(hook.entry), vars);
53
+ const stdinPayload = JSON.stringify(buildStdinPayload(hook, event));
54
+ // Merge the owning plugin's userConfig values into the hook's env.
55
+ // Hook scripts that need an API key declared in the manifest read it as
56
+ // `process.env[KEY]` without writing any glue — `${env:KEY}` substitution
57
+ // in the command string also resolves against this merged env. We fail
58
+ // silent if the read errors (no userConfig set yet ⇒ empty map).
59
+ let pluginEnv = {};
60
+ try {
61
+ pluginEnv = await getPluginUserConfigEnv(hook.pluginId);
62
+ }
63
+ catch (err) {
64
+ debugLog('hooks.user-config-read-failed', `${hook.pluginId}: ${String(err)}`);
65
+ }
66
+ try {
67
+ const result = await execa(expandedCommand, [], {
68
+ shell: true,
69
+ input: stdinPayload,
70
+ timeout: timeoutMs,
71
+ cancelSignal: opts.signal,
72
+ stdio: 'pipe',
73
+ reject: false, // Non-zero exits handled below explicitly, not as throws.
74
+ cwd: event.session.cwd,
75
+ env: { ...process.env, ...pluginEnv },
76
+ });
77
+ if (opts.signal?.aborted) {
78
+ // Aborted mid-execution. Caller's loop is winding down — surface
79
+ // by throwing so the bus stops cascading further hooks.
80
+ throw new Error('aborted');
81
+ }
82
+ if (result.timedOut) {
83
+ debugLog('hooks.exec-timeout', `${hook.pluginId} ${event.name}: timed out after ${timeoutMs}ms`);
84
+ return failurePolicyDecision(hook, `hook timed out after ${timeoutMs}ms`);
85
+ }
86
+ if (typeof result.exitCode === 'number' && result.exitCode !== 0) {
87
+ const stderrTail = (result.stderr ?? '').toString().slice(0, 200);
88
+ debugLog('hooks.exec-nonzero', `${hook.pluginId} ${event.name}: exit ${result.exitCode} stderr=${stderrTail}`);
89
+ return failurePolicyDecision(hook, `hook exited ${result.exitCode}`);
90
+ }
91
+ const decision = parseDecision(result.stdout ?? '', hook, event);
92
+ // Trace successful hook runs so plugin authors can confirm their
93
+ // hook actually fired without needing to add their own logging.
94
+ // Stdio is `pipe`d (we read the JSON decision out of stdout), so
95
+ // anything the hook writes to its own stderr is otherwise invisible
96
+ // — this breadcrumb is what `--plugin-debug` / `DEBUG_STDOUT=1`
97
+ // users grep for to verify the wiring.
98
+ debugLog('hooks.exec-ran', `${hook.pluginId} ${event.name}: decision=${decision.decision}`);
99
+ return decision;
100
+ }
101
+ catch (err) {
102
+ if (opts.signal?.aborted)
103
+ throw err;
104
+ debugLog('hooks.exec-error', `${hook.pluginId} ${event.name}: ${String(err)}`);
105
+ return failurePolicyDecision(hook, `hook crashed: ${err instanceof Error ? err.message : String(err)}`);
106
+ }
107
+ }
108
+ function failurePolicyDecision(hook, reason) {
109
+ if (hook.entry.failurePolicy === 'block')
110
+ return { decision: 'deny', reason };
111
+ return { decision: 'allow' };
112
+ }
113
+ /** Build the JSON object sent to the hook over stdin. Event-specific
114
+ * fields are flattened in at the top level (matches Claude Code's
115
+ * hook protocol shape). */
116
+ function buildStdinPayload(hook, event) {
117
+ const base = {
118
+ event: event.name,
119
+ session: event.session,
120
+ plugin: { id: hook.pluginId, dir: hook.pluginDir },
121
+ };
122
+ switch (event.name) {
123
+ case 'UserPromptSubmit':
124
+ base.prompt = event.prompt;
125
+ break;
126
+ case 'PreToolUse':
127
+ base.tool = event.tool;
128
+ break;
129
+ case 'PostToolUse':
130
+ base.tool = event.tool;
131
+ break;
132
+ case 'PreCompact':
133
+ base.trigger = event.trigger;
134
+ base.messageCount = event.messageCount;
135
+ base.tokenEstimate = event.tokenEstimate;
136
+ break;
137
+ case 'PostCompact':
138
+ base.trigger = event.trigger;
139
+ base.messageCount = event.messageCount;
140
+ base.summary = event.summary;
141
+ break;
142
+ case 'SubagentStart':
143
+ base.agent = event.agent;
144
+ break;
145
+ case 'SubagentStop':
146
+ base.agent = event.agent;
147
+ base.durationMs = event.durationMs;
148
+ base.outcome = event.outcome;
149
+ if (event.tokenUsage)
150
+ base.tokenUsage = event.tokenUsage;
151
+ break;
152
+ case 'TurnComplete':
153
+ base.turn = event.turn;
154
+ if (event.tokenUsage)
155
+ base.tokenUsage = event.tokenUsage;
156
+ break;
157
+ // SessionStart / SessionEnd have no extra fields beyond session/plugin.
158
+ }
159
+ return base;
160
+ }
161
+ function parseDecision(stdout, hook, event) {
162
+ const trimmed = (stdout ?? '').toString().trim();
163
+ if (!trimmed)
164
+ return { decision: 'allow' };
165
+ try {
166
+ const parsed = JSON.parse(trimmed);
167
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
168
+ const obj = parsed;
169
+ const d = obj.decision;
170
+ if (d === 'allow' || d === 'deny' || d === 'modify') {
171
+ return obj;
172
+ }
173
+ }
174
+ }
175
+ catch {
176
+ // Not JSON — many hooks intend stdout for human eyes (logs). Treat
177
+ // as default allow but breadcrumb in case the user expected it to
178
+ // influence the agent.
179
+ debugLog('hooks.decision-not-json', `${hook.pluginId} ${event.name}: ignoring non-JSON stdout: ${trimmed.slice(0, 200)}`);
180
+ }
181
+ return { decision: 'allow' };
182
+ }
183
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/hooks/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export type { DecisionEvent, HookConfig, HookConfigEntry, HookDecision, HookEvent, HookEventName, RegisteredHook, SessionContext, } from './types.js';
2
+ export { hookConfigSchema, parseHookConfig, HookConfigParseError } from './config-schema.js';
3
+ export { buildVariableContext, expandVariables } from './variables.js';
4
+ export type { VariableContext } from './variables.js';
5
+ export { executeHook } from './executor.js';
6
+ export type { ExecuteHookOptions } from './executor.js';
7
+ export { HookRegistry, buildHookRegistry, emptyHookRegistry } from './registry.js';
8
+ export { HookBus, emptyHookBus, aggregatePreToolUse, aggregatePostToolUse, aggregateUserPromptSubmit } from './bus.js';
9
+ export type { EmitOptions, PreToolEffect, PostToolEffect, UserPromptEffect } from './bus.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,aAAa,EACb,UAAU,EACV,eAAe,EACf,YAAY,EACZ,SAAS,EACT,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAA;AACnB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC5F,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACtE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAClF,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA;AACtH,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,6 @@
1
+ export { hookConfigSchema, parseHookConfig, HookConfigParseError } from './config-schema.js';
2
+ export { buildVariableContext, expandVariables } from './variables.js';
3
+ export { executeHook } from './executor.js';
4
+ export { HookRegistry, buildHookRegistry, emptyHookRegistry } from './registry.js';
5
+ export { HookBus, emptyHookBus, aggregatePreToolUse, aggregatePostToolUse, aggregateUserPromptSubmit } from './bus.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC5F,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAEtE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAClF,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAA"}
@@ -0,0 +1,23 @@
1
+ import type { HookConfig, HookEventName, RegisteredHook } from './types.js';
2
+ export declare class HookRegistry {
3
+ private byEvent;
4
+ constructor(hooks?: ReadonlyArray<RegisteredHook>);
5
+ /** Hooks bound to a given event, in registration order. */
6
+ get(event: HookEventName): readonly RegisteredHook[];
7
+ /** Cheap check the bus uses to skip event-payload construction when
8
+ * no hook is listening — every emit-site is in a hot path. */
9
+ has(event: HookEventName): boolean;
10
+ /** Every registered hook. Used by `/plugin doctor` to list what's
11
+ * active alongside which plugin contributed it. */
12
+ list(): readonly RegisteredHook[];
13
+ }
14
+ /** Build a registry from per-plugin hook configs. Iteration order of
15
+ * the input array determines emit order — the caller (integration.ts)
16
+ * is responsible for handing us plugins in a stable order. */
17
+ export declare function buildHookRegistry(pluginHooks: ReadonlyArray<{
18
+ pluginId: string;
19
+ pluginDir: string;
20
+ config: HookConfig;
21
+ }>): HookRegistry;
22
+ export declare function emptyHookRegistry(): HookRegistry;
23
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/hooks/registry.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAE3E,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAsC;gBAEzC,KAAK,GAAE,aAAa,CAAC,cAAc,CAAM;IASrD,2DAA2D;IAC3D,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,cAAc,EAAE;IAIpD;mEAC+D;IAC/D,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO;IAIlC;wDACoD;IACpD,IAAI,IAAI,SAAS,cAAc,EAAE;CAKlC;AAED;;+DAE+D;AAC/D,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,aAAa,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC,GACtF,YAAY,CAYd;AAED,wBAAgB,iBAAiB,IAAI,YAAY,CAEhD"}
@@ -0,0 +1,49 @@
1
+ export class HookRegistry {
2
+ byEvent;
3
+ constructor(hooks = []) {
4
+ this.byEvent = new Map();
5
+ for (const h of hooks) {
6
+ const list = this.byEvent.get(h.event) ?? [];
7
+ list.push(h);
8
+ this.byEvent.set(h.event, list);
9
+ }
10
+ }
11
+ /** Hooks bound to a given event, in registration order. */
12
+ get(event) {
13
+ return this.byEvent.get(event) ?? [];
14
+ }
15
+ /** Cheap check the bus uses to skip event-payload construction when
16
+ * no hook is listening — every emit-site is in a hot path. */
17
+ has(event) {
18
+ return (this.byEvent.get(event)?.length ?? 0) > 0;
19
+ }
20
+ /** Every registered hook. Used by `/plugin doctor` to list what's
21
+ * active alongside which plugin contributed it. */
22
+ list() {
23
+ const all = [];
24
+ for (const arr of this.byEvent.values())
25
+ all.push(...arr);
26
+ return all;
27
+ }
28
+ }
29
+ /** Build a registry from per-plugin hook configs. Iteration order of
30
+ * the input array determines emit order — the caller (integration.ts)
31
+ * is responsible for handing us plugins in a stable order. */
32
+ export function buildHookRegistry(pluginHooks) {
33
+ const all = [];
34
+ for (const { pluginId, pluginDir, config } of pluginHooks) {
35
+ for (const eventName of Object.keys(config)) {
36
+ const entries = config[eventName];
37
+ if (!entries)
38
+ continue;
39
+ for (const entry of entries) {
40
+ all.push({ pluginId, pluginDir, event: eventName, entry });
41
+ }
42
+ }
43
+ }
44
+ return new HookRegistry(all);
45
+ }
46
+ export function emptyHookRegistry() {
47
+ return new HookRegistry([]);
48
+ }
49
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/hooks/registry.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,YAAY;IACf,OAAO,CAAsC;IAErD,YAAY,QAAuC,EAAE;QACnD,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAA;QACxB,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;YAC5C,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACZ,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IAED,2DAA2D;IAC3D,GAAG,CAAC,KAAoB;QACtB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;IACtC,CAAC;IAED;mEAC+D;IAC/D,GAAG,CAAC,KAAoB;QACtB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;IACnD,CAAC;IAED;wDACoD;IACpD,IAAI;QACF,MAAM,GAAG,GAAqB,EAAE,CAAA;QAChC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAA;QACzD,OAAO,GAAG,CAAA;IACZ,CAAC;CACF;AAED;;+DAE+D;AAC/D,MAAM,UAAU,iBAAiB,CAC/B,WAAuF;IAEvF,MAAM,GAAG,GAAqB,EAAE,CAAA;IAChC,KAAK,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;QAC1D,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAoB,EAAE,CAAC;YAC/D,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAA;YACjC,IAAI,CAAC,OAAO;gBAAE,SAAQ;YACtB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;gBAC5B,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAA;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,YAAY,CAAC,GAAG,CAAC,CAAA;AAC9B,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,YAAY,CAAC,EAAE,CAAC,CAAA;AAC7B,CAAC"}
@@ -0,0 +1,165 @@
1
+ export type HookEventName = 'SessionStart' | 'UserPromptSubmit' | 'PreToolUse' | 'PostToolUse' | 'PreCompact' | 'PostCompact' | 'SubagentStart' | 'SubagentStop' | 'TurnComplete' | 'SessionEnd';
2
+ /** Subset of events that emit a decision the agent acts on. Other events
3
+ * are fire-and-forget — hooks may run side effects (logging,
4
+ * notifications) but the agent ignores their stdout. */
5
+ export type DecisionEvent = 'UserPromptSubmit' | 'PreToolUse' | 'PostToolUse';
6
+ /** One hook entry as it appears in hooks.json. */
7
+ export interface HookConfigEntry {
8
+ /** Optional regex matching tool name. Only meaningful for PreToolUse /
9
+ * PostToolUse — ignored for other events. A missing matcher means
10
+ * "every tool". */
11
+ matcher?: string;
12
+ /** Shell command to run on the current platform when no platform-specific
13
+ * override below is set. Supports `${pluginDir}` / `${pluginDataDir}` /
14
+ * `${cwd}` / `${homedir}` / `${env:NAME}` / `${sep}` variable expansion
15
+ * (see [[variables]]).
16
+ *
17
+ * We require this even when the platform overrides are set so plugin
18
+ * authors can't accidentally ship a plugin that runs on *only* one OS
19
+ * — the base command is the safety net for any platform the author
20
+ * didn't explicitly think about. */
21
+ command: string;
22
+ /** Platform-specific override commands. When set, the matching one
23
+ * replaces `command` on that OS. Keys match `process.platform`
24
+ * values; unknown platforms (freebsd / sunos / aix) fall through to
25
+ * the base `command`. */
26
+ commandWindows?: string;
27
+ commandDarwin?: string;
28
+ commandLinux?: string;
29
+ /** Per-hook timeout in ms (default 5000, capped at 30000). */
30
+ timeout?: number;
31
+ description?: string;
32
+ /** What to do when the hook exits non-zero or crashes:
33
+ *
34
+ * 'allow' (default) — log warning, treat as if the hook said allow
35
+ * 'block' — treat as deny (only meaningful for DecisionEvents)
36
+ *
37
+ * The default is permissive on purpose: a broken hook must not be
38
+ * able to wedge the agent loop indefinitely. */
39
+ failurePolicy?: 'allow' | 'block';
40
+ }
41
+ /** A whole hooks.json file. Each event name maps to an ordered array of
42
+ * entries — earlier entries run first, and for decision events a deny
43
+ * short-circuits the rest. */
44
+ export type HookConfig = Partial<Record<HookEventName, HookConfigEntry[]>>;
45
+ /** Session-level context attached to every event payload. */
46
+ export interface SessionContext {
47
+ cwd: string;
48
+ modelId: string;
49
+ /** Optional — when the CLI assigns a session id we pass it through so
50
+ * hooks can correlate events. */
51
+ sessionId?: string;
52
+ }
53
+ /** Discriminated union of every event payload shape. The `name` field
54
+ * doubles as the tag. The CLI builds these and hands them to
55
+ * [[HookBus.emit]] — the executor serialises them as JSON for stdin. */
56
+ export type HookEvent = {
57
+ name: 'SessionStart';
58
+ session: SessionContext;
59
+ } | {
60
+ name: 'UserPromptSubmit';
61
+ session: SessionContext;
62
+ prompt: string;
63
+ } | {
64
+ name: 'PreToolUse';
65
+ session: SessionContext;
66
+ tool: {
67
+ name: string;
68
+ args: unknown;
69
+ callId: string;
70
+ };
71
+ } | {
72
+ name: 'PostToolUse';
73
+ session: SessionContext;
74
+ tool: {
75
+ name: string;
76
+ args: unknown;
77
+ callId: string;
78
+ output: string;
79
+ isError: boolean;
80
+ };
81
+ } | {
82
+ name: 'PreCompact';
83
+ session: SessionContext;
84
+ /** Why compaction is about to run — useful for hooks that want to
85
+ * decide whether to checkpoint state or skip. */
86
+ trigger: 'proactive' | 'reactive';
87
+ /** Approximate message count and token count before compaction. */
88
+ messageCount: number;
89
+ tokenEstimate: number;
90
+ } | {
91
+ name: 'PostCompact';
92
+ session: SessionContext;
93
+ trigger: 'proactive' | 'reactive';
94
+ /** Message count after compaction — the delta from PreCompact's
95
+ * messageCount tells the hook how much was reclaimed. */
96
+ messageCount: number;
97
+ /** Empty string when the path was a light-compact (no LLM summary
98
+ * was written). */
99
+ summary: string;
100
+ } | {
101
+ name: 'SubagentStart';
102
+ session: SessionContext;
103
+ agent: {
104
+ /** The sub-agent's registered name (e.g. `code-reviewer`). */
105
+ name: string;
106
+ /** The parent agent's one-line task description. */
107
+ description: string;
108
+ /** The full prompt the parent agent sent to the sub-agent. */
109
+ prompt: string;
110
+ };
111
+ } | {
112
+ name: 'SubagentStop';
113
+ session: SessionContext;
114
+ agent: {
115
+ name: string;
116
+ description: string;
117
+ };
118
+ /** Wall-clock duration of the sub-agent run. */
119
+ durationMs: number;
120
+ /** How the sub-agent finished. `aborted` includes Esc cancellation
121
+ * and reaching the per-agent maxTurns cap without finalising. */
122
+ outcome: 'completed' | 'aborted' | 'failed';
123
+ tokenUsage?: {
124
+ inputTokens: number;
125
+ outputTokens: number;
126
+ totalTokens: number;
127
+ };
128
+ } | {
129
+ name: 'TurnComplete';
130
+ session: SessionContext;
131
+ turn: number;
132
+ tokenUsage?: {
133
+ inputTokens: number;
134
+ outputTokens: number;
135
+ totalTokens: number;
136
+ };
137
+ } | {
138
+ name: 'SessionEnd';
139
+ session: SessionContext;
140
+ };
141
+ /** What a hook can ask the agent to do via its stdout JSON. */
142
+ export type HookDecision = {
143
+ decision: 'allow';
144
+ context?: string;
145
+ } | {
146
+ decision: 'deny';
147
+ reason?: string;
148
+ } | {
149
+ decision: 'modify';
150
+ args?: unknown;
151
+ output?: string;
152
+ context?: string;
153
+ };
154
+ /** A hook ready to execute — paired with its owning plugin's identity
155
+ * and rootDir so variable expansion can resolve `${pluginDir}`. Built
156
+ * by [[buildHookRegistry]] at startup, immutable for the session. */
157
+ export interface RegisteredHook {
158
+ pluginId: string;
159
+ /** Absolute path to the plugin's root dir — substituted into the
160
+ * hook command via `${pluginDir}`. */
161
+ pluginDir: string;
162
+ event: HookEventName;
163
+ entry: HookConfigEntry;
164
+ }
165
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ // @x-code-cli/core — Hooks subsystem types
2
+ //
3
+ // A hook is a shell command a plugin registers against one of six agent
4
+ // lifecycle events. The CLI emits an event payload to the hook on stdin
5
+ // as one JSON line; the hook may reply on stdout with a one-line JSON
6
+ // `HookDecision` to influence what the agent does next (allow / deny /
7
+ // modify args / inject context).
8
+ //
9
+ // Why shell commands and not a programmatic SDK: lowest barrier to entry
10
+ // for plugin authors, matches the format users already see in Claude
11
+ // Code, and keeps the surface area small (no plugin code runs inside
12
+ // our process). See [[plugin-marketplace-design]] §8 for the full
13
+ // rationale.
14
+ //
15
+ // Why ten events: enough to cover the high-value lifecycle integrations
16
+ // (context injection, tool gating, sub-agent audit, compaction
17
+ // instrumentation, completion notifications) without exposing every
18
+ // internal seam we may want to refactor. Adding events later is cheap;
19
+ // removing them is a breaking change. PreCompact / PostCompact and
20
+ // SubagentStart / SubagentStop were added in round 2 to match the
21
+ // Claude/Codex shape — plugins that want to log every sub-agent
22
+ // invocation or persist state before compaction wipes it had no other
23
+ // hook to attach to.
24
+ export {};
25
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,sEAAsE;AACtE,uEAAuE;AACvE,iCAAiC;AACjC,EAAE;AACF,yEAAyE;AACzE,qEAAqE;AACrE,qEAAqE;AACrE,kEAAkE;AAClE,aAAa;AACb,EAAE;AACF,wEAAwE;AACxE,+DAA+D;AAC/D,oEAAoE;AACpE,uEAAuE;AACvE,mEAAmE;AACnE,kEAAkE;AAClE,gEAAgE;AAChE,sEAAsE;AACtE,qBAAqB"}
@@ -0,0 +1,22 @@
1
+ export interface VariableContext {
2
+ pluginDir: string;
3
+ /** Persistent per-plugin data directory. Pre-created by
4
+ * [[buildVariableContext]] when a `pluginId` is supplied. */
5
+ pluginDataDir?: string;
6
+ cwd: string;
7
+ homedir?: string;
8
+ sep?: string;
9
+ }
10
+ /** Default variables derived from the current process + caller context.
11
+ * Pass `pluginId` to enable `${pluginDataDir}` — we'll resolve the
12
+ * per-plugin data dir path and `mkdir -p` it so the plugin can write
13
+ * there immediately. mkdirSync on an existing dir is a cheap no-op. */
14
+ export declare function buildVariableContext(input: {
15
+ pluginDir: string;
16
+ cwd: string;
17
+ pluginId?: string;
18
+ }): VariableContext;
19
+ /** Expand `${pluginDir}` / `${pluginDataDir}` / `${cwd}` / `${homedir}` /
20
+ * `${sep}` / `${env:NAME}` references. Unknown patterns are left verbatim. */
21
+ export declare function expandVariables(source: string, ctx: VariableContext): string;
22
+ //# sourceMappingURL=variables.d.ts.map