@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.
Files changed (72) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/DOCS.md +27 -5
  3. package/README.md +6 -1
  4. package/devops/build-binaries.ts +3 -3
  5. package/devops/devops.xdocs.md +9 -6
  6. package/devops/extract-release-notes.spec.ts +54 -0
  7. package/devops/extract-release-notes.ts +40 -0
  8. package/devops/install.ps1 +29 -6
  9. package/devops/install.sh +61 -22
  10. package/devops/installers.spec.ts +162 -5
  11. package/devops/verify-release-assets.ts +14 -0
  12. package/docs/architecture/architecture.xdocs.md +2 -1
  13. package/docs/architecture/cli-architecture.md +18 -9
  14. package/docs/decisions/decisions.xdocs.md +4 -0
  15. package/docs/decisions/markdown-release-assets-and-version-scoped-notes.md +84 -0
  16. package/docs/plans/automatic-agent-maintenance.md +120 -0
  17. package/docs/plans/linux-installer-latest-release.md +43 -0
  18. package/docs/plans/plans.xdocs.md +6 -0
  19. package/docs/plans/platform-aware-startup-greeting.md +43 -0
  20. package/docs/plans/rfc-0034-cli-compliance-migration.md +17 -8
  21. package/docs/plans/upgrade-reliability-implementation.md +1 -1
  22. package/docs/reviews/implementation/automatic-agent-maintenance-review.md +63 -0
  23. package/docs/reviews/implementation/bash-installer-review.md +42 -0
  24. package/docs/reviews/implementation/implementation.xdocs.md +14 -0
  25. package/docs/reviews/implementation/linux-installer-latest-release-review.md +49 -0
  26. package/docs/reviews/implementation/platform-aware-startup-greeting-review.md +51 -0
  27. package/docs/reviews/implementation/rfc-0034-cli-compliance-migration-review.md +5 -2
  28. package/docs/reviews/implementation/unicode-help-tree-review.md +41 -0
  29. package/docs/reviews/implementation/upgrade-reliability-issue-12-review.md +62 -0
  30. package/docs/reviews/implementation/upgrade-reliability-issue-13-review.md +63 -0
  31. package/docs/reviews/plans/automatic-agent-maintenance-review.md +56 -0
  32. package/docs/reviews/plans/plans.xdocs.md +2 -0
  33. package/docs/superpowers/specs/2026-07-15-upgrade-reliability-design.md +1 -1
  34. package/docs/todo/automatic-agent-maintenance-implementation.md +55 -0
  35. package/docs/todo/automatic-agent-maintenance.md +86 -0
  36. package/docs/todo/bash-installer.md +45 -0
  37. package/docs/todo/linux-installer-latest-release.md +47 -0
  38. package/docs/todo/platform-aware-startup-greeting.md +41 -0
  39. package/docs/todo/rfc-0034-cli-compliance-migration-implementation.md +7 -2
  40. package/docs/todo/rfc-0034-cli-compliance-migration.md +7 -3
  41. package/docs/todo/todo.xdocs.md +14 -0
  42. package/docs/todo/unicode-help-tree.md +44 -0
  43. package/docs/todo/upgrade-reliability.md +51 -0
  44. package/docs/validation/automatic-agent-maintenance.md +63 -0
  45. package/docs/validation/bash-installer.md +55 -0
  46. package/docs/validation/linux-installer-latest-release.md +50 -0
  47. package/docs/validation/platform-aware-startup-greeting.md +50 -0
  48. package/docs/validation/rfc-0034-cli-compliance-migration.md +10 -4
  49. package/docs/validation/unicode-help-tree.md +43 -0
  50. package/docs/validation/upgrade-reliability-issue-12.md +74 -0
  51. package/docs/validation/upgrade-reliability-issue-13.md +72 -0
  52. package/docs/validation/upgrade-reliability.md +38 -99
  53. package/docs/validation/validation.xdocs.md +16 -2
  54. package/library/agent-maintenance.d.ts +19 -0
  55. package/library/agent-maintenance.d.ts.map +1 -0
  56. package/library/agent-maintenance.js +49 -0
  57. package/library/agents.d.ts +6 -1
  58. package/library/agents.d.ts.map +1 -1
  59. package/library/agents.js +58 -11
  60. package/library/cli.d.ts +2 -1
  61. package/library/cli.d.ts.map +1 -1
  62. package/library/cli.js +34 -9
  63. package/library/recovery.js +1 -1
  64. package/library/release-catalog.d.ts +2 -1
  65. package/library/release-catalog.d.ts.map +1 -1
  66. package/library/release-catalog.js +9 -1
  67. package/library/storage.d.ts +2 -1
  68. package/library/storage.d.ts.map +1 -1
  69. package/library/storage.js +13 -1
  70. package/package.json +1 -1
  71. package/skills/guiho-s-runx/SKILL.md +11 -0
  72. package/skills/guiho-s-runx/guiho-s-runx.xdocs.md +4 -1
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,11 +13,11 @@ 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';
19
- export { runCli, runCliWithErrorHandling, runxCommand, };
20
+ export { renderStartupBanner, runCli, runCliWithErrorHandling, runxCommand, };
20
21
  class CliHandled extends Error {
21
22
  }
22
23
  class CliUsageError extends Error {
@@ -31,6 +32,14 @@ const formatSchema = Type.Union([Type.Literal('text'), Type.Literal('json')]);
31
32
  const archSchema = Type.Union([Type.Literal('x64'), Type.Literal('arm64')]);
32
33
  const variantSchema = Type.Union([Type.Literal('baseline'), Type.Literal('default'), Type.Literal('modern')]);
33
34
  const positiveIntegerSchema = Type.Integer({ minimum: 1 });
35
+ const platformLabels = {
36
+ darwin: 'macOS',
37
+ linux: 'Linux',
38
+ win32: 'Windows',
39
+ };
40
+ function renderStartupBanner(platform = process.platform, version = readVersion()) {
41
+ return `Hello ${platformLabels[platform] ?? platform} - runx v${version}\n`;
42
+ }
34
43
  const helpArgs = {
35
44
  help: { type: 'boolean', alias: 'h', description: 'Show command help.' },
36
45
  'help-tree': { type: 'boolean', description: 'Show this command hierarchy.' },
@@ -135,7 +144,7 @@ function createCommandTree() {
135
144
  const upgradeList = leaf('runx upgrade list', 'List RunX releases newest first.', {
136
145
  page: { type: 'string', valueHint: 'positive-integer', description: 'Select result page.' },
137
146
  'per-page': { type: 'string', valueHint: 'positive-integer', description: 'Select page size.' },
138
- 'pre-releases': { type: 'boolean', description: 'Include prerelease versions.' },
147
+ 'pre-releases': { type: 'boolean', description: 'Accepted explicitly; prereleases are always included.' },
139
148
  arch: { type: 'string', valueHint: 'x64|arm64', description: 'Select target architecture.' },
140
149
  variant: { type: 'string', valueHint: 'baseline|default|modern', description: 'Select x64 variant.' },
141
150
  format: catalogArgs.format,
@@ -145,7 +154,11 @@ function createCommandTree() {
145
154
  args: { ...upgradeArgs, ...helpArgs },
146
155
  subCommands: { check: upgradeCheck, list: upgradeList },
147
156
  setup: helpSetup(state),
148
- run: async () => runUpgrade(options(state.args), state.args),
157
+ run: async () => {
158
+ if (state.command === upgradeCheck || state.command === upgradeList)
159
+ return;
160
+ await runUpgrade(options(state.args), state.args);
161
+ },
149
162
  });
150
163
  state.commands.set('upgrade', upgrade);
151
164
  const uninstall = leaf('runx uninstall', 'Uninstall the native RunX executable.', {
@@ -169,7 +182,7 @@ function createCommandTree() {
169
182
  },
170
183
  run: ({ args }) => {
171
184
  if (args._.length === 0)
172
- write(`Hello Windows - runx v${readVersion()}\n`);
185
+ write(renderStartupBanner());
173
186
  },
174
187
  });
175
188
  state.commands.set('', root);
@@ -229,6 +242,11 @@ async function runCli(rawArgs = process.argv.slice(2)) {
229
242
  await runUpdateWorker();
230
243
  return;
231
244
  }
245
+ const maintenanceWorkerCwd = agentMaintenanceWorkerCwd(rawArgs);
246
+ if (maintenanceWorkerCwd !== null) {
247
+ await runAgentMaintenanceWorker(maintenanceWorkerCwd);
248
+ return;
249
+ }
232
250
  const { command, state } = createCommandTree();
233
251
  const cleanOutput = rawArgs.some((arg) => ['-h', '--help', '-v', '--version', '--help-tree', '--help-docs'].includes(arg) || arg.startsWith('--help-tree-depth'));
234
252
  if (!cleanOutput) {
@@ -253,6 +271,14 @@ async function runCli(rawArgs = process.argv.slice(2)) {
253
271
  throw new CliUsageError(error.message, await renderUsage(state.command));
254
272
  throw error;
255
273
  }
274
+ finally {
275
+ if (shouldScheduleAgentMaintenance(rawArgs)) {
276
+ spawnAgentMaintenanceWorker(resolvePath(state.args.cwd ?? process.cwd()));
277
+ }
278
+ }
279
+ }
280
+ function shouldScheduleAgentMaintenance(rawArgs) {
281
+ return !['agent', 'uninstall'].includes(rawArgs[0] ?? '');
256
282
  }
257
283
  async function runCliWithErrorHandling(rawArgs) {
258
284
  try {
@@ -335,11 +361,10 @@ async function runUpgradeList(args) {
335
361
  const requestedArch = args.arch ? decode(archSchema, args.arch, '--arch') : process.arch;
336
362
  const platform = resolveUpgradePlatform(process.platform, requestedArch);
337
363
  const variant = decode(variantSchema, args.variant ?? 'baseline', '--variant');
338
- const page = positiveInteger(args.page ?? '1', '--page');
339
- const perPage = positiveInteger(args.perPage ?? '20', '--per-page');
364
+ const page = args.page ? positiveInteger(args.page, '--page') : undefined;
365
+ const perPage = args.perPage ? positiveInteger(args.perPage, '--per-page') : undefined;
340
366
  const catalog = await fetchReleaseCatalog({ ...platform, variant, currentVersion: readVersion() });
341
- const filtered = args.preReleases ? catalog.releases : catalog.releases.filter((release) => !release.prerelease);
342
- const paged = { ...catalog, releases: filtered.slice((page - 1) * perPage, page * perPage) };
367
+ const paged = paginateReleaseCatalog(catalog, page, perPage);
343
368
  write(options(args).format === 'json' ? renderJson(paged) : renderReleaseCatalog(paged));
344
369
  }
345
370
  async function runUpgrade(optionsValue, args) {
@@ -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 | sh -s -- --version '${escapeShell(targetVersion)}'`,
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)
@@ -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
@@ -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,GACd,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,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzE"}
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"}
@@ -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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@guiho/runx",
3
3
  "description": "A language-agnostic, documented command catalog and local CLI executor.",
4
- "version": "0.4.1",
4
+ "version": "0.5.2",
5
5
  "type": "module",
6
6
  "main": "./library/guiho-runx.js",
7
7
  "types": "./library/guiho-runx.d.ts",
@@ -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 execution and verified native upgrade/list/recovery operations.
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.