@guiho/runx 0.2.4 → 0.2.6
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 +14 -0
- package/DOCS.md +5 -3
- package/docs/decisions/decisions.xdocs.md +6 -0
- package/docs/decisions/mirror-automatic-push.md +84 -0
- package/docs/decisions/windows-self-upgrade.md +98 -0
- package/docs/plans/mirror-automatic-push.md +77 -0
- package/docs/plans/plans.xdocs.md +6 -0
- package/docs/plans/windows-self-upgrade.md +129 -0
- package/docs/reviews/implementation/implementation.xdocs.md +3 -0
- package/docs/reviews/implementation/windows-self-upgrade-review.md +79 -0
- package/docs/reviews/plans/mirror-automatic-push-review.md +57 -0
- package/docs/reviews/plans/plans.xdocs.md +6 -0
- package/docs/reviews/plans/windows-self-upgrade-review.md +71 -0
- package/docs/validation/validation.xdocs.md +3 -0
- package/docs/validation/windows-self-upgrade.md +85 -0
- package/library/self-management.d.ts +5 -4
- package/library/self-management.d.ts.map +1 -1
- package/library/self-management.js +66 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,20 @@ owner: runx
|
|
|
15
15
|
|
|
16
16
|
# Changelog
|
|
17
17
|
|
|
18
|
+
## 0.2.6 - 2026-07-14
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Added Windows CI coverage for replacing a running executable, verifying the
|
|
23
|
+
installed target version, cleaning the old image, and rolling back failures.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- Fixed `runx upgrade` on Windows so it replaces and verifies `runx.exe` before
|
|
28
|
+
reporting success instead of returning a detached `scheduled: true` state.
|
|
29
|
+
- Failed Windows replacements now restore the previous executable, report a
|
|
30
|
+
non-zero error, and clean `.new` and `.old` update files safely.
|
|
31
|
+
|
|
18
32
|
## 0.2.4 - 2026-07-14
|
|
19
33
|
|
|
20
34
|
### Added
|
package/DOCS.md
CHANGED
|
@@ -122,9 +122,11 @@ runx agents install local
|
|
|
122
122
|
|
|
123
123
|
`devops/install.ps1` installs Windows assets and `devops/install.sh` installs
|
|
124
124
|
macOS/Linux assets from GitHub Releases into the user's local bin directory.
|
|
125
|
-
`runx upgrade` uses the matching release asset and replaces a native executable
|
|
126
|
-
|
|
127
|
-
the
|
|
125
|
+
`runx upgrade` uses the matching release asset and replaces a native executable.
|
|
126
|
+
On Windows it renames the running executable, installs and verifies the target
|
|
127
|
+
version at the original path, and restores the previous executable if replacement
|
|
128
|
+
fails. Only cleanup of the renamed old image is deferred until RunX exits.
|
|
129
|
+
`runx uninstall` removes the same native executable and supports `--dry-run`.
|
|
128
130
|
|
|
129
131
|
When the latest GitHub Release matches the installed version, `runx upgrade` prints `Already up to date.` and exits successfully without downloading or scheduling executable replacement. JSON output reports `upToDate: true`.
|
|
130
132
|
|
|
@@ -6,16 +6,22 @@ children: []
|
|
|
6
6
|
files:
|
|
7
7
|
alpha-boundaries.md: Captures accepted alpha scope, safety, distribution, and compatibility decisions.
|
|
8
8
|
citty-cli-migration.md: Defines the accepted full migration from handwritten parsing and routing to Citty.
|
|
9
|
+
mirror-automatic-push.md: Defines automatic Mirror release pushes with a synchronized protected-main gate.
|
|
9
10
|
npm-trusted-publishing.md: Defines the accepted npm OIDC publishing workflow and protected-branch patch-release trial.
|
|
11
|
+
windows-self-upgrade.md: Defines synchronous Windows executable replacement, verification, rollback, and cleanup.
|
|
10
12
|
documents:
|
|
11
13
|
alpha-boundaries.md: Decision record for RunX alpha boundaries.
|
|
12
14
|
citty-cli-migration.md: Decision record for the complete Citty CLI parser and router migration.
|
|
15
|
+
mirror-automatic-push.md: Accepted release-policy decision for Mirror push=true and protected delivery ordering.
|
|
13
16
|
npm-trusted-publishing.md: Decision record for GitHub Actions npm trusted publishing and the first automated patch release.
|
|
17
|
+
windows-self-upgrade.md: Accepted design for synchronous and recoverable Windows native self-upgrade.
|
|
14
18
|
tags:
|
|
15
19
|
- decisions
|
|
16
20
|
keywords:
|
|
17
21
|
- runx
|
|
18
22
|
- decisions
|
|
23
|
+
- mirror push
|
|
24
|
+
- windows self-upgrade
|
|
19
25
|
flags: []
|
|
20
26
|
status: stable
|
|
21
27
|
---
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Mirror Automatic Release Push
|
|
3
|
+
purpose: Record the accepted policy that Mirror pushes RunX release commits and tags automatically.
|
|
4
|
+
description: Defines push=true, the synchronized-main precondition, protected GitHub delivery, failure behavior, and rollback boundary.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- accepted
|
|
8
|
+
tags:
|
|
9
|
+
- decisions
|
|
10
|
+
- release
|
|
11
|
+
- mirror
|
|
12
|
+
keywords:
|
|
13
|
+
- runx
|
|
14
|
+
- mirror push
|
|
15
|
+
- protected main
|
|
16
|
+
- release tags
|
|
17
|
+
owner: runx-decisions
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# RunX Mirror Automatic Release Push
|
|
21
|
+
|
|
22
|
+
## Status
|
|
23
|
+
|
|
24
|
+
Accepted by the repository owner on 2026-07-14.
|
|
25
|
+
|
|
26
|
+
## Context
|
|
27
|
+
|
|
28
|
+
RunX previously configured Mirror with `push = false`. Each release applied the
|
|
29
|
+
version commit and tag locally, then required separate branch delivery and tag
|
|
30
|
+
push commands. The owner wants RunX to match the automatic Mirror release flow
|
|
31
|
+
used by the related GUIHO repositories.
|
|
32
|
+
|
|
33
|
+
RunX also protects `main` and `@guiho/runx@*` tags. Automatic pushing must not
|
|
34
|
+
allow a release tag to reference a commit that has not reached protected
|
|
35
|
+
`main`.
|
|
36
|
+
|
|
37
|
+
## Decision
|
|
38
|
+
|
|
39
|
+
- Set `[git].push = true` in `mirror.config.toml`.
|
|
40
|
+
- Run future `mirror version apply` operations only from a clean, synchronized
|
|
41
|
+
local `main` whose HEAD equals `origin/main`.
|
|
42
|
+
- Complete implementation changes through protected pull requests before
|
|
43
|
+
applying Mirror.
|
|
44
|
+
- Treat `mirror version apply` as the single release mutation that writes the
|
|
45
|
+
version, commits, tags, and pushes the configured refs.
|
|
46
|
+
- Keep package publication behind the GitHub `production` environment approval
|
|
47
|
+
and npm OIDC trusted publishing.
|
|
48
|
+
|
|
49
|
+
## Alternatives Considered
|
|
50
|
+
|
|
51
|
+
- Keep `push = false`: rejected because it preserves the manual release step the
|
|
52
|
+
owner explicitly asked to remove.
|
|
53
|
+
- Pass `--push` per release: rejected because it makes release behavior depend
|
|
54
|
+
on operator memory instead of repository configuration.
|
|
55
|
+
- Apply Mirror on a release branch and merge later: rejected because the tag
|
|
56
|
+
could publish a commit before that commit is part of protected `main`.
|
|
57
|
+
|
|
58
|
+
## Consequences
|
|
59
|
+
|
|
60
|
+
- Successful Mirror applies will immediately push release refs and can trigger
|
|
61
|
+
the public Publish workflow.
|
|
62
|
+
- Operators must treat `mirror version apply` as an externally visible release,
|
|
63
|
+
not a local preparation step.
|
|
64
|
+
- The synchronized-main gate becomes mandatory; failures stop before apply.
|
|
65
|
+
- Existing GitHub rulesets, environment review, and OIDC remain the enforcement
|
|
66
|
+
layers for branch, tag, and package publication.
|
|
67
|
+
|
|
68
|
+
## Reversal Or Revisit Conditions
|
|
69
|
+
|
|
70
|
+
Return to `push = false` if Mirror cannot push through repository protections
|
|
71
|
+
reliably, if releases need a separate staging phase, or if automatic tag
|
|
72
|
+
publication creates unacceptable operational risk.
|
|
73
|
+
|
|
74
|
+
## Follow-up Work
|
|
75
|
+
|
|
76
|
+
- Update repository instructions and XDocs metadata.
|
|
77
|
+
- Validate resolved Mirror configuration and a read-only patch plan.
|
|
78
|
+
- Deliver the configuration through protected `main` without applying another
|
|
79
|
+
release.
|
|
80
|
+
|
|
81
|
+
## References
|
|
82
|
+
|
|
83
|
+
- [Citty CLI Migration Plan](../plans/citty-cli-migration.md)
|
|
84
|
+
- [npm Trusted Publishing Decision](npm-trusted-publishing.md)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Windows Self-Upgrade
|
|
3
|
+
purpose: Define synchronous and recoverable replacement of the running RunX executable on Windows.
|
|
4
|
+
description: Records the accepted Windows executable-swap, verification, rollback, cleanup, testing, and patch-release behavior.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- accepted
|
|
8
|
+
- implemented
|
|
9
|
+
tags:
|
|
10
|
+
- decisions
|
|
11
|
+
- cli
|
|
12
|
+
- windows
|
|
13
|
+
keywords:
|
|
14
|
+
- runx upgrade
|
|
15
|
+
- windows self-upgrade
|
|
16
|
+
- executable replacement
|
|
17
|
+
- rollback
|
|
18
|
+
owner: runx-decisions
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# RunX Windows Self-Upgrade
|
|
22
|
+
|
|
23
|
+
## Context
|
|
24
|
+
|
|
25
|
+
RunX 0.2.5 downloads a Windows update to `runx.exe.new`, starts a detached
|
|
26
|
+
`cmd.exe` process, reports `scheduled: true`, and exits without confirming that
|
|
27
|
+
the installed executable was replaced. The detached move can fail silently and
|
|
28
|
+
leave later invocations on the previous version.
|
|
29
|
+
|
|
30
|
+
Windows permits the running executable to be renamed while its image remains
|
|
31
|
+
mapped. A new executable can then be installed at the original path before the
|
|
32
|
+
current RunX process exits. Only deletion of the renamed, still-running image
|
|
33
|
+
must wait until the process releases it.
|
|
34
|
+
|
|
35
|
+
## Decision
|
|
36
|
+
|
|
37
|
+
`runx upgrade` on Windows will complete the executable swap synchronously:
|
|
38
|
+
|
|
39
|
+
1. Download the selected release asset to `runx.exe.new`.
|
|
40
|
+
2. Remove any stale backup that is not in use.
|
|
41
|
+
3. Rename the installed `runx.exe` to `runx.exe.old`.
|
|
42
|
+
4. Rename `runx.exe.new` to the canonical installed path.
|
|
43
|
+
5. Execute the newly installed path with `--version` and require the expected
|
|
44
|
+
target version and a zero exit code.
|
|
45
|
+
6. If installation or verification fails, remove the failed replacement and
|
|
46
|
+
restore `runx.exe.old` to the canonical path.
|
|
47
|
+
7. After successful verification, delete the backup immediately when possible;
|
|
48
|
+
when Windows still locks the running image, schedule only that backup cleanup
|
|
49
|
+
for after the current process exits.
|
|
50
|
+
|
|
51
|
+
The upgrade result reports `scheduled: false`. Deferred deletion of the old,
|
|
52
|
+
renamed image is cleanup and does not defer or weaken successful replacement.
|
|
53
|
+
|
|
54
|
+
## Error Handling
|
|
55
|
+
|
|
56
|
+
- A replacement failure must throw a concise `RunXError` and produce a non-zero
|
|
57
|
+
CLI exit code.
|
|
58
|
+
- Rollback must be attempted whenever the installed executable was renamed but
|
|
59
|
+
the new executable was not verified.
|
|
60
|
+
- If rollback also fails, the error must report both the replacement and
|
|
61
|
+
recovery failures and identify the affected installed path.
|
|
62
|
+
- The `.new` file must be removed after failures and must not remain after a
|
|
63
|
+
successful rename.
|
|
64
|
+
- A locked stale `.old` file must stop a new upgrade before the current
|
|
65
|
+
executable is modified.
|
|
66
|
+
|
|
67
|
+
## Testing
|
|
68
|
+
|
|
69
|
+
Automated coverage must prove that:
|
|
70
|
+
|
|
71
|
+
- the configured Windows self path contains the downloaded replacement before
|
|
72
|
+
`upgradeSelf()` resolves;
|
|
73
|
+
- successful Windows upgrades report `scheduled: false`;
|
|
74
|
+
- no `.new` file remains after success;
|
|
75
|
+
- a failed replacement restores the original executable;
|
|
76
|
+
- the equal-version no-op remains unchanged;
|
|
77
|
+
- `runx -h` continues to work outside a manifest directory.
|
|
78
|
+
|
|
79
|
+
The full release gate is `bun run typecheck`, `bun test`, `bun run build`,
|
|
80
|
+
`bun run binary`, `bun run binaries`, and strict XDocs validation.
|
|
81
|
+
|
|
82
|
+
## Release
|
|
83
|
+
|
|
84
|
+
After implementation and validation, use Mirror to plan and apply the next
|
|
85
|
+
patch. Update the changelog before applying the Mirror-managed version. Do not
|
|
86
|
+
hand-edit the package version or create the release tag manually.
|
|
87
|
+
|
|
88
|
+
## Acceptance Criteria
|
|
89
|
+
|
|
90
|
+
- When `runx upgrade` succeeds, the executable at the installed path is already
|
|
91
|
+
the target release.
|
|
92
|
+
- A same-terminal or new-terminal invocation immediately reports the target
|
|
93
|
+
version.
|
|
94
|
+
- The command never reports `scheduled: true` for upgrade replacement.
|
|
95
|
+
- Replacement and verification failures are visible and recover the old binary.
|
|
96
|
+
- Temporary update files are cleaned up safely.
|
|
97
|
+
- Issue #9 has automated Windows regression coverage and issue #1 remains
|
|
98
|
+
covered by the Citty help tests.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Mirror Automatic Push Plan
|
|
3
|
+
purpose: Execute the accepted push=true release policy through protected main without creating another release.
|
|
4
|
+
description: Sequences configuration, safety instructions, XDocs validation, protected delivery, and post-merge verification.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- approved
|
|
8
|
+
tags:
|
|
9
|
+
- plans
|
|
10
|
+
- release
|
|
11
|
+
- mirror
|
|
12
|
+
keywords:
|
|
13
|
+
- runx
|
|
14
|
+
- mirror push
|
|
15
|
+
- protected main
|
|
16
|
+
- configuration
|
|
17
|
+
owner: runx-plans
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# RunX Mirror Automatic Push Plan
|
|
21
|
+
|
|
22
|
+
## Source Decision
|
|
23
|
+
|
|
24
|
+
- [RunX Mirror Automatic Release Push](../decisions/mirror-automatic-push.md)
|
|
25
|
+
|
|
26
|
+
## Unit 1: Configure And Document Automatic Push
|
|
27
|
+
|
|
28
|
+
- Goal: Make automatic release pushing a repository-owned Mirror policy.
|
|
29
|
+
- Owner: RunX repository.
|
|
30
|
+
- Dependencies: Accepted automatic-push decision; `0.2.4` already applied and
|
|
31
|
+
pushed, so this change must not apply another version.
|
|
32
|
+
- Files:
|
|
33
|
+
- `mirror.config.toml`
|
|
34
|
+
- `AGENTS.md`
|
|
35
|
+
- `runx.xdocs.md`
|
|
36
|
+
- Data, auth, and cache: No application data, authentication, authorization, or
|
|
37
|
+
cache impact. GitHub credentials and rulesets remain external.
|
|
38
|
+
- Changes:
|
|
39
|
+
- Set `[git].push = true`.
|
|
40
|
+
- Require clean synchronized `main` before `mirror version apply`.
|
|
41
|
+
- Document that apply is an externally visible release mutation.
|
|
42
|
+
- Checks:
|
|
43
|
+
- `mirror config check`
|
|
44
|
+
- `mirror config show`
|
|
45
|
+
- `mirror version plan patch --format json`
|
|
46
|
+
- Verify the plan reports `pushEnabled: true` and next patch `0.2.5` without
|
|
47
|
+
applying it.
|
|
48
|
+
- Strict root XDocs metadata and doctor checks.
|
|
49
|
+
- Acceptance: The resolved config enables push; safety guidance prevents apply
|
|
50
|
+
from a feature branch or stale main; no version, commit, or tag is created by
|
|
51
|
+
validation.
|
|
52
|
+
- Stop conditions: Stop if Mirror cannot load the config, the read-only plan
|
|
53
|
+
mutates state, or the worktree contains unrelated changes.
|
|
54
|
+
|
|
55
|
+
## Unit 2: Deliver Through Protected Main
|
|
56
|
+
|
|
57
|
+
- Goal: Merge the configuration policy without bypassing required CI.
|
|
58
|
+
- Dependencies: Unit 1 complete and committed.
|
|
59
|
+
- Delivery:
|
|
60
|
+
- Push `codex/mirror-auto-push`.
|
|
61
|
+
- Open a ready pull request to `main`.
|
|
62
|
+
- Wait for required CI and merge through the repository ruleset.
|
|
63
|
+
- Synchronize local `main` and confirm `mirror config show` reports
|
|
64
|
+
`push: true`.
|
|
65
|
+
- Acceptance: `origin/main` owns the configuration and instructions; no new
|
|
66
|
+
release tag was created.
|
|
67
|
+
- Stop conditions: Stop on CI failure, unresolved protection failure, or an
|
|
68
|
+
unexpected version/tag mutation.
|
|
69
|
+
|
|
70
|
+
## TODO Alignment
|
|
71
|
+
|
|
72
|
+
This is a bounded owner-approved configuration change completed in one session;
|
|
73
|
+
it does not require a separate TODO entry.
|
|
74
|
+
|
|
75
|
+
## First Executable Unit
|
|
76
|
+
|
|
77
|
+
Unit 1: set and document the resolved Mirror automatic-push policy.
|
|
@@ -6,17 +6,23 @@ children: []
|
|
|
6
6
|
files:
|
|
7
7
|
alpha-implementation.md: Breaks the accepted alpha into implementation and validation units.
|
|
8
8
|
citty-cli-migration.md: Executes the full Citty command-tree migration, compatibility validation, protected delivery, and patch release.
|
|
9
|
+
mirror-automatic-push.md: Enables automatic Mirror release pushes with a synchronized protected-main safety gate.
|
|
9
10
|
npm-trusted-publishing-release.md: Sequences workflow implementation, protected delivery, Mirror patching, and public trusted-publishing verification.
|
|
11
|
+
windows-self-upgrade.md: Sequences synchronous Windows replacement, rollback coverage, validation, issue closure, and patch delivery.
|
|
10
12
|
documents:
|
|
11
13
|
alpha-implementation.md: Plan used for the initial RunX implementation.
|
|
12
14
|
citty-cli-migration.md: Active plan for replacing handwritten CLI parsing and routing with Citty and delivering its patch release.
|
|
15
|
+
mirror-automatic-push.md: Approved plan for configuring, validating, and merging Mirror push=true without applying another release.
|
|
13
16
|
npm-trusted-publishing-release.md: Approved executable plan for the RunX 0.2.1 trusted-publishing release trial.
|
|
17
|
+
windows-self-upgrade.md: Approved executable plan for fixing Windows native self-upgrade and delivering its patch.
|
|
14
18
|
tags:
|
|
15
19
|
- plans
|
|
16
20
|
keywords:
|
|
17
21
|
- runx
|
|
18
22
|
- implementation
|
|
19
23
|
- citty
|
|
24
|
+
- mirror push
|
|
25
|
+
- windows self-upgrade
|
|
20
26
|
flags: []
|
|
21
27
|
status: stable
|
|
22
28
|
---
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Windows Self-Upgrade Plan
|
|
3
|
+
purpose: Execute the accepted synchronous and recoverable Windows self-upgrade design.
|
|
4
|
+
description: Sequences executable replacement, regression coverage, documentation, validation, issue closure, and the next Mirror patch.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- approved
|
|
8
|
+
- executed
|
|
9
|
+
tags:
|
|
10
|
+
- plans
|
|
11
|
+
- cli
|
|
12
|
+
- windows
|
|
13
|
+
keywords:
|
|
14
|
+
- runx upgrade
|
|
15
|
+
- executable replacement
|
|
16
|
+
- rollback
|
|
17
|
+
- patch release
|
|
18
|
+
owner: runx-plans
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# RunX Windows Self-Upgrade Plan
|
|
22
|
+
|
|
23
|
+
## Sources
|
|
24
|
+
|
|
25
|
+
- [Windows Self-Upgrade Decision](../decisions/windows-self-upgrade.md)
|
|
26
|
+
- [Alpha Command Catalog Requirements](../requirements/alpha-command-catalog.md)
|
|
27
|
+
- [CLI Architecture](../architecture/cli-architecture.md)
|
|
28
|
+
- GitHub issues `CGuiho/runx#9` and `CGuiho/runx#1`
|
|
29
|
+
|
|
30
|
+
## Unit 1: Replace the Windows Executable Synchronously
|
|
31
|
+
|
|
32
|
+
- Goal: Make `upgradeSelf()` return successfully only after the canonical
|
|
33
|
+
Windows executable path contains and runs the target release.
|
|
34
|
+
- Owner: `C:\GUIHO\runx`.
|
|
35
|
+
- Dependencies: Accepted Windows self-upgrade decision.
|
|
36
|
+
- Files:
|
|
37
|
+
- `source/self-management.ts`
|
|
38
|
+
- `source/types.ts` only if the result contract must change
|
|
39
|
+
- Behavior:
|
|
40
|
+
- Download to `.new`, rename the installed executable to `.old`, install the
|
|
41
|
+
new file at the original path, and verify `<self-path> --version`.
|
|
42
|
+
- Return `scheduled: false` after verified replacement.
|
|
43
|
+
- On failure, remove the failed target, restore `.old`, remove `.new`, and
|
|
44
|
+
return a non-zero `RunXError` with recovery context.
|
|
45
|
+
- Delete `.old` immediately when possible; defer only deletion of the locked
|
|
46
|
+
old image after the current process exits.
|
|
47
|
+
- Data/schema, auth, permissions, and cache: No application data, schema,
|
|
48
|
+
authentication, authorization, or cache impact. Filesystem write permission
|
|
49
|
+
to the installed executable remains required.
|
|
50
|
+
- Acceptance: The installed path is the verified target before
|
|
51
|
+
`upgradeSelf()` resolves and no `.new` file remains.
|
|
52
|
+
- Stop conditions: Stop if Windows cannot rename the running executable, the
|
|
53
|
+
target cannot be verified, rollback cannot restore the installed path, or
|
|
54
|
+
unrelated self-management behavior changes.
|
|
55
|
+
|
|
56
|
+
## Unit 2: Add Regression Coverage
|
|
57
|
+
|
|
58
|
+
- Goal: Prove the fixed upgrade contract and preserve the already-correct help
|
|
59
|
+
behavior from issue #1.
|
|
60
|
+
- Dependencies: Unit 1 complete.
|
|
61
|
+
- Files:
|
|
62
|
+
- `source/guiho-runx.spec.ts` or a focused colocated self-management spec
|
|
63
|
+
- existing `source/cli.spec.ts` only if help coverage needs correction
|
|
64
|
+
- Checks:
|
|
65
|
+
- Mock the GitHub latest-release response and downloaded Windows binary.
|
|
66
|
+
- Configure `RUNX_SELF_PATH` to an isolated executable path.
|
|
67
|
+
- Assert the replacement exists at that path before the promise resolves,
|
|
68
|
+
reports `scheduled: false`, runs as the expected version, and leaves no
|
|
69
|
+
`.new` file.
|
|
70
|
+
- Force verification failure and assert restoration of the original file.
|
|
71
|
+
- Run the existing `-h`/`--help` tests outside a manifest directory.
|
|
72
|
+
- Acceptance: Windows CI exercises success and rollback; issue #1 remains
|
|
73
|
+
covered without changing its implemented behavior.
|
|
74
|
+
- Stop conditions: Stop on nondeterministic process cleanup, leaked test
|
|
75
|
+
processes, platform-dependent assertions on non-Windows runners, or failure
|
|
76
|
+
to restore global fetch/environment state.
|
|
77
|
+
|
|
78
|
+
## Unit 3: Align Documentation and Validate
|
|
79
|
+
|
|
80
|
+
- Goal: Make public and structured documentation describe completed rather than
|
|
81
|
+
scheduled Windows replacement, then pass the full release gate.
|
|
82
|
+
- Dependencies: Units 1 and 2 complete.
|
|
83
|
+
- Files:
|
|
84
|
+
- `DOCS.md`
|
|
85
|
+
- `source/source.xdocs.md`
|
|
86
|
+
- `runx.xdocs.md`
|
|
87
|
+
- accepted decision and plan lifecycle flags when implementation completes
|
|
88
|
+
- Checks:
|
|
89
|
+
- `bun run typecheck`
|
|
90
|
+
- `bun test`
|
|
91
|
+
- `bun run build`
|
|
92
|
+
- `bun run binary`
|
|
93
|
+
- `bun run binaries`
|
|
94
|
+
- `xdocs meta . --documents --strict --owner runx --format json`
|
|
95
|
+
- `xdocs doctor . --warnings-as-errors --format json`
|
|
96
|
+
- `git diff --check`
|
|
97
|
+
- Acceptance: All checks pass, docs agree with behavior, and the worktree
|
|
98
|
+
contains only understood task changes.
|
|
99
|
+
- Stop conditions: Stop on any failed validation or unexpected worktree change.
|
|
100
|
+
|
|
101
|
+
## Unit 4: Close Issues and Apply the Patch
|
|
102
|
+
|
|
103
|
+
- Goal: Close both resolved GitHub issues and publish the next
|
|
104
|
+
Mirror-managed patch state.
|
|
105
|
+
- Dependencies: Unit 3 committed and the worktree clean.
|
|
106
|
+
- Sequence:
|
|
107
|
+
- Confirm issue #9 acceptance evidence and issue #1 Citty regression evidence.
|
|
108
|
+
- Close issues #9 and #1 with concise resolution comments.
|
|
109
|
+
- Run `mirror config show` and `mirror version plan patch`.
|
|
110
|
+
- Update the configured changelog with the planned next version and commit
|
|
111
|
+
release preparation.
|
|
112
|
+
- Run the full typecheck/test gate again if release preparation changes any
|
|
113
|
+
executable inputs.
|
|
114
|
+
- Apply `mirror version apply patch --yes`; allow configured commit/push/tag
|
|
115
|
+
behavior and do not hand-edit Mirror-managed fields.
|
|
116
|
+
- Acceptance: Both issues are closed, the changelog records the fix, and
|
|
117
|
+
package version, release commit, tag, and configured remote push agree.
|
|
118
|
+
- Stop conditions: Stop if an issue acceptance criterion is unproved, Mirror
|
|
119
|
+
plans an unexpected version, validation fails, or protected push is rejected.
|
|
120
|
+
|
|
121
|
+
## TODO Alignment
|
|
122
|
+
|
|
123
|
+
This is one approved, focused execution session. No additional durable TODO
|
|
124
|
+
entry or delegated component task is required.
|
|
125
|
+
|
|
126
|
+
## First Executable Unit
|
|
127
|
+
|
|
128
|
+
Unit 1: implement synchronous Windows replacement and rollback in
|
|
129
|
+
`source/self-management.ts`.
|
|
@@ -5,8 +5,10 @@ parent: runx-reviews
|
|
|
5
5
|
children: []
|
|
6
6
|
files:
|
|
7
7
|
citty-cli-migration-review.md: Reviews the implemented Citty command tree, compatibility adapter, tests, documentation, packaging, and release readiness.
|
|
8
|
+
windows-self-upgrade-review.md: Reviews synchronous Windows replacement, rollback, cleanup, tests, CI coverage, and release readiness.
|
|
8
9
|
documents:
|
|
9
10
|
citty-cli-migration-review.md: Accepted implementation review for the full Citty CLI migration.
|
|
11
|
+
windows-self-upgrade-review.md: Accepted implementation review for the Windows native self-upgrade fix.
|
|
10
12
|
tags:
|
|
11
13
|
- reviews
|
|
12
14
|
- implementation
|
|
@@ -14,6 +16,7 @@ keywords:
|
|
|
14
16
|
- runx
|
|
15
17
|
- citty
|
|
16
18
|
- implementation review
|
|
19
|
+
- windows self-upgrade
|
|
17
20
|
flags: []
|
|
18
21
|
status: stable
|
|
19
22
|
---
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Windows Self-Upgrade Implementation Review
|
|
3
|
+
purpose: Review the implemented Windows self-upgrade fix against its accepted decision and plan.
|
|
4
|
+
description: Confirms synchronous replacement, target verification, rollback, cleanup, tests, CI coverage, documentation, and release readiness.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- accepted
|
|
8
|
+
tags:
|
|
9
|
+
- reviews
|
|
10
|
+
- implementation
|
|
11
|
+
- windows
|
|
12
|
+
keywords:
|
|
13
|
+
- runx upgrade
|
|
14
|
+
- executable replacement
|
|
15
|
+
- rollback
|
|
16
|
+
- windows ci
|
|
17
|
+
owner: runx-implementation-reviews
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# RunX Windows Self-Upgrade Implementation Review
|
|
21
|
+
|
|
22
|
+
## Verdict
|
|
23
|
+
|
|
24
|
+
Accepted. No blocker, high, medium, or low findings remain.
|
|
25
|
+
|
|
26
|
+
## Findings
|
|
27
|
+
|
|
28
|
+
No actionable findings. The implementation matches the approved synchronous
|
|
29
|
+
replacement and recovery design without changing manifest execution, Citty
|
|
30
|
+
routing, uninstall behavior, or non-Windows upgrade behavior.
|
|
31
|
+
|
|
32
|
+
## Acceptance Criteria
|
|
33
|
+
|
|
34
|
+
- `upgradeSelf()` renames the running Windows executable, installs the
|
|
35
|
+
downloaded target at the canonical path, and awaits `<path> --version`.
|
|
36
|
+
- Successful Windows upgrade results report `scheduled: false`.
|
|
37
|
+
- Verification failures remove the invalid replacement and restore `.old`.
|
|
38
|
+
- `.new` is absent after success and rollback.
|
|
39
|
+
- Cleanup retries deletion of the locked `.old` image after the old process
|
|
40
|
+
releases it.
|
|
41
|
+
- A Windows-only test holds a real copied executable open during replacement,
|
|
42
|
+
verifies the new binary at the canonical path before completion, and observes
|
|
43
|
+
backup cleanup.
|
|
44
|
+
- A second Windows test proves rollback after invalid-binary verification.
|
|
45
|
+
- Existing Citty tests continue to prove `-h` and `--help` outside a manifest.
|
|
46
|
+
- The GitHub workflow now runs typecheck, tests, build, and native compilation
|
|
47
|
+
on `windows-latest` in addition to the existing Linux release-matrix gate.
|
|
48
|
+
|
|
49
|
+
## Verification Evidence
|
|
50
|
+
|
|
51
|
+
- `bun run typecheck`: passed.
|
|
52
|
+
- `bun test`: 15 passed, 0 failed, 134 assertions.
|
|
53
|
+
- `bun run build`: passed.
|
|
54
|
+
- `bun run binary`: passed.
|
|
55
|
+
- `bun run binaries`: twelve native assets built and verified.
|
|
56
|
+
- Windows x64 native `-h` outside a manifest: passed.
|
|
57
|
+
- Windows x64 native `--version`: reported `0.2.5` before the release bump.
|
|
58
|
+
- CI workflow YAML parse: passed.
|
|
59
|
+
- `xdocs doctor . --warnings-as-errors --format json`: 0 errors, 0 warnings.
|
|
60
|
+
- `git diff --check`: passed.
|
|
61
|
+
|
|
62
|
+
## Documentation and TODO
|
|
63
|
+
|
|
64
|
+
`DOCS.md`, source/root/workflow XDocs descriptors, the accepted decision, plan,
|
|
65
|
+
plan review, this implementation review, and validation evidence are aligned.
|
|
66
|
+
No TODO entry is needed for this completed single-session fix.
|
|
67
|
+
|
|
68
|
+
## Residual Risk
|
|
69
|
+
|
|
70
|
+
The new `windows-latest` job cannot execute until the committed workflow reaches
|
|
71
|
+
GitHub. Local Windows coverage exercises the same live-file replacement and
|
|
72
|
+
cleanup behavior. Public upgrade from 0.2.0 to the new patch can only be verified
|
|
73
|
+
after the patch release assets exist.
|
|
74
|
+
|
|
75
|
+
## References
|
|
76
|
+
|
|
77
|
+
- [Decision](../../decisions/windows-self-upgrade.md)
|
|
78
|
+
- [Plan](../../plans/windows-self-upgrade.md)
|
|
79
|
+
- [Plan Review](../plans/windows-self-upgrade-review.md)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Mirror Automatic Push Plan Review
|
|
3
|
+
purpose: Verify that the automatic-push configuration plan is safe, bounded, and ready for execution.
|
|
4
|
+
description: Reviews synchronized-main safeguards, read-only validation, protected delivery, and release side effects.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- approved
|
|
8
|
+
tags:
|
|
9
|
+
- reviews
|
|
10
|
+
- plans
|
|
11
|
+
- release
|
|
12
|
+
keywords:
|
|
13
|
+
- runx
|
|
14
|
+
- mirror push
|
|
15
|
+
- plan review
|
|
16
|
+
- protected main
|
|
17
|
+
owner: runx-plan-reviews
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# RunX Mirror Automatic Push Plan Review
|
|
21
|
+
|
|
22
|
+
## Verdict
|
|
23
|
+
|
|
24
|
+
Ready for execution.
|
|
25
|
+
|
|
26
|
+
## Findings
|
|
27
|
+
|
|
28
|
+
- No blocker or high-severity findings remain.
|
|
29
|
+
- The clean, synchronized `main` precondition is explicit and prevents a
|
|
30
|
+
release tag from pointing at an unmerged feature or stale commit.
|
|
31
|
+
- Unit 1 uses only read-only Mirror validation and explicitly prohibits another
|
|
32
|
+
version apply, so the current `0.2.4` release remains unchanged.
|
|
33
|
+
- The plan documents that `push = true` makes every future Mirror apply an
|
|
34
|
+
externally visible release mutation.
|
|
35
|
+
- No application data, authentication, authorization, or cache behavior is
|
|
36
|
+
affected. GitHub credentials, rulesets, environment approval, and npm OIDC
|
|
37
|
+
remain external enforcement layers.
|
|
38
|
+
|
|
39
|
+
## Delivery Review
|
|
40
|
+
|
|
41
|
+
- The configuration change must pass the protected pull-request workflow
|
|
42
|
+
before reaching `main`.
|
|
43
|
+
- Post-merge verification checks the resolved configuration on synchronized
|
|
44
|
+
`main` and confirms that no `0.2.5` tag was created.
|
|
45
|
+
- A CI failure, protection failure, or unexpected version mutation is an
|
|
46
|
+
explicit stop condition.
|
|
47
|
+
|
|
48
|
+
## First Executable Unit
|
|
49
|
+
|
|
50
|
+
Execute Unit 1 in
|
|
51
|
+
[RunX Mirror Automatic Push Plan](../../plans/mirror-automatic-push.md): set and
|
|
52
|
+
document the resolved automatic-push policy without applying a release.
|
|
53
|
+
|
|
54
|
+
## References
|
|
55
|
+
|
|
56
|
+
- [RunX Mirror Automatic Push Plan](../../plans/mirror-automatic-push.md)
|
|
57
|
+
- [RunX Mirror Automatic Release Push](../../decisions/mirror-automatic-push.md)
|
|
@@ -5,10 +5,14 @@ parent: runx-reviews
|
|
|
5
5
|
children: []
|
|
6
6
|
files:
|
|
7
7
|
citty-cli-migration-review.md: Reviews completeness, compatibility, safety invariants, native packaging, and release sequencing for the Citty migration.
|
|
8
|
+
mirror-automatic-push-review.md: Reviews synchronized-main safeguards, read-only validation, protected delivery, and release side effects.
|
|
8
9
|
npm-trusted-publishing-release-review.md: Reviews sequencing, acceptance criteria, safety gates, and validation for the RunX 0.2.1 trusted-publishing plan.
|
|
10
|
+
windows-self-upgrade-review.md: Reviews synchronous replacement, rollback, regression coverage, issue closure, and patch delivery.
|
|
9
11
|
documents:
|
|
10
12
|
citty-cli-migration-review.md: Ready-for-execution review of the full Citty CLI migration plan.
|
|
13
|
+
mirror-automatic-push-review.md: Ready-for-execution review of the Mirror automatic-push configuration plan.
|
|
11
14
|
npm-trusted-publishing-release-review.md: Ready-for-execution review of the npm trusted-publishing release plan.
|
|
15
|
+
windows-self-upgrade-review.md: Ready-for-execution review of the Windows native self-upgrade fix plan.
|
|
12
16
|
tags:
|
|
13
17
|
- reviews
|
|
14
18
|
- plans
|
|
@@ -16,7 +20,9 @@ keywords:
|
|
|
16
20
|
- runx
|
|
17
21
|
- plan review
|
|
18
22
|
- citty
|
|
23
|
+
- mirror push
|
|
19
24
|
- trusted publishing
|
|
25
|
+
- windows self-upgrade
|
|
20
26
|
flags: []
|
|
21
27
|
status: stable
|
|
22
28
|
---
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Windows Self-Upgrade Plan Review
|
|
3
|
+
purpose: Verify that the Windows self-upgrade plan is safe, complete, and executable.
|
|
4
|
+
description: Reviews replacement sequencing, rollback, tests, documentation, issue closure, and Mirror patch delivery.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- approved
|
|
8
|
+
tags:
|
|
9
|
+
- reviews
|
|
10
|
+
- plans
|
|
11
|
+
- windows
|
|
12
|
+
keywords:
|
|
13
|
+
- runx upgrade
|
|
14
|
+
- executable replacement
|
|
15
|
+
- rollback
|
|
16
|
+
- mirror patch
|
|
17
|
+
owner: runx-plan-reviews
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# RunX Windows Self-Upgrade Plan Review
|
|
21
|
+
|
|
22
|
+
## Verdict
|
|
23
|
+
|
|
24
|
+
Ready for execution.
|
|
25
|
+
|
|
26
|
+
## Findings
|
|
27
|
+
|
|
28
|
+
No blocker, high, medium, or low findings remain. The plan traces to the accepted
|
|
29
|
+
Windows self-upgrade decision and existing native-upgrade requirement. Each unit
|
|
30
|
+
has a bounded outcome, named files, dependencies, acceptance criteria, checks,
|
|
31
|
+
and explicit stop conditions.
|
|
32
|
+
|
|
33
|
+
## Sequencing and Failure Safety
|
|
34
|
+
|
|
35
|
+
- Replacement precedes verification, and successful completion requires the
|
|
36
|
+
canonical path to execute the expected target version.
|
|
37
|
+
- Rollback occurs before any failure is surfaced after the old executable was
|
|
38
|
+
renamed.
|
|
39
|
+
- Deferred work is limited to deleting the locked old image; replacement itself
|
|
40
|
+
is complete before success.
|
|
41
|
+
- Issue closure and Mirror application follow implementation validation and a
|
|
42
|
+
clean committed worktree.
|
|
43
|
+
- The plan recognizes configured Mirror commit, push, and tag side effects and
|
|
44
|
+
stops on protected-push rejection.
|
|
45
|
+
|
|
46
|
+
## Coverage Review
|
|
47
|
+
|
|
48
|
+
- Success, failure, rollback, temporary-file cleanup, and platform isolation are
|
|
49
|
+
explicit.
|
|
50
|
+
- Existing `-h` coverage directly supports closing issue #1.
|
|
51
|
+
- Typecheck, unit tests, library build, local binary, the twelve-target matrix,
|
|
52
|
+
strict XDocs checks, and diff hygiene are included.
|
|
53
|
+
- No route, API, UI, data schema, authentication, authorization, cache, cloud,
|
|
54
|
+
secret, or database work is in scope.
|
|
55
|
+
|
|
56
|
+
## TODO and Documentation Alignment
|
|
57
|
+
|
|
58
|
+
The work is a single focused package session and does not need a long-running
|
|
59
|
+
TODO entry. Public `DOCS.md`, source/root XDocs descriptors, lifecycle records,
|
|
60
|
+
and the changelog are included in the correct sequence.
|
|
61
|
+
|
|
62
|
+
## First Executable Unit
|
|
63
|
+
|
|
64
|
+
Implement synchronous replacement, target-version verification, rollback, and
|
|
65
|
+
old-image cleanup in `source/self-management.ts`.
|
|
66
|
+
|
|
67
|
+
## References
|
|
68
|
+
|
|
69
|
+
- [Plan](../../plans/windows-self-upgrade.md)
|
|
70
|
+
- [Decision](../../decisions/windows-self-upgrade.md)
|
|
71
|
+
- [CLI Architecture](../../architecture/cli-architecture.md)
|
|
@@ -6,10 +6,12 @@ children: []
|
|
|
6
6
|
files:
|
|
7
7
|
alpha-implementation-summary.md: Records the completed alpha implementation, checks, and release boundaries.
|
|
8
8
|
citty-cli-migration.md: Records the complete local validation gate for the Citty command-tree migration.
|
|
9
|
+
windows-self-upgrade.md: Records Windows replacement, rollback, cleanup, native build, CI, and XDocs validation evidence.
|
|
9
10
|
documents:
|
|
10
11
|
alpha-implementation-summary.md: Validation summary for the first RunX implementation.
|
|
11
12
|
citty-cli-migration.md: Validation evidence for TypeScript, tests, native assets, npm packaging, CLI behavior, and XDocs.
|
|
12
13
|
npm-trusted-publishing-0.2.2.md: Validation evidence for the blocked 0.2.2 npm trusted-publishing retry.
|
|
14
|
+
windows-self-upgrade.md: Validation evidence for GitHub issues #9 and #1 and the Windows self-upgrade patch.
|
|
13
15
|
tags:
|
|
14
16
|
- validation
|
|
15
17
|
keywords:
|
|
@@ -17,6 +19,7 @@ keywords:
|
|
|
17
19
|
- citty
|
|
18
20
|
- tests
|
|
19
21
|
- summary
|
|
22
|
+
- windows self-upgrade
|
|
20
23
|
flags: []
|
|
21
24
|
status: stable
|
|
22
25
|
---
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Windows Self-Upgrade Validation
|
|
3
|
+
purpose: Record verification evidence for the Windows self-upgrade fix and issue closure.
|
|
4
|
+
description: Captures Windows replacement and rollback tests, complete Bun build checks, native CLI checks, CI syntax, XDocs health, and residual release risk.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- validated
|
|
8
|
+
tags:
|
|
9
|
+
- validation
|
|
10
|
+
- windows
|
|
11
|
+
- cli
|
|
12
|
+
keywords:
|
|
13
|
+
- runx upgrade
|
|
14
|
+
- windows executable
|
|
15
|
+
- rollback
|
|
16
|
+
- issue 9
|
|
17
|
+
- issue 1
|
|
18
|
+
owner: runx-validation
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# RunX Windows Self-Upgrade Validation
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
|
|
25
|
+
The implementation is ready for commit, issue closure, and the requested
|
|
26
|
+
Mirror-managed patch. All local checks passed on Windows.
|
|
27
|
+
|
|
28
|
+
## Scope
|
|
29
|
+
|
|
30
|
+
- Synchronous Windows replacement of a running native executable.
|
|
31
|
+
- Target-version verification before successful completion.
|
|
32
|
+
- Rollback after invalid replacement verification.
|
|
33
|
+
- Deferred cleanup of the locked old executable only.
|
|
34
|
+
- Existing manifest-free `-h` behavior from issue #1.
|
|
35
|
+
- Windows CI coverage and structured documentation health.
|
|
36
|
+
|
|
37
|
+
## Commands and Results
|
|
38
|
+
|
|
39
|
+
| Check | Result | Evidence |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| `bun run typecheck` | passed | TypeScript completed without diagnostics. |
|
|
42
|
+
| `bun test` | passed | 15 tests, 0 failures, 134 assertions. |
|
|
43
|
+
| `bun run build` | passed | Library output compiled. |
|
|
44
|
+
| `bun run binary` | passed | Local Windows executable compiled. |
|
|
45
|
+
| `bun run binaries` | passed | All twelve release assets built and verified. |
|
|
46
|
+
| Native `runx-windows-x64.exe -h` outside a manifest | passed | Citty usage rendered with exit code 0. |
|
|
47
|
+
| Native `runx-windows-x64.exe --version` | passed | Reported `0.2.5` before the patch bump. |
|
|
48
|
+
| `Bun.YAML.parse(.github/workflows/ci.yml)` | passed | Workflow YAML parsed successfully. |
|
|
49
|
+
| `xdocs meta . --documents --strict --owner runx --format json` | passed | Root metadata and companions valid. |
|
|
50
|
+
| `xdocs doctor . --warnings-as-errors --format json` | passed | 0 errors and 0 warnings. |
|
|
51
|
+
| `git diff --check` | passed | No whitespace errors. |
|
|
52
|
+
|
|
53
|
+
## Behavioral Evidence
|
|
54
|
+
|
|
55
|
+
`source/self-management.spec.ts` runs only on Windows for the platform-specific
|
|
56
|
+
cases. Its success case launches a copied PowerShell executable from the
|
|
57
|
+
configured self path, keeps that executable running, upgrades the same path to
|
|
58
|
+
the current Bun executable, and requires the replacement to report the expected
|
|
59
|
+
version before `upgradeSelf()` resolves. It also observes removal of `.new` and
|
|
60
|
+
eventual removal of `.old` after the running process exits.
|
|
61
|
+
|
|
62
|
+
The rollback case downloads invalid executable bytes, requires verification to
|
|
63
|
+
fail, and confirms that the original bytes are restored with neither `.new` nor
|
|
64
|
+
`.old` left behind.
|
|
65
|
+
|
|
66
|
+
The existing `source/cli.spec.ts` root-help test proves both `-h` and `--help`
|
|
67
|
+
work without a manifest, satisfying issue #1.
|
|
68
|
+
|
|
69
|
+
## Skipped or Blocked Checks
|
|
70
|
+
|
|
71
|
+
- The new GitHub-hosted `windows-latest` job is not locally runnable; it will
|
|
72
|
+
execute after the commit reaches GitHub.
|
|
73
|
+
- An actual 0.2.0-to-new-patch public upgrade is blocked until the new release
|
|
74
|
+
assets are published.
|
|
75
|
+
|
|
76
|
+
## Readiness
|
|
77
|
+
|
|
78
|
+
Ready for commit, closing GitHub issues #9 and #1, changelog preparation, and
|
|
79
|
+
the requested Mirror patch plan/apply sequence.
|
|
80
|
+
|
|
81
|
+
## References
|
|
82
|
+
|
|
83
|
+
- [Implementation Review](../reviews/implementation/windows-self-upgrade-review.md)
|
|
84
|
+
- [Plan](../plans/windows-self-upgrade.md)
|
|
85
|
+
- [Decision](../decisions/windows-self-upgrade.md)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { RunXUpgradeResult, UpdateResult } from './types.js';
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
export { checkForLatestVersion, listAvailableVersions, uninstallSelf, upgradeSelf, };
|
|
3
|
+
declare const checkForLatestVersion: () => Promise<UpdateResult>;
|
|
4
|
+
declare const listAvailableVersions: () => Promise<string[]>;
|
|
5
|
+
declare const upgradeSelf: (dryRun: boolean) => Promise<RunXUpgradeResult>;
|
|
6
|
+
declare const uninstallSelf: (dryRun: boolean) => Promise<{
|
|
6
7
|
executablePath: string;
|
|
7
8
|
scheduled: boolean;
|
|
8
9
|
dryRun: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-management.d.ts","sourceRoot":"","sources":["../source/self-management.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"self-management.d.ts","sourceRoot":"","sources":["../source/self-management.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEjE,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,aAAa,EACb,WAAW,GACZ,CAAA;AAMD,QAAA,MAAM,qBAAqB,QAAa,OAAO,CAAC,YAAY,CAY3D,CAAA;AAED,QAAA,MAAM,qBAAqB,QAAa,OAAO,CAAC,MAAM,EAAE,CAKvD,CAAA;AAED,QAAA,MAAM,WAAW,WAAkB,OAAO,KAAG,OAAO,CAAC,iBAAiB,CAmBrE,CAAA;AAED,QAAA,MAAM,aAAa,WAAkB,OAAO,KAAG,OAAO,CAAC;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAWrH,CAAA"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { Buffer } from 'node:buffer';
|
|
1
2
|
import { chmod, rename, rm } from 'node:fs/promises';
|
|
2
3
|
import { basename } from 'node:path';
|
|
3
4
|
import { RunXError } from './errors.js';
|
|
4
5
|
import { readVersion } from './help.js';
|
|
6
|
+
export { checkForLatestVersion, listAvailableVersions, uninstallSelf, upgradeSelf, };
|
|
5
7
|
const repositoryApi = 'https://api.github.com/repos/CGuiho/runx/releases';
|
|
6
|
-
|
|
8
|
+
const checkForLatestVersion = async () => {
|
|
7
9
|
const currentVersion = readVersion();
|
|
8
10
|
try {
|
|
9
11
|
const response = await fetch(`${repositoryApi}/latest`, { headers: { accept: 'application/vnd.github+json' } });
|
|
@@ -18,14 +20,14 @@ export const checkForLatestVersion = async () => {
|
|
|
18
20
|
return { currentVersion, latestVersion: currentVersion, updateAvailable: false };
|
|
19
21
|
}
|
|
20
22
|
};
|
|
21
|
-
|
|
23
|
+
const listAvailableVersions = async () => {
|
|
22
24
|
const response = await fetch(`${repositoryApi}?per_page=20`, { headers: { accept: 'application/vnd.github+json' } });
|
|
23
25
|
if (!response.ok)
|
|
24
26
|
throw new RunXError(`Could not retrieve RunX releases: HTTP ${response.status}`);
|
|
25
27
|
const releases = await response.json();
|
|
26
28
|
return releases.map((release) => release.tag_name.replace(/^@guiho\/runx@/, '').replace(/^v/, ''));
|
|
27
29
|
};
|
|
28
|
-
|
|
30
|
+
const upgradeSelf = async (dryRun) => {
|
|
29
31
|
const executablePath = requireNativeExecutable();
|
|
30
32
|
const update = await checkForLatestVersion();
|
|
31
33
|
const upToDate = !update.updateAvailable && update.latestVersion === update.currentVersion && Boolean(update.url);
|
|
@@ -43,10 +45,10 @@ export const upgradeSelf = async (dryRun) => {
|
|
|
43
45
|
await rename(temporaryPath, executablePath);
|
|
44
46
|
return { ...update, executablePath, scheduled: false, upToDate: false };
|
|
45
47
|
}
|
|
46
|
-
|
|
47
|
-
return { ...update, executablePath, scheduled:
|
|
48
|
+
await replaceWindowsExecutable(temporaryPath, executablePath, update.latestVersion);
|
|
49
|
+
return { ...update, executablePath, scheduled: false, upToDate: false };
|
|
48
50
|
};
|
|
49
|
-
|
|
51
|
+
const uninstallSelf = async (dryRun) => {
|
|
50
52
|
const executablePath = requireNativeExecutable();
|
|
51
53
|
if (dryRun)
|
|
52
54
|
return { executablePath, scheduled: false, dryRun: true };
|
|
@@ -66,10 +68,65 @@ const requireNativeExecutable = () => {
|
|
|
66
68
|
throw new RunXError('Self-management requires a native RunX executable installed from a GitHub release.');
|
|
67
69
|
return executablePath;
|
|
68
70
|
};
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
|
|
71
|
+
const replaceWindowsExecutable = async (temporaryPath, executablePath, expectedVersion) => {
|
|
72
|
+
const backupPath = `${executablePath}.old`;
|
|
73
|
+
let originalMoved = false;
|
|
74
|
+
try {
|
|
75
|
+
await rm(backupPath, { force: true });
|
|
76
|
+
await rename(executablePath, backupPath);
|
|
77
|
+
originalMoved = true;
|
|
78
|
+
await rename(temporaryPath, executablePath);
|
|
79
|
+
await verifyExecutableVersion(executablePath, expectedVersion);
|
|
80
|
+
await cleanupWindowsBackup(backupPath);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
const replacementFailure = errorMessage(error);
|
|
84
|
+
await rm(temporaryPath, { force: true }).catch(() => undefined);
|
|
85
|
+
if (!originalMoved) {
|
|
86
|
+
throw new RunXError(`Could not replace the Windows RunX executable at ${executablePath}: ${replacementFailure}`);
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await rm(executablePath, { force: true });
|
|
90
|
+
await rename(backupPath, executablePath);
|
|
91
|
+
}
|
|
92
|
+
catch (rollbackError) {
|
|
93
|
+
throw new RunXError(`Windows RunX upgrade failed at ${executablePath}: ${replacementFailure}. Automatic rollback also failed: ${errorMessage(rollbackError)}`);
|
|
94
|
+
}
|
|
95
|
+
throw new RunXError(`Windows RunX upgrade failed; the previous executable was restored at ${executablePath}: ${replacementFailure}`);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const verifyExecutableVersion = async (executablePath, expectedVersion) => {
|
|
99
|
+
const verification = Bun.spawn([executablePath, '--version'], { stdin: 'ignore', stdout: 'pipe', stderr: 'pipe' });
|
|
100
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
101
|
+
new Response(verification.stdout).text(),
|
|
102
|
+
new Response(verification.stderr).text(),
|
|
103
|
+
verification.exited,
|
|
104
|
+
]);
|
|
105
|
+
const actualVersion = stdout.trim();
|
|
106
|
+
if (exitCode !== 0)
|
|
107
|
+
throw new Error(`replacement exited with code ${exitCode}${stderr.trim() ? `: ${stderr.trim()}` : ''}`);
|
|
108
|
+
if (actualVersion !== expectedVersion)
|
|
109
|
+
throw new Error(`replacement reported version ${actualVersion || '<empty>'}; expected ${expectedVersion}`);
|
|
110
|
+
};
|
|
111
|
+
const cleanupWindowsBackup = async (backupPath) => {
|
|
112
|
+
try {
|
|
113
|
+
await rm(backupPath, { force: true });
|
|
114
|
+
}
|
|
115
|
+
catch { }
|
|
116
|
+
scheduleWindowsBackupCleanup(backupPath);
|
|
117
|
+
};
|
|
118
|
+
const scheduleWindowsBackupCleanup = (backupPath) => {
|
|
119
|
+
const command = 'for ($attempt = 0; $attempt -lt 300; $attempt += 1) { if (-not (Test-Path -LiteralPath $env:RUNX_BACKUP_PATH)) { exit 0 }; try { Remove-Item -LiteralPath $env:RUNX_BACKUP_PATH -Force -ErrorAction Stop; exit 0 } catch { Start-Sleep -Milliseconds 100 } }; exit 1';
|
|
120
|
+
const encodedCommand = Buffer.from(command, 'utf16le').toString('base64');
|
|
121
|
+
Bun.spawn(['cmd.exe', '/d', '/s', '/c', `powershell.exe -NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -EncodedCommand ${encodedCommand}`], {
|
|
122
|
+
detached: true,
|
|
123
|
+
env: { ...process.env, RUNX_BACKUP_PATH: backupPath },
|
|
124
|
+
stdout: 'ignore',
|
|
125
|
+
stderr: 'ignore',
|
|
126
|
+
stdin: 'ignore',
|
|
127
|
+
});
|
|
72
128
|
};
|
|
129
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
73
130
|
const compareVersions = (left, right) => {
|
|
74
131
|
const parse = (value) => value.split(/[.+-]/).map((part) => Number.parseInt(part, 10) || 0);
|
|
75
132
|
const a = parse(left);
|
package/package.json
CHANGED