@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.
@@ -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 };
@@ -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 };