@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
|
@@ -526,6 +526,23 @@ fi
|
|
|
526
526
|
# scanned whole.
|
|
527
527
|
UNCHANGED_RENAMES=$(git diff --cached -M --diff-filter=R --name-status 2>/dev/null | awk -F'\t' '$1 == "R100" { print $3 }')
|
|
528
528
|
|
|
529
|
+
# Paths that never belong in a commit, whatever they contain: signing material
|
|
530
|
+
# and keystores, and the dependency and build trees of the iOS and Swift
|
|
531
|
+
# toolchains. Checked by name before the content scan, which skips binaries.
|
|
532
|
+
blocked_path() {
|
|
533
|
+
local f="$1"
|
|
534
|
+
if printf '%s' "$f" | grep -qiE '\.(p12|pfx|p8|mobileprovision|provisionprofile|jks|keystore)$'; then
|
|
535
|
+
echo "BLOCKED: signing material or keystore staged: $f" >&2
|
|
536
|
+
FOUND=1
|
|
537
|
+
elif printf '%s' "$f" | grep -qE '(^|/)(Pods|\.build|DerivedData|\.DerivedData)/'; then
|
|
538
|
+
echo "BLOCKED: dependency or build output staged: $f" >&2
|
|
539
|
+
FOUND=1
|
|
540
|
+
fi
|
|
541
|
+
}
|
|
542
|
+
while IFS= read -r -d '' file; do
|
|
543
|
+
[ -n "$file" ] && blocked_path "$file"
|
|
544
|
+
done < <(git diff --cached --name-only --diff-filter=ACMR -z 2>/dev/null)
|
|
545
|
+
|
|
529
546
|
# Already-staged content - the common case, and the only source when nothing
|
|
530
547
|
# in the triggering command itself runs `git add`.
|
|
531
548
|
while IFS= read -r -d '' file; do
|
|
@@ -717,8 +734,10 @@ fi
|
|
|
717
734
|
|
|
718
735
|
# Attended commit inside a pipeline run: the run's gate ledger should hold a
|
|
719
736
|
# passing build and test verdict for HEAD (evidence-gate.mjs records both in an
|
|
720
|
-
# attended run too)
|
|
721
|
-
#
|
|
737
|
+
# attended run too), and from the commit phase on the review verdict.
|
|
738
|
+
# prefs.global.attendedCommitGate.mode: auto (default) refuses the commit when
|
|
739
|
+
# the committing session drives the run and warns otherwise, warn always lets
|
|
740
|
+
# it through with a note on stderr, block always refuses, off skips the check.
|
|
722
741
|
# Outside a run gate-ledger.mjs says nothing; any error of its own is not a
|
|
723
742
|
# reason to refuse a commit a person is watching.
|
|
724
743
|
if [ "$IS_COMMIT_HOOK" = "1" ] && ! ma_unattended && command -v node >/dev/null 2>&1; then
|
|
@@ -727,6 +746,13 @@ if [ "$IS_COMMIT_HOOK" = "1" ] && ! ma_unattended && command -v node >/dev/null
|
|
|
727
746
|
[ "$?" = "4" ] && exit 2
|
|
728
747
|
fi
|
|
729
748
|
|
|
749
|
+
# A commit inside a live pipeline run is authored by the run's identity
|
|
750
|
+
# (run-commit-check.mjs); outside a bound run it says nothing.
|
|
751
|
+
if [ "$IS_COMMIT_HOOK" = "1" ] && command -v node >/dev/null 2>&1 && [ -f "$PRE_COMMIT_DIR/run-commit-check.mjs" ]; then
|
|
752
|
+
printf '%s' "${HOOK_INPUT:-}" | node "$PRE_COMMIT_DIR/run-commit-check.mjs" --repo "${COMMIT_DIR:-${REPO_ROOT:-$PWD}}"
|
|
753
|
+
[ "$?" = "2" ] && exit 2
|
|
754
|
+
fi
|
|
755
|
+
|
|
730
756
|
# Unattended commit: the verification gates must have passed for this HEAD.
|
|
731
757
|
# The environment is the hook's own, inherited from the process the launcher
|
|
732
758
|
# started, so the run cannot talk its way past it by editing its state. An
|
|
@@ -2,19 +2,13 @@
|
|
|
2
2
|
# pre-push-check.sh - primary gate before every push.
|
|
3
3
|
#
|
|
4
4
|
# Purpose:
|
|
5
|
-
# The
|
|
6
|
-
#
|
|
7
|
-
# finished in about four seconds with zero steps recorded, which is a
|
|
8
|
-
# runner/quota block rather than a test failure. Both are now dormant by
|
|
9
|
-
# declaration too (ADR-0011: the push triggers are commented out). So this
|
|
10
|
-
# hook is not a second opinion - it is the only thing standing between a
|
|
11
|
-
# broken commit and npm.
|
|
5
|
+
# The local gate before every push. The repository's CI workflows are dormant
|
|
6
|
+
# (ADR-0011), so this is what stands between a commit and npm.
|
|
12
7
|
#
|
|
13
|
-
# It
|
|
14
|
-
#
|
|
15
|
-
# `for f in smoke-*.sh` loop cannot tell a passing suite from one that exited
|
|
16
|
-
# having asserted nothing; run-smokes.mjs can.
|
|
17
|
-
# it is trusted.
|
|
8
|
+
# It runs the canonical chain, `npm test`, rather than a hand-picked subset:
|
|
9
|
+
# a subset drifts from the chain as steps are added, and a bare
|
|
10
|
+
# `for f in smoke-*.sh` loop cannot tell a passing suite from one that exited
|
|
11
|
+
# 0 having asserted nothing; run-smokes.mjs can.
|
|
18
12
|
#
|
|
19
13
|
# Two modes, because a gate that runs INSIDE the push is a gate that breaks
|
|
20
14
|
# pushes. Git opens the connection to the remote before this hook fires, so a
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file rework-base.mjs - the tree a rework round started from.
|
|
4
|
+
*
|
|
5
|
+
* scope-check-gate.mjs --rejected compares the rework against the tree the
|
|
6
|
+
* review read, because rejected findings carry that tree's line numbers. Each
|
|
7
|
+
* review round rewrites triage-output.json, so the base is kept per round:
|
|
8
|
+
* `.pipeline/rework-base-<iteration>`. `record` writes HEAD for the round when
|
|
9
|
+
* the round has none yet (a resumed re-entry keeps the base it started from)
|
|
10
|
+
* and prints it; `get` only prints it.
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* rework-base.mjs record --worktree <dir> --iteration <N>
|
|
14
|
+
* rework-base.mjs get --worktree <dir> --iteration <N>
|
|
15
|
+
*
|
|
16
|
+
* Exit: 0 printed, 1 no base recorded for the round (get) or HEAD unreadable
|
|
17
|
+
* (record), 64 usage.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { execFileSync } from "node:child_process";
|
|
21
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
|
|
24
|
+
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
25
|
+
|
|
26
|
+
const SHA = /^[0-9a-f]{40,64}$/;
|
|
27
|
+
|
|
28
|
+
export function basePath(worktree, iteration) {
|
|
29
|
+
return join(worktree, ".pipeline", `rework-base-${iteration}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function read(path) {
|
|
33
|
+
if (!existsSync(path)) return null;
|
|
34
|
+
const sha = readFileSync(path, "utf8").trim();
|
|
35
|
+
return SHA.test(sha) ? sha : null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function record(worktree, iteration) {
|
|
39
|
+
const path = basePath(worktree, iteration);
|
|
40
|
+
const kept = read(path);
|
|
41
|
+
if (kept) return kept;
|
|
42
|
+
const head = execFileSync("git", ["-C", worktree, "rev-parse", "HEAD"], {
|
|
43
|
+
encoding: "utf8",
|
|
44
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
45
|
+
timeout: 30_000,
|
|
46
|
+
}).trim();
|
|
47
|
+
if (!SHA.test(head)) throw new Error("HEAD is not a commit");
|
|
48
|
+
mkdirSync(join(worktree, ".pipeline"), { recursive: true });
|
|
49
|
+
writeFileSync(path, head + "\n");
|
|
50
|
+
return head;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function get(worktree, iteration) {
|
|
54
|
+
return read(basePath(worktree, iteration));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function main() {
|
|
58
|
+
const [cmd, ...rest] = process.argv.slice(2);
|
|
59
|
+
const opt = (f) => {
|
|
60
|
+
const i = rest.indexOf(f);
|
|
61
|
+
return i >= 0 ? rest[i + 1] : undefined;
|
|
62
|
+
};
|
|
63
|
+
const worktree = opt("--worktree");
|
|
64
|
+
const iteration = Number(opt("--iteration"));
|
|
65
|
+
if (
|
|
66
|
+
!["record", "get"].includes(cmd) ||
|
|
67
|
+
rest.length !== 4 ||
|
|
68
|
+
!worktree ||
|
|
69
|
+
!Number.isInteger(iteration) ||
|
|
70
|
+
iteration < 1
|
|
71
|
+
) {
|
|
72
|
+
console.error("usage: rework-base.mjs record|get --worktree <dir> --iteration <N>");
|
|
73
|
+
return 64;
|
|
74
|
+
}
|
|
75
|
+
let sha;
|
|
76
|
+
try {
|
|
77
|
+
sha = cmd === "record" ? record(worktree, iteration) : get(worktree, iteration);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.error(`rework-base: ${err.message}`);
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
if (!sha) return 1;
|
|
83
|
+
process.stdout.write(sha + "\n");
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (invokedDirectly(import.meta.url)) process.exit(main());
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* rework-rulings.mjs - what happens to each open finding when the rework cap
|
|
4
|
+
* is reached.
|
|
5
|
+
*
|
|
6
|
+
* Phase 2 allows a fixed number of rework rounds. At the cap every accepted
|
|
7
|
+
* finding still open gets one ruling, recorded, never dropped:
|
|
8
|
+
*
|
|
9
|
+
* escalate load-bearing: blocking severity, or a security finding
|
|
10
|
+
* (ruleId SEC-* / CON-SEC-*, a security criteriaSource, or the
|
|
11
|
+
* security-auditor's `security` object). The run stops and the
|
|
12
|
+
* user decides.
|
|
13
|
+
* parked anything else. It leaves the loop as a follow-up with its
|
|
14
|
+
* reason, shown before commit (Phase 4 Step 0b), carried in the
|
|
15
|
+
* PR follow-ups and recorded in the debt list, so the run can finish instead of stopping on a
|
|
16
|
+
* finding that is safe to defer.
|
|
17
|
+
*
|
|
18
|
+
* The run escalates when any ruling is `escalate`; otherwise it continues.
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* rework-rulings.mjs --triage <triage-output.json> [--state <agent-state.json>]
|
|
22
|
+
*
|
|
23
|
+
* --state records the result as reviewIterations[-1].rulings.
|
|
24
|
+
*
|
|
25
|
+
* Output: {escalate, parked, rulings[]} as JSON on stdout.
|
|
26
|
+
* Exit: 0 decided (either way) · 2 usage or unreadable triage · 3 state write failed
|
|
27
|
+
*
|
|
28
|
+
* @module pipeline/scripts/rework-rulings
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
32
|
+
import { readRegularJson } from "../lib/regular-file.mjs";
|
|
33
|
+
import { updateState } from "./gate-ledger.mjs";
|
|
34
|
+
|
|
35
|
+
const SECURITY_RULE = /^(CON-)?SEC-/i;
|
|
36
|
+
|
|
37
|
+
/** True when a finding may not leave the loop without the user. */
|
|
38
|
+
export function loadBearing(f) {
|
|
39
|
+
if (f?.severity === "blocking") return true;
|
|
40
|
+
if (typeof f?.ruleId === "string" && SECURITY_RULE.test(f.ruleId)) return true;
|
|
41
|
+
if (f?.security && typeof f.security === "object") return true;
|
|
42
|
+
return typeof f?.criteriaSource === "string" && /security/i.test(f.criteriaSource);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** One ruling per accepted finding of a triage output. */
|
|
46
|
+
export function rule(triage) {
|
|
47
|
+
const rulings = (triage?.accepted ?? []).map((f) => {
|
|
48
|
+
const escalate = loadBearing(f);
|
|
49
|
+
return {
|
|
50
|
+
fingerprint: f.fingerprint ?? null,
|
|
51
|
+
file: f.file ?? null,
|
|
52
|
+
line: Number.isInteger(f.line) ? f.line : null,
|
|
53
|
+
severity: f.severity ?? null,
|
|
54
|
+
ruling: escalate ? "escalate" : "parked",
|
|
55
|
+
reason: escalate
|
|
56
|
+
? f.severity === "blocking"
|
|
57
|
+
? "blocking finding open at the rework cap"
|
|
58
|
+
: "security finding open at the rework cap"
|
|
59
|
+
: `rework cap reached; ${f.severity ?? "unrated"} finding parked as a follow-up`,
|
|
60
|
+
issue: f.issue ?? "",
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
escalate: rulings.some((r) => r.ruling === "escalate"),
|
|
65
|
+
parked: rulings.filter((r) => r.ruling === "parked").length,
|
|
66
|
+
rulings,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function flag(argv, name) {
|
|
71
|
+
const i = argv.indexOf(`--${name}`);
|
|
72
|
+
return i >= 0 ? argv[i + 1] : undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (invokedDirectly(import.meta.url)) {
|
|
76
|
+
const argv = process.argv.slice(2);
|
|
77
|
+
const triagePath = flag(argv, "triage");
|
|
78
|
+
if (!triagePath) {
|
|
79
|
+
console.error("usage: rework-rulings.mjs --triage <path> [--state <path>]");
|
|
80
|
+
process.exit(2);
|
|
81
|
+
}
|
|
82
|
+
const triage = readRegularJson(triagePath, null);
|
|
83
|
+
if (!triage || !Array.isArray(triage.accepted)) {
|
|
84
|
+
console.error(`rework-rulings: no accepted[] in ${triagePath}`);
|
|
85
|
+
process.exit(2);
|
|
86
|
+
}
|
|
87
|
+
const result = rule(triage);
|
|
88
|
+
const statePath = flag(argv, "state");
|
|
89
|
+
if (statePath) {
|
|
90
|
+
try {
|
|
91
|
+
await updateState(statePath, (s) => {
|
|
92
|
+
const iterations = Array.isArray(s.reviewIterations) ? [...s.reviewIterations] : [];
|
|
93
|
+
if (!iterations.length) iterations.push({ iteration: 1 });
|
|
94
|
+
iterations[iterations.length - 1] = {
|
|
95
|
+
...iterations[iterations.length - 1],
|
|
96
|
+
rulings: result.rulings,
|
|
97
|
+
};
|
|
98
|
+
return { ...s, reviewIterations: iterations };
|
|
99
|
+
});
|
|
100
|
+
} catch (e) {
|
|
101
|
+
console.error(`rework-rulings: state not written: ${e.message}`);
|
|
102
|
+
process.exitCode = 3;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
process.stdout.write(JSON.stringify(result) + "\n");
|
|
106
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @file run-commit-check.mjs - a commit inside a pipeline run is authored by
|
|
4
|
+
* the identity Phase 0 chose for it.
|
|
5
|
+
*
|
|
6
|
+
* Called by pre-commit-check.sh with the hook payload on stdin. For a `git
|
|
7
|
+
* commit` made in the session a live run is bound to, the author git will
|
|
8
|
+
* record (`--author`, `-c user.email=`, else `git var GIT_AUTHOR_IDENT` in the
|
|
9
|
+
* repository) must carry the run's identity email (`projects[].identity` for
|
|
10
|
+
* the repository's worktree, else `identity`). Outside a bound run, for a run
|
|
11
|
+
* that is not live, or with no identity recorded, it says nothing.
|
|
12
|
+
*
|
|
13
|
+
* Usage: run-commit-check.mjs --repo <dir> < hook-payload.json
|
|
14
|
+
* Exit: 0 fine or not judged; 2 the author is not the run's identity.
|
|
15
|
+
*
|
|
16
|
+
* @module pipeline/scripts/run-commit-check
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { spawnSync } from "node:child_process";
|
|
20
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
21
|
+
import { resolve } from "node:path";
|
|
22
|
+
|
|
23
|
+
import { invokedDirectly } from "../lib/invoked-directly.mjs";
|
|
24
|
+
import { findActiveRun } from "./_active-run.mjs";
|
|
25
|
+
|
|
26
|
+
const SESSION_BOUND = new Set(["session", "host-session"]);
|
|
27
|
+
const LIVE = new Set(["in_progress", "awaiting_input"]);
|
|
28
|
+
const COMMIT = /\bgit\b(?:\s+-[cC]\s+\S+|\s+--?[\w-]+(?:=\S+)?)*\s+commit\b/;
|
|
29
|
+
|
|
30
|
+
const real = (p) => {
|
|
31
|
+
try {
|
|
32
|
+
return realpathSync(resolve(p));
|
|
33
|
+
} catch {
|
|
34
|
+
return resolve(p);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** The author email this command makes git record, or null to ask git. */
|
|
39
|
+
export function commandAuthor(command) {
|
|
40
|
+
const author = /--author[=\s]+(['"]?)[^<'"]*<([^>]+)>\1/.exec(command);
|
|
41
|
+
if (author) return author[2].trim();
|
|
42
|
+
const cfg = /-c\s+user\.email=(['"]?)([^\s'"]+)\1/.exec(command);
|
|
43
|
+
return cfg ? cfg[2].trim() : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The identity email the run expects for a commit in `repo`, or null. */
|
|
47
|
+
export function expectedEmail(state, repo) {
|
|
48
|
+
const here = real(repo);
|
|
49
|
+
for (const p of Array.isArray(state.projects) ? state.projects : []) {
|
|
50
|
+
if (p?.worktreePath && real(p.worktreePath) === here && p.identity?.email)
|
|
51
|
+
return p.identity.email;
|
|
52
|
+
}
|
|
53
|
+
return typeof state.identity?.email === "string" && state.identity.email
|
|
54
|
+
? state.identity.email
|
|
55
|
+
: null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function gitAuthorEmail(repo) {
|
|
59
|
+
const r = spawnSync("git", ["-C", repo, "var", "GIT_AUTHOR_IDENT"], {
|
|
60
|
+
encoding: "utf8",
|
|
61
|
+
timeout: 5000,
|
|
62
|
+
});
|
|
63
|
+
return /<([^>]*)>/.exec(r.stdout || "")?.[1]?.trim() || null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** The refusal line, or null. */
|
|
67
|
+
export function verdict(payload, repo, env = process.env) {
|
|
68
|
+
const command = payload?.tool_input?.command;
|
|
69
|
+
if (typeof command !== "string" || !COMMIT.test(command)) return null;
|
|
70
|
+
const run = findActiveRun({
|
|
71
|
+
sessionId: typeof payload.session_id === "string" ? payload.session_id : null,
|
|
72
|
+
cwd: typeof payload.cwd === "string" ? payload.cwd : repo,
|
|
73
|
+
env,
|
|
74
|
+
});
|
|
75
|
+
if (!run || !SESSION_BOUND.has(run.matchedBy) || !LIVE.has(run.state?.status)) return null;
|
|
76
|
+
const want = expectedEmail(run.state, repo);
|
|
77
|
+
if (!want) return null;
|
|
78
|
+
const got = commandAuthor(command) || gitAuthorEmail(repo);
|
|
79
|
+
if (!got || got.toLowerCase() === want.toLowerCase()) return null;
|
|
80
|
+
return `BLOCKED: this commit would be authored by ${got}, and run ${run.state.taskId || run.statePath} commits as ${want} (the identity chosen in Phase 0). Set the worktree's user.email to it, or drop the override.`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function main(argv) {
|
|
84
|
+
const i = argv.indexOf("--repo");
|
|
85
|
+
const repo = i >= 0 && argv[i + 1] ? argv[i + 1] : process.cwd();
|
|
86
|
+
let payload;
|
|
87
|
+
try {
|
|
88
|
+
payload = JSON.parse(readFileSync(0, "utf8"));
|
|
89
|
+
} catch {
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
const line = verdict(payload, repo);
|
|
93
|
+
if (!line) return 0;
|
|
94
|
+
process.stderr.write(`${line}\n`);
|
|
95
|
+
return 2;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (invokedDirectly(import.meta.url)) {
|
|
99
|
+
try {
|
|
100
|
+
process.exitCode = main(process.argv.slice(2));
|
|
101
|
+
} catch {
|
|
102
|
+
process.exitCode = 0;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -51,6 +51,12 @@ const FIGMA_TOOL = /^mcp__.*figma/i;
|
|
|
51
51
|
const SESSION_BOUND = new Set(["session", "host-session"]);
|
|
52
52
|
const LIVE = new Set(["in_progress", "awaiting_input"]);
|
|
53
53
|
const FILE_TOOLS = new Set(["Edit", "Write", "NotebookEdit", "MultiEdit"]);
|
|
54
|
+
const STATE_FILES = new Set(["agent-state.json", "tracker-state.json"]);
|
|
55
|
+
const STATE_REDIRECT =
|
|
56
|
+
/(?:>>?|\btee\s+(?:-a\s+)?)\s*['"]?[^\s'"|;&]*(?:agent|tracker)-state\.json\b/;
|
|
57
|
+
const FIGMA_URL = /\bhttps?:\/\/(?:[\w-]+\.)*figma\.com(?=[/:?#\s'"]|$)/i;
|
|
58
|
+
const ADD_ALL = /\bgit\s+(?:-C\s+\S+\s+)?add\s+(?:[^;&|\n]*\s)?(?:-A|--all|\.)(?=$|[\s;&|])/;
|
|
59
|
+
const HTTP_CLIENT = /(?:^|[\s;&|(])(?:curl|wget|http|https|xh)\s/;
|
|
54
60
|
|
|
55
61
|
const deny = (reason) => ({
|
|
56
62
|
hookSpecificOutput: {
|
|
@@ -76,7 +82,39 @@ async function recordMcpCall(statePath, tool, phase) {
|
|
|
76
82
|
});
|
|
77
83
|
}
|
|
78
84
|
|
|
79
|
-
|
|
85
|
+
/** A Figma design read over HTTP: a WebFetch of figma.com, or curl and the like at it. */
|
|
86
|
+
function figmaOverHttp(payload) {
|
|
87
|
+
const ti = payload.tool_input || {};
|
|
88
|
+
if (payload.tool_name === "WebFetch") return typeof ti.url === "string" && FIGMA_URL.test(ti.url);
|
|
89
|
+
if (payload.tool_name !== "Bash" || typeof ti.command !== "string") return false;
|
|
90
|
+
return HTTP_CLIENT.test(ti.command) && FIGMA_URL.test(ti.command);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** An autopilot run answers its own questions: it derives, or it records a halt. */
|
|
94
|
+
function askDecision(run) {
|
|
95
|
+
const s = run.state;
|
|
96
|
+
if (!LIVE.has(s.status) || modeOf(s) !== "autopilot") return null;
|
|
97
|
+
return deny(
|
|
98
|
+
`run ${s.taskId || run.statePath} is on autopilot, which asks nobody. Derive the answer from the analysis, the repo and the preferences, or record a halt (status "paused" with a haltReason) for a decision only the user can make.`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** A write to run state that bypasses write-state.mjs, or null. */
|
|
103
|
+
function stateWriteDecision(payload) {
|
|
104
|
+
const ti = payload.tool_input || {};
|
|
105
|
+
const raw = FILE_TOOLS.has(payload.tool_name) ? ti.file_path || ti.notebook_path : null;
|
|
106
|
+
const byFile = typeof raw === "string" && STATE_FILES.has(basename(raw));
|
|
107
|
+
const byShell =
|
|
108
|
+
payload.tool_name === "Bash" &&
|
|
109
|
+
typeof ti.command === "string" &&
|
|
110
|
+
STATE_REDIRECT.test(ti.command);
|
|
111
|
+
if (!byFile && !byShell) return null;
|
|
112
|
+
return deny(
|
|
113
|
+
'run state is written through write-state.mjs only, which locks the file, merges the patch and refuses unearned phase moves; pipe the patch into node "$HOME/.claude/scripts/write-state.mjs" <path> instead.',
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function figmaDecision(payload, run, { record = true } = {}) {
|
|
80
118
|
const tool = payload.tool_name;
|
|
81
119
|
const state = run.state;
|
|
82
120
|
// A finished, failed or abandoned run governs nothing and records nothing.
|
|
@@ -88,7 +126,7 @@ async function figmaDecision(payload, run) {
|
|
|
88
126
|
`${tool} is a Figma call at Phase ${at} of run ${state.taskId || run.statePath}. The design is read during analysis only (through Phase ${figmaThroughPhase()}); later phases work from the analysis document and the repo's Code Connect mappings. If a variant or value is missing, halt and re-run /multi-agent:analysis.`,
|
|
89
127
|
);
|
|
90
128
|
}
|
|
91
|
-
await recordMcpCall(run.statePath, tool, Math.min(5, Math.max(0, at)));
|
|
129
|
+
if (record) await recordMcpCall(run.statePath, tool, Math.min(5, Math.max(0, at)));
|
|
92
130
|
return null;
|
|
93
131
|
}
|
|
94
132
|
|
|
@@ -152,8 +190,16 @@ function boundaryDecision(payload, run, env) {
|
|
|
152
190
|
export async function decide(payload, env = process.env) {
|
|
153
191
|
if (!payload || typeof payload !== "object") return null;
|
|
154
192
|
const tool = typeof payload.tool_name === "string" ? payload.tool_name : "";
|
|
193
|
+
const stateWrite = stateWriteDecision(payload);
|
|
194
|
+
if (stateWrite) return stateWrite;
|
|
155
195
|
const figma = FIGMA_TOOL.test(tool);
|
|
156
|
-
|
|
196
|
+
const figmaHttp = !figma && figmaOverHttp(payload);
|
|
197
|
+
const asking = tool === "AskUserQuestion";
|
|
198
|
+
const addAll =
|
|
199
|
+
tool === "Bash" &&
|
|
200
|
+
typeof payload.tool_input?.command === "string" &&
|
|
201
|
+
ADD_ALL.test(payload.tool_input.command);
|
|
202
|
+
if (!figma && !figmaHttp && !asking && !addAll && !FILE_TOOLS.has(tool)) return null;
|
|
157
203
|
const run = findActiveRun({
|
|
158
204
|
sessionId: typeof payload.session_id === "string" ? payload.session_id : null,
|
|
159
205
|
cwd: typeof payload.cwd === "string" ? payload.cwd : null,
|
|
@@ -162,6 +208,15 @@ export async function decide(payload, env = process.env) {
|
|
|
162
208
|
// Only a run bound to this session: an old local-mode run matched by its
|
|
163
209
|
// worktree (the project root) must not govern every later session there.
|
|
164
210
|
if (!run || !SESSION_BOUND.has(run.matchedBy)) return null;
|
|
211
|
+
if (asking) return askDecision(run);
|
|
212
|
+
if (addAll) {
|
|
213
|
+
return LIVE.has(run.state.status)
|
|
214
|
+
? deny(
|
|
215
|
+
`run ${run.state.taskId || run.statePath} stages the task's files by name: git add -A, --all and . also take agent artefacts and anything sensitive in the tree.`,
|
|
216
|
+
)
|
|
217
|
+
: null;
|
|
218
|
+
}
|
|
219
|
+
if (figmaHttp) return figmaDecision(payload, run, { record: false });
|
|
165
220
|
return figma ? figmaDecision(payload, run) : boundaryDecision(payload, run, env);
|
|
166
221
|
}
|
|
167
222
|
|
|
@@ -19,5 +19,17 @@ CORE="$HERE/run-scope-guard.mjs"
|
|
|
19
19
|
[ -f "$CORE" ] || exit 0
|
|
20
20
|
command -v node >/dev/null 2>&1 || exit 0
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
# Most Bash and WebFetch calls concern neither Figma nor run state; those end
|
|
23
|
+
# here without starting node.
|
|
24
|
+
INPUT="$(cat)"
|
|
25
|
+
case "$INPUT" in
|
|
26
|
+
*'"tool_name":"Bash"'* | *'"tool_name": "Bash"'* | *'"tool_name":"WebFetch"'* | *'"tool_name": "WebFetch"'*)
|
|
27
|
+
case "$INPUT" in
|
|
28
|
+
*[Ff]igma* | *agent-state.json* | *tracker-state.json* | *" add "*) ;;
|
|
29
|
+
*) exit 0 ;;
|
|
30
|
+
esac
|
|
31
|
+
;;
|
|
32
|
+
esac
|
|
33
|
+
|
|
34
|
+
printf '%s' "$INPUT" | node "$CORE" 2>/dev/null || true
|
|
23
35
|
exit 0
|