Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions .agents/skills/netscript-release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
name: netscript-release
description: NetScript release-cut workflow: use the one-shot release:cut command, interpret release gates, publish through GitHub Release/OIDC, verify race-free e2e-cli-prod, and roll back or retry a failed cut.
---

# NetScript Release

Use this skill for release-cut work, release-readiness questions, publish handoffs, rollback, or
debugging the `release:cut` flow. Pair it with `netscript-deno-toolchain` for Deno 2.9 command
semantics and `netscript-pr` for branch, PR, and comment mechanics.

## Prerequisites

- Work from a clean release-prep branch.
- Confirm `deno task release:preflight` is green before cutting. It enforces the JSR-safe bundled
asset rule: publishable source must use text imports or generated string constants, not
`Deno.readTextFile(new URL(..., import.meta.url))` or an identifier assigned from that URL.
- Do not delete `deno.lock`, delete caches, or run `deno cache --reload`.
- Do not publish from a local machine. Publishing stays in GitHub Actions through OIDC.
- Use `gh ... --body-file` for release PR creation and comments.

## One Command

Run the release cut from the repository root:

```bash
deno task release:cut -- <version>
```

Use a semver version newer than the root `deno.json` version, including prereleases such as
`0.0.1-alpha.12`.

For rehearsal:

```bash
deno task release:cut -- <version> --dry-run
```

Dry-run performs the bump, residue check, and gates, then skips branch creation, commit, push, and PR.
Run it in a disposable copy if you do not want the working tree version-bumped after a failed gate.

## What The Command Proves

`release:cut` is fail-fast and ordered:

1. Version validation refuses invalid semver and equal or older versions.
2. Workspace bump sets the root version, every package/plugin `deno.json`, nested workspace
`deno.json` files, and `deno.lock` `@netscript/*` ranges to the new version.
3. Residue check aborts if the old version remains in JSON files or `deno.lock`.
4. `release:preflight` blocks JSR-unsafe import-meta-relative runtime reads.
5. `publish:dry-run` proves the package publish surface builds before the real publish.
6. `deno ci --prod` proves the production dependency graph installs from the locked graph.
7. Non-dry-run creates `release/cut-<version>`, stages only bumped files, commits
`chore(release): cut <version>`, pushes, and opens the release PR.

## Merge And Publish Flow

After the release PR merges:

1. Create and publish GitHub Release `v<version>`.
2. `publish.yml` resolves the release version, runs the release preflight, runs publish dry-run, and
publishes every `@netscript/*` workspace member to JSR through OIDC.
3. On successful publish, `publish.yml` writes `version.txt` and uploads it as
`netscript-published-version-${{ github.run_id }}`.
4. `e2e-cli-prod.yml` runs from `workflow_run` only after `publish` succeeds, downloads that exact
artifact from `github.event.workflow_run.id`, reads the version, installs
`jsr:@netscript/cli@<version>`, and runs the published CLI smoke and scaffold runtime suite.
5. The manual `workflow_dispatch` path still accepts `published-version` for targeted rechecks.

## Rationale

- #122: one command prevents manual root version, member version, and lockfile drift.
- #123: `workflow_run` plus the run-id artifact removes the race where prod E2E installs before JSR
has the just-published CLI version.
- #133: text-import preflight catches the `import.meta.url` asset-read defect class that dry-run can
miss and real publish can reject.
- #146: `deno ci --prod` is already lockfile-frozen in Deno 2.9; an explicit extra flag is rejected.

## Rollback And Retry

- If `release:cut` fails before branch creation, fix the reported gate and rerun. Restore any dry-run
version bump with normal git checkout of the bumped files if you ran it in the live checkout.
- If the release PR is wrong before merge, push a follow-up commit to the release branch or close the
PR and cut again.
- If GitHub Release publish fails before any JSR package publishes, fix the workflow or gate and rerun
the release workflow.
- If publish partially succeeds, do not delete the tag or lockfile. Deno 2.9 skips already-published
members on retry; rerun after fixing the failing member or gate.
- If `e2e-cli-prod` fails after publish, keep the release record intact, investigate against the
exact artifact-provided version, and cut a patch/prerelease follow-up when the fix requires code.
90 changes: 90 additions & 0 deletions .claude/skills/netscript-release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
name: netscript-release
description: NetScript release-cut workflow: use the one-shot release:cut command, interpret release gates, publish through GitHub Release/OIDC, verify race-free e2e-cli-prod, and roll back or retry a failed cut.
---

# NetScript Release

Use this skill for release-cut work, release-readiness questions, publish handoffs, rollback, or
debugging the `release:cut` flow. Pair it with `netscript-deno-toolchain` for Deno 2.9 command
semantics and `netscript-pr` for branch, PR, and comment mechanics.

## Prerequisites

- Work from a clean release-prep branch.
- Confirm `deno task release:preflight` is green before cutting. It enforces the JSR-safe bundled
asset rule: publishable source must use text imports or generated string constants, not
`Deno.readTextFile(new URL(..., import.meta.url))` or an identifier assigned from that URL.
- Do not delete `deno.lock`, delete caches, or run `deno cache --reload`.
- Do not publish from a local machine. Publishing stays in GitHub Actions through OIDC.
- Use `gh ... --body-file` for release PR creation and comments.

## One Command

Run the release cut from the repository root:

```bash
deno task release:cut -- <version>
```

Use a semver version newer than the root `deno.json` version, including prereleases such as
`0.0.1-alpha.12`.

For rehearsal:

```bash
deno task release:cut -- <version> --dry-run
```

Dry-run performs the bump, residue check, and gates, then skips branch creation, commit, push, and PR.
Run it in a disposable copy if you do not want the working tree version-bumped after a failed gate.

## What The Command Proves

`release:cut` is fail-fast and ordered:

1. Version validation refuses invalid semver and equal or older versions.
2. Workspace bump sets the root version, every package/plugin `deno.json`, nested workspace
`deno.json` files, and `deno.lock` `@netscript/*` ranges to the new version.
3. Residue check aborts if the old version remains in JSON files or `deno.lock`.
4. `release:preflight` blocks JSR-unsafe import-meta-relative runtime reads.
5. `publish:dry-run` proves the package publish surface builds before the real publish.
6. `deno ci --prod` proves the production dependency graph installs from the locked graph.
7. Non-dry-run creates `release/cut-<version>`, stages only bumped files, commits
`chore(release): cut <version>`, pushes, and opens the release PR.

## Merge And Publish Flow

After the release PR merges:

1. Create and publish GitHub Release `v<version>`.
2. `publish.yml` resolves the release version, runs the release preflight, runs publish dry-run, and
publishes every `@netscript/*` workspace member to JSR through OIDC.
3. On successful publish, `publish.yml` writes `version.txt` and uploads it as
`netscript-published-version-${{ github.run_id }}`.
4. `e2e-cli-prod.yml` runs from `workflow_run` only after `publish` succeeds, downloads that exact
artifact from `github.event.workflow_run.id`, reads the version, installs
`jsr:@netscript/cli@<version>`, and runs the published CLI smoke and scaffold runtime suite.
5. The manual `workflow_dispatch` path still accepts `published-version` for targeted rechecks.

## Rationale

- #122: one command prevents manual root version, member version, and lockfile drift.
- #123: `workflow_run` plus the run-id artifact removes the race where prod E2E installs before JSR
has the just-published CLI version.
- #133: text-import preflight catches the `import.meta.url` asset-read defect class that dry-run can
miss and real publish can reject.
- #146: `deno ci --prod` is already lockfile-frozen in Deno 2.9; an explicit extra flag is rejected.

## Rollback And Retry

- If `release:cut` fails before branch creation, fix the reported gate and rerun. Restore any dry-run
version bump with normal git checkout of the bumped files if you ran it in the live checkout.
- If the release PR is wrong before merge, push a follow-up commit to the release branch or close the
PR and cut again.
- If GitHub Release publish fails before any JSR package publishes, fix the workflow or gate and rerun
the release workflow.
- If publish partially succeeds, do not delete the tag or lockfile. Deno 2.9 skips already-published
members on retry; rerun after fixing the failing member or gate.
- If `e2e-cli-prod` fails after publish, keep the release record intact, investigate against the
exact artifact-provided version, and cut a patch/prerelease follow-up when the fix requires code.
23 changes: 19 additions & 4 deletions .github/workflows/e2e-cli-prod.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: e2e-cli-prod

on:
release:
types: [published]
workflow_run:
workflows: ["publish"]
types: [completed]
workflow_dispatch:
inputs:
published-version:
Expand All @@ -11,6 +12,7 @@ on:
type: string

permissions:
actions: read
contents: read

concurrency:
Expand All @@ -20,6 +22,7 @@ concurrency:
jobs:
scaffold-runtime-jsr:
name: scaffold-runtime (published JSR CLI)
if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
timeout-minutes: 75
steps:
Expand All @@ -43,13 +46,25 @@ jobs:
dotnet tool install Aspire.Cli --tool-path "$HOME/.aspire/bin" --version "$ASPIRE_CLI_VERSION"
echo "$HOME/.aspire/bin" >> "$GITHUB_PATH"

- name: Download published version
if: github.event_name == 'workflow_run'
uses: actions/download-artifact@v4
with:
name: netscript-published-version-${{ github.event.workflow_run.id }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}
path: .llm/tmp/published-version

- name: Resolve published version
id: version
env:
DISPATCH_VERSION: ${{ github.event.inputs['published-version'] }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
VERSION_FILE: .llm/tmp/published-version/version.txt
run: |
version="${DISPATCH_VERSION:-${RELEASE_TAG#v}}"
version="${DISPATCH_VERSION:-}"
if [ -z "$version" ] && [ -f "$VERSION_FILE" ]; then
version="$(cat "$VERSION_FILE")"
fi
if [ -z "$version" ]; then
echo "A published version is required." >&2
exit 1
Expand Down
15 changes: 15 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ jobs:
JSR_API_TOKEN: ${{ secrets.JSR_TOKEN }}
run: deno run --allow-net --allow-read --allow-env .llm/tools/jsr-provision-packages.ts

- name: Release preflight
run: deno task release:preflight

- name: Publish dry-run
run: deno run --allow-read --allow-write --allow-run .llm/tools/run-publish.ts --dry-run

Expand Down Expand Up @@ -95,6 +98,18 @@ jobs:
if: steps.release.outputs.dry_run != 'true'
run: deno run --allow-read --allow-write --allow-run .llm/tools/run-publish.ts

- name: Write published version
if: steps.release.outputs.dry_run != 'true'
run: printf '%s\n' "${{ steps.release.outputs.version }}" > version.txt

- name: Upload published version
if: steps.release.outputs.dry_run != 'true'
uses: actions/upload-artifact@v4
with:
name: netscript-published-version-${{ github.run_id }}
path: version.txt
if-no-files-found: error

# Master switch for the settings reconciliation below. Reads
# `applyOnPublish` from jsr-package-settings.json (absent => true for
# back-compat). Set it false when the JSR presentation settings are already
Expand Down
7 changes: 7 additions & 0 deletions .llm/tmp/run/chore-release-one-shot--tooling/commits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# commits.md — chore-release-one-shot--tooling

- f07613d5: chore(release): fix prod install args
- d74ba7c2: chore(release): add text import preflight
- 0b2d1aa5: chore(release): add release cut orchestrator
- 307981d8: chore(release): order prod e2e after publish
- e2a6a2f5: docs(release): add release workflow skill
48 changes: 48 additions & 0 deletions .llm/tmp/run/chore-release-one-shot--tooling/context-pack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# context-pack.md — chore-release-one-shot--tooling

## Status

IMPLEMENTATION completed S1-S5 on `chore/release-one-shot` for PR #164. PLAN-EVAL cycle 2 was PASS
before implementation began.

## Commits

- `f07613d5` — S1, `chore(release): fix prod install args`
- `d74ba7c2` — S2, `chore(release): add text import preflight`
- `0b2d1aa5` — S3, `chore(release): add release cut orchestrator`
- `307981d8` — S4, `chore(release): order prod e2e after publish`
- `e2a6a2f5` — S5, `docs(release): add release workflow skill`

## Implemented

- `deps:prod-install` now runs `deno ci --prod` without the Deno 2.9-rejected extra flag, with unit
coverage and toolbelt docs cleaned.
- `release:preflight` scans publishable `@netscript/*` source for import-meta-relative
`Deno.readTextFile` / `Deno.readFile` calls, including cross-line identifier resolution and inline
read calls. Fixtures cover positive, negative, and allowlist cases.
- `release:cut` validates exact semver, bumps root/member/nested workspace `deno.json` files and
`deno.lock` `@netscript/*` ranges, checks residue, runs release gates, and creates the release PR
outside dry-run mode.
- `e2e-cli-prod` now runs from successful `publish` workflow completion and downloads the published
version artifact from the triggering run.
- `netscript-release` skill was added and mirrored to `.claude/skills/`; `AGENTS.md` points release
work to it.

## Gate Notes

- Focused S1-S5 type-check, unit, format, sync, and workflow sanity gates passed as recorded in
`worklog.md`.
- `actionlint` was not installed; S4 used YAML parsing plus manual sanity read.
- Broad `.llm/tools` check has a pre-existing unrelated failure in
`.llm/tools/fitness/check-manifest-integrity.ts` importing missing
`packages/fresh-ui/registry/manifest.ts`.
- `deno task release:preflight` and `release:cut --dry-run` correctly fail on a true package-source
finding: `packages/service/src/primitives/openapi.ts:155` reads `scalarJsUrl`, declared from
`new URL(..., import.meta.url)` on line 29. This was recorded and not suppressed because this run
is SCOPE-tools only.

## Next

Hand off to IMPL-EVAL in a separate OpenHands qwen3.7-max session. The evaluator should treat the
`packages/service` preflight finding as a real blocker outside this implementation scope rather than
a hidden tooling failure.
Loading
Loading