gstack/lib
YR 5d672526c6 fix(version): read the version from a package.json, and accept 3-digit semver
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.
2026-08-10 16:29:21 +03:00
..
diagram-render v1.58.0.0 feat: diagram + multi-format document engine (mermaid, excalidraw, single-file HTML, DOCX) (#1990) 2026-06-12 15:38:53 -07:00
bin-context.ts v1.57.5.0 feat: cross-session decision memory + gbrain dream-stage call graph (#1910) 2026-06-08 06:20:58 -07:00
conductor-env-shim.ts v1.58.1.0 feat: hermetic local E2E + Conductor prose AskUserQuestion (#2004) 2026-06-14 11:40:57 -07:00
gbrain-exec.ts v1.58.4.0 fix: high-priority community bug wave + PTY plan-mode smoke gate (#2077) 2026-06-21 07:15:19 -07:00
gbrain-guards.ts v1.57.5.0 feat: cross-session decision memory + gbrain dream-stage call graph (#1910) 2026-06-08 06:20:58 -07:00
gbrain-local-status.ts v1.61.0.0 fix wave: guards failing open / silent failures (9 fixes, 4 community PRs absorbed) (#2472) 2026-08-08 09:28:45 -07:00
gbrain-sources.ts v1.61.0.0 fix wave: guards failing open / silent failures (9 fixes, 4 community PRs absorbed) (#2472) 2026-08-08 09:28:45 -07:00
gstack-decision-semantic.ts v1.57.5.0 feat: cross-session decision memory + gbrain dream-stage call graph (#1910) 2026-06-08 06:20:58 -07:00
gstack-decision.ts v1.57.5.0 feat: cross-session decision memory + gbrain dream-stage call graph (#1910) 2026-06-08 06:20:58 -07:00
gstack-memory-helpers.ts fix(gbrain): canonicalize remotes with trailing slashes 2026-07-14 12:56:09 -07:00
is-conductor.ts v1.58.1.0 feat: hermetic local E2E + Conductor prose AskUserQuestion (#2004) 2026-06-14 11:40:57 -07:00
jsonl-store.ts v1.57.5.0 feat: cross-session decision memory + gbrain dream-stage call graph (#1910) 2026-06-08 06:20:58 -07:00
redact-audit-log.ts v1.53.0.0 feat: smarter redaction — PII/secrets/legal guard across /spec, /ship, /cso, /document-* (#1797) 2026-05-30 08:54:46 -07:00
redact-engine.ts v1.58.4.0 fix: high-priority community bug wave + PTY plan-mode smoke gate (#2077) 2026-06-21 07:15:19 -07:00
redact-patterns.ts v1.58.4.0 fix: high-priority community bug wave + PTY plan-mode smoke gate (#2077) 2026-06-21 07:15:19 -07:00
staging-guard.ts v1.56.1.0 fix(sync): staging-dir ownership guard + resume-correctness fixes (#1802) (#1856) 2026-06-07 06:51:10 -07:00
version-source.ts fix(version): read the version from a package.json, and accept 3-digit semver 2026-08-10 16:29:21 +03:00
worktree.ts feat: content security — 4-layer prompt injection defense for pair-agent (#815) 2026-04-06 14:41:06 -07:00