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,211 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as os from "node:os";
3
- import * as path from "node:path";
4
- import { describe, it, expect, afterEach } from "vitest";
5
- import { deepMerge, mergeLayered, loadLayered } from "./layered.js";
6
- describe("config/layered", () => {
7
- const tmpDirs = [];
8
- function makeTmpDir() {
9
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), "comis-layered-"));
10
- tmpDirs.push(dir);
11
- return dir;
12
- }
13
- function writeYaml(dir, name, content) {
14
- const filePath = path.join(dir, name);
15
- fs.writeFileSync(filePath, content, "utf-8");
16
- return filePath;
17
- }
18
- afterEach(() => {
19
- for (const dir of tmpDirs) {
20
- fs.rmSync(dir, { recursive: true, force: true });
21
- }
22
- tmpDirs.length = 0;
23
- });
24
- describe("deepMerge", () => {
25
- it("merges flat objects", () => {
26
- const result = deepMerge({ a: 1, b: 2 }, { b: 3, c: 4 });
27
- expect(result).toEqual({ a: 1, b: 3, c: 4 });
28
- });
29
- it("deep merges nested objects", () => {
30
- const result = deepMerge({ agent: { name: "Bot", maxSteps: 10 } }, { agent: { maxSteps: 20 } });
31
- expect(result).toEqual({ agent: { name: "Bot", maxSteps: 20 } });
32
- });
33
- it("replaces arrays entirely (no concatenation)", () => {
34
- const result = deepMerge({ security: { permission: { allowedFsPaths: ["/a", "/b"] } } }, { security: { permission: { allowedFsPaths: ["/c"] } } });
35
- expect(result.security.permission
36
- .allowedFsPaths).toEqual(["/c"]);
37
- });
38
- it("ignores undefined values in override", () => {
39
- const result = deepMerge({ a: 1, b: 2 }, { a: undefined, b: 3 });
40
- expect(result).toEqual({ a: 1, b: 3 });
41
- });
42
- it("overrides primitives", () => {
43
- const result = deepMerge({ logLevel: "info" }, { logLevel: "debug" });
44
- expect(result).toEqual({ logLevel: "debug" });
45
- });
46
- describe("prototype pollution defense", () => {
47
- it("skips __proto__ keys", () => {
48
- const base = { a: 1 };
49
- const override = JSON.parse('{"__proto__": {"polluted": true}, "b": 2}');
50
- const result = deepMerge(base, override);
51
- expect(result).toEqual({ a: 1, b: 2 });
52
- expect(result.__proto__).toBe(Object.prototype);
53
- expect(Object.prototype.polluted).toBeUndefined();
54
- });
55
- it("skips constructor keys", () => {
56
- const base = { a: 1 };
57
- const override = JSON.parse('{"constructor": {"polluted": true}, "b": 2}');
58
- const result = deepMerge(base, override);
59
- expect(result).toEqual({ a: 1, b: 2 });
60
- expect(result.constructor).toBe(Object);
61
- });
62
- it("skips prototype keys", () => {
63
- const base = { a: 1 };
64
- const override = JSON.parse('{"prototype": {"polluted": true}, "b": 2}');
65
- const result = deepMerge(base, override);
66
- expect(result).toEqual({ a: 1, b: 2 });
67
- });
68
- it("skips proto keys in nested objects (recursive defense)", () => {
69
- const base = { nested: { a: 1 } };
70
- const override = JSON.parse('{"nested": {"__proto__": {"polluted": true}, "b": 2}}');
71
- const result = deepMerge(base, override);
72
- expect(result).toEqual({ nested: { a: 1, b: 2 } });
73
- expect(Object.prototype.polluted).toBeUndefined();
74
- });
75
- it("filters all three proto keys simultaneously", () => {
76
- const base = {};
77
- const override = JSON.parse('{"__proto__": {}, "constructor": {}, "prototype": {}, "safe": 1}');
78
- const result = deepMerge(base, override);
79
- expect(Object.keys(result)).toEqual(["safe"]);
80
- expect(result).toEqual({ safe: 1 });
81
- });
82
- });
83
- });
84
- describe("mergeLayered", () => {
85
- it("returns defaults for empty layers", () => {
86
- const result = mergeLayered([]);
87
- expect(result.ok).toBe(true);
88
- if (result.ok) {
89
- expect(result.value.tenantId).toBe("default");
90
- expect(result.value.logLevel).toBe("info");
91
- }
92
- });
93
- it("validates and returns single layer", () => {
94
- const result = mergeLayered([{ tenantId: "single" }]);
95
- expect(result.ok).toBe(true);
96
- if (result.ok) {
97
- expect(result.value.tenantId).toBe("single");
98
- }
99
- });
100
- it("later layers override earlier layers", () => {
101
- const result = mergeLayered([
102
- { tenantId: "first", logLevel: "info" },
103
- { tenantId: "second" },
104
- ]);
105
- expect(result.ok).toBe(true);
106
- if (result.ok) {
107
- expect(result.value.tenantId).toBe("second");
108
- expect(result.value.logLevel).toBe("info");
109
- }
110
- });
111
- it("deep merges nested sections across layers", () => {
112
- const result = mergeLayered([
113
- { agents: { default: { name: "Base", maxSteps: 10 } } },
114
- { agents: { default: { maxSteps: 50 } } },
115
- ]);
116
- expect(result.ok).toBe(true);
117
- if (result.ok) {
118
- expect(result.value.agents.default.name).toBe("Base");
119
- expect(result.value.agents.default.maxSteps).toBe(50);
120
- }
121
- });
122
- it("replaces arrays from later layers", () => {
123
- const result = mergeLayered([
124
- { channels: { telegram: { allowFrom: ["user1", "user2"] } } },
125
- { channels: { telegram: { allowFrom: ["admin"] } } },
126
- ]);
127
- expect(result.ok).toBe(true);
128
- if (result.ok) {
129
- expect(result.value.channels.telegram.allowFrom).toEqual(["admin"]);
130
- }
131
- });
132
- it("returns validation error for invalid merged config", () => {
133
- const result = mergeLayered([{ logLevel: "invalid" }]);
134
- expect(result.ok).toBe(false);
135
- if (!result.ok) {
136
- expect(result.error.code).toBe("VALIDATION_ERROR");
137
- }
138
- });
139
- it("migrates legacy streaming keys before validation", () => {
140
- const result = mergeLayered([{
141
- streaming: {
142
- perChannel: {
143
- test: {
144
- pacingMinMs: 100,
145
- pacingMaxMs: 200,
146
- coalesceMaxChars: 400,
147
- },
148
- },
149
- },
150
- }]);
151
- expect(result.ok).toBe(true);
152
- if (result.ok) {
153
- const testChannel = result.value.streaming.perChannel.test;
154
- expect(testChannel).toBeDefined();
155
- // New nested structure should be present
156
- expect(testChannel.deliveryTiming.minMs).toBe(100);
157
- expect(testChannel.deliveryTiming.maxMs).toBe(200);
158
- expect(testChannel.coalescer.maxChars).toBe(400);
159
- // Old flat keys should NOT be present
160
- expect(testChannel.pacingMinMs).toBeUndefined();
161
- expect(testChannel.pacingMaxMs).toBeUndefined();
162
- expect(testChannel.coalesceMaxChars).toBeUndefined();
163
- }
164
- });
165
- });
166
- describe("loadLayered", () => {
167
- it("loads and merges multiple config files", () => {
168
- const dir = makeTmpDir();
169
- const base = writeYaml(dir, "base.yaml", `
170
- tenantId: base
171
- logLevel: info
172
- agents:
173
- default:
174
- name: BaseBot
175
- maxSteps: 10
176
- `);
177
- const override = writeYaml(dir, "override.yaml", `
178
- tenantId: production
179
- agents:
180
- default:
181
- maxSteps: 50
182
- `);
183
- const result = loadLayered([base, override]);
184
- expect(result.ok).toBe(true);
185
- if (result.ok) {
186
- expect(result.value.tenantId).toBe("production");
187
- expect(result.value.agents.default.name).toBe("BaseBot");
188
- expect(result.value.agents.default.maxSteps).toBe(50);
189
- expect(result.value.logLevel).toBe("info");
190
- }
191
- });
192
- it("returns error if any file is missing", () => {
193
- const dir = makeTmpDir();
194
- const existing = writeYaml(dir, "exists.yaml", "tenantId: ok\n");
195
- const result = loadLayered([existing, "/does/not/exist.yaml"]);
196
- expect(result.ok).toBe(false);
197
- if (!result.ok) {
198
- expect(result.error.code).toBe("FILE_NOT_FOUND");
199
- }
200
- });
201
- it("loads single file successfully", () => {
202
- const dir = makeTmpDir();
203
- const file = writeYaml(dir, "single.yaml", "tenantId: solo\n");
204
- const result = loadLayered([file]);
205
- expect(result.ok).toBe(true);
206
- if (result.ok) {
207
- expect(result.value.tenantId).toBe("solo");
208
- }
209
- });
210
- });
211
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,300 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as os from "node:os";
3
- import * as path from "node:path";
4
- import { describe, it, expect, afterEach } from "vitest";
5
- import { loadConfigFile, validateConfig } from "./loader.js";
6
- describe("config/loader", () => {
7
- const tmpDirs = [];
8
- function makeTmpDir() {
9
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), "comis-config-"));
10
- tmpDirs.push(dir);
11
- return dir;
12
- }
13
- function writeFile(dir, name, content) {
14
- const filePath = path.join(dir, name);
15
- fs.writeFileSync(filePath, content, "utf-8");
16
- return filePath;
17
- }
18
- afterEach(() => {
19
- for (const dir of tmpDirs) {
20
- fs.rmSync(dir, { recursive: true, force: true });
21
- }
22
- tmpDirs.length = 0;
23
- });
24
- describe("loadConfigFile", () => {
25
- it("loads valid YAML config", () => {
26
- const dir = makeTmpDir();
27
- const filePath = writeFile(dir, "config.yaml", `
28
- tenantId: test-tenant
29
- logLevel: debug
30
- agents:
31
- default:
32
- name: TestBot
33
- maxSteps: 10
34
- `);
35
- const result = loadConfigFile(filePath);
36
- expect(result.ok).toBe(true);
37
- if (result.ok) {
38
- expect(result.value.tenantId).toBe("test-tenant");
39
- expect(result.value.logLevel).toBe("debug");
40
- const agents = result.value.agents;
41
- expect(agents.default.name).toBe("TestBot");
42
- }
43
- });
44
- it("loads valid JSON config", () => {
45
- const dir = makeTmpDir();
46
- const filePath = writeFile(dir, "config.json", JSON.stringify({
47
- tenantId: "json-tenant",
48
- logLevel: "warn",
49
- }));
50
- const result = loadConfigFile(filePath);
51
- expect(result.ok).toBe(true);
52
- if (result.ok) {
53
- expect(result.value.tenantId).toBe("json-tenant");
54
- expect(result.value.logLevel).toBe("warn");
55
- }
56
- });
57
- it("returns FILE_NOT_FOUND for non-existent file", () => {
58
- const result = loadConfigFile("/does/not/exist/config.yaml");
59
- expect(result.ok).toBe(false);
60
- if (!result.ok) {
61
- expect(result.error.code).toBe("FILE_NOT_FOUND");
62
- expect(result.error.path).toContain("/does/not/exist/config.yaml");
63
- }
64
- });
65
- it("returns PARSE_ERROR for invalid YAML", () => {
66
- const dir = makeTmpDir();
67
- const filePath = writeFile(dir, "bad.yaml", "{ invalid: yaml: content: [}");
68
- const result = loadConfigFile(filePath);
69
- expect(result.ok).toBe(false);
70
- if (!result.ok) {
71
- expect(result.error.code).toBe("PARSE_ERROR");
72
- }
73
- });
74
- it("returns empty object for empty file", () => {
75
- const dir = makeTmpDir();
76
- const filePath = writeFile(dir, "empty.yaml", "");
77
- const result = loadConfigFile(filePath);
78
- expect(result.ok).toBe(true);
79
- if (result.ok) {
80
- expect(result.value).toEqual({});
81
- }
82
- });
83
- it("returns PARSE_ERROR for array root", () => {
84
- const dir = makeTmpDir();
85
- const filePath = writeFile(dir, "array.yaml", "- one\n- two\n");
86
- const result = loadConfigFile(filePath);
87
- expect(result.ok).toBe(false);
88
- if (!result.ok) {
89
- expect(result.error.code).toBe("PARSE_ERROR");
90
- expect(result.error.message).toContain("array");
91
- }
92
- });
93
- });
94
- describe("validateConfig", () => {
95
- it("validates minimal config with all defaults applied", () => {
96
- const result = validateConfig({});
97
- expect(result.ok).toBe(true);
98
- if (result.ok) {
99
- expect(result.value.tenantId).toBe("default");
100
- expect(result.value.logLevel).toBe("info");
101
- expect(result.value.dataDir).toBe("");
102
- expect(result.value.agents.default.name).toBe("Comis");
103
- expect(result.value.agents.default.model).toBe("default");
104
- expect(result.value.agents.default.maxSteps).toBe(150);
105
- expect(result.value.memory.walMode).toBe(true);
106
- expect(result.value.security.logRedaction).toBe(true);
107
- }
108
- });
109
- it("applies partial overrides with defaults for missing fields", () => {
110
- const result = validateConfig({
111
- tenantId: "custom",
112
- agents: { default: { name: "MyBot" } },
113
- });
114
- expect(result.ok).toBe(true);
115
- if (result.ok) {
116
- expect(result.value.tenantId).toBe("custom");
117
- expect(result.value.agents.default.name).toBe("MyBot");
118
- // Defaults still applied
119
- expect(result.value.agents.default.model).toBe("default");
120
- expect(result.value.logLevel).toBe("info");
121
- }
122
- });
123
- it("rejects invalid log level", () => {
124
- const result = validateConfig({ logLevel: "verbose" });
125
- expect(result.ok).toBe(false);
126
- if (!result.ok) {
127
- expect(result.error.code).toBe("VALIDATION_ERROR");
128
- expect(result.error.message).toContain("logLevel");
129
- }
130
- });
131
- it("rejects invalid types (string where number expected)", () => {
132
- const result = validateConfig({
133
- agents: { default: { maxSteps: "not-a-number" } },
134
- });
135
- expect(result.ok).toBe(false);
136
- if (!result.ok) {
137
- expect(result.error.code).toBe("VALIDATION_ERROR");
138
- }
139
- });
140
- it("rejects unknown top-level fields (strict mode)", () => {
141
- const result = validateConfig({ unknownField: true });
142
- expect(result.ok).toBe(false);
143
- if (!result.ok) {
144
- expect(result.error.code).toBe("VALIDATION_ERROR");
145
- }
146
- });
147
- it("validates full config with all sections", () => {
148
- const result = validateConfig({
149
- tenantId: "acme",
150
- logLevel: "debug",
151
- dataDir: "/var/comis",
152
- agents: {
153
- default: {
154
- name: "AcmeBot",
155
- model: "gpt-4",
156
- provider: "openai",
157
- maxSteps: 50,
158
- budgets: {
159
- perExecution: 50_000,
160
- perHour: 200_000,
161
- perDay: 1_000_000,
162
- },
163
- circuitBreaker: {
164
- failureThreshold: 3,
165
- resetTimeoutMs: 30_000,
166
- halfOpenTimeoutMs: 15_000,
167
- },
168
- },
169
- },
170
- channels: {
171
- telegram: { enabled: true, botToken: "tok123", allowFrom: ["user1"] },
172
- discord: {},
173
- slack: {},
174
- whatsapp: {},
175
- },
176
- memory: {
177
- dbPath: "/var/comis/memory.db",
178
- walMode: true,
179
- embeddingModel: "text-embedding-3-small",
180
- embeddingDimensions: 1536,
181
- compaction: { enabled: true, threshold: 500, targetSize: 250 },
182
- retention: { maxAgeDays: 90, maxEntries: 10_000 },
183
- },
184
- security: {
185
- logRedaction: true,
186
- auditLog: true,
187
- permission: {
188
- enableNodePermissions: true,
189
- allowedFsPaths: ["/var/comis"],
190
- allowedNetHosts: ["api.anthropic.com"],
191
- },
192
- actionConfirmation: {
193
- requireForDestructive: true,
194
- requireForSensitive: true,
195
- autoApprove: ["read_file"],
196
- },
197
- },
198
- });
199
- expect(result.ok).toBe(true);
200
- if (result.ok) {
201
- expect(result.value.tenantId).toBe("acme");
202
- expect(result.value.agents.default.budgets.perExecution).toBe(50_000);
203
- expect(result.value.channels.telegram.enabled).toBe(true);
204
- expect(result.value.memory.compaction.threshold).toBe(500);
205
- expect(result.value.security.permission.enableNodePermissions).toBe(true);
206
- }
207
- });
208
- });
209
- describe("multi-agent config", () => {
210
- it("validates agents: map with per-agent skills", () => {
211
- const result = validateConfig({
212
- agents: {
213
- dash: {
214
- name: "dash",
215
- provider: "anthropic",
216
- model: "claude-sonnet-4-5-20250929",
217
- skills: {
218
- toolPolicy: {
219
- profile: "full",
220
- deny: ["group:platform_actions"],
221
- },
222
- builtinTools: {
223
- read: true,
224
- write: true,
225
- },
226
- },
227
- },
228
- coder: {
229
- name: "coder",
230
- provider: "anthropic",
231
- model: "claude-sonnet-4-5-20250929",
232
- skills: {
233
- toolPolicy: {
234
- profile: "coding",
235
- },
236
- builtinTools: {
237
- read: true,
238
- edit: true,
239
- },
240
- },
241
- },
242
- },
243
- });
244
- expect(result.ok).toBe(true);
245
- if (result.ok) {
246
- expect(result.value.agents.dash.skills?.toolPolicy.profile).toBe("full");
247
- expect(result.value.agents.dash.skills?.toolPolicy.deny).toEqual(["group:platform_actions"]);
248
- expect(result.value.agents.dash.skills?.builtinTools.read).toBe(true);
249
- expect(result.value.agents.coder.skills?.toolPolicy.profile).toBe("coding");
250
- expect(result.value.agents.coder.skills?.builtinTools.read).toBe(true);
251
- expect(result.value.agents.coder.skills?.builtinTools.edit).toBe(true);
252
- }
253
- });
254
- it("per-agent skills block is optional", () => {
255
- const result = validateConfig({
256
- agents: {
257
- withSkills: {
258
- name: "WithSkills",
259
- skills: {
260
- toolPolicy: { profile: "full" },
261
- },
262
- },
263
- withoutSkills: {
264
- name: "WithoutSkills",
265
- },
266
- },
267
- });
268
- expect(result.ok).toBe(true);
269
- if (result.ok) {
270
- expect(result.value.agents.withSkills.skills).toBeDefined();
271
- expect(result.value.agents.withSkills.skills?.toolPolicy.profile).toBe("full");
272
- expect(result.value.agents.withoutSkills.skills).toBeUndefined();
273
- }
274
- });
275
- it("empty config produces default agents map", () => {
276
- const result = validateConfig({});
277
- expect(result.ok).toBe(true);
278
- if (result.ok) {
279
- expect(result.value.agents.default).toBeDefined();
280
- expect(result.value.agents.default.name).toBe("Comis");
281
- expect(result.value.agents.default.model).toBe("default");
282
- expect(result.value.agents.default.provider).toBe("default");
283
- }
284
- });
285
- it("rejects old singular agent: key", () => {
286
- const result = validateConfig({ agent: { name: "TestBot" } });
287
- expect(result.ok).toBe(false);
288
- if (!result.ok) {
289
- expect(result.error.code).toBe("VALIDATION_ERROR");
290
- }
291
- });
292
- it("rejects old global skills: key", () => {
293
- const result = validateConfig({ skills: { toolPolicy: { profile: "full" } } });
294
- expect(result.ok).toBe(false);
295
- if (!result.ok) {
296
- expect(result.error.code).toBe("VALIDATION_ERROR");
297
- }
298
- });
299
- });
300
- });