toolroll 0.9.54 → 0.9.56
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 +19 -0
- package/README.md +29 -12
- package/dist/action-ledger.d.ts +2 -4
- package/dist/action-ledger.js +2 -10
- package/dist/agent-onboard.js +4 -1
- package/dist/approval-policy.d.ts +5 -5
- package/dist/approval-policy.js +4 -4
- package/dist/approval-rules-ui.d.ts +3 -2
- package/dist/approval-rules-ui.js +17 -22
- package/dist/assignment-ui.d.ts +3 -2
- package/dist/assignment-ui.js +4 -11
- package/dist/backup-ui.d.ts +2 -1
- package/dist/backup-ui.js +16 -27
- package/dist/brand-mark.d.ts +3 -2
- package/dist/brand-mark.js +4 -4
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +25 -25
- package/dist/browser-shell.d.ts +2 -1
- package/dist/browser-shell.js +9 -9
- package/dist/browser-workspace.d.ts +14 -15
- package/dist/browser-workspace.js +0 -3
- package/dist/budget-alerts.js +3 -3
- package/dist/chat-actions.d.ts +23 -18
- package/dist/chat-actions.js +110 -88
- package/dist/chat-ask.d.ts +2 -2
- package/dist/chat-ask.js +5 -5
- package/dist/chat-channel.d.ts +15 -15
- package/dist/chat-channel.js +20 -20
- package/dist/chat-controls.d.ts +0 -4
- package/dist/chat-controls.js +0 -1
- package/dist/chat-core.js +1 -1
- package/dist/chat-delivery-state.js +2 -2
- package/dist/chat-delivery.d.ts +2 -2
- package/dist/chat-delivery.js +27 -34
- package/dist/chat-flow.js +3 -3
- package/dist/chat-messages.d.ts +1 -1
- package/dist/chat-messages.js +4 -4
- package/dist/chat-migration.d.ts +1 -1
- package/dist/chat-migration.js +11 -11
- package/dist/chat-polish.d.ts +5 -4
- package/dist/chat-polish.js +9 -10
- package/dist/chat-rooms.js +3 -3
- package/dist/chat-warmth.d.ts +2 -2
- package/dist/check-levels-ui.d.ts +2 -1
- package/dist/check-levels-ui.js +26 -53
- package/dist/cli.d.ts +3 -1
- package/dist/cli.js +15 -10
- package/dist/coding-shipping-ui.d.ts +2 -1
- package/dist/coding-shipping-ui.js +6 -6
- package/dist/coding-ui.d.ts +3 -1
- package/dist/coding-ui.js +30 -29
- package/dist/contracts/chat-actions.d.ts +32 -27
- package/dist/contracts/chat-actions.js +29 -11
- package/dist/contracts/chat-content.d.ts +1 -1
- package/dist/contracts/chat-content.js +1 -1
- package/dist/contracts/chat-tables.js +4 -4
- package/dist/contracts/cli.d.ts +1 -3
- package/dist/contracts/console-api.d.ts +7 -7
- package/dist/contracts/console-api.js +13 -12
- package/dist/contracts/flow-propose.d.ts +3 -3
- package/dist/contracts/flow.d.ts +132 -125
- package/dist/contracts/flow.js +27 -12
- package/dist/contracts/health.d.ts +1 -3
- package/dist/contracts/lead-context.d.ts +1 -1
- package/dist/contracts/lead-context.js +2 -2
- package/dist/contracts/lead-tools.d.ts +20 -18
- package/dist/contracts/lead-tools.js +15 -15
- package/dist/contracts/stage-output.d.ts +1 -1
- package/dist/contracts/stage-output.js +1 -1
- package/dist/contracts/store-json.d.ts +23 -22
- package/dist/contracts/store-json.js +17 -17
- package/dist/contracts/{teammate-turn.d.ts → subagent-turn.d.ts} +5 -5
- package/dist/contracts/{teammate-turn.js → subagent-turn.js} +7 -7
- package/dist/control-ui.d.ts +5 -4
- package/dist/control-ui.js +9 -34
- package/dist/converse.d.ts +23 -23
- package/dist/converse.js +28 -28
- package/dist/coordinator-proposals.d.ts +2 -2
- package/dist/coordinator-proposals.js +1 -1
- package/dist/coordinator.js +1 -1
- package/dist/credentials-ui.d.ts +5 -4
- package/dist/credentials-ui.js +23 -24
- package/dist/demo-chat.d.ts +3 -3
- package/dist/demo-chat.js +29 -76
- package/dist/deprecations.d.ts +12 -0
- package/dist/deprecations.js +20 -0
- package/dist/desktop-update-gate.js +8 -4
- package/dist/desktop-update.js +6 -1
- package/dist/discord-chat.js +6 -6
- package/dist/discord-settings.d.ts +3 -2
- package/dist/discord-settings.js +17 -42
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +1 -1
- package/dist/envelope.js +10 -1
- package/dist/evidence-pack.d.ts +2 -1
- package/dist/evidence-pack.js +45 -49
- package/dist/export-ui.d.ts +7 -2
- package/dist/export-ui.js +4 -10
- package/dist/export.js +7 -7
- package/dist/flow-engine.d.ts +2 -2
- package/dist/flow-engine.js +21 -21
- package/dist/flow-gallery-ui.d.ts +4 -3
- package/dist/flow-gallery-ui.js +28 -43
- package/dist/flow-insights.d.ts +1 -1
- package/dist/flow-share.js +13 -8
- package/dist/flow-starters-ui.d.ts +2 -1
- package/dist/flow-starters-ui.js +12 -15
- package/dist/flow-steps.d.ts +5 -5
- package/dist/flow-steps.js +19 -19
- package/dist/flow-triggers.d.ts +2 -1
- package/dist/flow-triggers.js +17 -15
- package/dist/flows-cli.js +1 -1
- package/dist/flows-ui.d.ts +4 -3
- package/dist/flows-ui.js +38 -49
- package/dist/flows.js +21 -20
- package/dist/guides.js +112 -6
- package/dist/html.d.ts +76 -0
- package/dist/html.js +173 -0
- package/dist/integrations-ui.d.ts +2 -1
- package/dist/integrations-ui.js +19 -23
- package/dist/invoke.js +1 -1
- package/dist/kits-ui.d.ts +5 -4
- package/dist/kits-ui.js +22 -24
- package/dist/kits.d.ts +12 -12
- package/dist/kits.js +31 -31
- package/dist/knowledge-ui.d.ts +6 -5
- package/dist/knowledge-ui.js +26 -25
- package/dist/{mate-cli.d.ts → lead-cli.d.ts} +11 -11
- package/dist/{mate-cli.js → lead-cli.js} +38 -38
- package/dist/lead-commitments.js +4 -4
- package/dist/lead-context.d.ts +12 -2
- package/dist/lead-context.js +15 -17
- package/dist/{mate-contract.d.ts → lead-contract.d.ts} +3 -3
- package/dist/{mate-contract.js → lead-contract.js} +7 -6
- package/dist/{mate-doors.d.ts → lead-doors.d.ts} +6 -6
- package/dist/{mate-doors.js → lead-doors.js} +24 -24
- package/dist/lead-follow.d.ts +5 -5
- package/dist/lead-follow.js +9 -9
- package/dist/lead-people.d.ts +5 -5
- package/dist/lead-people.js +14 -14
- package/dist/{mate-progress.d.ts → lead-progress.d.ts} +9 -9
- package/dist/{mate-progress.js → lead-progress.js} +3 -3
- package/dist/{mate-tools.d.ts → lead-tools.d.ts} +19 -19
- package/dist/{mate-tools.js → lead-tools.js} +109 -101
- package/dist/{mate.d.ts → lead.d.ts} +27 -27
- package/dist/{mate.js → lead.js} +102 -102
- package/dist/ledger-view.d.ts +2 -1
- package/dist/ledger-view.js +27 -29
- package/dist/limits-ui.d.ts +3 -2
- package/dist/limits-ui.js +8 -8
- package/dist/live-bus.d.ts +50 -8
- package/dist/live-bus.js +133 -50
- package/dist/mcp-connect.d.ts +1 -1
- package/dist/mcp-connect.js +3 -3
- package/dist/mcp-core.js +1 -1
- package/dist/mcp-oauth.js +35 -36
- package/dist/memory-pass.d.ts +2 -2
- package/dist/memory-pass.js +7 -7
- package/dist/models-ui.d.ts +2 -1
- package/dist/models-ui.js +25 -35
- package/dist/monitoring-ui.d.ts +4 -3
- package/dist/monitoring-ui.js +13 -26
- package/dist/notification-rows.d.ts +2 -2
- package/dist/openrouter-models.d.ts +2 -1
- package/dist/openrouter-models.js +5 -9
- package/dist/operate.d.ts +3 -3
- package/dist/operate.js +46 -41
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +13 -13
- package/dist/policy-ui.d.ts +3 -2
- package/dist/policy-ui.js +17 -23
- package/dist/policy.d.ts +1 -1
- package/dist/principal.d.ts +1 -1
- package/dist/principal.js +2 -2
- package/dist/project-delete-ui.d.ts +4 -3
- package/dist/project-delete-ui.js +16 -28
- package/dist/project-delete.d.ts +1 -1
- package/dist/project-delete.js +26 -26
- package/dist/project-memory.js +1 -1
- package/dist/project-tools.d.ts +1 -1
- package/dist/project-tools.js +1 -1
- package/dist/pull-request-ui.d.ts +2 -1
- package/dist/pull-request-ui.js +17 -32
- package/dist/recipe-ui.d.ts +8 -7
- package/dist/recipe-ui.js +39 -32
- package/dist/release-adapters.d.ts +60 -0
- package/dist/release-adapters.js +435 -0
- package/dist/release-cli.d.ts +24 -0
- package/dist/release-cli.js +181 -0
- package/dist/release-gate.d.ts +80 -0
- package/dist/release-gate.js +150 -0
- package/dist/release-links.d.ts +29 -0
- package/dist/release-links.js +102 -0
- package/dist/release.d.ts +331 -0
- package/dist/release.js +550 -0
- package/dist/reply-shape.d.ts +2 -1
- package/dist/reply-shape.js +5 -5
- package/dist/repository-context-ui.d.ts +2 -1
- package/dist/repository-context-ui.js +2 -7
- package/dist/request-budget-ui.d.ts +2 -1
- package/dist/request-budget-ui.js +16 -16
- package/dist/result-review.d.ts +2 -3
- package/dist/result-review.js +3 -9
- package/dist/retention-ui.d.ts +7 -1
- package/dist/retention-ui.js +7 -11
- package/dist/retention.js +4 -4
- package/dist/scope.d.ts +2 -2
- package/dist/scout-report.d.ts +1 -1
- package/dist/scout-report.js +1 -1
- package/dist/serve.d.ts +11 -2
- package/dist/serve.js +105 -99
- package/dist/server/chat.d.ts +7 -10
- package/dist/server/chat.js +984 -1021
- package/dist/server/chrome.d.ts +291 -0
- package/dist/server/chrome.js +747 -0
- package/dist/server/console.css +2819 -0
- package/dist/server/flows.d.ts +2 -6
- package/dist/server/flows.js +854 -773
- package/dist/server/guards.d.ts +1 -1
- package/dist/server/guards.js +8 -5
- package/dist/server/handler-context.d.ts +1 -1
- package/dist/server/handler-context.js +1 -1
- package/dist/server/handler-registry.d.ts +8 -6
- package/dist/server/handler-registry.js +14 -2
- package/dist/server/http.d.ts +274 -0
- package/dist/server/http.js +239 -0
- package/dist/server/live.d.ts +34 -0
- package/dist/server/live.js +309 -0
- package/dist/server/pages.d.ts +2 -6
- package/dist/server/pages.js +808 -789
- package/dist/server/people-tokens.d.ts +1 -6
- package/dist/server/people-tokens.js +581 -573
- package/dist/server/remote.d.ts +4 -7
- package/dist/server/remote.js +39 -70
- package/dist/server/render-chat.d.ts +402 -0
- package/dist/server/render-chat.js +927 -0
- package/dist/server/render-pages.d.ts +535 -0
- package/dist/server/render-pages.js +1277 -0
- package/dist/server/render-people.d.ts +32 -0
- package/dist/server/render-people.js +121 -0
- package/dist/server/render-results.d.ts +744 -0
- package/dist/server/render-results.js +2237 -0
- package/dist/server/render-settings.d.ts +154 -0
- package/dist/server/render-settings.js +580 -0
- package/dist/server/render-tasks.d.ts +632 -0
- package/dist/server/render-tasks.js +2345 -0
- package/dist/server/request-context.d.ts +46 -0
- package/dist/server/request-context.js +17 -0
- package/dist/server/route-table.d.ts +25 -3
- package/dist/server/route-table.js +167 -77
- package/dist/server/runtime.d.ts +28 -20
- package/dist/server/runtime.js +7 -1
- package/dist/server/session.d.ts +138 -0
- package/dist/server/session.js +94 -0
- package/dist/server/settings.d.ts +1 -5
- package/dist/server/settings.js +2186 -2121
- package/dist/server/task-views.d.ts +11 -4
- package/dist/server/task-views.js +26 -22
- package/dist/server/tasks.d.ts +9 -9
- package/dist/server/tasks.js +1489 -1420
- package/dist/server-telemetry.d.ts +4 -3
- package/dist/server-telemetry.js +4 -8
- package/dist/setup-guide.d.ts +2 -2
- package/dist/skills-ui.d.ts +4 -3
- package/dist/skills-ui.js +14 -17
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +2 -1
- package/dist/slack-chat.d.ts +2 -2
- package/dist/slack-chat.js +6 -6
- package/dist/slack-settings.d.ts +3 -2
- package/dist/slack-settings.js +17 -42
- package/dist/spend-ui.d.ts +5 -4
- package/dist/spend-ui.js +17 -40
- package/dist/spend.d.ts +14 -14
- package/dist/spend.js +31 -31
- package/dist/sso-ui.d.ts +3 -2
- package/dist/sso-ui.js +26 -27
- package/dist/storage-ui.d.ts +2 -1
- package/dist/storage-ui.js +14 -33
- package/dist/store-baseline.d.ts +19 -0
- package/dist/store-baseline.js +2873 -0
- package/dist/store.d.ts +197 -249
- package/dist/store.js +747 -3084
- package/dist/subagent-admin.d.ts +53 -0
- package/dist/{teammate-admin.js → subagent-admin.js} +37 -37
- package/dist/{teammate-desk.d.ts → subagent-desk.d.ts} +22 -23
- package/dist/{teammate-desk.js → subagent-desk.js} +26 -35
- package/dist/{teammate-memory.d.ts → subagent-memory.d.ts} +17 -17
- package/dist/{teammate-memory.js → subagent-memory.js} +41 -41
- package/dist/{teammate-question.d.ts → subagent-question.d.ts} +6 -6
- package/dist/{teammate-question.js → subagent-question.js} +17 -17
- package/dist/{teammate-tools.d.ts → subagent-tools.d.ts} +18 -18
- package/dist/{teammate-tools.js → subagent-tools.js} +36 -36
- package/dist/{teammate-week.d.ts → subagent-week.d.ts} +10 -10
- package/dist/{teammate-week.js → subagent-week.js} +23 -23
- package/dist/{teammate-work.d.ts → subagent-work.d.ts} +21 -21
- package/dist/{teammate-work.js → subagent-work.js} +50 -50
- package/dist/subagents-ui.d.ts +22 -0
- package/dist/subagents-ui.js +137 -0
- package/dist/{teammates.d.ts → subagents.d.ts} +11 -11
- package/dist/{teammates.js → subagents.js} +21 -21
- package/dist/subscription-chat.d.ts +13 -13
- package/dist/subscription-chat.js +19 -19
- package/dist/surface.d.ts +19 -2
- package/dist/surface.js +20 -33
- package/dist/task-composer.d.ts +2 -1
- package/dist/task-composer.js +7 -7
- package/dist/task-status.d.ts +4 -3
- package/dist/task-status.js +15 -16
- package/dist/team-cli.d.ts +1 -0
- package/dist/team-cli.js +14 -2
- package/dist/team-http.d.ts +5 -9
- package/dist/team-http.js +5 -63
- package/dist/team-leads.js +13 -13
- package/dist/team-runtime.d.ts +2 -2
- package/dist/team-runtime.js +8 -8
- package/dist/team-ui.d.ts +2 -1
- package/dist/team-ui.js +2 -5
- package/dist/teams-chat.js +6 -6
- package/dist/teams-settings.d.ts +3 -2
- package/dist/teams-settings.js +20 -31
- package/dist/telegram-flow.d.ts +3 -3
- package/dist/telegram-flow.js +3 -3
- package/dist/{telegram-mate.d.ts → telegram-lead.d.ts} +5 -5
- package/dist/{telegram-mate.js → telegram-lead.js} +27 -27
- package/dist/telegram-settings.d.ts +3 -2
- package/dist/telegram-settings.js +14 -25
- package/dist/telegram-status.js +1 -1
- package/dist/telegram-team.d.ts +1 -1
- package/dist/telegram-team.js +5 -5
- package/dist/telegram.d.ts +1 -1
- package/dist/telegram.js +9 -30
- package/dist/text-limits.d.ts +18 -18
- package/dist/text-limits.js +18 -18
- package/dist/toolroll-update-ui.d.ts +3 -2
- package/dist/toolroll-update-ui.js +35 -39
- package/dist/toolroll-update.d.ts +8 -0
- package/dist/toolroll-update.js +45 -8
- package/dist/tools-ui.d.ts +5 -2
- package/dist/tools-ui.js +31 -31
- package/dist/when-html.d.ts +11 -3
- package/dist/when-html.js +5 -6
- package/dist/workspace-ui.d.ts +4 -2
- package/dist/workspace-ui.js +10 -10
- package/package.json +1 -2
- package/dist/server/shared.d.ts +0 -3151
- package/dist/server/shared.js +0 -12001
- package/dist/teammate-admin.d.ts +0 -53
- package/dist/teammates-ui.d.ts +0 -20
- package/dist/teammates-ui.js +0 -166
package/dist/telegram-team.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { renderReply, shapeReplyParts } from "./reply-shape.js";
|
|
2
2
|
import { TeamLeads } from "./team-leads.js";
|
|
3
3
|
import { proposalPreview, tooLongText } from "./chat-channel.js";
|
|
4
|
-
import { PART_CAP, mintCardTokens, phoneLinkButton, splitParts } from "./telegram-
|
|
5
|
-
import {
|
|
4
|
+
import { PART_CAP, mintCardTokens, phoneLinkButton, splitParts } from "./telegram-lead.js";
|
|
5
|
+
import { LEAD_MESSAGE_MAX_CHARS } from "./lead.js";
|
|
6
6
|
import { phoneText } from "./telegram-status.js";
|
|
7
7
|
/** `/team` lists, `/team <n>` chooses, `/team off` (or `private`) leaves. Any other slash text is not ours. */
|
|
8
8
|
export function teamCommand(text) {
|
|
@@ -172,7 +172,7 @@ export function applyTeamInbound(input) {
|
|
|
172
172
|
report.ignored++;
|
|
173
173
|
return true;
|
|
174
174
|
}
|
|
175
|
-
if (trimmed.length >
|
|
175
|
+
if (trimmed.length > LEAD_MESSAGE_MAX_CHARS) {
|
|
176
176
|
say(chatId, tooLongText(trimmed.length));
|
|
177
177
|
report.chatRefused = (report.chatRefused ?? 0) + 1;
|
|
178
178
|
return true;
|
|
@@ -255,7 +255,7 @@ export async function deliverTeamChats(store, botId, transport, clock, report, p
|
|
|
255
255
|
const row = conversationRow(store, chat.conversation);
|
|
256
256
|
if (row === null)
|
|
257
257
|
continue;
|
|
258
|
-
const pending = store.handle.prepare(`SELECT m.id, m.role, m.text, m.turn, q.author, q.request_id, q.status FROM
|
|
258
|
+
const pending = store.handle.prepare(`SELECT m.id, m.role, m.text, m.turn, q.author, q.request_id, q.status FROM lead_message m
|
|
259
259
|
LEFT JOIN team_message q ON q.message = m.id WHERE m.thread = ? AND m.id > ? ORDER BY m.id LIMIT 20`).all(row.thread, chat.cursor);
|
|
260
260
|
for (const message of pending) {
|
|
261
261
|
const id = Number(message["id"]);
|
|
@@ -279,7 +279,7 @@ export async function deliverTeamChats(store, botId, transport, clock, report, p
|
|
|
279
279
|
if (role === "assistant" && message["turn"] !== null) {
|
|
280
280
|
const turn = Number(message["turn"]);
|
|
281
281
|
const cardBinding = cardBindingFor(store, botId, chat, turn);
|
|
282
|
-
for (const proposal of store.
|
|
282
|
+
for (const proposal of store.listLeadProposals(row.thread, ["pending"]).filter(one => one.turn === turn)) {
|
|
283
283
|
const enrolled = await access();
|
|
284
284
|
if (enrolled === null) {
|
|
285
285
|
complete = false;
|
package/dist/telegram.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* are one command.
|
|
20
20
|
*/
|
|
21
21
|
import { type Store, type Notification } from "./store.js";
|
|
22
|
-
import { type TelegramConversationOptions } from "./telegram-
|
|
22
|
+
import { type TelegramConversationOptions } from "./telegram-lead.js";
|
|
23
23
|
/** Read the enrolled project list on demand. No callback means no task data,
|
|
24
24
|
* never an implicit all-database ceiling. Shared by pass and embedded follower. */
|
|
25
25
|
export type TelegramReadProjects = () => Promise<readonly string[]>;
|
package/dist/telegram.js
CHANGED
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
* BotFather token plus `bridge telegram unpair` is the recovery, and both
|
|
19
19
|
* are one command.
|
|
20
20
|
*/
|
|
21
|
-
import { applyTelegramQuestionReply, applyTelegramQuestionTap, openQuestionOf, telegramQuestionButtons } from "./
|
|
22
|
-
import { messageTeammate } from "./teammate-desk.js";
|
|
21
|
+
import { applyTelegramQuestionReply, applyTelegramQuestionTap, openQuestionOf, telegramQuestionButtons } from "./subagent-question.js";
|
|
23
22
|
import { acceptanceEvidenceText } from "./chat-acceptance.js";
|
|
24
23
|
import { verifyApproverStanding } from "./principal.js";
|
|
25
24
|
import { resultImageFileName, resultTaskLabel, verifyResultImage } from "./chat-evidence.js";
|
|
@@ -43,9 +42,9 @@ import { focusContextFor, taskInCeiling } from "./chat-channel.js";
|
|
|
43
42
|
import { answersPrompt, applyDecideFeedback, applyDecideTap, decideFallbackLink, dropDecideTokens, hasLiveDecideTokens, linksFor, placeDecidePrompt, decideOffer, decideTargetOf, isDecideToken, mergedText, mintDecideButtons, offerFingerprint, openPromptFor, placeDecideTokens, recordChatMerge, retireDecideTokens } from "./chat-decide.js";
|
|
44
43
|
import { mergePullRequest } from "./pull-request-flow.js";
|
|
45
44
|
import { phoneCommand, phoneStatus, phoneTaskView, PHONE_CONSOLE_FOOTER, PHONE_HELP, notificationIdentity, phoneTaskChoices, resolvePhoneTask, phoneFocusText, phoneTaskListText, phoneText, PHONE_NO_MATCH, PHONE_BACK_TO_LEAD } from "./telegram-status.js";
|
|
46
|
-
import {
|
|
45
|
+
import { LEAD_MESSAGE_MAX_CHARS } from "./lead.js";
|
|
47
46
|
import { envValue } from "./names.js";
|
|
48
|
-
import { applyProposalTap, processTelegramConversations, phoneLinkButton, replyContextFor, telegramConversationRepos, telegramRequestId, tooLongText, whichTaskText, } from "./telegram-
|
|
47
|
+
import { applyProposalTap, processTelegramConversations, phoneLinkButton, replyContextFor, telegramConversationRepos, telegramRequestId, tooLongText, whichTaskText, } from "./telegram-lead.js";
|
|
49
48
|
import { askOf, parseTelegramUpdate, pickOf, readTelegramButtonData, readTelegramUpdate, telegramButton } from "./contracts/telegram-callback.js";
|
|
50
49
|
/** The environment name — and therefore the name the builder strips from agents (both names; see names.ts). */
|
|
51
50
|
export { TELEGRAM_TOKEN_ENV as TOKEN_ENV, TELEGRAM_TOKEN_ENVS as TOKEN_ENVS } from "./names.js";
|
|
@@ -1246,7 +1245,7 @@ async function deliverOne(store, botId, binding, sender, notification, clock, ph
|
|
|
1246
1245
|
parts = voiced.map(one => one.text);
|
|
1247
1246
|
entities = voiced.map(one => one.entities);
|
|
1248
1247
|
}
|
|
1249
|
-
// A
|
|
1248
|
+
// A subagent's question (v93): its options and "Answer in words", for the person it asks.
|
|
1250
1249
|
const asked = flowKeys === null && choiceKeys === null ? openQuestionOf(store, notification.dedupeKey) : null;
|
|
1251
1250
|
const questionKeys = asked === null ? null : telegramQuestionButtons(store, binding, asked, clock());
|
|
1252
1251
|
const keys = flowKeys ?? choiceKeys ?? questionKeys;
|
|
@@ -1649,7 +1648,7 @@ function applyMessage(context, update, effects) {
|
|
|
1649
1648
|
// assistant when a conversation is configured; otherwise silence.
|
|
1650
1649
|
const binding = store.liveTelegramBindingFor(botId, String(from.id));
|
|
1651
1650
|
// A reply to an Edit or Send back prompt (v86): the new draft, or the note it goes back with.
|
|
1652
|
-
// A reply to a
|
|
1651
|
+
// A reply to a subagent's "Answer in words" prompt (v93): the answer.
|
|
1653
1652
|
const questionPrompt = binding !== null && message.reply_to_message !== undefined && String(chat.id) === binding.chatId
|
|
1654
1653
|
? store.telegramQuestionPrompt(binding.chatId, String(message.reply_to_message.message_id), clock()) : null;
|
|
1655
1654
|
if (binding !== null && questionPrompt !== null) {
|
|
@@ -1694,27 +1693,7 @@ function applyMessage(context, update, effects) {
|
|
|
1694
1693
|
});
|
|
1695
1694
|
return;
|
|
1696
1695
|
}
|
|
1697
|
-
//
|
|
1698
|
-
if (binding !== null && message.reply_to_message === undefined && message.chat?.type === "private" && String(chat.id) === binding.chatId && store.accountOf(binding.approver)?.role === "approver") {
|
|
1699
|
-
const repos = context.projects === null ? store.knownRepos().filter(repo => store.accountCanAccess(binding.approver, repo)) : telegramConversationRepos(store, binding.approver, context.projects);
|
|
1700
|
-
const handed = messageTeammate(store, { who: binding.approver, repos, via: "Telegram" }, message.text ?? "", clock());
|
|
1701
|
-
if (handed !== null) {
|
|
1702
|
-
effects.push(async () => {
|
|
1703
|
-
let button = null;
|
|
1704
|
-
if (handed.link !== undefined) {
|
|
1705
|
-
try {
|
|
1706
|
-
button = phoneLinkButton(context.conversation?.phoneOrigin?.() ?? null, handed.link);
|
|
1707
|
-
}
|
|
1708
|
-
catch {
|
|
1709
|
-
button = null;
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1712
|
-
await transport("sendMessage", { chat_id: binding.chatId, text: handed.said, link_preview_options: { is_disabled: true }, reply_parameters: { message_id: message.message_id },
|
|
1713
|
-
...(button === null ? {} : { reply_markup: { inline_keyboard: [button] } }) });
|
|
1714
|
-
});
|
|
1715
|
-
return;
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1696
|
+
// D5: a message naming a subagent ("@rosa …") goes to the lead like any other, which asks the subagent with a card.
|
|
1718
1697
|
const repliedDecision = binding !== null && message.reply_to_message !== undefined
|
|
1719
1698
|
? store.decisionForTelegramMessage(binding.id, binding.chatId, String(message.reply_to_message.message_id))
|
|
1720
1699
|
: null;
|
|
@@ -1799,7 +1778,7 @@ function applyConversation(context, update, effects) {
|
|
|
1799
1778
|
report.ignored++;
|
|
1800
1779
|
return;
|
|
1801
1780
|
}
|
|
1802
|
-
if (text.length >
|
|
1781
|
+
if (text.length > LEAD_MESSAGE_MAX_CHARS) {
|
|
1803
1782
|
say(tooLongText(text.length));
|
|
1804
1783
|
report.chatRefused = (report.chatRefused ?? 0) + 1;
|
|
1805
1784
|
return;
|
|
@@ -2150,7 +2129,7 @@ function applyCallback(context, update, effects) {
|
|
|
2150
2129
|
editText(phoneFocusText(view.text), [[telegramButton("Back to the lead", "pick:lead")]]);
|
|
2151
2130
|
return;
|
|
2152
2131
|
}
|
|
2153
|
-
// A
|
|
2132
|
+
// A subagent's question (v93): an option answers it; "Answer in words" asks for a reply.
|
|
2154
2133
|
const questionAction = store.getTelegramQuestionAction(token);
|
|
2155
2134
|
if (questionAction !== null) {
|
|
2156
2135
|
if (questionAction.binding !== binding.id || questionAction.chatId !== tapChat || (questionAction.messageId !== null && questionAction.messageId !== String(message.message_id))) {
|
|
@@ -2247,7 +2226,7 @@ function applyCallback(context, update, effects) {
|
|
|
2247
2226
|
return;
|
|
2248
2227
|
}
|
|
2249
2228
|
const turn = askTap.turn;
|
|
2250
|
-
const found = store.
|
|
2229
|
+
const found = store.getLeadTurn(turn)?.approver === binding.approver ? store.leadAskState(turn, clock()) : { state: "expired" };
|
|
2251
2230
|
if (found.state !== "open") {
|
|
2252
2231
|
const line = found.state === "answered" ? "That question was already answered." : "That question expired. Send your answer as a message.";
|
|
2253
2232
|
ack(line);
|
package/dist/text-limits.d.ts
CHANGED
|
@@ -22,12 +22,12 @@ export declare const TEXT_LIMITS: {
|
|
|
22
22
|
readonly flowRef: 60;
|
|
23
23
|
/** A Message zone's message, or the comment an Update zone leaves. */
|
|
24
24
|
readonly flowMessage: 1000;
|
|
25
|
-
/** Who decides a "Person decides" zone (a sign-in name), and the
|
|
25
|
+
/** Who decides a "Person decides" zone (a sign-in name), and the subagent who works a zone, as written. */
|
|
26
26
|
readonly flowDecider: 64;
|
|
27
|
-
readonly
|
|
27
|
+
readonly flowSubagent: 40;
|
|
28
28
|
/** A Build zone's other project: its path. */
|
|
29
29
|
readonly flowRepo: 1000;
|
|
30
|
-
/** A script's or
|
|
30
|
+
/** A script's or subagent's answer, a choice's button, a Sort zone's answer and what it means, its question, and a score's level. */
|
|
31
31
|
readonly flowAnswer: 40;
|
|
32
32
|
readonly flowChoice: 40;
|
|
33
33
|
readonly flowSortMeans: 200;
|
|
@@ -136,11 +136,11 @@ export declare const TEXT_LIMITS: {
|
|
|
136
136
|
readonly decisionLabel: 120;
|
|
137
137
|
readonly decisionConsequence: 500;
|
|
138
138
|
readonly decisionAssignee: 120;
|
|
139
|
-
/** A
|
|
140
|
-
readonly
|
|
141
|
-
readonly
|
|
142
|
-
readonly
|
|
143
|
-
readonly
|
|
139
|
+
/** A subagent's turn (src/contracts/subagent-turn.ts): the answer it picks (and each option it offers), its question, its reason and what it remembers. */
|
|
140
|
+
readonly subagentAnswer: 60;
|
|
141
|
+
readonly subagentQuestion: 600;
|
|
142
|
+
readonly subagentReason: 400;
|
|
143
|
+
readonly subagentRemember: 300;
|
|
144
144
|
/** The lead's tools and the MCP gateway (src/contracts/lead-tools.ts, gateway-tools.ts): a task's id as a tool names
|
|
145
145
|
* it, a task's title and one path it touches, and a project's path as the gateway names it (an assignment brief or
|
|
146
146
|
* project context, and the rest of the gateway). */
|
|
@@ -175,17 +175,17 @@ export declare const TEXT_LIMITS: {
|
|
|
175
175
|
readonly actionUrl: 500;
|
|
176
176
|
readonly actionSecret: 64;
|
|
177
177
|
readonly actionAbout: 240;
|
|
178
|
-
/** A
|
|
178
|
+
/** A subagent change (propose_subagent): a soul section's title, a routine's schedule, a tool, an action, a limit's
|
|
179
179
|
* field, a name, a soul file, a note, a choice and text. */
|
|
180
|
-
readonly
|
|
181
|
-
readonly
|
|
182
|
-
readonly
|
|
183
|
-
readonly
|
|
184
|
-
readonly
|
|
185
|
-
readonly
|
|
186
|
-
readonly
|
|
187
|
-
readonly
|
|
188
|
-
readonly
|
|
180
|
+
readonly subagentSection: 60;
|
|
181
|
+
readonly subagentSchedule: 80;
|
|
182
|
+
readonly subagentTool: 40;
|
|
183
|
+
readonly subagentAction: 64;
|
|
184
|
+
readonly subagentName: 40;
|
|
185
|
+
readonly subagentSoul: 12000;
|
|
186
|
+
readonly subagentNote: 300;
|
|
187
|
+
readonly subagentChoice: 60;
|
|
188
|
+
readonly subagentText: 2000;
|
|
189
189
|
/** A project knowledge reference id, a promise and why it is released, what the lead remembers (its text, a
|
|
190
190
|
* decision's reason and source), a person's name, and a question to the owner with its options. */
|
|
191
191
|
readonly knowledgeReference: 20;
|
package/dist/text-limits.js
CHANGED
|
@@ -22,12 +22,12 @@ export const TEXT_LIMITS = {
|
|
|
22
22
|
flowRef: 60,
|
|
23
23
|
/** A Message zone's message, or the comment an Update zone leaves. */
|
|
24
24
|
flowMessage: 1_000,
|
|
25
|
-
/** Who decides a "Person decides" zone (a sign-in name), and the
|
|
25
|
+
/** Who decides a "Person decides" zone (a sign-in name), and the subagent who works a zone, as written. */
|
|
26
26
|
flowDecider: 64,
|
|
27
|
-
|
|
27
|
+
flowSubagent: 40,
|
|
28
28
|
/** A Build zone's other project: its path. */
|
|
29
29
|
flowRepo: 1_000,
|
|
30
|
-
/** A script's or
|
|
30
|
+
/** A script's or subagent's answer, a choice's button, a Sort zone's answer and what it means, its question, and a score's level. */
|
|
31
31
|
flowAnswer: 40,
|
|
32
32
|
flowChoice: 40,
|
|
33
33
|
flowSortMeans: 200,
|
|
@@ -136,11 +136,11 @@ export const TEXT_LIMITS = {
|
|
|
136
136
|
decisionLabel: 120,
|
|
137
137
|
decisionConsequence: 500,
|
|
138
138
|
decisionAssignee: 120,
|
|
139
|
-
/** A
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
/** A subagent's turn (src/contracts/subagent-turn.ts): the answer it picks (and each option it offers), its question, its reason and what it remembers. */
|
|
140
|
+
subagentAnswer: 60,
|
|
141
|
+
subagentQuestion: 600,
|
|
142
|
+
subagentReason: 400,
|
|
143
|
+
subagentRemember: 300,
|
|
144
144
|
/** The lead's tools and the MCP gateway (src/contracts/lead-tools.ts, gateway-tools.ts): a task's id as a tool names
|
|
145
145
|
* it, a task's title and one path it touches, and a project's path as the gateway names it (an assignment brief or
|
|
146
146
|
* project context, and the rest of the gateway). */
|
|
@@ -175,17 +175,17 @@ export const TEXT_LIMITS = {
|
|
|
175
175
|
actionUrl: 500,
|
|
176
176
|
actionSecret: 64,
|
|
177
177
|
actionAbout: 240,
|
|
178
|
-
/** A
|
|
178
|
+
/** A subagent change (propose_subagent): a soul section's title, a routine's schedule, a tool, an action, a limit's
|
|
179
179
|
* field, a name, a soul file, a note, a choice and text. */
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
180
|
+
subagentSection: 60,
|
|
181
|
+
subagentSchedule: 80,
|
|
182
|
+
subagentTool: 40,
|
|
183
|
+
subagentAction: 64,
|
|
184
|
+
subagentName: 40,
|
|
185
|
+
subagentSoul: 12_000,
|
|
186
|
+
subagentNote: 300,
|
|
187
|
+
subagentChoice: 60,
|
|
188
|
+
subagentText: 2_000,
|
|
189
189
|
/** A project knowledge reference id, a promise and why it is released, what the lead remembers (its text, a
|
|
190
190
|
* decision's reason and source), a person's name, and a question to the owner with its options. */
|
|
191
191
|
knowledgeReference: 20,
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* and a one-time "What's new" card afterwards. The work itself is the
|
|
5
5
|
* `toolroll update` command (toolroll-update.ts), started as its own job.
|
|
6
6
|
*/
|
|
7
|
+
import { type Html } from "./html.js";
|
|
7
8
|
import type { InstallMethod } from "./install-method.js";
|
|
8
9
|
import { type RuntimeUpdateJournal } from "./toolroll-update.js";
|
|
9
10
|
export declare const UPDATES_CSS: string;
|
|
@@ -29,11 +30,11 @@ export type UpdatesView = {
|
|
|
29
30
|
csrf: string;
|
|
30
31
|
};
|
|
31
32
|
/** The steps, each done, current, failed or waiting. Also the live region's fragment. */
|
|
32
|
-
export declare function updateStepsHtml(j: RuntimeUpdateJournal, running: boolean):
|
|
33
|
+
export declare function updateStepsHtml(j: RuntimeUpdateJournal, running: boolean): Html;
|
|
33
34
|
export declare function updatesHtml(view: UpdatesView, notice: {
|
|
34
35
|
said?: string | null;
|
|
35
36
|
problem?: string | null;
|
|
36
|
-
}):
|
|
37
|
+
}): Html;
|
|
37
38
|
export declare function newerThan(a: string, b: string): boolean;
|
|
38
39
|
/** Polls the steps every two seconds, keeps trying while the console
|
|
39
40
|
* restarts, and reloads once the update has finished. */
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings → Updates: the installed version, one of three ways to update
|
|
3
|
+
* (behind the operator's password), the update's steps live while it runs,
|
|
4
|
+
* and a one-time "What's new" card afterwards. The work itself is the
|
|
5
|
+
* `toolroll update` command (toolroll-update.ts), started as its own job.
|
|
6
|
+
*/
|
|
7
|
+
import { html, postForm, replaceMarkup } from "./html.js";
|
|
1
8
|
import { STEP_WORDS, UPDATE_STEPS, runtimeUpdateTerminal } from "./toolroll-update.js";
|
|
2
|
-
const e = (value) => String(value ?? "").replace(/[&<>"']/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c]);
|
|
3
9
|
const clock = (iso) => { const d = new Date(iso); return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`; };
|
|
4
10
|
export const UPDATES_CSS = `.updates{max-width:640px;min-width:0;overflow-wrap:anywhere}.updates .card{margin:0 0 16px}.updates h2{margin:0;font-size:1.0625rem}.updates .card>p{margin:4px 0 0}` +
|
|
5
11
|
`.updates .update-actions{display:flex;flex-wrap:wrap;gap:8px;margin:16px 0 0}.updates .update-actions button{white-space:nowrap}` +
|
|
@@ -23,60 +29,50 @@ export function updateStepsHtml(j, running) {
|
|
|
23
29
|
const items = UPDATE_STEPS.map((step, i) => {
|
|
24
30
|
const state = j.phase === "complete" || i < last ? "done" : i > last ? "waiting" : failed ? "failed" : finished ? "waiting" : "now";
|
|
25
31
|
// Only where it adds something: which work it waits for, or what went wrong.
|
|
26
|
-
const detail = state === "now" && step === "draining" && j.waiting ? `<span class="step-detail">${
|
|
27
|
-
: (state === "now" && step === "draining") || (state === "failed" && j.phase === "rolling-back") ? `<span class="step-detail">${
|
|
28
|
-
return `<li data-step="${step}" data-state="${state}">${
|
|
29
|
-
})
|
|
30
|
-
const title = j.phase === "scheduled" ? `Update to ${
|
|
31
|
-
: j.phase === "rolling-back" ? `Restoring ${
|
|
32
|
-
: j.kind === "rollback" ? `Rolling back to ${
|
|
33
|
-
const stalled = !running && !finished ? `<p class="update-problem" role="alert">The updater stopped. Run <code>toolroll update --resume</code> to continue it.</p>` : "";
|
|
34
|
-
return `<div id="update-live" data-phase="${
|
|
35
|
-
(j.phase === "scheduled" ? `<p class="meta">Running work finishes first. You can close this page.</p>` : `<ol class="update-steps" aria-label="Update steps">${items}</ol>`) + stalled + `</div>`;
|
|
32
|
+
const detail = state === "now" && step === "draining" && j.waiting ? html `<span class="step-detail">${j.waiting.on}.${j.waiting.action ? html ` If nothing of it is running, run <code>${j.waiting.action}</code>.` : ""}</span>`
|
|
33
|
+
: (state === "now" && step === "draining") || (state === "failed" && j.phase === "rolling-back") ? html `<span class="step-detail">${j.detail}</span>` : "";
|
|
34
|
+
return html `<li data-step="${step}" data-state="${state}">${STEP_WORDS[step]}${detail}</li>`;
|
|
35
|
+
});
|
|
36
|
+
const title = j.phase === "scheduled" ? `Update to ${j.to.version} scheduled for ${clock(j.at ?? j.startedAt)}`
|
|
37
|
+
: j.phase === "rolling-back" ? `Restoring ${j.from.version}`
|
|
38
|
+
: j.kind === "rollback" ? `Rolling back to ${j.to.version}` : `Updating to ${j.to.version}`;
|
|
39
|
+
const stalled = !running && !finished ? html `<p class="update-problem" role="alert">The updater stopped. Run <code>toolroll update --resume</code> to continue it.</p>` : "";
|
|
40
|
+
return html `<div id="update-live" data-phase="${j.phase}" data-done="${finished ? 1 : 0}"><h2>${title}</h2>${j.phase === "scheduled" ? html `<p class="meta">Running work finishes first. You can close this page.</p>` : html `<ol class="update-steps" aria-label="Update steps">${items}</ol>`}${stalled}</div>`;
|
|
36
41
|
}
|
|
37
42
|
function outcomeHtml(j) {
|
|
38
43
|
if (j.phase === "complete")
|
|
39
|
-
return j.kind === "rollback" ? `<div class="card" data-update-outcome="rolled-back"><h2>Back on ${
|
|
44
|
+
return j.kind === "rollback" ? html `<div class="card" data-update-outcome="rolled-back"><h2>Back on ${j.to.version}</h2><p class="meta">${j.detail}</p></div>` : "";
|
|
40
45
|
if (j.phase === "cancelled")
|
|
41
|
-
return `<div class="card" data-update-outcome="cancelled"><h2>Update cancelled</h2><p class="meta">Nothing changed.</p></div>`;
|
|
46
|
+
return html `<div class="card" data-update-outcome="cancelled"><h2>Update cancelled</h2><p class="meta">Nothing changed.</p></div>`;
|
|
42
47
|
// Stopped on a finished run it can't show has ended: what is in the way and the one command, nothing more.
|
|
43
48
|
if (j.phase === "refused" && j.waiting)
|
|
44
|
-
return `<div class="card" data-update-outcome="stopped"><h2>Update to ${
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return `<div class="card" data-update-outcome="${e(j.phase)}"><h2>${title}</h2><p class="${j.phase === "needs-attention" ? "update-problem" : ""}" role="alert">${e(j.detail)}</p>` +
|
|
48
|
-
`<details><summary>Steps</summary>${updateStepsHtml(j, false).replace(/<h2>.*?<\/h2>/, "")}</details></div>`;
|
|
49
|
+
return html `<div class="card" data-update-outcome="stopped"><h2>Update to ${j.to.version} stopped: run #${j.waiting.run} is in the way</h2><p>${j.waiting.on}. New work resumed.</p>${j.waiting.action ? html `<p class="meta">If nothing of it is running, run <code>${j.waiting.action}</code>, then update again.</p>` : html `<p class="meta">Update again once it has stopped.</p>`}</div>`;
|
|
50
|
+
const title = j.phase === "refused" ? html `Didn't update to ${j.to.version}` : j.phase === "restored" ? html `Update to ${j.to.version} didn't finish` : "The update needs attention";
|
|
51
|
+
return html `<div class="card" data-update-outcome="${j.phase}"><h2>${title}</h2><p class="${j.phase === "needs-attention" ? "update-problem" : ""}" role="alert">${j.detail}</p><details><summary>Steps</summary>${replaceMarkup(updateStepsHtml(j, false), /<h2>.*?<\/h2>/, () => html ``)}</details></div>`;
|
|
49
52
|
}
|
|
50
53
|
export function updatesHtml(view, notice) {
|
|
51
|
-
const note = notice.problem ? `<p class="update-problem" role="alert">${
|
|
54
|
+
const note = notice.problem ? html `<p class="update-problem" role="alert">${notice.problem}</p>` : notice.said ? html `<p role="status">${notice.said}</p>` : "";
|
|
52
55
|
const j = view.journal;
|
|
53
56
|
const active = j !== null && !runtimeUpdateTerminal(j.phase);
|
|
54
|
-
const
|
|
55
|
-
const whatsNew = view.whatsNew === null ? "" : `<div class="card whats-new" data-whats-new="${e(view.whatsNew.version)}"><h2>What’s new in ${e(view.whatsNew.version)}</h2>` +
|
|
56
|
-
(view.whatsNew.notes.length > 0 ? `<ul>${view.whatsNew.notes.map(line => `<li>${e(line)}</li>`).join("")}</ul>` : "") +
|
|
57
|
-
`<p class="meta"><a href="https://github.com/ap9000/toolroll/releases/tag/v${e(view.whatsNew.version)}" rel="noreferrer">Full release notes</a></p>` +
|
|
58
|
-
`<form method="post" action="/settings/updates/seen">${csrf}<button type="submit">Got it</button></form></div>`;
|
|
57
|
+
const whatsNew = view.whatsNew === null ? "" : html `<div class="card whats-new" data-whats-new="${view.whatsNew.version}"><h2>What’s new in ${view.whatsNew.version}</h2>${view.whatsNew.notes.length > 0 ? html `<ul>${view.whatsNew.notes.map(line => html `<li>${line}</li>`)}</ul>` : ""}<p class="meta"><a href="https://github.com/ap9000/toolroll/releases/tag/v${view.whatsNew.version}" rel="noreferrer">Full release notes</a></p>${postForm("/settings/updates/seen", html `<button type="submit">Got it</button>`)}</div>`;
|
|
59
58
|
if (active) {
|
|
60
|
-
const cancel = ["scheduled", "draining"].includes(j.phase) ?
|
|
61
|
-
return `<section class="updates">${note}<div class="card" id="update-region">${updateStepsHtml(j, view.running)}${cancel}</div><p class="meta stamp" id="update-region-stamp"></p></section>`;
|
|
59
|
+
const cancel = ["scheduled", "draining"].includes(j.phase) ? postForm("/settings/updates/cancel", html `<button type="submit">Cancel update</button>`, { attrs: { class: "update-actions" } }) : "";
|
|
60
|
+
return html `<section class="updates">${note}<div class="card" id="update-region">${updateStepsHtml(j, view.running)}${cancel}</div><p class="meta stamp" id="update-region-stamp"></p></section>`;
|
|
62
61
|
}
|
|
63
62
|
const latest = "version" in view.latest ? view.latest.version : null;
|
|
64
63
|
const newer = latest !== null && newerThan(latest, view.current);
|
|
65
|
-
const state = view.method.kind === "npx" ? `<h2>Toolroll ${
|
|
66
|
-
: view.method.kind === "source" ? `<h2>Toolroll ${
|
|
67
|
-
: newer && view.method.kind === "desktop" ? `<h2>Toolroll ${
|
|
68
|
-
: newer ? `<h2>Toolroll ${
|
|
69
|
-
: "off" in view.latest ? `<h2>Toolroll ${
|
|
70
|
-
: latest === null ? `<h2>Toolroll ${
|
|
71
|
-
: `<h2>Toolroll ${
|
|
64
|
+
const state = view.method.kind === "npx" ? html `<h2>Toolroll ${view.current}</h2><p class="meta">npx runs the latest release each time, so this is current.</p>`
|
|
65
|
+
: view.method.kind === "source" ? html `<h2>Toolroll ${view.current}</h2><p class="meta">This runs from a source checkout. Update it with git.</p>`
|
|
66
|
+
: newer && view.method.kind === "desktop" ? html `<h2>Toolroll ${latest} is available</h2><p class="meta">You have ${view.current}. Update it from the Toolroll app.</p>`
|
|
67
|
+
: newer ? html `<h2>Toolroll ${latest} is available</h2><p class="meta">You have ${view.current}. Running work finishes first, and your current version is kept so you can go back.</p>`
|
|
68
|
+
: "off" in view.latest ? html `<h2>Toolroll ${view.current}</h2><p class="meta">Update checks are off.</p><form method="get" action="/settings/updates" class="update-actions"><input type="hidden" name="check" value="now"><button type="submit">Check now</button></form>`
|
|
69
|
+
: latest === null ? html `<h2>Toolroll ${view.current}</h2><p class="meta">Couldn’t check for a newer release: ${"problem" in view.latest ? view.latest.problem : ""}</p>`
|
|
70
|
+
: html `<h2>Toolroll ${view.current} is up to date</h2>`;
|
|
72
71
|
const form = newer && !["npx", "source", "desktop"].includes(view.method.kind)
|
|
73
|
-
? `<
|
|
74
|
-
`<label class="step-up">Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label>` +
|
|
75
|
-
`<div class="update-actions"><button type="submit" name="when" value="now" class="primary">Update now</button>` +
|
|
76
|
-
`<button type="submit" name="when" value="when-idle">When idle</button><button type="submit" name="when" value="tonight">Tonight (03:00)</button></div></form>`
|
|
72
|
+
? postForm("/settings/updates", html `<label class="step-up">Your Toolroll password<input type="password" name="password" autocomplete="current-password" required></label><div class="update-actions"><button type="submit" name="when" value="now" class="primary">Update now</button><button type="submit" name="when" value="when-idle">When idle</button><button type="submit" name="when" value="tonight">Tonight (03:00)</button></div>`, { hidden: { version: latest } })
|
|
77
73
|
: "";
|
|
78
|
-
const rollback = view.rollbackTo !== null ? `<p class="meta">To go back to ${
|
|
79
|
-
return `<section class="updates">${note}${whatsNew}${j ? outcomeHtml(j) : ""}<div class="card" data-update-state="${newer ? "available" : "current"}">${state}${form}${rollback}</div></section>`;
|
|
74
|
+
const rollback = view.rollbackTo !== null ? html `<p class="meta">To go back to ${view.rollbackTo}: <code>toolroll update --rollback</code></p>` : "";
|
|
75
|
+
return html `<section class="updates">${note}${whatsNew}${j ? outcomeHtml(j) : ""}<div class="card" data-update-state="${newer ? "available" : "current"}">${state}${form}${rollback}</div></section>`;
|
|
80
76
|
}
|
|
81
77
|
export function newerThan(a, b) {
|
|
82
78
|
const [x, y] = [a, b].map(v => v.split(".").map(Number));
|
|
@@ -137,6 +137,14 @@ export type TableDigest = {
|
|
|
137
137
|
rows: number;
|
|
138
138
|
found: number;
|
|
139
139
|
};
|
|
140
|
+
compactedRuns?: {
|
|
141
|
+
run: number;
|
|
142
|
+
count: number;
|
|
143
|
+
}[];
|
|
144
|
+
summaries?: {
|
|
145
|
+
run: number;
|
|
146
|
+
hash: string;
|
|
147
|
+
}[];
|
|
140
148
|
};
|
|
141
149
|
/** Each saved table's columns, row count and last rowid; the append-only ones hashed (deploy-browser's rehearsal check).
|
|
142
150
|
* Bounded: only the ledger and small tables are read row by row. */
|
package/dist/toolroll-update.js
CHANGED
|
@@ -35,7 +35,7 @@ import { processMayBeAlive } from "./process-liveness.js";
|
|
|
35
35
|
import { assertCodingUpdateStopped, backupCodingCatalog, codingCatalogExists, releaseStaleCodingOwner, removeCodingUpdateGate } from "./coding-update.js";
|
|
36
36
|
import { installLaunchdService, launchdPlist, stopLaunchdService, writeFileDurably } from "./daemon.js";
|
|
37
37
|
import { NAME } from "./names.js";
|
|
38
|
-
import { updateSafeSchema } from "./store.js";
|
|
38
|
+
import { orphanKey, updateSafeSchema, V117_RENAMED_COLUMNS, V117_RENAMED_TABLES } from "./store.js";
|
|
39
39
|
import { isNewer, REGISTRY } from "./releases.js";
|
|
40
40
|
import { markNeverIndex } from "./never-index.js";
|
|
41
41
|
import { readRuntimeUpdateJournal, RUNTIME_PHASES, RUNTIME_UPDATE_STEPS, stagedStartedAt, updaterStartingOf } from "./contracts/update-journal.js";
|
|
@@ -322,7 +322,8 @@ export function durableRename(temp, target) {
|
|
|
322
322
|
* only when every saved value is null, or, with `carried`, when the receiving table gained exactly one receipt under
|
|
323
323
|
* that destination per row holding a value, and as many non-null values per column as the dropped columns held.
|
|
324
324
|
* `receives`: the only rows the table may gain are those receipts. `compacted`: rows may go only into summary rows,
|
|
325
|
-
* whose `sum` grows by exactly as many. `
|
|
325
|
+
* whose `sum` grows by exactly as many. `summarizes`: old summaries stay identical by run key; new ones account for
|
|
326
|
+
* that run's compacted witnesses, even below the previous maximum key. `retired`: a removed feature's table, which may go whole. `fromRoutines`: rows
|
|
326
327
|
* kept as they were, and the only rows the table may gain are one per saved routine, moved into a scheduled flow (its
|
|
327
328
|
* flow, or its schedule trigger naming that routine) — on only when the routine was approved and running. `moved`:
|
|
328
329
|
* the table may go only when every row it had (or the ones `rows` counts) arrived in `into`: the rows there that
|
|
@@ -366,7 +367,7 @@ const HISTORY_RULES = {
|
|
|
366
367
|
...Object.fromEntries(Object.entries(CHAT_MOVES).map(([table, moved]) => [table, { moved }])),
|
|
367
368
|
action_ledger: { appendOnly: true }, ledger_seal: { appendOnly: true }, ledger_checkpoint: { appendOnly: true },
|
|
368
369
|
// v114: a finished run whose process witnesses have all exited keeps one summary row in place of them.
|
|
369
|
-
run_process: { compacted: { into: "run_process_summary", sum: "witnesses" } }, run_process_summary: {
|
|
370
|
+
run_process: { compacted: { into: "run_process_summary", sum: "witnesses" } }, run_process_summary: { summarizes: "run_process" },
|
|
370
371
|
// v114: single-destination delivery columns may be dropped only once their values are legacy receipts.
|
|
371
372
|
notification: { dropped: ["attempts", "last_attempt_at", "last_error", "delivered_at", "receipt", "claim_owner", "claim_expires_at"], carried: { into: "notification_delivery", destination: LEGACY_DESTINATION } },
|
|
372
373
|
notification_delivery: { receives: LEGACY_DESTINATION },
|
|
@@ -377,11 +378,36 @@ const HISTORY_RULES = {
|
|
|
377
378
|
fallback_config: { retired: true }, fallback_cycle: { retired: true }, fallback_transition: { retired: true },
|
|
378
379
|
// v115: each routine becomes one scheduled flow and its schedule trigger.
|
|
379
380
|
flow: { fromRoutines: "flow" }, flow_trigger: { fromRoutines: "trigger" },
|
|
381
|
+
// v117 (D5): the lead's and the subagents' tables keep every row under their new names (mate_* → lead_*, teammate* →
|
|
382
|
+
// subagent*); a column renamed in a table that keeps its name keeps its values under the new one.
|
|
383
|
+
...Object.fromEntries(Object.entries(V117_RENAMED_TABLES).map(([old, now]) => [old, { moved: { into: now, where: "1" } }])),
|
|
384
|
+
...Object.fromEntries(V117_RENAMED_COLUMNS.filter(([table]) => !Object.values(V117_RENAMED_TABLES).includes(table)).map(([table, from, to]) => [table, { renamed: { [from]: to } }])),
|
|
380
385
|
};
|
|
381
386
|
/** The tables a migration may remove whole (v115's removed features). */
|
|
382
387
|
export const RETIRED_TABLES = Object.freeze(Object.keys(HISTORY_RULES).filter(name => HISTORY_RULES[name].retired));
|
|
383
388
|
const tableColumns = (db, name) => db.prepare("PRAGMA table_info(" + quote(name) + ")").all().map(r => String(r["name"]));
|
|
384
389
|
const plainValue = (_, v) => v instanceof Uint8Array ? Buffer.from(v).toString("hex") : typeof v === "bigint" ? String(v) : v;
|
|
390
|
+
const rowHash = (row) => createHash("sha256").update(JSON.stringify(Object.values(row), plainValue)).digest("hex");
|
|
391
|
+
const summaryRows = (db, name, columns) => db.prepare("SELECT " + columns.map(quote).join(",") + " FROM " + quote(name) + " ORDER BY run").iterate();
|
|
392
|
+
/** Keep every saved summary byte-identical. A new key must replace all witnesses saved for that same run. */
|
|
393
|
+
function keptSummaries(db, name, before, source) {
|
|
394
|
+
const saved = new Map(before?.summaries?.map(row => [row.run, row.hash]));
|
|
395
|
+
const witnesses = new Map(source?.compactedRuns?.map(row => [row.run, row.count]));
|
|
396
|
+
const from = HISTORY_RULES[name].summarizes, sum = HISTORY_RULES[from].compacted.sum;
|
|
397
|
+
const remaining = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name=?").get(from)
|
|
398
|
+
? db.prepare("SELECT 1 FROM " + quote(from) + " WHERE run = ? LIMIT 1") : undefined;
|
|
399
|
+
for (const row of summaryRows(db, name, before?.columns ?? tableColumns(db, name))) {
|
|
400
|
+
const run = Number(row["run"]), hash = saved.get(run);
|
|
401
|
+
if (hash !== undefined) {
|
|
402
|
+
if (rowHash(row) !== hash)
|
|
403
|
+
return false;
|
|
404
|
+
saved.delete(run);
|
|
405
|
+
}
|
|
406
|
+
else if (!witnesses.has(run) || Number(row[sum]) !== witnesses.get(run) || !remaining || remaining.get(run))
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
return saved.size === 0;
|
|
410
|
+
}
|
|
385
411
|
/** Rows streamed into a sha256, never held together: through a rowid in rowid order, or a WITHOUT ROWID table whole. */
|
|
386
412
|
function rowsHash(db, name, columns, through) {
|
|
387
413
|
const select = "SELECT " + (through === undefined ? "" : 'rowid AS "rowid:", ') + columns.map(quote).join(",") + " FROM " + quote(name);
|
|
@@ -423,8 +449,13 @@ export function historySnapshot(db) {
|
|
|
423
449
|
t.received = receipts(db, name, rule.receives, columns.filter(column => column !== "notification" && column !== "destination"));
|
|
424
450
|
if (rule?.appendOnly || rule?.fromRoutines)
|
|
425
451
|
t.hash = rowsHash(db, name, columns, t.last).hash;
|
|
426
|
-
if (rule?.compacted)
|
|
452
|
+
if (rule?.compacted) {
|
|
427
453
|
t.summed = summed(db, rule.compacted);
|
|
454
|
+
t.compactedRuns = db.prepare("SELECT run, count(*) AS n FROM " + quote(name) + " GROUP BY run ORDER BY run").all()
|
|
455
|
+
.map(r => ({ run: Number(r["run"]), count: Number(r["n"]) }));
|
|
456
|
+
}
|
|
457
|
+
if (rule?.summarizes)
|
|
458
|
+
t.summaries = [...summaryRows(db, name, columns)].map(row => ({ run: Number(row["run"]), hash: rowHash(row) }));
|
|
428
459
|
if (rule?.fromRoutines)
|
|
429
460
|
t.routines = savedRoutines(db);
|
|
430
461
|
if (rule?.moved)
|
|
@@ -500,7 +531,8 @@ export function changedHistory(db, before) {
|
|
|
500
531
|
return move === undefined || t.moved === undefined || arrived(db, move) - t.moved.found !== t.moved.rows;
|
|
501
532
|
}
|
|
502
533
|
const rule = HISTORY_RULES[t.name], present = new Set(tableColumns(db, t.name));
|
|
503
|
-
|
|
534
|
+
const kept = (c) => present.has(c) || (rule?.renamed?.[c] !== undefined && present.has(rule.renamed[c]));
|
|
535
|
+
if (t.columns.some(c => !kept(c) && (!rule?.dropped?.includes(c) || (t.nonNull?.[c] !== 0 && !accounted(rule, t)))))
|
|
504
536
|
return true;
|
|
505
537
|
const columns = t.columns.filter(c => present.has(c));
|
|
506
538
|
if (!t.rowid) {
|
|
@@ -515,9 +547,13 @@ export function changedHistory(db, before) {
|
|
|
515
547
|
const after = rowsHash(db, t.name, columns, t.last);
|
|
516
548
|
return after.count !== t.count || after.hash !== t.hash;
|
|
517
549
|
}
|
|
550
|
+
if (rule?.summarizes)
|
|
551
|
+
return !keptSummaries(db, t.name, t, before.find(one => one.name === rule.summarizes));
|
|
518
552
|
const r = db.prepare("SELECT count(*) AS n, coalesce(max(rowid),0) AS last FROM " + quote(t.name)).get(), count = Number(r["n"]), last = Number(r["last"]);
|
|
519
553
|
if (rule?.compacted)
|
|
520
|
-
return count > t.count || last > t.last || t.count - count !== summed(db, rule.compacted) - (t.summed ?? 0)
|
|
554
|
+
return count > t.count || last > t.last || t.count - count !== summed(db, rule.compacted) - (t.summed ?? 0)
|
|
555
|
+
// A newly created summary table has no digest of its own; check its keys here too.
|
|
556
|
+
|| (!before.some(one => one.name === rule.compacted.into) && tables.has(rule.compacted.into) && !keptSummaries(db, rule.compacted.into, undefined, t));
|
|
521
557
|
if (rule?.receives) {
|
|
522
558
|
const added = gained.get(t.name)?.count ?? 0;
|
|
523
559
|
return count - t.count !== added || (added > 0 && added !== owed.get(t.name)?.count) || last < t.last;
|
|
@@ -531,8 +567,9 @@ async function rehearse(j, system, source) {
|
|
|
531
567
|
chmodSync(copy, 0o600);
|
|
532
568
|
try {
|
|
533
569
|
let db = new (sqlite().DatabaseSync)(copy, { readOnly: true });
|
|
534
|
-
// Rows already pointing nowhere before the update are the install's own; only ones the migration makes refuse.
|
|
535
|
-
|
|
570
|
+
// Rows already pointing nowhere before the update are the install's own; only ones the migration makes refuse. (By
|
|
571
|
+
// today's table names: a renamed table's old orphan is the same row under its new name, orphanKey.)
|
|
572
|
+
const orphans = () => new Set([...db.prepare("PRAGMA foreign_key_check").iterate()].map(row => orphanKey(row)));
|
|
536
573
|
const before = historySnapshot(db), orphaned = orphans();
|
|
537
574
|
db.close();
|
|
538
575
|
await system.rehearse(j.to.dist, copy);
|
package/dist/tools-ui.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/** Settings → Tools: one project's MCP servers, in plain words. Secrets are
|
|
2
|
+
* entered here and nowhere else, and never shown again. */
|
|
3
|
+
import { type Html } from "./html.js";
|
|
1
4
|
import { type FoundTool, type ProjectTool, type ToolSpec } from "./project-tools.js";
|
|
2
5
|
export declare const TOOLS_CSS = ".tools{max-width:780px;min-width:0;overflow-wrap:anywhere}.tools .card{padding:16px 18px;margin:12px 0;min-width:0}.tools .card h2{font-size:1.05rem;margin:0;color:var(--so-ink);font-weight:600}.tools .tool-heading{display:flex;align-items:center;gap:10px}.tools .tool-heading h2{flex:1;min-width:0}.tools .tool-state{font-size:.85rem;flex-shrink:0;color:var(--so-muted)}.tools .tool-state[data-ready=\"false\"]{color:var(--so-warning)}.tools .card>p{margin:6px 0 0}.tools .tool-note{color:var(--so-warning)}.tools code{white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;font-size:.85rem}.tools form{display:grid;gap:10px;margin:0}.tools label{display:grid;gap:6px}.tools input,.tools select{box-sizing:border-box;width:100%;max-width:100%;min-width:0}.tools button{justify-self:start;white-space:nowrap;min-height:44px;max-width:100%;overflow:hidden;text-overflow:ellipsis}.tools details:not(.card){margin:6px 0 0;padding:0;border:0;border-radius:0;background:none;box-shadow:none}.tools details:not(.card)>summary{min-height:36px;display:flex;align-items:center;font-size:.9rem;color:var(--so-muted);cursor:pointer}.tools details:not(.card)[open]>summary{color:var(--so-ink)}.tools details.card>summary{cursor:pointer;min-height:44px;display:flex;align-items:center;font-weight:600}.tools summary{list-style:none;gap:10px}.tools summary::-webkit-details-marker{display:none}.tools summary::before{content:\"\";flex-shrink:0;width:6px;height:6px;margin:0 2px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(-45deg);transition:transform .15s}.tools details[open]>summary::before{transform:rotate(45deg)}.tools details:not(.card) form{padding:4px 0 10px}.tools .tool-facts{margin:0 0 8px;display:grid;gap:4px;font-size:.9rem}.tools .tool-facts p{margin:0}.tools .tool-controls{display:flex;gap:12px;flex-wrap:wrap;margin-top:12px}.tools .tool-found{display:flex;gap:10px;align-items:flex-start}.tools .tool-found input{flex:0 0 auto;width:18px;height:18px;margin-top:3px}.tools .tool-found span{min-width:0}.tools .problem{padding:10px 12px;margin:8px 0 0}.tools .tool-connect{scroll-margin-top:72px}.tools .connect-wanted{background:var(--so-accent);color:var(--so-on-accent);border-color:var(--so-accent)}.tools .connect-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:8px}.tools .connect-tile{display:grid;grid-template-columns:auto 1fr;column-gap:10px;align-items:center;justify-self:stretch;text-align:left;white-space:normal;padding:10px 12px;border:1px solid var(--so-line);border-radius:10px;background:var(--so-paper);color:var(--so-ink);min-height:60px;font:inherit;cursor:pointer;scroll-margin-top:96px}.tools .connect-tile:hover{border-color:var(--so-input-line);background:var(--so-raised)}.tools .connect-tile:target,.tools .connect-tile:focus-visible{outline:2px solid var(--so-accent);outline-offset:2px}.tools .connect-tile .brand-mark{grid-row:span 2}.tools .connect-tile strong{font-weight:600;line-height:1.3}.tools .connect-tile>span:not(.brand-mark){font-size:.8rem;color:var(--so-muted);line-height:1.35;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.tools .connect-tile[data-state=\"connected\"]>span:not(.brand-mark){color:var(--so-success)}.tools .connect-local{grid-column:1/-1}.tools .connect-local>span:not(.brand-mark){-webkit-line-clamp:unset}.tools .connect-problem{margin:0}.tools .connect-problem:focus{outline:2px solid var(--so-accent);outline-offset:2px}.tools .connect-tile:disabled{cursor:default;opacity:.6}@media(max-width:600px){.tools .connect-grid{grid-template-columns:1fr 1fr}.tools .connect-tile:not(.connect-local)>span:not(.brand-mark){display:none}.tools .connect-local>span:not(.brand-mark){grid-column:2}.tools .connect-tile{min-height:52px;padding:8px 10px}.tools .connect-tile .brand-mark{grid-row:auto}.tools input,.tools select{font-size:16px}.tools .card{padding:14px}}";
|
|
3
6
|
export type ToolsView = {
|
|
@@ -31,10 +34,10 @@ export type ToolsView = {
|
|
|
31
34
|
}[];
|
|
32
35
|
};
|
|
33
36
|
/** The project chooser: it opens the chosen project at once; without scripts, its button does. */
|
|
34
|
-
export declare function toolsProjectPicker(projects: readonly string[], chosen: string, keep?: Record<string, string>):
|
|
37
|
+
export declare function toolsProjectPicker(projects: readonly string[], chosen: string, keep?: Record<string, string>): Html | "";
|
|
35
38
|
/** Choosing another project marks every form on the page as stale before it reloads, so a tap racing the reload is refused. */
|
|
36
39
|
export declare const TOOLS_PROJECT_SCRIPT = "(function(){var s=document.querySelector('select[data-tools-project]');if(!s)return;s.addEventListener('change',function(){document.querySelectorAll('input[name=shown]').forEach(function(i){i.value=s.value;});});})();";
|
|
37
40
|
export declare function toolsHtml(view: ToolsView, csrf: string, canManage: boolean, message?: {
|
|
38
41
|
said?: string | null;
|
|
39
42
|
problem?: string | null;
|
|
40
|
-
}):
|
|
43
|
+
}): Html;
|