@guiho/runx 0.2.6 → 0.2.7
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 +17 -0
- package/DOCS.md +26 -6
- package/README.md +22 -3
- package/docs/decisions/decisions.xdocs.md +4 -0
- package/docs/decisions/interactive-init-manifest.md +187 -0
- package/docs/plans/interactive-init-manifest.md +177 -0
- package/docs/plans/plans.xdocs.md +4 -0
- package/docs/reviews/implementation/implementation.xdocs.md +4 -0
- package/docs/reviews/implementation/interactive-init-manifest-review.md +69 -0
- package/docs/reviews/plans/interactive-init-manifest-review.md +82 -0
- package/docs/reviews/plans/plans.xdocs.md +4 -0
- package/docs/validation/interactive-init-manifest.md +79 -0
- package/docs/validation/validation.xdocs.md +4 -0
- package/library/cli.d.ts.map +1 -1
- package/library/cli.js +18 -0
- package/library/help.d.ts.map +1 -1
- package/library/help.js +4 -0
- package/library/init.d.ts +37 -0
- package/library/init.d.ts.map +1 -0
- package/library/init.js +165 -0
- package/library/manifest.d.ts +4 -1
- package/library/manifest.d.ts.map +1 -1
- package/library/manifest.js +15 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -15,6 +15,23 @@ owner: runx
|
|
|
15
15
|
|
|
16
16
|
# Changelog
|
|
17
17
|
|
|
18
|
+
## 0.2.7 - 2026-07-15
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Added an interactive `runx init` command that collects the project name and
|
|
23
|
+
scripts directory, previews the generated catalog, and confirms before writing.
|
|
24
|
+
- Added safe cancellation and explicit overwrite confirmation so initialization
|
|
25
|
+
never leaves a partial manifest or replaces an existing catalog silently.
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- Initialized catalogs now use the SemVer-compatible manifest version `1.0.0`,
|
|
30
|
+
configure `scripts.directory`, include the required `public` group, and begin
|
|
31
|
+
with an empty command list.
|
|
32
|
+
- `runx init` creates only `runx.yaml`; the configured `scripts` directory is
|
|
33
|
+
created later with the first real script.
|
|
34
|
+
|
|
18
35
|
## 0.2.6 - 2026-07-14
|
|
19
36
|
|
|
20
37
|
### Added
|
package/DOCS.md
CHANGED
|
@@ -28,6 +28,7 @@ lists its commands, and runs exactly one selected command.
|
|
|
28
28
|
| `runx` | Show the home page and usage without loading a manifest. |
|
|
29
29
|
| `runx -h`, `runx --help` | Show Citty-generated usage without loading a manifest. Append help to a command for command-specific usage. |
|
|
30
30
|
| `runx -v`, `runx --version` | Show the installed version without loading a manifest. |
|
|
31
|
+
| `runx init [--cwd <path>]` | Interactively create an empty `runx.yaml` catalog in the selected directory. |
|
|
31
32
|
| `runx list` | List all manifest commands. Add `--format json` for structured output. |
|
|
32
33
|
| `runx describe <selector>` | Show one command's description and operational metadata. |
|
|
33
34
|
| `runx check` | Validate discovery and the manifest without execution. |
|
|
@@ -48,6 +49,13 @@ Global flags: `--cwd <path>`, `--file <path>`, `--format <text|json>`,
|
|
|
48
49
|
Unknown options and missing required arguments produce command usage instead
|
|
49
50
|
of falling through to manifest discovery.
|
|
50
51
|
|
|
52
|
+
`runx init` is intentionally an interactive text workflow: it accepts `--cwd`
|
|
53
|
+
to select the target project, but rejects `--file` (the target is always
|
|
54
|
+
`runx.yaml`) and `--format json`. It previews the exact file, requires a final
|
|
55
|
+
confirmation, asks before replacing an existing file, and leaves no partial
|
|
56
|
+
file when cancelled. It creates the manifest only; the configured scripts
|
|
57
|
+
directory is created later when the first script is added.
|
|
58
|
+
|
|
51
59
|
Citty is the CLI parser, command router, alias registry, and ordinary usage
|
|
52
60
|
renderer. RunX keeps its home page, extended command tree, and manifest guide
|
|
53
61
|
as the explicit `runx`, `--help-tree`, and `--help-docs` surfaces.
|
|
@@ -58,10 +66,14 @@ RunX searches upward from the current directory for `runx.yaml`. Use `--file`
|
|
|
58
66
|
to select an explicit manifest. RunX does not merge files.
|
|
59
67
|
|
|
60
68
|
```yaml
|
|
61
|
-
version: 1
|
|
69
|
+
version: "1.0.0"
|
|
62
70
|
project:
|
|
63
71
|
name: example
|
|
72
|
+
scripts:
|
|
73
|
+
directory: scripts
|
|
64
74
|
groups:
|
|
75
|
+
public:
|
|
76
|
+
summary: Default public project commands.
|
|
65
77
|
development:
|
|
66
78
|
summary: Local development work.
|
|
67
79
|
release:
|
|
@@ -85,14 +97,22 @@ commands:
|
|
|
85
97
|
confirm: always
|
|
86
98
|
```
|
|
87
99
|
|
|
88
|
-
|
|
89
|
-
|
|
100
|
+
`version` is a Semantic Versioning string. RunX currently supports major
|
|
101
|
+
version `1`, including valid prerelease and build metadata forms. Every manifest
|
|
102
|
+
also requires `scripts.directory`, which must be a relative subdirectory inside
|
|
103
|
+
the manifest directory, and a `public` group with a non-empty summary. A
|
|
104
|
+
catalog may start with `commands: []`; every command added later must explicitly
|
|
105
|
+
name an existing group (normally `public`).
|
|
106
|
+
|
|
107
|
+
Required command fields are `uid`, `id`, `group`, `summary`, `description`,
|
|
108
|
+
and `command`. `uid` and `id` begin with a lowercase letter and use lowercase
|
|
90
109
|
letters, digits, and hyphens. `uid` is globally unique; the group and ID pair
|
|
91
110
|
is also unique.
|
|
92
111
|
|
|
93
|
-
Optional fields are `cwd`, `shell`, `tags`, and `confirm`. `cwd` is
|
|
94
|
-
the manifest and cannot escape its directory. Shell values are
|
|
95
|
-
`sh`, `powershell`, and `cmd`. Confirmation values are `never`
|
|
112
|
+
Optional command fields are `cwd`, `shell`, `tags`, and `confirm`. `cwd` is
|
|
113
|
+
relative to the manifest and cannot escape its directory. Shell values are
|
|
114
|
+
`auto`, `bash`, `sh`, `powershell`, and `cmd`. Confirmation values are `never`
|
|
115
|
+
and `always`.
|
|
96
116
|
|
|
97
117
|
## Selectors and Safety
|
|
98
118
|
|
package/README.md
CHANGED
|
@@ -39,11 +39,29 @@ curl -fsSL https://raw.githubusercontent.com/CGuiho/runx/main/devops/install.sh
|
|
|
39
39
|
|
|
40
40
|
## Quick Start
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
Start with the interactive initializer:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
runx init
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
It writes only `runx.yaml`—not an empty `scripts/` directory. The resulting
|
|
49
|
+
catalog starts with a SemVer `1.x` manifest version, a configurable scripts
|
|
50
|
+
directory, the required `public` group, and no commands. Add commands directly
|
|
51
|
+
or ask an agent to add a script under the configured directory and its command
|
|
52
|
+
entry together.
|
|
53
|
+
|
|
54
|
+
For example, a catalog with a development command can look like this:
|
|
43
55
|
|
|
44
56
|
```yaml
|
|
45
|
-
version: 1
|
|
57
|
+
version: "1.0.0"
|
|
58
|
+
project:
|
|
59
|
+
name: example
|
|
60
|
+
scripts:
|
|
61
|
+
directory: scripts
|
|
46
62
|
groups:
|
|
63
|
+
public:
|
|
64
|
+
summary: Default public project commands.
|
|
47
65
|
development:
|
|
48
66
|
summary: Local development commands.
|
|
49
67
|
commands:
|
|
@@ -52,7 +70,7 @@ commands:
|
|
|
52
70
|
group: development
|
|
53
71
|
summary: Start the application locally.
|
|
54
72
|
description: Starts the application in local development mode until interrupted.
|
|
55
|
-
command:
|
|
73
|
+
command: bash scripts/dev.sh
|
|
56
74
|
shell: bash
|
|
57
75
|
tags: [local, watch]
|
|
58
76
|
```
|
|
@@ -63,6 +81,7 @@ Then use RunX:
|
|
|
63
81
|
runx Show the home page and usage.
|
|
64
82
|
runx -h Show Citty-generated command help.
|
|
65
83
|
runx -v Show the installed version without loading a manifest.
|
|
84
|
+
runx init Interactively create an empty runx.yaml catalog.
|
|
66
85
|
runx list List commands in the nearest manifest.
|
|
67
86
|
runx describe app-dev Explain one command without execution.
|
|
68
87
|
runx run app-dev --dry-run Inspect the execution plan.
|
|
@@ -6,12 +6,14 @@ children: []
|
|
|
6
6
|
files:
|
|
7
7
|
alpha-boundaries.md: Captures accepted alpha scope, safety, distribution, and compatibility decisions.
|
|
8
8
|
citty-cli-migration.md: Defines the accepted full migration from handwritten parsing and routing to Citty.
|
|
9
|
+
interactive-init-manifest.md: Defines interactive initialization, Semantic Versioning, the public group, and the scripts directory contract.
|
|
9
10
|
mirror-automatic-push.md: Defines automatic Mirror release pushes with a synchronized protected-main gate.
|
|
10
11
|
npm-trusted-publishing.md: Defines the accepted npm OIDC publishing workflow and protected-branch patch-release trial.
|
|
11
12
|
windows-self-upgrade.md: Defines synchronous Windows executable replacement, verification, rollback, and cleanup.
|
|
12
13
|
documents:
|
|
13
14
|
alpha-boundaries.md: Decision record for RunX alpha boundaries.
|
|
14
15
|
citty-cli-migration.md: Decision record for the complete Citty CLI parser and router migration.
|
|
16
|
+
interactive-init-manifest.md: Accepted manifest and interactive initialization decision for runx init.
|
|
15
17
|
mirror-automatic-push.md: Accepted release-policy decision for Mirror push=true and protected delivery ordering.
|
|
16
18
|
npm-trusted-publishing.md: Decision record for GitHub Actions npm trusted publishing and the first automated patch release.
|
|
17
19
|
windows-self-upgrade.md: Accepted design for synchronous and recoverable Windows native self-upgrade.
|
|
@@ -20,6 +22,8 @@ tags:
|
|
|
20
22
|
keywords:
|
|
21
23
|
- runx
|
|
22
24
|
- decisions
|
|
25
|
+
- runx init
|
|
26
|
+
- scripts directory
|
|
23
27
|
- mirror push
|
|
24
28
|
- windows self-upgrade
|
|
25
29
|
flags: []
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Interactive Init Manifest
|
|
3
|
+
purpose: Preserve the accepted manifest structure and initialization behavior for runx init.
|
|
4
|
+
description: Defines the Semantic Versioning manifest field, mandatory public group, configurable scripts directory, and empty interactive initialization contract.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- accepted
|
|
8
|
+
- decision
|
|
9
|
+
tags:
|
|
10
|
+
- decisions
|
|
11
|
+
- cli
|
|
12
|
+
- manifest
|
|
13
|
+
keywords:
|
|
14
|
+
- runx init
|
|
15
|
+
- runx.yaml
|
|
16
|
+
- semantic versioning
|
|
17
|
+
- public group
|
|
18
|
+
- scripts directory
|
|
19
|
+
owner: runx-decisions
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
# RunX Interactive Init Manifest
|
|
23
|
+
|
|
24
|
+
## Status
|
|
25
|
+
|
|
26
|
+
Accepted by the project owner on 2026-07-14.
|
|
27
|
+
|
|
28
|
+
## Context
|
|
29
|
+
|
|
30
|
+
RunX needs an interactive `runx init` command so a project can establish its
|
|
31
|
+
single `runx.yaml` command catalog before any commands exist. The repository
|
|
32
|
+
already defines groups and documented commands as the core catalog model. The
|
|
33
|
+
initializer must preserve that model without inventing framework-specific
|
|
34
|
+
commands, creating a second configuration file, or forcing a placeholder
|
|
35
|
+
command into the catalog.
|
|
36
|
+
|
|
37
|
+
Projects may later store executable Bash, PowerShell, or other script files in
|
|
38
|
+
a manifest-owned scripts directory. The manifest must identify that directory
|
|
39
|
+
so agents and developers use one predictable location when adding scripts.
|
|
40
|
+
|
|
41
|
+
## Decision
|
|
42
|
+
|
|
43
|
+
### Initialized manifest
|
|
44
|
+
|
|
45
|
+
`runx init` creates this shape, using the current directory name as the default
|
|
46
|
+
project name:
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
version: "1.0.0"
|
|
50
|
+
|
|
51
|
+
project:
|
|
52
|
+
name: my-project
|
|
53
|
+
|
|
54
|
+
scripts:
|
|
55
|
+
directory: scripts
|
|
56
|
+
|
|
57
|
+
groups:
|
|
58
|
+
public:
|
|
59
|
+
summary: Default public project commands.
|
|
60
|
+
|
|
61
|
+
commands: []
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The initializer creates only `runx.yaml`. It does not create an empty `scripts`
|
|
65
|
+
directory because the directory is created when the first script is written.
|
|
66
|
+
|
|
67
|
+
### Manifest version
|
|
68
|
+
|
|
69
|
+
- `version` is a valid Semantic Versioning 2.0.0 string with a
|
|
70
|
+
`MAJOR.MINOR.PATCH` core and optional prerelease or build metadata.
|
|
71
|
+
- The first supported manifest contract is `"1.0.0"`.
|
|
72
|
+
- RunX accepts manifest versions whose major version is `1` and rejects
|
|
73
|
+
unsupported major versions.
|
|
74
|
+
- Numeric `version: 1` manifests are invalid. RunX is still under development
|
|
75
|
+
and has no deployed numeric-version compatibility requirement.
|
|
76
|
+
- Future backward-incompatible manifest changes require a major version change.
|
|
77
|
+
|
|
78
|
+
### Scripts directory
|
|
79
|
+
|
|
80
|
+
- Every manifest contains `scripts.directory`; it configures the project script
|
|
81
|
+
location.
|
|
82
|
+
- The initializer's default value is `scripts` relative to the directory
|
|
83
|
+
containing `runx.yaml`.
|
|
84
|
+
- The path must remain inside the manifest directory and cannot escape through
|
|
85
|
+
an absolute path or parent traversal.
|
|
86
|
+
- Existing and future command strings may invoke any suitable script type from
|
|
87
|
+
this directory; RunX remains language-agnostic.
|
|
88
|
+
- The manifest command entry is the script descriptor. No sidecar RunX config
|
|
89
|
+
or per-script descriptor file is introduced.
|
|
90
|
+
|
|
91
|
+
### Groups and commands
|
|
92
|
+
|
|
93
|
+
- `groups` is a first-class catalog concept.
|
|
94
|
+
- Every manifest contains a `public` group, analogous to PostgreSQL's default
|
|
95
|
+
`public` schema.
|
|
96
|
+
- Additional groups may organize commands by domain or responsibility.
|
|
97
|
+
- Every command explicitly names an existing group. Missing and unknown group
|
|
98
|
+
references are invalid.
|
|
99
|
+
- Authoring workflows place a new command in `public` unless the user requests
|
|
100
|
+
or selects another group, but the stored command still contains
|
|
101
|
+
`group: public` explicitly.
|
|
102
|
+
- An initialized catalog may contain no commands. Once present, every command
|
|
103
|
+
retains the required `uid`, `id`, `group`, `summary`, `description`, and
|
|
104
|
+
executable `command` fields.
|
|
105
|
+
|
|
106
|
+
### Interactive behavior
|
|
107
|
+
|
|
108
|
+
- `runx init` is a first-class Citty command that never requires an existing
|
|
109
|
+
manifest.
|
|
110
|
+
- The interactive flow collects or confirms the project name and scripts
|
|
111
|
+
directory, renders a YAML preview, and requests confirmation before writing.
|
|
112
|
+
- The interface should use a polished terminal presentation with clear
|
|
113
|
+
progress, validation, cancellation, and success states.
|
|
114
|
+
- No framework-specific templates or automatic package-script imports are
|
|
115
|
+
offered.
|
|
116
|
+
- An existing `runx.yaml` is never overwritten without explicit confirmation.
|
|
117
|
+
- Cancellation leaves no partial file, and non-interactive invocation fails
|
|
118
|
+
clearly instead of hanging.
|
|
119
|
+
|
|
120
|
+
## Alternatives Considered
|
|
121
|
+
|
|
122
|
+
### Require a first command during initialization
|
|
123
|
+
|
|
124
|
+
Rejected. Initialization establishes the catalog so commands can be added later
|
|
125
|
+
from explicit developer requests. A fabricated starter command would make the
|
|
126
|
+
manifest less truthful.
|
|
127
|
+
|
|
128
|
+
### Offer framework-specific templates or scan package scripts
|
|
129
|
+
|
|
130
|
+
Rejected. RunX is language-agnostic, and the project owner explicitly excluded
|
|
131
|
+
framework-specific starter templates from the initializer.
|
|
132
|
+
|
|
133
|
+
### Keep numeric `version: 1` compatibility
|
|
134
|
+
|
|
135
|
+
Rejected. RunX has not been used outside development, so there is no legacy
|
|
136
|
+
manifest population to migrate. Supporting two version shapes would add
|
|
137
|
+
unnecessary schema and documentation complexity.
|
|
138
|
+
|
|
139
|
+
### Store the scripts directory in a separate config file
|
|
140
|
+
|
|
141
|
+
Rejected. `runx.yaml` remains the single source of truth for the command
|
|
142
|
+
catalog and its script location.
|
|
143
|
+
|
|
144
|
+
### Create the scripts directory eagerly
|
|
145
|
+
|
|
146
|
+
Rejected for initialization. An empty directory is not useful to the catalog
|
|
147
|
+
and is not preserved by Git. The directory should be created with the first
|
|
148
|
+
real script.
|
|
149
|
+
|
|
150
|
+
## Consequences
|
|
151
|
+
|
|
152
|
+
- The manifest TypeBox schema must accept only supported Semantic Versioning
|
|
153
|
+
strings, require `scripts.directory`, and allow an empty command array.
|
|
154
|
+
- Semantic validation must require the `public` group and continue requiring
|
|
155
|
+
every command to reference a declared group.
|
|
156
|
+
- Script-directory validation must enforce a relative path within the manifest
|
|
157
|
+
root.
|
|
158
|
+
- Existing fixtures and documentation using numeric `version: 1` must move to
|
|
159
|
+
`version: "1.0.0"` and include `public`.
|
|
160
|
+
- Listing and checking an empty initialized manifest must succeed without
|
|
161
|
+
attempting command execution.
|
|
162
|
+
- The initializer needs an isolated prompt boundary so interactive behavior can
|
|
163
|
+
be tested without depending on a real terminal.
|
|
164
|
+
- The bundled agent skill update is intentionally deferred to the process that
|
|
165
|
+
delivers the complete agent-integration request.
|
|
166
|
+
|
|
167
|
+
## Reversal Or Revisit Conditions
|
|
168
|
+
|
|
169
|
+
Revisit this decision only if real-world manifest migration requires a
|
|
170
|
+
compatibility policy, the command catalog needs multiple script roots, or a
|
|
171
|
+
future major manifest version replaces the group model. Such a change must be
|
|
172
|
+
recorded as a new decision and reflected in the manifest's major version.
|
|
173
|
+
|
|
174
|
+
## Follow-up Work
|
|
175
|
+
|
|
176
|
+
- Implement the manifest schema and semantic validation changes.
|
|
177
|
+
- Implement and test the interactive `runx init` command.
|
|
178
|
+
- Update canonical CLI and manifest documentation.
|
|
179
|
+
- Update XDocs descriptors for every changed module or companion document.
|
|
180
|
+
- Leave agent-skill content changes for the complete agent-integration work.
|
|
181
|
+
|
|
182
|
+
## References
|
|
183
|
+
|
|
184
|
+
- [Alpha boundaries](./alpha-boundaries.md)
|
|
185
|
+
- [Alpha command-catalog requirements](../requirements/alpha-command-catalog.md)
|
|
186
|
+
- [CLI architecture](../architecture/cli-architecture.md)
|
|
187
|
+
- [GitHub issue #10](https://github.com/CGuiho/runx/issues/10)
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Interactive Init Manifest Plan
|
|
3
|
+
purpose: Sequence implementation of the accepted runx init workflow and manifest contract.
|
|
4
|
+
description: Defines the schema, interactive terminal UI, validation, documentation, and pull-request work for RunX initialization.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- approved
|
|
8
|
+
tags:
|
|
9
|
+
- plans
|
|
10
|
+
- cli
|
|
11
|
+
- manifest
|
|
12
|
+
keywords:
|
|
13
|
+
- runx init
|
|
14
|
+
- runx.yaml
|
|
15
|
+
- semantic versioning
|
|
16
|
+
- public group
|
|
17
|
+
- scripts directory
|
|
18
|
+
owner: runx-plans
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# RunX Interactive Init Manifest Plan
|
|
22
|
+
|
|
23
|
+
## Sources
|
|
24
|
+
|
|
25
|
+
- [Interactive Init Manifest Decision](../decisions/interactive-init-manifest.md)
|
|
26
|
+
- [Alpha Command Catalog Requirements](../requirements/alpha-command-catalog.md)
|
|
27
|
+
- [CLI Architecture](../architecture/cli-architecture.md)
|
|
28
|
+
- GitHub issue [#10](https://github.com/CGuiho/runx/issues/10)
|
|
29
|
+
|
|
30
|
+
## Unit 1: Establish the Manifest Contract
|
|
31
|
+
|
|
32
|
+
- Goal: Make the current manifest validator enforce the accepted `1.x.x`
|
|
33
|
+
Semantic Versioning, scripts directory, public group, and empty catalog
|
|
34
|
+
contract.
|
|
35
|
+
- Owner: `C:\GUIHO\runx`.
|
|
36
|
+
- Dependencies: Accepted interactive-init decision.
|
|
37
|
+
- Files:
|
|
38
|
+
- `source/manifest.ts`
|
|
39
|
+
- `source/types.ts` when TypeScript inference exposes the new manifest shape
|
|
40
|
+
- `source/guiho-runx.spec.ts`
|
|
41
|
+
- `source/cli.spec.ts` fixtures that construct manifests
|
|
42
|
+
- Behavior:
|
|
43
|
+
- Replace numeric `version: 1` with a Semantic Versioning string and accept
|
|
44
|
+
only supported major version `1`.
|
|
45
|
+
- Require `scripts.directory` as a non-empty relative path inside the
|
|
46
|
+
manifest root.
|
|
47
|
+
- Require the `public` group with a non-empty summary.
|
|
48
|
+
- Permit an empty `commands` array while keeping every populated command
|
|
49
|
+
explicit about its existing group.
|
|
50
|
+
- Preserve strict unknown-property rejection and existing selector and
|
|
51
|
+
execution safety behavior.
|
|
52
|
+
- Data, auth, permissions, and cache: Local YAML contract only. No remote data,
|
|
53
|
+
authentication, authorization, cache, or secret changes.
|
|
54
|
+
- Tests:
|
|
55
|
+
- Accept `"1.0.0"` and prerelease/build SemVer forms with major `1`.
|
|
56
|
+
- Reject numeric versions, malformed SemVer, unsupported major versions,
|
|
57
|
+
missing scripts configuration, escaping script paths, missing public, and
|
|
58
|
+
commands that name unknown groups.
|
|
59
|
+
- Prove empty initialized catalogs check and list without execution.
|
|
60
|
+
- Acceptance: `readManifest()` returns a strict manifest with `scripts` and
|
|
61
|
+
`public`, and invalid configurations fail with actionable `RunXError`
|
|
62
|
+
messages.
|
|
63
|
+
- Stop conditions: Stop if SemVer support would require a migration policy,
|
|
64
|
+
scripts need more than one root, or the change weakens command safety.
|
|
65
|
+
|
|
66
|
+
## Unit 2: Implement the Interactive Initializer
|
|
67
|
+
|
|
68
|
+
- Goal: Add a beautiful, cancellable `runx init` Citty command that creates a
|
|
69
|
+
valid empty `runx.yaml` without ever executing a configured command.
|
|
70
|
+
- Dependencies: Unit 1.
|
|
71
|
+
- Files:
|
|
72
|
+
- `package.json`
|
|
73
|
+
- `bun.lock`
|
|
74
|
+
- `source/init.ts`
|
|
75
|
+
- `source/init.spec.ts`
|
|
76
|
+
- `source/cli.ts`
|
|
77
|
+
- `source/cli.spec.ts`
|
|
78
|
+
- `source/help.ts`
|
|
79
|
+
- Behavior:
|
|
80
|
+
- Use a dependency-free Bun terminal prompt adapter with clear visual states,
|
|
81
|
+
so the initializer remains portable across native and Windows builds.
|
|
82
|
+
- Isolate prompt interactions behind an injected interface so prompt flow and
|
|
83
|
+
filesystem behavior can be tested without a real terminal.
|
|
84
|
+
- In an interactive terminal, welcome the user, collect a project name
|
|
85
|
+
defaulting to the selected directory name, collect a scripts directory
|
|
86
|
+
defaulting to `scripts`, preview the exact YAML, and request confirmation.
|
|
87
|
+
- Write only `runx.yaml`; create `scripts/` later when the first real script
|
|
88
|
+
is added.
|
|
89
|
+
- Detect an existing `runx.yaml` in the selected directory and require a
|
|
90
|
+
second explicit overwrite confirmation.
|
|
91
|
+
- Use an atomic temporary-file write and leave no partial manifest on
|
|
92
|
+
cancellation or failure.
|
|
93
|
+
- Fail clearly outside an interactive terminal; do not hang and do not emit
|
|
94
|
+
interactive ANSI frames into JSON output.
|
|
95
|
+
- Accept `--cwd` as the target directory, reject `--file` because the
|
|
96
|
+
initializer always creates `runx.yaml`, and reject `--format json` because
|
|
97
|
+
initialization is an interactive terminal workflow.
|
|
98
|
+
- Register `init` as a first-class Citty command, include it in help/home and
|
|
99
|
+
command-tree output, and reserve the word from selector shorthand.
|
|
100
|
+
- Tests:
|
|
101
|
+
- Successful creation exactly matches the accepted YAML shape.
|
|
102
|
+
- Cancellation leaves no file.
|
|
103
|
+
- Existing-file rejection and confirmed overwrite are safe.
|
|
104
|
+
- Default and custom project/scripts values validate.
|
|
105
|
+
- CLI help works outside a manifest and non-interactive invocation exits with
|
|
106
|
+
a clear error.
|
|
107
|
+
- `--file` and `--format json` report clear unsupported-option errors without
|
|
108
|
+
creating files.
|
|
109
|
+
- The generated file passes `runx check` and `runx list`.
|
|
110
|
+
- Acceptance: `runx init` produces a polished, deterministic creation flow and
|
|
111
|
+
never executes a manifest command.
|
|
112
|
+
- Stop conditions: Stop if the terminal prompt adapter fails Bun tests or native
|
|
113
|
+
compile, if Citty cannot route `init` without conflicting with selector shorthand, or
|
|
114
|
+
if atomic replacement is not portable on Windows.
|
|
115
|
+
|
|
116
|
+
## Unit 3: Align Canonical Documentation and XDocs
|
|
117
|
+
|
|
118
|
+
- Goal: Make public and structured documentation accurately describe the new
|
|
119
|
+
manifest and initializer without modifying the bundled agent skill.
|
|
120
|
+
- Dependencies: Units 1 and 2.
|
|
121
|
+
- Files:
|
|
122
|
+
- `README.md`
|
|
123
|
+
- `DOCS.md`
|
|
124
|
+
- `source/source.xdocs.md`
|
|
125
|
+
- `runx.xdocs.md` when its package description needs updating
|
|
126
|
+
- `docs/plans/plans.xdocs.md`
|
|
127
|
+
- Behavior:
|
|
128
|
+
- Document `runx init`, Semantic Versioning, `scripts.directory`, mandatory
|
|
129
|
+
`public`, empty catalog initialization, and command-to-script examples.
|
|
130
|
+
- Keep the bundled `skills/guiho-s-runx/SKILL.md` unchanged; its update belongs
|
|
131
|
+
to the separate agent-integration delivery requested by the project owner.
|
|
132
|
+
- Update the source descriptor for the initializer module and changed CLI /
|
|
133
|
+
manifest responsibilities.
|
|
134
|
+
- Checks:
|
|
135
|
+
- `xdocs meta docs\plans --documents --strict --format json`
|
|
136
|
+
- `xdocs meta source --strict --format json`
|
|
137
|
+
- `xdocs tree`
|
|
138
|
+
- Acceptance: User-facing docs, XDocs metadata, and implementation agree.
|
|
139
|
+
- Stop conditions: Stop if XDocs requires unrelated coverage cleanup; validate
|
|
140
|
+
only the affected subtrees and report wider pre-existing findings.
|
|
141
|
+
|
|
142
|
+
## Unit 4: Validate, Review, Commit, Push, and Open a Pull Request
|
|
143
|
+
|
|
144
|
+
- Goal: Produce evidence that the implementation satisfies the accepted
|
|
145
|
+
decision, then deliver it as a draft pull request from `codex/runx-init`.
|
|
146
|
+
- Dependencies: Units 1 through 3.
|
|
147
|
+
- Checks:
|
|
148
|
+
- `bun run typecheck`
|
|
149
|
+
- `bun test`
|
|
150
|
+
- `bun run build`
|
|
151
|
+
- `bun run binary`
|
|
152
|
+
- `xdocs meta docs\plans --documents --strict --format json`
|
|
153
|
+
- `xdocs meta source --strict --format json`
|
|
154
|
+
- `xdocs tree`
|
|
155
|
+
- `git diff --check`
|
|
156
|
+
- Delivery:
|
|
157
|
+
- Write an implementation review and validation report with XDocs metadata.
|
|
158
|
+
- Commit coherent code, tests, documentation, and validation artifacts.
|
|
159
|
+
- Push only the feature branch and create a draft pull request that links
|
|
160
|
+
issue #10 and states that agent-skill automation is intentionally tracked
|
|
161
|
+
separately in issue #11.
|
|
162
|
+
- Acceptance: All applicable checks pass, the worktree is clean, the branch is
|
|
163
|
+
pushed, and the draft pull request is reviewable without a release, tag, or
|
|
164
|
+
package publication.
|
|
165
|
+
- Stop conditions: Stop before push/PR if validation fails, unrelated changes
|
|
166
|
+
appear, GitHub rejects authentication, or the branch diverges unexpectedly.
|
|
167
|
+
|
|
168
|
+
## TODO Alignment
|
|
169
|
+
|
|
170
|
+
This is one approved, focused package implementation and does not need a new
|
|
171
|
+
long-running TODO entry. The decision, plan, review, and validation records are
|
|
172
|
+
the durable delivery trail.
|
|
173
|
+
|
|
174
|
+
## First Executable Unit
|
|
175
|
+
|
|
176
|
+
Unit 1: update `source/manifest.ts` and its fixtures/tests to enforce the
|
|
177
|
+
accepted manifest contract.
|
|
@@ -6,12 +6,14 @@ children: []
|
|
|
6
6
|
files:
|
|
7
7
|
alpha-implementation.md: Breaks the accepted alpha into implementation and validation units.
|
|
8
8
|
citty-cli-migration.md: Executes the full Citty command-tree migration, compatibility validation, protected delivery, and patch release.
|
|
9
|
+
interactive-init-manifest.md: Sequences the SemVer manifest, public group, scripts directory, and interactive initializer delivery.
|
|
9
10
|
mirror-automatic-push.md: Enables automatic Mirror release pushes with a synchronized protected-main safety gate.
|
|
10
11
|
npm-trusted-publishing-release.md: Sequences workflow implementation, protected delivery, Mirror patching, and public trusted-publishing verification.
|
|
11
12
|
windows-self-upgrade.md: Sequences synchronous Windows replacement, rollback coverage, validation, issue closure, and patch delivery.
|
|
12
13
|
documents:
|
|
13
14
|
alpha-implementation.md: Plan used for the initial RunX implementation.
|
|
14
15
|
citty-cli-migration.md: Active plan for replacing handwritten CLI parsing and routing with Citty and delivering its patch release.
|
|
16
|
+
interactive-init-manifest.md: Approved implementation plan for the RunX interactive init manifest feature.
|
|
15
17
|
mirror-automatic-push.md: Approved plan for configuring, validating, and merging Mirror push=true without applying another release.
|
|
16
18
|
npm-trusted-publishing-release.md: Approved executable plan for the RunX 0.2.1 trusted-publishing release trial.
|
|
17
19
|
windows-self-upgrade.md: Approved executable plan for fixing Windows native self-upgrade and delivering its patch.
|
|
@@ -21,6 +23,8 @@ keywords:
|
|
|
21
23
|
- runx
|
|
22
24
|
- implementation
|
|
23
25
|
- citty
|
|
26
|
+
- runx init
|
|
27
|
+
- scripts directory
|
|
24
28
|
- mirror push
|
|
25
29
|
- windows self-upgrade
|
|
26
30
|
flags: []
|
|
@@ -5,9 +5,11 @@ parent: runx-reviews
|
|
|
5
5
|
children: []
|
|
6
6
|
files:
|
|
7
7
|
citty-cli-migration-review.md: Reviews the implemented Citty command tree, compatibility adapter, tests, documentation, packaging, and release readiness.
|
|
8
|
+
interactive-init-manifest-review.md: Reviews the implemented RunX initializer, strict manifest contract, tests, documentation, and delivery readiness.
|
|
8
9
|
windows-self-upgrade-review.md: Reviews synchronous Windows replacement, rollback, cleanup, tests, CI coverage, and release readiness.
|
|
9
10
|
documents:
|
|
10
11
|
citty-cli-migration-review.md: Accepted implementation review for the full Citty CLI migration.
|
|
12
|
+
interactive-init-manifest-review.md: Accepted implementation review for the RunX interactive init manifest feature.
|
|
11
13
|
windows-self-upgrade-review.md: Accepted implementation review for the Windows native self-upgrade fix.
|
|
12
14
|
tags:
|
|
13
15
|
- reviews
|
|
@@ -15,6 +17,8 @@ tags:
|
|
|
15
17
|
keywords:
|
|
16
18
|
- runx
|
|
17
19
|
- citty
|
|
20
|
+
- runx init
|
|
21
|
+
- scripts directory
|
|
18
22
|
- implementation review
|
|
19
23
|
- windows self-upgrade
|
|
20
24
|
flags: []
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Interactive Init Manifest Implementation Review
|
|
3
|
+
purpose: Assess the delivered RunX initializer and manifest contract against the accepted decision and plan.
|
|
4
|
+
description: Reviews Citty routing, strict SemVer and group validation, terminal safety, tests, documentation, and delivery boundaries.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- accepted
|
|
8
|
+
tags:
|
|
9
|
+
- reviews
|
|
10
|
+
- implementation
|
|
11
|
+
- cli
|
|
12
|
+
keywords:
|
|
13
|
+
- runx init
|
|
14
|
+
- runx.yaml
|
|
15
|
+
- semantic versioning
|
|
16
|
+
- public group
|
|
17
|
+
- scripts directory
|
|
18
|
+
owner: runx-implementation-reviews
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# RunX Interactive Init Manifest Implementation Review
|
|
22
|
+
|
|
23
|
+
## Verdict
|
|
24
|
+
|
|
25
|
+
Accepted. No blocking, high, medium, or low findings remain.
|
|
26
|
+
|
|
27
|
+
## Acceptance Criteria Check
|
|
28
|
+
|
|
29
|
+
- `runx init` is a first-class Citty command, appears in the home/help tree,
|
|
30
|
+
and is reserved from selector shorthand.
|
|
31
|
+
- The manifest accepts Semantic Versioning `1.x` strings, requires an in-root
|
|
32
|
+
`scripts.directory` and `public` group, and permits `commands: []` while
|
|
33
|
+
retaining strict command-group validation.
|
|
34
|
+
- The initializer uses a guided terminal adapter with project and scripts
|
|
35
|
+
prompts, an exact YAML preview, confirmation, overwrite confirmation, and
|
|
36
|
+
cancellation behavior. It writes only `runx.yaml`, not `scripts/`.
|
|
37
|
+
- Writes use a same-directory temporary file, validate the temporary manifest,
|
|
38
|
+
then rename it into place. No configured command is read for execution or
|
|
39
|
+
spawned by this path.
|
|
40
|
+
- `--file` and `--format json` fail explicitly for `init`; `--cwd` selects the
|
|
41
|
+
target directory.
|
|
42
|
+
- The README, canonical documentation, source XDocs metadata, and package
|
|
43
|
+
metadata align with the implementation. The bundled agent skill is unchanged
|
|
44
|
+
by design; the separate agent-integration follow-up remains issue #11.
|
|
45
|
+
|
|
46
|
+
## Verification Evidence
|
|
47
|
+
|
|
48
|
+
- `bun run typecheck` passed.
|
|
49
|
+
- `bun test` passed: 22 tests and 180 assertions, including initialization,
|
|
50
|
+
cancellation, overwrite, empty-catalog list/check, and non-interactive CLI
|
|
51
|
+
coverage.
|
|
52
|
+
- `bun run build` and `bun run binary` passed.
|
|
53
|
+
- The compiled `bin/runx.exe --help-tree` includes `init`.
|
|
54
|
+
- XDocs strict metadata checks for `source`, plans, and plan reviews passed;
|
|
55
|
+
the XDocs tree is intact.
|
|
56
|
+
|
|
57
|
+
## Residual Risk
|
|
58
|
+
|
|
59
|
+
The automated environment has no interactive TTY, so the live terminal frame
|
|
60
|
+
was exercised through the injected prompt contract rather than a human session.
|
|
61
|
+
The native binary build and its command-tree smoke check confirm that the
|
|
62
|
+
initializer is included in the compiled executable.
|
|
63
|
+
|
|
64
|
+
## References
|
|
65
|
+
|
|
66
|
+
- [Decision](../../decisions/interactive-init-manifest.md)
|
|
67
|
+
- [Plan](../../plans/interactive-init-manifest.md)
|
|
68
|
+
- [Plan Review](../plans/interactive-init-manifest-review.md)
|
|
69
|
+
- GitHub issues [#10](https://github.com/CGuiho/runx/issues/10) and [#11](https://github.com/CGuiho/runx/issues/11)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Interactive Init Manifest Plan Review
|
|
3
|
+
purpose: Verify that the interactive-init implementation plan is executable, safe, and traceable.
|
|
4
|
+
description: Reviews manifest constraints, terminal workflow boundaries, test coverage, XDocs work, and pull-request delivery for runx init.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- approved
|
|
8
|
+
tags:
|
|
9
|
+
- reviews
|
|
10
|
+
- plans
|
|
11
|
+
- cli
|
|
12
|
+
keywords:
|
|
13
|
+
- runx init
|
|
14
|
+
- runx.yaml
|
|
15
|
+
- semantic versioning
|
|
16
|
+
- public group
|
|
17
|
+
- scripts directory
|
|
18
|
+
owner: runx-plan-reviews
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# RunX Interactive Init Manifest Plan Review
|
|
22
|
+
|
|
23
|
+
## Verdict
|
|
24
|
+
|
|
25
|
+
Ready for execution.
|
|
26
|
+
|
|
27
|
+
## Findings
|
|
28
|
+
|
|
29
|
+
No blocker, high, medium, or low findings remain.
|
|
30
|
+
|
|
31
|
+
The plan is traceable to the accepted interactive-init decision, the existing
|
|
32
|
+
command-catalog requirement, and the Citty CLI architecture. The only review
|
|
33
|
+
finding was resolved in the plan: `runx init` is an interactive terminal
|
|
34
|
+
workflow, so `--format json` and `--file` must fail clearly rather than create
|
|
35
|
+
ambiguous output or target files.
|
|
36
|
+
|
|
37
|
+
## Sequencing and Safety
|
|
38
|
+
|
|
39
|
+
- Manifest schema changes precede the initializer, so generated YAML is
|
|
40
|
+
validated by the same strict contract that later commands use.
|
|
41
|
+
- The initializer is isolated from the executor and is explicitly prohibited
|
|
42
|
+
from spawning configured manifest commands.
|
|
43
|
+
- The prompt boundary is injectable for tests; an interactive terminal is
|
|
44
|
+
required for the real user interface.
|
|
45
|
+
- Existing-file confirmation, cancellation, and atomic writes prevent silent
|
|
46
|
+
replacement and partial manifests.
|
|
47
|
+
- The `scripts` directory is configured but not created until a real script is
|
|
48
|
+
added, matching the accepted file-only initialization boundary.
|
|
49
|
+
- Manifest evolution is constrained to supported SemVer major `1`; no legacy
|
|
50
|
+
numeric compatibility or migration policy is hidden in the implementation.
|
|
51
|
+
|
|
52
|
+
## Coverage Review
|
|
53
|
+
|
|
54
|
+
- Tests cover SemVer, public-group, scripts-directory, empty-catalog, command
|
|
55
|
+
group-reference, creation, cancellation, overwrite, non-interactive, and
|
|
56
|
+
unsupported-option behavior.
|
|
57
|
+
- The full Bun typecheck, test, library build, local native compilation, XDocs
|
|
58
|
+
subtree validation, and diff hygiene are named.
|
|
59
|
+
- Native compilation of the terminal prompt dependency is an explicit stop
|
|
60
|
+
condition.
|
|
61
|
+
- No API, database, authentication, authorization, cache, cloud, secret,
|
|
62
|
+
deployment, release, tag, or package-publication work is in scope.
|
|
63
|
+
|
|
64
|
+
## Documentation and TODO Alignment
|
|
65
|
+
|
|
66
|
+
The plan updates public CLI documentation and the affected XDocs descriptors.
|
|
67
|
+
The bundled RunX agent skill is deliberately deferred to the separate
|
|
68
|
+
agent-integration feature tracked in issue #11, as directed by the project
|
|
69
|
+
owner. The work is one focused package session, so no additional long-running
|
|
70
|
+
TODO entry is required.
|
|
71
|
+
|
|
72
|
+
## First Executable Unit
|
|
73
|
+
|
|
74
|
+
Update `source/manifest.ts` and its tests/fixtures to establish the SemVer,
|
|
75
|
+
scripts-directory, mandatory-public-group, and empty-catalog contract.
|
|
76
|
+
|
|
77
|
+
## References
|
|
78
|
+
|
|
79
|
+
- [Plan](../../plans/interactive-init-manifest.md)
|
|
80
|
+
- [Decision](../../decisions/interactive-init-manifest.md)
|
|
81
|
+
- [Requirements](../../requirements/alpha-command-catalog.md)
|
|
82
|
+
- [CLI Architecture](../../architecture/cli-architecture.md)
|
|
@@ -5,11 +5,13 @@ parent: runx-reviews
|
|
|
5
5
|
children: []
|
|
6
6
|
files:
|
|
7
7
|
citty-cli-migration-review.md: Reviews completeness, compatibility, safety invariants, native packaging, and release sequencing for the Citty migration.
|
|
8
|
+
interactive-init-manifest-review.md: Reviews the RunX init manifest schema, terminal workflow, tests, XDocs, and pull-request delivery.
|
|
8
9
|
mirror-automatic-push-review.md: Reviews synchronized-main safeguards, read-only validation, protected delivery, and release side effects.
|
|
9
10
|
npm-trusted-publishing-release-review.md: Reviews sequencing, acceptance criteria, safety gates, and validation for the RunX 0.2.1 trusted-publishing plan.
|
|
10
11
|
windows-self-upgrade-review.md: Reviews synchronous replacement, rollback, regression coverage, issue closure, and patch delivery.
|
|
11
12
|
documents:
|
|
12
13
|
citty-cli-migration-review.md: Ready-for-execution review of the full Citty CLI migration plan.
|
|
14
|
+
interactive-init-manifest-review.md: Ready-for-execution review of the RunX interactive init manifest plan.
|
|
13
15
|
mirror-automatic-push-review.md: Ready-for-execution review of the Mirror automatic-push configuration plan.
|
|
14
16
|
npm-trusted-publishing-release-review.md: Ready-for-execution review of the npm trusted-publishing release plan.
|
|
15
17
|
windows-self-upgrade-review.md: Ready-for-execution review of the Windows native self-upgrade fix plan.
|
|
@@ -20,6 +22,8 @@ keywords:
|
|
|
20
22
|
- runx
|
|
21
23
|
- plan review
|
|
22
24
|
- citty
|
|
25
|
+
- runx init
|
|
26
|
+
- scripts directory
|
|
23
27
|
- mirror push
|
|
24
28
|
- trusted publishing
|
|
25
29
|
- windows self-upgrade
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: RunX Interactive Init Manifest Validation
|
|
3
|
+
purpose: Record executable verification evidence for the RunX initializer and strict manifest contract.
|
|
4
|
+
description: Captures typecheck, tests, library and native builds, compiled CLI smoke checks, and XDocs validation for runx init.
|
|
5
|
+
created: 2026-07-14
|
|
6
|
+
flags:
|
|
7
|
+
- passed
|
|
8
|
+
tags:
|
|
9
|
+
- validation
|
|
10
|
+
- cli
|
|
11
|
+
- manifest
|
|
12
|
+
keywords:
|
|
13
|
+
- runx init
|
|
14
|
+
- runx.yaml
|
|
15
|
+
- bun test
|
|
16
|
+
- native binary
|
|
17
|
+
- xdocs
|
|
18
|
+
owner: runx-validation
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# RunX Interactive Init Manifest Validation
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
|
|
25
|
+
The interactive initializer and strict manifest contract passed all applicable
|
|
26
|
+
local validation gates. No release, version, tag, package publication, cloud,
|
|
27
|
+
or secret operation was performed.
|
|
28
|
+
|
|
29
|
+
## Scope
|
|
30
|
+
|
|
31
|
+
- Citty registration and help surfaces for `runx init`.
|
|
32
|
+
- SemVer `1.x`, scripts-directory, `public` group, and empty-command manifest
|
|
33
|
+
validation.
|
|
34
|
+
- Prompt cancellation, overwrite confirmation, exact generated YAML, atomic
|
|
35
|
+
write validation, and non-interactive error behavior.
|
|
36
|
+
- User documentation and XDocs metadata.
|
|
37
|
+
|
|
38
|
+
## Commands Run
|
|
39
|
+
|
|
40
|
+
| Command | Result | Evidence |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| `bun run typecheck` | Passed | Strict TypeScript compilation completed without diagnostics. |
|
|
43
|
+
| `bun test` | Passed | 22 tests and 180 assertions passed across CLI, manifest, initializer, and self-management suites. |
|
|
44
|
+
| `bun run build` | Passed | Library output compiled successfully. |
|
|
45
|
+
| `bun run binary` | Passed | Native Windows executable compiled to `bin/runx.exe`. |
|
|
46
|
+
| `bin/runx.exe --help-tree` | Passed | The compiled command tree includes `init`. |
|
|
47
|
+
| `xdocs meta source --strict --format json` | Passed | The new initializer and test files are fully described. |
|
|
48
|
+
| `xdocs meta docs\\plans --documents --strict --format json` | Passed | The plan and companion metadata validate. |
|
|
49
|
+
| `xdocs meta docs\\reviews\\plans --documents --strict --format json` | Passed | The plan review and companion metadata validate. |
|
|
50
|
+
| `xdocs tree` | Passed | The RunX documentation hierarchy is intact. |
|
|
51
|
+
| `git diff --check` | Passed | No whitespace errors were reported before delivery records were added. |
|
|
52
|
+
|
|
53
|
+
## Manual Checks
|
|
54
|
+
|
|
55
|
+
- The generated empty manifest has the required version, project, scripts,
|
|
56
|
+
`public` group, and `commands: []` shape.
|
|
57
|
+
- No empty `scripts/` directory is created by initialization.
|
|
58
|
+
- `runx init --file ...` and `runx init --format json` return explicit errors
|
|
59
|
+
without creating a manifest.
|
|
60
|
+
|
|
61
|
+
## Skipped Checks
|
|
62
|
+
|
|
63
|
+
A person-driven interactive terminal session could not be run in this automated
|
|
64
|
+
non-TTY environment. The initializer’s prompt sequence is covered through its
|
|
65
|
+
injected prompt adapter; the compiled executable was smoke-tested for command
|
|
66
|
+
registration.
|
|
67
|
+
|
|
68
|
+
## Readiness
|
|
69
|
+
|
|
70
|
+
Ready for code review and a draft pull request. The bundled agent-skill
|
|
71
|
+
automation remains intentionally outside this change and is tracked by issue
|
|
72
|
+
#11.
|
|
73
|
+
|
|
74
|
+
## References
|
|
75
|
+
|
|
76
|
+
- [Decision](../decisions/interactive-init-manifest.md)
|
|
77
|
+
- [Plan](../plans/interactive-init-manifest.md)
|
|
78
|
+
- [Implementation Review](../reviews/implementation/interactive-init-manifest-review.md)
|
|
79
|
+
- GitHub issue [#10](https://github.com/CGuiho/runx/issues/10)
|
|
@@ -6,10 +6,12 @@ children: []
|
|
|
6
6
|
files:
|
|
7
7
|
alpha-implementation-summary.md: Records the completed alpha implementation, checks, and release boundaries.
|
|
8
8
|
citty-cli-migration.md: Records the complete local validation gate for the Citty command-tree migration.
|
|
9
|
+
interactive-init-manifest.md: Records validation evidence for the interactive initializer and strict manifest contract.
|
|
9
10
|
windows-self-upgrade.md: Records Windows replacement, rollback, cleanup, native build, CI, and XDocs validation evidence.
|
|
10
11
|
documents:
|
|
11
12
|
alpha-implementation-summary.md: Validation summary for the first RunX implementation.
|
|
12
13
|
citty-cli-migration.md: Validation evidence for TypeScript, tests, native assets, npm packaging, CLI behavior, and XDocs.
|
|
14
|
+
interactive-init-manifest.md: Validation evidence for the RunX interactive init manifest feature.
|
|
13
15
|
npm-trusted-publishing-0.2.2.md: Validation evidence for the blocked 0.2.2 npm trusted-publishing retry.
|
|
14
16
|
windows-self-upgrade.md: Validation evidence for GitHub issues #9 and #1 and the Windows self-upgrade patch.
|
|
15
17
|
tags:
|
|
@@ -17,6 +19,8 @@ tags:
|
|
|
17
19
|
keywords:
|
|
18
20
|
- runx
|
|
19
21
|
- citty
|
|
22
|
+
- runx init
|
|
23
|
+
- scripts directory
|
|
20
24
|
- tests
|
|
21
25
|
- summary
|
|
22
26
|
- windows self-upgrade
|
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;AAaH,OAAO,KAAK,EAAkB,UAAU,EAAkB,MAAM,OAAO,CAAA;AAGvE,OAAO,EACL,MAAM,EACN,uBAAuB,EACvB,WAAW,GACZ,CAAA;AA8PD,QAAA,MAAiB,WAAW,iBAAwB,CAAA;AAEpD,iBAAe,MAAM,CAAC,OAAO,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAY9E;AAED,iBAAe,uBAAuB,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxE"}
|
package/library/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import { installAgentInstructions, installAgentSkill } from './agents.js';
|
|
|
7
7
|
import { RunXError } from './errors.js';
|
|
8
8
|
import { runCommand } from './executor.js';
|
|
9
9
|
import { readVersion, showHelpDocs, showHelpTree, showHome } from './help.js';
|
|
10
|
+
import { initializeRunXManifest } from './init.js';
|
|
10
11
|
import { readManifest, resolveCommand } from './manifest.js';
|
|
11
12
|
import { renderDescription, renderExecutionPlan, renderJson, renderList } from './render.js';
|
|
12
13
|
import { checkForLatestVersion, listAvailableVersions, uninstallSelf, upgradeSelf } from './self-management.js';
|
|
@@ -95,6 +96,12 @@ const createCommandTree = () => {
|
|
|
95
96
|
setup: withCommandHelp(state),
|
|
96
97
|
run: async () => checkManifest(resolveOptions(state.globalArgs)),
|
|
97
98
|
});
|
|
99
|
+
const initCommand = defineCommand({
|
|
100
|
+
meta: { name: 'runx init', description: 'Interactively create an empty RunX manifest.' },
|
|
101
|
+
args: commonArgs,
|
|
102
|
+
setup: withCommandHelp(state),
|
|
103
|
+
run: async () => initializeProject(state.globalArgs),
|
|
104
|
+
});
|
|
98
105
|
const agentsInstallCommand = defineCommand({
|
|
99
106
|
meta: { name: 'runx agents install', description: 'Install the bundled RunX skill.' },
|
|
100
107
|
args: {
|
|
@@ -166,6 +173,7 @@ const createCommandTree = () => {
|
|
|
166
173
|
describe: describeCommandDefinition,
|
|
167
174
|
run: runCommandDefinition,
|
|
168
175
|
check: checkCommand,
|
|
176
|
+
init: initCommand,
|
|
169
177
|
agents: agentsCommand,
|
|
170
178
|
upgrade: upgradeCommand,
|
|
171
179
|
uninstall: uninstallCommand,
|
|
@@ -176,6 +184,7 @@ const createCommandTree = () => {
|
|
|
176
184
|
['run', runCommandDefinition],
|
|
177
185
|
['r', runCommandDefinition],
|
|
178
186
|
['check', checkCommand],
|
|
187
|
+
['init', initCommand],
|
|
179
188
|
['agents', agentsCommand],
|
|
180
189
|
['agents install', agentsInstallCommand],
|
|
181
190
|
['agents instructions', agentsInstructionsCommand],
|
|
@@ -334,6 +343,15 @@ async function checkManifest(options) {
|
|
|
334
343
|
const result = { valid: true, manifestPath: path, commandCount: manifest.commands.length, groups: Object.keys(manifest.groups) };
|
|
335
344
|
write(options.format === 'json' ? renderJson(result) : `valid: true\nmanifest: ${path}\ncommands: ${result.commandCount}\n`);
|
|
336
345
|
}
|
|
346
|
+
async function initializeProject(args) {
|
|
347
|
+
if (args.file) {
|
|
348
|
+
throw new RunXError('runx init does not support --file. It always creates runx.yaml in --cwd or the current directory.');
|
|
349
|
+
}
|
|
350
|
+
if (args.format === 'json') {
|
|
351
|
+
throw new RunXError('runx init does not support --format json because initialization is an interactive terminal workflow.');
|
|
352
|
+
}
|
|
353
|
+
await initializeRunXManifest({ cwd: resolve(args.cwd ?? process.cwd()) });
|
|
354
|
+
}
|
|
337
355
|
async function runSelectedCommand(selector, options, args) {
|
|
338
356
|
const { manifest, path } = await readManifest(options.cwd, options.file);
|
|
339
357
|
const command = resolveCommand(manifest, path, selector);
|
package/library/help.d.ts.map
CHANGED
|
@@ -1 +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,
|
|
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,MAiB3B,CAAA;AAED,eAAO,MAAM,YAAY,QAAO,MAcpB,CAAA;AAEZ,eAAO,MAAM,YAAY,QAAO,MAW/B,CAAA"}
|
package/library/help.js
CHANGED
|
@@ -5,6 +5,7 @@ export const showHome = () => `RunX ${readVersion()}
|
|
|
5
5
|
A documented, local command catalog for runx.yaml manifests.
|
|
6
6
|
|
|
7
7
|
Usage:
|
|
8
|
+
runx init [--cwd <path>]
|
|
8
9
|
runx list [--file <path>] [--format <text|json>]
|
|
9
10
|
runx describe <selector>
|
|
10
11
|
runx run <selector> [--dry-run] [--yes]
|
|
@@ -12,6 +13,7 @@ Usage:
|
|
|
12
13
|
runx <selector>
|
|
13
14
|
|
|
14
15
|
Start here:
|
|
16
|
+
runx init Interactively create an empty runx.yaml catalog.
|
|
15
17
|
runx list List every command in the nearest manifest.
|
|
16
18
|
runx --help-tree Show the complete command tree.
|
|
17
19
|
runx --help-docs Show manifest and agent documentation guidance.
|
|
@@ -23,6 +25,7 @@ export const showHelpTree = () => [
|
|
|
23
25
|
'|- run <selector>',
|
|
24
26
|
'| `- alias: r',
|
|
25
27
|
'|- check',
|
|
28
|
+
'|- init',
|
|
26
29
|
'|- agents',
|
|
27
30
|
'| |- install <local|global>',
|
|
28
31
|
'| `- instructions',
|
|
@@ -33,6 +36,7 @@ export const showHelpTree = () => [
|
|
|
33
36
|
export const showHelpDocs = () => `RunX documentation
|
|
34
37
|
|
|
35
38
|
Manifest: runx.yaml, discovered from the current directory upward or selected with --file.
|
|
39
|
+
Create an empty catalog with runx init. Its manifest uses SemVer 1.x, configures a scripts directory, and always includes the public group.
|
|
36
40
|
Required command fields: uid, id, group, summary, description, command.
|
|
37
41
|
Optional command fields: cwd, shell, tags, confirm.
|
|
38
42
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
import type { RunXManifest } from './types.js';
|
|
5
|
+
export type RunXInitPrompter = {
|
|
6
|
+
intro(title: string): void;
|
|
7
|
+
text(options: {
|
|
8
|
+
message: string;
|
|
9
|
+
initialValue: string;
|
|
10
|
+
validate: (value: string | undefined) => string | undefined;
|
|
11
|
+
}): Promise<string | undefined>;
|
|
12
|
+
confirm(options: {
|
|
13
|
+
message: string;
|
|
14
|
+
initialValue: boolean;
|
|
15
|
+
}): Promise<boolean | undefined>;
|
|
16
|
+
preview(manifest: string): void;
|
|
17
|
+
cancel(message: string): void;
|
|
18
|
+
outro(message: string): void;
|
|
19
|
+
close?(): void;
|
|
20
|
+
};
|
|
21
|
+
export type RunXInitResult = {
|
|
22
|
+
status: 'cancelled';
|
|
23
|
+
} | {
|
|
24
|
+
status: 'created';
|
|
25
|
+
path: string;
|
|
26
|
+
manifest: RunXManifest;
|
|
27
|
+
};
|
|
28
|
+
type RunXInitOptions = {
|
|
29
|
+
cwd: string;
|
|
30
|
+
isInteractive?: boolean;
|
|
31
|
+
prompter?: RunXInitPrompter;
|
|
32
|
+
};
|
|
33
|
+
export declare const initializeRunXManifest: ({ cwd, isInteractive, prompter }: RunXInitOptions) => Promise<RunXInitResult>;
|
|
34
|
+
export declare const createInitialManifest: (projectName: string, scriptsDirectory: string) => RunXManifest;
|
|
35
|
+
export declare const renderInitialManifest: (manifest: RunXManifest) => string;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../source/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,IAAI,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAClJ,OAAO,CAAC,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAA;IAC1F,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,KAAK,CAAC,IAAI,IAAI,CAAA;CACf,CAAA;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,MAAM,EAAE,WAAW,CAAA;CAAE,GACvB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE,CAAA;AAE/D,KAAK,eAAe,GAAG;IACrB,GAAG,EAAE,MAAM,CAAA;IACX,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,gBAAgB,CAAA;CAC5B,CAAA;AAID,eAAO,MAAM,sBAAsB,qCAA4G,eAAe,KAAG,OAAO,CAAC,cAAc,CAmDtL,CAAA;AAED,eAAO,MAAM,qBAAqB,gBAAiB,MAAM,oBAAoB,MAAM,KAAG,YAQpF,CAAA;AAEF,eAAO,MAAM,qBAAqB,aAAc,YAAY,KAAG,MAenD,CAAA"}
|
package/library/init.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { rename, rm, writeFile } from 'node:fs/promises';
|
|
6
|
+
import { basename, isAbsolute, relative, resolve } from 'node:path';
|
|
7
|
+
import { createInterface } from 'node:readline/promises';
|
|
8
|
+
import { RunXError } from './errors.js';
|
|
9
|
+
import { readManifest } from './manifest.js';
|
|
10
|
+
const manifestVersion = '1.0.0';
|
|
11
|
+
export const initializeRunXManifest = async ({ cwd, isInteractive = process.stdin.isTTY === true && process.stdout.isTTY === true, prompter }) => {
|
|
12
|
+
if (!isInteractive) {
|
|
13
|
+
throw new RunXError('runx init requires an interactive terminal. Run it directly in a terminal with stdin and stdout attached.');
|
|
14
|
+
}
|
|
15
|
+
const activePrompter = prompter ?? createTerminalPrompter();
|
|
16
|
+
try {
|
|
17
|
+
const root = resolve(cwd);
|
|
18
|
+
const path = resolve(root, 'runx.yaml');
|
|
19
|
+
const defaultProjectName = basename(root) || 'my-project';
|
|
20
|
+
activePrompter.intro('RunX project setup');
|
|
21
|
+
if (await Bun.file(path).exists()) {
|
|
22
|
+
const overwrite = await activePrompter.confirm({
|
|
23
|
+
message: 'runx.yaml already exists. Replace it?',
|
|
24
|
+
initialValue: false,
|
|
25
|
+
});
|
|
26
|
+
if (overwrite !== true)
|
|
27
|
+
return cancelInitialization(activePrompter);
|
|
28
|
+
}
|
|
29
|
+
const projectName = await activePrompter.text({
|
|
30
|
+
message: 'Project name',
|
|
31
|
+
initialValue: defaultProjectName,
|
|
32
|
+
validate: (value) => value?.trim() ? undefined : 'Enter a project name.',
|
|
33
|
+
});
|
|
34
|
+
if (projectName === undefined)
|
|
35
|
+
return cancelInitialization(activePrompter);
|
|
36
|
+
const scriptsDirectory = await activePrompter.text({
|
|
37
|
+
message: 'Scripts directory',
|
|
38
|
+
initialValue: 'scripts',
|
|
39
|
+
validate: (value) => validateScriptsDirectory(value, root),
|
|
40
|
+
});
|
|
41
|
+
if (scriptsDirectory === undefined)
|
|
42
|
+
return cancelInitialization(activePrompter);
|
|
43
|
+
const manifest = createInitialManifest(projectName.trim(), scriptsDirectory.trim());
|
|
44
|
+
const yaml = renderInitialManifest(manifest);
|
|
45
|
+
activePrompter.preview(yaml);
|
|
46
|
+
const confirmed = await activePrompter.confirm({
|
|
47
|
+
message: 'Create this runx.yaml?',
|
|
48
|
+
initialValue: true,
|
|
49
|
+
});
|
|
50
|
+
if (confirmed !== true)
|
|
51
|
+
return cancelInitialization(activePrompter);
|
|
52
|
+
await writeValidatedManifest(root, path, yaml);
|
|
53
|
+
activePrompter.outro(`Created ${path}`);
|
|
54
|
+
return { status: 'created', path, manifest };
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
activePrompter.close?.();
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export const createInitialManifest = (projectName, scriptsDirectory) => ({
|
|
61
|
+
version: manifestVersion,
|
|
62
|
+
project: { name: projectName },
|
|
63
|
+
scripts: { directory: scriptsDirectory },
|
|
64
|
+
groups: {
|
|
65
|
+
public: { summary: 'Default public project commands.' },
|
|
66
|
+
},
|
|
67
|
+
commands: [],
|
|
68
|
+
});
|
|
69
|
+
export const renderInitialManifest = (manifest) => [
|
|
70
|
+
`version: ${JSON.stringify(manifest.version)}`,
|
|
71
|
+
'',
|
|
72
|
+
'project:',
|
|
73
|
+
` name: ${JSON.stringify(manifest.project?.name ?? '')}`,
|
|
74
|
+
'',
|
|
75
|
+
'scripts:',
|
|
76
|
+
` directory: ${JSON.stringify(manifest.scripts.directory)}`,
|
|
77
|
+
'',
|
|
78
|
+
'groups:',
|
|
79
|
+
' public:',
|
|
80
|
+
` summary: ${JSON.stringify(manifest.groups.public.summary)}`,
|
|
81
|
+
'',
|
|
82
|
+
'commands: []',
|
|
83
|
+
'',
|
|
84
|
+
].join('\n');
|
|
85
|
+
const createTerminalPrompter = () => {
|
|
86
|
+
const terminal = createInterface({ input: process.stdin, output: process.stdout, terminal: true });
|
|
87
|
+
const accent = (value) => process.env['NO_COLOR'] ? value : `\u001b[36m${value}\u001b[0m`;
|
|
88
|
+
const success = (value) => process.env['NO_COLOR'] ? value : `\u001b[32m${value}\u001b[0m`;
|
|
89
|
+
const muted = (value) => process.env['NO_COLOR'] ? value : `\u001b[2m${value}\u001b[0m`;
|
|
90
|
+
const error = (value) => process.env['NO_COLOR'] ? value : `\u001b[31m${value}\u001b[0m`;
|
|
91
|
+
const write = (value) => {
|
|
92
|
+
process.stdout.write(value);
|
|
93
|
+
};
|
|
94
|
+
const ask = async (label) => {
|
|
95
|
+
try {
|
|
96
|
+
return await terminal.question(label);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
intro: (title) => write(`\n${accent('◆')} ${title}\n${muted(' A documented command catalog for this project.')}\n\n`),
|
|
104
|
+
text: async (options) => {
|
|
105
|
+
while (true) {
|
|
106
|
+
const value = await ask(`${accent('◆')} ${options.message} ${muted(`[${options.initialValue}]`)}\n `);
|
|
107
|
+
if (value === undefined)
|
|
108
|
+
return undefined;
|
|
109
|
+
const selected = value.trim() || options.initialValue;
|
|
110
|
+
const validation = options.validate(selected);
|
|
111
|
+
if (!validation)
|
|
112
|
+
return selected;
|
|
113
|
+
write(`${error('▲')} ${validation}\n`);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
confirm: async (options) => {
|
|
117
|
+
while (true) {
|
|
118
|
+
const defaultLabel = options.initialValue ? 'Y/n' : 'y/N';
|
|
119
|
+
const value = await ask(`${accent('◆')} ${options.message} ${muted(`[${defaultLabel}]`)}\n `);
|
|
120
|
+
if (value === undefined)
|
|
121
|
+
return undefined;
|
|
122
|
+
const answer = value.trim().toLowerCase();
|
|
123
|
+
if (!answer)
|
|
124
|
+
return options.initialValue;
|
|
125
|
+
if (answer === 'y' || answer === 'yes')
|
|
126
|
+
return true;
|
|
127
|
+
if (answer === 'n' || answer === 'no')
|
|
128
|
+
return false;
|
|
129
|
+
write(`${error('▲')} Enter yes or no.\n`);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
preview: (manifest) => write(`\n${accent('┌─ runx.yaml preview ─────────────────────────────────')}\n${manifest.trimEnd().split('\n').map((line) => `${accent('│')} ${line}`).join('\n')}\n${accent('└────────────────────────────────────────────────────')}\n\n`),
|
|
133
|
+
cancel: (message) => write(`${error('■')} ${message}\n`),
|
|
134
|
+
outro: (message) => {
|
|
135
|
+
write(`${success('◆')} ${message}\n`);
|
|
136
|
+
},
|
|
137
|
+
close: () => terminal.close(),
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
const cancelInitialization = (prompter) => {
|
|
141
|
+
prompter.cancel('Initialization cancelled. No files were changed.');
|
|
142
|
+
return { status: 'cancelled' };
|
|
143
|
+
};
|
|
144
|
+
const validateScriptsDirectory = (value, root) => {
|
|
145
|
+
const directory = value?.trim();
|
|
146
|
+
if (!directory)
|
|
147
|
+
return 'Enter a scripts directory.';
|
|
148
|
+
const resolvedDirectory = resolve(root, directory);
|
|
149
|
+
const relativeDirectory = relative(root, resolvedDirectory);
|
|
150
|
+
if (relativeDirectory === '' || relativeDirectory === '.' || isAbsolute(relativeDirectory) || relativeDirectory.startsWith('..')) {
|
|
151
|
+
return 'Use a relative subdirectory inside this project.';
|
|
152
|
+
}
|
|
153
|
+
return undefined;
|
|
154
|
+
};
|
|
155
|
+
const writeValidatedManifest = async (root, path, yaml) => {
|
|
156
|
+
const temporaryPath = resolve(root, `.runx-${randomUUID()}.yaml.tmp`);
|
|
157
|
+
try {
|
|
158
|
+
await writeFile(temporaryPath, yaml, { encoding: 'utf8', flag: 'wx' });
|
|
159
|
+
await readManifest(root, temporaryPath);
|
|
160
|
+
await rename(temporaryPath, path);
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
await rm(temporaryPath, { force: true });
|
|
164
|
+
}
|
|
165
|
+
};
|
package/library/manifest.d.ts
CHANGED
|
@@ -12,10 +12,13 @@ export declare const CommandSchema: import("@sinclair/typebox").TObject<{
|
|
|
12
12
|
confirm: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TLiteral<"never">, import("@sinclair/typebox").TLiteral<"always">]>>;
|
|
13
13
|
}>;
|
|
14
14
|
export declare const ManifestSchema: import("@sinclair/typebox").TObject<{
|
|
15
|
-
version: import("@sinclair/typebox").
|
|
15
|
+
version: import("@sinclair/typebox").TString;
|
|
16
16
|
project: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
17
17
|
name: import("@sinclair/typebox").TString;
|
|
18
18
|
}>>;
|
|
19
|
+
scripts: import("@sinclair/typebox").TObject<{
|
|
20
|
+
directory: import("@sinclair/typebox").TString;
|
|
21
|
+
}>;
|
|
19
22
|
groups: import("@sinclair/typebox").TRecord<import("@sinclair/typebox").TString, import("@sinclair/typebox").TObject<{
|
|
20
23
|
summary: import("@sinclair/typebox").TString;
|
|
21
24
|
}>>;
|
|
@@ -1 +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;
|
|
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;AAK5E,eAAO,MAAM,aAAa;;;;;;;;;;;EAiBS,CAAA;AAEnC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;EAMQ,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"}
|
package/library/manifest.js
CHANGED
|
@@ -3,6 +3,7 @@ import { Type } from '@sinclair/typebox';
|
|
|
3
3
|
import { TypeCompiler } from '@sinclair/typebox/compiler';
|
|
4
4
|
import { RunXError, invariant } from './errors.js';
|
|
5
5
|
const identifier = '^[a-z][a-z0-9-]*$';
|
|
6
|
+
const semver = '^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$';
|
|
6
7
|
export const CommandSchema = Type.Object({
|
|
7
8
|
uid: Type.String({ pattern: identifier }),
|
|
8
9
|
id: Type.String({ pattern: identifier }),
|
|
@@ -22,10 +23,11 @@ export const CommandSchema = Type.Object({
|
|
|
22
23
|
confirm: Type.Optional(Type.Union([Type.Literal('never'), Type.Literal('always')])),
|
|
23
24
|
}, { additionalProperties: false });
|
|
24
25
|
export const ManifestSchema = Type.Object({
|
|
25
|
-
version: Type.
|
|
26
|
+
version: Type.String({ pattern: semver }),
|
|
26
27
|
project: Type.Optional(Type.Object({ name: Type.String({ minLength: 1 }) }, { additionalProperties: false })),
|
|
28
|
+
scripts: Type.Object({ directory: Type.String({ minLength: 1 }) }, { additionalProperties: false }),
|
|
27
29
|
groups: Type.Record(Type.String({ pattern: identifier }), Type.Object({ summary: Type.String({ minLength: 1 }) }, { additionalProperties: false })),
|
|
28
|
-
commands: Type.Array(CommandSchema
|
|
30
|
+
commands: Type.Array(CommandSchema),
|
|
29
31
|
}, { additionalProperties: false });
|
|
30
32
|
const manifestCheck = TypeCompiler.Compile(ManifestSchema);
|
|
31
33
|
export const findManifest = async (cwd, explicitFile) => {
|
|
@@ -96,6 +98,17 @@ export const resolveCommand = (manifest, manifestPath, selector) => {
|
|
|
96
98
|
};
|
|
97
99
|
};
|
|
98
100
|
const validateManifestSemantics = (manifest, path) => {
|
|
101
|
+
const versionMajor = manifest.version.split('.', 1)[0];
|
|
102
|
+
if (versionMajor !== '1') {
|
|
103
|
+
throw new RunXError(`Unsupported RunX manifest version "${manifest.version}" in ${path}. Supported major version: 1.`);
|
|
104
|
+
}
|
|
105
|
+
const manifestDirectory = dirname(path);
|
|
106
|
+
const scriptsDirectory = resolve(manifestDirectory, manifest.scripts.directory);
|
|
107
|
+
const relativeScriptsDirectory = relative(manifestDirectory, scriptsDirectory);
|
|
108
|
+
invariant(relativeScriptsDirectory !== '' && relativeScriptsDirectory !== '.' && !isAbsolute(relativeScriptsDirectory) && !relativeScriptsDirectory.startsWith('..'), `Scripts directory "${manifest.scripts.directory}" must be a relative subdirectory inside the manifest directory in ${path}.`);
|
|
109
|
+
if (!manifest.groups.public) {
|
|
110
|
+
throw new RunXError(`RunX manifest ${path} must define the default "public" group.`);
|
|
111
|
+
}
|
|
99
112
|
const uids = new Set();
|
|
100
113
|
const selectors = new Set();
|
|
101
114
|
for (const command of manifest.commands) {
|
package/package.json
CHANGED