mirror of
https://github.com/vercel/workflow.git
synced 2026-09-14 19:59:43 +08:00
nathanc/shared-queue-http-handler
39 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c8bcde53d0 | [ci] Track the /flow route bundle size against main (#3739) | ||
|
|
f771585486 |
fix(world-vercel,world-local): hold process-wide state on globalThis (#3728)
* fix(world-vercel,world-local): hold process-wide state on globalThis Both packages are bundled into the host application's server build, and a bundler keys module identity on (resource, layer) — Next.js alone builds `instrument`, app-route, `ssr` and `edge` layers, so one process holds one copy of each of these modules per layer. Every module-scope `const`/`let` in them was therefore per-copy state wearing the costume of a process singleton. vercel/workflow#3493 made `@workflow/world-vercel` bundled rather than external and the events WebSocket transport regressed to HTTP for exactly this reason: the queue consumer registered its channel in the `instrument` copy's `Map` and the write path looked it up in the route copy's empty one. A deterministic miss, for the life of the process. `@workflow/world-local` had the same exposure all along — including `runFileLocks`, where a duplicated mutex simply stops mutually excluding. Add `globalSingleton()` to `@workflow/utils` (the primitive `@workflow/core` already hand-rolls for its World cache) and route every mutable module-scope binding in both worlds through it. Regression cover, in three layers: - `global-singleton.test.ts` pins the primitive's semantics. - `ws-transport-module-copies.test.ts` imports the module twice in one process and asserts a transport registered by one copy is found by the other — it fails on a plain module-scope `Map`, which is the shipped bug. - `scripts/lint/module-scope-state.mjs` fails the class: an AST rule banning mutable module-scope state in these packages, with `// per-copy-ok: <why>` as the deliberate escape. Wired into both packages' `vitest run src`, with fixture self-tests so it cannot rot into a no-op. * test(world-postgres): pin the module-scope-state rule for the postgres world It is deduped today only because `getRuntimeRequire()` loads it — a property of how it is loaded, not how it is written, and exactly what changed for world-vercel in #3493. The package is already clean; this keeps it that way. * docs(worlds): codify "a world must not hold mutable module state" A world package is loaded one of two ways, and only one of them gives it a single module instance: a runtime `require()` (deduped by Node) or the host's bundler (one copy per layer). Which one you get is a property of how the world is loaded, not of how it is written, and it changed under `world-vercel` in #3493 — so the rule has to be "never rely on module scope", not "rely on it until someone flips a config". Written down in the four places someone can meet it: - `docs/content/worlds/{v4,v5}/building-a-world.mdx` — a "Process-wide state" section for custom-world authors, with the loading modes spelled out and a nudge to prefer World-instance state over a global. - `packages/world/README.md` — the same constraint on the contract package. - `CLAUDE.md` — so the next contributor working in these packages sees it. - `packages/core/src/runtime/world.ts` — at the two static imports, which is where the difference between a bundled world and a required one originates. The rule's own error message now teaches it too, rather than naming a helper. Consolidates the guard while here: `@workflow/utils` owns the rule and its fixture self-tests, and sweeps every *published* `packages/world-*` discovered at runtime, so a world package added later is covered without anyone remembering. Each world keeps a one-assertion mirror for locality. * style: drop prose em dashes from this branch's new text #3704 landed a repo-wide writing pass hours after this branch was written and took `world-vercel/src` from 406 em dashes to 130 (`ws-transport.ts` alone went 35 to 1). This branch's docs section, README, comments and lint messages were written before that and would have put 36 of them straight back into the files that were just cleaned. Rewritten sentence by sentence rather than by substitution: an em dash becomes a colon, a comma, a full stop or a parenthetical depending on what it was doing. Also fixes a real defect the sweep surfaced: `world-postgres`'s guard test was generated through a shell heredoc and had literal backslash-backticks in its doc comment. * Update .changeset/world-module-scope-state.md Co-authored-by: Peter Wielander <mittgfu@gmail.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * fix(core): build the entrypoint's queue handler from getWorld() Adopted from #3666 by @MintedKenny, which implements #3665 and could not run CI as a fork PR. One line of behavior: `workflowEntrypoint`'s lazy handler init calls `getWorld()` rather than `getWorldHandlers()`. `getWorldHandlers()` owns a second, build-time-safe cache, so calling it from the runtime route built a *second* World in the same process. That costs a stateful World duplicate resources on every instance — world-postgres eagerly constructs a `pg.Pool` (default `max: 10`) and a nested world-local World in `createWorld()`, so self-hosted users have been paying for two of each — and, for a bundled world package, the two Worlds are built by two different module copies, which is the mechanism behind the WS transport regression the rest of this branch contains. The public `getWorldHandlers()` and its separate build-time cache are unchanged; only the runtime route stops using it. Kept from the original: the regression test asserting the factory runs exactly once, and the api-reference wording (re-applied over #3704's list punctuation). Not taken: renaming the `workflow.route.get_world_handlers` span. It is a distinct span from the per-request `workflow.route.get_world` at the top of the flow route, and reusing that name would collide with it in traces and in `runtime-trace-mode.test.ts`; a comment records why the name outlived the call. Co-authored-by: Kenneth <kenneth@standardforensics.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: address AI review on the module-scope work Two blocking findings, both real: - **Cross-version state sharing** (`ws-transport.ts`). A process can hold two *published versions* of `@workflow/world-vercel` (a transitive dependency pinning an older `@workflow/core`, which depends on this package by exact version). Both wrote to the same unversioned `Symbol.for` key, so one version's write path could be handed a `WsEventsTransport` built by the other's class and frame against a protocol it may not share — with no version negotiation on the socket to catch it. `shapeVersion` cannot express this: the container is stable, the hazard is its contents. The registry and the events dispatcher recycler are now keyed by package version. The plain connection pools stay unversioned; sharing those across copies is the point. - **The documented pattern failed the rule this PR adds.** The custom-world docs teach `store[StateKey] ??= …`, which the rule flagged as a field write. It now recognizes state rooted at `globalThis`, following one alias hop, which is also what `core/private.ts:23` and `next/src/index.ts:58` are already doing correctly (core drops 26 findings to 22, next 7 to 6). The docs also now say outright that `globalSingleton()` is the same thing, since AGENTS.md prescribes it and the page did not mention it. Rule precision, from the review's probes: - `.mts`/`.cts` are scanned. `@workflow/world-testing` is authored in `.mts`, so its entry in the sweep was passing vacuously — with the walk fixed it reports a real finding, now annotated (it is a standalone `serve()` entry). - Mutations in top-level statements no longer count. A table filled at module evaluation is identical in every copy; divergence needs a later write. - `static` class fields are collected, attributed to the class name. - An *exported* binding initialized to an empty collection is a finding on its own, which approximates the cross-file case the walk cannot resolve. Six fixtures pin the new behavior. The rule's header now states what it does not see, and AGENTS.md states where the sweep stops and why core is not gated yet. Also tags `resetGlobalSingletonForTest` `@internal`. * fix(lint): attribute a static-field write to the field, not the class The static-field support added in the previous commit keyed `declared` on the class name, so a class carrying more than one mutable static reported one finding instead of one per field, and labelled the survivor with whichever mutation was seen first. On a two-static fixture it reported `static Registry.latch (`.set()`)`: the name of one field, the reason belonging to the other, pointing the reader at the wrong line. Key static fields `Class.field` and resolve a write to the same shape, via a new `memberPath()` that takes the first two segments of a member chain and tries that key before the bare root identifier. Two follow-ons fall out of having the path: - `this.field` inside a `static` member resolves to the class, which is the ordinary way to write the mutation. `staticClassOf()` returns nothing for an instance member, where `this` is an instance and the state is per-instance rather than per-copy, and nothing inside a nested `function`, which rebinds `this`. - `state.count++` is now a finding, like the `state.count += 1` that `assignment()` already reported. Fixtures pin all four, including the instance-field case that must stay clean. The four world packages still report zero, and the extracted `recordMutation()` keeps the file at its previous two Biome complexity warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix: make module duplication inert across every bundled package `@workflow/core` is bundled into the host server build the same way the worlds are, and always has been — the original repro measured three live copies in every arm, including the pre-#3493 external one. One instance is not reachable: layers cannot share a module, and core cannot be external because it *is* workflow code (`runtime/start.ts:253` and nine methods in `runtime/run.ts` are `'use step'`), so it must go through the SWC loader. The Next integration already encodes that rule by removing workflow-bearing packages from `serverExternalPackages`. So the duplication stays and the hazard is removed instead, everywhere the duplication can happen. `@workflow/core` (22 findings to 0): warn-once latches in `constants.ts`, `start.ts` and `telemetry.ts`; the source-map tracer cache; the VM script cache; the QuickJS compiled-assets and baseline caches; the dev-server port cache (its own comment already said "per process"); the text codecs; the zstd browser decoder; and the `useStep` closure brand, where a function marked by one copy was invisible to another. The one with teeth was `step-single-flight.ts`: a per-copy map is not single-flight. Two invocations reaching it through different layers would each believe they were alone in the process and both run the step body, silently degrading in-process dedup to the cross-process residual its own doc scopes out to the ownership lease. Also `@workflow/world` (a warn-once set, hand-rolled onto `globalThis` to keep that package dependency-free), `@workflow/ai` (the lazy OTel API), and `@workflow/nest` (bootstrap config in a module-level `let` and two static class fields — configure one copy, read another, and the controller is unconfigured for the life of the process). Five sites are deliberately per-copy and now say why: state keyed on objects that never cross copies (the barrier safety-net `WeakSet`, the QuickJS pending byte `WeakMap`), the synchronously-scoped guest-code sink, and the OTel diagnostic that reports what *this* copy sees. The sweep now covers all of it. Packages with a single module graph stay out (build-time code, the CLI, the o11y UI, the test runner) and AGENTS.md records which and why. Found while doing this: two static fields on one class collapsed into a single entry in the rule, so `WorkflowModule.options` was invisible behind `WorkflowModule.outDir`. Statics are now keyed `Class.field`. * fix(world): suppress noAssignInExpressions on the globalThis idiom The hand-rolled form trips Biome, as it does in `packages/core/src/private.ts`, which carries the same suppression. Restructuring it into a helper function instead would hide the state behind a call the module-scope rule cannot follow, so the binding would stop being recognized as off-module and the package would report a finding for correct code. * fix: sweep every bundled package, and mark utils side-effect free @shalabhc asked on review whether `@workflow/utils` needs this too. It does, and so do three others: `utils`, `errors`, `serde` and `workflow` all end up in the host application's server build and none were in the sweep. All four report zero today, which is exactly the state `world-testing` appeared to be in before the `.mts` walk was fixed and it turned out to have a real finding. Being clean and being *checked* are different properties, and only the second one survives the next contributor. `sideEffects: false` on `@workflow/utils`: verified that every module in the package only declares (no import-time work), so a bundler can now drop the unused parts of the barrel instead of keeping all ~64 KB of it because three packages import one 476-byte function. --------- Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: Peter Wielander <mittgfu@gmail.com> Co-authored-by: Kenneth <kenneth@standardforensics.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Peter Wielander <peter.wielander@vercel.com> |
||
|
|
9760f640bb | [e2e] Change race repro hook poke to soft-degrade instead of hard-stop at budget (#3561) | ||
|
|
e1e64e3de3 |
docs: apply Vercel technical writing standards (#3704)
* docs: apply Vercel technical writing standards Audit the complete documentation corpus, package READMEs, skills, and source TSDoc/comments against the vercel-technical-writing skill and style-rules.md. Normalize sentence-case headings without changing published anchors, remove prose em dashes and filler wording, improve active voice and self-contained phrasing, standardize product/brand capitalization, American English, list punctuation, units, and code fence languages, and preserve exact runtime strings/table placeholders. All executable code is unchanged. Modified skills have their metadata versions bumped. * docs: extend writing audit to repository Markdown Apply the same technical-writing rules to design documents, compiler specifications, workbench guides, package changelogs, and the remaining tracked Markdown outside the deployed docs corpus. Preserve historical meaning, commands, output literals, table placeholders, and heading anchors. * docs: exclude generated package changelogs from audit |
||
|
|
b3dbc6d264 | [docs] v5 changes docs: what's new, world upgrade guide, migration skills (#3100) | ||
|
|
f5591aa278 | [e2e] Fix event-log-race-repro for local/postgres (#3558) | ||
|
|
0c5a6495bc | [ci] Report all three event-log-race-repro lanes in one small PR comment (#3556) | ||
|
|
dc85865718 | [core] Drop pre-slot event ID support and preconditionGuard capability (#3519) | ||
|
|
01991edeeb |
feat(world-vercel): synthesize per-event client spans on the WS transport (#3452)
* feat(world-vercel): synthesize per-event client spans on the WS transport PR #3084 added the opt-in `WORKFLOW_EVENTS_TRANSPORT=ws` path and listed "no client-side span on the WS path" as a known limitation. Because event writes become multiplexed frames on one long-lived socket rather than individual `fetch` calls, the per-event `http POST` CLIENT span that the HTTP transport produced simply disappeared — traces went from one span per event to nothing between the invocation and the server. Restore it by synthesizing a request-shaped span around each frame, and give the upgrade its own span: - Extract `withHttpClientSpan` / `recordClientSpanStatus` from `instrumentedFetch` in `http-core.ts` so the synthetic span is emitted by the same envelope as the real one and cannot drift from it. `InstrumentedFetchOptions` now extends `HttpClientSpanOptions`. - `postEventFrameOverWs` opens `http POST` with `url.full` pointing at the v4 REST endpoint the frame is forwarded into, so per-event traces and latency dashboards keep working across the flag. Extract `eventsV4Url` so that URL cannot drift from the one the HTTP path actually requests. - Tag both transports with `workflow.events.transport` (`http` | `ws`) and `workflow.event.type`; the WS path additionally sets `network.protocol.name=websocket`, `workflow.events.ws.url` (the real wire destination) and `workflow.events.ws.req_id` (join key to the server's log line for the frame), so the span is never mistaken for a real HTTP request. - Add a `workflow.events.ws.connect` span around the upgrade — the one genuinely-HTTP request here, previously the invisible half of every WS write's latency — carrying `workflow.events.ws.reconnect_attempt`. This also puts `resolveUpgradeHeaders`' trace-context injection inside a client span, as AGENTS.md requires. - Fix `parseServer` to treat `wss:` as TLS (port 443, not 80). Out of scope, deliberately: per-frame `traceparent` (needs a frame-meta field plus a server change) and Vercel's outgoing-requests view (that instruments global `fetch`, so a frame structurally cannot appear there). Covered by `ws-transport-spans.test.ts`, which drives the real selection + transport + adapter stack over a fake socket and asserts span shape, failure reporting, retry behaviour and HTTP/WS parity. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: shalabhchaturvedi-7802 <shalabh.chaturvedi@vercel.com> Co-Authored-By: shalabhc <shalabh.chaturvedi@vercel.com> * chore: trim WS spans changeset to the user-facing summary Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: shalabhchaturvedi-7802 <shalabh.chaturvedi@vercel.com> Co-Authored-By: shalabhc <shalabh.chaturvedi@vercel.com> * fix(world-vercel): only tag event-write spans with transport Signed-off-by: Shalabh Chaturvedi <shalabh.chaturvedi@vercel.com> Co-Authored-By: shalabhchaturvedi-7802 <shalabh.chaturvedi@vercel.com> * fix(world-vercel): format WS transport span regression test Signed-off-by: Shalabh Chaturvedi <shalabh.chaturvedi@vercel.com> Co-Authored-By: Shalabh Chaturvedi <shalabh.chaturvedi@vercel.com> --------- Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> |
||
|
|
0f4b35f629 | [world-local] Fix CORRUPTED_EVENT_LOG from hook-resume staging slot holes (#3492) | ||
|
|
4174a6ea73 | [ci] Shrink the event-log race repro job 100x and add a local world-postgres runner (#3273) | ||
|
|
11dc036854 |
ci: stop deploying changeset-release/main, run its e2e against production (#3243)
* ci: stop deploying changeset-release/main, run its e2e against production The changesets action force-pushes `changeset-release/main`, and it can point at exactly main's HEAD SHA. Vercel keeps one commit status per project per SHA, so when both a production deployment (from main) and a preview deployment (from changeset-release/main) are built for the same commit, whichever finishes last owns the status. On 2026-07-30 the preview finished last, so `vercel/wait-for-deployment-action` — which reads the deployment ID out of that status — handed production e2e runs a preview deployment ID and forked runs across environments. Disable git deployments for that branch in every Vercel project rooted in this repo, and give the changeset PR's Vercel e2e lanes a deployment to test that actually exists: main's production deployment for the PR's base SHA, resolved by SHA so a mid-flight production build is waited out rather than silently replaced by an older one. Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> * ci: resolve changeset-release e2e deployments with the wait action, tokenless Per review: with changeset-release/main no longer deployed, main SHAs can never again be deployed to a second environment of these projects, so the per-SHA commit status the action reads is unambiguous for exactly this lane. Reuse vercel/wait-for-deployment-action with environment: production and sha pinned to the PR base SHA instead of the Vercel-API polling script, drop the script and its VERCEL_TOKEN usage, and inherit the action's inactive/skipped-build handling. Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> --------- Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> |
||
|
|
bc53e5a31b |
[ci] Backport only stability fixes to stable, default to claude-opus-5 (#3092)
|
||
|
|
2b63c6ed72 |
docs(agents): note lint/format/typecheck are advisory, not blocking (#2886)
Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
49a50e83d9 | Document configuration environment variables (v5) (#2468) | ||
|
|
90efb9653c |
otel(world-vercel): inject trace context on v4 event requests (#2533)
* otel(world-vercel): inject trace context on v4 event requests The v4 event path (createEvent / getEvent / listEvents) routes through fetchV4 → global fetch with a custom undici dispatcher, bypassing both the makeRequest path (where the explicit W3C trace-context injection lives) and ambient undici auto-instrumentation. As a result, v4 event traffic from the flow route carried no traceparent, so workflow-server could not parent its spans to the invocation — its spans never joined the /flow execution trace, even though v2/v3 reads/writes (via makeRequest) did join. fetchV4 now calls injectTraceContextIntoHeaders before fetch, the single choke point for all v4 create/get/list requests, mirroring makeRequest. No-op when no OpenTelemetry SDK is registered. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(agents): require trace-context injection on new world-vercel HTTP paths Codify the guardrail that the v4 regression revealed: any outgoing world-vercel request must call injectTraceContextIntoHeaders (auto- instrumentation can't be relied on with the custom dispatcher / global fetch), with a test in trace-propagation.test.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * changeset: make v4 trace-propagation note concise Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
e163422551 |
Add hook.hasConflict for early hook conflict detection (#2015)
* feat: add hook ready promise * test: cover hook ready continuation scheduling * feat: replace hook.ready with hook.hasConflict (Promise<boolean>) - hook.hasConflict resolves true when the token is owned by another active hook, false once registration is committed — no throw, so workflows can branch on conflicts early. Awaiting it suspends the workflow to commit the hook registration (createHook alone does not). - Chain the already-created fast-path through promiseQueue so resolution order matches event-log order (review feedback). - Skip inline step execution when a suspension has an awaited hook creation so the hasConflict continuation can advance independently of step execution (review feedback). - Update unit tests, e2e tests, workbench workflows, and v4/v5 docs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: fix inconsistent hasConflict bullet in create-webhook reference State both resolution values explicitly (true = token already owned, false = registered) instead of a parenthetical that only described the false case. * docs: require docs preview links in PR descriptions for docs changes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: restore SWC Plugin heading in AGENTS.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Nathan Rajlich <n@n8.io> |
||
|
|
2a010755f5 |
Remove pull_request_target trigger from backport workflow (#1972)
Drops the label-based backport override in favor of workflow_dispatch. The pull_request_target trigger has security concerns (it runs with write permissions on PR-controlled events), and we already have a manual dispatch path that covers the same use case. |
||
|
|
4c165b6276 |
Fix backport AI permission, surface infra failures, and allow manual dispatch (#1943)
* Hoist AI model env, fix opencode external_directory permission, fail loud on AI infra errors Three related fixes triggered by the failed run on #1935: 1. Hoist the AI model name to a top-level `AI_MODEL` env var (`anthropic/claude-opus-4.7`); both `opencode run` invocations now interpolate `vercel/${AI_MODEL}` so the model is specified in exactly one place. 2. Switch `OPENCODE_PERMISSION` from the bare-string shortcut `"allow"` to the explicit object form `{"*":"allow","external_directory":"allow"}`. The shortcut was observed not to override `external_directory` (which defaults to "ask" and auto-rejects in non-interactive `opencode run`), causing the conflict-resolution AI to fail when reading scratch files it created under `/tmp/`. 3. The `Resolve conflicts with opencode` step no longer uses `continue-on-error`, and now distinguishes two outcomes via an AI- written outcome file (`.backport-conflict-outcome.json`): - `{"status":"resolved"}` — the legitimate clean path; cherry-pick continues and the backport PR is opened. - `{"status":"unresolved", ...}` — the legitimate "AI couldn't do it, hand off to a human" path; `resolved=false` is set and the conflict-failure comment is posted on the source PR. - Anything else (missing file, malformed JSON, unknown status) is treated as an opencode/AI Gateway infra failure: the step exits non-zero, the workflow fails red, and the misleading "couldn't resolve" comment is suppressed. The prompt + scratch files are also moved into the workspace so opencode never needs `external_directory` access anyway. * Allow manual workflow_dispatch with ref+model inputs; use AI_MODEL in PR body Add a `workflow_dispatch` trigger to the backport workflow with two optional inputs: - `ref` — commit SHA on `main` to back-port (defaults to `main` HEAD) - `model` — overrides the default AI model used by opencode for the decision and conflict-resolution steps (defaults to the workflow's hardcoded `AI_MODEL`) The top-level `AI_MODEL` env var now uses `${{ inputs.model || 'anthropic/claude-opus-4.7' }}` so manual runs pick up the override without changing anything else. Manual dispatch (like the `backport-stable` label) always forces a backport regardless of any AI verdict — the operator's intent is explicit by virtue of triggering the workflow. The PR body shows "Triggered manually via `workflow_dispatch`." in that case. The PR body's conflict-resolution attribution also now interpolates `${AI_MODEL}` (e.g. "opencode with `anthropic/claude-opus-4.7`") instead of hardcoding "Claude Opus" so the text stays accurate if the default model is later changed. * Address PR review: also detect leftover conflict markers in staged files The previous `Resolve conflicts with opencode` sanity check used `git diff --diff-filter=U` to detect unresolved cherry-pick conflicts, which only catches unmerged index entries. That misses the case where the AI runs `git add` on a file that still has `<<<<<<<` / `=======` / `>>>>>>>` markers in its content — git happily stages the broken file as a normal modification. Add a second check using `git diff --check --cached`, which emits `leftover conflict marker` lines when any staged content still has the standard markers. Grep specifically for that phrase so unrelated whitespace warnings don't trip the check. Also update the inline comment to accurately describe what each check covers (per Copilot's review on #1943). |
||
|
|
b1fc9adfa2 |
Restructure backport workflow with AI-driven decisions (#1934)
* Restructure backport workflow with AI-driven decisions Run the backport workflow on every push to main and have AI analyze each commit to decide whether to recommend a backport to stable, instead of relying on a manual backport-stable label. The action now always opens a PR for human review and never pushes directly to stable. The backport-stable label is preserved as a manual override that forces a backport regardless of the AI verdict. * Address PR review: randomized output delimiters and updated manual instructions - Use uuidgen-based delimiters when writing multiline values (PR title, body, AI reasoning) to $GITHUB_OUTPUT, so user-/model-controlled content cannot collide with or inject into the heredoc terminator. - Update the manual conflict-resolution instructions to push a backport branch and open a PR against stable, matching the new "never push directly to stable" policy. - Document the head-commit-only behavior of the push trigger inline in the workflow. |
||
|
|
cd50618d1f |
ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources (#1882)
* ci: switch Vercel deployment-protection bypass to OIDC Trusted Sources The e2e, benchmark, and docs-smoke CI jobs previously used the static `VERCEL_AUTOMATION_BYPASS_SECRET` deployment-protection bypass token to reach protected Vercel deployments. Switch them over to the new OIDC Trusted Sources flow: the GitHub Actions runner mints a short-lived OIDC token via `core.getIDToken()` and forwards it on requests in the `x-vercel-trusted-oidc-idp-token` header. Each workbench project (and `workflow-docs`) has been configured with a matching trusted-source rule: aud=https://github.com/vercel, repository=vercel/workflow The shared header helper now lives at `scripts/trusted-sources-headers.mjs` and is imported by both the e2e/bench tests and the docs smoke script, removing the previous duplication. * rename to VERCEL_OIDC_TOKEN and wire through world-vercel - Rename the env var from VERCEL_TRUSTED_OIDC_TOKEN to VERCEL_OIDC_TOKEN to match Vercel's convention (also read by @vercel/oidc's getVercelOidcToken()). - In @workflow/world-vercel, replace the legacy VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS / x-vercel-protection-bypass flow with VERCEL_OIDC_TOKEN / x-vercel-trusted-oidc-idp-token. The trusted-source header is attached on every outbound workflow-server request (both proxied through api.vercel.com and direct). - Drop the bypass header from the encryption-key and resolve-latest-deployment fetches: those go to api.vercel.com which is public. - Drop VERCEL_WORKFLOW_SERVER_PROTECTION_BYPASS plumbing from tests.yml. - Update the pending world-vercel changeset to describe the final trusted-sources flow. * . * . * ci: add statuses:read permission for wait-for-vercel-project action The action queries /commits/{sha}/status (Commit Statuses API) in addition to the Deployments API, in order to extract the Vercel `dpl_...` ID. With an explicit permissions block in place, GITHUB_TOKEN now needs `statuses: read` or the action 403s when resolving the deployment ID. Reported by Copilot review on #1882. * ci(docs): log status code and body when waitForServer times out Helps diagnose deployment-protection / OIDC-trusted-source bypass failures (e.g. SSO redirects) on the workflow-docs preview. * ci(docs): log OIDC token claims (aud, repository, etc.) for diagnostics Helps determine whether the bypass is failing because of missing trusted-source config, claim mismatch, or audience mismatch. * ci(docs): add curl debug step to verify OIDC header reaches Vercel * . * ci: remove debug logging now that trusted-sources config is correct The fetch-failure root cause was the trusted-sources rule format: the labs workbench projects had been PATCHed with just `to.slugs` (no `preset`), but Vercel's edge requires the dashboard-form-style `to.preset: 'all-custom'` field plus `development` in the slug list to match incoming requests. After re-PATCHing all projects with the correct format, the bypass works end-to-end. * ci(docs): debug — test trusted-sources bypass against docs and labs deployments Trying repository_owner claim added to one labs project to see if that fixes the bypass. * ci(docs): revert curl debug step The GitHub Actions OIDC trusted-sources bypass returns 401 on all tested projects regardless of claim configuration (including workflow-docs which was set up via the dashboard). This is not a per-project config issue. Need to investigate with Vercel team before continuing. * ci(docs): probe trusted-sources bypass and surface x-vercel-id Adds a debug step that does two HEAD requests against the docs preview deployment (with and without the OIDC trusted-sources header) and prints the response status line plus `x-vercel-id` for each. The proxy-side trusted-sources changes for GitHub Actions OIDC tokens are rolling out gradually (~12+ hours), so the edge-node identifier in `x-vercel-id` helps explain why a request might succeed or fail during the rollout window. Also includes `x-vercel-id` in the `waitForServer` timeout error so post-mortem analysis of failing runs has the same edge-node info. * ci(docs): drop trusted-sources curl probe — bypass works once proxy fix reaches the serving edge node The probe served its purpose: confirmed the bypass is functional once the request lands on a region that has the proxy-side trusted-sources fix rolled out. The waitForServer error message still surfaces x-vercel-id for any future rollout-window debugging. * . * world-vercel: log outbound OIDC token claims once per process Adds a one-shot diagnostic that prints the non-sensitive claims of the OIDC token (`iss`, `aud`, `owner_id`, `project_id`, `environment`, `sub`, `scope`, `exp`) on the first request that uses bearer auth. This is invaluable for debugging Vercel deployment-protection trusted-source rule mismatches: a 401 from the edge tells you nothing about why the rule didn't match, and the token's claims are the only thing that determines that. The signature is never logged. Gated to once per process — Vercel-issued tokens are process-stable for the lambda's lifetime so further log lines would just be redundant spam. * world-vercel: route trusted-sources header through getVercelOidcToken() The Authorization bearer correctly preferred config.token (a static Vercel auth token from CLI / Actions runner) and fell back to getVercelOidcToken() inside a Vercel function. But the trusted-sources bypass header (x-vercel-trusted-oidc-idp-token) was being read directly from process.env.VERCEL_OIDC_TOKEN inside getHeaders(). That env var is the bake-time token, frozen at deployment-creation time — on a project that has been redeployed after a settings change, it carries stale claims (e.g. an iss from when the project was briefly in 'global' mode) that no longer match the workflow-server's trusted-sources rule. Move trusted-sources header attachment from getHeaders() (sync) to getHttpConfig() (async) and source it from getVercelOidcToken(). That function reads getContext().headers['x-vercel-oidc-token'] first — a freshly minted per-request token that always reflects current project settings — and only falls back to the env var when that header is missing. Bearer auth source remains config.token-first. Also expand the diagnostic to log claims from BOTH the per-request OIDC token AND the bake-time env var so the divergence is visible in logs when debugging future trusted-source mismatches. Removes the now-misleading getProtectionBypassHeader() helper (its 'read env var directly' semantics were exactly the bug). * world-vercel: skip OIDC trusted-sources header on proxied path The two outbound flows have different auth requirements: 1. Proxied (usingProxy=true) — calls api.vercel.com/v1/workflow. Public endpoint, authenticated with a static Vercel auth token via config.token. The api-workflow proxy mints its own OIDC token before forwarding to workflow-server, so the trusted-sources bypass header on the SDK→proxy hop is meaningless. CLI, GitHub Actions, and other API-client callers take this path. 2. Direct (usingProxy=false) — runs inside a Vercel deployment talking straight to workflow-server. workflow-server validates a Vercel OIDC bearer; Vercel's edge validates the trusted-sources header. Both must come from getVercelOidcToken() (the per-request fresh token), not process.env.VERCEL_OIDC_TOKEN (the bake-time token that can be stale after a project config change). Previously getHttpConfig attached x-vercel-trusted-oidc-idp-token on both paths whenever getVercelOidcToken() resolved. That accidentally forwarded the GitHub Actions OIDC token (when wired into VERCEL_OIDC_TOKEN by the test runner) onto every SDK→proxy request, which is harmless but wrong-by-design — the proxy is public, doesn't look at that header on its inbound side, and the GHA token isn't its intended audience. Bearer auth source rules: - Proxied: only config.token. (No fallback to OIDC; that auth pathway doesn't go through the proxy's auth checks.) - Direct: config.token (for tests / local dev), falling back to getVercelOidcToken() (for Vercel-runtime calls). * world-vercel: throw if proxied path is hit without a Vercel auth token The api-workflow proxy authenticates the caller with a regular Vercel auth token (not OIDC), so reaching the proxied path with no config.token is always wrong: the proxy will reject the request and the SDK caller would see an opaque 401 with no actionable hint. Throw at config-resolution time with a clear message that points to the WORKFLOW_VERCEL_AUTH_TOKEN env var the SDK reads from. Adds tests covering both the no-token-throws case and the with-token-attaches- bearer-and-skips-trusted-sources case. * test(e2e): include x-vercel-id in startWorkflowViaHttp error message When the trusted-sources bypass returns 401, the error message now surfaces the response's x-vercel-id header so we can identify which edge node served the failure. Helps distinguish proxy-rollout incompleteness from actual config errors during incremental rollouts of edge-side changes. * ci: mint GHA OIDC tokens on demand to survive 5-minute expiry GitHub Actions OIDC tokens have a hard 5-minute lifetime that cannot be extended (no API to ask for a longer TTL — exp is always iat + ~300s). Pre-minting once at the start of the job and shipping the result down to the test runner via env var means tests that run late in the suite hit an expired token and 401 on /api/trigger-pages (and any other trusted-sources protected endpoint). Move minting into scripts/trusted-sources-headers.mjs: - getTrustedSourcesHeaders() is now async. - It calls the runner's ACTIONS_ID_TOKEN_REQUEST_URL endpoint directly (the env vars GHA exposes when permissions: id-token: write is on) and re-mints 60s before the cached token's exp. - Falls back to process.env.VERCEL_OIDC_TOKEN for non-GHA contexts (Vercel runtime, local dev). Workflow files drop the now-redundant 'Mint OIDC token' step and the VERCEL_OIDC_TOKEN env-var passthrough on the test step. The runner env vars propagate to subsequent steps automatically. Updates all 17 callers in e2e.test.ts / bench.bench.ts / utils.ts / docs/scripts/check-docs-smoke.mjs to await the now-async call. * address PR #1882 code review - Drop `statuses: read` from the three workflow permission blocks (the wait-for-vercel-project action works without it on a public repo). - Revert the `x-vercel-id` debug logging in `startWorkflowViaHttp`. - Delete `packages/world-vercel/src/jwt-claims.ts` (debug-only helper). - Drop the JWT claims diagnostic logging from `getHttpConfig`. - Tighten the auth-flow comment in `getHttpConfig` and remove the historical 'no longer attaches' note from `getHeaders`/its test. - Restore `.changeset/world-vercel-protection-bypass.md` (already shipped in a beta release per .changeset/pre.json). - Trim the `.changeset/world-vercel-trusted-sources.md` description to one short paragraph. * docs(AGENTS): document local VERCEL_OIDC_TOKEN via vercel env pull Configured trustedSources.projects on all 11 workbench app projects so each one accepts a Vercel-issued OIDC token from any of the others. A developer running e2e locally can now do `vercel env pull` from any workbench app's directory and use the resulting VERCEL_OIDC_TOKEN to bypass Deployment Protection on any of the workbench preview/prod deployments — no need to disable protection on the project just to run the suite locally. |
||
|
|
d5517a1814 | docs: note WORKFLOW_PUBLIC_MANIFEST=1 requirement for local e2e dev server (#1890) | ||
|
|
fe382021b9 |
docs: document full Vercel E2E env vars in AGENTS.md (#1819)
* docs: update AGENTS.md with complete Vercel E2E env vars * docs: remove WORKFLOW_PUBLIC_MANIFEST from local E2E instructions |
||
|
|
59ec3983b9 |
docs: tighten changeset description guidance in AGENTS.md (#1833)
* docs: tighten changeset description guidance in AGENTS.md Specify that changeset descriptions should be one sentence (two at most), and remove the redundant BREAKING CHANGE marker guidance since breaking changes are already communicated via the major semver bump. * docs: address Copilot review feedback - Align command reference to `pnpm changeset add` (matching line 188) - Drop the "see existing changesets for examples" parenthetical since existing changesets predate the new sentence-limit guidance |
||
|
|
5889d84aef |
ci: auto-resolve skills/ conflicts in backport to stable (#1798)
* ci: auto-resolve skills/ conflicts in backport to stable The skills/ directory is not maintained on the stable branch (skill files are unrelated to npm packaging). Extend the backport workflow's auto-resolution — and the AI-assisted fallback prompt — to treat skills/ conflicts the same way docs app conflicts are handled: keep the stable side and drop the incoming change from main. Also updates AGENTS.md to document which directories are stable-only placeholders and how the backport action handles them. * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Nathan Rajlich <n@n8.io> --------- Signed-off-by: Nathan Rajlich <n@n8.io> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
5e0a0c7ab0 |
Prefer stable version for docs app conflicts in backport workflow (#1791)
* Prefer stable version for docs app conflicts in backport workflow After #1786 restored a minimal Next.js placeholder docs app on stable, docs app conflicts should resolve to the stable branch version rather than being deleted. Only docs/content/ is actively maintained on stable, so conflicts there should still be resolved normally. Update both the auto-resolution logic in backport.yml and the AI prompt to reflect the new policy, and update AGENTS.md to match. * Use git show :2:$file to detect ours-side presence in conflicts git ls-files --error-unmatch succeeds for unmerged paths even when the file only exists on the incoming (theirs) side, which would then fail on git checkout --ours. Use git show :2:$file to specifically check for a stage-2 entry, which indicates the file exists on the ours (stable) side. |
||
|
|
b5a723932b |
Improve backport workflow: auto-resolve docs and lockfile conflicts, add DCO signoff (#1770)
* Auto-resolve docs/ and pnpm-lock.yaml conflicts in backport workflow The docs/ directory is not maintained on the stable branch. When cherry-picking from main to stable, any conflicts in docs/ files are now auto-resolved by deleting them. Lockfile conflicts are resolved by re-running pnpm install. If these resolve all conflicts, the cherry-pick pushes directly to stable without needing AI resolution or a separate PR. * Add --signoff to cherry-pick to pass DCO check * Preserve docs/content/ in backport conflict resolution The docs/content/ directory is kept on stable because the markdown files are bundled into npm packages via prepack scripts. Update the conflict auto-resolution to only delete docs app files (outside of docs/content/), and update AGENTS.md accordingly. * Address review: setup pnpm before cherry-pick, fix grep pipefail, guard lockfile resolution - Move pnpm/node setup before the cherry-pick step so pnpm install is available during conflict resolution - Add || true to the docs grep pipeline to prevent pipefail exit when there are no non-content docs conflicts - Only run pnpm install for lockfile conflicts when no other conflicts remain, to avoid choking on conflict markers * Let pnpm resolve lockfile conflicts natively * Remove redundant Setup Node.js step for opencode path Node.js is now set up unconditionally at the start of the job for the cherry-pick step's pnpm install, so the conditional setup for the opencode path is redundant. |
||
|
|
11b85d0783 |
Add AI-powered conflict resolution to backport workflow (#1693)
* Add AI-powered conflict resolution to backport workflow Signed-off-by: Nathan Rajlich <n@n8.io> * Use anthropic/claude-opus-4.6 model identifier Signed-off-by: Nathan Rajlich <n@n8.io> * Address review feedback on AI conflict resolution Signed-off-by: Nathan Rajlich <n@n8.io> * Update .github/workflows/backport.yml Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> Signed-off-by: Nathan Rajlich <n@n8.io> * Fix script injection in gh pr create --title Signed-off-by: Nathan Rajlich <n@n8.io> --------- Signed-off-by: Nathan Rajlich <n@n8.io> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> |
||
|
|
1b997ae5fa |
Add dual-branch versioning strategy docs and backport automation (#1660)
* Add dual-branch versioning strategy docs and backport automation Signed-off-by: Nathan Rajlich <n@n8.io> * Add concurrency group to backport workflow Signed-off-by: Nathan Rajlich <n@n8.io> --------- Signed-off-by: Nathan Rajlich <n@n8.io> |
||
|
|
cdf90d5a38 |
Rename Workflow DevKit to Workflow SDK, remove beta badge, add tweet wall (#1541)
* Rename Workflow DevKit to Workflow SDK, remove beta badge, add tweet wall - Rename "Workflow DevKit" to "Workflow SDK" across all files (~108 files) - Rename standalone "WDK" references to "Workflow SDK" - Remove beta badge from homepage hero - Add tweet wall component to homepage with 4 builder testimonials Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Rename Workflow DevKit to Workflow SDK, remove beta badge, add tweet wall - Rename "Workflow DevKit" to "Workflow SDK" across all files (~108 files) - Rename standalone "WDK" references to "Workflow SDK" - Remove beta badge from homepage hero - Add tweet wall component to homepage with 4 builder testimonials Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Harpreet Arora <harpreet.txt@gmail.com> * Address review: fix missed trigger phrase renames and bump skill versions - Rename "workflow devkit" to "workflow sdk" in trigger phrases for both skill files - Bump workflow-init SKILL.md version to 1.1 - Bump workflow SKILL.md version to 1.5 - Note: CLAUDE.md is a symlink to AGENTS.md, already renamed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Harpreet Arora <harpreet.txt@gmail.com> * link correct tweet --------- Signed-off-by: Harpreet Arora <harpreet.txt@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Karthik Kalyanaraman <karthik.kalyanaraman@vercel.com> |
||
|
|
823f58e5c6 |
Revert "Add support for calling start() inside workflow functions (#1133)" (#1475)
This reverts commit
|
||
|
|
e889860984 |
Add support for calling start() inside workflow functions (#1133)
* Add support for calling `start()` directly inside workflow functions Enable `start()` to work in workflow context by routing through an internal step (`__workflow_start`), reusing existing step infrastructure with no new event types or server changes needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Address PR review feedback - Use typeof check instead of truthiness for WORKFLOW_START symbol - Validate start() options in workflow context (reject unsupported options like world) - Set maxRetries=0 on __workflow_start step to prevent orphaned child runs - Add unit tests for createStart factory (6 tests) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Make Run serializable in workflow context with step-backed methods - Add Run serialization via __serializable marker + custom Run reducer/reviver in the serialization module (avoids SWC plugin injecting class-serialization imports) - Create WorkflowRun class factory (packages/core/src/workflow/run.ts) with step-backed methods: cancel(), status, returnValue, workflowName, createdAt, startedAt, completedAt, exists - Register 8 built-in steps (__run_cancel, __run_status, etc.) in step-handler - Update __workflow_start to return full Run object (serialized → WorkflowRun in VM) - Update createStart to pass through step result directly - Update docs to reflect full Run support in workflow context Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix start() in workflow VM by delegating from api-workflow stub The workflow VM loads api-workflow.ts (via the "workflow" export condition) which stubs all runtime functions. The start stub needs to check for the injected WORKFLOW_START symbol and delegate to it, otherwise start() throws "doesn't allow this runtime usage" in the workflow context. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address PR review: fix stale WORKFLOW_SERIALIZE comments and register Run in host registry - Update comments in step-handler.ts and start.ts to reference the actual serialization mechanism (Run reducer with __serializable marker) instead of the stale WORKFLOW_SERIALIZE reference - Register Run class in the host's class registry from step-handler.ts so the Run reviver can deserialize Run/WorkflowRun instances in step context Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add docs for recursive/repeating workflows and deploymentId: "latest" - Document using start() for self-chaining workflows to avoid large event logs - Add examples for batch processing and cron-like repeating patterns - Document deploymentId: "latest" option with type safety warning - Update skill file with same patterns Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Return full Run object from startFromWorkflow e2e workflow Update the e2e workflow to return the childRun object directly instead of just childRun.runId, exercising Run serialization across the workflow boundary. Update e2e test assertions to match. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Add recursive fibonacci e2e test for start() in workflow Demonstrates recursive workflow composition: fibonacciWorkflow starts new instances of itself via start() + Promise.all to compute fib(6)=8, fanning out across independent workflow runs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Move Run method steps to builtins with "use step" directives Refactor: instead of manually registering Run method steps via registerStepFunction in step-handler.ts, define them as proper "use step" functions in builtins.ts with __builtin_ prefix. This leverages the existing SWC plugin infrastructure — functions starting with "__builtin" get stable bare-name step IDs. - Add __builtin_run_{cancel,status,return_value,...} to both builtins files - Use dynamic import() for getRun inside step bodies to avoid pulling Node.js modules into the workflow bundle - Remove manual registerStepFunction calls from step-handler.ts - Update WorkflowRun step references to __builtin_run_* names - Fix step name display in web observability: fall back to raw name instead of "?" for built-in steps that don't follow step//module//fn format - Add fibonacciWorkflow default args for nextjs-turbopack workbench UI Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Render Run objects as clickable links in web observability UI - Add RunRef type and Run reviver to observabilityRevivers so serialized Run objects are hydrated as RunRef instead of showing raw Uint8Array - Add RunRefInline component (purple badge with run ID) that navigates to the target run on click, matching the StreamRef pattern - Thread onRunClick callback through the component chain: WorkflowTraceViewer → EntityDetailPanel → AttributePanel → DataInspector - Wire up navigation in the web app's run-detail-view - Add startFromWorkflow default args for workbench UI Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Throw error instead of silent fallback when Run class not in registry Address PR review: the Run reviver now throws if the class isn't found in the registry, instead of silently returning a plain { runId } object that would break the assumption of getting a valid Run instance. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix e2e failures: allow retries on Run getter steps, fix docs code samples - Remove maxRetries=0 from read-only Run getter steps (status, returnValue, workflowName, etc.) — these are safe to retry and need retries when the child workflow hasn't completed within the step timeout. Only cancel keeps maxRetries=0. - Fix docs code samples: use correct import path (workflow/api not workflow), add declare statements for helper functions used in examples. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Use standard step//module//function naming for built-in steps Update the SWC plugin's __builtin_ special case to generate proper step//@workflow/core//{name} IDs instead of bare function names. This makes parseStepName work correctly for built-in steps, showing: - StepName: "Run#returnValue" (not "__builtin_run_return_value") - ModuleSpecifier: "@workflow/core" (not the raw function name) Convention: __builtin_Run_cancel → step//@workflow/core//Run#cancel (uppercase prefix + underscore → instance method # notation) - Move __workflow_start to builtins.ts as __builtin_start - Rename __builtin_run_* to __builtin_Run_* for proper # notation - Update WorkflowRun step refs to use full step// IDs - Remove manual registerStepFunction from step-handler.ts - Update SWC spec.md with new naming examples Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Remove SWC __builtin special case, use standard step naming for builtins Remove the SWC plugin's __builtin_ special case so built-in steps get standard step//{module}@{version}//{fn} IDs like any other step. This makes parseStepName work correctly, showing proper StepName and ModuleSpecifier in observability. The VM reconstructs the same IDs via builtinStepId() which uses the @workflow/core version to build: step//workflow/internal/builtins@{v}//{fn} - Remove __builtin special case from SWC plugin (revert to original) - Add builtinStepId() helper shared by workflow.ts, start.ts, run.ts - Rename Run steps: __builtin_Run_cancel → Run_cancel, etc. - Rename start step: __builtin_start → start - Move start step from manual registerStepFunction to builtins.ts - Keep __builtin_response_* names unchanged (pre-existing) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Use static class methods for Run steps to get Run.method naming Refactor Run method steps from standalone functions (Run_cancel) to static methods on a Run class, so the SWC plugin generates step IDs with the standard static method convention: Run.cancel, Run.returnValue, Run.status, etc. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address PR review: tests, docs warnings, skill fix - Add TODO on Run.returnValue about polling blocking (replace with system hooks once AbortSignal/AbortController PR lands) - Add docs callout warning about returnValue holding workers alive - Fix SKILL.md contradiction that said start() can't be used in workflows - Enhance suspension test to assert step arguments are forwarded - Add WorkflowRun unit tests: serializable marker, runId, registry, delegation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix response builtins: adopt this-serialization from PR #1413 The rebase onto main didn't fully adopt PR #1413's refactor of response builtins to use `this` instead of explicit parameters. The old pattern (resJson(this) wrappers) passed `this` as an argument, but the step functions now expect `this` to be set via method call context. Switch to Object.defineProperties on Request/Response prototypes, matching main's approach. Also document WORKFLOW_PUBLIC_MANIFEST=1 for local e2e testing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Address docs review: returnValue polling is temporary, link to start() API ref - Update returnValue warning to note this is a temporary implementation that will be replaced with internal hooks - Replace inline deploymentId: "latest" docs with link to the existing start() API reference which already covers it comprehensively Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix e2e tests: replace collectedRunIds with trackRun API PR #1426 replaced the manual collectedRunIds array with a trackRun() helper. The start() wrapper already auto-tracks, so just remove the manual push calls and add trackRun for the child run. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Signed-off-by: Pranay Prakash <pranay.gp@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
5040263bf9 |
Merge CLAUDE.md into AGENTS.md and symlink CLAUDE.md (#1326)
* Merge CLAUDE.md into AGENTS.md and symlink CLAUDE.md * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Nathan Rajlich <n@n8.io> --------- Signed-off-by: Nathan Rajlich <n@n8.io> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> |
||
|
|
289fc46a1c |
Add back sitemap code and add docs unit test (#1136)
* Bring back sitemap * Bring back sitemap * Add pre commit hooks for sitemap * Add pre commit hooks for sitemap * Fix failing queue test * Revert queue test failure * Add unit tests |
||
|
|
90ca1eff27 |
Remove "beads" config (#952)
* Remove "beads" config * Remove .beads |
||
|
|
4c01dd3d02 |
Update SWC plugin spec.md with latest state of compiler (#815)
|
||
|
|
b0773aa67c |
Don't push to main, bots
|
||
|
|
5e8c6209d0 |
Add installation instructions for "beads" to AGENTS.md (#742)
|
||
|
|
797b68748b | setup beads |