@event4u/agent-config 9.14.0 → 9.16.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 +118 -99
- package/README.md +8 -0
- package/dist/agent-src/commands/agents/audit.md +7 -7
- package/dist/agent-src/commands/agents/optimize.md +1 -1
- package/dist/agent-src/commands/analyze/reference-repo.md +1 -1
- package/dist/agent-src/commands/chat-history.md +1 -0
- package/dist/agent-src/commands/context.md +1 -0
- package/dist/agent-src/commands/council.md +1 -1
- package/dist/agent-src/commands/ghostwriter.md +1 -1
- package/dist/agent-src/commands/memory.md +2 -1
- package/dist/agent-src/commands/module.md +1 -0
- package/dist/agent-src/commands/optimize/agents-dir.md +1 -1
- package/dist/agent-src/commands/optimize/deep.md +5 -2
- package/dist/agent-src/commands/optimize/skills.md +5 -5
- package/dist/agent-src/commands/override.md +1 -0
- package/dist/agent-src/commands/prediction-pool.md +4 -4
- package/dist/agent-src/commands/research/deep.md +1 -1
- package/dist/agent-src/commands/roadmap.md +2 -1
- package/dist/agent-src/commands/rule-compliance-audit.md +1 -1
- package/dist/agent-src/commands/tdd.md +1 -0
- package/dist/agent-src/commands/tests.md +1 -0
- package/dist/agent-src/commands/upstream-contribute.md +5 -5
- package/dist/agent-src/commands/video/from-script.md +1 -1
- package/dist/agent-src/commands/video/from-song.md +1 -1
- package/dist/agent-src/commands/video/scene.md +1 -1
- package/dist/agent-src/commands/video/stitch.md +1 -1
- package/dist/agent-src/commands/video/storyboard.md +1 -1
- package/dist/agent-src/commands/worktree/create.md +2 -1
- package/dist/agent-src/contexts/augment-infrastructure.md +1 -1
- package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +5 -5
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +3 -3
- package/dist/agent-src/contexts/contracts/emergency-triage-block.md +2 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +4 -3
- package/dist/agent-src/contexts/execution/subagent-routing.md +19 -0
- package/dist/agent-src/contexts/override-system.md +1 -1
- package/dist/agent-src/ghostwriter/fictional-fixture-v1.md +1 -1
- package/dist/agent-src/rules/augment-edit-discipline.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +2 -1
- package/dist/agent-src/rules/brand-consistency.md +1 -0
- package/dist/agent-src/rules/brand-source-of-truth.md +1 -0
- package/dist/agent-src/rules/code-comment-discipline.md +2 -0
- package/dist/agent-src/rules/communication-through-line.md +1 -0
- package/dist/agent-src/rules/content-quoting-floor.md +1 -0
- package/dist/agent-src/rules/cross-source-consistency.md +0 -1
- package/dist/agent-src/rules/downstream-changes.md +1 -0
- package/dist/agent-src/rules/external-code-graph-interop.md +1 -0
- package/dist/agent-src/rules/external-reference-deep-dive.md +1 -0
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +0 -1
- package/dist/agent-src/rules/icon-consistency.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/improve-before-implement.md +1 -1
- package/dist/agent-src/rules/invite-challenge.md +1 -0
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
- package/dist/agent-src/rules/markdown-safe-codeblocks.md +1 -0
- package/dist/agent-src/rules/media-governance-routing.md +4 -3
- package/dist/agent-src/rules/media-sync-ground-truth.md +1 -0
- package/dist/agent-src/rules/no-attribution-footers.md +1 -0
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +1 -0
- package/dist/agent-src/rules/no-pr-progress-comments.md +1 -0
- package/dist/agent-src/rules/onboarding-gate.md +1 -0
- package/dist/agent-src/rules/output-discipline.md +1 -0
- package/dist/agent-src/rules/prefer-enums-over-literals.md +1 -0
- package/dist/agent-src/rules/preservation-guard.md +1 -0
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-ci-steps-policy.md +1 -0
- package/dist/agent-src/rules/role-mode-adherence.md +1 -0
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +1 -0
- package/dist/agent-src/rules/session-canary.md +9 -2
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/source-of-truth.md +1 -0
- package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -0
- package/dist/agent-src/rules/think-before-action.md +1 -0
- package/dist/agent-src/rules/token-budget-discipline.md +1 -0
- package/dist/agent-src/rules/token-efficiency.md +1 -0
- package/dist/agent-src/rules/token-optimizer-maintenance.md +5 -5
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +2 -0
- package/dist/agent-src/rules/user-interaction.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/skills/adr-create/SKILL.md +1 -1
- package/dist/agent-src/skills/check-refs/SKILL.md +1 -1
- package/dist/agent-src/skills/competitive-positioning/SKILL.md +1 -1
- package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
- package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
- package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +1 -1
- package/dist/agent-src/skills/description-assist/SKILL.md +1 -1
- package/dist/agent-src/skills/github-ci/SKILL.md +1 -0
- package/dist/agent-src/skills/guideline-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/lint-skills/SKILL.md +1 -1
- package/dist/agent-src/skills/readme-reviewer/SKILL.md +1 -1
- package/dist/agent-src/skills/roadmap-management/SKILL.md +8 -1
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/skill-writing/SKILL.md +4 -4
- package/dist/agent-src/skills/token-optimizer/SKILL.md +4 -4
- package/dist/agent-src/skills/upstream-contribute/SKILL.md +6 -6
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +25 -0
- package/dist/agent-src/templates/AGENTS.md +1 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/command.md +1 -1
- package/dist/agent-src/templates/copilot-instructions.md +3 -3
- package/dist/agent-src/templates/rule.md +2 -2
- package/dist/agent-src/templates/scripts/work_engine/orchestration.ts +1 -1
- package/dist/agent-src/templates/skill-archive-note.md +5 -5
- package/dist/agent-src/templates/skill.md +1 -1
- package/dist/cli/agent-config.js +66 -19
- package/dist/cli/agent-config.js.map +1 -1
- package/dist/cli/main.js +9 -4
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/content.js +1 -1
- package/dist/cli/mcp/content.js.map +1 -1
- package/dist/cli/python/workspace_drive.js +2 -0
- package/dist/cli/python/workspace_drive.js.map +1 -1
- package/dist/cli/python/workspace_drive_health.js +2 -0
- package/dist/cli/python/workspace_drive_health.js.map +1 -1
- package/dist/cli/python/workspace_hosts.js +2 -0
- package/dist/cli/python/workspace_hosts.js.map +1 -1
- package/dist/cli/python/workspace_sessions.js +2 -0
- package/dist/cli/python/workspace_sessions.js.map +1 -1
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-A3HJ6NTI.js → chunk-63WSP6YZ.js} +2 -1
- package/dist/cli-delegate/{chunk-EJYIGZ3T.js → chunk-BKO2AZ7Z.js} +1 -1
- package/dist/cli-delegate/{chunk-GCVFLBP2.js → chunk-H574KOUH.js} +338 -494
- package/dist/cli-delegate/chunk-NXFWFAYV.js +339 -0
- package/dist/cli-delegate/{chunk-TEGJU2JX.js → chunk-ZXXJLL5K.js} +2 -2
- package/dist/cli-delegate/cmd_conformance.js +29 -23
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- package/dist/cli-delegate/cmd_export.js +4 -4
- package/dist/cli-delegate/cmd_preflight.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +4 -4
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +127 -95
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +729 -430
- package/dist/install/install.mjs +52 -11
- package/dist/install/rule_scope.js +18 -2
- package/dist/install/rule_scope.js.map +1 -1
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +518 -411
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/claude_settings_hooks.js +30 -5
- package/dist/scripts/_lib/claude_settings_hooks.js.map +1 -1
- package/dist/scripts/_lib/scoped_projection.js +223 -0
- package/dist/scripts/_lib/scoped_projection.js.map +1 -0
- package/dist/scripts/_lib/surface_tiers.js +125 -0
- package/dist/scripts/_lib/surface_tiers.js.map +1 -0
- package/dist/scripts/_lib/token_count.js +166 -0
- package/dist/scripts/_lib/token_count.js.map +1 -0
- package/dist/scripts/_lib/trigger_eval_floors.js +8 -0
- package/dist/scripts/_lib/trigger_eval_floors.js.map +1 -1
- package/dist/scripts/condense.js +139 -9
- package/dist/scripts/condense.js.map +1 -1
- package/dist/scripts/project_thin_rules.js +450 -0
- package/dist/scripts/project_thin_rules.js.map +1 -0
- package/dist/server/routes/workspace.js +3 -1
- package/dist/server/routes/workspace.js.map +1 -1
- package/dist/server/schemas/settings.js +9 -3
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/userMd/utils.js +1 -1
- package/dist/shared/userMd/utils.js.map +1 -1
- package/dist/ui/assets/index-DmR0mbk4.js +26 -0
- package/dist/ui/assets/index-DmR0mbk4.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/package.json +14 -14
- package/src/agent-src/templates/AGENTS.md +1 -1
- package/src/agent-src/templates/scripts/work_engine/orchestration.ts +1 -1
- package/src/config/agent-settings.template.yml +61 -11
- package/src/config/budget-routing.json +7 -0
- package/src/config/ci-local-parity.yml +8 -0
- package/src/config/discovery/unassigned-artefacts.yml +23 -25
- package/src/config/evaluator-budgets.json +35 -5
- package/src/config/gate-coverage.yml +147 -0
- package/src/config/gate-violation-baselines.json +25 -0
- package/src/install/rule_scope.ts +27 -2
- package/src/scripts/_cli/cmd_conformance.ts +13 -24
- package/src/scripts/_dispatch.bash +10 -0
- package/src/scripts/_lib/claude_settings_hooks.ts +30 -4
- package/src/scripts/_lib/gate_baseline.ts +213 -0
- package/src/scripts/_lib/scoped_projection.ts +50 -0
- package/src/scripts/_lib/tier_budget_routing.ts +360 -0
- package/src/scripts/_lib/tool_adapter_registry.ts +8 -1
- package/src/scripts/_lib/trigger_eval_floors.ts +9 -0
- package/src/scripts/_lib/trigger_routers.ts +17 -5
- package/src/scripts/adr/regenerate_index.ts +4 -3
- package/src/scripts/ai-video/lib/parse-blueprint.sh +1 -1
- package/src/scripts/ai_council/compile_corpus.ts +1 -1
- package/src/scripts/anchor_scoring_run.ts +1 -1
- package/src/scripts/audit_cloud_compatibility.ts +37 -2
- package/src/scripts/audit_initial_context.ts +53 -19
- package/src/scripts/audit_likelihood.ts +31 -2
- package/src/scripts/audit_user_type_axis.ts +58 -11
- package/src/scripts/bench_hook_latency.ts +172 -41
- package/src/scripts/bench_persona_placebo.ts +1 -1
- package/src/scripts/bench_quality_run.ts +1 -1
- package/src/scripts/build_mcp_catalog.ts +12 -1
- package/src/scripts/check_always_budget.ts +122 -11
- package/src/scripts/check_augment_description_cap.ts +24 -3
- package/src/scripts/check_ci_strict_superset.ts +150 -0
- package/src/scripts/check_cli_registry_budget_sync.ts +168 -0
- package/src/scripts/check_cluster_patterns.ts +100 -0
- package/src/scripts/check_consumer_scope_flip.ts +26 -4
- package/src/scripts/check_evaluator_budgets.ts +198 -19
- package/src/scripts/check_gate_coverage.ts +338 -2
- package/src/scripts/check_generator_output_coverage.ts +2 -1
- package/src/scripts/check_iron_law_prominence.ts +1 -1
- package/src/scripts/check_kernel_rule_bundle.ts +1 -1
- package/src/scripts/check_no_new_legacy_path.ts +167 -3
- package/src/scripts/check_pack_size.ts +18 -4
- package/src/scripts/check_portability.ts +37 -7
- package/src/scripts/check_references.ts +19 -3
- package/src/scripts/check_release_pr_shape.ts +13 -0
- package/src/scripts/check_token_quality_golden.ts +1 -1
- package/src/scripts/check_token_regression.ts +9 -2
- package/src/scripts/condense.ts +155 -12
- package/src/scripts/cost/budget.mjs +77 -2
- package/src/scripts/evaluator_umbrella.sh +34 -1
- package/src/scripts/generate_capability_matrix.ts +8 -0
- package/src/scripts/generate_router_coverage_from_matrix.ts +155 -0
- package/src/scripts/hook_manifest.yaml +17 -3
- package/src/scripts/hooks/block_config_weakening.ts +337 -0
- package/src/scripts/hooks/concern_registry.ts +2 -0
- package/src/scripts/hooks/probe_throttle.ts +75 -0
- package/src/scripts/install-hooks.sh +24 -2
- package/src/scripts/install.ts +2 -2
- package/src/scripts/lint_agents_md.ts +9 -3
- package/src/scripts/lint_archived_skills.ts +1 -1
- package/src/scripts/lint_artefact_frontmatter.ts +185 -37
- package/src/scripts/lint_command_routing.ts +21 -52
- package/src/scripts/lint_command_verbs.ts +47 -28
- package/src/scripts/lint_context_spine_usage.ts +38 -12
- package/src/scripts/lint_framework_leakage.ts +25 -6
- package/src/scripts/lint_handoffs.ts +49 -2
- package/src/scripts/lint_media_policy_linkage.ts +62 -30
- package/src/scripts/lint_namespace.ts +92 -7
- package/src/scripts/lint_new_skill_gate.ts +39 -31
- package/src/scripts/lint_originality_shingles.ts +7 -1
- package/src/scripts/lint_override_kernel_guard.ts +21 -3
- package/src/scripts/lint_pack_boundaries.ts +461 -91
- package/src/scripts/lint_pack_dependencies.ts +24 -57
- package/src/scripts/lint_persona_governance.ts +1 -1
- package/src/scripts/lint_role_experiences.ts +34 -5
- package/src/scripts/lint_trigger_precision.ts +142 -0
- package/src/scripts/mcp_server/consumer_tool_catalog.json +12 -201
- package/src/scripts/mcp_server/tools.ts +1 -1
- package/src/scripts/prepack-check.mjs +40 -1
- package/src/scripts/prepack_router_targets.d.mts +7 -0
- package/src/scripts/prepack_router_targets.mjs +93 -0
- package/src/scripts/print_required_checks.ts +72 -18
- package/src/scripts/profile_staleness_hook.ts +12 -0
- package/src/scripts/record_evaluator_measurements.mjs +105 -0
- package/src/scripts/recruit_preflight.sh +1 -1
- package/src/scripts/release.ts +214 -7
- package/src/scripts/router_target_paths.d.mts +4 -0
- package/src/scripts/router_target_paths.mjs +69 -0
- package/src/scripts/router_telemetry.ts +52 -1
- package/src/scripts/routing_doctor.ts +560 -0
- package/src/scripts/rule_trigger_eval.ts +403 -0
- package/src/scripts/schemas/rule.schema.json +5 -1
- package/src/scripts/session_canary_hook.ts +96 -5
- package/src/scripts/skill_linter.ts +9 -28
- package/src/scripts/smoke/skills.sh +1 -1
- package/src/scripts/sweep_dead_scan_roots.ts +356 -10
- package/src/scripts/trigger_coverage.ts +13 -2
- package/src/scripts/update_counts.ts +1 -1
- package/src/scripts/validate_telegraph_carveouts.ts +1 -1
- package/src/scripts/wrapper_freshness_hook.ts +14 -0
- package/src/server/schemas/settings.ts +19 -5
- package/src/shared/userMd/utils.ts +1 -1
- package/dist/cli-delegate/chunk-TJIAM5FW.js +0 -133
- package/dist/ui/assets/index-BpSQt5vm.js +0 -40
- package/dist/ui/assets/index-BpSQt5vm.js.map +0 -1
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
import * as fs from 'node:fs';
|
|
33
33
|
import * as path from 'node:path';
|
|
34
34
|
|
|
35
|
+
import { resolve_rule_pack_scope } from '../scripts/_lib/scoped_projection.js';
|
|
35
36
|
import { rule_in_scope } from './ruleInScope.js';
|
|
36
37
|
|
|
37
38
|
/**
|
|
@@ -67,19 +68,43 @@ function _list(value: unknown): readonly string[] | null {
|
|
|
67
68
|
* already-parsed settings object (same key contract as condense's
|
|
68
69
|
* `_read_projection_list` — absent / empty = legacy-all).
|
|
69
70
|
*/
|
|
70
|
-
export function ruleScopeFromSettings(
|
|
71
|
+
export function ruleScopeFromSettings(
|
|
72
|
+
settings: Record<string, unknown>,
|
|
73
|
+
packageRoot?: string,
|
|
74
|
+
): RuleScope {
|
|
71
75
|
const proj = settings['projection'];
|
|
72
76
|
if (typeof proj !== 'object' || proj === null || Array.isArray(proj)) {
|
|
73
77
|
return LEGACY_ALL;
|
|
74
78
|
}
|
|
75
79
|
const p = proj as Record<string, unknown>;
|
|
80
|
+
// `rule_packs: auto` derives the active-pack set — the SAME set the
|
|
81
|
+
// skill/command prune uses — so the rule axis cannot drift from the
|
|
82
|
+
// artefact axis. Resolving it needs the package root (packs.yml lives
|
|
83
|
+
// there); without one the sentinel degrades to the inactive axis rather
|
|
84
|
+
// than to an empty set, which would prune every pack-tagged rule.
|
|
85
|
+
const packs =
|
|
86
|
+
packageRoot === undefined
|
|
87
|
+
? _list(p['rule_packs'])
|
|
88
|
+
: resolve_rule_pack_scope(
|
|
89
|
+
p['rule_packs'],
|
|
90
|
+
packageRoot,
|
|
91
|
+
_list(_runtimeActivePacks(settings)) ?? [],
|
|
92
|
+
);
|
|
76
93
|
return {
|
|
77
94
|
workspaces: _list(p['rule_workspaces']),
|
|
78
|
-
packs
|
|
95
|
+
packs,
|
|
79
96
|
roles: _list(p['rule_roles']),
|
|
80
97
|
};
|
|
81
98
|
}
|
|
82
99
|
|
|
100
|
+
/** `runtime.active_packs` overlay from an already-parsed settings object. */
|
|
101
|
+
function _runtimeActivePacks(settings: Record<string, unknown>): unknown {
|
|
102
|
+
const rt = settings['runtime'];
|
|
103
|
+
return typeof rt === 'object' && rt !== null && !Array.isArray(rt)
|
|
104
|
+
? (rt as Record<string, unknown>)['active_packs']
|
|
105
|
+
: null;
|
|
106
|
+
}
|
|
107
|
+
|
|
83
108
|
/**
|
|
84
109
|
* Whether a rule FILE (path into the shipped `dist/agent-src/rules` tree)
|
|
85
110
|
* arrives in a consumer install under `scope`.
|
|
@@ -38,6 +38,7 @@ import { atomicAppendLine } from '../../install/atomic.js';
|
|
|
38
38
|
import { readRecentEntries } from '../../install/txlog.js';
|
|
39
39
|
import { detectToolPresence } from '../../install/detect.js';
|
|
40
40
|
import { resolvePackageRoot } from '../_lib/package_root.js';
|
|
41
|
+
import { routeTargetPathsPosix } from '../router_target_paths.mjs';
|
|
41
42
|
import {
|
|
42
43
|
_classify,
|
|
43
44
|
_collect_manifest_entries,
|
|
@@ -146,32 +147,20 @@ export function _check_txlog_clean(logPath: string = installLogPath()): Dict {
|
|
|
146
147
|
* Map one `routes_to` target (`<kind>:<id>`) to its candidate
|
|
147
148
|
* package-relative paths. The FIRST existing candidate wins.
|
|
148
149
|
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
150
|
+
* The kind→path table itself lives in `../router_target_paths.mjs` and is
|
|
151
|
+
* SHARED with `prepack-check.mjs` gate 4, which asserts every one of these
|
|
152
|
+
* targets lands inside the `files[]` whitelist at pack time. A second copy of
|
|
153
|
+
* the table would let the pack gate and this runtime resolver disagree about
|
|
154
|
+
* where a pointer lives — the packaging↔runtime gap Phase 4 of
|
|
155
|
+
* `road-to-gates-that-can-fail` closes. `contract:`'s two legitimate homes
|
|
156
|
+
* (public `docs/contracts/` pages and agent-facing
|
|
157
|
+
* `dist/agent-src/contexts/contracts/` contexts) are documented there.
|
|
153
158
|
*/
|
|
154
159
|
export function routeTargetPaths(target: string): string[] {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (!id) return [];
|
|
160
|
-
switch (kind) {
|
|
161
|
-
case 'skill':
|
|
162
|
-
return [path.join('dist', 'agent-src', 'skills', id, 'SKILL.md')];
|
|
163
|
-
case 'command':
|
|
164
|
-
return [path.join('dist', 'agent-src', 'commands', `${id}.md`)];
|
|
165
|
-
case 'guideline':
|
|
166
|
-
return [path.join('docs', 'guidelines', `${id}.md`)];
|
|
167
|
-
case 'contract':
|
|
168
|
-
return [
|
|
169
|
-
path.join('docs', 'contracts', `${id}.md`),
|
|
170
|
-
path.join('dist', 'agent-src', 'contexts', 'contracts', `${id}.md`),
|
|
171
|
-
];
|
|
172
|
-
default:
|
|
173
|
-
return [];
|
|
174
|
-
}
|
|
160
|
+
// POSIX templates → platform paths. `path.join` over the split segments
|
|
161
|
+
// reproduces the previous per-kind `path.join(...)` calls exactly,
|
|
162
|
+
// including a slash-bearing id such as `guideline:a/b`.
|
|
163
|
+
return routeTargetPathsPosix(target).map((rel) => path.join(...rel.split('/')));
|
|
175
164
|
}
|
|
176
165
|
|
|
177
166
|
export function _check_router_pointers(packageRoot: string = PACKAGE_ROOT): Dict {
|
|
@@ -203,6 +203,11 @@ Tier 2 — maintenance / internal (hooks, MCP, memory, telemetry):
|
|
|
203
203
|
last dispatcher feedback per concern, missing trampolines.
|
|
204
204
|
Wraps hooks:status. Read-only.
|
|
205
205
|
Flags: --format json|table, --strict (CI), --project-root <path>
|
|
206
|
+
routing:doctor Live routing diagnosis: per-gate ACTIVE/INACTIVE with the
|
|
207
|
+
concern's own reason (read-only probes), session_start chain,
|
|
208
|
+
router + projection freshness, host bridge status.
|
|
209
|
+
Flags: --platform <p>, --workspace <path>, --json, --strict,
|
|
210
|
+
--no-freshness
|
|
206
211
|
hooks:replay Replay a fixture through the universal dispatcher with
|
|
207
212
|
AGENT_CONFIG_REPLAY=1 (no writes under agents/runtime/state/).
|
|
208
213
|
Usage: hooks:replay --platform <name> --event <event>
|
|
@@ -755,6 +760,10 @@ cmd_hooks_doctor() {
|
|
|
755
760
|
exec_hook "src/scripts/hooks_doctor" "$@"
|
|
756
761
|
}
|
|
757
762
|
|
|
763
|
+
cmd_routing_doctor() {
|
|
764
|
+
exec_hook "src/scripts/routing_doctor" "$@"
|
|
765
|
+
}
|
|
766
|
+
|
|
758
767
|
cmd_hooks_replay() {
|
|
759
768
|
exec_hook "src/scripts/hooks/replay_hook" "$@"
|
|
760
769
|
}
|
|
@@ -1217,6 +1226,7 @@ main() {
|
|
|
1217
1226
|
dispatch:hook) cmd_dispatch_hook "$@" ;;
|
|
1218
1227
|
hooks:status) cmd_hooks_status "$@" ;;
|
|
1219
1228
|
hooks:doctor) cmd_hooks_doctor "$@" ;;
|
|
1229
|
+
routing:doctor) cmd_routing_doctor "$@" ;;
|
|
1220
1230
|
hooks:replay) cmd_hooks_replay "$@" ;;
|
|
1221
1231
|
reach:doctor) cmd_reach_doctor "$@" ;;
|
|
1222
1232
|
telemetry:record) cmd_telemetry_record "$@" ;;
|
|
@@ -108,19 +108,45 @@ export function build_claude_hook_matrix(manifest_path: string): ClaudeHookMatri
|
|
|
108
108
|
if (!concerns || (Array.isArray(concerns) && concerns.length === 0)) continue;
|
|
109
109
|
const native = ac_to_native[ac_event];
|
|
110
110
|
if (native === undefined) continue;
|
|
111
|
-
//
|
|
111
|
+
// Bundle fast path (road-to-hook-latency-repair Phase 2): invoke the
|
|
112
|
+
// precompiled dispatcher bundle directly — no bash shim, no CLI boot
|
|
113
|
+
// (measured ~450-500 ms CLI vs ~110 ms bundle per event on a 1-vCPU
|
|
114
|
+
// container; bench_hook_latency --via-cli pins it). Candidates:
|
|
115
|
+
// 1. project npm install (node_modules/@event4u/agent-config/…)
|
|
116
|
+
// 2. a source checkout — guarded by hook_manifest.yaml existing
|
|
117
|
+
// next to it, so an UNRELATED consumer file that happens to sit
|
|
118
|
+
// at dist/hooks/dispatch.js can never be executed as a hook
|
|
119
|
+
// (council 2026-08-03).
|
|
120
|
+
// `exec node` replaces the shell; stdin/exit codes flow through
|
|
121
|
+
// unchanged (a fail_closed concern still denies). Global installs
|
|
122
|
+
// have no project-relative bundle path and take the CLI fallback
|
|
123
|
+
// below, which boots the same bundle in-process via the launcher
|
|
124
|
+
// fast path (src/cli/agent-config.ts).
|
|
125
|
+
//
|
|
126
|
+
// Hook-resilience fallback (road-to-opt-subagent-harvest P1.4):
|
|
112
127
|
// local binary → PATH fallback → SILENT exit 0 when neither exists
|
|
113
128
|
// (a hook must never error-spam the loop on an uninstalled repo).
|
|
114
129
|
// The dispatcher's own exit code PROPAGATES when it runs — a
|
|
115
130
|
// fail_closed concern (e.g. block-no-verify) still denies; only the
|
|
116
131
|
// missing-binary case degrades open, which is the honest degrade
|
|
117
132
|
// (an absent dispatcher cannot evaluate anything).
|
|
133
|
+
// NOTE: the CLI fallback carries MANAGED_SIGNATURE — keep it, or
|
|
134
|
+
// previously installed managed entries orphan on refresh.
|
|
135
|
+
const dispatchArgs =
|
|
136
|
+
`--platform claude --event ${ac_event} --native-event ${native} ` +
|
|
137
|
+
`--project-dir "$CLAUDE_PROJECT_DIR" --min-version ${String(hook_spec)}`;
|
|
118
138
|
matrix[native] =
|
|
139
|
+
'B=""; ' +
|
|
140
|
+
'[ -f "$CLAUDE_PROJECT_DIR/node_modules/@event4u/agent-config/dist/hooks/dispatch.js" ] && ' +
|
|
141
|
+
'B="$CLAUDE_PROJECT_DIR/node_modules/@event4u/agent-config/dist/hooks/dispatch.js"; ' +
|
|
142
|
+
'[ -z "$B" ] && [ -f "$CLAUDE_PROJECT_DIR/dist/hooks/dispatch.js" ] && ' +
|
|
143
|
+
'[ -f "$CLAUDE_PROJECT_DIR/src/scripts/hook_manifest.yaml" ] && ' +
|
|
144
|
+
'B="$CLAUDE_PROJECT_DIR/dist/hooks/dispatch.js"; ' +
|
|
145
|
+
'if [ -n "$B" ] && command -v node >/dev/null 2>&1; then ' +
|
|
146
|
+
`exec node "$B" ${dispatchArgs}; fi; ` +
|
|
119
147
|
'BIN="$CLAUDE_PROJECT_DIR/agent-config"; [ -x "$BIN" ] || BIN=agent-config; ' +
|
|
120
148
|
'command -v "$BIN" >/dev/null 2>&1 || exit 0; ' +
|
|
121
|
-
`"$BIN" dispatch:hook
|
|
122
|
-
`--native-event ${native} --project-dir "$CLAUDE_PROJECT_DIR" ` +
|
|
123
|
-
`--min-version ${String(hook_spec)}`;
|
|
149
|
+
`"$BIN" dispatch:hook ${dispatchArgs}`;
|
|
124
150
|
}
|
|
125
151
|
return matrix;
|
|
126
152
|
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Violation ratchet for gates whose scan root was repaired.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS (council 2026-08-02, roadmap `road-to-gates-that-can-fail`
|
|
5
|
+
* blocker `dead-gate-finding-triage`): repairing a dead scan root does not
|
|
6
|
+
* create violations, it REVEALS violations that were invisible while the gate
|
|
7
|
+
* scanned nothing. Landing the repair with a hard fail would turn `main` red on
|
|
8
|
+
* debt the repairing change did not cause, blocking every unrelated merge
|
|
9
|
+
* behind unrelated copy-editing. Suppressing the findings would be the same
|
|
10
|
+
* green-on-nothing failure the repair exists to end.
|
|
11
|
+
*
|
|
12
|
+
* The adopted shape is a ratchet:
|
|
13
|
+
*
|
|
14
|
+
* The repair records the revealed count as a per-gate baseline in
|
|
15
|
+
* `src/config/gate-violation-baselines.json`. The gate fails only when its
|
|
16
|
+
* count rises ABOVE the baseline. Lowering a baseline is a normal commit;
|
|
17
|
+
* raising one is a defect.
|
|
18
|
+
*
|
|
19
|
+
* This is not an allowlist: no individual violation is named or excused, the
|
|
20
|
+
* number is committed, and every change to it shows as a delta in the diff.
|
|
21
|
+
*
|
|
22
|
+
* ## The anti-fossilization clause — why entries expire
|
|
23
|
+
*
|
|
24
|
+
* The council's own strongest objection to the ratchet was that a baseline
|
|
25
|
+
* which never moves hardens from "debt" into "configuration", at which point it
|
|
26
|
+
* IS suppression with extra steps. So an entry is not permanent: it carries the
|
|
27
|
+
* date its repair landed, and after {@link STALE_AFTER_DAYS} days a baseline
|
|
28
|
+
* that has not been lowered fails the gate with an escalation message. Clearing
|
|
29
|
+
* it means one of three visible acts — fix the findings, lower the count, or
|
|
30
|
+
* write a `reaffirmed` block whose non-empty reason lands in the diff.
|
|
31
|
+
*
|
|
32
|
+
* Dates are plain `YYYY-MM-DD`; ages are whole days in UTC, so the verdict does
|
|
33
|
+
* not depend on the machine's timezone.
|
|
34
|
+
*/
|
|
35
|
+
import * as fs from 'node:fs';
|
|
36
|
+
import * as path from 'node:path';
|
|
37
|
+
|
|
38
|
+
/** Days a baseline may sit unchanged before it must be fixed or reaffirmed. */
|
|
39
|
+
export const STALE_AFTER_DAYS = 56;
|
|
40
|
+
|
|
41
|
+
/** Repo-relative location of the committed baseline file. */
|
|
42
|
+
export const BASELINE_REL = 'src/config/gate-violation-baselines.json';
|
|
43
|
+
|
|
44
|
+
/** A single gate's recorded debt. */
|
|
45
|
+
export interface BaselineEntry {
|
|
46
|
+
/** Violation count revealed when the scan root was repaired. */
|
|
47
|
+
count: number;
|
|
48
|
+
/** `YYYY-MM-DD` the repair (or the last lowering) landed. */
|
|
49
|
+
landed: string;
|
|
50
|
+
/** What the counted violations are, so a reader need not re-derive them. */
|
|
51
|
+
note: string;
|
|
52
|
+
/** Optional clock reset — requires a reason, and the reason lands in the diff. */
|
|
53
|
+
reaffirmed?: { date: string; reason: string };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface BaselineFile {
|
|
57
|
+
/** Human-facing pointer back to the rule that governs this file. */
|
|
58
|
+
$comment?: string;
|
|
59
|
+
gates: Record<string, BaselineEntry>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type BaselineStatus =
|
|
63
|
+
/** Count is at or under the baseline and the entry is still fresh. */
|
|
64
|
+
| 'within'
|
|
65
|
+
/** Count is below the baseline — the ratchet should be tightened. */
|
|
66
|
+
| 'improved'
|
|
67
|
+
/** Count rose above the baseline. This is the defect the ratchet catches. */
|
|
68
|
+
| 'regressed'
|
|
69
|
+
/** Count is within, but the entry has sat unchanged past the expiry. */
|
|
70
|
+
| 'stale'
|
|
71
|
+
/** No baseline recorded — zero violations is the only passing state. */
|
|
72
|
+
| 'unbaselined';
|
|
73
|
+
|
|
74
|
+
export interface BaselineVerdict {
|
|
75
|
+
status: BaselineStatus;
|
|
76
|
+
/** True when the gate may exit 0. */
|
|
77
|
+
ok: boolean;
|
|
78
|
+
/** The effective baseline (0 when no entry exists). */
|
|
79
|
+
baseline: number;
|
|
80
|
+
actual: number;
|
|
81
|
+
/** Whole days since `landed` (or since `reaffirmed.date` when present). */
|
|
82
|
+
ageDays: number | null;
|
|
83
|
+
/** One line, ready for stdout (ok) or stderr (not ok). */
|
|
84
|
+
message: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function parseIsoDate(value: string): number | null {
|
|
88
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const ms = Date.parse(`${value}T00:00:00Z`);
|
|
92
|
+
return Number.isNaN(ms) ? null : ms;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function wholeDaysBetween(fromMs: number, toMs: number): number {
|
|
96
|
+
return Math.floor((toMs - fromMs) / 86_400_000);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Read the committed baseline file. A missing file is an empty ratchet, not an error. */
|
|
100
|
+
export function loadBaselines(repoRoot: string, relPath: string = BASELINE_REL): BaselineFile {
|
|
101
|
+
const abs = path.join(repoRoot, relPath);
|
|
102
|
+
let raw: string;
|
|
103
|
+
try {
|
|
104
|
+
raw = fs.readFileSync(abs, 'utf8');
|
|
105
|
+
} catch {
|
|
106
|
+
return { gates: {} };
|
|
107
|
+
}
|
|
108
|
+
const parsed = JSON.parse(raw) as Partial<BaselineFile>;
|
|
109
|
+
const out: BaselineFile = { gates: parsed.gates ?? {} };
|
|
110
|
+
if (parsed.$comment !== undefined) out.$comment = parsed.$comment;
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface RatchetOptions {
|
|
115
|
+
/** Gate name — the key in the baseline file. */
|
|
116
|
+
gate: string;
|
|
117
|
+
/** How many violations this run found. */
|
|
118
|
+
actual: number;
|
|
119
|
+
/** Absolute repo root. */
|
|
120
|
+
repoRoot: string;
|
|
121
|
+
/** Override the baseline file location (tests). */
|
|
122
|
+
baselineRel?: string;
|
|
123
|
+
/** Override "now" as `YYYY-MM-DD` (tests); defaults to the current UTC date. */
|
|
124
|
+
today?: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Judge a violation count against its recorded baseline.
|
|
129
|
+
*
|
|
130
|
+
* Callers keep their own reporting and exit codes — this returns a verdict, it
|
|
131
|
+
* does not print or exit. A gate with no entry behaves exactly as it did before
|
|
132
|
+
* the ratchet existed: any violation fails.
|
|
133
|
+
*/
|
|
134
|
+
export function checkRatchet(opts: RatchetOptions): BaselineVerdict {
|
|
135
|
+
const { gate, actual } = opts;
|
|
136
|
+
const file = loadBaselines(opts.repoRoot, opts.baselineRel ?? BASELINE_REL);
|
|
137
|
+
const entry = file.gates[gate];
|
|
138
|
+
|
|
139
|
+
if (entry === undefined) {
|
|
140
|
+
return {
|
|
141
|
+
status: 'unbaselined',
|
|
142
|
+
ok: actual === 0,
|
|
143
|
+
baseline: 0,
|
|
144
|
+
actual,
|
|
145
|
+
ageDays: null,
|
|
146
|
+
message:
|
|
147
|
+
actual === 0
|
|
148
|
+
? `${gate}: 0 violation(s), no baseline needed.`
|
|
149
|
+
: `${gate}: ${actual} violation(s) and no recorded baseline — fix them, or ` +
|
|
150
|
+
`record the count in ${BASELINE_REL} if this is a scan-root repair ` +
|
|
151
|
+
'revealing pre-existing debt.',
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const anchor = entry.reaffirmed?.date ?? entry.landed;
|
|
156
|
+
const anchorMs = parseIsoDate(anchor);
|
|
157
|
+
const todayMs = parseIsoDate(opts.today ?? new Date().toISOString().slice(0, 10));
|
|
158
|
+
const ageDays = anchorMs !== null && todayMs !== null ? wholeDaysBetween(anchorMs, todayMs) : null;
|
|
159
|
+
|
|
160
|
+
if (actual > entry.count) {
|
|
161
|
+
return {
|
|
162
|
+
status: 'regressed',
|
|
163
|
+
ok: false,
|
|
164
|
+
baseline: entry.count,
|
|
165
|
+
actual,
|
|
166
|
+
ageDays,
|
|
167
|
+
message:
|
|
168
|
+
`${gate}: ${actual} violation(s) against a baseline of ${entry.count} — ` +
|
|
169
|
+
`${actual - entry.count} new. A ratchet only turns one way: fix the new ` +
|
|
170
|
+
`violation(s). Raising the baseline in ${BASELINE_REL} is a defect, not a fix.`,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (actual < entry.count) {
|
|
175
|
+
return {
|
|
176
|
+
status: 'improved',
|
|
177
|
+
ok: true,
|
|
178
|
+
baseline: entry.count,
|
|
179
|
+
actual,
|
|
180
|
+
ageDays,
|
|
181
|
+
message:
|
|
182
|
+
`${gate}: ${actual} violation(s), baseline ${entry.count} — ratchet is loose. ` +
|
|
183
|
+
`Lower it to ${actual} in ${BASELINE_REL} (and refresh \`landed\`) so the ` +
|
|
184
|
+
'gain cannot be silently given back.',
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (ageDays !== null && ageDays > STALE_AFTER_DAYS) {
|
|
189
|
+
return {
|
|
190
|
+
status: 'stale',
|
|
191
|
+
ok: false,
|
|
192
|
+
baseline: entry.count,
|
|
193
|
+
actual,
|
|
194
|
+
ageDays,
|
|
195
|
+
message:
|
|
196
|
+
`${gate}: baseline of ${entry.count} has not moved in ${ageDays} days ` +
|
|
197
|
+
`(limit ${STALE_AFTER_DAYS}). A baseline that never drops is suppression with ` +
|
|
198
|
+
'extra steps. Fix the findings, lower the count, or add a `reaffirmed` block ' +
|
|
199
|
+
`with a reason in ${BASELINE_REL}. Debt: ${entry.note}`,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
status: 'within',
|
|
205
|
+
ok: true,
|
|
206
|
+
baseline: entry.count,
|
|
207
|
+
actual,
|
|
208
|
+
ageDays,
|
|
209
|
+
message:
|
|
210
|
+
`${gate}: ${actual} violation(s) at baseline${ageDays === null ? '' : `, age ${ageDays}d`} ` +
|
|
211
|
+
`— known debt, not new breakage. ${entry.note}`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
@@ -160,6 +160,56 @@ export function is_pruned_under_scoped(md_path: string, active_ids: ReadonlySet<
|
|
|
160
160
|
return true;
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Sentinel value for `projection.rule_packs`: derive the pack scope from the
|
|
165
|
+
* active-pack set instead of listing ids by hand.
|
|
166
|
+
*
|
|
167
|
+
* The rule layer's pack axis was wired end-to-end but shipped inactive
|
|
168
|
+
* (`rule_packs: []`), so a rule whose own body says "auto-activates when
|
|
169
|
+
* pack-X is installed" projected into installs that do not have pack-X,
|
|
170
|
+
* where it guards nothing. Listing the active ids by hand is not a fix — the
|
|
171
|
+
* list would need re-typing whenever a pack is added, which is the
|
|
172
|
+
* two-counting-paths failure this module exists to prevent. `auto` reuses
|
|
173
|
+
* `compute_active_pack_ids`, the SAME set the skill/command prune uses, so
|
|
174
|
+
* the rule axis cannot drift from the artefact axis.
|
|
175
|
+
*/
|
|
176
|
+
export const RULE_PACKS_AUTO = 'auto';
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Resolve a raw `projection.rule_packs` setting into the pack scope
|
|
180
|
+
* `rule_in_scope` consumes.
|
|
181
|
+
*
|
|
182
|
+
* - `'auto'` (scalar or single-element list) → the derived active-pack set.
|
|
183
|
+
* - a non-empty list → that list, verbatim.
|
|
184
|
+
* - anything else (absent, `[]`, wrong type) → `null`, axis inactive.
|
|
185
|
+
*
|
|
186
|
+
* A derivation failure (unreadable / malformed `packs.yml`) returns `null`,
|
|
187
|
+
* not an empty set: an empty set would prune every pack-tagged rule, the
|
|
188
|
+
* opposite of the fail-safe contract `rule_in_scope` documents.
|
|
189
|
+
*/
|
|
190
|
+
export function resolve_rule_pack_scope(
|
|
191
|
+
raw: unknown,
|
|
192
|
+
package_root: string,
|
|
193
|
+
runtime_active_packs: readonly string[] = [],
|
|
194
|
+
): string[] | null {
|
|
195
|
+
const is_auto =
|
|
196
|
+
raw === RULE_PACKS_AUTO ||
|
|
197
|
+
(Array.isArray(raw) && raw.length === 1 && raw[0] === RULE_PACKS_AUTO);
|
|
198
|
+
if (is_auto) {
|
|
199
|
+
try {
|
|
200
|
+
return [
|
|
201
|
+
...compute_active_pack_ids(load_packs_registry(package_root), runtime_active_packs),
|
|
202
|
+
].sort();
|
|
203
|
+
} catch {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (Array.isArray(raw) && raw.length > 0) {
|
|
208
|
+
return raw.map((v) => String(v));
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
|
|
163
213
|
export interface ScopedProjectionStats {
|
|
164
214
|
/** Skills a default `projection.mode: scoped` install deploys. */
|
|
165
215
|
projected: number;
|