@struktoai/mirage-agents 0.0.5 → 0.0.7-alpha.1

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 (43) hide show
  1. package/README.md +138 -80
  2. package/dist/chunk-3N5GLSL7.js +33 -0
  3. package/dist/chunk-3N5GLSL7.js.map +1 -0
  4. package/dist/{chunk-IMI7BLEG.js → chunk-DIUKTEAK.js} +12 -11
  5. package/dist/chunk-DIUKTEAK.js.map +1 -0
  6. package/dist/{chunk-Y4G25V5V.js → chunk-GEO2G6YZ.js} +10 -19
  7. package/dist/chunk-GEO2G6YZ.js.map +1 -0
  8. package/dist/{chunk-ZPXFVDYT.js → chunk-S6DWWJVF.js} +1 -1
  9. package/dist/chunk-S6DWWJVF.js.map +1 -0
  10. package/dist/{chunk-XEQB7N3F.js → chunk-YJS2FVEB.js} +29 -11
  11. package/dist/chunk-YJS2FVEB.js.map +1 -0
  12. package/dist/claude-agent-sdk/index.d.ts +4 -4
  13. package/dist/claude-agent-sdk/index.js +5 -4
  14. package/dist/claude-agent-sdk/index.js.map +1 -1
  15. package/dist/{file-version-Clij-pms.d.ts → file-version-CE2J_nkn.d.ts} +2 -1
  16. package/dist/langchain/index.d.ts +3 -3
  17. package/dist/langchain/index.js +21 -5
  18. package/dist/langchain/index.js.map +1 -1
  19. package/dist/mastra/index.d.ts +8 -1
  20. package/dist/mastra/index.js +13 -3
  21. package/dist/mastra/index.js.map +1 -1
  22. package/dist/mcp/index.d.ts +4 -4
  23. package/dist/mcp/index.js +4 -3
  24. package/dist/mcp/index.js.map +1 -1
  25. package/dist/openai/index.d.ts +2 -2
  26. package/dist/openai/index.js +17 -8
  27. package/dist/openai/index.js.map +1 -1
  28. package/dist/opencode/index.d.ts +2 -2
  29. package/dist/opencode/index.js +8 -4
  30. package/dist/opencode/index.js.map +1 -1
  31. package/dist/pi/index.d.ts +3 -3
  32. package/dist/pi/index.js +11 -5
  33. package/dist/pi/index.js.map +1 -1
  34. package/dist/{prompt-B_6pxgjj.d.ts → prompt-CgKmMkVe.d.ts} +1 -1
  35. package/dist/{tool-descriptions-7CgIovZc.d.ts → tool-descriptions-C6xBOUjO.d.ts} +1 -1
  36. package/dist/vercel/index.d.ts +1 -1
  37. package/dist/vercel/index.js +5 -3
  38. package/dist/vercel/index.js.map +1 -1
  39. package/package.json +26 -23
  40. package/dist/chunk-IMI7BLEG.js.map +0 -1
  41. package/dist/chunk-XEQB7N3F.js.map +0 -1
  42. package/dist/chunk-Y4G25V5V.js.map +0 -1
  43. package/dist/chunk-ZPXFVDYT.js.map +0 -1
package/README.md CHANGED
@@ -1,82 +1,165 @@
1
- <p align="center">
2
- <img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-og-light@2x.png" alt="Mirage: A Unified Virtual File System for AI Agents" width="900">
3
- </p>
1
+ <h1 align="center">
2
+ <a href="https://www.strukto.ai/mirage">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-header-dark.svg">
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
+ </picture>
7
+ </a>
8
+ </h1>
4
9
 
5
10
  <p align="center">
6
11
  <a href="https://docs.mirage.strukto.ai" alt="Documentation">
7
- <img src="https://img.shields.io/badge/mirage-docs-0C0C0C?labelColor=FAFAFA" /></a>
12
+ <img src="https://img.shields.io/badge/mirage-docs-0C0C0C?labelColor=F0ECE2" /></a>
13
+ <a href="https://github.com/strukto-ai/mirage/releases" alt="Status">
14
+ <img src="https://img.shields.io/badge/status-preview-0C0C0C?labelColor=F0ECE2" alt="Status: preview" /></a>
8
15
  <a href="https://www.strukto.ai" alt="Website">
9
- <img src="https://img.shields.io/badge/made by-strukto.ai-0C0C0C?labelColor=FAFAFA" /></a>
16
+ <img src="https://img.shields.io/badge/made by-strukto.ai-0C0C0C?labelColor=F0ECE2" /></a>
10
17
  <a href="https://github.com/strukto-ai/mirage/blob/main/LICENSE" alt="License">
11
- <img src="https://img.shields.io/github/license/strukto-ai/mirage?color=0C0C0C&labelColor=FAFAFA" /></a>
18
+ <img src="https://img.shields.io/badge/license-Apache--2.0-0C0C0C?labelColor=F0ECE2" /></a>
12
19
  <a href="https://discord.gg/u8BPQ65KsS" alt="Discord">
13
- <img src="https://img.shields.io/badge/discord-join-0C0C0C?labelColor=FAFAFA&logo=discord&logoColor=0C0C0C" /></a>
20
+ <img src="https://img.shields.io/badge/discord-join-0C0C0C?labelColor=F0ECE2&logo=discord&logoColor=0C0C0C" /></a>
14
21
  <br/>
15
22
  <a href="https://docs.mirage.strukto.ai/python/quickstart" alt="Python docs">
16
- <img src="https://img.shields.io/badge/python-docs-0C0C0C?labelColor=FAFAFA&logo=python&logoColor=0C0C0C" alt="Python docs"></a>
23
+ <img src="https://img.shields.io/badge/python-docs-0C0C0C?labelColor=F0ECE2&logo=python&logoColor=0C0C0C" alt="Python docs"></a>
17
24
  <a href="https://pypi.org/project/mirage-ai/" alt="PyPI Version">
18
- <img src="https://img.shields.io/pypi/v/mirage-ai.svg?color=0C0C0C&labelColor=FAFAFA"/></a>
25
+ <img src="https://img.shields.io/pypi/v/mirage-ai.svg?color=0C0C0C&labelColor=F0ECE2"/></a>
19
26
  <br/>
20
27
  <a href="https://docs.mirage.strukto.ai/typescript/quickstart" alt="TypeScript docs">
21
- <img src="https://img.shields.io/badge/typescript-docs-0C0C0C?labelColor=FAFAFA&logo=typescript&logoColor=0C0C0C" alt="TypeScript docs"></a>
22
- <a href="https://www.npmjs.com/package/@struktoai/mirage-agents" alt="NPM Version">
23
- <img src="https://img.shields.io/npm/v/%40struktoai%2Fmirage-agents.svg?color=0C0C0C&labelColor=FAFAFA"/></a>
28
+ <img src="https://img.shields.io/badge/typescript-docs-0C0C0C?labelColor=F0ECE2&logo=typescript&logoColor=0C0C0C" alt="TypeScript docs"></a>
29
+ <a href="https://www.npmjs.com/package/@struktoai/mirage-node" alt="NPM Version">
30
+ <img src="https://img.shields.io/npm/v/@struktoai/mirage-node.svg?color=0C0C0C&labelColor=F0ECE2"/></a>
24
31
  </p>
25
32
 
26
33
  <p align="center">
27
- <a href="https://github.com/strukto-ai/mirage#readme"><img alt="README in English" src="https://img.shields.io/badge/English-d9d9d9"></a>
28
- <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.zh-CN.md"><img alt="简体中文 README" src="https://img.shields.io/badge/简体中文-d9d9d9"></a>
29
- <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.zh-TW.md"><img alt="繁體中文 README" src="https://img.shields.io/badge/繁體中文-d9d9d9"></a>
30
- <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.fr.md"><img alt="README en Français" src="https://img.shields.io/badge/Français-d9d9d9"></a>
31
- <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.vi.md"><img alt="README Tiếng Việt" src="https://img.shields.io/badge/Ti%E1%BA%BFng%20Vi%E1%BB%87t-d9d9d9"></a>
32
- <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-d9d9d9"></a>
34
+ <a href="https://github.com/strukto-ai/mirage/blob/main/README.md"><img alt="README in English" src="https://img.shields.io/badge/English-F0ECE2"></a>
35
+ <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.zh-CN.md"><img alt="简体中文 README" src="https://img.shields.io/badge/简体中文-F0ECE2"></a>
36
+ <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.zh-TW.md"><img alt="繁體中文 README" src="https://img.shields.io/badge/繁體中文-F0ECE2"></a>
37
+ <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.fr.md"><img alt="README en Français" src="https://img.shields.io/badge/Français-F0ECE2"></a>
38
+ <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.de.md"><img alt="README auf Deutsch" src="https://img.shields.io/badge/Deutsch-F0ECE2"></a>
39
+ <a href="https://github.com/strukto-ai/mirage/blob/main/readme/README.vi.md"><img alt="README Tiếng Việt" src="https://img.shields.io/badge/Ti%E1%BA%BFng%20Vi%E1%BB%87t-F0ECE2"></a>
40
+ <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>
33
41
  </p>
34
42
 
35
- Mirage is **a Unified Virtual File System for AI Agents**: it mounts services and data sources like S3, Google Drive, Slack, Gmail, and Redis side-by-side as one filesystem. Any LLM that already knows bash can read, grep, and pipe across every backend out of the box, with zero new vocabulary.
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.
36
44
 
37
- ```ts
38
- const ws = new Workspace({
39
- '/data': new RAMResource(),
40
- '/s3': new S3Resource({ bucket: 'logs' }),
41
- '/slack': new SlackResource({ token: process.env.SLACK_BOT_TOKEN! }),
42
- })
45
+ <p align="center">
46
+ <picture>
47
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-arch-dark.svg">
48
+ <img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-arch-light.svg" alt="Mirage architecture: agents and harness reach profiles and the Mirage shell, which resolve Unix-like commands, virtual CLIs and programming languages onto runtimes and the virtual filesystem, with authentication, the policy engine and notifications alongside" width="100%">
49
+ </picture>
50
+ </p>
43
51
 
44
- await ws.execute('grep -r alert /slack/channels/general__C04QX/ | wc -l')
45
- await ws.execute('cp /s3/report.csv /data/local.csv')
46
- await ws.execute('wc -l $(find /s3/data -name "*.jsonl")')
52
+ Here is an example of launching Mirage inside an application:
47
53
 
48
- // Commands are extensible: register new commands, or override one per
49
- // resource + filetype. Mirage ships no filetype renderers, so a format
50
- // like Parquet renders however you register it.
51
- ws.command('summarize', ...)
52
- ws.command('cat', { resource: 's3', filetype: 'parquet' }, ...)
54
+ ```python
55
+ ws = Workspace(
56
+ {
57
+ "/tmp": (RAMResource(), MountMode.EXEC),
58
+ "/redis": (RedisResource(url=redis_url), MountMode.WRITE),
59
+ "/slack": (SlackResource(SlackConfig(token=slack_bot_token)), MountMode.EXEC),
60
+ },
61
+ # monty captures python, so scripts run sandboxed inside the workspace
62
+ runtimes=[MontyRuntime(captures=["python", "python3"]), "vfs"],
63
+ )
53
64
 
54
- await ws.execute('summarize /data/local.csv')
55
- await ws.execute('cat /s3/events/2026-05-06.parquet | jq .user')
56
- ```
65
+ # one grep sweeps every source
66
+ await ws.execute("grep -rln session /redis /tmp")
57
67
 
58
- ## About
68
+ # run a script that lives in Slack, file the report into Redis
69
+ await ws.execute("python3 /slack/channels/general_.../files/example__F....py > /redis/report.txt")
59
70
 
60
- - **One interface instead of N SDKs and M MCPs.** Every service speaks the same filesystem semantics, and pipelines compose across services as naturally as on a local disk.
61
- - **Around 50 built-in backends:** RAM, Disk, Redis, S3 / R2 / OCI / Supabase / GCS, Gmail / GDrive / GDocs / GSheets / GSlides, GitHub / Linear / Notion / Trello, Slack / Discord / Email, MongoDB / Postgres / LanceDB, SSH, and more, mounted side-by-side under a single root.
62
- - **Portable workspaces:** clone, snapshot, and version a workspace; agent runs move between machines without restarting or reconfiguring the system.
63
- - **Embeddable:** the Python and TypeScript SDKs run in-process inside FastAPI, Express, browser apps, or any async runtime; no separate process required.
64
- - **Agent integrations:** OpenAI Agents SDK, Vercel AI SDK, LangChain, Pydantic AI, CAMEL, and OpenHands via the SDKs; coding agents through native adapters, installable plugins, MCP, or FUSE.
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.execute('slack send-message --channel general --text "report is up"')
75
+ ```
65
76
 
66
- ## Architecture
77
+ ## About
67
78
 
68
- <p align="center">
69
- <picture>
70
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-arch-dark.svg">
71
- <img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-arch-light.svg" alt="Mirage architecture: AI Agent and Application → Mirage Bash and VFS → Dispatcher &amp; Cache → Infrastructure and Remote" width="720">
72
- </picture>
73
- </p>
79
+ - **Unified virtual terminal interface, not N SDKs and M MCPs.** Every backend speaks the same filesystem semantics, so pipelines compose across services.
80
+ - **A virtual filesystem over every source.** S3, Google Drive, Slack, Gmail, Redis and the rest mount side by side under one root, so an agent reaches all of them through a unified interface with the unix tools it already knows, like `ls`, `grep`, `find` and `jq`.
81
+ - **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
+ - **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
+ - **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.
84
+ - **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
+ - **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
+ - **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.
87
+
88
+ ## Virtual Filesystem
89
+
90
+ Everything [Mirage](https://www.strukto.ai/mirage) "mounts" as one unified virtual filesystem for AI agents. Each
91
+ service sits side-by-side under a single root and answers the same POSIX semantics.
92
+
93
+ | | Resources |
94
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
95
+ | **Object Storage** | <a href="https://aws.amazon.com/s3/"><img src="https://api.iconify.design/logos/aws-s3.svg" width="20" height="20" alt="Amazon S3" title="Amazon S3" /></a>  <a href="https://developers.cloudflare.com/r2/"><img src="https://cdn.simpleicons.org/cloudflare" width="20" height="20" alt="Cloudflare R2" title="Cloudflare R2" /></a>  <a href="https://cloud.google.com/storage"><img src="https://api.iconify.design/logos/google-cloud.svg" width="25" height="20" alt="Google Cloud Storage" title="Google Cloud Storage" /></a>  <a href="https://www.oracle.com/cloud/storage/"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/oracle.svg" width="32" height="20" alt="Oracle OCI" title="Oracle OCI" /></a>  <a href="https://supabase.com/storage"><img src="https://api.iconify.design/logos/supabase-icon.svg" width="19" height="20" alt="Supabase Storage" title="Supabase Storage" /></a>  <a href="https://min.io"><img src="https://cdn.simpleicons.org/minio" width="20" height="20" alt="MinIO" title="MinIO" /></a>  <a href="https://ceph.io/en/discover/technology/"><img src="https://cdn.simpleicons.org/ceph" width="20" height="20" alt="Ceph" title="Ceph" /></a>  <a href="https://github.com/seaweedfs/seaweedfs"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/icons/seaweedfs.svg" width="20" height="20" alt="SeaweedFS" title="SeaweedFS" /></a>  <a href="https://wasabi.com/cloud-object-storage"><img src="https://cdn.simpleicons.org/wasabi" width="20" height="20" alt="Wasabi" title="Wasabi" /></a>  <a href="https://www.backblaze.com/cloud-storage"><img src="https://cdn.simpleicons.org/backblaze" width="20" height="20" alt="Backblaze B2" title="Backblaze B2" /></a>  <a href="https://www.digitalocean.com/products/spaces"><img src="https://cdn.simpleicons.org/digitalocean" width="20" height="20" alt="DigitalOcean Spaces" title="DigitalOcean Spaces" /></a>  <a href="https://www.alibabacloud.com/product/oss"><img src="https://cdn.simpleicons.org/alibabacloud" width="20" height="20" alt="Alibaba Cloud OSS" title="Alibaba Cloud OSS" /></a>  <a href="https://www.tencentcloud.com/products/cos"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/icons/tencent.png" width="20" height="20" alt="Tencent Cloud COS" title="Tencent Cloud COS" /></a>  <a href="https://www.scaleway.com/en/object-storage/"><img src="https://cdn.simpleicons.org/scaleway" width="20" height="20" alt="Scaleway" title="Scaleway" /></a>  <a href="https://www.qingcloud.com/products/qingstor"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/icons/qingstor.png" width="20" height="20" alt="QingStor" title="QingStor" /></a>  <a href="https://huggingface.co/docs/hub/storage-buckets"><img src="https://cdn.simpleicons.org/huggingface" width="20" height="20" alt="Hugging Face Buckets" title="Hugging Face Buckets" /></a>  <a href="https://www.mongodb.com/docs/manual/core/gridfs/"><img src="https://cdn.simpleicons.org/mongodb" width="20" height="20" alt="GridFS" title="GridFS" /></a> |
96
+ | **Files and Documents** | <a href="https://workspace.google.com/products/drive/"><img src="https://cdn.simpleicons.org/googledrive" width="20" height="20" alt="Google Drive" title="Google Drive" /></a>  <a href="https://docs.google.com"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/google-docs.svg" width="14" height="20" alt="Google Docs" title="Google Docs" /></a>  <a href="https://sheets.google.com"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/google-sheets.svg" width="15" height="20" alt="Google Sheets" title="Google Sheets" /></a>  <a href="https://slides.google.com"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/google-slides.svg" width="15" height="20" alt="Google Slides" title="Google Slides" /></a>  <a href="https://www.microsoft.com/microsoft-365/onedrive/online-cloud-storage"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/microsoft-onedrive.svg" width="30" height="20" alt="OneDrive" title="OneDrive" /></a>  <a href="https://www.microsoft.com/microsoft-365/sharepoint/collaboration"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/microsoft-sharepoint.svg" width="20" height="20" alt="SharePoint" title="SharePoint" /></a>  <a href="https://www.box.com"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/box.svg" width="20" height="20" alt="Box" title="Box" /></a>  <a href="https://www.dropbox.com"><img src="https://cdn.simpleicons.org/dropbox" width="20" height="20" alt="Dropbox" title="Dropbox" /></a>  <a href="https://nextcloud.com/files/"><img src="https://cdn.simpleicons.org/nextcloud" width="20" height="20" alt="Nextcloud" title="Nextcloud" /></a> |
97
+ | **Messaging and Work** | <a href="https://slack.com"><img src="https://api.iconify.design/logos/slack-icon.svg" width="20" height="20" alt="Slack" title="Slack" /></a>  <a href="https://discord.com"><img src="https://cdn.simpleicons.org/discord" width="20" height="20" alt="Discord" title="Discord" /></a>  <a href="https://mail.google.com"><img src="https://cdn.simpleicons.org/gmail" width="20" height="20" alt="Gmail" title="Gmail" /></a>  <a href="https://en.wikipedia.org/wiki/Internet_Message_Access_Protocol"><img src="https://api.iconify.design/lucide/mail.svg?color=%23888888" width="20" height="20" alt="IMAP / SMTP email" title="IMAP / SMTP email" /></a>  <a href="https://github.com"><img src="https://cdn.simpleicons.org/github/181717/e6edf3" width="20" height="20" alt="GitHub" title="GitHub" /></a>  <a href="https://linear.app"><img src="https://cdn.simpleicons.org/linear" width="20" height="20" alt="Linear" title="Linear" /></a>  <a href="https://www.notion.so"><img src="https://cdn.simpleicons.org/notion/000000/e6edf3" width="20" height="20" alt="Notion" title="Notion" /></a>  <a href="https://trello.com"><img src="https://cdn.simpleicons.org/trello" width="20" height="20" alt="Trello" title="Trello" /></a>  <a href="https://workspace.google.com/products/calendar/"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/google-calendar.svg" width="20" height="20" alt="Google Calendar" title="Google Calendar" /></a> |
98
+ | **Databases and Data Platforms** | <a href="https://www.postgresql.org"><img src="https://cdn.simpleicons.org/postgresql" width="20" height="20" alt="PostgreSQL" title="PostgreSQL" /></a>  <a href="https://www.mongodb.com"><img src="https://cdn.simpleicons.org/mongodb" width="20" height="20" alt="MongoDB" title="MongoDB" /></a>  <a href="https://redis.io"><img src="https://cdn.simpleicons.org/redis" width="20" height="20" alt="Redis" title="Redis" /></a> <a href="https://upstash.com"><img src="https://cdn.simpleicons.org/upstash" width="20" height="20" alt="Upstash Redis" title="Upstash Redis" /></a>  <a href="https://lancedb.com"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/icons/lancedb.png" width="20" height="20" alt="LanceDB" title="LanceDB" /></a>  <a href="https://qdrant.tech"><img src="https://cdn.simpleicons.org/qdrant" width="20" height="20" alt="Qdrant" title="Qdrant" /></a>  <a href="https://www.trychroma.com"><img src="https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/chroma.svg" width="31" height="20" alt="Chroma" title="Chroma" /></a>  <a href="https://mem0.ai"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/docs/images/mem0.svg" width="20" height="20" alt="Mem0" title="Mem0" /></a>  <a href="https://huggingface.co/datasets"><img src="https://cdn.simpleicons.org/huggingface" width="20" height="20" alt="Hugging Face Datasets" title="Hugging Face Datasets" /></a>  <a href="https://huggingface.co/models"><img src="https://cdn.simpleicons.org/huggingface" width="20" height="20" alt="Hugging Face Models" title="Hugging Face Models" /></a>  <a href="https://huggingface.co/spaces"><img src="https://cdn.simpleicons.org/huggingface" width="20" height="20" alt="Hugging Face Spaces" title="Hugging Face Spaces" /></a>  <a href="https://docs.databricks.com/aws/en/volumes/"><img src="https://cdn.simpleicons.org/databricks" width="20" height="20" alt="Databricks Volumes" title="Databricks Volumes" /></a>  <a href="https://dify.ai"><img src="https://cdn.simpleicons.org/dify" width="20" height="20" alt="Dify" title="Dify" /></a> |
99
+ | **Observability** | <a href="https://langfuse.com"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/docs/images/langfuse-logo.svg" width="20" height="20" alt="Langfuse" title="Langfuse" /></a>  <a href="https://www.jaegertracing.io"><img src="https://cdn.simpleicons.org/jaeger" width="20" height="20" alt="Jaeger" title="Jaeger" /></a> |
100
+ | **Local and Remote** | <a href="https://en.wikipedia.org/wiki/Random-access_memory"><img src="https://api.iconify.design/lucide/memory-stick.svg?color=%23888888" width="20" height="20" alt="RAM" title="RAM" /></a>  <a href="https://en.wikipedia.org/wiki/File_system"><img src="https://api.iconify.design/lucide/hard-drive.svg?color=%23888888" width="20" height="20" alt="Disk" title="Disk" /></a>  <a href="https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system"><img src="https://api.iconify.design/lucide/folder-lock.svg?color=%23888888" width="20" height="20" alt="OPFS" title="OPFS" /></a>  <a href="https://en.wikipedia.org/wiki/Secure_Shell"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/docs/images/ssh-logo.svg" width="20" height="20" alt="SSH" title="SSH" /></a> |
101
+
102
+ Agents reach it through the Python and TypeScript SDKs, the `mirage` CLI, or a real
103
+ mountpoint over FUSE and FSKit, then work it with the unix tools they already know,
104
+ like `ls`, `grep`, `find` and `jq`.
105
+
106
+ ## Virtual Command Line Tool
107
+
108
+ These command line tools are virtualized: [Mirage](https://www.strukto.ai/mirage) answers `git`, `slack` or `ntn`
109
+ itself, so an agent drives the service without that program being installed on the
110
+ machine. Each one mimics the real tool, so an agent that knows the CLI needs nothing
111
+ new. Because they are virtual, the same tool can be installed more than once under
112
+ different names, each with its own credentials, so every agent gets exactly the
113
+ accounts it is given.
114
+
115
+ | | CLIs |
116
+ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
117
+ | **Code** | <a href="https://git-scm.com"><img src="https://cdn.simpleicons.org/git" width="20" height="20" alt="git" title="git" /></a>  <a href="https://cli.github.com"><img src="https://cdn.simpleicons.org/github/181717/e6edf3" width="20" height="20" alt="gh" title="gh" /></a> |
118
+ | **Communication** | <a href="https://slack.com"><img src="https://api.iconify.design/logos/slack-icon.svg" width="20" height="20" alt="slack" title="slack" /></a>  <a href="https://discord.com"><img src="https://cdn.simpleicons.org/discord" width="20" height="20" alt="discord" title="discord" /></a>  <a href="https://github.com/pimalaya/himalaya"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/icons/himalaya.png" width="20" height="20" alt="himalaya" title="himalaya" /></a> |
119
+ | **Work and Data** | <a href="https://linear.app"><img src="https://cdn.simpleicons.org/linear" width="20" height="20" alt="linear" title="linear" /></a>  <a href="https://www.notion.so"><img src="https://cdn.simpleicons.org/notion/000000/e6edf3" width="20" height="20" alt="ntn" title="ntn" /></a>  <a href="https://workspace.google.com"><img src="https://cdn.simpleicons.org/google" width="20" height="20" alt="gws" title="gws" /></a>  <a href="https://huggingface.co"><img src="https://cdn.simpleicons.org/huggingface" width="20" height="20" alt="hf" title="hf" /></a> |
120
+
121
+ ## Virtual Runtime
122
+
123
+ Runtimes are virtualized the same way, and not only for coding languages. Any
124
+ command on the line can be redirected to a configured runtime, so Python might
125
+ run in-process with [Monty](https://pydantic.dev/articles/pydantic-monty) while
126
+ another command, say `kubectl`, is sent to a remote machine over SSH. Which runtime
127
+ serves a given line can be decided by a
128
+ [scripted runtime router](https://docs.mirage.strukto.ai/home/route-policy).
129
+
130
+ | | Runtimes |
131
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
132
+ | **Python** | <a href="https://pydantic.dev/articles/pydantic-monty"><img src="https://cdn.simpleicons.org/pydantic" width="20" height="20" alt="Monty" title="Monty" /></a>  <a href="https://wasi.dev"><img src="https://cdn.simpleicons.org/webassembly" width="20" height="20" alt="WASI CPython on wasmtime" title="WASI CPython on wasmtime" /></a>  <a href="https://pyodide.org"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/icons/pyodide.svg" width="56" height="20" alt="Pyodide" title="Pyodide" /></a>  <a href="https://pypi.org/project/sandlock/"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/docs/images/sandlock-logo.svg" width="20" height="20" alt="sandlock" title="sandlock" /></a>  <a href="https://www.python.org"><img src="https://cdn.simpleicons.org/python" width="20" height="20" alt="Host CPython" title="Host CPython" /></a> |
133
+ | **JavaScript** | <a href="https://docs.mirage.strukto.ai/home/setup/runtime/javascript"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/icons/quickjs.png" width="20" height="20" alt="QuickJS, serving node and js" title="QuickJS, serving node and js" /></a> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript"><img src="https://cdn.simpleicons.org/javascript" width="20" height="20" alt="JavaScript" title="JavaScript" /></a> <a href="https://www.typescriptlang.org"><img src="https://cdn.simpleicons.org/typescript" width="20" height="20" alt="TypeScript" title="TypeScript" /></a> |
134
+ | **Sandboxes** | <a href="https://www.docker.com"><img src="https://cdn.simpleicons.org/docker" width="20" height="20" alt="Docker" title="Docker" /></a>  <a href="https://e2b.dev"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/docs/images/e2b-logo.svg" width="20" height="20" alt="E2B" title="E2B" /></a>  <a href="https://www.daytona.io"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/docs/images/daytona-logo.svg" width="20" height="20" alt="Daytona" title="Daytona" /></a>  <a href="https://smolmachines.com"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/docs/images/smolvm-logo.svg" width="20" height="20" alt="smolVM" title="smolVM" /></a>  <a href="https://en.wikipedia.org/wiki/Secure_Shell"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/docs/images/ssh-logo.svg" width="20" height="20" alt="SSH" title="SSH" /></a> |
135
+
136
+ ## Security
137
+
138
+ A profile decides what a session may run and what it may see. Commands are governed
139
+ by customizable `allow`, `ask` and `deny` rules, and paths by `hide` and `show`, so a
140
+ hidden file is not merely unreadable but absent from the filesystem the agent sees.
141
+ For anything those rules cannot express, a profile can name a policy script that runs
142
+ at the gate on every command and answers allow, deny or ask itself, though like every
143
+ rule it can only restrict and never grant. Separately, a host can register its own
144
+ policies on the [policy engine](https://docs.mirage.strukto.ai/home/policy-engine), an
145
+ ordered stack the workspace consults on every command, VFS op and session write. See
146
+ the [permissions docs](https://docs.mirage.strukto.ai/home/permissions).
147
+
148
+ ## Authentication
149
+
150
+ Credentials and authentication integrate with the stores secrets already live in,
151
+ including AWS Secrets Manager, 1Password, Auth0 and dotenv, so an environment variable
152
+ in Mirage can resolve straight to a credential held in one of them.
153
+
154
+ | | Sources |
155
+ | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
156
+ | **Built in** | <a href="https://en.wikipedia.org/wiki/Environment_variable"><img src="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/icons/terminal.svg" width="20" height="20" alt="Environment" title="Environment" /></a> <a href="https://www.dotenv.org"><img src="https://cdn.simpleicons.org/dotenv" width="20" height="20" alt="dotenv" title="dotenv" /></a> <a href="https://aws.amazon.com/secrets-manager/"><img src="https://api.iconify.design/logos/aws-secrets-manager.svg" width="20" height="20" alt="AWS Secrets Manager" title="AWS Secrets Manager" /></a> |
157
+ | **Custom** | <a href="https://1password.com"><img src="https://cdn.simpleicons.org/1password" width="20" height="20" alt="1Password" title="1Password" /></a> <a href="https://auth0.com"><img src="https://cdn.simpleicons.org/auth0" width="20" height="20" alt="Auth0" title="Auth0" /></a> |
74
158
 
75
159
  ## Installation
76
160
 
77
161
  - **Python** ≥ 3.11 for the `mirage-ai` package and the `mirage` CLI
78
162
  - **Node.js** ≥ 20 for the TypeScript SDK
79
- - **macOS** or **Linux** (FUSE-based mounts require platform support)
80
163
 
81
164
  ### Python
82
165
 
@@ -152,35 +235,10 @@ mirage workspace snapshot demo demo.tar
152
235
  mirage workspace load demo.tar --id demo-restored
153
236
  ```
154
237
 
155
- ## Agent Frameworks
156
-
157
- Mirage plugs into agent frameworks as a sandbox or tool layer. POSIX operations such as `read` can also be customized per resource and filetype, e.g. reading a PDF returns parsed pages instead of raw bytes.
158
-
159
- | | Integrations |
160
- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
161
- | Python | [OpenAI Agents SDK](https://docs.mirage.strukto.ai/python/agents/openai-agents), [LangChain](https://docs.mirage.strukto.ai/python/agents/langchain), [Pydantic AI](https://docs.mirage.strukto.ai/python/agents/pydantic-ai), [CAMEL](https://docs.mirage.strukto.ai/python/agents/camel), [OpenHands](https://docs.mirage.strukto.ai/python/agents/openhands), [Agno](https://docs.mirage.strukto.ai/python/agents/agno) |
162
- | TypeScript | [Vercel AI SDK](https://docs.mirage.strukto.ai/typescript/agents/vercel), [OpenAI Agents SDK](https://docs.mirage.strukto.ai/typescript/agents/openai), [LangChain](https://docs.mirage.strukto.ai/typescript/agents/langchain), [Mastra](https://docs.mirage.strukto.ai/typescript/agents/mastra) |
163
- | Coding agents | [Claude Code](https://docs.mirage.strukto.ai/python/agents/claude-code), [Codex](https://docs.mirage.strukto.ai/typescript/agents/codex), [Grok Build](https://docs.mirage.strukto.ai/typescript/agents/grok-build), [OpenCode](https://docs.mirage.strukto.ai/typescript/agents/opencode), [Pi](https://docs.mirage.strukto.ai/typescript/agents/pi) |
238
+ ## Contributors
164
239
 
165
- ## Cache
166
-
167
- Every `Workspace` has a two-layer cache so repeated work against remote backends hits local state instead of the network:
168
-
169
- - **Index cache:** listings and metadata. The first directory walk hits the API; later ones serve from the index until the TTL expires (default 10 minutes).
170
- - **File cache:** object bytes. The first read streams from origin; later pipelines read from cache (default 512 MB).
171
-
172
- Both layers default to in-process RAM with zero setup. A Redis store shares cache state across workers, processes, and machines:
173
-
174
- ```ts
175
- import { RedisFileCacheStore, S3Resource, Workspace } from '@struktoai/mirage-node'
176
-
177
- const ws = new Workspace(
178
- { '/s3': new S3Resource({ bucket: 'my-bucket' }) },
179
- {
180
- cache: new RedisFileCacheStore({ url: 'redis://localhost:6379/0', cacheLimit: '8GB' }),
181
- index: { type: 'redis', url: 'redis://localhost:6379/0', ttl: 600 },
182
- },
183
- )
184
- ```
240
+ Thanks to everyone who has contributed to Mirage.
185
241
 
186
- See the [cache docs](https://docs.mirage.strukto.ai/home/cache) for the full miss/hit lifecycle.
242
+ <a href="https://github.com/strukto-ai/mirage/graphs/contributors">
243
+ <img src="https://contrib.rocks/image?repo=strukto-ai/mirage" alt="Mirage contributors" />
244
+ </a>
@@ -0,0 +1,33 @@
1
+ // src/io-text.ts
2
+ import { describeRefusal, saysWhy } from "@struktoai/mirage-core/policy/index";
3
+ function decode(value) {
4
+ if (value === null || value === void 0) return "";
5
+ return new TextDecoder("utf-8").decode(value);
6
+ }
7
+ function refusalLine(text, refusal) {
8
+ if (refusal === null || saysWhy(text, refusal)) return "";
9
+ return `${describeRefusal(refusal)}
10
+ `;
11
+ }
12
+ function withRefusal(text, refusal) {
13
+ const line = refusalLine(text, refusal);
14
+ if (line === "" || text === "") return text || line;
15
+ return text.endsWith("\n") ? `${text}${line}` : `${text}
16
+ ${line}`;
17
+ }
18
+ function ioToStr(io) {
19
+ const stdout = io.stdoutText;
20
+ const stderr = io.stderrText;
21
+ let text = stdout;
22
+ if (stderr) text = stdout ? `${stdout}
23
+ ${stderr}` : stderr;
24
+ return withRefusal(text, io.refusal);
25
+ }
26
+
27
+ export {
28
+ decode,
29
+ refusalLine,
30
+ withRefusal,
31
+ ioToStr
32
+ };
33
+ //# sourceMappingURL=chunk-3N5GLSL7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/io-text.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { describeRefusal, saysWhy } from '@struktoai/mirage-core/policy/index'\nimport type { Refusal } from '@struktoai/mirage-core/types'\nimport type { ExecuteResult } from '@struktoai/mirage-core/workspace/workspace/workspace'\n\nexport function decode(value: Uint8Array | null | undefined): string {\n if (value === null || value === undefined) return ''\n return new TextDecoder('utf-8').decode(value)\n}\n\n/**\n * The one line a text surface appends for a refusal, newline included,\n * or the empty string when there is nothing to add: no record, or a text\n * that already says why (an operand-scoped denial's GNU line, wherever\n * it landed). A command-scoped refusal's stderr is bash's bare\n * `Permission denied`, which never does. Mirrors Python's `refusal_line`.\n */\nexport function refusalLine(text: string, refusal: Refusal | null): string {\n if (refusal === null || saysWhy(text, refusal)) return ''\n return `${describeRefusal(refusal)}\\n`\n}\n\n/**\n * Append the refusal's reason as one more line after the shell's own\n * output, for a surface that hands the agent text.\n */\nexport function withRefusal(text: string, refusal: Refusal | null): string {\n const line = refusalLine(text, refusal)\n if (line === '' || text === '') return text || line\n return text.endsWith('\\n') ? `${text}${line}` : `${text}\\n${line}`\n}\n\nexport function ioToStr(io: ExecuteResult): string {\n const stdout = io.stdoutText\n const stderr = io.stderrText\n let text = stdout\n if (stderr) text = stdout ? `${stdout}\\n${stderr}` : stderr\n return withRefusal(text, io.refusal)\n}\n"],"mappings":";AAcA,SAAS,iBAAiB,eAAe;AAIlC,SAAS,OAAO,OAA8C;AACnE,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,SAAO,IAAI,YAAY,OAAO,EAAE,OAAO,KAAK;AAC9C;AASO,SAAS,YAAY,MAAc,SAAiC;AACzE,MAAI,YAAY,QAAQ,QAAQ,MAAM,OAAO,EAAG,QAAO;AACvD,SAAO,GAAG,gBAAgB,OAAO,CAAC;AAAA;AACpC;AAMO,SAAS,YAAY,MAAc,SAAiC;AACzE,QAAM,OAAO,YAAY,MAAM,OAAO;AACtC,MAAI,SAAS,MAAM,SAAS,GAAI,QAAO,QAAQ;AAC/C,SAAO,KAAK,SAAS,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI,KAAK,GAAG,IAAI;AAAA,EAAK,IAAI;AAClE;AAEO,SAAS,QAAQ,IAA2B;AACjD,QAAM,SAAS,GAAG;AAClB,QAAM,SAAS,GAAG;AAClB,MAAI,OAAO;AACX,MAAI,OAAQ,QAAO,SAAS,GAAG,MAAM;AAAA,EAAK,MAAM,KAAK;AACrD,SAAO,YAAY,MAAM,GAAG,OAAO;AACrC;","names":[]}
@@ -1,8 +1,9 @@
1
1
  // src/read-file.ts
2
- import { detectFileType, FileType as FileType2 } from "@struktoai/mirage-core";
2
+ import { detectFileType } from "@struktoai/mirage-core/commands/builtin/file_sniff";
3
+ import { FileType } from "@struktoai/mirage-core/types";
3
4
 
4
5
  // src/read-file/constants.ts
5
- import { FileType } from "@struktoai/mirage-core";
6
+ import { ContentType } from "@struktoai/mirage-core/types";
6
7
  var READ_FILE_MIME = Object.freeze({
7
8
  BINARY: "application/octet-stream",
8
9
  CSV: "text/csv",
@@ -65,13 +66,13 @@ var MIME_FOR_EXTENSION = Object.freeze({
65
66
  pdf: READ_FILE_MIME.PDF
66
67
  });
67
68
  var MIME_FOR_FILE_TYPE = Object.freeze({
68
- [FileType.JSON]: READ_FILE_MIME.JSON,
69
- [FileType.CSV]: READ_FILE_MIME.CSV,
70
- [FileType.TEXT]: READ_FILE_MIME.PLAIN_TEXT,
71
- [FileType.IMAGE_PNG]: READ_FILE_MIME.IMAGE_PNG,
72
- [FileType.IMAGE_JPEG]: READ_FILE_MIME.IMAGE_JPEG,
73
- [FileType.IMAGE_GIF]: READ_FILE_MIME.IMAGE_GIF,
74
- [FileType.PDF]: READ_FILE_MIME.PDF
69
+ [ContentType.JSON]: READ_FILE_MIME.JSON,
70
+ [ContentType.CSV]: READ_FILE_MIME.CSV,
71
+ [ContentType.TEXT]: READ_FILE_MIME.PLAIN_TEXT,
72
+ [ContentType.IMAGE_PNG]: READ_FILE_MIME.IMAGE_PNG,
73
+ [ContentType.IMAGE_JPEG]: READ_FILE_MIME.IMAGE_JPEG,
74
+ [ContentType.IMAGE_GIF]: READ_FILE_MIME.IMAGE_GIF,
75
+ [ContentType.PDF]: READ_FILE_MIME.PDF
75
76
  });
76
77
  var MODEL_IMAGE_MIMES = /* @__PURE__ */ new Set([
77
78
  READ_FILE_MIME.IMAGE_JPEG,
@@ -110,7 +111,7 @@ function isTextMime(mimeType) {
110
111
  }
111
112
  async function readWorkspaceFile(ws, path, reader) {
112
113
  const stat = await ws.fs.stat(path);
113
- if (stat.type === FileType2.DIRECTORY) {
114
+ if (stat.type === FileType.DIRECTORY) {
114
115
  throw new Error(`Cannot read directory as a file: ${path}`);
115
116
  }
116
117
  const data = reader === void 0 ? await ws.fs.readFile(path, { raw: true }) : await reader(path);
@@ -139,4 +140,4 @@ async function readWorkspaceFile(ws, path, reader) {
139
140
  export {
140
141
  readWorkspaceFile
141
142
  };
142
- //# sourceMappingURL=chunk-IMI7BLEG.js.map
143
+ //# sourceMappingURL=chunk-DIUKTEAK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/read-file.ts","../src/read-file/constants.ts"],"sourcesContent":["import { detectFileType } from '@struktoai/mirage-core/commands/builtin/file_sniff'\nimport { FileType } from '@struktoai/mirage-core/types'\nimport type { ContentType, FileStat } from '@struktoai/mirage-core/types'\nimport type { Workspace } from '@struktoai/mirage-core/workspace/workspace/workspace'\nimport {\n MIME_FOR_EXTENSION,\n MIME_FOR_FILE_TYPE,\n MODEL_IMAGE_MIMES,\n READ_FILE_MIME,\n TEXT_FILE_EXTENSIONS,\n type ReadFileMime,\n} from './read-file/constants.ts'\n\ninterface WorkspaceFileBase {\n path: string\n mimeType: ReadFileMime\n bytes: number\n}\n\nexport type WorkspaceFileReadResult =\n | (WorkspaceFileBase & { kind: 'text'; content: string })\n | (WorkspaceFileBase & { kind: 'image'; data: Uint8Array })\n | (WorkspaceFileBase & { kind: 'file'; data: Uint8Array; filename: string })\n | (WorkspaceFileBase & { kind: 'binary'; note: string })\n\nexport type WorkspaceFileReader = (path: string) => Promise<Uint8Array>\n\nfunction extOf(path: string): string {\n const dot = path.lastIndexOf('.')\n const slash = path.lastIndexOf('/')\n if (dot < 0 || dot < slash) return ''\n return path.slice(dot + 1).toLowerCase()\n}\n\nfunction filenameOf(path: string): string {\n const slash = path.lastIndexOf('/')\n const filename = slash < 0 ? path : path.slice(slash + 1)\n return filename === '' ? 'file' : filename\n}\n\nfunction mimeForExtension(path: string): ReadFileMime | undefined {\n const ext = extOf(path)\n return (\n MIME_FOR_EXTENSION[ext] ??\n (TEXT_FILE_EXTENSIONS.has(ext) ? READ_FILE_MIME.PLAIN_TEXT : undefined)\n )\n}\n\nfunction mimeForDetectedType(type: ContentType): ReadFileMime {\n return MIME_FOR_FILE_TYPE[type] ?? READ_FILE_MIME.BINARY\n}\n\nfunction mimeFor(path: string, bytes: Uint8Array, stat: FileStat): ReadFileMime {\n const extensionMime = mimeForExtension(path)\n if (extensionMime !== undefined) return extensionMime\n if (extOf(path) !== '') return READ_FILE_MIME.BINARY\n return mimeForDetectedType(detectFileType(bytes, stat))\n}\n\nfunction isTextMime(mimeType: ReadFileMime): boolean {\n return (\n mimeType.startsWith('text/') ||\n mimeType === READ_FILE_MIME.JSON ||\n mimeType === READ_FILE_MIME.SVG\n )\n}\n\nexport async function readWorkspaceFile(\n ws: Workspace,\n path: string,\n reader?: WorkspaceFileReader,\n): Promise<WorkspaceFileReadResult> {\n const stat = await ws.fs.stat(path)\n if (stat.type === FileType.DIRECTORY) {\n throw new Error(`Cannot read directory as a file: ${path}`)\n }\n const data = reader === undefined ? await ws.fs.readFile(path, { raw: true }) : await reader(path)\n const mimeType = mimeFor(path, data, stat)\n const base = { path, mimeType, bytes: data.byteLength }\n\n if (isTextMime(mimeType)) {\n return {\n ...base,\n kind: 'text',\n content: new TextDecoder('utf-8', { fatal: false }).decode(data),\n }\n }\n if (MODEL_IMAGE_MIMES.has(mimeType)) {\n return { ...base, kind: 'image', data }\n }\n if (mimeType === READ_FILE_MIME.PDF) {\n return { ...base, kind: 'file', data, filename: filenameOf(path) }\n }\n return {\n ...base,\n kind: 'binary',\n note:\n `Binary file ${path} (${mimeType}, ${String(data.byteLength)} bytes). ` +\n 'Use the execute tool with shell commands (head, file, wc, od) to inspect.',\n }\n}\n","import { ContentType } from '@struktoai/mirage-core/types'\n\nexport const READ_FILE_MIME = Object.freeze({\n BINARY: 'application/octet-stream',\n CSV: 'text/csv',\n HTML: 'text/html',\n IMAGE_GIF: 'image/gif',\n IMAGE_JPEG: 'image/jpeg',\n IMAGE_PNG: 'image/png',\n IMAGE_WEBP: 'image/webp',\n JSON: 'application/json',\n MARKDOWN: 'text/markdown',\n PDF: 'application/pdf',\n PLAIN_TEXT: 'text/plain',\n SVG: 'image/svg+xml',\n} as const)\n\nexport type ReadFileMime = (typeof READ_FILE_MIME)[keyof typeof READ_FILE_MIME]\n\nexport const TEXT_FILE_EXTENSIONS: ReadonlySet<string> = new Set([\n 'txt',\n 'yaml',\n 'yml',\n 'tsv',\n 'xml',\n 'js',\n 'mjs',\n 'cjs',\n 'ts',\n 'tsx',\n 'jsx',\n 'py',\n 'rb',\n 'rs',\n 'go',\n 'java',\n 'c',\n 'cpp',\n 'h',\n 'hpp',\n 'sh',\n 'bash',\n 'zsh',\n 'sql',\n 'log',\n 'env',\n 'ini',\n 'toml',\n 'conf',\n 'cfg',\n])\n\nexport const MIME_FOR_EXTENSION: Readonly<Record<string, ReadFileMime>> = Object.freeze({\n json: READ_FILE_MIME.JSON,\n jsonl: READ_FILE_MIME.JSON,\n csv: READ_FILE_MIME.CSV,\n html: READ_FILE_MIME.HTML,\n htm: READ_FILE_MIME.HTML,\n md: READ_FILE_MIME.MARKDOWN,\n svg: READ_FILE_MIME.SVG,\n png: READ_FILE_MIME.IMAGE_PNG,\n jpg: READ_FILE_MIME.IMAGE_JPEG,\n jpeg: READ_FILE_MIME.IMAGE_JPEG,\n gif: READ_FILE_MIME.IMAGE_GIF,\n webp: READ_FILE_MIME.IMAGE_WEBP,\n pdf: READ_FILE_MIME.PDF,\n})\n\nexport const MIME_FOR_FILE_TYPE: Readonly<Partial<Record<ContentType, ReadFileMime>>> =\n Object.freeze({\n [ContentType.JSON]: READ_FILE_MIME.JSON,\n [ContentType.CSV]: READ_FILE_MIME.CSV,\n [ContentType.TEXT]: READ_FILE_MIME.PLAIN_TEXT,\n [ContentType.IMAGE_PNG]: READ_FILE_MIME.IMAGE_PNG,\n [ContentType.IMAGE_JPEG]: READ_FILE_MIME.IMAGE_JPEG,\n [ContentType.IMAGE_GIF]: READ_FILE_MIME.IMAGE_GIF,\n [ContentType.PDF]: READ_FILE_MIME.PDF,\n })\n\nexport const MODEL_IMAGE_MIMES: ReadonlySet<ReadFileMime> = new Set([\n READ_FILE_MIME.IMAGE_JPEG,\n READ_FILE_MIME.IMAGE_PNG,\n READ_FILE_MIME.IMAGE_GIF,\n READ_FILE_MIME.IMAGE_WEBP,\n])\n"],"mappings":"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","names":[]}
@@ -1,25 +1,14 @@
1
1
  import {
2
2
  FileVersionTracker,
3
3
  StaleMirageFileError
4
- } from "./chunk-XEQB7N3F.js";
5
-
6
- // src/tool-operations.ts
7
- import { gnuDirname } from "@struktoai/mirage-core";
8
-
9
- // src/io-text.ts
10
- function decode(value) {
11
- if (value === null || value === void 0) return "";
12
- return new TextDecoder("utf-8").decode(value);
13
- }
14
- function ioToStr(io) {
15
- const stdout = io.stdoutText;
16
- const stderr = io.stderrText;
17
- if (stderr) return stdout ? `${stdout}
18
- ${stderr}` : stderr;
19
- return stdout;
20
- }
4
+ } from "./chunk-YJS2FVEB.js";
5
+ import {
6
+ decode,
7
+ ioToStr
8
+ } from "./chunk-3N5GLSL7.js";
21
9
 
22
10
  // src/tool-operations.ts
11
+ import { gnuDirname } from "@struktoai/mirage-core/utils/path";
23
12
  function textResult(text) {
24
13
  return { content: [{ type: "text", text }] };
25
14
  }
@@ -115,7 +104,9 @@ var MirageToolOperations = class {
115
104
  }
116
105
  async grep(pattern, path) {
117
106
  const io = await this.ws.execute(`grep -rn ${shQuote(pattern)} ${shQuote(path)}`);
118
- return textResult(ioToStr(io));
107
+ const result = textResult(ioToStr(io));
108
+ if (io.exitCode > 1) result.isError = true;
109
+ return result;
119
110
  }
120
111
  };
121
112
 
@@ -136,4 +127,4 @@ export {
136
127
  LS_DESCRIPTION,
137
128
  GREP_DESCRIPTION
138
129
  };
139
- //# sourceMappingURL=chunk-Y4G25V5V.js.map
130
+ //# sourceMappingURL=chunk-GEO2G6YZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tool-operations.ts","../src/tool-descriptions.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { gnuDirname } from '@struktoai/mirage-core/utils/path'\nimport type { ExecuteResult, Workspace } from '@struktoai/mirage-core/workspace/workspace/workspace'\nimport { FileVersionTracker, StaleMirageFileError } from './file-version.ts'\nimport { decode, ioToStr } from './io-text.ts'\n\nexport interface ToolResult {\n [key: string]: unknown\n content: { type: 'text'; text: string }[]\n isError?: boolean\n}\n\nexport interface MirageToolOperationsOptions {\n staleWriteProtection?: boolean\n}\n\nfunction textResult(text: string): ToolResult {\n return { content: [{ type: 'text', text }] }\n}\n\nfunction errorResult(text: string): ToolResult {\n return { content: [{ type: 'text', text }], isError: true }\n}\n\nfunction ioResult(io: ExecuteResult): ToolResult {\n const result = textResult(ioToStr(io))\n if (io.exitCode !== 0) result.isError = true\n return result\n}\n\nfunction shQuote(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`\n}\n\nasync function ensureParents(ws: Workspace, path: string): Promise<void> {\n const parent = gnuDirname(path)\n if (parent === '/' || parent === '' || parent === '.') return\n if (await ws.fs.exists(parent)) return\n await ensureParents(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nexport class MirageToolOperations {\n private readonly versions: FileVersionTracker\n\n constructor(\n private readonly ws: Workspace,\n options: MirageToolOperationsOptions = {},\n ) {\n this.versions = new FileVersionTracker(ws, options.staleWriteProtection ?? true)\n }\n\n async execute(command: string): Promise<ToolResult> {\n return ioResult(await this.ws.execute(command))\n }\n\n async read(path: string, offset = 0, limit = 2000): Promise<ToolResult> {\n let data: Uint8Array\n try {\n data = await this.versions.read(path)\n } catch (err) {\n if (!(await this.ws.fs.exists(path))) {\n return errorResult(`Error: file '${path}' not found`)\n }\n return errorResult(`Error: ${errorMessage(err)}`)\n }\n const text = decode(data)\n const raw = text.length === 0 ? [] : text.split(/(?<=\\n)/)\n const lines = raw.length > 0 && raw[raw.length - 1] === '' ? raw.slice(0, -1) : raw\n const sliced = lines.slice(offset, offset + limit)\n const numbered = sliced.map((line, i) => `${String(i + offset + 1).padStart(6)}\\t${line}`)\n return textResult(numbered.join(''))\n }\n\n async write(path: string, content: string): Promise<ToolResult> {\n if (await this.ws.fs.exists(path)) {\n return errorResult(`Error: file '${path}' already exists`)\n }\n await ensureParents(this.ws, path)\n await this.versions.write(path, content)\n return textResult(`Written: ${path}`)\n }\n\n async edit(\n path: string,\n oldString: string,\n newString: string,\n replaceAll = false,\n ): Promise<ToolResult> {\n let content: string\n try {\n content = (await this.versions.readForEdit(path)).toString('utf8')\n } catch (err) {\n if (err instanceof StaleMirageFileError) return errorResult(`Error: ${err.message}`)\n if (!(await this.ws.fs.exists(path))) {\n return errorResult(`Error: file '${path}' not found`)\n }\n return errorResult(`Error: ${errorMessage(err)}`)\n }\n const count = content.split(oldString).length - 1\n if (count === 0) {\n return errorResult(`Error: string not found in file: '${oldString}'`)\n }\n if (count > 1 && !replaceAll) {\n return errorResult(`Error: string appears ${String(count)} times. Pass replace_all=true`)\n }\n const newContent = replaceAll\n ? content.split(oldString).join(newString)\n : content.replace(oldString, newString)\n try {\n await this.versions.writeEdit(path, newContent)\n } catch (err) {\n return errorResult(`Error: ${errorMessage(err)}`)\n }\n const occurrences = replaceAll ? count : 1\n return textResult(`Edited: ${path} (${String(occurrences)} occurrence(s))`)\n }\n\n async ls(path: string): Promise<ToolResult> {\n return ioResult(await this.ws.execute(`ls ${shQuote(path)}`))\n }\n\n async grep(pattern: string, path: string): Promise<ToolResult> {\n const io = await this.ws.execute(`grep -rn ${shQuote(pattern)} ${shQuote(path)}`)\n // grep exits 1 for \"no match\", which is a normal empty answer, and\n // >1 for a real failure (bad regex, unreadable path). Only the\n // second is a tool error; reporting the first as one would tell the\n // agent its search broke every time nothing matched.\n const result = textResult(ioToStr(io))\n if (io.exitCode > 1) result.isError = true\n return result\n }\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nexport const EXECUTE_DESCRIPTION =\n 'Run a shell-style command on the Mirage virtual filesystem. ' +\n 'Supports cat, grep, find, head, tail, ls, wc, sort, uniq, tee, pipe, ' +\n 'and any other Unix command on mounted resources (S3, disk, RAM, etc.). ' +\n 'Files with no registered renderer, such as .parquet or .orc, read back as raw bytes.'\n\nexport const READ_DESCRIPTION =\n 'Read the contents of a file on the Mirage virtual filesystem. ' +\n 'Returns line-numbered text. ' +\n \"Optionally pass 'offset' (default 0) to start at a given line \" +\n \"and 'limit' (default 2000) to cap the number of lines returned.\"\n\nexport const WRITE_DESCRIPTION =\n 'Write content to a new file on the Mirage virtual filesystem. ' +\n 'Fails if the file already exists; use edit to modify an existing file.'\n\nexport const EDIT_DESCRIPTION =\n 'Replace a string in an existing file on the Mirage virtual filesystem. ' +\n 'Fails if the file changed since it was last read, old_string is not found, ' +\n 'or old_string appears more than once. ' +\n 'Pass replace_all=true (default false) to replace every occurrence.'\n\nexport const LS_DESCRIPTION =\n 'List files and directories at the given path on the Mirage virtual filesystem.'\n\nexport const GREP_DESCRIPTION =\n 'Search for a pattern in files on the Mirage virtual filesystem. ' +\n 'Supports regex. Searches recursively under path.'\n"],"mappings":"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","names":[]}
@@ -32,4 +32,4 @@ export {
32
32
  MIRAGE_SYSTEM_PROMPT,
33
33
  buildSystemPrompt
34
34
  };
35
- //# sourceMappingURL=chunk-ZPXFVDYT.js.map
35
+ //# sourceMappingURL=chunk-S6DWWJVF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/prompt.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-core/workspace/workspace/workspace'\n\nexport const MIRAGE_SYSTEM_PROMPT = `Your filesystem is powered by Mirage — a virtual filesystem that mounts cloud storage, local files, and in-memory data as a unified file tree.\n\nCapabilities beyond standard filesystem:\n- head -n 5 on data files returns the first 5 rows\n- grep works on structured text such as CSV and JSON, not just plain text\n- Pipes work: cat data.csv | grep error | sort | uniq | wc -l\n- head, tail, cut, wc, sort, uniq, tee, xargs are all available\n\nYou can write Python code and execute it. The workspace is pre-configured with your data sources mounted at their respective paths.\n\nUse the execute tool for complex operations. Use read/write/edit for simple file operations.\n`\n\nexport interface BuildSystemPromptOptions {\n workspace?: Workspace\n mountInfo?: Record<string, string>\n extraInstructions?: string\n}\n\nexport function buildSystemPrompt(opts: BuildSystemPromptOptions = {}): string {\n const parts: string[] = [MIRAGE_SYSTEM_PROMPT]\n if (opts.workspace !== undefined) {\n parts.push('Mounted data sources:\\n' + opts.workspace.filePrompt)\n } else if (opts.mountInfo !== undefined && Object.keys(opts.mountInfo).length > 0) {\n parts.push('\\nMounted data sources:')\n for (const [prefix, description] of Object.entries(opts.mountInfo)) {\n parts.push(`- ${prefix} — ${description}`)\n }\n parts.push('')\n }\n if (opts.extraInstructions !== undefined && opts.extraInstructions.length > 0) {\n parts.push(opts.extraInstructions)\n }\n return parts.join('\\n')\n}\n"],"mappings":";AAgBO,IAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmB7B,SAAS,kBAAkB,OAAiC,CAAC,GAAW;AAC7E,QAAM,QAAkB,CAAC,oBAAoB;AAC7C,MAAI,KAAK,cAAc,QAAW;AAChC,UAAM,KAAK,4BAA4B,KAAK,UAAU,UAAU;AAAA,EAClE,WAAW,KAAK,cAAc,UAAa,OAAO,KAAK,KAAK,SAAS,EAAE,SAAS,GAAG;AACjF,UAAM,KAAK,yBAAyB;AACpC,eAAW,CAAC,QAAQ,WAAW,KAAK,OAAO,QAAQ,KAAK,SAAS,GAAG;AAClE,YAAM,KAAK,KAAK,MAAM,WAAM,WAAW,EAAE;AAAA,IAC3C;AACA,UAAM,KAAK,EAAE;AAAA,EACf;AACA,MAAI,KAAK,sBAAsB,UAAa,KAAK,kBAAkB,SAAS,GAAG;AAC7E,UAAM,KAAK,KAAK,iBAAiB;AAAA,EACnC;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":[]}