toolroll 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1113 -0
- package/THIRD_PARTY_NOTICES.md +449 -0
- package/dist/accent-colors.d.ts +48 -0
- package/dist/accent-colors.js +122 -0
- package/dist/action-ledger.d.ts +26 -0
- package/dist/action-ledger.js +75 -0
- package/dist/agent-fence.d.ts +42 -0
- package/dist/agent-fence.js +183 -0
- package/dist/agentconfig.d.ts +216 -0
- package/dist/agentconfig.js +454 -0
- package/dist/api-tokens.d.ts +16 -0
- package/dist/api-tokens.js +27 -0
- package/dist/approval-policy.d.ts +69 -0
- package/dist/approval-policy.js +137 -0
- package/dist/approval-rules-ui.d.ts +25 -0
- package/dist/approval-rules-ui.js +39 -0
- package/dist/assignment-adapters.d.ts +180 -0
- package/dist/assignment-adapters.js +239 -0
- package/dist/assignment-brief.d.ts +71 -0
- package/dist/assignment-brief.js +129 -0
- package/dist/assignment-delivery.d.ts +56 -0
- package/dist/assignment-delivery.js +160 -0
- package/dist/assignment-presentation.d.ts +26 -0
- package/dist/assignment-presentation.js +80 -0
- package/dist/assignment-status.d.ts +62 -0
- package/dist/assignment-status.js +152 -0
- package/dist/assignment-ui.d.ts +71 -0
- package/dist/assignment-ui.js +103 -0
- package/dist/assignment.d.ts +222 -0
- package/dist/assignment.js +399 -0
- package/dist/attest.d.ts +56 -0
- package/dist/attest.js +153 -0
- package/dist/backend.d.ts +97 -0
- package/dist/backend.js +166 -0
- package/dist/backup-ui.d.ts +22 -0
- package/dist/backup-ui.js +59 -0
- package/dist/backup.d.ts +84 -0
- package/dist/backup.js +421 -0
- package/dist/beads.d.ts +34 -0
- package/dist/beads.js +135 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +22 -0
- package/dist/board.d.ts +150 -0
- package/dist/board.js +210 -0
- package/dist/boot-identity.d.ts +63 -0
- package/dist/boot-identity.js +99 -0
- package/dist/browser/THIRD_PARTY_NOTICES.txt +2295 -0
- package/dist/browser/workspace.css +4 -0
- package/dist/browser/workspace.js +225 -0
- package/dist/browser-crew.d.ts +11 -0
- package/dist/browser-crew.js +50 -0
- package/dist/browser-shell.d.ts +8 -0
- package/dist/browser-shell.js +60 -0
- package/dist/browser-workspace.d.ts +780 -0
- package/dist/browser-workspace.js +47 -0
- package/dist/budget-alerts.d.ts +19 -0
- package/dist/budget-alerts.js +46 -0
- package/dist/builder.d.ts +370 -0
- package/dist/builder.js +3262 -0
- package/dist/capscan.d.ts +35 -0
- package/dist/capscan.js +113 -0
- package/dist/chat-acceptance.d.ts +71 -0
- package/dist/chat-acceptance.js +120 -0
- package/dist/chat-actions.d.ts +265 -0
- package/dist/chat-actions.js +1273 -0
- package/dist/chat-channel.d.ts +109 -0
- package/dist/chat-channel.js +652 -0
- package/dist/chat-continuity.d.ts +32 -0
- package/dist/chat-continuity.js +317 -0
- package/dist/chat-controls.d.ts +113 -0
- package/dist/chat-controls.js +53 -0
- package/dist/chat-delivery-state.d.ts +159 -0
- package/dist/chat-delivery-state.js +309 -0
- package/dist/chat-delivery.d.ts +38 -0
- package/dist/chat-delivery.js +693 -0
- package/dist/chat-display.d.ts +1 -0
- package/dist/chat-display.js +18 -0
- package/dist/chat-evidence.d.ts +123 -0
- package/dist/chat-evidence.js +207 -0
- package/dist/chat-flow.d.ts +44 -0
- package/dist/chat-flow.js +215 -0
- package/dist/chat-inbox.d.ts +57 -0
- package/dist/chat-inbox.js +123 -0
- package/dist/chat-polish.d.ts +16 -0
- package/dist/chat-polish.js +135 -0
- package/dist/chat-review.d.ts +46 -0
- package/dist/chat-review.js +98 -0
- package/dist/chat-rooms.d.ts +123 -0
- package/dist/chat-rooms.js +216 -0
- package/dist/chat-task-actions.d.ts +44 -0
- package/dist/chat-task-actions.js +79 -0
- package/dist/check-progress.d.ts +51 -0
- package/dist/check-progress.js +290 -0
- package/dist/child-database.d.ts +12 -0
- package/dist/child-database.js +30 -0
- package/dist/claim.d.ts +688 -0
- package/dist/claim.js +1740 -0
- package/dist/cli.d.ts +137 -0
- package/dist/cli.js +1461 -0
- package/dist/codex-limits.d.ts +15 -0
- package/dist/codex-limits.js +145 -0
- package/dist/coding-context.d.ts +55 -0
- package/dist/coding-context.js +92 -0
- package/dist/coding-handoff.d.ts +57 -0
- package/dist/coding-handoff.js +277 -0
- package/dist/coding-provider.d.ts +72 -0
- package/dist/coding-provider.js +424 -0
- package/dist/coding-shipping-ui.d.ts +4 -0
- package/dist/coding-shipping-ui.js +12 -0
- package/dist/coding-types.d.ts +62 -0
- package/dist/coding-types.js +1 -0
- package/dist/coding-ui.d.ts +17 -0
- package/dist/coding-ui.js +364 -0
- package/dist/coding-update.d.ts +15 -0
- package/dist/coding-update.js +149 -0
- package/dist/coding-workspace.d.ts +124 -0
- package/dist/coding-workspace.js +768 -0
- package/dist/container-state.d.ts +5 -0
- package/dist/container-state.js +62 -0
- package/dist/containment.d.ts +197 -0
- package/dist/containment.js +559 -0
- package/dist/contest.d.ts +318 -0
- package/dist/contest.js +753 -0
- package/dist/control-setup.d.ts +35 -0
- package/dist/control-setup.js +40 -0
- package/dist/control-ui.d.ts +29 -0
- package/dist/control-ui.js +53 -0
- package/dist/controller-service.d.ts +1 -0
- package/dist/controller-service.js +19 -0
- package/dist/controller-supervisor.d.ts +30 -0
- package/dist/controller-supervisor.js +104 -0
- package/dist/converse.d.ts +304 -0
- package/dist/converse.js +849 -0
- package/dist/coordinator-proposals.d.ts +29 -0
- package/dist/coordinator-proposals.js +137 -0
- package/dist/coordinator.d.ts +186 -0
- package/dist/coordinator.js +447 -0
- package/dist/credentials-ui.d.ts +25 -0
- package/dist/credentials-ui.js +48 -0
- package/dist/daemon.d.ts +209 -0
- package/dist/daemon.js +604 -0
- package/dist/decision.d.ts +120 -0
- package/dist/decision.js +388 -0
- package/dist/demo.d.ts +55 -0
- package/dist/demo.js +992 -0
- package/dist/desktop-access.d.ts +28 -0
- package/dist/desktop-access.js +88 -0
- package/dist/desktop-bundle.d.ts +16 -0
- package/dist/desktop-bundle.js +74 -0
- package/dist/desktop-host.d.ts +54 -0
- package/dist/desktop-host.js +508 -0
- package/dist/desktop-update-gate.d.ts +12 -0
- package/dist/desktop-update-gate.js +91 -0
- package/dist/desktop-update-recovery.d.ts +14 -0
- package/dist/desktop-update-recovery.js +243 -0
- package/dist/desktop-update.d.ts +110 -0
- package/dist/desktop-update.js +740 -0
- package/dist/discord-api.d.ts +20 -0
- package/dist/discord-api.js +138 -0
- package/dist/discord-chat.d.ts +16 -0
- package/dist/discord-chat.js +381 -0
- package/dist/discord-settings.d.ts +7 -0
- package/dist/discord-settings.js +75 -0
- package/dist/discord.d.ts +10 -0
- package/dist/discord.js +169 -0
- package/dist/discover.d.ts +75 -0
- package/dist/discover.js +150 -0
- package/dist/dispatch.d.ts +100 -0
- package/dist/dispatch.js +311 -0
- package/dist/dispose.d.ts +161 -0
- package/dist/dispose.js +803 -0
- package/dist/email-settings.d.ts +34 -0
- package/dist/email-settings.js +50 -0
- package/dist/envelope.d.ts +47 -0
- package/dist/envelope.js +105 -0
- package/dist/evidence-pack.d.ts +185 -0
- package/dist/evidence-pack.js +258 -0
- package/dist/evidence.d.ts +345 -0
- package/dist/evidence.js +782 -0
- package/dist/exec.d.ts +285 -0
- package/dist/exec.js +1841 -0
- package/dist/exhaustion.d.ts +85 -0
- package/dist/exhaustion.js +141 -0
- package/dist/export-ui.d.ts +4 -0
- package/dist/export-ui.js +17 -0
- package/dist/export.d.ts +48 -0
- package/dist/export.js +305 -0
- package/dist/flow-actions.d.ts +77 -0
- package/dist/flow-actions.js +203 -0
- package/dist/flow-code.d.ts +50 -0
- package/dist/flow-code.js +159 -0
- package/dist/flow-draft.d.ts +38 -0
- package/dist/flow-draft.js +80 -0
- package/dist/flow-engine.d.ts +66 -0
- package/dist/flow-engine.js +416 -0
- package/dist/flow-insights.d.ts +95 -0
- package/dist/flow-insights.js +149 -0
- package/dist/flow-live.d.ts +24 -0
- package/dist/flow-live.js +150 -0
- package/dist/flow-people.d.ts +24 -0
- package/dist/flow-people.js +91 -0
- package/dist/flow-replies.d.ts +48 -0
- package/dist/flow-replies.js +113 -0
- package/dist/flow-scripts.d.ts +38 -0
- package/dist/flow-scripts.js +73 -0
- package/dist/flow-secrets.d.ts +13 -0
- package/dist/flow-secrets.js +45 -0
- package/dist/flow-sort.d.ts +82 -0
- package/dist/flow-sort.js +153 -0
- package/dist/flow-steps.d.ts +40 -0
- package/dist/flow-steps.js +408 -0
- package/dist/flow-triggers.d.ts +244 -0
- package/dist/flow-triggers.js +959 -0
- package/dist/flows-ui.d.ts +20 -0
- package/dist/flows-ui.js +175 -0
- package/dist/flows.d.ts +229 -0
- package/dist/flows.js +968 -0
- package/dist/fonts.d.ts +19 -0
- package/dist/fonts.js +19 -0
- package/dist/gaps.d.ts +35 -0
- package/dist/gaps.js +101 -0
- package/dist/gate-failure.d.ts +40 -0
- package/dist/gate-failure.js +66 -0
- package/dist/git.d.ts +54 -0
- package/dist/git.js +94 -0
- package/dist/google-mail.d.ts +58 -0
- package/dist/google-mail.js +151 -0
- package/dist/grant.d.ts +136 -0
- package/dist/grant.js +238 -0
- package/dist/graph.d.ts +164 -0
- package/dist/graph.js +383 -0
- package/dist/guides.d.ts +22 -0
- package/dist/guides.js +363 -0
- package/dist/held.d.ts +150 -0
- package/dist/held.js +799 -0
- package/dist/invoke.d.ts +112 -0
- package/dist/invoke.js +780 -0
- package/dist/issues.d.ts +41 -0
- package/dist/issues.js +131 -0
- package/dist/job-object-helper.ps1 +252 -0
- package/dist/jsonl-discriminants.d.ts +11 -0
- package/dist/jsonl-discriminants.js +93 -0
- package/dist/keys.d.ts +104 -0
- package/dist/keys.js +229 -0
- package/dist/kits-ui.d.ts +17 -0
- package/dist/kits-ui.js +46 -0
- package/dist/kits.d.ts +86 -0
- package/dist/kits.js +215 -0
- package/dist/knowledge-cli.d.ts +101 -0
- package/dist/knowledge-cli.js +92 -0
- package/dist/knowledge-ui.d.ts +24 -0
- package/dist/knowledge-ui.js +40 -0
- package/dist/lead-context.d.ts +8 -0
- package/dist/lead-context.js +56 -0
- package/dist/lead-follow.d.ts +22 -0
- package/dist/lead-follow.js +167 -0
- package/dist/lead-status.d.ts +75 -0
- package/dist/lead-status.js +285 -0
- package/dist/ledger-chain.d.ts +46 -0
- package/dist/ledger-chain.js +187 -0
- package/dist/ledger-csv.d.ts +4 -0
- package/dist/ledger-csv.js +11 -0
- package/dist/ledger-view.d.ts +24 -0
- package/dist/ledger-view.js +58 -0
- package/dist/limits-ui.d.ts +26 -0
- package/dist/limits-ui.js +67 -0
- package/dist/link.d.ts +72 -0
- package/dist/link.js +217 -0
- package/dist/live.d.ts +96 -0
- package/dist/live.js +366 -0
- package/dist/liveness.d.ts +30 -0
- package/dist/liveness.js +42 -0
- package/dist/log.d.ts +7 -0
- package/dist/log.js +25 -0
- package/dist/mailbox.d.ts +57 -0
- package/dist/mailbox.js +150 -0
- package/dist/maintenance.d.ts +11 -0
- package/dist/maintenance.js +35 -0
- package/dist/mate-cli.d.ts +52 -0
- package/dist/mate-cli.js +345 -0
- package/dist/mate-contract.d.ts +10 -0
- package/dist/mate-contract.js +30 -0
- package/dist/mate-doors.d.ts +69 -0
- package/dist/mate-doors.js +548 -0
- package/dist/mate-progress.d.ts +29 -0
- package/dist/mate-progress.js +121 -0
- package/dist/mate-tools.d.ts +94 -0
- package/dist/mate-tools.js +1878 -0
- package/dist/mate.d.ts +92 -0
- package/dist/mate.js +435 -0
- package/dist/mcp-connect.d.ts +103 -0
- package/dist/mcp-connect.js +252 -0
- package/dist/mcp.d.ts +27 -0
- package/dist/mcp.js +651 -0
- package/dist/memory-cli.d.ts +466 -0
- package/dist/memory-cli.js +111 -0
- package/dist/memory-pass.d.ts +160 -0
- package/dist/memory-pass.js +409 -0
- package/dist/metrics.d.ts +3 -0
- package/dist/metrics.js +56 -0
- package/dist/mobile-viewport.d.ts +3 -0
- package/dist/mobile-viewport.js +37 -0
- package/dist/model-catalog.d.ts +118 -0
- package/dist/model-catalog.js +376 -0
- package/dist/models-cli.d.ts +102 -0
- package/dist/models-cli.js +66 -0
- package/dist/models-ui.d.ts +34 -0
- package/dist/models-ui.js +68 -0
- package/dist/modes.d.ts +80 -0
- package/dist/modes.js +182 -0
- package/dist/monitoring-settings.d.ts +44 -0
- package/dist/monitoring-settings.js +173 -0
- package/dist/monitoring-ui.d.ts +20 -0
- package/dist/monitoring-ui.js +51 -0
- package/dist/monitoring.d.ts +34 -0
- package/dist/monitoring.js +221 -0
- package/dist/names.d.ts +67 -0
- package/dist/names.js +102 -0
- package/dist/observations.d.ts +40 -0
- package/dist/observations.js +211 -0
- package/dist/oidc.d.ts +71 -0
- package/dist/oidc.js +182 -0
- package/dist/onboard.d.ts +108 -0
- package/dist/onboard.js +325 -0
- package/dist/openrouter-models.d.ts +30 -0
- package/dist/openrouter-models.js +120 -0
- package/dist/operate.d.ts +118 -0
- package/dist/operate.js +11321 -0
- package/dist/peek-cli.d.ts +97 -0
- package/dist/peek-cli.js +215 -0
- package/dist/peek.d.ts +134 -0
- package/dist/peek.js +578 -0
- package/dist/phase-routing.d.ts +307 -0
- package/dist/phase-routing.js +658 -0
- package/dist/plan-auto.d.ts +14 -0
- package/dist/plan-auto.js +92 -0
- package/dist/plan.d.ts +186 -0
- package/dist/plan.js +401 -0
- package/dist/planner-source.d.ts +251 -0
- package/dist/planner-source.js +460 -0
- package/dist/planner.d.ts +75 -0
- package/dist/planner.js +992 -0
- package/dist/policy-ui.d.ts +20 -0
- package/dist/policy-ui.js +41 -0
- package/dist/policy.d.ts +111 -0
- package/dist/policy.js +231 -0
- package/dist/prepared-evidence.d.ts +16 -0
- package/dist/prepared-evidence.js +96 -0
- package/dist/pricing.d.ts +45 -0
- package/dist/pricing.js +77 -0
- package/dist/principal.d.ts +42 -0
- package/dist/principal.js +82 -0
- package/dist/probe.d.ts +46 -0
- package/dist/probe.js +79 -0
- package/dist/process-custody.d.ts +17 -0
- package/dist/process-custody.js +91 -0
- package/dist/process-liveness.d.ts +10 -0
- package/dist/process-liveness.js +81 -0
- package/dist/process-recovery-anchor.d.ts +75 -0
- package/dist/process-recovery-anchor.js +188 -0
- package/dist/process-recovery-coalition.d.ts +25 -0
- package/dist/process-recovery-coalition.js +105 -0
- package/dist/process-recovery-eligibility.d.ts +178 -0
- package/dist/process-recovery-eligibility.js +170 -0
- package/dist/process-recovery-native.d.ts +172 -0
- package/dist/process-recovery-native.js +592 -0
- package/dist/process-recovery-provenance.d.ts +163 -0
- package/dist/process-recovery-provenance.js +292 -0
- package/dist/process-recovery-services.d.ts +56 -0
- package/dist/process-recovery-services.js +191 -0
- package/dist/process-recovery-settlement.d.ts +32 -0
- package/dist/process-recovery-settlement.js +132 -0
- package/dist/process-recovery.d.ts +41 -0
- package/dist/process-recovery.js +91 -0
- package/dist/process-tree.d.ts +41 -0
- package/dist/process-tree.js +264 -0
- package/dist/project-access.d.ts +14 -0
- package/dist/project-access.js +34 -0
- package/dist/project-cli.d.ts +18 -0
- package/dist/project-cli.js +104 -0
- package/dist/project-delete-ui.d.ts +22 -0
- package/dist/project-delete-ui.js +48 -0
- package/dist/project-delete.d.ts +55 -0
- package/dist/project-delete.js +413 -0
- package/dist/project-knowledge.d.ts +111 -0
- package/dist/project-knowledge.js +241 -0
- package/dist/project-learning.d.ts +100 -0
- package/dist/project-learning.js +438 -0
- package/dist/project-memory.d.ts +81 -0
- package/dist/project-memory.js +264 -0
- package/dist/project-skills.d.ts +152 -0
- package/dist/project-skills.js +660 -0
- package/dist/project-tools.d.ts +219 -0
- package/dist/project-tools.js +796 -0
- package/dist/project.d.ts +61 -0
- package/dist/project.js +125 -0
- package/dist/prompt.d.ts +22 -0
- package/dist/prompt.js +72 -0
- package/dist/proof.d.ts +513 -0
- package/dist/proof.js +1140 -0
- package/dist/proposal.d.ts +82 -0
- package/dist/proposal.js +210 -0
- package/dist/provider-connection.d.ts +22 -0
- package/dist/provider-connection.js +98 -0
- package/dist/provider-limits.d.ts +35 -0
- package/dist/provider-limits.js +95 -0
- package/dist/provider.d.ts +279 -0
- package/dist/provider.js +935 -0
- package/dist/publish.d.ts +107 -0
- package/dist/publish.js +650 -0
- package/dist/pulls.d.ts +118 -0
- package/dist/pulls.js +240 -0
- package/dist/push.d.ts +95 -0
- package/dist/push.js +353 -0
- package/dist/quality.d.ts +8 -0
- package/dist/quality.js +6 -0
- package/dist/recipe-ui.d.ts +18 -0
- package/dist/recipe-ui.js +152 -0
- package/dist/recipes.d.ts +81 -0
- package/dist/recipes.js +332 -0
- package/dist/remote.d.ts +67 -0
- package/dist/remote.js +122 -0
- package/dist/render.d.ts +64 -0
- package/dist/render.js +587 -0
- package/dist/report-summary.d.ts +13 -0
- package/dist/report-summary.js +15 -0
- package/dist/repos.d.ts +65 -0
- package/dist/repos.js +277 -0
- package/dist/repository-context-ui.d.ts +2 -0
- package/dist/repository-context-ui.js +10 -0
- package/dist/repository-context.d.ts +67 -0
- package/dist/repository-context.js +376 -0
- package/dist/restart-certification.d.ts +134 -0
- package/dist/restart-certification.js +226 -0
- package/dist/result-actions.d.ts +28 -0
- package/dist/result-actions.js +270 -0
- package/dist/result-completion.d.ts +18 -0
- package/dist/result-completion.js +66 -0
- package/dist/result-review.d.ts +213 -0
- package/dist/result-review.js +430 -0
- package/dist/retention-ui.d.ts +12 -0
- package/dist/retention-ui.js +39 -0
- package/dist/retention.d.ts +72 -0
- package/dist/retention.js +288 -0
- package/dist/review-context.d.ts +243 -0
- package/dist/review-context.js +1043 -0
- package/dist/review-evidence.d.ts +33 -0
- package/dist/review-evidence.js +56 -0
- package/dist/reviewer.d.ts +97 -0
- package/dist/reviewer.js +202 -0
- package/dist/routine.d.ts +228 -0
- package/dist/routine.js +764 -0
- package/dist/runner.d.ts +266 -0
- package/dist/runner.js +399 -0
- package/dist/scan.d.ts +32 -0
- package/dist/scan.js +92 -0
- package/dist/scope.d.ts +695 -0
- package/dist/scope.js +1176 -0
- package/dist/scout-report.d.ts +42 -0
- package/dist/scout-report.js +108 -0
- package/dist/scout.d.ts +69 -0
- package/dist/scout.js +351 -0
- package/dist/serve.d.ts +313 -0
- package/dist/serve.js +21776 -0
- package/dist/session-brief.d.ts +8 -0
- package/dist/session-brief.js +24 -0
- package/dist/session-cli.d.ts +13 -0
- package/dist/session-cli.js +284 -0
- package/dist/session-contract.d.ts +183 -0
- package/dist/session-contract.js +122 -0
- package/dist/session-http.d.ts +19 -0
- package/dist/session-http.js +154 -0
- package/dist/session-server.d.ts +12 -0
- package/dist/session-server.js +37 -0
- package/dist/session-service.d.ts +22 -0
- package/dist/session-service.js +157 -0
- package/dist/setup-guide.d.ts +39 -0
- package/dist/setup-guide.js +93 -0
- package/dist/sign-in-guard.d.ts +45 -0
- package/dist/sign-in-guard.js +74 -0
- package/dist/skills-ui.d.ts +11 -0
- package/dist/skills-ui.js +58 -0
- package/dist/skills.d.ts +97 -0
- package/dist/skills.js +276 -0
- package/dist/slack-api.d.ts +55 -0
- package/dist/slack-api.js +229 -0
- package/dist/slack-chat.d.ts +28 -0
- package/dist/slack-chat.js +413 -0
- package/dist/slack-settings.d.ts +7 -0
- package/dist/slack-settings.js +75 -0
- package/dist/slack-state.d.ts +13 -0
- package/dist/slack-state.js +9 -0
- package/dist/slack.d.ts +13 -0
- package/dist/slack.js +167 -0
- package/dist/spend-ui.d.ts +28 -0
- package/dist/spend-ui.js +95 -0
- package/dist/spend.d.ts +142 -0
- package/dist/spend.js +313 -0
- package/dist/sqlite-runtime.d.ts +3 -0
- package/dist/sqlite-runtime.js +6 -0
- package/dist/sso-settings.d.ts +33 -0
- package/dist/sso-settings.js +103 -0
- package/dist/sso-ui.d.ts +22 -0
- package/dist/sso-ui.js +39 -0
- package/dist/storage.d.ts +15 -0
- package/dist/storage.js +84 -0
- package/dist/store.d.ts +7754 -0
- package/dist/store.js +23279 -0
- package/dist/structured-output.d.ts +58 -0
- package/dist/structured-output.js +103 -0
- package/dist/style-asset.d.ts +7 -0
- package/dist/style-asset.js +41 -0
- package/dist/subscription-chat.d.ts +46 -0
- package/dist/subscription-chat.js +275 -0
- package/dist/summary.d.ts +33 -0
- package/dist/summary.js +71 -0
- package/dist/supervisor.mjs +297 -0
- package/dist/surface.d.ts +63 -0
- package/dist/surface.js +352 -0
- package/dist/sync.d.ts +94 -0
- package/dist/sync.js +279 -0
- package/dist/task-composer.d.ts +13 -0
- package/dist/task-composer.js +52 -0
- package/dist/task-control.d.ts +165 -0
- package/dist/task-control.js +214 -0
- package/dist/task-outcome-cli.d.ts +10 -0
- package/dist/task-outcome-cli.js +92 -0
- package/dist/task-text.d.ts +30 -0
- package/dist/task-text.js +41 -0
- package/dist/team-cli.d.ts +15 -0
- package/dist/team-cli.js +618 -0
- package/dist/team-contract.d.ts +92 -0
- package/dist/team-contract.js +1 -0
- package/dist/team-http.d.ts +17 -0
- package/dist/team-http.js +144 -0
- package/dist/team-leads.d.ts +81 -0
- package/dist/team-leads.js +565 -0
- package/dist/team-runtime.d.ts +27 -0
- package/dist/team-runtime.js +264 -0
- package/dist/team-ui.d.ts +3 -0
- package/dist/team-ui.js +9 -0
- package/dist/team-updates.d.ts +8 -0
- package/dist/team-updates.js +57 -0
- package/dist/teammate-admin.d.ts +53 -0
- package/dist/teammate-admin.js +111 -0
- package/dist/teammate-desk.d.ts +60 -0
- package/dist/teammate-desk.js +154 -0
- package/dist/teammate-memory.d.ts +64 -0
- package/dist/teammate-memory.js +196 -0
- package/dist/teammate-question.d.ts +59 -0
- package/dist/teammate-question.js +175 -0
- package/dist/teammate-tools.d.ts +108 -0
- package/dist/teammate-tools.js +271 -0
- package/dist/teammate-week.d.ts +68 -0
- package/dist/teammate-week.js +132 -0
- package/dist/teammate-work.d.ts +76 -0
- package/dist/teammate-work.js +280 -0
- package/dist/teammates-ui.d.ts +20 -0
- package/dist/teammates-ui.js +166 -0
- package/dist/teammates.d.ts +180 -0
- package/dist/teammates.js +253 -0
- package/dist/teams-api.d.ts +33 -0
- package/dist/teams-api.js +204 -0
- package/dist/teams-chat.d.ts +26 -0
- package/dist/teams-chat.js +215 -0
- package/dist/teams-settings.d.ts +12 -0
- package/dist/teams-settings.js +57 -0
- package/dist/teams.d.ts +21 -0
- package/dist/teams.js +124 -0
- package/dist/telegram-flow.d.ts +49 -0
- package/dist/telegram-flow.js +110 -0
- package/dist/telegram-mate.d.ts +137 -0
- package/dist/telegram-mate.js +707 -0
- package/dist/telegram-progress.d.ts +14 -0
- package/dist/telegram-progress.js +129 -0
- package/dist/telegram-settings.d.ts +9 -0
- package/dist/telegram-settings.js +36 -0
- package/dist/telegram-status.d.ts +75 -0
- package/dist/telegram-status.js +265 -0
- package/dist/telegram-team.d.ts +85 -0
- package/dist/telegram-team.js +359 -0
- package/dist/telegram.d.ts +230 -0
- package/dist/telegram.js +1931 -0
- package/dist/templates.d.ts +65 -0
- package/dist/templates.js +118 -0
- package/dist/tool-launcher.d.ts +1 -0
- package/dist/tool-launcher.js +101 -0
- package/dist/tools-ui.d.ts +30 -0
- package/dist/tools-ui.js +40 -0
- package/dist/transitions-recipes.d.ts +1 -0
- package/dist/transitions-recipes.js +203 -0
- package/dist/tree-proof.d.ts +34 -0
- package/dist/tree-proof.js +58 -0
- package/dist/verification-evidence.d.ts +44 -0
- package/dist/verification-evidence.js +238 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +10 -0
- package/dist/webhooks.d.ts +91 -0
- package/dist/webhooks.js +283 -0
- package/dist/work-index.d.ts +68 -0
- package/dist/work-index.js +384 -0
- package/dist/work-summary.d.ts +57 -0
- package/dist/work-summary.js +116 -0
- package/dist/workspace-motion.d.ts +4 -0
- package/dist/workspace-motion.js +133 -0
- package/dist/workspace-revision.d.ts +19 -0
- package/dist/workspace-revision.js +92 -0
- package/dist/workspace-ui.d.ts +204 -0
- package/dist/workspace-ui.js +411 -0
- package/dist/worktree-notices.d.ts +13 -0
- package/dist/worktree-notices.js +17 -0
- package/dist/worktree.d.ts +249 -0
- package/dist/worktree.js +720 -0
- package/package.json +122 -0
- package/scripts/canary-assertions.mjs +42 -0
- package/scripts/crash-canary.mjs +253 -0
- package/scripts/fixtures/crash-process.mjs +74 -0
- package/scripts/fixtures/pilot-scenarios.mjs +85 -0
- package/scripts/fixtures/restart-service.mjs +27 -0
- package/scripts/launchd-certification.mjs +143 -0
- package/scripts/pilot.mjs +121 -0
- package/scripts/proof-preflight.mjs +140 -0
- package/scripts/provider-canary.mjs +379 -0
- package/scripts/recovery-canary.mjs +135 -0
- package/scripts/restart-certification.mjs +98 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Steps that run outside a model (v84), in the worker's pass:
|
|
3
|
+
*
|
|
4
|
+
* - check — runs one of the project's scripts (flow-scripts.ts) in a fresh
|
|
5
|
+
* copy of the card's latest result (or the base branch), after the
|
|
6
|
+
* project's approved setup, with the same bare environment setup
|
|
7
|
+
* and checks get, plus FLOW_* variables naming the card. Exit 0
|
|
8
|
+
* passes; anything else takes the failure path. The end of its
|
|
9
|
+
* output (64 KB, whole lines, keys blanked) is kept as the log.
|
|
10
|
+
* - update — comments on the GitHub or Linear issue the card came from, and
|
|
11
|
+
* can close it (Linear: moves it to the team's done state), with
|
|
12
|
+
* the person's own `gh` login and Linear key.
|
|
13
|
+
* - draft — (v86) Claude writes from the card (flow-draft.ts); the draft
|
|
14
|
+
* is kept on the card for a person and later steps.
|
|
15
|
+
* - sort — (v85) asks Jev through OpenRouter which of the zone's answers
|
|
16
|
+
* fits the card (flow-sort.ts), and sends it where that answer
|
|
17
|
+
* leads, or down the not-sure path.
|
|
18
|
+
*
|
|
19
|
+
* One run per visit to the zone (flow_step_run): two workers never run it
|
|
20
|
+
* twice. Trouble reaching a service is retried three times, 5 then 15
|
|
21
|
+
* minutes apart; a check that fails is an answer, not trouble.
|
|
22
|
+
*/
|
|
23
|
+
import { chmodSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
24
|
+
import { join } from "node:path";
|
|
25
|
+
import { approvedCommandShell, redactSecretAssignments, SETUP_ENV_ALLOWLIST, SETUP_ENV_DENYLIST } from "./builder.js";
|
|
26
|
+
import { assignmentOf } from "./assignment.js";
|
|
27
|
+
import { redactSecretLines, scanForSecrets } from "./evidence.js";
|
|
28
|
+
import { flowDefinitionOf } from "./flow-engine.js";
|
|
29
|
+
import { cardFollowers, notifyPeople } from "./flow-people.js";
|
|
30
|
+
import { LINEAR_URL, readLinearKey } from "./flow-triggers.js";
|
|
31
|
+
import { cardEmailOf, fillFlowText } from "./flows.js";
|
|
32
|
+
import { JEV_MODEL, askJev, readJevAnswers, sortLog, sortRequest, sortState, sortWords } from "./flow-sort.js";
|
|
33
|
+
import { claudeDraftRunner, DRAFT_TIMEOUT, draftPrompt, keptDraft } from "./flow-draft.js";
|
|
34
|
+
import { readFlowSecrets, sendingReady, runRequest, sendEmail, toolWaiting, useTool } from "./flow-actions.js";
|
|
35
|
+
import { cleanFolder, runCode } from "./flow-code.js";
|
|
36
|
+
import { agentFence } from "./agent-fence.js";
|
|
37
|
+
import { readProviderKey } from "./keys.js";
|
|
38
|
+
import { replyInChannel } from "./chat-inbox.js";
|
|
39
|
+
import { recordSent, threadOf } from "./flow-replies.js";
|
|
40
|
+
import { ASKED, teammateReady, teammateTurn } from "./teammate-work.js";
|
|
41
|
+
import { budgetHoldWords, claudeMachineBilling, monthOf } from "./spend.js";
|
|
42
|
+
import { toolRefusal } from "./policy.js";
|
|
43
|
+
const RETRY_MS = [5 * 60_000, 15 * 60_000];
|
|
44
|
+
/** A teammate's turn tries again sooner: a card waiting on a person's colleague shouldn't wait long for a hiccup. */
|
|
45
|
+
const TEAMMATE_RETRY_MS = [60_000, 5 * 60_000];
|
|
46
|
+
const OUTPUT_CHARS = 3000;
|
|
47
|
+
/** How much of a step's output its run keeps as the log. */
|
|
48
|
+
const LOG_CHARS = 64_000;
|
|
49
|
+
/** Run every due check and update in one project, then move each card on. */
|
|
50
|
+
export async function runFlowSteps(store, repo, now, io) {
|
|
51
|
+
// v105: one budget gate a pass, built only if a Sort card is waiting.
|
|
52
|
+
let gate = null;
|
|
53
|
+
const budgetGate = work => (gate ??= store.budgetGate(now))(work);
|
|
54
|
+
const pass = { ran: 0, problems: [] };
|
|
55
|
+
// A step left running long past any time limit had its worker stop: it may try again.
|
|
56
|
+
for (const stale of store.staleFlowSteps(new Date(now.getTime() - 75 * 60_000)))
|
|
57
|
+
store.finishFlowStep(stale.card, stale.entry, { state: "waiting", result: "Interrupted; trying again.", nextAt: now.toISOString() }, now);
|
|
58
|
+
const flows = new Map();
|
|
59
|
+
for (const card of store.activeFlowCards(repo)) {
|
|
60
|
+
let known = flows.get(card.flow);
|
|
61
|
+
if (known === undefined) {
|
|
62
|
+
const flow = store.getFlow(card.flow);
|
|
63
|
+
known = { flow, definition: flowDefinitionOf(flow) };
|
|
64
|
+
flows.set(card.flow, known);
|
|
65
|
+
}
|
|
66
|
+
const stage = known.definition?.stages.find(one => one.id === card.stage);
|
|
67
|
+
if (stage === undefined)
|
|
68
|
+
continue;
|
|
69
|
+
// v92: a teammate's turn — a zone it handles, or a decision it staffs (a person decides when it's paused or gone).
|
|
70
|
+
if (stage.kind === "teammate" || (stage.kind === "approval" && stage.teammate !== undefined)) {
|
|
71
|
+
await teammateStep(store, known.flow, known.definition, stage, card, now, io, pass);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (!["check", "update", "sort", "draft", "request", "email", "tool"].includes(stage.kind))
|
|
75
|
+
continue;
|
|
76
|
+
// Email and tools wait, saying why, until what they need is set up.
|
|
77
|
+
const setup = stage.kind === "email" && !sendingReady(io.dir) ? "Email isn't set up yet. Add your mail server or a Google account in Settings → Email."
|
|
78
|
+
: stage.kind === "tool" ? toolWaiting(store, stage, repo) : null;
|
|
79
|
+
if (setup !== null) {
|
|
80
|
+
if (card.waiting !== setup)
|
|
81
|
+
store.updateFlowCard(card.id, { waiting: setup }, now);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const key = stage.kind === "sort" ? (io.openRouterKey ?? (() => readProviderKey("openrouter")))() : null;
|
|
85
|
+
if (stage.kind === "sort" && key === null) {
|
|
86
|
+
const waiting = "Sorting needs an OpenRouter key. Add one in Settings → AI providers.";
|
|
87
|
+
if (card.waiting !== waiting)
|
|
88
|
+
store.updateFlowCard(card.id, { waiting }, now);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
// v105: sorting spends the key's credit, and a draft whatever this computer's Claude bills: a budget for this project
|
|
92
|
+
// (or everything) that holds key work holds them.
|
|
93
|
+
const agents = stage.kind === "sort" ? [{ provider: "openrouter", billing: "api-key" }]
|
|
94
|
+
: stage.kind === "draft" ? [{ provider: "claude", billing: claudeMachineBilling(store.handle) }] : null;
|
|
95
|
+
const held = agents === null ? null : budgetGate({ project: repo, person: null, teammate: null, agents });
|
|
96
|
+
if (held !== null && held.over !== null) {
|
|
97
|
+
const waiting = `${budgetHoldWords(held, monthOf(now).name)}. Raise it on Spend to go on.`;
|
|
98
|
+
if (card.waiting !== waiting)
|
|
99
|
+
store.updateFlowCard(card.id, { waiting }, now);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
// Sprint 8: a sort, a draft or a tool call the organisation policy doesn't allow waits, saying which rule.
|
|
103
|
+
const disallowed = stage.kind === "sort" ? store.agentPolicyRefusal("openrouter", JEV_MODEL)
|
|
104
|
+
: stage.kind === "draft" ? store.agentPolicyRefusal("claude", draftModel(store))
|
|
105
|
+
: stage.kind === "tool" && stage.tool !== undefined && stage.tool !== null ? toolRefusal(store.orgPolicy(), stage.tool.server) : null;
|
|
106
|
+
if (disallowed !== null) {
|
|
107
|
+
if (card.waiting !== disallowed)
|
|
108
|
+
store.updateFlowCard(card.id, { waiting: disallowed }, now);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const script = stage.kind === "check" && stage.script !== null ? store.flowScript(repo, stage.script) : null;
|
|
112
|
+
if (stage.kind === "check" && script === null) {
|
|
113
|
+
const waiting = `There's no script called ${stage.script ?? "(none)"} in this project. Make it on the flow's Scripts panel.`;
|
|
114
|
+
if (card.waiting !== waiting)
|
|
115
|
+
store.updateFlowCard(card.id, { waiting }, now);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// A script waits for the secrets it names (v90), and runs on its own once they're saved.
|
|
119
|
+
const missing = stage.kind === "check" ? (stage.secrets ?? []).filter(name => readFlowSecrets(io.dir, repo)[name] === undefined) : [];
|
|
120
|
+
if (missing.length > 0) {
|
|
121
|
+
const waiting = `${stage.script} needs the secret${missing.length === 1 ? "" : "s"} ${missing.join(", ")}. Save ${missing.length === 1 ? "it" : "them"} on the zone.`;
|
|
122
|
+
if (card.waiting !== waiting)
|
|
123
|
+
store.updateFlowCard(card.id, { waiting }, now);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (!store.claimFlowStep({ card: card.id, entry: card.entry, stage: stage.id, kind: stage.kind, script: script?.name ?? null, scriptVersion: script?.version ?? null }, now))
|
|
127
|
+
continue;
|
|
128
|
+
pass.ran++;
|
|
129
|
+
store.updateFlowCard(card.id, { waiting: { check: "Running its check…", sort: "Sorting…", draft: "Writing the draft…", request: "Calling the address…", email: "Sending the email…", tool: "Using the tool…" }[stage.kind] ?? "Updating the issue…" }, now);
|
|
130
|
+
let outcome;
|
|
131
|
+
const started = Date.now();
|
|
132
|
+
try {
|
|
133
|
+
outcome = stage.kind === "check" ? await runCheck(store, known.flow, stage, script, card, now, io)
|
|
134
|
+
: stage.kind === "sort" ? await sortCard(known.definition, stage, card, key, io)
|
|
135
|
+
: stage.kind === "draft" ? await draftCard(store, known.definition, stage, card, io, repo, now)
|
|
136
|
+
: stage.kind === "request" ? await runRequest(stage, card, repo, io)
|
|
137
|
+
: stage.kind === "email" ? await sendEmail(stage, card, io, threadOf(store, card))
|
|
138
|
+
: stage.kind === "tool" ? await useTool(store, stage, card, repo, io)
|
|
139
|
+
: await updateSource(store, stage, card, io, now);
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
outcome = { state: "retry", said: error instanceof Error ? error.message : "It couldn't run." };
|
|
143
|
+
}
|
|
144
|
+
// What went out is kept before the card moves on, so a reply that comes back at once still finds it.
|
|
145
|
+
if (outcome.state === "passed" && outcome.mail !== undefined)
|
|
146
|
+
recordSent(store, card, outcome.mail, now);
|
|
147
|
+
settle(store, known.definition, stage, store.getFlowCard(card.id), outcome, now, Date.now() - started);
|
|
148
|
+
if (outcome.state === "retry")
|
|
149
|
+
pass.problems.push(`flow card ${card.id}: ${outcome.said}`);
|
|
150
|
+
}
|
|
151
|
+
return pass;
|
|
152
|
+
}
|
|
153
|
+
/** One teammate turn, when one is due for this card: claimed like any step, retried on failure, and waiting while its question is open. */
|
|
154
|
+
async function teammateStep(store, flow, definition, stage, card, now, io, pass) {
|
|
155
|
+
// v102: on a protected project an AI teammate never decides an approval; the engine asks the person.
|
|
156
|
+
if (stage.kind === "approval" && store.approvalRules(flow.repo).protectProject)
|
|
157
|
+
return true;
|
|
158
|
+
const mate = stage.teammate === undefined ? null : store.teammateByHandle(flow.repo, stage.teammate);
|
|
159
|
+
const ready = teammateReady(store, mate, now);
|
|
160
|
+
if (!ready.ok) {
|
|
161
|
+
// A decision goes to its person (the engine asks them). A zone only it handles waits, saying why.
|
|
162
|
+
if (stage.kind === "approval")
|
|
163
|
+
return true;
|
|
164
|
+
const waiting = ready.why === "gone" ? `There's no teammate called ${stage.teammate ?? "(none)"} in this project.` : `${mate.handle} is ${ready.why === "paused" ? "paused" : `waiting: ${ready.why}`}.`;
|
|
165
|
+
if (card.waiting !== waiting)
|
|
166
|
+
store.updateFlowCard(card.id, { waiting }, now);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
// Waiting on a person: its own question, or (v94) a tool call they approve first.
|
|
170
|
+
if (store.openTeammateQuestionOn(card.id, card.entry) !== null)
|
|
171
|
+
return true;
|
|
172
|
+
if (!store.claimFlowStep({ card: card.id, entry: card.entry, stage: stage.id, kind: "teammate", script: null, scriptVersion: null }, now))
|
|
173
|
+
return true;
|
|
174
|
+
pass.ran++;
|
|
175
|
+
const started = Date.now();
|
|
176
|
+
let outcome;
|
|
177
|
+
try {
|
|
178
|
+
outcome = await teammateTurn(store, flow, definition, stage, card, mate, now, { ...(io.teammate === undefined ? {} : { turn: io.teammate }), ...(io.evidenceRoot === undefined ? {} : { evidenceRoot: io.evidenceRoot }),
|
|
179
|
+
...(io.callTool === undefined ? {} : { callTool: io.callTool }), ...(io.listTools === undefined ? {} : { listTools: io.listTools }), ...(io.toolHome === undefined ? {} : { toolHome: io.toolHome }) });
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
outcome = { state: "retry", said: error instanceof Error ? error.message : "It couldn't take its turn." };
|
|
183
|
+
}
|
|
184
|
+
const run = store.flowStepRun(card.id, card.entry);
|
|
185
|
+
const kept = { log: outcome.log === undefined ? null : keptLog(outcome.log), durationMs: Date.now() - started, ...(outcome.decisionJson === undefined ? {} : { decisionJson: outcome.decisionJson }) };
|
|
186
|
+
if (outcome.state === "retry") {
|
|
187
|
+
const attempts = run?.attempts ?? 1;
|
|
188
|
+
if (attempts <= TEAMMATE_RETRY_MS.length) {
|
|
189
|
+
store.finishFlowStep(card.id, card.entry, { state: "waiting", result: outcome.said, nextAt: new Date(now.getTime() + TEAMMATE_RETRY_MS[attempts - 1]).toISOString(), ...kept }, now);
|
|
190
|
+
if (stage.kind !== "approval")
|
|
191
|
+
store.updateFlowCard(card.id, { waiting: `${outcome.said} Trying again in ${attempts === 1 ? "a minute" : "5 minutes"}.` }, now);
|
|
192
|
+
pass.problems.push(`flow card ${card.id}: ${outcome.said}`);
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
outcome = { state: "failed", said: `${outcome.said} It didn't work after three tries.` };
|
|
196
|
+
store.addTeammateEvent({ teammate: mate.id, card: card.id, entry: card.entry, kind: "failed", said: `Couldn't take its turn on “${card.title}”: ${outcome.said}` }, now);
|
|
197
|
+
if (stage.kind !== "approval")
|
|
198
|
+
store.updateFlowCard(card.id, { waiting: outcome.said }, now);
|
|
199
|
+
}
|
|
200
|
+
store.finishFlowStep(card.id, card.entry, outcome.state === "waiting" ? { state: "waiting", result: outcome.said, nextAt: outcome.nextAt ?? ASKED, ...kept }
|
|
201
|
+
: { state: outcome.state === "passed" ? "passed" : "failed", result: outcome.said, ...kept }, now);
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
/** Record what a step did and move the card: on for a pass, down its failure path for a fail, or wait to try again. */
|
|
205
|
+
function settle(store, definition, stage, card, outcome, now, durationMs) {
|
|
206
|
+
const run = store.flowStepRun(card.id, card.entry);
|
|
207
|
+
const kept = { log: outcome.log === undefined ? null : keptLog(outcome.log), exitCode: outcome.exitCode ?? null, durationMs, ...(outcome.decisionJson === undefined ? {} : { decisionJson: outcome.decisionJson }) };
|
|
208
|
+
if (outcome.state === "retry") {
|
|
209
|
+
const attempts = run?.attempts ?? 1;
|
|
210
|
+
if (attempts <= RETRY_MS.length) {
|
|
211
|
+
store.finishFlowStep(card.id, card.entry, { state: "waiting", result: outcome.said, nextAt: new Date(now.getTime() + RETRY_MS[attempts - 1]).toISOString(), ...kept }, now);
|
|
212
|
+
store.updateFlowCard(card.id, { waiting: `${outcome.said} Trying again in ${attempts === 1 ? 5 : 15} minutes.` }, now);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
outcome = { state: "failed", said: `${outcome.said} It didn't work after three tries.` };
|
|
216
|
+
}
|
|
217
|
+
store.finishFlowStep(card.id, card.entry, { state: outcome.state === "passed" ? "passed" : "failed", result: outcome.said, ...kept }, now);
|
|
218
|
+
store.updateFlowCard(card.id, { outputs: { ...card.outputs, [stage.id]: outcome.output ?? outcome.said }, waiting: null }, now);
|
|
219
|
+
const titleOf = (id) => definition.stages.find(one => one.id === id)?.title ?? "another zone";
|
|
220
|
+
if (outcome.state === "passed") {
|
|
221
|
+
// A sort names where the card goes; one it isn't sure about is a person's to place.
|
|
222
|
+
const to = outcome.to !== undefined ? outcome.to : stage.next;
|
|
223
|
+
if (outcome.unsure === true) {
|
|
224
|
+
const people = card.owner === null ? cardFollowers(store, card) : [card.owner];
|
|
225
|
+
notifyPeople(store, card, people, null, { key: `unsure:${card.entry}`, subject: `${stage.title} wasn't sure about “${card.title}”`, body: `${outcome.said}${to === null ? " Move it to the right zone." : ` It's in ${definition.stages.find(one => one.id === to)?.title ?? "another zone"} for a person to place.`}`, attention: true }, now);
|
|
226
|
+
}
|
|
227
|
+
if (to === null) {
|
|
228
|
+
store.updateFlowCard(card.id, { waiting: outcome.to !== undefined ? `${outcome.said} Move it to the right zone.` : "Finished here. Move the card on when you're ready." }, now);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
store.moveFlowCard(card.id, { to, outcome: "ok", actor: "flow", expectEntry: card.entry }, now);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (stage.onFail === null) {
|
|
235
|
+
store.updateFlowCard(card.id, { waiting: `${outcome.said} Fix it, then move the card to try again.` }, now);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
store.moveFlowCard(card.id, { to: stage.onFail, outcome: "fail", actor: "flow", note: outcome.said, expectEntry: card.entry }, now);
|
|
239
|
+
}
|
|
240
|
+
const people = card.owner === null ? cardFollowers(store, card) : [card.owner];
|
|
241
|
+
notifyPeople(store, card, people, null, { key: `step-failed:${card.entry}`, subject: `${stage.title} didn't pass for “${card.title}”`, body: `${outcome.said}${stage.onFail === null ? "" : `\n\nIt's back in ${titleOf(stage.onFail)}.`}`, attention: true }, now);
|
|
242
|
+
}
|
|
243
|
+
/** A run's log: the end of its output in whole lines, where failures show, with key-shaped lines replaced and credential-looking values blanked. */
|
|
244
|
+
function keptLog(text) {
|
|
245
|
+
const end = text.length <= LOG_CHARS ? text : text.slice(-LOG_CHARS).replace(/^[^\n]*\n/, "");
|
|
246
|
+
return redactSecretAssignments(redactSecretLines(end, scanForSecrets(end)));
|
|
247
|
+
}
|
|
248
|
+
/** The end of a command's output, without anything that looks like a key. */
|
|
249
|
+
function tail(text) {
|
|
250
|
+
const end = text.trim().slice(-OUTPUT_CHARS);
|
|
251
|
+
return scanForSecrets(end).length > 0 ? "(Its output held something that looked like a key, so it isn't shown.)" : end;
|
|
252
|
+
}
|
|
253
|
+
/** The Claude model a draft runs on: the lead chat's Claude model, or Claude's default. */
|
|
254
|
+
function draftModel(store) {
|
|
255
|
+
const config = store.getChatConfig();
|
|
256
|
+
return config?.provider === "claude-subscription" ? config.model : "default";
|
|
257
|
+
}
|
|
258
|
+
/** A draft: Claude writes what the zone asks, from the card, with the lead chat's Claude model; the text stays on the card. */
|
|
259
|
+
async function draftCard(store, definition, stage, card, io, repo, now) {
|
|
260
|
+
const model = draftModel(store);
|
|
261
|
+
const answer = await (io.draft ?? claudeDraftRunner())({ model, prompt: draftPrompt(stage, card, definition), timeoutMs: DRAFT_TIMEOUT });
|
|
262
|
+
if (!answer.ok)
|
|
263
|
+
return { state: "retry", said: answer.said };
|
|
264
|
+
// v105: what it cost, billed as this computer's Claude does (a plan's is $0).
|
|
265
|
+
store.recordDraftSpend({ repo, model: model === "default" ? null : model, costUsd: answer.costUsd ?? null }, now);
|
|
266
|
+
const text = keptDraft(answer.text);
|
|
267
|
+
if (text === "")
|
|
268
|
+
return { state: "retry", said: "Claude's draft came back empty." };
|
|
269
|
+
const words = text.split(/\s+/).filter(Boolean).length;
|
|
270
|
+
return { state: "passed", said: `Drafted ${words} word${words === 1 ? "" : "s"}.`, output: text, log: `Claude (${model}) · ${(answer.ms / 1000).toFixed(1)} s\n\n${text}` };
|
|
271
|
+
}
|
|
272
|
+
/** A sort: Jev picks one of the zone's answers for the card; the answer (or the not-sure path) says where it goes. */
|
|
273
|
+
async function sortCard(definition, stage, card, key, io) {
|
|
274
|
+
const index = definition.stages.findIndex(one => one.id === stage.id);
|
|
275
|
+
const earlier = definition.stages.filter((one, at) => at !== index && card.outputs[one.id] !== undefined).map(one => ({ id: one.id, title: one.title }));
|
|
276
|
+
const asked = await askJev(io.fetch, key, sortRequest(stage.sort, sortState(card, earlier)));
|
|
277
|
+
if (!asked.ok)
|
|
278
|
+
return { state: "retry", said: asked.said };
|
|
279
|
+
const decision = readJevAnswers(stage, asked.body, asked.ms);
|
|
280
|
+
if ("problem" in decision)
|
|
281
|
+
return { state: "retry", said: decision.problem };
|
|
282
|
+
return { state: "passed", said: sortWords(decision), log: sortLog(stage, decision), to: decision.to, decisionJson: JSON.stringify(decision), unsure: !decision.confident };
|
|
283
|
+
}
|
|
284
|
+
/** A script step: a fresh detached copy at the card's latest result (or the base branch), the approved setup, then the script. */
|
|
285
|
+
/**
|
|
286
|
+
* A script zone (v90: code steps): the script runs with the card as its input, in a clean folder or in
|
|
287
|
+
* a copy of the card's work (after the project's setup), inside the agents' fence. What it prints is
|
|
288
|
+
* the step's result; a last "goto:" line picks one of the zone's answers.
|
|
289
|
+
*/
|
|
290
|
+
async function runCheck(store, flow, stage, script, card, now, io) {
|
|
291
|
+
const task = card.primaryTask ?? card.task;
|
|
292
|
+
const copy = (stage.runIn ?? "copy") === "copy";
|
|
293
|
+
const receipt = !copy || task === null ? null : assignmentOf(store, task, now, { principal: "operator", repos: [flow.repo] }, io.evidenceRoot)?.receipt ?? null;
|
|
294
|
+
const commit = receipt?.head ?? null;
|
|
295
|
+
const where = !copy ? "" : commit === null ? ` on ${io.base}` : ` on commit ${commit.slice(0, 7)}`;
|
|
296
|
+
// The secrets it names, from the flow's saved ones: a missing one is said, never run without.
|
|
297
|
+
const saved = readFlowSecrets(io.dir, flow.repo);
|
|
298
|
+
const missing = (stage.secrets ?? []).filter(name => saved[name] === undefined);
|
|
299
|
+
if (missing.length > 0)
|
|
300
|
+
return { state: "failed", said: `${script.name} needs the secret${missing.length === 1 ? "" : "s"} ${missing.join(", ")}. Save ${missing.length === 1 ? "it" : "them"} on the zone, then move the card back to try again.` };
|
|
301
|
+
const secrets = Object.fromEntries((stage.secrets ?? []).map(name => [name, saved[name]]));
|
|
302
|
+
mkdirSync(io.scratch, { recursive: true });
|
|
303
|
+
const path = copy ? join(io.scratch, `flow-check-${card.id}-${card.entry}`) : cleanFolder(io.scratch, `flow-run-${card.id}-${card.entry}`);
|
|
304
|
+
if (copy) {
|
|
305
|
+
rmSync(path, { recursive: true, force: true });
|
|
306
|
+
const added = await io.git("git", ["-C", flow.repo, "worktree", "add", "--detach", path, commit ?? io.base], { timeoutMs: 120_000 });
|
|
307
|
+
if (added.code !== 0)
|
|
308
|
+
return { state: "retry", said: `Couldn't make a copy of${where}: ${added.stderr.trim().split("\n")[0]?.slice(0, 160) ?? "git refused"}.` };
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const fence = agentFence({ databaseFile: store.databaseFile(), worktree: path });
|
|
312
|
+
let log = "";
|
|
313
|
+
const setup = copy ? store.liveWorktreeSetup(flow.repo) : null;
|
|
314
|
+
if (setup !== null) {
|
|
315
|
+
const shell = approvedCommandShell(setup.command);
|
|
316
|
+
const prepared = await io.shell(shell.file, shell.args, { cwd: path, timeoutMs: setup.timeoutMs, envAllowlist: SETUP_ENV_ALLOWLIST, omitEnv: SETUP_ENV_DENYLIST, processGroup: true, fence });
|
|
317
|
+
log += `$ ${setup.command}\n${prepared.stdout}${prepared.stderr}\n`;
|
|
318
|
+
if (prepared.code !== 0)
|
|
319
|
+
return { state: "failed", said: `The project's setup failed before ${script.name} ran (exit ${prepared.code}).\n${tail(`${prepared.stdout}\n${prepared.stderr}`)}`, log, exitCode: prepared.code };
|
|
320
|
+
}
|
|
321
|
+
const definition = flowDefinitionOf(flow);
|
|
322
|
+
const titleOf = (id) => definition?.stages.find(one => one.id === id)?.title ?? id;
|
|
323
|
+
// The card as data: never part of a command.
|
|
324
|
+
const input = {
|
|
325
|
+
card: { id: card.id, title: card.title, description: card.description, email: cardEmailOf(card) || null, note: card.note, owner: card.owner, source: card.source === null ? null : { kind: card.source.kind, label: card.source.label, url: card.source.url } },
|
|
326
|
+
outputs: Object.fromEntries(Object.entries(card.outputs).map(([id, text]) => [id, { zone: titleOf(id), text }])),
|
|
327
|
+
flow: { id: flow.id, name: flow.name }, zone: { id: stage.id, title: stage.title }, visit: card.entry, commit,
|
|
328
|
+
answers: (stage.routes ?? []).map(one => one.answer),
|
|
329
|
+
};
|
|
330
|
+
const env = { FLOW_NAME: flow.name, FLOW_CARD_ID: String(card.id), FLOW_CARD_TITLE: card.title, FLOW_COMMIT: commit ?? "", FLOW_SCRIPT: script.name, FLOW_PROJECT: flow.repo };
|
|
331
|
+
const ran = await runCode({ script, cwd: path, root: copy ? path : flow.repo, input, env, secrets, scratch: io.scratch, shell: io.shell, fence });
|
|
332
|
+
log += ran.log;
|
|
333
|
+
const output = ran.output === "" ? undefined : ran.output;
|
|
334
|
+
// Where it ran goes at the end of the first line: "run-tests failed (exit 1) on main."
|
|
335
|
+
const placed = (said) => { const [first = "", ...rest] = said.split("\n"); return [first.replace(/\.$/, `${where}.`), ...rest].join("\n"); };
|
|
336
|
+
if (ran.state === "failed")
|
|
337
|
+
return { state: "failed", said: placed(ran.said), log, exitCode: ran.exitCode, ...(output === undefined ? {} : { output }) };
|
|
338
|
+
if (ran.goTo === null)
|
|
339
|
+
return { state: "passed", said: copy ? `${script.name} passed${where}.` : `${script.name} ran.`, log, exitCode: 0, ...(output === undefined ? {} : { output }) };
|
|
340
|
+
const route = (stage.routes ?? []).find(one => one.answer.toLowerCase() === ran.goTo.toLowerCase());
|
|
341
|
+
if (route === undefined)
|
|
342
|
+
return { state: "failed", said: `${script.name} picked “${ran.goTo}”, but this zone has no answer called that${(stage.routes ?? []).length === 0 ? "" : ` (it has ${(stage.routes ?? []).map(one => one.answer).join(", ")})`}.`, log, exitCode: 0, ...(output === undefined ? {} : { output }) };
|
|
343
|
+
return { state: "passed", said: `${script.name} ran${where} and picked ${route.answer}.`, log, exitCode: 0, to: route.to, ...(output === undefined ? {} : { output }) };
|
|
344
|
+
}
|
|
345
|
+
finally {
|
|
346
|
+
if (copy)
|
|
347
|
+
await io.git("git", ["-C", flow.repo, "worktree", "remove", "--force", path], { timeoutMs: 60_000 }).catch(() => undefined);
|
|
348
|
+
rmSync(path, { recursive: true, force: true });
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/** An update: a comment on the issue the card came from, and closing it if the zone says so. */
|
|
352
|
+
async function updateSource(store, stage, card, io, now) {
|
|
353
|
+
const source = card.source;
|
|
354
|
+
const text = fillFlowText(stage.message ?? "Done: {{card.title}}", { title: card.title, description: card.description, note: card.note, outputs: card.outputs });
|
|
355
|
+
if (scanForSecrets(text).length > 0)
|
|
356
|
+
return { state: "failed", said: "The comment looked like it held a key or password, so nothing was posted." };
|
|
357
|
+
// A card from a chat channel (v89): the answer goes in the thread it came from.
|
|
358
|
+
if (source?.chat !== undefined) {
|
|
359
|
+
const replied = replyInChannel(store, source.chat, { card: card.id, entry: card.entry }, text, now);
|
|
360
|
+
return replied.ok ? { state: "passed", said: `Answered in the ${source.label.replace(/ message$/, "")} thread.` } : { state: "failed", said: replied.said };
|
|
361
|
+
}
|
|
362
|
+
const github = source?.kind === "github" && source.url !== null ? /^https:\/\/github\.com\/([A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)\/(issues|pull)\/(\d+)$/.exec(source.url) : null;
|
|
363
|
+
if (github !== null) {
|
|
364
|
+
const [, repo, what, number] = github;
|
|
365
|
+
const commented = await io.gh("gh", ["api", "-X", "POST", `repos/${repo}/issues/${number}/comments`, "-f", `body=${text}`], { timeoutMs: 20_000 });
|
|
366
|
+
if (commented.code !== 0)
|
|
367
|
+
return { state: "retry", said: `GitHub didn't take the comment: ${(commented.stderr || commented.stdout).trim().split("\n")[0]?.slice(0, 160)}.` };
|
|
368
|
+
if (stage.close === true && what === "issues") {
|
|
369
|
+
const closed = await io.gh("gh", ["api", "-X", "PATCH", `repos/${repo}/issues/${number}`, "-f", "state=closed", "-f", "state_reason=completed"], { timeoutMs: 20_000 });
|
|
370
|
+
if (closed.code !== 0)
|
|
371
|
+
return { state: "retry", said: `Commented, but GitHub didn't close it: ${(closed.stderr || closed.stdout).trim().split("\n")[0]?.slice(0, 160)}.` };
|
|
372
|
+
return { state: "passed", said: `Commented on and closed ${source.label}.` };
|
|
373
|
+
}
|
|
374
|
+
return { state: "passed", said: `Commented on ${source.label}.` };
|
|
375
|
+
}
|
|
376
|
+
const linear = source?.kind === "linear" ? /^Linear ([A-Z][A-Z0-9]*-\d+)$/.exec(source.label)?.[1] ?? null : null;
|
|
377
|
+
if (linear !== null) {
|
|
378
|
+
const key = readLinearKey(io.dir);
|
|
379
|
+
if (key === null)
|
|
380
|
+
return { state: "failed", said: "Needs a Linear API key to update the issue. Add it on the flow's Triggers panel." };
|
|
381
|
+
const ask = async (query, variables) => {
|
|
382
|
+
const response = await io.fetch(LINEAR_URL, { method: "POST", headers: { "content-type": "application/json", authorization: key }, body: JSON.stringify({ query, variables }), signal: AbortSignal.timeout(20_000) });
|
|
383
|
+
const body = await response.json();
|
|
384
|
+
if (!response.ok || (body.errors?.length ?? 0) > 0)
|
|
385
|
+
throw new Error(`Linear said: ${(body.errors?.[0]?.message ?? `status ${response.status}`).slice(0, 160)}.`);
|
|
386
|
+
return body.data ?? {};
|
|
387
|
+
};
|
|
388
|
+
try {
|
|
389
|
+
const found = await ask("query FlowIssue($id: String!) { issue(id: $id) { id team { states(filter: { type: { eq: \"completed\" } }) { nodes { id name } } } } }", { id: linear });
|
|
390
|
+
const issue = found["issue"];
|
|
391
|
+
if (issue === null || issue === undefined)
|
|
392
|
+
return { state: "failed", said: `Linear has no issue ${linear} this key can see.` };
|
|
393
|
+
await ask("mutation FlowComment($input: CommentCreateInput!) { commentCreate(input: $input) { success } }", { input: { issueId: issue.id, body: text } });
|
|
394
|
+
if (stage.close === true) {
|
|
395
|
+
const done = issue.team.states.nodes[0];
|
|
396
|
+
if (done === undefined)
|
|
397
|
+
return { state: "passed", said: `Commented on ${linear}; its team has no done state to move it to.` };
|
|
398
|
+
await ask("mutation FlowDone($id: String!, $input: IssueUpdateInput!) { issueUpdate(id: $id, input: $input) { success } }", { id: issue.id, input: { stateId: done.id } });
|
|
399
|
+
return { state: "passed", said: `Commented on ${linear} and moved it to ${done.name}.` };
|
|
400
|
+
}
|
|
401
|
+
return { state: "passed", said: `Commented on ${linear}.` };
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
return { state: "retry", said: error instanceof Error ? error.message : "Couldn't reach Linear." };
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return { state: "passed", said: "Nothing to update: this card didn't come from a GitHub or Linear issue or a chat channel." };
|
|
408
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import type { Runner } from "./backend.js";
|
|
2
|
+
import { type FlowAct } from "./flow-engine.js";
|
|
3
|
+
import type { FlowDefinition } from "./flows.js";
|
|
4
|
+
import { type MailReader } from "./mailbox.js";
|
|
5
|
+
import type { FlowCardSource, FlowRow, FlowTriggerRow, Store } from "./store.js";
|
|
6
|
+
export declare const FLOW_TRIGGER_KINDS: readonly ["button", "schedule", "github", "linear", "flow", "webhook", "email", "chat"];
|
|
7
|
+
export type FlowTriggerKind = (typeof FLOW_TRIGGER_KINDS)[number];
|
|
8
|
+
export type TriggerConfig = {
|
|
9
|
+
kind: "button";
|
|
10
|
+
label: string;
|
|
11
|
+
questions: string[];
|
|
12
|
+
zone: string | null;
|
|
13
|
+
}
|
|
14
|
+
/** `script` (v90): run this project script on the schedule and make a card of each item it prints, instead of one card titled `title`. */
|
|
15
|
+
| {
|
|
16
|
+
kind: "schedule";
|
|
17
|
+
schedule: string;
|
|
18
|
+
title: string;
|
|
19
|
+
description: string | null;
|
|
20
|
+
zone: string | null;
|
|
21
|
+
script?: string;
|
|
22
|
+
secrets?: string[];
|
|
23
|
+
} | {
|
|
24
|
+
kind: "github";
|
|
25
|
+
repo: string;
|
|
26
|
+
watch: "issues" | "pulls" | "checks";
|
|
27
|
+
label: string | null;
|
|
28
|
+
branch: string | null;
|
|
29
|
+
from: "team" | "anyone";
|
|
30
|
+
delivery: "poll" | "webhook";
|
|
31
|
+
zone: string | null;
|
|
32
|
+
} | {
|
|
33
|
+
kind: "linear";
|
|
34
|
+
team: string | null;
|
|
35
|
+
state: string | null;
|
|
36
|
+
label: string | null;
|
|
37
|
+
delivery: "poll" | "webhook";
|
|
38
|
+
zone: string | null;
|
|
39
|
+
} | {
|
|
40
|
+
kind: "flow";
|
|
41
|
+
flow: number;
|
|
42
|
+
when: string;
|
|
43
|
+
zone: string | null;
|
|
44
|
+
} | {
|
|
45
|
+
kind: "webhook";
|
|
46
|
+
title: string;
|
|
47
|
+
titleField: string | null;
|
|
48
|
+
bodyField: string | null;
|
|
49
|
+
zone: string | null;
|
|
50
|
+
}
|
|
51
|
+
/** `sender`: addresses or domains, comma-separated; `subject`: words the subject must contain. */
|
|
52
|
+
| {
|
|
53
|
+
kind: "email";
|
|
54
|
+
folder: string;
|
|
55
|
+
sender: string | null;
|
|
56
|
+
subject: string | null;
|
|
57
|
+
zone: string | null;
|
|
58
|
+
}
|
|
59
|
+
/** A channel in a chat app; `binding` is the pairing of the person who connected it (whose chat answers there). */
|
|
60
|
+
| {
|
|
61
|
+
kind: "chat";
|
|
62
|
+
app: ChatApp;
|
|
63
|
+
installation: string;
|
|
64
|
+
chat: string;
|
|
65
|
+
binding: number;
|
|
66
|
+
zone: string | null;
|
|
67
|
+
};
|
|
68
|
+
export type ChatApp = "slack" | "discord" | "teams" | "telegram";
|
|
69
|
+
export declare const CHAT_APP_NAMES: Record<ChatApp, string>;
|
|
70
|
+
/** What each kind is called on the canvas. */
|
|
71
|
+
export declare const FLOW_TRIGGER_WORDS: Record<FlowTriggerKind, string>;
|
|
72
|
+
/** How often the worker checks GitHub and Linear, and how it backs off when they don't answer. */
|
|
73
|
+
export declare const POLL_EVERY_MS: number;
|
|
74
|
+
/** At most this many cards from one check or one delivery; the rest wait for the next. */
|
|
75
|
+
export declare const CARDS_PER_CHECK = 10;
|
|
76
|
+
/** A schedule said in words ("every 2 hours", "daily 09:00 Europe/London", "monday 09:00") or in the routines' own form. */
|
|
77
|
+
export declare function scheduleFromWords(text: string): string | null;
|
|
78
|
+
/** A GitHub repository as owner/name, read from a project's origin remote when it is on GitHub. */
|
|
79
|
+
export declare function githubRepoOf(path: string): string | null;
|
|
80
|
+
/** A trigger's settings, checked whole against the flow it starts cards in. Throws in plain words. */
|
|
81
|
+
export declare function validateTriggerConfig(raw: unknown, context: {
|
|
82
|
+
store: Store;
|
|
83
|
+
flow: FlowRow;
|
|
84
|
+
definition: FlowDefinition;
|
|
85
|
+
actor: string;
|
|
86
|
+
}): TriggerConfig;
|
|
87
|
+
/** Whether an email is one this trigger takes: from a named sender (or domain), with the words in its subject. */
|
|
88
|
+
export declare function mailMatches(config: Extract<TriggerConfig, {
|
|
89
|
+
kind: "email";
|
|
90
|
+
}>, mail: {
|
|
91
|
+
from: string;
|
|
92
|
+
subject: string;
|
|
93
|
+
}): boolean;
|
|
94
|
+
/** The trigger in the words the canvas and its cards use. */
|
|
95
|
+
export declare function describeTrigger(config: TriggerConfig, store: Store): string;
|
|
96
|
+
/** The trigger in two short lines for the canvas: what it is, and the one detail that tells it apart. */
|
|
97
|
+
export declare function triggerHeadline(config: TriggerConfig, store: Store): {
|
|
98
|
+
name: string;
|
|
99
|
+
detail: string;
|
|
100
|
+
};
|
|
101
|
+
export declare function triggerConfigOf(trigger: FlowTriggerRow): TriggerConfig | null;
|
|
102
|
+
/** Whether this trigger takes deliveries at a secret address rather than being checked. */
|
|
103
|
+
export declare function takesDeliveries(config: TriggerConfig): boolean;
|
|
104
|
+
/** A webhook's signing secret (GitHub: made here; Linear: pasted from Linear). 0600, beside the database, never a column. */
|
|
105
|
+
export declare function saveHookSecret(dir: string, trigger: number, secret: string): void;
|
|
106
|
+
export declare function readHookSecret(dir: string, trigger: number): string | null;
|
|
107
|
+
export declare const LINEAR_ENV = "TOOLROLL_LINEAR_KEY";
|
|
108
|
+
/** The Linear API key the worker checks Linear with: the environment, or a 0600 file beside the database. */
|
|
109
|
+
export declare function readLinearKey(dir: string | null): string | null;
|
|
110
|
+
export declare function saveLinearKey(dir: string, key: string): {
|
|
111
|
+
ok: true;
|
|
112
|
+
} | {
|
|
113
|
+
ok: false;
|
|
114
|
+
message: string;
|
|
115
|
+
};
|
|
116
|
+
export declare function removeLinearKey(dir: string): void;
|
|
117
|
+
/** The public address webhooks reach this console at (a reverse proxy such as Caddy, exposing /hooks/ only). */
|
|
118
|
+
export declare function readHooksBase(dir: string | null): string | null;
|
|
119
|
+
export declare function saveHooksBase(dir: string, value: string): {
|
|
120
|
+
ok: true;
|
|
121
|
+
base: string | null;
|
|
122
|
+
} | {
|
|
123
|
+
ok: false;
|
|
124
|
+
message: string;
|
|
125
|
+
};
|
|
126
|
+
export declare const HOOK_PATH = "/hooks/flow/";
|
|
127
|
+
export type TriggerReveal = {
|
|
128
|
+
path: string;
|
|
129
|
+
address: string | null;
|
|
130
|
+
secret: string | null;
|
|
131
|
+
};
|
|
132
|
+
export type TriggerMade = {
|
|
133
|
+
ok: true;
|
|
134
|
+
id: number;
|
|
135
|
+
said: string;
|
|
136
|
+
reveal: TriggerReveal | null;
|
|
137
|
+
} | {
|
|
138
|
+
ok: false;
|
|
139
|
+
message: string;
|
|
140
|
+
};
|
|
141
|
+
/** Add a trigger to a flow. A webhook trigger's address (and GitHub's signing secret) is returned once and never stored readable. */
|
|
142
|
+
export declare function addFlowTriggerTo(store: Store, flow: FlowRow, raw: unknown, actor: string, now: Date, dir: string | null): TriggerMade;
|
|
143
|
+
/** A new secret address for a webhook trigger (the old one stops working at once). */
|
|
144
|
+
export declare function renewFlowHook(store: Store, trigger: FlowTriggerRow, now: Date, dir: string): TriggerMade;
|
|
145
|
+
export declare function removeFlowTrigger(store: Store, trigger: FlowTriggerRow, now: Date, dir: string | null): void;
|
|
146
|
+
export type Incoming = {
|
|
147
|
+
key: string;
|
|
148
|
+
title: string;
|
|
149
|
+
description: string | null;
|
|
150
|
+
source: FlowCardSource;
|
|
151
|
+
};
|
|
152
|
+
type Made = "added" | "seen" | "skipped";
|
|
153
|
+
/** One outside thing into one card through a trigger (a chat channel's message, v89): at most once per key. */
|
|
154
|
+
export declare function addTriggerCard(store: Store, trigger: FlowTriggerRow, item: Incoming, by: string, now: Date): {
|
|
155
|
+
made: Made;
|
|
156
|
+
note: string | null;
|
|
157
|
+
card: number | null;
|
|
158
|
+
};
|
|
159
|
+
/** Press a button trigger: the first answer is the card's title, the rest its details. */
|
|
160
|
+
export declare function pressFlowButton(store: Store, trigger: FlowTriggerRow, answers: readonly unknown[], actor: string, now: Date): FlowAct;
|
|
161
|
+
export type TriggerIo = {
|
|
162
|
+
gh: Runner;
|
|
163
|
+
fetch: typeof fetch;
|
|
164
|
+
dir: string | null;
|
|
165
|
+
/** How mail is read (default: IMAP; tests pass a scripted mailbox). */
|
|
166
|
+
mail?: MailReader;
|
|
167
|
+
/** v90: how a schedule's script runs (default: the same runner as gh) and where (default: beside the database). */
|
|
168
|
+
shell?: Runner;
|
|
169
|
+
scratch?: string;
|
|
170
|
+
};
|
|
171
|
+
export type TriggerPass = {
|
|
172
|
+
added: number;
|
|
173
|
+
checked: number;
|
|
174
|
+
problems: string[];
|
|
175
|
+
};
|
|
176
|
+
/** Every trigger in one project that is due: schedules and other flows here, GitHub, Linear and email by asking them. */
|
|
177
|
+
export declare function runFlowTriggers(store: Store, repo: string, now: Date, io: TriggerIo): Promise<TriggerPass>;
|
|
178
|
+
/** "Check now" on the canvas: one trigger, right away, in words. */
|
|
179
|
+
export declare function checkFlowTriggerNow(store: Store, trigger: FlowTriggerRow, now: Date, io: TriggerIo): Promise<{
|
|
180
|
+
ok: boolean;
|
|
181
|
+
said: string;
|
|
182
|
+
}>;
|
|
183
|
+
/** v96: a schedule (a teammate's routine) makes its card now, once per press, and keeps its own times. */
|
|
184
|
+
export declare function runScheduleNow(store: Store, trigger: FlowTriggerRow, actor: string, now: Date): {
|
|
185
|
+
ok: true;
|
|
186
|
+
card: number;
|
|
187
|
+
} | {
|
|
188
|
+
ok: false;
|
|
189
|
+
said: string;
|
|
190
|
+
};
|
|
191
|
+
type Found = (Incoming & {
|
|
192
|
+
at: string | null;
|
|
193
|
+
}) | {
|
|
194
|
+
key: string;
|
|
195
|
+
skip: string;
|
|
196
|
+
label: string;
|
|
197
|
+
at: string | null;
|
|
198
|
+
};
|
|
199
|
+
/** A GitHub issue or pull request as a card, or why it is left out; null when it doesn't match. */
|
|
200
|
+
export declare function githubItem(config: Extract<TriggerConfig, {
|
|
201
|
+
kind: "github";
|
|
202
|
+
}>, raw: unknown, what: "issue" | "pull"): Found | null;
|
|
203
|
+
/** A failed workflow run as a card: one card per failing commit on the watched branch. */
|
|
204
|
+
export declare function githubRunItem(config: Extract<TriggerConfig, {
|
|
205
|
+
kind: "github";
|
|
206
|
+
}>, raw: unknown): Found | null;
|
|
207
|
+
export declare const LINEAR_URL = "https://api.linear.app/graphql";
|
|
208
|
+
export declare const LINEAR_QUERY = "query FlowTrigger($filter: IssueFilter) { issues(filter: $filter, first: 50, orderBy: updatedAt) { nodes { identifier title description url updatedAt state { name } team { key } labels { nodes { name } } } } }";
|
|
209
|
+
/** A Linear issue as a card; null when it doesn't match the trigger. */
|
|
210
|
+
export declare function linearItem(config: Extract<TriggerConfig, {
|
|
211
|
+
kind: "linear";
|
|
212
|
+
}>, raw: unknown): Found | null;
|
|
213
|
+
export type HookDelivery = {
|
|
214
|
+
headers: Record<string, string | string[] | undefined>;
|
|
215
|
+
body: Buffer;
|
|
216
|
+
};
|
|
217
|
+
export type HookAnswer = {
|
|
218
|
+
status: number;
|
|
219
|
+
said: string;
|
|
220
|
+
};
|
|
221
|
+
/** A webhook delivery at a trigger's secret address: prove it, read it, make at most the cards it names. Nothing runs here. */
|
|
222
|
+
export declare function receiveFlowHook(store: Store, token: string, delivery: HookDelivery, dir: string, now: Date): HookAnswer;
|
|
223
|
+
/** Save Linear's signing secret for a Linear webhook trigger (pasted on the secure panel, never in chat). */
|
|
224
|
+
export declare function saveLinearSigningSecret(trigger: FlowTriggerRow, secret: string, dir: string): {
|
|
225
|
+
ok: true;
|
|
226
|
+
} | {
|
|
227
|
+
ok: false;
|
|
228
|
+
message: string;
|
|
229
|
+
};
|
|
230
|
+
/** Whether a webhook trigger can prove its deliveries: GitHub always (its secret is made here), Linear once its secret is pasted. */
|
|
231
|
+
export declare function hookReady(trigger: FlowTriggerRow, dir: string | null): boolean;
|
|
232
|
+
export declare const FORM_PATH = "/hooks/form/";
|
|
233
|
+
/** Share a button as a secret link anyone can fill in, without signing in. The link is shown once; only its hash is kept. */
|
|
234
|
+
export declare function shareFlowButton(store: Store, trigger: FlowTriggerRow, now: Date, dir: string | null): TriggerMade;
|
|
235
|
+
export declare function stopSharingFlowButton(store: Store, trigger: FlowTriggerRow, now: Date): void;
|
|
236
|
+
export type FormAnswer = {
|
|
237
|
+
status: number;
|
|
238
|
+
html: string;
|
|
239
|
+
};
|
|
240
|
+
/** GET a shared form: its questions. */
|
|
241
|
+
export declare function flowFormPage(store: Store, token: string, now: Date): FormAnswer;
|
|
242
|
+
/** POST a shared form: at most one card per submission, keys refused, a limit per hour, and quiet about what a bot did wrong. */
|
|
243
|
+
export declare function receiveFlowForm(store: Store, token: string, fields: URLSearchParams, now: Date): FormAnswer;
|
|
244
|
+
export {};
|