@event4u/agent-config 14.6.0 → 14.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +255 -145
- package/README.md +1 -1
- package/dist/agent-src/commands/analyze/inbox.md +264 -10
- package/dist/agent-src/commands/analyze.md +1 -1
- package/dist/agent-src/commands/evals/git-pr-merge.json +13 -0
- package/dist/agent-src/commands/evals/roadmap.json +17 -1
- package/dist/agent-src/commands/pr/create.md +14 -2
- package/dist/agent-src/commands/pr/merge.md +379 -0
- package/dist/agent-src/commands/roadmap/process-full.md +272 -32
- package/dist/agent-src/commands/roadmap.md +1 -1
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +46 -36
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +37 -2
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +95 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +289 -106
- package/dist/agent-src/rules/artifact-drafting-protocol.md +5 -1
- package/dist/agent-src/rules/context-hygiene.md +2 -0
- package/dist/agent-src/rules/decision-revisit-gate.md +67 -32
- package/dist/agent-src/rules/fix-what-you-see.md +108 -0
- package/dist/agent-src/rules/no-roadmap-references.md +0 -5
- package/dist/agent-src/rules/recurring-criticism.md +110 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +20 -1
- package/dist/agent-src/rules/rule-type-governance.md +0 -2
- package/dist/agent-src/rules/self-repair-loop.md +17 -0
- package/dist/agent-src/rules/skill-quality.md +0 -2
- package/dist/agent-src/rules/source-confidentiality.md +37 -7
- package/dist/agent-src/scripts/archival_sweep.ts +117 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +26 -7
- package/dist/agent-src/scripts/dashboard_mode.ts +212 -0
- package/dist/agent-src/scripts/gate_budget.ts +282 -0
- package/dist/agent-src/scripts/gate_execute.ts +72 -31
- package/dist/agent-src/scripts/roadmap_gates.ts +74 -3
- package/dist/agent-src/scripts/update_roadmap_progress.ts +296 -53
- package/dist/agent-src/skills/adr-create/SKILL.md +124 -5
- package/dist/agent-src/skills/ai-council/SKILL.md +48 -807
- package/dist/agent-src/skills/ai-council/references/advanced-modes.md +320 -0
- package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +99 -0
- package/dist/agent-src/skills/ai-council/references/execution-modes.md +162 -0
- package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +125 -0
- package/dist/agent-src/skills/ai-council/references/procedure.md +143 -0
- package/dist/agent-src/skills/decision-record/SKILL.md +61 -3
- package/dist/agent-src/skills/decision-review/SKILL.md +65 -0
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +26 -0
- package/dist/agent-src/skills/quality-tools/SKILL.md +34 -326
- package/dist/agent-src/skills/quality-tools/references/js-ts-tools.md +113 -0
- package/dist/agent-src/skills/quality-tools/references/php-tools.md +222 -0
- package/dist/agent-src/skills/roadmap-management/SKILL.md +15 -409
- package/dist/agent-src/skills/roadmap-management/references/archival.md +226 -0
- package/dist/agent-src/skills/roadmap-management/references/authoring.md +107 -0
- package/dist/agent-src/skills/roadmap-management/references/dashboard.md +47 -0
- package/dist/agent-src/skills/roadmap-management/references/lifecycle.md +58 -0
- package/dist/agent-src/skills/security/SKILL.md +8 -0
- package/dist/agent-src/skills/security-audit/SKILL.md +12 -1
- package/dist/agent-src/skills/skill-writing/SKILL.md +34 -570
- package/dist/agent-src/skills/skill-writing/references/procedure.md +275 -0
- package/dist/agent-src/skills/skill-writing/references/read-only-scripts.md +18 -0
- package/dist/agent-src/skills/skill-writing/references/section-patterns.md +298 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +65 -4
- package/dist/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
- package/dist/agent-src/templates/scripts/telemetry/remote.ts +160 -7
- package/dist/agent-src/templates/scripts/telemetry/transport.ts +169 -0
- package/dist/cli/registry.js +2 -1
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/chunk-2GNWGMAL.js +172 -0
- package/dist/cli-delegate/{chunk-P6LQDIWK.js → chunk-7PRE6ZV2.js} +338 -0
- package/dist/cli-delegate/{chunk-BKO2AZ7Z.js → chunk-B2ERU2VA.js} +1 -1
- package/dist/cli-delegate/chunk-E4XIZDIB.js +402 -0
- package/dist/cli-delegate/{chunk-3UCJWMMP.js → chunk-EEJUMCDZ.js} +16 -16
- package/dist/cli-delegate/{chunk-NXFWFAYV.js → chunk-G23AT6GD.js} +1 -0
- package/dist/cli-delegate/{chunk-XURJ4AQC.js → chunk-H4VIVD4C.js} +385 -284
- package/dist/cli-delegate/chunk-I3EIN2YG.js +36 -0
- package/dist/cli-delegate/{chunk-RLN73PR5.js → chunk-LPPWO5CE.js} +12 -8
- package/dist/cli-delegate/chunk-MWRD5YOH.js +100 -0
- package/dist/cli-delegate/{chunk-UEZ7D35A.js → chunk-N7CDDGI3.js} +4 -23
- package/dist/cli-delegate/{chunk-63WSP6YZ.js → chunk-PMEKGDED.js} +74 -167
- package/dist/cli-delegate/{chunk-GRRPEPRN.js → chunk-T7L2QK3K.js} +24 -5
- package/dist/cli-delegate/{chunk-EVTY7ISR.js → chunk-YM4GZDJG.js} +9 -1
- package/dist/cli-delegate/cmd_adr_effective.js +1162 -0
- package/dist/cli-delegate/cmd_conformance.js +466 -716
- package/dist/cli-delegate/cmd_converge.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +10 -10
- package/dist/cli-delegate/cmd_explain.js +1 -1
- package/dist/cli-delegate/cmd_export.js +10 -9
- package/dist/cli-delegate/cmd_handoff.js +10 -9
- package/dist/cli-delegate/cmd_memory_get.js +2 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +1 -1
- package/dist/cli-delegate/cmd_preflight.js +5 -5
- package/dist/cli-delegate/cmd_prune.js +11 -10
- package/dist/cli-delegate/cmd_route_audit.js +6 -5
- package/dist/cli-delegate/cmd_route_explain.js +3 -3
- package/dist/cli-delegate/cmd_session_recycle.js +840 -30
- package/dist/cli-delegate/cmd_settings_get.js +3 -3
- package/dist/cli-delegate/cmd_settings_migrate.js +10 -9
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +11 -10
- package/dist/cli-delegate/cmd_uninstall.js +13 -11
- package/dist/cli-delegate/cmd_update.js +4 -4
- package/dist/cli-delegate/cmd_upgrade.js +4 -4
- package/dist/cli-delegate/cmd_validate.js +11 -10
- package/dist/cli-delegate/cmd_versions.js +3 -3
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +111 -37
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +5 -5
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +15 -12
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +11 -8
- package/dist/hooks/dispatch.js +3165 -2192
- package/dist/install/claudePathsPlan.js +187 -0
- package/dist/install/claudePathsPlan.js.map +1 -0
- package/dist/install/globalRuleLayers.js +169 -0
- package/dist/install/globalRuleLayers.js.map +1 -0
- package/dist/install/hostLayerFingerprint.js +136 -0
- package/dist/install/hostLayerFingerprint.js.map +1 -0
- package/dist/install/install.mjs +553 -425
- package/dist/install/partitionEligibility.js +432 -0
- package/dist/install/partitionEligibility.js.map +1 -0
- package/dist/install/ruleLayerPartition.js +157 -0
- package/dist/install/ruleLayerPartition.js.map +1 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1863 -1234
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_src.js +41 -0
- package/dist/scripts/_lib/agent_src.js.map +1 -1
- package/dist/scripts/_lib/install_layout.js +83 -0
- package/dist/scripts/_lib/install_layout.js.map +1 -0
- package/dist/scripts/_lib/installed_lock.js +444 -0
- package/dist/scripts/_lib/installed_lock.js.map +1 -0
- package/dist/scripts/_lib/prune_empty_dirs.js +85 -0
- package/dist/scripts/_lib/prune_empty_dirs.js.map +1 -0
- package/dist/scripts/condense.js +63 -251
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/schemas/settings.js +4 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/docs/contracts/settings-classes.md +12 -6
- package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +8 -3
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +45 -1
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +26 -0
- package/docs/guidelines/agent-infra/false-green.md +47 -1
- package/docs/guidelines/agent-infra/memory-access.md +17 -0
- package/docs/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
- package/package.json +1 -1
- package/src/agent-src/scripts/archival_sweep.ts +117 -0
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +26 -7
- package/src/agent-src/scripts/dashboard_mode.ts +212 -0
- package/src/agent-src/scripts/gate_budget.ts +282 -0
- package/src/agent-src/scripts/gate_execute.ts +72 -31
- package/src/agent-src/scripts/roadmap_gates.ts +74 -3
- package/src/agent-src/scripts/update_roadmap_progress.ts +296 -53
- package/src/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
- package/src/agent-src/templates/scripts/telemetry/remote.ts +160 -7
- package/src/agent-src/templates/scripts/telemetry/transport.ts +169 -0
- package/src/config/agent-settings.template.yml +27 -2
- package/src/config/ci-local-parity.yml +39 -0
- package/src/config/estate-count-budget.json +612 -3
- package/src/config/evaluator-budgets.json +3 -3
- package/src/config/gate-coverage.yml +220 -12
- package/src/config/gate-violation-baselines.json +73 -63
- package/src/config/gitignore-block.txt +15 -2
- package/src/config/hook-latency-budget.json +5 -0
- package/src/config/rule-activation-census.json +14 -6
- package/src/config/rule-stub-ceilings.json +34 -7
- package/src/install/claudePathsPlan.ts +196 -0
- package/src/install/globalRuleLayers.ts +197 -0
- package/src/install/hostLayerFingerprint.ts +145 -0
- package/src/install/partitionEligibility.ts +502 -0
- package/src/install/ruleLayerPartition.ts +212 -0
- package/src/scripts/_cli/cmd_adr_effective.ts +484 -0
- package/src/scripts/_cli/cmd_session_recycle.ts +9 -1
- package/src/scripts/_dispatch.bash +17 -1
- package/src/scripts/_lib/ac_heading.ts +30 -0
- package/src/scripts/_lib/adr_frontmatter.test.ts +365 -0
- package/src/scripts/_lib/adr_frontmatter.ts +459 -0
- package/src/scripts/_lib/agent_src.ts +42 -0
- package/src/scripts/_lib/bench_ab_pinned_repo.ts +162 -0
- package/src/scripts/_lib/bench_ab_workspace.ts +10 -1
- package/src/scripts/_lib/envelope_grounding.ts +49 -9
- package/src/scripts/_lib/installed_lock.ts +50 -5
- package/src/scripts/_lib/layer_overlap_notice.ts +11 -2
- package/src/scripts/_lib/md_section.ts +129 -0
- package/src/scripts/_lib/prune_empty_dirs.ts +80 -0
- package/src/scripts/_lib/scope_guard.sh +26 -3
- package/src/scripts/_lib/self_repair.ts +19 -0
- package/src/scripts/_lib/self_repair_class_b.ts +171 -0
- package/src/scripts/adr/evidence_census.ts +899 -0
- package/src/scripts/adr/regenerate_index.ts +12 -32
- package/src/scripts/adr_cite_check.ts +540 -39
- package/src/scripts/ai_council/cli_help.ts +55 -0
- package/src/scripts/audit_adr_coverage.ts +103 -17
- package/src/scripts/before_complete_hook.ts +153 -28
- package/src/scripts/bench_ab_v2_complexity.ts +27 -7
- package/src/scripts/bench_hook_latency.ts +204 -0
- package/src/scripts/build_archive_index.ts +34 -0
- package/src/scripts/check_adr_frontmatter.ts +574 -39
- package/src/scripts/check_hook_bundle_content.ts +219 -0
- package/src/scripts/check_new_adr_evidence.ts +529 -0
- package/src/scripts/check_references.ts +78 -0
- package/src/scripts/check_release_published.ts +32 -11
- package/src/scripts/check_rule_layer_partition.ts +531 -0
- package/src/scripts/check_single_delivery.ts +194 -17
- package/src/scripts/check_standing_rule_delivery.ts +8 -2
- package/src/scripts/ci_settle.ts +170 -0
- package/src/scripts/condense.ts +79 -259
- package/src/scripts/council_cli.ts +3 -3
- package/src/scripts/dispatch_r2_reviewer.ts +6 -14
- package/src/scripts/external_sources_denylist.json +4 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +77 -14
- package/src/scripts/hooks/block_no_verify.ts +61 -10
- package/src/scripts/hooks/block_unauthorized_git.ts +21 -1
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/dispatch_hook.ts +154 -187
- package/src/scripts/hooks/dispatch_issues.ts +38 -19
- package/src/scripts/hooks/fallback_yaml.ts +66 -0
- package/src/scripts/hooks/host_semantics.ts +21 -0
- package/src/scripts/hooks/injection_budget.ts +13 -3
- package/src/scripts/hooks/py_json_dumps.ts +103 -0
- package/src/scripts/hooks/rtk_wrap_hook.ts +8 -3
- package/src/scripts/hooks/run_continuation_hook.ts +8 -5
- package/src/scripts/hooks/ship_diff_volume_hook.ts +81 -15
- package/src/scripts/hooks/source_first_gate_hook.ts +464 -0
- package/src/scripts/hooks/state_io.ts +870 -21
- package/src/scripts/hooks/stdin_failure_policy.ts +96 -0
- package/src/scripts/hooks/subagent_ledger_hook.ts +44 -15
- package/src/scripts/hooks/telemetry_flush_hook.ts +139 -0
- package/src/scripts/hooks/telemetry_self_repair.ts +128 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +22 -4
- package/src/scripts/hooks/turn_end_gate_hook.ts +81 -15
- package/src/scripts/injection_scan_hook.ts +137 -5
- package/src/scripts/install.ts +16 -11
- package/src/scripts/language_mirror_hook.ts +561 -25
- package/src/scripts/lint_framework_leakage_allowlist.json +2 -2
- package/src/scripts/lint_hook_manifest.ts +49 -0
- package/src/scripts/lint_plan_risk_register.ts +4 -3
- package/src/scripts/lint_provenance_vocabulary.ts +472 -4
- package/src/scripts/lint_skill_router_head.ts +4 -4
- package/src/scripts/mcp_server/tools.ts +2 -2
- package/src/scripts/new_roadmap.ts +136 -0
- package/src/scripts/pack_mcp_content.ts +20 -5
- package/src/scripts/release.ts +37 -38
- package/src/scripts/report_layer_overlap.ts +6 -0
- package/src/scripts/routing_doctor.ts +5 -1
- package/src/scripts/self_repair_hook.ts +37 -5
- package/src/scripts/session_register_hook.ts +11 -0
- package/src/scripts/skill_usage_collect.ts +11 -1
- package/src/scripts/skill_usage_report.ts +278 -8
- package/src/scripts/sync_pr_branch.ts +170 -20
- package/src/server/schemas/settings.ts +8 -0
- package/dist/cli-delegate/chunk-EJITJBJX.js +0 -172
- package/dist/cli-delegate/chunk-PZWRPRWP.js +0 -38
- package/dist/cli-delegate/{chunk-PPQO4NGR.js → chunk-6RJA2F5A.js} +3 -3
- package/dist/cli-delegate/{chunk-RYNADUFG.js → chunk-LWTYTX6F.js} +0 -0
- package/dist/cli-delegate/{chunk-FBKL6JWT.js → chunk-MMSGVZKV.js} +3 -3
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Content-equivalence gate for the self-hosted hook bundle.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS — measured, not hypothetical.
|
|
6
|
+
*
|
|
7
|
+
* `check_hook_bundle_freshness` compares **mtimes**: every bundled hook source
|
|
8
|
+
* must be older than `dist/hooks/dispatch.js`. That establishes ordering, not
|
|
9
|
+
* equivalence. An mtime-preserving edit, a `touch` on the bundle, a restore
|
|
10
|
+
* from an archive, or a filesystem with coarse timestamp resolution all make
|
|
11
|
+
* the inference false while the check stays green.
|
|
12
|
+
*
|
|
13
|
+
* On 2026-08-21 a live run edited `LEDGER_MAX_AGE_MS` in
|
|
14
|
+
* `block_unauthorized_git.ts`, did not rebuild, and the guard kept enforcing
|
|
15
|
+
* the old value; all three copies (source, repo bundle, global install) were
|
|
16
|
+
* inspected by hand before anyone noticed. **The freshness gate did not miss
|
|
17
|
+
* that one — it is pre-push and was never run.** Saying it "stayed green" would
|
|
18
|
+
* be a plausible mechanism standing in for the observed one, which is the
|
|
19
|
+
* failure this repository's own evidence discipline names.
|
|
20
|
+
*
|
|
21
|
+
* What the mtime check genuinely cannot see is narrower and is the reason this
|
|
22
|
+
* gate exists: the mtime check cannot see an edit that does not move the mtime — an
|
|
23
|
+
mtime-preserving write, a `touch` on the bundle, an archive or `cp -p` restore,
|
|
24
|
+
or a filesystem whose timestamp resolution is coarser than the edit interval.
|
|
25
|
+
Demonstrated on this tree rather than argued: an mtime-preserving edit to one
|
|
26
|
+
constant left the bundle at 1 139 302 bytes with an untouched mtime, the
|
|
27
|
+
freshness gate passed, and the digest differed.
|
|
28
|
+
*
|
|
29
|
+
* This gate answers the question directly — are the bytes that execute the
|
|
30
|
+
* bytes this source produces?
|
|
31
|
+
*
|
|
32
|
+
* WHAT IT CANNOT DO, STATED PLAINLY.
|
|
33
|
+
*
|
|
34
|
+
* `dist/hooks/` is **untracked** — `git ls-files dist/hooks/` returns zero.
|
|
35
|
+
* There is no committed artefact to compare against, so this gate can only
|
|
36
|
+
* compare the bundle **present on this machine** against a fresh rebuild from
|
|
37
|
+
* this checkout's sources. In CI a fresh checkout has no bundle at all, so
|
|
38
|
+
* this gate declares a loud no-op there and a green CI says nothing about the
|
|
39
|
+
* bundle a maintainer is actually running. That asymmetry is the finding, not
|
|
40
|
+
* a gap to paper over: the bundle is a local execution artefact and only a
|
|
41
|
+
* local gate can see it.
|
|
42
|
+
*
|
|
43
|
+
* The esbuild invocation is NOT duplicated here — it is read from
|
|
44
|
+
* `package.json`'s `build:hooks` script with only `--outfile=` rewritten, via
|
|
45
|
+
* the same `rewriteOutfile` helper `rebuild_hook_bundle` uses, so the flag set
|
|
46
|
+
* has exactly one home.
|
|
47
|
+
*
|
|
48
|
+
* DETERMINISM — measured, not assumed. Two consecutive rebuilds of an
|
|
49
|
+
* unchanged tree produced the identical sha256 (`616561fb…`, 2026-08-21), and
|
|
50
|
+
* a one-constant edit that left the output byte-count unchanged
|
|
51
|
+
* (1 139 302 bytes both times) still produced a different digest. So the
|
|
52
|
+
* comparison is byte-exact with no canonicalisation, and it is sensitive to
|
|
53
|
+
* the smallest semantic change. Had the rebuild NOT been reproducible, that
|
|
54
|
+
* would have been a release-integrity defect to fix rather than a reason to
|
|
55
|
+
* fall back to timestamps.
|
|
56
|
+
*
|
|
57
|
+
* Exit codes: 0 = equivalent, or no bundle to check · 1 = the executing bundle
|
|
58
|
+
* is not what this source produces · 2 = the rebuild itself failed.
|
|
59
|
+
*/
|
|
60
|
+
// ledger-exempt: single-artefact transaction — one rebuild compared against one
|
|
61
|
+
// bundle, yielding one aggregate verdict. The per-source accounting lives in
|
|
62
|
+
// check_hook_bundle_freshness, which carries the ledger.
|
|
63
|
+
import { spawnSync } from "node:child_process";
|
|
64
|
+
import * as crypto from "node:crypto";
|
|
65
|
+
import * as fs from "node:fs";
|
|
66
|
+
import * as path from "node:path";
|
|
67
|
+
import { fileURLToPath } from "node:url";
|
|
68
|
+
|
|
69
|
+
import { reportScanned } from "./_lib/scan_scope.js";
|
|
70
|
+
import { rewriteOutfile } from "./rebuild_hook_bundle.js";
|
|
71
|
+
|
|
72
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
73
|
+
const REPO_ROOT = path.resolve(HERE, "..", "..");
|
|
74
|
+
const LIVE_REL = path.join("dist", "hooks", "dispatch.js");
|
|
75
|
+
// Suffixed with the pid: two concurrent invocations in one checkout (the
|
|
76
|
+
// pre-push gate plus a manual run) otherwise share one path, the first
|
|
77
|
+
// `finally` deletes the other's output, and the survivor reports "rebuild
|
|
78
|
+
// failed" off a missing file — a false red on a pre-push gate, which is the
|
|
79
|
+
// failure mode the PATH injection below exists to avoid.
|
|
80
|
+
const PROBE_REL = path.join("dist", "hooks", `dispatch.content-check.${String(process.pid)}.js`);
|
|
81
|
+
|
|
82
|
+
/** sha256 of a file's bytes, hex. */
|
|
83
|
+
export function digestOf(file: string): string {
|
|
84
|
+
return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Read `build:hooks` out of package.json. Returns null when the script is
|
|
89
|
+
* absent — a renamed build script must fail loudly, never be guessed at.
|
|
90
|
+
*/
|
|
91
|
+
export function buildScript(repoRoot: string): string | null {
|
|
92
|
+
const pkgPath = path.join(repoRoot, "package.json");
|
|
93
|
+
if (!fs.existsSync(pkgPath)) return null;
|
|
94
|
+
const pkg: unknown = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
|
|
95
|
+
const scripts =
|
|
96
|
+
typeof pkg === "object" && pkg !== null ? (pkg as Record<string, unknown>)["scripts"] : null;
|
|
97
|
+
if (typeof scripts !== "object" || scripts === null) return null;
|
|
98
|
+
const s = (scripts as Record<string, unknown>)["build:hooks"];
|
|
99
|
+
return typeof s === "string" ? s : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function main(root: string = REPO_ROOT): number {
|
|
103
|
+
const live = path.join(root, LIVE_REL);
|
|
104
|
+
if (!fs.existsSync(live)) {
|
|
105
|
+
// Loud no-op, matching the sibling gates: a fresh checkout or CI has no
|
|
106
|
+
// bundle, and materialising one here would change what other gates see.
|
|
107
|
+
process.stdout.write(
|
|
108
|
+
`check_hook_bundle_content: no self-hosted ${LIVE_REL} — nothing executes locally, nothing to compare\n`,
|
|
109
|
+
);
|
|
110
|
+
reportScanned({
|
|
111
|
+
gate: "check_hook_bundle_content",
|
|
112
|
+
scanned: 0,
|
|
113
|
+
units: "bundle(s)",
|
|
114
|
+
roots: [LIVE_REL],
|
|
115
|
+
allowEmpty:
|
|
116
|
+
"OPTIONAL_INPUT: dist/hooks/ is UNTRACKED (`git ls-files dist/hooks/` returns zero), so a fresh " +
|
|
117
|
+
"checkout or a CI runner has no bundle by construction. An empty scope here is the " +
|
|
118
|
+
"correct reading of the environment, not a dead scan root — the artefact this gate " +
|
|
119
|
+
"guards is a local build output and exists only where the hooks actually run.",
|
|
120
|
+
});
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const script = buildScript(root);
|
|
125
|
+
if (script === null) {
|
|
126
|
+
process.stderr.write(
|
|
127
|
+
"check_hook_bundle_content: package.json has no `build:hooks` script — refusing to guess the flag set\n",
|
|
128
|
+
);
|
|
129
|
+
return 2;
|
|
130
|
+
}
|
|
131
|
+
const rewritten = rewriteOutfile(script, PROBE_REL);
|
|
132
|
+
if (rewritten === null) {
|
|
133
|
+
process.stderr.write(
|
|
134
|
+
`check_hook_bundle_content: \`build:hooks\` no longer writes ${LIVE_REL} — refusing to build to a guessed path\n`,
|
|
135
|
+
);
|
|
136
|
+
return 2;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const probe = path.join(root, PROBE_REL);
|
|
140
|
+
try {
|
|
141
|
+
// PATH is injected exactly as `rebuild_hook_bundle` does it, and for the
|
|
142
|
+
// same reason: `build:hooks` starts with a bare `esbuild`, so inheriting an
|
|
143
|
+
// ambient PATH without `node_modules/.bin` makes this gate report "rebuild
|
|
144
|
+
// failed" on a bundle that is in fact correct — a false red on a pre-push
|
|
145
|
+
// gate, which is how a pre-push gate teaches people to skip it.
|
|
146
|
+
const built = spawnSync("sh", ["-c", rewritten], {
|
|
147
|
+
cwd: root,
|
|
148
|
+
encoding: "utf8",
|
|
149
|
+
env: {
|
|
150
|
+
...process.env,
|
|
151
|
+
PATH: `${path.join(root, "node_modules", ".bin")}:${process.env["PATH"] ?? ""}`,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
if (built.status !== 0 || !fs.existsSync(probe)) {
|
|
155
|
+
process.stderr.write(
|
|
156
|
+
`check_hook_bundle_content: rebuild failed (exit ${String(built.status)})\n${built.stderr ?? ""}\n`,
|
|
157
|
+
);
|
|
158
|
+
return 2;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const liveDigest = digestOf(live);
|
|
162
|
+
const probeDigest = digestOf(probe);
|
|
163
|
+
if (liveDigest === probeDigest) {
|
|
164
|
+
process.stdout.write(
|
|
165
|
+
`✅ ${LIVE_REL} is byte-identical to a rebuild from this source (sha256 ${liveDigest.slice(0, 12)})\n`,
|
|
166
|
+
);
|
|
167
|
+
reportScanned({
|
|
168
|
+
gate: "check_hook_bundle_content",
|
|
169
|
+
scanned: 1,
|
|
170
|
+
units: "bundle(s)",
|
|
171
|
+
roots: [LIVE_REL],
|
|
172
|
+
});
|
|
173
|
+
return 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
process.stderr.write(
|
|
177
|
+
`❌ ${LIVE_REL} is NOT what this source produces.\n` +
|
|
178
|
+
` executing: sha256 ${liveDigest.slice(0, 12)} (${String(fs.statSync(live).size)} bytes)\n` +
|
|
179
|
+
` rebuilt: sha256 ${probeDigest.slice(0, 12)} (${String(fs.statSync(probe).size)} bytes)\n` +
|
|
180
|
+
` The mtime check cannot see this — it compares ordering, not bytes.\n` +
|
|
181
|
+
` Heal with: ./scripts-run src/scripts/rebuild_hook_bundle\n`,
|
|
182
|
+
);
|
|
183
|
+
reportScanned({
|
|
184
|
+
gate: "check_hook_bundle_content",
|
|
185
|
+
scanned: 1,
|
|
186
|
+
units: "bundle(s)",
|
|
187
|
+
roots: [LIVE_REL],
|
|
188
|
+
});
|
|
189
|
+
return 1;
|
|
190
|
+
} finally {
|
|
191
|
+
try {
|
|
192
|
+
fs.rmSync(probe, { force: true });
|
|
193
|
+
} catch {
|
|
194
|
+
// Best effort — a leftover probe file is untracked build output.
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Resolved on BOTH sides with `realpathSync`, mirroring `rebuild_hook_bundle`.
|
|
200
|
+
// A string compare against `import.meta.url` is false under a symlinked
|
|
201
|
+
// checkout, and under any repo path containing a space or a non-ASCII
|
|
202
|
+
// character, which `import.meta.url` percent-encodes and `path.resolve` does
|
|
203
|
+
// not. The failure is silent: `main()` never runs, the process exits 0, and
|
|
204
|
+
// the gate reports nothing — a green on an invariant it never evaluated,
|
|
205
|
+
// which is the exact class this gate exists to remove.
|
|
206
|
+
const invokedDirectly = ((): boolean => {
|
|
207
|
+
const entry = process.argv[1];
|
|
208
|
+
if (entry === undefined) return false;
|
|
209
|
+
try {
|
|
210
|
+
return fs.realpathSync(path.resolve(entry)) === fs.realpathSync(fileURLToPath(import.meta.url));
|
|
211
|
+
} catch {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
})();
|
|
215
|
+
|
|
216
|
+
if (invokedDirectly) {
|
|
217
|
+
process.exit(main());
|
|
218
|
+
}
|
|
219
|
+
|