toolroll 0.9.22 → 0.9.24
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 +12 -0
- package/dist/browser/workspace.js +31 -21
- package/dist/browser-workspace.d.ts +13 -1
- package/dist/flow-send.js +10 -1
- package/dist/serve.d.ts +12 -1
- package/dist/serve.js +72 -35
- package/package.json +1 -1
|
@@ -171,7 +171,8 @@ export type BrowserLimits = {
|
|
|
171
171
|
export type BrowserSettingsView = {
|
|
172
172
|
kind: 'settings';
|
|
173
173
|
said: string | null;
|
|
174
|
-
|
|
174
|
+
/** The settings destinations under short headings; a chat app's tile says whether it is connected and gets alerts. */
|
|
175
|
+
groups: BrowserSettingsGroup[];
|
|
175
176
|
theme: 'system' | 'light' | 'dark';
|
|
176
177
|
/** The signal colour chosen for this browser (Settings → Appearance), "#rrggbb"; chart magenta by default. */
|
|
177
178
|
accent: string;
|
|
@@ -280,6 +281,17 @@ export type BrowserSettingsView = {
|
|
|
280
281
|
/** Settings → Updates: this version, the latest known one and its notes, how to update, the daily-check switch, and each worker's version. */
|
|
281
282
|
updates?: BrowserUpdates | null;
|
|
282
283
|
};
|
|
284
|
+
export type BrowserSettingsGroup = {
|
|
285
|
+
title: string;
|
|
286
|
+
tiles: {
|
|
287
|
+
href: string;
|
|
288
|
+
label: string;
|
|
289
|
+
status?: {
|
|
290
|
+
tone: 'ok' | 'warn' | 'off';
|
|
291
|
+
words: string;
|
|
292
|
+
};
|
|
293
|
+
}[];
|
|
294
|
+
};
|
|
283
295
|
export type BrowserUpdates = {
|
|
284
296
|
current: string;
|
|
285
297
|
/** The latest release the last check found; null before any check has worked. */
|
package/dist/flow-send.js
CHANGED
|
@@ -55,6 +55,14 @@ function resultOf(store, taskId, now, evidenceRoot) {
|
|
|
55
55
|
shots: receipt !== null && store.artifactsFor(receipt.runId).some(one => one.kind === "screenshot") ? { taskId: receipt.taskId, run: receipt.runId } : null,
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
|
+
/** A research task's latest delivered report, when its run saved screenshots: what that step produced to show. */
|
|
59
|
+
function reportShotsOf(store, taskId) {
|
|
60
|
+
const ref = store.lookupRef(taskId);
|
|
61
|
+
if (ref === null)
|
|
62
|
+
return null;
|
|
63
|
+
const run = store.runsFor(ref.id).find(one => one.finishedAt !== null && one.role === "scout");
|
|
64
|
+
return run !== undefined && run.outcome === "built" && store.artifactsFor(run.id).some(one => one.kind === "screenshot") ? { taskId, run: run.id } : null;
|
|
65
|
+
}
|
|
58
66
|
/** What a visit sends its person, worked out from the card as it is now. */
|
|
59
67
|
export function flowSendContent(store, flow, definition, stage, card, now, evidenceRoot) {
|
|
60
68
|
const before = stepBefore(store, definition, card);
|
|
@@ -90,7 +98,8 @@ export function flowSendContent(store, flow, definition, stage, card, now, evide
|
|
|
90
98
|
const options = stage.kind === "choose" ? (stage.options ?? []).map((one, choice) => ({ choice, label: one.label })) : undefined;
|
|
91
99
|
return {
|
|
92
100
|
title: cut(plain(before === null ? card.title : `${card.title} · ${before.title}`), 200), ...(before === null ? {} : { from: before.title }),
|
|
93
|
-
|
|
101
|
+
// After research, its own screenshots are what that step produced; otherwise the build's.
|
|
102
|
+
summary: plain(lines.join("\n\n")), links, shots: (report === null ? null : reportShotsOf(store, report)) ?? result?.shots ?? null,
|
|
94
103
|
...(options === undefined ? {} : { options, reply: replyTarget(stage) !== null }),
|
|
95
104
|
};
|
|
96
105
|
}
|
package/dist/serve.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BrowserWorkspace, type BrowserNeedAction, type BrowserSignIn, type BrowserUpdateNotice } from './browser-workspace.js';
|
|
1
|
+
import { type BrowserWorkspace, type BrowserNeedAction, type BrowserSignIn, type BrowserUpdateNotice, type BrowserSettingsGroup } from './browser-workspace.js';
|
|
2
2
|
import { CodingWorkspace } from './coding-workspace.js';
|
|
3
3
|
import { type FetchLike } from "./flow-share.js";
|
|
4
4
|
import { type MailSender } from "./flow-actions.js";
|
|
@@ -569,4 +569,15 @@ export declare function needActionOf(assignment: AssignmentSnapshot | null, stat
|
|
|
569
569
|
* stop marker, so an open tab quits refetching a dead build (round-4
|
|
570
570
|
* finding 15). */
|
|
571
571
|
export declare function runFactsFragment(run: Run, taskId: string, live: boolean, route?: RouteStamp | null): string;
|
|
572
|
+
/**
|
|
573
|
+
* The settings groups, with each chat app's state from what the server already holds: not set up,
|
|
574
|
+
* connected, or getting alerts (only when that service was chosen, or is the only one).
|
|
575
|
+
* A Telegram bot whose saved delivery state reports a problem says so instead. With no config folder
|
|
576
|
+
* the state is unknown, so the tiles carry none.
|
|
577
|
+
*/
|
|
578
|
+
export declare function settingsGroups(messaging: {
|
|
579
|
+
channel: string | null;
|
|
580
|
+
implicit: boolean;
|
|
581
|
+
configured: string[];
|
|
582
|
+
} | null, telegramFailing?: boolean): BrowserSettingsGroup[];
|
|
572
583
|
export {};
|
package/dist/serve.js
CHANGED
|
@@ -4239,7 +4239,7 @@ export function createDecisionServer(options) {
|
|
|
4239
4239
|
})(), (() => {
|
|
4240
4240
|
const chosen = store.notificationPreference(who.name);
|
|
4241
4241
|
return { mode: chosen.mode, digestAt: chosen.digestAt, screenshots: chosen.screenshots, projects: notificationProjects(store, who.name) };
|
|
4242
|
-
})()));
|
|
4242
|
+
})(), telegramTrouble(store, loadBotToken(process.env, options.telegramTokenFile))));
|
|
4243
4243
|
}
|
|
4244
4244
|
if (url.pathname === "/push/key") {
|
|
4245
4245
|
// Session-gated: the key is not secret, but strangers get nothing.
|
|
@@ -15878,7 +15878,7 @@ button.pick-file { min-height: 1.75rem; padding: 0 .55rem; font-size: .75rem; }
|
|
|
15878
15878
|
}
|
|
15879
15879
|
`;
|
|
15880
15880
|
/** Appearance: a three-way segmented switch, one tap per choice. */
|
|
15881
|
-
const THEME_CONTROLS_CSS = `.task-repo select{width:100%;min-height:2.75rem;font-size:1rem}.task-repo-add{margin:.35rem .1rem .5rem}.task-repo-add a{display:inline-flex;align-items:center;min-height:2.25rem}details.result-request-open.result-request-form>summary{border:0;background:transparent;padding:.5rem 0;min-height:2.75rem;font-weight:600;display:list-item;list-style:revert}details.result-request-open.result-request-form>summary::-webkit-details-marker{display:revert}form.js-autosave button[type=submit]{display:none}.provider-row{border-bottom:1px solid var(--so-line);padding:.35rem 0}.provider-row:first-of-type{border-top:1px solid var(--so-line)}.provider-head{display:flex;align-items:center;gap:.75rem;margin:.4rem 0 0}.provider-status{display:inline-flex;align-items:center;gap:.4rem;color:var(--so-muted);font-size:.875rem}.provider-status i{width:.5rem;height:.5rem;border-radius:50%;background:var(--so-muted)}.provider-status--ok i{background:var(--so-success)}.provider-status--warn i{background:var(--so-attention)}.provider-status--off i{background:transparent;border:1.5px solid var(--so-muted)}details.provider-manage>summary{cursor:pointer;color:var(--so-accent-text);font-size:.875rem;min-height:2.5rem;display:list-item;padding-block:.5rem}.card.props .row{display:grid;gap:.1rem;margin:0 0 .75rem}.card.props .row>.meta{display:block;font-size:.75rem}.card.props .row>.meta::first-letter{text-transform:uppercase}.card.props .row>.mono{font-family:var(--font-sans);font-size:.875rem}.card.props .row>.mono .seal{font-family:var(--font-mono);font-size:.8125rem}details.evidence-files{margin:1rem 0}details.evidence-files>summary{cursor:pointer;min-height:2.75rem;display:list-item;padding-block:.7rem;font-weight:600}details.evidence-files ul{list-style:none;margin:0;padding:0}details.evidence-files li{display:flex;justify-content:space-between;gap:1rem;padding:.5rem 0;border-bottom:1px solid var(--so-line)}.result-action .result-feedback-link{display:inline-flex;align-items:center;min-height:2.5rem;padding:.5rem 1rem;border:1px solid var(--so-input-line);border-radius:.5rem;background:var(--so-paper);color:var(--so-ink);font-weight:600;text-decoration:none}@media(hover:hover) and (pointer:fine){.result-action .result-feedback-link:hover{background:var(--so-raised)}}.so-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.verdict{margin:.5rem 0 .75rem}.verdict-chips{display:flex;flex-wrap:wrap;gap:.4rem;list-style:none;padding:0;margin:0}.verdict-chip{display:inline-flex;align-items:center;gap:.3rem;min-height:1.75rem;padding:.2rem .65rem;border-radius:999px;font-size:.8125rem;font-weight:600;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}.verdict-chip svg{width:.9rem;height:.9rem}.verdict-chip--success{background:var(--so-success-soft);color:var(--so-success)}.verdict-chip--danger{background:var(--so-danger-soft);color:var(--so-danger)}.verdict-chip--warning{background:var(--so-warning-soft);color:var(--so-warning)}.verdict-chip--info{background:var(--so-info-soft);color:var(--so-info)}.verdict-by{margin:.4rem 0 0}details.result-request-open{margin:.5rem 0}details.result-request-open>summary{display:inline-flex;align-items:center;min-height:2.5rem;padding:.5rem 1rem;border:1px solid var(--so-input-line);border-radius:.5rem;background:var(--so-paper);color:var(--so-ink);font-weight:600;cursor:pointer;list-style:none}details.result-request-open>summary::-webkit-details-marker{display:none}details.result-request-open[open]>summary{margin-bottom:.75rem}.settings-tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(8.5rem,1fr));gap:.5rem;
|
|
15881
|
+
const THEME_CONTROLS_CSS = `.task-repo select{width:100%;min-height:2.75rem;font-size:1rem}.task-repo-add{margin:.35rem .1rem .5rem}.task-repo-add a{display:inline-flex;align-items:center;min-height:2.25rem}details.result-request-open.result-request-form>summary{border:0;background:transparent;padding:.5rem 0;min-height:2.75rem;font-weight:600;display:list-item;list-style:revert}details.result-request-open.result-request-form>summary::-webkit-details-marker{display:revert}form.js-autosave button[type=submit]{display:none}.provider-row{border-bottom:1px solid var(--so-line);padding:.35rem 0}.provider-row:first-of-type{border-top:1px solid var(--so-line)}.provider-head{display:flex;align-items:center;gap:.75rem;margin:.4rem 0 0}.provider-status{display:inline-flex;align-items:center;gap:.4rem;color:var(--so-muted);font-size:.875rem}.provider-status i{width:.5rem;height:.5rem;border-radius:50%;background:var(--so-muted)}.provider-status--ok i{background:var(--so-success)}.provider-status--warn i{background:var(--so-attention)}.provider-status--off i{background:transparent;border:1.5px solid var(--so-muted)}details.provider-manage>summary{cursor:pointer;color:var(--so-accent-text);font-size:.875rem;min-height:2.5rem;display:list-item;padding-block:.5rem}.card.props .row{display:grid;gap:.1rem;margin:0 0 .75rem}.card.props .row>.meta{display:block;font-size:.75rem}.card.props .row>.meta::first-letter{text-transform:uppercase}.card.props .row>.mono{font-family:var(--font-sans);font-size:.875rem}.card.props .row>.mono .seal{font-family:var(--font-mono);font-size:.8125rem}details.evidence-files{margin:1rem 0}details.evidence-files>summary{cursor:pointer;min-height:2.75rem;display:list-item;padding-block:.7rem;font-weight:600}details.evidence-files ul{list-style:none;margin:0;padding:0}details.evidence-files li{display:flex;justify-content:space-between;gap:1rem;padding:.5rem 0;border-bottom:1px solid var(--so-line)}.result-action .result-feedback-link{display:inline-flex;align-items:center;min-height:2.5rem;padding:.5rem 1rem;border:1px solid var(--so-input-line);border-radius:.5rem;background:var(--so-paper);color:var(--so-ink);font-weight:600;text-decoration:none}@media(hover:hover) and (pointer:fine){.result-action .result-feedback-link:hover{background:var(--so-raised)}}.so-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.verdict{margin:.5rem 0 .75rem}.verdict-chips{display:flex;flex-wrap:wrap;gap:.4rem;list-style:none;padding:0;margin:0}.verdict-chip{display:inline-flex;align-items:center;gap:.3rem;min-height:1.75rem;padding:.2rem .65rem;border-radius:999px;font-size:.8125rem;font-weight:600;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}.verdict-chip svg{width:.9rem;height:.9rem}.verdict-chip--success{background:var(--so-success-soft);color:var(--so-success)}.verdict-chip--danger{background:var(--so-danger-soft);color:var(--so-danger)}.verdict-chip--warning{background:var(--so-warning-soft);color:var(--so-warning)}.verdict-chip--info{background:var(--so-info-soft);color:var(--so-info)}.verdict-by{margin:.4rem 0 0}details.result-request-open{margin:.5rem 0}details.result-request-open>summary{display:inline-flex;align-items:center;min-height:2.5rem;padding:.5rem 1rem;border:1px solid var(--so-input-line);border-radius:.5rem;background:var(--so-paper);color:var(--so-ink);font-weight:600;cursor:pointer;list-style:none}details.result-request-open>summary::-webkit-details-marker{display:none}details.result-request-open[open]>summary{margin-bottom:.75rem}.settings-tiles{display:grid;gap:1.25rem;margin:0 0 2rem}.settings-tiles h2{margin:0 0 .5rem;font-size:.875rem;font-weight:600;color:var(--so-muted)}.settings-tiles section>div{display:grid;grid-template-columns:repeat(auto-fill,minmax(8.5rem,1fr));gap:.5rem}.settings-tiles a>span{display:grid;gap:.1rem;min-width:0}.settings-tiles .provider-status{font-weight:400;font-size:.8125rem}.settings-tiles a{display:flex;align-items:center;gap:.6rem;min-height:3rem;padding:.65rem .8rem;border:1px solid var(--so-line);border-radius:.625rem;background:var(--so-paper);color:var(--so-ink);text-decoration:none;font-weight:550;font-size:.875rem}@media(hover:hover) and (pointer:fine){.settings-tiles a:hover{border-color:var(--so-input-line);background:var(--so-raised)}}.settings-tiles svg{width:1.1rem;height:1.1rem;flex-shrink:0;color:var(--so-accent-text)}details.settings-more{margin:.25rem 0 1.25rem}details.settings-more>summary{cursor:pointer;min-height:2.75rem;display:list-item;padding-block:.7rem;font-weight:550}details.settings-more>summary .meta{font-weight:400;margin-left:.35rem}.settings-changed{margin-top:-.25rem}.appearance{margin:0 0 28px}.appearance h2{margin:0 0 10px}.theme-switch{display:inline-flex;flex-wrap:nowrap;max-width:100%;gap:4px;padding:4px;margin:0;border:1px solid var(--so-line);border-radius:10px;background:var(--so-raised)}.theme-switch .theme-choice,.so-native-region .theme-switch .theme-choice{flex:1 1 0;width:auto;white-space:nowrap;min-height:40px;padding:8px 16px;border:0;border-radius:7px;background:transparent;color:var(--so-muted);font:inherit;font-weight:550;box-shadow:none;cursor:pointer}@media(hover:hover) and (pointer:fine){.theme-switch .theme-choice:hover{color:var(--so-ink)}}.theme-switch .theme-choice[aria-pressed="true"]{background:var(--so-paper);color:var(--so-ink);box-shadow:0 1px 2px rgb(0 0 0 / .1)}.appearance .meta{margin:8px 0 0}@media(max-width:600px){.theme-switch .theme-choice{min-height:44px}}.update-notes{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;max-height:18rem;overflow:auto}`;
|
|
15882
15882
|
/** The page CSS this module writes itself (not the imported modules'), for the stylesheet contract tests. */
|
|
15883
15883
|
export const PAGE_CSS = STYLE + THEME_CONTROLS_CSS;
|
|
15884
15884
|
/** The Inbox tabs (console v2): a segmented track of real links; the dot marks a tab with something new, on phones only. */
|
|
@@ -23920,6 +23920,10 @@ function capsPage(chrome, caps, gaps, repo, now) {
|
|
|
23920
23920
|
`<p class="meta">Read-only here: checks are shell commands you wrote, and a web button that runs shell would need its own security review</p>`,
|
|
23921
23921
|
].join("\n"), { chrome });
|
|
23922
23922
|
}
|
|
23923
|
+
/** Whether the bot's saved delivery state reports a problem (no new check runs). */
|
|
23924
|
+
function telegramTrouble(store, bot) {
|
|
23925
|
+
return bot !== null && (store.telegramPush(bot.botId)?.problem ?? null) !== null;
|
|
23926
|
+
}
|
|
23923
23927
|
/** v98: how the bot's messages reach Toolroll, in words: pushed to the public address, or asked for. */
|
|
23924
23928
|
function telegramDeliveryWords(store, bot) {
|
|
23925
23929
|
if (bot === null)
|
|
@@ -23936,7 +23940,7 @@ function notificationProjects(store, account) {
|
|
|
23936
23940
|
.map(one => ({ repo: one.path, name: one.name, muted: muted.has(one.path) }))
|
|
23937
23941
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
23938
23942
|
}
|
|
23939
|
-
function settingsPage(chrome, existing, hasEnv, csrf, problem, messaging = null, push = null, providerKeys = null, digest = null, permissionDefault = null, qualityDefault = null, email = null, telegramDelivery = null, workers = null, updates = null, firstResult = null, chatNotices = null) {
|
|
23943
|
+
function settingsPage(chrome, existing, hasEnv, csrf, problem, messaging = null, push = null, providerKeys = null, digest = null, permissionDefault = null, qualityDefault = null, email = null, telegramDelivery = null, workers = null, updates = null, firstResult = null, chatNotices = null, telegramFailing = false) {
|
|
23940
23944
|
const permissionCard = permissionDefault === null
|
|
23941
23945
|
? ""
|
|
23942
23946
|
: [
|
|
@@ -24132,7 +24136,7 @@ function settingsPage(chrome, existing, hasEnv, csrf, problem, messaging = null,
|
|
|
24132
24136
|
const view = {
|
|
24133
24137
|
kind: "settings",
|
|
24134
24138
|
said: problem,
|
|
24135
|
-
|
|
24139
|
+
groups: settingsGroups(messaging, telegramFailing),
|
|
24136
24140
|
theme,
|
|
24137
24141
|
accent: requestContext.getStore()?.accent ?? DEFAULT_ACCENT,
|
|
24138
24142
|
accentPresets: ACCENT_PRESETS,
|
|
@@ -24165,7 +24169,7 @@ function settingsPage(chrome, existing, hasEnv, csrf, problem, messaging = null,
|
|
|
24165
24169
|
};
|
|
24166
24170
|
return screen("Settings", [
|
|
24167
24171
|
"<h1>Settings</h1>",
|
|
24168
|
-
settingsTiles(),
|
|
24172
|
+
settingsTiles(view.groups),
|
|
24169
24173
|
appearanceCard(csrf),
|
|
24170
24174
|
permissionCard,
|
|
24171
24175
|
qualityCard,
|
|
@@ -24264,37 +24268,70 @@ async function latestReleaseFor(latest) {
|
|
|
24264
24268
|
latestSeen = { at: Date.now(), value };
|
|
24265
24269
|
return value;
|
|
24266
24270
|
}
|
|
24267
|
-
/** Settings destinations
|
|
24268
|
-
function settingsTiles() {
|
|
24269
|
-
|
|
24270
|
-
|
|
24271
|
-
}
|
|
24272
|
-
|
|
24273
|
-
|
|
24274
|
-
["
|
|
24275
|
-
|
|
24276
|
-
|
|
24277
|
-
|
|
24278
|
-
|
|
24279
|
-
|
|
24280
|
-
|
|
24281
|
-
|
|
24282
|
-
["
|
|
24283
|
-
|
|
24284
|
-
|
|
24285
|
-
|
|
24286
|
-
["
|
|
24287
|
-
|
|
24288
|
-
|
|
24289
|
-
|
|
24290
|
-
|
|
24291
|
-
|
|
24292
|
-
["
|
|
24293
|
-
|
|
24294
|
-
|
|
24295
|
-
|
|
24271
|
+
/** Settings destinations under short headings: an icon and a name each, and a chat app's state. */
|
|
24272
|
+
function settingsTiles(groups) {
|
|
24273
|
+
return `<nav class="settings-tiles" aria-label="Settings sections">${groups.map(group => `<section aria-label="${escape(group.title)}"><h2>${escape(group.title)}</h2><div>${group.tiles.map(tile => `<a href="${escape(tile.href)}">${strokeIcon(SETTINGS_TILE_ICONS.get(tile.href) ?? "")}<span>${escape(tile.label)}${tile.status === undefined ? "" :
|
|
24274
|
+
`<span class="provider-status provider-status--${tile.status.tone}"><i aria-hidden="true"></i>${escape(tile.status.words)}</span>`}</span></a>`).join("")}</div></section>`).join("")}</nav>`;
|
|
24275
|
+
}
|
|
24276
|
+
/** Each destination once, in order: a group's heading, then its [href, label, icon] tiles. */
|
|
24277
|
+
const SETTINGS_GROUPS = [
|
|
24278
|
+
["Agents", [
|
|
24279
|
+
["/settings/lead", "Lead", `<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><path d="M8 9h8M8 13h5"/>`],
|
|
24280
|
+
["/settings/models", "Models", `<rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M9 2v2M15 2v2M9 20v2M15 20v2M2 9h2M2 15h2M20 9h2M20 15h2"/>`],
|
|
24281
|
+
["/settings/skills", "Skills", `<path d="m12 3 1.9 5.8L20 10l-5 3.6L16.8 20 12 16.4 7.2 20 9 13.6 4 10l6.1-1.2z"/>`],
|
|
24282
|
+
["/settings/tools", "Tools", `<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>`],
|
|
24283
|
+
["/settings/knowledge", "Knowledge", `<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20V3H6.5A2.5 2.5 0 0 0 4 5.5z"/><path d="M4 19.5A2.5 2.5 0 0 0 6.5 22H20v-5"/>`],
|
|
24284
|
+
["/settings/learning", "Learning", `<path d="M3 3v18h18"/><path d="m7 15 4-4 3 3 5-6"/>`],
|
|
24285
|
+
]],
|
|
24286
|
+
["Automation", [
|
|
24287
|
+
["/settings/flows", "Flows", `<rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="14" width="7" height="7" rx="1.5"/><path d="M10 6.5h4a3 3 0 0 1 3 3V14"/>`],
|
|
24288
|
+
["/settings/integrations", "Integrations", `<path d="M9 2v6M15 2v6"/><path d="M6 8h12v4a6 6 0 0 1-12 0z"/><path d="M12 18v4"/>`],
|
|
24289
|
+
]],
|
|
24290
|
+
["Chat apps", [
|
|
24291
|
+
["/settings/telegram", "Telegram", `<path d="m22 2-7 20-4-9-9-4z"/><path d="M22 2 11 13"/>`],
|
|
24292
|
+
["/settings/slack", "Slack", `<path d="M4 9h16M4 15h16M10 3 8 21M16 3l-2 18"/>`],
|
|
24293
|
+
["/settings/discord", "Discord", `<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>`],
|
|
24294
|
+
["/settings/teams", "Teams", `<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.9M16 3.1a4 4 0 0 1 0 7.8"/>`],
|
|
24295
|
+
]],
|
|
24296
|
+
["Access and rules", [
|
|
24297
|
+
["/settings/sign-in", "Sign-in", `<rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>`],
|
|
24298
|
+
["/settings/sessions", "Sessions & tokens", `<circle cx="7.5" cy="15.5" r="5.5"/><path d="m21 2-9.6 9.6M15.5 7.5l3 3L22 7l-3-3"/>`],
|
|
24299
|
+
["/settings/project", "Project", `<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>`],
|
|
24300
|
+
["/settings/policy", "Policy", `<path d="M9 12l2 2 4-4"/><rect x="4" y="3" width="16" height="18" rx="2"/>`],
|
|
24301
|
+
["/settings/approval", "Approval rules", `<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="m9 12 2 2 4-4"/>`],
|
|
24302
|
+
]],
|
|
24303
|
+
["System", [
|
|
24304
|
+
["/settings/monitoring", "Monitoring", `<path d="M22 12h-4l-3 9L9 3l-3 9H2"/>`],
|
|
24305
|
+
["/settings/retention", "Retention", `<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>`],
|
|
24306
|
+
["/settings/storage", "Storage", `<path d="M22 12H2"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/><path d="M6 16h.01M10 16h.01"/>`],
|
|
24307
|
+
["/settings/updates", "Updates", `<path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/>`],
|
|
24308
|
+
["/settings/backups", "Backups", `<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14c0 1.7 4 3 9 3s9-1.3 9-3V5"/><path d="M3 12c0 1.7 4 3 9 3s9-1.3 9-3"/>`],
|
|
24309
|
+
["/settings/data", "Data", `<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m7 10 5 5 5-5"/><path d="M12 15V3"/>`],
|
|
24310
|
+
]],
|
|
24296
24311
|
];
|
|
24297
|
-
const
|
|
24312
|
+
const SETTINGS_TILE_ICONS = new Map(SETTINGS_GROUPS.flatMap(([, tiles]) => tiles.map(([href, , icon]) => [href, icon])));
|
|
24313
|
+
const CHAT_APP_TILES = { "/settings/telegram": "telegram", "/settings/slack": "slack", "/settings/discord": "discord", "/settings/teams": "teams" };
|
|
24314
|
+
/**
|
|
24315
|
+
* The settings groups, with each chat app's state from what the server already holds: not set up,
|
|
24316
|
+
* connected, or getting alerts (only when that service was chosen, or is the only one).
|
|
24317
|
+
* A Telegram bot whose saved delivery state reports a problem says so instead. With no config folder
|
|
24318
|
+
* the state is unknown, so the tiles carry none.
|
|
24319
|
+
*/
|
|
24320
|
+
export function settingsGroups(messaging, telegramFailing = false) {
|
|
24321
|
+
return SETTINGS_GROUPS.map(([title, tiles]) => ({
|
|
24322
|
+
title,
|
|
24323
|
+
tiles: tiles.map(([href, label]) => {
|
|
24324
|
+
const app = CHAT_APP_TILES[href];
|
|
24325
|
+
if (app === undefined || messaging === null)
|
|
24326
|
+
return { href, label };
|
|
24327
|
+
if (!messaging.configured.includes(app))
|
|
24328
|
+
return { href, label, status: { tone: "off", words: "Not set up" } };
|
|
24329
|
+
if (app === "telegram" && telegramFailing)
|
|
24330
|
+
return { href, label, status: { tone: "warn", words: "Has a problem" } };
|
|
24331
|
+
return { href, label, status: { tone: "ok", words: messaging.channel === app && !messaging.implicit ? "Gets alerts" : "Connected" } };
|
|
24332
|
+
}),
|
|
24333
|
+
}));
|
|
24334
|
+
}
|
|
24298
24335
|
/** Light, dark or the device's choice, one tap each. Per browser (a cookie). */
|
|
24299
24336
|
function appearanceCard(csrf) {
|
|
24300
24337
|
if (csrf === "")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolroll",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.24",
|
|
4
4
|
"description": "A control plane for unattended coding agents — queue tasks, walk away, come back to pull requests. Agents build in leased worktrees, never touch your default branch, and interrupt you only for decisions that need a human.",
|
|
5
5
|
"directories": {
|
|
6
6
|
"doc": "docs"
|