@guiho/runx 0.4.1 → 0.5.2
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 +56 -0
- package/DOCS.md +27 -5
- package/README.md +6 -1
- package/devops/build-binaries.ts +3 -3
- package/devops/devops.xdocs.md +9 -6
- package/devops/extract-release-notes.spec.ts +54 -0
- package/devops/extract-release-notes.ts +40 -0
- package/devops/install.ps1 +29 -6
- package/devops/install.sh +61 -22
- package/devops/installers.spec.ts +162 -5
- package/devops/verify-release-assets.ts +14 -0
- package/docs/architecture/architecture.xdocs.md +2 -1
- package/docs/architecture/cli-architecture.md +18 -9
- package/docs/decisions/decisions.xdocs.md +4 -0
- package/docs/decisions/markdown-release-assets-and-version-scoped-notes.md +84 -0
- package/docs/plans/automatic-agent-maintenance.md +120 -0
- package/docs/plans/linux-installer-latest-release.md +43 -0
- package/docs/plans/plans.xdocs.md +6 -0
- package/docs/plans/platform-aware-startup-greeting.md +43 -0
- package/docs/plans/rfc-0034-cli-compliance-migration.md +17 -8
- package/docs/plans/upgrade-reliability-implementation.md +1 -1
- package/docs/reviews/implementation/automatic-agent-maintenance-review.md +63 -0
- package/docs/reviews/implementation/bash-installer-review.md +42 -0
- package/docs/reviews/implementation/implementation.xdocs.md +14 -0
- package/docs/reviews/implementation/linux-installer-latest-release-review.md +49 -0
- package/docs/reviews/implementation/platform-aware-startup-greeting-review.md +51 -0
- package/docs/reviews/implementation/rfc-0034-cli-compliance-migration-review.md +5 -2
- package/docs/reviews/implementation/unicode-help-tree-review.md +41 -0
- package/docs/reviews/implementation/upgrade-reliability-issue-12-review.md +62 -0
- package/docs/reviews/implementation/upgrade-reliability-issue-13-review.md +63 -0
- package/docs/reviews/plans/automatic-agent-maintenance-review.md +56 -0
- package/docs/reviews/plans/plans.xdocs.md +2 -0
- package/docs/superpowers/specs/2026-07-15-upgrade-reliability-design.md +1 -1
- package/docs/todo/automatic-agent-maintenance-implementation.md +55 -0
- package/docs/todo/automatic-agent-maintenance.md +86 -0
- package/docs/todo/bash-installer.md +45 -0
- package/docs/todo/linux-installer-latest-release.md +47 -0
- package/docs/todo/platform-aware-startup-greeting.md +41 -0
- package/docs/todo/rfc-0034-cli-compliance-migration-implementation.md +7 -2
- package/docs/todo/rfc-0034-cli-compliance-migration.md +7 -3
- package/docs/todo/todo.xdocs.md +14 -0
- package/docs/todo/unicode-help-tree.md +44 -0
- package/docs/todo/upgrade-reliability.md +51 -0
- package/docs/validation/automatic-agent-maintenance.md +63 -0
- package/docs/validation/bash-installer.md +55 -0
- package/docs/validation/linux-installer-latest-release.md +50 -0
- package/docs/validation/platform-aware-startup-greeting.md +50 -0
- package/docs/validation/rfc-0034-cli-compliance-migration.md +10 -4
- package/docs/validation/unicode-help-tree.md +43 -0
- package/docs/validation/upgrade-reliability-issue-12.md +74 -0
- package/docs/validation/upgrade-reliability-issue-13.md +72 -0
- package/docs/validation/upgrade-reliability.md +38 -99
- package/docs/validation/validation.xdocs.md +16 -2
- package/library/agent-maintenance.d.ts +19 -0
- package/library/agent-maintenance.d.ts.map +1 -0
- package/library/agent-maintenance.js +49 -0
- package/library/agents.d.ts +6 -1
- package/library/agents.d.ts.map +1 -1
- package/library/agents.js +58 -11
- package/library/cli.d.ts +2 -1
- package/library/cli.d.ts.map +1 -1
- package/library/cli.js +34 -9
- package/library/recovery.js +1 -1
- package/library/release-catalog.d.ts +2 -1
- package/library/release-catalog.d.ts.map +1 -1
- package/library/release-catalog.js +9 -1
- package/library/storage.d.ts +2 -1
- package/library/storage.d.ts.map +1 -1
- package/library/storage.js +13 -1
- package/package.json +1 -1
- package/skills/guiho-s-runx/SKILL.md +11 -0
- package/skills/guiho-s-runx/guiho-s-runx.xdocs.md +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,62 @@ owner: runx
|
|
|
15
15
|
|
|
16
16
|
# Changelog
|
|
17
17
|
|
|
18
|
+
## 0.5.2 - 2026-07-20
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Changed the Linux/macOS installer to download latest native and agent assets
|
|
23
|
+
through GitHub's stable `releases/latest/download` aliases, avoiding scoped
|
|
24
|
+
package-tag truncation during redirect parsing.
|
|
25
|
+
- Changed the no-argument greeting to report Windows, Linux, or macOS according
|
|
26
|
+
to the runtime operating system.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Migrated RunX release configuration from legacy `mirror.config.toml` to
|
|
31
|
+
`mirror.yaml` while preserving package, commit, tag, push, and changelog
|
|
32
|
+
behavior.
|
|
33
|
+
|
|
34
|
+
## 0.5.1 - 2026-07-19
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- Enforced LF line endings for Bash scripts so Windows checkouts preserve
|
|
39
|
+
portable installer syntax.
|
|
40
|
+
- Gave the detached agent-maintenance integration test an explicit
|
|
41
|
+
platform-appropriate timeout so slower Windows CI runners validate the full
|
|
42
|
+
workflow without changing runtime behavior.
|
|
43
|
+
|
|
44
|
+
## 0.5.0 - 2026-07-19
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- Added silent detached maintenance that keeps both global `guiho-s-runx`
|
|
49
|
+
skill installations current and reconciles one nearest managed `AGENTS.md`
|
|
50
|
+
block without changing foreground output or exit behavior.
|
|
51
|
+
- Added explicit regression coverage for every upgrade recovery outcome,
|
|
52
|
+
executable stable/prerelease installer verification, and the Unicode
|
|
53
|
+
description-aligned command tree.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- `runx upgrade list` now returns the complete published catalog, including
|
|
58
|
+
labeled prereleases, unless pagination is explicitly requested.
|
|
59
|
+
- The Linux/macOS installer and generated recovery commands now use Bash with
|
|
60
|
+
`set -euo pipefail`; canonical documentation no longer invokes `sh`.
|
|
61
|
+
- Release delivery now validates the exact twelve native binaries and two
|
|
62
|
+
Markdown agent assets and uses only the matching changelog version section
|
|
63
|
+
for GitHub Release notes.
|
|
64
|
+
|
|
65
|
+
### Fixed
|
|
66
|
+
|
|
67
|
+
- Fixed `runx upgrade list` and `runx upgrade check` so Citty does not execute
|
|
68
|
+
the parent upgrade action after the selected leaf or append a second JSON
|
|
69
|
+
document.
|
|
70
|
+
- Fixed automatic agent-resource updates to use idempotent atomic writes,
|
|
71
|
+
preserve user-authored instructions, migrate legacy markers, and remain safe
|
|
72
|
+
under concurrent invocations.
|
|
73
|
+
|
|
18
74
|
## 0.4.1 - 2026-07-18
|
|
19
75
|
|
|
20
76
|
### Fixed
|
package/DOCS.md
CHANGED
|
@@ -27,9 +27,11 @@ before Bun is installed.
|
|
|
27
27
|
No arguments prints exactly:
|
|
28
28
|
|
|
29
29
|
```text
|
|
30
|
-
Hello Windows - runx v<version>
|
|
30
|
+
Hello <Windows|Linux|macOS> - runx v<version>
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
+
The platform label matches the runtime operating system.
|
|
34
|
+
|
|
33
35
|
The foreground reads `~/.guiho/runx/cache.json` and never waits for network
|
|
34
36
|
work. A detached worker validates GitHub release data and atomically refreshes
|
|
35
37
|
that cache. When a decoded cache announces an update, RunX prints:
|
|
@@ -99,6 +101,14 @@ Skill install, update, and uninstall default to global scope and target both:
|
|
|
99
101
|
|
|
100
102
|
Use `--local` for the corresponding project-local paths.
|
|
101
103
|
|
|
104
|
+
Ordinary RunX commands schedule a hidden detached worker that compares the
|
|
105
|
+
bundled skill with both global copies and rewrites only missing or stale
|
|
106
|
+
targets. The worker finds the nearest existing `AGENTS.md` from effective
|
|
107
|
+
`--cwd`; when none exists in an ancestor, it creates `AGENTS.md` at effective
|
|
108
|
+
cwd. Reconciliation is atomic, migrates legacy RunX markers, preserves content
|
|
109
|
+
outside managed markers, and is silent when no change is required. Worker
|
|
110
|
+
failures never change foreground output or exit status.
|
|
111
|
+
|
|
102
112
|
Instruction actions manage both `AGENTS.md` and `CLAUDE.md` when both exist,
|
|
103
113
|
the existing one when only one exists, and create `AGENTS.md` when neither
|
|
104
114
|
exists. The exact idempotent boundaries are:
|
|
@@ -114,8 +124,10 @@ names; `agent prompt show <id>` prints only the raw prompt.
|
|
|
114
124
|
## Upgrade And Installation
|
|
115
125
|
|
|
116
126
|
`runx upgrade` accepts `--version`, `--arch`, `--variant`, `--dry-run`, and
|
|
117
|
-
`--format`. x64 defaults to `baseline`. `upgrade list`
|
|
118
|
-
|
|
127
|
+
`--format`. x64 defaults to `baseline`. `upgrade list` returns the complete
|
|
128
|
+
published catalog, including labeled prereleases, by default. Positive
|
|
129
|
+
`--page` and `--per-page` values request an explicit view; `--pre-releases` is
|
|
130
|
+
accepted but is unnecessary because prereleases are never hidden.
|
|
119
131
|
|
|
120
132
|
Replacement is transactional: download, native-format validation, backup,
|
|
121
133
|
replacement, version verification, rollback on failure, agent-skill refresh,
|
|
@@ -150,6 +162,16 @@ runx-windows-arm64.exe
|
|
|
150
162
|
runx-windows-x64.exe
|
|
151
163
|
runx-windows-x64-baseline.exe
|
|
152
164
|
runx-windows-x64-modern.exe
|
|
153
|
-
guiho-s-runx
|
|
154
|
-
guiho-i-runx
|
|
165
|
+
guiho-s-runx.md
|
|
166
|
+
guiho-i-runx.md
|
|
155
167
|
```
|
|
168
|
+
|
|
169
|
+
The Markdown suffix is part of the public GitHub Release filename contract.
|
|
170
|
+
Installers retain the standard installed skill filename `SKILL.md` and use the
|
|
171
|
+
instruction asset contents when reconciling managed instruction blocks. Before
|
|
172
|
+
either write, installers reject empty, executable, binary, invalid UTF-8, or
|
|
173
|
+
misidentified Markdown payloads.
|
|
174
|
+
|
|
175
|
+
Release descriptions contain only the matching `## <version> - <date>`
|
|
176
|
+
changelog section. The publish workflow fails closed when that exact section is
|
|
177
|
+
missing and refreshes the notes when rerunning an existing release.
|
package/README.md
CHANGED
|
@@ -32,13 +32,18 @@ irm https://raw.githubusercontent.com/CGuiho/runx/main/devops/install.ps1 | iex
|
|
|
32
32
|
POSIX:
|
|
33
33
|
|
|
34
34
|
```sh
|
|
35
|
-
curl --proto '=https' --tlsv1.2 -fsSL https://raw.githubusercontent.com/CGuiho/runx/main/devops/install.sh |
|
|
35
|
+
curl --proto '=https' --tlsv1.2 -fsSL https://raw.githubusercontent.com/CGuiho/runx/main/devops/install.sh | bash
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
The direct installers select and verify a native asset, install `runx` on PATH,
|
|
39
39
|
install `guiho-s-runx` into both global agent-tool directories, and reconcile
|
|
40
40
|
RunX instructions in the current project.
|
|
41
41
|
|
|
42
|
+
After installation, ordinary RunX invocations schedule a silent background
|
|
43
|
+
maintenance worker. It repairs missing or stale global skill copies and keeps
|
|
44
|
+
one compact RunX block in the nearest `AGENTS.md` without delaying or changing
|
|
45
|
+
the requested command's output.
|
|
46
|
+
|
|
42
47
|
The npm package is a Node-compatible bootstrap that downloads and delegates to
|
|
43
48
|
the version-matched native binary. Bun is not required for npm installation or
|
|
44
49
|
first execution.
|
package/devops/build-binaries.ts
CHANGED
|
@@ -31,7 +31,7 @@ const binaryTargets: readonly BinaryTarget[] = [
|
|
|
31
31
|
{ bunTarget: 'bun-windows-x64-modern', assetName: 'runx-windows-x64-modern.exe' },
|
|
32
32
|
]
|
|
33
33
|
|
|
34
|
-
const agentAssetNames = ['guiho-s-runx', 'guiho-i-runx'] as const
|
|
34
|
+
const agentAssetNames = ['guiho-s-runx.md', 'guiho-i-runx.md'] as const
|
|
35
35
|
const expectedReleaseAssetNames = [...binaryTargets.map((target) => target.assetName), ...agentAssetNames]
|
|
36
36
|
|
|
37
37
|
if (expectedReleaseAssetNames.length !== 14 || new Set(expectedReleaseAssetNames).size !== 14) {
|
|
@@ -69,8 +69,8 @@ if (import.meta.main) {
|
|
|
69
69
|
process.stdout.write(`built: ${target.assetName}\n`)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
await Bun.write(joinPath(bin, 'guiho-s-runx'), Bun.file(joinPath(root, 'skills', 'guiho-s-runx', 'SKILL.md')))
|
|
73
|
-
await Bun.write(joinPath(bin, 'guiho-i-runx'), Bun.file(joinPath(root, 'prompts', 'guiho-i-runx.md')))
|
|
72
|
+
await Bun.write(joinPath(bin, 'guiho-s-runx.md'), Bun.file(joinPath(root, 'skills', 'guiho-s-runx', 'SKILL.md')))
|
|
73
|
+
await Bun.write(joinPath(bin, 'guiho-i-runx.md'), Bun.file(joinPath(root, 'prompts', 'guiho-i-runx.md')))
|
|
74
74
|
|
|
75
75
|
const observed = [...new Bun.Glob('*').scanSync({ cwd: bin, onlyFiles: true })].sort()
|
|
76
76
|
const expected = [...expectedReleaseAssetNames].sort()
|
package/devops/devops.xdocs.md
CHANGED
|
@@ -4,11 +4,13 @@ description: Native release-asset compilation and direct RunX installer scripts.
|
|
|
4
4
|
parent: runx
|
|
5
5
|
children: []
|
|
6
6
|
files:
|
|
7
|
-
build-binaries.ts: Cross-compiles twelve RFC-named native binaries and adds the two exact agent assets.
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
build-binaries.ts: Cross-compiles twelve RFC-named native binaries and adds the two exact .md agent assets.
|
|
8
|
+
extract-release-notes.ts: Extracts one exact version section from CHANGELOG.md and fails closed when the heading or notes are missing.
|
|
9
|
+
extract-release-notes.spec.ts: Verifies exact heading boundaries and exclusion of frontmatter and other release sections.
|
|
10
|
+
verify-release-assets.ts: Fails on missing, duplicate, extra, legacy, empty, binary, or misidentified release assets.
|
|
11
|
+
installers.spec.ts: Verifies latest-alias and exact-tag URLs, installer progress, resources, executable version matching, Markdown rejection, and no POSIX Bun dependency.
|
|
10
12
|
install.ps1: Resolves an exact Windows release, downloads and validates a compatible asset, transactionally replaces the canonical executable, verifies its version, and rolls back on failure.
|
|
11
|
-
install.sh:
|
|
13
|
+
install.sh: Bash installer for Linux or Darwin with stable latest-download resolution, exact tagged releases, progress, validation, PATH, dual skills, instructions, verification, and rollback.
|
|
12
14
|
documents: {}
|
|
13
15
|
tags:
|
|
14
16
|
- devops
|
|
@@ -24,5 +26,6 @@ flags: []
|
|
|
24
26
|
status: stable
|
|
25
27
|
---
|
|
26
28
|
|
|
27
|
-
These scripts build and verify the exact fourteen-asset release
|
|
28
|
-
|
|
29
|
+
These scripts build and verify the exact fourteen-asset release, validate the
|
|
30
|
+
downloaded Markdown resource contract, create exact version-only GitHub Release
|
|
31
|
+
notes, and support direct installation without npm or Bun.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from 'bun:test'
|
|
6
|
+
import { extractReleaseNotes } from './extract-release-notes.js'
|
|
7
|
+
|
|
8
|
+
describe('extractReleaseNotes', () => {
|
|
9
|
+
test('extracts only the exact unbracketed version section', () => {
|
|
10
|
+
const changelog = `---
|
|
11
|
+
name: Example
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Changelog
|
|
15
|
+
|
|
16
|
+
## 0.4.10 - 2026-07-20
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Newer patch.
|
|
21
|
+
|
|
22
|
+
## 0.4.1 - 2026-07-18
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Requested patch.
|
|
27
|
+
|
|
28
|
+
## 0.4.0 - 2026-07-18
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
|
|
32
|
+
- Older release.
|
|
33
|
+
`
|
|
34
|
+
|
|
35
|
+
expect(extractReleaseNotes(changelog, '0.4.1')).toBe(`## 0.4.1 - 2026-07-18
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Requested patch.
|
|
40
|
+
`)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('fails closed when the exact version heading is absent', () => {
|
|
44
|
+
expect(() => extractReleaseNotes('## 0.4.1 - 2026-07-18\n\n- Fixed.\n', '0.4.2')).toThrow(
|
|
45
|
+
'Expected exactly one changelog heading for version 0.4.2.',
|
|
46
|
+
)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('rejects an empty version section', () => {
|
|
50
|
+
expect(() => extractReleaseNotes('## 0.4.2 - 2026-07-19\n## 0.4.1 - 2026-07-18\n\n- Older.\n', '0.4.2')).toThrow(
|
|
51
|
+
'Changelog section for version 0.4.2 has no release notes.',
|
|
52
|
+
)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
extractReleaseNotes,
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function escapeRegExp(value: string): string {
|
|
10
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function extractReleaseNotes(changelog: string, version: string): string {
|
|
14
|
+
const normalized = changelog.replace(/\r\n/g, '\n')
|
|
15
|
+
const heading = new RegExp(`^## ${escapeRegExp(version)} - .+$`, 'gm')
|
|
16
|
+
const matches = [...normalized.matchAll(heading)]
|
|
17
|
+
if (matches.length !== 1 || matches[0]?.index === undefined) {
|
|
18
|
+
throw new Error(`Expected exactly one changelog heading for version ${version}.`)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const start = matches[0].index
|
|
22
|
+
const nextHeading = normalized.indexOf('\n## ', start + matches[0][0].length)
|
|
23
|
+
const section = normalized.slice(start, nextHeading === -1 ? normalized.length : nextHeading).trim()
|
|
24
|
+
if (!section.includes('\n')) {
|
|
25
|
+
throw new Error(`Changelog section for version ${version} has no release notes.`)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return `${section}\n`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (import.meta.main) {
|
|
32
|
+
const [version, outputPath] = Bun.argv.slice(2)
|
|
33
|
+
if (!version || !outputPath) {
|
|
34
|
+
throw new Error('Usage: bun run devops/extract-release-notes.ts <version> <output-path>')
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const changelog = await Bun.file(new URL('../CHANGELOG.md', import.meta.url)).text()
|
|
38
|
+
await Bun.write(outputPath, extractReleaseNotes(changelog, version))
|
|
39
|
+
process.stdout.write(`wrote release notes for ${version}: ${outputPath}\n`)
|
|
40
|
+
}
|
package/devops/install.ps1
CHANGED
|
@@ -78,6 +78,25 @@ function Test-NativeBinary {
|
|
|
78
78
|
finally { $stream.Dispose() }
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
+
function Test-MarkdownAsset {
|
|
82
|
+
param([string]$Path, [string]$ExpectedName)
|
|
83
|
+
$bytes = [System.IO.File]::ReadAllBytes($Path)
|
|
84
|
+
if ($bytes.Length -eq 0) { throw "Downloaded Markdown asset is empty: $Path" }
|
|
85
|
+
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0x4D -and $bytes[1] -eq 0x5A) {
|
|
86
|
+
throw "Downloaded Markdown asset has a Windows executable header: $Path"
|
|
87
|
+
}
|
|
88
|
+
if ($bytes -contains 0) { throw "Downloaded Markdown asset contains binary NUL bytes: $Path" }
|
|
89
|
+
try {
|
|
90
|
+
$text = ([System.Text.UTF8Encoding]::new($false, $true)).GetString($bytes).Replace("`r`n", "`n")
|
|
91
|
+
} catch {
|
|
92
|
+
throw "Downloaded Markdown asset is not valid UTF-8 text: $Path"
|
|
93
|
+
}
|
|
94
|
+
if (-not $text.StartsWith("---`n")) { throw "Downloaded Markdown asset does not begin with YAML frontmatter: $Path" }
|
|
95
|
+
if ($text -notmatch "(?m)^name:\s*$([Regex]::Escape($ExpectedName))\s*$") {
|
|
96
|
+
throw "Downloaded Markdown asset identity does not match $ExpectedName`: $Path"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
81
100
|
function Test-InstalledVersion {
|
|
82
101
|
param([string]$Path, [string]$ExpectedVersion)
|
|
83
102
|
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
|
|
@@ -156,6 +175,8 @@ function Test-Shadowing {
|
|
|
156
175
|
}
|
|
157
176
|
}
|
|
158
177
|
|
|
178
|
+
if ($env:RUNX_INSTALLER_SOURCE_ONLY -eq '1') { return }
|
|
179
|
+
|
|
159
180
|
$detectedArch = if ($Arch) { $Arch } else { switch ($env:PROCESSOR_ARCHITECTURE) { 'AMD64' { 'x64' } 'ARM64' { 'arm64' } default { throw "Unsupported architecture: $env:PROCESSOR_ARCHITECTURE" } } }
|
|
160
181
|
if ($detectedArch -notin @('x64', 'arm64')) { throw "Invalid architecture: $detectedArch" }
|
|
161
182
|
if (-not [Environment]::Is64BitOperatingSystem) { throw 'Unsupported platform: Windows 32-bit is not supported.' }
|
|
@@ -208,13 +229,15 @@ try {
|
|
|
208
229
|
if (-not $downloadedPath) { throw "No compatible RunX $targetVersion binary found at https://github.com/$Repo/releases" }
|
|
209
230
|
Write-Host 'Replacing...'
|
|
210
231
|
Install-Transactional -DownloadedPath $downloadedPath -Destination $destination -ExpectedVersion $targetVersion
|
|
211
|
-
$skillAsset = Join-Path $temporaryDirectory 'guiho-s-runx'
|
|
212
|
-
$promptAsset = Join-Path $temporaryDirectory 'guiho-i-runx'
|
|
232
|
+
$skillAsset = Join-Path $temporaryDirectory 'guiho-s-runx.md'
|
|
233
|
+
$promptAsset = Join-Path $temporaryDirectory 'guiho-i-runx.md'
|
|
213
234
|
$assetBase = if ($DownloadBaseUrl) { "$DownloadBaseUrl/$encodedTag" } else { "https://github.com/$Repo/releases/download/$encodedTag" }
|
|
214
|
-
Write-Host "Downloading skill asset: $assetBase/guiho-s-runx"
|
|
215
|
-
Invoke-WebRequest -Uri "$assetBase/guiho-s-runx" -OutFile $skillAsset -UseBasicParsing
|
|
216
|
-
|
|
217
|
-
|
|
235
|
+
Write-Host "Downloading skill asset: $assetBase/guiho-s-runx.md"
|
|
236
|
+
Invoke-WebRequest -Uri "$assetBase/guiho-s-runx.md" -OutFile $skillAsset -UseBasicParsing
|
|
237
|
+
Test-MarkdownAsset -Path $skillAsset -ExpectedName 'guiho-s-runx'
|
|
238
|
+
Write-Host "Downloading instruction asset: $assetBase/guiho-i-runx.md"
|
|
239
|
+
Invoke-WebRequest -Uri "$assetBase/guiho-i-runx.md" -OutFile $promptAsset -UseBasicParsing
|
|
240
|
+
Test-MarkdownAsset -Path $promptAsset -ExpectedName 'guiho-i-runx'
|
|
218
241
|
foreach ($skillRoot in @((Join-Path $HOME '.agents\skills\guiho-s-runx'), (Join-Path $HOME '.claude\skills\guiho-s-runx'))) {
|
|
219
242
|
New-Item -ItemType Directory -Force -Path $skillRoot | Out-Null
|
|
220
243
|
Copy-Item -LiteralPath $skillAsset -Destination (Join-Path $skillRoot 'SKILL.md') -Force
|
package/devops/install.sh
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
set -
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
3
|
|
|
4
4
|
REPO="${RUNX_REPO:-CGuiho/runx}"
|
|
5
5
|
VERSION="${RUNX_VERSION:-latest}"
|
|
@@ -10,6 +10,7 @@ VARIANT_OVERRIDE=""
|
|
|
10
10
|
OS=""
|
|
11
11
|
ARCH=""
|
|
12
12
|
TARGET_VERSION=""
|
|
13
|
+
INSTALLED_VERSION=""
|
|
13
14
|
TMP=""
|
|
14
15
|
|
|
15
16
|
cleanup() { [ -z "$TMP" ] || rm -rf -- "$TMP"; }
|
|
@@ -76,11 +77,21 @@ normalize_version() {
|
|
|
76
77
|
|
|
77
78
|
resolve_target_version() {
|
|
78
79
|
if [ "$VERSION" != latest ]; then normalize_version "$VERSION"; return; fi
|
|
79
|
-
printf '
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
printf 'latest\n'
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
build_asset_url() {
|
|
84
|
+
asset=$1
|
|
85
|
+
if [ -n "$DOWNLOAD_BASE_URL" ]; then
|
|
86
|
+
printf '%s/%s\n' "${DOWNLOAD_BASE_URL%/}" "$asset"
|
|
87
|
+
return
|
|
88
|
+
fi
|
|
89
|
+
if [ "$TARGET_VERSION" = latest ]; then
|
|
90
|
+
printf 'https://github.com/%s/releases/latest/download/%s\n' "$REPO" "$asset"
|
|
91
|
+
return
|
|
92
|
+
fi
|
|
93
|
+
encoded_tag="%40guiho%2Frunx%40${TARGET_VERSION}"
|
|
94
|
+
printf 'https://github.com/%s/releases/download/%s/%s\n' "$REPO" "$encoded_tag" "$asset"
|
|
84
95
|
}
|
|
85
96
|
|
|
86
97
|
build_candidates() {
|
|
@@ -106,6 +117,25 @@ verify_native_binary() {
|
|
|
106
117
|
esac
|
|
107
118
|
}
|
|
108
119
|
|
|
120
|
+
verify_markdown_asset() {
|
|
121
|
+
path=$1
|
|
122
|
+
expected_name=$2
|
|
123
|
+
[ -s "$path" ] || fail "downloaded Markdown asset is empty: $path"
|
|
124
|
+
magic=$(od -An -tx1 -N2 "$path" 2>/dev/null | tr -d ' \n')
|
|
125
|
+
[ "$magic" != 4d5a ] || fail "downloaded Markdown asset has a Windows executable header: $path"
|
|
126
|
+
if od -An -tx1 "$path" 2>/dev/null | grep -Eq '(^|[[:space:]])00([[:space:]]|$)'; then
|
|
127
|
+
fail "downloaded Markdown asset contains binary NUL bytes: $path"
|
|
128
|
+
fi
|
|
129
|
+
iconv -f UTF-8 -t UTF-8 "$path" >/dev/null 2>&1 || fail "downloaded Markdown asset is not valid UTF-8 text: $path"
|
|
130
|
+
first_line=$(sed -n '1{s/\r$//;p;}' "$path")
|
|
131
|
+
[ "$first_line" = '---' ] || fail "downloaded Markdown asset does not begin with YAML frontmatter: $path"
|
|
132
|
+
awk -v expected="$expected_name" '
|
|
133
|
+
{ sub(/\r$/, "") }
|
|
134
|
+
$0 == "name: " expected { found=1 }
|
|
135
|
+
END { exit(found ? 0 : 1) }
|
|
136
|
+
' "$path" || fail "downloaded Markdown asset identity does not match $expected_name: $path"
|
|
137
|
+
}
|
|
138
|
+
|
|
109
139
|
verify_installed_version() {
|
|
110
140
|
verify_output=$(mktemp "${TMPDIR:-/tmp}/runx-version.XXXXXX") || return 1
|
|
111
141
|
"$1" --version >"$verify_output" 2>&1 &
|
|
@@ -129,16 +159,21 @@ verify_installed_version() {
|
|
|
129
159
|
fi
|
|
130
160
|
actual=$(cat "$verify_output")
|
|
131
161
|
rm -f -- "$verify_output"
|
|
132
|
-
|
|
162
|
+
normalized=$(normalize_version "$actual") || return 1
|
|
163
|
+
if [ "$TARGET_VERSION" != latest ] && [ "$normalized" != "$TARGET_VERSION" ]; then
|
|
164
|
+
printf 'error: installed RunX reported %s; expected %s\n' "${actual:-<empty>}" "$TARGET_VERSION" >&2
|
|
165
|
+
return 1
|
|
166
|
+
fi
|
|
167
|
+
INSTALLED_VERSION=$normalized
|
|
133
168
|
}
|
|
134
169
|
|
|
135
170
|
ensure_path() {
|
|
136
171
|
PATH="$INSTALL_DIR:$PATH"; export PATH
|
|
137
172
|
profile="$HOME/.profile"
|
|
138
|
-
case "${SHELL
|
|
173
|
+
case "${SHELL:-bash}" in */zsh|zsh) profile="$HOME/.zshrc" ;; */bash|bash) profile="$HOME/.bashrc" ;; */fish|fish) profile="$HOME/.config/fish/config.fish" ;; esac
|
|
139
174
|
mkdir -p -- "$(dirname "$profile")"
|
|
140
175
|
if ! grep -Fq "$INSTALL_DIR" "$profile" 2>/dev/null; then
|
|
141
|
-
if [ "${SHELL
|
|
176
|
+
if [ "${SHELL:-bash}" = fish ] || [ "${SHELL:-bash}" = */fish ]; then printf '\n# Added by runx installer\nfish_add_path %s\n' "$INSTALL_DIR" >>"$profile"
|
|
142
177
|
else printf '\n# Added by runx installer\nexport PATH=%s:$PATH\n' "$INSTALL_DIR" >>"$profile"; fi
|
|
143
178
|
fi
|
|
144
179
|
}
|
|
@@ -182,16 +217,17 @@ install_transactional() {
|
|
|
182
217
|
}
|
|
183
218
|
|
|
184
219
|
install_agent_assets() {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
prompt_url="${tag_base%/}/${encoded_tag}/guiho-i-runx"
|
|
220
|
+
skill_url=$(build_asset_url guiho-s-runx.md)
|
|
221
|
+
prompt_url=$(build_asset_url guiho-i-runx.md)
|
|
188
222
|
printf 'Downloading skill asset: %s\n' "$skill_url"
|
|
189
|
-
download_asset "$skill_url" "$TMP/guiho-s-runx" || fail 'could not download guiho-s-runx'
|
|
223
|
+
download_asset "$skill_url" "$TMP/guiho-s-runx.md" || fail 'could not download guiho-s-runx.md'
|
|
224
|
+
verify_markdown_asset "$TMP/guiho-s-runx.md" 'guiho-s-runx'
|
|
190
225
|
printf 'Downloading instruction asset: %s\n' "$prompt_url"
|
|
191
|
-
download_asset "$prompt_url" "$TMP/guiho-i-runx" || fail 'could not download guiho-i-runx'
|
|
226
|
+
download_asset "$prompt_url" "$TMP/guiho-i-runx.md" || fail 'could not download guiho-i-runx.md'
|
|
227
|
+
verify_markdown_asset "$TMP/guiho-i-runx.md" 'guiho-i-runx'
|
|
192
228
|
for skill_root in "$HOME/.agents/skills/guiho-s-runx" "$HOME/.claude/skills/guiho-s-runx"; do
|
|
193
229
|
mkdir -p -- "$skill_root"
|
|
194
|
-
install -m 0644 "$TMP/guiho-s-runx" "$skill_root/SKILL.md"
|
|
230
|
+
install -m 0644 "$TMP/guiho-s-runx.md" "$skill_root/SKILL.md"
|
|
195
231
|
printf 'Installed skill: %s\n' "$skill_root/SKILL.md"
|
|
196
232
|
done
|
|
197
233
|
targets=""
|
|
@@ -214,7 +250,7 @@ install_agent_assets() {
|
|
|
214
250
|
cat "$clean_file"
|
|
215
251
|
[ ! -s "$clean_file" ] || printf '\n'
|
|
216
252
|
printf '<!-- BEGIN RUNX — DO NOT EDIT THIS SECTION -->\n'
|
|
217
|
-
cat "$TMP/guiho-i-runx"
|
|
253
|
+
cat "$TMP/guiho-i-runx.md"
|
|
218
254
|
printf '\n<!-- END RUNX -->\n'
|
|
219
255
|
} >"$instruction_file"
|
|
220
256
|
done
|
|
@@ -222,20 +258,19 @@ install_agent_assets() {
|
|
|
222
258
|
|
|
223
259
|
main() {
|
|
224
260
|
parse_args "$@"
|
|
225
|
-
for command in awk cat curl date dirname grep head install mktemp mv od rm sed tr uname; do require_command "$command"; done
|
|
261
|
+
for command in awk cat curl date dirname grep head iconv install mktemp mv od rm sed tr uname; do require_command "$command"; done
|
|
226
262
|
OS=$(detect_os); ARCH=$(detect_arch); TARGET_VERSION=$(resolve_target_version)
|
|
227
263
|
TMP=$(mktemp -d "${TMPDIR:-/tmp}/runx-install.XXXXXX")
|
|
228
264
|
mkdir -p -- "$INSTALL_DIR"
|
|
229
265
|
destination="$INSTALL_DIR/runx"
|
|
230
|
-
encoded_tag="%40guiho%2Frunx%40${TARGET_VERSION}"
|
|
231
266
|
downloaded=""
|
|
232
267
|
first_asset=$(build_candidates | head -n 1)
|
|
233
|
-
source_url
|
|
268
|
+
source_url=$(build_asset_url "$first_asset")
|
|
234
269
|
printf 'Initiating GUIHO CLI Upgrade / Installation Sequence...\n'
|
|
235
270
|
printf 'Target Version: v%s\nArchitecture: %s\nVariant: %s\nSource URL: %s\n' "$TARGET_VERSION" "$ARCH" "${VARIANT_OVERRIDE:-baseline}" "$source_url"
|
|
236
271
|
build_candidates | while IFS= read -r asset; do printf '%s\n' "$asset"; done >"$TMP/candidates"
|
|
237
272
|
while IFS= read -r asset; do
|
|
238
|
-
|
|
273
|
+
url=$(build_asset_url "$asset")
|
|
239
274
|
candidate="$TMP/$asset"
|
|
240
275
|
printf 'Downloading %s\n' "$url"
|
|
241
276
|
if download_asset "$url" "$candidate"; then :; else
|
|
@@ -253,7 +288,11 @@ main() {
|
|
|
253
288
|
install_agent_assets
|
|
254
289
|
[ "${RUNX_SKIP_PATH_UPDATE:-0}" = 1 ] || ensure_path
|
|
255
290
|
printf 'Final verification: %s --version\n' "$destination"
|
|
256
|
-
printf 'Installed and verified RunX %s at %s\n' "$
|
|
291
|
+
printf 'Installed and verified RunX %s at %s\n' "$INSTALLED_VERSION" "$destination"
|
|
257
292
|
}
|
|
258
293
|
|
|
294
|
+
if [ "${RUNX_INSTALLER_SOURCE_ONLY:-0}" = 1 ]; then
|
|
295
|
+
return 0 2>/dev/null || exit 0
|
|
296
|
+
fi
|
|
297
|
+
|
|
259
298
|
main "$@"
|