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,234 @@
1
+ +++
2
+ title = "Modern JavaScript Features You Should Be Using"
3
+ description = "ES2020+ brought powerful features that make JavaScript more expressive and less error-prone. Here are the ones worth adopting."
4
+ date = 2024-12-20
5
+ [taxonomies]
6
+ tags = ["javascript", "es2020", "frontend"]
7
+ +++
8
+
9
+ # Modern JavaScript Features You Should Be Using
10
+
11
+ JavaScript evolves yearly. Here are features from recent versions that genuinely improve code quality.
12
+
13
+ ## Optional Chaining (?.)
14
+
15
+ Stop writing defensive chains:
16
+
17
+ ```javascript
18
+ // Before
19
+ const city = user && user.address && user.address.city;
20
+
21
+ // After
22
+ const city = user?.address?.city;
23
+ ```
24
+
25
+ Works with methods and arrays too:
26
+
27
+ ```javascript
28
+ const result = obj.method?.();
29
+ const first = arr?.[0];
30
+ ```
31
+
32
+ ## Nullish Coalescing (??)
33
+
34
+ Default values that respect `0` and `''`:
35
+
36
+ ```javascript
37
+ // Problem with ||
38
+ const count = response.count || 10; // 0 becomes 10!
39
+
40
+ // Solution with ??
41
+ const count = response.count ?? 10; // 0 stays 0
42
+ ```
43
+
44
+ ## Logical Assignment Operators
45
+
46
+ Combine logical operators with assignment:
47
+
48
+ ```javascript
49
+ // ||= assigns if falsy
50
+ options.timeout ||= 3000;
51
+
52
+ // ??= assigns if nullish
53
+ user.name ??= 'Anonymous';
54
+
55
+ // &&= assigns if truthy
56
+ config.debug &&= validateDebugMode();
57
+ ```
58
+
59
+ ## Array Methods
60
+
61
+ ### at() - Negative Indexing
62
+
63
+ ```javascript
64
+ const arr = [1, 2, 3, 4, 5];
65
+
66
+ // Before
67
+ const last = arr[arr.length - 1];
68
+
69
+ // After
70
+ const last = arr.at(-1);
71
+ const secondLast = arr.at(-2);
72
+ ```
73
+
74
+ ### findLast() and findLastIndex()
75
+
76
+ ```javascript
77
+ const transactions = [
78
+ { type: 'credit', amount: 100 },
79
+ { type: 'debit', amount: 50 },
80
+ { type: 'credit', amount: 200 },
81
+ ];
82
+
83
+ const lastCredit = transactions.findLast(t => t.type === 'credit');
84
+ // { type: 'credit', amount: 200 }
85
+ ```
86
+
87
+ ### toSorted(), toReversed(), toSpliced()
88
+
89
+ Non-mutating array operations:
90
+
91
+ ```javascript
92
+ const original = [3, 1, 2];
93
+
94
+ const sorted = original.toSorted();
95
+ // sorted: [1, 2, 3]
96
+ // original: [3, 1, 2] - unchanged!
97
+
98
+ const reversed = original.toReversed();
99
+ const removed = original.toSpliced(1, 1);
100
+ ```
101
+
102
+ ## Object.groupBy()
103
+
104
+ Native grouping without lodash:
105
+
106
+ ```javascript
107
+ const inventory = [
108
+ { name: 'apples', type: 'fruit' },
109
+ { name: 'bananas', type: 'fruit' },
110
+ { name: 'carrots', type: 'vegetable' },
111
+ ];
112
+
113
+ const grouped = Object.groupBy(inventory, item => item.type);
114
+ // {
115
+ // fruit: [{ name: 'apples', ... }, { name: 'bananas', ... }],
116
+ // vegetable: [{ name: 'carrots', ... }]
117
+ // }
118
+ ```
119
+
120
+ ## Promise.allSettled()
121
+
122
+ Wait for all promises regardless of rejection:
123
+
124
+ ```javascript
125
+ const results = await Promise.allSettled([
126
+ fetch('/api/users'),
127
+ fetch('/api/posts'),
128
+ fetch('/api/comments'),
129
+ ]);
130
+
131
+ results.forEach(result => {
132
+ if (result.status === 'fulfilled') {
133
+ console.log(result.value);
134
+ } else {
135
+ console.error(result.reason);
136
+ }
137
+ });
138
+ ```
139
+
140
+ ## Private Class Fields
141
+
142
+ True privacy with `#`:
143
+
144
+ ```javascript
145
+ class Counter {
146
+ #count = 0;
147
+
148
+ increment() {
149
+ this.#count++;
150
+ }
151
+
152
+ get value() {
153
+ return this.#count;
154
+ }
155
+ }
156
+
157
+ const counter = new Counter();
158
+ counter.increment();
159
+ console.log(counter.value); // 1
160
+ console.log(counter.#count); // SyntaxError!
161
+ ```
162
+
163
+ ## Static Blocks
164
+
165
+ Complex static initialization:
166
+
167
+ ```javascript
168
+ class Config {
169
+ static values;
170
+
171
+ static {
172
+ try {
173
+ this.values = JSON.parse(localStorage.getItem('config'));
174
+ } catch {
175
+ this.values = { theme: 'dark' };
176
+ }
177
+ }
178
+ }
179
+ ```
180
+
181
+ ## Top-Level Await
182
+
183
+ Use `await` outside async functions in modules:
184
+
185
+ ```javascript
186
+ // config.js
187
+ const response = await fetch('/api/config');
188
+ export const config = await response.json();
189
+
190
+ // main.js
191
+ import { config } from './config.js';
192
+ // config is already resolved
193
+ ```
194
+
195
+ ## Temporal API (Coming Soon)
196
+
197
+ Finally, a sane date/time API:
198
+
199
+ ```javascript
200
+ // Current (painful)
201
+ const date = new Date();
202
+ date.setDate(date.getDate() + 7);
203
+
204
+ // Temporal (clear)
205
+ const date = Temporal.Now.plainDateISO();
206
+ const nextWeek = date.add({ days: 7 });
207
+ ```
208
+
209
+ ## Error Cause
210
+
211
+ Chain errors with context:
212
+
213
+ ```javascript
214
+ try {
215
+ await fetchUserData(userId);
216
+ } catch (error) {
217
+ throw new Error('Failed to load user profile', {
218
+ cause: error
219
+ });
220
+ }
221
+ ```
222
+
223
+ ## Quick Adoption Guide
224
+
225
+ | Feature | Use When |
226
+ |---------|----------|
227
+ | `?.` | Accessing nested properties |
228
+ | `??` | Providing defaults (especially for 0/'') |
229
+ | `at(-1)` | Accessing from array end |
230
+ | `toSorted()` | Sorting without mutation |
231
+ | `Object.groupBy()` | Categorizing arrays |
232
+ | `#private` | Encapsulating class data |
233
+
234
+ Check [caniuse.com](https://caniuse.com) for browser support before using in production.
@@ -0,0 +1,311 @@
1
+ +++
2
+ title = "Testing Strategies That Actually Work"
3
+ description = "Testing isn't about coverage percentages. It's about confidence. Here's how to test effectively."
4
+ date = 2024-12-26
5
+ [taxonomies]
6
+ tags = ["testing", "quality", "development"]
7
+ +++
8
+
9
+ # Testing Strategies That Actually Work
10
+
11
+ The goal of testing isn't 100% coverage. It's confidence to ship.
12
+
13
+ ## The Testing Trophy
14
+
15
+ Forget the pyramid. Think trophy:
16
+
17
+ ```
18
+ ╱╲
19
+ ╱ ╲ E2E (few)
20
+ ╱────╲
21
+ ╱ ╲ Integration (most)
22
+ ╱────────╲
23
+ ╱ ╲ Unit (some)
24
+ ╱────────────╲
25
+ │ Static Types │
26
+ └──────────────┘
27
+ ```
28
+
29
+ **Static analysis** catches the most bugs with the least effort.
30
+
31
+ ## Unit Tests
32
+
33
+ Test pure functions and isolated logic:
34
+
35
+ ```javascript
36
+ // utils.test.js
37
+ import { formatCurrency, calculateDiscount } from './utils';
38
+
39
+ describe('formatCurrency', () => {
40
+ it('formats positive amounts', () => {
41
+ expect(formatCurrency(1234.5)).toBe('$1,234.50');
42
+ });
43
+
44
+ it('handles zero', () => {
45
+ expect(formatCurrency(0)).toBe('$0.00');
46
+ });
47
+
48
+ it('formats negative amounts', () => {
49
+ expect(formatCurrency(-50)).toBe('-$50.00');
50
+ });
51
+ });
52
+
53
+ describe('calculateDiscount', () => {
54
+ it('applies percentage discount', () => {
55
+ expect(calculateDiscount(100, 0.2)).toBe(80);
56
+ });
57
+
58
+ it('never goes below zero', () => {
59
+ expect(calculateDiscount(10, 2)).toBe(0);
60
+ });
61
+ });
62
+ ```
63
+
64
+ ### When to Unit Test
65
+
66
+ - Pure functions
67
+ - Complex business logic
68
+ - Utility functions
69
+ - State reducers
70
+ - Data transformations
71
+
72
+ ### When NOT to Unit Test
73
+
74
+ - Simple getters/setters
75
+ - Framework code
76
+ - Implementation details
77
+ - One-liner functions
78
+
79
+ ## Integration Tests
80
+
81
+ Test how pieces work together:
82
+
83
+ ```javascript
84
+ // api.test.js
85
+ import { createServer } from '../server';
86
+ import { db } from '../database';
87
+
88
+ describe('POST /users', () => {
89
+ let server;
90
+
91
+ beforeAll(async () => {
92
+ server = await createServer();
93
+ await db.migrate();
94
+ });
95
+
96
+ afterAll(async () => {
97
+ await db.close();
98
+ await server.close();
99
+ });
100
+
101
+ beforeEach(async () => {
102
+ await db.truncate('users');
103
+ });
104
+
105
+ it('creates a user and returns 201', async () => {
106
+ const response = await server.inject({
107
+ method: 'POST',
108
+ url: '/users',
109
+ payload: {
110
+ email: 'test@example.com',
111
+ name: 'Test User',
112
+ },
113
+ });
114
+
115
+ expect(response.statusCode).toBe(201);
116
+ expect(response.json()).toMatchObject({
117
+ email: 'test@example.com',
118
+ name: 'Test User',
119
+ });
120
+
121
+ // Verify database
122
+ const user = await db.query('SELECT * FROM users WHERE email = $1', ['test@example.com']);
123
+ expect(user).toBeDefined();
124
+ });
125
+
126
+ it('returns 400 for invalid email', async () => {
127
+ const response = await server.inject({
128
+ method: 'POST',
129
+ url: '/users',
130
+ payload: {
131
+ email: 'not-an-email',
132
+ name: 'Test',
133
+ },
134
+ });
135
+
136
+ expect(response.statusCode).toBe(400);
137
+ expect(response.json().error.code).toBe('VALIDATION_ERROR');
138
+ });
139
+ });
140
+ ```
141
+
142
+ ## Component Tests (Frontend)
143
+
144
+ Test components with realistic interactions:
145
+
146
+ ```javascript
147
+ // UserProfile.test.jsx
148
+ import { render, screen, waitFor } from '@testing-library/react';
149
+ import userEvent from '@testing-library/user-event';
150
+ import { UserProfile } from './UserProfile';
151
+ import { server } from '../mocks/server';
152
+ import { rest } from 'msw';
153
+
154
+ describe('UserProfile', () => {
155
+ it('displays user information', async () => {
156
+ render(<UserProfile userId="123" />);
157
+
158
+ await waitFor(() => {
159
+ expect(screen.getByRole('heading')).toHaveTextContent('Jane Doe');
160
+ });
161
+
162
+ expect(screen.getByText('jane@example.com')).toBeInTheDocument();
163
+ });
164
+
165
+ it('handles edit mode', async () => {
166
+ const user = userEvent.setup();
167
+ render(<UserProfile userId="123" />);
168
+
169
+ await user.click(screen.getByRole('button', { name: /edit/i }));
170
+
171
+ const input = screen.getByLabelText(/name/i);
172
+ await user.clear(input);
173
+ await user.type(input, 'Jane Smith');
174
+ await user.click(screen.getByRole('button', { name: /save/i }));
175
+
176
+ await waitFor(() => {
177
+ expect(screen.getByRole('heading')).toHaveTextContent('Jane Smith');
178
+ });
179
+ });
180
+
181
+ it('shows error state', async () => {
182
+ server.use(
183
+ rest.get('/api/users/:id', (req, res, ctx) => {
184
+ return res(ctx.status(500));
185
+ })
186
+ );
187
+
188
+ render(<UserProfile userId="123" />);
189
+
190
+ await waitFor(() => {
191
+ expect(screen.getByRole('alert')).toHaveTextContent(/failed to load/i);
192
+ });
193
+ });
194
+ });
195
+ ```
196
+
197
+ ## E2E Tests
198
+
199
+ Test critical user journeys:
200
+
201
+ ```javascript
202
+ // checkout.spec.js (Playwright)
203
+ import { test, expect } from '@playwright/test';
204
+
205
+ test.describe('Checkout Flow', () => {
206
+ test('completes purchase successfully', async ({ page }) => {
207
+ // Add item to cart
208
+ await page.goto('/products/widget');
209
+ await page.click('button:has-text("Add to Cart")');
210
+
211
+ // Go to checkout
212
+ await page.click('a:has-text("Checkout")');
213
+
214
+ // Fill shipping
215
+ await page.fill('[name="email"]', 'test@example.com');
216
+ await page.fill('[name="address"]', '123 Main St');
217
+ await page.fill('[name="city"]', 'Portland');
218
+ await page.selectOption('[name="state"]', 'OR');
219
+ await page.fill('[name="zip"]', '97201');
220
+
221
+ // Fill payment (test card)
222
+ await page.fill('[name="cardNumber"]', '4242424242424242');
223
+ await page.fill('[name="expiry"]', '12/25');
224
+ await page.fill('[name="cvc"]', '123');
225
+
226
+ // Submit
227
+ await page.click('button:has-text("Place Order")');
228
+
229
+ // Verify success
230
+ await expect(page.locator('h1')).toHaveText('Order Confirmed');
231
+ await expect(page.locator('.order-number')).toBeVisible();
232
+ });
233
+ });
234
+ ```
235
+
236
+ ### E2E Best Practices
237
+
238
+ - Test happy paths thoroughly
239
+ - Use realistic test data
240
+ - Run in CI on every PR
241
+ - Keep tests independent
242
+ - Use test IDs for stability
243
+
244
+ ## What NOT to Test
245
+
246
+ - Third-party libraries
247
+ - Framework internals
248
+ - Private implementation details
249
+ - Simple pass-through code
250
+ - Autogenerated code
251
+
252
+ ## Test Data Strategies
253
+
254
+ ### Factories
255
+
256
+ ```javascript
257
+ // factories/user.js
258
+ import { faker } from '@faker-js/faker';
259
+
260
+ export function createUser(overrides = {}) {
261
+ return {
262
+ id: faker.string.uuid(),
263
+ email: faker.internet.email(),
264
+ name: faker.person.fullName(),
265
+ createdAt: faker.date.past(),
266
+ ...overrides,
267
+ };
268
+ }
269
+
270
+ // In tests
271
+ const user = createUser({ email: 'specific@test.com' });
272
+ ```
273
+
274
+ ### Fixtures
275
+
276
+ ```javascript
277
+ // fixtures/users.json
278
+ {
279
+ "admin": {
280
+ "id": "admin-001",
281
+ "email": "admin@example.com",
282
+ "role": "admin"
283
+ },
284
+ "regular": {
285
+ "id": "user-001",
286
+ "email": "user@example.com",
287
+ "role": "user"
288
+ }
289
+ }
290
+ ```
291
+
292
+ ## Measuring Test Quality
293
+
294
+ Coverage is a **floor**, not a **ceiling**.
295
+
296
+ Better metrics:
297
+ - **Mutation score**: Do tests catch bugs?
298
+ - **Flakiness rate**: Are tests reliable?
299
+ - **Time to run**: Are tests fast enough?
300
+ - **Maintenance cost**: Are tests easy to update?
301
+
302
+ ## Quick Guidelines
303
+
304
+ | Test Type | Speed | Confidence | Quantity |
305
+ |-----------|-------|------------|----------|
306
+ | Static | Instant | Medium | All code |
307
+ | Unit | Fast | Low-Medium | Some |
308
+ | Integration | Medium | High | Most |
309
+ | E2E | Slow | Highest | Few |
310
+
311
+ Write tests that give you confidence to ship, not tests that give you coverage badges.
@@ -0,0 +1,104 @@
1
+ +++
2
+ title = "Typography Fundamentals for Developers"
3
+ description = "Good typography makes your content readable and your site professional. Here are the basics every developer should know."
4
+ date = 2024-12-15
5
+ [taxonomies]
6
+ tags = ["design", "typography", "css"]
7
+ +++
8
+
9
+ # Typography Fundamentals for Developers
10
+
11
+ You don't need to be a designer to get typography right. These fundamentals will take you far.
12
+
13
+ ## Choose Readable Fonts
14
+
15
+ For body text, prioritize readability:
16
+
17
+ - **Sans-serif** for screens: Geist, Inter, system-ui
18
+ - **Serif** for long-form: Georgia, Charter, Literata
19
+ - **Monospace** for code: Geist Mono, JetBrains Mono, Fira Code
20
+
21
+ Avoid decorative fonts for body text. Save them for headlines.
22
+
23
+ ## Set a Comfortable Line Length
24
+
25
+ Lines that are too long or too short hurt readability. Aim for **45-75 characters** per line:
26
+
27
+ ```css
28
+ .prose {
29
+ max-width: 65ch;
30
+ }
31
+ ```
32
+
33
+ The `ch` unit is based on the width of the "0" character, making it perfect for this.
34
+
35
+ ## Use a Type Scale
36
+
37
+ Don't pick font sizes randomly. Use a scale:
38
+
39
+ ```css
40
+ :root {
41
+ --text-xs: 0.75rem; /* 12px */
42
+ --text-sm: 0.875rem; /* 14px */
43
+ --text-base: 1rem; /* 16px */
44
+ --text-lg: 1.125rem; /* 18px */
45
+ --text-xl: 1.25rem; /* 20px */
46
+ --text-2xl: 1.5rem; /* 24px */
47
+ --text-3xl: 1.875rem; /* 30px */
48
+ --text-4xl: 2.25rem; /* 36px */
49
+ }
50
+ ```
51
+
52
+ ## Line Height Matters
53
+
54
+ Tighter line height for headlines, looser for body text:
55
+
56
+ ```css
57
+ h1, h2, h3 {
58
+ line-height: 1.2;
59
+ }
60
+
61
+ p {
62
+ line-height: 1.6;
63
+ }
64
+ ```
65
+
66
+ ## Vertical Rhythm
67
+
68
+ Consistent spacing creates visual harmony:
69
+
70
+ ```css
71
+ .prose > * + * {
72
+ margin-top: 1.5rem;
73
+ }
74
+
75
+ .prose h2 {
76
+ margin-top: 3rem;
77
+ }
78
+ ```
79
+
80
+ ## Font Loading
81
+
82
+ Use `font-display: swap` to prevent invisible text:
83
+
84
+ ```css
85
+ @font-face {
86
+ font-family: 'Geist';
87
+ src: url('/fonts/Geist-Variable.woff2') format('woff2');
88
+ font-display: swap;
89
+ }
90
+ ```
91
+
92
+ ## Responsive Typography
93
+
94
+ Scale fonts based on viewport:
95
+
96
+ ```css
97
+ html {
98
+ font-size: clamp(16px, 1vw + 14px, 20px);
99
+ }
100
+ ```
101
+
102
+ This creates fluid typography that adapts to screen size.
103
+
104
+ Good typography is invisible—readers don't notice it, they just enjoy the content.
@@ -0,0 +1,67 @@
1
+ +++
2
+ title = "Welcome to Tanuki"
3
+ description = "Introducing Tanuki, a whimsical Zola theme inspired by Nintendo's playful design philosophy."
4
+ date = 2024-12-27
5
+ [taxonomies]
6
+ tags = ["announcement", "release"]
7
+ +++
8
+
9
+ # Welcome to Tanuki
10
+
11
+ We're excited to introduce Tanuki, a new Zola theme that brings joy and whimsy to your documentation, books, and blogs.
12
+
13
+ ## Why Tanuki?
14
+
15
+ The tanuki (Japanese raccoon dog) is a beloved creature in Japanese folklore, known for being playful, mischievous, and a little magical. We chose this name because our theme embodies those same qualities—it's fun to use, delightful to look at, and just a bit magical in how it transforms your content.
16
+
17
+ ## Three Modes, One Theme
18
+
19
+ Tanuki supports three distinct modes:
20
+
21
+ 1. **Documentation Mode** - Perfect for API docs and technical references
22
+ 2. **E-Book Mode** - Ideal for tutorials, courses, and long-form content
23
+ 3. **Blog Mode** - Great for personal sites, portfolios, and announcements
24
+
25
+ Each mode is optimized for its purpose while maintaining a consistent, cohesive design language.
26
+
27
+ ## Features You'll Love
28
+
29
+ ### Catppuccin Colors
30
+
31
+ We use the beautiful [Catppuccin](https://github.com/catppuccin/catppuccin) color palette, with Mocha for dark mode and Latte for light mode. The colors are warm, inviting, and easy on the eyes during long reading sessions.
32
+
33
+ ### Nintendo-Inspired UX
34
+
35
+ Inspired by games like Animal Crossing and Super Mario Odyssey, we've added subtle animations and interactions that make using the theme feel delightful. Watch the theme toggle sparkle when you click it!
36
+
37
+ ### Full-Text Search
38
+
39
+ Press `/` anywhere to search your entire site instantly. Powered by Elasticlunr, it's fast and works offline.
40
+
41
+ ## Getting Started
42
+
43
+ Adding Tanuki to your project is simple:
44
+
45
+ ```bash
46
+ git submodule add https://github.com/raskell-io/tanuki themes/tanuki
47
+ ```
48
+
49
+ Then add to your `config.toml`:
50
+
51
+ ```toml
52
+ theme = "tanuki"
53
+
54
+ [extra]
55
+ mode = "site" # or "docs" or "book"
56
+ ```
57
+
58
+ ## What's Next?
59
+
60
+ We're just getting started! Upcoming features include:
61
+
62
+ - More theme color options
63
+ - Additional page templates
64
+ - Enhanced print stylesheets
65
+ - Improved accessibility features
66
+
67
+ Stay tuned for more updates, and happy building!