@guiho/mirror 3.2.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ 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.1] - 2026-06-09
9
+
10
+ ### Added
11
+
12
+ - Added lifecycle hooks with before/after hook points around planning, applying, writing, committing, tagging, pushing, and the full execution flow.
13
+
14
+ ### Changed
15
+
16
+ - Wrapped the generated Mirror `AGENTS.md` guidance in `BEGIN/END GUIHO MIRROR` markers that tell agents not to edit the Mirror-managed block.
17
+ - Made Mirror AGENTS guidance detection whitespace-insensitive so markdown formatting that only adds or removes blank lines does not duplicate the section.
18
+ - Updated hook tests to use the active Bun runtime instead of requiring a separate `node` binary on `PATH`.
19
+
8
20
  ## [3.2.0] - 2026-06-07
9
21
 
10
22
  ### Added
package/DOCS.md CHANGED
@@ -204,7 +204,7 @@ mirror agents instructions
204
204
 
205
205
  - `install local`: Writes `.agents/skills/guiho-as-mirror/SKILL.md` in the project.
206
206
  - `install global`: Writes `~/.agents/skills/guiho-as-mirror/SKILL.md`.
207
- - `instructions`: Creates or updates `AGENTS.md` with the GUIHO Mirror semantic versioning section.
207
+ - `instructions`: Creates or updates `AGENTS.md` with the protected GUIHO Mirror semantic versioning section.
208
208
 
209
209
  Global skill installation uses the user home directory. Tests and automation can override that home root with `MIRROR_AGENT_HOME`.
210
210
 
@@ -340,7 +340,7 @@ Automation is controlled by `[agents]`.
340
340
  - Disable changelog edits by agents with `write_changelog = false`.
341
341
  - Direct agents to the correct changelog with `changelog_path = "path/to/CHANGELOG.md"`.
342
342
 
343
- The generated AGENTS section instructs agents to invoke `guiho-as-mirror` for versioning work, inspect `mirror.config.toml`, respect `write_changelog`, and use `changelog_path` for changelog edits. Use `mirror agents install local` only when a project-local skill copy is desired explicitly.
343
+ The generated AGENTS section is wrapped in `<!-- BEGIN GUIHO MIRROR - DO NOT EDIT THIS SECTION -->` and `<!-- END GUIHO MIRROR -->` markers so agents know the block is Mirror-managed. It instructs agents to invoke `guiho-as-mirror` for versioning work, inspect `mirror.config.toml`, respect `write_changelog`, and use `changelog_path` for changelog edits. Mirror detects the existing block with whitespace-insensitive matching so markdown formatting that only adds or removes blank lines does not duplicate the section. Use `mirror agents install local` only when a project-local skill copy is desired explicitly.
344
344
 
345
345
  ## Release Safety Rules
346
346
 
@@ -355,6 +355,110 @@ Mirror intentionally separates planning from mutation.
355
355
 
356
356
  `mirror version apply` refuses to mutate unless `--yes` is passed, unless `--dry-run` is used.
357
357
 
358
+ ## Lifecycle Hooks
359
+
360
+ Mirror supports lifecycle hooks that run shell commands at defined points during `mirror version apply`. Hooks are configured in the `[hooks]` section of `mirror.config.toml`.
361
+
362
+ ### Lifecycle Tree
363
+
364
+ ```
365
+ before:everything # Runs once, before anything else
366
+
367
+ ├─ before:plan # Runs before buildVersionPlan()
368
+ │ buildVersionPlan() # Plan construction (read-only)
369
+ │ after:plan # Runs after plan is built
370
+
371
+ ├─ before:apply # Runs before executeVersionPlan()
372
+ │ │
373
+ │ ├─ before:write # Runs before each file-write batch
374
+ │ │ write-file(s) # Mutate package.json / jsr.json
375
+ │ │ after:write # Runs after all file writes
376
+ │ │
377
+ │ ├─ before:commit # Runs before git commit
378
+ │ │ git-commit # git add + git commit
379
+ │ │ after:commit # Runs after git commit
380
+ │ │
381
+ │ ├─ before:tag # Runs before git tag
382
+ │ │ git-tag # git tag -m "..."
383
+ │ │ after:tag # Runs after git tag
384
+ │ │
385
+ │ ├─ before:push # Runs before git push
386
+ │ │ git-push # git push + git push --tags
387
+ │ │ after:push # Runs after git push
388
+ │ │
389
+ │ after:apply # Runs after executeVersionPlan() completes (always runs)
390
+
391
+ after:everything # Runs once, after everything else (always runs)
392
+ ```
393
+
394
+ ### Hook Configuration
395
+
396
+ ```toml
397
+ [hooks]
398
+ before_everything = "npm run typecheck"
399
+ after_everything = "echo 'Release complete!'"
400
+
401
+ before_plan = ["npm run lint", "npm run typecheck"]
402
+ after_plan = "echo 'Plan is ready'"
403
+
404
+ before_apply = "npm run build"
405
+ after_apply = "node scripts/notify-release.js"
406
+
407
+ before_write = "echo 'Writing version files...'"
408
+ after_write = "echo 'Files written'"
409
+
410
+ before_commit = ["npm run format", "echo 'Committing...'"]
411
+ after_commit = "echo 'Committed'"
412
+
413
+ before_tag = "echo 'Tagging release...'"
414
+ after_tag = "echo 'Tagged'"
415
+
416
+ before_push = "echo 'Pushing...'"
417
+ after_push = "echo 'Pushed'"
418
+ ```
419
+
420
+ - Each hook key maps to a string (single command) or array of strings (multiple commands run sequentially).
421
+ - Hook names use underscores (`before_everything`) in TOML, which normalizes to colon form (`before:everything`) internally.
422
+ - Hook commands run in the project root directory through the default platform shell.
423
+ - Action-level hooks (`before:write`, `before:commit`, `before:tag`, `before:push` and their `after:` variants) fire only when the corresponding action is part of the plan.
424
+ - Hooks are skipped during `--dry-run`.
425
+
426
+ ### Hook Error Handling
427
+
428
+ - When a hook exits with a non-zero code, Mirror stops the pipeline and reports the failure.
429
+ - `after:apply` and `after:everything` always run, even when a prior hook or action failed. This ensures cleanup and notification hooks fire reliably.
430
+
431
+ ### Hook Environment Variables
432
+
433
+ Every hook receives `MIRROR_*` environment variables with release context:
434
+
435
+ | Variable | Scope | Description |
436
+ |------------------------|--------------|-------------------------------------------------------|
437
+ | `MIRROR_CWD` | Always | Project root directory |
438
+ | `MIRROR_CONFIG_PATH` | Always | Path to resolved `mirror.config.toml` |
439
+ | `MIRROR_SOURCE` | Always | Version source adapter |
440
+ | `MIRROR_OUTPUT` | Always | Comma-separated output adapters |
441
+ | `MIRROR_TARGET` | Always | The release target argument |
442
+ | `MIRROR_CURRENT` | Plan+ | Current version string |
443
+ | `MIRROR_NEXT` | Plan+ | Next version string |
444
+ | `MIRROR_PROJECT_NAME` | Plan+ | Resolved project name |
445
+ | `MIRROR_GIT_TAG` | Plan+ | Rendered git tag (if git output) |
446
+ | `MIRROR_FILE_PATHS` | Plan+ | Comma-separated file output paths |
447
+ | `MIRROR_COMMIT_ENABLED`| Plan+ | `true`/`false` |
448
+ | `MIRROR_PUSH_ENABLED` | Plan+ | `true`/`false` |
449
+ | `MIRROR_FILE_PATH` | Write | Path being written to |
450
+ | `MIRROR_FILE_CURRENT` | Write | Current version in the file |
451
+ | `MIRROR_FILE_NEXT` | Write | Next version being written |
452
+ | `MIRROR_COMMIT_MSG` | Commit | Commit message |
453
+ | `MIRROR_COMMIT_PATHS` | Commit | Space-separated paths being committed |
454
+ | `MIRROR_TAG` | Tag | Git tag being created |
455
+ | `MIRROR_INCLUDE_COMMIT`| Push | `true`/`false` |
456
+ | `MIRROR_INCLUDE_TAGS` | Push | `true`/`false` |
457
+ | `MIRROR_APPLIED` | Results | `true`/`false` (whether execution actually applied) |
458
+ | `MIRROR_DRY_RUN` | Results | `true`/`false` |
459
+
460
+ "Plan+" means the variable is available starting from `before:plan` and all later hooks. "Write", "Commit", "Tag", and "Push" mean the variable is available at the corresponding action-level hooks. "Results" means `after:apply` and `after:everything`.
461
+
358
462
  ## Recommended Agent Release Workflow
359
463
 
360
464
  When an AI coding agent prepares a Mirror-managed release, it should follow this sequence.
@@ -434,6 +538,7 @@ The API uses the same configuration discovery and safety rules as the CLI.
434
538
  - `source/adapters.ts`: package, JSR, and Git read/write primitives.
435
539
  - `source/plan.ts`: validation and read-only release plan construction.
436
540
  - `source/executor.ts`: mutation layer for file writes, Git commits, tags, and pushes.
541
+ - `source/hooks.ts`: lifecycle hook configuration, execution, and environment variable construction.
437
542
  - `source/reporter.ts`: text and JSON report formatting.
438
543
  - `source/agents.ts`: agent skill installation and AGENTS.md guidance automation.
439
544
  - `source/errors.ts`: user-facing errors with stable exit codes.
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guiho/mirror",
3
- "version": "3.2.0",
3
+ "version": "3.2.1",
4
4
  "exports": "./source/guiho-mirror.ts",
5
5
  "publish": {
6
6
  "include": [
@@ -3,9 +3,11 @@
3
3
  */
4
4
  import type { MirrorAgentAutomationResult, MirrorAgentSettings, MirrorAgentsInstructionsResult, MirrorCliOptions, MirrorSkillInstallResult, MirrorSkillInstallScope } from './types.js';
5
5
  export declare const mirrorSkillName = "guiho-as-mirror";
6
+ export declare const mirrorAgentsSectionStartMarker = "<!-- BEGIN GUIHO MIRROR - DO NOT EDIT THIS SECTION -->";
7
+ export declare const mirrorAgentsSectionEndMarker = "<!-- END GUIHO MIRROR -->";
6
8
  export declare const mirrorAgentsSectionHeading = "## Semantic Project Versioning -- GUIHO Mirror";
7
9
  export declare const defaultMirrorAgentSettings: MirrorAgentSettings;
8
- export declare const mirrorAgentsSection = "## Semantic Project Versioning -- GUIHO Mirror\n\nInvoke the guiho-as-mirror agent skill every time the user wants to bump, tag, release, plan, initialize, configure, or troubleshoot semantic project versioning with GUIHO Mirror.\n\nBefore editing release docs or changelogs, inspect mirror.config.toml. If [agents].write_changelog is false, skip changelog edits. If it is missing or true, changelog edits are allowed when the project has a changelog.\n\nUse [agents].changelog_path as the changelog file path. If it is missing, use CHANGELOG.md in the project root.\n";
10
+ export declare const mirrorAgentsSection: string;
9
11
  type MirrorSkillPathOptions = {
10
12
  cwd?: string;
11
13
  homeDirectory?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../source/agents.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EACV,2BAA2B,EAC3B,mBAAmB,EACnB,8BAA8B,EAC9B,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,YAAY,CAAA;AAInB,eAAO,MAAM,eAAe,oBAAoB,CAAA;AAChD,eAAO,MAAM,0BAA0B,mDAAmD,CAAA;AAE1F,eAAO,MAAM,0BAA0B,EAAE,mBAKxC,CAAA;AAED,eAAO,MAAM,mBAAmB,6jBAO/B,CAAA;AAED,KAAK,sBAAsB,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,KAAK,yBAAyB,GAAG,sBAAsB,GAAG;IACxD,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,KAAK,4BAA4B,GAAG,gBAAgB,GAAG;IACrD,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,OAAO,uBAAuB,EAAE,UAAS,sBAA2B,WAI1G,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,OAAO,uBAAuB,EAAE,UAAS,sBAA2B,YACvD,CAAA;AAEpD,eAAO,MAAM,kBAAkB,GAC7B,OAAO,uBAAuB,EAC9B,UAAS,yBAA8B,KACtC,OAAO,CAAC,wBAAwB,CAelC,CAAA;AAED,eAAO,MAAM,8BAA8B,GAAU,KAAK,MAAM,EAAE,gBAAc,KAAG,OAAO,CAAC,8BAA8B,CAkBxH,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,SAWrD,CAAA;AAED,eAAO,MAAM,0BAA0B,GAAU,UAAS,gBAAqB,KAAG,OAAO,CAAC,mBAAmB,CAa5G,CAAA;AAED,eAAO,MAAM,wBAAwB,GACnC,UAAS,4BAAiC,EAC1C,SAAQ,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,KAC3C,OAAO,CAAC,2BAA2B,CAkBrC,CAAA"}
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../source/agents.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EACV,2BAA2B,EAC3B,mBAAmB,EACnB,8BAA8B,EAC9B,gBAAgB,EAChB,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,YAAY,CAAA;AAInB,eAAO,MAAM,eAAe,oBAAoB,CAAA;AAChD,eAAO,MAAM,8BAA8B,2DAA2D,CAAA;AACtG,eAAO,MAAM,4BAA4B,8BAA8B,CAAA;AACvE,eAAO,MAAM,0BAA0B,mDAAmD,CAAA;AAE1F,eAAO,MAAM,0BAA0B,EAAE,mBAKxC,CAAA;AAWD,eAAO,MAAM,mBAAmB,QAEA,CAAA;AAEhC,KAAK,sBAAsB,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,KAAK,yBAAyB,GAAG,sBAAsB,GAAG;IACxD,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,KAAK,4BAA4B,GAAG,gBAAgB,GAAG;IACrD,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,OAAO,uBAAuB,EAAE,UAAS,sBAA2B,WAI1G,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,OAAO,uBAAuB,EAAE,UAAS,sBAA2B,YACvD,CAAA;AAEpD,eAAO,MAAM,kBAAkB,GAC7B,OAAO,uBAAuB,EAC9B,UAAS,yBAA8B,KACtC,OAAO,CAAC,wBAAwB,CAelC,CAAA;AAED,eAAO,MAAM,8BAA8B,GAAU,KAAK,MAAM,EAAE,gBAAc,KAAG,OAAO,CAAC,8BAA8B,CAkBxH,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,SAWrD,CAAA;AAED,eAAO,MAAM,0BAA0B,GAAU,UAAS,gBAAqB,KAAG,OAAO,CAAC,mBAAmB,CAa5G,CAAA;AAED,eAAO,MAAM,wBAAwB,GACnC,UAAS,4BAAiC,EAC1C,SAAQ,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,KAC3C,OAAO,CAAC,2BAA2B,CAkBrC,CAAA"}
package/library/agents.js CHANGED
@@ -8,6 +8,8 @@ import { dirname, resolve } from 'node:path';
8
8
  import { MirrorError } from './errors.js';
9
9
  import { discoverMirrorConfig, resolveMirrorPath } from './config.js';
10
10
  export const mirrorSkillName = 'guiho-as-mirror';
11
+ export const mirrorAgentsSectionStartMarker = '<!-- BEGIN GUIHO MIRROR - DO NOT EDIT THIS SECTION -->';
12
+ export const mirrorAgentsSectionEndMarker = '<!-- END GUIHO MIRROR -->';
11
13
  export const mirrorAgentsSectionHeading = '## Semantic Project Versioning -- GUIHO Mirror';
12
14
  export const defaultMirrorAgentSettings = {
13
15
  writeChangelog: true,
@@ -15,7 +17,7 @@ export const defaultMirrorAgentSettings = {
15
17
  autoAgentsMd: true,
16
18
  autoSkillInstall: true,
17
19
  };
18
- export const mirrorAgentsSection = `${mirrorAgentsSectionHeading}
20
+ const mirrorAgentsSectionBody = `${mirrorAgentsSectionHeading}
19
21
 
20
22
  Invoke the guiho-as-mirror agent skill every time the user wants to bump, tag, release, plan, initialize, configure, or troubleshoot semantic project versioning with GUIHO Mirror.
21
23
 
@@ -23,6 +25,9 @@ Before editing release docs or changelogs, inspect mirror.config.toml. If [agent
23
25
 
24
26
  Use [agents].changelog_path as the changelog file path. If it is missing, use CHANGELOG.md in the project root.
25
27
  `;
28
+ export const mirrorAgentsSection = `${mirrorAgentsSectionStartMarker}
29
+ ${mirrorAgentsSectionBody.trimEnd()}
30
+ ${mirrorAgentsSectionEndMarker}`;
26
31
  export const resolveMirrorSkillPath = (scope, options = {}) => {
27
32
  if (scope === 'local')
28
33
  return resolve(options.cwd ?? process.cwd(), '.agents', 'skills', mirrorSkillName, 'SKILL.md');
@@ -52,7 +57,7 @@ export const ensureMirrorAgentsInstructions = async (cwd, create = false) => {
52
57
  return { path, exists: true, changed: true };
53
58
  }
54
59
  const content = await readFile(path, 'utf8');
55
- if (content.includes(mirrorAgentsSectionHeading))
60
+ if (hasMirrorAgentsSection(content))
56
61
  return { path, exists: true, changed: false };
57
62
  const nextContent = `${content.trimEnd()}\n\n${mirrorAgentsSection}\n`;
58
63
  await writeFile(path, nextContent, 'utf8');
@@ -126,6 +131,13 @@ const optionalString = (value, key) => {
126
131
  throw new MirrorError(`Invalid ${key}. Expected a string.`);
127
132
  return value;
128
133
  };
134
+ const hasMirrorAgentsSection = (content) => {
135
+ const normalizedContent = normalizeMirrorAgentsSection(content);
136
+ return [mirrorAgentsSection, mirrorAgentsSectionBody].some((section) => {
137
+ return normalizedContent.includes(normalizeMirrorAgentsSection(section));
138
+ });
139
+ };
140
+ const normalizeMirrorAgentsSection = (content) => content.replace(/\s+/g, ' ').trim();
129
141
  const embeddedMirrorSkillContent = [
130
142
  '---',
131
143
  'name: guiho-as-mirror',
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../source/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AA6DH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;EAc5B,CAAA;AAEJ,eAAO,MAAM,YAAY,GAAU,kBAA+B,kBAwEjE,CAAA"}
package/library/cli.js CHANGED
@@ -14,6 +14,7 @@ import { createReadlineInitPrompter, isInteractiveInit, resolveInitAnswers } fro
14
14
  import { buildVersionPlan, validateMirrorConfig } from './plan.js';
15
15
  import { mirrorBanner, reportAgentsInstructions, reportConfig, reportConfigSchema, reportExecution, reportExecutionSummary, reportPlan, reportSkillInstall, reportValue, } from './reporter.js';
16
16
  import { resolveNextVersion } from './version.js';
17
+ import { runHooks, runHooksQuiet, hookEnvFromConfig, hookEnvForPlan, hookEnvForResult } from './hooks.js';
17
18
  const mirrorVersion = readInstalledVersion();
18
19
  const globalArgs = {
19
20
  config: { type: 'string', description: 'Path to mirror.config.toml' },
@@ -301,13 +302,41 @@ const createVersionCommand = () => defineCommand({
301
302
  async run(context) {
302
303
  const options = cliOptions(context.rawArgs, context.args);
303
304
  await prepareAgents(options);
304
- const plan = await buildVersionPlan(String(context.args['target']), options);
305
- if (options.format !== 'json')
306
- process.stdout.write(mirrorBanner(plan.configPath ? plan.configPath : ''));
307
- if (options.format !== 'json')
308
- process.stdout.write(reportPlan(plan, options.format));
309
- const result = await executeVersionPlan(plan, options);
310
- process.stdout.write(options.format === 'json' ? reportExecution(result, options.format) : reportExecutionSummary(result, options.format));
305
+ const target = String(context.args['target']);
306
+ const config = await loadMirrorConfig(options);
307
+ const hooks = config.hooks;
308
+ const hookResults = [];
309
+ const baseEnv = hookEnvFromConfig(config, target);
310
+ try {
311
+ await runHooks('before:everything', hooks['before:everything'], baseEnv, config.cwd);
312
+ }
313
+ catch (error) {
314
+ hookResults.push({ name: 'before:everything', commands: hooks['before:everything'] ?? [], status: 'failure', durationMs: 0, exitCode: error instanceof Error ? 1 : 1, stderr: error instanceof Error ? error.message : String(error) });
315
+ throw error;
316
+ }
317
+ try {
318
+ await runHooks('before:plan', hooks['before:plan'], baseEnv, config.cwd);
319
+ const plan = await buildVersionPlan(target, options);
320
+ const planEnv = hookEnvForPlan(plan, target);
321
+ await runHooks('after:plan', hooks['after:plan'], planEnv, config.cwd);
322
+ if (options.format !== 'json')
323
+ process.stdout.write(mirrorBanner(plan.configPath ? plan.configPath : ''));
324
+ if (options.format !== 'json')
325
+ process.stdout.write(reportPlan(plan, options.format));
326
+ await runHooks('before:apply', hooks['before:apply'], planEnv, config.cwd);
327
+ try {
328
+ const result = await executeVersionPlan(plan, options, hooks, target);
329
+ result.hookResults = hookResults;
330
+ process.stdout.write(options.format === 'json' ? reportExecution(result, options.format) : reportExecutionSummary(result, options.format));
331
+ }
332
+ finally {
333
+ const resultEnv = hookEnvForResult(plan, target, true, Boolean(options.dryRun));
334
+ await runHooksQuiet('after:apply', hooks['after:apply'], resultEnv, config.cwd, hookResults);
335
+ }
336
+ }
337
+ finally {
338
+ await runHooksQuiet('after:everything', hooks['after:everything'], baseEnv, config.cwd, hookResults);
339
+ }
311
340
  },
312
341
  }),
313
342
  },
@@ -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,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"}
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;AAQnB,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,YA2DF,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
@@ -7,6 +7,7 @@ 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
9
  import { mirrorConfigSchemaReference } from './schema.js';
10
+ import { normalizeHooksConfig } from './hooks.js';
10
11
  const adapters = new Set(['package.json', 'jsr.json', 'git']);
11
12
  const projectNameSources = new Set(['package.json', 'jsr.json']);
12
13
  export const resolveMirrorPath = (cwd, path) => (isAbsolute(path) ? path : resolve(cwd, path));
@@ -73,6 +74,7 @@ export const normalizeMirrorConfig = (raw, cwd, configPath, options = {}) => {
73
74
  const changelogPath = optionalString(raw.agents?.changelog_path, 'agents.changelog_path') ?? 'CHANGELOG.md';
74
75
  const autoAgentsMd = optionalBoolean(raw.agents?.auto_agents_md, 'agents.auto_agents_md') !== false;
75
76
  const autoSkillInstall = optionalBoolean(raw.agents?.auto_skill_install, 'agents.auto_skill_install') !== false;
77
+ const hooks = normalizeHooksConfig(raw.hooks);
76
78
  return {
77
79
  schema: 1,
78
80
  cwd,
@@ -106,6 +108,7 @@ export const normalizeMirrorConfig = (raw, cwd, configPath, options = {}) => {
106
108
  autoAgentsMd,
107
109
  autoSkillInstall,
108
110
  },
111
+ hooks,
109
112
  };
110
113
  };
111
114
  export const defaultInitAnswersForSource = (kind, cwd) => ({
@@ -1,7 +1,7 @@
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 { MirrorCliOptions, MirrorExecutionResult } from './types.js';
4
+ import type { MirrorCliOptions, MirrorExecutionResult, MirrorHooksConfig } from './types.js';
5
5
  export declare const applyVersionPlan: (target: string, options?: MirrorCliOptions) => Promise<MirrorExecutionResult>;
6
- export declare const executeVersionPlan: (plan: MirrorExecutionResult["plan"], options?: MirrorCliOptions) => Promise<MirrorExecutionResult>;
6
+ export declare const executeVersionPlan: (plan: MirrorExecutionResult["plan"], options?: MirrorCliOptions, hooks?: MirrorHooksConfig, target?: string) => Promise<MirrorExecutionResult>;
7
7
  //# sourceMappingURL=executor.d.ts.map
@@ -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;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"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../source/executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAM5F,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,EAC9B,QAAQ,iBAAiB,EACzB,eAAyB,KACxB,OAAO,CAAC,qBAAqB,CAoC/B,CAAA"}
@@ -4,29 +4,45 @@
4
4
  import { MirrorError } from './errors.js';
5
5
  import { createGitCommit, createGitTag, isGitDirty, isGitRepository, pushGitRefs, writeJsrVersionFile, writePackageVersionFile } from './adapters.js';
6
6
  import { buildVersionPlan } from './plan.js';
7
+ import { hookEnvForAction, runActionHooks } from './hooks.js';
7
8
  export const applyVersionPlan = async (target, options = {}) => {
8
9
  const plan = await buildVersionPlan(target, options);
9
10
  return executeVersionPlan(plan, options);
10
11
  };
11
- export const executeVersionPlan = async (plan, options = {}) => {
12
+ export const executeVersionPlan = async (plan, options = {}, hooks, target = plan.nextVersion) => {
13
+ const hookResults = [];
12
14
  if (options.dryRun)
13
- return { plan, applied: false, dryRun: true };
15
+ return { plan, applied: false, dryRun: true, hookResults };
14
16
  if (!plan.allowDirty && (await isGitRepository(plan.cwd)) && (await isGitDirty(plan.cwd))) {
15
17
  throw new MirrorError('Git worktree is dirty. Commit changes or pass --allow-dirty.');
16
18
  }
17
19
  if (!options.yes)
18
20
  throw new MirrorError('Refusing to apply without confirmation. Pass --yes to apply the plan.');
19
21
  for (const action of plan.actions) {
20
- if (action.type === 'write-file' && action.adapter === 'package.json')
21
- await writePackageVersionFile(action.path, plan.nextVersion);
22
- if (action.type === 'write-file' && action.adapter === 'jsr.json')
23
- await writeJsrVersionFile(action.path, plan.nextVersion);
24
- if (action.type === 'git-commit')
22
+ const actionEnv = hookEnvForAction(plan, target, action);
23
+ if (action.type === 'write-file') {
24
+ await runActionHooks('before:write', hooks?.['before:write'], actionEnv, plan.cwd, options);
25
+ if (action.adapter === 'package.json')
26
+ await writePackageVersionFile(action.path, plan.nextVersion);
27
+ if (action.adapter === 'jsr.json')
28
+ await writeJsrVersionFile(action.path, plan.nextVersion);
29
+ await runActionHooks('after:write', hooks?.['after:write'], actionEnv, plan.cwd, options);
30
+ }
31
+ if (action.type === 'git-commit') {
32
+ await runActionHooks('before:commit', hooks?.['before:commit'], actionEnv, plan.cwd, options);
25
33
  await createGitCommit(plan.cwd, action.paths, action.message);
26
- if (action.type === 'git-tag')
34
+ await runActionHooks('after:commit', hooks?.['after:commit'], actionEnv, plan.cwd, options);
35
+ }
36
+ if (action.type === 'git-tag') {
37
+ await runActionHooks('before:tag', hooks?.['before:tag'], actionEnv, plan.cwd, options);
27
38
  await createGitTag(plan.cwd, action.tag);
28
- if (action.type === 'git-push')
39
+ await runActionHooks('after:tag', hooks?.['after:tag'], actionEnv, plan.cwd, options);
40
+ }
41
+ if (action.type === 'git-push') {
42
+ await runActionHooks('before:push', hooks?.['before:push'], actionEnv, plan.cwd, options);
29
43
  await pushGitRefs(plan.cwd, action.includeCommit, action.includeTags);
44
+ await runActionHooks('after:push', hooks?.['after:push'], actionEnv, plan.cwd, options);
45
+ }
30
46
  }
31
- return { plan, applied: true, dryRun: false };
47
+ return { plan, applied: true, dryRun: false, hookResults };
32
48
  };
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
3
  */
4
- export type { MirrorAdapterName, MirrorCliOptions, MirrorConfig, MirrorExecutionResult, MirrorFormat, MirrorAgentAutomationResult, MirrorAgentSettings, MirrorAgentsInstructionsResult, MirrorInitAnswers, MirrorInitFlags, MirrorInitPrompter, MirrorRawConfig, MirrorSkillInstallResult, MirrorSkillInstallScope, MirrorVersionPlan, MirrorVersionPlanAction, MirrorVersionTarget, } from './types.js';
4
+ export type { MirrorAdapterName, MirrorCliOptions, MirrorConfig, MirrorExecutionResult, MirrorFormat, MirrorAgentAutomationResult, MirrorAgentSettings, MirrorAgentsInstructionsResult, MirrorHookCommand, MirrorHookName, MirrorHookResult, MirrorHooksConfig, MirrorInitAnswers, MirrorInitFlags, MirrorInitPrompter, MirrorRawConfig, MirrorSkillInstallResult, MirrorSkillInstallScope, MirrorVersionPlan, MirrorVersionPlanAction, MirrorVersionTarget, } from './types.js';
5
5
  export { MirrorError, invariant } from './errors.js';
6
6
  export { parseMirrorCliOptions } from './flags.js';
7
- export { defaultMirrorAgentSettings, ensureMirrorAgentsInstructions, findAgentsFile, installMirrorSkill, isMirrorSkillInstalled, mirrorAgentsSection, mirrorAgentsSectionHeading, mirrorSkillName, resolveMirrorAgentSettings, resolveMirrorSkillPath, runMirrorAgentAutomation, } from './agents.js';
7
+ export { defaultMirrorAgentSettings, ensureMirrorAgentsInstructions, findAgentsFile, installMirrorSkill, isMirrorSkillInstalled, mirrorAgentsSection, mirrorAgentsSectionEndMarker, mirrorAgentsSectionHeading, mirrorAgentsSectionStartMarker, mirrorSkillName, resolveMirrorAgentSettings, resolveMirrorSkillPath, runMirrorAgentAutomation, } from './agents.js';
8
8
  export { createInitConfig, defaultInitAnswersForSource, discoverMirrorConfig, generateInitConfig, loadMirrorConfig, normalizeMirrorConfig, reconcileInitConfig, writeInitConfig, writeInitConfigFromAnswers, } from './config.js';
9
9
  export { createReadlineInitPrompter, isInteractiveInit, parseAdapterList, resolveInitAnswers } from './init.js';
10
10
  export { mirrorConfigJsonSchema, mirrorConfigSchemaReference, renderMirrorConfigJsonSchema } from './schema.js';
@@ -12,6 +12,7 @@ export { assertValidSemver, isMirrorReleaseTarget, mirrorReleaseTargets, resolve
12
12
  export { createGitCommit, createGitTag, ensureAdapterFiles, ensureGitAvailable, assertSupportedGitTagTemplate, isGitDirty, isGitRepository, readCurrentVersion, readGitVersion, readJsrName, readJsrVersion, readJsrVersionFile, readPackageName, readPackageVersion, readPackageVersionFile, renderGitTag, resolveProjectName, supportedGitTagTemplates, versionFromTag, writeJsrVersion, writeJsrVersionFile, writePackageVersion, writePackageVersionFile, } from './adapters.js';
13
13
  export { buildVersionPlan, releaseLabel, resolveFileOutputPaths, validateMirrorConfig } from './plan.js';
14
14
  export { applyVersionPlan, executeVersionPlan } from './executor.js';
15
+ export { hookEnvFromConfig, hookEnvForAction, hookEnvForPlan, hookEnvForResult, mirrorHookNames, normalizeHooksConfig, runHooks, runHooksQuiet, } from './hooks.js';
15
16
  export { mirrorBanner, reportAgentsInstructions, reportConfig, reportConfigSchema, reportExecution, reportExecutionSummary, reportPlan, reportSkillInstall, reportValue, } from './reporter.js';
16
17
  export { createMirrorCommand, runMirrorCli } from './cli.js';
17
18
  //# sourceMappingURL=guiho-mirror.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"guiho-mirror.d.ts","sourceRoot":"","sources":["../source/guiho-mirror.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,2BAA2B,EAC3B,mBAAmB,EACnB,8BAA8B,EAC9B,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAC9B,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,0BAA0B,EAC1B,eAAe,EACf,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,gBAAgB,EAChB,2BAA2B,EAC3B,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,0BAA0B,GAC3B,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC/G,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA;AAC/G,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACvI,OAAO,EACL,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,6BAA6B,EAC7B,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,EACxB,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AACxG,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACpE,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EAClB,WAAW,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"guiho-mirror.d.ts","sourceRoot":"","sources":["../source/guiho-mirror.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,2BAA2B,EAC3B,mBAAmB,EACnB,8BAA8B,EAC9B,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAC9B,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,mBAAmB,EACnB,4BAA4B,EAC5B,0BAA0B,EAC1B,8BAA8B,EAC9B,eAAe,EACf,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,gBAAgB,EAChB,2BAA2B,EAC3B,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,EACf,0BAA0B,GAC3B,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AAC/G,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA;AAC/G,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACvI,OAAO,EACL,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,6BAA6B,EAC7B,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,sBAAsB,EACtB,YAAY,EACZ,kBAAkB,EAClB,wBAAwB,EACxB,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AACxG,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACpE,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,oBAAoB,EACpB,QAAQ,EACR,aAAa,GACd,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EAClB,WAAW,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA"}
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export { MirrorError, invariant } from './errors.js';
5
5
  export { parseMirrorCliOptions } from './flags.js';
6
- export { defaultMirrorAgentSettings, ensureMirrorAgentsInstructions, findAgentsFile, installMirrorSkill, isMirrorSkillInstalled, mirrorAgentsSection, mirrorAgentsSectionHeading, mirrorSkillName, resolveMirrorAgentSettings, resolveMirrorSkillPath, runMirrorAgentAutomation, } from './agents.js';
6
+ export { defaultMirrorAgentSettings, ensureMirrorAgentsInstructions, findAgentsFile, installMirrorSkill, isMirrorSkillInstalled, mirrorAgentsSection, mirrorAgentsSectionEndMarker, mirrorAgentsSectionHeading, mirrorAgentsSectionStartMarker, mirrorSkillName, resolveMirrorAgentSettings, resolveMirrorSkillPath, runMirrorAgentAutomation, } from './agents.js';
7
7
  export { createInitConfig, defaultInitAnswersForSource, discoverMirrorConfig, generateInitConfig, loadMirrorConfig, normalizeMirrorConfig, reconcileInitConfig, writeInitConfig, writeInitConfigFromAnswers, } from './config.js';
8
8
  export { createReadlineInitPrompter, isInteractiveInit, parseAdapterList, resolveInitAnswers } from './init.js';
9
9
  export { mirrorConfigJsonSchema, mirrorConfigSchemaReference, renderMirrorConfigJsonSchema } from './schema.js';
@@ -11,5 +11,6 @@ export { assertValidSemver, isMirrorReleaseTarget, mirrorReleaseTargets, resolve
11
11
  export { createGitCommit, createGitTag, ensureAdapterFiles, ensureGitAvailable, assertSupportedGitTagTemplate, isGitDirty, isGitRepository, readCurrentVersion, readGitVersion, readJsrName, readJsrVersion, readJsrVersionFile, readPackageName, readPackageVersion, readPackageVersionFile, renderGitTag, resolveProjectName, supportedGitTagTemplates, versionFromTag, writeJsrVersion, writeJsrVersionFile, writePackageVersion, writePackageVersionFile, } from './adapters.js';
12
12
  export { buildVersionPlan, releaseLabel, resolveFileOutputPaths, validateMirrorConfig } from './plan.js';
13
13
  export { applyVersionPlan, executeVersionPlan } from './executor.js';
14
+ export { hookEnvFromConfig, hookEnvForAction, hookEnvForPlan, hookEnvForResult, mirrorHookNames, normalizeHooksConfig, runHooks, runHooksQuiet, } from './hooks.js';
14
15
  export { mirrorBanner, reportAgentsInstructions, reportConfig, reportConfigSchema, reportExecution, reportExecutionSummary, reportPlan, reportSkillInstall, reportValue, } from './reporter.js';
15
16
  export { createMirrorCommand, runMirrorCli } from './cli.js';
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ */
4
+ import type { MirrorCliOptions, MirrorConfig, MirrorHookCommand, MirrorHookName, MirrorHookResult, MirrorHooksConfig, MirrorVersionPlan, MirrorVersionPlanAction } from './types.js';
5
+ export declare const mirrorHookNames: MirrorHookName[];
6
+ export declare const normalizeHooksConfig: (raw: Record<string, MirrorHookCommand> | undefined) => MirrorHooksConfig;
7
+ export declare const runHooks: (name: MirrorHookName, commands: string[] | undefined, env: Record<string, string>, cwd: string) => Promise<MirrorHookResult | undefined>;
8
+ export declare const runHooksQuiet: (name: MirrorHookName, commands: string[] | undefined, env: Record<string, string>, cwd: string, results: MirrorHookResult[]) => Promise<void>;
9
+ export declare const runActionHooks: (name: MirrorHookName, commands: string[] | undefined, env: Record<string, string>, cwd: string, options: MirrorCliOptions) => Promise<MirrorHookResult | undefined>;
10
+ export declare const hookEnvFromConfig: (config: MirrorConfig, target: string) => Record<string, string>;
11
+ export declare const hookEnvForPlan: (plan: MirrorVersionPlan, target: string) => Record<string, string>;
12
+ export declare const hookEnvForAction: (plan: MirrorVersionPlan, target: string, action: MirrorVersionPlanAction) => Record<string, string>;
13
+ export declare const hookEnvForResult: (plan: MirrorVersionPlan, target: string, applied: boolean, dryRun: boolean) => Record<string, string>;
14
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../source/hooks.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAUpL,eAAO,MAAM,eAAe,EAAE,cAAc,EAQ3C,CAAA;AAID,eAAO,MAAM,oBAAoB,GAAI,KAAK,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,SAAS,KAAG,iBAezF,CAAA;AAED,eAAO,MAAM,QAAQ,GACnB,MAAM,cAAc,EACpB,UAAU,MAAM,EAAE,GAAG,SAAS,EAC9B,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,KAAK,MAAM,KACV,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAwBtC,CAAA;AAED,eAAO,MAAM,aAAa,GACxB,MAAM,cAAc,EACpB,UAAU,MAAM,EAAE,GAAG,SAAS,EAC9B,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,KAAK,MAAM,EACX,SAAS,gBAAgB,EAAE,KAC1B,OAAO,CAAC,IAAI,CAUd,CAAA;AAED,eAAO,MAAM,cAAc,GACzB,MAAM,cAAc,EACpB,UAAU,MAAM,EAAE,GAAG,SAAS,EAC9B,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC3B,KAAK,MAAM,EACX,SAAS,gBAAgB,KACxB,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAItC,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,QAAQ,YAAY,EAAE,QAAQ,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAM5F,CAAA;AAEF,eAAO,MAAM,cAAc,GAAI,MAAM,iBAAiB,EAAE,QAAQ,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAa5F,CAAA;AAEF,eAAO,MAAM,gBAAgB,GAAI,MAAM,iBAAiB,EAAE,QAAQ,MAAM,EAAE,QAAQ,uBAAuB,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAwBhI,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,MAAM,iBAAiB,EAAE,QAAQ,MAAM,EAAE,SAAS,OAAO,EAAE,QAAQ,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAIjI,CAAA"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * @copyright Copyright (c) 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
3
+ */
4
+ import { exec } from 'node:child_process';
5
+ import { promisify } from 'node:util';
6
+ import { MirrorError } from './errors.js';
7
+ const execAsync = (command, options) => promisify(exec)(command, {
8
+ cwd: options.cwd,
9
+ env: { ...process.env, ...options.env },
10
+ maxBuffer: 10 * 1024 * 1024,
11
+ });
12
+ export const mirrorHookNames = [
13
+ 'before:everything', 'after:everything',
14
+ 'before:plan', 'after:plan',
15
+ 'before:apply', 'after:apply',
16
+ 'before:write', 'after:write',
17
+ 'before:commit', 'after:commit',
18
+ 'before:tag', 'after:tag',
19
+ 'before:push', 'after:push',
20
+ ];
21
+ const hookNameSet = new Set(mirrorHookNames);
22
+ export const normalizeHooksConfig = (raw) => {
23
+ if (!raw || typeof raw !== 'object')
24
+ return {};
25
+ const config = {};
26
+ for (const [key, value] of Object.entries(raw)) {
27
+ const name = key.replaceAll('_', ':');
28
+ if (!hookNameSet.has(name))
29
+ continue;
30
+ const commands = typeof value === 'string' ? [value] : value;
31
+ config[name] = commands;
32
+ }
33
+ return config;
34
+ };
35
+ export const runHooks = async (name, commands, env, cwd) => {
36
+ if (!commands || commands.length === 0)
37
+ return undefined;
38
+ const start = Date.now();
39
+ for (let i = 0; i < commands.length; i++) {
40
+ const command = commands[i];
41
+ if (!command)
42
+ continue;
43
+ try {
44
+ await execAsync(command, { cwd, env });
45
+ }
46
+ catch (error) {
47
+ const message = error instanceof Error ? error.message : String(error);
48
+ const exitCode = typeof error['code'] === 'number' ? error['code'] : 1;
49
+ throw new MirrorError(`Hook '${name}' failed (exit code ${exitCode}): ${command}\n${message}`, Number(exitCode));
50
+ }
51
+ }
52
+ return {
53
+ name,
54
+ commands,
55
+ status: 'success',
56
+ durationMs: Date.now() - start,
57
+ exitCode: 0,
58
+ };
59
+ };
60
+ export const runHooksQuiet = async (name, commands, env, cwd, results) => {
61
+ if (!commands || commands.length === 0)
62
+ return;
63
+ try {
64
+ await runHooks(name, commands, env, cwd);
65
+ results.push({ name, commands, status: 'success', durationMs: 0, exitCode: 0 });
66
+ }
67
+ catch (error) {
68
+ const exitCode = error instanceof MirrorError ? error.exitCode ?? 1 : 1;
69
+ results.push({ name, commands, status: 'failure', durationMs: 0, exitCode, stderr: error instanceof Error ? error.message : String(error) });
70
+ }
71
+ };
72
+ export const runActionHooks = async (name, commands, env, cwd, options) => {
73
+ if (options.dryRun || !commands || commands.length === 0)
74
+ return undefined;
75
+ return runHooks(name, commands, env, cwd);
76
+ };
77
+ export const hookEnvFromConfig = (config, target) => ({
78
+ MIRROR_CWD: config.cwd,
79
+ MIRROR_CONFIG_PATH: config.configPath ?? '',
80
+ MIRROR_SOURCE: config.version.source,
81
+ MIRROR_OUTPUT: config.version.output.join(','),
82
+ MIRROR_TARGET: target,
83
+ });
84
+ export const hookEnvForPlan = (plan, target) => ({
85
+ MIRROR_CWD: plan.cwd,
86
+ MIRROR_CONFIG_PATH: plan.configPath ?? '',
87
+ MIRROR_SOURCE: plan.source,
88
+ MIRROR_OUTPUT: plan.output.join(','),
89
+ MIRROR_TARGET: target,
90
+ MIRROR_CURRENT: plan.currentVersion,
91
+ MIRROR_NEXT: plan.nextVersion,
92
+ MIRROR_PROJECT_NAME: plan.project.name ?? '',
93
+ MIRROR_GIT_TAG: plan.gitTag ?? '',
94
+ MIRROR_FILE_PATHS: plan.fileOutputPaths.join(','),
95
+ MIRROR_COMMIT_ENABLED: String(plan.commitEnabled),
96
+ MIRROR_PUSH_ENABLED: String(plan.pushEnabled),
97
+ });
98
+ export const hookEnvForAction = (plan, target, action) => {
99
+ const env = hookEnvForPlan(plan, target);
100
+ if (action.type === 'write-file') {
101
+ env['MIRROR_FILE_PATH'] = action.path;
102
+ env['MIRROR_FILE_CURRENT'] = action.currentVersion;
103
+ env['MIRROR_FILE_NEXT'] = action.nextVersion;
104
+ }
105
+ if (action.type === 'git-commit') {
106
+ env['MIRROR_COMMIT_MSG'] = action.message;
107
+ env['MIRROR_COMMIT_PATHS'] = action.paths.join(' ');
108
+ }
109
+ if (action.type === 'git-tag') {
110
+ env['MIRROR_TAG'] = action.tag;
111
+ }
112
+ if (action.type === 'git-push') {
113
+ env['MIRROR_INCLUDE_COMMIT'] = String(action.includeCommit);
114
+ env['MIRROR_INCLUDE_TAGS'] = String(action.includeTags);
115
+ }
116
+ return env;
117
+ };
118
+ export const hookEnvForResult = (plan, target, applied, dryRun) => ({
119
+ ...hookEnvForPlan(plan, target),
120
+ MIRROR_APPLIED: String(applied),
121
+ MIRROR_DRY_RUN: String(dryRun),
122
+ });
@@ -1,7 +1,7 @@
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 { MirrorAgentsInstructionsResult, MirrorConfig, MirrorExecutionResult, MirrorFormat, MirrorSkillInstallResult, MirrorVersionPlan } from './types.js';
4
+ import type { MirrorAgentsInstructionsResult, MirrorConfig, MirrorExecutionResult, MirrorFormat, MirrorHookResult, MirrorSkillInstallResult, MirrorVersionPlan } from './types.js';
5
5
  export declare const mirrorBanner: (configPath?: string) => string;
6
6
  export declare const reportValue: (value: unknown, format?: MirrorFormat) => string;
7
7
  export declare const reportConfig: (config: MirrorConfig, format?: MirrorFormat) => string;
@@ -11,4 +11,5 @@ export declare const reportAgentsInstructions: (result: MirrorAgentsInstructions
11
11
  export declare const reportPlan: (plan: MirrorVersionPlan, format?: MirrorFormat) => string;
12
12
  export declare const reportExecution: (result: MirrorExecutionResult, format?: MirrorFormat) => string;
13
13
  export declare const reportExecutionSummary: (result: MirrorExecutionResult, format?: MirrorFormat) => string;
14
+ export declare const reportHookResults: (results: MirrorHookResult[]) => string;
14
15
  //# sourceMappingURL=reporter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../source/reporter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,8BAA8B,EAC9B,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,wBAAwB,EACxB,iBAAiB,EAClB,MAAM,YAAY,CAAA;AAInB,eAAO,MAAM,YAAY,GAAI,aAAa,MAAM,WAW/C,CAAA;AAED,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,EAAE,SAAQ,YAAqB,WAGxE,CAAA;AAED,eAAO,MAAM,YAAY,GAAI,QAAQ,YAAY,EAAE,SAAQ,YAAqB,WAoB/E,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,SAAQ,YAAqB,WAyC/D,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,QAAQ,wBAAwB,EAAE,SAAQ,YAAqB,WAWjG,CAAA;AAED,eAAO,MAAM,wBAAwB,GAAI,QAAQ,8BAA8B,EAAE,SAAQ,YAAqB,WAS7G,CAAA;AAED,eAAO,MAAM,UAAU,GAAI,MAAM,iBAAiB,EAAE,SAAQ,YAAqB,WAyBhF,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,QAAQ,qBAAqB,EAAE,SAAQ,YAAqB,WAG3F,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,QAAQ,qBAAqB,EAAE,SAAQ,YAAqB,WAgBlG,CAAA"}
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../source/reporter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACV,8BAA8B,EAC9B,YAAY,EACZ,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,iBAAiB,EAClB,MAAM,YAAY,CAAA;AAInB,eAAO,MAAM,YAAY,GAAI,aAAa,MAAM,WAW/C,CAAA;AAED,eAAO,MAAM,WAAW,GAAI,OAAO,OAAO,EAAE,SAAQ,YAAqB,WAGxE,CAAA;AAED,eAAO,MAAM,YAAY,GAAI,QAAQ,YAAY,EAAE,SAAQ,YAAqB,WAoB/E,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,SAAQ,YAAqB,WAyD/D,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,QAAQ,wBAAwB,EAAE,SAAQ,YAAqB,WAWjG,CAAA;AAED,eAAO,MAAM,wBAAwB,GAAI,QAAQ,8BAA8B,EAAE,SAAQ,YAAqB,WAS7G,CAAA;AAED,eAAO,MAAM,UAAU,GAAI,MAAM,iBAAiB,EAAE,SAAQ,YAAqB,WAyBhF,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,QAAQ,qBAAqB,EAAE,SAAQ,YAAqB,WAK3F,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,QAAQ,qBAAqB,EAAE,SAAQ,YAAqB,WAkBlG,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,SAAS,gBAAgB,EAAE,WAG5D,CAAA"}
@@ -78,6 +78,22 @@ export const reportConfigSchema = (format = 'text') => {
78
78
  ' auto_agents_md = true | false Optional. Insert Mirror guidance into AGENTS.md when present. Default: true.',
79
79
  ' auto_skill_install = true | false Optional. Install guiho-as-mirror globally when missing. Default: true.',
80
80
  '',
81
+ ' [hooks]',
82
+ ' before_everything = "<command>" Optional. Shell command(s) before any release work.',
83
+ ' after_everything = "<command>" Optional. Shell command(s) after all release work (always runs).',
84
+ ' before_plan = "<command>" Optional. Shell command(s) before building the release plan.',
85
+ ' after_plan = "<command>" Optional. Shell command(s) after the plan is built.',
86
+ ' before_apply = "<command>" Optional. Shell command(s) before executing the plan.',
87
+ ' after_apply = "<command>" Optional. Shell command(s) after plan execution (always runs).',
88
+ ' before_write = "<command>" Optional. Shell command(s) before writing version files.',
89
+ ' after_write = "<command>" Optional. Shell command(s) after writing version files.',
90
+ ' before_commit = "<command>" Optional. Shell command(s) before creating a release commit.',
91
+ ' after_commit = "<command>" Optional. Shell command(s) after creating a release commit.',
92
+ ' before_tag = "<command>" Optional. Shell command(s) before creating a release tag.',
93
+ ' after_tag = "<command>" Optional. Shell command(s) after creating a release tag.',
94
+ ' before_push = "<command>" Optional. Shell command(s) before pushing release refs.',
95
+ ' after_push = "<command>" Optional. Shell command(s) after pushing release refs.',
96
+ '',
81
97
  ].join('\n');
82
98
  };
83
99
  export const reportSkillInstall = (result, format = 'text') => {
@@ -135,7 +151,10 @@ export const reportPlan = (plan, format = 'text') => {
135
151
  export const reportExecution = (result, format = 'text') => {
136
152
  if (format === 'json')
137
153
  return `${JSON.stringify(result, null, 2)}\n`;
138
- return `${reportPlan(result.plan, 'text')}applied: ${String(result.applied)}\ndry_run: ${String(result.dryRun)}\n`;
154
+ let out = `${reportPlan(result.plan, 'text')}applied: ${String(result.applied)}\ndry_run: ${String(result.dryRun)}\n`;
155
+ if (result.hookResults && result.hookResults.length > 0)
156
+ out += reportHookResults(result.hookResults);
157
+ return out;
139
158
  };
140
159
  export const reportExecutionSummary = (result, format = 'text') => {
141
160
  if (format === 'json')
@@ -152,5 +171,12 @@ export const reportExecutionSummary = (result, format = 'text') => {
152
171
  lines.push(`files: ${files}`);
153
172
  if (result.plan.gitTag)
154
173
  lines.push(`tag: ${result.plan.gitTag}`);
174
+ let out = `${lines.join('\n')}\n`;
175
+ if (result.hookResults && result.hookResults.length > 0)
176
+ out += reportHookResults(result.hookResults);
177
+ return out;
178
+ };
179
+ export const reportHookResults = (results) => {
180
+ const lines = results.map((r) => `hooks: ${r.name} ${r.status}${r.exitCode ? ` (exit ${r.exitCode})` : ''}`);
155
181
  return `${lines.join('\n')}\n`;
156
182
  };
@@ -127,6 +127,37 @@ export declare const mirrorConfigJsonSchema: {
127
127
  };
128
128
  };
129
129
  };
130
+ readonly hooks: {
131
+ readonly type: "object";
132
+ readonly description: "Lifecycle hook commands that run at defined points during version apply.";
133
+ readonly additionalProperties: {
134
+ readonly oneOf: readonly [{
135
+ readonly type: "string";
136
+ readonly description: "A single shell command.";
137
+ }, {
138
+ readonly type: "array";
139
+ readonly items: {
140
+ readonly type: "string";
141
+ };
142
+ readonly description: "Multiple shell commands run sequentially.";
143
+ }];
144
+ };
145
+ readonly properties: {
146
+ [k: string]: {
147
+ oneOf: ({
148
+ type: string;
149
+ description: string;
150
+ items?: undefined;
151
+ } | {
152
+ type: string;
153
+ items: {
154
+ type: string;
155
+ };
156
+ description: string;
157
+ })[];
158
+ };
159
+ };
160
+ };
130
161
  };
131
162
  };
132
163
  export declare const renderMirrorConfigJsonSchema: () => string;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../source/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,2BAA2B,kEAAkE,CAAA;AAE1G,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0HzB,CAAA;AAEV,eAAO,MAAM,4BAA4B,cAA+D,CAAA"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../source/schema.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,2BAA2B,kEAAkE,CAAA;AAE1G,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkJzB,CAAA;AAEV,eAAO,MAAM,4BAA4B,cAA+D,CAAA"}
package/library/schema.js CHANGED
@@ -123,6 +123,30 @@ export const mirrorConfigJsonSchema = {
123
123
  },
124
124
  },
125
125
  },
126
+ hooks: {
127
+ type: 'object',
128
+ description: 'Lifecycle hook commands that run at defined points during version apply.',
129
+ additionalProperties: {
130
+ oneOf: [
131
+ { type: 'string', description: 'A single shell command.' },
132
+ { type: 'array', items: { type: 'string' }, description: 'Multiple shell commands run sequentially.' },
133
+ ],
134
+ },
135
+ properties: Object.fromEntries([
136
+ 'before_everything', 'after_everything',
137
+ 'before_plan', 'after_plan',
138
+ 'before_apply', 'after_apply',
139
+ 'before_write', 'after_write',
140
+ 'before_commit', 'after_commit',
141
+ 'before_tag', 'after_tag',
142
+ 'before_push', 'after_push',
143
+ ].map((key) => [key, {
144
+ oneOf: [
145
+ { type: 'string', description: `A single shell command to run at the ${key.replaceAll('_', ':')} lifecycle point.` },
146
+ { type: 'array', items: { type: 'string' }, description: `Multiple shell commands to run sequentially at the ${key.replaceAll('_', ':')} lifecycle point.` },
147
+ ],
148
+ }])),
149
+ },
126
150
  },
127
151
  };
128
152
  export const renderMirrorConfigJsonSchema = () => `${JSON.stringify(mirrorConfigJsonSchema, null, 2)}\n`;
@@ -8,6 +8,18 @@ export type MirrorFormat = 'text' | 'json';
8
8
  export type MirrorVersionTarget = ReleaseType | string;
9
9
  export type MirrorJsonObject = Record<string, unknown>;
10
10
  export type MirrorSkillInstallScope = 'local' | 'global';
11
+ export type MirrorHookName = 'before:everything' | 'after:everything' | 'before:plan' | 'after:plan' | 'before:apply' | 'after:apply' | 'before:write' | 'after:write' | 'before:commit' | 'after:commit' | 'before:tag' | 'after:tag' | 'before:push' | 'after:push';
12
+ export type MirrorHookCommand = string | string[];
13
+ export type MirrorHooksConfig = Partial<Record<MirrorHookName, string[]>>;
14
+ export type MirrorHookResult = {
15
+ name: MirrorHookName;
16
+ commands: string[];
17
+ status: 'success' | 'failure' | 'skipped';
18
+ durationMs: number;
19
+ exitCode?: number;
20
+ stdout?: string;
21
+ stderr?: string;
22
+ };
11
23
  export type MirrorRawConfig = Partial<{
12
24
  schema: number;
13
25
  project: Partial<{
@@ -39,6 +51,7 @@ export type MirrorRawConfig = Partial<{
39
51
  auto_agents_md: boolean;
40
52
  auto_skill_install: boolean;
41
53
  }>;
54
+ hooks: Record<string, MirrorHookCommand>;
42
55
  }>;
43
56
  export type MirrorConfig = {
44
57
  schema: 1;
@@ -68,6 +81,7 @@ export type MirrorConfig = {
68
81
  allowDirty: boolean;
69
82
  };
70
83
  agents: MirrorAgentSettings;
84
+ hooks: MirrorHooksConfig;
71
85
  };
72
86
  export type MirrorAgentSettings = {
73
87
  writeChangelog: boolean;
@@ -186,5 +200,6 @@ export type MirrorExecutionResult = {
186
200
  plan: MirrorVersionPlan;
187
201
  applied: boolean;
188
202
  dryRun: boolean;
203
+ hookResults?: MirrorHookResult[];
189
204
  };
190
205
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../source/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../source/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@guiho/mirror",
3
3
  "description": "Open source project versioning for Bun, npm, JSR, and Git.",
4
- "version": "3.2.0",
4
+ "version": "3.2.1",
5
5
  "type": "module",
6
6
  "main": "./library/guiho-mirror.js",
7
7
  "types": "./library/guiho-mirror.d.ts",
@@ -143,6 +143,237 @@
143
143
  "description": "Install guiho-as-mirror globally when missing."
144
144
  }
145
145
  }
146
+ },
147
+ "hooks": {
148
+ "type": "object",
149
+ "description": "Lifecycle hook commands that run at defined points during version apply.",
150
+ "additionalProperties": {
151
+ "oneOf": [
152
+ {
153
+ "type": "string",
154
+ "description": "A single shell command."
155
+ },
156
+ {
157
+ "type": "array",
158
+ "items": {
159
+ "type": "string"
160
+ },
161
+ "description": "Multiple shell commands run sequentially."
162
+ }
163
+ ]
164
+ },
165
+ "properties": {
166
+ "before_everything": {
167
+ "oneOf": [
168
+ {
169
+ "type": "string",
170
+ "description": "A single shell command to run at the before:everything lifecycle point."
171
+ },
172
+ {
173
+ "type": "array",
174
+ "items": {
175
+ "type": "string"
176
+ },
177
+ "description": "Multiple shell commands to run sequentially at the before:everything lifecycle point."
178
+ }
179
+ ]
180
+ },
181
+ "after_everything": {
182
+ "oneOf": [
183
+ {
184
+ "type": "string",
185
+ "description": "A single shell command to run at the after:everything lifecycle point."
186
+ },
187
+ {
188
+ "type": "array",
189
+ "items": {
190
+ "type": "string"
191
+ },
192
+ "description": "Multiple shell commands to run sequentially at the after:everything lifecycle point."
193
+ }
194
+ ]
195
+ },
196
+ "before_plan": {
197
+ "oneOf": [
198
+ {
199
+ "type": "string",
200
+ "description": "A single shell command to run at the before:plan lifecycle point."
201
+ },
202
+ {
203
+ "type": "array",
204
+ "items": {
205
+ "type": "string"
206
+ },
207
+ "description": "Multiple shell commands to run sequentially at the before:plan lifecycle point."
208
+ }
209
+ ]
210
+ },
211
+ "after_plan": {
212
+ "oneOf": [
213
+ {
214
+ "type": "string",
215
+ "description": "A single shell command to run at the after:plan lifecycle point."
216
+ },
217
+ {
218
+ "type": "array",
219
+ "items": {
220
+ "type": "string"
221
+ },
222
+ "description": "Multiple shell commands to run sequentially at the after:plan lifecycle point."
223
+ }
224
+ ]
225
+ },
226
+ "before_apply": {
227
+ "oneOf": [
228
+ {
229
+ "type": "string",
230
+ "description": "A single shell command to run at the before:apply lifecycle point."
231
+ },
232
+ {
233
+ "type": "array",
234
+ "items": {
235
+ "type": "string"
236
+ },
237
+ "description": "Multiple shell commands to run sequentially at the before:apply lifecycle point."
238
+ }
239
+ ]
240
+ },
241
+ "after_apply": {
242
+ "oneOf": [
243
+ {
244
+ "type": "string",
245
+ "description": "A single shell command to run at the after:apply lifecycle point."
246
+ },
247
+ {
248
+ "type": "array",
249
+ "items": {
250
+ "type": "string"
251
+ },
252
+ "description": "Multiple shell commands to run sequentially at the after:apply lifecycle point."
253
+ }
254
+ ]
255
+ },
256
+ "before_write": {
257
+ "oneOf": [
258
+ {
259
+ "type": "string",
260
+ "description": "A single shell command to run at the before:write lifecycle point."
261
+ },
262
+ {
263
+ "type": "array",
264
+ "items": {
265
+ "type": "string"
266
+ },
267
+ "description": "Multiple shell commands to run sequentially at the before:write lifecycle point."
268
+ }
269
+ ]
270
+ },
271
+ "after_write": {
272
+ "oneOf": [
273
+ {
274
+ "type": "string",
275
+ "description": "A single shell command to run at the after:write lifecycle point."
276
+ },
277
+ {
278
+ "type": "array",
279
+ "items": {
280
+ "type": "string"
281
+ },
282
+ "description": "Multiple shell commands to run sequentially at the after:write lifecycle point."
283
+ }
284
+ ]
285
+ },
286
+ "before_commit": {
287
+ "oneOf": [
288
+ {
289
+ "type": "string",
290
+ "description": "A single shell command to run at the before:commit lifecycle point."
291
+ },
292
+ {
293
+ "type": "array",
294
+ "items": {
295
+ "type": "string"
296
+ },
297
+ "description": "Multiple shell commands to run sequentially at the before:commit lifecycle point."
298
+ }
299
+ ]
300
+ },
301
+ "after_commit": {
302
+ "oneOf": [
303
+ {
304
+ "type": "string",
305
+ "description": "A single shell command to run at the after:commit lifecycle point."
306
+ },
307
+ {
308
+ "type": "array",
309
+ "items": {
310
+ "type": "string"
311
+ },
312
+ "description": "Multiple shell commands to run sequentially at the after:commit lifecycle point."
313
+ }
314
+ ]
315
+ },
316
+ "before_tag": {
317
+ "oneOf": [
318
+ {
319
+ "type": "string",
320
+ "description": "A single shell command to run at the before:tag lifecycle point."
321
+ },
322
+ {
323
+ "type": "array",
324
+ "items": {
325
+ "type": "string"
326
+ },
327
+ "description": "Multiple shell commands to run sequentially at the before:tag lifecycle point."
328
+ }
329
+ ]
330
+ },
331
+ "after_tag": {
332
+ "oneOf": [
333
+ {
334
+ "type": "string",
335
+ "description": "A single shell command to run at the after:tag lifecycle point."
336
+ },
337
+ {
338
+ "type": "array",
339
+ "items": {
340
+ "type": "string"
341
+ },
342
+ "description": "Multiple shell commands to run sequentially at the after:tag lifecycle point."
343
+ }
344
+ ]
345
+ },
346
+ "before_push": {
347
+ "oneOf": [
348
+ {
349
+ "type": "string",
350
+ "description": "A single shell command to run at the before:push lifecycle point."
351
+ },
352
+ {
353
+ "type": "array",
354
+ "items": {
355
+ "type": "string"
356
+ },
357
+ "description": "Multiple shell commands to run sequentially at the before:push lifecycle point."
358
+ }
359
+ ]
360
+ },
361
+ "after_push": {
362
+ "oneOf": [
363
+ {
364
+ "type": "string",
365
+ "description": "A single shell command to run at the after:push lifecycle point."
366
+ },
367
+ {
368
+ "type": "array",
369
+ "items": {
370
+ "type": "string"
371
+ },
372
+ "description": "Multiple shell commands to run sequentially at the after:push lifecycle point."
373
+ }
374
+ ]
375
+ }
376
+ }
146
377
  }
147
378
  }
148
379
  }