Skip to content

Releases: Confidee/flowreel

flowreel 0.6.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 18:12
edf485e

Install: npm install --save-dev @confidee/flowreel@0.6.0 (npm, published by the release workflow with a provenance attestation).

Narration is now off unless you turn it on. flowreel's built-in voices are
the macOS system voices, which Apple licenses for personal, non-commercial
use only, so no video is narrated with one by default, and a run that uses
one says so. The demo video is re-voiced with Kokoro (Apache-2.0). Also:
the plugin is ready for Anthropic's plugin directory, and the README records
the Agent Skill's run in Claude Code without the plugin.

Added

  • The plugin has an icon (plugin/.claude-plugin/icon.png, the brand
    avatar at 1024x1024) and the documentationUrl and supportUrl that
    Anthropic's plugin directory shows. Its README says where it works:
    everything in Claude Code; in claude.ai chat it can explain and plan, but
    not run anything.
  • MACOS_VOICE_NOTICE from @confidee/flowreel/voice: Apple's terms for
    its system voices, which every narration line names when a macOS voice
    spoke.

Changed

  • BREAKING: narration is off unless you turn it on, for every run
    (--narration on or FLOWREEL_NARRATION=on). Before, a tour at demo
    pace was narrated by default. flowreel's only built-in voices are the
    macOS system voices, and Apple licenses them for personal, non-commercial
    use only (macOS licence, section 2F): a work, client or public video is
    outside that licence, so no video is narrated with one unless someone
    chooses to. A run narrated with a macOS voice now says so in its log and
    in summary.md. The docs explain the terms and the alternatives
    ("Voices and licensing" in docs/narration-and-videos.md); the doctor's
    check, the narrate and run skills and the example say the same.
  • The demo video (assets/demo/flowreel-demo.mp4, linked from the README
    and the npm page) is re-voiced with Kokoro (Apache-2.0): the same lines
    at the same moments, the picture unchanged. Its first version used the
    macOS voice Ava. The README now shows the demo's thumbnail and links to
    the file.

flowreel 0.5.0

Choose a tag to compare

@github-actions github-actions released this 23 Oct 13:48
00e77c3

Install: npm install --save-dev @confidee/flowreel@0.5.0 (npm, published by the release workflow with a provenance attestation).

flowreel is now also a standard Agent Skill: one folder, skills/flowreel/,
that Cursor, GitHub Copilot in VS Code, Claude Code and other agents that
read the Agent Skills format can load. The Claude Code plugin and the npm
package work as before; the README's "Use with any Agent Skills agent" says
how to install the skill.

Added

  • skills/flowreel/: flowreel as a standard
    Agent Skill, for Cursor, GitHub Copilot in
    VS Code and any other agent that reads the format, besides Claude Code.
    It is one SKILL.md, written to the specification (only its six
    frontmatter fields; passes its reference validator at commit 69ef37e),
    that routes to the plugin's workflows. Its references/ and scripts/
    are generated from plugin/ by npm run sync:agent-skill, and a
    runtime test fails when they are stale or SKILL.md breaks the
    specification (a strict subset of YAML, so it never passes what the
    reference validator rejects). What the plugin's frontmatter enforced and
    the specification cannot express (workflows that start only when asked,
    read-only agents) is stated as rules in the skill and in each generated
    file. The plugin and its /flowreel:* commands are unchanged, and
    nothing changes in the npm package. The README's "Use with any Agent
    Skills agent" says where each agent looks for it.

flowreel 0.4.1

Choose a tag to compare

@github-actions github-actions released this 23 Oct 10:31
1aaf7fd

Install: npm install --save-dev @confidee/flowreel@0.4.1 (npm, published by the release workflow with a provenance attestation).

A fix for the Claude Code plugin only: its prerequisite check failed with a
syntax error in 0.4.0. The npm package's code is unchanged from 0.4.0; its
version moves with the plugin's, which is what makes plugin users get the
fix. Update the plugin with /plugin marketplace update flowreel.

Fixed

  • The plugin's prerequisite check (plugin/scripts/check-prereqs.sh) ran
    into a syntax error in 0.4.0 and exited with 2 (#29): the session-start
    hook showed a bash error in every session of a flowreel project, and
    /flowreel:doctor lost its summary line. An apostrophe inside a
    single-quoted string, in the advice line added in 0.4.0, ended the
    string early. A test now parses every plugin shell script and runs the
    check in both modes, under the shell on PATH and macOS's bash 3.2.
    The npm package was not affected.

flowreel 0.4.0

Choose a tag to compare

@github-actions github-actions released this 22 Oct 08:02
9e14834

Install: npm install --save-dev @confidee/flowreel@0.4.0 (npm, published by the release workflow with a provenance attestation).

Every request flowreel makes is bounded, and a failure says what it
means. The Microsoft 365 driver never follows a redirect and says whether
a failed send may have gone out; a mail wait rides out throttling and
brief network drops; the sign-in, session and persona requests have a time
limit; and the shared summary no longer carries Playwright's call log,
which could hold a live session cookie. Two security fixes: upgrade if
you use the Microsoft 365 driver or share summary.md.

Security

  • GraphMailDriver no longer follows redirects (#22). Affects 0.3.0
    and earlier. The driver's requests used fetch's default
    redirect: "follow", and the fetch standard keeps the body on a 307 or
    308: a 307 on sendMail sent the mail a second time (and reported the
    send as successful), a redirect loop sent it up to 21 times, and a 307
    on the token request re-sent the form body, client_secret included,
    to the redirect target. Every Graph and token request now uses
    redirect: "manual": a 3xx is a GraphHttpError that sent nothing
    (mayHaveSent: false), never followed and never retried. A project
    that passes its own fetch must make one attempt per call and never
    follow redirects.
  • summary.md, summary.json and summary.lines no longer carry
    Playwright's call log (#26).
    Affects 0.3.0 and earlier. The summary
    reporter copied up to 4000 characters of every error, and a failed
    Playwright request's error goes on, after its first line, with a
    "Call log" that names the full URL with its query string, every
    request header (the persona's session cookie, a CSRF token) and a
    response's set-cookie (on a stalled sign-in, the fresh session
    cookie): the file flowreel tells you to share could carry a live
    session. The summary now keeps an error up to its call log and drops
    every http(s):// URL's query string and fragment; the HTML report
    (where a toHaveURL failure that differs only in its query still shows
    the difference) and traces keep
    the whole error and stay credential-bearing. flowreel's own sign-in
    seam and session probes rethrow the first line of Playwright's error
    only, without a cause, and so do the template and example adapters. If
    you shared a summary.md from a run that failed on a request, check it
    for a Call log: block and revoke the sessions it names (a completed
    teardown already revoked them).

Added

  • requestTimeoutMs for GraphMailDriver (@confidee/flowreel/mail-graph):
    every Graph and token request, from the connection to the last byte of
    the body, gets at most this long (default 30 s), and inside waitFor no
    more than the wait has left. A whole number of milliseconds from 1 to
    2147483647; anything else is a ConfigError.

  • GraphRequestTimeoutError from @confidee/flowreel/mail-graph
    (timeoutMs, plus operation, mayHaveSent and clientRequestId from
    GraphRequestError): what a request that got no answer throws. A
    sendMail or a reply's send sets mayHaveSent, says the mail may have
    been sent and names its client-request-id; it is never retried.

  • GraphRequestError from @confidee/flowreel/mail-graph: the base of
    every error a Graph or token request ends in (operation,
    mayHaveSent, always a boolean, and clientRequestId), with a
    one-line message. A bad 2xx answer (a body that is not JSON, a token
    answer without access_token) throws it as is, with mayHaveSent
    false. GraphHttpError, GraphRequestTimeoutError and the new
    GraphTransportError extend it (#17).

  • GraphTransportError from @confidee/flowreel/mail-graph (code, such
    as ECONNRESET or UND_ERR_SOCKET; no cause): what a failure below
    HTTP throws, instead of a plain Error. The message is unchanged:
    Graph <operation> failed: fetch failed (ECONNREFUSED) (#17).

  • GraphHttpError takes an optional fifth argument, a details object
    (mayHaveSent, clientRequestId, requestId, date, traceId,
    correlationId, code), and exposes those fields; its four positional
    arguments are unchanged (#17, #19).

  • Request ids for GraphMailDriver: every Graph and token request carries
    a fresh random client-request-id, and the token request sends
    return-client-request-id: true. Every error keeps it; a
    GraphHttpError also keeps Graph's request-id and date, and a token
    error Entra's trace_id and correlation_id, when GUID-shaped. A token
    error's message always names its trace_id and correlation_id on the
    detail line; a Graph request's message names its ids only when the mail
    may have been sent (For Microsoft support: client-request-id …) (#19).

  • requestTimeoutMs for both seam HTTP clients
    (@confidee/flowreel/rails-inertia), 30 s by default:
    seamHttpFromRequest(request, { requestTimeoutMs }) passes it as
    Playwright's per-call timeout (inside @playwright/test a request
    context otherwise has none), and seamHttpFromFetch(baseURL, options)
    now also takes { fetch, requestTimeoutMs, setTimeout, clearTimeout }
    besides the fetch function it took before. A seam request that runs
    out is aborted and throws
    Seam <METHOD> <path> got no answer within 30 s; raise requestTimeoutMs if a job drain legitimately takes longer
    (#20).

  • requestTimeoutMs for flowreel's session requests (#24), 30 s by
    default, validated like every flowreel request bound (a whole number of
    milliseconds from 1 to 2147483647, else a ConfigError naming the
    option): on seamSignIn's options (@confidee/flowreel/rails-inertia),
    on SessionProtocol (isSessionSignedOut; revokeSession, which never
    throws, returns revoked: false naming the option, so teardown warns
    loudly), and on
    createPersonaApis and tourFixtures() for every persona request. It
    is the timeout of each request context they open.

  • requestFailure(error) from @confidee/flowreel/core: what may be
    said of a failed Playwright request, the first line of its message
    without a URL's query string, at most 300 characters. For a project's
    own adapter (#26).

  • /flowreel:doctor advises when e2e/flowreel/adapter.ts opens request
    contexts without a timeout (an adapter scaffolded before 0.4.0). It
    only reads the file, with grep.

Changed

  • GraphMailDriver.waitFor: a temporary network failure on a mail read
    or the token request is now re-polled instead of ending the wait (#23):
    ECONNRESET, UND_ERR_SOCKET, EPIPE, ECONNABORTED, ETIMEDOUT,
    EAI_AGAIN and undici's connect, headers and body timeouts (an
    AggregateError only when every inner code is listed), with the
    token's back-off (5 s, then 10 s, 20 s … up to 60 s, never past the
    wait's end, on top of the wait's own poll interval), counted apart for the token request and the reads. Only
    once that endpoint has answered the driver: at first contact the same
    error still ends the wait, so a firewall or broken DNS fails fast. Any
    other code, or none, stays fatal (ECONNREFUSED, ENOTFOUND, TLS, a
    custom fetch that throws a plain error), nothing that may have sent
    mail is ever re-polled, and nothing is retried outside waitFor. A
    wait that times out reports the step, the code and the count only
    (Last observed: Graph read failed (ECONNRESET), 3 in a row, no mailbox read completed in this wait, retrying).
  • GraphMailDriver.waitFor re-polls a 429, 503 or 504 only on a
    GET read; a write's never was reachable there, and now cannot be.
  • The persona request contexts (createPersonaApis, the tour's as()
    and personaApis) now have a 30 s timeout of their own, which
    overrides the project's actionTimeout for them (15 s under flowreel's
    createConfig); a request's own timeout still wins. Set
    requestTimeoutMs on tourFixtures() for a longer one.
  • Global teardown (signOutAll) now survives an AppAdapter.signOut
    that throws, against its contract: that persona gets the loud "could
    not sign out" warning (with the first line of the error) and the other
    personas are still signed out. Before, one throw skipped every later
    persona.
  • seamSignIn and isSessionSignedOut throw
    Test sign-in (POST <path>) failed: … and
    Session probe GET <path> failed: … with the first line of
    Playwright's error, instead of Playwright's error itself (#26).
  • The template adapter (/flowreel:init) and the example's set a
    REQUEST_TIMEOUT_MS (30 s) on every request context and on SESSION,
    describe a failed request with requestFailure(), and health()
    returns a failed request's first line instead of throwing; the
    template ships unit/adapter.spec.ts, which checks both. /flowreel:init
    never rewrites an existing adapter: copy these lines into one you
    scaffolded before (the doctor points it out).
  • GraphMailDriver: a failed sendMail or reply send now says whether
    the mail may have been sent from everything observed, not only a
    timeout. Any 5xx but 509 (503 included) and any transport failure that
    does not prove the request never left (a reset or closed socket,
    terminated, EPIPE, any code on a read or write, an unknown or
    missing code) set mayHaveSent; a 3xx, a 4xx (429 included), 509 and
    a DNS, connect or TLS failure (a getaddrinfo or connect syscall, or
    a listed code on an error without a syscall) do not. An error status
    whose body does not arrive within the bound stays a may-have-sent
    timeout. A 2xx status now resolves the send at once, even when its empty
    body then fails or never ends. Nothing is retried (#17).
  • GraphMailDriver.waitFor: a token request that is throttled or meets a
    server error (HTTP 429, 500, 502, 503, 504, or OAuth error
    temporarily_unavailable) is now re-polled instead of ending the wait,
    after ...
Read more

flowreel 0.3.0

Choose a tag to compare

@github-actions github-actions released this 20 Oct 08:03
4f74231

Install: npm install --save-dev @confidee/flowreel@0.3.0 (npm, published by the release workflow with a provenance attestation).

A stopped run keeps its evidence. CI stop signals, a pipeline that dies
and the new --deadline all stop the running stage the way Ctrl-C does,
so its video, trace, sign-out and report survive, and a stopped run is
never a pass. Also: the npm page's logo reads on dark themes.

Added

  • --deadline (or FLOWREEL_DEADLINE) for the pipeline: a duration from
    its start (25m, 90s, 1h, milliseconds) or a time (an ISO time with
    a zone, epoch milliseconds). At the deadline the running stage is
    stopped the way Ctrl-C stops it, no further stage starts
    (not run (deadline reached)) and no combined video is made (one being
    composed is stopped); exit 130, unless a FAIL (1) or an undo failure (4)
    outranks it. A deadline already past at the start runs nothing (no
    database copy, no stage). Stages get
    FLOWREEL_DEADLINE_AT and skip their own video when less than 60 s
    (FLOWREEL_COMPOSE_BUDGET_SEC) is left. No default. A bad value is a
    usage error (64). New exports: parseDeadline, deadlineAt,
    STOP_REASONS, ABORTED_REASON.
  • The stage guard, installStageGuard() from @confidee/flowreel/reporter,
    installed by the summary reporter first thing: SIGTERM (and Ctrl-Break
    on Windows) stops a run the way Ctrl-C does (or exits 130 before
    Playwright's runner listens); a stage whose pipeline is gone
    (FLOWREEL_PIPELINE_PID) stops itself within about a second; a hangup
    stops it gracefully when the pipeline runs in a terminal
    (FLOWREEL_HUP=graceful); output to a pipe whose reader is gone no
    longer crashes it. Only the first stop request becomes a Ctrl-C, so a
    later one never cuts the teardown short.
  • pipeline.json is written ahead, with a status: running from the
    start (stages pending, verdict INCOMPLETE, finishedAt null),
    rewritten as each stage starts and ends, stopping after the first stop
    request (with stoppedBy), finished at the end and aborted after a
    second Ctrl-C. Every write is atomic. Any status but finished means
    the pipeline did not finish; the explain skill and the run-explainer
    agent say so.

Changed

  • The npm page shows the logo on its own dark card
    (assets/brand/flowreel-mint-banner.svg), so it reads on light and dark
    pages alike; the dark-text logo was nearly invisible where the README is
    shown on a dark theme, such as Socket (#12).
  • BREAKING: a stage now runs Playwright's own command-line entry
    (@playwright/test/cli, resolved from the project) with the pipeline's
    Node, not npx; npx --no-install playwright is the fallback when the
    entry cannot be resolved, and the log says which. stageCommand()
    returns Playwright's arguments (test …) without the npx prefix, and
    processIo() adds the launcher: a custom PipelineIo.runChild must do
    the same. playwrightLauncher() and resolvePlaywrightCli() are new
    exports.
  • PipelineIo takes optional interruptChild, waitForChild,
    killChild, clock, schedule, pid and interactive, and its
    onInterrupt handler receives the signal. PipelineDocument has
    status and stoppedBy, and its finishedAt is null until the
    pipeline finished.
  • createConfig() sets handleSIGTERM: false in the browsers' launch
    options (a project's own launch options keep it unless they set it): a
    browser no longer closes itself when a CI signals the job's whole
    process group, so the running test's video is kept; the runner closes it
    in its graceful stop.
  • A stopped pipeline is never a pass: when a stop (a signal or the
    deadline) came and the stages that ran passed (a --local run, a stop
    during the combined video), the pipeline is INCOMPLETE with exit 130
    and a reason naming the stop.
  • In a terminal, a hangup (SIGHUP) is a stop request for the pipeline and
    the stage, and the pipeline ignores the closed terminal's output errors
    so it can still write pipeline.json. Without a terminal SIGHUP keeps
    its default.

Fixed

  • A CI job that is cancelled or runs out of time no longer loses the run
    (issue #11). The pipeline handles SIGINT, SIGTERM and, on Windows,
    Ctrl-Break: the first stop asks the running stage to stop as Ctrl-C
    does (on POSIX it sends the stage SIGINT, the one signal Playwright's
    runner stops gracefully on), so the browser closes and the test's video
    and trace are saved, the personas are signed out and the stage writes
    its summary; no further stage starts and no combined video is made. The
    same signal within 200 ms counts once; a SIGTERM after the first stop
    never forces (GitHub Actions sends SIGINT, then SIGTERM 7.5 s later);
    only a second Ctrl-C forces: the final pipeline files are written, the
    stage gets 3 s to close before it is killed, the database copy is
    dropped and the pipeline exits 130 (4 when a restore is still pending).
  • A stage whose pipeline was killed outright no longer runs on orphaned or
    crashes on its next log line: it stops gracefully within about a second.
  • A stop signal during video composition ends it at once (ffmpeg, the
    voice engine and the card renderer's browser are stopped) instead of
    killing the run mid-encode; the summary says
    video: not produced (video composition stopped (interrupted)). This
    holds for a stage's video (the reporter listens from the start of the
    run, so a signal that lands after Playwright's teardown, while the other
    reporters finish, no longer kills the stage before its summary; a second
    Ctrl-C a second later exits 130) and for the pipeline's combined video.
  • A run stopped during sign-in no longer leaves that session live: the
    global teardown waits (up to 60 s) for sign-ins still in flight before
    signing out. When the teardown was cut short, the summary reporter waits
    for its sign-out, or signs the personas out itself (after waiting up to
    20 s for pending restores) and says so loudly; the personas are never
    signed out twice.
  • Ctrl-Break on Windows stops a run gracefully instead of killing it, and
    on Windows the stage stops itself at the deadline (the pipeline cannot
    signal it there).
  • A stage no longer goes through npx, which cannot be spawned without a
    shell on Windows (EINVAL since Node 20.12). There is no npx fallback on
    Windows: a project without a resolvable @playwright/test gets a
    message saying to install it.

flowreel 0.2.1

Choose a tag to compare

@github-actions github-actions released this 16 Oct 21:08
41abc48

Install: npm install --save-dev @confidee/flowreel@0.2.1 (npm, published by the release workflow with a provenance attestation).

Documentation and release tooling only; the runtime's behaviour is
unchanged. The npm page now shows the logo, badges and the demo video's
thumbnail.

Added

  • The release workflow creates the GitHub Release after the npm publish:
    a third job (github-release, the only one that can write to the
    repository, and it never sees the npm token) titles it
    "flowreel " with an install line and the version's
    CHANGELOG.md section as its notes (scripts/release-notes.mjs, with
    unit tests). A release that already exists is left unchanged.
  • A 76-second narrated demo video at the top of the README, recorded with
    flowreel 0.2.0 from npm. The video, its thumbnail and the run's report
    are in assets/demo/; the leak tripwire allows the publisher's name in
    that demo's README and run report only.
  • The npm page (the runtime README) shows the demo's thumbnail, linked to
    the video on the project README (npm does not play videos); it appears
    on npm with the next release. Its logo is now the full mint logo (the
    symbol and the name, 320 px wide) instead of the small symbol alone.
  • Badges under the logo in the README and the npm page: npm version, CI,
    license, Node and Claude Code plugin.

Changed

  • CI can also be started by hand (Actions -> CI -> Run workflow).
  • README: install from npm (@confidee/flowreel is published); a clone
    is only for trying an unreleased change.
  • Docs: they now say the package is on npm (no "pre-release" or "until the
    runtime is on a registry"), and the example's setup offers the npm
    install first.
  • Docs: exit 130 and the INCOMPLETE verdict for an interrupted run are
    documented everywhere the exit codes are listed.
  • Docs: the tour scanner's TypeScript range is stated (5.x and 6.x;
    TypeScript 7 is not supported yet, issue #6), with a troubleshooting
    entry.
  • Docs: links in the plugin's templates and README work outside the
    repository; the changelog has version links.
  • Dependabot no longer proposes major versions of typescript (TypeScript
    7 has no JavaScript compiler API, which the tour scanner uses) or
    @types/node (the type definitions follow the supported Node versions,
    raised on purpose). Minor and patch updates still arrive.

flowreel 0.2.0

Choose a tag to compare

@fetijashari fetijashari released this 16 Oct 18:33

The first public release of flowreel: Playwright flows that are both your release gate and your narrated product videos.

You describe your app's features as plain-English plans; flowreel turns them into deterministic Playwright flows, runs them on a development target and then, only if they pass, on staging, and records each run as a branded, narrated video.

Install

The runtime, from npm:

npm install --save-dev @confidee/flowreel @playwright/test

The Claude Code plugin (it scaffolds, authors, runs and explains flows):

/plugin marketplace add Confidee/flowreel
/plugin install flowreel@flowreel

Start with the getting-started guide.

Highlights

  • A development -> staging gate with exit codes CI can rely on: 0 pass, 1 fail, 2 staging not configured, 3 nothing verified, 4 a shared change could not be undone (manual action needed), 130 interrupted.
  • Narrated, branded videos of every run, from the same flows that decide the verdict.
  • A write-ahead undo ledger: every change a flow makes to shared settings is recorded before it is made and restored afterwards; anything not restored is listed first, with instructions.
  • Adapters for Rails with Inertia (test seams that only answer from this machine, in development) and for Microsoft Graph mailboxes (send guards, redacted errors).
  • A Claude Code plugin that never installs anything without asking; skills with side effects run only when you invoke them.

Quality

  • 755 unit tests; coverage at 99.9% of lines and 98.6% of branches, with a 95% minimum enforced in CI and in the release build.
  • CI on Node 20, 22, 24 and 26.
  • Published from GitHub Actions through npm trusted publishing, with a provenance attestation. Check it with npm audit signatures.

Fixed since the internal 0.1.0

  • A Ctrl-C after development passed now ends as INCOMPLETE (exit 130), never PASS.
  • An undo ledger that cannot be read now fails closed (exit 4) instead of reading as nothing to restore.
  • The combined tour video is no longer lost when a summary holds a malformed feature entry.

Full list: CHANGELOG.md.

Security reports: please use private vulnerability reporting (see SECURITY.md).