diff --git a/docs/SURFACE.md b/docs/SURFACE.md index d3b115c33..fae809bca 100644 --- a/docs/SURFACE.md +++ b/docs/SURFACE.md @@ -42,7 +42,8 @@ export default flow("chief", { const plan = await f.agent("planner", { task: `Research and plan: ${intent}`, - workspace: "acme/api: readonly", // compiles to relayauth path scopes + workspace: "acme/api", + permissions: { accessPreset: "readonly" }, // validated declaration; currently unenforced }); const ok = await f.human(`Ship this?\n${plan.summary}`, { to: "khaliq" }); @@ -290,6 +291,33 @@ The authoring surface deliberately narrows `steps: []`: `flows check` refuses it as `invalid_spec`, while the kernel accepts it. This is a chosen authoring-time narrowing, not a kernel guarantee. +### Per-agent permissions in TypeScript + +Supported `f.agent` calls accept an optional `permissions` declaration: + +```ts +const draft = await f.agent("writer", { + task: "Write drafts/post.md.", + permissions: { fileGlobs: ["drafts/**"], accessPreset: "readwrite" }, +}); +const review = await f.agent("reviewer", { + task: "Review drafts/post.md and flag issues; do not edit it.", + permissions: { fileGlobs: ["drafts/**"], accessPreset: "readonly" }, +}); +``` + +The exported `PermissionsSpec` has three optional camelCase fields: +`fileGlobs?: string[]`, `networkAllowlist?: string[]`, and +`accessPreset?: "readonly" | "readwrite"`. Array elements must be nonempty +strings. Empty or partial declarations are accepted without inferred defaults; +no workspace is required. Workspace names must not carry permission suffixes. + +These per-step permissions are validated and recorded in the compiled step spec +but are **not currently enforced** (gate 8 / #442). They are separate from +flow-wide `FlowHeader.workspace` / `tools.fs` scopes. The chief harness above +remains an aspirational example; this option does not make that entire harness +executable today. + ### Supported TypeScript LLM calls The local authored executor supports these signatures: diff --git a/packages/sdk/src/authored-worker-step.ts b/packages/sdk/src/authored-worker-step.ts index defa8ff51..38cdc60c8 100644 --- a/packages/sdk/src/authored-worker-step.ts +++ b/packages/sdk/src/authored-worker-step.ts @@ -7,7 +7,7 @@ import { classifyOutcome, type RunLifecycleOptions } from './cli/run.js'; import type { PreflightDiagnostic } from './preflight.js'; import { AuthoredFlowExecutionError } from './authored-flow-error.js'; import type { JournalClient } from './journal-client.js'; -import { SPEC_SCHEMA_VERSION, type FlowSpec, type StepSpec } from './spec.js'; +import { SPEC_SCHEMA_VERSION, type FlowSpec, type PermissionsSpec, type StepSpec } from './spec.js'; import { isSurfaceCompletionReason, readCompletedStepOutput, readSuccessfulOutput } from './authored-step-output.js'; import type { AuthoredFlowJournalStep } from './authored-flow-executor.js'; import { snapshotJsonValue } from './json-value.js'; @@ -97,13 +97,10 @@ export function authoredWorkerRunner( if (options.workspace !== undefined && WORKSPACE_PERMISSION_ANNOTATION.test(options.workspace)) { throw new AuthoredFlowExecutionError( 'unsupported_workspace_permission', - `flow "${definition.name}" step "${id}": workspace "${options.workspace}" declares a ` - + 'permission annotation ("...: readonly" / "...: readwrite"), but nothing enforces it — ' - + 'no parser anywhere in this package turns that annotation into a real restriction ' - + '(kernel/DAEMON-LIFECYCLE.md\'s permission model is untouched by f.agent). ' - + 'Silently accepting and ignoring it would let a flow believe a restriction is in effect ' - + "when it is not. Declare a bare surface name (no trailing \": readonly\"/\": readwrite\") " - + 'if you do not need enforcement, or use the declarative spec\'s `permissions` field, which is real.', + `flow "${definition.name}" step "${id}": workspace "${options.workspace}": ` + + "Workspace permission suffixes are unsupported. Use a bare workspace name and f.agent's " + + "permissions option, for example permissions: { fileGlobs: ['src/**'], accessPreset: 'readonly' }. " + + 'This declaration is validated and recorded with the step spec; it is not currently enforced (gate 8 / #442).', ); } if (options.cli !== undefined && typeof options.cli !== 'string') { @@ -130,6 +127,9 @@ export function authoredWorkerRunner( `f.agent options.transport must be 'direct' or 'relay' (got ${JSON.stringify(options.transport)}).`, ); } + const permissions = options.permissions; + const permissionsSnapshot = permissions === undefined ? undefined + : snapshotJsonValue(permissions, 'f.agent options.permissions') as unknown as PermissionsSpec; // Artifact detection only tells the truth for the local-agent DIRECT // path: that is the only case that runs in this same process, on this // same filesystem, so `options.cwd` (or `process.cwd()`) is provably @@ -146,6 +146,7 @@ export function authoredWorkerRunner( const before = artifactRoot === undefined ? undefined : await snapshotWorkspaceFiles(artifactRoot); const output = await run({ id, type: 'agent', instruction: options.task, + ...(permissionsSnapshot === undefined ? {} : { permissions: permissionsSnapshot }), ...(localAgentStream === undefined ? {} : { surfaces: { streams: [{ stream: localAgentStream }] } }), ...(options.workspace === undefined ? {} : { surfaces: { workspace: [{ surface: options.workspace }] } }), ...(options.cli === undefined ? {} : { cli: options.cli }), diff --git a/packages/sdk/tests/authored-agent-permissions.test.ts b/packages/sdk/tests/authored-agent-permissions.test.ts new file mode 100644 index 000000000..70ca71c3f --- /dev/null +++ b/packages/sdk/tests/authored-agent-permissions.test.ts @@ -0,0 +1,142 @@ +import { chmodSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import type { Server } from 'node:net'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { flow, type AgentOptions } from '@relayflows/surface'; +import { executeAuthoredFlow } from '../src/authored-flow-executor.js'; +import { JournalClient } from '../src/journal-client.js'; +import { sendOk, sendResult, sockPath, startLoopback } from './journal-client-loopback.js'; + +describe('authored agent permissions', () => { + let root: string; + let server: Server | undefined; + let socket: string | undefined; + + beforeEach(() => { + root = mkdtempSync(join(tmpdir(), 'authored-permissions-')); + const wrapper = join(root, 'adapter.mjs'); + writeFileSync(wrapper, `#!/usr/bin/env node +import { receiveWrapperRequest } from ${JSON.stringify(resolve('../../testdata/preflight/wrapper-session.mjs'))}; +if (process.argv[2] === 'auth') process.exit(0); +await receiveWrapperRequest(); +process.stdout.write('unused'); +`); + chmodSync(wrapper, 0o755); + writeFileSync(join(root, 'flows.json'), JSON.stringify({ cli: wrapper, models: ['test-model'] })); + writeFileSync(join(root, 'package.json'), '{"type":"module"}'); + }); + + afterEach(async () => { + if (server) await new Promise(resolve => server!.close(() => resolve())); + if (socket) rmSync(socket, { force: true }); + rmSync(root, { recursive: true, force: true }); + server = undefined; + socket = undefined; + }); + + async function capture(options: AgentOptions, local = false): Promise> { + socket = sockPath(); + const submitted: Record[] = []; + const steps = new Map>(); + server = startLoopback(socket, { + hello: ctx => sendOk(ctx), + 'run.start': (ctx, params) => { + const spec = params.spec as { steps: Record[] }; + const step = spec.steps[0]!; + const runId = `permissions-${steps.size}`; + steps.set(runId, step); + if (step.type === 'agent') submitted.push(step); + sendResult(ctx, { run_id: runId, status: 'completed', completion_reason: 'success', completed_steps: 1 }); + }, + 'journal.read': (ctx, params) => sendResult(ctx, { + entries: [{ entry_type: 'step.completed', step_id: steps.get(params.run_id as string)!.id, + payload: { completionReason: 'success', disposition: 'step_done', + output: { exit_code: 0, stdout_tail: 'ok', stderr_tail: '' } } }], + }), + }); + const client = new JournalClient(socket, { requestTimeoutMs: 2000 }); + await client.connect(); + await client.hello('permissions-test'); + try { + await executeAuthoredFlow(flow('permissions', async f => { + await f.agent('writer', options); + f.done('success'); + }), client, undefined, { + flowPath: join(root, 'permissions.flow.ts'), + ...(local ? { localAgentStream: 'test-stream' } : {}), + }); + expect(submitted).toHaveLength(1); + return submitted[0]!; + } finally { client.close(); } + } + + it.each(['readonly', 'readwrite'] as const)('lowers the full %s declaration', async accessPreset => { + const step = await capture({ task: 'x', workspace: 'repo', permissions: { + fileGlobs: ['drafts/**'], networkAllowlist: ['example.com'], accessPreset, + } }); + expect(step.permissions).toEqual({ + file_globs: ['drafts/**'], network_allowlist: ['example.com'], access_preset: accessPreset, + }); + }); + + it.each([ + [{ fileGlobs: ['drafts/**'] }, { file_globs: ['drafts/**'] }], + [{ networkAllowlist: [] }, { network_allowlist: [] }], + [{ accessPreset: 'readonly' }, { access_preset: 'readonly' }], + [{}, {}], + [{ fileGlobs: undefined, accessPreset: 'readonly' }, { access_preset: 'readonly' }], + ])('preserves partial declarations without defaults: %j', async (permissions, expected) => { + const step = await capture({ task: 'x', permissions } as AgentOptions); + expect(step.permissions).toEqual(expected); + }); + + it.each([{}, { permissions: undefined }])('preserves absence: %j', async options => { + const step = await capture({ task: 'x', ...options } as AgentOptions); + expect(step).not.toHaveProperty('permissions'); + }); + + it('accepts permissions without workspace on the local stream path', async () => { + const step = await capture({ task: 'x', cwd: root, permissions: { accessPreset: 'readonly' } }, true); + expect(step.permissions).toEqual({ access_preset: 'readonly' }); + }); + + it('reads the outer permissions property once', async () => { + const getter = vi.fn(() => ({ fileGlobs: ['drafts/**'] })); + const step = await capture({ task: 'x', get permissions() { return getter(); } }); + expect(getter).toHaveBeenCalledTimes(1); + expect(step.permissions).toEqual({ file_globs: ['drafts/**'] }); + }); + + async function refuse(permissions: unknown, message: string, code?: string): Promise { + const client = new JournalClient('/journal-must-not-be-contacted'); + const submit = vi.spyOn(client, 'runStart'); + await expect(executeAuthoredFlow(flow('invalid-permissions', async f => { + await f.agent('writer', { task: 'x', permissions } as AgentOptions); + f.done('success'); + }), client, undefined, { flowPath: join(root, 'permissions.flow.ts') })).rejects.toMatchObject({ + message: expect.stringContaining(message), ...(code ? { code } : {}), + }); + expect(submit).not.toHaveBeenCalled(); + } + + it.each([null, [], 'readonly', 42, true])('rejects non-object %j', async value => { + await refuse(value, 'permissions: expected an object', 'agent_cli_unresolved'); + }); + + it.each([ + [{ unknown: true }, 'permissions: unknown key "unknown"'], + [{ file_globs: ['src/**'] }, 'unknown key "file_globs" — did you mean "fileGlobs"?'], + [{ accessPreset: 'admin' }, 'accessPreset: expected readonly | readwrite'], + ...['fileGlobs', 'networkAllowlist'].flatMap(field => + ['src/**', [1], ['']].map(value => [{ [field]: value }, `${field}: expected an array of strings`])), + ] as [unknown, string][])('rejects invalid declaration %j', async (value, message) => { + await refuse(value, message, 'agent_cli_unresolved'); + }); + + it('rejects nested accessors without invoking them', async () => { + const getter = vi.fn(() => ['drafts/**']); + await refuse({ get fileGlobs() { return getter(); } }, 'accessors are not allowed'); + expect(getter).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/sdk/tests/authored-flow.test.ts b/packages/sdk/tests/authored-flow.test.ts index 4e4ea80eb..aaff566fd 100644 --- a/packages/sdk/tests/authored-flow.test.ts +++ b/packages/sdk/tests/authored-flow.test.ts @@ -159,12 +159,13 @@ describe('authored flow journal executor', () => { it('refuses a workspace permission annotation f.agent cannot enforce, before contacting the journal', async () => { const disconnectedJournal = new JournalClient('/journal-must-not-be-contacted'); - for (const workspace of ['src/**: readonly', 'src/**: readwrite', 'src/**:readonly']) { + for (const workspace of ['src/**: readonly', 'src/**: readwrite', 'src/**:readonly', 'src/**: READONLY ', 'src/**:\treadwrite\t']) { await expect(executeAuthoredFlow(flow('workspace-permission-not-enforced', async (f) => { await f.agent('worker', { task: 'must not dispatch', workspace }); f.done('success'); }), disconnectedJournal)).rejects.toMatchObject({ code: 'unsupported_workspace_permission', + message: expect.stringMatching(/f\.agent's permissions option.*not currently enforced/), }); } diff --git a/packages/sdk/tsconfig.tests.json b/packages/sdk/tsconfig.tests.json index 8eb1254be..aebe9706f 100644 --- a/packages/sdk/tsconfig.tests.json +++ b/packages/sdk/tsconfig.tests.json @@ -25,6 +25,7 @@ "tests/authored-flow-lifecycle-executor.test.ts", "tests/authored-flow-operation.test.ts", "tests/authored-flow.test.ts", + "tests/authored-agent-permissions.test.ts", "tests/flow-executor-chain.test.ts", "tests/input-binding.test.ts", "tests/journal-client-loopback.ts", diff --git a/packages/sdk/type-tests/agent-permissions.ts b/packages/sdk/type-tests/agent-permissions.ts new file mode 100644 index 000000000..2a80cb6e0 --- /dev/null +++ b/packages/sdk/type-tests/agent-permissions.ts @@ -0,0 +1,8 @@ +import type { AgentOptions, PermissionsSpec as SurfacePermissionsSpec } from '@relayflows/surface'; +import type { AgentStepSpec, PermissionsSpec } from '../src/spec.js'; + +type Assert = T; +type Equal = + (() => T extends A ? 1 : 2) extends (() => T extends B ? 1 : 2) ? true : false; +type _OptionalFieldParity = Assert>; +type _ExportParity = Assert>; diff --git a/packages/surface/src/context.ts b/packages/surface/src/context.ts index e924ad6b9..527e68eeb 100644 --- a/packages/surface/src/context.ts +++ b/packages/surface/src/context.ts @@ -9,9 +9,20 @@ export interface AgentResult { artifacts: string[]; } +/** Per-step declarations: validated and recorded, not currently enforced (gate 8 / #442). + * Separate from flow-wide FlowHeader.workspace / tools.fs scopes. + */ +export interface PermissionsSpec { + fileGlobs?: string[]; + networkAllowlist?: string[]; + accessPreset?: 'readonly' | 'readwrite'; +} + export interface AgentOptions { task: string; workspace?: string; + /** Validated declaration only; not currently enforced (gate 8 / #442). */ + permissions?: PermissionsSpec; cli?: string; model?: string; /** Working directory for the CLI subprocess; defaults to the flow-runner's cwd. */ diff --git a/packages/surface/src/index.ts b/packages/surface/src/index.ts index 3d6b729a0..061a2ec9b 100644 --- a/packages/surface/src/index.ts +++ b/packages/surface/src/index.ts @@ -7,7 +7,7 @@ export type { WorkerSummary, CloudHelper, } from "./cloud.js"; -export type { AgentOptions, AgentResult, LlmOptions, Ctx } from "./context.js"; +export type { AgentOptions, AgentResult, PermissionsSpec, LlmOptions, Ctx } from "./context.js"; export { COMPLETION_REASONS, RUN_COMPLETION_REASONS, diff --git a/packages/surface/tests/agent-permissions.test-d.ts b/packages/surface/tests/agent-permissions.test-d.ts new file mode 100644 index 000000000..577d6168f --- /dev/null +++ b/packages/surface/tests/agent-permissions.test-d.ts @@ -0,0 +1,31 @@ +import type { Ctx, PermissionsSpec } from '../src/index.js'; + +export async function agentPermissions(f: Ctx): Promise { + await f.agent('writer', { + task: 'Write a draft.', + permissions: { fileGlobs: ['drafts/**'], accessPreset: 'readwrite' }, + }); + await f.agent('reviewer', { + task: 'Review drafts/post.md; do not edit it.', + permissions: { fileGlobs: ['drafts/**'], accessPreset: 'readonly' }, + }); + const full: PermissionsSpec = { + fileGlobs: ['src/**'], networkAllowlist: ['example.com'], accessPreset: 'readonly', + }; + f.agent('full', { task: 'x', permissions: full }); + f.agent('partial', { task: 'x', permissions: { networkAllowlist: [] } }); + f.agent('empty', { task: 'x', permissions: {} }); + f.agent('omitted', { task: 'x' }); + // @ts-expect-error Only readonly and readwrite are supported. + f.agent('bad', { task: 'x', permissions: { accessPreset: 'admin' } }); + // @ts-expect-error Authoring keys are camelCase. + f.agent('bad', { task: 'x', permissions: { file_globs: [] } }); + // @ts-expect-error fileGlobs must be an array. + f.agent('bad', { task: 'x', permissions: { fileGlobs: 'src/**' } }); + // @ts-expect-error networkAllowlist must be an array. + f.agent('bad', { task: 'x', permissions: { networkAllowlist: 'example.com' } }); + // @ts-expect-error fileGlobs elements must be strings. + f.agent('bad', { task: 'x', permissions: { fileGlobs: [1] } }); + // @ts-expect-error networkAllowlist elements must be strings. + f.agent('bad', { task: 'x', permissions: { networkAllowlist: [1] } }); +} diff --git a/summary.md b/summary.md new file mode 100644 index 000000000..c409c0f00 --- /dev/null +++ b/summary.md @@ -0,0 +1,665 @@ +# PR: Expose per-agent permissions in TypeScript flows + +`f.agent(name, options)` now accepts `permissions` with `fileGlobs`, +`networkAllowlist`, and `accessPreset`, matching the declarative SDK contract. +The surface exports `PermissionsSpec`; SDK type assertions pin parity. Lowering +reads the new option once, snapshots it as JSON data, and passes it through the +existing validator and compiler without supplying defaults. + +Workspace suffix refusals now point to the new option and explicitly state that +these declarations are not currently enforced. Surface documentation includes +the writer/reviewer example and corrects the chief example's misleading scope +comment. Enforcement remains gate 8 / #442; flow-wide scope compilation is +unchanged. + +Regression coverage includes surface type errors, exact submitted kernel fields, +absent/partial declarations, local-stream calls without workspace, malformed +runtime declarations, closed-key suggestions, and nested accessor refusal. +Loopback captures demonstrate submission, not kernel persistence or enforcement. + +Verification below passed with CI's Bun 1.4.0 after the environment's older Bun +versions failed to read the lockfile. This is targeted verification, not a full +SDK suite or mutation verification. No gates, manifests, lockfiles, release +versions, kernel code, or enforcement paths changed. Release via the existing +surface-before-SDK process; a local packed install does not establish registry +availability. + +Pre-existing documentation debt: SDK `PermissionsSpec` JSDoc says “readonly +provably cannot write.” It is unchanged because correcting it also affects +generated schema descriptions and belongs in an explicit documentation/schema +change. `plan.md` and `reviewed-plan.md` were existing untracked inputs and are +left uncommitted. + +## Captured verification + +All commands ran from the repository root unless their command explicitly +changes directory. The status capture precedes creation of this report. + +Command: + +```sh +bash scripts/surface-package-gate.sh +``` + +Captured output: + +```text +bun install v1.3.6 (d530ed99) +2 | "lockfileVersion": 2, + ^ +error: Unknown lockfile version + at bun.lock:2:22 +UnknownLockfileVersion: failed to parse lockfile: 'bun.lock' + +warn: Ignoring lockfile +error: lockfile had changes, but lockfile is frozen +``` + +Exit status: 1. + +Command: + +```sh +npm exec --yes --package=bun@1.3.9 -- bash scripts/surface-package-gate.sh +``` + +Captured output: + +```text +bun install v1.3.9 (cf6cdbbb) +2 | "lockfileVersion": 2, + ^ +error: Unknown lockfile version + at bun.lock:2:22 +UnknownLockfileVersion: failed to parse lockfile: 'bun.lock' + +warn: Ignoring lockfile +error: lockfile had changes, but lockfile is frozen +``` + +Exit status: 1. + +Command: + +```sh +npm exec --yes --package=bun@1.4.0 -- bash scripts/surface-package-gate.sh +``` + +Captured output: + +```text +bun install v1.4.0 (34cbb9a40) + ++ @types/node@22.20.2 ++ typescript@5.9.3 ++ vitest@2.1.9 ++ ai-hist@0.4.1 ++ @relayfile/relay-helpers@0.4.11 + +183 packages installed [382.00ms] +$ tsc +$ bun run build && tsc -p tsconfig.test.json && vitest run +$ tsc + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/surface + + ✓ tests/slack-block-kit.test.ts (5 tests) 5ms + ✓ tests/flow.test.ts (20 tests) 10ms + ✓ tests/provider-triggers.test.ts (3 tests) 9ms + ✓ tests/declined.test.ts (1 test) 2ms + ✓ tests/triggers.test.ts (4 tests) 6ms + ✓ tests/helpers.snapshot.test.ts (1 test) 276ms + + Test Files 6 passed (6) + Tests 34 passed (34) + Start at 22:04:33 + Duration 803ms (transform 287ms, setup 0ms, collect 763ms, tests 308ms, environment 1ms, prepare 249ms) + +$ tsc -p ../../regressions/tsconfig.json && tsc -p tsconfig.test.json && node scripts/check-generated-helpers.mjs +HELPERS_GENERATED_OK airtable.ts, asana.ts, azure-blob.ts, box.ts, calendly.ts, clickup.ts, clients.ts, cloudflare.ts, confluence.ts, daytona.ts, docker-hub.ts, dropbox.ts, fathom.ts, gcp.ts, gcs.ts, github.ts, gitlab.ts, gmail.ts, google-calendar.ts, google-drive.ts, granola.ts, hubspot.ts, index.ts, intercom.ts, jira.ts, linear.ts, mailgun.ts, mixpanel.ts, neon.ts, notion.ts, onedrive.ts, pipedrive.ts, postgres.ts, posthog.ts, providers.ts, ramp.ts, recall.ts, reddit.ts, redis.ts, s3.ts, salesforce.ts, segment.ts, sendgrid.ts, sharepoint.ts, shopify.ts, shortcut.ts, slack.ts, stripe.ts, teams.ts, telegram.ts, webhook-server.ts, x.ts, zendesk.ts +bun pack v1.4.0 (34cbb9a40) +$ bun run build +$ tsc + +packed 1.79KB package.json +packed 2.90KB README.md +packed 2.50KB dist/cloud.d.ts +packed 2.30KB dist/cloud.d.ts.map +packed 44B dist/cloud.js +packed 102B dist/cloud.js.map +packed 0.94KB dist/completion.d.ts +packed 463B dist/completion.d.ts.map +packed 0.71KB dist/completion.js +packed 458B dist/completion.js.map +packed 2.56KB dist/context.d.ts +packed 1.92KB dist/context.d.ts.map +packed 46B dist/context.js +packed 106B dist/context.js.map +packed 1.31KB dist/effect-transport.d.ts +packed 1.40KB dist/effect-transport.d.ts.map +packed 2.0KB dist/effect-transport.js +packed 2.27KB dist/effect-transport.js.map +packed 2.63KB dist/flow.d.ts +packed 2.54KB dist/flow.d.ts.map +packed 9.00KB dist/flow.js +packed 9.31KB dist/flow.js.map +packed 3.32KB dist/helper-clients.d.ts +packed 0.94KB dist/helper-clients.d.ts.map +packed 1.75KB dist/helper-clients.js +packed 1.63KB dist/helper-clients.js.map +packed 265B dist/helpers/airtable.d.ts +packed 281B dist/helpers/airtable.d.ts.map +packed 319B dist/helpers/airtable.js +packed 293B dist/helpers/airtable.js.map +packed 333B dist/helpers/asana.d.ts +packed 348B dist/helpers/asana.d.ts.map +packed 368B dist/helpers/asana.js +packed 329B dist/helpers/asana.js.map +packed 358B dist/helpers/azure-blob.d.ts +packed 357B dist/helpers/azure-blob.d.ts.map +packed 390B dist/helpers/azure-blob.js +packed 340B dist/helpers/azure-blob.js.map +packed 321B dist/helpers/box.d.ts +packed 342B dist/helpers/box.d.ts.map +packed 358B dist/helpers/box.js +packed 323B dist/helpers/box.js.map +packed 351B dist/helpers/calendly.d.ts +packed 354B dist/helpers/calendly.d.ts.map +packed 383B dist/helpers/calendly.js +packed 336B dist/helpers/calendly.js.map +packed 345B dist/helpers/clickup.d.ts +packed 352B dist/helpers/clickup.d.ts.map +packed 378B dist/helpers/clickup.js +packed 334B dist/helpers/clickup.js.map +packed 175B dist/helpers/clients.d.ts +packed 243B dist/helpers/clients.d.ts.map +packed 1.86KB dist/helpers/clients.js +packed 1.53KB dist/helpers/clients.js.map +packed 363B dist/helpers/cloudflare.d.ts +packed 364B dist/helpers/cloudflare.d.ts.map +packed 393B dist/helpers/cloudflare.js +packed 344B dist/helpers/cloudflare.js.map +packed 363B dist/helpers/confluence.d.ts +packed 364B dist/helpers/confluence.d.ts.map +packed 393B dist/helpers/confluence.js +packed 344B dist/helpers/confluence.js.map +packed 345B dist/helpers/daytona.d.ts +packed 352B dist/helpers/daytona.d.ts.map +packed 378B dist/helpers/daytona.js +packed 334B dist/helpers/daytona.js.map +packed 270B dist/helpers/docker-hub.d.ts +packed 285B dist/helpers/docker-hub.d.ts.map +packed 324B dist/helpers/docker-hub.js +packed 297B dist/helpers/docker-hub.js.map +packed 345B dist/helpers/dropbox.d.ts +packed 352B dist/helpers/dropbox.d.ts.map +packed 378B dist/helpers/dropbox.js +packed 334B dist/helpers/dropbox.js.map +packed 257B dist/helpers/fathom.d.ts +packed 277B dist/helpers/fathom.d.ts.map +packed 313B dist/helpers/fathom.js +packed 289B dist/helpers/fathom.js.map +packed 245B dist/helpers/gcp.d.ts +packed 269B dist/helpers/gcp.d.ts.map +packed 304B dist/helpers/gcp.js +packed 280B dist/helpers/gcp.js.map +packed 321B dist/helpers/gcs.d.ts +packed 342B dist/helpers/gcs.d.ts.map +packed 358B dist/helpers/gcs.js +packed 323B dist/helpers/gcs.js.map +packed 335B dist/helpers/github.d.ts +packed 350B dist/helpers/github.d.ts.map +packed 369B dist/helpers/github.js +packed 332B dist/helpers/github.js.map +packed 339B dist/helpers/gitlab.d.ts +packed 350B dist/helpers/gitlab.d.ts.map +packed 373B dist/helpers/gitlab.js +packed 332B dist/helpers/gitlab.js.map +packed 333B dist/helpers/gmail.d.ts +packed 348B dist/helpers/gmail.d.ts.map +packed 368B dist/helpers/gmail.js +packed 329B dist/helpers/gmail.js.map +packed 388B dist/helpers/google-calendar.d.ts +packed 374B dist/helpers/google-calendar.d.ts.map +packed 415B dist/helpers/google-calendar.js +packed 356B dist/helpers/google-calendar.js.map +packed 370B dist/helpers/google-drive.d.ts +packed 368B dist/helpers/google-drive.d.ts.map +packed 400B dist/helpers/google-drive.js +packed 348B dist/helpers/google-drive.js.map +packed 345B dist/helpers/granola.d.ts +packed 352B dist/helpers/granola.d.ts.map +packed 378B dist/helpers/granola.js +packed 334B dist/helpers/granola.js.map +packed 345B dist/helpers/hubspot.d.ts +packed 352B dist/helpers/hubspot.d.ts.map +packed 378B dist/helpers/hubspot.js +packed 334B dist/helpers/hubspot.js.map +packed 6.69KB dist/helpers/index.d.ts +packed 6.0KB dist/helpers/index.d.ts.map +packed 5.12KB dist/helpers/index.js +packed 4.22KB dist/helpers/index.js.map +packed 351B dist/helpers/intercom.d.ts +packed 354B dist/helpers/intercom.d.ts.map +packed 383B dist/helpers/intercom.js +packed 336B dist/helpers/intercom.js.map +packed 327B dist/helpers/jira.d.ts +packed 346B dist/helpers/jira.d.ts.map +packed 363B dist/helpers/jira.js +packed 327B dist/helpers/jira.js.map +packed 339B dist/helpers/linear.d.ts +packed 350B dist/helpers/linear.d.ts.map +packed 373B dist/helpers/linear.js +packed 332B dist/helpers/linear.js.map +packed 345B dist/helpers/mailgun.d.ts +packed 352B dist/helpers/mailgun.d.ts.map +packed 378B dist/helpers/mailgun.js +packed 334B dist/helpers/mailgun.js.map +packed 351B dist/helpers/mixpanel.d.ts +packed 354B dist/helpers/mixpanel.d.ts.map +packed 383B dist/helpers/mixpanel.js +packed 336B dist/helpers/mixpanel.js.map +packed 249B dist/helpers/neon.d.ts +packed 273B dist/helpers/neon.d.ts.map +packed 307B dist/helpers/neon.js +packed 284B dist/helpers/neon.js.map +packed 335B dist/helpers/notion.d.ts +packed 350B dist/helpers/notion.d.ts.map +packed 369B dist/helpers/notion.js +packed 332B dist/helpers/notion.js.map +packed 351B dist/helpers/onedrive.d.ts +packed 354B dist/helpers/onedrive.d.ts.map +packed 383B dist/helpers/onedrive.js +packed 336B dist/helpers/onedrive.js.map +packed 357B dist/helpers/pipedrive.d.ts +packed 355B dist/helpers/pipedrive.d.ts.map +packed 388B dist/helpers/pipedrive.js +packed 338B dist/helpers/pipedrive.js.map +packed 351B dist/helpers/postgres.d.ts +packed 354B dist/helpers/postgres.d.ts.map +packed 383B dist/helpers/postgres.js +packed 336B dist/helpers/postgres.js.map +packed 261B dist/helpers/posthog.d.ts +packed 279B dist/helpers/posthog.d.ts.map +packed 316B dist/helpers/posthog.js +packed 291B dist/helpers/posthog.js.map +packed 7.74KB dist/helpers/providers.d.ts +packed 403B dist/helpers/providers.d.ts.map +packed 7.61KB dist/helpers/providers.js +packed 4.99KB dist/helpers/providers.js.map +packed 479B dist/helpers/ramp.d.ts +packed 403B dist/helpers/ramp.d.ts.map +packed 432B dist/helpers/ramp.js +packed 409B dist/helpers/ramp.js.map +packed 339B dist/helpers/recall.d.ts +packed 350B dist/helpers/recall.d.ts.map +packed 373B dist/helpers/recall.js +packed 332B dist/helpers/recall.js.map +packed 339B dist/helpers/reddit.d.ts +packed 350B dist/helpers/reddit.d.ts.map +packed 373B dist/helpers/reddit.js +packed 332B dist/helpers/reddit.js.map +packed 333B dist/helpers/redis.d.ts +packed 348B dist/helpers/redis.d.ts.map +packed 368B dist/helpers/redis.js +packed 329B dist/helpers/redis.js.map +packed 315B dist/helpers/s3.d.ts +packed 340B dist/helpers/s3.d.ts.map +packed 353B dist/helpers/s3.js +packed 321B dist/helpers/s3.js.map +packed 363B dist/helpers/salesforce.d.ts +packed 364B dist/helpers/salesforce.d.ts.map +packed 393B dist/helpers/salesforce.js +packed 344B dist/helpers/salesforce.js.map +packed 261B dist/helpers/segment.d.ts +packed 279B dist/helpers/segment.d.ts.map +packed 316B dist/helpers/segment.js +packed 291B dist/helpers/segment.js.map +packed 351B dist/helpers/sendgrid.d.ts +packed 354B dist/helpers/sendgrid.d.ts.map +packed 383B dist/helpers/sendgrid.js +packed 336B dist/helpers/sendgrid.js.map +packed 363B dist/helpers/sharepoint.d.ts +packed 364B dist/helpers/sharepoint.d.ts.map +packed 393B dist/helpers/sharepoint.js +packed 344B dist/helpers/sharepoint.js.map +packed 261B dist/helpers/shopify.d.ts +packed 279B dist/helpers/shopify.d.ts.map +packed 316B dist/helpers/shopify.js +packed 291B dist/helpers/shopify.js.map +packed 351B dist/helpers/shortcut.d.ts +packed 354B dist/helpers/shortcut.d.ts.map +packed 383B dist/helpers/shortcut.js +packed 336B dist/helpers/shortcut.js.map +packed 0.82KB dist/helpers/slack.d.ts +packed 0.85KB dist/helpers/slack.d.ts.map +packed 179B dist/helpers/slack.js +packed 137B dist/helpers/slack.js.map +packed 335B dist/helpers/stripe.d.ts +packed 350B dist/helpers/stripe.d.ts.map +packed 369B dist/helpers/stripe.js +packed 332B dist/helpers/stripe.js.map +packed 333B dist/helpers/teams.d.ts +packed 348B dist/helpers/teams.d.ts.map +packed 368B dist/helpers/teams.js +packed 329B dist/helpers/teams.js.map +packed 351B dist/helpers/telegram.d.ts +packed 354B dist/helpers/telegram.d.ts.map +packed 383B dist/helpers/telegram.js +packed 336B dist/helpers/telegram.js.map +packed 286B dist/helpers/webhook-server.d.ts +packed 296B dist/helpers/webhook-server.d.ts.map +packed 336B dist/helpers/webhook-server.js +packed 307B dist/helpers/webhook-server.js.map +packed 237B dist/helpers/x.d.ts +packed 265B dist/helpers/x.d.ts.map +packed 298B dist/helpers/x.js +packed 276B dist/helpers/x.js.map +packed 345B dist/helpers/zendesk.d.ts +packed 352B dist/helpers/zendesk.d.ts.map +packed 378B dist/helpers/zendesk.js +packed 334B dist/helpers/zendesk.js.map +packed 1.31KB dist/index.d.ts +packed 1.1KB dist/index.d.ts.map +packed 309B dist/index.js +packed 322B dist/index.js.map +packed 0.87KB dist/memory.d.ts +packed 0.72KB dist/memory.d.ts.map +packed 45B dist/memory.js +packed 104B dist/memory.js.map +packed 321B dist/plugin-contract.d.ts +packed 363B dist/plugin-contract.d.ts.map +packed 54B dist/plugin-contract.js +packed 122B dist/plugin-contract.js.map +packed 0.74KB dist/provider-trigger.d.ts +packed 0.69KB dist/provider-trigger.d.ts.map +packed 0.81KB dist/provider-trigger.js +packed 0.82KB dist/provider-trigger.js.map +packed 497B dist/runtime.d.ts +packed 478B dist/runtime.d.ts.map +packed 345B dist/runtime.js +packed 362B dist/runtime.js.map +packed 1.47KB dist/slack.d.ts +packed 1.33KB dist/slack.d.ts.map +packed 0.78KB dist/slack.js +packed 0.91KB dist/slack.js.map +packed 1.98KB dist/step.d.ts +packed 1.0KB dist/step.d.ts.map +packed 43B dist/step.js +packed 100B dist/step.js.map +packed 0.60KB dist/triggers.d.ts +packed 0.57KB dist/triggers.d.ts.map +packed 2.20KB dist/triggers.js +packed 2.23KB dist/triggers.js.map +packed 0.61KB dist/triggers/github.d.ts +packed 241B dist/triggers/github.d.ts.map +packed 0.67KB dist/triggers/github.js +packed 0.70KB dist/triggers/github.js.map +packed 390B dist/triggers/index.d.ts +packed 245B dist/triggers/index.d.ts.map +packed 465B dist/triggers/index.js +packed 455B dist/triggers/index.js.map +packed 0.59KB dist/triggers/slack.d.ts +packed 239B dist/triggers/slack.d.ts.map +packed 0.68KB dist/triggers/slack.js +packed 0.69KB dist/triggers/slack.js.map +packed 2.0KB src/cloud.ts +packed 0.89KB src/completion.ts +packed 2.43KB src/context.ts +packed 3.0KB src/effect-transport.ts +packed 11.42KB src/flow.ts +packed 2.0KB src/helper-clients.ts +packed 2.74KB src/helpers/README.md +packed 437B src/helpers/airtable.ts +packed 487B src/helpers/asana.ts +packed 0.52KB src/helpers/azure-blob.ts +packed 473B src/helpers/box.ts +packed 508B src/helpers/calendly.ts +packed 501B src/helpers/clickup.ts +packed 1.85KB src/helpers/clients.ts +packed 0.52KB src/helpers/cloudflare.ts +packed 0.52KB src/helpers/confluence.ts +packed 501B src/helpers/daytona.ts +packed 442B src/helpers/docker-hub.ts +packed 501B src/helpers/dropbox.ts +packed 429B src/helpers/fathom.ts +packed 417B src/helpers/gcp.ts +packed 473B src/helpers/gcs.ts +packed 490B src/helpers/github.ts +packed 494B src/helpers/gitlab.ts +packed 487B src/helpers/gmail.ts +packed 0.55KB src/helpers/google-calendar.ts +packed 0.53KB src/helpers/google-drive.ts +packed 501B src/helpers/granola.ts +packed 501B src/helpers/hubspot.ts +packed 9.88KB src/helpers/index.ts +packed 508B src/helpers/intercom.ts +packed 480B src/helpers/jira.ts +packed 494B src/helpers/linear.ts +packed 501B src/helpers/mailgun.ts +packed 508B src/helpers/mixpanel.ts +packed 421B src/helpers/neon.ts +packed 490B src/helpers/notion.ts +packed 508B src/helpers/onedrive.ts +packed 0.52KB src/helpers/pipedrive.ts +packed 508B src/helpers/postgres.ts +packed 433B src/helpers/posthog.ts +packed 6.58KB src/helpers/providers.ts +packed 0.65KB src/helpers/ramp.ts +packed 494B src/helpers/recall.ts +packed 494B src/helpers/reddit.ts +packed 487B src/helpers/redis.ts +packed 466B src/helpers/s3.ts +packed 0.52KB src/helpers/salesforce.ts +packed 433B src/helpers/segment.ts +packed 508B src/helpers/sendgrid.ts +packed 0.52KB src/helpers/sharepoint.ts +packed 433B src/helpers/shopify.ts +packed 508B src/helpers/shortcut.ts +packed 0.91KB src/helpers/slack.ts +packed 490B src/helpers/stripe.ts +packed 487B src/helpers/teams.ts +packed 508B src/helpers/telegram.ts +packed 458B src/helpers/webhook-server.ts +packed 409B src/helpers/x.ts +packed 501B src/helpers/zendesk.ts +packed 1.34KB src/index.ts +packed 0.81KB src/memory.ts +packed 277B src/plugin-contract.ts +packed 1.23KB src/provider-trigger.ts +packed 475B src/runtime.ts +packed 1.83KB src/slack.ts +packed 1.91KB src/step.ts +packed 2.54KB src/triggers.ts +packed 4.60KB src/triggers/README.md +packed 0.72KB src/triggers/github.ts +packed 443B src/triggers/index.ts +packed 0.71KB src/triggers/slack.ts + +/tmp/relayflows-surface-pack.fS3hBn/relayflows-surface-2.0.16.tgz + +Total files: 354 +Shasum: 56411bb58c5cbadab9a992ec785a348efb3436ce +Integrity: sha512-X0a0NoKLgkiDv[...]+cwcKajuuHsKA== +Unpacked size: 0.28MB +Packed size: 58.43KB +npm warn deprecated whatwg-encoding@3.1.1: Use @exodus/bytes instead for a more spec-conformant and faster implementation + +added 192 packages, and audited 193 packages in 2s + +65 packages are looking for funding + run `npm fund` for details + +6 vulnerabilities (4 moderate, 1 high, 1 critical) + +To address issues that do not require attention, run: + npm audit fix + +To address all issues (including breaking changes), run: + npm audit fix --force + +Run `npm audit` for details. + +changed 1 package, and audited 193 packages in 950ms + +65 packages are looking for funding + run `npm fund` for details + +6 vulnerabilities (4 moderate, 1 high, 1 critical) + +To address issues that do not require attention, run: + npm audit fix + +To address all issues (including breaking changes), run: + npm audit fix --force + +Run `npm audit` for details. + +> @relayflows/sdk@2.0.16 typecheck +> tsc --noEmit && tsc -p tsconfig.type-tests.json + +bun add v1.4.0 (34cbb9a40) +Resolving dependencies +Resolved, downloaded and extracted [292] +Saved lockfile + +installed @relayflows/surface@/tmp/relayflows-surface-pack.fS3hBn/relayflows-surface-2.0.16.tgz + +138 packages installed [1.91s] +PACKED_RUNTIME_OK name=packed-runtime-consumer completionReason=success +PACKED_RUNTIME_REFUSAL_OK invalidHeaders=9 forgedHandle=refused +PACKED_TYPESCRIPT_OK + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + + ✓ tests/authored-flow.test.ts (25 tests) 721ms + + Test Files 1 passed (1) + Tests 25 passed (25) + Start at 22:04:47 + Duration 1.75s (transform 444ms, setup 0ms, collect 839ms, tests 721ms, environment 0ms, prepare 49ms) + +``` + +Exit status: 0. + +Command: + +```sh +npm run typecheck:tests --prefix packages/sdk +``` + +Captured output: + +```text + +> @relayflows/sdk@2.0.16 typecheck:tests +> tsc -p tsconfig.tests.json + +``` + +Exit status: 0. + +Command: + +```sh +npm run build --prefix packages/sdk +``` + +Captured output: + +```text + +> @relayflows/sdk@2.0.16 build +> tsc && node scripts/make-cli-executable.mjs + +``` + +Exit status: 0. + +Command: + +```sh +(cd packages/sdk && ./node_modules/.bin/vitest run tests/authored-agent-permissions.test.ts tests/authored-flow.test.ts tests/validate.test.ts tests/verb-field-lint.test.ts tests/deterministic-llm.test.ts) +``` + +Captured output: + +```text + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + + ✓ tests/validate.test.ts (68 tests) 41ms + ✓ tests/verb-field-lint.test.ts (96 tests) 312ms + ✓ tests/authored-flow.test.ts (25 tests) 751ms + ✓ tests/deterministic-llm.test.ts (5 tests) 47ms + ✓ tests/authored-agent-permissions.test.ts (26 tests) 787ms + + Test Files 5 passed (5) + Tests 220 passed (220) + Start at 22:05:11 + Duration 2.61s (transform 1.04s, setup 0ms, collect 3.54s, tests 1.94s, environment 1ms, prepare 270ms) + +``` + +Exit status: 0. + +Command: + +```sh +(cd packages/sdk && ./node_modules/.bin/vitest run tests/authored-agent-permissions.test.ts) +``` + +Captured output: + +```text + + RUN v2.1.9 /home/daytona/.relayflow-v2-supervisor/durable/repository/packages/sdk + + ✓ tests/authored-agent-permissions.test.ts (26 tests) 840ms + + Test Files 1 passed (1) + Tests 26 passed (26) + Start at 22:05:37 + Duration 2.12s (transform 603ms, setup 0ms, collect 1.10s, tests 840ms, environment 0ms, prepare 43ms) + +``` + +Exit status: 0. + +Command: + +```sh +git diff --check +``` + +Captured output: + +```text +``` + +Exit status: 0. + +Command: + +```sh +git status --short +``` + +Captured output: + +```text + M docs/SURFACE.md + M packages/sdk/src/authored-worker-step.ts + M packages/sdk/tests/authored-flow.test.ts + M packages/sdk/tsconfig.tests.json + M packages/surface/src/context.ts + M packages/surface/src/index.ts +?? packages/sdk/tests/authored-agent-permissions.test.ts +?? packages/sdk/type-tests/agent-permissions.ts +?? packages/surface/tests/agent-permissions.test-d.ts +?? plan.md +?? reviewed-plan.md +``` + +Exit status: 0.