<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Changelog — stack</title>
<meta name="description" content="What's shipped so far, on the way to v1.0." />
<link rel="icon" href="assets/logo.svg" type="image/svg+xml" />
<link rel="stylesheet" href="styles.css" />
<style>
.wrap { max-width: 800px; margin: 0 auto; padding: 0 clamp(20px, 5vw, 72px); }
.nav { padding-inline: max(clamp(20px, 5vw, 72px), calc((100% - 1200px) / 2 + clamp(20px, 5vw, 72px))); }
.nav a[aria-current='page'] { color: var(--color-accent-700); }
main { padding-block: var(--space-8); }
.lead { font-size: 17px; opacity: 0.85; max-width: 60ch; }
.entry { margin: var(--space-8) 0; }
.entry-tag { display: inline-flex; align-items: center; font-family: var(--font-heading); font-size: 11px;
letter-spacing: 0.02em; padding: 3px 10px; border: 1px solid var(--color-accent); color: var(--color-accent-700); margin-bottom: var(--space-2); }
.entry h2 { margin-top: 0; }
.entry ul { margin: var(--space-3) 0 0; padding-left: 1.2em; }
.entry li { margin-bottom: var(--space-2); font-size: 14.5px; }
.entry li code { font-size: 0.9em; }
</style>
</head>
<body>
<nav class="nav site-nav">
<a href="index.html" class="nav-lockup"><img class="nav-mark" src="assets/logo.svg" alt="" /><span class="nav-brand">stack</span></a>
<div class="nav-links">
<a href="getting-started.html">Docs</a>
<a href="changelog.html" aria-current="page">Changelog</a>
<a href="https://github.com/sanayasfp/stack" target="_blank" rel="noopener">GitHub</a>
</div>
<button type="button" class="btn btn-secondary btn-icon theme-toggle blueprint" id="theme-toggle" aria-label="Switch between light and dark">
<i class="corner tl"></i><i class="corner tr"></i><i class="corner bl"></i><i class="corner br"></i>
<svg class="icon-sun" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>
<svg class="icon-moon" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
</nav>
<div class="wrap">
<main>
<span class="kicker" style="display:block;font-family:var(--font-heading);font-size:12px;letter-spacing:.08em;text-transform:uppercase;font-weight:600;color:var(--color-accent-700);margin-bottom:8px;">Changelog</span>
<h1>Changelog</h1>
<p class="lead">Per-version entries below. v0.1.0's initial feature set is grouped by area rather than as a flat commit list.</p>
<div class="entry">
<span class="entry-tag">v0.1.13 — 2026-07-28</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.13" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Fixed</h2>
<ul>
<li>Static assets (CSS, JS, fonts, images) on PHP projects using the v0.1.12 FastCGI default were being routed through <code>php-cgi</code> instead of served directly, coming back with the wrong <code>Content-Type</code> — browsers silently accept that for scripts but strictly refuse it for stylesheets, so any project relying on Caddy to serve its own static files (plain PHP, WordPress, phpMyAdmin) rendered completely unstyled. The FastCGI route now only proxies <code>*.php</code> requests and serves everything else directly, matching Caddy's own documented expansion of its <code>php_fastcgi</code> directive.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.12 — 2026-07-28</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.12" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Added</h2>
<ul>
<li>Real concurrent PHP execution. <code>php -S</code> can only handle one request at a time — a large database import, several browser tabs, or a frontend firing concurrent API calls all serialize and stall each other. A <code>[run]</code> block on a project with <code>[language.php]</code> declared and no explicit <code>command</code> now defaults to <code>php-cgi.exe</code> running real worker processes, fronted by Caddy's FastCGI transport — genuinely parallel request handling. No new manifest field: write nothing and this is the default; an explicit <code>command</code> is respected exactly as before. The doc root is auto-detected (<code>public/index.php</code> present means Laravel/Symfony-style; otherwise the project root).</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.11 — 2026-07-27</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.11" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Fixed</h2>
<ul>
<li><code>stack down</code> had no middle ground between stopping just a project's own <code>[run]</code> process and <code>--all</code> (every running project on the machine). Plain <code>stack down</code> now also stops any service the project declared — but only once no other currently running project still needs it, checked live at the moment you run it. If another project still depends on it, it's left running with a message naming which one.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.10 — 2026-07-27</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.10" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Changed</h2>
<ul>
<li>Internal: split the single 1300+ line command file into <code>core/commands/{lifecycle, scaffold, registry_commands, shell_integration}.rs</code>, grouped along the structure already implicit in the CLI. Pure refactor — nothing about how <code>stack</code> behaves changes in this version.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.9 — 2026-07-27</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.9" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Fixed</h2>
<ul>
<li><code>stack up</code> printed <code>languages</code>/<code>services</code> using Rust's raw debug array format (<code>languages: ["python"]</code>) instead of readable text — now a plain comma-joined list, or <code>(none)</code> when empty.</li>
<li>A failed language install left a raw Lua plugin-hook traceback with no indication of how to find a valid version — now points at <code>vfox search <plugin></code>.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.8 — 2026-07-26</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.8" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Fixed</h2>
<ul>
<li>A <code>[language.*]</code> pinned to a loose version (e.g. <code>php = "8.4"</code>, <code>node = "24.18"</code>) could fail to resolve even right after a clean, successful install — <code>vfox install php@8.4</code> would succeed and install the concrete <code>8.4.0-nts</code> build, but the follow-up lookup queried vfox with the original loose string, which was never itself an installed key. Broke both <code>stack up</code> and the ambient per-prompt <code>stack activate</code> for any language pinned this way, cascading into <code>[run].command</code> failing with "program not found". Now falls back to matching vfox's actually-installed versions as a prefix of the requested version when the exact key isn't found.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.7 — 2026-07-26</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.7" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Fixed</h2>
<ul>
<li>A registered service/tool whose path contains backslashes (the normal case on Windows) failed to start with a bogus "program not found" error. The path was fine — <code>stack</code> was tokenizing the resolved command with a POSIX-style shell parser that treats backslash as an escape character, silently corrupting the path first. Affected any registered service with a backslash path, not just one engine.</li>
</ul>
<h2>Added</h2>
<ul>
<li><code>stack unregister <kind> <name> <version></code> — removes a single entry from the global registry directly. Previously the only options were <code>stack register</code> (add) and <code>stack prune</code> (bulk-remove only entries orphaned across every tracked project).</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.6 — 2026-07-26</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.6" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Added</h2>
<ul>
<li><code>port</code> fields in <code>[service.*]</code> and <code>[run]</code> now accept a quoted <code>"{VAR}"</code> placeholder (e.g. <code>port = "{MEILISEARCH_PORT}"</code>), resolved the same way <code>command</code> placeholders already are (environment, then an interactive prompt with <code>--prompt</code>). Previously only a literal number was valid — quoting a placeholder there failed with a raw TOML type error before stack's own resolution logic ever ran.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.5 — 2026-07-26</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.5" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Fixed</h2>
<ul>
<li>Every CLI command and argument now has real help text. <code>stack --help</code> and <code>stack <command> --help</code> previously showed blank descriptions for every command, argument, and flag — the doc comments existed in the source but had never actually been committed, so no prior release shipped them.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.4 — 2026-07-26</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.4" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Fixed</h2>
<ul>
<li><code>stack doctor</code>/<code>stack setup</code> no longer reinstall Caddy on every run. The check only tested bare <code>PATH</code>, not the pinned-tools-store fallback <code>stack up</code> already resolves Caddy through — so every run re-downloaded and re-extracted the ~49MB zip and printed <code>warning: one or more checks failed</code>, even when Caddy was already correctly installed.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.3 — 2026-07-26</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);"><a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.3" target="_blank" rel="noopener">Release notes and downloads on GitHub</a>.</p>
<h2>Fixed</h2>
<ul>
<li><code>stack setup</code>'s printed tip line referenced an internal planning document that was never part of this repository. Removed — the tip is now just the Acrylic DNS Proxy suggestion.</li>
</ul>
<h2>Added</h2>
<ul>
<li><code>CLA.md</code> plus a CLA Assistant GitHub Action, and <code>CONTRIBUTING.md</code> — a clear path for outside contributions.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.1 – v0.1.2 — 2026-07-26</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);">Docs/metadata-only republishes — no source changes. <a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.2" target="_blank" rel="noopener">v0.1.2 release notes</a> · <a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.1" target="_blank" rel="noopener">v0.1.1</a>.</p>
<h2>Fixed</h2>
<ul>
<li>README's installer command, stale since v0.1.0 (hardcoded to that version's asset URL) — switched to GitHub's <code>releases/latest/download/</code> redirect so it doesn't need a manual bump on every future release.</li>
<li>Removed a README parenthetical describing a temporary docs-hosting arrangement that had no business being permanent public record.</li>
</ul>
</div>
<div class="entry">
<span class="entry-tag">v0.1.0 — 2026-07-26</span>
<p style="font-size:13px;opacity:0.75;margin:0 0 var(--space-3);">First tagged release. <a href="https://github.com/sanayasfp/stack/releases/tag/v0.1.0" target="_blank" rel="noopener">Release notes and downloads on GitHub</a> · <a href="https://crates.io/crates/stackenv" target="_blank" rel="noopener">crates.io</a>.</p>
<h2>Core orchestration</h2>
<ul>
<li>Manifest-driven <code>stack up</code>/<code>stack down</code>: clone-if-missing, language activation, service start/reuse, dev-server spawn, domain routing — in that order.</li>
<li>Services dedup by <code>engine@version</code> — every project referencing the same database version shares the one running instance, isolated by schema.</li>
<li><code>[run].external</code> — run your own dev server yourself, in your own terminal, exactly how you already would; stack only routes to it.</li>
<li><code>[service.*].external</code> — adopt a database you already have running instead of colliding with it or starting a duplicate.</li>
<li>Detached process spawn that survives the launching terminal closing, with output captured to a per-process log file.</li>
</ul>
</div>
<div class="entry">
<h2>Routing</h2>
<ul>
<li>Caddy driven entirely over its HTTP admin API — no Caddyfile, no file writes, no reload signal. Started on demand, torn down with <code>stack down --all</code>.</li>
<li><code>stack status</code> shows Caddy's own liveness and live route count.</li>
</ul>
</div>
<div class="entry">
<h2>Shell integration</h2>
<ul>
<li>Ambient per-prompt activation for PowerShell — <code>cd</code> into a project and its pinned languages are on <code>PATH</code>; leave, and it resets.</li>
<li>cmd.exe support via a regenerated <code>stack-activate.bat</code>, run manually after <code>cd</code>-ing (cmd has no per-prompt hook the way PowerShell does).</li>
<li>Automatic Composer function shadowing for PHP projects, so <code>composer install</code> uses the project's pinned PHP version even though Composer's own installer hardcodes one.</li>
<li><code>stack load-env</code> — session-scoped <code>.env</code> loading; confirms which variable names loaded, never the values.</li>
<li>A small <code>[stack]</code> prompt indicator, on both shells, when a project is active.</li>
</ul>
</div>
<div class="entry">
<h2>Manifest & CLI</h2>
<ul>
<li><code>[language.*]</code> generalized beyond php/node/python — any vfox-plugin language, an explicit manager, or a fully BYO path.</li>
<li><code>stack new</code> / <code>stack add</code> / <code>stack remove</code> — interactive scaffolding and format-preserving manifest edits that leave your comments and key order untouched.</li>
<li><code>stack register</code> + <code>stack list</code> + <code>stack prune</code> — reuse a BYO service/tool path across every project, see everything installed in one place, and clean up what's no longer referenced (dry-run by default).</li>
<li><code>stack stats</code> — continuously-refreshing CPU/memory view, <code>docker stats</code>-style.</li>
<li><code>stack doctor [--fix]</code> — checks vfox/uv/Caddy and every registered path; <code>--fix</code> installs the three at pinned, tested versions. Also flags pre-existing Windows database services worth adopting instead of duplicating.</li>
</ul>
</div>
</main>
</div>
<script src="site.js"></script>
</body>
</html>