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,384 @@
|
|
|
1
|
+
/** Paginated, permission-bound summaries of saved task facts. These reads do
|
|
2
|
+
* not verify artifacts, inspect processes, or authorize task operations. */
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { readProjectAccess } from './project-access.js';
|
|
5
|
+
import { scopeTermsProblem } from './store.js';
|
|
6
|
+
export const WORK_INDEX_PAGE_LIMIT = 40;
|
|
7
|
+
export const WORK_INDEX_MAX_LIMIT = 100;
|
|
8
|
+
const EMPTY = { all: 0, 'needs-you': 0, running: 0, completed: 0 };
|
|
9
|
+
const FAMILY_PROBLEM = 'Task history is unavailable or incomplete. This task is shown separately.';
|
|
10
|
+
const VIEWS = ['all', 'needs-you', 'running', 'completed'];
|
|
11
|
+
const n = (row, key) => Number(row[key] ?? 0);
|
|
12
|
+
const s = (row, key) => row[key] == null ? null : String(row[key]);
|
|
13
|
+
/** Keep the lineage predicates identical to Store.taskFamilyProjection: an
|
|
14
|
+
* admitted child needs its parent's exact revision brief, in the same repo.
|
|
15
|
+
* All subsequent reads are scalar/indexed metadata, never artifact bytes.
|
|
16
|
+
* MATERIALIZED prevents counts + page selection repeating correlated reads. */
|
|
17
|
+
const PROJECTION = `WITH RECURSIVE admitted AS MATERIALIZED (
|
|
18
|
+
SELECT t.id, t.title, t.state, t.created_at, t.updated_at, r.id ref_id, r.repo,
|
|
19
|
+
r.revision_of, r.revision_brief_artifact, r.assigned_runner, r.plan,
|
|
20
|
+
r.deliverable, r.coordinator_cid, r.capability_requirements, r.park_rate
|
|
21
|
+
FROM task_ref r JOIN task t ON t.id = r.external_id
|
|
22
|
+
WHERE r.backend = 'built-in' AND ((r.repo IS NULL AND $unplaced = 1)
|
|
23
|
+
OR (r.repo IS NOT NULL AND ($all = 1 OR r.repo IN (SELECT value FROM json_each($repos)))))
|
|
24
|
+
AND ($projectSet = 0 OR r.repo IS $project)
|
|
25
|
+
), lineage(ref_id,root_ref,depth) AS (
|
|
26
|
+
SELECT ref_id,ref_id,0 FROM admitted WHERE revision_of IS NULL
|
|
27
|
+
UNION ALL
|
|
28
|
+
SELECT child.ref_id,l.root_ref,l.depth+1 FROM lineage l
|
|
29
|
+
JOIN admitted parent ON parent.ref_id=l.ref_id
|
|
30
|
+
JOIN admitted child ON child.revision_of=parent.id AND child.repo IS parent.repo
|
|
31
|
+
JOIN artifact brief ON brief.id=child.revision_brief_artifact AND brief.kind='revision-brief'
|
|
32
|
+
JOIN run source ON source.id=brief.run AND source.task_ref=parent.ref_id WHERE l.depth<63
|
|
33
|
+
), questions AS MATERIALIZED (
|
|
34
|
+
SELECT r.task_ref,MAX(d.id) decision_id FROM decision d INDEXED BY work_open_decision
|
|
35
|
+
JOIN run r ON r.id=d.run JOIN admitted a ON a.ref_id=r.task_ref
|
|
36
|
+
WHERE d.state<>'answered' AND d.answered_at IS NULL GROUP BY r.task_ref
|
|
37
|
+
), custody AS MATERIALIZED (
|
|
38
|
+
SELECT r.task_ref FROM held_session h JOIN run r ON r.id=h.run JOIN admitted a ON a.ref_id=r.task_ref WHERE h.ended_at IS NULL
|
|
39
|
+
UNION
|
|
40
|
+
SELECT r.task_ref FROM run r INDEXED BY work_spawned_run JOIN admitted a ON a.ref_id=r.task_ref
|
|
41
|
+
WHERE r.provider_started_at IS NOT NULL AND NOT EXISTS(SELECT 1 FROM run_process p WHERE p.run=r.id)
|
|
42
|
+
UNION
|
|
43
|
+
SELECT r.task_ref FROM run_process p INDEXED BY work_unsettled_custody JOIN run r ON r.id=p.run JOIN admitted a ON a.ref_id=r.task_ref
|
|
44
|
+
WHERE p.exited_at IS NULL AND p.container_empty_at IS NULL
|
|
45
|
+
), members AS MATERIALIZED (
|
|
46
|
+
SELECT a.*,COALESCE(l.root_ref,a.ref_id) root_ref,l.ref_id IS NULL broken,
|
|
47
|
+
(SELECT lease_id FROM claim WHERE task_ref=a.ref_id AND released_at IS NULL AND expires_at>$now
|
|
48
|
+
AND lease_generation=(SELECT MAX(lease_generation) FROM claim WHERE task_ref=a.ref_id)) live_lease,
|
|
49
|
+
(SELECT id FROM run WHERE task_ref=a.ref_id AND outcome IS NULL ORDER BY id DESC LIMIT 1) unfinished,
|
|
50
|
+
CASE WHEN a.state='done' THEN (SELECT id FROM run WHERE task_ref=a.ref_id AND finished_at IS NOT NULL AND role IN ('builder','scout') ORDER BY id DESC LIMIT 1) END result_id,
|
|
51
|
+
(SELECT h.id FROM hold h WHERE h.task_ref=a.ref_id AND (h.until IS NULL OR h.until>$now) ORDER BY h.held_at,h.id LIMIT 1) hold_id,
|
|
52
|
+
q.decision_id,cu.task_ref IS NOT NULL custody_unresolved
|
|
53
|
+
FROM admitted a LEFT JOIN lineage l ON l.ref_id=a.ref_id
|
|
54
|
+
LEFT JOIN questions q ON q.task_ref=a.ref_id LEFT JOIN custody cu ON cu.task_ref=a.ref_id
|
|
55
|
+
), family_heads AS MATERIALIZED (
|
|
56
|
+
SELECT root_ref,COUNT(*) version_count,MAX(updated_at) family_updated,
|
|
57
|
+
CAST(substr(MAX((CASE WHEN ref_id=root_ref THEN '0' ELSE '1' END)||created_at||printf('%020d',ref_id)),-20) AS INTEGER) current_ref,
|
|
58
|
+
SUM(state IN ('queued','running') OR live_lease IS NOT NULL OR unfinished IS NOT NULL OR custody_unresolved) active_count,
|
|
59
|
+
MIN(CASE WHEN state IN ('queued','running') OR live_lease IS NOT NULL OR unfinished IS NOT NULL OR custody_unresolved THEN ref_id END) first_active,
|
|
60
|
+
MAX(CASE WHEN state IN ('queued','running') OR live_lease IS NOT NULL OR unfinished IS NOT NULL OR custody_unresolved THEN ref_id END) last_active,
|
|
61
|
+
MAX(live_lease IS NOT NULL) family_running,MIN(decision_id) question_id
|
|
62
|
+
FROM members GROUP BY root_ref
|
|
63
|
+
), ordered AS MATERIALIZED (
|
|
64
|
+
SELECT m.*,CASE WHEN m.ref_id=f.current_ref THEN 1 ELSE 2 END version_rank
|
|
65
|
+
FROM members m JOIN family_heads f USING(root_ref)
|
|
66
|
+
), families AS MATERIALIZED (
|
|
67
|
+
SELECT f.root_ref,f.version_count,f.family_updated,f.family_running,
|
|
68
|
+
f.active_count-(c.state IN ('queued','running') OR c.live_lease IS NOT NULL OR c.unfinished IS NOT NULL OR c.custody_unresolved) earlier_active,
|
|
69
|
+
earlier.id earlier_id,COALESCE(c.decision_id,f.question_id) question_id
|
|
70
|
+
FROM family_heads f JOIN members c ON c.ref_id=f.current_ref
|
|
71
|
+
LEFT JOIN admitted earlier ON earlier.ref_id=CASE WHEN f.first_active=f.current_ref THEN f.last_active ELSE f.first_active END
|
|
72
|
+
), workers AS MATERIALIZED (
|
|
73
|
+
SELECT r.name,r.capacity,r.heartbeat_at,j.value repo,
|
|
74
|
+
(SELECT COUNT(*) FROM claim c WHERE c.runner=r.name AND c.released_at IS NULL AND c.expires_at>$now
|
|
75
|
+
AND c.lease_generation=(SELECT MAX(newest.lease_generation) FROM claim newest WHERE newest.task_ref=c.task_ref)
|
|
76
|
+
AND c.lease_id NOT IN (SELECT lease_id FROM held_session WHERE ended_at IS NULL)) occupied
|
|
77
|
+
FROM runner r,json_each(CASE WHEN json_valid(r.repos) THEN r.repos ELSE '[]' END) j WHERE r.retired_at IS NULL
|
|
78
|
+
), facts AS MATERIALIZED (
|
|
79
|
+
SELECT c.*,f.version_count,f.family_updated,f.earlier_active,f.earlier_id,f.family_running,f.question_id,
|
|
80
|
+
root.id root_id,root.title root_title,
|
|
81
|
+
result.role result_role,result.outcome result_outcome,result.head_revision,result.scope_digest,result.finished_at,
|
|
82
|
+
(SELECT id FROM run WHERE task_ref=c.ref_id AND lease_id=c.live_lease AND outcome IS NULL ORDER BY id DESC LIMIT 1) live_run,
|
|
83
|
+
h.owner_kind hold_kind,h.reason hold_reason,h.until hold_until,
|
|
84
|
+
sc.task_id scope_id,sc.digest,sc.approved_at,sc.proposed_at,sc.profile_state,
|
|
85
|
+
(sc.approved_at IS NOT NULL AND sc.approved_by IS NOT NULL AND sc.approved_digest=sc.digest) approved,
|
|
86
|
+
(sc.approval_basis IS NOT 'mode' OR EXISTS(SELECT 1 FROM operating_mode om JOIN approver signer ON signer.name=om.signed_by
|
|
87
|
+
WHERE om.repo=c.repo AND om.digest=sc.mode_digest AND om.revoked_at IS NULL AND om.absolute_expiry>$now
|
|
88
|
+
AND signer.role='approver' AND signer.revoked_at IS NULL)) dispatch_approval,
|
|
89
|
+
CASE WHEN sc.task_id IS NULL THEN 0 ELSE so_work_scope_valid(json_object(
|
|
90
|
+
'touches',sc.touches,'acceptance_json',sc.acceptance_json,'budget_microusd',sc.budget_microusd,
|
|
91
|
+
'goal',CASE WHEN typeof(sc.goal)='text' THEN '' ELSE sc.goal END,
|
|
92
|
+
'out_of_scope',CASE WHEN typeof(sc.out_of_scope)='text' THEN '' ELSE sc.out_of_scope END,
|
|
93
|
+
'quality_mode',sc.quality_mode,'risk_level',sc.risk_level,'approval_kind',sc.approval_kind,
|
|
94
|
+
'profile_state',sc.profile_state,'digest_version',sc.digest_version,'proposed_via',sc.proposed_via,'route_era',sc.route_era,
|
|
95
|
+
'digest',sc.digest,'proposed_at',sc.proposed_at,'approved_at',sc.approved_at,'approved_by',sc.approved_by,'approved_digest',sc.approved_digest,
|
|
96
|
+
'profile_json',CASE WHEN typeof(sc.profile_json)='text' THEN '' ELSE sc.profile_json END,
|
|
97
|
+
'approved_profile_json',CASE WHEN typeof(sc.approved_profile_json)='text' THEN '' ELSE sc.approved_profile_json END,
|
|
98
|
+
'proposed_chain_json',CASE WHEN typeof(sc.proposed_chain_json)='text' THEN '' ELSE sc.proposed_chain_json END,
|
|
99
|
+
'approved_chain_json',CASE WHEN typeof(sc.approved_chain_json)='text' THEN '' ELSE sc.approved_chain_json END,
|
|
100
|
+
'proposed_route_json',CASE WHEN typeof(sc.proposed_route_json)='text' THEN '' ELSE sc.proposed_route_json END,
|
|
101
|
+
'approved_route_json',CASE WHEN typeof(sc.approved_route_json)='text' THEN '' ELSE sc.approved_route_json END,
|
|
102
|
+
'unresolved_reason',CASE WHEN typeof(sc.unresolved_reason)='text' THEN '' ELSE sc.unresolved_reason END)) END scope_valid,
|
|
103
|
+
(SELECT CASE WHEN EXISTS(SELECT 1 FROM admitted visible WHERE visible.id=blocker.id) THEN blocker.id END FROM task_edge e JOIN task blocker ON blocker.id=e.blocker WHERE e.blocked=c.id AND blocker.state<>'done'
|
|
104
|
+
ORDER BY (blocker.state IN ('failed','cancelled')) DESC,blocker.id LIMIT 1) dependency_id,
|
|
105
|
+
(SELECT blocker.state FROM task_edge e JOIN task blocker ON blocker.id=e.blocker WHERE e.blocked=c.id AND blocker.state<>'done'
|
|
106
|
+
ORDER BY (blocker.state IN ('failed','cancelled')) DESC,blocker.id LIMIT 1) dependency_state,
|
|
107
|
+
(SELECT COUNT(*) FROM workers w WHERE w.repo=c.repo AND (c.assigned_runner IS NULL OR w.name=c.assigned_runner)) worker_count,
|
|
108
|
+
(SELECT COUNT(*) FROM workers w WHERE w.repo=c.repo AND (c.assigned_runner IS NULL OR w.name=c.assigned_runner) AND w.heartbeat_at>$alive) online_count,
|
|
109
|
+
(SELECT COUNT(*) FROM workers w WHERE w.repo=c.repo AND (c.assigned_runner IS NULL OR w.name=c.assigned_runner) AND w.heartbeat_at>$alive AND w.occupied<w.capacity) available_count,
|
|
110
|
+
CASE WHEN NOT json_valid(c.capability_requirements) THEN 1 ELSE EXISTS(
|
|
111
|
+
SELECT 1 FROM json_each(c.capability_requirements) req WHERE req.type<>'text' OR instr(req.value,':')<2
|
|
112
|
+
OR NOT EXISTS(SELECT 1 FROM capability cap WHERE cap.repo=c.repo AND cap.kind=substr(req.value,1,instr(req.value,':')-1)
|
|
113
|
+
AND cap.name=substr(req.value,instr(req.value,':')+1) AND cap.status='verified' AND (cap.expires_at IS NULL OR cap.expires_at>$now))) END capability_gap,
|
|
114
|
+
(SELECT run FROM run_stop WHERE task_ref=c.ref_id AND resumed_at IS NULL ORDER BY requested_at DESC LIMIT 1) stop_run,
|
|
115
|
+
(SELECT settled_at FROM run_stop WHERE task_ref=c.ref_id AND resumed_at IS NULL ORDER BY requested_at DESC LIMIT 1) stop_settled,
|
|
116
|
+
COALESCE((SELECT substr(actor,13) FROM action_ledger WHERE task_id=root.id AND action='assignment claimed' AND source='work' ORDER BY id DESC LIMIT 1),root.coordinator_cid) owner_id,
|
|
117
|
+
pub.pr_url publication_url
|
|
118
|
+
FROM ordered c JOIN families f USING(root_ref) JOIN admitted root ON root.ref_id=c.root_ref
|
|
119
|
+
LEFT JOIN run result INDEXED BY work_result ON result.task_ref=c.ref_id AND result.id=c.result_id
|
|
120
|
+
AND result.finished_at IS NOT NULL AND result.role IN ('builder','scout') LEFT JOIN hold h ON h.id=c.hold_id
|
|
121
|
+
LEFT JOIN task_scope sc ON sc.task_id=c.id LEFT JOIN publication pub ON pub.run=c.result_id
|
|
122
|
+
WHERE c.version_rank=1
|
|
123
|
+
), ready AS MATERIALIZED (
|
|
124
|
+
SELECT f.*,state='done' AND broken=0 AND earlier_active=0 AND unfinished IS NULL AND live_lease IS NULL
|
|
125
|
+
AND question_id IS NULL AND hold_id IS NULL AND stop_run IS NULL AND custody_unresolved=0 AND scope_valid AND approved
|
|
126
|
+
AND digest=scope_digest AND ((result_role='scout' AND result_outcome='built') OR
|
|
127
|
+
(result_role='builder' AND result_outcome IN ('built','no-change') AND length(head_revision)=40 AND head_revision NOT GLOB '*[^a-f0-9]*')) ready
|
|
128
|
+
FROM facts f
|
|
129
|
+
), completion_families AS MATERIALIZED (
|
|
130
|
+
SELECT root_ref FROM ready f WHERE f.ready AND EXISTS(SELECT 1 FROM action_ledger a
|
|
131
|
+
WHERE a.task_id=f.root_id AND a.run_id=f.result_id AND a.action='assignment handoff checked' AND a.source='work')
|
|
132
|
+
), completion_metadata AS MATERIALIZED (
|
|
133
|
+
SELECT m.root_ref,MAX((SELECT MAX(a.id) FROM action_ledger a WHERE a.task_id=m.id
|
|
134
|
+
AND a.action IN ('task state changed','scope approved','task placed','run started','run finished'))) changed_id,
|
|
135
|
+
MAX((SELECT MAX(ar.created_at) FROM run r JOIN artifact ar ON ar.run=r.id WHERE r.task_ref=m.ref_id)) artifact_at
|
|
136
|
+
FROM completion_families f JOIN ordered m ON m.root_ref=f.root_ref GROUP BY m.root_ref
|
|
137
|
+
), checked AS MATERIALIZED (
|
|
138
|
+
SELECT f.*,(SELECT a.id FROM action_ledger a WHERE f.ready AND a.task_id=f.root_id AND a.run_id=f.result_id
|
|
139
|
+
AND a.action='assignment handoff checked' AND a.source='work' AND a.repo IS f.repo
|
|
140
|
+
AND length(a.outcome)=64 AND a.outcome NOT GLOB '*[^a-f0-9]*'
|
|
141
|
+
AND a.at>=f.family_updated AND a.at>=f.finished_at AND a.at>=f.approved_at AND a.at>=f.proposed_at
|
|
142
|
+
AND (a.actor GLOB 'operator:?*' OR a.actor GLOB 'coordinator:?*' OR a.actor GLOB 'lead:?*')
|
|
143
|
+
AND (cm.changed_id IS NULL OR a.id>=cm.changed_id) AND (cm.artifact_at IS NULL OR a.at>=cm.artifact_at)
|
|
144
|
+
AND NOT EXISTS(SELECT 1 FROM proof_verdict p WHERE p.run=f.result_id AND p.decided_at>a.at)
|
|
145
|
+
AND NOT EXISTS(SELECT 1 FROM proof_acceptance p WHERE p.run=f.result_id AND p.accepted_at>a.at)
|
|
146
|
+
ORDER BY a.id DESC LIMIT 1) checked_id
|
|
147
|
+
FROM ready f LEFT JOIN completion_metadata cm ON cm.root_ref=f.root_ref
|
|
148
|
+
), classified AS MATERIALIZED (
|
|
149
|
+
SELECT f.*,CASE
|
|
150
|
+
WHEN broken THEN 'history-problem'
|
|
151
|
+
WHEN state='cancelled' THEN 'cancelled'
|
|
152
|
+
WHEN earlier_active>0 AND state='done' THEN 'earlier-active'
|
|
153
|
+
WHEN stop_run IS NOT NULL THEN CASE WHEN stop_settled IS NULL THEN 'stopping' ELSE 'stopped' END
|
|
154
|
+
WHEN ready THEN CASE WHEN checked_id IS NULL THEN 'ready-to-check' ELSE 'complete' END
|
|
155
|
+
WHEN state='done' AND question_id IS NOT NULL AND hold_id IS NULL THEN 'waiting-decision'
|
|
156
|
+
WHEN state='done' THEN 'result-needs-attention'
|
|
157
|
+
WHEN custody_unresolved AND live_lease IS NULL THEN 'process-needs-attention'
|
|
158
|
+
WHEN state='failed' THEN 'failed'
|
|
159
|
+
WHEN live_lease IS NOT NULL THEN CASE WHEN question_id IS NOT NULL THEN 'waiting-decision' ELSE 'running' END
|
|
160
|
+
WHEN state='running' OR unfinished IS NOT NULL THEN 'vanished-run'
|
|
161
|
+
WHEN EXISTS(SELECT 1 FROM sqlite_master WHERE type='trigger' AND name GLOB 'so_desktop_update_*') THEN 'updating'
|
|
162
|
+
WHEN hold_kind='backoff' THEN 'retry-scheduled'
|
|
163
|
+
WHEN hold_kind='decision' THEN 'waiting-decision'
|
|
164
|
+
WHEN hold_kind='incident' THEN 'waiting-incident'
|
|
165
|
+
WHEN hold_kind='stop' THEN 'stopped'
|
|
166
|
+
WHEN hold_id IS NOT NULL THEN 'held'
|
|
167
|
+
WHEN dependency_state IN ('failed','cancelled') THEN 'terminal-dependency'
|
|
168
|
+
WHEN dependency_state IS NOT NULL THEN 'waiting-dependency'
|
|
169
|
+
WHEN repo IS NULL THEN 'needs-project'
|
|
170
|
+
WHEN plan IS NOT 'requested' AND scope_id IS NULL THEN 'needs-scope'
|
|
171
|
+
WHEN scope_id IS NOT NULL AND NOT scope_valid THEN 'invalid-scope'
|
|
172
|
+
WHEN (plan IS NOT 'requested' OR COALESCE(approved AND dispatch_approval,0)) AND profile_state='unresolved' THEN 'needs-agent-profile'
|
|
173
|
+
WHEN (plan IS NOT 'requested' OR COALESCE(approved AND dispatch_approval,0)) AND (NOT approved OR NOT dispatch_approval) THEN 'needs-approval'
|
|
174
|
+
WHEN capability_gap THEN 'missing-requirement'
|
|
175
|
+
WHEN question_id IS NOT NULL THEN 'waiting-decision'
|
|
176
|
+
WHEN worker_count=0 THEN 'no-worker-registered'
|
|
177
|
+
WHEN online_count=0 THEN 'no-worker-online'
|
|
178
|
+
WHEN available_count=0 THEN 'worker-at-capacity'
|
|
179
|
+
WHEN (plan='requested' OR park_rate>0) AND (SELECT COUNT(*) FROM decision WHERE state<>'answered' AND answered_at IS NULL)>=5 THEN 'decision-queue'
|
|
180
|
+
WHEN plan='requested' AND NOT COALESCE(approved AND dispatch_approval,0) THEN 'planning-ready'
|
|
181
|
+
WHEN deliverable='report' THEN 'scouting-ready'
|
|
182
|
+
ELSE 'queued' END code
|
|
183
|
+
FROM checked f
|
|
184
|
+
), ranked AS MATERIALIZED (
|
|
185
|
+
SELECT c.*,code NOT IN ('cancelled','complete','running','updating','retry-scheduled','waiting-dependency','worker-at-capacity','planning-ready','scouting-ready','queued') needs,
|
|
186
|
+
CASE WHEN code='complete' THEN 3 WHEN code='cancelled' THEN 4 WHEN code='running' THEN 1
|
|
187
|
+
WHEN code IN ('updating','retry-scheduled','waiting-dependency','worker-at-capacity','planning-ready','scouting-ready','queued') THEN 2 ELSE 0 END rank,
|
|
188
|
+
CASE WHEN code='complete' THEN completed.at ELSE family_updated END sort_at,
|
|
189
|
+
completed.actor checked_actor,completed.at checked_at,completed.outcome checked_digest
|
|
190
|
+
FROM classified c LEFT JOIN action_ledger completed ON completed.id=c.checked_id WHERE ($state IS NULL OR c.state=$state) AND ($leadId IS NULL OR EXISTS(SELECT 1 FROM team_task_owner own WHERE own.task_ref=c.root_ref AND own.lead=$leadId))
|
|
191
|
+
)`;
|
|
192
|
+
const registered = new WeakMap();
|
|
193
|
+
/** Connection-local pure parsing, with exactly the authoritative stored-scope
|
|
194
|
+
* validator. The callback cannot query, inspect files or grant authority. */
|
|
195
|
+
function registerValidators(store) {
|
|
196
|
+
const db = store.handle;
|
|
197
|
+
const cached = registered.get(db);
|
|
198
|
+
if (cached !== undefined)
|
|
199
|
+
return cached;
|
|
200
|
+
if (typeof db.function !== 'function')
|
|
201
|
+
throw new Error('Work summaries require the native SQLite scalar-function API.');
|
|
202
|
+
db.function('so_work_scope_valid', { deterministic: true }, value => {
|
|
203
|
+
try {
|
|
204
|
+
return scopeTermsProblem(JSON.parse(String(value))) === null ? 1 : 0;
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
return 0;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
db.function('so_work_operator_access', { deterministic: true }, (raw, repo) => {
|
|
211
|
+
const projects = readProjectAccess(raw);
|
|
212
|
+
return projects === null || (typeof repo === 'string' && projects.includes(repo)) ? 1 : 0;
|
|
213
|
+
});
|
|
214
|
+
// Same-schema non-migrating readers may predate these optional indexes.
|
|
215
|
+
// Discover once per connection; never initialize/migrate on a list read.
|
|
216
|
+
const available = new Set(db.prepare(`SELECT name FROM sqlite_master WHERE type='index'
|
|
217
|
+
AND name IN ('work_open_decision','work_spawned_run','work_unsettled_custody','work_result')`)
|
|
218
|
+
.all().map(row => String(row['name'])));
|
|
219
|
+
const projection = available.size === 4 ? PROJECTION : PROJECTION.replace(/ INDEXED BY (work_open_decision|work_spawned_run|work_unsettled_custody|work_result)\b/g, (hint, name) => available.has(name) ? hint : '');
|
|
220
|
+
registered.set(db, projection);
|
|
221
|
+
return projection;
|
|
222
|
+
}
|
|
223
|
+
function parameters(now, access, options) {
|
|
224
|
+
return { $now: now.toISOString(), $alive: new Date(now.getTime() - 180_000).toISOString(),
|
|
225
|
+
$all: access.repos === null ? 1 : 0, $repos: JSON.stringify(access.repos ?? []),
|
|
226
|
+
$unplaced: access.principal === 'operator' && access.includeUnplaced === true ? 1 : 0,
|
|
227
|
+
$projectSet: options.project != null ? 1 : 0, $project: options.project ?? null, $state: options.state ?? null, $leadId: options.leadId ?? null };
|
|
228
|
+
}
|
|
229
|
+
function counts(row) {
|
|
230
|
+
return { all: n(row, 'all_count'), 'needs-you': n(row, 'needs_count'), running: n(row, 'running_count'), completed: n(row, 'completed_count') };
|
|
231
|
+
}
|
|
232
|
+
const TOTALS = `COUNT(*) all_count,COALESCE(SUM(needs),0) needs_count,COALESCE(SUM(family_running),0) running_count,COALESCE(SUM(code='complete'),0) completed_count`;
|
|
233
|
+
export class WorkIndexCursorError extends Error {
|
|
234
|
+
constructor() { super('This work page cursor is invalid or belongs to a different view.'); this.name = 'WorkIndexCursorError'; }
|
|
235
|
+
}
|
|
236
|
+
function cursorScope(access, options, view) {
|
|
237
|
+
return createHash('sha256').update(JSON.stringify({ principal: access.principal,
|
|
238
|
+
repos: access.repos === null ? null : [...new Set(access.repos)].sort(),
|
|
239
|
+
unplaced: access.principal === 'operator' && access.includeUnplaced === true,
|
|
240
|
+
leadId: options.leadId ?? null, project: options.project ?? null, state: options.state ?? null, view })).digest('hex');
|
|
241
|
+
}
|
|
242
|
+
function readCursor(value, scope) {
|
|
243
|
+
if (value == null)
|
|
244
|
+
return null;
|
|
245
|
+
try {
|
|
246
|
+
if (value.length > 1024 || !/^[\w-]+$/.test(value))
|
|
247
|
+
throw Error();
|
|
248
|
+
const c = JSON.parse(Buffer.from(value, 'base64url').toString());
|
|
249
|
+
if (c.version !== 1 || c.scope !== scope || !Number.isSafeInteger(c.rank) || c.rank < 0 || c.rank > 4 ||
|
|
250
|
+
!Number.isSafeInteger(c.root) || c.root < 1 || typeof c.at !== 'string' || !/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(c.at))
|
|
251
|
+
throw Error();
|
|
252
|
+
return c;
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
throw new WorkIndexCursorError();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/** A single SQLite statement gives rows and exact totals one read snapshot.
|
|
259
|
+
* Completion is a recorded acknowledgment of the latest run/scope/family by
|
|
260
|
+
* its current lead or an admitted approver, invalidated by newer source facts.
|
|
261
|
+
* Its historical receipt hash also binds disk state, which is deliberately
|
|
262
|
+
* rechecked only on opening/acting. This query grants no completion authority.
|
|
263
|
+
* Project counters share the page's admitted project/state filter.
|
|
264
|
+
* Cursors bind the admitted scope, project and view, never broaden access. */
|
|
265
|
+
export function workIndexPage(store, now, access, options = {}) {
|
|
266
|
+
const projection = registerValidators(store);
|
|
267
|
+
const view = VIEWS.includes(options.view ?? 'all') ? options.view ?? 'all' : 'all';
|
|
268
|
+
const limit = Number.isFinite(options.limit) ? Math.max(1, Math.min(WORK_INDEX_MAX_LIMIT, Math.floor(options.limit))) : WORK_INDEX_PAGE_LIMIT;
|
|
269
|
+
const scope = cursorScope(access, options, view), cursor = readCursor(options.cursor, scope);
|
|
270
|
+
const filter = view === 'needs-you' ? 'needs=1' : view === 'running' ? 'family_running=1' : view === 'completed' ? "code='complete'" : '1';
|
|
271
|
+
const rows = store.handle.prepare(`${projection}, selected_page AS MATERIALIZED (
|
|
272
|
+
SELECT * FROM ranked WHERE ${filter} AND ($cursorRoot=0 OR rank>$cursorRank OR
|
|
273
|
+
(rank=$cursorRank AND (sort_at<$cursorAt OR (sort_at=$cursorAt AND root_ref<$cursorRoot))))
|
|
274
|
+
ORDER BY rank,sort_at DESC,root_ref DESC LIMIT $limit
|
|
275
|
+
), page AS (SELECT p.*,COALESCE(p.result_id,(SELECT id FROM run WHERE task_ref=p.ref_id AND finished_at IS NOT NULL AND role IN ('builder','scout') ORDER BY id DESC LIMIT 1)) page_result_id FROM selected_page p), totals AS (SELECT ${TOTALS} FROM ranked), project_totals AS (
|
|
276
|
+
SELECT repo,${TOTALS},SUM(state='queued' AND family_running=0) queued,
|
|
277
|
+
SUM(state='done' AND family_running=0 AND updated_at>=$recent) done_recently FROM ranked GROUP BY repo
|
|
278
|
+
)
|
|
279
|
+
SELECT 0 record_kind,totals.*,(SELECT json_group_array(json_object('repo',repo,'all_count',all_count,'needs_count',needs_count,
|
|
280
|
+
'running_count',running_count,'completed_count',completed_count,'queued',queued,'done_recently',done_recently)) FROM project_totals) row_json FROM totals
|
|
281
|
+
UNION ALL SELECT 1,0,0,0,0,json_object('root_ref',root_ref,'root_id',root_id,'id',id,'root_title',root_title,'repo',repo,
|
|
282
|
+
'state',state,'created_at',created_at,'family_updated',family_updated,'version_count',version_count,'earlier_active',earlier_active,
|
|
283
|
+
'earlier_id',earlier_id,'broken',broken,'live_run',live_run,'result_id',page_result_id,'result_outcome',(SELECT outcome FROM run WHERE id=page_result_id),
|
|
284
|
+
'publication_url',(SELECT pr_url FROM publication WHERE run=page_result_id),'code',code,'needs',needs,'family_running',family_running,'rank',rank,'sort_at',sort_at,
|
|
285
|
+
'checked_actor',checked_actor,'checked_at',checked_at,'checked_digest',checked_digest,'question_id',question_id,
|
|
286
|
+
'dependency_id',dependency_id,'dependency_state',dependency_state,'custody_unresolved',custody_unresolved,'hold_kind',hold_kind,'hold_reason',substr(hold_reason,1,300),'stop_run',stop_run,'unfinished',unfinished,
|
|
287
|
+
'question_run',(SELECT run FROM decision WHERE id=page.question_id),
|
|
288
|
+
'question_task',(SELECT r.external_id FROM decision d JOIN run ON run.id=d.run JOIN task_ref r ON r.id=run.task_ref WHERE d.id=page.question_id)) FROM page`)
|
|
289
|
+
.all({ ...parameters(now, access, options), $cursorRoot: cursor?.root ?? 0, $cursorRank: cursor?.rank ?? 0, $cursorAt: cursor?.at ?? '', $limit: limit + 1, $recent: new Date(now.getTime() - 86_400_000).toISOString() });
|
|
290
|
+
const selected = rows.slice(1).map(row => JSON.parse(String(row['row_json'])));
|
|
291
|
+
const page = selected.slice(0, limit), last = page.at(-1);
|
|
292
|
+
const nextCursor = selected.length > limit && last !== undefined ? Buffer.from(JSON.stringify({ version: 1, scope,
|
|
293
|
+
rank: n(last, 'rank'), at: s(last, 'sort_at'), root: n(last, 'root_ref') })).toString('base64url') : null;
|
|
294
|
+
const projects = JSON.parse(String(rows[0]?.['row_json'] ?? '[]')).map(row => ({ repo: s(row, 'repo'), totals: counts(row), queued: n(row, 'queued'), doneRecently: n(row, 'done_recently') }));
|
|
295
|
+
return { items: page.map(row => itemOf(row, access.principal)), projects, totals: rows[0] === undefined ? { ...EMPTY } : counts(rows[0]), nextCursor, limit, view };
|
|
296
|
+
}
|
|
297
|
+
export function workCountsByProject(store, now, access) {
|
|
298
|
+
const projection = registerValidators(store);
|
|
299
|
+
return store.handle.prepare(`${projection} SELECT repo,${TOTALS},SUM(state='queued' AND family_running=0) queued,
|
|
300
|
+
SUM(state='done' AND family_running=0 AND updated_at>=$recent) done_recently FROM ranked GROUP BY repo ORDER BY repo`)
|
|
301
|
+
.all({ ...parameters(now, access, {}), $recent: new Date(now.getTime() - 86_400_000).toISOString() })
|
|
302
|
+
.map(row => ({ repo: s(row, 'repo'), totals: counts(row), queued: n(row, 'queued'), doneRecently: n(row, 'done_recently') }));
|
|
303
|
+
}
|
|
304
|
+
/** Labels stay navigation, never an authorization to mutate. Full task
|
|
305
|
+
* opening re-proves process custody, receipt bytes and approval terms. */
|
|
306
|
+
function itemOf(row, principal) {
|
|
307
|
+
const code = String(row['code']), id = String(row['id']);
|
|
308
|
+
const need = n(row, 'needs') === 1, running = n(row, 'family_running') === 1;
|
|
309
|
+
const assignmentState = code === 'complete' ? 'complete' : code === 'ready-to-check' ? 'ready-to-check'
|
|
310
|
+
: code === 'cancelled' ? 'cancelled' : need ? 'needs-decision' : 'working';
|
|
311
|
+
const words = {
|
|
312
|
+
'history-problem': ['Needs your decision', FAMILY_PROBLEM, 'inspect-task', 'Review task history'],
|
|
313
|
+
'earlier-active': ['Needs your decision', 'Earlier work is still active. Resolve it before completing this assignment.', 'inspect-task', 'Review active work'],
|
|
314
|
+
'ready-to-check': ['Ready', 'The saved result is ready to review.', 'open-result', 'Open result'],
|
|
315
|
+
complete: ['Complete', 'Completion is recorded for this result. Open it to inspect the saved evidence.', 'open-result', 'Open result'],
|
|
316
|
+
cancelled: ['Cancelled', 'This assignment was cancelled.', 'inspect-task', 'View assignment'],
|
|
317
|
+
running: ['Running now', 'A worker owns a current live claim.', null, ''],
|
|
318
|
+
'waiting-decision': ['Needs your decision', 'An unanswered question is waiting.', n(row, 'question_id') ? 'answer-decision' : 'inspect-decisions', 'Answer question'],
|
|
319
|
+
'decision-queue': ['Needs your decision', 'The decision queue is full.', 'inspect-decisions', 'Review open questions'],
|
|
320
|
+
'result-needs-attention': ['Needs your decision', 'Inspect the saved result and resolve its remaining execution or scope issue.', 'inspect-run', 'Inspect run'],
|
|
321
|
+
'process-needs-attention': ['Needs your decision', 'A process exit is not recorded. Open the attempt to check whether its work has stopped.', 'inspect-run', 'Inspect run'],
|
|
322
|
+
failed: ['Needs your decision', 'The last attempt stopped; review its incident before retrying.', 'retry-task', 'Review and retry'],
|
|
323
|
+
'vanished-run': ['Needs your decision', 'An unfinished attempt has no current live claim.', 'reconcile-run', 'Check the unfinished attempt'],
|
|
324
|
+
stopping: ['Needs your decision', 'The stop is waiting for recorded settlement.', 'inspect-stop', 'View stop details'],
|
|
325
|
+
stopped: ['Needs your decision', 'The stopped attempt is preserved.', 'resume-run', 'Review pause'],
|
|
326
|
+
held: ['Needs your decision', s(row, 'hold_reason') ?? 'This task is on hold.', s(row, 'hold_kind') === 'operator' ? 'unhold' : 'inspect-hold', 'Review hold'],
|
|
327
|
+
'waiting-incident': ['Needs your decision', 'An unresolved incident holds the next attempt.', 'retry-task', 'Review and retry'],
|
|
328
|
+
'terminal-dependency': ['Needs your decision', 'A required task did not finish.', 'repair-dependency', 'Review required task'],
|
|
329
|
+
'waiting-dependency': ['Waiting for another task', 'A required task must finish before this task can start.', null, ''],
|
|
330
|
+
'needs-project': ['Needs your decision', 'Choose a project for this task.', 'place-task', 'Choose a project'],
|
|
331
|
+
'needs-scope': ['Needs your decision', 'Define the task before a worker can start.', 'write-scope', 'Define the task'],
|
|
332
|
+
'invalid-scope': ['Needs your decision', 'The saved task scope cannot be read safely.', 'write-scope', 'Review scope'],
|
|
333
|
+
'needs-agent-profile': ['Needs your decision', 'Choose an available agent for this task.', 'select-agent', 'Choose an agent'],
|
|
334
|
+
'needs-approval': ['Needs your decision', 'Review the current plan before a worker can start.', 'approve-scope', 'Review plan'],
|
|
335
|
+
'missing-requirement': ['Needs your decision', 'A required capability is missing or expired.', 'repair-capability', 'Review missing requirement'],
|
|
336
|
+
'no-worker-registered': ['Needs your decision', 'No connected builder includes this project.', 'start-worker', 'Check connection'],
|
|
337
|
+
'no-worker-online': ['Needs your decision', 'The builder has stopped checking in.', 'start-worker', 'Check connection'],
|
|
338
|
+
'worker-at-capacity': ['Waiting for worker capacity', 'This task starts when an eligible worker has capacity.', null, ''],
|
|
339
|
+
'retry-scheduled': ['Retry scheduled', 'The attempt is backing off before retrying.', null, ''],
|
|
340
|
+
updating: ['Waiting for app update', 'New work resumes after the update.', null, ''],
|
|
341
|
+
'planning-ready': ['Planner ready', 'A connected worker can draft the plan.', null, ''],
|
|
342
|
+
'scouting-ready': ['Scout ready', 'A connected worker can produce the report.', null, ''],
|
|
343
|
+
queued: ['Ready to run', 'A connected worker can claim this task.', null, ''],
|
|
344
|
+
};
|
|
345
|
+
let [label, detail, actionCode, actionLabel] = words[code];
|
|
346
|
+
if (code === 'running' && n(row, 'version_count') > 1)
|
|
347
|
+
label = 'Revising';
|
|
348
|
+
if (code === 'terminal-dependency' && s(row, 'dependency_id') !== null)
|
|
349
|
+
detail = `${s(row, 'dependency_id')} ${s(row, 'dependency_state') === 'cancelled' ? 'was cancelled' : 'failed'} before it finished.`;
|
|
350
|
+
if (code === 'result-needs-attention' && n(row, 'custody_unresolved'))
|
|
351
|
+
detail = 'A process exit is not recorded. Open the result to check whether its work has stopped.';
|
|
352
|
+
if (code === 'result-needs-attention' && ['built', 'no-change'].includes(s(row, 'result_outcome') ?? '')) {
|
|
353
|
+
actionCode = 'open-result';
|
|
354
|
+
actionLabel = 'Open result';
|
|
355
|
+
}
|
|
356
|
+
if (actionCode === null) {
|
|
357
|
+
actionCode = code === 'running' ? 'inspect-run' : 'inspect-task';
|
|
358
|
+
actionLabel = code === 'running' ? 'Watch the build' : 'View task details';
|
|
359
|
+
}
|
|
360
|
+
const read = actionCode !== null && ['inspect-task', 'inspect-run', 'inspect-stop', 'inspect-decisions', 'open-result'].includes(actionCode);
|
|
361
|
+
const primaryAction = actionCode === null ? null : { code: actionCode, label: actionLabel,
|
|
362
|
+
target: { taskId: code === 'earlier-active' ? s(row, 'earlier_id') ?? id : actionCode === 'answer-decision' ? s(row, 'question_task') ?? id : id,
|
|
363
|
+
runId: actionCode === 'answer-decision' ? n(row, 'question_run') || null : actionCode === 'inspect-run' && code === 'running' ? n(row, 'live_run') || null : actionCode === 'open-result' || actionCode === 'inspect-run' ? n(row, 'result_id') || null
|
|
364
|
+
: actionCode === 'reconcile-run' ? n(row, 'unfinished') || null : ['resume-run', 'inspect-stop'].includes(actionCode) ? n(row, 'stop_run') || null : null,
|
|
365
|
+
decisionId: actionCode === 'answer-decision' ? n(row, 'question_id') || null : null },
|
|
366
|
+
access: read ? 'read' : principal === 'operator' ? 'operator-control' : ['answer-decision', 'write-scope', 'unhold'].includes(actionCode) ? 'proposal-only' : 'operator-handoff',
|
|
367
|
+
retry: actionCode === 'reconcile-run' ? 'reconcile-before-retry' : read ? 'read-again' : 'refresh-before-acting' };
|
|
368
|
+
const views = ['all'];
|
|
369
|
+
if (need)
|
|
370
|
+
views.push('needs-you');
|
|
371
|
+
if (running)
|
|
372
|
+
views.push('running');
|
|
373
|
+
if (code === 'complete')
|
|
374
|
+
views.push('completed');
|
|
375
|
+
return { rootId: String(row['root_id']), activeTaskId: id, title: String(row['root_title']), repo: s(row, 'repo'),
|
|
376
|
+
state: String(row['state']), assignmentState, createdAt: String(row['created_at']), updatedAt: String(row['sort_at']),
|
|
377
|
+
versionCount: n(row, 'version_count'), earlierActiveCount: n(row, 'earlier_active'), familyProblem: n(row, 'broken') ? FAMILY_PROBLEM : null,
|
|
378
|
+
liveRunId: n(row, 'live_run') || null, unfinishedRunId: n(row, 'unfinished') || null, resultRunId: n(row, 'result_id') || null, resultTaskId: n(row, 'result_id') ? id : null,
|
|
379
|
+
resultOutcome: s(row, 'result_outcome'), publicationUrl: s(row, 'publication_url'),
|
|
380
|
+
status: { token: `assignment-${assignmentState}`, label, detail, tone: code === 'complete' ? 'done' : code === 'ready-to-check' ? 'ready' : need ? 'attention' : running ? 'live' : 'muted',
|
|
381
|
+
action: primaryAction === null ? null : { label: actionLabel, kind: actionCode === 'open-result' ? 'open-result' : 'open-task' }, views, rank: n(row, 'rank') },
|
|
382
|
+
primaryAction, completion: code === 'complete' ? { actor: String(row['checked_actor']), at: String(row['checked_at']), digest: String(row['checked_digest']) } : null,
|
|
383
|
+
evidence: 'recorded' };
|
|
384
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Read-only work context shared by console, CLI, and agent adapters.
|
|
2
|
+
* State, decisions, approval, process custody and proof still belong to
|
|
3
|
+
* their existing owners. Action hints are navigation/proposal guidance,
|
|
4
|
+
* never credentials or permission to bypass an owning operation. */
|
|
5
|
+
import { type DispatchAction } from "./dispatch.js";
|
|
6
|
+
import type { Store } from "./store.js";
|
|
7
|
+
import { type DisplayStatus, type WorkFacts, type WorkStatus } from "./workspace-ui.js";
|
|
8
|
+
export type WorkPrincipal = "operator" | "coordinator";
|
|
9
|
+
export type WorkTarget = {
|
|
10
|
+
taskId: string;
|
|
11
|
+
runId: number | null;
|
|
12
|
+
decisionId: number | null;
|
|
13
|
+
};
|
|
14
|
+
export type WorkAction = {
|
|
15
|
+
code: DispatchAction | "inspect-task" | "inspect-run" | "inspect-stop" | "inspect-decisions" | "reconcile-run" | "open-pr";
|
|
16
|
+
label: string;
|
|
17
|
+
target: WorkTarget;
|
|
18
|
+
access: "read" | "operator-control" | "proposal-only" | "operator-handoff";
|
|
19
|
+
/** Never interpret a hint as permission to retry a mutation blindly. */
|
|
20
|
+
retry: "read-again" | "refresh-before-acting" | "reconcile-before-retry";
|
|
21
|
+
};
|
|
22
|
+
export type WorkSummary = {
|
|
23
|
+
taskId: string;
|
|
24
|
+
state: WorkFacts["state"];
|
|
25
|
+
resultRunId: number | null;
|
|
26
|
+
liveRunId: number | null;
|
|
27
|
+
status: WorkStatus;
|
|
28
|
+
primaryAction: WorkAction | null;
|
|
29
|
+
nextActions: WorkAction[];
|
|
30
|
+
diagnostics: NonNullable<WorkStatus["diagnostics"]>;
|
|
31
|
+
/** A stored verdict is not a new audit of files on disk. The console
|
|
32
|
+
* supplies its existing receipt projection when it has re-read them. */
|
|
33
|
+
evidence: "recorded" | "receipt-checked";
|
|
34
|
+
};
|
|
35
|
+
/** Call only after admitting the task's project. Keep the question's
|
|
36
|
+
* exact run and id; never substitute a family's newest attempt. Expiry
|
|
37
|
+
* is attention metadata in the decision owner, so overdue stays open.
|
|
38
|
+
* Finishing a result does not answer its questions: only the normal
|
|
39
|
+
* decision operation settles them, including on earlier family versions. */
|
|
40
|
+
export declare function openWorkDecisionOf(store: Store, taskRef: number, now: Date): Exclude<WorkFacts["openDecision"], undefined>;
|
|
41
|
+
/** One exact answer target across task and family projections. This is
|
|
42
|
+
* still only a proposal for a coordinator, never approval authority. */
|
|
43
|
+
export declare function workDecisionAction(taskId: string, decision: NonNullable<WorkFacts["openDecision"]>, principal: WorkPrincipal): WorkAction;
|
|
44
|
+
/** Pure counterpart for callers already holding the same facts. */
|
|
45
|
+
export declare function workSummaryOf(facts: WorkFacts, principal: WorkPrincipal, resultDisplay?: DisplayStatus): WorkSummary;
|
|
46
|
+
export type WorkSummaryAccess = {
|
|
47
|
+
principal: "operator";
|
|
48
|
+
repos: readonly string[] | null;
|
|
49
|
+
includeUnplaced?: boolean;
|
|
50
|
+
} | {
|
|
51
|
+
principal: "coordinator";
|
|
52
|
+
repos: readonly string[];
|
|
53
|
+
};
|
|
54
|
+
/** Admission precedes reading question/proof bodies. Missing and foreign
|
|
55
|
+
* tasks share the same result. The caller must authenticate/revalidate
|
|
56
|
+
* its principal; this allowlist is not a credential. */
|
|
57
|
+
export declare function taskWorkSummaryOf(store: Store, taskId: string, now: Date, access: WorkSummaryAccess): WorkSummary | null;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/** Read-only work context shared by console, CLI, and agent adapters.
|
|
2
|
+
* State, decisions, approval, process custody and proof still belong to
|
|
3
|
+
* their existing owners. Action hints are navigation/proposal guidance,
|
|
4
|
+
* never credentials or permission to bypass an owning operation. */
|
|
5
|
+
import { diagnoseTaskDispatch } from "./dispatch.js";
|
|
6
|
+
import { isAlive } from "./runner.js";
|
|
7
|
+
import { taskControlOf } from "./task-control.js";
|
|
8
|
+
import { reviewFactsOf, workStatusOf } from "./workspace-ui.js";
|
|
9
|
+
/** Call only after admitting the task's project. Keep the question's
|
|
10
|
+
* exact run and id; never substitute a family's newest attempt. Expiry
|
|
11
|
+
* is attention metadata in the decision owner, so overdue stays open.
|
|
12
|
+
* Finishing a result does not answer its questions: only the normal
|
|
13
|
+
* decision operation settles them, including on earlier family versions. */
|
|
14
|
+
export function openWorkDecisionOf(store, taskRef, now) {
|
|
15
|
+
const decision = store.decisionsForTask(taskRef).find(one => one.state !== "answered" && one.answeredAt === null);
|
|
16
|
+
return decision === undefined ? null : {
|
|
17
|
+
id: decision.id, runId: decision.run, question: decision.question,
|
|
18
|
+
overdue: decision.state === "expired" || (decision.deadline !== null && Date.parse(decision.deadline) <= now.getTime()),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** One exact answer target across task and family projections. This is
|
|
22
|
+
* still only a proposal for a coordinator, never approval authority. */
|
|
23
|
+
export function workDecisionAction(taskId, decision, principal) {
|
|
24
|
+
return { code: "answer-decision", label: "Answer question", target: { taskId, runId: decision.runId, decisionId: decision.id },
|
|
25
|
+
access: principal === "operator" ? "operator-control" : "proposal-only", retry: "refresh-before-acting" };
|
|
26
|
+
}
|
|
27
|
+
const PROPOSABLE = new Set(["answer-decision", "write-scope", "unhold"]);
|
|
28
|
+
const READ_ACTIONS = new Set(["open-result", "open-pr", "inspect-task", "inspect-run", "inspect-stop", "inspect-decisions"]);
|
|
29
|
+
/** Pure counterpart for callers already holding the same facts. */
|
|
30
|
+
export function workSummaryOf(facts, principal, resultDisplay) {
|
|
31
|
+
const status = workStatusOf(facts, resultDisplay);
|
|
32
|
+
const target = { taskId: facts.id, runId: null, decisionId: null };
|
|
33
|
+
const make = (code, label, exact = {}) => ({
|
|
34
|
+
code, label, target: { ...target, ...exact },
|
|
35
|
+
access: READ_ACTIONS.has(code) ? "read" : principal === "operator" ? "operator-control" : PROPOSABLE.has(code) ? "proposal-only" : "operator-handoff",
|
|
36
|
+
retry: code === "reconcile-run" ? "reconcile-before-retry" : READ_ACTIONS.has(code) ? "read-again" : "refresh-before-acting",
|
|
37
|
+
});
|
|
38
|
+
const question = (facts.state === "queued" || facts.state === "running" || facts.state === "done") ? facts.openDecision ?? null : null;
|
|
39
|
+
const questionAction = question === null ? null : workDecisionAction(facts.id, question, principal);
|
|
40
|
+
let primary = null;
|
|
41
|
+
if (status.action !== null) {
|
|
42
|
+
if (facts.control?.kind === "stopping")
|
|
43
|
+
primary = make("inspect-stop", status.action.label, { runId: facts.control.run });
|
|
44
|
+
else if (facts.control?.kind === "paused")
|
|
45
|
+
primary = make("resume-run", status.action.label, { runId: facts.control.run });
|
|
46
|
+
else if (status.token === "waiting-decision" && questionAction !== null)
|
|
47
|
+
primary = questionAction;
|
|
48
|
+
else if (facts.dispatch?.code === "vanished-run")
|
|
49
|
+
primary = make("reconcile-run", "Check the unfinished attempt", { runId: facts.unfinishedRunId ?? null });
|
|
50
|
+
else if (status.action.kind === "open-result" || status.action.kind === "open-review")
|
|
51
|
+
primary = make("open-result", status.action.label, { runId: facts.result?.runId ?? null });
|
|
52
|
+
else if (status.action.kind === "open-pr")
|
|
53
|
+
primary = make("open-pr", status.action.label, { runId: facts.result?.runId ?? null });
|
|
54
|
+
else if (status.action.kind === "open-run")
|
|
55
|
+
primary = make("inspect-run", status.action.label, { runId: facts.liveRunId ?? facts.result?.runId ?? null });
|
|
56
|
+
// A full decision queue can block a task that asked no question of
|
|
57
|
+
// its own. Do not invent a decision target on that task.
|
|
58
|
+
else if (facts.dispatch?.action === "answer-decision")
|
|
59
|
+
primary = make("inspect-decisions", "Review open questions");
|
|
60
|
+
else
|
|
61
|
+
primary = make(facts.dispatch?.action ?? "inspect-task", status.action.label);
|
|
62
|
+
}
|
|
63
|
+
const nextActions = primary === null ? [] : [primary];
|
|
64
|
+
if (questionAction !== null && primary?.code !== "answer-decision")
|
|
65
|
+
nextActions.push(questionAction);
|
|
66
|
+
const diagnostics = [...(status.diagnostics ?? [])];
|
|
67
|
+
if (facts.dispatch !== null && facts.dispatch.code !== status.token && !diagnostics.some(one => one.token === facts.dispatch?.code)) {
|
|
68
|
+
diagnostics.push({ token: facts.dispatch.code, label: facts.dispatch.summary, detail: facts.dispatch.detail, tone: "attention" });
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
taskId: facts.id, state: facts.state, resultRunId: facts.result?.runId ?? null, liveRunId: facts.liveRunId,
|
|
72
|
+
status, primaryAction: primary, nextActions, diagnostics, evidence: resultDisplay === undefined ? "recorded" : "receipt-checked",
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** Admission precedes reading question/proof bodies. Missing and foreign
|
|
76
|
+
* tasks share the same result. The caller must authenticate/revalidate
|
|
77
|
+
* its principal; this allowlist is not a credential. */
|
|
78
|
+
export function taskWorkSummaryOf(store, taskId, now, access) {
|
|
79
|
+
const ref = store.lookupRef(taskId);
|
|
80
|
+
if (ref === null || (ref.repo === null
|
|
81
|
+
? access.principal !== "operator" || access.includeUnplaced !== true
|
|
82
|
+
: access.repos !== null && !access.repos.includes(ref.repo)))
|
|
83
|
+
return null;
|
|
84
|
+
const task = store.getTask(taskId);
|
|
85
|
+
if (task === null)
|
|
86
|
+
return null;
|
|
87
|
+
const runs = store.runsFor(ref.id);
|
|
88
|
+
const result = runs.find(one => one.finishedAt !== null && (one.role === "builder" || one.role === "scout")) ?? null;
|
|
89
|
+
const proof = result === null ? null : store.proofVerdictFor(result.id);
|
|
90
|
+
const lease = store.currentLiveLease(ref.id, now);
|
|
91
|
+
const live = runs.find(one => one.outcome === null && lease !== null && one.leaseId === lease) ?? null;
|
|
92
|
+
const publication = result === null ? null : store.publicationForRun(result.id);
|
|
93
|
+
const facts = {
|
|
94
|
+
id: task.id, title: task.title, repo: ref.repo, state: task.state, updatedAt: task.updatedAt,
|
|
95
|
+
dispatch: diagnoseTaskDispatch(store, taskId, now), liveRunId: live?.id ?? null,
|
|
96
|
+
unfinishedRunId: runs.find(one => one.outcome === null && one.role !== "reviewer")?.id ?? null,
|
|
97
|
+
control: taskControlOf(store, ref.id, now), openDecision: openWorkDecisionOf(store, ref.id, now),
|
|
98
|
+
result: result === null ? null : {
|
|
99
|
+
runId: result.id, role: result.role, outcome: result.outcome,
|
|
100
|
+
verdict: proof?.verdict ?? null, reasons: proof?.reasons ?? [], accepted: store.proofAcceptance(result.id) !== null,
|
|
101
|
+
review: reviewFactsOf(store.reviewRetryStateOf(result.id), name => {
|
|
102
|
+
const runner = store.getRunner(name)?.runner;
|
|
103
|
+
return runner !== undefined && isAlive(runner, now);
|
|
104
|
+
}),
|
|
105
|
+
...(result.outcome !== "no-change" ? {} : { recordComplete: (() => {
|
|
106
|
+
const kinds = new Set(store.artifactsFor(result.id).map(one => one.kind));
|
|
107
|
+
return kinds.has("handoff") && kinds.has("terminal-diff");
|
|
108
|
+
})() }),
|
|
109
|
+
},
|
|
110
|
+
publication: publication === null ? null : {
|
|
111
|
+
state: publication.state, prNumber: publication.prNumber, prUrl: publication.prUrl,
|
|
112
|
+
remoteState: publication.remoteState, lastCheckState: publication.lastCheckState,
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
return workSummaryOf(facts, access.principal);
|
|
116
|
+
}
|