@spec-engine/spec-engine 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/architecture/index.html +10 -2
- package/dist/docs/commands/index.html +7 -4
- package/dist/docs/pagefind/fragment/en_34cad94.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_94271d5.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_aa3ebfe.pf_fragment +0 -0
- package/dist/docs/pagefind/index/en_9af49f2.pf_index +0 -0
- package/dist/docs/pagefind/pagefind-entry.json +1 -1
- package/dist/docs/pagefind/pagefind.en_beb6d752c1.pf_meta +0 -0
- package/dist/docs/platform-mapping/index.html +4 -3
- package/dist/impl.js +248 -71
- package/package.json +1 -1
- package/dist/docs/pagefind/fragment/en_48f1b3a.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_73bb90d.pf_fragment +0 -0
- package/dist/docs/pagefind/fragment/en_a7dfb2d.pf_fragment +0 -0
- package/dist/docs/pagefind/index/en_6c7635b.pf_index +0 -0
- package/dist/docs/pagefind/pagefind.en_20f81448c5.pf_meta +0 -0
|
@@ -378,7 +378,15 @@
|
|
|
378
378
|
|
|
379
379
|
|
|
380
380
|
|
|
381
|
-
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
<table><thead><tr><th>Operation</th><th>Input</th><th>Result</th><th>CLI</th><th>HTTP</th><th>MCP</th></tr></thead><tbody><tr><td><code dir="auto">query</code></td><td>storage, text, limit</td><td>ranked hits, or <code dir="auto">usage</code> on an FTS5 grammar error</td><td><code dir="auto">spec query</code></td><td><code dir="auto">GET /api/query</code></td><td><code dir="auto">spec_query</code></td></tr><tr><td><code dir="auto">resolveFiles</code></td><td>storage, platform-relative files</td><td>the requirements tagged in them</td><td><code dir="auto">spec resolve</code></td><td><code dir="auto">GET /api/resolve?files=</code></td><td><code dir="auto">spec_resolve</code></td></tr><tr><td><code dir="auto">reqTags</code></td><td>storage, requirement id</td><td>every tag site, and whether the id is known</td><td><code dir="auto">spec resolve --req</code></td><td><code dir="auto">GET /api/resolve?req=</code></td><td><code dir="auto">spec_req_tags</code></td></tr><tr><td><code dir="auto">propagation</code></td><td>storage, requirement id</td><td>per-member migration state</td><td><code dir="auto">spec propagation</code></td><td><code dir="auto">GET /api/propagation/:id</code></td><td><code dir="auto">spec_propagation</code></td></tr><tr><td><code dir="auto">coverageReport</code></td><td>storage</td><td>per-domain rollup</td><td></td><td><code dir="auto">GET /api/report</code></td><td><code dir="auto">spec_coverage_report</code></td></tr><tr><td><code dir="auto">check</code></td><td>storage, platform dir, results file, base ref, flags</td><td>diagnostics, <code dir="auto">build_id</code>, red or green</td><td><code dir="auto">spec check</code></td><td></td><td><code dir="auto">spec_check</code></td></tr><tr><td><code dir="auto">nextId</code></td><td>platform dir, domain key or prefix</td><td>the resolved key and next unused id, or <code dir="auto">usage</code></td><td><code dir="auto">spec req</code></td><td></td><td><code dir="auto">spec_next_id</code></td></tr><tr><td><code dir="auto">mint</code></td><td>platform dir, key, statement, why, lives-in, issue, status</td><td>the new id and file, or <code dir="auto">not_found</code> / <code dir="auto">usage</code> / <code dir="auto">invalid_domain_file</code></td><td><code dir="auto">spec req --text</code></td><td><code dir="auto">POST /api/requirements</code></td><td></td></tr><tr><td><code dir="auto">amend</code></td><td>platform dir, id, fields, a fresh-tags callback</td><td>the changed fields, or <code dir="auto">not_found</code> / <code dir="auto">conflict</code> / <code dir="auto">invalid_domain_file</code></td><td><code dir="auto">spec amend</code></td><td><code dir="auto">PUT /api/requirements/:id</code></td><td></td></tr><tr><td><code dir="auto">supersede</code></td><td>platform dir, id, successor statement and fields, a fresh-tags callback</td><td>the successor id, the domain version, the retag worklist, or <code dir="auto">not_found</code> / <code dir="auto">conflict</code> / <code dir="auto">usage</code> / <code dir="auto">invalid_domain_file</code></td><td><code dir="auto">spec supersede</code></td><td><code dir="auto">POST /api/requirements/:id/supersede</code></td><td><code dir="auto">spec_supersede</code></td></tr><tr><td><code dir="auto">move</code></td><td>platform dir, id, target domain key, optional successor fields, a fresh-tags callback</td><td>both files, both versions, the retag worklist, or <code dir="auto">usage</code> / <code dir="auto">not_found</code> / <code dir="auto">conflict</code> / <code dir="auto">invalid_domain_file</code></td><td><code dir="auto">spec move</code></td><td></td><td></td></tr><tr><td><code dir="auto">deprecate</code></td><td>platform dir, id, reason, a fresh-tags callback</td><td>the file and the tags still bound, or <code dir="auto">not_found</code> / <code dir="auto">conflict</code> / <code dir="auto">invalid_domain_file</code></td><td><code dir="auto">spec deprecate</code></td><td><code dir="auto">POST /api/requirements/:id/deprecate</code></td><td><code dir="auto">spec_deprecate</code></td></tr><tr><td><code dir="auto">accept</code></td><td>platform dir, id</td><td>the file, or <code dir="auto">not_found</code> / <code dir="auto">conflict</code> / <code dir="auto">invalid_domain_file</code></td><td><code dir="auto">spec accept</code></td><td><code dir="auto">POST /api/requirements/:id/accept</code></td><td><code dir="auto">spec_accept</code></td></tr><tr><td><code dir="auto">mintTerm</code>, <code dir="auto">listTerms</code>, <code dir="auto">reviseTerm</code>, <code dir="auto">confirmTerm</code></td><td>platform dir, term fields or ids</td><td>the term id, the store rows, the bumped version, or the re-pinned citation; <code dir="auto">not_found</code> / <code dir="auto">conflict</code> / <code dir="auto">invalid_domain_file</code></td><td><code dir="auto">spec term</code></td><td></td><td></td></tr><tr><td><code dir="auto">coverageMatrix</code></td><td>storage</td><td>requirement × repo rows</td><td><code dir="auto">spec map</code></td><td><code dir="auto">GET /api/coverage</code></td><td></td></tr><tr><td><code dir="auto">getRecord</code></td><td>storage, requirement id</td><td>one full <code dir="auto">Requirement</code> row, or null</td><td><code dir="auto">spec get</code></td><td><code dir="auto">GET /api/requirements/:id</code></td><td><code dir="auto">spec_get</code></td></tr><tr><td><code dir="auto">listRecords</code></td><td>storage, optional key and status</td><td>every <code dir="auto">Requirement</code> row in (key, seq) order</td><td><code dir="auto">spec list</code></td><td><code dir="auto">GET /api/requirements</code></td><td><code dir="auto">spec_list</code></td></tr><tr><td><code dir="auto">relations</code></td><td>storage</td><td><code dir="auto">relates</code> links</td><td><code dir="auto">spec relations</code></td><td><code dir="auto">GET /api/relations</code></td><td></td></tr><tr><td><code dir="auto">provenance</code></td><td>storage, optional issue id</td><td>provenance matrix rows</td><td><code dir="auto">spec provenance</code></td><td><code dir="auto">GET /api/provenance</code></td><td></td></tr><tr><td><code dir="auto">guard</code></td><td>storage, platform dir, git ref</td><td>the losses a change is about to cause</td><td><code dir="auto">spec guard</code></td><td></td><td></td></tr><tr><td><code dir="auto">gate</code></td><td>storage, platform dir, repo, requirement id</td><td>the gate outcome and <code dir="auto">build_id</code>, or <code dir="auto">usage</code> for an unknown repo</td><td><code dir="auto">spec gate</code></td><td></td><td></td></tr><tr><td><code dir="auto">resolveMemberPin</code>, <code dir="auto">writeMemberConfig</code></td><td>repo dir, pin override, force</td><td>the pin and its source; wrote or already configured, or <code dir="auto">usage</code> / <code dir="auto">conflict</code></td><td><code dir="auto">spec init</code></td><td></td><td></td></tr><tr><td><code dir="auto">newDomain</code>, <code dir="auto">listDomains</code></td><td>platform dir, key</td><td>the scaffolded file, or <code dir="auto">usage</code> / <code dir="auto">conflict</code> / <code dir="auto">invalid_domain_file</code>; the <code dir="auto">{ key, scope }</code> rows</td><td><code dir="auto">spec domain</code></td><td></td><td></td></tr><tr><td><code dir="auto">writeGlossary</code>, <code dir="auto">migrateGlossary</code>, <code dir="auto">checkGlossary</code></td><td>platform dir</td><td>the generated count, the migrated count or a skip, clean or drift</td><td><code dir="auto">spec glossary</code></td><td></td><td></td></tr></tbody></table>
|
|
382
390
|
<p>Reads take an open <code dir="auto">Storage</code> handle because the surface owns the handle’s lifetime: the CLI and MCP open one per call through <code dir="auto">withIndex</code>, the API keeps one for the life of the server. Writes take the platform directory because they edit <code dir="auto">SPEC.json</code> files. A lifecycle write takes a fresh-tags callback for its worklist, so a one-shot surface cold-rebuilds a throwaway index while the API re-indexes into the handle it keeps. Every guard runs before the first byte is written (REQ-038 <!-- @spec REQ-038 -->), and <code dir="auto">operations-parity.test.ts</code> proves each surface writes the same envelope.</p>
|
|
383
391
|
<div class="sl-heading-wrapper level-h2"><h2 id="the-single-seams">The single seams</h2><a class="sl-anchor-link" href="#the-single-seams"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “The single seams”</span></a></div>
|
|
384
392
|
<p>Each of these exists exactly once, and a grep fence in <code dir="auto">scripts/arch-fences.sh</code> fails CI if a second copy appears. Every fence label starts with the id of the requirement the fence enforces, and the fence function carries that id as its <code dir="auto">@spec</code> tag.</p>
|
|
@@ -443,7 +451,7 @@
|
|
|
443
451
|
<li>Render text to stdout, or the sorted <code dir="auto">--json</code> array. Warnings and guidance go to stderr.</li>
|
|
444
452
|
</ol>
|
|
445
453
|
<div class="sl-heading-wrapper level-h2"><h2 id="write-path">Write path</h2><a class="sl-anchor-link" href="#write-path"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Write path”</span></a></div>
|
|
446
|
-
<p><code dir="auto">spec req</code>, <code dir="auto">spec amend</code>, <code dir="auto">spec supersede</code>, <code dir="auto">spec move</code>, <code dir="auto">spec deprecate</code>, <code dir="auto">spec term</code>:</p>
|
|
454
|
+
<p><code dir="auto">spec req</code>, <code dir="auto">spec amend</code>, <code dir="auto">spec accept</code>, <code dir="auto">spec supersede</code>, <code dir="auto">spec move</code>, <code dir="auto">spec deprecate</code>, <code dir="auto">spec term</code>:</p>
|
|
447
455
|
<ol>
|
|
448
456
|
<li>Resolve the target domain and run every guard before writing a byte.</li>
|
|
449
457
|
<li>Allocate the next id from the filesystem, never from the index.</li>
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
})();
|
|
71
71
|
</script> </sl-sidebar-state-persist> <div class="md:sl-hidden"> <div class="mobile-preferences sl-flex astro-2lx56rho"> <div class="social-icons astro-2lx56rho"> <a href="https://github.com/spec-engine/spec-engine" rel="me" class="sl-flex astro-opyhioab"><span class="sr-only astro-opyhioab">GitHub</span><svg aria-hidden="true" class="astro-opyhioab astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M12 .3a12 12 0 0 0-3.8 23.38c.6.12.83-.26.83-.57L9 21.07c-3.34.72-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.08-.74.09-.73.09-.73 1.2.09 1.83 1.24 1.83 1.24 1.08 1.83 2.81 1.3 3.5 1 .1-.78.42-1.31.76-1.61-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.14-.3-.54-1.52.1-3.18 0 0 1-.32 3.3 1.23a11.5 11.5 0 0 1 6 0c2.28-1.55 3.29-1.23 3.29-1.23.64 1.66.24 2.88.12 3.18a4.65 4.65 0 0 1 1.23 3.22c0 4.61-2.8 5.63-5.48 5.92.42.36.81 1.1.81 2.22l-.01 3.29c0 .31.2.69.82.57A12 12 0 0 0 12 .3Z"/></svg></a> </div> <starlight-theme-select> <label style="--sl-select-width: 6.25em" class="astro-oxpvutiw"> <span class="sr-only astro-oxpvutiw">Select theme</span> <svg aria-hidden="true" class="icon label-icon astro-oxpvutiw astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M21 14h-1V7a3 3 0 0 0-3-3H7a3 3 0 0 0-3 3v7H3a1 1 0 0 0-1 1v2a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3v-2a1 1 0 0 0-1-1ZM6 7a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v7H6V7Zm14 10a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-1h16v1Z"/></svg> <select autocomplete="off" class="astro-oxpvutiw"> <option value="dark" class="astro-oxpvutiw">Dark</option><option value="light" class="astro-oxpvutiw">Light</option><option value="auto" selected class="astro-oxpvutiw">Auto</option> </select> <svg aria-hidden="true" class="icon caret astro-oxpvutiw astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1em;"><path d="M17 9.17a1 1 0 0 0-1.41 0L12 12.71 8.46 9.17a1 1 0 1 0-1.41 1.42l4.24 4.24a1.002 1.002 0 0 0 1.42 0L17 10.59a1.002 1.002 0 0 0 0-1.42Z"/></svg> </label> </starlight-theme-select> <script>
|
|
72
72
|
StarlightThemeProvider.updatePickers();
|
|
73
|
-
</script> </div> </div> </div> </div> </nav> <div class="main-frame astro-to3xypmc"> <script type="module">const a=document.getElementById("starlight__sidebar"),n=a?.querySelector("sl-sidebar-state-persist"),o="sl-sidebar-state",i=()=>{let t=[];const e=n?.dataset.hash||"";try{const s=sessionStorage.getItem(o),r=JSON.parse(s||"{}");Array.isArray(r.open)&&r.hash===e&&(t=r.open)}catch{}return{hash:e,open:t,scroll:a?.scrollTop||0}},c=t=>{try{sessionStorage.setItem(o,JSON.stringify(t))}catch{}},d=()=>c(i()),l=(t,e)=>{const s=i();s.open[e]=t,c(s)};n?.addEventListener("click",t=>{if(!(t.target instanceof Element))return;const e=t.target.closest("summary")?.closest("details");if(!e)return;const s=e.querySelector("sl-sidebar-restore"),r=parseInt(s?.dataset.index||"");isNaN(r)||l(!e.open,r)});addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&d()});addEventListener("pageHide",d);</script> <div class="lg:sl-flex astro-blhl7r6q"> <aside class="right-sidebar-container print:hidden astro-blhl7r6q"> <div class="right-sidebar astro-blhl7r6q"> <div class="lg:sl-hidden astro-l5m3cfel"><mobile-starlight-toc data-min-h="2" data-max-h="3" class="astro-goxitxj7"><nav aria-labelledby="starlight__on-this-page--mobile" class="astro-goxitxj7"><details id="starlight__mobile-toc" class="astro-goxitxj7"><summary id="starlight__on-this-page--mobile" class="sl-flex astro-goxitxj7"><span class="toggle sl-flex astro-goxitxj7">On this page<svg aria-hidden="true" class="caret astro-goxitxj7 astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg></span><span class="display-current astro-goxitxj7"></span></summary><div class="dropdown astro-goxitxj7"><ul class="isMobile astro-xz67lhkg" style="--depth: 0;"> <li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#_top" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Overview</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#exit-code-contract" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Exit code contract</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#common-flags" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Common flags</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#command-reference" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Command reference</span> </a> <ul class="isMobile astro-xz67lhkg" style="--depth: 1;"> <li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-index-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec index [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-check-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec check [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-guard-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec guard [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-map-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec map [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-get-key-nnn-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec get <KEY-NNN> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-list-platformdir---domain-key---status-s" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec list [platformDir] [--domain KEY] [--status S]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-query-text-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec query <text> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-relations-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec relations [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-provenance-issueid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec provenance [issueId] [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-resolve-files-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec resolve <files...> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-propagation-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec propagation <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-gate-repo-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec gate <repo> <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-init-repo" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec init [repo]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-domain-new-name--spec-domain-list-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec domain new <name> / spec domain list [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-migrate-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec migrate [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-req-domain-prefix-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec req <domain-prefix> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-term-" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec term …</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-glossary-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec glossary [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-supersede-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec supersede <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-move-reqid-new-domain-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec move <reqId> <NEW-DOMAIN> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-amend-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec amend <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-serve-platformdir---port-n" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec serve [platformDir] [--port N]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-mcp-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec mcp [platformDir]</span> </a> </li> </ul> </li> </ul></div></details></nav></mobile-starlight-toc><script type="module" src="/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.hwBsy0Mo.js"></script></div><div class="right-sidebar-panel sl-hidden lg:sl-block astro-l5m3cfel"><div class="sl-container astro-l5m3cfel"><starlight-toc data-min-h="2" data-max-h="3"><nav aria-labelledby="starlight__on-this-page"><h2 id="starlight__on-this-page">On this page</h2><ul class="astro-xz67lhkg" style="--depth: 0;"> <li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#_top" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Overview</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#exit-code-contract" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Exit code contract</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#common-flags" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Common flags</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#command-reference" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Command reference</span> </a> <ul class="astro-xz67lhkg" style="--depth: 1;"> <li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-index-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec index [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-check-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec check [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-guard-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec guard [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-map-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec map [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-get-key-nnn-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec get <KEY-NNN> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-list-platformdir---domain-key---status-s" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec list [platformDir] [--domain KEY] [--status S]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-query-text-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec query <text> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-relations-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec relations [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-provenance-issueid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec provenance [issueId] [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-resolve-files-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec resolve <files...> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-propagation-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec propagation <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-gate-repo-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec gate <repo> <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-init-repo" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec init [repo]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-domain-new-name--spec-domain-list-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec domain new <name> / spec domain list [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-migrate-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec migrate [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-req-domain-prefix-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec req <domain-prefix> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-term-" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec term …</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-glossary-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec glossary [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-supersede-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec supersede <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-move-reqid-new-domain-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec move <reqId> <NEW-DOMAIN> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-amend-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec amend <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-serve-platformdir---port-n" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec serve [platformDir] [--port N]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-mcp-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec mcp [platformDir]</span> </a> </li> </ul> </li> </ul></nav></starlight-toc><script type="module" src="/_astro/TableOfContents.astro_astro_type_script_index_0_lang.FuRcXuRY.js"></script></div></div> </div> </aside> <div class="main-pane astro-blhl7r6q"> <main data-pagefind-body class="astro-ioexmpvj" lang="en" dir="ltr"> <div class="content-panel astro-sfndtt72"> <div class="sl-container astro-sfndtt72"> <h1 id="_top" class="astro-4b4mtvou">Commands</h1> </div> </div> <div class="content-panel astro-sfndtt72"> <div class="sl-container astro-sfndtt72"> <div class="sl-markdown-content"> <p>Install the CLI from npm — <code dir="auto">bun add -g @spec-engine/spec-engine</code> puts <code dir="auto">spec</code> on your PATH, and every command below is written that way. Without a global install, run any of them as <code dir="auto">bunx @spec-engine/spec-engine <command> [args]</code>; from a checkout, as <code dir="auto">bun packages/engine/src/cli.ts <command> [args]</code>. See <a href="/getting-started/">Getting Started</a> for the details.</p>
|
|
73
|
+
</script> </div> </div> </div> </div> </nav> <div class="main-frame astro-to3xypmc"> <script type="module">const a=document.getElementById("starlight__sidebar"),n=a?.querySelector("sl-sidebar-state-persist"),o="sl-sidebar-state",i=()=>{let t=[];const e=n?.dataset.hash||"";try{const s=sessionStorage.getItem(o),r=JSON.parse(s||"{}");Array.isArray(r.open)&&r.hash===e&&(t=r.open)}catch{}return{hash:e,open:t,scroll:a?.scrollTop||0}},c=t=>{try{sessionStorage.setItem(o,JSON.stringify(t))}catch{}},d=()=>c(i()),l=(t,e)=>{const s=i();s.open[e]=t,c(s)};n?.addEventListener("click",t=>{if(!(t.target instanceof Element))return;const e=t.target.closest("summary")?.closest("details");if(!e)return;const s=e.querySelector("sl-sidebar-restore"),r=parseInt(s?.dataset.index||"");isNaN(r)||l(!e.open,r)});addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"&&d()});addEventListener("pageHide",d);</script> <div class="lg:sl-flex astro-blhl7r6q"> <aside class="right-sidebar-container print:hidden astro-blhl7r6q"> <div class="right-sidebar astro-blhl7r6q"> <div class="lg:sl-hidden astro-l5m3cfel"><mobile-starlight-toc data-min-h="2" data-max-h="3" class="astro-goxitxj7"><nav aria-labelledby="starlight__on-this-page--mobile" class="astro-goxitxj7"><details id="starlight__mobile-toc" class="astro-goxitxj7"><summary id="starlight__on-this-page--mobile" class="sl-flex astro-goxitxj7"><span class="toggle sl-flex astro-goxitxj7">On this page<svg aria-hidden="true" class="caret astro-goxitxj7 astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1rem;"><path d="m14.83 11.29-4.24-4.24a1 1 0 1 0-1.42 1.41L12.71 12l-3.54 3.54a1 1 0 0 0 0 1.41 1 1 0 0 0 .71.29 1 1 0 0 0 .71-.29l4.24-4.24a1.002 1.002 0 0 0 0-1.42Z"/></svg></span><span class="display-current astro-goxitxj7"></span></summary><div class="dropdown astro-goxitxj7"><ul class="isMobile astro-xz67lhkg" style="--depth: 0;"> <li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#_top" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Overview</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#exit-code-contract" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Exit code contract</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#common-flags" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Common flags</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#command-reference" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Command reference</span> </a> <ul class="isMobile astro-xz67lhkg" style="--depth: 1;"> <li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-index-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec index [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-check-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec check [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-guard-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec guard [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-map-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec map [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-get-key-nnn-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec get <KEY-NNN> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-list-platformdir---domain-key---status-s" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec list [platformDir] [--domain KEY] [--status S]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-query-text-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec query <text> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-relations-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec relations [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-provenance-issueid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec provenance [issueId] [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-resolve-files-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec resolve <files...> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-propagation-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec propagation <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-gate-repo-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec gate <repo> <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-init-repo" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec init [repo]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-domain-new-name--spec-domain-list-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec domain new <name> / spec domain list [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-migrate-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec migrate [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-req-domain-prefix-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec req <domain-prefix> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-term-" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec term …</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-glossary-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec glossary [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-supersede-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec supersede <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-move-reqid-new-domain-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec move <reqId> <NEW-DOMAIN> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-amend-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec amend <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-accept-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec accept <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-serve-platformdir---port-n" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec serve [platformDir] [--port N]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-mcp-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec mcp [platformDir]</span> </a> </li> </ul> </li> </ul></div></details></nav></mobile-starlight-toc><script type="module" src="/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.hwBsy0Mo.js"></script></div><div class="right-sidebar-panel sl-hidden lg:sl-block astro-l5m3cfel"><div class="sl-container astro-l5m3cfel"><starlight-toc data-min-h="2" data-max-h="3"><nav aria-labelledby="starlight__on-this-page"><h2 id="starlight__on-this-page">On this page</h2><ul class="astro-xz67lhkg" style="--depth: 0;"> <li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#_top" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Overview</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#exit-code-contract" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Exit code contract</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#common-flags" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Common flags</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 0;"> <a href="#command-reference" class="astro-xz67lhkg" style="--depth: 0;"> <span class="astro-xz67lhkg" style="--depth: 0;">Command reference</span> </a> <ul class="astro-xz67lhkg" style="--depth: 1;"> <li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-index-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec index [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-check-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec check [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-guard-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec guard [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-map-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec map [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-get-key-nnn-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec get <KEY-NNN> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-list-platformdir---domain-key---status-s" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec list [platformDir] [--domain KEY] [--status S]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-query-text-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec query <text> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-relations-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec relations [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-provenance-issueid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec provenance [issueId] [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-resolve-files-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec resolve <files...> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-propagation-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec propagation <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-gate-repo-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec gate <repo> <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-init-repo" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec init [repo]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-domain-new-name--spec-domain-list-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec domain new <name> / spec domain list [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-migrate-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec migrate [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-req-domain-prefix-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec req <domain-prefix> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-term-" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec term …</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-glossary-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec glossary [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-supersede-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec supersede <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-move-reqid-new-domain-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec move <reqId> <NEW-DOMAIN> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-amend-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec amend <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-accept-reqid-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec accept <reqId> [platformDir]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-serve-platformdir---port-n" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec serve [platformDir] [--port N]</span> </a> </li><li class="astro-xz67lhkg" style="--depth: 1;"> <a href="#spec-mcp-platformdir" class="astro-xz67lhkg" style="--depth: 1;"> <span class="astro-xz67lhkg" style="--depth: 1;">spec mcp [platformDir]</span> </a> </li> </ul> </li> </ul></nav></starlight-toc><script type="module" src="/_astro/TableOfContents.astro_astro_type_script_index_0_lang.FuRcXuRY.js"></script></div></div> </div> </aside> <div class="main-pane astro-blhl7r6q"> <main data-pagefind-body class="astro-ioexmpvj" lang="en" dir="ltr"> <div class="content-panel astro-sfndtt72"> <div class="sl-container astro-sfndtt72"> <h1 id="_top" class="astro-4b4mtvou">Commands</h1> </div> </div> <div class="content-panel astro-sfndtt72"> <div class="sl-container astro-sfndtt72"> <div class="sl-markdown-content"> <p>Install the CLI from npm — <code dir="auto">bun add -g @spec-engine/spec-engine</code> puts <code dir="auto">spec</code> on your PATH, and every command below is written that way. Without a global install, run any of them as <code dir="auto">bunx @spec-engine/spec-engine <command> [args]</code>; from a checkout, as <code dir="auto">bun packages/engine/src/cli.ts <command> [args]</code>. See <a href="/getting-started/">Getting Started</a> for the details.</p>
|
|
74
74
|
<div class="sl-heading-wrapper level-h2"><h2 id="exit-code-contract">Exit code contract</h2><a class="sl-anchor-link" href="#exit-code-contract"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Exit code contract”</span></a></div>
|
|
75
75
|
|
|
76
76
|
|
|
@@ -197,7 +197,7 @@
|
|
|
197
197
|
<p>One-time hard cutover: convert every legacy canonical <code dir="auto">SPEC.md</code> to a schema-validated sibling <code dir="auto">SPEC.json</code>, then delete the <code dir="auto">SPEC.md</code>. Idempotent — skips already-migrated dirs.</p>
|
|
198
198
|
<p><strong>Exit codes:</strong> 0 / 2</p>
|
|
199
199
|
<div class="sl-heading-wrapper level-h3"><h3 id="spec-req-domain-prefix-platformdir"><code dir="auto">spec req <domain-prefix> [platformDir]</code></h3><a class="sl-anchor-link" href="#spec-req-domain-prefix-platformdir"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “spec req <domain-prefix> [platformDir]”</span></a></div>
|
|
200
|
-
<p><strong>Piped:</strong> prints the next unused requirement ID (e.g. <code dir="auto">BILLING-010</code>) — zero prompts, zero writes. <strong>TTY:</strong> interactive authoring. <strong><code dir="auto">--text</code> (+ <code dir="auto">--why</code> / <code dir="auto">--lives</code>):</strong> appends a born-active entry non-interactively through the validated write seam. Prefix is case-insensitive (<code dir="auto">bil</code> → <code dir="auto">BILLING</code>; ambiguous → exit 2). <code dir="auto">spec req <domain></code> alone prints the domain’s charter before authoring.</p>
|
|
200
|
+
<p><strong>Piped:</strong> prints the next unused requirement ID (e.g. <code dir="auto">BILLING-010</code>) — zero prompts, zero writes. <strong>TTY:</strong> interactive authoring. <strong><code dir="auto">--text</code> (+ <code dir="auto">--why</code> / <code dir="auto">--lives</code>):</strong> appends a born-active entry non-interactively through the validated write seam. <strong><code dir="auto">--draft</code>:</strong> the entry is born Draft instead (promote it with <code dir="auto">spec accept</code>). Prefix is case-insensitive (<code dir="auto">bil</code> → <code dir="auto">BILLING</code>; ambiguous → exit 2). <code dir="auto">spec req <domain></code> alone prints the domain’s charter before authoring.</p>
|
|
201
201
|
<p><strong>Exit codes:</strong> 0 / 2</p>
|
|
202
202
|
<div class="sl-heading-wrapper level-h3"><h3 id="spec-term-"><code dir="auto">spec term …</code></h3><a class="sl-anchor-link" href="#spec-term-"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “spec term …”</span></a></div>
|
|
203
203
|
<p>The glossary authoring surface — a term is a requirement row in the reserved <code dir="auto">TERM</code> domain (definition in the statement, headword in <code dir="auto">term</code>, synonyms in <code dir="auto">aliases</code>):</p>
|
|
@@ -221,7 +221,10 @@
|
|
|
221
221
|
<p>Cross-domain supersede for taxonomy reorganization: mints the successor as the next id in <code dir="auto"><NEW-DOMAIN></code> (which must exist), carrying the source’s fields (<code dir="auto">--text</code>/<code dir="auto">--why</code>/<code dir="auto">--lives</code> override), flips the source to superseded with a cross-domain <code dir="auto">supersededBy</code>, and emits the retag worklist. Both envelopes validate before either is written — a reject never half-applies. Only Active requirements move; moving into the source’s own domain is a usage error (use <code dir="auto">supersede</code>).</p>
|
|
222
222
|
<p><strong>Exit codes:</strong> 0 / 2</p>
|
|
223
223
|
<div class="sl-heading-wrapper level-h3"><h3 id="spec-amend-reqid-platformdir"><code dir="auto">spec amend <reqId> [platformDir]</code></h3><a class="sl-anchor-link" href="#spec-amend-reqid-platformdir"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “spec amend <reqId> [platformDir]”</span></a></div>
|
|
224
|
-
<p>Revise an unshipped requirement’s fields in place — same ID, no version change (the domain version only derives from supersessions). Field flags name what changes (<code dir="auto">--text</code>/<code dir="auto">--why</code>/<code dir="auto">--lives</code>, at least one); untouched fields stay byte-identical. Only Active and Draft entries amend.</p>
|
|
224
|
+
<p>Revise an unshipped requirement’s fields in place — same ID, no version change (the domain version only derives from supersessions). Field flags name what changes (<code dir="auto">--text</code>/<code dir="auto">--why</code>/<code dir="auto">--lives</code>, at least one); untouched fields stay byte-identical. <code dir="auto">--lives</code> repeats or comma-separates and replaces the whole list; <code dir="auto">--lives ""</code> clears it. Only Active and Draft entries amend.</p>
|
|
225
|
+
<p><strong>Exit codes:</strong> 0 / 2</p>
|
|
226
|
+
<div class="sl-heading-wrapper level-h3"><h3 id="spec-accept-reqid-platformdir"><code dir="auto">spec accept <reqId> [platformDir]</code></h3><a class="sl-anchor-link" href="#spec-accept-reqid-platformdir"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “spec accept <reqId> [platformDir]”</span></a></div>
|
|
227
|
+
<p>Promote a Draft requirement to Active — same ID, every other field untouched, no version change. A Draft is never an orphan, never unverified, and never counted in coverage; accepting it makes it an obligation.</p>
|
|
225
228
|
<p><strong>Exit codes:</strong> 0 / 2</p>
|
|
226
229
|
<div class="sl-heading-wrapper level-h3"><h3 id="spec-serve-platformdir---port-n"><code dir="auto">spec serve [platformDir] [--port N]</code></h3><a class="sl-anchor-link" href="#spec-serve-platformdir---port-n"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “spec serve [platformDir] [--port N]”</span></a></div>
|
|
227
230
|
<p>Launch the local webapp over the derived index. Binds <code dir="auto">127.0.0.1</code> only. <code dir="auto">--probe</code> boots on an ephemeral port, smoke-tests, and exits.</p>
|
|
@@ -229,5 +232,5 @@
|
|
|
229
232
|
<p><strong>Feature-flagged routes:</strong> <code dir="auto">/api/query?q=&limit=</code>, <code dir="auto">/api/relations[?format=mermaid]</code>, <code dir="auto">/api/provenance</code>, and the editor’s write routes answer <strong>404</strong> until their feature is enabled — the unshipped webapp features (query, relations, provenance, editor, glossary, logs) all default off. Opt in locally with a comma-separated <code dir="auto">SPEC_FLAGS</code> env var: <code dir="auto">SPEC_FLAGS=query,relations spec serve .</code> (unknown keys are ignored).</p>
|
|
230
233
|
<p><strong>Exit codes:</strong> 0 / 1 / 2</p>
|
|
231
234
|
<div class="sl-heading-wrapper level-h3"><h3 id="spec-mcp-platformdir"><code dir="auto">spec mcp [platformDir]</code></h3><a class="sl-anchor-link" href="#spec-mcp-platformdir"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “spec mcp [platformDir]”</span></a></div>
|
|
232
|
-
<p>Serve Spec Engine as a Model Context Protocol server over stdio. Tools: <code dir="auto">spec_query</code>, <code dir="auto">spec_resolve</code>, <code dir="auto">spec_req_tags</code>, <code dir="auto">spec_coverage_report</code>, <code dir="auto">spec_check</code>, <code dir="auto">spec_propagation</code>, <code dir="auto">spec_next_id</code>, <code dir="auto">spec_get</code>, <code dir="auto">spec_list</code>, <code dir="auto">spec_supersede</code>, <code dir="auto">spec_deprecate</code> — the same JSON the CLI’s <code dir="auto">--json</code> modes emit, reindexed fresh per call. Also advertises the <code dir="auto">author_requirements</code> prompt (a static authoring playbook; the engine itself runs no model).</p>
|
|
235
|
+
<p>Serve Spec Engine as a Model Context Protocol server over stdio. Tools: <code dir="auto">spec_query</code>, <code dir="auto">spec_resolve</code>, <code dir="auto">spec_req_tags</code>, <code dir="auto">spec_coverage_report</code>, <code dir="auto">spec_check</code>, <code dir="auto">spec_propagation</code>, <code dir="auto">spec_next_id</code>, <code dir="auto">spec_get</code>, <code dir="auto">spec_list</code>, <code dir="auto">spec_supersede</code>, <code dir="auto">spec_deprecate</code>, <code dir="auto">spec_accept</code> — the same JSON the CLI’s <code dir="auto">--json</code> modes emit, reindexed fresh per call. Also advertises the <code dir="auto">author_requirements</code> prompt (a static authoring playbook; the engine itself runs no model).</p>
|
|
233
236
|
<p><strong>Exit codes:</strong> 0 / 2</p> </div> <footer class="sl-flex astro-5h22m7ac"> <div class="meta sl-flex astro-5h22m7ac"> <a href="https://github.com/spec-engine/spec-engine/edit/main/packages/site/src/content/docs/commands.md" class="sl-flex print:hidden astro-txs4wy42"><svg aria-hidden="true" class="astro-txs4wy42 astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.2em;"><path d="M22 7.24a1 1 0 0 0-.29-.71l-4.24-4.24a1 1 0 0 0-1.1-.22 1 1 0 0 0-.32.22l-2.83 2.83L2.29 16.05a1 1 0 0 0-.29.71V21a1 1 0 0 0 1 1h4.24a1 1 0 0 0 .76-.29l10.87-10.93L21.71 8c.1-.1.17-.2.22-.33a1 1 0 0 0 0-.24v-.14l.07-.05ZM6.83 20H4v-2.83l9.93-9.93 2.83 2.83L6.83 20ZM18.17 8.66l-2.83-2.83 1.42-1.41 2.82 2.82-1.41 1.42Z"/></svg>Edit page</a> </div> <div class="pagination-links print:hidden astro-7kn6nbmm" dir="ltr"> <a href="/platform-mapping/" rel="prev" class="astro-7kn6nbmm"> <svg aria-hidden="true" class="astro-7kn6nbmm astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17 11H9.41l3.3-3.29a1.004 1.004 0 1 0-1.42-1.42l-5 5a1 1 0 0 0-.21.33 1 1 0 0 0 0 .76 1 1 0 0 0 .21.33l5 5a1.002 1.002 0 0 0 1.639-.325 1 1 0 0 0-.219-1.095L9.41 13H17a1 1 0 0 0 0-2Z"/></svg> <span class="astro-7kn6nbmm"> Previous <br class="astro-7kn6nbmm"> <span class="link-title astro-7kn6nbmm">Platform Mapping</span> </span> </a> <a href="/format/" rel="next" class="astro-7kn6nbmm"> <svg aria-hidden="true" class="astro-7kn6nbmm astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg> <span class="astro-7kn6nbmm"> Next <br class="astro-7kn6nbmm"> <span class="link-title astro-7kn6nbmm">SPEC.json Format</span> </span> </a> </div> </footer> </div> </div> </main> </div> </div> </div> </div> </body></html>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.5.2","languages":{"en":{"hash":"
|
|
1
|
+
{"version":"1.5.2","languages":{"en":{"hash":"en_beb6d752c1","wasm":"en","page_count":12}},"include_characters":["_","‿","⁀","⁔","︳","︴","﹍","﹎","﹏","_"]}
|
|
Binary file
|
|
@@ -119,11 +119,12 @@
|
|
|
119
119
|
<div class="sl-heading-wrapper level-h2"><h2 id="monorepo-members-and-their-packages">Monorepo members and their packages</h2><a class="sl-anchor-link" href="#monorepo-members-and-their-packages"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Monorepo members and their packages”</span></a></div>
|
|
120
120
|
<p>platform-map classifies every member as <code dir="auto">single-repo</code> or <code dir="auto">monorepo</code> from its ecosystem’s workspace manifest: <code dir="auto">pnpm-workspace.yaml</code>, <code dir="auto">package.json</code> <code dir="auto">workspaces</code>, <code dir="auto">lerna.json</code>, a <code dir="auto">uv</code> workspace, a Cargo workspace, or <code dir="auto">go.work</code>. A monorepo member’s packages are the directories its workspace manifest lists.</p>
|
|
121
121
|
<p>Each package is its own coverage column, named by the package’s path relative to the member (<code dir="auto">packages/ui</code>), prefixed by the member name when the member belongs to a declared platform (<code dir="auto">shared/packages/ui</code>). A package inherits its member’s pin unless it carries a nested <code dir="auto">spec-engine.member.json</code>, whose pin and <code dir="auto">ignore</code> then apply to that package alone. That is how one package can sit on <code dir="auto">spec-engine@2</code> while a sibling lags on <code dir="auto">@1</code>.</p>
|
|
122
|
+
<p>A monorepo’s files outside every workspace package (CI scripts, infrastructure, migrations at the repository root) are one more column: named by the member for a declared member, and by the directory for a lone monorepo. That column skips every package path, so no file is scanned twice, and it inherits the member’s <code dir="auto">ignore</code> list. When a workspace lists the repository root itself as a package, the root is already a column and no extra one is added. <!-- @spec INIT-040 --></p>
|
|
122
123
|
<p>There is no <code dir="auto">members</code> glob in <code dir="auto">spec-engine.member.json</code>. The workspace manifest is the one place a monorepo names its packages.</p>
|
|
123
124
|
<div class="sl-heading-wrapper level-h2"><h2 id="a-lone-repository">A lone repository</h2><a class="sl-anchor-link" href="#a-lone-repository"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “A lone repository”</span></a></div>
|
|
124
125
|
<p>A repository that holds its own <code dir="auto">spec-engine/</code> tree and is not a declared platform is a lone repository. platform-map maps it as <code dir="auto">single-repo</code> or <code dir="auto">monorepo</code> with one repo entry, and Spec Engine scans that repo without any member config or CI gate. <!-- @spec INIT-035 --></p>
|
|
125
|
-
<p>A lone <code dir="auto">single-repo</code> is one coverage column named by the directory name. A lone <code dir="auto">monorepo</code> has one coverage column per workspace package, named by the package’s repo-relative path (<code dir="auto">packages/engine</code>), with no member prefix. Every lone-repository column, and the canonical <code dir="auto">spec-engine</code> row itself, is pinned to the derived platform version, so a repository is never reported drifted against its own working-tree domains. A nested <code dir="auto">spec-engine.member.json</code> inside a package still overrides that package’s pin. <!-- @spec INIT-028 --></p>
|
|
126
|
-
<p>This repository is a lone <code dir="auto">monorepo</code>. Its coverage columns are <code dir="auto">packages/engine</code>, <code dir="auto">packages/shared</code>, <code dir="auto">packages/site</code>, <code dir="auto">packages/tracker</code>, <code dir="auto">packages/webapp</code>, and <code dir="auto">scripts</code>, each a workspace package of the root <code dir="auto">package.json</code
|
|
126
|
+
<p>A lone <code dir="auto">single-repo</code> is one coverage column named by the directory name. A lone <code dir="auto">monorepo</code> has one coverage column per workspace package, named by the package’s repo-relative path (<code dir="auto">packages/engine</code>), with no member prefix, plus one column named by the directory for its files outside every package. Every lone-repository column, and the canonical <code dir="auto">spec-engine</code> row itself, is pinned to the derived platform version, so a repository is never reported drifted against its own working-tree domains. A nested <code dir="auto">spec-engine.member.json</code> inside a package still overrides that package’s pin. <!-- @spec INIT-028 --></p>
|
|
127
|
+
<p>This repository is a lone <code dir="auto">monorepo</code>. Its coverage columns are <code dir="auto">packages/engine</code>, <code dir="auto">packages/shared</code>, <code dir="auto">packages/site</code>, <code dir="auto">packages/tracker</code>, <code dir="auto">packages/webapp</code>, and <code dir="auto">scripts</code>, each a workspace package of the root <code dir="auto">package.json</code>. It has no root column: a checkout directory named <code dir="auto">spec-engine</code> would collide with the canonical <code dir="auto">spec-engine</code> row, the same limitation a lone single repository of that name has.</p>
|
|
127
128
|
<div class="sl-heading-wrapper level-h2"><h2 id="names">Names</h2><a class="sl-anchor-link" href="#names"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Names”</span></a></div>
|
|
128
129
|
<p>One name serves everywhere. For a declared member it is the member name from the platform file. For a package it is the member name and the package path joined by <code dir="auto">/</code>, or the bare package path in a lone monorepo. That same string is:</p>
|
|
129
130
|
<ul>
|
|
@@ -256,6 +257,6 @@
|
|
|
256
257
|
<p><code dir="auto">spec check . --ci</code> runs platform-map’s own check underneath, so one gate fails when a requirement, a tag, a pin, or the platform declaration is broken.</p>
|
|
257
258
|
<div class="sl-heading-wrapper level-h2"><h2 id="propagation-order-dependson">Propagation order: <code dir="auto">dependsOn</code></h2><a class="sl-anchor-link" href="#propagation-order-dependson"><span aria-hidden="true" class="sl-anchor-icon"><svg width="16" height="16" viewBox="0 0 24 24"><path fill="currentcolor" d="m12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z"></path></svg></span><span class="sr-only" data-pagefind-ignore="">Section titled “Propagation order: dependsOn”</span></a></div>
|
|
258
259
|
<p>Every repo and package in the map carries <code dir="auto">dependsOn</code>, the platform’s own package names its manifest depends on, matched within one ecosystem. Spec Engine reads it as the order in which a superseded requirement propagates: a consumer can only move to the successor after the packages it depends on ship it. <code dir="auto">spec propagation</code>, <code dir="auto">/api/propagation/:id</code>, <code dir="auto">spec_propagation</code>, and the webapp’s propagation page list members in dependency order, a member after every member it depends on, and members at the same depth by name. <!-- @spec PROP-006 --></p>
|
|
259
|
-
<p>The depth is a coverage-column fact, computed at discovery and stored in the derived index. A single-repo member’s node is its map repo; a monorepo member’s package column, and a lone monorepo’s package column, is its map <code dir="auto">Package</code>. A column depends on another column when the other’s <code dir="auto">packageName</code> appears in its <code dir="auto">dependsOn</code>; a name that is no column (a monorepo
|
|
260
|
+
<p>The depth is a coverage-column fact, computed at discovery and stored in the derived index. A single-repo member’s node is its map repo; a monorepo member’s package column, and a lone monorepo’s package column, is its map <code dir="auto">Package</code>. A column depends on another column when the other’s <code dir="auto">packageName</code> appears in its <code dir="auto">dependsOn</code>; a name that is no column (an absent member or package) is no edge; a monorepo’s root column carries its root manifest’s name and dependencies. A column with no dependency is depth 0; every other column is one deeper than its deepest dependency. A dependency cycle, and every column downstream of it, sits at one depth after every column outside it, by name.</p>
|
|
260
261
|
<div class="expressive-code"><figure class="frame not-content"><figcaption class="header"></figcaption><pre data-language="plaintext"><code><div class="ec-line"><div class="code"><span style="--0:#d6deeb;--1:#403f53">$ spec propagation BILLING-002 .</span></div></div><div class="ec-line"><div class="code"><span style="--0:#d6deeb;--1:#403f53">REPO STATE VIA DRIFT?</span></div></div><div class="ec-line"><div class="code"><span style="--0:#d6deeb;--1:#403f53">shared MIGRATED_VERIFIED — no</span></div></div><div class="ec-line"><div class="code"><span style="--0:#d6deeb;--1:#403f53">zed NO_DOMAIN_REFERENCE — no</span></div></div><div class="ec-line"><div class="code"><span style="--0:#d6deeb;--1:#403f53">api ON_PREDECESSOR BILLING-001 no</span></div></div><div class="ec-line"><div class="code"><span style="--0:#d6deeb;--1:#403f53">web MIGRATED_UNVERIFIED — no</span></div></div></code></pre><div class="copy"><div aria-live="polite"></div><button title="Copy to clipboard" data-copied="Copied!" data-code="$ spec propagation BILLING-002 .REPO STATE VIA DRIFT?shared MIGRATED_VERIFIED — nozed NO_DOMAIN_REFERENCE — noapi ON_PREDECESSOR BILLING-001 noweb MIGRATED_UNVERIFIED — no"><div></div></button></div></figure></div>
|
|
261
262
|
<p>Here <code dir="auto">api</code> depends on <code dir="auto">shared</code> and <code dir="auto">web</code> on <code dir="auto">api</code>, so <code dir="auto">api</code> is the member to migrate next. A platform with no in-platform dependencies lists members by name, as before.</p> </div> <footer class="sl-flex astro-5h22m7ac"> <div class="meta sl-flex astro-5h22m7ac"> <a href="https://github.com/spec-engine/spec-engine/edit/main/packages/site/src/content/docs/platform-mapping.md" class="sl-flex print:hidden astro-txs4wy42"><svg aria-hidden="true" class="astro-txs4wy42 astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.2em;"><path d="M22 7.24a1 1 0 0 0-.29-.71l-4.24-4.24a1 1 0 0 0-1.1-.22 1 1 0 0 0-.32.22l-2.83 2.83L2.29 16.05a1 1 0 0 0-.29.71V21a1 1 0 0 0 1 1h4.24a1 1 0 0 0 .76-.29l10.87-10.93L21.71 8c.1-.1.17-.2.22-.33a1 1 0 0 0 0-.24v-.14l.07-.05ZM6.83 20H4v-2.83l9.93-9.93 2.83 2.83L6.83 20ZM18.17 8.66l-2.83-2.83 1.42-1.41 2.82 2.82-1.41 1.42Z"/></svg>Edit page</a> </div> <div class="pagination-links print:hidden astro-7kn6nbmm" dir="ltr"> <a href="/architecture/" rel="prev" class="astro-7kn6nbmm"> <svg aria-hidden="true" class="astro-7kn6nbmm astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17 11H9.41l3.3-3.29a1.004 1.004 0 1 0-1.42-1.42l-5 5a1 1 0 0 0-.21.33 1 1 0 0 0 0 .76 1 1 0 0 0 .21.33l5 5a1.002 1.002 0 0 0 1.639-.325 1 1 0 0 0-.219-1.095L9.41 13H17a1 1 0 0 0 0-2Z"/></svg> <span class="astro-7kn6nbmm"> Previous <br class="astro-7kn6nbmm"> <span class="link-title astro-7kn6nbmm">Architecture</span> </span> </a> <a href="/commands/" rel="next" class="astro-7kn6nbmm"> <svg aria-hidden="true" class="astro-7kn6nbmm astro-lm5mbbcm" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style="--sl-icon-size: 1.5rem;"><path d="M17.92 11.62a1.001 1.001 0 0 0-.21-.33l-5-5a1.003 1.003 0 1 0-1.42 1.42l3.3 3.29H7a1 1 0 0 0 0 2h7.59l-3.3 3.29a1.002 1.002 0 0 0 .325 1.639 1 1 0 0 0 1.095-.219l5-5a1 1 0 0 0 .21-.33 1 1 0 0 0 0-.76Z"/></svg> <span class="astro-7kn6nbmm"> Next <br class="astro-7kn6nbmm"> <span class="link-title astro-7kn6nbmm">Commands</span> </span> </a> </div> </footer> </div> </div> </main> </div> </div> </div> </div> </body></html>
|
package/dist/impl.js
CHANGED
|
@@ -20,7 +20,7 @@ var package_default;
|
|
|
20
20
|
var init_package = __esm(() => {
|
|
21
21
|
package_default = {
|
|
22
22
|
name: "@spec-engine/spec-engine",
|
|
23
|
-
version: "0.
|
|
23
|
+
version: "0.6.0",
|
|
24
24
|
description: "Cross-repo spec engine \u2014 durable requirements with permanent IDs, bound to code via @spec tags, checked in CI. Ships the spec CLI, the local coverage webapp (spec serve), and offline docs (spec docs).",
|
|
25
25
|
license: "MIT",
|
|
26
26
|
type: "module",
|
|
@@ -1274,6 +1274,37 @@ async function packageColumns(repoPath, prefix, repo, parentPin) {
|
|
|
1274
1274
|
}
|
|
1275
1275
|
return out;
|
|
1276
1276
|
}
|
|
1277
|
+
function packageDirs(repo) {
|
|
1278
|
+
const dirs = repo.packages.map((p) => p.path);
|
|
1279
|
+
return dirs.some((d) => d === "" || d === ".") ? null : dirs;
|
|
1280
|
+
}
|
|
1281
|
+
function loneRootColumn(absPlatform, repo, platformVersion) {
|
|
1282
|
+
const dirs = packageDirs(repo);
|
|
1283
|
+
const { dependency_depth: _depth, ...self } = selfMember(absPlatform, platformVersion);
|
|
1284
|
+
if (dirs === null || self.name === CANONICAL_SPECS_DIR)
|
|
1285
|
+
return [];
|
|
1286
|
+
return [{ repo: { ...self, ignore: dirs }, node: repo }];
|
|
1287
|
+
}
|
|
1288
|
+
async function loneMembers(repo, absPlatform, platformVersion) {
|
|
1289
|
+
if (repo === undefined || repo.mode !== "monorepo" || repo.packages.length === 0) {
|
|
1290
|
+
return [selfMember(absPlatform, platformVersion)];
|
|
1291
|
+
}
|
|
1292
|
+
return toRepos([
|
|
1293
|
+
...await packageColumns(absPlatform, "", repo, platformVersion),
|
|
1294
|
+
...loneRootColumn(absPlatform, repo, platformVersion)
|
|
1295
|
+
]);
|
|
1296
|
+
}
|
|
1297
|
+
async function memberColumns(repo, path, cfg) {
|
|
1298
|
+
const pin = extractPin(cfg.specs);
|
|
1299
|
+
if (repo.mode !== "monorepo" || repo.packages.length === 0) {
|
|
1300
|
+
return [column(repo.name, path, pin, repo, cfg.ignore)];
|
|
1301
|
+
}
|
|
1302
|
+
const packages = await packageColumns(path, `${repo.name}/`, repo, pin);
|
|
1303
|
+
const dirs = packageDirs(repo);
|
|
1304
|
+
if (dirs === null)
|
|
1305
|
+
return packages;
|
|
1306
|
+
return [...packages, column(repo.name, path, pin, repo, [...cfg.ignore ?? [], ...dirs])];
|
|
1307
|
+
}
|
|
1277
1308
|
function describe(d, mapped) {
|
|
1278
1309
|
const s = d.subject;
|
|
1279
1310
|
switch (d.code) {
|
|
@@ -1306,8 +1337,7 @@ async function membersOf(reading, absPlatform, platformVersion) {
|
|
|
1306
1337
|
const { mapped, located } = reading;
|
|
1307
1338
|
const diagnostics2 = surfaced(mapped);
|
|
1308
1339
|
if (mapped.mode !== "multi-repo") {
|
|
1309
|
-
const
|
|
1310
|
-
const members = repo !== undefined && repo.mode === "monorepo" && repo.packages.length > 0 ? toRepos(await packageColumns(absPlatform, "", repo, platformVersion)) : [selfMember(absPlatform, platformVersion)];
|
|
1340
|
+
const members = await loneMembers(mapped.repos[0], absPlatform, platformVersion);
|
|
1311
1341
|
return { mode: mapped.mode, members, unpinned: [], undeclared: [], diagnostics: diagnostics2 };
|
|
1312
1342
|
}
|
|
1313
1343
|
if (!mapped.declared) {
|
|
@@ -1325,13 +1355,7 @@ async function membersOf(reading, absPlatform, platformVersion) {
|
|
|
1325
1355
|
unpinned.push({ name: repo.name, path });
|
|
1326
1356
|
continue;
|
|
1327
1357
|
}
|
|
1328
|
-
|
|
1329
|
-
const pin = extractPin(cfg.specs);
|
|
1330
|
-
if (repo.mode === "monorepo" && repo.packages.length > 0) {
|
|
1331
|
-
columns.push(...await packageColumns(path, `${repo.name}/`, repo, pin));
|
|
1332
|
-
} else {
|
|
1333
|
-
columns.push(column(repo.name, path, pin, repo, cfg.ignore));
|
|
1334
|
-
}
|
|
1358
|
+
columns.push(...await memberColumns(repo, path, await readRepoConfig(configPath)));
|
|
1335
1359
|
}
|
|
1336
1360
|
const undeclared = mapped.diagnostics.filter((d) => d.code === "UNLISTED_REPO").map((d) => ({ name: d.subject, path: join3(absPlatform, d.subject) }));
|
|
1337
1361
|
return { mode: "multi-repo", members: toRepos(columns), unpinned, undeclared, diagnostics: diagnostics2 };
|
|
@@ -3314,7 +3338,24 @@ import { resolve as resolve6 } from "path";
|
|
|
3314
3338
|
function resolvePlatformDir(args) {
|
|
3315
3339
|
return resolve6(args.platformDir ?? process.cwd());
|
|
3316
3340
|
}
|
|
3317
|
-
|
|
3341
|
+
function listFlag(rawArgs, name, parsed) {
|
|
3342
|
+
const flag = `--${name}`;
|
|
3343
|
+
const raw = [];
|
|
3344
|
+
for (let i = 0;i < rawArgs.length; i++) {
|
|
3345
|
+
const arg = rawArgs[i];
|
|
3346
|
+
if (arg === flag && i + 1 < rawArgs.length)
|
|
3347
|
+
raw.push(rawArgs[++i]);
|
|
3348
|
+
else if (arg.startsWith(`${flag}=`))
|
|
3349
|
+
raw.push(arg.slice(flag.length + 1));
|
|
3350
|
+
}
|
|
3351
|
+
if (raw.length === 0) {
|
|
3352
|
+
if (parsed === undefined)
|
|
3353
|
+
return;
|
|
3354
|
+
raw.push(parsed);
|
|
3355
|
+
}
|
|
3356
|
+
return raw.flatMap((v) => v.split(",")).map((v) => v.trim()).filter((v) => v !== "");
|
|
3357
|
+
}
|
|
3358
|
+
var platformDirArg, outArg, jsonArg, freshArg, noPromptArg, livesArg;
|
|
3318
3359
|
var init__args = __esm(() => {
|
|
3319
3360
|
init_constants();
|
|
3320
3361
|
platformDirArg = {
|
|
@@ -3335,6 +3376,10 @@ var init__args = __esm(() => {
|
|
|
3335
3376
|
type: "boolean",
|
|
3336
3377
|
description: "Suppress the interactive onboarding prompt for siblings missing spec-engine.member.json (they surface as NO_SPEC_CONFIG warnings)"
|
|
3337
3378
|
};
|
|
3379
|
+
livesArg = {
|
|
3380
|
+
type: "string",
|
|
3381
|
+
description: "Lives in (livesIn) paths: repeat the flag or comma-separate; an empty value clears the list"
|
|
3382
|
+
};
|
|
3338
3383
|
});
|
|
3339
3384
|
|
|
3340
3385
|
// src/commands/index.ts
|
|
@@ -6448,24 +6493,27 @@ __export(exports_req, {
|
|
|
6448
6493
|
});
|
|
6449
6494
|
import { createInterface as createInterface2 } from "readline";
|
|
6450
6495
|
import { defineCommand as defineCommand12 } from "citty";
|
|
6451
|
-
async function mintFromFlags(platformDir, key, textFlag, args) {
|
|
6496
|
+
async function mintFromFlags(platformDir, key, textFlag, args, rawArgs) {
|
|
6452
6497
|
const statement = textFlag.trim();
|
|
6453
6498
|
if (statement === "") {
|
|
6454
6499
|
console.error("spec req: --text must be a non-empty Requirement");
|
|
6455
6500
|
process.exit(EXIT.USAGE);
|
|
6456
6501
|
}
|
|
6457
6502
|
await printResolvedCharter(platformDir, key);
|
|
6458
|
-
const lives = (args.lives ?? "").trim();
|
|
6459
6503
|
await mintAndReport(platformDir, key, {
|
|
6460
6504
|
statement,
|
|
6461
6505
|
why: (args.why ?? "").trim(),
|
|
6462
|
-
livesIn: lives
|
|
6506
|
+
livesIn: listFlag(rawArgs, "lives", args.lives) ?? [],
|
|
6463
6507
|
issue: (args.issue ?? "").trim() || undefined,
|
|
6508
|
+
status: statusOf(args),
|
|
6464
6509
|
json: Boolean(args.json)
|
|
6465
6510
|
});
|
|
6466
6511
|
}
|
|
6467
|
-
|
|
6468
|
-
|
|
6512
|
+
function statusOf(args) {
|
|
6513
|
+
return args.draft ? "draft" : "active";
|
|
6514
|
+
}
|
|
6515
|
+
async function mintInteractively(platformDir, key, id, status) {
|
|
6516
|
+
console.error(`Authoring ${id} \u2014 ${status === "draft" ? "Draft" : "Active"}`);
|
|
6469
6517
|
await printResolvedCharter(platformDir, key);
|
|
6470
6518
|
const requirement = (await askLine("Requirement: ")).trim();
|
|
6471
6519
|
if (requirement === "") {
|
|
@@ -6474,12 +6522,13 @@ async function mintInteractively(platformDir, key, id) {
|
|
|
6474
6522
|
return;
|
|
6475
6523
|
}
|
|
6476
6524
|
const why = (await askLine("Why it matters: ")).trim();
|
|
6477
|
-
const
|
|
6525
|
+
const livesIn = listFlag([], "lives", await askLine("Lives in: ")) ?? [];
|
|
6478
6526
|
await mintAndReport(platformDir, key, {
|
|
6479
6527
|
statement: requirement,
|
|
6480
6528
|
why,
|
|
6481
|
-
livesIn
|
|
6529
|
+
livesIn,
|
|
6482
6530
|
issue: undefined,
|
|
6531
|
+
status,
|
|
6483
6532
|
json: false
|
|
6484
6533
|
});
|
|
6485
6534
|
}
|
|
@@ -6532,10 +6581,14 @@ var init_req = __esm(() => {
|
|
|
6532
6581
|
description: "Non-interactive authoring: the Requirement field. When set, the entry appends with zero prompts."
|
|
6533
6582
|
},
|
|
6534
6583
|
why: { type: "string", description: "Why it matters field (only with --text)" },
|
|
6535
|
-
lives:
|
|
6584
|
+
lives: livesArg,
|
|
6536
6585
|
issue: {
|
|
6537
6586
|
type: "string",
|
|
6538
6587
|
description: "Originating ticket id, recorded as created-provenance on the entry (only with --text; opaque \u2014 never a requirement id)"
|
|
6588
|
+
},
|
|
6589
|
+
draft: {
|
|
6590
|
+
type: "boolean",
|
|
6591
|
+
description: "Author the entry as Draft instead of Active (promote it later with spec accept)"
|
|
6539
6592
|
}
|
|
6540
6593
|
};
|
|
6541
6594
|
reqCommand = defineCommand12({
|
|
@@ -6544,7 +6597,7 @@ var init_req = __esm(() => {
|
|
|
6544
6597
|
description: "Author a new requirement interactively (TTY) or print the next unused id (non-TTY)"
|
|
6545
6598
|
},
|
|
6546
6599
|
args: reqArgs,
|
|
6547
|
-
async run({ args }) {
|
|
6600
|
+
async run({ args, rawArgs }) {
|
|
6548
6601
|
const input = args.domainPrefix;
|
|
6549
6602
|
const platformDir = resolvePlatformDir(args);
|
|
6550
6603
|
try {
|
|
@@ -6558,7 +6611,7 @@ var init_req = __esm(() => {
|
|
|
6558
6611
|
const { key, nextId: id } = allocated;
|
|
6559
6612
|
const textFlag = args.text;
|
|
6560
6613
|
if (textFlag !== undefined) {
|
|
6561
|
-
await mintFromFlags(platformDir, key, textFlag, args);
|
|
6614
|
+
await mintFromFlags(platformDir, key, textFlag, args, rawArgs);
|
|
6562
6615
|
return;
|
|
6563
6616
|
}
|
|
6564
6617
|
const hasFieldFlags = typeof args.why === "string" || typeof args.lives === "string" || typeof args.issue === "string";
|
|
@@ -6567,6 +6620,11 @@ var init_req = __esm(() => {
|
|
|
6567
6620
|
process.exit(EXIT.USAGE);
|
|
6568
6621
|
return;
|
|
6569
6622
|
}
|
|
6623
|
+
if (args.draft && (args.json || !process.stdin.isTTY)) {
|
|
6624
|
+
console.error("spec req: --draft authors an entry \u2014 pass --text, or run on a TTY");
|
|
6625
|
+
process.exit(EXIT.USAGE);
|
|
6626
|
+
return;
|
|
6627
|
+
}
|
|
6570
6628
|
if (args.json) {
|
|
6571
6629
|
console.log(JSON.stringify({ domain: key, next_id: id }));
|
|
6572
6630
|
return;
|
|
@@ -6575,7 +6633,7 @@ var init_req = __esm(() => {
|
|
|
6575
6633
|
console.log(id);
|
|
6576
6634
|
return;
|
|
6577
6635
|
}
|
|
6578
|
-
await mintInteractively(platformDir, key, id);
|
|
6636
|
+
await mintInteractively(platformDir, key, id, statusOf(args));
|
|
6579
6637
|
}
|
|
6580
6638
|
});
|
|
6581
6639
|
});
|
|
@@ -7122,14 +7180,13 @@ async function resolveSuccessorText(args, platformDir, id) {
|
|
|
7122
7180
|
function splitAliases(raw) {
|
|
7123
7181
|
return raw.split(",").map((s) => s.trim()).filter((s) => s !== "");
|
|
7124
7182
|
}
|
|
7125
|
-
function inputFromArgs(args, platformDir, id, statement) {
|
|
7183
|
+
function inputFromArgs(args, rawArgs, platformDir, id, statement) {
|
|
7126
7184
|
const input = { platformDir, id, statement, noBump: Boolean(args.noBump) };
|
|
7127
7185
|
if (typeof args.why === "string")
|
|
7128
7186
|
input.why = args.why;
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
input.livesIn =
|
|
7132
|
-
}
|
|
7187
|
+
const livesIn = listFlag(rawArgs, "lives", args.lives);
|
|
7188
|
+
if (livesIn !== undefined)
|
|
7189
|
+
input.livesIn = livesIn;
|
|
7133
7190
|
if (typeof args.term === "string")
|
|
7134
7191
|
input.term = args.term;
|
|
7135
7192
|
if (typeof args.aliases === "string")
|
|
@@ -7166,7 +7223,7 @@ var init_supersede2 = __esm(() => {
|
|
|
7166
7223
|
},
|
|
7167
7224
|
lives: {
|
|
7168
7225
|
type: "string",
|
|
7169
|
-
description: "Successor's Lives in (default: copied from the old entry)"
|
|
7226
|
+
description: "Successor's Lives in: repeat or comma-separate; empty clears (default: copied from the old entry)"
|
|
7170
7227
|
},
|
|
7171
7228
|
term: {
|
|
7172
7229
|
type: "string",
|
|
@@ -7195,7 +7252,7 @@ var init_supersede2 = __esm(() => {
|
|
|
7195
7252
|
description: "Supersede a shipped requirement: flip it to superseded, mint the successor, bump specVersion, and emit the retag worklist."
|
|
7196
7253
|
},
|
|
7197
7254
|
args: supersedeArgs,
|
|
7198
|
-
async run({ args }) {
|
|
7255
|
+
async run({ args, rawArgs }) {
|
|
7199
7256
|
const id = args.id;
|
|
7200
7257
|
if (!ID_RE.test(id)) {
|
|
7201
7258
|
console.error(`spec supersede: id must be a requirement id (KEY-NNN); got ${id}`);
|
|
@@ -7208,7 +7265,7 @@ var init_supersede2 = __esm(() => {
|
|
|
7208
7265
|
handleNotAPlatform(e);
|
|
7209
7266
|
}
|
|
7210
7267
|
const statement = await resolveSuccessorText(args, platformDir, id);
|
|
7211
|
-
const result = await supersede(inputFromArgs(args, platformDir, id, statement), coldFreshTags(platformDir));
|
|
7268
|
+
const result = await supersede(inputFromArgs(args, rawArgs, platformDir, id, statement), coldFreshTags(platformDir));
|
|
7212
7269
|
if (!result.ok)
|
|
7213
7270
|
exitOnFailure("spec supersede", result);
|
|
7214
7271
|
printWarnings("spec supersede", result.warnings);
|
|
@@ -7454,16 +7511,15 @@ __export(exports_move, {
|
|
|
7454
7511
|
moveCommand: () => moveCommand
|
|
7455
7512
|
});
|
|
7456
7513
|
import { defineCommand as defineCommand17 } from "citty";
|
|
7457
|
-
function inputFromArgs2(args, platformDir, id, targetKey) {
|
|
7514
|
+
function inputFromArgs2(args, rawArgs, platformDir, id, targetKey) {
|
|
7458
7515
|
const input = { platformDir, id, targetKey, noBump: Boolean(args.noBump) };
|
|
7459
7516
|
if (typeof args.text === "string")
|
|
7460
7517
|
input.statement = args.text;
|
|
7461
7518
|
if (typeof args.why === "string")
|
|
7462
7519
|
input.why = args.why;
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
input.livesIn =
|
|
7466
|
-
}
|
|
7520
|
+
const livesIn = listFlag(rawArgs, "lives", args.lives);
|
|
7521
|
+
if (livesIn !== undefined)
|
|
7522
|
+
input.livesIn = livesIn;
|
|
7467
7523
|
return input;
|
|
7468
7524
|
}
|
|
7469
7525
|
var moveArgs, moveCommand;
|
|
@@ -7498,7 +7554,7 @@ var init_move2 = __esm(() => {
|
|
|
7498
7554
|
},
|
|
7499
7555
|
lives: {
|
|
7500
7556
|
type: "string",
|
|
7501
|
-
description: "Rewrite the successor's Lives in (default: copied from the source)"
|
|
7557
|
+
description: "Rewrite the successor's Lives in: repeat or comma-separate; empty clears (default: copied from the source)"
|
|
7502
7558
|
},
|
|
7503
7559
|
noBump: {
|
|
7504
7560
|
type: "boolean",
|
|
@@ -7515,7 +7571,7 @@ var init_move2 = __esm(() => {
|
|
|
7515
7571
|
description: "Move a requirement to another domain: mint the successor in <NEW-DOMAIN> carrying the source's fields, mark the source superseded, bump both specVersions, and emit the retag worklist."
|
|
7516
7572
|
},
|
|
7517
7573
|
args: moveArgs,
|
|
7518
|
-
async run({ args }) {
|
|
7574
|
+
async run({ args, rawArgs }) {
|
|
7519
7575
|
const id = args.id;
|
|
7520
7576
|
const rawTargetKey = args.newDomain;
|
|
7521
7577
|
const platformDir = resolvePlatformDir(args);
|
|
@@ -7533,7 +7589,7 @@ var init_move2 = __esm(() => {
|
|
|
7533
7589
|
} catch (e) {
|
|
7534
7590
|
handleNotAPlatform(e);
|
|
7535
7591
|
}
|
|
7536
|
-
const result = await move(inputFromArgs2(args, platformDir, id, targetKey), coldFreshTags(platformDir));
|
|
7592
|
+
const result = await move(inputFromArgs2(args, rawArgs, platformDir, id, targetKey), coldFreshTags(platformDir));
|
|
7537
7593
|
if (!result.ok)
|
|
7538
7594
|
exitOnFailure("spec move", result);
|
|
7539
7595
|
printWarnings("spec move", result.warnings);
|
|
@@ -7679,7 +7735,7 @@ function assertAmendFlags(args) {
|
|
|
7679
7735
|
function splitAliases2(raw) {
|
|
7680
7736
|
return raw === "" ? [] : raw.split(",").map((s) => s.trim()).filter((s) => s !== "");
|
|
7681
7737
|
}
|
|
7682
|
-
function fieldsFromArgs(args) {
|
|
7738
|
+
function fieldsFromArgs(args, rawArgs) {
|
|
7683
7739
|
assertAmendFlags(args);
|
|
7684
7740
|
const fields = {};
|
|
7685
7741
|
if (args.text !== undefined)
|
|
@@ -7688,10 +7744,9 @@ function fieldsFromArgs(args) {
|
|
|
7688
7744
|
const v = args.why.trim();
|
|
7689
7745
|
fields.why = v === "" ? null : v;
|
|
7690
7746
|
}
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
fields.livesIn =
|
|
7694
|
-
}
|
|
7747
|
+
const livesIn = listFlag(rawArgs, "lives", args.lives);
|
|
7748
|
+
if (livesIn !== undefined)
|
|
7749
|
+
fields.livesIn = livesIn;
|
|
7695
7750
|
if (args.term !== undefined)
|
|
7696
7751
|
fields.term = args.term.trim();
|
|
7697
7752
|
if (args.issue !== undefined && args.issue.trim() !== "")
|
|
@@ -7718,7 +7773,7 @@ var init_amend2 = __esm(() => {
|
|
|
7718
7773
|
platformDir: platformDirArg,
|
|
7719
7774
|
text: { type: "string", description: "New Requirement (statement) field value" },
|
|
7720
7775
|
why: { type: "string", description: "New Why it matters field value" },
|
|
7721
|
-
lives:
|
|
7776
|
+
lives: livesArg,
|
|
7722
7777
|
issue: {
|
|
7723
7778
|
type: "string",
|
|
7724
7779
|
description: "Ticket that motivated this amendment \u2014 recorded as amends-via provenance (opaque, never a requirement id)"
|
|
@@ -7736,7 +7791,7 @@ var init_amend2 = __esm(() => {
|
|
|
7736
7791
|
description: "Revise an unshipped requirement's fields in place (same id, no specVersion bump). Supersede shipped truth instead."
|
|
7737
7792
|
},
|
|
7738
7793
|
args: amendArgs,
|
|
7739
|
-
async run({ args }) {
|
|
7794
|
+
async run({ args, rawArgs }) {
|
|
7740
7795
|
const id = args.id;
|
|
7741
7796
|
if (!ID_RE.test(id)) {
|
|
7742
7797
|
console.error(`spec amend: id must be a requirement id (KEY-NNN); got ${id}`);
|
|
@@ -7749,7 +7804,7 @@ var init_amend2 = __esm(() => {
|
|
|
7749
7804
|
} catch (e) {
|
|
7750
7805
|
handleNotAPlatform(e);
|
|
7751
7806
|
}
|
|
7752
|
-
const fields = fieldsFromArgs(args);
|
|
7807
|
+
const fields = fieldsFromArgs(args, rawArgs);
|
|
7753
7808
|
const result = await amend({ platformDir, id, fields }, coldFreshTags(platformDir));
|
|
7754
7809
|
if (!result.ok)
|
|
7755
7810
|
exitOnFailure("spec amend", result);
|
|
@@ -7763,6 +7818,86 @@ var init_amend2 = __esm(() => {
|
|
|
7763
7818
|
});
|
|
7764
7819
|
});
|
|
7765
7820
|
|
|
7821
|
+
// src/operations/accept.ts
|
|
7822
|
+
async function accept(input) {
|
|
7823
|
+
const { platformDir, id } = input;
|
|
7824
|
+
const located = await locateEntry(platformDir, id);
|
|
7825
|
+
if (!located.ok)
|
|
7826
|
+
return located;
|
|
7827
|
+
const { specPath, relFile, domain: domain2, req } = located;
|
|
7828
|
+
if (req.status.toLowerCase() !== "draft") {
|
|
7829
|
+
return fail("conflict", `${id} is ${displayStatus(req.status)} \u2014 only a Draft entry accepts`);
|
|
7830
|
+
}
|
|
7831
|
+
req.status = "active";
|
|
7832
|
+
domain2.updated = localToday();
|
|
7833
|
+
const res = await validateAndWrite(specPath, domain2, relFile);
|
|
7834
|
+
if (!res.ok) {
|
|
7835
|
+
return fail("invalid_domain_file", res.diagnostics.map((d) => d.detail).join(`
|
|
7836
|
+
`), {
|
|
7837
|
+
diagnostics: res.diagnostics
|
|
7838
|
+
});
|
|
7839
|
+
}
|
|
7840
|
+
return { ok: true, id, file: relFile };
|
|
7841
|
+
}
|
|
7842
|
+
var init_accept = __esm(() => {
|
|
7843
|
+
init_src();
|
|
7844
|
+
init__envelope();
|
|
7845
|
+
init__result();
|
|
7846
|
+
});
|
|
7847
|
+
|
|
7848
|
+
// src/commands/accept.ts
|
|
7849
|
+
var exports_accept = {};
|
|
7850
|
+
__export(exports_accept, {
|
|
7851
|
+
acceptCommand: () => acceptCommand
|
|
7852
|
+
});
|
|
7853
|
+
import { defineCommand as defineCommand19 } from "citty";
|
|
7854
|
+
var acceptCommand;
|
|
7855
|
+
var init_accept2 = __esm(() => {
|
|
7856
|
+
init_constants();
|
|
7857
|
+
init_discover();
|
|
7858
|
+
init_accept();
|
|
7859
|
+
init_grammar3();
|
|
7860
|
+
init__args();
|
|
7861
|
+
init__shared();
|
|
7862
|
+
acceptCommand = defineCommand19({
|
|
7863
|
+
meta: {
|
|
7864
|
+
name: "accept",
|
|
7865
|
+
description: "Promote a Draft requirement to Active (same id, fields untouched)"
|
|
7866
|
+
},
|
|
7867
|
+
args: {
|
|
7868
|
+
id: {
|
|
7869
|
+
type: "positional",
|
|
7870
|
+
required: true,
|
|
7871
|
+
description: "Draft requirement id to accept (KEY-NNN)"
|
|
7872
|
+
},
|
|
7873
|
+
platformDir: platformDirArg,
|
|
7874
|
+
json: jsonArg
|
|
7875
|
+
},
|
|
7876
|
+
async run({ args }) {
|
|
7877
|
+
const id = args.id;
|
|
7878
|
+
if (!ID_RE.test(id)) {
|
|
7879
|
+
console.error(`spec accept: id must be a requirement id (KEY-NNN); got ${id}`);
|
|
7880
|
+
process.exit(EXIT.USAGE);
|
|
7881
|
+
return;
|
|
7882
|
+
}
|
|
7883
|
+
const platformDir = resolvePlatformDir(args);
|
|
7884
|
+
try {
|
|
7885
|
+
assertSpecPlatform(platformDir);
|
|
7886
|
+
} catch (e) {
|
|
7887
|
+
handleNotAPlatform(e);
|
|
7888
|
+
}
|
|
7889
|
+
const result = await accept({ platformDir, id });
|
|
7890
|
+
if (!result.ok)
|
|
7891
|
+
exitOnFailure("spec accept", result);
|
|
7892
|
+
if (args.json) {
|
|
7893
|
+
console.log(JSON.stringify({ id, file: result.file }));
|
|
7894
|
+
return;
|
|
7895
|
+
}
|
|
7896
|
+
console.log(`accepted ${id} in ${result.file} \u2014 now Active`);
|
|
7897
|
+
}
|
|
7898
|
+
});
|
|
7899
|
+
});
|
|
7900
|
+
|
|
7766
7901
|
// src/server/authorPrompt.ts
|
|
7767
7902
|
function renderAuthorPrompt(opts) {
|
|
7768
7903
|
const charterBlock = opts.charter ? `
|
|
@@ -7938,6 +8073,19 @@ function buildMcpServer(platformDir) {
|
|
|
7938
8073
|
const r = await deprecate({ platformDir, id: req_id, reason: trimmed }, coldFreshTags(platformDir));
|
|
7939
8074
|
return r.ok ? jsonResult({ id: r.id, file: r.file, reason: r.reason, sites: r.sites }) : errorResult(r.detail);
|
|
7940
8075
|
});
|
|
8076
|
+
server.registerTool("spec_accept", {
|
|
8077
|
+
title: "Accept a draft requirement",
|
|
8078
|
+
description: "Promote a Draft requirement to Active, leaving every other field untouched. The same JSON as `spec accept --json`.",
|
|
8079
|
+
inputSchema: {
|
|
8080
|
+
req_id: z3.string().describe("The Draft requirement id to accept (KEY-NNN)")
|
|
8081
|
+
}
|
|
8082
|
+
}, async ({ req_id }) => {
|
|
8083
|
+
if (!ID_RE.test(req_id)) {
|
|
8084
|
+
return errorResult(`req_id must be a requirement id (KEY-NNN); got ${req_id}`);
|
|
8085
|
+
}
|
|
8086
|
+
const r = await accept({ platformDir, id: req_id });
|
|
8087
|
+
return r.ok ? jsonResult({ id: r.id, file: r.file }) : errorResult(r.detail);
|
|
8088
|
+
});
|
|
7941
8089
|
server.registerPrompt("author_requirements", {
|
|
7942
8090
|
title: "Author requirements from a brief",
|
|
7943
8091
|
description: "Turn a vague brief/ticket into well-formed Spec Engine requirements: one requirement per testable promise, placed by domain charter, deduped via spec query, drafted to the GUARD template + cold-read rubric, minted with spec req. The engine returns a static playbook template \u2014 your model runs it.",
|
|
@@ -7972,6 +8120,7 @@ var init_mcp = __esm(() => {
|
|
|
7972
8120
|
init_src();
|
|
7973
8121
|
init_domains();
|
|
7974
8122
|
init__index();
|
|
8123
|
+
init_accept();
|
|
7975
8124
|
init_check();
|
|
7976
8125
|
init_deprecate();
|
|
7977
8126
|
init_nextId();
|
|
@@ -7987,14 +8136,14 @@ __export(exports_mcp, {
|
|
|
7987
8136
|
mcpCommand: () => mcpCommand
|
|
7988
8137
|
});
|
|
7989
8138
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7990
|
-
import { defineCommand as
|
|
8139
|
+
import { defineCommand as defineCommand20 } from "citty";
|
|
7991
8140
|
var mcpCommand;
|
|
7992
8141
|
var init_mcp2 = __esm(() => {
|
|
7993
8142
|
init_discover();
|
|
7994
8143
|
init_mcp();
|
|
7995
8144
|
init__args();
|
|
7996
8145
|
init__shared();
|
|
7997
|
-
mcpCommand =
|
|
8146
|
+
mcpCommand = defineCommand20({
|
|
7998
8147
|
meta: {
|
|
7999
8148
|
name: "mcp",
|
|
8000
8149
|
description: "Serve Spec Engine as an MCP (Model Context Protocol) server over stdio \u2014 agent-native query/resolve/check/report tools."
|
|
@@ -8023,7 +8172,7 @@ __export(exports_resolve, {
|
|
|
8023
8172
|
});
|
|
8024
8173
|
import { statSync as statSync5 } from "fs";
|
|
8025
8174
|
import { join as join12, relative as relative2, resolve as resolve13, sep as sep3 } from "path";
|
|
8026
|
-
import { defineCommand as
|
|
8175
|
+
import { defineCommand as defineCommand21 } from "citty";
|
|
8027
8176
|
function classifyArg(a) {
|
|
8028
8177
|
if (a.startsWith("--")) {
|
|
8029
8178
|
const eq = a.indexOf("=");
|
|
@@ -8209,7 +8358,7 @@ var init_resolve2 = __esm(() => {
|
|
|
8209
8358
|
description: "Suppress interactive onboarding prompt for siblings missing spec-engine.member.json (defaults to NO_SPEC_CONFIG warning)"
|
|
8210
8359
|
}
|
|
8211
8360
|
};
|
|
8212
|
-
resolveCommand =
|
|
8361
|
+
resolveCommand = defineCommand21({
|
|
8213
8362
|
meta: {
|
|
8214
8363
|
name: "resolve",
|
|
8215
8364
|
description: "Return the requirements tagged in the given files (RSLV-01). Accepts multiple positional file paths (e.g. `spec resolve api/src/renew.ts api/src/charge.ts`) and a comma-split fallback inside a single positional (`spec resolve a.ts,b.ts`). Paths may be platform-relative or absolute under the platform tree."
|
|
@@ -8374,7 +8523,7 @@ __export(exports_gate, {
|
|
|
8374
8523
|
});
|
|
8375
8524
|
import { existsSync as existsSync12 } from "fs";
|
|
8376
8525
|
import { join as join13 } from "path";
|
|
8377
|
-
import { defineCommand as
|
|
8526
|
+
import { defineCommand as defineCommand22 } from "citty";
|
|
8378
8527
|
function isEpipe(e) {
|
|
8379
8528
|
if (e === null || typeof e !== "object" || !("code" in e))
|
|
8380
8529
|
return false;
|
|
@@ -8437,7 +8586,7 @@ var init_gate2 = __esm(() => {
|
|
|
8437
8586
|
description: "Suppress interactive onboarding prompt for siblings missing spec-engine.member.json (defaults to NO_SPEC_CONFIG warning)"
|
|
8438
8587
|
}
|
|
8439
8588
|
};
|
|
8440
|
-
gateCommand =
|
|
8589
|
+
gateCommand = defineCommand22({
|
|
8441
8590
|
meta: {
|
|
8442
8591
|
name: "gate",
|
|
8443
8592
|
description: "Rung-3 approval primitive: passes iff <reqId> is Active and <repo>'s pinned spec_version covers its changed_at_version. Exits 0 PASS / 1 any gate failure / 2 crash or bad args."
|
|
@@ -8759,14 +8908,14 @@ var exports_guard = {};
|
|
|
8759
8908
|
__export(exports_guard, {
|
|
8760
8909
|
guardCommand: () => guardCommand
|
|
8761
8910
|
});
|
|
8762
|
-
import { defineCommand as
|
|
8911
|
+
import { defineCommand as defineCommand23 } from "citty";
|
|
8763
8912
|
var guardCommand;
|
|
8764
8913
|
var init_guard2 = __esm(() => {
|
|
8765
8914
|
init_constants();
|
|
8766
8915
|
init_guard();
|
|
8767
8916
|
init__args();
|
|
8768
8917
|
init__shared();
|
|
8769
|
-
guardCommand =
|
|
8918
|
+
guardCommand = defineCommand23({
|
|
8770
8919
|
meta: {
|
|
8771
8920
|
name: "guard",
|
|
8772
8921
|
description: "Loss detection: diff the requirement derivation at a git ref (default HEAD) against the working tree and block requirements about to be steamrolled."
|
|
@@ -11730,6 +11879,15 @@ function toLivesIn(v) {
|
|
|
11730
11879
|
return [v];
|
|
11731
11880
|
return [];
|
|
11732
11881
|
}
|
|
11882
|
+
function mintFieldsFromBody(body) {
|
|
11883
|
+
return {
|
|
11884
|
+
statement: typeof body.statement === "string" ? body.statement : "",
|
|
11885
|
+
why: typeof body.why === "string" ? body.why : "",
|
|
11886
|
+
livesIn: toLivesIn(body.livesIn),
|
|
11887
|
+
issue: typeof body.issue === "string" && body.issue.trim() !== "" ? body.issue.trim() : undefined,
|
|
11888
|
+
status: body.status === "draft" ? "draft" : "active"
|
|
11889
|
+
};
|
|
11890
|
+
}
|
|
11733
11891
|
function amendFieldsFromBody(body) {
|
|
11734
11892
|
const fields = {};
|
|
11735
11893
|
if (typeof body.statement === "string")
|
|
@@ -11814,14 +11972,7 @@ function mountApi(app, storage2, platformDir = process.cwd()) {
|
|
|
11814
11972
|
return c.json({ error: "unknown domain key" }, 400);
|
|
11815
11973
|
}
|
|
11816
11974
|
return withWriteLock(async () => {
|
|
11817
|
-
const r = await mint({
|
|
11818
|
-
platformDir,
|
|
11819
|
-
key,
|
|
11820
|
-
statement: typeof body.statement === "string" ? body.statement : "",
|
|
11821
|
-
why: typeof body.why === "string" ? body.why : "",
|
|
11822
|
-
livesIn: toLivesIn(body.livesIn),
|
|
11823
|
-
issue: typeof body.issue === "string" && body.issue.trim() !== "" ? body.issue.trim() : undefined
|
|
11824
|
-
});
|
|
11975
|
+
const r = await mint({ platformDir, key, ...mintFieldsFromBody(body) });
|
|
11825
11976
|
if (!r.ok)
|
|
11826
11977
|
return failureResponse(c, r);
|
|
11827
11978
|
await runIndex({ platformDir, storage: storage2 });
|
|
@@ -11932,6 +12083,30 @@ function mountApi(app, storage2, platformDir = process.cwd()) {
|
|
|
11932
12083
|
return c.json({ ok: true, id: r.id, file: r.file, reason: r.reason, sites: r.sites }, 200);
|
|
11933
12084
|
});
|
|
11934
12085
|
}));
|
|
12086
|
+
app.post("/api/requirements/:id/accept", guarded(async function acceptRequirement(c) {
|
|
12087
|
+
if (!featureEnabled("editor")) {
|
|
12088
|
+
return c.json({ error: featureDisabledMessage("editor") }, 404);
|
|
12089
|
+
}
|
|
12090
|
+
const originReject = rejectCrossOrigin(c);
|
|
12091
|
+
if (originReject)
|
|
12092
|
+
return originReject;
|
|
12093
|
+
const headerReject = rejectBadWriteHeaders(c);
|
|
12094
|
+
if (headerReject)
|
|
12095
|
+
return headerReject;
|
|
12096
|
+
const parsed = await readJsonBody(c);
|
|
12097
|
+
if (!parsed.ok)
|
|
12098
|
+
return parsed.res;
|
|
12099
|
+
const id = c.req.param("id") ?? "";
|
|
12100
|
+
if (!ID_RE.test(id))
|
|
12101
|
+
return c.json({ error: "id must be a requirement id (KEY-NNN)" }, 400);
|
|
12102
|
+
return withWriteLock(async () => {
|
|
12103
|
+
const r = await accept({ platformDir, id });
|
|
12104
|
+
if (!r.ok)
|
|
12105
|
+
return failureResponse(c, r);
|
|
12106
|
+
await runIndex({ platformDir, storage: storage2 });
|
|
12107
|
+
return c.json({ ok: true, id: r.id, file: r.file }, 200);
|
|
12108
|
+
});
|
|
12109
|
+
}));
|
|
11935
12110
|
app.get("/api/propagation/:id", guarded((c) => c.json(propagation2(storage2, c.req.param("id") ?? "").rows)));
|
|
11936
12111
|
app.get("/api/query", guarded((c) => {
|
|
11937
12112
|
if (!featureEnabled("query")) {
|
|
@@ -12012,6 +12187,7 @@ var init_api = __esm(() => {
|
|
|
12012
12187
|
init_discover();
|
|
12013
12188
|
init_pipeline();
|
|
12014
12189
|
init__result();
|
|
12190
|
+
init_accept();
|
|
12015
12191
|
init_amend();
|
|
12016
12192
|
init_deprecate();
|
|
12017
12193
|
init_mint();
|
|
@@ -12033,7 +12209,7 @@ __export(exports_serve, {
|
|
|
12033
12209
|
});
|
|
12034
12210
|
import { existsSync as existsSync13, mkdirSync as mkdirSync6 } from "fs";
|
|
12035
12211
|
import { dirname as dirname8 } from "path";
|
|
12036
|
-
import { defineCommand as
|
|
12212
|
+
import { defineCommand as defineCommand24 } from "citty";
|
|
12037
12213
|
import { Hono as Hono2 } from "hono";
|
|
12038
12214
|
function composeServeApp(storage2, platformDir = process.cwd()) {
|
|
12039
12215
|
const app = new Hono2;
|
|
@@ -12082,7 +12258,7 @@ var init_serve = __esm(() => {
|
|
|
12082
12258
|
init_sqlite();
|
|
12083
12259
|
init__args();
|
|
12084
12260
|
init__shared();
|
|
12085
|
-
serveCommand =
|
|
12261
|
+
serveCommand = defineCommand24({
|
|
12086
12262
|
meta: {
|
|
12087
12263
|
name: "serve",
|
|
12088
12264
|
description: "Run the local webapp. Binds 127.0.0.1 on --port (loopback only \u2014 no --host). --probe is the SERV-04 asset-embedding smoke."
|
|
@@ -12185,7 +12361,7 @@ __export(exports_docs, {
|
|
|
12185
12361
|
import { existsSync as existsSync14, statSync as statSync6 } from "fs";
|
|
12186
12362
|
import { join as join15, normalize, sep as sep4 } from "path";
|
|
12187
12363
|
import { fileURLToPath } from "url";
|
|
12188
|
-
import { defineCommand as
|
|
12364
|
+
import { defineCommand as defineCommand25 } from "citty";
|
|
12189
12365
|
function resolveDocsRootFrom(candidates) {
|
|
12190
12366
|
for (const candidate of candidates) {
|
|
12191
12367
|
if (existsSync14(join15(candidate, "index.html")))
|
|
@@ -12263,7 +12439,7 @@ function exitNoDocsRoot() {
|
|
|
12263
12439
|
var docsCommand;
|
|
12264
12440
|
var init_docs2 = __esm(() => {
|
|
12265
12441
|
init_constants();
|
|
12266
|
-
docsCommand =
|
|
12442
|
+
docsCommand = defineCommand25({
|
|
12267
12443
|
meta: {
|
|
12268
12444
|
name: "docs",
|
|
12269
12445
|
description: "Serve the bundled documentation site offline. Binds 127.0.0.1 on --port (loopback only \u2014 no --host). --probe is the boot-and-fetch smoke."
|
|
@@ -12324,10 +12500,10 @@ __export(exports___smoke, {
|
|
|
12324
12500
|
schemaSmokeCommand: () => schemaSmokeCommand,
|
|
12325
12501
|
schemaMismatchSmokeCommand: () => schemaMismatchSmokeCommand
|
|
12326
12502
|
});
|
|
12327
|
-
import { defineCommand as
|
|
12503
|
+
import { defineCommand as defineCommand26 } from "citty";
|
|
12328
12504
|
var schemaSmokeCommand, schemaMismatchSmokeCommand;
|
|
12329
12505
|
var init___smoke = __esm(() => {
|
|
12330
|
-
schemaSmokeCommand =
|
|
12506
|
+
schemaSmokeCommand = defineCommand26({
|
|
12331
12507
|
meta: {
|
|
12332
12508
|
name: "__schema-smoke",
|
|
12333
12509
|
description: "(hidden CI) open a fresh DB, exec DDL, assert the schema shape",
|
|
@@ -12370,7 +12546,7 @@ var init___smoke = __esm(() => {
|
|
|
12370
12546
|
console.log("__schema-smoke OK");
|
|
12371
12547
|
}
|
|
12372
12548
|
});
|
|
12373
|
-
schemaMismatchSmokeCommand =
|
|
12549
|
+
schemaMismatchSmokeCommand = defineCommand26({
|
|
12374
12550
|
meta: {
|
|
12375
12551
|
name: "__schema-mismatch-smoke",
|
|
12376
12552
|
description: "(hidden CI) corrupt _schema_version, re-open, assert silent rebuild",
|
|
@@ -12396,8 +12572,8 @@ var init___smoke = __esm(() => {
|
|
|
12396
12572
|
|
|
12397
12573
|
// src/cli.ts
|
|
12398
12574
|
init_package();
|
|
12399
|
-
import { defineCommand as
|
|
12400
|
-
var main =
|
|
12575
|
+
import { defineCommand as defineCommand27, runMain, showUsage } from "citty";
|
|
12576
|
+
var main = defineCommand27({
|
|
12401
12577
|
meta: {
|
|
12402
12578
|
name: "spec",
|
|
12403
12579
|
version: package_default.version,
|
|
@@ -12422,6 +12598,7 @@ var main = defineCommand26({
|
|
|
12422
12598
|
deprecate: () => Promise.resolve().then(() => (init_deprecate2(), exports_deprecate)).then((m) => m.deprecateCommand),
|
|
12423
12599
|
move: () => Promise.resolve().then(() => (init_move2(), exports_move)).then((m) => m.moveCommand),
|
|
12424
12600
|
amend: () => Promise.resolve().then(() => (init_amend2(), exports_amend)).then((m) => m.amendCommand),
|
|
12601
|
+
accept: () => Promise.resolve().then(() => (init_accept2(), exports_accept)).then((m) => m.acceptCommand),
|
|
12425
12602
|
mcp: () => Promise.resolve().then(() => (init_mcp2(), exports_mcp)).then((m) => m.mcpCommand),
|
|
12426
12603
|
resolve: () => Promise.resolve().then(() => (init_resolve2(), exports_resolve)).then((m) => m.resolveCommand),
|
|
12427
12604
|
gate: () => Promise.resolve().then(() => (init_gate2(), exports_gate)).then((m) => m.gateCommand),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spec-engine/spec-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Cross-repo spec engine — durable requirements with permanent IDs, bound to code via @spec tags, checked in CI. Ships the spec CLI, the local coverage webapp (spec serve), and offline docs (spec docs).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|