@cybernetyx1/atlasflow-runtime 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,65 @@
1
+ import { ExecFileOptions } from 'node:child_process';
2
+ import { C as Command, a as CommandExecutor, S as SandboxNetworkPolicy, b as SandboxFactory } from '../command-kxrqWIH7.js';
3
+ import { Hono } from 'hono';
4
+
5
+ type CommandOptions = ExecFileOptions;
6
+ declare function defineCommand(name: string): Command;
7
+ declare function defineCommand(name: string, options: CommandOptions): Command;
8
+ declare function defineCommand(name: string, execute: CommandExecutor): Command;
9
+
10
+ /**
11
+ * Local sandbox — host-mounted just-bash by default, or explicit host shell.
12
+ *
13
+ * SECURITY: raw host mode gives the agent direct access to the host machine's
14
+ * shell and filesystem. Use it only in development or in an already-isolated
15
+ * environment (container, VM, CI runner). For untrusted workloads use the
16
+ * default virtual mode or an isolated sandbox provider.
17
+ */
18
+
19
+ interface LocalSandboxOptions {
20
+ /**
21
+ * "host" executes commands with the OS shell. "virtual" mounts `cwd` into
22
+ * just-bash at `mountPath` and supports scoped `defineCommand` grants.
23
+ * Defaults to "virtual".
24
+ */
25
+ mode?: "host" | "virtual";
26
+ cwd?: string;
27
+ env?: Record<string, string>;
28
+ /**
29
+ * Environment inherited from the host. Defaults to a small non-secret
30
+ * allowlist. Set true only inside an already-isolated environment.
31
+ */
32
+ inheritEnv?: boolean | string[];
33
+ /** Shell executable used for commands. Defaults to /bin/bash when present. */
34
+ shell?: string;
35
+ /** Maximum combined stdout/stderr retained before the command is killed. */
36
+ maxOutputBytes?: number;
37
+ /** Virtual path used when `mode: "virtual"`. Defaults to /workspace. */
38
+ mountPath?: string;
39
+ /**
40
+ * Network policy for virtual local mode. Host mode rejects this option because
41
+ * AtlasFlow cannot enforce network isolation around an OS shell.
42
+ */
43
+ network?: SandboxNetworkPolicy;
44
+ /**
45
+ * Required for raw host mode. It is intentionally separate from mode:"host"
46
+ * so accidental host-shell exposure fails closed.
47
+ */
48
+ allowHostAccess?: boolean;
49
+ }
50
+ declare function local(options?: LocalSandboxOptions): SandboxFactory;
51
+ declare function localVirtual(options?: Omit<LocalSandboxOptions, "mode">): SandboxFactory;
52
+
53
+ /** Start a Node HTTP server for an AtlasFlow app. */
54
+
55
+ interface ServeOptions {
56
+ port?: number;
57
+ hostname?: string;
58
+ backlog?: number;
59
+ }
60
+ declare function serve(app: Hono, options?: ServeOptions): {
61
+ port: number;
62
+ close: () => void;
63
+ };
64
+
65
+ export { type CommandOptions, type LocalSandboxOptions, type ServeOptions, defineCommand, local, localVirtual, serve };
@@ -0,0 +1,251 @@
1
+ import {
2
+ BaseSandboxEnv,
3
+ bashFactoryToSessionEnv,
4
+ createCwdSessionEnv,
5
+ resolveSandboxNetworkPolicy
6
+ } from "../chunk-4DU4GJ2X.js";
7
+ import {
8
+ normalizeCommandExecutor
9
+ } from "../chunk-S7RZJMCF.js";
10
+
11
+ // src/node/define-command.ts
12
+ import { execFile } from "child_process";
13
+ import { promisify } from "util";
14
+ var execFileAsync = promisify(execFile);
15
+ var DEFAULT_ENV = {
16
+ PATH: process.env.PATH,
17
+ HOME: process.env.HOME,
18
+ USER: process.env.USER,
19
+ USERNAME: process.env.USERNAME,
20
+ LOGNAME: process.env.LOGNAME,
21
+ HOSTNAME: process.env.HOSTNAME,
22
+ SHELL: process.env.SHELL,
23
+ LANG: process.env.LANG,
24
+ LC_ALL: process.env.LC_ALL,
25
+ LC_CTYPE: process.env.LC_CTYPE,
26
+ TERM: process.env.TERM,
27
+ TMPDIR: process.env.TMPDIR,
28
+ TMP: process.env.TMP,
29
+ TEMP: process.env.TEMP
30
+ };
31
+ function defineCommand(name, arg) {
32
+ if (typeof arg === "function") return { name, execute: normalizeCommandExecutor(arg) };
33
+ const options = arg ?? {};
34
+ const env = { ...DEFAULT_ENV, ...options.env ?? {} };
35
+ const execute = async (args, signal) => {
36
+ const { stdout, stderr } = await execFileAsync(name, args, {
37
+ maxBuffer: 50 * 1024 * 1024,
38
+ ...options,
39
+ env,
40
+ signal
41
+ });
42
+ return { stdout: String(stdout ?? ""), stderr: String(stderr ?? ""), exitCode: 0 };
43
+ };
44
+ return { name, execute: normalizeCommandExecutor(execute) };
45
+ }
46
+
47
+ // src/node/local-sandbox.ts
48
+ import { spawn } from "child_process";
49
+ import * as fsSync from "fs";
50
+ import * as fs from "fs/promises";
51
+ import * as nodePath from "path";
52
+ import { Bash, InMemoryFs, MountableFs, ReadWriteFs } from "just-bash";
53
+ var DEFAULT_ENV_ALLOWLIST = [
54
+ "PATH",
55
+ "HOME",
56
+ "USER",
57
+ "USERNAME",
58
+ "TMPDIR",
59
+ "TMP",
60
+ "TEMP",
61
+ "LANG",
62
+ "LC_ALL",
63
+ "TERM",
64
+ "SHELL",
65
+ "SystemRoot",
66
+ "ComSpec"
67
+ ];
68
+ var DEFAULT_MAX_OUTPUT_BYTES = 64 * 1024 * 1024;
69
+ var DEFAULT_VIRTUAL_NETWORK = {
70
+ dangerouslyAllowFullInternetAccess: true,
71
+ denyPrivateRanges: true
72
+ };
73
+ var LocalSandboxEnv = class extends BaseSandboxEnv {
74
+ cwd;
75
+ #env;
76
+ #inheritEnv;
77
+ #shell;
78
+ #maxOutputBytes;
79
+ constructor(options) {
80
+ super();
81
+ this.cwd = options.cwd ?? process.cwd();
82
+ this.#env = options.env ?? {};
83
+ this.#inheritEnv = options.inheritEnv ?? DEFAULT_ENV_ALLOWLIST;
84
+ this.#shell = options.shell ?? defaultShell();
85
+ this.#maxOutputBytes = options.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
86
+ }
87
+ exec(command, options) {
88
+ const cwd = options?.cwd ?? this.cwd;
89
+ const env = { ...filteredEnv(this.#inheritEnv), ...this.#env, ...options?.env };
90
+ const child = spawn(this.#shell, ["-c", command], { cwd, env, detached: process.platform !== "win32", signal: options?.signal });
91
+ return new Promise((resolve, reject) => {
92
+ let stdout = "";
93
+ let stderr = "";
94
+ let outputBytes = 0;
95
+ let timer;
96
+ let timedOut = false;
97
+ let outputCapped = false;
98
+ if (options?.timeoutMs)
99
+ timer = setTimeout(() => {
100
+ timedOut = true;
101
+ killProcessTree(child.pid, "SIGKILL");
102
+ }, options.timeoutMs);
103
+ const append = (stream, chunk) => {
104
+ if (outputCapped) return;
105
+ outputBytes += chunk.byteLength;
106
+ if (outputBytes > this.#maxOutputBytes) {
107
+ outputCapped = true;
108
+ const note = `
109
+ [command output exceeded ${this.#maxOutputBytes} bytes; process killed]`;
110
+ if (stream === "stdout") stdout += note;
111
+ else stderr += note;
112
+ killProcessTree(child.pid, "SIGKILL");
113
+ return;
114
+ }
115
+ if (stream === "stdout") stdout += chunk.toString();
116
+ else stderr += chunk.toString();
117
+ };
118
+ child.stdout.on("data", (d) => append("stdout", d));
119
+ child.stderr.on("data", (d) => append("stderr", d));
120
+ child.on("error", (err) => {
121
+ if (timer) clearTimeout(timer);
122
+ reject(err);
123
+ });
124
+ child.on("close", (code, sig) => {
125
+ if (timer) clearTimeout(timer);
126
+ if (timedOut) resolve({ stdout, stderr: `${stderr}
127
+ [command timed out after ${options?.timeoutMs}ms]`.trim(), exitCode: 124 });
128
+ else if (outputCapped) resolve({ stdout, stderr, exitCode: code ?? (sig ? 137 : 1) });
129
+ else resolve({ stdout, stderr, exitCode: code ?? (sig ? 137 : 1) });
130
+ });
131
+ });
132
+ }
133
+ readFile(path) {
134
+ return fs.readFile(this.resolvePath(path), "utf8");
135
+ }
136
+ async readFileBuffer(path) {
137
+ return new Uint8Array(await fs.readFile(this.resolvePath(path)));
138
+ }
139
+ async writeFile(path, data) {
140
+ const resolved = this.resolvePath(path);
141
+ await fs.mkdir(nodePath.dirname(resolved), { recursive: true }).catch(() => {
142
+ });
143
+ await fs.writeFile(resolved, data);
144
+ }
145
+ async stat(path) {
146
+ const s = await fs.lstat(this.resolvePath(path));
147
+ return { isFile: s.isFile(), isDirectory: s.isDirectory(), isSymbolicLink: s.isSymbolicLink(), size: s.size, mtimeMs: s.mtimeMs };
148
+ }
149
+ readdir(path) {
150
+ return fs.readdir(this.resolvePath(path));
151
+ }
152
+ async mkdir(path, options) {
153
+ await fs.mkdir(this.resolvePath(path), { recursive: options?.recursive ?? true });
154
+ }
155
+ async rm(path, options) {
156
+ await fs.rm(this.resolvePath(path), { recursive: options?.recursive ?? false, force: options?.force ?? false });
157
+ }
158
+ resolvePath(path) {
159
+ return nodePath.isAbsolute(path) ? path : nodePath.join(this.cwd, path);
160
+ }
161
+ };
162
+ function local(options = {}) {
163
+ return {
164
+ async createSessionEnv(opts) {
165
+ const mode = options.mode ?? "virtual";
166
+ if (mode === "virtual") return createVirtualLocalSessionEnv(options, opts.cwd, opts.env);
167
+ if (options.network) {
168
+ throw new Error(
169
+ 'local({ mode: "host" }) does not support sandbox network policy or credential brokering. Use the default virtual sandbox, local({ mode: "virtual" }), or an isolated provider that enforces network policy.'
170
+ );
171
+ }
172
+ if (options.allowHostAccess !== true) {
173
+ throw new Error(
174
+ 'local({ mode: "host" }) requires allowHostAccess: true. Raw host mode has direct access to the host shell and filesystem; use local() or local({ mode: "virtual" }) for the safer default.'
175
+ );
176
+ }
177
+ return new LocalSandboxEnv(options);
178
+ }
179
+ };
180
+ }
181
+ function localVirtual(options = {}) {
182
+ return local({ ...options, mode: "virtual" });
183
+ }
184
+ async function createVirtualLocalSessionEnv(options, cwd, envVars) {
185
+ const hostRoot = options.cwd ?? process.cwd();
186
+ const mountPath = normalizeMountPath(options.mountPath ?? "/workspace");
187
+ const rwfs = new ReadWriteFs({ root: hostRoot });
188
+ const mounted = new MountableFs({ base: new InMemoryFs() });
189
+ mounted.mount(mountPath, rwfs);
190
+ const network = resolveSandboxNetworkPolicy(options.network, envVars) ?? DEFAULT_VIRTUAL_NETWORK;
191
+ const env = await bashFactoryToSessionEnv(
192
+ () => new Bash({
193
+ fs: mounted,
194
+ cwd: mountPath,
195
+ env: { ...filteredEnv(options.inheritEnv ?? DEFAULT_ENV_ALLOWLIST), ...options.env },
196
+ network
197
+ })
198
+ );
199
+ return cwd ? createCwdSessionEnv(env, cwd) : env;
200
+ }
201
+ function filteredEnv(inherit) {
202
+ if (inherit === true) return { ...process.env };
203
+ if (inherit === false) return {};
204
+ const out = {};
205
+ for (const key of inherit) {
206
+ const value = process.env[key];
207
+ if (typeof value === "string") out[key] = value;
208
+ }
209
+ return out;
210
+ }
211
+ function defaultShell() {
212
+ if (process.platform === "win32") return "bash";
213
+ for (const candidate of ["/bin/bash", "/usr/bin/bash", "/usr/local/bin/bash"]) {
214
+ if (fsSync.existsSync(candidate)) return candidate;
215
+ }
216
+ return "bash";
217
+ }
218
+ function normalizeMountPath(path) {
219
+ if (!path.startsWith("/")) throw new Error(`local({ mode: "virtual" }) mountPath must be absolute: ${path}`);
220
+ const normalized = nodePath.posix.normalize(path);
221
+ if (normalized === "/") throw new Error('local({ mode: "virtual" }) mountPath cannot be "/"; use "/workspace" or another subdirectory.');
222
+ return normalized.replace(/\/+$/, "");
223
+ }
224
+ function killProcessTree(pid, signal) {
225
+ if (!pid) return;
226
+ try {
227
+ if (process.platform !== "win32") process.kill(-pid, signal);
228
+ else process.kill(pid, signal);
229
+ } catch {
230
+ try {
231
+ process.kill(pid, signal);
232
+ } catch {
233
+ }
234
+ }
235
+ }
236
+
237
+ // src/node/serve.ts
238
+ import { createAdaptorServer } from "@hono/node-server";
239
+ var DEFAULT_LISTEN_BACKLOG = 1024;
240
+ function serve(app, options = {}) {
241
+ const port = options.port ?? 4577;
242
+ const server = createAdaptorServer({ fetch: app.fetch, hostname: options.hostname });
243
+ server.listen({ port, host: options.hostname, backlog: options.backlog ?? DEFAULT_LISTEN_BACKLOG });
244
+ return { port, close: () => server.close() };
245
+ }
246
+ export {
247
+ defineCommand,
248
+ local,
249
+ localVirtual,
250
+ serve
251
+ };
@@ -0,0 +1,40 @@
1
+ import { Api, Model } from '@earendil-works/pi-ai';
2
+ export { ApiProvider, getApiProvider, getApiProviders, registerApiProvider, unregisterApiProviders } from '@earendil-works/pi-ai';
3
+
4
+ /**
5
+ * Provider extension surface.
6
+ *
7
+ * AtlasFlow keeps model execution behind AgentEngine, but the default PI engine
8
+ * can resolve both pi-ai catalog providers and module-scoped provider
9
+ * registrations declared by application code.
10
+ */
11
+
12
+ interface ProviderRegistration {
13
+ /** pi-ai wire protocol slug. Required when providerId is not in the catalog. */
14
+ api?: Api;
15
+ /** Provider endpoint root. Required when providerId is not in the catalog. */
16
+ baseUrl?: string;
17
+ apiKey?: string;
18
+ headers?: Record<string, string>;
19
+ contextWindow?: number;
20
+ maxTokens?: number;
21
+ /** Per-model metadata overrides keyed by model id. */
22
+ models?: Record<string, {
23
+ contextWindow?: number;
24
+ maxTokens?: number;
25
+ name?: string;
26
+ }>;
27
+ /** Reserved for OpenAI Responses-style providers that support remote item storage. */
28
+ storeResponses?: boolean;
29
+ }
30
+ declare class ProviderRegistrationError extends Error {
31
+ constructor(providerId: string);
32
+ }
33
+ declare function registerProvider(providerId: string, registration: ProviderRegistration): void;
34
+ declare function resetProvidersForTests(): void;
35
+ declare function hasRegisteredProvider(providerId: string): boolean;
36
+ declare function getRegisteredApiKey(providerId: string): string | undefined;
37
+ declare function getRegisteredStoreResponses(providerId: string): boolean;
38
+ declare function resolveRegisteredModel(providerId: string, modelId: string): Model<Api> | undefined;
39
+
40
+ export { type ProviderRegistration, ProviderRegistrationError, getRegisteredApiKey, getRegisteredStoreResponses, hasRegisteredProvider, registerProvider, resetProvidersForTests, resolveRegisteredModel };
@@ -0,0 +1,26 @@
1
+ import {
2
+ ProviderRegistrationError,
3
+ getApiProvider,
4
+ getApiProviders,
5
+ getRegisteredApiKey,
6
+ getRegisteredStoreResponses,
7
+ hasRegisteredProvider,
8
+ registerApiProvider,
9
+ registerProvider,
10
+ resetProvidersForTests,
11
+ resolveRegisteredModel,
12
+ unregisterApiProviders
13
+ } from "./chunk-HO6QHSUS.js";
14
+ export {
15
+ ProviderRegistrationError,
16
+ getApiProvider,
17
+ getApiProviders,
18
+ getRegisteredApiKey,
19
+ getRegisteredStoreResponses,
20
+ hasRegisteredProvider,
21
+ registerApiProvider,
22
+ registerProvider,
23
+ resetProvidersForTests,
24
+ resolveRegisteredModel,
25
+ unregisterApiProviders
26
+ };
@@ -0,0 +1,256 @@
1
+ import { MiddlewareHandler, Hono } from 'hono';
2
+ import { C as CreatedAgent, A as AgentEngine, a as AgentProfile, W as WorkflowDef, b as ChannelDefinition, I as InvokeResult, D as DurableExecutionRunner } from '../channel-Dv3Hv1ee.js';
3
+ import { P as PersistenceAdapter, A as AtlasEvent } from '../index-UFTgKRK4.js';
4
+ import 'valibot';
5
+ import '../command-kxrqWIH7.js';
6
+
7
+ /**
8
+ * HTTP routing — a Hono app that mounts agents and admin routes.
9
+ *
10
+ * GET /health liveness probe (always open)
11
+ * GET /agents agent manifest
12
+ * POST /agents/:name/:id invoke an agent interactively
13
+ * POST /sessions/:id/messages invoke the single deployed agent interactively
14
+ * POST /runs dispatch the single deployed agent
15
+ * POST /runs/:name dispatch a durable run (agent or workflow; ?wait=result blocks for agents)
16
+ * GET /runs/:runId public run metadata
17
+ * GET /runs/:runId/events resumable run event stream (SSE) or JSON replay
18
+ * PUT /streams/* create a public writable durable stream
19
+ * GET /streams/* read a public durable stream
20
+ * POST /streams/* append to or close a public durable stream
21
+ * POST /runs/:runId/approve decide a workflow gate or tool approval
22
+ * POST /workflows/:name deprecated alias of POST /runs/:name
23
+ * GET /admin/agents list registered agents
24
+ * GET /admin/runs list runs
25
+ * GET /admin/runs/:runId get a run record
26
+ * GET /admin/runs/:runId/events run event log (JSON)
27
+ *
28
+ * POST /agents/:name/:id response modes:
29
+ * - `Accept: text/event-stream` → live SSE events + terminal `result` event
30
+ * - `x-webhook: true` header → fire-and-forget: 202 + runId immediately
31
+ * - otherwise → synchronous JSON
32
+ */
33
+
34
+ interface AgentTriggers {
35
+ webhook?: boolean;
36
+ cron?: string;
37
+ crons?: string[];
38
+ }
39
+ /**
40
+ * Handed to custom route mounts and scheduled handlers: invoke/dispatch are
41
+ * pre-wired with the app's agents, persistence, AGENTS.md, and shared
42
+ * subagents, so a webhook handler is one call.
43
+ */
44
+ interface AtlasRouteContext {
45
+ agents: Record<string, CreatedAgent>;
46
+ persistence: PersistenceAdapter;
47
+ invoke(name: string, opts?: RouteInvokeOptions): Promise<InvokeResult>;
48
+ dispatch(name: string, opts?: RouteInvokeOptions): Promise<{
49
+ runId: string;
50
+ done: Promise<void>;
51
+ }>;
52
+ }
53
+ interface RouteInvokeOptions {
54
+ instanceId?: string;
55
+ message?: string;
56
+ payload?: unknown;
57
+ env?: Record<string, unknown>;
58
+ signal?: AbortSignal;
59
+ runId?: string;
60
+ /** Receive live events — build custom streaming endpoints (SSE, websockets). */
61
+ onEvent?: (event: AtlasEvent) => void;
62
+ }
63
+ /** An authored workflow plus the context its steps resolve against. */
64
+ interface WorkflowMount {
65
+ def: WorkflowDef;
66
+ skills?: {
67
+ name: string;
68
+ description: string;
69
+ body: string;
70
+ }[];
71
+ defaultModel?: string;
72
+ /** Persona executing slot-less steps (the workflow's owner). */
73
+ defaultPersona?: string;
74
+ profiles?: AgentProfile[];
75
+ /** Deploy-time role-slot rebinding. */
76
+ bindings?: Record<string, string>;
77
+ }
78
+ interface AppOptions {
79
+ agents: Record<string, CreatedAgent>;
80
+ /** Override the default model engine for app-managed invocations. */
81
+ engine?: AgentEngine;
82
+ persistence?: PersistenceAdapter;
83
+ /** Middleware applied to /agents/*, /runs/*, /workflows/* and /admin/*. */
84
+ auth?: MiddlewareHandler;
85
+ /** Trigger metadata per agent (shown in the manifest; cron drives schedules). */
86
+ triggers?: Record<string, AgentTriggers>;
87
+ /** Prepended to every agent's instructions (e.g. workspace AGENTS.md). */
88
+ baseInstructions?: string;
89
+ /** Personas available to every agent's task tool (e.g. workspace roles/). */
90
+ personas?: AgentProfile[];
91
+ /** @deprecated Use `personas`. */
92
+ subagents?: AgentProfile[];
93
+ /** Authored workflows (gated, role-slotted) dispatchable via POST /runs/:name. */
94
+ workflows?: Record<string, WorkflowDef | WorkflowMount>;
95
+ /**
96
+ * First-class ingress handlers. A channel owns external webhook parsing and
97
+ * maps each event to a continuationToken, which becomes the AtlasFlow session id.
98
+ */
99
+ channels?: Record<string, ChannelDefinition>;
100
+ /**
101
+ * Mount project routes (webhooks, operator endpoints) on the app. These are
102
+ * NOT behind `auth` unless mounted under a gated prefix — webhook handlers
103
+ * do their own signature verification (HMAC etc.). Registered before the
104
+ * built-in routes, so custom paths win.
105
+ */
106
+ routes?: (app: Hono, atlas: AtlasRouteContext) => void;
107
+ /** Wrap durable/background agent execution in a platform primitive. */
108
+ durability?: DurableExecutionRunner;
109
+ /** Optional browser CORS policy. Disabled by default. */
110
+ cors?: CorsOptions | false | ((env: Record<string, string | undefined>) => CorsOptions | false | undefined);
111
+ /** Optional per-isolate rate limit for public and authenticated HTTP routes. */
112
+ rateLimit?: RateLimitSource | false;
113
+ /** Optional in-process runtime metrics surfaced on the authenticated /admin/metrics route. */
114
+ metrics?: {
115
+ snapshot(): unknown;
116
+ };
117
+ }
118
+ interface CorsOptions {
119
+ /** Allowed browser origins. Use "*" only for non-credentialed public/dev APIs. */
120
+ origins: "*" | string[];
121
+ methods?: string[];
122
+ headers?: string[];
123
+ exposeHeaders?: string[];
124
+ credentials?: boolean;
125
+ maxAgeSeconds?: number;
126
+ }
127
+ interface RateLimitOptions {
128
+ /** Bucket namespace. Generated apps default to "default"; custom apps can set this to isolate tenants. */
129
+ scope?: string;
130
+ /** Requests allowed per window for each derived client key. Defaults to 120. */
131
+ limit?: number;
132
+ /** Window length in milliseconds. Defaults to 60 seconds. */
133
+ windowMs?: number;
134
+ /** Token-bucket burst capacity. Defaults to min(limit, 30). */
135
+ burst?: number;
136
+ /** Maximum tracked client keys before old buckets are pruned. Defaults to 10,000. */
137
+ maxKeys?: number;
138
+ /** Override the default key of client IP + presented auth/channel token + route group. */
139
+ key?: (input: RateLimitKeyInput) => string | undefined;
140
+ }
141
+ interface RateLimitKeyInput {
142
+ request: Request;
143
+ url: URL;
144
+ env: Record<string, string | undefined>;
145
+ route: string;
146
+ clientIp: string;
147
+ tokenHash: string;
148
+ }
149
+ type RateLimitSource = RateLimitOptions | ((env: Record<string, string | undefined>) => RateLimitOptions | false | undefined);
150
+ interface ScopedTokenClaims {
151
+ v: 1;
152
+ exp: number;
153
+ iat?: number;
154
+ sub?: string;
155
+ aud?: string;
156
+ scopes?: string[];
157
+ agents?: string[];
158
+ instanceIds?: string[];
159
+ }
160
+ interface ScopedTokenMintOptions {
161
+ /** Server-side signing secret. Do not send this value to browsers. */
162
+ secret: string;
163
+ ttlSeconds?: number;
164
+ expiresAt?: number | Date;
165
+ subject?: string;
166
+ audience?: string;
167
+ scopes?: string[];
168
+ agents?: string[];
169
+ instanceIds?: string[];
170
+ now?: () => number;
171
+ }
172
+ interface ScopedTokenAuthOptions {
173
+ /** Defaults to ATLASFLOW_BROWSER_TOKEN_SECRET, then ATLASFLOW_API_KEY. */
174
+ secret?: string;
175
+ audience?: string;
176
+ leewaySeconds?: number;
177
+ now?: () => number;
178
+ }
179
+ interface ApiKeyAuthOptions {
180
+ token?: string;
181
+ header?: string;
182
+ allowUnconfigured?: boolean | ((env: Record<string, string | undefined>) => boolean);
183
+ scopedTokens?: boolean | ScopedTokenAuthOptions | false | ((env: Record<string, string | undefined>) => boolean | ScopedTokenAuthOptions | false | undefined);
184
+ }
185
+ /**
186
+ * Auth middleware: require a bearer token. The expected token is resolved from
187
+ * `options.token`, else the `ATLASFLOW_API_KEY` env/secret.
188
+ *
189
+ * Secure by default: if no token can be resolved the gate fails CLOSED (503).
190
+ * `allowUnconfigured` opts into an open gate — pass `true`, or a predicate on
191
+ * the request env (e.g. only when ATLASFLOW_MODE=local).
192
+ */
193
+ declare function requireApiKey(options?: ApiKeyAuthOptions): MiddlewareHandler;
194
+ /** Mint a browser-safe short-lived token. Call this only from trusted server code. */
195
+ declare function mintScopedToken(options: ScopedTokenMintOptions): Promise<string>;
196
+ /**
197
+ * Helper for generated apps: browser scoped tokens stay disabled unless the
198
+ * deployment sets ATLASFLOW_BROWSER_TOKEN_SECRET or ATLASFLOW_BROWSER_TOKENS=true.
199
+ */
200
+ declare function scopedTokensFromEnv(env?: Record<string, string | undefined>): ScopedTokenAuthOptions | false;
201
+ /** Helper for generated apps: comma-separated ATLASFLOW_CORS_ORIGINS enables CORS. */
202
+ declare function corsFromEnv(env?: Record<string, string | undefined>): CorsOptions | false;
203
+ /**
204
+ * Helper for generated apps. Rate limiting is enabled by default for built
205
+ * servers and can be tuned or disabled with environment variables:
206
+ * ATLASFLOW_RATE_LIMIT_ENABLED=false
207
+ * ATLASFLOW_RATE_LIMIT_RPM=120
208
+ * ATLASFLOW_RATE_LIMIT_BURST=30
209
+ * ATLASFLOW_RATE_LIMIT_WINDOW_MS=60000
210
+ */
211
+ declare function rateLimitFromEnv(env?: Record<string, string | undefined>): RateLimitOptions | false;
212
+ declare function rateLimit(source?: RateLimitSource): MiddlewareHandler;
213
+ /**
214
+ * Keep a background promise alive past the response. On Cloudflare the request
215
+ * context is torn down once the response is sent, cancelling stray promises —
216
+ * waitUntil is the supported escape hatch. On Node accessing executionCtx
217
+ * throws; background promises simply keep running there. Use this in custom
218
+ * routes after `atlas.dispatch(...)`.
219
+ */
220
+ declare function keepAlive(c: {
221
+ executionCtx?: {
222
+ waitUntil?: (p: Promise<unknown>) => void;
223
+ };
224
+ }, promise: Promise<unknown>): void;
225
+ declare function createApp(options: AppOptions): Hono;
226
+ /**
227
+ * Startup recovery for everything durable: re-dispatch interrupted agent runs
228
+ * AND resume interrupted workflow runs from their persisted cursor. Runs
229
+ * parked at a gate (waiting_approval) stay parked — they wait on a human.
230
+ */
231
+ declare function recoverAppRuns(options: AppOptions, env?: Record<string, unknown>): Promise<string[]>;
232
+ interface ScheduledHandlerOptions extends Pick<AppOptions, "agents" | "engine" | "triggers" | "baseInstructions" | "personas" | "subagents" | "durability"> {
233
+ /** Resolve persistence from the per-invocation env (e.g. a Durable Object binding). */
234
+ persistenceFor?: (env: Record<string, unknown>) => PersistenceAdapter | undefined;
235
+ }
236
+ interface ScheduledEvent {
237
+ /** The cron expression that fired (provided by Cloudflare). */
238
+ cron?: string;
239
+ scheduledTime?: number;
240
+ }
241
+ /**
242
+ * Build a `scheduled(event, env, ctx)` handler that dispatches a durable
243
+ * run for every agent whose trigger metadata is due. Older generated apps use
244
+ * `triggers.cron`; folder-first apps may use `triggers.crons` when one agent
245
+ * has multiple schedule files. Background work is registered with `ctx.waitUntil`.
246
+ */
247
+ declare function createScheduledHandler(options: ScheduledHandlerOptions): (event: ScheduledEvent, env?: Record<string, unknown>, ctx?: {
248
+ waitUntil?: (p: Promise<unknown>) => void;
249
+ }) => Promise<{
250
+ dispatched: {
251
+ agent: string;
252
+ runId: string;
253
+ }[];
254
+ }>;
255
+
256
+ export { type AgentTriggers, type ApiKeyAuthOptions, type AppOptions, type AtlasRouteContext, type CorsOptions, type RateLimitKeyInput, type RateLimitOptions, type RateLimitSource, type RouteInvokeOptions, type ScheduledEvent, type ScheduledHandlerOptions, type ScopedTokenAuthOptions, type ScopedTokenClaims, type ScopedTokenMintOptions, type WorkflowMount, corsFromEnv, createApp, createScheduledHandler, keepAlive, mintScopedToken, rateLimit, rateLimitFromEnv, recoverAppRuns, requireApiKey, scopedTokensFromEnv };