tinybeeai 0.0.0-stage → 0.16.1
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/.railway/railway.ts +83 -0
- package/.railway/tsconfig.json +13 -0
- package/AGENTS.md +102 -0
- package/Dockerfile +108 -0
- package/LICENSE +21 -0
- package/README.md +275 -2
- package/bin/localdost.js +29 -0
- package/bin/tinybeeai.js +28 -0
- package/compose.yml +63 -0
- package/demo/payloads/ci_failure.json +46 -0
- package/demo/payloads/outage.json +18 -0
- package/demo/payloads/pr_comment_edited.json +50 -0
- package/demo/payloads/pr_merged.json +80 -0
- package/demo/payloads/pr_opened.json +69 -0
- package/demo/payloads/pr_synchronize.json +69 -0
- package/demo/payloads/ticket_created.json +138 -0
- package/demo/sample-app/playwright.config.ts +20 -0
- package/demo/sample-app/server.ts +163 -0
- package/demo/sample-app/tests/checkout.spec.ts +13 -0
- package/demo/sample-app/tests/smoke.spec.ts +8 -0
- package/dist/agent/approval-retries.js +59 -0
- package/dist/agent/approval-retries.js.map +1 -0
- package/dist/agent/approvals.js +390 -0
- package/dist/agent/approvals.js.map +1 -0
- package/dist/agent/chat-bridge.js +154 -0
- package/dist/agent/chat-bridge.js.map +1 -0
- package/dist/agent/chat-lead.js +475 -0
- package/dist/agent/chat-lead.js.map +1 -0
- package/dist/agent/chat-loop.js +106 -0
- package/dist/agent/chat-loop.js.map +1 -0
- package/dist/agent/chat-mcp.js +49 -0
- package/dist/agent/chat-mcp.js.map +1 -0
- package/dist/agent/chat-tool-blocks.js +453 -0
- package/dist/agent/chat-tool-blocks.js.map +1 -0
- package/dist/agent/chat-view.js +94 -0
- package/dist/agent/chat-view.js.map +1 -0
- package/dist/agent/chat-views.js +781 -0
- package/dist/agent/chat-views.js.map +1 -0
- package/dist/agent/chat.js +1703 -0
- package/dist/agent/chat.js.map +1 -0
- package/dist/agent/destinations.js +150 -0
- package/dist/agent/destinations.js.map +1 -0
- package/dist/agent/llm-cli.js +451 -0
- package/dist/agent/llm-cli.js.map +1 -0
- package/dist/agent/llm-codex.js +493 -0
- package/dist/agent/llm-codex.js.map +1 -0
- package/dist/agent/llm-openai.js +211 -0
- package/dist/agent/llm-openai.js.map +1 -0
- package/dist/agent/llm.js +1464 -0
- package/dist/agent/llm.js.map +1 -0
- package/dist/agent/memory.js +33 -0
- package/dist/agent/memory.js.map +1 -0
- package/dist/agent/mock-views.js +93 -0
- package/dist/agent/mock-views.js.map +1 -0
- package/dist/agent/model-availability.js +207 -0
- package/dist/agent/model-availability.js.map +1 -0
- package/dist/agent/model-errors.js +188 -0
- package/dist/agent/model-errors.js.map +1 -0
- package/dist/agent/model-guard.js +311 -0
- package/dist/agent/model-guard.js.map +1 -0
- package/dist/agent/prompts.js +374 -0
- package/dist/agent/prompts.js.map +1 -0
- package/dist/agent/qa-lenses/qa-auth.md +32 -0
- package/dist/agent/qa-lenses/qa-check-then-act.md +33 -0
- package/dist/agent/qa-lenses/qa-control-has-no-effect.md +32 -0
- package/dist/agent/qa-lenses/qa-dates.md +31 -0
- package/dist/agent/qa-lenses/qa-double-submit.md +34 -0
- package/dist/agent/qa-lenses/qa-feature-flag.md +29 -0
- package/dist/agent/qa-lenses/qa-migration.md +35 -0
- package/dist/agent/qa-lenses/qa-money.md +38 -0
- package/dist/agent/qa-lenses/qa-response-shape-break.md +33 -0
- package/dist/agent/qa-lenses/qa-validation.md +29 -0
- package/dist/agent/qa-prompts.js +660 -0
- package/dist/agent/qa-prompts.js.map +1 -0
- package/dist/agent/reasoning.js +55 -0
- package/dist/agent/reasoning.js.map +1 -0
- package/dist/agent/redact.js +48 -0
- package/dist/agent/redact.js.map +1 -0
- package/dist/agent/rules.js +927 -0
- package/dist/agent/rules.js.map +1 -0
- package/dist/agent/runs.js +440 -0
- package/dist/agent/runs.js.map +1 -0
- package/dist/agent/send-retry.js +62 -0
- package/dist/agent/send-retry.js.map +1 -0
- package/dist/agent/team-notes.js +288 -0
- package/dist/agent/team-notes.js.map +1 -0
- package/dist/agent/token-meter.js +31 -0
- package/dist/agent/token-meter.js.map +1 -0
- package/dist/agent/triage.js +506 -0
- package/dist/agent/triage.js.map +1 -0
- package/dist/api.js +1047 -0
- package/dist/api.js.map +1 -0
- package/dist/approval-targets.js +107 -0
- package/dist/approval-targets.js.map +1 -0
- package/dist/bee/cloudflared.js +108 -0
- package/dist/bee/cloudflared.js.map +1 -0
- package/dist/bee/health.js +99 -0
- package/dist/bee/health.js.map +1 -0
- package/dist/bee/hive-client.js +75 -0
- package/dist/bee/hive-client.js.map +1 -0
- package/dist/bee/identity.js +39 -0
- package/dist/bee/identity.js.map +1 -0
- package/dist/bee/models.js +510 -0
- package/dist/bee/models.js.map +1 -0
- package/dist/bee/pairing.js +351 -0
- package/dist/bee/pairing.js.map +1 -0
- package/dist/bee/relay-client.js +50 -0
- package/dist/bee/relay-client.js.map +1 -0
- package/dist/bee/routes.js +214 -0
- package/dist/bee/routes.js.map +1 -0
- package/dist/bee/setup-page.js +223 -0
- package/dist/bee/setup-page.js.map +1 -0
- package/dist/bee/state.js +41 -0
- package/dist/bee/state.js.map +1 -0
- package/dist/bee/status.js +117 -0
- package/dist/bee/status.js.map +1 -0
- package/dist/bee/tunnel-manager.js +245 -0
- package/dist/bee/tunnel-manager.js.map +1 -0
- package/dist/bee/updater.js +268 -0
- package/dist/bee/updater.js.map +1 -0
- package/dist/boot.js +41 -0
- package/dist/boot.js.map +1 -0
- package/dist/call/index.js +145 -0
- package/dist/call/index.js.map +1 -0
- package/dist/case-folders.js +294 -0
- package/dist/case-folders.js.map +1 -0
- package/dist/cases.js +554 -0
- package/dist/cases.js.map +1 -0
- package/dist/chat-blocks.js +709 -0
- package/dist/chat-blocks.js.map +1 -0
- package/dist/chat-parse-util.js +38 -0
- package/dist/chat-parse-util.js.map +1 -0
- package/dist/chat-results.js +96 -0
- package/dist/chat-results.js.map +1 -0
- package/dist/chat-stats.js +193 -0
- package/dist/chat-stats.js.map +1 -0
- package/dist/chat-view-specs.js +186 -0
- package/dist/chat-view-specs.js.map +1 -0
- package/dist/cli/doctor-ops.js +361 -0
- package/dist/cli/doctor-ops.js.map +1 -0
- package/dist/cli/doctor.js +289 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/dogfood.js +70 -0
- package/dist/cli/dogfood.js.map +1 -0
- package/dist/cli/env-file.js +34 -0
- package/dist/cli/env-file.js.map +1 -0
- package/dist/cli/eval-chat-cases.js +359 -0
- package/dist/cli/eval-chat-cases.js.map +1 -0
- package/dist/cli/eval-chat-results.js +85 -0
- package/dist/cli/eval-chat-results.js.map +1 -0
- package/dist/cli/eval-chat.js +508 -0
- package/dist/cli/eval-chat.js.map +1 -0
- package/dist/cli/eval-designer.js +67 -0
- package/dist/cli/eval-designer.js.map +1 -0
- package/dist/cli/eval-qa-review.js +284 -0
- package/dist/cli/eval-qa-review.js.map +1 -0
- package/dist/cli/golden-export.js +35 -0
- package/dist/cli/golden-export.js.map +1 -0
- package/dist/cli/index.js +90 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.js +746 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/scan-repo.js +199 -0
- package/dist/cli/scan-repo.js.map +1 -0
- package/dist/cli/seed.js +108 -0
- package/dist/cli/seed.js.map +1 -0
- package/dist/cli/tinybee.js +247 -0
- package/dist/cli/tinybee.js.map +1 -0
- package/dist/config.js +138 -0
- package/dist/config.js.map +1 -0
- package/dist/connect/aivision-local.js +833 -0
- package/dist/connect/aivision-local.js.map +1 -0
- package/dist/connect/aivision-token.js +84 -0
- package/dist/connect/aivision-token.js.map +1 -0
- package/dist/connect/crypto.js +65 -0
- package/dist/connect/crypto.js.map +1 -0
- package/dist/connect/deps.js +110 -0
- package/dist/connect/deps.js.map +1 -0
- package/dist/connect/engines.js +144 -0
- package/dist/connect/engines.js.map +1 -0
- package/dist/connect/github-access.js +74 -0
- package/dist/connect/github-access.js.map +1 -0
- package/dist/connect/github-app.js +129 -0
- package/dist/connect/github-app.js.map +1 -0
- package/dist/connect/index.js +9 -0
- package/dist/connect/index.js.map +1 -0
- package/dist/connect/model-choices.js +201 -0
- package/dist/connect/model-choices.js.map +1 -0
- package/dist/connect/providers.js +900 -0
- package/dist/connect/providers.js.map +1 -0
- package/dist/connect/readiness.js +232 -0
- package/dist/connect/readiness.js.map +1 -0
- package/dist/connect/redact.js +16 -0
- package/dist/connect/redact.js.map +1 -0
- package/dist/connect/registry.js +406 -0
- package/dist/connect/registry.js.map +1 -0
- package/dist/connect/store.js +283 -0
- package/dist/connect/store.js.map +1 -0
- package/dist/connect/tunnel.js +134 -0
- package/dist/connect/tunnel.js.map +1 -0
- package/dist/connect/types.js +8 -0
- package/dist/connect/types.js.map +1 -0
- package/dist/connections/index.js +5 -0
- package/dist/connections/index.js.map +1 -0
- package/dist/connections/manager.js +223 -0
- package/dist/connections/manager.js.map +1 -0
- package/dist/connections/presets.js +264 -0
- package/dist/connections/presets.js.map +1 -0
- package/dist/connections/store.js +132 -0
- package/dist/connections/store.js.map +1 -0
- package/dist/connections/tools.js +206 -0
- package/dist/connections/tools.js.map +1 -0
- package/dist/db-schema.js +355 -0
- package/dist/db-schema.js.map +1 -0
- package/dist/db.js +379 -0
- package/dist/db.js.map +1 -0
- package/dist/delivery.js +49 -0
- package/dist/delivery.js.map +1 -0
- package/dist/deploy-wait.js +701 -0
- package/dist/deploy-wait.js.map +1 -0
- package/dist/disk.js +243 -0
- package/dist/disk.js.map +1 -0
- package/dist/dot-health.js +966 -0
- package/dist/dot-health.js.map +1 -0
- package/dist/dot-remove.js +246 -0
- package/dist/dot-remove.js.map +1 -0
- package/dist/events.js +38 -0
- package/dist/events.js.map +1 -0
- package/dist/evidence-pack.js +423 -0
- package/dist/evidence-pack.js.map +1 -0
- package/dist/flows/answers.js +289 -0
- package/dist/flows/answers.js.map +1 -0
- package/dist/flows/change.js +811 -0
- package/dist/flows/change.js.map +1 -0
- package/dist/flows/checkStatus.js +524 -0
- package/dist/flows/checkStatus.js.map +1 -0
- package/dist/flows/ci.js +236 -0
- package/dist/flows/ci.js.map +1 -0
- package/dist/flows/ciFailure.js +76 -0
- package/dist/flows/ciFailure.js.map +1 -0
- package/dist/flows/common.js +522 -0
- package/dist/flows/common.js.map +1 -0
- package/dist/flows/default-branch.js +29 -0
- package/dist/flows/default-branch.js.map +1 -0
- package/dist/flows/defectDraft.js +447 -0
- package/dist/flows/defectDraft.js.map +1 -0
- package/dist/flows/defects.js +623 -0
- package/dist/flows/defects.js.map +1 -0
- package/dist/flows/digest.js +295 -0
- package/dist/flows/digest.js.map +1 -0
- package/dist/flows/impact.js +82 -0
- package/dist/flows/impact.js.map +1 -0
- package/dist/flows/index.js +23 -0
- package/dist/flows/index.js.map +1 -0
- package/dist/flows/intent-sources.js +72 -0
- package/dist/flows/intent-sources.js.map +1 -0
- package/dist/flows/mergeCases.js +169 -0
- package/dist/flows/mergeCases.js.map +1 -0
- package/dist/flows/nightlyRun.js +82 -0
- package/dist/flows/nightlyRun.js.map +1 -0
- package/dist/flows/outage.js +64 -0
- package/dist/flows/outage.js.map +1 -0
- package/dist/flows/postMerge.js +5 -0
- package/dist/flows/postMerge.js.map +1 -0
- package/dist/flows/prCheck.js +5 -0
- package/dist/flows/prCheck.js.map +1 -0
- package/dist/flows/prTarget.js +66 -0
- package/dist/flows/prTarget.js.map +1 -0
- package/dist/flows/qa.js +363 -0
- package/dist/flows/qa.js.map +1 -0
- package/dist/flows/questions.js +160 -0
- package/dist/flows/questions.js.map +1 -0
- package/dist/flows/recovery.js +64 -0
- package/dist/flows/recovery.js.map +1 -0
- package/dist/flows/rerun.js +50 -0
- package/dist/flows/rerun.js.map +1 -0
- package/dist/flows/testDesign.js +294 -0
- package/dist/flows/testDesign.js.map +1 -0
- package/dist/flows/testDesignJob.js +46 -0
- package/dist/flows/testDesignJob.js.map +1 -0
- package/dist/flows/testRepo.js +228 -0
- package/dist/flows/testRepo.js.map +1 -0
- package/dist/flows/testSavings.js +381 -0
- package/dist/flows/testSavings.js.map +1 -0
- package/dist/flows/testStatus.js +343 -0
- package/dist/flows/testStatus.js.map +1 -0
- package/dist/flows/ticketContext.js +425 -0
- package/dist/flows/ticketContext.js.map +1 -0
- package/dist/flows/ticketReview.js +249 -0
- package/dist/flows/ticketReview.js.map +1 -0
- package/dist/flows/ticks.js +73 -0
- package/dist/flows/ticks.js.map +1 -0
- package/dist/hive/admin.js +122 -0
- package/dist/hive/admin.js.map +1 -0
- package/dist/hive/auth.js +130 -0
- package/dist/hive/auth.js.map +1 -0
- package/dist/hive/billing.js +278 -0
- package/dist/hive/billing.js.map +1 -0
- package/dist/hive/config.js +63 -0
- package/dist/hive/config.js.map +1 -0
- package/dist/hive/db.js +186 -0
- package/dist/hive/db.js.map +1 -0
- package/dist/hive/embed.js +76 -0
- package/dist/hive/embed.js.map +1 -0
- package/dist/hive/errors.js +17 -0
- package/dist/hive/errors.js.map +1 -0
- package/dist/hive/google.js +75 -0
- package/dist/hive/google.js.map +1 -0
- package/dist/hive/index.js +25 -0
- package/dist/hive/index.js.map +1 -0
- package/dist/hive/jwt.js +57 -0
- package/dist/hive/jwt.js.map +1 -0
- package/dist/hive/keys.js +61 -0
- package/dist/hive/keys.js.map +1 -0
- package/dist/hive/mail.js +27 -0
- package/dist/hive/mail.js.map +1 -0
- package/dist/hive/native-push.js +255 -0
- package/dist/hive/native-push.js.map +1 -0
- package/dist/hive/pairing.js +342 -0
- package/dist/hive/pairing.js.map +1 -0
- package/dist/hive/presence.js +121 -0
- package/dist/hive/presence.js.map +1 -0
- package/dist/hive/push.js +185 -0
- package/dist/hive/push.js.map +1 -0
- package/dist/hive/relay.js +205 -0
- package/dist/hive/relay.js.map +1 -0
- package/dist/hive/routes.js +228 -0
- package/dist/hive/routes.js.map +1 -0
- package/dist/hive/server.js +12 -0
- package/dist/hive/server.js.map +1 -0
- package/dist/hive/session.js +28 -0
- package/dist/hive/session.js.map +1 -0
- package/dist/hive/tenants.js +287 -0
- package/dist/hive/tenants.js.map +1 -0
- package/dist/hive/tunnel/cloudflare.js +160 -0
- package/dist/hive/tunnel/cloudflare.js.map +1 -0
- package/dist/hive/tunnel/mock.js +52 -0
- package/dist/hive/tunnel/mock.js.map +1 -0
- package/dist/hive/tunnel/provider.js +19 -0
- package/dist/hive/tunnel/provider.js.map +1 -0
- package/dist/hive/updates.js +61 -0
- package/dist/hive/updates.js.map +1 -0
- package/dist/http-error.js +11 -0
- package/dist/http-error.js.map +1 -0
- package/dist/impact/classify.js +226 -0
- package/dist/impact/classify.js.map +1 -0
- package/dist/impact/find.js +259 -0
- package/dist/impact/find.js.map +1 -0
- package/dist/impact/pr.js +54 -0
- package/dist/impact/pr.js.map +1 -0
- package/dist/impact/store.js +365 -0
- package/dist/impact/store.js.map +1 -0
- package/dist/impact/text.js +158 -0
- package/dist/impact/text.js.map +1 -0
- package/dist/index.js +288 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/adf.js +397 -0
- package/dist/integrations/adf.js.map +1 -0
- package/dist/integrations/bot-marker.js +103 -0
- package/dist/integrations/bot-marker.js.map +1 -0
- package/dist/integrations/github-issues.js +705 -0
- package/dist/integrations/github-issues.js.map +1 -0
- package/dist/integrations/github.js +1284 -0
- package/dist/integrations/github.js.map +1 -0
- package/dist/integrations/issue-create.js +60 -0
- package/dist/integrations/issue-create.js.map +1 -0
- package/dist/integrations/jira.js +279 -0
- package/dist/integrations/jira.js.map +1 -0
- package/dist/integrations/linear.js +273 -0
- package/dist/integrations/linear.js.map +1 -0
- package/dist/integrations/own-identity-warm.js +47 -0
- package/dist/integrations/own-identity-warm.js.map +1 -0
- package/dist/integrations/own-identity.js +39 -0
- package/dist/integrations/own-identity.js.map +1 -0
- package/dist/integrations/status-change.js +42 -0
- package/dist/integrations/status-change.js.map +1 -0
- package/dist/lead-defects.js +202 -0
- package/dist/lead-defects.js.map +1 -0
- package/dist/lead-digest.js +333 -0
- package/dist/lead-digest.js.map +1 -0
- package/dist/lead-release.js +286 -0
- package/dist/lead-release.js.map +1 -0
- package/dist/lead.js +328 -0
- package/dist/lead.js.map +1 -0
- package/dist/legacy-names.js +51 -0
- package/dist/legacy-names.js.map +1 -0
- package/dist/limits.js +44 -0
- package/dist/limits.js.map +1 -0
- package/dist/link-trust.js +224 -0
- package/dist/link-trust.js.map +1 -0
- package/dist/links.js +219 -0
- package/dist/links.js.map +1 -0
- package/dist/loopback.js +35 -0
- package/dist/loopback.js.map +1 -0
- package/dist/model-cap.js +60 -0
- package/dist/model-cap.js.map +1 -0
- package/dist/model-usage.js +173 -0
- package/dist/model-usage.js.map +1 -0
- package/dist/monitor/backfill.js +39 -0
- package/dist/monitor/backfill.js.map +1 -0
- package/dist/monitor/browser-probe.js +198 -0
- package/dist/monitor/browser-probe.js.map +1 -0
- package/dist/monitor/catch-up.js +31 -0
- package/dist/monitor/catch-up.js.map +1 -0
- package/dist/monitor/pollers.js +1606 -0
- package/dist/monitor/pollers.js.map +1 -0
- package/dist/monitor/probes.js +178 -0
- package/dist/monitor/probes.js.map +1 -0
- package/dist/monitor/self-health.js +228 -0
- package/dist/monitor/self-health.js.map +1 -0
- package/dist/monitor/statuspage.js +105 -0
- package/dist/monitor/statuspage.js.map +1 -0
- package/dist/nightly-scheduler.js +127 -0
- package/dist/nightly-scheduler.js.map +1 -0
- package/dist/nightly.js +141 -0
- package/dist/nightly.js.map +1 -0
- package/dist/notify/headline.js +114 -0
- package/dist/notify/headline.js.map +1 -0
- package/dist/notify/push.js +174 -0
- package/dist/notify/push.js.map +1 -0
- package/dist/object-cards.js +585 -0
- package/dist/object-cards.js.map +1 -0
- package/dist/object-links.js +47 -0
- package/dist/object-links.js.map +1 -0
- package/dist/onboarding-checks.js +141 -0
- package/dist/onboarding-checks.js.map +1 -0
- package/dist/onboarding.js +401 -0
- package/dist/onboarding.js.map +1 -0
- package/dist/path-filters.js +62 -0
- package/dist/path-filters.js.map +1 -0
- package/dist/phone/alerts.js +67 -0
- package/dist/phone/alerts.js.map +1 -0
- package/dist/phone/auth.js +240 -0
- package/dist/phone/auth.js.map +1 -0
- package/dist/phone/pairing.js +442 -0
- package/dist/phone/pairing.js.map +1 -0
- package/dist/phone/prefs.js +27 -0
- package/dist/phone/prefs.js.map +1 -0
- package/dist/phone/tailscale.js +161 -0
- package/dist/phone/tailscale.js.map +1 -0
- package/dist/pr-scope.js +441 -0
- package/dist/pr-scope.js.map +1 -0
- package/dist/proc.js +156 -0
- package/dist/proc.js.map +1 -0
- package/dist/profile/cache.js +108 -0
- package/dist/profile/cache.js.map +1 -0
- package/dist/profile/ci.js +216 -0
- package/dist/profile/ci.js.map +1 -0
- package/dist/profile/index.js +8 -0
- package/dist/profile/index.js.map +1 -0
- package/dist/profile/job.js +135 -0
- package/dist/profile/job.js.map +1 -0
- package/dist/profile/queries/go-tags.scm +47 -0
- package/dist/profile/queries/java-tags.scm +25 -0
- package/dist/profile/queries/javascript-tags.scm +104 -0
- package/dist/profile/queries/python-tags.scm +19 -0
- package/dist/profile/queries/typescript-tags.scm +28 -0
- package/dist/profile/scan-thread.js +42 -0
- package/dist/profile/scan-thread.js.map +1 -0
- package/dist/profile/scan-worker.js +16 -0
- package/dist/profile/scan-worker.js.map +1 -0
- package/dist/profile/scan.js +351 -0
- package/dist/profile/scan.js.map +1 -0
- package/dist/profile/stack.js +528 -0
- package/dist/profile/stack.js.map +1 -0
- package/dist/profile/store.js +35 -0
- package/dist/profile/store.js.map +1 -0
- package/dist/profile/tests.js +399 -0
- package/dist/profile/tests.js.map +1 -0
- package/dist/queue.js +350 -0
- package/dist/queue.js.map +1 -0
- package/dist/refs.js +756 -0
- package/dist/refs.js.map +1 -0
- package/dist/release-notes.js +272 -0
- package/dist/release-notes.js.map +1 -0
- package/dist/reports/build.js +243 -0
- package/dist/reports/build.js.map +1 -0
- package/dist/reports/index.js +211 -0
- package/dist/reports/index.js.map +1 -0
- package/dist/reports/store.js +150 -0
- package/dist/reports/store.js.map +1 -0
- package/dist/reports/ticket-titles.js +124 -0
- package/dist/reports/ticket-titles.js.map +1 -0
- package/dist/reports/trace-map.js +1278 -0
- package/dist/reports/trace-map.js.map +1 -0
- package/dist/reports/traceability.js +422 -0
- package/dist/reports/traceability.js.map +1 -0
- package/dist/repos/mirror.js +356 -0
- package/dist/repos/mirror.js.map +1 -0
- package/dist/repos-github.js +108 -0
- package/dist/repos-github.js.map +1 -0
- package/dist/repos.js +891 -0
- package/dist/repos.js.map +1 -0
- package/dist/review/backend-anthropic.js +90 -0
- package/dist/review/backend-anthropic.js.map +1 -0
- package/dist/review/backend-cli.js +248 -0
- package/dist/review/backend-cli.js.map +1 -0
- package/dist/review/backend-codex.js +81 -0
- package/dist/review/backend-codex.js.map +1 -0
- package/dist/review/backend-mock.js +686 -0
- package/dist/review/backend-mock.js.map +1 -0
- package/dist/review/backend-only.js +168 -0
- package/dist/review/backend-only.js.map +1 -0
- package/dist/review/backend.js +105 -0
- package/dist/review/backend.js.map +1 -0
- package/dist/review/baseline/render-v1.js +483 -0
- package/dist/review/baseline/render-v1.js.map +1 -0
- package/dist/review/change-summary.js +197 -0
- package/dist/review/change-summary.js.map +1 -0
- package/dist/review/changelog.js +40 -0
- package/dist/review/changelog.js.map +1 -0
- package/dist/review/check.js +494 -0
- package/dist/review/check.js.map +1 -0
- package/dist/review/checkout.js +185 -0
- package/dist/review/checkout.js.map +1 -0
- package/dist/review/classify.js +178 -0
- package/dist/review/classify.js.map +1 -0
- package/dist/review/coverage.js +347 -0
- package/dist/review/coverage.js.map +1 -0
- package/dist/review/decision-eval.js +121 -0
- package/dist/review/decision-eval.js.map +1 -0
- package/dist/review/deliver.js +104 -0
- package/dist/review/deliver.js.map +1 -0
- package/dist/review/designer-eval.js +280 -0
- package/dist/review/designer-eval.js.map +1 -0
- package/dist/review/dogfood-digest.js +136 -0
- package/dist/review/dogfood-digest.js.map +1 -0
- package/dist/review/dogfood-eval.js +486 -0
- package/dist/review/dogfood-eval.js.map +1 -0
- package/dist/review/environment.js +109 -0
- package/dist/review/environment.js.map +1 -0
- package/dist/review/eval.js +405 -0
- package/dist/review/eval.js.map +1 -0
- package/dist/review/glob.js +110 -0
- package/dist/review/glob.js.map +1 -0
- package/dist/review/golden-export.js +219 -0
- package/dist/review/golden-export.js.map +1 -0
- package/dist/review/impact.js +406 -0
- package/dist/review/impact.js.map +1 -0
- package/dist/review/imports.js +542 -0
- package/dist/review/imports.js.map +1 -0
- package/dist/review/index.js +512 -0
- package/dist/review/index.js.map +1 -0
- package/dist/review/intent.js +128 -0
- package/dist/review/intent.js.map +1 -0
- package/dist/review/lenses.js +167 -0
- package/dist/review/lenses.js.map +1 -0
- package/dist/review/linked-tickets.js +293 -0
- package/dist/review/linked-tickets.js.map +1 -0
- package/dist/review/merge.js +370 -0
- package/dist/review/merge.js.map +1 -0
- package/dist/review/on-demand.js +218 -0
- package/dist/review/on-demand.js.map +1 -0
- package/dist/review/prompt-eval.js +299 -0
- package/dist/review/prompt-eval.js.map +1 -0
- package/dist/review/prompt-variants.js +37 -0
- package/dist/review/prompt-variants.js.map +1 -0
- package/dist/review/readability-eval.js +217 -0
- package/dist/review/readability-eval.js.map +1 -0
- package/dist/review/readability.js +295 -0
- package/dist/review/readability.js.map +1 -0
- package/dist/review/render.js +2409 -0
- package/dist/review/render.js.map +1 -0
- package/dist/review/repo.js +194 -0
- package/dist/review/repo.js.map +1 -0
- package/dist/review/report-plan.js +90 -0
- package/dist/review/report-plan.js.map +1 -0
- package/dist/review/routes.js +195 -0
- package/dist/review/routes.js.map +1 -0
- package/dist/review/run-summary.js +34 -0
- package/dist/review/run-summary.js.map +1 -0
- package/dist/review/run.js +245 -0
- package/dist/review/run.js.map +1 -0
- package/dist/review/scope.js +454 -0
- package/dist/review/scope.js.map +1 -0
- package/dist/review/security.js +432 -0
- package/dist/review/security.js.map +1 -0
- package/dist/review/signals.js +550 -0
- package/dist/review/signals.js.map +1 -0
- package/dist/review/specs.js +150 -0
- package/dist/review/specs.js.map +1 -0
- package/dist/review/ste.js +133 -0
- package/dist/review/ste.js.map +1 -0
- package/dist/review/test-repo-file.js +18 -0
- package/dist/review/test-repo-file.js.map +1 -0
- package/dist/review/test-repo-lines.js +53 -0
- package/dist/review/test-repo-lines.js.map +1 -0
- package/dist/review/ticket-on-demand.js +232 -0
- package/dist/review/ticket-on-demand.js.map +1 -0
- package/dist/review/yaml.js +298 -0
- package/dist/review/yaml.js.map +1 -0
- package/dist/room.js +361 -0
- package/dist/room.js.map +1 -0
- package/dist/routes/activity.js +219 -0
- package/dist/routes/activity.js.map +1 -0
- package/dist/routes/call.js +29 -0
- package/dist/routes/call.js.map +1 -0
- package/dist/routes/cards.js +40 -0
- package/dist/routes/cards.js.map +1 -0
- package/dist/routes/cases.js +133 -0
- package/dist/routes/cases.js.map +1 -0
- package/dist/routes/connect.js +268 -0
- package/dist/routes/connect.js.map +1 -0
- package/dist/routes/connection-presets.js +32 -0
- package/dist/routes/connection-presets.js.map +1 -0
- package/dist/routes/connections.js +177 -0
- package/dist/routes/connections.js.map +1 -0
- package/dist/routes/disk.js +19 -0
- package/dist/routes/disk.js.map +1 -0
- package/dist/routes/docs.js +71 -0
- package/dist/routes/docs.js.map +1 -0
- package/dist/routes/dot-suggest.js +1002 -0
- package/dist/routes/dot-suggest.js.map +1 -0
- package/dist/routes/evidence-pack.js +16 -0
- package/dist/routes/evidence-pack.js.map +1 -0
- package/dist/routes/health.js +121 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/impact.js +48 -0
- package/dist/routes/impact.js.map +1 -0
- package/dist/routes/lead.js +50 -0
- package/dist/routes/lead.js.map +1 -0
- package/dist/routes/links.js +13 -0
- package/dist/routes/links.js.map +1 -0
- package/dist/routes/markdown.js +62 -0
- package/dist/routes/markdown.js.map +1 -0
- package/dist/routes/onboarding.js +47 -0
- package/dist/routes/onboarding.js.map +1 -0
- package/dist/routes/phone.js +231 -0
- package/dist/routes/phone.js.map +1 -0
- package/dist/routes/release-notes.js +30 -0
- package/dist/routes/release-notes.js.map +1 -0
- package/dist/routes/reports.js +102 -0
- package/dist/routes/reports.js.map +1 -0
- package/dist/routes/repos.js +91 -0
- package/dist/routes/repos.js.map +1 -0
- package/dist/routes/review.js +283 -0
- package/dist/routes/review.js.map +1 -0
- package/dist/routes/roles.js +114 -0
- package/dist/routes/roles.js.map +1 -0
- package/dist/routes/room.js +21 -0
- package/dist/routes/room.js.map +1 -0
- package/dist/routes/runner.js +156 -0
- package/dist/routes/runner.js.map +1 -0
- package/dist/routes/runs.js +84 -0
- package/dist/routes/runs.js.map +1 -0
- package/dist/routes/setup.js +18 -0
- package/dist/routes/setup.js.map +1 -0
- package/dist/routes/test-runs.js +220 -0
- package/dist/routes/test-runs.js.map +1 -0
- package/dist/routes/ticket-status.js +17 -0
- package/dist/routes/ticket-status.js.map +1 -0
- package/dist/routes/traceability.js +143 -0
- package/dist/routes/traceability.js.map +1 -0
- package/dist/routes/true.js +142 -0
- package/dist/routes/true.js.map +1 -0
- package/dist/routes/updates.js +70 -0
- package/dist/routes/updates.js.map +1 -0
- package/dist/runner/adapters/index.js +12 -0
- package/dist/runner/adapters/index.js.map +1 -0
- package/dist/runner/adapters/playwright.js +68 -0
- package/dist/runner/adapters/playwright.js.map +1 -0
- package/dist/runner/aivision/cases.js +172 -0
- package/dist/runner/aivision/cases.js.map +1 -0
- package/dist/runner/aivision/cli.js +201 -0
- package/dist/runner/aivision/cli.js.map +1 -0
- package/dist/runner/aivision/index.js +281 -0
- package/dist/runner/aivision/index.js.map +1 -0
- package/dist/runner/aivision/server.js +394 -0
- package/dist/runner/aivision/server.js.map +1 -0
- package/dist/runner/aivision/shared.js +140 -0
- package/dist/runner/aivision/shared.js.map +1 -0
- package/dist/runner/artifact-cap.js +189 -0
- package/dist/runner/artifact-cap.js.map +1 -0
- package/dist/runner/artifacts.js +433 -0
- package/dist/runner/artifacts.js.map +1 -0
- package/dist/runner/command.js +564 -0
- package/dist/runner/command.js.map +1 -0
- package/dist/runner/copyfiles.js +221 -0
- package/dist/runner/copyfiles.js.map +1 -0
- package/dist/runner/engines.js +32 -0
- package/dist/runner/engines.js.map +1 -0
- package/dist/runner/evidence.js +114 -0
- package/dist/runner/evidence.js.map +1 -0
- package/dist/runner/host-env.js +160 -0
- package/dist/runner/host-env.js.map +1 -0
- package/dist/runner/index.js +1221 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/observe.js +603 -0
- package/dist/runner/observe.js.map +1 -0
- package/dist/runner/playwright-json.js +108 -0
- package/dist/runner/playwright-json.js.map +1 -0
- package/dist/runner/pwgen/exec.js +192 -0
- package/dist/runner/pwgen/exec.js.map +1 -0
- package/dist/runner/pwgen/explore.js +111 -0
- package/dist/runner/pwgen/explore.js.map +1 -0
- package/dist/runner/pwgen/index.js +423 -0
- package/dist/runner/pwgen/index.js.map +1 -0
- package/dist/runner/pwgen/propose.js +69 -0
- package/dist/runner/pwgen/propose.js.map +1 -0
- package/dist/runner/pwgen/source.js +632 -0
- package/dist/runner/pwgen/source.js.map +1 -0
- package/dist/runner/setup.js +222 -0
- package/dist/runner/setup.js.map +1 -0
- package/dist/runner/step-reporter.js +107 -0
- package/dist/runner/step-reporter.js.map +1 -0
- package/dist/runner/test-repo.js +326 -0
- package/dist/runner/test-repo.js.map +1 -0
- package/dist/runner/typed-value.js +46 -0
- package/dist/runner/typed-value.js.map +1 -0
- package/dist/runner/verify.js +133 -0
- package/dist/runner/verify.js.map +1 -0
- package/dist/runner/worktree.js +349 -0
- package/dist/runner/worktree.js.map +1 -0
- package/dist/sandbox.js +61 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/server.js +262 -0
- package/dist/server.js.map +1 -0
- package/dist/shadow-week.js +126 -0
- package/dist/shadow-week.js.map +1 -0
- package/dist/shutdown.js +92 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/slack/index.js +645 -0
- package/dist/slack/index.js.map +1 -0
- package/dist/stages/config.js +147 -0
- package/dist/stages/config.js.map +1 -0
- package/dist/stages/index.js +41 -0
- package/dist/stages/index.js.map +1 -0
- package/dist/suites.js +293 -0
- package/dist/suites.js.map +1 -0
- package/dist/target-url.js +116 -0
- package/dist/target-url.js.map +1 -0
- package/dist/test-runs.js +662 -0
- package/dist/test-runs.js.map +1 -0
- package/dist/ticket-keys.js +97 -0
- package/dist/ticket-keys.js.map +1 -0
- package/dist/ticket-supersede.js +105 -0
- package/dist/ticket-supersede.js.map +1 -0
- package/dist/tinybee/ed25519.js +99 -0
- package/dist/tinybee/ed25519.js.map +1 -0
- package/dist/tinybee/models-routes.js +19 -0
- package/dist/tinybee/models-routes.js.map +1 -0
- package/dist/tinybee/pair-payload.js +41 -0
- package/dist/tinybee/pair-payload.js.map +1 -0
- package/dist/tinybee/update-manifest.js +77 -0
- package/dist/tinybee/update-manifest.js.map +1 -0
- package/dist/tinybee/well-known.js +64 -0
- package/dist/tinybee/well-known.js.map +1 -0
- package/dist/tinybee/workflows/activity.js +23 -0
- package/dist/tinybee/workflows/activity.js.map +1 -0
- package/dist/tinybee/workflows/cron.js +210 -0
- package/dist/tinybee/workflows/cron.js.map +1 -0
- package/dist/tinybee/workflows/engine.js +371 -0
- package/dist/tinybee/workflows/engine.js.map +1 -0
- package/dist/tinybee/workflows/from-text.js +203 -0
- package/dist/tinybee/workflows/from-text.js.map +1 -0
- package/dist/tinybee/workflows/routes.js +189 -0
- package/dist/tinybee/workflows/routes.js.map +1 -0
- package/dist/tinybee/workflows/scheduler.js +100 -0
- package/dist/tinybee/workflows/scheduler.js.map +1 -0
- package/dist/tinybee/workflows/skills.js +227 -0
- package/dist/tinybee/workflows/skills.js.map +1 -0
- package/dist/tinybee/workflows/store.js +205 -0
- package/dist/tinybee/workflows/store.js.map +1 -0
- package/dist/tinybee/workflows/types.js +180 -0
- package/dist/tinybee/workflows/types.js.map +1 -0
- package/dist/tinybee/workflows/yaml.js +323 -0
- package/dist/tinybee/workflows/yaml.js.map +1 -0
- package/dist/true/api.js +495 -0
- package/dist/true/api.js.map +1 -0
- package/dist/true/client.js +292 -0
- package/dist/true/client.js.map +1 -0
- package/dist/true/clock.js +36 -0
- package/dist/true/clock.js.map +1 -0
- package/dist/true/events.js +125 -0
- package/dist/true/events.js.map +1 -0
- package/dist/true/hosts.js +98 -0
- package/dist/true/hosts.js.map +1 -0
- package/dist/true/index.js +29 -0
- package/dist/true/index.js.map +1 -0
- package/dist/true/key.js +54 -0
- package/dist/true/key.js.map +1 -0
- package/dist/true/line.js +69 -0
- package/dist/true/line.js.map +1 -0
- package/dist/true/mask.js +31 -0
- package/dist/true/mask.js.map +1 -0
- package/dist/true/names.js +114 -0
- package/dist/true/names.js.map +1 -0
- package/dist/true/outbox.js +233 -0
- package/dist/true/outbox.js.map +1 -0
- package/dist/true/replay.js +164 -0
- package/dist/true/replay.js.map +1 -0
- package/dist/true/settings.js +123 -0
- package/dist/true/settings.js.map +1 -0
- package/dist/true/status.js +189 -0
- package/dist/true/status.js.map +1 -0
- package/dist/true/sync-cases.js +222 -0
- package/dist/true/sync-cases.js.map +1 -0
- package/dist/true/sync-manual.js +295 -0
- package/dist/true/sync-manual.js.map +1 -0
- package/dist/true/sync-runs.js +109 -0
- package/dist/true/sync-runs.js.map +1 -0
- package/dist/true/worker.js +414 -0
- package/dist/true/worker.js.map +1 -0
- package/dist/types.js +32 -0
- package/dist/types.js.map +1 -0
- package/dist/updates/asks.js +38 -0
- package/dist/updates/asks.js.map +1 -0
- package/dist/updates/index.js +835 -0
- package/dist/updates/index.js.map +1 -0
- package/dist/updates/owner.js +24 -0
- package/dist/updates/owner.js.map +1 -0
- package/dist/updates/prefs.js +118 -0
- package/dist/updates/prefs.js.map +1 -0
- package/dist/updates/route.js +78 -0
- package/dist/updates/route.js.map +1 -0
- package/dist/updates/sources.js +345 -0
- package/dist/updates/sources.js.map +1 -0
- package/dist/updates/words.js +452 -0
- package/dist/updates/words.js.map +1 -0
- package/dist/version.js +53 -0
- package/dist/version.js.map +1 -0
- package/dist/view-compute.js +382 -0
- package/dist/view-compute.js.map +1 -0
- package/dist/view-spec.js +894 -0
- package/dist/view-spec.js.map +1 -0
- package/dist/web/apple-touch-icon.png +0 -0
- package/dist/web/assets/ApprovalCard-Br_z5z7G.css +1 -0
- package/dist/web/assets/ApprovalCard-CfGhGFo_.js +3 -0
- package/dist/web/assets/CardFromRef-BaTGmZ9c.js +2 -0
- package/dist/web/assets/CardFromRef-DO7i2uDd.css +1 -0
- package/dist/web/assets/Cases-8l_6UcLh.js +2 -0
- package/dist/web/assets/Cases-CpfED0uB.css +1 -0
- package/dist/web/assets/Chat-BKDiR0qt.js +3 -0
- package/dist/web/assets/Chat-DxjdyYUu.css +1 -0
- package/dist/web/assets/ConfirmDialog-CIMveD-b.js +2 -0
- package/dist/web/assets/ConnectSheet-Cm5vbZdR.js +4 -0
- package/dist/web/assets/Docs-HKGuY0WE.js +2 -0
- package/dist/web/assets/Docs-fodKx8S7.css +1 -0
- package/dist/web/assets/DotDetail-DskS3NWe.js +2 -0
- package/dist/web/assets/DotDetail-OWRSD_1x.css +1 -0
- package/dist/web/assets/DotStage-BZDclfzV.css +1 -0
- package/dist/web/assets/DotStage-CtMNzCN3.js +2 -0
- package/dist/web/assets/Dots-BqCsS34m.js +2 -0
- package/dist/web/assets/EvidencePack-DQ3kCJX4.js +2 -0
- package/dist/web/assets/EvidencePack-DV_9ETsA.css +1 -0
- package/dist/web/assets/FailedDeliveries-1F2kFcs9.js +2 -0
- package/dist/web/assets/FailedDeliveries-DXa2_VvI.css +1 -0
- package/dist/web/assets/Feed-5wiHRTFK.js +2 -0
- package/dist/web/assets/GfmView-C-NYaduC.js +4 -0
- package/dist/web/assets/ImpactList-C-RNuDB0.js +2 -0
- package/dist/web/assets/ImpactList-C612dFdw.css +1 -0
- package/dist/web/assets/Inbox-kc1bKVL_.js +2 -0
- package/dist/web/assets/JoinScreen-C3L4wmP3.js +2 -0
- package/dist/web/assets/JoinScreen-COeAUv5v.css +1 -0
- package/dist/web/assets/LeadDialog-N3Zul9Rw.js +8 -0
- package/dist/web/assets/LeadDialog-xyWjAuAS.css +1 -0
- package/dist/web/assets/ListeningLine-BRFNaczY.js +2 -0
- package/dist/web/assets/ListeningLine-pN8CgyiK.css +1 -0
- package/dist/web/assets/Mascots-pIyGpxtD.js +2 -0
- package/dist/web/assets/ModelChoices-BxO1zyyr.js +2 -0
- package/dist/web/assets/ModelChoices-DQJnVxfs.css +1 -0
- package/dist/web/assets/NewDotDialog-CDPUWmgN.js +2 -0
- package/dist/web/assets/NewDotDialog-DrPPqkSZ.css +1 -0
- package/dist/web/assets/NewTestRunDialog-BQBthVHE.js +2 -0
- package/dist/web/assets/NoBreakNames-Csxdqdt6.js +2 -0
- package/dist/web/assets/Pair-omex_K7H.js +2 -0
- package/dist/web/assets/PushSection-CmqHlE_2.js +2 -0
- package/dist/web/assets/ReleaseNotes-B6VqFewP.js +2 -0
- package/dist/web/assets/ReleaseNotes-DBJUL7Vm.css +1 -0
- package/dist/web/assets/ReportPage-BHS1xWEt.js +162 -0
- package/dist/web/assets/Reports-BEHnDIb1.js +2 -0
- package/dist/web/assets/ReviewChangeDialog-BVSt-cw-.js +2 -0
- package/dist/web/assets/ReviewChangeDialog-BbIlHRx0.css +1 -0
- package/dist/web/assets/Room-BoG_uge4.js +2 -0
- package/dist/web/assets/Room-evAfiW_e.css +1 -0
- package/dist/web/assets/RunActions-ZY7yf1AF.js +2 -0
- package/dist/web/assets/RunDetail-C8St20GQ.css +1 -0
- package/dist/web/assets/RunDetail-qADXjBvd.js +9 -0
- package/dist/web/assets/RunRow-BKEJv8ib.js +2 -0
- package/dist/web/assets/RunnerTry-Dgpp67-s.js +6 -0
- package/dist/web/assets/RunnerTry-DsweWOfO.css +1 -0
- package/dist/web/assets/Settings-fs-QJwNM.js +2 -0
- package/dist/web/assets/Setup-DI6hBEP-.js +2 -0
- package/dist/web/assets/TestRows-wh03T5Li.js +4 -0
- package/dist/web/assets/TestRun-DTOyF-Pv.js +2 -0
- package/dist/web/assets/TestRuns-ggDjm1Q8.js +2 -0
- package/dist/web/assets/TinyBeeAddLaptop-bc3pmh3T.js +2 -0
- package/dist/web/assets/TinyBeeAi-CkyOzhm5.js +2 -0
- package/dist/web/assets/TinyBeeConnections-B2K_P38u.js +2 -0
- package/dist/web/assets/TinyBeeHome-DSpxX5KS.js +3 -0
- package/dist/web/assets/TinyBeePlan-BamiLziu.js +2 -0
- package/dist/web/assets/TinyBeeSignup-vHcz0Wen.js +2 -0
- package/dist/web/assets/TinyBeeSkills-By9RLUse.js +2 -0
- package/dist/web/assets/TinyBeeWorkflow-DeNO7Jsh.js +2 -0
- package/dist/web/assets/TinyBeeWorkflowEditor-B6OGC2OT.js +2 -0
- package/dist/web/assets/TinyBeeWorkflows-BN4-h6lt.js +2 -0
- package/dist/web/assets/Trace-BBCI1aIB.css +1 -0
- package/dist/web/assets/Trace-aF92UWaH.js +2 -0
- package/dist/web/assets/UpdatesSection-CCWEbkue.js +2 -0
- package/dist/web/assets/Welcome-CCcy558Q.js +2 -0
- package/dist/web/assets/activity-C3qilrDm.css +1 -0
- package/dist/web/assets/activity-CBfTSxqw.js +2 -0
- package/dist/web/assets/authedMedia-BTYt_tyu.js +2 -0
- package/dist/web/assets/beeApi-BHW8Tx1s.js +2 -0
- package/dist/web/assets/data-CmXvx3Mj.js +2 -0
- package/dist/web/assets/engines-CfdJODFj.css +1 -0
- package/dist/web/assets/format-BBZ8vFyT.js +2 -0
- package/dist/web/assets/forms-Coc7p2UF.css +1 -0
- package/dist/web/assets/hivePush-DZJDokj7.js +2 -0
- package/dist/web/assets/impactModel-MY1OFuiP.js +2 -0
- package/dist/web/assets/index-B6qKm1NW.js +13 -0
- package/dist/web/assets/index-BvKyT1X7.css +1 -0
- package/dist/web/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/dist/web/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/dist/web/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/dist/web/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/dist/web/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/dist/web/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/dist/web/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/dist/web/assets/lead-BL_P_kri.css +1 -0
- package/dist/web/assets/model-BIQy5IVG.js +2 -0
- package/dist/web/assets/modelsApi-PUSySRQw.js +2 -0
- package/dist/web/assets/newDotModel-BaLLyw57.js +2 -0
- package/dist/web/assets/onboarding-bfKqnM4Z.css +1 -0
- package/dist/web/assets/phone-Rs7FoyG0.css +1 -0
- package/dist/web/assets/phoneApi-BG_1-M-D.js +3 -0
- package/dist/web/assets/releaseModel-EynYMVOC.js +2 -0
- package/dist/web/assets/releaseNotesModel-A1Rtv3cV.js +2 -0
- package/dist/web/assets/reports-BWaA1HhM.js +37 -0
- package/dist/web/assets/reports-DXwdWQsB.css +1 -0
- package/dist/web/assets/router-W6nZsQ33.js +2 -0
- package/dist/web/assets/runs-BY0Owv93.css +1 -0
- package/dist/web/assets/shadowWeekModel-BUUiww09.js +2 -0
- package/dist/web/assets/storage-yvL36AWt.js +2 -0
- package/dist/web/assets/store-IqrqHuFR.js +2 -0
- package/dist/web/assets/testruns-BzIZ0cR0.css +1 -0
- package/dist/web/assets/testruns-DyaqX4ji.js +2 -0
- package/dist/web/assets/true-9Q68cs5b.js +2 -0
- package/dist/web/assets/true-DPGBpoir.css +1 -0
- package/dist/web/assets/ui-DcmhYyYp.js +13 -0
- package/dist/web/assets/ui-DxEDgbIx.css +1 -0
- package/dist/web/assets/usePauseDot-BV60ZVy1.js +2 -0
- package/dist/web/assets/usePauseDot-NrSzMI1C.css +1 -0
- package/dist/web/assets/usePush-Dsm-TjlG.js +2 -0
- package/dist/web/assets/useRefChips-CbafNx59.js +68 -0
- package/dist/web/assets/useRestoreDot-D0B6W82H.js +2 -0
- package/dist/web/assets/view-worker-pyeVAhUT.js +2 -0
- package/dist/web/assets/workflowUi-QYsd3n9J.js +2 -0
- package/dist/web/favicon.png +0 -0
- package/dist/web/icon-192.png +0 -0
- package/dist/web/icon-512.png +0 -0
- package/dist/web/icon-maskable-512.png +0 -0
- package/dist/web/index.html +45 -0
- package/dist/web/manifest.webmanifest +23 -0
- package/dist/web/mascots/argus-attention.svg +7 -0
- package/dist/web/mascots/argus-ok.svg +7 -0
- package/dist/web/mascots/argus-outage.svg +7 -0
- package/dist/web/mascots/argus-running.svg +7 -0
- package/dist/web/mascots/bolt-attention.svg +7 -0
- package/dist/web/mascots/bolt-ok.svg +7 -0
- package/dist/web/mascots/bolt-outage.svg +7 -0
- package/dist/web/mascots/bolt-running.svg +7 -0
- package/dist/web/mascots/echo-attention.svg +7 -0
- package/dist/web/mascots/echo-ok.svg +7 -0
- package/dist/web/mascots/echo-outage.svg +7 -0
- package/dist/web/mascots/echo-running.svg +7 -0
- package/dist/web/mascots/lens-attention.svg +7 -0
- package/dist/web/mascots/lens-ok.svg +7 -0
- package/dist/web/mascots/lens-outage.svg +7 -0
- package/dist/web/mascots/lens-running.svg +7 -0
- package/dist/web/mascots/moss-attention.svg +7 -0
- package/dist/web/mascots/moss-ok.svg +7 -0
- package/dist/web/mascots/moss-outage.svg +7 -0
- package/dist/web/mascots/moss-running.svg +7 -0
- package/dist/web/mascots/nit-attention.svg +7 -0
- package/dist/web/mascots/nit-ok.svg +7 -0
- package/dist/web/mascots/nit-outage.svg +7 -0
- package/dist/web/mascots/nit-running.svg +7 -0
- package/dist/web/mascots/nova-attention.svg +7 -0
- package/dist/web/mascots/nova-ok.svg +7 -0
- package/dist/web/mascots/nova-outage.svg +7 -0
- package/dist/web/mascots/nova-running.svg +7 -0
- package/dist/web/mascots/penn-attention.svg +7 -0
- package/dist/web/mascots/penn-ok.svg +7 -0
- package/dist/web/mascots/penn-outage.svg +7 -0
- package/dist/web/mascots/penn-running.svg +7 -0
- package/dist/web/mascots/pip-attention.svg +7 -0
- package/dist/web/mascots/pip-ok.svg +7 -0
- package/dist/web/mascots/pip-outage.svg +7 -0
- package/dist/web/mascots/pip-running.svg +7 -0
- package/dist/web/mascots/ward-attention.svg +7 -0
- package/dist/web/mascots/ward-ok.svg +7 -0
- package/dist/web/mascots/ward-outage.svg +7 -0
- package/dist/web/mascots/ward-running.svg +7 -0
- package/dist/web/sw.js +98 -0
- package/dist/webhook-seen.js +53 -0
- package/dist/webhook-seen.js.map +1 -0
- package/dist/webhooks.js +625 -0
- package/dist/webhooks.js.map +1 -0
- package/dist/zip.js +63 -0
- package/dist/zip.js.map +1 -0
- package/docs/API-V2.md +532 -0
- package/docs/CHAT-EVAL.md +130 -0
- package/docs/CHAT-UI.md +416 -0
- package/docs/CONNECTIONS.md +89 -0
- package/docs/DATA-MODEL.md +518 -0
- package/docs/DEPLOY.md +577 -0
- package/docs/DOGFOOD-LEDGER.md +81 -0
- package/docs/GITHUB.md +148 -0
- package/docs/INTEGRATION-MODEL.md +200 -0
- package/docs/LEAD-DOT.md +553 -0
- package/docs/LIST-PATTERNS.md +52 -0
- package/docs/MULTI-REPO.md +766 -0
- package/docs/PARITY.md +276 -0
- package/docs/PR-REVIEW-QA.md +1266 -0
- package/docs/PR-REVIEW.md +357 -0
- package/docs/SANDBOX.md +320 -0
- package/docs/SETUP.md +776 -0
- package/docs/SLACK.md +80 -0
- package/docs/STAGES.md +619 -0
- package/docs/TRACE-MAP.md +89 -0
- package/docs/TRACKERS.md +225 -0
- package/docs/VOICE.md +36 -0
- package/docs/tinybee/00-README.md +45 -0
- package/docs/tinybee/01-PRD.md +216 -0
- package/docs/tinybee/02-architecture-pairing.md +199 -0
- package/docs/tinybee/03-local-agent.md +222 -0
- package/docs/tinybee/04-local-setup-ui.md +128 -0
- package/docs/tinybee/05-mobile-app-ux.md +199 -0
- package/docs/tinybee/06-environments-and-delivery.md +148 -0
- package/docs/tinybee/07-coding-agent-handoff.md +116 -0
- package/docs/tinybee/OPEN-QUESTIONS.md +26 -0
- package/docs/tinybee/PROGRESS.md +134 -0
- package/package.json +111 -4
package/dist/webhooks.js
ADDED
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { config, log } from './config.js';
|
|
3
|
+
import { insert, list, update, findOne } from './db.js';
|
|
4
|
+
import { enqueue } from './queue.js';
|
|
5
|
+
import { debouncedRunAfter, isStalePrHead, notePrHead, supersedeOlderPrJobs } from './flows/testSavings.js';
|
|
6
|
+
import { inheritedWait, isStaleTicketEdit, queuedTicketReviews, supersedeQueuedTicketReviews } from './ticket-supersede.js';
|
|
7
|
+
import { githubFor, normalizeCommentEdit, normalizeGithub, hasStickyMarker } from './integrations/github.js';
|
|
8
|
+
import { applyChecklistEdit } from './flows/ticks.js';
|
|
9
|
+
import { handleNewComments } from './flows/answers.js';
|
|
10
|
+
import { issueApi, issueInScope, issueSkip, normalizeGithubIssue, recordIssueEvent, reviewedSameBody, REVIEW_COMMAND, trackerRepos, } from './integrations/github-issues.js';
|
|
11
|
+
import { applyPrState } from './agent/approvals.js';
|
|
12
|
+
import { normalizeJira } from './integrations/jira.js';
|
|
13
|
+
import { normalizeLinear } from './integrations/linear.js';
|
|
14
|
+
import { findRepo, repoForEvent, watchRepos } from './repos.js';
|
|
15
|
+
import { filesMatchFilters, resolveChangedFiles } from './path-filters.js';
|
|
16
|
+
import { outOfScope, resolvePrScope } from './pr-scope.js';
|
|
17
|
+
import { noteWebhook } from './webhook-seen.js';
|
|
18
|
+
import { stageFor } from './stages/index.js';
|
|
19
|
+
import { stageOffReason, stageOn } from './stages/config.js';
|
|
20
|
+
// Signature checks
|
|
21
|
+
/** Constant-time compare of `prefix + hex(HMAC-SHA256(raw))` against the header value. */
|
|
22
|
+
export function verifySignature(raw, secret, got, prefix = '') {
|
|
23
|
+
if (!got)
|
|
24
|
+
return false;
|
|
25
|
+
const want = Buffer.from(prefix + createHmac('sha256', secret).update(raw).digest('hex'));
|
|
26
|
+
const have = Buffer.from(got.trim());
|
|
27
|
+
return want.length === have.length && timingSafeEqual(want, have);
|
|
28
|
+
}
|
|
29
|
+
/** GitHub: `X-Hub-Signature-256: sha256=<hex>`. */
|
|
30
|
+
export function verifyGithub(raw, secret, header) {
|
|
31
|
+
return verifySignature(raw, secret, header, 'sha256=');
|
|
32
|
+
}
|
|
33
|
+
/** Jira: `X-Hub-Signature: <method>=<hex>` (WebSub). Only sha256 is accepted. */
|
|
34
|
+
export function verifyJira(raw, secret, header) {
|
|
35
|
+
if (!header)
|
|
36
|
+
return false;
|
|
37
|
+
const i = header.indexOf('=');
|
|
38
|
+
if (i < 0)
|
|
39
|
+
return false;
|
|
40
|
+
if (header.slice(0, i).trim().toLowerCase() !== 'sha256')
|
|
41
|
+
return false;
|
|
42
|
+
return verifySignature(raw, secret, header.slice(i + 1).toLowerCase());
|
|
43
|
+
}
|
|
44
|
+
/** Linear: `Linear-Signature: <hex>` plus a `webhookTimestamp` (ms) within 60 s of now. */
|
|
45
|
+
export function verifyLinear(raw, secret, header, webhookTimestamp, now = Date.now()) {
|
|
46
|
+
if (!verifySignature(raw, secret, header?.toLowerCase()))
|
|
47
|
+
return { ok: false, reason: 'bad signature' };
|
|
48
|
+
const ts = Number(webhookTimestamp);
|
|
49
|
+
if (!Number.isFinite(ts))
|
|
50
|
+
return { ok: false, reason: 'missing webhookTimestamp' };
|
|
51
|
+
if (Math.abs(now - ts) > config.linearMaxSkewMs)
|
|
52
|
+
return { ok: false, reason: 'stale webhookTimestamp' };
|
|
53
|
+
return { ok: true };
|
|
54
|
+
}
|
|
55
|
+
// Trigger to job routing
|
|
56
|
+
const JOB_FOR = {
|
|
57
|
+
pr_opened: 'pr_check',
|
|
58
|
+
pr_merged: 'post_merge',
|
|
59
|
+
push: 'post_merge',
|
|
60
|
+
ci_failure: 'ci_failure',
|
|
61
|
+
ticket_created: 'ticket_review',
|
|
62
|
+
ticket_updated: 'ticket_review',
|
|
63
|
+
probe_down: 'outage',
|
|
64
|
+
statuspage: 'outage',
|
|
65
|
+
probe_up: 'recovery',
|
|
66
|
+
schedule: 'digest',
|
|
67
|
+
};
|
|
68
|
+
export function jobKindFor(ev) {
|
|
69
|
+
return JOB_FOR[ev.kind] ?? null;
|
|
70
|
+
}
|
|
71
|
+
const lc = (s) => (s ?? '').toLowerCase();
|
|
72
|
+
/**
|
|
73
|
+
* Jobs each repo role gets from a GitHub event (docs/MULTI-REPO.md sections 1.4 and 3.6).
|
|
74
|
+
* App repos keep the full table. A test repo gets CI triage only until test_pr_check and
|
|
75
|
+
* repo_scan exist (KAT-86, KAT-85 part 2); a docs repo gets no job yet.
|
|
76
|
+
*/
|
|
77
|
+
const ROLE_JOBS = {
|
|
78
|
+
app: new Set(['pr_check', 'post_merge', 'ci_failure']),
|
|
79
|
+
test: new Set(['ci_failure']),
|
|
80
|
+
docs: new Set(),
|
|
81
|
+
};
|
|
82
|
+
export function roleAllows(role, job) {
|
|
83
|
+
return !!job && ROLE_JOBS[role].has(job);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Does this Watch own the event? A GitHub event matches when its repo is in the dot's repo set and
|
|
87
|
+
* the repo's role takes the job. Push events also require that repo's default branch. A PR event must
|
|
88
|
+
* also be in the repo's PR scope (KAT-354, src/pr-scope.ts).
|
|
89
|
+
*/
|
|
90
|
+
export function watchMatches(w, ev) {
|
|
91
|
+
return matchesSources(w, ev) && !outOfScope(w, ev);
|
|
92
|
+
}
|
|
93
|
+
/** watchMatches without the PR scope: the dot watches what the event names. dispatchTrigger applies the scope next, so it can record a skip. */
|
|
94
|
+
function matchesSources(w, ev) {
|
|
95
|
+
switch (ev.source) {
|
|
96
|
+
case 'github': {
|
|
97
|
+
// GitHub issues: the dot's tracker decides (repos, labels, issue types, milestones).
|
|
98
|
+
if (ev.ticket)
|
|
99
|
+
return issueInScope(w, ev);
|
|
100
|
+
const entry = repoForEvent(w, ev);
|
|
101
|
+
if (!entry)
|
|
102
|
+
return false;
|
|
103
|
+
if (!roleAllows(entry.role, jobKindFor(ev)))
|
|
104
|
+
return false;
|
|
105
|
+
if (ev.kind === 'push' && ev.push) {
|
|
106
|
+
const branch = ev.push.ref.replace(/^refs\/heads\//, '');
|
|
107
|
+
// The default branch, or a branch the dot lists in testBranches (KAT-292).
|
|
108
|
+
if (!(branch === entry.defaultBranch || (w.testBranches ?? []).includes(branch)))
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
// Repo path filters (KAT-160): one changed file must fall inside them. Unknown files match, and the run says so.
|
|
112
|
+
if (entry.pathFilters?.length && (ev.pr || ev.push) && ev.changedFiles)
|
|
113
|
+
return filesMatchFilters(ev.changedFiles, entry.pathFilters);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
case 'jira':
|
|
117
|
+
case 'linear': {
|
|
118
|
+
if (!w.tracker || !ev.ticket || w.tracker.kind !== ev.ticket.tracker)
|
|
119
|
+
return false;
|
|
120
|
+
const keys = w.tracker.kind === 'jira' ? w.tracker.projectKeys : w.tracker.kind === 'linear' ? w.tracker.teamKeys : [];
|
|
121
|
+
return keys.some((k) => lc(k) === lc(ev.ticket.projectKey));
|
|
122
|
+
}
|
|
123
|
+
case 'probe':
|
|
124
|
+
return !!ev.probe && w.probes.some((p) => p.url === ev.probe.url);
|
|
125
|
+
case 'statuspage':
|
|
126
|
+
return typeof ev.url === 'string' && w.statusPages.some((u) => ev.url.startsWith(u.replace(/\/+$/, '')));
|
|
127
|
+
default:
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Records a PR the dot's scope keeps out: an events row with the reason (once per delivery), a log line, and an entry in the result. */
|
|
132
|
+
function skipScope(w, ev, reason, stage, skipped) {
|
|
133
|
+
skipped.push({ watchId: w.id, stage: stage ?? 'reviewer', reason });
|
|
134
|
+
if (!findOne('events', { watchId: w.id, dedupeKey: ev.dedupeKey })) {
|
|
135
|
+
insert('events', { watchId: w.id, source: ev.source, kind: ev.kind, dedupeKey: ev.dedupeKey, title: ev.title, url: ev.url, trigger: ev, skipped: reason });
|
|
136
|
+
}
|
|
137
|
+
log.info(`${w.name}: skipped "${ev.title}": ${reason}`);
|
|
138
|
+
}
|
|
139
|
+
/** True when this dot has a PR check for this PR head that did not fail. */
|
|
140
|
+
export function reviewedHead(watchId, ev) {
|
|
141
|
+
if (!ev.pr?.headSha || !ev.repo)
|
|
142
|
+
return false;
|
|
143
|
+
const want = `${ev.repo.owner}/${ev.repo.name}`.toLowerCase();
|
|
144
|
+
return list('jobs', { watchId, kind: 'pr_check' }, { orderBy: 'id DESC', limit: 300 }).some((j) => {
|
|
145
|
+
const p = (j.payload ?? {});
|
|
146
|
+
return (j.status !== 'failed' &&
|
|
147
|
+
p.pr?.number === ev.pr.number &&
|
|
148
|
+
p.pr?.headSha === ev.pr.headSha &&
|
|
149
|
+
(!p.repo || `${p.repo.owner}/${p.repo.name}`.toLowerCase() === want));
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* A GitHub issue that a dot's tracker covers but its scope skips (a missing required label, a type, a milestone, a skip
|
|
154
|
+
* label) is logged with the reason, once per dot, so a team can tell why an issue got no review. Dots whose tracker
|
|
155
|
+
* does not list the repo say nothing: the issue was never theirs.
|
|
156
|
+
*/
|
|
157
|
+
function logSkippedIssue(all, targets, ev) {
|
|
158
|
+
if (ev.source !== 'github' || ev.ticket?.tracker !== 'github')
|
|
159
|
+
return;
|
|
160
|
+
for (const w of all) {
|
|
161
|
+
if (w.paused || w.archived || targets.includes(w) || w.tracker?.kind !== 'github')
|
|
162
|
+
continue;
|
|
163
|
+
if (!trackerRepos(w).includes(lc(ev.ticket.projectKey)))
|
|
164
|
+
continue;
|
|
165
|
+
const skip = issueSkip(w, ev);
|
|
166
|
+
if (!skip)
|
|
167
|
+
continue;
|
|
168
|
+
// An in-scope issue whose event starts nothing is not a dropped issue: the wording keeps a team from reading it as one.
|
|
169
|
+
log.info(skip.inScope ? `${w.name}: no new review for ${ev.ticket.key}: ${skip.why}` : `${w.name}: skipped issue ${ev.ticket.key}: ${skip.why}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The single path from a normalized TriggerEvent to stored events rows and queued jobs.
|
|
174
|
+
* Webhooks, simulate, and any other producer go through here.
|
|
175
|
+
*/
|
|
176
|
+
export function dispatchTrigger(ev, opts = {}) {
|
|
177
|
+
const jobKind = jobKindFor(ev);
|
|
178
|
+
if (!jobKind)
|
|
179
|
+
return { accepted: false, reason: `no job for trigger ${ev.kind}`, trigger: ev, jobs: [] };
|
|
180
|
+
const all = list('watches');
|
|
181
|
+
const stage = stageFor(jobKind);
|
|
182
|
+
const skipped = [];
|
|
183
|
+
let targets;
|
|
184
|
+
if (opts.watchIds?.length)
|
|
185
|
+
targets = all.filter((w) => !w.archived && opts.watchIds.includes(w.id));
|
|
186
|
+
else {
|
|
187
|
+
const pool = all.filter((w) => !w.paused && !w.archived && (!opts.onlyWatchIds || opts.onlyWatchIds.includes(w.id)));
|
|
188
|
+
targets = [];
|
|
189
|
+
for (const w of pool) {
|
|
190
|
+
if (!matchesSources(w, ev))
|
|
191
|
+
continue;
|
|
192
|
+
// A PR outside the repo's PR scope is recorded as a skip with its rule, never dropped without a trace (KAT-354).
|
|
193
|
+
// A simulated event and a review a person asked for are not held back (outOfScope also checks requestedBy).
|
|
194
|
+
const why = opts.simulate ? null : outOfScope(w, ev);
|
|
195
|
+
if (why)
|
|
196
|
+
skipScope(w, ev, why, stage, skipped);
|
|
197
|
+
else
|
|
198
|
+
targets.push(w);
|
|
199
|
+
}
|
|
200
|
+
logSkippedIssue(all, targets, ev);
|
|
201
|
+
if (!targets.length && !skipped.length && opts.fallbackToAll)
|
|
202
|
+
targets = all.filter((w) => !w.paused && !w.archived);
|
|
203
|
+
}
|
|
204
|
+
if (!targets.length && skipped.length)
|
|
205
|
+
return { accepted: false, reason: skipped[0].reason, trigger: ev, jobKind, jobs: [], skipped };
|
|
206
|
+
if (!targets.length)
|
|
207
|
+
return { accepted: false, reason: 'no matching dot', trigger: ev, jobKind, jobs: [] };
|
|
208
|
+
const jobs = [];
|
|
209
|
+
let duplicates = 0;
|
|
210
|
+
let stale = 0;
|
|
211
|
+
for (const w of targets) {
|
|
212
|
+
// A stage that is off queues nothing. The event row keeps the trigger and the reason, so the skip is never silent.
|
|
213
|
+
if (stage && !stageOn(w, stage)) {
|
|
214
|
+
const reason = stageOffReason(stage);
|
|
215
|
+
skipped.push({ watchId: w.id, stage, reason });
|
|
216
|
+
if (!findOne('events', { watchId: w.id, dedupeKey: ev.dedupeKey })) {
|
|
217
|
+
insert('events', {
|
|
218
|
+
watchId: w.id,
|
|
219
|
+
source: ev.source,
|
|
220
|
+
kind: ev.kind,
|
|
221
|
+
dedupeKey: ev.dedupeKey,
|
|
222
|
+
title: ev.title,
|
|
223
|
+
url: ev.url,
|
|
224
|
+
trigger: ev,
|
|
225
|
+
skipped: reason,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
log.info(`${w.name}: skipped ${jobKind} "${ev.title}": ${reason}`);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
// KAT-346: a delivery for a head that is no longer the PR's current head starts no run and cancels nothing.
|
|
232
|
+
if (jobKind === 'pr_check' && !opts.simulate && !ev.requestedBy && isStalePrHead(ev)) {
|
|
233
|
+
stale++;
|
|
234
|
+
log.info(`${w.name}: ignored ${jobKind} "${ev.title}": stale head ${ev.pr?.headSha?.slice(0, 7) ?? ''}`);
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const dedupeKey = `${ev.dedupeKey}:${w.id}:${jobKind}`;
|
|
238
|
+
// A draft turning ready has the head a dot may have reviewed while it was a draft: the dot that did takes no second review (KAT-354).
|
|
239
|
+
if (ev.pr?.readyForReview && !ev.requestedBy && reviewedHead(w.id, ev)) {
|
|
240
|
+
duplicates++;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (findOne('jobs', { dedupeKey }) || reviewedSameBody(w.id, ev)) {
|
|
244
|
+
duplicates++;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
// KAT-408: a ticket edited while its review still waits keeps one review, the newest. A backfilled review (nobody asked for it)
|
|
248
|
+
// never replaces one that is queued, and a simulated event never stops a real review (KAT-350).
|
|
249
|
+
const olderReviews = jobKind === 'ticket_review' && !opts.simulate ? queuedTicketReviews(w.id, ev) : [];
|
|
250
|
+
if (ev.backfill && olderReviews.length) {
|
|
251
|
+
duplicates++;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
// A late delivery for an older edit than the queued review reads old text: it starts nothing and stops nothing.
|
|
255
|
+
if (!ev.requestedBy && isStaleTicketEdit(olderReviews, ev)) {
|
|
256
|
+
duplicates++;
|
|
257
|
+
log.info(`${w.name}: ignored ${jobKind} "${ev.title}": a newer edit of the ticket is already queued`);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
const evRow = insert('events', {
|
|
261
|
+
watchId: w.id,
|
|
262
|
+
source: ev.source,
|
|
263
|
+
kind: ev.kind,
|
|
264
|
+
dedupeKey: ev.dedupeKey,
|
|
265
|
+
title: ev.title,
|
|
266
|
+
url: ev.url,
|
|
267
|
+
trigger: ev,
|
|
268
|
+
});
|
|
269
|
+
// KAT-344: a pr_check waits for a quiet period, and the jobs of older heads of the same PR stop.
|
|
270
|
+
// A review that replaces one held for the daily model cap stays held until the reset, so no second "waiting for the cap" run is made.
|
|
271
|
+
const wait = inheritedWait(olderReviews);
|
|
272
|
+
const runAfter = jobKind === 'pr_check' && !opts.simulate ? debouncedRunAfter(w, ev) : wait.runAfter;
|
|
273
|
+
const jobId = enqueue({ kind: jobKind, watchId: w.id, eventId: evRow.id, dedupeKey, payload: ev, ...(runAfter ? { runAfter } : {}) });
|
|
274
|
+
if (!jobId) {
|
|
275
|
+
duplicates++;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
update('events', evRow.id, { jobId });
|
|
279
|
+
// A simulated event (e2e, demo) never stops a real review of the same PR (KAT-350).
|
|
280
|
+
if (jobKind === 'pr_check' && !opts.simulate)
|
|
281
|
+
supersedeOlderPrJobs(jobId, w, ev);
|
|
282
|
+
if (olderReviews.length) {
|
|
283
|
+
supersedeQueuedTicketReviews(jobId, olderReviews, ev);
|
|
284
|
+
if (wait.heldBy)
|
|
285
|
+
update('jobs', jobId, { heldBy: wait.heldBy });
|
|
286
|
+
}
|
|
287
|
+
jobs.push({ watchId: w.id, jobId, eventId: evRow.id });
|
|
288
|
+
}
|
|
289
|
+
const extra = skipped.length ? { skipped } : {};
|
|
290
|
+
if (!jobs.length && skipped.length && !duplicates)
|
|
291
|
+
return { accepted: false, reason: skipped[0].reason, trigger: ev, jobKind, jobs, ...extra };
|
|
292
|
+
if (!jobs.length && stale && !duplicates)
|
|
293
|
+
return { accepted: false, reason: 'stale head', trigger: ev, jobKind, jobs, ...extra };
|
|
294
|
+
if (!jobs.length && duplicates)
|
|
295
|
+
return { accepted: true, duplicate: true, trigger: ev, jobKind, jobs, ...extra };
|
|
296
|
+
log.info(`${ev.source} ${ev.kind} "${ev.title}" -> ${jobKind} x${jobs.length}`);
|
|
297
|
+
return { accepted: true, trigger: ev, jobKind, jobs, ...extra };
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* A pull_request delivery says the PR's state and head: pending approvals for a merged or closed PR,
|
|
301
|
+
* and check-run drafts for an old head, expire (KAT-94). Closed PRs make no trigger, so this runs first.
|
|
302
|
+
*/
|
|
303
|
+
export function notePrState(payload) {
|
|
304
|
+
try {
|
|
305
|
+
const p = (payload ?? {});
|
|
306
|
+
const pr = p.pull_request;
|
|
307
|
+
const owner = p.repository?.owner?.login;
|
|
308
|
+
const name = p.repository?.name;
|
|
309
|
+
if (!pr || !owner || !name || !Number.isInteger(Number(pr.number)))
|
|
310
|
+
return;
|
|
311
|
+
const state = pr.merged || pr.merged_at ? 'merged' : pr.state === 'open' ? 'open' : 'closed';
|
|
312
|
+
if (state === 'open')
|
|
313
|
+
notePrHead(`${owner}/${name}`, Number(pr.number), String(pr.head?.sha ?? ''), typeof pr.updated_at === 'string' ? pr.updated_at : undefined);
|
|
314
|
+
for (const w of list('watches')) {
|
|
315
|
+
// Any repo in the dot's set can own the PR, not only the first app repo.
|
|
316
|
+
if (!findRepo(w, { owner, name }))
|
|
317
|
+
continue;
|
|
318
|
+
// Only drafts older than this delivery's PR update: a redelivered or out-of-order event cannot expire newer ones.
|
|
319
|
+
const updated = typeof pr.updated_at === 'string' ? pr.updated_at : undefined;
|
|
320
|
+
applyPrState(w.id, Number(pr.number), { state, headSha: String(pr.head?.sha ?? ''), ...(state === 'merged' && pr.merge_commit_sha ? { mergeSha: String(pr.merge_commit_sha) } : {}) }, updated, `${owner}/${name}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
catch (err) {
|
|
324
|
+
log.warn(`pull_request approval check failed: ${String(err)}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/** True when a dot that holds `repo` as an app repo lists `branch` in testBranches (KAT-292). */
|
|
328
|
+
function listsTestBranch(repo, branch) {
|
|
329
|
+
return list('watches').some((w) => !w.paused && !w.archived && (w.testBranches ?? []).includes(branch) && findRepo(w, repo)?.role === 'app');
|
|
330
|
+
}
|
|
331
|
+
export function normalize(source, eventName, payload, deliveryId) {
|
|
332
|
+
switch (source) {
|
|
333
|
+
case 'github':
|
|
334
|
+
if (eventName === 'issues' || eventName === 'issue_comment')
|
|
335
|
+
return normalizeGithubIssue(eventName, payload);
|
|
336
|
+
return normalizeGithub(eventName ?? '', payload, deliveryId, { isTestBranch: listsTestBranch });
|
|
337
|
+
case 'jira':
|
|
338
|
+
return normalizeJira(payload, deliveryId);
|
|
339
|
+
case 'linear':
|
|
340
|
+
return normalizeLinear(payload);
|
|
341
|
+
default: {
|
|
342
|
+
const p = (payload ?? {});
|
|
343
|
+
const kind = p.kind ?? (source === 'statuspage' ? 'statuspage' : source === 'schedule' ? 'schedule' : 'probe_down');
|
|
344
|
+
return {
|
|
345
|
+
...p,
|
|
346
|
+
source,
|
|
347
|
+
kind,
|
|
348
|
+
dedupeKey: p.dedupeKey ?? `${source}:${kind}:${p.probe?.url ?? p.url ?? ''}:${Date.now()}`,
|
|
349
|
+
title: p.title ?? (kind === 'probe_down' ? `Probe failing: ${p.probe?.url ?? ''}` : `${source} ${kind}`),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/** Normalizes a payload; returns the event, or the result that ends the delivery. */
|
|
355
|
+
function prepare(source, eventName, payload, opts) {
|
|
356
|
+
let ev;
|
|
357
|
+
if (source === 'github' && eventName === 'pull_request' && !opts.simulate)
|
|
358
|
+
notePrState(payload);
|
|
359
|
+
try {
|
|
360
|
+
ev = normalize(source, eventName, payload, opts.deliveryId);
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
log.error(`normalize ${source}/${eventName ?? ''} failed`, err);
|
|
364
|
+
return { result: { accepted: false, reason: `normalize failed: ${String(err)}`, jobs: [] } };
|
|
365
|
+
}
|
|
366
|
+
if (!ev)
|
|
367
|
+
return { result: { accepted: false, reason: `ignored ${source} event ${eventName ?? ''}`.trim(), jobs: [] } };
|
|
368
|
+
// Simulations must never collide with each other or with real deliveries.
|
|
369
|
+
if (opts.simulate)
|
|
370
|
+
ev = { ...ev, dedupeKey: `${ev.dedupeKey}:sim:${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}` };
|
|
371
|
+
return { ev };
|
|
372
|
+
}
|
|
373
|
+
export function ingest(source, eventName, payload, opts = {}) {
|
|
374
|
+
const p = prepare(source, eventName, payload, opts);
|
|
375
|
+
return 'result' in p ? p.result : dispatchTrigger(p.ev, opts);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Like ingest, but first reads what the dots need from GitHub: the PR's changed files when a dot filters the repo by
|
|
379
|
+
* path (KAT-160), and the team and linked issue answers when a dot scopes its PRs (KAT-354).
|
|
380
|
+
*/
|
|
381
|
+
export async function ingestResolved(source, eventName, payload, opts = {}) {
|
|
382
|
+
const p = prepare(source, eventName, payload, opts);
|
|
383
|
+
if ('result' in p)
|
|
384
|
+
return p.result;
|
|
385
|
+
const ev = await resolveChangedFiles(p.ev);
|
|
386
|
+
return dispatchTrigger(opts.simulate ? ev : await resolvePrScope(ev), opts);
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* The answer for a source whose webhook secret is unset: 503 and nothing queued, unless
|
|
390
|
+
* LOCALDOST_ALLOW_UNSIGNED_WEBHOOKS=1. Returns undefined when the event may go on to be handled.
|
|
391
|
+
*/
|
|
392
|
+
function unsignedGate(setting, label, warnKey) {
|
|
393
|
+
if (config.allowUnsignedWebhooks) {
|
|
394
|
+
log.warnOnce(warnKey, `${setting} unset: ${label} webhook signatures are not verified (LOCALDOST_ALLOW_UNSIGNED_WEBHOOKS is on)`);
|
|
395
|
+
return undefined;
|
|
396
|
+
}
|
|
397
|
+
const text = `${setting} is not set, so this server refuses ${label} webhooks. Set ${setting} to the secret configured on the ${label} webhook. For a local demo only, set LOCALDOST_ALLOW_UNSIGNED_WEBHOOKS=1.`;
|
|
398
|
+
return { status: 503, body: { error: text }, text };
|
|
399
|
+
}
|
|
400
|
+
function header(h, name) {
|
|
401
|
+
const v = h[name.toLowerCase()];
|
|
402
|
+
return Array.isArray(v) ? v[0] : v;
|
|
403
|
+
}
|
|
404
|
+
function parseBody(raw, contentType) {
|
|
405
|
+
const text = raw.toString('utf8');
|
|
406
|
+
// GitHub can be configured to send form-encoded `payload=<json>`.
|
|
407
|
+
if (contentType?.includes('application/x-www-form-urlencoded')) {
|
|
408
|
+
const p = new URLSearchParams(text).get('payload');
|
|
409
|
+
return p ? JSON.parse(p) : {};
|
|
410
|
+
}
|
|
411
|
+
return text ? JSON.parse(text) : {};
|
|
412
|
+
}
|
|
413
|
+
function toResponse(r) {
|
|
414
|
+
return {
|
|
415
|
+
status: 202,
|
|
416
|
+
body: { ok: true, accepted: r.accepted, duplicate: r.duplicate ?? false, reason: r.reason, jobs: r.jobs.map((j) => j.jobId) },
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
/** Does any live dot set a PR scope on an app repo? */
|
|
420
|
+
function someDotScopesPrs() {
|
|
421
|
+
return list('watches').some((w) => !w.paused && !w.archived && watchRepos(w).some((r) => r.role === 'app' && !!r.prScope));
|
|
422
|
+
}
|
|
423
|
+
export function handleGithubHook(raw, headers) {
|
|
424
|
+
const secret = config.secrets.github;
|
|
425
|
+
const eventName = header(headers, 'x-github-event') ?? '';
|
|
426
|
+
if (secret) {
|
|
427
|
+
if (!verifyGithub(raw, secret, header(headers, 'x-hub-signature-256')))
|
|
428
|
+
return { status: 401, body: { error: 'bad signature' } };
|
|
429
|
+
// A signed delivery shows that GitHub sends webhooks here; the setup flow reads it (src/webhook-seen.ts).
|
|
430
|
+
noteWebhook('github', eventName);
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
const refused = unsignedGate('GITHUB_WEBHOOK_SECRET', 'GitHub', 'gh-secret');
|
|
434
|
+
if (refused)
|
|
435
|
+
return refused;
|
|
436
|
+
}
|
|
437
|
+
if (eventName === 'ping')
|
|
438
|
+
return { status: 200, body: { ok: true, pong: true } };
|
|
439
|
+
let payload;
|
|
440
|
+
try {
|
|
441
|
+
payload = parseBody(raw, header(headers, 'content-type'));
|
|
442
|
+
}
|
|
443
|
+
catch {
|
|
444
|
+
return { status: 400, body: { error: 'invalid JSON' } };
|
|
445
|
+
}
|
|
446
|
+
if (eventName === 'issues') {
|
|
447
|
+
recordIssueEvent(payload);
|
|
448
|
+
return toResponse(ingest('github', eventName, payload, { deliveryId: header(headers, 'x-github-delivery') }));
|
|
449
|
+
}
|
|
450
|
+
// `/localdost review` on an issue asks for a ticket review, on a PR for a new check; the write-access check is async.
|
|
451
|
+
if (eventName === 'issue_comment' && payload?.action === 'created') {
|
|
452
|
+
const p = payload;
|
|
453
|
+
if (p.issue?.pull_request)
|
|
454
|
+
return handlePrCommand(payload);
|
|
455
|
+
// A comment on an issue that is no command may answer the questions of a ticket review (KAT-393).
|
|
456
|
+
return REVIEW_COMMAND.test(String(p.comment?.body ?? '')) ? handleIssueCommand(payload) : handleIssueAnswer(payload);
|
|
457
|
+
}
|
|
458
|
+
// Sticky-comment edits carry checklist ticks; they update a run and start no job.
|
|
459
|
+
if (eventName === 'issue_comment')
|
|
460
|
+
return handleCommentEdit(payload);
|
|
461
|
+
// The normalizer keys dedupe on X-GitHub-Delivery when present; redeliveries reuse the same GUID.
|
|
462
|
+
// A pull_request may need its file list for repo pathFilters, so it answers after that read. A push to a repo with a PR
|
|
463
|
+
// scope needs the PR whose merge it is, so the scope can keep the merge of a PR it kept out from running (KAT-354).
|
|
464
|
+
if (eventName === 'pull_request' || (eventName === 'push' && someDotScopesPrs()))
|
|
465
|
+
return ingestResolved('github', eventName, payload, { deliveryId: header(headers, 'x-github-delivery') }).then(toResponse);
|
|
466
|
+
return toResponse(ingest('github', eventName, payload, { deliveryId: header(headers, 'x-github-delivery') }));
|
|
467
|
+
}
|
|
468
|
+
/** issue_comment: only edits of the sticky comment matter. The permission check is async, so it runs after the 202. */
|
|
469
|
+
export function handleCommentEdit(payload) {
|
|
470
|
+
const edit = normalizeCommentEdit('issue_comment', payload);
|
|
471
|
+
if (!edit)
|
|
472
|
+
return { status: 202, body: { ok: true, accepted: false, reason: 'not an edit of the localdost comment' } };
|
|
473
|
+
void applyChecklistEdit(edit)
|
|
474
|
+
.then((r) => log.info(`checklist edit on ${edit.repo.owner}/${edit.repo.name}#${edit.pr}: ${r.reason}`))
|
|
475
|
+
.catch((err) => log.error('checklist edit failed', err));
|
|
476
|
+
return { status: 202, body: { ok: true, accepted: true, checklist: true } };
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* issue_comment.created with `/localdost review` on an issue. Only users with write access may ask, so
|
|
480
|
+
* outsiders cannot spend model calls. The check runs after the 202.
|
|
481
|
+
*/
|
|
482
|
+
export function handleIssueCommand(payload, check) {
|
|
483
|
+
const ev = normalizeGithubIssue('issue_comment', payload);
|
|
484
|
+
if (!ev?.ticket)
|
|
485
|
+
return { status: 202, body: { ok: true, accepted: false, reason: 'not a /localdost review command on an issue' } };
|
|
486
|
+
const full = ev.ticket.projectKey;
|
|
487
|
+
const login = ev.ticket.change?.value ?? '';
|
|
488
|
+
const canWrite = check ?? ((repo, user) => issueApi(repo).writePermission(user));
|
|
489
|
+
void canWrite(full, login)
|
|
490
|
+
.then((ok) => {
|
|
491
|
+
if (ok !== true)
|
|
492
|
+
return log.info(`/localdost review on ${ev.ticket.key} by ${login}: ignored, no write access`);
|
|
493
|
+
const r = dispatchTrigger(ev);
|
|
494
|
+
log.info(`/localdost review on ${ev.ticket.key} by ${login}: ${r.accepted ? `${r.jobs.length} job(s)` : r.reason}`);
|
|
495
|
+
})
|
|
496
|
+
.catch((err) => log.error('/localdost review failed', err));
|
|
497
|
+
return { status: 202, body: { ok: true, accepted: true, command: true } };
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* issue_comment.created on an issue, no command in it (KAT-393): the same decision the poller makes for the comments it reads
|
|
501
|
+
* (src/flows/answers.ts). The checks that need GitHub (who wrote the issue, who has write access) run after the 202.
|
|
502
|
+
*/
|
|
503
|
+
export function answerFromWebhook(payload, deps = {}) {
|
|
504
|
+
const p = payload;
|
|
505
|
+
const repo = p?.repository;
|
|
506
|
+
const full = repo?.full_name ?? `${repo?.owner?.login ?? repo?.owner?.name ?? ''}/${repo?.name ?? ''}`;
|
|
507
|
+
const n = Number(p?.issue?.number);
|
|
508
|
+
if (!p?.comment || p.issue?.pull_request || !Number.isInteger(n) || !/^[^/]+\/[^/]+$/.test(full))
|
|
509
|
+
return Promise.resolve({ queued: 0, joined: 0, limit: 0, ignored: 1, retry: 0 });
|
|
510
|
+
// The delivery carries what the REST list does: the comment, its writer and role, and the issue it sits under.
|
|
511
|
+
const row = { ...p.comment, issue_url: p.comment.issue_url ?? `https://api.github.com/repos/${full}/issues/${n}` };
|
|
512
|
+
return handleNewComments(full, [row], deps);
|
|
513
|
+
}
|
|
514
|
+
/** A delivery that GitHub could not be asked about (the issue read or the write-access check failed) is judged again after each of these waits. */
|
|
515
|
+
export const ANSWER_WEBHOOK_RETRY_MS = [30_000, 5 * 60_000, 20 * 60_000];
|
|
516
|
+
const pause = (ms) => new Promise((resolve) => {
|
|
517
|
+
// The timer does not keep the process alive: a server that stops drops the retry, and a poll (when it is on) reads the comment again.
|
|
518
|
+
setTimeout(resolve, ms).unref();
|
|
519
|
+
});
|
|
520
|
+
/**
|
|
521
|
+
* answerFromWebhook, asked again after each wait of `delays` while GitHub fails (`retry` in the tally). A webhook is sent once, so without
|
|
522
|
+
* this a 5xx or a rate limit on the issue read would lose the answer for good. A comment judged on an earlier try is absorbed by its job
|
|
523
|
+
* key, so a dot that queued its review does not queue it twice. Returns the tally of the last try.
|
|
524
|
+
*/
|
|
525
|
+
export async function answerWithRetry(payload, deps = {}, delays = ANSWER_WEBHOOK_RETRY_MS, wait = pause) {
|
|
526
|
+
for (let i = 0;; i++) {
|
|
527
|
+
const t = await answerFromWebhook(payload, deps);
|
|
528
|
+
if (t.queued || t.joined || t.limit)
|
|
529
|
+
log.info(`issue comment: ${t.queued} review(s) queued, ${t.joined} joined to a waiting review, ${t.limit} over the daily limit`);
|
|
530
|
+
if (!t.retry)
|
|
531
|
+
return t;
|
|
532
|
+
if (i >= delays.length) {
|
|
533
|
+
log.warn(`issue comment: GitHub did not answer after ${i + 1} tries, so the comment is not judged`);
|
|
534
|
+
return t;
|
|
535
|
+
}
|
|
536
|
+
log.warn(`issue comment: GitHub did not answer, so the comment is judged again in ${Math.round(delays[i] / 1000)} s`);
|
|
537
|
+
await wait(delays[i]);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
export function handleIssueAnswer(payload, deps = {}) {
|
|
541
|
+
void answerWithRetry(payload, deps).catch((err) => log.error('issue comment answer check failed', err));
|
|
542
|
+
return { status: 202, body: { ok: true, accepted: false, reason: 'not a /localdost review command on an issue' } };
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* issue_comment.created with `/localdost review` on a pull request: a new check of its latest push, for every dot that watches the
|
|
546
|
+
* repo as an app repo (KAT-376, the footer of every report says it works). Only users with write access may ask, so outsiders
|
|
547
|
+
* cannot spend model calls, and a bot never asks. The check runs after the 202.
|
|
548
|
+
*/
|
|
549
|
+
export function handlePrCommand(payload, deps = {}) {
|
|
550
|
+
const p = payload;
|
|
551
|
+
const body = String(p?.comment?.body ?? '');
|
|
552
|
+
const repo = { owner: String(p?.repository?.owner?.login ?? p?.repository?.owner?.name ?? ''), name: String(p?.repository?.name ?? '') };
|
|
553
|
+
const pr = Number(p?.issue?.number);
|
|
554
|
+
const login = String(p?.sender?.login ?? '');
|
|
555
|
+
const no = (reason) => ({ status: 202, body: { ok: true, accepted: false, reason } });
|
|
556
|
+
if (p?.action !== 'created' || !p.issue?.pull_request || !Number.isInteger(pr) || !repo.owner || !repo.name)
|
|
557
|
+
return no('not a /localdost review command on a PR');
|
|
558
|
+
if (!REVIEW_COMMAND.test(body) || hasStickyMarker(body))
|
|
559
|
+
return no('not a /localdost review command on a PR');
|
|
560
|
+
if (p.sender?.type === 'Bot' || /\[bot\]$/.test(login))
|
|
561
|
+
return no('a bot asked');
|
|
562
|
+
const canWrite = deps.canWrite ?? ((w, r, user) => githubFor(w, { repo: r }).writePermission(user));
|
|
563
|
+
const ask = deps.ask ??
|
|
564
|
+
(async (w, n, r) => {
|
|
565
|
+
const { requestReview } = await import('./review/on-demand.js');
|
|
566
|
+
return requestReview(w, { pr: n }, { requestedBy: 'user', repo: r });
|
|
567
|
+
});
|
|
568
|
+
void (async () => {
|
|
569
|
+
const watches = list('watches').filter((w) => !w.archived && !w.paused && findRepo(w, repo)?.role === 'app');
|
|
570
|
+
for (const w of watches) {
|
|
571
|
+
if ((await canWrite(w, repo, login)) !== true) {
|
|
572
|
+
log.info(`/localdost review on ${repo.owner}/${repo.name}#${pr} by ${login}: ignored, no write access`);
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
const r = await ask(w, pr, `${repo.owner}/${repo.name}`);
|
|
576
|
+
log.info(`/localdost review on ${repo.owner}/${repo.name}#${pr} by ${login}: ${r.ok ? 'queued' : (r.error ?? 'not queued')}`);
|
|
577
|
+
}
|
|
578
|
+
})().catch((err) => log.error('/localdost review on a PR failed', err));
|
|
579
|
+
return { status: 202, body: { ok: true, accepted: true, command: true } };
|
|
580
|
+
}
|
|
581
|
+
export function handleJiraHook(raw, headers) {
|
|
582
|
+
const secret = config.secrets.jira;
|
|
583
|
+
if (secret) {
|
|
584
|
+
if (!verifyJira(raw, secret, header(headers, 'x-hub-signature')))
|
|
585
|
+
return { status: 401, body: { error: 'bad signature' } };
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
const refused = unsignedGate('JIRA_WEBHOOK_SECRET', 'Jira', 'jira-secret');
|
|
589
|
+
if (refused)
|
|
590
|
+
return refused;
|
|
591
|
+
}
|
|
592
|
+
let payload;
|
|
593
|
+
try {
|
|
594
|
+
payload = parseBody(raw, header(headers, 'content-type'));
|
|
595
|
+
}
|
|
596
|
+
catch {
|
|
597
|
+
return { status: 400, body: { error: 'invalid JSON' } };
|
|
598
|
+
}
|
|
599
|
+
return toResponse(ingest('jira', payload?.webhookEvent, payload, {
|
|
600
|
+
deliveryId: header(headers, 'x-atlassian-webhook-identifier'),
|
|
601
|
+
}));
|
|
602
|
+
}
|
|
603
|
+
export function handleLinearHook(raw, headers) {
|
|
604
|
+
const secret = config.secrets.linear;
|
|
605
|
+
if (!secret) {
|
|
606
|
+
const refused = unsignedGate('LINEAR_WEBHOOK_SECRET', 'Linear', 'linear-secret');
|
|
607
|
+
if (refused)
|
|
608
|
+
return refused;
|
|
609
|
+
}
|
|
610
|
+
let payload;
|
|
611
|
+
try {
|
|
612
|
+
payload = parseBody(raw, header(headers, 'content-type'));
|
|
613
|
+
}
|
|
614
|
+
catch {
|
|
615
|
+
return { status: 400, body: { error: 'invalid JSON' } };
|
|
616
|
+
}
|
|
617
|
+
if (secret) {
|
|
618
|
+
const v = verifyLinear(raw, secret, header(headers, 'linear-signature'), payload?.webhookTimestamp);
|
|
619
|
+
if (!v.ok)
|
|
620
|
+
return { status: 401, body: { error: v.reason } };
|
|
621
|
+
}
|
|
622
|
+
const p = payload;
|
|
623
|
+
return toResponse(ingest('linear', `${p?.type ?? ''}.${p?.action ?? ''}`, payload));
|
|
624
|
+
}
|
|
625
|
+
//# sourceMappingURL=webhooks.js.map
|