@nhtio/adk 1.20260607.2 → 1.20260609.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 (501) hide show
  1. package/CHANGELOG.md +185 -0
  2. package/batteries/embeddings/openai/adapter.cjs +1 -1
  3. package/batteries/embeddings/openai/adapter.mjs +1 -1
  4. package/batteries/embeddings/openai/exceptions.cjs +1 -1
  5. package/batteries/embeddings/openai/exceptions.mjs +1 -1
  6. package/batteries/embeddings/openai/types.d.ts +7 -0
  7. package/batteries/embeddings/webllm/adapter.cjs +1 -1
  8. package/batteries/embeddings/webllm/adapter.mjs +1 -1
  9. package/batteries/embeddings/webllm/exceptions.cjs +1 -1
  10. package/batteries/embeddings/webllm/exceptions.mjs +1 -1
  11. package/batteries/llm/chat_common/helpers.d.ts +165 -0
  12. package/batteries/llm/chat_common/types.d.ts +309 -0
  13. package/batteries/llm/index.d.ts +5 -0
  14. package/batteries/llm/ollama/adapter.cjs +736 -0
  15. package/batteries/llm/ollama/adapter.cjs.map +1 -0
  16. package/batteries/llm/ollama/adapter.d.ts +64 -0
  17. package/batteries/llm/ollama/adapter.mjs +734 -0
  18. package/batteries/llm/ollama/adapter.mjs.map +1 -0
  19. package/batteries/llm/ollama/exceptions.cjs +105 -0
  20. package/batteries/llm/ollama/exceptions.cjs.map +1 -0
  21. package/batteries/llm/ollama/exceptions.d.ts +112 -0
  22. package/batteries/llm/ollama/exceptions.mjs +96 -0
  23. package/batteries/llm/ollama/exceptions.mjs.map +1 -0
  24. package/batteries/llm/ollama/helpers.cjs +487 -0
  25. package/batteries/llm/ollama/helpers.cjs.map +1 -0
  26. package/batteries/llm/ollama/helpers.d.ts +158 -0
  27. package/batteries/llm/ollama/helpers.mjs +450 -0
  28. package/batteries/llm/ollama/helpers.mjs.map +1 -0
  29. package/batteries/llm/ollama/index.d.ts +29 -0
  30. package/batteries/llm/ollama/types.cjs +2 -0
  31. package/batteries/llm/ollama/types.d.ts +334 -0
  32. package/batteries/llm/ollama/types.mjs +0 -0
  33. package/batteries/llm/ollama/validation.cjs +130 -0
  34. package/batteries/llm/ollama/validation.cjs.map +1 -0
  35. package/batteries/llm/ollama/validation.d.ts +31 -0
  36. package/batteries/llm/ollama/validation.mjs +127 -0
  37. package/batteries/llm/ollama/validation.mjs.map +1 -0
  38. package/batteries/llm/ollama.cjs +54 -0
  39. package/batteries/llm/ollama.mjs +6 -0
  40. package/batteries/llm/openai_chat_completions/adapter.cjs +36 -19
  41. package/batteries/llm/openai_chat_completions/adapter.cjs.map +1 -1
  42. package/batteries/llm/openai_chat_completions/adapter.mjs +23 -6
  43. package/batteries/llm/openai_chat_completions/adapter.mjs.map +1 -1
  44. package/batteries/llm/openai_chat_completions/exceptions.cjs +1 -1
  45. package/batteries/llm/openai_chat_completions/exceptions.mjs +1 -1
  46. package/batteries/llm/openai_chat_completions/helpers.cjs +80 -320
  47. package/batteries/llm/openai_chat_completions/helpers.cjs.map +1 -1
  48. package/batteries/llm/openai_chat_completions/helpers.d.ts +68 -144
  49. package/batteries/llm/openai_chat_completions/helpers.mjs +40 -280
  50. package/batteries/llm/openai_chat_completions/helpers.mjs.map +1 -1
  51. package/batteries/llm/openai_chat_completions/types.d.ts +273 -181
  52. package/batteries/llm/openai_chat_completions/validation.cjs +2 -2
  53. package/batteries/llm/openai_chat_completions/validation.cjs.map +1 -1
  54. package/batteries/llm/openai_chat_completions/validation.mjs +2 -2
  55. package/batteries/llm/openai_chat_completions/validation.mjs.map +1 -1
  56. package/batteries/llm/openai_chat_completions.cjs +29 -28
  57. package/batteries/llm/openai_chat_completions.mjs +2 -1
  58. package/batteries/llm/webllm_chat_completions/adapter.cjs +38 -19
  59. package/batteries/llm/webllm_chat_completions/adapter.cjs.map +1 -1
  60. package/batteries/llm/webllm_chat_completions/adapter.d.ts +18 -0
  61. package/batteries/llm/webllm_chat_completions/adapter.mjs +25 -6
  62. package/batteries/llm/webllm_chat_completions/adapter.mjs.map +1 -1
  63. package/batteries/llm/webllm_chat_completions/exceptions.cjs +1 -1
  64. package/batteries/llm/webllm_chat_completions/exceptions.mjs +1 -1
  65. package/batteries/llm/webllm_chat_completions/helpers.cjs +29 -28
  66. package/batteries/llm/webllm_chat_completions/helpers.mjs +2 -1
  67. package/batteries/llm/webllm_chat_completions/types.d.ts +21 -0
  68. package/batteries/llm/webllm_chat_completions/validation.cjs +13 -1
  69. package/batteries/llm/webllm_chat_completions/validation.cjs.map +1 -1
  70. package/batteries/llm/webllm_chat_completions/validation.d.ts +12 -0
  71. package/batteries/llm/webllm_chat_completions/validation.mjs +13 -1
  72. package/batteries/llm/webllm_chat_completions/validation.mjs.map +1 -1
  73. package/batteries/llm/webllm_chat_completions.cjs +29 -28
  74. package/batteries/llm/webllm_chat_completions.mjs +2 -1
  75. package/batteries/llm.cjs +44 -28
  76. package/batteries/llm.mjs +9 -4
  77. package/batteries/storage/flydrive.cjs +1 -1
  78. package/batteries/storage/flydrive.mjs +1 -1
  79. package/batteries/storage/in_memory/index.d.ts +1 -1
  80. package/batteries/storage/in_memory.cjs +2 -2
  81. package/batteries/storage/in_memory.cjs.map +1 -1
  82. package/batteries/storage/in_memory.mjs +2 -2
  83. package/batteries/storage/in_memory.mjs.map +1 -1
  84. package/batteries/storage/opfs/index.d.ts +19 -0
  85. package/batteries/storage/opfs.cjs +1 -1
  86. package/batteries/storage/opfs.cjs.map +1 -1
  87. package/batteries/storage/opfs.mjs +1 -1
  88. package/batteries/storage/opfs.mjs.map +1 -1
  89. package/batteries/tools/color.cjs +3 -2
  90. package/batteries/tools/color.cjs.map +1 -1
  91. package/batteries/tools/color.mjs +3 -2
  92. package/batteries/tools/color.mjs.map +1 -1
  93. package/batteries/tools/comparison.cjs +4 -3
  94. package/batteries/tools/comparison.cjs.map +1 -1
  95. package/batteries/tools/comparison.mjs +4 -3
  96. package/batteries/tools/comparison.mjs.map +1 -1
  97. package/batteries/tools/data_structure.cjs +30 -10
  98. package/batteries/tools/data_structure.cjs.map +1 -1
  99. package/batteries/tools/data_structure.mjs +30 -10
  100. package/batteries/tools/data_structure.mjs.map +1 -1
  101. package/batteries/tools/datetime_extended.cjs +5 -10
  102. package/batteries/tools/datetime_extended.cjs.map +1 -1
  103. package/batteries/tools/datetime_extended.mjs +5 -10
  104. package/batteries/tools/datetime_extended.mjs.map +1 -1
  105. package/batteries/tools/datetime_math.cjs +2 -2
  106. package/batteries/tools/datetime_math.mjs +2 -2
  107. package/batteries/tools/encoding.cjs +13 -4
  108. package/batteries/tools/encoding.cjs.map +1 -1
  109. package/batteries/tools/encoding.mjs +13 -4
  110. package/batteries/tools/encoding.mjs.map +1 -1
  111. package/batteries/tools/formatting.cjs +4 -4
  112. package/batteries/tools/formatting.cjs.map +1 -1
  113. package/batteries/tools/formatting.mjs +4 -4
  114. package/batteries/tools/formatting.mjs.map +1 -1
  115. package/batteries/tools/geo_basics.cjs +2 -2
  116. package/batteries/tools/geo_basics.mjs +2 -2
  117. package/batteries/tools/index.d.ts +1 -0
  118. package/batteries/tools/math.cjs +10 -8
  119. package/batteries/tools/math.cjs.map +1 -1
  120. package/batteries/tools/math.mjs +10 -8
  121. package/batteries/tools/math.mjs.map +1 -1
  122. package/batteries/tools/memory.cjs +5 -5
  123. package/batteries/tools/memory.mjs +5 -5
  124. package/batteries/tools/parsing.cjs +9 -5
  125. package/batteries/tools/parsing.cjs.map +1 -1
  126. package/batteries/tools/parsing.mjs +9 -5
  127. package/batteries/tools/parsing.mjs.map +1 -1
  128. package/batteries/tools/retrievables.cjs +4 -4
  129. package/batteries/tools/retrievables.mjs +4 -4
  130. package/batteries/tools/searxng/exceptions.d.ts +21 -0
  131. package/batteries/tools/searxng/index.d.ts +150 -0
  132. package/batteries/tools/searxng.cjs +5 -0
  133. package/batteries/tools/searxng.mjs +2 -0
  134. package/batteries/tools/standing_instructions.cjs +4 -4
  135. package/batteries/tools/standing_instructions.mjs +4 -4
  136. package/batteries/tools/statistics.cjs +54 -43
  137. package/batteries/tools/statistics.cjs.map +1 -1
  138. package/batteries/tools/statistics.mjs +54 -43
  139. package/batteries/tools/statistics.mjs.map +1 -1
  140. package/batteries/tools/string_processing.cjs +5 -5
  141. package/batteries/tools/string_processing.cjs.map +1 -1
  142. package/batteries/tools/string_processing.mjs +5 -5
  143. package/batteries/tools/string_processing.mjs.map +1 -1
  144. package/batteries/tools/structured_data.cjs +8 -13
  145. package/batteries/tools/structured_data.cjs.map +1 -1
  146. package/batteries/tools/structured_data.mjs +8 -13
  147. package/batteries/tools/structured_data.mjs.map +1 -1
  148. package/batteries/tools/text_analysis.cjs +3 -3
  149. package/batteries/tools/text_analysis.mjs +3 -3
  150. package/batteries/tools/text_comparison.cjs +2 -2
  151. package/batteries/tools/text_comparison.mjs +2 -2
  152. package/batteries/tools/time.cjs +2 -2
  153. package/batteries/tools/time.mjs +2 -2
  154. package/batteries/tools/unit_conversion.cjs +10 -8
  155. package/batteries/tools/unit_conversion.cjs.map +1 -1
  156. package/batteries/tools/unit_conversion.mjs +10 -8
  157. package/batteries/tools/unit_conversion.mjs.map +1 -1
  158. package/batteries/tools.cjs +3 -0
  159. package/batteries/tools.mjs +2 -1
  160. package/batteries/vector/arangodb/index.d.ts +2 -0
  161. package/batteries/vector/arangodb.cjs +2 -1
  162. package/batteries/vector/arangodb.cjs.map +1 -1
  163. package/batteries/vector/arangodb.mjs +2 -1
  164. package/batteries/vector/arangodb.mjs.map +1 -1
  165. package/batteries/vector/builder.cjs +31 -0
  166. package/batteries/vector/builder.cjs.map +1 -1
  167. package/batteries/vector/builder.d.ts +58 -0
  168. package/batteries/vector/builder.mjs +31 -0
  169. package/batteries/vector/builder.mjs.map +1 -1
  170. package/batteries/vector/chroma/index.d.ts +4 -0
  171. package/batteries/vector/chroma.cjs +3 -0
  172. package/batteries/vector/chroma.cjs.map +1 -1
  173. package/batteries/vector/chroma.mjs +3 -0
  174. package/batteries/vector/chroma.mjs.map +1 -1
  175. package/batteries/vector/clickhouse/index.d.ts +2 -0
  176. package/batteries/vector/clickhouse.cjs +2 -1
  177. package/batteries/vector/clickhouse.cjs.map +1 -1
  178. package/batteries/vector/clickhouse.mjs +2 -1
  179. package/batteries/vector/clickhouse.mjs.map +1 -1
  180. package/batteries/vector/cloudflare/index.d.ts +2 -0
  181. package/batteries/vector/cloudflare.cjs +2 -1
  182. package/batteries/vector/cloudflare.cjs.map +1 -1
  183. package/batteries/vector/cloudflare.mjs +2 -1
  184. package/batteries/vector/cloudflare.mjs.map +1 -1
  185. package/batteries/vector/conformance/index.d.ts +22 -0
  186. package/batteries/vector/conformance.cjs +22 -0
  187. package/batteries/vector/conformance.cjs.map +1 -1
  188. package/batteries/vector/conformance.mjs +22 -0
  189. package/batteries/vector/conformance.mjs.map +1 -1
  190. package/batteries/vector/contract.cjs +22 -0
  191. package/batteries/vector/contract.cjs.map +1 -1
  192. package/batteries/vector/contract.d.ts +51 -0
  193. package/batteries/vector/contract.mjs +22 -0
  194. package/batteries/vector/contract.mjs.map +1 -1
  195. package/batteries/vector/couchbase/index.d.ts +2 -0
  196. package/batteries/vector/couchbase.cjs +2 -1
  197. package/batteries/vector/couchbase.cjs.map +1 -1
  198. package/batteries/vector/couchbase.mjs +2 -1
  199. package/batteries/vector/couchbase.mjs.map +1 -1
  200. package/batteries/vector/duckdb/index.d.ts +2 -0
  201. package/batteries/vector/duckdb.cjs +2 -1
  202. package/batteries/vector/duckdb.cjs.map +1 -1
  203. package/batteries/vector/duckdb.mjs +2 -1
  204. package/batteries/vector/duckdb.mjs.map +1 -1
  205. package/batteries/vector/elasticsearch/index.d.ts +2 -0
  206. package/batteries/vector/elasticsearch.cjs +2 -1
  207. package/batteries/vector/elasticsearch.cjs.map +1 -1
  208. package/batteries/vector/elasticsearch.mjs +2 -1
  209. package/batteries/vector/elasticsearch.mjs.map +1 -1
  210. package/batteries/vector/exceptions.cjs +1 -1
  211. package/batteries/vector/exceptions.mjs +1 -1
  212. package/batteries/vector/factory.cjs +6 -0
  213. package/batteries/vector/factory.cjs.map +1 -1
  214. package/batteries/vector/factory.d.ts +14 -0
  215. package/batteries/vector/factory.mjs +6 -0
  216. package/batteries/vector/factory.mjs.map +1 -1
  217. package/batteries/vector/filters.cjs +22 -1
  218. package/batteries/vector/filters.cjs.map +1 -1
  219. package/batteries/vector/filters.d.ts +38 -0
  220. package/batteries/vector/filters.mjs +22 -1
  221. package/batteries/vector/filters.mjs.map +1 -1
  222. package/batteries/vector/helpers.cjs +13 -0
  223. package/batteries/vector/helpers.cjs.map +1 -1
  224. package/batteries/vector/helpers.d.ts +14 -0
  225. package/batteries/vector/helpers.mjs +13 -0
  226. package/batteries/vector/helpers.mjs.map +1 -1
  227. package/batteries/vector/hnswlib/index.d.ts +2 -0
  228. package/batteries/vector/hnswlib.cjs +2 -1
  229. package/batteries/vector/hnswlib.cjs.map +1 -1
  230. package/batteries/vector/hnswlib.mjs +2 -1
  231. package/batteries/vector/hnswlib.mjs.map +1 -1
  232. package/batteries/vector/in_memory/index.d.ts +1 -0
  233. package/batteries/vector/in_memory.cjs +1 -0
  234. package/batteries/vector/in_memory.cjs.map +1 -1
  235. package/batteries/vector/in_memory.mjs +1 -0
  236. package/batteries/vector/in_memory.mjs.map +1 -1
  237. package/batteries/vector/lancedb/index.d.ts +2 -0
  238. package/batteries/vector/lancedb.cjs +2 -1
  239. package/batteries/vector/lancedb.cjs.map +1 -1
  240. package/batteries/vector/lancedb.mjs +2 -1
  241. package/batteries/vector/lancedb.mjs.map +1 -1
  242. package/batteries/vector/mariadb/index.d.ts +2 -0
  243. package/batteries/vector/mariadb.cjs +2 -1
  244. package/batteries/vector/mariadb.cjs.map +1 -1
  245. package/batteries/vector/mariadb.mjs +2 -1
  246. package/batteries/vector/mariadb.mjs.map +1 -1
  247. package/batteries/vector/meilisearch/index.d.ts +2 -0
  248. package/batteries/vector/meilisearch.cjs +2 -1
  249. package/batteries/vector/meilisearch.cjs.map +1 -1
  250. package/batteries/vector/meilisearch.mjs +2 -1
  251. package/batteries/vector/meilisearch.mjs.map +1 -1
  252. package/batteries/vector/migrate.cjs +18 -1
  253. package/batteries/vector/migrate.cjs.map +1 -1
  254. package/batteries/vector/migrate.d.ts +31 -0
  255. package/batteries/vector/migrate.mjs +18 -1
  256. package/batteries/vector/migrate.mjs.map +1 -1
  257. package/batteries/vector/milvus/index.d.ts +5 -0
  258. package/batteries/vector/milvus.cjs +4 -0
  259. package/batteries/vector/milvus.cjs.map +1 -1
  260. package/batteries/vector/milvus.mjs +4 -0
  261. package/batteries/vector/milvus.mjs.map +1 -1
  262. package/batteries/vector/mongodb/index.d.ts +2 -0
  263. package/batteries/vector/mongodb.cjs +2 -1
  264. package/batteries/vector/mongodb.cjs.map +1 -1
  265. package/batteries/vector/mongodb.mjs +2 -1
  266. package/batteries/vector/mongodb.mjs.map +1 -1
  267. package/batteries/vector/neo4j/index.d.ts +2 -0
  268. package/batteries/vector/neo4j.cjs +2 -1
  269. package/batteries/vector/neo4j.cjs.map +1 -1
  270. package/batteries/vector/neo4j.mjs +2 -1
  271. package/batteries/vector/neo4j.mjs.map +1 -1
  272. package/batteries/vector/opensearch/index.d.ts +2 -0
  273. package/batteries/vector/opensearch.cjs +2 -1
  274. package/batteries/vector/opensearch.cjs.map +1 -1
  275. package/batteries/vector/opensearch.mjs +2 -1
  276. package/batteries/vector/opensearch.mjs.map +1 -1
  277. package/batteries/vector/oracle23ai/index.d.ts +2 -0
  278. package/batteries/vector/oracle23ai.cjs +2 -1
  279. package/batteries/vector/oracle23ai.cjs.map +1 -1
  280. package/batteries/vector/oracle23ai.mjs +2 -1
  281. package/batteries/vector/oracle23ai.mjs.map +1 -1
  282. package/batteries/vector/orama/index.d.ts +1 -0
  283. package/batteries/vector/orama.cjs +1 -0
  284. package/batteries/vector/orama.cjs.map +1 -1
  285. package/batteries/vector/orama.mjs +1 -0
  286. package/batteries/vector/orama.mjs.map +1 -1
  287. package/batteries/vector/pgvector/index.d.ts +9 -2
  288. package/batteries/vector/pgvector.cjs +4 -0
  289. package/batteries/vector/pgvector.cjs.map +1 -1
  290. package/batteries/vector/pgvector.mjs +4 -0
  291. package/batteries/vector/pgvector.mjs.map +1 -1
  292. package/batteries/vector/pinecone/index.d.ts +5 -0
  293. package/batteries/vector/pinecone.cjs +3 -1
  294. package/batteries/vector/pinecone.cjs.map +1 -1
  295. package/batteries/vector/pinecone.mjs +3 -1
  296. package/batteries/vector/pinecone.mjs.map +1 -1
  297. package/batteries/vector/plan.d.ts +27 -0
  298. package/batteries/vector/qdrant/index.d.ts +5 -0
  299. package/batteries/vector/qdrant.cjs +4 -0
  300. package/batteries/vector/qdrant.cjs.map +1 -1
  301. package/batteries/vector/qdrant.mjs +4 -0
  302. package/batteries/vector/qdrant.mjs.map +1 -1
  303. package/batteries/vector/redis/index.d.ts +2 -0
  304. package/batteries/vector/redis.cjs +2 -1
  305. package/batteries/vector/redis.cjs.map +1 -1
  306. package/batteries/vector/redis.mjs +2 -1
  307. package/batteries/vector/redis.mjs.map +1 -1
  308. package/batteries/vector/retrievable.cjs +9 -1
  309. package/batteries/vector/retrievable.cjs.map +1 -1
  310. package/batteries/vector/retrievable.mjs +9 -1
  311. package/batteries/vector/retrievable.mjs.map +1 -1
  312. package/batteries/vector/retrievable_glue.d.ts +21 -0
  313. package/batteries/vector/s3vectors/index.d.ts +2 -0
  314. package/batteries/vector/s3vectors.cjs +2 -1
  315. package/batteries/vector/s3vectors.cjs.map +1 -1
  316. package/batteries/vector/s3vectors.mjs +2 -1
  317. package/batteries/vector/s3vectors.mjs.map +1 -1
  318. package/batteries/vector/schema.cjs +28 -0
  319. package/batteries/vector/schema.cjs.map +1 -1
  320. package/batteries/vector/schema.d.ts +39 -0
  321. package/batteries/vector/schema.mjs +28 -0
  322. package/batteries/vector/schema.mjs.map +1 -1
  323. package/batteries/vector/solr/index.d.ts +2 -0
  324. package/batteries/vector/solr.cjs +2 -1
  325. package/batteries/vector/solr.cjs.map +1 -1
  326. package/batteries/vector/solr.mjs +2 -1
  327. package/batteries/vector/solr.mjs.map +1 -1
  328. package/batteries/vector/sqlite_vec/index.d.ts +6 -3
  329. package/batteries/vector/sqlite_vec.cjs +2 -0
  330. package/batteries/vector/sqlite_vec.cjs.map +1 -1
  331. package/batteries/vector/sqlite_vec.mjs +2 -0
  332. package/batteries/vector/sqlite_vec.mjs.map +1 -1
  333. package/batteries/vector/surrealdb/index.d.ts +2 -0
  334. package/batteries/vector/surrealdb.cjs +2 -1
  335. package/batteries/vector/surrealdb.cjs.map +1 -1
  336. package/batteries/vector/surrealdb.mjs +2 -1
  337. package/batteries/vector/surrealdb.mjs.map +1 -1
  338. package/batteries/vector/types.d.ts +27 -0
  339. package/batteries/vector/typesense/index.d.ts +2 -0
  340. package/batteries/vector/typesense.cjs +2 -1
  341. package/batteries/vector/typesense.cjs.map +1 -1
  342. package/batteries/vector/typesense.mjs +2 -1
  343. package/batteries/vector/typesense.mjs.map +1 -1
  344. package/batteries/vector/validation.cjs +14 -0
  345. package/batteries/vector/validation.cjs.map +1 -1
  346. package/batteries/vector/validation.d.ts +14 -0
  347. package/batteries/vector/validation.mjs +14 -0
  348. package/batteries/vector/validation.mjs.map +1 -1
  349. package/batteries/vector/vector_store_constructor.cjs +1 -1
  350. package/batteries/vector/vector_store_constructor.cjs.map +1 -1
  351. package/batteries/vector/vector_store_constructor.d.ts +1 -1
  352. package/batteries/vector/vector_store_constructor.mjs +1 -1
  353. package/batteries/vector/vector_store_constructor.mjs.map +1 -1
  354. package/batteries/vector/vespa/index.d.ts +2 -0
  355. package/batteries/vector/vespa.cjs +2 -1
  356. package/batteries/vector/vespa.cjs.map +1 -1
  357. package/batteries/vector/vespa.mjs +2 -1
  358. package/batteries/vector/vespa.mjs.map +1 -1
  359. package/batteries/vector/weaviate/index.d.ts +2 -0
  360. package/batteries/vector/weaviate.cjs +2 -1
  361. package/batteries/vector/weaviate.cjs.map +1 -1
  362. package/batteries/vector/weaviate.mjs +2 -1
  363. package/batteries/vector/weaviate.mjs.map +1 -1
  364. package/batteries.cjs +46 -28
  365. package/batteries.mjs +10 -5
  366. package/{common-BT0nfCi9.mjs → common-DYDUi99O.mjs} +9 -9
  367. package/common-DYDUi99O.mjs.map +1 -0
  368. package/{common-Cj8TaQ9U.js → common-DZl3ADJs.js} +9 -9
  369. package/common-DZl3ADJs.js.map +1 -0
  370. package/common.cjs +7 -7
  371. package/common.d.ts +1 -1
  372. package/common.mjs +7 -7
  373. package/{dispatch_runner-DPcS7Y_M.mjs → dispatch_runner--ZhdDWRZ.mjs} +27 -5
  374. package/{dispatch_runner-DPcS7Y_M.mjs.map → dispatch_runner--ZhdDWRZ.mjs.map} +1 -1
  375. package/{dispatch_runner-BHBNupqp.js → dispatch_runner-nHDKkxye.js} +27 -5
  376. package/{dispatch_runner-BHBNupqp.js.map → dispatch_runner-nHDKkxye.js.map} +1 -1
  377. package/dispatch_runner.cjs +1 -1
  378. package/dispatch_runner.d.ts +1 -1
  379. package/dispatch_runner.mjs +1 -1
  380. package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs +1 -0
  381. package/eslint/rules/artifact_tool_forbids_artifact_constructor.cjs.map +1 -1
  382. package/eslint/rules/artifact_tool_forbids_artifact_constructor.d.ts +1 -0
  383. package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs +1 -0
  384. package/eslint/rules/artifact_tool_forbids_artifact_constructor.mjs.map +1 -1
  385. package/eslint/rules/no_model_in_tool_handler.cjs +1 -0
  386. package/eslint/rules/no_model_in_tool_handler.cjs.map +1 -1
  387. package/eslint/rules/no_model_in_tool_handler.d.ts +1 -0
  388. package/eslint/rules/no_model_in_tool_handler.mjs +1 -0
  389. package/eslint/rules/no_model_in_tool_handler.mjs.map +1 -1
  390. package/eslint/rules/require_validator_any_required.cjs +1 -0
  391. package/eslint/rules/require_validator_any_required.cjs.map +1 -1
  392. package/eslint/rules/require_validator_any_required.d.ts +1 -0
  393. package/eslint/rules/require_validator_any_required.mjs +1 -0
  394. package/eslint/rules/require_validator_any_required.mjs.map +1 -1
  395. package/eslint/rules/thought_payload_requires_replay_tag.cjs +1 -0
  396. package/eslint/rules/thought_payload_requires_replay_tag.cjs.map +1 -1
  397. package/eslint/rules/thought_payload_requires_replay_tag.d.ts +1 -0
  398. package/eslint/rules/thought_payload_requires_replay_tag.mjs +1 -0
  399. package/eslint/rules/thought_payload_requires_replay_tag.mjs.map +1 -1
  400. package/eslint/rules/token_encoding_requires_context_window.cjs +1 -0
  401. package/eslint/rules/token_encoding_requires_context_window.cjs.map +1 -1
  402. package/eslint/rules/token_encoding_requires_context_window.d.ts +1 -0
  403. package/eslint/rules/token_encoding_requires_context_window.mjs +1 -0
  404. package/eslint/rules/token_encoding_requires_context_window.mjs.map +1 -1
  405. package/eslint.cjs +1 -1
  406. package/eslint.mjs +1 -1
  407. package/{exceptions-BeWH2FwP.mjs → exceptions-BDhN0Xzr.mjs} +3 -2
  408. package/exceptions-BDhN0Xzr.mjs.map +1 -0
  409. package/{exceptions-CitH5wZI.js → exceptions-BRXrUKiW.js} +3 -2
  410. package/exceptions-BRXrUKiW.js.map +1 -0
  411. package/exceptions.cjs +2 -2
  412. package/exceptions.mjs +2 -2
  413. package/factories.cjs +1 -1
  414. package/factories.mjs +1 -1
  415. package/forge.cjs +4 -4
  416. package/forge.d.ts +1 -1
  417. package/forge.mjs +4 -4
  418. package/guards.cjs +9 -9
  419. package/guards.mjs +9 -9
  420. package/helpers-DSTFxTiC.js +497 -0
  421. package/helpers-DSTFxTiC.js.map +1 -0
  422. package/helpers-xhrQbMAG.mjs +306 -0
  423. package/helpers-xhrQbMAG.mjs.map +1 -0
  424. package/index.cjs +13 -13
  425. package/index.mjs +13 -13
  426. package/lib/classes/base_exception.d.ts +1 -0
  427. package/lib/classes/media.d.ts +10 -0
  428. package/lib/classes/retrievable.d.ts +1 -1
  429. package/lib/classes/spooled_json_artifact.d.ts +1 -1
  430. package/lib/classes/spooled_markdown_artifact.d.ts +1 -0
  431. package/lib/classes/tokenizable.d.ts +3 -0
  432. package/lib/classes/tool.d.ts +8 -0
  433. package/lib/classes/turn_gate.d.ts +6 -0
  434. package/lib/dispatch_runner.d.ts +4 -32
  435. package/lib/helpers/bignum.cjs +82 -0
  436. package/lib/helpers/bignum.cjs.map +1 -0
  437. package/lib/helpers/bignum.d.ts +52 -0
  438. package/lib/helpers/bignum.mjs +74 -0
  439. package/lib/helpers/bignum.mjs.map +1 -0
  440. package/lib/turn_runner.d.ts +1 -1
  441. package/lib/types/dispatch_runner.d.ts +83 -0
  442. package/lib/utils/exceptions.d.ts +1 -1
  443. package/lib/utils/retry.cjs.map +1 -1
  444. package/lib/utils/retry.d.ts +2 -0
  445. package/lib/utils/retry.mjs.map +1 -1
  446. package/mcp/adk-docs-corpus.json +1 -1
  447. package/package.json +264 -224
  448. package/{runtime-j92CNi5z.mjs → runtime-Bz5zA8wc.mjs} +2 -2
  449. package/{runtime-j92CNi5z.mjs.map → runtime-Bz5zA8wc.mjs.map} +1 -1
  450. package/{runtime-MFFcJrRv.js → runtime-DslE1aBw.js} +2 -2
  451. package/{runtime-MFFcJrRv.js.map → runtime-DslE1aBw.js.map} +1 -1
  452. package/searxng-Bkrwhwhw.js +269 -0
  453. package/searxng-Bkrwhwhw.js.map +1 -0
  454. package/searxng-CyA-nEu5.mjs +257 -0
  455. package/searxng-CyA-nEu5.mjs.map +1 -0
  456. package/skills/adk-assembly/SKILL.md +2 -2
  457. package/{spooled_artifact-CHoZgWwI.mjs → spooled_artifact-7eePq7JA.mjs} +5 -5
  458. package/{spooled_artifact-CHoZgWwI.mjs.map → spooled_artifact-7eePq7JA.mjs.map} +1 -1
  459. package/{spooled_artifact-BTq6Nzfy.js → spooled_artifact-DX8LLyUX.js} +5 -5
  460. package/{spooled_artifact-BTq6Nzfy.js.map → spooled_artifact-DX8LLyUX.js.map} +1 -1
  461. package/spooled_artifact.cjs +2 -2
  462. package/spooled_artifact.mjs +2 -2
  463. package/{spooled_markdown_artifact-CALSDxIx.js → spooled_markdown_artifact-ClX72lek.js} +4 -4
  464. package/spooled_markdown_artifact-ClX72lek.js.map +1 -0
  465. package/{spooled_markdown_artifact-Ci5UL7l4.mjs → spooled_markdown_artifact-wkrBF3oX.mjs} +4 -4
  466. package/spooled_markdown_artifact-wkrBF3oX.mjs.map +1 -0
  467. package/{thought-D34QQZZ9.mjs → thought-B_vxAiKU.mjs} +5 -5
  468. package/{thought-D34QQZZ9.mjs.map → thought-B_vxAiKU.mjs.map} +1 -1
  469. package/{thought-BbwhJ1wb.js → thought-DLwpF7MI.js} +5 -5
  470. package/{thought-BbwhJ1wb.js.map → thought-DLwpF7MI.js.map} +1 -1
  471. package/{tool-CVyZkFC7.js → tool-D5WGVIcI.js} +4 -4
  472. package/{tool-CVyZkFC7.js.map → tool-D5WGVIcI.js.map} +1 -1
  473. package/{tool-CMhaDRNd.mjs → tool-wMYMVl60.mjs} +4 -4
  474. package/{tool-CMhaDRNd.mjs.map → tool-wMYMVl60.mjs.map} +1 -1
  475. package/{tool_call-CV5qVNlb.mjs → tool_call-B4-_-vjG.mjs} +5 -5
  476. package/tool_call-B4-_-vjG.mjs.map +1 -0
  477. package/{tool_call-Db68hB7y.js → tool_call-DixVlW40.js} +5 -5
  478. package/tool_call-DixVlW40.js.map +1 -0
  479. package/{tool_registry-D1pSSlsd.mjs → tool_registry-791Vrjtf.mjs} +4 -3
  480. package/tool_registry-791Vrjtf.mjs.map +1 -0
  481. package/{tool_registry-DYUYqXvo.js → tool_registry-CKJPze3j.js} +4 -3
  482. package/tool_registry-CKJPze3j.js.map +1 -0
  483. package/{turn_runner-DqWHNP80.js → turn_runner-HXImLGIn.js} +7 -7
  484. package/turn_runner-HXImLGIn.js.map +1 -0
  485. package/{turn_runner-fg1Wc3dK.mjs → turn_runner-ZyYO-Kti.mjs} +7 -7
  486. package/turn_runner-ZyYO-Kti.mjs.map +1 -0
  487. package/turn_runner.cjs +1 -1
  488. package/turn_runner.mjs +1 -1
  489. package/types.d.ts +1 -1
  490. package/common-BT0nfCi9.mjs.map +0 -1
  491. package/common-Cj8TaQ9U.js.map +0 -1
  492. package/exceptions-BeWH2FwP.mjs.map +0 -1
  493. package/exceptions-CitH5wZI.js.map +0 -1
  494. package/spooled_markdown_artifact-CALSDxIx.js.map +0 -1
  495. package/spooled_markdown_artifact-Ci5UL7l4.mjs.map +0 -1
  496. package/tool_call-CV5qVNlb.mjs.map +0 -1
  497. package/tool_call-Db68hB7y.js.map +0 -1
  498. package/tool_registry-D1pSSlsd.mjs.map +0 -1
  499. package/tool_registry-DYUYqXvo.js.map +0 -1
  500. package/turn_runner-DqWHNP80.js.map +0 -1
  501. package/turn_runner-fg1Wc3dK.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"opfs.cjs","names":["#handle","#threshold","#load","#readRange","#ready","#init","#buildStreamingIndex","#resolveRoot","#prefix","#defaultThreshold","#keyFor","#getRoot","#writeStreamViaSyncHandle","#writeStreamViaWritable","#writeViaSyncHandle","#writeViaWritable","#isNotFoundError","#root"],"sources":["../../../src/batteries/storage/opfs/index.ts"],"sourcesContent":["/**\n * Browser-only Origin Private File System storage for spooled artifacts.\n *\n * @module @nhtio/adk/batteries/storage/opfs\n *\n * @remarks\n * Opt-in **browser-only** storage battery backed by the\n * [Origin Private File System](https://developer.mozilla.org/docs/Web/API/File_System_API/Origin_private_file_system)\n * (OPFS). Provides {@link OpfsSpoolReader} (a {@link @nhtio/adk!SpoolReader} over a `OpfsFileHandle`)\n * and {@link OpfsSpoolStore} (a `write(callId, bytes) → reader` persistence layer that wraps an\n * OPFS directory).\n *\n * The reader has two modes selected lazily on first method invocation based on the size of the\n * underlying file:\n *\n * - **Eager mode** — when `file.size` is below `streamThresholdBytes` (default 10 MiB), the\n * reader calls `file.text()` once, splits the content on `\\n`, and caches lines + byte count.\n * All subsequent calls resolve from memory.\n * - **Streaming mode** — when `file.size` meets or exceeds the threshold, the reader streams the\n * file once via `file.stream().getReader()` to build a line-offset index (`number[]` of byte\n * offsets per line), then serves each `line(i)` request by slicing the underlying `Blob` —\n * `Blob.slice(start, end).text()` decodes only the requested range, no head-of-file scan.\n * Caps RAM at one index + one line buffer regardless of file size.\n *\n * The store auto-selects its write API by execution scope:\n *\n * - In **worker scopes** (`self instanceof WorkerGlobalScope`), it acquires a\n * `FileSystemSyncAccessHandle` and writes synchronously. Sync handles are the only API\n * available in workers and the fastest path for the spool-write hot path.\n * - On the **main thread**, it uses `OpfsFileHandle.createWritable()` and the async\n * stream API. Sync access handles are not exposed on the main thread.\n *\n * This module assumes a browser-equivalent runtime — `navigator.storage`,\n * `OpfsFileHandle`, `TextEncoder`/`TextDecoder`, and `Blob` must all exist. It must not\n * be imported from Node code; do so and you will fail at resolve time when `navigator` is\n * referenced.\n *\n * @example\n * ```ts\n * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'\n *\n * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })\n * const reader = await store.write(callId, bytes)\n * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact\n * const artifact = new Ctor(reader)\n * ```\n */\n\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport type { SpoolReader, SpoolStore } from '@nhtio/adk/common'\n\n// The project's tsconfig limits `lib` to `ESNext`, so the DOM and File System Access types\n// referenced below are not in scope by default — neither `tsc --noEmit` nor the downstream dts\n// pipeline (api-extractor) can see them. Re-declare here the **minimum** surface this module\n// touches via a local handle-shape interface. Public API uses `OpfsFileHandle` /\n// `OpfsDirectoryHandle` instead of the DOM globals so the published `.d.ts` is self-contained\n// and consumers do not have to chase the lib graph.\n\n/**\n * Minimal subset of the\n * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)\n * `OpfsFileHandle` interface that this module touches at runtime. Structurally compatible\n * with the DOM-lib `OpfsFileHandle` — at call sites you pass real OPFS handles directly.\n */\nexport interface OpfsFileHandle {\n readonly kind: 'file'\n readonly name: string\n getFile(): Promise<OpfsFile>\n createWritable(): Promise<OpfsWritableFileStream>\n}\n\n/**\n * Minimal subset of the\n * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)\n * `OpfsDirectoryHandle` interface that this module touches at runtime. Structurally\n * compatible with the DOM-lib `OpfsDirectoryHandle` — at call sites you pass real OPFS\n * handles directly.\n */\nexport interface OpfsDirectoryHandle {\n readonly kind: 'directory'\n readonly name: string\n getFileHandle(name: string, options?: { create?: boolean }): Promise<OpfsFileHandle>\n getDirectoryHandle(name: string, options?: { create?: boolean }): Promise<OpfsDirectoryHandle>\n removeEntry(name: string, options?: { recursive?: boolean }): Promise<void>\n}\n\n/**\n * Minimal subset of the DOM `FileSystemWritableFileStream` interface used by the OPFS battery's\n * main-thread write path.\n */\nexport interface OpfsWritableFileStream {\n write(data: Uint8Array | ArrayBufferView | ArrayBuffer | string): Promise<void>\n close(): Promise<void>\n}\n\n/**\n * Minimal subset of the DOM `Blob` interface used by {@link OpfsSpoolReader} streaming-mode\n * random-access reads. Real OPFS handles return a `File` here; we narrow to the methods we\n * actually call.\n */\nexport interface OpfsBlob {\n readonly size: number\n slice(start?: number, end?: number, contentType?: string): OpfsBlob\n text(): Promise<string>\n stream(): OpfsReadableStream\n}\n\n/**\n * Minimal subset of the DOM `File` interface used by {@link OpfsSpoolReader}.\n */\nexport interface OpfsFile extends OpfsBlob {\n readonly name: string\n}\n\n/**\n * Minimal subset of the DOM `ReadableStream<Uint8Array>` interface used by streaming-mode\n * index construction.\n */\nexport interface OpfsReadableStream {\n getReader(): OpfsReadableStreamReader\n}\n\n/**\n * Minimal subset of the DOM `ReadableStreamDefaultReader<Uint8Array>` interface used by\n * streaming-mode index construction.\n */\nexport interface OpfsReadableStreamReader {\n read(): Promise<{ done: false; value: Uint8Array } | { done: true; value: undefined }>\n releaseLock(): void\n}\n\ndeclare const navigator: {\n storage: { getDirectory(): Promise<OpfsDirectoryHandle> }\n}\ndeclare class TextEncoder {\n encode(input?: string): Uint8Array\n}\ndeclare const self: unknown\ndeclare const WorkerGlobalScope: { new (): unknown } | undefined\n\ninterface FileSystemSyncAccessHandle {\n truncate(newSize: number): void\n write(buffer: Uint8Array | ArrayBuffer | ArrayBufferView, options?: { at?: number }): number\n flush(): void\n close(): void\n}\ninterface OpfsFileHandleWithSyncAccess extends OpfsFileHandle {\n createSyncAccessHandle(): Promise<FileSystemSyncAccessHandle>\n}\n\nconst DEFAULT_STREAM_THRESHOLD_BYTES = 10 * 1024 * 1024 // 10 MiB\n\nconst LF = 0x0a // '\\n'\n\nconst isNonNegativeFiniteNumber = (n: unknown): n is number =>\n typeof n === 'number' && Number.isFinite(n) && n >= 0\n\n/**\n * Constructor options for {@link OpfsSpoolReader}.\n */\nexport interface OpfsSpoolReaderOptions {\n /**\n * Byte-length threshold that switches between eager and streaming modes.\n *\n * @remarks\n * - Below the threshold → eager (whole-file in memory).\n * - At or above the threshold → streaming (line-offset index + per-line slice reads).\n *\n * Set to `0` to force streaming mode; set to `Number.POSITIVE_INFINITY` to force eager mode.\n *\n * @defaultValue `10 * 1024 * 1024` (10 MiB)\n */\n streamThresholdBytes?: number\n}\n\ninterface EagerState {\n mode: 'eager'\n lines: string[]\n bytes: number\n content: string\n}\n\ninterface StreamingState {\n mode: 'streaming'\n file: OpfsFile\n /**\n * Byte offsets where each line *starts*. Length equals lineCount + 1; the final entry equals\n * the total byte length. So `offsets[i + 1] - offsets[i]` is the byte length of line `i`\n * including any trailing `\\n`.\n */\n offsets: number[]\n bytes: number\n}\n\ntype ReaderState = EagerState | StreamingState\n\n/**\n * Returns `true` when the current global scope is a Web Worker (`DedicatedWorkerGlobalScope`,\n * `SharedWorkerGlobalScope`, or `ServiceWorkerGlobalScope` all inherit from `WorkerGlobalScope`).\n *\n * @remarks\n * The check is needed at runtime because `FileSystemSyncAccessHandle` is only exposed in worker\n * scopes — calling it from the main thread throws. We pick the write strategy based on the\n * answer here.\n *\n * @internal\n */\nconst isWorkerScope = (): boolean => {\n if (typeof WorkerGlobalScope === 'undefined') return false\n // eslint-disable-next-line adk/use-is-instance-of -- native built-in narrowing on `self`; no cross-realm risk\n return self instanceof WorkerGlobalScope\n}\n\n/**\n * Reads an OPFS-backed file as a {@link @nhtio/adk!SpoolReader}.\n *\n * @remarks\n * Constructor is **not** async — but the first method call awaits a private readiness promise\n * that fetches the underlying `File` (and in eager mode, its contents). Subsequent calls reuse\n * the cached state. This keeps construction call sites synchronous while still doing real I/O\n * lazily.\n *\n * All four `SpoolReader` methods on this reader return promises. The `SpoolReader` contract\n * supports both sync and async return; consumers of `SpooledArtifact` handle either.\n */\nexport class OpfsSpoolReader implements SpoolReader {\n readonly #handle: OpfsFileHandle\n readonly #threshold: number\n #ready: Promise<ReaderState> | undefined\n\n constructor(handle: OpfsFileHandle, opts: OpfsSpoolReaderOptions = {}) {\n this.#handle = handle\n const raw = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES\n // Allow `Infinity` (forces eager) but reject anything non-finite-negative.\n if (typeof raw !== 'number' || Number.isNaN(raw) || raw < 0) {\n throw new TypeError(\n `OpfsSpoolReader: streamThresholdBytes must be a non-negative number or Infinity, got ${String(raw)}`\n )\n }\n this.#threshold = raw\n }\n\n /**\n * Returns `true` if `value` is an {@link OpfsSpoolReader} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is an {@link OpfsSpoolReader} instance.\n */\n public static isOpfsSpoolReader(value: unknown): value is OpfsSpoolReader {\n return isInstanceOf(value, 'OpfsSpoolReader', OpfsSpoolReader)\n }\n\n async line(index: number): Promise<string | undefined> {\n const state = await this.#load()\n if (state.mode === 'eager') return state.lines[index]\n if (index < 0 || index >= state.offsets.length - 1) return undefined\n return this.#readRange(state.file, state.offsets[index], state.offsets[index + 1])\n }\n\n async byteLength(): Promise<number> {\n const state = await this.#load()\n return state.bytes\n }\n\n async lineCount(): Promise<number> {\n const state = await this.#load()\n return state.mode === 'eager' ? state.lines.length : state.offsets.length - 1\n }\n\n /**\n * Returns the full underlying content as a single decoded string, byte-faithful to the source.\n *\n * @remarks\n * In **eager mode** the content is already cached at first-call load and this method is\n * effectively a property access. In **streaming mode** there is no cache: the file is re-read\n * (as a single `File.text()` call) on every invocation. Use `SpooledArtifact.asString()`\n * judiciously on large streaming-mode artifacts.\n */\n async readAll(): Promise<string> {\n const state = await this.#load()\n if (state.mode === 'eager') return state.content\n return state.file.text()\n }\n\n /**\n * Lazily initialise the reader's mode-specific state. Called by every public method; the\n * promise is cached so the work runs at most once.\n */\n #load(): Promise<ReaderState> {\n if (!this.#ready) this.#ready = this.#init()\n return this.#ready\n }\n\n async #init(): Promise<ReaderState> {\n const file = await this.#handle.getFile()\n const bytes = file.size\n if (!isNonNegativeFiniteNumber(bytes)) {\n throw new Error(`OpfsSpoolReader: file handle returned a non-finite size (${String(bytes)})`)\n }\n if (bytes < this.#threshold) {\n // Eager — pull the whole thing into memory.\n const content = await file.text()\n const lines = content === '' ? [] : content.split('\\n')\n return { mode: 'eager', lines, bytes, content }\n }\n // Streaming — build a line-offset index by scanning bytes once.\n return this.#buildStreamingIndex(file, bytes)\n }\n\n async #buildStreamingIndex(file: OpfsFile, bytes: number): Promise<StreamingState> {\n // Edge case first — an empty file is one offset (the EOF), zero lines.\n if (bytes === 0) return { mode: 'streaming', file, offsets: [0], bytes }\n\n // offsets[i] is the byte position where line `i` starts. offsets[lineCount] is one-past-end.\n // For \"a\\nb\\nc\" → offsets=[0, 2, 4, 5] (3 lines).\n // For \"a\\nb\\n\" → offsets=[0, 2, 4, 4] (3 lines, last is the trailing empty line). This\n // mirrors `String.prototype.split('\\n')` semantics so streaming and eager agree.\n const offsets: number[] = [0]\n let position = 0\n let lastByte = -1\n const reader = file.stream().getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n for (const byte of value) {\n position++\n if (byte === LF) offsets.push(position)\n lastByte = byte\n }\n }\n } finally {\n reader.releaseLock()\n }\n // If the file ends on a newline, the byte after the LF is the start of an empty trailing\n // line — record it. If it doesn't, the final line's end is the EOF and we need to push\n // it so line(N-1) can read up to bytes.\n if (lastByte === LF) offsets.push(position)\n else if (offsets[offsets.length - 1] !== position) offsets.push(position)\n return { mode: 'streaming', file, offsets, bytes }\n }\n\n /**\n * Slices the byte range `[start, end)` from the backing file and returns it as a UTF-8\n * string, stripping a trailing `\\n` if present.\n *\n * @remarks\n * `Blob.slice` is O(1) metadata; `Blob.text()` only decodes the slice. The line-offset index\n * brackets each line *with* its trailing LF (so `offsets[i+1]` points at the start of the\n * next line) and the `SpoolReader` contract returns lines *without* their trailing newline,\n * so we strip a single trailing LF if present.\n */\n async #readRange(file: OpfsFile, start: number, end: number): Promise<string> {\n if (start === end) return ''\n const slice = file.slice(start, end)\n const text = await slice.text()\n if (text.length > 0 && text.charCodeAt(text.length - 1) === LF) {\n return text.slice(0, -1)\n }\n return text\n }\n}\n\n/**\n * Constructor options for {@link OpfsSpoolStore}.\n */\nexport interface OpfsSpoolStoreOptions {\n /**\n * Optional thunk that resolves the {@link OpfsDirectoryHandle} used as the store root.\n *\n * @remarks\n * When omitted, the store resolves the root via `navigator.storage.getDirectory()` on its\n * first filesystem call. Override for tests (to point at a per-suite subdirectory) or to\n * scope the store to a nested directory inside OPFS.\n *\n * The thunk is invoked at most once per store; the returned handle is memoised.\n */\n directory?: () => Promise<OpfsDirectoryHandle>\n\n /**\n * Optional filename prefix prepended to every `callId`.\n *\n * @remarks\n * Prefix is a **filename prefix**, not a subdirectory — `keyPrefix: 'agent-runs/'` produces\n * a file literally named `agent-runs/<callId>` at the root, not a nested directory. (OPFS\n * filenames may not contain `/`, so use a non-`/` separator like `-` if you want a flat\n * namespace.) This mirrors the `keyPrefix` semantics in the flydrive and in-memory batteries.\n *\n * @defaultValue `\"\"`\n */\n keyPrefix?: string\n\n /**\n * Default `streamThresholdBytes` for readers produced by `write()` and `read()`. Individual\n * calls may override via their own `opts` argument.\n *\n * @defaultValue `10 * 1024 * 1024` (10 MiB)\n */\n streamThresholdBytes?: number\n}\n\n/**\n * \"Give bytes, get a reader\" persistence layer over an OPFS directory.\n *\n * @remarks\n * `write(callId, bytes)` resolves the root directory (lazily, on first call), opens or creates\n * the file named `keyPrefix + callId`, then writes via the API matching the current scope:\n * a `FileSystemSyncAccessHandle` in worker scopes, `OpfsFileHandle.createWritable()` on\n * the main thread. A fresh {@link OpfsSpoolReader} pointed at the same file is returned.\n *\n * `read(callId)` returns a reader without re-writing; `delete(callId)` removes the entry.\n *\n * The store is otherwise stateless — it owns no in-memory cache of writes. Multiple\n * `OpfsSpoolStore` instances sharing the same root directory and key prefix see the same data.\n *\n * @example\n * ```ts\n * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'\n *\n * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })\n *\n * const bytes = await tool.executor(ctx)(args)\n * const reader = await store.write(callId, bytes)\n * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact\n * const artifact = new Ctor(reader)\n * ```\n */\nexport class OpfsSpoolStore implements SpoolStore {\n readonly #resolveRoot: () => Promise<OpfsDirectoryHandle>\n readonly #prefix: string\n readonly #defaultThreshold: number\n #root: OpfsDirectoryHandle | undefined\n\n constructor(opts: OpfsSpoolStoreOptions = {}) {\n this.#resolveRoot = opts.directory ?? (() => navigator.storage.getDirectory())\n this.#prefix = opts.keyPrefix ?? ''\n this.#defaultThreshold = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES\n }\n\n /**\n * Returns `true` if `value` is an {@link OpfsSpoolStore} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is an {@link OpfsSpoolStore} instance.\n */\n public static isOpfsSpoolStore(value: unknown): value is OpfsSpoolStore {\n return isInstanceOf(value, 'OpfsSpoolStore', OpfsSpoolStore)\n }\n\n /**\n * Persists `bytes` under `callId` and returns a reader bound to the stored key.\n *\n * @remarks\n * `string` input is encoded as UTF-8; `Uint8Array` is stored byte-faithfully;\n * `ReadableStream<Uint8Array>` is written incrementally — the stream is consumed chunk-by-chunk\n * straight to OPFS without first materializing the whole payload in memory, which is the point\n * of accepting a stream for a durable store.\n *\n * @param callId - Identifier used to retrieve the bytes via {@link OpfsSpoolStore.read}.\n * @param bytes - The bytes to store, as a `string`, `Uint8Array`, or `ReadableStream<Uint8Array>`.\n * @param opts - Per-call override for `streamThresholdBytes`.\n * @returns An {@link OpfsSpoolReader} over the stored bytes.\n */\n async write(\n callId: string,\n bytes: string | Uint8Array | ReadableStream<Uint8Array>,\n opts?: OpfsSpoolReaderOptions\n ): Promise<OpfsSpoolReader> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n const handle = await root.getFileHandle(name, { create: true })\n if (isInstanceOf(bytes, 'ReadableStream', ReadableStream)) {\n if (isWorkerScope()) {\n await this.#writeStreamViaSyncHandle(handle, bytes)\n } else {\n await this.#writeStreamViaWritable(handle, bytes)\n }\n } else {\n const payload = typeof bytes === 'string' ? new TextEncoder().encode(bytes) : bytes\n if (isWorkerScope()) {\n await this.#writeViaSyncHandle(handle, payload)\n } else {\n await this.#writeViaWritable(handle, payload)\n }\n }\n return new OpfsSpoolReader(handle, {\n streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold,\n })\n }\n\n /**\n * Returns a reader over the bytes previously written under `callId`.\n *\n * @remarks\n * Returns `undefined` if the file does not exist.\n *\n * @param callId - Identifier supplied to a prior {@link OpfsSpoolStore.write} call.\n * @param opts - Per-call override for `streamThresholdBytes`.\n * @returns An {@link OpfsSpoolReader}, or `undefined` if the key is missing.\n */\n async read(callId: string, opts?: OpfsSpoolReaderOptions): Promise<OpfsSpoolReader | undefined> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n let handle: OpfsFileHandle\n try {\n handle = await root.getFileHandle(name)\n } catch (err) {\n if (this.#isNotFoundError(err)) return undefined\n throw err\n }\n return new OpfsSpoolReader(handle, {\n streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold,\n })\n }\n\n /**\n * Removes the entry under `callId`.\n *\n * @param callId - Identifier whose entry should be removed.\n * @returns `true` if the entry existed and was removed; `false` if it didn't exist.\n */\n async delete(callId: string): Promise<boolean> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n try {\n await root.removeEntry(name)\n return true\n } catch (err) {\n if (this.#isNotFoundError(err)) return false\n throw err\n }\n }\n\n /**\n * Returns `true` if a file is present under `callId`.\n *\n * @param callId - Identifier to test.\n * @returns `true` when the file exists, `false` otherwise.\n */\n async has(callId: string): Promise<boolean> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n try {\n await root.getFileHandle(name)\n return true\n } catch (err) {\n if (this.#isNotFoundError(err)) return false\n throw err\n }\n }\n\n /**\n * Returns the full filename for a given `callId` (i.e. `keyPrefix + callId`).\n *\n * @remarks\n * Useful for tests or for callers that want to interact with the underlying OPFS directory\n * directly.\n */\n keyFor(callId: string): string {\n return this.#keyFor(callId)\n }\n\n #keyFor(callId: string): string {\n return this.#prefix + callId\n }\n\n async #getRoot(): Promise<OpfsDirectoryHandle> {\n if (!this.#root) this.#root = await this.#resolveRoot()\n return this.#root\n }\n\n async #writeViaSyncHandle(handle: OpfsFileHandle, payload: Uint8Array): Promise<void> {\n const sync = await (handle as OpfsFileHandleWithSyncAccess).createSyncAccessHandle()\n try {\n sync.truncate(0)\n sync.write(payload, { at: 0 })\n sync.flush()\n } finally {\n sync.close()\n }\n }\n\n async #writeViaWritable(handle: OpfsFileHandle, payload: Uint8Array): Promise<void> {\n const writable = await handle.createWritable()\n try {\n await writable.write(payload)\n } finally {\n await writable.close()\n }\n }\n\n async #writeStreamViaWritable(\n handle: OpfsFileHandle,\n stream: ReadableStream<Uint8Array>\n ): Promise<void> {\n const writable = await handle.createWritable()\n try {\n const reader = stream.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (value) await writable.write(value)\n }\n } finally {\n reader.releaseLock()\n }\n } finally {\n await writable.close()\n }\n }\n\n async #writeStreamViaSyncHandle(\n handle: OpfsFileHandle,\n stream: ReadableStream<Uint8Array>\n ): Promise<void> {\n const sync = await (handle as OpfsFileHandleWithSyncAccess).createSyncAccessHandle()\n try {\n sync.truncate(0)\n let at = 0\n const reader = stream.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (value && value.byteLength > 0) {\n sync.write(value, { at })\n at += value.byteLength\n }\n }\n } finally {\n reader.releaseLock()\n }\n sync.flush()\n } finally {\n sync.close()\n }\n }\n\n #isNotFoundError(err: unknown): boolean {\n if (err === null || typeof err !== 'object') return false\n const name = (err as { name?: unknown }).name\n return name === 'NotFoundError'\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsJA,IAAM,iCAAiC,KAAK,OAAO;AAEnD,IAAM,KAAK;AAEX,IAAM,6BAA6B,MACjC,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,KAAK;;;;;;;;;;;;AAoDtD,IAAM,sBAA+B;CACnC,IAAI,OAAO,sBAAsB,aAAa,OAAO;CAErD,OAAO,gBAAgB;AACzB;;;;;;;;;;;;;AAcA,IAAa,kBAAb,MAAa,gBAAuC;CAClD;CACA;CACA;CAEA,YAAY,QAAwB,OAA+B,CAAC,GAAG;EACrE,KAAKA,UAAU;EACf,MAAM,MAAM,KAAK,wBAAwB;EAEzC,IAAI,OAAO,QAAQ,YAAY,OAAO,MAAM,GAAG,KAAK,MAAM,GACxD,MAAM,IAAI,UACR,wFAAwF,OAAO,GAAG,GACpG;EAEF,KAAKC,aAAa;CACpB;;;;;;;;;;CAWA,OAAc,kBAAkB,OAA0C;EACxE,OAAO,sBAAA,aAAa,OAAO,mBAAmB,eAAe;CAC/D;CAEA,MAAM,KAAK,OAA4C;EACrD,MAAM,QAAQ,MAAM,KAAKC,MAAM;EAC/B,IAAI,MAAM,SAAS,SAAS,OAAO,MAAM,MAAM;EAC/C,IAAI,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,GAAG,OAAO,KAAA;EAC3D,OAAO,KAAKC,WAAW,MAAM,MAAM,MAAM,QAAQ,QAAQ,MAAM,QAAQ,QAAQ,EAAE;CACnF;CAEA,MAAM,aAA8B;EAElC,QAAO,MADa,KAAKD,MAAM,GAClB;CACf;CAEA,MAAM,YAA6B;EACjC,MAAM,QAAQ,MAAM,KAAKA,MAAM;EAC/B,OAAO,MAAM,SAAS,UAAU,MAAM,MAAM,SAAS,MAAM,QAAQ,SAAS;CAC9E;;;;;;;;;;CAWA,MAAM,UAA2B;EAC/B,MAAM,QAAQ,MAAM,KAAKA,MAAM;EAC/B,IAAI,MAAM,SAAS,SAAS,OAAO,MAAM;EACzC,OAAO,MAAM,KAAK,KAAK;CACzB;;;;;CAMA,QAA8B;EAC5B,IAAI,CAAC,KAAKE,QAAQ,KAAKA,SAAS,KAAKC,MAAM;EAC3C,OAAO,KAAKD;CACd;CAEA,MAAMC,QAA8B;EAClC,MAAM,OAAO,MAAM,KAAKL,QAAQ,QAAQ;EACxC,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,0BAA0B,KAAK,GAClC,MAAM,IAAI,MAAM,4DAA4D,OAAO,KAAK,EAAE,EAAE;EAE9F,IAAI,QAAQ,KAAKC,YAAY;GAE3B,MAAM,UAAU,MAAM,KAAK,KAAK;GAEhC,OAAO;IAAE,MAAM;IAAS,OADV,YAAY,KAAK,CAAC,IAAI,QAAQ,MAAM,IAAI;IACvB;IAAO;GAAQ;EAChD;EAEA,OAAO,KAAKK,qBAAqB,MAAM,KAAK;CAC9C;CAEA,MAAMA,qBAAqB,MAAgB,OAAwC;EAEjF,IAAI,UAAU,GAAG,OAAO;GAAE,MAAM;GAAa;GAAM,SAAS,CAAC,CAAC;GAAG;EAAM;EAMvE,MAAM,UAAoB,CAAC,CAAC;EAC5B,IAAI,WAAW;EACf,IAAI,WAAW;EACf,MAAM,SAAS,KAAK,OAAO,EAAE,UAAU;EACvC,IAAI;GACF,SAAS;IACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;IAC1C,IAAI,MAAM;IACV,KAAK,MAAM,QAAQ,OAAO;KACxB;KACA,IAAI,SAAS,IAAI,QAAQ,KAAK,QAAQ;KACtC,WAAW;IACb;GACF;EACF,UAAU;GACR,OAAO,YAAY;EACrB;EAIA,IAAI,aAAa,IAAI,QAAQ,KAAK,QAAQ;OACrC,IAAI,QAAQ,QAAQ,SAAS,OAAO,UAAU,QAAQ,KAAK,QAAQ;EACxE,OAAO;GAAE,MAAM;GAAa;GAAM;GAAS;EAAM;CACnD;;;;;;;;;;;CAYA,MAAMH,WAAW,MAAgB,OAAe,KAA8B;EAC5E,IAAI,UAAU,KAAK,OAAO;EAE1B,MAAM,OAAO,MADC,KAAK,MAAM,OAAO,GACb,EAAM,KAAK;EAC9B,IAAI,KAAK,SAAS,KAAK,KAAK,WAAW,KAAK,SAAS,CAAC,MAAM,IAC1D,OAAO,KAAK,MAAM,GAAG,EAAE;EAEzB,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkEA,IAAa,iBAAb,MAAa,eAAqC;CAChD;CACA;CACA;CACA;CAEA,YAAY,OAA8B,CAAC,GAAG;EAC5C,KAAKI,eAAe,KAAK,oBAAoB,UAAU,QAAQ,aAAa;EAC5E,KAAKC,UAAU,KAAK,aAAa;EACjC,KAAKC,oBAAoB,KAAK,wBAAwB;CACxD;;;;;;;;;;CAWA,OAAc,iBAAiB,OAAyC;EACtE,OAAO,sBAAA,aAAa,OAAO,kBAAkB,cAAc;CAC7D;;;;;;;;;;;;;;;CAgBA,MAAM,MACJ,QACA,OACA,MAC0B;EAC1B,MAAM,OAAO,KAAKC,QAAQ,MAAM;EAEhC,MAAM,SAAS,OAAM,MADF,KAAKC,SAAS,GACP,cAAc,MAAM,EAAE,QAAQ,KAAK,CAAC;EAC9D,IAAI,sBAAA,aAAa,OAAO,kBAAkB,cAAc,GACtD,IAAI,cAAc,GAChB,MAAM,KAAKC,0BAA0B,QAAQ,KAAK;OAElD,MAAM,KAAKC,wBAAwB,QAAQ,KAAK;OAE7C;GACL,MAAM,UAAU,OAAO,UAAU,WAAW,IAAI,YAAY,EAAE,OAAO,KAAK,IAAI;GAC9E,IAAI,cAAc,GAChB,MAAM,KAAKC,oBAAoB,QAAQ,OAAO;QAE9C,MAAM,KAAKC,kBAAkB,QAAQ,OAAO;EAEhD;EACA,OAAO,IAAI,gBAAgB,QAAQ,EACjC,sBAAsB,MAAM,wBAAwB,KAAKN,kBAC3D,CAAC;CACH;;;;;;;;;;;CAYA,MAAM,KAAK,QAAgB,MAAqE;EAC9F,MAAM,OAAO,KAAKC,QAAQ,MAAM;EAChC,MAAM,OAAO,MAAM,KAAKC,SAAS;EACjC,IAAI;EACJ,IAAI;GACF,SAAS,MAAM,KAAK,cAAc,IAAI;EACxC,SAAS,KAAK;GACZ,IAAI,KAAKK,iBAAiB,GAAG,GAAG,OAAO,KAAA;GACvC,MAAM;EACR;EACA,OAAO,IAAI,gBAAgB,QAAQ,EACjC,sBAAsB,MAAM,wBAAwB,KAAKP,kBAC3D,CAAC;CACH;;;;;;;CAQA,MAAM,OAAO,QAAkC;EAC7C,MAAM,OAAO,KAAKC,QAAQ,MAAM;EAChC,MAAM,OAAO,MAAM,KAAKC,SAAS;EACjC,IAAI;GACF,MAAM,KAAK,YAAY,IAAI;GAC3B,OAAO;EACT,SAAS,KAAK;GACZ,IAAI,KAAKK,iBAAiB,GAAG,GAAG,OAAO;GACvC,MAAM;EACR;CACF;;;;;;;CAQA,MAAM,IAAI,QAAkC;EAC1C,MAAM,OAAO,KAAKN,QAAQ,MAAM;EAChC,MAAM,OAAO,MAAM,KAAKC,SAAS;EACjC,IAAI;GACF,MAAM,KAAK,cAAc,IAAI;GAC7B,OAAO;EACT,SAAS,KAAK;GACZ,IAAI,KAAKK,iBAAiB,GAAG,GAAG,OAAO;GACvC,MAAM;EACR;CACF;;;;;;;;CASA,OAAO,QAAwB;EAC7B,OAAO,KAAKN,QAAQ,MAAM;CAC5B;CAEA,QAAQ,QAAwB;EAC9B,OAAO,KAAKF,UAAU;CACxB;CAEA,MAAMG,WAAyC;EAC7C,IAAI,CAAC,KAAKM,OAAO,KAAKA,QAAQ,MAAM,KAAKV,aAAa;EACtD,OAAO,KAAKU;CACd;CAEA,MAAMH,oBAAoB,QAAwB,SAAoC;EACpF,MAAM,OAAO,MAAO,OAAwC,uBAAuB;EACnF,IAAI;GACF,KAAK,SAAS,CAAC;GACf,KAAK,MAAM,SAAS,EAAE,IAAI,EAAE,CAAC;GAC7B,KAAK,MAAM;EACb,UAAU;GACR,KAAK,MAAM;EACb;CACF;CAEA,MAAMC,kBAAkB,QAAwB,SAAoC;EAClF,MAAM,WAAW,MAAM,OAAO,eAAe;EAC7C,IAAI;GACF,MAAM,SAAS,MAAM,OAAO;EAC9B,UAAU;GACR,MAAM,SAAS,MAAM;EACvB;CACF;CAEA,MAAMF,wBACJ,QACA,QACe;EACf,MAAM,WAAW,MAAM,OAAO,eAAe;EAC7C,IAAI;GACF,MAAM,SAAS,OAAO,UAAU;GAChC,IAAI;IACF,SAAS;KACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;KAC1C,IAAI,MAAM;KACV,IAAI,OAAO,MAAM,SAAS,MAAM,KAAK;IACvC;GACF,UAAU;IACR,OAAO,YAAY;GACrB;EACF,UAAU;GACR,MAAM,SAAS,MAAM;EACvB;CACF;CAEA,MAAMD,0BACJ,QACA,QACe;EACf,MAAM,OAAO,MAAO,OAAwC,uBAAuB;EACnF,IAAI;GACF,KAAK,SAAS,CAAC;GACf,IAAI,KAAK;GACT,MAAM,SAAS,OAAO,UAAU;GAChC,IAAI;IACF,SAAS;KACP,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;KAC1C,IAAI,MAAM;KACV,IAAI,SAAS,MAAM,aAAa,GAAG;MACjC,KAAK,MAAM,OAAO,EAAE,GAAG,CAAC;MACxB,MAAM,MAAM;KACd;IACF;GACF,UAAU;IACR,OAAO,YAAY;GACrB;GACA,KAAK,MAAM;EACb,UAAU;GACR,KAAK,MAAM;EACb;CACF;CAEA,iBAAiB,KAAuB;EACtC,IAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU,OAAO;EAEpD,OADc,IAA2B,SACzB;CAClB;AACF"}
1
+ {"version":3,"file":"opfs.cjs","names":["#handle","#threshold","#load","#readRange","#ready","#init","#buildStreamingIndex","#resolveRoot","#prefix","#defaultThreshold","#keyFor","#getRoot","#writeStreamViaSyncHandle","#writeStreamViaWritable","#writeViaSyncHandle","#writeViaWritable","#isNotFoundError","#root"],"sources":["../../../src/batteries/storage/opfs/index.ts"],"sourcesContent":["/**\n * Browser-only Origin Private File System storage for spooled artifacts.\n *\n * @module @nhtio/adk/batteries/storage/opfs\n *\n * @remarks\n * Opt-in **browser-only** storage battery backed by the\n * [Origin Private File System](https://developer.mozilla.org/docs/Web/API/File_System_API/Origin_private_file_system)\n * (OPFS). Provides {@link OpfsSpoolReader} (a {@link @nhtio/adk!SpoolReader} over a `OpfsFileHandle`)\n * and {@link OpfsSpoolStore} (a `write(callId, bytes) → reader` persistence layer that wraps an\n * OPFS directory).\n *\n * The reader has two modes selected lazily on first method invocation based on the size of the\n * underlying file:\n *\n * - **Eager mode** — when `file.size` is below `streamThresholdBytes` (default 10 MiB), the\n * reader calls `file.text()` once, splits the content on `\\n`, and caches lines + byte count.\n * All subsequent calls resolve from memory.\n * - **Streaming mode** — when `file.size` meets or exceeds the threshold, the reader streams the\n * file once via `file.stream().getReader()` to build a line-offset index (`number[]` of byte\n * offsets per line), then serves each `line(i)` request by slicing the underlying `Blob` —\n * `Blob.slice(start, end).text()` decodes only the requested range, no head-of-file scan.\n * Caps RAM at one index + one line buffer regardless of file size.\n *\n * The store auto-selects its write API by execution scope:\n *\n * - In **worker scopes** (`self instanceof WorkerGlobalScope`), it acquires a\n * `FileSystemSyncAccessHandle` and writes synchronously. Sync handles are the only API\n * available in workers and the fastest path for the spool-write hot path.\n * - On the **main thread**, it uses `OpfsFileHandle.createWritable()` and the async\n * stream API. Sync access handles are not exposed on the main thread.\n *\n * This module assumes a browser-equivalent runtime — `navigator.storage`,\n * `OpfsFileHandle`, `TextEncoder`/`TextDecoder`, and `Blob` must all exist. It must not\n * be imported from Node code; do so and you will fail at resolve time when `navigator` is\n * referenced.\n *\n * @example\n * ```ts\n * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'\n *\n * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })\n * const reader = await store.write(callId, bytes)\n * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact\n * const artifact = new Ctor(reader)\n * ```\n */\n\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport type { SpoolReader, SpoolStore } from '@nhtio/adk/common'\n\n// The project's tsconfig limits `lib` to `ESNext`, so the DOM and File System Access types\n// referenced below are not in scope by default — neither `tsc --noEmit` nor the downstream dts\n// pipeline (api-extractor) can see them. Re-declare here the **minimum** surface this module\n// touches via a local handle-shape interface. Public API uses `OpfsFileHandle` /\n// `OpfsDirectoryHandle` instead of the DOM globals so the published `.d.ts` is self-contained\n// and consumers do not have to chase the lib graph.\n\n/**\n * Minimal subset of the\n * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)\n * `OpfsFileHandle` interface that this module touches at runtime. Structurally compatible\n * with the DOM-lib `OpfsFileHandle` — at call sites you pass real OPFS handles directly.\n */\nexport interface OpfsFileHandle {\n /** Discriminant: always `'file'`. */\n readonly kind: 'file'\n /** The entry's name. */\n readonly name: string\n /** Resolve a readable {@link OpfsFile} snapshot of the handle's contents. */\n getFile(): Promise<OpfsFile>\n /** Open a writable stream that replaces the file's contents. */\n createWritable(): Promise<OpfsWritableFileStream>\n}\n\n/**\n * Minimal subset of the\n * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)\n * `OpfsDirectoryHandle` interface that this module touches at runtime. Structurally\n * compatible with the DOM-lib `OpfsDirectoryHandle` — at call sites you pass real OPFS\n * handles directly.\n */\nexport interface OpfsDirectoryHandle {\n /** Discriminant: always `'directory'`. */\n readonly kind: 'directory'\n /** The directory's name. */\n readonly name: string\n /** Resolve a child file handle, optionally creating it. */\n getFileHandle(name: string, options?: { create?: boolean }): Promise<OpfsFileHandle>\n /** Resolve a child directory handle, optionally creating it. */\n getDirectoryHandle(name: string, options?: { create?: boolean }): Promise<OpfsDirectoryHandle>\n /** Remove a child entry, optionally recursively. */\n removeEntry(name: string, options?: { recursive?: boolean }): Promise<void>\n}\n\n/**\n * Minimal subset of the DOM `FileSystemWritableFileStream` interface used by the OPFS battery's\n * main-thread write path.\n */\nexport interface OpfsWritableFileStream {\n /** Append/write a chunk to the stream. */\n write(data: Uint8Array | ArrayBufferView | ArrayBuffer | string): Promise<void>\n /** Flush and close the stream, committing the written contents. */\n close(): Promise<void>\n}\n\n/**\n * Minimal subset of the DOM `Blob` interface used by {@link OpfsSpoolReader} streaming-mode\n * random-access reads. Real OPFS handles return a `File` here; we narrow to the methods we\n * actually call.\n */\nexport interface OpfsBlob {\n /** Byte length of the blob. */\n readonly size: number\n /** Return a sub-range of the blob as a new blob. */\n slice(start?: number, end?: number, contentType?: string): OpfsBlob\n /** Read the blob's contents as text. */\n text(): Promise<string>\n /** Open a readable byte stream over the blob. */\n stream(): OpfsReadableStream\n}\n\n/**\n * Minimal subset of the DOM `File` interface used by {@link OpfsSpoolReader}.\n */\nexport interface OpfsFile extends OpfsBlob {\n /** The file's name. */\n readonly name: string\n}\n\n/**\n * Minimal subset of the DOM `ReadableStream<Uint8Array>` interface used by streaming-mode\n * index construction.\n */\nexport interface OpfsReadableStream {\n /** Acquire a reader over the stream. */\n getReader(): OpfsReadableStreamReader\n}\n\n/**\n * Minimal subset of the DOM `ReadableStreamDefaultReader<Uint8Array>` interface used by\n * streaming-mode index construction.\n */\nexport interface OpfsReadableStreamReader {\n /** Read the next chunk, or signal end-of-stream with `done: true`. */\n read(): Promise<{ done: false; value: Uint8Array } | { done: true; value: undefined }>\n /** Release the reader's lock on the stream. */\n releaseLock(): void\n}\n\ndeclare const navigator: {\n storage: { getDirectory(): Promise<OpfsDirectoryHandle> }\n}\ndeclare class TextEncoder {\n encode(input?: string): Uint8Array\n}\ndeclare const self: unknown\ndeclare const WorkerGlobalScope: { new (): unknown } | undefined\n\ninterface FileSystemSyncAccessHandle {\n truncate(newSize: number): void\n write(buffer: Uint8Array | ArrayBuffer | ArrayBufferView, options?: { at?: number }): number\n flush(): void\n close(): void\n}\ninterface OpfsFileHandleWithSyncAccess extends OpfsFileHandle {\n createSyncAccessHandle(): Promise<FileSystemSyncAccessHandle>\n}\n\nconst DEFAULT_STREAM_THRESHOLD_BYTES = 10 * 1024 * 1024 // 10 MiB\n\nconst LF = 0x0a // '\\n'\n\nconst isNonNegativeFiniteNumber = (n: unknown): n is number =>\n typeof n === 'number' && Number.isFinite(n) && n >= 0\n\n/**\n * Constructor options for {@link OpfsSpoolReader}.\n */\nexport interface OpfsSpoolReaderOptions {\n /**\n * Byte-length threshold that switches between eager and streaming modes.\n *\n * @remarks\n * - Below the threshold → eager (whole-file in memory).\n * - At or above the threshold → streaming (line-offset index + per-line slice reads).\n *\n * Set to `0` to force streaming mode; set to `Number.POSITIVE_INFINITY` to force eager mode.\n *\n * @defaultValue `10 * 1024 * 1024` (10 MiB)\n */\n streamThresholdBytes?: number\n}\n\ninterface EagerState {\n mode: 'eager'\n lines: string[]\n bytes: number\n content: string\n}\n\ninterface StreamingState {\n mode: 'streaming'\n file: OpfsFile\n /**\n * Byte offsets where each line *starts*. Length equals lineCount + 1; the final entry equals\n * the total byte length. So `offsets[i + 1] - offsets[i]` is the byte length of line `i`\n * including any trailing `\\n`.\n */\n offsets: number[]\n bytes: number\n}\n\ntype ReaderState = EagerState | StreamingState\n\n/**\n * Returns `true` when the current global scope is a Web Worker (`DedicatedWorkerGlobalScope`,\n * `SharedWorkerGlobalScope`, or `ServiceWorkerGlobalScope` all inherit from `WorkerGlobalScope`).\n *\n * @remarks\n * The check is needed at runtime because `FileSystemSyncAccessHandle` is only exposed in worker\n * scopes — calling it from the main thread throws. We pick the write strategy based on the\n * answer here.\n *\n * @internal\n */\nconst isWorkerScope = (): boolean => {\n if (typeof WorkerGlobalScope === 'undefined') return false\n // eslint-disable-next-line adk/use-is-instance-of -- native built-in narrowing on `self`; no cross-realm risk\n return self instanceof WorkerGlobalScope\n}\n\n/**\n * Reads an OPFS-backed file as a {@link @nhtio/adk!SpoolReader}.\n *\n * @remarks\n * Constructor is **not** async — but the first method call awaits a private readiness promise\n * that fetches the underlying `File` (and in eager mode, its contents). Subsequent calls reuse\n * the cached state. This keeps construction call sites synchronous while still doing real I/O\n * lazily.\n *\n * All four `SpoolReader` methods on this reader return promises. The `SpoolReader` contract\n * supports both sync and async return; consumers of `SpooledArtifact` handle either.\n */\nexport class OpfsSpoolReader implements SpoolReader {\n readonly #handle: OpfsFileHandle\n readonly #threshold: number\n #ready: Promise<ReaderState> | undefined\n\n constructor(handle: OpfsFileHandle, opts: OpfsSpoolReaderOptions = {}) {\n this.#handle = handle\n const raw = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES\n // Allow `Infinity` (forces eager) but reject anything non-finite-negative.\n if (typeof raw !== 'number' || Number.isNaN(raw) || raw < 0) {\n throw new TypeError(\n `OpfsSpoolReader: streamThresholdBytes must be a non-negative number or Infinity, got ${String(raw)}`\n )\n }\n this.#threshold = raw\n }\n\n /**\n * Returns `true` if `value` is an {@link OpfsSpoolReader} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is an {@link OpfsSpoolReader} instance.\n */\n public static isOpfsSpoolReader(value: unknown): value is OpfsSpoolReader {\n return isInstanceOf(value, 'OpfsSpoolReader', OpfsSpoolReader)\n }\n\n async line(index: number): Promise<string | undefined> {\n const state = await this.#load()\n if (state.mode === 'eager') return state.lines[index]\n if (index < 0 || index >= state.offsets.length - 1) return undefined\n return this.#readRange(state.file, state.offsets[index], state.offsets[index + 1])\n }\n\n async byteLength(): Promise<number> {\n const state = await this.#load()\n return state.bytes\n }\n\n async lineCount(): Promise<number> {\n const state = await this.#load()\n return state.mode === 'eager' ? state.lines.length : state.offsets.length - 1\n }\n\n /**\n * Returns the full underlying content as a single decoded string, byte-faithful to the source.\n *\n * @remarks\n * In **eager mode** the content is already cached at first-call load and this method is\n * effectively a property access. In **streaming mode** there is no cache: the file is re-read\n * (as a single `File.text()` call) on every invocation. Use `SpooledArtifact.asString()`\n * judiciously on large streaming-mode artifacts.\n */\n async readAll(): Promise<string> {\n const state = await this.#load()\n if (state.mode === 'eager') return state.content\n return state.file.text()\n }\n\n /**\n * Lazily initialise the reader's mode-specific state. Called by every public method; the\n * promise is cached so the work runs at most once.\n */\n #load(): Promise<ReaderState> {\n if (!this.#ready) this.#ready = this.#init()\n return this.#ready\n }\n\n async #init(): Promise<ReaderState> {\n const file = await this.#handle.getFile()\n const bytes = file.size\n if (!isNonNegativeFiniteNumber(bytes)) {\n throw new Error(`OpfsSpoolReader: file handle returned a non-finite size (${String(bytes)})`)\n }\n if (bytes < this.#threshold) {\n // Eager — pull the whole thing into memory.\n const content = await file.text()\n const lines = content === '' ? [] : content.split('\\n')\n return { mode: 'eager', lines, bytes, content }\n }\n // Streaming — build a line-offset index by scanning bytes once.\n return this.#buildStreamingIndex(file, bytes)\n }\n\n async #buildStreamingIndex(file: OpfsFile, bytes: number): Promise<StreamingState> {\n // Edge case first — an empty file is one offset (the EOF), zero lines.\n if (bytes === 0) return { mode: 'streaming', file, offsets: [0], bytes }\n\n // offsets[i] is the byte position where line `i` starts. offsets[lineCount] is one-past-end.\n // For \"a\\nb\\nc\" → offsets=[0, 2, 4, 5] (3 lines).\n // For \"a\\nb\\n\" → offsets=[0, 2, 4, 4] (3 lines, last is the trailing empty line). This\n // mirrors `String.prototype.split('\\n')` semantics so streaming and eager agree.\n const offsets: number[] = [0]\n let position = 0\n let lastByte = -1\n const reader = file.stream().getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n for (const byte of value) {\n position++\n if (byte === LF) offsets.push(position)\n lastByte = byte\n }\n }\n } finally {\n reader.releaseLock()\n }\n // If the file ends on a newline, the byte after the LF is the start of an empty trailing\n // line — record it. If it doesn't, the final line's end is the EOF and we need to push\n // it so line(N-1) can read up to bytes.\n if (lastByte === LF) offsets.push(position)\n else if (offsets[offsets.length - 1] !== position) offsets.push(position)\n return { mode: 'streaming', file, offsets, bytes }\n }\n\n /**\n * Slices the byte range `[start, end)` from the backing file and returns it as a UTF-8\n * string, stripping a trailing `\\n` if present.\n *\n * @remarks\n * `Blob.slice` is O(1) metadata; `Blob.text()` only decodes the slice. The line-offset index\n * brackets each line *with* its trailing LF (so `offsets[i+1]` points at the start of the\n * next line) and the `SpoolReader` contract returns lines *without* their trailing newline,\n * so we strip a single trailing LF if present.\n */\n async #readRange(file: OpfsFile, start: number, end: number): Promise<string> {\n if (start === end) return ''\n const slice = file.slice(start, end)\n const text = await slice.text()\n if (text.length > 0 && text.charCodeAt(text.length - 1) === LF) {\n return text.slice(0, -1)\n }\n return text\n }\n}\n\n/**\n * Constructor options for {@link OpfsSpoolStore}.\n */\nexport interface OpfsSpoolStoreOptions {\n /**\n * Optional thunk that resolves the {@link OpfsDirectoryHandle} used as the store root.\n *\n * @remarks\n * When omitted, the store resolves the root via `navigator.storage.getDirectory()` on its\n * first filesystem call. Override for tests (to point at a per-suite subdirectory) or to\n * scope the store to a nested directory inside OPFS.\n *\n * The thunk is invoked at most once per store; the returned handle is memoised.\n */\n directory?: () => Promise<OpfsDirectoryHandle>\n\n /**\n * Optional filename prefix prepended to every `callId`.\n *\n * @remarks\n * Prefix is a **filename prefix**, not a subdirectory — `keyPrefix: 'agent-runs/'` produces\n * a file literally named `agent-runs/<callId>` at the root, not a nested directory. (OPFS\n * filenames may not contain `/`, so use a non-`/` separator like `-` if you want a flat\n * namespace.) This mirrors the `keyPrefix` semantics in the flydrive and in-memory batteries.\n *\n * @defaultValue `\"\"`\n */\n keyPrefix?: string\n\n /**\n * Default `streamThresholdBytes` for readers produced by `write()` and `read()`. Individual\n * calls may override via their own `opts` argument.\n *\n * @defaultValue `10 * 1024 * 1024` (10 MiB)\n */\n streamThresholdBytes?: number\n}\n\n/**\n * \"Give bytes, get a reader\" persistence layer over an OPFS directory.\n *\n * @remarks\n * `write(callId, bytes)` resolves the root directory (lazily, on first call), opens or creates\n * the file named `keyPrefix + callId`, then writes via the API matching the current scope:\n * a `FileSystemSyncAccessHandle` in worker scopes, `OpfsFileHandle.createWritable()` on\n * the main thread. A fresh {@link OpfsSpoolReader} pointed at the same file is returned.\n *\n * `read(callId)` returns a reader without re-writing; `delete(callId)` removes the entry.\n *\n * The store is otherwise stateless — it owns no in-memory cache of writes. Multiple\n * `OpfsSpoolStore` instances sharing the same root directory and key prefix see the same data.\n *\n * @example\n * ```ts\n * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'\n *\n * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })\n *\n * const bytes = await tool.executor(ctx)(args)\n * const reader = await store.write(callId, bytes)\n * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact\n * const artifact = new Ctor(reader)\n * ```\n */\nexport class OpfsSpoolStore implements SpoolStore {\n readonly #resolveRoot: () => Promise<OpfsDirectoryHandle>\n readonly #prefix: string\n readonly #defaultThreshold: number\n #root: OpfsDirectoryHandle | undefined\n\n constructor(opts: OpfsSpoolStoreOptions = {}) {\n this.#resolveRoot = opts.directory ?? (() => navigator.storage.getDirectory())\n this.#prefix = opts.keyPrefix ?? ''\n this.#defaultThreshold = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES\n }\n\n /**\n * Returns `true` if `value` is an {@link OpfsSpoolStore} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is an {@link OpfsSpoolStore} instance.\n */\n public static isOpfsSpoolStore(value: unknown): value is OpfsSpoolStore {\n return isInstanceOf(value, 'OpfsSpoolStore', OpfsSpoolStore)\n }\n\n /**\n * Persists `bytes` under `callId` and returns a reader bound to the stored key.\n *\n * @remarks\n * `string` input is encoded as UTF-8; `Uint8Array` is stored byte-faithfully;\n * `ReadableStream<Uint8Array>` is written incrementally — the stream is consumed chunk-by-chunk\n * straight to OPFS without first materializing the whole payload in memory, which is the point\n * of accepting a stream for a durable store.\n *\n * @param callId - Identifier used to retrieve the bytes via {@link OpfsSpoolStore.read}.\n * @param bytes - The bytes to store, as a `string`, `Uint8Array`, or `ReadableStream<Uint8Array>`.\n * @param opts - Per-call override for `streamThresholdBytes`.\n * @returns An {@link OpfsSpoolReader} over the stored bytes.\n */\n async write(\n callId: string,\n bytes: string | Uint8Array | ReadableStream<Uint8Array>,\n opts?: OpfsSpoolReaderOptions\n ): Promise<OpfsSpoolReader> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n const handle = await root.getFileHandle(name, { create: true })\n if (isInstanceOf(bytes, 'ReadableStream', ReadableStream)) {\n if (isWorkerScope()) {\n await this.#writeStreamViaSyncHandle(handle, bytes)\n } else {\n await this.#writeStreamViaWritable(handle, bytes)\n }\n } else {\n const payload = typeof bytes === 'string' ? new TextEncoder().encode(bytes) : bytes\n if (isWorkerScope()) {\n await this.#writeViaSyncHandle(handle, payload)\n } else {\n await this.#writeViaWritable(handle, payload)\n }\n }\n return new OpfsSpoolReader(handle, {\n streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold,\n })\n }\n\n /**\n * Returns a reader over the bytes previously written under `callId`.\n *\n * @remarks\n * Returns `undefined` if the file does not exist.\n *\n * @param callId - Identifier supplied to a prior {@link OpfsSpoolStore.write} call.\n * @param opts - Per-call override for `streamThresholdBytes`.\n * @returns An {@link OpfsSpoolReader}, or `undefined` if the key is missing.\n */\n async read(callId: string, opts?: OpfsSpoolReaderOptions): Promise<OpfsSpoolReader | undefined> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n let handle: OpfsFileHandle\n try {\n handle = await root.getFileHandle(name)\n } catch (err) {\n if (this.#isNotFoundError(err)) return undefined\n throw err\n }\n return new OpfsSpoolReader(handle, {\n streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold,\n })\n }\n\n /**\n * Removes the entry under `callId`.\n *\n * @param callId - Identifier whose entry should be removed.\n * @returns `true` if the entry existed and was removed; `false` if it didn't exist.\n */\n async delete(callId: string): Promise<boolean> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n try {\n await root.removeEntry(name)\n return true\n } catch (err) {\n if (this.#isNotFoundError(err)) return false\n throw err\n }\n }\n\n /**\n * Returns `true` if a file is present under `callId`.\n *\n * @param callId - Identifier to test.\n * @returns `true` when the file exists, `false` otherwise.\n */\n async has(callId: string): Promise<boolean> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n try {\n await root.getFileHandle(name)\n return true\n } catch (err) {\n if (this.#isNotFoundError(err)) return false\n throw err\n }\n }\n\n /**\n * Returns the full filename for a given `callId` (i.e. `keyPrefix + callId`).\n *\n * @remarks\n * Useful for tests or for callers that want to interact with the underlying OPFS directory\n * directly.\n */\n keyFor(callId: string): string {\n return this.#keyFor(callId)\n }\n\n #keyFor(callId: string): string {\n return this.#prefix + callId\n }\n\n async #getRoot(): Promise<OpfsDirectoryHandle> {\n if (!this.#root) this.#root = await this.#resolveRoot()\n return this.#root\n }\n\n async #writeViaSyncHandle(handle: OpfsFileHandle, payload: Uint8Array): Promise<void> {\n const sync = await (handle as OpfsFileHandleWithSyncAccess).createSyncAccessHandle()\n try {\n sync.truncate(0)\n sync.write(payload, { at: 0 })\n sync.flush()\n } finally {\n sync.close()\n }\n }\n\n async #writeViaWritable(handle: OpfsFileHandle, payload: Uint8Array): Promise<void> {\n const writable = await handle.createWritable()\n try {\n await writable.write(payload)\n } finally {\n await writable.close()\n }\n }\n\n async #writeStreamViaWritable(\n handle: OpfsFileHandle,\n stream: ReadableStream<Uint8Array>\n ): Promise<void> {\n const writable = await handle.createWritable()\n try {\n const reader = stream.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (value) await writable.write(value)\n }\n } finally {\n reader.releaseLock()\n }\n } finally {\n await writable.close()\n }\n }\n\n async #writeStreamViaSyncHandle(\n handle: OpfsFileHandle,\n stream: ReadableStream<Uint8Array>\n ): Promise<void> {\n const sync = await (handle as OpfsFileHandleWithSyncAccess).createSyncAccessHandle()\n try {\n sync.truncate(0)\n let at = 0\n const reader = stream.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (value && value.byteLength > 0) {\n sync.write(value, { at })\n at += value.byteLength\n }\n }\n } finally {\n reader.releaseLock()\n }\n sync.flush()\n } finally {\n sync.close()\n }\n }\n\n #isNotFoundError(err: unknown): boolean {\n if (err === null || typeof err !== 'object') return false\n const name = (err as { name?: unknown }).name\n return name === 'NotFoundError'\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { s as isInstanceOf } from "../../tool_registry-D1pSSlsd.mjs";
1
+ import { s as isInstanceOf } from "../../tool_registry-791Vrjtf.mjs";
2
2
  import "../../guards.mjs";
3
3
  //#region src/batteries/storage/opfs/index.ts
4
4
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"opfs.mjs","names":["#handle","#threshold","#load","#readRange","#ready","#init","#buildStreamingIndex","#resolveRoot","#prefix","#defaultThreshold","#keyFor","#getRoot","#writeStreamViaSyncHandle","#writeStreamViaWritable","#writeViaSyncHandle","#writeViaWritable","#isNotFoundError","#root"],"sources":["../../../src/batteries/storage/opfs/index.ts"],"sourcesContent":["/**\n * Browser-only Origin Private File System storage for spooled artifacts.\n *\n * @module @nhtio/adk/batteries/storage/opfs\n *\n * @remarks\n * Opt-in **browser-only** storage battery backed by the\n * [Origin Private File System](https://developer.mozilla.org/docs/Web/API/File_System_API/Origin_private_file_system)\n * (OPFS). Provides {@link OpfsSpoolReader} (a {@link @nhtio/adk!SpoolReader} over a `OpfsFileHandle`)\n * and {@link OpfsSpoolStore} (a `write(callId, bytes) → reader` persistence layer that wraps an\n * OPFS directory).\n *\n * The reader has two modes selected lazily on first method invocation based on the size of the\n * underlying file:\n *\n * - **Eager mode** — when `file.size` is below `streamThresholdBytes` (default 10 MiB), the\n * reader calls `file.text()` once, splits the content on `\\n`, and caches lines + byte count.\n * All subsequent calls resolve from memory.\n * - **Streaming mode** — when `file.size` meets or exceeds the threshold, the reader streams the\n * file once via `file.stream().getReader()` to build a line-offset index (`number[]` of byte\n * offsets per line), then serves each `line(i)` request by slicing the underlying `Blob` —\n * `Blob.slice(start, end).text()` decodes only the requested range, no head-of-file scan.\n * Caps RAM at one index + one line buffer regardless of file size.\n *\n * The store auto-selects its write API by execution scope:\n *\n * - In **worker scopes** (`self instanceof WorkerGlobalScope`), it acquires a\n * `FileSystemSyncAccessHandle` and writes synchronously. Sync handles are the only API\n * available in workers and the fastest path for the spool-write hot path.\n * - On the **main thread**, it uses `OpfsFileHandle.createWritable()` and the async\n * stream API. Sync access handles are not exposed on the main thread.\n *\n * This module assumes a browser-equivalent runtime — `navigator.storage`,\n * `OpfsFileHandle`, `TextEncoder`/`TextDecoder`, and `Blob` must all exist. It must not\n * be imported from Node code; do so and you will fail at resolve time when `navigator` is\n * referenced.\n *\n * @example\n * ```ts\n * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'\n *\n * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })\n * const reader = await store.write(callId, bytes)\n * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact\n * const artifact = new Ctor(reader)\n * ```\n */\n\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport type { SpoolReader, SpoolStore } from '@nhtio/adk/common'\n\n// The project's tsconfig limits `lib` to `ESNext`, so the DOM and File System Access types\n// referenced below are not in scope by default — neither `tsc --noEmit` nor the downstream dts\n// pipeline (api-extractor) can see them. Re-declare here the **minimum** surface this module\n// touches via a local handle-shape interface. Public API uses `OpfsFileHandle` /\n// `OpfsDirectoryHandle` instead of the DOM globals so the published `.d.ts` is self-contained\n// and consumers do not have to chase the lib graph.\n\n/**\n * Minimal subset of the\n * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)\n * `OpfsFileHandle` interface that this module touches at runtime. Structurally compatible\n * with the DOM-lib `OpfsFileHandle` — at call sites you pass real OPFS handles directly.\n */\nexport interface OpfsFileHandle {\n readonly kind: 'file'\n readonly name: string\n getFile(): Promise<OpfsFile>\n createWritable(): Promise<OpfsWritableFileStream>\n}\n\n/**\n * Minimal subset of the\n * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)\n * `OpfsDirectoryHandle` interface that this module touches at runtime. Structurally\n * compatible with the DOM-lib `OpfsDirectoryHandle` — at call sites you pass real OPFS\n * handles directly.\n */\nexport interface OpfsDirectoryHandle {\n readonly kind: 'directory'\n readonly name: string\n getFileHandle(name: string, options?: { create?: boolean }): Promise<OpfsFileHandle>\n getDirectoryHandle(name: string, options?: { create?: boolean }): Promise<OpfsDirectoryHandle>\n removeEntry(name: string, options?: { recursive?: boolean }): Promise<void>\n}\n\n/**\n * Minimal subset of the DOM `FileSystemWritableFileStream` interface used by the OPFS battery's\n * main-thread write path.\n */\nexport interface OpfsWritableFileStream {\n write(data: Uint8Array | ArrayBufferView | ArrayBuffer | string): Promise<void>\n close(): Promise<void>\n}\n\n/**\n * Minimal subset of the DOM `Blob` interface used by {@link OpfsSpoolReader} streaming-mode\n * random-access reads. Real OPFS handles return a `File` here; we narrow to the methods we\n * actually call.\n */\nexport interface OpfsBlob {\n readonly size: number\n slice(start?: number, end?: number, contentType?: string): OpfsBlob\n text(): Promise<string>\n stream(): OpfsReadableStream\n}\n\n/**\n * Minimal subset of the DOM `File` interface used by {@link OpfsSpoolReader}.\n */\nexport interface OpfsFile extends OpfsBlob {\n readonly name: string\n}\n\n/**\n * Minimal subset of the DOM `ReadableStream<Uint8Array>` interface used by streaming-mode\n * index construction.\n */\nexport interface OpfsReadableStream {\n getReader(): OpfsReadableStreamReader\n}\n\n/**\n * Minimal subset of the DOM `ReadableStreamDefaultReader<Uint8Array>` interface used by\n * streaming-mode index construction.\n */\nexport interface OpfsReadableStreamReader {\n read(): Promise<{ done: false; value: Uint8Array } | { done: true; value: undefined }>\n releaseLock(): void\n}\n\ndeclare const navigator: {\n storage: { getDirectory(): Promise<OpfsDirectoryHandle> }\n}\ndeclare class TextEncoder {\n encode(input?: string): Uint8Array\n}\ndeclare const self: unknown\ndeclare const WorkerGlobalScope: { new (): unknown } | undefined\n\ninterface FileSystemSyncAccessHandle {\n truncate(newSize: number): void\n write(buffer: Uint8Array | ArrayBuffer | ArrayBufferView, options?: { at?: number }): number\n flush(): void\n close(): void\n}\ninterface OpfsFileHandleWithSyncAccess extends OpfsFileHandle {\n createSyncAccessHandle(): Promise<FileSystemSyncAccessHandle>\n}\n\nconst DEFAULT_STREAM_THRESHOLD_BYTES = 10 * 1024 * 1024 // 10 MiB\n\nconst LF = 0x0a // '\\n'\n\nconst isNonNegativeFiniteNumber = (n: unknown): n is number =>\n typeof n === 'number' && Number.isFinite(n) && n >= 0\n\n/**\n * Constructor options for {@link OpfsSpoolReader}.\n */\nexport interface OpfsSpoolReaderOptions {\n /**\n * Byte-length threshold that switches between eager and streaming modes.\n *\n * @remarks\n * - Below the threshold → eager (whole-file in memory).\n * - At or above the threshold → streaming (line-offset index + per-line slice reads).\n *\n * Set to `0` to force streaming mode; set to `Number.POSITIVE_INFINITY` to force eager mode.\n *\n * @defaultValue `10 * 1024 * 1024` (10 MiB)\n */\n streamThresholdBytes?: number\n}\n\ninterface EagerState {\n mode: 'eager'\n lines: string[]\n bytes: number\n content: string\n}\n\ninterface StreamingState {\n mode: 'streaming'\n file: OpfsFile\n /**\n * Byte offsets where each line *starts*. Length equals lineCount + 1; the final entry equals\n * the total byte length. So `offsets[i + 1] - offsets[i]` is the byte length of line `i`\n * including any trailing `\\n`.\n */\n offsets: number[]\n bytes: number\n}\n\ntype ReaderState = EagerState | StreamingState\n\n/**\n * Returns `true` when the current global scope is a Web Worker (`DedicatedWorkerGlobalScope`,\n * `SharedWorkerGlobalScope`, or `ServiceWorkerGlobalScope` all inherit from `WorkerGlobalScope`).\n *\n * @remarks\n * The check is needed at runtime because `FileSystemSyncAccessHandle` is only exposed in worker\n * scopes — calling it from the main thread throws. We pick the write strategy based on the\n * answer here.\n *\n * @internal\n */\nconst isWorkerScope = (): boolean => {\n if (typeof WorkerGlobalScope === 'undefined') return false\n // eslint-disable-next-line adk/use-is-instance-of -- native built-in narrowing on `self`; no cross-realm risk\n return self instanceof WorkerGlobalScope\n}\n\n/**\n * Reads an OPFS-backed file as a {@link @nhtio/adk!SpoolReader}.\n *\n * @remarks\n * Constructor is **not** async — but the first method call awaits a private readiness promise\n * that fetches the underlying `File` (and in eager mode, its contents). Subsequent calls reuse\n * the cached state. This keeps construction call sites synchronous while still doing real I/O\n * lazily.\n *\n * All four `SpoolReader` methods on this reader return promises. The `SpoolReader` contract\n * supports both sync and async return; consumers of `SpooledArtifact` handle either.\n */\nexport class OpfsSpoolReader implements SpoolReader {\n readonly #handle: OpfsFileHandle\n readonly #threshold: number\n #ready: Promise<ReaderState> | undefined\n\n constructor(handle: OpfsFileHandle, opts: OpfsSpoolReaderOptions = {}) {\n this.#handle = handle\n const raw = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES\n // Allow `Infinity` (forces eager) but reject anything non-finite-negative.\n if (typeof raw !== 'number' || Number.isNaN(raw) || raw < 0) {\n throw new TypeError(\n `OpfsSpoolReader: streamThresholdBytes must be a non-negative number or Infinity, got ${String(raw)}`\n )\n }\n this.#threshold = raw\n }\n\n /**\n * Returns `true` if `value` is an {@link OpfsSpoolReader} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is an {@link OpfsSpoolReader} instance.\n */\n public static isOpfsSpoolReader(value: unknown): value is OpfsSpoolReader {\n return isInstanceOf(value, 'OpfsSpoolReader', OpfsSpoolReader)\n }\n\n async line(index: number): Promise<string | undefined> {\n const state = await this.#load()\n if (state.mode === 'eager') return state.lines[index]\n if (index < 0 || index >= state.offsets.length - 1) return undefined\n return this.#readRange(state.file, state.offsets[index], state.offsets[index + 1])\n }\n\n async byteLength(): Promise<number> {\n const state = await this.#load()\n return state.bytes\n }\n\n async lineCount(): Promise<number> {\n const state = await this.#load()\n return state.mode === 'eager' ? state.lines.length : state.offsets.length - 1\n }\n\n /**\n * Returns the full underlying content as a single decoded string, byte-faithful to the source.\n *\n * @remarks\n * In **eager mode** the content is already cached at first-call load and this method is\n * effectively a property access. In **streaming mode** there is no cache: the file is re-read\n * (as a single `File.text()` call) on every invocation. Use `SpooledArtifact.asString()`\n * judiciously on large streaming-mode artifacts.\n */\n async readAll(): Promise<string> {\n const state = await this.#load()\n if (state.mode === 'eager') return state.content\n return state.file.text()\n }\n\n /**\n * Lazily initialise the reader's mode-specific state. Called by every public method; the\n * promise is cached so the work runs at most once.\n */\n #load(): Promise<ReaderState> {\n if (!this.#ready) this.#ready = this.#init()\n return this.#ready\n }\n\n async #init(): Promise<ReaderState> {\n const file = await this.#handle.getFile()\n const bytes = file.size\n if (!isNonNegativeFiniteNumber(bytes)) {\n throw new Error(`OpfsSpoolReader: file handle returned a non-finite size (${String(bytes)})`)\n }\n if (bytes < this.#threshold) {\n // Eager — pull the whole thing into memory.\n const content = await file.text()\n const lines = content === '' ? [] : content.split('\\n')\n return { mode: 'eager', lines, bytes, content }\n }\n // Streaming — build a line-offset index by scanning bytes once.\n return this.#buildStreamingIndex(file, bytes)\n }\n\n async #buildStreamingIndex(file: OpfsFile, bytes: number): Promise<StreamingState> {\n // Edge case first — an empty file is one offset (the EOF), zero lines.\n if (bytes === 0) return { mode: 'streaming', file, offsets: [0], bytes }\n\n // offsets[i] is the byte position where line `i` starts. offsets[lineCount] is one-past-end.\n // For \"a\\nb\\nc\" → offsets=[0, 2, 4, 5] (3 lines).\n // For \"a\\nb\\n\" → offsets=[0, 2, 4, 4] (3 lines, last is the trailing empty line). This\n // mirrors `String.prototype.split('\\n')` semantics so streaming and eager agree.\n const offsets: number[] = [0]\n let position = 0\n let lastByte = -1\n const reader = file.stream().getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n for (const byte of value) {\n position++\n if (byte === LF) offsets.push(position)\n lastByte = byte\n }\n }\n } finally {\n reader.releaseLock()\n }\n // If the file ends on a newline, the byte after the LF is the start of an empty trailing\n // line — record it. If it doesn't, the final line's end is the EOF and we need to push\n // it so line(N-1) can read up to bytes.\n if (lastByte === LF) offsets.push(position)\n else if (offsets[offsets.length - 1] !== position) offsets.push(position)\n return { mode: 'streaming', file, offsets, bytes }\n }\n\n /**\n * Slices the byte range `[start, end)` from the backing file and returns it as a UTF-8\n * string, stripping a trailing `\\n` if present.\n *\n * @remarks\n * `Blob.slice` is O(1) metadata; `Blob.text()` only decodes the slice. The line-offset index\n * brackets each line *with* its trailing LF (so `offsets[i+1]` points at the start of the\n * next line) and the `SpoolReader` contract returns lines *without* their trailing newline,\n * so we strip a single trailing LF if present.\n */\n async #readRange(file: OpfsFile, start: number, end: number): Promise<string> {\n if (start === end) return ''\n const slice = file.slice(start, end)\n const text = await slice.text()\n if (text.length > 0 && text.charCodeAt(text.length - 1) === LF) {\n return text.slice(0, -1)\n }\n return text\n }\n}\n\n/**\n * Constructor options for {@link OpfsSpoolStore}.\n */\nexport interface OpfsSpoolStoreOptions {\n /**\n * Optional thunk that resolves the {@link OpfsDirectoryHandle} used as the store root.\n *\n * @remarks\n * When omitted, the store resolves the root via `navigator.storage.getDirectory()` on its\n * first filesystem call. Override for tests (to point at a per-suite subdirectory) or to\n * scope the store to a nested directory inside OPFS.\n *\n * The thunk is invoked at most once per store; the returned handle is memoised.\n */\n directory?: () => Promise<OpfsDirectoryHandle>\n\n /**\n * Optional filename prefix prepended to every `callId`.\n *\n * @remarks\n * Prefix is a **filename prefix**, not a subdirectory — `keyPrefix: 'agent-runs/'` produces\n * a file literally named `agent-runs/<callId>` at the root, not a nested directory. (OPFS\n * filenames may not contain `/`, so use a non-`/` separator like `-` if you want a flat\n * namespace.) This mirrors the `keyPrefix` semantics in the flydrive and in-memory batteries.\n *\n * @defaultValue `\"\"`\n */\n keyPrefix?: string\n\n /**\n * Default `streamThresholdBytes` for readers produced by `write()` and `read()`. Individual\n * calls may override via their own `opts` argument.\n *\n * @defaultValue `10 * 1024 * 1024` (10 MiB)\n */\n streamThresholdBytes?: number\n}\n\n/**\n * \"Give bytes, get a reader\" persistence layer over an OPFS directory.\n *\n * @remarks\n * `write(callId, bytes)` resolves the root directory (lazily, on first call), opens or creates\n * the file named `keyPrefix + callId`, then writes via the API matching the current scope:\n * a `FileSystemSyncAccessHandle` in worker scopes, `OpfsFileHandle.createWritable()` on\n * the main thread. A fresh {@link OpfsSpoolReader} pointed at the same file is returned.\n *\n * `read(callId)` returns a reader without re-writing; `delete(callId)` removes the entry.\n *\n * The store is otherwise stateless — it owns no in-memory cache of writes. Multiple\n * `OpfsSpoolStore` instances sharing the same root directory and key prefix see the same data.\n *\n * @example\n * ```ts\n * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'\n *\n * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })\n *\n * const bytes = await tool.executor(ctx)(args)\n * const reader = await store.write(callId, bytes)\n * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact\n * const artifact = new Ctor(reader)\n * ```\n */\nexport class OpfsSpoolStore implements SpoolStore {\n readonly #resolveRoot: () => Promise<OpfsDirectoryHandle>\n readonly #prefix: string\n readonly #defaultThreshold: number\n #root: OpfsDirectoryHandle | undefined\n\n constructor(opts: OpfsSpoolStoreOptions = {}) {\n this.#resolveRoot = opts.directory ?? (() => navigator.storage.getDirectory())\n this.#prefix = opts.keyPrefix ?? ''\n this.#defaultThreshold = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES\n }\n\n /**\n * Returns `true` if `value` is an {@link OpfsSpoolStore} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is an {@link OpfsSpoolStore} instance.\n */\n public static isOpfsSpoolStore(value: unknown): value is OpfsSpoolStore {\n return isInstanceOf(value, 'OpfsSpoolStore', OpfsSpoolStore)\n }\n\n /**\n * Persists `bytes` under `callId` and returns a reader bound to the stored key.\n *\n * @remarks\n * `string` input is encoded as UTF-8; `Uint8Array` is stored byte-faithfully;\n * `ReadableStream<Uint8Array>` is written incrementally — the stream is consumed chunk-by-chunk\n * straight to OPFS without first materializing the whole payload in memory, which is the point\n * of accepting a stream for a durable store.\n *\n * @param callId - Identifier used to retrieve the bytes via {@link OpfsSpoolStore.read}.\n * @param bytes - The bytes to store, as a `string`, `Uint8Array`, or `ReadableStream<Uint8Array>`.\n * @param opts - Per-call override for `streamThresholdBytes`.\n * @returns An {@link OpfsSpoolReader} over the stored bytes.\n */\n async write(\n callId: string,\n bytes: string | Uint8Array | ReadableStream<Uint8Array>,\n opts?: OpfsSpoolReaderOptions\n ): Promise<OpfsSpoolReader> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n const handle = await root.getFileHandle(name, { create: true })\n if (isInstanceOf(bytes, 'ReadableStream', ReadableStream)) {\n if (isWorkerScope()) {\n await this.#writeStreamViaSyncHandle(handle, bytes)\n } else {\n await this.#writeStreamViaWritable(handle, bytes)\n }\n } else {\n const payload = typeof bytes === 'string' ? new TextEncoder().encode(bytes) : bytes\n if (isWorkerScope()) {\n await this.#writeViaSyncHandle(handle, payload)\n } else {\n await this.#writeViaWritable(handle, payload)\n }\n }\n return new OpfsSpoolReader(handle, {\n streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold,\n })\n }\n\n /**\n * Returns a reader over the bytes previously written under `callId`.\n *\n * @remarks\n * Returns `undefined` if the file does not exist.\n *\n * @param callId - Identifier supplied to a prior {@link OpfsSpoolStore.write} call.\n * @param opts - Per-call override for `streamThresholdBytes`.\n * @returns An {@link OpfsSpoolReader}, or `undefined` if the key is missing.\n */\n async read(callId: string, opts?: OpfsSpoolReaderOptions): Promise<OpfsSpoolReader | undefined> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n let handle: OpfsFileHandle\n try {\n handle = await root.getFileHandle(name)\n } catch (err) {\n if (this.#isNotFoundError(err)) return undefined\n throw err\n }\n return new OpfsSpoolReader(handle, {\n streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold,\n })\n }\n\n /**\n * Removes the entry under `callId`.\n *\n * @param callId - Identifier whose entry should be removed.\n * @returns `true` if the entry existed and was removed; `false` if it didn't exist.\n */\n async delete(callId: string): Promise<boolean> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n try {\n await root.removeEntry(name)\n return true\n } catch (err) {\n if (this.#isNotFoundError(err)) return false\n throw err\n }\n }\n\n /**\n * Returns `true` if a file is present under `callId`.\n *\n * @param callId - Identifier to test.\n * @returns `true` when the file exists, `false` otherwise.\n */\n async has(callId: string): Promise<boolean> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n try {\n await root.getFileHandle(name)\n return true\n } catch (err) {\n if (this.#isNotFoundError(err)) return false\n throw err\n }\n }\n\n /**\n * Returns the full filename for a given `callId` (i.e. `keyPrefix + callId`).\n *\n * @remarks\n * Useful for tests or for callers that want to interact with the underlying OPFS directory\n * directly.\n */\n keyFor(callId: string): string {\n return this.#keyFor(callId)\n }\n\n #keyFor(callId: string): string {\n return this.#prefix + callId\n }\n\n async #getRoot(): Promise<OpfsDirectoryHandle> {\n if (!this.#root) this.#root = await this.#resolveRoot()\n return this.#root\n }\n\n async #writeViaSyncHandle(handle: OpfsFileHandle, payload: Uint8Array): Promise<void> {\n const sync = await (handle as OpfsFileHandleWithSyncAccess).createSyncAccessHandle()\n try {\n sync.truncate(0)\n sync.write(payload, { at: 0 })\n sync.flush()\n } finally {\n sync.close()\n }\n }\n\n async #writeViaWritable(handle: OpfsFileHandle, payload: Uint8Array): Promise<void> {\n const writable = await handle.createWritable()\n try {\n await writable.write(payload)\n } finally {\n await writable.close()\n }\n }\n\n async #writeStreamViaWritable(\n handle: OpfsFileHandle,\n stream: ReadableStream<Uint8Array>\n ): Promise<void> {\n const writable = await handle.createWritable()\n try {\n const reader = stream.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (value) await writable.write(value)\n }\n } finally {\n reader.releaseLock()\n }\n } finally {\n await writable.close()\n }\n }\n\n async #writeStreamViaSyncHandle(\n handle: OpfsFileHandle,\n stream: ReadableStream<Uint8Array>\n ): Promise<void> {\n const sync = await (handle as OpfsFileHandleWithSyncAccess).createSyncAccessHandle()\n try {\n sync.truncate(0)\n let at = 0\n const reader = stream.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (value && value.byteLength > 0) {\n sync.write(value, { at })\n at += value.byteLength\n }\n }\n } finally {\n reader.releaseLock()\n }\n sync.flush()\n } finally {\n sync.close()\n }\n }\n\n #isNotFoundError(err: unknown): boolean {\n if (err === null || typeof err !== 'object') return false\n const name = (err as { name?: unknown }).name\n return name === 'NotFoundError'\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"opfs.mjs","names":["#handle","#threshold","#load","#readRange","#ready","#init","#buildStreamingIndex","#resolveRoot","#prefix","#defaultThreshold","#keyFor","#getRoot","#writeStreamViaSyncHandle","#writeStreamViaWritable","#writeViaSyncHandle","#writeViaWritable","#isNotFoundError","#root"],"sources":["../../../src/batteries/storage/opfs/index.ts"],"sourcesContent":["/**\n * Browser-only Origin Private File System storage for spooled artifacts.\n *\n * @module @nhtio/adk/batteries/storage/opfs\n *\n * @remarks\n * Opt-in **browser-only** storage battery backed by the\n * [Origin Private File System](https://developer.mozilla.org/docs/Web/API/File_System_API/Origin_private_file_system)\n * (OPFS). Provides {@link OpfsSpoolReader} (a {@link @nhtio/adk!SpoolReader} over a `OpfsFileHandle`)\n * and {@link OpfsSpoolStore} (a `write(callId, bytes) → reader` persistence layer that wraps an\n * OPFS directory).\n *\n * The reader has two modes selected lazily on first method invocation based on the size of the\n * underlying file:\n *\n * - **Eager mode** — when `file.size` is below `streamThresholdBytes` (default 10 MiB), the\n * reader calls `file.text()` once, splits the content on `\\n`, and caches lines + byte count.\n * All subsequent calls resolve from memory.\n * - **Streaming mode** — when `file.size` meets or exceeds the threshold, the reader streams the\n * file once via `file.stream().getReader()` to build a line-offset index (`number[]` of byte\n * offsets per line), then serves each `line(i)` request by slicing the underlying `Blob` —\n * `Blob.slice(start, end).text()` decodes only the requested range, no head-of-file scan.\n * Caps RAM at one index + one line buffer regardless of file size.\n *\n * The store auto-selects its write API by execution scope:\n *\n * - In **worker scopes** (`self instanceof WorkerGlobalScope`), it acquires a\n * `FileSystemSyncAccessHandle` and writes synchronously. Sync handles are the only API\n * available in workers and the fastest path for the spool-write hot path.\n * - On the **main thread**, it uses `OpfsFileHandle.createWritable()` and the async\n * stream API. Sync access handles are not exposed on the main thread.\n *\n * This module assumes a browser-equivalent runtime — `navigator.storage`,\n * `OpfsFileHandle`, `TextEncoder`/`TextDecoder`, and `Blob` must all exist. It must not\n * be imported from Node code; do so and you will fail at resolve time when `navigator` is\n * referenced.\n *\n * @example\n * ```ts\n * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'\n *\n * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })\n * const reader = await store.write(callId, bytes)\n * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact\n * const artifact = new Ctor(reader)\n * ```\n */\n\nimport { isInstanceOf } from '@nhtio/adk/guards'\nimport type { SpoolReader, SpoolStore } from '@nhtio/adk/common'\n\n// The project's tsconfig limits `lib` to `ESNext`, so the DOM and File System Access types\n// referenced below are not in scope by default — neither `tsc --noEmit` nor the downstream dts\n// pipeline (api-extractor) can see them. Re-declare here the **minimum** surface this module\n// touches via a local handle-shape interface. Public API uses `OpfsFileHandle` /\n// `OpfsDirectoryHandle` instead of the DOM globals so the published `.d.ts` is self-contained\n// and consumers do not have to chase the lib graph.\n\n/**\n * Minimal subset of the\n * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)\n * `OpfsFileHandle` interface that this module touches at runtime. Structurally compatible\n * with the DOM-lib `OpfsFileHandle` — at call sites you pass real OPFS handles directly.\n */\nexport interface OpfsFileHandle {\n /** Discriminant: always `'file'`. */\n readonly kind: 'file'\n /** The entry's name. */\n readonly name: string\n /** Resolve a readable {@link OpfsFile} snapshot of the handle's contents. */\n getFile(): Promise<OpfsFile>\n /** Open a writable stream that replaces the file's contents. */\n createWritable(): Promise<OpfsWritableFileStream>\n}\n\n/**\n * Minimal subset of the\n * [File System Access](https://developer.mozilla.org/docs/Web/API/File_System_API)\n * `OpfsDirectoryHandle` interface that this module touches at runtime. Structurally\n * compatible with the DOM-lib `OpfsDirectoryHandle` — at call sites you pass real OPFS\n * handles directly.\n */\nexport interface OpfsDirectoryHandle {\n /** Discriminant: always `'directory'`. */\n readonly kind: 'directory'\n /** The directory's name. */\n readonly name: string\n /** Resolve a child file handle, optionally creating it. */\n getFileHandle(name: string, options?: { create?: boolean }): Promise<OpfsFileHandle>\n /** Resolve a child directory handle, optionally creating it. */\n getDirectoryHandle(name: string, options?: { create?: boolean }): Promise<OpfsDirectoryHandle>\n /** Remove a child entry, optionally recursively. */\n removeEntry(name: string, options?: { recursive?: boolean }): Promise<void>\n}\n\n/**\n * Minimal subset of the DOM `FileSystemWritableFileStream` interface used by the OPFS battery's\n * main-thread write path.\n */\nexport interface OpfsWritableFileStream {\n /** Append/write a chunk to the stream. */\n write(data: Uint8Array | ArrayBufferView | ArrayBuffer | string): Promise<void>\n /** Flush and close the stream, committing the written contents. */\n close(): Promise<void>\n}\n\n/**\n * Minimal subset of the DOM `Blob` interface used by {@link OpfsSpoolReader} streaming-mode\n * random-access reads. Real OPFS handles return a `File` here; we narrow to the methods we\n * actually call.\n */\nexport interface OpfsBlob {\n /** Byte length of the blob. */\n readonly size: number\n /** Return a sub-range of the blob as a new blob. */\n slice(start?: number, end?: number, contentType?: string): OpfsBlob\n /** Read the blob's contents as text. */\n text(): Promise<string>\n /** Open a readable byte stream over the blob. */\n stream(): OpfsReadableStream\n}\n\n/**\n * Minimal subset of the DOM `File` interface used by {@link OpfsSpoolReader}.\n */\nexport interface OpfsFile extends OpfsBlob {\n /** The file's name. */\n readonly name: string\n}\n\n/**\n * Minimal subset of the DOM `ReadableStream<Uint8Array>` interface used by streaming-mode\n * index construction.\n */\nexport interface OpfsReadableStream {\n /** Acquire a reader over the stream. */\n getReader(): OpfsReadableStreamReader\n}\n\n/**\n * Minimal subset of the DOM `ReadableStreamDefaultReader<Uint8Array>` interface used by\n * streaming-mode index construction.\n */\nexport interface OpfsReadableStreamReader {\n /** Read the next chunk, or signal end-of-stream with `done: true`. */\n read(): Promise<{ done: false; value: Uint8Array } | { done: true; value: undefined }>\n /** Release the reader's lock on the stream. */\n releaseLock(): void\n}\n\ndeclare const navigator: {\n storage: { getDirectory(): Promise<OpfsDirectoryHandle> }\n}\ndeclare class TextEncoder {\n encode(input?: string): Uint8Array\n}\ndeclare const self: unknown\ndeclare const WorkerGlobalScope: { new (): unknown } | undefined\n\ninterface FileSystemSyncAccessHandle {\n truncate(newSize: number): void\n write(buffer: Uint8Array | ArrayBuffer | ArrayBufferView, options?: { at?: number }): number\n flush(): void\n close(): void\n}\ninterface OpfsFileHandleWithSyncAccess extends OpfsFileHandle {\n createSyncAccessHandle(): Promise<FileSystemSyncAccessHandle>\n}\n\nconst DEFAULT_STREAM_THRESHOLD_BYTES = 10 * 1024 * 1024 // 10 MiB\n\nconst LF = 0x0a // '\\n'\n\nconst isNonNegativeFiniteNumber = (n: unknown): n is number =>\n typeof n === 'number' && Number.isFinite(n) && n >= 0\n\n/**\n * Constructor options for {@link OpfsSpoolReader}.\n */\nexport interface OpfsSpoolReaderOptions {\n /**\n * Byte-length threshold that switches between eager and streaming modes.\n *\n * @remarks\n * - Below the threshold → eager (whole-file in memory).\n * - At or above the threshold → streaming (line-offset index + per-line slice reads).\n *\n * Set to `0` to force streaming mode; set to `Number.POSITIVE_INFINITY` to force eager mode.\n *\n * @defaultValue `10 * 1024 * 1024` (10 MiB)\n */\n streamThresholdBytes?: number\n}\n\ninterface EagerState {\n mode: 'eager'\n lines: string[]\n bytes: number\n content: string\n}\n\ninterface StreamingState {\n mode: 'streaming'\n file: OpfsFile\n /**\n * Byte offsets where each line *starts*. Length equals lineCount + 1; the final entry equals\n * the total byte length. So `offsets[i + 1] - offsets[i]` is the byte length of line `i`\n * including any trailing `\\n`.\n */\n offsets: number[]\n bytes: number\n}\n\ntype ReaderState = EagerState | StreamingState\n\n/**\n * Returns `true` when the current global scope is a Web Worker (`DedicatedWorkerGlobalScope`,\n * `SharedWorkerGlobalScope`, or `ServiceWorkerGlobalScope` all inherit from `WorkerGlobalScope`).\n *\n * @remarks\n * The check is needed at runtime because `FileSystemSyncAccessHandle` is only exposed in worker\n * scopes — calling it from the main thread throws. We pick the write strategy based on the\n * answer here.\n *\n * @internal\n */\nconst isWorkerScope = (): boolean => {\n if (typeof WorkerGlobalScope === 'undefined') return false\n // eslint-disable-next-line adk/use-is-instance-of -- native built-in narrowing on `self`; no cross-realm risk\n return self instanceof WorkerGlobalScope\n}\n\n/**\n * Reads an OPFS-backed file as a {@link @nhtio/adk!SpoolReader}.\n *\n * @remarks\n * Constructor is **not** async — but the first method call awaits a private readiness promise\n * that fetches the underlying `File` (and in eager mode, its contents). Subsequent calls reuse\n * the cached state. This keeps construction call sites synchronous while still doing real I/O\n * lazily.\n *\n * All four `SpoolReader` methods on this reader return promises. The `SpoolReader` contract\n * supports both sync and async return; consumers of `SpooledArtifact` handle either.\n */\nexport class OpfsSpoolReader implements SpoolReader {\n readonly #handle: OpfsFileHandle\n readonly #threshold: number\n #ready: Promise<ReaderState> | undefined\n\n constructor(handle: OpfsFileHandle, opts: OpfsSpoolReaderOptions = {}) {\n this.#handle = handle\n const raw = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES\n // Allow `Infinity` (forces eager) but reject anything non-finite-negative.\n if (typeof raw !== 'number' || Number.isNaN(raw) || raw < 0) {\n throw new TypeError(\n `OpfsSpoolReader: streamThresholdBytes must be a non-negative number or Infinity, got ${String(raw)}`\n )\n }\n this.#threshold = raw\n }\n\n /**\n * Returns `true` if `value` is an {@link OpfsSpoolReader} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is an {@link OpfsSpoolReader} instance.\n */\n public static isOpfsSpoolReader(value: unknown): value is OpfsSpoolReader {\n return isInstanceOf(value, 'OpfsSpoolReader', OpfsSpoolReader)\n }\n\n async line(index: number): Promise<string | undefined> {\n const state = await this.#load()\n if (state.mode === 'eager') return state.lines[index]\n if (index < 0 || index >= state.offsets.length - 1) return undefined\n return this.#readRange(state.file, state.offsets[index], state.offsets[index + 1])\n }\n\n async byteLength(): Promise<number> {\n const state = await this.#load()\n return state.bytes\n }\n\n async lineCount(): Promise<number> {\n const state = await this.#load()\n return state.mode === 'eager' ? state.lines.length : state.offsets.length - 1\n }\n\n /**\n * Returns the full underlying content as a single decoded string, byte-faithful to the source.\n *\n * @remarks\n * In **eager mode** the content is already cached at first-call load and this method is\n * effectively a property access. In **streaming mode** there is no cache: the file is re-read\n * (as a single `File.text()` call) on every invocation. Use `SpooledArtifact.asString()`\n * judiciously on large streaming-mode artifacts.\n */\n async readAll(): Promise<string> {\n const state = await this.#load()\n if (state.mode === 'eager') return state.content\n return state.file.text()\n }\n\n /**\n * Lazily initialise the reader's mode-specific state. Called by every public method; the\n * promise is cached so the work runs at most once.\n */\n #load(): Promise<ReaderState> {\n if (!this.#ready) this.#ready = this.#init()\n return this.#ready\n }\n\n async #init(): Promise<ReaderState> {\n const file = await this.#handle.getFile()\n const bytes = file.size\n if (!isNonNegativeFiniteNumber(bytes)) {\n throw new Error(`OpfsSpoolReader: file handle returned a non-finite size (${String(bytes)})`)\n }\n if (bytes < this.#threshold) {\n // Eager — pull the whole thing into memory.\n const content = await file.text()\n const lines = content === '' ? [] : content.split('\\n')\n return { mode: 'eager', lines, bytes, content }\n }\n // Streaming — build a line-offset index by scanning bytes once.\n return this.#buildStreamingIndex(file, bytes)\n }\n\n async #buildStreamingIndex(file: OpfsFile, bytes: number): Promise<StreamingState> {\n // Edge case first — an empty file is one offset (the EOF), zero lines.\n if (bytes === 0) return { mode: 'streaming', file, offsets: [0], bytes }\n\n // offsets[i] is the byte position where line `i` starts. offsets[lineCount] is one-past-end.\n // For \"a\\nb\\nc\" → offsets=[0, 2, 4, 5] (3 lines).\n // For \"a\\nb\\n\" → offsets=[0, 2, 4, 4] (3 lines, last is the trailing empty line). This\n // mirrors `String.prototype.split('\\n')` semantics so streaming and eager agree.\n const offsets: number[] = [0]\n let position = 0\n let lastByte = -1\n const reader = file.stream().getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n for (const byte of value) {\n position++\n if (byte === LF) offsets.push(position)\n lastByte = byte\n }\n }\n } finally {\n reader.releaseLock()\n }\n // If the file ends on a newline, the byte after the LF is the start of an empty trailing\n // line — record it. If it doesn't, the final line's end is the EOF and we need to push\n // it so line(N-1) can read up to bytes.\n if (lastByte === LF) offsets.push(position)\n else if (offsets[offsets.length - 1] !== position) offsets.push(position)\n return { mode: 'streaming', file, offsets, bytes }\n }\n\n /**\n * Slices the byte range `[start, end)` from the backing file and returns it as a UTF-8\n * string, stripping a trailing `\\n` if present.\n *\n * @remarks\n * `Blob.slice` is O(1) metadata; `Blob.text()` only decodes the slice. The line-offset index\n * brackets each line *with* its trailing LF (so `offsets[i+1]` points at the start of the\n * next line) and the `SpoolReader` contract returns lines *without* their trailing newline,\n * so we strip a single trailing LF if present.\n */\n async #readRange(file: OpfsFile, start: number, end: number): Promise<string> {\n if (start === end) return ''\n const slice = file.slice(start, end)\n const text = await slice.text()\n if (text.length > 0 && text.charCodeAt(text.length - 1) === LF) {\n return text.slice(0, -1)\n }\n return text\n }\n}\n\n/**\n * Constructor options for {@link OpfsSpoolStore}.\n */\nexport interface OpfsSpoolStoreOptions {\n /**\n * Optional thunk that resolves the {@link OpfsDirectoryHandle} used as the store root.\n *\n * @remarks\n * When omitted, the store resolves the root via `navigator.storage.getDirectory()` on its\n * first filesystem call. Override for tests (to point at a per-suite subdirectory) or to\n * scope the store to a nested directory inside OPFS.\n *\n * The thunk is invoked at most once per store; the returned handle is memoised.\n */\n directory?: () => Promise<OpfsDirectoryHandle>\n\n /**\n * Optional filename prefix prepended to every `callId`.\n *\n * @remarks\n * Prefix is a **filename prefix**, not a subdirectory — `keyPrefix: 'agent-runs/'` produces\n * a file literally named `agent-runs/<callId>` at the root, not a nested directory. (OPFS\n * filenames may not contain `/`, so use a non-`/` separator like `-` if you want a flat\n * namespace.) This mirrors the `keyPrefix` semantics in the flydrive and in-memory batteries.\n *\n * @defaultValue `\"\"`\n */\n keyPrefix?: string\n\n /**\n * Default `streamThresholdBytes` for readers produced by `write()` and `read()`. Individual\n * calls may override via their own `opts` argument.\n *\n * @defaultValue `10 * 1024 * 1024` (10 MiB)\n */\n streamThresholdBytes?: number\n}\n\n/**\n * \"Give bytes, get a reader\" persistence layer over an OPFS directory.\n *\n * @remarks\n * `write(callId, bytes)` resolves the root directory (lazily, on first call), opens or creates\n * the file named `keyPrefix + callId`, then writes via the API matching the current scope:\n * a `FileSystemSyncAccessHandle` in worker scopes, `OpfsFileHandle.createWritable()` on\n * the main thread. A fresh {@link OpfsSpoolReader} pointed at the same file is returned.\n *\n * `read(callId)` returns a reader without re-writing; `delete(callId)` removes the entry.\n *\n * The store is otherwise stateless — it owns no in-memory cache of writes. Multiple\n * `OpfsSpoolStore` instances sharing the same root directory and key prefix see the same data.\n *\n * @example\n * ```ts\n * import { OpfsSpoolStore } from '@nhtio/adk/batteries/storage/opfs'\n *\n * const store = new OpfsSpoolStore({ keyPrefix: 'agent-runs/' })\n *\n * const bytes = await tool.executor(ctx)(args)\n * const reader = await store.write(callId, bytes)\n * const Ctor = tool.artifactConstructor?.() ?? SpooledArtifact\n * const artifact = new Ctor(reader)\n * ```\n */\nexport class OpfsSpoolStore implements SpoolStore {\n readonly #resolveRoot: () => Promise<OpfsDirectoryHandle>\n readonly #prefix: string\n readonly #defaultThreshold: number\n #root: OpfsDirectoryHandle | undefined\n\n constructor(opts: OpfsSpoolStoreOptions = {}) {\n this.#resolveRoot = opts.directory ?? (() => navigator.storage.getDirectory())\n this.#prefix = opts.keyPrefix ?? ''\n this.#defaultThreshold = opts.streamThresholdBytes ?? DEFAULT_STREAM_THRESHOLD_BYTES\n }\n\n /**\n * Returns `true` if `value` is an {@link OpfsSpoolStore} instance.\n *\n * @remarks\n * Uses {@link @nhtio/adk!isInstanceOf} for cross-realm safety.\n *\n * @param value - The value to test.\n * @returns `true` when `value` is an {@link OpfsSpoolStore} instance.\n */\n public static isOpfsSpoolStore(value: unknown): value is OpfsSpoolStore {\n return isInstanceOf(value, 'OpfsSpoolStore', OpfsSpoolStore)\n }\n\n /**\n * Persists `bytes` under `callId` and returns a reader bound to the stored key.\n *\n * @remarks\n * `string` input is encoded as UTF-8; `Uint8Array` is stored byte-faithfully;\n * `ReadableStream<Uint8Array>` is written incrementally — the stream is consumed chunk-by-chunk\n * straight to OPFS without first materializing the whole payload in memory, which is the point\n * of accepting a stream for a durable store.\n *\n * @param callId - Identifier used to retrieve the bytes via {@link OpfsSpoolStore.read}.\n * @param bytes - The bytes to store, as a `string`, `Uint8Array`, or `ReadableStream<Uint8Array>`.\n * @param opts - Per-call override for `streamThresholdBytes`.\n * @returns An {@link OpfsSpoolReader} over the stored bytes.\n */\n async write(\n callId: string,\n bytes: string | Uint8Array | ReadableStream<Uint8Array>,\n opts?: OpfsSpoolReaderOptions\n ): Promise<OpfsSpoolReader> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n const handle = await root.getFileHandle(name, { create: true })\n if (isInstanceOf(bytes, 'ReadableStream', ReadableStream)) {\n if (isWorkerScope()) {\n await this.#writeStreamViaSyncHandle(handle, bytes)\n } else {\n await this.#writeStreamViaWritable(handle, bytes)\n }\n } else {\n const payload = typeof bytes === 'string' ? new TextEncoder().encode(bytes) : bytes\n if (isWorkerScope()) {\n await this.#writeViaSyncHandle(handle, payload)\n } else {\n await this.#writeViaWritable(handle, payload)\n }\n }\n return new OpfsSpoolReader(handle, {\n streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold,\n })\n }\n\n /**\n * Returns a reader over the bytes previously written under `callId`.\n *\n * @remarks\n * Returns `undefined` if the file does not exist.\n *\n * @param callId - Identifier supplied to a prior {@link OpfsSpoolStore.write} call.\n * @param opts - Per-call override for `streamThresholdBytes`.\n * @returns An {@link OpfsSpoolReader}, or `undefined` if the key is missing.\n */\n async read(callId: string, opts?: OpfsSpoolReaderOptions): Promise<OpfsSpoolReader | undefined> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n let handle: OpfsFileHandle\n try {\n handle = await root.getFileHandle(name)\n } catch (err) {\n if (this.#isNotFoundError(err)) return undefined\n throw err\n }\n return new OpfsSpoolReader(handle, {\n streamThresholdBytes: opts?.streamThresholdBytes ?? this.#defaultThreshold,\n })\n }\n\n /**\n * Removes the entry under `callId`.\n *\n * @param callId - Identifier whose entry should be removed.\n * @returns `true` if the entry existed and was removed; `false` if it didn't exist.\n */\n async delete(callId: string): Promise<boolean> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n try {\n await root.removeEntry(name)\n return true\n } catch (err) {\n if (this.#isNotFoundError(err)) return false\n throw err\n }\n }\n\n /**\n * Returns `true` if a file is present under `callId`.\n *\n * @param callId - Identifier to test.\n * @returns `true` when the file exists, `false` otherwise.\n */\n async has(callId: string): Promise<boolean> {\n const name = this.#keyFor(callId)\n const root = await this.#getRoot()\n try {\n await root.getFileHandle(name)\n return true\n } catch (err) {\n if (this.#isNotFoundError(err)) return false\n throw err\n }\n }\n\n /**\n * Returns the full filename for a given `callId` (i.e. `keyPrefix + callId`).\n *\n * @remarks\n * Useful for tests or for callers that want to interact with the underlying OPFS directory\n * directly.\n */\n keyFor(callId: string): string {\n return this.#keyFor(callId)\n }\n\n #keyFor(callId: string): string {\n return this.#prefix + callId\n }\n\n async #getRoot(): Promise<OpfsDirectoryHandle> {\n if (!this.#root) this.#root = await this.#resolveRoot()\n return this.#root\n }\n\n async #writeViaSyncHandle(handle: OpfsFileHandle, payload: Uint8Array): Promise<void> {\n const sync = await (handle as OpfsFileHandleWithSyncAccess).createSyncAccessHandle()\n try {\n sync.truncate(0)\n sync.write(payload, { at: 0 })\n sync.flush()\n } finally {\n sync.close()\n }\n }\n\n async #writeViaWritable(handle: OpfsFileHandle, payload: Uint8Array): Promise<void> {\n const writable = await handle.createWritable()\n try {\n await writable.write(payload)\n } finally {\n await writable.close()\n }\n }\n\n async #writeStreamViaWritable(\n handle: OpfsFileHandle,\n stream: ReadableStream<Uint8Array>\n ): Promise<void> {\n const writable = await handle.createWritable()\n try {\n const reader = stream.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (value) await writable.write(value)\n }\n } finally {\n reader.releaseLock()\n }\n } finally {\n await writable.close()\n }\n }\n\n async #writeStreamViaSyncHandle(\n handle: OpfsFileHandle,\n stream: ReadableStream<Uint8Array>\n ): Promise<void> {\n const sync = await (handle as OpfsFileHandleWithSyncAccess).createSyncAccessHandle()\n try {\n sync.truncate(0)\n let at = 0\n const reader = stream.getReader()\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n if (value && value.byteLength > 0) {\n sync.write(value, { at })\n at += value.byteLength\n }\n }\n } finally {\n reader.releaseLock()\n }\n sync.flush()\n } finally {\n sync.close()\n }\n }\n\n #isNotFoundError(err: unknown): boolean {\n if (err === null || typeof err !== 'object') return false\n const name = (err as { name?: unknown }).name\n return name === 'NotFoundError'\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("../../chunk-Ble4zEEl.js");
3
- const require_tool = require("../../tool-CVyZkFC7.js");
4
- require("../../common-Cj8TaQ9U.js");
3
+ const require_tool = require("../../tool-D5WGVIcI.js");
4
+ require("../../common-DZl3ADJs.js");
5
5
  let _nhtio_validation = require("@nhtio/validation");
6
6
  //#region src/batteries/tools/color/index.ts
7
7
  /**
@@ -15,6 +15,7 @@ let _nhtio_validation = require("@nhtio/validation");
15
15
  */
16
16
  function hexToRgb(hex) {
17
17
  const cleaned = hex.replace(/^#/, "");
18
+ if (!/^[0-9a-fA-F]+$/.test(cleaned)) return null;
18
19
  let r;
19
20
  let g;
20
21
  let b;
@@ -1 +1 @@
1
- {"version":3,"file":"color.cjs","names":[],"sources":["../../../src/batteries/tools/color/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for color conversion and palette-oriented calculations.\n *\n * @module @nhtio/adk/batteries/tools/color\n *\n * @remarks\n * Pre-constructed bundled tools for the `color` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { validator } from '@nhtio/validation'\n\ntype RGB = { r: number; g: number; b: number }\ntype HSL = { h: number; s: number; l: number }\n\nfunction hexToRgb(hex: string): RGB | null {\n const cleaned = hex.replace(/^#/, '')\n let r: number\n let g: number\n let b: number\n\n if (cleaned.length === 3) {\n r = Number.parseInt(cleaned[0] + cleaned[0], 16)\n g = Number.parseInt(cleaned[1] + cleaned[1], 16)\n b = Number.parseInt(cleaned[2] + cleaned[2], 16)\n } else if (cleaned.length === 6) {\n r = Number.parseInt(cleaned.slice(0, 2), 16)\n g = Number.parseInt(cleaned.slice(2, 4), 16)\n b = Number.parseInt(cleaned.slice(4, 6), 16)\n } else {\n return null\n }\n\n if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return null\n return { r, g, b }\n}\n\nfunction parseRgbString(input: string): RGB | null {\n const match = input.match(/^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i)\n if (!match) return null\n const r = Number.parseInt(match[1], 10)\n const g = Number.parseInt(match[2], 10)\n const b = Number.parseInt(match[3], 10)\n if (r > 255 || g > 255 || b > 255) return null\n return { r, g, b }\n}\n\nfunction parseHslString(input: string): HSL | null {\n const match = input.match(/^hsl\\(\\s*(\\d+)\\s*,\\s*(\\d+)%?\\s*,\\s*(\\d+)%?\\s*\\)$/i)\n if (!match) return null\n return {\n h: Number.parseInt(match[1], 10) % 360,\n s: Math.min(100, Number.parseInt(match[2], 10)),\n l: Math.min(100, Number.parseInt(match[3], 10)),\n }\n}\n\nconst NAMED_COLORS: Record<string, string> = {\n 'black': '#000000',\n 'white': '#FFFFFF',\n 'transparent': '#FFFFFF',\n 'aqua': '#00FFFF',\n 'magenta': '#FF00FF',\n 'fuchsia': '#FF00FF',\n 'silver': '#C0C0C0',\n 'maroon': '#800000',\n 'olive': '#808000',\n 'navy': '#000080',\n 'coral': '#FF7F50',\n 'crimson': '#DC143C',\n 'gold': '#FFD700',\n 'ivory': '#FFFFF0',\n 'khaki': '#F0E68C',\n 'lavender': '#E6E6FA',\n 'plum': '#DDA0DD',\n 'salmon': '#FA8072',\n 'sienna': '#A0522D',\n 'tan': '#D2B48C',\n 'tomato': '#FF6347',\n 'turquoise': '#40E0D0',\n 'violet': '#EE82EE',\n 'wheat': '#F5DEB3',\n 'red': '#F44336',\n 'red-lighten-5': '#FFEBEE',\n 'red-lighten-4': '#FFCDD2',\n 'red-lighten-3': '#EF9A9A',\n 'red-lighten-2': '#E57373',\n 'red-lighten-1': '#EF5350',\n 'red-darken-1': '#E53935',\n 'red-darken-2': '#D32F2F',\n 'red-darken-3': '#C62828',\n 'red-darken-4': '#B71C1C',\n 'red-accent-1': '#FF8A80',\n 'red-accent-2': '#FF5252',\n 'red-accent-3': '#FF1744',\n 'red-accent-4': '#D50000',\n 'pink': '#E91E63',\n 'pink-lighten-5': '#FCE4EC',\n 'pink-lighten-4': '#F8BBD0',\n 'pink-lighten-3': '#F48FB1',\n 'pink-lighten-2': '#F06292',\n 'pink-lighten-1': '#EC407A',\n 'pink-darken-1': '#D81B60',\n 'pink-darken-2': '#C2185B',\n 'pink-darken-3': '#AD1457',\n 'pink-darken-4': '#880E4F',\n 'pink-accent-1': '#FF80AB',\n 'pink-accent-2': '#FF4081',\n 'pink-accent-3': '#F50057',\n 'pink-accent-4': '#C51162',\n 'purple': '#9C27B0',\n 'purple-lighten-5': '#F3E5F5',\n 'purple-lighten-4': '#E1BEE7',\n 'purple-lighten-3': '#CE93D8',\n 'purple-lighten-2': '#BA68C8',\n 'purple-lighten-1': '#AB47BC',\n 'purple-darken-1': '#8E24AA',\n 'purple-darken-2': '#7B1FA2',\n 'purple-darken-3': '#6A1B9A',\n 'purple-darken-4': '#4A148C',\n 'purple-accent-1': '#EA80FC',\n 'purple-accent-2': '#E040FB',\n 'purple-accent-3': '#D500F9',\n 'purple-accent-4': '#AA00FF',\n 'deep-purple': '#673AB7',\n 'deep-purple-lighten-5': '#EDE7F6',\n 'deep-purple-lighten-4': '#D1C4E9',\n 'deep-purple-lighten-3': '#B39DDB',\n 'deep-purple-lighten-2': '#9575CD',\n 'deep-purple-lighten-1': '#7E57C2',\n 'deep-purple-darken-1': '#5E35B1',\n 'deep-purple-darken-2': '#512DA8',\n 'deep-purple-darken-3': '#4527A0',\n 'deep-purple-darken-4': '#311B92',\n 'deep-purple-accent-1': '#B388FF',\n 'deep-purple-accent-2': '#7C4DFF',\n 'deep-purple-accent-3': '#651FFF',\n 'deep-purple-accent-4': '#6200EA',\n 'indigo': '#3F51B5',\n 'indigo-lighten-5': '#E8EAF6',\n 'indigo-lighten-4': '#C5CAE9',\n 'indigo-lighten-3': '#9FA8DA',\n 'indigo-lighten-2': '#7986CB',\n 'indigo-lighten-1': '#5C6BC0',\n 'indigo-darken-1': '#3949AB',\n 'indigo-darken-2': '#303F9F',\n 'indigo-darken-3': '#283593',\n 'indigo-darken-4': '#1A237E',\n 'indigo-accent-1': '#8C9EFF',\n 'indigo-accent-2': '#536DFE',\n 'indigo-accent-3': '#3D5AFE',\n 'indigo-accent-4': '#304FFE',\n 'blue': '#2196F3',\n 'blue-lighten-5': '#E3F2FD',\n 'blue-lighten-4': '#BBDEFB',\n 'blue-lighten-3': '#90CAF9',\n 'blue-lighten-2': '#64B5F6',\n 'blue-lighten-1': '#42A5F5',\n 'blue-darken-1': '#1E88E5',\n 'blue-darken-2': '#1976D2',\n 'blue-darken-3': '#1565C0',\n 'blue-darken-4': '#0D47A1',\n 'blue-accent-1': '#82B1FF',\n 'blue-accent-2': '#448AFF',\n 'blue-accent-3': '#2979FF',\n 'blue-accent-4': '#2962FF',\n 'light-blue': '#03A9F4',\n 'light-blue-lighten-5': '#E1F5FE',\n 'light-blue-lighten-4': '#B3E5FC',\n 'light-blue-lighten-3': '#81D4FA',\n 'light-blue-lighten-2': '#4FC3F7',\n 'light-blue-lighten-1': '#29B6F6',\n 'light-blue-darken-1': '#039BE5',\n 'light-blue-darken-2': '#0288D1',\n 'light-blue-darken-3': '#0277BD',\n 'light-blue-darken-4': '#01579B',\n 'light-blue-accent-1': '#80D8FF',\n 'light-blue-accent-2': '#40C4FF',\n 'light-blue-accent-3': '#00B0FF',\n 'light-blue-accent-4': '#0091EA',\n 'cyan': '#00BCD4',\n 'cyan-lighten-5': '#E0F7FA',\n 'cyan-lighten-4': '#B2EBF2',\n 'cyan-lighten-3': '#80DEEA',\n 'cyan-lighten-2': '#4DD0E1',\n 'cyan-lighten-1': '#26C6DA',\n 'cyan-darken-1': '#00ACC1',\n 'cyan-darken-2': '#0097A7',\n 'cyan-darken-3': '#00838F',\n 'cyan-darken-4': '#006064',\n 'cyan-accent-1': '#84FFFF',\n 'cyan-accent-2': '#18FFFF',\n 'cyan-accent-3': '#00E5FF',\n 'cyan-accent-4': '#00B8D4',\n 'teal': '#009688',\n 'teal-lighten-5': '#E0F2F1',\n 'teal-lighten-4': '#B2DFDB',\n 'teal-lighten-3': '#80CBC4',\n 'teal-lighten-2': '#4DB6AC',\n 'teal-lighten-1': '#26A69A',\n 'teal-darken-1': '#00897B',\n 'teal-darken-2': '#00796B',\n 'teal-darken-3': '#00695C',\n 'teal-darken-4': '#004D40',\n 'teal-accent-1': '#A7FFEB',\n 'teal-accent-2': '#64FFDA',\n 'teal-accent-3': '#1DE9B6',\n 'teal-accent-4': '#00BFA5',\n 'green': '#4CAF50',\n 'green-lighten-5': '#E8F5E9',\n 'green-lighten-4': '#C8E6C9',\n 'green-lighten-3': '#A5D6A7',\n 'green-lighten-2': '#81C784',\n 'green-lighten-1': '#66BB6A',\n 'green-darken-1': '#43A047',\n 'green-darken-2': '#388E3C',\n 'green-darken-3': '#2E7D32',\n 'green-darken-4': '#1B5E20',\n 'green-accent-1': '#B9F6CA',\n 'green-accent-2': '#69F0AE',\n 'green-accent-3': '#00E676',\n 'green-accent-4': '#00C853',\n 'light-green': '#8BC34A',\n 'light-green-lighten-5': '#F1F8E9',\n 'light-green-lighten-4': '#DCEDC8',\n 'light-green-lighten-3': '#C5E1A5',\n 'light-green-lighten-2': '#AED581',\n 'light-green-lighten-1': '#9CCC65',\n 'light-green-darken-1': '#7CB342',\n 'light-green-darken-2': '#689F38',\n 'light-green-darken-3': '#558B2F',\n 'light-green-darken-4': '#33691E',\n 'light-green-accent-1': '#CCFF90',\n 'light-green-accent-2': '#B2FF59',\n 'light-green-accent-3': '#76FF03',\n 'light-green-accent-4': '#64DD17',\n 'lime': '#CDDC39',\n 'lime-lighten-5': '#F9FBE7',\n 'lime-lighten-4': '#F0F4C3',\n 'lime-lighten-3': '#E6EE9C',\n 'lime-lighten-2': '#DCE775',\n 'lime-lighten-1': '#D4E157',\n 'lime-darken-1': '#C0CA33',\n 'lime-darken-2': '#AFB42B',\n 'lime-darken-3': '#9E9D24',\n 'lime-darken-4': '#827717',\n 'lime-accent-1': '#F4FF81',\n 'lime-accent-2': '#EEFF41',\n 'lime-accent-3': '#C6FF00',\n 'lime-accent-4': '#AEEA00',\n 'yellow': '#FFEB3B',\n 'yellow-lighten-5': '#FFFDE7',\n 'yellow-lighten-4': '#FFF9C4',\n 'yellow-lighten-3': '#FFF59D',\n 'yellow-lighten-2': '#FFF176',\n 'yellow-lighten-1': '#FFEE58',\n 'yellow-darken-1': '#FDD835',\n 'yellow-darken-2': '#FBC02D',\n 'yellow-darken-3': '#F9A825',\n 'yellow-darken-4': '#F57F17',\n 'yellow-accent-1': '#FFFF8D',\n 'yellow-accent-2': '#FFFF00',\n 'yellow-accent-3': '#FFEA00',\n 'yellow-accent-4': '#FFD600',\n 'amber': '#FFC107',\n 'amber-lighten-5': '#FFF8E1',\n 'amber-lighten-4': '#FFECB3',\n 'amber-lighten-3': '#FFE082',\n 'amber-lighten-2': '#FFD54F',\n 'amber-lighten-1': '#FFCA28',\n 'amber-darken-1': '#FFB300',\n 'amber-darken-2': '#FFA000',\n 'amber-darken-3': '#FF8F00',\n 'amber-darken-4': '#FF6F00',\n 'amber-accent-1': '#FFE57F',\n 'amber-accent-2': '#FFD740',\n 'amber-accent-3': '#FFC400',\n 'amber-accent-4': '#FFAB00',\n 'orange': '#FF9800',\n 'orange-lighten-5': '#FFF3E0',\n 'orange-lighten-4': '#FFE0B2',\n 'orange-lighten-3': '#FFCC80',\n 'orange-lighten-2': '#FFB74D',\n 'orange-lighten-1': '#FFA726',\n 'orange-darken-1': '#FB8C00',\n 'orange-darken-2': '#F57C00',\n 'orange-darken-3': '#EF6C00',\n 'orange-darken-4': '#E65100',\n 'orange-accent-1': '#FFD180',\n 'orange-accent-2': '#FFAB40',\n 'orange-accent-3': '#FF9100',\n 'orange-accent-4': '#FF6D00',\n 'deep-orange': '#FF5722',\n 'deep-orange-lighten-5': '#FBE9E7',\n 'deep-orange-lighten-4': '#FFCCBC',\n 'deep-orange-lighten-3': '#FFAB91',\n 'deep-orange-lighten-2': '#FF8A65',\n 'deep-orange-lighten-1': '#FF7043',\n 'deep-orange-darken-1': '#F4511E',\n 'deep-orange-darken-2': '#E64A19',\n 'deep-orange-darken-3': '#D84315',\n 'deep-orange-darken-4': '#BF360C',\n 'deep-orange-accent-1': '#FF9E80',\n 'deep-orange-accent-2': '#FF6E40',\n 'deep-orange-accent-3': '#FF3D00',\n 'deep-orange-accent-4': '#DD2C00',\n 'brown': '#795548',\n 'brown-lighten-5': '#EFEBE9',\n 'brown-lighten-4': '#D7CCC8',\n 'brown-lighten-3': '#BCAAA4',\n 'brown-lighten-2': '#A1887F',\n 'brown-lighten-1': '#8D6E63',\n 'brown-darken-1': '#6D4C41',\n 'brown-darken-2': '#5D4037',\n 'brown-darken-3': '#4E342E',\n 'brown-darken-4': '#3E2723',\n 'blue-grey': '#607D8B',\n 'blue-grey-lighten-5': '#ECEFF1',\n 'blue-grey-lighten-4': '#CFD8DC',\n 'blue-grey-lighten-3': '#B0BEC5',\n 'blue-grey-lighten-2': '#90A4AE',\n 'blue-grey-lighten-1': '#78909C',\n 'blue-grey-darken-1': '#546E7A',\n 'blue-grey-darken-2': '#455A64',\n 'blue-grey-darken-3': '#37474F',\n 'blue-grey-darken-4': '#263238',\n 'grey': '#9E9E9E',\n 'gray': '#9E9E9E',\n 'grey-lighten-5': '#FAFAFA',\n 'grey-lighten-4': '#F5F5F5',\n 'grey-lighten-3': '#EEEEEE',\n 'grey-lighten-2': '#E0E0E0',\n 'grey-lighten-1': '#BDBDBD',\n 'grey-darken-1': '#757575',\n 'grey-darken-2': '#616161',\n 'grey-darken-3': '#424242',\n 'grey-darken-4': '#212121',\n}\n\nfunction parseColor(input: string): RGB | null {\n const trimmed = input.trim()\n const lower = trimmed.toLowerCase()\n\n if (NAMED_COLORS[lower]) {\n return hexToRgb(NAMED_COLORS[lower])\n }\n\n if (trimmed.startsWith('#')) return hexToRgb(trimmed)\n if (lower.startsWith('rgb(')) return parseRgbString(trimmed)\n if (lower.startsWith('hsl(')) {\n const hsl = parseHslString(trimmed)\n return hsl ? hslToRgb(hsl) : null\n }\n\n return hexToRgb(trimmed)\n}\n\nfunction rgbToHex(rgb: RGB): string {\n const toHex = (n: number) =>\n Math.round(Math.max(0, Math.min(255, n)))\n .toString(16)\n .padStart(2, '0')\n return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`\n}\n\nfunction rgbToHsl(rgb: RGB): HSL {\n const r = rgb.r / 255\n const g = rgb.g / 255\n const b = rgb.b / 255\n\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n const l = (max + min) / 2\n\n if (max === min) return { h: 0, s: 0, l: Math.round(l * 100) }\n\n const d = max - min\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)\n\n let h = 0\n if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6\n else if (max === g) h = ((b - r) / d + 2) / 6\n else h = ((r - g) / d + 4) / 6\n\n return {\n h: Math.round(h * 360),\n s: Math.round(s * 100),\n l: Math.round(l * 100),\n }\n}\n\nfunction hslToRgb(hsl: HSL): RGB {\n const h = hsl.h / 360\n const s = hsl.s / 100\n const l = hsl.l / 100\n\n if (s === 0) {\n const v = Math.round(l * 255)\n return { r: v, g: v, b: v }\n }\n\n const hue2rgb = (p: number, q: number, t: number) => {\n if (t < 0) t += 1\n if (t > 1) t -= 1\n if (t < 1 / 6) return p + (q - p) * 6 * t\n if (t < 1 / 2) return q\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6\n return p\n }\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s\n const p = 2 * l - q\n\n return {\n r: Math.round(hue2rgb(p, q, h + 1 / 3) * 255),\n g: Math.round(hue2rgb(p, q, h) * 255),\n b: Math.round(hue2rgb(p, q, h - 1 / 3) * 255),\n }\n}\n\nfunction relativeLuminance(rgb: RGB): number {\n const srgb = [rgb.r, rgb.g, rgb.b].map((c) => {\n const s = c / 255\n return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4)\n })\n return 0.2126 * srgb[0] + 0.7152 * srgb[1] + 0.0722 * srgb[2]\n}\n\nfunction contrastRatio(c1: RGB, c2: RGB): number {\n const l1 = relativeLuminance(c1)\n const l2 = relativeLuminance(c2)\n const lighter = Math.max(l1, l2)\n const darker = Math.min(l1, l2)\n return (lighter + 0.05) / (darker + 0.05)\n}\n\nfunction rotateHue(hsl: HSL, degrees: number): HSL {\n return { h: (hsl.h + degrees + 360) % 360, s: hsl.s, l: hsl.l }\n}\n\nfunction formatColor(rgb: RGB): string {\n const hex = rgbToHex(rgb)\n const hsl = rgbToHsl(rgb)\n return `${hex} / rgb(${rgb.r}, ${rgb.g}, ${rgb.b}) / hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`\n}\n\n/**\n * Compute the WCAG 2.1 contrast ratio between two colours.\n *\n * @remarks\n * Accepts hex (`#rgb`, `#rrggbb`), `rgb()`, `hsl()`, or one of the CSS / Material Design named\n * colours. Reports the ratio and pass/fail against WCAG AA and AAA at both normal and large text\n * sizes. If the foreground/background combination fails AA Normal (4.5:1), the tool suggests\n * lightened or darkened variants that would pass.\n */\nexport const colorContrastTool = new Tool({\n name: 'color_contrast',\n description:\n 'Check the contrast ratio between two colors for WCAG accessibility compliance. Reports the contrast ratio and pass/fail for WCAG AA and AAA levels.',\n inputSchema: validator.object({\n foreground: validator\n .string()\n .required()\n .description('Foreground color (hex, rgb(), hsl(), or named color).'),\n background: validator\n .string()\n .required()\n .description('Background color (hex, rgb(), hsl(), or named color).'),\n }),\n handler: async (args) => {\n const { foreground, background } = args as { foreground: string; background: string }\n const fg = parseColor(foreground)\n const bg = parseColor(background)\n\n if (!fg) return `Error: could not parse foreground color \"${foreground}\".`\n if (!bg) return `Error: could not parse background color \"${background}\".`\n\n const ratio = contrastRatio(fg, bg)\n const rounded = Math.round(ratio * 100) / 100\n\n const aaLargeText = ratio >= 3\n const aaNormalText = ratio >= 4.5\n const aaaLargeText = ratio >= 4.5\n const aaaNormalText = ratio >= 7\n\n const lines = [\n `Foreground: ${formatColor(fg)}`,\n `Background: ${formatColor(bg)}`,\n `Contrast ratio: ${rounded}:1`,\n '',\n 'WCAG 2.1 compliance:',\n ` AA Normal text (4.5:1): ${aaNormalText ? 'PASS' : 'FAIL'}`,\n ` AA Large text (3.0:1): ${aaLargeText ? 'PASS' : 'FAIL'}`,\n ` AAA Normal text (7.0:1): ${aaaNormalText ? 'PASS' : 'FAIL'}`,\n ` AAA Large text (4.5:1): ${aaaLargeText ? 'PASS' : 'FAIL'}`,\n ]\n\n if (!aaNormalText) {\n const fgHsl = rgbToHsl(fg)\n const bgHsl = rgbToHsl(bg)\n const fgLighter = fgHsl.l > bgHsl.l\n\n const suggestions: string[] = []\n if (fgLighter) {\n const lighter = hslToRgb({ ...fgHsl, l: Math.min(100, fgHsl.l + 15) })\n const darkerBg = hslToRgb({ ...bgHsl, l: Math.max(0, bgHsl.l - 15) })\n if (contrastRatio(lighter, bg) >= 4.5) {\n suggestions.push(\n ` Lighten foreground to ${rgbToHex(lighter)} (ratio: ${Math.round(contrastRatio(lighter, bg) * 100) / 100}:1)`\n )\n }\n if (contrastRatio(fg, darkerBg) >= 4.5) {\n suggestions.push(\n ` Darken background to ${rgbToHex(darkerBg)} (ratio: ${Math.round(contrastRatio(fg, darkerBg) * 100) / 100}:1)`\n )\n }\n } else {\n const darker = hslToRgb({ ...fgHsl, l: Math.max(0, fgHsl.l - 15) })\n const lighterBg = hslToRgb({ ...bgHsl, l: Math.min(100, bgHsl.l + 15) })\n if (contrastRatio(darker, bg) >= 4.5) {\n suggestions.push(\n ` Darken foreground to ${rgbToHex(darker)} (ratio: ${Math.round(contrastRatio(darker, bg) * 100) / 100}:1)`\n )\n }\n if (contrastRatio(fg, lighterBg) >= 4.5) {\n suggestions.push(\n ` Lighten background to ${rgbToHex(lighterBg)} (ratio: ${Math.round(contrastRatio(fg, lighterBg) * 100) / 100}:1)`\n )\n }\n }\n\n if (suggestions.length > 0) {\n lines.push('', 'Suggestions to reach AA Normal (4.5:1):')\n lines.push(...suggestions)\n }\n }\n\n return lines.join('\\n')\n },\n})\n\n/**\n * Generate a colour palette from a base colour using a named harmony.\n *\n * @remarks\n * Supported schemes: `complementary`, `analogous`, `triadic`, `split-complementary`,\n * `monochromatic`. Each entry reports its hex, rgb, and hsl forms, plus the contrast ratio\n * relative to the base colour.\n */\nexport const colorSchemeTool = new Tool({\n name: 'color_scheme',\n description:\n 'Generate a color palette from a base color. Supports complementary, analogous, triadic, split-complementary, and monochromatic schemes.',\n inputSchema: validator.object({\n color: validator\n .string()\n .required()\n .description('Base color (hex, rgb(), hsl(), or named color).'),\n scheme: validator\n .string()\n .valid('complementary', 'analogous', 'triadic', 'split-complementary', 'monochromatic')\n .required()\n .description('Type of color scheme to generate.'),\n }),\n handler: async (args) => {\n const { color, scheme } = args as {\n color: string\n scheme: 'complementary' | 'analogous' | 'triadic' | 'split-complementary' | 'monochromatic'\n }\n const rgb = parseColor(color)\n if (!rgb) return `Error: could not parse color \"${color}\".`\n\n const hsl = rgbToHsl(rgb)\n const palette: { label: string; rgb: RGB }[] = [{ label: 'Base', rgb }]\n\n switch (scheme) {\n case 'complementary':\n palette.push({ label: 'Complement', rgb: hslToRgb(rotateHue(hsl, 180)) })\n break\n\n case 'analogous':\n palette.push({ label: 'Analogous -30', rgb: hslToRgb(rotateHue(hsl, -30)) })\n palette.push({ label: 'Analogous +30', rgb: hslToRgb(rotateHue(hsl, 30)) })\n break\n\n case 'triadic':\n palette.push({ label: 'Triadic +120', rgb: hslToRgb(rotateHue(hsl, 120)) })\n palette.push({ label: 'Triadic +240', rgb: hslToRgb(rotateHue(hsl, 240)) })\n break\n\n case 'split-complementary':\n palette.push({ label: 'Split +150', rgb: hslToRgb(rotateHue(hsl, 150)) })\n palette.push({ label: 'Split +210', rgb: hslToRgb(rotateHue(hsl, 210)) })\n break\n\n case 'monochromatic':\n palette.push({ label: 'Light', rgb: hslToRgb({ ...hsl, l: Math.min(100, hsl.l + 20) }) })\n palette.push({ label: 'Lighter', rgb: hslToRgb({ ...hsl, l: Math.min(100, hsl.l + 35) }) })\n palette.push({ label: 'Dark', rgb: hslToRgb({ ...hsl, l: Math.max(0, hsl.l - 20) }) })\n palette.push({ label: 'Darker', rgb: hslToRgb({ ...hsl, l: Math.max(0, hsl.l - 35) }) })\n break\n }\n\n const lines = [`Color scheme: ${scheme}`, '']\n for (const entry of palette) {\n lines.push(`${entry.label}: ${formatColor(entry.rgb)}`)\n }\n\n if (palette.length > 1) {\n lines.push('', 'Contrast ratios with base:')\n for (const entry of palette.slice(1)) {\n const ratio = Math.round(contrastRatio(rgb, entry.rgb) * 100) / 100\n lines.push(` ${entry.label}: ${ratio}:1`)\n }\n }\n\n return lines.join('\\n')\n },\n})\n\n/**\n * Lighten or darken a colour by a percentage of HSL lightness.\n *\n * @remarks\n * `amount` is clamped to `[1, 100]`; `steps` is clamped to `[1, 10]`. With `steps > 1` the tool\n * emits a ramp of progressively-adjusted colours, useful for generating tint/shade scales.\n */\nexport const colorAdjustTool = new Tool({\n name: 'color_adjust',\n description:\n 'Lighten or darken a color by a specified amount. Returns the adjusted color in hex, rgb, and hsl formats. Can generate multiple steps for a tint/shade scale.',\n inputSchema: validator.object({\n color: validator\n .string()\n .required()\n .description('Color to adjust (hex, rgb(), hsl(), or named color).'),\n action: validator\n .string()\n .valid('lighten', 'darken')\n .required()\n .description('Whether to lighten or darken the color.'),\n amount: validator\n .number()\n .default(15)\n .description('Amount to adjust per step (1-100, percentage of lightness). Default: 15.'),\n steps: validator\n .number()\n .default(1)\n .description('Generate multiple steps of adjustment (1-10). Default: 1.'),\n }),\n handler: async (args) => {\n const {\n color,\n action,\n amount: rawAmount,\n steps: rawSteps,\n } = args as {\n color: string\n action: 'lighten' | 'darken'\n amount: number\n steps: number\n }\n const rgb = parseColor(color)\n if (!rgb) return `Error: could not parse color \"${color}\".`\n\n const amount = Math.max(1, Math.min(100, rawAmount))\n const steps = Math.max(1, Math.min(10, rawSteps))\n const hsl = rgbToHsl(rgb)\n\n const lines = [`Original: ${formatColor(rgb)}`]\n\n for (let i = 1; i <= steps; i++) {\n const delta = amount * i\n const newL = action === 'lighten' ? Math.min(100, hsl.l + delta) : Math.max(0, hsl.l - delta)\n const adjusted = hslToRgb({ ...hsl, l: newL })\n const label =\n steps === 1\n ? `${action === 'lighten' ? 'Lightened' : 'Darkened'} (${delta}%)`\n : `Step ${i} (${action} ${delta}%)`\n lines.push(`${label}: ${formatColor(adjusted)}`)\n }\n\n return lines.join('\\n')\n },\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"color.cjs","names":[],"sources":["../../../src/batteries/tools/color/index.ts"],"sourcesContent":["/**\n * Pre-constructed tools for color conversion and palette-oriented calculations.\n *\n * @module @nhtio/adk/batteries/tools/color\n *\n * @remarks\n * Pre-constructed bundled tools for the `color` category. Import individually, the whole\n * category, or import every tool via `@nhtio/adk/batteries`.\n */\n\nimport { Tool } from '@nhtio/adk/common'\nimport { validator } from '@nhtio/validation'\n\ntype RGB = { r: number; g: number; b: number }\ntype HSL = { h: number; s: number; l: number }\n\nfunction hexToRgb(hex: string): RGB | null {\n const cleaned = hex.replace(/^#/, '')\n // Reject any non-hex character up front. `Number.parseInt('1Z', 16)` silently drops the trailing\n // 'Z' and returns 1 (passing the NaN check below), so '#1Z2Z3Z' would otherwise be accepted as a\n // bogus colour rgb(1, 2, 3).\n if (!/^[0-9a-fA-F]+$/.test(cleaned)) return null\n\n let r: number\n let g: number\n let b: number\n\n if (cleaned.length === 3) {\n r = Number.parseInt(cleaned[0] + cleaned[0], 16)\n g = Number.parseInt(cleaned[1] + cleaned[1], 16)\n b = Number.parseInt(cleaned[2] + cleaned[2], 16)\n } else if (cleaned.length === 6) {\n r = Number.parseInt(cleaned.slice(0, 2), 16)\n g = Number.parseInt(cleaned.slice(2, 4), 16)\n b = Number.parseInt(cleaned.slice(4, 6), 16)\n } else {\n return null\n }\n\n if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) return null\n return { r, g, b }\n}\n\nfunction parseRgbString(input: string): RGB | null {\n const match = input.match(/^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i)\n if (!match) return null\n const r = Number.parseInt(match[1], 10)\n const g = Number.parseInt(match[2], 10)\n const b = Number.parseInt(match[3], 10)\n if (r > 255 || g > 255 || b > 255) return null\n return { r, g, b }\n}\n\nfunction parseHslString(input: string): HSL | null {\n const match = input.match(/^hsl\\(\\s*(\\d+)\\s*,\\s*(\\d+)%?\\s*,\\s*(\\d+)%?\\s*\\)$/i)\n if (!match) return null\n return {\n h: Number.parseInt(match[1], 10) % 360,\n s: Math.min(100, Number.parseInt(match[2], 10)),\n l: Math.min(100, Number.parseInt(match[3], 10)),\n }\n}\n\nconst NAMED_COLORS: Record<string, string> = {\n 'black': '#000000',\n 'white': '#FFFFFF',\n 'transparent': '#FFFFFF',\n 'aqua': '#00FFFF',\n 'magenta': '#FF00FF',\n 'fuchsia': '#FF00FF',\n 'silver': '#C0C0C0',\n 'maroon': '#800000',\n 'olive': '#808000',\n 'navy': '#000080',\n 'coral': '#FF7F50',\n 'crimson': '#DC143C',\n 'gold': '#FFD700',\n 'ivory': '#FFFFF0',\n 'khaki': '#F0E68C',\n 'lavender': '#E6E6FA',\n 'plum': '#DDA0DD',\n 'salmon': '#FA8072',\n 'sienna': '#A0522D',\n 'tan': '#D2B48C',\n 'tomato': '#FF6347',\n 'turquoise': '#40E0D0',\n 'violet': '#EE82EE',\n 'wheat': '#F5DEB3',\n 'red': '#F44336',\n 'red-lighten-5': '#FFEBEE',\n 'red-lighten-4': '#FFCDD2',\n 'red-lighten-3': '#EF9A9A',\n 'red-lighten-2': '#E57373',\n 'red-lighten-1': '#EF5350',\n 'red-darken-1': '#E53935',\n 'red-darken-2': '#D32F2F',\n 'red-darken-3': '#C62828',\n 'red-darken-4': '#B71C1C',\n 'red-accent-1': '#FF8A80',\n 'red-accent-2': '#FF5252',\n 'red-accent-3': '#FF1744',\n 'red-accent-4': '#D50000',\n 'pink': '#E91E63',\n 'pink-lighten-5': '#FCE4EC',\n 'pink-lighten-4': '#F8BBD0',\n 'pink-lighten-3': '#F48FB1',\n 'pink-lighten-2': '#F06292',\n 'pink-lighten-1': '#EC407A',\n 'pink-darken-1': '#D81B60',\n 'pink-darken-2': '#C2185B',\n 'pink-darken-3': '#AD1457',\n 'pink-darken-4': '#880E4F',\n 'pink-accent-1': '#FF80AB',\n 'pink-accent-2': '#FF4081',\n 'pink-accent-3': '#F50057',\n 'pink-accent-4': '#C51162',\n 'purple': '#9C27B0',\n 'purple-lighten-5': '#F3E5F5',\n 'purple-lighten-4': '#E1BEE7',\n 'purple-lighten-3': '#CE93D8',\n 'purple-lighten-2': '#BA68C8',\n 'purple-lighten-1': '#AB47BC',\n 'purple-darken-1': '#8E24AA',\n 'purple-darken-2': '#7B1FA2',\n 'purple-darken-3': '#6A1B9A',\n 'purple-darken-4': '#4A148C',\n 'purple-accent-1': '#EA80FC',\n 'purple-accent-2': '#E040FB',\n 'purple-accent-3': '#D500F9',\n 'purple-accent-4': '#AA00FF',\n 'deep-purple': '#673AB7',\n 'deep-purple-lighten-5': '#EDE7F6',\n 'deep-purple-lighten-4': '#D1C4E9',\n 'deep-purple-lighten-3': '#B39DDB',\n 'deep-purple-lighten-2': '#9575CD',\n 'deep-purple-lighten-1': '#7E57C2',\n 'deep-purple-darken-1': '#5E35B1',\n 'deep-purple-darken-2': '#512DA8',\n 'deep-purple-darken-3': '#4527A0',\n 'deep-purple-darken-4': '#311B92',\n 'deep-purple-accent-1': '#B388FF',\n 'deep-purple-accent-2': '#7C4DFF',\n 'deep-purple-accent-3': '#651FFF',\n 'deep-purple-accent-4': '#6200EA',\n 'indigo': '#3F51B5',\n 'indigo-lighten-5': '#E8EAF6',\n 'indigo-lighten-4': '#C5CAE9',\n 'indigo-lighten-3': '#9FA8DA',\n 'indigo-lighten-2': '#7986CB',\n 'indigo-lighten-1': '#5C6BC0',\n 'indigo-darken-1': '#3949AB',\n 'indigo-darken-2': '#303F9F',\n 'indigo-darken-3': '#283593',\n 'indigo-darken-4': '#1A237E',\n 'indigo-accent-1': '#8C9EFF',\n 'indigo-accent-2': '#536DFE',\n 'indigo-accent-3': '#3D5AFE',\n 'indigo-accent-4': '#304FFE',\n 'blue': '#2196F3',\n 'blue-lighten-5': '#E3F2FD',\n 'blue-lighten-4': '#BBDEFB',\n 'blue-lighten-3': '#90CAF9',\n 'blue-lighten-2': '#64B5F6',\n 'blue-lighten-1': '#42A5F5',\n 'blue-darken-1': '#1E88E5',\n 'blue-darken-2': '#1976D2',\n 'blue-darken-3': '#1565C0',\n 'blue-darken-4': '#0D47A1',\n 'blue-accent-1': '#82B1FF',\n 'blue-accent-2': '#448AFF',\n 'blue-accent-3': '#2979FF',\n 'blue-accent-4': '#2962FF',\n 'light-blue': '#03A9F4',\n 'light-blue-lighten-5': '#E1F5FE',\n 'light-blue-lighten-4': '#B3E5FC',\n 'light-blue-lighten-3': '#81D4FA',\n 'light-blue-lighten-2': '#4FC3F7',\n 'light-blue-lighten-1': '#29B6F6',\n 'light-blue-darken-1': '#039BE5',\n 'light-blue-darken-2': '#0288D1',\n 'light-blue-darken-3': '#0277BD',\n 'light-blue-darken-4': '#01579B',\n 'light-blue-accent-1': '#80D8FF',\n 'light-blue-accent-2': '#40C4FF',\n 'light-blue-accent-3': '#00B0FF',\n 'light-blue-accent-4': '#0091EA',\n 'cyan': '#00BCD4',\n 'cyan-lighten-5': '#E0F7FA',\n 'cyan-lighten-4': '#B2EBF2',\n 'cyan-lighten-3': '#80DEEA',\n 'cyan-lighten-2': '#4DD0E1',\n 'cyan-lighten-1': '#26C6DA',\n 'cyan-darken-1': '#00ACC1',\n 'cyan-darken-2': '#0097A7',\n 'cyan-darken-3': '#00838F',\n 'cyan-darken-4': '#006064',\n 'cyan-accent-1': '#84FFFF',\n 'cyan-accent-2': '#18FFFF',\n 'cyan-accent-3': '#00E5FF',\n 'cyan-accent-4': '#00B8D4',\n 'teal': '#009688',\n 'teal-lighten-5': '#E0F2F1',\n 'teal-lighten-4': '#B2DFDB',\n 'teal-lighten-3': '#80CBC4',\n 'teal-lighten-2': '#4DB6AC',\n 'teal-lighten-1': '#26A69A',\n 'teal-darken-1': '#00897B',\n 'teal-darken-2': '#00796B',\n 'teal-darken-3': '#00695C',\n 'teal-darken-4': '#004D40',\n 'teal-accent-1': '#A7FFEB',\n 'teal-accent-2': '#64FFDA',\n 'teal-accent-3': '#1DE9B6',\n 'teal-accent-4': '#00BFA5',\n 'green': '#4CAF50',\n 'green-lighten-5': '#E8F5E9',\n 'green-lighten-4': '#C8E6C9',\n 'green-lighten-3': '#A5D6A7',\n 'green-lighten-2': '#81C784',\n 'green-lighten-1': '#66BB6A',\n 'green-darken-1': '#43A047',\n 'green-darken-2': '#388E3C',\n 'green-darken-3': '#2E7D32',\n 'green-darken-4': '#1B5E20',\n 'green-accent-1': '#B9F6CA',\n 'green-accent-2': '#69F0AE',\n 'green-accent-3': '#00E676',\n 'green-accent-4': '#00C853',\n 'light-green': '#8BC34A',\n 'light-green-lighten-5': '#F1F8E9',\n 'light-green-lighten-4': '#DCEDC8',\n 'light-green-lighten-3': '#C5E1A5',\n 'light-green-lighten-2': '#AED581',\n 'light-green-lighten-1': '#9CCC65',\n 'light-green-darken-1': '#7CB342',\n 'light-green-darken-2': '#689F38',\n 'light-green-darken-3': '#558B2F',\n 'light-green-darken-4': '#33691E',\n 'light-green-accent-1': '#CCFF90',\n 'light-green-accent-2': '#B2FF59',\n 'light-green-accent-3': '#76FF03',\n 'light-green-accent-4': '#64DD17',\n 'lime': '#CDDC39',\n 'lime-lighten-5': '#F9FBE7',\n 'lime-lighten-4': '#F0F4C3',\n 'lime-lighten-3': '#E6EE9C',\n 'lime-lighten-2': '#DCE775',\n 'lime-lighten-1': '#D4E157',\n 'lime-darken-1': '#C0CA33',\n 'lime-darken-2': '#AFB42B',\n 'lime-darken-3': '#9E9D24',\n 'lime-darken-4': '#827717',\n 'lime-accent-1': '#F4FF81',\n 'lime-accent-2': '#EEFF41',\n 'lime-accent-3': '#C6FF00',\n 'lime-accent-4': '#AEEA00',\n 'yellow': '#FFEB3B',\n 'yellow-lighten-5': '#FFFDE7',\n 'yellow-lighten-4': '#FFF9C4',\n 'yellow-lighten-3': '#FFF59D',\n 'yellow-lighten-2': '#FFF176',\n 'yellow-lighten-1': '#FFEE58',\n 'yellow-darken-1': '#FDD835',\n 'yellow-darken-2': '#FBC02D',\n 'yellow-darken-3': '#F9A825',\n 'yellow-darken-4': '#F57F17',\n 'yellow-accent-1': '#FFFF8D',\n 'yellow-accent-2': '#FFFF00',\n 'yellow-accent-3': '#FFEA00',\n 'yellow-accent-4': '#FFD600',\n 'amber': '#FFC107',\n 'amber-lighten-5': '#FFF8E1',\n 'amber-lighten-4': '#FFECB3',\n 'amber-lighten-3': '#FFE082',\n 'amber-lighten-2': '#FFD54F',\n 'amber-lighten-1': '#FFCA28',\n 'amber-darken-1': '#FFB300',\n 'amber-darken-2': '#FFA000',\n 'amber-darken-3': '#FF8F00',\n 'amber-darken-4': '#FF6F00',\n 'amber-accent-1': '#FFE57F',\n 'amber-accent-2': '#FFD740',\n 'amber-accent-3': '#FFC400',\n 'amber-accent-4': '#FFAB00',\n 'orange': '#FF9800',\n 'orange-lighten-5': '#FFF3E0',\n 'orange-lighten-4': '#FFE0B2',\n 'orange-lighten-3': '#FFCC80',\n 'orange-lighten-2': '#FFB74D',\n 'orange-lighten-1': '#FFA726',\n 'orange-darken-1': '#FB8C00',\n 'orange-darken-2': '#F57C00',\n 'orange-darken-3': '#EF6C00',\n 'orange-darken-4': '#E65100',\n 'orange-accent-1': '#FFD180',\n 'orange-accent-2': '#FFAB40',\n 'orange-accent-3': '#FF9100',\n 'orange-accent-4': '#FF6D00',\n 'deep-orange': '#FF5722',\n 'deep-orange-lighten-5': '#FBE9E7',\n 'deep-orange-lighten-4': '#FFCCBC',\n 'deep-orange-lighten-3': '#FFAB91',\n 'deep-orange-lighten-2': '#FF8A65',\n 'deep-orange-lighten-1': '#FF7043',\n 'deep-orange-darken-1': '#F4511E',\n 'deep-orange-darken-2': '#E64A19',\n 'deep-orange-darken-3': '#D84315',\n 'deep-orange-darken-4': '#BF360C',\n 'deep-orange-accent-1': '#FF9E80',\n 'deep-orange-accent-2': '#FF6E40',\n 'deep-orange-accent-3': '#FF3D00',\n 'deep-orange-accent-4': '#DD2C00',\n 'brown': '#795548',\n 'brown-lighten-5': '#EFEBE9',\n 'brown-lighten-4': '#D7CCC8',\n 'brown-lighten-3': '#BCAAA4',\n 'brown-lighten-2': '#A1887F',\n 'brown-lighten-1': '#8D6E63',\n 'brown-darken-1': '#6D4C41',\n 'brown-darken-2': '#5D4037',\n 'brown-darken-3': '#4E342E',\n 'brown-darken-4': '#3E2723',\n 'blue-grey': '#607D8B',\n 'blue-grey-lighten-5': '#ECEFF1',\n 'blue-grey-lighten-4': '#CFD8DC',\n 'blue-grey-lighten-3': '#B0BEC5',\n 'blue-grey-lighten-2': '#90A4AE',\n 'blue-grey-lighten-1': '#78909C',\n 'blue-grey-darken-1': '#546E7A',\n 'blue-grey-darken-2': '#455A64',\n 'blue-grey-darken-3': '#37474F',\n 'blue-grey-darken-4': '#263238',\n 'grey': '#9E9E9E',\n 'gray': '#9E9E9E',\n 'grey-lighten-5': '#FAFAFA',\n 'grey-lighten-4': '#F5F5F5',\n 'grey-lighten-3': '#EEEEEE',\n 'grey-lighten-2': '#E0E0E0',\n 'grey-lighten-1': '#BDBDBD',\n 'grey-darken-1': '#757575',\n 'grey-darken-2': '#616161',\n 'grey-darken-3': '#424242',\n 'grey-darken-4': '#212121',\n}\n\nfunction parseColor(input: string): RGB | null {\n const trimmed = input.trim()\n const lower = trimmed.toLowerCase()\n\n if (NAMED_COLORS[lower]) {\n return hexToRgb(NAMED_COLORS[lower])\n }\n\n if (trimmed.startsWith('#')) return hexToRgb(trimmed)\n if (lower.startsWith('rgb(')) return parseRgbString(trimmed)\n if (lower.startsWith('hsl(')) {\n const hsl = parseHslString(trimmed)\n return hsl ? hslToRgb(hsl) : null\n }\n\n return hexToRgb(trimmed)\n}\n\nfunction rgbToHex(rgb: RGB): string {\n const toHex = (n: number) =>\n Math.round(Math.max(0, Math.min(255, n)))\n .toString(16)\n .padStart(2, '0')\n return `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`\n}\n\nfunction rgbToHsl(rgb: RGB): HSL {\n const r = rgb.r / 255\n const g = rgb.g / 255\n const b = rgb.b / 255\n\n const max = Math.max(r, g, b)\n const min = Math.min(r, g, b)\n const l = (max + min) / 2\n\n if (max === min) return { h: 0, s: 0, l: Math.round(l * 100) }\n\n const d = max - min\n const s = l > 0.5 ? d / (2 - max - min) : d / (max + min)\n\n let h = 0\n if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6\n else if (max === g) h = ((b - r) / d + 2) / 6\n else h = ((r - g) / d + 4) / 6\n\n return {\n h: Math.round(h * 360),\n s: Math.round(s * 100),\n l: Math.round(l * 100),\n }\n}\n\nfunction hslToRgb(hsl: HSL): RGB {\n const h = hsl.h / 360\n const s = hsl.s / 100\n const l = hsl.l / 100\n\n if (s === 0) {\n const v = Math.round(l * 255)\n return { r: v, g: v, b: v }\n }\n\n const hue2rgb = (p: number, q: number, t: number) => {\n if (t < 0) t += 1\n if (t > 1) t -= 1\n if (t < 1 / 6) return p + (q - p) * 6 * t\n if (t < 1 / 2) return q\n if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6\n return p\n }\n\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s\n const p = 2 * l - q\n\n return {\n r: Math.round(hue2rgb(p, q, h + 1 / 3) * 255),\n g: Math.round(hue2rgb(p, q, h) * 255),\n b: Math.round(hue2rgb(p, q, h - 1 / 3) * 255),\n }\n}\n\nfunction relativeLuminance(rgb: RGB): number {\n const srgb = [rgb.r, rgb.g, rgb.b].map((c) => {\n const s = c / 255\n return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4)\n })\n return 0.2126 * srgb[0] + 0.7152 * srgb[1] + 0.0722 * srgb[2]\n}\n\nfunction contrastRatio(c1: RGB, c2: RGB): number {\n const l1 = relativeLuminance(c1)\n const l2 = relativeLuminance(c2)\n const lighter = Math.max(l1, l2)\n const darker = Math.min(l1, l2)\n return (lighter + 0.05) / (darker + 0.05)\n}\n\nfunction rotateHue(hsl: HSL, degrees: number): HSL {\n return { h: (hsl.h + degrees + 360) % 360, s: hsl.s, l: hsl.l }\n}\n\nfunction formatColor(rgb: RGB): string {\n const hex = rgbToHex(rgb)\n const hsl = rgbToHsl(rgb)\n return `${hex} / rgb(${rgb.r}, ${rgb.g}, ${rgb.b}) / hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`\n}\n\n/**\n * Compute the WCAG 2.1 contrast ratio between two colours.\n *\n * @remarks\n * Accepts hex (`#rgb`, `#rrggbb`), `rgb()`, `hsl()`, or one of the CSS / Material Design named\n * colours. Reports the ratio and pass/fail against WCAG AA and AAA at both normal and large text\n * sizes. If the foreground/background combination fails AA Normal (4.5:1), the tool suggests\n * lightened or darkened variants that would pass.\n */\nexport const colorContrastTool = new Tool({\n name: 'color_contrast',\n description:\n 'Check the contrast ratio between two colors for WCAG accessibility compliance. Reports the contrast ratio and pass/fail for WCAG AA and AAA levels.',\n inputSchema: validator.object({\n foreground: validator\n .string()\n .required()\n .description('Foreground color (hex, rgb(), hsl(), or named color).'),\n background: validator\n .string()\n .required()\n .description('Background color (hex, rgb(), hsl(), or named color).'),\n }),\n handler: async (args) => {\n const { foreground, background } = args as { foreground: string; background: string }\n const fg = parseColor(foreground)\n const bg = parseColor(background)\n\n if (!fg) return `Error: could not parse foreground color \"${foreground}\".`\n if (!bg) return `Error: could not parse background color \"${background}\".`\n\n const ratio = contrastRatio(fg, bg)\n const rounded = Math.round(ratio * 100) / 100\n\n const aaLargeText = ratio >= 3\n const aaNormalText = ratio >= 4.5\n const aaaLargeText = ratio >= 4.5\n const aaaNormalText = ratio >= 7\n\n const lines = [\n `Foreground: ${formatColor(fg)}`,\n `Background: ${formatColor(bg)}`,\n `Contrast ratio: ${rounded}:1`,\n '',\n 'WCAG 2.1 compliance:',\n ` AA Normal text (4.5:1): ${aaNormalText ? 'PASS' : 'FAIL'}`,\n ` AA Large text (3.0:1): ${aaLargeText ? 'PASS' : 'FAIL'}`,\n ` AAA Normal text (7.0:1): ${aaaNormalText ? 'PASS' : 'FAIL'}`,\n ` AAA Large text (4.5:1): ${aaaLargeText ? 'PASS' : 'FAIL'}`,\n ]\n\n if (!aaNormalText) {\n const fgHsl = rgbToHsl(fg)\n const bgHsl = rgbToHsl(bg)\n const fgLighter = fgHsl.l > bgHsl.l\n\n const suggestions: string[] = []\n if (fgLighter) {\n const lighter = hslToRgb({ ...fgHsl, l: Math.min(100, fgHsl.l + 15) })\n const darkerBg = hslToRgb({ ...bgHsl, l: Math.max(0, bgHsl.l - 15) })\n if (contrastRatio(lighter, bg) >= 4.5) {\n suggestions.push(\n ` Lighten foreground to ${rgbToHex(lighter)} (ratio: ${Math.round(contrastRatio(lighter, bg) * 100) / 100}:1)`\n )\n }\n if (contrastRatio(fg, darkerBg) >= 4.5) {\n suggestions.push(\n ` Darken background to ${rgbToHex(darkerBg)} (ratio: ${Math.round(contrastRatio(fg, darkerBg) * 100) / 100}:1)`\n )\n }\n } else {\n const darker = hslToRgb({ ...fgHsl, l: Math.max(0, fgHsl.l - 15) })\n const lighterBg = hslToRgb({ ...bgHsl, l: Math.min(100, bgHsl.l + 15) })\n if (contrastRatio(darker, bg) >= 4.5) {\n suggestions.push(\n ` Darken foreground to ${rgbToHex(darker)} (ratio: ${Math.round(contrastRatio(darker, bg) * 100) / 100}:1)`\n )\n }\n if (contrastRatio(fg, lighterBg) >= 4.5) {\n suggestions.push(\n ` Lighten background to ${rgbToHex(lighterBg)} (ratio: ${Math.round(contrastRatio(fg, lighterBg) * 100) / 100}:1)`\n )\n }\n }\n\n if (suggestions.length > 0) {\n lines.push('', 'Suggestions to reach AA Normal (4.5:1):')\n lines.push(...suggestions)\n }\n }\n\n return lines.join('\\n')\n },\n})\n\n/**\n * Generate a colour palette from a base colour using a named harmony.\n *\n * @remarks\n * Supported schemes: `complementary`, `analogous`, `triadic`, `split-complementary`,\n * `monochromatic`. Each entry reports its hex, rgb, and hsl forms, plus the contrast ratio\n * relative to the base colour.\n */\nexport const colorSchemeTool = new Tool({\n name: 'color_scheme',\n description:\n 'Generate a color palette from a base color. Supports complementary, analogous, triadic, split-complementary, and monochromatic schemes.',\n inputSchema: validator.object({\n color: validator\n .string()\n .required()\n .description('Base color (hex, rgb(), hsl(), or named color).'),\n scheme: validator\n .string()\n .valid('complementary', 'analogous', 'triadic', 'split-complementary', 'monochromatic')\n .required()\n .description('Type of color scheme to generate.'),\n }),\n handler: async (args) => {\n const { color, scheme } = args as {\n color: string\n scheme: 'complementary' | 'analogous' | 'triadic' | 'split-complementary' | 'monochromatic'\n }\n const rgb = parseColor(color)\n if (!rgb) return `Error: could not parse color \"${color}\".`\n\n const hsl = rgbToHsl(rgb)\n const palette: { label: string; rgb: RGB }[] = [{ label: 'Base', rgb }]\n\n switch (scheme) {\n case 'complementary':\n palette.push({ label: 'Complement', rgb: hslToRgb(rotateHue(hsl, 180)) })\n break\n\n case 'analogous':\n palette.push({ label: 'Analogous -30', rgb: hslToRgb(rotateHue(hsl, -30)) })\n palette.push({ label: 'Analogous +30', rgb: hslToRgb(rotateHue(hsl, 30)) })\n break\n\n case 'triadic':\n palette.push({ label: 'Triadic +120', rgb: hslToRgb(rotateHue(hsl, 120)) })\n palette.push({ label: 'Triadic +240', rgb: hslToRgb(rotateHue(hsl, 240)) })\n break\n\n case 'split-complementary':\n palette.push({ label: 'Split +150', rgb: hslToRgb(rotateHue(hsl, 150)) })\n palette.push({ label: 'Split +210', rgb: hslToRgb(rotateHue(hsl, 210)) })\n break\n\n case 'monochromatic':\n palette.push({ label: 'Light', rgb: hslToRgb({ ...hsl, l: Math.min(100, hsl.l + 20) }) })\n palette.push({ label: 'Lighter', rgb: hslToRgb({ ...hsl, l: Math.min(100, hsl.l + 35) }) })\n palette.push({ label: 'Dark', rgb: hslToRgb({ ...hsl, l: Math.max(0, hsl.l - 20) }) })\n palette.push({ label: 'Darker', rgb: hslToRgb({ ...hsl, l: Math.max(0, hsl.l - 35) }) })\n break\n }\n\n const lines = [`Color scheme: ${scheme}`, '']\n for (const entry of palette) {\n lines.push(`${entry.label}: ${formatColor(entry.rgb)}`)\n }\n\n if (palette.length > 1) {\n lines.push('', 'Contrast ratios with base:')\n for (const entry of palette.slice(1)) {\n const ratio = Math.round(contrastRatio(rgb, entry.rgb) * 100) / 100\n lines.push(` ${entry.label}: ${ratio}:1`)\n }\n }\n\n return lines.join('\\n')\n },\n})\n\n/**\n * Lighten or darken a colour by a percentage of HSL lightness.\n *\n * @remarks\n * `amount` is clamped to `[1, 100]`; `steps` is clamped to `[1, 10]`. With `steps > 1` the tool\n * emits a ramp of progressively-adjusted colours, useful for generating tint/shade scales.\n */\nexport const colorAdjustTool = new Tool({\n name: 'color_adjust',\n description:\n 'Lighten or darken a color by a specified amount. Returns the adjusted color in hex, rgb, and hsl formats. Can generate multiple steps for a tint/shade scale.',\n inputSchema: validator.object({\n color: validator\n .string()\n .required()\n .description('Color to adjust (hex, rgb(), hsl(), or named color).'),\n action: validator\n .string()\n .valid('lighten', 'darken')\n .required()\n .description('Whether to lighten or darken the color.'),\n amount: validator\n .number()\n .default(15)\n .description('Amount to adjust per step (1-100, percentage of lightness). Default: 15.'),\n steps: validator\n .number()\n .default(1)\n .description('Generate multiple steps of adjustment (1-10). Default: 1.'),\n }),\n handler: async (args) => {\n const {\n color,\n action,\n amount: rawAmount,\n steps: rawSteps,\n } = args as {\n color: string\n action: 'lighten' | 'darken'\n amount: number\n steps: number\n }\n const rgb = parseColor(color)\n if (!rgb) return `Error: could not parse color \"${color}\".`\n\n const amount = Math.max(1, Math.min(100, rawAmount))\n const steps = Math.max(1, Math.min(10, rawSteps))\n const hsl = rgbToHsl(rgb)\n\n const lines = [`Original: ${formatColor(rgb)}`]\n\n for (let i = 1; i <= steps; i++) {\n const delta = amount * i\n const newL = action === 'lighten' ? Math.min(100, hsl.l + delta) : Math.max(0, hsl.l - delta)\n const adjusted = hslToRgb({ ...hsl, l: newL })\n const label =\n steps === 1\n ? `${action === 'lighten' ? 'Lightened' : 'Darkened'} (${delta}%)`\n : `Step ${i} (${action} ${delta}%)`\n lines.push(`${label}: ${formatColor(adjusted)}`)\n }\n\n return lines.join('\\n')\n },\n})\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { t as Tool } from "../../tool-CMhaDRNd.mjs";
2
- import "../../common-BT0nfCi9.mjs";
1
+ import { t as Tool } from "../../tool-wMYMVl60.mjs";
2
+ import "../../common-DYDUi99O.mjs";
3
3
  import { validator } from "@nhtio/validation";
4
4
  //#region src/batteries/tools/color/index.ts
5
5
  /**
@@ -13,6 +13,7 @@ import { validator } from "@nhtio/validation";
13
13
  */
14
14
  function hexToRgb(hex) {
15
15
  const cleaned = hex.replace(/^#/, "");
16
+ if (!/^[0-9a-fA-F]+$/.test(cleaned)) return null;
16
17
  let r;
17
18
  let g;
18
19
  let b;