@guiho/runx 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/DOCS.md +24 -4
- 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 +36 -11
- package/devops/installers.spec.ts +152 -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/plans.xdocs.md +2 -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 +12 -2
- package/docs/reviews/implementation/rfc-0034-cli-compliance-migration-review.md +18 -5
- 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/rfc-0034-cli-compliance-migration-implementation.md +27 -3
- package/docs/todo/rfc-0034-cli-compliance-migration.md +9 -4
- package/docs/todo/todo.xdocs.md +12 -2
- 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/rfc-0034-cli-compliance-migration.md +29 -7
- 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 +14 -4
- 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 +8 -2
- package/library/agents.d.ts.map +1 -1
- package/library/agents.js +58 -11
- package/library/cli.d.ts.map +1 -1
- package/library/cli.js +50 -15
- 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/library/agents.js
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
3
|
*/
|
|
4
4
|
import { RunXError } from './errors.js';
|
|
5
|
-
import { homeDirectory, joinPath, resolvePath } from './path-utils.js';
|
|
6
|
-
import { ensureDirectory, pathExists, readTextIfExists, removePath, writeTextFile } from './storage.js';
|
|
7
|
-
export { applyAgentInstructions, installAgentSkill, listAgentPrompts, listAgentSkills, removeAgentInstructions, showAgentInstructions, showAgentPrompt, showAgentSkill, uninstallAgentSkill, updateAgentInstructions, updateAgentSkill, };
|
|
5
|
+
import { directoryName, homeDirectory, joinPath, resolvePath } from './path-utils.js';
|
|
6
|
+
import { ensureDirectory, pathExists, readTextIfExists, removePath, writeTextFile, writeTextFileAtomic } from './storage.js';
|
|
7
|
+
export { applyAgentInstructions, installAgentSkill, listAgentPrompts, listAgentSkills, maintainAgentIntegration, removeAgentInstructions, showAgentInstructions, showAgentPrompt, showAgentSkill, uninstallAgentSkill, updateAgentInstructions, updateAgentSkill, };
|
|
8
8
|
const skillId = 'guiho-s-runx';
|
|
9
9
|
const promptId = 'guiho-i-runx';
|
|
10
10
|
const managedStart = '<!-- BEGIN RUNX — DO NOT EDIT THIS SECTION -->';
|
|
11
11
|
const managedEnd = '<!-- END RUNX -->';
|
|
12
|
+
const legacyManagedStart = '<!-- BEGIN RUNX AGENT INSTRUCTIONS -->';
|
|
13
|
+
const legacyManagedEnd = '<!-- END RUNX AGENT INSTRUCTIONS -->';
|
|
12
14
|
async function installAgentSkill(scope, cwd) {
|
|
13
15
|
return writeSkillTargets(scope, cwd);
|
|
14
16
|
}
|
|
@@ -69,6 +71,26 @@ async function showAgentPrompt(id) {
|
|
|
69
71
|
throw new RunXError(`Unknown RunX prompt: ${id}`, 2);
|
|
70
72
|
return readBundledPrompt();
|
|
71
73
|
}
|
|
74
|
+
async function maintainAgentIntegration(cwd) {
|
|
75
|
+
const skill = await readBundledSkill();
|
|
76
|
+
const skills = [];
|
|
77
|
+
for (const directory of skillDirectories('global', cwd)) {
|
|
78
|
+
const path = joinPath(directory, 'SKILL.md');
|
|
79
|
+
if (await readTextIfExists(path) === skill)
|
|
80
|
+
continue;
|
|
81
|
+
await writeTextFileAtomic(path, skill);
|
|
82
|
+
skills.push(path);
|
|
83
|
+
}
|
|
84
|
+
const instructionPath = await nearestAgentsPath(cwd);
|
|
85
|
+
const existing = await readTextIfExists(instructionPath) ?? '';
|
|
86
|
+
const next = replaceManagedBlock(existing, instructionBlock());
|
|
87
|
+
const instructions = [];
|
|
88
|
+
if (next !== existing) {
|
|
89
|
+
await writeTextFileAtomic(instructionPath, next);
|
|
90
|
+
instructions.push(instructionPath);
|
|
91
|
+
}
|
|
92
|
+
return { skills, instructions };
|
|
93
|
+
}
|
|
72
94
|
async function writeSkillTargets(scope, cwd) {
|
|
73
95
|
const skill = await readBundledSkill();
|
|
74
96
|
const installed = [];
|
|
@@ -115,23 +137,48 @@ function instructionBlock() {
|
|
|
115
137
|
return `${managedStart}
|
|
116
138
|
## RunX Command Catalog
|
|
117
139
|
|
|
118
|
-
Load the \`guiho-s-runx\` skill
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
140
|
+
Load the \`guiho-s-runx\` skill whenever discovering commands, creating or
|
|
141
|
+
updating catalog entries, validating \`runx.yaml\`, inspecting command details,
|
|
142
|
+
or executing RunX commands.
|
|
143
|
+
Start with \`runx check --format json\` and \`runx list --format json\`, select
|
|
144
|
+
stable UIDs, use \`runx describe <uid>\`, and run
|
|
145
|
+
\`runx run <uid> --dry-run\` before unfamiliar or side-effecting work.
|
|
122
146
|
${managedEnd}
|
|
123
147
|
`;
|
|
124
148
|
}
|
|
125
149
|
function replaceManagedBlock(existing, block) {
|
|
126
|
-
const
|
|
127
|
-
const stripped = existing.replace(pattern, '').trimEnd();
|
|
150
|
+
const stripped = removeKnownManagedBlocks(existing).trimEnd();
|
|
128
151
|
return `${stripped}${stripped ? '\n\n' : ''}${block}`;
|
|
129
152
|
}
|
|
130
153
|
function removeManagedBlock(existing) {
|
|
131
|
-
const
|
|
132
|
-
const next = existing.replace(pattern, '\n').trimEnd();
|
|
154
|
+
const next = removeKnownManagedBlocks(existing, true).trimEnd();
|
|
133
155
|
return next ? `${next}\n` : '';
|
|
134
156
|
}
|
|
157
|
+
function removeKnownManagedBlocks(existing, includeLeadingWhitespace = false) {
|
|
158
|
+
let output = existing;
|
|
159
|
+
for (const [start, end] of [
|
|
160
|
+
[managedStart, managedEnd],
|
|
161
|
+
[legacyManagedStart, legacyManagedEnd],
|
|
162
|
+
]) {
|
|
163
|
+
const prefix = includeLeadingWhitespace ? '\\s*' : '';
|
|
164
|
+
const pattern = new RegExp(`${prefix}${escapeRegExp(start)}[\\s\\S]*?${escapeRegExp(end)}\\s*`, 'g');
|
|
165
|
+
output = output.replace(pattern, includeLeadingWhitespace ? '\n' : '');
|
|
166
|
+
}
|
|
167
|
+
return output;
|
|
168
|
+
}
|
|
169
|
+
async function nearestAgentsPath(cwd) {
|
|
170
|
+
const effectiveCwd = resolvePath(cwd);
|
|
171
|
+
let current = effectiveCwd;
|
|
172
|
+
while (true) {
|
|
173
|
+
const candidate = joinPath(current, 'AGENTS.md');
|
|
174
|
+
if (await pathExists(candidate))
|
|
175
|
+
return candidate;
|
|
176
|
+
const parent = directoryName(current);
|
|
177
|
+
if (parent === current)
|
|
178
|
+
return joinPath(effectiveCwd, 'AGENTS.md');
|
|
179
|
+
current = parent;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
135
182
|
async function readBundledSkill() {
|
|
136
183
|
if (globalThis.__RUNX_EMBEDDED_RESOURCES__?.skill)
|
|
137
184
|
return globalThis.__RUNX_EMBEDDED_RESOURCES__.skill;
|
package/library/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../source/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../source/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AA+BH,OAAO,KAAK,EAAkB,UAAU,EAAkB,MAAM,OAAO,CAAA;AAIvE,OAAO,EACL,MAAM,EACN,uBAAuB,EACvB,WAAW,GACZ,CAAA;AAyPD,QAAA,MAAiB,WAAW,iBAAwB,CAAA;AAEpD,iBAAe,MAAM,CAAC,OAAO,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC9E;AAMD,iBAAe,uBAAuB,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAexE"}
|
package/library/cli.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { Type } from '@sinclair/typebox';
|
|
5
5
|
import { Value } from '@sinclair/typebox/value';
|
|
6
6
|
import { defineCommand, renderUsage, runCommand as runCittyCommand } from 'citty';
|
|
7
|
+
import { agentMaintenanceWorkerCwd, runAgentMaintenanceWorker, spawnAgentMaintenanceWorker } from './agent-maintenance.js';
|
|
7
8
|
import { applyAgentInstructions, installAgentSkill, listAgentPrompts, listAgentSkills, removeAgentInstructions, showAgentInstructions, showAgentPrompt, showAgentSkill, uninstallAgentSkill, updateAgentInstructions, updateAgentSkill, } from './agents.js';
|
|
8
9
|
import { RunXError } from './errors.js';
|
|
9
10
|
import { runCommand } from './executor.js';
|
|
@@ -12,7 +13,7 @@ import { initializeRunXManifest } from './init.js';
|
|
|
12
13
|
import { readManifest, resolveCommand } from './manifest.js';
|
|
13
14
|
import { resolvePath } from './path-utils.js';
|
|
14
15
|
import { renderDescription, renderExecutionPlan, renderJson, renderList } from './render.js';
|
|
15
|
-
import { fetchReleaseCatalog, resolveUpgradePlatform } from './release-catalog.js';
|
|
16
|
+
import { fetchReleaseCatalog, paginateReleaseCatalog, resolveUpgradePlatform } from './release-catalog.js';
|
|
16
17
|
import { checkForLatestVersion, uninstallSelf, upgradeSelf } from './self-management.js';
|
|
17
18
|
import { readCachedUpdateNotice, runUpdateWorker, spawnUpdateWorker } from './update-cache.js';
|
|
18
19
|
import { renderReleaseCatalog, renderUpgradeEvent, renderUpgradeHeading, renderUpgradePlan, renderUpgradeResult } from './upgrade-reporting.js';
|
|
@@ -102,7 +103,14 @@ function createCommandTree() {
|
|
|
102
103
|
const instruction = group('runx agent instruction', 'Manage RunX instruction blocks.', { apply: instructionApply, remove: instructionRemove, update: instructionUpdate, show: instructionShow }, state);
|
|
103
104
|
const promptList = leaf('runx agent prompt list', 'List bundled RunX prompts.', {
|
|
104
105
|
names: { type: 'boolean', description: 'Print prompt names only.' }, format: catalogArgs.format,
|
|
105
|
-
}, () =>
|
|
106
|
+
}, () => {
|
|
107
|
+
if (state.args.names) {
|
|
108
|
+
const names = listAgentPrompts(true);
|
|
109
|
+
write(options(state.args).format === 'json' ? renderJson(names) : `${names.join('\n')}\n`);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
writeFormatted(listAgentPrompts(false), state.args);
|
|
113
|
+
});
|
|
106
114
|
const promptShow = leaf('runx agent prompt show', 'Print one raw bundled prompt.', {
|
|
107
115
|
id: { type: 'positional', description: 'Bundled prompt ID.' },
|
|
108
116
|
}, async ({ args }) => {
|
|
@@ -112,14 +120,13 @@ function createCommandTree() {
|
|
|
112
120
|
});
|
|
113
121
|
const prompt = group('runx agent prompt', 'Inspect bundled agent prompts.', { list: promptList, show: promptShow }, state);
|
|
114
122
|
const agent = group('runx agent', 'Manage RunX agent integration.', { skill, instruction, prompt }, state);
|
|
115
|
-
const
|
|
123
|
+
const upgradeArgs = {
|
|
116
124
|
version: { type: 'string', valueHint: 'version', description: 'Select an exact release version.' },
|
|
117
125
|
arch: { type: 'string', valueHint: 'x64|arm64', description: 'Select target architecture.' },
|
|
118
126
|
variant: { type: 'string', valueHint: 'baseline|default|modern', description: 'Select x64 binary variant.' },
|
|
119
127
|
'dry-run': { type: 'boolean', description: 'Plan without mutation.' },
|
|
120
128
|
format: catalogArgs.format,
|
|
121
|
-
}
|
|
122
|
-
upgradeApply.meta = { ...upgradeApply.meta, hidden: true };
|
|
129
|
+
};
|
|
123
130
|
const upgradeCheck = leaf('runx upgrade check', 'Check whether a newer stable release exists.', {
|
|
124
131
|
format: catalogArgs.format,
|
|
125
132
|
}, async () => {
|
|
@@ -129,12 +136,23 @@ function createCommandTree() {
|
|
|
129
136
|
const upgradeList = leaf('runx upgrade list', 'List RunX releases newest first.', {
|
|
130
137
|
page: { type: 'string', valueHint: 'positive-integer', description: 'Select result page.' },
|
|
131
138
|
'per-page': { type: 'string', valueHint: 'positive-integer', description: 'Select page size.' },
|
|
132
|
-
'pre-releases': { type: 'boolean', description: '
|
|
139
|
+
'pre-releases': { type: 'boolean', description: 'Accepted explicitly; prereleases are always included.' },
|
|
133
140
|
arch: { type: 'string', valueHint: 'x64|arm64', description: 'Select target architecture.' },
|
|
134
141
|
variant: { type: 'string', valueHint: 'baseline|default|modern', description: 'Select x64 variant.' },
|
|
135
142
|
format: catalogArgs.format,
|
|
136
143
|
}, async () => runUpgradeList(state.args));
|
|
137
|
-
const upgrade =
|
|
144
|
+
const upgrade = defineCommand({
|
|
145
|
+
meta: { name: 'runx upgrade', description: 'Inspect or upgrade a native RunX executable.' },
|
|
146
|
+
args: { ...upgradeArgs, ...helpArgs },
|
|
147
|
+
subCommands: { check: upgradeCheck, list: upgradeList },
|
|
148
|
+
setup: helpSetup(state),
|
|
149
|
+
run: async () => {
|
|
150
|
+
if (state.command === upgradeCheck || state.command === upgradeList)
|
|
151
|
+
return;
|
|
152
|
+
await runUpgrade(options(state.args), state.args);
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
state.commands.set('upgrade', upgrade);
|
|
138
156
|
const uninstall = leaf('runx uninstall', 'Uninstall the native RunX executable.', {
|
|
139
157
|
'dry-run': { type: 'boolean', description: 'Print the target without deleting it.' }, format: catalogArgs.format,
|
|
140
158
|
}, async () => {
|
|
@@ -149,8 +167,9 @@ function createCommandTree() {
|
|
|
149
167
|
state.args = context.args;
|
|
150
168
|
state.command = resolveHelpCommand(state);
|
|
151
169
|
await validateInvocation(state);
|
|
152
|
-
if (
|
|
170
|
+
if (context.rawArgs.length === 1 && ['-v', '--version'].includes(context.rawArgs[0] ?? '')) {
|
|
153
171
|
return handled(`${readVersion()}\n`);
|
|
172
|
+
}
|
|
154
173
|
await handleHelp(state);
|
|
155
174
|
},
|
|
156
175
|
run: ({ args }) => {
|
|
@@ -215,12 +234,21 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
215
234
|
await runUpdateWorker();
|
|
216
235
|
return;
|
|
217
236
|
}
|
|
237
|
+
const maintenanceWorkerCwd = agentMaintenanceWorkerCwd(rawArgs);
|
|
238
|
+
if (maintenanceWorkerCwd !== null) {
|
|
239
|
+
await runAgentMaintenanceWorker(maintenanceWorkerCwd);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
218
242
|
const { command, state } = createCommandTree();
|
|
219
243
|
const cleanOutput = rawArgs.some((arg) => ['-h', '--help', '-v', '--version', '--help-tree', '--help-docs'].includes(arg) || arg.startsWith('--help-tree-depth'));
|
|
220
|
-
if (!cleanOutput
|
|
244
|
+
if (!cleanOutput) {
|
|
221
245
|
const notice = await readCachedUpdateNotice(rawArgs.includes('--verbose'));
|
|
222
|
-
if (notice)
|
|
223
|
-
|
|
246
|
+
if (notice) {
|
|
247
|
+
if (rawArgs.length === 0)
|
|
248
|
+
write(`${notice}\n`);
|
|
249
|
+
else
|
|
250
|
+
process.stderr.write(`${notice}\n`);
|
|
251
|
+
}
|
|
224
252
|
}
|
|
225
253
|
spawnUpdateWorker();
|
|
226
254
|
try {
|
|
@@ -235,6 +263,14 @@ async function runCli(rawArgs = process.argv.slice(2)) {
|
|
|
235
263
|
throw new CliUsageError(error.message, await renderUsage(state.command));
|
|
236
264
|
throw error;
|
|
237
265
|
}
|
|
266
|
+
finally {
|
|
267
|
+
if (shouldScheduleAgentMaintenance(rawArgs)) {
|
|
268
|
+
spawnAgentMaintenanceWorker(resolvePath(state.args.cwd ?? process.cwd()));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function shouldScheduleAgentMaintenance(rawArgs) {
|
|
273
|
+
return !['agent', 'uninstall'].includes(rawArgs[0] ?? '');
|
|
238
274
|
}
|
|
239
275
|
async function runCliWithErrorHandling(rawArgs) {
|
|
240
276
|
try {
|
|
@@ -317,11 +353,10 @@ async function runUpgradeList(args) {
|
|
|
317
353
|
const requestedArch = args.arch ? decode(archSchema, args.arch, '--arch') : process.arch;
|
|
318
354
|
const platform = resolveUpgradePlatform(process.platform, requestedArch);
|
|
319
355
|
const variant = decode(variantSchema, args.variant ?? 'baseline', '--variant');
|
|
320
|
-
const page = positiveInteger(args.page
|
|
321
|
-
const perPage = positiveInteger(args.perPage
|
|
356
|
+
const page = args.page ? positiveInteger(args.page, '--page') : undefined;
|
|
357
|
+
const perPage = args.perPage ? positiveInteger(args.perPage, '--per-page') : undefined;
|
|
322
358
|
const catalog = await fetchReleaseCatalog({ ...platform, variant, currentVersion: readVersion() });
|
|
323
|
-
const
|
|
324
|
-
const paged = { ...catalog, releases: filtered.slice((page - 1) * perPage, page * perPage) };
|
|
359
|
+
const paged = paginateReleaseCatalog(catalog, page, perPage);
|
|
325
360
|
write(options(args).format === 'json' ? renderJson(paged) : renderReleaseCatalog(paged));
|
|
326
361
|
}
|
|
327
362
|
async function runUpgrade(optionsValue, args) {
|
package/library/recovery.js
CHANGED
|
@@ -15,7 +15,7 @@ const createRecoveryInstructions = (targetVersion, os, targetSource = 'resolved'
|
|
|
15
15
|
return {
|
|
16
16
|
targetVersion,
|
|
17
17
|
targetSource,
|
|
18
|
-
installCommand: `curl -fsSL ${installerBaseUrl}/install.sh |
|
|
18
|
+
installCommand: `curl -fsSL ${installerBaseUrl}/install.sh | bash -s -- --version '${escapeShell(targetVersion)}'`,
|
|
19
19
|
stopProcessCommand: 'pkill -x runx',
|
|
20
20
|
};
|
|
21
21
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
3
|
*/
|
|
4
4
|
import type { ReleaseAsset, ReleaseCatalog, UpgradeArch, UpgradeOs, UpgradeVariant } from './upgrade-types.js';
|
|
5
|
-
export { assetCandidates, fetchReleaseCatalog, findCompatibleAsset, normalizeReleaseVersion, resolveUpgradePlatform, };
|
|
5
|
+
export { assetCandidates, fetchReleaseCatalog, findCompatibleAsset, normalizeReleaseVersion, paginateReleaseCatalog, resolveUpgradePlatform, };
|
|
6
6
|
declare const githubReleaseSchema: import("@sinclair/typebox").TObject<{
|
|
7
7
|
tag_name: import("@sinclair/typebox").TString;
|
|
8
8
|
draft: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
@@ -29,4 +29,5 @@ declare const findCompatibleAsset: (release: GitHubRelease, platform: ReleasePla
|
|
|
29
29
|
declare const assetCandidates: ({ os, arch, variant }: ReleasePlatform) => string[];
|
|
30
30
|
declare const resolveUpgradePlatform: (platform?: NodeJS.Platform, architecture?: NodeJS.Architecture) => ReleasePlatform;
|
|
31
31
|
declare const normalizeReleaseVersion: (tag: string) => string;
|
|
32
|
+
declare const paginateReleaseCatalog: (catalog: ReleaseCatalog, page?: number, perPage?: number) => ReleaseCatalog;
|
|
32
33
|
//# sourceMappingURL=release-catalog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-catalog.d.ts","sourceRoot":"","sources":["../source/release-catalog.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAuB,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnI,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACvB,CAAA;AAED,QAAA,MAAM,mBAAmB;;;;;;;;;;EAUS,CAAA;AAIlC,MAAM,MAAM,aAAa,GAAG,OAAO,mBAAmB,EAAE,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAE1F,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,SAAS,CAAA;IACb,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,cAAc,CAAA;CACxB,CAAA;AAED,KAAK,mBAAmB,GAAG,eAAe,GAAG;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB,CAAA;AAID,QAAA,MAAM,mBAAmB,YAAmB,mBAAmB,KAAG,OAAO,CAAC,cAAc,CAoCvF,CAAA;AAkBD,QAAA,MAAM,mBAAmB,YAAa,aAAa,YAAY,eAAe,KAAG,YAAY,GAAG,IAM/F,CAAA;AAED,QAAA,MAAM,eAAe,0BAA2B,eAAe,KAAG,MAAM,EAUvE,CAAA;AAED,QAAA,MAAM,sBAAsB,sEAA+D,eAM1F,CAAA;AAED,QAAA,MAAM,uBAAuB,QAAS,MAAM,KAAG,MAA6D,CAAA"}
|
|
1
|
+
{"version":3,"file":"release-catalog.d.ts","sourceRoot":"","sources":["../source/release-catalog.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAuB,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnI,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,GACvB,CAAA;AAED,QAAA,MAAM,mBAAmB;;;;;;;;;;EAUS,CAAA;AAIlC,MAAM,MAAM,aAAa,GAAG,OAAO,mBAAmB,EAAE,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAE1F,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,SAAS,CAAA;IACb,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,cAAc,CAAA;CACxB,CAAA;AAED,KAAK,mBAAmB,GAAG,eAAe,GAAG;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB,CAAA;AAID,QAAA,MAAM,mBAAmB,YAAmB,mBAAmB,KAAG,OAAO,CAAC,cAAc,CAoCvF,CAAA;AAkBD,QAAA,MAAM,mBAAmB,YAAa,aAAa,YAAY,eAAe,KAAG,YAAY,GAAG,IAM/F,CAAA;AAED,QAAA,MAAM,eAAe,0BAA2B,eAAe,KAAG,MAAM,EAUvE,CAAA;AAED,QAAA,MAAM,sBAAsB,sEAA+D,eAM1F,CAAA;AAED,QAAA,MAAM,uBAAuB,QAAS,MAAM,KAAG,MAA6D,CAAA;AAE5G,QAAA,MAAM,sBAAsB,YAAa,cAAc,SAAS,MAAM,YAAY,MAAM,KAAG,cAM1F,CAAA"}
|
|
@@ -5,7 +5,7 @@ import { Type } from '@sinclair/typebox';
|
|
|
5
5
|
import { Value } from '@sinclair/typebox/value';
|
|
6
6
|
import { compare, parse, valid } from 'semver';
|
|
7
7
|
import { RunXError } from './errors.js';
|
|
8
|
-
export { assetCandidates, fetchReleaseCatalog, findCompatibleAsset, normalizeReleaseVersion, resolveUpgradePlatform, };
|
|
8
|
+
export { assetCandidates, fetchReleaseCatalog, findCompatibleAsset, normalizeReleaseVersion, paginateReleaseCatalog, resolveUpgradePlatform, };
|
|
9
9
|
const githubReleaseSchema = Type.Object({
|
|
10
10
|
tag_name: Type.String(),
|
|
11
11
|
draft: Type.Optional(Type.Boolean()),
|
|
@@ -100,6 +100,14 @@ const resolveUpgradePlatform = (platform = process.platform, architecture = proc
|
|
|
100
100
|
return { os, arch, variant: 'baseline' };
|
|
101
101
|
};
|
|
102
102
|
const normalizeReleaseVersion = (tag) => tag.replace(/^@guiho\/runx@/, '').replace(/^v/, '');
|
|
103
|
+
const paginateReleaseCatalog = (catalog, page, perPage) => {
|
|
104
|
+
if (page === undefined && perPage === undefined)
|
|
105
|
+
return catalog;
|
|
106
|
+
const selectedPage = page ?? 1;
|
|
107
|
+
const selectedPageSize = perPage ?? 20;
|
|
108
|
+
const start = (selectedPage - 1) * selectedPageSize;
|
|
109
|
+
return { ...catalog, releases: catalog.releases.slice(start, start + selectedPageSize) };
|
|
110
|
+
};
|
|
103
111
|
const releaseChannel = (version, prerelease) => {
|
|
104
112
|
const parsed = parse(version);
|
|
105
113
|
if (!parsed)
|
package/library/storage.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
3
|
*/
|
|
4
|
-
export { copyTextFile, ensureDirectory, globalRunXDirectory, movePath, pathExists, readTextIfExists, removePath, writeTextFile, };
|
|
4
|
+
export { copyTextFile, ensureDirectory, globalRunXDirectory, movePath, pathExists, readTextIfExists, removePath, writeTextFile, writeTextFileAtomic, };
|
|
5
5
|
declare function globalRunXDirectory(): string;
|
|
6
6
|
declare function pathExists(path: string): Promise<boolean>;
|
|
7
7
|
declare function ensureDirectory(path: string): Promise<void>;
|
|
@@ -9,5 +9,6 @@ declare function removePath(path: string): Promise<void>;
|
|
|
9
9
|
declare function movePath(from: string, to: string): Promise<void>;
|
|
10
10
|
declare function readTextIfExists(path: string): Promise<string | null>;
|
|
11
11
|
declare function writeTextFile(path: string, value: string): Promise<void>;
|
|
12
|
+
declare function writeTextFileAtomic(path: string, value: string): Promise<void>;
|
|
12
13
|
declare function copyTextFile(source: string, target: string): Promise<void>;
|
|
13
14
|
//# sourceMappingURL=storage.d.ts.map
|
package/library/storage.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../source/storage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EACL,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,aAAa,
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../source/storage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EACL,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,mBAAmB,GACpB,CAAA;AAED,iBAAS,mBAAmB,IAAI,MAAM,CAErC;AAED,iBAAe,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAExD;AAED,iBAAe,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED,iBAAe,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AAED,iBAAe,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ/D;AAED,iBAAe,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAEpE;AAED,iBAAe,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvE;AAED,iBAAe,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU7E;AAED,iBAAe,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzE"}
|
package/library/storage.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { $ } from 'bun';
|
|
5
5
|
import { directoryName, homeDirectory, joinPath } from './path-utils.js';
|
|
6
|
-
export { copyTextFile, ensureDirectory, globalRunXDirectory, movePath, pathExists, readTextIfExists, removePath, writeTextFile, };
|
|
6
|
+
export { copyTextFile, ensureDirectory, globalRunXDirectory, movePath, pathExists, readTextIfExists, removePath, writeTextFile, writeTextFileAtomic, };
|
|
7
7
|
function globalRunXDirectory() {
|
|
8
8
|
return joinPath(homeDirectory(), '.guiho', 'runx');
|
|
9
9
|
}
|
|
@@ -33,6 +33,18 @@ async function writeTextFile(path, value) {
|
|
|
33
33
|
await ensureDirectory(directoryName(path));
|
|
34
34
|
await Bun.write(path, value);
|
|
35
35
|
}
|
|
36
|
+
async function writeTextFileAtomic(path, value) {
|
|
37
|
+
await ensureDirectory(directoryName(path));
|
|
38
|
+
const temporary = `${path}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
39
|
+
try {
|
|
40
|
+
await Bun.write(temporary, value);
|
|
41
|
+
await movePath(temporary, path);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
await removePath(temporary);
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
36
48
|
async function copyTextFile(source, target) {
|
|
37
49
|
await writeTextFile(target, await Bun.file(source).text());
|
|
38
50
|
}
|
package/package.json
CHANGED
|
@@ -76,3 +76,14 @@ runx upgrade --dry-run
|
|
|
76
76
|
|
|
77
77
|
Use `--help`, `--help-tree`, or `--help-docs` at any command scope for the
|
|
78
78
|
current executable contract.
|
|
79
|
+
|
|
80
|
+
## Automatic Agent Maintenance
|
|
81
|
+
|
|
82
|
+
Ordinary RunX commands schedule a silent, non-blocking worker that keeps the
|
|
83
|
+
bundled skill current in both global agent-tool directories and reconciles one
|
|
84
|
+
compact managed block in the nearest `AGENTS.md`. A current installation is not
|
|
85
|
+
rewritten. Automatic failures never fail or pollute the foreground command.
|
|
86
|
+
|
|
87
|
+
Explicit `runx agent ...` commands remain the manual repair and local-scope
|
|
88
|
+
interface. Explicit agent-resource removal and `runx uninstall` do not schedule
|
|
89
|
+
automatic reinstallation.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
subject: guiho-s-runx
|
|
3
|
-
description: Agent workflow for safe RunX catalog
|
|
3
|
+
description: Agent workflow for safe RunX catalog work, automatic resource maintenance, and verified native upgrade/list/recovery operations.
|
|
4
4
|
parent: runx-skills
|
|
5
5
|
children: []
|
|
6
6
|
files:
|
|
@@ -17,6 +17,7 @@ keywords:
|
|
|
17
17
|
- dry run
|
|
18
18
|
- runx upgrade
|
|
19
19
|
- recovery install
|
|
20
|
+
- automatic maintenance
|
|
20
21
|
flags: []
|
|
21
22
|
status: stable
|
|
22
23
|
---
|
|
@@ -24,3 +25,5 @@ status: stable
|
|
|
24
25
|
The skill makes manifest inspection, UID selection, dry runs, and explicit
|
|
25
26
|
confirmation the default agent workflow for RunX commands and teaches agents
|
|
26
27
|
how to interpret transactional native upgrades and their recovery contract.
|
|
28
|
+
Ordinary RunX invocations also reconcile the current global skill and nearest
|
|
29
|
+
managed project instruction block through a silent detached worker.
|