* test(#1854): failing-first coverage for user-files-backup restore
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(#1854): offer restore for user-added files backed up on update
Adds a restore-custom-files gsd-tools verb and wires it into update.md as a
restore_custom_files step: plan, compatibility-check against the newly
installed release, then restore only on explicit opt-in. The backup is never
deleted, a shipped path is never overwritten, and a single unwritable entry
does not abort the rest.
Also drops the jq pipe from update-context field extraction (#2589 class,
missed by that sweep) and repairs a broken code fence in docs/CLI-TOOLS.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(#1854): reject symlinked restore destinations and backup roots
Self-review of the restore path found two write-through holes: copyFileSync
follows a symlinked destination, so a link planted at the restore target wrote
outside the config dir with every ancestor still a real directory; and statSync
on the backup root followed a link, letting the walk read arbitrary files and
present them as the user's own backup. Both now lstat.
Also marks the report's path/detail strings as untrusted data in update.md so
the rendered step cannot carry instructions into the runtime model.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test(#1854): move the update-context jq guard into the #2589 sweep
update.md joins the AUDITED list rather than carrying a duplicate assertion in
the backup-restore suite, and the guard gains a negative-proof companion so
'no jq pipe' cannot pass by the fields simply no longer being read.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(#1854): validate manifest files map shape before trusting it
Security review flagged that Object.keys on a non-plain-object files field
yields numeric-index keys matching nothing, so the managed-path check dies
silently while manifest_found still reports true. Shape, not just type
(ADR-227): an array or scalar files map is now an unusable manifest.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(#1854): size the restore prompt by eligible_count
Spec review found the prompt was driven by entries.length, so a backup holding
only blocked entries asked "Restore 1 file(s)?" when accepting would restore
zero. The question now reads eligible_count, and an all-blocked backup reports
its reasons instead of offering a choice that cannot be honored. The decline
path names the resolved backup_dir rather than the bare directory name.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test(#1854): use t.skip on hosts without symlink support
A bare return in a node:test body registers as a PASS, so the four symlink
guards silently reported green on unprivileged Windows instead of skipping.
Adds the dangling-link destination case the security review called out, and
moves outside-dir teardown to t.after so a failing assert cannot leak it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(#1854): unfence restore hint, regen goldens, widen install timeout
Three gate failures from the c99d612a5 run, all root-caused:
1. capability-registry (3): update.md's decline message put an instructional
'gsd-tools ...' line in an UNTAGGED fence, and the guard treats untagged
fences as shell blocks. Retagged both display blocks as text and switched
the hint to the resolved 'node <config-dir>/.../gsd-tools.cjs' form users
can actually paste.
2. golden-install-parity (19): update.md and gsd-tools.cjs ship, so every
runtime fixture moved. Regenerated; the diff is exactly those two hashes
per fixture, no other drift.
3. install.test.cjs (5): one real failure, four cascades. The Cursor suite's
before hook died on 'spawnSync ETIMEDOUT' at the 60s cap while the node22
lane passed the SAME commit in 12.7s. A full install measures 13-30s idle,
so 60s was under 2x headroom and shrinks with every file added to the
payload. Raised to 120s, matching the heavy case already in this file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* chore(#1854): backfill changeset pr number to 2679
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* feat(#1754): CLI version-skew detection — warn when a global install shadows project-local GSD
Addresses #1754 (approved-enhancement). Detects when the running gsd-tools.cjs
is outside the project root while a project-local install exists — the shadowing
scenario from #1748 where a stale global canary CLI (retired @gsd-build/sdk)
silently overrides project-local GSD.
Implementation (Node CLI entry-point, not shell snippet — avoids bloating 93
workflow files past their size caps):
- src/cli-skew-check.cts: pure function checkCliSkew({resolvedPath, projectRoot,
projectLocalExists}) → string|null. Compares paths via path.relative; returns
a warning when the resolved CLI is outside the project root AND a project-local
install exists. Includes @gsd-build/sdk removal hint when the path matches.
No I/O (pure), no gsd-sdk literal (avoids bug-2801 lint).
- gsd-core/bin/gsd-tools.cjs: wired at startup via the existing findProjectRoot
resolver. Non-blocking (try/catch; advisory stderr warning, never gates).
- eslint.config.mjs: registers the new ADR-457 generated artifact in the ignores.
- tests: 6-case suite (skew/no-skew/legacy/normalization); all green.
- Golden fixtures regenerated (UPDATE_GOLDEN=1) for the new compiled artifact.
- docs/how-to/update-gsd.md: Diátaxis reference note for the skew warning.
Full suite: 3354 pass, 0 regressions (1 pre-existing local AGENTS.md failure).
lint:ci green.
Closes#1754
* chore(#1754): backfill changeset pr placeholder
* chore(#1754): regenerate INVENTORY-MANIFEST for the new cli-skew-check source module
---------
Co-authored-by: review-bot <review-bot@gsd>
Adds an opt-in --next (alias --rc) flag to /gsd-update targeting the @next RC dist-tag (ADR #660), with a {latest,next} allowlist enforced at three layers, channel-aware version check + banner, and byte-for-byte unchanged default @latest behavior.
Closes#815
* chore: wire docs/agents config into AGENTS.md Agent skills section
Add the `## Agent skills` discovery block pointing the engineering
skills at the existing docs/agents/{issue-tracker,triage-labels,domain}.md
files (issue tracker, triage label mapping, single-context domain docs).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs: rebrand to GSD Core and restructure docs with Diataxis
Reorganise the root README and docs/ around the Diataxis framework
(tutorials, how-to guides, reference, explanation), add new how-to
guides and schema references (STATE.md / CONTEXT.md / PLAN.md /
planning artifacts), and cross-link the whole set. Update the lone
legacy gsd-build reference to open-gsd; keep internal get-shit-done/
filesystem paths unchanged (directory rename tracked separately in
open-gsd/gsd-core#604). Regenerate the ja-JP, ko-KR, pt-BR and zh-CN
localised trees to mirror the new structure.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs: backfill changeset PR number (#605)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>