CLI runs on Node 20+: npx storebound (bunx keeps working)

- cli/lib/rt.ts: the runtime layer on node: modules (spawn / spawnSync with Bun's defaults, exit codes and
  "Executable not found", which with PATHEXT, sleep, serve, Glob, hasher, gunzip, stdin, SQLite, packageRoot,
  config imports with a type-stripping fallback for Node 20); every Bun.* use in cli/ goes through it
- tools/gen-embedded.ts -> cli/lib/embedded.ts: templates/, cli/shots/*.html and Play's Data safety form embedded
  (replaces Bun text imports; the bundle and the compiled sidecar carry them), checked fresh by bun run ci
- package.json: bin dist/storebound.mjs (Node ESM bundle, tools/build-node.ts, prepack), engines node >=20
- bun run ci: node bundle + node smoke (real node: --version, help, check same as Bun, scan, release plan --help,
  init, MCP handshake + tool call); Forgejo CI sets up Node 20; tests/node-compat.test.ts guards cli/
- install writes npx MCP commands when run with Node; bin/storebound falls back to Node
- docs: npx storebound init (Node 20+) or bunx storebound init
This commit is contained in:
CRTkafa 2026-10-13 04:03:09 +08:00
parent 614c32bcba
commit 36a8bf9625
73 changed files with 1195 additions and 251 deletions

View file

@ -65,10 +65,10 @@
</div>
<div class="install" role="group" aria-label="Install command">
<span class="prompt" aria-hidden="true">$</span>
<code id="install-cmd">bunx storebound init</code>
<button class="copy" type="button" data-copy="bunx storebound init" aria-label="Copy install command">Copy</button>
<code id="install-cmd">npx storebound init</code>
<button class="copy" type="button" data-copy="npx storebound init" aria-label="Copy install command">Copy</button>
</div>
<p class="install-note">Needs <a href="https://bun.sh" target="_blank" rel="noopener">Bun<span class="ext" aria-hidden="true">↗</span><span class="sr-only"> (opens in a new tab)</span></a> 1.1+. No account, no sign-up, no telemetry.</p>
<p class="install-note">Needs Node 20+ (or <a href="https://bun.sh" target="_blank" rel="noopener">Bun<span class="ext" aria-hidden="true">↗</span><span class="sr-only"> (opens in a new tab)</span></a> 1.1+: <code>bunx storebound init</code>). No account, no sign-up, no telemetry.</p>
</div>
<figure class="hero-video" id="teaser" aria-labelledby="teaser-cap">
@ -556,47 +556,47 @@ Rejection risks: 2 blocker, 3 high, 0 medium, 0 low
<div class="code"><button class="copy" type="button" data-copy-target="c-claude" aria-label="Copy Claude Code commands">Copy</button>
<pre id="c-claude"><code>/plugin marketplace add https://git.crt.fyi/CRT/storebound.git
/plugin install storebound@crtkafa</code></pre></div>
<p>Skills, MCP server and <code>storebound</code> on PATH. Or per project: <code>bunx storebound install <span class="nw">--agent claude</span></code></p>
<p>Skills, MCP server and <code>storebound</code> on PATH. Or per project: <code>npx storebound install <span class="nw">--agent claude</span></code></p>
</div>
<div class="panel" role="tabpanel" id="p-codex" aria-labelledby="tab-codex" tabindex="0">
<h4 class="panel-h">OpenAI Codex</h4>
<div class="code"><button class="copy" type="button" data-copy-target="c-codex" aria-label="Copy Codex command">Copy</button>
<pre id="c-codex"><code>bunx storebound install --agent codex</code></pre></div>
<pre id="c-codex"><code>npx storebound install --agent codex</code></pre></div>
<p>Skills in <code>.agents/skills</code>, MCP in <code>.codex/config.toml</code> (Codex reads it for trusted projects). The repo is also a Codex plugin, skills only.</p>
</div>
<div class="panel" role="tabpanel" id="p-gemini" aria-labelledby="tab-gemini" tabindex="0">
<h4 class="panel-h">Gemini CLI</h4>
<div class="code"><button class="copy" type="button" data-copy-target="c-gemini" aria-label="Copy Gemini CLI command">Copy</button>
<pre id="c-gemini"><code>gemini extensions install https://git.crt.fyi/CRT/storebound.git</code></pre></div>
<p>Skills, MCP server and <code>GEMINI.md</code>. Or <code>bunx storebound install --agent gemini</code></p>
<p>Skills, MCP server and <code>GEMINI.md</code>. Or <code>npx storebound install --agent gemini</code></p>
</div>
<div class="panel" role="tabpanel" id="p-cursor" aria-labelledby="tab-cursor" tabindex="0">
<h4 class="panel-h">Cursor</h4>
<div class="code"><button class="copy" type="button" data-copy-target="c-cursor" aria-label="Copy Cursor command">Copy</button>
<pre id="c-cursor"><code>bunx storebound install --agent cursor</code></pre></div>
<pre id="c-cursor"><code>npx storebound install --agent cursor</code></pre></div>
<p>Skills in <code>.agents/skills</code> and <code>.cursor/mcp.json</code>. The repo's <code>.cursor/rules/storebound.mdc</code> is an agent-requested rule you can copy.</p>
</div>
<div class="panel" role="tabpanel" id="p-copilot" aria-labelledby="tab-copilot" tabindex="0">
<h4 class="panel-h">VS Code / GitHub Copilot</h4>
<div class="code"><button class="copy" type="button" data-copy-target="c-copilot" aria-label="Copy Copilot command">Copy</button>
<pre id="c-copilot"><code>bunx storebound install --agent copilot</code></pre></div>
<pre id="c-copilot"><code>npx storebound install --agent copilot</code></pre></div>
<p>Skills in <code>.github/skills</code> and <code>.vscode/mcp.json</code>.</p>
</div>
<div class="panel" role="tabpanel" id="p-windsurf" aria-labelledby="tab-windsurf" tabindex="0">
<h4 class="panel-h">Windsurf (Devin Desktop)</h4>
<div class="code"><button class="copy" type="button" data-copy-target="c-windsurf" aria-label="Copy Windsurf command">Copy</button>
<pre id="c-windsurf"><code>bunx storebound install --agent windsurf</code></pre></div>
<pre id="c-windsurf"><code>npx storebound install --agent windsurf</code></pre></div>
<p>Skills in <code>.agents/skills</code>, MCP in your global <code>mcp_config.json</code>.</p>
</div>
<div class="panel" role="tabpanel" id="p-opencode" aria-labelledby="tab-opencode" tabindex="0">
<h4 class="panel-h">OpenCode</h4>
<div class="code"><button class="copy" type="button" data-copy-target="c-opencode" aria-label="Copy OpenCode command">Copy</button>
<pre id="c-opencode"><code>bunx storebound install --agent opencode</code></pre></div>
<pre id="c-opencode"><code>npx storebound install --agent opencode</code></pre></div>
<p>Skills in <code>.opencode/skills</code> and <code>opencode.json</code>.</p>
</div>
<div class="panel" role="tabpanel" id="p-agents" aria-labelledby="tab-agents" tabindex="0">
<h4 class="panel-h">Anything that reads AGENTS.md</h4>
<p>Copy or link <code>AGENTS.md</code> (rules and skill index) into your project and use the CLI. For an MCP client <code>install</code> does not know: command <code>bunx</code> with args <code>["storebound", "mcp"]</code>.</p>
<p>Copy or link <code>AGENTS.md</code> (rules and skill index) into your project and use the CLI. For an MCP client <code>install</code> does not know: command <code>npx</code> (or <code>bunx</code>) with args <code>["storebound", "mcp"]</code>.</p>
</div>
</div>
<p class="fine"><code>install</code> takes several agents at once (<code>--agent codex,cursor</code>), <code>--dry</code> to preview, and only touches its own <code>storebound</code> entry and skill folders. Re-running it is safe.</p>
@ -702,8 +702,8 @@ com.example.app.gems_100 create 174 regions, 2 listings, USD 0.99
</div>
<div class="st-panel" id="sp-1">
<div class="pv pv-term">
<div class="pv-bar"><span class="pv-k">Terminal</span><button class="copy" type="button" data-copy="bunx storebound init --profile app" aria-label="Copy step 1 command">Copy</button></div>
<pre><code><span class="p">$</span> bunx storebound init --profile app</code></pre>
<div class="pv-bar"><span class="pv-k">Terminal</span><button class="copy" type="button" data-copy="npx storebound init --profile app" aria-label="Copy step 1 command">Copy</button></div>
<pre><code><span class="p">$</span> npx storebound init --profile app</code></pre>
</div>
<div class="pv-row">
<span class="pv-label">Profiles</span>
@ -714,7 +714,7 @@ com.example.app.gems_100 create 174 regions, 2 listings, USD 0.99
<li><code>store/</code><span>listing text, questionnaire answers, screenshot captions</span></li>
<li><code>.storebound/</code><span>your keys, gitignored</span></li>
</ul>
<p class="pv-note">Needs <a href="https://bun.sh" target="_blank" rel="noopener">Bun<span class="ext" aria-hidden="true">↗</span><span class="sr-only"> (opens in a new tab)</span></a> 1.1+, plus <code>ffmpeg</code> for icons, screenshots and video.</p>
<p class="pv-note">Needs Node 20+ (or <a href="https://bun.sh" target="_blank" rel="noopener">Bun<span class="ext" aria-hidden="true">↗</span><span class="sr-only"> (opens in a new tab)</span></a> 1.1+ with <code>bunx</code>), plus <code>ffmpeg</code> for icons, screenshots and video.</p>
<div class="st-foot" hidden><span>Step 1 of 5</span><button class="st-next" type="button" data-next="1">Next: Describe the app once<span class="ic ic-caret-right" aria-hidden="true"></span></button></div>
</div>
</li>
@ -738,8 +738,8 @@ com.example.app.gems_100 create 174 regions, 2 listings, USD 0.99
};</code></pre>
</div>
<div class="pv pv-term">
<div class="pv-bar"><span class="pv-k">Terminal</span><button class="copy" type="button" data-copy="bunx storebound check" aria-label="Copy step 2 command">Copy</button></div>
<pre><code><span class="p">$</span> bunx storebound check</code></pre>
<div class="pv-bar"><span class="pv-k">Terminal</span><button class="copy" type="button" data-copy="npx storebound check" aria-label="Copy step 2 command">Copy</button></div>
<pre><code><span class="p">$</span> npx storebound check</code></pre>
</div>
<p class="pv-note">Store text lives next to it in <code>store/listing.md</code> and <code>store/appstore.md</code>, one section per language.</p>
<div class="st-foot" hidden><span>Step 2 of 5</span><button class="st-next" type="button" data-next="2">Next: Add your store keys<span class="ic ic-caret-right" aria-hidden="true"></span></button></div>
@ -773,8 +773,8 @@ com.example.app.gems_100 create 174 regions, 2 listings, USD 0.99
</div>
<div class="st-panel" id="sp-4">
<div class="pv pv-term">
<div class="pv-bar"><span class="pv-k">Terminal</span><button class="copy" type="button" data-copy="bunx storebound install --agent claude" aria-label="Copy step 4 command">Copy</button></div>
<pre><code><span class="p">$</span> bunx storebound install --agent claude</code></pre>
<div class="pv-bar"><span class="pv-k">Terminal</span><button class="copy" type="button" data-copy="npx storebound install --agent claude" aria-label="Copy step 4 command">Copy</button></div>
<pre><code><span class="p">$</span> npx storebound install --agent claude</code></pre>
</div>
<p class="pv-note">Or <code>codex</code>, <code>cursor</code>, <code>copilot</code>, <code>gemini</code>, <code>windsurf</code>, <code>opencode</code> (<a href="#agents">per tool</a>). No agent? Every step is a CLI command too.</p>
<ul class="asks2" aria-label="Things to ask">
@ -793,8 +793,8 @@ com.example.app.gems_100 create 174 regions, 2 listings, USD 0.99
</div>
<div class="st-panel" id="sp-5">
<div class="pv pv-term">
<div class="pv-bar"><span class="pv-k">Terminal</span><button class="copy" type="button" data-copy="bunx storebound validate" aria-label="Copy step 5 command">Copy</button></div>
<pre><code><span class="p">$</span> bunx storebound validate</code></pre>
<div class="pv-bar"><span class="pv-k">Terminal</span><button class="copy" type="button" data-copy="npx storebound validate" aria-label="Copy step 5 command">Copy</button></div>
<pre><code><span class="p">$</span> npx storebound validate</code></pre>
</div>
<ol class="gate" aria-label="The last step">
<li><b>Blockers, per store, in fix order</b><span>build, encryption, metadata, screenshots, review details, prices, products</span></li>
@ -840,7 +840,7 @@ com.example.app.gems_100 create 174 regions, 2 listings, USD 0.99
<div class="faq">
<details open>
<summary><h3>Do I need an AI agent?</h3></summary>
<div class="faq-a"><p>No. Every step is a CLI command too (<code>bunx storebound --help</code>), and the skills are Markdown checklists you can read yourself for the console-only forms. The agent integrations are optional.</p></div>
<div class="faq-a"><p>No. Every step is a CLI command too (<code>npx storebound --help</code>), and the skills are Markdown checklists you can read yourself for the console-only forms. The agent integrations are optional.</p></div>
</details>
<details>
<summary><h3>Will it press Submit for me?</h3></summary>
@ -868,7 +868,7 @@ com.example.app.gems_100 create 174 regions, 2 listings, USD 0.99
</details>
<details>
<summary><h3>Does it run on Windows or Linux?</h3></summary>
<div class="faq-a"><p>It runs wherever Bun 1.1+ runs; it does not run on plain Node. The store commands are API calls. Capturing from the iOS Simulator needs a Mac with Xcode; a web build, an Android emulator or a folder of frames works anywhere. Icons, screenshots and video also need <code>ffmpeg</code>.</p></div>
<div class="faq-a"><p>It runs on Node 20+ (<code>npx storebound</code>) and on Bun 1.1+ (<code>bunx storebound</code>). The store commands are API calls. Capturing from the iOS Simulator needs a Mac with Xcode; a web build, an Android emulator or a folder of frames works anywhere. Icons, screenshots and video also need <code>ffmpeg</code>.</p></div>
</details>
</div>
</div>