@struktoai/mirage-cli 0.0.5 → 0.0.6

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.
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-cli" alt="NPM Version">
23
- <img src="https://img.shields.io/npm/v/%40struktoai%2Fmirage-cli.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 like Claude Code and Codex via the lightweight CLI + daemon.
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/python/agents/codex), [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>
@@ -13,19 +13,19 @@ import {
13
13
  resolvedConfig,
14
14
  setConfig,
15
15
  unsetConfig
16
- } from "../chunk-PCROWRBJ.js";
16
+ } from "../chunk-BNUV7A4V.js";
17
17
 
18
18
  // src/bin/mirage.ts
19
19
  import { DaemonConfigError as DaemonConfigError2 } from "@struktoai/mirage-server";
20
20
 
21
21
  // src/main.ts
22
22
  import { readFileSync as readFileSync4 } from "fs";
23
- import { dirname, join } from "path";
23
+ import { dirname as dirname2, join } from "path";
24
24
  import { fileURLToPath } from "url";
25
25
  import { Command } from "commander";
26
26
 
27
27
  // src/config.ts
28
- import { compareCodePoints } from "@struktoai/mirage-core";
28
+ import { compareCodePoints } from "@struktoai/mirage-core/utils/sort";
29
29
  import { ALLOWED_KEYS, DaemonConfigError } from "@struktoai/mirage-server";
30
30
  function mask(key, value) {
31
31
  if (key === "auth_token" && value !== "") return "***";
@@ -388,9 +388,12 @@ function registerSessionCommands(program) {
388
388
  const sess = program.command("session").description("Manage workspace sessions.");
389
389
  sess.command("create").argument("<wsId>").option("--id <sessionId>").option(
390
390
  "-m, --mount <prefix>",
391
- "restrict session to a mount, optionally capping its mode: '/data:read' (alias '/data:r'), '/scratch:rw', '/bin:rwx', or a bare '/data' to keep the mount's own mode; repeatable",
391
+ "narrow a mount's mode for this session: '/data:read' (alias '/data:r'), '/scratch:rw', '/bin:rwx', or a bare '/data' to keep the mount's own mode; repeatable. This narrows only: a mount you do not name keeps its own mode, and keeping a session away from one is a hide in its profile",
392
392
  (value, prev) => prev.concat([value]),
393
393
  []
394
+ ).option(
395
+ "-p, --profile <name>",
396
+ "the profile this session runs under, by name from the workspace's profiles; omit it to take the workspace default"
394
397
  ).action(async (wsId, opts) => {
395
398
  const c = buildClient3();
396
399
  await c.ensureRunning({ allowSpawn: false });
@@ -399,6 +402,7 @@ function registerSessionCommands(program) {
399
402
  if (opts.mount !== void 0 && opts.mount.length > 0) {
400
403
  body.mounts = parseMountModes(opts.mount);
401
404
  }
405
+ if (opts.profile !== void 0) body.profile = opts.profile;
402
406
  emit(
403
407
  await handleResponse(
404
408
  await c.request("POST", `/v1/workspaces/${wsId}/sessions`, {
@@ -425,8 +429,12 @@ function registerSessionCommands(program) {
425
429
 
426
430
  // src/workspace.ts
427
431
  import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
428
- import { resolve } from "path";
429
- import { checkWorkspaceConfigFile, interpolateEnv } from "@struktoai/mirage-server";
432
+ import { dirname, resolve } from "path";
433
+ import {
434
+ absolutizeScripts,
435
+ checkWorkspaceConfigFile,
436
+ interpolateEnv
437
+ } from "@struktoai/mirage-server";
430
438
  import { parse as yamlParse } from "yaml";
431
439
  function buildClient4() {
432
440
  return makeClient(loadDaemonSettings());
@@ -441,11 +449,16 @@ function envRecord() {
441
449
  function loadConfigArgument(path) {
442
450
  if (!existsSync2(path)) fail(`config file not found: ${path}`, 2);
443
451
  const text = readFileSync3(path, "utf-8");
452
+ let config;
444
453
  try {
445
- return interpolateEnv(yamlParse(text), envRecord());
454
+ config = interpolateEnv(yamlParse(text), envRecord());
446
455
  } catch (err) {
447
456
  fail(`invalid config YAML/JSON at ${path}: ${String(err)}`, 2);
448
457
  }
458
+ if (typeof config === "object" && config !== null && !Array.isArray(config)) {
459
+ absolutizeScripts(config, dirname(resolve(path)));
460
+ }
461
+ return config;
449
462
  }
450
463
  function formatWorkspaceList(items) {
451
464
  if (items.length === 0) return "No active workspaces.";
@@ -487,6 +500,19 @@ function formatWorkspaceDetail(d) {
487
500
  }
488
501
  return lines.join("\n");
489
502
  }
503
+ function formatAsks(items) {
504
+ if (items.length === 0) return "No asks.";
505
+ return formatTable(
506
+ ["ID", "SESSION", "COMMAND", "STATUS", "REASON"],
507
+ items.map((a) => [
508
+ a.id,
509
+ a.sessionId,
510
+ [a.command, ...a.argv].join(" "),
511
+ a.outcome ?? "pending",
512
+ a.reason
513
+ ])
514
+ );
515
+ }
490
516
  function formatVersionLog(items) {
491
517
  if (items.length === 0) return "No versions.";
492
518
  return formatTable(
@@ -585,6 +611,36 @@ function registerWorkspaceCommands(program) {
585
611
  emit(await handleResponse(r), formatDiff);
586
612
  }
587
613
  );
614
+ ws.command("list-asks").description("List pending asks (every decision with --all).").argument("<id>").option("--session <sessionId>", "Only this session's asks").option("--all", "Include settled decisions, not just pending asks").action(async (id, opts) => {
615
+ const params = new URLSearchParams();
616
+ if (opts.session !== void 0) params.set("sessionId", opts.session);
617
+ if (opts.all === true) params.set("all", "true");
618
+ const c = buildClient4();
619
+ await c.ensureRunning({ allowSpawn: false });
620
+ const qs = params.toString();
621
+ const r = await c.request("GET", `/v1/workspaces/${id}/asks${qs === "" ? "" : `?${qs}`}`);
622
+ emit(await handleResponse(r), formatAsks);
623
+ });
624
+ ws.command("allow").description("Allow a pending ask; the retry of the asked line passes.").argument("<id>").argument("<askId>", "Ask id, as quoted in the refusal").option(
625
+ "--scope <scope>",
626
+ "once answers the exact line; session answers every line the rule covers",
627
+ "once"
628
+ ).option("--note <note>", "What to record alongside the answer", "").action(async (id, askId, opts) => {
629
+ const c = buildClient4();
630
+ await c.ensureRunning({ allowSpawn: false });
631
+ const r = await c.request("POST", `/v1/workspaces/${id}/asks/${askId}`, {
632
+ body: JSON.stringify({ answer: "allow", scope: opts.scope, note: opts.note })
633
+ });
634
+ emit(await handleResponse(r), (d) => `Allowed ${d.id} (${d.scope}).`);
635
+ });
636
+ ws.command("deny").description("Deny a pending ask; the retry is refused in the deny voice, once.").argument("<id>").argument("<askId>", "Ask id, as quoted in the refusal").option("--note <note>", "What to record alongside the answer", "").action(async (id, askId, opts) => {
637
+ const c = buildClient4();
638
+ await c.ensureRunning({ allowSpawn: false });
639
+ const r = await c.request("POST", `/v1/workspaces/${id}/asks/${askId}`, {
640
+ body: JSON.stringify({ answer: "deny", note: opts.note })
641
+ });
642
+ emit(await handleResponse(r), (d) => `Denied ${d.id}.`);
643
+ });
588
644
  ws.command("checkout").description("Restore a workspace in place to one of its versions.").argument("<id>").argument("<ref>", "Version id or branch to restore").action(async (id, ref) => {
589
645
  const c = buildClient4();
590
646
  await c.ensureRunning({ allowSpawn: false });
@@ -618,14 +674,14 @@ function registerWorkspaceCommands(program) {
618
674
 
619
675
  // src/main.ts
620
676
  function resolveVersion() {
621
- let dir = dirname(fileURLToPath(import.meta.url));
677
+ let dir = dirname2(fileURLToPath(import.meta.url));
622
678
  for (let i = 0; i < 6; i++) {
623
679
  try {
624
680
  const pkg = JSON.parse(readFileSync4(join(dir, "package.json"), "utf8"));
625
681
  if (pkg.name === "@struktoai/mirage-cli" && pkg.version) return pkg.version;
626
682
  } catch {
627
683
  }
628
- dir = dirname(dir);
684
+ dir = dirname2(dir);
629
685
  }
630
686
  return "0.0.0";
631
687
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/mirage.ts","../../src/main.ts","../../src/config.ts","../../src/daemon.ts","../../src/execute.ts","../../src/job.ts","../../src/mcp.ts","../../src/provision.ts","../../src/session.ts","../../src/workspace.ts"],"sourcesContent":["#!/usr/bin/env node\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\nimport { DaemonConfigError } from '@struktoai/mirage-server'\nimport { buildProgram } from '../main.ts'\n\nconst ALIASES: Record<string, string> = {\n '--workspace_id': '--workspace',\n '--session_id': '--session',\n}\n\nfunction rewriteArgv(argv: string[]): string[] {\n return argv.map((arg) => {\n for (const [from, to] of Object.entries(ALIASES)) {\n if (arg === from) return to\n if (arg.startsWith(from + '=')) return to + arg.slice(from.length)\n }\n return arg\n })\n}\n\nbuildProgram()\n .parseAsync(rewriteArgv(process.argv))\n .catch((err: unknown) => {\n if (err instanceof DaemonConfigError) {\n console.error(err.message)\n process.exit(2)\n }\n console.error(err)\n process.exit(1)\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\nimport { readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { Command } from 'commander'\nimport { registerConfigCommands } from './config.ts'\nimport { registerDaemonCommands } from './daemon.ts'\nimport { registerExecuteCommand } from './execute.ts'\nimport { registerJobCommands } from './job.ts'\nimport { registerMcpCommand } from './mcp.ts'\nimport { registerProvisionCommand } from './provision.ts'\nimport { registerSessionCommands } from './session.ts'\nimport { registerWorkspaceCommands } from './workspace.ts'\n\nfunction resolveVersion(): string {\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 6; i++) {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as {\n name?: string\n version?: string\n }\n if (pkg.name === '@struktoai/mirage-cli' && pkg.version) return pkg.version\n } catch {\n // package.json absent at this level: keep walking up to the package root\n }\n dir = dirname(dir)\n }\n return '0.0.0'\n}\n\nexport function buildProgram(): Command {\n const program = new Command()\n program\n .name('mirage')\n .description('Mirage daemon CLI: manage workspaces and execute commands.')\n .version(resolveVersion())\n registerWorkspaceCommands(program)\n registerSessionCommands(program)\n registerJobCommands(program)\n registerExecuteCommand(program)\n registerMcpCommand(program)\n registerProvisionCommand(program)\n registerDaemonCommands(program)\n registerConfigCommands(program)\n return program\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\nimport { compareCodePoints } from '@struktoai/mirage-core'\nimport { ALLOWED_KEYS, DaemonConfigError } from '@struktoai/mirage-server'\nimport type { Command } from 'commander'\nimport { emit, fail } from './output.ts'\nimport { getConfig, listConfig, resolvedConfig, setConfig, unsetConfig } from './settings.ts'\n\nfunction mask(key: string, value: string): string {\n if (key === 'auth_token' && value !== '') return '***'\n return value\n}\n\ninterface ResolvedEntry {\n value: string\n origin: string\n}\n\nfunction humanTable(table: Record<string, string>): string {\n return Object.entries(table)\n .map(([k, v]) => `${k} = ${v}`)\n .join('\\n')\n}\n\nfunction humanResolved(table: Record<string, ResolvedEntry>): string {\n return Object.entries(table)\n .map(([k, e]) => `${k} = ${e.value} (${e.origin})`)\n .join('\\n')\n}\n\nfunction listResolved(): void {\n let resolved: Record<string, [string, string]>\n try {\n resolved = resolvedConfig()\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n const payload: Record<string, ResolvedEntry> = {}\n for (const [key, [value, origin]] of Object.entries(resolved)) {\n payload[key] = { value: mask(key, value), origin }\n }\n emit(payload, humanResolved)\n}\n\nfunction listFile(): void {\n let table: Record<string, string>\n try {\n table = listConfig()\n } catch (e) {\n if (!(e instanceof DaemonConfigError)) throw e\n fail(e.message, 2)\n return\n }\n const unknown = Object.keys(table)\n .filter((k) => !ALLOWED_KEYS.has(k))\n .sort(compareCodePoints)\n if (unknown.length > 0) {\n process.stderr.write(\n 'warning: unknown [daemon] keys (daemon will refuse to ' + `start): ${unknown.join(', ')}\\n`,\n )\n }\n emit(table, humanTable)\n}\n\nexport function registerConfigCommands(program: Command): void {\n const config = program\n .command('config')\n .description('Read and write daemon settings in config.toml.')\n\n config\n .command('list')\n .option('--resolved', 'show effective values and their origins')\n .description('Print the config.toml [daemon] table.')\n .action((opts: { resolved?: boolean }) => {\n if (opts.resolved === true) listResolved()\n else listFile()\n })\n\n config\n .command('get')\n .argument('<key>')\n .description('Print one [daemon] key.')\n .action((key: string) => {\n let value: string | undefined\n try {\n value = getConfig(key)\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n if (value === undefined) {\n fail(`${key} is not set`, 1)\n return\n }\n emit({ [key]: value }, () => value)\n })\n\n config\n .command('set')\n .argument('<key>')\n .argument('<value>')\n .description('Write a [daemon] key (path settings apply on next daemon restart).')\n .action((key: string, value: string) => {\n try {\n setConfig(key, value)\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n emit({ [key]: value, written: true }, () => `${key} = ${value}`)\n })\n\n config\n .command('unset')\n .argument('<key>')\n .description('Remove a [daemon] key.')\n .action((key: string) => {\n try {\n unsetConfig(key)\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n emit({ [key]: null, unset: true }, () => `unset ${key}`)\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\nimport { existsSync, readFileSync } from 'node:fs'\nimport { pidFilePath } from '@struktoai/mirage-server'\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, fail, formatAge } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\ninterface DaemonStatus {\n running: boolean\n pid: number | null\n url: string\n uptimeS?: number\n workspaces?: number\n}\n\nfunction formatStatus(d: DaemonStatus): string {\n if (!d.running) return `Daemon not running. URL: ${d.url}`\n const parts: string[] = [`Running. PID ${d.pid !== null ? String(d.pid) : '?'}`]\n if (d.uptimeS !== undefined) {\n parts.push(`uptime ${formatAge(Date.now() / 1000 - d.uptimeS)}`)\n }\n if (d.workspaces !== undefined) {\n parts.push(`${String(d.workspaces)} workspace${d.workspaces === 1 ? '' : 's'}`)\n }\n return parts.join(', ') + `. URL: ${d.url}`\n}\n\nfunction formatStop(d: { via?: string; pid?: number }): string {\n const via = d.via ?? '?'\n return `Stopped (via ${via}${d.pid !== undefined ? `, PID ${String(d.pid)}` : ''}).`\n}\n\nfunction formatRestart(d: { spawnedFresh?: boolean }): string {\n if (d.spawnedFresh === true) return 'Restarted (eager spawn).'\n return 'Restarted; next CLI command will auto-spawn.'\n}\n\nfunction formatKill(d: { killed: boolean; pid?: number | null }): string {\n if (d.killed) return `Killed PID ${String(d.pid ?? '?')}.`\n if (d.pid === null || d.pid === undefined) return 'Daemon not running.'\n return `Already gone (PID ${String(d.pid)}).`\n}\n\nfunction readPid(): number | null {\n const p = pidFilePath()\n if (!existsSync(p)) return null\n const text = readFileSync(p, 'utf-8').trim()\n const pid = Number(text)\n return Number.isFinite(pid) && pid > 0 ? pid : null\n}\n\nfunction processAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ESRCH') return false\n if (code === 'EPERM') return true\n return false\n }\n}\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nasync function waitForUnreachable(timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n const c = buildClient()\n if (!(await c.isReachable(300))) return true\n await new Promise((r) => setTimeout(r, 200))\n }\n return false\n}\n\nexport function registerDaemonCommands(program: Command): void {\n const d = program.command('daemon').description('Manage the daemon process lifecycle.')\n\n d.command('status')\n .description('Show daemon health, PID, uptime, workspace count.')\n .action(async () => {\n const pid = readPid()\n const c = buildClient()\n const url = c.settings.url\n try {\n const r = await c.request('GET', '/v1/health')\n if (r.status !== 200) {\n emit({ running: false, pid, url } as DaemonStatus, formatStatus)\n process.exit(1)\n }\n const body = (await r.json()) as Record<string, unknown>\n emit({ running: true, pid, url, ...body } as DaemonStatus, formatStatus)\n } catch {\n emit({ running: false, pid, url } as DaemonStatus, formatStatus)\n process.exit(1)\n }\n })\n\n d.command('stop')\n .description('Gracefully stop the daemon.')\n .option('--timeout <s>', 'Seconds to wait for graceful exit', '5')\n .action(async (opts: { timeout: string }) => {\n const timeoutMs = Number(opts.timeout) * 1000\n const c = buildClient()\n let r: Response\n try {\n r = await c.request('POST', '/v1/shutdown')\n } catch (err: unknown) {\n fail(`daemon not reachable: ${String(err)}`)\n }\n if (r.status >= 400) fail(`shutdown failed: ${await r.text()}`, 2)\n if (await waitForUnreachable(timeoutMs)) {\n emit({ stopped: true, via: 'graceful' }, formatStop)\n return\n }\n const pid = readPid()\n if (pid !== null && processAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM')\n emit({ stopped: true, via: 'sigterm', pid }, formatStop)\n return\n } catch {\n // fall through to fail\n }\n }\n fail(`daemon did not exit within ${opts.timeout}s and no live PID found`, 2)\n })\n\n d.command('restart')\n .description('Stop the daemon. Next CLI command auto-spawns a fresh one.')\n .option('--timeout <s>', 'Seconds to wait for graceful exit', '5')\n .option('--eager', 'Spawn a fresh daemon immediately')\n .action(async (opts: { timeout: string; eager?: boolean }) => {\n const timeoutMs = Number(opts.timeout) * 1000\n try {\n await buildClient().request('POST', '/v1/shutdown')\n } catch {\n // already unreachable; fall through to pid cleanup\n }\n if (!(await waitForUnreachable(timeoutMs))) {\n const pid = readPid()\n if (pid !== null && processAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM')\n } catch {\n // process may have exited between checks\n }\n }\n }\n if (opts.eager === true) {\n await buildClient().ensureRunning({ allowSpawn: true })\n emit({ restarted: true, spawnedFresh: true }, formatRestart)\n return\n }\n emit(\n {\n restarted: true,\n spawnedFresh: false,\n note: 'next workspace create will auto-spawn',\n },\n formatRestart,\n )\n })\n\n d.command('kill')\n .description('SIGKILL the daemon. Last resort -- skips graceful shutdown.')\n .action(() => {\n const pid = readPid()\n if (pid === null) {\n emit({ killed: false, reason: 'no daemon running', pid: null }, formatKill)\n return\n }\n if (!processAlive(pid)) {\n emit({ killed: false, reason: 'process already gone', pid }, formatKill)\n return\n }\n try {\n process.kill(pid, 'SIGKILL')\n } catch {\n emit({ killed: false, reason: 'process gone', pid }, formatKill)\n return\n }\n emit({ killed: true, pid }, formatKill)\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\nimport { readFileSync } from 'node:fs'\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, exitCodeFromResponse, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nexport function registerExecuteCommand(program: Command): void {\n program\n .command('execute')\n .description('Execute a command.')\n .requiredOption('-w, --workspace <id>', 'Workspace id')\n .requiredOption('-c, --command <command>', 'Shell command to execute')\n .option('-s, --session <id>', 'Session id')\n .option('--cwd <path>', 'Working directory for this line (a workspace path)')\n .option('--runtime <name>', \"Workspace runtime entry to place this line's captured stages on\")\n .option('--bg', 'Background; return job_id immediately')\n .action(\n async (opts: {\n workspace: string\n command: string\n session?: string\n cwd?: string\n runtime?: string\n bg?: boolean\n }) => {\n const body: Record<string, unknown> = { command: opts.command, provision: false }\n if (opts.session !== undefined) body.sessionId = opts.session\n if (opts.cwd !== undefined) body.cwd = opts.cwd\n if (opts.runtime !== undefined) body.runtime = opts.runtime\n if (opts.bg !== true && !process.stdin.isTTY) {\n body.stdinBase64 = readFileSync(0).toString('base64')\n }\n const path =\n `/v1/workspaces/${opts.workspace}/execute` + (opts.bg === true ? '?background=true' : '')\n const c = makeClient(loadDaemonSettings())\n await c.ensureRunning({ allowSpawn: false })\n const response = await handleResponse(\n await c.request('POST', path, { body: JSON.stringify(body) }),\n )\n emit(response)\n process.exit(exitCodeFromResponse(response))\n },\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\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, exitCodeFromResponse, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nexport function registerJobCommands(program: Command): void {\n const job = program.command('job').description('Manage daemon jobs.')\n\n job\n .command('list')\n .option('-w, --workspace <id>')\n .action(async (opts: { workspace?: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const path =\n '/v1/jobs' + (opts.workspace !== undefined ? `?workspaceId=${opts.workspace}` : '')\n emit(await handleResponse(await c.request('GET', path)))\n })\n\n job\n .command('get')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const response = await handleResponse(await c.request('GET', `/v1/jobs/${id}`))\n emit(response)\n process.exit(exitCodeFromResponse(response))\n })\n\n job\n .command('wait')\n .argument('<id>')\n .option('--timeout <s>')\n .action(async (id: string, opts: { timeout?: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const body: Record<string, unknown> = {}\n if (opts.timeout !== undefined) body.timeoutS = Number(opts.timeout)\n const response = await handleResponse(\n await c.request('POST', `/v1/jobs/${id}/wait`, { body: JSON.stringify(body) }),\n )\n emit(response)\n process.exit(exitCodeFromResponse(response))\n })\n\n job\n .command('cancel')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(await handleResponse(await c.request('DELETE', `/v1/jobs/${id}`)))\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\nimport { serveMirageMcp } from '@struktoai/mirage-agents/mcp'\nimport type { Workspace } from '@struktoai/mirage-node'\nimport { buildWorkspaceFromConfig, resolveWorkspaceConfig } from '@struktoai/mirage-server'\nimport type { Command } from 'commander'\n\nexport interface McpConfigResolutionOptions {\n cwd?: string\n env?: Record<string, string | undefined>\n}\n\ninterface McpCommandOptions {\n staleWriteProtection: boolean\n}\n\nexport function resolveMcpConfig(\n config: string | undefined,\n options: McpConfigResolutionOptions = {},\n): string {\n return resolveWorkspaceConfig(config, {\n ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),\n ...(options.env !== undefined ? { env: options.env } : {}),\n envNames: ['MIRAGE_MCP_CONFIG', 'MIRAGE_CONFIG'],\n })\n}\n\nexport async function buildMcpWorkspace(configPath: string): Promise<Workspace> {\n return buildWorkspaceFromConfig(configPath)\n}\n\nasync function runMcpServer(config: string | undefined, options: McpCommandOptions): Promise<void> {\n const configPath = resolveMcpConfig(config)\n const workspace = await buildMcpWorkspace(configPath)\n try {\n await serveMirageMcp(workspace, {\n staleWriteProtection: options.staleWriteProtection,\n })\n } catch (error) {\n await workspace.close()\n throw error\n }\n}\n\nexport function registerMcpCommand(program: Command): void {\n program\n .command('mcp')\n .argument('[config]', 'Mirage workspace YAML config')\n .option('--no-stale-write-protection', 'allow edits after a file changed since it was read')\n .description('Serve a Mirage workspace as MCP tools over stdio.')\n .action(runMcpServer)\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\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nexport function registerProvisionCommand(program: Command): void {\n program\n .command('provision')\n .description('Estimate cost / preview a command without running it.')\n .requiredOption('-w, --workspace <id>', 'Workspace id')\n .requiredOption('-c, --command <command>', 'Shell command to estimate')\n .option('-s, --session <id>', 'Session id')\n .action(async (opts: { workspace: string; command: string; session?: string }) => {\n const body: Record<string, unknown> = { command: opts.command, provision: true }\n if (opts.session !== undefined) body.sessionId = opts.session\n const c = makeClient(loadDaemonSettings())\n await c.ensureRunning({ allowSpawn: false })\n emit(\n await handleResponse(\n await c.request('POST', `/v1/workspaces/${opts.workspace}/execute`, {\n body: JSON.stringify(body),\n }),\n ),\n )\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\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nconst MODES = new Set(['read', 'write', 'exec', 'r', 'rw', 'rwx'])\n\n/**\n * Parse `-m` values like `/data:read` into a modes mapping. Modes are\n * the words ('read', 'write', 'exec') or their cumulative filesystem\n * aliases ('r', 'rw', 'rwx'). A bare prefix (no mode suffix) keeps\n * the mount's own configured mode. The mode is taken from the last\n * `:` so mount prefixes that contain colons still parse.\n */\nexport function parseMountModes(mounts: string[]): Record<string, string> {\n const modes: Record<string, string> = {}\n for (const item of mounts) {\n const idx = item.lastIndexOf(':')\n const mode = idx >= 0 ? item.slice(idx + 1) : ''\n if (idx >= 0 && MODES.has(mode)) {\n modes[item.slice(0, idx)] = mode\n } else {\n modes[item] = 'exec'\n }\n }\n return modes\n}\n\nexport function registerSessionCommands(program: Command): void {\n const sess = program.command('session').description('Manage workspace sessions.')\n\n sess\n .command('create')\n .argument('<wsId>')\n .option('--id <sessionId>')\n .option(\n '-m, --mount <prefix>',\n \"restrict session to a mount, optionally capping its mode: '/data:read' \" +\n \"(alias '/data:r'), '/scratch:rw', '/bin:rwx', or a bare '/data' to keep \" +\n \"the mount's own mode; repeatable\",\n (value: string, prev: string[]) => prev.concat([value]),\n [] as string[],\n )\n .action(async (wsId: string, opts: { id?: string; mount?: string[] }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const body: Record<string, unknown> = {}\n if (opts.id !== undefined) body.sessionId = opts.id\n if (opts.mount !== undefined && opts.mount.length > 0) {\n body.mounts = parseMountModes(opts.mount)\n }\n emit(\n await handleResponse(\n await c.request('POST', `/v1/workspaces/${wsId}/sessions`, {\n body: JSON.stringify(body),\n }),\n ),\n )\n })\n\n sess\n .command('list')\n .argument('<wsId>')\n .action(async (wsId: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(await handleResponse(await c.request('GET', `/v1/workspaces/${wsId}/sessions`)))\n })\n\n sess\n .command('delete')\n .argument('<wsId>')\n .argument('<sessionId>')\n .action(async (wsId: string, sessionId: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n await handleResponse(\n await c.request('DELETE', `/v1/workspaces/${wsId}/sessions/${sessionId}`),\n ),\n )\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\nimport { existsSync, readFileSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { checkWorkspaceConfigFile, interpolateEnv } from '@struktoai/mirage-server'\nimport { parse as yamlParse } from 'yaml'\nimport { makeClient } from './client.ts'\nimport { emit, fail, formatAge, formatTable, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nfunction envRecord(): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === 'string') out[k] = v\n }\n return out\n}\n\nfunction loadConfigArgument(path: string): unknown {\n if (!existsSync(path)) fail(`config file not found: ${path}`, 2)\n const text = readFileSync(path, 'utf-8')\n try {\n return interpolateEnv(yamlParse(text), envRecord())\n } catch (err: unknown) {\n fail(`invalid config YAML/JSON at ${path}: ${String(err)}`, 2)\n }\n}\n\ninterface WorkspaceBrief {\n id: string\n mode: string\n mountCount: number\n sessionCount: number\n createdAt: number\n}\n\ninterface MountSummary {\n prefix: string\n resource: string\n mode: string\n}\n\ninterface SessionSummary {\n sessionId: string\n cwd: string\n}\n\ninterface Internals {\n cacheBytes: number | null\n cacheEntries: number | null\n historyLength: number\n inFlightJobs: number\n}\n\ninterface WorkspaceDetail {\n id: string\n mode: string\n createdAt: number\n mounts?: MountSummary[]\n sessions?: SessionSummary[]\n internals?: Internals | null\n}\n\nfunction formatWorkspaceList(items: WorkspaceBrief[]): string {\n if (items.length === 0) return 'No active workspaces.'\n const rows = items.map((w) => [\n w.id,\n w.mode,\n String(w.mountCount),\n String(w.sessionCount),\n formatAge(w.createdAt),\n ])\n return formatTable(['ID', 'MODE', 'MOUNTS', 'SESSIONS', 'AGE'], rows)\n}\n\nfunction formatWorkspaceDetail(d: WorkspaceDetail): string {\n const lines: string[] = [\n `ID: ${d.id}`,\n `Mode: ${d.mode}`,\n `Created: ${formatAge(d.createdAt)} ago`,\n ]\n if (d.mounts !== undefined && d.mounts.length > 0) {\n const rows = d.mounts.map((m) => [m.prefix, m.resource, m.mode])\n lines.push('', 'Mounts:')\n for (const ln of formatTable(['PREFIX', 'RESOURCE', 'MODE'], rows).split('\\n')) {\n lines.push(' ' + ln)\n }\n }\n if (d.sessions !== undefined && d.sessions.length > 0) {\n const rows = d.sessions.map((s) => [s.sessionId, s.cwd])\n lines.push('', 'Sessions:')\n for (const ln of formatTable(['SESSION', 'CWD'], rows).split('\\n')) {\n lines.push(' ' + ln)\n }\n }\n if (d.internals != null) {\n lines.push('', 'Internals:')\n for (const k of ['cacheBytes', 'cacheEntries', 'historyLength', 'inFlightJobs'] as const) {\n const value = d.internals[k]\n lines.push(` ${k.padEnd(16)} ${value === null ? 'n/a (not tracked)' : String(value)}`)\n }\n }\n return lines.join('\\n')\n}\n\ninterface VersionLogItem {\n id: string\n message: string\n}\n\ninterface DiffResult {\n added: string[]\n modified: string[]\n deleted: string[]\n}\n\nfunction formatVersionLog(items: VersionLogItem[]): string {\n if (items.length === 0) return 'No versions.'\n return formatTable(\n ['VERSION', 'MESSAGE'],\n items.map((v) => [v.id.slice(0, 12), v.message]),\n )\n}\n\nfunction formatDiff(changes: DiffResult): string {\n const lines: string[] = []\n for (const kind of ['added', 'modified', 'deleted'] as const) {\n for (const path of changes[kind]) lines.push(`${kind.padEnd(9)} ${path}`)\n }\n return lines.length > 0 ? lines.join('\\n') : 'No changes.'\n}\n\nexport function registerWorkspaceCommands(program: Command): void {\n const ws = program.command('workspace').description('Manage workspaces.')\n\n ws.command('create')\n .description('Create a workspace; daemon auto-spawns if not running.')\n .argument('<config>', 'YAML/JSON workspace config')\n .option('--id <id>', 'Explicit workspace id')\n .action(async (configPath: string, opts: { id?: string }) => {\n // Checked and env-interpolated here (the user's shell env is the\n // source of truth, and a missing var must fail before the round\n // trip), but sent in the file's own spelling: the daemon runs the\n // same check, and it speaks snake_case like the Python one.\n const cfg = checkWorkspaceConfigFile(configPath)\n const body: { config: unknown; id?: string } = { config: cfg }\n if (opts.id !== undefined) body.id = opts.id\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: true })\n const r = await c.request('POST', '/v1/workspaces', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('list')\n .description('List active workspaces.')\n .action(async () => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n (await handleResponse(await c.request('GET', '/v1/workspaces'))) as WorkspaceBrief[],\n formatWorkspaceList,\n )\n })\n\n ws.command('get')\n .description('Show full details for one workspace.')\n .argument('<id>')\n .option('--verbose', 'Include cache/dirty/history internals')\n .action(async (id: string, opts: { verbose?: boolean }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const path = `/v1/workspaces/${id}` + (opts.verbose === true ? '?verbose=true' : '')\n emit(\n (await handleResponse(await c.request('GET', path))) as WorkspaceDetail,\n formatWorkspaceDetail,\n )\n })\n\n ws.command('delete')\n .description('Stop and remove a workspace.')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n (await handleResponse(await c.request('DELETE', `/v1/workspaces/${id}`))) as {\n id: string\n },\n (d) => `Deleted workspace ${d.id}.`,\n )\n })\n\n ws.command('clone')\n .description('Clone a workspace, optionally from one of its past versions.')\n .argument('<srcId>')\n .option('--id <id>', 'Explicit id for the clone')\n .option('--at <ref>', 'Clone from a past version (id or branch) not the live state')\n .action(async (srcId: string, opts: { id?: string; at?: string }) => {\n const body: Record<string, unknown> = { sourceId: srcId }\n if (opts.id !== undefined) body.id = opts.id\n if (opts.at !== undefined) body.at = opts.at\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', '/v1/workspaces/clone', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('commit')\n .description(\"Commit the workspace's current state as a version.\")\n .argument('<id>')\n .option('-m, --message <msg>', 'Version message', '')\n .option('-b, --branch <branch>', 'Branch to commit on', 'main')\n .action(async (id: string, opts: { message: string; branch: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/commit`, {\n body: JSON.stringify({ message: opts.message, branch: opts.branch }),\n })\n emit(\n (await handleResponse(r)) as { version: string; branch: string },\n (d) => `Committed ${d.version.slice(0, 12)} on ${d.branch}.`,\n )\n })\n\n ws.command('branch')\n .description(\"Create a branch at another branch's current version.\")\n .argument('<id>')\n .argument('<name>')\n .option('--from <branch>', 'Branch to fork from', 'main')\n .action(async (id: string, name: string, opts: { from: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/branch`, {\n body: JSON.stringify({ name, fromBranch: opts.from }),\n })\n emit(\n (await handleResponse(r)) as { branch: string; version: string },\n (d) => `Created branch ${d.branch} at ${d.version.slice(0, 12)}.`,\n )\n })\n\n ws.command('log')\n .description(\"List a workspace's versions (newest first).\")\n .argument('<id>')\n .option('-b, --branch <branch>', 'Branch', 'main')\n .action(async (id: string, opts: { branch: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('GET', `/v1/workspaces/${id}/versions?branch=${opts.branch}`)\n emit((await handleResponse(r)) as VersionLogItem[], formatVersionLog)\n })\n\n ws.command('diff')\n .description('Show changed files (git-style): live vs HEAD, live vs <a>, or <a> vs <b>.')\n .argument('<id>')\n .argument('[a]', 'Base ref; omit to use live state')\n .argument('[b]', 'Compare ref; omit to use live state')\n .option('-b, --branch <branch>', 'Branch', 'main')\n .action(\n async (\n id: string,\n a: string | undefined,\n b: string | undefined,\n opts: { branch: string },\n ) => {\n const params = new URLSearchParams({ branch: opts.branch })\n if (a !== undefined) params.set('a', a)\n if (b !== undefined) params.set('b', b)\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('GET', `/v1/workspaces/${id}/diff?${params.toString()}`)\n emit((await handleResponse(r)) as DiffResult, formatDiff)\n },\n )\n\n ws.command('checkout')\n .description('Restore a workspace in place to one of its versions.')\n .argument('<id>')\n .argument('<ref>', 'Version id or branch to restore')\n .action(async (id: string, ref: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/checkout`, {\n body: JSON.stringify({ ref }),\n })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('snapshot')\n .description(\n 'Snapshot a workspace to a tar file. The path is resolved to an absolute path and the daemon writes the tar.',\n )\n .argument('<id>')\n .argument('<output>', 'Path to write the .tar to')\n .action(async (id: string, output: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/snapshot`, {\n body: JSON.stringify({ path: resolve(output) }),\n })\n const d = (await handleResponse(r)) as { id: string; path: string; size: number }\n emit(d, (x) => `Snapshot ${x.id} -> ${x.path} (${x.size.toLocaleString()} bytes).`)\n })\n\n ws.command('load')\n .description('Load a workspace from a tar file.')\n .argument('<tar>', 'Path to a .tar produced by `mirage workspace snapshot`')\n .argument('[config]', 'Workspace YAML/JSON config')\n .option('--id <id>', 'Explicit workspace id')\n .action(async (tarPath: string, configPath: string | undefined, opts: { id?: string }) => {\n if (!existsSync(tarPath)) fail(`tar file not found: ${tarPath}`, 2)\n const body: { path: string; id?: string; override?: unknown } = { path: resolve(tarPath) }\n if (opts.id !== undefined) body.id = opts.id\n if (configPath !== undefined) body.override = loadConfigArgument(configPath)\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: true })\n const r = await c.request('POST', '/v1/workspaces/load', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n}\n"],"mappings":"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","names":["DaemonConfigError","readFileSync","readFileSync","readFileSync","buildClient","buildClient","existsSync","readFileSync","buildClient","existsSync","readFileSync","readFileSync","DaemonConfigError"]}
1
+ {"version":3,"sources":["../../src/bin/mirage.ts","../../src/main.ts","../../src/config.ts","../../src/daemon.ts","../../src/execute.ts","../../src/job.ts","../../src/mcp.ts","../../src/provision.ts","../../src/session.ts","../../src/workspace.ts"],"sourcesContent":["#!/usr/bin/env node\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\nimport { DaemonConfigError } from '@struktoai/mirage-server'\nimport { buildProgram } from '../main.ts'\n\nconst ALIASES: Record<string, string> = {\n '--workspace_id': '--workspace',\n '--session_id': '--session',\n}\n\nfunction rewriteArgv(argv: string[]): string[] {\n return argv.map((arg) => {\n for (const [from, to] of Object.entries(ALIASES)) {\n if (arg === from) return to\n if (arg.startsWith(from + '=')) return to + arg.slice(from.length)\n }\n return arg\n })\n}\n\nbuildProgram()\n .parseAsync(rewriteArgv(process.argv))\n .catch((err: unknown) => {\n if (err instanceof DaemonConfigError) {\n console.error(err.message)\n process.exit(2)\n }\n console.error(err)\n process.exit(1)\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\nimport { readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { Command } from 'commander'\nimport { registerConfigCommands } from './config.ts'\nimport { registerDaemonCommands } from './daemon.ts'\nimport { registerExecuteCommand } from './execute.ts'\nimport { registerJobCommands } from './job.ts'\nimport { registerMcpCommand } from './mcp.ts'\nimport { registerProvisionCommand } from './provision.ts'\nimport { registerSessionCommands } from './session.ts'\nimport { registerWorkspaceCommands } from './workspace.ts'\n\nfunction resolveVersion(): string {\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 6; i++) {\n try {\n const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as {\n name?: string\n version?: string\n }\n if (pkg.name === '@struktoai/mirage-cli' && pkg.version) return pkg.version\n } catch {\n // package.json absent at this level: keep walking up to the package root\n }\n dir = dirname(dir)\n }\n return '0.0.0'\n}\n\nexport function buildProgram(): Command {\n const program = new Command()\n program\n .name('mirage')\n .description('Mirage daemon CLI: manage workspaces and execute commands.')\n .version(resolveVersion())\n registerWorkspaceCommands(program)\n registerSessionCommands(program)\n registerJobCommands(program)\n registerExecuteCommand(program)\n registerMcpCommand(program)\n registerProvisionCommand(program)\n registerDaemonCommands(program)\n registerConfigCommands(program)\n return program\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\nimport { compareCodePoints } from '@struktoai/mirage-core/utils/sort'\nimport { ALLOWED_KEYS, DaemonConfigError } from '@struktoai/mirage-server'\nimport type { Command } from 'commander'\nimport { emit, fail } from './output.ts'\nimport { getConfig, listConfig, resolvedConfig, setConfig, unsetConfig } from './settings.ts'\n\nfunction mask(key: string, value: string): string {\n if (key === 'auth_token' && value !== '') return '***'\n return value\n}\n\ninterface ResolvedEntry {\n value: string\n origin: string\n}\n\nfunction humanTable(table: Record<string, string>): string {\n return Object.entries(table)\n .map(([k, v]) => `${k} = ${v}`)\n .join('\\n')\n}\n\nfunction humanResolved(table: Record<string, ResolvedEntry>): string {\n return Object.entries(table)\n .map(([k, e]) => `${k} = ${e.value} (${e.origin})`)\n .join('\\n')\n}\n\nfunction listResolved(): void {\n let resolved: Record<string, [string, string]>\n try {\n resolved = resolvedConfig()\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n const payload: Record<string, ResolvedEntry> = {}\n for (const [key, [value, origin]] of Object.entries(resolved)) {\n payload[key] = { value: mask(key, value), origin }\n }\n emit(payload, humanResolved)\n}\n\nfunction listFile(): void {\n let table: Record<string, string>\n try {\n table = listConfig()\n } catch (e) {\n if (!(e instanceof DaemonConfigError)) throw e\n fail(e.message, 2)\n return\n }\n const unknown = Object.keys(table)\n .filter((k) => !ALLOWED_KEYS.has(k))\n .sort(compareCodePoints)\n if (unknown.length > 0) {\n process.stderr.write(\n 'warning: unknown [daemon] keys (daemon will refuse to ' + `start): ${unknown.join(', ')}\\n`,\n )\n }\n emit(table, humanTable)\n}\n\nexport function registerConfigCommands(program: Command): void {\n const config = program\n .command('config')\n .description('Read and write daemon settings in config.toml.')\n\n config\n .command('list')\n .option('--resolved', 'show effective values and their origins')\n .description('Print the config.toml [daemon] table.')\n .action((opts: { resolved?: boolean }) => {\n if (opts.resolved === true) listResolved()\n else listFile()\n })\n\n config\n .command('get')\n .argument('<key>')\n .description('Print one [daemon] key.')\n .action((key: string) => {\n let value: string | undefined\n try {\n value = getConfig(key)\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n if (value === undefined) {\n fail(`${key} is not set`, 1)\n return\n }\n emit({ [key]: value }, () => value)\n })\n\n config\n .command('set')\n .argument('<key>')\n .argument('<value>')\n .description('Write a [daemon] key (path settings apply on next daemon restart).')\n .action((key: string, value: string) => {\n try {\n setConfig(key, value)\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n emit({ [key]: value, written: true }, () => `${key} = ${value}`)\n })\n\n config\n .command('unset')\n .argument('<key>')\n .description('Remove a [daemon] key.')\n .action((key: string) => {\n try {\n unsetConfig(key)\n } catch (e) {\n fail((e as Error).message, 2)\n return\n }\n emit({ [key]: null, unset: true }, () => `unset ${key}`)\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\nimport { existsSync, readFileSync } from 'node:fs'\nimport { pidFilePath } from '@struktoai/mirage-server'\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, fail, formatAge } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\ninterface DaemonStatus {\n running: boolean\n pid: number | null\n url: string\n uptimeS?: number\n workspaces?: number\n}\n\nfunction formatStatus(d: DaemonStatus): string {\n if (!d.running) return `Daemon not running. URL: ${d.url}`\n const parts: string[] = [`Running. PID ${d.pid !== null ? String(d.pid) : '?'}`]\n if (d.uptimeS !== undefined) {\n parts.push(`uptime ${formatAge(Date.now() / 1000 - d.uptimeS)}`)\n }\n if (d.workspaces !== undefined) {\n parts.push(`${String(d.workspaces)} workspace${d.workspaces === 1 ? '' : 's'}`)\n }\n return parts.join(', ') + `. URL: ${d.url}`\n}\n\nfunction formatStop(d: { via?: string; pid?: number }): string {\n const via = d.via ?? '?'\n return `Stopped (via ${via}${d.pid !== undefined ? `, PID ${String(d.pid)}` : ''}).`\n}\n\nfunction formatRestart(d: { spawnedFresh?: boolean }): string {\n if (d.spawnedFresh === true) return 'Restarted (eager spawn).'\n return 'Restarted; next CLI command will auto-spawn.'\n}\n\nfunction formatKill(d: { killed: boolean; pid?: number | null }): string {\n if (d.killed) return `Killed PID ${String(d.pid ?? '?')}.`\n if (d.pid === null || d.pid === undefined) return 'Daemon not running.'\n return `Already gone (PID ${String(d.pid)}).`\n}\n\nfunction readPid(): number | null {\n const p = pidFilePath()\n if (!existsSync(p)) return null\n const text = readFileSync(p, 'utf-8').trim()\n const pid = Number(text)\n return Number.isFinite(pid) && pid > 0 ? pid : null\n}\n\nfunction processAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (err: unknown) {\n const code = (err as NodeJS.ErrnoException).code\n if (code === 'ESRCH') return false\n if (code === 'EPERM') return true\n return false\n }\n}\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nasync function waitForUnreachable(timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n const c = buildClient()\n if (!(await c.isReachable(300))) return true\n await new Promise((r) => setTimeout(r, 200))\n }\n return false\n}\n\nexport function registerDaemonCommands(program: Command): void {\n const d = program.command('daemon').description('Manage the daemon process lifecycle.')\n\n d.command('status')\n .description('Show daemon health, PID, uptime, workspace count.')\n .action(async () => {\n const pid = readPid()\n const c = buildClient()\n const url = c.settings.url\n try {\n const r = await c.request('GET', '/v1/health')\n if (r.status !== 200) {\n emit({ running: false, pid, url } as DaemonStatus, formatStatus)\n process.exit(1)\n }\n const body = (await r.json()) as Record<string, unknown>\n emit({ running: true, pid, url, ...body } as DaemonStatus, formatStatus)\n } catch {\n emit({ running: false, pid, url } as DaemonStatus, formatStatus)\n process.exit(1)\n }\n })\n\n d.command('stop')\n .description('Gracefully stop the daemon.')\n .option('--timeout <s>', 'Seconds to wait for graceful exit', '5')\n .action(async (opts: { timeout: string }) => {\n const timeoutMs = Number(opts.timeout) * 1000\n const c = buildClient()\n let r: Response\n try {\n r = await c.request('POST', '/v1/shutdown')\n } catch (err: unknown) {\n fail(`daemon not reachable: ${String(err)}`)\n }\n if (r.status >= 400) fail(`shutdown failed: ${await r.text()}`, 2)\n if (await waitForUnreachable(timeoutMs)) {\n emit({ stopped: true, via: 'graceful' }, formatStop)\n return\n }\n const pid = readPid()\n if (pid !== null && processAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM')\n emit({ stopped: true, via: 'sigterm', pid }, formatStop)\n return\n } catch {\n // fall through to fail\n }\n }\n fail(`daemon did not exit within ${opts.timeout}s and no live PID found`, 2)\n })\n\n d.command('restart')\n .description('Stop the daemon. Next CLI command auto-spawns a fresh one.')\n .option('--timeout <s>', 'Seconds to wait for graceful exit', '5')\n .option('--eager', 'Spawn a fresh daemon immediately')\n .action(async (opts: { timeout: string; eager?: boolean }) => {\n const timeoutMs = Number(opts.timeout) * 1000\n try {\n await buildClient().request('POST', '/v1/shutdown')\n } catch {\n // already unreachable; fall through to pid cleanup\n }\n if (!(await waitForUnreachable(timeoutMs))) {\n const pid = readPid()\n if (pid !== null && processAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM')\n } catch {\n // process may have exited between checks\n }\n }\n }\n if (opts.eager === true) {\n await buildClient().ensureRunning({ allowSpawn: true })\n emit({ restarted: true, spawnedFresh: true }, formatRestart)\n return\n }\n emit(\n {\n restarted: true,\n spawnedFresh: false,\n note: 'next workspace create will auto-spawn',\n },\n formatRestart,\n )\n })\n\n d.command('kill')\n .description('SIGKILL the daemon. Last resort -- skips graceful shutdown.')\n .action(() => {\n const pid = readPid()\n if (pid === null) {\n emit({ killed: false, reason: 'no daemon running', pid: null }, formatKill)\n return\n }\n if (!processAlive(pid)) {\n emit({ killed: false, reason: 'process already gone', pid }, formatKill)\n return\n }\n try {\n process.kill(pid, 'SIGKILL')\n } catch {\n emit({ killed: false, reason: 'process gone', pid }, formatKill)\n return\n }\n emit({ killed: true, pid }, formatKill)\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\nimport { readFileSync } from 'node:fs'\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, exitCodeFromResponse, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nexport function registerExecuteCommand(program: Command): void {\n program\n .command('execute')\n .description('Execute a command.')\n .requiredOption('-w, --workspace <id>', 'Workspace id')\n .requiredOption('-c, --command <command>', 'Shell command to execute')\n .option('-s, --session <id>', 'Session id')\n .option('--cwd <path>', 'Working directory for this line (a workspace path)')\n .option('--runtime <name>', \"Workspace runtime entry to place this line's captured stages on\")\n .option('--bg', 'Background; return job_id immediately')\n .action(\n async (opts: {\n workspace: string\n command: string\n session?: string\n cwd?: string\n runtime?: string\n bg?: boolean\n }) => {\n const body: Record<string, unknown> = { command: opts.command, provision: false }\n if (opts.session !== undefined) body.sessionId = opts.session\n if (opts.cwd !== undefined) body.cwd = opts.cwd\n if (opts.runtime !== undefined) body.runtime = opts.runtime\n if (opts.bg !== true && !process.stdin.isTTY) {\n body.stdinBase64 = readFileSync(0).toString('base64')\n }\n const path =\n `/v1/workspaces/${opts.workspace}/execute` + (opts.bg === true ? '?background=true' : '')\n const c = makeClient(loadDaemonSettings())\n await c.ensureRunning({ allowSpawn: false })\n const response = await handleResponse(\n await c.request('POST', path, { body: JSON.stringify(body) }),\n )\n emit(response)\n process.exit(exitCodeFromResponse(response))\n },\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\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, exitCodeFromResponse, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nexport function registerJobCommands(program: Command): void {\n const job = program.command('job').description('Manage daemon jobs.')\n\n job\n .command('list')\n .option('-w, --workspace <id>')\n .action(async (opts: { workspace?: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const path =\n '/v1/jobs' + (opts.workspace !== undefined ? `?workspaceId=${opts.workspace}` : '')\n emit(await handleResponse(await c.request('GET', path)))\n })\n\n job\n .command('get')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const response = await handleResponse(await c.request('GET', `/v1/jobs/${id}`))\n emit(response)\n process.exit(exitCodeFromResponse(response))\n })\n\n job\n .command('wait')\n .argument('<id>')\n .option('--timeout <s>')\n .action(async (id: string, opts: { timeout?: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const body: Record<string, unknown> = {}\n if (opts.timeout !== undefined) body.timeoutS = Number(opts.timeout)\n const response = await handleResponse(\n await c.request('POST', `/v1/jobs/${id}/wait`, { body: JSON.stringify(body) }),\n )\n emit(response)\n process.exit(exitCodeFromResponse(response))\n })\n\n job\n .command('cancel')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(await handleResponse(await c.request('DELETE', `/v1/jobs/${id}`)))\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\nimport { serveMirageMcp } from '@struktoai/mirage-agents/mcp'\nimport type { Workspace } from '@struktoai/mirage-node'\nimport { buildWorkspaceFromConfig, resolveWorkspaceConfig } from '@struktoai/mirage-server'\nimport type { Command } from 'commander'\n\nexport interface McpConfigResolutionOptions {\n cwd?: string\n env?: Record<string, string | undefined>\n}\n\ninterface McpCommandOptions {\n staleWriteProtection: boolean\n}\n\nexport function resolveMcpConfig(\n config: string | undefined,\n options: McpConfigResolutionOptions = {},\n): string {\n return resolveWorkspaceConfig(config, {\n ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),\n ...(options.env !== undefined ? { env: options.env } : {}),\n envNames: ['MIRAGE_MCP_CONFIG', 'MIRAGE_CONFIG'],\n })\n}\n\nexport async function buildMcpWorkspace(configPath: string): Promise<Workspace> {\n return buildWorkspaceFromConfig(configPath)\n}\n\nasync function runMcpServer(config: string | undefined, options: McpCommandOptions): Promise<void> {\n const configPath = resolveMcpConfig(config)\n const workspace = await buildMcpWorkspace(configPath)\n try {\n await serveMirageMcp(workspace, {\n staleWriteProtection: options.staleWriteProtection,\n })\n } catch (error) {\n await workspace.close()\n throw error\n }\n}\n\nexport function registerMcpCommand(program: Command): void {\n program\n .command('mcp')\n .argument('[config]', 'Mirage workspace YAML config')\n .option('--no-stale-write-protection', 'allow edits after a file changed since it was read')\n .description('Serve a Mirage workspace as MCP tools over stdio.')\n .action(runMcpServer)\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\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nexport function registerProvisionCommand(program: Command): void {\n program\n .command('provision')\n .description('Estimate cost / preview a command without running it.')\n .requiredOption('-w, --workspace <id>', 'Workspace id')\n .requiredOption('-c, --command <command>', 'Shell command to estimate')\n .option('-s, --session <id>', 'Session id')\n .action(async (opts: { workspace: string; command: string; session?: string }) => {\n const body: Record<string, unknown> = { command: opts.command, provision: true }\n if (opts.session !== undefined) body.sessionId = opts.session\n const c = makeClient(loadDaemonSettings())\n await c.ensureRunning({ allowSpawn: false })\n emit(\n await handleResponse(\n await c.request('POST', `/v1/workspaces/${opts.workspace}/execute`, {\n body: JSON.stringify(body),\n }),\n ),\n )\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\nimport type { Command } from 'commander'\nimport { makeClient } from './client.ts'\nimport { emit, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nconst MODES = new Set(['read', 'write', 'exec', 'r', 'rw', 'rwx'])\n\n/**\n * Parse `-m` values like `/data:read` into a modes mapping. Modes are\n * the words ('read', 'write', 'exec') or their cumulative filesystem\n * aliases ('r', 'rw', 'rwx'). A bare prefix (no mode suffix) keeps\n * the mount's own configured mode. The mode is taken from the last\n * `:` so mount prefixes that contain colons still parse.\n */\nexport function parseMountModes(mounts: string[]): Record<string, string> {\n const modes: Record<string, string> = {}\n for (const item of mounts) {\n const idx = item.lastIndexOf(':')\n const mode = idx >= 0 ? item.slice(idx + 1) : ''\n if (idx >= 0 && MODES.has(mode)) {\n modes[item.slice(0, idx)] = mode\n } else {\n modes[item] = 'exec'\n }\n }\n return modes\n}\n\nexport function registerSessionCommands(program: Command): void {\n const sess = program.command('session').description('Manage workspace sessions.')\n\n sess\n .command('create')\n .argument('<wsId>')\n .option('--id <sessionId>')\n .option(\n '-m, --mount <prefix>',\n \"narrow a mount's mode for this session: '/data:read' (alias '/data:r'), \" +\n \"'/scratch:rw', '/bin:rwx', or a bare '/data' to keep the mount's own \" +\n 'mode; repeatable. This narrows only: a mount you do not name keeps its ' +\n 'own mode, and keeping a session away from one is a hide in its profile',\n (value: string, prev: string[]) => prev.concat([value]),\n [] as string[],\n )\n .option(\n '-p, --profile <name>',\n \"the profile this session runs under, by name from the workspace's profiles; \" +\n 'omit it to take the workspace default',\n )\n .action(async (wsId: string, opts: { id?: string; mount?: string[]; profile?: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const body: Record<string, unknown> = {}\n if (opts.id !== undefined) body.sessionId = opts.id\n if (opts.mount !== undefined && opts.mount.length > 0) {\n body.mounts = parseMountModes(opts.mount)\n }\n if (opts.profile !== undefined) body.profile = opts.profile\n emit(\n await handleResponse(\n await c.request('POST', `/v1/workspaces/${wsId}/sessions`, {\n body: JSON.stringify(body),\n }),\n ),\n )\n })\n\n sess\n .command('list')\n .argument('<wsId>')\n .action(async (wsId: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(await handleResponse(await c.request('GET', `/v1/workspaces/${wsId}/sessions`)))\n })\n\n sess\n .command('delete')\n .argument('<wsId>')\n .argument('<sessionId>')\n .action(async (wsId: string, sessionId: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n await handleResponse(\n await c.request('DELETE', `/v1/workspaces/${wsId}/sessions/${sessionId}`),\n ),\n )\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\nimport { existsSync, readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport {\n absolutizeScripts,\n checkWorkspaceConfigFile,\n interpolateEnv,\n} from '@struktoai/mirage-server'\nimport { parse as yamlParse } from 'yaml'\nimport { makeClient } from './client.ts'\nimport { emit, fail, formatAge, formatTable, handleResponse } from './output.ts'\nimport { loadDaemonSettings } from './settings.ts'\n\nfunction buildClient() {\n return makeClient(loadDaemonSettings())\n}\n\nfunction envRecord(): Record<string, string> {\n const out: Record<string, string> = {}\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === 'string') out[k] = v\n }\n return out\n}\n\n// A config handed to `load` or `clone`: env-interpolated, and with its\n// relative script paths and code refs rebased onto the file's directory\n// exactly as `create` rebases them, so `resource: ./wiki.mjs:WikiResource`\n// in an override means \"next to this file\", never \"wherever the daemon\n// runs\". Not validated, because an override may name only a subset of\n// mounts. Mirrors `_resolve_config_arg` in the Python CLI.\nfunction loadConfigArgument(path: string): unknown {\n if (!existsSync(path)) fail(`config file not found: ${path}`, 2)\n const text = readFileSync(path, 'utf-8')\n let config: unknown\n try {\n config = interpolateEnv(yamlParse(text), envRecord())\n } catch (err: unknown) {\n fail(`invalid config YAML/JSON at ${path}: ${String(err)}`, 2)\n }\n if (typeof config === 'object' && config !== null && !Array.isArray(config)) {\n absolutizeScripts(config as Record<string, unknown>, dirname(resolve(path)))\n }\n return config\n}\n\ninterface WorkspaceBrief {\n id: string\n mode: string\n mountCount: number\n sessionCount: number\n createdAt: number\n}\n\ninterface MountSummary {\n prefix: string\n resource: string\n mode: string\n}\n\ninterface SessionSummary {\n sessionId: string\n cwd: string\n}\n\ninterface Internals {\n cacheBytes: number | null\n cacheEntries: number | null\n historyLength: number\n inFlightJobs: number\n}\n\ninterface WorkspaceDetail {\n id: string\n mode: string\n createdAt: number\n mounts?: MountSummary[]\n sessions?: SessionSummary[]\n internals?: Internals | null\n}\n\nfunction formatWorkspaceList(items: WorkspaceBrief[]): string {\n if (items.length === 0) return 'No active workspaces.'\n const rows = items.map((w) => [\n w.id,\n w.mode,\n String(w.mountCount),\n String(w.sessionCount),\n formatAge(w.createdAt),\n ])\n return formatTable(['ID', 'MODE', 'MOUNTS', 'SESSIONS', 'AGE'], rows)\n}\n\nfunction formatWorkspaceDetail(d: WorkspaceDetail): string {\n const lines: string[] = [\n `ID: ${d.id}`,\n `Mode: ${d.mode}`,\n `Created: ${formatAge(d.createdAt)} ago`,\n ]\n if (d.mounts !== undefined && d.mounts.length > 0) {\n const rows = d.mounts.map((m) => [m.prefix, m.resource, m.mode])\n lines.push('', 'Mounts:')\n for (const ln of formatTable(['PREFIX', 'RESOURCE', 'MODE'], rows).split('\\n')) {\n lines.push(' ' + ln)\n }\n }\n if (d.sessions !== undefined && d.sessions.length > 0) {\n const rows = d.sessions.map((s) => [s.sessionId, s.cwd])\n lines.push('', 'Sessions:')\n for (const ln of formatTable(['SESSION', 'CWD'], rows).split('\\n')) {\n lines.push(' ' + ln)\n }\n }\n if (d.internals != null) {\n lines.push('', 'Internals:')\n for (const k of ['cacheBytes', 'cacheEntries', 'historyLength', 'inFlightJobs'] as const) {\n const value = d.internals[k]\n lines.push(` ${k.padEnd(16)} ${value === null ? 'n/a (not tracked)' : String(value)}`)\n }\n }\n return lines.join('\\n')\n}\n\ninterface AskRecord {\n id: string\n sessionId: string\n agentId: string\n command: string\n argv: string[]\n cwd: string\n paths: string[]\n reason: string\n outcome: string | null\n scope: string\n note: string\n}\n\nfunction formatAsks(items: AskRecord[]): string {\n if (items.length === 0) return 'No asks.'\n return formatTable(\n ['ID', 'SESSION', 'COMMAND', 'STATUS', 'REASON'],\n items.map((a) => [\n a.id,\n a.sessionId,\n [a.command, ...a.argv].join(' '),\n a.outcome ?? 'pending',\n a.reason,\n ]),\n )\n}\n\ninterface VersionLogItem {\n id: string\n message: string\n}\n\ninterface DiffResult {\n added: string[]\n modified: string[]\n deleted: string[]\n}\n\nfunction formatVersionLog(items: VersionLogItem[]): string {\n if (items.length === 0) return 'No versions.'\n return formatTable(\n ['VERSION', 'MESSAGE'],\n items.map((v) => [v.id.slice(0, 12), v.message]),\n )\n}\n\nfunction formatDiff(changes: DiffResult): string {\n const lines: string[] = []\n for (const kind of ['added', 'modified', 'deleted'] as const) {\n for (const path of changes[kind]) lines.push(`${kind.padEnd(9)} ${path}`)\n }\n return lines.length > 0 ? lines.join('\\n') : 'No changes.'\n}\n\nexport function registerWorkspaceCommands(program: Command): void {\n const ws = program.command('workspace').description('Manage workspaces.')\n\n ws.command('create')\n .description('Create a workspace; daemon auto-spawns if not running.')\n .argument('<config>', 'YAML/JSON workspace config')\n .option('--id <id>', 'Explicit workspace id')\n .action(async (configPath: string, opts: { id?: string }) => {\n // Checked and env-interpolated here (the user's shell env is the\n // source of truth, and a missing var must fail before the round\n // trip), but sent in the file's own spelling: the daemon runs the\n // same check, and it speaks snake_case like the Python one.\n const cfg = checkWorkspaceConfigFile(configPath)\n const body: { config: unknown; id?: string } = { config: cfg }\n if (opts.id !== undefined) body.id = opts.id\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: true })\n const r = await c.request('POST', '/v1/workspaces', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('list')\n .description('List active workspaces.')\n .action(async () => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n (await handleResponse(await c.request('GET', '/v1/workspaces'))) as WorkspaceBrief[],\n formatWorkspaceList,\n )\n })\n\n ws.command('get')\n .description('Show full details for one workspace.')\n .argument('<id>')\n .option('--verbose', 'Include cache/dirty/history internals')\n .action(async (id: string, opts: { verbose?: boolean }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const path = `/v1/workspaces/${id}` + (opts.verbose === true ? '?verbose=true' : '')\n emit(\n (await handleResponse(await c.request('GET', path))) as WorkspaceDetail,\n formatWorkspaceDetail,\n )\n })\n\n ws.command('delete')\n .description('Stop and remove a workspace.')\n .argument('<id>')\n .action(async (id: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n emit(\n (await handleResponse(await c.request('DELETE', `/v1/workspaces/${id}`))) as {\n id: string\n },\n (d) => `Deleted workspace ${d.id}.`,\n )\n })\n\n ws.command('clone')\n .description('Clone a workspace, optionally from one of its past versions.')\n .argument('<srcId>')\n .option('--id <id>', 'Explicit id for the clone')\n .option('--at <ref>', 'Clone from a past version (id or branch) not the live state')\n .action(async (srcId: string, opts: { id?: string; at?: string }) => {\n const body: Record<string, unknown> = { sourceId: srcId }\n if (opts.id !== undefined) body.id = opts.id\n if (opts.at !== undefined) body.at = opts.at\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', '/v1/workspaces/clone', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('commit')\n .description(\"Commit the workspace's current state as a version.\")\n .argument('<id>')\n .option('-m, --message <msg>', 'Version message', '')\n .option('-b, --branch <branch>', 'Branch to commit on', 'main')\n .action(async (id: string, opts: { message: string; branch: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/commit`, {\n body: JSON.stringify({ message: opts.message, branch: opts.branch }),\n })\n emit(\n (await handleResponse(r)) as { version: string; branch: string },\n (d) => `Committed ${d.version.slice(0, 12)} on ${d.branch}.`,\n )\n })\n\n ws.command('branch')\n .description(\"Create a branch at another branch's current version.\")\n .argument('<id>')\n .argument('<name>')\n .option('--from <branch>', 'Branch to fork from', 'main')\n .action(async (id: string, name: string, opts: { from: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/branch`, {\n body: JSON.stringify({ name, fromBranch: opts.from }),\n })\n emit(\n (await handleResponse(r)) as { branch: string; version: string },\n (d) => `Created branch ${d.branch} at ${d.version.slice(0, 12)}.`,\n )\n })\n\n ws.command('log')\n .description(\"List a workspace's versions (newest first).\")\n .argument('<id>')\n .option('-b, --branch <branch>', 'Branch', 'main')\n .action(async (id: string, opts: { branch: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('GET', `/v1/workspaces/${id}/versions?branch=${opts.branch}`)\n emit((await handleResponse(r)) as VersionLogItem[], formatVersionLog)\n })\n\n ws.command('diff')\n .description('Show changed files (git-style): live vs HEAD, live vs <a>, or <a> vs <b>.')\n .argument('<id>')\n .argument('[a]', 'Base ref; omit to use live state')\n .argument('[b]', 'Compare ref; omit to use live state')\n .option('-b, --branch <branch>', 'Branch', 'main')\n .action(\n async (\n id: string,\n a: string | undefined,\n b: string | undefined,\n opts: { branch: string },\n ) => {\n const params = new URLSearchParams({ branch: opts.branch })\n if (a !== undefined) params.set('a', a)\n if (b !== undefined) params.set('b', b)\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('GET', `/v1/workspaces/${id}/diff?${params.toString()}`)\n emit((await handleResponse(r)) as DiffResult, formatDiff)\n },\n )\n\n ws.command('list-asks')\n .description('List pending asks (every decision with --all).')\n .argument('<id>')\n .option('--session <sessionId>', \"Only this session's asks\")\n .option('--all', 'Include settled decisions, not just pending asks')\n .action(async (id: string, opts: { session?: string; all?: boolean }) => {\n const params = new URLSearchParams()\n if (opts.session !== undefined) params.set('sessionId', opts.session)\n if (opts.all === true) params.set('all', 'true')\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const qs = params.toString()\n const r = await c.request('GET', `/v1/workspaces/${id}/asks${qs === '' ? '' : `?${qs}`}`)\n emit((await handleResponse(r)) as AskRecord[], formatAsks)\n })\n\n ws.command('allow')\n .description('Allow a pending ask; the retry of the asked line passes.')\n .argument('<id>')\n .argument('<askId>', 'Ask id, as quoted in the refusal')\n .option(\n '--scope <scope>',\n 'once answers the exact line; session answers every line the rule covers',\n 'once',\n )\n .option('--note <note>', 'What to record alongside the answer', '')\n .action(async (id: string, askId: string, opts: { scope: string; note: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/asks/${askId}`, {\n body: JSON.stringify({ answer: 'allow', scope: opts.scope, note: opts.note }),\n })\n emit((await handleResponse(r)) as AskRecord, (d) => `Allowed ${d.id} (${d.scope}).`)\n })\n\n ws.command('deny')\n .description('Deny a pending ask; the retry is refused in the deny voice, once.')\n .argument('<id>')\n .argument('<askId>', 'Ask id, as quoted in the refusal')\n .option('--note <note>', 'What to record alongside the answer', '')\n .action(async (id: string, askId: string, opts: { note: string }) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/asks/${askId}`, {\n body: JSON.stringify({ answer: 'deny', note: opts.note }),\n })\n emit((await handleResponse(r)) as AskRecord, (d) => `Denied ${d.id}.`)\n })\n\n ws.command('checkout')\n .description('Restore a workspace in place to one of its versions.')\n .argument('<id>')\n .argument('<ref>', 'Version id or branch to restore')\n .action(async (id: string, ref: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/checkout`, {\n body: JSON.stringify({ ref }),\n })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n\n ws.command('snapshot')\n .description(\n 'Snapshot a workspace to a tar file. The path is resolved to an absolute path and the daemon writes the tar.',\n )\n .argument('<id>')\n .argument('<output>', 'Path to write the .tar to')\n .action(async (id: string, output: string) => {\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: false })\n const r = await c.request('POST', `/v1/workspaces/${id}/snapshot`, {\n body: JSON.stringify({ path: resolve(output) }),\n })\n const d = (await handleResponse(r)) as { id: string; path: string; size: number }\n emit(d, (x) => `Snapshot ${x.id} -> ${x.path} (${x.size.toLocaleString()} bytes).`)\n })\n\n ws.command('load')\n .description('Load a workspace from a tar file.')\n .argument('<tar>', 'Path to a .tar produced by `mirage workspace snapshot`')\n .argument('[config]', 'Workspace YAML/JSON config')\n .option('--id <id>', 'Explicit workspace id')\n .action(async (tarPath: string, configPath: string | undefined, opts: { id?: string }) => {\n if (!existsSync(tarPath)) fail(`tar file not found: ${tarPath}`, 2)\n const body: { path: string; id?: string; override?: unknown } = { path: resolve(tarPath) }\n if (opts.id !== undefined) body.id = opts.id\n if (configPath !== undefined) body.override = loadConfigArgument(configPath)\n const c = buildClient()\n await c.ensureRunning({ allowSpawn: true })\n const r = await c.request('POST', '/v1/workspaces/load', { body: JSON.stringify(body) })\n emit((await handleResponse(r)) as WorkspaceDetail, formatWorkspaceDetail)\n })\n}\n"],"mappings":"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","names":["DaemonConfigError","readFileSync","dirname","readFileSync","readFileSync","buildClient","buildClient","existsSync","readFileSync","buildClient","existsSync","readFileSync","dirname","readFileSync","DaemonConfigError"]}
@@ -163,7 +163,7 @@ function makeClient(settings) {
163
163
  // src/settings.ts
164
164
  import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
165
165
  import { dirname, join as join2 } from "path";
166
- import { compareCodePoints } from "@struktoai/mirage-core";
166
+ import { compareCodePoints } from "@struktoai/mirage-core/utils/sort";
167
167
  import {
168
168
  ALLOWED_KEYS,
169
169
  DaemonConfigError,
@@ -425,4 +425,4 @@ export {
425
425
  formatAge,
426
426
  formatTable
427
427
  };
428
- //# sourceMappingURL=chunk-PCROWRBJ.js.map
428
+ //# sourceMappingURL=chunk-BNUV7A4V.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts","../src/env.ts","../src/settings.ts","../src/output.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 { spawn } from 'node:child_process'\nimport { existsSync, mkdirSync, openSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { join } from 'node:path'\nimport {\n AuthMode,\n defaultTokenFile,\n ensureTokenFile,\n mirageHome,\n readDaemonTable,\n validateDaemonTable,\n} from '@struktoai/mirage-server'\n\nimport { ENV_AUTH_MODE, ENV_AUTH_TOKEN, ENV_DAEMON_PORT, ENV_IDLE_GRACE_SECONDS } from './env.ts'\nimport type { DaemonSettings } from './settings.ts'\n\nconst requireFromHere = createRequire(import.meta.url)\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 60_000\n\nexport class DaemonClient {\n readonly settings: DaemonSettings\n\n constructor(settings: DaemonSettings) {\n this.settings = settings\n }\n\n private headers(extra?: Record<string, string>): Record<string, string> {\n const h: Record<string, string> = { ...extra }\n if (this.settings.authToken !== '') h.Authorization = `Bearer ${this.settings.authToken}`\n return h\n }\n\n async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const { timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, ...rest } = init\n const headers: Record<string, string> = {\n ...this.headers(),\n ...((rest.headers ?? {}) as Record<string, string>),\n }\n if (rest.body !== undefined && headers['Content-Type'] === undefined) {\n headers['Content-Type'] = 'application/json'\n }\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, timeoutMs)\n try {\n return await fetch(this.settings.url + path, {\n ...rest,\n method,\n headers,\n signal: ctrl.signal,\n })\n } finally {\n clearTimeout(t)\n }\n }\n\n async requestMultipart(method: string, path: string, form: FormData): Promise<Response> {\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, DEFAULT_REQUEST_TIMEOUT_MS)\n try {\n return await fetch(this.settings.url + path, {\n method,\n headers: this.headers(),\n body: form,\n signal: ctrl.signal,\n })\n } finally {\n clearTimeout(t)\n }\n }\n\n async isReachable(timeoutMs = 500): Promise<boolean> {\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, timeoutMs)\n try {\n const r = await fetch(this.settings.url + '/v1/health', {\n headers: this.headers(),\n signal: ctrl.signal,\n })\n return r.status === 200\n } catch {\n return false\n } finally {\n clearTimeout(t)\n }\n }\n\n async ensureRunning(opts: { allowSpawn?: boolean; timeoutMs?: number } = {}): Promise<void> {\n const allowSpawn = opts.allowSpawn ?? true\n const timeoutMs = opts.timeoutMs ?? 5000\n if (await this.isReachable()) return\n if (!allowSpawn) {\n throw new Error(\n `daemon not reachable at ${this.settings.url}; run \\`mirage workspace create CONFIG.yaml\\``,\n )\n }\n this.spawnDaemon()\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n if (await this.isReachable(300)) return\n await new Promise((r) => setTimeout(r, 100))\n }\n throw new Error(`daemon spawned but did not answer /v1/health within ${String(timeoutMs)}ms`)\n }\n\n private spawnDaemon(): void {\n const table = readDaemonTable(mirageHome())\n validateDaemonTable(table)\n const env: Record<string, string> = {}\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === 'string') env[k] = v\n }\n env[ENV_DAEMON_PORT] = String(this.resolvePort(table))\n env[ENV_IDLE_GRACE_SECONDS] = String(this.settings.idleGraceSeconds)\n if (this.settings.authToken === '') {\n this.settings.authToken = ensureTokenFile(defaultTokenFile())\n }\n env[ENV_AUTH_TOKEN] = this.settings.authToken\n if ((env[ENV_AUTH_MODE] ?? '') === '' && (table.auth_mode ?? '') === '') {\n env[ENV_AUTH_MODE] = AuthMode.Local\n }\n const logDir = mirageHome()\n mkdirSync(logDir, { recursive: true })\n const out = openSync(join(logDir, 'daemon.log'), 'a')\n const daemonEntry = requireFromHere.resolve('@struktoai/mirage-server/bin/daemon')\n if (!existsSync(daemonEntry)) {\n throw new Error(\n `daemon binary not found at ${daemonEntry}; reinstall @struktoai/mirage-server`,\n )\n }\n const child = spawn(process.execPath, [daemonEntry], {\n env,\n detached: true,\n stdio: ['ignore', out, out],\n })\n child.on('error', (err) => {\n console.error('failed to spawn daemon:', err)\n })\n child.unref()\n }\n\n private resolvePort(table: Record<string, string>): number {\n const envPort = process.env[ENV_DAEMON_PORT]\n if (envPort !== undefined && envPort !== '') return Number(envPort)\n const configPort = table.port\n if (configPort !== undefined && configPort !== '') return Number(configPort)\n return this.portFromUrl()\n }\n\n private portFromUrl(): number {\n const u = new URL(this.settings.url)\n return Number(u.port) || 8765\n }\n}\n\nexport function makeClient(settings: DaemonSettings): DaemonClient {\n return new DaemonClient(settings)\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 {\n ENV_AUTH_MODE,\n ENV_AUTH_TOKEN,\n ENV_DAEMON_PORT,\n ENV_IDLE_GRACE_SECONDS,\n} from '@struktoai/mirage-server'\n\nexport const ENV_DAEMON_URL = 'MIRAGE_DAEMON_URL'\nexport const ENV_TOKEN = 'MIRAGE_TOKEN'\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\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { compareCodePoints } from '@struktoai/mirage-core/utils/sort'\nimport {\n ALLOWED_KEYS,\n DaemonConfigError,\n DEFAULT_ALLOWED_HOSTS,\n NUMERIC_KEYS,\n defaultTokenFile,\n mirageHome,\n parseDaemonTable,\n readDaemonTable,\n readTokenFile,\n} from '@struktoai/mirage-server'\n\nimport { ENV_DAEMON_URL, ENV_TOKEN } from './env.ts'\n\nexport const DEFAULT_DAEMON_URL = 'http://127.0.0.1:8765'\n\nexport interface DaemonSettings {\n url: string\n authToken: string\n idleGraceSeconds: number\n}\n\nexport interface LoadOptions {\n env?: Record<string, string | undefined>\n configPath?: string\n tokenFile?: string\n}\n\nexport function loadDaemonSettings(options: LoadOptions = {}): DaemonSettings {\n const env = options.env ?? (process.env as Record<string, string | undefined>)\n const table =\n options.configPath !== undefined\n ? existsSync(options.configPath)\n ? parseDaemonTable(readFileSync(options.configPath, 'utf-8'))\n : {}\n : readDaemonTable(mirageHome(env))\n const settings: DaemonSettings = {\n url: table.url ?? DEFAULT_DAEMON_URL,\n authToken: table.auth_token ?? '',\n idleGraceSeconds: Number(table.idle_grace_seconds ?? '30'),\n }\n const envUrl = env[ENV_DAEMON_URL]\n if (envUrl !== undefined && envUrl !== '') {\n settings.url = envUrl\n }\n const envToken = env[ENV_TOKEN]\n if (envToken !== undefined && envToken !== '') {\n settings.authToken = envToken\n }\n if (settings.authToken === '') {\n const fileToken = readTokenFile(options.tokenFile ?? defaultTokenFile(env))\n if (fileToken !== undefined && fileToken !== '') {\n settings.authToken = fileToken\n }\n }\n return settings\n}\n\nfunction defaultConfigPath(env: Record<string, string | undefined> = process.env): string {\n return join(mirageHome(env), 'config.toml')\n}\n\nconst ENV_FOR_KEY: Record<string, string> = {\n url: ENV_DAEMON_URL,\n allowed_hosts: 'MIRAGE_ALLOWED_HOSTS',\n auth_mode: 'MIRAGE_AUTH_MODE',\n jwt_alg: 'MIRAGE_JWT_ALG',\n jwt_issuer: 'MIRAGE_JWT_ISSUER',\n jwt_audience: 'MIRAGE_JWT_AUDIENCE',\n jwt_pubkey_file: 'MIRAGE_JWT_PUBKEY_FILE',\n jwt_clock_skew: 'MIRAGE_JWT_CLOCK_SKEW_SECONDS',\n jwt_authorized_parties: 'MIRAGE_JWT_AUTHORIZED_PARTIES',\n auth_token: ENV_TOKEN,\n idle_grace_seconds: 'MIRAGE_IDLE_GRACE_SECONDS',\n port: 'MIRAGE_DAEMON_PORT',\n}\n\nfunction defaultForKey(key: string): string {\n const defaults: Record<string, string> = {\n url: DEFAULT_DAEMON_URL,\n allowed_hosts: DEFAULT_ALLOWED_HOSTS.join(','),\n auth_mode: 'local',\n jwt_alg: '',\n jwt_issuer: '',\n jwt_audience: '',\n jwt_pubkey_file: '',\n jwt_clock_skew: '5',\n jwt_authorized_parties: '',\n socket: '',\n auth_token: '',\n idle_grace_seconds: '30',\n port: '8765',\n }\n return defaults[key] ?? ''\n}\n\nexport function resolvedConfig(\n env: Record<string, string | undefined> = process.env as Record<string, string | undefined>,\n): Record<string, [string, string]> {\n const home = mirageHome(env)\n const table = readDaemonTable(home)\n const out: Record<string, [string, string]> = {}\n for (const key of [...ALLOWED_KEYS].sort(compareCodePoints)) {\n const envName = ENV_FOR_KEY[key]\n if (envName !== undefined) {\n const envValue = env[envName]\n if (envValue !== undefined && envValue !== '') {\n out[key] = [envValue, `env ${envName}`]\n continue\n }\n }\n const fileValue = table[key]\n if (fileValue !== undefined && fileValue !== '') {\n out[key] = [fileValue, 'file']\n } else {\n out[key] = [defaultForKey(key), 'default']\n }\n }\n return out\n}\n\nfunction checkKey(key: string): void {\n if (!ALLOWED_KEYS.has(key)) {\n throw new DaemonConfigError(\n `unknown config key: '${key}'; allowed: ${[...ALLOWED_KEYS].sort(compareCodePoints).join(', ')}`,\n )\n }\n}\n\nfunction formatValue(key: string, value: string): string {\n if (NUMERIC_KEYS.has(key)) return value\n return `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`\n}\n\nexport function listConfig(path?: string): Record<string, string> {\n const p = path ?? defaultConfigPath(process.env as Record<string, string | undefined>)\n if (!existsSync(p)) return {}\n return parseDaemonTable(readFileSync(p, 'utf-8'))\n}\n\nexport function getConfig(key: string, path?: string): string | undefined {\n checkKey(key)\n return listConfig(path)[key]\n}\n\nexport function setConfig(key: string, value: string, path?: string): void {\n checkKey(key)\n const p = path ?? defaultConfigPath(process.env as Record<string, string | undefined>)\n const lines = existsSync(p) ? readFileSync(p, 'utf-8').split('\\n') : []\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()\n const rendered = `${key} = ${formatValue(key, value)}`\n let headerIdx = -1\n for (let i = 0; i < lines.length; i++) {\n if ((lines[i] ?? '').trim() === '[daemon]') {\n headerIdx = i\n break\n }\n }\n if (headerIdx < 0) {\n if (lines.length > 0 && (lines[lines.length - 1] ?? '').trim() !== '') lines.push('')\n lines.push('[daemon]', rendered)\n } else {\n let end = lines.length\n for (let i = headerIdx + 1; i < lines.length; i++) {\n if ((lines[i] ?? '').trim().startsWith('[')) {\n end = i\n break\n }\n }\n let replaced = false\n for (let i = headerIdx + 1; i < end; i++) {\n const t = (lines[i] ?? '').trim()\n if (t.startsWith('#') || !t.includes('=')) continue\n if (t.slice(0, t.indexOf('=')).trim() === key) {\n lines[i] = rendered\n replaced = true\n break\n }\n }\n if (!replaced) lines.splice(end, 0, rendered)\n }\n mkdirSync(dirname(p), { recursive: true })\n writeFileSync(p, lines.join('\\n') + '\\n')\n chmodSync(p, 0o600)\n}\n\nexport function unsetConfig(key: string, path?: string): void {\n const p = path ?? defaultConfigPath(process.env as Record<string, string | undefined>)\n if (!existsSync(p)) return\n const lines = readFileSync(p, 'utf-8').split('\\n')\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()\n const kept: string[] = []\n let inDaemon = false\n for (const line of lines) {\n const t = line.trim()\n if (t === '[daemon]') {\n inDaemon = true\n kept.push(line)\n continue\n }\n if (t.startsWith('[')) inDaemon = false\n if (\n inDaemon &&\n t.includes('=') &&\n !t.startsWith('#') &&\n t.slice(0, t.indexOf('=')).trim() === key\n )\n continue\n kept.push(line)\n }\n writeFileSync(p, kept.join('\\n') + '\\n')\n chmodSync(p, 0o600)\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 type Formatter<T = unknown> = (obj: T) => string\n\nexport function emit<T = unknown>(obj: T, human?: Formatter<T>): void {\n if (human !== undefined && process.stdout.isTTY) {\n process.stdout.write(human(obj) + '\\n')\n return\n }\n process.stdout.write(JSON.stringify(obj, null, 2) + '\\n')\n}\n\nexport function fail(message: string, exitCode = 1): never {\n process.stderr.write(message + '\\n')\n process.exit(exitCode)\n}\n\nexport function exitCodeFromResponse(r: unknown): number {\n if (typeof r !== 'object' || r === null) return 0\n const obj = r as Record<string, unknown>\n const inner =\n obj.kind === 'io' ? obj : ((obj.result as Record<string, unknown> | null | undefined) ?? null)\n if (\n inner !== null &&\n inner.kind === 'io' &&\n typeof inner.exitCode === 'number' &&\n Number.isFinite(inner.exitCode)\n ) {\n return Math.min(255, Math.max(0, Math.trunc(inner.exitCode)))\n }\n if (typeof obj.status === 'string' && (obj.status === 'failed' || obj.status === 'canceled')) {\n return 2\n }\n return 0\n}\n\nexport async function handleResponse(r: Response): Promise<unknown> {\n if (r.status >= 400) {\n let detail = await r.text()\n try {\n const parsed = JSON.parse(detail) as { detail?: string }\n if (parsed.detail !== undefined) detail = parsed.detail\n } catch {\n // body wasn't JSON; fall through with the raw text as detail\n }\n fail(`daemon error ${String(r.status)}: ${detail}`, 2)\n }\n if (r.status === 204) return {}\n const text = await r.text()\n if (text === '') return {}\n return JSON.parse(text) as unknown\n}\n\nexport function formatAge(epoch: number, now: number = Date.now() / 1000): string {\n const delta = Math.max(0, now - epoch)\n if (delta < 60) return `${String(Math.floor(delta))}s`\n if (delta < 3600) return `${String(Math.floor(delta / 60))}m`\n if (delta < 86400) return `${String(Math.floor(delta / 3600))}h`\n return `${String(Math.floor(delta / 86400))}d`\n}\n\nexport function formatTable(headers: string[], rows: (string | undefined)[][]): string {\n if (rows.length === 0) return headers.join(' ')\n const norm: string[][] = rows.map((row) => row.map((c) => c ?? ''))\n const widths = headers.map((h) => h.length)\n for (const row of norm) {\n for (let i = 0; i < row.length; i++) {\n widths[i] = Math.max(widths[i] ?? 0, row[i]?.length ?? 0)\n }\n }\n const pad = (s: string, w: number) => s + ' '.repeat(Math.max(0, w - s.length))\n const out: string[] = []\n out.push(\n headers\n .map((h, i) => pad(h, widths[i] ?? h.length))\n .join(' ')\n .trimEnd(),\n )\n for (const row of norm) {\n out.push(\n row\n .map((c, i) => pad(c, widths[i] ?? c.length))\n .join(' ')\n .trimEnd(),\n )\n }\n return out.join('\\n')\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","join","defaultTokenFile","mirageHome","readDaemonTable","existsSync","readDaemonTable","mirageHome","defaultTokenFile","join","mkdirSync"]}
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import {
6
6
  handleResponse,
7
7
  loadDaemonSettings,
8
8
  makeClient
9
- } from "./chunk-PCROWRBJ.js";
9
+ } from "./chunk-BNUV7A4V.js";
10
10
  export {
11
11
  DEFAULT_DAEMON_URL,
12
12
  DaemonClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@struktoai/mirage-cli",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "A Unified Virtual Filesystem For AI Agents",
5
5
  "keywords": [
6
6
  "bash",
@@ -31,6 +31,9 @@
31
31
  "access": "public"
32
32
  },
33
33
  "type": "module",
34
+ "engines": {
35
+ "node": ">=20.10.0"
36
+ },
34
37
  "main": "./dist/index.js",
35
38
  "types": "./dist/index.d.ts",
36
39
  "files": [
@@ -42,10 +45,10 @@
42
45
  "dependencies": {
43
46
  "commander": "^14.0.0",
44
47
  "yaml": "^2.6.0",
45
- "@struktoai/mirage-agents": "0.0.5",
46
- "@struktoai/mirage-core": "0.0.5",
47
- "@struktoai/mirage-server": "0.0.5",
48
- "@struktoai/mirage-node": "0.0.5"
48
+ "@struktoai/mirage-agents": "0.0.6",
49
+ "@struktoai/mirage-node": "0.0.6",
50
+ "@struktoai/mirage-core": "0.0.6",
51
+ "@struktoai/mirage-server": "0.0.6"
49
52
  },
50
53
  "optionalDependencies": {
51
54
  "@zkochan/fuse-native": "^0.1.0"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/client.ts","../src/env.ts","../src/settings.ts","../src/output.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 { spawn } from 'node:child_process'\nimport { existsSync, mkdirSync, openSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { join } from 'node:path'\nimport {\n AuthMode,\n defaultTokenFile,\n ensureTokenFile,\n mirageHome,\n readDaemonTable,\n validateDaemonTable,\n} from '@struktoai/mirage-server'\n\nimport { ENV_AUTH_MODE, ENV_AUTH_TOKEN, ENV_DAEMON_PORT, ENV_IDLE_GRACE_SECONDS } from './env.ts'\nimport type { DaemonSettings } from './settings.ts'\n\nconst requireFromHere = createRequire(import.meta.url)\n\nconst DEFAULT_REQUEST_TIMEOUT_MS = 60_000\n\nexport class DaemonClient {\n readonly settings: DaemonSettings\n\n constructor(settings: DaemonSettings) {\n this.settings = settings\n }\n\n private headers(extra?: Record<string, string>): Record<string, string> {\n const h: Record<string, string> = { ...extra }\n if (this.settings.authToken !== '') h.Authorization = `Bearer ${this.settings.authToken}`\n return h\n }\n\n async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const { timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, ...rest } = init\n const headers: Record<string, string> = {\n ...this.headers(),\n ...((rest.headers ?? {}) as Record<string, string>),\n }\n if (rest.body !== undefined && headers['Content-Type'] === undefined) {\n headers['Content-Type'] = 'application/json'\n }\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, timeoutMs)\n try {\n return await fetch(this.settings.url + path, {\n ...rest,\n method,\n headers,\n signal: ctrl.signal,\n })\n } finally {\n clearTimeout(t)\n }\n }\n\n async requestMultipart(method: string, path: string, form: FormData): Promise<Response> {\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, DEFAULT_REQUEST_TIMEOUT_MS)\n try {\n return await fetch(this.settings.url + path, {\n method,\n headers: this.headers(),\n body: form,\n signal: ctrl.signal,\n })\n } finally {\n clearTimeout(t)\n }\n }\n\n async isReachable(timeoutMs = 500): Promise<boolean> {\n const ctrl = new AbortController()\n const t = setTimeout(() => {\n ctrl.abort()\n }, timeoutMs)\n try {\n const r = await fetch(this.settings.url + '/v1/health', {\n headers: this.headers(),\n signal: ctrl.signal,\n })\n return r.status === 200\n } catch {\n return false\n } finally {\n clearTimeout(t)\n }\n }\n\n async ensureRunning(opts: { allowSpawn?: boolean; timeoutMs?: number } = {}): Promise<void> {\n const allowSpawn = opts.allowSpawn ?? true\n const timeoutMs = opts.timeoutMs ?? 5000\n if (await this.isReachable()) return\n if (!allowSpawn) {\n throw new Error(\n `daemon not reachable at ${this.settings.url}; run \\`mirage workspace create CONFIG.yaml\\``,\n )\n }\n this.spawnDaemon()\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n if (await this.isReachable(300)) return\n await new Promise((r) => setTimeout(r, 100))\n }\n throw new Error(`daemon spawned but did not answer /v1/health within ${String(timeoutMs)}ms`)\n }\n\n private spawnDaemon(): void {\n const table = readDaemonTable(mirageHome())\n validateDaemonTable(table)\n const env: Record<string, string> = {}\n for (const [k, v] of Object.entries(process.env)) {\n if (typeof v === 'string') env[k] = v\n }\n env[ENV_DAEMON_PORT] = String(this.resolvePort(table))\n env[ENV_IDLE_GRACE_SECONDS] = String(this.settings.idleGraceSeconds)\n if (this.settings.authToken === '') {\n this.settings.authToken = ensureTokenFile(defaultTokenFile())\n }\n env[ENV_AUTH_TOKEN] = this.settings.authToken\n if ((env[ENV_AUTH_MODE] ?? '') === '' && (table.auth_mode ?? '') === '') {\n env[ENV_AUTH_MODE] = AuthMode.Local\n }\n const logDir = mirageHome()\n mkdirSync(logDir, { recursive: true })\n const out = openSync(join(logDir, 'daemon.log'), 'a')\n const daemonEntry = requireFromHere.resolve('@struktoai/mirage-server/bin/daemon')\n if (!existsSync(daemonEntry)) {\n throw new Error(\n `daemon binary not found at ${daemonEntry}; reinstall @struktoai/mirage-server`,\n )\n }\n const child = spawn(process.execPath, [daemonEntry], {\n env,\n detached: true,\n stdio: ['ignore', out, out],\n })\n child.on('error', (err) => {\n console.error('failed to spawn daemon:', err)\n })\n child.unref()\n }\n\n private resolvePort(table: Record<string, string>): number {\n const envPort = process.env[ENV_DAEMON_PORT]\n if (envPort !== undefined && envPort !== '') return Number(envPort)\n const configPort = table.port\n if (configPort !== undefined && configPort !== '') return Number(configPort)\n return this.portFromUrl()\n }\n\n private portFromUrl(): number {\n const u = new URL(this.settings.url)\n return Number(u.port) || 8765\n }\n}\n\nexport function makeClient(settings: DaemonSettings): DaemonClient {\n return new DaemonClient(settings)\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 {\n ENV_AUTH_MODE,\n ENV_AUTH_TOKEN,\n ENV_DAEMON_PORT,\n ENV_IDLE_GRACE_SECONDS,\n} from '@struktoai/mirage-server'\n\nexport const ENV_DAEMON_URL = 'MIRAGE_DAEMON_URL'\nexport const ENV_TOKEN = 'MIRAGE_TOKEN'\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\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { compareCodePoints } from '@struktoai/mirage-core'\nimport {\n ALLOWED_KEYS,\n DaemonConfigError,\n DEFAULT_ALLOWED_HOSTS,\n NUMERIC_KEYS,\n defaultTokenFile,\n mirageHome,\n parseDaemonTable,\n readDaemonTable,\n readTokenFile,\n} from '@struktoai/mirage-server'\n\nimport { ENV_DAEMON_URL, ENV_TOKEN } from './env.ts'\n\nexport const DEFAULT_DAEMON_URL = 'http://127.0.0.1:8765'\n\nexport interface DaemonSettings {\n url: string\n authToken: string\n idleGraceSeconds: number\n}\n\nexport interface LoadOptions {\n env?: Record<string, string | undefined>\n configPath?: string\n tokenFile?: string\n}\n\nexport function loadDaemonSettings(options: LoadOptions = {}): DaemonSettings {\n const env = options.env ?? (process.env as Record<string, string | undefined>)\n const table =\n options.configPath !== undefined\n ? existsSync(options.configPath)\n ? parseDaemonTable(readFileSync(options.configPath, 'utf-8'))\n : {}\n : readDaemonTable(mirageHome(env))\n const settings: DaemonSettings = {\n url: table.url ?? DEFAULT_DAEMON_URL,\n authToken: table.auth_token ?? '',\n idleGraceSeconds: Number(table.idle_grace_seconds ?? '30'),\n }\n const envUrl = env[ENV_DAEMON_URL]\n if (envUrl !== undefined && envUrl !== '') {\n settings.url = envUrl\n }\n const envToken = env[ENV_TOKEN]\n if (envToken !== undefined && envToken !== '') {\n settings.authToken = envToken\n }\n if (settings.authToken === '') {\n const fileToken = readTokenFile(options.tokenFile ?? defaultTokenFile(env))\n if (fileToken !== undefined && fileToken !== '') {\n settings.authToken = fileToken\n }\n }\n return settings\n}\n\nfunction defaultConfigPath(env: Record<string, string | undefined> = process.env): string {\n return join(mirageHome(env), 'config.toml')\n}\n\nconst ENV_FOR_KEY: Record<string, string> = {\n url: ENV_DAEMON_URL,\n allowed_hosts: 'MIRAGE_ALLOWED_HOSTS',\n auth_mode: 'MIRAGE_AUTH_MODE',\n jwt_alg: 'MIRAGE_JWT_ALG',\n jwt_issuer: 'MIRAGE_JWT_ISSUER',\n jwt_audience: 'MIRAGE_JWT_AUDIENCE',\n jwt_pubkey_file: 'MIRAGE_JWT_PUBKEY_FILE',\n jwt_clock_skew: 'MIRAGE_JWT_CLOCK_SKEW_SECONDS',\n jwt_authorized_parties: 'MIRAGE_JWT_AUTHORIZED_PARTIES',\n auth_token: ENV_TOKEN,\n idle_grace_seconds: 'MIRAGE_IDLE_GRACE_SECONDS',\n port: 'MIRAGE_DAEMON_PORT',\n}\n\nfunction defaultForKey(key: string): string {\n const defaults: Record<string, string> = {\n url: DEFAULT_DAEMON_URL,\n allowed_hosts: DEFAULT_ALLOWED_HOSTS.join(','),\n auth_mode: 'local',\n jwt_alg: '',\n jwt_issuer: '',\n jwt_audience: '',\n jwt_pubkey_file: '',\n jwt_clock_skew: '5',\n jwt_authorized_parties: '',\n socket: '',\n auth_token: '',\n idle_grace_seconds: '30',\n port: '8765',\n }\n return defaults[key] ?? ''\n}\n\nexport function resolvedConfig(\n env: Record<string, string | undefined> = process.env as Record<string, string | undefined>,\n): Record<string, [string, string]> {\n const home = mirageHome(env)\n const table = readDaemonTable(home)\n const out: Record<string, [string, string]> = {}\n for (const key of [...ALLOWED_KEYS].sort(compareCodePoints)) {\n const envName = ENV_FOR_KEY[key]\n if (envName !== undefined) {\n const envValue = env[envName]\n if (envValue !== undefined && envValue !== '') {\n out[key] = [envValue, `env ${envName}`]\n continue\n }\n }\n const fileValue = table[key]\n if (fileValue !== undefined && fileValue !== '') {\n out[key] = [fileValue, 'file']\n } else {\n out[key] = [defaultForKey(key), 'default']\n }\n }\n return out\n}\n\nfunction checkKey(key: string): void {\n if (!ALLOWED_KEYS.has(key)) {\n throw new DaemonConfigError(\n `unknown config key: '${key}'; allowed: ${[...ALLOWED_KEYS].sort(compareCodePoints).join(', ')}`,\n )\n }\n}\n\nfunction formatValue(key: string, value: string): string {\n if (NUMERIC_KEYS.has(key)) return value\n return `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`\n}\n\nexport function listConfig(path?: string): Record<string, string> {\n const p = path ?? defaultConfigPath(process.env as Record<string, string | undefined>)\n if (!existsSync(p)) return {}\n return parseDaemonTable(readFileSync(p, 'utf-8'))\n}\n\nexport function getConfig(key: string, path?: string): string | undefined {\n checkKey(key)\n return listConfig(path)[key]\n}\n\nexport function setConfig(key: string, value: string, path?: string): void {\n checkKey(key)\n const p = path ?? defaultConfigPath(process.env as Record<string, string | undefined>)\n const lines = existsSync(p) ? readFileSync(p, 'utf-8').split('\\n') : []\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()\n const rendered = `${key} = ${formatValue(key, value)}`\n let headerIdx = -1\n for (let i = 0; i < lines.length; i++) {\n if ((lines[i] ?? '').trim() === '[daemon]') {\n headerIdx = i\n break\n }\n }\n if (headerIdx < 0) {\n if (lines.length > 0 && (lines[lines.length - 1] ?? '').trim() !== '') lines.push('')\n lines.push('[daemon]', rendered)\n } else {\n let end = lines.length\n for (let i = headerIdx + 1; i < lines.length; i++) {\n if ((lines[i] ?? '').trim().startsWith('[')) {\n end = i\n break\n }\n }\n let replaced = false\n for (let i = headerIdx + 1; i < end; i++) {\n const t = (lines[i] ?? '').trim()\n if (t.startsWith('#') || !t.includes('=')) continue\n if (t.slice(0, t.indexOf('=')).trim() === key) {\n lines[i] = rendered\n replaced = true\n break\n }\n }\n if (!replaced) lines.splice(end, 0, rendered)\n }\n mkdirSync(dirname(p), { recursive: true })\n writeFileSync(p, lines.join('\\n') + '\\n')\n chmodSync(p, 0o600)\n}\n\nexport function unsetConfig(key: string, path?: string): void {\n const p = path ?? defaultConfigPath(process.env as Record<string, string | undefined>)\n if (!existsSync(p)) return\n const lines = readFileSync(p, 'utf-8').split('\\n')\n if (lines.length > 0 && lines[lines.length - 1] === '') lines.pop()\n const kept: string[] = []\n let inDaemon = false\n for (const line of lines) {\n const t = line.trim()\n if (t === '[daemon]') {\n inDaemon = true\n kept.push(line)\n continue\n }\n if (t.startsWith('[')) inDaemon = false\n if (\n inDaemon &&\n t.includes('=') &&\n !t.startsWith('#') &&\n t.slice(0, t.indexOf('=')).trim() === key\n )\n continue\n kept.push(line)\n }\n writeFileSync(p, kept.join('\\n') + '\\n')\n chmodSync(p, 0o600)\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 type Formatter<T = unknown> = (obj: T) => string\n\nexport function emit<T = unknown>(obj: T, human?: Formatter<T>): void {\n if (human !== undefined && process.stdout.isTTY) {\n process.stdout.write(human(obj) + '\\n')\n return\n }\n process.stdout.write(JSON.stringify(obj, null, 2) + '\\n')\n}\n\nexport function fail(message: string, exitCode = 1): never {\n process.stderr.write(message + '\\n')\n process.exit(exitCode)\n}\n\nexport function exitCodeFromResponse(r: unknown): number {\n if (typeof r !== 'object' || r === null) return 0\n const obj = r as Record<string, unknown>\n const inner =\n obj.kind === 'io' ? obj : ((obj.result as Record<string, unknown> | null | undefined) ?? null)\n if (\n inner !== null &&\n inner.kind === 'io' &&\n typeof inner.exitCode === 'number' &&\n Number.isFinite(inner.exitCode)\n ) {\n return Math.min(255, Math.max(0, Math.trunc(inner.exitCode)))\n }\n if (typeof obj.status === 'string' && (obj.status === 'failed' || obj.status === 'canceled')) {\n return 2\n }\n return 0\n}\n\nexport async function handleResponse(r: Response): Promise<unknown> {\n if (r.status >= 400) {\n let detail = await r.text()\n try {\n const parsed = JSON.parse(detail) as { detail?: string }\n if (parsed.detail !== undefined) detail = parsed.detail\n } catch {\n // body wasn't JSON; fall through with the raw text as detail\n }\n fail(`daemon error ${String(r.status)}: ${detail}`, 2)\n }\n if (r.status === 204) return {}\n const text = await r.text()\n if (text === '') return {}\n return JSON.parse(text) as unknown\n}\n\nexport function formatAge(epoch: number, now: number = Date.now() / 1000): string {\n const delta = Math.max(0, now - epoch)\n if (delta < 60) return `${String(Math.floor(delta))}s`\n if (delta < 3600) return `${String(Math.floor(delta / 60))}m`\n if (delta < 86400) return `${String(Math.floor(delta / 3600))}h`\n return `${String(Math.floor(delta / 86400))}d`\n}\n\nexport function formatTable(headers: string[], rows: (string | undefined)[][]): string {\n if (rows.length === 0) return headers.join(' ')\n const norm: string[][] = rows.map((row) => row.map((c) => c ?? ''))\n const widths = headers.map((h) => h.length)\n for (const row of norm) {\n for (let i = 0; i < row.length; i++) {\n widths[i] = Math.max(widths[i] ?? 0, row[i]?.length ?? 0)\n }\n }\n const pad = (s: string, w: number) => s + ' '.repeat(Math.max(0, w - s.length))\n const out: string[] = []\n out.push(\n headers\n .map((h, i) => pad(h, widths[i] ?? h.length))\n .join(' ')\n .trimEnd(),\n )\n for (const row of norm) {\n out.push(\n row\n .map((c, i) => pad(c, widths[i] ?? c.length))\n .join(' ')\n .trimEnd(),\n )\n }\n return out.join('\\n')\n}\n"],"mappings":"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","names":["existsSync","mkdirSync","join","defaultTokenFile","mirageHome","readDaemonTable","existsSync","readDaemonTable","mirageHome","defaultTokenFile","join","mkdirSync"]}