toolroll 0.9.52 → 0.9.54
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 +16 -0
- package/README.md +55 -80
- package/dist/agentconfig.d.ts +11 -36
- package/dist/agentconfig.js +3 -62
- package/dist/approval-policy.d.ts +1 -1
- package/dist/approval-policy.js +1 -1
- package/dist/board.d.ts +3 -19
- package/dist/board.js +4 -42
- package/dist/browser/workspace.js +18 -18
- package/dist/browser-workspace.d.ts +2 -1
- package/dist/builder.d.ts +9 -40
- package/dist/builder.js +50 -257
- package/dist/chat-actions.js +3 -14
- package/dist/chat-ask.js +8 -8
- package/dist/chat-controls.d.ts +0 -4
- package/dist/chat-controls.js +0 -1
- package/dist/chat-core.d.ts +171 -0
- package/dist/chat-core.js +288 -0
- package/dist/chat-decide.d.ts +10 -8
- package/dist/chat-decide.js +27 -24
- package/dist/chat-delivery-state.d.ts +51 -75
- package/dist/chat-delivery-state.js +140 -170
- package/dist/chat-delivery.d.ts +21 -4
- package/dist/chat-delivery.js +313 -195
- package/dist/chat-flow.d.ts +29 -1
- package/dist/chat-flow.js +24 -50
- package/dist/chat-messages.d.ts +319 -0
- package/dist/chat-messages.js +841 -0
- package/dist/chat-migration.d.ts +30 -0
- package/dist/chat-migration.js +802 -0
- package/dist/chat-quiet.d.ts +3 -0
- package/dist/chat-quiet.js +7 -2
- package/dist/chat-task-actions.d.ts +1 -1
- package/dist/chat-task-actions.js +0 -2
- package/dist/claim.d.ts +79 -244
- package/dist/claim.js +688 -1023
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +10 -2
- package/dist/contracts/chat-content.d.ts +71 -2
- package/dist/contracts/chat-content.js +22 -3
- package/dist/contracts/chat-tables.d.ts +11 -4
- package/dist/contracts/chat-tables.js +165 -87
- package/dist/contracts/cli.d.ts +0 -13
- package/dist/contracts/cli.js +0 -2
- package/dist/contracts/console-api.d.ts +5 -10
- package/dist/contracts/console-api.js +4 -10
- package/dist/contracts/discord-callback.js +2 -1
- package/dist/contracts/flow.d.ts +50 -0
- package/dist/contracts/flow.js +26 -1
- package/dist/contracts/lead-tools.d.ts +0 -13
- package/dist/contracts/lead-tools.js +3 -3
- package/dist/contracts/slack-callback.js +3 -2
- package/dist/contracts/store-json.d.ts +1 -29
- package/dist/contracts/store-json.js +4 -17
- package/dist/contracts/teams-callback.js +2 -1
- package/dist/converse.d.ts +1 -11
- package/dist/converse.js +6 -38
- package/dist/coordinator.d.ts +0 -1
- package/dist/coordinator.js +3 -5
- package/dist/demo.js +16 -26
- package/dist/desktop-update-gate.js +0 -1
- package/dist/desktop-update.js +1 -3
- package/dist/discord-chat.js +19 -38
- package/dist/discord-settings.js +4 -13
- package/dist/discord.js +4 -14
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/dispose.d.ts +2 -3
- package/dist/dispose.js +17 -92
- package/dist/envelope.js +0 -3
- package/dist/exec.d.ts +0 -64
- package/dist/exec.js +3 -356
- package/dist/exhaustion.d.ts +22 -76
- package/dist/exhaustion.js +14 -140
- package/dist/export.js +8 -8
- package/dist/flow-engine.js +1 -1
- package/dist/flow-schedule.d.ts +154 -0
- package/dist/flow-schedule.js +321 -0
- package/dist/flow-share.js +1 -1
- package/dist/flow-triggers.d.ts +6 -1
- package/dist/flow-triggers.js +65 -10
- package/dist/flows-cli.js +8 -4
- package/dist/flows-ui.js +2 -0
- package/dist/flows.js +1 -1
- package/dist/guides.js +9 -29
- package/dist/invoke.d.ts +1 -24
- package/dist/invoke.js +17 -259
- package/dist/lead-status.js +2 -4
- package/dist/lead-voice.js +1 -1
- package/dist/mate-doors.d.ts +1 -2
- package/dist/mate-doors.js +12 -25
- package/dist/mate-tools.d.ts +2 -2
- package/dist/mate-tools.js +13 -24
- package/dist/modes.d.ts +19 -8
- package/dist/modes.js +24 -14
- package/dist/notification-rows.d.ts +30 -0
- package/dist/notification-rows.js +102 -0
- package/dist/operate-remote-arguments.js +2 -6
- package/dist/operate-remote.js +6 -7
- package/dist/operate.d.ts +0 -6
- package/dist/operate.js +226 -2248
- package/dist/phase-routing.d.ts +13 -23
- package/dist/phase-routing.js +13 -35
- package/dist/plan-auto.js +2 -2
- package/dist/plane-review.js +5 -11
- package/dist/planner-source.js +2 -1
- package/dist/policy.d.ts +1 -4
- package/dist/policy.js +0 -8
- package/dist/process-recovery-eligibility.js +2 -3
- package/dist/project-delete.js +24 -41
- package/dist/proposal.d.ts +4 -24
- package/dist/proposal.js +3 -88
- package/dist/provider-auth.d.ts +3 -3
- package/dist/provider-auth.js +4 -6
- package/dist/provider.d.ts +11 -25
- package/dist/provider.js +4 -36
- package/dist/push.js +1 -1
- package/dist/recipe-ui.js +6 -6
- package/dist/recipes.d.ts +3 -3
- package/dist/recipes.js +27 -23
- package/dist/result-shots.js +2 -2
- package/dist/retention.js +1 -1
- package/dist/run-closeout.d.ts +1 -1
- package/dist/run-closeout.js +1 -4
- package/dist/scope.d.ts +11 -65
- package/dist/scope.js +17 -82
- package/dist/serve.js +15 -24
- package/dist/server/chat.js +7 -30
- package/dist/server/flows.js +11 -10
- package/dist/server/guards.js +0 -1
- package/dist/server/pages-assets.js +1 -1
- package/dist/server/pages.js +0 -2
- package/dist/server/people-tokens.js +0 -4
- package/dist/server/route-table.d.ts +1 -1
- package/dist/server/route-table.js +2 -17
- package/dist/server/settings.js +6 -12
- package/dist/server/shared.d.ts +28 -212
- package/dist/server/shared.js +71 -780
- package/dist/server/task-views.js +9 -76
- package/dist/server/tasks.d.ts +1 -50
- package/dist/server/tasks.js +36 -946
- package/dist/setup-guide.d.ts +2 -2
- package/dist/slack-api.d.ts +5 -1
- package/dist/slack-api.js +2 -2
- package/dist/slack-chat.d.ts +9 -6
- package/dist/slack-chat.js +29 -53
- package/dist/slack-settings.js +6 -15
- package/dist/slack.js +6 -16
- package/dist/store.d.ts +200 -1702
- package/dist/store.js +811 -5439
- package/dist/surface.js +10 -24
- package/dist/task-composer.d.ts +1 -1
- package/dist/task-composer.js +1 -1
- package/dist/task-control.d.ts +3 -10
- package/dist/task-control.js +2 -7
- package/dist/teammate-desk.js +1 -1
- package/dist/teammate-question.js +12 -12
- package/dist/teammates-ui.js +1 -1
- package/dist/teams-chat.js +12 -9
- package/dist/teams-settings.js +2 -2
- package/dist/teams.js +4 -5
- package/dist/telegram-flow.js +5 -5
- package/dist/telegram-mate.d.ts +0 -3
- package/dist/telegram-mate.js +0 -1
- package/dist/telegram.js +4 -4
- package/dist/templates.d.ts +11 -7
- package/dist/templates.js +12 -9
- package/dist/toolroll-update.d.ts +20 -0
- package/dist/toolroll-update.js +104 -5
- package/dist/work-index.js +2 -6
- package/dist/workspace-revision.js +3 -1
- package/dist/workspace-ui.js +1 -1
- package/package.json +1 -1
- package/scripts/recovery-canary.mjs +3 -3
- package/dist/contest.d.ts +0 -318
- package/dist/contest.js +0 -753
- package/dist/held.d.ts +0 -150
- package/dist/held.js +0 -799
- package/dist/liveness.d.ts +0 -30
- package/dist/liveness.js +0 -42
- package/dist/pricing.d.ts +0 -45
- package/dist/pricing.js +0 -77
- package/dist/routine.d.ts +0 -228
- package/dist/routine.js +0 -764
- package/dist/slack-state.d.ts +0 -13
- package/dist/slack-state.js +0 -10
- package/dist/supervisor.mjs +0 -297
package/dist/server/pages.js
CHANGED
|
@@ -320,7 +320,6 @@ export function createPagesHandlers(runtime) {
|
|
|
320
320
|
settings: options.telegramTokenFile !== undefined,
|
|
321
321
|
building: store.liveClaims(project, now),
|
|
322
322
|
runners: store.listRunners(),
|
|
323
|
-
heldSessions: new Map(store.openHeldSessions().reduce((by, one) => by.set(one.runner, (by.get(one.runner) ?? 0) + 1), new Map())),
|
|
324
323
|
worktrees: store
|
|
325
324
|
.listWorktrees()
|
|
326
325
|
.filter(one => project === null || sameRepo(one.repo, project)),
|
|
@@ -346,7 +345,6 @@ export function createPagesHandlers(runtime) {
|
|
|
346
345
|
}),
|
|
347
346
|
building: store.liveClaims(project, now),
|
|
348
347
|
runners: store.listRunners(),
|
|
349
|
-
heldSessions: new Map(store.openHeldSessions().reduce((by, one) => by.set(one.runner, (by.get(one.runner) ?? 0) + 1), new Map())),
|
|
350
348
|
worktrees: store.listWorktrees().filter(one => project === null || sameRepo(one.repo, project)),
|
|
351
349
|
episode: project === null ? null : store.latestWatchEpisode(project),
|
|
352
350
|
outboxPending: store.pendingForAttention().length,
|
|
@@ -73,7 +73,6 @@ export function createPeopleHandlers(runtime) {
|
|
|
73
73
|
`<p class="meta">Operators with all-project access also manage the instance.</p><fieldset><legend>Projects</legend>${projectChoices.length === 0 ? `<p class="meta">Add a project before granting selected access.</p>` : projectChoices.map(repo => `<label class="row"><input type="checkbox" name="projects" value="${escape(repo)}"${selected?.includes(repo) ? " checked" : ""}>${escape(projectName(repo))}</label>`).join("")}</fieldset>`;
|
|
74
74
|
const cards = accounts.map(one => {
|
|
75
75
|
const seen = lastSeenOf(one.name);
|
|
76
|
-
const attended = store.openAttendedOf(one.name);
|
|
77
76
|
const acts = store.recentActsOf(one.name);
|
|
78
77
|
const standing = one.revokedAt !== null
|
|
79
78
|
? `revoked ${escape(one.revokedAt.slice(0, 16).replace("T", " "))} by ${personChip(one.revokedBy ?? "?")}`
|
|
@@ -87,9 +86,6 @@ export function createPeopleHandlers(runtime) {
|
|
|
87
86
|
approverView && one.revokedAt === null ? `<details><summary>Edit project access</summary><form method="post" action="/people/projects">${hiddenFields({ csrf, name: one.name })}${accessFields(one.projects)}<label>Your password<input type="password" name="token" autocomplete="current-password" required></label><p class="meta">Changing access signs this person out and ends their derived sessions and modes. Previously approved work stays recorded.</p><button type="submit">Save project access</button></form></details>` : "",
|
|
88
87
|
`<p class="meta">${seen === null ? "not signed in right now" : `signed in \u2014 active ${escape(new Date(seen).toISOString().slice(11, 16))} UTC`} \u00b7 joined ${escape(one.addedAt.slice(0, 10))}</p>`,
|
|
89
88
|
`<p><a href="${escape(personHref(one.name))}">Tokens and remote activity</a></p>`,
|
|
90
|
-
attended.length === 0
|
|
91
|
-
? ""
|
|
92
|
-
: `<p class="row">watching now: ${attended.map(session => `<a href="/t/${escape(session.taskId)}">${escape(session.taskId)}</a>`).join(", ")}</p>`,
|
|
93
89
|
acts.length === 0
|
|
94
90
|
? `<p class="meta">No recorded acts yet</p>`
|
|
95
91
|
: acts.map(act => `<p class="row meta">${escape(act.kind)} ${escape(act.subject)} \u00b7 ${escape(act.at.slice(0, 16).replace("T", " "))}</p>`).join("\n"),
|
|
@@ -17,7 +17,7 @@ export type Caller = "anonymous" | "service" | "cookie" | "bearer" | "oauth" | "
|
|
|
17
17
|
/** What the caller must hold: nothing, read, act (an approver or an `act` token), or a fresh password/provider check on top. */
|
|
18
18
|
export type RouteScope = "none" | "read" | "act" | "step-up";
|
|
19
19
|
/** Where the request's project comes from. */
|
|
20
|
-
export type ProjectResolver = "none" | "session" | "form" | "form-path" | "task" | "run" | "decision" | "incident" | "
|
|
20
|
+
export type ProjectResolver = "none" | "session" | "form" | "form-path" | "task" | "run" | "decision" | "incident" | "flow" | "proposal" | "conversation" | "coding" | "adapter";
|
|
21
21
|
/**
|
|
22
22
|
* What a project-limited account may do here:
|
|
23
23
|
* - `deny`: instance access only.
|
|
@@ -120,7 +120,6 @@ get("tasks", "runs", "/runs", { limited: "collection" });
|
|
|
120
120
|
get("pages", "menu", "/menu", { limited: "collection", ...free });
|
|
121
121
|
get("tasks", "run.page", `^\\/r\\/${ID}$`, { project: "run", limited: "resource", ...free, sample: "/r/1" });
|
|
122
122
|
get("tasks", "run.evidence", `^\\/r\\/${ID}\\/evidence\\/${ID}$`, { project: "run", limited: "resource", ...free, sample: "/r/1/evidence/2" });
|
|
123
|
-
get("tasks", "contest.page", `^\\/contest\\/${ID}$`, { ...free, sample: "/contest/1" });
|
|
124
123
|
get("pages", "caps", "/caps");
|
|
125
124
|
get("flows", "flows.new", "/flows/new", { limited: "resource", ...free });
|
|
126
125
|
get("flows", "flows.gallery", "^\\/flows\\/new\\/[a-z-]{1,40}$", { limited: "resource", ...free, sample: "/flows/new/triage" });
|
|
@@ -139,13 +138,14 @@ for (const one of ["run", "start", "new", "edit", "from-task", "preview", "expor
|
|
|
139
138
|
get("flows", `recipes.${one}`, `/recipes/${one}`, { limited: "collection" });
|
|
140
139
|
// Any other recipe screen answers the recipe area's own refusal.
|
|
141
140
|
get("flows", "recipes.other", "^\\/recipes\\/.*$", { sample: "/recipes/unknown" });
|
|
141
|
+
// v115: routines became scheduled flows; old links to them land on the flows page.
|
|
142
142
|
get("tasks", "routines", "/routines", { limited: "collection" });
|
|
143
143
|
get("chat", "chat.stream", "/chat/stream", free);
|
|
144
144
|
get("chat", "chat.mate-status", "/chat/mate/status", free);
|
|
145
145
|
get("chat", "chat.demo-live", "/chat/demo/live", free);
|
|
146
146
|
get("chat", "chat.page", "/chat", { project: "conversation", limited: "conversation", ...free });
|
|
147
147
|
get("chat", "chat.ack", `^\\/chat\\/ack\\/${ID}$`, { sample: "/chat/ack/1" });
|
|
148
|
-
get("tasks", "routine.page", `^\\/routines\\/${ID}$`, {
|
|
148
|
+
get("tasks", "routine.page", `^\\/routines\\/${ID}$`, { limited: "resource", sample: "/routines/1" });
|
|
149
149
|
get("settings", "control", "/control");
|
|
150
150
|
get("settings", "control.connection", "/control/connection");
|
|
151
151
|
get("chat", "chat.action", `^\\/chat\\/action\\/${ID}$`, { project: "proposal", limited: "proposal", ...free, sample: "/chat/action/1" });
|
|
@@ -166,8 +166,6 @@ get("chat", "lead.status", "/lead/status", free);
|
|
|
166
166
|
get("chat", "chat.task-status", "/chat/task-status", free);
|
|
167
167
|
get("tasks", "decision.evidence", `^\\/d\\/${ID}\\/evidence\\/${ID}$`, { project: "decision", limited: "resource", ...free, sample: "/d/1/evidence/2" });
|
|
168
168
|
// ---- console actions -------------------------------------------------------------------------------------------
|
|
169
|
-
// The attended beat guards itself (cookie, form type, Sec-Fetch-Site) before the shared mutation guard.
|
|
170
|
-
post("tasks", "session.attended-beats", "/session/attended-beats", { callers: ["cookie"], scopeRefusal: "your login can watch, not keep sessions alive", callerRefusal: { status: 403, type: "text/plain; charset=utf-8", body: "watching is a browser session's act" } });
|
|
171
169
|
// The scripted demo: the handler answers a non-browser caller "no page here".
|
|
172
170
|
post("chat", "chat.demo", "^\\/chat\\/demo\\/(ask|[0-9]{1,9}\\/(approve|change|revise|complete))$", { sample: "/chat/demo/ask" });
|
|
173
171
|
post("settings", "provider.resume", "^\\/providers\\/[a-z]+\\/resume$", { sample: "/providers/codex/resume" });
|
|
@@ -243,12 +241,6 @@ post("people", "people.revoke", "/people/revoke", { scope: "step-up" });
|
|
|
243
241
|
post("pages", "fleet.retire", "/fleet/runner/retire", { scope: "step-up" });
|
|
244
242
|
// Answering a parked decision needs act access and irreversible-choice confirmation, not password step-up.
|
|
245
243
|
post("tasks", "decision.answer", `^\\/d\\/${ID}\\/answer$`, { project: "decision", limited: "resource", scope: "act", sample: "/d/1/answer" });
|
|
246
|
-
post("tasks", "contest.act.arm", `^\\/contest\\/${ID}\\/arm$`, { sample: "/contest/1/arm" });
|
|
247
|
-
post("tasks", "contest.act.pick", `^\\/contest\\/${ID}\\/pick$`, { scope: "step-up", sample: "/contest/1/pick" });
|
|
248
|
-
post("tasks", "contest.act.abandon", `^\\/contest\\/${ID}\\/abandon$`, { scope: "step-up", sample: "/contest/1/abandon" });
|
|
249
|
-
post("tasks", "task.attend.attend-preview", `^\\/t\\/${TASK}\\/attend-preview$`, { callers: ["cookie"], project: "task", sample: "/t/one/attend-preview" });
|
|
250
|
-
post("tasks", "task.attend.attend", `^\\/t\\/${TASK}\\/attend$`, { scope: "step-up", project: "task", sample: "/t/one/attend" });
|
|
251
|
-
post("tasks", "task.attend.attend-revoke", `^\\/t\\/${TASK}\\/attend-revoke$`, { callers: ["cookie"], project: "task", sample: "/t/one/attend-revoke" });
|
|
252
244
|
post("tasks", "task.act.hold", `^\\/t\\/${TASK}\\/hold$`, { project: "task", limited: "resource", sample: "/t/one/hold" });
|
|
253
245
|
post("tasks", "task.act.unhold", `^\\/t\\/${TASK}\\/unhold$`, { project: "task", limited: "resource", sample: "/t/one/unhold" });
|
|
254
246
|
post("tasks", "task.act.requeue", `^\\/t\\/${TASK}\\/requeue$`, { project: "task", limited: "resource", sample: "/t/one/requeue" });
|
|
@@ -291,15 +283,8 @@ post("chat", "chat.ack-send", `^\\/chat\\/ack\\/${ID}$`, { scope: "step-up", sam
|
|
|
291
283
|
for (const one of ["prepare", "preview", "import", "save"])
|
|
292
284
|
post("flows", `recipes.${one}-send`, `/recipes/${one}`, { limited: "collection" });
|
|
293
285
|
post("flows", "recipes.launch-send", "/recipes/launch", { limited: "collection" });
|
|
294
|
-
post("tasks", "routines.add", "/routines/add", { project: "form", limited: "collection" });
|
|
295
|
-
post("tasks", "routine.act.approve", `^\\/routines\\/${ID}\\/approve$`, { scope: "step-up", project: "routine", limited: "resource", sample: "/routines/1/approve" });
|
|
296
|
-
post("tasks", "routine.act.refresh", `^\\/routines\\/${ID}\\/refresh$`, { project: "routine", limited: "resource", sample: "/routines/1/refresh" });
|
|
297
|
-
post("tasks", "routine.act.pause", `^\\/routines\\/${ID}\\/pause$`, { project: "routine", limited: "resource", sample: "/routines/1/pause" });
|
|
298
|
-
post("tasks", "routine.act.resume", `^\\/routines\\/${ID}\\/resume$`, { project: "routine", limited: "resource", sample: "/routines/1/resume" });
|
|
299
|
-
post("tasks", "routine.act.run-now", `^\\/routines\\/${ID}\\/run-now$`, { scope: "step-up", project: "routine", limited: "resource", sample: "/routines/1/run-now" });
|
|
300
286
|
post("tasks", "run.act", `^\\/r\\/${ID}\\/(note|comment|revise|draft-repair|checks|add-tests)$`, { project: "run", limited: "resource", sample: "/r/1/note" });
|
|
301
287
|
post("tasks", "session.editor-links", "/session/editor-links", { viewer: true });
|
|
302
|
-
post("tasks", "run.turn", `^\\/r\\/${ID}\\/turn$`, { project: "run", sample: "/r/1/turn" });
|
|
303
288
|
post("tasks", "incident.resolve", `^\\/i\\/${ID}\\/resolve$`, { project: "incident", sample: "/i/1/resolve" });
|
|
304
289
|
/** The sole route table, in match order. */
|
|
305
290
|
export const ROUTES = Object.freeze(rows.map(one => Object.freeze(one)));
|
package/dist/server/settings.js
CHANGED
|
@@ -66,7 +66,7 @@ import { startConnect } from "../mcp-connect.js";
|
|
|
66
66
|
import { decideProposal, listProposals, memoryStatus } from "../memory-pass.js";
|
|
67
67
|
import { checkModels, isNewModel, modelOptions, modelWords, RUNTIME_TOOLS, runtimeStates, seenModels, setWatch, updateRuntime, watchState } from "../model-catalog.js";
|
|
68
68
|
import { modelsHtml, modelsScript } from "../models-ui.js";
|
|
69
|
-
import { MODE_MAX_DAYS, modeDigestOf, modeTermsJson, modeWords, presetTerms } from "../modes.js";
|
|
69
|
+
import { CHAT_APPROVE_ALL, MODE_MAX_DAYS, modeDigestOf, modeTermsJson, modeWords, presetTerms } from "../modes.js";
|
|
70
70
|
import { monitoringChange, readMonitoring, saveMonitoring } from "../monitoring-settings.js";
|
|
71
71
|
import { monitoringHtml, signingSecretHtml } from "../monitoring-ui.js";
|
|
72
72
|
import { openRouterPickerScript } from "../openrouter-models.js";
|
|
@@ -96,7 +96,6 @@ import { addProjectInstructions, ASSISTANTS, detectPreparation, modelChoices, pr
|
|
|
96
96
|
import { skillsHtml, skillsScript } from "../skills-ui.js";
|
|
97
97
|
import { checkSlackCredentials, clearSlackCredentials, loadSlackCredentials, saveSlackCredentials, SLACK_MANIFEST, SlackError } from "../slack-api.js";
|
|
98
98
|
import { slackSettingsHtml } from "../slack-settings.js";
|
|
99
|
-
import { SlackState } from "../slack-state.js";
|
|
100
99
|
import { spendCsv, spendHtml } from "../spend-ui.js";
|
|
101
100
|
import { budgetStates, monthNamed, spendItems, usd as spendUsd, teammateNames as teammateNamesOf } from "../spend.js";
|
|
102
101
|
import { removeSsoSettings, saveSsoSettings, SSO_CALLBACK, ssoChangeWords } from "../sso-settings.js";
|
|
@@ -200,10 +199,6 @@ export function createSettingsHandlers(runtime) {
|
|
|
200
199
|
`<option value="">approve plans and merges here, with my password (the default)</option>` +
|
|
201
200
|
`<option value="1">approve plans and merge ready pull requests from my paired chat, two taps each</option>` +
|
|
202
201
|
`</select><span class="meta">Plans that widen permissions, exceed the attempt cap or touch protected paths still open Toolroll.</span></label>`,
|
|
203
|
-
`<label>If a subscription runs out<select name="allow-paid-fallback">` +
|
|
204
|
-
`<option value="">never switch to a paid API key on its own (the default, every preset)</option>` +
|
|
205
|
-
`<option value="1">allow the approved fallback — spend moves to that account</option>` +
|
|
206
|
-
`</select></label>`,
|
|
207
202
|
`<button type="submit">Read the full terms</button>`,
|
|
208
203
|
`</form>`,
|
|
209
204
|
`</div>`,
|
|
@@ -1603,7 +1598,7 @@ export function createSettingsHandlers(runtime) {
|
|
|
1603
1598
|
const body = readForm(posted, CONSOLE_FORMS.slack);
|
|
1604
1599
|
if (who.via !== "cookie" || who.role !== "approver" || restricted() || !options.configDir)
|
|
1605
1600
|
return refuse(response, who, 403, "An installation approver can connect Slack.", "/settings");
|
|
1606
|
-
const dir = options.configDir, state = new
|
|
1601
|
+
const dir = options.configDir, state = new ChatState(store, "slack"), action = url.pathname.split("/").at(-1);
|
|
1607
1602
|
const show = (problem, status = 400) => sendScreen(response, status, screen("Slack", slackSettingsHtml(store, dir, who.session.csrf, { problem, who: who.name }), { chrome: chromeFor(projectOf(who, request) ?? null, "settings") }));
|
|
1608
1603
|
if (["password", "app-token", "bot-token"].some(key => body.getAll(key).length > 1))
|
|
1609
1604
|
return show("Submit one value for each field.");
|
|
@@ -2049,16 +2044,15 @@ export function createSettingsHandlers(runtime) {
|
|
|
2049
2044
|
planAuto: body.get("plan-auto") === "1",
|
|
2050
2045
|
reviewAuto: false,
|
|
2051
2046
|
reviewRetryAuto: false,
|
|
2052
|
-
// The paid-fallback grant is NEVER a preset default (R8): unchecked
|
|
2053
|
-
// stays false on every preset — only the explicit box grants it.
|
|
2054
|
-
allowPaidFallback: body.get("allow-paid-fallback") === "1",
|
|
2055
2047
|
// The repair-auto grant is the SAME rule (v40): unchecked stays
|
|
2056
2048
|
// false on every preset — only the explicit box grants it, and the
|
|
2057
2049
|
// attempt cap it carries is meaningless without it.
|
|
2058
2050
|
repairAuto: false,
|
|
2059
2051
|
repairMaxAttempts: 0,
|
|
2060
|
-
// Approving from the paired chat: only the explicit choice grants it
|
|
2052
|
+
// Approving from the paired chat: only the explicit choice grants it, naming every chat app it covers (a grant
|
|
2053
|
+
// signed before it named them stays Telegram only).
|
|
2061
2054
|
chatApprove: body.get("chat-approve") === "1",
|
|
2055
|
+
...(body.get("chat-approve") === "1" ? { chatApproveChats: CHAT_APPROVE_ALL } : {}),
|
|
2062
2056
|
publication: body.get("publication") === "automerge" ? "automerge" : "notify",
|
|
2063
2057
|
};
|
|
2064
2058
|
if (["review-auto", "review-retry-auto", "repair-auto"].some(field => body.get(field) === "1")) {
|
|
@@ -2080,7 +2074,7 @@ export function createSettingsHandlers(runtime) {
|
|
|
2080
2074
|
`<input type="hidden" name="csrf" value="${escape(who.session.csrf)}">` +
|
|
2081
2075
|
`<input type="hidden" name="nonce" value="${escape(nonce)}">` +
|
|
2082
2076
|
`<input type="hidden" name="digest" value="${escape(digest)}">` +
|
|
2083
|
-
["name", "days", "publication", "auto-approve", "plan-auto", "chat-approve"
|
|
2077
|
+
["name", "days", "publication", "auto-approve", "plan-auto", "chat-approve"]
|
|
2084
2078
|
.map(field => `<input type="hidden" name="${field}" value="${escape(body.get(field) ?? "")}">`)
|
|
2085
2079
|
.join("") +
|
|
2086
2080
|
`<input type="hidden" name="expiry" value="${escape(expiry)}">` +
|