@opengsd/gsd-path 1.2.0 → 1.3.0
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 +19 -0
- package/DOCS.md +4 -0
- package/QUICK.md +2 -5
- package/README.md +6 -6
- package/UPDATE.md +26 -0
- package/package.json +1 -1
- package/scripts/install.mjs +24 -2
- package/scripts/install.py +10 -11
- package/scripts/runtime_store.py +4 -1
- package/scripts/wizard.mjs +8 -2
- package/skills/gsd-path/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -66,3 +66,22 @@ are documented here. Format follows [Keep a Changelog](https://keepachangelog.co
|
|
|
66
66
|
- Restore same-cycle recovery after partial review completion
|
|
67
67
|
- Isolate assignment rejections and align native panel exclusions
|
|
68
68
|
- Fix dispatch isolation, legacy pinning, and independent panel selection
|
|
69
|
+
|
|
70
|
+
## [1.3.0] - 2026-09-21
|
|
71
|
+
|
|
72
|
+
### Added
|
|
73
|
+
- migrate legacy runtimes during upgrades
|
|
74
|
+
|
|
75
|
+
### Changed
|
|
76
|
+
- Clarify receipt reuse and consolidate release policy guidance
|
|
77
|
+
- Clarify legacy upgrade guidance and verify syntax
|
|
78
|
+
- update release notes for v1.2.0
|
|
79
|
+
|
|
80
|
+
### Fixed
|
|
81
|
+
- validate installer changes without live host reruns
|
|
82
|
+
- preserve closed review cycles in host recovery
|
|
83
|
+
- clarify owner gates and accept serial task release evidence
|
|
84
|
+
|
|
85
|
+
### Other
|
|
86
|
+
- Clarify reviewer ownership; live verification remains pending
|
|
87
|
+
- Reject unretired verification worktrees and branches in release evidence
|
package/DOCS.md
CHANGED
|
@@ -405,6 +405,10 @@ the declaration and stable wiring. It does not stage or commit. Resolve local
|
|
|
405
405
|
runtime edits or unknown files first. Interrupted migration is recovered by the
|
|
406
406
|
same explicit command; its journal lives outside the checkout.
|
|
407
407
|
|
|
408
|
+
To migrate and then update skills and project wiring in one invocation, follow
|
|
409
|
+
[Legacy project runtime](UPDATE.md#legacy-project-runtime) for wizard consent,
|
|
410
|
+
unattended commands, dry-run scope, and recovery after an update failure.
|
|
411
|
+
|
|
408
412
|
An ignore rule alone cannot migrate tracked runtime files. This runtime lifecycle
|
|
409
413
|
covers runtime code and launch wiring; project-local skill copies, retained skill
|
|
410
414
|
backups, and mixed user/host settings remain separately owned installation output.
|
package/QUICK.md
CHANGED
|
@@ -67,11 +67,8 @@ node scripts/install.mjs --all --project "$(pwd)"
|
|
|
67
67
|
Installs the [project contracts](DOCS.md#installing)
|
|
68
68
|
(+ `.claude/CLAUDE.md` if Claude is selected).
|
|
69
69
|
If those managed files already exist, a plain install **refuses and installs
|
|
70
|
-
nothing** —
|
|
71
|
-
|
|
72
|
-
hook wiring while keeping your contracts and selected runtime. Merge contract
|
|
73
|
-
changes by hand
|
|
74
|
-
([UPDATE.md](UPDATE.md)).
|
|
70
|
+
nothing** — use [the update guide](UPDATE.md) for existing installations,
|
|
71
|
+
including [legacy runtime migration during upgrades](UPDATE.md#legacy-project-runtime).
|
|
75
72
|
|
|
76
73
|
**Optional** archive/git guards:
|
|
77
74
|
|
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.
|
|
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)
|
|
20
20
|
|
|
21
21
|
**Recent highlights**
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- reuse
|
|
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
|
|
27
27
|
|
|
28
28
|
<!-- /release-docs -->
|
|
29
29
|
|
package/UPDATE.md
CHANGED
|
@@ -98,6 +98,32 @@ node scripts/install.mjs --update --claude --cursor
|
|
|
98
98
|
|
|
99
99
|
`--update` only refreshes hosts that **already have** GSD Path installed.
|
|
100
100
|
|
|
101
|
+
### Legacy project runtime
|
|
102
|
+
|
|
103
|
+
The interactive npm installer detects the old `.gsd-path/runtime/` layout when
|
|
104
|
+
you choose to update project wiring. Choose **Migrate and continue upgrade** to
|
|
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.
|
|
108
|
+
|
|
109
|
+
For unattended upgrades, migration requires explicit consent:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npx @opengsd/gsd-path@latest --update --runtime-migrate --project "/absolute/project" --dry-run
|
|
113
|
+
npx @opengsd/gsd-path@latest --update --runtime-migrate --project "/absolute/project"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The combined dry run previews migration only and writes nothing. The real command
|
|
117
|
+
migrates, then validates and applies the update. These are separate operations:
|
|
118
|
+
if the update fails, the completed migration remains as an unstaged Git diff.
|
|
119
|
+
Review it with `git status --short` and `git diff` in the project.
|
|
120
|
+
|
|
121
|
+
Migration is needed once per project. For later updates, omit `--runtime-migrate`.
|
|
122
|
+
For runtime selection after migration, see
|
|
123
|
+
[Project runtime versions](DOCS.md#project-runtime-versions).
|
|
124
|
+
Without migration consent, legacy project updates stop before writing files and
|
|
125
|
+
print the exact migration command.
|
|
126
|
+
|
|
101
127
|
### After updating
|
|
102
128
|
|
|
103
129
|
1. Restart your agent session (hosts reload skills on session start).
|
package/package.json
CHANGED
package/scripts/install.mjs
CHANGED
|
@@ -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\n" +
|
|
1658
|
+
" --runtime-migrate migrate a tracked 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" +
|
|
@@ -1684,6 +1684,8 @@ export async function main(argv, env = process.env) {
|
|
|
1684
1684
|
colored: !process.env.NO_COLOR,
|
|
1685
1685
|
version: packageVersion(),
|
|
1686
1686
|
targets: TARGETS,
|
|
1687
|
+
legacyRuntime: lexists(path.join(process.cwd(), ".gsd-path", "runtime")) &&
|
|
1688
|
+
!lexists(path.join(process.cwd(), ".gsd-path", "runtime.json")),
|
|
1687
1689
|
installed: (target, local) =>
|
|
1688
1690
|
hasManagedInstall(local ? localRoot(target, process.cwd()) : defaultRoot(target, env)),
|
|
1689
1691
|
});
|
|
@@ -1695,7 +1697,12 @@ export async function main(argv, env = process.env) {
|
|
|
1695
1697
|
: path.resolve(SCRIPT_DIRECTORY, "..");
|
|
1696
1698
|
const project =
|
|
1697
1699
|
values.project !== undefined ? absolutePath(values.project) : null;
|
|
1698
|
-
|
|
1700
|
+
const migrateAndUpdate = values["runtime-migrate"] && values.update;
|
|
1701
|
+
if (migrateAndUpdate && (project === null || values["runtime-restore"] || values["runtime-upgrade"] || values.doctor || values["hooks-init"] || values["hooks-refresh"] || values["hooks-refresh-full"])) {
|
|
1702
|
+
ui.error("--runtime-migrate --update requires --project and cannot be combined with another runtime, doctor, or hook operation");
|
|
1703
|
+
return 2;
|
|
1704
|
+
}
|
|
1705
|
+
if (!migrateAndUpdate && ["runtime-restore", "runtime-upgrade", "runtime-migrate"].some(name => values[name])) {
|
|
1699
1706
|
const interpreter = requiredPythonRuntime("project runtime");
|
|
1700
1707
|
const result = spawnSync(interpreter, ["-B", path.join(SCRIPT_DIRECTORY, "install.py"),
|
|
1701
1708
|
...argv.filter(arg => arg !== "--no-color")], { stdio: "inherit", env });
|
|
@@ -1800,6 +1807,21 @@ export async function main(argv, env = process.env) {
|
|
|
1800
1807
|
} else {
|
|
1801
1808
|
plans = selected.map((target) => targetPlan(target, rootFor(target)));
|
|
1802
1809
|
}
|
|
1810
|
+
if (migrateAndUpdate) {
|
|
1811
|
+
const interpreter = requiredPythonRuntime("project runtime");
|
|
1812
|
+
const migration = spawnSync(interpreter, ["-B", path.join(SCRIPT_DIRECTORY, "install.py"),
|
|
1813
|
+
"--runtime-migrate", "--project", project, "--source-root", sourceRoot,
|
|
1814
|
+
...(values["dry-run"] ? ["--dry-run"] : [])], { stdio: "inherit", env });
|
|
1815
|
+
if (migration.error || migration.status !== 0) {
|
|
1816
|
+
if (migration.error) ui.error(migration.error.message);
|
|
1817
|
+
return migration.status ?? 1;
|
|
1818
|
+
}
|
|
1819
|
+
if (values["dry-run"]) {
|
|
1820
|
+
ui.result("Migration preview only; nothing was written. Run without --dry-run to migrate, then validate and apply the update.");
|
|
1821
|
+
return 0;
|
|
1822
|
+
}
|
|
1823
|
+
ui.result("Migration completed. Review the unstaged Git diff. Updating skills and wiring next; an update failure will retain the completed migration.");
|
|
1824
|
+
}
|
|
1803
1825
|
const spin = ui.spinner("Preparing");
|
|
1804
1826
|
try {
|
|
1805
1827
|
const results = await install(sourceRootForInstall, plans, {
|
package/scripts/install.py
CHANGED
|
@@ -2641,17 +2641,16 @@ def install(
|
|
|
2641
2641
|
|
|
2642
2642
|
if project is not None:
|
|
2643
2643
|
_validate_directory_destination(project, "project path")
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
)
|
|
2644
|
+
_validate_project(
|
|
2645
|
+
source_root,
|
|
2646
|
+
project,
|
|
2647
|
+
selected,
|
|
2648
|
+
hooks,
|
|
2649
|
+
[*mutation_roots, *planned_backups],
|
|
2650
|
+
interpreter,
|
|
2651
|
+
hooks_dir,
|
|
2652
|
+
update,
|
|
2653
|
+
)
|
|
2655
2654
|
|
|
2656
2655
|
results = []
|
|
2657
2656
|
with tempfile.TemporaryDirectory(prefix="gsd-path-install-") as temporary:
|
package/scripts/runtime_store.py
CHANGED
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
import os
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
import shutil
|
|
9
|
+
import shlex
|
|
9
10
|
import tempfile
|
|
10
11
|
from contextlib import contextmanager
|
|
11
12
|
|
|
@@ -135,7 +136,9 @@ def prepare(source, project, *, dry_run=False):
|
|
|
135
136
|
status_runtime.validate_runtime(pin)
|
|
136
137
|
return pin
|
|
137
138
|
if os.path.lexists(project / ".gsd-path/runtime"):
|
|
138
|
-
raise ValueError("legacy project runtime requires
|
|
139
|
+
raise ValueError("legacy project runtime requires explicit migration before updating; run: "
|
|
140
|
+
f"npx @opengsd/gsd-path@latest --runtime-migrate --project {shlex.quote(str(project.resolve()))}; "
|
|
141
|
+
"then retry the update. Migration produces a reviewable Git diff")
|
|
139
142
|
return publish(source, dry_run=dry_run)
|
|
140
143
|
|
|
141
144
|
|
package/scripts/wizard.mjs
CHANGED
|
@@ -125,7 +125,7 @@ const confirm = (io, theme, title, yes = "Yes", no = "No") =>
|
|
|
125
125
|
|
|
126
126
|
// Pure: runs the question flow and returns install.mjs argv (or null if cancelled).
|
|
127
127
|
// `installed(target, local)` reports whether a managed install already exists for that host in that scope.
|
|
128
|
-
export async function wizard({ input, output, colored = true, version = "", cwd = process.cwd(), installed = () => false, targets }) {
|
|
128
|
+
export async function wizard({ input, output, colored = true, version = "", cwd = process.cwd(), installed = () => false, legacyRuntime = false, targets }) {
|
|
129
129
|
const theme = makeTheme(colored);
|
|
130
130
|
const keys = keyReader(input);
|
|
131
131
|
const io = { keys, output };
|
|
@@ -147,8 +147,13 @@ export async function wizard({ input, output, colored = true, version = "", cwd
|
|
|
147
147
|
hostItems.some((item) => item.checked && hosts.includes(item.value)) &&
|
|
148
148
|
(await confirm(io, theme, "Existing installs found. What do you want to do?", "Update in place", "Fresh install"));
|
|
149
149
|
|
|
150
|
-
const project = await confirm(io, theme, "Write AGENTS.md + WORKFLOW.md contracts into this repo?", `Yes — ${cwd}`, "Not now");
|
|
150
|
+
const project = await confirm(io, theme, update ? "Refresh this project's wiring (keep its contracts and selected runtime)?" : "Write AGENTS.md + WORKFLOW.md contracts into this repo?", `Yes — ${cwd}`, "Not now");
|
|
151
151
|
const hooks = project && (await confirm(io, theme, "Install guard hooks (archive immutability, ship-commit purity)?"));
|
|
152
|
+
const migrate = project && update && legacyRuntime;
|
|
153
|
+
if (migrate) {
|
|
154
|
+
output.write(`\n This project uses the old runtime layout. Migration moves managed runtime files\n outside the repo and leaves an unstaged Git diff for review. Local edits are preserved.\n`);
|
|
155
|
+
if (!(await confirm(io, theme, "Migrate this project before updating?", "Migrate and continue upgrade", "Cancel"))) return null;
|
|
156
|
+
}
|
|
152
157
|
|
|
153
158
|
const argv = [];
|
|
154
159
|
if (hosts.length === targets.length) argv.push("--all");
|
|
@@ -157,6 +162,7 @@ export async function wizard({ input, output, colored = true, version = "", cwd
|
|
|
157
162
|
if (local) argv.push("--local");
|
|
158
163
|
if (project) argv.push("--project", cwd);
|
|
159
164
|
if (hooks) argv.push("--hooks");
|
|
165
|
+
if (migrate) argv.push("--runtime-migrate");
|
|
160
166
|
|
|
161
167
|
output.write(`\n ${theme.dim("Equivalent command:")}\n ${theme.accent("$")} gsd-path ${argv.join(" ")}\n`);
|
|
162
168
|
const go = await select(io, theme, "Ready?", [
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|