@mmerterden/multi-agent-pipeline 20.33.0 → 20.35.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/CHANGELOG.md +98 -1
- package/README.md +3 -1
- package/README.tr.md +2 -1
- package/docs/adr/0018-cross-repo-links-not-a-global-graph.md +43 -0
- package/docs/adr/README.md +2 -1
- package/docs/facts.json +5 -4
- package/docs/features.md +1 -1
- package/install/_dev-only-files.mjs +1 -0
- package/install/catalog-history.json +1 -1
- package/install/claude.mjs +24 -2
- package/install/templates/claude-hooks.json +34 -1
- package/manifest.json +393 -339
- package/package.json +3 -1
- package/pipeline/agents/bulk-reader.md +3 -0
- package/pipeline/agents/code-reviewer.md +9 -0
- package/pipeline/agents/explorer.md +4 -0
- package/pipeline/agents/plan-critic.md +4 -2
- package/pipeline/commands/multi-agent/SKILL.md +17 -136
- package/pipeline/commands/multi-agent/channels/SKILL.md +16 -298
- package/pipeline/commands/multi-agent/graph/SKILL.md +5 -2
- package/pipeline/commands/multi-agent/language/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/office-on/SKILL.md +7 -3
- package/pipeline/commands/multi-agent/office-status/SKILL.md +3 -2
- package/pipeline/commands/multi-agent/resume/SKILL.md +8 -22
- package/pipeline/commands/multi-agent/review/SKILL.md +7 -131
- package/pipeline/commands/multi-agent/setup/SKILL.md +19 -224
- package/pipeline/contract/CHANGELOG.md +9 -0
- package/pipeline/contract/README.md +6 -2
- package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
- package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
- package/pipeline/contract/fixtures/error-unsigned.json +1 -1
- package/pipeline/contract/manifest.json +14 -1
- package/pipeline/contract/types/index.d.ts +24 -2
- package/pipeline/lib/json-file-lock.mjs +61 -15
- package/pipeline/lib/office-remote.mjs +228 -0
- package/pipeline/lib/qr-code.mjs +360 -0
- package/pipeline/lib/repo-hygiene.sh +1 -0
- package/pipeline/lib/run-completion.mjs +17 -0
- package/pipeline/multi-agent-refs/channels/generator.md +146 -0
- package/pipeline/multi-agent-refs/channels/issue-comment.md +1 -1
- package/pipeline/multi-agent-refs/channels/menu.md +55 -0
- package/pipeline/multi-agent-refs/channels/multi-repo.md +6 -0
- package/pipeline/multi-agent-refs/channels/preview.md +25 -0
- package/pipeline/multi-agent-refs/channels/reference.md +98 -0
- package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +1 -1
- package/pipeline/multi-agent-refs/features/code-graph.md +27 -0
- package/pipeline/multi-agent-refs/features/office-remote-protocol.md +166 -0
- package/pipeline/multi-agent-refs/features/office-threat-model.md +2 -2
- package/pipeline/multi-agent-refs/features/plan-critic.md +5 -2
- package/pipeline/multi-agent-refs/features/review-delta.md +4 -1
- package/pipeline/multi-agent-refs/features/scope-check.md +25 -1
- package/pipeline/multi-agent-refs/features/verify-by-test.md +10 -0
- package/pipeline/multi-agent-refs/keychain.md +7 -0
- package/pipeline/multi-agent-refs/knowledge.md +9 -0
- package/pipeline/multi-agent-refs/orchestrator/dispatcher.md +163 -0
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +6 -2
- package/pipeline/multi-agent-refs/phases/phase-1-plan.md +8 -10
- package/pipeline/multi-agent-refs/phases/phase-2-dev.md +18 -20
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +20 -14
- package/pipeline/multi-agent-refs/phases/phase-4-commit.md +8 -7
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +6 -3
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/resume/details.md +35 -0
- package/pipeline/multi-agent-refs/review/inputs.md +87 -0
- package/pipeline/multi-agent-refs/review/module-guides.md +25 -0
- package/pipeline/multi-agent-refs/review/valven.md +42 -0
- package/pipeline/multi-agent-refs/rules.md +3 -2
- package/pipeline/multi-agent-refs/setup/accounts.md +27 -0
- package/pipeline/multi-agent-refs/setup/app-store-connect.md +5 -0
- package/pipeline/multi-agent-refs/setup/firebase.md +5 -0
- package/pipeline/multi-agent-refs/setup/google-play.md +4 -0
- package/pipeline/multi-agent-refs/setup/hooks-and-plugins.md +21 -0
- package/pipeline/multi-agent-refs/setup/language.md +46 -0
- package/pipeline/multi-agent-refs/setup/multi-repo-group.md +51 -0
- package/pipeline/multi-agent-refs/setup/summaries.md +63 -0
- package/pipeline/multi-agent-refs/setup/token-save-flow.md +51 -0
- package/pipeline/multi-agent-refs/tracker-contract.md +1 -1
- package/pipeline/office/NOTICE.md +4 -1
- package/pipeline/office/assets/char_12.png +0 -0
- package/pipeline/office/assets/char_13.png +0 -0
- package/pipeline/office/assets/char_14.png +0 -0
- package/pipeline/office/assets/char_15.png +0 -0
- package/pipeline/office/assets/char_16.png +0 -0
- package/pipeline/office/assets/char_17.png +0 -0
- package/pipeline/office/assets/char_18.png +0 -0
- package/pipeline/office/assets/char_19.png +0 -0
- package/pipeline/office/assets/char_20.png +0 -0
- package/pipeline/office/assets/char_21.png +0 -0
- package/pipeline/office/assets/char_22.png +0 -0
- package/pipeline/office/assets/char_23.png +0 -0
- package/pipeline/office/assets/char_24.png +0 -0
- package/pipeline/office/assets/char_25.png +0 -0
- package/pipeline/office/assets/char_26.png +0 -0
- package/pipeline/office/assets/char_27.png +0 -0
- package/pipeline/office/assets/char_28.png +0 -0
- package/pipeline/office/assets/char_29.png +0 -0
- package/pipeline/office/assets/char_30.png +0 -0
- package/pipeline/office/index.html +304 -55
- package/pipeline/office/toolkit.json +1 -1
- package/pipeline/rules/response-shape.md +6 -7
- package/pipeline/schemas/agent-state.schema.json +36 -0
- package/pipeline/schemas/phases.json +4 -4
- package/pipeline/schemas/plan-critique.schema.json +9 -2
- package/pipeline/schemas/planning-output.schema.json +43 -2
- package/pipeline/schemas/pr-reach.schema.json +55 -0
- package/pipeline/schemas/prefs.schema.json +37 -8
- package/pipeline/schemas/reviewer-output.schema.json +20 -2
- package/pipeline/schemas/token-budget.json +4 -4
- package/pipeline/schemas/triage-output.schema.json +32 -3
- package/pipeline/schemas/unattended-policy.json +2 -1
- package/pipeline/scripts/_graph-analysis.mjs +270 -0
- package/pipeline/scripts/_guard_rules.py +449 -1
- package/pipeline/scripts/_memory-policy.mjs +165 -0
- package/pipeline/scripts/_secret-scan.mjs +105 -0
- package/pipeline/scripts/_test-gaming.mjs +36 -0
- package/pipeline/scripts/_unified-diff.mjs +2 -2
- package/pipeline/scripts/agent-guard.py +79 -19
- package/pipeline/scripts/anonymize-findings.mjs +99 -0
- package/pipeline/scripts/answer-check.mjs +113 -0
- package/pipeline/scripts/answer-check.sh +20 -0
- package/pipeline/scripts/autopilot-publish.mjs +9 -2
- package/pipeline/scripts/capture-flush.sh +12 -2
- package/pipeline/scripts/check-read-size.sh +9 -0
- package/pipeline/scripts/code-graph-rules/android.json +8 -3
- package/pipeline/scripts/contract-server.mjs +71 -16
- package/pipeline/scripts/debt-ledger.mjs +323 -0
- package/pipeline/scripts/file-context.mjs +261 -0
- package/pipeline/scripts/file-context.sh +20 -0
- package/pipeline/scripts/gate-ledger.mjs +144 -21
- package/pipeline/scripts/graph-links.mjs +230 -0
- package/pipeline/scripts/graph-query.mjs +133 -1
- package/pipeline/scripts/graph-report.mjs +65 -0
- package/pipeline/scripts/learn-from-transcripts.mjs +12 -48
- package/pipeline/scripts/learnings-ledger.mjs +143 -24
- package/pipeline/scripts/office-build.mjs +276 -5
- package/pipeline/scripts/office-control.mjs +70 -10
- package/pipeline/scripts/office-pair.mjs +407 -0
- package/pipeline/scripts/office-remote-client.mjs +463 -0
- package/pipeline/scripts/phase-tracker.sh +8 -0
- package/pipeline/scripts/phase0-exit-gate.mjs +40 -37
- package/pipeline/scripts/phone-devices.mjs +9 -1
- package/pipeline/scripts/plan-critique-gate.mjs +11 -2
- package/pipeline/scripts/pre-commit-check.sh +28 -2
- package/pipeline/scripts/pre-push-check.sh +6 -12
- package/pipeline/scripts/rework-base.mjs +87 -0
- package/pipeline/scripts/rework-rulings.mjs +106 -0
- package/pipeline/scripts/run-commit-check.mjs +104 -0
- package/pipeline/scripts/run-scope-guard.mjs +58 -3
- package/pipeline/scripts/run-scope-guard.sh +13 -1
- package/pipeline/scripts/scope-check-gate.mjs +213 -2
- package/pipeline/scripts/task-mirror.mjs +106 -15
- package/pipeline/scripts/task-mirror.sh +3 -2
- package/pipeline/scripts/test-stability-gate.mjs +112 -0
- package/pipeline/scripts/triage-memory.mjs +64 -37
- package/pipeline/scripts/update-check.sh +7 -1
- package/pipeline/scripts/update-issue-progress.sh +73 -8
- package/pipeline/scripts/validate-planning.mjs +172 -4
- package/pipeline/scripts/validate-reviewer.mjs +20 -0
- package/pipeline/scripts/validate-triage.mjs +149 -4
- package/pipeline/scripts/work-items.mjs +119 -1
- package/pipeline/scripts/worktree-prepare-all.mjs +200 -0
- package/pipeline/scripts/worktree-prepare.sh +40 -4
- package/pipeline/scripts/write-state.mjs +67 -24
- package/pipeline/skills/.skill-manifest.json +9 -9
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +5 -5
- package/pipeline/skills/shared/core/google-play-compliance/references/rules.yml +1 -1
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +5 -2
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +4 -4
- package/pipeline/skills/shared/core/multi-agent-office-status/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +2 -0
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +4 -4
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +14 -0
- package/pipeline/skills/shared/external/android-architecture/references/patterns.md +6 -0
- package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +10 -0
- package/pipeline/skills/shared/external/android-datastore/references/patterns.md +11 -0
- package/pipeline/skills/shared/external/android-design-tokens-codegen/references/patterns.md +8 -0
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +6 -0
- package/pipeline/skills/shared/external/android-mvi-viewmodel/references/patterns.md +10 -0
- package/pipeline/skills/shared/external/android-performance/references/patterns.md +13 -0
- package/pipeline/skills/shared/external/android-security/references/patterns.md +16 -0
- package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +9 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +12 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +13 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +12 -0
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +9 -0
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +8 -0
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +10 -0
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +21 -0
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +9 -0
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +7 -0
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -2
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +10 -0
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +10 -1
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +22 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +17 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +22 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +17 -0
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +9 -0
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +11 -0
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +13 -0
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +9 -0
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +10 -0
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +15 -0
- package/pipeline/skills/shared/external/compose-components/references/patterns.md +7 -0
- package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +7 -0
- package/pipeline/skills/shared/external/compose-testing/references/patterns.md +15 -0
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +9 -0
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +11 -0
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +10 -0
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +13 -0
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +20 -0
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +16 -0
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +16 -0
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +14 -0
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +13 -0
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +10 -0
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +10 -0
- package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +10 -0
- package/pipeline/skills/shared/external/gradle-kotlin-dsl/references/patterns.md +17 -0
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +12 -0
- package/pipeline/skills/shared/external/hig-app-icons/references/icon-workflow.md +10 -0
- package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +10 -0
- package/pipeline/skills/shared/external/hig-components-layout/references/bars-and-tabs.md +11 -0
- package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +13 -0
- package/pipeline/skills/shared/external/hig-foundations/references/type-color-spacing.md +13 -0
- package/pipeline/skills/shared/external/hig-patterns/references/onboarding-and-states.md +11 -0
- package/pipeline/skills/shared/external/hig-platforms/references/ipad-layout.md +12 -0
- package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +16 -0
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +9 -0
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +18 -0
- package/pipeline/skills/shared/external/ios-accessibility/references/large-content-and-appearance.md +9 -0
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +9 -0
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +7 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +13 -0
- package/pipeline/skills/shared/external/ios-design-review/references/appearance-matrix.md +9 -0
- package/pipeline/skills/shared/external/ios-design-review/references/checklist.md +15 -0
- package/pipeline/skills/shared/external/ios-haptics/references/core-haptics.md +11 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/references/api-map.md +11 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/references/fixed-assumptions.md +15 -0
- package/pipeline/skills/shared/external/ios-iphone-duo/references/poses-and-panes.md +11 -0
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +18 -0
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +19 -0
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +15 -0
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +7 -0
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +8 -0
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +12 -0
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +17 -0
- package/pipeline/skills/shared/external/ios-security/references/app-review-guidelines.md +8 -0
- package/pipeline/skills/shared/external/ios-security/references/cryptokit-advanced.md +14 -0
- package/pipeline/skills/shared/external/ios-security/references/file-storage-patterns.md +8 -0
- package/pipeline/skills/shared/external/ios-security/references/privacy-manifest.md +9 -0
- package/pipeline/skills/shared/external/ios-sf-symbols/references/effects-and-custom-symbols.md +9 -0
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +13 -0
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +8 -0
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +21 -0
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +9 -0
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +12 -0
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +16 -0
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +21 -0
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +10 -0
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +9 -0
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +12 -0
- package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +11 -0
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +11 -0
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +18 -0
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +11 -0
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +11 -0
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +15 -0
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +14 -0
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +14 -0
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +14 -0
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +14 -0
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +10 -0
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +12 -0
- package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +14 -0
- package/pipeline/skills/shared/external/room-database/references/patterns.md +16 -0
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +10 -0
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +10 -0
- package/pipeline/skills/shared/external/spm-build-analysis/references/build-optimization-sources.md +14 -0
- package/pipeline/skills/shared/external/spm-build-analysis/references/spm-analysis-checks.md +19 -0
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +13 -0
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +31 -0
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +8 -0
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +9 -0
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +10 -0
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +8 -0
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +24 -0
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +8 -0
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +14 -0
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +12 -0
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +10 -0
- package/pipeline/skills/shared/external/swift-concurrency-expert/references/swift-6-2-concurrency.md +8 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/actors.md +10 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/cancellation.md +7 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/interop.md +10 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/new-features.md +11 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/structured.md +9 -0
- package/pipeline/skills/shared/external/swift-concurrency-pro/references/testing.md +13 -0
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +7 -0
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +14 -0
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +16 -0
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +17 -0
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +19 -0
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +16 -0
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +19 -0
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +18 -0
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +16 -0
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +17 -0
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +17 -0
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +17 -0
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +18 -0
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +21 -0
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +16 -0
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +16 -0
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +9 -0
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +24 -0
- package/pipeline/skills/shared/external/swift-testing-pro/references/async-tests.md +9 -0
- package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +11 -0
- package/pipeline/skills/shared/external/swift-testing-pro/references/writing-better-tests.md +13 -0
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +8 -0
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +17 -0
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +12 -0
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +11 -0
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +7 -0
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +13 -0
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +24 -0
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +12 -0
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +15 -0
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +15 -0
- package/pipeline/skills/shared/external/swiftui-animation/references/scroll-effects.md +12 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/accessibility-patterns.md +11 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-advanced.md +7 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-basics.md +13 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/animation-transitions.md +9 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/charts-accessibility.md +9 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/charts.md +17 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/image-optimization.md +9 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/latest-apis.md +10 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/layout-best-practices.md +12 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/list-patterns.md +12 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-scenes.md +13 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-views.md +12 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/macos-window-styling.md +12 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/performance-patterns.md +7 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/scroll-patterns.md +9 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/sheet-navigation-patterns.md +10 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/state-management.md +18 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/references/view-structure.md +16 -0
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +11 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +8 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +14 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +9 -0
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +22 -0
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/uikit-glass.md +14 -0
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +10 -0
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +10 -0
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +13 -0
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +10 -0
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +14 -0
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +30 -0
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +16 -0
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +11 -0
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +11 -0
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +10 -0
- package/pipeline/skills/shared/external/swiftui-performance-audit/references/code-smells.md +8 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/app-wiring.md +12 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/menu-bar.md +10 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/navigationstack.md +11 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/scroll-reveal.md +12 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/sheets.md +14 -0
- package/pipeline/skills/shared/external/swiftui-ui-patterns/references/tabview.md +10 -0
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +10 -0
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +13 -0
- package/pipeline/skills/shared/external/swiftui-view-refactor/references/mv-patterns.md +12 -0
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +8 -0
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +8 -0
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +14 -0
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +17 -0
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +11 -0
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +11 -0
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +27 -0
- package/pipeline/skills/shared/external/xcode-build-fixer/references/build-settings-best-practices.md +9 -0
- package/pipeline/skills/shared/external/xcode-build-fixer/references/fix-patterns.md +7 -0
- package/pipeline/skills/shared/external/xcode-build-orchestrator/references/build-settings-best-practices.md +9 -0
- package/pipeline/skills/shared/external/xcode-compilation-analyzer/references/build-optimization-sources.md +14 -0
- package/pipeline/skills/shared/external/xcode-compilation-analyzer/references/code-compilation-checks.md +8 -0
- package/pipeline/skills/shared/external/xcode-project-analyzer/references/build-optimization-sources.md +14 -0
- package/pipeline/skills/shared/external/xcode-project-analyzer/references/build-settings-best-practices.md +9 -0
- package/pipeline/skills/shared/external/xcode-project-analyzer/references/project-audit-checks.md +13 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file file-context.mjs - what the repository's memory says about a file,
|
|
4
|
+
* handed to the model right after it reads that file.
|
|
5
|
+
*
|
|
6
|
+
* PostToolUse on Read. For the file just read it looks up, in the per-repo
|
|
7
|
+
* stores under ~/.claude/memory/multi-agent/<repo-slug>/:
|
|
8
|
+
*
|
|
9
|
+
* learnings-ledger.jsonl durable facts and conventions whose scope covers the file,
|
|
10
|
+
* minus those the feedback suppressed (_memory-policy.mjs)
|
|
11
|
+
* triage-corpus.jsonl the latest review findings recorded against it
|
|
12
|
+
* debt.jsonl open known limits in it (debt-ledger.mjs)
|
|
13
|
+
*
|
|
14
|
+
* and returns at most MAX_LINES of them as PostToolUse additionalContext,
|
|
15
|
+
* inside an <untrusted-data> block: the rows hold model-written text, so they
|
|
16
|
+
* are evidence about the file, never an instruction.
|
|
17
|
+
*
|
|
18
|
+
* When it runs: inside a pipeline run bound to the session (_active-run.mjs),
|
|
19
|
+
* or anywhere when prefs.global.fileContext.enabled is true; never when that
|
|
20
|
+
* flag is false. Each file is answered once per session. The text passes the
|
|
21
|
+
* secret scan before it is handed over; a hit means nothing is said.
|
|
22
|
+
*
|
|
23
|
+
* `file-context.mjs --lines <path>` prints the same lines, secret-scanned and
|
|
24
|
+
* wrapped the same way, for a caller that already decided to show them
|
|
25
|
+
* (check-read-size.sh, when it turns a whole-file read away). It applies no
|
|
26
|
+
* session or run condition, but stays silent when the flag is false.
|
|
27
|
+
*
|
|
28
|
+
* Blocks nothing and prints nothing on any failure: a missing store, a slow
|
|
29
|
+
* scan or a malformed payload all end in exit 0 with no output.
|
|
30
|
+
*
|
|
31
|
+
* @module pipeline/scripts/file-context
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { spawnSync } from "node:child_process";
|
|
35
|
+
import {
|
|
36
|
+
existsSync,
|
|
37
|
+
lstatSync,
|
|
38
|
+
mkdirSync,
|
|
39
|
+
readFileSync,
|
|
40
|
+
realpathSync,
|
|
41
|
+
statSync,
|
|
42
|
+
writeFileSync,
|
|
43
|
+
} from "node:fs";
|
|
44
|
+
import { homedir, tmpdir } from "node:os";
|
|
45
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
46
|
+
|
|
47
|
+
import { wrapUntrusted } from "../lib/untrusted.mjs";
|
|
48
|
+
import { findActiveRun } from "./_active-run.mjs";
|
|
49
|
+
import { ledgerRowId, standing } from "./_memory-policy.mjs";
|
|
50
|
+
import { openScanner } from "./_secret-scan.mjs";
|
|
51
|
+
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
52
|
+
|
|
53
|
+
const MAX_INPUT = 256 * 1024;
|
|
54
|
+
const MAX_LINES = 6;
|
|
55
|
+
const MAX_LINE_CHARS = 220;
|
|
56
|
+
const STORE_MAX_BYTES = 4 * 1024 * 1024;
|
|
57
|
+
|
|
58
|
+
const prefsPath = (env) =>
|
|
59
|
+
env.MULTI_AGENT_PREFS || join(env.HOME || homedir(), ".claude", "multi-agent-preferences.json");
|
|
60
|
+
|
|
61
|
+
/** off | on | run-only, from prefs.global.fileContext.enabled. */
|
|
62
|
+
export function mode(env = process.env) {
|
|
63
|
+
try {
|
|
64
|
+
const flag = JSON.parse(readFileSync(prefsPath(env), "utf8"))?.global?.fileContext?.enabled;
|
|
65
|
+
if (flag === false) return "off";
|
|
66
|
+
if (flag === true) return "on";
|
|
67
|
+
} catch {
|
|
68
|
+
/* no prefs: the default */
|
|
69
|
+
}
|
|
70
|
+
return "run-only";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Repo slug and the file's path inside the repo, as the stores key them. */
|
|
74
|
+
export function locate(filePath) {
|
|
75
|
+
const dir = dirname(filePath);
|
|
76
|
+
const git = (args) =>
|
|
77
|
+
spawnSync("git", ["-C", dir, ...args], { encoding: "utf8", timeout: 2000 }).stdout?.trim();
|
|
78
|
+
const top = git(["rev-parse", "--show-toplevel"]);
|
|
79
|
+
if (!top) return null;
|
|
80
|
+
const common = git(["rev-parse", "--path-format=absolute", "--git-common-dir"]) || "";
|
|
81
|
+
const root = basename(common) === ".git" ? dirname(common) : top;
|
|
82
|
+
// git answers with the resolved path (/private/var on macOS), so the file is
|
|
83
|
+
// resolved the same way before the two are compared.
|
|
84
|
+
return { slug: basename(root), rel: relative(realpathSync(top), realpathSync(filePath)) };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function rows(path) {
|
|
88
|
+
try {
|
|
89
|
+
if (statSync(path).size > STORE_MAX_BYTES) return [];
|
|
90
|
+
return readFileSync(path, "utf8")
|
|
91
|
+
.split("\n")
|
|
92
|
+
.filter((l) => l.trim())
|
|
93
|
+
.flatMap((l) => {
|
|
94
|
+
try {
|
|
95
|
+
return [JSON.parse(l)];
|
|
96
|
+
} catch {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
} catch {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function scopeCovers(scope, rel) {
|
|
106
|
+
if (!scope || scope === "global") return false;
|
|
107
|
+
const dirOf = (g) =>
|
|
108
|
+
String(g)
|
|
109
|
+
.replace(/\/+$/, "")
|
|
110
|
+
.replace(/\/\*+$/, "");
|
|
111
|
+
const s = dirOf(scope);
|
|
112
|
+
return s === rel || rel.startsWith(s + "/");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const clip = (s) => {
|
|
116
|
+
const one = String(s ?? "")
|
|
117
|
+
.replace(/\s+/g, " ")
|
|
118
|
+
.trim();
|
|
119
|
+
return one.length > MAX_LINE_CHARS ? one.slice(0, MAX_LINE_CHARS - 3) + "..." : one;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/** The lines worth saying about one file, most specific first. */
|
|
123
|
+
export function linesFor(storeDir, rel) {
|
|
124
|
+
const out = [];
|
|
125
|
+
const feedback = new Map();
|
|
126
|
+
for (const f of rows(join(storeDir, "learnings-feedback.jsonl"))) {
|
|
127
|
+
if (!feedback.has(f.id)) feedback.set(f.id, []);
|
|
128
|
+
feedback.get(f.id).push(f);
|
|
129
|
+
}
|
|
130
|
+
for (const r of rows(join(storeDir, "learnings-ledger.jsonl"))) {
|
|
131
|
+
if (!scopeCovers(r.scope, rel)) continue;
|
|
132
|
+
if (standing(feedback.get(ledgerRowId(r)) ?? []).suppressed) continue;
|
|
133
|
+
out.push(`${r.kind}: ${clip(r.statement)}`);
|
|
134
|
+
}
|
|
135
|
+
const findings = rows(join(storeDir, "triage-corpus.jsonl"))
|
|
136
|
+
.filter((r) => r.file === rel)
|
|
137
|
+
.slice(-3)
|
|
138
|
+
.reverse();
|
|
139
|
+
for (const f of findings) {
|
|
140
|
+
out.push(`past review (${f.classification}, ${f.severity}): ${clip(f.issue)}`);
|
|
141
|
+
}
|
|
142
|
+
const debt = new Map();
|
|
143
|
+
for (const r of rows(join(storeDir, "debt.jsonl"))) debt.set(r.id, { ...debt.get(r.id), ...r });
|
|
144
|
+
for (const d of debt.values()) {
|
|
145
|
+
if (d.status === "open" && d.file === rel) out.push(`known limit (${d.kind}): ${clip(d.text)}`);
|
|
146
|
+
}
|
|
147
|
+
return out.slice(0, MAX_LINES);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** The cache directory exists, is a real directory and belongs to this user. */
|
|
151
|
+
function ownDir(dir) {
|
|
152
|
+
try {
|
|
153
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
154
|
+
const st = lstatSync(dir);
|
|
155
|
+
return st.isDirectory() && (process.getuid === undefined || st.uid === process.getuid());
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function seenBefore(sessionId, rel, slug) {
|
|
162
|
+
if (!sessionId) return false;
|
|
163
|
+
const uid = process.getuid?.() ?? "user";
|
|
164
|
+
const dir = join(tmpdir(), `multi-agent-file-context-${uid}`);
|
|
165
|
+
const f = join(dir, `${String(sessionId).replace(/[^A-Za-z0-9_-]/g, "")}.json`);
|
|
166
|
+
if (!ownDir(dir)) return false;
|
|
167
|
+
let seen = [];
|
|
168
|
+
try {
|
|
169
|
+
seen = JSON.parse(readFileSync(f, "utf8"));
|
|
170
|
+
} catch {
|
|
171
|
+
/* first file this session */
|
|
172
|
+
}
|
|
173
|
+
const key = `${slug}:${rel}`;
|
|
174
|
+
if (seen.includes(key)) return true;
|
|
175
|
+
try {
|
|
176
|
+
writeFileSync(f, JSON.stringify([...seen, key].slice(-500)), { mode: 0o600 });
|
|
177
|
+
} catch {
|
|
178
|
+
/* a lost cache only means saying it twice */
|
|
179
|
+
}
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** The hook's answer for one payload, or null for silence. */
|
|
184
|
+
export function answer(payload, env = process.env) {
|
|
185
|
+
if (payload?.tool_name !== "Read") return null;
|
|
186
|
+
const filePath = payload?.tool_input?.file_path;
|
|
187
|
+
if (typeof filePath !== "string" || !filePath || !existsSync(filePath)) return null;
|
|
188
|
+
const m = mode(env);
|
|
189
|
+
if (m === "off") return null;
|
|
190
|
+
if (m === "run-only" && !findActiveRun({ sessionId: payload.session_id, cwd: payload.cwd, env }))
|
|
191
|
+
return null;
|
|
192
|
+
const where = locate(filePath);
|
|
193
|
+
if (!where || where.rel.startsWith("..")) return null;
|
|
194
|
+
const storeDir = join(env.HOME || homedir(), ".claude", "memory", "multi-agent", where.slug);
|
|
195
|
+
const lines = linesFor(storeDir, where.rel);
|
|
196
|
+
if (!lines.length || seenBefore(payload.session_id, where.rel, where.slug)) return null;
|
|
197
|
+
const text = lines.map((l) => `- ${l}`).join("\n");
|
|
198
|
+
const scan = openScanner();
|
|
199
|
+
try {
|
|
200
|
+
if (!scan.isClean(text)) return null;
|
|
201
|
+
} finally {
|
|
202
|
+
scan.close();
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
hookSpecificOutput: {
|
|
206
|
+
hookEventName: "PostToolUse",
|
|
207
|
+
additionalContext: wrapUntrusted(`memory:${where.slug}/${where.rel}`, text),
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* The scanned lines for one file inside an untrusted-data block, or "" when
|
|
214
|
+
* file context is off, there is nothing, or the scan refused it.
|
|
215
|
+
*/
|
|
216
|
+
export function blockForPath(filePath, env = process.env) {
|
|
217
|
+
if (mode(env) === "off" || !existsSync(filePath)) return "";
|
|
218
|
+
const where = locate(filePath);
|
|
219
|
+
if (!where || where.rel.startsWith("..")) return "";
|
|
220
|
+
const storeDir = join(env.HOME || homedir(), ".claude", "memory", "multi-agent", where.slug);
|
|
221
|
+
const text = linesFor(storeDir, where.rel)
|
|
222
|
+
.map((l) => `- ${l}`)
|
|
223
|
+
.join("\n");
|
|
224
|
+
if (!text) return "";
|
|
225
|
+
const scan = openScanner();
|
|
226
|
+
try {
|
|
227
|
+
return scan.isClean(text) ? wrapUntrusted(`memory:${where.slug}/${where.rel}`, text) : "";
|
|
228
|
+
} finally {
|
|
229
|
+
scan.close();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function main() {
|
|
234
|
+
const i = process.argv.indexOf("--lines");
|
|
235
|
+
if (i > 0) {
|
|
236
|
+
const block = process.argv[i + 1] ? blockForPath(process.argv[i + 1]) : "";
|
|
237
|
+
if (block) process.stdout.write(block);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
let raw;
|
|
241
|
+
try {
|
|
242
|
+
raw = readFileSync(0, "utf8");
|
|
243
|
+
} catch {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (!raw || raw.length > MAX_INPUT) return;
|
|
247
|
+
let payload;
|
|
248
|
+
try {
|
|
249
|
+
payload = JSON.parse(raw);
|
|
250
|
+
} catch {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const out = answer(payload);
|
|
254
|
+
if (out) process.stdout.write(JSON.stringify(out) + "\n");
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
try {
|
|
258
|
+
if (invokedDirectly(import.meta.url)) main();
|
|
259
|
+
} catch {
|
|
260
|
+
/* silent by contract */
|
|
261
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# file-context.sh - PostToolUse hook (Read) for the pipeline.
|
|
3
|
+
#
|
|
4
|
+
# Hands the model what the repository's memory says about the file it just
|
|
5
|
+
# read: ledger facts, past review findings and open known limits. The logic is
|
|
6
|
+
# in file-context.mjs; this wrapper exists because every hook the pipeline
|
|
7
|
+
# registers is a `bash "$HOME/.<host>/scripts/<name>"` command.
|
|
8
|
+
#
|
|
9
|
+
# Exits 0 on every path: a missing node, a slow scan or any internal error
|
|
10
|
+
# means no context, never a blocked tool call.
|
|
11
|
+
|
|
12
|
+
set -u
|
|
13
|
+
|
|
14
|
+
HERE="$(cd "$(dirname "$0")" 2>/dev/null && pwd || true)"
|
|
15
|
+
CORE="$HERE/file-context.mjs"
|
|
16
|
+
[ -f "$CORE" ] || exit 0
|
|
17
|
+
command -v node >/dev/null 2>&1 || exit 0
|
|
18
|
+
|
|
19
|
+
node "$CORE" 2>/dev/null || true
|
|
20
|
+
exit 0
|
|
@@ -54,14 +54,18 @@
|
|
|
54
54
|
|
|
55
55
|
import { spawnSync } from "node:child_process";
|
|
56
56
|
import {
|
|
57
|
+
copyFileSync,
|
|
57
58
|
existsSync,
|
|
59
|
+
mkdtempSync,
|
|
58
60
|
readFileSync,
|
|
59
61
|
realpathSync,
|
|
60
62
|
renameSync,
|
|
63
|
+
rmSync,
|
|
61
64
|
statSync,
|
|
62
65
|
writeFileSync,
|
|
63
66
|
} from "node:fs";
|
|
64
|
-
import {
|
|
67
|
+
import { tmpdir } from "node:os";
|
|
68
|
+
import { basename, dirname, join } from "node:path";
|
|
65
69
|
|
|
66
70
|
import { decisionEntry, withDecision } from "../lib/decisions.mjs";
|
|
67
71
|
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
@@ -103,31 +107,77 @@ export const ATTENDED_RECORDED = new Set([
|
|
|
103
107
|
"plan-coverage",
|
|
104
108
|
"evidence-gate/build",
|
|
105
109
|
"evidence-gate/test",
|
|
110
|
+
"review-decision",
|
|
106
111
|
]);
|
|
107
112
|
|
|
108
113
|
/** What an attended commit is checked for (pre-commit-check.sh, `evidence`). */
|
|
114
|
+
/**
|
|
115
|
+
* Fix loops with a hard cap (rules.md: three attempts, the fourth failure
|
|
116
|
+
* pauses): consecutive failing verdicts of one of these gates count, and the
|
|
117
|
+
* append that reaches RETRY_CAP pauses the run with a halt reason.
|
|
118
|
+
*/
|
|
119
|
+
export const RETRY_CAPPED = new Set(["evidence-gate/build", "evidence-gate/test"]);
|
|
120
|
+
export const RETRY_CAP = 4;
|
|
121
|
+
|
|
122
|
+
/** Consecutive failing verdicts at the end of `gates` for one gate. */
|
|
123
|
+
export function trailingFailures(gates, gate) {
|
|
124
|
+
let n = 0;
|
|
125
|
+
for (let i = gates.length - 1; i >= 0; i--) {
|
|
126
|
+
const e = gates[i];
|
|
127
|
+
if (!e || e.gate !== gate) continue;
|
|
128
|
+
if (e.verdict !== "fail") break;
|
|
129
|
+
n += 1;
|
|
130
|
+
}
|
|
131
|
+
return n;
|
|
132
|
+
}
|
|
133
|
+
|
|
109
134
|
export const ATTENDED_COMMIT_EVIDENCE = ["evidence-gate/build", "evidence-gate/test"];
|
|
110
135
|
|
|
111
|
-
/**
|
|
112
|
-
export const
|
|
136
|
+
/** Asked for too once the run is in its commit phase: the review verdict. */
|
|
137
|
+
export const ATTENDED_REVIEW_EVIDENCE = "review-decision";
|
|
138
|
+
export const ATTENDED_REVIEW_FROM_PHASE = 4;
|
|
113
139
|
|
|
114
140
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
141
|
+
* prefs.global.attendedCommitGate.mode values. `auto`, the default, blocks
|
|
142
|
+
* the commit when the run is bound to the committing session (the session
|
|
143
|
+
* driving it) and warns otherwise.
|
|
144
|
+
*/
|
|
145
|
+
export const ATTENDED_COMMIT_MODES = ["off", "warn", "block", "auto"];
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The evidence an attended commit on `sha` lacks: every gate in
|
|
149
|
+
* ATTENDED_COMMIT_EVIDENCE, plus the review verdict from the commit phase on,
|
|
150
|
+
* whose latest entry for that sha, attended or not, is missing or not passing.
|
|
151
|
+
* A checkpoint commit during development comes before any review and is held
|
|
152
|
+
* to build and test only.
|
|
118
153
|
*
|
|
119
154
|
* @param {object} state
|
|
120
155
|
* @param {string} sha
|
|
121
156
|
* @returns {string[]}
|
|
122
157
|
*/
|
|
123
|
-
export function attendedEvidenceGaps(state, sha) {
|
|
124
|
-
const
|
|
125
|
-
|
|
158
|
+
export function attendedEvidenceGaps(state, sha, { sameTree } = {}) {
|
|
159
|
+
const wanted = [...ATTENDED_COMMIT_EVIDENCE];
|
|
160
|
+
if (Number(state?.currentPhase) >= ATTENDED_REVIEW_FROM_PHASE)
|
|
161
|
+
wanted.push(ATTENDED_REVIEW_EVIDENCE);
|
|
162
|
+
const asked = (Array.isArray(state?.gates) ? state.gates : []).filter((e) =>
|
|
163
|
+
wanted.includes(e?.gate),
|
|
164
|
+
);
|
|
165
|
+
const latest = sameTree
|
|
166
|
+
? latestByGateWhere(asked, (s) => s === sha || sameTree(s))
|
|
167
|
+
: latestByGate(asked, sha);
|
|
168
|
+
return wanted.filter((g) => {
|
|
126
169
|
const e = latest.get(g);
|
|
127
170
|
return !e || !PASSING.has(e.verdict);
|
|
128
171
|
});
|
|
129
172
|
}
|
|
130
173
|
|
|
174
|
+
/** The mode that applies: an explicit off/warn/block, else block for a bound run. */
|
|
175
|
+
export function effectiveCommitMode(pref, bound) {
|
|
176
|
+
const mode = ATTENDED_COMMIT_MODES.includes(pref) ? pref : "auto";
|
|
177
|
+
if (mode !== "auto") return mode;
|
|
178
|
+
return bound ? "block" : "warn";
|
|
179
|
+
}
|
|
180
|
+
|
|
131
181
|
const QUESTION_ID = /^[a-z][a-z0-9-]*$/;
|
|
132
182
|
const OPTION_ID = /^[a-z0-9][a-z0-9+_-]*$/;
|
|
133
183
|
const QUESTION_KEYS = ["id", "stepId", "text", "kind", "options"];
|
|
@@ -184,6 +234,54 @@ export class LedgerError extends Error {
|
|
|
184
234
|
* HEAD of the repository at `dir`, or null outside one.
|
|
185
235
|
* @param {string} dir
|
|
186
236
|
*/
|
|
237
|
+
/**
|
|
238
|
+
* A predicate: does a recorded sha hold the content this commit records?
|
|
239
|
+
* Yes when its tree is the index's, or the tree `git add -A` would stage from
|
|
240
|
+
* the working tree (built in a throwaway copy of the index, so the real index
|
|
241
|
+
* is untouched). The hook runs before a `git add ... && git commit` line
|
|
242
|
+
* stages anything, and Phase 4's `git reset HEAD~1` leaves a checkpoint
|
|
243
|
+
* commit's new files untracked; both still match the evidence they were
|
|
244
|
+
* tested with, while a file added after the evidence does not. Each sha is
|
|
245
|
+
* asked once; anything git cannot answer is "no".
|
|
246
|
+
*/
|
|
247
|
+
export function sameTreeAs(dir) {
|
|
248
|
+
const run = (args, env) => {
|
|
249
|
+
const r = spawnSync("git", ["-C", dir, ...args], {
|
|
250
|
+
encoding: "utf8",
|
|
251
|
+
timeout: 20000,
|
|
252
|
+
env: env ? { ...process.env, ...env } : process.env,
|
|
253
|
+
});
|
|
254
|
+
return r.status === 0 ? r.stdout.trim() : null;
|
|
255
|
+
};
|
|
256
|
+
const indexTree = run(["write-tree"]);
|
|
257
|
+
let workTree = null;
|
|
258
|
+
const indexPath = run(["rev-parse", "--path-format=absolute", "--git-path", "index"]);
|
|
259
|
+
if (indexPath) {
|
|
260
|
+
const scratch = mkdtempSync(join(tmpdir(), "ma-tree-"));
|
|
261
|
+
const copy = join(scratch, "index");
|
|
262
|
+
try {
|
|
263
|
+
if (existsSync(indexPath)) copyFileSync(indexPath, copy);
|
|
264
|
+
if (run(["add", "-A"], { GIT_INDEX_FILE: copy }) !== null) {
|
|
265
|
+
workTree = run(["write-tree"], { GIT_INDEX_FILE: copy });
|
|
266
|
+
}
|
|
267
|
+
} catch {
|
|
268
|
+
workTree = null;
|
|
269
|
+
} finally {
|
|
270
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
const targets = new Set([indexTree, workTree].filter(Boolean));
|
|
274
|
+
const seen = new Map();
|
|
275
|
+
return (sha) => {
|
|
276
|
+
if (!targets.size || typeof sha !== "string" || !/^[0-9a-f]{7,64}$/.test(sha)) return false;
|
|
277
|
+
if (!seen.has(sha)) {
|
|
278
|
+
const tree = run(["rev-parse", "--verify", "--quiet", `${sha}^{tree}`]);
|
|
279
|
+
seen.set(sha, Boolean(tree) && targets.has(tree));
|
|
280
|
+
}
|
|
281
|
+
return seen.get(sha);
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
187
285
|
export function headSha(dir) {
|
|
188
286
|
const r = spawnSync("git", ["-C", dir, "rev-parse", "HEAD"], {
|
|
189
287
|
encoding: "utf8",
|
|
@@ -399,11 +497,22 @@ export async function record(
|
|
|
399
497
|
detail: detail && typeof detail === "object" ? detail : { value: detail },
|
|
400
498
|
...(attended ? { attended: true } : {}),
|
|
401
499
|
};
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
gates
|
|
405
|
-
|
|
406
|
-
|
|
500
|
+
let capped = false;
|
|
501
|
+
await updateState(path, (s) => {
|
|
502
|
+
const gates = [...(Array.isArray(s.gates) ? s.gates : []), entry];
|
|
503
|
+
const next = { ...s, gates };
|
|
504
|
+
if (
|
|
505
|
+
RETRY_CAPPED.has(gate) &&
|
|
506
|
+
verdict === "fail" &&
|
|
507
|
+
trailingFailures(gates, gate) >= RETRY_CAP
|
|
508
|
+
) {
|
|
509
|
+
capped = true;
|
|
510
|
+
next.status = "paused";
|
|
511
|
+
next.haltReason = `${phaseOf(s)}:retry-cap: ${gate} failed ${RETRY_CAP} times in a row; the fix loop stops here for the user`;
|
|
512
|
+
}
|
|
513
|
+
return next;
|
|
514
|
+
});
|
|
515
|
+
return { written: true, statePath: path, entry, capped };
|
|
407
516
|
}
|
|
408
517
|
|
|
409
518
|
/**
|
|
@@ -494,9 +603,14 @@ function phaseOf(state) {
|
|
|
494
603
|
* Latest entry per gate for one sha. "Latest" is by `at`, then by position.
|
|
495
604
|
*/
|
|
496
605
|
export function latestByGate(gates, sha) {
|
|
606
|
+
return latestByGateWhere(gates, (s) => s === sha);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/** latestByGate over the entries whose sha `accept` takes. */
|
|
610
|
+
export function latestByGateWhere(gates, accept) {
|
|
497
611
|
const out = new Map();
|
|
498
612
|
(Array.isArray(gates) ? gates : []).forEach((e, i) => {
|
|
499
|
-
if (!e || typeof e !== "object" ||
|
|
613
|
+
if (!e || typeof e !== "object" || typeof e.gate !== "string" || !accept(e.sha)) return;
|
|
500
614
|
const prev = out.get(e.gate);
|
|
501
615
|
const t = Date.parse(e.at) || 0;
|
|
502
616
|
if (!prev || t > prev.t || (t === prev.t && i > prev.i)) out.set(e.gate, { e, t, i });
|
|
@@ -570,6 +684,12 @@ async function main(argv) {
|
|
|
570
684
|
// Gates off: nothing is written and nothing is said.
|
|
571
685
|
if (!r.written && r.reason === attendedVerdict(opts.gate).reason) return 0;
|
|
572
686
|
if (!r.written) process.stderr.write(`gate-ledger: nothing written: ${r.reason}\n`);
|
|
687
|
+
if (r.capped) {
|
|
688
|
+
process.stderr.write(
|
|
689
|
+
`gate-ledger: ${opts.gate} failed ${RETRY_CAP} times in a row; the run is paused (retry cap). Report what was tried and ask the user how to continue.\n`,
|
|
690
|
+
);
|
|
691
|
+
return 5;
|
|
692
|
+
}
|
|
573
693
|
return r.written ? 0 : 3;
|
|
574
694
|
}
|
|
575
695
|
if (mode === "check") {
|
|
@@ -619,9 +739,8 @@ async function main(argv) {
|
|
|
619
739
|
// mode that commits nothing, evidence present), 1 warn, 4 block. Never 2
|
|
620
740
|
// or 3 for a missing run: outside the pipeline a commit is none of this
|
|
621
741
|
// hook's business.
|
|
622
|
-
const pref = globalPref("attendedCommitGate.mode", "
|
|
623
|
-
|
|
624
|
-
if (gateMode === "off") return 0;
|
|
742
|
+
const pref = globalPref("attendedCommitGate.mode", "auto");
|
|
743
|
+
if (pref === "off") return 0;
|
|
625
744
|
let session = "";
|
|
626
745
|
if (opts["hook-input"] === "-") {
|
|
627
746
|
try {
|
|
@@ -638,7 +757,11 @@ async function main(argv) {
|
|
|
638
757
|
if (modeEntry(state)?.commits === false) return 0;
|
|
639
758
|
const sha = opts.sha || headSha(repo);
|
|
640
759
|
if (!sha) return 0;
|
|
641
|
-
const
|
|
760
|
+
const launched = process.env.MULTI_AGENT_SESSION_ID || "";
|
|
761
|
+
const bound =
|
|
762
|
+
(session && state.hostSessionId === session) || (launched && state.sessionId === launched);
|
|
763
|
+
const gateMode = effectiveCommitMode(pref, Boolean(bound));
|
|
764
|
+
const missing = attendedEvidenceGaps(state, sha, { sameTree: sameTreeAs(repo) });
|
|
642
765
|
if (opts.json)
|
|
643
766
|
writeFileSync(1, `${JSON.stringify({ statePath: path, sha, gateMode, missing })}\n`);
|
|
644
767
|
if (!missing.length) return 0;
|
|
@@ -647,9 +770,9 @@ async function main(argv) {
|
|
|
647
770
|
2,
|
|
648
771
|
`${[
|
|
649
772
|
`pre-commit-check: ${verb}: the run's gate ledger (${path}) has no passing ${missing.join(" / ")} for HEAD ${sha.slice(0, 12)}.`,
|
|
650
|
-
" Run the build and the tests through evidence-gate.mjs (Phase 2 Gate 1) so the commit rests on recorded evidence.",
|
|
773
|
+
" Run the build and the tests through evidence-gate.mjs (Phase 2 Gate 1), and in the commit phase the review verdict (review-decision-gate.mjs), so the commit rests on recorded evidence.",
|
|
651
774
|
gateMode === "block"
|
|
652
|
-
? " prefs.global.attendedCommitGate.mode
|
|
775
|
+
? " This session drives the run, so the commit waits for the evidence; prefs.global.attendedCommitGate.mode warn lets it through."
|
|
653
776
|
: " The commit goes ahead; prefs.global.attendedCommitGate.mode block refuses it instead.",
|
|
654
777
|
].join("\n")}\n`,
|
|
655
778
|
);
|