@event4u/agent-config 16.2.0 → 16.3.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +89 -237
- package/README.md +14 -12
- package/dist/agent-src/commands/analyze/inbox.md +1 -1
- package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
- package/dist/agent-src/commands/bug/fix.md +17 -2
- package/dist/agent-src/commands/feature/plan.md +1 -1
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +1 -1
- package/dist/agent-src/commands/implement-ticket.md +1 -1
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/roadmap/create.md +1 -1
- package/dist/agent-src/commands/roadmap/materialize.md +1 -1
- package/dist/agent-src/commands/roadmap/process-full.md +4 -4
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
- package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
- package/dist/agent-src/commands/roadmap.md +18 -4
- package/dist/agent-src/commands/tests/create.md +17 -3
- package/dist/agent-src/commands/tests/execute.md +22 -5
- package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
- package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
- package/dist/agent-src/rules/active-remediation.md +1 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -0
- package/dist/agent-src/rules/broken-access-control.md +1 -0
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
- package/dist/agent-src/rules/context-hygiene.md +1 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
- package/dist/agent-src/rules/design-fidelity.md +13 -16
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
- package/dist/agent-src/rules/domain-safety-pii.md +1 -0
- package/dist/agent-src/rules/domain-safety-retention.md +1 -0
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
- package/dist/agent-src/rules/finance-safety-floor.md +1 -0
- package/dist/agent-src/rules/git-history-discipline.md +1 -0
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
- package/dist/agent-src/rules/legal-safety-floor.md +3 -2
- 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/media-governance-routing.md +14 -17
- package/dist/agent-src/rules/persona-governance.md +2 -2
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
- package/dist/agent-src/rules/question-not-instruction.md +1 -0
- package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -0
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
- package/dist/agent-src/rules/session-canary.md +8 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -0
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
- package/dist/agent-src/rules/tool-safety.md +1 -0
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/dist/agent-src/scripts/deferral_carry.ts +339 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
- package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
- package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
- package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
- package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
- package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
- package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
- package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +2 -2
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/cli/registry.js +1 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +12 -1
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
- package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- package/dist/cli-delegate/{chunk-IGD6ERX6.js → chunk-JQVYKIZA.js} +10 -0
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
- package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
- package/dist/cli-delegate/{chunk-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
- package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
- package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-NQ7WT43P.js} +1186 -244
- package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
- package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
- package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
- package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
- package/dist/cli-delegate/{chunk-7XGBX6ZH.js → chunk-RQNNW7IF.js} +1314 -560
- package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-S4UMZNES.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
- package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-TRI6DQZ6.js} +2781 -340
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
- package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
- package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +1167 -234
- package/dist/cli-delegate/cmd_doctor.js +13 -6
- package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
- package/dist/cli-delegate/cmd_explain.js +5 -5
- package/dist/cli-delegate/cmd_export.js +11 -8
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_handoff.js +10 -7
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +3 -3
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +11 -8
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +8 -6
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +4 -3
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +11 -8
- package/dist/cli-delegate/cmd_uninstall.js +11 -8
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +3 -2
- package/dist/cli-delegate/cmd_validate.js +11 -8
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_execute.js +2 -2
- package/dist/cli-delegate/roadmap_gates.js +5 -5
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +127 -75
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +7 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +6 -4
- package/dist/hooks/dispatch.js +5357 -6656
- package/dist/hooks/dispatch.sha256 +1 -1
- package/dist/install/claudePathsPlan.js +47 -6
- package/dist/install/claudeRuleRewrite.js +7 -0
- package/dist/install/emit_host_rules_cli.js +39 -36
- package/dist/install/globalRuleScope.js +87 -0
- package/dist/install/host_rule_ownership.js +160 -0
- package/dist/install/install.mjs +2080 -1024
- package/dist/install/installThinLayer.js +261 -0
- package/dist/install/installedRuleLinks.js +176 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +31965 -27154
- package/dist/scripts/_lib/agent_settings.js +11 -0
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/installed_layer.js +378 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/rule_consequence_class.js +45 -0
- package/dist/scripts/_lib/rule_injection.js +67 -10
- package/dist/scripts/_lib/rule_law_section.js +122 -0
- package/dist/scripts/_lib/thin_rules.js +458 -0
- package/dist/scripts/_lib/windsurf_render.js +60 -0
- package/dist/scripts/condense.js +14 -26
- package/dist/scripts/project_thin_rules.js +14 -294
- package/dist/server/schemas/settings.js +6 -0
- package/dist/shared/skillRanking.js +74 -13
- package/docs/contracts/settings-classes.md +7 -5
- package/package.json +1 -1
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
- package/src/agent-src/scripts/deferral_carry.ts +339 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/config/agent-settings.template.yml +62 -22
- package/src/config/continuity-surface.json +7 -0
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +96 -3
- package/src/config/gate-violation-baselines.json +17 -9
- package/src/config/hook-bundle-budget.json +25 -0
- package/src/config/hook-token-budget.json +6 -1
- package/src/config/host-instruction-limits.json +33 -0
- package/src/config/routing-coverage-seed.json +24 -3
- package/src/config/rule-activation-census.json +7 -3
- package/src/config/rule-consequence-class.json +161 -0
- package/src/config/rule-law-ceilings.json +99 -0
- package/src/install/claudePathsPlan.ts +46 -4
- package/src/install/claudeRuleRewrite.ts +10 -1
- package/src/install/emit_host_rules_cli.ts +43 -34
- package/src/install/globalRuleScope.ts +109 -0
- package/src/install/host_rule_ownership.ts +170 -0
- package/src/install/installThinLayer.ts +312 -0
- package/src/install/installedRuleLinks.ts +220 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_doctor.ts +23 -71
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
- package/src/scripts/_dispatch.bash +16 -2
- package/src/scripts/_lib/agent_settings.ts +11 -0
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/estate_offsets.ts +241 -0
- package/src/scripts/_lib/exemption_shape.ts +143 -0
- package/src/scripts/_lib/fnv.ts +23 -0
- package/src/scripts/_lib/foreign_scan.ts +106 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
- package/src/scripts/_lib/graph_feeder_record.ts +214 -0
- package/src/scripts/_lib/hook_settings.ts +73 -0
- package/src/scripts/_lib/host_capability.ts +40 -19
- package/src/scripts/_lib/host_hook_merge.ts +165 -0
- package/src/scripts/_lib/installed_layer.ts +538 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/release_migration_gate.ts +19 -3
- package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
- package/src/scripts/_lib/review_coverage.ts +134 -0
- package/src/scripts/_lib/rule_consequence_class.ts +71 -0
- package/src/scripts/_lib/rule_injection.ts +130 -10
- package/src/scripts/_lib/rule_law_section.ts +147 -0
- package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/thin_rules.ts +540 -0
- package/src/scripts/_lib/touched_file_quality.ts +434 -0
- package/src/scripts/_lib/turn_end_refusals.ts +77 -2
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/ai_council/cli_call_budget.ts +13 -5
- package/src/scripts/ai_council/clients.ts +26 -57
- package/src/scripts/ai_council/config.ts +1 -1
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/before_complete_hook.ts +243 -12
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/check_enforcement_matrix.ts +377 -20
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_finding_dispositions.ts +116 -4
- package/src/scripts/check_hook_bundle_composition.ts +370 -0
- package/src/scripts/check_kernel_edit_ratified.ts +49 -11
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_standing_rule_delivery.ts +33 -13
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/code_graph/detect.ts +127 -7
- package/src/scripts/code_graph/foreign.ts +194 -0
- package/src/scripts/code_graph/query.ts +217 -4
- package/src/scripts/code_graph/types.ts +26 -2
- package/src/scripts/code_graph/validate.ts +3 -1
- package/src/scripts/code_graph/verbs.ts +103 -0
- package/src/scripts/compile_hook_manifest.ts +33 -1
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/generate_host_cost_table.ts +1 -1
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +150 -9
- package/src/scripts/hooks/block_config_weakening.ts +67 -2
- package/src/scripts/hooks/block_plumbing_writes.ts +29 -1
- package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
- package/src/scripts/hooks/concern_failure_policy.ts +280 -0
- package/src/scripts/hooks/dispatch_hook.ts +52 -52
- package/src/scripts/hooks/exit_codes.ts +2 -1
- package/src/scripts/hooks/host_lowering.json +1 -1
- package/src/scripts/hooks/host_lowering.ts +19 -1
- package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
- package/src/scripts/hooks/payload_stub.ts +10 -1
- package/src/scripts/hooks/rule_inject_hook.ts +757 -63
- package/src/scripts/hooks/table_fingerprint.ts +21 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +64 -8
- package/src/scripts/hooks/turn_end_gate_hook.ts +84 -0
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install.ts +72 -185
- package/src/scripts/installed_layer_report.ts +103 -0
- package/src/scripts/language_mirror_hook.ts +15 -6
- package/src/scripts/learning_sidecar.ts +119 -8
- package/src/scripts/lint_hook_manifest.ts +53 -0
- package/src/scripts/lint_major_migration_sections.ts +156 -26
- package/src/scripts/lint_pack_boundaries.ts +63 -5
- package/src/scripts/lint_rule_law_section.ts +517 -0
- package/src/scripts/lint_workflow_security.ts +161 -5
- package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
- package/src/scripts/mcp_server/graph_tools.ts +72 -3
- package/src/scripts/measure_routing_signal.ts +54 -16
- package/src/scripts/measure_skill_ranker_baseline.ts +216 -8
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/model_rule_injection.ts +52 -5
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +157 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_obligation_mechanism.ts +230 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_ranker_confusion.ts +442 -0
- package/src/scripts/report_standing_payload_by_host.ts +188 -15
- package/src/scripts/report_verification_record_coverage.ts +306 -0
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/review-findings.schema.json +3 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/self_review_gate.ts +62 -7
- package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/trigger_eval_grandfather.json +0 -5
- package/src/server/schemas/settings.ts +10 -0
- package/src/shared/skillRanking.ts +117 -11
- package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who put a ranked skill on disk, and whether its body has been looked at.
|
|
3
|
+
*
|
|
4
|
+
* SPLIT OUT OF `neighbour_census.ts` FOR ONE CONCRETE REASON. The ranker
|
|
5
|
+
* (`skill_tools/score_skill_relevance`) needs these primitives, and the ranker
|
|
6
|
+
* runs inside the shared hook bundle on `user_prompt_submit`. The census module
|
|
7
|
+
* reaches the host-hook merger, the secret detector and the install-ownership
|
|
8
|
+
* reader; every byte of that would be inlined into one bundle that every concern
|
|
9
|
+
* loads on every dispatch, under a ceiling `check_hook_bundle_composition` holds.
|
|
10
|
+
* So the primitives live here, importing only the manifest reader, and the census
|
|
11
|
+
* re-exports them — one definition, two call sites, no second module graph.
|
|
12
|
+
*
|
|
13
|
+
* ORIGIN IS READ FROM A CLAIM RECORD, NEVER INFERRED FROM A ROOT. The temptation
|
|
14
|
+
* is to call `~/.claude/skills` foreign and the workspace ours. That is wrong in
|
|
15
|
+
* both directions: `agent-config install` writes this package's own skills into
|
|
16
|
+
* the host-global root, and a consumer's hand-written skills sit in the project
|
|
17
|
+
* root. The one artifact that records what this package actually wrote is the
|
|
18
|
+
* installed-tools manifest, so the manifest is the authority and the root is only
|
|
19
|
+
* a tie-break between the two NON-package labels.
|
|
20
|
+
*/
|
|
21
|
+
import { createHash } from 'node:crypto';
|
|
22
|
+
import * as fs from 'node:fs';
|
|
23
|
+
import * as os from 'node:os';
|
|
24
|
+
import * as path from 'node:path';
|
|
25
|
+
|
|
26
|
+
import { parse as parseYaml } from 'yaml';
|
|
27
|
+
|
|
28
|
+
import { manifest_path } from './installed_tools.js';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Where a RANKED skill came from — a question about AUTHORSHIP.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately not the census's `origin` id segment, which is WHERE a file was
|
|
34
|
+
* found (`project`, `user`, `cursor`, …). Location does not answer authorship in
|
|
35
|
+
* either direction, which is the whole reason this type exists beside that one.
|
|
36
|
+
*
|
|
37
|
+
* `home` is spelled `home` rather than the census's `user` because this value is
|
|
38
|
+
* printed on a ROUTE LINE beside a skill name, where it has to read as a place a
|
|
39
|
+
* reader can go and look.
|
|
40
|
+
*/
|
|
41
|
+
export type SkillOrigin = 'package' | 'project' | 'home';
|
|
42
|
+
|
|
43
|
+
/** One `compat` label per neighbour skill. Order decided in {@link classifyCompat}. */
|
|
44
|
+
export type Compat = 'shadowed' | 'overlapping' | 'unscanned' | 'unclassified';
|
|
45
|
+
|
|
46
|
+
/** The authored source tree, relative to a maintainer checkout's root. */
|
|
47
|
+
export const AUTHORED_SKILL_ROOT = path.join('src', 'skills');
|
|
48
|
+
|
|
49
|
+
/** Where the scan verdicts the ranker reads are written, relative to the root. */
|
|
50
|
+
export const SCAN_CACHE_RELATIVE = path.join('agents', 'reports', 'neighbour-scan.json');
|
|
51
|
+
|
|
52
|
+
/** Default scan-cache path for a project root. */
|
|
53
|
+
export function scanCachePath(projectRoot: string): string {
|
|
54
|
+
return path.join(projectRoot, SCAN_CACHE_RELATIVE);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* What a route line prints: bare for ours, `origin:name` for a neighbour.
|
|
59
|
+
*
|
|
60
|
+
* One function, so the ranker, the census and every report agree on the
|
|
61
|
+
* spelling. Two spellings of one name is how a collision stops being visible,
|
|
62
|
+
* which is the defect this whole step exists to close.
|
|
63
|
+
*/
|
|
64
|
+
export function qualifiedSkillName(name: string, origin: SkillOrigin): string {
|
|
65
|
+
return origin === 'package' ? name : `${origin}:${name}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Split a qualified name back apart. A bare name resolves to `package`. */
|
|
69
|
+
export function splitQualifiedName(qualified: string): { origin: SkillOrigin; name: string } {
|
|
70
|
+
const m = /^(project|home):([\s\S]*)$/.exec(qualified);
|
|
71
|
+
if (m) return { origin: m[1] as SkillOrigin, name: m[2] as string };
|
|
72
|
+
return { origin: 'package', name: qualified };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Every absolute path this package's installed-tools manifest claims, or `null`
|
|
77
|
+
* when there is no manifest to claim anything.
|
|
78
|
+
*
|
|
79
|
+
* `null` and an empty set are different answers and callers must keep them
|
|
80
|
+
* apart. An empty set means the manifest was read and claims nothing; `null`
|
|
81
|
+
* means nothing recorded a claim at all, which is a tree that has never run an
|
|
82
|
+
* install — this repository, for one.
|
|
83
|
+
*
|
|
84
|
+
* WHY THIS PARSES THE MANIFEST ITSELF, which is a thing to justify rather than
|
|
85
|
+
* do quietly. Three readers of this file already exist and none answers this
|
|
86
|
+
* question at a cost this path can pay. `installed_tools.read_manifest` drops
|
|
87
|
+
* the nested `tools[].files[]` rows by design — its own header says so, and
|
|
88
|
+
* those rows are the entire input here. `install_drift.collect_drift` and
|
|
89
|
+
* `recordedOwnership.readRecordedHashes` both parse the YAML directly FOR THAT
|
|
90
|
+
* REASON, so parsing it directly is the established answer rather than a new
|
|
91
|
+
* idea; what is new is the fourth question — the PATHS only, with no sha, no
|
|
92
|
+
* tool grouping and no hash map. `readRecordedHashes` would have answered it
|
|
93
|
+
* and was measured costing 1,706 bytes of the shared hook bundle, which is the
|
|
94
|
+
* budget this whole module was split out to protect. The `~` expansion below is
|
|
95
|
+
* the same one all three use.
|
|
96
|
+
*/
|
|
97
|
+
export function packageClaimedPaths(projectRoot: string): ReadonlySet<string> | null {
|
|
98
|
+
const manifest = manifest_path(projectRoot);
|
|
99
|
+
let doc: unknown;
|
|
100
|
+
try {
|
|
101
|
+
doc = parseYaml(fs.readFileSync(manifest, 'utf-8'), { version: '1.1' });
|
|
102
|
+
} catch {
|
|
103
|
+
// Unreadable and absent are the same answer: nothing recorded a claim.
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
if (doc === null || typeof doc !== 'object' || Array.isArray(doc)) return null;
|
|
107
|
+
const tools = (doc as Record<string, unknown>)['tools'];
|
|
108
|
+
const out = new Set<string>();
|
|
109
|
+
if (!Array.isArray(tools)) return out;
|
|
110
|
+
for (const tool of tools) {
|
|
111
|
+
if (tool === null || typeof tool !== 'object' || Array.isArray(tool)) continue;
|
|
112
|
+
const files = (tool as Record<string, unknown>)['files'];
|
|
113
|
+
if (!Array.isArray(files)) continue;
|
|
114
|
+
for (const entry of files) {
|
|
115
|
+
if (entry === null || typeof entry !== 'object' || Array.isArray(entry)) continue;
|
|
116
|
+
const raw = (entry as Record<string, unknown>)['path'];
|
|
117
|
+
if (typeof raw !== 'string' || raw === '') continue;
|
|
118
|
+
out.add(path.resolve(projectRoot, _expanduser(raw)));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Expand a leading `~`, matching the three sibling manifest readers. */
|
|
125
|
+
function _expanduser(p: string): string {
|
|
126
|
+
if (p === '~') return os.homedir();
|
|
127
|
+
if (p.startsWith('~/') || (process.platform === 'win32' && p.startsWith('~\\'))) {
|
|
128
|
+
return path.join(os.homedir(), p.slice(2));
|
|
129
|
+
}
|
|
130
|
+
return p;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export interface SkillOriginOptions {
|
|
134
|
+
/** Pre-read claim set, to avoid a second manifest read. `null` = no manifest. */
|
|
135
|
+
claims?: ReadonlySet<string> | null;
|
|
136
|
+
/** Maintainer checkout root whose `src/skills` is the authored tree. */
|
|
137
|
+
packageRoot?: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Resolve one `SKILL.md` path to the origin of the skill it defines.
|
|
142
|
+
*
|
|
143
|
+
* NO CLAIM RECORD MEANS NO QUALIFIER. With no manifest, nothing on disk carries
|
|
144
|
+
* evidence that any skill is foreign, so everything resolves to `package`, the
|
|
145
|
+
* ranker qualifies nothing, and its output is exactly what it was before this
|
|
146
|
+
* function existed. That is deliberate rather than a gap being tolerated: a
|
|
147
|
+
* `home:` prefix asserted without a claim record is a guess printed in the shape
|
|
148
|
+
* of a fact, and a reader cannot tell the two apart. The cost is stated rather
|
|
149
|
+
* than hidden — where no manifest exists a foreign skill is invisible here, and
|
|
150
|
+
* the thing that fixes it is running an install, not loosening this rule.
|
|
151
|
+
*
|
|
152
|
+
* The authored tree is the one exception, and it is a construction rather than a
|
|
153
|
+
* guess: `<root>/src/skills` exists only in a maintainer checkout of THIS
|
|
154
|
+
* package and holds its source of truth, so nothing foreign can be under it.
|
|
155
|
+
*/
|
|
156
|
+
export function makeSkillOriginResolver(
|
|
157
|
+
projectRoot: string,
|
|
158
|
+
opts: SkillOriginOptions = {},
|
|
159
|
+
): (skillMdPath: string) => SkillOrigin {
|
|
160
|
+
const claims = opts.claims !== undefined ? opts.claims : packageClaimedPaths(projectRoot);
|
|
161
|
+
const root = path.resolve(projectRoot);
|
|
162
|
+
const authored = path.join(path.resolve(opts.packageRoot ?? projectRoot), AUTHORED_SKILL_ROOT);
|
|
163
|
+
const under = (abs: string, dir: string): boolean =>
|
|
164
|
+
abs === dir || abs.startsWith(dir + path.sep);
|
|
165
|
+
return (skillMdPath: string): SkillOrigin => {
|
|
166
|
+
const abs = path.resolve(skillMdPath);
|
|
167
|
+
if (under(abs, authored)) return 'package';
|
|
168
|
+
if (claims === null) return 'package';
|
|
169
|
+
if (claims.has(abs)) return 'package';
|
|
170
|
+
return under(abs, root) ? 'project' : 'home';
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* The one label, and the order it is decided in.
|
|
176
|
+
*
|
|
177
|
+
* `unscanned` — the shape scan refused the body. FIRST, because an overlap
|
|
178
|
+
* score is derived FROM a body this census declined to read,
|
|
179
|
+
* and publishing it would be the refusal cancelling itself.
|
|
180
|
+
* `shadowed` — one of ours carries the same bare name. Name-derived, so it
|
|
181
|
+
* stays true under `unscanned`; it loses the slot only
|
|
182
|
+
* because `unscanned` is the stronger call to action.
|
|
183
|
+
* `overlapping` — content similarity against one of ours at or above the
|
|
184
|
+
* threshold `audit_skill_overlap` already calibrates.
|
|
185
|
+
* `unclassified` — none of the above fired. Not a clearance.
|
|
186
|
+
*/
|
|
187
|
+
export function classifyCompat(args: {
|
|
188
|
+
unscanned: string | null;
|
|
189
|
+
shadows: readonly string[];
|
|
190
|
+
overlaps: readonly string[];
|
|
191
|
+
}): Compat {
|
|
192
|
+
if (args.unscanned !== null) return 'unscanned';
|
|
193
|
+
if (args.shadows.length > 0) return 'shadowed';
|
|
194
|
+
if (args.overlaps.length > 0) return 'overlapping';
|
|
195
|
+
return 'unclassified';
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** One recorded scan verdict. `unscanned` is `null` when every shape passed. */
|
|
199
|
+
export interface ScanRecord {
|
|
200
|
+
qualified: string;
|
|
201
|
+
digest: string;
|
|
202
|
+
unscanned: string | null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export interface ScanCache {
|
|
206
|
+
schema_version: 1;
|
|
207
|
+
entries: ScanRecord[];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Read the scan cache, or `null` when it is absent or unreadable. */
|
|
211
|
+
export function readScanCache(file: string): ScanCache | null {
|
|
212
|
+
let parsed: unknown;
|
|
213
|
+
try {
|
|
214
|
+
parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
215
|
+
} catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return null;
|
|
219
|
+
const entries = (parsed as Record<string, unknown>)['entries'];
|
|
220
|
+
if (!Array.isArray(entries)) return null;
|
|
221
|
+
return { schema_version: 1, entries: entries as ScanRecord[] };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** sha256 of a file's bytes, or `null` when it cannot be read. */
|
|
225
|
+
export function fileDigest(file: string): string | null {
|
|
226
|
+
try {
|
|
227
|
+
return createHash('sha256').update(fs.readFileSync(file)).digest('hex');
|
|
228
|
+
} catch {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Whether a neighbour body may be indexed, and why not when it may not.
|
|
235
|
+
*
|
|
236
|
+
* THREE REFUSALS, REPORTED SEPARATELY, because they ask the maintainer for three
|
|
237
|
+
* different things: run the census, re-run it, or read the finding. A missing
|
|
238
|
+
* record is a refusal and not a pass — a gate that passes on missing evidence is
|
|
239
|
+
* satisfied by deleting the evidence, which is the opposite of a floor. The
|
|
240
|
+
* digest compare is what "a changed digest rescans first" means from the reading
|
|
241
|
+
* side: a body edited after its scan is unscanned again until the census runs.
|
|
242
|
+
*/
|
|
243
|
+
export function scanVerdict(
|
|
244
|
+
cache: ScanCache | null,
|
|
245
|
+
qualified: string,
|
|
246
|
+
digest: string | null,
|
|
247
|
+
): { ok: true } | { ok: false; kind: string } {
|
|
248
|
+
if (cache === null) return { ok: false, kind: 'no-scan-record' };
|
|
249
|
+
const rec = cache.entries.find((e) => e.qualified === qualified);
|
|
250
|
+
if (rec === undefined) return { ok: false, kind: 'no-scan-record' };
|
|
251
|
+
if (digest === null || rec.digest !== digest) return { ok: false, kind: 'digest-changed' };
|
|
252
|
+
if (rec.unscanned !== null) return { ok: false, kind: rec.unscanned };
|
|
253
|
+
return { ok: true };
|
|
254
|
+
}
|
|
@@ -15,45 +15,74 @@
|
|
|
15
15
|
*
|
|
16
16
|
* What is observed, and what is a shape guess — the line is drawn explicitly.
|
|
17
17
|
*
|
|
18
|
-
* `STRUCTURED_ASK_SHAPES`
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
18
|
+
* `STRUCTURED_ASK_SHAPES` carries **one** row, for `claude`, written from an
|
|
19
|
+
* observation under `host-capability-manifest.md` § Observation protocol —
|
|
20
|
+
* 48 `AskUserQuestion` `tool_use` blocks across host versions 2.1.252 to
|
|
21
|
+
* 2.1.284, 2026-09-01 to 2026-10-02. Artifact:
|
|
22
|
+
* `agents/evidence/analysis/structured-ask-host-observation-2026-10.md`. code-comment-allow provenance-comment -- the observation protocol declares a row inadmissible without its artifact citation, so this pointer is part of the contract the row satisfies, not evidence duplicated from a roadmap
|
|
23
|
+
* Every other host has no row, which is "never looked", and inventing one from
|
|
24
|
+
* a vendor's documentation is exactly what that protocol forbids.
|
|
22
25
|
*
|
|
23
|
-
* `STRUCTURED_ASK_TOOL_NAME_RE` is
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* `STRUCTURED_ASK_TOOL_NAME_RE` is a **name-shape pattern, not a host fact**,
|
|
27
|
+
* and stays one even now that a host fact exists beside it: the pattern is what
|
|
28
|
+
* every caller passing no host id still matches on. It exists so that a picker
|
|
29
|
+
* appearing in a transcript is MEASURED rather than missed. A reader must not
|
|
30
|
+
* read a match as evidence that a named host ships that tool; the only thing
|
|
31
|
+
* that establishes that is an observation written into
|
|
29
32
|
* `STRUCTURED_ASK_SHAPES` with the protocol's four-part citation.
|
|
30
33
|
*
|
|
31
|
-
* Consequence, stated rather than discovered later: `native` is
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
+
* Consequence, stated rather than discovered later: `native` is **0** on every
|
|
35
|
+
* corpus this repo can scan today — and the 2026-10 observation does NOT change
|
|
36
|
+
* that, which is worth stating because it looks like it should.
|
|
37
|
+
* `probe_unblocked_ask` partitions hand-back ask turns, and a picker call is
|
|
38
|
+
* answered by a `tool_result` rather than by a free user turn, so it was never
|
|
39
|
+
* in that probe's denominator. The zero means "no prose hand-back used a picker
|
|
40
|
+
* instead"; it never meant "no picker exists".
|
|
41
|
+
*
|
|
42
|
+
* That makes the zero DEFINITIONAL for this probe, not a measurement of
|
|
43
|
+
* scarcity, and the earlier wording claimed the opposite on both halves: it
|
|
44
|
+
* called the zero a measurement, and attributed it to the capability being
|
|
45
|
+
* unobserved. The capability is observed and the zero is unchanged, which is
|
|
46
|
+
* the cleanest available proof that the two were never connected.
|
|
34
47
|
*/
|
|
35
48
|
|
|
36
49
|
/** The per-host shape of a structured-ask tool, once one has been OBSERVED. */
|
|
37
50
|
export interface StructuredAskShape {
|
|
38
51
|
/** The tool name as it appears in a transcript's `tool_use` block. */
|
|
39
52
|
readonly tool: string;
|
|
40
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* The largest question count OBSERVED in one call, never a host ceiling the
|
|
55
|
+
* host was asked for and refused. `1` is also the shape this repo wants.
|
|
56
|
+
*/
|
|
41
57
|
readonly max_questions: number;
|
|
42
|
-
/**
|
|
58
|
+
/** The largest option count OBSERVED on one question — same caveat. */
|
|
43
59
|
readonly max_options_per_question: number;
|
|
44
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Whether the host's picker admits a free-text answer alongside the options.
|
|
62
|
+
* The WEAKEST of the four to establish, because it is read by negation — an
|
|
63
|
+
* answer carrying none of the offered labels. A cancelled ask looks the same
|
|
64
|
+
* from the outside, so a `true` here is "observed at least once", never a
|
|
65
|
+
* count. The citing artifact carries the per-row basis.
|
|
66
|
+
*/
|
|
45
67
|
readonly free_text: boolean;
|
|
46
68
|
}
|
|
47
69
|
|
|
48
70
|
/**
|
|
49
71
|
* Observed per-host structured-ask shapes.
|
|
50
72
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
73
|
+
* A row is written only from an observation in a real session under
|
|
74
|
+
* `contexts/execution/host-capability-manifest.md` § Observation protocol —
|
|
75
|
+
* host · host version · transcript reference · date. Never from a host's
|
|
76
|
+
* documentation, and never by analogy to another host.
|
|
77
|
+
*
|
|
78
|
+
* `claude`'s row is the first, and the two numeric fields are **observed
|
|
79
|
+
* maxima over 48 calls, not host ceilings**: no call carried two questions, so
|
|
80
|
+
* the host was never asked to accept two. The guard's threshold does not rest
|
|
81
|
+
* on them — one question per call is this repo's own rule either way.
|
|
55
82
|
*/
|
|
56
|
-
export const STRUCTURED_ASK_SHAPES: Readonly<Record<string, StructuredAskShape>> = {
|
|
83
|
+
export const STRUCTURED_ASK_SHAPES: Readonly<Record<string, StructuredAskShape>> = {
|
|
84
|
+
claude: { tool: 'AskUserQuestion', max_questions: 1, max_options_per_question: 4, free_text: true },
|
|
85
|
+
};
|
|
57
86
|
|
|
58
87
|
/** The observed shape for `hostId`, or `undefined` when none has been observed. */
|
|
59
88
|
export function structuredAskShape(
|
|
@@ -77,6 +106,20 @@ export const STRUCTURED_ASK_TOOL_NAME_RE = /^(ask[_-]?user[_-]?question|user[_-]
|
|
|
77
106
|
* An observed per-host shape wins outright — that is a fact about the host. The
|
|
78
107
|
* name-shape pattern is the fallback, and it is why the probe can report a
|
|
79
108
|
* measured zero instead of nothing at all.
|
|
109
|
+
*
|
|
110
|
+
* KNOWN ASYMMETRY, named rather than left for the next reader to hit. With a
|
|
111
|
+
* row present, this returns `name === shape.tool`: ONE observed name becomes an
|
|
112
|
+
* exclusive allowlist, so every other picker name is answered `false` on that
|
|
113
|
+
* host — a universal negative from a single positive observation, which is the
|
|
114
|
+
* shape of inference the observation protocol refuses elsewhere. It is left as
|
|
115
|
+
* it is because the alternative (union of the row and the pattern) would make
|
|
116
|
+
* an observed row buy nothing, and because no caller is affected today. There
|
|
117
|
+
* are TWO production callers, both host-blind, enumerated rather than recalled:
|
|
118
|
+
* `hooks/one_question_per_ask_hook.ts:103` and `probe_unblocked_ask.ts:184`,
|
|
119
|
+
* each calling `isStructuredAskTool(name)` with no second argument. A caller
|
|
120
|
+
* that does start passing one inherits the asymmetry, and
|
|
121
|
+
* `tests/scripts/ask_surface.test.ts` pins it so the inheritance is visible
|
|
122
|
+
* rather than silent.
|
|
80
123
|
*/
|
|
81
124
|
export function isStructuredAskTool(name: string, hostId?: string | null): boolean {
|
|
82
125
|
const shape = structuredAskShape(hostId);
|