toolroll 0.9.55 → 0.9.57
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 +18 -0
- package/README.md +24 -8
- package/dist/action-ledger.d.ts +2 -4
- package/dist/action-ledger.js +2 -10
- package/dist/approval-policy.d.ts +5 -5
- package/dist/approval-policy.js +4 -4
- package/dist/approval-rules-ui.js +2 -2
- package/dist/assignment-adapters.d.ts +5 -0
- package/dist/assignment.d.ts +24 -3
- package/dist/assignment.js +36 -10
- package/dist/browser/workspace.js +5 -5
- package/dist/browser-workspace.d.ts +12 -12
- package/dist/browser-workspace.js +1 -1
- package/dist/budget-alerts.js +3 -3
- package/dist/chat-actions.d.ts +23 -18
- package/dist/chat-actions.js +110 -88
- package/dist/chat-ask.d.ts +2 -2
- package/dist/chat-ask.js +5 -5
- package/dist/chat-channel.d.ts +15 -15
- package/dist/chat-channel.js +20 -20
- package/dist/chat-controls.d.ts +0 -4
- package/dist/chat-controls.js +0 -1
- package/dist/chat-core.js +1 -1
- package/dist/chat-delivery-state.js +2 -2
- package/dist/chat-delivery.d.ts +2 -2
- package/dist/chat-delivery.js +30 -37
- package/dist/chat-flow.js +3 -3
- package/dist/chat-messages.d.ts +1 -1
- package/dist/chat-messages.js +4 -4
- package/dist/chat-migration.d.ts +1 -1
- package/dist/chat-migration.js +11 -11
- package/dist/chat-rooms.js +3 -3
- package/dist/chat-voice.js +1 -1
- package/dist/chat-warmth.d.ts +2 -2
- package/dist/check-levels.d.ts +3 -0
- package/dist/check-levels.js +5 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +6 -7
- package/dist/contracts/chat-actions.d.ts +32 -27
- package/dist/contracts/chat-actions.js +29 -11
- package/dist/contracts/chat-content.d.ts +1 -1
- package/dist/contracts/chat-content.js +1 -1
- package/dist/contracts/chat-tables.js +4 -4
- package/dist/contracts/console-api.d.ts +6 -6
- package/dist/contracts/console-api.js +7 -7
- package/dist/contracts/flow-propose.d.ts +3 -3
- package/dist/contracts/flow.d.ts +132 -125
- package/dist/contracts/flow.js +27 -12
- package/dist/contracts/lead-context.d.ts +1 -1
- package/dist/contracts/lead-context.js +2 -2
- package/dist/contracts/lead-tools.d.ts +20 -18
- package/dist/contracts/lead-tools.js +15 -15
- package/dist/contracts/stage-output.d.ts +1 -1
- package/dist/contracts/stage-output.js +1 -1
- package/dist/contracts/store-json.d.ts +23 -22
- package/dist/contracts/store-json.js +17 -17
- package/dist/contracts/{teammate-turn.d.ts → subagent-turn.d.ts} +5 -5
- package/dist/contracts/{teammate-turn.js → subagent-turn.js} +7 -7
- package/dist/converse.d.ts +23 -23
- package/dist/converse.js +28 -28
- package/dist/coordinator-proposals.d.ts +2 -2
- package/dist/coordinator-proposals.js +1 -1
- package/dist/coordinator.js +1 -1
- package/dist/deprecations.d.ts +12 -0
- package/dist/deprecations.js +20 -0
- package/dist/desktop-update-gate.js +8 -4
- package/dist/desktop-update.js +6 -1
- package/dist/discord-chat.js +6 -6
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/dispose.js +0 -5
- package/dist/envelope.js +0 -1
- package/dist/export-ui.js +1 -1
- package/dist/export.js +7 -7
- package/dist/flow-engine.d.ts +2 -2
- package/dist/flow-engine.js +21 -21
- package/dist/flow-insights.d.ts +1 -1
- package/dist/flow-share.js +13 -8
- package/dist/flow-steps.d.ts +5 -5
- package/dist/flow-steps.js +19 -19
- package/dist/flow-triggers.d.ts +1 -1
- package/dist/flow-triggers.js +1 -1
- package/dist/flows-cli.js +1 -1
- package/dist/flows-ui.js +20 -20
- package/dist/flows.js +19 -19
- package/dist/guides.js +4 -3
- package/dist/invoke.js +1 -1
- package/dist/kits-ui.js +5 -5
- package/dist/kits.d.ts +12 -12
- package/dist/kits.js +31 -31
- package/dist/{mate-cli.d.ts → lead-cli.d.ts} +11 -11
- package/dist/{mate-cli.js → lead-cli.js} +38 -38
- package/dist/lead-commitments.js +4 -4
- package/dist/lead-context.d.ts +2 -2
- package/dist/lead-context.js +9 -9
- package/dist/{mate-contract.d.ts → lead-contract.d.ts} +3 -3
- package/dist/{mate-contract.js → lead-contract.js} +7 -6
- package/dist/{mate-doors.d.ts → lead-doors.d.ts} +6 -6
- package/dist/{mate-doors.js → lead-doors.js} +24 -24
- package/dist/lead-follow.d.ts +5 -5
- package/dist/lead-follow.js +9 -9
- package/dist/lead-people.d.ts +5 -5
- package/dist/lead-people.js +14 -14
- package/dist/{mate-progress.d.ts → lead-progress.d.ts} +9 -9
- package/dist/{mate-progress.js → lead-progress.js} +3 -3
- package/dist/lead-status.d.ts +1 -1
- package/dist/lead-status.js +2 -2
- package/dist/{mate-tools.d.ts → lead-tools.d.ts} +19 -19
- package/dist/{mate-tools.js → lead-tools.js} +109 -101
- package/dist/{mate.d.ts → lead.d.ts} +27 -27
- package/dist/{mate.js → lead.js} +102 -102
- package/dist/limits-ui.d.ts +1 -1
- package/dist/limits-ui.js +1 -1
- package/dist/mcp-connect.d.ts +1 -1
- package/dist/mcp-connect.js +3 -3
- package/dist/mcp-core.js +1 -1
- package/dist/memory-pass.d.ts +2 -2
- package/dist/memory-pass.js +7 -7
- package/dist/notification-rows.d.ts +2 -2
- package/dist/operate.d.ts +3 -3
- package/dist/operate.js +52 -42
- package/dist/policy.d.ts +1 -1
- package/dist/principal.d.ts +1 -1
- package/dist/principal.js +2 -2
- package/dist/project-delete-ui.js +1 -1
- package/dist/project-delete.d.ts +1 -1
- package/dist/project-delete.js +26 -26
- package/dist/project-memory.js +1 -1
- package/dist/project-tools.d.ts +1 -1
- package/dist/project-tools.js +1 -1
- package/dist/proof.d.ts +9 -0
- package/dist/proof.js +12 -0
- package/dist/recipe-ui.js +1 -1
- package/dist/release-coverage.d.ts +16 -0
- package/dist/release-coverage.js +92 -0
- package/dist/retention.js +4 -4
- package/dist/scope.d.ts +2 -2
- package/dist/scout-report.d.ts +1 -1
- package/dist/scout-report.js +1 -1
- package/dist/serve.js +40 -45
- package/dist/server/chat.d.ts +4 -4
- package/dist/server/chat.js +105 -103
- package/dist/server/chrome.js +3 -3
- package/dist/server/flows.js +69 -62
- package/dist/server/guards.js +3 -3
- package/dist/server/http.d.ts +3 -3
- package/dist/server/http.js +1 -1
- package/dist/server/live.js +6 -6
- package/dist/server/people-tokens.js +1 -1
- package/dist/server/remote.js +12 -10
- package/dist/server/render-chat.d.ts +30 -30
- package/dist/server/render-chat.js +33 -33
- package/dist/server/render-pages.js +2 -2
- package/dist/server/render-results.d.ts +4 -1
- package/dist/server/render-results.js +23 -9
- package/dist/server/render-settings.d.ts +7 -0
- package/dist/server/render-settings.js +3 -0
- package/dist/server/route-table.js +9 -7
- package/dist/server/runtime.d.ts +13 -13
- package/dist/server/settings.js +14 -13
- package/dist/server/tasks.js +34 -30
- package/dist/setup-guide.d.ts +2 -2
- package/dist/slack-chat.d.ts +2 -2
- package/dist/slack-chat.js +6 -6
- package/dist/spend-ui.d.ts +3 -3
- package/dist/spend-ui.js +9 -9
- package/dist/spend.d.ts +14 -14
- package/dist/spend.js +31 -31
- package/dist/store-baseline.d.ts +19 -0
- package/dist/store-baseline.js +2873 -0
- package/dist/store.d.ts +200 -254
- package/dist/store.js +830 -3152
- package/dist/subagent-admin.d.ts +53 -0
- package/dist/{teammate-admin.js → subagent-admin.js} +37 -37
- package/dist/{teammate-desk.d.ts → subagent-desk.d.ts} +22 -23
- package/dist/{teammate-desk.js → subagent-desk.js} +26 -35
- package/dist/{teammate-memory.d.ts → subagent-memory.d.ts} +17 -17
- package/dist/{teammate-memory.js → subagent-memory.js} +41 -41
- package/dist/{teammate-question.d.ts → subagent-question.d.ts} +6 -6
- package/dist/{teammate-question.js → subagent-question.js} +17 -17
- package/dist/{teammate-tools.d.ts → subagent-tools.d.ts} +18 -18
- package/dist/{teammate-tools.js → subagent-tools.js} +36 -36
- package/dist/{teammate-week.d.ts → subagent-week.d.ts} +10 -10
- package/dist/{teammate-week.js → subagent-week.js} +23 -23
- package/dist/{teammate-work.d.ts → subagent-work.d.ts} +21 -21
- package/dist/{teammate-work.js → subagent-work.js} +50 -50
- package/dist/subagents-ui.d.ts +22 -0
- package/dist/{teammates-ui.js → subagents-ui.js} +45 -45
- package/dist/{teammates.d.ts → subagents.d.ts} +11 -11
- package/dist/{teammates.js → subagents.js} +21 -21
- package/dist/subscription-chat.d.ts +13 -13
- package/dist/subscription-chat.js +19 -19
- package/dist/surface.d.ts +19 -2
- package/dist/surface.js +7 -31
- package/dist/task-outcome-cli.js +3 -1
- package/dist/task-status.d.ts +59 -7
- package/dist/task-status.js +132 -16
- package/dist/team-cli.d.ts +1 -0
- package/dist/team-cli.js +14 -2
- package/dist/team-leads.js +13 -13
- package/dist/team-runtime.d.ts +2 -2
- package/dist/team-runtime.js +9 -9
- package/dist/teams-chat.js +6 -6
- package/dist/telegram-flow.d.ts +3 -3
- package/dist/telegram-flow.js +3 -3
- package/dist/{telegram-mate.d.ts → telegram-lead.d.ts} +5 -5
- package/dist/{telegram-mate.js → telegram-lead.js} +27 -27
- package/dist/telegram-status.d.ts +11 -4
- package/dist/telegram-status.js +18 -11
- package/dist/telegram-team.d.ts +1 -1
- package/dist/telegram-team.js +5 -5
- package/dist/telegram.d.ts +1 -1
- package/dist/telegram.js +13 -34
- package/dist/text-limits.d.ts +18 -18
- package/dist/text-limits.js +18 -18
- package/dist/toolroll-update.d.ts +8 -0
- package/dist/toolroll-update.js +45 -8
- package/dist/work-index.d.ts +6 -1
- package/dist/work-index.js +50 -8
- package/dist/workspace-ui.js +2 -1
- package/package.json +1 -2
- package/dist/teammate-admin.d.ts +0 -53
- package/dist/teammates-ui.d.ts +0 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.57 — 2026-10-09
|
|
4
|
+
|
|
5
|
+
- **Truthful status.** Finished tasks read Complete everywhere. With checks
|
|
6
|
+
off, criteria read "checked at release" instead of Needs you.
|
|
7
|
+
- **No false finish.** Completing or deploying refuses a failed or missing
|
|
8
|
+
check, an unmet criterion, a serious review finding, or missing evidence.
|
|
9
|
+
- **Clear revisions.** Revisions are named after their task: -v2, -v3.
|
|
10
|
+
|
|
11
|
+
## 0.9.56 — 2026-10-09
|
|
12
|
+
|
|
13
|
+
- **One lead.** Your assistant in the console, on your phone, in chat and in
|
|
14
|
+
the CLI is the same lead. Teammates are now its subagents, with their
|
|
15
|
+
personalities and rules: "ask Rosa to…", or from a flow step.
|
|
16
|
+
- **Retiring soon.** The central team service and native coding sessions are
|
|
17
|
+
hidden and warn when used; they are removed next release.
|
|
18
|
+
- **Fresh baseline.** New installs start from a baseline schema. Databases
|
|
19
|
+
older than 0.5.0 are asked to update through 0.9.x first.
|
|
20
|
+
|
|
3
21
|
## 0.9.55 — 2026-10-09
|
|
4
22
|
|
|
5
23
|
- **One door per route.** Every page's access comes from one table with one
|
package/README.md
CHANGED
|
@@ -366,7 +366,7 @@ for people splitting those parts across machines.
|
|
|
366
366
|
Specialized views remain in **Tools** and **Settings**: the activity ledger, the review cockpit,
|
|
367
367
|
the fleet,
|
|
368
368
|
people (invite a second approver), the operating mode (a signed, expiring
|
|
369
|
-
envelope that pre-approves your own filings), and **chat** —
|
|
369
|
+
envelope that pre-approves your own filings), and **chat** — your lead, one
|
|
370
370
|
conversation across every project, which only ever proposes.
|
|
371
371
|
|
|
372
372
|
### In the terminal
|
|
@@ -383,7 +383,7 @@ toolroll decide <id> --choose <option> # answer a parked decision
|
|
|
383
383
|
toolroll task show retries # attempts, outcome, where the branch is
|
|
384
384
|
|
|
385
385
|
toolroll task add "Why does the login test flake?" --id flaky --report # a scout
|
|
386
|
-
toolroll chat --say "what is waiting on me across every project?" #
|
|
386
|
+
toolroll chat --say "what is waiting on me across every project?" # your lead
|
|
387
387
|
```
|
|
388
388
|
|
|
389
389
|
Every command takes `--json` and answers with one envelope; every mutation
|
|
@@ -808,21 +808,37 @@ contents or command lines, with credential-shaped lines redacted at
|
|
|
808
808
|
write. Digits focus one pane, `a` shows them all, `q` leaves. Outside a
|
|
809
809
|
terminal, or with `--json`, it prints one snapshot and exits.
|
|
810
810
|
|
|
811
|
-
## The
|
|
811
|
+
## The lead, its subagents, and the gateway
|
|
812
812
|
|
|
813
|
-
`/chat` in the console (or `toolroll chat` in the terminal
|
|
814
|
-
conversation across every project you serve.
|
|
813
|
+
`/chat` in the console (or `toolroll chat` in the terminal, or your chat app on
|
|
814
|
+
the phone) is one conversation with your lead across every project you serve.
|
|
815
|
+
The console, the terminal, Telegram, Slack, Discord and Teams all talk to the
|
|
816
|
+
same lead with the same tools. The lead reads the fleet
|
|
815
817
|
and **only proposes**: file a task (or a scout), move one to the front,
|
|
816
818
|
reserve it for a worker, hold it, rewrite a scope, retry/replace/unlink a
|
|
817
819
|
terminal dependency, guide a task's next attempt, cancel, or suggest an answer to a parked decision. Every
|
|
818
820
|
proposal is a card you confirm, with
|
|
819
821
|
every consequence and the builder's recommendation shown beside the
|
|
820
|
-
|
|
822
|
+
lead's pick; a scope the lead wrote never seals under an operating mode.
|
|
821
823
|
Absolute paths, internal digests and account names are redacted; source context includes relative file citations. Direct API use spends
|
|
822
824
|
against a ceiling you set per conversation. The console keeps a live pulse for every
|
|
823
825
|
admitted project beside that shared thread, with one-click fleet questions
|
|
824
826
|
and a direct road to each project's board.
|
|
825
827
|
|
|
828
|
+
The lead has **subagents**: named helpers, each with its own personality,
|
|
829
|
+
instructions and rules (what it does on its own, what it asks first, what it
|
|
830
|
+
never does). Say "ask Maya to draft the refund reply" and the lead shows a card
|
|
831
|
+
with exactly what goes to Maya; once you confirm, Maya works it within her rules
|
|
832
|
+
and her answer comes back to you. A flow step can call a subagent by name too.
|
|
833
|
+
They live in **Settings → Lead → Subagents** ([guide](docs/guide/subagents.md)).
|
|
834
|
+
Subagents used to be called AI teammates; each carried over unchanged.
|
|
835
|
+
|
|
836
|
+
The central team service (`toolroll connect`, the central `toolroll lead
|
|
837
|
+
list|create|update|member|transfer`, `toolroll conversation …`, team chat) and
|
|
838
|
+
native coding sessions (`toolroll session …`, the `/code` page) are deprecated:
|
|
839
|
+
they still work for this release, hidden from help and the console, print one warning
|
|
840
|
+
when used, and are removed in the next minor release.
|
|
841
|
+
|
|
826
842
|
Every task has an **Overview / Ask** switch. **Ask** opens a focused companion
|
|
827
843
|
to that task without creating another conversation: Toolroll attaches
|
|
828
844
|
the current task to each new message, keeps the live status beside the thread,
|
|
@@ -831,7 +847,7 @@ result inspection. Proposed guidance is inert until you confirm its card, then i
|
|
|
831
847
|
reaches the next attempt without interrupting work already running.
|
|
832
848
|
|
|
833
849
|
New work starts the same way: describe the outcome once in ordinary language.
|
|
834
|
-
The
|
|
850
|
+
The lead infers a concise title, narrow scope, safe non-goals, and proof
|
|
835
851
|
criteria; it asks only when the project or outcome is genuinely ambiguous, or
|
|
836
852
|
when an irreversible or compatibility tradeoff changes what should be built.
|
|
837
853
|
Questions are grouped, carry a recommended default, and stop for reversible
|
|
@@ -985,7 +1001,7 @@ Everything below ships in 0.4.0:
|
|
|
985
1001
|
sessions, invites, and every mode they signed end together, while
|
|
986
1002
|
history stays attributed forever.
|
|
987
1003
|
- **Scout tasks** — `task add … --report` (or the "scout" checkbox, or
|
|
988
|
-
the
|
|
1004
|
+
the lead's `propose_task` with `report: true`) files a task whose
|
|
989
1005
|
deliverable is a report, never a branch: once its scope is approved,
|
|
990
1006
|
a read-only session investigates the goal as a question and hands
|
|
991
1007
|
back a title, a summary, a document, and up to five follow-ups, each
|
package/dist/action-ledger.d.ts
CHANGED
|
@@ -16,11 +16,9 @@ export type LedgerEntry = {
|
|
|
16
16
|
/** v99: what changed, in a short line (a policy's "before → after"); never a secret, prompt or body. */
|
|
17
17
|
detail: string | null;
|
|
18
18
|
};
|
|
19
|
-
/** The table as
|
|
20
|
-
export declare const LEDGER_V54_TABLE: (name: string) => string;
|
|
21
|
-
export declare const LEDGER_V54_COLUMNS: readonly ["id", "at", "actor", "repo", "task_id", "run_id", "action", "outcome", "source"];
|
|
22
|
-
/** The table as v99 made it: the v110 rebuild accepts this shape and v54's. */
|
|
19
|
+
/** The table as v99 made it (v107 has it): the one earlier shape the v110 rebuild accepts. */
|
|
23
20
|
export declare const LEDGER_V99_TABLE: (name: string) => string;
|
|
21
|
+
export declare const LEDGER_COLUMNS: readonly ["id", "at", "actor", "repo", "task_id", "run_id", "action", "outcome", "source", "detail"];
|
|
24
22
|
export declare const LEDGER_TABLE: (name: string) => string;
|
|
25
23
|
export declare const LEDGER_SCHEMA: string;
|
|
26
24
|
/** Installed after all table migrations. Work events commit with the work,
|
package/dist/action-ledger.js
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
/** v99: sign-ins (and refusals, lockouts, sign-outs) and policy changes are their own kinds of event.
|
|
2
2
|
* v110: commands a person ran on this server with their API token, from the CLI ('api') or their agent ('mcp'). */
|
|
3
3
|
export const LEDGER_SOURCES = ["work", "request", "access", "sign-in", "policy", "api", "mcp"];
|
|
4
|
-
/** The table as
|
|
5
|
-
export const LEDGER_V54_TABLE = (name) => `CREATE TABLE ${name} (
|
|
6
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
7
|
-
at TEXT NOT NULL, actor TEXT NOT NULL, repo TEXT,
|
|
8
|
-
task_id TEXT, run_id INTEGER,
|
|
9
|
-
action TEXT NOT NULL, outcome TEXT NOT NULL,
|
|
10
|
-
source TEXT NOT NULL CHECK (source IN ('work','request','access'))
|
|
11
|
-
)`;
|
|
12
|
-
export const LEDGER_V54_COLUMNS = ["id", "at", "actor", "repo", "task_id", "run_id", "action", "outcome", "source"];
|
|
13
|
-
/** The table as v99 made it: the v110 rebuild accepts this shape and v54's. */
|
|
4
|
+
/** The table as v99 made it (v107 has it): the one earlier shape the v110 rebuild accepts. */
|
|
14
5
|
export const LEDGER_V99_TABLE = (name) => `CREATE TABLE ${name} (
|
|
15
6
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
16
7
|
at TEXT NOT NULL, actor TEXT NOT NULL, repo TEXT,
|
|
@@ -19,6 +10,7 @@ export const LEDGER_V99_TABLE = (name) => `CREATE TABLE ${name} (
|
|
|
19
10
|
source TEXT NOT NULL CHECK (source IN ('work','request','access','sign-in','policy')),
|
|
20
11
|
detail TEXT
|
|
21
12
|
)`;
|
|
13
|
+
export const LEDGER_COLUMNS = ["id", "at", "actor", "repo", "task_id", "run_id", "action", "outcome", "source", "detail"];
|
|
22
14
|
export const LEDGER_TABLE = (name) => `CREATE TABLE ${name} (
|
|
23
15
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
24
16
|
at TEXT NOT NULL, actor TEXT NOT NULL, repo TEXT,
|
|
@@ -5,21 +5,21 @@
|
|
|
5
5
|
* - The person who filed a task can't approve it ("not the requester").
|
|
6
6
|
* - Protected work (the whole project, or tasks that touch protected paths)
|
|
7
7
|
* needs two different people to approve the same exact scope, and an AI
|
|
8
|
-
*
|
|
8
|
+
* subagent or an operating mode can never decide it.
|
|
9
9
|
*
|
|
10
10
|
* The store enforces these at the one place every approval is sealed
|
|
11
11
|
* (`Store.sealScopeApproval`); this module holds the pure parts.
|
|
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
|
-
*
|
|
15
|
+
* subagent, 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
|
-
export type FilerKind = "person" | "coordinator" | "
|
|
17
|
+
export type FilerKind = "person" | "coordinator" | "subagent" | "automation";
|
|
18
18
|
export type Filer = {
|
|
19
19
|
name: string | null;
|
|
20
20
|
kind: FilerKind;
|
|
21
21
|
};
|
|
22
|
-
/** A filer from a name as the ledger writes it:
|
|
22
|
+
/** A filer from a name as the ledger writes it: a subagent's ends " (AI)"; a coordinator's starts "coordinator:"; none is automation. */
|
|
23
23
|
export declare function filerFor(name: string | null | undefined): Filer;
|
|
24
24
|
export type ApprovalRules = {
|
|
25
25
|
notRequester: boolean;
|
|
@@ -27,7 +27,7 @@ export type ApprovalRules = {
|
|
|
27
27
|
protectedPaths: string[];
|
|
28
28
|
};
|
|
29
29
|
export declare const NO_RULES: ApprovalRules;
|
|
30
|
-
/** Who is sealing: a person at a ceremony, an operating mode,
|
|
30
|
+
/** Who is sealing: a person at a ceremony, an operating mode, a subagent, or automation. */
|
|
31
31
|
export type ApproverKind = "person" | "mode" | "ai" | "automation";
|
|
32
32
|
export type ApprovalGate = {
|
|
33
33
|
verdict: "seal";
|
package/dist/approval-policy.js
CHANGED
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
* - The person who filed a task can't approve it ("not the requester").
|
|
6
6
|
* - Protected work (the whole project, or tasks that touch protected paths)
|
|
7
7
|
* needs two different people to approve the same exact scope, and an AI
|
|
8
|
-
*
|
|
8
|
+
* subagent or an operating mode can never decide it.
|
|
9
9
|
*
|
|
10
10
|
* The store enforces these at the one place every approval is sealed
|
|
11
11
|
* (`Store.sealScopeApproval`); this module holds the pure parts.
|
|
12
12
|
*/
|
|
13
|
-
/** A filer from a name as the ledger writes it:
|
|
13
|
+
/** A filer from a name as the ledger writes it: a subagent's ends " (AI)"; a coordinator's starts "coordinator:"; none is automation. */
|
|
14
14
|
export function filerFor(name) {
|
|
15
15
|
if (name == null || name === "")
|
|
16
16
|
return { name: null, kind: "automation" };
|
|
17
17
|
if (name.endsWith(" (AI)"))
|
|
18
|
-
return { name, kind: "
|
|
18
|
+
return { name, kind: "subagent" };
|
|
19
19
|
if (name.startsWith("coordinator:"))
|
|
20
20
|
return { name, kind: "coordinator" };
|
|
21
21
|
return { name, kind: "person" };
|
|
@@ -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 schedule or
|
|
136
|
+
: "This work is protected: a person has to approve it, not an operating mode, a schedule or a subagent.";
|
|
137
137
|
}
|
|
@@ -16,9 +16,9 @@ export function rulesSummary(rules) {
|
|
|
16
16
|
if (rules.notRequester)
|
|
17
17
|
parts.push("The person who filed a task can't approve it.");
|
|
18
18
|
if (rules.protectProject)
|
|
19
|
-
parts.push("All work here is protected: two people approve it, never
|
|
19
|
+
parts.push("All work here is protected: two people approve it, never a subagent or an operating mode.");
|
|
20
20
|
else if (rules.protectedPaths.length > 0)
|
|
21
|
-
parts.push(`Work touching ${rules.protectedPaths.join(", ")} is protected: two people approve it, never
|
|
21
|
+
parts.push(`Work touching ${rules.protectedPaths.join(", ")} is protected: two people approve it, never a subagent or an operating mode.`);
|
|
22
22
|
return parts.length === 0 ? "No approval rules: anyone who can approve on this project can approve its work, including their own." : parts.join(" ");
|
|
23
23
|
}
|
|
24
24
|
export function approvalRulesHtml(view, notice) {
|
|
@@ -109,6 +109,11 @@ export declare function assignmentForCoordinator(store: Store, token: string, op
|
|
|
109
109
|
deployment: {
|
|
110
110
|
status: "not-recorded";
|
|
111
111
|
};
|
|
112
|
+
readiness: {
|
|
113
|
+
verdict: import("./proof.js").ProofVerdict | null;
|
|
114
|
+
checksOff: boolean;
|
|
115
|
+
blockers: import("./task-status.js").CompletionBlocker[];
|
|
116
|
+
} | null;
|
|
112
117
|
};
|
|
113
118
|
}[];
|
|
114
119
|
nextCursor: number;
|
package/dist/assignment.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { type Store, type ProofVerdictRow, type ProofAcceptanceRow } from "./store.js";
|
|
2
2
|
import { type WorkAction, type WorkSummaryAccess } from "./work-summary.js";
|
|
3
3
|
import { type VerifiedApprover } from "./principal.js";
|
|
4
|
+
import { type ProofVerdict } from "./proof.js";
|
|
4
5
|
import { type CheckLevel } from "./check-levels.js";
|
|
5
6
|
import { type BuildReviewView } from "./review-switch.js";
|
|
6
7
|
import { type NeedKey, type WaitKey } from "./needs-you.js";
|
|
7
|
-
import { type ChecksBatch } from "./task-status.js";
|
|
8
|
+
import { type ChecksBatch, type CompletionBlocker } from "./task-status.js";
|
|
9
|
+
import { type ReleaseCoverage, type ReleaseMemo } from "./release-coverage.js";
|
|
8
10
|
import { type LeadClaim } from "./lead-voice.js";
|
|
9
11
|
export type AssignmentAccess = WorkSummaryAccess;
|
|
10
12
|
export type AssignmentOwner = {
|
|
@@ -24,6 +26,8 @@ export type AssignmentChecks = {
|
|
|
24
26
|
running?: "quick" | "full" | null;
|
|
25
27
|
/** A batch check (batch-checks.ts): waiting for its batch, or how it was checked. */
|
|
26
28
|
batch?: ChecksBatch | null;
|
|
29
|
+
/** Checks Off: the passing full release check that contains this commit (release-coverage.ts), read now, never sealed. */
|
|
30
|
+
release?: ReleaseCoverage | null;
|
|
27
31
|
};
|
|
28
32
|
export type AssignmentReceipt = {
|
|
29
33
|
digest: string;
|
|
@@ -118,6 +122,13 @@ export type AssignmentSnapshot = {
|
|
|
118
122
|
earlierActive?: number;
|
|
119
123
|
/** Of those, how many are running rather than only queued; present with earlierActive. */
|
|
120
124
|
earlierRunning?: number;
|
|
125
|
+
/** The result as it reads today (task-status.ts): the verdict it shows, whether its checks were deliberately Off, and
|
|
126
|
+
* what refuses Complete. Derived at read time; never part of the sealed receipt. Null without a result. */
|
|
127
|
+
readiness?: {
|
|
128
|
+
verdict: ProofVerdict | null;
|
|
129
|
+
checksOff: boolean;
|
|
130
|
+
blockers: CompletionBlocker[];
|
|
131
|
+
} | null;
|
|
121
132
|
};
|
|
122
133
|
/** Status-first handoff for routine reads. Fetch get_assignment only when
|
|
123
134
|
* inspecting its exact evidence; do not repeat a full proof in every poll. */
|
|
@@ -169,9 +180,14 @@ export declare function assignmentBrief(assignment: AssignmentSnapshot | null):
|
|
|
169
180
|
deployment: {
|
|
170
181
|
status: "not-recorded";
|
|
171
182
|
};
|
|
183
|
+
readiness: {
|
|
184
|
+
verdict: ProofVerdict | null;
|
|
185
|
+
checksOff: boolean;
|
|
186
|
+
blockers: CompletionBlocker[];
|
|
187
|
+
} | null;
|
|
172
188
|
} | null;
|
|
173
189
|
export declare function assignmentChecksForRun(store: Store, root: string | undefined, runId: number, now: Date): AssignmentChecks;
|
|
174
|
-
export declare function assignmentOf(store: Store, taskId: string, now: Date, access: AssignmentAccess, root?: string): AssignmentSnapshot | null;
|
|
190
|
+
export declare function assignmentOf(store: Store, taskId: string, now: Date, access: AssignmentAccess, root?: string, memo?: ReleaseMemo): AssignmentSnapshot | null;
|
|
175
191
|
type MutationResult = {
|
|
176
192
|
ok: true;
|
|
177
193
|
assignment: AssignmentSnapshot;
|
|
@@ -203,7 +219,7 @@ type Finished = {
|
|
|
203
219
|
* (no reason needed), or an exception a report that doesn't match its changes needs a reason for. Null when
|
|
204
220
|
* Accept and finish is a plain completion: nothing is owed (no proof, a failed check, or a verified result),
|
|
205
221
|
* or it was already accepted. */
|
|
206
|
-
export declare function owedAcceptance(receipt: AssignmentReceipt | null): "person-check" | "exception" | null;
|
|
222
|
+
export declare function owedAcceptance(receipt: AssignmentReceipt | null, blockers?: readonly CompletionBlocker[]): "person-check" | "exception" | null;
|
|
207
223
|
/** Accept and finish: the person's acceptance of the exact result they read and its completion, in one
|
|
208
224
|
* transaction. Whether an acceptance is owed is decided here, against the receipt as it stands: only a
|
|
209
225
|
* person's own check or a reasoned exception records one (with its ledger act); an exception without its
|
|
@@ -278,6 +294,11 @@ export declare function assignmentUpdates(store: Store, now: Date, access: Assig
|
|
|
278
294
|
deployment: {
|
|
279
295
|
status: "not-recorded";
|
|
280
296
|
};
|
|
297
|
+
readiness: {
|
|
298
|
+
verdict: ProofVerdict | null;
|
|
299
|
+
checksOff: boolean;
|
|
300
|
+
blockers: CompletionBlocker[];
|
|
301
|
+
} | null;
|
|
281
302
|
};
|
|
282
303
|
}[];
|
|
283
304
|
nextCursor: number;
|
package/dist/assignment.js
CHANGED
|
@@ -14,13 +14,14 @@ import { verificationEvidence } from "./verification-evidence.js";
|
|
|
14
14
|
import { reproveApprover } from "./principal.js";
|
|
15
15
|
import { noteAssignmentStatus } from "./assignment-status.js";
|
|
16
16
|
import { historicalAssessmentReason } from "./assignment-presentation.js";
|
|
17
|
-
import { manualReviewOnly } from "./proof.js";
|
|
17
|
+
import { manualReviewOnly, shownVerdictOf } from "./proof.js";
|
|
18
18
|
import { ACCEPT_NEEDS_REASON, cantAcceptYetOf } from "./result-acts.js";
|
|
19
|
-
import { runCheckLevel } from "./check-levels.js";
|
|
19
|
+
import { requiredCheckCommandFor, runCheckLevel } from "./check-levels.js";
|
|
20
20
|
import { followUpChecksOf, withFollowUps } from "./result-follow-ups.js";
|
|
21
21
|
import { buildReviewOf, findingWords } from "./review-switch.js";
|
|
22
22
|
import { NEEDS, WAITS, processNeedOf, resultHoldUpSentence } from "./needs-you.js";
|
|
23
|
-
import { assignmentStageOf } from "./task-status.js";
|
|
23
|
+
import { assignmentStageOf, checkBackingOf, completionBlockersOf, requirementWordOf } from "./task-status.js";
|
|
24
|
+
import { releaseCoverageOf } from "./release-coverage.js";
|
|
24
25
|
import { leadClaimOf } from "./lead-voice.js";
|
|
25
26
|
/** Status-first handoff for routine reads. Fetch get_assignment only when
|
|
26
27
|
* inspecting its exact evidence; do not repeat a full proof in every poll. */
|
|
@@ -35,7 +36,7 @@ export function assignmentBrief(assignment) {
|
|
|
35
36
|
base: receipt.base, head: receipt.head, completionKind: receipt.completionKind,
|
|
36
37
|
checks: receipt.checks, proofAcceptance: receipt.proofAcceptance, verdict: receipt.proof?.verdict ?? null,
|
|
37
38
|
criteria: { passed: receipt.proof?.matrix.filter(row => row.state === "pass").length ?? 0, total: receipt.proof?.matrix.length ?? 0 }, evidence: receipt.evidence },
|
|
38
|
-
publication: assignment.publication, review: assignment.review, deployment: assignment.deployment };
|
|
39
|
+
publication: assignment.publication, review: assignment.review, deployment: assignment.deployment, readiness: assignment.readiness ?? null };
|
|
39
40
|
}
|
|
40
41
|
const digest = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
41
42
|
/** A lookup added with lead-quiet, read safely: a deploy proves completion with this code over the INSTALLED runtime's
|
|
@@ -51,7 +52,7 @@ function olderStoreSafe(read, absent) {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
/** A check as the receipt digest seals it: presentation-only fields (check-levels.ts) left out. */
|
|
54
|
-
const sealedChecks = ({ level: _level, running: _running, batch: _batch, ...proof }) => proof;
|
|
55
|
+
const sealedChecks = ({ level: _level, running: _running, batch: _batch, release: _release, ...proof }) => proof;
|
|
55
56
|
const OWNER_ACTION = "assignment claimed";
|
|
56
57
|
const CHECK_ACTION = COMPLETION_ACTION;
|
|
57
58
|
const actorOf = (owner) => `${owner.kind}:${owner.id}`;
|
|
@@ -127,7 +128,7 @@ function buildChecks(store, root, runId) {
|
|
|
127
128
|
return unavailable("Saved checks could not be read.");
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
|
-
export function assignmentOf(store, taskId, now, access, root) {
|
|
131
|
+
export function assignmentOf(store, taskId, now, access, root, memo) {
|
|
131
132
|
const family = store.taskFamilyOf(taskId, access.repos, access.principal === "operator" && access.includeUnplaced === true);
|
|
132
133
|
if (family === null)
|
|
133
134
|
return null;
|
|
@@ -163,7 +164,10 @@ export function assignmentOf(store, taskId, now, access, root) {
|
|
|
163
164
|
const reports = artifacts.filter(a => a.kind === "report");
|
|
164
165
|
const unavailable = family.versions.flatMap(version => store.runsFor(version.refId).flatMap(run => store.artifactsFor(run.id).filter(artifact => root === undefined || !readVerifiedArtifact(root, artifact).ok)
|
|
165
166
|
.map(artifact => `Saved ${artifact.kind} #${artifact.id} (run ${run.id}) is unavailable or changed.`)));
|
|
166
|
-
const
|
|
167
|
+
const ownChecks = result === null ? null : assignmentChecksForRun(store, root, result.id, now);
|
|
168
|
+
// Checks Off: a passing full release check that contains this commit covers it, read now from the existing receipts.
|
|
169
|
+
const checks = ownChecks === null || ownChecks.level !== "off" || ownChecks.status === "passed" || ownChecks.status === "failed" ? ownChecks
|
|
170
|
+
: { ...ownChecks, release: releaseCoverageOf(store, root, current.repo, result.headRevision, memo === undefined ? {} : { memo }) };
|
|
167
171
|
const finishedBuild = result?.role === "builder" && (result.outcome === "built" || result.outcome === "no-change") &&
|
|
168
172
|
result.finishedAt !== null && /^[a-f0-9]{40}$/.test(result.headRevision ?? "");
|
|
169
173
|
// Finished work returns to its lead or user. Strict terms and previous model
|
|
@@ -339,6 +343,7 @@ export function assignmentOf(store, taskId, now, access, root) {
|
|
|
339
343
|
attention, receipt: receipt?.digest ?? null }), acknowledged: false } : null;
|
|
340
344
|
const publication = result === null ? null : store.publicationForRun(result.id);
|
|
341
345
|
const lead = state === "complete" || state === "cancelled" || access.principal !== "operator" ? null : leadClaimOf(store, family.root.id, now, access.viewer);
|
|
346
|
+
const readiness = receipt === null ? null : readinessOf(store, receipt, current.repo, review);
|
|
342
347
|
// Existing saved inputs and output, read only after family admission. Keep
|
|
343
348
|
// polling briefs small; full reads disclose exactly which excerpts are shortened.
|
|
344
349
|
const planId = result?.planRevision == null ? null : store.getPlanRevision(result.planRevision)?.artifact;
|
|
@@ -355,7 +360,21 @@ export function assignmentOf(store, taskId, now, access, root) {
|
|
|
355
360
|
return { version: 1, rootId: family.root.id, activeTaskId: current.id, repo: current.repo, title: family.root.title,
|
|
356
361
|
state, detail, primaryAction, attention: [...new Set(attention)], attempts, owner, receipt, savedContext, completion, handoff,
|
|
357
362
|
publication: publication === null ? null : { state: publication.state, prUrl: publication.prUrl, remoteState: publication.remoteState },
|
|
358
|
-
review, deployment: { status: "not-recorded" }, ...(need === null ? {} : { need }), ...(lead === null ? {} : { lead }), ...(earlierActive.length === 0 ? {} : { earlierActive: earlierActive.length, earlierRunning }) };
|
|
363
|
+
review, deployment: { status: "not-recorded" }, readiness, ...(need === null ? {} : { need }), ...(lead === null ? {} : { lead }), ...(earlierActive.length === 0 ? {} : { earlierActive: earlierActive.length, earlierRunning }) };
|
|
364
|
+
}
|
|
365
|
+
/** The result's shown verdict and completion blockers (task-status.ts), from the receipt, the project's approved check
|
|
366
|
+
* and the automatic review. A HIGH finding a revision already took is resolved there. */
|
|
367
|
+
function readinessOf(store, receipt, repo, review) {
|
|
368
|
+
const report = receipt.completionKind === "research-report";
|
|
369
|
+
const high = review === null || review.sentBackAs !== null || review.state !== "reviewed" ? 0 : review.high.length;
|
|
370
|
+
const checkRequired = olderStoreSafe(() => requiredCheckCommandFor(store, repo, receipt.taskId, receipt.checks.level), null) !== null;
|
|
371
|
+
const matrix = receipt.proof?.matrix ?? [];
|
|
372
|
+
const backing = checkBackingOf(receipt.checks);
|
|
373
|
+
const verdict = shownVerdictOf(receipt.proof?.verdict ?? null, { checkFailed: !report && receipt.checks.status === "failed", highFindings: high,
|
|
374
|
+
reviewPending: review?.state === "pending", criteriaPassed: matrix.every(row => requirementWordOf(row, null, backing) === "Met") });
|
|
375
|
+
const blockers = completionBlockersOf({ report, checks: receipt.checks, checkRequired, matrix, verdict: receipt.proof?.verdict ?? null,
|
|
376
|
+
accepted: receipt.proofAcceptance !== null, high });
|
|
377
|
+
return { verdict, checksOff: !report && receipt.checks.level === "off", blockers };
|
|
359
378
|
}
|
|
360
379
|
function admittedOwner(store, taskId, owner, now, root) {
|
|
361
380
|
if (owner.kind !== "coordinator")
|
|
@@ -417,6 +436,10 @@ function acknowledgeCurrent(store, current, receiptDigest, actor, now, root, acc
|
|
|
417
436
|
if (current.state !== "ready-to-check" && current.state !== "complete")
|
|
418
437
|
return { ok: false, reason: "not-ready", message: "This assignment still has unresolved execution, scope or decisions." };
|
|
419
438
|
if (current.state !== "complete") {
|
|
439
|
+
// The one readiness guard: a failed or missing required check, an unresolved requirement or HIGH finding refuses.
|
|
440
|
+
const blockers = current.readiness?.blockers ?? [];
|
|
441
|
+
if (blockers.length > 0)
|
|
442
|
+
return { ok: false, reason: "not-ready", message: blockers.map(one => one.message).join(" ") };
|
|
420
443
|
// v102: declared paths are only a promise. A result whose actual diff reaches protected files, on a
|
|
421
444
|
// scope one person approved, completes only by someone else — two people have then seen the work.
|
|
422
445
|
const problem = store.protectedResultProblem(receipt.taskId, familyChangedFiles(store, receipt.taskId, receipt.runId, root), actor.startsWith("operator:") ? actor.slice("operator:".length) : null);
|
|
@@ -476,11 +499,14 @@ class Undone extends Error {
|
|
|
476
499
|
* (no reason needed), or an exception a report that doesn't match its changes needs a reason for. Null when
|
|
477
500
|
* Accept and finish is a plain completion: nothing is owed (no proof, a failed check, or a verified result),
|
|
478
501
|
* or it was already accepted. */
|
|
479
|
-
export function owedAcceptance(receipt) {
|
|
502
|
+
export function owedAcceptance(receipt, blockers = []) {
|
|
480
503
|
if (receipt === null || receipt.proofAcceptance !== null)
|
|
481
504
|
return null;
|
|
482
505
|
if (personCheckPending(receipt))
|
|
483
506
|
return "person-check";
|
|
507
|
+
// An unresolved requirement is resolved only by an acceptance that says why.
|
|
508
|
+
if (blockers.some(one => one.key === "criteria"))
|
|
509
|
+
return "exception";
|
|
484
510
|
return cantAcceptYetOf(receipt.proof?.verdict ?? null, receipt.proof?.reasons ?? [], false) === ACCEPT_NEEDS_REASON ? "exception" : null;
|
|
485
511
|
}
|
|
486
512
|
/** Accept and finish: the person's acceptance of the exact result they read and its completion, in one
|
|
@@ -505,7 +531,7 @@ export function acceptAndCompleteAsOperator(store, taskId, input, who, now, root
|
|
|
505
531
|
return { ok: false, reason: "stale", message: "This result changed. Open the current result before accepting it." };
|
|
506
532
|
}
|
|
507
533
|
// Already complete, or nothing owed: the plain completion of the receipt as read.
|
|
508
|
-
const owed = before.state === "ready-to-check" ? owedAcceptance(receipt) : null;
|
|
534
|
+
const owed = before.state === "ready-to-check" ? owedAcceptance(receipt, before.readiness?.blockers ?? []) : null;
|
|
509
535
|
// An exception is accepted only with its reason: never a completion that skips it.
|
|
510
536
|
if (owed === "exception" && input.note === null)
|
|
511
537
|
return { ok: false, reason: "needs-reason", message: `${ACCEPT_NEEDS_REASON}.` };
|