@askexenow/exe-os 0.9.392 → 0.9.393
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/deploy/stack-manifests/v0.9.json +134 -1
- package/dist/.dist-verified.json +3 -3
- package/dist/bin/cli.js +3 -3
- package/dist/bin/registry-proxy.js +1 -1
- package/dist/bin/stack-update.js +54 -4
- package/dist/bin/vps-health-gate.js +1 -1
- package/dist/build-manifest.json +34 -34
- package/dist/{chunk-PRCJG3PK.js → chunk-NJ57AHX4.js} +1 -1
- package/dist/{chunk-33CHRORT.js → chunk-POBFVHIS.js} +1 -1
- package/dist/{chunk-TVSIS36M.js → chunk-V57YDQQA.js} +1 -1
- package/dist/{chunk-3SXU7KLW.js → chunk-WMGS5U2J.js} +188 -0
- package/dist/hooks/manifest.json +1 -1
- package/dist/lib/registry-proxy.js +1 -1
- package/dist/{stack-generate-manifest-QWU7Q4MJ.js → stack-generate-manifest-XZ534AJH.js} +2 -2
- package/dist/{stack-promote-26RFMNSB.js → stack-promote-EAPCVGKJ.js} +2 -2
- package/dist/{stack-release-7YHSLY7J.js → stack-release-YEO6BFVR.js} +3 -3
- package/dist/{stack-update-DTMW7GMW.js → stack-update-NEDES5S4.js} +1 -1
- package/package.json +1 -1
- package/release-notes.json +11 -8
|
@@ -4909,11 +4909,144 @@
|
|
|
4909
4909
|
"composeSha256": "220b251375f372107e8d8d54a9c3e4ceab1f57aae80f4babf2933c3887532263",
|
|
4910
4910
|
"composeOverrideSha256": "af295ca2f75b85788416e4df51cab86d8b773bf4cafe6cf6df9c7c26b9a42d6d"
|
|
4911
4911
|
}
|
|
4912
|
+
},
|
|
4913
|
+
"0.9.53": {
|
|
4914
|
+
"version": "0.9.53",
|
|
4915
|
+
"releasedAt": "2026-09-23T21:55:18.488Z",
|
|
4916
|
+
"npmVersion": "0.9.393",
|
|
4917
|
+
"notes": "Dashboard-only Exe dogfood canary replacing unapplied 0.9.52: npm 0.9.393 scopes retained-Compose health to Dashboard, required core, and rendered dependencies while recording unchanged unrelated red containers and failing new regressions. From live stack 0.9.50, update only Dashboard to v0.9.392. Preserve CRM v0.9.66, Auth v0.6.10, and every other service pin. Signed live base and override Compose bytes are unchanged; no config assets are delivered. Public DEMO remains disabled pending separate CRM rollout.",
|
|
4918
|
+
"services": {
|
|
4919
|
+
"exe-db": {
|
|
4920
|
+
"image": "update.askexe.com/askexe/pgvector:0.8.0-pg16@sha256:a132765ec351c65111b5b675928a3a0515a466a40f97277329db8b8209ad8bc9",
|
|
4921
|
+
"env": "EXE_DB_IMAGE",
|
|
4922
|
+
"composeService": "exe-db",
|
|
4923
|
+
"required": true,
|
|
4924
|
+
"category": "core",
|
|
4925
|
+
"description": "Postgres (pgvector) — digest-pinned (bug 32d6e02f; was tag-only in 0.9.25, regressed from 0.9.24)"
|
|
4926
|
+
},
|
|
4927
|
+
"exe-os": {
|
|
4928
|
+
"image": "update.askexe.com/askexe/exe-os:v0.9.382@sha256:266a59a482865eab9f79497999acb33c1fe1868ec54ea5cd1ce971c492f11bd6",
|
|
4929
|
+
"env": "EXE_OS_IMAGE_TAG",
|
|
4930
|
+
"composeService": "exe-os",
|
|
4931
|
+
"healthUrl": "http://127.0.0.1:8765/health",
|
|
4932
|
+
"required": true,
|
|
4933
|
+
"category": "core",
|
|
4934
|
+
"description": "exe-os daemon + MCP server"
|
|
4935
|
+
},
|
|
4936
|
+
"crm": {
|
|
4937
|
+
"image": "update.askexe.com/askexe/exe-crm:v0.9.66@sha256:38bbae74ddd33dbbd62175a46ad0d3f99ef6c671b0c2187e35398ca9c504c3eb",
|
|
4938
|
+
"env": "CRM_IMAGE_TAG",
|
|
4939
|
+
"composeService": "exe-crm",
|
|
4940
|
+
"healthUrl": "http://127.0.0.1:3000/healthz",
|
|
4941
|
+
"category": "app",
|
|
4942
|
+
"gitSha": "a3d107483304d10b05c9f1ee5e1b0182c4628e65",
|
|
4943
|
+
"description": "Central authentication and recovery with server-validated shared sessions for CRM web and worker."
|
|
4944
|
+
},
|
|
4945
|
+
"wiki": {
|
|
4946
|
+
"image": "update.askexe.com/askexe/exe-wiki:v0.9.37@sha256:8fa22e77c0742fbb690f7b4c8431a186692a20ebd335fb141782df4289dc337f",
|
|
4947
|
+
"env": "WIKI_IMAGE_TAG",
|
|
4948
|
+
"composeService": "exe-wiki",
|
|
4949
|
+
"healthUrl": "http://127.0.0.1:3001/api/ping",
|
|
4950
|
+
"category": "app",
|
|
4951
|
+
"description": "Central hosted authentication and recovery with server-validated shared sessions, membership enforcement, and no product-local credential form.",
|
|
4952
|
+
"gitSha": "713a4370c2b641b8f8b07fd1e7390afa79a9c931"
|
|
4953
|
+
},
|
|
4954
|
+
"gateway": {
|
|
4955
|
+
"image": "update.askexe.com/askexe/exe-gateway:v2026.08.07-c15f093-stamped@sha256:1bc11a2a0ad1f3929d59d2685696f22a72042b9fca9c75e15c02dc7d3c640105",
|
|
4956
|
+
"env": "GATEWAY_IMAGE_TAG",
|
|
4957
|
+
"composeService": "exe-gateway",
|
|
4958
|
+
"healthUrl": "http://127.0.0.1:3100/health",
|
|
4959
|
+
"category": "app",
|
|
4960
|
+
"description": "WhatsApp/messaging gateway — provenance-stamped rebuild of main (outbound message persistence fix); pinned by digest, dated immutable tag.",
|
|
4961
|
+
"gitSha": "c15f093a0f59730bd5c2c73791ff77059dfa7cc1"
|
|
4962
|
+
},
|
|
4963
|
+
"monitorAgent": {
|
|
4964
|
+
"image": "update.askexe.com/askexe/exe-monitor-agent:v2026.08.09-10660eb4-stamped@sha256:29fbd445f79484df04f000603e4ff445e76f0380f86d687a0033e3a0ef7d1b7a",
|
|
4965
|
+
"env": "MONITOR_AGENT_IMAGE_TAG",
|
|
4966
|
+
"composeService": "exe-monitor-agent",
|
|
4967
|
+
"category": "monitoring",
|
|
4968
|
+
"gitSha": "10660eb4abdeffbcba2aad13549aa58e208ac7a3"
|
|
4969
|
+
},
|
|
4970
|
+
"monitorHub": {
|
|
4971
|
+
"image": "update.askexe.com/askexe/exe-monitor-hub:v2026.08.09-10660eb4-stamped@sha256:c9a9218c2713b8dffea7e1cf8c0702a614657d311a7a4e821c6a543bab29bb97",
|
|
4972
|
+
"env": "MONITOR_HUB_IMAGE_TAG",
|
|
4973
|
+
"composeService": "exe-monitor-hub",
|
|
4974
|
+
"healthUrl": "http://127.0.0.1:8090/api/health",
|
|
4975
|
+
"category": "monitoring",
|
|
4976
|
+
"gitSha": "10660eb4abdeffbcba2aad13549aa58e208ac7a3"
|
|
4977
|
+
},
|
|
4978
|
+
"auth": {
|
|
4979
|
+
"image": "update.askexe.com/askexe/exe-auth:v0.6.10@sha256:0260349962d087cd3c33fed1d362029416e82ae9cc60abca7969beac2cb8639f",
|
|
4980
|
+
"env": "AUTH_IMAGE_TAG",
|
|
4981
|
+
"composeService": "exe-auth",
|
|
4982
|
+
"healthUrl": "http://127.0.0.1:3300/",
|
|
4983
|
+
"category": "auth",
|
|
4984
|
+
"description": "GoTrue SSO and privileged license authority bridge; stateless auth proxy.",
|
|
4985
|
+
"gitSha": "29fe7015d90b80c94db3a1e3904852b934071711"
|
|
4986
|
+
},
|
|
4987
|
+
"erp": {
|
|
4988
|
+
"image": "update.askexe.com/askexe/exe-erp:v0.3.17@sha256:ef61b59d94c04189fe2975045a3816d2fecc8efe3027e0ee8c17d0fa2efdbc3b",
|
|
4989
|
+
"env": "ERP_IMAGE_TAG",
|
|
4990
|
+
"composeService": "exe-erp",
|
|
4991
|
+
"healthUrl": "http://127.0.0.1:8069/api/method/ping",
|
|
4992
|
+
"healthHost": "localhost",
|
|
4993
|
+
"required": false,
|
|
4994
|
+
"category": "app",
|
|
4995
|
+
"description": "Enterprise Resource Planning with central hosted authentication and subject-bound organization admission.",
|
|
4996
|
+
"gitSha": "a769ec5e0ae53bc5944715845869715ebbffd63a"
|
|
4997
|
+
},
|
|
4998
|
+
"gotrue": {
|
|
4999
|
+
"image": "update.askexe.com/askexe/gotrue:v2.172.1@sha256:b0dd7aa28dd1f9a8bd31f136c8b912661f701d9b863171e5843cb08f18f49de4",
|
|
5000
|
+
"composeService": "gotrue",
|
|
5001
|
+
"healthUrl": "http://127.0.0.1:9999/health",
|
|
5002
|
+
"category": "infra"
|
|
5003
|
+
},
|
|
5004
|
+
"redis": {
|
|
5005
|
+
"image": "update.askexe.com/askexe/redis:7.4-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99",
|
|
5006
|
+
"composeService": "redis",
|
|
5007
|
+
"category": "infra"
|
|
5008
|
+
},
|
|
5009
|
+
"clickhouse": {
|
|
5010
|
+
"image": "update.askexe.com/askexe/clickhouse-server:24.8.4.13-alpine@sha256:88a45f9e328549b2579256c46ee38e5c0e25ae58303d9eb6d9c7ed8d6d2bbf3c",
|
|
5011
|
+
"composeService": "clickhouse",
|
|
5012
|
+
"category": "infra"
|
|
5013
|
+
},
|
|
5014
|
+
"cloudflared": {
|
|
5015
|
+
"image": "update.askexe.com/askexe/cloudflared:2026-07@sha256:ba461b8aa9c042156dbd39c38657fe7431bafa063220eab8d5330a523863da9f",
|
|
5016
|
+
"composeService": "cloudflared",
|
|
5017
|
+
"category": "infra"
|
|
5018
|
+
},
|
|
5019
|
+
"exe-sso-edge": {
|
|
5020
|
+
"image": "update.askexe.com/askexe/nginx:alpine@sha256:20316569d8f81a160065d7d2a5eeffc7ca97d79022462ee255fd23fa103a6b5c",
|
|
5021
|
+
"composeService": "exe-sso-edge",
|
|
5022
|
+
"category": "infra"
|
|
5023
|
+
},
|
|
5024
|
+
"exe-otel-collector": {
|
|
5025
|
+
"image": "update.askexe.com/askexe/otel-collector-contrib:0.114.0@sha256:37fa87091cfaaec7234a27e4e395a40c31c2bfaea97a349a4afef6d9e9681197",
|
|
5026
|
+
"composeService": "exe-otel-collector",
|
|
5027
|
+
"category": "infra"
|
|
5028
|
+
},
|
|
5029
|
+
"dashboard": {
|
|
5030
|
+
"image": "update.askexe.com/askexe/exe-dashboard:v0.9.392@sha256:d151441554c00e216084bd1caf2278e8c41fde188c039e0f167e158a511cbeec",
|
|
5031
|
+
"env": "DASHBOARD_IMAGE_TAG",
|
|
5032
|
+
"composeService": "exe-dashboard",
|
|
5033
|
+
"healthUrl": "http://127.0.0.1:3301/health",
|
|
5034
|
+
"required": false,
|
|
5035
|
+
"category": "optional",
|
|
5036
|
+
"description": "Customer dashboard at dashboard.<apex> — credits, usage, API keys, billing",
|
|
5037
|
+
"gitSha": "e11b25ad567389440da8ed5e566a9c59bce24123"
|
|
5038
|
+
}
|
|
5039
|
+
},
|
|
5040
|
+
"rolloutStage": "canary",
|
|
5041
|
+
"config": {
|
|
5042
|
+
"composeSha256": "220b251375f372107e8d8d54a9c3e4ceab1f57aae80f4babf2933c3887532263",
|
|
5043
|
+
"composeOverrideSha256": "af295ca2f75b85788416e4df51cab86d8b773bf4cafe6cf6df9c7c26b9a42d6d"
|
|
5044
|
+
}
|
|
4912
5045
|
}
|
|
4913
5046
|
},
|
|
4914
5047
|
"signature": {
|
|
4915
5048
|
"keyId": "exe-stack-1",
|
|
4916
5049
|
"alg": "ed25519",
|
|
4917
|
-
"signature": "
|
|
5050
|
+
"signature": "sr79I2vY2ZVjMGGV/aGJp5i3sT3+nZX0urNqH7jw10Zu1yZNZa62y1973V6b2N5DKNwjE7aZHlQn5aF6nouBDg=="
|
|
4918
5051
|
}
|
|
4919
5052
|
}
|
package/dist/.dist-verified.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"verified_at": "2026-09-
|
|
4
|
-
"manifest_sha256": "
|
|
5
|
-
"package_version": "0.9.
|
|
3
|
+
"verified_at": "2026-09-23T22:15:04.008Z",
|
|
4
|
+
"manifest_sha256": "c3c456977d8ec9e709146a39b984af444449c4bc1716922aa8323e33f06bdfa9",
|
|
5
|
+
"package_version": "0.9.393"
|
|
6
6
|
}
|
package/dist/bin/cli.js
CHANGED
|
@@ -798,14 +798,14 @@ ${JSON.stringify(stormAlert, null, 2)}`);
|
|
|
798
798
|
const { runStackUpdateCli } = await import("./stack-update.js");
|
|
799
799
|
await runStackUpdateCli(args.slice(1));
|
|
800
800
|
} else if (args[0] === "release") {
|
|
801
|
-
const { parseReleaseArgs, runStackRelease } = await import("../stack-release-
|
|
801
|
+
const { parseReleaseArgs, runStackRelease } = await import("../stack-release-YEO6BFVR.js");
|
|
802
802
|
const releaseFlags = parseReleaseArgs(args.slice(1));
|
|
803
803
|
await runStackRelease(releaseFlags);
|
|
804
804
|
} else if (args[0] === "stack-promote") {
|
|
805
|
-
const { runStackPromoteCli } = await import("../stack-promote-
|
|
805
|
+
const { runStackPromoteCli } = await import("../stack-promote-EAPCVGKJ.js");
|
|
806
806
|
await runStackPromoteCli(args.slice(1));
|
|
807
807
|
} else if (args[0] === "stack-generate-manifest") {
|
|
808
|
-
const { runStackGenerateManifestCli } = await import("../stack-generate-manifest-
|
|
808
|
+
const { runStackGenerateManifestCli } = await import("../stack-generate-manifest-XZ534AJH.js");
|
|
809
809
|
process.exit(await runStackGenerateManifestCli(args.slice(1)));
|
|
810
810
|
} else if (args[0] === "repo-truth") {
|
|
811
811
|
const { runRepoTruthCli } = await import("./exe-repo-truth.js");
|
package/dist/bin/stack-update.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
assertRetainedComposeRenderedImage,
|
|
8
8
|
assertRetainedComposeRunningService,
|
|
9
9
|
assertSignedManifestDeliveryGate,
|
|
10
|
+
assessRetainedHealthBefore,
|
|
10
11
|
backupStackConfig,
|
|
11
12
|
bootstrapStackHost,
|
|
12
13
|
builtinStackManifestPublicKeyPath,
|
|
@@ -23,6 +24,7 @@ import {
|
|
|
23
24
|
loadStackManifestWithFallback,
|
|
24
25
|
parseComposeVolumeNames,
|
|
25
26
|
parseEnv,
|
|
27
|
+
parseRetainedContainerHealth,
|
|
26
28
|
patchEnv,
|
|
27
29
|
printDanglingVolumes,
|
|
28
30
|
printVolumeCleanupResult,
|
|
@@ -33,6 +35,9 @@ import {
|
|
|
33
35
|
reportStackManifestSource,
|
|
34
36
|
requiredImagePinKeys,
|
|
35
37
|
resolveComposeProjectName,
|
|
38
|
+
retainedCompletedDependencies,
|
|
39
|
+
retainedContainerIsHealthy,
|
|
40
|
+
retainedCriticalServices,
|
|
36
41
|
runScopedServiceSelection,
|
|
37
42
|
runStackUpdate,
|
|
38
43
|
saveServiceSelection,
|
|
@@ -41,7 +46,7 @@ import {
|
|
|
41
46
|
verifyManifestImagesAvailable,
|
|
42
47
|
warnUnmanagedManifestServices,
|
|
43
48
|
withStackUpdateOperationLock
|
|
44
|
-
} from "../chunk-
|
|
49
|
+
} from "../chunk-WMGS5U2J.js";
|
|
45
50
|
import "../chunk-EC5H53YD.js";
|
|
46
51
|
import {
|
|
47
52
|
runVerifyStack
|
|
@@ -57,7 +62,7 @@ import {
|
|
|
57
62
|
import {
|
|
58
63
|
logResult,
|
|
59
64
|
runHealthGate
|
|
60
|
-
} from "../chunk-
|
|
65
|
+
} from "../chunk-POBFVHIS.js";
|
|
61
66
|
import "../chunk-L25OAFOU.js";
|
|
62
67
|
import "../chunk-RT57D7C4.js";
|
|
63
68
|
import "../chunk-FTZET5YX.js";
|
|
@@ -2076,7 +2081,25 @@ function readInstalledVersion(lockFile) {
|
|
|
2076
2081
|
return void 0;
|
|
2077
2082
|
}
|
|
2078
2083
|
}
|
|
2079
|
-
function printChanges(changes, composeFile, envFile) {
|
|
2084
|
+
function printChanges(changes, composeFile, envFile, retainedHealth) {
|
|
2085
|
+
if (retainedHealth) {
|
|
2086
|
+
if (changes.length > 0) {
|
|
2087
|
+
console.log("Planned image tag changes:");
|
|
2088
|
+
for (const c of changes) console.log(` - ${c.service}: ${c.key}
|
|
2089
|
+
${c.before ?? "<unset>"} \u2192 ${c.after}`);
|
|
2090
|
+
}
|
|
2091
|
+
console.log("\nCurrent container health (selected service and required dependencies are gates):");
|
|
2092
|
+
for (const [service, container] of retainedHealth.containers) {
|
|
2093
|
+
const critical = retainedHealth.critical.has(service);
|
|
2094
|
+
const healthy = retainedContainerIsHealthy(container, retainedHealth.completedDependencies?.has(service));
|
|
2095
|
+
const label = critical ? "required for this update" : "unrelated, unchanged baseline";
|
|
2096
|
+
console.log(` ${healthy ? "\u2705" : critical ? "\u274C" : "\u26A0\uFE0F"} ${service}: ${container.state}${container.health ? ` (health: ${container.health})` : ""} \u2014 ${label}`);
|
|
2097
|
+
}
|
|
2098
|
+
const failures = assessRetainedHealthBefore(retainedHealth);
|
|
2099
|
+
if (failures.length > 0) console.log(`
|
|
2100
|
+
\u{1F534} Retained-Compose health gate failed: ${failures.join(", ")}`);
|
|
2101
|
+
return failures.length;
|
|
2102
|
+
}
|
|
2080
2103
|
if (changes.length === 0) {
|
|
2081
2104
|
const running2 = areCliContainersRunning(composeFile, envFile);
|
|
2082
2105
|
if (running2) {
|
|
@@ -2111,6 +2134,23 @@ function printChanges(changes, composeFile, envFile) {
|
|
|
2111
2134
|
}
|
|
2112
2135
|
return 0;
|
|
2113
2136
|
}
|
|
2137
|
+
function captureRetainedHealthForCli(composeFile, envFile, selectedService, requiredCore) {
|
|
2138
|
+
const args = composeArgsForStack(composeFile, envFile);
|
|
2139
|
+
const config = spawnSync3("docker", [...args, "config", "--format", "json"], {
|
|
2140
|
+
encoding: "utf8",
|
|
2141
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
2142
|
+
timeout: 2e4
|
|
2143
|
+
});
|
|
2144
|
+
const critical = retainedCriticalServices(config.status === 0 ? config.stdout : null, selectedService, requiredCore);
|
|
2145
|
+
const completedDependencies = retainedCompletedDependencies(config.stdout, critical, selectedService, requiredCore);
|
|
2146
|
+
const ps = spawnSync3("docker", [...args, "ps", "--all", "--format", "json"], {
|
|
2147
|
+
encoding: "utf8",
|
|
2148
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
2149
|
+
timeout: 2e4
|
|
2150
|
+
});
|
|
2151
|
+
const containers = parseRetainedContainerHealth(ps.status === 0 ? ps.stdout : null);
|
|
2152
|
+
return { critical, completedDependencies, containers };
|
|
2153
|
+
}
|
|
2114
2154
|
function areCliContainersRunning(composeFile, envFile) {
|
|
2115
2155
|
try {
|
|
2116
2156
|
const result = spawnSync3("docker", [...composeArgsForStack(composeFile, envFile), "ps", "-q"], {
|
|
@@ -2511,7 +2551,16 @@ async function main(args = process.argv.slice(2)) {
|
|
|
2511
2551
|
console.log("");
|
|
2512
2552
|
}
|
|
2513
2553
|
}
|
|
2514
|
-
const
|
|
2554
|
+
const retainedHealth = opts.retainCompose && targetRelease ? captureRetainedHealthForCli(
|
|
2555
|
+
opts.composeFile,
|
|
2556
|
+
opts.envFile,
|
|
2557
|
+
Object.values(plan.release.services)[0].composeService ?? opts.serviceName,
|
|
2558
|
+
Object.entries(targetRelease.services).filter(([, service]) => service.required === true && service.category === "core").map(([name, service]) => service.composeService ?? name)
|
|
2559
|
+
) : void 0;
|
|
2560
|
+
const unhealthyCount = printChanges(plan.changes, opts.composeFile, opts.envFile, retainedHealth);
|
|
2561
|
+
if (opts.retainCompose && unhealthyCount > 0 && !opts.check && !opts.dryRun) {
|
|
2562
|
+
throw new Error("--retain-compose refused: selected service or required dependency is unhealthy");
|
|
2563
|
+
}
|
|
2515
2564
|
printBreaking(plan.breakingChanges);
|
|
2516
2565
|
if (opts.verifyImages) {
|
|
2517
2566
|
const started = Date.now();
|
|
@@ -2704,6 +2753,7 @@ export {
|
|
|
2704
2753
|
isProductionControlPlaneApply,
|
|
2705
2754
|
manifestSignatureSkipBanner,
|
|
2706
2755
|
parseArgs as parseStackUpdateArgs,
|
|
2756
|
+
printChanges,
|
|
2707
2757
|
reportPartialRun,
|
|
2708
2758
|
resolveManifestSignaturePolicy,
|
|
2709
2759
|
main as runStackUpdateCli,
|
package/dist/build-manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 2,
|
|
3
|
-
"generated_at": "2026-09-
|
|
3
|
+
"generated_at": "2026-09-23T22:15:03.947Z",
|
|
4
4
|
"files": [
|
|
5
5
|
{
|
|
6
6
|
"path": "active-agent-KMGOYJTP.js",
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
},
|
|
180
180
|
{
|
|
181
181
|
"path": "bin/cli.js",
|
|
182
|
-
"sha256": "
|
|
182
|
+
"sha256": "a26f29a3a9652a702b0bdafd1bbceb13389b3fffc4d49477eae926e855a59ee6",
|
|
183
183
|
"bytes": 69792
|
|
184
184
|
},
|
|
185
185
|
{
|
|
@@ -524,7 +524,7 @@
|
|
|
524
524
|
},
|
|
525
525
|
{
|
|
526
526
|
"path": "bin/registry-proxy.js",
|
|
527
|
-
"sha256": "
|
|
527
|
+
"sha256": "e4b41eb986a2f7baf4371bb8a1bd5ec046ef6741c5df16a1f7aaeda5cb946675",
|
|
528
528
|
"bytes": 1885
|
|
529
529
|
},
|
|
530
530
|
{
|
|
@@ -549,8 +549,8 @@
|
|
|
549
549
|
},
|
|
550
550
|
{
|
|
551
551
|
"path": "bin/stack-update.js",
|
|
552
|
-
"sha256": "
|
|
553
|
-
"bytes":
|
|
552
|
+
"sha256": "45e9139c3b040aff8c4e863ada54ca75c58c4c14b7c8571f67a599372a0978bb",
|
|
553
|
+
"bytes": 131290
|
|
554
554
|
},
|
|
555
555
|
{
|
|
556
556
|
"path": "bin/update.js",
|
|
@@ -569,7 +569,7 @@
|
|
|
569
569
|
},
|
|
570
570
|
{
|
|
571
571
|
"path": "bin/vps-health-gate.js",
|
|
572
|
-
"sha256": "
|
|
572
|
+
"sha256": "1b4e8961edf1b549fc3900950e8ddd6bf1bff6dc02fed969028f31b4c730a3d3",
|
|
573
573
|
"bytes": 333
|
|
574
574
|
},
|
|
575
575
|
{
|
|
@@ -672,11 +672,6 @@
|
|
|
672
672
|
"sha256": "0649a4d1eb38a53ced9d539731618da75464e0e191ebcc39b03aa2871071c2d4",
|
|
673
673
|
"bytes": 442
|
|
674
674
|
},
|
|
675
|
-
{
|
|
676
|
-
"path": "chunk-33CHRORT.js",
|
|
677
|
-
"sha256": "0f7fbaa13b4c7522f0b14a45b48ce2dfc004790e2577760afb9bb370e69ff90f",
|
|
678
|
-
"bytes": 7587
|
|
679
|
-
},
|
|
680
675
|
{
|
|
681
676
|
"path": "chunk-37IIJJZ7.js",
|
|
682
677
|
"sha256": "f7f9ea3373fb44a010f78ef8852bd264f8d67bea44c3ae9abc1d84c7d2771513",
|
|
@@ -717,11 +712,6 @@
|
|
|
717
712
|
"sha256": "46303e5db720a3f0b9ed8ecab75b9c6ea3c4a644f3805c6ae465e2fb9bd23fef",
|
|
718
713
|
"bytes": 5705
|
|
719
714
|
},
|
|
720
|
-
{
|
|
721
|
-
"path": "chunk-3SXU7KLW.js",
|
|
722
|
-
"sha256": "9df2f153a553b1270f7a9011d4f081732ea89b9ac2b042cb149b14f4ed44da22",
|
|
723
|
-
"bytes": 252039
|
|
724
|
-
},
|
|
725
715
|
{
|
|
726
716
|
"path": "chunk-3VW5ZP2F.js",
|
|
727
717
|
"sha256": "9eb8516063b9279b0556d589f9d7e3024b554ed2cf60cc84a58c32a193e85744",
|
|
@@ -1537,6 +1527,11 @@
|
|
|
1537
1527
|
"sha256": "cfdcf9141d53bd73b7b8cc3a4097773d1f854a9dffb7a81324f2782c7d70fe6c",
|
|
1538
1528
|
"bytes": 14891
|
|
1539
1529
|
},
|
|
1530
|
+
{
|
|
1531
|
+
"path": "chunk-NJ57AHX4.js",
|
|
1532
|
+
"sha256": "37cd6a8a4df230eca98e5fc2792fa39027c3ca8cbfbb5438f87680a1c996a755",
|
|
1533
|
+
"bytes": 40844
|
|
1534
|
+
},
|
|
1540
1535
|
{
|
|
1541
1536
|
"path": "chunk-NKPPPX6I.js",
|
|
1542
1537
|
"sha256": "4a5f8acc2c7b70708de8b68c7c3b7b3f5981395f2bd1a4db3b3b7151769910db",
|
|
@@ -1663,9 +1658,9 @@
|
|
|
1663
1658
|
"bytes": 3317
|
|
1664
1659
|
},
|
|
1665
1660
|
{
|
|
1666
|
-
"path": "chunk-
|
|
1667
|
-
"sha256": "
|
|
1668
|
-
"bytes":
|
|
1661
|
+
"path": "chunk-POBFVHIS.js",
|
|
1662
|
+
"sha256": "398f78513e36934eebeaceb2644137c3a95acb515783aa0bdf6dd970bb33cbb9",
|
|
1663
|
+
"bytes": 7587
|
|
1669
1664
|
},
|
|
1670
1665
|
{
|
|
1671
1666
|
"path": "chunk-PYS43F2X.js",
|
|
@@ -1862,11 +1857,6 @@
|
|
|
1862
1857
|
"sha256": "56262268c24e15325112a9d2d1dd785dea9fe96ac44e0c14ff243edd1fbd7e04",
|
|
1863
1858
|
"bytes": 76651
|
|
1864
1859
|
},
|
|
1865
|
-
{
|
|
1866
|
-
"path": "chunk-TVSIS36M.js",
|
|
1867
|
-
"sha256": "c12d360e3677fc87730097aab294f995d40c3bb8daf837fbe1856f258cc2a742",
|
|
1868
|
-
"bytes": 3766
|
|
1869
|
-
},
|
|
1870
1860
|
{
|
|
1871
1861
|
"path": "chunk-TWMWHDOY.js",
|
|
1872
1862
|
"sha256": "d1a4b120060e1bda1c09919ff863fbb281c71f017d89b31f47e8df07587814c0",
|
|
@@ -1917,6 +1907,11 @@
|
|
|
1917
1907
|
"sha256": "697ecdef6991c061baab1e9759bc14aecd28631954b2edfdb721c98c72d41c82",
|
|
1918
1908
|
"bytes": 1813
|
|
1919
1909
|
},
|
|
1910
|
+
{
|
|
1911
|
+
"path": "chunk-V57YDQQA.js",
|
|
1912
|
+
"sha256": "6284d4a8d979d18fdb3b863f59f91c7cd616c169349bb77766a94693477706e9",
|
|
1913
|
+
"bytes": 3766
|
|
1914
|
+
},
|
|
1920
1915
|
{
|
|
1921
1916
|
"path": "chunk-VGMACSEV.js",
|
|
1922
1917
|
"sha256": "4a51d1fb50f1389160ec2d06ebeb702976a647212f7731ab58f562de3f53f215",
|
|
@@ -1972,6 +1967,11 @@
|
|
|
1972
1967
|
"sha256": "288099f4b532013a4c9ba4c6129273a6f5036fc99f574e4b4d2b0fddc3792b67",
|
|
1973
1968
|
"bytes": 1549
|
|
1974
1969
|
},
|
|
1970
|
+
{
|
|
1971
|
+
"path": "chunk-WMGS5U2J.js",
|
|
1972
|
+
"sha256": "688da29e942b4732af8dc9d226f26a1c57c37e30581a97e30be5af4bfc4ad4ae",
|
|
1973
|
+
"bytes": 260597
|
|
1974
|
+
},
|
|
1975
1975
|
{
|
|
1976
1976
|
"path": "chunk-WPTIHQ6M.js",
|
|
1977
1977
|
"sha256": "a999baf6db449dcd8c856393a0721a50aceb27e74a49f71bbc6b553081d98fc2",
|
|
@@ -2574,7 +2574,7 @@
|
|
|
2574
2574
|
},
|
|
2575
2575
|
{
|
|
2576
2576
|
"path": "hooks/manifest.json",
|
|
2577
|
-
"sha256": "
|
|
2577
|
+
"sha256": "af052428c7e0f413b988ae47ed6a7120020847a8d665eb125ff24e0f5571b633",
|
|
2578
2578
|
"bytes": 1841
|
|
2579
2579
|
},
|
|
2580
2580
|
{
|
|
@@ -2879,7 +2879,7 @@
|
|
|
2879
2879
|
},
|
|
2880
2880
|
{
|
|
2881
2881
|
"path": "lib/registry-proxy.js",
|
|
2882
|
-
"sha256": "
|
|
2882
|
+
"sha256": "086622c69175e1c94ca91d2ac0dab2042db655eb14252e8acabc3e02fc2dd40b",
|
|
2883
2883
|
"bytes": 749
|
|
2884
2884
|
},
|
|
2885
2885
|
{
|
|
@@ -3463,8 +3463,8 @@
|
|
|
3463
3463
|
"bytes": 111
|
|
3464
3464
|
},
|
|
3465
3465
|
{
|
|
3466
|
-
"path": "stack-generate-manifest-
|
|
3467
|
-
"sha256": "
|
|
3466
|
+
"path": "stack-generate-manifest-XZ534AJH.js",
|
|
3467
|
+
"sha256": "5a3b5b3ab0b6160c45abf107a099e188db1cd3239f983c774bb32a4304d02fa9",
|
|
3468
3468
|
"bytes": 56960
|
|
3469
3469
|
},
|
|
3470
3470
|
{
|
|
@@ -3473,18 +3473,18 @@
|
|
|
3473
3473
|
"bytes": 4761
|
|
3474
3474
|
},
|
|
3475
3475
|
{
|
|
3476
|
-
"path": "stack-promote-
|
|
3477
|
-
"sha256": "
|
|
3476
|
+
"path": "stack-promote-EAPCVGKJ.js",
|
|
3477
|
+
"sha256": "5dbfd92d46224fa325522dcb29a0c37a04503bcbc240338e6dd81999915e41df",
|
|
3478
3478
|
"bytes": 7425
|
|
3479
3479
|
},
|
|
3480
3480
|
{
|
|
3481
|
-
"path": "stack-release-
|
|
3482
|
-
"sha256": "
|
|
3481
|
+
"path": "stack-release-YEO6BFVR.js",
|
|
3482
|
+
"sha256": "59e8eb373abf14f60ab5c7b758b8ab9cebe044490622af22c1af3746f0bd2102",
|
|
3483
3483
|
"bytes": 117550
|
|
3484
3484
|
},
|
|
3485
3485
|
{
|
|
3486
|
-
"path": "stack-update-
|
|
3487
|
-
"sha256": "
|
|
3486
|
+
"path": "stack-update-NEDES5S4.js",
|
|
3487
|
+
"sha256": "f70a348356634acc818edf94d0deaf756ca7ad3198d6f339b39b8358a6962afe",
|
|
3488
3488
|
"bytes": 7863
|
|
3489
3489
|
},
|
|
3490
3490
|
{
|
|
@@ -138,7 +138,7 @@ async function assertManifestSignature(manifest, publicKeyPem) {
|
|
|
138
138
|
"manifest carries no `signature`. Fleets that enforce EXE_STACK_PUBLIC_KEY reject unsigned manifests, so publishing one would ship a release no host can install. Re-sign with the custodied key: node scripts/sign-stack-manifest.mjs deploy/stack-manifests/v0.9.json"
|
|
139
139
|
);
|
|
140
140
|
}
|
|
141
|
-
const { verifyStackManifestSignature } = await import("./stack-update-
|
|
141
|
+
const { verifyStackManifestSignature } = await import("./stack-update-NEDES5S4.js");
|
|
142
142
|
try {
|
|
143
143
|
verifyStackManifestSignature(manifest, publicKeyPem);
|
|
144
144
|
} catch (err) {
|
|
@@ -212,7 +212,7 @@ async function main(args) {
|
|
|
212
212
|
console.log("[health-gate] Starting rollback...");
|
|
213
213
|
restorePreDeployBackup();
|
|
214
214
|
try {
|
|
215
|
-
const { rollbackStackUpdate, defaultStackPaths } = await import("./stack-update-
|
|
215
|
+
const { rollbackStackUpdate, defaultStackPaths } = await import("./stack-update-NEDES5S4.js");
|
|
216
216
|
const paths = defaultStackPaths();
|
|
217
217
|
await rollbackStackUpdate({
|
|
218
218
|
manifestRef: paths.manifestRef,
|
|
@@ -120,6 +120,162 @@ ${remedy}
|
|
|
120
120
|
return gaps;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
// src/lib/retained-compose-health.ts
|
|
124
|
+
function parseRecords(raw) {
|
|
125
|
+
if (raw === null || !raw.trim())
|
|
126
|
+
throw new Error("--retain-compose health state unavailable");
|
|
127
|
+
const trimmed = raw.trim().replace(/^\ufeff/, "");
|
|
128
|
+
let records;
|
|
129
|
+
try {
|
|
130
|
+
const parsed = JSON.parse(trimmed);
|
|
131
|
+
records = Array.isArray(parsed) ? parsed : [parsed];
|
|
132
|
+
} catch {
|
|
133
|
+
try {
|
|
134
|
+
records = trimmed.split("\n").filter(Boolean).map((line) => JSON.parse(line));
|
|
135
|
+
} catch {
|
|
136
|
+
throw new Error("--retain-compose health state could not be parsed");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (records.length === 0 || records.some(
|
|
140
|
+
(record) => !record || typeof record !== "object" || Array.isArray(record)
|
|
141
|
+
)) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
"--retain-compose health state contains no usable containers"
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
return records;
|
|
147
|
+
}
|
|
148
|
+
function parseRetainedContainerHealth(raw) {
|
|
149
|
+
const containers = /* @__PURE__ */ new Map();
|
|
150
|
+
for (const record of parseRecords(raw)) {
|
|
151
|
+
const service = String(record.Service ?? "").trim();
|
|
152
|
+
if (!service || containers.has(service))
|
|
153
|
+
throw new Error(
|
|
154
|
+
"--retain-compose health state has missing or duplicate service names"
|
|
155
|
+
);
|
|
156
|
+
containers.set(service, {
|
|
157
|
+
service,
|
|
158
|
+
id: String(record.ID ?? "").trim(),
|
|
159
|
+
state: String(record.State ?? "").trim().toLowerCase(),
|
|
160
|
+
health: String(record.Health ?? "").trim().toLowerCase(),
|
|
161
|
+
restartCount: record.RestartCount === void 0 || record.RestartCount === null ? null : Number(record.RestartCount),
|
|
162
|
+
exitCode: record.ExitCode === void 0 || record.ExitCode === null || String(record.ExitCode).trim() === "" ? null : Number.isInteger(Number(record.ExitCode)) ? Number(record.ExitCode) : null
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return containers;
|
|
166
|
+
}
|
|
167
|
+
function parseRenderedServices(renderedCompose) {
|
|
168
|
+
let services;
|
|
169
|
+
try {
|
|
170
|
+
const parsed = JSON.parse(renderedCompose ?? "");
|
|
171
|
+
if (!parsed.services || typeof parsed.services !== "object" || Array.isArray(parsed.services))
|
|
172
|
+
throw new Error();
|
|
173
|
+
services = parsed.services;
|
|
174
|
+
} catch {
|
|
175
|
+
throw new Error("--retain-compose rendered dependency graph unavailable");
|
|
176
|
+
}
|
|
177
|
+
return services;
|
|
178
|
+
}
|
|
179
|
+
function retainedCriticalServices(renderedCompose, selectedService, requiredCore) {
|
|
180
|
+
const services = parseRenderedServices(renderedCompose);
|
|
181
|
+
const critical = /* @__PURE__ */ new Set();
|
|
182
|
+
const visit = (service) => {
|
|
183
|
+
if (!services[service])
|
|
184
|
+
throw new Error(
|
|
185
|
+
`--retain-compose required service ${service} absent from rendered Compose`
|
|
186
|
+
);
|
|
187
|
+
if (critical.has(service)) return;
|
|
188
|
+
critical.add(service);
|
|
189
|
+
const deps = services[service].depends_on;
|
|
190
|
+
if (deps !== void 0 && !Array.isArray(deps) && (typeof deps !== "object" || deps === null)) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`--retain-compose dependencies for ${service} could not be parsed`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
const names = Array.isArray(deps) ? deps : Object.keys(deps ?? {});
|
|
196
|
+
for (const name of names) {
|
|
197
|
+
if (typeof name !== "string")
|
|
198
|
+
throw new Error(
|
|
199
|
+
`--retain-compose dependencies for ${service} could not be parsed`
|
|
200
|
+
);
|
|
201
|
+
visit(name);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
visit(selectedService);
|
|
205
|
+
for (const service of requiredCore) visit(service);
|
|
206
|
+
return critical;
|
|
207
|
+
}
|
|
208
|
+
function retainedCompletedDependencies(renderedCompose, critical, selectedService, requiredCore) {
|
|
209
|
+
const services = parseRenderedServices(renderedCompose);
|
|
210
|
+
const inbound = /* @__PURE__ */ new Map();
|
|
211
|
+
for (const parent of critical) {
|
|
212
|
+
const dependencies = services[parent]?.depends_on;
|
|
213
|
+
if (!dependencies) continue;
|
|
214
|
+
const entries = Array.isArray(dependencies) ? dependencies.map((name) => [
|
|
215
|
+
String(name),
|
|
216
|
+
{ condition: "service_started" }
|
|
217
|
+
]) : Object.entries(dependencies);
|
|
218
|
+
for (const [name, value] of entries) {
|
|
219
|
+
if (!critical.has(name)) continue;
|
|
220
|
+
const condition = value && typeof value === "object" ? String(
|
|
221
|
+
value.condition ?? "service_started"
|
|
222
|
+
) : "service_started";
|
|
223
|
+
inbound.set(name, [...inbound.get(name) ?? [], condition]);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const roots = /* @__PURE__ */ new Set([selectedService, ...requiredCore]);
|
|
227
|
+
return new Set(
|
|
228
|
+
[...inbound].filter(
|
|
229
|
+
([name, conditions]) => !roots.has(name) && // Compose's omitted restart policy is "no". An explicit policy
|
|
230
|
+
// that restarts the job is not a completed one-shot dependency.
|
|
231
|
+
(services[name]?.restart === void 0 || services[name]?.restart === "no") && conditions.length > 0 && conditions.every(
|
|
232
|
+
(condition) => condition === "service_completed_successfully"
|
|
233
|
+
)
|
|
234
|
+
).map(([name]) => name)
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
function retainedContainerIsHealthy(container, completedDependency = false) {
|
|
238
|
+
return !!container && !!container.id && (completedDependency ? container.state === "exited" && container.exitCode === 0 : container.state === "running" && (container.health === "" || container.health === "healthy")) && (container.restartCount === null || Number.isFinite(container.restartCount) && container.restartCount <= 2);
|
|
239
|
+
}
|
|
240
|
+
function assessRetainedHealthBefore(witness) {
|
|
241
|
+
const failures = [];
|
|
242
|
+
for (const service of witness.critical) {
|
|
243
|
+
if (!retainedContainerIsHealthy(
|
|
244
|
+
witness.containers.get(service),
|
|
245
|
+
witness.completedDependencies?.has(service)
|
|
246
|
+
))
|
|
247
|
+
failures.push(service);
|
|
248
|
+
}
|
|
249
|
+
for (const [service, container] of witness.containers) {
|
|
250
|
+
if (!witness.critical.has(service) && !retainedContainerIsHealthy(container) && !container.id) {
|
|
251
|
+
failures.push(`${service} (unhealthy container identity unavailable)`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return failures;
|
|
255
|
+
}
|
|
256
|
+
function assessRetainedHealthAfter(before, after) {
|
|
257
|
+
const failures = [];
|
|
258
|
+
for (const service of before.critical) {
|
|
259
|
+
if (!retainedContainerIsHealthy(
|
|
260
|
+
after.get(service),
|
|
261
|
+
before.completedDependencies?.has(service)
|
|
262
|
+
))
|
|
263
|
+
failures.push(service);
|
|
264
|
+
}
|
|
265
|
+
for (const [service, current] of after) {
|
|
266
|
+
if (before.critical.has(service) || retainedContainerIsHealthy(current))
|
|
267
|
+
continue;
|
|
268
|
+
const prior = before.containers.get(service);
|
|
269
|
+
if (!prior || retainedContainerIsHealthy(prior) || !prior.id || prior.id !== current.id || prior.state !== current.state || prior.health !== current.health || prior.restartCount !== current.restartCount) {
|
|
270
|
+
failures.push(service);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
for (const service of before.containers.keys()) {
|
|
274
|
+
if (!after.has(service)) failures.push(`${service} (disappeared)`);
|
|
275
|
+
}
|
|
276
|
+
return [...new Set(failures)];
|
|
277
|
+
}
|
|
278
|
+
|
|
123
279
|
// src/lib/stack-lock-derive.ts
|
|
124
280
|
import { spawnSync } from "child_process";
|
|
125
281
|
var GIT_SHA_LABEL = "org.exe.git_sha";
|
|
@@ -3953,6 +4109,24 @@ ${lines.join("\n")}`
|
|
|
3953
4109
|
options.preDeployBackup(plan.targetVersion);
|
|
3954
4110
|
} catch {
|
|
3955
4111
|
}
|
|
4112
|
+
let retainedHealthBaseline;
|
|
4113
|
+
if (options.retainCompose) {
|
|
4114
|
+
const [selectedName, selectedEntry] = Object.entries(plan.release.services)[0];
|
|
4115
|
+
const selected = selectedEntry.composeService ?? selectedName;
|
|
4116
|
+
const requiredCore = Object.entries(targetRelease.services).filter(([, service]) => service.required === true && service.category === "core").map(([name, service]) => service.composeService ?? name);
|
|
4117
|
+
const args = composeArgsForStack(options.composeFile, options.envFile);
|
|
4118
|
+
const rendered = (options.composeConfigCapture ?? defaultComposeConfigCapture)(args, process.env);
|
|
4119
|
+
const critical = retainedCriticalServices(rendered, selected, requiredCore);
|
|
4120
|
+
const completedDependencies = retainedCompletedDependencies(rendered, critical, selected, requiredCore);
|
|
4121
|
+
const rawHealth = (options.composePsCapture ?? defaultComposePsCapture)(args);
|
|
4122
|
+
retainedHealthBaseline = { critical, completedDependencies, containers: parseRetainedContainerHealth(rawHealth) };
|
|
4123
|
+
const failures = assessRetainedHealthBefore(retainedHealthBaseline);
|
|
4124
|
+
if (failures.length > 0) throw new Error(`--retain-compose health gate failed before update: ${failures.join(", ")}`);
|
|
4125
|
+
const preexisting = [...retainedHealthBaseline.containers.values()].filter((container) => !critical.has(container.service) && (container.state !== "running" || container.health === "unhealthy" || container.restartCount !== null && container.restartCount > 2));
|
|
4126
|
+
for (const container of preexisting) {
|
|
4127
|
+
console.warn(`[stack-update] Pre-existing unrelated unhealthy container (unchanged identity required): ${container.service}`);
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
3956
4130
|
const stackDir = path.dirname(options.envFile);
|
|
3957
4131
|
const configBackup = preBootstrapBackup ?? backupStackConfig(stackDir, options.composeFile, envRaw, now);
|
|
3958
4132
|
const updateBackupDir = configBackup.updateBackupDir;
|
|
@@ -4426,6 +4600,15 @@ Push the missing image(s) to the registry, or re-run with --break-glass <reason>
|
|
|
4426
4600
|
endPhase3();
|
|
4427
4601
|
}
|
|
4428
4602
|
}
|
|
4603
|
+
if (retainedHealthBaseline) {
|
|
4604
|
+
const after = parseRetainedContainerHealth(
|
|
4605
|
+
(options.composePsCapture ?? defaultComposePsCapture)(composeArgs)
|
|
4606
|
+
);
|
|
4607
|
+
const regressions = assessRetainedHealthAfter(retainedHealthBaseline, after);
|
|
4608
|
+
if (regressions.length > 0) {
|
|
4609
|
+
throw new Error(`--retain-compose health regression after update: ${regressions.join(", ")}`);
|
|
4610
|
+
}
|
|
4611
|
+
}
|
|
4429
4612
|
{
|
|
4430
4613
|
const cfIngressConfigPath = path.join(path.dirname(options.composeFile), "cloudflared", "config.yml");
|
|
4431
4614
|
const cfIngressConfigYml = existsSync(cfIngressConfigPath) ? readFileSync(cfIngressConfigPath, "utf8") : null;
|
|
@@ -5484,6 +5667,11 @@ function loadDefaultPublicKey() {
|
|
|
5484
5667
|
}
|
|
5485
5668
|
|
|
5486
5669
|
export {
|
|
5670
|
+
parseRetainedContainerHealth,
|
|
5671
|
+
retainedCriticalServices,
|
|
5672
|
+
retainedCompletedDependencies,
|
|
5673
|
+
retainedContainerIsHealthy,
|
|
5674
|
+
assessRetainedHealthBefore,
|
|
5487
5675
|
resolveServiceHealthTimeout,
|
|
5488
5676
|
serviceSelectionPath,
|
|
5489
5677
|
loadServiceSelection,
|
package/dist/hooks/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"generatedAt": "2026-09-23T22:15:03.718Z",
|
|
4
4
|
"hashes": {
|
|
5
5
|
"bug-report-worker.js": "7c5f5951fe30192e374d9047c3a7f2975a879a5951457aafea5db95d5d6be6af",
|
|
6
6
|
"codex-stop-task-finalizer.js": "f963449525e068ebf3f04a2950adf21464de71774b60165a84d69621a5eca30a",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
writeSignedStackManifest
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-V57YDQQA.js";
|
|
5
|
+
import "./chunk-WMGS5U2J.js";
|
|
6
6
|
import "./chunk-EC5H53YD.js";
|
|
7
7
|
import "./chunk-YYRI2AGK.js";
|
|
8
8
|
import "./chunk-L25OAFOU.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
writeSignedStackManifest
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-V57YDQQA.js";
|
|
5
|
+
import "./chunk-WMGS5U2J.js";
|
|
6
6
|
import "./chunk-EC5H53YD.js";
|
|
7
7
|
import "./chunk-YYRI2AGK.js";
|
|
8
8
|
import "./chunk-L25OAFOU.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
writeSignedStackManifest
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-V57YDQQA.js";
|
|
5
|
+
import "./chunk-WMGS5U2J.js";
|
|
6
6
|
import "./chunk-EC5H53YD.js";
|
|
7
7
|
import {
|
|
8
8
|
assertPreflightGate,
|
|
@@ -2028,7 +2028,7 @@ async function warmProxyCache(imageRef) {
|
|
|
2028
2028
|
async function resolveImageGitShaLabel(ref, dryRun) {
|
|
2029
2029
|
if (!ref || dryRun) return void 0;
|
|
2030
2030
|
try {
|
|
2031
|
-
const { readProvenanceLabels } = await import("./stack-generate-manifest-
|
|
2031
|
+
const { readProvenanceLabels } = await import("./stack-generate-manifest-XZ534AJH.js");
|
|
2032
2032
|
const labels = await readProvenanceLabels(ref);
|
|
2033
2033
|
return labels["org.exe.git_sha"] ?? labels["org.opencontainers.image.revision"];
|
|
2034
2034
|
} catch (err) {
|
|
@@ -132,7 +132,7 @@ import {
|
|
|
132
132
|
waitForHttpOk,
|
|
133
133
|
warnUnmanagedManifestServices,
|
|
134
134
|
withStackUpdateOperationLock
|
|
135
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-WMGS5U2J.js";
|
|
136
136
|
import "./chunk-EC5H53YD.js";
|
|
137
137
|
import "./chunk-YYRI2AGK.js";
|
|
138
138
|
import "./chunk-L25OAFOU.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askexenow/exe-os",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.393",
|
|
4
4
|
"description": "AI employee operating system \u2014 persistent memory, task management, and multi-agent coordination for Claude Code.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
package/release-notes.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"current": "0.9.
|
|
2
|
+
"current": "0.9.393",
|
|
3
3
|
"notes": {
|
|
4
|
-
"0.9.
|
|
5
|
-
"version": "0.9.
|
|
4
|
+
"0.9.393": {
|
|
5
|
+
"version": "0.9.393",
|
|
6
6
|
"date": "2026-09-23",
|
|
7
7
|
"features": [
|
|
8
8
|
"local CI triage — classify failing checks at zero token cost (#1441)",
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
"sign recoverable B3 invite proofs with native keys"
|
|
14
14
|
],
|
|
15
15
|
"fixes": [
|
|
16
|
+
"honor omitted default no-restart policy",
|
|
17
|
+
"honor completed one-shot dependencies in retained health",
|
|
18
|
+
"require critical container identity and preserve missing restart data",
|
|
19
|
+
"scope retained health to selected service and critical dependencies",
|
|
16
20
|
"compare override drift to signed snapshot",
|
|
17
21
|
"attest retained Compose override for scoped releases",
|
|
18
22
|
"no_raw excludes captured searches (bug 37353c88 residual a) (#1509)",
|
|
@@ -33,14 +37,13 @@
|
|
|
33
37
|
"extract-review-findings.sh fails loudly on a broken comments lookup (#1441 follow-up) (#1493)",
|
|
34
38
|
"report duplicate hook entries as a --check failure, not just --apply (#1179 follow-up) (#1492)",
|
|
35
39
|
"ledger mutations commit atomically without a cross-await transaction (#1229 follow-up) (#1490)",
|
|
36
|
-
"memory/DB layer lifecycle cluster — all 10 bugs (#1473)"
|
|
37
|
-
"any unreadable SSO-edge config means unverified delivery (#1221 follow-up) (#1489)",
|
|
38
|
-
"session/orchestration cluster — 6 fixes, 1 verified, 4 documented deferrals (#1469)",
|
|
39
|
-
"an unreadable grandfather marker is not an absent one (bug d11c5049, D22) (#1317)",
|
|
40
|
-
"guard-reachability — advisory report, not a blocking gate (bug efabb902) (#1216)"
|
|
40
|
+
"memory/DB layer lifecycle cluster — all 10 bugs (#1473)"
|
|
41
41
|
],
|
|
42
42
|
"security": [],
|
|
43
43
|
"other": [
|
|
44
|
+
"Prepare signed Dashboard canary stack 0.9.53 with scoped updater 0.9.393",
|
|
45
|
+
"assert required core failure in retained scope",
|
|
46
|
+
"release(npm): publish 0.9.392 from exact green main source",
|
|
44
47
|
"release(stack): sign Dashboard topology canary 0.9.52",
|
|
45
48
|
"release(stack): pin Dashboard v0.9.392 in canary 0.9.51 (#1511)",
|
|
46
49
|
"release: use declared control runner lane",
|