toolroll 0.9.67 → 0.9.69
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 +70 -0
- 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 +58 -0
- package/dist/agent-fence.js +214 -19
- package/dist/agentconfig.d.ts +1 -1
- package/dist/agentconfig.js +6 -2
- package/dist/batch-checks.js +14 -26
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +31 -29
- package/dist/builder.d.ts +9 -0
- package/dist/builder.js +30 -27
- 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/check-access.d.ts +54 -0
- package/dist/check-access.js +80 -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 +39 -5
- package/dist/invoke.js +181 -24
- 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.js +2 -1
- 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 +4 -0
- package/dist/operate.js +456 -750
- 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 +16 -0
- package/dist/project-delete-ui.js +60 -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 +3 -0
- package/dist/release-adapters.js +15 -5
- 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 +11 -21
- 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 +9 -0
- package/dist/scope.js +13 -18
- package/dist/scout-browser.js +2 -1
- package/dist/serve.js +11 -2
- package/dist/server/console.css +5 -133
- package/dist/server/flows.js +2 -2
- package/dist/server/http.d.ts +4 -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-results.d.ts +3 -6
- package/dist/server/render-results.js +4 -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 +60 -23
- package/dist/server/task-views.js +1 -1
- package/dist/server/tasks.js +5 -3
- 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 +29 -75
- package/dist/store.js +89 -180
- 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/surface.js +2 -1
- 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/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-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/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/package.json +1 -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/discord-settings.js
CHANGED
|
@@ -1,41 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { html, postForm } from "./html.js";
|
|
1
|
+
import { html } from "./html.js";
|
|
3
2
|
import { loadDiscordCredentials } from "./discord-api.js";
|
|
4
|
-
import {
|
|
3
|
+
import { chatSettingsHtml } from "./chat-settings-page.js";
|
|
5
4
|
export function discordSettingsHtml(store, dir, options = {}) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const parts = [];
|
|
15
|
-
if (!credentials) {
|
|
16
|
-
parts.push(html `<p>Manage projects and review results in a private Discord conversation.</p>`, html `<details open><summary>Create your Discord app</summary><ol><li><a href="https://discord.com/developers/applications" target="_blank" rel="noopener noreferrer">Create an application</a>, then copy its token from the Bot page.</li><li>Keep the Interactions Endpoint URL empty and privileged intents off.</li><li>Under Installation, enable Guild Install with the bot scope and no server permissions. Use its install link to add it to your server, then open a direct message to the bot.</li></ol></details>`, post("connect", html `<label>Bot token<input style="min-height:44px" type="password" name="bot-token" autocomplete="off" required></label>${password}<p class="meta">The token stays on this installation. Next, pair your own Discord account.</p><button type="submit">Connect Discord</button>`));
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
parts.push(html `<p><strong>${credentials.workspace}</strong> · ${live ? "Connected" : "Waiting for connection"}</p>`);
|
|
20
|
-
if (runtime?.problem)
|
|
21
|
-
parts.push(html `<p role="status">${String(runtime.problem)}</p>`);
|
|
22
|
-
if (!live && !runtime?.problem)
|
|
23
|
-
parts.push(html `<p>Keep the Toolroll worker running to receive Discord messages.</p>`);
|
|
24
|
-
if (options.code) {
|
|
25
|
-
parts.push(html `<h2>Pair your account</h2><p>Send this in a direct message to your Toolroll Discord app. It expires in 10 minutes.</p>`, html `<label>Pairing message<input type="text" readonly value="pair ${options.code}" autocomplete="off" style="width:100%;max-width:100%;font-size:14px;min-height:44px"></label>`, html `<a class="button-link" style="min-height:44px;white-space:nowrap" href="/settings/discord">Check connection</a>`);
|
|
26
|
-
}
|
|
27
|
-
else if (binding && state.live(binding)) {
|
|
28
|
-
const { pending, dropped: failed } = state.partCounts(binding.id);
|
|
29
|
-
parts.push(html `<p>Your Discord account is paired.${others ? ` ${others} teammate${others === 1 ? " is" : "s are"} paired too.` : ""}${pending ? ` ${pending} replies waiting to send.` : ""}${failed ? ` ${failed} replies could not be delivered. Open the saved chat to recover them.` : ""}</p>`, html `<p>Try “What needs my attention?” or “Show the evidence for the latest result.”</p>`, html `<p><a href="/chat">Open saved chat</a></p>`, loadPrimary(process.env, dir) === "discord"
|
|
30
|
-
? html `<p>Task updates are sent here.</p>`
|
|
31
|
-
: post("alerts", html `<button type="submit">Send task updates here</button>`));
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
parts.push(post("pair", html `<h2>Pair your account</h2><p>Your paired Discord account can read your connected projects and confirm proposed changes. Password approvals still open in Toolroll.${others ? ` ${others} teammate${others === 1 ? " is" : "s are"} already paired.` : ""}</p>${password}<button type="submit">Create pairing code</button>`));
|
|
35
|
-
}
|
|
36
|
-
if (binding && state.live(binding) && !options.code)
|
|
37
|
-
parts.push(post("unpair", html `${password}<p class="meta">Unpairing ends every open button in your chat. Teammates are unaffected.</p><button type="submit">Unpair my account</button>`));
|
|
38
|
-
parts.push(html `<details><summary>Connection settings</summary>${post("disconnect", html `${password}<button type="submit">Disconnect Discord</button>`)}</details>`);
|
|
39
|
-
}
|
|
40
|
-
return html `<section style="max-width:42rem;overflow-wrap:anywhere"><p><a href="/settings">Settings</a></p><h1>Discord</h1>${options.problem ? html `<p class="problem" role="alert">${options.problem}</p>` : ""}${parts}<details><summary>Access and setup</summary><p>Private messages and replies use your Toolroll permissions. Shared channels are not supported. Secure review links use this installation’s configured HTTPS console address.</p><p>The worker connects out to Discord. It does not need a public webhook or a Tailscale account.</p></details></section>`;
|
|
5
|
+
return chatSettingsHtml(store, dir, options, {
|
|
6
|
+
provider: "discord",
|
|
7
|
+
label: "Discord",
|
|
8
|
+
credentials: loadDiscordCredentials(dir),
|
|
9
|
+
setup: html `<details open><summary>Create your Discord app</summary><ol><li><a href="https://discord.com/developers/applications" target="_blank" rel="noopener noreferrer">Create an application</a>, then copy its token from the Bot page.</li><li>Keep the Interactions Endpoint URL empty and privileged intents off.</li><li>Under Installation, enable Guild Install with the bot scope and no server permissions. Use its install link to add it to your server, then open a direct message to the bot.</li></ol></details>`,
|
|
10
|
+
connect: password => html `<label>Bot token<input style="min-height:44px" type="password" name="bot-token" autocomplete="off" required></label>${password}<p class="meta">The token stays on this installation. Next, pair your own Discord account.</p><button type="submit">Connect Discord</button>`,
|
|
11
|
+
access: html `<p>Private messages and replies use your Toolroll permissions. Shared channels are not supported. Secure review links use this installation’s configured HTTPS console address.</p><p>The worker connects out to Discord. It does not need a public webhook or a Tailscale account.</p>`,
|
|
12
|
+
});
|
|
41
13
|
}
|
package/dist/discord.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** A single leased Discord Gateway connection, hosted by the ordinary worker. */
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
|
-
import {
|
|
3
|
+
import { abortablePause, workChatQueue } from "./chat-follow.js";
|
|
4
4
|
import { loadDiscordCredentials, discordApi, object, discordId, } from "./discord-api.js";
|
|
5
5
|
import { ChatState, chatHash } from "./chat-delivery-state.js";
|
|
6
6
|
import { receiveDiscord, processDiscordEvent, deliverDiscordPart, planDiscordNotifications, planDiscordRooms, } from "./discord-chat.js";
|
|
@@ -12,14 +12,7 @@ export function discordReadyMatches(raw, identity) {
|
|
|
12
12
|
}
|
|
13
13
|
export async function followDiscord(options) {
|
|
14
14
|
const owner = randomBytes(16).toString("hex"), state = new ChatState(options.store, "discord");
|
|
15
|
-
const pause =
|
|
16
|
-
try {
|
|
17
|
-
await sleep(ms, undefined, { signal: options.signal });
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
/* shutdown */
|
|
21
|
-
}
|
|
22
|
-
};
|
|
15
|
+
const pause = abortablePause(options.signal);
|
|
23
16
|
while (!options.signal.aborted) {
|
|
24
17
|
const credentials = loadDiscordCredentials(options.dir);
|
|
25
18
|
if (!credentials ||
|
|
@@ -129,20 +122,16 @@ export async function followDiscord(options) {
|
|
|
129
122
|
};
|
|
130
123
|
try {
|
|
131
124
|
await client.login(credentials.botToken);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (same() && options.notifications())
|
|
143
|
-
await planDiscordNotifications(chat);
|
|
144
|
-
await pause(1000);
|
|
145
|
-
}
|
|
125
|
+
await workChatQueue({
|
|
126
|
+
same,
|
|
127
|
+
ready: () => connected && !(state.retryAt(credentials.installation) > new Date().toISOString()),
|
|
128
|
+
pause,
|
|
129
|
+
notifications: () => options.notifications(),
|
|
130
|
+
process: () => processDiscordEvent(chat),
|
|
131
|
+
rooms: () => planDiscordRooms(chat),
|
|
132
|
+
deliver: () => deliverDiscordPart(chat),
|
|
133
|
+
notify: () => planDiscordNotifications(chat),
|
|
134
|
+
});
|
|
146
135
|
}
|
|
147
136
|
catch {
|
|
148
137
|
if (alive)
|
package/dist/evidence.d.ts
CHANGED
|
@@ -80,7 +80,6 @@ export declare function evidenceRoot(home: string): string;
|
|
|
80
80
|
* name. The agent learns the name from its brief and nowhere else.
|
|
81
81
|
*/
|
|
82
82
|
export declare function mailboxName(): string;
|
|
83
|
-
export declare function looksLikeMailbox(name: string): boolean;
|
|
84
83
|
/** Every protocol file the sweep must never let an old attempt leave behind.
|
|
85
84
|
* The pre-rename NIGHTORDERS- prefix stays recognized here — a worktree cut
|
|
86
85
|
* down before 2026-08-13 may still hold one, and cleanup has no vintage. */
|
package/dist/evidence.js
CHANGED
|
@@ -128,9 +128,6 @@ export function evidenceRoot(home) {
|
|
|
128
128
|
export function mailboxName() {
|
|
129
129
|
return `${MAILBOX_PREFIX}${randomBytes(8).toString("hex")}${MAILBOX_SUFFIX}`;
|
|
130
130
|
}
|
|
131
|
-
export function looksLikeMailbox(name) {
|
|
132
|
-
return name.startsWith(MAILBOX_PREFIX) && name.endsWith(MAILBOX_SUFFIX);
|
|
133
|
-
}
|
|
134
131
|
/** Every protocol file the sweep must never let an old attempt leave behind.
|
|
135
132
|
* The pre-rename NIGHTORDERS- prefix stays recognized here — a worktree cut
|
|
136
133
|
* down before 2026-08-13 may still hold one, and cleanup has no vintage. */
|
package/dist/exec.d.ts
CHANGED
|
@@ -246,15 +246,6 @@ export declare function run(file: string, args: readonly string[], options?: Run
|
|
|
246
246
|
* worst useful case while remaining a hard, per-event memory boundary.
|
|
247
247
|
*/
|
|
248
248
|
export declare const JSONL_EVENT_HARD_CAP: number;
|
|
249
|
-
/**
|
|
250
|
-
* The accounting an oversized Claude result still carries, read by a bounded scan of its kept prefix and tail: the
|
|
251
|
-
* session's running `total_cost_usd`, its `usage` and `num_turns`, and whether it is a main result at all (an
|
|
252
|
-
* `origin` naming anything but a person makes it a background task's). Anything unreadable or seen twice is absent.
|
|
253
|
-
*/
|
|
254
|
-
export declare function scanOversizedClaudeResult(prefix: Buffer, tail: Buffer | undefined): {
|
|
255
|
-
primary: boolean;
|
|
256
|
-
account: Record<string, unknown>;
|
|
257
|
-
};
|
|
258
249
|
/** Marks a Claude result whose session cost could not be read: the gateway charges the run's dollar cap instead. */
|
|
259
250
|
export declare const CLAUDE_COST_UNKNOWN = "standing_orders_cost_unknown";
|
|
260
251
|
export declare function runStreamJsonl(file: string, args: readonly string[], options?: RunOptions): Promise<ExecResult>;
|
package/dist/exec.js
CHANGED
|
@@ -9,12 +9,12 @@
|
|
|
9
9
|
import { ACP_LINE_CAP, createAcpConversation } from "./acp-client.js";
|
|
10
10
|
import { linuxFenceAvailable, linuxFenced, macosFenceAvailable, macosFenced } from "./agent-fence.js";
|
|
11
11
|
import { execFile, execFileSync, spawn } from "node:child_process";
|
|
12
|
-
import {
|
|
13
|
-
import { join } from "node:path";
|
|
12
|
+
import { realpathSync } from "node:fs";
|
|
14
13
|
import { observeProcessTree, stopProcessTree } from "./process-tree.js";
|
|
15
14
|
import { jsonlDiscriminants } from "./jsonl-discriminants.js";
|
|
16
15
|
import { createContainer, currentContainment } from "./containment.js";
|
|
17
16
|
import { claudeLimitsOf, noteLimits } from "./provider-limits.js";
|
|
17
|
+
import { sleep as defaultSleep } from "./sleep.js";
|
|
18
18
|
/** Shell convention for "could not be executed": the refusal before any target ran. */
|
|
19
19
|
export const CONTAINMENT_REFUSED_CODE = 126;
|
|
20
20
|
/** Live provider children, for the deterministic stop. Registered only when `processGroup` was set. */
|
|
@@ -508,7 +508,7 @@ export function isTransientSpawnFailure(error) {
|
|
|
508
508
|
* A non-transient answer — success, a real exit code, not found, timeout —
|
|
509
509
|
* is returned at once: only the never-started case is retried.
|
|
510
510
|
*/
|
|
511
|
-
export async function retryTransientSpawn(attempt, delays = SPAWN_RETRY_DELAYS_MS, sleep =
|
|
511
|
+
export async function retryTransientSpawn(attempt, delays = SPAWN_RETRY_DELAYS_MS, sleep = defaultSleep) {
|
|
512
512
|
let last = await attempt();
|
|
513
513
|
for (const delay of delays) {
|
|
514
514
|
if (!last.transient)
|
|
@@ -942,81 +942,6 @@ function leadingClaudeSystemSubtype(prefix) {
|
|
|
942
942
|
}
|
|
943
943
|
/** How much of an oversized Claude result's end is kept to read its cost and usage (they follow the words). */
|
|
944
944
|
const CLAUDE_RESULT_TAIL_CAP = 64 * 1024;
|
|
945
|
-
/**
|
|
946
|
-
* Where a key's value starts in a fragment of JSON text, once and only once. `"key":` never occurs inside a JSON
|
|
947
|
-
* string (every quote there is escaped, so `y":` cannot appear), so each match is a real key, though possibly of a
|
|
948
|
-
* nested object. A key seen more than once is ambiguous and reads as absent.
|
|
949
|
-
*/
|
|
950
|
-
function soleKeyValueAt(texts, key) {
|
|
951
|
-
const pattern = new RegExp(`"${key}"\\s*:\\s*`, "g");
|
|
952
|
-
let found = null;
|
|
953
|
-
for (const text of texts) {
|
|
954
|
-
for (const match of text.matchAll(pattern)) {
|
|
955
|
-
if (found !== null)
|
|
956
|
-
return null;
|
|
957
|
-
found = { text, at: match.index + match[0].length };
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
return found;
|
|
961
|
-
}
|
|
962
|
-
/** The JSON object starting at `at`, read to its matching brace (strings and escapes respected), or null. */
|
|
963
|
-
function jsonObjectAt(text, at) {
|
|
964
|
-
if (text[at] !== "{")
|
|
965
|
-
return null;
|
|
966
|
-
let depth = 0, inString = false;
|
|
967
|
-
for (let i = at; i < text.length && i - at < CLAUDE_RESULT_TAIL_CAP; i += 1) {
|
|
968
|
-
const c = text[i];
|
|
969
|
-
if (inString) {
|
|
970
|
-
if (c === "\\")
|
|
971
|
-
i += 1;
|
|
972
|
-
else if (c === '"')
|
|
973
|
-
inString = false;
|
|
974
|
-
}
|
|
975
|
-
else if (c === '"')
|
|
976
|
-
inString = true;
|
|
977
|
-
else if (c === "{")
|
|
978
|
-
depth += 1;
|
|
979
|
-
else if (c === "}" && --depth === 0) {
|
|
980
|
-
try {
|
|
981
|
-
const value = JSON.parse(text.slice(at, i + 1));
|
|
982
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
983
|
-
}
|
|
984
|
-
catch {
|
|
985
|
-
return null;
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
return null;
|
|
990
|
-
}
|
|
991
|
-
/**
|
|
992
|
-
* The accounting an oversized Claude result still carries, read by a bounded scan of its kept prefix and tail: the
|
|
993
|
-
* session's running `total_cost_usd`, its `usage` and `num_turns`, and whether it is a main result at all (an
|
|
994
|
-
* `origin` naming anything but a person makes it a background task's). Anything unreadable or seen twice is absent.
|
|
995
|
-
*/
|
|
996
|
-
export function scanOversizedClaudeResult(prefix, tail) {
|
|
997
|
-
const texts = [prefix.toString("utf8"), ...(tail === undefined ? [] : [tail.toString("utf8")])];
|
|
998
|
-
const origin = soleKeyValueAt(texts, "origin");
|
|
999
|
-
const originObject = origin === null ? null : jsonObjectAt(origin.text, origin.at);
|
|
1000
|
-
const primary = originObject === null || String(originObject["kind"] ?? "") === "human";
|
|
1001
|
-
const account = {};
|
|
1002
|
-
const number = (key) => {
|
|
1003
|
-
const at = soleKeyValueAt(texts, key);
|
|
1004
|
-
const match = at === null ? null : /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/.exec(at.text.slice(at.at, at.at + 64));
|
|
1005
|
-
const value = match === null ? NaN : Number(match[0]);
|
|
1006
|
-
return Number.isFinite(value) && value >= 0 ? value : null;
|
|
1007
|
-
};
|
|
1008
|
-
const cost = number("total_cost_usd");
|
|
1009
|
-
if (cost !== null)
|
|
1010
|
-
account["total_cost_usd"] = cost;
|
|
1011
|
-
const turns = number("num_turns");
|
|
1012
|
-
if (turns !== null)
|
|
1013
|
-
account["num_turns"] = turns;
|
|
1014
|
-
const usageAt = soleKeyValueAt(texts, "usage");
|
|
1015
|
-
const usage = usageAt === null ? null : jsonObjectAt(usageAt.text, usageAt.at);
|
|
1016
|
-
if (usage !== null)
|
|
1017
|
-
account["usage"] = usage;
|
|
1018
|
-
return { primary, account };
|
|
1019
|
-
}
|
|
1020
945
|
/** Marks a Claude result whose session cost could not be read: the gateway charges the run's dollar cap instead. */
|
|
1021
946
|
export const CLAUDE_COST_UNKNOWN = "standing_orders_cost_unknown";
|
|
1022
947
|
function malformedCodexEventIsLoadBearing(prefix) {
|
|
@@ -1036,7 +961,6 @@ function malformedGeminiEventIsLoadBearing(prefix) {
|
|
|
1036
961
|
return type === "init" || type === "result";
|
|
1037
962
|
}
|
|
1038
963
|
export function runStreamJsonl(file, args, options = {}) {
|
|
1039
|
-
const { cwd } = options;
|
|
1040
964
|
const childEnv = resolveChildEnv(options);
|
|
1041
965
|
return new Promise(resolve => {
|
|
1042
966
|
let child;
|
|
@@ -1249,7 +1173,6 @@ export function runStreamJsonl(file, args, options = {}) {
|
|
|
1249
1173
|
* semantics match `runStreamJsonl`.
|
|
1250
1174
|
*/
|
|
1251
1175
|
export function runGeminiStreamJsonl(file, args, options = {}) {
|
|
1252
|
-
const { cwd } = options;
|
|
1253
1176
|
const childEnv = resolveChildEnv(options);
|
|
1254
1177
|
return new Promise(resolve => {
|
|
1255
1178
|
let child;
|
|
@@ -1843,7 +1766,6 @@ export const STREAM_INPUT = Symbol.for("toolroll.streamInput");
|
|
|
1843
1766
|
/** Whether a runner declares it keeps stdin open for a live session; an injected runner opts in by carrying the mark. */
|
|
1844
1767
|
export const streamsInput = (runner) => typeof runner === "function" && runner[STREAM_INPUT] === true;
|
|
1845
1768
|
export function runClaudeStreamJsonl(file, args, options = {}) {
|
|
1846
|
-
const { cwd } = options;
|
|
1847
1769
|
const childEnv = resolveChildEnv(options);
|
|
1848
1770
|
const live = options.liveInput ?? null;
|
|
1849
1771
|
return new Promise(resolve => {
|
package/dist/flow-actions.js
CHANGED
|
@@ -18,9 +18,6 @@
|
|
|
18
18
|
* answer: the card takes its failure path. Trouble reaching a service is
|
|
19
19
|
* tried again, like every step.
|
|
20
20
|
*/
|
|
21
|
-
import { createHash } from "node:crypto";
|
|
22
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
23
|
-
import { join } from "node:path";
|
|
24
21
|
import { redactSecretAssignments } from "./builder.js";
|
|
25
22
|
import { redactSecretLines, scanForSecrets } from "./evidence.js";
|
|
26
23
|
import { fillFlowText } from "./flows.js";
|
package/dist/flow-draft.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type CommandRunner } from "./claude-print.js";
|
|
2
2
|
import { type FlowDefinition, type FlowStage } from "./flows.js";
|
|
3
3
|
export declare const DRAFT_CHARS: 12000;
|
|
4
4
|
export type DraftCard = {
|
|
@@ -37,8 +37,6 @@ export declare function draftPrompt(stage: FlowStage, card: DraftCard, definitio
|
|
|
37
37
|
export declare function wholeDraft(text: string): string;
|
|
38
38
|
/** A draft a person edited, as kept: trimmed, whole (one over DRAFT_CHARS is refused where it is written, never cut), and never holding a key-shaped line. */
|
|
39
39
|
export declare function keptDraft(text: string): string;
|
|
40
|
-
type CommandRunner = (file: string, args: readonly string[], options: Parameters<typeof run>[2]) => Promise<ExecResult>;
|
|
41
40
|
/** The production runner: Claude through the sign-in on this computer, with no tools, no MCP servers and no repository. */
|
|
42
41
|
export declare function claudeDraftRunner(runner?: CommandRunner): DraftRunner;
|
|
43
42
|
export declare const DRAFT_TIMEOUT = 180000;
|
|
44
|
-
export {};
|
package/dist/flow-draft.js
CHANGED
|
@@ -7,13 +7,9 @@
|
|
|
7
7
|
* nothing is sent: a later zone shows it to a person, and a later step posts
|
|
8
8
|
* it ({{stage.<id>}}).
|
|
9
9
|
*/
|
|
10
|
-
import { Buffer } from "node:buffer";
|
|
11
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
12
|
-
import { tmpdir } from "node:os";
|
|
13
|
-
import { join } from "node:path";
|
|
14
|
-
import { strictJsonParse } from "./converse.js";
|
|
15
10
|
import { redactSecretLines, scanForSecrets } from "./evidence.js";
|
|
16
11
|
import { run } from "./exec.js";
|
|
12
|
+
import { CLAUDE_NO_TOOLS_ARGS, CLAUDE_SIGNED_OUT, claudeJsonBody, claudeModelArgs, inScratchDir } from "./claude-print.js";
|
|
17
13
|
import { fillFlowText } from "./flows.js";
|
|
18
14
|
import { ALL_CREDENTIAL_ENV } from "./provider.js";
|
|
19
15
|
import { LIMITS } from "./decision.js";
|
|
@@ -62,30 +58,21 @@ export function keptDraft(text) {
|
|
|
62
58
|
}
|
|
63
59
|
/** The production runner: Claude through the sign-in on this computer, with no tools, no MCP servers and no repository. */
|
|
64
60
|
export function claudeDraftRunner(runner = run) {
|
|
65
|
-
return async (
|
|
66
|
-
const dir = mkdtempSync(join(tmpdir(), "standing-orders-draft-"));
|
|
61
|
+
return request => inScratchDir("standing-orders-draft-", async (dir) => {
|
|
67
62
|
const started = Date.now();
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const parsed = strictJsonParse(Buffer.from(result.stdout, "utf8"), 256 * 1024, 12);
|
|
79
|
-
const body = parsed.ok && typeof parsed.value === "object" && parsed.value !== null && !Array.isArray(parsed.value) ? parsed.value : null;
|
|
80
|
-
if (result.code !== 0 || body === null || body["is_error"] === true || body["subtype"] !== "success" || typeof body["result"] !== "string") {
|
|
81
|
-
return { ok: false, said: /not logged in|login|authenticat/i.test(`${result.stdout}${result.stderr}`) ? "Claude isn't signed in on this computer." : "Claude couldn't write the draft." };
|
|
82
|
-
}
|
|
83
|
-
const cost = body["total_cost_usd"];
|
|
84
|
-
return { ok: true, text: body["result"], ms: Date.now() - started, ...(typeof cost === "number" && Number.isFinite(cost) && cost >= 0 ? { costUsd: cost } : {}) };
|
|
63
|
+
const result = await runner("claude", [
|
|
64
|
+
"-p", "--output-format", "json", ...CLAUDE_NO_TOOLS_ARGS, ...claudeModelArgs(request.model),
|
|
65
|
+
], { cwd: dir, stdin: request.prompt, timeoutMs: request.timeoutMs, maxBuffer: 256 * 1024, omitEnv: ALL_CREDENTIAL_ENV, processGroup: true });
|
|
66
|
+
if (result.notFound)
|
|
67
|
+
return { ok: false, said: "Claude isn't installed on this computer." };
|
|
68
|
+
if (result.timedOut)
|
|
69
|
+
return { ok: false, said: "Claude took too long to write the draft." };
|
|
70
|
+
const body = claudeJsonBody(result.stdout, 256 * 1024);
|
|
71
|
+
if (result.code !== 0 || body === null || body["is_error"] === true || body["subtype"] !== "success" || typeof body["result"] !== "string") {
|
|
72
|
+
return { ok: false, said: CLAUDE_SIGNED_OUT.test(`${result.stdout}${result.stderr}`) ? "Claude isn't signed in on this computer." : "Claude couldn't write the draft." };
|
|
85
73
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
};
|
|
74
|
+
const cost = body["total_cost_usd"];
|
|
75
|
+
return { ok: true, text: body["result"], ms: Date.now() - started, ...(typeof cost === "number" && Number.isFinite(cost) && cost >= 0 ? { costUsd: cost } : {}) };
|
|
76
|
+
});
|
|
90
77
|
}
|
|
91
78
|
export const DRAFT_TIMEOUT = DRAFT_TIMEOUT_MS;
|
package/dist/flow-scripts.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ScriptLanguage } from "./flows.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Store } from "./store.js";
|
|
3
3
|
export type ScriptDraft = {
|
|
4
4
|
name: string;
|
|
5
5
|
about: string;
|
|
@@ -29,10 +29,3 @@ export type ScriptSaved = {
|
|
|
29
29
|
};
|
|
30
30
|
/** Save a script (a new version when it exists). */
|
|
31
31
|
export declare function saveScript(store: Store, repo: string, input: Parameters<typeof validateScript>[0], actor: string, now: Date): ScriptSaved;
|
|
32
|
-
/** The flows and zones in a project that run each script. */
|
|
33
|
-
export declare function scriptUses(store: Store, repo: string): Map<string, {
|
|
34
|
-
flow: number;
|
|
35
|
-
flowName: string;
|
|
36
|
-
zone: string;
|
|
37
|
-
}[]>;
|
|
38
|
-
export declare function scriptWords(script: FlowScriptRow): string;
|
package/dist/flow-scripts.js
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { createHash } from "node:crypto";
|
|
12
12
|
import { scanForSecrets } from "./evidence.js";
|
|
13
|
-
import { flowDefinitionOf } from "./flow-engine.js";
|
|
14
13
|
import { SCRIPT_LANGUAGES, SCRIPT_NAME } from "./flows.js";
|
|
15
14
|
/** A script as it would be saved, checked in plain words. Throws. */
|
|
16
15
|
export function validateScript(input) {
|
|
@@ -59,15 +58,3 @@ export function saveScript(store, repo, input, actor, now) {
|
|
|
59
58
|
const version = store.saveFlowScript({ repo, ...draft, digest: scriptDigest(draft), by: actor }, now);
|
|
60
59
|
return { ok: true, said: current === null ? `Saved the ${draft.name} script. Any flow in this project can run it.` : `Saved version ${version} of ${draft.name}. Every flow that runs it uses this version from now on.`, version };
|
|
61
60
|
}
|
|
62
|
-
/** The flows and zones in a project that run each script. */
|
|
63
|
-
export function scriptUses(store, repo) {
|
|
64
|
-
const uses = new Map();
|
|
65
|
-
for (const flow of store.listFlows([repo]))
|
|
66
|
-
for (const stage of flowDefinitionOf(flow)?.stages ?? [])
|
|
67
|
-
if (stage.kind === "check" && stage.script !== null)
|
|
68
|
-
uses.set(stage.script, [...uses.get(stage.script) ?? [], { flow: flow.id, flowName: flow.name, zone: stage.title }]);
|
|
69
|
-
return uses;
|
|
70
|
-
}
|
|
71
|
-
export function scriptWords(script) {
|
|
72
|
-
return `${script.name} (version ${script.version}, up to ${script.timeoutMinutes} min): ${script.about}`;
|
|
73
|
-
}
|
package/dist/flow-send.js
CHANGED
|
@@ -19,7 +19,7 @@ import { withActor } from "./actor.js";
|
|
|
19
19
|
import { flowCardHref, flowDefinitionOf, revisionWithNote } from "./flow-engine.js";
|
|
20
20
|
import { itemPlug, itemSource } from "./flow-items.js";
|
|
21
21
|
import { withStageHandoff } from "./contracts/stage-output.js";
|
|
22
|
-
import { flowSendForStore, readFlowChoiceAnswer,
|
|
22
|
+
import { flowSendForStore, readFlowChoiceAnswer, readFlowSendPayload } from "./contracts/flow-send.js";
|
|
23
23
|
import { notifyPeople } from "./flow-people.js";
|
|
24
24
|
import { readVerifiedReport } from "./evidence.js";
|
|
25
25
|
import { FLOW_END, replyTarget } from "./flows.js";
|
package/dist/flow-share.d.ts
CHANGED
|
@@ -59,8 +59,6 @@ export declare function importFlow(store: Store, plan: FlowImportPlan, actor: st
|
|
|
59
59
|
id: number;
|
|
60
60
|
said: string;
|
|
61
61
|
};
|
|
62
|
-
/** What a flow's zones and paths are, without where they sit on the canvas: what a round trip keeps. */
|
|
63
|
-
export declare function flowShape(definition: FlowDefinition): string;
|
|
64
62
|
/** A gist or GitHub file page as the address of its raw text; null when it isn't one Toolroll fetches. */
|
|
65
63
|
export declare function rawFlowUrl(address: string): string | null;
|
|
66
64
|
export type FetchLike = (url: string, init: {
|
package/dist/flow-share.js
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
* a person approves them, and its instructions are shown as the untrusted
|
|
16
16
|
* text they are.
|
|
17
17
|
*/
|
|
18
|
-
import { createHash } from "node:crypto";
|
|
19
18
|
import { scanForSecrets } from "./evidence.js";
|
|
20
19
|
import { flowDefinitionOf } from "./flow-engine.js";
|
|
21
20
|
import { readFlowSecrets } from "./flow-secrets.js";
|
|
@@ -24,7 +23,7 @@ import { addFlowTriggerTo, describeTrigger, HOOK_PATH, readHooksBase, triggerCon
|
|
|
24
23
|
import { durationMinutes, durationWords, FlowContractError, flowTerms, inStepWords, LANGUAGE_WORDS, validateFlowDefinition } from "./flows.js";
|
|
25
24
|
import { stageReferenceProblems } from "./contracts/stage-output.js";
|
|
26
25
|
import { readVersioned } from "./contracts/contract.js";
|
|
27
|
-
import { FLOW_ALIASES, WEBHOOK_SENDERS, FLOW_FILE_FORMAT, legacyFlowNeed, legacySubagentStep, FLOW_FILE_VERSION, flowFileSchema
|
|
26
|
+
import { FLOW_ALIASES, WEBHOOK_SENDERS, FLOW_FILE_FORMAT, legacyFlowNeed, legacySubagentStep, FLOW_FILE_VERSION, flowFileSchema } from "./contracts/flow.js";
|
|
28
27
|
import { parseSchedule } from "./flow-schedule.js";
|
|
29
28
|
export { FLOW_FILE_FORMAT, FLOW_FILE_VERSION };
|
|
30
29
|
/** The largest flow file Toolroll reads or fetches. */
|
|
@@ -550,10 +549,6 @@ export function importFlow(store, plan, actor, now, dir) {
|
|
|
550
549
|
return { id, said: `Imported ${plan.name}.${off === 0 ? "" : ` Its ${off === 1 ? "trigger is" : `${off} triggers are`} off until you turn ${off === 1 ? "it" : "them"} on.`}${held === 0 ? "" : ` Approve its ${held === 1 ? "script" : `${held} scripts`} on the Scripts panel before ${held === 1 ? "it runs" : "they run"}.`}` };
|
|
551
550
|
});
|
|
552
551
|
}
|
|
553
|
-
/** What a flow's zones and paths are, without where they sit on the canvas: what a round trip keeps. */
|
|
554
|
-
export function flowShape(definition) {
|
|
555
|
-
return createHash("sha256").update(JSON.stringify({ start: definition.start, stages: definition.stages.map(one => ({ ...one, zone: null })) })).digest("hex");
|
|
556
|
-
}
|
|
557
552
|
// ------------------------------------------------------------------ fetching
|
|
558
553
|
const FETCH_HOSTS = new Set(["github.com", "gist.github.com", "raw.githubusercontent.com", "gist.githubusercontent.com"]);
|
|
559
554
|
/** A gist or GitHub file page as the address of its raw text; null when it isn't one Toolroll fetches. */
|
package/dist/flow-steps.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* twice. Trouble reaching a service is retried three times, 5 then 15
|
|
23
23
|
* minutes apart; a check that fails is an answer, not trouble.
|
|
24
24
|
*/
|
|
25
|
-
import {
|
|
25
|
+
import { mkdirSync, rmSync } from "node:fs";
|
|
26
26
|
import { join } from "node:path";
|
|
27
27
|
import { approvedCommandShell, redactSecretAssignments, SETUP_ENV_ALLOWLIST, SETUP_ENV_DENYLIST } from "./builder.js";
|
|
28
28
|
import { assignmentOf } from "./assignment.js";
|
package/dist/flow-triggers.d.ts
CHANGED
|
@@ -62,7 +62,6 @@ export declare function takesDeliveries(config: TriggerConfig): boolean;
|
|
|
62
62
|
export declare function saveHookSecret(dir: string, trigger: number, secret: string, credential?: string): void;
|
|
63
63
|
/** Exactly this credential's secret, or null: never another's. */
|
|
64
64
|
export declare function readHookSecret(dir: string, trigger: number, credential?: string): string | null;
|
|
65
|
-
export declare const LINEAR_ENV = "TOOLROLL_LINEAR_KEY";
|
|
66
65
|
/** The Linear API key the worker checks Linear with: the environment, or kept by Toolroll (the keychain, or an owner-only file beside the database). */
|
|
67
66
|
export declare function readLinearKey(dir: string | null): string | null;
|
|
68
67
|
export declare function saveLinearKey(dir: string, key: string): {
|
package/dist/flow-triggers.js
CHANGED
|
@@ -50,6 +50,7 @@ import { prepareUnattendedCandidates, grantSignsScriptOf, scriptProvenanceOf, sc
|
|
|
50
50
|
import { tmpdir } from "node:os";
|
|
51
51
|
import { envValue } from "./names.js";
|
|
52
52
|
import { linearLabelNames, readFormSubmission, readGithubEvent, readGithubIssue, readGithubIssueEventList, readGithubIssueList, readGithubRun, readGithubRunList, readInboundMail, readLinearAnswer, readLinearEvent, readLinearIssue, readWebhookPayload } from "./contracts/trigger-payloads.js";
|
|
53
|
+
import { isRecord } from "./is-record.js";
|
|
53
54
|
export { FLOW_TRIGGER_KINDS };
|
|
54
55
|
export const CHAT_APP_NAMES = { slack: "Slack", discord: "Discord", teams: "Teams", telegram: "Telegram" };
|
|
55
56
|
/** What each kind is called on the canvas. */
|
|
@@ -66,7 +67,6 @@ const HOOK_BYTES = 1_000_000;
|
|
|
66
67
|
const TEAM = new Set(["OWNER", "MEMBER", "COLLABORATOR"]);
|
|
67
68
|
// ------------------------------------------------------------ the terms
|
|
68
69
|
const HIDDEN = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f\u200b-\u200f\u202a-\u202e\u2066-\u2069]/;
|
|
69
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
70
70
|
/**
|
|
71
71
|
* A trigger's settings read by their one schema (`label: required`, `unknown key 'flows'`). A setting given as null is
|
|
72
72
|
* left out, and a button's blank question lines are dropped, as every release has read them. Then what the schema can't
|
|
@@ -414,7 +414,6 @@ function dropHookSecret(dir, trigger, credential) {
|
|
|
414
414
|
catch { /* never read: nothing points at it */ }
|
|
415
415
|
}
|
|
416
416
|
const LINEAR = { name: "linear-key", file: ["linear-key"] };
|
|
417
|
-
export const LINEAR_ENV = "TOOLROLL_LINEAR_KEY";
|
|
418
417
|
/** The Linear API key the worker checks Linear with: the environment, or kept by Toolroll (the keychain, or an owner-only file beside the database). */
|
|
419
418
|
export function readLinearKey(dir) {
|
|
420
419
|
const env = envValue(process.env, "LINEAR_KEY")?.trim();
|
package/dist/flow-unattended.js
CHANGED
|
@@ -33,6 +33,7 @@ import { isProtectedWork } from "./approval-policy.js";
|
|
|
33
33
|
import { dollarWords as dollars, scheduleWords, UNATTENDED_RULE_WORDS, unattendedCoverWords, unattendedEndWords, unattendedHeadWords, unattendedLimitWords, untilWords } from "./flow-unattended-words.js";
|
|
34
34
|
import { MODE_MAX_DAYS } from "./modes.js";
|
|
35
35
|
import { accountReachesSql } from "./project-access.js";
|
|
36
|
+
import { canonicalJson } from "./canonical-json.js";
|
|
36
37
|
/** Grant history, run reservations and the last prepared script snapshots shared by UI/worker processes. Additive only. */
|
|
37
38
|
export const FLOW_UNATTENDED_SCHEMA = `
|
|
38
39
|
CREATE TABLE IF NOT EXISTS flow_script_provenance (
|
|
@@ -72,18 +73,6 @@ export const FLOW_ACCEPTANCE = {
|
|
|
72
73
|
export const UNATTENDED_MAX_RUNS = 50;
|
|
73
74
|
/** The largest per-attempt budget a grant may name: $100. */
|
|
74
75
|
export const UNATTENDED_MAX_BUDGET_MICROUSD = 100_000_000;
|
|
75
|
-
function canonicalJson(value) {
|
|
76
|
-
if (Array.isArray(value))
|
|
77
|
-
return `[${value.map(canonicalJson).join(",")}]`;
|
|
78
|
-
if (value !== null && typeof value === "object") {
|
|
79
|
-
const entries = Object.entries(value)
|
|
80
|
-
.filter(([, v]) => v !== undefined)
|
|
81
|
-
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
82
|
-
.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`);
|
|
83
|
-
return `{${entries.join(",")}}`;
|
|
84
|
-
}
|
|
85
|
-
return JSON.stringify(value);
|
|
86
|
-
}
|
|
87
76
|
export const unattendedTermsJson = (terms) => canonicalJson(terms);
|
|
88
77
|
/** sha256 over a domain-separated canonical encoding, 32 hex like the mode digest. */
|
|
89
78
|
export function unattendedDigestOf(terms) {
|
package/dist/flows.js
CHANGED
|
@@ -54,6 +54,7 @@ import { cardReference } from "./task-source.js";
|
|
|
54
54
|
import { parseContract, readVersioned } from "./contracts/contract.js";
|
|
55
55
|
import { stageReferenceProblems } from "./contracts/stage-output.js";
|
|
56
56
|
import { CHOICES_MAX, CHOICES_MIN, FLOW_ALIASES, FLOW_COLORS, FLOW_DEFINITION_VERSION, FLOW_END, FLOW_MERGE_METHODS, FLOW_STAGE_KINDS, flowDefinitionSchema, flowStepsSchema, HEADERS_MAX, legacySubagentStep, LONGEST_WAIT_MINUTES, savedFlowDefinitionSchema, SCRIPT_LANGUAGES, SCRIPT_NAME, sortKeyOf, SURE_AT_MAX, SURE_AT_MIN, ZONE_ID, } from "./contracts/flow.js";
|
|
57
|
+
import { isRecord } from "./is-record.js";
|
|
57
58
|
export { CHOICES_MAX, CHOICES_MIN, FLOW_COLORS, FLOW_END, FLOW_MERGE_METHODS, FLOW_STAGE_KINDS, LONGEST_WAIT_MINUTES, SCRIPT_LANGUAGES, SCRIPT_NAME, sortKeyOf };
|
|
58
59
|
/** What each kind is called and does, in the words the canvas uses. */
|
|
59
60
|
export const FLOW_KIND_WORDS = {
|
|
@@ -137,7 +138,6 @@ export class FlowContractError extends Error {
|
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
// ------------------------------------------------------------------ reading a drawing
|
|
140
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
141
141
|
/** Text as every release has kept it: trimmed, and blank as none. Anything else is left for the schema to name. */
|
|
142
142
|
const said = (value) => value === undefined || value === null ? null : typeof value === "string" ? value.trim() === "" ? null : value.trim() : value;
|
|
143
143
|
const coordinate = (value, min, max, fallback) => typeof value === "number" && Number.isFinite(value) ? Math.round(Math.min(max, Math.max(min, value))) : fallback;
|
package/dist/health-cli.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type ConnectOptions } from './connect-cli.js';
|
|
2
2
|
/** Read the running server, never a fresh CLI process's empty counters or the local database. */
|
|
3
|
-
export declare function runHealthCommand(argv: readonly string[], write: (line: string) => void, options?:
|
|
3
|
+
export declare function runHealthCommand(argv: readonly string[], write: (line: string) => void, options?: ConnectOptions): Promise<number>;
|
package/dist/health-cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { bearerOf, centralProfile } from './
|
|
1
|
+
import { bearerOf, centralProfile } from './connect-cli.js';
|
|
2
2
|
import { envelopeJson } from './envelope.js';
|
|
3
3
|
import { healthSnapshotSchema } from './contracts/health.js';
|
|
4
4
|
/** Read the running server, never a fresh CLI process's empty counters or the local database. */
|