@guiho/mirror 3.1.1 → 3.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 +15 -0
- package/DOCS.md +23 -5
- package/README.md +9 -6
- package/jsr.json +1 -1
- package/library/adapters.d.ts +4 -0
- package/library/adapters.d.ts.map +1 -1
- package/library/adapters.js +8 -1
- package/library/cli.d.ts.map +1 -1
- package/library/cli.js +54 -13
- package/library/config.d.ts +5 -1
- package/library/config.d.ts.map +1 -1
- package/library/config.js +135 -89
- package/library/executor.d.ts.map +1 -1
- package/library/executor.js +5 -7
- package/library/flags.d.ts.map +1 -1
- package/library/flags.js +11 -1
- package/library/guiho-mirror.d.ts +5 -3
- package/library/guiho-mirror.d.ts.map +1 -1
- package/library/guiho-mirror.js +4 -2
- package/library/init.d.ts +12 -0
- package/library/init.d.ts.map +1 -0
- package/library/init.js +100 -0
- package/library/plan.d.ts.map +1 -1
- package/library/plan.js +9 -5
- package/library/reporter.d.ts.map +1 -1
- package/library/reporter.js +4 -1
- package/library/schema.d.ts +133 -0
- package/library/schema.d.ts.map +1 -0
- package/library/schema.js +128 -0
- package/library/types.d.ts +35 -0
- package/library/types.d.ts.map +1 -1
- package/package.json +2 -1
- package/schema/mirror.config.schema.json +148 -0
- package/skills/guiho-as-mirror/SKILL.md +13 -7
package/CHANGELOG.md
CHANGED
|
@@ -5,12 +5,27 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.2.0] - 2026-06-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added auxiliary package outputs via `[package].auxiliary_paths` so extra `package.json` files mirror the main package version.
|
|
13
|
+
- Added an interactive `mirror init` wizard (TTY-only) with defaults you accept by pressing Enter, plus flags for every answer and `--non-interactive` for automation.
|
|
14
|
+
- Added new `mirror init` flags: `--output`, `--auxiliary`, `--tag-template`, `--name`, `--commit`, `--push`, `--non-interactive`.
|
|
15
|
+
- Added a JSON Schema for `mirror.config.toml`, shipped at `schema/mirror.config.schema.json` and printable via `mirror config schema --format json`.
|
|
16
|
+
- Generated config files now include a `#:schema` directive for editor autocomplete.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- `mirror init` now reconciles an existing `mirror.config.toml` (adds missing defaults) instead of failing, and `--yes` overwrites with generated defaults.
|
|
21
|
+
|
|
8
22
|
## [3.1.1] - 2026-06-07
|
|
9
23
|
|
|
10
24
|
### Changed
|
|
11
25
|
|
|
12
26
|
- Changed Mirror skill installation paths to the standard `.agents/skills` and `~/.agents/skills` directories.
|
|
13
27
|
- Changed automatic skill installation to global-only by default while keeping explicit local installation available through `mirror agents install local`.
|
|
28
|
+
- Changed no-argument `mirror` startup to run configured agent setup before showing help.
|
|
14
29
|
- Updated documentation, schema text, and tests to describe the standard agent skill directories.
|
|
15
30
|
|
|
16
31
|
## [3.1.0] - 2026-06-07
|
package/DOCS.md
CHANGED
|
@@ -160,7 +160,15 @@ Version and config commands accept runtime overrides.
|
|
|
160
160
|
|
|
161
161
|
### `mirror init`
|
|
162
162
|
|
|
163
|
-
Creates `mirror.config.toml` in the current working directory.
|
|
163
|
+
Creates `mirror.config.toml` in the current working directory. When a configuration file already exists, `mirror init` reconciles missing default keys into it without overwriting user-configured values. Use `--yes` only when you intentionally want to replace the file with freshly generated defaults.
|
|
164
|
+
|
|
165
|
+
On an interactive terminal, `mirror init` runs a step-by-step wizard for the core fields (version source, outputs, package path, auxiliary package paths, jsr path, git tag template, commit, push). Each prompt shows a default that you accept by pressing Enter. Defaults are source `package.json` and outputs `package.json` + `git`.
|
|
166
|
+
|
|
167
|
+
Every answer also has a flag, so the command runs fully non-interactively when flags are provided. In non-TTY environments (CI, AI agents) or with `--non-interactive`/`--yes`, Mirror skips prompts and uses flags + defaults instead of waiting for input.
|
|
168
|
+
|
|
169
|
+
Init flags: `--source`, `--output`, `--package-file`, `--jsr-file`, `--auxiliary`, `--tag-template`, `--name`, `--preid`, `--commit`, `--push`, `--non-interactive`, `--yes`.
|
|
170
|
+
|
|
171
|
+
Generated configuration files start with a `#:schema` directive pointing at the bundled JSON Schema (`./node_modules/@guiho/mirror/schema/mirror.config.schema.json`) so editors with Taplo / Even Better TOML provide autocomplete and validation.
|
|
164
172
|
|
|
165
173
|
```bash
|
|
166
174
|
mirror init package.json
|
|
@@ -182,7 +190,7 @@ mirror config schema
|
|
|
182
190
|
|
|
183
191
|
- `show`: Prints the resolved configuration after defaults and CLI overrides.
|
|
184
192
|
- `check`: Validates configuration, adapter files, Git availability, and supported Git tag templates.
|
|
185
|
-
- `schema`: Prints the configuration reference.
|
|
193
|
+
- `schema`: Prints the configuration reference. `--format json` prints a JSON Schema for editor autocomplete; the same schema ships at `schema/mirror.config.schema.json`.
|
|
186
194
|
|
|
187
195
|
### `mirror agents`
|
|
188
196
|
|
|
@@ -245,6 +253,7 @@ prerelease_id = "alpha"
|
|
|
245
253
|
|
|
246
254
|
[package]
|
|
247
255
|
path = "package.json"
|
|
256
|
+
auxiliary_paths = []
|
|
248
257
|
|
|
249
258
|
[jsr]
|
|
250
259
|
path = "jsr.json"
|
|
@@ -285,6 +294,9 @@ Exactly one source is used. Multiple outputs are allowed.
|
|
|
285
294
|
### `[package]`
|
|
286
295
|
|
|
287
296
|
- `path`: Optional path to `package.json`. Default: `package.json`.
|
|
297
|
+
- `auxiliary_paths`: Optional array of extra `package.json` files that mirror the main package version. Default: `[]`.
|
|
298
|
+
|
|
299
|
+
The main package path remains the source of truth for package version reads and project name reads. Auxiliary package files are write-only mirrors: when `package.json` is in `[version].output`, Mirror plans and writes the same next version to each auxiliary package file and includes those files in release commits.
|
|
288
300
|
|
|
289
301
|
### `[jsr]`
|
|
290
302
|
|
|
@@ -319,7 +331,7 @@ Mirror uses standard agent skill directories:
|
|
|
319
331
|
|
|
320
332
|
Mirror can self-provision AI-agent instructions for projects that use standard agent skill directories.
|
|
321
333
|
|
|
322
|
-
When automation is enabled, project commands check for `AGENTS.md` and for global `guiho-as-mirror` skill installation. If guidance is missing, Mirror notifies the user and writes the missing global skill or AGENTS section. Mirror does not automatically write a local skill file; local installation is explicit.
|
|
334
|
+
When automation is enabled, project commands check for `AGENTS.md` and for global `guiho-as-mirror` skill installation. If guidance is missing, Mirror notifies the user and writes the missing global skill or AGENTS section. Running `mirror` with no arguments performs this configured setup before showing help. Mirror does not automatically write a local skill file; local installation is explicit.
|
|
323
335
|
|
|
324
336
|
Automation is controlled by `[agents]`.
|
|
325
337
|
|
|
@@ -414,7 +426,9 @@ The API uses the same configuration discovery and safety rules as the CLI.
|
|
|
414
426
|
- `source/guiho-mirror.ts`: public library export surface.
|
|
415
427
|
- `source/guiho-mirror-bin.ts`: CLI binary entrypoint.
|
|
416
428
|
- `source/cli.ts`: citty command tree, CLI argument mapping, and process-facing error handling.
|
|
417
|
-
- `source/config.ts`: TOML discovery, schema validation, defaulting, init config generation, and override merge.
|
|
429
|
+
- `source/config.ts`: TOML discovery, schema validation, defaulting, init config generation, init reconciliation, and override merge.
|
|
430
|
+
- `source/init.ts`: init answer resolution, interactive prompts (TTY-only), and defaults.
|
|
431
|
+
- `source/schema.ts`: JSON Schema for `mirror.config.toml` and the `#:schema` reference.
|
|
418
432
|
- `source/types.ts`: public and internal TypeScript types.
|
|
419
433
|
- `source/version.ts`: semver target validation and next-version resolution.
|
|
420
434
|
- `source/adapters.ts`: package, JSR, and Git read/write primitives.
|
|
@@ -516,7 +530,11 @@ Run `mirror init package.json`, `mirror init jsr.json`, or `mirror init git` fro
|
|
|
516
530
|
|
|
517
531
|
### Adapter file not found
|
|
518
532
|
|
|
519
|
-
Check `[package].path` or `[jsr].path`, or pass `--package-file` or `--jsr-file`.
|
|
533
|
+
Check `[package].path`, `[package].auxiliary_paths`, or `[jsr].path`, or pass `--package-file` or `--jsr-file`.
|
|
534
|
+
|
|
535
|
+
### Auxiliary package version did not change
|
|
536
|
+
|
|
537
|
+
Ensure `package.json` is present in `[version].output` and the file is listed in `[package].auxiliary_paths`.
|
|
520
538
|
|
|
521
539
|
### Unsupported Git tag template
|
|
522
540
|
|
package/README.md
CHANGED
|
@@ -73,16 +73,18 @@ Adapters connect Mirror to different versioning ecosystems:
|
|
|
73
73
|
Mirror provides a concise CLI with three main command groups:
|
|
74
74
|
|
|
75
75
|
#### `mirror init`
|
|
76
|
-
Creates a `mirror.config.toml` file in the current directory.
|
|
77
|
-
- `mirror init
|
|
78
|
-
- `mirror init jsr.json`
|
|
79
|
-
-
|
|
76
|
+
Creates or reconciles a `mirror.config.toml` file in the current directory. On an interactive terminal, `mirror init` asks step-by-step questions (version source, outputs, package path, auxiliary paths, tag template, commit/push) with defaults you accept by pressing Enter. Pass flags to answer non-interactively, and in CI / non-TTY environments it uses flags + defaults without prompting.
|
|
77
|
+
- `mirror init` (interactive wizard, or flags + defaults when non-interactive)
|
|
78
|
+
- `mirror init package.json` / `mirror init jsr.json` / `mirror init git` (source shortcut)
|
|
79
|
+
- Flags: `--source`, `--output`, `--package-file`, `--jsr-file`, `--auxiliary`, `--tag-template`, `--name`, `--preid`, `--commit`, `--push`, `--non-interactive`, `--yes`
|
|
80
|
+
|
|
81
|
+
Defaults: source `package.json`, outputs `package.json` + `git`.
|
|
80
82
|
|
|
81
83
|
#### `mirror config`
|
|
82
84
|
Validates and inspects configuration.
|
|
83
85
|
- `mirror config show`: Prints the resolved configuration.
|
|
84
86
|
- `mirror config check`: Validates configuration without output.
|
|
85
|
-
- `mirror config schema`: Prints the comprehensive configuration reference.
|
|
87
|
+
- `mirror config schema`: Prints the comprehensive configuration reference. Use `--format json` to print a JSON Schema for editor autocomplete.
|
|
86
88
|
|
|
87
89
|
#### `mirror agents`
|
|
88
90
|
Installs Mirror-aware agent guidance for projects that use AI coding agents.
|
|
@@ -118,6 +120,7 @@ prerelease_id = "alpha" # Optional. e.g., creates 1.0.1-alpha.0
|
|
|
118
120
|
|
|
119
121
|
[package]
|
|
120
122
|
path = "package.json" # Optional. Override path to package.json
|
|
123
|
+
auxiliary_paths = [] # Optional. Extra package.json files that mirror the main version
|
|
121
124
|
|
|
122
125
|
[jsr]
|
|
123
126
|
path = "jsr.json" # Optional. Override path to jsr.json
|
|
@@ -137,7 +140,7 @@ auto_skill_install = true # Optional. Install guiho-as-mirror globa
|
|
|
137
140
|
|
|
138
141
|
### Agent Automation
|
|
139
142
|
|
|
140
|
-
Mirror is designed to be safely used by AI agents. Project commands automatically check for `AGENTS.md` and the `guiho-as-mirror` skill, then add the Mirror guidance or install the missing skill when automation is enabled.
|
|
143
|
+
Mirror is designed to be safely used by AI agents. Project commands automatically check for `AGENTS.md` and the `guiho-as-mirror` skill, then add the Mirror guidance or install the missing skill when automation is enabled. Running `mirror` with no arguments also performs this configured agent setup before showing help.
|
|
141
144
|
|
|
142
145
|
Set `write_changelog = false` when agents should skip changelog edits during release preparation. Set `changelog_path = "docs/CHANGELOG.md"` when the changelog is not at the project root. Set `auto_agents_md = false` to opt out of automatic guidance insertion, or `auto_skill_install = false` to opt out of automatic global skill installation.
|
|
143
146
|
|
package/jsr.json
CHANGED
package/library/adapters.d.ts
CHANGED
|
@@ -9,10 +9,14 @@ export declare const readJsrJson: (path: string) => Promise<MirrorJsonObject>;
|
|
|
9
9
|
export declare const writeJsonObject: (path: string, object: MirrorJsonObject) => Promise<void>;
|
|
10
10
|
export declare const readPackageVersion: (config: MirrorConfig) => Promise<string>;
|
|
11
11
|
export declare const readJsrVersion: (config: MirrorConfig) => Promise<string>;
|
|
12
|
+
export declare const readPackageVersionFile: (path: string) => Promise<string>;
|
|
13
|
+
export declare const readJsrVersionFile: (path: string) => Promise<string>;
|
|
12
14
|
export declare const readPackageName: (config: MirrorConfig) => Promise<string>;
|
|
13
15
|
export declare const readJsrName: (config: MirrorConfig) => Promise<string>;
|
|
14
16
|
export declare const writePackageVersion: (config: MirrorConfig, nextVersion: string) => Promise<void>;
|
|
15
17
|
export declare const writeJsrVersion: (config: MirrorConfig, nextVersion: string) => Promise<void>;
|
|
18
|
+
export declare const writePackageVersionFile: (path: string, nextVersion: string) => Promise<void>;
|
|
19
|
+
export declare const writeJsrVersionFile: (path: string, nextVersion: string) => Promise<void>;
|
|
16
20
|
export declare const ensureAdapterFiles: (config: MirrorConfig) => Promise<void>;
|
|
17
21
|
export declare const resolveProjectName: (config: MirrorConfig) => Promise<string | undefined>;
|
|
18
22
|
export declare const readCurrentVersion: (config: MirrorConfig, projectName?: string) => Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../source/adapters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAsBhE,eAAO,MAAM,kBAAkB,qBAI9B,CAAA;AAiBD,eAAO,MAAM,wBAAwB,kEAAmE,CAAA;AAExG,eAAO,MAAM,eAAe,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,gBAAgB,CAAyC,CAAA;AACtH,eAAO,MAAM,WAAW,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,gBAAgB,CAAqC,CAAA;AAE9G,eAAO,MAAM,eAAe,GAAU,MAAM,MAAM,EAAE,QAAQ,gBAAgB,kBAE3E,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAU,QAAQ,YAAY,oBAAyF,CAAA;AACtJ,eAAO,MAAM,cAAc,GAAU,QAAQ,YAAY,oBAAiF,CAAA;AAC1I,eAAO,MAAM,eAAe,GAAU,QAAQ,YAAY,oBAAsF,CAAA;AAChJ,eAAO,MAAM,WAAW,GAAU,QAAQ,YAAY,oBAA8E,CAAA;AAEpI,eAAO,MAAM,mBAAmB,GAAU,QAAQ,YAAY,EAAE,aAAa,MAAM,kBACiB,CAAA;AAEpG,eAAO,MAAM,eAAe,GAAU,QAAQ,YAAY,EAAE,aAAa,MAAM,kBACa,CAAA;AAE5F,eAAO,MAAM,kBAAkB,GAAU,QAAQ,YAAY,
|
|
1
|
+
{"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../source/adapters.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAsBhE,eAAO,MAAM,kBAAkB,qBAI9B,CAAA;AAiBD,eAAO,MAAM,wBAAwB,kEAAmE,CAAA;AAExG,eAAO,MAAM,eAAe,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,gBAAgB,CAAyC,CAAA;AACtH,eAAO,MAAM,WAAW,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,gBAAgB,CAAqC,CAAA;AAE9G,eAAO,MAAM,eAAe,GAAU,MAAM,MAAM,EAAE,QAAQ,gBAAgB,kBAE3E,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAU,QAAQ,YAAY,oBAAyF,CAAA;AACtJ,eAAO,MAAM,cAAc,GAAU,QAAQ,YAAY,oBAAiF,CAAA;AAC1I,eAAO,MAAM,sBAAsB,GAAU,MAAM,MAAM,oBAA2C,CAAA;AACpG,eAAO,MAAM,kBAAkB,GAAU,MAAM,MAAM,oBAAuC,CAAA;AAC5F,eAAO,MAAM,eAAe,GAAU,QAAQ,YAAY,oBAAsF,CAAA;AAChJ,eAAO,MAAM,WAAW,GAAU,QAAQ,YAAY,oBAA8E,CAAA;AAEpI,eAAO,MAAM,mBAAmB,GAAU,QAAQ,YAAY,EAAE,aAAa,MAAM,kBACiB,CAAA;AAEpG,eAAO,MAAM,eAAe,GAAU,QAAQ,YAAY,EAAE,aAAa,MAAM,kBACa,CAAA;AAE5F,eAAO,MAAM,uBAAuB,GAAU,MAAM,MAAM,EAAE,aAAa,MAAM,kBAAyD,CAAA;AACxI,eAAO,MAAM,mBAAmB,GAAU,MAAM,MAAM,EAAE,aAAa,MAAM,kBAAqD,CAAA;AAEhI,eAAO,MAAM,kBAAkB,GAAU,QAAQ,YAAY,kBAO5D,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAU,QAAQ,YAAY,gCAK5D,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAU,QAAQ,YAAY,EAAE,cAAc,MAAM,oBAIlF,CAAA;AAED,eAAO,MAAM,cAAc,GAAU,QAAQ,YAAY,EAAE,cAAc,MAAM,oBAe9E,CAAA;AAED,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,EAAE,SAAS,MAAM,EAAE,cAAc,MAAM,WAOnF,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,UAAU,MAAM,EAAE,KAAK,MAAM,EAAE,cAAc,MAAM,uBAmBjF,CAAA;AAED,eAAO,MAAM,6BAA6B,GAAI,UAAU,MAAM,SAI7D,CAAA;AAED,eAAO,MAAM,eAAe,GAAU,KAAK,MAAM,qBAQhD,CAAA;AAED,eAAO,MAAM,UAAU,GAAU,KAAK,MAAM,qBAG3C,CAAA;AAED,eAAO,MAAM,eAAe,GAAU,KAAK,MAAM,EAAE,OAAO,MAAM,EAAE,EAAE,SAAS,MAAM,kBAIlF,CAAA;AAED,eAAO,MAAM,YAAY,GAAU,KAAK,MAAM,EAAE,KAAK,MAAM,kBAG1D,CAAA;AAED,eAAO,MAAM,WAAW,GAAU,KAAK,MAAM,EAAE,eAAe,OAAO,EAAE,aAAa,OAAO,kBAI1F,CAAA"}
|
package/library/adapters.js
CHANGED
|
@@ -51,13 +51,20 @@ export const writeJsonObject = async (path, object) => {
|
|
|
51
51
|
};
|
|
52
52
|
export const readPackageVersion = async (config) => readVersionField(resolveMirrorPath(config.cwd, config.package.path), 'package.json');
|
|
53
53
|
export const readJsrVersion = async (config) => readVersionField(resolveMirrorPath(config.cwd, config.jsr.path), 'jsr.json');
|
|
54
|
+
export const readPackageVersionFile = async (path) => readVersionField(path, 'package.json');
|
|
55
|
+
export const readJsrVersionFile = async (path) => readVersionField(path, 'jsr.json');
|
|
54
56
|
export const readPackageName = async (config) => readNameField(resolveMirrorPath(config.cwd, config.package.path), 'package.json');
|
|
55
57
|
export const readJsrName = async (config) => readNameField(resolveMirrorPath(config.cwd, config.jsr.path), 'jsr.json');
|
|
56
58
|
export const writePackageVersion = async (config, nextVersion) => writeVersionField(resolveMirrorPath(config.cwd, config.package.path), 'package.json', nextVersion);
|
|
57
59
|
export const writeJsrVersion = async (config, nextVersion) => writeVersionField(resolveMirrorPath(config.cwd, config.jsr.path), 'jsr.json', nextVersion);
|
|
60
|
+
export const writePackageVersionFile = async (path, nextVersion) => writeVersionField(path, 'package.json', nextVersion);
|
|
61
|
+
export const writeJsrVersionFile = async (path, nextVersion) => writeVersionField(path, 'jsr.json', nextVersion);
|
|
58
62
|
export const ensureAdapterFiles = async (config) => {
|
|
59
|
-
if (usesAdapter(config, 'package.json'))
|
|
63
|
+
if (usesAdapter(config, 'package.json')) {
|
|
60
64
|
ensureFile(resolveMirrorPath(config.cwd, config.package.path), 'package.json');
|
|
65
|
+
for (const path of config.package.auxiliaryPaths)
|
|
66
|
+
ensureFile(resolveMirrorPath(config.cwd, path), 'package.json');
|
|
67
|
+
}
|
|
61
68
|
if (usesAdapter(config, 'jsr.json'))
|
|
62
69
|
ensureFile(resolveMirrorPath(config.cwd, config.jsr.path), 'jsr.json');
|
|
63
70
|
if (usesAdapter(config, 'git'))
|
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;AA4DH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;EAc5B,CAAA;AAEJ,eAAO,MAAM,YAAY,GAAU,kBAA+B,kBAwEjE,CAAA"}
|
package/library/cli.js
CHANGED
|
@@ -7,9 +7,10 @@ import { resolve } from 'node:path';
|
|
|
7
7
|
import { ensureMirrorAgentsInstructions, installMirrorSkill, runMirrorAgentAutomation } from './agents.js';
|
|
8
8
|
import { MirrorError } from './errors.js';
|
|
9
9
|
import { readCurrentVersion, resolveProjectName } from './adapters.js';
|
|
10
|
-
import { configPathForDisplay, discoverMirrorConfig, loadMirrorConfig, relativeFromCwd,
|
|
10
|
+
import { configPathForDisplay, discoverMirrorConfig, loadMirrorConfig, relativeFromCwd, writeInitConfigFromAnswers } from './config.js';
|
|
11
11
|
import { executeVersionPlan } from './executor.js';
|
|
12
12
|
import { parseMirrorCliOptions } from './flags.js';
|
|
13
|
+
import { createReadlineInitPrompter, isInteractiveInit, resolveInitAnswers } from './init.js';
|
|
13
14
|
import { buildVersionPlan, validateMirrorConfig } from './plan.js';
|
|
14
15
|
import { mirrorBanner, reportAgentsInstructions, reportConfig, reportConfigSchema, reportExecution, reportExecutionSummary, reportPlan, reportSkillInstall, reportValue, } from './reporter.js';
|
|
15
16
|
import { resolveNextVersion } from './version.js';
|
|
@@ -61,6 +62,9 @@ export const runMirrorCli = async (rawArgs = process.argv.slice(2)) => {
|
|
|
61
62
|
try {
|
|
62
63
|
if (effectiveArgs.includes('--no-color'))
|
|
63
64
|
process.env['NO_COLOR'] = '1';
|
|
65
|
+
if (rawArgs.length === 0) {
|
|
66
|
+
await prepareAgents({});
|
|
67
|
+
}
|
|
64
68
|
if (effectiveArgs.includes('--help')) {
|
|
65
69
|
const parsed = parseMirrorCliOptions(effectiveArgs);
|
|
66
70
|
const cwd = resolve(parsed.cwd ?? process.cwd());
|
|
@@ -140,23 +144,50 @@ const handleCliError = (error, verbose, exitCode) => {
|
|
|
140
144
|
process.exit(exitCode ?? 1);
|
|
141
145
|
};
|
|
142
146
|
const createInitCommand = () => defineCommand({
|
|
143
|
-
meta: { name: 'init', description: 'Create a Mirror configuration file.' },
|
|
144
|
-
subCommands: {
|
|
145
|
-
'package.json': createInitKindCommand('package.json'),
|
|
146
|
-
'jsr.json': createInitKindCommand('jsr.json'),
|
|
147
|
-
git: createInitKindCommand('git'),
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
const createInitKindCommand = (kind) => defineCommand({
|
|
151
|
-
meta: { name: kind, description: `Create ${kind} project configuration.` },
|
|
147
|
+
meta: { name: 'init', description: 'Create or update a Mirror configuration file.' },
|
|
152
148
|
args: {
|
|
153
149
|
...globalArgs,
|
|
154
|
-
|
|
150
|
+
source: { type: 'positional', required: false, description: 'Version source: package.json, jsr.json, or git' },
|
|
151
|
+
output: { type: 'string', description: 'Version outputs. Repeat or comma-separate package.json, jsr.json, git.' },
|
|
152
|
+
'package-file': { type: 'string', description: 'Path to package.json' },
|
|
153
|
+
'jsr-file': { type: 'string', description: 'Path to jsr.json' },
|
|
154
|
+
auxiliary: { type: 'string', description: 'Auxiliary package.json paths. Repeat or comma-separate values.' },
|
|
155
|
+
'tag-template': { type: 'string', description: 'Git tag template' },
|
|
156
|
+
name: { type: 'string', description: 'Explicit project name' },
|
|
157
|
+
preid: { type: 'string', description: 'Default prerelease identifier' },
|
|
158
|
+
commit: { type: 'boolean', description: 'Create release commits' },
|
|
159
|
+
push: { type: 'boolean', description: 'Push release refs' },
|
|
160
|
+
'non-interactive': { type: 'boolean', description: 'Skip interactive prompts and use flags + defaults' },
|
|
161
|
+
yes: { type: 'boolean', description: 'Overwrite an existing mirror.config.toml with generated defaults' },
|
|
155
162
|
},
|
|
156
163
|
async run(context) {
|
|
157
164
|
const options = cliOptions(context.rawArgs, context.args);
|
|
158
|
-
const
|
|
159
|
-
|
|
165
|
+
const cwd = resolve(options.cwd ?? process.cwd());
|
|
166
|
+
const positionalSource = adapterArg(context.args['source']);
|
|
167
|
+
const commitProvided = context.rawArgs.includes('--commit');
|
|
168
|
+
const pushProvided = context.rawArgs.includes('--push');
|
|
169
|
+
const flags = {
|
|
170
|
+
source: options.source ?? positionalSource,
|
|
171
|
+
output: options.output,
|
|
172
|
+
packagePath: options.packageFile,
|
|
173
|
+
auxiliaryPaths: options.auxiliary,
|
|
174
|
+
jsrPath: options.jsrFile,
|
|
175
|
+
tagTemplate: options.tagTemplate,
|
|
176
|
+
name: options.name,
|
|
177
|
+
prereleaseId: options.preid,
|
|
178
|
+
commit: commitProvided ? options.commit : undefined,
|
|
179
|
+
push: pushProvided ? options.push : undefined,
|
|
180
|
+
};
|
|
181
|
+
const interactive = isInteractiveInit(options);
|
|
182
|
+
const prompter = interactive ? createReadlineInitPrompter() : undefined;
|
|
183
|
+
try {
|
|
184
|
+
const answers = await resolveInitAnswers(flags, cwd, prompter);
|
|
185
|
+
const path = await writeInitConfigFromAnswers(answers, cwd, Boolean(options.yes));
|
|
186
|
+
process.stdout.write(reportValue(`created ${path}`, options.format));
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
await prompter?.close();
|
|
190
|
+
}
|
|
160
191
|
},
|
|
161
192
|
});
|
|
162
193
|
const createConfigCommand = () => defineCommand({
|
|
@@ -292,16 +323,26 @@ const cliOptions = (rawArgs, args) => {
|
|
|
292
323
|
output: parsed.output ?? outputArg(args['output']),
|
|
293
324
|
packageFile: parsed.packageFile ?? stringArg(args['packageFile']),
|
|
294
325
|
jsrFile: parsed.jsrFile ?? stringArg(args['jsrFile']),
|
|
326
|
+
auxiliary: parsed.auxiliary ?? outputListArg(args['auxiliary']),
|
|
327
|
+
tagTemplate: parsed.tagTemplate ?? stringArg(args['tagTemplate']),
|
|
328
|
+
name: parsed.name ?? stringArg(args['name']),
|
|
295
329
|
preid: parsed.preid ?? stringArg(args['preid']),
|
|
296
330
|
dryRun: parsed.dryRun || args['dryRun'] === true,
|
|
297
331
|
commit: parsed.commit || args['commit'] === true,
|
|
298
332
|
push: parsed.push || args['push'] === true,
|
|
299
333
|
allowDirty: parsed.allowDirty || args['allowDirty'] === true,
|
|
334
|
+
nonInteractive: parsed.nonInteractive || args['nonInteractive'] === true,
|
|
300
335
|
yes: parsed.yes || args['yes'] === true,
|
|
301
336
|
verbose: parsed.verbose || args['verbose'] === true,
|
|
302
337
|
};
|
|
303
338
|
};
|
|
304
339
|
const stringArg = (value) => (typeof value === 'string' ? value : undefined);
|
|
340
|
+
const outputListArg = (value) => {
|
|
341
|
+
if (typeof value !== 'string')
|
|
342
|
+
return undefined;
|
|
343
|
+
const values = value.split(',').map((item) => item.trim()).filter(Boolean);
|
|
344
|
+
return values.length > 0 ? values : undefined;
|
|
345
|
+
};
|
|
305
346
|
const adapterArg = (value) => {
|
|
306
347
|
if (value === 'package.json' || value === 'jsr.json' || value === 'git')
|
|
307
348
|
return value;
|
package/library/config.d.ts
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
3
|
*/
|
|
4
|
-
import type { MirrorAdapterName, MirrorCliOptions, MirrorConfig, MirrorConfigDiscovery, MirrorRawConfig } from './types.js';
|
|
4
|
+
import type { MirrorAdapterName, MirrorCliOptions, MirrorConfig, MirrorConfigDiscovery, MirrorInitAnswers, MirrorRawConfig } from './types.js';
|
|
5
5
|
export declare const resolveMirrorPath: (cwd: string, path: string) => string;
|
|
6
6
|
export declare const relativeFromCwd: (cwd: string, path: string) => string;
|
|
7
7
|
export declare const discoverMirrorConfig: (cwd: string, explicitPath?: string) => Promise<MirrorConfigDiscovery>;
|
|
8
8
|
export declare const readConfigFile: (path: string) => Promise<MirrorRawConfig>;
|
|
9
9
|
export declare const loadMirrorConfig: (options?: MirrorCliOptions) => Promise<MirrorConfig>;
|
|
10
10
|
export declare const normalizeMirrorConfig: (raw: MirrorRawConfig, cwd: string, configPath: string | undefined, options?: MirrorCliOptions) => MirrorConfig;
|
|
11
|
+
export declare const defaultInitAnswersForSource: (kind: MirrorAdapterName, cwd: string) => MirrorInitAnswers;
|
|
12
|
+
export declare const generateInitConfig: (answers: MirrorInitAnswers, cwd: string) => string;
|
|
11
13
|
export declare const createInitConfig: (kind: MirrorAdapterName, cwd: string) => string;
|
|
12
14
|
export declare const writeInitConfig: (kind: MirrorAdapterName, cwd: string, overwrite?: boolean) => Promise<string>;
|
|
15
|
+
export declare const writeInitConfigFromAnswers: (answers: MirrorInitAnswers, cwd: string, overwrite?: boolean) => Promise<string>;
|
|
16
|
+
export declare const reconcileInitConfig: (existingContent: string, defaultsContent: string) => string;
|
|
13
17
|
export declare const configPathForDisplay: (config: MirrorConfig) => string;
|
|
14
18
|
//# sourceMappingURL=config.d.ts.map
|
package/library/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../source/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../source/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,EAEjB,eAAe,EAChB,MAAM,YAAY,CAAA;AAOnB,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,EAAE,MAAM,MAAM,WAAmD,CAAA;AAE9G,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,EAAE,MAAM,MAAM,WAGxD,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAU,KAAK,MAAM,EAAE,eAAe,MAAM,KAAG,OAAO,CAAC,qBAAqB,CAa5G,CAAA;AAED,eAAO,MAAM,cAAc,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,eAAe,CAe1E,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAU,UAAS,gBAAqB,KAAG,OAAO,CAAC,YAAY,CAO3F,CAAA;AAED,eAAO,MAAM,qBAAqB,GAChC,KAAK,eAAe,EACpB,KAAK,MAAM,EACX,YAAY,MAAM,GAAG,SAAS,EAC9B,UAAS,gBAAqB,KAC7B,YAyDF,CAAA;AAED,eAAO,MAAM,2BAA2B,GAAI,MAAM,iBAAiB,EAAE,KAAK,MAAM,KAAG,iBAWjF,CAAA;AAEF,eAAO,MAAM,kBAAkB,GAAI,SAAS,iBAAiB,EAAE,KAAK,MAAM,WAsCzE,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,MAAM,iBAAiB,EAAE,KAAK,MAAM,WAAoE,CAAA;AAEzI,eAAO,MAAM,eAAe,GAAU,MAAM,iBAAiB,EAAE,KAAK,MAAM,EAAE,mBAAiB,oBACT,CAAA;AAEpF,eAAO,MAAM,0BAA0B,GAAU,SAAS,iBAAiB,EAAE,KAAK,MAAM,EAAE,mBAAiB,oBAW1G,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,iBAAiB,MAAM,EAAE,iBAAiB,MAAM,WAyBnF,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAI,QAAQ,YAAY,WAAoF,CAAA"}
|
package/library/config.js
CHANGED
|
@@ -6,6 +6,7 @@ import { readFile, writeFile } from 'node:fs/promises';
|
|
|
6
6
|
import { basename, isAbsolute, join, relative, resolve } from 'node:path';
|
|
7
7
|
import { parse as parseToml } from 'smol-toml';
|
|
8
8
|
import { MirrorError } from './errors.js';
|
|
9
|
+
import { mirrorConfigSchemaReference } from './schema.js';
|
|
9
10
|
const adapters = new Set(['package.json', 'jsr.json', 'git']);
|
|
10
11
|
const projectNameSources = new Set(['package.json', 'jsr.json']);
|
|
11
12
|
export const resolveMirrorPath = (cwd, path) => (isAbsolute(path) ? path : resolve(cwd, path));
|
|
@@ -62,6 +63,7 @@ export const normalizeMirrorConfig = (raw, cwd, configPath, options = {}) => {
|
|
|
62
63
|
const projectName = optionalString(raw.project?.name, 'project.name');
|
|
63
64
|
const prereleaseId = options.preid ?? optionalString(raw.version?.prerelease_id, 'version.prerelease_id') ?? '';
|
|
64
65
|
const packagePath = options.packageFile ?? optionalString(raw.package?.path, 'package.path') ?? 'package.json';
|
|
66
|
+
const packageAuxiliaryPaths = assertStringArray(raw.package?.auxiliary_paths, 'package.auxiliary_paths');
|
|
65
67
|
const jsrPath = options.jsrFile ?? optionalString(raw.jsr?.path, 'jsr.path') ?? 'jsr.json';
|
|
66
68
|
const tagTemplate = optionalString(raw.git?.tag_template, 'git.tag_template') ?? 'v{version}';
|
|
67
69
|
const gitCommit = optionalBoolean(raw.git?.commit, 'git.commit') === true;
|
|
@@ -87,6 +89,7 @@ export const normalizeMirrorConfig = (raw, cwd, configPath, options = {}) => {
|
|
|
87
89
|
},
|
|
88
90
|
package: {
|
|
89
91
|
path: packagePath,
|
|
92
|
+
auxiliaryPaths: packageAuxiliaryPaths,
|
|
90
93
|
},
|
|
91
94
|
jsr: {
|
|
92
95
|
path: jsrPath,
|
|
@@ -105,98 +108,90 @@ export const normalizeMirrorConfig = (raw, cwd, configPath, options = {}) => {
|
|
|
105
108
|
},
|
|
106
109
|
};
|
|
107
110
|
};
|
|
108
|
-
export const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
[
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
[
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
[
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
[
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
write_changelog = true
|
|
164
|
-
changelog_path = "CHANGELOG.md"
|
|
165
|
-
auto_agents_md = true
|
|
166
|
-
auto_skill_install = true
|
|
167
|
-
`;
|
|
168
|
-
}
|
|
169
|
-
return `schema = 1
|
|
170
|
-
|
|
171
|
-
[project]
|
|
172
|
-
name = "${projectName}"
|
|
173
|
-
|
|
174
|
-
[version]
|
|
175
|
-
scheme = "semver"
|
|
176
|
-
source = "git"
|
|
177
|
-
output = ["git"]
|
|
178
|
-
prerelease_id = ""
|
|
179
|
-
|
|
180
|
-
[git]
|
|
181
|
-
tag_template = "v{version}"
|
|
182
|
-
commit = false
|
|
183
|
-
push = false
|
|
184
|
-
allow_dirty = false
|
|
185
|
-
|
|
186
|
-
[agents]
|
|
187
|
-
write_changelog = true
|
|
188
|
-
changelog_path = "CHANGELOG.md"
|
|
189
|
-
auto_agents_md = true
|
|
190
|
-
auto_skill_install = true
|
|
191
|
-
`;
|
|
192
|
-
};
|
|
193
|
-
export const writeInitConfig = async (kind, cwd, overwrite = false) => {
|
|
111
|
+
export const defaultInitAnswersForSource = (kind, cwd) => ({
|
|
112
|
+
source: kind,
|
|
113
|
+
output: kind === 'git' ? ['git'] : [kind, 'git'],
|
|
114
|
+
packagePath: 'package.json',
|
|
115
|
+
auxiliaryPaths: [],
|
|
116
|
+
jsrPath: 'jsr.json',
|
|
117
|
+
name: kind === 'git' ? basename(cwd) : undefined,
|
|
118
|
+
prereleaseId: '',
|
|
119
|
+
tagTemplate: '{name}@{version}',
|
|
120
|
+
commit: kind !== 'git',
|
|
121
|
+
push: false,
|
|
122
|
+
});
|
|
123
|
+
export const generateInitConfig = (answers, cwd) => {
|
|
124
|
+
const lines = [];
|
|
125
|
+
lines.push(`#:schema ${mirrorConfigSchemaReference}`);
|
|
126
|
+
lines.push('');
|
|
127
|
+
lines.push('schema = 1');
|
|
128
|
+
lines.push('');
|
|
129
|
+
lines.push('[project]');
|
|
130
|
+
if (answers.source === 'package.json')
|
|
131
|
+
lines.push('name_source = "package.json"');
|
|
132
|
+
else if (answers.source === 'jsr.json')
|
|
133
|
+
lines.push('name_source = "jsr.json"');
|
|
134
|
+
else
|
|
135
|
+
lines.push(`name = "${answers.name ?? basename(cwd)}"`);
|
|
136
|
+
lines.push('');
|
|
137
|
+
lines.push('[version]');
|
|
138
|
+
lines.push('scheme = "semver"');
|
|
139
|
+
lines.push(`source = "${answers.source}"`);
|
|
140
|
+
lines.push(`output = [${answers.output.map((value) => `"${value}"`).join(', ')}]`);
|
|
141
|
+
lines.push(`prerelease_id = "${answers.prereleaseId}"`);
|
|
142
|
+
lines.push('');
|
|
143
|
+
lines.push('[package]');
|
|
144
|
+
lines.push(`path = "${answers.packagePath}"`);
|
|
145
|
+
lines.push(`auxiliary_paths = [${answers.auxiliaryPaths.map((value) => `"${value}"`).join(', ')}]`);
|
|
146
|
+
lines.push('');
|
|
147
|
+
lines.push('[jsr]');
|
|
148
|
+
lines.push(`path = "${answers.jsrPath}"`);
|
|
149
|
+
lines.push('');
|
|
150
|
+
lines.push('[git]');
|
|
151
|
+
lines.push(`tag_template = "${answers.tagTemplate}"`);
|
|
152
|
+
lines.push(`commit = ${String(answers.commit)}`);
|
|
153
|
+
lines.push(`push = ${String(answers.push)}`);
|
|
154
|
+
lines.push('allow_dirty = false');
|
|
155
|
+
lines.push('');
|
|
156
|
+
lines.push('[agents]');
|
|
157
|
+
lines.push('write_changelog = true');
|
|
158
|
+
lines.push('changelog_path = "CHANGELOG.md"');
|
|
159
|
+
lines.push('auto_agents_md = true');
|
|
160
|
+
lines.push('auto_skill_install = true');
|
|
161
|
+
return `${lines.join('\n')}\n`;
|
|
162
|
+
};
|
|
163
|
+
export const createInitConfig = (kind, cwd) => generateInitConfig(defaultInitAnswersForSource(kind, cwd), cwd);
|
|
164
|
+
export const writeInitConfig = async (kind, cwd, overwrite = false) => writeInitConfigFromAnswers(defaultInitAnswersForSource(kind, cwd), cwd, overwrite);
|
|
165
|
+
export const writeInitConfigFromAnswers = async (answers, cwd, overwrite = false) => {
|
|
194
166
|
const path = join(cwd, 'mirror.config.toml');
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
167
|
+
const generated = generateInitConfig(answers, cwd);
|
|
168
|
+
if (existsSync(path) && !overwrite) {
|
|
169
|
+
await writeFile(path, reconcileInitConfig(await readFile(path, 'utf8'), generated), 'utf8');
|
|
170
|
+
return path;
|
|
171
|
+
}
|
|
172
|
+
await writeFile(path, generated, 'utf8');
|
|
198
173
|
return path;
|
|
199
174
|
};
|
|
175
|
+
export const reconcileInitConfig = (existingContent, defaultsContent) => {
|
|
176
|
+
const existingRaw = parseConfigContent(existingContent, 'existing configuration');
|
|
177
|
+
const defaultsRaw = parseConfigContent(defaultsContent, 'default configuration');
|
|
178
|
+
const additions = [];
|
|
179
|
+
for (const [sectionName, defaultSection] of Object.entries(defaultsRaw)) {
|
|
180
|
+
if (!isRecord(defaultSection))
|
|
181
|
+
continue;
|
|
182
|
+
const existingSection = existingRaw[sectionName];
|
|
183
|
+
if (!isRecord(existingSection)) {
|
|
184
|
+
additions.push(renderTomlSection(sectionName, defaultSection));
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const missingValues = Object.fromEntries(Object.entries(defaultSection).filter(([key]) => existingSection[key] === undefined));
|
|
188
|
+
if (Object.keys(missingValues).length > 0)
|
|
189
|
+
existingContent = insertTomlValuesIntoSection(existingContent, sectionName, missingValues);
|
|
190
|
+
}
|
|
191
|
+
if (additions.length === 0)
|
|
192
|
+
return existingContent;
|
|
193
|
+
return `${existingContent.trimEnd()}\n\n${additions.join('\n\n')}\n`;
|
|
194
|
+
};
|
|
200
195
|
export const configPathForDisplay = (config) => (config.configPath ? relativeFromCwd(config.cwd, config.configPath) : '(none)');
|
|
201
196
|
const assertAdapter = (value, key) => {
|
|
202
197
|
if (typeof value !== 'string' || !adapters.has(value))
|
|
@@ -213,6 +208,17 @@ const assertOutput = (value) => {
|
|
|
213
208
|
throw new MirrorError('Invalid or missing version.output. Expected at least one output adapter.');
|
|
214
209
|
return value.map((item) => assertAdapter(item, 'version.output'));
|
|
215
210
|
};
|
|
211
|
+
const assertStringArray = (value, key) => {
|
|
212
|
+
if (value === undefined)
|
|
213
|
+
return [];
|
|
214
|
+
if (!Array.isArray(value))
|
|
215
|
+
throw new MirrorError(`Invalid ${key}. Expected an array of strings.`);
|
|
216
|
+
return value.map((item) => {
|
|
217
|
+
if (typeof item !== 'string' || item.length === 0)
|
|
218
|
+
throw new MirrorError(`Invalid ${key}. Expected an array of strings.`);
|
|
219
|
+
return item;
|
|
220
|
+
});
|
|
221
|
+
};
|
|
216
222
|
const dedupeAdapters = (value) => [...new Set(value)];
|
|
217
223
|
const optionalString = (value, key) => {
|
|
218
224
|
if (value === undefined)
|
|
@@ -229,3 +235,43 @@ const optionalBoolean = (value, key) => {
|
|
|
229
235
|
return value;
|
|
230
236
|
};
|
|
231
237
|
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
238
|
+
const parseConfigContent = (content, label) => {
|
|
239
|
+
let parsed;
|
|
240
|
+
try {
|
|
241
|
+
parsed = parseToml(content);
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
245
|
+
throw new MirrorError(`Invalid TOML in ${label}:\n${message}`);
|
|
246
|
+
}
|
|
247
|
+
if (!isRecord(parsed))
|
|
248
|
+
throw new MirrorError(`Invalid ${label}. Expected a TOML object.`);
|
|
249
|
+
return parsed;
|
|
250
|
+
};
|
|
251
|
+
const renderTomlSection = (sectionName, values) => {
|
|
252
|
+
const lines = [`[${sectionName}]`];
|
|
253
|
+
for (const [key, value] of Object.entries(values)) {
|
|
254
|
+
lines.push(`${key} = ${renderTomlValue(value)}`);
|
|
255
|
+
}
|
|
256
|
+
return lines.join('\n');
|
|
257
|
+
};
|
|
258
|
+
const insertTomlValuesIntoSection = (content, sectionName, values) => {
|
|
259
|
+
const lines = content.split(/\r?\n/);
|
|
260
|
+
const sectionIndex = lines.findIndex((line) => line.trim() === `[${sectionName}]`);
|
|
261
|
+
if (sectionIndex === -1)
|
|
262
|
+
return `${content.trimEnd()}\n\n${renderTomlSection(sectionName, values)}\n`;
|
|
263
|
+
const nextSectionIndex = lines.findIndex((line, index) => index > sectionIndex && /^\[[^\]]+]\s*$/.test(line.trim()));
|
|
264
|
+
const insertIndex = nextSectionIndex === -1 ? lines.length : nextSectionIndex;
|
|
265
|
+
const renderedValues = Object.entries(values).map(([key, value]) => `${key} = ${renderTomlValue(value)}`);
|
|
266
|
+
lines.splice(insertIndex, 0, ...renderedValues);
|
|
267
|
+
return lines.join('\n');
|
|
268
|
+
};
|
|
269
|
+
const renderTomlValue = (value) => {
|
|
270
|
+
if (typeof value === 'string')
|
|
271
|
+
return JSON.stringify(value);
|
|
272
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
273
|
+
return String(value);
|
|
274
|
+
if (Array.isArray(value))
|
|
275
|
+
return `[${value.map(renderTomlValue).join(', ')}]`;
|
|
276
|
+
throw new MirrorError('Cannot render unsupported init configuration value.');
|
|
277
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../source/executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../source/executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAKzE,eAAO,MAAM,gBAAgB,GAAU,QAAQ,MAAM,EAAE,UAAS,gBAAqB,KAAG,OAAO,CAAC,qBAAqB,CAIpH,CAAA;AAED,eAAO,MAAM,kBAAkB,GAC7B,MAAM,qBAAqB,CAAC,MAAM,CAAC,EACnC,UAAS,gBAAqB,KAC7B,OAAO,CAAC,qBAAqB,CAgB/B,CAAA"}
|