mirror of https://github.com/garrytan/gstack.git
The version-path pin (--version-path / .gstack/version-path) already let a repo point
the version tooling anywhere, but two real-world shapes still failed — and both failed
CLOSED, which silently disabled /ship's queue-collision check rather than erroring:
1. A package.json as the version source. The readers treated the pinned path as raw
text, so a JSON file was whitespace-stripped into
'{"name":"frontend","version":"0.99.2",...' — which parseVersion rejected, so every
read fell through to the 0.0.0.0 default. This bites any repo whose version lives in
a package.json rather than a plain VERSION file, at the root or not.
2. 3-digit semver. parseVersion required exactly four components, so gstack-next-version
exited 2 on every invocation in such a repo. That CLI *is* the queue-collision check,
so /ship took its documented offline path — naive local patch arithmetic. Two branches
cut from the same base then pick the same version, and git merges that WITHOUT a
conflict because both sides set one line to identical text. The duplicate slot ships
silently: two PRs land as one version, and only one gets a CHANGELOG entry. We hit
this six times in one repo before working out why.
lib/version-source.ts now holds the semantics so both CLIs agree by construction.
Detection is by shape rather than new configuration: a version-path ending in .json is
read (and written) as JSON via .version; a version string with three components stays
three components through bumping and formatting. A repo with a root VERSION file and
4-digit versions sees no behaviour change.
Details worth reviewing:
- MICRO on a 3-digit version is carried out as a PATCH, with a warning in the output.
/ship auto-picks MICRO by default, so erroring would make it unusable in every 3-digit
repo; a silent no-op would be worse, since the caller would write back the version it
started with and claim a slot already taken.
- When the version-path IS a package.json, that file is the single source of truth: it is
the only file written, and the DRIFT_* states cannot arise (there is no second file to
drift from), so classify returns only FRESH / ALREADY_BUMPED and repair is a no-op.
Also syncing a root package.json there would be a guess about which of two JSON files
the repo publishes from.
- Fixes a pre-existing bug in gstack-version-bump: versionRel was derived from the CLI
flag alone, ignoring the .gstack/version-path pin, so a pinned repo compared its local
version against the BASE's root VERSION — two different files. On a repo with no root
VERSION the base then always read as 0.0.0.0 and every branch looked FRESH.
Two existing assertions encoded the old 4-digit-only contract (parseVersion('1.2.3')
is null; VERSION_RE rejects 3-digit). Both are updated with the reasoning inline, and
the garbage-rejection cases are kept and extended.
ship/SKILL.md is deliberately untouched: documenting the new shapes there also requires
regenerating the three host-variant copies and three golden fixtures, which looks like a
release chore rather than something to guess at from outside. Happy to add the prose in a
follow-up if you tell me the right way to regenerate those.
|
||
|---|---|---|
| .. | ||
| diagram-render | ||
| bin-context.ts | ||
| conductor-env-shim.ts | ||
| gbrain-exec.ts | ||
| gbrain-guards.ts | ||
| gbrain-local-status.ts | ||
| gbrain-sources.ts | ||
| gstack-decision-semantic.ts | ||
| gstack-decision.ts | ||
| gstack-memory-helpers.ts | ||
| is-conductor.ts | ||
| jsonl-store.ts | ||
| redact-audit-log.ts | ||
| redact-engine.ts | ||
| redact-patterns.ts | ||
| staging-guard.ts | ||
| version-source.ts | ||
| worktree.ts | ||