toolroll 0.9.65 → 0.9.68
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 +93 -0
- package/README.md +20 -2
- package/dist/acp-client.js +1 -3
- package/dist/agent-board.d.ts +0 -1
- package/dist/agent-board.js +0 -1
- package/dist/agent-fence.d.ts +69 -2
- package/dist/agent-fence.js +294 -11
- package/dist/agentconfig.js +4 -1
- package/dist/batch-checks.js +3 -2
- package/dist/browser/THIRD_PARTY_NOTICES.txt +46 -0
- package/dist/browser/terminal.js +134 -23
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +31 -29
- package/dist/builder.d.ts +4 -0
- package/dist/builder.js +56 -37
- package/dist/canonical-json.d.ts +14 -0
- package/dist/canonical-json.js +36 -0
- package/dist/chat-actions.js +1 -2
- package/dist/chat-admission.d.ts +19 -0
- package/dist/chat-admission.js +22 -0
- package/dist/chat-channel.js +1 -1
- package/dist/chat-delivery.js +0 -1
- package/dist/chat-follow.d.ts +17 -0
- package/dist/chat-follow.js +32 -0
- package/dist/chat-messages.js +0 -1
- package/dist/chat-settings-page.d.ts +23 -0
- package/dist/chat-settings-page.js +41 -0
- package/dist/claim.js +3 -6
- package/dist/claude-print.d.ts +12 -0
- package/dist/claude-print.js +34 -0
- package/dist/cli-http.d.ts +0 -7
- package/dist/cli-http.js +0 -21
- package/dist/cli.d.ts +3 -10
- package/dist/cli.js +15 -24
- package/dist/coding-provider.js +2 -1
- package/dist/coding-workspace.js +1 -1
- package/dist/{team-cli.d.ts → connect-cli.d.ts} +5 -9
- package/dist/connect-cli.js +331 -0
- package/dist/containment.d.ts +0 -2
- package/dist/containment.js +2 -6
- package/dist/contracts/chat-actions.d.ts +0 -1
- package/dist/contracts/chat-content.d.ts +0 -4
- package/dist/contracts/chat-content.js +0 -2
- package/dist/contracts/chat-tables.d.ts +0 -1
- package/dist/contracts/cli.d.ts +0 -62
- package/dist/contracts/cli.js +0 -4
- package/dist/contracts/coding-workspace.js +1 -1
- package/dist/contracts/console-api.d.ts +1 -0
- package/dist/contracts/console-api.js +1 -0
- package/dist/contracts/contract.js +1 -1
- package/dist/contracts/flow-card.d.ts +0 -1
- package/dist/contracts/flow-propose.d.ts +0 -1
- package/dist/contracts/flow-send.js +1 -1
- package/dist/contracts/gateway-tools.d.ts +0 -1
- package/dist/contracts/integration-metadata.js +1 -1
- package/dist/contracts/lead-tools.d.ts +0 -1
- package/dist/contracts/memory-pass.d.ts +0 -1
- package/dist/contracts/memory-pass.js +1 -1
- package/dist/contracts/plan.js +1 -1
- package/dist/contracts/project-knowledge.js +1 -1
- package/dist/contracts/project-skills.d.ts +0 -1
- package/dist/contracts/proof.js +1 -1
- package/dist/contracts/recipes.js +1 -1
- package/dist/contracts/scope.js +1 -1
- package/dist/contracts/scout-report.js +1 -1
- package/dist/contracts/teams-callback.d.ts +0 -1
- package/dist/converse.d.ts +0 -6
- package/dist/converse.js +0 -19
- package/dist/daemon.js +3 -2
- package/dist/decision.d.ts +1 -3
- package/dist/deprecations.d.ts +12 -4
- package/dist/deprecations.js +27 -4
- package/dist/desktop-update-recovery.js +1 -1
- package/dist/desktop-update.js +3 -2
- package/dist/discord-chat.js +4 -15
- package/dist/discord-settings.d.ts +2 -6
- package/dist/discord-settings.js +10 -38
- package/dist/discord.js +12 -23
- package/dist/evidence.d.ts +0 -1
- package/dist/evidence.js +0 -3
- package/dist/exec.d.ts +0 -9
- package/dist/exec.js +3 -81
- package/dist/flow-actions.js +0 -3
- package/dist/flow-draft.d.ts +1 -3
- package/dist/flow-draft.js +15 -28
- package/dist/flow-scripts.d.ts +1 -8
- package/dist/flow-scripts.js +0 -13
- package/dist/flow-send.js +1 -1
- package/dist/flow-share.d.ts +0 -2
- package/dist/flow-share.js +1 -6
- package/dist/flow-steps.js +1 -1
- package/dist/flow-triggers.d.ts +0 -1
- package/dist/flow-triggers.js +1 -2
- package/dist/flow-unattended.js +1 -12
- package/dist/flows.js +1 -1
- package/dist/health-cli.d.ts +2 -2
- package/dist/health-cli.js +1 -1
- package/dist/invoke.d.ts +18 -3
- package/dist/invoke.js +142 -17
- package/dist/is-record.d.ts +2 -0
- package/dist/is-record.js +2 -0
- package/dist/lead-doors.d.ts +1 -5
- package/dist/lead-doors.js +0 -4
- package/dist/lead-tools.js +3 -6
- package/dist/live-detail.d.ts +0 -1
- package/dist/live-detail.js +0 -6
- package/dist/live-terminal.d.ts +24 -13
- package/dist/live-terminal.js +81 -43
- package/dist/live.d.ts +0 -1
- package/dist/live.js +1 -2
- package/dist/mcp-core.js +0 -2
- package/dist/memory-pass.js +1 -1
- package/dist/model-catalog.js +1 -1
- package/dist/modes.js +1 -12
- package/dist/operate.d.ts +2 -0
- package/dist/operate.js +436 -745
- package/dist/password-bearer.d.ts +0 -2
- package/dist/password-bearer.js +0 -4
- package/dist/peek-cli.js +2 -1
- package/dist/peek.d.ts +2 -26
- package/dist/peek.js +2 -168
- package/dist/phase-routing.d.ts +0 -4
- package/dist/phase-routing.js +2 -21
- package/dist/planner-source.d.ts +2 -1
- package/dist/planner-source.js +2 -12
- package/dist/planner.js +2 -14
- package/dist/process-tree.d.ts +0 -2
- package/dist/process-tree.js +0 -10
- package/dist/project-delete-ui.d.ts +6 -0
- package/dist/project-delete-ui.js +20 -1
- package/dist/project-delete.d.ts +0 -2
- package/dist/project-delete.js +1 -3
- package/dist/project-learning.d.ts +0 -14
- package/dist/project-skills.d.ts +0 -1
- package/dist/project-skills.js +0 -14
- package/dist/project-tools.js +2 -10
- package/dist/provider.d.ts +0 -17
- package/dist/provider.js +0 -26
- package/dist/pulls.d.ts +0 -2
- package/dist/pulls.js +0 -9
- package/dist/release-adapters.d.ts +9 -0
- package/dist/release-adapters.js +81 -4
- package/dist/release.d.ts +7 -1
- package/dist/release.js +20 -7
- package/dist/remote-exec.d.ts +3 -2
- package/dist/remote-exec.js +3 -2
- package/dist/repos.d.ts +0 -5
- package/dist/repos.js +2 -10
- package/dist/repository-context.d.ts +0 -2
- package/dist/repository-context.js +0 -4
- package/dist/restart-certification.d.ts +0 -2
- package/dist/restart-certification.js +1 -5
- package/dist/result-follow-ups.d.ts +1 -4
- package/dist/result-follow-ups.js +4 -8
- package/dist/result-review.d.ts +0 -2
- package/dist/result-review.js +0 -2
- package/dist/retention.d.ts +0 -1
- package/dist/retention.js +0 -1
- package/dist/review-context.d.ts +0 -1
- package/dist/review-context.js +1 -12
- package/dist/reviewer.d.ts +0 -16
- package/dist/reviewer.js +0 -18
- package/dist/run-closeout.js +2 -1
- package/dist/scope.d.ts +13 -0
- package/dist/scope.js +11 -18
- package/dist/scout-browser.js +2 -1
- package/dist/serve.js +3 -2
- package/dist/server/chrome.d.ts +10 -1
- package/dist/server/chrome.js +45 -4
- package/dist/server/console.css +60 -137
- package/dist/server/flows.js +2 -2
- package/dist/server/http.d.ts +2 -0
- package/dist/server/http.js +5 -0
- package/dist/server/pages.js +2 -2
- package/dist/server/people-tokens.js +3 -4
- package/dist/server/remote.js +1 -6
- package/dist/server/render-chat.d.ts +9 -2
- package/dist/server/render-chat.js +53 -7
- package/dist/server/render-pages.d.ts +28 -3
- package/dist/server/render-pages.js +78 -9
- package/dist/server/render-results.d.ts +0 -6
- package/dist/server/render-results.js +3 -9
- package/dist/server/render-tasks.js +6 -6
- package/dist/server/route-table.d.ts +0 -4
- package/dist/server/route-table.js +1 -6
- package/dist/server/settings.js +43 -22
- package/dist/server/task-views.js +1 -1
- package/dist/server/tasks.js +10 -7
- package/dist/setup-guide.d.ts +2 -2
- package/dist/skills.d.ts +0 -6
- package/dist/skills.js +0 -8
- package/dist/slack-chat.d.ts +1 -7
- package/dist/slack-chat.js +5 -18
- package/dist/slack-settings.d.ts +2 -6
- package/dist/slack-settings.js +10 -38
- package/dist/slack.js +12 -23
- package/dist/sleep.d.ts +2 -0
- package/dist/sleep.js +2 -0
- package/dist/store.d.ts +11 -74
- package/dist/store.js +36 -179
- package/dist/structured-output.d.ts +0 -1
- package/dist/structured-output.js +0 -1
- package/dist/subagent-work.d.ts +0 -2
- package/dist/subagent-work.js +0 -2
- package/dist/subagents.d.ts +1 -3
- package/dist/subagents.js +20 -33
- package/dist/subscription-chat.d.ts +1 -3
- package/dist/subscription-chat.js +2 -3
- package/dist/task-sizing.d.ts +1 -4
- package/dist/task-sizing.js +3 -10
- package/dist/teams-chat.js +4 -11
- package/dist/teams.js +12 -19
- package/dist/teardown-git.d.ts +22 -0
- package/dist/teardown-git.js +136 -2
- package/dist/telegram-lead.js +2 -2
- package/dist/telegram.js +1 -1
- package/dist/token-notices.d.ts +0 -11
- package/dist/token-notices.js +1 -5
- package/dist/tool-broker.d.ts +12 -0
- package/dist/tool-broker.js +66 -2
- package/dist/tool-secret-store.d.ts +0 -3
- package/dist/tool-secret-store.js +2 -11
- package/dist/toolroll-update.d.ts +0 -2
- package/dist/toolroll-update.js +2 -2
- package/dist/unfenced-test-support.d.ts +2 -0
- package/dist/unfenced-test-support.js +11 -0
- package/dist/verification-evidence.d.ts +0 -1
- package/dist/verification-evidence.js +0 -1
- package/dist/webhooks.d.ts +0 -1
- package/dist/webhooks.js +0 -1
- package/dist/workspace-ui.d.ts +0 -8
- package/dist/workspace-ui.js +1 -6
- package/dist/writes-mode.d.ts +9 -0
- package/dist/writes-mode.js +8 -0
- package/package.json +5 -1
- package/dist/contracts/native-census.d.ts +0 -42
- package/dist/contracts/native-census.js +0 -36
- package/dist/process-recovery-anchor.d.ts +0 -75
- package/dist/process-recovery-anchor.js +0 -188
- package/dist/process-recovery-coalition.d.ts +0 -25
- package/dist/process-recovery-coalition.js +0 -105
- package/dist/process-recovery-eligibility.d.ts +0 -179
- package/dist/process-recovery-eligibility.js +0 -174
- package/dist/process-recovery-native.d.ts +0 -161
- package/dist/process-recovery-native.js +0 -595
- package/dist/process-recovery-provenance.d.ts +0 -163
- package/dist/process-recovery-provenance.js +0 -292
- package/dist/process-recovery-services.d.ts +0 -56
- package/dist/process-recovery-services.js +0 -191
- package/dist/process-recovery-settlement.d.ts +0 -32
- package/dist/process-recovery-settlement.js +0 -133
- package/dist/process-recovery.d.ts +0 -41
- package/dist/process-recovery.js +0 -91
- package/dist/session-brief.d.ts +0 -8
- package/dist/session-brief.js +0 -24
- package/dist/session-cli.d.ts +0 -42
- package/dist/session-cli.js +0 -271
- package/dist/session-contract.d.ts +0 -183
- package/dist/session-contract.js +0 -122
- package/dist/session-remote.d.ts +0 -19
- package/dist/session-remote.js +0 -86
- package/dist/session-service.d.ts +0 -22
- package/dist/session-service.js +0 -157
- package/dist/team-cli.js +0 -692
package/dist/run-closeout.js
CHANGED
|
@@ -18,6 +18,7 @@ import { existsSync, readdirSync, readlinkSync, realpathSync } from "node:fs";
|
|
|
18
18
|
import { hostname } from "node:os";
|
|
19
19
|
import { basename, sep } from "node:path";
|
|
20
20
|
import { ownedProcessCount, runOwnerTag } from "./exec.js";
|
|
21
|
+
import { sleep as defaultSleep } from "./sleep.js";
|
|
21
22
|
/** How long a process has after SIGTERM before SIGKILL. */
|
|
22
23
|
export const STOP_GRACE_MS = 10_000;
|
|
23
24
|
/** `ps` reports age in whole seconds: a process born this close after the run saw its pid is still that process. */
|
|
@@ -86,7 +87,7 @@ export async function stopProcesses(targets, options = {}) {
|
|
|
86
87
|
const graceMs = options.graceMs ?? STOP_GRACE_MS;
|
|
87
88
|
const census = options.census ?? (() => processCensus());
|
|
88
89
|
const signal = options.signal ?? ((pid, name) => process.kill(pid, name));
|
|
89
|
-
const sleep = options.sleep ??
|
|
90
|
+
const sleep = options.sleep ?? defaultSleep;
|
|
90
91
|
const send = (rows, name) => {
|
|
91
92
|
for (const row of rows) {
|
|
92
93
|
try {
|
package/dist/scope.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
3
3
|
import { isAcpProfile, type AcpProviderId } from "./acp-agents.js";
|
|
4
4
|
export { isAcpProfile };
|
|
5
5
|
import { type NetworkProfile } from "./egress.js";
|
|
6
|
+
import { type WritesMode } from "./writes-mode.js";
|
|
6
7
|
import { type EvidenceKind } from "./contracts/acceptance-terms.js";
|
|
7
8
|
import { type AcceptanceCriterion, type AcceptanceProblem, type ScopeTerms } from "./contracts/scope.js";
|
|
8
9
|
import type { Store, Mutation } from "./store.js";
|
|
@@ -74,6 +75,9 @@ export type ClaudeProfile = {
|
|
|
74
75
|
/** What the build may reach (egress.ts), resolved when the scope was written; absent on approvals sealed before
|
|
75
76
|
* network policies, which run narrowed (egress.ts legacyNetwork). */
|
|
76
77
|
network?: NetworkProfile;
|
|
78
|
+
/** Where the build may write (writes-mode.ts), resolved when the scope was written; absent on approvals sealed before
|
|
79
|
+
* write allowlists, which keep writing anywhere their fence allows. */
|
|
80
|
+
writes?: WritesMode;
|
|
77
81
|
};
|
|
78
82
|
export type CodexShapedProfile = {
|
|
79
83
|
provider: "codex" | "openrouter";
|
|
@@ -91,6 +95,9 @@ export type CodexShapedProfile = {
|
|
|
91
95
|
repairTimeoutSeconds: number;
|
|
92
96
|
repairModel: string;
|
|
93
97
|
network?: NetworkProfile;
|
|
98
|
+
/** Where the build may write (writes-mode.ts), resolved when the scope was written; absent on approvals sealed before
|
|
99
|
+
* write allowlists, which keep writing anywhere their fence allows. */
|
|
100
|
+
writes?: WritesMode;
|
|
94
101
|
};
|
|
95
102
|
export type GeminiProfile = {
|
|
96
103
|
provider: "gemini";
|
|
@@ -110,6 +117,9 @@ export type GeminiProfile = {
|
|
|
110
117
|
repairTimeoutSeconds: number;
|
|
111
118
|
repairModel: string;
|
|
112
119
|
network?: NetworkProfile;
|
|
120
|
+
/** Where the build may write (writes-mode.ts), resolved when the scope was written; absent on approvals sealed before
|
|
121
|
+
* write allowlists, which keep writing anywhere their fence allows. */
|
|
122
|
+
writes?: WritesMode;
|
|
113
123
|
};
|
|
114
124
|
/**
|
|
115
125
|
* An agent over the Agent Client Protocol (acp-agents.ts, docs/plans/acp-adapter.md).
|
|
@@ -130,6 +140,9 @@ export type AcpProfile = {
|
|
|
130
140
|
repairIdleTimeoutSeconds: number;
|
|
131
141
|
repairModel: string;
|
|
132
142
|
network?: NetworkProfile;
|
|
143
|
+
/** Where the build may write (writes-mode.ts), resolved when the scope was written; absent on approvals sealed before
|
|
144
|
+
* write allowlists, which keep writing anywhere their fence allows. */
|
|
145
|
+
writes?: WritesMode;
|
|
133
146
|
};
|
|
134
147
|
export type ExecutionProfile = ClaudeProfile | CodexShapedProfile | GeminiProfile | AcpProfile;
|
|
135
148
|
/** Whether a profile's clock is a no-progress window (an ACP profile has both clocks; its overall one is a deadline). */
|
package/dist/scope.js
CHANGED
|
@@ -11,6 +11,7 @@ import { claimActor, currentActor } from "./actor.js";
|
|
|
11
11
|
import { parseLeadToken } from "./api-tokens.js";
|
|
12
12
|
import { isAcpProfile, isAcpProvider } from "./acp-agents.js";
|
|
13
13
|
import { levelOfProfile } from "./policy.js";
|
|
14
|
+
import { canonicalJson } from "./canonical-json.js";
|
|
14
15
|
export { isAcpProfile };
|
|
15
16
|
/**
|
|
16
17
|
* What a task is allowed to become, agreed before anything builds it.
|
|
@@ -39,6 +40,7 @@ export { isAcpProfile };
|
|
|
39
40
|
*/
|
|
40
41
|
import { createHash, randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
|
|
41
42
|
import { networkFromValue, networkWords } from "./egress.js";
|
|
43
|
+
import { isWritesMode, writesWords } from "./writes-mode.js";
|
|
42
44
|
import { z } from "zod";
|
|
43
45
|
import {} from "./contracts/acceptance-terms.js";
|
|
44
46
|
import { parseContract } from "./contracts/contract.js";
|
|
@@ -132,19 +134,6 @@ export function watchdogsOf(profile, timeoutMs, repair = false) {
|
|
|
132
134
|
return profile.timeoutKind === "idle" ? { idleTimeoutMs: timeoutMs } : { timeoutMs };
|
|
133
135
|
}
|
|
134
136
|
export const PROFILE_DIGEST_VERSION = 2;
|
|
135
|
-
/** Deterministic JSON: object keys sorted recursively, arrays in order. */
|
|
136
|
-
function canonicalJson(value) {
|
|
137
|
-
if (Array.isArray(value))
|
|
138
|
-
return `[${value.map(canonicalJson).join(",")}]`;
|
|
139
|
-
if (value !== null && typeof value === "object") {
|
|
140
|
-
const entries = Object.entries(value)
|
|
141
|
-
.filter(([, v]) => v !== undefined)
|
|
142
|
-
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
143
|
-
.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`);
|
|
144
|
-
return `{${entries.join(",")}}`;
|
|
145
|
-
}
|
|
146
|
-
return JSON.stringify(value);
|
|
147
|
-
}
|
|
148
137
|
/** The stored snapshot bytes: version embedded IN the snapshot (finding 17). */
|
|
149
138
|
export function canonicalProfileJson(profile) {
|
|
150
139
|
return canonicalJson({ digestVersion: PROFILE_DIGEST_VERSION, profile });
|
|
@@ -362,9 +351,12 @@ export function profileFromJson(json) {
|
|
|
362
351
|
const network = p["network"] === undefined ? undefined : networkFromValue(p["network"]);
|
|
363
352
|
if (network === null)
|
|
364
353
|
return null;
|
|
365
|
-
const
|
|
354
|
+
const writes = p["writes"];
|
|
355
|
+
if (writes !== undefined && !isWritesMode(writes))
|
|
356
|
+
return null;
|
|
357
|
+
const withNetwork = { ...(network === undefined ? {} : { network }), ...(writes === undefined ? {} : { writes }) };
|
|
366
358
|
if (p["provider"] === "claude") {
|
|
367
|
-
if (exactKeys(p, [...PROVIDER_KEYS, "permissionArgv"], ["timeoutKind", "network"]) &&
|
|
359
|
+
if (exactKeys(p, [...PROVIDER_KEYS, "permissionArgv"], ["timeoutKind", "network", "writes"]) &&
|
|
368
360
|
str(p["model"]) &&
|
|
369
361
|
(p["permissionArgv"] === "auto" || p["permissionArgv"] === "acceptEdits" || p["permissionArgv"] === "bypassPermissions") &&
|
|
370
362
|
num(p["maxTurns"]) && num(p["repairMaxTurns"]) &&
|
|
@@ -386,7 +378,7 @@ export function profileFromJson(json) {
|
|
|
386
378
|
return null;
|
|
387
379
|
}
|
|
388
380
|
if (p["provider"] === "codex" || p["provider"] === "openrouter") {
|
|
389
|
-
if (exactKeys(p, [...PROVIDER_KEYS, "sandboxMode"], ["timeoutKind", "network"]) &&
|
|
381
|
+
if (exactKeys(p, [...PROVIDER_KEYS, "sandboxMode"], ["timeoutKind", "network", "writes"]) &&
|
|
390
382
|
str(p["model"]) &&
|
|
391
383
|
(p["sandboxMode"] === "workspace-write" || p["sandboxMode"] === "danger-full-access") &&
|
|
392
384
|
p["maxTurns"] === "unsupported" && p["repairMaxTurns"] === "unsupported" &&
|
|
@@ -408,7 +400,7 @@ export function profileFromJson(json) {
|
|
|
408
400
|
return null;
|
|
409
401
|
}
|
|
410
402
|
if (p["provider"] === "gemini") {
|
|
411
|
-
if (exactKeys(p, [...PROVIDER_KEYS, "approvalArgv"], ["timeoutKind", "network"]) &&
|
|
403
|
+
if (exactKeys(p, [...PROVIDER_KEYS, "approvalArgv"], ["timeoutKind", "network", "writes"]) &&
|
|
412
404
|
str(p["model"]) &&
|
|
413
405
|
(p["approvalArgv"] === "auto_edit" || p["approvalArgv"] === "yolo") &&
|
|
414
406
|
p["maxTurns"] === "unsupported" && p["repairMaxTurns"] === "unsupported" &&
|
|
@@ -430,7 +422,7 @@ export function profileFromJson(json) {
|
|
|
430
422
|
return null;
|
|
431
423
|
}
|
|
432
424
|
if (typeof p["provider"] === "string" && isAcpProvider(p["provider"])) {
|
|
433
|
-
if (exactKeys(p, [...PROVIDER_KEYS, "permission", "idleTimeoutSeconds", "repairIdleTimeoutSeconds"], ["network"]) &&
|
|
425
|
+
if (exactKeys(p, [...PROVIDER_KEYS, "permission", "idleTimeoutSeconds", "repairIdleTimeoutSeconds"], ["network", "writes"]) &&
|
|
434
426
|
str(p["model"]) &&
|
|
435
427
|
p["permission"] === "full" &&
|
|
436
428
|
p["maxTurns"] === "unsupported" && p["repairMaxTurns"] === "unsupported" &&
|
|
@@ -1278,6 +1270,7 @@ export function describeScope(scope, readiness = NO_READINESS) {
|
|
|
1278
1270
|
...scopeRouteWords(scope, readiness),
|
|
1279
1271
|
// What the build may reach (egress.ts), part of what the yes agrees to.
|
|
1280
1272
|
...(scope.profile === null || scope.profile === undefined ? [] : [` network ${networkWords(scope.profile.network ?? null).replace(/^Network: /, "")}`]),
|
|
1273
|
+
...(scope.profile === null || scope.profile === undefined ? [] : [` writes ${writesWords(scope.profile.writes)}`]),
|
|
1281
1274
|
` reference ${scope.digest}`,
|
|
1282
1275
|
` approved ${describeApproval(approval)}`,
|
|
1283
1276
|
];
|
package/dist/scout-browser.js
CHANGED
|
@@ -16,6 +16,7 @@ import { request as httpRequest } from "node:http";
|
|
|
16
16
|
import { connect, createServer } from "node:net";
|
|
17
17
|
import { readdirSync, rmSync } from "node:fs";
|
|
18
18
|
import { join } from "node:path";
|
|
19
|
+
import { sleep } from "./sleep.js";
|
|
19
20
|
/** The public page the check opens through the scout's proxy. */
|
|
20
21
|
export const PREFLIGHT_PAGE = "https://example.com/";
|
|
21
22
|
const PREFLIGHT_TIMEOUT_MS = 60_000;
|
|
@@ -90,7 +91,7 @@ async function serveBrowser(launch, options, deadline, late) {
|
|
|
90
91
|
};
|
|
91
92
|
// First runs download the pinned tool; it listens once it is ready.
|
|
92
93
|
while (stopped === null && Date.now() < deadline && !(await answers(port)))
|
|
93
|
-
await
|
|
94
|
+
await sleep(250);
|
|
94
95
|
if (stopped !== null || Date.now() >= deadline) {
|
|
95
96
|
const reason = stopped ?? late;
|
|
96
97
|
await close();
|
package/dist/serve.js
CHANGED
|
@@ -151,7 +151,7 @@ import { loadConsoleUrl } from "./webhooks.js";
|
|
|
151
151
|
import { reviewFactsOf } from "./workspace-ui.js";
|
|
152
152
|
import { WorktreePool } from "./worktree.js";
|
|
153
153
|
export function createDecisionServer(options) {
|
|
154
|
-
const {
|
|
154
|
+
const { projectFamilyPeek, familiesInView, familyTasksInView, revisionDestination, runIsLive, runIsTaskResult, revisionViewOf, taskViewData, routeViewOf, taskChatFocus, pullRequestTargetOf, failureOf, explainAttempt, taskScreen, armTaskResume, planViewOf, planContractViewOf, revisionDocOf, revisionLedgerOf, resultDetailOf } = createTaskViews({
|
|
155
155
|
get store() { return store; },
|
|
156
156
|
get projectCounts() { return projectCounts; },
|
|
157
157
|
get admissionList() { return admissionList; },
|
|
@@ -170,7 +170,7 @@ export function createDecisionServer(options) {
|
|
|
170
170
|
get dockedConversation() { return dockedConversation; },
|
|
171
171
|
get liveRefreshSeconds() { return liveRefreshSeconds; },
|
|
172
172
|
});
|
|
173
|
-
const { authenticateApprover, authenticateCredential, authorizeMutation, projectOf,
|
|
173
|
+
const { authenticateApprover, authenticateCredential, authorizeMutation, projectOf, projectRequestAllowed, identify, lookupSession, restricted, visible, admissionList, codingActorAllowed, codingProjectAllowed, workAccess, familyOf, taskRepoOf, runVisible } = createSharedGuards({
|
|
174
174
|
get store() { return store; },
|
|
175
175
|
get liveCeiling() { return liveCeiling; },
|
|
176
176
|
get codingProjects() { return codingProjects; },
|
|
@@ -447,6 +447,7 @@ export function createDecisionServer(options) {
|
|
|
447
447
|
builds: projectBuildsOf(repo, who),
|
|
448
448
|
access: projectAccessOf(repo),
|
|
449
449
|
network: { setting: store.projectNetwork(repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
|
|
450
|
+
writes: { setting: store.projectWrites(repo), canChange: who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo) },
|
|
450
451
|
liveView: (() => {
|
|
451
452
|
const commands = liveCommandsShown(store, repo);
|
|
452
453
|
const canChange = who.via === "cookie" && who.role === "approver" && !store.isDemo() && store.accountCanAccess(who.name, repo);
|
package/dist/server/chrome.d.ts
CHANGED
|
@@ -128,7 +128,9 @@ export type Chrome = {
|
|
|
128
128
|
* at the sink like every page, fetched same-origin — and the nonce'd CSP
|
|
129
129
|
* refuses to execute anything the region could smuggle. Nothing reads on a timer.
|
|
130
130
|
*/
|
|
131
|
-
export declare function regionScript(regionId: string, fragmentName: string, path?: string
|
|
131
|
+
export declare function regionScript(regionId: string, fragmentName: string, path?: string, options?: {
|
|
132
|
+
animate?: boolean;
|
|
133
|
+
}): string;
|
|
132
134
|
/**
|
|
133
135
|
* The live transcript's DEDICATED poller (arc 1 §4): a JSON byte-offset
|
|
134
136
|
* protocol, not an HTML fragment — the response is raw sanitized text and
|
|
@@ -297,3 +299,10 @@ export declare function safePrUrl(url: string | null): string | null;
|
|
|
297
299
|
export declare function shortDigest(digest: string): Html;
|
|
298
300
|
/** One display line, bounded — turn text is data, never layout. */
|
|
299
301
|
export declare function oneLineOf(text: string, cap: number): string;
|
|
302
|
+
/**
|
|
303
|
+
* The board's clocks tick in the page: each <time data-tick> counts up from
|
|
304
|
+
* its datetime, measured against the server's own now (the board's data-now)
|
|
305
|
+
* so a skewed device clock cannot run them backwards. The server-rendered
|
|
306
|
+
* minutes are the answer without script.
|
|
307
|
+
*/
|
|
308
|
+
export declare function boardTickScript(regionId?: string): string;
|
package/dist/server/chrome.js
CHANGED
|
@@ -161,7 +161,7 @@ export const WORKSPACE_STYLE = styleAsset(STYLE + BRAND_MARK_CSS + INBOX_TABS_CS
|
|
|
161
161
|
* at the sink like every page, fetched same-origin — and the nonce'd CSP
|
|
162
162
|
* refuses to execute anything the region could smuggle. Nothing reads on a timer.
|
|
163
163
|
*/
|
|
164
|
-
export function regionScript(regionId, fragmentName, path) {
|
|
164
|
+
export function regionScript(regionId, fragmentName, path, options = {}) {
|
|
165
165
|
// Where the fragment lives: the page's own URL by default; an explicit
|
|
166
166
|
// path when a page embeds another entity's region (the task page embeds
|
|
167
167
|
// the live run's peek, slice 1c — no proxy route exists for it).
|
|
@@ -184,7 +184,7 @@ export function regionScript(regionId, fragmentName, path) {
|
|
|
184
184
|
`function keep(){var data={lanes:[],focus:null,pager:-1,fold:{}};` +
|
|
185
185
|
`region.querySelectorAll("details.lane").forEach(function(d){var k=laneKey(d);if(k)data.fold[k]=d.open;});` +
|
|
186
186
|
`var act=document.activeElement;` +
|
|
187
|
-
`if(act&®ion.contains(act)&&act.matches&&act.matches("a.row, a.lane-card"))data.focus=act.getAttribute("href")
|
|
187
|
+
`if(act&®ion.contains(act)&&act.matches&&act.matches("a.row, a.lane-card, a.worker-job")){data.focus=act.getAttribute("href");data.focusKind=act.matches("a.worker-job")?"a.worker-job":"a.row, a.lane-card";}` +
|
|
188
188
|
`var board=region.querySelector(".board");` +
|
|
189
189
|
`if(board&&board.scrollLeft>0){var lanes=board.querySelectorAll(".lane");` +
|
|
190
190
|
`var bc=board.getBoundingClientRect();var mid=bc.left+bc.width/2;var best=-1,bd=1e9;` +
|
|
@@ -208,17 +208,41 @@ export function regionScript(regionId, fragmentName, path) {
|
|
|
208
208
|
`if(board){var lanes=board.querySelectorAll(".lane");var at=Math.min(data.pager,lanes.length-1);` +
|
|
209
209
|
`if(at>=0){var br=board.getBoundingClientRect();var lr=lanes[at].getBoundingClientRect();` +
|
|
210
210
|
`board.scrollLeft=board.scrollLeft+(lr.left+lr.width/2)-(br.left+br.width/2);}}}` +
|
|
211
|
-
`if(data.focus!==null){var links=region.querySelectorAll(
|
|
211
|
+
`if(data.focus!==null){var links=region.querySelectorAll(data.focusKind);` +
|
|
212
212
|
`for(var i=0;i<links.length;i++){if(links[i].getAttribute("href")===data.focus){links[i].focus({preventScroll:true});break;}}}}` +
|
|
213
213
|
`function tell(){if(!stamp||stopped)return;var s=Math.round((Date.now()-last)/1000);` +
|
|
214
214
|
`stamp.textContent=failed?"stale — retrying ("+s+"s old)":"updated "+s+"s ago";}` +
|
|
215
215
|
`setInterval(tell,1000);` +
|
|
216
|
+
// The animated swap (the live board): a card that changed lane slides there and a new one drops in, through one
|
|
217
|
+
// same-document view transition keyed by each card's data-vt; a worker whose builds changed flashes once
|
|
218
|
+
// (data-flash). Never under reduced motion, in a hidden tab, or where the browser lacks view transitions — there
|
|
219
|
+
// the swap is the plain instant one. Names are set only for the swap and cleared after it.
|
|
220
|
+
`var animate=${options.animate === true ? "true" : "false"};` +
|
|
221
|
+
// A name spells the whole key in hex — two tasks can never share one, so a card's identity never jumps to another.
|
|
222
|
+
`function vtName(v){var n="so-c";for(var i=0;i<v.length;i++){n+=("000"+v.charCodeAt(i).toString(16)).slice(-4);}return n;}` +
|
|
223
|
+
`function nameAll(){var seen={};region.querySelectorAll("[data-vt]").forEach(function(e){var n=vtName(e.getAttribute("data-vt"));if(seen[n])return;seen[n]=1;e.style.setProperty("view-transition-name",n);});}` +
|
|
224
|
+
`function flashes(){var m={};region.querySelectorAll("[data-flash]").forEach(function(e){m[e.getAttribute("data-flash")]=e.getAttribute("data-flash-value");});return m;}` +
|
|
225
|
+
`function apply(t){var before=animate?flashes():{};var kept=keep();region.innerHTML=t;restore(kept);` +
|
|
226
|
+
`if(animate)region.querySelectorAll("[data-flash]").forEach(function(e){var k=e.getAttribute("data-flash"),v=e.getAttribute("data-flash-value");if(k in before&&before[k]!==v&&v!=="")e.classList.add("flash");});}` +
|
|
227
|
+
// The swap resolves when its transition has finished, and the next fetch waits for it (refresh holds busy), so
|
|
228
|
+
// one transition runs at a time; each cleans up only its own (the generation), never a later one's.
|
|
229
|
+
`var generation=0;` +
|
|
230
|
+
`function swap(t){var calm=!window.matchMedia||matchMedia("(prefers-reduced-motion: reduce)").matches;` +
|
|
231
|
+
`if(!animate||calm||document.hidden||typeof document.startViewTransition!=="function"){apply(t);return Promise.resolve();}` +
|
|
232
|
+
// Bounded: a transition that never settles (or never runs its update) is let go after 1.5 s — the fragment is
|
|
233
|
+
// applied exactly once either way, so the board can never stop refreshing behind an animation.
|
|
234
|
+
`var root=document.documentElement;var mine=++generation;var applied=false;var settled=false;nameAll();root.classList.add("so-swap");` +
|
|
235
|
+
`var once=function(){if(applied)return false;applied=true;apply(t);return true;};` +
|
|
236
|
+
`var end=function(){if(settled)return;settled=true;once();if(mine!==generation)return;root.classList.remove("so-swap");region.querySelectorAll("[data-vt]").forEach(function(e){e.style.removeProperty("view-transition-name");});};` +
|
|
237
|
+
`var vt;try{vt=document.startViewTransition(function(){if(once())nameAll();});}catch(e){end();return Promise.resolve();}` +
|
|
238
|
+
`return new Promise(function(done){var timer=setTimeout(function(){end();done();},1500);` +
|
|
239
|
+
`var fin=function(){clearTimeout(timer);end();done();};try{Promise.resolve(vt&&vt.finished).then(fin,fin);}catch(e){fin();}});}` +
|
|
216
240
|
`function refresh(){if(stopped)return;if(busy){again=true;return;}busy=true;again=false;` +
|
|
217
241
|
`var q=location.search?location.search+"&fragment="+${JSON.stringify(fragmentName)}:"?fragment="+${JSON.stringify(fragmentName)};` +
|
|
218
242
|
`fetch(${target},{redirect:"manual",cache:"no-store"})` +
|
|
219
243
|
`.then(function(r){if(r.type==="opaqueredirect"||r.status===401||r.status===403){location.href="/login";return null;}` +
|
|
220
244
|
`return r.ok?r.text():null;})` +
|
|
221
|
-
`.then(function(t){if(t){
|
|
245
|
+
`.then(function(t){if(t){return swap(t).then(function(){last=Date.now();failed=false;});}failed=true;})` +
|
|
222
246
|
`.catch(function(){failed=true;})` +
|
|
223
247
|
// A fragment that marks itself final stops: a finished or abandoned build is not fetched again.
|
|
224
248
|
`.then(function(){busy=false;tell();if(region.querySelector("[data-region-stop]")){stopped=true;if(stamp)stamp.textContent="";return;}if(again)refresh();});}` +
|
|
@@ -760,3 +784,20 @@ export function oneLineOf(text, cap) {
|
|
|
760
784
|
const flat = text.replace(/\s+/g, " ").trim();
|
|
761
785
|
return flat.length <= cap ? flat : `${flat.slice(0, cap - 1)}…`;
|
|
762
786
|
}
|
|
787
|
+
/**
|
|
788
|
+
* The board's clocks tick in the page: each <time data-tick> counts up from
|
|
789
|
+
* its datetime, measured against the server's own now (the board's data-now)
|
|
790
|
+
* so a skewed device clock cannot run them backwards. The server-rendered
|
|
791
|
+
* minutes are the answer without script.
|
|
792
|
+
*/
|
|
793
|
+
export function boardTickScript(regionId = "board-region") {
|
|
794
|
+
return (`(function(){var seen=null,offset=0;var region=document.getElementById(${JSON.stringify(regionId)});` +
|
|
795
|
+
`function fmt(s){if(s<0)s=0;var h=Math.floor(s/3600),m=Math.floor(s%3600/60),x=s%60;return h>0?h+"h "+(m<10?"0":"")+m+"m":m+":"+(x<10?"0":"")+x;}` +
|
|
796
|
+
`function run(){var scope=region||document;var anchor=scope.querySelector("[data-now]");var v=anchor?anchor.getAttribute("data-now"):null;` +
|
|
797
|
+
`if(v!==null&&v!==seen){seen=v;var n=Number(v);offset=isFinite(n)?n-Date.now():0;}` +
|
|
798
|
+
`var now=Date.now()+offset;scope.querySelectorAll("time[data-tick]").forEach(function(t){var at=Date.parse(t.getAttribute("datetime")||"");if(isNaN(at))return;var text=fmt(Math.floor((now-at)/1000));if(t.textContent!==text)t.textContent=text;});}` +
|
|
799
|
+
// A swapped region brings back the server's minutes, so a swap (the region's children replaced — never a clock's
|
|
800
|
+
// own text) ticks at once and no clock flickers back to them. Hidden tabs do not tick.
|
|
801
|
+
`run();setInterval(function(){if(!document.hidden)run();},1000);document.addEventListener("visibilitychange",function(){if(!document.hidden)run();});` +
|
|
802
|
+
`if(region&&typeof MutationObserver==="function")new MutationObserver(run).observe(region,{childList:true});})();`);
|
|
803
|
+
}
|