toolroll 0.9.93 → 0.9.95
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/CHANGELOG.md +79 -0
- package/dist/activity-line.d.ts +7 -4
- package/dist/activity-line.js +9 -7
- package/dist/agent-fence.d.ts +10 -0
- package/dist/agent-fence.js +6 -3
- package/dist/approval-authority.d.ts +7 -1
- package/dist/approval-authority.js +11 -2
- package/dist/approval-password.d.ts +31 -0
- package/dist/approval-password.js +26 -0
- package/dist/assignment-status.d.ts +1 -1
- package/dist/assignment-ui.js +3 -1
- package/dist/assignment.js +5 -0
- package/dist/attest.d.ts +3 -0
- package/dist/attest.js +10 -0
- package/dist/boot-identity.d.ts +2 -1
- package/dist/boot-identity.js +6 -4
- package/dist/bounded-spawn.d.ts +57 -0
- package/dist/bounded-spawn.js +220 -0
- package/dist/browser/terminal.js +42 -42
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +32 -32
- package/dist/browser-crew.js +2 -0
- package/dist/browser-shell.d.ts +1 -1
- package/dist/browser-shell.js +2 -2
- package/dist/browser-workspace.d.ts +50 -2
- package/dist/browser-workspace.js +3 -3
- package/dist/build-review.js +2 -0
- package/dist/builder-restart.d.ts +21 -0
- package/dist/builder-restart.js +50 -0
- package/dist/builder.d.ts +11 -2
- package/dist/builder.js +234 -101
- package/dist/card-catalog.d.ts +209 -0
- package/dist/card-catalog.js +133 -0
- package/dist/card-cli.d.ts +43 -0
- package/dist/card-cli.js +44 -0
- package/dist/card-render.d.ts +26 -0
- package/dist/card-render.js +223 -0
- package/dist/card-sources.d.ts +68 -0
- package/dist/card-sources.js +234 -0
- package/dist/chat-acceptance.js +1 -1
- package/dist/chat-actions.d.ts +106 -9
- package/dist/chat-actions.js +473 -46
- package/dist/chat-approval.d.ts +13 -0
- package/dist/chat-approval.js +39 -9
- package/dist/chat-card-part.d.ts +11 -0
- package/dist/chat-card-part.js +18 -0
- package/dist/chat-card.d.ts +46 -0
- package/dist/chat-card.js +99 -0
- package/dist/chat-channel.d.ts +2 -0
- package/dist/chat-channel.js +37 -14
- package/dist/chat-controls.d.ts +4 -0
- package/dist/chat-controls.js +4 -0
- package/dist/chat-decide.d.ts +10 -16
- package/dist/chat-decide.js +79 -62
- package/dist/chat-delivery.js +13 -4
- package/dist/chat-flow.d.ts +0 -27
- package/dist/chat-flow.js +31 -2
- package/dist/chat-quiet.js +4 -4
- package/dist/chat-task-actions.d.ts +3 -2
- package/dist/chat-task-actions.js +19 -5
- package/dist/chat-terms.d.ts +14 -2
- package/dist/chat-terms.js +35 -0
- package/dist/chat-voice.d.ts +1 -1
- package/dist/chat-voice.js +2 -2
- package/dist/check-facts.d.ts +3 -1
- package/dist/check-facts.js +57 -11
- package/dist/check-failure.d.ts +24 -3
- package/dist/check-failure.js +89 -13
- package/dist/check-levels-ui.d.ts +4 -0
- package/dist/check-levels-ui.js +10 -1
- package/dist/check-load.d.ts +85 -0
- package/dist/check-load.js +147 -0
- package/dist/check-only-standing.d.ts +36 -0
- package/dist/check-only-standing.js +39 -0
- package/dist/check-only.d.ts +15 -0
- package/dist/check-only.js +99 -0
- package/dist/check-repair.d.ts +47 -0
- package/dist/check-repair.js +240 -0
- package/dist/check-report.d.ts +2 -0
- package/dist/check-report.js +1 -1
- package/dist/check-stamp.d.ts +46 -0
- package/dist/check-stamp.js +93 -0
- package/dist/checkout-cleanup.d.ts +36 -5
- package/dist/checkout-cleanup.js +166 -14
- package/dist/claim.d.ts +6 -0
- package/dist/claim.js +13 -2
- package/dist/cli-help.d.ts +4 -1
- package/dist/cli-help.js +49 -30
- package/dist/cli.js +15 -1
- package/dist/code-extract.d.ts +44 -0
- package/dist/code-extract.js +88 -0
- package/dist/code-map-acts.d.ts +24 -0
- package/dist/code-map-acts.js +53 -0
- package/dist/code-map-admission.d.ts +52 -0
- package/dist/code-map-admission.js +295 -0
- package/dist/code-map-build.d.ts +63 -0
- package/dist/code-map-build.js +415 -0
- package/dist/code-map-cli.d.ts +153 -0
- package/dist/code-map-cli.js +103 -0
- package/dist/code-map-main.d.ts +1 -0
- package/dist/code-map-main.js +48 -0
- package/dist/code-map-read.d.ts +106 -0
- package/dist/code-map-read.js +171 -0
- package/dist/code-map-report.d.ts +37 -0
- package/dist/code-map-report.js +95 -0
- package/dist/code-map-shape.d.ts +172 -0
- package/dist/code-map-shape.js +327 -0
- package/dist/code-map-store.d.ts +136 -0
- package/dist/code-map-store.js +233 -0
- package/dist/coding-provider.d.ts +3 -1
- package/dist/coding-provider.js +12 -7
- package/dist/coding-update.js +3 -2
- package/dist/coding-workspace.d.ts +1 -1
- package/dist/coding-workspace.js +8 -8
- package/dist/console-chrome.js +2 -2
- package/dist/containment.d.ts +5 -0
- package/dist/containment.js +14 -1
- package/dist/contracts/chat-actions.d.ts +92 -0
- package/dist/contracts/chat-actions.js +20 -0
- package/dist/contracts/chat-card.d.ts +91 -0
- package/dist/contracts/chat-card.js +54 -0
- package/dist/contracts/chat-content.d.ts +191 -0
- package/dist/contracts/chat-content.js +4 -0
- package/dist/contracts/cli.d.ts +52 -0
- package/dist/contracts/cli.js +4 -0
- package/dist/contracts/console-api.d.ts +12 -3
- package/dist/contracts/console-api.js +12 -3
- package/dist/contracts/flow-propose.d.ts +8 -1
- package/dist/contracts/flow-propose.js +3 -1
- package/dist/contracts/flow-send.d.ts +126 -0
- package/dist/contracts/flow-send.js +3 -0
- package/dist/contracts/gateway-tools.d.ts +17 -0
- package/dist/contracts/gateway-tools.js +3 -1
- package/dist/contracts/lead-tools.d.ts +234 -0
- package/dist/contracts/lead-tools.js +25 -1
- package/dist/contracts/project-knowledge.d.ts +38 -5
- package/dist/contracts/project-knowledge.js +11 -5
- package/dist/contracts/project-memory.d.ts +3 -1
- package/dist/contracts/project-memory.js +3 -2
- package/dist/contracts/storage.d.ts +14 -0
- package/dist/contracts/storage.js +3 -1
- package/dist/contracts/store-json.d.ts +18 -0
- package/dist/contracts/youiyoux-request.d.ts +1 -1
- package/dist/contracts/youiyoux-request.js +1 -1
- package/dist/desktop-access.js +6 -2
- package/dist/discord-chat.js +14 -0
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +25 -16
- package/dist/dispose.d.ts +19 -0
- package/dist/dispose.js +55 -9
- package/dist/easy-start.js +2 -3
- package/dist/eval-oracle.js +4 -1
- package/dist/evals.js +2 -1
- package/dist/evidence-pair.d.ts +53 -0
- package/dist/evidence-pair.js +128 -0
- package/dist/exhaustion.d.ts +17 -4
- package/dist/exhaustion.js +44 -4
- package/dist/export.js +1 -1
- package/dist/failing-first.d.ts +31 -0
- package/dist/failing-first.js +44 -0
- package/dist/fallback-schema.d.ts +8 -0
- package/dist/fallback-schema.js +40 -0
- package/dist/fallback.d.ts +138 -0
- package/dist/fallback.js +605 -0
- package/dist/fast-start.d.ts +136 -0
- package/dist/fast-start.js +431 -0
- package/dist/fast-terms.d.ts +9 -0
- package/dist/fast-terms.js +23 -0
- package/dist/fenced-check-coverage.d.ts +62 -0
- package/dist/fenced-check-coverage.js +54 -0
- package/dist/findings.d.ts +224 -0
- package/dist/findings.js +449 -0
- package/dist/first-run.js +1 -1
- package/dist/flaky-ci.d.ts +31 -0
- package/dist/flaky-ci.js +149 -0
- package/dist/flaky-cli.d.ts +60 -0
- package/dist/flaky-cli.js +60 -0
- package/dist/flaky.d.ts +75 -9
- package/dist/flaky.js +255 -0
- package/dist/fleet-schema.d.ts +17 -0
- package/dist/fleet-schema.js +135 -0
- package/dist/flow-browser.js +2 -2
- package/dist/flow-card-task.js +3 -0
- package/dist/flow-code.d.ts +2 -2
- package/dist/flow-code.js +9 -5
- package/dist/flow-result-card.d.ts +22 -0
- package/dist/flow-result-card.js +55 -0
- package/dist/flow-send.js +12 -9
- package/dist/flow-steps.js +1 -1
- package/dist/flow-triggers.d.ts +1 -1
- package/dist/flow-triggers.js +2 -2
- package/dist/flow-unattended.d.ts +26 -0
- package/dist/flow-unattended.js +12 -3
- package/dist/flows-ui.js +10 -2
- package/dist/follow-through-brief.d.ts +12 -0
- package/dist/follow-through-brief.js +31 -0
- package/dist/follow-through-cli.d.ts +23 -0
- package/dist/follow-through-cli.js +153 -0
- package/dist/git-incident.d.ts +16 -0
- package/dist/git-incident.js +69 -6
- package/dist/github-import.d.ts +62 -0
- package/dist/github-import.js +146 -0
- package/dist/guides.js +15 -10
- package/dist/handover-note.d.ts +33 -0
- package/dist/handover-note.js +106 -0
- package/dist/invoke.d.ts +25 -2
- package/dist/invoke.js +157 -58
- package/dist/job-object-helper.ps1 +10 -3
- package/dist/keymap.d.ts +41 -0
- package/dist/keymap.js +51 -0
- package/dist/knowledge-cli.js +1 -1
- package/dist/knowledge-ui.d.ts +21 -4
- package/dist/knowledge-ui.js +75 -7
- package/dist/laptop-background.d.ts +16 -0
- package/dist/laptop-background.js +108 -2
- package/dist/lead-cli.js +26 -24
- package/dist/lead-context.js +1 -1
- package/dist/lead-contract.d.ts +1 -1
- package/dist/lead-contract.js +3 -2
- package/dist/lead-doors.d.ts +4 -0
- package/dist/lead-doors.js +2 -2
- package/dist/lead-progress.js +5 -0
- package/dist/lead-status.d.ts +2 -0
- package/dist/lead-status.js +6 -2
- package/dist/lead-tools.js +162 -34
- package/dist/lead.js +2 -2
- package/dist/lesson-notes.d.ts +81 -0
- package/dist/lesson-notes.js +336 -0
- package/dist/limits-ui.js +1 -1
- package/dist/local-owner.d.ts +1 -1
- package/dist/local-owner.js +16 -0
- package/dist/machine-check.d.ts +16 -0
- package/dist/machine-check.js +26 -0
- package/dist/machine-identity.d.ts +75 -0
- package/dist/machine-identity.js +170 -0
- package/dist/mcp-core.js +11 -1
- package/dist/memory-cli.d.ts +300 -1
- package/dist/memory-cli.js +62 -9
- package/dist/memory-pass.d.ts +16 -0
- package/dist/memory-pass.js +67 -3
- package/dist/memory-tidy.d.ts +181 -0
- package/dist/memory-tidy.js +523 -0
- package/dist/memory-use.d.ts +35 -0
- package/dist/memory-use.js +109 -0
- package/dist/merge-checklist.d.ts +55 -0
- package/dist/merge-checklist.js +182 -0
- package/dist/modes.d.ts +6 -6
- package/dist/modes.js +3 -1
- package/dist/needs-you.d.ts +31 -9
- package/dist/needs-you.js +110 -41
- package/dist/nightly-github.d.ts +2 -0
- package/dist/nightly-github.js +4 -4
- package/dist/operate-remote-arguments.js +7 -1
- package/dist/operate-remote.js +3 -1
- package/dist/operate.d.ts +6 -1
- package/dist/operate.js +565 -64
- package/dist/phase-routing.js +2 -2
- package/dist/plain-schema.d.ts +23 -0
- package/dist/plain-schema.js +94 -0
- package/dist/plain-words.d.ts +20 -0
- package/dist/plain-words.js +66 -0
- package/dist/plan-login.d.ts +14 -0
- package/dist/plan-login.js +58 -0
- package/dist/planner.d.ts +1 -1
- package/dist/planner.js +4 -2
- package/dist/process-liveness.d.ts +2 -0
- package/dist/process-liveness.js +61 -17
- package/dist/project-delete-ui.d.ts +19 -2
- package/dist/project-delete-ui.js +29 -1
- package/dist/project-delete.js +14 -1
- package/dist/project-knowledge.d.ts +18 -11
- package/dist/project-knowledge.js +39 -9
- package/dist/project-learning.d.ts +2 -1
- package/dist/project-learning.js +15 -45
- package/dist/project-memory.d.ts +5 -0
- package/dist/project-memory.js +22 -2
- package/dist/project-tools.d.ts +4 -4
- package/dist/project-tools.js +23 -7
- package/dist/proof.js +30 -5
- package/dist/protected-storage-look.d.ts +1 -0
- package/dist/protected-storage-look.js +13 -0
- package/dist/protected-storage.d.ts +70 -39
- package/dist/protected-storage.js +196 -147
- package/dist/provider-auth.js +1 -1
- package/dist/provider-capture.d.ts +34 -0
- package/dist/provider-capture.js +53 -0
- package/dist/publish.js +9 -1
- package/dist/pull-request-flow.js +5 -0
- package/dist/push.d.ts +18 -2
- package/dist/push.js +40 -16
- package/dist/release-adapters.d.ts +9 -0
- package/dist/release-adapters.js +76 -0
- package/dist/release-auto.js +13 -13
- package/dist/release-card.d.ts +1 -2
- package/dist/release-card.js +11 -0
- package/dist/release-carry.d.ts +7 -2
- package/dist/release-carry.js +49 -10
- package/dist/release-cli.d.ts +4 -0
- package/dist/release-cli.js +29 -22
- package/dist/release-coverage.js +1 -1
- package/dist/release-next.d.ts +48 -0
- package/dist/release-next.js +161 -0
- package/dist/release.d.ts +20 -1
- package/dist/release.js +85 -9
- package/dist/remote-destination.d.ts +36 -0
- package/dist/remote-destination.js +217 -0
- package/dist/remote-main.d.ts +48 -0
- package/dist/remote-main.js +84 -5
- package/dist/repository-context.d.ts +3 -2
- package/dist/repository-context.js +112 -70
- package/dist/restart-certification.d.ts +1 -0
- package/dist/restart-certification.js +8 -6
- package/dist/result-acts.d.ts +27 -19
- package/dist/result-acts.js +36 -25
- package/dist/result-follow-ups.d.ts +2 -2
- package/dist/result-follow-ups.js +18 -4
- package/dist/result-review.d.ts +1 -1
- package/dist/route-change-check.d.ts +4 -0
- package/dist/route-change-check.js +13 -0
- package/dist/route-change.d.ts +22 -0
- package/dist/route-change.js +89 -0
- package/dist/route-hooks.js +3 -2
- package/dist/route-results.d.ts +6 -1
- package/dist/route-results.js +14 -5
- package/dist/run-closeout.d.ts +1 -1
- package/dist/run-closeout.js +7 -5
- package/dist/runner-process.js +3 -2
- package/dist/runner.js +2 -1
- package/dist/scope.d.ts +28 -4
- package/dist/scope.js +92 -28
- package/dist/scout.d.ts +1 -1
- package/dist/scout.js +2 -1
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +26 -18
- package/dist/server/chat.js +16 -14
- package/dist/server/chrome.d.ts +1 -1
- package/dist/server/chrome.js +26 -35
- package/dist/server/console.css +73 -0
- package/dist/server/guards.js +3 -0
- package/dist/server/home.d.ts +6 -0
- package/dist/server/home.js +21 -13
- package/dist/server/http.js +1 -1
- package/dist/server/kit.js +1 -1
- package/dist/server/merge-ready-view.d.ts +10 -0
- package/dist/server/merge-ready-view.js +30 -0
- package/dist/server/pages-assets.d.ts +1 -0
- package/dist/server/pages-assets.js +8 -5
- package/dist/server/pages.js +103 -82
- package/dist/server/render-chat.js +16 -3
- package/dist/server/render-code-map.d.ts +30 -0
- package/dist/server/render-code-map.js +137 -0
- package/dist/server/render-flaky.d.ts +20 -0
- package/dist/server/render-flaky.js +59 -0
- package/dist/server/render-follow-through.d.ts +11 -0
- package/dist/server/render-follow-through.js +68 -0
- package/dist/server/render-history.js +1 -1
- package/dist/server/render-new-task.d.ts +26 -1
- package/dist/server/render-new-task.js +30 -5
- package/dist/server/render-pages.d.ts +1 -175
- package/dist/server/render-pages.js +38 -313
- package/dist/server/render-projects.d.ts +2 -1
- package/dist/server/render-projects.js +9 -7
- package/dist/server/render-release.d.ts +2 -0
- package/dist/server/render-release.js +3 -3
- package/dist/server/render-results.d.ts +2 -0
- package/dist/server/render-results.js +68 -68
- package/dist/server/render-tasks.d.ts +16 -2
- package/dist/server/render-tasks.js +177 -141
- package/dist/server/retired-routes.d.ts +17 -0
- package/dist/server/retired-routes.js +53 -0
- package/dist/server/route-table.d.ts +3 -0
- package/dist/server/route-table.js +48 -12
- package/dist/server/settings.js +166 -34
- package/dist/server/task-views.js +66 -26
- package/dist/server/tasks.d.ts +2 -6
- package/dist/server/tasks.js +250 -321
- package/dist/server/welcome.js +1 -1
- package/dist/settings-groups-ui.d.ts +1 -0
- package/dist/settings-groups-ui.js +4 -2
- package/dist/settings-kit.js +3 -2
- package/dist/settings-proofs.js +3 -1
- package/dist/slack-chat.js +14 -1
- package/dist/steer-mailbox.d.ts +8 -1
- package/dist/steer-mailbox.js +164 -6
- package/dist/stop-proof.js +6 -4
- package/dist/storage-sweep-process.js +1 -1
- package/dist/storage-sweep.d.ts +5 -3
- package/dist/storage-sweep.js +30 -9
- package/dist/storage-ui.js +28 -17
- package/dist/storage.d.ts +27 -2
- package/dist/storage.js +39 -2
- package/dist/store.d.ts +89 -7
- package/dist/store.js +386 -114
- package/dist/surface.js +67 -6
- package/dist/sweep-quarantine.d.ts +1 -0
- package/dist/sweep-quarantine.js +6 -4
- package/dist/tamper-scan.d.ts +4 -0
- package/dist/tamper-scan.js +90 -0
- package/dist/task-aliases.d.ts +5 -0
- package/dist/task-aliases.js +9 -0
- package/dist/task-control.d.ts +2 -1
- package/dist/task-control.js +4 -1
- package/dist/task-outcome-cli.d.ts +2 -0
- package/dist/task-outcome-cli.js +17 -17
- package/dist/task-sizing.d.ts +5 -0
- package/dist/task-sizing.js +2 -0
- package/dist/task-source.d.ts +7 -0
- package/dist/task-source.js +14 -0
- package/dist/task-status.d.ts +9 -0
- package/dist/task-status.js +45 -49
- package/dist/teardown-git.d.ts +18 -0
- package/dist/teardown-git.js +105 -21
- package/dist/telegram-lead.js +23 -6
- package/dist/telegram-progress.js +5 -3
- package/dist/telegram-status.js +6 -4
- package/dist/telegram.js +12 -1
- package/dist/test-infra.d.ts +8 -0
- package/dist/test-infra.js +18 -0
- package/dist/tidy.js +1 -1
- package/dist/toolroll-update.js +19 -5
- package/dist/tui-contract.d.ts +24 -0
- package/dist/tui-source.js +67 -8
- package/dist/tui.js +51 -51
- package/dist/vanished-retry.d.ts +30 -0
- package/dist/vanished-retry.js +174 -0
- package/dist/work-index.d.ts +2 -0
- package/dist/work-index.js +95 -66
- package/dist/work-summary.d.ts +1 -1
- package/dist/work-summary.js +7 -2
- package/dist/workspace-ui.d.ts +7 -3
- package/dist/workspace-ui.js +38 -23
- package/dist/worktree.d.ts +12 -3
- package/dist/worktree.js +91 -14
- package/package.json +2 -1
- package/dist/server/render-next.d.ts +0 -63
- package/dist/server/render-next.js +0 -109
package/dist/scout.js
CHANGED
|
@@ -27,6 +27,7 @@ import { scoutHandbackSchema } from "./contracts/scout-report.js";
|
|
|
27
27
|
import { parseReport, REPORT_IMAGE_FILE, REPORT_LIMITS, REPORT_VERSION, SCOUT_OUTPUT_JSON_SCHEMA } from "./scout-report.js";
|
|
28
28
|
import { TOKEN_ENVS as TELEGRAM_TOKEN_ENVS } from "./telegram.js";
|
|
29
29
|
import { evidenceRoot, mailboxName, quarantineMailboxes, readMailbox, reportFileName, SCREENSHOT_BYTE_CAP, storeEvidence, validateScreenshotBytes, writeEvidenceFile, } from "./evidence.js";
|
|
30
|
+
import { gitFailureWords } from "./builder.js";
|
|
30
31
|
import { MARKER as LEASE_MARKER } from "./worktree.js";
|
|
31
32
|
import { liveLogContext } from "./live-detail.js";
|
|
32
33
|
import { openLiveLog } from "./live.js";
|
|
@@ -251,7 +252,7 @@ async function scoutWith(store, request, outputDir) {
|
|
|
251
252
|
}
|
|
252
253
|
const revision = await git(GIT, ["--no-optional-locks", "rev-parse", "HEAD"], { cwd: worktree });
|
|
253
254
|
if (revision.code !== 0) {
|
|
254
|
-
return { ok: false, kind: "failure", reason: "git", message: `could not read the base revision in ${worktree}` };
|
|
255
|
+
return { ok: false, kind: "failure", reason: "git", message: `could not read the base revision in ${worktree} (${gitFailureWords(revision)})` };
|
|
255
256
|
}
|
|
256
257
|
const baseRevision = revision.stdout.trim();
|
|
257
258
|
store.stampRun(request.runId, { baseRevision });
|
package/dist/serve.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export declare function createDecisionServer(options: ServeOptions): DecisionSer
|
|
|
4
4
|
export { PAGE_CSS, pinnedTheme, SENSITIVE_INPUT } from "./server/chrome.js";
|
|
5
5
|
export { redactedPath, SHUTDOWN_WAIT_MS, type ServeOptions } from "./server/http.js";
|
|
6
6
|
export { TASK_COMPOSER_MODES, type TaskComposerMode } from "./server/render-chat.js";
|
|
7
|
-
export {
|
|
7
|
+
export { queueScript } from "./server/render-pages.js";
|
|
8
8
|
export { ssoStepUps, wrongHostPage } from "./server/render-people.js";
|
|
9
9
|
export { diffFileAnchor, editorFileHref, needActionOf, orderChangedFiles, plainConclusionOf, rankReviewQueue, reviewFilePriority, reviewPriorityOf, runFactsFragment, withinSignedTouches, type ReviewFileRow, type ReviewPriority, type ReviewQueueFacts } from "./server/render-results.js";
|
|
10
10
|
export { decisionAnswerScript, earlierVersionsWords, revisionLineageWords, type RouteView } from "./server/render-tasks.js";
|
package/dist/serve.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { secretFolder } from "./tool-secret-store.js";
|
|
2
|
+
import { fallbackSettingOf } from "./fallback.js";
|
|
2
3
|
import { acceptedIdentities, recoverLearning } from "./project-learning.js";
|
|
3
4
|
import { consoleFolderGate, syncProjectIdentities } from "./project-identity.js";
|
|
4
5
|
import { inFolderScope } from "./folder-gate.js";
|
|
@@ -108,6 +109,7 @@ import { keepSlowRequest, Timeline } from "./latency-timeline.js";
|
|
|
108
109
|
import { readFileSync } from "node:fs";
|
|
109
110
|
import { createServer } from "node:http";
|
|
110
111
|
import { homedir, hostname } from "node:os";
|
|
112
|
+
import { sameMachineHost } from "./machine-identity.js";
|
|
111
113
|
import { dirname, join } from "node:path";
|
|
112
114
|
import { pinnedAccent } from "./accent-colors.js";
|
|
113
115
|
import { CHAT_KEY_ENV, credentialKeyOf, fetchOpenRouterCatalog, isSubscriptionChatProvider, priceForConfig, subscriptionCredentialKey } from "./converse.js";
|
|
@@ -506,6 +508,7 @@ export function createDecisionServer(options) {
|
|
|
506
508
|
builds: projectBuildsOf(repo, who),
|
|
507
509
|
access: projectAccessOf(repo),
|
|
508
510
|
network: { setting: store.projectNetwork(repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
|
|
511
|
+
fallback: { setting: fallbackSettingOf(store, repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
|
|
509
512
|
writes: { setting: store.projectWrites(repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
|
|
510
513
|
sandbox: { setting: store.projectSandbox(repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
|
|
511
514
|
checkAccess: {
|
|
@@ -1109,7 +1112,7 @@ export function createDecisionServer(options) {
|
|
|
1109
1112
|
// A project link is a read context, not a session-changing operation.
|
|
1110
1113
|
// Prove it against both admission and the known project catalog before
|
|
1111
1114
|
// collection queries; unknown/foreign paths reveal no work.
|
|
1112
|
-
if ((route.id === 'work' || route.id === 'system') && url.searchParams.has('project')) {
|
|
1115
|
+
if ((route.id === 'tasks' || route.id === 'work' || route.id === 'system') && url.searchParams.has('project')) {
|
|
1113
1116
|
const wanted = url.searchParams.get('project') ?? '';
|
|
1114
1117
|
if (url.searchParams.getAll('project').length !== 1 || !visible(wanted) ||
|
|
1115
1118
|
![...managedRepos(), ...store.listProjects().map(one => one.path)].includes(wanted)) {
|
|
@@ -1128,7 +1131,9 @@ export function createDecisionServer(options) {
|
|
|
1128
1131
|
project = wanted;
|
|
1129
1132
|
}
|
|
1130
1133
|
// All projects, asked for by name on Tasks (its project filter): the rolled-up list, admission-bound as ever.
|
|
1131
|
-
|
|
1134
|
+
// Tasks (P1.4) says every project as scope=all; an old link's all=1 still reads so.
|
|
1135
|
+
if (route.id === 'tasks' && !url.searchParams.has('project') && ((url.searchParams.get('scope') === 'all' && url.searchParams.getAll('scope').length === 1)
|
|
1136
|
+
|| (url.searchParams.get('all') === '1' && url.searchParams.getAll('all').length === 1)))
|
|
1132
1137
|
project = null;
|
|
1133
1138
|
// Every page's Tasks count covers this one project view, whatever project the page itself shows.
|
|
1134
1139
|
const facts = requestContext.getStore();
|
|
@@ -1145,7 +1150,7 @@ export function createDecisionServer(options) {
|
|
|
1145
1150
|
const namedProject = url.searchParams.get("project");
|
|
1146
1151
|
if (url.searchParams.getAll("result").length !== 1 || url.searchParams.getAll("run").length > 1 || url.searchParams.getAll("project").length > 1 ||
|
|
1147
1152
|
(namedProject !== null && (ref === null || !visible(ref.repo) || namedProject !== ref.repo))) {
|
|
1148
|
-
return refuse(response, who, 404, "No such result in your projects.", "/
|
|
1153
|
+
return refuse(response, who, 404, "No such result in your projects.", "/tasks");
|
|
1149
1154
|
}
|
|
1150
1155
|
if (who.via === "cookie" && ref !== null && visible(ref.repo))
|
|
1151
1156
|
project = ref.repo;
|
|
@@ -1171,7 +1176,7 @@ export function createDecisionServer(options) {
|
|
|
1171
1176
|
const needsProject = who.via === "cookie" && project === null && !unscopedMode &&
|
|
1172
1177
|
route.needsProject &&
|
|
1173
1178
|
!(route.id === "review" && url.searchParams.has("result")) &&
|
|
1174
|
-
!(route.id === "board" && url.searchParams.get("scope") === "all");
|
|
1179
|
+
!(route.id === "board" && url.searchParams.get("scope") === "all") && !(route.id === "tasks" && url.searchParams.get("scope") === "all");
|
|
1175
1180
|
if (needsProject)
|
|
1176
1181
|
return redirect(response, `/projects?return=${encodeURIComponent(safeReturn(url.pathname + url.search))}`);
|
|
1177
1182
|
return dispatchConsole(route, { url, who, request, response, route, now, project, chosenProject, posted: new URLSearchParams() });
|
|
@@ -1201,9 +1206,10 @@ export function createDecisionServer(options) {
|
|
|
1201
1206
|
const here = hostname();
|
|
1202
1207
|
const registered = store.listRunners().filter(one => one.retiredAt === null);
|
|
1203
1208
|
const workers = registered.filter(one => runnerAlive(one, now));
|
|
1204
|
-
|
|
1209
|
+
// This machine under any of its own names (machine-identity.ts): a hostname that moved with the network is still here.
|
|
1210
|
+
if (workers.some(one => !sameMachineHost(one.host, here) && store.providerReadiness(one.name).some(seen => seen.state === "ready")))
|
|
1205
1211
|
return true;
|
|
1206
|
-
return options.localRunner !== undefined || registered.length === 0 || workers.some(one => one.host
|
|
1212
|
+
return options.localRunner !== undefined || registered.length === 0 || workers.some(one => sameMachineHost(one.host, here)) ? localAgentSignedIn() : false;
|
|
1207
1213
|
}
|
|
1208
1214
|
let localSignIn = null;
|
|
1209
1215
|
let localSignInChecking = null;
|
|
@@ -1495,15 +1501,15 @@ export function createDecisionServer(options) {
|
|
|
1495
1501
|
function paletteIndexTag(project) {
|
|
1496
1502
|
const admitted = project === null ? admissionList() : null;
|
|
1497
1503
|
const entries = [
|
|
1498
|
-
{ label: "tasks", href: "/
|
|
1499
|
-
{ label: "needs you", href: "/
|
|
1500
|
-
{ label: "
|
|
1501
|
-
{ label: "board", href: "/board
|
|
1504
|
+
{ label: "tasks", href: "/tasks" },
|
|
1505
|
+
{ label: "needs you", href: "/tasks?view=needs-you" },
|
|
1506
|
+
{ label: "home", href: "/" },
|
|
1507
|
+
{ label: "board", href: "/tasks?view=board&scope=all" },
|
|
1502
1508
|
{ label: "queue", href: QUEUE_VIEW },
|
|
1503
|
-
{ label: "
|
|
1509
|
+
{ label: "every project", href: "/tasks?scope=all" },
|
|
1504
1510
|
{ label: "flows", href: "/flows" },
|
|
1505
|
-
{ label: "
|
|
1506
|
-
{ label: "review
|
|
1511
|
+
{ label: "finished", href: "/tasks?view=done" },
|
|
1512
|
+
{ label: "ready for review", href: "/tasks?view=ready" },
|
|
1507
1513
|
{ label: "fleet", href: "/fleet" },
|
|
1508
1514
|
{ label: "activity", href: "/activity" },
|
|
1509
1515
|
{ label: "action ledger", href: "/ledger" },
|
|
@@ -1518,8 +1524,8 @@ export function createDecisionServer(options) {
|
|
|
1518
1524
|
entries.push({ label: `${one.id} — ${one.title}`, href: `/t/${encodeURIComponent(one.id)}` });
|
|
1519
1525
|
}
|
|
1520
1526
|
const saturated = open.length > 200;
|
|
1521
|
-
const safeEntries = restricted() ? entries.filter(one => ["/
|
|
1522
|
-
return jsonScript(saturated ? [...safeEntries, { label: "… more in Tasks", href: "/
|
|
1527
|
+
const safeEntries = restricted() ? entries.filter(one => ["/tasks", "/tasks?view=needs-you", "/", "/tasks?view=board", "/flows", "/tasks?view=done", "/tasks?view=ready", "/runs", "/projects", "/ledger"].includes(one.href) || one.href.startsWith("/t/")) : entries;
|
|
1528
|
+
return jsonScript(saturated ? [...safeEntries, { label: "… more in Tasks", href: "/tasks" }] : safeEntries, { id: "palette-index" });
|
|
1523
1529
|
}
|
|
1524
1530
|
/**
|
|
1525
1531
|
* The palette cache (arc 4, finding 6), and its honest contract: a
|
|
@@ -1710,7 +1716,7 @@ export function createDecisionServer(options) {
|
|
|
1710
1716
|
needsYou: { count: needsYou, saturated: s.chrome.inboxSaturated === true, scope: tasksProject ?? null,
|
|
1711
1717
|
label: s.chrome.inboxLabel ?? `${needsYou} ${needsYou === 1 ? 'needs' : 'need'} you`,
|
|
1712
1718
|
// Every project, said by name (all=1), so a session's own open project never narrows the list the count opens.
|
|
1713
|
-
href: tasksProject === null ? '/
|
|
1719
|
+
href: tasksProject === null ? '/tasks?scope=all&view=needs-you' : `/tasks?project=${encodeURIComponent(tasksProject)}&view=needs-you` },
|
|
1714
1720
|
chats,
|
|
1715
1721
|
// The same count per project (the rail's project rows), read from the same work index totals.
|
|
1716
1722
|
...(() => { if (sensitive)
|
|
@@ -1753,7 +1759,9 @@ export function createDecisionServer(options) {
|
|
|
1753
1759
|
// A page with its own view keeps its script; the chat page runs the result script.
|
|
1754
1760
|
const functional = conversation === null || extras.view ? (s.functional?.script ?? '') : RESULT_REVIEW_SCRIPT;
|
|
1755
1761
|
const document = shell(s.title, s.body, { chrome: s.chrome, sensitive });
|
|
1756
|
-
|
|
1762
|
+
// The keys and their list (keymap.ts) work here as on every chromed page; the list sits beside the app React owns.
|
|
1763
|
+
// A sensitive page keeps to its own script.
|
|
1764
|
+
return page(response, status, browserWorkspaceDocument(document, workspace, nonce, functional + MOBILE_VIEWPORT_SCRIPT + keyFill + (sensitive ? '' : chromeScript()), sensitive ? html `` : KBD_HELP), nonce, true);
|
|
1757
1765
|
}
|
|
1758
1766
|
// A one-time secret on screen (a token, an invite link, a pairing code): the
|
|
1759
1767
|
// page carries no script of any kind, so it leaves the workspace for a
|
|
@@ -2485,7 +2493,7 @@ export function createDecisionServer(options) {
|
|
|
2485
2493
|
export { PAGE_CSS, pinnedTheme, SENSITIVE_INPUT } from "./server/chrome.js";
|
|
2486
2494
|
export { redactedPath, SHUTDOWN_WAIT_MS } from "./server/http.js";
|
|
2487
2495
|
export { TASK_COMPOSER_MODES } from "./server/render-chat.js";
|
|
2488
|
-
export {
|
|
2496
|
+
export { queueScript } from "./server/render-pages.js";
|
|
2489
2497
|
export { ssoStepUps, wrongHostPage } from "./server/render-people.js";
|
|
2490
2498
|
export { diffFileAnchor, editorFileHref, needActionOf, orderChangedFiles, plainConclusionOf, rankReviewQueue, reviewFilePriority, reviewPriorityOf, runFactsFragment, withinSignedTouches } from "./server/render-results.js";
|
|
2491
2499
|
export { decisionAnswerScript, earlierVersionsWords, revisionLineageWords } from "./server/render-tasks.js";
|
package/dist/server/chat.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { freshFacts,
|
|
1
|
+
import { freshFacts, freshnessFor, spendingOnlyOnSuccess, withFreshness } from "../scope.js";
|
|
2
|
+
import { approvalPasswordField } from "../approval-password.js";
|
|
2
3
|
import { CHAT_ACTION_LOCAL_ACTS, localOwnerRefusal } from "../local-owner.js";
|
|
3
|
-
import { localApprovalEligible } from "../scope.js";
|
|
4
4
|
import { handlersOf } from './handler-registry.js';
|
|
5
5
|
import { DEPRECATED_PAGE } from "../deprecations.js";
|
|
6
6
|
/** chat handlers, moved without changing their route bodies. */
|
|
@@ -170,7 +170,7 @@ export function createChatHandlers(runtime) {
|
|
|
170
170
|
const requestedRevision = url.searchParams.get("revision");
|
|
171
171
|
if (requestedRevision !== null) {
|
|
172
172
|
if (focusTask === null || !focusTask.family.versions.some(one => one.id === requestedRevision) || url.searchParams.has("result")) {
|
|
173
|
-
return refuse(response, who, 404, "That revision is not available for this task.", "/
|
|
173
|
+
return refuse(response, who, 404, "That revision is not available for this task.", "/tasks");
|
|
174
174
|
}
|
|
175
175
|
if (requestedRevision !== focusTask.executionId)
|
|
176
176
|
return redirect(response, `${taskHref(focusTask.id)}?version=${encodeURIComponent(requestedRevision)}`);
|
|
@@ -402,20 +402,22 @@ export function createChatHandlers(runtime) {
|
|
|
402
402
|
const evidenceLink = action.operation === 'result_accept' ? html `<a href="/r/${Number(action.request['run'])}">Inspect this result</a>` : '';
|
|
403
403
|
// Cockpit B2: approving standard work may stand on a password remembered on this session, exactly as on the task
|
|
404
404
|
// page (the same rule approve() applies when the form comes back); the field then may be left empty.
|
|
405
|
+
// The one password rule every approve form reads (approval-password.ts).
|
|
405
406
|
const freshSince = (() => {
|
|
406
407
|
const task = typeof action.request['task'] === 'string' ? action.request['task'] : null;
|
|
407
408
|
if (action.operation !== 'scope_approve' || task === null)
|
|
408
409
|
return null;
|
|
409
410
|
const scope = store.getScope(task), fresh = withFreshness('approve-standard', () => freshnessFor(who.name, Date.now(), true));
|
|
410
|
-
if (scope === null
|
|
411
|
+
if (scope === null)
|
|
411
412
|
return null;
|
|
412
|
-
const
|
|
413
|
-
return
|
|
413
|
+
const field = approvalPasswordField(store, { name: who.name, taskId: task, scope, passwordless: false, localOwner: false, freshAt: fresh?.at ?? null, returnTo: '/chat' });
|
|
414
|
+
return field.field === 'remembered' ? new Date(field.since) : null;
|
|
414
415
|
})();
|
|
415
416
|
// Easy-start C5: a laptop's local owner confirms its own acts without a password (an approval only when it is
|
|
416
417
|
// eligible: localApprovalEligible, the rule the seal applies again); anything else says how to get a password.
|
|
417
418
|
const reviewTask = typeof action.request['task'] === 'string' ? action.request['task'] : null;
|
|
418
|
-
const
|
|
419
|
+
const localScope = reviewTask === null ? null : store.getScope(reviewTask);
|
|
420
|
+
const localOk = who.authority === 'local-owner' && CHAT_ACTION_LOCAL_ACTS[action.operation] !== null && (action.operation !== 'scope_approve' || (reviewTask !== null && localScope !== null && approvalPasswordField(store, { name: who.name, taskId: reviewTask, scope: localScope, passwordless: false, localOwner: true, freshAt: null, returnTo: '/chat' }).field === 'none'));
|
|
419
421
|
const localWords = who.authority === 'local-owner' && !localOk ? localOwnerRefusal(store.accountOf(who.name)?.passwordSet === true, '/chat') : null;
|
|
420
422
|
const passwordField = !CHAT_ACTIONS[action.operation].password || localOk ? '' : localWords !== null ? html `<p class="approval-password-note">${localWords.message} <a href="${localWords.href}">${localWords.action}</a></p>` : reauth(freshSince === null
|
|
421
423
|
? html `<label>Your password<input type="password" name="token" autocomplete="current-password" required></label>`
|
|
@@ -788,7 +790,7 @@ export function createChatHandlers(runtime) {
|
|
|
788
790
|
}
|
|
789
791
|
// A scope approval's re-check is spent only if the whole confirmation commits (one transaction: the proposal's
|
|
790
792
|
// settlement included). Any other action spends it whatever comes of it (its effects aren't all in the database).
|
|
791
|
-
const confirmIt = () => confirmLeadProposal(store, principal, id, now, { authority: who.authority, chatProvider: teamChatProvider, confirm: body.get("confirm") === "yes", via: "web", evidenceRoot, ...(body.has("nonce") ? { actionReview: { nonce: body.get("nonce") ?? "", password: body.get("token") ?? "" } } : {}) });
|
|
793
|
+
const confirmIt = () => confirmLeadProposal(store, principal, id, now, { authority: who.authority, chatProvider: teamChatProvider, confirm: body.get("confirm") === "yes", via: "web", person: who.via === "cookie", evidenceRoot, ...(body.has("nonce") ? { actionReview: { nonce: body.get("nonce") ?? "", password: body.get("token") ?? "" } } : {}) });
|
|
792
794
|
const proposed = store.getLeadProposal(id);
|
|
793
795
|
const approving = proposed?.kind === "action" && sharedActionPayload(proposed.payload)?.operation === "scope_approve";
|
|
794
796
|
const outcome = approving ? spendingOnlyOnSuccess(confirmIt, result => !result.ok || ("already" in result && result.already === true)) : confirmIt();
|
|
@@ -830,7 +832,7 @@ export function createChatHandlers(runtime) {
|
|
|
830
832
|
}
|
|
831
833
|
if (outcome.ok && outcome.kind === "task_action" && outcome.taskId !== null) {
|
|
832
834
|
const proposal = store.getLeadProposal(id);
|
|
833
|
-
if (proposal.payload["operation"] === "resume") {
|
|
835
|
+
if (proposal.payload["operation"] === "resume" && who.via !== "cookie") {
|
|
834
836
|
return armTaskResume(response, who, outcome.taskId, String(proposal.payload["run"]), "chat", now);
|
|
835
837
|
}
|
|
836
838
|
return redirect(response, `${proposalTaskHref(outcome.taskId)}#task-chat-live`);
|
|
@@ -1471,11 +1473,11 @@ export function createChatHandlers(runtime) {
|
|
|
1471
1473
|
const all = view("all"), needs = view("needs-you"), done = view("completed");
|
|
1472
1474
|
const weekAgo = new Date(now.getTime() - 7 * 86_400_000).toISOString();
|
|
1473
1475
|
const counts = [
|
|
1474
|
-
{ key: "working", label: "Working now", value: agents.length, href: "/
|
|
1476
|
+
{ key: "working", label: "Working now", value: agents.length, href: "/tasks?view=running" },
|
|
1475
1477
|
// Each by its shared headline, as the Tasks list words it: a result whose checks failed waits on you, it isn't ready.
|
|
1476
|
-
{ key: "waiting", label: "Waiting on you", value: needs.items.filter(one => one.status.label !== "Ready for review").length, href: "/
|
|
1477
|
-
{ key: "ready", label: "Ready to review", value: needs.items.filter(one => one.status.label === "Ready for review").length, href: "/
|
|
1478
|
-
{ key: "done", label: "Done this week", value: done.items.filter(one => (one.completion?.at ?? one.updatedAt) >= weekAgo).length, href: "/
|
|
1478
|
+
{ key: "waiting", label: "Waiting on you", value: needs.items.filter(one => one.status.label !== "Ready for review").length, href: "/tasks?view=needs-you" },
|
|
1479
|
+
{ key: "ready", label: "Ready to review", value: needs.items.filter(one => one.status.label === "Ready for review").length, href: "/tasks?view=needs-you" },
|
|
1480
|
+
{ key: "done", label: "Done this week", value: done.items.filter(one => (one.completion?.at ?? one.updatedAt) >= weekAgo).length, href: "/tasks?view=completed" },
|
|
1479
1481
|
];
|
|
1480
1482
|
const tabOf = (one) => one.assignmentState === "ready-to-check" ? one.status.label === "Ready for review" ? "ready" : "needs-you"
|
|
1481
1483
|
: one.assignmentState === "needs-decision" ? "needs-you" : one.assignmentState === "working" || one.assignmentState === "checking" ? "running" : "finished";
|
|
@@ -1494,7 +1496,7 @@ export function createChatHandlers(runtime) {
|
|
|
1494
1496
|
const lead = activity === null ? null : { name: activity.name, doing: activity.doing, at: activity.at,
|
|
1495
1497
|
href: leadTask == null || !admitted(leadTask.repo) ? null : taskHref(familyOf(activity.taskId)?.root.id ?? activity.taskId) };
|
|
1496
1498
|
return {
|
|
1497
|
-
agents, counts, catchUp, allHref: "/
|
|
1499
|
+
agents, counts, catchUp, allHref: "/tasks", ...(lead === null ? {} : { lead }),
|
|
1498
1500
|
planUse: (windows?.tiles ?? []).map(one => ({ name: one.name, window: one.window, percent: one.percent, detail: one.detail, tone: one.tone })),
|
|
1499
1501
|
};
|
|
1500
1502
|
}
|
package/dist/server/chrome.d.ts
CHANGED
|
@@ -264,7 +264,7 @@ export declare const TO_FRONT_ICON: Html;
|
|
|
264
264
|
* wear an icon each; the foot's list stays text, the way Linear's does. */
|
|
265
265
|
export declare const strokeIcon: (paths: Html | string) => Html;
|
|
266
266
|
/** Where the queue lives now: the board, flipped to dispatch order. */
|
|
267
|
-
export declare const QUEUE_VIEW = "/
|
|
267
|
+
export declare const QUEUE_VIEW = "/tasks?view=order";
|
|
268
268
|
export declare const FOLDER_PATHS: Html;
|
|
269
269
|
export declare const CHAT_PATHS: Html;
|
|
270
270
|
export declare const WORK_PATHS: Html;
|
package/dist/server/chrome.js
CHANGED
|
@@ -14,6 +14,7 @@ import { DISCLOSURE_CSS } from "../disclosure.js";
|
|
|
14
14
|
import { EVIDENCE_PACK_CSS } from "../evidence-pack.js";
|
|
15
15
|
import { EXPORT_CSS } from "../export-ui.js";
|
|
16
16
|
import { START_COMMAND } from "../first-run.js";
|
|
17
|
+
import { SHORTCUTS, webKeymapScript } from "../keymap.js";
|
|
17
18
|
import { GALLERY_CSS } from "../flow-gallery-ui.js";
|
|
18
19
|
import { STARTERS_CSS } from "../flow-starters-ui.js";
|
|
19
20
|
import { FLOWS_CSS } from "../flows-ui.js";
|
|
@@ -347,8 +348,9 @@ export function chromeScript() {
|
|
|
347
348
|
`navGroups.forEach(function(g){g.addEventListener("toggle",function(){` +
|
|
348
349
|
`if(g.open){navGroups.forEach(function(o){if(o!==g)o.removeAttribute("open");});}});});` +
|
|
349
350
|
// the palette
|
|
350
|
-
|
|
351
|
-
`var
|
|
351
|
+
// No index on a workspace page: search is the workspace's own there (keymap.ts search), and the keys still work.
|
|
352
|
+
`var raw=document.getElementById("palette-index");var index=[];` +
|
|
353
|
+
`if(raw){try{index=JSON.parse(raw.textContent||"[]");}catch(e){return;}}` +
|
|
352
354
|
`var open=false,box=null,list=null,input=null,items=[],paletteBack=null;` +
|
|
353
355
|
`function close(){if(!open)return;open=false;box.remove();box=null;if(paletteBack&&paletteBack.isConnected)paletteBack.focus();paletteBack=null;}` +
|
|
354
356
|
`function go(href){location.href=href;}` +
|
|
@@ -395,23 +397,22 @@ export function chromeScript() {
|
|
|
395
397
|
`var next=at===-1?(delta>0?0:set.length-1):Math.max(0,Math.min(set.length-1,at+delta));` +
|
|
396
398
|
`if(next===at)return;` +
|
|
397
399
|
`set[next].focus();ev.preventDefault();}` +
|
|
398
|
-
// key routing: never inside editable targets, no modifiers, no IME
|
|
399
|
-
// composition (finding 4); repeats allowed only for j/k
|
|
400
|
+
// key routing (keymap.ts, one table with the terminal UI): never inside editable targets, no modifiers, no IME
|
|
401
|
+
// composition (finding 4); repeats allowed only for j/k. A press key presses only a control the page rendered.
|
|
402
|
+
webKeymapScript() +
|
|
400
403
|
`var pending=null;` +
|
|
401
404
|
`document.addEventListener("keydown",function(ev){` +
|
|
402
405
|
`if(ev.isComposing||ev.metaKey||ev.ctrlKey||ev.altKey)return;` +
|
|
403
406
|
`var t=ev.target;var tag=t&&t.tagName?t.tagName.toLowerCase():"";` +
|
|
404
|
-
`if(tag==="input"||tag==="textarea"||tag==="select"||
|
|
407
|
+
`if(tag==="input"||tag==="textarea"||tag==="select"||(t&&t.isContentEditable)||(t&&t.closest&&t.closest("[role=textbox],[role=dialog]:not(.kbd-help)")))return;` +
|
|
405
408
|
`if(ev.key==="Escape"){if(helpOpen()){toggleHelp();ev.preventDefault();return;}close();return;}` +
|
|
406
409
|
`if(helpOpen())return;` +
|
|
407
410
|
`if(ev.repeat&&ev.key!=="j"&&ev.key!=="k")return;` +
|
|
408
|
-
`if(ev.key==="/"){show();ev.preventDefault();return;}` +
|
|
409
|
-
`if(ev.key==="?"){toggleHelp();ev.preventDefault();return;}` +
|
|
410
411
|
`if(ev.key==="j"||ev.key==="k"){rove(ev.key==="j"?1:-1,ev);return;}` +
|
|
411
|
-
`if(pending==="g"){pending=null
|
|
412
|
-
`
|
|
413
|
-
`
|
|
414
|
-
`if(ev.
|
|
412
|
+
`if(pending==="g"){pending=null;var after=GKEYS[ev.key];if(after&&run(after))ev.preventDefault();return;}` +
|
|
413
|
+
`if(ev.key==="g"){pending="g";setTimeout(function(){pending=null;},800);return;}` +
|
|
414
|
+
`var act=Object.prototype.hasOwnProperty.call(KEYS,ev.key)?KEYS[ev.key]:null;` +
|
|
415
|
+
`if(act&&run(act))ev.preventDefault();});` +
|
|
415
416
|
`})();`);
|
|
416
417
|
}
|
|
417
418
|
export const ROLE_TITLES = { plan: "Planner", build: "Builder", review: "Reviewer", repair: "Repair" };
|
|
@@ -440,17 +441,7 @@ FINISH: unreviewed and undocumented is unfinished; this build ends with the fini
|
|
|
440
441
|
* absent from sensitive pages. Navigation help in plain words — no key
|
|
441
442
|
* ever posts. */
|
|
442
443
|
export const KBD_HELP = html `<div class="kbd-help" hidden role="dialog" aria-label="keyboard shortcuts" tabindex="-1">\
|
|
443
|
-
<h2>Keyboard shortcuts</h2><table
|
|
444
|
-
<tr><td><kbd>/</kbd></td><td>jump to a page or an open task</td></tr>\
|
|
445
|
-
<tr><td><kbd>g</kbd> then <kbd>i</kbd></td><td>go to the inbox</td></tr>\
|
|
446
|
-
<tr><td><kbd>g</kbd> then <kbd>b</kbd></td><td>go to the board</td></tr>\
|
|
447
|
-
<tr><td><kbd>g</kbd> then <kbd>q</kbd></td><td>go to the queue</td></tr>\
|
|
448
|
-
<tr><td><kbd>g</kbd> then <kbd>f</kbd></td><td>go to the fleet</td></tr>\
|
|
449
|
-
<tr><td><kbd>g</kbd> then <kbd>w</kbd></td><td>go to the workbench</td></tr>\
|
|
450
|
-
<tr><td><kbd>g</kbd> then <kbd>t</kbd></td><td>go to the task list</td></tr>\
|
|
451
|
-
<tr><td><kbd>g</kbd> then <kbd>a</kbd></td><td>go to the activity view</td></tr>\
|
|
452
|
-
<tr><td><kbd>g</kbd> then <kbd>p</kbd></td><td>go to the projects</td></tr>\
|
|
453
|
-
<tr><td><kbd>g</kbd> then <kbd>d</kbd></td><td>go to what is done</td></tr>\
|
|
444
|
+
<h2>Keyboard shortcuts</h2><table>${SHORTCUTS.map(one => html `<tr><td>${joinHtml(one.keys.split(" ").map(key => html `<kbd>${key}</kbd>`), " then ")}</td><td>${one.says}</td></tr>`)}\
|
|
454
445
|
<tr><td><kbd>j</kbd> / <kbd>k</kbd></td><td>move through the rows on this page</td></tr>\
|
|
455
446
|
<tr><td><kbd>Escape</kbd></td><td>close this</td></tr>\
|
|
456
447
|
</table></div>`;
|
|
@@ -513,8 +504,8 @@ ${count !== undefined && count > 0 ? html ` <span class="count badge badge-open"
|
|
|
513
504
|
const scopeStatus = peekCounts === null
|
|
514
505
|
? null
|
|
515
506
|
: html `<span class="scope-status">\
|
|
516
|
-
${peekCounts.waiting > 0 ? html `<a class="hot" href="/
|
|
517
|
-
<a href="/runs">${peekCounts.running} live</a><a href="/
|
|
507
|
+
${peekCounts.waiting > 0 ? html `<a class="hot" href="/tasks?view=needs-you">${peekCounts.waiting} needs you</a>` : html `<a href="/tasks?view=needs-you">0 needs you</a>`}\
|
|
508
|
+
<a href="/runs">${peekCounts.running} live</a><a href="/tasks?view=order">${peekCounts.queued} queued</a></span>`;
|
|
518
509
|
const scopeName = effectiveScope === "project" && chrome.project !== null ? projectName(chrome.project) : "All projects";
|
|
519
510
|
// The switcher (board pass): the scope's name opens a menu of every
|
|
520
511
|
// enrolled project — one tap to open one, or to widen to all — as plain
|
|
@@ -556,7 +547,7 @@ ${scopeStatus}</div>`;
|
|
|
556
547
|
${count !== undefined && count > 0 ? html ` <span${chrome.inboxLabel === undefined ? "" : html ` aria-label="${chrome.inboxLabel}" title="${chrome.inboxLabel}"`} class="count badge badge-open">${count}${chrome.inboxSaturated ? "+" : ""}</span>` : ""}</a>`;
|
|
557
548
|
const side = joinHtml([
|
|
558
549
|
html `<aside class="side">`,
|
|
559
|
-
html `<div class="side-head"><a class="brand" href="${chrome.chat === true ? "/chat" : "/
|
|
550
|
+
html `<div class="side-head"><a class="brand" href="${chrome.chat === true ? "/chat" : "/tasks"}"><span class="brand-long">Toolroll</span><span class="brand-short">T</span></a>`,
|
|
560
551
|
...(options.sidebarToggle === true
|
|
561
552
|
? [html `<button type="button" class="side-toggle" aria-label="collapse sidebar" aria-expanded="true" title="collapse sidebar">${strokeIcon(html `<path d="m15 18-6-6 6-6"/>`)}</button>`]
|
|
562
553
|
: []),
|
|
@@ -566,7 +557,7 @@ ${count !== undefined && count > 0 ? html ` <span${chrome.inboxLabel === undefin
|
|
|
566
557
|
// gating); Work and Projects always. Every specialist tool is a dim
|
|
567
558
|
// text row inside one of the two accordion groups below.
|
|
568
559
|
...(chrome.chat ? [primaryItem("chat", "/chat", "Chat")] : []),
|
|
569
|
-
primaryItem("work", "/
|
|
560
|
+
primaryItem("work", "/tasks", "Tasks", chrome.inboxCount),
|
|
570
561
|
primaryItem("flows", "/flows", "Flows"),
|
|
571
562
|
primaryItem("projects", "/projects", "Projects"),
|
|
572
563
|
html `</nav>`,
|
|
@@ -607,7 +598,7 @@ ${postForm(update.dismissHref, html `<button type="submit">Dismiss</button>`, {
|
|
|
607
598
|
// these only below 760px; desktop keeps the sidebar untouched.
|
|
608
599
|
const mobileTop = joinHtml([
|
|
609
600
|
html `<header class="mobile-top">`,
|
|
610
|
-
html `<a class="brand-mini" href="${chrome.chat === true ? "/chat" : "/
|
|
601
|
+
html `<a class="brand-mini" href="${chrome.chat === true ? "/chat" : "/tasks"}">T</a>`,
|
|
611
602
|
// On a phone the pill IS the scope row (mobile pass): the project's
|
|
612
603
|
// name, its three counts, and the one /projects link at that
|
|
613
604
|
// breakpoint — the scope bar hides below 760px so the header is one
|
|
@@ -640,7 +631,7 @@ ${count !== undefined && count > 0 ? html `<span class="dot-badge" role="img" ar
|
|
|
640
631
|
const tabbar = joinHtml([
|
|
641
632
|
html `<nav class="tabbar">`,
|
|
642
633
|
...(chrome.chat ? [tab("chat", "/chat", "Chat")] : []),
|
|
643
|
-
tab("work", "/
|
|
634
|
+
tab("work", "/tasks", "Tasks", chrome.inboxCount),
|
|
644
635
|
tab("flows", "/flows", "Flows"),
|
|
645
636
|
tab("projects", "/projects", "Projects"),
|
|
646
637
|
html `</nav>`,
|
|
@@ -702,7 +693,7 @@ export const TO_FRONT_ICON = html `<svg viewBox="0 0 24 24" fill="none" stroke="
|
|
|
702
693
|
* wear an icon each; the foot's list stays text, the way Linear's does. */
|
|
703
694
|
export const strokeIcon = (paths) => html `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">${paths}</svg>`;
|
|
704
695
|
/** Where the queue lives now: the board, flipped to dispatch order. */
|
|
705
|
-
export const QUEUE_VIEW = "/
|
|
696
|
+
export const QUEUE_VIEW = "/tasks?view=order";
|
|
706
697
|
export const FOLDER_PATHS = html `<path d="M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z"/>`;
|
|
707
698
|
export const CHAT_PATHS = html `<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>`;
|
|
708
699
|
export const WORK_PATHS = html `<path d="M9 6h11"/><path d="M9 12h11"/><path d="M9 18h11"/><path d="m4 6 1 1 2-2"/><path d="m4 12 1 1 2-2"/><path d="m4 18 1 1 2-2"/>`;
|
|
@@ -730,11 +721,11 @@ export function workToolRows(scoped = false, _offersChat = false, offersCode = f
|
|
|
730
721
|
// D5: coding sessions are deprecated; /code still opens this release, but nothing links to it.
|
|
731
722
|
// Live terminals: an operator's own Claude Code, Codex or shell, in a real terminal (docs/plans/live-terminal.md).
|
|
732
723
|
...(offersCode ? [{ key: "code", href: "/term", label: "Live", hint: "your own terminals: Claude Code, Codex or a shell" }] : []),
|
|
733
|
-
{ key: "inbox", href: "/
|
|
734
|
-
{ key: "board", href: "/board", label: "Board", hint: "lanes by state, with the order view" },
|
|
735
|
-
{ key: "tasks", href: "/
|
|
724
|
+
{ key: "inbox", href: "/", label: "Home", hint: "what needs you, what runs, and what waits" },
|
|
725
|
+
{ key: "board", href: "/tasks?view=board", label: "Board", hint: "lanes by state, with the order view" },
|
|
726
|
+
{ key: "tasks", href: "/tasks", label: "Task list", hint: "everything, filterable by state" },
|
|
736
727
|
{ key: "recipes", href: "/recipes", label: "Recipes", hint: "choose, customize, and reuse a workflow" },
|
|
737
|
-
{ key: "workbench", href: "/
|
|
728
|
+
{ key: "workbench", href: "/tasks?scope=all", label: "Every project", hint: "every project's tasks in one list" },
|
|
738
729
|
{ key: "ledger", href: "/ledger", label: "Action ledger", hint: "who acted, what happened, and the result" },
|
|
739
730
|
{ key: "spend", href: "/spend", label: "Spend", hint: "what agent work cost, and monthly budgets" },
|
|
740
731
|
];
|
|
@@ -759,8 +750,8 @@ export const SETTINGS_KEYS = new Set(["settings", "fleet", "caps", "people", "mo
|
|
|
759
750
|
export function buildsViews(current) {
|
|
760
751
|
const views = [
|
|
761
752
|
["builds", "/runs", "builds"],
|
|
762
|
-
["done", "/done", "done"],
|
|
763
|
-
["review", "/
|
|
753
|
+
["done", "/tasks?view=done", "done"],
|
|
754
|
+
["review", "/tasks?view=ready", "review"],
|
|
764
755
|
["activity", "/activity", "activity"],
|
|
765
756
|
];
|
|
766
757
|
return html `<p class="meta board-view">${joinHtml(views.map(([key, href, label]) => (key === current ? html `<strong>${label}</strong>` : html `<a href="${href}">${label}</a>`)), " \u00b7 ")}</p>`;
|
package/dist/server/console.css
CHANGED
|
@@ -1229,6 +1229,9 @@
|
|
|
1229
1229
|
.approval-field-hint { color: var(--muted-foreground); font-size: 12px; line-height: 1.5; }
|
|
1230
1230
|
.approval-field textarea, .approval-field input[type=text] { width: 100%; max-width: 75ch; margin: 0; font-family: var(--font-sans); font-size: 14px; line-height: 1.55; }
|
|
1231
1231
|
.approval-requirements { display: grid; gap: 6px; margin: 2px 0 0; padding: 0; list-style: none; }
|
|
1232
|
+
.approval-requirements li { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
|
|
1233
|
+
.approval-requirements li input[type=text] { flex: 1 1 22rem; }
|
|
1234
|
+
.approval-how { flex: 0 1 auto; max-width: 100%; min-height: 2.125rem; margin: 0; font-size: 13px; }
|
|
1232
1235
|
.approval-edit-act { display: flex; flex-wrap: wrap; align-items: center; gap: var(--so-space-sm); }
|
|
1233
1236
|
.approval-edit-act button { margin: 0; min-height: 2.125rem; white-space: nowrap; }
|
|
1234
1237
|
.approval-link { display: inline-flex; align-items: center; min-height: 32px; padding: 0 var(--so-space-md); border: 1px solid var(--border); border-radius: var(--so-radius-md); background: var(--card); color: var(--foreground); font-size: 13px; font-weight: 500; text-decoration: none; }
|
|
@@ -2793,3 +2796,73 @@ html.so-swap::view-transition-old(*):only-child { animation: so-card-out 160ms e
|
|
|
2793
2796
|
@media (max-width: 40rem) { .welcome form > .k-btn[type=submit] { width: auto; } }
|
|
2794
2797
|
/* On a phone the step's primary lives in the dock: its copy in the step is hidden. */
|
|
2795
2798
|
@media (max-width: 760px) { .welcome .k-btn.k-docked { display: none; } }
|
|
2799
|
+
|
|
2800
|
+
/* Code map: every name is repository data, however long; nothing may push the page wider. */
|
|
2801
|
+
.cm-list { list-style: none; margin: 0; padding: 0; }
|
|
2802
|
+
.cm-item { display: grid; gap: 2px; min-width: 0; padding: 10px 0; border-bottom: 1px solid var(--so-line); overflow-wrap: anywhere; }
|
|
2803
|
+
.cm-title { font-size: 13px; font-weight: 500; color: var(--so-ink); }
|
|
2804
|
+
.cm-meta { font-size: 12.5px; color: var(--so-muted); }
|
|
2805
|
+
.cm-path { overflow-wrap: anywhere; user-select: all; }
|
|
2806
|
+
.cm-search { display: flex; gap: var(--so-space-sm); align-items: center; margin: 0 0 var(--so-space-md); }
|
|
2807
|
+
.cm-search .k-input, .cm-search input[type="search"] { flex: 1 1 auto; min-width: 0; }
|
|
2808
|
+
.cm-search .k-btn { flex: 0 0 auto; white-space: nowrap; }
|
|
2809
|
+
/* A test's name is the row: it wraps whole, its facts sit under it, and the one action stays on one line. */
|
|
2810
|
+
.flaky-rows .k-row-a .k-btn { white-space: nowrap; }
|
|
2811
|
+
@media (min-width: 761px) {
|
|
2812
|
+
.flaky-rows .k-row { grid-template-columns: 96px minmax(0, 1fr) auto auto; padding-block: 10px; }
|
|
2813
|
+
.flaky-rows .k-row-t { grid-column: 2; grid-row: 1; white-space: normal; overflow-wrap: anywhere; }
|
|
2814
|
+
.flaky-rows .k-row-d { grid-column: 2; grid-row: 2; white-space: normal; }
|
|
2815
|
+
.flaky-rows .k-row-m { grid-column: 3; grid-row: 1 / span 2; }
|
|
2816
|
+
.flaky-rows .k-row-a { grid-column: 4; grid-row: 1 / span 2; }
|
|
2817
|
+
.flaky-rows .k-row-c { grid-row: 1 / span 2; }
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
/* A Toolroll card (card-render.ts): tables, charts and key facts in chat, on the console's own tokens. */
|
|
2821
|
+
.tc-card { display: grid; gap: var(--so-space-sm); min-width: 0; font-size: 13px; line-height: 1.45; color: var(--so-ink); }
|
|
2822
|
+
.tc-part { display: grid; gap: 6px; min-width: 0; }
|
|
2823
|
+
.tc-part h4 { margin: 0; font-size: 12.5px; font-weight: 600; }
|
|
2824
|
+
.tc-text { margin: 0; }
|
|
2825
|
+
/* The lead's own words in a card: set apart from the records, never styled as one. */
|
|
2826
|
+
.tc-lead { display: grid; gap: 2px; padding-left: var(--so-space-sm); border-left: 2px solid var(--so-line); font-style: italic; }
|
|
2827
|
+
.tc-lead .tc-note { font-style: normal; }
|
|
2828
|
+
.tc-note { margin: 0; font-size: 11.5px; color: var(--so-muted); }
|
|
2829
|
+
.tc-rule { width: 100%; margin: 0; border: 0; border-top: 1px solid var(--so-line); }
|
|
2830
|
+
.tc-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: var(--so-space-sm); margin: 0; }
|
|
2831
|
+
.tc-facts > div { display: grid; gap: 1px; min-width: 0; }
|
|
2832
|
+
.tc-facts dt { font-size: 11.5px; color: var(--so-muted); }
|
|
2833
|
+
.tc-facts dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
|
|
2834
|
+
.tc-scroll { max-width: 100%; overflow-x: auto; }
|
|
2835
|
+
.tc-table { width: 100%; border-collapse: collapse; }
|
|
2836
|
+
.tc-table th { font-size: 11.5px; font-weight: 500; color: var(--so-muted); text-align: left; white-space: nowrap; }
|
|
2837
|
+
.tc-table th, .tc-table td { padding: 5px var(--so-space-md) 5px 0; border-bottom: 1px solid var(--so-line); vertical-align: top; }
|
|
2838
|
+
/* Cells break between words, never inside one: a narrow screen scrolls the table (.tc-scroll) instead. */
|
|
2839
|
+
.tc-table td { overflow-wrap: break-word; }
|
|
2840
|
+
.tc-table tr:last-child td { border-bottom: 0; }
|
|
2841
|
+
.tc-table .tc-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
2842
|
+
.tc-bars { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
|
|
2843
|
+
.tc-bars li { display: grid; grid-template-columns: minmax(0, 8rem) minmax(0, 1fr) auto; gap: var(--so-space-sm); align-items: center; }
|
|
2844
|
+
.tc-bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
2845
|
+
.tc-bar-track { height: 8px; border-radius: 4px; background: var(--so-raised); }
|
|
2846
|
+
.tc-bar-fill { display: block; height: 100%; border-radius: 4px; background: var(--so-ink); }
|
|
2847
|
+
.tc-bar-value { font-variant-numeric: tabular-nums; }
|
|
2848
|
+
.tc-pie { display: flex; flex-wrap: wrap; align-items: center; gap: var(--so-space-md); }
|
|
2849
|
+
.tc-pie svg { flex: none; width: 88px; height: 88px; }
|
|
2850
|
+
.tc-legend { display: grid; flex: 1 1 140px; gap: 3px; margin: 0; padding: 0; list-style: none; }
|
|
2851
|
+
.tc-legend li { display: flex; align-items: center; gap: 6px; min-width: 0; }
|
|
2852
|
+
.tc-legend strong { margin-left: auto; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
2853
|
+
.tc-key { flex: none; width: 9px; height: 9px; border-radius: 2px; background: currentColor; }
|
|
2854
|
+
.tc-c0 { color: var(--so-ink); stroke: var(--so-ink); }
|
|
2855
|
+
.tc-c1 { color: var(--so-info); stroke: var(--so-info); }
|
|
2856
|
+
.tc-c2 { color: var(--so-success); stroke: var(--so-success); }
|
|
2857
|
+
.tc-c3 { color: var(--so-warning); stroke: var(--so-warning); }
|
|
2858
|
+
.tc-c4 { color: var(--so-danger); stroke: var(--so-danger); }
|
|
2859
|
+
.tc-c5 { color: var(--so-muted); stroke: var(--so-muted); }
|
|
2860
|
+
.tc-line { margin: 0; display: grid; gap: var(--so-space-xs); }
|
|
2861
|
+
.tc-line svg { width: 100%; height: 90px; }
|
|
2862
|
+
.tc-line figcaption { font-size: 11.5px; color: var(--so-muted); }
|
|
2863
|
+
.tc-stroke { stroke: var(--so-ink); stroke-width: 1.5; }
|
|
2864
|
+
.tc-area { fill: var(--so-raised); }
|
|
2865
|
+
.tc-notes { display: grid; gap: var(--so-space-xs); margin: 0; padding-left: var(--so-space-md); overflow-wrap: anywhere; }
|
|
2866
|
+
|
|
2867
|
+
/* The handover note wraps on a narrow screen rather than scrolling sideways. */
|
|
2868
|
+
.handover-note { white-space: pre-wrap; }
|
package/dist/server/guards.js
CHANGED
|
@@ -272,6 +272,9 @@ export function createSharedGuards(runtime) {
|
|
|
272
272
|
if (url.searchParams.get("view") === "order")
|
|
273
273
|
url.searchParams.delete("view");
|
|
274
274
|
}
|
|
275
|
+
// Tasks (P1.4) keeps the board's rule: the queue's order view stays an instance view, never a limited person's.
|
|
276
|
+
if (route.id === "tasks" && url.searchParams.get("view") === "order")
|
|
277
|
+
url.searchParams.set("view", "board");
|
|
275
278
|
return true;
|
|
276
279
|
}
|
|
277
280
|
function workAccess() {
|
package/dist/server/home.d.ts
CHANGED
|
@@ -25,6 +25,12 @@ export type HomeFacts = {
|
|
|
25
25
|
chat: boolean;
|
|
26
26
|
/** This person can answer an agent's question (an approver in a browser session). */
|
|
27
27
|
canAnswer: boolean;
|
|
28
|
+
/** Why this task's plan can't take a yes right now (render-tasks.ts consentDoorOf), or null when it can. */
|
|
29
|
+
closedDoor: (taskId: string) => {
|
|
30
|
+
title: string;
|
|
31
|
+
why: string;
|
|
32
|
+
road: "scope" | "agents";
|
|
33
|
+
} | null;
|
|
28
34
|
};
|
|
29
35
|
/** "7 need you across 2 projects." — the sentence and the figures read the same totals. */
|
|
30
36
|
export declare function homeSentence(needs: number, perProject: readonly {
|