toolroll 0.9.51 → 0.9.53
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 +20 -0
- package/README.md +55 -80
- package/dist/agentconfig.d.ts +11 -36
- package/dist/agentconfig.js +3 -62
- package/dist/approval-policy.d.ts +1 -1
- package/dist/approval-policy.js +1 -1
- package/dist/backup.d.ts +8 -0
- package/dist/backup.js +10 -1
- package/dist/board.d.ts +3 -19
- package/dist/board.js +4 -42
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +18 -18
- package/dist/browser-workspace.d.ts +3 -1
- package/dist/builder.d.ts +9 -40
- package/dist/builder.js +50 -257
- package/dist/chat-actions.js +3 -14
- package/dist/chat-controls.d.ts +0 -4
- package/dist/chat-controls.js +0 -1
- package/dist/chat-decide.js +1 -3
- package/dist/chat-delivery.d.ts +0 -2
- package/dist/chat-delivery.js +0 -1
- package/dist/chat-quiet.js +2 -2
- package/dist/chat-task-actions.d.ts +1 -1
- package/dist/chat-task-actions.js +0 -2
- package/dist/claim.d.ts +79 -244
- package/dist/claim.js +688 -1023
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +10 -2
- package/dist/contracts/cli.d.ts +0 -13
- package/dist/contracts/cli.js +0 -2
- package/dist/contracts/console-api.d.ts +5 -10
- package/dist/contracts/console-api.js +4 -10
- package/dist/contracts/flow.d.ts +50 -0
- package/dist/contracts/flow.js +26 -1
- package/dist/contracts/lead-tools.d.ts +0 -13
- package/dist/contracts/lead-tools.js +3 -3
- package/dist/contracts/store-json.d.ts +1 -25
- package/dist/contracts/store-json.js +3 -13
- package/dist/converse.d.ts +1 -11
- package/dist/converse.js +6 -38
- package/dist/coordinator.d.ts +0 -1
- package/dist/coordinator.js +3 -5
- package/dist/database-reclaim.d.ts +4 -0
- package/dist/database-reclaim.js +13 -0
- package/dist/demo.d.ts +1 -1
- package/dist/demo.js +17 -27
- package/dist/desktop-update-gate.js +0 -1
- package/dist/desktop-update.d.ts +1 -1
- package/dist/desktop-update.js +1 -3
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/dispose.d.ts +2 -3
- package/dist/dispose.js +17 -92
- package/dist/envelope.js +0 -3
- package/dist/exec.d.ts +0 -64
- package/dist/exec.js +3 -356
- package/dist/exhaustion.d.ts +22 -76
- package/dist/exhaustion.js +14 -140
- package/dist/export.js +4 -4
- package/dist/flow-engine.js +1 -1
- package/dist/flow-schedule.d.ts +154 -0
- package/dist/flow-schedule.js +321 -0
- package/dist/flow-share.js +1 -1
- package/dist/flow-triggers.d.ts +6 -1
- package/dist/flow-triggers.js +65 -10
- package/dist/flows-cli.js +8 -4
- package/dist/flows-ui.js +2 -0
- package/dist/flows.js +1 -1
- package/dist/guides.js +9 -29
- package/dist/invoke.d.ts +1 -24
- package/dist/invoke.js +17 -259
- package/dist/lead-status.js +2 -4
- package/dist/lead-voice.js +1 -1
- package/dist/live-bus.d.ts +3 -3
- package/dist/live-bus.js +3 -3
- package/dist/mate-doors.d.ts +1 -2
- package/dist/mate-doors.js +12 -25
- package/dist/mate-tools.d.ts +2 -2
- package/dist/mate-tools.js +10 -22
- package/dist/modes.d.ts +6 -7
- package/dist/modes.js +7 -13
- package/dist/monitoring.js +32 -8
- package/dist/notification-delivery.d.ts +19 -0
- package/dist/notification-delivery.js +37 -0
- package/dist/operate-remote-arguments.js +2 -6
- package/dist/operate-remote.js +6 -7
- package/dist/operate.d.ts +0 -6
- package/dist/operate.js +283 -2378
- package/dist/phase-routing.d.ts +13 -23
- package/dist/phase-routing.js +13 -35
- package/dist/plan-auto.js +2 -2
- package/dist/planner-source.js +2 -1
- package/dist/policy.d.ts +1 -4
- package/dist/policy.js +0 -8
- package/dist/process-recovery-eligibility.js +2 -3
- package/dist/process-recovery-settlement.js +1 -0
- package/dist/project-delete.js +3 -15
- package/dist/proposal.d.ts +4 -24
- package/dist/proposal.js +3 -88
- package/dist/provider-auth.d.ts +3 -3
- package/dist/provider-auth.js +4 -6
- package/dist/provider.d.ts +11 -25
- package/dist/provider.js +4 -36
- package/dist/push.js +1 -1
- package/dist/recipe-ui.js +6 -6
- package/dist/recipes.d.ts +3 -3
- package/dist/recipes.js +27 -23
- package/dist/retention.js +6 -5
- package/dist/run-closeout.d.ts +1 -1
- package/dist/run-closeout.js +1 -4
- package/dist/scope.d.ts +11 -65
- package/dist/scope.js +17 -82
- package/dist/serve.js +16 -25
- package/dist/server/chat.js +7 -30
- package/dist/server/flows.js +11 -10
- package/dist/server/guards.js +0 -1
- package/dist/server/pages-assets.js +1 -1
- package/dist/server/pages.js +0 -2
- package/dist/server/people-tokens.js +0 -4
- package/dist/server/route-table.d.ts +1 -1
- package/dist/server/route-table.js +2 -17
- package/dist/server/settings.js +4 -9
- package/dist/server/shared.d.ts +29 -212
- package/dist/server/shared.js +73 -780
- package/dist/server/task-views.js +9 -76
- package/dist/server/tasks.d.ts +1 -50
- package/dist/server/tasks.js +36 -946
- package/dist/setup-guide.d.ts +2 -2
- package/dist/slack-chat.d.ts +0 -2
- package/dist/slack-chat.js +0 -1
- package/dist/store.d.ts +142 -1382
- package/dist/store.js +900 -4083
- package/dist/surface.js +10 -25
- package/dist/task-composer.d.ts +1 -1
- package/dist/task-composer.js +1 -1
- package/dist/task-control.d.ts +3 -10
- package/dist/task-control.js +2 -7
- package/dist/teammate-desk.js +1 -1
- package/dist/teammates-ui.js +1 -1
- package/dist/telegram-mate.d.ts +0 -3
- package/dist/telegram-mate.js +0 -1
- package/dist/templates.d.ts +11 -7
- package/dist/templates.js +12 -9
- package/dist/toolroll-update.d.ts +24 -3
- package/dist/toolroll-update.js +159 -16
- package/dist/webhooks.d.ts +10 -22
- package/dist/webhooks.js +43 -81
- package/dist/work-index.js +3 -7
- package/dist/workspace-revision.d.ts +28 -1
- package/dist/workspace-revision.js +276 -49
- package/dist/workspace-ui.js +1 -1
- package/package.json +1 -3
- package/scripts/recovery-canary.mjs +3 -3
- package/dist/contest.d.ts +0 -318
- package/dist/contest.js +0 -753
- package/dist/held.d.ts +0 -150
- package/dist/held.js +0 -799
- package/dist/liveness.d.ts +0 -30
- package/dist/liveness.js +0 -42
- package/dist/pricing.d.ts +0 -45
- package/dist/pricing.js +0 -77
- package/dist/routine.d.ts +0 -228
- package/dist/routine.js +0 -764
- package/dist/supervisor.mjs +0 -297
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.53 — 2026-10-08
|
|
4
|
+
|
|
5
|
+
- **Fewer features to learn.** Contests, held sessions and fallback chains
|
|
6
|
+
are gone. Routines are now scheduled flows; existing routines migrate,
|
|
7
|
+
paused, and `toolroll routine` points you to flows.
|
|
8
|
+
- **Schedule limits hold.** Moving a flow card can't reset its spending or
|
|
9
|
+
single-flight limits.
|
|
10
|
+
|
|
11
|
+
## 0.9.52 — 2026-10-07
|
|
12
|
+
|
|
13
|
+
- **Smaller database.** Process logs are compacted after each run, so the
|
|
14
|
+
database file shrinks (one install went from about 116 MB to 26 MB), and
|
|
15
|
+
backups shrink with it. The action ledger is checkpointed automatically.
|
|
16
|
+
- **Lighter under the hood.** Update checks read history with bounded memory,
|
|
17
|
+
and live views update without database triggers.
|
|
18
|
+
- **Honest release check.** It runs every unit test on 8 workers, and its
|
|
19
|
+
tests check behaviour at runtime instead of reading source text.
|
|
20
|
+
- **Webhook alerts keep working.** Legacy Slack and Discord webhooks still
|
|
21
|
+
send this release, with a notice pointing to Chat settings.
|
|
22
|
+
|
|
3
23
|
## 0.9.51 — 2026-10-07
|
|
4
24
|
|
|
5
25
|
- **No lockout by username.** Wrong passwords slow the source that sent them,
|
package/README.md
CHANGED
|
@@ -163,7 +163,10 @@ failed when a result is marked complete.
|
|
|
163
163
|
- **Triggers start cards on their own.** A button with a few questions, a
|
|
164
164
|
schedule, GitHub (new issues, a label being added, new pull requests,
|
|
165
165
|
failed checks), Linear (a team, a state, a label), or another flow's cards
|
|
166
|
-
reaching a zone.
|
|
166
|
+
reaching a zone. A schedule can carry a standing order — the exact task to
|
|
167
|
+
file each time, with its own per-run budget and a rolling 7-day cost
|
|
168
|
+
ceiling — and runs one at a time, skipping while the last task is
|
|
169
|
+
unfinished. GitHub is checked through your `gh` login and Linear
|
|
167
170
|
with an API key kept on this computer; neither spends model tokens. Each
|
|
168
171
|
issue or run makes at most one card; text from outside the repository's
|
|
169
172
|
team is left out unless you say anyone. With a public address, GitHub,
|
|
@@ -361,7 +364,7 @@ for people splitting those parts across machines.
|
|
|
361
364
|
mandatory review step. Older results retain their own links.
|
|
362
365
|
|
|
363
366
|
Specialized views remain in **Tools** and **Settings**: the activity ledger, the review cockpit,
|
|
364
|
-
|
|
367
|
+
the fleet,
|
|
365
368
|
people (invite a second approver), the operating mode (a signed, expiring
|
|
366
369
|
envelope that pre-approves your own filings), and **chat** — the mate, one
|
|
367
370
|
conversation across every project, which only ever proposes.
|
|
@@ -597,16 +600,17 @@ deployment require their own authority and checks.
|
|
|
597
600
|
|
|
598
601
|
Which agent plans, builds, and repairs a task is decided once, from
|
|
599
602
|
signed facts, and written down with its reasons. The route reads the task's
|
|
600
|
-
|
|
603
|
+
**size** (small, medium, large, risky or not), its quality mode, what the
|
|
601
604
|
acceptance rubric demands (screenshots, manual review), how far a live
|
|
602
|
-
operating mode may carry the result unattended,
|
|
605
|
+
operating mode may carry the result unattended, each provider's plan room, and
|
|
606
|
+
the agents you configured for each phase. Strength is never
|
|
603
607
|
inferred from a model's name: the ordinary phase row is the routine tier, and
|
|
604
608
|
`config set <phase> --tier strong --provider <p> --model <m>` names the agent
|
|
605
|
-
|
|
609
|
+
large or risky, strict, screenshot-proof, and automerge routes reach for. With no
|
|
606
610
|
strong row, a demanding task keeps the default and says so.
|
|
607
611
|
|
|
608
612
|
```
|
|
609
|
-
toolroll task
|
|
613
|
+
toolroll task route <id> --size large --as you --token <t>
|
|
610
614
|
toolroll task route <id> # every leg, its reason, its readiness
|
|
611
615
|
toolroll task route <id> --phase build --provider codex --model gpt-5-codex --as you --token <t>
|
|
612
616
|
toolroll task route <id> --clear-phase build --as you --token <t>
|
|
@@ -625,8 +629,8 @@ an exact model too, and a plan override becomes the planner pin.
|
|
|
625
629
|
Every override is recorded under the approver's name, in one transaction that
|
|
626
630
|
checks the scope you were reading is still the one on file (`--digest`, or the
|
|
627
631
|
form's own field). Approval seals the route — routine-shaped routes included —
|
|
628
|
-
|
|
629
|
-
|
|
632
|
+
exactly as it seals the execution profile; a later size change or override
|
|
633
|
+
re-files the scope and the old
|
|
630
634
|
approval reads stale, while a global configuration change can never rewrite a
|
|
631
635
|
sealed route. A row filed before routing existed is recognised by a durable
|
|
632
636
|
marker and stays governed by its sealed profile; a routed row whose route data
|
|
@@ -636,44 +640,35 @@ readiness without spending — at startup and with `providers --report`, never
|
|
|
636
640
|
on a timer — and the task page, the chat, and `task show` say **ready**,
|
|
637
641
|
**unavailable** (with the runner's own words), or **unknown** beside the
|
|
638
642
|
agents, outside what the approval signs; an unavailable provider halts before
|
|
639
|
-
any claim and is never substituted
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
Every run is stamped with its route and the actual provider and model at
|
|
643
|
+
any claim and is never substituted. When a provider's plan runs out mid-build,
|
|
644
|
+
the attempt fails with its reason like any other failure and the task waits
|
|
645
|
+
for a retry or for you; nothing switches to another agent or account on its
|
|
646
|
+
own. Every run is stamped with its route and the actual provider and model at
|
|
643
647
|
admission — set once; a run that would spend as anything else refuses.
|
|
644
648
|
|
|
645
649
|
Admission proves that stamp before any run row exists: its shape (a known
|
|
646
650
|
phase, provenance word, and provider; a digest; an exact, argv-safe model id),
|
|
647
651
|
its phase against the run's role, its provider and model against what the run
|
|
648
652
|
would spend as, and its provenance against the authority the task actually
|
|
649
|
-
holds — the sealed route's digest and that phase's exact leg,
|
|
650
|
-
fallback-chain entry the run is bound to for a `fallback` run (two entries
|
|
651
|
-
that share a provider and model but differ in auth mode or repair model are
|
|
652
|
-
different authorities, and an ambiguous pair proves nothing), or a proven
|
|
653
|
+
holds — the sealed route's digest and that phase's exact leg, or a proven
|
|
653
654
|
pre-routing row for `legacy`, whose stamp must name the very sealed profile
|
|
654
655
|
(and, for a build or repair, its exact pair) — the bare word `legacy` belongs
|
|
655
656
|
only to a task with no scope. A task filed under routing never opens an
|
|
656
657
|
unstamped run, and the store dictates nothing: every planner, builder, scout,
|
|
657
|
-
reviewer, repair turn
|
|
658
|
+
reviewer, and repair turn **presents** the exact authority it holds
|
|
658
659
|
(`routeAuthorityFor` puts it in the caller's hands, in words), and a missing,
|
|
659
660
|
forged, stale, or inexact stamp opens no row — the refusal names what would
|
|
660
|
-
have had to be presented.
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
chain, or fallback JSON, a model id that is not one, a turn bound or clock
|
|
672
|
-
that is not a positive whole number, a run row whose chain index or auth mode
|
|
673
|
-
does not read — fails closed in words and never shrinks: a fallback row that
|
|
674
|
-
cannot be read files the scope unresolved rather than sealing a single profile
|
|
675
|
-
nobody configured, and an unreadable binding is no binding, never the base
|
|
676
|
-
entry or the subscription credential.
|
|
661
|
+
have had to be presented. A repair turn mends exactly its same-task parent
|
|
662
|
+
under the claim that holds the task now. A run admitted under a route the scope
|
|
663
|
+
has since re-sealed away refuses to spend. Malformed authority — corrupt route
|
|
664
|
+
or profile JSON, a model id that is not one, a turn bound or clock that is not
|
|
665
|
+
a positive whole number — fails closed in words and never shrinks.
|
|
666
|
+
|
|
667
|
+
Fallback chains and the declared risk level were removed (schema v115). An
|
|
668
|
+
unfinished task that was filed or approved with fallback agents asks again
|
|
669
|
+
after the update — its scope says so, and saving it once chooses its
|
|
670
|
+
agents; finished tasks and routes sealed at elevated or high risk keep their
|
|
671
|
+
exact bytes and still verify.
|
|
677
672
|
|
|
678
673
|
Codex resumes carry their sandbox as a configuration override (`-c
|
|
679
674
|
sandbox_mode=…`): `codex exec resume` has no `--sandbox` flag, so a structured
|
|
@@ -683,49 +678,37 @@ the planning attempt with its typed reason — the recorded session is not
|
|
|
683
678
|
resumed twice — and the next attempt, after the planning backoff, is a fresh
|
|
684
679
|
planner root in a fresh session.
|
|
685
680
|
|
|
686
|
-
A **
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
v48), one whose snapshot cannot be read, or one whose snapshot no longer
|
|
700
|
-
verifies fires nothing and pages once; its page and `routine show` say so and
|
|
701
|
-
offer the one road: `toolroll routine refresh <name>` (or the page's
|
|
702
|
-
**Refresh agents** button) re-resolves the agents from today's configuration,
|
|
703
|
-
withdraws an approval that is not live even when the working agents are
|
|
704
|
-
unchanged, and approves nothing — you read the exact agents it now names and
|
|
705
|
-
approve it again with your password, and only that yes fires the new
|
|
706
|
-
snapshot. An authentic v47 database, or one whose v47→v48 upgrade was
|
|
707
|
-
interrupted, upgrades without re-running older data passes, changing ids,
|
|
708
|
-
backfilling a route, or approving anything.
|
|
681
|
+
A **scheduled flow** with a standing order files an ordinary task each time
|
|
682
|
+
it fires: the order's terms (goal, exclusions, touches, requirements, success
|
|
683
|
+
checks, per-run budget) are copied into the task's scope unchanged, and the
|
|
684
|
+
task waits for approval under the project's approval rules like any other
|
|
685
|
+
proposal. A standing order moved over from an old routine keeps that routine's
|
|
686
|
+
approval and its frozen agents while they still verify: each firing re-hashes
|
|
687
|
+
the frozen snapshot against the approval, holds the build and repair legs to
|
|
688
|
+
the sealed profile's exact provider and model, and rolls the whole firing back
|
|
689
|
+
unless the task seals under it — a later `config set` cannot re-route it. Once
|
|
690
|
+
that approval no longer verifies, each firing says why and waits for approval
|
|
691
|
+
as an ordinary proposal. `toolroll flows show` prints a standing order's
|
|
692
|
+
terms; `toolroll flows trigger pause|resume` (or **Resume** on the flow canvas)
|
|
693
|
+
stops and starts its schedule.
|
|
709
694
|
|
|
710
695
|
Every approval surface — the task page, the focused chat, and `/next` — shows
|
|
711
|
-
the same concise line of exact agents above the password, with
|
|
712
|
-
|
|
696
|
+
the same concise line of exact agents above the password, with why stronger
|
|
697
|
+
agents run explained in plain words and the runtime limits one tap away; changing
|
|
713
698
|
any agent invalidates the approval every surface signed under. Where no yes
|
|
714
|
-
could bind — an unreadable route, a route that cannot run, a
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
button with nothing to type; an old approval already on a pre-routing row is
|
|
721
|
-
grandfathered, but no new yes lands on it. In the demo sandbox, Chat is a
|
|
699
|
+
could bind — an unreadable route, a route that cannot run, or a pre-routing
|
|
700
|
+
row whose old approval no longer stands — those surfaces mint no nonce and
|
|
701
|
+
show no password or approve button, only the reason and the act that opens it
|
|
702
|
+
(re-file the scope or change the agents) — the inbox row reads *needs
|
|
703
|
+
attention* rather than *review & approve*; an old approval already on a
|
|
704
|
+
pre-routing row is grandfathered, but no new yes lands on it. In the demo sandbox, Chat is a
|
|
722
705
|
scripted lead that never calls a model; real chat evidence is a subscription-backed plane. The task page's controls offer,
|
|
723
706
|
per role, only the agents you configured *for that role* (gemini never
|
|
724
707
|
reviews; repairs stay on the build provider), a current agent the
|
|
725
708
|
configuration no longer names is shown for what runs today and never offered
|
|
726
|
-
again, and each
|
|
727
|
-
|
|
728
|
-
and proposes one confirmation-gated change (`propose_agents`) — a
|
|
709
|
+
again, and each size says what it does — truthfully under strict quality and
|
|
710
|
+
screenshot proof too. Chat reads the same route (`get_agents`)
|
|
711
|
+
and proposes one confirmation-gated change (`propose_agents`) — a size, one
|
|
729
712
|
role switched to a listed agent, or a hand-picked role cleared — which lands,
|
|
730
713
|
when you confirm the card, through the same authenticated route edit the page
|
|
731
714
|
uses; the chosen agent is re-proved against the role's configured choices
|
|
@@ -947,9 +930,6 @@ Everything below ships in 0.4.0:
|
|
|
947
930
|
dependencies (cycles refused), "starts after" on the filing form,
|
|
948
931
|
`task next` moves work to the front of its own queue. Scheduling,
|
|
949
932
|
never authority: approvals are untouched by any of it.
|
|
950
|
-
- **Tournaments** — race 2–4 agents on one task under native dollar
|
|
951
|
-
caps, compare their verified diffs side by side, and pick one through
|
|
952
|
-
a password ceremony; the losers' branches and evidence are kept.
|
|
953
933
|
- **The live peek** — a running build's page shows what is changing in
|
|
954
934
|
its checkout right now (names and counts, never contents), through a
|
|
955
935
|
native reader that executes nothing — no git command ever runs
|
|
@@ -967,8 +947,7 @@ Everything below ships in 0.4.0:
|
|
|
967
947
|
into one new approval-bound task.
|
|
968
948
|
- **Operating modes** — a per-repository, password-signed, expiring
|
|
969
949
|
envelope that pre-authorizes the SIGNER'S OWN future acts: your
|
|
970
|
-
filings approve themselves the moment you file them,
|
|
971
|
-
start without retyping your password, merges fire themselves when CI
|
|
950
|
+
filings approve themselves the moment you file them, merges fire themselves when CI
|
|
972
951
|
is seen green on the exact authorized commit (only through a merge
|
|
973
952
|
grant, never around one), and daily run/dollar rails bound the spend.
|
|
974
953
|
Every term renders in words at the signing ceremony — including the
|
|
@@ -981,7 +960,7 @@ Everything below ships in 0.4.0:
|
|
|
981
960
|
re-verified against its recorded hash, comments are proven
|
|
982
961
|
patch-local, and they land beside your own for YOU to prune and seal
|
|
983
962
|
into a revision task. A revision keeps the source's contract — its
|
|
984
|
-
goal, exclusions, touches, exact rubric,
|
|
963
|
+
goal, exclusions, touches, exact rubric, quality,
|
|
985
964
|
permission posture, and budget ceiling — however the installation's
|
|
986
965
|
defaults have changed since, re-resolves its agents for a fresh
|
|
987
966
|
approval, and inherits no approval, session, publication, or merge
|
|
@@ -1004,10 +983,6 @@ Everything below ships in 0.4.0:
|
|
|
1004
983
|
doing what, and remove access with one ceremony that actually severs:
|
|
1005
984
|
sessions, invites, and every mode they signed end together, while
|
|
1006
985
|
history stays attributed forever.
|
|
1007
|
-
- **Watched sessions, plural** — run several attended sessions per
|
|
1008
|
-
worker under one signed ceiling, each with its own model and
|
|
1009
|
-
permission posture chosen at mint, the whole execution profile under
|
|
1010
|
-
the signature.
|
|
1011
986
|
- **Scout tasks** — `task add … --report` (or the "scout" checkbox, or
|
|
1012
987
|
the mate's `propose_task` with `report: true`) files a task whose
|
|
1013
988
|
deliverable is a report, never a branch: once its scope is approved,
|
package/dist/agentconfig.d.ts
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
* the caller snapshots it into the run row.
|
|
21
21
|
*/
|
|
22
22
|
import { type AgentSpec, type Phase } from "./provider.js";
|
|
23
|
-
import {
|
|
24
|
-
import { type
|
|
23
|
+
import type { Store, TaskRef } from "./store.js";
|
|
24
|
+
import { type ExecutionProfile, type UnattendedPermissionMode } from "./scope.js";
|
|
25
25
|
import { type ExactSpec, type PhaseRoute, type RouteCandidates } from "./phase-routing.js";
|
|
26
26
|
import type { AcceptanceCriterion } from "./scope.js";
|
|
27
27
|
export declare const INSTALLATION_SCOPE = "installation";
|
|
@@ -66,30 +66,6 @@ export declare function resolveScopeProfile(store: Store, repo: string | null, r
|
|
|
66
66
|
repairModel?: string | undefined;
|
|
67
67
|
permissionMode?: UnattendedPermissionMode | undefined;
|
|
68
68
|
}): ProfileResolution;
|
|
69
|
-
export type ChainResolution = {
|
|
70
|
-
ok: true;
|
|
71
|
-
chain: ChainEntry[];
|
|
72
|
-
kind: "profile" | "chain";
|
|
73
|
-
} | {
|
|
74
|
-
ok: false;
|
|
75
|
-
reason: "base-unresolved" | "bad-fallback" | "duplicate";
|
|
76
|
-
problem: string;
|
|
77
|
-
};
|
|
78
|
-
/**
|
|
79
|
-
* Resolve the full EXECUTION CHAIN a scope files under (v30): the base
|
|
80
|
-
* (entry 0) is the ordinary single-profile resolution wearing the base
|
|
81
|
-
* provider's auth mode; the fallbacks are the scope's configured entries,
|
|
82
|
-
* each resolved to a WHOLE ExecutionProfile (repair per entry). With no
|
|
83
|
-
* fallbacks configured, the result is `kind: "profile"` — a single-profile
|
|
84
|
-
* approval, byte-identical to today (NOT an explicit chain). With
|
|
85
|
-
* fallbacks, it is `kind: "chain"` and the approval binds the whole thing.
|
|
86
|
-
* The base auth mode is passed in (the caller reads it from the managed
|
|
87
|
-
* key store) so resolution stays pure and testable.
|
|
88
|
-
*/
|
|
89
|
-
export declare function resolveScopeChain(store: Store, repo: string | null, ref: Pick<TaskRef, "agentProvider" | "agentModel"> | undefined, flags: PhaseFlags & {
|
|
90
|
-
repairModel?: string | undefined;
|
|
91
|
-
permissionMode?: UnattendedPermissionMode | undefined;
|
|
92
|
-
}, baseAuthMode: "subscription" | "api-key"): ChainResolution;
|
|
93
69
|
/**
|
|
94
70
|
* The two candidate tiers the routing policy chooses between, per phase,
|
|
95
71
|
* read from configuration ONLY — never inferred from a model's name:
|
|
@@ -166,16 +142,15 @@ export type TaskRoute = {
|
|
|
166
142
|
};
|
|
167
143
|
export declare function routeOfTask(store: Store, taskId: string, ref: TaskRef | null, now: Date): TaskRoute | null;
|
|
168
144
|
/**
|
|
169
|
-
* THE
|
|
170
|
-
* route
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* it is filed again under a configuration that can.
|
|
145
|
+
* THE EXACT AUTHORITY a project's configuration names today: the four-role
|
|
146
|
+
* route work would run under, and the execution profile that restates its
|
|
147
|
+
* build and repair legs exactly. The rubric's evidence needs, the
|
|
148
|
+
* installation's quality default, and the repository's publication
|
|
149
|
+
* authority are the other inputs. A configuration that cannot make an
|
|
150
|
+
* exact, runnable route answers with the words (the recipes preview shows
|
|
151
|
+
* them before any work is created).
|
|
177
152
|
*/
|
|
178
|
-
export type
|
|
153
|
+
export type AgentAuthority = {
|
|
179
154
|
ok: true;
|
|
180
155
|
route: PhaseRoute;
|
|
181
156
|
profile: ExecutionProfile;
|
|
@@ -183,7 +158,7 @@ export type RoutineAuthority = {
|
|
|
183
158
|
ok: false;
|
|
184
159
|
problem: string;
|
|
185
160
|
};
|
|
186
|
-
export declare function
|
|
161
|
+
export declare function resolveAgentAuthority(store: Store, repo: string, acceptance: readonly AcceptanceCriterion[], now: Date): AgentAuthority;
|
|
187
162
|
/** One agent a surface shows for one role: an exact pair, where it comes
|
|
188
163
|
* from, whether it is the role's current leg, and whether it can be
|
|
189
164
|
* CHOSEN — only a pair the active configuration names for this role is
|
package/dist/agentconfig.js
CHANGED
|
@@ -20,9 +20,7 @@
|
|
|
20
20
|
* the caller snapshots it into the run row.
|
|
21
21
|
*/
|
|
22
22
|
import { isProviderId, validateSpec } from "./provider.js";
|
|
23
|
-
import {
|
|
24
|
-
import { CLAUDE_LIMITS, CODEX_SHAPED_LIMITS, GEMINI_LIMITS, chainFromJson, canonicalChainJson } from "./scope.js";
|
|
25
|
-
import { SUBSCRIPTION_CAPABLE } from "./keys.js";
|
|
23
|
+
import { CLAUDE_LIMITS, CODEX_SHAPED_LIMITS, GEMINI_LIMITS } from "./scope.js";
|
|
26
24
|
import { exactModelId, legOf, PHASES, recommendRoute, routeFromJson, routeProblems, sameSpec } from "./phase-routing.js";
|
|
27
25
|
export const INSTALLATION_SCOPE = "installation";
|
|
28
26
|
/**
|
|
@@ -177,61 +175,6 @@ export function resolveScopeProfile(store, repo, ref, flags) {
|
|
|
177
175
|
};
|
|
178
176
|
return { ok: true, profile, provenance: { resolvedFrom: build.source, repairFrom } };
|
|
179
177
|
}
|
|
180
|
-
/**
|
|
181
|
-
* Resolve the full EXECUTION CHAIN a scope files under (v30): the base
|
|
182
|
-
* (entry 0) is the ordinary single-profile resolution wearing the base
|
|
183
|
-
* provider's auth mode; the fallbacks are the scope's configured entries,
|
|
184
|
-
* each resolved to a WHOLE ExecutionProfile (repair per entry). With no
|
|
185
|
-
* fallbacks configured, the result is `kind: "profile"` — a single-profile
|
|
186
|
-
* approval, byte-identical to today (NOT an explicit chain). With
|
|
187
|
-
* fallbacks, it is `kind: "chain"` and the approval binds the whole thing.
|
|
188
|
-
* The base auth mode is passed in (the caller reads it from the managed
|
|
189
|
-
* key store) so resolution stays pure and testable.
|
|
190
|
-
*/
|
|
191
|
-
export function resolveScopeChain(store, repo, ref, flags, baseAuthMode) {
|
|
192
|
-
const base = resolveScopeProfile(store, repo, ref, flags);
|
|
193
|
-
if (!base.ok)
|
|
194
|
-
return { ok: false, reason: "base-unresolved", problem: base.problem };
|
|
195
|
-
const unreadable = repo === null ? null : store.fallbackConfigProblem(repo);
|
|
196
|
-
if (unreadable !== null)
|
|
197
|
-
return { ok: false, reason: "bad-fallback", problem: unreadable };
|
|
198
|
-
const fallbacks = repo === null ? [] : store.fallbackConfig(repo);
|
|
199
|
-
if (fallbacks.length === 0) {
|
|
200
|
-
// No fallbacks: a legacy single-profile approval, unchanged.
|
|
201
|
-
return { ok: true, chain: [{ profile: base.profile, authMode: baseAuthMode }], kind: "profile" };
|
|
202
|
-
}
|
|
203
|
-
const entries = [{ profile: base.profile, authMode: baseAuthMode }];
|
|
204
|
-
for (const one of fallbacks) {
|
|
205
|
-
if (!isProviderId(one.provider) || one.model === undefined || one.model === "") {
|
|
206
|
-
return { ok: false, reason: "bad-fallback", problem: `a fallback entry names an unknown provider or empty model (${one.provider}:${one.model})` };
|
|
207
|
-
}
|
|
208
|
-
if (one.authMode !== "subscription" && one.authMode !== "api-key") {
|
|
209
|
-
return { ok: false, reason: "bad-fallback", problem: `a fallback entry has an unknown auth mode` };
|
|
210
|
-
}
|
|
211
|
-
// An entry can only pin an auth mode its provider can actually take:
|
|
212
|
-
// "subscription" on a provider with no login (openrouter) would seal an
|
|
213
|
-
// entry that can never authenticate (E3d, gateway pin).
|
|
214
|
-
if (one.authMode === "subscription" && !SUBSCRIPTION_CAPABLE[one.provider]) {
|
|
215
|
-
return { ok: false, reason: "bad-fallback", problem: `${one.provider} has no subscription login — this entry must use an API key` };
|
|
216
|
-
}
|
|
217
|
-
// The model rides provider argv (F+G review, finding 1): the SAME
|
|
218
|
-
// argv-safety validation every other sealed model passes — never a
|
|
219
|
-
// leading dash, control bytes, or whitespace into a harness's argv.
|
|
220
|
-
const argvSafe = validateSpec({ provider: one.provider, model: one.model });
|
|
221
|
-
if (!argvSafe.ok) {
|
|
222
|
-
return { ok: false, reason: "bad-fallback", problem: argvSafe.problem };
|
|
223
|
-
}
|
|
224
|
-
entries.push({ profile: contestantProfileOf(one.provider, one.model, one.repairModel ?? "inherit", flags.permissionMode ?? store.permissionDefault().mode), authMode: one.authMode });
|
|
225
|
-
}
|
|
226
|
-
// Re-prove the whole chain through the strict rehydrator: it rejects
|
|
227
|
-
// exact-duplicate entries and any malformed shape, so what the approval
|
|
228
|
-
// seals is exactly what dispatch will re-derive.
|
|
229
|
-
const proven = chainFromJson(canonicalChainJson(entries));
|
|
230
|
-
if (proven === null) {
|
|
231
|
-
return { ok: false, reason: "duplicate", problem: "the fallback chain has a duplicate entry (same profile and auth mode) or is malformed" };
|
|
232
|
-
}
|
|
233
|
-
return { ok: true, chain: proven, kind: "chain" };
|
|
234
|
-
}
|
|
235
178
|
const PHASE_NOUN = { plan: "planner", build: "builder", repair: "repair", review: "reviewer" };
|
|
236
179
|
export function resolveRouteCandidates(store, repo, pins = {}) {
|
|
237
180
|
// The LIGHT tier (v2): the operator's named fast builder, project over
|
|
@@ -289,7 +232,7 @@ export function resolveRouteCandidates(store, repo, pins = {}) {
|
|
|
289
232
|
if (!routine.ok)
|
|
290
233
|
return { ok: false, problem: routine.problem };
|
|
291
234
|
if (routine.spec.model === null || routine.spec.model === "") {
|
|
292
|
-
// A PINNED exact pair (
|
|
235
|
+
// A PINNED exact pair (an approved standing order's frozen profile, a plan
|
|
293
236
|
// request's pin) is the phase's agent whatever the configuration
|
|
294
237
|
// says — it stands in as the candidate when nothing exact is
|
|
295
238
|
// configured, so a firing never depends on today's config.
|
|
@@ -417,7 +360,6 @@ export function routeOfTask(store, taskId, ref, now) {
|
|
|
417
360
|
if (!candidates.ok)
|
|
418
361
|
return { kind: "unreadable", problem: candidates.problem };
|
|
419
362
|
const route = recommendRoute({
|
|
420
|
-
risk: ref?.riskLevel ?? "routine",
|
|
421
363
|
qualityMode: ref?.qualityMode ?? store.qualityDefault().mode,
|
|
422
364
|
evidence: [],
|
|
423
365
|
publication: store.publicationAuthorityOf(repo, now),
|
|
@@ -429,12 +371,11 @@ export function routeOfTask(store, taskId, ref, now) {
|
|
|
429
371
|
});
|
|
430
372
|
return { kind: "route", route, source: "live" };
|
|
431
373
|
}
|
|
432
|
-
export function
|
|
374
|
+
export function resolveAgentAuthority(store, repo, acceptance, now) {
|
|
433
375
|
const candidates = resolveRouteCandidates(store, repo);
|
|
434
376
|
if (!candidates.ok)
|
|
435
377
|
return { ok: false, problem: candidates.problem };
|
|
436
378
|
const route = recommendRoute({
|
|
437
|
-
risk: "routine",
|
|
438
379
|
qualityMode: store.qualityDefault().mode,
|
|
439
380
|
evidence: [...new Set(acceptance.flatMap(one => one.evidence))],
|
|
440
381
|
publication: store.publicationAuthorityOf(repo, now),
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
/** Who filed a task, as far as anyone can tell: a person (browser, chat, a
|
|
14
14
|
* revision), a coordinator acting for the person who made it, an AI
|
|
15
|
-
* teammate, or automation that names no person (a
|
|
15
|
+
* teammate, or automation that names no person (a schedule, the CLI, a flow
|
|
16
16
|
* with no owner). The requester rule binds only a named person. */
|
|
17
17
|
export type FilerKind = "person" | "coordinator" | "teammate" | "automation";
|
|
18
18
|
export type Filer = {
|
package/dist/approval-policy.js
CHANGED
|
@@ -133,5 +133,5 @@ export function gateWords(gate) {
|
|
|
133
133
|
: `Your approval is recorded (${gate.have} of ${gate.need}). This work is protected, so a second person needs to approve it.`;
|
|
134
134
|
return gate.reason === "requester"
|
|
135
135
|
? "You filed this task, and this project needs someone else to approve it."
|
|
136
|
-
: "This work is protected: a person has to approve it, not an operating mode, a
|
|
136
|
+
: "This work is protected: a person has to approve it, not an operating mode, a schedule or an AI teammate.";
|
|
137
137
|
}
|
package/dist/backup.d.ts
CHANGED
|
@@ -31,12 +31,20 @@ export declare function backupFiles(folder: string, owner: BackupOwner): {
|
|
|
31
31
|
}[];
|
|
32
32
|
/** Remove all but this database's newest `keep` backups. Never touches another database's, or anything else in the folder. */
|
|
33
33
|
export declare function pruneBackups(folder: string, keep: number, owner: BackupOwner): number;
|
|
34
|
+
/** The checkpoint made before a backup: the head it records, a broken chain's first break (none recorded), or null (nothing new since the last). */
|
|
35
|
+
export type BackupCheckpoint = {
|
|
36
|
+
through: number;
|
|
37
|
+
hash: string;
|
|
38
|
+
} | {
|
|
39
|
+
problem: string;
|
|
40
|
+
} | null;
|
|
34
41
|
export type BackupOutcome = {
|
|
35
42
|
ok: true;
|
|
36
43
|
id: number;
|
|
37
44
|
file: string;
|
|
38
45
|
bytes: number;
|
|
39
46
|
removed: number;
|
|
47
|
+
checkpoint: BackupCheckpoint;
|
|
40
48
|
} | {
|
|
41
49
|
ok: false;
|
|
42
50
|
id: number;
|
package/dist/backup.js
CHANGED
|
@@ -164,6 +164,15 @@ export async function backupNow(store, databaseFile, trigger, clock = () => new
|
|
|
164
164
|
let name = `standing-orders-${stamp}.db`;
|
|
165
165
|
for (let n = 2; existsSync(join(folder, name)); n++)
|
|
166
166
|
name = `standing-orders-${stamp}-${n}.db`;
|
|
167
|
+
// The whole chain walked and its head checkpointed first, so the copy carries the checkpoint. A broken chain gets
|
|
168
|
+
// none (the walk raises the console's chain alarm, as any whole walk does); the backup goes ahead either way.
|
|
169
|
+
let checkpoint;
|
|
170
|
+
try {
|
|
171
|
+
checkpoint = store.ledgerCheckpoint("system", clock(), {});
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
checkpoint = { problem: message(error) };
|
|
175
|
+
}
|
|
167
176
|
partial = join(folder, `.${name}.${randomBytes(4).toString("hex")}.partial`);
|
|
168
177
|
const made = await onlineCopy(databaseFile, partial);
|
|
169
178
|
const file = join(folder, name);
|
|
@@ -171,7 +180,7 @@ export async function backupNow(store, databaseFile, trigger, clock = () => new
|
|
|
171
180
|
partial = null;
|
|
172
181
|
const removed = pruneBackups(folder, settings.keep, backupOwner(store, databaseFile));
|
|
173
182
|
store.finishBackupRun(id, { ok: true, file, bytes: made.bytes, schemaVersion: made.schemaVersion, removed }, clock());
|
|
174
|
-
return { ok: true, id, file, bytes: made.bytes, removed };
|
|
183
|
+
return { ok: true, id, file, bytes: made.bytes, removed, checkpoint };
|
|
175
184
|
}
|
|
176
185
|
catch (error) {
|
|
177
186
|
if (partial !== null)
|
package/dist/board.d.ts
CHANGED
|
@@ -57,17 +57,9 @@ export type BoardFacts = {
|
|
|
57
57
|
liveRunId?: number | null;
|
|
58
58
|
/** The top-precedence live hold: operator > backoff > decision > incident. */
|
|
59
59
|
hold: {
|
|
60
|
-
ownerKind: "operator" | "decision" | "incident" | "backoff"
|
|
60
|
+
ownerKind: "operator" | "decision" | "incident" | "backoff";
|
|
61
61
|
until: string | null;
|
|
62
62
|
} | null;
|
|
63
|
-
/** The task's open tournament, when agents raced (v14). Optional so
|
|
64
|
-
* callers that predate tournaments stay valid; absent reads as none. */
|
|
65
|
-
contest?: {
|
|
66
|
-
id: number;
|
|
67
|
-
state: string;
|
|
68
|
-
agents: number;
|
|
69
|
-
kind?: "race" | "comparison";
|
|
70
|
-
} | null;
|
|
71
63
|
/** The first blocker that is not done, when one exists. */
|
|
72
64
|
unmetDependency: string | null;
|
|
73
65
|
/** That blocker's state — pre-redacted by the caller to null when the
|
|
@@ -76,11 +68,6 @@ export type BoardFacts = {
|
|
|
76
68
|
blockerState: string | null;
|
|
77
69
|
/** The first required capability not currently verified, as "kind:name". */
|
|
78
70
|
missingRequirement: string | null;
|
|
79
|
-
/** The standing order this task is an instance of, when it is one. The
|
|
80
|
-
* board keeps instances in their track row — they enter the main lanes
|
|
81
|
-
* only when they need a person, wearing the routine's name. */
|
|
82
|
-
routineId: number | null;
|
|
83
|
-
routineName: string | null;
|
|
84
71
|
/** Queue rank — 0 is filing order. Scheduling only; ranks compare
|
|
85
72
|
* within one column, never across columns. */
|
|
86
73
|
priority?: number;
|
|
@@ -102,8 +89,6 @@ export type BoardCard = {
|
|
|
102
89
|
/** The live attempt's ordinal when earlier ones failed — building only. */
|
|
103
90
|
attempt: number | null;
|
|
104
91
|
overdue: boolean;
|
|
105
|
-
/** The routine this card is an instance of — the chip it wears in lanes. */
|
|
106
|
-
routineName: string | null;
|
|
107
92
|
/** The task's queue rank, carried for the queued lane's sort and badge. */
|
|
108
93
|
priority: number;
|
|
109
94
|
/** The worker this card is reserved for; null = the shared queue. */
|
|
@@ -111,9 +96,8 @@ export type BoardCard = {
|
|
|
111
96
|
};
|
|
112
97
|
/**
|
|
113
98
|
* Plain words for every hold owner — shared with the task page so "who is
|
|
114
|
-
* holding this" reads the same everywhere.
|
|
115
|
-
*
|
|
116
|
-
* generic word, never to its raw name.
|
|
99
|
+
* holding this" reads the same everywhere. An unknown or retired owner
|
|
100
|
+
* degrades to the generic word, never to its raw name.
|
|
117
101
|
*/
|
|
118
102
|
export declare const HOLD_OWNER_WORDS: Record<string, string>;
|
|
119
103
|
export declare function holdOwnerWords(ownerKind: string): string;
|