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
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
// Waiting for the deploy of a merge before its post-merge run (KAT-368). A merge reaches the QA environment a few minutes after it
|
|
2
|
+
// lands, and a run that starts at once tests the build from before the merge. A dot with `waitForDeploySec` above 0 and a
|
|
3
|
+
// `deployEnvironment` holds the post_merge job of a merge into the default branch until GitHub shows a successful deployment of
|
|
4
|
+
// the merge commit, or of a later commit that contains it, to that environment. Then the run tests. When the time is up the run
|
|
5
|
+
// tests anyway and says so in a step.
|
|
6
|
+
//
|
|
7
|
+
// The wait holds no queue slot. A gate (queue.ts onBeforeJob, like the model cap) looks for the deployment each time the queue claims
|
|
8
|
+
// the job; when there is none yet it sends the job back with `runAfter` and a run that shows the wait, and the slot is free again. The
|
|
9
|
+
// job is looked at again
|
|
10
|
+
// - every 30 s for a dot that polls GitHub, since nothing tells it a deploy finished (the poll cadence of the server),
|
|
11
|
+
// - at once when a deployment_status success for that repository and environment arrives, for a dot on webhooks, and
|
|
12
|
+
// - every 5 min as well on webhooks, since a delivery the server missed (a restart, a lost hook) would otherwise be waited out.
|
|
13
|
+
// Each look reads what webhooks said (the deployments the server heard of) and then GitHub (GET /repos/{o}/{r}/deployments?sha=&environment=
|
|
14
|
+
// and the statuses of each deployment). A deployment counts when it holds the merge commit and is on the default branch: a feature
|
|
15
|
+
// branch built on the merge is not a deploy of the merge. A newer merge into the same branch that waits for its own deploy replaces a
|
|
16
|
+
// job that waits. Newer means later in the branch, which GitHub's compare of the two commits says, and not the order the two events
|
|
17
|
+
// came in.
|
|
18
|
+
//
|
|
19
|
+
// Per repo (KAT-395): an app repo may set its own `deployEnvironment` and `waitForDeploySec`; the dot's two fields are the default for
|
|
20
|
+
// a repo that sets none. A repo with a wait of 0 does not wait while the dot waits for the others. A merge waits on its own repo's
|
|
21
|
+
// settings, and the deployments it looks at are those of that repo's merge commit in that repo's environment.
|
|
22
|
+
//
|
|
23
|
+
// All the deployments of one commit in one environment are one set: a push may deploy several services, each as its own deployment.
|
|
24
|
+
// The merge counts as deployed when the newest attempt of every service succeeded, and the wait ends with no test run when the newest
|
|
25
|
+
// attempt of one of them ended in `failure` or `error`: the build that would be tested does not hold the merge. A failed deployment that
|
|
26
|
+
// was retried is not a failed service: the retry is the newest attempt. Attempts of one service are told apart by the service the
|
|
27
|
+
// deployment names in a field made for it (payload or task). A name read from the description is a guess, since parallel jobs of one
|
|
28
|
+
// pipeline share it, so it and a deployment that names none go by order: a deployment of the same commit and environment made after
|
|
29
|
+
// the failure was written replaces it, and one made before it (a service deployed in parallel) does not. A failure of the
|
|
30
|
+
// merge commit's own deploy is final only after the later commits that contain the merge were looked at: one of them that deployed is
|
|
31
|
+
// the deploy of the merge. A plain step says so, the check on the commit closes, and no defect is drafted.
|
|
32
|
+
//
|
|
33
|
+
// The target of the tests is the Base URL unless a deployment of the set gave the address of the site: its `environment_url` is used
|
|
34
|
+
// only when its origin is the Base URL's origin, or the host or origin the repo names in `deployUrlMatch`, and only when it is the root
|
|
35
|
+
// of the site (https://web.qa.example.com, never https://api.qa.example.com/health). With no Base URL and no `deployUrlMatch`, the
|
|
36
|
+
// address is used when every deployment of the set that gives one gives the same origin.
|
|
37
|
+
//
|
|
38
|
+
// The run is interrupted with the reason `deploy_wait` while the job waits, so a restart loses nothing and the dot's health does not
|
|
39
|
+
// change. It carries one step with the environment and the time waited, rewritten on each look. When the wait ends the same run goes
|
|
40
|
+
// on (src/agent/runs.ts startRun finds it by the job).
|
|
41
|
+
import { log } from './config.js';
|
|
42
|
+
import { get, list, update } from './db.js';
|
|
43
|
+
import { addStep, closeDeployRun, holdRunForDeploy, startRun } from './agent/runs.js';
|
|
44
|
+
import { docsOnlyChange, mergeShaOf, testSavings } from './flows/testSavings.js';
|
|
45
|
+
import { closeUnrun, noteDeployWait, noteSupersededWait, scopeOf } from './flows/checkStatus.js';
|
|
46
|
+
import { eventOf, getDiff, repoTarget } from './flows/common.js';
|
|
47
|
+
import { testRepoSwitches, testReposFor } from './flows/testRepo.js';
|
|
48
|
+
import { githubFor, onDeploymentEnd } from './integrations/github.js';
|
|
49
|
+
import { wantsGithubPoll } from './monitor/pollers.js';
|
|
50
|
+
import { onBeforeJob, withJobContext } from './queue.js';
|
|
51
|
+
import { repoForEvent, targetRepo, testsOffRepo } from './repos.js';
|
|
52
|
+
import { cleanDeployEnvironment, cleanDeploySec } from './runner/command.js';
|
|
53
|
+
import { hostOf, matchesDeployUrl, originOf, targetUrlOf, uiBaseOf } from './target-url.js';
|
|
54
|
+
/** Seconds between two looks at GitHub for a dot that polls. */
|
|
55
|
+
export const DEPLOY_POLL_SEC = 30;
|
|
56
|
+
/** Seconds between two looks for a dot on webhooks, which a deployment_status delivery also wakes. */
|
|
57
|
+
export const DEPLOY_NUDGE_SEC = 300;
|
|
58
|
+
/** The label of the step a merge run carries when the time is up: the wording the pilot team reads on the run page. */
|
|
59
|
+
export const DEPLOY_TIMEOUT_LABEL = 'Tested before the QA deploy finished; the build may be older than this merge';
|
|
60
|
+
/** A deployment of a later commit counts only when GitHub wrote it after the job began, less this slack for the clocks of two machines. */
|
|
61
|
+
const LATER_SLACK_MS = 5 * 60_000;
|
|
62
|
+
/** Deployments heard on webhooks are kept for this long and this many for each repository and environment. */
|
|
63
|
+
const HEARD_MS = 24 * 3600_000;
|
|
64
|
+
const HEARD_MAX = 20;
|
|
65
|
+
/**
|
|
66
|
+
* The deploy wait of a merge, or null when it is off: no seconds, or no environment to wait on. The repo's own fields come first and
|
|
67
|
+
* the dot's are the default for a field the repo leaves out (KAT-395). A repo with 0 seconds does not wait, whatever the dot says.
|
|
68
|
+
*/
|
|
69
|
+
export function deployWaitOf(w, repo) {
|
|
70
|
+
const sec = cleanDeploySec(repo?.waitForDeploySec !== undefined && repo?.waitForDeploySec !== null ? repo.waitForDeploySec : w.waitForDeploySec);
|
|
71
|
+
const environment = cleanDeployEnvironment(repo?.deployEnvironment) ?? cleanDeployEnvironment(w.deployEnvironment);
|
|
72
|
+
return sec && environment ? { sec, environment } : null;
|
|
73
|
+
}
|
|
74
|
+
/** The environment as a person writes it in a sentence: qa is QA, any other name stays as it was typed. */
|
|
75
|
+
export function environmentWords(environment) {
|
|
76
|
+
return environment.trim().toLowerCase() === 'qa' ? 'QA' : environment.trim();
|
|
77
|
+
}
|
|
78
|
+
export { targetUrlOf };
|
|
79
|
+
/** True when the host of `url` is the host of `base` or a subdomain of it. */
|
|
80
|
+
export function withinSiteOf(base, url) {
|
|
81
|
+
const b = hostOf(base);
|
|
82
|
+
const h = hostOf(url);
|
|
83
|
+
return !!b && !!h && (h === b || h.endsWith(`.${b}`));
|
|
84
|
+
}
|
|
85
|
+
/** True when a test login of the dot (runner.passEnv, a file runner.copyFiles copies in, a Tests repo's passEnv, or an AI-Vision credential variable) would go with a run. */
|
|
86
|
+
function carriesTestLogin(w, ev) {
|
|
87
|
+
const ai = w.runner.aivision;
|
|
88
|
+
return (!!w.runner.passEnv?.length ||
|
|
89
|
+
!!w.runner.copyFiles?.length ||
|
|
90
|
+
testReposFor(w, ev, 'post_merge').some((r) => !!r.test?.passEnv?.length) ||
|
|
91
|
+
!!(ai && (ai.passEnv?.length || ai.tokenEnv || ai.cookieEnv || ai.userEnv || ai.passwordEnv)));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The address a merge's tests run against after the deploy (KAT-395): the environment URL of the deployment. GitHub gives that
|
|
95
|
+
* address, and anyone who can write a deployment status in the environment chooses it, so a dot that carries a test login uses it only
|
|
96
|
+
* when it is on the Base URL's own site (the same host or a subdomain of it). Any other address is left out, and the tests run against
|
|
97
|
+
* the Base URL as before. `ignored` is the host that was left out.
|
|
98
|
+
*/
|
|
99
|
+
export function deployTargetFor(w, ev, url) {
|
|
100
|
+
if (!url)
|
|
101
|
+
return {};
|
|
102
|
+
if (!carriesTestLogin(w, ev) || withinSiteOf(w.baseUrl, url))
|
|
103
|
+
return { url };
|
|
104
|
+
return { ignored: hostOf(url) ?? url };
|
|
105
|
+
}
|
|
106
|
+
const lc = (s) => s.toLowerCase();
|
|
107
|
+
const sameSha = (a, b) => !!a && !!b && (a === b || a.startsWith(b) || b.startsWith(a));
|
|
108
|
+
const repoKey = (r) => lc(`${r.owner}/${r.name}`);
|
|
109
|
+
/** "2 min 30 s", "45 s", "1 h 5 min": the time of a step. */
|
|
110
|
+
export function durationText(ms) {
|
|
111
|
+
const s = Math.max(0, Math.round(ms / 1000));
|
|
112
|
+
if (s < 60)
|
|
113
|
+
return `${s} s`;
|
|
114
|
+
const m = Math.floor(s / 60);
|
|
115
|
+
if (m < 60)
|
|
116
|
+
return s % 60 ? `${m} min ${s % 60} s` : `${m} min`;
|
|
117
|
+
return m % 60 ? `${Math.floor(m / 60)} h ${m % 60} min` : `${Math.floor(m / 60)} h`;
|
|
118
|
+
}
|
|
119
|
+
const heard = new Map();
|
|
120
|
+
const heardKey = (repo, environment) => `${repoKey(repo)}@${lc(environment)}`;
|
|
121
|
+
/** Ids for deliveries that carry none, rising so a later delivery is a later deployment. Far from any id GitHub gives. */
|
|
122
|
+
let heardSeq = Number.MIN_SAFE_INTEGER;
|
|
123
|
+
const HEARD_DEPLOYMENTS_MAX = 30;
|
|
124
|
+
function hear(d, now = Date.now()) {
|
|
125
|
+
if (!d.environment || !d.sha)
|
|
126
|
+
return;
|
|
127
|
+
const key = heardKey(d.repo, d.environment);
|
|
128
|
+
const live = (heard.get(key) ?? []).filter((h) => now - h.at < HEARD_MS);
|
|
129
|
+
const before = live.find((h) => h.sha === d.sha);
|
|
130
|
+
const kept = live.filter((h) => h.sha !== d.sha);
|
|
131
|
+
const deployments = [...(before?.deployments ?? [])];
|
|
132
|
+
const at = deployments.findIndex((x) => d.id !== undefined && x.id === d.id);
|
|
133
|
+
const prior = at >= 0 ? deployments[at] : undefined;
|
|
134
|
+
const row = {
|
|
135
|
+
id: d.id ?? ++heardSeq,
|
|
136
|
+
sha: d.sha,
|
|
137
|
+
environment: d.environment,
|
|
138
|
+
state: d.state,
|
|
139
|
+
// A deployment that succeeded at any time was deployed, like a status list of GitHub reads.
|
|
140
|
+
succeeded: d.state === 'success' || !!prior?.succeeded,
|
|
141
|
+
...((d.at ?? prior?.at) ? { at: (d.at ?? prior?.at) } : {}),
|
|
142
|
+
...((d.createdAt ?? prior?.createdAt) ? { createdAt: (d.createdAt ?? prior?.createdAt) } : {}),
|
|
143
|
+
...((d.service ?? prior?.service) ? { service: (d.service ?? prior?.service) } : {}),
|
|
144
|
+
...((d.service ? d.serviceGuessed : prior?.serviceGuessed) ? { serviceGuessed: true } : {}),
|
|
145
|
+
};
|
|
146
|
+
if (at >= 0)
|
|
147
|
+
deployments[at] = row;
|
|
148
|
+
else
|
|
149
|
+
deployments.push(row);
|
|
150
|
+
const set = deployments.slice(-HEARD_DEPLOYMENTS_MAX);
|
|
151
|
+
const verdict = judgeSet(set);
|
|
152
|
+
const failed = verdict.state === 'failed' ? (verdict.failed.state === 'error' ? 'error' : 'failure') : undefined;
|
|
153
|
+
heard.set(key, [{ sha: d.sha, at: now, ok: set.some((x) => x.succeeded), ...(failed ? { failed } : {}), deployments: set }, ...kept].slice(0, HEARD_MAX));
|
|
154
|
+
}
|
|
155
|
+
/** True when a deployment succeeded in this repository and environment after `since` (ms): a delivery that arrived while a look was under way. */
|
|
156
|
+
function heardSince(repo, environment, since) {
|
|
157
|
+
return (heard.get(heardKey(repo, environment)) ?? []).some((h) => h.at > since);
|
|
158
|
+
}
|
|
159
|
+
/** Forgets every deployment heard. Used by tests. */
|
|
160
|
+
export function resetHeardDeployments() {
|
|
161
|
+
heard.clear();
|
|
162
|
+
}
|
|
163
|
+
/** True when the newest status of the deployment is a failure or an error and none was a success. */
|
|
164
|
+
const failedDeployment = (d) => !d.succeeded && (d.state === 'failure' || d.state === 'error');
|
|
165
|
+
const timeOf = (iso) => {
|
|
166
|
+
const t = iso ? Date.parse(iso) : NaN;
|
|
167
|
+
return Number.isFinite(t) ? t : undefined;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* True when both deployments name the same service in a field made for it (payload, task). A name read from the description is a guess:
|
|
171
|
+
* parallel jobs of one pipeline share it once their numbers are cut, so it never makes the higher id a retry on its own (KAT-403).
|
|
172
|
+
*/
|
|
173
|
+
const sameNamedService = (a, b) => !!a.service && a.service === b.service && !a.serviceGuessed && !b.serviceGuessed;
|
|
174
|
+
/**
|
|
175
|
+
* True when `later` is a newer attempt at what `earlier` deployed. Both name a service: the same one, whatever the order of the times
|
|
176
|
+
* (a retry made while the first attempt still ran is older than the failure that attempt wrote later). Otherwise (one or both name
|
|
177
|
+
* none) it is a deployment of the same commit and environment that GitHub made after the failure of `earlier` was written. A
|
|
178
|
+
* deployment made before that (a service deployed in parallel, whose own deploy finished first) is another deployment, not a retry.
|
|
179
|
+
* With times unknown a keyless pair is two deployments.
|
|
180
|
+
*/
|
|
181
|
+
function newerAttempt(later, earlier) {
|
|
182
|
+
if (later === earlier || later.id <= earlier.id)
|
|
183
|
+
return false;
|
|
184
|
+
if (!!later.service && !!earlier.service && later.service !== earlier.service)
|
|
185
|
+
return false;
|
|
186
|
+
// The same named service: the higher id is the newer attempt, whenever GitHub wrote the failure of the older one. A retry is often made
|
|
187
|
+
// while the first attempt is still running, so the failure of that attempt is written after the retry was created (KAT-403).
|
|
188
|
+
if (sameNamedService(later, earlier))
|
|
189
|
+
return true;
|
|
190
|
+
const made = timeOf(later.createdAt);
|
|
191
|
+
const was = timeOf(earlier.at);
|
|
192
|
+
if (made !== undefined && was !== undefined)
|
|
193
|
+
return made >= was;
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* The address a set of deployments gives for the tests, or undefined (keep the Base URL). Only a successful deployment gives one, and
|
|
198
|
+
* only the root of a site (uiBaseOf). It is used when it is on the origin of the Base URL, or on the host or origin the repo names;
|
|
199
|
+
* a repo's own name comes first. With neither a Base URL nor a name, an address counts only when the deployments agree on one origin.
|
|
200
|
+
*/
|
|
201
|
+
export function pickTargetUrl(set, rule = {}) {
|
|
202
|
+
const urls = set.filter((d) => d.succeeded).flatMap((d) => uiBaseOf(d.url, rule.baseUrl) ?? []);
|
|
203
|
+
if (rule.match) {
|
|
204
|
+
const named = urls.find((u) => matchesDeployUrl(rule.match, u));
|
|
205
|
+
if (named)
|
|
206
|
+
return named;
|
|
207
|
+
}
|
|
208
|
+
const base = originOf(rule.baseUrl);
|
|
209
|
+
if (base)
|
|
210
|
+
return urls.find((u) => originOf(u) === base);
|
|
211
|
+
if (rule.match)
|
|
212
|
+
return undefined;
|
|
213
|
+
const origins = new Set(urls.map((u) => originOf(u)));
|
|
214
|
+
return origins.size === 1 ? urls[0] : undefined;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* The deployments of a commit in an environment as one set (KAT-395, KAT-388). One push may deploy several services, each as its own
|
|
218
|
+
* deployment, so the commit is deployed only when the newest attempt of every service succeeded, and a failure of the newest attempt
|
|
219
|
+
* of any one is a failed deploy. An attempt that a retry replaced (newerAttempt) is left out: a keyless failure is replaced by a
|
|
220
|
+
* deployment made after it, a failure of a named service by a newer deployment of that service. A deployment that GitHub marked
|
|
221
|
+
* inactive without a success was replaced before it finished and is left out. `none` for a commit with no deployment, `pending` while
|
|
222
|
+
* at least one is still on its way.
|
|
223
|
+
*/
|
|
224
|
+
export function judgeSet(set, rule = {}) {
|
|
225
|
+
const live = set.filter((d) => d.succeeded || d.state !== 'inactive');
|
|
226
|
+
if (!live.length)
|
|
227
|
+
return { state: 'none' };
|
|
228
|
+
const current = live.filter((d) => !live.some((y) => newerAttempt(y, d) && (sameNamedService(y, d) || failedDeployment(d))));
|
|
229
|
+
const failed = current.find(failedDeployment);
|
|
230
|
+
if (failed)
|
|
231
|
+
return { state: 'failed', failed };
|
|
232
|
+
if (current.every((d) => d.succeeded)) {
|
|
233
|
+
const url = pickTargetUrl(current, rule);
|
|
234
|
+
return { state: 'deployed', ...(url ? { url } : {}) };
|
|
235
|
+
}
|
|
236
|
+
return { state: 'pending' };
|
|
237
|
+
}
|
|
238
|
+
/** True when `deploySha` contains `mergeSha`: the compare of the merge commit against the deploy says it is behind it, or the same. */
|
|
239
|
+
async function contains(gh, deploySha, mergeSha) {
|
|
240
|
+
try {
|
|
241
|
+
const rel = await gh.compareStatus(deploySha, mergeSha);
|
|
242
|
+
return rel === 'behind' || rel === 'identical';
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* True when `sha` is on the branch: the branch head is that commit or holds it. A commit of a feature branch built on the merge holds
|
|
250
|
+
* the merge commit too, with code that is not merged, so a deploy of it is not the deploy of the merge. A GitHub error is no.
|
|
251
|
+
*/
|
|
252
|
+
async function onBranch(gh, branch, sha) {
|
|
253
|
+
if (!branch)
|
|
254
|
+
return true;
|
|
255
|
+
try {
|
|
256
|
+
const rel = await gh.compareStatus(branch, sha);
|
|
257
|
+
return rel === 'behind' || rel === 'identical';
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Is the merge commit deployed to the environment? GitHub first: the deployments of the merge commit itself are one set (judgeSet),
|
|
265
|
+
* and when that set has none or is not finished, the newest few of the environment, which may hold a later commit. A later commit
|
|
266
|
+
* counts when GitHub says it contains the merge commit and that it is on the branch, and its own deployments are judged as a set the
|
|
267
|
+
* same way. A deployment that webhooks reported counts for itself only when GitHub lists no deployment of that commit, or cannot be read:
|
|
268
|
+
* a delivery says one deployment succeeded, and the set may hold more. A GitHub error is returned, not thrown: the job keeps waiting,
|
|
269
|
+
* and the timeout step names it.
|
|
270
|
+
*/
|
|
271
|
+
async function lookDeployed(o) {
|
|
272
|
+
const { gh, repo, branch, environment, sha } = o;
|
|
273
|
+
const rule = o.rule ?? {};
|
|
274
|
+
/** A later commit counts when it holds the merge commit and the branch holds it. */
|
|
275
|
+
const laterCounts = async (later) => (await contains(gh, later, sha)) && (await onBranch(gh, branch, later));
|
|
276
|
+
// What deliveries reported. GitHub's list outranks them when it can be read and has the commit; they stand when it has none or is unreadable.
|
|
277
|
+
const heardAll = heard.get(heardKey(repo, environment)) ?? [];
|
|
278
|
+
const heardHere = heardAll.filter((h) => h.ok && !h.failed);
|
|
279
|
+
const heardFailed = (commit) => heardAll.find((h) => sameSha(h.sha, commit) && h.failed);
|
|
280
|
+
const setOf = (commit) => gh.deployments({ environment, sha: commit, limit: 30 });
|
|
281
|
+
let error;
|
|
282
|
+
// The merge commit's own deploy failed. That is final only after the later commits that hold the merge were looked at, since one of
|
|
283
|
+
// them that deployed is the deploy of the merge (the failure was fixed by a later push, or by a new commit on the branch).
|
|
284
|
+
let ownFailure;
|
|
285
|
+
// True when the later commits could not be listed or judged on GitHub, so a rescue may be hidden.
|
|
286
|
+
let laterUnread = false;
|
|
287
|
+
const verdicts = new Map();
|
|
288
|
+
try {
|
|
289
|
+
if (gh.deployments) {
|
|
290
|
+
const own = judgeSet(await setOf(sha), rule);
|
|
291
|
+
verdicts.set(sha, own);
|
|
292
|
+
if (own.state === 'failed')
|
|
293
|
+
ownFailure = { sha: own.failed.sha || sha, later: false, state: own.failed.state, id: own.failed.id };
|
|
294
|
+
if (own.state === 'deployed')
|
|
295
|
+
return { found: { sha, later: false, ...(own.url ? { url: own.url } : {}) } };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
error = err instanceof Error ? err.message : String(err);
|
|
300
|
+
}
|
|
301
|
+
// GitHub lists nothing of this commit, or could not be read: what deliveries said stands. A failed deployment comes first, since a
|
|
302
|
+
// commit with one failed deployment is not deployed whatever else succeeded.
|
|
303
|
+
const blind = !!error || verdicts.get(sha)?.state === 'none' || !gh.deployments;
|
|
304
|
+
const own = verdicts.get(sha);
|
|
305
|
+
const ownFailed = heardFailed(sha);
|
|
306
|
+
if (ownFailed && blind)
|
|
307
|
+
ownFailure = { sha: ownFailed.sha, later: false, state: ownFailed.failed };
|
|
308
|
+
const same = heardHere.find((h) => sameSha(h.sha, sha));
|
|
309
|
+
if (same && blind && !ownFailure)
|
|
310
|
+
return { found: { sha: same.sha, later: false } };
|
|
311
|
+
// The deploys of the merge commit itself are still on their way: only a later commit that deployed stands in for them. A later commit
|
|
312
|
+
// that failed says nothing about them.
|
|
313
|
+
const ownPending = own?.state === 'pending';
|
|
314
|
+
// A later commit that contains the merge: the ones webhooks heard of, then the newest of the environment.
|
|
315
|
+
const candidates = [];
|
|
316
|
+
const add = (c) => {
|
|
317
|
+
if (c && !sameSha(c, sha) && !candidates.some((x) => sameSha(x, c)))
|
|
318
|
+
candidates.push(c);
|
|
319
|
+
};
|
|
320
|
+
for (const h of heardAll)
|
|
321
|
+
if (h.at >= o.jobAt - LATER_SLACK_MS && (h.ok || h.failed))
|
|
322
|
+
add(h.sha);
|
|
323
|
+
// A read of the merge commit's own deployments that failed does not stop the look at the later commits (KAT-403): the list of the
|
|
324
|
+
// environment may read fine, and a later commit that deployed is the deploy of the merge. `githubOut` is set by the first later read that fails.
|
|
325
|
+
const ownReadFailed = !!error;
|
|
326
|
+
let githubOut = false;
|
|
327
|
+
if (gh.deployments) {
|
|
328
|
+
try {
|
|
329
|
+
for (const d of await gh.deployments({ environment, limit: 5 })) {
|
|
330
|
+
if (d.at && Date.parse(d.at) < o.jobAt - LATER_SLACK_MS)
|
|
331
|
+
continue;
|
|
332
|
+
add(d.sha);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
catch (err) {
|
|
336
|
+
error = err instanceof Error ? err.message : String(err);
|
|
337
|
+
githubOut = true;
|
|
338
|
+
// GitHub could not be read at all (the own set failed too): a failure that deliveries reported stands, as it always did.
|
|
339
|
+
if (!ownReadFailed)
|
|
340
|
+
laterUnread = true;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// The newest commit that deployed settles it, whatever order the candidates came in: a failed later commit that holds the merge is
|
|
344
|
+
// only the answer when no other later commit deployed, so a failure is kept aside and the rest are looked at first.
|
|
345
|
+
let laterFailed;
|
|
346
|
+
for (const later of candidates) {
|
|
347
|
+
if (!(await laterCounts(later)))
|
|
348
|
+
continue;
|
|
349
|
+
let verdict = { state: 'none' };
|
|
350
|
+
if (gh.deployments && !githubOut) {
|
|
351
|
+
try {
|
|
352
|
+
verdict = judgeSet(await setOf(later), rule);
|
|
353
|
+
}
|
|
354
|
+
catch (err) {
|
|
355
|
+
error = err instanceof Error ? err.message : String(err);
|
|
356
|
+
githubOut = true;
|
|
357
|
+
laterUnread = true;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (verdict.state === 'failed') {
|
|
361
|
+
laterFailed ??= { sha: verdict.failed.sha || later, later: true, state: verdict.failed.state, id: verdict.failed.id };
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
if (verdict.state === 'deployed')
|
|
365
|
+
return { found: { sha: later, later: true, ...(verdict.url ? { url: verdict.url } : {}) } };
|
|
366
|
+
// No deployment of that commit on GitHub, or it cannot be read: what webhooks heard stands.
|
|
367
|
+
if (verdict.state === 'none') {
|
|
368
|
+
if (heardHere.some((h) => sameSha(h.sha, later)))
|
|
369
|
+
return { found: { sha: later, later: true } };
|
|
370
|
+
const failedHere = heardFailed(later);
|
|
371
|
+
if (failedHere)
|
|
372
|
+
laterFailed ??= { sha: later, later: true, state: failedHere.failed };
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
// The merge commit's own deploy failed and no later commit that holds the merge deployed: the merge is not on the environment. When
|
|
376
|
+
// the later commits could not be read on GitHub one of them may have deployed, so the wait goes on and the next look decides.
|
|
377
|
+
if (ownFailure)
|
|
378
|
+
return laterUnread ? { error: error ?? 'GitHub could not be read' } : { failed: ownFailure };
|
|
379
|
+
// A failed later commit ends the wait only when the merge commit's own deploy is known not to be on its way: not while it is still
|
|
380
|
+
// running, and not while GitHub cannot be read, since it may be running then too.
|
|
381
|
+
if (laterFailed && !ownPending && !error)
|
|
382
|
+
return { failed: laterFailed };
|
|
383
|
+
return error ? { error } : {};
|
|
384
|
+
}
|
|
385
|
+
// ---------- the gate ----------
|
|
386
|
+
/** What a merge job needs for a wait, or null when it has none: no wait set, a run a person asked for, or nothing to wait for. */
|
|
387
|
+
async function waitFor(w, ev) {
|
|
388
|
+
const sha = mergeShaOf(ev);
|
|
389
|
+
const repo = targetRepo(w, ev);
|
|
390
|
+
// The repo's own wait first, the dot's as the default (KAT-395).
|
|
391
|
+
const cfg = deployWaitOf(w, repo);
|
|
392
|
+
if (!cfg || !sha || !repo || repo.role !== 'app' || ev.requestedBy)
|
|
393
|
+
return null;
|
|
394
|
+
// A repo with Run tests off runs no tests of its own, so there is nothing to time, unless its merge runs a Tests repo (KAT-86): that
|
|
395
|
+
// suite tests the deployed build, and it is the one that needs the wait.
|
|
396
|
+
if (testsOffRepo(w, ev) && !(testRepoSwitches(w).onMerge && testReposFor(w, ev, 'post_merge').length))
|
|
397
|
+
return null;
|
|
398
|
+
// The environment deploys the default branch. A merge into a release branch the dot also tests would wait for a deploy that never comes.
|
|
399
|
+
const merged = ev.push ? ev.push.ref.replace(/^refs\/heads\//, '') : ev.pr?.baseRef;
|
|
400
|
+
const branch = repoForEvent(w, ev)?.defaultBranch ?? repo.defaultBranch;
|
|
401
|
+
if (merged && merged !== branch)
|
|
402
|
+
return null;
|
|
403
|
+
const gh = githubFor(w, ev);
|
|
404
|
+
if (gh.mode === 'demo' || !gh.deployments)
|
|
405
|
+
return null;
|
|
406
|
+
return { cfg, sha, repo, branch, gh };
|
|
407
|
+
}
|
|
408
|
+
/** The first step of a wait run: the same step the run of a merge starts with, so the wait follows the merge it is for. */
|
|
409
|
+
const MERGE_STEP = 'Merge detected';
|
|
410
|
+
/** The step of a wait: what it waits for and how long it has waited. With `over` it is the last word of the wait, once the time is known. */
|
|
411
|
+
function waitStep(env, short, waitedMs, maxSec, error, over = false) {
|
|
412
|
+
const label = `Waiting for the ${env} deploy`;
|
|
413
|
+
const of = `${durationText(waitedMs)} of ${durationText(maxSec * 1000)}`;
|
|
414
|
+
if (over)
|
|
415
|
+
return { label, detail: `Waited ${of} for a successful deploy of merge commit ${short} to ${env}.` };
|
|
416
|
+
return {
|
|
417
|
+
label,
|
|
418
|
+
detail: `Merge commit ${short} has no successful deploy to ${env} yet. Waited ${of} so far. The tests start when it deploys, or when the time is up.${error ? ` The last look at GitHub failed: ${error}` : ''}`,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
/** Ends the wait of a job. The job runs on the next claim, or this one when the gate returns false. */
|
|
422
|
+
function release(job, state, outcome) {
|
|
423
|
+
update('jobs', job.id, { heldBy: null, deployWait: { ...state, state: 'released', outcome } });
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* The dot was paused or archived under a job that waits: the held run is cancelled with the step that says why, and the job ends its wait.
|
|
428
|
+
* The handler then closes the job as it does for any paused dot. False, like release: the job is not held any more.
|
|
429
|
+
*/
|
|
430
|
+
function stopWaiting(job, state) {
|
|
431
|
+
if (state?.runId)
|
|
432
|
+
closeDeployRun(state.runId, { label: 'Stopped waiting for the deploy', detail: 'The dot is paused, so localdost did not run this check.', status: 'warn' }, 'dot paused');
|
|
433
|
+
return state ? release(job, state, 'stopped') : false;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Queue gate: true when the job waits for the deploy of its merge and goes back to the queue. False when it may run: no wait applies,
|
|
437
|
+
* the merge is deployed, or the time is up. The run that shows the wait is made on the first look.
|
|
438
|
+
*/
|
|
439
|
+
export async function holdForDeploy(job, now = new Date()) {
|
|
440
|
+
if (job.kind !== 'post_merge')
|
|
441
|
+
return false;
|
|
442
|
+
const prior = job.deployWait;
|
|
443
|
+
// A job that waited already, or was replaced, does not wait again: a retry of its run starts at once.
|
|
444
|
+
if (prior && prior.state !== 'waiting')
|
|
445
|
+
return false;
|
|
446
|
+
const w = get('watches', job.watchId);
|
|
447
|
+
if (!w)
|
|
448
|
+
return false;
|
|
449
|
+
const ev = eventOf(job);
|
|
450
|
+
// The dot was paused while the job waited: the run stops, and the handler closes the job as it does for any paused dot.
|
|
451
|
+
if (w.paused || w.archived)
|
|
452
|
+
return stopWaiting(job, prior);
|
|
453
|
+
const need = prior ? await waitFor(w, ev) : await firstWaitFor(w, ev);
|
|
454
|
+
if (!need) {
|
|
455
|
+
// The setting was turned off, or no longer applies, while the job waited: the run goes on now.
|
|
456
|
+
if (prior?.runId)
|
|
457
|
+
holdRunForDeploy(prior.runId, { environment: prior.environment, sha: prior.sha, since: prior.since, until: now.toISOString() }, { label: 'Stopped waiting for the deploy', detail: 'The deploy wait no longer applies to this merge, so the tests start now.' });
|
|
458
|
+
return prior ? release(job, prior, 'off') : false;
|
|
459
|
+
}
|
|
460
|
+
const { cfg, sha, repo, branch, gh } = need;
|
|
461
|
+
const env = cfg.environment;
|
|
462
|
+
const short = sha.slice(0, 7);
|
|
463
|
+
const since = prior?.since ?? now.toISOString();
|
|
464
|
+
const waitedMs = now.getTime() - Date.parse(since);
|
|
465
|
+
const deadline = Date.parse(since) + cfg.sec * 1000;
|
|
466
|
+
const state = { ...(prior ?? { since, sha, repo: repoKey(repo) }), state: 'waiting', environment: env };
|
|
467
|
+
const hold = { environment: env, sha, since, until: new Date(deadline).toISOString() };
|
|
468
|
+
if (!state.runId) {
|
|
469
|
+
// The run of this merge starts here, so the wait is on screen from the first look. It is held at once and the job keeps its id, so
|
|
470
|
+
// whatever happens next the job's own start finds it (src/agent/runs.ts startRun) and no run is left running with nobody to renew it.
|
|
471
|
+
state.runId = await withJobContext(job, async () => {
|
|
472
|
+
const run = startRun(w.id, 'post_merge', ev);
|
|
473
|
+
addStep(run.id, MERGE_STEP, ev.title);
|
|
474
|
+
holdRunForDeploy(run.id, hold, waitStep(env, short, 0, cfg.sec));
|
|
475
|
+
return run.id;
|
|
476
|
+
});
|
|
477
|
+
update('jobs', job.id, { deployWait: state });
|
|
478
|
+
void noteDeployWait(job, w, `Waiting for the ${env} deploy`, `${ev.title}\n\nlocaldost waits for merge commit ${short} to deploy to ${env}, up to ${durationText(cfg.sec * 1000)}, and tests after that.`);
|
|
479
|
+
}
|
|
480
|
+
// A merge that waits and is newer ends the wait of the older one. When this job is the older one, the newer one ends this job.
|
|
481
|
+
await settleOrder(job, w, ev, sha, gh);
|
|
482
|
+
if (replaced(job.id))
|
|
483
|
+
return true;
|
|
484
|
+
const lookStarted = Date.now();
|
|
485
|
+
const look = await lookDeployed({
|
|
486
|
+
gh,
|
|
487
|
+
repo,
|
|
488
|
+
branch,
|
|
489
|
+
environment: env,
|
|
490
|
+
sha,
|
|
491
|
+
jobAt: Date.parse(job.createdAt) || now.getTime(),
|
|
492
|
+
rule: { baseUrl: w.baseUrl, match: repo.deployUrlMatch },
|
|
493
|
+
});
|
|
494
|
+
// A newer merge may have replaced this job while the look was under way. The job stays as that merge left it.
|
|
495
|
+
if (replaced(job.id))
|
|
496
|
+
return true;
|
|
497
|
+
// The dot may have been paused or archived while the look was under way. releaseDeployWaits wakes only the jobs that sit in the queue,
|
|
498
|
+
// so this job, which was running, is the one that must notice: it ends its wait now and not with a deploy that nobody tests.
|
|
499
|
+
const now2 = get('watches', job.watchId);
|
|
500
|
+
if (!now2 || now2.paused || now2.archived)
|
|
501
|
+
return stopWaiting(job, state);
|
|
502
|
+
if (look.error)
|
|
503
|
+
state.lastError = look.error;
|
|
504
|
+
else
|
|
505
|
+
delete state.lastError;
|
|
506
|
+
// The run stays held until the handler starts it again, so each ending is a step on the held run.
|
|
507
|
+
if (look.failed) {
|
|
508
|
+
const d = look.failed;
|
|
509
|
+
const words = environmentWords(env);
|
|
510
|
+
const sentence = `The ${words} deploy of this merge failed, so the tests did not run.`;
|
|
511
|
+
holdRunForDeploy(state.runId, hold, {
|
|
512
|
+
label: `Waiting for the ${env} deploy`,
|
|
513
|
+
detail: `Waited ${durationText(waitedMs)} of ${durationText(cfg.sec * 1000)} for a successful deploy of merge commit ${short} to ${env}.`,
|
|
514
|
+
});
|
|
515
|
+
// The wait ends here and nothing tests: no test run, so no defect and no verdict about the product. The check on the commit says why.
|
|
516
|
+
closeDeployRun(state.runId, {
|
|
517
|
+
label: sentence,
|
|
518
|
+
detail: `${d.later ? `Commit ${d.sha.slice(0, 7)}, which contains the merge commit ${short},` : `Merge commit ${short}`} has a deployment to ${env} that ended in ${d.state}${d.id ? ` (deployment ${d.id})` : ''}. Waited ${durationText(waitedMs)}.`,
|
|
519
|
+
status: 'error',
|
|
520
|
+
}, 'the failed deploy');
|
|
521
|
+
update('jobs', job.id, {
|
|
522
|
+
status: 'done',
|
|
523
|
+
error: sentence,
|
|
524
|
+
finishedAt: new Date().toISOString(),
|
|
525
|
+
heldBy: null,
|
|
526
|
+
deployWait: { ...state, state: 'released', outcome: 'failed' },
|
|
527
|
+
});
|
|
528
|
+
void closeUnrun(job, w, `The ${words} deploy failed`, sentence);
|
|
529
|
+
log.info(`deploy wait: job ${job.id} for ${short} ends, the ${env} deploy ended in ${d.state}`);
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
if (look.found) {
|
|
533
|
+
const d = look.found;
|
|
534
|
+
const target = deployTargetFor(w, ev, d.url);
|
|
535
|
+
holdRunForDeploy(state.runId, hold, waitStep(env, short, waitedMs, cfg.sec, undefined, true));
|
|
536
|
+
holdRunForDeploy(state.runId, hold, {
|
|
537
|
+
label: `Deployed to ${env}`,
|
|
538
|
+
detail: `${d.later ? `Commit ${d.sha.slice(0, 7)}, which contains the merge commit ${short}, deployed to ${env}` : `Merge commit ${short} deployed to ${env}`}. Waited ${durationText(waitedMs)}. The tests start now${target.url ? `, against ${target.url}` : ''}.${target.ignored
|
|
539
|
+
? ` The deploy gave the address ${target.ignored}, which is outside the site of the Base URL, so the tests run against the Base URL and keep the test login away from it.`
|
|
540
|
+
: ''}`,
|
|
541
|
+
status: target.ignored ? 'warn' : 'ok',
|
|
542
|
+
});
|
|
543
|
+
if (target.url)
|
|
544
|
+
state.url = target.url;
|
|
545
|
+
return release(job, state, 'deployed');
|
|
546
|
+
}
|
|
547
|
+
if (now.getTime() >= deadline) {
|
|
548
|
+
holdRunForDeploy(state.runId, hold, waitStep(env, short, waitedMs, cfg.sec, undefined, true));
|
|
549
|
+
holdRunForDeploy(state.runId, hold, {
|
|
550
|
+
label: DEPLOY_TIMEOUT_LABEL,
|
|
551
|
+
detail: `Waited ${durationText(cfg.sec * 1000)} for a successful deploy of ${short} to ${env}. The tests run on the ${env} build as it is.${state.lastError ? ` The last look at GitHub failed: ${state.lastError}` : ''}`,
|
|
552
|
+
status: 'warn',
|
|
553
|
+
});
|
|
554
|
+
return release(job, state, 'timeout');
|
|
555
|
+
}
|
|
556
|
+
// Not deployed yet. The run says how long it has waited, and the job goes back to the queue for the next look.
|
|
557
|
+
// A deployment_status that came in while this look was under way found the job running, so it woke nothing: look again at once.
|
|
558
|
+
const gapMs = heardSince(repo, env, lookStarted) ? 0 : (wantsGithubPoll(w) ? DEPLOY_POLL_SEC : DEPLOY_NUDGE_SEC) * 1000;
|
|
559
|
+
const next = Math.max(now.getTime() + 1000, Math.min(now.getTime() + gapMs, deadline));
|
|
560
|
+
holdRunForDeploy(state.runId, hold, waitStep(env, short, waitedMs, cfg.sec, state.lastError));
|
|
561
|
+
update('jobs', job.id, {
|
|
562
|
+
status: 'queued',
|
|
563
|
+
attempts: Math.max(0, job.attempts - 1),
|
|
564
|
+
runAfter: new Date(next).toISOString(),
|
|
565
|
+
error: null,
|
|
566
|
+
heldBy: 'deploy_wait',
|
|
567
|
+
deployWait: state,
|
|
568
|
+
});
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* The first look at a job: like waitFor, and a merge that changes only docs is left out when the dot skips the tests of such a
|
|
573
|
+
* change (the run would skip them after the wait, and the environment may not deploy docs). A diff GitHub cannot give keeps the wait.
|
|
574
|
+
*/
|
|
575
|
+
async function firstWaitFor(w, ev) {
|
|
576
|
+
const need = await waitFor(w, ev);
|
|
577
|
+
if (!need || !testSavings(w).docsOnlySkip)
|
|
578
|
+
return need;
|
|
579
|
+
try {
|
|
580
|
+
if (docsOnlyChange(await getDiff(w, ev)))
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
catch {
|
|
584
|
+
/* the wait goes on */
|
|
585
|
+
}
|
|
586
|
+
return need;
|
|
587
|
+
}
|
|
588
|
+
// ---------- a newer merge, and a deployment that arrives ----------
|
|
589
|
+
/** True when a newer merge replaced the job: its wait is over, and nothing more is done for it. */
|
|
590
|
+
function replaced(jobId) {
|
|
591
|
+
return get('jobs', jobId)?.deployWait?.state === 'superseded';
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* The jobs that wait for another merge into the same branch of the same repository, a job in the middle of its look included. Not
|
|
595
|
+
* this job, and not the same commit: one merge that arrives twice (a pull request event and a push event) is not a newer merge.
|
|
596
|
+
*/
|
|
597
|
+
function waitingForOthers(job, w, ev, sha) {
|
|
598
|
+
const scope = scopeOf('post_merge', ev, w, sha);
|
|
599
|
+
const repo = repoTarget(w, ev);
|
|
600
|
+
return list('jobs', { watchId: w.id, status: ['queued', 'running'] }).filter((j) => {
|
|
601
|
+
const st = j.deployWait;
|
|
602
|
+
if (j.id === job.id || j.kind !== 'post_merge' || !st || st.state !== 'waiting' || sameSha(st.sha, sha))
|
|
603
|
+
return false;
|
|
604
|
+
const other = eventOf(j);
|
|
605
|
+
return repoTarget(w, other) === repo && scopeOf('post_merge', other, w, st.sha) === scope;
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* Which merge is later in the branch: GitHub's compare of the two merge commits says which one holds the other. The order the two
|
|
610
|
+
* events came in says nothing, since each merge sends two events and a delivery can be late. `unknown` when GitHub cannot say.
|
|
611
|
+
*/
|
|
612
|
+
async function laterMerge(gh, mine, other) {
|
|
613
|
+
try {
|
|
614
|
+
// compareStatus(base, head) is `behind` when head is an ancestor of base: the other merge is behind this one.
|
|
615
|
+
const rel = await gh.compareStatus(mine, other);
|
|
616
|
+
return rel === 'behind' ? 'newer' : rel === 'ahead' ? 'older' : 'unknown';
|
|
617
|
+
}
|
|
618
|
+
catch {
|
|
619
|
+
return 'unknown';
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
/** Ends the wait of a job: its job is done, its run is cancelled with the step that says which merge tests instead, and its check is closed. */
|
|
623
|
+
function endWait(j, w, by) {
|
|
624
|
+
const st = j.deployWait;
|
|
625
|
+
if (!st)
|
|
626
|
+
return;
|
|
627
|
+
const scope = scopeOf('post_merge', eventOf(j), w, st.sha);
|
|
628
|
+
const branch = scope.replace(/^branch:/, '');
|
|
629
|
+
update('jobs', j.id, {
|
|
630
|
+
status: 'done',
|
|
631
|
+
error: `Superseded by the newer merge ${by.slice(0, 7)}.`,
|
|
632
|
+
finishedAt: new Date().toISOString(),
|
|
633
|
+
heldBy: null,
|
|
634
|
+
deployWait: { ...st, state: 'superseded' },
|
|
635
|
+
});
|
|
636
|
+
if (st.runId)
|
|
637
|
+
closeDeployRun(st.runId, {
|
|
638
|
+
label: 'Superseded by a newer merge',
|
|
639
|
+
detail: `${by.slice(0, 7)} is a newer merge${scope.startsWith('branch:') ? ` into ${branch}` : ''}, so localdost tests that merge instead of waiting for the ${st.environment} deploy of ${st.sha.slice(0, 7)}.`,
|
|
640
|
+
status: 'warn',
|
|
641
|
+
}, 'a newer merge');
|
|
642
|
+
void noteSupersededWait(j, w, by);
|
|
643
|
+
log.info(`deploy wait: job ${j.id} for ${st.sha.slice(0, 7)} superseded by the newer merge ${by.slice(0, 7)}`);
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Settles which merge waits when two merges into the same branch both wait. The later one in the branch replaces the other: when it
|
|
647
|
+
* is this job's merge, the other job ends; when it is not (the event of an older merge came in late), this job ends. When GitHub cannot
|
|
648
|
+
* say which is later, both keep waiting: a build tested twice costs less than a merge that nothing tests. Called by a job that waits,
|
|
649
|
+
* on each of its looks, so a pair left open once is settled on the next look.
|
|
650
|
+
*/
|
|
651
|
+
async function settleOrder(job, w, ev, sha, gh) {
|
|
652
|
+
for (const other of waitingForOthers(job, w, ev, sha)) {
|
|
653
|
+
const theirs = other.deployWait.sha;
|
|
654
|
+
const order = await laterMerge(gh, sha, theirs);
|
|
655
|
+
// The compare took time, and another look may have ended either job meanwhile: act on what is still so.
|
|
656
|
+
const mine = get('jobs', job.id);
|
|
657
|
+
if (mine?.deployWait?.state !== 'waiting')
|
|
658
|
+
return;
|
|
659
|
+
const there = get('jobs', other.id);
|
|
660
|
+
if (there?.deployWait?.state !== 'waiting')
|
|
661
|
+
continue;
|
|
662
|
+
if (order === 'newer')
|
|
663
|
+
endWait(there, w, sha);
|
|
664
|
+
else if (order === 'older') {
|
|
665
|
+
endWait(mine, w, theirs);
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/** Makes the jobs of a dot that wait look again now: the dot's deploy wait was changed in a save. Returns how many it woke. */
|
|
671
|
+
export function releaseDeployWaits(w, now = new Date()) {
|
|
672
|
+
const waiting = list('jobs', { watchId: w.id, status: 'queued', heldBy: 'deploy_wait' });
|
|
673
|
+
for (const j of waiting)
|
|
674
|
+
update('jobs', j.id, { runAfter: now.toISOString() });
|
|
675
|
+
return waiting.length;
|
|
676
|
+
}
|
|
677
|
+
/** A deployment_status that ends a deployment arrived: remember a success, and wake the jobs that wait for that repository and environment. */
|
|
678
|
+
function onDeployment(d, now = new Date()) {
|
|
679
|
+
hear(d, now.getTime());
|
|
680
|
+
let woken = 0;
|
|
681
|
+
for (const j of list('jobs', { status: 'queued', heldBy: 'deploy_wait' })) {
|
|
682
|
+
const st = j.deployWait;
|
|
683
|
+
if (!st || st.state !== 'waiting' || st.repo !== repoKey(d.repo) || lc(st.environment) !== lc(d.environment))
|
|
684
|
+
continue;
|
|
685
|
+
update('jobs', j.id, { runAfter: now.toISOString() });
|
|
686
|
+
woken++;
|
|
687
|
+
}
|
|
688
|
+
if (woken)
|
|
689
|
+
log.info(`deploy wait: ${d.repo.owner}/${d.repo.name} deployment of ${d.sha.slice(0, 7)} to ${d.environment} ended in ${d.state}, ${woken} job(s) look again`);
|
|
690
|
+
return woken;
|
|
691
|
+
}
|
|
692
|
+
let registered = false;
|
|
693
|
+
/** Puts the gate and the deployment listener in place. Importing src/flows/index.ts does this once. */
|
|
694
|
+
export function registerDeployWait() {
|
|
695
|
+
if (registered)
|
|
696
|
+
return;
|
|
697
|
+
registered = true;
|
|
698
|
+
onBeforeJob((job) => holdForDeploy(job));
|
|
699
|
+
onDeploymentEnd((d) => void onDeployment(d));
|
|
700
|
+
}
|
|
701
|
+
//# sourceMappingURL=deploy-wait.js.map
|