@sealant/mend 0.36.0-next.628 → 0.36.0-next.643
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/dist/{chunk-OTYH35OK.js → chunk-2TDRYRGO.js} +78 -3
- package/dist/{dashboard-P73HKQOT.js → dashboard-2HF3KTTU.js} +9 -1
- package/dist/main.js +392 -21
- package/man/mend-accounts.1 +1 -1
- package/man/mend-adopt.1 +1 -1
- package/man/mend-attach.1 +1 -1
- package/man/mend-codex.1 +1 -1
- package/man/mend-completions.1 +1 -1
- package/man/mend-connect-pi.1 +1 -1
- package/man/mend-connect.1 +1 -1
- package/man/mend-continue.1 +1 -1
- package/man/mend-doctor.1 +1 -1
- package/man/mend-dotfiles-repo.1 +1 -1
- package/man/mend-dotfiles-sync.1 +1 -1
- package/man/mend-dotfiles.1 +1 -1
- package/man/mend-env-cluster.1 +1 -1
- package/man/mend-env-load.1 +1 -1
- package/man/mend-env-show.1 +1 -1
- package/man/mend-folder-create.1 +1 -1
- package/man/mend-folder-list.1 +1 -1
- package/man/mend-folder-push.1 +1 -1
- package/man/mend-folder-rm.1 +1 -1
- package/man/mend-git-author.1 +1 -1
- package/man/mend-help.1 +1 -1
- package/man/mend-invite.1 +1 -1
- package/man/mend-keys-init.1 +1 -1
- package/man/mend-keys-mode.1 +1 -1
- package/man/mend-keys-share.1 +1 -1
- package/man/mend-keys-show.1 +1 -1
- package/man/mend-land.1 +1 -1
- package/man/mend-login.1 +1 -1
- package/man/mend-logout.1 +1 -1
- package/man/mend-man.1 +1 -1
- package/man/mend-members.1 +1 -1
- package/man/mend-memory-import.1 +1 -1
- package/man/mend-memory-rm.1 +1 -1
- package/man/mend-memory-show.1 +1 -1
- package/man/mend-memory.1 +1 -1
- package/man/mend-models.1 +1 -1
- package/man/mend-operator-exposure.1 +1 -1
- package/man/mend-operator-gate.1 +1 -1
- package/man/mend-operator-grant-owner.1 +1 -1
- package/man/mend-operator-org-create.1 +1 -1
- package/man/mend-operator-org-invite-owner.1 +1 -1
- package/man/mend-operator-org-list.1 +1 -1
- package/man/mend-operator-org-rename.1 +1 -1
- package/man/mend-operator-reset-link.1 +1 -1
- package/man/mend-pair.1 +1 -1
- package/man/mend-projects.1 +1 -1
- package/man/mend-pull.1 +1 -1
- package/man/mend-refresh.1 +1 -1
- package/man/mend-rejoin.1 +1 -1
- package/man/mend-resume.1 +1 -1
- package/man/mend-run.1 +1 -1
- package/man/mend-secrets-add.1 +1 -1
- package/man/mend-secrets-rm.1 +1 -1
- package/man/mend-secrets.1 +1 -1
- package/man/mend-server-logs.1 +1 -1
- package/man/mend-server-restart.1 +1 -1
- package/man/mend-server-setup.1 +1 -1
- package/man/mend-server-start.1 +1 -1
- package/man/mend-server-status.1 +1 -1
- package/man/mend-server-stop.1 +1 -1
- package/man/mend-server-upgrade.1 +9 -2
- package/man/mend-server.1 +1 -1
- package/man/mend-service-add.1 +1 -1
- package/man/mend-service-connect.1 +1 -1
- package/man/mend-service-init.1 +1 -1
- package/man/mend-service-list.1 +1 -1
- package/man/mend-service-logs.1 +1 -1
- package/man/mend-service-restart.1 +1 -1
- package/man/mend-service-run.1 +1 -1
- package/man/mend-service-stop.1 +1 -1
- package/man/mend-session-share.1 +1 -1
- package/man/mend-sessions.1 +1 -1
- package/man/mend-shell.1 +1 -1
- package/man/mend-skills-push.1 +1 -1
- package/man/mend-skills.1 +1 -1
- package/man/mend-snake.1 +1 -1
- package/man/mend-ssh-setup.1 +1 -1
- package/man/mend-ssh.1 +1 -1
- package/man/mend-stop.1 +1 -1
- package/man/mend-ui.1 +1 -1
- package/man/mend-uninstall.1 +1 -1
- package/man/mend-version.1 +1 -1
- package/man/mend-worktrees-rm.1 +1 -1
- package/man/mend-worktrees.1 +1 -1
- package/man/mend.1 +1 -1
- package/package.json +2 -2
|
@@ -26965,13 +26965,17 @@ var sameGrant = (left, right) => {
|
|
|
26965
26965
|
var LAUNCH_WAITING_PREFIX = "waiting \xB7 the previous session in this worktree";
|
|
26966
26966
|
var LAUNCH_WAITING_SAVING = `${LAUNCH_WAITING_PREFIX} is saving`;
|
|
26967
26967
|
var LAUNCH_BOOTING = "booting";
|
|
26968
|
+
var LAUNCH_QUEUED = "queued \xB7 waiting for a worker";
|
|
26969
|
+
var LAUNCH_BUILDING_PREFIX = "building the workspace image";
|
|
26968
26970
|
var LAUNCH_PREPARING = "preparing the workspace \xB7 no runtime yet \xB7 after an update, building the image takes about 8 minutes";
|
|
26969
26971
|
var LAUNCH_BUILDING_IMAGE_LEGACY = "building the workspace image (first launch after an update, ~8 min)";
|
|
26970
26972
|
var LAUNCH_PHASE_PREFIXES = [
|
|
26971
26973
|
LAUNCH_WAITING_PREFIX,
|
|
26972
26974
|
LAUNCH_BOOTING,
|
|
26975
|
+
LAUNCH_QUEUED,
|
|
26973
26976
|
LAUNCH_PREPARING,
|
|
26974
|
-
LAUNCH_BUILDING_IMAGE_LEGACY
|
|
26977
|
+
LAUNCH_BUILDING_IMAGE_LEGACY,
|
|
26978
|
+
LAUNCH_BUILDING_PREFIX
|
|
26975
26979
|
];
|
|
26976
26980
|
var phaseWordsOf = (summary) => {
|
|
26977
26981
|
for (const prefix of LAUNCH_PHASE_PREFIXES) {
|
|
@@ -26995,6 +26999,12 @@ var launchPhaseOf = (summary) => {
|
|
|
26995
26999
|
return { kind: "waiting-previous", words: phase.words };
|
|
26996
27000
|
}
|
|
26997
27001
|
if (phase.words.startsWith(LAUNCH_BOOTING)) return { kind: "booting", words: phase.words };
|
|
27002
|
+
if (phase.words.startsWith(LAUNCH_QUEUED)) return { kind: "queued", words: phase.words };
|
|
27003
|
+
if (phase.words === LAUNCH_BUILDING_IMAGE_LEGACY)
|
|
27004
|
+
return { kind: "preparing", words: phase.words };
|
|
27005
|
+
if (phase.words.startsWith(LAUNCH_BUILDING_PREFIX)) {
|
|
27006
|
+
return { kind: "building", words: phase.words };
|
|
27007
|
+
}
|
|
26998
27008
|
return { kind: "preparing", words: phase.words };
|
|
26999
27009
|
};
|
|
27000
27010
|
|
|
@@ -27127,6 +27137,9 @@ var AuditAction = Schema_exports.Literals([
|
|
|
27127
27137
|
"session.shared_control_off",
|
|
27128
27138
|
// The owner ended a session's workspace with captures still pending: work was discarded.
|
|
27129
27139
|
"session.unsaved_discarded",
|
|
27140
|
+
// Mend stopped a session whose owner no longer has access to where it ran (mend#558): a removed
|
|
27141
|
+
// member, or a joiner who can no longer see the project. The session's owner is the actor.
|
|
27142
|
+
"session.stopped_no_access",
|
|
27130
27143
|
"member.password_reset_issued",
|
|
27131
27144
|
"organization.created",
|
|
27132
27145
|
"organization.renamed",
|
|
@@ -28105,6 +28118,14 @@ var Session = class extends Schema_exports.Class("Session")({
|
|
|
28105
28118
|
sharedControlEnabledAt: Schema_exports.NullOr(Timestamp).pipe(
|
|
28106
28119
|
Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
|
|
28107
28120
|
),
|
|
28121
|
+
/**
|
|
28122
|
+
* When shared control was first turned on, kept after it is turned off (docs/adr/0016,
|
|
28123
|
+
* decision 9): a session once shared runs on no one's memory and credits nobody until it ends.
|
|
28124
|
+
*/
|
|
28125
|
+
sharedControlEverAt: Schema_exports.NullOr(Timestamp).pipe(
|
|
28126
|
+
Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(null)),
|
|
28127
|
+
Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
|
|
28128
|
+
),
|
|
28108
28129
|
/**
|
|
28109
28130
|
* Whether the harness left a conversation behind — a transcript Mend captured at settle or
|
|
28110
28131
|
* found in the live harness home. False is a dead end: nothing to resume, nothing to hand
|
|
@@ -28436,7 +28457,7 @@ var ProjectClusterBindingsSnapshot = class extends Schema_exports.Class(
|
|
|
28436
28457
|
}) {
|
|
28437
28458
|
};
|
|
28438
28459
|
|
|
28439
|
-
// ../../node_modules/.pnpm/@sealant+api-contracts-next@0.39.0-next.
|
|
28460
|
+
// ../../node_modules/.pnpm/@sealant+api-contracts-next@0.39.0-next.706_effect@4.0.0-beta.93/node_modules/@sealant/api-contracts-next/dist/workspace-environment.js
|
|
28440
28461
|
var RESERVED_NAMES = new Map([
|
|
28441
28462
|
// Identity/process roots the daemon and shells own.
|
|
28442
28463
|
...[
|
|
@@ -28607,7 +28628,17 @@ var SessionProcess = class extends Schema_exports.Class("SessionProcess")({
|
|
|
28607
28628
|
Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
|
|
28608
28629
|
),
|
|
28609
28630
|
exitedAt: Schema_exports.NullOr(Timestamp),
|
|
28610
|
-
updatedAt: Timestamp
|
|
28631
|
+
updatedAt: Timestamp,
|
|
28632
|
+
/**
|
|
28633
|
+
* The Mend account whose Linux user the process runs as in a person-layout executor
|
|
28634
|
+
* (docs/adr/0016, decision 1: "the person a process runs as is recorded on the process when it
|
|
28635
|
+
* starts"). Null for a process that runs as root (a `shared` executor), on rows from before it
|
|
28636
|
+
* was recorded, and where older servers omit it.
|
|
28637
|
+
*/
|
|
28638
|
+
runsAs: Schema_exports.NullOr(Schema_exports.String).pipe(
|
|
28639
|
+
Schema_exports.withDecodingDefaultKey(Effect_exports.succeed(null)),
|
|
28640
|
+
Schema_exports.withConstructorDefault(Effect_exports.succeed(null))
|
|
28641
|
+
)
|
|
28611
28642
|
}) {
|
|
28612
28643
|
};
|
|
28613
28644
|
|
|
@@ -29064,6 +29095,50 @@ var SlackLinkedMentionJob = Schema_exports.Struct({
|
|
|
29064
29095
|
linkedAt: Schema_exports.String
|
|
29065
29096
|
});
|
|
29066
29097
|
|
|
29098
|
+
// ../../packages/domain/src/workbench/steering.ts
|
|
29099
|
+
var ConversationWaitWork = Schema_exports.Struct({
|
|
29100
|
+
kind: Schema_exports.Literals([
|
|
29101
|
+
"task",
|
|
29102
|
+
"paused-task",
|
|
29103
|
+
"sub-agent",
|
|
29104
|
+
"terminal",
|
|
29105
|
+
"goal",
|
|
29106
|
+
"wakeup",
|
|
29107
|
+
"monitor",
|
|
29108
|
+
"cron",
|
|
29109
|
+
"unknown"
|
|
29110
|
+
]),
|
|
29111
|
+
/** The harness's own id: what ending it names. */
|
|
29112
|
+
id: Schema_exports.String,
|
|
29113
|
+
description: Schema_exports.NullOr(Schema_exports.String),
|
|
29114
|
+
/**
|
|
29115
|
+
* The person the process runs as, or the session's owner, can end it from the waiting line
|
|
29116
|
+
* (Claude's task stop, a monitor's included, Codex's terminal terminate and goal clear). A
|
|
29117
|
+
* wakeup ends on its own within an hour; a scheduled prompt and what the harness would not say
|
|
29118
|
+
* are waited for at most `CONVERSATION_WAIT_BOUNDS_MS`.
|
|
29119
|
+
*/
|
|
29120
|
+
endable: Schema_exports.Boolean
|
|
29121
|
+
});
|
|
29122
|
+
var ConversationWait = class extends Schema_exports.Class("ConversationWait")({
|
|
29123
|
+
sessionId: SessionId,
|
|
29124
|
+
/** The turn that waits; the turns behind it wait with it. */
|
|
29125
|
+
turnId: AgentTurnId,
|
|
29126
|
+
/** Whose process finishes its work: the person it runs as. */
|
|
29127
|
+
runsAs: Schema_exports.NullOr(Schema_exports.String),
|
|
29128
|
+
/** Whose turn waits. */
|
|
29129
|
+
sender: Schema_exports.String,
|
|
29130
|
+
/** A turn still runs in the process. */
|
|
29131
|
+
openTurn: Schema_exports.Boolean,
|
|
29132
|
+
work: Schema_exports.Array(ConversationWaitWork),
|
|
29133
|
+
/** The waiting line, in words: "Waits for Alice's 2 background tasks … before Bob's turn starts." */
|
|
29134
|
+
line: Schema_exports.String,
|
|
29135
|
+
since: Timestamp
|
|
29136
|
+
}) {
|
|
29137
|
+
};
|
|
29138
|
+
var CONVERSATION_WAIT_BOUNDS_MS = {
|
|
29139
|
+
cron: 10 * 6e4
|
|
29140
|
+
};
|
|
29141
|
+
|
|
29067
29142
|
// ../../packages/domain/src/workbench/tour.ts
|
|
29068
29143
|
var TourStop = class extends Schema_exports.Class("TourStop")({
|
|
29069
29144
|
title: Schema_exports.String,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
repositoryCloneUrlIssue,
|
|
18
18
|
servicesHoldLine,
|
|
19
19
|
withoutLaunchPhase
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-2TDRYRGO.js";
|
|
21
21
|
|
|
22
22
|
// src/dashboard.tsx
|
|
23
23
|
import { CliRenderEvents, createCliRenderer } from "@opentui/core";
|
|
@@ -271,6 +271,10 @@ var startingWordsOf = (session) => {
|
|
|
271
271
|
return phase.words.endsWith("is saving") ? "waiting for the previous save" : "waiting for the previous session";
|
|
272
272
|
case "booting":
|
|
273
273
|
return "booting";
|
|
274
|
+
case "queued":
|
|
275
|
+
return "queued";
|
|
276
|
+
case "building":
|
|
277
|
+
return "building the image";
|
|
274
278
|
case "preparing":
|
|
275
279
|
return "preparing the workspace";
|
|
276
280
|
}
|
|
@@ -283,6 +287,10 @@ var startingExplanationOf = (session) => {
|
|
|
283
287
|
return phase.words.endsWith("is saving") ? "the previous session in this worktree is still saving \xB7 this one starts from its save" : phase.words;
|
|
284
288
|
case "booting":
|
|
285
289
|
return "the workspace is booting \xB7 the agent starts when it is up";
|
|
290
|
+
case "queued":
|
|
291
|
+
return "the launch waits for a worker \xB7 it starts when one takes it";
|
|
292
|
+
case "building":
|
|
293
|
+
return `${phase.words} \xB7 the agent starts once it is built and booted`;
|
|
286
294
|
case "preparing":
|
|
287
295
|
return "the workspace has no runtime yet \xB7 after an update, building its image takes about 8 minutes";
|
|
288
296
|
}
|
package/dist/main.js
CHANGED
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
trackBracketedPaste,
|
|
53
53
|
validatePiProfile,
|
|
54
54
|
validateSecretFilePath
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-2TDRYRGO.js";
|
|
56
56
|
|
|
57
57
|
// src/main.ts
|
|
58
58
|
import { spawn as spawn3, spawnSync as spawnSync6 } from "node:child_process";
|
|
@@ -2814,12 +2814,16 @@ var COMMANDS = [
|
|
|
2814
2814
|
name: "server upgrade",
|
|
2815
2815
|
section: "this machine",
|
|
2816
2816
|
summary: "upgrade to an explicit version with a database backup",
|
|
2817
|
-
synopsis: [
|
|
2817
|
+
synopsis: [
|
|
2818
|
+
"--version <target|latest> [--assets-dir <dir>] [--offline] [--from-preview] [--keep-backups <n>]"
|
|
2819
|
+
],
|
|
2818
2820
|
description: [
|
|
2819
2821
|
"Preflights release assets and the canonical image's version label before interrupting Mend. Downgrades are refused. latest is resolved only when explicitly requested; a same-version request does nothing.",
|
|
2820
2822
|
"The installed configuration stays: the bind, the origin, the ports, the edge host and the declared exposure and tenancy are carried into the new generation, which renders the same overlays beside the new compose.yaml. An upgrade never drops the edge or the posture; mend server setup is where they change.",
|
|
2821
2823
|
"Stops app writers, starts official Postgres if needed, and streams pg_dumpall into a private database backup before selecting and starting the target. Connections are interrupted. Workspace containers and data are retained, but active work can lose connectivity and need reconnection. Stop any external database writers before upgrading.",
|
|
2822
|
-
"Preflight or backup failure retains the old pin and attempts to recover the old app if it was running. Once target startup may have begun, Mend never automatically downgrades or restores the database. The target pin, old generation and backup remain. Inspect logs, fix the target, then use mend server start. Recovery records are under the installation's backups/upgrade-UUID directory."
|
|
2824
|
+
"Preflight or backup failure retains the old pin and attempts to recover the old app if it was running. Once target startup may have begun, Mend never automatically downgrades or restores the database. The target pin, old generation and backup remain. Inspect logs, fix the target, then use mend server start. Recovery records are under the installation's backups/upgrade-UUID directory.",
|
|
2825
|
+
"After the target answers health, its recovery record is marked completed and older completed backups are removed, keeping the newest two (this one included) in the order Mend wrote them; each removal is printed with the space it freed. A failed upgrade removes nothing. A backup this release recorded as pending, or whose dump is incomplete, is always kept. Each dump holds the whole database, so it can run to gigabytes.",
|
|
2826
|
+
'Backups written by releases before 0.36 carry no outcome: the first upgrade on 0.36 or later treats each one whose dump is whole as completed and keeps only the newest N, so copy any you want to keep out of backups/ first. Their removals are marked "from before 0.36, no recorded outcome".'
|
|
2823
2827
|
],
|
|
2824
2828
|
options: [
|
|
2825
2829
|
{
|
|
@@ -2837,6 +2841,10 @@ var COMMANDS = [
|
|
|
2837
2841
|
{
|
|
2838
2842
|
flag: "--from-preview",
|
|
2839
2843
|
text: "once, from a preview numbered X.Y.Z-preview.K to a next build X.Y.Z-next.N; refused unless the target carries every migration the server applied"
|
|
2844
|
+
},
|
|
2845
|
+
{
|
|
2846
|
+
flag: "--keep-backups <n>",
|
|
2847
|
+
text: "completed upgrade backups to keep after a healthy upgrade, this one included; 0 keeps all. Default: 2"
|
|
2840
2848
|
}
|
|
2841
2849
|
],
|
|
2842
2850
|
examples: [
|
|
@@ -5993,6 +6001,286 @@ var commitGeneration = (paths, files) => {
|
|
|
5993
6001
|
activateGeneration(paths, generation);
|
|
5994
6002
|
return generation;
|
|
5995
6003
|
};
|
|
6004
|
+
var renderRecovery = (record2) => `${JSON.stringify(record2, null, 2)}
|
|
6005
|
+
`;
|
|
6006
|
+
var BACKUP_NAME = /^upgrade-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
6007
|
+
var REMOVING_NAME = /^upgrade-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.removing$/;
|
|
6008
|
+
var RECOVERY_TEMPORARY = /^\.recovery-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
6009
|
+
var lstatOptional = (file) => {
|
|
6010
|
+
try {
|
|
6011
|
+
return fs14.lstatSync(file);
|
|
6012
|
+
} catch (cause) {
|
|
6013
|
+
if (hasCode(cause, "ENOENT")) return null;
|
|
6014
|
+
throw cause;
|
|
6015
|
+
}
|
|
6016
|
+
};
|
|
6017
|
+
var freedBy = (stat) => stat.nlink === 1 ? stat.size : 0;
|
|
6018
|
+
var GENERATION_NAME = /^gen-[0-9a-f-]{36}$/;
|
|
6019
|
+
var VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
6020
|
+
var generationVersion = (configDir, generation) => {
|
|
6021
|
+
if (!GENERATION_NAME.test(generation)) return void 0;
|
|
6022
|
+
try {
|
|
6023
|
+
const parsed = JSON.parse(
|
|
6024
|
+
fs14.readFileSync(path15.join(configDir, "generations", generation, "server.json"), "utf8")
|
|
6025
|
+
);
|
|
6026
|
+
return typeof parsed === "object" && parsed !== null && "serverVersion" in parsed && typeof parsed.serverVersion === "string" && VERSION.test(parsed.serverVersion) ? parsed.serverVersion : void 0;
|
|
6027
|
+
} catch {
|
|
6028
|
+
return void 0;
|
|
6029
|
+
}
|
|
6030
|
+
};
|
|
6031
|
+
var readRecord = (configDir, file, stat) => {
|
|
6032
|
+
let parsed;
|
|
6033
|
+
try {
|
|
6034
|
+
parsed = JSON.parse(fs14.readFileSync(file, "utf8"));
|
|
6035
|
+
} catch {
|
|
6036
|
+
return null;
|
|
6037
|
+
}
|
|
6038
|
+
if (typeof parsed !== "object" || parsed === null || !("previousGeneration" in parsed) || !("targetGeneration" in parsed) || typeof parsed.previousGeneration !== "string" || typeof parsed.targetGeneration !== "string")
|
|
6039
|
+
return null;
|
|
6040
|
+
const sequence = "sequence" in parsed && typeof parsed.sequence === "number" && Number.isSafeInteger(parsed.sequence) && parsed.sequence > 0 ? parsed.sequence : void 0;
|
|
6041
|
+
const stamped = "createdAt" in parsed && typeof parsed.createdAt === "string" ? Date.parse(parsed.createdAt) : Number.NaN;
|
|
6042
|
+
const targetGeneration = path15.basename(parsed.targetGeneration);
|
|
6043
|
+
return {
|
|
6044
|
+
previousGeneration: path15.basename(parsed.previousGeneration),
|
|
6045
|
+
targetGeneration,
|
|
6046
|
+
state: "state" in parsed ? parsed.state : void 0,
|
|
6047
|
+
sequence,
|
|
6048
|
+
recordsOutcome: "state" in parsed || "sequence" in parsed,
|
|
6049
|
+
targetVersion: generationVersion(configDir, targetGeneration),
|
|
6050
|
+
clock: Number.isFinite(stamped) ? stamped : stat.mtimeMs
|
|
6051
|
+
};
|
|
6052
|
+
};
|
|
6053
|
+
var DUMP_TRAILER = /-- PostgreSQL database cluster dump complete\r?\n(?:--\r?\n)?\s*$/;
|
|
6054
|
+
var dumpIsWhole = (file, size) => {
|
|
6055
|
+
const length = Math.min(size, 256);
|
|
6056
|
+
if (length === 0) return false;
|
|
6057
|
+
const buffer = Buffer.alloc(length);
|
|
6058
|
+
const fd = fs14.openSync(file, "r");
|
|
6059
|
+
try {
|
|
6060
|
+
fs14.readSync(fd, buffer, 0, length, size - length);
|
|
6061
|
+
} finally {
|
|
6062
|
+
fs14.closeSync(fd);
|
|
6063
|
+
}
|
|
6064
|
+
const tail = buffer.toString("utf8");
|
|
6065
|
+
const match = DUMP_TRAILER.exec(tail);
|
|
6066
|
+
if (match === null) return false;
|
|
6067
|
+
return match.index === 0 ? length === size : tail[match.index - 1] === "\n";
|
|
6068
|
+
};
|
|
6069
|
+
var readBackup = (configDir, directory) => {
|
|
6070
|
+
const stat = lstatOptional(directory);
|
|
6071
|
+
if (stat === null || !stat.isDirectory()) return { kind: "foreign" };
|
|
6072
|
+
if (REMOVING_NAME.test(path15.basename(directory))) return readRemoving(directory);
|
|
6073
|
+
if (!BACKUP_NAME.test(path15.basename(directory))) return { kind: "foreign" };
|
|
6074
|
+
const entries = fs14.readdirSync(directory);
|
|
6075
|
+
if (entries.length === 0) return { kind: "interrupted", bytes: 0 };
|
|
6076
|
+
const recoveryFile = path15.join(directory, "recovery.json");
|
|
6077
|
+
const recovery = lstatOptional(recoveryFile);
|
|
6078
|
+
if (recovery === null || !recovery.isFile()) return { kind: "foreign" };
|
|
6079
|
+
const record2 = readRecord(configDir, recoveryFile, recovery);
|
|
6080
|
+
if (record2 === null) return { kind: "foreign" };
|
|
6081
|
+
if (entries.includes("database.sql.partial"))
|
|
6082
|
+
return { kind: "held", reason: "unfinished", record: record2 };
|
|
6083
|
+
if (entries.some(
|
|
6084
|
+
(name) => name !== "database.sql" && name !== "recovery.json" && !RECOVERY_TEMPORARY.test(name)
|
|
6085
|
+
))
|
|
6086
|
+
return { kind: "foreign" };
|
|
6087
|
+
if (record2.recordsOutcome && (record2.sequence === void 0 || record2.state === void 0))
|
|
6088
|
+
return {
|
|
6089
|
+
kind: "held",
|
|
6090
|
+
reason: "unreadable",
|
|
6091
|
+
detail: "recovery.json has a state without a valid sequence"
|
|
6092
|
+
};
|
|
6093
|
+
const dump = lstatOptional(path15.join(directory, "database.sql"));
|
|
6094
|
+
if (dump !== null && !dump.isFile()) return { kind: "foreign" };
|
|
6095
|
+
if (dump === null)
|
|
6096
|
+
return record2.state === "completed" ? { kind: "interrupted", bytes: freedBy(recovery) } : { kind: "held", reason: "unfinished", record: record2 };
|
|
6097
|
+
if (!dumpIsWhole(path15.join(directory, "database.sql"), dump.size))
|
|
6098
|
+
return { kind: "held", reason: "unfinished", record: record2 };
|
|
6099
|
+
if (record2.recordsOutcome && record2.state !== "completed")
|
|
6100
|
+
return { kind: "held", reason: "pending", record: record2 };
|
|
6101
|
+
return {
|
|
6102
|
+
kind: "completed",
|
|
6103
|
+
record: record2,
|
|
6104
|
+
bytes: freedBy(dump) + freedBy(recovery),
|
|
6105
|
+
legacy: !record2.recordsOutcome
|
|
6106
|
+
};
|
|
6107
|
+
};
|
|
6108
|
+
var readRemoving = (directory) => {
|
|
6109
|
+
let bytes = 0;
|
|
6110
|
+
for (const name of fs14.readdirSync(directory)) {
|
|
6111
|
+
const file = lstatOptional(path15.join(directory, name));
|
|
6112
|
+
if (file === null || !file.isFile() || !(name === "database.sql" || name === "database.sql.partial" || name === "recovery.json" || RECOVERY_TEMPORARY.test(name)))
|
|
6113
|
+
return { kind: "foreign" };
|
|
6114
|
+
bytes += freedBy(file);
|
|
6115
|
+
}
|
|
6116
|
+
return { kind: "interrupted", bytes };
|
|
6117
|
+
};
|
|
6118
|
+
var nextSequence = (configDir, backups) => {
|
|
6119
|
+
let highest = 0;
|
|
6120
|
+
for (const name of fs14.readdirSync(backups)) {
|
|
6121
|
+
if (!BACKUP_NAME.test(name)) continue;
|
|
6122
|
+
try {
|
|
6123
|
+
const directory = path15.join(backups, name);
|
|
6124
|
+
const stat = lstatOptional(directory);
|
|
6125
|
+
if (stat === null || !stat.isDirectory()) continue;
|
|
6126
|
+
const file = path15.join(directory, "recovery.json");
|
|
6127
|
+
const recovery = lstatOptional(file);
|
|
6128
|
+
if (recovery === null || !recovery.isFile()) continue;
|
|
6129
|
+
highest = Math.max(highest, readRecord(configDir, file, recovery)?.sequence ?? 0);
|
|
6130
|
+
} catch {
|
|
6131
|
+
continue;
|
|
6132
|
+
}
|
|
6133
|
+
}
|
|
6134
|
+
return highest + 1;
|
|
6135
|
+
};
|
|
6136
|
+
var versionOrder = (compareVersions, a, b) => {
|
|
6137
|
+
if (a === void 0 || b === void 0) return 0;
|
|
6138
|
+
try {
|
|
6139
|
+
return compareVersions(a, b);
|
|
6140
|
+
} catch {
|
|
6141
|
+
return 0;
|
|
6142
|
+
}
|
|
6143
|
+
};
|
|
6144
|
+
var chainDepths = (records) => {
|
|
6145
|
+
const depths = /* @__PURE__ */ new Map();
|
|
6146
|
+
const depth = (record2, visiting) => {
|
|
6147
|
+
const known = depths.get(record2);
|
|
6148
|
+
if (known !== void 0) return known;
|
|
6149
|
+
const next = new Set(visiting).add(record2);
|
|
6150
|
+
const before = records.filter(
|
|
6151
|
+
(other) => !next.has(other) && other.targetGeneration === record2.previousGeneration && other.targetGeneration !== other.previousGeneration
|
|
6152
|
+
);
|
|
6153
|
+
const value = Math.max(-1, ...before.map((other) => depth(other, next))) + 1;
|
|
6154
|
+
depths.set(record2, value);
|
|
6155
|
+
return value;
|
|
6156
|
+
};
|
|
6157
|
+
return (record2) => depth(record2, /* @__PURE__ */ new Set());
|
|
6158
|
+
};
|
|
6159
|
+
var newestFirst = (records, compareVersions) => {
|
|
6160
|
+
const depth = chainDepths(records.filter((record2) => record2.sequence === void 0));
|
|
6161
|
+
return (a, b) => {
|
|
6162
|
+
if (a.sequence !== void 0 || b.sequence !== void 0) {
|
|
6163
|
+
if (a.sequence === void 0) return 1;
|
|
6164
|
+
if (b.sequence === void 0) return -1;
|
|
6165
|
+
if (a.sequence !== b.sequence) return b.sequence - a.sequence;
|
|
6166
|
+
} else {
|
|
6167
|
+
const byVersion = versionOrder(compareVersions, b.targetVersion, a.targetVersion);
|
|
6168
|
+
if (byVersion !== 0) return byVersion;
|
|
6169
|
+
const byChain = depth(b) - depth(a);
|
|
6170
|
+
if (byChain !== 0) return byChain;
|
|
6171
|
+
}
|
|
6172
|
+
return b.clock - a.clock;
|
|
6173
|
+
};
|
|
6174
|
+
};
|
|
6175
|
+
var writtenAfterOutcomes = (record2, records, current, compareVersions) => {
|
|
6176
|
+
const sequenced = records.filter((other) => other.sequence !== void 0);
|
|
6177
|
+
const unsequenced = records.filter((other) => other.sequence === void 0);
|
|
6178
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6179
|
+
const chainsFromSequenced = (candidate) => {
|
|
6180
|
+
if (seen.has(candidate)) return false;
|
|
6181
|
+
seen.add(candidate);
|
|
6182
|
+
if (sequenced.some((other) => other.targetGeneration === candidate.previousGeneration))
|
|
6183
|
+
return true;
|
|
6184
|
+
return unsequenced.some(
|
|
6185
|
+
(other) => other.targetGeneration === candidate.previousGeneration && chainsFromSequenced(other)
|
|
6186
|
+
);
|
|
6187
|
+
};
|
|
6188
|
+
return chainsFromSequenced(record2) || sequenced.some(
|
|
6189
|
+
(other) => other !== current && versionOrder(compareVersions, record2.targetVersion, other.targetVersion) > 0
|
|
6190
|
+
);
|
|
6191
|
+
};
|
|
6192
|
+
var removeBackup = (directory) => {
|
|
6193
|
+
const removing = REMOVING_NAME.test(path15.basename(directory)) ? directory : `${directory}.removing`;
|
|
6194
|
+
if (removing !== directory) fs14.renameSync(directory, removing);
|
|
6195
|
+
for (const name of fs14.readdirSync(removing))
|
|
6196
|
+
if (name === "database.sql" || name === "database.sql.partial" || name === "recovery.json" || RECOVERY_TEMPORARY.test(name))
|
|
6197
|
+
fs14.unlinkSync(path15.join(removing, name));
|
|
6198
|
+
fs14.rmdirSync(removing);
|
|
6199
|
+
};
|
|
6200
|
+
var entryOf = ({ directory, bytes, legacy }) => ({
|
|
6201
|
+
directory,
|
|
6202
|
+
bytes,
|
|
6203
|
+
legacy,
|
|
6204
|
+
interrupted: false
|
|
6205
|
+
});
|
|
6206
|
+
var failureOf = (cause) => cause instanceof Error ? cause.message : "unknown filesystem error";
|
|
6207
|
+
var pruneBackups = (configDir, keep, current, compareVersions) => {
|
|
6208
|
+
if (!Number.isSafeInteger(keep) || keep < 1)
|
|
6209
|
+
throw new ServerStoreError("Pruning keeps at least one upgrade backup.");
|
|
6210
|
+
const backups = path15.join(configDir, "backups");
|
|
6211
|
+
if (path15.dirname(current.directory) !== backups)
|
|
6212
|
+
throw new ServerStoreError("The current upgrade backup is outside this installation.");
|
|
6213
|
+
const currentRead = readBackup(configDir, current.directory);
|
|
6214
|
+
if (currentRead.kind !== "completed" || currentRead.record.sequence === void 0)
|
|
6215
|
+
throw new ServerStoreError("The current upgrade backup is not completed; nothing was pruned.");
|
|
6216
|
+
const completed = [];
|
|
6217
|
+
const interrupted = [];
|
|
6218
|
+
const held = [];
|
|
6219
|
+
const records = [currentRead.record];
|
|
6220
|
+
for (const name of fs14.readdirSync(backups).toSorted()) {
|
|
6221
|
+
const directory = path15.join(backups, name);
|
|
6222
|
+
if (directory === current.directory) continue;
|
|
6223
|
+
let read;
|
|
6224
|
+
try {
|
|
6225
|
+
read = readBackup(configDir, directory);
|
|
6226
|
+
} catch (cause) {
|
|
6227
|
+
if (BACKUP_NAME.test(name) || REMOVING_NAME.test(name))
|
|
6228
|
+
held.push({ directory, reason: "unreadable", detail: failureOf(cause) });
|
|
6229
|
+
continue;
|
|
6230
|
+
}
|
|
6231
|
+
if (read.kind === "held") {
|
|
6232
|
+
held.push({
|
|
6233
|
+
directory,
|
|
6234
|
+
reason: read.reason,
|
|
6235
|
+
...read.detail === void 0 ? {} : { detail: read.detail }
|
|
6236
|
+
});
|
|
6237
|
+
if (read.record !== void 0) records.push(read.record);
|
|
6238
|
+
}
|
|
6239
|
+
if (read.kind === "interrupted")
|
|
6240
|
+
interrupted.push({ directory, bytes: read.bytes, legacy: false, interrupted: true });
|
|
6241
|
+
if (read.kind === "completed") {
|
|
6242
|
+
completed.push({
|
|
6243
|
+
directory,
|
|
6244
|
+
bytes: read.bytes,
|
|
6245
|
+
legacy: read.legacy,
|
|
6246
|
+
interrupted: false,
|
|
6247
|
+
record: read.record
|
|
6248
|
+
});
|
|
6249
|
+
records.push(read.record);
|
|
6250
|
+
}
|
|
6251
|
+
}
|
|
6252
|
+
const candidates = completed.filter((entry) => {
|
|
6253
|
+
if (!entry.legacy || !writtenAfterOutcomes(entry.record, records, currentRead.record, compareVersions))
|
|
6254
|
+
return true;
|
|
6255
|
+
held.push({ directory: entry.directory, reason: "no-outcome" });
|
|
6256
|
+
return false;
|
|
6257
|
+
});
|
|
6258
|
+
const compare = newestFirst(records, compareVersions);
|
|
6259
|
+
candidates.sort((a, b) => compare(a.record, b.record));
|
|
6260
|
+
const kept = [
|
|
6261
|
+
{ directory: current.directory, bytes: currentRead.bytes, legacy: false, interrupted: false },
|
|
6262
|
+
...candidates.slice(0, keep - 1).map(entryOf)
|
|
6263
|
+
];
|
|
6264
|
+
const removed = [];
|
|
6265
|
+
const failed = [];
|
|
6266
|
+
for (const candidate of [...interrupted, ...candidates.slice(keep - 1).map(entryOf)]) {
|
|
6267
|
+
try {
|
|
6268
|
+
removeBackup(candidate.directory);
|
|
6269
|
+
removed.push(candidate);
|
|
6270
|
+
} catch (cause) {
|
|
6271
|
+
failed.push({ directory: candidate.directory, message: failureOf(cause) });
|
|
6272
|
+
}
|
|
6273
|
+
}
|
|
6274
|
+
let unsynced;
|
|
6275
|
+
if (removed.length > 0 || failed.length > 0) {
|
|
6276
|
+
try {
|
|
6277
|
+
syncDirectory(backups);
|
|
6278
|
+
} catch (cause) {
|
|
6279
|
+
unsynced = failureOf(cause);
|
|
6280
|
+
}
|
|
6281
|
+
}
|
|
6282
|
+
return { removed, kept, held, failed, ...unsynced === void 0 ? {} : { unsynced } };
|
|
6283
|
+
};
|
|
5996
6284
|
var createStore = (configDir, lock) => {
|
|
5997
6285
|
const paths = {
|
|
5998
6286
|
configDir,
|
|
@@ -6014,22 +6302,19 @@ var createStore = (configDir, lock) => {
|
|
|
6014
6302
|
const backups = path15.join(configDir, "backups");
|
|
6015
6303
|
fs14.mkdirSync(backups, { recursive: true, mode: 448 });
|
|
6016
6304
|
fs14.chmodSync(backups, 448);
|
|
6305
|
+
const sequence = nextSequence(configDir, backups);
|
|
6017
6306
|
const directory = path15.join(backups, `upgrade-${randomUUID2()}`);
|
|
6018
6307
|
fs14.mkdirSync(directory, { mode: 448 });
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
2
|
|
6030
|
-
)}
|
|
6031
|
-
`
|
|
6032
|
-
);
|
|
6308
|
+
const record2 = {
|
|
6309
|
+
previousGeneration: previous.directory,
|
|
6310
|
+
targetGeneration: target.directory,
|
|
6311
|
+
database: "database.sql",
|
|
6312
|
+
sequence,
|
|
6313
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6314
|
+
policy: "If target is active, migrations may have begun. Never downgrade or restore automatically."
|
|
6315
|
+
};
|
|
6316
|
+
const recoveryFile = path15.join(directory, "recovery.json");
|
|
6317
|
+
writeDurable(recoveryFile, renderRecovery({ ...record2, state: "pending" }));
|
|
6033
6318
|
syncDirectory(directory);
|
|
6034
6319
|
syncDirectory(backups);
|
|
6035
6320
|
syncDirectory(configDir);
|
|
@@ -6049,9 +6334,16 @@ var createStore = (configDir, lock) => {
|
|
|
6049
6334
|
}
|
|
6050
6335
|
fs14.renameSync(partialFile, path15.join(directory, "database.sql"));
|
|
6051
6336
|
syncDirectory(directory);
|
|
6337
|
+
}),
|
|
6338
|
+
markCompleted: () => whileOwned(() => {
|
|
6339
|
+
const temporary = path15.join(directory, `.recovery-${randomUUID2()}`);
|
|
6340
|
+
writeDurable(temporary, renderRecovery({ ...record2, state: "completed" }));
|
|
6341
|
+
fs14.renameSync(temporary, recoveryFile);
|
|
6342
|
+
syncDirectory(directory);
|
|
6052
6343
|
})
|
|
6053
6344
|
};
|
|
6054
|
-
})
|
|
6345
|
+
}),
|
|
6346
|
+
pruneBackups: (keep, current, compareVersions) => whileOwned(() => pruneBackups(configDir, keep, current, compareVersions))
|
|
6055
6347
|
};
|
|
6056
6348
|
};
|
|
6057
6349
|
var refuseFlatLayout = (configDir) => {
|
|
@@ -7406,9 +7698,26 @@ var startInstallation = async (runtime, installation, secrets) => {
|
|
|
7406
7698
|
await probeHealth(runtime, healthOrigin(installation.config), installation.config.serverVersion);
|
|
7407
7699
|
runtime.writeLine(reachableLine(installation.config));
|
|
7408
7700
|
};
|
|
7701
|
+
var DEFAULT_KEEP_BACKUPS = 2;
|
|
7409
7702
|
var parseUpgradeOptions = (args) => {
|
|
7410
7703
|
const fromPreview = args.includes("--from-preview");
|
|
7411
|
-
const rest =
|
|
7704
|
+
const rest = [];
|
|
7705
|
+
let keepBackups = DEFAULT_KEEP_BACKUPS;
|
|
7706
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
7707
|
+
const flag = args[index];
|
|
7708
|
+
if (flag === void 0 || flag === "--from-preview") continue;
|
|
7709
|
+
if (flag === "--keep-backups") {
|
|
7710
|
+
const value = args[index + 1];
|
|
7711
|
+
if (value === void 0 || !/^\d+$/.test(value) || !Number.isSafeInteger(Number(value)))
|
|
7712
|
+
throw setupError(
|
|
7713
|
+
"--keep-backups takes a whole number: how many upgrade backups to keep, 0 for all."
|
|
7714
|
+
);
|
|
7715
|
+
keepBackups = Number(value);
|
|
7716
|
+
index += 1;
|
|
7717
|
+
continue;
|
|
7718
|
+
}
|
|
7719
|
+
rest.push(flag);
|
|
7720
|
+
}
|
|
7412
7721
|
for (let index = 0; index < rest.length; index += 1) {
|
|
7413
7722
|
const flag = rest[index];
|
|
7414
7723
|
if (flag === "--offline") continue;
|
|
@@ -7421,7 +7730,63 @@ var parseUpgradeOptions = (args) => {
|
|
|
7421
7730
|
throw setupError(
|
|
7422
7731
|
"Upgrade requires --version TARGET. Use --version latest only to request the latest release explicitly."
|
|
7423
7732
|
);
|
|
7424
|
-
return { ...options, fromPreview };
|
|
7733
|
+
return { ...options, fromPreview, keepBackups };
|
|
7734
|
+
};
|
|
7735
|
+
var formatBytes3 = (bytes) => {
|
|
7736
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
7737
|
+
const units = ["KiB", "MiB", "GiB", "TiB"];
|
|
7738
|
+
let value = bytes / 1024;
|
|
7739
|
+
let unit = 0;
|
|
7740
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
7741
|
+
value /= 1024;
|
|
7742
|
+
unit += 1;
|
|
7743
|
+
}
|
|
7744
|
+
return `${value.toFixed(value < 10 ? 1 : 0)} ${units[unit]}`;
|
|
7745
|
+
};
|
|
7746
|
+
var heldReason = (entry) => {
|
|
7747
|
+
switch (entry.reason) {
|
|
7748
|
+
case "pending":
|
|
7749
|
+
return "pending: its upgrade never recorded a healthy target";
|
|
7750
|
+
case "unfinished":
|
|
7751
|
+
return "unfinished: no complete database dump";
|
|
7752
|
+
case "no-outcome":
|
|
7753
|
+
return "no recorded outcome: written after a 0.36 backup by a CLI that records none";
|
|
7754
|
+
case "unreadable":
|
|
7755
|
+
return `unreadable: ${entry.detail ?? "not read"}`;
|
|
7756
|
+
}
|
|
7757
|
+
};
|
|
7758
|
+
var pruneUpgradeBackups = (runtime, store, backup, keep) => {
|
|
7759
|
+
const marked = backup.markCompleted();
|
|
7760
|
+
if (marked._tag === "error") {
|
|
7761
|
+
runtime.writeLine(
|
|
7762
|
+
`Could not record the upgrade as completed in ${backup.directory}/recovery.json; no backups were removed. ${marked.error.message}`
|
|
7763
|
+
);
|
|
7764
|
+
return;
|
|
7765
|
+
}
|
|
7766
|
+
if (keep === 0) {
|
|
7767
|
+
runtime.writeLine("Upgrade backups \xB7 all kept (--keep-backups 0)");
|
|
7768
|
+
return;
|
|
7769
|
+
}
|
|
7770
|
+
const pruned = store.pruneBackups(keep, backup, upgradeOrder);
|
|
7771
|
+
if (pruned._tag === "error") {
|
|
7772
|
+
runtime.writeLine(`Upgrade backups \xB7 not pruned: ${pruned.error.message}`);
|
|
7773
|
+
return;
|
|
7774
|
+
}
|
|
7775
|
+
const { removed, kept, held, failed, unsynced } = pruned.value;
|
|
7776
|
+
for (const entry of removed)
|
|
7777
|
+
runtime.writeLine(
|
|
7778
|
+
`Removed upgrade backup ${entry.directory} \xB7 ${formatBytes3(entry.bytes)}${entry.interrupted ? " \xB7 finishing a removal a crash cut short" : entry.legacy ? " \xB7 from before 0.36, no recorded outcome" : ""}`
|
|
7779
|
+
);
|
|
7780
|
+
const freed = removed.reduce((total, entry) => total + entry.bytes, 0);
|
|
7781
|
+
runtime.writeLine(
|
|
7782
|
+
`Upgrade backups \xB7 removed ${removed.length}${removed.length > 0 ? ` \xB7 ${formatBytes3(freed)} freed` : ""} \xB7 kept ${kept.length} (--keep-backups ${keep})`
|
|
7783
|
+
);
|
|
7784
|
+
for (const entry of failed)
|
|
7785
|
+
runtime.writeLine(`Could not remove upgrade backup ${entry.directory}: ${entry.message}`);
|
|
7786
|
+
if (unsynced !== void 0)
|
|
7787
|
+
runtime.writeLine(`Upgrade backups \xB7 removals made but not fsynced: ${unsynced}`);
|
|
7788
|
+
for (const entry of held)
|
|
7789
|
+
runtime.writeLine(`Kept upgrade backup ${entry.directory} \xB7 ${heldReason(entry)}`);
|
|
7425
7790
|
};
|
|
7426
7791
|
var LEGACY_PREVIEW = /^(\d+\.\d+\.\d+)-preview\.(0|[1-9]\d*)$/;
|
|
7427
7792
|
var NEXT_BUILD = /^(\d+\.\d+\.\d+)-next\.(0|[1-9]\d*)(\.preview\.[1-9]\d*)?$/;
|
|
@@ -7430,6 +7795,11 @@ var isPreviewToNext = (from, to) => {
|
|
|
7430
7795
|
const next = NEXT_BUILD.exec(to);
|
|
7431
7796
|
return preview !== null && next !== null && preview[1] === next[1];
|
|
7432
7797
|
};
|
|
7798
|
+
var upgradeOrder = (a, b) => {
|
|
7799
|
+
if (isPreviewToNext(a, b)) return -1;
|
|
7800
|
+
if (isPreviewToNext(b, a)) return 1;
|
|
7801
|
+
return compareServerVersions(a, b);
|
|
7802
|
+
};
|
|
7433
7803
|
var drizzleMillis = (folder) => {
|
|
7434
7804
|
const at = (start, end) => Number(folder.slice(start, end));
|
|
7435
7805
|
return String(Date.UTC(at(0, 4), at(4, 6) - 1, at(6, 8), at(8, 10), at(10, 12), at(12, 14)));
|
|
@@ -7669,6 +8039,7 @@ var upgradeServer = async (args, runtime, store, existing) => {
|
|
|
7669
8039
|
);
|
|
7670
8040
|
}
|
|
7671
8041
|
runtime.writeLine(`Upgraded to ${version}. Retained database backup: ${backup.directory}`);
|
|
8042
|
+
pruneUpgradeBackups(runtime, store, backup, options.keepBackups);
|
|
7672
8043
|
};
|
|
7673
8044
|
var observeEdgeCertificate = async (runtime, installation, host) => {
|
|
7674
8045
|
const listed = await runtime.run(
|
|
@@ -12537,7 +12908,7 @@ var dashboard = async (config, options = {}) => {
|
|
|
12537
12908
|
);
|
|
12538
12909
|
process.exit(rerun.status ?? 0);
|
|
12539
12910
|
}
|
|
12540
|
-
const { runDashboard } = await import("./dashboard-
|
|
12911
|
+
const { runDashboard } = await import("./dashboard-2HF3KTTU.js");
|
|
12541
12912
|
const agentShare = await startShareIfBridge(config);
|
|
12542
12913
|
const tunnels = options.noTunnel === true || serverIsLocal(config) ? null : createServiceTunnels({
|
|
12543
12914
|
listServices: () => fetchServices(config),
|
package/man/mend-accounts.1
CHANGED
package/man/mend-adopt.1
CHANGED