@devrouter/cli 0.0.74 → 0.0.75
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/devrouter-lifecycle-worker.js +5498 -5429
- package/dist/devrouter.js +180 -19
- package/package.json +1 -1
- package/upgrade-prompts/0.0.75.md +35 -0
package/dist/devrouter.js
CHANGED
|
@@ -4256,7 +4256,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs7.default.read
|
|
|
4256
4256
|
const config = parseConfig(parsed ?? {}, configPath);
|
|
4257
4257
|
const requiredVersion = config.devrouter?.version;
|
|
4258
4258
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
4259
|
-
const cliVersion = true ? "0.0.
|
|
4259
|
+
const cliVersion = true ? "0.0.75" : "0.0.0-dev";
|
|
4260
4260
|
if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
|
|
4261
4261
|
hasWarnedVersionMismatch = true;
|
|
4262
4262
|
process.stderr.write(
|
|
@@ -5509,7 +5509,7 @@ var init_reliability_contract = __esm({
|
|
|
5509
5509
|
|
|
5510
5510
|
// src/core/reliability-operation-store.ts
|
|
5511
5511
|
function installedCliVersion() {
|
|
5512
|
-
return true ? "0.0.
|
|
5512
|
+
return true ? "0.0.75" : "0.0.0-dev";
|
|
5513
5513
|
}
|
|
5514
5514
|
function compareCliVersions(left, right) {
|
|
5515
5515
|
const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
@@ -8413,6 +8413,12 @@ function isWildcard(values) {
|
|
|
8413
8413
|
function sha256(contents) {
|
|
8414
8414
|
return (0, import_node_crypto11.createHash)("sha256").update(contents, "utf-8").digest("hex");
|
|
8415
8415
|
}
|
|
8416
|
+
function safeComposeProject(value) {
|
|
8417
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(value)) {
|
|
8418
|
+
throw new Error(`Docker Compose project '${value}' is not a safe exact identifier.`);
|
|
8419
|
+
}
|
|
8420
|
+
return value;
|
|
8421
|
+
}
|
|
8416
8422
|
function inspectManagedDevcontainerConfig(options) {
|
|
8417
8423
|
const managedRuntime = options.config.managedRuntime;
|
|
8418
8424
|
if (!managedRuntime) {
|
|
@@ -8531,6 +8537,91 @@ function managedComposeEnvironment(workspace) {
|
|
|
8531
8537
|
}
|
|
8532
8538
|
return env;
|
|
8533
8539
|
}
|
|
8540
|
+
function assertReadableComposeFile(file) {
|
|
8541
|
+
try {
|
|
8542
|
+
if (!import_node_fs18.default.statSync(file).isFile()) throw new Error("not a regular file");
|
|
8543
|
+
import_node_fs18.default.accessSync(file, import_node_fs18.default.constants.R_OK);
|
|
8544
|
+
} catch {
|
|
8545
|
+
throw new Error("Managed container Compose configuration contains an unreadable file.");
|
|
8546
|
+
}
|
|
8547
|
+
}
|
|
8548
|
+
function assertManagedContainerConfigUnchanged(options) {
|
|
8549
|
+
if (options.containers.length === 0) {
|
|
8550
|
+
throw new Error("Managed container configuration cannot be verified without containers.");
|
|
8551
|
+
}
|
|
8552
|
+
for (const container of options.containers) {
|
|
8553
|
+
const project = container.labels["com.docker.compose.project"];
|
|
8554
|
+
const service = container.labels["com.docker.compose.service"];
|
|
8555
|
+
const workingDirectory = container.labels["com.docker.compose.project.working_dir"];
|
|
8556
|
+
const recordedConfigFiles = container.labels["com.docker.compose.project.config_files"];
|
|
8557
|
+
const expectedHash = container.labels["com.docker.compose.config-hash"];
|
|
8558
|
+
if (!project || !service || !workingDirectory || !recordedConfigFiles || !expectedHash || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(service) || !/^[a-f0-9]{64}$/.test(expectedHash)) {
|
|
8559
|
+
throw new Error("Managed container is missing valid Compose identity and hash labels.");
|
|
8560
|
+
}
|
|
8561
|
+
const composeProject = safeComposeProject(project);
|
|
8562
|
+
const configFiles2 = recordedConfigFiles.split(",").map((file) => file.trim());
|
|
8563
|
+
if (configFiles2.some((file) => file.length === 0)) {
|
|
8564
|
+
throw new Error("Managed container has an invalid recorded Compose file list.");
|
|
8565
|
+
}
|
|
8566
|
+
if (options.plan.composeFiles.some(
|
|
8567
|
+
(expected) => !configFiles2.some((actual) => sameWorkspacePath(actual, expected))
|
|
8568
|
+
)) {
|
|
8569
|
+
throw new Error("Managed container Compose files do not include the managed plan files.");
|
|
8570
|
+
}
|
|
8571
|
+
for (const file of configFiles2) assertReadableComposeFile(file);
|
|
8572
|
+
const fileArgs = configFiles2.flatMap((file) => ["-f", file]);
|
|
8573
|
+
const result = (() => {
|
|
8574
|
+
try {
|
|
8575
|
+
const composeArgs = [
|
|
8576
|
+
"compose",
|
|
8577
|
+
"--project-name",
|
|
8578
|
+
composeProject,
|
|
8579
|
+
"--project-directory",
|
|
8580
|
+
workingDirectory
|
|
8581
|
+
];
|
|
8582
|
+
const env = managedComposeEnvironment(options.workspace);
|
|
8583
|
+
const rendered = (0, import_node_child_process8.spawnSync)(
|
|
8584
|
+
"docker",
|
|
8585
|
+
[...composeArgs, ...fileArgs, "config", "--format", "json"],
|
|
8586
|
+
{
|
|
8587
|
+
cwd: workingDirectory,
|
|
8588
|
+
encoding: "utf-8",
|
|
8589
|
+
env,
|
|
8590
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
8591
|
+
timeout: COMPOSE_HASH_TIMEOUT_MS,
|
|
8592
|
+
maxBuffer: 1024 * 1024
|
|
8593
|
+
}
|
|
8594
|
+
);
|
|
8595
|
+
if (rendered.status !== 0 || rendered.error || !rendered.stdout?.trim()) {
|
|
8596
|
+
throw new Error("Compose configuration rendering failed.");
|
|
8597
|
+
}
|
|
8598
|
+
return (0, import_node_child_process8.spawnSync)(
|
|
8599
|
+
"docker",
|
|
8600
|
+
[...composeArgs, "-f", "-", "config", "--no-interpolate", "--hash", service],
|
|
8601
|
+
{
|
|
8602
|
+
cwd: workingDirectory,
|
|
8603
|
+
encoding: "utf-8",
|
|
8604
|
+
env,
|
|
8605
|
+
input: rendered.stdout,
|
|
8606
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
8607
|
+
timeout: COMPOSE_HASH_TIMEOUT_MS,
|
|
8608
|
+
maxBuffer: 1024 * 1024
|
|
8609
|
+
}
|
|
8610
|
+
);
|
|
8611
|
+
} catch {
|
|
8612
|
+
throw new Error(`Could not verify managed Compose configuration for service '${service}'.`);
|
|
8613
|
+
}
|
|
8614
|
+
})();
|
|
8615
|
+
if (result.status !== 0 || result.error) {
|
|
8616
|
+
throw new Error(`Could not verify managed Compose configuration for service '${service}'.`);
|
|
8617
|
+
}
|
|
8618
|
+
const output2 = typeof result.stdout === "string" ? result.stdout.trim() : "";
|
|
8619
|
+
const match = /^(\S+)\s+([a-f0-9]{64})$/.exec(output2);
|
|
8620
|
+
if (!match || match[1] !== service || match[2] !== expectedHash) {
|
|
8621
|
+
throw new Error(`Managed Compose configuration changed for service '${service}'.`);
|
|
8622
|
+
}
|
|
8623
|
+
}
|
|
8624
|
+
}
|
|
8534
8625
|
function stopExactManagedService(containerId, service, options) {
|
|
8535
8626
|
assertSafeContainerId(containerId);
|
|
8536
8627
|
const result = (0, import_node_child_process8.spawnSync)("docker", ["stop", containerId], {
|
|
@@ -8543,7 +8634,7 @@ function stopExactManagedService(containerId, service, options) {
|
|
|
8543
8634
|
throw new Error(`Could not stop exact managed service '${service}' (${containerId}).`);
|
|
8544
8635
|
}
|
|
8545
8636
|
}
|
|
8546
|
-
var import_node_child_process8, import_node_crypto11, import_node_fs18, import_node_path25, import_yaml3, MANAGED_DEVCONTAINER_PATH, MANAGED_DEVCONTAINER_MARKER;
|
|
8637
|
+
var import_node_child_process8, import_node_crypto11, import_node_fs18, import_node_path25, import_yaml3, MANAGED_DEVCONTAINER_PATH, MANAGED_DEVCONTAINER_MARKER, COMPOSE_HASH_TIMEOUT_MS;
|
|
8547
8638
|
var init_devcontainer_profile = __esm({
|
|
8548
8639
|
"src/core/devcontainer-profile.ts"() {
|
|
8549
8640
|
"use strict";
|
|
@@ -8559,6 +8650,7 @@ var init_devcontainer_profile = __esm({
|
|
|
8559
8650
|
init_workspace();
|
|
8560
8651
|
MANAGED_DEVCONTAINER_PATH = ".devcontainer/devcontainer.devrouter.json";
|
|
8561
8652
|
MANAGED_DEVCONTAINER_MARKER = "// devrouter:managed devcontainer profile";
|
|
8653
|
+
COMPOSE_HASH_TIMEOUT_MS = 1e4;
|
|
8562
8654
|
}
|
|
8563
8655
|
});
|
|
8564
8656
|
|
|
@@ -10529,8 +10621,27 @@ function proveInitialManagedDevsyAbsence(repoPath, expectedId) {
|
|
|
10529
10621
|
}
|
|
10530
10622
|
function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
|
|
10531
10623
|
if (!import_node_fs25.default.existsSync(import_node_path33.default.join(repoPath, ".devrouter.yml"))) return false;
|
|
10624
|
+
if (!loadRepoConfig(repoPath).managedRuntime) return false;
|
|
10532
10625
|
const linked = isLinkedWorktree(repoPath);
|
|
10533
10626
|
const workspace = linked ? resolveWorktreeWorkspace(repoPath) : void 0;
|
|
10627
|
+
const identity2 = { repoPath, workspace: workspace ?? null, provider: "devsy" };
|
|
10628
|
+
const readAuthority = () => {
|
|
10629
|
+
const record5 = readReliabilityOperation(identity2);
|
|
10630
|
+
const operation = record5?.state.operation;
|
|
10631
|
+
const entries = record5?.state.operationHistory.filter((entry2) => entry2.id === operation?.id);
|
|
10632
|
+
const entry = entries?.[0];
|
|
10633
|
+
if (!record5 || !(0, import_node_util9.isDeepStrictEqual)(record5.identity, identity2) || record5.worker || !operation || operation.kind !== "ensure" || !operation.drained || !["COMPLETED", "INTERRUPTED", "COMPLETION_UNKNOWN"].includes(operation.status) || record5.state.phase !== "stopping" || record5.state.desired !== "stopped-by-user" || entries?.length !== 1 || !entry || entry.kind !== "ensure" || !entry.profile || !entry.drained || entry.status !== operation.status)
|
|
10634
|
+
throw new Error("Initial managed stop requires the drained ensure's recorded profile.");
|
|
10635
|
+
return {
|
|
10636
|
+
identity: record5.identity,
|
|
10637
|
+
fence: reliabilityFence(record5.state),
|
|
10638
|
+
operation,
|
|
10639
|
+
entry
|
|
10640
|
+
};
|
|
10641
|
+
};
|
|
10642
|
+
const authority = readAuthority();
|
|
10643
|
+
const gitCommonDir = linked ? resolveGitCommonDir(repoPath) : void 0;
|
|
10644
|
+
const workspaceEnv = workspace && gitCommonDir ? { token: workspace, gitCommonDir } : void 0;
|
|
10534
10645
|
const registration2 = () => {
|
|
10535
10646
|
resetWorkspaceRuntimeCaches();
|
|
10536
10647
|
if (resolveWorkspaceRuntimeOrDefault(repoPath) !== "devsy")
|
|
@@ -10540,14 +10651,20 @@ function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
|
|
|
10540
10651
|
throw new Error("Initial managed stop requires one exact Devsy registration.");
|
|
10541
10652
|
if (linked) {
|
|
10542
10653
|
const record5 = workspace ? readWorkspaceOwnership(repoPath, workspace) : void 0;
|
|
10543
|
-
if (!record5 || record5.devpodId !== devsyId || !sameWorkspacePath(record5.worktreePath, repoPath) || resolveWorktreeWorkspace(repoPath) !== workspace)
|
|
10654
|
+
if (!record5 || record5.devpodId !== devsyId || !sameWorkspacePath(record5.worktreePath, repoPath) || resolveWorktreeWorkspace(repoPath) !== workspace || resolveGitCommonDir(repoPath) !== gitCommonDir || inspectWorkspaceOwnership(record5, listGitWorktrees(repoPath), void 0).ownerStatus !== "present")
|
|
10544
10655
|
throw new Error("Initial managed stop workspace ownership changed.");
|
|
10545
10656
|
}
|
|
10546
10657
|
return owner2.workspace;
|
|
10547
10658
|
};
|
|
10548
|
-
const runtime = loadRuntimeConfig(repoPath, workspace ?? "");
|
|
10549
|
-
if (!runtime.config.managedRuntime
|
|
10659
|
+
const runtime = loadRuntimeConfig(repoPath, workspace ?? "", authority.entry.profile);
|
|
10660
|
+
if (!runtime.config.managedRuntime || runtime.profile !== authority.entry.profile)
|
|
10661
|
+
throw new Error("Initial managed stop requires the recorded managed profile.");
|
|
10550
10662
|
const owner = registration2();
|
|
10663
|
+
proveLocalDockerSelection(owner);
|
|
10664
|
+
const endpoint = resolveManagedStopEndpoint();
|
|
10665
|
+
if (!supportsManagedStopBaseline(endpoint))
|
|
10666
|
+
throw new Error("Initial managed stop requires a pinned local Docker endpoint.");
|
|
10667
|
+
const daemon = inspectManagedStopDaemon(endpoint);
|
|
10551
10668
|
if (!owner.context || !/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(owner.context) || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(devsyId))
|
|
10552
10669
|
throw new Error("Initial managed stop requires exact provider context.");
|
|
10553
10670
|
const plan = inspectManagedDevcontainerConfig({
|
|
@@ -10567,27 +10684,51 @@ function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
|
|
|
10567
10684
|
".docker-compose"
|
|
10568
10685
|
);
|
|
10569
10686
|
const observe = () => {
|
|
10570
|
-
if (!(0, import_node_util9.isDeepStrictEqual)(registration2(), owner) || readManagedRuntimeState(repoPath, workspace))
|
|
10571
|
-
throw new Error("Initial managed stop
|
|
10687
|
+
if (!(0, import_node_util9.isDeepStrictEqual)(readAuthority(), authority) || !(0, import_node_util9.isDeepStrictEqual)(registration2(), owner) || readManagedRuntimeState(repoPath, workspace) || resolveManagedStopEndpoint() !== endpoint || inspectManagedStopDaemon(endpoint) !== daemon)
|
|
10688
|
+
throw new Error("Initial managed stop authority or runtime state changed.");
|
|
10689
|
+
proveLocalDockerSelection(owner);
|
|
10690
|
+
if (listDevpodWorkspacesRaw({ readLocalWhenMissing: true }).some(
|
|
10691
|
+
(entry) => entry.id === devsyId || entry.source.localFolder !== "" && sameWorkspacePath(entry.source.localFolder, repoPath)
|
|
10692
|
+
))
|
|
10693
|
+
throw new Error("Initial managed stop found conflicting provider ownership.");
|
|
10694
|
+
const currentRuntime = loadRuntimeConfig(repoPath, workspace ?? "", authority.entry.profile);
|
|
10695
|
+
const currentPlan = inspectManagedDevcontainerConfig({
|
|
10696
|
+
repoPath,
|
|
10697
|
+
config: currentRuntime.config,
|
|
10698
|
+
profile: currentRuntime.resolvedProfile,
|
|
10699
|
+
linked
|
|
10700
|
+
});
|
|
10701
|
+
if (currentRuntime.profile !== authority.entry.profile || !(0, import_node_util9.isDeepStrictEqual)(currentRuntime.resolvedProfile, runtime.resolvedProfile) || !(0, import_node_util9.isDeepStrictEqual)(currentPlan, plan) || inspectManagedDevcontainerGeneratedConfig(currentPlan).status !== "valid")
|
|
10702
|
+
throw new Error("Initial managed stop configuration changed.");
|
|
10572
10703
|
const matches = inspectWorkspaceContainers().filter(
|
|
10573
10704
|
(c) => sameWorkspacePath(
|
|
10574
10705
|
c.labels["com.docker.compose.project.working_dir"] ?? "",
|
|
10575
10706
|
plan.composeDirectory
|
|
10576
10707
|
)
|
|
10577
10708
|
);
|
|
10578
|
-
if (!matches.length)
|
|
10709
|
+
if (!matches.length)
|
|
10710
|
+
throw new Error("Initial managed stop requires its complete selected population.");
|
|
10579
10711
|
const projects = new Set(matches.map((c) => c.labels["com.docker.compose.project"]));
|
|
10580
10712
|
if (projects.size !== 1 || !matches[0]?.labels["com.docker.compose.project"])
|
|
10581
10713
|
throw new Error("Initial managed stop requires one exact Compose project.");
|
|
10582
10714
|
const population = inspectManagedStopContainers(
|
|
10583
|
-
matches[0].labels["com.docker.compose.project"]
|
|
10715
|
+
matches[0].labels["com.docker.compose.project"],
|
|
10716
|
+
endpoint
|
|
10584
10717
|
);
|
|
10585
10718
|
if (!sameSet(
|
|
10719
|
+
inspectManagedStopWorkspaceIds(endpoint, plan.composeDirectory),
|
|
10720
|
+
population.map((c) => c.id)
|
|
10721
|
+
) || !sameSet(
|
|
10586
10722
|
matches.map((c) => c.id),
|
|
10587
10723
|
population.map((c) => c.id)
|
|
10588
10724
|
))
|
|
10589
10725
|
throw new Error("Initial managed stop population changed.");
|
|
10590
|
-
|
|
10726
|
+
if (!sameSet(
|
|
10727
|
+
population.map((c) => c.labels["com.docker.compose.service"] ?? ""),
|
|
10728
|
+
plan.desiredServices
|
|
10729
|
+
))
|
|
10730
|
+
throw new Error("Initial managed stop requires its complete selected population.");
|
|
10731
|
+
const primary = proveManagedComposePopulation({
|
|
10591
10732
|
plan,
|
|
10592
10733
|
repoPath,
|
|
10593
10734
|
composeProject: matches[0].labels["com.docker.compose.project"],
|
|
@@ -10595,9 +10736,23 @@ function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
|
|
|
10595
10736
|
featureDirectory,
|
|
10596
10737
|
containers: population
|
|
10597
10738
|
});
|
|
10739
|
+
const uidBytes = Buffer.byteLength(owner.uid ?? "");
|
|
10740
|
+
const runnerId = (uidBytes === 16 || uidBytes === 40 ? owner.uid : void 0) ?? devsyId;
|
|
10741
|
+
if (owner.source.container && owner.source.container !== primary.id || !owner.source.container && inspectManagedStopRunnerId(endpoint, primary.id) !== runnerId)
|
|
10742
|
+
throw new Error("Initial managed stop provider-to-container binding changed.");
|
|
10743
|
+
if (!owner.source.container && !sameSet(inspectProviderRunnerContainers(endpoint, runnerId), [primary.id]))
|
|
10744
|
+
throw new Error("Initial managed stop provider runner population changed.");
|
|
10745
|
+
assertManagedContainerConfigUnchanged({
|
|
10746
|
+
plan,
|
|
10747
|
+
containers: population,
|
|
10748
|
+
workspace: workspaceEnv
|
|
10749
|
+
});
|
|
10750
|
+
if (!(0, import_node_util9.isDeepStrictEqual)(readAuthority(), authority) || !(0, import_node_util9.isDeepStrictEqual)(registration2(), owner) || resolveManagedStopEndpoint() !== endpoint || inspectManagedStopDaemon(endpoint) !== daemon)
|
|
10751
|
+
throw new Error("Initial managed stop authority changed during inspection.");
|
|
10598
10752
|
return population;
|
|
10599
10753
|
};
|
|
10600
10754
|
const initial = observe();
|
|
10755
|
+
const stopped = new Set(initial.filter((c) => !c.state.Running).map((c) => c.id));
|
|
10601
10756
|
const stable = () => {
|
|
10602
10757
|
const current = observe();
|
|
10603
10758
|
if (!sameSet(
|
|
@@ -10605,19 +10760,21 @@ function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
|
|
|
10605
10760
|
current.map((c) => c.id)
|
|
10606
10761
|
) || current.some((c) => {
|
|
10607
10762
|
const prior = initial.find((p) => p.id === c.id);
|
|
10608
|
-
return !prior || containerIdentity(prior) !== containerIdentity(c) ||
|
|
10763
|
+
return !prior || containerIdentity(prior) !== containerIdentity(c) || stopped.has(c.id) && c.state.Running;
|
|
10609
10764
|
}))
|
|
10610
10765
|
throw new Error("Initial managed stop population or identity changed.");
|
|
10766
|
+
for (const c of current) if (!c.state.Running) stopped.add(c.id);
|
|
10611
10767
|
return current;
|
|
10612
10768
|
};
|
|
10613
10769
|
stable();
|
|
10614
|
-
if (!initial.length) return false;
|
|
10615
10770
|
for (const container of initial) {
|
|
10616
10771
|
const current = stable().find((c) => c.id === container.id);
|
|
10617
|
-
if (current?.state.Running)
|
|
10618
|
-
|
|
10619
|
-
|
|
10620
|
-
|
|
10772
|
+
if (current?.state.Running) {
|
|
10773
|
+
claimLifecycleEffect();
|
|
10774
|
+
stopPinnedManagedContainer(endpoint, current.id);
|
|
10775
|
+
if (stable().find((c) => c.id === current.id)?.state.Running)
|
|
10776
|
+
throw new Error("Initial managed stop container cessation is not proven.");
|
|
10777
|
+
}
|
|
10621
10778
|
}
|
|
10622
10779
|
if (stable().some((c) => c.state.Running))
|
|
10623
10780
|
throw new Error("Initial managed stop left a workload running.");
|
|
@@ -10837,11 +10994,15 @@ var init_managed_devsy_stop = __esm({
|
|
|
10837
10994
|
init_devcontainer_profile();
|
|
10838
10995
|
init_devpod_environment();
|
|
10839
10996
|
init_devpod_registry();
|
|
10997
|
+
init_devsy_exec_proof();
|
|
10840
10998
|
init_devsy_workspaces();
|
|
10841
10999
|
init_host_routes();
|
|
10842
11000
|
init_managed_compose_population();
|
|
10843
11001
|
init_managed_runtime_state();
|
|
10844
11002
|
init_managed_stop_recovery();
|
|
11003
|
+
init_reliability_context();
|
|
11004
|
+
init_reliability_contract();
|
|
11005
|
+
init_reliability_operation_store();
|
|
10845
11006
|
init_repo_config();
|
|
10846
11007
|
init_route_publication();
|
|
10847
11008
|
init_traefik_route_health();
|
|
@@ -20955,7 +21116,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
20955
21116
|
const config = runtimeConfig.config;
|
|
20956
21117
|
loadedConfig = config;
|
|
20957
21118
|
loadedWorkspace = runtimeConfig.workspace;
|
|
20958
|
-
const cliVersion = true ? "0.0.
|
|
21119
|
+
const cliVersion = true ? "0.0.75" : "0.0.0-dev";
|
|
20959
21120
|
const configVersion = config.devrouter?.version;
|
|
20960
21121
|
if (configVersion && cliVersion !== "0.0.0-dev" && compareSemver(configVersion, cliVersion) > 0) {
|
|
20961
21122
|
addCheck(checks, {
|
|
@@ -26396,7 +26557,7 @@ var init_version = __esm({
|
|
|
26396
26557
|
|
|
26397
26558
|
// src/cli.ts
|
|
26398
26559
|
var import_commander = require("commander");
|
|
26399
|
-
var CLI_VERSION = true ? "0.0.
|
|
26560
|
+
var CLI_VERSION = true ? "0.0.75" : "0.0.0-dev";
|
|
26400
26561
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
26401
26562
|
function withErrorHandling(action2) {
|
|
26402
26563
|
return async (...args) => {
|
package/package.json
CHANGED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Upgrade to devrouter 0.0.75
|
|
2
|
+
|
|
3
|
+
This patch fixes canonical stop after initial managed Devsy startup is cancelled
|
|
4
|
+
before managed runtime state is saved. Stop uses the exact drained ensure's
|
|
5
|
+
recorded profile and validates complete live ownership and Compose configuration
|
|
6
|
+
hashes. No configuration schema, command, flag or runtime-provider migration is
|
|
7
|
+
required.
|
|
8
|
+
|
|
9
|
+
## Task
|
|
10
|
+
|
|
11
|
+
Use the published 0.0.75 CLI. Update `.devrouter.yml` devrouter.version to 0.0.75
|
|
12
|
+
only when consumer source changes are authorized. Preserve staged work owned by
|
|
13
|
+
another task. Refresh generated agent guidance only with the repository owner's
|
|
14
|
+
authority. No DevPod installation is needed.
|
|
15
|
+
|
|
16
|
+
For an affected exact checkout, use `devrouter stop <path> --json` with the same
|
|
17
|
+
non-secret Compose inputs used at startup. Existing interrupted workspaces can
|
|
18
|
+
recover when the exact operation history and all live configuration and ownership
|
|
19
|
+
proofs remain available. Missing, unreadable, conflicting or changed evidence
|
|
20
|
+
remains a refusal; never fabricate journal state or replace the selected profile
|
|
21
|
+
with the default to bypass it. Stop is non-destructive and retains volumes.
|
|
22
|
+
|
|
23
|
+
## Validation
|
|
24
|
+
|
|
25
|
+
Verify the released CLI revision and exact checkout ownership. Let the checkout's
|
|
26
|
+
runtime owner perform the canonical stop, require provider cessation and route
|
|
27
|
+
removal proof, then verify stopped lifecycle state. Revalidate port conflicts
|
|
28
|
+
before a new ensure and require its own provider, application and route proof.
|
|
29
|
+
A successful stop or source test does not prove successful application startup.
|
|
30
|
+
|
|
31
|
+
## Report
|
|
32
|
+
|
|
33
|
+
Report release version/revision, exact checkout, producing stop result and
|
|
34
|
+
lifecycle state, subsequent ensure evidence or precise refusal, and source/index
|
|
35
|
+
preservation. Separate released source from live consumer acceptance.
|