@opengsd/gsd-path 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -85,3 +85,16 @@ are documented here. Format follows [Keep a Changelog](https://keepachangelog.co
85
85
  ### Other
86
86
  - Clarify reviewer ownership; live verification remains pending
87
87
  - Reject unretired verification worktrees and branches in release evidence
88
+
89
+ ## [1.3.1] - 2026-09-22
90
+
91
+ ### Changed
92
+ - Clarify legacy runtime backup guidance
93
+ - Consolidate legacy runtime migration guidance
94
+ - prepare 1.3.1 patch candidate
95
+ - Clarify legacy runtime migration documentation
96
+ - update release notes for v1.3.0
97
+
98
+ ### Fixed
99
+ - describe untracked legacy migration in help
100
+ - preserve older untracked runtimes during migration
package/DOCS.md CHANGED
@@ -398,12 +398,15 @@ files. The supplied package must match both the version and digest; custom sourc
398
398
  builds may share a release version while having different digests. No command
399
399
  silently substitutes a newer runtime, and status/guards never install or download.
400
400
 
401
- For an old tracked `.gsd-path/runtime/`, run `gsd-path --runtime-migrate --project
401
+ For an old `.gsd-path/runtime/`, run `gsd-path --runtime-migrate --project
402
402
  /absolute/project --dry-run`, then the same command without `--dry-run` and review
403
403
  the Git diff. Migration removes the generated files from the checkout and writes
404
404
  the declaration and stable wiring. It does not stage or commit. Resolve local
405
- runtime edits or unknown files first. Interrupted migration is recovered by the
406
- same explicit command; its journal lives outside the checkout.
405
+ edits to tracked runtime files or unknown files first. When untracked managed
406
+ files differ from the supplied package, migration saves those files' original
407
+ bytes under `~/.gsd-path/runtime-migrations/backups/` and prints the backup
408
+ directory for review. Interrupted migration is recovered by the same explicit
409
+ command; its journal lives outside the checkout.
407
410
 
408
411
  To migrate and then update skills and project wiring in one invocation, follow
409
412
  [Legacy project runtime](UPDATE.md#legacy-project-runtime) for wizard consent,
package/README.md CHANGED
@@ -16,14 +16,14 @@ Support means the installer and dispatch contract exist. See the
16
16
  proof and each host's guard tier.
17
17
 
18
18
  <!-- release-docs -->
19
- **Latest npm release:** [@opengsd/gsd-path@1.3.0](https://www.npmjs.com/package/@opengsd/gsd-path/v/1.3.0) — [release notes](CHANGELOG.md#130---2026-09-21)
19
+ **Latest npm release:** [@opengsd/gsd-path@1.3.1](https://www.npmjs.com/package/@opengsd/gsd-path/v/1.3.1) — [release notes](CHANGELOG.md#131---2026-09-22)
20
20
 
21
21
  **Recent highlights**
22
- - migrate legacy runtimes during upgrades
23
- - validate installer changes without live host reruns
24
- - preserve closed review cycles in host recovery
25
- - clarify owner gates and accept serial task release evidence
26
- - Clarify receipt reuse and consolidate release policy guidance
22
+ - describe untracked legacy migration in help
23
+ - preserve older untracked runtimes during migration
24
+ - Clarify legacy runtime backup guidance
25
+ - Consolidate legacy runtime migration guidance
26
+ - prepare 1.3.1 patch candidate
27
27
 
28
28
  <!-- /release-docs -->
29
29
 
package/UPDATE.md CHANGED
@@ -103,8 +103,8 @@ node scripts/install.mjs --update --claude --cursor
103
103
  The interactive npm installer detects the old `.gsd-path/runtime/` layout when
104
104
  you choose to update project wiring. Choose **Migrate and continue upgrade** to
105
105
  migrate first, then update skills and wiring. Cancelling leaves the installation
106
- unchanged. Migration preserves locally modified files by stopping for you to
107
- resolve them; it never stages or commits changes.
106
+ unchanged. See [Project runtime versions](DOCS.md#project-runtime-versions)
107
+ for migration safety checks and backups. Migration never stages or commits changes.
108
108
 
109
109
  For unattended upgrades, migration requires explicit consent:
110
110
 
@@ -160,8 +160,8 @@ local edits. Clean source checkouts still refresh before a project update.
160
160
  Older unstamped installs show **Unknown — version metadata unavailable**.
161
161
  This does not establish that their runtime is outdated or broken. **Update**
162
162
  uses the guarded migration for legacy runtime directories and an upgrade for
163
- version-pinned runtimes. Migration leaves a reviewable Git diff and refuses
164
- modified or unknown runtime files; the dashboard shows the failure reason.
163
+ version-pinned runtimes. Migration leaves a reviewable Git diff; the dashboard
164
+ shows the failure reason when it stops.
165
165
  See [Project runtime versions](DOCS.md#project-runtime-versions) for manual
166
166
  migration and preview commands. Use `--doctor --project PATH` to check runtime files.
167
167
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/gsd-path",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "Disk-backed AI agent pipeline. Docs: DOCS.md (start here), QUICK.md, FULL.md, UPDATE.md",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1655,7 +1655,7 @@ function usage() {
1655
1655
  " --hooks-init add guards to an existing project without changing its contracts\n" +
1656
1656
  " --runtime-restore restore the exact declared runtime from --source-root\n" +
1657
1657
  " --runtime-upgrade explicitly select the supplied package runtime\n" +
1658
- " --runtime-migrate migrate a tracked legacy runtime for review; add --update to continue upgrading\n" +
1658
+ " --runtime-migrate migrate a legacy runtime for review; add --update to continue upgrading\n" +
1659
1659
  " --hooks-refresh validate the selected runtime; keep its version\n" +
1660
1660
  " --hooks-refresh-full refresh native settings/git hooks; target flags create missing configs\n" +
1661
1661
  " --dry-run preview without writing\n" +
@@ -2839,6 +2839,8 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
2839
2839
  _release_install_locks(locks, created)
2840
2840
  print(f"runtime: {runtime_action} {pin['version']} ({pin['digest']})"
2841
2841
  + (" (dry run)" if arguments.dry_run else ""))
2842
+ if pin.get("backup"):
2843
+ print(f"legacy runtime backup: {pin['backup']}")
2842
2844
  return 0
2843
2845
  except (InstallerError, OSError, ValueError) as error:
2844
2846
  print(f"error: {error}", file=sys.stderr)
@@ -235,6 +235,7 @@ def operate(source, project, action, *, dry_run=False):
235
235
  raise ValueError("legacy runtime contains unknown files; preserve and resolve them before migration")
236
236
  managed = entries + [project / ".gsd-path/status_runtime.py"]
237
237
  managed += [project / ".gsd-path" / n for n in GUARDS if (project / ".gsd-path" / n).exists()]
238
+ divergent = []
238
239
  for path in managed:
239
240
  if path.is_symlink() or not path.is_file():
240
241
  raise ValueError(f"unsafe migration file: {path}")
@@ -249,7 +250,7 @@ def operate(source, project, action, *, dry_run=False):
249
250
  if clean.stdout:
250
251
  raise ValueError(f"locally modified migration file: {path}")
251
252
  elif path.read_bytes() != (source / "scripts" / path.name).read_bytes():
252
- raise ValueError(f"untracked migration file differs from source: {path}")
253
+ divergent.append(path)
253
254
  pin = publish(source, dry_run=dry_run)
254
255
  if dry_run:
255
256
  return pin
@@ -257,6 +258,17 @@ def operate(source, project, action, *, dry_run=False):
257
258
  declaration = project / ".gsd-path/runtime.json"
258
259
  if os.path.lexists(declaration):
259
260
  raise ValueError("runtime declaration already exists; refusing legacy migration")
261
+ backup = None
262
+ if divergent:
263
+ backup_root = migration_journal(project).parent / "backups"
264
+ if backup_root.is_symlink():
265
+ raise ValueError(f"unsafe runtime migration backup directory: {backup_root}")
266
+ backup_root.mkdir(parents=True, exist_ok=True)
267
+ backup = Path(tempfile.mkdtemp(prefix="legacy-", dir=backup_root))
268
+ for path in divergent:
269
+ saved = backup / path.relative_to(project / ".gsd-path")
270
+ saved.parent.mkdir(parents=True, exist_ok=True)
271
+ saved.write_bytes(originals[path])
260
272
  updates = {project / ".gsd-path/status_runtime.py": (source / "scripts/status_runtime.py").read_bytes(),
261
273
  declaration: pin_text(pin).encode()}
262
274
  updates.update({p: None for p in entries})
@@ -278,4 +290,4 @@ def operate(source, project, action, *, dry_run=False):
278
290
  recover_migration(project)
279
291
  raise
280
292
  journal.unlink()
281
- return pin
293
+ return {**pin, "backup": str(backup)} if backup else pin