enya-agent 0.1.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 (389) hide show
  1. package/.env.example +20 -0
  2. package/.github/workflows/ci.yml +70 -0
  3. package/.github/workflows/publish.yml +250 -0
  4. package/.gitmodules +3 -0
  5. package/Cargo.lock +3584 -0
  6. package/Cargo.toml +97 -0
  7. package/crates/enact/Cargo.toml +27 -0
  8. package/crates/enact/src/lib.rs +60 -0
  9. package/crates/enact-a2a/Cargo.toml +25 -0
  10. package/crates/enact-a2a/src/lib.rs +411 -0
  11. package/crates/enact-channels/Cargo.toml +64 -0
  12. package/crates/enact-channels/examples/README.md +80 -0
  13. package/crates/enact-channels/examples/channel_bot.rs +169 -0
  14. package/crates/enact-channels/examples/telegram-echo.rs +34 -0
  15. package/crates/enact-channels/examples/whatsapp-echo.rs +142 -0
  16. package/crates/enact-channels/src/config.rs +213 -0
  17. package/crates/enact-channels/src/lib.rs +25 -0
  18. package/crates/enact-channels/src/runtime.rs +237 -0
  19. package/crates/enact-channels/src/security/mod.rs +5 -0
  20. package/crates/enact-channels/src/security/pairing.rs +205 -0
  21. package/crates/enact-channels/src/teams.rs +601 -0
  22. package/crates/enact-channels/src/telegram.rs +2833 -0
  23. package/crates/enact-channels/src/traits.rs +200 -0
  24. package/crates/enact-channels/src/webhook.rs +262 -0
  25. package/crates/enact-channels/src/whatsapp.rs +310 -0
  26. package/crates/enact-cli/Cargo.toml +40 -0
  27. package/crates/enact-cli/src/commands/doctor.rs +62 -0
  28. package/crates/enact-cli/src/commands/mod.rs +3 -0
  29. package/crates/enact-cli/src/commands/run.rs +69 -0
  30. package/crates/enact-cli/src/commands/serve.rs +81 -0
  31. package/crates/enact-cli/src/config.rs +2 -0
  32. package/crates/enact-cli/src/main.rs +79 -0
  33. package/crates/enact-config/Cargo.toml +36 -0
  34. package/crates/enact-config/ENV_VAR_MAPPING.md +135 -0
  35. package/crates/enact-config/QUICK_REFERENCE.md +92 -0
  36. package/crates/enact-config/README.md +107 -0
  37. package/crates/enact-config/TESTING.md +161 -0
  38. package/crates/enact-config/examples/test-env-vars.rs +100 -0
  39. package/crates/enact-config/src/config.rs +399 -0
  40. package/crates/enact-config/src/encrypted_store.rs +211 -0
  41. package/crates/enact-config/src/lib.rs +298 -0
  42. package/crates/enact-config/src/secrets.rs +149 -0
  43. package/crates/enact-config/src/sync.rs +260 -0
  44. package/crates/enact-config/test-env-vars.sh +34 -0
  45. package/crates/enact-config/tests/README.md +99 -0
  46. package/crates/enact-config/tests/config_integration_test.rs +202 -0
  47. package/crates/enact-config/tests/security_test.rs +140 -0
  48. package/crates/enact-context/Cargo.toml +41 -0
  49. package/crates/enact-context/src/budget.rs +314 -0
  50. package/crates/enact-context/src/calibrator.rs +535 -0
  51. package/crates/enact-context/src/compactor.rs +392 -0
  52. package/crates/enact-context/src/condenser.rs +826 -0
  53. package/crates/enact-context/src/lib.rs +94 -0
  54. package/crates/enact-context/src/segment.rs +238 -0
  55. package/crates/enact-context/src/step_context.rs +645 -0
  56. package/crates/enact-context/src/token_counter.rs +148 -0
  57. package/crates/enact-context/src/window.rs +372 -0
  58. package/crates/enact-core/Cargo.toml +42 -0
  59. package/crates/enact-core/README.md +98 -0
  60. package/crates/enact-core/src/background/executor.rs +524 -0
  61. package/crates/enact-core/src/background/mod.rs +48 -0
  62. package/crates/enact-core/src/background/target_binding.rs +390 -0
  63. package/crates/enact-core/src/background/trigger.rs +511 -0
  64. package/crates/enact-core/src/callable/callable.rs +152 -0
  65. package/crates/enact-core/src/callable/composite.rs +817 -0
  66. package/crates/enact-core/src/callable/graph.rs +104 -0
  67. package/crates/enact-core/src/callable/llm.rs +211 -0
  68. package/crates/enact-core/src/callable/mod.rs +64 -0
  69. package/crates/enact-core/src/callable/registry.rs +206 -0
  70. package/crates/enact-core/src/context/execution_context.rs +757 -0
  71. package/crates/enact-core/src/context/invocation.rs +99 -0
  72. package/crates/enact-core/src/context/mod.rs +50 -0
  73. package/crates/enact-core/src/context/tenant.rs +175 -0
  74. package/crates/enact-core/src/context/trace.rs +127 -0
  75. package/crates/enact-core/src/flow/conditional.rs +293 -0
  76. package/crates/enact-core/src/flow/mod.rs +43 -0
  77. package/crates/enact-core/src/flow/parallel.rs +437 -0
  78. package/crates/enact-core/src/flow/repeat.rs +534 -0
  79. package/crates/enact-core/src/flow/sequential.rs +248 -0
  80. package/crates/enact-core/src/graph/checkpoint.rs +79 -0
  81. package/crates/enact-core/src/graph/checkpoint_store.rs +76 -0
  82. package/crates/enact-core/src/graph/compiled.rs +189 -0
  83. package/crates/enact-core/src/graph/edge.rs +59 -0
  84. package/crates/enact-core/src/graph/graph_schema.rs +218 -0
  85. package/crates/enact-core/src/graph/loader.rs +155 -0
  86. package/crates/enact-core/src/graph/mod.rs +18 -0
  87. package/crates/enact-core/src/graph/node/function.rs +49 -0
  88. package/crates/enact-core/src/graph/node/mod.rs +48 -0
  89. package/crates/enact-core/src/graph/schema.rs +62 -0
  90. package/crates/enact-core/src/inbox/message.rs +405 -0
  91. package/crates/enact-core/src/inbox/mod.rs +31 -0
  92. package/crates/enact-core/src/inbox/store.rs +355 -0
  93. package/crates/enact-core/src/kernel/artifact/filesystem.rs +546 -0
  94. package/crates/enact-core/src/kernel/artifact/metadata.rs +283 -0
  95. package/crates/enact-core/src/kernel/artifact/mod.rs +27 -0
  96. package/crates/enact-core/src/kernel/artifact/store.rs +427 -0
  97. package/crates/enact-core/src/kernel/enforcement.rs +1315 -0
  98. package/crates/enact-core/src/kernel/error.rs +1200 -0
  99. package/crates/enact-core/src/kernel/event.rs +1394 -0
  100. package/crates/enact-core/src/kernel/execution_model.rs +831 -0
  101. package/crates/enact-core/src/kernel/execution_state.rs +189 -0
  102. package/crates/enact-core/src/kernel/execution_strategy.rs +117 -0
  103. package/crates/enact-core/src/kernel/ids.rs +2086 -0
  104. package/crates/enact-core/src/kernel/interrupt.rs +125 -0
  105. package/crates/enact-core/src/kernel/kernel.rs +1283 -0
  106. package/crates/enact-core/src/kernel/mod.rs +205 -0
  107. package/crates/enact-core/src/kernel/persistence/event_store.rs +270 -0
  108. package/crates/enact-core/src/kernel/persistence/message_store.rs +908 -0
  109. package/crates/enact-core/src/kernel/persistence/mod.rs +102 -0
  110. package/crates/enact-core/src/kernel/persistence/state_store.rs +228 -0
  111. package/crates/enact-core/src/kernel/persistence/vector_store.rs +299 -0
  112. package/crates/enact-core/src/kernel/reducer.rs +808 -0
  113. package/crates/enact-core/src/kernel/replay.rs +153 -0
  114. package/crates/enact-core/src/lib.rs +413 -0
  115. package/crates/enact-core/src/memory/episodic.rs +0 -0
  116. package/crates/enact-core/src/memory/mod.rs +6 -0
  117. package/crates/enact-core/src/memory/semantic.rs +0 -0
  118. package/crates/enact-core/src/memory/trait.rs +0 -0
  119. package/crates/enact-core/src/memory/vector_db.rs +0 -0
  120. package/crates/enact-core/src/memory/working.rs +0 -0
  121. package/crates/enact-core/src/policy/execution_policy.rs +292 -0
  122. package/crates/enact-core/src/policy/filters.rs +458 -0
  123. package/crates/enact-core/src/policy/input_processor.rs +407 -0
  124. package/crates/enact-core/src/policy/long_running.rs +134 -0
  125. package/crates/enact-core/src/policy/mod.rs +193 -0
  126. package/crates/enact-core/src/policy/pii_input.rs +274 -0
  127. package/crates/enact-core/src/policy/tenant_policy.rs +453 -0
  128. package/crates/enact-core/src/policy/tool_policy.rs +407 -0
  129. package/crates/enact-core/src/providers/mod.rs +63 -0
  130. package/crates/enact-core/src/providers/trait.rs +292 -0
  131. package/crates/enact-core/src/runner/callbacks.rs +6 -0
  132. package/crates/enact-core/src/runner/execution_runner.rs +476 -0
  133. package/crates/enact-core/src/runner/loop.rs +117 -0
  134. package/crates/enact-core/src/runner/mod.rs +58 -0
  135. package/crates/enact-core/src/runner/protected_runner.rs +280 -0
  136. package/crates/enact-core/src/signal/inmemory.rs +231 -0
  137. package/crates/enact-core/src/signal/mod.rs +108 -0
  138. package/crates/enact-core/src/streaming/event_logger.rs +195 -0
  139. package/crates/enact-core/src/streaming/event_stream.rs +1423 -0
  140. package/crates/enact-core/src/streaming/mod.rs +108 -0
  141. package/crates/enact-core/src/streaming/pause_cancel.rs +0 -0
  142. package/crates/enact-core/src/streaming/protected_emitter.rs +173 -0
  143. package/crates/enact-core/src/streaming/protection/context.rs +136 -0
  144. package/crates/enact-core/src/streaming/protection/encryption.rs +289 -0
  145. package/crates/enact-core/src/streaming/protection/mod.rs +43 -0
  146. package/crates/enact-core/src/streaming/protection/pii_protection.rs +243 -0
  147. package/crates/enact-core/src/streaming/protection/processor.rs +166 -0
  148. package/crates/enact-core/src/streaming/sse.rs +0 -0
  149. package/crates/enact-core/src/telemetry/exporter.rs +0 -0
  150. package/crates/enact-core/src/telemetry/init.rs +0 -0
  151. package/crates/enact-core/src/telemetry/mod.rs +49 -0
  152. package/crates/enact-core/src/telemetry/spans.rs +245 -0
  153. package/crates/enact-core/src/tool/agent_tool.rs +177 -0
  154. package/crates/enact-core/src/tool/browser/mod.rs +0 -0
  155. package/crates/enact-core/src/tool/browser/webdriver.rs +0 -0
  156. package/crates/enact-core/src/tool/cost.rs +247 -0
  157. package/crates/enact-core/src/tool/discovery.rs +0 -0
  158. package/crates/enact-core/src/tool/dispatcher.rs +347 -0
  159. package/crates/enact-core/src/tool/filesystem.rs +231 -0
  160. package/crates/enact-core/src/tool/function.rs +99 -0
  161. package/crates/enact-core/src/tool/git.rs +162 -0
  162. package/crates/enact-core/src/tool/http.rs +214 -0
  163. package/crates/enact-core/src/tool/mcp/client.rs +0 -0
  164. package/crates/enact-core/src/tool/mcp/mod.rs +0 -0
  165. package/crates/enact-core/src/tool/mod.rs +51 -0
  166. package/crates/enact-core/src/tool/reasoning/debugging.rs +0 -0
  167. package/crates/enact-core/src/tool/reasoning/mcts.rs +0 -0
  168. package/crates/enact-core/src/tool/reasoning/mod.rs +0 -0
  169. package/crates/enact-core/src/tool/reasoning/sequential.rs +0 -0
  170. package/crates/enact-core/src/tool/sandbox/dagger.rs +0 -0
  171. package/crates/enact-core/src/tool/sandbox/mod.rs +0 -0
  172. package/crates/enact-core/src/tool/shell.rs +147 -0
  173. package/crates/enact-core/src/tool/trait.rs +33 -0
  174. package/crates/enact-core/src/tool/web_search.rs +277 -0
  175. package/crates/enact-core/src/util/config.rs +0 -0
  176. package/crates/enact-core/src/util/errors.rs +0 -0
  177. package/crates/enact-core/src/util/mod.rs +6 -0
  178. package/crates/enact-core/tests/airgapped_e2e_test.rs +291 -0
  179. package/crates/enact-core/tests/e2e_agentic_loop.rs +119 -0
  180. package/crates/enact-core/tests/e2e_test.rs +259 -0
  181. package/crates/enact-core/tests/graph_test.rs +130 -0
  182. package/crates/enact-core/tests/stream_event_id_validation.rs +435 -0
  183. package/crates/enact-cron/Cargo.toml +28 -0
  184. package/crates/enact-cron/src/lib.rs +44 -0
  185. package/crates/enact-cron/src/schedule.rs +156 -0
  186. package/crates/enact-cron/src/store.rs +589 -0
  187. package/crates/enact-cron/src/types.rs +148 -0
  188. package/crates/enact-gateway/Cargo.toml +31 -0
  189. package/crates/enact-gateway/README.md +30 -0
  190. package/crates/enact-gateway/examples/whatsapp-gateway-runner-mock.rs +59 -0
  191. package/crates/enact-gateway/examples/whatsapp-gateway.rs +42 -0
  192. package/crates/enact-gateway/src/lib.rs +582 -0
  193. package/crates/enact-mcp/Cargo.toml +24 -0
  194. package/crates/enact-mcp/src/lib.rs +178 -0
  195. package/crates/enact-memory/Cargo.toml +25 -0
  196. package/crates/enact-memory/src/backend.rs +20 -0
  197. package/crates/enact-memory/src/chunker.rs +230 -0
  198. package/crates/enact-memory/src/embeddings.rs +221 -0
  199. package/crates/enact-memory/src/lib.rs +67 -0
  200. package/crates/enact-memory/src/markdown.rs +127 -0
  201. package/crates/enact-memory/src/none.rs +61 -0
  202. package/crates/enact-memory/src/sqlite.rs +276 -0
  203. package/crates/enact-memory/src/traits.rs +65 -0
  204. package/crates/enact-memory/src/vector.rs +198 -0
  205. package/crates/enact-oauth/Cargo.toml +27 -0
  206. package/crates/enact-oauth/src/lib.rs +584 -0
  207. package/crates/enact-observability/Cargo.toml +22 -0
  208. package/crates/enact-observability/src/lib.rs +197 -0
  209. package/crates/enact-providers/Cargo.toml +33 -0
  210. package/crates/enact-providers/examples/hello-agent.rs +33 -0
  211. package/crates/enact-providers/src/anthropic.rs +182 -0
  212. package/crates/enact-providers/src/azure.rs +96 -0
  213. package/crates/enact-providers/src/bridge.rs +221 -0
  214. package/crates/enact-providers/src/gemini.rs +227 -0
  215. package/crates/enact-providers/src/http.rs +78 -0
  216. package/crates/enact-providers/src/lib.rs +53 -0
  217. package/crates/enact-providers/src/openai_compatible.rs +167 -0
  218. package/crates/enact-providers/src/openrouter.rs +33 -0
  219. package/crates/enact-runner/Cargo.toml +24 -0
  220. package/crates/enact-runner/README.md +76 -0
  221. package/crates/enact-runner/src/compaction.rs +225 -0
  222. package/crates/enact-runner/src/config.rs +118 -0
  223. package/crates/enact-runner/src/lib.rs +63 -0
  224. package/crates/enact-runner/src/loop_driver.rs +414 -0
  225. package/crates/enact-runner/src/parser.rs +421 -0
  226. package/crates/enact-runner/src/retry.rs +262 -0
  227. package/crates/enact-runner/tests/integration.rs +278 -0
  228. package/crates/enact-security/Cargo.toml +22 -0
  229. package/crates/enact-security/src/audit.rs +375 -0
  230. package/crates/enact-security/src/lib.rs +37 -0
  231. package/crates/enact-security/src/policy.rs +406 -0
  232. package/crates/enact-skills/Cargo.toml +25 -0
  233. package/crates/enact-skills/src/lib.rs +506 -0
  234. package/crates/enact-tools/Cargo.toml +22 -0
  235. package/crates/enact-tools/src/file_read.rs +166 -0
  236. package/crates/enact-tools/src/file_write.rs +216 -0
  237. package/crates/enact-tools/src/git_operations.rs +513 -0
  238. package/crates/enact-tools/src/http_request.rs +417 -0
  239. package/crates/enact-tools/src/lib.rs +104 -0
  240. package/crates/enact-tools/src/security.rs +227 -0
  241. package/crates/enact-tools/src/shell.rs +191 -0
  242. package/crates/enact-tools/src/traits.rs +159 -0
  243. package/docs/Makefile +74 -0
  244. package/docs/config.toml +62 -0
  245. package/docs/content/_index.md +174 -0
  246. package/docs/content/a2a/_index.md +431 -0
  247. package/docs/content/api/_index.md +323 -0
  248. package/docs/content/channels/_index.md +160 -0
  249. package/docs/content/channels/teams.md +205 -0
  250. package/docs/content/channels/telegram.md +182 -0
  251. package/docs/content/channels/webhook.md +423 -0
  252. package/docs/content/channels/whatsapp.md +240 -0
  253. package/docs/content/cli/_index.md +261 -0
  254. package/docs/content/concepts/_index.md +273 -0
  255. package/docs/content/configuration/_index.md +241 -0
  256. package/docs/content/cron/_index.md +248 -0
  257. package/docs/content/developers/_index.md +278 -0
  258. package/docs/content/getting-started/_index.md +180 -0
  259. package/docs/content/installation/_index.md +186 -0
  260. package/docs/content/installation/uninstall.md +101 -0
  261. package/docs/content/installation/updating.md +120 -0
  262. package/docs/content/mcp/_index.md +215 -0
  263. package/docs/content/memory/_index.md +163 -0
  264. package/docs/content/oauth/_index.md +515 -0
  265. package/docs/content/providers/_index.md +206 -0
  266. package/docs/content/roadmap/_index.md +199 -0
  267. package/docs/content/security/_index.md +219 -0
  268. package/docs/content/skills/_index.md +228 -0
  269. package/docs/content/tools/_index.md +485 -0
  270. package/docs/content/troubleshooting/_index.md +259 -0
  271. package/docs/content/yaml-schema/_index.md +294 -0
  272. package/docs/static/giallo-dark.css +91 -0
  273. package/docs/static/giallo-light.css +91 -0
  274. package/docs/themes/tanuki/.github/workflows/deploy.yml +44 -0
  275. package/docs/themes/tanuki/LICENSE +21 -0
  276. package/docs/themes/tanuki/README.md +166 -0
  277. package/docs/themes/tanuki/examples/blog/config.toml +58 -0
  278. package/docs/themes/tanuki/examples/blog/content/_index.md +4 -0
  279. package/docs/themes/tanuki/examples/blog/content/about.md +33 -0
  280. package/docs/themes/tanuki/examples/blog/content/blog/_index.md +7 -0
  281. package/docs/themes/tanuki/examples/blog/content/blog/api-design-best-practices.md +245 -0
  282. package/docs/themes/tanuki/examples/blog/content/blog/building-accessible-websites.md +147 -0
  283. package/docs/themes/tanuki/examples/blog/content/blog/css-grid-vs-flexbox.md +165 -0
  284. package/docs/themes/tanuki/examples/blog/content/blog/customizing-catppuccin-colors.md +137 -0
  285. package/docs/themes/tanuki/examples/blog/content/blog/dark-mode-best-practices.md +82 -0
  286. package/docs/themes/tanuki/examples/blog/content/blog/docker-essentials.md +301 -0
  287. package/docs/themes/tanuki/examples/blog/content/blog/getting-started-with-zola.md +129 -0
  288. package/docs/themes/tanuki/examples/blog/content/blog/git-workflow-for-content.md +112 -0
  289. package/docs/themes/tanuki/examples/blog/content/blog/introduction-to-webassembly.md +183 -0
  290. package/docs/themes/tanuki/examples/blog/content/blog/modern-javascript-features.md +234 -0
  291. package/docs/themes/tanuki/examples/blog/content/blog/testing-strategies.md +311 -0
  292. package/docs/themes/tanuki/examples/blog/content/blog/typography-for-developers.md +104 -0
  293. package/docs/themes/tanuki/examples/blog/content/blog/welcome-to-tanuki.md +67 -0
  294. package/docs/themes/tanuki/examples/blog/content/blog/why-static-sites.md +85 -0
  295. package/docs/themes/tanuki/examples/blog/content/projects.md +64 -0
  296. package/docs/themes/tanuki/examples/book/config.toml +17 -0
  297. package/docs/themes/tanuki/examples/book/content/_index.md +12 -0
  298. package/docs/themes/tanuki/examples/book/content/chapter-1.md +90 -0
  299. package/docs/themes/tanuki/examples/book/content/chapter-2.md +143 -0
  300. package/docs/themes/tanuki/examples/book/content/chapter-3.md +217 -0
  301. package/docs/themes/tanuki/examples/book/content/chapter-4.md +224 -0
  302. package/docs/themes/tanuki/examples/book/content/chapter-5.md +297 -0
  303. package/docs/themes/tanuki/examples/book/content/print.md +6 -0
  304. package/docs/themes/tanuki/examples/docs/config.toml +28 -0
  305. package/docs/themes/tanuki/examples/docs/content/_index.md +20 -0
  306. package/docs/themes/tanuki/examples/docs/content/components.md +156 -0
  307. package/docs/themes/tanuki/examples/docs/content/configuration.md +94 -0
  308. package/docs/themes/tanuki/examples/docs/content/customization.md +202 -0
  309. package/docs/themes/tanuki/examples/docs/content/deployment.md +204 -0
  310. package/docs/themes/tanuki/examples/docs/content/installation.md +59 -0
  311. package/docs/themes/tanuki/examples/docs/content/print.md +6 -0
  312. package/docs/themes/tanuki/examples/docs/static/img/tanuki-icon.avif +0 -0
  313. package/docs/themes/tanuki/examples/index.html +2104 -0
  314. package/docs/themes/tanuki/mise.toml +108 -0
  315. package/docs/themes/tanuki/sass/base/_catppuccin.scss +164 -0
  316. package/docs/themes/tanuki/sass/base/_fonts.scss +64 -0
  317. package/docs/themes/tanuki/sass/base/_reset.scss +152 -0
  318. package/docs/themes/tanuki/sass/base/_typography.scss +523 -0
  319. package/docs/themes/tanuki/sass/components/_buttons.scss +209 -0
  320. package/docs/themes/tanuki/sass/components/_code.scss +457 -0
  321. package/docs/themes/tanuki/sass/components/_landing.scss +633 -0
  322. package/docs/themes/tanuki/sass/components/_layout.scss +294 -0
  323. package/docs/themes/tanuki/sass/components/_navigation.scss +1200 -0
  324. package/docs/themes/tanuki/sass/components/_print.scss +237 -0
  325. package/docs/themes/tanuki/sass/components/_search.scss +224 -0
  326. package/docs/themes/tanuki/sass/components/_sidebar.scss +473 -0
  327. package/docs/themes/tanuki/sass/components/_theme-toggle.scss +186 -0
  328. package/docs/themes/tanuki/sass/modes/_blog.scss +366 -0
  329. package/docs/themes/tanuki/sass/modes/_product.scss +875 -0
  330. package/docs/themes/tanuki/sass/modes/_raskell.scss +1696 -0
  331. package/docs/themes/tanuki/sass/patterns/_buttons.scss +183 -0
  332. package/docs/themes/tanuki/sass/patterns/_cards.scss +144 -0
  333. package/docs/themes/tanuki/sass/patterns/_index.scss +9 -0
  334. package/docs/themes/tanuki/sass/patterns/_lists.scss +259 -0
  335. package/docs/themes/tanuki/sass/patterns/_sections.scss +243 -0
  336. package/docs/themes/tanuki/sass/style.scss +47 -0
  337. package/docs/themes/tanuki/sass/tokens/_colors.scss +139 -0
  338. package/docs/themes/tanuki/sass/tokens/_spacing.scss +100 -0
  339. package/docs/themes/tanuki/sass/tokens/_typography.scss +186 -0
  340. package/docs/themes/tanuki/screenshot.png +0 -0
  341. package/docs/themes/tanuki/sentinel.kdl +59 -0
  342. package/docs/themes/tanuki/static/elasticlunr.min.js +10 -0
  343. package/docs/themes/tanuki/static/fonts/GEIST-LICENSE.txt +92 -0
  344. package/docs/themes/tanuki/static/fonts/Geist-Variable.woff2 +0 -0
  345. package/docs/themes/tanuki/static/fonts/GeistMono-Variable.woff2 +0 -0
  346. package/docs/themes/tanuki/static/img/tanuki-icon.avif +0 -0
  347. package/docs/themes/tanuki/static/img/tanuki-icon.png +0 -0
  348. package/docs/themes/tanuki/static/js/anchors.js +18 -0
  349. package/docs/themes/tanuki/static/js/app.js +274 -0
  350. package/docs/themes/tanuki/static/js/code.js +394 -0
  351. package/docs/themes/tanuki/static/js/navigation.js +778 -0
  352. package/docs/themes/tanuki/static/js/scroll-to-top.js +33 -0
  353. package/docs/themes/tanuki/static/js/search-raskell.js +240 -0
  354. package/docs/themes/tanuki/static/js/search.js +215 -0
  355. package/docs/themes/tanuki/static/js/theme.js +169 -0
  356. package/docs/themes/tanuki/static/syntax-dark.css +151 -0
  357. package/docs/themes/tanuki/static/syntax-light.css +151 -0
  358. package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm.js +486 -0
  359. package/docs/themes/tanuki/static/wasm/sentinel_playground_wasm_bg.wasm +0 -0
  360. package/docs/themes/tanuki/templates/404.html +52 -0
  361. package/docs/themes/tanuki/templates/base.html +428 -0
  362. package/docs/themes/tanuki/templates/blog.html +66 -0
  363. package/docs/themes/tanuki/templates/home.html +108 -0
  364. package/docs/themes/tanuki/templates/index.html +178 -0
  365. package/docs/themes/tanuki/templates/landing.html +168 -0
  366. package/docs/themes/tanuki/templates/macros/nav.html +128 -0
  367. package/docs/themes/tanuki/templates/macros/posts.html +101 -0
  368. package/docs/themes/tanuki/templates/macros/ui.html +159 -0
  369. package/docs/themes/tanuki/templates/page.html +135 -0
  370. package/docs/themes/tanuki/templates/partials/footer.html +38 -0
  371. package/docs/themes/tanuki/templates/partials/header.html +366 -0
  372. package/docs/themes/tanuki/templates/partials/nav-buttons.html +55 -0
  373. package/docs/themes/tanuki/templates/partials/nav-overlay.html +81 -0
  374. package/docs/themes/tanuki/templates/partials/page-toc-panel.html +43 -0
  375. package/docs/themes/tanuki/templates/partials/search.html +52 -0
  376. package/docs/themes/tanuki/templates/partials/sidebar.html +107 -0
  377. package/docs/themes/tanuki/templates/partials/theme-toggle.html +35 -0
  378. package/docs/themes/tanuki/templates/partials/toc-overlay.html +146 -0
  379. package/docs/themes/tanuki/templates/partials/version-picker.html +38 -0
  380. package/docs/themes/tanuki/templates/print.html +244 -0
  381. package/docs/themes/tanuki/templates/section.html +186 -0
  382. package/docs/themes/tanuki/templates/taxonomy_list.html +18 -0
  383. package/docs/themes/tanuki/templates/taxonomy_single.html +31 -0
  384. package/docs/themes/tanuki/theme.toml +58 -0
  385. package/examples/hello-agent.rs +55 -0
  386. package/package.json +36 -0
  387. package/proto/config.proto +60 -0
  388. package/proto/events.proto +0 -0
  389. package/proto/runtime.proto +215 -0
@@ -0,0 +1,399 @@
1
+ //! Configuration Types - Core configuration structure
2
+ //!
3
+ //! This module defines the configuration structure that matches the TypeScript schema.
4
+ //! It's kept in sync with packages/enact-schemas/src/config.schemas.ts
5
+
6
+ use serde::{Deserialize, Serialize};
7
+
8
+ /// Runtime mode
9
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
10
+ pub enum RuntimeMode {
11
+ #[default]
12
+ #[serde(rename = "local")]
13
+ Local,
14
+ #[serde(rename = "airgapped")]
15
+ AirGapped,
16
+ #[serde(rename = "cloud")]
17
+ Cloud,
18
+ }
19
+
20
+ impl RuntimeMode {
21
+ /// Parse a runtime mode string into the enum (defaults to Local)
22
+ pub fn from_str(value: &str) -> Self {
23
+ match value.to_ascii_lowercase().as_str() {
24
+ "airgapped" => RuntimeMode::AirGapped,
25
+ "cloud" => RuntimeMode::Cloud,
26
+ _ => RuntimeMode::Local,
27
+ }
28
+ }
29
+ }
30
+
31
+
32
+ impl ToString for RuntimeMode {
33
+ fn to_string(&self) -> String {
34
+ match self {
35
+ RuntimeMode::Local => "local".to_string(),
36
+ RuntimeMode::AirGapped => "airgapped".to_string(),
37
+ RuntimeMode::Cloud => "cloud".to_string(),
38
+ }
39
+ }
40
+ }
41
+
42
+ /// Provider configuration
43
+ #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
44
+ pub struct Providers {
45
+ pub azure: Option<AzureProvider>,
46
+ pub anthropic: Option<AnthropicProvider>,
47
+ pub openai: Option<OpenAIProvider>,
48
+ pub ollama: Option<OllamaProvider>,
49
+ pub google: Option<GoogleProvider>,
50
+ }
51
+
52
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
53
+ pub struct AzureProvider {
54
+ pub endpoint: Option<String>,
55
+ pub api_key: Option<String>,
56
+ pub deployment_name: Option<String>,
57
+ #[serde(default = "default_api_version")]
58
+ pub api_version: String,
59
+ }
60
+
61
+ fn default_api_version() -> String {
62
+ "2024-02-15-preview".to_string()
63
+ }
64
+
65
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
66
+ pub struct AnthropicProvider {
67
+ pub api_key: Option<String>,
68
+ #[serde(default = "default_anthropic_base_url")]
69
+ pub base_url: String,
70
+ }
71
+
72
+ fn default_anthropic_base_url() -> String {
73
+ "https://api.anthropic.com".to_string()
74
+ }
75
+
76
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
77
+ pub struct OpenAIProvider {
78
+ pub api_key: Option<String>,
79
+ #[serde(default = "default_openai_base_url")]
80
+ pub base_url: String,
81
+ pub organization: Option<String>,
82
+ }
83
+
84
+ fn default_openai_base_url() -> String {
85
+ "https://api.openai.com/v1".to_string()
86
+ }
87
+
88
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
89
+ pub struct OllamaProvider {
90
+ #[serde(default = "default_ollama_base_url")]
91
+ pub base_url: String,
92
+ }
93
+
94
+ fn default_ollama_base_url() -> String {
95
+ "http://localhost:11434".to_string()
96
+ }
97
+
98
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
99
+ pub struct GoogleProvider {
100
+ pub api_key: Option<String>,
101
+ #[serde(default = "default_google_base_url")]
102
+ pub base_url: String,
103
+ }
104
+
105
+ fn default_google_base_url() -> String {
106
+ "https://generativelanguage.googleapis.com/v1".to_string()
107
+ }
108
+
109
+ /// Runtime configuration
110
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
111
+ pub struct Runtime {
112
+ #[serde(default)]
113
+ pub mode: RuntimeMode,
114
+ #[serde(default = "default_max_concurrent")]
115
+ pub max_concurrent_executions: u32,
116
+ #[serde(default = "default_timeout")]
117
+ pub default_timeout: u64,
118
+ #[serde(default = "default_true")]
119
+ pub enable_telemetry: bool,
120
+ #[serde(default = "default_true")]
121
+ pub allow_network: bool,
122
+ }
123
+
124
+ fn default_max_concurrent() -> u32 {
125
+ 10
126
+ }
127
+
128
+ fn default_timeout() -> u64 {
129
+ 30000
130
+ }
131
+
132
+ fn default_true() -> bool {
133
+ true
134
+ }
135
+
136
+ impl Default for Runtime {
137
+ fn default() -> Self {
138
+ Self {
139
+ mode: RuntimeMode::Local,
140
+ max_concurrent_executions: 10,
141
+ default_timeout: 30000,
142
+ enable_telemetry: true,
143
+ allow_network: true,
144
+ }
145
+ }
146
+ }
147
+
148
+ /// Storage configuration
149
+ #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
150
+ pub struct Storage {
151
+ #[serde(default = "default_event_store")]
152
+ pub event_store: EventStore,
153
+ #[serde(default = "default_state_store")]
154
+ pub state_store: StateStore,
155
+ #[serde(default = "default_filesystem_store")]
156
+ pub artifact_store: ArtifactStore,
157
+ #[serde(default = "default_sqlite_vector_store")]
158
+ pub vector_store: VectorStore,
159
+ }
160
+
161
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
162
+ pub struct EventStore {
163
+ #[serde(default = "default_sqlite")]
164
+ pub r#type: String,
165
+ pub path: Option<String>,
166
+ pub dsn: Option<String>,
167
+ }
168
+
169
+ fn default_sqlite() -> String {
170
+ "sqlite".to_string()
171
+ }
172
+
173
+ impl Default for EventStore {
174
+ fn default() -> Self {
175
+ Self {
176
+ r#type: "sqlite".to_string(),
177
+ path: None,
178
+ dsn: None,
179
+ }
180
+ }
181
+ }
182
+
183
+ fn default_event_store() -> EventStore {
184
+ EventStore::default()
185
+ }
186
+
187
+ impl Default for StateStore {
188
+ fn default() -> Self {
189
+ Self {
190
+ r#type: "sqlite".to_string(),
191
+ path: None,
192
+ dsn: None,
193
+ }
194
+ }
195
+ }
196
+
197
+ fn default_state_store() -> StateStore {
198
+ StateStore::default()
199
+ }
200
+
201
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
202
+ pub struct StateStore {
203
+ #[serde(default = "default_sqlite")]
204
+ pub r#type: String,
205
+ pub path: Option<String>,
206
+ pub dsn: Option<String>,
207
+ }
208
+
209
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
210
+ pub struct ArtifactStore {
211
+ #[serde(default = "default_filesystem")]
212
+ pub r#type: String,
213
+ pub path: Option<String>,
214
+ #[serde(default = "default_zstd")]
215
+ pub compression: String,
216
+ }
217
+
218
+ fn default_filesystem() -> String {
219
+ "filesystem".to_string()
220
+ }
221
+
222
+ fn default_zstd() -> String {
223
+ "zstd".to_string()
224
+ }
225
+
226
+ impl Default for ArtifactStore {
227
+ fn default() -> Self {
228
+ Self {
229
+ r#type: "filesystem".to_string(),
230
+ path: None,
231
+ compression: "zstd".to_string(),
232
+ }
233
+ }
234
+ }
235
+
236
+ fn default_filesystem_store() -> ArtifactStore {
237
+ ArtifactStore::default()
238
+ }
239
+
240
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
241
+ pub struct VectorStore {
242
+ #[serde(default = "default_sqlite")]
243
+ pub r#type: String,
244
+ pub url: Option<String>,
245
+ pub collection: Option<String>,
246
+ pub path: Option<String>,
247
+ pub dsn: Option<String>,
248
+ }
249
+
250
+ impl Default for VectorStore {
251
+ fn default() -> Self {
252
+ Self {
253
+ r#type: "sqlite".to_string(),
254
+ url: None,
255
+ collection: None,
256
+ path: None,
257
+ dsn: None,
258
+ }
259
+ }
260
+ }
261
+
262
+ fn default_sqlite_vector_store() -> VectorStore {
263
+ VectorStore::default()
264
+ }
265
+
266
+ /// Tools configuration
267
+ #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
268
+ pub struct Tools {
269
+ #[serde(default)]
270
+ pub ingestion: IngestionTools,
271
+ }
272
+
273
+ #[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
274
+ pub struct IngestionTools {
275
+ #[serde(default = "default_pdf")]
276
+ pub pdf: PdfIngestion,
277
+ #[serde(default = "default_ocr")]
278
+ pub ocr: OcrIngestion,
279
+ #[serde(default = "default_embeddings")]
280
+ pub embeddings: EmbeddingsIngestion,
281
+ }
282
+
283
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
284
+ pub struct PdfIngestion {
285
+ #[serde(default = "default_pdfium")]
286
+ pub engine: String,
287
+ }
288
+
289
+ impl Default for PdfIngestion {
290
+ fn default() -> Self {
291
+ Self {
292
+ engine: "pdfium".to_string(),
293
+ }
294
+ }
295
+ }
296
+
297
+ fn default_pdfium() -> String {
298
+ "pdfium".to_string()
299
+ }
300
+
301
+ fn default_pdf() -> PdfIngestion {
302
+ PdfIngestion {
303
+ engine: "pdfium".to_string(),
304
+ }
305
+ }
306
+
307
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
308
+ pub struct OcrIngestion {
309
+ #[serde(default = "default_tesseract")]
310
+ pub engine: String,
311
+ #[serde(default = "default_languages")]
312
+ pub languages: Vec<String>,
313
+ }
314
+
315
+ impl Default for OcrIngestion {
316
+ fn default() -> Self {
317
+ Self {
318
+ engine: "tesseract".to_string(),
319
+ languages: vec!["eng".to_string()],
320
+ }
321
+ }
322
+ }
323
+
324
+ fn default_tesseract() -> String {
325
+ "tesseract".to_string()
326
+ }
327
+
328
+ fn default_languages() -> Vec<String> {
329
+ vec!["eng".to_string()]
330
+ }
331
+
332
+ fn default_ocr() -> OcrIngestion {
333
+ OcrIngestion {
334
+ engine: "tesseract".to_string(),
335
+ languages: vec!["eng".to_string()],
336
+ }
337
+ }
338
+
339
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
340
+ pub struct EmbeddingsIngestion {
341
+ #[serde(default = "default_fastembed")]
342
+ pub engine: String,
343
+ pub model: Option<String>,
344
+ }
345
+
346
+ impl Default for EmbeddingsIngestion {
347
+ fn default() -> Self {
348
+ Self {
349
+ engine: "fastembed".to_string(),
350
+ model: None,
351
+ }
352
+ }
353
+ }
354
+
355
+ fn default_fastembed() -> String {
356
+ "fastembed".to_string()
357
+ }
358
+
359
+ fn default_embeddings() -> EmbeddingsIngestion {
360
+ EmbeddingsIngestion {
361
+ engine: "fastembed".to_string(),
362
+ model: None,
363
+ }
364
+ }
365
+
366
+ /// Cloud configuration
367
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
368
+ pub struct Cloud {
369
+ pub api_url: Option<String>,
370
+ pub tenant_id: Option<String>,
371
+ #[serde(default)]
372
+ pub auto_sync: bool,
373
+ }
374
+
375
+ /// Main configuration structure
376
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
377
+ pub struct Config {
378
+ #[serde(default)]
379
+ pub providers: Providers,
380
+ #[serde(default)]
381
+ pub runtime: Runtime,
382
+ #[serde(default)]
383
+ pub storage: Storage,
384
+ #[serde(default)]
385
+ pub tools: Tools,
386
+ pub cloud: Option<Cloud>,
387
+ }
388
+
389
+ impl Default for Config {
390
+ fn default() -> Self {
391
+ Self {
392
+ providers: Providers::default(),
393
+ runtime: Runtime::default(),
394
+ storage: Storage::default(),
395
+ tools: Tools::default(),
396
+ cloud: None,
397
+ }
398
+ }
399
+ }
@@ -0,0 +1,211 @@
1
+ //! Encrypted File Storage - Secure storage for non-sensitive settings
2
+ //!
3
+ //! Stores configuration in an encrypted file using AES-256-GCM.
4
+ //! The encryption key is derived from environment variables.
5
+
6
+ use aes_gcm::{
7
+ aead::{Aead, AeadCore, KeyInit, OsRng},
8
+ Aes256Gcm, Key, Nonce,
9
+ };
10
+ use anyhow::{Context, Result};
11
+ use serde::{Deserialize, Serialize};
12
+ use std::{
13
+ fs,
14
+ path::{Path, PathBuf},
15
+ };
16
+ use tracing::debug;
17
+
18
+ use crate::secrets::SecretManager;
19
+
20
+ const ENCRYPTION_KEY_NAME: &str = "enact.config.encryption_key";
21
+ const NONCE_SIZE: usize = 12; // 96 bits for GCM
22
+
23
+ /// Encrypted configuration store
24
+ pub struct EncryptedStore {
25
+ config_path: PathBuf,
26
+ secrets: SecretManager,
27
+ }
28
+
29
+ #[derive(Debug, Serialize, Deserialize)]
30
+ struct EncryptedData {
31
+ nonce: Vec<u8>,
32
+ ciphertext: Vec<u8>,
33
+ }
34
+
35
+ impl EncryptedStore {
36
+ /// Create a new encrypted store
37
+ ///
38
+ /// # Arguments
39
+ /// * `config_path` - Path to the encrypted config file
40
+ pub fn new(config_path: impl AsRef<Path>) -> Result<Self> {
41
+ // Always use SecretManager
42
+ let secrets = SecretManager::new();
43
+ Self::with_secrets(config_path, secrets)
44
+ }
45
+
46
+ /// Create a new encrypted store with a specific secret manager
47
+ ///
48
+ /// # Arguments
49
+ /// * `config_path` - Path to the encrypted config file
50
+ /// * `secrets` - Secret manager to use
51
+ pub fn with_secrets(config_path: impl AsRef<Path>, secrets: SecretManager) -> Result<Self> {
52
+ let config_path = config_path.as_ref().to_path_buf();
53
+
54
+ // Ensure parent directory exists
55
+ if let Some(parent) = config_path.parent() {
56
+ fs::create_dir_all(parent).context("Failed to create config directory")?;
57
+ }
58
+
59
+ Ok(Self {
60
+ config_path,
61
+ secrets,
62
+ })
63
+ }
64
+
65
+ /// Get or create the encryption key
66
+ fn get_encryption_key(&self) -> Result<Key<Aes256Gcm>> {
67
+ // Try to get existing key from environment
68
+ if let Some(key_str) = self.secrets.get(ENCRYPTION_KEY_NAME)? {
69
+ // Decode hex string to key
70
+ let key_bytes = hex::decode(&key_str).context("Failed to decode encryption key")?;
71
+ if key_bytes.len() == 32 {
72
+ return Ok(*Key::<Aes256Gcm>::from_slice(&key_bytes));
73
+ }
74
+ }
75
+
76
+ // Generate new key if not found
77
+ // Since we can't persist it to .env automatically, we must warn the user
78
+ let key = Aes256Gcm::generate_key(&mut OsRng);
79
+ let key_hex = hex::encode(key.as_slice());
80
+
81
+ // Try to store in secrets (works if mock store, fails/warns if .env)
82
+ if let Err(_) = self.secrets.set(ENCRYPTION_KEY_NAME, &key_hex) {
83
+ eprintln!("⚠️ WARNING: No encryption key found in environment.");
84
+ eprintln!(" Generated temporary key: {}", key_hex);
85
+ eprintln!(
86
+ " Set ENACT_CONFIG_ENCRYPTION_KEY={} in your .env file to persist configuration.",
87
+ key_hex
88
+ );
89
+ } else {
90
+ debug!("Generated and stored new encryption key (mock)");
91
+ }
92
+
93
+ debug!("Using generated encryption key");
94
+ Ok(key)
95
+ }
96
+
97
+ /// Encrypt and store configuration
98
+ ///
99
+ /// # Arguments
100
+ /// * `config` - The configuration to store (as JSON string)
101
+ pub fn save(&self, config: &str) -> Result<()> {
102
+ let key = self.get_encryption_key()?;
103
+ let cipher = Aes256Gcm::new(&key);
104
+
105
+ // Generate nonce
106
+ let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
107
+
108
+ // Encrypt
109
+ let ciphertext = cipher
110
+ .encrypt(&nonce, config.as_bytes())
111
+ .map_err(|_| anyhow::anyhow!("Failed to encrypt configuration"))?;
112
+
113
+ // Store encrypted data
114
+ let encrypted_data = EncryptedData {
115
+ nonce: nonce.to_vec(),
116
+ ciphertext,
117
+ };
118
+
119
+ let json = serde_json::to_string_pretty(&encrypted_data)
120
+ .context("Failed to serialize encrypted data")?;
121
+
122
+ fs::write(&self.config_path, json).context("Failed to write encrypted config file")?;
123
+
124
+ debug!("Saved encrypted configuration to {:?}", self.config_path);
125
+ Ok(())
126
+ }
127
+
128
+ /// Load and decrypt configuration
129
+ ///
130
+ /// # Returns
131
+ /// * `Ok(Some(config))` if the config exists and was decrypted successfully
132
+ /// * `Ok(None)` if the config file doesn't exist
133
+ /// * `Err` if there was an error reading or decrypting
134
+ pub fn load(&self) -> Result<Option<String>> {
135
+ if !self.config_path.exists() {
136
+ debug!("Config file does not exist: {:?}", self.config_path);
137
+ return Ok(None);
138
+ }
139
+
140
+ let json = fs::read_to_string(&self.config_path)
141
+ .context("Failed to read encrypted config file")?;
142
+
143
+ let encrypted_data: EncryptedData =
144
+ serde_json::from_str(&json).context("Failed to parse encrypted config file")?;
145
+
146
+ let key = self.get_encryption_key()?;
147
+ let cipher = Aes256Gcm::new(&key);
148
+
149
+ // Reconstruct nonce
150
+ if encrypted_data.nonce.len() != NONCE_SIZE {
151
+ return Err(anyhow::anyhow!("Invalid nonce size"));
152
+ }
153
+ let nonce = Nonce::from_slice(&encrypted_data.nonce);
154
+
155
+ // Decrypt
156
+ let plaintext = cipher
157
+ .decrypt(nonce, encrypted_data.ciphertext.as_ref())
158
+ .map_err(|_| {
159
+ anyhow::anyhow!(
160
+ "Failed to decrypt configuration - Check your ENACT_CONFIG_ENCRYPTION_KEY"
161
+ )
162
+ })?;
163
+
164
+ let config = String::from_utf8(plaintext)
165
+ .context("Failed to decode decrypted configuration as UTF-8")?;
166
+
167
+ debug!("Loaded encrypted configuration from {:?}", self.config_path);
168
+ Ok(Some(config))
169
+ }
170
+
171
+ /// Get the config file path
172
+ pub fn config_path(&self) -> &Path {
173
+ &self.config_path
174
+ }
175
+ }
176
+
177
+ /// Get the default config file path for the current platform
178
+ pub fn default_config_path() -> Result<PathBuf> {
179
+ let config_dir = dirs::config_dir()
180
+ .or_else(|| dirs::home_dir().map(|h| h.join(".config")))
181
+ .context("Failed to determine config directory")?;
182
+
183
+ Ok(config_dir.join("enact").join("config.encrypted"))
184
+ }
185
+
186
+ #[cfg(test)]
187
+ mod tests {
188
+ use super::*;
189
+ use tempfile::TempDir;
190
+
191
+ #[test]
192
+ fn test_encrypted_store() {
193
+ let temp_dir = TempDir::new().unwrap();
194
+ let config_path = temp_dir.path().join("test_config.encrypted");
195
+ // Use mock secrets for test to avoid stderr clutter and ensure key storage
196
+ let secrets = SecretManager::new_mock();
197
+ let store = EncryptedStore::with_secrets(&config_path, secrets).unwrap();
198
+
199
+ // Test save and load
200
+ let test_config = r#"{"test": "value", "number": 42}"#;
201
+ store.save(test_config).unwrap();
202
+
203
+ let loaded = store.load().unwrap();
204
+ assert_eq!(loaded, Some(test_config.to_string()));
205
+
206
+ // Test that it's actually encrypted
207
+ let file_contents = fs::read_to_string(&config_path).unwrap();
208
+ assert!(!file_contents.contains("test"));
209
+ assert!(!file_contents.contains("value"));
210
+ }
211
+ }