comisai 1.0.10 → 1.0.12

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 (251) hide show
  1. package/README.md +3 -3
  2. package/node_modules/@comis/agent/dist/executor/pi-executor.d.ts +1 -4
  3. package/node_modules/@comis/agent/package.json +1 -1
  4. package/node_modules/@comis/channels/package.json +1 -1
  5. package/node_modules/@comis/cli/dist/wizard/steps/06-channels.js +88 -11
  6. package/node_modules/@comis/cli/dist/wizard/steps/10-write-config.js +4 -0
  7. package/node_modules/@comis/cli/dist/wizard/types.d.ts +1 -0
  8. package/node_modules/@comis/cli/package.json +1 -1
  9. package/node_modules/@comis/core/package.json +1 -1
  10. package/node_modules/@comis/daemon/package.json +1 -1
  11. package/node_modules/@comis/gateway/package.json +1 -1
  12. package/node_modules/@comis/infra/package.json +1 -1
  13. package/node_modules/@comis/memory/package.json +1 -1
  14. package/node_modules/@comis/scheduler/package.json +1 -1
  15. package/node_modules/@comis/shared/package.json +1 -1
  16. package/node_modules/@comis/skills/package.json +1 -1
  17. package/package.json +18 -18
  18. package/node_modules/@comis/core/dist/approval/approval-gate.test.d.ts +0 -1
  19. package/node_modules/@comis/core/dist/approval/approval-gate.test.js +0 -1003
  20. package/node_modules/@comis/core/dist/bootstrap.test.d.ts +0 -1
  21. package/node_modules/@comis/core/dist/bootstrap.test.js +0 -150
  22. package/node_modules/@comis/core/dist/config/backup.test.d.ts +0 -1
  23. package/node_modules/@comis/core/dist/config/backup.test.js +0 -160
  24. package/node_modules/@comis/core/dist/config/env-substitution.test.d.ts +0 -1
  25. package/node_modules/@comis/core/dist/config/env-substitution.test.js +0 -259
  26. package/node_modules/@comis/core/dist/config/field-metadata.test.d.ts +0 -1
  27. package/node_modules/@comis/core/dist/config/field-metadata.test.js +0 -72
  28. package/node_modules/@comis/core/dist/config/git-manager.test.d.ts +0 -1
  29. package/node_modules/@comis/core/dist/config/git-manager.test.js +0 -1042
  30. package/node_modules/@comis/core/dist/config/immutable-keys.test.d.ts +0 -1
  31. package/node_modules/@comis/core/dist/config/immutable-keys.test.js +0 -283
  32. package/node_modules/@comis/core/dist/config/include-resolver.test.d.ts +0 -1
  33. package/node_modules/@comis/core/dist/config/include-resolver.test.js +0 -292
  34. package/node_modules/@comis/core/dist/config/layered.test.d.ts +0 -1
  35. package/node_modules/@comis/core/dist/config/layered.test.js +0 -211
  36. package/node_modules/@comis/core/dist/config/loader.test.d.ts +0 -1
  37. package/node_modules/@comis/core/dist/config/loader.test.js +0 -300
  38. package/node_modules/@comis/core/dist/config/migrate.test.d.ts +0 -1
  39. package/node_modules/@comis/core/dist/config/migrate.test.js +0 -244
  40. package/node_modules/@comis/core/dist/config/partial-validator.test.d.ts +0 -1
  41. package/node_modules/@comis/core/dist/config/partial-validator.test.js +0 -98
  42. package/node_modules/@comis/core/dist/config/schema-agent-model.test.d.ts +0 -1
  43. package/node_modules/@comis/core/dist/config/schema-agent-model.test.js +0 -279
  44. package/node_modules/@comis/core/dist/config/schema-agent-session.test.d.ts +0 -1
  45. package/node_modules/@comis/core/dist/config/schema-agent-session.test.js +0 -242
  46. package/node_modules/@comis/core/dist/config/schema-agent.test.d.ts +0 -1
  47. package/node_modules/@comis/core/dist/config/schema-agent.test.js +0 -645
  48. package/node_modules/@comis/core/dist/config/schema-channel.test.d.ts +0 -1
  49. package/node_modules/@comis/core/dist/config/schema-channel.test.js +0 -341
  50. package/node_modules/@comis/core/dist/config/schema-coalescer.test.d.ts +0 -1
  51. package/node_modules/@comis/core/dist/config/schema-coalescer.test.js +0 -51
  52. package/node_modules/@comis/core/dist/config/schema-context-engine.test.d.ts +0 -1
  53. package/node_modules/@comis/core/dist/config/schema-context-engine.test.js +0 -797
  54. package/node_modules/@comis/core/dist/config/schema-context-guard.test.d.ts +0 -1
  55. package/node_modules/@comis/core/dist/config/schema-context-guard.test.js +0 -111
  56. package/node_modules/@comis/core/dist/config/schema-daemon.test.d.ts +0 -1
  57. package/node_modules/@comis/core/dist/config/schema-daemon.test.js +0 -107
  58. package/node_modules/@comis/core/dist/config/schema-delivery-timing.test.d.ts +0 -1
  59. package/node_modules/@comis/core/dist/config/schema-delivery-timing.test.js +0 -51
  60. package/node_modules/@comis/core/dist/config/schema-documentation.test.d.ts +0 -1
  61. package/node_modules/@comis/core/dist/config/schema-documentation.test.js +0 -63
  62. package/node_modules/@comis/core/dist/config/schema-gateway.test.d.ts +0 -1
  63. package/node_modules/@comis/core/dist/config/schema-gateway.test.js +0 -219
  64. package/node_modules/@comis/core/dist/config/schema-gemini-cache.test.d.ts +0 -1
  65. package/node_modules/@comis/core/dist/config/schema-gemini-cache.test.js +0 -41
  66. package/node_modules/@comis/core/dist/config/schema-integrations.test.d.ts +0 -1
  67. package/node_modules/@comis/core/dist/config/schema-integrations.test.js +0 -92
  68. package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.test.d.ts +0 -1
  69. package/node_modules/@comis/core/dist/config/schema-lifecycle-reactions.test.js +0 -61
  70. package/node_modules/@comis/core/dist/config/schema-misc.test.d.ts +0 -1
  71. package/node_modules/@comis/core/dist/config/schema-misc.test.js +0 -394
  72. package/node_modules/@comis/core/dist/config/schema-observability.test.d.ts +0 -1
  73. package/node_modules/@comis/core/dist/config/schema-observability.test.js +0 -76
  74. package/node_modules/@comis/core/dist/config/schema-providers.test.d.ts +0 -1
  75. package/node_modules/@comis/core/dist/config/schema-providers.test.js +0 -294
  76. package/node_modules/@comis/core/dist/config/schema-queue.test.d.ts +0 -1
  77. package/node_modules/@comis/core/dist/config/schema-queue.test.js +0 -234
  78. package/node_modules/@comis/core/dist/config/schema-response-prefix.test.d.ts +0 -1
  79. package/node_modules/@comis/core/dist/config/schema-response-prefix.test.js +0 -36
  80. package/node_modules/@comis/core/dist/config/schema-security.test.d.ts +0 -1
  81. package/node_modules/@comis/core/dist/config/schema-security.test.js +0 -54
  82. package/node_modules/@comis/core/dist/config/schema-sender-trust-display.test.d.ts +0 -1
  83. package/node_modules/@comis/core/dist/config/schema-sender-trust-display.test.js +0 -60
  84. package/node_modules/@comis/core/dist/config/schema-serializer.test.d.ts +0 -1
  85. package/node_modules/@comis/core/dist/config/schema-serializer.test.js +0 -73
  86. package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.test.d.ts +0 -1
  87. package/node_modules/@comis/core/dist/config/schema-telegram-file-guard.test.js +0 -39
  88. package/node_modules/@comis/core/dist/context/context.test.d.ts +0 -1
  89. package/node_modules/@comis/core/dist/context/context.test.js +0 -276
  90. package/node_modules/@comis/core/dist/domain/agent-response.test.d.ts +0 -1
  91. package/node_modules/@comis/core/dist/domain/agent-response.test.js +0 -159
  92. package/node_modules/@comis/core/dist/domain/credential-mapping.test.d.ts +0 -1
  93. package/node_modules/@comis/core/dist/domain/credential-mapping.test.js +0 -135
  94. package/node_modules/@comis/core/dist/domain/delivery-origin.test.d.ts +0 -1
  95. package/node_modules/@comis/core/dist/domain/delivery-origin.test.js +0 -68
  96. package/node_modules/@comis/core/dist/domain/execution-graph.test.d.ts +0 -1
  97. package/node_modules/@comis/core/dist/domain/execution-graph.test.js +0 -441
  98. package/node_modules/@comis/core/dist/domain/memory-entry.test.d.ts +0 -1
  99. package/node_modules/@comis/core/dist/domain/memory-entry.test.js +0 -193
  100. package/node_modules/@comis/core/dist/domain/normalized-message.test.d.ts +0 -1
  101. package/node_modules/@comis/core/dist/domain/normalized-message.test.js +0 -255
  102. package/node_modules/@comis/core/dist/domain/session-key.test.d.ts +0 -1
  103. package/node_modules/@comis/core/dist/domain/session-key.test.js +0 -291
  104. package/node_modules/@comis/core/dist/domain/subagent-context-config.test.d.ts +0 -1
  105. package/node_modules/@comis/core/dist/domain/subagent-context-config.test.js +0 -131
  106. package/node_modules/@comis/core/dist/domain/subagent-context-types.test.d.ts +0 -1
  107. package/node_modules/@comis/core/dist/domain/subagent-context-types.test.js +0 -182
  108. package/node_modules/@comis/core/dist/event-bus/bus.test.d.ts +0 -1
  109. package/node_modules/@comis/core/dist/event-bus/bus.test.js +0 -152
  110. package/node_modules/@comis/core/dist/event-bus/events-agent.test.d.ts +0 -1
  111. package/node_modules/@comis/core/dist/event-bus/events-agent.test.js +0 -409
  112. package/node_modules/@comis/core/dist/event-bus/events-channel.test.d.ts +0 -1
  113. package/node_modules/@comis/core/dist/event-bus/events-channel.test.js +0 -240
  114. package/node_modules/@comis/core/dist/event-bus/events-infra.test.d.ts +0 -1
  115. package/node_modules/@comis/core/dist/event-bus/events-infra.test.js +0 -416
  116. package/node_modules/@comis/core/dist/event-bus/events-messaging.test.d.ts +0 -1
  117. package/node_modules/@comis/core/dist/event-bus/events-messaging.test.js +0 -433
  118. package/node_modules/@comis/core/dist/event-bus/events.test.d.ts +0 -1
  119. package/node_modules/@comis/core/dist/event-bus/events.test.js +0 -93
  120. package/node_modules/@comis/core/dist/hooks/hook-runner-global.test.d.ts +0 -1
  121. package/node_modules/@comis/core/dist/hooks/hook-runner-global.test.js +0 -29
  122. package/node_modules/@comis/core/dist/hooks/hook-runner.test.d.ts +0 -1
  123. package/node_modules/@comis/core/dist/hooks/hook-runner.test.js +0 -490
  124. package/node_modules/@comis/core/dist/hooks/hook-strategies.test.d.ts +0 -1
  125. package/node_modules/@comis/core/dist/hooks/hook-strategies.test.js +0 -209
  126. package/node_modules/@comis/core/dist/hooks/integration.test.d.ts +0 -1
  127. package/node_modules/@comis/core/dist/hooks/integration.test.js +0 -235
  128. package/node_modules/@comis/core/dist/hooks/plugin-registry.test.d.ts +0 -1
  129. package/node_modules/@comis/core/dist/hooks/plugin-registry.test.js +0 -470
  130. package/node_modules/@comis/core/dist/load-env.test.d.ts +0 -1
  131. package/node_modules/@comis/core/dist/load-env.test.js +0 -21
  132. package/node_modules/@comis/core/dist/security/action-classifier.test.d.ts +0 -1
  133. package/node_modules/@comis/core/dist/security/action-classifier.test.js +0 -298
  134. package/node_modules/@comis/core/dist/security/audit-aggregator.test.d.ts +0 -1
  135. package/node_modules/@comis/core/dist/security/audit-aggregator.test.js +0 -128
  136. package/node_modules/@comis/core/dist/security/audit.test.d.ts +0 -1
  137. package/node_modules/@comis/core/dist/security/audit.test.js +0 -154
  138. package/node_modules/@comis/core/dist/security/canary-token.test.d.ts +0 -1
  139. package/node_modules/@comis/core/dist/security/canary-token.test.js +0 -45
  140. package/node_modules/@comis/core/dist/security/config-redaction.test.d.ts +0 -1
  141. package/node_modules/@comis/core/dist/security/config-redaction.test.js +0 -107
  142. package/node_modules/@comis/core/dist/security/external-content.test.d.ts +0 -1
  143. package/node_modules/@comis/core/dist/security/external-content.test.js +0 -210
  144. package/node_modules/@comis/core/dist/security/injection-patterns.test.d.ts +0 -1
  145. package/node_modules/@comis/core/dist/security/injection-patterns.test.js +0 -213
  146. package/node_modules/@comis/core/dist/security/injection-rate-limiter.test.d.ts +0 -1
  147. package/node_modules/@comis/core/dist/security/injection-rate-limiter.test.js +0 -194
  148. package/node_modules/@comis/core/dist/security/input-guard.test.d.ts +0 -1
  149. package/node_modules/@comis/core/dist/security/input-guard.test.js +0 -215
  150. package/node_modules/@comis/core/dist/security/input-security-guard.test.d.ts +0 -1
  151. package/node_modules/@comis/core/dist/security/input-security-guard.test.js +0 -215
  152. package/node_modules/@comis/core/dist/security/input-validator.test.d.ts +0 -1
  153. package/node_modules/@comis/core/dist/security/input-validator.test.js +0 -133
  154. package/node_modules/@comis/core/dist/security/log-sanitizer.test.d.ts +0 -1
  155. package/node_modules/@comis/core/dist/security/log-sanitizer.test.js +0 -260
  156. package/node_modules/@comis/core/dist/security/memory-write-validator.test.d.ts +0 -1
  157. package/node_modules/@comis/core/dist/security/memory-write-validator.test.js +0 -62
  158. package/node_modules/@comis/core/dist/security/output-guard.test.d.ts +0 -1
  159. package/node_modules/@comis/core/dist/security/output-guard.test.js +0 -397
  160. package/node_modules/@comis/core/dist/security/safe-path.test.d.ts +0 -1
  161. package/node_modules/@comis/core/dist/security/safe-path.test.js +0 -95
  162. package/node_modules/@comis/core/dist/security/scoped-secret-manager.test.d.ts +0 -1
  163. package/node_modules/@comis/core/dist/security/scoped-secret-manager.test.js +0 -231
  164. package/node_modules/@comis/core/dist/security/secret-access.test.d.ts +0 -1
  165. package/node_modules/@comis/core/dist/security/secret-access.test.js +0 -41
  166. package/node_modules/@comis/core/dist/security/secret-crypto.test.d.ts +0 -1
  167. package/node_modules/@comis/core/dist/security/secret-crypto.test.js +0 -113
  168. package/node_modules/@comis/core/dist/security/secret-manager.test.d.ts +0 -1
  169. package/node_modules/@comis/core/dist/security/secret-manager.test.js +0 -394
  170. package/node_modules/@comis/core/dist/security/secret-ref-resolver.test.d.ts +0 -1
  171. package/node_modules/@comis/core/dist/security/secret-ref-resolver.test.js +0 -268
  172. package/node_modules/@comis/core/dist/security/secrets-audit.test.d.ts +0 -10
  173. package/node_modules/@comis/core/dist/security/secrets-audit.test.js +0 -295
  174. package/node_modules/@comis/core/dist/security/ssrf-guard.test.d.ts +0 -1
  175. package/node_modules/@comis/core/dist/security/ssrf-guard.test.js +0 -127
  176. package/node_modules/@comis/core/dist/security/token-generator.test.d.ts +0 -1
  177. package/node_modules/@comis/core/dist/security/token-generator.test.js +0 -35
  178. package/node_modules/@comis/core/dist/tool-metadata.test.d.ts +0 -1
  179. package/node_modules/@comis/core/dist/tool-metadata.test.js +0 -112
  180. package/node_modules/@comis/memory/dist/compaction.test.d.ts +0 -1
  181. package/node_modules/@comis/memory/dist/compaction.test.js +0 -298
  182. package/node_modules/@comis/memory/dist/context-schema.test.d.ts +0 -1
  183. package/node_modules/@comis/memory/dist/context-schema.test.js +0 -246
  184. package/node_modules/@comis/memory/dist/context-store.test.d.ts +0 -1
  185. package/node_modules/@comis/memory/dist/context-store.test.js +0 -708
  186. package/node_modules/@comis/memory/dist/credential-mapping-schema.test.d.ts +0 -7
  187. package/node_modules/@comis/memory/dist/credential-mapping-schema.test.js +0 -73
  188. package/node_modules/@comis/memory/dist/credential-mapping-store.test.d.ts +0 -8
  189. package/node_modules/@comis/memory/dist/credential-mapping-store.test.js +0 -340
  190. package/node_modules/@comis/memory/dist/delivery-mirror-adapter.test.d.ts +0 -1
  191. package/node_modules/@comis/memory/dist/delivery-mirror-adapter.test.js +0 -165
  192. package/node_modules/@comis/memory/dist/delivery-queue-adapter.test.d.ts +0 -1
  193. package/node_modules/@comis/memory/dist/delivery-queue-adapter.test.js +0 -263
  194. package/node_modules/@comis/memory/dist/embedding-batch-indexer.test.d.ts +0 -1
  195. package/node_modules/@comis/memory/dist/embedding-batch-indexer.test.js +0 -202
  196. package/node_modules/@comis/memory/dist/embedding-cache-lru.test.d.ts +0 -1
  197. package/node_modules/@comis/memory/dist/embedding-cache-lru.test.js +0 -241
  198. package/node_modules/@comis/memory/dist/embedding-cache-sqlite.test.d.ts +0 -8
  199. package/node_modules/@comis/memory/dist/embedding-cache-sqlite.test.js +0 -678
  200. package/node_modules/@comis/memory/dist/embedding-cache.test.d.ts +0 -1
  201. package/node_modules/@comis/memory/dist/embedding-cache.test.js +0 -213
  202. package/node_modules/@comis/memory/dist/embedding-fingerprint.test.d.ts +0 -1
  203. package/node_modules/@comis/memory/dist/embedding-fingerprint.test.js +0 -87
  204. package/node_modules/@comis/memory/dist/embedding-hash.test.d.ts +0 -1
  205. package/node_modules/@comis/memory/dist/embedding-hash.test.js +0 -31
  206. package/node_modules/@comis/memory/dist/embedding-integration.test.d.ts +0 -8
  207. package/node_modules/@comis/memory/dist/embedding-integration.test.js +0 -232
  208. package/node_modules/@comis/memory/dist/embedding-provider-factory.test.d.ts +0 -1
  209. package/node_modules/@comis/memory/dist/embedding-provider-factory.test.js +0 -176
  210. package/node_modules/@comis/memory/dist/embedding-provider-local.test.d.ts +0 -8
  211. package/node_modules/@comis/memory/dist/embedding-provider-local.test.js +0 -76
  212. package/node_modules/@comis/memory/dist/embedding-provider-openai.test.d.ts +0 -8
  213. package/node_modules/@comis/memory/dist/embedding-provider-openai.test.js +0 -100
  214. package/node_modules/@comis/memory/dist/embedding-queue.test.d.ts +0 -1
  215. package/node_modules/@comis/memory/dist/embedding-queue.test.js +0 -236
  216. package/node_modules/@comis/memory/dist/hybrid-search.test.d.ts +0 -1
  217. package/node_modules/@comis/memory/dist/hybrid-search.test.js +0 -476
  218. package/node_modules/@comis/memory/dist/identity-link-store.test.d.ts +0 -1
  219. package/node_modules/@comis/memory/dist/identity-link-store.test.js +0 -88
  220. package/node_modules/@comis/memory/dist/memory-api.test.d.ts +0 -1
  221. package/node_modules/@comis/memory/dist/memory-api.test.js +0 -495
  222. package/node_modules/@comis/memory/dist/memory-concurrency.test.d.ts +0 -20
  223. package/node_modules/@comis/memory/dist/memory-concurrency.test.js +0 -222
  224. package/node_modules/@comis/memory/dist/named-graph-store.test.d.ts +0 -1
  225. package/node_modules/@comis/memory/dist/named-graph-store.test.js +0 -227
  226. package/node_modules/@comis/memory/dist/observability-store.test.d.ts +0 -1
  227. package/node_modules/@comis/memory/dist/observability-store.test.js +0 -704
  228. package/node_modules/@comis/memory/dist/row-mapper.test.d.ts +0 -1
  229. package/node_modules/@comis/memory/dist/row-mapper.test.js +0 -409
  230. package/node_modules/@comis/memory/dist/schema.test.d.ts +0 -1
  231. package/node_modules/@comis/memory/dist/schema.test.js +0 -240
  232. package/node_modules/@comis/memory/dist/secret-store-schema.test.d.ts +0 -7
  233. package/node_modules/@comis/memory/dist/secret-store-schema.test.js +0 -90
  234. package/node_modules/@comis/memory/dist/session-store.test.d.ts +0 -1
  235. package/node_modules/@comis/memory/dist/session-store.test.js +0 -262
  236. package/node_modules/@comis/memory/dist/setup-secrets.test.d.ts +0 -1
  237. package/node_modules/@comis/memory/dist/setup-secrets.test.js +0 -140
  238. package/node_modules/@comis/memory/dist/sqlite-memory-adapter.test.d.ts +0 -1
  239. package/node_modules/@comis/memory/dist/sqlite-memory-adapter.test.js +0 -888
  240. package/node_modules/@comis/memory/dist/sqlite-secret-store.test.d.ts +0 -8
  241. package/node_modules/@comis/memory/dist/sqlite-secret-store.test.js +0 -245
  242. package/node_modules/@comis/shared/dist/abort.test.d.ts +0 -1
  243. package/node_modules/@comis/shared/dist/abort.test.js +0 -71
  244. package/node_modules/@comis/shared/dist/result.test.d.ts +0 -1
  245. package/node_modules/@comis/shared/dist/result.test.js +0 -178
  246. package/node_modules/@comis/shared/dist/suppress-error.test.d.ts +0 -1
  247. package/node_modules/@comis/shared/dist/suppress-error.test.js +0 -50
  248. package/node_modules/@comis/shared/dist/timeout.test.d.ts +0 -1
  249. package/node_modules/@comis/shared/dist/timeout.test.js +0 -75
  250. package/node_modules/@comis/shared/dist/ttl-cache.test.d.ts +0 -1
  251. package/node_modules/@comis/shared/dist/ttl-cache.test.js +0 -81
@@ -1,490 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { ok } from "@comis/shared";
3
- import { TypedEventBus } from "../event-bus/index.js";
4
- import { createPluginRegistry } from "./plugin-registry.js";
5
- import { createHookRunner } from "./hook-runner.js";
6
- /**
7
- * Create a minimal test plugin with sensible defaults.
8
- */
9
- function createTestPlugin(overrides) {
10
- return {
11
- name: overrides.name ?? `test-plugin-${overrides.id}`,
12
- register: overrides.register ?? ((_api) => ok(undefined)),
13
- ...overrides,
14
- };
15
- }
16
- describe("HookRunner", () => {
17
- // ─── Void Hook Execution ────────────────────────────────────────
18
- describe("void hook execution", () => {
19
- it("runs void hooks in parallel (verifies Promise.all-like behavior)", async () => {
20
- const registry = createPluginRegistry();
21
- const runner = createHookRunner(registry);
22
- const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
23
- registry.register(createTestPlugin({
24
- id: "slow-1",
25
- register: (api) => {
26
- api.registerHook("agent_end", async () => {
27
- await delay(50);
28
- });
29
- return ok(undefined);
30
- },
31
- }));
32
- registry.register(createTestPlugin({
33
- id: "slow-2",
34
- register: (api) => {
35
- api.registerHook("agent_end", async () => {
36
- await delay(50);
37
- });
38
- return ok(undefined);
39
- },
40
- }));
41
- const startMs = Date.now();
42
- await runner.runAgentEnd({ durationMs: 100, success: true }, { agentId: "test-agent" });
43
- const elapsed = Date.now() - startMs;
44
- // If parallel: ~50ms. If sequential: ~100ms.
45
- // Use generous margin for CI variance.
46
- expect(elapsed).toBeLessThan(90);
47
- });
48
- it("void hook errors are caught and do not propagate (catchErrors: true)", async () => {
49
- const registry = createPluginRegistry();
50
- const runner = createHookRunner(registry, { catchErrors: true });
51
- registry.register(createTestPlugin({
52
- id: "throws",
53
- register: (api) => {
54
- api.registerHook("agent_end", () => {
55
- throw new Error("boom");
56
- });
57
- return ok(undefined);
58
- },
59
- }));
60
- // Should not throw
61
- await expect(runner.runAgentEnd({ durationMs: 100, success: true }, { agentId: "a" })).resolves.toBeUndefined();
62
- });
63
- it("void hook errors propagate when catchErrors is false", async () => {
64
- const registry = createPluginRegistry();
65
- const runner = createHookRunner(registry, { catchErrors: false });
66
- registry.register(createTestPlugin({
67
- id: "throws",
68
- register: (api) => {
69
- api.registerHook("agent_end", () => {
70
- throw new Error("propagate-me");
71
- });
72
- return ok(undefined);
73
- },
74
- }));
75
- await expect(runner.runAgentEnd({ durationMs: 100, success: true }, { agentId: "a" })).rejects.toThrow("propagate-me");
76
- });
77
- it("void hooks with no registrations complete without error", async () => {
78
- const registry = createPluginRegistry();
79
- const runner = createHookRunner(registry);
80
- await expect(runner.runAgentEnd({ durationMs: 100, success: true }, { agentId: "a" })).resolves.toBeUndefined();
81
- });
82
- });
83
- // ─── Modifying Hook Execution ───────────────────────────────────
84
- describe("modifying hook execution", () => {
85
- it("runs modifying hooks sequentially (verifies order)", async () => {
86
- const registry = createPluginRegistry();
87
- const runner = createHookRunner(registry);
88
- const executionOrder = [];
89
- registry.register(createTestPlugin({
90
- id: "high-pri",
91
- register: (api) => {
92
- api.registerHook("before_agent_start", () => {
93
- executionOrder.push("high");
94
- return { systemPrompt: "high" };
95
- }, { priority: 10 });
96
- return ok(undefined);
97
- },
98
- }));
99
- registry.register(createTestPlugin({
100
- id: "low-pri",
101
- register: (api) => {
102
- api.registerHook("before_agent_start", () => {
103
- executionOrder.push("low");
104
- return { systemPrompt: "low" };
105
- }, { priority: 5 });
106
- return ok(undefined);
107
- },
108
- }));
109
- await runner.runBeforeAgentStart({ systemPrompt: "original", messages: [] }, { agentId: "a" });
110
- // Higher priority runs first
111
- expect(executionOrder).toEqual(["high", "low"]);
112
- });
113
- it("modifying hook merges results correctly for before_agent_start", async () => {
114
- const registry = createPluginRegistry();
115
- const runner = createHookRunner(registry);
116
- registry.register(createTestPlugin({
117
- id: "a",
118
- register: (api) => {
119
- api.registerHook("before_agent_start", () => ({ systemPrompt: "modified" }), { priority: 10 });
120
- return ok(undefined);
121
- },
122
- }));
123
- registry.register(createTestPlugin({
124
- id: "b",
125
- register: (api) => {
126
- api.registerHook("before_agent_start", () => ({ prependContext: "extra" }), { priority: 5 });
127
- return ok(undefined);
128
- },
129
- }));
130
- const result = await runner.runBeforeAgentStart({ systemPrompt: "original", messages: [] }, { agentId: "a" });
131
- expect(result).toEqual({
132
- systemPrompt: "modified",
133
- prependContext: "extra",
134
- });
135
- });
136
- it("modifying hook: later hook overrides earlier for same field", async () => {
137
- const registry = createPluginRegistry();
138
- const runner = createHookRunner(registry);
139
- registry.register(createTestPlugin({
140
- id: "first",
141
- register: (api) => {
142
- api.registerHook("before_agent_start", () => ({ systemPrompt: "first" }), { priority: 10 });
143
- return ok(undefined);
144
- },
145
- }));
146
- registry.register(createTestPlugin({
147
- id: "second",
148
- register: (api) => {
149
- api.registerHook("before_agent_start", () => ({ systemPrompt: "second" }), { priority: 5 });
150
- return ok(undefined);
151
- },
152
- }));
153
- const result = await runner.runBeforeAgentStart({ systemPrompt: "original", messages: [] }, { agentId: "a" });
154
- // B runs after A (lower priority), so B's value overrides A's
155
- expect(result?.systemPrompt).toBe("second");
156
- });
157
- it("modifying hooks return undefined when no hooks registered", async () => {
158
- const registry = createPluginRegistry();
159
- const runner = createHookRunner(registry);
160
- const result = await runner.runBeforeAgentStart({ systemPrompt: "original", messages: [] }, { agentId: "a" });
161
- expect(result).toBeUndefined();
162
- });
163
- it("modifying hook errors are caught and skipped (catchErrors: true)", async () => {
164
- const registry = createPluginRegistry();
165
- const runner = createHookRunner(registry, { catchErrors: true });
166
- registry.register(createTestPlugin({
167
- id: "throws",
168
- register: (api) => {
169
- api.registerHook("before_agent_start", () => {
170
- throw new Error("broken hook");
171
- }, { priority: 10 });
172
- return ok(undefined);
173
- },
174
- }));
175
- registry.register(createTestPlugin({
176
- id: "good",
177
- register: (api) => {
178
- api.registerHook("before_agent_start", () => ({ systemPrompt: "good-result" }), { priority: 5 });
179
- return ok(undefined);
180
- },
181
- }));
182
- const result = await runner.runBeforeAgentStart({ systemPrompt: "original", messages: [] }, { agentId: "a" });
183
- // The erroring hook is skipped, good hook's result is returned
184
- expect(result?.systemPrompt).toBe("good-result");
185
- });
186
- });
187
- // ─── before_tool_call specific ──────────────────────────────────
188
- describe("before_tool_call specific", () => {
189
- it("before_tool_call can block tool execution", async () => {
190
- const registry = createPluginRegistry();
191
- const runner = createHookRunner(registry);
192
- registry.register(createTestPlugin({
193
- id: "blocker",
194
- register: (api) => {
195
- api.registerHook("before_tool_call", () => ({
196
- block: true,
197
- blockReason: "denied",
198
- }));
199
- return ok(undefined);
200
- },
201
- }));
202
- const result = await runner.runBeforeToolCall({ toolName: "shell:exec", params: {} }, { agentId: "a" });
203
- expect(result?.block).toBe(true);
204
- expect(result?.blockReason).toBe("denied");
205
- });
206
- it("before_tool_call can modify params", async () => {
207
- const registry = createPluginRegistry();
208
- const runner = createHookRunner(registry);
209
- registry.register(createTestPlugin({
210
- id: "modifier",
211
- register: (api) => {
212
- api.registerHook("before_tool_call", () => ({
213
- params: { modified: true },
214
- }));
215
- return ok(undefined);
216
- },
217
- }));
218
- const result = await runner.runBeforeToolCall({ toolName: "read_file", params: { path: "/tmp" } }, { agentId: "a" });
219
- expect(result?.params).toEqual({ modified: true });
220
- });
221
- });
222
- // ─── tool_result_persist synchronous ────────────────────────────
223
- describe("tool_result_persist synchronous", () => {
224
- it("runToolResultPersist is synchronous (returns value, not promise)", () => {
225
- const registry = createPluginRegistry();
226
- const runner = createHookRunner(registry);
227
- registry.register(createTestPlugin({
228
- id: "sync-plugin",
229
- register: (api) => {
230
- api.registerHook("tool_result_persist", () => ({
231
- result: "transformed",
232
- }));
233
- return ok(undefined);
234
- },
235
- }));
236
- const result = runner.runToolResultPersist({ toolName: "test", result: "original" }, { agentId: "a" });
237
- // Verify it's not a Promise
238
- expect(result).toBeDefined();
239
- expect(typeof result === "object" && result !== null && "then" in result).toBe(false);
240
- expect(result?.result).toBe("transformed");
241
- });
242
- it("tool_result_persist can transform the persisted result", () => {
243
- const registry = createPluginRegistry();
244
- const runner = createHookRunner(registry);
245
- registry.register(createTestPlugin({
246
- id: "redactor",
247
- register: (api) => {
248
- api.registerHook("tool_result_persist", (event) => ({
249
- result: event.result.replace(/secret/g, "[REDACTED]"),
250
- }));
251
- return ok(undefined);
252
- },
253
- }));
254
- const result = runner.runToolResultPersist({ toolName: "test", result: "the secret data" }, { agentId: "a" });
255
- expect(result?.result).toBe("the [REDACTED] data");
256
- });
257
- });
258
- // ─── before_compaction specific ─────────────────────────────────
259
- describe("before_compaction specific", () => {
260
- it("before_compaction can cancel compaction", async () => {
261
- const registry = createPluginRegistry();
262
- const runner = createHookRunner(registry);
263
- registry.register(createTestPlugin({
264
- id: "cancel-compaction",
265
- register: (api) => {
266
- api.registerHook("before_compaction", () => ({
267
- cancel: true,
268
- cancelReason: "test",
269
- }));
270
- return ok(undefined);
271
- },
272
- }));
273
- const result = await runner.runBeforeCompaction({
274
- sessionKey: { tenantId: "t", userId: "u", channelId: "c" },
275
- messageCount: 100,
276
- }, { agentId: "a" });
277
- expect(result?.cancel).toBe(true);
278
- expect(result?.cancelReason).toBe("test");
279
- });
280
- });
281
- // ─── Observability Events ───────────────────────────────────────
282
- describe("observability events", () => {
283
- it("emits hook:executed event for each hook invocation", async () => {
284
- const eventBus = new TypedEventBus();
285
- const registry = createPluginRegistry({ eventBus });
286
- const runner = createHookRunner(registry, { eventBus });
287
- const hookEvents = [];
288
- eventBus.on("hook:executed", (e) => hookEvents.push(e));
289
- registry.register(createTestPlugin({
290
- id: "observable",
291
- register: (api) => {
292
- api.registerHook("agent_end", () => { });
293
- return ok(undefined);
294
- },
295
- }));
296
- await runner.runAgentEnd({ durationMs: 100, success: true }, { agentId: "a" });
297
- expect(hookEvents).toHaveLength(1);
298
- });
299
- it("hook:executed includes correct hookName, pluginId, durationMs, success", async () => {
300
- const eventBus = new TypedEventBus();
301
- const registry = createPluginRegistry({ eventBus });
302
- const runner = createHookRunner(registry, { eventBus });
303
- const hookEvents = [];
304
- eventBus.on("hook:executed", (e) => hookEvents.push(e));
305
- registry.register(createTestPlugin({
306
- id: "metric-plugin",
307
- register: (api) => {
308
- api.registerHook("before_agent_start", () => ({ systemPrompt: "ok" }));
309
- return ok(undefined);
310
- },
311
- }));
312
- await runner.runBeforeAgentStart({ systemPrompt: "original", messages: [] }, { agentId: "a" });
313
- expect(hookEvents).toHaveLength(1);
314
- const event = hookEvents[0];
315
- expect(event.hookName).toBe("before_agent_start");
316
- expect(event.pluginId).toBe("metric-plugin");
317
- expect(typeof event.durationMs).toBe("number");
318
- expect(event.durationMs).toBeGreaterThanOrEqual(0);
319
- expect(event.success).toBe(true);
320
- });
321
- it("hook:executed has success: false when hook throws", async () => {
322
- const eventBus = new TypedEventBus();
323
- const registry = createPluginRegistry({ eventBus });
324
- const runner = createHookRunner(registry, { eventBus, catchErrors: true });
325
- const hookEvents = [];
326
- eventBus.on("hook:executed", (e) => hookEvents.push(e));
327
- registry.register(createTestPlugin({
328
- id: "failing-plugin",
329
- register: (api) => {
330
- api.registerHook("agent_end", () => {
331
- throw new Error("hook failure");
332
- });
333
- return ok(undefined);
334
- },
335
- }));
336
- await runner.runAgentEnd({ durationMs: 100, success: true }, { agentId: "a" });
337
- expect(hookEvents).toHaveLength(1);
338
- const event = hookEvents[0];
339
- expect(event.success).toBe(false);
340
- expect(event.error).toBe("hook failure");
341
- });
342
- });
343
- // ─── Zod Validation (SHR-02) ────────────────────────────────────
344
- describe("Zod schema validation (SHR-02)", () => {
345
- it("hook returning valid schema shape is merged correctly", async () => {
346
- const eventBus = new TypedEventBus();
347
- const registry = createPluginRegistry({ eventBus });
348
- const runner = createHookRunner(registry, { eventBus });
349
- registry.register(createTestPlugin({
350
- id: "valid-hook",
351
- register: (api) => {
352
- api.registerHook("before_agent_start", () => ({
353
- systemPrompt: "modified-prompt",
354
- }));
355
- return ok(undefined);
356
- },
357
- }));
358
- const result = await runner.runBeforeAgentStart({ systemPrompt: "original", messages: [] }, { agentId: "a" });
359
- expect(result?.systemPrompt).toBe("modified-prompt");
360
- });
361
- it("hook returning extra properties (strict mode) is skipped with error event", async () => {
362
- const eventBus = new TypedEventBus();
363
- const registry = createPluginRegistry({ eventBus });
364
- const runner = createHookRunner(registry, { eventBus });
365
- const hookEvents = [];
366
- eventBus.on("hook:executed", (e) => hookEvents.push(e));
367
- registry.register(createTestPlugin({
368
- id: "extra-props",
369
- register: (api) => {
370
- api.registerHook("before_agent_start", () => ({
371
- systemPrompt: "modified",
372
- maliciousField: "injected",
373
- }));
374
- return ok(undefined);
375
- },
376
- }));
377
- const result = await runner.runBeforeAgentStart({ systemPrompt: "original", messages: [] }, { agentId: "a" });
378
- // The result should be undefined because the invalid hook was skipped
379
- expect(result).toBeUndefined();
380
- // A hook:executed event should be emitted with success: false
381
- const failEvent = hookEvents.find((e) => !e.success);
382
- expect(failEvent).toBeDefined();
383
- expect(failEvent?.error).toContain("Invalid hook return");
384
- });
385
- it("hook returning extra properties on before_tool_call is skipped", async () => {
386
- const eventBus = new TypedEventBus();
387
- const registry = createPluginRegistry({ eventBus });
388
- const runner = createHookRunner(registry, { eventBus });
389
- registry.register(createTestPlugin({
390
- id: "extra-tool-props",
391
- register: (api) => {
392
- api.registerHook("before_tool_call", () => ({
393
- block: true,
394
- blockReason: "denied",
395
- extraProp: "injected",
396
- }));
397
- return ok(undefined);
398
- },
399
- }));
400
- const result = await runner.runBeforeToolCall({ toolName: "shell:exec", params: {} }, { agentId: "a" });
401
- // Skipped due to strict schema validation
402
- expect(result).toBeUndefined();
403
- });
404
- it("sync hook (tool_result_persist) with extra properties is skipped", () => {
405
- const eventBus = new TypedEventBus();
406
- const registry = createPluginRegistry({ eventBus });
407
- const runner = createHookRunner(registry, { eventBus });
408
- registry.register(createTestPlugin({
409
- id: "extra-sync-props",
410
- register: (api) => {
411
- api.registerHook("tool_result_persist", () => ({
412
- result: "ok",
413
- extraField: "injected",
414
- }));
415
- return ok(undefined);
416
- },
417
- }));
418
- const result = runner.runToolResultPersist({ toolName: "test", result: "original" }, { agentId: "a" });
419
- // Skipped due to strict schema validation
420
- expect(result).toBeUndefined();
421
- });
422
- });
423
- // ─── Audit Events for Modifications (SHR-02) ──────────────────
424
- describe("audit events for hook modifications (SHR-02)", () => {
425
- it("emits audit:event when before_agent_start modifies systemPrompt", async () => {
426
- const eventBus = new TypedEventBus();
427
- const registry = createPluginRegistry({ eventBus });
428
- const runner = createHookRunner(registry, { eventBus });
429
- const auditEvents = [];
430
- eventBus.on("audit:event", (e) => auditEvents.push(e));
431
- registry.register(createTestPlugin({
432
- id: "prompt-modifier",
433
- register: (api) => {
434
- api.registerHook("before_agent_start", () => ({
435
- systemPrompt: "modified prompt",
436
- }));
437
- return ok(undefined);
438
- },
439
- }));
440
- await runner.runBeforeAgentStart({ systemPrompt: "original", messages: [] }, { agentId: "a" });
441
- expect(auditEvents).toHaveLength(1);
442
- expect(auditEvents[0].actionType).toBe("hook_modification");
443
- expect(auditEvents[0].metadata?.hookName).toBe("before_agent_start");
444
- expect(auditEvents[0].metadata?.pluginId).toBe("prompt-modifier");
445
- expect(auditEvents[0].metadata?.systemPromptModified).toBe(true);
446
- });
447
- it("emits audit:event when before_tool_call modifies params", async () => {
448
- const eventBus = new TypedEventBus();
449
- const registry = createPluginRegistry({ eventBus });
450
- const runner = createHookRunner(registry, { eventBus });
451
- const auditEvents = [];
452
- eventBus.on("audit:event", (e) => auditEvents.push(e));
453
- registry.register(createTestPlugin({
454
- id: "param-modifier",
455
- register: (api) => {
456
- api.registerHook("before_tool_call", () => ({
457
- params: { overridden: true },
458
- }));
459
- return ok(undefined);
460
- },
461
- }));
462
- await runner.runBeforeToolCall({ toolName: "read_file", params: { path: "/tmp" } }, { agentId: "a" });
463
- expect(auditEvents).toHaveLength(1);
464
- expect(auditEvents[0].actionType).toBe("hook_modification");
465
- expect(auditEvents[0].metadata?.hookName).toBe("before_tool_call");
466
- expect(auditEvents[0].metadata?.paramsModified).toBe(true);
467
- });
468
- it("emits audit:event when before_tool_call blocks execution", async () => {
469
- const eventBus = new TypedEventBus();
470
- const registry = createPluginRegistry({ eventBus });
471
- const runner = createHookRunner(registry, { eventBus });
472
- const auditEvents = [];
473
- eventBus.on("audit:event", (e) => auditEvents.push(e));
474
- registry.register(createTestPlugin({
475
- id: "tool-blocker",
476
- register: (api) => {
477
- api.registerHook("before_tool_call", () => ({
478
- block: true,
479
- blockReason: "forbidden",
480
- }));
481
- return ok(undefined);
482
- },
483
- }));
484
- await runner.runBeforeToolCall({ toolName: "shell:exec", params: {} }, { agentId: "a" });
485
- expect(auditEvents).toHaveLength(1);
486
- expect(auditEvents[0].metadata?.blocked).toBe(true);
487
- expect(auditEvents[0].metadata?.blockReason).toBe("forbidden");
488
- });
489
- });
490
- });