Skip to content

Releases: gemstack-land/gemstack

@gemstack/framework@0.8.0

Choose a tag to compare

@github-actions github-actions released this 05 Jul 20:26
077ff47

Minor Changes

  • 385c953: feat(framework): hosted run relay — watch one run from multiple browsers (#230)

    The first slice toward shared team sessions: a run can now be watched live from more than one machine. framework relay hosts a relay; a run started with framework "..." --share <relay-url> publishes its event stream to it and prints a shareable URL. Anyone who opens that URL gets the same dashboard over SSE, replaying the run's full history and then following live — so two teammates watch one build together.

    Reuses the existing dashboard: the SSE serving is factored into a shared helper and the page's stream/stop paths are now relative so they resolve both on the localhost dashboard and under the relay's /r/<id>/. New exports: startRelay, relayPublisher. Deliberately unauthenticated — accounts, teams, RBAC, and authorized steering layer on later; the relay only projects the stream, it never runs an agent.

@gemstack/framework@0.7.0

Choose a tag to compare

@github-actions github-actions released this 05 Jul 19:30
7e8fdae

Minor Changes

  • cc6a8db: feat(framework): AI meta-select — auto-pick the Open Loop domain preset, modes, and build event kind from the prompt + workspace (#270)

    A live run with no --preset (and none in the-framework.yml) now infers the best-fit domain preset, its modes (technical / autopilot), and the build event kind from what you asked for and the project you are in, then runs under it. So framework "add a login page" in a web app picks Web Development on its own. --no-auto-preset opts out (plain framework flow); --fake stays deterministic. Any failed or empty pick falls back to the plain flow, so the auto-pick never blocks a run.

  • 5f319ff: feat(framework): show the active Open Loop modes as read-only checkboxes on the dashboard (#272)

    When a run builds under a domain preset, the dashboard now renders a Modes panel with the run's modes as checkboxes ([x] technical / [ ] autopilot), so the policy driving the build is visible beside the stack and loop panels. Backed by a new modes framework event (OPEN_LOOP_MODES is the canonical mode ordering, shared with the meta-select router); a run with no preset emits nothing and shows no panel. The event persists with the run, so --resume rehydrates the panel too.

  • 9f62be7: feat(framework): run the --serve verification in a Docker sandbox (#229)

    framework --serve ... --sandbox docker now boots the app inside a throwaway container instead of on the host: the source is copied in, deps install and the dev server runs in the container, and the health check hits a mapped port. So agent-authored code never installs or runs on your machine to be verified. --sandbox local (the default) is unchanged — it adopts the host cwd in place.

    This is the first slice of #229: only the serve verification is sandboxed; the build itself still runs on the host (the container is re-seeded with the latest source before each check). Requires a reachable Docker daemon — a run that asks for the sandbox without one fails fast with a clear message; --sandbox docker without --serve is a no-op note. runFramework gains sandbox and an injectable runner option.

Patch Changes

  • Updated dependencies [08f5710]
    • @gemstack/ai-autopilot@0.9.0

@gemstack/framework@0.6.0

Choose a tag to compare

@github-actions github-actions released this 05 Jul 17:59
0211b23

Minor Changes

  • 4a6311e: Domain preset runs can now pick a build event kind, so a preset's bug-fix loop actually fires. A run chooses it with runFramework({ buildEvent }) / the framework --kind <name> flag, and a preset can declare its own default via preset.md metadata.event (surfaced as DomainPreset.defaultEvent). Precedence: run choice > preset default > major-change; an event the preset has no loop for still falls back to the built-in checklist.

  • b81e563: Run a build under an Open Loop domain preset (#251).

    runFramework({ preset, modes }) now accepts a user-picked domain preset
    ({loops, prompts, skills}). Its skills (and their personas) frame every phase of
    the run alongside the detected framework skill, the selected domain and active
    modes are narrated, and its loops + prompts are materialized into a driver-backed
    LoopEngine exposed as result.loop (each pass is a fresh driver prompt). The
    new driverLoopPrompts bridge does the materialization. Opt-in and additive: a
    run with no preset is unchanged. Driving the exposed loop as a run phase is the
    follow-up (#252).

  • c28c373: the-framework.yml gains an event: key so a repo can pin its build event kind (e.g. bug-fix) alongside preset/autopilot/technical. Precedence: --kind flag > the-framework.yml event > preset default > major-change.

  • 74a9907: CLI: --preset <name> runs a build under an Open Loop domain preset, with
    --autopilot / --technical mode flags (#256).

    --preset resolves a shipped domain preset by name (via builtinDomainPresets +
    selectPreset) and hands it to runFramework, so its loops, prompts, and skills
    frame the build. --autopilot / --technical activate the preset's conditions
    variants (applied at load time and narrated). An unknown preset name is a usage
    error that lists the available presets; the mode flags note when given without a
    preset. Additive: a run with no --preset is unchanged.

  • 8c3e7d0: The domain loop drives the production-grade review phase (#252).

    When a run has a domain preset, its review loop now replaces the built-in
    checklist: each pass dispatches a major-change event through the preset's
    driver-backed loop, so its review chain (e.g. code review, test coverage, security
    review) fires through the wrapped agent, and Bootstrap's pass / improve / maxPasses
    machinery gates on the union of the { blockers } verdicts the chain reports. A
    preset with no loop for the build event falls back to the built-in checklist, so a
    run is never left unreviewed. New: domainLoopChecklist + verdictFromLoopRun
    (@gemstack/framework).

    The shipped Software Development preset's review prompts (code review, test
    coverage, security review) now end with a { blockers } verdict so the loop
    actually gates rather than only running.

  • c24ae22: Read the-framework.yml for per-repo Open Loop defaults (#258).

    A project can now carry its own domain preset + modes, so you do not retype the
    flags each run:

    preset: software-development
    autopilot: true

    The CLI reads it from the run's workspace and merges it with the flags: --preset
    wins over the file's preset; --autopilot / --technical OR with the file's
    booleans (a flag only ever enables a mode). A missing file is a no-op and a
    malformed one is a warning, never a failed run. New exports: loadFrameworkConfig,
    parseFrameworkConfig, mergeRunConfig, FRAMEWORK_CONFIG_FILES,
    FrameworkFileConfig.

  • edd242b: Repo files as persistent AI memory (#260).

    The agent now reads the project's special files (CODE-OVERVIEW.md,
    KNOWLEDGE-BASE.md, BRAINSTORMING.md, DECISIONS.md) at the start of a run and is
    told to keep the ones it owns current, so a project's memory lives in the repo as
    plain markdown and the next run picks up where the last left off. DECISIONS.md
    stays framework-owned (we write it from the decisions ledger), so the agent reads
    it but does not edit it. New: loadRepoMemory(cwd), memoryFraming,
    MEMORY_FILES, and a memory option on runFramework; the CLI reads the files
    from the workspace and frames them alongside personas and skills.

Patch Changes

@gemstack/ai-autopilot@0.9.0

Choose a tag to compare

@github-actions github-actions released this 05 Jul 19:30
7e8fdae

Minor Changes

  • 08f5710: feat(ai-autopilot): add Product Management and Biological Science domain presets (#275)

    Ships the last two of Rom's #204 domain list as built-in Open Loop presets, so the set is now five: Software Development, Web Development, Data Science, Product Management, and Biological Science.

    • Product Management reviews a substantial change against the requirement it serves, the experience it gives the user, and whether its success is measurable; a fix traces the user impact and root cause before it is locked in. Technical Control runs the leaner requirements review only.
    • Biological Science reviews an analysis or pipeline for sound experimental design, trustworthy data provenance, and statistical rigor; a fix traces the analytical cause before it is locked in. Technical Control runs the experimental-design review only.

    Both are pure .md content under presets/, auto-discovered by builtinDomainPresets(), so meta-select and --preset can route to them with no further wiring. Each ships a real stable skill reference (Shape Up; Ten Simple Rules for Reproducible Computational Research).

@gemstack/ai-autopilot@0.8.0

Choose a tag to compare

@github-actions github-actions released this 05 Jul 17:59
0211b23

Minor Changes

  • 4a6311e: Domain preset runs can now pick a build event kind, so a preset's bug-fix loop actually fires. A run chooses it with runFramework({ buildEvent }) / the framework --kind <name> flag, and a preset can declare its own default via preset.md metadata.event (surfaced as DomainPreset.defaultEvent). Precedence: run choice > preset default > major-change; an event the preset has no loop for still falls back to the built-in checklist.

  • 8c3e7d0: The domain loop drives the production-grade review phase (#252).

    When a run has a domain preset, its review loop now replaces the built-in
    checklist: each pass dispatches a major-change event through the preset's
    driver-backed loop, so its review chain (e.g. code review, test coverage, security
    review) fires through the wrapped agent, and Bootstrap's pass / improve / maxPasses
    machinery gates on the union of the { blockers } verdicts the chain reports. A
    preset with no loop for the build event falls back to the built-in checklist, so a
    run is never left unreviewed. New: domainLoopChecklist + verdictFromLoopRun
    (@gemstack/framework).

    The shipped Software Development preset's review prompts (code review, test
    coverage, security review) now end with a { blockers } verdict so the loop
    actually gates rather than only running.

  • 03e06aa: Add the Open Loop bundle unit: a domain preset = {loops, prompts, skills} (#242).

    This is the keystone that ties the three data types the framework already ships
    separately into one selectable, composable thing. Author one in code with
    defineDomainPreset, or load one from a directory of .md files (preset.md +
    loops/, prompts/, skills/) with loadDomainPreset. composeDomainPresets
    merges several into one (loops concatenate; prompts and skills merge by id/name,
    later wins), so presets-of-presets falls out; selectPreset picks the user's
    domain by name. Kept distinct from the framework Preset detector in presets/
    (skipped for the Open Loop MVP) by naming this DomainPreset.

  • 3c72f14: Add modes (Autopilot / Technical) to domain presets via conditions frontmatter (#244).

    A preset content file can now ship mode variants: a stem.<variant>.md sibling
    that declares metadata.conditions (a mode or list) overrides its stem.md base
    when those modes are active. loadDomainPreset(dir, { modes }) (and
    softwareDevelopmentPreset({ modes })) resolve the winner per stem — the most
    specific eligible variant, falling back to the base. The shipped Software
    Development preset gains a technical variant of its major-change loop as an
    illustration. This is the simple frontmatter fan-out; composing prompts from
    parameters is the follow-up (#245).

  • e45e4d0: Preset discovery API: enumerate domain presets so the CLI/UI picker can list and
    pick one by name (#254).

    builtinDomainPresets() loads every domain preset shipped under the package's
    presets/ directory (today just Software Development; new built-ins are picked up
    automatically). loadDomainPresetsFrom(dir) loads every immediate subdirectory
    that holds a preset.md, skipping the rest, sorted by name. Pair either with the
    existing selectPreset(list, name) to pick the user's chosen domain.

  • 396dc7f: Rename the loop engine's rules vocabulary to loops (Open Loop, #241).

    A loop is a meta prompt, so that is the user-facing unit even though rule logic powers it. defineLoop / defaultLoops / Loop / LoopSpec replace defineRule / defaultLoopRules / LoopRule / LoopRuleSpec; the engine class is now LoopEngine (was Loop), created via createLoopEngine with LoopEngineOptions; and its option key is loops (was rules). Vocabulary only, no behavior change.

  • 24944b9: Ship the "Software Development" domain preset (#243).

    The first built-in Open Loop preset, authored as a directory of .md files:
    two loops (major-change -> code-review + test-coverage + security-review; bug-fix
    -> root-cause + regression-test), five stack-agnostic prompt bodies, and one skill
    pointer. Non-web and user-picked (no dependency detection). Load it with
    softwareDevelopmentPreset(); builtinPresetsDir() points at the shipped
    presets/ directory. Proves the bundle unit end to end.

  • d2acba4: Add two more built-in domain presets: web-development and data-science.

    Each ships as a directory of .md files like software-development, so it is
    auto-discovered by builtinDomainPresets(), selectable via --preset <name> and
    the-framework.yml, and drives the review phase. Both carry a Technical Control
    variant (leaner major-change loop) and a bug-fix loop. Their major-change review
    prompts end with the { blockers } verdict footer so the review loop gates.

    • web-development — accessibility, performance budget, and web-security review; skill points at web.dev.
    • data-science — reproducibility, data validation, and methodology review; skill points at Google's Rules of ML.

@gemstack/framework@0.5.2

Choose a tag to compare

@github-actions github-actions released this 04 Jul 23:23
e31500c

Patch Changes

  • 1d3ce64: Fix the Claude Code driver treating a non-zero agent exit as success when the agent had already streamed some text. A crash mid-build now fails the turn (surfacing stderr or the partial text) instead of resolving as a result the loop can score production-grade.

  • 45b13b2: Default the CLI to bypassPermissions so the headless loop can build/verify

    Every framework turn is a headless claude -p invocation, which can't answer an
    interactive approval. The driver's library default (acceptEdits) auto-approves
    edits but not Bash, so installs/builds/tests were silently denied: the
    production-grade checklist tried npm run build / dev-boot, hit "Build needs
    interactive approval which isn't available," failed pass 1 as "could not be
    executed this session," and the loop ground on listing blockers it couldn't
    verify.

    The framework CLI now defaults its Claude Code driver to bypassPermissions so
    the full loop (install, build, test, dev-boot) runs unattended and the checklist
    verifies for real. This is a permissive default appropriate to a headless
    autonomous builder; --permission-mode <mode> still overrides it (e.g.
    --permission-mode acceptEdits for the old, conservative behavior), and
    --dangerously-skip-permissions still takes precedence. The ClaudeCodeDriver
    library default is unchanged (still acceptEdits); only the CLI opts up.

    Closes #225.

  • 1259282: Fail closed when a checklist reply omits the required { blockers } verdict. A verdict-less reply was scored as empty-blockers (production-grade) and stopped the loop; it now surfaces a blocker so the loop re-prompts instead of declaring the app done off an unverifiable reply.

@gemstack/framework@0.5.1

Choose a tag to compare

@github-actions github-actions released this 04 Jul 21:30
54d525d

Patch Changes

  • Updated dependencies [6f7e7e3]
    • @gemstack/ai-autopilot@0.7.0

@gemstack/framework@0.5.0

Choose a tag to compare

@github-actions github-actions released this 04 Jul 20:14
2f871f3

Minor Changes

  • 16f6bb8: Stop a run from the dashboard

    The dashboard now has a Stop button that interrupts the running build from the browser, instead of only from the terminal. It POSTs to a new /stop route that aborts the run's AbortSignal, which runFramework checks between phases and the driver honours mid-turn (it kills the current agent turn). The run ends cleanly as stopped (not failed): the CLI prints ■ Stopped and exits 0, the dashboard shows a stopped status, and the persisted run records status: "stopped" so --resume shows it that way.

    startDashboard gains an onStop option (wire it to controller.abort()); the page hides the button when no stop handler is wired (e.g. a read-only --resume view). The end event gained an optional stopped flag.

    Part of #110 (first interactive slice of #165's web client). Closes #218.

Patch Changes

  • c7eae83: Label the dashboard session link honestly

    Our runs are headless, which is deliberately not Remote-Controlled, so the default https://claude.ai/code link is a generic entry point, not a live per-run session. The dashboard now labels it Open Claude Code instead of "live session"; the "live session" label is kept only for a real user-supplied --session-link. The real session id (the local transcript id, usable with claude --resume) is still shown.

    The README's session section is rewritten to be accurate: to steer a session live in the browser you start your own interactive claude auth login + claude --remote-control --name <run> session and open it from claude.ai/code, which is a separate process from an orchestration run. Corrects the overpromise from #212. Closes #221.

@gemstack/framework@0.4.0

Choose a tag to compare

@github-actions github-actions released this 04 Jul 18:51
60ceb4a

Minor Changes

  • c3e7e9e: Thread an active extension's own skills into the agent frame

    The extension SPI (#190) let a FrameworkExtension carry skills (llms.txt doc pointers), but run.ts only framed the built-in SkillRegistry matches, so a discovered extension's own skills were collected and then dropped. Add composeSkills (symmetric with composePersonas): it unions the registry-matched skills with every active extension's skills, deduped by name. run.ts uses it, so an active extension now contributes both its personas and its doc pointers to the frame. Surfaced by the new examples/framework-discovery-demo end-to-end proof, where the third-party framework-hello extension's hello-guide skill now reaches the agent.

  • f156cf8: Default the live-run session link to claude.ai/code

    A live run now shows a session link to https://claude.ai/code by default (the page where a Claude Code session appears once Remote Control is enabled), so the dashboard points somewhere useful without needing --session-link. --fake gets no link (it has no real session), and an explicit --session-link still wins — including the {sessionId} template, which is filled in with the real Claude session id once known.

    Why not a per-session deep link: we drive Claude Code headless, and Remote Control (which powers the claude.ai/code session view) is opt-in and subscription-gated, so there is no session-URL slug to construct. The session id is already surfaced on the dashboard and in the CLI narration; the README's new "Watching the live session" section documents the Remote Control path. New exports: chooseSessionLink, CLAUDE_CODE_SESSION_LIST.

    Part of #209. Closes #212.

  • 97b2943: Extend an existing project instead of rebuilding it from scratch

    Pointed at a workspace that already has source, the build step now frames the wrapped agent to work within the existing codebase (read it, follow its conventions, add what was asked) rather than scaffold a fresh app. Greenfield runs (an empty workspace) are unchanged, and detection is gated on a real driver, so --fake stays deterministic. Combined with the live preset detection already wired from the real workspace, running in an existing project now detects its real stack and extends it.

    New exports: extendPrompt, isWorkspaceEmpty.

    Part of #110. Closes #185.

  • de37e7e: Make The Framework modular: a capability-extension + skill SPI, discovered instead of hardcoded

    The composition was pinned in run.ts (a fixed vikeExtensionPersonas list swapped in behind --compose-extensions), so no third party could publish a framework-* package and have it compose. This adds the extension SPI (#190), all agnostic (nothing is framework-gated):

    • defineFrameworkExtension — a capability (auth, data, rbac, crud, shell, ...) that self-registers, matched by signal (a dependency is present) or opt-in, and frames the agent with its personas. An extension supersedes the neutral default persona of the same capability (e.g. framework-data replaces the default ORM modeler), so the agent never gets two conflicting personas for one concern.
    • defineSkill — a doc pointer (an llms.txt), the shared unit with Open Loop (#204). A framework is a skill, not an adapter package: Vike now rides the same seam as https://vike.dev/llms.txt.
    • ExtensionRegistry / SkillRegistry, composePersonas, skillInstructions, and loadExtensionsFromModules for discovering installed framework-* packages.

    run.ts now composes matched extensions + skills through the registry instead of the hardcoded list, and the CLI reads the project's real signals and discovers installed framework-* capability packages (resolved from the user's workspace, failures reported not thrown). The built-in vike-* composers ship as extensions (framework-auth, framework-data, framework-rbac, framework-crud, framework-shell) and Vike ships as a skill, proving the seam. --compose-extensions still opts every built-in in; the publish-safe default (hand-rolled + Prisma) is unchanged. Closes #190.

  • d98d4ad: Move the framework page builder off the preset onto its skill (fully skill-driven framing)

    A framework was represented twice: its page-builder persona rode the preset seam (preset.personas, framed as the run's base) while its docs rode the skill seam (vike.dev/llms.txt). This finishes the "framework = skill, adapter axis gone" design: a Skill now carries its own curated framing personas alongside the doc pointer, so all of a framework's knowledge lives in one unit. vikeSkill carries vikePageBuilder; the new nextSkill carries nextPageBuilder. A preset is now a pure detector that points at its framework skill, and run.ts frames the page builder through the skill set (the detected preset's skill is always framed, even on an empty from-scratch project where nothing signal-matched, since preset selection is the fallback). New exports: nextSkill, skillPersonas. presetPersonas and the framing narration are unchanged. Part of #190.

  • a06e845: Persist the orchestration state so a restarted dashboard can resume it

    A run now saves its orchestration state (the stack rationale, loop status, and decisions ledger) so it survives a restart. Because the dashboard is a pure projection of the run's FrameworkEvent stream, persisting is durably logging that stream: each run appends to .framework/events.jsonl in the workspace, keeps a small derived run.json snapshot beside it, and writes a human-readable DECISIONS.md at the root. framework --resume reopens the last run's dashboard read-only by replaying the log into a fresh stream, exactly as it looked, without running the agent again. --no-persist opts out of writing state.

    Per the design sync we do not persist the agent's chat transcript (Claude Code owns that); only our own orchestration events. New RunStore module and exports (RunStore, nodeStoreFs, metaFromEvents, applyEventToMeta, RunMeta, StoreFs, ...); new --resume / --no-persist CLI flags.

    Part of #209. Closes #211.

  • c79f567: Recover from-scratch builds: scaffold an empty workspace instead of only polishing

    The full-fledged loop assumed an app already existed, so a from-scratch run could end at the framework's default "Welcome" page. The build step now verifies it produced files and hard re-prompts to scaffold from scratch if the workspace is still empty; the improve step switches to a "create the whole app from scratch" directive when the workspace is empty (instead of "smallest change / no unrelated features"); and the default --max-passes is raised from 3 to 5 so a from-scratch build has room to recover. Also clarifies the dashboard/terminal end status ("finished", not "done", so it reads as separate from the production-grade badge). Closes #182.

  • f1d11d9: Architect stack rationale: PROS/CONS + alternatives considered

    The web dashboard's edge over the CLI is showing why the AI chose the stack. The architect step now returns that rationale, not just a one-line why:

    • ArchitectPlan gains optional pros, cons, and alternatives ({option, whyNot}). The agentArchitect (ai-sdk) and driverArchitect (framework) both ask for them and parse them; absent fields are omitted, so existing producers are unaffected.
    • A new exported STACK_TRADEOFFS block gives the architect objective, reusable Vike-vs-Next reasons (edge/Cloudflare deploy, renderer-agnostic, ecosystem size) so the justification is grounded rather than invented per run. Both architect prompts embed it.
    • The Bootstrap orchestrator emits pros/cons/alternatives on the architect event and records the rejected alternatives to the decisions ledger as rejections, so the ledger shows what was weighed.
    • The framework dashboard's "Stack & rationale" panel renders the pros, cons, and "Considered instead" alternatives. The --fake demo populates them.

    Part of #209. Closes #210.

Patch Changes

  • 5288ca6: Enforce the Vike-only constraint on --compose-extensions

    --compose-extensions is documented as Vike-only, but runFramework applied the vike-* composer personas regardless of the detected preset, so a Next project would be framed with nextPageBuilder plus composers telling the agent to install vike-auth/vike-crud/etc.: an incoherent prompt. It now gates compose on the Vike preset and, on any other preset, falls back to the hand-rolled + Prisma path and emits a log explaining why.

  • c9cf96b: Fix the --compose-extensions help text to name the full composer set

    The framework --help output described --compose-extensions as composing "vike-auth for auth" only, but the flag frames the agent with the whole vike-* composer set: auth, the universal-orm data layer, rbac, crud/admin, and themes/layouts. The help text now names them accurately.

  • Updated dependencies [1db19e2]

  • Updated dependencies [c3e7e9e]

  • Updated dependencies [6625ca7]

  • Updated dependencies [bd13fcf]

  • Updated dependencies [11f76da]

  • Updated dependencies [c79f567]

  • Updated dependencies [93892d7]

  • Updated dependencies [de37e7e]

  • Updated dependencies [d98d4ad]

  • Updated dependencies [f1d11d9]

    • @gemstack/ai-autopilot@0.6.0

@gemstack/ai-autopilot@0.7.0

Choose a tag to compare

@github-actions github-actions released this 04 Jul 21:30
54d525d

Minor Changes

  • 6f7e7e3: Add WebContainerRunner, the in-browser sandboxed runner

    WebContainerRunner is the third real Runner adapter (after LocalRunner and
    DockerRunner), wrapping StackBlitz's @webcontainer/api. It runs untrusted,
    agent-authored code entirely inside a browser tab: an in-browser Node runtime, an
    isolated filesystem, and an instant preview() URL for a dev server, with nothing
    touching the host. This is the "sit on harnesses, don't compete" bet for the
    browser: the same Runner interface, now backed by WebContainer.

    It is browser-only by construction (WebContainer needs SharedArrayBuffer, so the
    hosting page must be cross-origin isolated), so @webcontainer/api is an optional
    peer dependency and is imported lazily: loading @gemstack/ai-autopilot in Node
    never pulls it in. Guard with the new webContainerAvailable() and reach for
    DockerRunner on the server.

    Because a WebContainer cannot boot in Node, boot-and-serve is proven by a headless
    Chromium harness under packages/ai-autopilot/harness/webcontainer/ that drives
    the compiled adapter through boot, fs, exec (exit codes, cwd/env, timeout kill),
    start, a real preview URL, an in-container serve check, dispose, and reboot. The
    Node-only guards are covered by the default test suite.

    Part of #109 (the Flue adapter stays gated on a live Flue environment).