Repository navigation
fix: report the nightly's own version, not the release it anticipates #149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
f56accf
fix(cli): report the nightly's own version, not the release it antici…
theCodeDrift d983e4b
fix(cli): refuse to emit a nightly that disagrees with itself about i…
theCodeDrift b061eb6
docs(openspec): correct the two specs that said version always comes …
theCodeDrift File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| --- | ||
| "@taskless/cli": patch | ||
| --- | ||
|
|
||
| A nightly now reports the version it is, not the release it anticipates. | ||
|
|
||
| Installing a nightly wrote the previous release into `.taskless/taskless.json` | ||
| — `install.cliVersion: "0.10.2"` — while the skills written beside it, by the | ||
| same command in the same run, pinned every invocation to | ||
| `@taskless/cli-nightly@0.11.0-…`. The manifest attributed the install to a | ||
| version that never performed it, which matters because `install.cliVersion` is | ||
| what answers "what installed this?", and that question gets asked precisely | ||
| when someone is running a nightly to reproduce unreleased behavior. | ||
|
|
||
| A nightly's version is stamped when the publishable artifact is produced, and | ||
| the committed `package.json` is deliberately left untouched — so the build was | ||
| reading a file that could not know the answer. It now takes the same stamp that | ||
| names the published package, so the version a nightly reports and the version | ||
| it sends an agent to are the same string by construction. | ||
|
|
||
| This also corrects `taskless --version`, the CLI version in recipe headers, and | ||
| the `cliVersion` telemetry property on nightly builds. Released builds are | ||
| unaffected. A nightly that cannot determine its own version now fails the build | ||
| rather than quietly reporting the released one. | ||
|
|
||
| The build now also refuses to emit a nightly whose reported version and | ||
| embedded invocation disagree. Both derive from the same stamp, so they cannot | ||
| diverge today — but that was true of the two values in this bug as well, right | ||
| up until one of them started reading `package.json` instead. Deriving from one | ||
| source is not the same as being checked against it. |
63 changes: 63 additions & 0 deletions
63
openspec/changes/archive/2026-08-24-nightly-self-reported-version/proposal.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| ## Why | ||
|
|
||
| A nightly reports the version of the release it anticipates, not the version | ||
| it is. Installing `@taskless/cli-nightly@0.11.0-20260823220841xd9dee3d` writes | ||
| `install.cliVersion: "0.10.2"` into `.taskless/taskless.json`, while the skills | ||
| emitted beside it — in the same run, by the same build — pin every command to | ||
| the nightly's exact version. | ||
|
|
||
| The cause is an ordering the nightly design chose deliberately. The version is | ||
| stamped when the publishable artifact is produced, and the committed manifest | ||
| is left alone; but `__VERSION__` is baked from that committed manifest at build | ||
| time. So `package.json` is asked a question it cannot answer, and it answers | ||
| confidently with the previous release. | ||
|
|
||
| This is quiet rather than loud, which is what makes it worth fixing. Nothing | ||
| errors. The manifest simply attributes the install to a version that never | ||
| performed it — and `install.cliVersion` exists precisely to answer "what | ||
| installed this?", which is the question asked when a nightly is being used to | ||
| reproduce unreleased behavior. | ||
|
|
||
| ## What Changes | ||
|
|
||
| - **A build reports the version it is published as.** `resolveCliVersion` | ||
| returns the stamped nightly version for the `nightly` target and the | ||
| committed package version for every other, and the build's `__VERSION__` | ||
| define reads it instead of `package.json` directly. | ||
| - **The refusal matches the invocation's.** A `nightly` build with no stamp | ||
| throws rather than falling back, reusing `resolveNightlyVersion`. The | ||
| plausible fallback is the wrong answer that produced this bug. | ||
| - **Nothing else moves.** The committed manifest is still untouched by a | ||
| nightly build, which the existing requirement demands. | ||
|
|
||
| This corrects `taskless --version`, the `%(CLI_VERSION)s` recipe header, the | ||
| `cliVersion` telemetry property, and `install.cliVersion` — all four read the | ||
| same define. | ||
|
|
||
| **Delivery is a single PR.** One pure function, its call site, tests, and a | ||
| spec delta. | ||
|
|
||
| ## Capabilities | ||
|
|
||
| ### Modified Capabilities | ||
|
|
||
| - `cli-nightly-builds`: a nightly reports its own published version as its CLI | ||
| version, rather than the released version its committed manifest declares. | ||
|
|
||
| ## Impact | ||
|
|
||
| - **Modified**: `packages/cli/scripts/build-target.ts` (new `resolveCliVersion`), | ||
| `packages/cli/vite.config.ts` (the `__VERSION__` define), | ||
| `packages/cli/test/build-target.test.ts`. | ||
| - **Unchanged**: `packages/cli/package.json`, and `.github/scripts/nightly-pack.cjs` | ||
| — the stamp is already computed once and already passed to the build as | ||
| `TASKLESS_NIGHTLY_VERSION`. This change consumes a value that was already | ||
| there rather than plumbing a new one. | ||
| - **Unchanged**: the `assert-skill-versions` build check, which compares skill | ||
| frontmatter against the committed `package.json`. That is a claim about | ||
| source files in the repository, not about what a build reports, and a nightly | ||
| must not rewrite it. | ||
| - **Not fixed retroactively**: manifests already written by a nightly still | ||
| record the anticipated release. The next install corrects them. | ||
|
|
||
| **Tracking:** taskless/cli#148 |
30 changes: 30 additions & 0 deletions
30
...hanges/archive/2026-08-24-nightly-self-reported-version/specs/analytics/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| ## MODIFIED Requirements | ||
|
|
||
| ### Requirement: All capture calls include standard properties | ||
|
|
||
| Every `capture()` call SHALL include the `cli` property (anonymous UUID), the `cliVersion` property (the version the build reports as its own, baked in at build time), and the `scaffoldVersion` property (the `version` field from `.taskless/taskless.json`, or `0` if the manifest is absent or unreadable). When authenticated, the `groups` parameter SHALL include `{ organization: String(orgId) }`. The `cliVersion` and `scaffoldVersion` values SHALL be resolved once at telemetry initialization and attached to every subsequent `capture()` call without re-reading the source files. | ||
|
|
||
| #### Scenario: Anonymous capture includes standard properties | ||
|
|
||
| - **WHEN** `capture("cli_run")` is called without authentication | ||
| - **THEN** the event SHALL include `{ cli: anonymousUuid, cliVersion: <string>, scaffoldVersion: <number> }` | ||
| - **AND** the event SHALL NOT include a `groups` parameter | ||
|
|
||
| #### Scenario: Authenticated capture includes standard properties and group | ||
|
|
||
| - **WHEN** `capture("cli_rule_created")` is called with authentication | ||
| - **THEN** the event SHALL include `{ cli: anonymousUuid, cliVersion: <string>, scaffoldVersion: <number> }` | ||
| - **AND** the `groups` parameter SHALL include `{ organization: String(orgId) }` | ||
|
|
||
| #### Scenario: Scaffold version falls back to 0 when manifest missing | ||
|
|
||
| - **WHEN** `getTelemetry(cwd)` is initialized in a directory with no `.taskless/taskless.json` | ||
| - **THEN** every `capture()` call from the returned client SHALL include `scaffoldVersion: 0` | ||
|
|
||
| #### Scenario: CLI version is the version the build reports as its own | ||
|
|
||
| - **WHEN** `getTelemetry()` is initialized | ||
| - **THEN** `cliVersion` SHALL be the version the build reports as its own, bundled at build time | ||
| - **AND** for every build target but `nightly` that SHALL be the version in `packages/cli/package.json` | ||
| - **AND** for a `nightly` it SHALL be the version the nightly is published under, so events are attributed to the build that emitted them rather than to the release it anticipates | ||
| - **AND** SHALL be attached to every event emitted through the returned client |
46 changes: 46 additions & 0 deletions
46
...chive/2026-08-24-nightly-self-reported-version/specs/cli-nightly-builds/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| ## ADDED Requirements | ||
|
|
||
| ### Requirement: A nightly reports the version it is published as | ||
|
|
||
| A nightly build SHALL report, as its own CLI version, the version it is published under — not the released version declared by the package manifest in version control. This applies wherever the build states its version, including the version command, the CLI version embedded in recipe headers, telemetry, and the CLI version recorded when it installs into a project. | ||
|
|
||
| The version SHALL come from the same stamp used to name the published package, so that the version a nightly reports and the version an agent is sent to are the same string by construction rather than by coincidence. | ||
|
|
||
| A nightly build with no stamp available SHALL fail rather than report the committed version. Reporting the released version is the failure this requirement exists to prevent, and a build that cannot name itself has no correct value to substitute. | ||
|
|
||
| Builds other than nightly SHALL report the committed package version, which for those targets is the version they are. | ||
|
|
||
| A nightly build SHALL verify, before emitting, that the version it reports and the version its embedded invocation names are the same. Deriving both from one stamp is not sufficient on its own: the two were derived from a single source and still diverged, because nothing compared them. | ||
|
|
||
| #### Scenario: A nightly records its own version when it installs | ||
|
|
||
| - **WHEN** a nightly installs into a project | ||
| - **THEN** the CLI version recorded in the project manifest SHALL be the nightly's published version | ||
| - **AND** SHALL match the version pinned in the skills and commands emitted by that same install | ||
|
|
||
| #### Scenario: A nightly states its own version when asked | ||
|
|
||
| - **WHEN** a nightly is asked for its version | ||
| - **THEN** it SHALL report its published version rather than the released version its committed manifest declares | ||
|
|
||
| #### Scenario: A nightly build without a version stamp fails | ||
|
|
||
| - **WHEN** a nightly build is attempted with no version stamp available | ||
| - **THEN** the build SHALL fail | ||
| - **AND** SHALL NOT fall back to the committed package version | ||
|
|
||
| #### Scenario: A nightly that disagrees with itself is not emitted | ||
|
|
||
| - **WHEN** a nightly build's reported version and the invocation it embeds name different versions | ||
| - **THEN** the build SHALL fail | ||
| - **AND** SHALL NOT emit the artifact | ||
|
|
||
| #### Scenario: A released build reports the committed version | ||
|
|
||
| - **WHEN** a non-nightly build is asked for its version | ||
| - **THEN** it SHALL report the version declared by the committed package manifest | ||
|
|
||
| #### Scenario: Reporting its own version does not modify the committed manifest | ||
|
|
||
| - **WHEN** a nightly build has run | ||
| - **THEN** the CLI package manifest in version control SHALL still declare the released version |
15 changes: 15 additions & 0 deletions
15
...spec/changes/archive/2026-08-24-nightly-self-reported-version/specs/cli/spec.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| ## MODIFIED Requirements | ||
|
|
||
| ### Requirement: CLI version is injected at build time | ||
|
|
||
| The CLI's `vite.config.ts` SHALL use the Vite `define` option to replace a `__VERSION__` sentinel with the version the build reports as its own, resolved at build time. For every build target but `nightly` that is the version string in `packages/cli/package.json`. A `nightly` is the exception, because its version is stamped when the publishable artifact is produced and the committed manifest is deliberately left unchanged, so `package.json` names the release the nightly anticipates rather than the nightly itself (see the `cli-nightly-builds` capability). No runtime file reads or import assertions SHALL be used for version resolution. | ||
|
|
||
| #### Scenario: Build replaces version sentinel | ||
|
|
||
| - **WHEN** `pnpm build` is run in `packages/cli/` | ||
| - **THEN** all occurrences of `__VERSION__` in source code SHALL be replaced with the literal version string from package.json | ||
|
|
||
| #### Scenario: A nightly build replaces the sentinel with its own stamped version | ||
|
|
||
| - **WHEN** a `nightly` build is run | ||
| - **THEN** `__VERSION__` SHALL be replaced with the version the nightly is published under, not the version in package.json |
26 changes: 26 additions & 0 deletions
26
openspec/changes/archive/2026-08-24-nightly-self-reported-version/tasks.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| Delivery shape: **single PR**. A pure function, one call site, tests, and a spec delta — nothing here can land independently of the rest. | ||
|
|
||
| ## 1. Reproduce before fixing | ||
|
|
||
| - [x] 1.1 Build a nightly locally (`TASKLESS_NIGHTLY_VERSION=… pnpm --filter @taskless/cli build:nightly`) and confirm it reports the committed version while pinning the nightly invocation — the two halves of the report, from one artifact | ||
| - [x] 1.2 Confirm the write path is not itself at fault: `wizard/index.ts` persists `getCliVersion()`, and reads `previousState.cliVersion` only to render the diff, so nothing is preserving a stale value | ||
|
|
||
| ## 2. Fix | ||
|
|
||
| - [x] 2.1 Add `resolveCliVersion(environment, packageVersion)` to `build-target.ts`, delegating to `resolveNightlyVersion` for the nightly target so the no-stamp refusal is shared rather than restated | ||
| - [x] 2.2 Read it from the `__VERSION__` define in `vite.config.ts` | ||
| - [x] 2.3 Leave `assert-skill-versions` reading `pkg.version` — it asserts about committed source, not about the build | ||
|
|
||
| ## 3. Tests | ||
|
|
||
| - [x] 3.1 Nightly reports the stamped version, not the committed one | ||
| - [x] 3.2 A nightly with no stamp throws, naming the env var | ||
| - [x] 3.3 prod/dev/self and an empty environment all keep the committed version | ||
|
|
||
| ## 4. Verification | ||
|
|
||
| - [x] 4.1 Nightly build reports the stamped version in `--version` and in the recipe header | ||
| - [x] 4.2 Prod build still reports the committed version | ||
| - [x] 4.3 End-to-end: `init` under a nightly build writes the stamped version to `install.cliVersion` | ||
| - [x] 4.4 `pnpm --filter @taskless/cli build` then `test`, `pnpm typecheck`, `pnpm lint`, `pnpm openspec validate --all --strict` | ||
| - [x] 4.5 Changeset |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.