@struktoai/mirage-agents 0.0.3 → 0.0.4

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/claude-agent-sdk/server.ts","../../src/io-text.ts","../../src/claude-agent-sdk/descriptions.ts","../../src/claude-agent-sdk/options.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 { ExecuteResult, Workspace } from '@struktoai/mirage-core'\nimport { VERSION, gnuDirname } from '@struktoai/mirage-core'\nimport { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk'\nimport { z } from 'zod'\nimport { decode, ioToStr } from '../io-text.ts'\nimport {\n EDIT_DESCRIPTION,\n EXECUTE_DESCRIPTION,\n GREP_DESCRIPTION,\n LS_DESCRIPTION,\n READ_DESCRIPTION,\n WRITE_DESCRIPTION,\n} from './descriptions.ts'\n\nexport interface ToolResult {\n [key: string]: unknown\n content: { type: 'text'; text: string }[]\n isError?: boolean\n}\n\nfunction textResult(text: string): ToolResult {\n return { content: [{ type: 'text', text }] }\n}\n\nfunction errorResult(text: string): ToolResult {\n return { content: [{ type: 'text', text }], isError: true }\n}\n\nfunction ioResult(io: ExecuteResult): ToolResult {\n const result = textResult(ioToStr(io))\n if (io.exitCode !== 0) result.isError = true\n return result\n}\n\nfunction shQuote(value: string): string {\n return `'${value.replace(/'/g, \"'\\\\''\")}'`\n}\n\nasync function ensureParents(ws: Workspace, path: string): Promise<void> {\n const parent = gnuDirname(path)\n if (parent === '/' || parent === '' || parent === '.') return\n if (await ws.fs.exists(parent)) return\n await ensureParents(ws, parent)\n try {\n await ws.fs.mkdir(parent)\n } catch (err) {\n if (!(await ws.fs.exists(parent))) throw err\n }\n}\n\nexport async function runExecute(ws: Workspace, command: string): Promise<ToolResult> {\n return ioResult(await ws.execute(command))\n}\n\nexport async function runRead(\n ws: Workspace,\n path: string,\n offset = 0,\n limit = 2000,\n): Promise<ToolResult> {\n let data: Uint8Array\n try {\n data = await ws.fs.readFile(path)\n } catch (err) {\n if (!(await ws.fs.exists(path))) {\n return errorResult(`Error: file '${path}' not found`)\n }\n return errorResult(`Error: ${err instanceof Error ? err.message : String(err)}`)\n }\n const text = decode(data)\n const raw = text.length === 0 ? [] : text.split(/(?<=\\n)/)\n const lines = raw.length > 0 && raw[raw.length - 1] === '' ? raw.slice(0, -1) : raw\n const sliced = lines.slice(offset, offset + limit)\n const numbered = sliced.map((line, i) => `${String(i + offset + 1).padStart(6)}\\t${line}`)\n return textResult(numbered.join(''))\n}\n\nexport async function runWrite(ws: Workspace, path: string, content: string): Promise<ToolResult> {\n if (await ws.fs.exists(path)) {\n return errorResult(`Error: file '${path}' already exists`)\n }\n await ensureParents(ws, path)\n await ws.fs.writeFile(path, content)\n return textResult(`Written: ${path}`)\n}\n\nexport async function runEdit(\n ws: Workspace,\n path: string,\n oldString: string,\n newString: string,\n replaceAll = false,\n): Promise<ToolResult> {\n let content: string\n try {\n content = await ws.fs.readFileText(path)\n } catch {\n return errorResult(`Error: file '${path}' not found`)\n }\n const count = content.split(oldString).length - 1\n if (count === 0) {\n return errorResult(`Error: string not found in file: '${oldString}'`)\n }\n if (count > 1 && !replaceAll) {\n return errorResult(`Error: string appears ${String(count)} times. Pass replace_all=true`)\n }\n const newContent = replaceAll\n ? content.split(oldString).join(newString)\n : content.replace(oldString, newString)\n await ws.fs.writeFile(path, newContent)\n const occurrences = replaceAll ? count : 1\n return textResult(`Edited: ${path} (${String(occurrences)} occurrence(s))`)\n}\n\nexport async function runLs(ws: Workspace, path: string): Promise<ToolResult> {\n return ioResult(await ws.execute(`ls ${shQuote(path)}`))\n}\n\nexport async function runGrep(ws: Workspace, pattern: string, path: string): Promise<ToolResult> {\n const io = await ws.execute(`grep -rn ${shQuote(pattern)} ${shQuote(path)}`)\n return textResult(ioToStr(io))\n}\n\nexport function MirageServer(workspace: Workspace) {\n return createSdkMcpServer({\n name: 'mirage',\n version: VERSION,\n alwaysLoad: true,\n tools: [\n tool('execute_command', EXECUTE_DESCRIPTION, { command: z.string() }, (args) =>\n runExecute(workspace, args.command),\n ),\n tool(\n 'read',\n READ_DESCRIPTION,\n { path: z.string(), offset: z.number().optional(), limit: z.number().optional() },\n (args) => runRead(workspace, args.path, args.offset, args.limit),\n { annotations: { readOnlyHint: true } },\n ),\n tool('write', WRITE_DESCRIPTION, { path: z.string(), content: z.string() }, (args) =>\n runWrite(workspace, args.path, args.content),\n ),\n tool(\n 'edit',\n EDIT_DESCRIPTION,\n {\n path: z.string(),\n old_string: z.string(),\n new_string: z.string(),\n replace_all: z.boolean().optional(),\n },\n (args) => runEdit(workspace, args.path, args.old_string, args.new_string, args.replace_all),\n ),\n tool('ls', LS_DESCRIPTION, { path: z.string() }, (args) => runLs(workspace, args.path), {\n annotations: { readOnlyHint: true },\n }),\n tool(\n 'grep',\n GREP_DESCRIPTION,\n { pattern: z.string(), path: z.string() },\n (args) => runGrep(workspace, args.pattern, args.path),\n { annotations: { readOnlyHint: true } },\n ),\n ],\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { ExecuteResult } from '@struktoai/mirage-core'\n\nexport function decode(value: Uint8Array | null | undefined): string {\n if (value === null || value === undefined) return ''\n return new TextDecoder('utf-8').decode(value)\n}\n\nexport function ioToStr(io: ExecuteResult): string {\n const stdout = io.stdoutText\n const stderr = io.stderrText\n if (stderr) return stdout ? `${stdout}\\n${stderr}` : stderr\n return stdout\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nexport const EXECUTE_DESCRIPTION =\n 'Run a shell-style command on the Mirage virtual filesystem. ' +\n 'Supports cat, grep, find, head, tail, ls, wc, sort, uniq, tee, pipe, ' +\n 'and any other Unix command on mounted resources (S3, disk, RAM, etc.). ' +\n 'Also supports reading structured files: cat on .parquet/.orc/.csv returns a table.'\n\nexport const READ_DESCRIPTION =\n 'Read the contents of a file on the Mirage virtual filesystem. ' +\n 'Returns line-numbered text. ' +\n \"Optionally pass 'offset' (default 0) to start at a given line \" +\n \"and 'limit' (default 2000) to cap the number of lines returned.\"\n\nexport const WRITE_DESCRIPTION =\n 'Write content to a new file on the Mirage virtual filesystem. ' +\n 'Fails if the file already exists; use edit to modify an existing file.'\n\nexport const EDIT_DESCRIPTION =\n 'Replace a string in an existing file on the Mirage virtual filesystem. ' +\n 'Fails if old_string is not found or appears more than once. ' +\n 'Pass replace_all=true (default false) to replace every occurrence.'\n\nexport const LS_DESCRIPTION =\n 'List files and directories at the given path on the Mirage virtual filesystem.'\n\nexport const GREP_DESCRIPTION =\n 'Search for a pattern in files on the Mirage virtual filesystem. ' +\n 'Supports regex. Searches recursively under path.'\n","// ========= 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 { Options } from '@anthropic-ai/claude-agent-sdk'\nimport { buildSystemPrompt } from '../prompt.ts'\nimport { MirageServer } from './server.ts'\n\nexport interface BuildOptionsOptions {\n systemPrompt?: string\n}\n\nexport function buildOptions(workspace: Workspace, opts: BuildOptionsOptions = {}): Options {\n return {\n mcpServers: { mirage: MirageServer(workspace) },\n allowedTools: ['mcp__mirage__*'],\n systemPrompt: opts.systemPrompt ?? buildSystemPrompt({ workspace }),\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/claude-agent-sdk/server.ts","../../src/claude-agent-sdk/options.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 { VERSION } from '@struktoai/mirage-core'\nimport { createSdkMcpServer, tool } from '@anthropic-ai/claude-agent-sdk'\nimport { z } from 'zod'\nimport {\n MirageToolOperations,\n type MirageToolOperationsOptions,\n type ToolResult,\n} from '../tool-operations.ts'\nimport {\n EDIT_DESCRIPTION,\n EXECUTE_DESCRIPTION,\n GREP_DESCRIPTION,\n LS_DESCRIPTION,\n READ_DESCRIPTION,\n WRITE_DESCRIPTION,\n} from './descriptions.ts'\n\nexport async function runExecute(ws: Workspace, command: string): Promise<ToolResult> {\n return new MirageToolOperations(ws).execute(command)\n}\n\nexport async function runRead(\n ws: Workspace,\n path: string,\n offset = 0,\n limit = 2000,\n): Promise<ToolResult> {\n return new MirageToolOperations(ws).read(path, offset, limit)\n}\n\nexport async function runWrite(ws: Workspace, path: string, content: string): Promise<ToolResult> {\n return new MirageToolOperations(ws).write(path, content)\n}\n\nexport async function runEdit(\n ws: Workspace,\n path: string,\n oldString: string,\n newString: string,\n replaceAll = false,\n): Promise<ToolResult> {\n return new MirageToolOperations(ws).edit(path, oldString, newString, replaceAll)\n}\n\nexport async function runLs(ws: Workspace, path: string): Promise<ToolResult> {\n return new MirageToolOperations(ws).ls(path)\n}\n\nexport async function runGrep(ws: Workspace, pattern: string, path: string): Promise<ToolResult> {\n return new MirageToolOperations(ws).grep(pattern, path)\n}\n\nexport function MirageServer(workspace: Workspace, options: MirageToolOperationsOptions = {}) {\n const operations = new MirageToolOperations(workspace, options)\n return createSdkMcpServer({\n name: 'mirage',\n version: VERSION,\n alwaysLoad: true,\n tools: [\n tool('execute_command', EXECUTE_DESCRIPTION, { command: z.string() }, (args) =>\n operations.execute(args.command),\n ),\n tool(\n 'read',\n READ_DESCRIPTION,\n { path: z.string(), offset: z.number().optional(), limit: z.number().optional() },\n (args) => operations.read(args.path, args.offset, args.limit),\n { annotations: { readOnlyHint: true } },\n ),\n tool('write', WRITE_DESCRIPTION, { path: z.string(), content: z.string() }, (args) =>\n operations.write(args.path, args.content),\n ),\n tool(\n 'edit',\n EDIT_DESCRIPTION,\n {\n path: z.string(),\n old_string: z.string(),\n new_string: z.string(),\n replace_all: z.boolean().optional(),\n },\n (args) => operations.edit(args.path, args.old_string, args.new_string, args.replace_all),\n ),\n tool('ls', LS_DESCRIPTION, { path: z.string() }, (args) => operations.ls(args.path), {\n annotations: { readOnlyHint: true },\n }),\n tool(\n 'grep',\n GREP_DESCRIPTION,\n { pattern: z.string(), path: z.string() },\n (args) => operations.grep(args.pattern, args.path),\n { annotations: { readOnlyHint: true } },\n ),\n ],\n })\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport type { Workspace } from '@struktoai/mirage-core'\nimport type { Options } from '@anthropic-ai/claude-agent-sdk'\nimport { buildSystemPrompt } from '../prompt.ts'\nimport { MirageServer } from './server.ts'\n\nexport interface BuildOptionsOptions {\n systemPrompt?: string\n}\n\nexport function buildOptions(workspace: Workspace, opts: BuildOptionsOptions = {}): Options {\n return {\n mcpServers: { mirage: MirageServer(workspace) },\n allowedTools: ['mcp__mirage__*'],\n systemPrompt: opts.systemPrompt ?? buildSystemPrompt({ workspace }),\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,SAAS,eAAe;AACxB,SAAS,oBAAoB,YAAY;AACzC,SAAS,SAAS;AAkDX,SAAS,aAAa,WAAsB,UAAuC,CAAC,GAAG;AAC5F,QAAM,aAAa,IAAI,qBAAqB,WAAW,OAAO;AAC9D,SAAO,mBAAmB;AAAA,IACxB,MAAM;AAAA,IACN,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,QAAK;AAAA,QAAmB;AAAA,QAAqB,EAAE,SAAS,EAAE,OAAO,EAAE;AAAA,QAAG,CAAC,SACrE,WAAW,QAAQ,KAAK,OAAO;AAAA,MACjC;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA,EAAE,MAAM,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,EAAE,SAAS,GAAG,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE;AAAA,QAChF,CAAC,SAAS,WAAW,KAAK,KAAK,MAAM,KAAK,QAAQ,KAAK,KAAK;AAAA,QAC5D,EAAE,aAAa,EAAE,cAAc,KAAK,EAAE;AAAA,MACxC;AAAA,MACA;AAAA,QAAK;AAAA,QAAS;AAAA,QAAmB,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,EAAE;AAAA,QAAG,CAAC,SAC3E,WAAW,MAAM,KAAK,MAAM,KAAK,OAAO;AAAA,MAC1C;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,UACE,MAAM,EAAE,OAAO;AAAA,UACf,YAAY,EAAE,OAAO;AAAA,UACrB,YAAY,EAAE,OAAO;AAAA,UACrB,aAAa,EAAE,QAAQ,EAAE,SAAS;AAAA,QACpC;AAAA,QACA,CAAC,SAAS,WAAW,KAAK,KAAK,MAAM,KAAK,YAAY,KAAK,YAAY,KAAK,WAAW;AAAA,MACzF;AAAA,MACA,KAAK,MAAM,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,SAAS,WAAW,GAAG,KAAK,IAAI,GAAG;AAAA,QACnF,aAAa,EAAE,cAAc,KAAK;AAAA,MACpC,CAAC;AAAA,MACD;AAAA,QACE;AAAA,QACA;AAAA,QACA,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE;AAAA,QACxC,CAAC,SAAS,WAAW,KAAK,KAAK,SAAS,KAAK,IAAI;AAAA,QACjD,EAAE,aAAa,EAAE,cAAc,KAAK,EAAE;AAAA,MACxC;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ACvFO,SAAS,aAAa,WAAsB,OAA4B,CAAC,GAAY;AAC1F,SAAO;AAAA,IACL,YAAY,EAAE,QAAQ,aAAa,SAAS,EAAE;AAAA,IAC9C,cAAc,CAAC,gBAAgB;AAAA,IAC/B,cAAc,KAAK,gBAAgB,kBAAkB,EAAE,UAAU,CAAC;AAAA,EACpE;AACF;","names":[]}
@@ -0,0 +1,22 @@
1
+ import { Workspace } from '@struktoai/mirage-core';
2
+
3
+ declare class StaleMirageFileError extends Error {
4
+ readonly path: string;
5
+ constructor(path: string);
6
+ }
7
+ declare class FileVersionTracker {
8
+ private readonly ws;
9
+ private readonly enabled;
10
+ private readonly readVersions;
11
+ private readonly editVersions;
12
+ constructor(ws: Workspace, enabled?: boolean);
13
+ private currentVersion;
14
+ private assertVersion;
15
+ private recordWrite;
16
+ read(path: string): Promise<Buffer>;
17
+ readForEdit(path: string): Promise<Buffer>;
18
+ write(path: string, content: string): Promise<void>;
19
+ writeEdit(path: string, content: string): Promise<void>;
20
+ }
21
+
22
+ export { FileVersionTracker as F, StaleMirageFileError as S };
@@ -0,0 +1,14 @@
1
+ import { Workspace } from '@struktoai/mirage-core';
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { M as MirageToolOperationsOptions } from '../tool-descriptions-7CgIovZc.js';
4
+ export { E as EDIT_DESCRIPTION, a as EXECUTE_DESCRIPTION, G as GREP_DESCRIPTION, L as LS_DESCRIPTION, b as MirageToolOperations, R as READ_DESCRIPTION, T as ToolResult, W as WRITE_DESCRIPTION } from '../tool-descriptions-7CgIovZc.js';
5
+ export { F as FileVersionTracker, S as StaleMirageFileError } from '../file-version-Clij-pms.js';
6
+
7
+ interface MirageMcpServerOptions extends MirageToolOperationsOptions {
8
+ name?: string;
9
+ version?: string;
10
+ }
11
+ declare function createMirageMcpServer(workspace: Workspace, options?: MirageMcpServerOptions): McpServer;
12
+ declare function serveMirageMcp(workspace: Workspace, options?: MirageMcpServerOptions): Promise<McpServer>;
13
+
14
+ export { type MirageMcpServerOptions, MirageToolOperationsOptions, createMirageMcpServer, serveMirageMcp };
@@ -0,0 +1,100 @@
1
+ import {
2
+ EDIT_DESCRIPTION,
3
+ EXECUTE_DESCRIPTION,
4
+ GREP_DESCRIPTION,
5
+ LS_DESCRIPTION,
6
+ MirageToolOperations,
7
+ READ_DESCRIPTION,
8
+ WRITE_DESCRIPTION
9
+ } from "../chunk-OLFSAPC6.js";
10
+ import {
11
+ FileVersionTracker,
12
+ StaleMirageFileError
13
+ } from "../chunk-XEQB7N3F.js";
14
+
15
+ // src/mcp/server.ts
16
+ import { VERSION } from "@struktoai/mirage-core";
17
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
18
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
+ import { z } from "zod";
20
+ function createMirageMcpServer(workspace, options = {}) {
21
+ const operations = new MirageToolOperations(workspace, options);
22
+ const server = new McpServer({
23
+ name: options.name ?? "mirage",
24
+ version: options.version ?? VERSION
25
+ });
26
+ server.registerTool(
27
+ "execute_command",
28
+ { description: EXECUTE_DESCRIPTION, inputSchema: { command: z.string() } },
29
+ (args) => operations.execute(args.command)
30
+ );
31
+ server.registerTool(
32
+ "read",
33
+ {
34
+ description: READ_DESCRIPTION,
35
+ inputSchema: {
36
+ path: z.string(),
37
+ offset: z.number().int().min(0).optional(),
38
+ limit: z.number().int().min(1).optional()
39
+ },
40
+ annotations: { readOnlyHint: true }
41
+ },
42
+ (args) => operations.read(args.path, args.offset, args.limit)
43
+ );
44
+ server.registerTool(
45
+ "write",
46
+ { description: WRITE_DESCRIPTION, inputSchema: { path: z.string(), content: z.string() } },
47
+ (args) => operations.write(args.path, args.content)
48
+ );
49
+ server.registerTool(
50
+ "edit",
51
+ {
52
+ description: EDIT_DESCRIPTION,
53
+ inputSchema: {
54
+ path: z.string(),
55
+ old_string: z.string(),
56
+ new_string: z.string(),
57
+ replace_all: z.boolean().optional()
58
+ }
59
+ },
60
+ (args) => operations.edit(args.path, args.old_string, args.new_string, args.replace_all)
61
+ );
62
+ server.registerTool(
63
+ "ls",
64
+ {
65
+ description: LS_DESCRIPTION,
66
+ inputSchema: { path: z.string() },
67
+ annotations: { readOnlyHint: true }
68
+ },
69
+ (args) => operations.ls(args.path)
70
+ );
71
+ server.registerTool(
72
+ "grep",
73
+ {
74
+ description: GREP_DESCRIPTION,
75
+ inputSchema: { pattern: z.string(), path: z.string() },
76
+ annotations: { readOnlyHint: true }
77
+ },
78
+ (args) => operations.grep(args.pattern, args.path)
79
+ );
80
+ return server;
81
+ }
82
+ async function serveMirageMcp(workspace, options = {}) {
83
+ const server = createMirageMcpServer(workspace, options);
84
+ await server.connect(new StdioServerTransport());
85
+ return server;
86
+ }
87
+ export {
88
+ EDIT_DESCRIPTION,
89
+ EXECUTE_DESCRIPTION,
90
+ FileVersionTracker,
91
+ GREP_DESCRIPTION,
92
+ LS_DESCRIPTION,
93
+ MirageToolOperations,
94
+ READ_DESCRIPTION,
95
+ StaleMirageFileError,
96
+ WRITE_DESCRIPTION,
97
+ createMirageMcpServer,
98
+ serveMirageMcp
99
+ };
100
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/mcp/server.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 { VERSION } from '@struktoai/mirage-core'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { z } from 'zod'\nimport {\n EDIT_DESCRIPTION,\n EXECUTE_DESCRIPTION,\n GREP_DESCRIPTION,\n LS_DESCRIPTION,\n READ_DESCRIPTION,\n WRITE_DESCRIPTION,\n} from '../tool-descriptions.ts'\nimport { MirageToolOperations, type MirageToolOperationsOptions } from '../tool-operations.ts'\n\nexport interface MirageMcpServerOptions extends MirageToolOperationsOptions {\n name?: string\n version?: string\n}\n\nexport function createMirageMcpServer(\n workspace: Workspace,\n options: MirageMcpServerOptions = {},\n): McpServer {\n const operations = new MirageToolOperations(workspace, options)\n const server = new McpServer({\n name: options.name ?? 'mirage',\n version: options.version ?? VERSION,\n })\n\n server.registerTool(\n 'execute_command',\n { description: EXECUTE_DESCRIPTION, inputSchema: { command: z.string() } },\n (args) => operations.execute(args.command),\n )\n server.registerTool(\n 'read',\n {\n description: READ_DESCRIPTION,\n inputSchema: {\n path: z.string(),\n offset: z.number().int().min(0).optional(),\n limit: z.number().int().min(1).optional(),\n },\n annotations: { readOnlyHint: true },\n },\n (args) => operations.read(args.path, args.offset, args.limit),\n )\n server.registerTool(\n 'write',\n { description: WRITE_DESCRIPTION, inputSchema: { path: z.string(), content: z.string() } },\n (args) => operations.write(args.path, args.content),\n )\n server.registerTool(\n 'edit',\n {\n description: EDIT_DESCRIPTION,\n inputSchema: {\n path: z.string(),\n old_string: z.string(),\n new_string: z.string(),\n replace_all: z.boolean().optional(),\n },\n },\n (args) => operations.edit(args.path, args.old_string, args.new_string, args.replace_all),\n )\n server.registerTool(\n 'ls',\n {\n description: LS_DESCRIPTION,\n inputSchema: { path: z.string() },\n annotations: { readOnlyHint: true },\n },\n (args) => operations.ls(args.path),\n )\n server.registerTool(\n 'grep',\n {\n description: GREP_DESCRIPTION,\n inputSchema: { pattern: z.string(), path: z.string() },\n annotations: { readOnlyHint: true },\n },\n (args) => operations.grep(args.pattern, args.path),\n )\n\n return server\n}\n\nexport async function serveMirageMcp(\n workspace: Workspace,\n options: MirageMcpServerOptions = {},\n): Promise<McpServer> {\n const server = createMirageMcpServer(workspace, options)\n await server.connect(new StdioServerTransport())\n return server\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAS,eAAe;AACxB,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,SAAS;AAgBX,SAAS,sBACd,WACA,UAAkC,CAAC,GACxB;AACX,QAAM,aAAa,IAAI,qBAAqB,WAAW,OAAO;AAC9D,QAAM,SAAS,IAAI,UAAU;AAAA,IAC3B,MAAM,QAAQ,QAAQ;AAAA,IACtB,SAAS,QAAQ,WAAW;AAAA,EAC9B,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,EAAE,aAAa,qBAAqB,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;AAAA,IACzE,CAAC,SAAS,WAAW,QAAQ,KAAK,OAAO;AAAA,EAC3C;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa;AAAA,QACX,MAAM,EAAE,OAAO;AAAA,QACf,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,QACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,MAC1C;AAAA,MACA,aAAa,EAAE,cAAc,KAAK;AAAA,IACpC;AAAA,IACA,CAAC,SAAS,WAAW,KAAK,KAAK,MAAM,KAAK,QAAQ,KAAK,KAAK;AAAA,EAC9D;AACA,SAAO;AAAA,IACL;AAAA,IACA,EAAE,aAAa,mBAAmB,aAAa,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,EAAE,EAAE;AAAA,IACzF,CAAC,SAAS,WAAW,MAAM,KAAK,MAAM,KAAK,OAAO;AAAA,EACpD;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa;AAAA,QACX,MAAM,EAAE,OAAO;AAAA,QACf,YAAY,EAAE,OAAO;AAAA,QACrB,YAAY,EAAE,OAAO;AAAA,QACrB,aAAa,EAAE,QAAQ,EAAE,SAAS;AAAA,MACpC;AAAA,IACF;AAAA,IACA,CAAC,SAAS,WAAW,KAAK,KAAK,MAAM,KAAK,YAAY,KAAK,YAAY,KAAK,WAAW;AAAA,EACzF;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE;AAAA,MAChC,aAAa,EAAE,cAAc,KAAK;AAAA,IACpC;AAAA,IACA,CAAC,SAAS,WAAW,GAAG,KAAK,IAAI;AAAA,EACnC;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,aAAa,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE;AAAA,MACrD,aAAa,EAAE,cAAc,KAAK;AAAA,IACpC;AAAA,IACA,CAAC,SAAS,WAAW,KAAK,KAAK,SAAS,KAAK,IAAI;AAAA,EACnD;AAEA,SAAO;AACT;AAEA,eAAsB,eACpB,WACA,UAAkC,CAAC,GACf;AACpB,QAAM,SAAS,sBAAsB,WAAW,OAAO;AACvD,QAAM,OAAO,QAAQ,IAAI,qBAAqB,CAAC;AAC/C,SAAO;AACT;","names":[]}
@@ -1,5 +1,7 @@
1
1
  import { Workspace } from '@struktoai/mirage-core';
2
- import { Editor, ApplyPatchOperation, ApplyPatchResult, Shell, ShellAction, ShellResult } from '@openai/agents';
2
+ import * as _openai_agents from '@openai/agents';
3
+ import { Editor, ApplyPatchOperation, ApplyPatchResult, ToolOutputText, ToolOutputImage, ToolOutputFileContent, Shell, ShellAction, ShellResult } from '@openai/agents';
4
+ import { z } from 'zod';
3
5
  export { B as BuildSystemPromptOptions, M as MIRAGE_SYSTEM_PROMPT, b as buildSystemPrompt } from '../prompt-Ca4hc1Ul.js';
4
6
 
5
7
  declare class MirageEditor implements Editor {
@@ -16,10 +18,19 @@ declare class MirageEditor implements Editor {
16
18
  }>): Promise<ApplyPatchResult>;
17
19
  }
18
20
 
21
+ declare function mirageExecuteTool(ws: Workspace): _openai_agents.FunctionTool<unknown, z.ZodObject<{
22
+ command: z.ZodString;
23
+ }, z.core.$strip>, string>;
24
+
25
+ type MirageReadFileOutput = ToolOutputText | ToolOutputImage | ToolOutputFileContent;
26
+ declare function mirageReadFileTool(ws: Workspace): _openai_agents.FunctionTool<unknown, z.ZodObject<{
27
+ path: z.ZodString;
28
+ }, z.core.$strip>, string>;
29
+
19
30
  declare class MirageShell implements Shell {
20
31
  private readonly ws;
21
32
  constructor(ws: Workspace);
22
33
  run(action: ShellAction): Promise<ShellResult>;
23
34
  }
24
35
 
25
- export { MirageEditor, MirageShell };
36
+ export { MirageEditor, type MirageReadFileOutput, MirageShell, mirageExecuteTool, mirageReadFileTool };
@@ -2,6 +2,9 @@ import {
2
2
  MIRAGE_SYSTEM_PROMPT,
3
3
  buildSystemPrompt
4
4
  } from "../chunk-ODKR5YZI.js";
5
+ import {
6
+ readWorkspaceFile
7
+ } from "../chunk-IMI7BLEG.js";
5
8
 
6
9
  // src/openai/editor.ts
7
10
  import { applyDiff } from "@openai/agents";
@@ -48,6 +51,81 @@ var MirageEditor = class {
48
51
  }
49
52
  };
50
53
 
54
+ // src/openai/execute.ts
55
+ import { tool } from "@openai/agents";
56
+ import { z } from "zod";
57
+ function formatExecuteOutput(stdout, stderr, exitCode) {
58
+ const sections = [`exit code: ${String(exitCode)}`];
59
+ if (stdout !== "") sections.push(`stdout:
60
+ ${stdout}`);
61
+ if (stderr !== "") sections.push(`stderr:
62
+ ${stderr}`);
63
+ return sections.join("\n");
64
+ }
65
+ async function executeOutput(ws, command) {
66
+ try {
67
+ const result = await ws.execute(command);
68
+ return formatExecuteOutput(result.stdoutText, result.stderrText, result.exitCode);
69
+ } catch (error) {
70
+ const message = error instanceof Error ? error.message : String(error);
71
+ return `Unable to execute command: ${message}`;
72
+ }
73
+ }
74
+ function mirageExecuteTool(ws) {
75
+ return tool({
76
+ name: "execute",
77
+ description: "Execute a shell command inside the Mirage workspace and return its stdout, stderr, and exit code.",
78
+ parameters: z.object({
79
+ command: z.string().describe("Shell command to execute inside the Mirage workspace.")
80
+ }),
81
+ execute: async ({ command }) => executeOutput(ws, command)
82
+ });
83
+ }
84
+
85
+ // src/openai/read-file.ts
86
+ import {
87
+ tool as tool2
88
+ } from "@openai/agents";
89
+ import { z as z2 } from "zod";
90
+ async function readFileOutput(ws, path) {
91
+ try {
92
+ const result = await readWorkspaceFile(ws, path);
93
+ if (result.kind === "text") {
94
+ return { type: "text", text: result.content };
95
+ }
96
+ if (result.kind === "image") {
97
+ return {
98
+ type: "image",
99
+ image: { data: Uint8Array.from(result.data), mediaType: result.mimeType }
100
+ };
101
+ }
102
+ if (result.kind === "file") {
103
+ return {
104
+ type: "file",
105
+ file: {
106
+ data: Uint8Array.from(result.data),
107
+ mediaType: result.mimeType,
108
+ filename: result.filename
109
+ }
110
+ };
111
+ }
112
+ return { type: "text", text: result.note };
113
+ } catch (error) {
114
+ const message = error instanceof Error ? error.message : String(error);
115
+ return { type: "text", text: `Unable to read ${path}: ${message}` };
116
+ }
117
+ }
118
+ function mirageReadFileTool(ws) {
119
+ return tool2({
120
+ name: "read_file",
121
+ description: "Read a file from the Mirage workspace. Returns UTF-8 text directly, images as model-visible image input, PDFs as model-visible file input, and a metadata description for other binary formats.",
122
+ parameters: z2.object({
123
+ path: z2.string().describe("Absolute path inside the Mirage workspace.")
124
+ }),
125
+ execute: async ({ path }) => readFileOutput(ws, path)
126
+ });
127
+ }
128
+
51
129
  // src/openai/shell.ts
52
130
  var MirageShell = class {
53
131
  constructor(ws) {
@@ -71,6 +149,8 @@ export {
71
149
  MIRAGE_SYSTEM_PROMPT,
72
150
  MirageEditor,
73
151
  MirageShell,
74
- buildSystemPrompt
152
+ buildSystemPrompt,
153
+ mirageExecuteTool,
154
+ mirageReadFileTool
75
155
  };
76
156
  //# sourceMappingURL=index.js.map
@@ -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'\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":[]}
1
+ {"version":3,"sources":["../../src/openai/editor.ts","../../src/openai/execute.ts","../../src/openai/read-file.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 { tool } from '@openai/agents'\nimport { z } from 'zod'\n\nfunction formatExecuteOutput(stdout: string, stderr: string, exitCode: number): string {\n const sections = [`exit code: ${String(exitCode)}`]\n if (stdout !== '') sections.push(`stdout:\\n${stdout}`)\n if (stderr !== '') sections.push(`stderr:\\n${stderr}`)\n return sections.join('\\n')\n}\n\nasync function executeOutput(ws: Workspace, command: string): Promise<string> {\n try {\n const result = await ws.execute(command)\n return formatExecuteOutput(result.stdoutText, result.stderrText, result.exitCode)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return `Unable to execute command: ${message}`\n }\n}\n\nexport function mirageExecuteTool(ws: Workspace) {\n return tool({\n name: 'execute',\n description:\n 'Execute a shell command inside the Mirage workspace and return its stdout, stderr, and exit code.',\n parameters: z.object({\n command: z.string().describe('Shell command to execute inside the Mirage workspace.'),\n }),\n execute: async ({ command }) => executeOutput(ws, command),\n })\n}\n","import type { Workspace } from '@struktoai/mirage-core'\nimport {\n tool,\n type ToolOutputFileContent,\n type ToolOutputImage,\n type ToolOutputText,\n} from '@openai/agents'\nimport { z } from 'zod'\nimport { readWorkspaceFile } from '../read-file.ts'\n\nexport type MirageReadFileOutput = ToolOutputText | ToolOutputImage | ToolOutputFileContent\n\nasync function readFileOutput(ws: Workspace, path: string): Promise<MirageReadFileOutput> {\n try {\n const result = await readWorkspaceFile(ws, path)\n if (result.kind === 'text') {\n return { type: 'text', text: result.content }\n }\n if (result.kind === 'image') {\n return {\n type: 'image',\n image: { data: Uint8Array.from(result.data), mediaType: result.mimeType },\n }\n }\n if (result.kind === 'file') {\n return {\n type: 'file',\n file: {\n data: Uint8Array.from(result.data),\n mediaType: result.mimeType,\n filename: result.filename,\n },\n }\n }\n return { type: 'text', text: result.note }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return { type: 'text', text: `Unable to read ${path}: ${message}` }\n }\n}\n\nexport function mirageReadFileTool(ws: Workspace) {\n return tool({\n name: 'read_file',\n description:\n 'Read a file from the Mirage workspace. Returns UTF-8 text directly, images as model-visible image input, PDFs as model-visible file input, and a metadata description for other binary formats.',\n parameters: z.object({\n path: z.string().describe('Absolute path inside the Mirage workspace.'),\n }),\n execute: async ({ path }) => readFileOutput(ws, path),\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":"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","names":["tool","z","tool","z"]}
@@ -1,24 +1,14 @@
1
+ import { ToolContext, Plugin, ToolDefinition } from '@opencode-ai/plugin';
1
2
  import { Workspace } from '@struktoai/mirage-node';
2
- import { z } from 'zod';
3
+ export { S as StaleMirageFileError } from '../file-version-Clij-pms.js';
4
+ import '@struktoai/mirage-core';
3
5
 
4
- interface ToolContext {
5
- sessionID: string;
6
- messageID: string;
7
- agent: string;
8
- abort: AbortSignal;
9
- }
10
6
  type WsResolver = (ctx: ToolContext) => Workspace | Promise<Workspace>;
11
7
  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>;
8
+ interface MirageOpenCodeOptions {
9
+ staleWriteProtection?: boolean;
20
10
  }
21
- type PluginFn = (input: unknown) => Promise<Hooks>;
22
- declare function miragePlugin(ws: WsLike): PluginFn;
11
+ declare function mirageTools(ws: WsLike, options?: MirageOpenCodeOptions): Record<string, ToolDefinition>;
12
+ declare function miragePlugin(ws: WsLike, options?: MirageOpenCodeOptions): Plugin;
23
13
 
24
- export { type ToolContext, type WsLike, type WsResolver, miragePlugin, mirageTools };
14
+ export { type MirageOpenCodeOptions, type WsLike, type WsResolver, miragePlugin, mirageTools };
@@ -1,9 +1,15 @@
1
+ import {
2
+ readWorkspaceFile
3
+ } from "../chunk-IMI7BLEG.js";
4
+ import {
5
+ FileVersionTracker,
6
+ StaleMirageFileError
7
+ } from "../chunk-XEQB7N3F.js";
8
+
1
9
  // src/opencode/index.ts
2
- import { z } from "zod";
3
- import { gnuDirname } from "@struktoai/mirage-core";
4
- function tool(input) {
5
- return input;
6
- }
10
+ import { tool } from "@opencode-ai/plugin";
11
+ import { encodeBase64, gnuDirname } from "@struktoai/mirage-core";
12
+ var z = tool.schema;
7
13
  function isResolver(ws) {
8
14
  return typeof ws === "function";
9
15
  }
@@ -21,73 +27,54 @@ async function ensureParent(ws, path) {
21
27
  if (!await ws.fs.exists(parent)) throw err;
22
28
  }
23
29
  }
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
30
  function errMsg(err) {
71
31
  return err instanceof Error ? err.message : String(err);
72
32
  }
73
- function mirageTools(ws) {
33
+ function trackerFor(trackers, ws, ctx, enabled) {
34
+ let sessions = trackers.get(ws);
35
+ if (sessions === void 0) {
36
+ sessions = /* @__PURE__ */ new Map();
37
+ trackers.set(ws, sessions);
38
+ }
39
+ let tracker = sessions.get(ctx.sessionID);
40
+ if (tracker === void 0) {
41
+ tracker = new FileVersionTracker(ws, enabled);
42
+ sessions.set(ctx.sessionID, tracker);
43
+ }
44
+ return tracker;
45
+ }
46
+ function mirageTools(ws, options = {}) {
47
+ const trackers = /* @__PURE__ */ new WeakMap();
48
+ const staleWriteProtection = options.staleWriteProtection ?? true;
74
49
  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.",
50
+ description: "Read a file. Returns UTF-8 text for source/data files, attaches PDFs and images for multimodal models, and returns metadata for other binary files.",
76
51
  args: {
77
52
  filePath: z.string().describe("Absolute path of the file to read.")
78
53
  },
79
54
  execute: async ({ filePath }, ctx) => {
80
55
  const w = await resolveWs(ws, ctx);
81
- let bytes;
56
+ const versions = trackerFor(trackers, w, ctx, staleWriteProtection);
82
57
  try {
83
- bytes = await w.fs.readFile(filePath);
58
+ const result = await readWorkspaceFile(w, filePath, versions.read.bind(versions));
59
+ if (result.kind === "text") return result.content;
60
+ if (result.kind === "image" || result.kind === "file") {
61
+ const filename = result.path.split("/").pop() ?? result.path;
62
+ return {
63
+ output: `${result.path} (${result.mimeType}, ${String(result.bytes)} bytes)`,
64
+ attachments: [
65
+ {
66
+ type: "file",
67
+ mime: result.mimeType,
68
+ url: `data:${result.mimeType};base64,${encodeBase64(result.data)}`,
69
+ filename
70
+ }
71
+ ]
72
+ };
73
+ }
74
+ return result.note;
84
75
  } catch (err) {
85
76
  return `Error: ${errMsg(err)}`;
86
77
  }
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
78
  }
92
79
  });
93
80
  const write = tool({
@@ -98,9 +85,14 @@ function mirageTools(ws) {
98
85
  },
99
86
  execute: async ({ filePath, content }, ctx) => {
100
87
  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}`;
88
+ const versions = trackerFor(trackers, w, ctx, staleWriteProtection);
89
+ try {
90
+ await ensureParent(w, filePath);
91
+ await versions.write(filePath, content);
92
+ return `Wrote ${String(content.length)} bytes to ${filePath}`;
93
+ } catch (err) {
94
+ return `Error: ${errMsg(err)}`;
95
+ }
104
96
  }
105
97
  });
106
98
  const edit = tool({
@@ -113,10 +105,12 @@ function mirageTools(ws) {
113
105
  },
114
106
  execute: async ({ filePath, oldString, newString, replaceAll }, ctx) => {
115
107
  const w = await resolveWs(ws, ctx);
108
+ const versions = trackerFor(trackers, w, ctx, staleWriteProtection);
116
109
  let current;
117
110
  try {
118
- current = await w.fs.readFileText(filePath);
119
- } catch {
111
+ current = (await versions.readForEdit(filePath)).toString("utf8");
112
+ } catch (err) {
113
+ if (await w.fs.exists(filePath)) return `Error: ${errMsg(err)}`;
120
114
  return `Error: file '${filePath}' not found`;
121
115
  }
122
116
  const count = current.split(oldString).length - 1;
@@ -127,7 +121,11 @@ function mirageTools(ws) {
127
121
  return `Error: string '${oldString}' appears ${String(count)} times. Use replaceAll=true`;
128
122
  }
129
123
  const next = replaceAll === true ? current.split(oldString).join(newString) : current.replace(oldString, newString);
130
- await w.fs.writeFile(filePath, next);
124
+ try {
125
+ await versions.writeEdit(filePath, next);
126
+ } catch (err) {
127
+ return `Error: ${errMsg(err)}`;
128
+ }
131
129
  const occurrences = replaceAll === true ? count : 1;
132
130
  return `Edited ${filePath} (${String(occurrences)} occurrence${occurrences === 1 ? "" : "s"})`;
133
131
  }
@@ -196,10 +194,11 @@ function mirageTools(ws) {
196
194
  });
197
195
  return { read, write, edit, ls, bash, glob, grep };
198
196
  }
199
- function miragePlugin(ws) {
200
- return () => Promise.resolve({ tool: mirageTools(ws) });
197
+ function miragePlugin(ws, options = {}) {
198
+ return () => Promise.resolve({ tool: mirageTools(ws, options) });
201
199
  }
202
200
  export {
201
+ StaleMirageFileError,
203
202
  miragePlugin,
204
203
  mirageTools
205
204
  };