@flue/sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +200 -0
- package/README.md +194 -0
- package/dist/client.d.mts +30 -0
- package/dist/client.mjs +62 -0
- package/dist/cloudflare/index.d.mts +36 -0
- package/dist/cloudflare/index.mjs +206 -0
- package/dist/index.d.mts +26 -0
- package/dist/index.mjs +775 -0
- package/dist/sandbox.d.mts +28 -0
- package/dist/sandbox.mjs +101 -0
- package/dist/session-BD0MEuO3.mjs +1300 -0
- package/dist/types-xNvqlohs.d.mts +327 -0
- package/package.json +50 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import "../session-BD0MEuO3.mjs";
|
|
2
|
+
import { createSandboxSessionEnv } from "../sandbox.mjs";
|
|
3
|
+
import { Workspace, WorkspaceFileSystem } from "@cloudflare/shell";
|
|
4
|
+
|
|
5
|
+
//#region src/cloudflare/context.ts
|
|
6
|
+
let currentContext = null;
|
|
7
|
+
function setCloudflareContext(ctx) {
|
|
8
|
+
currentContext = ctx;
|
|
9
|
+
}
|
|
10
|
+
function getCloudflareContext() {
|
|
11
|
+
if (!currentContext) throw new Error("[flue:cloudflare] Not running in a Cloudflare context. This function can only be called inside a Cloudflare Worker or Durable Object.");
|
|
12
|
+
return currentContext;
|
|
13
|
+
}
|
|
14
|
+
function clearCloudflareContext() {
|
|
15
|
+
currentContext = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/cloudflare/virtual-sandbox.ts
|
|
20
|
+
/**
|
|
21
|
+
* In-process just-bash sandbox for Cloudflare Workers (no container).
|
|
22
|
+
* Without args: empty in-memory. With R2 bucket: persistent files via DO SQLite + R2.
|
|
23
|
+
*/
|
|
24
|
+
function adaptStat(cfStat) {
|
|
25
|
+
return {
|
|
26
|
+
isFile: cfStat.type === "file",
|
|
27
|
+
isDirectory: cfStat.type === "directory",
|
|
28
|
+
isSymbolicLink: cfStat.type === "symlink",
|
|
29
|
+
mode: cfStat.mode ?? (cfStat.type === "directory" ? 493 : 420),
|
|
30
|
+
size: cfStat.size,
|
|
31
|
+
mtime: cfStat.mtime
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function adaptToJustBash(cfFs) {
|
|
35
|
+
return {
|
|
36
|
+
readFile: (path, _opts) => cfFs.readFile(path),
|
|
37
|
+
readFileBuffer: (path) => cfFs.readFileBytes(path),
|
|
38
|
+
async writeFile(path, content, _opts) {
|
|
39
|
+
if (typeof content === "string") await cfFs.writeFile(path, content);
|
|
40
|
+
else await cfFs.writeFileBytes(path, content);
|
|
41
|
+
},
|
|
42
|
+
appendFile: (path, content, _opts) => cfFs.appendFile(path, content),
|
|
43
|
+
exists: (path) => cfFs.exists(path),
|
|
44
|
+
async stat(path) {
|
|
45
|
+
return adaptStat(await cfFs.stat(path));
|
|
46
|
+
},
|
|
47
|
+
async lstat(path) {
|
|
48
|
+
return adaptStat(await cfFs.lstat(path));
|
|
49
|
+
},
|
|
50
|
+
mkdir: (path, opts) => cfFs.mkdir(path, opts),
|
|
51
|
+
readdir: (path) => cfFs.readdir(path),
|
|
52
|
+
async readdirWithFileTypes(path) {
|
|
53
|
+
return (await cfFs.readdirWithFileTypes(path)).map((e) => ({
|
|
54
|
+
name: e.name,
|
|
55
|
+
isFile: e.type === "file",
|
|
56
|
+
isDirectory: e.type === "directory",
|
|
57
|
+
isSymbolicLink: e.type === "symlink"
|
|
58
|
+
}));
|
|
59
|
+
},
|
|
60
|
+
rm: (path, opts) => cfFs.rm(path, opts),
|
|
61
|
+
cp: (src, dest, opts) => cfFs.cp(src, dest, opts),
|
|
62
|
+
mv: (src, dest) => cfFs.mv(src, dest),
|
|
63
|
+
resolvePath: (base, path) => cfFs.resolvePath(base, path),
|
|
64
|
+
getAllPaths: () => [],
|
|
65
|
+
async chmod(_path, _mode) {},
|
|
66
|
+
symlink: (target, linkPath) => cfFs.symlink(target, linkPath),
|
|
67
|
+
async link(existingPath, newPath) {
|
|
68
|
+
const content = await cfFs.readFileBytes(existingPath);
|
|
69
|
+
await cfFs.writeFileBytes(newPath, content);
|
|
70
|
+
},
|
|
71
|
+
readlink: (path) => cfFs.readlink(path),
|
|
72
|
+
realpath: (path) => cfFs.realpath(path),
|
|
73
|
+
async utimes(_path, _atime, _mtime) {}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function getVirtualSandbox(bucket, options) {
|
|
77
|
+
if (bucket === void 0) {
|
|
78
|
+
const { Bash, InMemoryFs } = await import(
|
|
79
|
+
/* @vite-ignore */
|
|
80
|
+
"just-bash"
|
|
81
|
+
);
|
|
82
|
+
return new Bash({
|
|
83
|
+
fs: new InMemoryFs(),
|
|
84
|
+
network: { dangerouslyAllowFullInternetAccess: true }
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const { storage } = getCloudflareContext();
|
|
88
|
+
const prefix = options?.prefix ?? "default";
|
|
89
|
+
const r2Adapter = adaptToJustBash(new WorkspaceFileSystem(new Workspace({
|
|
90
|
+
sql: storage.sql,
|
|
91
|
+
r2: bucket,
|
|
92
|
+
name: () => prefix
|
|
93
|
+
})));
|
|
94
|
+
const { Bash, MountableFs, InMemoryFs } = await import(
|
|
95
|
+
/* @vite-ignore */
|
|
96
|
+
"just-bash"
|
|
97
|
+
);
|
|
98
|
+
const fs = new MountableFs({ base: new InMemoryFs() });
|
|
99
|
+
fs.mount("/workspace", r2Adapter);
|
|
100
|
+
return new Bash({
|
|
101
|
+
fs,
|
|
102
|
+
cwd: "/workspace",
|
|
103
|
+
network: { dangerouslyAllowFullInternetAccess: true }
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/cloudflare/cf-sandbox.ts
|
|
109
|
+
/** Wraps a @cloudflare/sandbox instance (from getSandbox()) into SessionEnv. */
|
|
110
|
+
async function cfSandboxToSessionEnv(sandbox, cwd = "/workspace") {
|
|
111
|
+
return createSandboxSessionEnv({
|
|
112
|
+
async readFile(path) {
|
|
113
|
+
return (await sandbox.readFile(path)).content;
|
|
114
|
+
},
|
|
115
|
+
async readFileBuffer(path) {
|
|
116
|
+
const file = await sandbox.readFile(path, { encoding: "base64" });
|
|
117
|
+
const binary = atob(file.content);
|
|
118
|
+
const bytes = new Uint8Array(binary.length);
|
|
119
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
120
|
+
return bytes;
|
|
121
|
+
},
|
|
122
|
+
async writeFile(path, content) {
|
|
123
|
+
if (typeof content === "string") await sandbox.writeFile(path, content);
|
|
124
|
+
else {
|
|
125
|
+
let binary = "";
|
|
126
|
+
for (let i = 0; i < content.length; i++) binary += String.fromCharCode(content[i]);
|
|
127
|
+
const b64 = btoa(binary);
|
|
128
|
+
await sandbox.writeFile(path, b64, { encoding: "base64" });
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
async stat(path) {
|
|
132
|
+
const result = await sandbox.exec(`stat -c '{"size":%s,"isDir":%F}' '${path.replace(/'/g, "'\\''")}'`);
|
|
133
|
+
if (!result.success) throw new Error(`stat failed for ${path}: ${result.stderr}`);
|
|
134
|
+
try {
|
|
135
|
+
const raw = result.stdout.trim();
|
|
136
|
+
const sizeMatch = raw.match(/"size":(\d+)/);
|
|
137
|
+
const isDir = raw.includes("directory");
|
|
138
|
+
return {
|
|
139
|
+
isFile: !isDir,
|
|
140
|
+
isDirectory: isDir,
|
|
141
|
+
isSymbolicLink: false,
|
|
142
|
+
size: sizeMatch ? parseInt(sizeMatch[1], 10) : 0,
|
|
143
|
+
mtime: /* @__PURE__ */ new Date()
|
|
144
|
+
};
|
|
145
|
+
} catch {
|
|
146
|
+
throw new Error(`Failed to parse stat output for ${path}: ${result.stdout}`);
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
async readdir(path) {
|
|
150
|
+
const result = await sandbox.exec(`ls -1 '${path.replace(/'/g, "'\\''")}'`);
|
|
151
|
+
if (!result.success) throw new Error(`readdir failed for ${path}: ${result.stderr}`);
|
|
152
|
+
return result.stdout.trim().split("\n").filter((s) => s.length > 0);
|
|
153
|
+
},
|
|
154
|
+
async exists(path) {
|
|
155
|
+
return (await sandbox.exists(path)).exists;
|
|
156
|
+
},
|
|
157
|
+
async mkdir(path, opts) {
|
|
158
|
+
await sandbox.mkdir(path, opts);
|
|
159
|
+
},
|
|
160
|
+
async rm(path, opts) {
|
|
161
|
+
if (opts?.recursive || opts?.force) {
|
|
162
|
+
const flags = [opts.recursive ? "-r" : "", opts.force ? "-f" : ""].filter(Boolean).join("");
|
|
163
|
+
await sandbox.exec(`rm ${flags} '${path.replace(/'/g, "'\\''")}'`);
|
|
164
|
+
} else await sandbox.deleteFile(path);
|
|
165
|
+
},
|
|
166
|
+
async exec(command, execOpts) {
|
|
167
|
+
const result = await sandbox.exec(command, {
|
|
168
|
+
cwd: execOpts?.cwd,
|
|
169
|
+
env: execOpts?.env
|
|
170
|
+
});
|
|
171
|
+
return {
|
|
172
|
+
stdout: result.stdout ?? "",
|
|
173
|
+
stderr: result.stderr ?? "",
|
|
174
|
+
exitCode: result.exitCode ?? (result.success ? 0 : 1)
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}, cwd);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/cloudflare/session-store.ts
|
|
182
|
+
function store() {
|
|
183
|
+
return {
|
|
184
|
+
async save(_id, data) {
|
|
185
|
+
const { agentInstance } = getCloudflareContext();
|
|
186
|
+
agentInstance.setState({
|
|
187
|
+
...agentInstance.state,
|
|
188
|
+
sessionData: data
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
async load(_id) {
|
|
192
|
+
const { agentInstance } = getCloudflareContext();
|
|
193
|
+
return agentInstance.state?.sessionData ?? null;
|
|
194
|
+
},
|
|
195
|
+
async delete(_id) {
|
|
196
|
+
const { agentInstance } = getCloudflareContext();
|
|
197
|
+
agentInstance.setState({
|
|
198
|
+
...agentInstance.state,
|
|
199
|
+
sessionData: null
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
//#endregion
|
|
206
|
+
export { cfSandboxToSessionEnv, clearCloudflareContext, getCloudflareContext, getVirtualSandbox, setCloudflareContext, store };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { C as ShellOptions, D as TaskOptions, E as SkillOptions, O as ToolDef, S as SessionStore, T as Skill, _ as Role, a as BuildOptions, b as SessionEnv, c as CommandDef, d as FlueContext, f as FlueEvent, g as PromptResponse, h as PromptOptions, i as BuildContext, l as CommandSupport, m as FlueSession, n as AgentInfo, o as BuildPlugin, p as FlueEventCallback, r as BashLike, s as Command, t as AgentConfig, u as FileStat, v as SandboxFactory, w as ShellResult, x as SessionInit, y as SessionData } from "./types-xNvqlohs.mjs";
|
|
2
|
+
import { FlueContextConfig, FlueContextInternal, createFlueContext } from "./client.mjs";
|
|
3
|
+
import { AgentTool } from "@mariozechner/pi-agent-core";
|
|
4
|
+
import "valibot";
|
|
5
|
+
|
|
6
|
+
//#region src/build.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* Build a workspace into a deployable artifact.
|
|
9
|
+
* AGENTS.md and .agents/skills/ are NOT bundled — discovered at runtime from session cwd.
|
|
10
|
+
*/
|
|
11
|
+
declare function build(options: BuildOptions): Promise<void>;
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/session.d.ts
|
|
14
|
+
/** In-memory session store. Sessions persist for the lifetime of the process. */
|
|
15
|
+
declare class InMemorySessionStore implements SessionStore {
|
|
16
|
+
private store;
|
|
17
|
+
save(id: string, data: SessionData): Promise<void>;
|
|
18
|
+
load(id: string): Promise<SessionData | null>;
|
|
19
|
+
delete(id: string): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/agent.d.ts
|
|
23
|
+
declare const BUILTIN_TOOL_NAMES: Set<string>;
|
|
24
|
+
declare function createTools(env: SessionEnv): AgentTool<any>[];
|
|
25
|
+
//#endregion
|
|
26
|
+
export { type AgentConfig, type AgentInfo, BUILTIN_TOOL_NAMES, type BashLike, type BuildContext, type BuildOptions, type BuildPlugin, type Command, type CommandDef, type CommandSupport, type FileStat, type FlueContext, type FlueContextConfig, type FlueContextInternal, type FlueEvent, type FlueEventCallback, type FlueSession, InMemorySessionStore, type PromptOptions, type PromptResponse, type Role, type SandboxFactory, type SessionData, type SessionEnv, type SessionInit, type SessionStore, type ShellOptions, type ShellResult, type Skill, type SkillOptions, type TaskOptions, type ToolDef, build, createFlueContext, createTools };
|