@event4u/agent-config 16.2.0 → 16.4.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 +337 -234
- package/README.md +15 -13
- package/agents/templates/.ai-council.yml.example +26 -8
- package/dist/agent-src/commands/analyze/inbox.md +11 -8
- 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/bug/investigate.md +1 -1
- package/dist/agent-src/commands/commit/in-chunks.md +40 -31
- package/dist/agent-src/commands/commit.md +72 -33
- package/dist/agent-src/commands/condense.md +2 -8
- package/dist/agent-src/commands/council/debate.md +11 -7
- package/dist/agent-src/commands/council/default.md +10 -9
- package/dist/agent-src/commands/council.md +1 -1
- package/dist/agent-src/commands/estimate-ticket.md +1 -1
- package/dist/agent-src/commands/feature/explore.md +3 -3
- package/dist/agent-src/commands/feature/plan.md +2 -2
- package/dist/agent-src/commands/feature/roadmap.md +1 -1
- package/dist/agent-src/commands/fix/ci.md +18 -4
- package/dist/agent-src/commands/fix/commit-messages.md +48 -23
- package/dist/agent-src/commands/fix/pr-comments.md +3 -6
- package/dist/agent-src/commands/implement-ticket.md +4 -4
- package/dist/agent-src/commands/jira-ticket.md +1 -1
- package/dist/agent-src/commands/memory/add.md +4 -16
- package/dist/agent-src/commands/memory/load.md +5 -6
- package/dist/agent-src/commands/memory/promote.md +3 -16
- package/dist/agent-src/commands/mission/upgrade.md +3 -2
- package/dist/agent-src/commands/optimize/agents-dir.md +2 -2
- package/dist/agent-src/commands/optimize/deep.md +4 -2
- package/dist/agent-src/commands/optimize/rtk.md +4 -26
- package/dist/agent-src/commands/pr/create/description-only.md +18 -15
- package/dist/agent-src/commands/pr/create.md +42 -34
- package/dist/agent-src/commands/pr/merge.md +136 -9
- package/dist/agent-src/commands/prepare-for-review.md +13 -11
- package/dist/agent-src/commands/project/analyze.md +7 -35
- package/dist/agent-src/commands/refine-ticket.md +1 -1
- package/dist/agent-src/commands/review/changes.md +14 -19
- 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/next.md +10 -1
- package/dist/agent-src/commands/roadmap/process-full.md +56 -42
- package/dist/agent-src/commands/roadmap/resolve-blockers.md +411 -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/commands/worktree/create.md +7 -3
- package/dist/agent-src/commands/worktree/verify.md +2 -1
- 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/communication/rules-auto/think-before-action-mechanics.md +5 -3
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +7 -9
- package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +8 -6
- package/dist/agent-src/contexts/contracts/frugality-charter.md +8 -5
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +7 -7
- package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +0 -1
- package/dist/agent-src/contexts/execution/evidence-discipline.md +2 -2
- package/dist/agent-src/contexts/execution/non-interactive-contract.md +5 -8
- package/dist/agent-src/contexts/execution/rdp-gate.md +4 -4
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +9 -8
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +99 -54
- package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
- package/dist/agent-src/contexts/execution/subagent-routing.md +8 -8
- package/dist/agent-src/contexts/execution/subagent-steering.md +6 -4
- package/dist/agent-src/contexts/execution/terminal-states.md +2 -2
- package/dist/agent-src/contexts/execution/toolchain-resolver.md +95 -7
- package/dist/agent-src/contexts/subagent-configuration.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
- package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
- package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
- package/dist/agent-src/guidelines/agent-infra/layered-settings.md +13 -1
- package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
- package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +36 -0
- package/dist/agent-src/guidelines/php/git.md +15 -2
- package/dist/agent-src/rules/active-remediation.md +1 -2
- package/dist/agent-src/rules/analysis-skill-routing.md +0 -1
- package/dist/agent-src/rules/architecture.md +0 -1
- package/dist/agent-src/rules/artifact-drafting-protocol.md +0 -1
- package/dist/agent-src/rules/artifact-engagement-recording.md +0 -1
- package/dist/agent-src/rules/augment-edit-discipline.md +0 -1
- package/dist/agent-src/rules/autonomous-execution.md +1 -1
- package/dist/agent-src/rules/brand-consistency.md +0 -1
- package/dist/agent-src/rules/brand-source-of-truth.md +0 -1
- package/dist/agent-src/rules/broken-access-control.md +1 -1
- package/dist/agent-src/rules/cli-output-handling.md +0 -1
- package/dist/agent-src/rules/code-comment-discipline.md +0 -1
- package/dist/agent-src/rules/code-provenance.md +0 -1
- package/dist/agent-src/rules/command-suggestion-policy.md +1 -1
- package/dist/agent-src/rules/commit-conventions.md +1 -2
- package/dist/agent-src/rules/communication-through-line.md +1 -2
- package/dist/agent-src/rules/content-quoting-floor.md +1 -2
- package/dist/agent-src/rules/context-hygiene.md +6 -6
- package/dist/agent-src/rules/copilot-routing.md +1 -2
- package/dist/agent-src/rules/council-availability.md +4 -4
- package/dist/agent-src/rules/cross-source-consistency.md +4 -6
- package/dist/agent-src/rules/decision-revisit-gate.md +17 -35
- package/dist/agent-src/rules/delegation-policy.md +2 -3
- package/dist/agent-src/rules/design-fidelity.md +12 -16
- package/dist/agent-src/rules/design-review-after-ui-write.md +3 -3
- package/dist/agent-src/rules/devcontainer-routing.md +1 -2
- package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -1
- package/dist/agent-src/rules/docker-commands.md +0 -1
- package/dist/agent-src/rules/domain-adoption-policy.md +0 -1
- package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -1
- package/dist/agent-src/rules/domain-safety-pii.md +1 -1
- package/dist/agent-src/rules/domain-safety-retention.md +1 -1
- package/dist/agent-src/rules/downstream-changes.md +0 -1
- package/dist/agent-src/rules/engineering-safety-floor.md +1 -1
- package/dist/agent-src/rules/evaluator-independence.md +3 -2
- package/dist/agent-src/rules/external-code-graph-interop.md +0 -1
- package/dist/agent-src/rules/external-reference-deep-dive.md +0 -1
- package/dist/agent-src/rules/fast-path-marker-visibility.md +2 -2
- package/dist/agent-src/rules/finance-safety-floor.md +1 -1
- package/dist/agent-src/rules/fix-what-you-see.md +6 -32
- package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +0 -1
- package/dist/agent-src/rules/git-history-discipline.md +2 -2
- package/dist/agent-src/rules/guidelines.md +0 -1
- package/dist/agent-src/rules/history-discipline.md +0 -1
- package/dist/agent-src/rules/icon-consistency.md +0 -1
- package/dist/agent-src/rules/image-likeness-and-rights.md +1 -1
- package/dist/agent-src/rules/improve-before-implement.md +0 -1
- package/dist/agent-src/rules/invite-challenge.md +0 -1
- package/dist/agent-src/rules/laravel-routing.md +1 -2
- package/dist/agent-src/rules/laravel-translations.md +0 -1
- package/dist/agent-src/rules/legal-safety-floor.md +3 -3
- package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -1
- package/dist/agent-src/rules/linked-projects-onboarding-gate.md +0 -1
- package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -1
- package/dist/agent-src/rules/markdown-safe-codeblocks.md +0 -1
- package/dist/agent-src/rules/media-governance-routing.md +13 -17
- package/dist/agent-src/rules/media-sync-ground-truth.md +0 -1
- package/dist/agent-src/rules/minimal-safe-diff.md +0 -1
- package/dist/agent-src/rules/missing-skill-recovery.md +0 -1
- package/dist/agent-src/rules/missing-tool-handling.md +0 -1
- package/dist/agent-src/rules/model-recommendation.md +0 -1
- package/dist/agent-src/rules/neighbour-precedence.md +64 -0
- package/dist/agent-src/rules/no-attribution-footers.md +0 -1
- package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +0 -1
- package/dist/agent-src/rules/no-pr-progress-comments.md +0 -1
- package/dist/agent-src/rules/no-roadmap-references.md +0 -1
- package/dist/agent-src/rules/notes-first-reasoning.md +0 -1
- package/dist/agent-src/rules/onboarding-gate.md +0 -1
- package/dist/agent-src/rules/output-discipline.md +0 -1
- package/dist/agent-src/rules/package-ci-checks.md +0 -1
- package/dist/agent-src/rules/persona-governance.md +4 -5
- package/dist/agent-src/rules/php-coding.md +0 -1
- package/dist/agent-src/rules/prefer-enums-over-literals.md +0 -1
- package/dist/agent-src/rules/preservation-guard.md +0 -1
- package/dist/agent-src/rules/provider-lifecycle-discipline.md +3 -4
- package/dist/agent-src/rules/question-not-instruction.md +1 -1
- package/dist/agent-src/rules/reviewer-awareness.md +0 -1
- package/dist/agent-src/rules/roadmap-ci-steps-policy.md +0 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +4 -7
- package/dist/agent-src/rules/role-mode-adherence.md +0 -1
- package/dist/agent-src/rules/rule-type-governance.md +0 -1
- package/dist/agent-src/rules/runtime-safety.md +1 -1
- package/dist/agent-src/rules/scale-discipline.md +0 -1
- package/dist/agent-src/rules/secret-vcs-guard.md +1 -1
- package/dist/agent-src/rules/security-sensitive-stop.md +3 -3
- package/dist/agent-src/rules/self-repair-loop.md +0 -1
- package/dist/agent-src/rules/senior-engineering-discipline.md +0 -1
- package/dist/agent-src/rules/session-canary.md +7 -62
- package/dist/agent-src/rules/settings-ask-protocol.md +6 -6
- package/dist/agent-src/rules/size-enforcement.md +0 -1
- package/dist/agent-src/rules/skill-improvement-trigger.md +2 -3
- package/dist/agent-src/rules/skill-quality.md +0 -1
- package/dist/agent-src/rules/slash-command-routing-policy.md +0 -1
- package/dist/agent-src/rules/source-confidentiality.md +1 -1
- package/dist/agent-src/rules/source-discovery-gate.md +0 -1
- package/dist/agent-src/rules/source-of-truth.md +0 -1
- package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -2
- package/dist/agent-src/rules/strategy-safety-floor.md +1 -1
- package/dist/agent-src/rules/symfony-routing.md +1 -2
- package/dist/agent-src/rules/think-before-action.md +0 -1
- package/dist/agent-src/rules/token-budget-discipline.md +12 -46
- package/dist/agent-src/rules/token-efficiency.md +0 -1
- package/dist/agent-src/rules/token-optimizer-maintenance.md +0 -1
- package/dist/agent-src/rules/tool-safety.md +1 -1
- package/dist/agent-src/rules/ui-audit-gate.md +1 -2
- package/dist/agent-src/rules/untrusted-input-defense.md +1 -1
- package/dist/agent-src/rules/upstream-proposal.md +0 -1
- package/dist/agent-src/rules/user-interaction.md +0 -1
- package/dist/agent-src/rules/user-interrupt-priority.md +1 -1
- 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/gate_budget.ts +47 -23
- package/dist/agent-src/scripts/gate_execute.ts +12 -4
- package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/dist/agent-src/skills/ai-council/SKILL.md +7 -4
- package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +21 -11
- package/dist/agent-src/skills/ai-council/references/procedure.md +12 -6
- package/dist/agent-src/skills/analysis-autonomous-mode/SKILL.md +1 -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/bug-analyzer/SKILL.md +1 -1
- package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
- package/dist/agent-src/skills/command-routing/SKILL.md +3 -4
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +127 -139
- package/dist/agent-src/skills/corpus-grounding/ATTRIBUTION.md +39 -0
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +8 -2
- package/dist/agent-src/skills/database/data/manifest.json +2 -2
- package/dist/agent-src/skills/database/data/query-tuning.csv +13 -13
- package/dist/agent-src/skills/design-system-capture/SKILL.md +0 -3
- package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
- package/dist/agent-src/skills/estimate-ticket/SKILL.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/feature-planning/SKILL.md +1 -1
- package/dist/agent-src/skills/git-workflow/SKILL.md +44 -44
- package/dist/agent-src/skills/git-workflow/references/branch-update.md +312 -0
- package/dist/agent-src/skills/git-workflow/references/commit-subject.md +205 -0
- package/dist/agent-src/skills/iconography/SKILL.md +1 -1
- package/dist/agent-src/skills/jira-integration/SKILL.md +3 -3
- package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +10 -4
- package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
- package/dist/agent-src/skills/po-discovery/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/refine-ticket/SKILL.md +4 -4
- package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +2 -2
- package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +5 -3
- package/dist/agent-src/skills/source-discovery/SKILL.md +1 -1
- package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
- package/dist/agent-src/skills/tailwind-engineer/SKILL.md +4 -2
- 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/testing-anti-patterns/SKILL.md +1 -1
- package/dist/agent-src/skills/ui-component-architect/SKILL.md +2 -2
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
- package/dist/agent-src/templates/AGENTS.md +1 -1
- package/dist/agent-src/templates/agent-settings.md +46 -129
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +3 -3
- package/dist/agent-src/templates/command.md +2 -2
- package/dist/agent-src/templates/roadmaps.md +6 -1
- package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
- package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
- package/dist/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
- package/dist/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
- package/dist/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
- package/dist/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
- package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/dist/agent-src/templates/skill.md +1 -1
- package/dist/cli/registry.js +2 -1
- package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
- package/dist/cli-delegate/check_update_banner.js +207 -120
- package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
- package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-5GPULQBE.js} +2797 -338
- package/dist/cli-delegate/{chunk-IGD6ERX6.js → chunk-6SRJTYJS.js} +42 -176
- package/dist/cli-delegate/chunk-6V5FMA3P.js +186 -0
- package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
- package/dist/cli-delegate/chunk-6YQC2HLF.js +415 -0
- package/dist/cli-delegate/{chunk-E4XIZDIB.js → chunk-7HKRE54K.js} +1 -64
- package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
- package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-AED2VQGM.js} +1245 -249
- package/dist/cli-delegate/{chunk-7HQ52DHU.js → chunk-AL3RZ22D.js} +1 -1
- package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
- package/dist/cli-delegate/{chunk-DBH4AHDK.js → chunk-ED7KCMLB.js} +9 -11
- package/dist/cli-delegate/chunk-F3QDG2GT.js +2569 -0
- package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-G5VVIZRC.js} +3 -3
- package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-H76PHZBI.js} +149 -61
- package/dist/cli-delegate/chunk-IAYTIIQW.js +67 -0
- package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
- 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-KXXWJTDO.js} +6 -11
- package/dist/cli-delegate/{chunk-T7L2QK3K.js → chunk-LQOCRFWT.js} +1 -1
- package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-MDPPKQCQ.js} +58 -9
- package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-MSUL5NYP.js} +5 -5
- package/dist/cli-delegate/chunk-OAFSJBHH.js +272 -0
- 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-P6ZHP5W2.js → chunk-PWX7CKMD.js} +4 -4
- package/dist/cli-delegate/{chunk-NDJLNC6Q.js → chunk-T6BP34WI.js} +1 -0
- package/dist/cli-delegate/{chunk-7XGBX6ZH.js → chunk-T7XSJSUQ.js} +1144 -589
- package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
- package/dist/cli-delegate/chunk-WQWXGIWB.js +1779 -0
- package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-XQTPXKFA.js} +1 -1
- 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 +223 -43
- package/dist/cli-delegate/cmd_brand_status.js +3 -2
- package/dist/cli-delegate/cmd_conformance.js +1252 -249
- package/dist/cli-delegate/cmd_converge.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +19 -9
- package/dist/cli-delegate/cmd_doctor_neighbours.js +30 -0
- package/dist/cli-delegate/cmd_explain.js +45 -21
- package/dist/cli-delegate/cmd_export.js +13 -10
- package/dist/cli-delegate/cmd_fleet.js +3 -3
- package/dist/cli-delegate/cmd_git_convention.js +1851 -0
- package/dist/cli-delegate/cmd_handoff.js +44 -22
- package/dist/cli-delegate/cmd_mcp_available.js +3 -2
- package/dist/cli-delegate/cmd_memory_get.js +3 -1
- package/dist/cli-delegate/cmd_migrate.js +3 -3
- package/dist/cli-delegate/cmd_packs_active.js +5 -4
- package/dist/cli-delegate/cmd_preflight.js +6 -6
- package/dist/cli-delegate/cmd_prune.js +14 -11
- package/dist/cli-delegate/cmd_refresh.js +2 -1
- package/dist/cli-delegate/cmd_route_audit.js +10 -8
- package/dist/cli-delegate/cmd_route_explain.js +4 -4
- package/dist/cli-delegate/cmd_session_recycle.js +10 -7
- package/dist/cli-delegate/cmd_settings_check.js +54 -7
- package/dist/cli-delegate/cmd_settings_get.js +18 -8
- package/dist/cli-delegate/cmd_settings_migrate.js +13 -10
- package/dist/cli-delegate/cmd_settings_set.js +4 -4
- package/dist/cli-delegate/cmd_sync.js +14 -11
- package/dist/cli-delegate/cmd_uninstall.js +15 -12
- package/dist/cli-delegate/cmd_update.js +7 -7
- package/dist/cli-delegate/cmd_upgrade.js +9 -8
- package/dist/cli-delegate/cmd_validate.js +15 -12
- package/dist/cli-delegate/cmd_versions.js +5 -5
- package/dist/cli-delegate/deferral_carry.js +16 -0
- package/dist/cli-delegate/gate_budget.js +1 -1
- package/dist/cli-delegate/gate_execute.js +3 -3
- package/dist/cli-delegate/roadmap_gates.js +6 -6
- package/dist/cli-delegate/update_roadmap_progress.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +232 -141
- 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 +26 -9
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +7 -4
- package/dist/hooks/dispatch.js +5655 -6623
- 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 +2336 -1249
- package/dist/install/installThinLayer.js +289 -0
- package/dist/install/installedRuleLinks.js +262 -0
- package/dist/install/wizard-plan.js +24 -0
- package/dist/mcp/awesome-mcp-servers.row.md +1 -1
- package/dist/mcp/mcp-cloudflare-catalogue.json +2 -2
- package/dist/mcp/registry-manifest.json +5 -5
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +36504 -30986
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +26 -120
- package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
- package/dist/scripts/_lib/compile_time_toggles.js +12 -21
- package/dist/scripts/_lib/git_convention.js +232 -0
- package/dist/scripts/_lib/global_deploy_inventory.js +730 -0
- package/dist/scripts/_lib/installed_layer.js +704 -0
- package/dist/scripts/_lib/lean_projection_mode.js +218 -15
- package/dist/scripts/_lib/package_root.js +68 -0
- 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/settings_removed_keys.js +168 -0
- package/dist/scripts/_lib/thin_rules.js +535 -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/app.js +2 -1
- package/dist/server/gitKeysGate.js +105 -0
- package/dist/server/routes/settings.js +67 -8
- package/dist/server/routes/wizard.js +4 -0
- package/dist/server/schemas/settings.js +29 -81
- package/dist/shared/skillRanking.js +103 -16
- package/dist/ui/assets/{index-Cwq4d0hX.js → index-C3djEJah.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/docs/MIGRATION.md +72 -1
- package/docs/contracts/settings-classes.md +39 -67
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +39 -0
- package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +1 -1
- package/docs/guidelines/agent-infra/cross-source-consistency-mechanics.md +8 -10
- package/docs/guidelines/agent-infra/frontier-reasoning-operating-profile.md +3 -2
- package/docs/guidelines/agent-infra/layered-settings.md +13 -1
- package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
- package/docs/guidelines/agent-infra/self-improvement-pipeline.md +10 -3
- package/docs/guidelines/agent-infra/size-and-scope.md +36 -0
- package/docs/guidelines/php/git.md +15 -2
- 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/gate_budget.ts +47 -23
- package/src/agent-src/scripts/gate_execute.ts +12 -4
- package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
- package/src/agent-src/templates/AGENTS.md +1 -1
- package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -6
- package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +11 -7
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +3 -2
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +2 -1
- package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +0 -6
- package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +9 -12
- package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +2 -1
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
- package/src/config/agent-settings.template.yml +141 -334
- package/src/config/agents-paths.yml +16 -0
- package/src/config/assurance-capability-registry.json +7 -3
- package/src/config/ci-local-parity.yml +3 -0
- package/src/config/continuity-surface.json +10 -3
- package/src/config/discovery/packs.yml +17 -1
- package/src/config/evaluator-budgets.json +23 -10
- package/src/config/gate-coverage.yml +138 -3
- package/src/config/gate-violation-baselines.json +64 -16
- package/src/config/gitignore-block.txt +19 -0
- 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/release-gate-locality.yml +2 -1
- package/src/config/routing-coverage-seed.json +67 -4
- 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 +105 -0
- package/src/config/rule-obligations.json +833 -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 +378 -0
- package/src/install/installedRuleLinks.ts +308 -0
- package/src/install/wizard-plan.ts +24 -0
- package/src/scripts/_cli/cmd_analyze_session.ts +9 -15
- package/src/scripts/_cli/cmd_conformance.ts +13 -2
- package/src/scripts/_cli/cmd_doctor.ts +33 -81
- package/src/scripts/_cli/cmd_doctor_neighbours.ts +426 -0
- package/src/scripts/_cli/cmd_explain.ts +72 -14
- package/src/scripts/_cli/cmd_git_convention.ts +637 -0
- package/src/scripts/_cli/cmd_settings_check.ts +66 -8
- package/src/scripts/_cli/cmd_settings_get.ts +18 -3
- package/src/scripts/_cli/doctor_execution.ts +72 -1
- package/src/scripts/_dispatch.bash +53 -4
- package/src/scripts/_lib/agent_settings.ts +26 -124
- package/src/scripts/_lib/blocked_by_marker.ts +1 -1
- package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
- package/src/scripts/_lib/compile_time_toggles.ts +12 -21
- package/src/scripts/_lib/dispatch_import_closure.ts +163 -0
- 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/git_base_ref.ts +92 -0
- package/src/scripts/_lib/git_convention.ts +291 -0
- package/src/scripts/_lib/git_convention_carrier.ts +389 -0
- package/src/scripts/_lib/git_convention_grammar.ts +246 -0
- package/src/scripts/_lib/git_convention_measure.ts +344 -0
- package/src/scripts/_lib/gitignore_block.ts +314 -0
- package/src/scripts/_lib/global_deploy_inventory.ts +106 -0
- package/src/scripts/_lib/graph_feeder_record.ts +437 -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 +963 -0
- package/src/scripts/_lib/json_merge.ts +82 -0
- package/src/scripts/_lib/json_pointers.ts +93 -11
- package/src/scripts/_lib/knowledge_global.ts +14 -1
- package/src/scripts/_lib/lean_projection_mode.ts +275 -15
- package/src/scripts/_lib/machine_wake.ts +16 -3
- package/src/scripts/_lib/module_reach.ts +456 -0
- package/src/scripts/_lib/neighbour_census.ts +760 -0
- package/src/scripts/_lib/neighbour_contradictions.ts +236 -0
- package/src/scripts/_lib/neighbour_scan.ts +122 -0
- package/src/scripts/_lib/neighbour_tool_use.ts +187 -0
- package/src/scripts/_lib/prompt_shape.ts +46 -0
- package/src/scripts/_lib/ratification_artifact.ts +220 -1
- package/src/scripts/_lib/ratification_subject.ts +92 -0
- package/src/scripts/_lib/release_findings_ingest.ts +15 -7
- package/src/scripts/_lib/release_highlights.ts +5 -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/rule_obligations.ts +205 -0
- package/src/scripts/_lib/self_repair.ts +1 -1
- package/src/scripts/_lib/settings_removed_keys.ts +173 -0
- package/src/scripts/_lib/skill_origin.ts +254 -0
- package/src/scripts/_lib/structured_ask.ts +64 -21
- package/src/scripts/_lib/test_red_state.ts +5 -0
- package/src/scripts/_lib/thin_rules.ts +620 -0
- package/src/scripts/_lib/touched_file_quality.ts +570 -0
- package/src/scripts/_lib/turn_end_refusals.ts +77 -2
- package/src/scripts/_lib/windsurf_render.ts +63 -0
- package/src/scripts/_lib/worker_budget.ts +1 -1
- package/src/scripts/adr/regenerate_index.ts +16 -1
- 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 +8 -8
- package/src/scripts/ai_council/modification_review.ts +100 -0
- package/src/scripts/ai_council/modification_review_questions.ts +90 -0
- package/src/scripts/ai_council/orchestrator.ts +5 -5
- package/src/scripts/ai_council/spend_gate.ts +18 -7
- package/src/scripts/ai_council/vendor_defaults.ts +45 -0
- package/src/scripts/ai_team/config.ts +11 -16
- package/src/scripts/audit_skill_overlap.ts +261 -0
- package/src/scripts/audit_user_type_axis.ts +20 -8
- package/src/scripts/before_complete_hook.ts +243 -12
- package/src/scripts/bench_ab_clone.ts +1 -2
- package/src/scripts/bench_concern_spawn_path.ts +129 -0
- package/src/scripts/bench_graph_feeder_latency.ts +584 -0
- package/src/scripts/bench_touched_file_quality.ts +238 -0
- package/src/scripts/check_agent_artifact_location.ts +36 -0
- package/src/scripts/check_branch_freshness.ts +147 -24
- package/src/scripts/check_enforcement_coverage.ts +130 -0
- package/src/scripts/check_enforcement_matrix.ts +377 -20
- package/src/scripts/check_estate_count.ts +130 -153
- package/src/scripts/check_evaluator_budgets.ts +4 -0
- package/src/scripts/check_finding_dispositions.ts +196 -21
- package/src/scripts/check_gate_coverage.ts +4 -3
- package/src/scripts/check_gate_reachability.ts +48 -1
- package/src/scripts/check_generator_sync.ts +48 -0
- package/src/scripts/check_hook_bundle_composition.ts +477 -0
- package/src/scripts/check_kernel_edit_ratified.ts +132 -14
- package/src/scripts/check_memory.ts +7 -1
- package/src/scripts/check_pack_size.ts +1 -1
- package/src/scripts/check_release_highlights.ts +10 -0
- package/src/scripts/check_release_manifest_content.ts +189 -0
- package/src/scripts/check_release_pr_shape.ts +38 -15
- package/src/scripts/check_standing_rule_delivery.ts +129 -13
- package/src/scripts/check_suppression_hygiene.ts +2 -5
- package/src/scripts/check_verify_expectation_delta.ts +521 -0
- package/src/scripts/ci_settle.ts +42 -5
- package/src/scripts/classify_merge_risk.ts +320 -0
- package/src/scripts/closure_scan.ts +91 -1
- 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/command_suggester/settings.ts +8 -108
- package/src/scripts/command_suggester/types.ts +4 -5
- package/src/scripts/compile_hook_manifest.ts +33 -1
- package/src/scripts/condense.ts +14 -27
- package/src/scripts/consumer_matrix.ts +102 -0
- package/src/scripts/context_hygiene_hook.ts +13 -23
- package/src/scripts/cost/preflight.mjs +12 -1
- package/src/scripts/council_cli.ts +7 -7
- package/src/scripts/dispatch_r2_reviewer.ts +24 -11
- package/src/scripts/estate_exemption_shape.ts +202 -0
- package/src/scripts/explain_run.ts +8 -13
- package/src/scripts/generate_git_convention_grammar.ts +127 -0
- package/src/scripts/generate_host_cost_table.ts +21 -4
- package/src/scripts/handoff_context_hook.ts +86 -37
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +175 -15
- package/src/scripts/hooks/block_config_weakening.ts +115 -7
- package/src/scripts/hooks/block_plumbing_writes.ts +37 -5
- 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/concern_registry.ts +2 -0
- package/src/scripts/hooks/delegation_nudge_hook.ts +2 -3
- package/src/scripts/hooks/dispatch_hook.ts +52 -52
- package/src/scripts/hooks/evidence_independence.ts +12 -4
- 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/mcp_usage_observation_hook.ts +121 -0
- 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/push_settle_hook.ts +4 -3
- package/src/scripts/hooks/rule_inject_hook.ts +795 -60
- package/src/scripts/hooks/state_io.ts +8 -4
- package/src/scripts/hooks/table_fingerprint.ts +21 -0
- package/src/scripts/hooks/telemetry_usage_hook.ts +24 -7
- package/src/scripts/hooks/turn_end_gate_hook.ts +85 -0
- package/src/scripts/hooks_status.ts +112 -0
- package/src/scripts/injection_scan_hook.ts +7 -0
- package/src/scripts/install-hooks.sh +42 -14
- package/src/scripts/install.ts +78 -215
- 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_blocker_citations.ts +198 -0
- package/src/scripts/lint_evidence_artifacts.ts +9 -0
- package/src/scripts/lint_hook_concern_budget.ts +10 -21
- 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 +465 -29
- package/src/scripts/lint_roadmap_blockers.ts +282 -29
- package/src/scripts/lint_roadmap_complexity.ts +4 -2
- package/src/scripts/lint_rule_law_section.ts +647 -0
- package/src/scripts/lint_rule_skill_pack_reach.ts +17 -0
- package/src/scripts/lint_settings_classes.ts +1 -1
- package/src/scripts/lint_ticked_unmet_criteria.ts +165 -0
- package/src/scripts/lint_workflow_security.ts +173 -6
- 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 +221 -8
- package/src/scripts/memory_learn_hook.ts +91 -6
- package/src/scripts/model_rule_injection.ts +55 -8
- package/src/scripts/onboarding_gate_hook.ts +7 -6
- package/src/scripts/print_required_checks.ts +15 -3
- package/src/scripts/probe_host_compliance.ts +33 -5
- package/src/scripts/probe_turnaround.ts +183 -3
- package/src/scripts/project_thin_rules.ts +34 -327
- package/src/scripts/ratification_header.ts +77 -0
- package/src/scripts/refusal_envelope.ts +138 -0
- package/src/scripts/release_publication.ts +29 -3
- package/src/scripts/report_dispatch_import_closure.ts +76 -0
- package/src/scripts/report_evidence_temperature.ts +657 -0
- package/src/scripts/report_installed_rule_links.ts +274 -0
- package/src/scripts/report_label_agreement.ts +233 -0
- package/src/scripts/report_module_reach.ts +212 -0
- package/src/scripts/report_obligation_mechanism.ts +228 -0
- package/src/scripts/report_parked_blockers.ts +222 -0
- package/src/scripts/report_required_checks_drift.ts +196 -0
- package/src/scripts/report_single_token_triggers.ts +277 -0
- package/src/scripts/report_skill_ranker_confusion.ts +543 -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/routing_doctor.ts +2 -2
- package/src/scripts/rule_activation_census.ts +5 -2
- package/src/scripts/rule_trigger_eval.ts +9 -9
- package/src/scripts/schemas/agent-settings.schema.json +17 -31
- package/src/scripts/schemas/command.schema.json +1 -1
- package/src/scripts/schemas/review-findings.schema.json +3 -2
- package/src/scripts/schemas/rule.schema.json +5 -0
- package/src/scripts/schemas/skill.schema.json +1 -1
- package/src/scripts/self_review_gate.ts +101 -9
- package/src/scripts/skill_tools/score_skill_relevance.ts +314 -40
- package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
- package/src/scripts/sync_gitignore.ts +29 -235
- package/src/scripts/sync_pr_branch.ts +403 -132
- package/src/scripts/trigger_eval_grandfather.json +0 -21
- package/src/server/schemas/settings.ts +42 -176
- package/src/shared/skillRanking.ts +169 -14
- package/dist/cli-delegate/chunk-5R7HOLAF.js +0 -99
- package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
- package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
- package/src/scripts/_lib/config_chain.ts +0 -477
- package/src/scripts/_lib/conformance_report.ts +0 -403
- package/src/scripts/_lib/eval_discrimination.ts +0 -95
- package/src/scripts/_lib/evaluator_promotion.ts +0 -225
- package/src/scripts/_lib/file_slicer.ts +0 -117
- package/src/scripts/_lib/legacy_boundary_map.ts +0 -228
- package/src/scripts/_lib/minimality_tiebreak.ts +0 -168
- package/src/scripts/_lib/overbuild_lens_contract.ts +0 -196
- package/src/scripts/_lib/role_split.ts +0 -338
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-tool inventory of files written by global deploys — and stale reaping.
|
|
3
|
+
*
|
|
4
|
+
* Ported from the retired Python `src/scripts/_lib/global_deploy_inventory.py` (ADR-200 —
|
|
5
|
+
* Python→TS migration, Phase 2 / Wave 2a). Public API mirrors the Python
|
|
6
|
+
* module exactly (snake_case kept deliberately), including the JSON
|
|
7
|
+
* serialization shape (`indent=2, sort_keys=True` + trailing newline) and the
|
|
8
|
+
* inventory-walk / orphan-reap semantics.
|
|
9
|
+
*
|
|
10
|
+
* Sidecar at `~/.event4u/agent-config/deployed-files.json`. Records, per tool,
|
|
11
|
+
* the anchor directory and the relative paths of every file the most recent
|
|
12
|
+
* global deploy maintains there. On the next deploy the previous inventory is
|
|
13
|
+
* diffed against the current expected file set and **only** previously-recorded,
|
|
14
|
+
* now-orphaned files are deleted.
|
|
15
|
+
*
|
|
16
|
+
* Why this exists (2026-06 Zed fix follow-up): deploy anchors are SHARED
|
|
17
|
+
* directories — `~/.agents/skills/` holds the user's own Zed skills next to
|
|
18
|
+
* agent-config's deployed bundle, `~/.claude/commands/` holds user-authored
|
|
19
|
+
* commands. A naive "delete everything not in the source" sync would destroy
|
|
20
|
+
* user files, so the installer historically deleted nothing — and renamed or
|
|
21
|
+
* removed package skills rotted in place. The inventory provides the ownership
|
|
22
|
+
* proof that makes reaping safe: a path is deleted only if a previous
|
|
23
|
+
* agent-config deploy recorded writing it AND the current deploy no longer
|
|
24
|
+
* ships it.
|
|
25
|
+
*
|
|
26
|
+
* Safety properties:
|
|
27
|
+
*
|
|
28
|
+
* - Never deletes a path that was not recorded by a previous deploy.
|
|
29
|
+
* - Never deletes outside the recorded anchor (resolved containment check).
|
|
30
|
+
* - Never deletes directories — only files/symlinks, then prunes empty dirs.
|
|
31
|
+
* - Anchor moved between installs → no reaping (the old tree is unknown
|
|
32
|
+
* territory; the new inventory simply replaces the record).
|
|
33
|
+
* - Missing / corrupt inventory → no reaping (first run records only).
|
|
34
|
+
*
|
|
35
|
+
* Schema (JSON):
|
|
36
|
+
*
|
|
37
|
+
* {
|
|
38
|
+
* "schema_version": 1,
|
|
39
|
+
* "tools": {
|
|
40
|
+
* "<tool_id>": {
|
|
41
|
+
* "anchor": "/abs/path/to/anchor",
|
|
42
|
+
* "files": ["skills/foo/SKILL.md", ...] // anchor-relative, sorted
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
* }
|
|
46
|
+
*/
|
|
47
|
+
import { randomBytes } from "node:crypto";
|
|
48
|
+
import * as fs from "node:fs";
|
|
49
|
+
import * as os from "node:os";
|
|
50
|
+
import * as path from "node:path";
|
|
51
|
+
import * as user_global_paths from "./user_global_paths.js";
|
|
52
|
+
export const SCHEMA_VERSION = 1;
|
|
53
|
+
export const INVENTORY_BASENAME = "deployed-files.json";
|
|
54
|
+
export const INVENTORY_ENV = "AGENT_CONFIG_DEPLOY_INVENTORY";
|
|
55
|
+
/** Expand a leading `~` like Python's `Path.expanduser()`. */
|
|
56
|
+
function expanduser(p) {
|
|
57
|
+
if (p === "~") {
|
|
58
|
+
return os.homedir();
|
|
59
|
+
}
|
|
60
|
+
if (p.startsWith("~/") || (process.platform === "win32" && p.startsWith("~\\"))) {
|
|
61
|
+
return path.join(os.homedir(), p.slice(2));
|
|
62
|
+
}
|
|
63
|
+
return p;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* `expanduser`, against a STATED home rather than the process's own.
|
|
67
|
+
*
|
|
68
|
+
* `home` omitted or empty falls back to {@link expanduser}, so every existing
|
|
69
|
+
* caller is unchanged.
|
|
70
|
+
*/
|
|
71
|
+
function expanduser_at(p, home) {
|
|
72
|
+
if (home === undefined || home === null || home === "")
|
|
73
|
+
return expanduser(p);
|
|
74
|
+
if (p === "~")
|
|
75
|
+
return home;
|
|
76
|
+
if (p.startsWith("~/") || (process.platform === "win32" && p.startsWith("~\\"))) {
|
|
77
|
+
return path.join(home, p.slice(2));
|
|
78
|
+
}
|
|
79
|
+
return p;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolve a path the way `Path.resolve()` does: expand-free `realpath`-style
|
|
83
|
+
* resolution that follows existing symlinks and normalises `..`, but does not
|
|
84
|
+
* fail when the path does not exist (the trailing non-existent components are
|
|
85
|
+
* resolved lexically). Used for containment checks and anchor comparison.
|
|
86
|
+
*/
|
|
87
|
+
function resolve_path(p) {
|
|
88
|
+
try {
|
|
89
|
+
return fs.realpathSync(p);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Path (or a parent) does not exist — resolve lexically against the
|
|
93
|
+
// longest existing prefix, mirroring Python's strict=False resolve.
|
|
94
|
+
const abs = path.resolve(p);
|
|
95
|
+
const parts = abs.split(path.sep);
|
|
96
|
+
// Find the longest existing ancestor, realpath it, then re-append the
|
|
97
|
+
// remaining (non-existent) components.
|
|
98
|
+
for (let i = parts.length; i > 0; i -= 1) {
|
|
99
|
+
const prefix = parts.slice(0, i).join(path.sep) || path.sep;
|
|
100
|
+
try {
|
|
101
|
+
const real = fs.realpathSync(prefix);
|
|
102
|
+
const rest = parts.slice(i);
|
|
103
|
+
return rest.length > 0 ? path.join(real, ...rest) : real;
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return abs;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Python `Path.exists()` — follows symlinks; False for a dangling symlink. */
|
|
113
|
+
function path_exists(p) {
|
|
114
|
+
try {
|
|
115
|
+
fs.statSync(p);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Canonical inventory location, honoring the test/env override. */
|
|
123
|
+
export function inventory_path(env) {
|
|
124
|
+
const env_map = env ?? process.env;
|
|
125
|
+
const override = env_map[INVENTORY_ENV];
|
|
126
|
+
if (override) {
|
|
127
|
+
return expanduser(override);
|
|
128
|
+
}
|
|
129
|
+
return user_global_paths.write_target(INVENTORY_BASENAME, { env: env ?? null });
|
|
130
|
+
}
|
|
131
|
+
/** Read the inventory; missing or malformed files yield an empty shell. */
|
|
132
|
+
export function load_inventory(p) {
|
|
133
|
+
const target = p ?? inventory_path();
|
|
134
|
+
let data;
|
|
135
|
+
try {
|
|
136
|
+
data = JSON.parse(fs.readFileSync(target, { encoding: "utf-8" }));
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return { schema_version: SCHEMA_VERSION, tools: {} };
|
|
140
|
+
}
|
|
141
|
+
if (typeof data !== "object" ||
|
|
142
|
+
data === null ||
|
|
143
|
+
Array.isArray(data) ||
|
|
144
|
+
typeof data["tools"] !== "object" ||
|
|
145
|
+
data["tools"] === null ||
|
|
146
|
+
Array.isArray(data["tools"])) {
|
|
147
|
+
return { schema_version: SCHEMA_VERSION, tools: {} };
|
|
148
|
+
}
|
|
149
|
+
return data;
|
|
150
|
+
}
|
|
151
|
+
/** Atomically write the inventory (tempfile + rename). */
|
|
152
|
+
export function save_inventory(data, p) {
|
|
153
|
+
const target = p ?? inventory_path();
|
|
154
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
155
|
+
const payload = json_dumps_sorted(data, 2) + "\n";
|
|
156
|
+
const parent = path.dirname(target);
|
|
157
|
+
let fd = null;
|
|
158
|
+
let tmp_name = "";
|
|
159
|
+
for (let attempt = 0; attempt < 32; attempt += 1) {
|
|
160
|
+
tmp_name = path.join(parent, `${path.basename(target)}.${randomBytes(6).toString("hex")}`);
|
|
161
|
+
try {
|
|
162
|
+
fd = fs.openSync(tmp_name, "wx", 0o600);
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
if (err.code === "EEXIST") {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
throw err;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (fd === null) {
|
|
173
|
+
throw new Error("save_inventory: could not create a unique temp file");
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
fs.writeFileSync(fd, payload, { encoding: "utf-8" });
|
|
177
|
+
fs.closeSync(fd);
|
|
178
|
+
fs.renameSync(tmp_name, target);
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
try {
|
|
182
|
+
fs.closeSync(fd);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// fd may already be closed.
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
fs.unlinkSync(tmp_name);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Best-effort cleanup.
|
|
192
|
+
}
|
|
193
|
+
throw err;
|
|
194
|
+
}
|
|
195
|
+
return target;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Serialize like Python's `json.dumps(data, indent=2, sort_keys=True)`.
|
|
199
|
+
* Object keys are emitted in sorted order; arrays keep their order; non-ASCII
|
|
200
|
+
* characters are `\uXXXX`-escaped (Python's `ensure_ascii=True` default).
|
|
201
|
+
* Mirrors Python's separators for `indent` mode (`","` line separator, `": "`
|
|
202
|
+
* key separator).
|
|
203
|
+
*/
|
|
204
|
+
function json_dumps_sorted(value, indent) {
|
|
205
|
+
return render_json(value, indent, 0);
|
|
206
|
+
}
|
|
207
|
+
function render_json(value, indent, depth) {
|
|
208
|
+
if (value === null) {
|
|
209
|
+
return "null";
|
|
210
|
+
}
|
|
211
|
+
if (typeof value === "boolean" || typeof value === "number") {
|
|
212
|
+
return JSON.stringify(value);
|
|
213
|
+
}
|
|
214
|
+
if (typeof value === "string") {
|
|
215
|
+
return json_string_ascii(value);
|
|
216
|
+
}
|
|
217
|
+
const pad = " ".repeat(indent * (depth + 1));
|
|
218
|
+
const close_pad = " ".repeat(indent * depth);
|
|
219
|
+
if (Array.isArray(value)) {
|
|
220
|
+
if (value.length === 0) {
|
|
221
|
+
return "[]";
|
|
222
|
+
}
|
|
223
|
+
const items = value.map((v) => pad + render_json(v, indent, depth + 1));
|
|
224
|
+
return "[\n" + items.join(",\n") + "\n" + close_pad + "]";
|
|
225
|
+
}
|
|
226
|
+
if (typeof value === "object") {
|
|
227
|
+
const obj = value;
|
|
228
|
+
const keys = Object.keys(obj).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
229
|
+
if (keys.length === 0) {
|
|
230
|
+
return "{}";
|
|
231
|
+
}
|
|
232
|
+
const items = keys.map((k) => pad + json_string_ascii(k) + ": " + render_json(obj[k], indent, depth + 1));
|
|
233
|
+
return "{\n" + items.join(",\n") + "\n" + close_pad + "}";
|
|
234
|
+
}
|
|
235
|
+
// Fallback for unsupported types (undefined, function) — Python would raise;
|
|
236
|
+
// here we coerce to null to avoid producing invalid JSON.
|
|
237
|
+
return "null";
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* JSON-encode a string the way Python's `json.dumps(s, ensure_ascii=True)`
|
|
241
|
+
* does: standard escapes plus `\uXXXX` for any codepoint > 0x7e. Astral
|
|
242
|
+
* codepoints are emitted as UTF-16 surrogate pairs, matching CPython.
|
|
243
|
+
*/
|
|
244
|
+
function json_string_ascii(s) {
|
|
245
|
+
// JSON.stringify handles the standard escapes (\", \\, \n, \t, control
|
|
246
|
+
// chars) and surrogate-pair structure; we then escape any remaining
|
|
247
|
+
// non-ASCII code units to \uXXXX, which is exactly Python's ensure_ascii.
|
|
248
|
+
const base = JSON.stringify(s);
|
|
249
|
+
let out = "";
|
|
250
|
+
for (let i = 0; i < base.length; i += 1) {
|
|
251
|
+
const code = base.charCodeAt(i);
|
|
252
|
+
if (code > 0x7e) {
|
|
253
|
+
out += "\\u" + code.toString(16).padStart(4, "0");
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
out += base[i];
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return out;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Anchor-relative paths the deploy of `src` → `<anchor>/<dest_rel>` maintains
|
|
263
|
+
* — written OR skipped-as-identical.
|
|
264
|
+
*
|
|
265
|
+
* Mirrors the traversal of `install._copy_dir_dereferencing_symlinks`:
|
|
266
|
+
* symlinked files resolve to file entries, symlinked subdirectories are walked
|
|
267
|
+
* through their resolved targets. `dest_rel` may be empty (`""`) for plan
|
|
268
|
+
* entries that deploy into the anchor root.
|
|
269
|
+
*
|
|
270
|
+
* `file_filter` MUST be the same predicate the copy was given. This set is what
|
|
271
|
+
* the reaper treats as "should exist"; a file the copy skipped but this set
|
|
272
|
+
* still lists is never reaped, and a file this set omits while the copy wrote it
|
|
273
|
+
* is deleted on the next deploy. Passing the filter to one and not the other is
|
|
274
|
+
* the failure mode the rule-scoping work exists to avoid — see
|
|
275
|
+
* `install._deploy_global_content`, which derives one filter and hands it to
|
|
276
|
+
* both.
|
|
277
|
+
*/
|
|
278
|
+
export function expected_deploy_files(src, dest_rel, file_filter = null) {
|
|
279
|
+
const out = new Set();
|
|
280
|
+
let src_stat;
|
|
281
|
+
try {
|
|
282
|
+
src_stat = fs.statSync(src);
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
// Source does not exist (or a broken symlink) → empty set.
|
|
286
|
+
return out;
|
|
287
|
+
}
|
|
288
|
+
if (!src_stat.isDirectory()) {
|
|
289
|
+
if (file_filter !== null && !file_filter(src)) {
|
|
290
|
+
return out;
|
|
291
|
+
}
|
|
292
|
+
out.add(as_posix(dest_rel));
|
|
293
|
+
return out;
|
|
294
|
+
}
|
|
295
|
+
const _walk = (node, prefix) => {
|
|
296
|
+
const entries = fs.readdirSync(node).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
297
|
+
for (const name of entries) {
|
|
298
|
+
const entry = path.join(node, name);
|
|
299
|
+
const rel = join_rel(prefix, name);
|
|
300
|
+
const lst = fs.lstatSync(entry);
|
|
301
|
+
if (lst.isDirectory() && !lst.isSymbolicLink()) {
|
|
302
|
+
_walk(entry, rel);
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
// Resolve the entry; symlinked dirs are walked through their target.
|
|
306
|
+
let resolved_is_dir = false;
|
|
307
|
+
try {
|
|
308
|
+
resolved_is_dir = fs.statSync(entry).isDirectory();
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
resolved_is_dir = false;
|
|
312
|
+
}
|
|
313
|
+
if (resolved_is_dir) {
|
|
314
|
+
_walk(fs.realpathSync(entry), rel);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
// The predicate sees the SOURCE path, never `rel`: the rule-scope
|
|
318
|
+
// predicate reads the file's own frontmatter tags, so a dest-relative
|
|
319
|
+
// path would not resolve. Same contract as the copy twin.
|
|
320
|
+
if (file_filter !== null && !file_filter(entry)) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
out.add(as_posix(rel));
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
_walk(src, dest_rel);
|
|
327
|
+
return out;
|
|
328
|
+
}
|
|
329
|
+
/** Join a prefix path fragment with a child name, tolerating an empty prefix. */
|
|
330
|
+
function join_rel(prefix, name) {
|
|
331
|
+
return prefix ? path.join(prefix, name) : name;
|
|
332
|
+
}
|
|
333
|
+
/** Convert a path to POSIX (forward-slash) form, like `PurePath.as_posix()`. */
|
|
334
|
+
function as_posix(p) {
|
|
335
|
+
if (p === "") {
|
|
336
|
+
// Python's `Path('').as_posix()` is `"."`.
|
|
337
|
+
return ".";
|
|
338
|
+
}
|
|
339
|
+
return p.split(path.sep).join("/");
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Delete previously-deployed files that the current deploy dropped.
|
|
343
|
+
*
|
|
344
|
+
* Returns the absolute paths actually deleted. Mutates nothing in `inventory`
|
|
345
|
+
* — callers record the new state via {@link record_deploy}.
|
|
346
|
+
*
|
|
347
|
+
* `dry_run=true` computes and returns the would-delete set (only paths that
|
|
348
|
+
* currently exist on disk) WITHOUT unlinking anything or pruning empty
|
|
349
|
+
* directories — the preview surface for `agent-config install --dry-run`. The selection
|
|
350
|
+
* logic (orphan diff, containment proof, directory guard) is identical to the
|
|
351
|
+
* live path, so the preview is exact.
|
|
352
|
+
*/
|
|
353
|
+
export function reap_stale(tool_id, anchor, current_files, inventory, dry_run = false) {
|
|
354
|
+
const tools = inventory["tools"] ?? {};
|
|
355
|
+
const entry = tools[tool_id];
|
|
356
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
357
|
+
return [];
|
|
358
|
+
}
|
|
359
|
+
const e = entry;
|
|
360
|
+
const recorded_anchor = e["anchor"];
|
|
361
|
+
const prev_files = e["files"];
|
|
362
|
+
if (typeof recorded_anchor !== "string" || !Array.isArray(prev_files)) {
|
|
363
|
+
return [];
|
|
364
|
+
}
|
|
365
|
+
const anchor_resolved = resolve_path(expanduser(anchor));
|
|
366
|
+
if (resolve_path(expanduser(recorded_anchor)) !== anchor_resolved) {
|
|
367
|
+
// Anchor moved between installs — the old tree is not provably ours
|
|
368
|
+
// anymore; record-only, never delete.
|
|
369
|
+
return [];
|
|
370
|
+
}
|
|
371
|
+
const deleted = [];
|
|
372
|
+
const prune_candidates = new Set();
|
|
373
|
+
const orphans = difference(prev_files, current_files);
|
|
374
|
+
for (const rel of sorted_strings(orphans)) {
|
|
375
|
+
if (typeof rel !== "string" || !rel || rel.startsWith("/") || rel.startsWith("..")) {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
const target = path.join(anchor_resolved, rel);
|
|
379
|
+
try {
|
|
380
|
+
// Containment proof: the path (sans final component, which may be a
|
|
381
|
+
// dangling symlink) must stay inside the anchor.
|
|
382
|
+
relative_to(resolve_path(path.dirname(target)), anchor_resolved);
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
let lst = null;
|
|
388
|
+
try {
|
|
389
|
+
lst = fs.lstatSync(target);
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
lst = null;
|
|
393
|
+
}
|
|
394
|
+
if (lst && lst.isDirectory() && !lst.isSymbolicLink()) {
|
|
395
|
+
continue; // never delete directories
|
|
396
|
+
}
|
|
397
|
+
if (dry_run) {
|
|
398
|
+
// Preview: report only what is actually on disk and would go.
|
|
399
|
+
if (path_exists(target) || (lst !== null && lst.isSymbolicLink())) {
|
|
400
|
+
deleted.push(target);
|
|
401
|
+
}
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
try {
|
|
405
|
+
fs.unlinkSync(target);
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
deleted.push(target);
|
|
411
|
+
prune_candidates.add(path.dirname(target));
|
|
412
|
+
}
|
|
413
|
+
prune_empty_dirs(prune_candidates, anchor_resolved);
|
|
414
|
+
return deleted;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Marker-based reaping of package-tagged orphans — runs EVERY deploy.
|
|
418
|
+
*
|
|
419
|
+
* This is the self-healing reaping path, complementary to {@link reap_stale}
|
|
420
|
+
* (which can only diff against the *previous* inventory). It is the **only**
|
|
421
|
+
* path with ownership proof independent of inventory history: every deployed
|
|
422
|
+
* `.md` carries the injected `package:` frontmatter tag (install P5.1), so a
|
|
423
|
+
* tagged file absent from the current bundle is provably our orphan regardless
|
|
424
|
+
* of whether any inventory ever recorded it.
|
|
425
|
+
*
|
|
426
|
+
* Why it must run every deploy, not just on first-run: an install that
|
|
427
|
+
* predates the inventory sidecar never recorded its files, so once a tool
|
|
428
|
+
* *does* get an inventory entry, {@link reap_stale} has no record of those
|
|
429
|
+
* legacy files to diff against — they would rot forever (the renamed skills,
|
|
430
|
+
* retired command-as-skill entries, 2026-05-13 colon-named shapes, and
|
|
431
|
+
* post-6.0.0 command renames like `create-pr` → `pr/create`). Running this
|
|
432
|
+
* sweep unconditionally closes that gap; it is idempotent (a clean tree yields
|
|
433
|
+
* no deletions).
|
|
434
|
+
*
|
|
435
|
+
* Deletes `.md` files under `<anchor>/<dest_sub>` that (a) carry
|
|
436
|
+
* `package: <package_tag>` in their frontmatter and (b) are not in the current
|
|
437
|
+
* expected file set; then prunes empty directories. Untagged files
|
|
438
|
+
* (user-authored skills in shared anchors) are never touched. Returns the
|
|
439
|
+
* absolute paths deleted.
|
|
440
|
+
*
|
|
441
|
+
* `dry_run=true` returns the would-delete set (tagged orphans actually present
|
|
442
|
+
* on disk) WITHOUT unlinking or pruning — the preview surface for
|
|
443
|
+
* `agent-config install --dry-run`. Selection logic is identical to the live path.
|
|
444
|
+
*/
|
|
445
|
+
export function reap_tagged_orphans(anchor, dest_subs, current_files, package_tag, dry_run = false) {
|
|
446
|
+
const anchor_resolved = resolve_path(expanduser(anchor));
|
|
447
|
+
const deleted = [];
|
|
448
|
+
const prune_candidates = new Set();
|
|
449
|
+
const needle = `package: ${package_tag}`;
|
|
450
|
+
for (const dest_sub of dest_subs) {
|
|
451
|
+
const root = dest_sub ? path.join(anchor_resolved, dest_sub) : anchor_resolved;
|
|
452
|
+
let root_stat;
|
|
453
|
+
try {
|
|
454
|
+
root_stat = fs.statSync(root);
|
|
455
|
+
}
|
|
456
|
+
catch {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (!root_stat.isDirectory()) {
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
for (const md of rglob_md(root)) {
|
|
463
|
+
let md_lst;
|
|
464
|
+
try {
|
|
465
|
+
md_lst = fs.lstatSync(md);
|
|
466
|
+
}
|
|
467
|
+
catch {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
if (md_lst.isDirectory()) {
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
const rel = relative_to_posix(md, anchor_resolved);
|
|
474
|
+
if (current_files.has(rel)) {
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
try {
|
|
478
|
+
relative_to(resolve_path(path.dirname(md)), anchor_resolved);
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
let head;
|
|
484
|
+
try {
|
|
485
|
+
head = fs.readFileSync(md, { encoding: "utf-8" });
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
if (!head.startsWith("---")) {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
const end = head.indexOf("\n---", 3);
|
|
494
|
+
const block = head.slice(0, end !== -1 ? end : head.length);
|
|
495
|
+
const hit = splitlines(block).some((line) => line.trim() === needle);
|
|
496
|
+
if (!hit) {
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
if (dry_run) {
|
|
500
|
+
deleted.push(md);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
fs.unlinkSync(md);
|
|
505
|
+
}
|
|
506
|
+
catch {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
deleted.push(md);
|
|
510
|
+
prune_candidates.add(path.dirname(md));
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
prune_empty_dirs(prune_candidates, anchor_resolved);
|
|
514
|
+
return deleted;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Upsert the tool's inventory entry; returns the mutated inventory.
|
|
518
|
+
*
|
|
519
|
+
* `anchor` is stored AS GIVEN — pass the unexpanded form (`~/.agents/`) so the
|
|
520
|
+
* inventory content stays identical across machines/homes (GUI/CLI parity) and
|
|
521
|
+
* survives a home relocation. {@link reap_stale} expands the recorded value at
|
|
522
|
+
* comparison time.
|
|
523
|
+
*/
|
|
524
|
+
export function record_deploy(tool_id, anchor, current_files, inventory) {
|
|
525
|
+
if (typeof inventory["tools"] !== "object" ||
|
|
526
|
+
inventory["tools"] === null ||
|
|
527
|
+
Array.isArray(inventory["tools"])) {
|
|
528
|
+
inventory["tools"] = {};
|
|
529
|
+
}
|
|
530
|
+
const tools = inventory["tools"];
|
|
531
|
+
tools[tool_id] = {
|
|
532
|
+
anchor: String(anchor),
|
|
533
|
+
files: sorted_strings([...current_files]),
|
|
534
|
+
};
|
|
535
|
+
inventory["schema_version"] = SCHEMA_VERSION;
|
|
536
|
+
return inventory;
|
|
537
|
+
}
|
|
538
|
+
// --- helpers ---------------------------------------------------------------
|
|
539
|
+
/** Prune now-empty directories up to (exclusive) the anchor. */
|
|
540
|
+
function prune_empty_dirs(prune_candidates, anchor_resolved) {
|
|
541
|
+
const ordered = [...prune_candidates].sort((a, b) => b.split(path.sep).length - a.split(path.sep).length);
|
|
542
|
+
for (const start of ordered) {
|
|
543
|
+
let node = start;
|
|
544
|
+
while (node !== anchor_resolved && is_ancestor(anchor_resolved, node)) {
|
|
545
|
+
try {
|
|
546
|
+
fs.rmdirSync(node); // only succeeds when empty
|
|
547
|
+
}
|
|
548
|
+
catch {
|
|
549
|
+
break;
|
|
550
|
+
}
|
|
551
|
+
node = path.dirname(node);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
/** `anchor in node.parents` — is `anchor` a strict ancestor of `node`? */
|
|
556
|
+
/**
|
|
557
|
+
* Is `node` strictly inside `anchor`? Pure path arithmetic, no I/O — callers
|
|
558
|
+
* pass already-resolved (realpath'd) paths when symlink escape matters.
|
|
559
|
+
*
|
|
560
|
+
* Exported for `install._copy_dir_dereferencing_symlinks`, which must reject a
|
|
561
|
+
* symlink whose target leaves the package root. One definition rather than a
|
|
562
|
+
* second copy of the `path.relative` idiom.
|
|
563
|
+
*/
|
|
564
|
+
export function is_ancestor(anchor, node) {
|
|
565
|
+
const rel = path.relative(anchor, node);
|
|
566
|
+
return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
567
|
+
}
|
|
568
|
+
/** `child.relative_to(parent)` — throws if `child` is not inside `parent`. */
|
|
569
|
+
function relative_to(child, parent) {
|
|
570
|
+
if (child === parent) {
|
|
571
|
+
return "";
|
|
572
|
+
}
|
|
573
|
+
const rel = path.relative(parent, child);
|
|
574
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) {
|
|
575
|
+
throw new Error(`'${child}' is not in the subpath of '${parent}'`);
|
|
576
|
+
}
|
|
577
|
+
return rel;
|
|
578
|
+
}
|
|
579
|
+
/** Anchor-relative POSIX path of `child` under `parent`. */
|
|
580
|
+
function relative_to_posix(child, parent) {
|
|
581
|
+
return path.relative(parent, child).split(path.sep).join("/");
|
|
582
|
+
}
|
|
583
|
+
/** Recursively collect all `*.md` files under `root` (deterministic order). */
|
|
584
|
+
function rglob_md(root) {
|
|
585
|
+
const out = [];
|
|
586
|
+
const walk = (dir) => {
|
|
587
|
+
let names;
|
|
588
|
+
try {
|
|
589
|
+
names = fs.readdirSync(dir).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
590
|
+
}
|
|
591
|
+
catch {
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
for (const name of names) {
|
|
595
|
+
const full = path.join(dir, name);
|
|
596
|
+
let lst;
|
|
597
|
+
try {
|
|
598
|
+
lst = fs.lstatSync(full);
|
|
599
|
+
}
|
|
600
|
+
catch {
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
603
|
+
if (lst.isDirectory() && !lst.isSymbolicLink()) {
|
|
604
|
+
walk(full);
|
|
605
|
+
}
|
|
606
|
+
else if (name.endsWith(".md")) {
|
|
607
|
+
out.push(full);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
walk(root);
|
|
612
|
+
return out;
|
|
613
|
+
}
|
|
614
|
+
/** `set(prev) - current` over string members. */
|
|
615
|
+
function difference(prev, current) {
|
|
616
|
+
const seen = new Set();
|
|
617
|
+
const out = [];
|
|
618
|
+
for (const item of prev) {
|
|
619
|
+
if (typeof item === "string" && current.has(item)) {
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
if (seen.has(item)) {
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
seen.add(item);
|
|
626
|
+
out.push(item);
|
|
627
|
+
}
|
|
628
|
+
return out;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* The anchor-relative paths a previous deploy of `tool_id` recorded.
|
|
632
|
+
*
|
|
633
|
+
* Empty whenever the inventory has no entry, the recorded anchor differs from
|
|
634
|
+
* `anchor`, or the entry is malformed — the same "not provably ours anymore"
|
|
635
|
+
* discipline `reap_stale` applies before it deletes anything. Callers use it
|
|
636
|
+
* to answer "did this package write that file" for a file the CURRENT run did
|
|
637
|
+
* not write.
|
|
638
|
+
*/
|
|
639
|
+
export function recorded_rel_files(tool_id, anchor, inventory) {
|
|
640
|
+
const inv = inventory ?? load_inventory();
|
|
641
|
+
const tools = inv["tools"] ?? {};
|
|
642
|
+
const entry = tools[tool_id];
|
|
643
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
644
|
+
return new Set();
|
|
645
|
+
}
|
|
646
|
+
const e = entry;
|
|
647
|
+
const recorded_anchor = e["anchor"];
|
|
648
|
+
const files = e["files"];
|
|
649
|
+
if (typeof recorded_anchor !== "string" || !Array.isArray(files)) {
|
|
650
|
+
return new Set();
|
|
651
|
+
}
|
|
652
|
+
if (resolve_path(expanduser(recorded_anchor)) !== resolve_path(expanduser(anchor))) {
|
|
653
|
+
return new Set();
|
|
654
|
+
}
|
|
655
|
+
return new Set(files.filter((f) => typeof f === "string"));
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Every file a previous deploy recorded, as ABSOLUTE paths, across all tools.
|
|
659
|
+
*
|
|
660
|
+
* `recorded_rel_files` answers "did this package write that file" for one tool
|
|
661
|
+
* whose anchor the caller already knows. This answers the ownership question a
|
|
662
|
+
* READER has — the installed-layer report and the install receipt both walk
|
|
663
|
+
* host rule directories and hold absolute paths, with no tool id and no anchor
|
|
664
|
+
* in hand — so asking the inventory per tool would mean the reader guessing
|
|
665
|
+
* anchors it never recorded.
|
|
666
|
+
*
|
|
667
|
+
* `home` IS A PARAMETER, AND NOT A CONVENIENCE. The installer records the
|
|
668
|
+
* anchor TILDE-RELATIVE — the real inventory reads `"anchor": "~/.claude/"` —
|
|
669
|
+
* so the recorded path is only meaningful against a stated home. Expanding it
|
|
670
|
+
* against `os.homedir()` makes the answer depend on which process is asking,
|
|
671
|
+
* which is exactly how a reader measuring a staged install under a temporary
|
|
672
|
+
* HOME gets back a set naming the maintainer's own machine and claims nothing.
|
|
673
|
+
* Omitted, it falls back to `os.homedir()`, which is right for a caller asking
|
|
674
|
+
* about the install it is itself running under.
|
|
675
|
+
*
|
|
676
|
+
* BOTH SPELLINGS OF EVERY PATH ARE EMITTED — the symlink-resolved one and the
|
|
677
|
+
* merely-normalised one. Callers compare by set membership against a path they
|
|
678
|
+
* built with `path.join(dir, name)` while walking a directory, which is
|
|
679
|
+
* lexical; the inventory's anchor is resolved with `realpath` the way
|
|
680
|
+
* `recorded_rel_files` resolves its anchor comparison. On macOS those two
|
|
681
|
+
* differ for anything under `/var`, which realpaths to `/private/var`, and a
|
|
682
|
+
* one-spelling set silently claimed nothing there — the reader asked about
|
|
683
|
+
* `/var/...`, the set held `/private/var/...`, and every file read foreign.
|
|
684
|
+
* Emitting both is the cheap direction: a set is a membership test, so a second
|
|
685
|
+
* spelling can only make a true answer reachable, never a false one.
|
|
686
|
+
*
|
|
687
|
+
* A malformed tool entry contributes nothing rather than throwing: a corrupt
|
|
688
|
+
* inventory is "no evidence", never a finding, which is the same discipline
|
|
689
|
+
* `reap_stale` applies before it deletes anything.
|
|
690
|
+
*/
|
|
691
|
+
export function recorded_absolute_files(inventory, home) {
|
|
692
|
+
const inv = inventory ?? load_inventory();
|
|
693
|
+
const tools = inv["tools"] ?? {};
|
|
694
|
+
const out = new Set();
|
|
695
|
+
if (typeof tools !== "object" || tools === null || Array.isArray(tools))
|
|
696
|
+
return out;
|
|
697
|
+
for (const entry of Object.values(tools)) {
|
|
698
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry))
|
|
699
|
+
continue;
|
|
700
|
+
const e = entry;
|
|
701
|
+
const anchor = e["anchor"];
|
|
702
|
+
const files = e["files"];
|
|
703
|
+
if (typeof anchor !== "string" || !Array.isArray(files))
|
|
704
|
+
continue;
|
|
705
|
+
const expanded = expanduser_at(anchor, home);
|
|
706
|
+
for (const rel of files) {
|
|
707
|
+
if (typeof rel !== "string")
|
|
708
|
+
continue;
|
|
709
|
+
const lexical = path.resolve(expanded, rel);
|
|
710
|
+
out.add(lexical);
|
|
711
|
+
out.add(resolve_path(lexical));
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
return out;
|
|
715
|
+
}
|
|
716
|
+
/** Sort string members ascending by codepoint (non-strings filtered out). */
|
|
717
|
+
function sorted_strings(items) {
|
|
718
|
+
return items
|
|
719
|
+
.filter((i) => typeof i === "string")
|
|
720
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
721
|
+
}
|
|
722
|
+
/** `str.splitlines()` — split on `\n`, dropping a trailing empty segment. */
|
|
723
|
+
function splitlines(text) {
|
|
724
|
+
const parts = text.split("\n");
|
|
725
|
+
if (parts.length > 0 && parts[parts.length - 1] === "") {
|
|
726
|
+
parts.pop();
|
|
727
|
+
}
|
|
728
|
+
return parts;
|
|
729
|
+
}
|
|
730
|
+
//# sourceMappingURL=global_deploy_inventory.js.map
|