@boardwalk-labs/workflow 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,227 @@
1
+ // workflowManifestSchema — the validator of record for a workflow's `meta`.
2
+ //
3
+ // One Zod schema, consumed by every engine (local `dev`, the self-hosted server, Boardwalk
4
+ // hosted platform) and by `extract.ts` after pure-literal extraction. The TS manifest type is derived
5
+ // from the schema, never hand-written. Unknown fields are validation errors — no silent drift.
6
+ //
7
+ // Union ordering rule: most-specific-first. Zod unions are first-match-wins and strict objects
8
+ // reject extras, but keep the discipline anyway — a less-specific variant listed first can
9
+ // silently strip fields if an object is ever relaxed from strict.
10
+ import { z } from "zod";
11
+ // ============================================================================
12
+ // Shared scalars
13
+ // ============================================================================
14
+ const NAME_RE = /^[a-zA-Z0-9-]+$/;
15
+ const workflowName = z
16
+ .string()
17
+ .min(1)
18
+ .max(100)
19
+ .regex(NAME_RE, "name must be alphanumeric with hyphens");
20
+ /** A short identifier (tool/MCP/skill/secret names). */
21
+ const shortName = z.string().min(1).max(120);
22
+ /** Loosely-typed JSON Schema objects (input_schema / output_schema / tool inputSchema). */
23
+ const jsonSchemaObject = z.record(z.string(), z.unknown());
24
+ // ============================================================================
25
+ // Triggers
26
+ // ============================================================================
27
+ const cronExpr = z
28
+ .string()
29
+ .min(1)
30
+ .max(120)
31
+ .refine((expr) => {
32
+ const fields = expr.trim().split(/\s+/);
33
+ return fields.length === 5 || fields.length === 6;
34
+ }, { message: "cron expression must have 5 fields (standard) or 6 (with seconds)" });
35
+ const cronTriggerSchema = z.strictObject({
36
+ kind: z.literal("cron"),
37
+ expr: cronExpr,
38
+ timezone: z.string().min(1).max(80).optional(),
39
+ });
40
+ const webhookTriggerSchema = z.strictObject({
41
+ kind: z.literal("webhook"),
42
+ auth: z.enum(["token", "signature"]),
43
+ });
44
+ const manualTriggerSchema = z.strictObject({
45
+ kind: z.literal("manual"),
46
+ });
47
+ const triggerSchema = z.discriminatedUnion("kind", [
48
+ cronTriggerSchema,
49
+ webhookTriggerSchema,
50
+ manualTriggerSchema,
51
+ ]);
52
+ // ============================================================================
53
+ // Secrets and env
54
+ // ============================================================================
55
+ /** A secret ref is exactly `{ name }` — secrets + env vars are the entire credential story. */
56
+ const secretRefSchema = z.strictObject({ name: shortName });
57
+ const RESERVED_ENV_PREFIX_RE = /^(boardwalk_|aws_)/i;
58
+ /** The ONLY supported interpolation: a whole-value `${{ secrets.NAME }}` reference. */
59
+ const WHOLE_VALUE_SECRET_RE = /^\$\{\{\s*secrets\.[A-Za-z0-9_-]+\s*\}\}$/;
60
+ const envVarsSchema = z
61
+ .record(z.string().min(1).max(120), z.string().max(32_768))
62
+ .superRefine((vars, ctx) => {
63
+ const keys = Object.keys(vars);
64
+ if (keys.length > 100) {
65
+ ctx.addIssue({ code: "custom", message: "at most 100 env vars are allowed" });
66
+ }
67
+ for (const key of keys) {
68
+ if (RESERVED_ENV_PREFIX_RE.test(key)) {
69
+ ctx.addIssue({
70
+ code: "custom",
71
+ path: [key],
72
+ message: `"${key}" uses a reserved prefix (BOARDWALK_* / AWS_*)`,
73
+ });
74
+ }
75
+ const value = vars[key];
76
+ if (value !== undefined && value.includes("${{") && !WHOLE_VALUE_SECRET_RE.test(value)) {
77
+ ctx.addIssue({
78
+ code: "custom",
79
+ path: [key],
80
+ message: "only whole-value secret references are supported — write exactly " +
81
+ '"${{ secrets.NAME }}" (no partial interpolation)',
82
+ });
83
+ }
84
+ }
85
+ });
86
+ // ============================================================================
87
+ // Workspace (program-level persistent directories; agent memory is separate + auto-persisted)
88
+ // ============================================================================
89
+ /** Workspace-relative, no escapes: rejects absolute paths, backslashes, `..` and `.` segments. */
90
+ const persistPath = z
91
+ .string()
92
+ .min(1)
93
+ .max(512)
94
+ .refine((p) => !p.startsWith("/") && !p.includes("\\"), {
95
+ message: "persist paths must be workspace-relative (no leading / or backslashes)",
96
+ })
97
+ .refine((p) => p.split("/").every((seg) => seg !== "" && seg !== "." && seg !== ".."), {
98
+ message: "persist paths must not contain `..`, `.` or empty segments",
99
+ });
100
+ const workspaceSchema = z.strictObject({
101
+ persist: z.union([z.boolean(), z.array(persistPath).min(1).max(50)]).optional(),
102
+ });
103
+ // ============================================================================
104
+ // Budget and concurrency
105
+ // ============================================================================
106
+ const budgetSchema = z.strictObject({
107
+ max_tokens: z.number().int().positive().optional(),
108
+ max_usd: z.number().positive().finite().optional(),
109
+ max_duration_seconds: z.number().int().positive().optional(),
110
+ });
111
+ const concurrencySchema = z.union([
112
+ z.strictObject({ mode: z.literal("serial_by_key"), key: z.string().min(1).max(200) }),
113
+ z.strictObject({ mode: z.literal("serial") }),
114
+ z.strictObject({ mode: z.literal("unlimited") }),
115
+ ]);
116
+ // ============================================================================
117
+ // Agent capabilities: NONE on the manifest — tools/mcp/skills/memory are all per-agent
118
+ // ============================================================================
119
+ // Used only by the platform-extension permissions.tools (hosted run-permission scoping).
120
+ const toolGrantSchema = z.strictObject({
121
+ name: shortName,
122
+ config: z.record(z.string(), z.unknown()).optional(),
123
+ scope: z.array(z.string().min(1).max(200)).optional(),
124
+ });
125
+ // ============================================================================
126
+ // Runner selection
127
+ // ============================================================================
128
+ const hostedRunsOnLabel = z.enum([
129
+ "boardwalk/linux",
130
+ "boardwalk/linux-node",
131
+ "boardwalk/linux-python",
132
+ "boardwalk/linux-large",
133
+ ]);
134
+ const runsOnSchema = z.union([
135
+ z.strictObject({
136
+ kind: z.literal("self-hosted"),
137
+ pool: z.string().min(1).max(120),
138
+ labels: z.array(z.string().min(1).max(120)).optional(),
139
+ }),
140
+ z.strictObject({
141
+ label: hostedRunsOnLabel,
142
+ size: z.enum(["small", "medium", "large", "xlarge"]).optional(),
143
+ }),
144
+ hostedRunsOnLabel,
145
+ ]);
146
+ // ============================================================================
147
+ // Platform-extension fields (validated everywhere, enforced where the capability exists)
148
+ // ============================================================================
149
+ const containerSchema = z.strictObject({ image: z.string().min(1).max(512) });
150
+ const permissionAccess = z.enum(["none", "read", "write"]);
151
+ const permissionsSchema = z.strictObject({
152
+ id_token: z.enum(["none", "write"]).optional(),
153
+ artifacts: permissionAccess.optional(),
154
+ contents: permissionAccess.optional(),
155
+ secrets: z.array(secretRefSchema).optional(),
156
+ tools: z.array(toolGrantSchema).optional(),
157
+ });
158
+ const callableBySchema = z.union([
159
+ z.strictObject({ roles: z.array(z.enum(["owner", "admin", "member", "viewer"])).min(1) }),
160
+ z.strictObject({ workflows: z.array(workflowName).min(1) }),
161
+ z.enum(["anyone_in_org", "users_only", "workflows_only"]),
162
+ ]);
163
+ const egressSchema = z.union([
164
+ z.strictObject({
165
+ level: z.literal("custom"),
166
+ allow: z.array(z.string().min(1).max(256)).min(1),
167
+ include_defaults: z.boolean().optional(),
168
+ }),
169
+ z.strictObject({ level: z.enum(["none", "trusted", "full"]) }),
170
+ ]);
171
+ const notificationSchema = z.union([
172
+ z.strictObject({
173
+ on: z.enum(["completion", "failure", "cancelled"]),
174
+ channel: z.enum(["email", "webhook"]),
175
+ target: z.string().min(1).max(2048),
176
+ template: z.string().max(10_000).optional(),
177
+ }),
178
+ z.strictObject({
179
+ on: z.literal("budget_exceeded"),
180
+ channel: z.literal("email"),
181
+ target: z.string().min(1).max(2048),
182
+ }),
183
+ ]);
184
+ // ============================================================================
185
+ // The manifest
186
+ // ============================================================================
187
+ export const workflowManifestSchema = z.strictObject({
188
+ name: workflowName,
189
+ description: z.string().max(1000).optional(),
190
+ triggers: z.array(triggerSchema).min(1),
191
+ secrets: z.array(secretRefSchema).optional(),
192
+ env: envVarsSchema.optional(),
193
+ input_schema: jsonSchemaObject.optional(),
194
+ output_schema: jsonSchemaObject.optional(),
195
+ workspace: workspaceSchema.optional(),
196
+ budget: budgetSchema.optional(),
197
+ concurrency: concurrencySchema.default({ mode: "unlimited" }),
198
+ // NO capability fields (tools/mcp/skills/memory) — all per-agent via AgentOptions.
199
+ runs_on: runsOnSchema.default("boardwalk/linux"),
200
+ // Platform-extension fields.
201
+ container: containerSchema.optional(),
202
+ permissions: permissionsSchema.optional(),
203
+ callable_by: callableBySchema.default("anyone_in_org"),
204
+ egress: egressSchema.optional(),
205
+ notifications: z.array(notificationSchema).optional(),
206
+ });
207
+ /**
208
+ * Validate an already-extracted `meta` object (e.g. from `extract.ts` or a test fixture) and
209
+ * return the manifest, or throw a `MetaValidationError` listing every issue with its path.
210
+ */
211
+ export function validateMeta(meta) {
212
+ const result = workflowManifestSchema.safeParse(meta);
213
+ if (!result.success) {
214
+ const issues = result.error.issues
215
+ .map((i) => ` ${i.path.length > 0 ? i.path.join(".") : "(root)"}: ${i.message}`)
216
+ .join("\n");
217
+ throw new MetaValidationError(`Workflow \`meta\` failed manifest validation:\n${issues}`);
218
+ }
219
+ return result.data;
220
+ }
221
+ /** Thrown by {@link validateMeta} when a `meta` object violates the manifest schema. */
222
+ export class MetaValidationError extends Error {
223
+ constructor(message) {
224
+ super(message);
225
+ this.name = "MetaValidationError";
226
+ }
227
+ }
package/dist/meta.d.ts ADDED
@@ -0,0 +1,164 @@
1
+ export interface CronTrigger {
2
+ kind: "cron";
3
+ /** Cron expression (5-field standard or 6-field with seconds). */
4
+ expr: string;
5
+ /** IANA timezone (e.g. `America/Anchorage`). Defaults to UTC. */
6
+ timezone?: string;
7
+ }
8
+ /** Server engines only (the self-hosted server and the hosted Boardwalk platform) — `dev` has no listener. */
9
+ export interface WebhookTrigger {
10
+ kind: "webhook";
11
+ auth: "token" | "signature";
12
+ }
13
+ export interface ManualTrigger {
14
+ kind: "manual";
15
+ }
16
+ export type Trigger = CronTrigger | WebhookTrigger | ManualTrigger;
17
+ /**
18
+ * A built-in tool grant, with optional configuration. Used only by the platform-extension
19
+ * `permissions.tools` (hosted run-permission scoping) — agent tool selection is per-call.
20
+ */
21
+ export interface ToolGrant {
22
+ name: string;
23
+ config?: Record<string, unknown>;
24
+ scope?: readonly string[];
25
+ }
26
+ /**
27
+ * An MCP server an `agent()` call connects to (inline in `AgentOptions.mcp` — per-agent, no
28
+ * meta declaration). The program is the trusted layer: put credentials in `env`/`headers`
29
+ * directly (e.g. from `secrets.get`) — no interpolation syntax.
30
+ */
31
+ export type McpServerRef = {
32
+ name: string;
33
+ transport: "stdio";
34
+ command: string;
35
+ args?: readonly string[];
36
+ env?: Record<string, string>;
37
+ } | {
38
+ name: string;
39
+ transport: "http";
40
+ url: string;
41
+ headers?: Record<string, string>;
42
+ };
43
+ export type Concurrency = {
44
+ mode: "unlimited";
45
+ } | {
46
+ mode: "serial";
47
+ } | {
48
+ mode: "serial_by_key";
49
+ key: string;
50
+ };
51
+ export type HostedRunsOn = "boardwalk/linux" | "boardwalk/linux-node" | "boardwalk/linux-python" | "boardwalk/linux-large";
52
+ export type HostedRunnerSize = "small" | "medium" | "large" | "xlarge";
53
+ export interface HostedRunsOnObject {
54
+ label: HostedRunsOn;
55
+ size?: HostedRunnerSize;
56
+ }
57
+ export interface SelfHostedRunsOn {
58
+ kind: "self-hosted";
59
+ pool: string;
60
+ labels?: readonly string[];
61
+ }
62
+ export type RunsOn = HostedRunsOn | HostedRunsOnObject | SelfHostedRunsOn;
63
+ export interface Container {
64
+ /** Fully-qualified image reference. Hosted-platform capability. */
65
+ image: string;
66
+ }
67
+ /**
68
+ * A secret the program may read with `secrets.get(name)` — an allowlist entry, never a value.
69
+ * Resolution is engine-dependent: environment/`.env` on local engines, the encrypted vault on
70
+ * the Boardwalk platform. Secrets + env vars are the entire credential story.
71
+ */
72
+ export interface SecretRef {
73
+ name: string;
74
+ }
75
+ /**
76
+ * Environment variables for the run. A value is either non-secret plaintext, or a whole-value
77
+ * secret reference `"${{ secrets.NAME }}"` resolved at run time (never stored in the manifest).
78
+ * Referencing a secret here also grants the run access to it. Reserved `BOARDWALK_*` / `AWS_*`
79
+ * keys are not allowed.
80
+ */
81
+ export type EnvVars = Record<string, string>;
82
+ export type EgressPolicy = {
83
+ level: "none";
84
+ } | {
85
+ level: "trusted";
86
+ } | {
87
+ level: "full";
88
+ } | {
89
+ level: "custom";
90
+ allow: readonly string[];
91
+ include_defaults?: boolean;
92
+ };
93
+ export type RunPermissionAccess = "none" | "read" | "write";
94
+ export interface RunPermissions {
95
+ id_token?: "none" | "write";
96
+ artifacts?: RunPermissionAccess;
97
+ contents?: RunPermissionAccess;
98
+ secrets?: readonly SecretRef[];
99
+ tools?: readonly ToolGrant[];
100
+ }
101
+ export type OrgRole = "owner" | "admin" | "member" | "viewer";
102
+ export type CallableBy = "anyone_in_org" | "users_only" | "workflows_only" | {
103
+ roles: readonly OrgRole[];
104
+ } | {
105
+ workflows: readonly string[];
106
+ };
107
+ export type Notification = {
108
+ on: "completion" | "failure" | "cancelled";
109
+ channel: "email" | "webhook";
110
+ target: string;
111
+ template?: string;
112
+ } | {
113
+ on: "budget_exceeded";
114
+ channel: "email";
115
+ target: string;
116
+ };
117
+ /** Enforced by engines — breaching a budget terminates the run, it doesn't truncate silently. */
118
+ export interface Budget {
119
+ max_tokens?: number;
120
+ max_usd?: number;
121
+ max_duration_seconds?: number;
122
+ }
123
+ /**
124
+ * Persistent directories for the PROGRAM (not the same thing as agent memory).
125
+ *
126
+ * Every run gets a writable workspace directory that exists before your program runs; without
127
+ * `persist` it is scratch space, discarded at run end. `persist: true` persists the whole
128
+ * workspace across runs; a list persists exactly those WORKSPACE-RELATIVE subdirectories
129
+ * (`"cache"`, `"index"`, …) — `..` or absolute paths are validation errors. Persisted
130
+ * directories are hydrated at run start and written back at successful run end; concurrent
131
+ * runs sharing one are last-writer-wins, so prefer `concurrency: { mode: "serial" }`.
132
+ *
133
+ * Agent **memory** is separate and needs no declaration here: `agent(prompt, { memory: "<dir>" })`
134
+ * names any workspace-relative directory and the engine auto-persists it across runs (see
135
+ * {@link import("./types.js").AgentOptions}.memory). Use `workspace.persist` for non-memory
136
+ * state your program code manages directly.
137
+ */
138
+ export interface Workspace {
139
+ persist?: boolean | readonly string[];
140
+ }
141
+ /**
142
+ * The pure-literal contract a workflow program exports. Must be a literal — no variables,
143
+ * calls, spreads, or interpolation — so engines can statically extract it without executing
144
+ * the program. Validated by `workflowManifestSchema`; unknown fields are errors.
145
+ */
146
+ export interface WorkflowMeta {
147
+ name: string;
148
+ description?: string;
149
+ /** At least one trigger is required. */
150
+ triggers: readonly Trigger[];
151
+ secrets?: readonly SecretRef[];
152
+ env?: EnvVars;
153
+ input_schema?: Record<string, unknown>;
154
+ output_schema?: Record<string, unknown>;
155
+ workspace?: Workspace;
156
+ budget?: Budget;
157
+ concurrency?: Concurrency;
158
+ runs_on?: RunsOn;
159
+ container?: Container;
160
+ permissions?: RunPermissions;
161
+ callable_by?: CallableBy;
162
+ egress?: EgressPolicy;
163
+ notifications?: readonly Notification[];
164
+ }
package/dist/meta.js ADDED
@@ -0,0 +1,8 @@
1
+ // WorkflowMeta — the TypeScript shape of a workflow's `meta` export.
2
+ //
3
+ // A workflow program declares `export const meta = { … } satisfies WorkflowMeta`. The
4
+ // `satisfies` operator is type-only and erased at compile time, so it does NOT break the
5
+ // pure-literal static extraction engines perform over the source (see extract.ts). This type
6
+ // is the author-facing typing; `workflowManifestSchema` (manifest.ts) is the validator of
7
+ // record — the two are kept faithful to each other.
8
+ export {};
@@ -0,0 +1,3 @@
1
+ export { installHost, installInput, installConfig, takeDeclaredOutput, resetRuntime, requireHost, } from "./host.js";
2
+ export type { WorkflowHost } from "./host.js";
3
+ export type { AgentOptions, ToolDef, ArtifactBody, ArtifactRef, CallOptions, JsonValue, PhaseOptions, SleepArg, JsonSchema, } from "./types.js";
@@ -0,0 +1,6 @@
1
+ // @boardwalk-labs/workflow/runtime — the ENGINE-facing API.
2
+ //
3
+ // An engine imports this to install the host adapter and the trigger payload BEFORE
4
+ // evaluating a workflow program. Authors never import this — they import the hooks
5
+ // from "@boardwalk-labs/workflow".
6
+ export { installHost, installInput, installConfig, takeDeclaredOutput, resetRuntime, requireHost, } from "./host.js";
@@ -0,0 +1,110 @@
1
+ import type { McpServerRef } from "./meta.js";
2
+ /** A JSON Schema object (loosely typed — the engine validates against it). */
3
+ export type JsonSchema = Record<string, unknown>;
4
+ /** Any JSON value — the shape of the run's `config`, `output(...)`, and event payloads. */
5
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
6
+ [key: string]: JsonValue;
7
+ };
8
+ /**
9
+ * A program-defined tool for an {@link import("./index.js").agent} loop. `execute` runs in the
10
+ * program process — the trusted layer (it may read secrets); only its RETURN VALUE enters model
11
+ * context, subject to secret redaction.
12
+ */
13
+ export interface ToolDef {
14
+ /** Tool name the model sees. Unique within the call's tool set. */
15
+ name: string;
16
+ /** What the tool does — the model chooses tools by this. */
17
+ description: string;
18
+ /** JSON Schema for the tool's input. */
19
+ inputSchema: JsonSchema;
20
+ /** Runs in the program process; the resolved value is returned to the model (redacted). */
21
+ execute: (input: unknown) => Promise<unknown>;
22
+ }
23
+ /**
24
+ * Options for an {@link import("./index.js").agent} leaf call. Capabilities are PER-AGENT:
25
+ * each call brings its own `tools`, `mcp` servers, `skills`, and `memory` — the manifest
26
+ * declares none of them. A plain `agent(prompt)` is simple inference.
27
+ */
28
+ export interface AgentOptions {
29
+ /**
30
+ * The model, as an OPAQUE string passed VERBATIM to the provider — engines never parse,
31
+ * prefix, or rewrite it. Use whatever identifier your provider expects (e.g.
32
+ * `claude-sonnet-4-5` for Anthropic; `anthropic/sonnet-4.5` if that's what your local
33
+ * server serves it as). OPTIONAL — when omitted, the provider routes automatically (the
34
+ * default `boardwalk` provider's Auto lane). Fulfillment is chosen by `provider`, never
35
+ * by anything in this string.
36
+ */
37
+ model?: string;
38
+ /**
39
+ * Who fulfills this leaf. Defaults to `boardwalk` (Boardwalk-managed inference) on EVERY
40
+ * engine; your own keys are used only when this names a non-`boardwalk` provider — a
41
+ * built-in vendor (`anthropic`, `openai`, …) or a provider configured on the engine.
42
+ */
43
+ provider?: string;
44
+ /**
45
+ * JSON Schema for the leaf's structured output. When supplied, `agent()` resolves to the
46
+ * validated object (the run fails on mismatch); without it, to the leaf's final text.
47
+ */
48
+ schema?: JsonSchema;
49
+ /**
50
+ * Tools this leaf may use: engine built-in names, plus inline program-defined
51
+ * {@link ToolDef}s. Per-agent — no meta declaration. Defaults to none.
52
+ */
53
+ tools?: readonly (string | ToolDef)[];
54
+ /**
55
+ * MCP servers this leaf connects to, defined inline ({@link McpServerRef}). Per-agent — no
56
+ * meta declaration; the program supplies credentials directly (it is the trusted layer).
57
+ * Defaults to none.
58
+ */
59
+ mcp?: readonly McpServerRef[];
60
+ /**
61
+ * Skills loadable into this leaf's context, by name — resolved from the `skills/` directory
62
+ * deployed alongside the program (`skills/<name>.md`). Per-agent. Defaults to none.
63
+ */
64
+ skills?: readonly string[];
65
+ /**
66
+ * The leaf's persistent memory: a workspace-relative directory. Per-agent — the engine
67
+ * persists it across runs automatically (no `workspace.persist` declaration needed). The
68
+ * loop gets read/write file tools scoped to that directory and loads its index at turn
69
+ * start; the program may read/write the same files in plain code. Agents may use separate
70
+ * directories or deliberately share one.
71
+ */
72
+ memory?: string;
73
+ }
74
+ /** Options for a {@link import("./index.js").workflows}.call durable child run. */
75
+ export interface CallOptions {
76
+ /**
77
+ * Idempotency key for the child call. Defaults to a deterministic key over
78
+ * `(parent_run_id, target, input)` so a restarted parent re-attaches to the existing
79
+ * child instead of spawning a duplicate.
80
+ */
81
+ idempotencyKey?: string;
82
+ }
83
+ /**
84
+ * How long {@link import("./index.js").sleep} holds the run. A bare number is milliseconds;
85
+ * the object forms are explicit.
86
+ */
87
+ export type SleepArg = number | {
88
+ durationMs: number;
89
+ } | {
90
+ until: string | Date;
91
+ };
92
+ /** Options for {@link import("./index.js").Phase}, the run-timeline marker. */
93
+ export interface PhaseOptions {
94
+ /**
95
+ * Optional stable identifier for the phase. Omit for the engine to assign one in marker order.
96
+ * This is only an observability key; it is not a checkpoint/resume identifier.
97
+ */
98
+ id?: string;
99
+ }
100
+ /** Body for {@link import("./index.js").artifacts}.write — UTF-8 text or raw bytes. */
101
+ export type ArtifactBody = string | Uint8Array;
102
+ /** A stored artifact, returned by {@link import("./index.js").artifacts}.write. */
103
+ export interface ArtifactRef {
104
+ /** Stable artifact id. */
105
+ id: string;
106
+ /** The name it was stored under. */
107
+ name: string;
108
+ /** A download URL (signed and time-limited on hosted engines; a file URL locally). */
109
+ url: string;
110
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ // Option/argument types for the workflow hooks (Phase, agent, workflows.call, sleep, secrets).
2
+ export {};
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@boardwalk-labs/workflow",
3
+ "version": "0.1.0",
4
+ "description": "Author Boardwalk workflows in TypeScript: agent(), sleep(), workflows.call(), secrets, the manifest schema, and the run-event wire format.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=24"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./runtime": {
16
+ "types": "./dist/runtime.d.ts",
17
+ "default": "./dist/runtime.js"
18
+ },
19
+ "./extract": {
20
+ "types": "./dist/extract.d.ts",
21
+ "default": "./dist/extract.js"
22
+ }
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsc -p tsconfig.build.json",
31
+ "typecheck": "tsc --noEmit",
32
+ "lint": "eslint . --max-warnings 0",
33
+ "format": "prettier --write .",
34
+ "format:check": "prettier --check .",
35
+ "test": "vitest run",
36
+ "test:watch": "vitest"
37
+ },
38
+ "dependencies": {
39
+ "typescript": "^5.6.0",
40
+ "zod": "^4.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "@eslint/js": "^9.18.0",
44
+ "@types/node": "^24.0.0",
45
+ "eslint": "^9.18.0",
46
+ "prettier": "^3.4.0",
47
+ "typescript-eslint": "^8.20.0",
48
+ "vitest": "^3.0.0"
49
+ }
50
+ }