toolroll 0.8.1 → 0.9.0
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 +49 -0
- package/dist/agent-onboard.d.ts +7 -0
- package/dist/agent-onboard.js +23 -5
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +21 -20
- package/dist/browser-workspace.d.ts +10 -0
- package/dist/chat-delivery.js +51 -3
- package/dist/chat-quiet.d.ts +28 -0
- package/dist/chat-quiet.js +161 -0
- package/dist/checkout-cleanup.d.ts +84 -0
- package/dist/checkout-cleanup.js +245 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +3 -0
- package/dist/digest-times.d.ts +3 -0
- package/dist/digest-times.js +7 -0
- package/dist/dispose.js +2 -0
- package/dist/export.js +1 -1
- package/dist/first-run.d.ts +4 -1
- package/dist/first-run.js +2 -1
- package/dist/integrations-ui.d.ts +13 -0
- package/dist/integrations-ui.js +65 -0
- package/dist/integrations.d.ts +113 -0
- package/dist/integrations.js +526 -0
- package/dist/mcp.js +26 -0
- package/dist/operate.d.ts +5 -6
- package/dist/operate.js +254 -25
- package/dist/project-delete.js +1 -0
- package/dist/prompt.d.ts +7 -2
- package/dist/prompt.js +36 -7
- package/dist/publish.d.ts +11 -0
- package/dist/publish.js +9 -2
- package/dist/pull-request-flow.d.ts +140 -0
- package/dist/pull-request-flow.js +440 -0
- package/dist/pull-request-schema.d.ts +5 -0
- package/dist/pull-request-schema.js +21 -0
- package/dist/pull-request-ui.d.ts +23 -0
- package/dist/pull-request-ui.js +55 -0
- package/dist/pulls.d.ts +5 -0
- package/dist/pulls.js +11 -0
- package/dist/serve.d.ts +6 -0
- package/dist/serve.js +323 -26
- package/dist/setup-guide.d.ts +2 -2
- package/dist/storage-ui.d.ts +10 -0
- package/dist/storage-ui.js +67 -0
- package/dist/storage.d.ts +15 -1
- package/dist/storage.js +62 -7
- package/dist/store.d.ts +66 -5
- package/dist/store.js +160 -19
- package/dist/surface.js +2 -0
- package/dist/telegram-progress.d.ts +1 -0
- package/dist/telegram-progress.js +1 -1
- package/dist/telegram.js +95 -15
- package/dist/toolroll-update-ui.d.ts +2 -0
- package/dist/toolroll-update-ui.js +1 -1
- package/dist/toolroll-update.d.ts +26 -6
- package/dist/toolroll-update.js +188 -50
- package/dist/worktree.d.ts +24 -10
- package/dist/worktree.js +84 -44
- package/package.json +1 -1
package/dist/surface.js
CHANGED
|
@@ -118,6 +118,8 @@ export const COMMAND_GUIDE = [
|
|
|
118
118
|
...MODELS_DESCRIPTORS.map(spec => ({ invocation: `models ${spec.action}`, synopsis: spec.synopsis, audience: "agent", agentMayInvoke: true, mutation: spec.mutation, flags: spec.flags, ...(spec.takesQuery ? { positionals: [{ name: "target", required: true, meaning: "the CLI to update, or on/off" }] } : {}) })),
|
|
119
119
|
// ---- the queue (agent surface) ----
|
|
120
120
|
{ invocation: "status", synopsis: "running work, queued reasons, results to review, the latest release check and plan windows", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag] },
|
|
121
|
+
{ invocation: "integrations", synopsis: "every integration as Connected, Not set up or Broken, with its last success and error, what uses it and what to do; --saved skips new checks; never a secret", audience: "agent", agentMayInvoke: true, mutation: "none",
|
|
122
|
+
flags: [jsonFlag, dbFlag, { name: "saved", takesValue: false, meaning: "show the last checks without checking again" }] },
|
|
121
123
|
{ invocation: "ready", synopsis: "what could be dispatched right now (rows carry reservedFor)", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag] },
|
|
122
124
|
{ invocation: "brief", synopsis: "with a saved central profile, --lead <id> --conversation <id> reads messages, proposals and saved work; --request-id inspects your saved receipt without resending; --local uses local DB catch-up, where --history selects the older operational report", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag] },
|
|
123
125
|
{ invocation: "gaps", synopsis: "requirement gaps blocking dispatch", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag, repoFlag] },
|
|
@@ -123,7 +123,7 @@ export function telegramProgressCard(store, run, taskId, project, now = new Date
|
|
|
123
123
|
...(next ? ["", next] : []),
|
|
124
124
|
...(acceptance === null ? [] : [acceptance]),
|
|
125
125
|
...(delivery === null ? [] : ["", delivery]), "", `${projectLabel(project)} · #${run.id}`].join("\n");
|
|
126
|
-
return { text, entities: [{ type: "bold", offset: 0, length: title.length }, { type: "bold", offset: title.length + 1, length: heading.length }],
|
|
126
|
+
return { text, next, entities: [{ type: "bold", offset: 0, length: title.length }, { type: "bold", offset: title.length + 1, length: heading.length }],
|
|
127
127
|
link: { label, path: operatorHold || accessBlocked || (!built && run.outcome !== null)
|
|
128
128
|
? chatControlHref("recovery", taskId) : built ? chatResultHref(taskId, run.id, checksFailed ? "checks" : "summary") : chatControlHref("task", taskId) } };
|
|
129
129
|
}
|
package/dist/telegram.js
CHANGED
|
@@ -29,6 +29,7 @@ import { join } from "node:path";
|
|
|
29
29
|
import { validateNote } from "./decision.js";
|
|
30
30
|
import { isLifecycleNotification, isTelegramProgressNotification, TELEGRAM_HOLD_REASONS } from "./store.js";
|
|
31
31
|
import { telegramProgressCard } from "./telegram-progress.js";
|
|
32
|
+
import { enqueueEveningDigests, isTaskFact, needsPerson, quietCardView, readyPingView } from "./chat-quiet.js";
|
|
32
33
|
import { applyTeamInbound, deliverTeamChats, teamCommand } from "./telegram-team.js";
|
|
33
34
|
import { applyFlowReply, applyFlowTap, FLOW_DECIDE_KEY, flowButtons, flowDecisionAt } from "./telegram-flow.js";
|
|
34
35
|
import { connectChannel, FLOW_WORDS, takeChannelMessage, watchedChannel } from "./chat-inbox.js";
|
|
@@ -519,6 +520,8 @@ async function processConversations(store, botId, transport, owner, clock, repor
|
|
|
519
520
|
function factLinkLabel(path) {
|
|
520
521
|
if (/^\/review\?result=[^&]+&run=\d+&tab=checks$/.test(path))
|
|
521
522
|
return "Inspect result";
|
|
523
|
+
if (/^\/t\/[^?#]+#merge$/.test(path))
|
|
524
|
+
return "Merge";
|
|
522
525
|
if (/^\/chat\?task=[^&]+&result=/.test(path))
|
|
523
526
|
return "Open result";
|
|
524
527
|
if (/^\/(?:chat\?task=|t\/)/.test(path))
|
|
@@ -563,6 +566,13 @@ async function deliverOutbox(store, botId, transport, owner, clock, report, read
|
|
|
563
566
|
}
|
|
564
567
|
const digest = store.telegramDigest();
|
|
565
568
|
const now = clock();
|
|
569
|
+
// An evening digest someone asked for is due: record it as their own notification, delivered below.
|
|
570
|
+
try {
|
|
571
|
+
enqueueEveningDigests(store, now, evidenceRoot);
|
|
572
|
+
}
|
|
573
|
+
catch {
|
|
574
|
+
report.problems.push("evening digest could not be prepared");
|
|
575
|
+
}
|
|
566
576
|
const digestDue = digest.everyMs === null || digest.lastSentAt === null || now.getTime() >= new Date(digest.lastSentAt).getTime() + digest.everyMs;
|
|
567
577
|
// Every paired person is a destination of their own: each binding claims
|
|
568
578
|
// and settles its own rows under its own ceiling, in turn.
|
|
@@ -571,13 +581,16 @@ async function deliverOutbox(store, botId, transport, owner, clock, report, read
|
|
|
571
581
|
}
|
|
572
582
|
async function deliverOutboxTo(store, botId, binding, transport, owner, clock, report, digest, digestDue, readProjects, canDeliver, phoneOrigin, evidenceRoot) {
|
|
573
583
|
const now = clock();
|
|
574
|
-
|
|
584
|
+
// Only when I'm needed (the default): a task's facts edit its one card and only what needs this person makes a
|
|
585
|
+
// new message, so the installation's routine-fact cadence does not apply. Every step keeps today's behaviour.
|
|
586
|
+
const quiet = store.notificationPreference(binding.approver).mode === "quiet";
|
|
587
|
+
const claimed = store.claimTelegramDeliveries(binding, owner, DELIVERY_CLAIM_MS, now, quiet || digestDue ? "all" : "urgent");
|
|
575
588
|
// Preserve ID order, flushing earlier routine facts before an urgent task
|
|
576
589
|
// update. An earlier failed/retrying row also fences later rows for that task.
|
|
577
590
|
const groups = [];
|
|
578
591
|
for (const row of claimed) {
|
|
579
592
|
const last = groups[groups.length - 1];
|
|
580
|
-
if (digest.everyMs !== null && !isUrgent(row) && last !== undefined && !isUrgent(last[0]))
|
|
593
|
+
if (!quiet && digest.everyMs !== null && !isUrgent(row) && last !== undefined && !isUrgent(last[0]))
|
|
581
594
|
last.push(row);
|
|
582
595
|
else
|
|
583
596
|
groups.push([row]);
|
|
@@ -638,12 +651,12 @@ async function deliverOutboxTo(store, botId, binding, transport, owner, clock, r
|
|
|
638
651
|
}
|
|
639
652
|
return null;
|
|
640
653
|
};
|
|
641
|
-
const sender = async (text, keyboard, messageRows = rows, entities) => {
|
|
654
|
+
const sender = async (text, keyboard, messageRows = rows, entities, silent) => {
|
|
642
655
|
// Finish every await before the synchronous fence and transport call.
|
|
643
656
|
const problem = (await readAccess()) ?? fence();
|
|
644
657
|
if (problem !== null)
|
|
645
658
|
return { ok: false, error: problem };
|
|
646
|
-
const sent = await send(transport, binding.chatId, text, keyboard, entities);
|
|
659
|
+
const sent = await send(transport, binding.chatId, text, keyboard, entities, silent);
|
|
647
660
|
if (!sent.ok) {
|
|
648
661
|
if (sent.retryAfter !== undefined)
|
|
649
662
|
store.deferTelegram(botId, new Date(clock().getTime() + sent.retryAfter * 1_000).toISOString());
|
|
@@ -694,7 +707,7 @@ async function deliverOutboxTo(store, botId, binding, transport, owner, clock, r
|
|
|
694
707
|
const after = (await readAccess()) ?? fence();
|
|
695
708
|
return after === null ? { ok: true, receipt: receiptFor(botId, binding.chatId, String(messageId)) } : { ok: false, error: after };
|
|
696
709
|
};
|
|
697
|
-
const batched = digest.everyMs !== null && !isUrgent(rows[0]);
|
|
710
|
+
const batched = !quiet && digest.everyMs !== null && !isUrgent(rows[0]);
|
|
698
711
|
const row = rows[0];
|
|
699
712
|
const progressRun = batched ? null : store.telegramProgressRun(row);
|
|
700
713
|
const progress = progressRun !== null && isTelegramProgressNotification(row);
|
|
@@ -731,15 +744,80 @@ async function deliverOutboxTo(store, botId, binding, transport, owner, clock, r
|
|
|
731
744
|
const after = (await readAccess()) ?? fence();
|
|
732
745
|
return after === null ? edited : { ok: false, error: after };
|
|
733
746
|
};
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
747
|
+
/** Quiet mode: the task's one card (or its group's), created silently and then only ever edited. */
|
|
748
|
+
const updateCard = async (fact) => {
|
|
749
|
+
const problem = (await readAccess()) ?? fence();
|
|
750
|
+
if (problem !== null)
|
|
751
|
+
return { ok: false, error: problem };
|
|
752
|
+
const card = store.chatCardFor(fact.destination, fact.taskRef, store.getTask(fact.taskId)?.createdAt ?? fact.createdAt, clock());
|
|
753
|
+
const view = quietCardView(store, card.tasks, clock(), evidenceRoot);
|
|
754
|
+
if (view === null)
|
|
755
|
+
return { ok: true, messageId: card.message };
|
|
756
|
+
let button = null;
|
|
757
|
+
try {
|
|
758
|
+
button = phoneLinkButton(phoneOrigin?.() ?? null, view.link);
|
|
759
|
+
}
|
|
760
|
+
catch { /* No trusted origin. */ }
|
|
761
|
+
const keyboard = button === null ? [] : [button];
|
|
762
|
+
const shown = createHash("sha256").update(JSON.stringify([view.text, view.entities, keyboard])).digest("hex");
|
|
763
|
+
if (card.message !== null && card.digest === shown) {
|
|
764
|
+
store.recordTelegramMessage(fact, binding, card.message, clock());
|
|
765
|
+
return { ok: true, messageId: card.message };
|
|
766
|
+
}
|
|
767
|
+
if (card.message !== null) {
|
|
768
|
+
const edited = await editProgress(transport, binding.chatId, card.message, view.text, keyboard, view.entities);
|
|
769
|
+
if (edited.ok) {
|
|
770
|
+
store.setChatCardMessage(card.id, card.message, shown);
|
|
771
|
+
store.recordTelegramMessage(fact, binding, card.message, clock());
|
|
772
|
+
const after = (await readAccess()) ?? fence();
|
|
773
|
+
return after === null ? edited : { ok: false, error: after };
|
|
774
|
+
}
|
|
775
|
+
if (edited.retryAfter !== undefined)
|
|
776
|
+
store.deferTelegram(botId, new Date(clock().getTime() + edited.retryAfter * 1000).toISOString());
|
|
777
|
+
// Only Telegram's definitive missing/uneditable answer permits a replacement card.
|
|
778
|
+
if (!edited.replace)
|
|
779
|
+
return edited;
|
|
780
|
+
}
|
|
781
|
+
const sent = await sender(view.text, keyboard, [fact], view.entities, true);
|
|
782
|
+
// A card that reached the chat is kept even if a later fence refused the acknowledgement: never a second card.
|
|
783
|
+
const placed = sent.ok ? sent.messageId : store.telegramMessageOf(fact.id, fact.destination);
|
|
784
|
+
if (placed !== null)
|
|
785
|
+
store.setChatCardMessage(card.id, placed, shown);
|
|
786
|
+
return sent;
|
|
787
|
+
};
|
|
788
|
+
const quietOutcome = async (fact) => {
|
|
789
|
+
const card = await updateCard(fact);
|
|
790
|
+
if (!card.ok)
|
|
791
|
+
return card;
|
|
792
|
+
if (!needsPerson(fact))
|
|
793
|
+
return { ok: true, receipt: receiptFor(botId, binding.chatId, card.messageId) };
|
|
794
|
+
const readyRun = fact.kind === "run-finished" ? store.telegramProgressRun(fact) : null;
|
|
795
|
+
if (readyRun !== null) {
|
|
796
|
+
const ping = readyPingView(store, store.getRun(readyRun.id), fact.taskId, fact.project, clock(), evidenceRoot);
|
|
797
|
+
let button = null;
|
|
798
|
+
try {
|
|
799
|
+
button = phoneLinkButton(phoneOrigin?.() ?? null, ping.link);
|
|
800
|
+
}
|
|
801
|
+
catch { /* No trusted origin. */ }
|
|
802
|
+
const sent = await sender(ping.text, button === null ? undefined : [button], [fact], ping.entities);
|
|
803
|
+
return sent.ok ? { ok: true, receipt: receiptFor(botId, binding.chatId, sent.messageId) } : sent;
|
|
804
|
+
}
|
|
805
|
+
return fact.kind === "acceptance-evidence" ? imageSender(fact) : deliverOne(store, botId, binding, sender, fact, clock, phoneOrigin, evidenceRoot, projects);
|
|
806
|
+
};
|
|
807
|
+
let outcome;
|
|
808
|
+
if (quiet && rows.length === 1 && isTaskFact(row))
|
|
809
|
+
outcome = await quietOutcome(row);
|
|
810
|
+
else {
|
|
811
|
+
// A failure or decision still gets its own alert. Refresh an existing
|
|
812
|
+
// card first so it does not keep saying the build is running.
|
|
813
|
+
if (!progress && progressRun !== null)
|
|
814
|
+
await updateProgress(true);
|
|
815
|
+
const updated = progress ? await updateProgress(false) : null;
|
|
816
|
+
outcome = updated !== null ? updated.ok ? { ok: true, receipt: receiptFor(botId, binding.chatId, updated.messageId) } : updated
|
|
817
|
+
: rows[0].kind === "acceptance-evidence" ? await imageSender(rows[0]) : batched
|
|
818
|
+
? await deliverDigest(botId, binding, sender, rows, digest.lastSentAt, clock)
|
|
819
|
+
: await deliverOne(store, botId, binding, sender, rows[0], clock, phoneOrigin, evidenceRoot, projects);
|
|
820
|
+
}
|
|
743
821
|
const finalProblem = outcome.ok ? (await readAccess()) ?? fence() : null;
|
|
744
822
|
const settled = finalProblem === null ? outcome : { ok: false, error: finalProblem };
|
|
745
823
|
// A skipped screenshot settles its row but nothing reached the phone.
|
|
@@ -934,7 +1012,7 @@ async function deliverOne(store, botId, binding, sender, notification, clock, ph
|
|
|
934
1012
|
}
|
|
935
1013
|
return { ok: true, receipt: receiptFor(botId, binding.chatId, sent.messageId) };
|
|
936
1014
|
}
|
|
937
|
-
async function send(transport, chatId, text, keyboard, entities) {
|
|
1015
|
+
async function send(transport, chatId, text, keyboard, entities, silent) {
|
|
938
1016
|
// No markup parsing. Only machine-selected heading ranges may be bold;
|
|
939
1017
|
// agent text remains literal and URLs never trigger link previews.
|
|
940
1018
|
let answer;
|
|
@@ -944,6 +1022,8 @@ async function send(transport, chatId, text, keyboard, entities) {
|
|
|
944
1022
|
text,
|
|
945
1023
|
...(entities === undefined ? {} : { entities }),
|
|
946
1024
|
link_preview_options: { is_disabled: true },
|
|
1025
|
+
// A new quiet card arrives without a sound; only a ping should buzz.
|
|
1026
|
+
...(silent === true ? { disable_notification: true } : {}),
|
|
947
1027
|
...(keyboard === undefined ? {} : { reply_markup: { inline_keyboard: keyboard } }),
|
|
948
1028
|
});
|
|
949
1029
|
}
|
|
@@ -24,6 +24,8 @@ export type UpdatesView = {
|
|
|
24
24
|
version: string;
|
|
25
25
|
notes: string[];
|
|
26
26
|
} | null;
|
|
27
|
+
/** The version `toolroll update --rollback` returns to: the last completed update's, while it is what runs. */
|
|
28
|
+
rollbackTo: string | null;
|
|
27
29
|
csrf: string;
|
|
28
30
|
};
|
|
29
31
|
/** The steps, each done, current, failed or waiting. Also the live region's fragment. */
|
|
@@ -70,7 +70,7 @@ export function updatesHtml(view, notice) {
|
|
|
70
70
|
`<div class="update-actions"><button type="submit" name="when" value="now" class="primary">Update now</button>` +
|
|
71
71
|
`<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
72
|
: "";
|
|
73
|
-
const rollback =
|
|
73
|
+
const rollback = view.rollbackTo !== null ? `<p class="meta">To go back to ${e(view.rollbackTo)}: <code>toolroll update --rollback</code></p>` : "";
|
|
74
74
|
return `<section class="updates">${note}${whatsNew}${j ? outcomeHtml(j) : ""}<div class="card" data-update-state="${newer ? "available" : "current"}">${state}${form}${rollback}</div></section>`;
|
|
75
75
|
}
|
|
76
76
|
export function newerThan(a, b) {
|
|
@@ -67,10 +67,12 @@ export type RuntimeUpdateJournal = {
|
|
|
67
67
|
unit: string;
|
|
68
68
|
pids: number[];
|
|
69
69
|
};
|
|
70
|
-
/** Each repo's watch daemon that runs this version, recorded the same way:
|
|
70
|
+
/** Each repo's watch daemon that runs this version, recorded the same way: switched with the service, and stopped and
|
|
71
|
+
* restarted with it only when launchd had it loaded before the update (`loaded` absent: 0.8.1 stopped every one). */
|
|
71
72
|
watches?: {
|
|
72
73
|
unit: string;
|
|
73
74
|
pids: number[];
|
|
75
|
+
loaded?: boolean;
|
|
74
76
|
}[];
|
|
75
77
|
/** Recorded before each change so a resumed or failed run knows what to put back. */
|
|
76
78
|
switched?: {
|
|
@@ -88,10 +90,15 @@ export type RuntimeUpdateJournal = {
|
|
|
88
90
|
}[];
|
|
89
91
|
databaseRestored?: boolean;
|
|
90
92
|
};
|
|
91
|
-
/** What the live database held when a failed run restored its backup: nothing written is lost. */
|
|
93
|
+
/** What the live database held when a failed run restored its backup: nothing written is lost. The newest of `kept`. */
|
|
92
94
|
keptAside?: string;
|
|
93
95
|
/** The live database could not be read, so it was moved aside whole rather than copied. */
|
|
94
96
|
keptAsideUnreadable?: boolean;
|
|
97
|
+
/** Every copy kept aside, oldest first: a retried restore adds one and never drops the pointer to an earlier one. */
|
|
98
|
+
kept?: {
|
|
99
|
+
path: string;
|
|
100
|
+
unreadable: boolean;
|
|
101
|
+
}[];
|
|
95
102
|
/** The restore put the backup back: a retried restore never puts it back again (what was written since belongs to
|
|
96
103
|
* the restored version and would be lost), and it keeps a fresh copy aside before every attempt until then. */
|
|
97
104
|
restoredDatabase?: boolean;
|
|
@@ -129,6 +136,8 @@ export type UpdateSystem = {
|
|
|
129
136
|
}) => Promise<void>;
|
|
130
137
|
/** The processes the service runs now. */
|
|
131
138
|
servicePids: (unit: string) => Promise<number[]>;
|
|
139
|
+
/** Whether launchd has the service loaded now. */
|
|
140
|
+
serviceLoaded: (unit: string) => Promise<boolean>;
|
|
132
141
|
/** Unload the service; resolves once launchd no longer has it. */
|
|
133
142
|
stopService: (unit: string) => Promise<void>;
|
|
134
143
|
/** Load and start the service from its definition on disk. */
|
|
@@ -138,8 +147,11 @@ export type UpdateSystem = {
|
|
|
138
147
|
healthTimeoutMs?: number;
|
|
139
148
|
/** How long stopped service processes may take to exit. */
|
|
140
149
|
exitTimeoutMs?: number;
|
|
141
|
-
/**
|
|
142
|
-
|
|
150
|
+
/** Bytes free for this user in the folder `dir` is on. */
|
|
151
|
+
freeBytes?: (dir: string) => number;
|
|
152
|
+
/** Fault injection for state-machine tests, never selectable by a flag. `kept-aside`: the live database was just
|
|
153
|
+
* kept aside, before the backup is put back. */
|
|
154
|
+
checkpoint?: (phase: RuntimePhase | "kept-aside") => void;
|
|
143
155
|
};
|
|
144
156
|
export type UpdateOutcome = {
|
|
145
157
|
ok: boolean;
|
|
@@ -211,7 +223,10 @@ export declare function startRuntimeRollback(o: {
|
|
|
211
223
|
export declare function resumeRuntimeUpdate(stateDir: string, system: UpdateSystem, id?: string): Promise<UpdateOutcome>;
|
|
212
224
|
/** A prepared update whose job could not start. */
|
|
213
225
|
export declare function abandonRuntimeUpdate(stateDir: string, id: string, why: string, now: Date): void;
|
|
214
|
-
|
|
226
|
+
/** `locked`: a test's seam, called once the updater's lock is held and before the journal is read again. */
|
|
227
|
+
export declare function requestRuntimeUpdateCancel(stateDir: string, now?: Date, seams?: {
|
|
228
|
+
locked?: () => void;
|
|
229
|
+
}): string;
|
|
215
230
|
/** Keep the newest release-* runtimes (and any in `keep`), at most KEEP_RUNTIMES; deploy-browser's browser-* and
|
|
216
231
|
* the rollback-* records are not this updater's to remove. */
|
|
217
232
|
export declare function pruneRuntimes(stateDir: string, keep: readonly string[]): string[];
|
|
@@ -223,6 +238,11 @@ export type RuntimeUpdateStatus = {
|
|
|
223
238
|
version: string;
|
|
224
239
|
notes: string[];
|
|
225
240
|
} | null;
|
|
241
|
+
/** The last completed update `--rollback` returns from, whatever was attempted since. */
|
|
242
|
+
lastUpdate: {
|
|
243
|
+
from: string;
|
|
244
|
+
to: string;
|
|
245
|
+
} | null;
|
|
226
246
|
};
|
|
227
247
|
export declare function runtimeUpdateStatus(stateDir: string): RuntimeUpdateStatus;
|
|
228
248
|
export declare function markWhatsNewSeen(stateDir: string): void;
|
|
@@ -261,7 +281,7 @@ export declare function launchRuntimeUpdate(args: {
|
|
|
261
281
|
home?: string;
|
|
262
282
|
run?: SupervisorRunner;
|
|
263
283
|
platform?: NodeJS.Platform;
|
|
264
|
-
npmBin?: () => string | null
|
|
284
|
+
npmBin?: () => Promise<string | null>;
|
|
265
285
|
}): Promise<void>;
|
|
266
286
|
/** The job's last act: its definition goes, so nothing can start it again. Only the definition for this id. */
|
|
267
287
|
export declare function retireUpdateJob(id: string, home?: string): void;
|