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,213 @@
|
|
|
1
|
+
/** Result-first review (workspace package 3, 2026-09-13): the pure parts
|
|
2
|
+
* of ONE result presentation shared by the task chat receipt, the run
|
|
3
|
+
* page, the review cockpit, and the chat's result detail.
|
|
4
|
+
*
|
|
5
|
+
* Nothing here reads a database or renders a full page. The server
|
|
6
|
+
* assembles the same verified records it already reads (handoff, proof,
|
|
7
|
+
* diff, matrix, publication, report) into `SharedResultFacts`; every
|
|
8
|
+
* surface prints those facts through `resultFactsAttributes`, so a test —
|
|
9
|
+
* or a person — can check that chat, run detail, and review agree on the
|
|
10
|
+
* run, its head, its checks, its caveats, and its publication.
|
|
11
|
+
*
|
|
12
|
+
* The presentation leads with the deliverable itself: validated
|
|
13
|
+
* screenshots for UI work, the escaped report for an investigation, a
|
|
14
|
+
* concise change summary for code. Missing, corrupt, or truncated
|
|
15
|
+
* evidence is named in `evidenceProblemsOf` and is never described as
|
|
16
|
+
* validated. Three local views — Summary, Changes, Checks — are anchor
|
|
17
|
+
* links (`?tab=`) the server honours, enhanced in the browser by
|
|
18
|
+
* `RESULT_REVIEW_SCRIPT`, which also keeps a bounded review draft, the
|
|
19
|
+
* selected tab, and the reading position in this tab's sessionStorage,
|
|
20
|
+
* keyed by the server-named account, the task, and the run. */
|
|
21
|
+
import { type ResultFacts, type PublicationFacts, type DisplayStatus } from "./workspace-ui.js";
|
|
22
|
+
/** Add re-read evidence health to the existing result/review projection.
|
|
23
|
+
* This is presentation only: the recorded verdict and acceptance stay intact. */
|
|
24
|
+
export declare function evidenceResultStatusOf(result: ResultFacts, publication: PublicationFacts, evidence: EvidenceHealth): DisplayStatus;
|
|
25
|
+
export declare function evidenceShortenedWords(evidence: EvidenceHealth): string;
|
|
26
|
+
export type ResultTab = "summary" | "changes" | "checks";
|
|
27
|
+
export declare const RESULT_TABS: readonly {
|
|
28
|
+
key: ResultTab;
|
|
29
|
+
label: string;
|
|
30
|
+
}[];
|
|
31
|
+
/** The requested local view; anything unknown reads as Summary. */
|
|
32
|
+
export declare function parseResultTab(raw: string | null | undefined): ResultTab;
|
|
33
|
+
/** What leads the Summary view — decided from the records present, never
|
|
34
|
+
* from the outcome word: a scout's report leads even when a diff exists;
|
|
35
|
+
* validated screenshots lead UI work; a sealed diff leads code; the
|
|
36
|
+
* handoff alone leads when nothing else was captured. */
|
|
37
|
+
export type ResultLead = "report" | "screenshots" | "changes" | "summary";
|
|
38
|
+
export declare function resultLeadOf(input: {
|
|
39
|
+
role: string;
|
|
40
|
+
report: boolean;
|
|
41
|
+
screenshots: number;
|
|
42
|
+
diff: boolean;
|
|
43
|
+
}): ResultLead;
|
|
44
|
+
/** One validated screenshot as the page will show it, or the reason it
|
|
45
|
+
* cannot be shown. `problem` is set when the stored bytes no longer verify
|
|
46
|
+
* against their record; such a shot is counted as unavailable and is
|
|
47
|
+
* never rendered as an image or described as validated. */
|
|
48
|
+
export type ResultScreenshot = {
|
|
49
|
+
path: string;
|
|
50
|
+
caption: string;
|
|
51
|
+
artifactId: number;
|
|
52
|
+
problem: string | null;
|
|
53
|
+
};
|
|
54
|
+
export type ResultEvidenceInput = {
|
|
55
|
+
/** The proof artifact exists but cannot be shown (corrupt, unparseable). */
|
|
56
|
+
proofProblem: string | null;
|
|
57
|
+
/** The sealed diff's health: absent, unverifiable, or fine. */
|
|
58
|
+
diff: {
|
|
59
|
+
problem: string;
|
|
60
|
+
} | {
|
|
61
|
+
truncated: boolean;
|
|
62
|
+
} | null;
|
|
63
|
+
stat: {
|
|
64
|
+
problem: string;
|
|
65
|
+
} | {
|
|
66
|
+
filesTruncated: boolean;
|
|
67
|
+
} | null;
|
|
68
|
+
/** The check log: absent, no longer verifying (`problem`), or stored
|
|
69
|
+
* whole or shortened. */
|
|
70
|
+
checkLog: {
|
|
71
|
+
problem: string;
|
|
72
|
+
} | {
|
|
73
|
+
truncated: boolean;
|
|
74
|
+
} | null;
|
|
75
|
+
screenshots: readonly ResultScreenshot[];
|
|
76
|
+
/** Screenshot paths the proof cites that no stored artifact answers. */
|
|
77
|
+
uncapturedScreenshots: readonly string[];
|
|
78
|
+
/** A scout's report record: absent, unverifiable, or fine (possibly
|
|
79
|
+
* shortened when it was stored). */
|
|
80
|
+
report: {
|
|
81
|
+
problem: string;
|
|
82
|
+
} | {
|
|
83
|
+
ok: true;
|
|
84
|
+
truncated?: boolean;
|
|
85
|
+
} | null;
|
|
86
|
+
/** Whether a report is owed (a scout's run) — absence is then a problem. */
|
|
87
|
+
reportExpected: boolean;
|
|
88
|
+
/** The handoff record: a no-change conclusion owes one. */
|
|
89
|
+
handoffPresent: boolean;
|
|
90
|
+
outcome: string | null;
|
|
91
|
+
};
|
|
92
|
+
/** What kind of evidence problem a record has (repair 2026-09-14):
|
|
93
|
+
* `damaged` — the stored bytes no longer verify, cannot be read, or the
|
|
94
|
+
* capture itself failed, so nothing can be shown for that record;
|
|
95
|
+
* `shortened` — the record was cut at its storage cap, so its download is
|
|
96
|
+
* the stored part only, never the full bytes; `missing` — a record the
|
|
97
|
+
* result owes was never stored. */
|
|
98
|
+
export type EvidenceProblemKind = "damaged" | "shortened" | "missing";
|
|
99
|
+
export type EvidenceProblem = {
|
|
100
|
+
kind: EvidenceProblemKind;
|
|
101
|
+
words: string;
|
|
102
|
+
};
|
|
103
|
+
/** Every evidence problem, classified, in a stable order. Empty means
|
|
104
|
+
* every record this result cites is present, whole, and verifies. */
|
|
105
|
+
export declare function evidenceProblemDetailsOf(input: ResultEvidenceInput): EvidenceProblem[];
|
|
106
|
+
/** Every evidence problem in plain words, in a stable order. */
|
|
107
|
+
export declare function evidenceProblemsOf(input: ResultEvidenceInput): string[];
|
|
108
|
+
/** The counts the shared status reads: how many records are damaged,
|
|
109
|
+
* shortened, or missing. A status is truthful only when it knows these. */
|
|
110
|
+
export type EvidenceHealth = {
|
|
111
|
+
damaged: number;
|
|
112
|
+
shortened: number;
|
|
113
|
+
missing: number;
|
|
114
|
+
};
|
|
115
|
+
export declare function evidenceHealthOf(problems: readonly EvidenceProblem[]): EvidenceHealth;
|
|
116
|
+
/** The facts every result surface must agree on. */
|
|
117
|
+
export type SharedResultFacts = {
|
|
118
|
+
runId: number;
|
|
119
|
+
/** The exact commits, from the sealed diff summary when it verifies,
|
|
120
|
+
* else from the run record — `headSource` says which. */
|
|
121
|
+
base: string | null;
|
|
122
|
+
head: string | null;
|
|
123
|
+
headSource: "sealed diff" | "run record" | null;
|
|
124
|
+
/** Signed criteria passed, from the machine's matrix; null = no rubric. */
|
|
125
|
+
checks: {
|
|
126
|
+
passed: number;
|
|
127
|
+
total: number;
|
|
128
|
+
} | null;
|
|
129
|
+
caveats: readonly string[];
|
|
130
|
+
evidenceProblems: readonly string[];
|
|
131
|
+
/** How many of the problems above are damaged, shortened, or missing
|
|
132
|
+
* records — what the shared status reads (repair 2026-09-14). */
|
|
133
|
+
evidenceHealth: EvidenceHealth;
|
|
134
|
+
/** The observed publication state, "none" when nothing was intended. */
|
|
135
|
+
publicationState: string;
|
|
136
|
+
publicationWords: string;
|
|
137
|
+
};
|
|
138
|
+
/** The `data-result-*` attributes every surface stamps on its result
|
|
139
|
+
* element. Values are short, escaped, and deterministic for one run, so
|
|
140
|
+
* two surfaces rendering the same result carry byte-identical attributes. */
|
|
141
|
+
/** The shared facts as the panel's data attributes, unescaped (the rebuilt
|
|
142
|
+
* result page sets them through React). */
|
|
143
|
+
export declare function resultFactsAttributeMap(facts: SharedResultFacts): Record<string, string>;
|
|
144
|
+
export declare function resultFactsAttributes(facts: SharedResultFacts): string;
|
|
145
|
+
/** The shared fact names, in the order `resultFactsAttributes` writes them. */
|
|
146
|
+
export declare const RESULT_FACT_KEYS: readonly ["run", "head", "base", "head-source", "checks", "caveats", "evidence", "publication"];
|
|
147
|
+
/** Parse the shared facts back — the test-side and proof-side reader.
|
|
148
|
+
* Only the shared keys are read; a panel's own presentation attributes
|
|
149
|
+
* (place, lead, task, user) are not facts and are left out. */
|
|
150
|
+
export declare function resultFactsFromHtml(html: string): Record<string, string>[];
|
|
151
|
+
/** Where a result form may send its reader back: the review cockpit's
|
|
152
|
+
* own deep link, the chat's result detail, or the run page. Anything else
|
|
153
|
+
* lands on the run page. Matched exactly — never a bare open redirect. */
|
|
154
|
+
export declare function resultReturnTarget(raw: string | null | undefined, runId: number): string;
|
|
155
|
+
/** A form's own request token, minted per render — the same shape the
|
|
156
|
+
* chat composer uses. A replayed submission carries the same token, so
|
|
157
|
+
* the server can recognise it and mint nothing twice. */
|
|
158
|
+
export declare const REQUEST_TOKEN: RegExp;
|
|
159
|
+
/** The dedupe key a review note is stored under when the form carried a
|
|
160
|
+
* request token: bound to the account and the token, never to the words,
|
|
161
|
+
* so the same person saying the same thing twice on purpose still lands. */
|
|
162
|
+
export declare function commentSourceKey(user: string, request: string | null | undefined): string | undefined;
|
|
163
|
+
/** The revision form's exact batch (repair 2026-09-14): the ids of the
|
|
164
|
+
* live notes the page DISPLAYED, oldest first, joined by commas, plus the
|
|
165
|
+
* source scope digest the page rendered against ("none" when the task has
|
|
166
|
+
* no scope). A seal binds to exactly these — never to "whatever is live
|
|
167
|
+
* when the POST arrives" — so a replayed or second-tab submission can
|
|
168
|
+
* only ever consume the notes its own reader saw. */
|
|
169
|
+
export declare function revisionBatchOf(comments: readonly {
|
|
170
|
+
id: number;
|
|
171
|
+
}[]): string;
|
|
172
|
+
/** User feedback requests work; a reviewer's observations only do so when
|
|
173
|
+
* they are problems. The original findings always remain on record. */
|
|
174
|
+
export declare function isRevisionFeedback(comment: {
|
|
175
|
+
reviewerRun: number | null;
|
|
176
|
+
severity: string | null;
|
|
177
|
+
}): boolean;
|
|
178
|
+
export declare const REVISION_BATCH_CAP = 500;
|
|
179
|
+
/** Parse a posted batch back into distinct positive ids, or null when the
|
|
180
|
+
* field is absent or malformed (an out-of-date form, a hand-built POST). */
|
|
181
|
+
export declare function parseRevisionBatch(raw: string | null | undefined): number[] | null;
|
|
182
|
+
/** The source binding the revision form carries: the scope digest the
|
|
183
|
+
* page was rendered against, or "none". */
|
|
184
|
+
export declare function revisionSourceOf(scopeDigest: string | null): string;
|
|
185
|
+
export declare const REVIEW_DRAFT_PREFIX = "standing-orders:review-draft:";
|
|
186
|
+
export declare const RESULT_SCROLL_PREFIX = "standing-orders:result-scroll:";
|
|
187
|
+
/** The in-page half of the result presentation. Everything it does is
|
|
188
|
+
* presentational or a bounded draft: no fetch, no endpoint, no submit.
|
|
189
|
+
*
|
|
190
|
+
* - Tabs: the anchor links switch the visible view in place and record
|
|
191
|
+
* `?tab=` with replaceState, so refresh and Back land on the same view
|
|
192
|
+
* the server would render for that URL.
|
|
193
|
+
* - Diff modes: View hides the line pins; Annotate shows them. A pin or a
|
|
194
|
+
* file button copies its target into the Request changes form, opens
|
|
195
|
+
* the pin disclosure, and focuses the note.
|
|
196
|
+
* - Review draft: the note, file, and line are kept in sessionStorage
|
|
197
|
+
* under the account, task, and run the form names, for at most a day,
|
|
198
|
+
* and restored on load. The draft clears only when the page carries the
|
|
199
|
+
* receipt for THIS draft's request token (`?noted=<token>`); a refused
|
|
200
|
+
* submission leaves it in place. Other accounts' drafts on this tab are
|
|
201
|
+
* dropped, never restored.
|
|
202
|
+
* - Request identity (repair 2026-09-14): the form's request token is
|
|
203
|
+
* bound to the exact note, file, and line last displayed, even when
|
|
204
|
+
* FormData is sent directly. An unchanged retry keeps the token, so the server
|
|
205
|
+
* records it once; editing any of the three after a submission mints a
|
|
206
|
+
* fresh token, so the edited words are a new note and can never be
|
|
207
|
+
* swallowed by the earlier one's receipt. A refusal that comes back with
|
|
208
|
+
* `?conflict=<token>` rotates that token too, keeping the words.
|
|
209
|
+
* - Reading position: the page's scroll offset is kept under the same
|
|
210
|
+
* account/task and the URL's own result and tab, and restored on load
|
|
211
|
+
* when the URL carries no hash, so Back to chat and refresh return the
|
|
212
|
+
* reader to where they were. */
|
|
213
|
+
export declare const RESULT_REVIEW_SCRIPT: string;
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/** Result-first review (workspace package 3, 2026-09-13): the pure parts
|
|
2
|
+
* of ONE result presentation shared by the task chat receipt, the run
|
|
3
|
+
* page, the review cockpit, and the chat's result detail.
|
|
4
|
+
*
|
|
5
|
+
* Nothing here reads a database or renders a full page. The server
|
|
6
|
+
* assembles the same verified records it already reads (handoff, proof,
|
|
7
|
+
* diff, matrix, publication, report) into `SharedResultFacts`; every
|
|
8
|
+
* surface prints those facts through `resultFactsAttributes`, so a test —
|
|
9
|
+
* or a person — can check that chat, run detail, and review agree on the
|
|
10
|
+
* run, its head, its checks, its caveats, and its publication.
|
|
11
|
+
*
|
|
12
|
+
* The presentation leads with the deliverable itself: validated
|
|
13
|
+
* screenshots for UI work, the escaped report for an investigation, a
|
|
14
|
+
* concise change summary for code. Missing, corrupt, or truncated
|
|
15
|
+
* evidence is named in `evidenceProblemsOf` and is never described as
|
|
16
|
+
* validated. Three local views — Summary, Changes, Checks — are anchor
|
|
17
|
+
* links (`?tab=`) the server honours, enhanced in the browser by
|
|
18
|
+
* `RESULT_REVIEW_SCRIPT`, which also keeps a bounded review draft, the
|
|
19
|
+
* selected tab, and the reading position in this tab's sessionStorage,
|
|
20
|
+
* keyed by the server-named account, the task, and the run. */
|
|
21
|
+
import { resultStatusOf } from "./workspace-ui.js";
|
|
22
|
+
/** Add re-read evidence health to the existing result/review projection.
|
|
23
|
+
* This is presentation only: the recorded verdict and acceptance stay intact. */
|
|
24
|
+
export function evidenceResultStatusOf(result, publication, evidence) {
|
|
25
|
+
const recorded = resultStatusOf({ ...result, review: null }, publication);
|
|
26
|
+
let stored = recorded;
|
|
27
|
+
if (!result.accepted && !["checks-failed", "evidence-mismatch"].includes(recorded.token) && (evidence.damaged > 0 || (result.role === "scout" && evidence.missing > 0))) {
|
|
28
|
+
stored = {
|
|
29
|
+
token: "evidence-damaged",
|
|
30
|
+
label: "Result saved, but some saved material is unavailable",
|
|
31
|
+
detail: `Some saved material is missing, damaged, or could not be read. The machine's verdict at completion is unchanged: ${result.verdict === "verified" ? "the approved check passed against it then" : recorded.label.toLowerCase()}.`,
|
|
32
|
+
tone: "problem",
|
|
33
|
+
action: { label: "See what is missing", kind: "open-result" },
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const shortened = evidenceShortenedWords(evidence);
|
|
37
|
+
if (shortened)
|
|
38
|
+
stored = { ...stored, detail: `${stored.detail} ${shortened}` };
|
|
39
|
+
return stored;
|
|
40
|
+
}
|
|
41
|
+
export function evidenceShortenedWords(evidence) {
|
|
42
|
+
const n = evidence.shortened;
|
|
43
|
+
return n === 0 ? "" : `${n} stored record${n === 1 ? " was" : "s were"} shortened at storage; ${n === 1 ? "its download holds" : "their downloads hold"} only the stored part.`;
|
|
44
|
+
}
|
|
45
|
+
export const RESULT_TABS = [
|
|
46
|
+
{ key: "summary", label: "Summary" },
|
|
47
|
+
{ key: "changes", label: "Changes" },
|
|
48
|
+
{ key: "checks", label: "Checks" },
|
|
49
|
+
];
|
|
50
|
+
/** The requested local view; anything unknown reads as Summary. */
|
|
51
|
+
export function parseResultTab(raw) {
|
|
52
|
+
return raw === "changes" || raw === "checks" ? raw : "summary";
|
|
53
|
+
}
|
|
54
|
+
export function resultLeadOf(input) {
|
|
55
|
+
if (input.role === "scout" || input.report)
|
|
56
|
+
return "report";
|
|
57
|
+
if (input.screenshots > 0)
|
|
58
|
+
return "screenshots";
|
|
59
|
+
if (input.diff)
|
|
60
|
+
return "changes";
|
|
61
|
+
return "summary";
|
|
62
|
+
}
|
|
63
|
+
/** Every evidence problem, classified, in a stable order. Empty means
|
|
64
|
+
* every record this result cites is present, whole, and verifies. */
|
|
65
|
+
export function evidenceProblemDetailsOf(input) {
|
|
66
|
+
const problems = [];
|
|
67
|
+
const damaged = (words) => problems.push({ kind: "damaged", words });
|
|
68
|
+
const shortened = (words) => problems.push({ kind: "shortened", words });
|
|
69
|
+
const missing = (words) => problems.push({ kind: "missing", words });
|
|
70
|
+
if (input.proofProblem !== null)
|
|
71
|
+
damaged(`The agent's proof cannot be shown: ${input.proofProblem}.`);
|
|
72
|
+
if (input.diff !== null && "problem" in input.diff)
|
|
73
|
+
damaged(`The sealed diff is unavailable: ${input.diff.problem}.`);
|
|
74
|
+
else if (input.diff !== null && input.diff.truncated)
|
|
75
|
+
shortened("The sealed diff was shortened when it was stored; its download holds only the stored part, not the full change.");
|
|
76
|
+
else if (input.diff === null && input.outcome === "no-change" && !input.reportExpected)
|
|
77
|
+
missing("No sealed diff was captured, so the no-change conclusion is not verified.");
|
|
78
|
+
if (input.stat !== null && "problem" in input.stat)
|
|
79
|
+
damaged(`The change summary is unavailable: ${input.stat.problem}.`);
|
|
80
|
+
else if (input.stat !== null && input.stat.filesTruncated)
|
|
81
|
+
shortened("The changed-file list was cut short; the counts are complete.");
|
|
82
|
+
if (input.checkLog !== null && "problem" in input.checkLog)
|
|
83
|
+
damaged(`The check log no longer verifies (${input.checkLog.problem}); its output is not shown.`);
|
|
84
|
+
else if (input.checkLog !== null && input.checkLog.truncated)
|
|
85
|
+
shortened("The check output was shortened when it was stored; its download holds only the stored part.");
|
|
86
|
+
for (const shot of input.screenshots) {
|
|
87
|
+
if (shot.problem !== null)
|
|
88
|
+
damaged(`Screenshot ${shot.path} no longer verifies (${shot.problem}) and is not shown.`);
|
|
89
|
+
}
|
|
90
|
+
for (const path of input.uncapturedScreenshots)
|
|
91
|
+
missing(`The proof cites screenshot ${path}, but no validated image was stored.`);
|
|
92
|
+
if (input.report !== null && "problem" in input.report)
|
|
93
|
+
damaged(`The report cannot be shown: ${input.report.problem}.`);
|
|
94
|
+
else if (input.report !== null && input.report.truncated === true)
|
|
95
|
+
shortened("The report was shortened when it was stored; its download holds only the stored part.");
|
|
96
|
+
else if (input.report === null && input.reportExpected)
|
|
97
|
+
missing("This investigation stored no report.");
|
|
98
|
+
if (!input.handoffPresent && input.outcome === "no-change" && !input.reportExpected)
|
|
99
|
+
missing("The no-change conclusion has no handoff record.");
|
|
100
|
+
return problems;
|
|
101
|
+
}
|
|
102
|
+
/** Every evidence problem in plain words, in a stable order. */
|
|
103
|
+
export function evidenceProblemsOf(input) {
|
|
104
|
+
return evidenceProblemDetailsOf(input).map(one => one.words);
|
|
105
|
+
}
|
|
106
|
+
export function evidenceHealthOf(problems) {
|
|
107
|
+
const health = { damaged: 0, shortened: 0, missing: 0 };
|
|
108
|
+
for (const one of problems)
|
|
109
|
+
health[one.kind] += 1;
|
|
110
|
+
return health;
|
|
111
|
+
}
|
|
112
|
+
/** The `data-result-*` attributes every surface stamps on its result
|
|
113
|
+
* element. Values are short, escaped, and deterministic for one run, so
|
|
114
|
+
* two surfaces rendering the same result carry byte-identical attributes. */
|
|
115
|
+
/** The shared facts as the panel's data attributes, unescaped (the rebuilt
|
|
116
|
+
* result page sets them through React). */
|
|
117
|
+
export function resultFactsAttributeMap(facts) {
|
|
118
|
+
return {
|
|
119
|
+
"data-result-run": String(facts.runId),
|
|
120
|
+
"data-result-head": facts.head === null ? "" : facts.head.slice(0, 12),
|
|
121
|
+
"data-result-base": facts.base === null ? "" : facts.base.slice(0, 12),
|
|
122
|
+
"data-result-head-source": facts.headSource ?? "none",
|
|
123
|
+
"data-result-checks": facts.checks === null ? "none" : `${facts.checks.passed}/${facts.checks.total}`,
|
|
124
|
+
"data-result-caveats": String(facts.caveats.length),
|
|
125
|
+
"data-result-evidence": facts.evidenceProblems.length === 0 ? "ok" : `problems:${facts.evidenceProblems.length}`,
|
|
126
|
+
"data-result-publication": facts.publicationState,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
export function resultFactsAttributes(facts) {
|
|
130
|
+
return Object.entries(resultFactsAttributeMap(facts)).map(([name, value]) => ` ${name}="${escapeAttribute(value)}"`).join("");
|
|
131
|
+
}
|
|
132
|
+
/** The shared fact names, in the order `resultFactsAttributes` writes them. */
|
|
133
|
+
export const RESULT_FACT_KEYS = ["run", "head", "base", "head-source", "checks", "caveats", "evidence", "publication"];
|
|
134
|
+
/** Parse the shared facts back — the test-side and proof-side reader.
|
|
135
|
+
* Only the shared keys are read; a panel's own presentation attributes
|
|
136
|
+
* (place, lead, task, user) are not facts and are left out. */
|
|
137
|
+
export function resultFactsFromHtml(html) {
|
|
138
|
+
const found = [];
|
|
139
|
+
const tag = /<[a-z]+\b[^>]*\bdata-result-run="[^"]*"[^>]*>/g;
|
|
140
|
+
const keys = new Set(RESULT_FACT_KEYS);
|
|
141
|
+
for (const match of html.matchAll(tag)) {
|
|
142
|
+
const facts = {};
|
|
143
|
+
for (const pair of match[0].matchAll(/data-result-([a-z-]+)="([^"]*)"/g)) {
|
|
144
|
+
if (keys.has(pair[1]))
|
|
145
|
+
facts[pair[1]] = unescapeAttribute(pair[2]);
|
|
146
|
+
}
|
|
147
|
+
found.push(facts);
|
|
148
|
+
}
|
|
149
|
+
return found;
|
|
150
|
+
}
|
|
151
|
+
/** Where a result form may send its reader back: the review cockpit's
|
|
152
|
+
* own deep link, the chat's result detail, or the run page. Anything else
|
|
153
|
+
* lands on the run page. Matched exactly — never a bare open redirect. */
|
|
154
|
+
export function resultReturnTarget(raw, runId) {
|
|
155
|
+
if (raw !== null && raw !== undefined) {
|
|
156
|
+
const review = /^\/review\?result=[A-Za-z0-9._~%-]{1,200}(?:&run=([0-9]{1,15}))?$/.exec(raw);
|
|
157
|
+
if (review !== null && (review[1] === undefined || Number(review[1]) === runId))
|
|
158
|
+
return raw;
|
|
159
|
+
const chat = /^\/chat\?task=([A-Za-z0-9._~%-]{1,200})&result=([0-9]{1,15})(?:&conversation=[A-Za-z0-9-]{1,128})?$/.exec(raw);
|
|
160
|
+
if (chat !== null && Number(chat[2]) === runId)
|
|
161
|
+
return raw;
|
|
162
|
+
}
|
|
163
|
+
return `/r/${runId}`;
|
|
164
|
+
}
|
|
165
|
+
/** A form's own request token, minted per render — the same shape the
|
|
166
|
+
* chat composer uses. A replayed submission carries the same token, so
|
|
167
|
+
* the server can recognise it and mint nothing twice. */
|
|
168
|
+
export const REQUEST_TOKEN = /^[a-f0-9]{32}$/;
|
|
169
|
+
/** The dedupe key a review note is stored under when the form carried a
|
|
170
|
+
* request token: bound to the account and the token, never to the words,
|
|
171
|
+
* so the same person saying the same thing twice on purpose still lands. */
|
|
172
|
+
export function commentSourceKey(user, request) {
|
|
173
|
+
return request !== null && request !== undefined && REQUEST_TOKEN.test(request) ? `review:${user}:${request}` : undefined;
|
|
174
|
+
}
|
|
175
|
+
/** The revision form's exact batch (repair 2026-09-14): the ids of the
|
|
176
|
+
* live notes the page DISPLAYED, oldest first, joined by commas, plus the
|
|
177
|
+
* source scope digest the page rendered against ("none" when the task has
|
|
178
|
+
* no scope). A seal binds to exactly these — never to "whatever is live
|
|
179
|
+
* when the POST arrives" — so a replayed or second-tab submission can
|
|
180
|
+
* only ever consume the notes its own reader saw. */
|
|
181
|
+
export function revisionBatchOf(comments) {
|
|
182
|
+
return comments.map(one => String(one.id)).join(",");
|
|
183
|
+
}
|
|
184
|
+
/** User feedback requests work; a reviewer's observations only do so when
|
|
185
|
+
* they are problems. The original findings always remain on record. */
|
|
186
|
+
export function isRevisionFeedback(comment) {
|
|
187
|
+
return comment.reviewerRun === null || comment.severity === "problem";
|
|
188
|
+
}
|
|
189
|
+
export const REVISION_BATCH_CAP = 500;
|
|
190
|
+
/** Parse a posted batch back into distinct positive ids, or null when the
|
|
191
|
+
* field is absent or malformed (an out-of-date form, a hand-built POST). */
|
|
192
|
+
export function parseRevisionBatch(raw) {
|
|
193
|
+
if (raw === null || raw === undefined)
|
|
194
|
+
return null;
|
|
195
|
+
const text = raw.trim();
|
|
196
|
+
if (text === "" || !/^[0-9]{1,15}(,[0-9]{1,15})*$/.test(text))
|
|
197
|
+
return null;
|
|
198
|
+
const ids = text.split(",").map(Number);
|
|
199
|
+
if (ids.length > REVISION_BATCH_CAP || ids.some(one => !Number.isSafeInteger(one) || one < 1))
|
|
200
|
+
return null;
|
|
201
|
+
return new Set(ids).size === ids.length ? ids : null;
|
|
202
|
+
}
|
|
203
|
+
/** The source binding the revision form carries: the scope digest the
|
|
204
|
+
* page was rendered against, or "none". */
|
|
205
|
+
export function revisionSourceOf(scopeDigest) {
|
|
206
|
+
return scopeDigest === null ? "none" : scopeDigest;
|
|
207
|
+
}
|
|
208
|
+
export const REVIEW_DRAFT_PREFIX = "standing-orders:review-draft:";
|
|
209
|
+
export const RESULT_SCROLL_PREFIX = "standing-orders:result-scroll:";
|
|
210
|
+
/** The in-page half of the result presentation. Everything it does is
|
|
211
|
+
* presentational or a bounded draft: no fetch, no endpoint, no submit.
|
|
212
|
+
*
|
|
213
|
+
* - Tabs: the anchor links switch the visible view in place and record
|
|
214
|
+
* `?tab=` with replaceState, so refresh and Back land on the same view
|
|
215
|
+
* the server would render for that URL.
|
|
216
|
+
* - Diff modes: View hides the line pins; Annotate shows them. A pin or a
|
|
217
|
+
* file button copies its target into the Request changes form, opens
|
|
218
|
+
* the pin disclosure, and focuses the note.
|
|
219
|
+
* - Review draft: the note, file, and line are kept in sessionStorage
|
|
220
|
+
* under the account, task, and run the form names, for at most a day,
|
|
221
|
+
* and restored on load. The draft clears only when the page carries the
|
|
222
|
+
* receipt for THIS draft's request token (`?noted=<token>`); a refused
|
|
223
|
+
* submission leaves it in place. Other accounts' drafts on this tab are
|
|
224
|
+
* dropped, never restored.
|
|
225
|
+
* - Request identity (repair 2026-09-14): the form's request token is
|
|
226
|
+
* bound to the exact note, file, and line last displayed, even when
|
|
227
|
+
* FormData is sent directly. An unchanged retry keeps the token, so the server
|
|
228
|
+
* records it once; editing any of the three after a submission mints a
|
|
229
|
+
* fresh token, so the edited words are a new note and can never be
|
|
230
|
+
* swallowed by the earlier one's receipt. A refusal that comes back with
|
|
231
|
+
* `?conflict=<token>` rotates that token too, keeping the words.
|
|
232
|
+
* - Reading position: the page's scroll offset is kept under the same
|
|
233
|
+
* account/task and the URL's own result and tab, and restored on load
|
|
234
|
+
* when the URL carries no hash, so Back to chat and refresh return the
|
|
235
|
+
* reader to where they were. */
|
|
236
|
+
export const RESULT_REVIEW_SCRIPT = String.raw `
|
|
237
|
+
(function(){
|
|
238
|
+
var panel=document.querySelector('[data-result-panel]');
|
|
239
|
+
var user=panel?panel.getAttribute('data-result-user')||'':'';
|
|
240
|
+
var task=panel?panel.getAttribute('data-result-task')||'':'';
|
|
241
|
+
var run=panel?panel.getAttribute('data-result-run')||'':'';
|
|
242
|
+
var draftPrefix='standing-orders:review-draft:',scrollPrefix='standing-orders:result-scroll:';
|
|
243
|
+
var day=86400000,storage=true,rememberPosition=null;
|
|
244
|
+
function read(key){try{return JSON.parse(sessionStorage.getItem(key)||'null');}catch(e){return null;}}
|
|
245
|
+
function write(key,value){try{if(value===null)sessionStorage.removeItem(key);else sessionStorage.setItem(key,JSON.stringify(value));}catch(e){storage=false;}}
|
|
246
|
+
// Prune: anything older than a day, and anything another account left on this tab.
|
|
247
|
+
try{
|
|
248
|
+
for(var i=sessionStorage.length-1;i>=0;i--){var k=sessionStorage.key(i);if(!k)continue;
|
|
249
|
+
if(k.indexOf(draftPrefix)===0||k.indexOf(scrollPrefix)===0){var item=read(k);var owner=k.split(':')[2]||'';
|
|
250
|
+
if(!item||typeof item.at!=='number'||item.at<Date.now()-day||(user&&owner!==user))sessionStorage.removeItem(k);}}
|
|
251
|
+
}catch(e){storage=false;}
|
|
252
|
+
// ---- tabs -----------------------------------------------------------
|
|
253
|
+
if(panel){
|
|
254
|
+
var tabs=panel.querySelectorAll('[data-result-tab]'),views=panel.querySelectorAll('[data-result-view]');
|
|
255
|
+
function show(name){
|
|
256
|
+
var tabField=panel.querySelector('#comment-form input[name="tab"]');if(tabField)tabField.value=name;
|
|
257
|
+
Array.prototype.forEach.call(views,function(view){var on=view.getAttribute('data-result-view')===name;view.hidden=!on;});
|
|
258
|
+
Array.prototype.forEach.call(tabs,function(tab){var on=tab.getAttribute('data-result-tab')===name;tab.setAttribute('aria-selected',on?'true':'false');tab.tabIndex=on?0:-1;});
|
|
259
|
+
}
|
|
260
|
+
Array.prototype.forEach.call(tabs,function(tab){
|
|
261
|
+
tab.addEventListener('click',function(ev){
|
|
262
|
+
if(ev.metaKey||ev.ctrlKey||ev.shiftKey||ev.altKey||ev.button!==0)return;
|
|
263
|
+
ev.preventDefault();var name=tab.getAttribute('data-result-tab');show(name);
|
|
264
|
+
try{var url=new URL(location.href);url.searchParams.set('tab',name);url.hash='';history.replaceState(history.state,'',url.toString());}catch(e){}
|
|
265
|
+
if(rememberPosition)rememberPosition();
|
|
266
|
+
});
|
|
267
|
+
tab.addEventListener('keydown',function(ev){
|
|
268
|
+
var list=Array.prototype.slice.call(tabs),at=list.indexOf(tab),next=null;
|
|
269
|
+
if(ev.key==='ArrowRight')next=list[(at+1)%list.length];else if(ev.key==='ArrowLeft')next=list[(at-1+list.length)%list.length];else if(ev.key==='Home')next=list[0];else if(ev.key==='End')next=list[list.length-1];
|
|
270
|
+
if(next){ev.preventDefault();next.focus();next.click();}
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
// ---- diff modes and line pins ------------------------------------------
|
|
275
|
+
var form=document.getElementById('comment-form');
|
|
276
|
+
var review=document.querySelector('[data-review-diff]');
|
|
277
|
+
if(review){
|
|
278
|
+
review.setAttribute('data-mode','view');
|
|
279
|
+
review.addEventListener('click',function(ev){
|
|
280
|
+
var mode=ev.target&&ev.target.closest?ev.target.closest('button[data-diff-mode]'):null;if(!mode)return;
|
|
281
|
+
var value=mode.getAttribute('data-diff-mode')==='annotate'?'annotate':'view';review.setAttribute('data-mode',value);
|
|
282
|
+
review.querySelectorAll('button[data-diff-mode]').forEach(function(one){one.setAttribute('aria-pressed',String(one===mode));});
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// The feedback form waits behind "Request changes"; anything that points
|
|
286
|
+
// at it (a line pin, the result's own link, a saved draft) opens it first.
|
|
287
|
+
var formShell=form?form.closest('details.result-request-open'):null;
|
|
288
|
+
function openForm(){if(formShell&&!formShell.open)formShell.open=true;}
|
|
289
|
+
if(formShell&&location.hash==='#request-changes')openForm();
|
|
290
|
+
document.addEventListener('click',function(ev){var link=ev.target&&ev.target.closest?ev.target.closest('a[href="#request-changes"]'):null;if(link)openForm();});
|
|
291
|
+
if(form){
|
|
292
|
+
var noteBox=form.querySelector('[name=note]'),pathBox=form.querySelector('[name=path]'),lineBox=form.querySelector('[name=line]'),pin=form.querySelector('details.result-pin');
|
|
293
|
+
var limit=document.getElementById('comment-note-limit'),requestBox=form.querySelector('[name=request]');
|
|
294
|
+
function updateActions(){
|
|
295
|
+
var typed=!!(noteBox&¬eBox.value.trim()),batch=form.querySelector('[name=batch]');
|
|
296
|
+
var requestAction=form.querySelector('[data-request-changes]'),saveAction=form.querySelector('[data-save-feedback]');
|
|
297
|
+
if(requestAction)requestAction.disabled=!typed&&!(batch&&batch.value);
|
|
298
|
+
if(saveAction)saveAction.disabled=!typed;
|
|
299
|
+
}
|
|
300
|
+
updateActions();if(noteBox)noteBox.addEventListener('input',updateActions);
|
|
301
|
+
if(noteBox&&limit&¬eBox.maxLength>0){
|
|
302
|
+
var tally=function(){limit.textContent=noteBox.value.length===0?'up to '+noteBox.maxLength+' characters':noteBox.value.length+' of '+noteBox.maxLength+' characters';};
|
|
303
|
+
tally();noteBox.addEventListener('input',tally);
|
|
304
|
+
}
|
|
305
|
+
document.addEventListener('click',function(ev){
|
|
306
|
+
var button=ev.target&&ev.target.closest?ev.target.closest('button.pick-file,button.pick-line'):null;if(!button)return;
|
|
307
|
+
var reviewNote=button.getAttribute('data-review-note');
|
|
308
|
+
if(reviewNote!==null&¬eBox&¬eBox.value&&!window.confirm('Replace the feedback draft with this note?'))return;
|
|
309
|
+
if(reviewNote!==null&¬eBox)noteBox.value=reviewNote;
|
|
310
|
+
if(pathBox)pathBox.value=button.getAttribute('data-path')||'';
|
|
311
|
+
if(lineBox)lineBox.value=button.getAttribute('data-line')||'';
|
|
312
|
+
if(pin)pin.open=true;
|
|
313
|
+
openForm();
|
|
314
|
+
save();
|
|
315
|
+
form.scrollIntoView({behavior:window.matchMedia&&window.matchMedia('(prefers-reduced-motion: reduce)').matches?'instant':'smooth',block:'center'});if(noteBox){noteBox.dispatchEvent(new Event('input',{bubbles:true}));noteBox.focus();}
|
|
316
|
+
});
|
|
317
|
+
// The bounded draft: this account, this task, this run.
|
|
318
|
+
var draftKey=draftPrefix+user+':'+task+':'+run;
|
|
319
|
+
var noted=null,conflict=null;try{var here=new URL(location.href);noted=here.searchParams.get('noted');conflict=here.searchParams.get('conflict');}catch(e){}
|
|
320
|
+
var saved=read(draftKey);
|
|
321
|
+
var recorded=form.querySelector('[data-recorded-requests]');
|
|
322
|
+
if(saved&&saved.request!==conflict&&recorded&&recorded.value.split(',').includes(saved.request)){write(draftKey,null);saved=null;}
|
|
323
|
+
if(saved&¬ed&&saved.request===noted){write(draftKey,null);saved=null;}
|
|
324
|
+
// A fresh request identity: 16 random bytes as hex, the server's own shape.
|
|
325
|
+
function mint(){var bytes=new Uint8Array(16);try{crypto.getRandomValues(bytes);}catch(e){for(var i=0;i<16;i++)bytes[i]=Math.floor(Math.random()*256);}
|
|
326
|
+
var hex='';for(var j=0;j<16;j++)hex+=(bytes[j]<16?'0':'')+bytes[j].toString(16);return hex;}
|
|
327
|
+
function payload(){return JSON.stringify([noteBox?noteBox.value:'',pathBox?pathBox.value:'',lineBox?lineBox.value:'']);}
|
|
328
|
+
// What the current token was last submitted with; null = never sent.
|
|
329
|
+
var sent=null,bound=null;
|
|
330
|
+
// The server refused this token for a different note or another result:
|
|
331
|
+
// the words stay, the identity does not.
|
|
332
|
+
if(saved&&conflict&&saved.request===conflict){saved.request=mint();saved.sent=null;write(draftKey,saved);}
|
|
333
|
+
// The receipt lands with a fragment: browsers skip autofocus on a
|
|
334
|
+
// fragment URL and move focus to the fragment's target on load, so the
|
|
335
|
+
// just-posted form's note box is focused after that step.
|
|
336
|
+
if(noted&¬eBox&&!noteBox.value){
|
|
337
|
+
openForm();
|
|
338
|
+
var focusNote=function(){setTimeout(function(){noteBox.focus({preventScroll:true});},0);};
|
|
339
|
+
if(document.readyState==='complete')focusNote();else window.addEventListener('load',focusNote);
|
|
340
|
+
}
|
|
341
|
+
if(saved&&typeof saved.note==='string'&&saved.note.length<=2000){
|
|
342
|
+
if(noteBox&&!noteBox.value)noteBox.value=saved.note;
|
|
343
|
+
if(saved.note)openForm();
|
|
344
|
+
if(pathBox&&!pathBox.value&&typeof saved.path==='string')pathBox.value=saved.path;
|
|
345
|
+
if(lineBox&&!lineBox.value&&typeof saved.line==='string')lineBox.value=saved.line;
|
|
346
|
+
if(pin&&(pathBox&&pathBox.value||lineBox&&lineBox.value))pin.open=true;
|
|
347
|
+
if(typeof saved.request==='string'&&/^[a-f0-9]{32}$/.test(saved.request)&&requestBox)requestBox.value=saved.request;
|
|
348
|
+
if(typeof saved.sent==='string')sent=saved.sent;
|
|
349
|
+
bound=JSON.stringify([saved.note,saved.path||'',saved.line||'']);
|
|
350
|
+
if(noteBox)noteBox.dispatchEvent(new Event('input'));
|
|
351
|
+
}
|
|
352
|
+
function save(){
|
|
353
|
+
var note=noteBox?noteBox.value:'',path=pathBox?pathBox.value:'',line=lineBox?lineBox.value:'';
|
|
354
|
+
// Bind every observed payload, including FormData sent without a
|
|
355
|
+
// submit event. A changed note, path, or line always gets a new token.
|
|
356
|
+
var current=payload();
|
|
357
|
+
if((bound!==null&¤t!==bound)||(sent!==null&¤t!==sent)){sent=null;if(requestBox)requestBox.value=mint();}
|
|
358
|
+
bound=current;
|
|
359
|
+
if(!note&&!path&&!line){write(draftKey,null);return;}
|
|
360
|
+
write(draftKey,{note:note,path:path,line:line,request:requestBox?requestBox.value:'',sent:sent,at:Date.now()});
|
|
361
|
+
if(!storage&&limit)limit.textContent='Draft stays on this page only. Browser storage is unavailable.';
|
|
362
|
+
}
|
|
363
|
+
form.addEventListener('input',save);
|
|
364
|
+
// A double click never posts twice; a refused post keeps the draft.
|
|
365
|
+
// On a chat page the conversation's own delegated latch owns
|
|
366
|
+
// aria-busy (it runs after this form-level listener and would refuse
|
|
367
|
+
// a form already marked busy), so the latch is added only elsewhere.
|
|
368
|
+
var chatLatch=document.querySelector('.composer[data-chat-session]')!==null;
|
|
369
|
+
form.addEventListener('submit',function(event){
|
|
370
|
+
save();
|
|
371
|
+
// Bind the identity to exactly what is being sent.
|
|
372
|
+
sent=payload();var draft=read(draftKey);if(draft){draft.sent=sent;write(draftKey,draft);}
|
|
373
|
+
if(chatLatch)return;
|
|
374
|
+
if(form.getAttribute('aria-busy')==='true'){event.preventDefault();return;}
|
|
375
|
+
form.setAttribute('aria-busy','true');
|
|
376
|
+
});
|
|
377
|
+
window.addEventListener('pageshow',function(){form.removeAttribute('aria-busy');});
|
|
378
|
+
}
|
|
379
|
+
// ---- reading position ---------------------------------------------------
|
|
380
|
+
// Kept under the account, the task, and the URL's own result and view,
|
|
381
|
+
// read again at every save so a tab switched in place records under the
|
|
382
|
+
// view the URL now names.
|
|
383
|
+
var returnKey=scrollPrefix+user+':'+task+':return';
|
|
384
|
+
function scrollKeyFor(){var url=null;try{url=new URL(location.href);}catch(e){}
|
|
385
|
+
return scrollPrefix+user+':'+task+':'+(url?(url.searchParams.get('result')||run)+':'+(url.searchParams.get('tab')||'summary'):run);}
|
|
386
|
+
// Once a navigation has begun (pageswap / beforeunload) the document's
|
|
387
|
+
// scroll is no longer the reader's — a cross-document transition can
|
|
388
|
+
// move it to the top while it is captured — so remembering stops.
|
|
389
|
+
var leaving=false;
|
|
390
|
+
window.addEventListener('pageswap',function(){leaving=true;});
|
|
391
|
+
window.addEventListener('beforeunload',function(){leaving=true;});
|
|
392
|
+
if(panel&&user&&task){
|
|
393
|
+
var pending=false;
|
|
394
|
+
var remember=function(){pending=false;if(leaving)return;write(scrollKeyFor(),{y:window.scrollY,at:Date.now()});};
|
|
395
|
+
rememberPosition=remember;
|
|
396
|
+
window.addEventListener('scroll',function(){if(!pending){pending=true;requestAnimationFrame(remember);}},{passive:true});
|
|
397
|
+
// Leaving the result view marks the way back, so the conversation can
|
|
398
|
+
// return the reader to where they were. The position itself is taken
|
|
399
|
+
// from the last scroll, never at pagehide: a navigation's transition
|
|
400
|
+
// can already have moved the document by then.
|
|
401
|
+
window.addEventListener('pagehide',function(){write(returnKey,{at:Date.now()});});
|
|
402
|
+
var where=read(scrollKeyFor());
|
|
403
|
+
if(where&&typeof where.y==='number'&&!location.hash){
|
|
404
|
+
try{if('scrollRestoration' in history)history.scrollRestoration='manual';}catch(e){}
|
|
405
|
+
window.scrollTo({top:where.y,behavior:'instant'});
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
// Chat pages remember where the reader was, so opening a result and
|
|
409
|
+
// coming back lands on the same message (the page itself, no panel).
|
|
410
|
+
var composer=document.querySelector('.composer[data-chat-session]');
|
|
411
|
+
if(!panel&&composer&&composer.dataset.chatTask){
|
|
412
|
+
var chatUser=composer.dataset.chatUser||'',chatTask=composer.dataset.chatTask;
|
|
413
|
+
var chatKey=scrollPrefix+chatUser+':'+chatTask+':chat',chatReturn=scrollPrefix+chatUser+':'+chatTask+':return';
|
|
414
|
+
var chatPending=false;
|
|
415
|
+
function rememberChat(){chatPending=false;if(leaving)return;write(chatKey,{y:window.scrollY,at:Date.now()});}
|
|
416
|
+
window.addEventListener('scroll',function(){if(!chatPending){chatPending=true;requestAnimationFrame(rememberChat);}},{passive:true});
|
|
417
|
+
var came=read(chatReturn);write(chatReturn,null);
|
|
418
|
+
var back=read(chatKey);
|
|
419
|
+
if(came&&typeof came.at==='number'&&came.at>Date.now()-600000&&back&&typeof back.y==='number'&&!location.hash){
|
|
420
|
+
try{if('scrollRestoration' in history)history.scrollRestoration='manual';}catch(e){}
|
|
421
|
+
window.scrollTo({top:back.y,behavior:'instant'});
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
})();`;
|
|
425
|
+
function escapeAttribute(text) {
|
|
426
|
+
return text.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
427
|
+
}
|
|
428
|
+
function unescapeAttribute(text) {
|
|
429
|
+
return text.replace(/"/g, '"').replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
430
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type RetentionCount, type RetentionPeriods } from "./retention.js";
|
|
2
|
+
export declare const RETENTION_CSS: string;
|
|
3
|
+
export type RetentionView = {
|
|
4
|
+
periods: RetentionPeriods;
|
|
5
|
+
next: RetentionCount[];
|
|
6
|
+
lastSweep: string | null;
|
|
7
|
+
csrf: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function retentionHtml(view: RetentionView, notice: {
|
|
10
|
+
said?: string | null;
|
|
11
|
+
problem?: string | null;
|
|
12
|
+
}): string;
|