@guiho/runx 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/DOCS.md +118 -0
- package/LICENSE.md +36 -0
- package/README.md +79 -0
- package/SECURITY.md +28 -0
- package/devops/build-binaries.ts +99 -0
- package/devops/devops.xdocs.md +25 -0
- package/devops/install.ps1 +216 -0
- package/devops/install.sh +324 -0
- package/docs/architecture/architecture.xdocs.md +20 -0
- package/docs/architecture/cli-architecture.md +39 -0
- package/docs/decisions/alpha-boundaries.md +29 -0
- package/docs/decisions/decisions.xdocs.md +19 -0
- package/docs/docs.xdocs.md +24 -0
- package/docs/plans/alpha-implementation.md +27 -0
- package/docs/plans/plans.xdocs.md +19 -0
- package/docs/requirements/alpha-command-catalog.md +41 -0
- package/docs/requirements/requirements.xdocs.md +19 -0
- package/docs/todo/implement-runx-alpha.md +36 -0
- package/docs/todo/protect-branches-and-tag-creation.md +83 -0
- package/docs/todo/todo.xdocs.md +21 -0
- package/docs/validation/alpha-implementation-summary.md +52 -0
- package/docs/validation/validation.xdocs.md +21 -0
- package/library/agents.d.ts +11 -0
- package/library/agents.d.ts.map +1 -0
- package/library/agents.js +51 -0
- package/library/cli.d.ts +3 -0
- package/library/cli.d.ts.map +1 -0
- package/library/cli.js +146 -0
- package/library/embedded-resources.d.ts +7 -0
- package/library/embedded-resources.d.ts.map +1 -0
- package/library/embedded-resources.js +5 -0
- package/library/errors.d.ts +6 -0
- package/library/errors.d.ts.map +1 -0
- package/library/errors.js +12 -0
- package/library/executor.d.ts +3 -0
- package/library/executor.d.ts.map +1 -0
- package/library/executor.js +24 -0
- package/library/flags.d.ts +5 -0
- package/library/flags.d.ts.map +1 -0
- package/library/flags.js +32 -0
- package/library/guiho-runx-bin.d.ts +3 -0
- package/library/guiho-runx-bin.d.ts.map +1 -0
- package/library/guiho-runx-bin.js +3 -0
- package/library/guiho-runx-native-bin.d.ts +3 -0
- package/library/guiho-runx-native-bin.d.ts.map +1 -0
- package/library/guiho-runx-native-bin.js +5 -0
- package/library/guiho-runx.d.ts +4 -0
- package/library/guiho-runx.d.ts.map +1 -0
- package/library/guiho-runx.js +2 -0
- package/library/help.d.ts +6 -0
- package/library/help.d.ts.map +1 -0
- package/library/help.js +47 -0
- package/library/manifest.d.ts +41 -0
- package/library/manifest.d.ts.map +1 -0
- package/library/manifest.js +112 -0
- package/library/render.d.ts +6 -0
- package/library/render.d.ts.map +1 -0
- package/library/render.js +40 -0
- package/library/self-management.d.ts +13 -0
- package/library/self-management.d.ts.map +1 -0
- package/library/self-management.js +82 -0
- package/library/types.d.ts +31 -0
- package/library/types.d.ts.map +1 -0
- package/library/types.js +0 -0
- package/package.json +77 -0
- package/scripts/runx-bin.ts +18 -0
- package/scripts/scripts.xdocs.md +20 -0
- package/skills/guiho-s-runx/SKILL.md +57 -0
- package/skills/guiho-s-runx/agents/openai.yaml +4 -0
- package/skills/guiho-s-runx/guiho-s-runx.xdocs.md +22 -0
- package/skills/skills.xdocs.md +19 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
subject: runx-todo
|
|
3
|
+
description: Linked task specifications for the RunX TODO index.
|
|
4
|
+
parent: runx-docs
|
|
5
|
+
children: []
|
|
6
|
+
files:
|
|
7
|
+
implement-runx-alpha.md: Defines the completion signals and constraints for the alpha task.
|
|
8
|
+
protect-branches-and-tag-creation.md: Records the verified active GitHub branch and release-tag rulesets for RunX.
|
|
9
|
+
documents:
|
|
10
|
+
implement-runx-alpha.md: Task specification for implementing RunX alpha.
|
|
11
|
+
protect-branches-and-tag-creation.md: Completed task specification with active RunX ruleset IDs, protected patterns, and verification evidence.
|
|
12
|
+
tags:
|
|
13
|
+
- todo
|
|
14
|
+
keywords:
|
|
15
|
+
- runx
|
|
16
|
+
- tasks
|
|
17
|
+
flags: []
|
|
18
|
+
status: stable
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
Task specifications linked from the package-local RunX TODO index.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Alpha Implementation Summary
|
|
3
|
+
purpose: Summarize the first implemented RunX alpha and preserve its validation evidence.
|
|
4
|
+
description: Records delivered CLI behavior, agent and distribution support, checks run, and release boundaries.
|
|
5
|
+
created: 2026-07-12
|
|
6
|
+
flags:
|
|
7
|
+
- validated
|
|
8
|
+
tags:
|
|
9
|
+
- validation
|
|
10
|
+
- implementation
|
|
11
|
+
keywords:
|
|
12
|
+
- runx
|
|
13
|
+
- alpha
|
|
14
|
+
- summary
|
|
15
|
+
owner: runx-validation
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# RunX Alpha Implementation Summary
|
|
19
|
+
|
|
20
|
+
## Implementation Summary
|
|
21
|
+
|
|
22
|
+
RunX is implemented as the open-source `@guiho/runx` Bun/TypeScript CLI. The
|
|
23
|
+
alpha discovers one nearest `runx.yaml`, validates it strictly with TypeBox,
|
|
24
|
+
lists documented commands through `runx list`, and runs an explicitly selected
|
|
25
|
+
command through `runx run` or `runx r`. A bare selector remains available as a
|
|
26
|
+
human shorthand; no-argument `runx` now shows the requested home page and usage.
|
|
27
|
+
|
|
28
|
+
The implementation includes UID/group-ID/index selector handling, JSON output,
|
|
29
|
+
describe, check, dry run, confirmation gates, help/help-tree/help-docs, bundled
|
|
30
|
+
`guiho-s-runx` skill installation, native upgrade and uninstall paths, Windows
|
|
31
|
+
and macOS/Linux direct installers, MIT licensing, and GitHub Actions CI. CI
|
|
32
|
+
validates only; npm and release publishing are intentionally absent.
|
|
33
|
+
|
|
34
|
+
## Validation Evidence
|
|
35
|
+
|
|
36
|
+
- `bun run typecheck` passed.
|
|
37
|
+
- `bun test` passed with four tests covering manifest discovery, selector
|
|
38
|
+
behavior, flags, the `r` alias, dry runs, and real local command execution.
|
|
39
|
+
- `bun run build` passed and emitted the ignored TypeScript library output.
|
|
40
|
+
- `bun run binary` passed and emitted the ignored Windows native executable.
|
|
41
|
+
- The Bun source CLI displayed `--help`, `--help-tree`, and `--help-docs`.
|
|
42
|
+
- `xdocs tree`, `xdocs scan`, and `xdocs doctor --format json` passed. The
|
|
43
|
+
doctor reported only metadata warnings for the special-purpose skill file;
|
|
44
|
+
there were no descriptor, document, or tree errors.
|
|
45
|
+
- `mirror config check` passed. Mirror applied the local `0.1.0` minor release
|
|
46
|
+
and created `@guiho/runx@0.1.0`; the configuration did not push or publish.
|
|
47
|
+
|
|
48
|
+
## Release Boundary
|
|
49
|
+
|
|
50
|
+
The initial external capability warranted and received a Mirror minor transition
|
|
51
|
+
from `0.0.0` to `0.1.0`. It created the configured local version commit and Git
|
|
52
|
+
tag without pushing either because `mirror.config.toml` sets `push = false`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
subject: runx-validation
|
|
3
|
+
description: Validation evidence and implementation summaries for RunX releases.
|
|
4
|
+
parent: runx-docs
|
|
5
|
+
children: []
|
|
6
|
+
files:
|
|
7
|
+
alpha-implementation-summary.md: Records the completed alpha implementation, checks, and release boundaries.
|
|
8
|
+
documents:
|
|
9
|
+
alpha-implementation-summary.md: Validation summary for the first RunX implementation.
|
|
10
|
+
tags:
|
|
11
|
+
- validation
|
|
12
|
+
keywords:
|
|
13
|
+
- runx
|
|
14
|
+
- tests
|
|
15
|
+
- summary
|
|
16
|
+
flags: []
|
|
17
|
+
status: stable
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
Validation records document exact checks, results, exclusions, and manual
|
|
21
|
+
release boundaries for RunX.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AgentScope, AgentTool } from './types.js';
|
|
2
|
+
type EmbeddedResources = {
|
|
3
|
+
skill: string;
|
|
4
|
+
} | undefined;
|
|
5
|
+
declare global {
|
|
6
|
+
var __RUNX_EMBEDDED_RESOURCES__: EmbeddedResources;
|
|
7
|
+
}
|
|
8
|
+
export declare const installAgentSkill: (scope: AgentScope, tool: AgentTool, cwd: string) => Promise<string[]>;
|
|
9
|
+
export declare const installAgentInstructions: (cwd: string) => Promise<string>;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../source/agents.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAGvD,KAAK,iBAAiB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAA;AAEtD,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,2BAA2B,EAAE,iBAAiB,CAAA;CACnD;AAKD,eAAO,MAAM,iBAAiB,UAAiB,UAAU,QAAQ,SAAS,OAAO,MAAM,KAAG,OAAO,CAAC,MAAM,EAAE,CAiBzG,CAAA;AAED,eAAO,MAAM,wBAAwB,QAAe,MAAM,KAAG,OAAO,CAAC,MAAM,CAgB1E,CAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { RunXError } from './errors.js';
|
|
5
|
+
const managedStart = '<!-- BEGIN RUNX AGENT INSTRUCTIONS -->';
|
|
6
|
+
const managedEnd = '<!-- END RUNX AGENT INSTRUCTIONS -->';
|
|
7
|
+
export const installAgentSkill = async (scope, tool, cwd) => {
|
|
8
|
+
const root = scope === 'global' ? homedir() : cwd;
|
|
9
|
+
const skill = await readBundledSkill();
|
|
10
|
+
const targets = tool === 'all' ? ['agents', 'claude'] : [tool];
|
|
11
|
+
const installed = [];
|
|
12
|
+
for (const target of targets) {
|
|
13
|
+
const directory = target === 'agents'
|
|
14
|
+
? join(root, '.agents', 'skills', 'guiho-s-runx')
|
|
15
|
+
: join(root, '.claude', 'skills', 'guiho-s-runx');
|
|
16
|
+
const path = join(directory, 'SKILL.md');
|
|
17
|
+
await mkdir(directory, { recursive: true });
|
|
18
|
+
await writeFile(path, skill, 'utf8');
|
|
19
|
+
installed.push(path);
|
|
20
|
+
}
|
|
21
|
+
return installed;
|
|
22
|
+
};
|
|
23
|
+
export const installAgentInstructions = async (cwd) => {
|
|
24
|
+
const path = join(cwd, 'AGENTS.md');
|
|
25
|
+
let existing = '';
|
|
26
|
+
try {
|
|
27
|
+
existing = await readFile(path, 'utf8');
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (!(error instanceof Error && 'code' in error && error.code === 'ENOENT'))
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
const section = `${managedStart}\n## RunX Command Catalog\n\nUse the bundled \`guiho-s-runx\` skill whenever working with \`runx.yaml\` manifests. Inspect with \`runx check --format json\` and \`runx list --format json\` before selecting a command. Use a UID for automation and require explicit developer approval before \`--yes\` on confirmation-gated commands.\n${managedEnd}`;
|
|
34
|
+
const pattern = new RegExp(`${escapeRegExp(managedStart)}[\\s\\S]*?${escapeRegExp(managedEnd)}`, 'g');
|
|
35
|
+
const next = pattern.test(existing) ? existing.replace(pattern, section) : `${existing.trimEnd()}${existing.trim() ? '\n\n' : ''}${section}\n`;
|
|
36
|
+
await mkdir(dirname(path), { recursive: true });
|
|
37
|
+
await writeFile(path, next, 'utf8');
|
|
38
|
+
return path;
|
|
39
|
+
};
|
|
40
|
+
const readBundledSkill = async () => {
|
|
41
|
+
if (globalThis.__RUNX_EMBEDDED_RESOURCES__?.skill)
|
|
42
|
+
return globalThis.__RUNX_EMBEDDED_RESOURCES__.skill;
|
|
43
|
+
const path = new URL('../skills/guiho-s-runx/SKILL.md', import.meta.url);
|
|
44
|
+
try {
|
|
45
|
+
return await Bun.file(path).text();
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
throw new RunXError('Bundled guiho-s-runx skill is unavailable. Reinstall RunX from an official release.');
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
package/library/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../source/cli.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,MAAM,aAAmB,MAAM,EAAE,KAA2B,OAAO,CAAC,IAAI,CAyBpF,CAAA;AAED,eAAO,MAAM,uBAAuB,aAAoB,MAAM,EAAE,KAAG,OAAO,CAAC,IAAI,CAY9E,CAAA"}
|
package/library/cli.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { installAgentInstructions, installAgentSkill } from './agents.js';
|
|
3
|
+
import { RunXError } from './errors.js';
|
|
4
|
+
import { runCommand } from './executor.js';
|
|
5
|
+
import { booleanFlag, parseArgs, stringFlag } from './flags.js';
|
|
6
|
+
import { readVersion, showCommandHelp, showHelpDocs, showHelpTree, showHome } from './help.js';
|
|
7
|
+
import { readManifest, resolveCommand } from './manifest.js';
|
|
8
|
+
import { renderDescription, renderExecutionPlan, renderJson, renderList } from './render.js';
|
|
9
|
+
import { checkForLatestVersion, listAvailableVersions, uninstallSelf, upgradeSelf } from './self-management.js';
|
|
10
|
+
const builtins = new Set(['list', 'describe', 'run', 'r', 'check', 'agents', 'upgrade', 'uninstall']);
|
|
11
|
+
export const runCli = async (rawArgs = process.argv.slice(2)) => {
|
|
12
|
+
const parsed = parseArgs(rawArgs);
|
|
13
|
+
const options = resolveOptions(parsed.flags);
|
|
14
|
+
if (booleanFlag(parsed.flags, 'version'))
|
|
15
|
+
return write(`${readVersion()}\n`);
|
|
16
|
+
if (booleanFlag(parsed.flags, 'helpTree'))
|
|
17
|
+
return write(`${showHelpTree()}\n`);
|
|
18
|
+
if (booleanFlag(parsed.flags, 'helpDocs'))
|
|
19
|
+
return write(showHelpDocs());
|
|
20
|
+
if (booleanFlag(parsed.flags, 'help'))
|
|
21
|
+
return write(parsed.command && builtins.has(parsed.command) ? showCommandHelp(parsed.command) : showHome());
|
|
22
|
+
if (!parsed.command)
|
|
23
|
+
return write(showHome());
|
|
24
|
+
if (!builtins.has(parsed.command)) {
|
|
25
|
+
await runSelectedCommand(parsed.command, parsed.positionals, options, parsed.flags);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
switch (parsed.command) {
|
|
29
|
+
case 'list':
|
|
30
|
+
await listCommands(options);
|
|
31
|
+
return;
|
|
32
|
+
case 'describe':
|
|
33
|
+
await describeCommand(parsed.positionals[0], options);
|
|
34
|
+
return;
|
|
35
|
+
case 'run':
|
|
36
|
+
case 'r':
|
|
37
|
+
await runSelectedCommand(parsed.positionals[0], parsed.positionals.slice(1), options, parsed.flags);
|
|
38
|
+
return;
|
|
39
|
+
case 'check':
|
|
40
|
+
await checkManifest(options);
|
|
41
|
+
return;
|
|
42
|
+
case 'agents':
|
|
43
|
+
await runAgents(parsed.positionals, options, parsed.flags);
|
|
44
|
+
return;
|
|
45
|
+
case 'upgrade':
|
|
46
|
+
await runUpgrade(parsed.positionals, options, parsed.flags);
|
|
47
|
+
return;
|
|
48
|
+
case 'uninstall':
|
|
49
|
+
await runUninstall(options, parsed.flags);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
export const runCliWithErrorHandling = async (rawArgs) => {
|
|
54
|
+
try {
|
|
55
|
+
await runCli(rawArgs);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (error instanceof RunXError) {
|
|
59
|
+
process.stderr.write(`error: ${error.message}\n`);
|
|
60
|
+
process.exitCode = error.exitCode;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
process.stderr.write(`error: ${error instanceof Error ? error.message : 'Unexpected failure.'}\n`);
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const listCommands = async (options) => {
|
|
68
|
+
const { manifest, path } = await readManifest(options.cwd, options.file);
|
|
69
|
+
write(options.format === 'json' ? renderJson({ manifestPath: path, manifest }) : renderList(manifest, path));
|
|
70
|
+
};
|
|
71
|
+
const describeCommand = async (selector, options) => {
|
|
72
|
+
if (!selector)
|
|
73
|
+
throw new RunXError('Missing selector. Usage: runx describe <selector>');
|
|
74
|
+
const { manifest, path } = await readManifest(options.cwd, options.file);
|
|
75
|
+
const command = resolveCommand(manifest, path, selector);
|
|
76
|
+
write(options.format === 'json' ? renderJson(command) : renderDescription(command));
|
|
77
|
+
};
|
|
78
|
+
const checkManifest = async (options) => {
|
|
79
|
+
const { manifest, path } = await readManifest(options.cwd, options.file);
|
|
80
|
+
const result = { valid: true, manifestPath: path, commandCount: manifest.commands.length, groups: Object.keys(manifest.groups) };
|
|
81
|
+
write(options.format === 'json' ? renderJson(result) : `valid: true\nmanifest: ${path}\ncommands: ${result.commandCount}\n`);
|
|
82
|
+
};
|
|
83
|
+
const runSelectedCommand = async (selector, _, options, flags) => {
|
|
84
|
+
if (!selector)
|
|
85
|
+
throw new RunXError('Missing selector. Usage: runx run <selector>');
|
|
86
|
+
const { manifest, path } = await readManifest(options.cwd, options.file);
|
|
87
|
+
const command = resolveCommand(manifest, path, selector);
|
|
88
|
+
if (booleanFlag(flags, 'dryRun')) {
|
|
89
|
+
write(options.format === 'json' ? renderJson({ dryRun: true, command }) : renderExecutionPlan(command));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (command.confirm === 'always' && !booleanFlag(flags, 'yes')) {
|
|
93
|
+
throw new RunXError(`Command ${command.uid} requires confirmation. Review it with \`runx describe ${command.uid}\` and rerun with --yes when authorized.`);
|
|
94
|
+
}
|
|
95
|
+
if (options.format === 'text')
|
|
96
|
+
write(`Running ${command.uid} (${command.selector})\n`);
|
|
97
|
+
const exitCode = await runCommand(command);
|
|
98
|
+
process.exitCode = exitCode;
|
|
99
|
+
};
|
|
100
|
+
const runAgents = async (positionals, options, flags) => {
|
|
101
|
+
const action = positionals[0];
|
|
102
|
+
if (action === 'install') {
|
|
103
|
+
const scope = (positionals[1] ?? 'local');
|
|
104
|
+
if (scope !== 'local' && scope !== 'global')
|
|
105
|
+
throw new RunXError('Agent scope must be local or global.');
|
|
106
|
+
const tool = (stringFlag(flags, 'tool') ?? 'agents');
|
|
107
|
+
if (!['agents', 'claude', 'all'].includes(tool))
|
|
108
|
+
throw new RunXError('Agent tool must be agents, claude, or all.');
|
|
109
|
+
const installed = await installAgentSkill(scope, tool, options.cwd);
|
|
110
|
+
write(options.format === 'json' ? renderJson({ installed }) : `${installed.map((path) => `installed: ${path}`).join('\n')}\n`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (action === 'instructions') {
|
|
114
|
+
const path = await installAgentInstructions(options.cwd);
|
|
115
|
+
write(options.format === 'json' ? renderJson({ instructions: path }) : `updated: ${path}\n`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
throw new RunXError('Usage: runx agents install <local|global> [--tool agents|claude|all] | runx agents instructions');
|
|
119
|
+
};
|
|
120
|
+
const runUpgrade = async (positionals, options, flags) => {
|
|
121
|
+
if (positionals[0] === 'check') {
|
|
122
|
+
const result = await checkForLatestVersion();
|
|
123
|
+
write(options.format === 'json' ? renderJson(result) : `current: ${result.currentVersion}\nlatest: ${result.latestVersion}\nupdate_available: ${result.updateAvailable}\n`);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (positionals[0] === 'list') {
|
|
127
|
+
const versions = await listAvailableVersions();
|
|
128
|
+
write(options.format === 'json' ? renderJson({ versions }) : `${versions.join('\n')}\n`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const result = await upgradeSelf(booleanFlag(flags, 'dryRun'));
|
|
132
|
+
write(options.format === 'json' ? renderJson(result) : `current: ${result.currentVersion}\ntarget: ${result.latestVersion}\npath: ${result.executablePath}\n${result.scheduled ? 'scheduled: true\n' : ''}`);
|
|
133
|
+
};
|
|
134
|
+
const runUninstall = async (options, flags) => {
|
|
135
|
+
const result = await uninstallSelf(booleanFlag(flags, 'dryRun'));
|
|
136
|
+
write(options.format === 'json' ? renderJson(result) : `path: ${result.executablePath}\n${result.dryRun ? 'dry_run: true\n' : result.scheduled ? 'scheduled: true\n' : 'uninstalled: true\n'}`);
|
|
137
|
+
};
|
|
138
|
+
const resolveOptions = (flags) => {
|
|
139
|
+
const format = stringFlag(flags, 'format') ?? 'text';
|
|
140
|
+
if (format !== 'text' && format !== 'json')
|
|
141
|
+
throw new RunXError('Invalid --format value. Expected text or json.');
|
|
142
|
+
return { cwd: resolve(stringFlag(flags, 'cwd') ?? process.cwd()), file: stringFlag(flags, 'file'), format: format, verbose: booleanFlag(flags, 'verbose') };
|
|
143
|
+
};
|
|
144
|
+
const write = (value) => {
|
|
145
|
+
process.stdout.write(value);
|
|
146
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded-resources.d.ts","sourceRoot":"","sources":["../source/embedded-resources.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,CAAC;IACb,IAAI,2BAA2B,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAA;CAC/D;AAED,eAAO,MAAM,yBAAyB,QAAO,IAE5C,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @ts-expect-error Bun text imports embed the bundled agent skill in native binaries.
|
|
2
|
+
import skill from '../skills/guiho-s-runx/SKILL.md' with { type: 'text' };
|
|
3
|
+
export const registerEmbeddedResources = () => {
|
|
4
|
+
globalThis.__RUNX_EMBEDDED_RESOURCES__ = { skill };
|
|
5
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../source/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IAEzB,YAAY,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAI,EAIxC;CACF;AAED,eAAO,MAAM,SAAS,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,SAExE,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export class RunXError extends Error {
|
|
2
|
+
exitCode;
|
|
3
|
+
constructor(message, exitCode = 1) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = 'RunXError';
|
|
6
|
+
this.exitCode = exitCode;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export const invariant = (condition, message) => {
|
|
10
|
+
if (!condition)
|
|
11
|
+
throw new RunXError(message);
|
|
12
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../source/executor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAGjD,eAAO,MAAM,UAAU,YAAmB,eAAe,KAAG,OAAO,CAAC,MAAM,CAWzE,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { RunXError } from './errors.js';
|
|
3
|
+
export const runCommand = async (command) => {
|
|
4
|
+
if (!existsSync(command.cwd))
|
|
5
|
+
throw new RunXError(`Command working directory does not exist: ${command.cwd}`);
|
|
6
|
+
const process = Bun.spawn(shellArguments(command), {
|
|
7
|
+
cwd: command.cwd,
|
|
8
|
+
stdin: 'inherit',
|
|
9
|
+
stdout: 'inherit',
|
|
10
|
+
stderr: 'inherit',
|
|
11
|
+
});
|
|
12
|
+
return process.exited;
|
|
13
|
+
};
|
|
14
|
+
const shellArguments = (command) => {
|
|
15
|
+
switch (command.shell ?? 'auto') {
|
|
16
|
+
case 'bash': return ['bash', '-lc', command.command];
|
|
17
|
+
case 'sh': return ['sh', '-lc', command.command];
|
|
18
|
+
case 'powershell': return [process.platform === 'win32' ? 'powershell.exe' : 'pwsh', '-NoProfile', '-NonInteractive', '-Command', command.command];
|
|
19
|
+
case 'cmd': return ['cmd.exe', '/d', '/s', '/c', command.command];
|
|
20
|
+
case 'auto': return process.platform === 'win32'
|
|
21
|
+
? ['cmd.exe', '/d', '/s', '/c', command.command]
|
|
22
|
+
: ['sh', '-lc', command.command];
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ParsedArgs } from './types.js';
|
|
2
|
+
export declare const parseArgs: (args: string[]) => ParsedArgs;
|
|
3
|
+
export declare const booleanFlag: (flags: ParsedArgs['flags'], name: string) => boolean;
|
|
4
|
+
export declare const stringFlag: (flags: ParsedArgs['flags'], name: string) => string | undefined;
|
|
5
|
+
//# sourceMappingURL=flags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../source/flags.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAI5C,eAAO,MAAM,SAAS,SAAU,MAAM,EAAE,KAAG,UA8B1C,CAAA;AAED,eAAO,MAAM,WAAW,UAAW,UAAU,CAAC,OAAO,CAAC,QAAQ,MAAM,KAAG,OAA+B,CAAA;AAEtG,eAAO,MAAM,UAAU,UAAW,UAAU,CAAC,OAAO,CAAC,QAAQ,MAAM,KAAG,MAAM,GAAG,SAG9E,CAAA"}
|
package/library/flags.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const booleanFlags = new Set(['help', 'helpTree', 'helpDocs', 'version', 'verbose', 'dryRun', 'yes']);
|
|
2
|
+
export const parseArgs = (args) => {
|
|
3
|
+
const positionals = [];
|
|
4
|
+
const flags = {};
|
|
5
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
6
|
+
const value = args[index];
|
|
7
|
+
if (!value.startsWith('--')) {
|
|
8
|
+
positionals.push(value);
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
const [rawName, inlineValue] = value.slice(2).split('=', 2);
|
|
12
|
+
const name = toCamelCase(rawName);
|
|
13
|
+
if (inlineValue !== undefined) {
|
|
14
|
+
flags[name] = inlineValue;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const next = args[index + 1];
|
|
18
|
+
if (!booleanFlags.has(name) && next && !next.startsWith('--')) {
|
|
19
|
+
flags[name] = next;
|
|
20
|
+
index += 1;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
flags[name] = true;
|
|
24
|
+
}
|
|
25
|
+
return { command: positionals.shift(), positionals, flags };
|
|
26
|
+
};
|
|
27
|
+
export const booleanFlag = (flags, name) => flags[name] === true;
|
|
28
|
+
export const stringFlag = (flags, name) => {
|
|
29
|
+
const value = flags[name];
|
|
30
|
+
return typeof value === 'string' ? value : undefined;
|
|
31
|
+
};
|
|
32
|
+
const toCamelCase = (value) => value.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guiho-runx-bin.d.ts","sourceRoot":"","sources":["../source/guiho-runx-bin.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guiho-runx-native-bin.d.ts","sourceRoot":"","sources":["../source/guiho-runx-native-bin.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guiho-runx.d.ts","sourceRoot":"","sources":["../source/guiho-runx.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC1E,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const readVersion: () => string;
|
|
2
|
+
export declare const showHome: () => string;
|
|
3
|
+
export declare const showHelpTree: () => string;
|
|
4
|
+
export declare const showHelpDocs: () => string;
|
|
5
|
+
export declare const showCommandHelp: (command: string) => string;
|
|
6
|
+
//# sourceMappingURL=help.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../source/help.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,QAAO,MAAiF,CAAA;AAEhH,eAAO,MAAM,QAAQ,QAAO,MAe3B,CAAA;AAED,eAAO,MAAM,YAAY,QAAO,MAapB,CAAA;AAEZ,eAAO,MAAM,YAAY,QAAO,MAU/B,CAAA;AAED,eAAO,MAAM,eAAe,YAAa,MAAM,KAAG,MAGjD,CAAA"}
|
package/library/help.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import packageJson from '../package.json' with { type: 'json' };
|
|
2
|
+
export const readVersion = () => typeof packageJson.version === 'string' ? packageJson.version : '0.0.0';
|
|
3
|
+
export const showHome = () => `RunX ${readVersion()}
|
|
4
|
+
|
|
5
|
+
A documented, local command catalog for runx.yaml manifests.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
runx list [--file <path>] [--format <text|json>]
|
|
9
|
+
runx describe <selector>
|
|
10
|
+
runx run <selector> [--dry-run] [--yes]
|
|
11
|
+
runx r <selector> [--dry-run] [--yes]
|
|
12
|
+
runx <selector>
|
|
13
|
+
|
|
14
|
+
Start here:
|
|
15
|
+
runx list List every command in the nearest manifest.
|
|
16
|
+
runx --help-tree Show the complete command tree.
|
|
17
|
+
runx --help-docs Show manifest and agent documentation guidance.
|
|
18
|
+
`;
|
|
19
|
+
export const showHelpTree = () => [
|
|
20
|
+
'runx',
|
|
21
|
+
'|- list',
|
|
22
|
+
'|- describe <selector>',
|
|
23
|
+
'|- run <selector>',
|
|
24
|
+
'| `- alias: r',
|
|
25
|
+
'|- check',
|
|
26
|
+
'|- agents',
|
|
27
|
+
'| |- install <local|global>',
|
|
28
|
+
'| `- instructions',
|
|
29
|
+
'|- upgrade [check|list]',
|
|
30
|
+
'`- uninstall',
|
|
31
|
+
'',
|
|
32
|
+
].join('\n');
|
|
33
|
+
export const showHelpDocs = () => `RunX documentation
|
|
34
|
+
|
|
35
|
+
Manifest: runx.yaml, discovered from the current directory upward or selected with --file.
|
|
36
|
+
Required command fields: uid, id, group, summary, description, command.
|
|
37
|
+
Optional command fields: cwd, shell, tags, confirm.
|
|
38
|
+
|
|
39
|
+
Selectors resolve in this order: UID, group/id, one-based index, then an unambiguous ID.
|
|
40
|
+
Use UID values for automation. Use runx describe <selector> and runx run <selector> --dry-run before unfamiliar execution.
|
|
41
|
+
|
|
42
|
+
Agent skill: runx agents install local installs guiho-s-runx under .agents/skills.
|
|
43
|
+
`;
|
|
44
|
+
export const showCommandHelp = (command) => `RunX ${command}
|
|
45
|
+
|
|
46
|
+
Run \`runx --help-tree\` for command structure and \`runx --help-docs\` for manifest guidance.
|
|
47
|
+
`;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ResolvedCommand, RunXManifest } from './types.js';
|
|
2
|
+
export declare const CommandSchema: import("@sinclair/typebox").TObject<{
|
|
3
|
+
uid: import("@sinclair/typebox").TString;
|
|
4
|
+
id: import("@sinclair/typebox").TString;
|
|
5
|
+
group: import("@sinclair/typebox").TString;
|
|
6
|
+
summary: import("@sinclair/typebox").TString;
|
|
7
|
+
description: import("@sinclair/typebox").TString;
|
|
8
|
+
command: import("@sinclair/typebox").TString;
|
|
9
|
+
cwd: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
10
|
+
shell: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"auto">, import("@sinclair/typebox").TLiteral<"bash">, import("@sinclair/typebox").TLiteral<"sh">, import("@sinclair/typebox").TLiteral<"powershell">, import("@sinclair/typebox").TLiteral<"cmd">]>>;
|
|
11
|
+
tags: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
12
|
+
confirm: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"never">, import("@sinclair/typebox").TLiteral<"always">]>>;
|
|
13
|
+
}>;
|
|
14
|
+
export declare const ManifestSchema: import("@sinclair/typebox").TObject<{
|
|
15
|
+
version: import("@sinclair/typebox").TLiteral<1>;
|
|
16
|
+
project: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
17
|
+
name: import("@sinclair/typebox").TString;
|
|
18
|
+
}>>;
|
|
19
|
+
groups: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TObject<{
|
|
20
|
+
summary: import("@sinclair/typebox").TString;
|
|
21
|
+
}>>;
|
|
22
|
+
commands: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
23
|
+
uid: import("@sinclair/typebox").TString;
|
|
24
|
+
id: import("@sinclair/typebox").TString;
|
|
25
|
+
group: import("@sinclair/typebox").TString;
|
|
26
|
+
summary: import("@sinclair/typebox").TString;
|
|
27
|
+
description: import("@sinclair/typebox").TString;
|
|
28
|
+
command: import("@sinclair/typebox").TString;
|
|
29
|
+
cwd: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
|
|
30
|
+
shell: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"auto">, import("@sinclair/typebox").TLiteral<"bash">, import("@sinclair/typebox").TLiteral<"sh">, import("@sinclair/typebox").TLiteral<"powershell">, import("@sinclair/typebox").TLiteral<"cmd">]>>;
|
|
31
|
+
tags: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
|
|
32
|
+
confirm: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"never">, import("@sinclair/typebox").TLiteral<"always">]>>;
|
|
33
|
+
}>>;
|
|
34
|
+
}>;
|
|
35
|
+
export declare const findManifest: (cwd: string, explicitFile?: string) => Promise<string>;
|
|
36
|
+
export declare const readManifest: (cwd: string, explicitFile?: string) => Promise<{
|
|
37
|
+
manifest: RunXManifest;
|
|
38
|
+
path: string;
|
|
39
|
+
}>;
|
|
40
|
+
export declare const resolveCommand: (manifest: RunXManifest, manifestPath: string, selector: string) => ResolvedCommand;
|
|
41
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../source/manifest.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAe,YAAY,EAAE,MAAM,YAAY,CAAA;AAI5E,eAAO,MAAM,aAAa;;;;;;;;;;;EAiBS,CAAA;AAEnC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;EAKQ,CAAA;AAInC,eAAO,MAAM,YAAY,QAAe,MAAM,iBAAiB,MAAM,KAAG,OAAO,CAAC,MAAM,CAiBrF,CAAA;AAED,eAAO,MAAM,YAAY,QAAe,MAAM,iBAAiB,MAAM,KAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAmBvH,CAAA;AAED,eAAO,MAAM,cAAc,aAAc,YAAY,gBAAgB,MAAM,YAAY,MAAM,KAAG,eAkC/F,CAAA"}
|