@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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Generated by pipeline/contract/build.mjs from pipeline/schemas/*.schema.json.
|
|
2
2
|
// Do not edit: change the schema and run `node pipeline/contract/build.mjs --write`.
|
|
3
3
|
|
|
4
|
-
export type ContractVersion = "1.
|
|
5
|
-
export type SurfaceId = "runs" | "run" | "commands" | "questions" | "issues" | "worktrees" | "launch-spec" | "repos" | "repo-add" | "repo-remove" | "launch" | "answer" | "run-log" | "resume" | "kill" | "gc" | "autopilot" | "autopilot-off" | "phone-runs" | "phone-run" | "phone-answer" | "phone-launch" | "autopilot-on" | "steer" | "activity" | "activity-stream" | "agent-chat" | "routines" | "routine-delete" | "jobs" | "job-start" | "stack" | "stack-set" | "ledger" | "system" | "prune-logs" | "settings" | "settings-set" | "credentials" | "memory" | "run-results" | "run-evidence" | "review-verdict" | "issue-maturity" | "prs" | "tools" | "tool-call" | "service-confluence" | "service-crashlytics" | "service-figma" | "permissions";
|
|
4
|
+
export type ContractVersion = "1.7.0";
|
|
5
|
+
export type SurfaceId = "runs" | "run" | "commands" | "questions" | "issues" | "worktrees" | "launch-spec" | "repos" | "repo-add" | "repo-remove" | "launch" | "answer" | "run-log" | "resume" | "kill" | "gc" | "autopilot" | "autopilot-off" | "phone-runs" | "phone-run" | "phone-answer" | "phone-launch" | "autopilot-on" | "steer" | "activity" | "activity-stream" | "agent-chat" | "routines" | "routine-delete" | "jobs" | "job-start" | "stack" | "stack-set" | "ledger" | "system" | "prune-logs" | "settings" | "settings-set" | "credentials" | "memory" | "run-results" | "run-evidence" | "review-verdict" | "issue-maturity" | "prs" | "prs-reach" | "tools" | "tool-call" | "service-confluence" | "service-crashlytics" | "service-figma" | "permissions";
|
|
6
6
|
|
|
7
7
|
/** What `runs-index.mjs --json` prints: every run under the log root and the unattended log root (one record per task id), grouped per status/SKILL.md 3b. Fields are only ever added - a decoder ignores keys it does not know. `--redact` drops every x-sensitivity local field (and `logsRoot`) and scrubs the free text in the title, `now`, sub-step names, task subjects and the pending question. */
|
|
8
8
|
export interface RunsIndex {
|
|
@@ -1202,6 +1202,28 @@ export interface Prs {
|
|
|
1202
1202
|
}>;
|
|
1203
1203
|
}
|
|
1204
1204
|
|
|
1205
|
+
/** What GET /v1/prs/reach returns (`work-items.mjs reach`): for each open GitHub pull request (at most 20), how many files in the repository's own code graph depend on what it changes, widest first. Changed paths serve only as keys into the local graph and are never returned. A pull request that cannot be measured carries reach null and its reason. */
|
|
1206
|
+
export interface PrReach {
|
|
1207
|
+
contractVersion: string;
|
|
1208
|
+
/** Reverse-dependency depth the count was taken at. */
|
|
1209
|
+
depth: number;
|
|
1210
|
+
items: Array<{
|
|
1211
|
+
source: "github" | "bitbucket";
|
|
1212
|
+
repo: string;
|
|
1213
|
+
number: number;
|
|
1214
|
+
/** The knowledge-folder project whose graph answered, or null. */
|
|
1215
|
+
project: string | null;
|
|
1216
|
+
/** Files the pull request changes. */
|
|
1217
|
+
changed?: number;
|
|
1218
|
+
/** Of those, files the graph knows. */
|
|
1219
|
+
inGraph?: number;
|
|
1220
|
+
/** Files that depend on the changed ones, within depth. Null when not measured. */
|
|
1221
|
+
reach: number | null;
|
|
1222
|
+
/** Why reach is null. */
|
|
1223
|
+
reason?: string;
|
|
1224
|
+
}>;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1205
1227
|
/** The body of POST /v1/runs/{id}/review-verdict: empty for the preview, confirmToken to post. The verdict is never chosen by the request; it follows from the review's recorded findings. */
|
|
1206
1228
|
export interface ReviewVerdictRequest {
|
|
1207
1229
|
contractVersion: string;
|
|
@@ -18,9 +18,12 @@
|
|
|
18
18
|
|
|
19
19
|
import {
|
|
20
20
|
chmodSync,
|
|
21
|
+
closeSync,
|
|
22
|
+
fstatSync,
|
|
21
23
|
linkSync,
|
|
22
24
|
lstatSync,
|
|
23
25
|
mkdirSync,
|
|
26
|
+
openSync,
|
|
24
27
|
readFileSync,
|
|
25
28
|
readlinkSync,
|
|
26
29
|
realpathSync,
|
|
@@ -47,22 +50,70 @@ export class FileLockTimeout extends Error {
|
|
|
47
50
|
|
|
48
51
|
const pause = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
49
52
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
/**
|
|
54
|
+
* The PID inside a lock file and that file's identity, read through one
|
|
55
|
+
* descriptor. Read by path twice, the PID can come from a lock that was
|
|
56
|
+
* released in between and the identity from the one acquired after it, which
|
|
57
|
+
* makes a live lock look like a dead holder's.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} lockPath
|
|
60
|
+
* @returns {{pid: number, ino: number, mtimeMs: number} | null}
|
|
61
|
+
*/
|
|
62
|
+
export function readLockOwner(lockPath) {
|
|
63
|
+
let fd;
|
|
53
64
|
try {
|
|
54
|
-
|
|
55
|
-
st =
|
|
65
|
+
fd = openSync(lockPath, "r");
|
|
66
|
+
const st = fstatSync(fd);
|
|
67
|
+
const pid = parseInt(readFileSync(fd, "utf8").trim(), 10);
|
|
68
|
+
return { pid, ino: st.ino, mtimeMs: st.mtimeMs };
|
|
56
69
|
} catch {
|
|
57
70
|
return null;
|
|
71
|
+
} finally {
|
|
72
|
+
if (fd !== undefined) closeSync(fd);
|
|
58
73
|
}
|
|
59
|
-
|
|
60
|
-
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Remove the lock judged stale, and only that one. The lock is first moved to
|
|
78
|
+
* a name private to this process, so the file examined is the file removed; a
|
|
79
|
+
* live lock that took its place in the meantime is linked back as the same
|
|
80
|
+
* file, which its holder's release recognises by inode.
|
|
81
|
+
*
|
|
82
|
+
* @param {string} lockPath
|
|
83
|
+
* @param {{ino: number, mtimeMs: number}} judged
|
|
84
|
+
* @returns {boolean} true when the stale lock was removed
|
|
85
|
+
*/
|
|
86
|
+
export function reapLock(lockPath, judged) {
|
|
87
|
+
const reap = `${lockPath}.${process.pid}.reap`;
|
|
61
88
|
try {
|
|
62
|
-
|
|
89
|
+
renameSync(lockPath, reap);
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const st = statSync(reap);
|
|
94
|
+
if (st.ino === judged.ino && st.mtimeMs === judged.mtimeMs) {
|
|
95
|
+
unlinkSync(reap);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
linkSync(reap, lockPath);
|
|
100
|
+
} catch {
|
|
101
|
+
/* a new holder already has the path; the displaced one keeps its inode */
|
|
102
|
+
}
|
|
103
|
+
unlinkSync(reap);
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function staleIdentity(lockPath, staleMs) {
|
|
108
|
+
const owner = readLockOwner(lockPath);
|
|
109
|
+
if (!owner) return null;
|
|
110
|
+
const age = Date.now() - owner.mtimeMs;
|
|
111
|
+
if (!Number.isInteger(owner.pid) || owner.pid <= 0) return age > staleMs ? owner : null;
|
|
112
|
+
try {
|
|
113
|
+
process.kill(owner.pid, 0);
|
|
63
114
|
return null;
|
|
64
115
|
} catch (err) {
|
|
65
|
-
return err.code === "ESRCH" ?
|
|
116
|
+
return err.code === "ESRCH" ? owner : null;
|
|
66
117
|
}
|
|
67
118
|
}
|
|
68
119
|
|
|
@@ -82,12 +133,7 @@ function acquire(lockPath, timeoutMs, staleMs) {
|
|
|
82
133
|
}
|
|
83
134
|
const stale = staleIdentity(lockPath, staleMs);
|
|
84
135
|
if (stale) {
|
|
85
|
-
|
|
86
|
-
const now = statSync(lockPath);
|
|
87
|
-
if (now.ino === stale.ino && now.mtimeMs === stale.mtimeMs) unlinkSync(lockPath);
|
|
88
|
-
} catch {
|
|
89
|
-
/* gone already */
|
|
90
|
-
}
|
|
136
|
+
reapLock(lockPath, stale);
|
|
91
137
|
continue;
|
|
92
138
|
}
|
|
93
139
|
if (Date.now() >= deadline) throw new FileLockTimeout(lockPath, timeoutMs);
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* office-remote.mjs - the machine side of the office remote layer
|
|
3
|
+
* (features/office-remote-protocol.md).
|
|
4
|
+
*
|
|
5
|
+
* - Keys: P-256 ECDH between the machine key and the phone's session key,
|
|
6
|
+
* through HKDF-SHA-256 with the pairing id as salt, into one AES-256 key per
|
|
7
|
+
* direction.
|
|
8
|
+
* - Frames: AES-256-GCM; the 12-byte nonce is a 4-byte direction tag and an
|
|
9
|
+
* 8-byte counter, so a frame opens only in its own direction and a counter
|
|
10
|
+
* that does not exceed the last accepted one is refused as a replay.
|
|
11
|
+
* - Pairing: the phone's first message is sealed with a key that also mixes in
|
|
12
|
+
* the one-time pairing secret from the QR code, so the relay cannot open it
|
|
13
|
+
* even holding both public keys.
|
|
14
|
+
* - Comparison code: six digits from both public keys, the same on either end.
|
|
15
|
+
* - Passkey: a WebAuthn assertion checked against the paired credential key,
|
|
16
|
+
* rp id, origin, the request-bound challenge, user verification and the sign
|
|
17
|
+
* count.
|
|
18
|
+
*
|
|
19
|
+
* Zero runtime dependencies (ADR-0004): node:crypto only.
|
|
20
|
+
*
|
|
21
|
+
* @module pipeline/lib/office-remote
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
createCipheriv,
|
|
26
|
+
createDecipheriv,
|
|
27
|
+
createHash,
|
|
28
|
+
createPrivateKey,
|
|
29
|
+
createPublicKey,
|
|
30
|
+
diffieHellman,
|
|
31
|
+
generateKeyPairSync,
|
|
32
|
+
hkdfSync,
|
|
33
|
+
timingSafeEqual,
|
|
34
|
+
verify,
|
|
35
|
+
} from "node:crypto";
|
|
36
|
+
|
|
37
|
+
const DIRECTIONS = { "phone-to-machine": 1, "machine-to-phone": 2 };
|
|
38
|
+
const INFO = "ma-office v1 ";
|
|
39
|
+
const MAX_COUNTER = 2 ** 48;
|
|
40
|
+
|
|
41
|
+
const b64u = (b) => Buffer.from(b).toString("base64url");
|
|
42
|
+
const fromB64u = (s) => Buffer.from(String(s || ""), "base64url");
|
|
43
|
+
const sha256 = (b) => createHash("sha256").update(b).digest();
|
|
44
|
+
|
|
45
|
+
/** A new machine key pair: PKCS#8 PEM private key, base64url SPKI public key. */
|
|
46
|
+
export function createMachineKeys() {
|
|
47
|
+
const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "prime256v1" });
|
|
48
|
+
return {
|
|
49
|
+
privatePem: privateKey.export({ type: "pkcs8", format: "pem" }),
|
|
50
|
+
publicKey: b64u(publicKey.export({ type: "spki", format: "der" })),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function shared(privatePem, peerPublic) {
|
|
55
|
+
return diffieHellman({
|
|
56
|
+
privateKey: createPrivateKey(privatePem),
|
|
57
|
+
publicKey: createPublicKey({ key: fromB64u(peerPublic), format: "der", type: "spki" }),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const derive = (ikm, pairingId, label) =>
|
|
62
|
+
Buffer.from(
|
|
63
|
+
hkdfSync("sha256", ikm, Buffer.from(String(pairingId)), Buffer.from(INFO + label), 32),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The two AES keys of a pairing, from this end's point of view.
|
|
68
|
+
*
|
|
69
|
+
* @param {{privatePem: string, peerPublic: string, pairingId: string, role: "machine"|"phone"}} p
|
|
70
|
+
* @returns {{send: Buffer, recv: Buffer}}
|
|
71
|
+
*/
|
|
72
|
+
export function directionKeys({ privatePem, peerPublic, pairingId, role }) {
|
|
73
|
+
const ikm = shared(privatePem, peerPublic);
|
|
74
|
+
const p2m = derive(ikm, pairingId, "phone-to-machine");
|
|
75
|
+
const m2p = derive(ikm, pairingId, "machine-to-phone");
|
|
76
|
+
return role === "machine" ? { send: m2p, recv: p2m } : { send: p2m, recv: m2p };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function nonceFor(direction, counter) {
|
|
80
|
+
const tag = DIRECTIONS[direction];
|
|
81
|
+
if (!tag) throw new Error(`unknown direction ${direction}`);
|
|
82
|
+
if (!Number.isSafeInteger(counter) || counter < 1 || counter >= MAX_COUNTER) {
|
|
83
|
+
throw new Error("counter out of range");
|
|
84
|
+
}
|
|
85
|
+
const iv = Buffer.alloc(12);
|
|
86
|
+
iv.writeUInt32BE(tag, 0);
|
|
87
|
+
iv.writeUIntBE(counter, 6, 6);
|
|
88
|
+
return iv;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Seal a JSON value as one frame. */
|
|
92
|
+
export function sealFrame(key, counter, direction, value) {
|
|
93
|
+
const iv = nonceFor(direction, counter);
|
|
94
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
95
|
+
cipher.setAAD(Buffer.from(direction));
|
|
96
|
+
const body = Buffer.concat([cipher.update(JSON.stringify(value), "utf8"), cipher.final()]);
|
|
97
|
+
return { counter, ct: b64u(Buffer.concat([body, cipher.getAuthTag()])) };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Open one frame. Refuses a counter that does not exceed `lastCounter`, a
|
|
102
|
+
* frame for the other direction and any altered byte.
|
|
103
|
+
*
|
|
104
|
+
* @returns {{ok: true, value: unknown, counter: number} | {ok: false, reason: string}}
|
|
105
|
+
*/
|
|
106
|
+
export function openFrame(key, frame, direction, lastCounter) {
|
|
107
|
+
const counter = Number(frame?.counter);
|
|
108
|
+
if (!Number.isSafeInteger(counter) || counter <= Number(lastCounter || 0)) {
|
|
109
|
+
return { ok: false, reason: "counter did not grow (replay or reorder)" };
|
|
110
|
+
}
|
|
111
|
+
let iv;
|
|
112
|
+
try {
|
|
113
|
+
iv = nonceFor(direction, counter);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
return { ok: false, reason: err.message };
|
|
116
|
+
}
|
|
117
|
+
const raw = fromB64u(frame?.ct);
|
|
118
|
+
if (raw.length < 17) return { ok: false, reason: "frame too short" };
|
|
119
|
+
try {
|
|
120
|
+
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
121
|
+
decipher.setAAD(Buffer.from(direction));
|
|
122
|
+
decipher.setAuthTag(raw.subarray(raw.length - 16));
|
|
123
|
+
const text = Buffer.concat([
|
|
124
|
+
decipher.update(raw.subarray(0, raw.length - 16)),
|
|
125
|
+
decipher.final(),
|
|
126
|
+
]);
|
|
127
|
+
return { ok: true, value: JSON.parse(text.toString("utf8")), counter };
|
|
128
|
+
} catch {
|
|
129
|
+
return { ok: false, reason: "frame did not authenticate" };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function pairingKey({ privatePem, peerPublic, secret, pairingId }) {
|
|
134
|
+
const ikm = Buffer.concat([shared(privatePem, peerPublic), fromB64u(secret)]);
|
|
135
|
+
return derive(ikm, pairingId, "pairing");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Seal the phone's pairing message (counter 1, phone to machine). */
|
|
139
|
+
export function sealPairing({ privatePem, peerPublic, secret, pairingId, value }) {
|
|
140
|
+
return sealFrame(
|
|
141
|
+
pairingKey({ privatePem, peerPublic, secret, pairingId }),
|
|
142
|
+
1,
|
|
143
|
+
"phone-to-machine",
|
|
144
|
+
value,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Open the phone's pairing message with the machine key and the pairing secret. */
|
|
149
|
+
export function openPairing({ privatePem, peerPublic, secret, pairingId, sealed }) {
|
|
150
|
+
try {
|
|
151
|
+
const key = pairingKey({ privatePem, peerPublic, secret, pairingId });
|
|
152
|
+
const r = openFrame(key, sealed, "phone-to-machine", 0);
|
|
153
|
+
return r.ok ? { ok: true, value: r.value } : r;
|
|
154
|
+
} catch {
|
|
155
|
+
return { ok: false, reason: "pairing message could not be opened" };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Six digits from two public keys, independent of their order. */
|
|
160
|
+
export function comparisonCode(a, b) {
|
|
161
|
+
const [x, y] = [String(a), String(b)].sort();
|
|
162
|
+
const n = sha256(Buffer.from(`${INFO}compare\n${x}\n${y}`)).readUInt32BE(0) % 1_000_000;
|
|
163
|
+
return String(n).padStart(6, "0");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const sameBytes = (a, b) => a.length === b.length && timingSafeEqual(a, b);
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Check a WebAuthn assertion against the paired passkey.
|
|
170
|
+
*
|
|
171
|
+
* @param {object} p
|
|
172
|
+
* @param {{authenticatorData: string, clientDataJSON: string, signature: string}} p.assertion base64url fields
|
|
173
|
+
* @param {string} p.credential base64url SPKI of the passkey public key
|
|
174
|
+
* @param {string} p.rpId
|
|
175
|
+
* @param {string} p.origin
|
|
176
|
+
* @param {Buffer} p.challenge the bytes this request binds (SHA-256 of its canonical signed text)
|
|
177
|
+
* @param {number} [p.prevSignCount]
|
|
178
|
+
* @returns {{ok: true, signCount: number} | {ok: false, reason: string}}
|
|
179
|
+
*/
|
|
180
|
+
export function verifyPasskey({
|
|
181
|
+
assertion,
|
|
182
|
+
credential,
|
|
183
|
+
rpId,
|
|
184
|
+
origin,
|
|
185
|
+
challenge,
|
|
186
|
+
prevSignCount = 0,
|
|
187
|
+
}) {
|
|
188
|
+
const authData = fromB64u(assertion?.authenticatorData);
|
|
189
|
+
const clientRaw = fromB64u(assertion?.clientDataJSON);
|
|
190
|
+
if (authData.length < 37) return { ok: false, reason: "authenticator data too short" };
|
|
191
|
+
let client;
|
|
192
|
+
try {
|
|
193
|
+
client = JSON.parse(clientRaw.toString("utf8"));
|
|
194
|
+
} catch {
|
|
195
|
+
return { ok: false, reason: "client data is not JSON" };
|
|
196
|
+
}
|
|
197
|
+
if (client?.type !== "webauthn.get")
|
|
198
|
+
return { ok: false, reason: "client data type is not webauthn.get" };
|
|
199
|
+
if (!sameBytes(fromB64u(client.challenge), Buffer.from(challenge))) {
|
|
200
|
+
return { ok: false, reason: "challenge is not this request" };
|
|
201
|
+
}
|
|
202
|
+
if (client.origin !== origin) return { ok: false, reason: "origin is not the paired one" };
|
|
203
|
+
if (!sameBytes(authData.subarray(0, 32), sha256(Buffer.from(rpId)))) {
|
|
204
|
+
return { ok: false, reason: "rp id is not the paired one" };
|
|
205
|
+
}
|
|
206
|
+
const flags = authData[32];
|
|
207
|
+
if (!(flags & 0x01) || !(flags & 0x04))
|
|
208
|
+
return { ok: false, reason: "the user was not present and verified" };
|
|
209
|
+
const signCount = authData.readUInt32BE(33);
|
|
210
|
+
if ((signCount !== 0 || prevSignCount !== 0) && signCount <= prevSignCount) {
|
|
211
|
+
return { ok: false, reason: "sign count did not grow (a cloned authenticator or a replay)" };
|
|
212
|
+
}
|
|
213
|
+
let good;
|
|
214
|
+
try {
|
|
215
|
+
const key = createPublicKey({ key: fromB64u(credential), format: "der", type: "spki" });
|
|
216
|
+
good = verify(
|
|
217
|
+
"sha256",
|
|
218
|
+
Buffer.concat([authData, sha256(clientRaw)]),
|
|
219
|
+
key,
|
|
220
|
+
fromB64u(assertion.signature),
|
|
221
|
+
);
|
|
222
|
+
} catch {
|
|
223
|
+
good = false;
|
|
224
|
+
}
|
|
225
|
+
return good
|
|
226
|
+
? { ok: true, signCount }
|
|
227
|
+
: { ok: false, reason: "signature does not verify with the paired passkey" };
|
|
228
|
+
}
|