feat: full-stack MCP surface — client template, npm CI, 13 repos
- build.py: vendor templates/client into mcp/templates/client with client.json manifest (16 kinds); register drone-npm as a third CI shape (types: pypi/npm/docker); root *.py stale doc numbers fixed - registry.py: registry://client resource + list_client_components / get_client_component / get_client_template tools; build prompt gains the client scaffold step (docs://modules/ui_admin); compliance prompt covers npm packages; drone docs describe all three shapes - repos.json (+mcp): doc-weaver, react-auth, react-openapi (npm Type B, package.json version source), vet (app Type C, VERSION) - docs: 90_drone_pipelines gains Type B npm section; 91_versioning covers package.json as a version source; 94_repository_inventory gains the npm package table and services/apps Type C; lib index updated Verified: bundle regen (24 modules, client 16, drone 3, repos 13); registry client readers exercised against the vendored bundle.
This commit is contained in:
@@ -611,9 +611,18 @@
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#type-b-docker-deployment-service-dockeryaml" class="md-nav__link">
|
||||
<a href="#type-b-npm-package-npm-libyaml" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Type B — Docker deployment (service-docker.yaml)
|
||||
Type B — npm package (npm-lib.yaml)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#type-c-docker-deployment-service-dockeryaml" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Type C — Docker deployment (service-docker.yaml)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -656,7 +665,7 @@
|
||||
<h1 id="drone-pipelines">Drone Pipelines</h1>
|
||||
<h2 id="summary">Summary</h2>
|
||||
<p>Every Aetos repository ships a Drone CI definition at <code>.drone.yml</code>. There is
|
||||
exactly <strong>one standard per repository</strong>, and there are <strong>two types of file</strong>,
|
||||
exactly <strong>one standard per repository</strong>, and there are <strong>three types of file</strong>,
|
||||
chosen by what the repository produces:</p>
|
||||
<table>
|
||||
<thead>
|
||||
@@ -675,23 +684,30 @@ chosen by what the repository produces:</p>
|
||||
<td><code>dagpipe</code>, <code>doc-forge</code>, <code>hexa</code>, <code>mail-intake</code>, <code>mongo-ops</code>, <code>omniread</code>, <code>openapi-first</code>, <code>py-jwt</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>B — Docker deployment</strong></td>
|
||||
<td><strong>B — npm package</strong></td>
|
||||
<td><code>templates/drone/npm-lib.yaml</code></td>
|
||||
<td>A package published to the private npm registry</td>
|
||||
<td><code>doc-weaver</code>, <code>react-auth</code>, <code>react-openapi</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>C — Docker deployment</strong></td>
|
||||
<td><code>templates/drone/service-docker.yaml</code></td>
|
||||
<td>An image pushed to the registry and run as a container</td>
|
||||
<td><code>auth-server</code></td>
|
||||
<td><code>auth-server</code>, <code>vet</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Both templates run on <code>platform: linux / arm64</code> with the workspace at
|
||||
<code>/drone/src</code>. Copy the matching template to <code><repo>/.drone.yml</code>; the Type A file
|
||||
needs no edits, the Type B file needs its placeholders filled in (below).</p>
|
||||
<p>All templates run on <code>platform: linux / arm64</code> with the workspace at
|
||||
<code>/drone/src</code>. Copy the matching template to <code><repo>/.drone.yml</code>; the Type A and
|
||||
Type B files need no edits, the Type C file needs its placeholders filled in
|
||||
(below).</p>
|
||||
<blockquote>
|
||||
<p>Conventions: <code>.drone.yml</code> (not <code>.yaml</code>), one file per repo, secrets injected
|
||||
with <code>from_secret</code> — never commit credentials.</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<h2 id="type-a-pypi-package-python-libyaml">Type A — PyPI package (<code>python-lib.yaml</code>)</h2>
|
||||
<p>For internal libraries. The file contains <strong>two pipelines</strong>:</p>
|
||||
<p>For internal Python libraries. The file contains <strong>two pipelines</strong>:</p>
|
||||
<ol>
|
||||
<li><strong><code>build-and-publish-pypi</code></strong> — triggered on <code>tag</code>:</li>
|
||||
<li><code>check-version</code> — <strong>guard</strong>: fail unless <code>$DRONE_TAG</code> equals the version in
|
||||
@@ -716,7 +732,28 @@ with <code>from_secret</code> — never commit credentials.</p>
|
||||
same file is reused verbatim across every library.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="type-b-docker-deployment-service-dockeryaml">Type B — Docker deployment (<code>service-docker.yaml</code>)</h2>
|
||||
<h2 id="type-b-npm-package-npm-libyaml">Type B — npm package (<code>npm-lib.yaml</code>)</h2>
|
||||
<p>For internal npm libraries (the React packages). One pipeline,
|
||||
<strong><code>build-and-publish-npm</code></strong>, triggered on <code>tag</code>:</p>
|
||||
<ul>
|
||||
<li><code>check-version</code> — <strong>guard</strong>: fail unless <code>$DRONE_TAG</code> equals the version in
|
||||
<code>package.json</code>; query <code>$NPM_REPO_URL</code> for <code>name@version</code>; if it already
|
||||
exists, exit <code>78</code> and skip the whole build.</li>
|
||||
<li><code>quality-gate</code> — write <code>.npmrc</code> from the secrets, <code>npm install</code>, then
|
||||
<code>npm run quality-gate</code>.</li>
|
||||
<li><code>build-package</code> — <code>npm install && npm run build</code> into <code>dist/</code>.</li>
|
||||
<li><code>publish-to-private-npm</code> — <code>npm publish --access restricted</code> to
|
||||
<code>$NPM_REPO_URL</code>.</li>
|
||||
</ul>
|
||||
<p>Secrets: <code>NPM_REPO_URL</code>, <code>NPM_USERNAME</code>, <code>NPM_PASSWORD</code>. Auth is a generated
|
||||
<code>.npmrc</code> (<code>registry=</code> + <code>_auth=</code> base64 of <code>user:pass</code>) written from secrets at
|
||||
runtime — the committed <code>.npmrc</code> in a repo only points at the registry URL.</p>
|
||||
<ul>
|
||||
<li><strong>Ship as-is.</strong> Name and version come from <code>package.json</code>, so the same file
|
||||
is reused verbatim across every npm package.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="type-c-docker-deployment-service-dockeryaml">Type C — Docker deployment (<code>service-docker.yaml</code>)</h2>
|
||||
<p>For a service that ships a container image — a long-running API/worker, e.g.
|
||||
<code>auth-server</code>. The file contains <strong>one pipeline</strong>, <code>build-and-deploy-service</code>,
|
||||
triggered on <code>tag</code>:</p>
|
||||
@@ -774,15 +811,18 @@ triggered on <code>tag</code>:</p>
|
||||
<hr />
|
||||
<h2 id="what-not-to-do">What not to do</h2>
|
||||
<ul>
|
||||
<li>Do not hand-roll a third shape. A repo is either Type A or Type B, never both.</li>
|
||||
<li>Do not hand-roll a fourth shape. A repo is exactly one of Type A, B, or C,
|
||||
never combinations.</li>
|
||||
<li>Do not inline secrets; always use <code>from_secret</code>.</li>
|
||||
<li>Do not drop the <code>check-version</code> / <code>check-remote-image</code> skip — it guards the
|
||||
index and the running container against duplicate publishes.</li>
|
||||
<li>Do not drop the tag↔version guard. A package needs its <code>pyproject.toml</code>
|
||||
version to equal the tag; a service needs a root <code>VERSION</code> file that equals
|
||||
the tag. See <a href="../91_versioning_and_changelog/">91 – Versioning & Changelog</a>.</li>
|
||||
<li>Do not drop the tag↔version guard. A Python package needs its
|
||||
<code>pyproject.toml</code> version to equal the tag; an npm package needs its
|
||||
<code>package.json</code> version; a service needs a root <code>VERSION</code> file. See
|
||||
<a href="../91_versioning_and_changelog/">91 – Versioning & Changelog</a>.</li>
|
||||
<li>Do not rename the pipelines; tooling and runbooks key off
|
||||
<code>build-and-publish-pypi</code> and <code>build-and-deploy-service</code>.</li>
|
||||
<code>build-and-publish-pypi</code>, <code>build-and-publish-npm</code>, and
|
||||
<code>build-and-deploy-service</code>.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="related">Related</h2>
|
||||
|
||||
@@ -725,7 +725,7 @@ The <strong>version file is the source of truth</strong>, the <strong>git tag mu
|
||||
a Drone guard enforces that equality before anything is published. Releases are
|
||||
cut manually; a tag is what triggers the pipeline.</p>
|
||||
<p>This page pairs with <a href="../90_drone_pipelines/">90 – Drone Pipelines</a>: the version
|
||||
and tag contract is exactly what those two CI shapes consume.</p>
|
||||
and tag contract is exactly what those three CI shapes consume.</p>
|
||||
<hr />
|
||||
<h2 id="the-version-contract">The version contract</h2>
|
||||
<table>
|
||||
@@ -743,6 +743,11 @@ and tag contract is exactly what those two CI shapes consume.</p>
|
||||
<td><code>check-version</code> also reads it to skip duplicates</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Library (npm package)</td>
|
||||
<td><code>version</code> in <code>package.json</code></td>
|
||||
<td><code>check-version</code> also queries the registry to skip duplicates</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Service (Docker)</td>
|
||||
<td><code>VERSION</code> file at the repo root</td>
|
||||
<td>one line, <code>x.y.z</code>; the service <strong>reads</strong> it (build-arg) — never hardcode the version</td>
|
||||
@@ -838,7 +843,8 @@ bump travels with the change and only the tag is added afterwards:</p>
|
||||
<li><strong>In the MR</strong> — reconcile <code>[Unreleased]</code> against the change (see
|
||||
<a href="#reconcile-before-releasing">Reconcile before releasing</a>) and get the user's
|
||||
approval for any additions. Then set the intended release version: <code>version</code>
|
||||
in <code>pyproject.toml</code> (or the <code>VERSION</code> file) to <code>x.y.z</code>, and promote the
|
||||
in <code>pyproject.toml</code> or <code>package.json</code> (or the <code>VERSION</code> file) to <code>x.y.z</code>,
|
||||
and promote the
|
||||
changelog (below). Changelog entries and link references name the
|
||||
<strong>version/tag</strong>, never a commit id.</li>
|
||||
<li><strong>Merge or squash</strong> the MR into <code>main</code>.</li>
|
||||
@@ -853,8 +859,10 @@ After the user confirms the MR is merged/squashed and says to proceed:</p>
|
||||
<ol>
|
||||
<li><strong>Wait</strong> for that explicit go-ahead.</li>
|
||||
<li>Find the commit that introduced the version bump:</li>
|
||||
<li>packages:
|
||||
<li>Python packages:
|
||||
<code>git log -S 'version = "x.y.z"' -n 1 --format='%H %s' -- pyproject.toml</code></li>
|
||||
<li>npm packages:
|
||||
<code>git log -S '"version": "x.y.z"' -n 1 --format='%H %s' -- package.json</code></li>
|
||||
<li>services:
|
||||
<code>git log -S 'x.y.z' -n 1 --format='%H %s' -- VERSION</code></li>
|
||||
<li>Confirm that commit's version file equals <code>x.y.z</code>, then tag <strong>only</strong> that
|
||||
@@ -873,13 +881,14 @@ After the user confirms the MR is merged/squashed and says to proceed:</p>
|
||||
on top.</li>
|
||||
<li>In the MR: add the two compare-link references at the bottom of the
|
||||
changelog, naming the version/tag (never a commit id).</li>
|
||||
<li>In the MR: set the version file — <code>pyproject.toml</code> (<code>version = "x.y.z"</code>) or
|
||||
<code>VERSION</code> — to the intended release version.</li>
|
||||
<li>In the MR: set the version file — <code>pyproject.toml</code> (<code>version = "x.y.z"</code>),
|
||||
<code>package.json</code> (<code>"version": "x.y.z"</code>), or <code>VERSION</code> — to the intended
|
||||
release version.</li>
|
||||
<li>Merge or squash the MR into <code>main</code>.</li>
|
||||
<li>Create the tag on the resulting commit: lightweight <code>git tag x.y.z</code>.</li>
|
||||
<li>Push the tag (<code>git push origin x.y.z</code>). Watch Drone: Type A publishes the
|
||||
wheel/sdist, Type B builds and deploys the image; both first assert
|
||||
<code>tag == version</code>.</li>
|
||||
wheel/sdist, Type B publishes the npm package, Type C builds and deploys
|
||||
the image; all three first assert <code>tag == version</code>.</li>
|
||||
<li>Do not reuse the tag if the run fails — fix and cut <code>x.y.(z+1)</code>.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
|
||||
@@ -602,18 +602,27 @@
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#packages-type-a" class="md-nav__link">
|
||||
<a href="#packages-type-a-pypi" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Packages (Type A)
|
||||
Packages (Type A — PyPI)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#services-type-b" class="md-nav__link">
|
||||
<a href="#packages-type-b-npm" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Services (Type B)
|
||||
Packages (Type B — npm)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#services-apps-type-c" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Services & Apps (Type C)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -667,13 +676,13 @@
|
||||
<p>The canonical list of Aetos repositories covered by the CI and versioning
|
||||
standards, with the artifact each one produces, its version source, and its
|
||||
Drone shape. Every entry maps to the contract in
|
||||
<a href="../91_versioning_and_changelog/">91 – Versioning & Changelog</a> and the two CI
|
||||
<a href="../91_versioning_and_changelog/">91 – Versioning & Changelog</a> and the three CI
|
||||
files in <a href="../90_drone_pipelines/">90 – Drone Pipelines</a>.</p>
|
||||
<p>The same data is published machine-readably as the <code>registry://repos</code> MCP
|
||||
resource (and the <code>list_repos</code> tool), sourced from <code>standards/src/repos.json</code>.
|
||||
Paths are relative to the <code>aetos/</code> workspace root.</p>
|
||||
<hr />
|
||||
<h2 id="packages-type-a">Packages (Type A)</h2>
|
||||
<h2 id="packages-type-a-pypi">Packages (Type A — PyPI)</h2>
|
||||
<p>A wheel + sdist published to the private index. Version source is
|
||||
<code>pyproject.toml</code>; Drone file is <code>python-lib.yaml</code> (tag-triggered).</p>
|
||||
<table>
|
||||
@@ -737,7 +746,41 @@ Paths are relative to the <code>aetos/</code> workspace root.</p>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="services-type-b">Services (Type B)</h2>
|
||||
<h2 id="packages-type-b-npm">Packages (Type B — npm)</h2>
|
||||
<p>A package published to the private npm registry (<code>npm.aetoskia.com</code>). Version
|
||||
source is <code>package.json</code>; Drone file is <code>npm-lib.yaml</code> (tag-triggered).</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Repo</th>
|
||||
<th>Path</th>
|
||||
<th>Docs</th>
|
||||
<th>MCP server</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>doc-weaver</code></td>
|
||||
<td><code>doc-weaver</code></td>
|
||||
<td>lib, wiki</td>
|
||||
<td><code>doc-weaver:8010</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>react-auth</code></td>
|
||||
<td><code>react/react-auth</code></td>
|
||||
<td>lib, wiki</td>
|
||||
<td><code>react-auth:8011</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>react-openapi</code></td>
|
||||
<td><code>react/react-openapi</code></td>
|
||||
<td>lib, wiki</td>
|
||||
<td><code>react-openapi:8012</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="services-apps-type-c">Services & Apps (Type C)</h2>
|
||||
<p>A container image pushed to the registry and run on the Docker host. Version
|
||||
source is the <code>VERSION</code> file; Drone file is <code>service-docker.yaml</code>.</p>
|
||||
<table>
|
||||
@@ -745,6 +788,7 @@ source is the <code>VERSION</code> file; Drone file is <code>service-docker.yaml
|
||||
<tr>
|
||||
<th>Repo</th>
|
||||
<th>Path</th>
|
||||
<th>Type</th>
|
||||
<th>Trigger</th>
|
||||
<th>Docs</th>
|
||||
</tr>
|
||||
@@ -753,9 +797,17 @@ source is the <code>VERSION</code> file; Drone file is <code>service-docker.yaml
|
||||
<tr>
|
||||
<td><code>auth-server</code></td>
|
||||
<td><code>auth-server</code></td>
|
||||
<td>service</td>
|
||||
<td>tag</td>
|
||||
<td>api, lib, wiki</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>vet</code></td>
|
||||
<td><code>react/vet</code></td>
|
||||
<td>app</td>
|
||||
<td>tag</td>
|
||||
<td>lib, wiki</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Tag-triggered and enforces <code>tag == VERSION</code>.</p>
|
||||
@@ -772,13 +824,19 @@ source is the <code>VERSION</code> file; Drone file is <code>service-docker.yaml
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>package</td>
|
||||
<td>package (PyPI)</td>
|
||||
<td><code>pyproject.toml</code></td>
|
||||
<td><code>CHANGELOG.md</code></td>
|
||||
<td><code>python-lib.yaml</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>service</td>
|
||||
<td>package (npm)</td>
|
||||
<td><code>package.json</code></td>
|
||||
<td><code>CHANGELOG.md</code></td>
|
||||
<td><code>npm-lib.yaml</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>service / app</td>
|
||||
<td><code>VERSION</code></td>
|
||||
<td><code>CHANGELOG.md</code></td>
|
||||
<td><code>service-docker.yaml</code></td>
|
||||
|
||||
@@ -821,8 +821,8 @@ and an optional pipelines layer.</p>
|
||||
</ul>
|
||||
<h2 id="delivery-meta">Delivery & Meta</h2>
|
||||
<ul>
|
||||
<li><strong>Drone Pipelines</strong> — the two CI shapes: a PyPI/npm package or a Docker
|
||||
deployment.</li>
|
||||
<li><strong>Drone Pipelines</strong> — the three CI shapes: a PyPI package, an npm package,
|
||||
or a Docker deployment.</li>
|
||||
<li><strong>Versioning & Changelog</strong> — SemVer, the tag↔version contract, and the
|
||||
release changelog.</li>
|
||||
<li><strong>Repository Inventory</strong> — every covered repo, its type, version source, and
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Reference in New Issue
Block a user