toolroll 0.9.71 → 0.9.73
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 +155 -0
- package/dist/agent-fence.d.ts +10 -2
- package/dist/agent-fence.js +47 -9
- package/dist/approval-authority.d.ts +20 -0
- package/dist/approval-authority.js +67 -0
- package/dist/assignment.js +26 -4
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +28 -28
- package/dist/builder.js +48 -6
- package/dist/chat-actions.js +13 -8
- package/dist/chat-decide.d.ts +47 -1
- package/dist/chat-decide.js +186 -5
- package/dist/check-access.js +2 -2
- package/dist/check-report.d.ts +109 -0
- package/dist/check-report.js +205 -0
- package/dist/claim.js +1 -1
- package/dist/coding-provider.js +4 -2
- package/dist/commit-extract.d.ts +111 -0
- package/dist/commit-extract.js +514 -0
- package/dist/contracts/console-api.d.ts +4 -4
- package/dist/contracts/console-api.js +5 -4
- package/dist/contracts/flow.d.ts +16 -0
- package/dist/contracts/flow.js +3 -0
- package/dist/contracts/release-check.d.ts +335 -0
- package/dist/contracts/release-check.js +159 -0
- package/dist/contracts/release-terms.d.ts +66 -0
- package/dist/contracts/release-terms.js +74 -0
- package/dist/contracts/verification-receipt.d.ts +42 -8
- package/dist/contracts/verification-receipt.js +24 -7
- package/dist/contracts/verification-view.d.ts +1 -0
- package/dist/deploy-gate.d.ts +17 -0
- package/dist/deploy-gate.js +68 -0
- package/dist/dispatch.js +3 -10
- package/dist/dispose.js +4 -1
- package/dist/evidence-pack.d.ts +1 -1
- package/dist/evidence-pack.js +20 -2
- package/dist/evidence.d.ts +1 -0
- package/dist/evidence.js +2 -1
- package/dist/exec.d.ts +1 -1
- package/dist/exec.js +7 -3
- package/dist/flow-engine.js +5 -1
- package/dist/flow-gallery-ui.js +4 -2
- package/dist/flow-gallery.d.ts +3 -0
- package/dist/flow-gallery.js +6 -2
- package/dist/flow-pull-request.d.ts +5 -2
- package/dist/flow-pull-request.js +14 -5
- package/dist/flow-schedule.js +25 -6
- package/dist/flow-triggers.d.ts +8 -0
- package/dist/flow-triggers.js +15 -0
- package/dist/flows-cli.js +13 -3
- package/dist/flows-ui.js +7 -1
- package/dist/guides.js +10 -1
- package/dist/invoke.d.ts +17 -6
- package/dist/invoke.js +48 -18
- package/dist/kits-ui.js +4 -2
- package/dist/kits.d.ts +6 -4
- package/dist/kits.js +9 -11
- package/dist/lead-status.js +5 -2
- package/dist/live-terminal.d.ts +10 -6
- package/dist/live-terminal.js +55 -14
- package/dist/mcp-connect.d.ts +10 -0
- package/dist/mcp-connect.js +2 -0
- package/dist/nightly-check.d.ts +104 -0
- package/dist/nightly-check.js +362 -0
- package/dist/operate.js +39 -2
- package/dist/person-proof.d.ts +2 -0
- package/dist/person-proof.js +14 -0
- package/dist/plan-auto.js +4 -4
- package/dist/planner-source.d.ts +1 -1
- package/dist/project-delete-ui.js +1 -1
- package/dist/project-tools.js +3 -1
- package/dist/proof.js +2 -0
- package/dist/protected-storage.d.ts +67 -0
- package/dist/protected-storage.js +398 -0
- package/dist/publish.js +156 -144
- package/dist/pull-request-flow.d.ts +2 -0
- package/dist/pull-request-flow.js +24 -2
- package/dist/release-adapters.d.ts +16 -1
- package/dist/release-adapters.js +292 -29
- package/dist/release-authority.d.ts +118 -0
- package/dist/release-authority.js +135 -0
- package/dist/release-card.d.ts +76 -0
- package/dist/release-card.js +252 -0
- package/dist/release-carry.d.ts +236 -0
- package/dist/release-carry.js +664 -0
- package/dist/release-cli.d.ts +3 -0
- package/dist/release-cli.js +158 -6
- package/dist/release-coverage.js +3 -0
- package/dist/release-git.d.ts +43 -0
- package/dist/release-git.js +106 -0
- package/dist/release-recheck.d.ts +146 -0
- package/dist/release-recheck.js +657 -0
- package/dist/release-view.d.ts +34 -0
- package/dist/release-view.js +27 -0
- package/dist/release.d.ts +139 -3
- package/dist/release.js +641 -250
- package/dist/remote-main.d.ts +2 -0
- package/dist/remote-main.js +1 -1
- package/dist/result-completion.d.ts +6 -0
- package/dist/result-completion.js +15 -1
- package/dist/result-follow-ups.js +29 -1
- package/dist/sandbox-runtime.d.ts +16 -5
- package/dist/sandbox-runtime.js +19 -6
- package/dist/scope.d.ts +122 -5
- package/dist/scope.js +236 -7
- package/dist/server/flows.js +40 -10
- package/dist/server/render-settings.js +1 -1
- package/dist/server/render-tasks.d.ts +8 -0
- package/dist/server/render-tasks.js +50 -9
- package/dist/server/route-table.js +1 -0
- package/dist/server/settings.js +26 -5
- package/dist/server/task-views.js +4 -0
- package/dist/server/tasks.js +12 -0
- package/dist/setup-guide.d.ts +2 -2
- package/dist/store.d.ts +230 -5
- package/dist/store.js +733 -37
- package/dist/subagent-memory.d.ts +1 -0
- package/dist/subagent-memory.js +1 -1
- package/dist/subagent-tools.d.ts +22 -6
- package/dist/subagent-tools.js +44 -8
- package/dist/subagent-work.d.ts +2 -0
- package/dist/subagent-work.js +5 -2
- package/dist/subagents-ui.js +6 -4
- package/dist/task-outcome-cli.js +7 -3
- package/dist/telegram.d.ts +6 -1
- package/dist/telegram.js +58 -6
- package/dist/toolroll-update.js +2 -2
- package/dist/verification-evidence.d.ts +25 -1
- package/dist/verification-evidence.js +57 -2
- package/dist/work-index.js +3 -6
- package/package.json +1 -1
|
@@ -381,6 +381,7 @@ post("tasks", "task.act.retry-review", `^\\/t\\/${TASK}\\/retry-review$`, { proj
|
|
|
381
381
|
post("tasks", "task.act.complete", `^\\/t\\/${TASK}\\/complete$`, { project: "task", limited: "resource", sample: "/t/one/complete", ...approver("Only an approver can mark a result complete.") });
|
|
382
382
|
post("tasks", "task.act.merge", `^\\/t\\/${TASK}\\/merge$`, { project: "task", limited: "resource", sample: "/t/one/merge", ...approver("Only an approver can merge.") });
|
|
383
383
|
post("tasks", "task.act.confirm-stopped", `^\\/t\\/${TASK}\\/confirm-stopped$`, { scope: "step-up", project: "task", limited: "resource", sample: "/t/one/confirm-stopped", ...approver("Only an approver can confirm a build stopped.") });
|
|
384
|
+
post("tasks", "task.act.stop-carrying", `^\\/t\\/${TASK}\\/stop-carrying$`, { project: "task", limited: "resource", sample: "/t/one/stop-carrying", ...approver("Only an approver can stop carrying a release.") });
|
|
384
385
|
post("tasks", "task.act.stop", `^\\/t\\/${TASK}\\/stop$`, { project: "task", limited: "resource", sample: "/t/one/stop" });
|
|
385
386
|
post("tasks", "task.act.pause", `^\\/t\\/${TASK}\\/pause$`, { project: "task", limited: "resource", sample: "/t/one/pause" });
|
|
386
387
|
post("tasks", "task.act.resume-arm", `^\\/t\\/${TASK}\\/resume-arm$`, { project: "task", limited: "resource", sample: "/t/one/resume-arm" });
|
package/dist/server/settings.js
CHANGED
|
@@ -1422,7 +1422,12 @@ ${repositoryContextHtml(chosen, query, result, who.role === 'approver' ? csrf :
|
|
|
1422
1422
|
for (const [key, visit] of connectVisits)
|
|
1423
1423
|
if (visit.expires < Date.now())
|
|
1424
1424
|
connectVisits.delete(key);
|
|
1425
|
-
|
|
1425
|
+
// The password above proves one thing: this connection, by this account as it is now, and (from a kit whose subagent
|
|
1426
|
+
// is set up) letting that subagent use this tool in this project. The callback holds the visit to exactly that.
|
|
1427
|
+
const kitSet = kit === null || also !== null ? null : kitOf(kit);
|
|
1428
|
+
const installed = kitSet === null || !kitSet.tools.some(one => one.tool === service.id) ? null : kitInstalled(store, kitSet, target);
|
|
1429
|
+
connectVisits.set(started.state, { ...started.visit, generation: store.accountOf(who.name)?.generation ?? -1,
|
|
1430
|
+
grant: installed === null ? null : { subagent: installed.mate.id, tool: service.id, repo: target } });
|
|
1426
1431
|
return goOutside(response, started.go, `Going to ${service.label} to sign in…`, { state: started.state, path: CONNECT_CALLBACK, secure: origin.startsWith("https:") });
|
|
1427
1432
|
}
|
|
1428
1433
|
async function toolsChange(ctx) {
|
|
@@ -2015,6 +2020,11 @@ ${postForm("/settings/chat-approval/save", html `\
|
|
|
2015
2020
|
if (wanted !== "auto" && wanted !== "bypassPermissions") {
|
|
2016
2021
|
return refuse(response, who, 400, "permissions must be Auto or Full access", "/settings");
|
|
2017
2022
|
}
|
|
2023
|
+
// Widening every new task to Full access takes a password (chat-management.md §0a.3): an ordinary step-up, so a
|
|
2024
|
+
// signed-in session does under Passwordless. Back to Auto narrows, and needs none.
|
|
2025
|
+
if (wanted === "bypassPermissions" && store.permissionDefault().mode !== "bypassPermissions" && !authenticateApprover(who, body.get("password") ?? "").ok) {
|
|
2026
|
+
return redirect(response, `/settings?said=${encodeURIComponent("Enter your Toolroll password to start new tasks with Full access. Nothing changed.")}`);
|
|
2027
|
+
}
|
|
2018
2028
|
store.setPermissionDefault(wanted, who.name, now);
|
|
2019
2029
|
return redirect(response, `/settings?said=${encodeURIComponent(wanted === "bypassPermissions"
|
|
2020
2030
|
? "New tasks now start with Full access. Approved tasks keep their setting."
|
|
@@ -2413,7 +2423,14 @@ ${modeWords(terms)
|
|
|
2413
2423
|
return done("/settings/tools", "problem", "That sign-in was started in another browser. Connect again from this one.");
|
|
2414
2424
|
const visit = connectVisits.get(state);
|
|
2415
2425
|
connectVisits.delete(state);
|
|
2416
|
-
|
|
2426
|
+
// The signer as at Connect: still an approver, not revoked, the same generation, still in the project. Checked here,
|
|
2427
|
+
// before the connection changes, and again at the grant, after every wait.
|
|
2428
|
+
const standing = () => {
|
|
2429
|
+
const account = visit === undefined ? null : store.accountOf(visit.by);
|
|
2430
|
+
return visit !== undefined && account !== null && account.role === "approver" && account.revokedAt === null && visit.generation !== undefined
|
|
2431
|
+
&& account.generation === visit.generation && store.accountCanAccess(visit.by, visit.repo);
|
|
2432
|
+
};
|
|
2433
|
+
if (visit === undefined || visit.expires < Date.now() || !standing())
|
|
2417
2434
|
return done("/settings/tools", "problem", "That sign-in expired. Connect again.");
|
|
2418
2435
|
const service = oneClickOf(visit.service);
|
|
2419
2436
|
const kit = visit.kit === null ? null : kitOf(visit.kit);
|
|
@@ -2430,13 +2447,17 @@ ${modeWords(terms)
|
|
|
2430
2447
|
const now = clock();
|
|
2431
2448
|
if (!adapterPolicy({ caller: "service", capability: "none" }).ok)
|
|
2432
2449
|
return respond(response, 403, "text/plain", "Forbidden");
|
|
2433
|
-
const finished = await finishConnect(store, visit, code, now, { fetcher: options.connectFetch ?? fetch, home: toolHome, omitEnv: ALL_CREDENTIAL_ENV });
|
|
2450
|
+
const finished = await finishConnect(store, visit, code, now, { fetcher: options.connectFetch ?? fetch, home: toolHome, omitEnv: ALL_CREDENTIAL_ENV, stillStanding: standing });
|
|
2434
2451
|
if (!finished.ok)
|
|
2435
2452
|
return done(back, "problem", finished.said);
|
|
2436
2453
|
// From a kit: its teammate may use the tool now (reading freely, the rest after a person approves each call).
|
|
2437
2454
|
const set = kit === null || !kit.tools.some(one => one.tool === service.id) ? null : kitInstalled(store, kit, visit.repo);
|
|
2438
|
-
|
|
2439
|
-
|
|
2455
|
+
const bound = visit.grant ?? null;
|
|
2456
|
+
if (set !== null && bound !== null && bound.subagent === set.mate.id && bound.tool === service.id && bound.repo === visit.repo && set.mate.repo === visit.repo
|
|
2457
|
+
&& store.subagentGrant(set.mate.id, service.id) === null && standing()) {
|
|
2458
|
+
// The password at Connect (toolsConnect) is this grant's proof, for exactly the grant the visit names, while the
|
|
2459
|
+
// signer still stands: re-checked after the tool's listing, in the step that saves the grant.
|
|
2460
|
+
const granted = await grantTool(store, set.mate, service.id, visit.by, now, { toolHome }, { widening: "proved", stillProved: standing });
|
|
2440
2461
|
if (granted.ok)
|
|
2441
2462
|
return done(back, "said", `${service.label} is connected to ${to}, and ${nameOf(set.mate)} can use it: reading freely, the rest after you approve each call.`);
|
|
2442
2463
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { releaseViewOf } from "../release-view.js";
|
|
2
|
+
import { releaseObligationsOf } from "../release-recheck.js";
|
|
1
3
|
import { approvalProofOf, freshlyApprovable, freshnessFor, withFreshness } from "../scope.js";
|
|
2
4
|
import { liveAttemptOf, steerControlsFor } from "../steer-controls.js";
|
|
3
5
|
import { originOf } from "../task-source.js";
|
|
@@ -493,6 +495,8 @@ export function createTaskViews(runtime) {
|
|
|
493
495
|
base: taskBaseOf(runtime.store, taskId),
|
|
494
496
|
steeringLive: ref !== null && runtime.store.steeringLiveBuild(ref.id, now) !== null,
|
|
495
497
|
steeringRun: ref === null ? null : runtime.store.steeringLiveBuild(ref.id, now),
|
|
498
|
+
release: ref === null ? null : releaseViewOf(runtime.store, ref.externalId, now, authority => releaseObligationsOf(runtime.store, runtime.evidenceRoot, authority)),
|
|
499
|
+
canStopRelease: who.role === "approver" && who.via === "cookie",
|
|
496
500
|
approvalProof: (() => {
|
|
497
501
|
// The proof of the approval shown: its approver, its exact sealed digest (approvedDigest === digest when approved).
|
|
498
502
|
const scope = ref === null ? null : runtime.store.getScope(ref.externalId);
|
package/dist/server/tasks.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { releaseAuthorityOfTask, revokeRelease } from "../store.js";
|
|
1
2
|
import { steerCapabilityOf } from "../steer-capabilities.js";
|
|
2
3
|
import { canReveal, localCheckoutOf, revealInFinder } from "../checkout-proof.js";
|
|
3
4
|
/** A form's way back to a flow card ("flow:<flow>:<card>"), read strictly: numbers only, never a path. */
|
|
@@ -1972,6 +1973,16 @@ export function createTasksHandlers(runtime) {
|
|
|
1972
1973
|
store.unhold(ref.id);
|
|
1973
1974
|
return redirect(response, taskHref(taskId));
|
|
1974
1975
|
}
|
|
1976
|
+
case "stop-carrying": {
|
|
1977
|
+
// One click, any active approver (release-once.md): later commits of this release ask again. Only ever stricter.
|
|
1978
|
+
const found = releaseAuthorityOfTask(store, taskId);
|
|
1979
|
+
if (found === null)
|
|
1980
|
+
return taskScreen(response, who, taskId, "This task isn't part of a release.", 409);
|
|
1981
|
+
const stopped = revokeRelease(store, found.authority.id, who.name, now);
|
|
1982
|
+
if (!stopped.ok)
|
|
1983
|
+
return taskScreen(response, who, taskId, stopped.why, 409);
|
|
1984
|
+
return redirect(response, `${taskHref(taskId)}#release`);
|
|
1985
|
+
}
|
|
1975
1986
|
case "requeue": {
|
|
1976
1987
|
const body = readForm(posted, CONSOLE_FORMS.taskRequeue);
|
|
1977
1988
|
// Retry may carry a note for the next attempt: the same steering note, checked before anything changes.
|
|
@@ -3036,6 +3047,7 @@ export function createTasksHandlers(runtime) {
|
|
|
3036
3047
|
"task.act.merge": taskMerge,
|
|
3037
3048
|
"task.act.confirm-stopped": taskConfirmStopped,
|
|
3038
3049
|
"task.act.stop": taskAct("stop"),
|
|
3050
|
+
"task.act.stop-carrying": taskAct("stop-carrying"),
|
|
3039
3051
|
"task.act.pause": taskAct("pause"),
|
|
3040
3052
|
"task.act.resume-arm": taskAct("resume-arm"),
|
|
3041
3053
|
"task.act.resume": taskAct("resume"),
|
package/dist/setup-guide.d.ts
CHANGED
|
@@ -15,10 +15,10 @@ export declare function detectPreparation(repo: string): {
|
|
|
15
15
|
} | null;
|
|
16
16
|
/** Browser installation may write only this known file inside its project. */
|
|
17
17
|
export declare function previewProjectInstructions(repo: string): {
|
|
18
|
+
content?: never;
|
|
18
19
|
ok: false;
|
|
19
20
|
message: string;
|
|
20
21
|
plan?: never;
|
|
21
|
-
content?: never;
|
|
22
22
|
fingerprint?: never;
|
|
23
23
|
installed?: never;
|
|
24
24
|
} | {
|
|
@@ -30,10 +30,10 @@ export declare function previewProjectInstructions(repo: string): {
|
|
|
30
30
|
installed: boolean;
|
|
31
31
|
};
|
|
32
32
|
export declare function addProjectInstructions(repo: string, fingerprint: string): {
|
|
33
|
+
content?: never;
|
|
33
34
|
ok: false;
|
|
34
35
|
message: string;
|
|
35
36
|
plan?: never;
|
|
36
|
-
content?: never;
|
|
37
37
|
fingerprint?: never;
|
|
38
38
|
installed?: never;
|
|
39
39
|
} | import("./skills.js").InstallResult;
|
package/dist/store.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { type Actor } from "./actor.js";
|
|
|
15
15
|
import { type LiveActivityKind } from "./live.js";
|
|
16
16
|
import { type CredentialKind, type TokenPurpose } from "./api-tokens.js";
|
|
17
17
|
import { type CriterionMatrixRow, type CriterionJudgementWord } from "./proof.js";
|
|
18
|
-
import { type ExecutionProfile, type UnattendedPermissionMode, type AcceptanceCriterion } from "./scope.js";
|
|
18
|
+
import { type ScopeAuthor, type ExecutionProfile, type UnattendedPermissionMode, type AcceptanceCriterion } from "./scope.js";
|
|
19
19
|
import { type ProviderRoom, type CandidateTier, type TaskSize, type TaskSizing, type PhaseRoute, type PublicationAuthority, type RouteStamp, type ReadinessLookup, type ReadinessObservation, type RouteOverride } from "./phase-routing.js";
|
|
20
20
|
import type { TerminalClass } from "./exhaustion.js";
|
|
21
21
|
import { type ProviderId } from "./provider.js";
|
|
@@ -26,6 +26,7 @@ import type { Scope } from "./scope.js";
|
|
|
26
26
|
import type { QualityMode } from "./quality.js";
|
|
27
27
|
import type { ProgressSnapshot } from "./plan.js";
|
|
28
28
|
import { type CheckProgressSnapshot } from "./check-progress.js";
|
|
29
|
+
import { type ReleaseTerms } from "./contracts/release-terms.js";
|
|
29
30
|
import { type ProjectAccess } from "./project-access.js";
|
|
30
31
|
import { type LedgerEntry } from "./action-ledger.js";
|
|
31
32
|
import type { LimitReading, LimitWindow } from "./provider-limits.js";
|
|
@@ -182,7 +183,7 @@ export type SealedLedgerEntry = LedgerEntry & {
|
|
|
182
183
|
hash: string;
|
|
183
184
|
} | null;
|
|
184
185
|
};
|
|
185
|
-
export declare const SCHEMA_VERSION =
|
|
186
|
+
export declare const SCHEMA_VERSION = 135;
|
|
186
187
|
/** v118: the tables merged into `credential`, in the order they move (a person's API tokens keep their ids first). */
|
|
187
188
|
export declare const V118_MERGED_TABLES: Readonly<Record<string, CredentialKind>>;
|
|
188
189
|
/**
|
|
@@ -316,6 +317,26 @@ export declare const V129_ADDED_COLUMNS: Readonly<Record<string, Readonly<Record
|
|
|
316
317
|
definition: string;
|
|
317
318
|
saved: string;
|
|
318
319
|
}>>>>;
|
|
320
|
+
/** v134 (approval policy): how each protected-work vote was proved, and who decided a flow card at a decision zone.
|
|
321
|
+
* Saved rows read NULL: no proof or authority on record, which never counts as a person. */
|
|
322
|
+
export declare const V134_ADDED_COLUMNS: Readonly<Record<string, Readonly<Record<string, {
|
|
323
|
+
definition: string;
|
|
324
|
+
saved: string;
|
|
325
|
+
}>>>>;
|
|
326
|
+
/** v135 (docs/plans/release-once.md): a scope's release terms, part of its digest when present. Saved rows read NULL. */
|
|
327
|
+
export declare const V135_ADDED_COLUMNS: Readonly<Record<string, Readonly<Record<string, {
|
|
328
|
+
definition: string;
|
|
329
|
+
saved: string;
|
|
330
|
+
}>>>>;
|
|
331
|
+
/**
|
|
332
|
+
* v135: one approval per release (docs/plans/release-once.md). `release_authority` is the single source of truth for a
|
|
333
|
+
* release a person approved: one row per generation, changed only by compare-and-swap on `rev`, with a lease whose
|
|
334
|
+
* epoch goes up on every takeover. `release_carry` records each later commit carried under it, `release_operation` each
|
|
335
|
+
* deploy or merge that can't be undone. `release_check_attempt` seals a check's intended mode, inventory and context
|
|
336
|
+
* before it runs. `main_check_failure` keeps one row per item the nightly full check on main found failing, until a
|
|
337
|
+
* qualifying full pass clears that exact item; `nightly_check` records each nightly firing.
|
|
338
|
+
*/
|
|
339
|
+
export declare const RELEASE_ONCE_SCHEMA = "\nCREATE TABLE IF NOT EXISTS release_authority (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n repo TEXT NOT NULL,\n generation INTEGER NOT NULL,\n previous INTEGER REFERENCES release_authority(id),\n version TEXT NOT NULL,\n pr INTEGER NOT NULL,\n branch TEXT NOT NULL,\n base TEXT NOT NULL,\n anchor_task TEXT NOT NULL,\n anchor_digest TEXT NOT NULL,\n approved_sha TEXT NOT NULL,\n approved_tree TEXT NOT NULL,\n artifact_digest TEXT,\n tip_sha TEXT NOT NULL,\n tip_task TEXT NOT NULL,\n policy_json TEXT NOT NULL,\n policy_digest TEXT NOT NULL,\n verify_command INTEGER NOT NULL,\n verify_digest TEXT NOT NULL,\n access_digest TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('open','deploying','merge-reserved','merged','revoked','expired','superseded')),\n rev INTEGER NOT NULL DEFAULT 0,\n lease_owner TEXT,\n lease_epoch INTEGER NOT NULL DEFAULT 0,\n lease_expires TEXT,\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL,\n ended_at TEXT,\n ended_by TEXT,\n UNIQUE (repo, version, pr, generation)\n);\nCREATE UNIQUE INDEX IF NOT EXISTS release_authority_live ON release_authority (repo, version, pr)\n WHERE state IN ('open','deploying','merge-reserved');\nCREATE INDEX IF NOT EXISTS release_authority_anchor ON release_authority (anchor_task);\nCREATE TABLE IF NOT EXISTS release_carry (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n authority INTEGER NOT NULL REFERENCES release_authority(id),\n task_id TEXT NOT NULL UNIQUE,\n scope_digest TEXT NOT NULL,\n request_id TEXT NOT NULL,\n from_sha TEXT NOT NULL,\n to_sha TEXT NOT NULL,\n to_tree TEXT NOT NULL,\n artifact_digest TEXT NOT NULL,\n commits_json TEXT NOT NULL,\n changed_lines INTEGER NOT NULL,\n files INTEGER NOT NULL,\n churn INTEGER NOT NULL,\n runtime TEXT NOT NULL,\n proved_at TEXT NOT NULL,\n UNIQUE (authority, to_sha)\n);\nCREATE TABLE IF NOT EXISTS release_operation (\n id TEXT PRIMARY KEY,\n authority INTEGER NOT NULL REFERENCES release_authority(id),\n kind TEXT NOT NULL CHECK (kind IN ('deploy','merge')),\n task_id TEXT NOT NULL,\n candidate TEXT NOT NULL,\n epoch INTEGER NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('reserved','running','succeeded','failed','unknown')),\n external_ref TEXT,\n -- The sha256 of a secret only the reserving coordinator holds: a deploy run adopting this operation proves it.\n secret_hash TEXT,\n -- 1: reserved by a person's own deploy run with no coordinator holding the release (its epoch is the one it found).\n direct INTEGER NOT NULL DEFAULT 0,\n -- The process that reserved, then issued, the call: its pid, its start time and when it was recorded (real time).\n -- Recovery settles a started operation only once that process is proven gone (review round 2).\n issuer_pid INTEGER,\n issuer_started TEXT,\n issued_at TEXT,\n -- A person's direct deploy: the staging folder its deployment journals in.\n stage TEXT,\n reserved_at TEXT NOT NULL,\n finished_at TEXT,\n detail TEXT\n);\nCREATE INDEX IF NOT EXISTS release_operation_open ON release_operation (authority, state);\nCREATE TABLE IF NOT EXISTS release_check_attempt (\n run INTEGER PRIMARY KEY REFERENCES run(id),\n authority INTEGER REFERENCES release_authority(id),\n mode TEXT NOT NULL CHECK (mode IN ('full','targeted')),\n base_run INTEGER REFERENCES run(id),\n plan_digest TEXT,\n snapshot_digest TEXT,\n inventory_digest TEXT NOT NULL,\n context_digest TEXT NOT NULL,\n nonce_hash TEXT NOT NULL,\n created_at TEXT NOT NULL,\n settled_at TEXT\n);\nCREATE TABLE IF NOT EXISTS main_check_failure (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n repo TEXT NOT NULL,\n sha TEXT NOT NULL,\n run INTEGER NOT NULL,\n item TEXT NOT NULL,\n opened_at TEXT NOT NULL,\n cleared_by_run INTEGER,\n cleared_at TEXT,\n UNIQUE (repo, run, item)\n);\nCREATE INDEX IF NOT EXISTS main_check_failure_open ON main_check_failure (repo) WHERE cleared_at IS NULL;\nCREATE TABLE IF NOT EXISTS nightly_check (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n repo TEXT NOT NULL,\n sha TEXT NOT NULL,\n task TEXT,\n run INTEGER,\n outcome TEXT,\n at TEXT NOT NULL\n);\n";
|
|
319
340
|
/** v130: a project's network (an approver's setting, egress.ts ProjectNetwork as JSON) and the installation's choice
|
|
320
341
|
* whether an agent may run where no OS confinement exists (one row; 0 until an instance operator turns it on). */
|
|
321
342
|
export declare const CONFINEMENT_SCHEMA = "\nCREATE TABLE IF NOT EXISTS project_network (\n repo TEXT PRIMARY KEY,\n network_json TEXT NOT NULL CHECK (length(network_json) <= 16384),\n updated_at TEXT NOT NULL,\n updated_by TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS confinement_setting (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n unfenced_allowed INTEGER NOT NULL DEFAULT 0 CHECK (unfenced_allowed IN (0, 1)),\n updated_at TEXT,\n updated_by TEXT\n);\nINSERT OR IGNORE INTO confinement_setting (id, unfenced_allowed) VALUES (1, 0);\n";
|
|
@@ -2312,7 +2333,9 @@ export declare class Store {
|
|
|
2312
2333
|
permissionMode?: UnattendedPermissionMode;
|
|
2313
2334
|
qualityMode?: QualityMode;
|
|
2314
2335
|
posture?: "escalated";
|
|
2315
|
-
proposedVia?:
|
|
2336
|
+
proposedVia?: ScopeAuthor | null;
|
|
2337
|
+
/** v135: release terms (release-once.md); undefined keeps the ones the scope carries, null removes them. */
|
|
2338
|
+
releaseTerms?: ReleaseTerms | null;
|
|
2316
2339
|
}): void;
|
|
2317
2340
|
/**
|
|
2318
2341
|
* Re-file a scope under its OWN current words (v47): the route is
|
|
@@ -2329,8 +2352,11 @@ export declare class Store {
|
|
|
2329
2352
|
* exactly what the signed digest was bound to. Returns false when the
|
|
2330
2353
|
* scope vanished mid-ceremony. */
|
|
2331
2354
|
sealScopeApproval(taskId: string, by: string, now: Date, mutation?: Mutation, basis?: {
|
|
2332
|
-
kind: "mode" | "chat" | "grant";
|
|
2355
|
+
kind: "mode" | "chat" | "grant" | "schedule";
|
|
2333
2356
|
modeDigest: string;
|
|
2357
|
+
/** A chat seal of a deploy gate: the release card it came from (chat-management.md §0a.5). */
|
|
2358
|
+
card?: "release";
|
|
2359
|
+
cardDigest?: string;
|
|
2334
2360
|
}, approverKind?: ApproverKind): boolean;
|
|
2335
2361
|
/** Whether this task's scope carries a LIVE seal: approved, and the
|
|
2336
2362
|
* approved digest is the current one (a rewritten scope unseals). The
|
|
@@ -2449,7 +2475,7 @@ export declare class Store {
|
|
|
2449
2475
|
* changed files come from the build's own diff; `null` (unreadable) counts as protected. */
|
|
2450
2476
|
protectedResultProblem(taskId: string, changed: readonly string[] | null, completer: string | null): string | null;
|
|
2451
2477
|
/** One person's yes to these exact bytes (protected work counts two). */
|
|
2452
|
-
recordApprovalVote(taskId: string, digest: string, by: string, now: Date): void;
|
|
2478
|
+
recordApprovalVote(taskId: string, digest: string, by: string, now: Date, proof: string): void;
|
|
2453
2479
|
/** Who has approved the current scope so far (protected work). */
|
|
2454
2480
|
approvalVotes(taskId: string): {
|
|
2455
2481
|
approver: string;
|
|
@@ -5694,6 +5720,9 @@ export declare class Store {
|
|
|
5694
5720
|
expectEntry?: number;
|
|
5695
5721
|
/** v91: said in the card's history only; the card's note ({{note}}) is left as it is. */
|
|
5696
5722
|
historyNote?: string;
|
|
5723
|
+
/** v134: who decided a decision move (approval policy §1.7): a person, a subagent, or a machine credential. Only a
|
|
5724
|
+
* person's approval lets a Pull request zone merge. Absent on other moves. */
|
|
5725
|
+
authority?: FlowDecisionAuthority;
|
|
5697
5726
|
}, now: Date): boolean;
|
|
5698
5727
|
/** What a card's current zone is doing: its task, the card's main work, what it waits on, what zones reported. */
|
|
5699
5728
|
/** Read and written in one transaction, so a pass changing one field never writes back another pass's older task or waiting. */
|
|
@@ -5707,6 +5736,7 @@ export declare class Store {
|
|
|
5707
5736
|
actor: string;
|
|
5708
5737
|
note: string | null;
|
|
5709
5738
|
at: string;
|
|
5739
|
+
authority: FlowDecisionAuthority | null;
|
|
5710
5740
|
}[];
|
|
5711
5741
|
/** When a card came into the zone it is in: its latest history line (it is written with every move). */
|
|
5712
5742
|
flowCardEnteredAt(card: number): string | null;
|
|
@@ -7522,3 +7552,198 @@ export type VerifiedAuthor = string & {
|
|
|
7522
7552
|
readonly __verifiedAuthor: unique symbol;
|
|
7523
7553
|
};
|
|
7524
7554
|
export declare function verifiedAuthor(name: string): VerifiedAuthor;
|
|
7555
|
+
/**
|
|
7556
|
+
* Who wrote a scope's text after this write (docs/plans/approval-policy.md §1.4), from trusted context only. A person's
|
|
7557
|
+
* write sets what the caller says (null for their own words), as always. A machine's write — the lead's token or a
|
|
7558
|
+
* remote API run — never clears or downgrades a mark: a quarantined author (a chat proposal, a scout, a coordinator)
|
|
7559
|
+
* stays, and otherwise the lead's write is marked `lead` (a remote run's keeps whatever was there).
|
|
7560
|
+
*/
|
|
7561
|
+
export declare function provenanceAfter(prior: unknown, requested: ScopeAuthor | null): ScopeAuthor | null;
|
|
7562
|
+
/** Who decided a flow card at a decision zone (v134, approval policy §1.7). */
|
|
7563
|
+
export type FlowDecisionAuthority = "person" | "subagent" | "lead" | "remote";
|
|
7564
|
+
export declare const FLOW_DECISION_AUTHORITIES: readonly FlowDecisionAuthority[];
|
|
7565
|
+
/** A release check attempt, sealed before its command runs (release_check_attempt). */
|
|
7566
|
+
export type CheckAttempt = {
|
|
7567
|
+
run: number;
|
|
7568
|
+
authority: number | null;
|
|
7569
|
+
mode: "full" | "targeted";
|
|
7570
|
+
baseRun: number | null;
|
|
7571
|
+
planDigest: string | null;
|
|
7572
|
+
snapshotDigest: string | null;
|
|
7573
|
+
inventoryDigest: string;
|
|
7574
|
+
contextDigest: string;
|
|
7575
|
+
nonceHash: string;
|
|
7576
|
+
createdAt: string;
|
|
7577
|
+
settledAt: string | null;
|
|
7578
|
+
};
|
|
7579
|
+
/** Seal a check attempt before its command is spawned. Once written it never changes (bar its settled mark). */
|
|
7580
|
+
export declare function recordCheckAttempt(store: Store, attempt: Omit<CheckAttempt, "createdAt" | "settledAt">, now: Date): void;
|
|
7581
|
+
/** A run's sealed check attempt, or null. */
|
|
7582
|
+
export declare function checkAttemptOf(store: Store, run: number): CheckAttempt | null;
|
|
7583
|
+
/** Release terms as this code writes them: the contract's own reading of them, serialized. */
|
|
7584
|
+
export declare function serializeReleaseTerms(terms: ReleaseTerms): string;
|
|
7585
|
+
export { LIVE_RELEASE_STATES, belongsToRelease, newestReleaseGeneration, outstandingReleaseOperations, releaseAuthority, releaseAuthorityOfTask, releaseCarries, releaseCarryTo, releaseOperation, releaseOperations, releaseSealProblem, type ReleaseAuthority, type ReleaseCarry, type ReleaseOperation, type ReleaseState, } from "./release-authority.js";
|
|
7586
|
+
import { type ReleaseCarry, type ReleaseOperation } from "./release-authority.js";
|
|
7587
|
+
/**
|
|
7588
|
+
* Open a release's authority for a person's seal of its terms (inside the seal's transaction): the next generation,
|
|
7589
|
+
* superseding the live one. False when it can't (releaseSealProblem), which refuses the seal.
|
|
7590
|
+
*/
|
|
7591
|
+
export declare function openReleaseAuthority(store: Store, input: {
|
|
7592
|
+
taskId: string;
|
|
7593
|
+
digest: string;
|
|
7594
|
+
terms: ReleaseTerms;
|
|
7595
|
+
by: string;
|
|
7596
|
+
now: Date;
|
|
7597
|
+
}): number | null;
|
|
7598
|
+
/** Seal the anchor's artifact digest once (the person's seal authorized building that approved commit). */
|
|
7599
|
+
export declare function sealAnchorArtifact(store: Store, id: number, digest: string, now: Date): boolean;
|
|
7600
|
+
/** Take (or keep) a release's lease. A takeover by another owner raises the epoch, which fences every operation the
|
|
7601
|
+
* old owner reserved. */
|
|
7602
|
+
export declare function takeReleaseLease(store: Store, id: number, owner: string, now: Date, ttlMs?: number): {
|
|
7603
|
+
ok: true;
|
|
7604
|
+
epoch: number;
|
|
7605
|
+
} | {
|
|
7606
|
+
ok: false;
|
|
7607
|
+
why: string;
|
|
7608
|
+
};
|
|
7609
|
+
/** Renew a lease this owner still holds at this epoch. */
|
|
7610
|
+
export declare function renewReleaseLease(store: Store, id: number, owner: string, epoch: number, now: Date, ttlMs?: number): boolean;
|
|
7611
|
+
/**
|
|
7612
|
+
* Reserve a deploy or a merge of the release tip (the freeze happens here, in the store): a deploy moves `open` to
|
|
7613
|
+
* `deploying` (or, already deploying, reserves a new attempt of the same frozen candidate); a merge moves `deploying`
|
|
7614
|
+
* to `merge-reserved`. `epoch` null is a direct deploy by a person: it takes the current epoch, and only while no
|
|
7615
|
+
* coordinator holds a live lease. Refused while any earlier operation is unsettled.
|
|
7616
|
+
*/
|
|
7617
|
+
export declare function reserveRelease(store: Store, input: {
|
|
7618
|
+
authority: number;
|
|
7619
|
+
kind: "deploy" | "merge";
|
|
7620
|
+
taskId: string;
|
|
7621
|
+
candidate: string;
|
|
7622
|
+
epoch: number | null;
|
|
7623
|
+
operationId: string;
|
|
7624
|
+
now: Date;
|
|
7625
|
+
secret?: string;
|
|
7626
|
+
issuer?: ReleaseIssuer;
|
|
7627
|
+
stage?: string;
|
|
7628
|
+
}): {
|
|
7629
|
+
ok: true;
|
|
7630
|
+
operation: ReleaseOperation;
|
|
7631
|
+
} | {
|
|
7632
|
+
ok: false;
|
|
7633
|
+
why: string;
|
|
7634
|
+
};
|
|
7635
|
+
/** The external call's own fence, taken immediately before the call is spawned: `reserved` → `running` (issuing) only
|
|
7636
|
+
* at the epoch that reserved it, while that epoch still holds the lease (a direct deploy's epoch is checked as
|
|
7637
|
+
* reserved) and the release stands, recording the process that issues it. False: the call must not start. */
|
|
7638
|
+
export declare function runReleaseOperation(store: Store, id: string, epoch: number, now: Date, issuer?: ReleaseIssuer): boolean;
|
|
7639
|
+
/** Settle an operation: `succeeded`, `failed` or `unknown` (reconciled later). A merge that succeeded ends the release
|
|
7640
|
+
* as `merged`; one that failed puts it back to `deploying`. */
|
|
7641
|
+
export declare function finishReleaseOperation(store: Store, id: string, outcome: "succeeded" | "failed" | "unknown", facts: {
|
|
7642
|
+
externalRef?: string | null;
|
|
7643
|
+
detail?: string | null;
|
|
7644
|
+
}, now: Date, epoch: number): boolean;
|
|
7645
|
+
/** Stop carrying later commits: any active approver, any time before the merge starts. */
|
|
7646
|
+
export declare function revokeRelease(store: Store, id: number, by: string, now: Date): {
|
|
7647
|
+
ok: true;
|
|
7648
|
+
} | {
|
|
7649
|
+
ok: false;
|
|
7650
|
+
why: string;
|
|
7651
|
+
};
|
|
7652
|
+
/** Write the carry, in the one transaction that re-proves every mutable fact first (release-carry.ts proveCarry). */
|
|
7653
|
+
export type CarryWrite = {
|
|
7654
|
+
authority: number;
|
|
7655
|
+
expectRev: number;
|
|
7656
|
+
expectTip: string;
|
|
7657
|
+
to: string;
|
|
7658
|
+
toTree: string;
|
|
7659
|
+
requestId: string;
|
|
7660
|
+
artifactDigest: string;
|
|
7661
|
+
commits: ReleaseCarry["commits"];
|
|
7662
|
+
changedLines: number;
|
|
7663
|
+
files: number;
|
|
7664
|
+
churn: number;
|
|
7665
|
+
runtime: string;
|
|
7666
|
+
taskId: string;
|
|
7667
|
+
title: string;
|
|
7668
|
+
};
|
|
7669
|
+
/**
|
|
7670
|
+
* THE carry transaction (release-carry.ts proveCarry step 4), one BEGIN IMMEDIATE: every mutable fact is proved again
|
|
7671
|
+
* — the authority's `rev` and tip, its state and expiry and the whole live-release predicate (liveReleaseOf), the
|
|
7672
|
+
* anchor's sealed artifact digest equal to the candidate's, and whatever `recheck` re-reads (the policy, grant and
|
|
7673
|
+
* check access as they are now) — then it writes the carried task and its scope (the anchor's approved terms, profile,
|
|
7674
|
+
* route and acceptance verbatim, with candidate `to`), its seal (basis `carried`, reference `<authority>:<carry>`), the
|
|
7675
|
+
* carry row, the new tip with `rev + 1`, and the ledger row. A carry already written for (authority, `to`) is returned
|
|
7676
|
+
* as it is.
|
|
7677
|
+
*/
|
|
7678
|
+
export declare function carryReleaseApproval(store: Store, w: CarryWrite, now: Date, recheck: () => string | null): {
|
|
7679
|
+
ok: true;
|
|
7680
|
+
taskId: string;
|
|
7681
|
+
carry: ReleaseCarry;
|
|
7682
|
+
} | {
|
|
7683
|
+
ok: false;
|
|
7684
|
+
why: string;
|
|
7685
|
+
};
|
|
7686
|
+
/** Thrown inside a seal whose release authority can't open: the whole seal rolls back. */
|
|
7687
|
+
export declare class ReleaseSealRefused extends Error {
|
|
7688
|
+
}
|
|
7689
|
+
/**
|
|
7690
|
+
* Whether a deploy run may adopt operation `id` (deploy-browser.mjs --operation): it is this release's running deploy of
|
|
7691
|
+
* this candidate, reserved at the epoch that still holds a live lease, and the run proves the secret only the
|
|
7692
|
+
* reserving coordinator holds (handed over on stdin, never in argv).
|
|
7693
|
+
*/
|
|
7694
|
+
export declare function adoptReleaseOperation(store: Store, input: {
|
|
7695
|
+
id: string;
|
|
7696
|
+
authority: number;
|
|
7697
|
+
candidate: string;
|
|
7698
|
+
secret: string;
|
|
7699
|
+
now: Date;
|
|
7700
|
+
}): {
|
|
7701
|
+
ok: true;
|
|
7702
|
+
} | {
|
|
7703
|
+
ok: false;
|
|
7704
|
+
why: string;
|
|
7705
|
+
};
|
|
7706
|
+
/** The nightly check of main is a check only (release-once.md, part 3). */
|
|
7707
|
+
export declare const NIGHTLY_CHECK_ONLY = "The nightly check of main is only a check; it is never published or merged.";
|
|
7708
|
+
/** Whether a task reference is a nightly check of main. */
|
|
7709
|
+
export declare function nightlyTaskRef(store: Store, taskRef: number): boolean;
|
|
7710
|
+
/** Whether a publication belongs to a nightly check of main. */
|
|
7711
|
+
export declare function nightlyPublication(store: Store, publication: number): boolean;
|
|
7712
|
+
/** A release's result merges only through its coordinator: every other merge road refuses it. */
|
|
7713
|
+
export declare const RELEASE_MERGES_ONLY = "This result belongs to a release; it merges only through `toolroll release`.";
|
|
7714
|
+
/** Whether a task reference is a release's anchor or a carried release task. */
|
|
7715
|
+
export declare function releaseTaskRef(store: Store, taskRef: number): boolean;
|
|
7716
|
+
/** Whether a publication belongs to a release's task. */
|
|
7717
|
+
export declare function releasePublication(store: Store, publication: number): boolean;
|
|
7718
|
+
/** The ledger act that records a trusted read of a project's recorded remote main (remote-main.ts). */
|
|
7719
|
+
export declare const TRUSTED_MAIN_ACTION = "remote main read";
|
|
7720
|
+
/** The identity of a project's recorded remote: its URL and the ledger record that last set it (0: set on admission
|
|
7721
|
+
* with no record). A read of main stands only for the remote identity it was read from (review round 2). */
|
|
7722
|
+
export declare function trustedRemoteIdentity(store: Store, repo: string): {
|
|
7723
|
+
url: string;
|
|
7724
|
+
record: number;
|
|
7725
|
+
} | null;
|
|
7726
|
+
/** Record the commit the project's recorded remote main was at, as Toolroll's own process fetched it just now from
|
|
7727
|
+
* `url`, bound to the remote's identity at this moment. Refused (nothing recorded) when `url` isn't the recorded one. */
|
|
7728
|
+
export declare function recordTrustedMain(store: Store, repo: string, sha: string, url: string, now: Date): boolean;
|
|
7729
|
+
/** A failed read of the recorded remote: the last read no longer stands. */
|
|
7730
|
+
export declare function forgetTrustedMain(store: Store, repo: string, why: string, now: Date): void;
|
|
7731
|
+
/**
|
|
7732
|
+
* A pull request check failed after the deploy reservation (Alex, 2026-10-25): the candidate froze at deploy, so the
|
|
7733
|
+
* release stops and asks a person again — even for the same commit, a new person-approved generation continues it.
|
|
7734
|
+
*/
|
|
7735
|
+
export declare function requireFreshReleaseApproval(store: Store, id: number, reason: string, epoch: number, now: Date): boolean;
|
|
7736
|
+
/** The process that reserves or issues a release operation: its pid, its start time, and when it was recorded. */
|
|
7737
|
+
export type ReleaseIssuer = {
|
|
7738
|
+
pid: number;
|
|
7739
|
+
started: string;
|
|
7740
|
+
at: string;
|
|
7741
|
+
};
|
|
7742
|
+
/** This process, as a release operation's issuer. Real time, whatever clock a caller passes for the rest. */
|
|
7743
|
+
export declare function currentReleaseIssuer(): ReleaseIssuer;
|
|
7744
|
+
/**
|
|
7745
|
+
* Whether an operation's issuer is proven gone (review round 2): no process has its pid, or the process that has it
|
|
7746
|
+
* started after the issuer was recorded (so it is another one). Anything unknown — no issuer recorded, a start time
|
|
7747
|
+
* that can't be read — is not proof, and the operation stays for a person.
|
|
7748
|
+
*/
|
|
7749
|
+
export declare function releaseIssuerGone(op: ReleaseOperation): boolean;
|