@struktoai/mirage-browser 0.0.8-alpha.1 → 0.0.8

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 (289) hide show
  1. package/README.md +140 -46
  2. package/dist/core/opfs/append.d.ts +1 -2
  3. package/dist/core/opfs/append.d.ts.map +1 -1
  4. package/dist/core/opfs/append.js +2 -5
  5. package/dist/core/opfs/append.js.map +1 -1
  6. package/dist/core/opfs/capacity.d.ts +8 -0
  7. package/dist/core/opfs/capacity.d.ts.map +1 -0
  8. package/dist/core/opfs/capacity.js +42 -0
  9. package/dist/core/opfs/capacity.js.map +1 -0
  10. package/dist/core/opfs/stream.d.ts.map +1 -1
  11. package/dist/core/opfs/stream.js +2 -0
  12. package/dist/core/opfs/stream.js.map +1 -1
  13. package/dist/core/opfs/write.d.ts +1 -2
  14. package/dist/core/opfs/write.d.ts.map +1 -1
  15. package/dist/core/opfs/write.js +2 -5
  16. package/dist/core/opfs/write.js.map +1 -1
  17. package/dist/index.d.ts +79 -99
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +53 -91
  20. package/dist/index.js.map +1 -1
  21. package/dist/io/gateway.d.ts +8 -0
  22. package/dist/io/gateway.d.ts.map +1 -0
  23. package/dist/io/gateway.js +238 -0
  24. package/dist/io/gateway.js.map +1 -0
  25. package/dist/io/network.d.ts +21 -0
  26. package/dist/io/network.d.ts.map +1 -0
  27. package/dist/io/network.js +131 -0
  28. package/dist/io/network.js.map +1 -0
  29. package/dist/io/spool.d.ts +2 -0
  30. package/dist/io/spool.d.ts.map +1 -0
  31. package/dist/io/spool.js +68 -0
  32. package/dist/io/spool.js.map +1 -0
  33. package/dist/vfs/aliyun/aliyun.d.ts +4 -5
  34. package/dist/vfs/aliyun/aliyun.d.ts.map +1 -1
  35. package/dist/vfs/aliyun/aliyun.js +2 -4
  36. package/dist/vfs/aliyun/aliyun.js.map +1 -1
  37. package/dist/vfs/aliyun/config.d.ts +22 -11
  38. package/dist/vfs/aliyun/config.d.ts.map +1 -1
  39. package/dist/vfs/aliyun/config.js +2 -7
  40. package/dist/vfs/aliyun/config.js.map +1 -1
  41. package/dist/vfs/backblaze/backblaze.d.ts +4 -5
  42. package/dist/vfs/backblaze/backblaze.d.ts.map +1 -1
  43. package/dist/vfs/backblaze/backblaze.js +2 -4
  44. package/dist/vfs/backblaze/backblaze.js.map +1 -1
  45. package/dist/vfs/backblaze/config.d.ts +22 -11
  46. package/dist/vfs/backblaze/config.d.ts.map +1 -1
  47. package/dist/vfs/backblaze/config.js +2 -7
  48. package/dist/vfs/backblaze/config.js.map +1 -1
  49. package/dist/vfs/ceph/ceph.d.ts +4 -5
  50. package/dist/vfs/ceph/ceph.d.ts.map +1 -1
  51. package/dist/vfs/ceph/ceph.js +2 -4
  52. package/dist/vfs/ceph/ceph.js.map +1 -1
  53. package/dist/vfs/ceph/config.d.ts +22 -10
  54. package/dist/vfs/ceph/config.d.ts.map +1 -1
  55. package/dist/vfs/ceph/config.js +1 -7
  56. package/dist/vfs/ceph/config.js.map +1 -1
  57. package/dist/vfs/digitalocean/config.d.ts +22 -11
  58. package/dist/vfs/digitalocean/config.d.ts.map +1 -1
  59. package/dist/vfs/digitalocean/config.js +2 -7
  60. package/dist/vfs/digitalocean/config.js.map +1 -1
  61. package/dist/vfs/digitalocean/digitalocean.d.ts +4 -5
  62. package/dist/vfs/digitalocean/digitalocean.d.ts.map +1 -1
  63. package/dist/vfs/digitalocean/digitalocean.js +2 -4
  64. package/dist/vfs/digitalocean/digitalocean.js.map +1 -1
  65. package/dist/vfs/discord/config.d.ts +5 -14
  66. package/dist/vfs/discord/config.d.ts.map +1 -1
  67. package/dist/vfs/discord/config.js +11 -18
  68. package/dist/vfs/discord/config.js.map +1 -1
  69. package/dist/vfs/discord/discord.d.ts +7 -10
  70. package/dist/vfs/discord/discord.d.ts.map +1 -1
  71. package/dist/vfs/discord/discord.js +7 -11
  72. package/dist/vfs/discord/discord.js.map +1 -1
  73. package/dist/vfs/gcs/config.d.ts +34 -15
  74. package/dist/vfs/gcs/config.d.ts.map +1 -1
  75. package/dist/vfs/gcs/config.js +12 -6
  76. package/dist/vfs/gcs/config.js.map +1 -1
  77. package/dist/vfs/gcs/gcs.d.ts +4 -5
  78. package/dist/vfs/gcs/gcs.d.ts.map +1 -1
  79. package/dist/vfs/gcs/gcs.js +2 -4
  80. package/dist/vfs/gcs/gcs.js.map +1 -1
  81. package/dist/vfs/minio/config.d.ts +22 -10
  82. package/dist/vfs/minio/config.d.ts.map +1 -1
  83. package/dist/vfs/minio/config.js +1 -7
  84. package/dist/vfs/minio/config.js.map +1 -1
  85. package/dist/vfs/minio/minio.d.ts +4 -5
  86. package/dist/vfs/minio/minio.d.ts.map +1 -1
  87. package/dist/vfs/minio/minio.js +2 -4
  88. package/dist/vfs/minio/minio.js.map +1 -1
  89. package/dist/vfs/mongodb/http_driver.d.ts +2 -0
  90. package/dist/vfs/mongodb/http_driver.d.ts.map +1 -1
  91. package/dist/vfs/mongodb/http_driver.js +2 -1
  92. package/dist/vfs/mongodb/http_driver.js.map +1 -1
  93. package/dist/vfs/mongodb/mongodb.d.ts +10 -11
  94. package/dist/vfs/mongodb/mongodb.d.ts.map +1 -1
  95. package/dist/vfs/mongodb/mongodb.js +8 -7
  96. package/dist/vfs/mongodb/mongodb.js.map +1 -1
  97. package/dist/vfs/notion/config.d.ts +4 -15
  98. package/dist/vfs/notion/config.d.ts.map +1 -1
  99. package/dist/vfs/notion/config.js +7 -17
  100. package/dist/vfs/notion/config.js.map +1 -1
  101. package/dist/vfs/notion/notion.d.ts +7 -10
  102. package/dist/vfs/notion/notion.d.ts.map +1 -1
  103. package/dist/vfs/notion/notion.js +5 -10
  104. package/dist/vfs/notion/notion.js.map +1 -1
  105. package/dist/vfs/oci/config.d.ts +25 -11
  106. package/dist/vfs/oci/config.d.ts.map +1 -1
  107. package/dist/vfs/oci/config.js +7 -7
  108. package/dist/vfs/oci/config.js.map +1 -1
  109. package/dist/vfs/oci/oci.d.ts +4 -5
  110. package/dist/vfs/oci/oci.d.ts.map +1 -1
  111. package/dist/vfs/oci/oci.js +2 -4
  112. package/dist/vfs/oci/oci.js.map +1 -1
  113. package/dist/vfs/opfs/opfs.d.ts +18 -11
  114. package/dist/vfs/opfs/opfs.d.ts.map +1 -1
  115. package/dist/vfs/opfs/opfs.js +62 -38
  116. package/dist/vfs/opfs/opfs.js.map +1 -1
  117. package/dist/vfs/postgres/neon_driver.d.ts +3 -1
  118. package/dist/vfs/postgres/neon_driver.d.ts.map +1 -1
  119. package/dist/vfs/postgres/neon_driver.js +34 -3
  120. package/dist/vfs/postgres/neon_driver.js.map +1 -1
  121. package/dist/vfs/postgres/postgres.d.ts +10 -11
  122. package/dist/vfs/postgres/postgres.d.ts.map +1 -1
  123. package/dist/vfs/postgres/postgres.js +6 -7
  124. package/dist/vfs/postgres/postgres.js.map +1 -1
  125. package/dist/vfs/qingstor/config.d.ts +22 -11
  126. package/dist/vfs/qingstor/config.d.ts.map +1 -1
  127. package/dist/vfs/qingstor/config.js +2 -7
  128. package/dist/vfs/qingstor/config.js.map +1 -1
  129. package/dist/vfs/qingstor/qingstor.d.ts +4 -5
  130. package/dist/vfs/qingstor/qingstor.d.ts.map +1 -1
  131. package/dist/vfs/qingstor/qingstor.js +2 -4
  132. package/dist/vfs/qingstor/qingstor.js.map +1 -1
  133. package/dist/vfs/r2/config.d.ts +27 -11
  134. package/dist/vfs/r2/config.d.ts.map +1 -1
  135. package/dist/vfs/r2/config.js +11 -7
  136. package/dist/vfs/r2/config.js.map +1 -1
  137. package/dist/vfs/r2/r2.d.ts +4 -5
  138. package/dist/vfs/r2/r2.d.ts.map +1 -1
  139. package/dist/vfs/r2/r2.js +2 -4
  140. package/dist/vfs/r2/r2.js.map +1 -1
  141. package/dist/vfs/redis/redis.d.ts +5 -1
  142. package/dist/vfs/redis/redis.d.ts.map +1 -1
  143. package/dist/vfs/redis/redis.js +1 -1
  144. package/dist/vfs/redis/redis.js.map +1 -1
  145. package/dist/vfs/redis/store.d.ts +2 -0
  146. package/dist/vfs/redis/store.d.ts.map +1 -1
  147. package/dist/vfs/redis/store.js +24 -5
  148. package/dist/vfs/redis/store.js.map +1 -1
  149. package/dist/vfs/registry.d.ts.map +1 -1
  150. package/dist/vfs/registry.js +87 -85
  151. package/dist/vfs/registry.js.map +1 -1
  152. package/dist/vfs/s3/config.d.ts +17 -5
  153. package/dist/vfs/s3/config.d.ts.map +1 -1
  154. package/dist/vfs/s3/config.js +7 -7
  155. package/dist/vfs/s3/config.js.map +1 -1
  156. package/dist/vfs/s3/s3.d.ts +6 -9
  157. package/dist/vfs/s3/s3.d.ts.map +1 -1
  158. package/dist/vfs/s3/s3.js +5 -10
  159. package/dist/vfs/s3/s3.js.map +1 -1
  160. package/dist/vfs/s3_alias.d.ts +22 -32
  161. package/dist/vfs/s3_alias.d.ts.map +1 -1
  162. package/dist/vfs/s3_alias.js +35 -23
  163. package/dist/vfs/s3_alias.js.map +1 -1
  164. package/dist/vfs/scaleway/config.d.ts +22 -11
  165. package/dist/vfs/scaleway/config.d.ts.map +1 -1
  166. package/dist/vfs/scaleway/config.js +2 -7
  167. package/dist/vfs/scaleway/config.js.map +1 -1
  168. package/dist/vfs/scaleway/scaleway.d.ts +4 -5
  169. package/dist/vfs/scaleway/scaleway.d.ts.map +1 -1
  170. package/dist/vfs/scaleway/scaleway.js +2 -4
  171. package/dist/vfs/scaleway/scaleway.js.map +1 -1
  172. package/dist/vfs/seaweedfs/config.d.ts +22 -10
  173. package/dist/vfs/seaweedfs/config.d.ts.map +1 -1
  174. package/dist/vfs/seaweedfs/config.js +1 -7
  175. package/dist/vfs/seaweedfs/config.js.map +1 -1
  176. package/dist/vfs/seaweedfs/seaweedfs.d.ts +4 -5
  177. package/dist/vfs/seaweedfs/seaweedfs.d.ts.map +1 -1
  178. package/dist/vfs/seaweedfs/seaweedfs.js +2 -4
  179. package/dist/vfs/seaweedfs/seaweedfs.js.map +1 -1
  180. package/dist/vfs/slack/config.d.ts +5 -15
  181. package/dist/vfs/slack/config.d.ts.map +1 -1
  182. package/dist/vfs/slack/config.js +11 -21
  183. package/dist/vfs/slack/config.js.map +1 -1
  184. package/dist/vfs/slack/slack.d.ts +7 -10
  185. package/dist/vfs/slack/slack.d.ts.map +1 -1
  186. package/dist/vfs/slack/slack.js +7 -11
  187. package/dist/vfs/slack/slack.js.map +1 -1
  188. package/dist/vfs/supabase/config.d.ts +25 -11
  189. package/dist/vfs/supabase/config.d.ts.map +1 -1
  190. package/dist/vfs/supabase/config.js +7 -7
  191. package/dist/vfs/supabase/config.js.map +1 -1
  192. package/dist/vfs/supabase/supabase.d.ts +4 -5
  193. package/dist/vfs/supabase/supabase.d.ts.map +1 -1
  194. package/dist/vfs/supabase/supabase.js +2 -4
  195. package/dist/vfs/supabase/supabase.js.map +1 -1
  196. package/dist/vfs/tencent/config.d.ts +22 -11
  197. package/dist/vfs/tencent/config.d.ts.map +1 -1
  198. package/dist/vfs/tencent/config.js +2 -7
  199. package/dist/vfs/tencent/config.js.map +1 -1
  200. package/dist/vfs/tencent/tencent.d.ts +4 -5
  201. package/dist/vfs/tencent/tencent.d.ts.map +1 -1
  202. package/dist/vfs/tencent/tencent.js +2 -4
  203. package/dist/vfs/tencent/tencent.js.map +1 -1
  204. package/dist/vfs/wasabi/config.d.ts +32 -16
  205. package/dist/vfs/wasabi/config.d.ts.map +1 -1
  206. package/dist/vfs/wasabi/config.js +8 -7
  207. package/dist/vfs/wasabi/config.js.map +1 -1
  208. package/dist/vfs/wasabi/wasabi.d.ts +4 -5
  209. package/dist/vfs/wasabi/wasabi.d.ts.map +1 -1
  210. package/dist/vfs/wasabi/wasabi.js +2 -4
  211. package/dist/vfs/wasabi/wasabi.js.map +1 -1
  212. package/dist/workspace.d.ts +2 -3
  213. package/dist/workspace.d.ts.map +1 -1
  214. package/dist/workspace.js +10 -18
  215. package/dist/workspace.js.map +1 -1
  216. package/package.json +7 -10
  217. package/THIRD_PARTY_NOTICES +0 -66
  218. package/dist/core/opfs/constants.d.ts +0 -2
  219. package/dist/core/opfs/constants.d.ts.map +0 -1
  220. package/dist/core/opfs/constants.js +0 -15
  221. package/dist/core/opfs/constants.js.map +0 -1
  222. package/dist/generated/wasm.d.ts +0 -3
  223. package/dist/generated/wasm.d.ts.map +0 -1
  224. package/dist/generated/wasm.js +0 -7
  225. package/dist/generated/wasm.js.map +0 -1
  226. package/dist/vfs/aliyun/prompt.d.ts +0 -2
  227. package/dist/vfs/aliyun/prompt.d.ts.map +0 -1
  228. package/dist/vfs/aliyun/prompt.js +0 -19
  229. package/dist/vfs/aliyun/prompt.js.map +0 -1
  230. package/dist/vfs/backblaze/prompt.d.ts +0 -2
  231. package/dist/vfs/backblaze/prompt.d.ts.map +0 -1
  232. package/dist/vfs/backblaze/prompt.js +0 -19
  233. package/dist/vfs/backblaze/prompt.js.map +0 -1
  234. package/dist/vfs/ceph/prompt.d.ts +0 -2
  235. package/dist/vfs/ceph/prompt.d.ts.map +0 -1
  236. package/dist/vfs/ceph/prompt.js +0 -19
  237. package/dist/vfs/ceph/prompt.js.map +0 -1
  238. package/dist/vfs/digitalocean/prompt.d.ts +0 -2
  239. package/dist/vfs/digitalocean/prompt.d.ts.map +0 -1
  240. package/dist/vfs/digitalocean/prompt.js +0 -19
  241. package/dist/vfs/digitalocean/prompt.js.map +0 -1
  242. package/dist/vfs/gcs/prompt.d.ts +0 -2
  243. package/dist/vfs/gcs/prompt.d.ts.map +0 -1
  244. package/dist/vfs/gcs/prompt.js +0 -19
  245. package/dist/vfs/gcs/prompt.js.map +0 -1
  246. package/dist/vfs/minio/prompt.d.ts +0 -2
  247. package/dist/vfs/minio/prompt.d.ts.map +0 -1
  248. package/dist/vfs/minio/prompt.js +0 -19
  249. package/dist/vfs/minio/prompt.js.map +0 -1
  250. package/dist/vfs/oci/prompt.d.ts +0 -2
  251. package/dist/vfs/oci/prompt.d.ts.map +0 -1
  252. package/dist/vfs/oci/prompt.js +0 -19
  253. package/dist/vfs/oci/prompt.js.map +0 -1
  254. package/dist/vfs/opfs/prompt.d.ts +0 -2
  255. package/dist/vfs/opfs/prompt.d.ts.map +0 -1
  256. package/dist/vfs/opfs/prompt.js +0 -17
  257. package/dist/vfs/opfs/prompt.js.map +0 -1
  258. package/dist/vfs/qingstor/prompt.d.ts +0 -2
  259. package/dist/vfs/qingstor/prompt.d.ts.map +0 -1
  260. package/dist/vfs/qingstor/prompt.js +0 -19
  261. package/dist/vfs/qingstor/prompt.js.map +0 -1
  262. package/dist/vfs/r2/prompt.d.ts +0 -2
  263. package/dist/vfs/r2/prompt.d.ts.map +0 -1
  264. package/dist/vfs/r2/prompt.js +0 -19
  265. package/dist/vfs/r2/prompt.js.map +0 -1
  266. package/dist/vfs/s3/prompt.d.ts +0 -2
  267. package/dist/vfs/s3/prompt.d.ts.map +0 -1
  268. package/dist/vfs/s3/prompt.js +0 -19
  269. package/dist/vfs/s3/prompt.js.map +0 -1
  270. package/dist/vfs/scaleway/prompt.d.ts +0 -2
  271. package/dist/vfs/scaleway/prompt.d.ts.map +0 -1
  272. package/dist/vfs/scaleway/prompt.js +0 -19
  273. package/dist/vfs/scaleway/prompt.js.map +0 -1
  274. package/dist/vfs/seaweedfs/prompt.d.ts +0 -2
  275. package/dist/vfs/seaweedfs/prompt.d.ts.map +0 -1
  276. package/dist/vfs/seaweedfs/prompt.js +0 -19
  277. package/dist/vfs/seaweedfs/prompt.js.map +0 -1
  278. package/dist/vfs/supabase/prompt.d.ts +0 -2
  279. package/dist/vfs/supabase/prompt.d.ts.map +0 -1
  280. package/dist/vfs/supabase/prompt.js +0 -19
  281. package/dist/vfs/supabase/prompt.js.map +0 -1
  282. package/dist/vfs/tencent/prompt.d.ts +0 -2
  283. package/dist/vfs/tencent/prompt.d.ts.map +0 -1
  284. package/dist/vfs/tencent/prompt.js +0 -19
  285. package/dist/vfs/tencent/prompt.js.map +0 -1
  286. package/dist/vfs/wasabi/prompt.d.ts +0 -2
  287. package/dist/vfs/wasabi/prompt.d.ts.map +0 -1
  288. package/dist/vfs/wasabi/prompt.js +0 -19
  289. package/dist/vfs/wasabi/prompt.js.map +0 -1
package/README.md CHANGED
@@ -5,6 +5,14 @@
5
5
  <img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-header-light.svg" width="100%" alt="Mirage: A Virtual Terminal for AI Agents" />
6
6
  </picture>
7
7
  </a>
8
+ <a href="https://agentvfs.org">
9
+ <picture>
10
+ <source media="(max-width: 767px) and (prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/agentvfs-banner-narrow-dark.svg">
11
+ <source media="(max-width: 767px)" srcset="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/agentvfs-banner-narrow-light.svg">
12
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/agentvfs-banner-dark.svg">
13
+ <img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/agentvfs-banner-light.svg" width="100%" alt="AgentVFS: the open, vendor-neutral virtual filesystem interface for AI agents" />
14
+ </picture>
15
+ </a>
8
16
  </h1>
9
17
 
10
18
  <p align="center">
@@ -16,6 +24,8 @@
16
24
  <img src="https://img.shields.io/badge/made by-strukto.ai-0C0C0C?labelColor=F0ECE2" /></a>
17
25
  <a href="https://github.com/strukto-ai/mirage/blob/main/LICENSE" alt="License">
18
26
  <img src="https://img.shields.io/badge/license-Apache--2.0-0C0C0C?labelColor=F0ECE2" /></a>
27
+ <a href="https://doi.org/10.5281/zenodo.23504502" alt="DOI">
28
+ <img src="https://img.shields.io/badge/DOI-10.5281%2Fzenodo.23504502-0C0C0C?labelColor=F0ECE2" alt="DOI 10.5281/zenodo.23504502" /></a>
19
29
  <a href="https://discord.gg/u8BPQ65KsS" alt="Discord">
20
30
  <img src="https://img.shields.io/badge/discord-join-0C0C0C?labelColor=F0ECE2&logo=discord&logoColor=0C0C0C" /></a>
21
31
  <br/>
@@ -40,7 +50,7 @@
40
50
  <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.ko.md"><img alt="README 한국어" src="https://img.shields.io/badge/%ED%95%9C%EA%B5%AD%EC%96%B4-F0ECE2"></a>
41
51
  </p>
42
52
 
43
- Mirage is **a Virtual Terminal for AI Agents**. The virtual filesystem delivers broad data context, virtualized CLIs give an agent more flexibility on tool use, dynamic runtimes save underlying infrastructure cost and are more token efficient, and fine-grained control over an agent's actions and even over what it can see gives the best security. Together these parts form one virtualized terminal, giving the best agent performance, cost efficiency and security.
53
+ Mirage is **a Virtual Terminal for AI Agents**: one shell over data, CLIs and runtimes. Unix tools reach every service, and `grep` runs on each service's own search, such as Gmail's or Slack's. Mirage routes each command to the runtime that fits it, so most lines run in-process and only heavy work reaches a sandbox, which cuts infrastructure cost and tokens. The terminal itself is light: a workspace takes **about 100 KB** of memory and each new session **about 10 KB**, so one process serves many agents at once. Profiles decide what an agent can run and even what it can see, and scriptable policies refuse anything those rules cannot express.
44
54
 
45
55
  <p align="center">
46
56
  <picture>
@@ -54,24 +64,56 @@ Here is an example of launching Mirage inside an application:
54
64
  ```python
55
65
  ws = Workspace(
56
66
  {
57
- "/tmp": (RAMVFS(), MountMode.EXEC),
58
- "/redis": (RedisVFS(url=redis_url), MountMode.WRITE),
67
+ "/s3": (S3VFS(S3Config(bucket="my-bucket")), MountMode.WRITE),
59
68
  "/slack": (SlackVFS(SlackConfig(token=slack_bot_token)), MountMode.EXEC),
69
+ "/gmail": (GmailVFS(GmailConfig(**google_credentials)), MountMode.READ),
60
70
  },
61
- # monty captures python, so scripts run sandboxed inside the workspace
62
- runtimes=[MontyRuntime(captures=["python", "python3"]), "workspace"],
71
+ # Install the Slack CLI, run by name and listed by `man` and `which` like any program
72
+ clis={"slack": (SLACK, {"token": slack_bot_token})},
73
+ # the analyst profile hides /s3/secrets and denies posting to Slack and curl
74
+ profiles={
75
+ "analyst": {
76
+ "paths": {"hide": ["/s3/secrets"]},
77
+ "commands": {"deny": ["slack send-message", "curl"]},
78
+ },
79
+ },
80
+ runtimes=[
81
+ MontyRuntime(captures=["python", "python3"]),
82
+ E2BRuntime(
83
+ captures=["python", "python3"],
84
+ config={"sandbox_id": sandbox_id, "mount_type": "ssh"},
85
+ ),
86
+ ],
87
+ # route the underlying computation: numpy lines run in the e2b sandbox, the rest on monty
88
+ route_policy=lambda ctx: "e2b" if "numpy" in ctx.line else None,
63
89
  )
64
90
 
65
- # one grep sweeps every source
66
- await ws.shell("grep -rln session /redis /tmp")
91
+ # Add an agent using the analyst profile
92
+ alice = await ws.session("alice", profile="analyst")
93
+
94
+ # one grep sweeps S3, Slack and Gmail, on each service's own search where it has one
95
+ await alice.shell("grep -rlw invoice /s3 /slack /gmail")
67
96
 
68
- # run a script that lives in Slack, file the report into Redis
69
- await ws.shell("python3 /slack/channels/general_.../files/example__F....py > /redis/report.txt")
97
+ # run a script that lives in Slack on monty, file the report into S3
98
+ await alice.shell("python3 /slack/channels/general__C0123/2026-10-21/files/report__F0456.py > /s3/report.txt")
70
99
 
71
- # install a typed CLI under a head word: dispatched by name, not by path,
72
- # and discoverable through `man`, `type` and `which` like any other program
73
- ws.register_cli("slack", SLACK, {"token": slack_bot_token})
74
- await ws.shell('slack send-message --channel general --text "report is up"')
100
+ # numpy is not in monty, so the route policy sends this line to e2b
101
+ await alice.shell("python3 -c 'import numpy; print(numpy.arange(10).sum())'")
102
+ ```
103
+
104
+ And what `alice` sees in the shell:
105
+
106
+ ```console
107
+ $ grep -rlw invoice /s3 /slack /gmail
108
+ /s3/billing/2026-10.csv
109
+ /gmail/INBOX/2026-10-21/Invoice_1042__18f3a9c2b7d1e0f4.gmail.json
110
+ $ ls /s3
111
+ billing
112
+ report.txt
113
+ $ cat /s3/secrets/aws.txt
114
+ cat: /s3/secrets/aws.txt: No such file or directory
115
+ $ slack send-message --channel general --text "report is up"
116
+ slack: Permission denied
75
117
  ```
76
118
 
77
119
  ## About
@@ -81,6 +123,7 @@ await ws.shell('slack send-message --channel general --text "report is up"')
81
123
  - **Virtual command line tools (CLIs).** `git`, `slack` and `ntn` are answered by Mirage itself, so an agent drives the service with nothing installed, across different runtimes and machines, and one tool can be virtualized into two or more, each under its own name with its own credentials.
82
124
  - **Routed, dynamic runtimes.** Python, JavaScript and any other command can be sent to a configured runtime, in process, sandboxed or remote, which decouples computation from storage and lets either change without touching the other.
83
125
  - **The virtualized Mirage shell.** It binds the filesystem, the CLIs and the runtimes into one command line, so pipes, redirection, variables, jobs and history work across all three.
126
+ - **Lightweight by design.** A workspace, the virtual terminal itself, takes about 100 KB of memory and each new session about 10 KB, so one process serves many agents without a container or VM per agent.
84
127
  - **Profiles designed for agents.** `allow`, `ask` and `deny` govern commands and CLIs, while `hide` and `show` govern files and folders, so a hidden path is not merely unreadable but absent from the filesystem the agent sees.
85
128
  - **A scriptable policy engine.** A policy script can prohibit any dangerous action before it runs, and the same stack gates every VFS op and session write, so neither a file nor an environment variable leaks.
86
129
  - **Notifications wired into the VFS and agents.** External changes become an event stream on the mount, so a new Slack reply surfaces as a change to the chat file in the virtual filesystem, and the agent reacts to it instead of rescanning the tree.
@@ -158,8 +201,8 @@ in Mirage can resolve straight to a credential held in one of them.
158
201
 
159
202
  ## Installation
160
203
 
161
- - **Python** ≥ 3.11 for the `mirage-ai` package and the `mirage` CLI
162
- - **Node.js** ≥ 20 for the TypeScript SDK
204
+ - **Python** ≥ 3.12 for the `mirage-ai` package and the `mirage` CLI
205
+ - **Node.js** 22.20+ on Node 22, 24.12+ on Node 24, or 25+ for the TypeScript SDK
163
206
 
164
207
  ### Python
165
208
 
@@ -181,58 +224,109 @@ Both runtime packages pull in `@struktoai/mirage-core` automatically.
181
224
  ### CLI
182
225
 
183
226
  ```bash
184
- curl -fsSL https://strukto.ai/mirage/install.sh | sh
185
- # or
186
227
  npm install -g @struktoai/mirage-cli
187
228
  # or
188
- uvx mirage-ai
229
+ uvx --from mirage-ai mirage
189
230
  # or
190
231
  npx @struktoai/mirage-cli
191
232
  ```
192
233
 
193
- ## Quickstart
234
+ To get started, see the quickstarts for
235
+ [Python](https://docs.mirage.strukto.ai/python/quickstart),
236
+ [TypeScript](https://docs.mirage.strukto.ai/typescript/quickstart) and the
237
+ [CLI](https://docs.mirage.strukto.ai/home/access/cli).
194
238
 
195
- ### Python
239
+ ## Scriptable Policy
240
+
241
+ A profile can name policy scripts for what its rules cannot express. A script
242
+ reads the command as JSON, can open the files it names, and prints a deny, an
243
+ ask or nothing. This one disables `rm`, and a Python script whose code
244
+ deletes files:
196
245
 
197
246
  ```python
198
- from mirage import Workspace
199
- from mirage.vfs.ram import RAMVFS
200
- from mirage.vfs.s3 import S3Config, S3VFS
247
+ import json, os
201
248
 
202
- ws = Workspace({
203
- "/data": RAMVFS(),
204
- "/s3": S3VFS(S3Config(bucket="my-bucket")),
205
- })
249
+ ctx = json.loads(os.environ["MIRAGE_POLICY_CTX"])
206
250
 
207
- await ws.shell("cp /s3/report.csv /data/report.csv")
208
- await ws.shell("grep alert /s3/data/log.jsonl | wc -l")
209
251
 
210
- await ws.snapshot("demo.tar")
211
- ```
252
+ def deletes(path):
253
+ try:
254
+ code = open(path).read()
255
+ except OSError:
256
+ return False
257
+ return any(call in code for call in ("os.remove", "os.unlink", "shutil.rmtree"))
212
258
 
213
- ### TypeScript
214
259
 
215
- ```ts
216
- import { Workspace, RAMVFS, S3VFS } from '@struktoai/mirage-node'
260
+ if ctx["command"] == "rm" or (
261
+ ctx["command"].startswith("python") and any(deletes(p) for p in ctx["paths"])
262
+ ):
263
+ print(json.dumps({"kind": "deny", "reason": "deleting files is disabled"}))
264
+ ```
217
265
 
218
- const ws = new Workspace({
219
- '/data': new RAMVFS(),
220
- '/s3': new S3VFS({ bucket: 'my-bucket' }),
221
- })
266
+ Register it in a profile, here to run on Monty before every command:
222
267
 
223
- await ws.shell('cp /s3/report.csv /data/report.csv')
224
- await ws.shell('grep alert /s3/data/log.jsonl | wc -l')
268
+ ```python
269
+ ws = Workspace(
270
+ {"/s3": (S3VFS(S3Config(bucket="my-bucket")), MountMode.WRITE)},
271
+ profiles={
272
+ "analyst": {
273
+ "policy": {
274
+ "pre_command": [{"script": ScriptSource(Path("guard.py").read_text()), "runtime": "monty"}],
275
+ },
276
+ },
277
+ },
278
+ profile="analyst",
279
+ )
280
+ ```
225
281
 
226
- await ws.snapshot('demo.tar')
282
+ ```console
283
+ $ cat /s3/clean.py
284
+ import os
285
+ os.remove("/s3/report.txt")
286
+ $ rm /s3/report.txt
287
+ rm: Permission denied
288
+ $ python3 /s3/clean.py
289
+ python3: Permission denied
227
290
  ```
228
291
 
229
- ### CLI
292
+ See [policy scripts](https://docs.mirage.strukto.ai/home/policy/scripts) for
293
+ the other stages a script can answer at.
294
+
295
+ ## Embedded Terminal
296
+
297
+ Most of the time an agent does not need a sandbox, only a terminal-like
298
+ interface, and Mirage embeds one in an application server. Each terminal is a
299
+ Mirage session with its own working directory, environment and history, and Python
300
+ runs in-process on Monty, so a terminal starts with no container or VM. Here
301
+ it is in Express; the FastAPI version is in the
302
+ [docs](https://docs.mirage.strukto.ai/home/examples/embedded-terminal).
230
303
 
231
304
  ```bash
232
- mirage workspace create ws.yaml --id demo
233
- mirage shell --workspace_id demo --command "cp /s3/report.csv /data/report.csv"
234
- mirage workspace snapshot demo demo.tar
235
- mirage workspace load demo.tar --id demo-restored
305
+ npm install @struktoai/mirage-node @pydantic/monty express
306
+ ```
307
+
308
+ ```ts
309
+ import express from 'express'
310
+ import { MontyRuntime, MountMode, RAMVFS, Workspace } from '@struktoai/mirage-node'
311
+
312
+ const ws = new Workspace(
313
+ { '/work': new RAMVFS() },
314
+ { mode: MountMode.EXEC, runtimes: [new MontyRuntime({ captures: ['python', 'python3'] })] },
315
+ )
316
+ const app = express()
317
+ app.use(express.json())
318
+
319
+ app.post('/sessions/:id', (req, res) => {
320
+ ws.createSession(req.params.id)
321
+ res.sendStatus(201)
322
+ })
323
+
324
+ app.post('/sessions/:id/run', async (req, res) => {
325
+ const r = await ws.shell(req.body.command, { sessionId: req.params.id })
326
+ res.json({ stdout: r.stdoutText, stderr: r.stderrText, exitCode: r.exitCode })
327
+ })
328
+
329
+ app.listen(3000, '127.0.0.1')
236
330
  ```
237
331
 
238
332
  ## Contributors
@@ -1,6 +1,5 @@
1
1
  import type { ByteSource } from '@struktoai/mirage-core/io/types';
2
2
  import type { PathSpec } from '@struktoai/mirage-core/types';
3
3
  import type { OPFSAccessor } from '../../accessor/opfs.ts';
4
- export declare function appendBytes(accessor: OPFSAccessor, p: PathSpec, data: Uint8Array): Promise<void>;
5
- export declare function appendStream(accessor: OPFSAccessor, p: PathSpec, data: ByteSource): Promise<void>;
4
+ export declare function append(accessor: OPFSAccessor, p: PathSpec, data: ByteSource, signal?: AbortSignal): Promise<void>;
6
5
  //# sourceMappingURL=append.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../../../src/core/opfs/append.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAGjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAG1D,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,YAAY,EACtB,CAAC,EAAE,QAAQ,EACX,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,YAAY,CAChC,QAAQ,EAAE,YAAY,EACtB,CAAC,EAAE,QAAQ,EACX,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC,CAqCf"}
1
+ {"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../../../src/core/opfs/append.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAGjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAG1D,wBAAsB,MAAM,CAC1B,QAAQ,EAAE,YAAY,EACtB,CAAC,EAAE,QAAQ,EACX,IAAI,EAAE,UAAU,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAqCf"}
@@ -15,10 +15,7 @@ import { chunks } from '@struktoai/mirage-core/io/cooperative';
15
15
  import { record, startOp } from '@struktoai/mirage-core/observe/context';
16
16
  import { VFSName } from '@struktoai/mirage-core/types';
17
17
  import { openError, resolveFileHandle, toWritableChunk } from "./utils.js";
18
- export async function appendBytes(accessor, p, data) {
19
- await appendStream(accessor, p, data);
20
- }
21
- export async function appendStream(accessor, p, data) {
18
+ export async function append(accessor, p, data, signal) {
22
19
  const root = await accessor.root();
23
20
  const timer = startOp();
24
21
  const key = p.mountPath;
@@ -29,7 +26,7 @@ export async function appendStream(accessor, p, data) {
29
26
  catch (err) {
30
27
  throw await openError(root, key, err, p);
31
28
  }
32
- const source = chunks(data)[Symbol.asyncIterator]();
29
+ const source = chunks(data, signal)[Symbol.asyncIterator]();
33
30
  let writable = null;
34
31
  let size = 0;
35
32
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"append.js","sourceRoot":"","sources":["../../../src/core/opfs/append.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"append.js","sourceRoot":"","sources":["../../../src/core/opfs/append.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AACjC,uEAAuE;AAEvE,OAAO,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAE9D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AAGtD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE1E,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,QAAsB,EACtB,CAAW,EACX,IAAgB,EAChB,MAAoB;IAEpB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAClC,MAAM,KAAK,GAAG,OAAO,EAAE,CAAA;IACvB,MAAM,GAAG,GAAG,CAAC,CAAC,SAAS,CAAA;IACvB,IAAI,MAA4B,CAAA;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;IAC1C,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAA;IAC3D,IAAI,QAAQ,GAAwC,IAAI,CAAA;IACxD,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;QACjC,IAAI,KAAK,CAAC,IAAI;YAAE,OAAM;QACtB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAA;QACvC,QAAQ,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAA;QAClE,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAClC,MAAM,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;QAClD,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAA;QAC1B,SAAS,CAAC;YACR,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;YAChC,IAAI,IAAI,CAAC,IAAI;gBAAE,MAAK;YACpB,MAAM,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;YACjD,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;QAC3B,CAAC;QACD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAA;QACtB,QAAQ,GAAG,IAAI,CAAA;IACjB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,MAAM,EAAE,EAAE,CAAA;QACvB,IAAI,QAAQ,KAAK,IAAI;YACnB,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,OAAgB,EAAE,EAAE;gBAChD,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,OAAO,CAAC,CAAA;YACvD,CAAC,CAAC,CAAA;IACN,CAAC;IACD,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;AACxD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { PathSpec } from '@struktoai/mirage-core/types';
2
+ import type { OPFSAccessor } from '../../accessor/opfs.ts';
3
+ /** The bytes at `path`, a directory's whole subtree included; 0 for none.
4
+ * Mirrors the disk backend's `sizeOf`. */
5
+ export declare function sizeOf(accessor: OPFSAccessor, path: PathSpec): Promise<number>;
6
+ /** The bytes the whole mount root holds. */
7
+ export declare function count(accessor: OPFSAccessor): Promise<number>;
8
+ //# sourceMappingURL=capacity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capacity.d.ts","sourceRoot":"","sources":["../../../src/core/opfs/capacity.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAe1D;0CAC0C;AAC1C,wBAAsB,MAAM,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAOpF;AAED,4CAA4C;AAC5C,wBAAsB,KAAK,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAEnE"}
@@ -0,0 +1,42 @@
1
+ // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
14
+ import { iterEntries, kindAt, resolveDirHandle, resolveFileHandle } from "./utils.js";
15
+ /** The bytes of every file under `dir`. */
16
+ async function bytesUnder(dir) {
17
+ let total = 0;
18
+ for await (const [name, handle] of iterEntries(dir)) {
19
+ total +=
20
+ handle.kind === 'file'
21
+ ? (await (await dir.getFileHandle(name)).getFile()).size
22
+ : await bytesUnder(await dir.getDirectoryHandle(name));
23
+ }
24
+ return total;
25
+ }
26
+ /** The bytes at `path`, a directory's whole subtree included; 0 for none.
27
+ * Mirrors the disk backend's `sizeOf`. */
28
+ export async function sizeOf(accessor, path) {
29
+ const root = await accessor.root();
30
+ const key = path.mountPath;
31
+ const kind = key === '/' || key === '' ? 'dir' : await kindAt(root, key);
32
+ if (kind === 'file')
33
+ return (await (await resolveFileHandle(root, key)).getFile()).size;
34
+ if (kind === 'dir')
35
+ return bytesUnder(await resolveDirHandle(root, key));
36
+ return 0;
37
+ }
38
+ /** The bytes the whole mount root holds. */
39
+ export async function count(accessor) {
40
+ return bytesUnder(await accessor.root());
41
+ }
42
+ //# sourceMappingURL=capacity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capacity.js","sourceRoot":"","sources":["../../../src/core/opfs/capacity.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AACjC,uEAAuE;AAIvE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAErF,2CAA2C;AAC3C,KAAK,UAAU,UAAU,CAAC,GAA8B;IACtD,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACpD,KAAK;YACH,MAAM,CAAC,IAAI,KAAK,MAAM;gBACpB,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI;gBACxD,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAA;IAC5D,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;0CAC0C;AAC1C,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,QAAsB,EAAE,IAAc;IACjE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAA;IAC1B,MAAM,IAAI,GAAG,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IACxE,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,CAAC,MAAM,CAAC,MAAM,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAA;IACvF,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,UAAU,CAAC,MAAM,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAA;IACxE,OAAO,CAAC,CAAA;AACV,CAAC;AAED,4CAA4C;AAC5C,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,QAAsB;IAChD,OAAO,UAAU,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AAC1C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/core/opfs/stream.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAG1D,wBAAuB,UAAU,CAC/B,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,QAAQ,GACb,aAAa,CAAC,UAAU,CAAC,CAoB3B"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../../src/core/opfs/stream.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAG1D,wBAAuB,UAAU,CAC/B,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,QAAQ,GACb,aAAa,CAAC,UAAU,CAAC,CAsB3B"}
@@ -37,5 +37,7 @@ export async function* readStream(accessor, path) {
37
37
  rec.bytes += value.byteLength;
38
38
  yield value;
39
39
  }
40
+ if (rec !== null)
41
+ rec.complete = true;
40
42
  }
41
43
  //# sourceMappingURL=stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../../src/core/opfs/stream.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AACjC,uEAAuE;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AAGtD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEzD,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,UAAU,CAC/B,QAAsB,EACtB,IAAc;IAEd,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAA;IAC1B,IAAI,MAA4B,CAAA;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;IAChE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,uEAAuE;QACvE,iEAAiE;QACjE,MAAM,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAC7C,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAA;IACnC,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,CAAA;IACxC,SAAS,CAAC;QACR,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;QAC3C,IAAI,IAAI;YAAE,MAAK;QACf,IAAI,GAAG,KAAK,IAAI;YAAE,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAA;QAC/C,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../../src/core/opfs/stream.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AACjC,uEAAuE;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,wCAAwC,CAAA;AACrE,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AAGtD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEzD,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,UAAU,CAC/B,QAAsB,EACtB,IAAc;IAEd,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAClC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAA;IAC1B,IAAI,MAA4B,CAAA;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;IAChE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,uEAAuE;QACvE,iEAAiE;QACjE,MAAM,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;IAC7C,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAA;IACnC,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,CAAA;IACxC,SAAS,CAAC;QACR,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;QAC3C,IAAI,IAAI;YAAE,MAAK;QACf,IAAI,GAAG,KAAK,IAAI;YAAE,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,UAAU,CAAA;QAC/C,MAAM,KAAK,CAAA;IACb,CAAC;IAED,IAAI,GAAG,KAAK,IAAI;QAAE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAA;AACvC,CAAC"}
@@ -1,6 +1,5 @@
1
1
  import type { ByteSource } from '@struktoai/mirage-core/io/types';
2
2
  import type { PathSpec } from '@struktoai/mirage-core/types';
3
3
  import type { OPFSAccessor } from '../../accessor/opfs.ts';
4
- export declare function write(accessor: OPFSAccessor, p: PathSpec, data: Uint8Array): Promise<void>;
5
- export declare function writeStream(accessor: OPFSAccessor, p: PathSpec, data: ByteSource): Promise<void>;
4
+ export declare function write(accessor: OPFSAccessor, p: PathSpec, data: ByteSource, signal?: AbortSignal): Promise<void>;
6
5
  //# sourceMappingURL=write.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/opfs/write.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAGjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAG1D,wBAAsB,KAAK,CAAC,QAAQ,EAAE,YAAY,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhG;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,YAAY,EACtB,CAAC,EAAE,QAAQ,EACX,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,IAAI,CAAC,CAyBf"}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/core/opfs/write.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAA;AAGjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAG1D,wBAAsB,KAAK,CACzB,QAAQ,EAAE,YAAY,EACtB,CAAC,EAAE,QAAQ,EACX,IAAI,EAAE,UAAU,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAyBf"}
@@ -15,10 +15,7 @@ import { chunks } from '@struktoai/mirage-core/io/cooperative';
15
15
  import { record, startOp } from '@struktoai/mirage-core/observe/context';
16
16
  import { VFSName } from '@struktoai/mirage-core/types';
17
17
  import { openError, resolveFileHandle, toWritableChunk } from "./utils.js";
18
- export async function write(accessor, p, data) {
19
- await writeStream(accessor, p, data);
20
- }
21
- export async function writeStream(accessor, p, data) {
18
+ export async function write(accessor, p, data, signal) {
22
19
  const root = await accessor.root();
23
20
  const timer = startOp();
24
21
  const key = p.mountPath;
@@ -32,7 +29,7 @@ export async function writeStream(accessor, p, data) {
32
29
  const writable = await handle.createWritable();
33
30
  let size = 0;
34
31
  try {
35
- for await (const part of chunks(data)) {
32
+ for await (const part of chunks(data, signal)) {
36
33
  await writable.write(toWritableChunk(part));
37
34
  size += part.length;
38
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/core/opfs/write.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AACjC,uEAAuE;AAEvE,OAAO,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAE9D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AAGtD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE1E,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,QAAsB,EAAE,CAAW,EAAE,IAAgB;IAC/E,MAAM,WAAW,CAAC,QAAQ,EAAE,CAAC,EAAE,IAAI,CAAC,CAAA;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAsB,EACtB,CAAW,EACX,IAAgB;IAEhB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAClC,MAAM,KAAK,GAAG,OAAO,EAAE,CAAA;IACvB,MAAM,GAAG,GAAG,CAAC,CAAC,SAAS,CAAA;IACvB,IAAI,MAA4B,CAAA;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;IAC1C,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAA;IAC9C,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAA;YAC3C,IAAI,IAAI,IAAI,CAAC,MAAM,CAAA;QACrB,CAAC;QACD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,OAAgB,EAAE,EAAE;YAChD,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,OAAO,CAAC,CAAA;QACtD,CAAC,CAAC,CAAA;QACF,MAAM,KAAK,CAAA;IACb,CAAC;IACD,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;AACvD,CAAC"}
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/core/opfs/write.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AACjC,uEAAuE;AAEvE,OAAO,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAE9D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,wCAAwC,CAAA;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAA;AAGtD,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE1E,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,QAAsB,EACtB,CAAW,EACX,IAAgB,EAChB,MAAoB;IAEpB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAClC,MAAM,KAAK,GAAG,OAAO,EAAE,CAAA;IACvB,MAAM,GAAG,GAAG,CAAC,CAAC,SAAS,CAAA;IACvB,IAAI,MAA4B,CAAA;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;IAC1C,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAA;IAC9C,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,CAAC;QACH,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;YAC9C,MAAM,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAA;YAC3C,IAAI,IAAI,IAAI,CAAC,MAAM,CAAA;QACrB,CAAC;QACD,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,OAAgB,EAAE,EAAE;YAChD,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,OAAO,CAAC,CAAA;QACtD,CAAC,CAAC,CAAA;QACF,MAAM,KAAK,CAAA;IACb,CAAC;IACD,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;AACvD,CAAC"}