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
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ provenance: inferred

# CAP-013 — TypeScript Bot API npm publishing

(No purpose statement was recorded in the source spec.)
Publish the TypeScript Bot API package (`@robocode.dev/tank-royale-bot-api`) to the npm registry through Gradle, so every official Bot API is installable through its platform's native channel (Java via Maven Central, Python via PyPI, TypeScript via npm).

Extracted from `openspec/specs/typescript-bot-api-npm-publish/spec.md` at CH-001; the source spec's requirement prose is preserved as comments in [criteria.md](criteria.md).
Implemented: the `npmPack` and `npmPublish` Gradle tasks live in `bot-api/typescript/build.gradle.kts`, the `/release` skill drives `npmPublish`, and the package is live on npm. Criteria stay `draft` until their tests are wired (P-001/M-002).

Extracted from `openspec/specs/typescript-bot-api-npm-publish/spec.md` at CH-001 and reconciled to the shipped implementation at CH-002; the source spec's original requirement prose is preserved as comments in [criteria.md](criteria.md).
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,27 @@ Feature: typescript-bot-api-npm-publish — TypeScript Bot API npm publishing
# the Python bot API's PyPI publishing tasks.
# The following tasks SHALL be available:
# - `npmPack` — runs `npm pack` to produce a local `.tgz` tarball for verification and local use
# - `npmPublishDryRun` — validates the package with `npm publish --dry-run` without uploading
# - `npmPublish` — publishes to the npm registry; requires `NPM_TOKEN` environment variable
# - `npmPublish` — publishes to the npm registry; requires the `npmjs-api-key` Gradle property

@TNP-001
# TNP-001 retired (CH-002): the `npmPublishDryRun` task it verified was never built and
# is not needed — `npmPack` already produces the `.tgz` and shows what would be published
# without uploading. No replacement minted.
@TNP-001 @retired
Scenario: npmPublishDryRun succeeds without credentials
When `./gradlew :bot-api:typescript:npmPublishDryRun` is run
Then the task succeeds and prints the files that would be published
And no package is uploaded to the registry

@TNP-002
# TNP-002 retired (CH-002): the shipped task uses the `npmjs-api-key` Gradle property, not
# an `NPM_TOKEN` environment variable. Reminted as TNP-005.
@TNP-002 @retired
Scenario: npmPublish requires NPM_TOKEN
When `./gradlew :bot-api:typescript:npmPublish` is run without `NPM_TOKEN` set
Then the build fails with a clear error message indicating the token is missing

@TNP-003
# TNP-003 retired (CH-002): credential carrier changed from `NPM_TOKEN` to the
# `npmjs-api-key` Gradle property. Reminted as TNP-006.
@TNP-003 @retired
Scenario: npmPublish succeeds with valid token
When `./gradlew :bot-api:typescript:npmPublish` is run with a valid `NPM_TOKEN`
Then the package is uploaded to `https://registry.npmjs.org`
Expand All @@ -41,4 +47,15 @@ Feature: typescript-bot-api-npm-publish — TypeScript Bot API npm publishing
Scenario: npmrc is not committed to source control
When the `npmPublish` task writes a temporary `.npmrc` file
Then `.npmrc` is listed in `.gitignore` and cannot be accidentally committed

@TNP-005
Scenario: npmPublish requires the npmjs-api-key Gradle property
When `./gradlew :bot-api:typescript:npmPublish` is run without `npmjs-api-key` set
Then the build fails with a clear error message: "npmjs-api-key is not set in gradle.properties"

@TNP-006
Scenario: npmPublish succeeds with a valid npmjs-api-key
When `./gradlew :bot-api:typescript:npmPublish` is run with a valid `npmjs-api-key` Gradle property
Then the package is published to `https://registry.npmjs.org` with public access
And the temporary `.npmrc` credential file is deleted after the task completes
```
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,25 @@ provenance: inferred

# CAP-013 design

Carried over from the in-flight OpenSpec change `add-typescript-bot-api-npm-publish` at CH-001 (tracked as [P-002](../../plans/P-002-typescript-bot-api-npm.md), door M-004).
Originated as the in-flight OpenSpec change `add-typescript-bot-api-npm-publish`, carried into the corpus at CH-001 (tracked as [P-002](../../plans/P-002-typescript-bot-api-npm.md), door M-004) and reconciled to the shipped implementation at CH-002.

The TypeScript Bot API package (`@robocode.dev/tank-royale-bot-api`) builds but cannot be published to the npm registry through Gradle, while Java (Maven Central) and Python (PyPI) both publish via Gradle tasks. The intended shape:
The TypeScript Bot API package (`@robocode.dev/tank-royale-bot-api`) builds but originally could not be published to the npm registry through Gradle, while Java (Maven Central) and Python (PyPI) both publish via Gradle tasks. As shipped in `bot-api/typescript/build.gradle.kts`:

- `npmPack` task in `bot-api/typescript/build.gradle.kts` (also needed by sample-bot startup work)
- `npmPublishDryRun` task — `npm publish --dry-run` validates the package without uploading
- `npmPublish` task — publishes to npm; requires the `NPM_TOKEN` environment variable
- `npmPack` task — runs `npm pack` to produce a local `.tgz` tarball for verification and local use. This also covers pre-publish inspection: it shows exactly what would be published without uploading, so a separate `npm publish --dry-run` task was deemed redundant and not built.
- `npmPublish` task — publishes to npm with `--access public`; requires the `npmjs-api-key` Gradle property (looked up from the user or project `gradle.properties`), consistent with the Sonatype/PyPI credential pattern and the `/release` skill. It writes a temporary `.npmrc` with the token and deletes it afterwards.

Impact beyond the build script: `.gitignore` must exclude `.npmrc` (a temporary credential file is written and deleted during publish).
Impact beyond the build script: `.gitignore` excludes `/bot-api/typescript/.npmrc` (the temporary credential file written and deleted during publish).

## Credential setup

`npmPublish` reads the npm token from the `npmjs-api-key` Gradle property. Keep it out of the repo by putting it in your **user** Gradle properties file, never the project one:

- Unix/macOS: `~/.gradle/gradle.properties`
- Windows: `%USERPROFILE%\.gradle\gradle.properties`

```properties
# npm token (Automation type) from https://www.npmjs.com/settings/<user>/tokens
npmjs-api-key=npm_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

The token must have publish rights to the `@robocode.dev` scope. If it is missing, `npmPublish` fails with `npmjs-api-key is not set in gradle.properties` (criterion TNP-005). This mirrors the other publish credentials, which live in the same file: `ossrhUsername` / `ossrhPassword` (Maven Central), `nuget-api-key` (NuGet), `pypiToken` (PyPI) — see the `/release` skill for the full set.
2 changes: 2 additions & 0 deletions docs/decisions/log.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Decisions that are cheap and local to reverse, one row each — newest first. Th

| Date | Decision | Why | Change/PR |
|---|---|---|---|
| 2026-07-19 | Drop the never-built `npmPublishDryRun` task from CAP-013 (retire TNP-001) instead of building it | `npmPack` already produces the `.tgz` and shows what would be published without uploading, so a dry-run task is redundant | CH-002 |
| 2026-07-19 | TypeScript npm publishing authenticates via the `npmjs-api-key` Gradle property, not an `NPM_TOKEN` env var (retire TNP-002/003, remint TNP-005/006) | Reconciles the corpus to the shipped code and matches the Sonatype/PyPI credential pattern and the `/release` skill | CH-002 |
| 2026-07-19 | Extracted criteria are born `status: draft`; a capability's criteria go `active` when its tests carry purpose tags | Draft criteria are exempt from the AC↔test wall, which turns the four-language tagging backlog (P-001/M-002) into per-capability increments instead of one blocking big bang | CH-001 |
| 2026-07-19 | Pre-Cliewen ADRs keep ids ADR-0001…ADR-0041 and become `verified` with `accepted-by: … (date, pre-Cliewen MADR acceptance)` | The MADR acceptance already happened and is preserved as fact, not re-judged; renumbering 41 cross-referenced records would break links for no gain | CH-001 |
| 2026-07-19 | `INDEX.md` files and `docs/decisions/template.md` deleted; README `clue:index` blocks are the only indexes | Two indexes drift; the validate-checked index block is the enforced one | CH-001 |
Expand Down
4 changes: 2 additions & 2 deletions docs/plans/P-002-typescript-bot-api-npm.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
id: P-002
type: plan
status: active
status: completed
links: [G-001]
title: TypeScript Bot API reaches npm
provenance: inferred
Expand All @@ -15,4 +15,4 @@ Carried over from the pending OpenSpec change `add-typescript-bot-api-npm-publis

| ID | Milestone | Exit criterion | Status | Evidence |
|---|---|---|---|---|
| M-004 | npm publishing via Gradle | `npmPack`, `npmPublishDryRun`, `npmPublish` Gradle tasks exist and a dry-run publish of the package succeeds from a clean checkout; CAP-014 flips to `active` with its ACs tested | todo | |
| M-004 | npm publishing via Gradle | `npmPack` and `npmPublish` Gradle tasks exist in `bot-api/typescript/build.gradle.kts` and the package publishes to npm via the `/release` skill | done | Commits `b1654f620` / `287ff01ac` / `51c30e21b`; `@robocode.dev/tank-royale-bot-api@1.0.2` live on npm; CAP-013 |
Loading