@struktoai/mirage-agents 0.0.2-alpha.0 → 0.0.3-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -127
- package/dist/langchain/index.js +3 -8
- package/dist/langchain/index.js.map +1 -1
- package/dist/mastra/index.js +3 -8
- package/dist/mastra/index.js.map +1 -1
- package/dist/openai/index.js +3 -8
- package/dist/openai/index.js.map +1 -1
- package/dist/opencode/index.d.ts +24 -0
- package/dist/opencode/index.js +206 -0
- package/dist/opencode/index.js.map +1 -0
- package/dist/pi/index.js +4 -3
- package/dist/pi/index.js.map +1 -1
- package/dist/vercel/index.js +3 -9
- package/dist/vercel/index.js.map +1 -1
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -23,135 +23,125 @@
|
|
|
23
23
|
<img src="https://img.shields.io/npm/v/%40struktoai%2Fmirage-agents.svg?color=0C0C0C&labelColor=FAFAFA"/></a>
|
|
24
24
|
</p>
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
<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>
|
|
33
|
+
</p>
|
|
27
34
|
|
|
28
|
-
|
|
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.
|
|
29
36
|
|
|
30
37
|
```ts
|
|
31
38
|
const ws = new Workspace({
|
|
32
|
-
'/data':
|
|
33
|
-
'/s3':
|
|
34
|
-
'/slack': new SlackResource({}),
|
|
35
|
-
'/github': new GitHubResource({}),
|
|
39
|
+
'/data': new RAMResource(),
|
|
40
|
+
'/s3': new S3Resource({ bucket: 'logs' }),
|
|
41
|
+
'/slack': new SlackResource({ token: process.env.SLACK_BOT_TOKEN! }),
|
|
36
42
|
})
|
|
37
43
|
|
|
38
|
-
await ws.execute('grep alert /slack/
|
|
39
|
-
await ws.execute('cat /github/mirage/README.md')
|
|
44
|
+
await ws.execute('grep -r alert /slack/channels/general__C04QX/ | wc -l')
|
|
40
45
|
await ws.execute('cp /s3/report.csv /data/local.csv')
|
|
46
|
+
await ws.execute('wc -l $(find /s3/data -name "*.jsonl")')
|
|
47
|
+
|
|
48
|
+
// Commands are extensible: register new commands, or override one per
|
|
49
|
+
// resource + filetype, e.g. `cat` on S3 Parquet renders rows as JSON.
|
|
50
|
+
ws.command('summarize', ...)
|
|
51
|
+
ws.command('cat', { resource: 's3', filetype: 'parquet' }, ...)
|
|
52
|
+
|
|
53
|
+
await ws.execute('summarize /data/local.csv')
|
|
54
|
+
await ws.execute('cat /s3/events/2026-05-06.parquet | jq .user')
|
|
41
55
|
```
|
|
42
56
|
|
|
43
57
|
## About
|
|
44
58
|
|
|
45
|
-
- **One
|
|
46
|
-
- **
|
|
47
|
-
- **
|
|
48
|
-
- **
|
|
49
|
-
- **
|
|
50
|
-
- **Works with major agent application frameworks:** OpenAI Agents SDK, Vercel AI SDK (TypeScript), LangChain, Pydantic AI, CAMEL, and OpenHands.
|
|
51
|
-
- **Lightweight CLI + daemon:** plugs into coding agents like Claude Code and Codex so they reach every mounted resource through familiar bash, getting more useful work done per turn.
|
|
59
|
+
- **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.
|
|
60
|
+
- **Around 50 built-in backends:** RAM, Disk, Redis, S3 / R2 / OCI / Supabase / GCS, Gmail / GDrive / GDocs / GSheets / GSlides, GitHub / Linear / Notion / Trello, Slack / Discord / Telegram / Email, MongoDB / Postgres / LanceDB, SSH, and more, mounted side-by-side under a single root.
|
|
61
|
+
- **Portable workspaces:** clone, snapshot, and version a workspace; agent runs move between machines without restarting or reconfiguring the system.
|
|
62
|
+
- **Embeddable:** the Python and TypeScript SDKs run in-process inside FastAPI, Express, browser apps, or any async runtime; no separate process required.
|
|
63
|
+
- **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.
|
|
52
64
|
|
|
53
65
|
## Architecture
|
|
54
66
|
|
|
55
67
|
<p align="center">
|
|
56
68
|
<picture>
|
|
57
69
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/strukto-ai/mirage/main/assets/mirage-arch-dark.svg">
|
|
58
|
-
<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 & Cache → Infrastructure and Remote" width="
|
|
70
|
+
<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 & Cache → Infrastructure and Remote" width="720">
|
|
59
71
|
</picture>
|
|
60
72
|
</p>
|
|
61
73
|
|
|
62
74
|
## Installation
|
|
63
75
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
- **Python** ≥ 3.12 for the `mirage-ai` package and the `mirage` CLI
|
|
76
|
+
- **Python** ≥ 3.11 for the `mirage-ai` package and the `mirage` CLI
|
|
67
77
|
- **Node.js** ≥ 20 for the TypeScript SDK
|
|
68
78
|
- **macOS** or **Linux** (FUSE-based mounts require platform support)
|
|
69
79
|
|
|
70
80
|
### Python
|
|
71
81
|
|
|
72
82
|
```bash
|
|
73
|
-
uv add mirage-ai
|
|
83
|
+
uv add mirage-ai # installs the `mirage` library and the `mirage` CLI binary
|
|
74
84
|
```
|
|
75
85
|
|
|
76
|
-
This installs both the `mirage` library and the `mirage` CLI binary.
|
|
77
|
-
|
|
78
86
|
### TypeScript
|
|
79
87
|
|
|
80
|
-
Pick the package that matches your runtime:
|
|
81
|
-
|
|
82
88
|
```bash
|
|
83
89
|
npm install @struktoai/mirage-node # Node.js servers and CLIs
|
|
84
90
|
npm install @struktoai/mirage-browser # browser / edge runtimes
|
|
85
|
-
npm install @struktoai/mirage-
|
|
91
|
+
npm install @struktoai/mirage-agents # OpenAI / Vercel AI / LangChain / Mastra adapters
|
|
86
92
|
```
|
|
87
93
|
|
|
88
|
-
|
|
94
|
+
Both runtime packages pull in `@struktoai/mirage-core` automatically.
|
|
89
95
|
|
|
90
96
|
### CLI
|
|
91
97
|
|
|
92
98
|
```bash
|
|
93
99
|
curl -fsSL https://strukto.ai/mirage/install.sh | sh
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
Or via your package manager of choice:
|
|
97
|
-
|
|
98
|
-
```bash
|
|
100
|
+
# or
|
|
99
101
|
npm install -g @struktoai/mirage-cli
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
```bash
|
|
102
|
+
# or
|
|
103
103
|
uvx mirage-ai
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
```bash
|
|
104
|
+
# or
|
|
107
105
|
npx @struktoai/mirage-cli
|
|
108
106
|
```
|
|
109
107
|
|
|
110
|
-
## Quickstart
|
|
108
|
+
## Quickstart
|
|
109
|
+
|
|
110
|
+
### Python
|
|
111
111
|
|
|
112
112
|
```python
|
|
113
113
|
from mirage import Workspace
|
|
114
|
-
from mirage.resource.gdocs import GDocsConfig, GDocsResource
|
|
115
114
|
from mirage.resource.ram import RAMResource
|
|
116
115
|
from mirage.resource.s3 import S3Config, S3Resource
|
|
117
|
-
from mirage.resource.slack import SlackConfig, SlackResource
|
|
118
116
|
|
|
119
117
|
ws = Workspace({
|
|
120
|
-
"/data":
|
|
121
|
-
"/s3":
|
|
122
|
-
"/slack": SlackResource(SlackConfig()),
|
|
123
|
-
"/docs": GDocsResource(GDocsConfig()),
|
|
118
|
+
"/data": RAMResource(),
|
|
119
|
+
"/s3": S3Resource(S3Config(bucket="my-bucket")),
|
|
124
120
|
})
|
|
125
121
|
|
|
126
122
|
await ws.execute("cp /s3/report.csv /data/report.csv")
|
|
127
123
|
await ws.execute("grep alert /s3/data/log.jsonl | wc -l")
|
|
128
124
|
|
|
129
|
-
ws.snapshot("demo.tar")
|
|
125
|
+
await ws.snapshot("demo.tar")
|
|
130
126
|
```
|
|
131
127
|
|
|
132
|
-
|
|
128
|
+
### TypeScript
|
|
133
129
|
|
|
134
130
|
```ts
|
|
135
|
-
import {
|
|
136
|
-
Workspace,
|
|
137
|
-
RAMResource,
|
|
138
|
-
S3Resource,
|
|
139
|
-
SlackResource,
|
|
140
|
-
GDocsResource,
|
|
141
|
-
} from '@struktoai/mirage-browser'
|
|
131
|
+
import { Workspace, RAMResource, S3Resource } from '@struktoai/mirage-node'
|
|
142
132
|
|
|
143
133
|
const ws = new Workspace({
|
|
144
134
|
'/data': new RAMResource(),
|
|
145
135
|
'/s3': new S3Resource({ bucket: 'my-bucket' }),
|
|
146
|
-
'/slack': new SlackResource({}),
|
|
147
|
-
'/docs': new GDocsResource({}),
|
|
148
136
|
})
|
|
149
137
|
|
|
150
138
|
await ws.execute('cp /s3/report.csv /data/report.csv')
|
|
151
139
|
await ws.execute('grep alert /s3/data/log.jsonl | wc -l')
|
|
140
|
+
|
|
141
|
+
await ws.snapshot('demo.tar')
|
|
152
142
|
```
|
|
153
143
|
|
|
154
|
-
|
|
144
|
+
### CLI
|
|
155
145
|
|
|
156
146
|
```bash
|
|
157
147
|
mirage workspace create ws.yaml --id demo
|
|
@@ -163,89 +153,33 @@ mirage workspace load demo.tar --id demo-restored
|
|
|
163
153
|
|
|
164
154
|
## Agent Frameworks
|
|
165
155
|
|
|
166
|
-
Mirage
|
|
167
|
-
|
|
168
|
-
### OpenAI Agents SDK (Python)
|
|
156
|
+
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.
|
|
169
157
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
from agents.sandbox import SandboxAgent, SandboxRunConfig
|
|
176
|
-
|
|
177
|
-
from mirage.agents.openai_agents import MirageSandboxClient
|
|
178
|
-
|
|
179
|
-
client = MirageSandboxClient(ws)
|
|
180
|
-
agent = SandboxAgent(
|
|
181
|
-
name="Mirage Sandbox Agent",
|
|
182
|
-
model="gpt-5.4-nano",
|
|
183
|
-
instructions=ws.file_prompt,
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
result = await Runner.run(
|
|
187
|
-
agent,
|
|
188
|
-
"Summarize /s3/data/report.parquet into /report.txt.",
|
|
189
|
-
run_config=RunConfig(sandbox=SandboxRunConfig(client=client)),
|
|
190
|
-
)
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Vercel AI SDK (TypeScript)
|
|
194
|
-
|
|
195
|
-
`mirageTools(ws)` exposes the workspace as a typed AI SDK tool set, so any model wired into the AI SDK can read and write across mounts, in Node or the browser.
|
|
196
|
-
|
|
197
|
-
```ts
|
|
198
|
-
import { generateText } from 'ai'
|
|
199
|
-
import { openai } from '@ai-sdk/openai'
|
|
200
|
-
import { mirageTools } from '@struktoai/mirage-agents/vercel'
|
|
201
|
-
import { buildSystemPrompt } from '@struktoai/mirage-agents/openai'
|
|
202
|
-
|
|
203
|
-
const { text } = await generateText({
|
|
204
|
-
model: openai('gpt-5.4-nano'),
|
|
205
|
-
system: buildSystemPrompt({ mountInfo: { '/': 'In-memory filesystem' } }),
|
|
206
|
-
prompt: "Use readFile to read /docs/paper.pdf, then describe what's in it.",
|
|
207
|
-
tools: mirageTools(ws),
|
|
208
|
-
})
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
LangChain, Pydantic AI, CAMEL, OpenHands, and Mastra adapters live alongside these.
|
|
158
|
+
| | Integrations |
|
|
159
|
+
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
160
|
+
| 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) |
|
|
161
|
+
| 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) |
|
|
162
|
+
| 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) |
|
|
212
163
|
|
|
213
164
|
## Cache
|
|
214
165
|
|
|
215
|
-
Every `Workspace`
|
|
166
|
+
Every `Workspace` has a two-layer cache so repeated work against remote backends hits local state instead of the network:
|
|
216
167
|
|
|
217
|
-
- **Index cache
|
|
218
|
-
- **File cache
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
- **Redis**: shared across workers, processes, and machines. Best for serverless, multi-replica services, or when you want cache state to survive restarts.
|
|
168
|
+
- **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).
|
|
169
|
+
- **File cache:** object bytes. The first read streams from origin; later pipelines read from cache (default 512 MB).
|
|
170
|
+
|
|
171
|
+
Both layers default to in-process RAM with zero setup. A Redis store shares cache state across workers, processes, and machines:
|
|
222
172
|
|
|
223
173
|
```ts
|
|
224
|
-
import { RedisFileCacheStore,
|
|
174
|
+
import { RedisFileCacheStore, S3Resource, Workspace } from '@struktoai/mirage-node'
|
|
225
175
|
|
|
226
176
|
const ws = new Workspace(
|
|
227
177
|
{ '/s3': new S3Resource({ bucket: 'my-bucket' }) },
|
|
228
178
|
{
|
|
229
|
-
cache: new RedisFileCacheStore({ url: 'redis://localhost:6379/0',
|
|
230
|
-
index:
|
|
179
|
+
cache: new RedisFileCacheStore({ url: 'redis://localhost:6379/0', cacheLimit: '8GB' }),
|
|
180
|
+
index: { type: 'redis', url: 'redis://localhost:6379/0', ttl: 600 },
|
|
231
181
|
},
|
|
232
182
|
)
|
|
233
183
|
```
|
|
234
184
|
|
|
235
|
-
|
|
236
|
-
import { S3Resource, Workspace } from 'mirage/node'
|
|
237
|
-
|
|
238
|
-
const ws = new Workspace({ '/s3': new S3Resource({ bucket: 'my-bucket' }) })
|
|
239
|
-
|
|
240
|
-
// 1. Index miss → S3 LIST. Listing stored in index cache.
|
|
241
|
-
await ws.execute('ls /s3/data/')
|
|
242
|
-
|
|
243
|
-
// 2. Index hit → 0 network calls.
|
|
244
|
-
await ws.execute('find /s3/data/ -name "*.jsonl"')
|
|
245
|
-
|
|
246
|
-
// 3. File miss → S3 GET. Bytes stored in file cache.
|
|
247
|
-
await ws.execute('cat /s3/data/log.jsonl | wc -l')
|
|
248
|
-
|
|
249
|
-
// 4. File hit → 0 network calls.
|
|
250
|
-
await ws.execute('grep alert /s3/data/log.jsonl')
|
|
251
|
-
```
|
|
185
|
+
See the [cache docs](https://docs.mirage.strukto.ai/home/cache) for the full miss/hit lifecycle.
|
package/dist/langchain/index.js
CHANGED
|
@@ -46,6 +46,7 @@ function ioToFileInfos(io) {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// src/langchain/backend.ts
|
|
49
|
+
import { gnuDirname } from "@struktoai/mirage-core";
|
|
49
50
|
var TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
50
51
|
"txt",
|
|
51
52
|
"md",
|
|
@@ -89,15 +90,9 @@ function shellQuote(s) {
|
|
|
89
90
|
if (/^[A-Za-z0-9_./-]+$/.test(s)) return s;
|
|
90
91
|
return `'${s.replaceAll(`'`, `'\\''`)}'`;
|
|
91
92
|
}
|
|
92
|
-
function parentOf(path) {
|
|
93
|
-
const trimmed = path.replace(/\/+$/, "");
|
|
94
|
-
const idx = trimmed.lastIndexOf("/");
|
|
95
|
-
if (idx <= 0) return "/";
|
|
96
|
-
return trimmed.slice(0, idx);
|
|
97
|
-
}
|
|
98
93
|
async function ensureParent(ws, path) {
|
|
99
|
-
const parent =
|
|
100
|
-
if (parent === "/" || parent === "") return;
|
|
94
|
+
const parent = gnuDirname(path);
|
|
95
|
+
if (parent === "/" || parent === "" || parent === ".") return;
|
|
101
96
|
if (await ws.fs.exists(parent)) return;
|
|
102
97
|
await ensureParent(ws, parent);
|
|
103
98
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/langchain/convert.ts","../../src/langchain/backend.ts","../../src/langchain/messages.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { ExecuteResponse, FileInfo, GrepMatch } from 'deepagents'\n\ninterface IOLike {\n stdoutText: string\n stderrText: string\n exitCode: number | null\n}\n\nexport function ioToExecuteResponse(io: IOLike): ExecuteResponse {\n const stdout = io.stdoutText\n const stderr = io.stderrText\n let output = stdout\n if (stderr.length > 0) {\n output = stdout.length > 0 ? `${stdout}\\n${stderr}` : stderr\n }\n return { output, exitCode: io.exitCode, truncated: false }\n}\n\nexport function ioToGrepMatches(io: IOLike): GrepMatch[] {\n const stdout = io.stdoutText.trim()\n if (stdout.length === 0) return []\n const matches: GrepMatch[] = []\n for (const line of stdout.split('\\n')) {\n const firstColon = line.indexOf(':')\n if (firstColon < 0) continue\n const secondColon = line.indexOf(':', firstColon + 1)\n if (secondColon < 0) continue\n const path = line.slice(0, firstColon)\n const lineNumStr = line.slice(firstColon + 1, secondColon)\n const text = line.slice(secondColon + 1)\n const lineNum = Number.parseInt(lineNumStr, 10)\n if (Number.isNaN(lineNum)) continue\n matches.push({ path, line: lineNum, text })\n }\n return matches\n}\n\nexport function ioToFileInfos(io: IOLike): FileInfo[] {\n const stdout = io.stdoutText.trim()\n if (stdout.length === 0) return []\n const infos: FileInfo[] = []\n for (const raw of stdout.split('\\n')) {\n const entry = raw.trim()\n if (entry.length === 0) continue\n const isDir = entry.endsWith('/')\n infos.push({ path: isDir ? entry.slice(0, -1) : entry, is_dir: isDir })\n }\n return infos\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 { Workspace } from '@struktoai/mirage-node'\nimport type {\n EditResult,\n ExecuteResponse,\n FileData,\n FileDownloadResponse,\n FileInfo,\n FileUploadResponse,\n GlobResult,\n GrepResult,\n LsResult,\n ReadRawResult,\n ReadResult,\n SandboxBackendProtocolV2 as SandboxBackendProtocol,\n WriteResult,\n} from 'deepagents'\nimport { ioToExecuteResponse, ioToFileInfos, ioToGrepMatches } from './convert.ts'\n\nconst TEXT_EXTENSIONS = new Set([\n 'txt',\n 'md',\n 'json',\n 'jsonl',\n 'yaml',\n 'yml',\n 'csv',\n 'tsv',\n 'xml',\n 'html',\n 'htm',\n 'js',\n 'mjs',\n 'cjs',\n 'ts',\n 'tsx',\n 'jsx',\n 'py',\n 'rb',\n 'rs',\n 'go',\n 'java',\n 'c',\n 'cpp',\n 'h',\n 'hpp',\n 'sh',\n 'bash',\n 'zsh',\n 'fish',\n 'sql',\n 'log',\n 'env',\n 'ini',\n 'toml',\n 'conf',\n 'cfg',\n])\n\nfunction shellQuote(s: string): string {\n if (/^[A-Za-z0-9_./-]+$/.test(s)) return s\n return `'${s.replaceAll(`'`, `'\\\\''`)}'`\n}\n\nfunction parentOf(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n const idx = trimmed.lastIndexOf('/')\n if (idx <= 0) return '/'\n return trimmed.slice(0, idx)\n}\n\nasync function ensureParent(ws: Workspace, path: string): Promise<void> {\n const parent = parentOf(path)\n if (parent === '/' || parent === '') return\n if (await ws.fs.exists(parent)) return\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nfunction extOf(path: string): string {\n const dot = path.lastIndexOf('.')\n if (dot < 0) return ''\n return path.slice(dot + 1).toLowerCase()\n}\n\nconst MIRAGE_RENDERED_AS_TEXT = new Set(['parquet', 'h5', 'hdf5', 'feather'])\n\nfunction mimeFor(path: string): string {\n const ext = extOf(path)\n if (ext === 'json' || ext === 'jsonl') return 'application/json'\n if (ext === 'csv') return 'text/csv'\n if (ext === 'html' || ext === 'htm') return 'text/html'\n if (ext === 'md') return 'text/markdown'\n if (TEXT_EXTENSIONS.has(ext)) return 'text/plain'\n if (MIRAGE_RENDERED_AS_TEXT.has(ext)) return 'text/plain'\n if (ext === 'png') return 'image/png'\n if (ext === 'jpg' || ext === 'jpeg') return 'image/jpeg'\n if (ext === 'pdf') return 'application/pdf'\n return 'application/octet-stream'\n}\n\nfunction isTextMime(mimeType: string): boolean {\n return mimeType.startsWith('text/') || mimeType === 'application/json'\n}\n\nconst ANTHROPIC_BINARY_MIMES = new Set([\n 'application/pdf',\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n])\n\nexport interface LangchainWorkspaceOptions {\n sandboxId?: string\n}\n\nexport class LangchainWorkspace implements SandboxBackendProtocol {\n readonly id: string\n private readonly ws: Workspace\n\n constructor(workspace: Workspace, options: LangchainWorkspaceOptions = {}) {\n this.ws = workspace\n this.id = options.sandboxId ?? 'mirage'\n }\n\n async execute(command: string): Promise<ExecuteResponse> {\n const io = await this.ws.execute(command)\n return ioToExecuteResponse(io)\n }\n\n async ls(path: string): Promise<LsResult> {\n let entries: string[]\n try {\n entries = await this.ws.fs.readdir(path)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const files: FileInfo[] = []\n for (const entry of entries) {\n const isDir = await this.ws.fs.isDir(entry)\n files.push({ path: entry, is_dir: isDir })\n }\n return { files }\n }\n\n async read(filePath: string, offset = 0, limit = 500): Promise<ReadResult> {\n const mimeType = mimeFor(filePath)\n let bytes: Uint8Array\n try {\n bytes = await this.ws.fs.readFile(filePath)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n if (!isTextMime(mimeType)) {\n if (ANTHROPIC_BINARY_MIMES.has(mimeType)) {\n return { content: bytes, mimeType }\n }\n return {\n error: `Binary file '${filePath}' (${mimeType}, ${String(bytes.length)} bytes). Use shell commands (head, file, wc, od) via execute() to inspect.`,\n }\n }\n const text = new TextDecoder('utf-8').decode(bytes)\n const lines = text.split('\\n')\n if (offset >= lines.length) {\n return {\n error: `Line offset ${String(offset)} exceeds file length (${String(lines.length)} lines)`,\n }\n }\n const end = Math.min(offset + limit, lines.length)\n return { content: lines.slice(offset, end).join('\\n'), mimeType }\n }\n\n async readRaw(filePath: string): Promise<ReadRawResult> {\n let stat: Awaited<ReturnType<Workspace['fs']['stat']>>\n let bytes: Uint8Array\n try {\n stat = await this.ws.fs.stat(filePath)\n bytes = await this.ws.fs.readFile(filePath)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const mimeType = mimeFor(filePath)\n const content: string | Uint8Array = isTextMime(mimeType)\n ? new TextDecoder('utf-8').decode(bytes)\n : bytes\n const modified = stat.modified ?? new Date().toISOString()\n const data: FileData = {\n content,\n mimeType,\n created_at: modified,\n modified_at: modified,\n }\n return { data }\n }\n\n async write(filePath: string, content: string): Promise<WriteResult> {\n if (await this.ws.fs.exists(filePath)) {\n return { error: `Error: file '${filePath}' already exists` }\n }\n await ensureParent(this.ws, filePath)\n await this.ws.fs.writeFile(filePath, content)\n return { path: filePath }\n }\n\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll = false,\n ): Promise<EditResult> {\n let current: string\n try {\n current = await this.ws.fs.readFileText(filePath)\n } catch {\n return { error: `Error: file '${filePath}' not found` }\n }\n const count = current.split(oldString).length - 1\n if (count === 0) {\n return { error: `Error: string not found in file: '${oldString}'` }\n }\n if (count > 1 && !replaceAll) {\n return {\n error: `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`,\n }\n }\n const next = replaceAll\n ? current.split(oldString).join(newString)\n : current.replace(oldString, newString)\n await this.ws.fs.writeFile(filePath, next)\n return { path: filePath, occurrences: replaceAll ? count : 1 }\n }\n\n async grep(pattern: string, path?: string | null, glob?: string | null): Promise<GrepResult> {\n const parts: string[] = ['grep', '-rn']\n if (glob !== undefined && glob !== null && glob.length > 0) {\n parts.push('--include', shellQuote(glob))\n }\n parts.push(shellQuote(pattern))\n parts.push(shellQuote(path ?? '/'))\n const io = await this.ws.execute(parts.join(' '))\n return { matches: ioToGrepMatches(io) }\n }\n\n async glob(pattern: string, path = '/'): Promise<GlobResult> {\n const name = pattern.includes('/') ? (pattern.split('/').pop() ?? pattern) : pattern\n const io = await this.ws.execute(`find ${shellQuote(path)} -name ${shellQuote(name)}`)\n return { files: ioToFileInfos(io) }\n }\n\n async uploadFiles(\n files: readonly (readonly [string, Uint8Array])[],\n ): Promise<FileUploadResponse[]> {\n const results: FileUploadResponse[] = []\n for (const [path, data] of files) {\n await ensureParent(this.ws, path)\n await this.ws.fs.writeFile(path, data)\n results.push({ path, error: null })\n }\n return results\n }\n\n async downloadFiles(paths: readonly string[]): Promise<FileDownloadResponse[]> {\n const results: FileDownloadResponse[] = []\n for (const path of paths) {\n try {\n const content = await this.ws.fs.readFile(path)\n results.push({ path, content, error: null })\n } catch {\n results.push({ path, content: null, error: 'file_not_found' })\n }\n }\n return results\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\ninterface MessageLike {\n content?: unknown\n}\n\ninterface ContentBlock {\n type?: string\n text?: string\n}\n\nfunction isTextBlock(value: unknown): value is { type: 'text'; text: string } {\n if (typeof value !== 'object' || value === null) return false\n const block = value as ContentBlock\n return block.type === 'text' && typeof block.text === 'string'\n}\n\nexport function extractText(messages: readonly MessageLike[]): string[] {\n const texts: string[] = []\n for (const msg of messages) {\n if (!('content' in msg) || msg.content === undefined || msg.content === null) continue\n const content = msg.content\n if (typeof content === 'string') {\n if (content.trim().length > 0) texts.push(content)\n continue\n }\n if (Array.isArray(content)) {\n for (const block of content) {\n if (isTextBlock(block) && block.text.trim().length > 0) {\n texts.push(block.text)\n }\n }\n }\n }\n return texts\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/langchain/convert.ts","../../src/langchain/backend.ts","../../src/langchain/messages.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { ExecuteResponse, FileInfo, GrepMatch } from 'deepagents'\n\ninterface IOLike {\n stdoutText: string\n stderrText: string\n exitCode: number | null\n}\n\nexport function ioToExecuteResponse(io: IOLike): ExecuteResponse {\n const stdout = io.stdoutText\n const stderr = io.stderrText\n let output = stdout\n if (stderr.length > 0) {\n output = stdout.length > 0 ? `${stdout}\\n${stderr}` : stderr\n }\n return { output, exitCode: io.exitCode, truncated: false }\n}\n\nexport function ioToGrepMatches(io: IOLike): GrepMatch[] {\n const stdout = io.stdoutText.trim()\n if (stdout.length === 0) return []\n const matches: GrepMatch[] = []\n for (const line of stdout.split('\\n')) {\n const firstColon = line.indexOf(':')\n if (firstColon < 0) continue\n const secondColon = line.indexOf(':', firstColon + 1)\n if (secondColon < 0) continue\n const path = line.slice(0, firstColon)\n const lineNumStr = line.slice(firstColon + 1, secondColon)\n const text = line.slice(secondColon + 1)\n const lineNum = Number.parseInt(lineNumStr, 10)\n if (Number.isNaN(lineNum)) continue\n matches.push({ path, line: lineNum, text })\n }\n return matches\n}\n\nexport function ioToFileInfos(io: IOLike): FileInfo[] {\n const stdout = io.stdoutText.trim()\n if (stdout.length === 0) return []\n const infos: FileInfo[] = []\n for (const raw of stdout.split('\\n')) {\n const entry = raw.trim()\n if (entry.length === 0) continue\n const isDir = entry.endsWith('/')\n infos.push({ path: isDir ? entry.slice(0, -1) : entry, is_dir: isDir })\n }\n return infos\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 { Workspace } from '@struktoai/mirage-node'\nimport type {\n EditResult,\n ExecuteResponse,\n FileData,\n FileDownloadResponse,\n FileInfo,\n FileUploadResponse,\n GlobResult,\n GrepResult,\n LsResult,\n ReadRawResult,\n ReadResult,\n SandboxBackendProtocolV2 as SandboxBackendProtocol,\n WriteResult,\n} from 'deepagents'\nimport { ioToExecuteResponse, ioToFileInfos, ioToGrepMatches } from './convert.ts'\nimport { gnuDirname } from '@struktoai/mirage-core'\n\nconst TEXT_EXTENSIONS = new Set([\n 'txt',\n 'md',\n 'json',\n 'jsonl',\n 'yaml',\n 'yml',\n 'csv',\n 'tsv',\n 'xml',\n 'html',\n 'htm',\n 'js',\n 'mjs',\n 'cjs',\n 'ts',\n 'tsx',\n 'jsx',\n 'py',\n 'rb',\n 'rs',\n 'go',\n 'java',\n 'c',\n 'cpp',\n 'h',\n 'hpp',\n 'sh',\n 'bash',\n 'zsh',\n 'fish',\n 'sql',\n 'log',\n 'env',\n 'ini',\n 'toml',\n 'conf',\n 'cfg',\n])\n\nfunction shellQuote(s: string): string {\n if (/^[A-Za-z0-9_./-]+$/.test(s)) return s\n return `'${s.replaceAll(`'`, `'\\\\''`)}'`\n}\n\nasync function ensureParent(ws: Workspace, path: string): Promise<void> {\n const parent = gnuDirname(path)\n if (parent === '/' || parent === '' || parent === '.') return\n if (await ws.fs.exists(parent)) return\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nfunction extOf(path: string): string {\n const dot = path.lastIndexOf('.')\n if (dot < 0) return ''\n return path.slice(dot + 1).toLowerCase()\n}\n\nconst MIRAGE_RENDERED_AS_TEXT = new Set(['parquet', 'h5', 'hdf5', 'feather'])\n\nfunction mimeFor(path: string): string {\n const ext = extOf(path)\n if (ext === 'json' || ext === 'jsonl') return 'application/json'\n if (ext === 'csv') return 'text/csv'\n if (ext === 'html' || ext === 'htm') return 'text/html'\n if (ext === 'md') return 'text/markdown'\n if (TEXT_EXTENSIONS.has(ext)) return 'text/plain'\n if (MIRAGE_RENDERED_AS_TEXT.has(ext)) return 'text/plain'\n if (ext === 'png') return 'image/png'\n if (ext === 'jpg' || ext === 'jpeg') return 'image/jpeg'\n if (ext === 'pdf') return 'application/pdf'\n return 'application/octet-stream'\n}\n\nfunction isTextMime(mimeType: string): boolean {\n return mimeType.startsWith('text/') || mimeType === 'application/json'\n}\n\nconst ANTHROPIC_BINARY_MIMES = new Set([\n 'application/pdf',\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n])\n\nexport interface LangchainWorkspaceOptions {\n sandboxId?: string\n}\n\nexport class LangchainWorkspace implements SandboxBackendProtocol {\n readonly id: string\n private readonly ws: Workspace\n\n constructor(workspace: Workspace, options: LangchainWorkspaceOptions = {}) {\n this.ws = workspace\n this.id = options.sandboxId ?? 'mirage'\n }\n\n async execute(command: string): Promise<ExecuteResponse> {\n const io = await this.ws.execute(command)\n return ioToExecuteResponse(io)\n }\n\n async ls(path: string): Promise<LsResult> {\n let entries: string[]\n try {\n entries = await this.ws.fs.readdir(path)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const files: FileInfo[] = []\n for (const entry of entries) {\n const isDir = await this.ws.fs.isDir(entry)\n files.push({ path: entry, is_dir: isDir })\n }\n return { files }\n }\n\n async read(filePath: string, offset = 0, limit = 500): Promise<ReadResult> {\n const mimeType = mimeFor(filePath)\n let bytes: Uint8Array\n try {\n bytes = await this.ws.fs.readFile(filePath)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n if (!isTextMime(mimeType)) {\n if (ANTHROPIC_BINARY_MIMES.has(mimeType)) {\n return { content: bytes, mimeType }\n }\n return {\n error: `Binary file '${filePath}' (${mimeType}, ${String(bytes.length)} bytes). Use shell commands (head, file, wc, od) via execute() to inspect.`,\n }\n }\n const text = new TextDecoder('utf-8').decode(bytes)\n const lines = text.split('\\n')\n if (offset >= lines.length) {\n return {\n error: `Line offset ${String(offset)} exceeds file length (${String(lines.length)} lines)`,\n }\n }\n const end = Math.min(offset + limit, lines.length)\n return { content: lines.slice(offset, end).join('\\n'), mimeType }\n }\n\n async readRaw(filePath: string): Promise<ReadRawResult> {\n let stat: Awaited<ReturnType<Workspace['fs']['stat']>>\n let bytes: Uint8Array\n try {\n stat = await this.ws.fs.stat(filePath)\n bytes = await this.ws.fs.readFile(filePath)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const mimeType = mimeFor(filePath)\n const content: string | Uint8Array = isTextMime(mimeType)\n ? new TextDecoder('utf-8').decode(bytes)\n : bytes\n const modified = stat.modified ?? new Date().toISOString()\n const data: FileData = {\n content,\n mimeType,\n created_at: modified,\n modified_at: modified,\n }\n return { data }\n }\n\n async write(filePath: string, content: string): Promise<WriteResult> {\n if (await this.ws.fs.exists(filePath)) {\n return { error: `Error: file '${filePath}' already exists` }\n }\n await ensureParent(this.ws, filePath)\n await this.ws.fs.writeFile(filePath, content)\n return { path: filePath }\n }\n\n async edit(\n filePath: string,\n oldString: string,\n newString: string,\n replaceAll = false,\n ): Promise<EditResult> {\n let current: string\n try {\n current = await this.ws.fs.readFileText(filePath)\n } catch {\n return { error: `Error: file '${filePath}' not found` }\n }\n const count = current.split(oldString).length - 1\n if (count === 0) {\n return { error: `Error: string not found in file: '${oldString}'` }\n }\n if (count > 1 && !replaceAll) {\n return {\n error: `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`,\n }\n }\n const next = replaceAll\n ? current.split(oldString).join(newString)\n : current.replace(oldString, newString)\n await this.ws.fs.writeFile(filePath, next)\n return { path: filePath, occurrences: replaceAll ? count : 1 }\n }\n\n async grep(pattern: string, path?: string | null, glob?: string | null): Promise<GrepResult> {\n const parts: string[] = ['grep', '-rn']\n if (glob !== undefined && glob !== null && glob.length > 0) {\n parts.push('--include', shellQuote(glob))\n }\n parts.push(shellQuote(pattern))\n parts.push(shellQuote(path ?? '/'))\n const io = await this.ws.execute(parts.join(' '))\n return { matches: ioToGrepMatches(io) }\n }\n\n async glob(pattern: string, path = '/'): Promise<GlobResult> {\n const name = pattern.includes('/') ? (pattern.split('/').pop() ?? pattern) : pattern\n const io = await this.ws.execute(`find ${shellQuote(path)} -name ${shellQuote(name)}`)\n return { files: ioToFileInfos(io) }\n }\n\n async uploadFiles(\n files: readonly (readonly [string, Uint8Array])[],\n ): Promise<FileUploadResponse[]> {\n const results: FileUploadResponse[] = []\n for (const [path, data] of files) {\n await ensureParent(this.ws, path)\n await this.ws.fs.writeFile(path, data)\n results.push({ path, error: null })\n }\n return results\n }\n\n async downloadFiles(paths: readonly string[]): Promise<FileDownloadResponse[]> {\n const results: FileDownloadResponse[] = []\n for (const path of paths) {\n try {\n const content = await this.ws.fs.readFile(path)\n results.push({ path, content, error: null })\n } catch {\n results.push({ path, content: null, error: 'file_not_found' })\n }\n }\n return results\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\ninterface MessageLike {\n content?: unknown\n}\n\ninterface ContentBlock {\n type?: string\n text?: string\n}\n\nfunction isTextBlock(value: unknown): value is { type: 'text'; text: string } {\n if (typeof value !== 'object' || value === null) return false\n const block = value as ContentBlock\n return block.type === 'text' && typeof block.text === 'string'\n}\n\nexport function extractText(messages: readonly MessageLike[]): string[] {\n const texts: string[] = []\n for (const msg of messages) {\n if (!('content' in msg) || msg.content === undefined || msg.content === null) continue\n const content = msg.content\n if (typeof content === 'string') {\n if (content.trim().length > 0) texts.push(content)\n continue\n }\n if (Array.isArray(content)) {\n for (const block of content) {\n if (isTextBlock(block) && block.text.trim().length > 0) {\n texts.push(block.text)\n }\n }\n }\n }\n return texts\n}\n"],"mappings":"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","names":[]}
|
package/dist/mastra/index.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
// src/mastra/index.ts
|
|
2
2
|
import { createTool } from "@mastra/core/tools";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
|
|
5
|
-
const trimmed = path.replace(/\/+$/, "");
|
|
6
|
-
const idx = trimmed.lastIndexOf("/");
|
|
7
|
-
if (idx <= 0) return "/";
|
|
8
|
-
return trimmed.slice(0, idx);
|
|
9
|
-
}
|
|
4
|
+
import { gnuDirname } from "@struktoai/mirage-core";
|
|
10
5
|
async function ensureParent(ws, path) {
|
|
11
|
-
const parent =
|
|
12
|
-
if (parent === "/" || parent === "") return;
|
|
6
|
+
const parent = gnuDirname(path);
|
|
7
|
+
if (parent === "/" || parent === "" || parent === ".") return;
|
|
13
8
|
if (await ws.fs.exists(parent)) return;
|
|
14
9
|
await ensureParent(ws, parent);
|
|
15
10
|
try {
|
package/dist/mastra/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mastra/index.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-core'\nimport { createTool } from '@mastra/core/tools'\nimport { z } from 'zod'\n\nfunction parentOf(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n const idx = trimmed.lastIndexOf('/')\n if (idx <= 0) return '/'\n return trimmed.slice(0, idx)\n}\n\nasync function ensureParent(ws: Workspace, path: string): Promise<void> {\n const parent = parentOf(path)\n if (parent === '/' || parent === '') return\n if (await ws.fs.exists(parent)) return\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nexport function mirageTools(ws: Workspace) {\n return {\n execute: createTool({\n id: 'mirage-execute',\n description:\n 'Execute a shell command in the Mirage workspace and return stdout, stderr, and exitCode.',\n inputSchema: z.object({\n command: z.string().describe('The shell command to execute.'),\n }),\n outputSchema: z.object({\n stdout: z.string(),\n stderr: z.string(),\n exitCode: z.number(),\n }),\n execute: async (inputData) => {\n const { command } = inputData as { command: string }\n const io = await ws.execute(command)\n return {\n stdout: io.stdoutText,\n stderr: io.stderrText,\n exitCode: io.exitCode,\n }\n },\n }),\n\n readFile: createTool({\n id: 'mirage-read-file',\n description: 'Read the contents of a file from the Mirage workspace as UTF-8 text.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path inside the workspace.'),\n }),\n outputSchema: z.object({\n content: z.string().optional(),\n error: z.string().optional(),\n }),\n execute: async (inputData) => {\n const { path } = inputData as { path: string }\n try {\n const content = await ws.fs.readFileText(path)\n return { content }\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n },\n }),\n\n writeFile: createTool({\n id: 'mirage-write-file',\n description:\n 'Write content to a file in the Mirage workspace. Creates missing parent directories.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path inside the workspace.'),\n content: z.string().describe('UTF-8 text content to write.'),\n }),\n outputSchema: z.object({ path: z.string() }),\n execute: async (inputData) => {\n const { path, content } = inputData as { path: string; content: string }\n await ensureParent(ws, path)\n await ws.fs.writeFile(path, content)\n return { path }\n },\n }),\n\n editFile: createTool({\n id: 'mirage-edit-file',\n description:\n 'Replace a string inside an existing file. Errors if the string appears more than once unless replaceAll is true.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path of the file to edit.'),\n oldString: z.string().describe('The exact string to replace.'),\n newString: z.string().describe('The replacement string.'),\n replaceAll: z\n .boolean()\n .optional()\n .describe('Replace every occurrence rather than requiring a unique match.'),\n }),\n outputSchema: z.object({\n path: z.string().optional(),\n occurrences: z.number().optional(),\n error: z.string().optional(),\n }),\n execute: async (inputData) => {\n const { path, oldString, newString, replaceAll } = inputData as {\n path: string\n oldString: string\n newString: string\n replaceAll?: boolean\n }\n let current: string\n try {\n current = await ws.fs.readFileText(path)\n } catch {\n return { error: `Error: file '${path}' not found` }\n }\n const count = current.split(oldString).length - 1\n if (count === 0) {\n return { error: `Error: string not found in file: '${oldString}'` }\n }\n if (count > 1 && replaceAll !== true) {\n return {\n error: `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`,\n }\n }\n const next =\n replaceAll === true\n ? current.split(oldString).join(newString)\n : current.replace(oldString, newString)\n await ws.fs.writeFile(path, next)\n return { path, occurrences: replaceAll === true ? count : 1 }\n },\n }),\n\n ls: createTool({\n id: 'mirage-ls',\n description: 'List entries of a directory in the Mirage workspace.',\n inputSchema: z.object({\n path: z.string().describe('Absolute directory path inside the workspace.'),\n }),\n outputSchema: z.object({\n files: z.array(z.object({ path: z.string(), is_dir: z.boolean() })).optional(),\n error: z.string().optional(),\n }),\n execute: async (inputData) => {\n const { path } = inputData as { path: string }\n let entries: string[]\n try {\n entries = await ws.fs.readdir(path)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const files: { path: string; is_dir: boolean }[] = []\n for (const entry of entries) {\n const isDir = await ws.fs.isDir(entry)\n files.push({ path: entry, is_dir: isDir })\n }\n return { files }\n },\n }),\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/mastra/index.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-core'\nimport { createTool } from '@mastra/core/tools'\nimport { z } from 'zod'\nimport { gnuDirname } from '@struktoai/mirage-core'\n\nasync function ensureParent(ws: Workspace, path: string): Promise<void> {\n const parent = gnuDirname(path)\n if (parent === '/' || parent === '' || parent === '.') return\n if (await ws.fs.exists(parent)) return\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nexport function mirageTools(ws: Workspace) {\n return {\n execute: createTool({\n id: 'mirage-execute',\n description:\n 'Execute a shell command in the Mirage workspace and return stdout, stderr, and exitCode.',\n inputSchema: z.object({\n command: z.string().describe('The shell command to execute.'),\n }),\n outputSchema: z.object({\n stdout: z.string(),\n stderr: z.string(),\n exitCode: z.number(),\n }),\n execute: async (inputData) => {\n const { command } = inputData as { command: string }\n const io = await ws.execute(command)\n return {\n stdout: io.stdoutText,\n stderr: io.stderrText,\n exitCode: io.exitCode,\n }\n },\n }),\n\n readFile: createTool({\n id: 'mirage-read-file',\n description: 'Read the contents of a file from the Mirage workspace as UTF-8 text.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path inside the workspace.'),\n }),\n outputSchema: z.object({\n content: z.string().optional(),\n error: z.string().optional(),\n }),\n execute: async (inputData) => {\n const { path } = inputData as { path: string }\n try {\n const content = await ws.fs.readFileText(path)\n return { content }\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n },\n }),\n\n writeFile: createTool({\n id: 'mirage-write-file',\n description:\n 'Write content to a file in the Mirage workspace. Creates missing parent directories.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path inside the workspace.'),\n content: z.string().describe('UTF-8 text content to write.'),\n }),\n outputSchema: z.object({ path: z.string() }),\n execute: async (inputData) => {\n const { path, content } = inputData as { path: string; content: string }\n await ensureParent(ws, path)\n await ws.fs.writeFile(path, content)\n return { path }\n },\n }),\n\n editFile: createTool({\n id: 'mirage-edit-file',\n description:\n 'Replace a string inside an existing file. Errors if the string appears more than once unless replaceAll is true.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path of the file to edit.'),\n oldString: z.string().describe('The exact string to replace.'),\n newString: z.string().describe('The replacement string.'),\n replaceAll: z\n .boolean()\n .optional()\n .describe('Replace every occurrence rather than requiring a unique match.'),\n }),\n outputSchema: z.object({\n path: z.string().optional(),\n occurrences: z.number().optional(),\n error: z.string().optional(),\n }),\n execute: async (inputData) => {\n const { path, oldString, newString, replaceAll } = inputData as {\n path: string\n oldString: string\n newString: string\n replaceAll?: boolean\n }\n let current: string\n try {\n current = await ws.fs.readFileText(path)\n } catch {\n return { error: `Error: file '${path}' not found` }\n }\n const count = current.split(oldString).length - 1\n if (count === 0) {\n return { error: `Error: string not found in file: '${oldString}'` }\n }\n if (count > 1 && replaceAll !== true) {\n return {\n error: `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`,\n }\n }\n const next =\n replaceAll === true\n ? current.split(oldString).join(newString)\n : current.replace(oldString, newString)\n await ws.fs.writeFile(path, next)\n return { path, occurrences: replaceAll === true ? count : 1 }\n },\n }),\n\n ls: createTool({\n id: 'mirage-ls',\n description: 'List entries of a directory in the Mirage workspace.',\n inputSchema: z.object({\n path: z.string().describe('Absolute directory path inside the workspace.'),\n }),\n outputSchema: z.object({\n files: z.array(z.object({ path: z.string(), is_dir: z.boolean() })).optional(),\n error: z.string().optional(),\n }),\n execute: async (inputData) => {\n const { path } = inputData as { path: string }\n let entries: string[]\n try {\n entries = await ws.fs.readdir(path)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const files: { path: string; is_dir: boolean }[] = []\n for (const entry of entries) {\n const isDir = await ws.fs.isDir(entry)\n files.push({ path: entry, is_dir: isDir })\n }\n return { files }\n },\n }),\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/openai/index.js
CHANGED
|
@@ -5,15 +5,10 @@ import {
|
|
|
5
5
|
|
|
6
6
|
// src/openai/editor.ts
|
|
7
7
|
import { applyDiff } from "@openai/agents";
|
|
8
|
-
|
|
9
|
-
const trimmed = path.replace(/\/+$/, "");
|
|
10
|
-
const idx = trimmed.lastIndexOf("/");
|
|
11
|
-
if (idx <= 0) return "/";
|
|
12
|
-
return trimmed.slice(0, idx);
|
|
13
|
-
}
|
|
8
|
+
import { gnuDirname } from "@struktoai/mirage-core";
|
|
14
9
|
async function ensureParent(ws, path) {
|
|
15
|
-
const parent =
|
|
16
|
-
if (parent === "/" || parent === "") return;
|
|
10
|
+
const parent = gnuDirname(path);
|
|
11
|
+
if (parent === "/" || parent === "" || parent === ".") return;
|
|
17
12
|
if (await ws.fs.exists(parent)) return;
|
|
18
13
|
await ensureParent(ws, parent);
|
|
19
14
|
try {
|
package/dist/openai/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/openai/editor.ts","../../src/openai/shell.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-core'\nimport { applyDiff } from '@openai/agents'\nimport type { ApplyPatchOperation, ApplyPatchResult, Editor } from '@openai/agents'\
|
|
1
|
+
{"version":3,"sources":["../../src/openai/editor.ts","../../src/openai/shell.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-core'\nimport { applyDiff } from '@openai/agents'\nimport type { ApplyPatchOperation, ApplyPatchResult, Editor } from '@openai/agents'\nimport { gnuDirname } from '@struktoai/mirage-core'\n\nasync function ensureParent(ws: Workspace, path: string): Promise<void> {\n const parent = gnuDirname(path)\n if (parent === '/' || parent === '' || parent === '.') return\n if (await ws.fs.exists(parent)) return\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n // Tolerate mkdir race: another caller may have created the dir between exists() and mkdir().\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nexport class MirageEditor implements Editor {\n constructor(private readonly ws: Workspace) {}\n\n async createFile(\n op: Extract<ApplyPatchOperation, { type: 'create_file' }>,\n ): Promise<ApplyPatchResult> {\n await ensureParent(this.ws, op.path)\n const content = applyDiff('', op.diff, 'create')\n await this.ws.fs.writeFile(op.path, content)\n return { status: 'completed' }\n }\n\n async updateFile(\n op: Extract<ApplyPatchOperation, { type: 'update_file' }>,\n ): Promise<ApplyPatchResult> {\n let current: string\n try {\n current = await this.ws.fs.readFileText(op.path)\n } catch {\n return { status: 'failed', output: `File not found: ${op.path}` }\n }\n const next = applyDiff(current, op.diff)\n await this.ws.fs.writeFile(op.path, next)\n return { status: 'completed' }\n }\n\n async deleteFile(\n op: Extract<ApplyPatchOperation, { type: 'delete_file' }>,\n ): Promise<ApplyPatchResult> {\n if (!(await this.ws.fs.exists(op.path))) {\n return { status: 'failed', output: `File not found: ${op.path}` }\n }\n await this.ws.fs.unlink(op.path)\n return { status: 'completed' }\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 { Workspace } from '@struktoai/mirage-core'\nimport type { Shell, ShellAction, ShellResult, ShellOutputResult } from '@openai/agents'\n\nexport class MirageShell implements Shell {\n constructor(private readonly ws: Workspace) {}\n\n async run(action: ShellAction): Promise<ShellResult> {\n const output: ShellOutputResult[] = []\n for (const cmd of action.commands) {\n const io = await this.ws.execute(cmd)\n output.push({\n stdout: io.stdoutText,\n stderr: io.stderrText,\n outcome: { type: 'exit', exitCode: io.exitCode },\n })\n }\n return { output }\n }\n}\n"],"mappings":";;;;;;AAeA,SAAS,iBAAiB;AAE1B,SAAS,kBAAkB;AAE3B,eAAe,aAAa,IAAe,MAA6B;AACtE,QAAM,SAAS,WAAW,IAAI;AAC9B,MAAI,WAAW,OAAO,WAAW,MAAM,WAAW,IAAK;AACvD,MAAI,MAAM,GAAG,GAAG,OAAO,MAAM,EAAG;AAChC,QAAM,aAAa,IAAI,MAAM;AAC7B,MAAI;AACF,UAAM,GAAG,GAAG,MAAM,MAAM;AAAA,EAC1B,SAAS,KAAK;AAEZ,QAAI,CAAE,MAAM,GAAG,GAAG,OAAO,MAAM,EAAI,OAAM;AAAA,EAC3C;AACF;AAEO,IAAM,eAAN,MAAqC;AAAA,EAC1C,YAA6B,IAAe;AAAf;AAAA,EAAgB;AAAA,EAAhB;AAAA,EAE7B,MAAM,WACJ,IAC2B;AAC3B,UAAM,aAAa,KAAK,IAAI,GAAG,IAAI;AACnC,UAAM,UAAU,UAAU,IAAI,GAAG,MAAM,QAAQ;AAC/C,UAAM,KAAK,GAAG,GAAG,UAAU,GAAG,MAAM,OAAO;AAC3C,WAAO,EAAE,QAAQ,YAAY;AAAA,EAC/B;AAAA,EAEA,MAAM,WACJ,IAC2B;AAC3B,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,KAAK,GAAG,GAAG,aAAa,GAAG,IAAI;AAAA,IACjD,QAAQ;AACN,aAAO,EAAE,QAAQ,UAAU,QAAQ,mBAAmB,GAAG,IAAI,GAAG;AAAA,IAClE;AACA,UAAM,OAAO,UAAU,SAAS,GAAG,IAAI;AACvC,UAAM,KAAK,GAAG,GAAG,UAAU,GAAG,MAAM,IAAI;AACxC,WAAO,EAAE,QAAQ,YAAY;AAAA,EAC/B;AAAA,EAEA,MAAM,WACJ,IAC2B;AAC3B,QAAI,CAAE,MAAM,KAAK,GAAG,GAAG,OAAO,GAAG,IAAI,GAAI;AACvC,aAAO,EAAE,QAAQ,UAAU,QAAQ,mBAAmB,GAAG,IAAI,GAAG;AAAA,IAClE;AACA,UAAM,KAAK,GAAG,GAAG,OAAO,GAAG,IAAI;AAC/B,WAAO,EAAE,QAAQ,YAAY;AAAA,EAC/B;AACF;;;AClDO,IAAM,cAAN,MAAmC;AAAA,EACxC,YAA6B,IAAe;AAAf;AAAA,EAAgB;AAAA,EAAhB;AAAA,EAE7B,MAAM,IAAI,QAA2C;AACnD,UAAM,SAA8B,CAAC;AACrC,eAAW,OAAO,OAAO,UAAU;AACjC,YAAM,KAAK,MAAM,KAAK,GAAG,QAAQ,GAAG;AACpC,aAAO,KAAK;AAAA,QACV,QAAQ,GAAG;AAAA,QACX,QAAQ,GAAG;AAAA,QACX,SAAS,EAAE,MAAM,QAAQ,UAAU,GAAG,SAAS;AAAA,MACjD,CAAC;AAAA,IACH;AACA,WAAO,EAAE,OAAO;AAAA,EAClB;AACF;","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Workspace } from '@struktoai/mirage-node';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
interface ToolContext {
|
|
5
|
+
sessionID: string;
|
|
6
|
+
messageID: string;
|
|
7
|
+
agent: string;
|
|
8
|
+
abort: AbortSignal;
|
|
9
|
+
}
|
|
10
|
+
type WsResolver = (ctx: ToolContext) => Workspace | Promise<Workspace>;
|
|
11
|
+
type WsLike = Workspace | WsResolver;
|
|
12
|
+
interface ToolDefinition<Args extends z.ZodRawShape = z.ZodRawShape> {
|
|
13
|
+
description: string;
|
|
14
|
+
args: Args;
|
|
15
|
+
execute(args: z.infer<z.ZodObject<Args>>, context: ToolContext): Promise<string>;
|
|
16
|
+
}
|
|
17
|
+
declare function mirageTools(ws: WsLike): Record<string, ToolDefinition>;
|
|
18
|
+
interface Hooks {
|
|
19
|
+
tool?: Record<string, ToolDefinition>;
|
|
20
|
+
}
|
|
21
|
+
type PluginFn = (input: unknown) => Promise<Hooks>;
|
|
22
|
+
declare function miragePlugin(ws: WsLike): PluginFn;
|
|
23
|
+
|
|
24
|
+
export { type ToolContext, type WsLike, type WsResolver, miragePlugin, mirageTools };
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// src/opencode/index.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { gnuDirname } from "@struktoai/mirage-core";
|
|
4
|
+
function tool(input) {
|
|
5
|
+
return input;
|
|
6
|
+
}
|
|
7
|
+
function isResolver(ws) {
|
|
8
|
+
return typeof ws === "function";
|
|
9
|
+
}
|
|
10
|
+
async function resolveWs(ws, ctx) {
|
|
11
|
+
return isResolver(ws) ? ws(ctx) : ws;
|
|
12
|
+
}
|
|
13
|
+
async function ensureParent(ws, path) {
|
|
14
|
+
const parent = gnuDirname(path);
|
|
15
|
+
if (parent === "/" || parent === "" || parent === ".") return;
|
|
16
|
+
if (await ws.fs.exists(parent)) return;
|
|
17
|
+
await ensureParent(ws, parent);
|
|
18
|
+
try {
|
|
19
|
+
await ws.fs.mkdir(parent);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
if (!await ws.fs.exists(parent)) throw err;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
var TEXT_EXTS = /* @__PURE__ */ new Set([
|
|
25
|
+
"txt",
|
|
26
|
+
"md",
|
|
27
|
+
"json",
|
|
28
|
+
"jsonl",
|
|
29
|
+
"yaml",
|
|
30
|
+
"yml",
|
|
31
|
+
"csv",
|
|
32
|
+
"tsv",
|
|
33
|
+
"xml",
|
|
34
|
+
"html",
|
|
35
|
+
"htm",
|
|
36
|
+
"js",
|
|
37
|
+
"mjs",
|
|
38
|
+
"cjs",
|
|
39
|
+
"ts",
|
|
40
|
+
"tsx",
|
|
41
|
+
"jsx",
|
|
42
|
+
"py",
|
|
43
|
+
"rb",
|
|
44
|
+
"rs",
|
|
45
|
+
"go",
|
|
46
|
+
"java",
|
|
47
|
+
"c",
|
|
48
|
+
"cpp",
|
|
49
|
+
"h",
|
|
50
|
+
"hpp",
|
|
51
|
+
"sh",
|
|
52
|
+
"bash",
|
|
53
|
+
"zsh",
|
|
54
|
+
"sql",
|
|
55
|
+
"log",
|
|
56
|
+
"env",
|
|
57
|
+
"ini",
|
|
58
|
+
"toml",
|
|
59
|
+
"conf",
|
|
60
|
+
"cfg"
|
|
61
|
+
]);
|
|
62
|
+
function extOf(path) {
|
|
63
|
+
const dot = path.lastIndexOf(".");
|
|
64
|
+
if (dot < 0) return "";
|
|
65
|
+
return path.slice(dot + 1).toLowerCase();
|
|
66
|
+
}
|
|
67
|
+
function isLikelyText(path) {
|
|
68
|
+
return TEXT_EXTS.has(extOf(path));
|
|
69
|
+
}
|
|
70
|
+
function errMsg(err) {
|
|
71
|
+
return err instanceof Error ? err.message : String(err);
|
|
72
|
+
}
|
|
73
|
+
function mirageTools(ws) {
|
|
74
|
+
const read = tool({
|
|
75
|
+
description: "Read a file. Returns UTF-8 text for source/data files; for binary files returns a metadata stub. Use the bash tool to inspect binaries.",
|
|
76
|
+
args: {
|
|
77
|
+
filePath: z.string().describe("Absolute path of the file to read.")
|
|
78
|
+
},
|
|
79
|
+
execute: async ({ filePath }, ctx) => {
|
|
80
|
+
const w = await resolveWs(ws, ctx);
|
|
81
|
+
let bytes;
|
|
82
|
+
try {
|
|
83
|
+
bytes = await w.fs.readFile(filePath);
|
|
84
|
+
} catch (err) {
|
|
85
|
+
return `Error: ${errMsg(err)}`;
|
|
86
|
+
}
|
|
87
|
+
if (isLikelyText(filePath)) {
|
|
88
|
+
return new TextDecoder("utf-8", { fatal: false }).decode(bytes);
|
|
89
|
+
}
|
|
90
|
+
return `Binary file ${filePath} (${String(bytes.length)} bytes). Use the bash tool with head/file/wc/od to inspect.`;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
const write = tool({
|
|
94
|
+
description: "Write content to a file. Creates missing parent directories.",
|
|
95
|
+
args: {
|
|
96
|
+
filePath: z.string().describe("Absolute path of the file to write."),
|
|
97
|
+
content: z.string().describe("UTF-8 text content to write.")
|
|
98
|
+
},
|
|
99
|
+
execute: async ({ filePath, content }, ctx) => {
|
|
100
|
+
const w = await resolveWs(ws, ctx);
|
|
101
|
+
await ensureParent(w, filePath);
|
|
102
|
+
await w.fs.writeFile(filePath, content);
|
|
103
|
+
return `Wrote ${String(content.length)} bytes to ${filePath}`;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
const edit = tool({
|
|
107
|
+
description: "Replace a string inside an existing file. Errors if the string appears more than once unless replaceAll is true.",
|
|
108
|
+
args: {
|
|
109
|
+
filePath: z.string().describe("Absolute path of the file to edit."),
|
|
110
|
+
oldString: z.string().describe("The exact string to replace."),
|
|
111
|
+
newString: z.string().describe("The replacement string."),
|
|
112
|
+
replaceAll: z.boolean().optional().describe("Replace every occurrence rather than requiring a unique match.")
|
|
113
|
+
},
|
|
114
|
+
execute: async ({ filePath, oldString, newString, replaceAll }, ctx) => {
|
|
115
|
+
const w = await resolveWs(ws, ctx);
|
|
116
|
+
let current;
|
|
117
|
+
try {
|
|
118
|
+
current = await w.fs.readFileText(filePath);
|
|
119
|
+
} catch {
|
|
120
|
+
return `Error: file '${filePath}' not found`;
|
|
121
|
+
}
|
|
122
|
+
const count = current.split(oldString).length - 1;
|
|
123
|
+
if (count === 0) {
|
|
124
|
+
return `Error: string not found in file: '${oldString}'`;
|
|
125
|
+
}
|
|
126
|
+
if (count > 1 && replaceAll !== true) {
|
|
127
|
+
return `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`;
|
|
128
|
+
}
|
|
129
|
+
const next = replaceAll === true ? current.split(oldString).join(newString) : current.replace(oldString, newString);
|
|
130
|
+
await w.fs.writeFile(filePath, next);
|
|
131
|
+
const occurrences = replaceAll === true ? count : 1;
|
|
132
|
+
return `Edited ${filePath} (${String(occurrences)} occurrence${occurrences === 1 ? "" : "s"})`;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
const ls = tool({
|
|
136
|
+
description: "List entries of a directory.",
|
|
137
|
+
args: {
|
|
138
|
+
path: z.string().describe("Absolute directory path.")
|
|
139
|
+
},
|
|
140
|
+
execute: async ({ path }, ctx) => {
|
|
141
|
+
const w = await resolveWs(ws, ctx);
|
|
142
|
+
let entries;
|
|
143
|
+
try {
|
|
144
|
+
entries = await w.fs.readdir(path);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
return `Error: ${errMsg(err)}`;
|
|
147
|
+
}
|
|
148
|
+
const lines = [];
|
|
149
|
+
for (const entry of entries) {
|
|
150
|
+
const isDir = await w.fs.isDir(entry);
|
|
151
|
+
lines.push(isDir ? `${entry}/` : entry);
|
|
152
|
+
}
|
|
153
|
+
return lines.join("\n");
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
const bash = tool({
|
|
157
|
+
description: "Execute a shell command and return stdout, stderr, and exit code.",
|
|
158
|
+
args: {
|
|
159
|
+
command: z.string().describe("The shell command to execute.")
|
|
160
|
+
},
|
|
161
|
+
execute: async ({ command }, ctx) => {
|
|
162
|
+
const w = await resolveWs(ws, ctx);
|
|
163
|
+
const io = await w.execute(command);
|
|
164
|
+
const parts = [];
|
|
165
|
+
if (io.stdoutText.length > 0) parts.push(io.stdoutText);
|
|
166
|
+
if (io.stderrText.length > 0) parts.push(io.stderrText);
|
|
167
|
+
return parts.join("\n").trim();
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
const glob = tool({
|
|
171
|
+
description: "Find files matching a name pattern.",
|
|
172
|
+
args: {
|
|
173
|
+
pattern: z.string().describe('Filename pattern (e.g. "*.ts").'),
|
|
174
|
+
path: z.string().optional().describe("Directory to search under. Defaults to /.")
|
|
175
|
+
},
|
|
176
|
+
execute: async ({ pattern, path }, ctx) => {
|
|
177
|
+
const w = await resolveWs(ws, ctx);
|
|
178
|
+
const root = path ?? "/";
|
|
179
|
+
const io = await w.execute(`find ${root} -name '${pattern.replace(/'/g, "'\\''")}'`);
|
|
180
|
+
return io.stdoutText.trim();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
const grep = tool({
|
|
184
|
+
description: "Search for a regex pattern in files.",
|
|
185
|
+
args: {
|
|
186
|
+
pattern: z.string().describe("Pattern to search for."),
|
|
187
|
+
path: z.string().optional().describe("Directory or file to search under. Defaults to /.")
|
|
188
|
+
},
|
|
189
|
+
execute: async ({ pattern, path }, ctx) => {
|
|
190
|
+
const w = await resolveWs(ws, ctx);
|
|
191
|
+
const root = path ?? "/";
|
|
192
|
+
const escaped = pattern.replace(/'/g, "'\\''");
|
|
193
|
+
const io = await w.execute(`grep -rn '${escaped}' ${root}`);
|
|
194
|
+
return io.stdoutText.trim();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
return { read, write, edit, ls, bash, glob, grep };
|
|
198
|
+
}
|
|
199
|
+
function miragePlugin(ws) {
|
|
200
|
+
return () => Promise.resolve({ tool: mirageTools(ws) });
|
|
201
|
+
}
|
|
202
|
+
export {
|
|
203
|
+
miragePlugin,
|
|
204
|
+
mirageTools
|
|
205
|
+
};
|
|
206
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/opencode/index.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-node'\nimport { z } from 'zod'\nimport { gnuDirname } from '@struktoai/mirage-core'\n\nexport interface ToolContext {\n sessionID: string\n messageID: string\n agent: string\n abort: AbortSignal\n}\n\nexport type WsResolver = (ctx: ToolContext) => Workspace | Promise<Workspace>\nexport type WsLike = Workspace | WsResolver\n\ninterface ToolDefinition<Args extends z.ZodRawShape = z.ZodRawShape> {\n description: string\n args: Args\n execute(args: z.infer<z.ZodObject<Args>>, context: ToolContext): Promise<string>\n}\n\nfunction tool<Args extends z.ZodRawShape>(input: ToolDefinition<Args>): ToolDefinition<Args> {\n return input\n}\n\nfunction isResolver(ws: WsLike): ws is WsResolver {\n return typeof ws === 'function'\n}\n\nasync function resolveWs(ws: WsLike, ctx: ToolContext): Promise<Workspace> {\n return isResolver(ws) ? ws(ctx) : ws\n}\n\nasync function ensureParent(ws: Workspace, path: string): Promise<void> {\n const parent = gnuDirname(path)\n if (parent === '/' || parent === '' || parent === '.') return\n if (await ws.fs.exists(parent)) return\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nconst TEXT_EXTS = new Set([\n 'txt',\n 'md',\n 'json',\n 'jsonl',\n 'yaml',\n 'yml',\n 'csv',\n 'tsv',\n 'xml',\n 'html',\n 'htm',\n 'js',\n 'mjs',\n 'cjs',\n 'ts',\n 'tsx',\n 'jsx',\n 'py',\n 'rb',\n 'rs',\n 'go',\n 'java',\n 'c',\n 'cpp',\n 'h',\n 'hpp',\n 'sh',\n 'bash',\n 'zsh',\n 'sql',\n 'log',\n 'env',\n 'ini',\n 'toml',\n 'conf',\n 'cfg',\n])\n\nfunction extOf(path: string): string {\n const dot = path.lastIndexOf('.')\n if (dot < 0) return ''\n return path.slice(dot + 1).toLowerCase()\n}\n\nfunction isLikelyText(path: string): boolean {\n return TEXT_EXTS.has(extOf(path))\n}\n\nfunction errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nexport function mirageTools(ws: WsLike): Record<string, ToolDefinition> {\n const read = tool({\n description:\n 'Read a file. Returns UTF-8 text for source/data files; for binary files returns a metadata stub. Use the bash tool to inspect binaries.',\n args: {\n filePath: z.string().describe('Absolute path of the file to read.'),\n },\n execute: async ({ filePath }, ctx) => {\n const w = await resolveWs(ws, ctx)\n let bytes: Uint8Array\n try {\n bytes = await w.fs.readFile(filePath)\n } catch (err) {\n return `Error: ${errMsg(err)}`\n }\n if (isLikelyText(filePath)) {\n return new TextDecoder('utf-8', { fatal: false }).decode(bytes)\n }\n return `Binary file ${filePath} (${String(bytes.length)} bytes). Use the bash tool with head/file/wc/od to inspect.`\n },\n })\n\n const write = tool({\n description: 'Write content to a file. Creates missing parent directories.',\n args: {\n filePath: z.string().describe('Absolute path of the file to write.'),\n content: z.string().describe('UTF-8 text content to write.'),\n },\n execute: async ({ filePath, content }, ctx) => {\n const w = await resolveWs(ws, ctx)\n await ensureParent(w, filePath)\n await w.fs.writeFile(filePath, content)\n return `Wrote ${String(content.length)} bytes to ${filePath}`\n },\n })\n\n const edit = tool({\n description:\n 'Replace a string inside an existing file. Errors if the string appears more than once unless replaceAll is true.',\n args: {\n filePath: z.string().describe('Absolute path of the file to edit.'),\n oldString: z.string().describe('The exact string to replace.'),\n newString: z.string().describe('The replacement string.'),\n replaceAll: z\n .boolean()\n .optional()\n .describe('Replace every occurrence rather than requiring a unique match.'),\n },\n execute: async ({ filePath, oldString, newString, replaceAll }, ctx) => {\n const w = await resolveWs(ws, ctx)\n let current: string\n try {\n current = await w.fs.readFileText(filePath)\n } catch {\n return `Error: file '${filePath}' not found`\n }\n const count = current.split(oldString).length - 1\n if (count === 0) {\n return `Error: string not found in file: '${oldString}'`\n }\n if (count > 1 && replaceAll !== true) {\n return `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`\n }\n const next =\n replaceAll === true\n ? current.split(oldString).join(newString)\n : current.replace(oldString, newString)\n await w.fs.writeFile(filePath, next)\n const occurrences = replaceAll === true ? count : 1\n return `Edited ${filePath} (${String(occurrences)} occurrence${occurrences === 1 ? '' : 's'})`\n },\n })\n\n const ls = tool({\n description: 'List entries of a directory.',\n args: {\n path: z.string().describe('Absolute directory path.'),\n },\n execute: async ({ path }, ctx) => {\n const w = await resolveWs(ws, ctx)\n let entries: string[]\n try {\n entries = await w.fs.readdir(path)\n } catch (err) {\n return `Error: ${errMsg(err)}`\n }\n const lines: string[] = []\n for (const entry of entries) {\n const isDir = await w.fs.isDir(entry)\n lines.push(isDir ? `${entry}/` : entry)\n }\n return lines.join('\\n')\n },\n })\n\n const bash = tool({\n description: 'Execute a shell command and return stdout, stderr, and exit code.',\n args: {\n command: z.string().describe('The shell command to execute.'),\n },\n execute: async ({ command }, ctx) => {\n const w = await resolveWs(ws, ctx)\n const io = await w.execute(command)\n const parts: string[] = []\n if (io.stdoutText.length > 0) parts.push(io.stdoutText)\n if (io.stderrText.length > 0) parts.push(io.stderrText)\n return parts.join('\\n').trim()\n },\n })\n\n const glob = tool({\n description: 'Find files matching a name pattern.',\n args: {\n pattern: z.string().describe('Filename pattern (e.g. \"*.ts\").'),\n path: z.string().optional().describe('Directory to search under. Defaults to /.'),\n },\n execute: async ({ pattern, path }, ctx) => {\n const w = await resolveWs(ws, ctx)\n const root = path ?? '/'\n const io = await w.execute(`find ${root} -name '${pattern.replace(/'/g, \"'\\\\''\")}'`)\n return io.stdoutText.trim()\n },\n })\n\n const grep = tool({\n description: 'Search for a regex pattern in files.',\n args: {\n pattern: z.string().describe('Pattern to search for.'),\n path: z.string().optional().describe('Directory or file to search under. Defaults to /.'),\n },\n execute: async ({ pattern, path }, ctx) => {\n const w = await resolveWs(ws, ctx)\n const root = path ?? '/'\n const escaped = pattern.replace(/'/g, \"'\\\\''\")\n const io = await w.execute(`grep -rn '${escaped}' ${root}`)\n return io.stdoutText.trim()\n },\n })\n\n return { read, write, edit, ls, bash, glob, grep }\n}\n\ninterface Hooks {\n tool?: Record<string, ToolDefinition>\n}\n\ntype PluginFn = (input: unknown) => Promise<Hooks>\n\nexport function miragePlugin(ws: WsLike): PluginFn {\n return () => Promise.resolve({ tool: mirageTools(ws) })\n}\n"],"mappings":"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","names":[]}
|
package/dist/pi/index.js
CHANGED
|
@@ -16,8 +16,9 @@ import {
|
|
|
16
16
|
|
|
17
17
|
// src/pi/operations.ts
|
|
18
18
|
import picomatch from "picomatch";
|
|
19
|
+
import { rstripSlash } from "@struktoai/mirage-core";
|
|
19
20
|
async function ensureParent(ws, dir) {
|
|
20
|
-
const norm = dir
|
|
21
|
+
const norm = rstripSlash(dir) || "/";
|
|
21
22
|
if (norm === "/" || await ws.fs.exists(norm)) return;
|
|
22
23
|
const parent = norm.substring(0, norm.lastIndexOf("/")) || "/";
|
|
23
24
|
await ensureParent(ws, parent);
|
|
@@ -90,7 +91,7 @@ function mirageOperations(ws) {
|
|
|
90
91
|
glob: async (pattern, cwd, options) => {
|
|
91
92
|
const matcher = picomatch(pattern, { dot: false });
|
|
92
93
|
const ignoreMatchers = options.ignore.map((p) => picomatch(p, { dot: false }));
|
|
93
|
-
const root = cwd
|
|
94
|
+
const root = rstripSlash(cwd) || "/";
|
|
94
95
|
const cwdPrefix = root === "/" ? "/" : `${root}/`;
|
|
95
96
|
const results = [];
|
|
96
97
|
await walkDirectory(
|
|
@@ -112,7 +113,7 @@ function mirageOperations(ws) {
|
|
|
112
113
|
},
|
|
113
114
|
readdir: async (absolutePath) => {
|
|
114
115
|
const entries = await ws.fs.readdir(absolutePath);
|
|
115
|
-
const prefix = absolutePath === "/" ? "/" : `${absolutePath
|
|
116
|
+
const prefix = absolutePath === "/" ? "/" : `${rstripSlash(absolutePath)}/`;
|
|
116
117
|
return entries.map((e) => e.startsWith(prefix) ? e.slice(prefix.length) : e);
|
|
117
118
|
}
|
|
118
119
|
};
|
package/dist/pi/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pi/extension.ts","../../src/pi/operations.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-core'\nimport {\n createBashToolDefinition,\n createEditToolDefinition,\n createFindToolDefinition,\n createGrepToolDefinition,\n createLsToolDefinition,\n createReadToolDefinition,\n createWriteToolDefinition,\n type ExtensionFactory,\n} from '@mariozechner/pi-coding-agent'\nimport { mirageOperations } from './operations.ts'\n\nexport interface MirageExtensionOptions {\n cwd?: string\n}\n\nexport function mirageExtension(\n ws: Workspace,\n opts: MirageExtensionOptions = {},\n): ExtensionFactory {\n const cwd = opts.cwd ?? '/'\n const ops = mirageOperations(ws)\n return (pi) => {\n pi.registerTool(createReadToolDefinition(cwd, { operations: ops.read }))\n pi.registerTool(createWriteToolDefinition(cwd, { operations: ops.write }))\n pi.registerTool(createEditToolDefinition(cwd, { operations: ops.edit }))\n pi.registerTool(createBashToolDefinition(cwd, { operations: ops.bash }))\n pi.registerTool(createGrepToolDefinition(cwd, { operations: ops.grep }))\n pi.registerTool(createFindToolDefinition(cwd, { operations: ops.find }))\n pi.registerTool(createLsToolDefinition(cwd, { operations: ops.ls }))\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 { Workspace } from '@struktoai/mirage-core'\nimport type {\n BashOperations,\n EditOperations,\n FindOperations,\n GrepOperations,\n LsOperations,\n ReadOperations,\n WriteOperations,\n} from '@mariozechner/pi-coding-agent'\nimport picomatch from 'picomatch'\n\nexport interface MirageOperationsBundle {\n read: ReadOperations\n write: WriteOperations\n edit: EditOperations\n bash: BashOperations\n grep: GrepOperations\n find: FindOperations\n ls: LsOperations\n}\n\nasync function ensureParent(ws: Workspace, dir: string): Promise<void> {\n const norm = dir.replace(/\\/+$/, '') || '/'\n if (norm === '/' || (await ws.fs.exists(norm))) return\n const parent = norm.substring(0, norm.lastIndexOf('/')) || '/'\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(norm)\n } catch (err) {\n if (await ws.fs.isDir(norm)) return\n throw err\n }\n}\n\ninterface WalkOptions {\n ignoreMatchers: ((path: string) => boolean)[]\n limit: number\n}\n\nasync function walkDirectory(\n ws: Workspace,\n dir: string,\n cwdPrefix: string,\n matcher: (relativePath: string) => boolean,\n opts: WalkOptions,\n results: string[],\n): Promise<void> {\n if (results.length >= opts.limit) return\n let entries: string[]\n try {\n entries = await ws.fs.readdir(dir)\n } catch {\n return\n }\n for (const full of entries) {\n if (results.length >= opts.limit) return\n const rel = full.startsWith(cwdPrefix) ? full.slice(cwdPrefix.length) : full\n if (opts.ignoreMatchers.some((m) => m(rel))) continue\n const isDir = await ws.fs.isDir(full)\n if (matcher(rel)) results.push(full)\n if (isDir) await walkDirectory(ws, full, cwdPrefix, matcher, opts, results)\n }\n}\n\nexport function mirageOperations(ws: Workspace): MirageOperationsBundle {\n const read: ReadOperations = {\n readFile: async (absolutePath: string) => {\n const bytes = await ws.fs.readFile(absolutePath, { raw: true })\n return Buffer.from(bytes)\n },\n access: async (absolutePath: string) => {\n await ws.fs.stat(absolutePath)\n },\n }\n\n const write: WriteOperations = {\n writeFile: async (absolutePath: string, content: string) => {\n await ws.fs.writeFile(absolutePath, content)\n },\n mkdir: async (dir: string) => {\n await ensureParent(ws, dir)\n if (!(await ws.fs.exists(dir))) {\n await ws.fs.mkdir(dir)\n }\n },\n }\n\n const edit: EditOperations = {\n readFile: read.readFile,\n writeFile: write.writeFile,\n access: read.access,\n }\n\n const bash: BashOperations = {\n exec: async (command, _cwd, options) => {\n const result = await ws.execute(command)\n const combined = result.stdoutText + result.stderrText\n if (combined.length > 0) {\n options.onData(Buffer.from(combined))\n }\n return { exitCode: result.exitCode }\n },\n }\n\n const grep: GrepOperations = {\n isDirectory: async (absolutePath: string) => ws.fs.isDir(absolutePath),\n readFile: async (absolutePath: string) => ws.fs.readFileText(absolutePath),\n }\n\n const find: FindOperations = {\n exists: async (absolutePath: string) => ws.fs.exists(absolutePath),\n glob: async (pattern, cwd, options) => {\n const matcher = picomatch(pattern, { dot: false })\n const ignoreMatchers = options.ignore.map((p) => picomatch(p, { dot: false }))\n const root = cwd.replace(/\\/+$/, '') || '/'\n const cwdPrefix = root === '/' ? '/' : `${root}/`\n const results: string[] = []\n await walkDirectory(\n ws,\n root,\n cwdPrefix,\n matcher,\n { ignoreMatchers, limit: options.limit },\n results,\n )\n return results\n },\n }\n\n const ls: LsOperations = {\n exists: async (absolutePath: string) => ws.fs.exists(absolutePath),\n stat: async (absolutePath: string) => {\n const isDir = await ws.fs.isDir(absolutePath)\n return { isDirectory: () => isDir }\n },\n readdir: async (absolutePath: string) => {\n const entries = await ws.fs.readdir(absolutePath)\n const prefix = absolutePath === '/' ? '/' : `${absolutePath.replace(/\\/+$/, '')}/`\n return entries.map((e) => (e.startsWith(prefix) ? e.slice(prefix.length) : e))\n },\n }\n\n return { read, write, edit, bash, grep, find, ls }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/pi/extension.ts","../../src/pi/operations.ts"],"sourcesContent":["// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-core'\nimport {\n createBashToolDefinition,\n createEditToolDefinition,\n createFindToolDefinition,\n createGrepToolDefinition,\n createLsToolDefinition,\n createReadToolDefinition,\n createWriteToolDefinition,\n type ExtensionFactory,\n} from '@mariozechner/pi-coding-agent'\nimport { mirageOperations } from './operations.ts'\n\nexport interface MirageExtensionOptions {\n cwd?: string\n}\n\nexport function mirageExtension(\n ws: Workspace,\n opts: MirageExtensionOptions = {},\n): ExtensionFactory {\n const cwd = opts.cwd ?? '/'\n const ops = mirageOperations(ws)\n return (pi) => {\n pi.registerTool(createReadToolDefinition(cwd, { operations: ops.read }))\n pi.registerTool(createWriteToolDefinition(cwd, { operations: ops.write }))\n pi.registerTool(createEditToolDefinition(cwd, { operations: ops.edit }))\n pi.registerTool(createBashToolDefinition(cwd, { operations: ops.bash }))\n pi.registerTool(createGrepToolDefinition(cwd, { operations: ops.grep }))\n pi.registerTool(createFindToolDefinition(cwd, { operations: ops.find }))\n pi.registerTool(createLsToolDefinition(cwd, { operations: ops.ls }))\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 { Workspace } from '@struktoai/mirage-core'\nimport type {\n BashOperations,\n EditOperations,\n FindOperations,\n GrepOperations,\n LsOperations,\n ReadOperations,\n WriteOperations,\n} from '@mariozechner/pi-coding-agent'\nimport picomatch from 'picomatch'\nimport { rstripSlash } from '@struktoai/mirage-core'\n\nexport interface MirageOperationsBundle {\n read: ReadOperations\n write: WriteOperations\n edit: EditOperations\n bash: BashOperations\n grep: GrepOperations\n find: FindOperations\n ls: LsOperations\n}\n\nasync function ensureParent(ws: Workspace, dir: string): Promise<void> {\n const norm = rstripSlash(dir) || '/'\n if (norm === '/' || (await ws.fs.exists(norm))) return\n const parent = norm.substring(0, norm.lastIndexOf('/')) || '/'\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(norm)\n } catch (err) {\n if (await ws.fs.isDir(norm)) return\n throw err\n }\n}\n\ninterface WalkOptions {\n ignoreMatchers: ((path: string) => boolean)[]\n limit: number\n}\n\nasync function walkDirectory(\n ws: Workspace,\n dir: string,\n cwdPrefix: string,\n matcher: (relativePath: string) => boolean,\n opts: WalkOptions,\n results: string[],\n): Promise<void> {\n if (results.length >= opts.limit) return\n let entries: string[]\n try {\n entries = await ws.fs.readdir(dir)\n } catch {\n return\n }\n for (const full of entries) {\n if (results.length >= opts.limit) return\n const rel = full.startsWith(cwdPrefix) ? full.slice(cwdPrefix.length) : full\n if (opts.ignoreMatchers.some((m) => m(rel))) continue\n const isDir = await ws.fs.isDir(full)\n if (matcher(rel)) results.push(full)\n if (isDir) await walkDirectory(ws, full, cwdPrefix, matcher, opts, results)\n }\n}\n\nexport function mirageOperations(ws: Workspace): MirageOperationsBundle {\n const read: ReadOperations = {\n readFile: async (absolutePath: string) => {\n const bytes = await ws.fs.readFile(absolutePath, { raw: true })\n return Buffer.from(bytes)\n },\n access: async (absolutePath: string) => {\n await ws.fs.stat(absolutePath)\n },\n }\n\n const write: WriteOperations = {\n writeFile: async (absolutePath: string, content: string) => {\n await ws.fs.writeFile(absolutePath, content)\n },\n mkdir: async (dir: string) => {\n await ensureParent(ws, dir)\n if (!(await ws.fs.exists(dir))) {\n await ws.fs.mkdir(dir)\n }\n },\n }\n\n const edit: EditOperations = {\n readFile: read.readFile,\n writeFile: write.writeFile,\n access: read.access,\n }\n\n const bash: BashOperations = {\n exec: async (command, _cwd, options) => {\n const result = await ws.execute(command)\n const combined = result.stdoutText + result.stderrText\n if (combined.length > 0) {\n options.onData(Buffer.from(combined))\n }\n return { exitCode: result.exitCode }\n },\n }\n\n const grep: GrepOperations = {\n isDirectory: async (absolutePath: string) => ws.fs.isDir(absolutePath),\n readFile: async (absolutePath: string) => ws.fs.readFileText(absolutePath),\n }\n\n const find: FindOperations = {\n exists: async (absolutePath: string) => ws.fs.exists(absolutePath),\n glob: async (pattern, cwd, options) => {\n const matcher = picomatch(pattern, { dot: false })\n const ignoreMatchers = options.ignore.map((p) => picomatch(p, { dot: false }))\n const root = rstripSlash(cwd) || '/'\n const cwdPrefix = root === '/' ? '/' : `${root}/`\n const results: string[] = []\n await walkDirectory(\n ws,\n root,\n cwdPrefix,\n matcher,\n { ignoreMatchers, limit: options.limit },\n results,\n )\n return results\n },\n }\n\n const ls: LsOperations = {\n exists: async (absolutePath: string) => ws.fs.exists(absolutePath),\n stat: async (absolutePath: string) => {\n const isDir = await ws.fs.isDir(absolutePath)\n return { isDirectory: () => isDir }\n },\n readdir: async (absolutePath: string) => {\n const entries = await ws.fs.readdir(absolutePath)\n const prefix = absolutePath === '/' ? '/' : `${rstripSlash(absolutePath)}/`\n return entries.map((e) => (e.startsWith(prefix) ? e.slice(prefix.length) : e))\n },\n }\n\n return { read, write, edit, bash, grep, find, ls }\n}\n"],"mappings":"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","names":[]}
|
package/dist/vercel/index.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
// src/vercel/index.ts
|
|
2
|
-
import { encodeBase64 } from "@struktoai/mirage-core";
|
|
2
|
+
import { encodeBase64, gnuDirname } from "@struktoai/mirage-core";
|
|
3
3
|
import { tool } from "ai";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
function parentOf(path) {
|
|
6
|
-
const trimmed = path.replace(/\/+$/, "");
|
|
7
|
-
const idx = trimmed.lastIndexOf("/");
|
|
8
|
-
if (idx <= 0) return "/";
|
|
9
|
-
return trimmed.slice(0, idx);
|
|
10
|
-
}
|
|
11
5
|
async function ensureParent(ws, path) {
|
|
12
|
-
const parent =
|
|
13
|
-
if (parent === "/" || parent === "") return;
|
|
6
|
+
const parent = gnuDirname(path);
|
|
7
|
+
if (parent === "/" || parent === "" || parent === ".") return;
|
|
14
8
|
if (await ws.fs.exists(parent)) return;
|
|
15
9
|
await ensureParent(ws, parent);
|
|
16
10
|
try {
|
package/dist/vercel/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/vercel/index.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 { encodeBase64 } from '@struktoai/mirage-core'\nimport type { Workspace } from '@struktoai/mirage-node'\nimport { tool } from 'ai'\nimport { z } from 'zod'\n\nfunction parentOf(path: string): string {\n const trimmed = path.replace(/\\/+$/, '')\n const idx = trimmed.lastIndexOf('/')\n if (idx <= 0) return '/'\n return trimmed.slice(0, idx)\n}\n\nasync function ensureParent(ws: Workspace, path: string): Promise<void> {\n const parent = parentOf(path)\n if (parent === '/' || parent === '') return\n if (await ws.fs.exists(parent)) return\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nconst TEXT_EXTS = new Set([\n 'txt',\n 'md',\n 'json',\n 'jsonl',\n 'yaml',\n 'yml',\n 'csv',\n 'tsv',\n 'xml',\n 'html',\n 'htm',\n 'js',\n 'mjs',\n 'cjs',\n 'ts',\n 'tsx',\n 'jsx',\n 'py',\n 'rb',\n 'rs',\n 'go',\n 'java',\n 'c',\n 'cpp',\n 'h',\n 'hpp',\n 'sh',\n 'bash',\n 'zsh',\n 'sql',\n 'log',\n 'env',\n 'ini',\n 'toml',\n 'conf',\n 'cfg',\n])\n\nconst PRESENTABLE_BINARY = new Set([\n 'application/pdf',\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n])\n\nfunction extOf(path: string): string {\n const dot = path.lastIndexOf('.')\n if (dot < 0) return ''\n return path.slice(dot + 1).toLowerCase()\n}\n\nfunction mimeFor(path: string): string {\n const ext = extOf(path)\n if (ext === 'json' || ext === 'jsonl') return 'application/json'\n if (ext === 'csv') return 'text/csv'\n if (ext === 'html' || ext === 'htm') return 'text/html'\n if (ext === 'md') return 'text/markdown'\n if (TEXT_EXTS.has(ext)) return 'text/plain'\n if (ext === 'png') return 'image/png'\n if (ext === 'jpg' || ext === 'jpeg') return 'image/jpeg'\n if (ext === 'gif') return 'image/gif'\n if (ext === 'webp') return 'image/webp'\n if (ext === 'pdf') return 'application/pdf'\n return 'application/octet-stream'\n}\n\nfunction isTextMime(mime: string): boolean {\n return mime.startsWith('text/') || mime === 'application/json'\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n return encodeBase64(bytes)\n}\n\ntype ReadFileResult =\n | { kind: 'text'; path: string; mimeType: string; content: string; bytes: number }\n | { kind: 'media'; path: string; mimeType: string; base64: string; bytes: number }\n | { kind: 'binary'; path: string; mimeType: string; bytes: number; note: string }\n | { error: string }\n\nfunction isError(r: ReadFileResult): r is { error: string } {\n return 'error' in r\n}\n\nexport function mirageTools(ws: Workspace) {\n return {\n execute: tool({\n description:\n 'Execute a shell command in the Mirage workspace and return stdout, stderr, and exitCode.',\n inputSchema: z.object({\n command: z.string().describe('The shell command to execute.'),\n }),\n execute: async ({ command }) => {\n const io = await ws.execute(command)\n return {\n stdout: io.stdoutText,\n stderr: io.stderrText,\n exitCode: io.exitCode,\n }\n },\n }),\n\n readFile: tool({\n description:\n 'Read a file from the Mirage workspace. Text files (utf-8 source/data) come back as text; PDFs and images (png/jpeg/gif/webp) come back as base64 media that is forwarded to the model as a multimodal attachment; other binaries return a metadata stub.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path inside the workspace.'),\n }),\n execute: async ({ path }): Promise<ReadFileResult> => {\n let bytes: Uint8Array\n try {\n bytes = await ws.fs.readFile(path)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const mimeType = mimeFor(path)\n if (isTextMime(mimeType)) {\n return {\n kind: 'text',\n path,\n mimeType,\n content: new TextDecoder('utf-8', { fatal: false }).decode(bytes),\n bytes: bytes.length,\n }\n }\n if (PRESENTABLE_BINARY.has(mimeType)) {\n return {\n kind: 'media',\n path,\n mimeType,\n base64: bytesToBase64(bytes),\n bytes: bytes.length,\n }\n }\n return {\n kind: 'binary',\n path,\n mimeType,\n bytes: bytes.length,\n note: `Binary file ${path} (${mimeType}, ${String(bytes.length)} bytes). Use the execute tool with shell commands (head, file, wc, od) to inspect.`,\n }\n },\n toModelOutput: ({ output }) => {\n const out: ReadFileResult = output\n if (isError(out)) return { type: 'error-text', value: out.error }\n if (out.kind === 'text') return { type: 'text', value: out.content }\n if (out.kind === 'media') {\n return {\n type: 'content',\n value: [\n {\n type: 'text',\n text: `[${out.path}] ${out.mimeType} (${String(out.bytes)} bytes)`,\n },\n { type: 'media', data: out.base64, mediaType: out.mimeType },\n ],\n }\n }\n return { type: 'text', value: out.note }\n },\n }),\n\n writeFile: tool({\n description:\n 'Write content to a file in the Mirage workspace. Creates missing parent directories.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path inside the workspace.'),\n content: z.string().describe('UTF-8 text content to write.'),\n }),\n execute: async ({ path, content }) => {\n await ensureParent(ws, path)\n await ws.fs.writeFile(path, content)\n return { path }\n },\n }),\n\n editFile: tool({\n description:\n 'Replace a string inside an existing file. Errors if the string appears more than once unless replaceAll is true.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path of the file to edit.'),\n oldString: z.string().describe('The exact string to replace.'),\n newString: z.string().describe('The replacement string.'),\n replaceAll: z\n .boolean()\n .optional()\n .describe('Replace every occurrence rather than requiring a unique match.'),\n }),\n execute: async ({ path, oldString, newString, replaceAll }) => {\n let current: string\n try {\n current = await ws.fs.readFileText(path)\n } catch {\n return { error: `Error: file '${path}' not found` }\n }\n const count = current.split(oldString).length - 1\n if (count === 0) {\n return { error: `Error: string not found in file: '${oldString}'` }\n }\n if (count > 1 && replaceAll !== true) {\n return {\n error: `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`,\n }\n }\n const next =\n replaceAll === true\n ? current.split(oldString).join(newString)\n : current.replace(oldString, newString)\n await ws.fs.writeFile(path, next)\n return { path, occurrences: replaceAll === true ? count : 1 }\n },\n }),\n\n ls: tool({\n description: 'List entries of a directory in the Mirage workspace.',\n inputSchema: z.object({\n path: z.string().describe('Absolute directory path inside the workspace.'),\n }),\n execute: async ({ path }) => {\n let entries: string[]\n try {\n entries = await ws.fs.readdir(path)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const files: { path: string; is_dir: boolean }[] = []\n for (const entry of entries) {\n const isDir = await ws.fs.isDir(entry)\n files.push({ path: entry, is_dir: isDir })\n }\n return { files }\n },\n }),\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/vercel/index.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 { encodeBase64, gnuDirname } from '@struktoai/mirage-core'\nimport type { Workspace } from '@struktoai/mirage-node'\nimport { tool } from 'ai'\nimport { z } from 'zod'\n\nasync function ensureParent(ws: Workspace, path: string): Promise<void> {\n const parent = gnuDirname(path)\n if (parent === '/' || parent === '' || parent === '.') return\n if (await ws.fs.exists(parent)) return\n await ensureParent(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nconst TEXT_EXTS = new Set([\n 'txt',\n 'md',\n 'json',\n 'jsonl',\n 'yaml',\n 'yml',\n 'csv',\n 'tsv',\n 'xml',\n 'html',\n 'htm',\n 'js',\n 'mjs',\n 'cjs',\n 'ts',\n 'tsx',\n 'jsx',\n 'py',\n 'rb',\n 'rs',\n 'go',\n 'java',\n 'c',\n 'cpp',\n 'h',\n 'hpp',\n 'sh',\n 'bash',\n 'zsh',\n 'sql',\n 'log',\n 'env',\n 'ini',\n 'toml',\n 'conf',\n 'cfg',\n])\n\nconst PRESENTABLE_BINARY = new Set([\n 'application/pdf',\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n])\n\nfunction extOf(path: string): string {\n const dot = path.lastIndexOf('.')\n if (dot < 0) return ''\n return path.slice(dot + 1).toLowerCase()\n}\n\nfunction mimeFor(path: string): string {\n const ext = extOf(path)\n if (ext === 'json' || ext === 'jsonl') return 'application/json'\n if (ext === 'csv') return 'text/csv'\n if (ext === 'html' || ext === 'htm') return 'text/html'\n if (ext === 'md') return 'text/markdown'\n if (TEXT_EXTS.has(ext)) return 'text/plain'\n if (ext === 'png') return 'image/png'\n if (ext === 'jpg' || ext === 'jpeg') return 'image/jpeg'\n if (ext === 'gif') return 'image/gif'\n if (ext === 'webp') return 'image/webp'\n if (ext === 'pdf') return 'application/pdf'\n return 'application/octet-stream'\n}\n\nfunction isTextMime(mime: string): boolean {\n return mime.startsWith('text/') || mime === 'application/json'\n}\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n return encodeBase64(bytes)\n}\n\ntype ReadFileResult =\n | { kind: 'text'; path: string; mimeType: string; content: string; bytes: number }\n | { kind: 'media'; path: string; mimeType: string; base64: string; bytes: number }\n | { kind: 'binary'; path: string; mimeType: string; bytes: number; note: string }\n | { error: string }\n\nfunction isError(r: ReadFileResult): r is { error: string } {\n return 'error' in r\n}\n\nexport function mirageTools(ws: Workspace) {\n return {\n execute: tool({\n description:\n 'Execute a shell command in the Mirage workspace and return stdout, stderr, and exitCode.',\n inputSchema: z.object({\n command: z.string().describe('The shell command to execute.'),\n }),\n execute: async ({ command }) => {\n const io = await ws.execute(command)\n return {\n stdout: io.stdoutText,\n stderr: io.stderrText,\n exitCode: io.exitCode,\n }\n },\n }),\n\n readFile: tool({\n description:\n 'Read a file from the Mirage workspace. Text files (utf-8 source/data) come back as text; PDFs and images (png/jpeg/gif/webp) come back as base64 media that is forwarded to the model as a multimodal attachment; other binaries return a metadata stub.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path inside the workspace.'),\n }),\n execute: async ({ path }): Promise<ReadFileResult> => {\n let bytes: Uint8Array\n try {\n bytes = await ws.fs.readFile(path)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const mimeType = mimeFor(path)\n if (isTextMime(mimeType)) {\n return {\n kind: 'text',\n path,\n mimeType,\n content: new TextDecoder('utf-8', { fatal: false }).decode(bytes),\n bytes: bytes.length,\n }\n }\n if (PRESENTABLE_BINARY.has(mimeType)) {\n return {\n kind: 'media',\n path,\n mimeType,\n base64: bytesToBase64(bytes),\n bytes: bytes.length,\n }\n }\n return {\n kind: 'binary',\n path,\n mimeType,\n bytes: bytes.length,\n note: `Binary file ${path} (${mimeType}, ${String(bytes.length)} bytes). Use the execute tool with shell commands (head, file, wc, od) to inspect.`,\n }\n },\n toModelOutput: ({ output }) => {\n const out: ReadFileResult = output\n if (isError(out)) return { type: 'error-text', value: out.error }\n if (out.kind === 'text') return { type: 'text', value: out.content }\n if (out.kind === 'media') {\n return {\n type: 'content',\n value: [\n {\n type: 'text',\n text: `[${out.path}] ${out.mimeType} (${String(out.bytes)} bytes)`,\n },\n { type: 'media', data: out.base64, mediaType: out.mimeType },\n ],\n }\n }\n return { type: 'text', value: out.note }\n },\n }),\n\n writeFile: tool({\n description:\n 'Write content to a file in the Mirage workspace. Creates missing parent directories.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path inside the workspace.'),\n content: z.string().describe('UTF-8 text content to write.'),\n }),\n execute: async ({ path, content }) => {\n await ensureParent(ws, path)\n await ws.fs.writeFile(path, content)\n return { path }\n },\n }),\n\n editFile: tool({\n description:\n 'Replace a string inside an existing file. Errors if the string appears more than once unless replaceAll is true.',\n inputSchema: z.object({\n path: z.string().describe('Absolute path of the file to edit.'),\n oldString: z.string().describe('The exact string to replace.'),\n newString: z.string().describe('The replacement string.'),\n replaceAll: z\n .boolean()\n .optional()\n .describe('Replace every occurrence rather than requiring a unique match.'),\n }),\n execute: async ({ path, oldString, newString, replaceAll }) => {\n let current: string\n try {\n current = await ws.fs.readFileText(path)\n } catch {\n return { error: `Error: file '${path}' not found` }\n }\n const count = current.split(oldString).length - 1\n if (count === 0) {\n return { error: `Error: string not found in file: '${oldString}'` }\n }\n if (count > 1 && replaceAll !== true) {\n return {\n error: `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`,\n }\n }\n const next =\n replaceAll === true\n ? current.split(oldString).join(newString)\n : current.replace(oldString, newString)\n await ws.fs.writeFile(path, next)\n return { path, occurrences: replaceAll === true ? count : 1 }\n },\n }),\n\n ls: tool({\n description: 'List entries of a directory in the Mirage workspace.',\n inputSchema: z.object({\n path: z.string().describe('Absolute directory path inside the workspace.'),\n }),\n execute: async ({ path }) => {\n let entries: string[]\n try {\n entries = await ws.fs.readdir(path)\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) }\n }\n const files: { path: string; is_dir: boolean }[] = []\n for (const entry of entries) {\n const isDir = await ws.fs.isDir(entry)\n files.push({ path: entry, is_dir: isDir })\n }\n return { files }\n },\n }),\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@struktoai/mirage-agents",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3-alpha.0",
|
|
4
4
|
"description": "A Unified Virtual Filesystem For AI Agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bash",
|
|
@@ -57,6 +57,10 @@
|
|
|
57
57
|
"./mastra": {
|
|
58
58
|
"types": "./dist/mastra/index.d.ts",
|
|
59
59
|
"import": "./dist/mastra/index.js"
|
|
60
|
+
},
|
|
61
|
+
"./opencode": {
|
|
62
|
+
"types": "./dist/opencode/index.d.ts",
|
|
63
|
+
"import": "./dist/opencode/index.js"
|
|
60
64
|
}
|
|
61
65
|
},
|
|
62
66
|
"files": [
|
|
@@ -64,7 +68,7 @@
|
|
|
64
68
|
],
|
|
65
69
|
"dependencies": {
|
|
66
70
|
"picomatch": "^4.0.4",
|
|
67
|
-
"@struktoai/mirage-core": "0.0.
|
|
71
|
+
"@struktoai/mirage-core": "0.0.3-alpha.0"
|
|
68
72
|
},
|
|
69
73
|
"peerDependencies": {
|
|
70
74
|
"@mariozechner/pi-ai": "^0.70.0",
|
|
@@ -85,9 +89,9 @@
|
|
|
85
89
|
"deepagents": "^1.9.0",
|
|
86
90
|
"tsup": "^8.5.0",
|
|
87
91
|
"typescript": "^6.0.0",
|
|
88
|
-
"vitest": "^3.
|
|
92
|
+
"vitest": "^3.2.6",
|
|
89
93
|
"zod": "^4.0.0",
|
|
90
|
-
"@struktoai/mirage-node": "0.0.
|
|
94
|
+
"@struktoai/mirage-node": "0.0.3-alpha.0"
|
|
91
95
|
},
|
|
92
96
|
"scripts": {
|
|
93
97
|
"build": "tsup",
|