@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.
- package/README.md +2 -2
- package/dist/chunk-IMI7BLEG.js +142 -0
- package/dist/chunk-IMI7BLEG.js.map +1 -0
- package/dist/chunk-OLFSAPC6.js +139 -0
- package/dist/chunk-OLFSAPC6.js.map +1 -0
- package/dist/chunk-XEQB7N3F.js +79 -0
- package/dist/chunk-XEQB7N3F.js.map +1 -0
- package/dist/claude-agent-sdk/index.d.ts +4 -9
- package/dist/claude-agent-sdk/index.js +19 -110
- package/dist/claude-agent-sdk/index.js.map +1 -1
- package/dist/file-version-Clij-pms.d.ts +22 -0
- package/dist/mcp/index.d.ts +14 -0
- package/dist/mcp/index.js +100 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/openai/index.d.ts +13 -2
- package/dist/openai/index.js +81 -1
- package/dist/openai/index.js.map +1 -1
- package/dist/opencode/index.d.ts +8 -18
- package/dist/opencode/index.js +66 -67
- package/dist/opencode/index.js.map +1 -1
- package/dist/pi/index.d.ts +12 -7
- package/dist/pi/index.js +65 -36
- package/dist/pi/index.js.map +1 -1
- package/dist/tool-descriptions-7CgIovZc.d.ts +33 -0
- package/dist/vercel/index.d.ts +3 -67
- package/dist/vercel/index.js +28 -102
- package/dist/vercel/index.js.map +1 -1
- package/package.json +32 -25
|
@@ -1 +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":[]}
|
|
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 { tool, type Plugin, type ToolContext, type ToolDefinition } from '@opencode-ai/plugin'\nimport type { Workspace } from '@struktoai/mirage-node'\nimport { encodeBase64, gnuDirname } from '@struktoai/mirage-core'\nimport { FileVersionTracker } from '../file-version.ts'\nimport { readWorkspaceFile } from '../read-file.ts'\n\nconst z = tool.schema\n\nexport type WsResolver = (ctx: ToolContext) => Workspace | Promise<Workspace>\nexport type WsLike = Workspace | WsResolver\n\nexport interface MirageOpenCodeOptions {\n staleWriteProtection?: boolean\n}\n\ntype SessionTrackers = Map<string, FileVersionTracker>\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\nfunction errMsg(err: unknown): string {\n return err instanceof Error ? err.message : String(err)\n}\n\nfunction trackerFor(\n trackers: WeakMap<Workspace, SessionTrackers>,\n ws: Workspace,\n ctx: ToolContext,\n enabled: boolean,\n): FileVersionTracker {\n let sessions = trackers.get(ws)\n if (sessions === undefined) {\n sessions = new Map<string, FileVersionTracker>()\n trackers.set(ws, sessions)\n }\n let tracker = sessions.get(ctx.sessionID)\n if (tracker === undefined) {\n tracker = new FileVersionTracker(ws, enabled)\n sessions.set(ctx.sessionID, tracker)\n }\n return tracker\n}\n\nexport function mirageTools(\n ws: WsLike,\n options: MirageOpenCodeOptions = {},\n): Record<string, ToolDefinition> {\n const trackers = new WeakMap<Workspace, SessionTrackers>()\n const staleWriteProtection = options.staleWriteProtection ?? true\n const read = tool({\n description:\n '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.',\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 const versions = trackerFor(trackers, w, ctx, staleWriteProtection)\n try {\n const result = await readWorkspaceFile(w, filePath, versions.read.bind(versions))\n if (result.kind === 'text') return result.content\n if (result.kind === 'image' || result.kind === 'file') {\n const filename = result.path.split('/').pop() ?? result.path\n return {\n output: `${result.path} (${result.mimeType}, ${String(result.bytes)} bytes)`,\n attachments: [\n {\n type: 'file' as const,\n mime: result.mimeType,\n url: `data:${result.mimeType};base64,${encodeBase64(result.data)}`,\n filename,\n },\n ],\n }\n }\n return result.note\n } catch (err) {\n return `Error: ${errMsg(err)}`\n }\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 const versions = trackerFor(trackers, w, ctx, staleWriteProtection)\n try {\n await ensureParent(w, filePath)\n await versions.write(filePath, content)\n return `Wrote ${String(content.length)} bytes to ${filePath}`\n } catch (err) {\n return `Error: ${errMsg(err)}`\n }\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 const versions = trackerFor(trackers, w, ctx, staleWriteProtection)\n let current: string\n try {\n current = (await versions.readForEdit(filePath)).toString('utf8')\n } catch (err) {\n if (await w.fs.exists(filePath)) return `Error: ${errMsg(err)}`\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 try {\n await versions.writeEdit(filePath, next)\n } catch (err) {\n return `Error: ${errMsg(err)}`\n }\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\nexport function miragePlugin(ws: WsLike, options: MirageOpenCodeOptions = {}): Plugin {\n return () => Promise.resolve({ tool: mirageTools(ws, options) })\n}\n\nexport { StaleMirageFileError } from '../file-version.ts'\n"],"mappings":"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","names":[]}
|
package/dist/pi/index.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { Workspace } from '@struktoai/mirage-core';
|
|
2
|
-
import {
|
|
2
|
+
import { ReadOperations, WriteOperations, EditOperations, BashOperations, GrepOperations, FindOperations, LsOperations, InlineExtension } from '@earendil-works/pi-coding-agent';
|
|
3
3
|
export { B as BuildSystemPromptOptions, M as MIRAGE_SYSTEM_PROMPT, b as buildSystemPrompt } from '../prompt-Ca4hc1Ul.js';
|
|
4
|
+
export { S as StaleMirageFileError } from '../file-version-Clij-pms.js';
|
|
4
5
|
|
|
5
|
-
interface
|
|
6
|
-
|
|
6
|
+
interface MirageOperationsOptions {
|
|
7
|
+
staleWriteProtection?: boolean;
|
|
7
8
|
}
|
|
8
|
-
declare function mirageExtension(ws: Workspace, opts?: MirageExtensionOptions): ExtensionFactory;
|
|
9
|
-
|
|
10
9
|
interface MirageOperationsBundle {
|
|
11
10
|
read: ReadOperations;
|
|
12
11
|
write: WriteOperations;
|
|
@@ -16,6 +15,12 @@ interface MirageOperationsBundle {
|
|
|
16
15
|
find: FindOperations;
|
|
17
16
|
ls: LsOperations;
|
|
18
17
|
}
|
|
19
|
-
declare function mirageOperations(ws: Workspace): MirageOperationsBundle;
|
|
18
|
+
declare function mirageOperations(ws: Workspace, options?: MirageOperationsOptions): MirageOperationsBundle;
|
|
19
|
+
|
|
20
|
+
interface MirageExtensionOptions extends MirageOperationsOptions {
|
|
21
|
+
cwd?: string;
|
|
22
|
+
systemPrompt?: string | false;
|
|
23
|
+
}
|
|
24
|
+
declare function mirageExtension(ws: Workspace, opts?: MirageExtensionOptions): InlineExtension;
|
|
20
25
|
|
|
21
|
-
export { type MirageExtensionOptions, type MirageOperationsBundle, mirageExtension, mirageOperations };
|
|
26
|
+
export { type MirageExtensionOptions, type MirageOperationsBundle, type MirageOperationsOptions, mirageExtension, mirageOperations };
|
package/dist/pi/index.js
CHANGED
|
@@ -2,6 +2,10 @@ import {
|
|
|
2
2
|
MIRAGE_SYSTEM_PROMPT,
|
|
3
3
|
buildSystemPrompt
|
|
4
4
|
} from "../chunk-ODKR5YZI.js";
|
|
5
|
+
import {
|
|
6
|
+
FileVersionTracker,
|
|
7
|
+
StaleMirageFileError
|
|
8
|
+
} from "../chunk-XEQB7N3F.js";
|
|
5
9
|
|
|
6
10
|
// src/pi/extension.ts
|
|
7
11
|
import {
|
|
@@ -12,11 +16,11 @@ import {
|
|
|
12
16
|
createLsToolDefinition,
|
|
13
17
|
createReadToolDefinition,
|
|
14
18
|
createWriteToolDefinition
|
|
15
|
-
} from "@
|
|
19
|
+
} from "@earendil-works/pi-coding-agent";
|
|
16
20
|
|
|
17
21
|
// src/pi/operations.ts
|
|
18
|
-
import picomatch from "picomatch";
|
|
19
22
|
import { rstripSlash } from "@struktoai/mirage-core";
|
|
23
|
+
import picomatch from "picomatch";
|
|
20
24
|
async function ensureParent(ws, dir) {
|
|
21
25
|
const norm = rstripSlash(dir) || "/";
|
|
22
26
|
if (norm === "/" || await ws.fs.exists(norm)) return;
|
|
@@ -31,12 +35,7 @@ async function ensureParent(ws, dir) {
|
|
|
31
35
|
}
|
|
32
36
|
async function walkDirectory(ws, dir, cwdPrefix, matcher, opts, results) {
|
|
33
37
|
if (results.length >= opts.limit) return;
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
entries = await ws.fs.readdir(dir);
|
|
37
|
-
} catch {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
38
|
+
const entries = await ws.fs.readdir(dir);
|
|
40
39
|
for (const full of entries) {
|
|
41
40
|
if (results.length >= opts.limit) return;
|
|
42
41
|
const rel = full.startsWith(cwdPrefix) ? full.slice(cwdPrefix.length) : full;
|
|
@@ -46,20 +45,16 @@ async function walkDirectory(ws, dir, cwdPrefix, matcher, opts, results) {
|
|
|
46
45
|
if (isDir) await walkDirectory(ws, full, cwdPrefix, matcher, opts, results);
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
|
-
function mirageOperations(ws) {
|
|
48
|
+
function mirageOperations(ws, options = {}) {
|
|
49
|
+
const versions = new FileVersionTracker(ws, options.staleWriteProtection ?? true);
|
|
50
50
|
const read = {
|
|
51
|
-
readFile:
|
|
52
|
-
const bytes = await ws.fs.readFile(absolutePath, { raw: true });
|
|
53
|
-
return Buffer.from(bytes);
|
|
54
|
-
},
|
|
51
|
+
readFile: (absolutePath) => versions.read(absolutePath),
|
|
55
52
|
access: async (absolutePath) => {
|
|
56
53
|
await ws.fs.stat(absolutePath);
|
|
57
54
|
}
|
|
58
55
|
};
|
|
59
56
|
const write = {
|
|
60
|
-
writeFile:
|
|
61
|
-
await ws.fs.writeFile(absolutePath, content);
|
|
62
|
-
},
|
|
57
|
+
writeFile: (absolutePath, content) => versions.write(absolutePath, content),
|
|
63
58
|
mkdir: async (dir) => {
|
|
64
59
|
await ensureParent(ws, dir);
|
|
65
60
|
if (!await ws.fs.exists(dir)) {
|
|
@@ -68,29 +63,44 @@ function mirageOperations(ws) {
|
|
|
68
63
|
}
|
|
69
64
|
};
|
|
70
65
|
const edit = {
|
|
71
|
-
readFile:
|
|
72
|
-
writeFile:
|
|
66
|
+
readFile: (absolutePath) => versions.readForEdit(absolutePath),
|
|
67
|
+
writeFile: (absolutePath, content) => versions.writeEdit(absolutePath, content),
|
|
73
68
|
access: read.access
|
|
74
69
|
};
|
|
75
70
|
const bash = {
|
|
76
|
-
exec: async (command,
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
exec: async (command, cwd, options2) => {
|
|
72
|
+
const timeoutSignal = options2.timeout !== void 0 && options2.timeout > 0 ? AbortSignal.timeout(options2.timeout * 1e3) : void 0;
|
|
73
|
+
const signal = options2.signal !== void 0 && timeoutSignal !== void 0 ? AbortSignal.any([options2.signal, timeoutSignal]) : options2.signal ?? timeoutSignal;
|
|
74
|
+
let result;
|
|
75
|
+
try {
|
|
76
|
+
result = signal === void 0 ? await ws.execute(command, { cwd }) : await ws.execute(command, { cwd, signal });
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (options2.signal?.aborted === true) {
|
|
79
|
+
throw new Error("aborted");
|
|
80
|
+
}
|
|
81
|
+
if (timeoutSignal?.aborted === true) {
|
|
82
|
+
throw new Error("timeout:" + String(options2.timeout));
|
|
83
|
+
}
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
if (result.stdout.length > 0) {
|
|
87
|
+
options2.onData(Buffer.from(result.stdout));
|
|
88
|
+
}
|
|
89
|
+
if (result.stderr.length > 0) {
|
|
90
|
+
options2.onData(Buffer.from(result.stderr));
|
|
81
91
|
}
|
|
82
92
|
return { exitCode: result.exitCode };
|
|
83
93
|
}
|
|
84
94
|
};
|
|
85
95
|
const grep = {
|
|
86
96
|
isDirectory: async (absolutePath) => ws.fs.isDir(absolutePath),
|
|
87
|
-
readFile: async (absolutePath) =>
|
|
97
|
+
readFile: async (absolutePath) => (await versions.read(absolutePath)).toString("utf-8")
|
|
88
98
|
};
|
|
89
99
|
const find = {
|
|
90
100
|
exists: async (absolutePath) => ws.fs.exists(absolutePath),
|
|
91
|
-
glob: async (pattern, cwd,
|
|
101
|
+
glob: async (pattern, cwd, options2) => {
|
|
92
102
|
const matcher = picomatch(pattern, { dot: false });
|
|
93
|
-
const ignoreMatchers =
|
|
103
|
+
const ignoreMatchers = options2.ignore.map((p) => picomatch(p, { dot: false }));
|
|
94
104
|
const root = rstripSlash(cwd) || "/";
|
|
95
105
|
const cwdPrefix = root === "/" ? "/" : `${root}/`;
|
|
96
106
|
const results = [];
|
|
@@ -99,7 +109,7 @@ function mirageOperations(ws) {
|
|
|
99
109
|
root,
|
|
100
110
|
cwdPrefix,
|
|
101
111
|
matcher,
|
|
102
|
-
{ ignoreMatchers, limit:
|
|
112
|
+
{ ignoreMatchers, limit: options2.limit },
|
|
103
113
|
results
|
|
104
114
|
);
|
|
105
115
|
return results;
|
|
@@ -121,21 +131,40 @@ function mirageOperations(ws) {
|
|
|
121
131
|
}
|
|
122
132
|
|
|
123
133
|
// src/pi/extension.ts
|
|
134
|
+
function bashAtCwd(operations, cwd) {
|
|
135
|
+
return {
|
|
136
|
+
exec: (command, _hostCwd, options) => operations.exec(command, cwd, options)
|
|
137
|
+
};
|
|
138
|
+
}
|
|
124
139
|
function mirageExtension(ws, opts = {}) {
|
|
125
140
|
const cwd = opts.cwd ?? "/";
|
|
126
|
-
const ops = mirageOperations(ws);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
pi
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
141
|
+
const ops = mirageOperations(ws, opts);
|
|
142
|
+
const userBash = bashAtCwd(ops.bash, cwd);
|
|
143
|
+
const systemPrompt = opts.systemPrompt === false ? void 0 : opts.systemPrompt ?? buildSystemPrompt({ workspace: ws });
|
|
144
|
+
return {
|
|
145
|
+
name: "mirage",
|
|
146
|
+
factory: (pi) => {
|
|
147
|
+
pi.registerTool(createReadToolDefinition(cwd, { operations: ops.read }));
|
|
148
|
+
pi.registerTool(createWriteToolDefinition(cwd, { operations: ops.write }));
|
|
149
|
+
pi.registerTool(createEditToolDefinition(cwd, { operations: ops.edit }));
|
|
150
|
+
pi.registerTool(createBashToolDefinition(cwd, { operations: ops.bash }));
|
|
151
|
+
pi.registerTool(createGrepToolDefinition(cwd, { operations: ops.grep }));
|
|
152
|
+
pi.registerTool(createFindToolDefinition(cwd, { operations: ops.find }));
|
|
153
|
+
pi.registerTool(createLsToolDefinition(cwd, { operations: ops.ls }));
|
|
154
|
+
pi.on("user_bash", () => ({ operations: userBash }));
|
|
155
|
+
if (systemPrompt !== void 0) {
|
|
156
|
+
pi.on("before_agent_start", (event) => ({
|
|
157
|
+
systemPrompt: `${event.systemPrompt}
|
|
158
|
+
|
|
159
|
+
${systemPrompt}`
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
135
163
|
};
|
|
136
164
|
}
|
|
137
165
|
export {
|
|
138
166
|
MIRAGE_SYSTEM_PROMPT,
|
|
167
|
+
StaleMirageFileError,
|
|
139
168
|
buildSystemPrompt,
|
|
140
169
|
mirageExtension,
|
|
141
170
|
mirageOperations
|
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'\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":[]}
|
|
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 BashOperations,\n type InlineExtension,\n} from '@earendil-works/pi-coding-agent'\nimport { buildSystemPrompt } from '../prompt.ts'\nimport { mirageOperations, type MirageOperationsOptions } from './operations.ts'\n\nexport interface MirageExtensionOptions extends MirageOperationsOptions {\n cwd?: string\n systemPrompt?: string | false\n}\n\nfunction bashAtCwd(operations: BashOperations, cwd: string): BashOperations {\n return {\n exec: (command, _hostCwd, options) => operations.exec(command, cwd, options),\n }\n}\n\nexport function mirageExtension(ws: Workspace, opts: MirageExtensionOptions = {}): InlineExtension {\n const cwd = opts.cwd ?? '/'\n const ops = mirageOperations(ws, opts)\n const userBash = bashAtCwd(ops.bash, cwd)\n const systemPrompt =\n opts.systemPrompt === false\n ? undefined\n : (opts.systemPrompt ?? buildSystemPrompt({ workspace: ws }))\n return {\n name: 'mirage',\n factory: (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 pi.on('user_bash', () => ({ operations: userBash }))\n if (systemPrompt !== undefined) {\n pi.on('before_agent_start', (event) => ({\n systemPrompt: `${event.systemPrompt}\\n\\n${systemPrompt}`,\n }))\n }\n },\n }\n}\n","// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========\n\nimport { rstripSlash, type ExecuteResult, type Workspace } from '@struktoai/mirage-core'\nimport type {\n BashOperations,\n EditOperations,\n FindOperations,\n GrepOperations,\n LsOperations,\n ReadOperations,\n WriteOperations,\n} from '@earendil-works/pi-coding-agent'\nimport picomatch from 'picomatch'\nimport { FileVersionTracker } from '../file-version.ts'\n\nexport { StaleMirageFileError } from '../file-version.ts'\n\nexport interface MirageOperationsOptions {\n staleWriteProtection?: boolean\n}\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 const entries = await ws.fs.readdir(dir)\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(\n ws: Workspace,\n options: MirageOperationsOptions = {},\n): MirageOperationsBundle {\n const versions = new FileVersionTracker(ws, options.staleWriteProtection ?? true)\n const read: ReadOperations = {\n readFile: (absolutePath: string) => versions.read(absolutePath),\n access: async (absolutePath: string) => {\n await ws.fs.stat(absolutePath)\n },\n }\n\n const write: WriteOperations = {\n writeFile: (absolutePath: string, content: string) => versions.write(absolutePath, content),\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: (absolutePath: string) => versions.readForEdit(absolutePath),\n writeFile: (absolutePath: string, content: string) => versions.writeEdit(absolutePath, content),\n access: read.access,\n }\n\n const bash: BashOperations = {\n exec: async (command, cwd, options) => {\n const timeoutSignal =\n options.timeout !== undefined && options.timeout > 0\n ? AbortSignal.timeout(options.timeout * 1000)\n : undefined\n const signal =\n options.signal !== undefined && timeoutSignal !== undefined\n ? AbortSignal.any([options.signal, timeoutSignal])\n : (options.signal ?? timeoutSignal)\n let result: ExecuteResult\n try {\n result =\n signal === undefined\n ? await ws.execute(command, { cwd })\n : await ws.execute(command, { cwd, signal })\n } catch (error) {\n if (options.signal?.aborted === true) {\n throw new Error('aborted')\n }\n if (timeoutSignal?.aborted === true) {\n throw new Error('timeout:' + String(options.timeout))\n }\n throw error\n }\n if (result.stdout.length > 0) {\n options.onData(Buffer.from(result.stdout))\n }\n if (result.stderr.length > 0) {\n options.onData(Buffer.from(result.stderr))\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) => (await versions.read(absolutePath)).toString('utf-8'),\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":["options"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Workspace } from '@struktoai/mirage-core';
|
|
2
|
+
|
|
3
|
+
interface ToolResult {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
content: {
|
|
6
|
+
type: 'text';
|
|
7
|
+
text: string;
|
|
8
|
+
}[];
|
|
9
|
+
isError?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface MirageToolOperationsOptions {
|
|
12
|
+
staleWriteProtection?: boolean;
|
|
13
|
+
}
|
|
14
|
+
declare class MirageToolOperations {
|
|
15
|
+
private readonly ws;
|
|
16
|
+
private readonly versions;
|
|
17
|
+
constructor(ws: Workspace, options?: MirageToolOperationsOptions);
|
|
18
|
+
execute(command: string): Promise<ToolResult>;
|
|
19
|
+
read(path: string, offset?: number, limit?: number): Promise<ToolResult>;
|
|
20
|
+
write(path: string, content: string): Promise<ToolResult>;
|
|
21
|
+
edit(path: string, oldString: string, newString: string, replaceAll?: boolean): Promise<ToolResult>;
|
|
22
|
+
ls(path: string): Promise<ToolResult>;
|
|
23
|
+
grep(pattern: string, path: string): Promise<ToolResult>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
declare const EXECUTE_DESCRIPTION: string;
|
|
27
|
+
declare const READ_DESCRIPTION: string;
|
|
28
|
+
declare const WRITE_DESCRIPTION: string;
|
|
29
|
+
declare const EDIT_DESCRIPTION: string;
|
|
30
|
+
declare const LS_DESCRIPTION = "List files and directories at the given path on the Mirage virtual filesystem.";
|
|
31
|
+
declare const GREP_DESCRIPTION: string;
|
|
32
|
+
|
|
33
|
+
export { EDIT_DESCRIPTION as E, GREP_DESCRIPTION as G, LS_DESCRIPTION as L, type MirageToolOperationsOptions as M, READ_DESCRIPTION as R, type ToolResult as T, WRITE_DESCRIPTION as W, EXECUTE_DESCRIPTION as a, MirageToolOperations as b };
|
package/dist/vercel/index.d.ts
CHANGED
|
@@ -1,70 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { Workspace } from '@struktoai/mirage-core';
|
|
2
|
+
import { ToolSet } from 'ai';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
kind: 'text';
|
|
6
|
-
path: string;
|
|
7
|
-
mimeType: string;
|
|
8
|
-
content: string;
|
|
9
|
-
bytes: number;
|
|
10
|
-
} | {
|
|
11
|
-
kind: 'media';
|
|
12
|
-
path: string;
|
|
13
|
-
mimeType: string;
|
|
14
|
-
base64: string;
|
|
15
|
-
bytes: number;
|
|
16
|
-
} | {
|
|
17
|
-
kind: 'binary';
|
|
18
|
-
path: string;
|
|
19
|
-
mimeType: string;
|
|
20
|
-
bytes: number;
|
|
21
|
-
note: string;
|
|
22
|
-
} | {
|
|
23
|
-
error: string;
|
|
24
|
-
};
|
|
25
|
-
declare function mirageTools(ws: Workspace): {
|
|
26
|
-
execute: ai.Tool<{
|
|
27
|
-
command: string;
|
|
28
|
-
}, {
|
|
29
|
-
stdout: string;
|
|
30
|
-
stderr: string;
|
|
31
|
-
exitCode: number;
|
|
32
|
-
}>;
|
|
33
|
-
readFile: ai.Tool<{
|
|
34
|
-
path: string;
|
|
35
|
-
}, ReadFileResult>;
|
|
36
|
-
writeFile: ai.Tool<{
|
|
37
|
-
path: string;
|
|
38
|
-
content: string;
|
|
39
|
-
}, {
|
|
40
|
-
path: string;
|
|
41
|
-
}>;
|
|
42
|
-
editFile: ai.Tool<{
|
|
43
|
-
path: string;
|
|
44
|
-
oldString: string;
|
|
45
|
-
newString: string;
|
|
46
|
-
replaceAll?: boolean | undefined;
|
|
47
|
-
}, {
|
|
48
|
-
error: string;
|
|
49
|
-
path?: never;
|
|
50
|
-
occurrences?: never;
|
|
51
|
-
} | {
|
|
52
|
-
path: string;
|
|
53
|
-
occurrences: number;
|
|
54
|
-
error?: never;
|
|
55
|
-
}>;
|
|
56
|
-
ls: ai.Tool<{
|
|
57
|
-
path: string;
|
|
58
|
-
}, {
|
|
59
|
-
error: string;
|
|
60
|
-
files?: never;
|
|
61
|
-
} | {
|
|
62
|
-
files: {
|
|
63
|
-
path: string;
|
|
64
|
-
is_dir: boolean;
|
|
65
|
-
}[];
|
|
66
|
-
error?: never;
|
|
67
|
-
}>;
|
|
68
|
-
};
|
|
4
|
+
declare function mirageTools(ws: Workspace): ToolSet;
|
|
69
5
|
|
|
70
6
|
export { mirageTools };
|
package/dist/vercel/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readWorkspaceFile
|
|
3
|
+
} from "../chunk-IMI7BLEG.js";
|
|
4
|
+
|
|
1
5
|
// src/vercel/index.ts
|
|
2
6
|
import { encodeBase64, gnuDirname } from "@struktoai/mirage-core";
|
|
3
7
|
import { tool } from "ai";
|
|
@@ -13,79 +17,30 @@ async function ensureParent(ws, path) {
|
|
|
13
17
|
if (!await ws.fs.exists(parent)) throw err;
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
|
-
var TEXT_EXTS = /* @__PURE__ */ new Set([
|
|
17
|
-
"txt",
|
|
18
|
-
"md",
|
|
19
|
-
"json",
|
|
20
|
-
"jsonl",
|
|
21
|
-
"yaml",
|
|
22
|
-
"yml",
|
|
23
|
-
"csv",
|
|
24
|
-
"tsv",
|
|
25
|
-
"xml",
|
|
26
|
-
"html",
|
|
27
|
-
"htm",
|
|
28
|
-
"js",
|
|
29
|
-
"mjs",
|
|
30
|
-
"cjs",
|
|
31
|
-
"ts",
|
|
32
|
-
"tsx",
|
|
33
|
-
"jsx",
|
|
34
|
-
"py",
|
|
35
|
-
"rb",
|
|
36
|
-
"rs",
|
|
37
|
-
"go",
|
|
38
|
-
"java",
|
|
39
|
-
"c",
|
|
40
|
-
"cpp",
|
|
41
|
-
"h",
|
|
42
|
-
"hpp",
|
|
43
|
-
"sh",
|
|
44
|
-
"bash",
|
|
45
|
-
"zsh",
|
|
46
|
-
"sql",
|
|
47
|
-
"log",
|
|
48
|
-
"env",
|
|
49
|
-
"ini",
|
|
50
|
-
"toml",
|
|
51
|
-
"conf",
|
|
52
|
-
"cfg"
|
|
53
|
-
]);
|
|
54
|
-
var PRESENTABLE_BINARY = /* @__PURE__ */ new Set([
|
|
55
|
-
"application/pdf",
|
|
56
|
-
"image/jpeg",
|
|
57
|
-
"image/png",
|
|
58
|
-
"image/gif",
|
|
59
|
-
"image/webp"
|
|
60
|
-
]);
|
|
61
|
-
function extOf(path) {
|
|
62
|
-
const dot = path.lastIndexOf(".");
|
|
63
|
-
if (dot < 0) return "";
|
|
64
|
-
return path.slice(dot + 1).toLowerCase();
|
|
65
|
-
}
|
|
66
|
-
function mimeFor(path) {
|
|
67
|
-
const ext = extOf(path);
|
|
68
|
-
if (ext === "json" || ext === "jsonl") return "application/json";
|
|
69
|
-
if (ext === "csv") return "text/csv";
|
|
70
|
-
if (ext === "html" || ext === "htm") return "text/html";
|
|
71
|
-
if (ext === "md") return "text/markdown";
|
|
72
|
-
if (TEXT_EXTS.has(ext)) return "text/plain";
|
|
73
|
-
if (ext === "png") return "image/png";
|
|
74
|
-
if (ext === "jpg" || ext === "jpeg") return "image/jpeg";
|
|
75
|
-
if (ext === "gif") return "image/gif";
|
|
76
|
-
if (ext === "webp") return "image/webp";
|
|
77
|
-
if (ext === "pdf") return "application/pdf";
|
|
78
|
-
return "application/octet-stream";
|
|
79
|
-
}
|
|
80
|
-
function isTextMime(mime) {
|
|
81
|
-
return mime.startsWith("text/") || mime === "application/json";
|
|
82
|
-
}
|
|
83
20
|
function bytesToBase64(bytes) {
|
|
84
21
|
return encodeBase64(bytes);
|
|
85
22
|
}
|
|
86
23
|
function isError(r) {
|
|
87
24
|
return "error" in r;
|
|
88
25
|
}
|
|
26
|
+
async function readFileResult(ws, path) {
|
|
27
|
+
try {
|
|
28
|
+
const result = await readWorkspaceFile(ws, path);
|
|
29
|
+
if (result.kind === "text") return result;
|
|
30
|
+
if (result.kind === "image" || result.kind === "file") {
|
|
31
|
+
return {
|
|
32
|
+
kind: "media",
|
|
33
|
+
path: result.path,
|
|
34
|
+
mimeType: result.mimeType,
|
|
35
|
+
base64: bytesToBase64(result.data),
|
|
36
|
+
bytes: result.bytes
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
89
44
|
function mirageTools(ws) {
|
|
90
45
|
return {
|
|
91
46
|
execute: tool({
|
|
@@ -107,40 +62,7 @@ function mirageTools(ws) {
|
|
|
107
62
|
inputSchema: z.object({
|
|
108
63
|
path: z.string().describe("Absolute path inside the workspace.")
|
|
109
64
|
}),
|
|
110
|
-
execute: async ({ path }) =>
|
|
111
|
-
let bytes;
|
|
112
|
-
try {
|
|
113
|
-
bytes = await ws.fs.readFile(path);
|
|
114
|
-
} catch (err) {
|
|
115
|
-
return { error: err instanceof Error ? err.message : String(err) };
|
|
116
|
-
}
|
|
117
|
-
const mimeType = mimeFor(path);
|
|
118
|
-
if (isTextMime(mimeType)) {
|
|
119
|
-
return {
|
|
120
|
-
kind: "text",
|
|
121
|
-
path,
|
|
122
|
-
mimeType,
|
|
123
|
-
content: new TextDecoder("utf-8", { fatal: false }).decode(bytes),
|
|
124
|
-
bytes: bytes.length
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
if (PRESENTABLE_BINARY.has(mimeType)) {
|
|
128
|
-
return {
|
|
129
|
-
kind: "media",
|
|
130
|
-
path,
|
|
131
|
-
mimeType,
|
|
132
|
-
base64: bytesToBase64(bytes),
|
|
133
|
-
bytes: bytes.length
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
return {
|
|
137
|
-
kind: "binary",
|
|
138
|
-
path,
|
|
139
|
-
mimeType,
|
|
140
|
-
bytes: bytes.length,
|
|
141
|
-
note: `Binary file ${path} (${mimeType}, ${String(bytes.length)} bytes). Use the execute tool with shell commands (head, file, wc, od) to inspect.`
|
|
142
|
-
};
|
|
143
|
-
},
|
|
65
|
+
execute: async ({ path }) => readFileResult(ws, path),
|
|
144
66
|
toModelOutput: ({ output }) => {
|
|
145
67
|
const out = output;
|
|
146
68
|
if (isError(out)) return { type: "error-text", value: out.error };
|
|
@@ -153,7 +75,11 @@ function mirageTools(ws) {
|
|
|
153
75
|
type: "text",
|
|
154
76
|
text: `[${out.path}] ${out.mimeType} (${String(out.bytes)} bytes)`
|
|
155
77
|
},
|
|
156
|
-
{
|
|
78
|
+
{
|
|
79
|
+
type: "file",
|
|
80
|
+
data: { type: "data", data: out.base64 },
|
|
81
|
+
mediaType: out.mimeType
|
|
82
|
+
}
|
|
157
83
|
]
|
|
158
84
|
};
|
|
159
85
|
}
|