@event4u/agent-config 9.27.0 → 9.29.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.
Files changed (220) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/AGENTS.md +13 -12
  3. package/CHANGELOG.md +165 -0
  4. package/README.md +1 -1
  5. package/agents/templates/.ai-council.yml.example +55 -24
  6. package/dist/agent-src/commands/analyze/conformance.md +24 -0
  7. package/dist/agent-src/commands/cost/report.md +2 -2
  8. package/dist/agent-src/commands/team/adversarial.md +8 -7
  9. package/dist/agent-src/commands/team/delegate.md +13 -12
  10. package/dist/agent-src/commands/team/review.md +9 -8
  11. package/dist/agent-src/commands/team/status.md +9 -8
  12. package/dist/agent-src/commands/team.md +29 -19
  13. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +88 -2
  14. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +29 -21
  15. package/dist/agent-src/contexts/execution/host-capability-manifest.md +26 -15
  16. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +28 -3
  17. package/dist/agent-src/contexts/execution/subagent-response-contract.md +54 -0
  18. package/dist/agent-src/contexts/execution/subagent-routing.md +13 -11
  19. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +25 -0
  20. package/dist/agent-src/contexts/execution/subagent-steering.md +6 -3
  21. package/dist/agent-src/rules/artifact-engagement-recording.md +4 -1
  22. package/dist/agent-src/rules/autonomous-execution.md +1 -1
  23. package/dist/agent-src/rules/brand-source-of-truth.md +33 -6
  24. package/dist/agent-src/rules/context-hygiene.md +3 -1
  25. package/dist/agent-src/rules/council-availability.md +93 -0
  26. package/dist/agent-src/rules/cross-source-consistency.md +3 -0
  27. package/dist/agent-src/rules/delegation-policy.md +38 -10
  28. package/dist/agent-src/rules/design-fidelity.md +3 -0
  29. package/dist/agent-src/rules/evaluator-independence.md +2 -1
  30. package/dist/agent-src/rules/external-code-graph-interop.md +2 -1
  31. package/dist/agent-src/rules/finance-safety-floor.md +1 -1
  32. package/dist/agent-src/rules/git-history-discipline.md +1 -1
  33. package/dist/agent-src/rules/history-discipline.md +3 -1
  34. package/dist/agent-src/rules/legal-safety-floor.md +1 -1
  35. package/dist/agent-src/rules/no-pr-progress-comments.md +3 -1
  36. package/dist/agent-src/rules/onboarding-gate.md +3 -1
  37. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +4 -1
  38. package/dist/agent-src/rules/role-mode-adherence.md +1 -1
  39. package/dist/agent-src/rules/scale-discipline.md +3 -1
  40. package/dist/agent-src/rules/self-repair-loop.md +103 -0
  41. package/dist/agent-src/rules/session-canary.md +2 -1
  42. package/dist/agent-src/rules/settings-ask-protocol.md +8 -7
  43. package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
  44. package/dist/agent-src/rules/token-budget-discipline.md +4 -2
  45. package/dist/agent-src/rules/tool-safety.md +5 -1
  46. package/dist/agent-src/skills/adversarial-review/SKILL.md +1 -1
  47. package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -1
  48. package/dist/agent-src/skills/forensics-report/SKILL.md +114 -0
  49. package/dist/agent-src/skills/forensics-report/evals/triggers.json +17 -0
  50. package/dist/agent-src/skills/performance-analysis/SKILL.md +1 -1
  51. package/dist/agent-src/skills/persona-improvement/SKILL.md +1 -1
  52. package/dist/agent-src/skills/premortem/SKILL.md +30 -1
  53. package/dist/agent-src/skills/project-analyzer/SKILL.md +1 -1
  54. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -1
  55. package/dist/agent-src/skills/security-audit/SKILL.md +1 -1
  56. package/dist/agent-src/skills/sequential-thinking/SKILL.md +1 -1
  57. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  58. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +7 -5
  59. package/dist/agent-src/skills/subagent-orchestration/schemas/subagent-status.json +61 -3
  60. package/dist/agent-src/skills/test-case-discovery/SKILL.md +1 -1
  61. package/dist/agent-src/skills/universal-project-analysis/SKILL.md +1 -1
  62. package/dist/agent-src/templates/AGENTS.md +8 -12
  63. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  64. package/dist/agent-src/templates/roadmaps.md +23 -0
  65. package/dist/cli/registry.js +7 -0
  66. package/dist/cli/registry.js.map +1 -1
  67. package/dist/cli-delegate/chunk-66OVWGB5.js +270 -0
  68. package/dist/cli-delegate/{chunk-HJ6DAJHR.js → chunk-LCFJIQ4J.js} +89 -7
  69. package/dist/cli-delegate/{chunk-VSYT7OHO.js → chunk-LVRYBKTI.js} +31 -2
  70. package/dist/cli-delegate/{chunk-DVRS2KVR.js → chunk-MMXA5GY7.js} +10 -17
  71. package/dist/cli-delegate/{chunk-WR6GTRHJ.js → chunk-MP3JT3IU.js} +3 -3
  72. package/dist/cli-delegate/{chunk-3KJIMFTB.js → chunk-NZ5N2XQL.js} +467 -305
  73. package/dist/cli-delegate/{chunk-AIIUU73N.js → chunk-OJM3MBJM.js} +1 -1
  74. package/dist/cli-delegate/{chunk-BCPIOAGV.js → chunk-RCIA67XN.js} +117 -96
  75. package/dist/cli-delegate/chunk-REKCMYOU.js +2991 -0
  76. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  77. package/dist/cli-delegate/cmd_brand_status.js +134 -0
  78. package/dist/cli-delegate/cmd_conformance.js +10 -47
  79. package/dist/cli-delegate/cmd_converge.js +3 -3
  80. package/dist/cli-delegate/cmd_doctor.js +10 -6
  81. package/dist/cli-delegate/cmd_explain.js +80 -330
  82. package/dist/cli-delegate/cmd_export.js +6 -6
  83. package/dist/cli-delegate/cmd_fleet.js +3 -3
  84. package/dist/cli-delegate/cmd_handoff.js +3 -3
  85. package/dist/cli-delegate/cmd_mcp_available.js +433 -0
  86. package/dist/cli-delegate/cmd_migrate.js +3 -3
  87. package/dist/cli-delegate/cmd_packs_active.js +153 -0
  88. package/dist/cli-delegate/cmd_preflight.js +1 -1
  89. package/dist/cli-delegate/cmd_prune.js +6 -6
  90. package/dist/cli-delegate/cmd_route_audit.js +8 -8
  91. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  92. package/dist/cli-delegate/cmd_settings_get.js +266 -0
  93. package/dist/cli-delegate/cmd_settings_migrate.js +6 -6
  94. package/dist/cli-delegate/cmd_settings_set.js +8 -2968
  95. package/dist/cli-delegate/cmd_sync.js +6 -6
  96. package/dist/cli-delegate/cmd_uninstall.js +6 -6
  97. package/dist/cli-delegate/cmd_update.js +4 -4
  98. package/dist/cli-delegate/cmd_upgrade.js +4 -4
  99. package/dist/cli-delegate/cmd_validate.js +6 -6
  100. package/dist/cli-delegate/cmd_versions.js +4 -4
  101. package/dist/discovery/deprecation-report.md +1 -1
  102. package/dist/discovery/discovery-manifest.json +164 -55
  103. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  104. package/dist/discovery/discovery-manifest.summary.md +4 -3
  105. package/dist/discovery/orphan-report.md +1 -1
  106. package/dist/discovery/packs.json +44 -5
  107. package/dist/discovery/trust-report.md +11 -11
  108. package/dist/discovery/workspaces.json +16 -6
  109. package/dist/hooks/dispatch.js +9341 -6131
  110. package/dist/install/install.mjs +739 -524
  111. package/dist/mcp/registry-manifest.json +3 -3
  112. package/dist/mcp/server.json +2 -2
  113. package/dist/mcp/server.mjs +777 -281
  114. package/dist/router.json +1 -1
  115. package/dist/scripts/_lib/agent_settings.js +134 -15
  116. package/dist/scripts/_lib/agent_settings.js.map +1 -1
  117. package/dist/scripts/condense.js +147 -2
  118. package/dist/scripts/condense.js.map +1 -1
  119. package/dist/server/schemas/settings.js +6 -7
  120. package/dist/server/schemas/settings.js.map +1 -1
  121. package/dist/shared/settingsCarveOut.js +0 -9
  122. package/dist/shared/settingsCarveOut.js.map +1 -1
  123. package/dist/shared/settingsClasses.js +11 -9
  124. package/dist/shared/settingsClasses.js.map +1 -1
  125. package/dist/ui/assets/{index-DmR0mbk4.js → index-JDAF00bC.js} +2 -2
  126. package/dist/ui/assets/{index-DmR0mbk4.js.map → index-JDAF00bC.js.map} +1 -1
  127. package/dist/ui/index.html +1 -1
  128. package/docs/contracts/settings-classes.md +68 -17
  129. package/docs/guidelines/agent-infra/memory-access.md +14 -3
  130. package/package.json +1 -1
  131. package/src/agent-src/templates/AGENTS.md +8 -12
  132. package/src/config/agent-settings.template.yml +52 -66
  133. package/src/config/budgets.yml +29 -0
  134. package/src/config/discovery/packs.yml +11 -0
  135. package/src/config/discovery/workspaces.yml +1 -1
  136. package/src/config/evaluator-budgets.json +4 -4
  137. package/src/config/gate-coverage.yml +26 -0
  138. package/src/config/gate-violation-baselines.json +3 -3
  139. package/src/scripts/_cli/cmd_brand_status.ts +174 -0
  140. package/src/scripts/_cli/cmd_conformance.ts +14 -42
  141. package/src/scripts/_cli/cmd_doctor.ts +65 -48
  142. package/src/scripts/_cli/cmd_mcp_available.ts +266 -0
  143. package/src/scripts/_cli/cmd_packs_active.ts +225 -0
  144. package/src/scripts/_cli/cmd_settings_get.ts +324 -0
  145. package/src/scripts/_dispatch.bash +57 -0
  146. package/src/scripts/_lib/agent_settings.ts +140 -16
  147. package/src/scripts/_lib/auto_dispatch.corpus.test.ts +1 -1
  148. package/src/scripts/_lib/auto_dispatch.ts +23 -18
  149. package/src/scripts/_lib/capsule_trigger.ts +124 -0
  150. package/src/scripts/_lib/carrier_divergence.ts +135 -0
  151. package/src/scripts/_lib/host_capability.ts +144 -4
  152. package/src/scripts/_lib/judgment_ladder.ts +382 -0
  153. package/src/scripts/_lib/orchestration_gate.ts +8 -0
  154. package/src/scripts/_lib/orchestration_record.ts +37 -0
  155. package/src/scripts/_lib/orchestration_savings.ts +1 -1
  156. package/src/scripts/_lib/prompt_shape.ts +88 -0
  157. package/src/scripts/_lib/review_skipped_record.ts +102 -0
  158. package/src/scripts/_lib/rule_layer_overlap.ts +254 -0
  159. package/src/scripts/_lib/self_repair.ts +489 -0
  160. package/src/scripts/_lib/self_repair_store.ts +128 -0
  161. package/src/scripts/_lib/subagent_capsule.ts +182 -0
  162. package/src/scripts/_lib/subagent_response.ts +19 -0
  163. package/src/scripts/_lib/subagent_spawn.ts +13 -0
  164. package/src/scripts/_lib/subagent_steering.ts +9 -4
  165. package/src/scripts/_lib/tier_budget_routing.ts +6 -1
  166. package/src/scripts/_lib/transcript_entry.ts +80 -0
  167. package/src/scripts/_lib/worker_budget.ts +37 -2
  168. package/src/scripts/ai_council/clients.ts +76 -54
  169. package/src/scripts/ai_council/config.ts +94 -6
  170. package/src/scripts/ai_council/handoff.ts +113 -0
  171. package/src/scripts/ai_council/modes.ts +19 -4
  172. package/src/scripts/ai_council/orchestrator.ts +105 -0
  173. package/src/scripts/ai_council/quorum.ts +84 -0
  174. package/src/scripts/ai_council/session.ts +44 -0
  175. package/src/scripts/ai_council/transport_resolver.ts +127 -1
  176. package/src/scripts/ai_team/availability.ts +110 -0
  177. package/src/scripts/ai_team/config.ts +34 -14
  178. package/src/scripts/ai_team/team_dispatch.ts +71 -29
  179. package/src/scripts/bench_critic_protocol.ts +396 -0
  180. package/src/scripts/check_branch_freshness.ts +255 -0
  181. package/src/scripts/check_council_config_location.ts +125 -1
  182. package/src/scripts/check_detector_corpus.ts +202 -0
  183. package/src/scripts/check_hook_bundle_freshness.ts +4 -1
  184. package/src/scripts/check_standing_rule_delivery.ts +314 -0
  185. package/src/scripts/condense.ts +162 -2
  186. package/src/scripts/config/profiles.ts +13 -3
  187. package/src/scripts/conformance_scan.ts +272 -24
  188. package/src/scripts/council_availability_hook.ts +188 -0
  189. package/src/scripts/council_cli.ts +527 -32
  190. package/src/scripts/forensics_report.ts +333 -0
  191. package/src/scripts/hook_manifest.yaml +107 -26
  192. package/src/scripts/hooks/block_no_verify.ts +39 -2
  193. package/src/scripts/hooks/block_unauthorized_git.ts +156 -7
  194. package/src/scripts/hooks/concern_registry.ts +10 -0
  195. package/src/scripts/hooks/delegation_nudge_hook.ts +484 -0
  196. package/src/scripts/hooks/end_review_nudge_hook.ts +726 -0
  197. package/src/scripts/hooks/orchestration_record_hook.ts +342 -0
  198. package/src/scripts/install.ts +151 -0
  199. package/src/scripts/language_mirror_hook.ts +30 -37
  200. package/src/scripts/lint_discovery_vocabulary.ts +2 -0
  201. package/src/scripts/lint_never_silent.ts +276 -0
  202. package/src/scripts/lint_no_activation_gates.ts +271 -0
  203. package/src/scripts/measure_scope_dedup.ts +19 -13
  204. package/src/scripts/onboarding_gate_hook.ts +40 -1
  205. package/src/scripts/orchestration_record.ts +12 -1
  206. package/src/scripts/preamble_byte_census.ts +9 -20
  207. package/src/scripts/rebuild_hook_bundle.ts +177 -0
  208. package/src/scripts/release.ts +74 -2
  209. package/src/scripts/report_carrier_divergence.ts +364 -0
  210. package/src/scripts/report_skill_activation.ts +257 -0
  211. package/src/scripts/report_skill_obligation_violations.ts +579 -0
  212. package/src/scripts/routing_doctor.ts +95 -39
  213. package/src/scripts/score_skill_selection.ts +19 -5
  214. package/src/scripts/self_repair_cli.ts +470 -0
  215. package/src/scripts/self_repair_hook.ts +241 -0
  216. package/src/scripts/team_events_spike.ts +271 -0
  217. package/src/scripts/team_review_gate_hook.ts +31 -9
  218. package/src/server/schemas/settings.ts +10 -17
  219. package/src/shared/settingsCarveOut.ts +0 -10
  220. package/src/shared/settingsClasses.ts +11 -9
@@ -44,6 +44,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
44
44
  import * as YAML from 'yaml';
45
45
 
46
46
  import { resolveGlobalProfilePath } from './_lib/agent_user_profile.js';
47
+ import { censusRuleDir, type RuleDirCensus } from './_lib/carrier_divergence.js';
47
48
  import { DEFAULT_PROJECTS_ROOT, scanTranscripts } from './_lib/cc_transcript.js';
48
49
  import { censusDuplicateScope } from './_lib/duplicate_scope_census.js';
49
50
  import { computeColdStarts } from './cache_realization_report.js';
@@ -71,26 +72,14 @@ function readCharsIfExists(p: string): number {
71
72
 
72
73
  // ── source 1/2: rule directories ────────────────────────────────────────
73
74
 
74
- export interface RuleDirCensus {
75
- files: number;
76
- chars: number;
77
- }
78
-
79
- export function censusRuleDir(dir: string): RuleDirCensus {
80
- if (!fs.existsSync(dir)) return { files: 0, chars: 0 };
81
- let files = 0;
82
- let chars = 0;
83
- for (const name of fs.readdirSync(dir)) {
84
- if (!name.endsWith('.md')) continue;
85
- try {
86
- chars += fs.statSync(path.join(dir, name)).size;
87
- files += 1;
88
- } catch {
89
- // Unreadable entry — skip rather than fail the whole census.
90
- }
91
- }
92
- return { files, chars };
93
- }
75
+ // Moved to `_lib/carrier_divergence.ts` when `conformance_scan` needed the same
76
+ // count (round-6 Phase 4.3): that module is on a bundled CLI path and this one
77
+ // pulls `yaml` plus the cold-start report, so importing this file to reach fifteen
78
+ // lines of `statSync` was the wrong direction. Re-exported so every existing
79
+ // caller keeps its import and there is still one definition. Imported as well as
80
+ // re-exported: a bare `export … from` does not bind the name in this module's own
81
+ // scope, and this file uses both below.
82
+ export { censusRuleDir, type RuleDirCensus };
94
83
 
95
84
  export interface PerRuleCost {
96
85
  file: string;
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Safe self-heal for the self-hosted hook bundle — the builder that
4
+ * `check_hook_bundle_freshness` deliberately is not.
5
+ *
6
+ * WHY THIS EXISTS — measured, not hypothetical.
7
+ *
8
+ * The freshness gate reds after ANY hook-source merge from main, because
9
+ * `dist/hooks/dispatch.js` is untracked and nothing in the local chain
10
+ * rebuilds it. On 2026-08-09 that turned `task release` (9.28.0) into a
11
+ * blocked push with a remedy the operator had to run by hand — a routine
12
+ * pre-push chore promoted to a release incident. The gate is right to never
13
+ * build (its documented hazard: esbuild overwriting the dispatcher a running
14
+ * hook is executing can wedge the tool loop). The hazard is in HOW a naive
15
+ * rebuild writes, not in rebuilding: this script builds to a sibling `.new`
16
+ * file, proves the result actually dispatches, and only then renames it into
17
+ * place — an atomic same-directory rename that a running hook holding an open
18
+ * file descriptor never observes mid-write.
19
+ *
20
+ * The `.new` file MUST live in `dist/hooks/` (not a temp dir): the bundle
21
+ * resolves `src/scripts/hook_manifest.yaml` relative to its OWN location via
22
+ * the `__AGENT_CONFIG_BUNDLE__` path-depth switch. Built anywhere else, every
23
+ * probe answers "manifest missing" with exit 0 and the smoke test proves
24
+ * nothing (measured 2026-08-08).
25
+ *
26
+ * The esbuild invocation is NOT duplicated here — it is read from
27
+ * `package.json`'s `build:hooks` script and only the `--outfile=` is
28
+ * rewritten, so the flag set (banner, defines, target) has exactly one home.
29
+ *
30
+ * Behaviour:
31
+ * no self-hosted bundle → no-op (fresh checkout / CI — nothing is running
32
+ * stale code, and materialising a bundle here would
33
+ * change what other gates see)
34
+ * bundle fresh → no-op
35
+ * bundle stale → rebuild to `.new`, probe, rename into place
36
+ * build or probe fails → the `.new` file is removed and the OLD bundle
37
+ * keeps running (old-but-working beats broken);
38
+ * exit 1 so the freshness gate behind this still
39
+ * reds and the failure is loud.
40
+ *
41
+ * Exit codes: 0 = fresh / healed / nothing to heal · 1 = heal failed.
42
+ */
43
+ import { spawnSync } from "node:child_process";
44
+ import * as fs from "node:fs";
45
+ import * as path from "node:path";
46
+ import { fileURLToPath } from "node:url";
47
+
48
+ import { check } from "./check_hook_bundle_freshness.js";
49
+
50
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
51
+ const REPO_ROOT = path.resolve(HERE, "..", "..");
52
+ const LIVE_REL = path.join("dist", "hooks", "dispatch.js");
53
+ const NEW_REL = path.join("dist", "hooks", "dispatch.new.js");
54
+
55
+ /**
56
+ * Rewrite the `--outfile=` of the canonical `build:hooks` script to the
57
+ * `.new` sibling. Returns null when the expected outfile token is absent —
58
+ * a changed `package.json` must fail loudly, never build to a guessed path.
59
+ */
60
+ export function rewriteOutfile(script: string, newOutfile: string): string | null {
61
+ const token = `--outfile=${LIVE_REL}`;
62
+ if (!script.includes(token)) return null;
63
+ return script.replace(token, `--outfile=${newOutfile}`);
64
+ }
65
+
66
+ /**
67
+ * Verdict on a dispatcher probe. The probe contract is pinned against the
68
+ * real dry-run output: exit 0 AND parseable JSON AND a non-empty `concerns`
69
+ * array. Exit 0 alone is NOT enough — a bundle that cannot find its manifest
70
+ * answers "manifest missing" with exit 0 (measured 2026-08-08), which is
71
+ * exactly the broken dispatcher this probe exists to keep out of the live
72
+ * path. Returns null on pass, a human-readable reason on failure.
73
+ */
74
+ export function probeVerdict(exitCode: number, stdout: string): string | null {
75
+ if (exitCode !== 0) return `probe exited ${String(exitCode)}`;
76
+ let parsed: unknown;
77
+ try {
78
+ parsed = JSON.parse(stdout);
79
+ } catch {
80
+ return `probe output is not JSON: ${stdout.slice(0, 120)}`;
81
+ }
82
+ const concerns = (parsed as { concerns?: unknown }).concerns;
83
+ if (!Array.isArray(concerns) || concerns.length === 0) {
84
+ return "probe JSON carries no concerns — the bundle dispatched nothing";
85
+ }
86
+ return null;
87
+ }
88
+
89
+ function cleanup(newAbs: string): void {
90
+ try {
91
+ fs.rmSync(newAbs, { force: true });
92
+ } catch {
93
+ // Best-effort: a leftover .new file is inert (nothing executes it).
94
+ }
95
+ }
96
+
97
+ export function main(): number {
98
+ const r = check(REPO_ROOT);
99
+
100
+ if (r.skipped) {
101
+ process.stdout.write(
102
+ `✅ OK rebuild_hook_bundle: no self-hosted ${LIVE_REL} — nothing runs stale code, nothing to heal\n`,
103
+ );
104
+ return 0;
105
+ }
106
+ if (r.stale.length === 0) {
107
+ process.stdout.write("✅ OK rebuild_hook_bundle: bundle already fresh — no rebuild needed\n");
108
+ return 0;
109
+ }
110
+
111
+ process.stdout.write(
112
+ `🔧 hook bundle stale (${String(r.stale.length)} newer source(s)) — rebuilding safely (build .new → probe → atomic rename)\n`,
113
+ );
114
+
115
+ const pkg = JSON.parse(fs.readFileSync(path.join(REPO_ROOT, "package.json"), "utf-8")) as {
116
+ scripts?: Record<string, string>;
117
+ };
118
+ const buildScript = pkg.scripts?.["build:hooks"];
119
+ if (buildScript === undefined) {
120
+ console.error("❌ rebuild_hook_bundle: package.json has no build:hooks script");
121
+ return 1;
122
+ }
123
+ const cmd = rewriteOutfile(buildScript, NEW_REL);
124
+ if (cmd === null) {
125
+ console.error(
126
+ `❌ rebuild_hook_bundle: build:hooks no longer targets --outfile=${LIVE_REL} — ` +
127
+ "refusing to build to a guessed path; update this script alongside package.json",
128
+ );
129
+ return 1;
130
+ }
131
+
132
+ const newAbs = path.join(REPO_ROOT, NEW_REL);
133
+ const build = spawnSync("sh", ["-c", cmd], {
134
+ cwd: REPO_ROOT,
135
+ encoding: "utf-8",
136
+ env: { ...process.env, PATH: `${path.join(REPO_ROOT, "node_modules", ".bin")}:${process.env["PATH"] ?? ""}` },
137
+ });
138
+ if (build.status !== 0) {
139
+ cleanup(newAbs);
140
+ console.error(`❌ rebuild_hook_bundle: esbuild failed (${String(build.status)}):`);
141
+ console.error((build.stderr || build.stdout || "").trim());
142
+ return 1;
143
+ }
144
+
145
+ const probe = spawnSync(
146
+ "node",
147
+ [newAbs, "--platform", "claude", "--event", "pre_tool_use", "--dry-run"],
148
+ { cwd: REPO_ROOT, encoding: "utf-8", input: "{}" },
149
+ );
150
+ const verdict = probeVerdict(probe.status ?? 1, probe.stdout ?? "");
151
+ if (verdict !== null) {
152
+ cleanup(newAbs);
153
+ console.error(`❌ rebuild_hook_bundle: new bundle failed its probe — ${verdict}`);
154
+ console.error(" The old bundle stays in place (old-but-working beats broken).");
155
+ return 1;
156
+ }
157
+
158
+ fs.renameSync(newAbs, path.join(REPO_ROOT, LIVE_REL));
159
+ process.stdout.write(
160
+ `✅ OK rebuild_hook_bundle: rebuilt + probed + renamed into place (${String(r.checked)} bundled source(s))\n`,
161
+ );
162
+ return 0;
163
+ }
164
+
165
+ const invokedDirectly = ((): boolean => {
166
+ const entry = process.argv[1];
167
+ if (entry === undefined) return false;
168
+ try {
169
+ return fs.realpathSync(path.resolve(entry)) === fs.realpathSync(fileURLToPath(import.meta.url));
170
+ } catch {
171
+ return false;
172
+ }
173
+ })();
174
+
175
+ if (invokedDirectly) {
176
+ process.exit(main());
177
+ }
@@ -1073,6 +1073,78 @@ function _tag_exists_remote(tag: string): boolean {
1073
1073
  return r.returncode === 0;
1074
1074
  }
1075
1075
 
1076
+ /**
1077
+ * True when git rejected a tag push because the ref already exists on the
1078
+ * remote. Wording pinned from the real failure (2026-08-09, 9.28.0 — two
1079
+ * concurrent resume runs, the loser crashed):
1080
+ *
1081
+ * ! [remote rejected] 9.28.0 -> 9.28.0 (cannot lock ref 'refs/tags/9.28.0': reference already exists)
1082
+ *
1083
+ * plus the `[rejected] … (already exists)` variant git emits when the local
1084
+ * and remote tag objects differ.
1085
+ */
1086
+ export function _is_tag_already_exists(stderr: string, stdout: string): boolean {
1087
+ const text = `${stderr}\n${stdout}`;
1088
+ return /\[(?:remote )?rejected\]/i.test(text) && /already exists/i.test(text);
1089
+ }
1090
+
1091
+ /** Peeled commit the remote tag points at, or null when the tag is absent. */
1092
+ function _remote_tag_commit(tag: string): string | null {
1093
+ const r = run(['git', 'ls-remote', REMOTE, `refs/tags/${tag}`, `refs/tags/${tag}^{}`], {
1094
+ check: false,
1095
+ capture: true,
1096
+ });
1097
+ if (r.returncode !== 0) return null;
1098
+ const lines = r.stdout.trim().split('\n').filter(Boolean);
1099
+ if (lines.length === 0) return null;
1100
+ // An annotated tag lists the tag object AND the peeled `^{}` commit — the
1101
+ // peeled line wins so the comparison is commit-vs-commit regardless of
1102
+ // whether the two runs minted distinct tag objects for the same commit.
1103
+ const peeled = lines.find((l) => l.trimEnd().endsWith('^{}'));
1104
+ return (peeled ?? (lines[0] as string)).split('\t')[0] ?? null;
1105
+ }
1106
+
1107
+ /**
1108
+ * Push a tag, tolerating exactly ONE failure: the concurrent-release race.
1109
+ * `_tag_exists_remote` in step 8 is a live check, but between it and this
1110
+ * push a parallel `task release` run can land the same tag (measured
1111
+ * 2026-08-09, 9.28.0). When the remote tag already points at the same commit
1112
+ * as the local one, the repository IS in the desired state — continue. Any
1113
+ * other rejection, and a same-name tag on a DIFFERENT commit, stays fatal
1114
+ * with the push output as the error.
1115
+ */
1116
+ function _push_tag(tag: string): void {
1117
+ const first = run(['git', 'push', REMOTE, tag], { check: false, capture: true });
1118
+ if (first.returncode === 0) {
1119
+ process.stdout.write(first.stdout);
1120
+ process.stderr.write(first.stderr);
1121
+ return;
1122
+ }
1123
+ if (_is_tag_already_exists(first.stderr, first.stdout)) {
1124
+ const remote = _remote_tag_commit(tag);
1125
+ const local = git(['rev-list', '-n', '1', tag], { capture: true });
1126
+ if (remote !== null && remote === local) {
1127
+ process.stdout.write(
1128
+ `↻ tag ${tag} already on ${REMOTE} at the same commit — a parallel run pushed it; continuing\n`,
1129
+ );
1130
+ return;
1131
+ }
1132
+ process.stdout.write(first.stdout);
1133
+ process.stderr.write(first.stderr);
1134
+ die(
1135
+ `tag ${tag} exists on ${REMOTE} pointing at ${remote ?? '<unreadable>'} while the local tag ` +
1136
+ `points at ${local} — refusing to overwrite a published tag; ` +
1137
+ 'delete the wrong one deliberately and re-run',
1138
+ );
1139
+ }
1140
+ process.stdout.write(first.stdout);
1141
+ process.stderr.write(first.stderr);
1142
+ die(
1143
+ `push of tag ${tag} failed (exit ${first.returncode}) — ` +
1144
+ 'the push output above is the real error (a pre-push gate, credentials, or protection)',
1145
+ );
1146
+ }
1147
+
1076
1148
  /** Most recent PR (any state) with `release/X.Y.Z` as head, or null. */
1077
1149
  function _pr_for_branch(branch: string): Record<string, unknown> | null {
1078
1150
  const r = run(
@@ -2029,7 +2101,7 @@ function execute(
2029
2101
  _step(8, total, `Tag ${plan.target} already on ${REMOTE} — skip`);
2030
2102
  } else {
2031
2103
  _step(8, total, `Tag ${plan.target} exists locally — push only`);
2032
- run(['git', 'push', REMOTE, plan.target]);
2104
+ _push_tag(plan.target);
2033
2105
  }
2034
2106
  } else {
2035
2107
  // Sequencing is load-bearing (release-truth Phase 1, council
@@ -2047,7 +2119,7 @@ function execute(
2047
2119
  );
2048
2120
  }
2049
2121
  run(['git', 'tag', '-a', plan.target, '-m', tag_message_from_section(merged!.body, plan.target)]);
2050
- run(['git', 'push', REMOTE, plan.target]);
2122
+ _push_tag(plan.target);
2051
2123
  }
2052
2124
 
2053
2125
  // ─── 9. GitHub Release ──────────────────────────────────────────────────
@@ -0,0 +1,364 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * report_carrier_divergence.ts — which rules the two carriers deliver
4
+ * differently, BY NAME.
5
+ *
6
+ * Executes round-5 Phase 1.3, landed under round-6 Phase 4.1. Advisory: **it
7
+ * gates on nothing** and must not acquire a threshold, for the reason
8
+ * `report_skill_activation` and `report_imperative_density` must not — plus one
9
+ * specific to this surface, below.
10
+ *
11
+ * WHY THIS EXISTS
12
+ * ---------------
13
+ * The suite installs machine-globally (`~/.claude/rules/`) and the package's own
14
+ * checkout also projects per-project (`dist/agent-src/rules/`, which every
15
+ * project-scope tree symlinks). A machine that has both loads the shared rules
16
+ * twice, and nothing said whether the two copies agree. Round 5 measured the
17
+ * condition once and named the dangerous case: its global copy of
18
+ * `git-history-discipline` asserted an unqualified "deterministically blocked by
19
+ * the `block-no-verify` PreToolUse guard" while the shipped copy carried the
20
+ * host-scoped retraction of exactly that claim. The agent held both, with no
21
+ * precedence marker.
22
+ *
23
+ * A one-off measurement cannot own that condition, because the condition is
24
+ * **transient and maintainer-dependent**: it appears when the checkout moves
25
+ * ahead of the installed release and disappears the next time the maintainer
26
+ * reinstalls. Verified both directions — see § THE 2026-08-08 RE-MEASUREMENT.
27
+ * So the deliverable is a report anyone can re-run, not a number in a roadmap.
28
+ *
29
+ * WHY IT MUST NOT BECOME A GATE
30
+ * -----------------------------
31
+ * A maintainer developing the package is *legitimately* ahead of their own
32
+ * global install — `condense.ts` says so where it explains why the byte-keyed
33
+ * dedup is inert in that state. A gate here would fail on the normal
34
+ * development condition, and a gate that fires on sanctioned behaviour gets
35
+ * ignored, which is the failure `check-rule-invariants` already paid for once.
36
+ * The point is that the condition becomes VISIBLE, not that it becomes illegal.
37
+ *
38
+ * THE THREE CLASSES, AND WHICH ONE A READER MUST ACT ON
39
+ * ----------------------------------------------------
40
+ * body-diff the two carriers deliver different TEXT. This is the class
41
+ * round 5's contradiction lived in, and the only one that
42
+ * needs a decision. Precedence when it appears: the project
43
+ * projection is generated from `src/` at the current commit,
44
+ * so it is the newer copy and it wins; the global install is
45
+ * a release snapshot. Printed with the report so the
46
+ * precedence is read at the moment it matters rather than
47
+ * looked up.
48
+ * provenance-only identical after removing the two installer ownership keys.
49
+ * Structural, expected, and decided against closing —
50
+ * `agents/settings/contexts/dedup-reachability-refusal.md`.
51
+ * Reported as a count with that pointer, never as a finding,
52
+ * or the real class drowns in it.
53
+ * one-carrier-only a rule present at exactly one scope. Not a contradiction:
54
+ * project-only is a rule newer than the installed release,
55
+ * global-only is a rule the release still carries. Named
56
+ * because asymmetric reach is what makes a project-scope
57
+ * measurement non-transferable to another machine.
58
+ *
59
+ * NOT IN SCOPE. Skills, commands and contexts have the same two-carrier shape
60
+ * and are not compared here; this executes the rule-scoped step that was
61
+ * specified. Nor does it compare `~/.claude/CLAUDE.md` against the project's
62
+ * `CLAUDE.md` — a different mechanism with a different precedence story.
63
+ *
64
+ * Exit: 0 always, except a usage error (1). Deliberate — see above.
65
+ */
66
+ import * as fs from 'node:fs';
67
+ import * as os from 'node:os';
68
+ import * as path from 'node:path';
69
+ import process from 'node:process';
70
+ import { fileURLToPath, pathToFileURL } from 'node:url';
71
+
72
+ import { comparePair, type PairVerdict } from './_lib/carrier_divergence.js';
73
+
74
+ const _HERE = fileURLToPath(import.meta.url);
75
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
76
+
77
+ /**
78
+ * The project carrier — the tree the host actually reads at project scope, NOT
79
+ * `dist/agent-src/rules/`.
80
+ *
81
+ * The distinction is load-bearing and was found by measuring: the global
82
+ * installer delivers the five ADR-004 `type: manual` rules while the project
83
+ * projection deliberately omits them, so anchoring on `dist` (which holds all
84
+ * 115) reports those five as *shared* when in fact only one carrier delivers
85
+ * them. Two writers, different filters — exactly the asymmetry this report
86
+ * exists to name. `dist` is still read, as the reference for what COULD be
87
+ * projected, which is what makes the manual class attributable rather than a
88
+ * bare absence.
89
+ */
90
+ export const PROJECT_RULES = path.join('.claude', 'rules');
91
+ /** What the project projection is generated from — the reference set. */
92
+ export const PROJECTION_SOURCE = path.join('dist', 'agent-src', 'rules');
93
+ /** The machine-global carrier, relative to the user's home. */
94
+ export const GLOBAL_RULES = path.join('.claude', 'rules');
95
+
96
+ export interface CarrierDivergence {
97
+ projectDir: string;
98
+ globalDir: string;
99
+ /** `false` when the global carrier is absent — every count is then 0. */
100
+ globalPresent: boolean;
101
+ /** `false` when the project tree has not been generated in this checkout. */
102
+ projectPresent: boolean;
103
+ shared: number;
104
+ identical: string[];
105
+ provenanceOnly: string[];
106
+ bodyDiff: string[];
107
+ projectOnly: string[];
108
+ globalOnly: string[];
109
+ /**
110
+ * Shared names whose copies could not both be read (a dangling symlink from a
111
+ * half-finished install). Counted rather than dropped: a pair that silently
112
+ * leaves `shared` makes every other number in the report unaccounted for.
113
+ */
114
+ unreadable: string[];
115
+ /**
116
+ * Rules the projection source carries, the global carrier delivers, and the
117
+ * project projection omits by design (`type: manual`). A subset of
118
+ * `globalOnly`, separated so the expected half does not read as drift.
119
+ */
120
+ manualOnlyGlobal: string[];
121
+ }
122
+
123
+ function _listRules(dir: string): string[] {
124
+ try {
125
+ return fs
126
+ .readdirSync(dir)
127
+ .filter((f) => f.endsWith('.md'))
128
+ .sort();
129
+ } catch {
130
+ return [];
131
+ }
132
+ }
133
+
134
+ /** `type:` from a rule's frontmatter, or `''` when unreadable / absent. */
135
+ function _ruleType(file: string): string {
136
+ let text: string;
137
+ try {
138
+ text = fs.readFileSync(file, 'utf-8');
139
+ } catch {
140
+ return '';
141
+ }
142
+ if (!text.startsWith('---')) return '';
143
+ const end = text.indexOf('\n---', 3);
144
+ const fm = end === -1 ? text : text.slice(0, end);
145
+ const m = /^type:\s*"?([a-z]+)"?/m.exec(fm);
146
+ return m === null ? '' : (m[1] as string);
147
+ }
148
+
149
+ /**
150
+ * Compare the two carriers over the UNION of their rule names.
151
+ *
152
+ * The union is the point: anchoring on either side alone hides one direction of
153
+ * asymmetric reach, and it was the hidden direction — rules the global install
154
+ * carries and the project does not — that made round 5's cross-project
155
+ * comparison hard to interpret.
156
+ *
157
+ * `sourceDir` is the projection source, read only to attribute a global-only
158
+ * rule to the ADR-004 manual filter rather than to drift. Absent → the manual
159
+ * split is simply empty, never a guess.
160
+ */
161
+ export function compareCarriers(
162
+ projectDir: string,
163
+ globalDir: string,
164
+ sourceDir?: string,
165
+ ): CarrierDivergence {
166
+ const out: CarrierDivergence = {
167
+ projectDir,
168
+ globalDir,
169
+ globalPresent: fs.existsSync(globalDir),
170
+ projectPresent: fs.existsSync(projectDir),
171
+ shared: 0,
172
+ identical: [],
173
+ provenanceOnly: [],
174
+ bodyDiff: [],
175
+ projectOnly: [],
176
+ globalOnly: [],
177
+ unreadable: [],
178
+ manualOnlyGlobal: [],
179
+ };
180
+ const project = new Set(_listRules(projectDir));
181
+ const global = new Set(_listRules(globalDir));
182
+
183
+ for (const rule of [...new Set([...project, ...global])].sort()) {
184
+ const inP = project.has(rule);
185
+ const inG = global.has(rule);
186
+ if (inP && !inG) {
187
+ out.projectOnly.push(rule);
188
+ continue;
189
+ }
190
+ if (!inP && inG) {
191
+ out.globalOnly.push(rule);
192
+ if (sourceDir !== undefined && _ruleType(path.join(sourceDir, rule)) === 'manual') {
193
+ out.manualOnlyGlobal.push(rule);
194
+ }
195
+ continue;
196
+ }
197
+ out.shared += 1;
198
+ let verdict: PairVerdict;
199
+ try {
200
+ verdict = comparePair(
201
+ fs.readFileSync(path.join(projectDir, rule)),
202
+ fs.readFileSync(path.join(globalDir, rule)),
203
+ );
204
+ } catch {
205
+ // An unreadable copy is not a body difference and must not be
206
+ // reported as one — a permission error would otherwise manufacture
207
+ // the only class this report asks a reader to act on. It is still
208
+ // NAMED: a pair that just disappears from `shared` leaves the ledger
209
+ // short with nothing saying why.
210
+ out.shared -= 1;
211
+ out.unreadable.push(rule);
212
+ continue;
213
+ }
214
+ if (verdict === 'identical') out.identical.push(rule);
215
+ else if (verdict === 'provenance-only') out.provenanceOnly.push(rule);
216
+ else out.bodyDiff.push(rule);
217
+ }
218
+ return out;
219
+ }
220
+
221
+ export function render(d: CarrierDivergence): string {
222
+ const lines: string[] = [];
223
+ lines.push('cross-carrier rule divergence — advisory, gates on nothing');
224
+ lines.push(` project carrier: ${d.projectDir}`);
225
+ lines.push(` global carrier: ${d.globalDir}`);
226
+ lines.push('');
227
+
228
+ if (!d.globalPresent) {
229
+ lines.push(' The global carrier is absent — this machine loads the project projection');
230
+ lines.push(' only, so there is no second copy to diverge from. Nothing to report, and');
231
+ lines.push(' that is a real answer rather than a skipped check.');
232
+ return lines.join('\n');
233
+ }
234
+ if (!d.projectPresent) {
235
+ lines.push(' The project rule tree does not exist in this checkout — it is generated and');
236
+ lines.push(' gitignored, so a fresh clone has none, and `agents/.agent-tools.yml` may');
237
+ lines.push(' select zero tools deliberately. Run `task generate-tools` and re-run this');
238
+ lines.push(' report. Reported rather than silently substituted with the projection');
239
+ lines.push(' source: dist/ holds rules the project tree omits by design, so reading it');
240
+ lines.push(' as the project carrier would answer a different question than the one asked.');
241
+ return lines.join('\n');
242
+ }
243
+
244
+ lines.push(` shared rule names ${d.shared}`);
245
+ lines.push(` byte-identical ${d.identical.length}`);
246
+ lines.push(` differ ONLY in the install stamp ${d.provenanceOnly.length}`);
247
+ lines.push(` differ in BODY ${d.bodyDiff.length}`);
248
+ if (d.unreadable.length > 0) {
249
+ lines.push(` unreadable on one side ${d.unreadable.length} (${d.unreadable.join(', ')})`);
250
+ lines.push(' Not counted as shared and NOT a body difference — a dangling entry is');
251
+ lines.push(' a broken install, not a disagreement about content.');
252
+ }
253
+ lines.push(` present at project scope only ${d.projectOnly.length}`);
254
+ lines.push(` present at global scope only ${d.globalOnly.length}`);
255
+ lines.push('');
256
+
257
+ if (d.bodyDiff.length > 0) {
258
+ lines.push(' BODY DIVERGENCE — the two carriers deliver different text for these rules.');
259
+ lines.push(' Both copies reach the model, with no precedence marker between them, so a');
260
+ lines.push(' claim one copy retracts can be re-asserted by the other. PRECEDENCE: the');
261
+ lines.push(' project projection is generated from src/ at this commit and wins; the');
262
+ lines.push(' global install is a release snapshot. Close it by reinstalling the global');
263
+ lines.push(' copy, or by reading the project copy as authoritative.');
264
+ for (const r of d.bodyDiff) lines.push(` - ${r}`);
265
+ lines.push('');
266
+ }
267
+
268
+ if (d.provenanceOnly.length > 0) {
269
+ lines.push(` ${String(d.provenanceOnly.length)} pair(s) differ only by the installer's package:/source_path: stamp.`);
270
+ lines.push(' Not a content difference and NOT a defect: install.ts stamps every installed');
271
+ lines.push(' rule, the in-repo projection stamps nothing. Closing it was decided against');
272
+ lines.push(' on 2026-07-31 — agents/settings/contexts/dedup-reachability-refusal.md holds');
273
+ lines.push(' the analysis and the five reopen conditions. Reported as a count on purpose:');
274
+ lines.push(' naming every expected pair would bury the class above.');
275
+ lines.push('');
276
+ }
277
+
278
+ if (d.projectOnly.length > 0) {
279
+ lines.push(` project-scope only (${String(d.projectOnly.length)}) — newer than the installed release:`);
280
+ lines.push(` ${d.projectOnly.join(', ')}`);
281
+ }
282
+ const driftGlobalOnly = d.globalOnly.filter((r) => !d.manualOnlyGlobal.includes(r));
283
+ if (driftGlobalOnly.length > 0) {
284
+ lines.push(` global-scope only (${String(driftGlobalOnly.length)}) — the release carries these, this checkout does not project them:`);
285
+ lines.push(` ${driftGlobalOnly.join(', ')}`);
286
+ }
287
+ if (d.manualOnlyGlobal.length > 0) {
288
+ lines.push(
289
+ ` delivered by the global carrier ONLY, by design (${String(d.manualOnlyGlobal.length)}, ADR-004 \`type: manual\`):`,
290
+ );
291
+ lines.push(` ${d.manualOnlyGlobal.join(', ')}`);
292
+ lines.push(' The project projection filters these out and the global installer does not.');
293
+ lines.push(' Two writers, different filters — so on a machine with both carriers these');
294
+ lines.push(' rules reach the model, and on a project-only machine they do not. Expected,');
295
+ lines.push(' and worth knowing before citing any project-scope reach figure.');
296
+ }
297
+ if (d.projectOnly.length > 0 || d.globalOnly.length > 0) {
298
+ lines.push('');
299
+ lines.push(' Asymmetric reach is why a project-scope conformance figure does not transfer');
300
+ lines.push(' to another machine: the rule set the model was told differs by carrier.');
301
+ }
302
+
303
+ if (d.bodyDiff.length === 0) {
304
+ lines.push('');
305
+ lines.push(' No body divergence. The condition is transient — it returns whenever the');
306
+ lines.push(' checkout moves ahead of the installed release — so this is a reading of');
307
+ lines.push(' right now, not a property of the repo. Re-run it, do not cite it.');
308
+ }
309
+ return lines.join('\n');
310
+ }
311
+
312
+ export function main(argv?: readonly string[]): number {
313
+ const args = argv ?? process.argv.slice(2);
314
+ let projectDir = path.join(REPO_ROOT, PROJECT_RULES);
315
+ let globalDir = path.join(os.homedir(), GLOBAL_RULES);
316
+ let sourceDir = path.join(REPO_ROOT, PROJECTION_SOURCE);
317
+ // A value must not itself be a flag. `--project --global /x` otherwise
318
+ // resolves a directory literally named `--global` and silently drops `/x`,
319
+ // reporting "tree does not exist" instead of a usage error — the flag-VALUE
320
+ // half of the hole this file's own test closes on the flag-NAME half.
321
+ const value = (i: number): string | null => {
322
+ const v = args[i + 1];
323
+ return v === undefined || v.startsWith('-') ? null : v;
324
+ };
325
+ for (let i = 0; i < args.length; i += 1) {
326
+ const a = args[i];
327
+ if (a === '--project' || a === '--global' || a === '--source') {
328
+ const v = value(i);
329
+ if (v === null) {
330
+ process.stderr.write(`report_carrier_divergence: ${a} needs a directory\n`);
331
+ return 1;
332
+ }
333
+ const resolved = path.resolve(v);
334
+ if (a === '--project') projectDir = resolved;
335
+ else if (a === '--global') globalDir = resolved;
336
+ else sourceDir = resolved;
337
+ i += 1;
338
+ } else if (a === '--help' || a === '-h') {
339
+ process.stdout.write(
340
+ 'usage: report_carrier_divergence [--project DIR] [--global DIR] [--source DIR]\n',
341
+ );
342
+ return 0;
343
+ } else if (a !== undefined && a.startsWith('--') && a !== '--quiet') {
344
+ process.stderr.write(`report_carrier_divergence: unknown flag ${a}\n`);
345
+ return 1;
346
+ }
347
+ }
348
+ process.stdout.write(`${render(compareCarriers(projectDir, globalDir, sourceDir))}\n`);
349
+ return 0;
350
+ }
351
+
352
+ function _isCliEntry(): boolean {
353
+ if (process.argv[1] === undefined) return false;
354
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
355
+ try {
356
+ return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
357
+ } catch {
358
+ return false;
359
+ }
360
+ }
361
+
362
+ if (_isCliEntry()) {
363
+ process.exit(main());
364
+ }