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:
2026-10-20 12:02:31 +05:30
parent 406affcfcf
commit d7c344c9aa
44 changed files with 3251 additions and 94 deletions

View File

@@ -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>&lt;repo&gt;/.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>&lt;repo&gt;/.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 &amp;&amp; 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 &amp; 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 &amp; 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>