Triggered on tags matching v*.*.* - runs the quality gate (lint,
typecheck, format:check, the existing test suite, build) as
individual steps for clear failure attribution, then publishes to
this Gitea instance's own npm registry (dev.pivoine.art, unscoped
package name - Gitea's npm registry supports that directly, no
@owner/ rename needed).
The release version comes from the git tag (v1.0.0 -> 1.0.0 via
`npm pkg set`), patched into package.json only in the CI run, never
committed back. publishConfig.registry in package.json is a static
string (safe to commit); the auth token is supplied at publish time
via NODE_AUTH_TOKEN, written to a CI-generated user-level .npmrc by
actions/setup-node's registry-url option rather than a repo-committed
one - pnpm >=10.34.2/11.5.3 (this repo pins 11.21.0) blocks ${VAR}
expansion in repository-controlled npmrc/pnpm-workspace.yaml
specifically to stop a malicious repo from exfiltrating CI secrets
that way, so the token can't live in a committed .npmrc at all.
Verified locally end-to-end short of the actual registry upload:
lint/typecheck/format:check/test/build all pass, and
`pnpm publish --dry-run --no-git-checks` after a temporary version
bump confirms publishConfig.registry resolves to the right URL and
prepack (next build) fires automatically as part of publish.
One-time manual setup this can't do by itself (documented in the plan
file): a repo-scoped Gitea Personal Access Token with the `package`
Read&Write scope, stored as the GITEA_PACKAGE_TOKEN repo secret -
Gitea's own auto-injected GITEA_TOKEN explicitly cannot publish
packages (unimplemented per Gitea's own docs).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Now that the CLI and the Next.js app are one package, nesting it inside
app/ served no purpose - the repo root itself becomes the published
npm package. Merges app/.gitignore and app/README.md into the root
versions, drops the now-duplicate app/LICENSE, and updates path
references (README, docs/ARCHITECTURE.md, docs/CONFIG_REFERENCE.md,
package.json's repository.directory) that assumed the app/ nesting.
Also fixes a real bug this surfaced: the in-app docs viewer resolved
docs/ relative to process.cwd(), which only worked by accident when the
CLI happened to be invoked from app/'s parent directory. A first attempt
at fixing it with import.meta.dirname broke instead, for the same
cross-module-graph reason config-path resolution already documented -
Next compiles Route Handlers through a separate module graph that
doesn't preserve source-relative import.meta paths. Fixed by exposing
the app root via TRIGGERSHELL_APP_ROOT (set once in server.ts, where
import.meta *does* resolve correctly), the same pattern already used
for TRIGGERSHELL_CONFIG_PATH.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>