openmeld 0.3.206 → 0.3.207

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.
Files changed (86) hide show
  1. package/dist/{add-me-membership-BkHWMxE4.js → add-me-membership-1JHMjZoR.js} +2 -2
  2. package/dist/{add-me-membership-BkHWMxE4.js.map → add-me-membership-1JHMjZoR.js.map} +1 -1
  3. package/dist/{agents-BOTlKiwS.js → agents-CIDsThyG.js} +150 -108
  4. package/dist/agents-CIDsThyG.js.map +1 -0
  5. package/dist/{api-client-foundation-6ms5gSu8.js → api-client-foundation-D6_NXHPV.js} +1 -1
  6. package/dist/{api-client-foundation-DpgDs0rw.js → api-client-foundation-DSurenul.js} +3 -3
  7. package/dist/{api-client-foundation-DpgDs0rw.js.map → api-client-foundation-DSurenul.js.map} +1 -1
  8. package/dist/auth-session-B7QMhHwh.js +4 -0
  9. package/dist/{auth-session-BjSqMLTz.js → auth-session-CO5XtFaq.js} +266 -75
  10. package/dist/auth-session-CO5XtFaq.js.map +1 -0
  11. package/dist/{base-url-CRAYNW-4.js → base-url-BE3pFiOZ.js} +1 -1
  12. package/dist/{base-url-9A557X2K.js → base-url-C6sHRNGu.js} +2 -2
  13. package/dist/{base-url-9A557X2K.js.map → base-url-C6sHRNGu.js.map} +1 -1
  14. package/dist/cli-binary-manifest-DiUulkp0.js +117 -0
  15. package/dist/cli-binary-manifest-DiUulkp0.js.map +1 -0
  16. package/dist/{command-CkbzbvXy.js → command-Bzt9zgnI.js} +13 -11
  17. package/dist/{command-CkbzbvXy.js.map → command-Bzt9zgnI.js.map} +1 -1
  18. package/dist/computer-connection-BOl79Ftf.js +54 -0
  19. package/dist/computer-connection-BOl79Ftf.js.map +1 -0
  20. package/dist/computer-connection-review-BTOvbJYL.js +39 -0
  21. package/dist/computer-connection-review-BTOvbJYL.js.map +1 -0
  22. package/dist/{computer-setup-continuation-Cd9nhLQ-.js → computer-setup-continuation-DmKdhR5u.js} +4 -4
  23. package/dist/{computer-setup-continuation-Cd9nhLQ-.js.map → computer-setup-continuation-DmKdhR5u.js.map} +1 -1
  24. package/dist/control-plane-D9jDcbMZ.js +1211 -0
  25. package/dist/control-plane-D9jDcbMZ.js.map +1 -0
  26. package/dist/daemon-local-state-file-jOXuXrky.js +45 -0
  27. package/dist/daemon-local-state-file-jOXuXrky.js.map +1 -0
  28. package/dist/daemon-runtime-lease-Dd4hdHNo.js +50 -0
  29. package/dist/daemon-runtime-lease-Dd4hdHNo.js.map +1 -0
  30. package/dist/{daemon-runtime-lease-BG9g0a6Z.js → daemon-runtime-lease-y3n1K0-C.js} +1 -1
  31. package/dist/{daemon-service-manager-DqVtRLBY.js → daemon-service-manager-Bh0LoLed.js} +1 -1
  32. package/dist/{daemon-service-manager-BVipiZwK.js → daemon-service-manager-GiMCiTmu.js} +99 -85
  33. package/dist/daemon-service-manager-GiMCiTmu.js.map +1 -0
  34. package/dist/daemon-service-runtime-DQW9gSLT.js +3642 -0
  35. package/dist/daemon-service-runtime-DQW9gSLT.js.map +1 -0
  36. package/dist/{daemon-state-BwIoDq7_.js → daemon-state-C37ZtIZK.js} +11 -5
  37. package/dist/daemon-state-C37ZtIZK.js.map +1 -0
  38. package/dist/{dist-CxadJClH.js → dist-D-kJdWZE.js} +726 -579
  39. package/dist/dist-D-kJdWZE.js.map +1 -0
  40. package/dist/dist-DTG_Vqc7.js +4 -0
  41. package/dist/distribution-DY2fBeSW.js +72 -0
  42. package/dist/distribution-DY2fBeSW.js.map +1 -0
  43. package/dist/{elapsed-time-C7P-nWIO.js → elapsed-time-CcoM2R3N.js} +7 -4
  44. package/dist/{elapsed-time-C7P-nWIO.js.map → elapsed-time-CcoM2R3N.js.map} +1 -1
  45. package/dist/{installation-inventory-P49sTjhe.js → installation-inventory-DJlwXa1q.js} +7 -6
  46. package/dist/{installation-inventory-P49sTjhe.js.map → installation-inventory-DJlwXa1q.js.map} +1 -1
  47. package/dist/{lock-CvBnBcFK.js → lock-Dxp6o_t_.js} +56 -7
  48. package/dist/lock-Dxp6o_t_.js.map +1 -0
  49. package/dist/{openmeld-ChOHuaqH.js → openmeld-CiL4AiB0.js} +226 -21
  50. package/dist/openmeld-CiL4AiB0.js.map +1 -0
  51. package/dist/openmeld-dev.js +1 -1
  52. package/dist/openmeld-environment-target-NtJYJe1D.js +256 -0
  53. package/dist/openmeld-environment-target-NtJYJe1D.js.map +1 -0
  54. package/dist/{openmeld-maintenance-worker-C7WykyDt.js → openmeld-maintenance-worker-DjdmRASI.js} +9 -8
  55. package/dist/{openmeld-maintenance-worker-C7WykyDt.js.map → openmeld-maintenance-worker-DjdmRASI.js.map} +1 -1
  56. package/dist/{openmeld-tools-update-coordinator-BBZhGo1A.js → openmeld-tools-update-coordinator-D9Skj8IE.js} +52 -4013
  57. package/dist/openmeld-tools-update-coordinator-D9Skj8IE.js.map +1 -0
  58. package/dist/openmeld.js +3 -3
  59. package/dist/{prepare-session-executor-CLmDoHom.js → prepare-session-executor-B0NtjHEL.js} +15 -13
  60. package/dist/{prepare-session-executor-CLmDoHom.js.map → prepare-session-executor-B0NtjHEL.js.map} +1 -1
  61. package/dist/{profiles-BCecj4Pj.js → runtime-transport-QIZmAo4-.js} +936 -2127
  62. package/dist/runtime-transport-QIZmAo4-.js.map +1 -0
  63. package/dist/service-account-authorization-Dt8kGvq8.js +56 -0
  64. package/dist/service-account-authorization-Dt8kGvq8.js.map +1 -0
  65. package/dist/service-control-capabilities-BU5F75zi.js +54 -0
  66. package/dist/service-control-capabilities-BU5F75zi.js.map +1 -0
  67. package/dist/service-control-capabilities-CzUB1ovW.js +4 -0
  68. package/dist/upgrade-DLECkjMt.js +4 -0
  69. package/dist/{upgrade-l_5Tge_z.js → upgrade-NxpTydHp.js} +6 -4
  70. package/dist/upgrade-NxpTydHp.js.map +1 -0
  71. package/package.json +2 -2
  72. package/dist/agents-BOTlKiwS.js.map +0 -1
  73. package/dist/auth-session-BjSqMLTz.js.map +0 -1
  74. package/dist/auth-session-ahQ5VXiF.js +0 -4
  75. package/dist/daemon-runtime-lease-CXlGR-iA.js +0 -87
  76. package/dist/daemon-runtime-lease-CXlGR-iA.js.map +0 -1
  77. package/dist/daemon-service-manager-BVipiZwK.js.map +0 -1
  78. package/dist/daemon-state-BwIoDq7_.js.map +0 -1
  79. package/dist/dist-0boZRalP.js +0 -4
  80. package/dist/dist-CxadJClH.js.map +0 -1
  81. package/dist/lock-CvBnBcFK.js.map +0 -1
  82. package/dist/openmeld-ChOHuaqH.js.map +0 -1
  83. package/dist/openmeld-tools-update-coordinator-BBZhGo1A.js.map +0 -1
  84. package/dist/profiles-BCecj4Pj.js.map +0 -1
  85. package/dist/upgrade-BKEAZKre.js +0 -4
  86. package/dist/upgrade-l_5Tge_z.js.map +0 -1
@@ -0,0 +1,3642 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { $ as openMeldBinDir, N as OPENMELD_HOME_ENV_KEY, a as isOpenMeldOrphanedLockError, d as runWithHeldLock, dt as resolveOpenMeldEnvPreset, et as openMeldManagedBinaryPath, ft as resolveOpenMeldRootDir, i as isOpenMeldLockError, it as openMeldVersionsDir, mt as resolveOpenMeldServiceScope, nt as openMeldManagedVersionDir, rt as openMeldRootDir, t as acquireLock, tt as openMeldManagedVersionBinaryPath, v as resolveCliContextId } from "./lock-Dxp6o_t_.js";
4
+ import { n as cliBinaryManifestSchema, r as cliBinaryServiceReleaseSchema, t as cliBinaryDeltaPatchSchema } from "./cli-binary-manifest-DiUulkp0.js";
5
+ import { R as openMeldToolsUpdateOperationPhaseSchema, V as openMeldToolsUpdateRequestSourceSchema, a as openMeldDaemonControlPlaneResponseSchema } from "./control-plane-D9jDcbMZ.js";
6
+ import { t as daemonServiceContractSchema } from "./service-contract-CRyDcIIf.js";
7
+ import { n as resolveOpenMeldDistribution, t as isBinaryDistribution } from "./distribution-DY2fBeSW.js";
8
+ import { r as readDaemonRuntimeLease } from "./daemon-runtime-lease-Dd4hdHNo.js";
9
+ import { n as writeDaemonLocalStateFile, t as readDaemonLocalStateFile } from "./daemon-local-state-file-jOXuXrky.js";
10
+ import { A as getDaemonStatus, C as daemonServiceStableBinaryExecutablePath, D as daemonStatePath, E as daemonServiceUpdateWorkerBinaryExecutablePath, N as readDaemonControlPlaneToken, P as readDaemonServiceLifecycleLockMeta, R as resolveDaemonControlPlaneEndpoint, T as daemonServiceStableLauncherPath, U as uninstallDaemon, _ as daemonRuntimeStateRootPath, a as DAEMON_SERVICE_RUNTIME_MODE_ENV, b as daemonServiceLegacyExecutableWrapperPath, f as daemonLifecycleJournalPath, g as daemonRuntimeServiceManagerPath, h as daemonRuntimeRootPath, i as DAEMON_SERVICE_RUNTIME_DETACHED_ENV, k as getDaemonRuntimeStatus, l as clearDaemonServiceRuntimeState, n as DAEMON_SERVICE_RUNTIME_AUTO_START_ENV, p as daemonRuntimeBundlesPath, r as DAEMON_SERVICE_RUNTIME_CONTROLLER_ENV, s as DAEMON_SERVICE_RUNTIME_SYSTEM_SERVICE_ENV, t as DAEMON_HEARTBEAT_STALE_MS, v as daemonServiceActiveBundleStatePath, w as daemonServiceStableExecutableWrapperPath, x as daemonServiceRecognizedExecutablePaths$1, y as daemonServiceExecutableWrapperPaths$1 } from "./daemon-state-C37ZtIZK.js";
11
+ import { A as isTestProcess, D as assertNoPublishedProductionMutationDuringTests, E as resolveDaemonServiceIdentity, S as resolveDaemonServiceManager, k as isPublishedProductionOpenMeldRoot } from "./daemon-service-manager-GiMCiTmu.js";
12
+ import { t as sleep } from "./dist-o3UL1EGQ.js";
13
+ import { createRequire } from "node:module";
14
+ import { createHash } from "node:crypto";
15
+ import { homedir } from "node:os";
16
+ import path, { basename, dirname, isAbsolute, join, relative, sep } from "node:path";
17
+ import { access, appendFile, chmod, copyFile, cp, lstat, mkdir, readFile, readdir, readlink, realpath, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
18
+ import * as z$1 from "zod/v4";
19
+ import { constants } from "node:fs";
20
+ import process$1 from "node:process";
21
+ import { execFile, spawn } from "node:child_process";
22
+ import { setTimeout } from "node:timers/promises";
23
+ import { fileURLToPath } from "node:url";
24
+ import { promisify } from "node:util";
25
+ import { createConnection } from "node:net";
26
+ import { gunzipSync } from "node:zlib";
27
+ //#region ../../packages/schemas/dist/schemas/daemon/service-update-job.js
28
+ const OPENMELD_DAEMON_SERVICE_UPDATE_JOB_SCHEMA = "openmeld-daemon-service-update-job-v2";
29
+ const daemonServiceUpdatePreparedBundleSchema = z$1.strictObject({
30
+ v: z$1.literal(2),
31
+ schema: z$1.literal("openmeld-daemon-active-bundle-v2"),
32
+ bundleId: z$1.string().min(1),
33
+ daemonVersion: z$1.string().min(1),
34
+ entryScriptRelativePath: z$1.string().min(1),
35
+ bundleFormat: z$1.enum([
36
+ "legacy_linked_v1",
37
+ "self_contained_v1",
38
+ "binary_v1"
39
+ ]),
40
+ sourceEntryScriptPath: z$1.string().min(1),
41
+ sourcePackageRootPath: z$1.string().min(1),
42
+ sourceDistRootPath: z$1.string().min(1),
43
+ sourceDistFingerprint: z$1.string().min(1).nullable().optional(),
44
+ sourceKind: z$1.enum([
45
+ "workspace",
46
+ "package_install",
47
+ "npx_cache",
48
+ "unknown"
49
+ ]),
50
+ createdAt: z$1.iso.datetime({ offset: true }),
51
+ updatedAt: z$1.iso.datetime({ offset: true })
52
+ });
53
+ const daemonServiceUpdateJobBodySchema = z$1.strictObject({
54
+ attempts: z$1.number().int().nonnegative(),
55
+ desiredState: z$1.enum(["background", "stopped"]),
56
+ errorMessage: z$1.string().min(1).nullable(),
57
+ jobId: z$1.string().min(1),
58
+ preparedBundle: daemonServiceUpdatePreparedBundleSchema,
59
+ requestedAt: z$1.iso.datetime({ offset: true }),
60
+ targetVersion: z$1.string().min(1),
61
+ updatedAt: z$1.iso.datetime({ offset: true }),
62
+ urgency: z$1.enum(["available", "required"])
63
+ });
64
+ const daemonServiceUpdateJobV1Schema = daemonServiceUpdateJobBodySchema.extend({
65
+ v: z$1.literal(1),
66
+ schema: z$1.literal("openmeld-daemon-service-update-job-v1"),
67
+ status: z$1.enum([
68
+ "scheduled",
69
+ "running",
70
+ "completed",
71
+ "failed"
72
+ ])
73
+ });
74
+ const daemonServiceUpdateJobSchema = daemonServiceUpdateJobBodySchema.extend({
75
+ v: z$1.literal(2),
76
+ schema: z$1.literal(OPENMELD_DAEMON_SERVICE_UPDATE_JOB_SCHEMA),
77
+ phase: openMeldToolsUpdateOperationPhaseSchema,
78
+ requestSource: openMeldToolsUpdateRequestSourceSchema
79
+ });
80
+ const storedDaemonServiceUpdateJobSchema = z$1.discriminatedUnion("v", [daemonServiceUpdateJobV1Schema, daemonServiceUpdateJobSchema]);
81
+ //#endregion
82
+ //#region src/config/daemon-service-contract.ts
83
+ const DAEMON_SERVICE_CONTRACT_FILENAME = "service-contract.json";
84
+ function daemonServiceContractPath(pathInput = {}) {
85
+ return join(daemonRuntimeStateRootPath(pathInput), DAEMON_SERVICE_CONTRACT_FILENAME);
86
+ }
87
+ async function readDaemonServiceContract(pathInput = {}) {
88
+ return await readDaemonLocalStateFile({
89
+ path: daemonServiceContractPath(pathInput),
90
+ schema: daemonServiceContractSchema
91
+ });
92
+ }
93
+ async function upsertDaemonServiceContract(input, pathInput = {}) {
94
+ assertDaemonServiceContractMutationAllowed(pathInput);
95
+ const current = await readDaemonServiceContract(pathInput);
96
+ const candidate = buildContractCandidate(input, pathInput, current);
97
+ assertDaemonServiceContractIdentityAllowed(candidate, pathInput);
98
+ if (current && isSameContractState(current, candidate)) return current;
99
+ const next = {
100
+ ...candidate,
101
+ generation: current ? current.generation + 1 : 1,
102
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
103
+ };
104
+ await writeDaemonLocalStateFile({
105
+ path: daemonServiceContractPath(pathInput),
106
+ schema: daemonServiceContractSchema,
107
+ value: next,
108
+ mode: 384
109
+ });
110
+ return next;
111
+ }
112
+ async function clearDaemonServiceContract(pathInput = {}) {
113
+ assertDaemonServiceContractMutationAllowed(pathInput);
114
+ await rm(daemonServiceContractPath(pathInput), { force: true });
115
+ }
116
+ function assertDaemonServiceContractMutationAllowed(pathInput) {
117
+ assertNoPublishedProductionMutationDuringTests(pathInput, "OpenMeld Service contract");
118
+ }
119
+ function assertDaemonServiceContractIdentityAllowed(candidate, pathInput) {
120
+ if (!isUnsafeProductionDaemonServiceContractIdentity(candidate)) return;
121
+ if (isTestProcess(pathInput) && !isPublishedProductionOpenMeldRoot(pathInput)) return;
122
+ throw new Error(["Refusing to write OpenMeld Service contract with a test fixture identity in the published production lane.", "Run `openmeld service repair --profile <profile-id>` from the signed-in production lane, or clear the polluted local service state before retrying."].join(" "));
123
+ }
124
+ function isDaemonServiceContractIdentityReusable(contract, pathInput = {}) {
125
+ if (!contract) return false;
126
+ if (contract.lane !== resolveOpenMeldEnvPreset(pathInput)) return false;
127
+ return !isUnsafeProductionDaemonServiceContractIdentity(contract);
128
+ }
129
+ function isUnsafeProductionDaemonServiceContractIdentity(contract) {
130
+ if (contract.lane !== "prod") return false;
131
+ return isUnsafeProductionDeviceId(contract.deviceId) || (contract.profileId ? isUnsafeProductionProfileId(contract.profileId) : false);
132
+ }
133
+ function isUnsafeProductionDeviceId(deviceId) {
134
+ return normalizeFixtureText(deviceId) === "device_123";
135
+ }
136
+ function isUnsafeProductionProfileId(profileId) {
137
+ return UNSAFE_PRODUCTION_PROFILE_IDS.has(normalizeFixtureText(profileId));
138
+ }
139
+ const UNSAFE_PRODUCTION_PROFILE_IDS = /* @__PURE__ */ new Set([
140
+ "agt_existing",
141
+ "11111111-1111-1111-1111-111111111111",
142
+ "agt_11111111-1111-1111-1111-111111111111",
143
+ "11111111-1111-4111-8111-111111111111",
144
+ "agt_11111111-1111-4111-8111-111111111111"
145
+ ]);
146
+ function normalizeFixtureText(value) {
147
+ return value.trim().toLowerCase();
148
+ }
149
+ function buildContractCandidate(input, pathInput, current) {
150
+ const lane = input.lane ?? resolveOpenMeldEnvPreset(pathInput);
151
+ const connectedComputerId = input.connectedComputerId ?? (current && canReuseConnectedComputerEvidence(current, input, lane) ? current.connectedComputerId : void 0);
152
+ return {
153
+ schema: "openmeld-daemon-service-contract-v1",
154
+ v: 1,
155
+ lane,
156
+ daemonVersion: input.daemonVersion,
157
+ bundleId: input.bundleId,
158
+ desiredState: input.desiredState,
159
+ serviceController: input.serviceController,
160
+ autoStart: input.autoStart,
161
+ gatewayUrl: input.gatewayUrl,
162
+ ...input.ownerUserId ? { ownerUserId: input.ownerUserId } : {},
163
+ ...input.profileId ? { profileId: input.profileId } : {},
164
+ deviceId: input.deviceId,
165
+ ...connectedComputerId ? { connectedComputerId } : {},
166
+ heartbeatMs: input.heartbeatMs
167
+ };
168
+ }
169
+ function canReuseConnectedComputerEvidence(current, input, lane) {
170
+ if (current.lane !== lane || current.gatewayUrl !== input.gatewayUrl || current.deviceId !== input.deviceId) return false;
171
+ if (current.ownerUserId && input.ownerUserId) return current.ownerUserId === input.ownerUserId;
172
+ if (current.profileId && input.profileId) return current.profileId === input.profileId;
173
+ return !(current.ownerUserId || input.ownerUserId);
174
+ }
175
+ function isSameContractState(current, candidate) {
176
+ return current.schema === candidate.schema && current.v === candidate.v && current.lane === candidate.lane && current.daemonVersion === candidate.daemonVersion && current.bundleId === candidate.bundleId && current.desiredState === candidate.desiredState && current.serviceController === candidate.serviceController && current.autoStart === candidate.autoStart && current.gatewayUrl === candidate.gatewayUrl && current.ownerUserId === candidate.ownerUserId && current.profileId === candidate.profileId && current.deviceId === candidate.deviceId && current.connectedComputerId === candidate.connectedComputerId && current.heartbeatMs === candidate.heartbeatMs;
177
+ }
178
+ //#endregion
179
+ //#region src/local-service/control-plane/client.ts
180
+ const DEFAULT_LOCAL_DAEMON_CONTROL_PLANE_TIMEOUT_MS = 5e3;
181
+ var LocalDaemonControlPlaneClientError = class extends Error {
182
+ code;
183
+ constructor(code, message) {
184
+ super(message);
185
+ this.code = code;
186
+ }
187
+ };
188
+ async function sendLocalDaemonControlPlaneRequest(input) {
189
+ const endpoint = input.endpoint ?? resolveDaemonControlPlaneEndpoint();
190
+ const authToken = await readDaemonControlPlaneToken();
191
+ if (!authToken) throw new LocalDaemonControlPlaneClientError("daemon.control.auth_token_missing", "daemon control token is missing");
192
+ const rawResponse = await writeControlPlaneRequest({
193
+ endpoint,
194
+ request: {
195
+ ...input.request,
196
+ authToken
197
+ },
198
+ timeoutMs: input.timeoutMs ?? DEFAULT_LOCAL_DAEMON_CONTROL_PLANE_TIMEOUT_MS
199
+ });
200
+ const parsed = openMeldDaemonControlPlaneResponseSchema.safeParse(rawResponse);
201
+ if (!parsed.success) throw new LocalDaemonControlPlaneClientError("daemon.control.invalid_response", "local daemon control returned an invalid response");
202
+ if (parsed.data.code === "service.error") throw new LocalDaemonControlPlaneClientError(parsed.data.payload.errorCode, parsed.data.payload.errorMessage);
203
+ return parsed.data;
204
+ }
205
+ async function requestLocalSyncRouteCatalog(input) {
206
+ let response;
207
+ try {
208
+ response = await sendLocalDaemonControlPlaneRequest({
209
+ endpoint: input.endpoint,
210
+ timeoutMs: input.timeoutMs,
211
+ request: {
212
+ v: 1,
213
+ command: "sync_route_catalog",
214
+ payload: input.payload
215
+ }
216
+ });
217
+ } catch (error) {
218
+ throw rewriteDaemonControlPlaneContractMismatch(error);
219
+ }
220
+ if (response.code !== "service.sync_route_catalog") throw new LocalDaemonControlPlaneClientError("daemon.control.invalid_response", "local daemon control returned an unexpected response for route catalog sync");
221
+ return response.payload;
222
+ }
223
+ async function requestLocalAgentActivitySync(input) {
224
+ let response;
225
+ try {
226
+ response = await sendLocalDaemonControlPlaneRequest({
227
+ endpoint: input.endpoint,
228
+ timeoutMs: input.timeoutMs,
229
+ request: {
230
+ v: 1,
231
+ command: "request_agent_activity_sync",
232
+ payload: input.payload
233
+ }
234
+ });
235
+ } catch (error) {
236
+ throw rewriteDaemonControlPlaneContractMismatch(error);
237
+ }
238
+ if (response.code !== "service.agent_activity_sync_requested") throw new LocalDaemonControlPlaneClientError("daemon.control.invalid_response", "local daemon control returned an unexpected response for Agent Activity sync");
239
+ return response.payload;
240
+ }
241
+ async function requestLocalDaemonShutdown(input) {
242
+ let response;
243
+ try {
244
+ response = await sendLocalDaemonControlPlaneRequest({
245
+ endpoint: input.endpoint,
246
+ timeoutMs: input.timeoutMs,
247
+ request: {
248
+ v: 1,
249
+ command: "shutdown",
250
+ payload: input.payload
251
+ }
252
+ });
253
+ } catch (error) {
254
+ throw rewriteDaemonControlPlaneContractMismatch(error);
255
+ }
256
+ if (response.code !== "service.shutdown") throw new LocalDaemonControlPlaneClientError("daemon.control.invalid_response", "local daemon control returned an unexpected response for shutdown");
257
+ return response.payload;
258
+ }
259
+ async function requestLocalDaemonServiceUpdateReadiness(input = {}) {
260
+ let response;
261
+ try {
262
+ response = await sendLocalDaemonControlPlaneRequest({
263
+ endpoint: input.endpoint,
264
+ timeoutMs: input.timeoutMs,
265
+ request: {
266
+ v: 1,
267
+ command: "service_update_readiness"
268
+ }
269
+ });
270
+ } catch (error) {
271
+ throw rewriteDaemonControlPlaneContractMismatch(error);
272
+ }
273
+ if (response.code !== "service.update_readiness") throw new LocalDaemonControlPlaneClientError("daemon.control.invalid_response", "local daemon control returned an unexpected response for service update readiness");
274
+ return response.payload;
275
+ }
276
+ function rewriteDaemonControlPlaneContractMismatch(error) {
277
+ if (error instanceof LocalDaemonControlPlaneClientError && error.code === "service.invalid_request") return new LocalDaemonControlPlaneClientError("daemon.control.contract_mismatch", "local OpenMeld Service must be restarted because the daemon control-plane contract changed on this device");
278
+ return error;
279
+ }
280
+ async function writeControlPlaneRequest(input) {
281
+ return await new Promise((resolve, reject) => {
282
+ const socket = createConnection(input.endpoint);
283
+ let responseBuffer = "";
284
+ let settled = false;
285
+ const cleanup = () => {
286
+ socket.setTimeout(0);
287
+ socket.off("connect", handleConnect);
288
+ socket.off("data", handleData);
289
+ socket.off("end", handleEnd);
290
+ socket.off("error", handleError);
291
+ socket.off("timeout", handleTimeout);
292
+ };
293
+ const settle = (action) => {
294
+ if (settled) return;
295
+ settled = true;
296
+ cleanup();
297
+ action();
298
+ };
299
+ const fail = (error) => {
300
+ settle(() => {
301
+ socket.destroy();
302
+ reject(error);
303
+ });
304
+ };
305
+ const handleConnect = () => {
306
+ socket.write(`${JSON.stringify(input.request)}\n`);
307
+ };
308
+ const handleData = (chunk) => {
309
+ responseBuffer += chunk;
310
+ };
311
+ const handleEnd = () => {
312
+ settle(() => {
313
+ const rawResponse = responseBuffer.trim();
314
+ if (!rawResponse) {
315
+ reject(new LocalDaemonControlPlaneClientError("daemon.control.empty_response", "local daemon control returned an empty response"));
316
+ return;
317
+ }
318
+ try {
319
+ resolve(JSON.parse(rawResponse));
320
+ } catch {
321
+ reject(new LocalDaemonControlPlaneClientError("daemon.control.invalid_json", "local daemon control returned malformed JSON"));
322
+ }
323
+ });
324
+ };
325
+ const handleError = (error) => {
326
+ const code = error && typeof error === "object" && "code" in error ? String(error.code) : "daemon.control.connection_failed";
327
+ fail(new LocalDaemonControlPlaneClientError(code === "ENOENT" || code === "ECONNREFUSED" ? "daemon.control.endpoint_missing" : code, error instanceof Error ? error.message : "failed to connect to local daemon control"));
328
+ };
329
+ const handleTimeout = () => {
330
+ fail(new LocalDaemonControlPlaneClientError("daemon.control.timeout", `local daemon control timed out after ${String(input.timeoutMs)}ms`));
331
+ };
332
+ socket.setEncoding("utf8");
333
+ socket.setTimeout(input.timeoutMs);
334
+ socket.once("connect", handleConnect);
335
+ socket.on("data", handleData);
336
+ socket.once("end", handleEnd);
337
+ socket.once("error", handleError);
338
+ socket.once("timeout", handleTimeout);
339
+ });
340
+ }
341
+ //#endregion
342
+ //#region ../../runtime/local-service/src/cli-binary-delta.ts
343
+ function reconstructCliBinaryDelta(input) {
344
+ verifyBytes({
345
+ bytes: input.baseBytes,
346
+ expectedSha256: input.delta.fromSha256,
347
+ expectedSizeBytes: input.delta.fromSizeBytes,
348
+ label: "delta base"
349
+ });
350
+ const patch = parseCliBinaryDeltaPatch(input.patchPayloadBytes);
351
+ assertPatchMatchesRelease({
352
+ delta: input.delta,
353
+ patch,
354
+ targetSha256: input.targetSha256,
355
+ targetSizeBytes: input.targetSizeBytes
356
+ });
357
+ const targetBytes = Buffer.alloc(input.targetSizeBytes);
358
+ input.baseBytes.copy(targetBytes, 0, 0, Math.min(input.baseBytes.byteLength, targetBytes.byteLength));
359
+ let previousEnd = 0;
360
+ for (const segment of patch.segments) {
361
+ const bytes = Buffer.from(segment.dataBase64, "base64");
362
+ const segmentEnd = segment.offset + bytes.byteLength;
363
+ if (segment.offset < previousEnd) throw new Error("delta patch segments must be sorted and non-overlapping");
364
+ if (segmentEnd > targetBytes.byteLength) throw new Error("delta patch segment exceeds the target binary size");
365
+ bytes.copy(targetBytes, segment.offset);
366
+ previousEnd = segmentEnd;
367
+ }
368
+ verifyBytes({
369
+ bytes: targetBytes,
370
+ expectedSha256: input.targetSha256,
371
+ expectedSizeBytes: input.targetSizeBytes,
372
+ label: "reconstructed binary"
373
+ });
374
+ return targetBytes;
375
+ }
376
+ function parseCliBinaryDeltaPatch(bytes) {
377
+ let value;
378
+ try {
379
+ value = JSON.parse(bytes.toString("utf8"));
380
+ } catch (error) {
381
+ throw new Error(`delta patch is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
382
+ }
383
+ const parsed = cliBinaryDeltaPatchSchema.safeParse(value);
384
+ if (!parsed.success) throw new Error(`delta patch is invalid: ${parsed.error.message}`);
385
+ return parsed.data;
386
+ }
387
+ function assertPatchMatchesRelease(input) {
388
+ const mismatches = [
389
+ [
390
+ "format",
391
+ input.patch.patchFormat,
392
+ input.delta.patchFormat
393
+ ],
394
+ [
395
+ "base sha256",
396
+ input.patch.baseSha256,
397
+ input.delta.fromSha256
398
+ ],
399
+ [
400
+ "base size",
401
+ input.patch.baseSizeBytes,
402
+ input.delta.fromSizeBytes
403
+ ],
404
+ [
405
+ "target sha256",
406
+ input.patch.targetSha256,
407
+ input.targetSha256
408
+ ],
409
+ [
410
+ "target size",
411
+ input.patch.targetSizeBytes,
412
+ input.targetSizeBytes
413
+ ]
414
+ ].filter(([, actual, expected]) => actual !== expected);
415
+ if (mismatches.length > 0) throw new Error(`delta patch metadata mismatch: ${mismatches.map(([label]) => label).join(", ")}`);
416
+ }
417
+ function verifyBytes(input) {
418
+ if (input.bytes.byteLength !== input.expectedSizeBytes) throw new Error(`${input.label} size mismatch: expected ${input.expectedSizeBytes} bytes, received ${input.bytes.byteLength} bytes`);
419
+ const actualSha256 = createHash("sha256").update(input.bytes).digest("hex");
420
+ if (actualSha256 !== input.expectedSha256.toLowerCase()) throw new Error(`${input.label} sha256 mismatch: expected ${input.expectedSha256.toLowerCase()}, received ${actualSha256}`);
421
+ }
422
+ //#endregion
423
+ //#region ../../runtime/local-service/src/cli-binary-update-artifact.ts
424
+ const HARDENED_RUNTIME_FLAG_RE = /flags=.*runtime/iu;
425
+ const SIGNING_TIMESTAMP_RE = /^Timestamp=/mu;
426
+ async function resolveCliBinaryUpdatePlan(input) {
427
+ const fullDownloadPlan = resolveFullCliBinaryUpdatePlan(input.release);
428
+ const versionDeltas = input.release.deltas?.filter((candidate) => candidate.fromVersion === input.currentVersion);
429
+ if (!versionDeltas?.length) return fullDownloadPlan;
430
+ let baseBytes;
431
+ try {
432
+ baseBytes = await readFile(input.baseBinaryPath);
433
+ } catch (error) {
434
+ input.onDeltaFallback(toError(error));
435
+ return fullDownloadPlan;
436
+ }
437
+ const baseSha256 = createHash("sha256").update(baseBytes).digest("hex");
438
+ const delta = versionDeltas.find((candidate) => candidate.fromSizeBytes === baseBytes.byteLength && candidate.fromSha256.toLowerCase() === baseSha256);
439
+ if (!delta) return fullDownloadPlan;
440
+ return {
441
+ baseBytes,
442
+ delta,
443
+ downloadSizeBytes: delta.patchSizeBytes,
444
+ transport: "delta"
445
+ };
446
+ }
447
+ async function downloadCliBinaryUpdateArtifact(input) {
448
+ if (input.plan.transport === "delta") {
449
+ try {
450
+ return await downloadCliBinaryDelta({
451
+ ...input,
452
+ baseBytes: input.plan.baseBytes,
453
+ delta: input.plan.delta
454
+ });
455
+ } catch (error) {
456
+ input.onDeltaFallback(toError(error));
457
+ }
458
+ return downloadFullCliBinaryArtifact({
459
+ ...input,
460
+ plan: resolveFullCliBinaryUpdatePlan(input.release)
461
+ });
462
+ }
463
+ return downloadFullCliBinaryArtifact({
464
+ ...input,
465
+ plan: input.plan
466
+ });
467
+ }
468
+ async function verifyCliBinaryCodeSignature(input) {
469
+ const { codeIdentifier, teamIdentifier } = input.release;
470
+ if (!(codeIdentifier && teamIdentifier)) return;
471
+ if (process.platform !== "darwin") throw new Error("signed OpenMeld CLI verification requires macOS");
472
+ const verification = await input.runCommand("/usr/bin/codesign", [
473
+ "--verify",
474
+ "--strict",
475
+ "--verbose=2",
476
+ input.artifactPath
477
+ ]);
478
+ if (verification.code !== 0) throw new Error(`binary code signature verification failed: ${commandFailureDetails(verification)}`);
479
+ const inspection = await input.runCommand("/usr/bin/codesign", [
480
+ "--display",
481
+ "--verbose=4",
482
+ input.artifactPath
483
+ ]);
484
+ if (inspection.code !== 0) throw new Error(`binary code signature inspection failed: ${commandFailureDetails(inspection)}`);
485
+ const details = `${inspection.stdout}\n${inspection.stderr}`;
486
+ for (const expected of [
487
+ `Identifier=${codeIdentifier}`,
488
+ `TeamIdentifier=${teamIdentifier}`,
489
+ "Authority=Developer ID Application:"
490
+ ]) if (!details.includes(expected)) throw new Error(`binary code signature is missing expected identity: ${expected}`);
491
+ if (!HARDENED_RUNTIME_FLAG_RE.test(details)) throw new Error("binary code signature is missing the hardened runtime");
492
+ if (!SIGNING_TIMESTAMP_RE.test(details)) throw new Error("binary code signature is missing a trusted timestamp");
493
+ }
494
+ async function downloadCliBinaryDelta(input) {
495
+ const response = await input.fetchImpl(input.delta.patchUrl, {
496
+ method: "GET",
497
+ signal: AbortSignal.timeout(input.downloadTimeoutMs)
498
+ });
499
+ if (!response.ok) {
500
+ const body = await response.text().catch(() => "");
501
+ throw new Error(`binary delta download failed: HTTP ${response.status}${body ? `: ${body}` : ""}`);
502
+ }
503
+ const patchBytes = Buffer.from(await response.arrayBuffer());
504
+ verifyBinaryBytes({
505
+ bytes: patchBytes,
506
+ expectedSha256: input.delta.patchSha256,
507
+ expectedSizeBytes: input.delta.patchSizeBytes,
508
+ label: "binary delta archive"
509
+ });
510
+ let patchPayloadBytes;
511
+ try {
512
+ patchPayloadBytes = gunzipSync(patchBytes, { maxOutputLength: input.delta.patchPayloadSizeBytes });
513
+ } catch (error) {
514
+ throw new Error(`binary delta could not be decompressed: ${toError(error).message}`);
515
+ }
516
+ if (patchPayloadBytes.byteLength !== input.delta.patchPayloadSizeBytes) throw new Error(`binary delta payload size mismatch: expected ${input.delta.patchPayloadSizeBytes} bytes, received ${patchPayloadBytes.byteLength} bytes`);
517
+ return reconstructCliBinaryDelta({
518
+ baseBytes: input.baseBytes,
519
+ delta: input.delta,
520
+ patchPayloadBytes,
521
+ targetSha256: input.release.sha256,
522
+ targetSizeBytes: input.release.sizeBytes
523
+ });
524
+ }
525
+ function resolveFullCliBinaryUpdatePlan(release) {
526
+ if (hasCompressedCliBinaryTransport(release)) return {
527
+ downloadSha256: release.archiveSha256,
528
+ downloadSizeBytes: release.archiveSizeBytes,
529
+ downloadUrl: release.archiveUrl,
530
+ transport: "archive"
531
+ };
532
+ return {
533
+ downloadSha256: release.sha256,
534
+ downloadSizeBytes: release.sizeBytes,
535
+ downloadUrl: release.url,
536
+ transport: "raw"
537
+ };
538
+ }
539
+ async function downloadFullCliBinaryArtifact(input) {
540
+ const response = await input.fetchImpl(input.plan.downloadUrl, {
541
+ method: "GET",
542
+ signal: AbortSignal.timeout(input.downloadTimeoutMs)
543
+ });
544
+ if (!response.ok) {
545
+ const body = await response.text().catch(() => "");
546
+ throw new Error(`binary download failed: HTTP ${response.status}${body ? `: ${body}` : ""}`);
547
+ }
548
+ const downloadBytes = Buffer.from(await response.arrayBuffer());
549
+ verifyBinaryBytes({
550
+ bytes: downloadBytes,
551
+ expectedSha256: input.plan.downloadSha256,
552
+ expectedSizeBytes: input.plan.downloadSizeBytes,
553
+ label: input.plan.transport === "archive" ? "binary archive" : "binary download"
554
+ });
555
+ let artifactBytes = downloadBytes;
556
+ if (input.plan.transport === "archive") try {
557
+ artifactBytes = gunzipSync(downloadBytes, { maxOutputLength: input.release.sizeBytes });
558
+ } catch (error) {
559
+ throw new Error(`binary archive could not be decompressed: ${toError(error).message}`);
560
+ }
561
+ verifyBinaryBytes({
562
+ bytes: artifactBytes,
563
+ expectedSha256: input.release.sha256,
564
+ expectedSizeBytes: input.release.sizeBytes,
565
+ label: "binary download"
566
+ });
567
+ return artifactBytes;
568
+ }
569
+ function hasCompressedCliBinaryTransport(release) {
570
+ return release.archiveFormat === "gzip" && typeof release.archiveUrl === "string" && typeof release.archiveSha256 === "string" && typeof release.archiveSizeBytes === "number";
571
+ }
572
+ function verifyBinaryBytes(input) {
573
+ if (input.bytes.byteLength !== input.expectedSizeBytes) throw new Error(`${input.label} size mismatch: expected ${input.expectedSizeBytes} bytes, received ${input.bytes.byteLength} bytes`);
574
+ const actualSha256 = createHash("sha256").update(input.bytes).digest("hex");
575
+ if (actualSha256 !== input.expectedSha256.toLowerCase()) throw new Error(`${input.label} sha256 mismatch: expected ${input.expectedSha256.toLowerCase()}, received ${actualSha256}`);
576
+ }
577
+ function commandFailureDetails(result) {
578
+ return result.stderr.trim() || result.stdout.trim() || `exit ${result.code}`;
579
+ }
580
+ function toError(error) {
581
+ return error instanceof Error ? error : new Error(String(error));
582
+ }
583
+ //#endregion
584
+ //#region src/config/daemon-service-update-worker-registration.ts
585
+ const MANAGED_VERSION_FROM_EXECUTABLE_PATTERN = /[\\/]versions[\\/](v?(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)[\\/]openmeld(?:\.exe)?/gu;
586
+ const SELF_CONTAINED_BUNDLE_FROM_EXECUTABLE_PATTERN = /[\\/]runtime[\\/]daemon[\\/]bundles[\\/]([0-9A-Za-z._-]+)[\\/]/gu;
587
+ const INDEPENDENT_MAINTENANCE_REGISTRATION = "openmeld-independent-maintenance-v1";
588
+ function configureDaemonMaintenanceEnvironment(env) {
589
+ for (const key of [
590
+ DAEMON_SERVICE_RUNTIME_AUTO_START_ENV,
591
+ DAEMON_SERVICE_RUNTIME_CONTROLLER_ENV,
592
+ DAEMON_SERVICE_RUNTIME_DETACHED_ENV,
593
+ DAEMON_SERVICE_RUNTIME_MODE_ENV,
594
+ DAEMON_SERVICE_RUNTIME_SYSTEM_SERVICE_ENV
595
+ ]) delete env[key];
596
+ env.OPENMELD_INTERNAL_MAINTENANCE_WORKER = "1";
597
+ }
598
+ const NPM_ENTRY_IMPORT_PATTERN = /^await import\((".*")\);$/mu;
599
+ function daemonServiceUpdateWorkerNpmEntryPath(pathInput = {}) {
600
+ return join(daemonRuntimeRootPath(pathInput), "service-update-worker.mjs");
601
+ }
602
+ async function hasIndependentMaintenanceRegistration(pathInput = {}, platform = process$1.platform, expectedDefinition) {
603
+ if (platform === "win32") {
604
+ const { runWindowsUserTask, readWindowsTaskAction } = await import("./windows-user-task-DxPN7TzK.js");
605
+ const task = await runWindowsUserTask({
606
+ name: resolveDaemonServiceUpdateWorkerIdentity(pathInput).windowsServiceName,
607
+ legacyScript: resolveDaemonServiceUpdateWorkerWindowsScriptPath(pathInput),
608
+ operation: "status"
609
+ });
610
+ return Boolean(task.installed && !task.legacy && task.actionArguments && (expectedDefinition === void 0 || task.actionArguments === expectedDefinition) && resolveOpenMeldRootDir({ env: readWindowsTaskAction(task.actionArguments).env }) === resolveOpenMeldRootDir(pathInput));
611
+ }
612
+ const registration = await readDaemonServiceUpdateWorkerRegistration(pathInput, platform);
613
+ if (!registration?.includes("openmeld-independent-maintenance-v1")) return false;
614
+ if (expectedDefinition !== void 0 && registration !== expectedDefinition) return false;
615
+ const { parseDaemonServiceEnvironmentFromDefinition } = await import("./daemon-service-manager-Bh0LoLed.js");
616
+ return resolveOpenMeldRootDir({ env: parseDaemonServiceEnvironmentFromDefinition({
617
+ controller: platform === "darwin" ? "launchd" : "systemd",
618
+ definition: registration
619
+ }) }) === resolveOpenMeldRootDir(pathInput);
620
+ }
621
+ function resolveDaemonServiceUpdateWorkerIdentity(pathInput = {}) {
622
+ const preset = resolveOpenMeldEnvPreset(pathInput);
623
+ const scope = resolveOpenMeldServiceScope(pathInput);
624
+ const suffix = (preset === "prod" ? "" : `-${preset}`) + (scope ? `-${scope}` : "");
625
+ return {
626
+ launchdLabel: `com.openmeld.openmeld-service-update${(preset === "prod" ? "" : `.${preset}`) + (scope ? `.${scope}` : "")}`,
627
+ serviceName: `openmeld-service-update${suffix}`,
628
+ windowsDisplayName: `OpenMeld Service Update${preset === "prod" ? "" : ` (${preset})`}`,
629
+ windowsServiceName: `OpenMeld-Service-Update${suffix}`
630
+ };
631
+ }
632
+ function resolveDaemonServiceUpdateWorkerLaunchdPlistPath(pathInput = {}) {
633
+ return join(pathInput.homeDir ?? homedir(), "Library", "LaunchAgents", `${resolveDaemonServiceUpdateWorkerIdentity(pathInput).launchdLabel}.plist`);
634
+ }
635
+ function resolveDaemonServiceUpdateWorkerSystemdUnitPath(pathInput = {}) {
636
+ return join(pathInput.homeDir ?? homedir(), ".config", "systemd", "user", `${resolveDaemonServiceUpdateWorkerIdentity(pathInput).serviceName}.service`);
637
+ }
638
+ function resolveDaemonServiceUpdateWorkerSystemdPathUnitPath(pathInput = {}) {
639
+ return join(pathInput.homeDir ?? homedir(), ".config", "systemd", "user", `${resolveDaemonServiceUpdateWorkerIdentity(pathInput).serviceName}.path`);
640
+ }
641
+ function resolveDaemonServiceUpdateWorkerWindowsScriptPath(pathInput = {}) {
642
+ return join(daemonRuntimeRootPath(pathInput), "service-update-worker.bat");
643
+ }
644
+ function resolveDaemonServiceUpdateWorkerSystemdTimerUnitPath(pathInput = {}) {
645
+ return join(pathInput.homeDir ?? homedir(), ".config", "systemd", "user", `${resolveDaemonServiceUpdateWorkerIdentity(pathInput).serviceName}.timer`);
646
+ }
647
+ async function readDaemonServiceUpdateWorkerProtectedManagedVersions(pathInput = {}, platform = process$1.platform) {
648
+ const contents = await readDaemonServiceUpdateWorkerRegistration(pathInput, platform);
649
+ return contents === null ? /* @__PURE__ */ new Set() : readManagedVersionsFromUpdateWorkerRegistration(contents);
650
+ }
651
+ async function readDaemonServiceUpdateWorkerProtectedBundleIds(pathInput = {}, platform = process$1.platform) {
652
+ const contents = await readDaemonServiceUpdateWorkerRegistration(pathInput, platform);
653
+ const protectedIds = contents === null ? /* @__PURE__ */ new Set() : readBundleIdsFromUpdateWorkerRegistration(contents);
654
+ const launcher = await readFile(daemonServiceUpdateWorkerNpmEntryPath(pathInput), "utf8").catch((error) => {
655
+ if (getErrorCode$2(error) === "ENOENT") return null;
656
+ throw error;
657
+ });
658
+ if (launcher !== null) {
659
+ const importLine = launcher.trim().match(NPM_ENTRY_IMPORT_PATTERN);
660
+ if (!importLine?.[1]) throw new Error("OpenMeld maintenance launcher is invalid; bundle cleanup was stopped.");
661
+ const entryPath = fileURLToPath(JSON.parse(importLine[1]));
662
+ for (const id of readBundleIdsFromUpdateWorkerRegistration(entryPath)) protectedIds.add(id);
663
+ }
664
+ return protectedIds;
665
+ }
666
+ function readManagedVersionsFromUpdateWorkerRegistration(contents) {
667
+ const versions = /* @__PURE__ */ new Set();
668
+ for (const match of contents.matchAll(MANAGED_VERSION_FROM_EXECUTABLE_PATTERN)) {
669
+ const version = match[1];
670
+ if (version) versions.add(version);
671
+ }
672
+ return versions;
673
+ }
674
+ function readBundleIdsFromUpdateWorkerRegistration(contents) {
675
+ const bundleIds = /* @__PURE__ */ new Set();
676
+ for (const match of contents.matchAll(SELF_CONTAINED_BUNDLE_FROM_EXECUTABLE_PATTERN)) {
677
+ const bundleId = match[1];
678
+ if (bundleId) bundleIds.add(bundleId);
679
+ }
680
+ return bundleIds;
681
+ }
682
+ function resolveDaemonServiceUpdateWorkerRegistrationPath(pathInput, platform) {
683
+ if (platform === "darwin") return resolveDaemonServiceUpdateWorkerLaunchdPlistPath(pathInput);
684
+ if (platform === "linux") return resolveDaemonServiceUpdateWorkerSystemdUnitPath(pathInput);
685
+ if (platform === "win32") return resolveDaemonServiceUpdateWorkerWindowsScriptPath(pathInput);
686
+ return null;
687
+ }
688
+ async function readDaemonServiceUpdateWorkerRegistration(pathInput, platform) {
689
+ const registrationPath = resolveDaemonServiceUpdateWorkerRegistrationPath(pathInput, platform);
690
+ if (registrationPath === null) return null;
691
+ return await readFile(registrationPath, "utf8").catch((error) => {
692
+ if (getErrorCode$2(error) === "ENOENT") return null;
693
+ throw error;
694
+ });
695
+ }
696
+ function getErrorCode$2(error) {
697
+ return error && typeof error === "object" && "code" in error ? String(error.code) : null;
698
+ }
699
+ //#endregion
700
+ //#region package.json
701
+ var package_default = {
702
+ $schema: "https://www.schemastore.org/package.json",
703
+ name: "openmeld",
704
+ version: "0.3.207",
705
+ openMeldReleaseDate: "2026-09-15",
706
+ description: "OpenMeld CLI - https://openmeld.ai",
707
+ license: "MIT",
708
+ type: "module",
709
+ bin: { "openmeld": "dist/openmeld.js" },
710
+ "private": false,
711
+ publishConfig: { "access": "public" },
712
+ engines: { "node": "20.x || >=22 <26" },
713
+ files: [
714
+ "README.md",
715
+ "dist",
716
+ "!dist/binary/**",
717
+ "skills"
718
+ ],
719
+ scripts: {
720
+ "build": "tsdown && node scripts/build-macos-keychain-addon.mjs --copy-npm",
721
+ "prepack": "pnpm -C ../.. run verify:release-ready -- --force && pnpm run verify:pack-readme",
722
+ "deploy": "pnpm -C ../.. run release:deploy:local -- --scope cli",
723
+ "publish:npm": "npm publish",
724
+ "prepublishOnly": "pnpm run verify:pack-readme",
725
+ "verify:pack-readme": "node scripts/verify-npm-pack-readme.mjs",
726
+ "typecheck": "tsc -p tsconfig.json --noEmit",
727
+ "check": "biome check --no-errors-on-unmatched ./ && tsc -p tsconfig.json --noEmit",
728
+ "test": "vitest run --config vitest.config.ts",
729
+ "test:integration": "node scripts/run-integration-tests.mjs",
730
+ "test:full": "pnpm run test && pnpm run test:integration",
731
+ "test:local-service": "vitest run --config vitest.integration.config.ts tests/local-service-state.integration.test.ts tests/local-service-command.integration.test.ts tests/local-service-menu.integration.test.ts tests/local-service-run.integration.test.ts tests/local-service-bootstrap-recommendation.test.ts",
732
+ "test:watch": "vitest"
733
+ },
734
+ dependencies: {
735
+ "@anthropic-ai/claude-agent-sdk": "^0.3.195",
736
+ "@anthropic-ai/sdk": "^0.93.0",
737
+ "@clack/prompts": "^1.0.1",
738
+ "@mariozechner/pi-tui": "0.57.1",
739
+ "@modelcontextprotocol/sdk": "^1.29.0",
740
+ "@opencode-ai/sdk": "^1.18.7",
741
+ "better-sqlite3": "^12.6.2",
742
+ "commander": "^14.0.0",
743
+ "picocolors": "^1.1.1",
744
+ "string-width": "^8.1.0",
745
+ "wrap-ansi": "10.0.0",
746
+ "ws": "^8.18.3",
747
+ "zod": "^4.3.6"
748
+ },
749
+ devDependencies: {
750
+ "@openmeld/adapter-claude-code": "workspace:*",
751
+ "@openmeld/adapter-codex": "workspace:*",
752
+ "@openmeld/adapter-core": "workspace:*",
753
+ "@openmeld/adapter-cursor": "workspace:*",
754
+ "@openmeld/adapter-grok-build": "workspace:*",
755
+ "@openmeld/adapter-openclaw": "workspace:*",
756
+ "@openmeld/adapter-opencode": "workspace:*",
757
+ "@openmeld/agent-runtime": "workspace:*",
758
+ "@openmeld/api-client": "workspace:*",
759
+ "@openmeld/gateway-contract": "workspace:*",
760
+ "@openmeld/local-execution": "workspace:*",
761
+ "@openmeld/local-service": "workspace:*",
762
+ "@openmeld/projects": "workspace:*",
763
+ "@openmeld/protocol": "workspace:*",
764
+ "@openmeld/routine-schedule": "workspace:*",
765
+ "@openmeld/schemas": "workspace:*",
766
+ "@openmeld/space": "workspace:*",
767
+ "@openmeld/space-mesh": "workspace:*",
768
+ "@openmeld/start": "workspace:*",
769
+ "@openmeld/utils": "workspace:*",
770
+ "@types/better-sqlite3": "^7.6.13",
771
+ "@types/node": "^24.3.0",
772
+ "@types/ws": "^8.18.1",
773
+ "node-gyp": "^12.4.0",
774
+ "oxc-resolver": "^11.0.0",
775
+ "tsdown": "^0.20.3",
776
+ "typescript": "^5.9.3",
777
+ "unplugin-lightningcss": "^0.4.0",
778
+ "vitest": "~3.2.0"
779
+ },
780
+ openmeld: {
781
+ "releaseLine": "openmeld-greenfield-2026-07",
782
+ "minRequiredCliVersion": "0.3.198"
783
+ }
784
+ };
785
+ //#endregion
786
+ //#region src/config/service-release.ts
787
+ function resolveBundledServiceRelease() {
788
+ if (!isBinaryDistribution()) return;
789
+ const metadata = package_default;
790
+ const selection = typeof __OPENMELD_SERVICE_RELEASE__ === "undefined" ? metadata.openmeld?.service : __OPENMELD_SERVICE_RELEASE__;
791
+ if (selection === void 0) return;
792
+ const parsed = cliBinaryServiceReleaseSchema.safeParse(selection);
793
+ if (!parsed.success) throw new Error("The installed CLI contains invalid Service release metadata.");
794
+ const platform = `${process.platform}-${process.arch}`;
795
+ const artifact = parsed.data.platforms[platform];
796
+ if (!artifact) throw new Error(`The installed CLI has no Service artifact for ${platform}.`);
797
+ return {
798
+ ...artifact,
799
+ version: parsed.data.version,
800
+ platform,
801
+ minRequiredCliVersion: null
802
+ };
803
+ }
804
+ //#endregion
805
+ //#region src/config/version-state.ts
806
+ const VERSION_STATE_FILENAME = "version.json";
807
+ const NPM_REGISTRY_LATEST_TIMEOUT_MS = 5e3;
808
+ const VERSION_CHECK_CACHE_TTL_MS = 1440 * 60 * 1e3;
809
+ const LEADING_V_PREFIX_REGEX = /^v/;
810
+ const SEMVER_CORE_REGEX = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+.*)?$/;
811
+ const NUMERIC_SEMVER_IDENTIFIER_REGEX = /^\d+$/;
812
+ const versionCache = /* @__PURE__ */ new Map();
813
+ const inFlightVersionRequests = /* @__PURE__ */ new Map();
814
+ function versionStatePath() {
815
+ return join(openMeldRootDir(), VERSION_STATE_FILENAME);
816
+ }
817
+ async function readVersionState() {
818
+ const raw = await readFile(versionStatePath(), "utf8").catch(() => null);
819
+ if (!raw) return null;
820
+ try {
821
+ const parsed = JSON.parse(raw);
822
+ if (parsed.v !== 1 || typeof parsed.updated_at !== "string") return null;
823
+ const lastVersion = toNonEmptyString(parsed.last_version);
824
+ const latestVersion = toNonEmptyString(parsed.latest_version);
825
+ const lastCheckedAt = toNonEmptyString(parsed.last_checked_at);
826
+ const dismissedVersion = parsed.dismissed_version === null ? null : toNonEmptyString(parsed.dismissed_version);
827
+ const requiredFloor = parseStoredRequiredFloor(parsed.required_floor);
828
+ return {
829
+ v: 1,
830
+ ...lastVersion ? { last_version: lastVersion } : {},
831
+ ...latestVersion ? { latest_version: latestVersion } : {},
832
+ ...lastCheckedAt ? { last_checked_at: lastCheckedAt } : {},
833
+ ...dismissedVersion === void 0 ? {} : { dismissed_version: dismissedVersion },
834
+ ...requiredFloor === void 0 ? {} : { required_floor: requiredFloor },
835
+ updated_at: parsed.updated_at
836
+ };
837
+ } catch {
838
+ return null;
839
+ }
840
+ }
841
+ async function writeVersionState(state) {
842
+ await mkdir(openMeldRootDir(), { recursive: true });
843
+ await writeFile(versionStatePath(), `${JSON.stringify(state, null, 2)}\n`);
844
+ }
845
+ function createInitialVersionState(input) {
846
+ const checkedAt = input.checkedAt ?? (/* @__PURE__ */ new Date()).toISOString();
847
+ return {
848
+ v: 1,
849
+ last_version: input.currentVersion,
850
+ latest_version: input.currentVersion,
851
+ last_checked_at: checkedAt,
852
+ dismissed_version: null,
853
+ updated_at: checkedAt
854
+ };
855
+ }
856
+ function hasValidLastVersion(state) {
857
+ return Boolean(toNonEmptyString(state?.last_version));
858
+ }
859
+ async function ensureVersionStateReady(input) {
860
+ const previousVersionState = await readVersionState();
861
+ if (!previousVersionState) {
862
+ const nextState = createInitialVersionState({ currentVersion: input.currentVersion });
863
+ await writeVersionState(nextState);
864
+ return nextState;
865
+ }
866
+ if (hasValidLastVersion(previousVersionState)) return previousVersionState;
867
+ const nextState = {
868
+ ...previousVersionState,
869
+ last_version: input.currentVersion,
870
+ latest_version: previousVersionState.latest_version ?? input.currentVersion
871
+ };
872
+ await writeVersionState(nextState);
873
+ return nextState;
874
+ }
875
+ function buildNextVersionState(input) {
876
+ const checkedAt = input.checkedAt ?? (/* @__PURE__ */ new Date()).toISOString();
877
+ const latestVersion = toNonEmptyString(input.latestVersion) ?? toNonEmptyString(input.previous?.latest_version) ?? input.currentVersion;
878
+ const requiredFloor = input.requiredFloor === void 0 ? input.previous?.required_floor ?? null : input.requiredFloor;
879
+ return {
880
+ v: 1,
881
+ last_version: input.currentVersion,
882
+ latest_version: latestVersion,
883
+ last_checked_at: checkedAt,
884
+ dismissed_version: input.dismissedVersion ?? input.previous?.dismissed_version ?? null,
885
+ ...requiredFloor ? { required_floor: requiredFloor } : {},
886
+ updated_at: checkedAt
887
+ };
888
+ }
889
+ function parseStoredRequiredFloor(value) {
890
+ if (value === void 0) return;
891
+ if (value === null) return null;
892
+ return toNonEmptyString(value);
893
+ }
894
+ async function fetchLatestPackageInfo(packageName, input = {}) {
895
+ const now = Date.now();
896
+ const cached = input.forceRefresh ? void 0 : versionCache.get(packageName);
897
+ if (cached && now - cached.fetchedAt < VERSION_CHECK_CACHE_TTL_MS) return cached.info;
898
+ const requestKey = input.forceRefresh ? `${packageName}:force_refresh` : packageName;
899
+ const inFlight = inFlightVersionRequests.get(requestKey);
900
+ if (inFlight) return inFlight;
901
+ const request = requestLatestPackageInfo(packageName);
902
+ inFlightVersionRequests.set(requestKey, request);
903
+ try {
904
+ const info = await request;
905
+ versionCache.set(packageName, {
906
+ info,
907
+ fetchedAt: Date.now()
908
+ });
909
+ return info;
910
+ } finally {
911
+ inFlightVersionRequests.delete(requestKey);
912
+ }
913
+ }
914
+ async function fetchLatestCliBinaryRelease(input) {
915
+ const manifest = await requestCliBinaryManifest();
916
+ const platform = toNonEmptyString(input?.platform) ?? `${process$1.platform}-${process$1.arch}`;
917
+ const release = manifest.platforms[platform];
918
+ if (!release) throw new Error(`version check failed: invalid CLI manifest response: missing platform ${platform}`);
919
+ const serviceRelease = manifest.service?.platforms[platform];
920
+ return {
921
+ version: manifest.version,
922
+ minRequiredCliVersion: manifest.minRequiredCliVersion,
923
+ platform,
924
+ ...release,
925
+ ...manifest.service && serviceRelease ? { service: {
926
+ ...serviceRelease,
927
+ version: manifest.service.version,
928
+ platform
929
+ } } : {}
930
+ };
931
+ }
932
+ async function requestLatestPackageInfo(packageName) {
933
+ if (isBinaryDistribution()) return await requestLatestPackageInfoFromCliManifest();
934
+ const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`, {
935
+ method: "GET",
936
+ signal: AbortSignal.timeout(NPM_REGISTRY_LATEST_TIMEOUT_MS)
937
+ });
938
+ const raw = await response.text();
939
+ if (!response.ok) throw new Error(`version check failed: HTTP ${response.status}: ${raw}`);
940
+ try {
941
+ const parsed = JSON.parse(raw);
942
+ const version = typeof parsed.version === "string" ? parsed.version.trim() : "";
943
+ if (!version) throw new Error("missing version");
944
+ return {
945
+ version,
946
+ minRequiredCliVersion: readMinRequiredCliVersion(parsed.openmeld)
947
+ };
948
+ } catch (error) {
949
+ throw new Error(`version check failed: invalid registry response: ${toErrorMessage(error)}`);
950
+ }
951
+ }
952
+ const CLI_BINARY_MANIFEST_URL = toNonEmptyString(process$1.env.OPENMELD_CLI_BINARY_MANIFEST_URL) ?? "https://openmeld.ai/cli/manifest.json";
953
+ async function requestLatestPackageInfoFromCliManifest() {
954
+ const manifest = await requestCliBinaryManifest();
955
+ return {
956
+ version: manifest.version,
957
+ minRequiredCliVersion: manifest.minRequiredCliVersion,
958
+ ...manifest.service ? { serviceVersion: manifest.service.version } : {}
959
+ };
960
+ }
961
+ async function requestCliBinaryManifest() {
962
+ const response = await fetch(CLI_BINARY_MANIFEST_URL, {
963
+ method: "GET",
964
+ signal: AbortSignal.timeout(NPM_REGISTRY_LATEST_TIMEOUT_MS)
965
+ });
966
+ const raw = await response.text();
967
+ if (!response.ok) throw new Error(`version check failed: HTTP ${response.status}: ${raw}`);
968
+ try {
969
+ return parseCliBinaryManifest(raw);
970
+ } catch (error) {
971
+ throw new Error(`version check failed: invalid CLI manifest response: ${toErrorMessage(error)}`);
972
+ }
973
+ }
974
+ function parseCliBinaryManifest(raw) {
975
+ const parsed = cliBinaryManifestSchema.safeParse(JSON.parse(raw));
976
+ if (!parsed.success) throw new Error(parsed.error.message);
977
+ const stable = parsed.data.channels.stable;
978
+ return {
979
+ ...stable,
980
+ minRequiredCliVersion: stable.minRequiredCliVersion ?? null
981
+ };
982
+ }
983
+ function readMinRequiredCliVersion(openmeld) {
984
+ if (!openmeld || typeof openmeld !== "object") return null;
985
+ const value = openmeld.minRequiredCliVersion;
986
+ if (typeof value !== "string") return null;
987
+ const trimmed = value.trim();
988
+ return trimmed.length > 0 && isPlainReleaseVersion(trimmed) ? trimmed : null;
989
+ }
990
+ const PLAIN_RELEASE_VERSION_RE = /^\d+\.\d+\.\d+$/;
991
+ function isPlainReleaseVersion(value) {
992
+ return PLAIN_RELEASE_VERSION_RE.test(value.trim());
993
+ }
994
+ function compareSemver(a, b) {
995
+ const left = parseSemver(a);
996
+ const right = parseSemver(b);
997
+ if (!(left && right)) return a.localeCompare(b);
998
+ if (left.major !== right.major) return left.major > right.major ? 1 : -1;
999
+ if (left.minor !== right.minor) return left.minor > right.minor ? 1 : -1;
1000
+ if (left.patch !== right.patch) return left.patch > right.patch ? 1 : -1;
1001
+ return comparePrereleaseIdentifiers(left.prerelease, right.prerelease);
1002
+ }
1003
+ function parseSemver(value) {
1004
+ const match = value.trim().replace(LEADING_V_PREFIX_REGEX, "").match(SEMVER_CORE_REGEX);
1005
+ if (!match) return null;
1006
+ return {
1007
+ major: Number(match[1]),
1008
+ minor: Number(match[2]),
1009
+ patch: Number(match[3]),
1010
+ prerelease: match[4] ? match[4].split(".") : null
1011
+ };
1012
+ }
1013
+ function comparePrereleaseIdentifiers(left, right) {
1014
+ if (!(left || right)) return 0;
1015
+ if (!left) return 1;
1016
+ if (!right) return -1;
1017
+ const maxLength = Math.max(left.length, right.length);
1018
+ for (let index = 0; index < maxLength; index += 1) {
1019
+ const leftIdentifier = left[index];
1020
+ const rightIdentifier = right[index];
1021
+ const lengthComparison = comparePrereleaseLengthAtIndex(leftIdentifier, rightIdentifier);
1022
+ if (lengthComparison !== 0) return lengthComparison;
1023
+ if (!(leftIdentifier && rightIdentifier)) continue;
1024
+ const compared = compareSinglePrereleaseIdentifier(leftIdentifier, rightIdentifier);
1025
+ if (compared !== 0) return compared;
1026
+ }
1027
+ return 0;
1028
+ }
1029
+ function comparePrereleaseLengthAtIndex(leftIdentifier, rightIdentifier) {
1030
+ if (leftIdentifier === void 0 && rightIdentifier === void 0) return 0;
1031
+ if (leftIdentifier === void 0) return -1;
1032
+ if (rightIdentifier === void 0) return 1;
1033
+ return 0;
1034
+ }
1035
+ function compareSinglePrereleaseIdentifier(leftIdentifier, rightIdentifier) {
1036
+ if (leftIdentifier === rightIdentifier) return 0;
1037
+ const leftNumber = toNumericPrereleaseIdentifier(leftIdentifier);
1038
+ const rightNumber = toNumericPrereleaseIdentifier(rightIdentifier);
1039
+ if (leftNumber !== null && rightNumber !== null) {
1040
+ if (leftNumber === rightNumber) return 0;
1041
+ return leftNumber > rightNumber ? 1 : -1;
1042
+ }
1043
+ if (leftNumber !== null) return -1;
1044
+ if (rightNumber !== null) return 1;
1045
+ return leftIdentifier > rightIdentifier ? 1 : -1;
1046
+ }
1047
+ function toNumericPrereleaseIdentifier(identifier) {
1048
+ if (!NUMERIC_SEMVER_IDENTIFIER_REGEX.test(identifier)) return null;
1049
+ return Number(identifier);
1050
+ }
1051
+ function toNonEmptyString(value) {
1052
+ if (typeof value !== "string") return null;
1053
+ const normalized = value.trim();
1054
+ return normalized.length > 0 ? normalized : null;
1055
+ }
1056
+ function toErrorMessage(error) {
1057
+ if (error instanceof Error) return error.message;
1058
+ return String(error);
1059
+ }
1060
+ //#endregion
1061
+ //#region src/local-service/lifecycle/daemon-service-update-state.ts
1062
+ const DAEMON_SERVICE_UPDATE_JOB_SCHEMA = OPENMELD_DAEMON_SERVICE_UPDATE_JOB_SCHEMA;
1063
+ function daemonServicePendingUpdatePath(pathInput = {}) {
1064
+ return join(daemonRuntimeStateRootPath(pathInput), "service-update.json");
1065
+ }
1066
+ function daemonServiceLastUpdatePath(pathInput = {}) {
1067
+ return join(daemonRuntimeStateRootPath(pathInput), "service-update-last.json");
1068
+ }
1069
+ async function readPendingDaemonServiceUpdate(pathInput = {}) {
1070
+ return await readDaemonServiceUpdateJob(daemonServicePendingUpdatePath(pathInput));
1071
+ }
1072
+ async function readLastDaemonServiceUpdate(pathInput = {}) {
1073
+ return await readDaemonServiceUpdateJob(daemonServiceLastUpdatePath(pathInput));
1074
+ }
1075
+ async function persistPendingDaemonServiceUpdate(job, pathInput = {}) {
1076
+ await writeUpdateJobAtomically({
1077
+ job,
1078
+ path: daemonServicePendingUpdatePath(pathInput)
1079
+ });
1080
+ }
1081
+ async function completePendingDaemonServiceUpdate(job, pathInput = {}, retainPending = false) {
1082
+ await writeUpdateJobAtomically({
1083
+ job,
1084
+ path: daemonServiceLastUpdatePath(pathInput)
1085
+ });
1086
+ if (retainPending) {
1087
+ await persistPendingDaemonServiceUpdate(job, pathInput);
1088
+ return;
1089
+ }
1090
+ await rm(daemonServicePendingUpdatePath(pathInput), { force: true });
1091
+ }
1092
+ async function readDaemonServiceUpdateJob(path) {
1093
+ const raw = await readFile(path, "utf8").catch((error) => {
1094
+ if (error.code === "ENOENT") return null;
1095
+ throw error;
1096
+ });
1097
+ if (raw === null) return null;
1098
+ const parsed = storedDaemonServiceUpdateJobSchema.safeParse(JSON.parse(raw));
1099
+ if (!parsed.success) throw new Error("OpenMeld Service update state is invalid.");
1100
+ if (parsed.data.v === 2) return parsed.data;
1101
+ const { status, ...legacyJob } = parsed.data;
1102
+ return daemonServiceUpdateJobSchema.parse({
1103
+ ...legacyJob,
1104
+ v: 2,
1105
+ schema: DAEMON_SERVICE_UPDATE_JOB_SCHEMA,
1106
+ phase: migrateLegacyPhase(status),
1107
+ requestSource: "cli"
1108
+ });
1109
+ }
1110
+ function migrateLegacyPhase(status) {
1111
+ switch (status) {
1112
+ case "scheduled": return "waiting_for_work";
1113
+ case "running": return "updating";
1114
+ case "completed": return "updated";
1115
+ case "failed": return "needs_help";
1116
+ default: return status;
1117
+ }
1118
+ }
1119
+ async function writeUpdateJobAtomically(input) {
1120
+ const temporaryPath = `${input.path}.${String(process.pid)}.tmp`;
1121
+ await mkdir(dirname(input.path), { recursive: true });
1122
+ await writeFile(temporaryPath, `${JSON.stringify(input.job, null, 2)}\n`, {
1123
+ encoding: "utf8",
1124
+ mode: 384
1125
+ });
1126
+ await rename(temporaryPath, input.path);
1127
+ }
1128
+ //#endregion
1129
+ //#region src/runtime/version.ts
1130
+ /**
1131
+ * The version of the running CLI and Service bundle.
1132
+ *
1133
+ * npm builds use package.json. Binary builds may inject an isolated staging
1134
+ * prerelease so the real update lifecycle can be exercised before a production
1135
+ * version exists.
1136
+ */
1137
+ function resolveOpenMeldVersion() {
1138
+ return (typeof __OPENMELD_VERSION__ === "string" ? __OPENMELD_VERSION__.trim() : "") || package_default.version;
1139
+ }
1140
+ const OPENMELD_VERSION = resolveOpenMeldVersion();
1141
+ //#endregion
1142
+ //#region src/local-components/managed-version-pruning.ts
1143
+ const MANAGED_VERSION_DIRECTORY_PATTERN = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
1144
+ async function pruneManagedVersions(input) {
1145
+ const versionsDir = openMeldVersionsDir(input.pathInput);
1146
+ const managedVersions = (await readdir(versionsDir, { withFileTypes: true })).filter((entry) => entry.isDirectory() && MANAGED_VERSION_DIRECTORY_PATTERN.test(entry.name)).map((entry) => entry.name);
1147
+ const usableManagedVersions = new Set((await Promise.all(managedVersions.map(async (version) => ({
1148
+ usable: await isUsableManagedVersion(version, versionsDir),
1149
+ version
1150
+ })))).filter((entry) => entry.usable).map((entry) => entry.version));
1151
+ const retainedVersions = /* @__PURE__ */ new Set([input.currentVersion]);
1152
+ let rollbackVersion = null;
1153
+ if (input.preferredRollbackVersion && input.preferredRollbackVersion !== input.currentVersion && usableManagedVersions.has(input.preferredRollbackVersion)) rollbackVersion = input.preferredRollbackVersion;
1154
+ rollbackVersion ??= [...usableManagedVersions].filter((version) => compareSemver(version, input.currentVersion) < 0).sort((left, right) => compareSemver(right, left))[0] ?? null;
1155
+ if (rollbackVersion) retainedVersions.add(rollbackVersion);
1156
+ for (const protectedVersion of input.protectedVersions ?? []) if (usableManagedVersions.has(protectedVersion)) retainedVersions.add(protectedVersion);
1157
+ await Promise.all(managedVersions.filter((version) => !retainedVersions.has(version)).map((version) => rm(path.join(versionsDir, version), { recursive: true })));
1158
+ }
1159
+ async function isUsableManagedVersion(version, versionsDir) {
1160
+ const target = path.join(versionsDir, version, "openmeld");
1161
+ if (!(await stat(target).catch((error) => {
1162
+ if (getErrorCode$1(error) === "ENOENT") return null;
1163
+ throw error;
1164
+ }))?.isFile()) return false;
1165
+ return await access(target, constants.X_OK).then(() => true, (error) => {
1166
+ if (getErrorCode$1(error) === "EACCES" || getErrorCode$1(error) === "ENOENT") return false;
1167
+ throw error;
1168
+ });
1169
+ }
1170
+ function getErrorCode$1(error) {
1171
+ return error && typeof error === "object" && "code" in error ? String(error.code) : null;
1172
+ }
1173
+ //#endregion
1174
+ //#region src/local-components/managed-install.ts
1175
+ const MANAGED_INSTALL_LOCK_PROFILE = "managed-cli";
1176
+ const MANAGED_INSTALL_LOCK_KEY = "install";
1177
+ const MANAGED_INSTALL_LOCK_RETRY_DELAY_MS = 100;
1178
+ const MANAGED_INSTALL_LOCK_TIMEOUT_MS = 3e4;
1179
+ function resolveCliPlatformToken() {
1180
+ return `${process$1.platform}-${process$1.arch}`;
1181
+ }
1182
+ function resolveCliSelfVersion() {
1183
+ return OPENMELD_VERSION;
1184
+ }
1185
+ async function isUsableManagedBinary(target) {
1186
+ if (!(await stat(target).catch((error) => {
1187
+ if (isErrorWithCode(error, "ENOENT")) return null;
1188
+ throw error;
1189
+ }))?.isFile()) return false;
1190
+ return await access(target, constants.X_OK).then(() => true, (error) => {
1191
+ if (isErrorWithCode(error, "EACCES") || isErrorWithCode(error, "ENOENT")) return false;
1192
+ throw error;
1193
+ });
1194
+ }
1195
+ async function readCurrentPointerVersion(pathInput = {}) {
1196
+ const pointerPath = openMeldManagedBinaryPath(pathInput);
1197
+ const target = await readlink(pointerPath).catch((error) => {
1198
+ if (isErrorWithCode(error, "ENOENT") || isErrorWithCode(error, "EINVAL")) return null;
1199
+ throw error;
1200
+ });
1201
+ if (!target) return null;
1202
+ const resolved = path.isAbsolute(target) ? target : path.resolve(path.dirname(pointerPath), target);
1203
+ const version = path.basename(path.dirname(resolved));
1204
+ return version.length > 0 && path.resolve(resolved) === openMeldManagedVersionBinaryPath(version, pathInput) ? version : null;
1205
+ }
1206
+ async function readManagedCliInstallation() {
1207
+ const version = await readCurrentPointerVersion();
1208
+ if (!version) return null;
1209
+ const binaryPath = openMeldManagedVersionBinaryPath(version);
1210
+ if (!await isUsableManagedBinary(binaryPath)) return null;
1211
+ return {
1212
+ version,
1213
+ binaryPath
1214
+ };
1215
+ }
1216
+ /**
1217
+ * Install the currently-running binary (process.execPath) into the managed
1218
+ * layout and point bin/openmeld at it. Idempotent with semver arbitration:
1219
+ * a same-or-newer pointer is left in place (install only goes up), unless
1220
+ * `force` is set. Both the versioned binary and the pointer are swapped in
1221
+ * atomically via a temp name + rename.
1222
+ */
1223
+ async function performManagedInstall(input) {
1224
+ return await withManagedInstallTransaction(async () => performManagedInstallLocked(input));
1225
+ }
1226
+ async function withManagedInstallTransaction(run, pathInput = {}) {
1227
+ const startedAtMs = Date.now();
1228
+ for (;;) try {
1229
+ return await runWithHeldLock({
1230
+ lock: await acquireLock({
1231
+ openMeldProfileId: MANAGED_INSTALL_LOCK_PROFILE,
1232
+ key: MANAGED_INSTALL_LOCK_KEY,
1233
+ meta: { component: "managed_cli.install" },
1234
+ pathResolution: pathInput
1235
+ }),
1236
+ run,
1237
+ releaseContext: {
1238
+ component: "managed_cli.install",
1239
+ lockKey: MANAGED_INSTALL_LOCK_KEY,
1240
+ openMeldProfileId: MANAGED_INSTALL_LOCK_PROFILE
1241
+ }
1242
+ });
1243
+ } catch (error) {
1244
+ if (!isOpenMeldLockError(error) || isOpenMeldOrphanedLockError(error) || Date.now() - startedAtMs >= MANAGED_INSTALL_LOCK_TIMEOUT_MS) throw error;
1245
+ await setTimeout(MANAGED_INSTALL_LOCK_RETRY_DELAY_MS);
1246
+ }
1247
+ }
1248
+ /**
1249
+ * Prune managed CLI versions only while holding the install transaction lock.
1250
+ * The current pointer and every durable Service update target are re-read in
1251
+ * the lock, so cleanup cannot race an install or use a stale pending snapshot.
1252
+ */
1253
+ async function pruneManagedInstallVersions(input) {
1254
+ const pathInput = input.pathInput;
1255
+ assertNoPublishedProductionMutationDuringTests(pathInput, "managed CLI versions");
1256
+ await withManagedInstallTransaction(async () => {
1257
+ const currentVersion = await readCurrentPointerVersion(pathInput);
1258
+ if (currentVersion === null) return;
1259
+ const protectedVersions = await readManagedInstallProtectedVersions(pathInput);
1260
+ await pruneManagedVersions({
1261
+ currentVersion,
1262
+ pathInput,
1263
+ preferredRollbackVersion: input.preferredRollbackVersion,
1264
+ protectedVersions
1265
+ });
1266
+ }, pathInput);
1267
+ }
1268
+ async function performManagedInstallLocked(input) {
1269
+ const force = input?.force ?? false;
1270
+ const version = resolveCliSelfVersion();
1271
+ const platform = resolveCliPlatformToken();
1272
+ const currentPointerPath = openMeldManagedBinaryPath();
1273
+ const managedBinaryPath = openMeldManagedVersionBinaryPath(version);
1274
+ const previousVersion = await readCurrentPointerVersion();
1275
+ const protectedVersions = await readManagedInstallProtectedVersions();
1276
+ const baseOutcome = {
1277
+ version,
1278
+ platform,
1279
+ managedBinaryPath,
1280
+ currentPointerPath,
1281
+ previousVersion,
1282
+ forced: force
1283
+ };
1284
+ if (previousVersion !== null) {
1285
+ const comparison = compareSemver(version, previousVersion);
1286
+ if (!force && comparison === 0 && await isUsableManagedBinary(managedBinaryPath)) {
1287
+ await pruneManagedVersions({
1288
+ currentVersion: previousVersion,
1289
+ protectedVersions
1290
+ });
1291
+ return {
1292
+ ...baseOutcome,
1293
+ result: "noop_same_version"
1294
+ };
1295
+ }
1296
+ if (comparison < 0 && !force) {
1297
+ if (!await isUsableManagedBinary(managedBinaryPath)) await placeVersionedBinary(input?.sourceBinaryPath ?? process$1.execPath, version, managedBinaryPath);
1298
+ await pruneManagedVersions({
1299
+ currentVersion: previousVersion,
1300
+ preferredRollbackVersion: version,
1301
+ protectedVersions
1302
+ });
1303
+ return {
1304
+ ...baseOutcome,
1305
+ result: "noop_newer_present"
1306
+ };
1307
+ }
1308
+ }
1309
+ await placeVersionedBinary(input?.sourceBinaryPath ?? process$1.execPath, version, managedBinaryPath);
1310
+ await pruneManagedVersions({
1311
+ currentVersion: version,
1312
+ preferredRollbackVersion: previousVersion,
1313
+ protectedVersions
1314
+ });
1315
+ await swapCurrentPointer(currentPointerPath, managedBinaryPath);
1316
+ return {
1317
+ ...baseOutcome,
1318
+ result: "installed"
1319
+ };
1320
+ }
1321
+ async function readManagedInstallProtectedVersions(pathInput = {}) {
1322
+ const [protectedVersions, pendingServiceUpdate, activeBundle] = await Promise.all([
1323
+ readDaemonServiceUpdateWorkerProtectedManagedVersions(pathInput),
1324
+ readPendingDaemonServiceUpdate(pathInput),
1325
+ readDaemonActiveBundleState(pathInput)
1326
+ ]);
1327
+ if (activeBundle?.bundleFormat === "binary_v1") protectedVersions.add(activeBundle.daemonVersion);
1328
+ if (pendingServiceUpdate?.preparedBundle.bundleFormat === "binary_v1") protectedVersions.add(pendingServiceUpdate.preparedBundle.daemonVersion);
1329
+ return protectedVersions;
1330
+ }
1331
+ async function placeVersionedBinary(sourceBinary, version, managedBinaryPath) {
1332
+ await mkdir(openMeldManagedVersionDir(version), { recursive: true });
1333
+ const tmpPath = `${managedBinaryPath}.tmp-${process$1.pid}-${Date.now()}`;
1334
+ await rm(tmpPath, { force: true }).catch(() => void 0);
1335
+ await copyFile(sourceBinary, tmpPath);
1336
+ await chmod(tmpPath, 493);
1337
+ if ((await lstat(managedBinaryPath).catch((error) => {
1338
+ if (isErrorWithCode(error, "ENOENT")) return null;
1339
+ throw error;
1340
+ }))?.isDirectory()) await rm(managedBinaryPath, { recursive: true });
1341
+ await rename(tmpPath, managedBinaryPath);
1342
+ }
1343
+ async function swapCurrentPointer(currentPointerPath, managedBinaryPath) {
1344
+ await mkdir(openMeldBinDir(), { recursive: true });
1345
+ const relativeTarget = path.relative(path.dirname(currentPointerPath), managedBinaryPath);
1346
+ const tmpPath = `${currentPointerPath}.tmp-${process$1.pid}-${Date.now()}`;
1347
+ await rm(tmpPath, { force: true }).catch(() => void 0);
1348
+ await symlink(relativeTarget, tmpPath);
1349
+ await rename(tmpPath, currentPointerPath);
1350
+ }
1351
+ function buildInstallSelfJsonPayload(outcome) {
1352
+ return {
1353
+ schemaVersion: 1,
1354
+ type: "cli.install_self",
1355
+ result: outcome.result,
1356
+ version: outcome.version,
1357
+ platform: outcome.platform,
1358
+ managedBinaryPath: outcome.managedBinaryPath,
1359
+ currentPointerPath: outcome.currentPointerPath,
1360
+ previousVersion: outcome.previousVersion,
1361
+ forced: outcome.forced
1362
+ };
1363
+ }
1364
+ function isErrorWithCode(error, code) {
1365
+ return error instanceof Error && "code" in error && error.code === code;
1366
+ }
1367
+ //#endregion
1368
+ //#region src/system/local-operation-diagnostics.ts
1369
+ const ERROR_CODES = /* @__PURE__ */ new Set([
1370
+ "EPERM",
1371
+ "EACCES",
1372
+ "ENOENT",
1373
+ "ENOTDIR",
1374
+ "EISDIR",
1375
+ "EROFS",
1376
+ "ENOSPC",
1377
+ "EBUSY",
1378
+ "ETXTBSY",
1379
+ "EEXIST",
1380
+ "EIO",
1381
+ "EMFILE",
1382
+ "ENFILE",
1383
+ "EINVAL",
1384
+ "ENAMETOOLONG"
1385
+ ]);
1386
+ const SYSCALLS = /* @__PURE__ */ new Set([
1387
+ "access",
1388
+ "open",
1389
+ "read",
1390
+ "write",
1391
+ "chmod",
1392
+ "chown",
1393
+ "copyfile",
1394
+ "rename",
1395
+ "unlink",
1396
+ "rmdir",
1397
+ "mkdir",
1398
+ "stat",
1399
+ "lstat",
1400
+ "realpath",
1401
+ "spawn"
1402
+ ]);
1403
+ const APP_BUNDLE_PATH_PATTERN = /(?:^|[/\\])[^/\\]+\.app(?:[/\\]|$)/iu;
1404
+ function classifyDiagnosticPath(value) {
1405
+ if (typeof value !== "string" || !value) return "unknown";
1406
+ if (APP_BUNDLE_PATH_PATTERN.test(value)) return "app_bundle";
1407
+ return isAbsolute(value) ? "absolute_other" : "relative";
1408
+ }
1409
+ function collectLocalOperationFailure(error) {
1410
+ let current = error;
1411
+ for (let depth = 0; depth < 4 && current instanceof Error; depth += 1) {
1412
+ const native = current;
1413
+ if (native.code && ERROR_CODES.has(native.code)) return {
1414
+ code: native.code,
1415
+ ...Number.isSafeInteger(native.errno) ? { errno: native.errno } : {},
1416
+ ...native.syscall && SYSCALLS.has(native.syscall) ? { syscall: native.syscall } : {},
1417
+ pathCategory: classifyDiagnosticPath(native.path),
1418
+ ...native.dest === void 0 ? {} : { destinationCategory: classifyDiagnosticPath(native.dest) }
1419
+ };
1420
+ current = current.cause;
1421
+ }
1422
+ }
1423
+ //#endregion
1424
+ //#region src/local-service/lifecycle/daemon-lifecycle-journal.ts
1425
+ const DAEMON_LIFECYCLE_EVENT_TYPES = [
1426
+ "connection.state",
1427
+ "daemon.crash",
1428
+ "lifecycle.command.begin",
1429
+ "lifecycle.command.end",
1430
+ "owner.snapshot",
1431
+ "route_catalog.initial_load",
1432
+ "runtime_state.takeover",
1433
+ "stop.controlled_drain",
1434
+ "stop.strategy.selected",
1435
+ "service_manager.action",
1436
+ "service_manager.registration_reconcile",
1437
+ "process_stop.action",
1438
+ "service_contract.write",
1439
+ "stop.signal.observed"
1440
+ ];
1441
+ const DAEMON_STOP_CAUSES = [
1442
+ "user_stop",
1443
+ "controlled_service_update",
1444
+ "service_crash",
1445
+ "network_disconnect",
1446
+ "unknown"
1447
+ ];
1448
+ function toJournalErrorMessage(error) {
1449
+ return error instanceof Error ? error.message : String(error);
1450
+ }
1451
+ function normalizeSessionId(value) {
1452
+ const normalized = typeof value === "string" ? value.trim() : "";
1453
+ return normalized.length > 0 ? normalized : null;
1454
+ }
1455
+ function resolveDaemonStopCause(input) {
1456
+ if (input.explicitCause) return input.explicitCause;
1457
+ if (input.type === "daemon.crash") return "service_crash";
1458
+ if (input.type === "connection.state") return "unknown";
1459
+ if (input.intent === "stop") return "user_stop";
1460
+ if (input.intent === "upgrade_reconcile" || input.intent === "reinstall" || input.intent === "startup_check" || input.intent === "status_cleanup") return "controlled_service_update";
1461
+ return "unknown";
1462
+ }
1463
+ function isDaemonLifecycleEvent(event) {
1464
+ if (typeof event !== "object" || event === null) return false;
1465
+ const candidate = event;
1466
+ return candidate.schema === "openmeld-daemon-lifecycle-event-v1" && candidate.v === 1 && DAEMON_LIFECYCLE_EVENT_TYPES.includes(candidate.type) && typeof candidate.timestamp === "string" && candidate.timestamp.length > 0 && typeof candidate.lane === "string" && candidate.lane.length > 0 && typeof candidate.intent === "string" && candidate.intent.length > 0 && typeof candidate.command === "string" && candidate.command.length > 0 && typeof candidate.pid === "number" && Number.isInteger(candidate.pid) && candidate.pid > 0 && (candidate.sessionId === null || typeof candidate.sessionId === "string" && candidate.sessionId.length > 0) && (candidate.stopCause === void 0 || DAEMON_STOP_CAUSES.includes(candidate.stopCause)) && typeof candidate.result === "string" && candidate.result.length > 0;
1467
+ }
1468
+ async function resolveDaemonLifecycleAttribution(input) {
1469
+ const lockMeta = await readDaemonServiceLifecycleLockMeta().catch(() => null);
1470
+ return {
1471
+ command: input.command?.trim() || (typeof lockMeta?.command === "string" ? lockMeta.command.trim() : "") || "unknown",
1472
+ intent: input.intent ?? (typeof lockMeta?.intent === "string" ? lockMeta.intent : "unknown"),
1473
+ lane: resolveOpenMeldEnvPreset(input.pathInput),
1474
+ pid: typeof lockMeta?.pid === "number" && lockMeta.pid > 0 ? lockMeta.pid : process$1.pid,
1475
+ sessionId: normalizeSessionId(lockMeta?.sessionId) ?? resolveCliContextId()
1476
+ };
1477
+ }
1478
+ async function emitDaemonLifecycleEvent(input) {
1479
+ assertNoPublishedProductionMutationDuringTests(input.pathInput ?? {}, "OpenMeld Service lifecycle journal");
1480
+ const journalPath = daemonLifecycleJournalPath(input.pathInput);
1481
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1482
+ const attribution = input.type === "connection.state" ? {
1483
+ command: "openmeld service run",
1484
+ intent: "unknown",
1485
+ lane: resolveOpenMeldEnvPreset(input.pathInput),
1486
+ pid: process$1.pid,
1487
+ sessionId: resolveCliContextId()
1488
+ } : await resolveDaemonLifecycleAttribution(input);
1489
+ const event = {
1490
+ schema: "openmeld-daemon-lifecycle-event-v1",
1491
+ v: 1,
1492
+ type: input.type,
1493
+ timestamp,
1494
+ lane: attribution.lane,
1495
+ intent: attribution.intent,
1496
+ command: attribution.command,
1497
+ pid: attribution.pid,
1498
+ sessionId: attribution.sessionId,
1499
+ stopCause: resolveDaemonStopCause({
1500
+ explicitCause: input.stopCause,
1501
+ intent: attribution.intent,
1502
+ result: input.result,
1503
+ type: input.type
1504
+ }),
1505
+ result: input.result,
1506
+ ...input.metadata ? { metadata: input.metadata } : {}
1507
+ };
1508
+ if (!isDaemonLifecycleEvent(event)) {
1509
+ console.warn(`[openmeld:lifecycle-journal] rejected invalid event ${input.type}`);
1510
+ return;
1511
+ }
1512
+ try {
1513
+ await mkdir(dirname(journalPath), { recursive: true });
1514
+ await appendFile(journalPath, `${JSON.stringify(event)}\n`, "utf8");
1515
+ } catch (error) {
1516
+ console.warn(`[openmeld:lifecycle-journal] failed to append event ${input.type}: ${toJournalErrorMessage(error)}`);
1517
+ }
1518
+ }
1519
+ async function runWithDaemonLifecycleCommandJournal(input) {
1520
+ await emitDaemonLifecycleEvent({
1521
+ type: "lifecycle.command.begin",
1522
+ result: "started",
1523
+ metadata: input.includeProcessUptime ? {
1524
+ ...input.metadata,
1525
+ processUptimeMs: Math.round(process$1.uptime() * 1e3)
1526
+ } : input.metadata,
1527
+ pathInput: input.pathInput,
1528
+ command: input.command,
1529
+ intent: input.intent
1530
+ });
1531
+ try {
1532
+ const result = await input.run();
1533
+ const resolvedResult = input.resolveResult?.(result) ?? { result: "completed" };
1534
+ await emitDaemonLifecycleEvent({
1535
+ type: "lifecycle.command.end",
1536
+ result: resolvedResult.result,
1537
+ metadata: resolvedResult.metadata,
1538
+ pathInput: input.pathInput,
1539
+ command: input.command,
1540
+ intent: input.intent
1541
+ });
1542
+ return result;
1543
+ } catch (error) {
1544
+ await emitDaemonLifecycleEvent({
1545
+ type: "lifecycle.command.end",
1546
+ result: "failed",
1547
+ metadata: { errorMessage: toJournalErrorMessage(error) },
1548
+ pathInput: input.pathInput,
1549
+ command: input.command,
1550
+ intent: input.intent
1551
+ });
1552
+ throw error;
1553
+ }
1554
+ }
1555
+ async function runDaemonServiceManagerAction(input) {
1556
+ const startedAtMs = Date.now();
1557
+ try {
1558
+ const result = await input.run();
1559
+ await emitDaemonLifecycleEvent({
1560
+ type: "service_manager.action",
1561
+ result: "completed",
1562
+ metadata: {
1563
+ action: input.action,
1564
+ controller: input.controller,
1565
+ durationMs: Date.now() - startedAtMs,
1566
+ ...input.metadata ?? {}
1567
+ },
1568
+ pathInput: input.pathInput,
1569
+ command: input.command,
1570
+ intent: input.intent
1571
+ });
1572
+ return result;
1573
+ } catch (error) {
1574
+ let errorMetadata = null;
1575
+ try {
1576
+ errorMetadata = input.resolveErrorMetadata?.(error) ?? null;
1577
+ } catch {
1578
+ errorMetadata = null;
1579
+ }
1580
+ await emitDaemonLifecycleEvent({
1581
+ type: "service_manager.action",
1582
+ result: "failed",
1583
+ metadata: {
1584
+ action: input.action,
1585
+ controller: input.controller,
1586
+ durationMs: Date.now() - startedAtMs,
1587
+ errorMessage: toJournalErrorMessage(error),
1588
+ ...errorMetadata ?? {},
1589
+ ...input.metadata ?? {}
1590
+ },
1591
+ pathInput: input.pathInput,
1592
+ command: input.command,
1593
+ intent: input.intent
1594
+ });
1595
+ throw error;
1596
+ }
1597
+ }
1598
+ const DAEMON_LIFECYCLE_ORIGIN_EVENT_TYPES = /* @__PURE__ */ new Set([
1599
+ "daemon.crash",
1600
+ "lifecycle.command.end",
1601
+ "process_stop.action",
1602
+ "runtime_state.takeover",
1603
+ "service_contract.write",
1604
+ "service_manager.action"
1605
+ ]);
1606
+ async function readLatestDaemonLifecycleOriginEvent(input = {}) {
1607
+ return await readLatestDaemonLifecycleEvent({
1608
+ pathInput: input.pathInput,
1609
+ typeFilter: DAEMON_LIFECYCLE_ORIGIN_EVENT_TYPES
1610
+ });
1611
+ }
1612
+ async function readLatestDaemonLifecycleConnectionStateEvent(input = {}) {
1613
+ return await readLatestDaemonLifecycleEvent({
1614
+ pathInput: input.pathInput,
1615
+ typeFilter: /* @__PURE__ */ new Set(["connection.state"])
1616
+ });
1617
+ }
1618
+ async function readLatestDaemonLifecycleEvent(input) {
1619
+ const journalPath = daemonLifecycleJournalPath(input.pathInput);
1620
+ let content;
1621
+ try {
1622
+ content = await readFile(journalPath, "utf8");
1623
+ } catch (error) {
1624
+ if (error.code === "ENOENT") return null;
1625
+ throw error;
1626
+ }
1627
+ const lines = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
1628
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
1629
+ const line = lines[index];
1630
+ if (!line) continue;
1631
+ try {
1632
+ const parsed = JSON.parse(line);
1633
+ if (isDaemonLifecycleEvent(parsed) && input.typeFilter.has(parsed.type)) return parsed;
1634
+ } catch {}
1635
+ }
1636
+ return null;
1637
+ }
1638
+ async function readRecentDaemonLifecycleEvents(input) {
1639
+ if (input.maxEntries <= 0) return [];
1640
+ const journalPath = daemonLifecycleJournalPath(input.pathInput);
1641
+ let content;
1642
+ try {
1643
+ content = await readFile(journalPath, "utf8");
1644
+ } catch (error) {
1645
+ if (error.code === "ENOENT") return [];
1646
+ throw error;
1647
+ }
1648
+ const lines = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
1649
+ const recent = [];
1650
+ for (let index = lines.length - 1; index >= 0; index -= 1) {
1651
+ const line = lines[index];
1652
+ if (!line) continue;
1653
+ try {
1654
+ const parsed = JSON.parse(line);
1655
+ if (isDaemonLifecycleEvent(parsed)) {
1656
+ recent.push(parsed);
1657
+ if (recent.length >= input.maxEntries) break;
1658
+ }
1659
+ } catch {}
1660
+ }
1661
+ return recent.reverse();
1662
+ }
1663
+ async function resolveRecentDaemonSignalStopCause(input = {}) {
1664
+ const nowMs = Date.now();
1665
+ const maxAgeMs = input.maxAgeMs ?? 3e4;
1666
+ const events = await readRecentDaemonLifecycleEvents({
1667
+ maxEntries: 32,
1668
+ pathInput: input.pathInput
1669
+ });
1670
+ for (const event of events.toReversed()) {
1671
+ const eventAtMs = Date.parse(event.timestamp);
1672
+ if (!Number.isFinite(eventAtMs) || nowMs - eventAtMs < 0 || nowMs - eventAtMs > maxAgeMs) continue;
1673
+ if (event.stopCause === "user_stop" || event.stopCause === "controlled_service_update") return event.stopCause;
1674
+ }
1675
+ return "unknown";
1676
+ }
1677
+ function formatDaemonLifecycleOriginSummary(event) {
1678
+ const intent = formatDaemonLifecycleIntent(event.intent);
1679
+ return `${event.result} ${intent} from ${event.command} at ${event.timestamp} (pid ${event.pid})`;
1680
+ }
1681
+ function formatDaemonLifecycleIntent(intent) {
1682
+ if (intent === "unknown") return "OpenMeld Service task";
1683
+ return intent.replaceAll("_", " ");
1684
+ }
1685
+ //#endregion
1686
+ //#region src/local-service/lifecycle/daemon-service-artifact.ts
1687
+ function resolveDaemonServiceArtifact(input) {
1688
+ const installVersion = input.installStatus.installed ? input.installStatus.state.daemonVersion : null;
1689
+ const expectedBundleId = input.serviceContract?.bundleId ?? null;
1690
+ const expectedDaemonVersion = input.expectedVersion;
1691
+ const activeBundleVersion = input.activeBundle?.daemonVersion ?? null;
1692
+ const driftReasonCodes = input.activeBundle ? collectActiveBundleDriftReasonCodes({
1693
+ activeBundle: input.activeBundle,
1694
+ activeBundleEntryPath: input.activeBundleEntryPath,
1695
+ activeBundleSourceAvailable: input.activeBundleSourceAvailable,
1696
+ installedBundleFingerprint: input.installedBundleFingerprint,
1697
+ expectedBundleId,
1698
+ expectedDaemonVersion,
1699
+ pathInput: input.pathInput
1700
+ }) : ["bundle_missing"];
1701
+ const isAligned = driftReasonCodes.length === 0;
1702
+ return {
1703
+ expectedVersion: input.expectedVersion,
1704
+ installVersion,
1705
+ activeBundleVersion,
1706
+ resolvedEntryPath: isAligned ? input.activeBundleEntryPath : null,
1707
+ driftReasonCodes,
1708
+ isAligned
1709
+ };
1710
+ }
1711
+ function collectActiveBundleDriftReasonCodes(input) {
1712
+ const driftReasonCodes = [];
1713
+ if (hasBundleVersionDrift(input)) driftReasonCodes.push("bundle_version_drift");
1714
+ if (hasBundleIdDrift(input)) driftReasonCodes.push("bundle_id_drift");
1715
+ if (!isDaemonBundleSourceAllowedForLane({
1716
+ sourceKind: input.activeBundle.sourceKind,
1717
+ pathInput: input.pathInput
1718
+ })) driftReasonCodes.push("bundle_lane_drift");
1719
+ if (input.activeBundle.bundleFormat === "legacy_linked_v1") {
1720
+ driftReasonCodes.push("bundle_strategy_legacy");
1721
+ if (input.activeBundleSourceAvailable === false) driftReasonCodes.push("bundle_provenance_drift");
1722
+ } else if (hasBundleContentDrift(input)) driftReasonCodes.push("bundle_content_drift");
1723
+ if (!input.activeBundleEntryPath) driftReasonCodes.push("bundle_path_invalid");
1724
+ return driftReasonCodes;
1725
+ }
1726
+ function hasBundleVersionDrift(input) {
1727
+ return input.activeBundle.daemonVersion !== input.expectedDaemonVersion;
1728
+ }
1729
+ function hasBundleIdDrift(input) {
1730
+ return input.expectedBundleId !== null && input.activeBundle.bundleId !== input.expectedBundleId;
1731
+ }
1732
+ function hasBundleContentDrift(input) {
1733
+ return input.installedBundleFingerprint === null || input.activeBundle.sourceDistFingerprint !== input.installedBundleFingerprint;
1734
+ }
1735
+ //#endregion
1736
+ //#region src/local-service/lifecycle/daemon-service-bundle.ts
1737
+ const DAEMON_ACTIVE_BUNDLE_SCHEMA = "openmeld-daemon-active-bundle-v2";
1738
+ const DAEMON_ACTIVE_BUNDLE_LEGACY_SCHEMA = "openmeld-daemon-active-bundle-v1";
1739
+ const DAEMON_CLI_ENTRY_NAMES = ["openmeld-dev.js", "openmeld.js"];
1740
+ const DAEMON_BUNDLE_SOURCE_KIND_WORKSPACE = "workspace";
1741
+ const DAEMON_BUNDLE_SOURCE_KIND_PACKAGE_INSTALL = "package_install";
1742
+ const DAEMON_BUNDLE_SOURCE_KIND_NPX_CACHE = "npx_cache";
1743
+ const DAEMON_BUNDLE_SOURCE_KIND_UNKNOWN = "unknown";
1744
+ const DAEMON_SOURCE_DIST_IGNORED_TOP_LEVEL_DIRS = /* @__PURE__ */ new Set(["binary", "native"]);
1745
+ function daemonServiceActiveBundlePath(pathInput = {}) {
1746
+ return daemonServiceActiveBundleStatePath(pathInput);
1747
+ }
1748
+ function daemonServiceLauncherPath(pathInput = {}) {
1749
+ return daemonServiceStableLauncherPath(pathInput);
1750
+ }
1751
+ function daemonServiceExecutableWrapperPath(pathInput = {}) {
1752
+ return daemonServiceStableExecutableWrapperPath(pathInput);
1753
+ }
1754
+ function daemonServiceBinaryExecutablePath(pathInput = {}) {
1755
+ return daemonServiceStableBinaryExecutablePath(pathInput);
1756
+ }
1757
+ function daemonServiceUpdateWorkerBinaryPath(pathInput = {}) {
1758
+ return daemonServiceUpdateWorkerBinaryExecutablePath(pathInput);
1759
+ }
1760
+ function daemonServiceExecutableWrapperPaths(pathInput = {}) {
1761
+ return daemonServiceExecutableWrapperPaths$1(pathInput);
1762
+ }
1763
+ function daemonServiceRecognizedExecutablePaths(pathInput = {}) {
1764
+ return daemonServiceRecognizedExecutablePaths$1(pathInput);
1765
+ }
1766
+ function daemonServiceLegacyWrapperPath(pathInput = {}) {
1767
+ return daemonServiceLegacyExecutableWrapperPath(pathInput);
1768
+ }
1769
+ function resolveDaemonBundleRootPath(bundleId, pathInput = {}) {
1770
+ return join(daemonRuntimeBundlesPath(pathInput), bundleId);
1771
+ }
1772
+ function isDaemonBundleSourceAllowedForLane(input) {
1773
+ if (input.sourceKind !== DAEMON_BUNDLE_SOURCE_KIND_WORKSPACE) return true;
1774
+ return resolveOpenMeldEnvPreset(input.pathInput) === "dev-local";
1775
+ }
1776
+ async function readDaemonActiveBundleState(pathInput = {}) {
1777
+ const raw = await readFile(daemonServiceActiveBundlePath(pathInput), "utf8").catch((error) => {
1778
+ if (getErrorCode(error) === "ENOENT") return null;
1779
+ throw error;
1780
+ });
1781
+ if (raw === null) return null;
1782
+ try {
1783
+ const parsed = JSON.parse(raw);
1784
+ if (parsed.v === 2 && parsed.schema === DAEMON_ACTIVE_BUNDLE_SCHEMA) {
1785
+ if (typeof parsed.bundleId !== "string" || parsed.bundleId.length === 0 || typeof parsed.daemonVersion !== "string" || parsed.daemonVersion.length === 0 || typeof parsed.entryScriptRelativePath !== "string" || parsed.entryScriptRelativePath.length === 0 || !isDaemonBundleFormat(parsed.bundleFormat) || typeof parsed.sourceEntryScriptPath !== "string" || parsed.sourceEntryScriptPath.length === 0 || typeof parsed.sourcePackageRootPath !== "string" || parsed.sourcePackageRootPath.length === 0 || typeof parsed.sourceDistRootPath !== "string" || parsed.sourceDistRootPath.length === 0 || !isDaemonBundleSourceKind(parsed.sourceKind) || typeof parsed.createdAt !== "string" || parsed.createdAt.length === 0 || typeof parsed.updatedAt !== "string" || parsed.updatedAt.length === 0) return null;
1786
+ return {
1787
+ v: 2,
1788
+ schema: DAEMON_ACTIVE_BUNDLE_SCHEMA,
1789
+ bundleId: parsed.bundleId,
1790
+ daemonVersion: parsed.daemonVersion,
1791
+ entryScriptRelativePath: parsed.entryScriptRelativePath,
1792
+ bundleFormat: parsed.bundleFormat,
1793
+ sourceEntryScriptPath: parsed.sourceEntryScriptPath,
1794
+ sourcePackageRootPath: parsed.sourcePackageRootPath,
1795
+ sourceDistRootPath: parsed.sourceDistRootPath,
1796
+ sourceDistFingerprint: normalizeOptionalText(parsed.sourceDistFingerprint),
1797
+ sourceKind: parsed.sourceKind,
1798
+ createdAt: parsed.createdAt,
1799
+ updatedAt: parsed.updatedAt
1800
+ };
1801
+ }
1802
+ const legacyParsed = parsed;
1803
+ if (legacyParsed.v !== 1 || legacyParsed.schema !== DAEMON_ACTIVE_BUNDLE_LEGACY_SCHEMA || typeof legacyParsed.bundleId !== "string" || legacyParsed.bundleId.length === 0 || typeof legacyParsed.daemonVersion !== "string" || legacyParsed.daemonVersion.length === 0 || typeof legacyParsed.entryScriptRelativePath !== "string" || legacyParsed.entryScriptRelativePath.length === 0 || typeof legacyParsed.sourceDistRootPath !== "string" || legacyParsed.sourceDistRootPath.length === 0 || typeof legacyParsed.createdAt !== "string" || legacyParsed.createdAt.length === 0 || typeof legacyParsed.updatedAt !== "string" || legacyParsed.updatedAt.length === 0) return null;
1804
+ const sourceEntryScriptPath = join(legacyParsed.sourceDistRootPath, basename(legacyParsed.entryScriptRelativePath));
1805
+ const sourcePackageRootPath = dirname(legacyParsed.sourceDistRootPath);
1806
+ return {
1807
+ v: 2,
1808
+ schema: DAEMON_ACTIVE_BUNDLE_SCHEMA,
1809
+ bundleId: legacyParsed.bundleId,
1810
+ daemonVersion: legacyParsed.daemonVersion,
1811
+ entryScriptRelativePath: legacyParsed.entryScriptRelativePath,
1812
+ bundleFormat: "legacy_linked_v1",
1813
+ sourceEntryScriptPath,
1814
+ sourcePackageRootPath,
1815
+ sourceDistRootPath: legacyParsed.sourceDistRootPath,
1816
+ sourceDistFingerprint: null,
1817
+ sourceKind: inferDaemonBundleSourceKind(sourcePackageRootPath),
1818
+ createdAt: legacyParsed.createdAt,
1819
+ updatedAt: legacyParsed.updatedAt
1820
+ };
1821
+ } catch {
1822
+ return null;
1823
+ }
1824
+ }
1825
+ async function resolveAlignedDaemonActiveBundleEntryPath(input = {}) {
1826
+ const [installStatus, serviceContract, state] = await Promise.all([
1827
+ getDaemonStatus(),
1828
+ readDaemonServiceContract().catch(() => null),
1829
+ readDaemonActiveBundleState()
1830
+ ]);
1831
+ const expectedVersion = input.expectedVersion ?? serviceContract?.daemonVersion ?? (installStatus.installed ? installStatus.state.daemonVersion : state?.daemonVersion ?? "unknown");
1832
+ const matchingServiceContract = input.expectedVersion && serviceContract?.daemonVersion !== input.expectedVersion ? null : serviceContract;
1833
+ const activeBundleEntryPath = await resolveDaemonBundleEntryPathFromState(state);
1834
+ const installedBundleFingerprint = activeBundleEntryPath ? await resolveInstalledDaemonBundleFingerprint(state) : null;
1835
+ return resolveDaemonServiceArtifact({
1836
+ expectedVersion,
1837
+ installStatus,
1838
+ serviceContract: matchingServiceContract,
1839
+ activeBundle: state,
1840
+ activeBundleSourceAvailable: state && state.bundleFormat === "legacy_linked_v1" ? await pathExists(state.sourcePackageRootPath).catch(() => null) : null,
1841
+ activeBundleEntryPath,
1842
+ installedBundleFingerprint
1843
+ }).resolvedEntryPath;
1844
+ }
1845
+ async function resolveInstalledDaemonBundleFingerprint(state, pathInput = {}) {
1846
+ if (state?.bundleFormat === "binary_v1") {
1847
+ const entryPath = await resolveDaemonBundleEntryPathFromState(state, pathInput);
1848
+ return entryPath ? await hashDaemonBinaryFile(entryPath) : null;
1849
+ }
1850
+ if (state?.bundleFormat === "self_contained_v1") {
1851
+ const bundleRootPath = resolveDaemonBundleRootPath(state.bundleId, pathInput);
1852
+ const distRootPath = join(bundleRootPath, dirname(state.entryScriptRelativePath));
1853
+ const relativeDistRootPath = relative(bundleRootPath, distRootPath);
1854
+ if (relativeDistRootPath === ".." || relativeDistRootPath.startsWith(`..${sep}`) || isAbsolute(relativeDistRootPath)) return null;
1855
+ return await computeDaemonSourceDistFingerprint(distRootPath);
1856
+ }
1857
+ return null;
1858
+ }
1859
+ async function resolveDaemonBundleEntryPathFromState(state, pathInput = {}) {
1860
+ if (!state) return null;
1861
+ if (state.bundleFormat === "binary_v1") {
1862
+ const stableExecutablePath = daemonServiceBinaryExecutablePath(pathInput);
1863
+ if (await pathExists(stableExecutablePath)) return stableExecutablePath;
1864
+ return await pathExists(state.sourceEntryScriptPath) ? state.sourceEntryScriptPath : null;
1865
+ }
1866
+ const entryPath = join(resolveDaemonBundleRootPath(state.bundleId, pathInput), state.entryScriptRelativePath);
1867
+ return await pathExists(entryPath) ? entryPath : null;
1868
+ }
1869
+ async function prepareDaemonServiceBundle(input) {
1870
+ const preparedBundle = isBinaryDistribution() ? await prepareBinaryDaemonServiceBundle(input) : await prepareNodeDaemonServiceBundle(input);
1871
+ if (input.activate !== false) await activateDaemonServiceBundle(preparedBundle);
1872
+ return preparedBundle;
1873
+ }
1874
+ async function prepareNodeDaemonServiceBundle(input) {
1875
+ const sourceProvenance = await resolveDaemonBundleSourceProvenance(input.cliScriptPath);
1876
+ if (!isDaemonBundleSourceAllowedForLane({ sourceKind: sourceProvenance.sourceKind })) throw new Error("OpenMeld Service cannot use repo-local workspace service files in this lane. Repo-local service files are only allowed through `openmeld-dev`.");
1877
+ const { sourceEntryScriptPath, sourceDistRootPath, sourcePackageRootPath } = sourceProvenance;
1878
+ const sourceDistFingerprint = await computeDaemonSourceDistFingerprint(sourceDistRootPath);
1879
+ const entryScriptRelativePath = basename(sourceEntryScriptPath);
1880
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1881
+ const bundleId = createBundleId(input.daemonVersion);
1882
+ const bundleRootPath = resolveDaemonBundleRootPath(bundleId);
1883
+ const targetDistRootPath = join(bundleRootPath, "dist");
1884
+ await Promise.all([
1885
+ mkdir(daemonRuntimeRootPath(), { recursive: true }),
1886
+ mkdir(daemonRuntimeBundlesPath(), { recursive: true }),
1887
+ mkdir(daemonRuntimeStateRootPath(), { recursive: true }),
1888
+ mkdir(daemonRuntimeServiceManagerPath(), { recursive: true })
1889
+ ]);
1890
+ try {
1891
+ await rm(bundleRootPath, {
1892
+ recursive: true,
1893
+ force: true
1894
+ });
1895
+ await mkdir(bundleRootPath, { recursive: true });
1896
+ await cp(sourceDistRootPath, targetDistRootPath, {
1897
+ recursive: true,
1898
+ force: true,
1899
+ filter: (sourcePath) => isDaemonSourceDistPathIncluded(sourceDistRootPath, sourcePath)
1900
+ });
1901
+ await writeDaemonBundlePackageManifest({
1902
+ bundleRootPath,
1903
+ daemonVersion: input.daemonVersion
1904
+ });
1905
+ await copyDaemonBundleRuntimeDependencies({
1906
+ bundleRootPath,
1907
+ sourcePackageRootPath
1908
+ });
1909
+ } catch (error) {
1910
+ await rm(bundleRootPath, {
1911
+ recursive: true,
1912
+ force: true
1913
+ }).catch(() => void 0);
1914
+ throw error;
1915
+ }
1916
+ return {
1917
+ v: 2,
1918
+ schema: DAEMON_ACTIVE_BUNDLE_SCHEMA,
1919
+ bundleId,
1920
+ daemonVersion: input.daemonVersion,
1921
+ entryScriptRelativePath: join("dist", entryScriptRelativePath),
1922
+ bundleFormat: "self_contained_v1",
1923
+ sourceEntryScriptPath,
1924
+ sourcePackageRootPath,
1925
+ sourceDistRootPath,
1926
+ sourceDistFingerprint,
1927
+ sourceKind: sourceProvenance.sourceKind,
1928
+ createdAt: now,
1929
+ updatedAt: now
1930
+ };
1931
+ }
1932
+ async function prepareBinaryDaemonServiceBundle(input) {
1933
+ const { daemonVersion } = input;
1934
+ const bundledRelease = resolveBundledServiceRelease();
1935
+ const binaryRelease = input.binaryRelease ?? (bundledRelease?.version === daemonVersion ? bundledRelease : void 0);
1936
+ if (daemonVersion !== resolveCliSelfVersion()) {
1937
+ const active = await readDaemonActiveBundleState();
1938
+ if (active?.bundleFormat === "binary_v1" && active.daemonVersion === daemonVersion && active.sourceDistFingerprint && (!binaryRelease || binaryRelease.sha256 === active.sourceDistFingerprint) && await pathExists(active.sourceEntryScriptPath) && await hashDaemonBinaryFile(active.sourceEntryScriptPath) === active.sourceDistFingerprint) return active;
1939
+ }
1940
+ if (binaryRelease) return await prepareSelectedBinaryDaemonServiceBundle({
1941
+ daemonVersion,
1942
+ release: binaryRelease
1943
+ });
1944
+ if (daemonVersion !== resolveCliSelfVersion()) throw new Error(`Cannot prepare OpenMeld Service ${daemonVersion} from CLI ${resolveCliSelfVersion()}. Acquire the selected Service release before preparing the update.`);
1945
+ const outcome = await performManagedInstall();
1946
+ const managedBinaryPath = outcome.managedBinaryPath;
1947
+ if (!await pathExists(managedBinaryPath)) throw new Error(`OpenMeld managed binary is missing at ${managedBinaryPath}; cannot prepare binary OpenMeld Service.`);
1948
+ const managedVersionDir = dirname(managedBinaryPath);
1949
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1950
+ await Promise.all([
1951
+ mkdir(daemonRuntimeRootPath(), { recursive: true }),
1952
+ mkdir(daemonRuntimeStateRootPath(), { recursive: true }),
1953
+ mkdir(daemonRuntimeServiceManagerPath(), { recursive: true })
1954
+ ]);
1955
+ return {
1956
+ v: 2,
1957
+ schema: DAEMON_ACTIVE_BUNDLE_SCHEMA,
1958
+ bundleId: createBundleId(outcome.version),
1959
+ daemonVersion: outcome.version,
1960
+ entryScriptRelativePath: "openmeld",
1961
+ bundleFormat: "binary_v1",
1962
+ sourceEntryScriptPath: managedBinaryPath,
1963
+ sourcePackageRootPath: managedVersionDir,
1964
+ sourceDistRootPath: managedVersionDir,
1965
+ sourceDistFingerprint: await hashDaemonBinaryFile(managedBinaryPath),
1966
+ sourceKind: DAEMON_BUNDLE_SOURCE_KIND_PACKAGE_INSTALL,
1967
+ createdAt: now,
1968
+ updatedAt: now
1969
+ };
1970
+ }
1971
+ async function prepareSelectedBinaryDaemonServiceBundle(input) {
1972
+ if (input.release.version !== input.daemonVersion) throw new Error("The selected Service artifact does not match the update target.");
1973
+ const bundleId = createBundleId(input.daemonVersion);
1974
+ const bundleRootPath = resolveDaemonBundleRootPath(bundleId);
1975
+ const executablePath = join(bundleRootPath, "openmeld");
1976
+ const onDeltaFallback = (error) => {
1977
+ console.warn("[openmeld.service.artifact_delta_fallback]", error.message);
1978
+ };
1979
+ const plan = await resolveCliBinaryUpdatePlan({
1980
+ baseBinaryPath: process$1.execPath,
1981
+ currentVersion: resolveCliSelfVersion(),
1982
+ onDeltaFallback,
1983
+ release: input.release
1984
+ });
1985
+ const bytes = await downloadCliBinaryUpdateArtifact({
1986
+ downloadTimeoutMs: 6e4,
1987
+ fetchImpl: fetch,
1988
+ onDeltaFallback,
1989
+ plan,
1990
+ release: input.release
1991
+ });
1992
+ await mkdir(bundleRootPath, { recursive: true });
1993
+ try {
1994
+ await writeFile(executablePath, bytes, { mode: 493 });
1995
+ await verifyCliBinaryCodeSignature({
1996
+ artifactPath: executablePath,
1997
+ release: input.release,
1998
+ runCommand: async (command, args) => {
1999
+ const result = await promisify(execFile)(command, args, { encoding: "utf8" });
2000
+ return {
2001
+ code: 0,
2002
+ stdout: result.stdout,
2003
+ stderr: result.stderr
2004
+ };
2005
+ }
2006
+ });
2007
+ } catch (error) {
2008
+ await rm(bundleRootPath, {
2009
+ recursive: true,
2010
+ force: true
2011
+ });
2012
+ throw error;
2013
+ }
2014
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2015
+ return {
2016
+ v: 2,
2017
+ schema: DAEMON_ACTIVE_BUNDLE_SCHEMA,
2018
+ bundleId,
2019
+ daemonVersion: input.daemonVersion,
2020
+ entryScriptRelativePath: "openmeld",
2021
+ bundleFormat: "binary_v1",
2022
+ sourceEntryScriptPath: executablePath,
2023
+ sourcePackageRootPath: bundleRootPath,
2024
+ sourceDistRootPath: bundleRootPath,
2025
+ sourceDistFingerprint: input.release.sha256.toLowerCase(),
2026
+ sourceKind: DAEMON_BUNDLE_SOURCE_KIND_PACKAGE_INSTALL,
2027
+ createdAt: now,
2028
+ updatedAt: now
2029
+ };
2030
+ }
2031
+ async function activateDaemonServiceBundle(preparedBundle) {
2032
+ await mkdir(daemonRuntimeStateRootPath(), { recursive: true });
2033
+ await writeFile(daemonServiceActiveBundlePath(), `${JSON.stringify(preparedBundle, null, 2)}\n`, {
2034
+ encoding: "utf8",
2035
+ mode: 384
2036
+ });
2037
+ if (preparedBundle.bundleFormat !== "binary_v1") await ensureDaemonServiceManagerExecutables();
2038
+ }
2039
+ async function discardPreparedDaemonServiceBundle(preparedBundle) {
2040
+ if (preparedBundle.bundleFormat === "legacy_linked_v1") return;
2041
+ if ((await readDaemonActiveBundleState())?.bundleId === preparedBundle.bundleId) return;
2042
+ await rm(resolveDaemonBundleRootPath(preparedBundle.bundleId), {
2043
+ recursive: true,
2044
+ force: true
2045
+ });
2046
+ }
2047
+ async function hashDaemonBinaryFile(filePath) {
2048
+ const hash = createHash("sha256");
2049
+ hash.update(await readFile(filePath));
2050
+ return hash.digest("hex");
2051
+ }
2052
+ async function runAuditedServiceManagerCarrierMutation(input) {
2053
+ const pathInput = input.pathInput ?? {};
2054
+ const metadata = {
2055
+ distribution: input.distribution ?? resolveOpenMeldDistribution(),
2056
+ executable: process$1.execPath,
2057
+ operation: input.operation,
2058
+ preset: resolveOpenMeldEnvPreset(pathInput),
2059
+ targetPath: input.targetPath,
2060
+ targetCategory: classifyDiagnosticPath(input.targetPath),
2061
+ actorPid: process$1.pid,
2062
+ parentPid: process$1.ppid
2063
+ };
2064
+ await emitDaemonLifecycleEvent({
2065
+ command: "openmeld service carrier mutation",
2066
+ intent: "status_cleanup",
2067
+ metadata,
2068
+ pathInput,
2069
+ result: "attempted",
2070
+ type: "service_manager.registration_reconcile"
2071
+ });
2072
+ try {
2073
+ const result = await input.run();
2074
+ await emitDaemonLifecycleEvent({
2075
+ command: "openmeld service carrier mutation",
2076
+ intent: "status_cleanup",
2077
+ metadata,
2078
+ pathInput,
2079
+ result: "completed",
2080
+ type: "service_manager.registration_reconcile"
2081
+ });
2082
+ return result;
2083
+ } catch (error) {
2084
+ await emitDaemonLifecycleEvent({
2085
+ command: "openmeld service carrier mutation",
2086
+ intent: "status_cleanup",
2087
+ metadata: {
2088
+ ...metadata,
2089
+ errorMessage: error instanceof Error ? error.message : String(error),
2090
+ operationFailure: collectLocalOperationFailure(error)
2091
+ },
2092
+ pathInput,
2093
+ result: "failed",
2094
+ type: "service_manager.registration_reconcile"
2095
+ });
2096
+ throw error;
2097
+ }
2098
+ }
2099
+ async function ensureDaemonServiceStableBinaryExecutable(pathInput = {}) {
2100
+ const activeBundle = await readDaemonActiveBundleState();
2101
+ if (activeBundle?.bundleFormat !== "binary_v1") throw new Error("OpenMeld cannot prepare the stable macOS Service executable without an active binary bundle.");
2102
+ return await ensureVerifiedBinaryCarrier({
2103
+ bundle: activeBundle,
2104
+ operationName: "stable_binary",
2105
+ pathInput,
2106
+ targetPath: daemonServiceBinaryExecutablePath(pathInput)
2107
+ });
2108
+ }
2109
+ async function ensureDaemonServiceUpdateWorkerBinaryExecutable(preparedBundle, pathInput = {}) {
2110
+ if (preparedBundle.bundleFormat !== "binary_v1") throw new Error("OpenMeld cannot prepare the update worker binary without a binary Service bundle.");
2111
+ return await ensureVerifiedBinaryCarrier({
2112
+ bundle: preparedBundle,
2113
+ operationName: "update_worker_binary",
2114
+ pathInput,
2115
+ targetPath: daemonServiceUpdateWorkerBinaryPath(pathInput)
2116
+ });
2117
+ }
2118
+ async function clearDaemonServiceUpdateWorkerBinaryExecutable(pathInput = {}) {
2119
+ const targetPath = daemonServiceUpdateWorkerBinaryPath(pathInput);
2120
+ await runAuditedServiceManagerCarrierMutation({
2121
+ distribution: "binary",
2122
+ operation: "remove_update_worker_binary",
2123
+ pathInput,
2124
+ targetPath,
2125
+ run: async () => await rm(targetPath, { force: true })
2126
+ });
2127
+ }
2128
+ async function ensureVerifiedBinaryCarrier(input) {
2129
+ const sourcePath = input.bundle.sourceEntryScriptPath;
2130
+ const expectedFingerprint = input.bundle.sourceDistFingerprint ?? await hashDaemonBinaryFile(sourcePath);
2131
+ const stableExecutablePath = input.targetPath;
2132
+ const stableExecutableStat = await lstat(stableExecutablePath).catch(() => null);
2133
+ if (stableExecutableStat?.isFile() === true && !stableExecutableStat.isSymbolicLink() && await hashDaemonBinaryFile(stableExecutablePath).catch(() => null) === expectedFingerprint) {
2134
+ await runAuditedServiceManagerCarrierMutation({
2135
+ distribution: "binary",
2136
+ operation: `refresh_${input.operationName}_permissions`,
2137
+ pathInput: input.pathInput,
2138
+ targetPath: stableExecutablePath,
2139
+ run: async () => await chmod(stableExecutablePath, 448)
2140
+ });
2141
+ return stableExecutablePath;
2142
+ }
2143
+ await mkdir(dirname(stableExecutablePath), { recursive: true });
2144
+ const preparedPath = `${stableExecutablePath}.next-${String(process$1.pid)}`;
2145
+ await runAuditedServiceManagerCarrierMutation({
2146
+ distribution: "binary",
2147
+ operation: `clear_prepared_${input.operationName}`,
2148
+ pathInput: input.pathInput,
2149
+ targetPath: preparedPath,
2150
+ run: async () => await rm(preparedPath, { force: true })
2151
+ });
2152
+ try {
2153
+ await runAuditedServiceManagerCarrierMutation({
2154
+ distribution: "binary",
2155
+ operation: `prepare_${input.operationName}`,
2156
+ pathInput: input.pathInput,
2157
+ targetPath: preparedPath,
2158
+ run: async () => {
2159
+ await copyFile(sourcePath, preparedPath);
2160
+ await chmod(preparedPath, 448);
2161
+ }
2162
+ });
2163
+ if (await hashDaemonBinaryFile(preparedPath) !== expectedFingerprint) throw new Error("OpenMeld could not verify the prepared Service carrier executable.");
2164
+ await runAuditedServiceManagerCarrierMutation({
2165
+ distribution: "binary",
2166
+ operation: `replace_${input.operationName}`,
2167
+ pathInput: input.pathInput,
2168
+ targetPath: stableExecutablePath,
2169
+ run: async () => await rename(preparedPath, stableExecutablePath)
2170
+ });
2171
+ return stableExecutablePath;
2172
+ } finally {
2173
+ await runAuditedServiceManagerCarrierMutation({
2174
+ distribution: "binary",
2175
+ operation: `clear_prepared_${input.operationName}`,
2176
+ pathInput: input.pathInput,
2177
+ targetPath: preparedPath,
2178
+ run: async () => await rm(preparedPath, { force: true })
2179
+ }).catch(() => void 0);
2180
+ }
2181
+ }
2182
+ async function verifyDaemonActiveBundleIntegrity(activeBundle) {
2183
+ const expectedFingerprint = activeBundle.sourceDistFingerprint?.trim();
2184
+ if (!expectedFingerprint || activeBundle.bundleFormat === "legacy_linked_v1") return false;
2185
+ if (!await resolveDaemonBundleEntryPathFromState(activeBundle)) return false;
2186
+ return await resolveInstalledDaemonBundleFingerprint(activeBundle) === expectedFingerprint;
2187
+ }
2188
+ async function writeDaemonBundlePackageManifest(input) {
2189
+ await writeFile(join(input.bundleRootPath, "package.json"), `${JSON.stringify({
2190
+ name: "openmeld-daemon-service-bundle",
2191
+ private: true,
2192
+ type: "module",
2193
+ version: input.daemonVersion
2194
+ }, null, 2)}\n`, {
2195
+ encoding: "utf8",
2196
+ mode: 384
2197
+ });
2198
+ }
2199
+ async function copyDaemonBundleRuntimeDependencies(input) {
2200
+ const runtimeDependencies = await collectDaemonBundleRuntimeDependencyClosure({ sourcePackageRootPath: input.sourcePackageRootPath });
2201
+ const targetNodeModulesPath = join(input.bundleRootPath, "node_modules");
2202
+ await rm(targetNodeModulesPath, {
2203
+ recursive: true,
2204
+ force: true
2205
+ });
2206
+ await mkdir(targetNodeModulesPath, { recursive: true });
2207
+ for (const runtimeDependency of runtimeDependencies) await copyDaemonBundleDependencyDirectory({
2208
+ dependencyName: runtimeDependency.dependencyName,
2209
+ sourceDependencyPath: runtimeDependency.packageRootPath,
2210
+ targetNodeModulesPath
2211
+ });
2212
+ }
2213
+ async function copyDaemonBundleDependencyDirectory(input) {
2214
+ if (!await pathExists(input.sourceDependencyPath)) throw new Error(`OpenMeld could not copy runtime dependency ${input.dependencyName} for background service bundling from ${input.sourceDependencyPath}. Run \`pnpm install\` and retry.`);
2215
+ const targetDependencyPath = join(input.targetNodeModulesPath, ...input.dependencyName.split("/"));
2216
+ await mkdir(dirname(targetDependencyPath), { recursive: true });
2217
+ await cp(input.sourceDependencyPath, targetDependencyPath, {
2218
+ recursive: true,
2219
+ force: true,
2220
+ dereference: true,
2221
+ preserveTimestamps: true
2222
+ });
2223
+ }
2224
+ async function writeDaemonServiceLauncher(pathInput = {}) {
2225
+ await mkdir(daemonRuntimeServiceManagerPath(pathInput), { recursive: true });
2226
+ const targetPath = daemonServiceLauncherPath(pathInput);
2227
+ await runAuditedServiceManagerCarrierMutation({
2228
+ distribution: "npm",
2229
+ operation: "write_launcher",
2230
+ pathInput,
2231
+ targetPath,
2232
+ run: async () => await writeFile(targetPath, `${buildDaemonServiceLauncherSource(pathInput)}\n`, {
2233
+ encoding: "utf8",
2234
+ mode: 448
2235
+ })
2236
+ });
2237
+ }
2238
+ async function writeDaemonServiceExecutableWrapper(pathInput = {}) {
2239
+ await mkdir(daemonRuntimeServiceManagerPath(pathInput), { recursive: true });
2240
+ await Promise.all(daemonServiceExecutableWrapperPaths(pathInput).map(async (wrapperPath) => {
2241
+ await runAuditedServiceManagerCarrierMutation({
2242
+ distribution: "npm",
2243
+ operation: "write_executable_wrapper",
2244
+ pathInput,
2245
+ targetPath: wrapperPath,
2246
+ run: async () => {
2247
+ await writeFile(wrapperPath, `${buildDaemonServiceExecutableWrapperSource(pathInput)}\n`, {
2248
+ encoding: "utf8",
2249
+ mode: 448
2250
+ });
2251
+ await chmod(wrapperPath, 448);
2252
+ }
2253
+ });
2254
+ }));
2255
+ }
2256
+ async function ensureDaemonServiceManagerExecutables(pathInput = {}) {
2257
+ await writeDaemonServiceLauncher(pathInput);
2258
+ await writeDaemonServiceExecutableWrapper(pathInput);
2259
+ }
2260
+ async function restoreDaemonActiveBundleStateSnapshot(snapshot, pathInput = {}) {
2261
+ if (!snapshot) {
2262
+ await rm(daemonServiceActiveBundlePath(pathInput), { force: true });
2263
+ return;
2264
+ }
2265
+ await mkdir(daemonRuntimeStateRootPath(pathInput), { recursive: true });
2266
+ await writeFile(daemonServiceActiveBundlePath(pathInput), `${JSON.stringify(snapshot, null, 2)}\n`, {
2267
+ encoding: "utf8",
2268
+ mode: 384
2269
+ });
2270
+ }
2271
+ async function cleanupInactiveDaemonServiceBundles(input = {}) {
2272
+ const [active, serviceContract, runtimeLease, registeredWorkerBundleIds, pendingUpdate] = await Promise.all([
2273
+ readDaemonActiveBundleState(),
2274
+ readDaemonServiceContract().catch(() => null),
2275
+ readDaemonRuntimeLease().catch(() => null),
2276
+ readDaemonServiceUpdateWorkerProtectedBundleIds(),
2277
+ readPendingDaemonServiceUpdate()
2278
+ ]);
2279
+ const retain = /* @__PURE__ */ new Set([
2280
+ ...active ? [active.bundleId] : [],
2281
+ ...serviceContract?.bundleId ? [serviceContract.bundleId] : [],
2282
+ ...runtimeLease?.bundleId ? [runtimeLease.bundleId] : [],
2283
+ ...registeredWorkerBundleIds,
2284
+ ...pendingUpdate?.preparedBundle.bundleFormat === "self_contained_v1" ? [pendingUpdate.preparedBundle.bundleId] : [],
2285
+ ...input.retainBundleIds ?? []
2286
+ ]);
2287
+ const bundleEntries = await readDirectoryNames(daemonRuntimeBundlesPath());
2288
+ await Promise.all(bundleEntries.filter((bundleId) => !retain.has(bundleId)).map(async (bundleId) => {
2289
+ await rm(resolveDaemonBundleRootPath(bundleId), {
2290
+ recursive: true,
2291
+ force: true
2292
+ });
2293
+ }));
2294
+ }
2295
+ async function resolveDaemonBundleSourceProvenance(explicitPath) {
2296
+ const sourceEntryScriptPath = await resolveCliScriptPath(explicitPath);
2297
+ const sourceDistRootPath = dirname(sourceEntryScriptPath);
2298
+ const sourcePackageRootPath = dirname(sourceDistRootPath);
2299
+ return {
2300
+ sourceEntryScriptPath,
2301
+ sourceDistRootPath,
2302
+ sourcePackageRootPath,
2303
+ sourceKind: inferDaemonBundleSourceKind(sourcePackageRootPath)
2304
+ };
2305
+ }
2306
+ async function resolveCliScriptPath(explicitPath) {
2307
+ const rawPath = explicitPath ?? process$1.argv[1];
2308
+ if (!rawPath) throw new Error("Cannot determine CLI script path for OpenMeld background service bundle.");
2309
+ const resolvedPath = await realpath(rawPath).catch(async () => {
2310
+ const fallbackPath = await resolvePreferredCliScriptPath(rawPath);
2311
+ if (fallbackPath) return fallbackPath;
2312
+ throw new Error(`OpenMeld could not resolve a CLI dist entry for service bundling from ${rawPath}.`);
2313
+ });
2314
+ const preferredPath = await resolvePreferredCliScriptPath(resolvedPath);
2315
+ if (preferredPath) return preferredPath;
2316
+ throw new Error(`OpenMeld could not find a supported CLI dist entry for service bundling from ${resolvedPath}.`);
2317
+ }
2318
+ function createBundleId(version) {
2319
+ return `${version.replace(/[^a-zA-Z0-9._-]+/g, "_")}-${Date.now()}`;
2320
+ }
2321
+ async function computeDaemonSourceDistFingerprint(sourceDistRootPath) {
2322
+ const filePaths = await listDaemonSourceDistFiles(sourceDistRootPath);
2323
+ const hash = createHash("sha256");
2324
+ for (const filePath of filePaths) {
2325
+ const relativePath = relative(sourceDistRootPath, filePath).replaceAll("\\", "/");
2326
+ hash.update(relativePath, "utf8");
2327
+ hash.update("\0", "utf8");
2328
+ hash.update(await readFile(filePath));
2329
+ hash.update("\0", "utf8");
2330
+ }
2331
+ return hash.digest("hex");
2332
+ }
2333
+ async function listDaemonSourceDistFiles(path) {
2334
+ return await listIncludedDaemonSourceDistFiles(path, path);
2335
+ }
2336
+ async function listIncludedDaemonSourceDistFiles(sourceDistRootPath, currentPath) {
2337
+ const entries = await readdir(currentPath, { withFileTypes: true });
2338
+ const filePaths = [];
2339
+ for (const entry of entries) {
2340
+ const entryPath = join(currentPath, entry.name);
2341
+ if (!isDaemonSourceDistPathIncluded(sourceDistRootPath, entryPath)) continue;
2342
+ if (entry.isDirectory()) {
2343
+ filePaths.push(...await listIncludedDaemonSourceDistFiles(sourceDistRootPath, entryPath));
2344
+ continue;
2345
+ }
2346
+ if (entry.isFile()) filePaths.push(entryPath);
2347
+ }
2348
+ return filePaths.sort((left, right) => {
2349
+ if (left === right) return 0;
2350
+ return left < right ? -1 : 1;
2351
+ });
2352
+ }
2353
+ function isDaemonSourceDistPathIncluded(sourceDistRootPath, candidatePath) {
2354
+ const relativePath = relative(sourceDistRootPath, candidatePath).replaceAll("\\", "/");
2355
+ if (!relativePath || relativePath.startsWith("..")) return true;
2356
+ const topLevelPathSegment = relativePath.split("/")[0] ?? "";
2357
+ return !DAEMON_SOURCE_DIST_IGNORED_TOP_LEVEL_DIRS.has(topLevelPathSegment);
2358
+ }
2359
+ async function collectDaemonBundleRuntimeDependencyClosure(input) {
2360
+ const packageManifestPath = join(input.sourcePackageRootPath, "package.json");
2361
+ const packageManifestRaw = await readFile(packageManifestPath, "utf8").catch((error) => {
2362
+ if (getErrorCode(error) === "ENOENT") throw new Error(`OpenMeld could not find the CLI package manifest for background service bundling at ${packageManifestPath}.`);
2363
+ throw error;
2364
+ });
2365
+ const packageManifest = JSON.parse(packageManifestRaw);
2366
+ const resolvedDependencies = /* @__PURE__ */ new Map();
2367
+ const queue = [...Object.keys(packageManifest.dependencies ?? {}).map((dependencyName) => ({
2368
+ dependencyName,
2369
+ required: true,
2370
+ resolverPackageRootPath: input.sourcePackageRootPath
2371
+ })), ...Object.keys(packageManifest.optionalDependencies ?? {}).map((dependencyName) => ({
2372
+ dependencyName,
2373
+ required: false,
2374
+ resolverPackageRootPath: input.sourcePackageRootPath
2375
+ }))];
2376
+ while (queue.length > 0) {
2377
+ const nextDependency = queue.shift();
2378
+ if (!nextDependency) continue;
2379
+ if (isTypeOnlyDependencyName(nextDependency.dependencyName)) continue;
2380
+ if (resolvedDependencies.has(nextDependency.dependencyName)) continue;
2381
+ const dependencyManifest = await readDaemonBundleDependencyManifest({
2382
+ dependencyName: nextDependency.dependencyName,
2383
+ required: nextDependency.required,
2384
+ resolverPackageRootPath: nextDependency.resolverPackageRootPath
2385
+ });
2386
+ if (!dependencyManifest) continue;
2387
+ resolvedDependencies.set(nextDependency.dependencyName, dependencyManifest.packageRootPath);
2388
+ const nestedRequiredDependencies = Object.keys(dependencyManifest.dependencies ?? {});
2389
+ const nestedOptionalDependencies = Object.keys(dependencyManifest.optionalDependencies ?? {});
2390
+ const nestedPeerDependencies = Object.keys(dependencyManifest.peerDependencies ?? {});
2391
+ for (const dependencyName of nestedRequiredDependencies) queue.push({
2392
+ dependencyName,
2393
+ required: true,
2394
+ resolverPackageRootPath: dependencyManifest.packageRootPath
2395
+ });
2396
+ for (const dependencyName of nestedOptionalDependencies) queue.push({
2397
+ dependencyName,
2398
+ required: false,
2399
+ resolverPackageRootPath: dependencyManifest.packageRootPath
2400
+ });
2401
+ for (const dependencyName of nestedPeerDependencies) queue.push({
2402
+ dependencyName,
2403
+ required: false,
2404
+ resolverPackageRootPath: dependencyManifest.packageRootPath
2405
+ });
2406
+ }
2407
+ return [...resolvedDependencies.entries()].map(([dependencyName, packageRootPath]) => ({
2408
+ dependencyName,
2409
+ packageRootPath
2410
+ })).sort((left, right) => left.dependencyName.localeCompare(right.dependencyName));
2411
+ }
2412
+ function isTypeOnlyDependencyName(dependencyName) {
2413
+ return dependencyName.startsWith("@types/");
2414
+ }
2415
+ async function readDaemonBundleDependencyManifest(input) {
2416
+ const dependencyPackageRootPath = await resolveDaemonDependencyPackageRoot({
2417
+ dependencyName: input.dependencyName,
2418
+ resolverPackageRootPath: input.resolverPackageRootPath,
2419
+ required: input.required
2420
+ });
2421
+ if (!dependencyPackageRootPath) return null;
2422
+ const dependencyManifestPath = join(dependencyPackageRootPath, "package.json");
2423
+ const dependencyManifestRaw = await readFile(dependencyManifestPath, "utf8").catch((error) => {
2424
+ if (getErrorCode(error) === "ENOENT") {
2425
+ if (!input.required) return null;
2426
+ throw new Error(`OpenMeld could not find runtime dependency ${input.dependencyName} for background service bundling at ${dependencyManifestPath}. Run \`pnpm install\` and retry.`);
2427
+ }
2428
+ throw error;
2429
+ });
2430
+ if (dependencyManifestRaw === null) return null;
2431
+ return {
2432
+ packageRootPath: dependencyPackageRootPath,
2433
+ ...JSON.parse(dependencyManifestRaw)
2434
+ };
2435
+ }
2436
+ async function resolveDaemonDependencyPackageRoot(input) {
2437
+ const resolver = createRequire(join(input.resolverPackageRootPath, "package.json"));
2438
+ const dependencyPackageRootPath = await resolveDaemonDependencyPackageRootFromManifest({
2439
+ dependencyName: input.dependencyName,
2440
+ resolver
2441
+ });
2442
+ if (dependencyPackageRootPath) return dependencyPackageRootPath;
2443
+ try {
2444
+ return await findDaemonDependencyPackageRoot(await realpath(resolver.resolve(input.dependencyName)));
2445
+ } catch (error) {
2446
+ if (isPackageEntryResolutionError(error)) {
2447
+ const dependencyPackageRootPath = await findDaemonDependencyPackageRootFromResolutionPaths({
2448
+ dependencyName: input.dependencyName,
2449
+ resolver
2450
+ });
2451
+ if (dependencyPackageRootPath) return dependencyPackageRootPath;
2452
+ if (!input.required) return null;
2453
+ throw new Error(`OpenMeld could not find runtime dependency ${input.dependencyName} for background service bundling from ${input.resolverPackageRootPath}. Run \`pnpm install\` and retry.`);
2454
+ }
2455
+ throw error;
2456
+ }
2457
+ }
2458
+ async function resolveDaemonDependencyPackageRootFromManifest(input) {
2459
+ try {
2460
+ return await findDaemonDependencyPackageRootFromManifestPath({
2461
+ dependencyManifestPath: await realpath(input.resolver.resolve(`${input.dependencyName}/package.json`)),
2462
+ dependencyName: input.dependencyName
2463
+ });
2464
+ } catch (error) {
2465
+ if (isPackageEntryResolutionError(error)) return null;
2466
+ throw error;
2467
+ }
2468
+ }
2469
+ async function findDaemonDependencyPackageRootFromManifestPath(input) {
2470
+ let currentPath = dirname(input.dependencyManifestPath);
2471
+ while (true) {
2472
+ const packageManifestRaw = await readFile(join(currentPath, "package.json"), "utf8").catch((error) => {
2473
+ if (getErrorCode(error) === "ENOENT") return null;
2474
+ throw error;
2475
+ });
2476
+ if (packageManifestRaw !== null) {
2477
+ if (JSON.parse(packageManifestRaw).name === input.dependencyName) return currentPath;
2478
+ }
2479
+ const parentPath = dirname(currentPath);
2480
+ if (parentPath === currentPath) return null;
2481
+ currentPath = parentPath;
2482
+ }
2483
+ }
2484
+ async function findDaemonDependencyPackageRootFromResolutionPaths(input) {
2485
+ const resolutionPaths = input.resolver.resolve.paths(input.dependencyName);
2486
+ if (!resolutionPaths) return null;
2487
+ for (const nodeModulesPath of resolutionPaths) {
2488
+ const candidatePackageRootPath = join(nodeModulesPath, ...input.dependencyName.split("/"));
2489
+ if (await pathExists(join(candidatePackageRootPath, "package.json"))) return await realpath(candidatePackageRootPath);
2490
+ }
2491
+ return null;
2492
+ }
2493
+ async function findDaemonDependencyPackageRoot(resolvedEntryPath) {
2494
+ let currentPath = dirname(resolvedEntryPath);
2495
+ while (true) {
2496
+ if (await pathExists(join(currentPath, "package.json"))) return currentPath;
2497
+ const parentPath = dirname(currentPath);
2498
+ if (parentPath === currentPath) break;
2499
+ currentPath = parentPath;
2500
+ }
2501
+ throw new Error(`OpenMeld could not determine the package root for background service dependency entry ${resolvedEntryPath}.`);
2502
+ }
2503
+ function buildDaemonServiceLauncherSource(pathInput = {}) {
2504
+ return `import { access, readFile, readdir, stat, writeFile } from "node:fs/promises";
2505
+ import { join } from "node:path";
2506
+ import process from "node:process";
2507
+ import { spawn } from "node:child_process";
2508
+
2509
+ const ACTIVE_BUNDLE_PATH = ${JSON.stringify(daemonServiceActiveBundlePath(pathInput))};
2510
+ const INSTALL_STATE_PATH = ${JSON.stringify(daemonStatePath(pathInput))};
2511
+ const BUNDLE_ROOT_PATH = ${JSON.stringify(daemonRuntimeBundlesPath(pathInput))};
2512
+ const ALLOW_WORKSPACE_BUNDLE_SOURCE = ${JSON.stringify(resolveOpenMeldEnvPreset(pathInput) === "dev-local")};
2513
+
2514
+ const ACTIVE_BUNDLE_SCHEMA = "openmeld-daemon-active-bundle-v2";
2515
+ const ACTIVE_BUNDLE_LEGACY_SCHEMA = "openmeld-daemon-active-bundle-v1";
2516
+ const INSTALL_STATE_SCHEMA = "openmeld-daemon-install-v1";
2517
+
2518
+ async function readJsonFile(path) {
2519
+ try {
2520
+ return JSON.parse(await readFile(path, "utf8"));
2521
+ } catch (error) {
2522
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
2523
+ return null;
2524
+ }
2525
+ throw error;
2526
+ }
2527
+ }
2528
+
2529
+ async function pathExists(path) {
2530
+ try {
2531
+ await access(path);
2532
+ return true;
2533
+ } catch (error) {
2534
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
2535
+ return false;
2536
+ }
2537
+ throw error;
2538
+ }
2539
+ }
2540
+
2541
+ function normalizeInstallState(parsed) {
2542
+ if (!parsed || parsed.schema !== INSTALL_STATE_SCHEMA || typeof parsed.daemonVersion !== "string" || parsed.daemonVersion.length === 0) {
2543
+ return null;
2544
+ }
2545
+ return {
2546
+ daemonVersion: parsed.daemonVersion,
2547
+ };
2548
+ }
2549
+
2550
+ function normalizeBundleState(parsed) {
2551
+ if (
2552
+ parsed &&
2553
+ parsed.v === 2 &&
2554
+ parsed.schema === ACTIVE_BUNDLE_SCHEMA &&
2555
+ typeof parsed.bundleId === "string" &&
2556
+ parsed.bundleId.length > 0 &&
2557
+ typeof parsed.daemonVersion === "string" &&
2558
+ parsed.daemonVersion.length > 0 &&
2559
+ typeof parsed.entryScriptRelativePath === "string" &&
2560
+ parsed.entryScriptRelativePath.length > 0 &&
2561
+ (parsed.bundleFormat === "self_contained_v1" || parsed.bundleFormat === "legacy_linked_v1")
2562
+ ) {
2563
+ return parsed;
2564
+ }
2565
+ if (
2566
+ parsed &&
2567
+ parsed.v === 1 &&
2568
+ parsed.schema === ACTIVE_BUNDLE_LEGACY_SCHEMA &&
2569
+ typeof parsed.bundleId === "string" &&
2570
+ parsed.bundleId.length > 0 &&
2571
+ typeof parsed.daemonVersion === "string" &&
2572
+ parsed.daemonVersion.length > 0 &&
2573
+ typeof parsed.entryScriptRelativePath === "string" &&
2574
+ parsed.entryScriptRelativePath.length > 0
2575
+ ) {
2576
+ return {
2577
+ ...parsed,
2578
+ bundleFormat: "legacy_linked_v1",
2579
+ };
2580
+ }
2581
+ return null;
2582
+ }
2583
+
2584
+ function normalizeBundlePackageManifest(parsed) {
2585
+ if (!parsed || typeof parsed.version !== "string" || parsed.version.length === 0) {
2586
+ return null;
2587
+ }
2588
+ return {
2589
+ version: parsed.version,
2590
+ };
2591
+ }
2592
+
2593
+ function uniqueNonEmptyStrings(values) {
2594
+ return [...new Set(values.filter((value) => typeof value === "string" && value.length > 0))];
2595
+ }
2596
+
2597
+ async function findFallbackSelfContainedBundle(input) {
2598
+ const directories = await readdir(BUNDLE_ROOT_PATH, { withFileTypes: true }).catch((error) => {
2599
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
2600
+ return [];
2601
+ }
2602
+ throw error;
2603
+ });
2604
+ const entryScriptRelativePaths = uniqueNonEmptyStrings([
2605
+ input.preferredEntryScriptRelativePath,
2606
+ "dist/openmeld.js",
2607
+ "dist/openmeld-dev.js",
2608
+ ]);
2609
+ const candidates = [];
2610
+ for (const directory of directories) {
2611
+ if (!directory.isDirectory()) {
2612
+ continue;
2613
+ }
2614
+ const bundleId = directory.name;
2615
+ const bundlePath = join(BUNDLE_ROOT_PATH, bundleId);
2616
+ const manifest = normalizeBundlePackageManifest(
2617
+ await readJsonFile(join(bundlePath, "package.json"))
2618
+ );
2619
+ if (manifest?.version !== input.installState.daemonVersion) {
2620
+ continue;
2621
+ }
2622
+ for (const entryScriptRelativePath of entryScriptRelativePaths) {
2623
+ const entryPath = join(bundlePath, entryScriptRelativePath);
2624
+ if (!(await pathExists(entryPath))) {
2625
+ continue;
2626
+ }
2627
+ const entryStat = await stat(entryPath).catch(() => null);
2628
+ candidates.push({
2629
+ bundleId,
2630
+ entryPath,
2631
+ entryScriptRelativePath,
2632
+ mtimeMs: entryStat?.mtimeMs ?? 0,
2633
+ });
2634
+ break;
2635
+ }
2636
+ }
2637
+ candidates.sort((a, b) => {
2638
+ if (b.mtimeMs !== a.mtimeMs) {
2639
+ return b.mtimeMs - a.mtimeMs;
2640
+ }
2641
+ return b.bundleId.localeCompare(a.bundleId);
2642
+ });
2643
+ return candidates[0] ?? null;
2644
+ }
2645
+
2646
+ async function persistFallbackActiveBundleState(input) {
2647
+ const now = new Date().toISOString();
2648
+ const bundleRootPath = join(BUNDLE_ROOT_PATH, input.bundleId);
2649
+ const nextState = {
2650
+ v: 2,
2651
+ schema: ACTIVE_BUNDLE_SCHEMA,
2652
+ bundleId: input.bundleId,
2653
+ daemonVersion: input.installState.daemonVersion,
2654
+ entryScriptRelativePath: input.entryScriptRelativePath,
2655
+ bundleFormat: "self_contained_v1",
2656
+ sourceEntryScriptPath: input.entryPath,
2657
+ sourcePackageRootPath: bundleRootPath,
2658
+ sourceDistRootPath: join(bundleRootPath, "dist"),
2659
+ sourceDistFingerprint: null,
2660
+ sourceKind: "package_install",
2661
+ createdAt: input.previousBundleState?.createdAt ?? now,
2662
+ updatedAt: now,
2663
+ };
2664
+ await writeFile(ACTIVE_BUNDLE_PATH, \`\${JSON.stringify(nextState, null, 2)}\\n\`, {
2665
+ encoding: "utf8",
2666
+ mode: 0o600,
2667
+ }).catch((error) => {
2668
+ console.error(\`OpenMeld Service launcher recovered a matching bundle but could not update active bundle state: \${String(error)}\`);
2669
+ });
2670
+ }
2671
+
2672
+ async function resolveEntryPath() {
2673
+ const installState = normalizeInstallState(await readJsonFile(INSTALL_STATE_PATH));
2674
+ const bundleState = normalizeBundleState(await readJsonFile(ACTIVE_BUNDLE_PATH));
2675
+ if (!installState) {
2676
+ throw new Error("OpenMeld Service launcher could not read a valid install state.");
2677
+ }
2678
+ if (!bundleState) {
2679
+ const fallback = await findFallbackSelfContainedBundle({
2680
+ installState,
2681
+ preferredEntryScriptRelativePath: null,
2682
+ });
2683
+ if (!fallback) {
2684
+ throw new Error("OpenMeld Service launcher could not read a valid active bundle state.");
2685
+ }
2686
+ await persistFallbackActiveBundleState({
2687
+ ...fallback,
2688
+ installState,
2689
+ previousBundleState: null,
2690
+ });
2691
+ console.error(\`OpenMeld Service launcher recovered bundle \${fallback.bundleId} because active bundle state was missing or invalid.\`);
2692
+ return fallback.entryPath;
2693
+ }
2694
+ if (bundleState.bundleFormat !== "self_contained_v1") {
2695
+ const fallback = await findFallbackSelfContainedBundle({
2696
+ installState,
2697
+ preferredEntryScriptRelativePath: bundleState.entryScriptRelativePath,
2698
+ });
2699
+ if (!fallback) {
2700
+ throw new Error(\`OpenMeld Service launcher refused to start legacy bundle format \${String(bundleState.bundleFormat)}.\`);
2701
+ }
2702
+ await persistFallbackActiveBundleState({
2703
+ ...fallback,
2704
+ installState,
2705
+ previousBundleState: bundleState,
2706
+ });
2707
+ console.error(\`OpenMeld Service launcher recovered bundle \${fallback.bundleId} because active bundle state used legacy bundle format \${String(bundleState.bundleFormat)}.\`);
2708
+ return fallback.entryPath;
2709
+ }
2710
+ if (bundleState.sourceKind === "workspace" && !ALLOW_WORKSPACE_BUNDLE_SOURCE) {
2711
+ const fallback = await findFallbackSelfContainedBundle({
2712
+ installState,
2713
+ preferredEntryScriptRelativePath: bundleState.entryScriptRelativePath,
2714
+ });
2715
+ if (!fallback) {
2716
+ throw new Error("OpenMeld Service launcher refused to start repo-local workspace service files in this lane. Repo-local service files are only allowed through \`openmeld-dev\`.");
2717
+ }
2718
+ await persistFallbackActiveBundleState({
2719
+ ...fallback,
2720
+ installState,
2721
+ previousBundleState: bundleState,
2722
+ });
2723
+ console.error(\`OpenMeld Service launcher recovered bundle \${fallback.bundleId} because active bundle state pointed at a repo-local workspace bundle in this lane.\`);
2724
+ return fallback.entryPath;
2725
+ }
2726
+ if (bundleState.daemonVersion !== installState.daemonVersion) {
2727
+ const fallback = await findFallbackSelfContainedBundle({
2728
+ installState,
2729
+ preferredEntryScriptRelativePath: bundleState.entryScriptRelativePath,
2730
+ });
2731
+ if (!fallback) {
2732
+ throw new Error(\`OpenMeld Service launcher detected bundle version drift: bundle v\${String(bundleState.daemonVersion)} != install v\${String(installState.daemonVersion)}.\`);
2733
+ }
2734
+ await persistFallbackActiveBundleState({
2735
+ ...fallback,
2736
+ installState,
2737
+ previousBundleState: bundleState,
2738
+ });
2739
+ console.error(\`OpenMeld Service launcher recovered bundle \${fallback.bundleId} because active bundle state had version drift.\`);
2740
+ return fallback.entryPath;
2741
+ }
2742
+ const entryPath = join(BUNDLE_ROOT_PATH, bundleState.bundleId, bundleState.entryScriptRelativePath);
2743
+ if (await pathExists(entryPath)) {
2744
+ return entryPath;
2745
+ }
2746
+ const fallback = await findFallbackSelfContainedBundle({
2747
+ installState,
2748
+ preferredEntryScriptRelativePath: bundleState.entryScriptRelativePath,
2749
+ });
2750
+ if (!fallback) {
2751
+ throw new Error(\`OpenMeld Service launcher could not find active bundle entry \${entryPath}.\`);
2752
+ }
2753
+ await persistFallbackActiveBundleState({
2754
+ ...fallback,
2755
+ installState,
2756
+ previousBundleState: bundleState,
2757
+ });
2758
+ console.error(\`OpenMeld Service launcher recovered bundle \${fallback.bundleId} because active bundle entry was missing.\`);
2759
+ return fallback.entryPath;
2760
+ }
2761
+
2762
+ async function main() {
2763
+ const entryPath = await resolveEntryPath();
2764
+ const child = spawn(process.execPath, [entryPath, ...process.argv.slice(2)], {
2765
+ stdio: "inherit",
2766
+ env: process.env,
2767
+ windowsHide: true,
2768
+ });
2769
+
2770
+ const forwardSignal = (signal) => {
2771
+ if (!child.killed) {
2772
+ child.kill(signal);
2773
+ }
2774
+ };
2775
+
2776
+ for (const signal of ["SIGINT", "SIGTERM"]) {
2777
+ process.on(signal, () => {
2778
+ forwardSignal(signal);
2779
+ });
2780
+ }
2781
+
2782
+ child.once("error", (error) => {
2783
+ console.error(String(error));
2784
+ process.exitCode = 1;
2785
+ });
2786
+
2787
+ child.once("close", (code, signal) => {
2788
+ if (typeof code === "number") {
2789
+ process.exitCode = code;
2790
+ return;
2791
+ }
2792
+ if (signal) {
2793
+ process.kill(process.pid, signal);
2794
+ return;
2795
+ }
2796
+ process.exitCode = 1;
2797
+ });
2798
+ }
2799
+
2800
+ await main();`;
2801
+ }
2802
+ function buildDaemonServiceExecutableWrapperSource(pathInput = {}) {
2803
+ return ["#!/bin/sh", `exec ${quoteShellSingle(process$1.execPath)} ${quoteShellSingle(daemonServiceLauncherPath(pathInput))} "$@"`].join("\n");
2804
+ }
2805
+ function quoteShellSingle(value) {
2806
+ return `'${value.replaceAll("'", "'\"'\"'")}'`;
2807
+ }
2808
+ async function readDirectoryNames(path) {
2809
+ return (await readdir(path, { withFileTypes: true }).catch((error) => {
2810
+ if (getErrorCode(error) === "ENOENT") return [];
2811
+ throw error;
2812
+ })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
2813
+ }
2814
+ function inferDaemonBundleSourceKind(sourcePackageRootPath) {
2815
+ const normalized = sourcePackageRootPath.replaceAll("\\", "/").toLowerCase();
2816
+ if (normalized.includes("/.npm/") && normalized.includes("_npx")) return DAEMON_BUNDLE_SOURCE_KIND_NPX_CACHE;
2817
+ if (normalized.includes("/node_modules/")) return DAEMON_BUNDLE_SOURCE_KIND_PACKAGE_INSTALL;
2818
+ if (normalized.includes("/openmeld/")) return DAEMON_BUNDLE_SOURCE_KIND_WORKSPACE;
2819
+ return DAEMON_BUNDLE_SOURCE_KIND_UNKNOWN;
2820
+ }
2821
+ function isDaemonBundleFormat(value) {
2822
+ return value === "legacy_linked_v1" || value === "self_contained_v1" || value === "binary_v1";
2823
+ }
2824
+ function isDaemonBundleSourceKind(value) {
2825
+ return value === DAEMON_BUNDLE_SOURCE_KIND_WORKSPACE || value === DAEMON_BUNDLE_SOURCE_KIND_PACKAGE_INSTALL || value === DAEMON_BUNDLE_SOURCE_KIND_NPX_CACHE || value === DAEMON_BUNDLE_SOURCE_KIND_UNKNOWN;
2826
+ }
2827
+ function isPackageEntryResolutionError(error) {
2828
+ const code = getErrorCode(error);
2829
+ return code === "MODULE_NOT_FOUND" || code === "ERR_PACKAGE_PATH_NOT_EXPORTED";
2830
+ }
2831
+ function normalizeOptionalText(value) {
2832
+ const normalized = String(value ?? "").trim();
2833
+ return normalized.length > 0 ? normalized : null;
2834
+ }
2835
+ async function pathExists(path) {
2836
+ try {
2837
+ await stat(path);
2838
+ return true;
2839
+ } catch (error) {
2840
+ if (getErrorCode(error) === "ENOENT") return false;
2841
+ throw error;
2842
+ }
2843
+ }
2844
+ async function resolvePreferredCliScriptPath(rawPath) {
2845
+ const preferredScriptNames = buildPreferredCliScriptNames(rawPath);
2846
+ const candidateRoots = [
2847
+ dirname(rawPath),
2848
+ join(process$1.cwd(), "dist"),
2849
+ join(process$1.cwd(), "clients", "openmeld-cli", "dist"),
2850
+ dirname(fileURLToPath(import.meta.url)),
2851
+ join(dirname(fileURLToPath(import.meta.url)), "..", "dist")
2852
+ ];
2853
+ for (const scriptName of preferredScriptNames) for (const candidateRoot of candidateRoots) {
2854
+ const candidatePath = join(candidateRoot, scriptName);
2855
+ if (await pathExists(candidatePath)) return candidatePath;
2856
+ }
2857
+ return null;
2858
+ }
2859
+ function buildPreferredCliScriptNames(rawPath) {
2860
+ const requestedScriptName = basename(rawPath).endsWith(".js") ? basename(rawPath) : `${basename(rawPath)}.js`;
2861
+ if (isSupportedDaemonCliEntryName(requestedScriptName)) return [requestedScriptName];
2862
+ if (String(process$1.env.OPENMELD_DEV_MODE ?? "").trim() === "1") return [...DAEMON_CLI_ENTRY_NAMES];
2863
+ return [...DAEMON_CLI_ENTRY_NAMES].reverse();
2864
+ }
2865
+ function isSupportedDaemonCliEntryName(value) {
2866
+ return DAEMON_CLI_ENTRY_NAMES.includes(value);
2867
+ }
2868
+ function getErrorCode(error) {
2869
+ if (!error || typeof error !== "object") return;
2870
+ const code = error.code;
2871
+ return typeof code === "string" ? code : void 0;
2872
+ }
2873
+ //#endregion
2874
+ //#region src/local-service/lifecycle/daemon-managed-binary-path.ts
2875
+ const MANAGED_BINARY_NAME = "openmeld";
2876
+ const PATH_BOUNDARY_PATTERN = /[\s"'<>]/u;
2877
+ const TRAILING_SLASHES_PATTERN = /\/+$/u;
2878
+ const VERSION_SEGMENT_BOUNDARY_PATTERN = /[\s"'<>/]/u;
2879
+ function isOpenMeldManagedBinaryPath(value, pathInput = {}) {
2880
+ const normalizedPath = normalizeManagedBinaryPathText(value);
2881
+ if (normalizedPath === normalizeManagedBinaryPathText(openMeldManagedBinaryPath(pathInput))) return true;
2882
+ return isManagedVersionBinaryPath(normalizedPath, pathInput);
2883
+ }
2884
+ function containsOpenMeldManagedBinaryPath(value, pathInput = {}) {
2885
+ const normalizedValue = normalizeManagedBinaryPathText(value);
2886
+ return containsExactManagedPath(normalizedValue, normalizeManagedBinaryPathText(openMeldManagedBinaryPath(pathInput))) || containsManagedVersionBinaryPath(normalizedValue, pathInput);
2887
+ }
2888
+ function resolveOpenMeldManagedVersionBinaryRootPath(value) {
2889
+ const normalizedPath = normalizeManagedBinaryPathText(value);
2890
+ const segments = normalizedPath.split("/");
2891
+ const binaryName = segments.pop();
2892
+ const versionSegment = segments.pop();
2893
+ const versionsDirectory = segments.pop();
2894
+ if (binaryName !== MANAGED_BINARY_NAME || versionsDirectory !== "versions" || !versionSegment || !isValidManagedVersionSegment(versionSegment)) return null;
2895
+ const rootPath = segments.join("/");
2896
+ if (rootPath.length > 0) return rootPath;
2897
+ return normalizedPath.startsWith("/") ? "/" : null;
2898
+ }
2899
+ function isManagedVersionBinaryPath(normalizedPath, pathInput) {
2900
+ const versionsRoot = normalizeVersionsRoot(pathInput);
2901
+ if (!normalizedPath.startsWith(versionsRoot)) return false;
2902
+ const segments = normalizedPath.slice(versionsRoot.length).split("/");
2903
+ const versionSegment = segments[0] ?? "";
2904
+ const binaryName = segments[1] ?? "";
2905
+ return segments.length === 2 && versionSegment.length > 0 && binaryName === MANAGED_BINARY_NAME;
2906
+ }
2907
+ function containsManagedVersionBinaryPath(normalizedValue, pathInput) {
2908
+ const versionsRoot = normalizeVersionsRoot(pathInput);
2909
+ let index = normalizedValue.indexOf(versionsRoot);
2910
+ while (index >= 0) {
2911
+ const before = index > 0 ? normalizedValue[index - 1] ?? "" : "";
2912
+ const afterRoot = normalizedValue.slice(index + versionsRoot.length);
2913
+ const versionSeparatorIndex = afterRoot.indexOf("/");
2914
+ if (isPathBoundary(before) && versionSeparatorIndex > 0 && isValidManagedVersionSegment(afterRoot.slice(0, versionSeparatorIndex))) {
2915
+ const afterVersion = afterRoot.slice(versionSeparatorIndex + 1);
2916
+ if (afterVersion.startsWith(MANAGED_BINARY_NAME)) {
2917
+ if (isPathBoundary(afterVersion[8] ?? "")) return true;
2918
+ }
2919
+ }
2920
+ index = normalizedValue.indexOf(versionsRoot, index + 1);
2921
+ }
2922
+ return false;
2923
+ }
2924
+ function containsExactManagedPath(normalizedValue, normalizedPath) {
2925
+ let index = normalizedValue.indexOf(normalizedPath);
2926
+ while (index >= 0) {
2927
+ const before = index > 0 ? normalizedValue[index - 1] ?? "" : "";
2928
+ const after = normalizedValue[index + normalizedPath.length] ?? "";
2929
+ if (isPathBoundary(before) && isPathBoundary(after)) return true;
2930
+ index = normalizedValue.indexOf(normalizedPath, index + 1);
2931
+ }
2932
+ return false;
2933
+ }
2934
+ function normalizeVersionsRoot(pathInput) {
2935
+ return `${normalizeManagedBinaryPathText(openMeldVersionsDir(pathInput)).replace(TRAILING_SLASHES_PATTERN, "")}/`;
2936
+ }
2937
+ function normalizeManagedBinaryPathText(value) {
2938
+ return value.trim().replaceAll("\\", "/").toLowerCase();
2939
+ }
2940
+ function isPathBoundary(value) {
2941
+ return value === "" || PATH_BOUNDARY_PATTERN.test(value);
2942
+ }
2943
+ function isValidManagedVersionSegment(value) {
2944
+ return value.length > 0 && !VERSION_SEGMENT_BOUNDARY_PATTERN.test(value);
2945
+ }
2946
+ //#endregion
2947
+ //#region src/local-service/lifecycle/daemon-service-manager-command-match.ts
2948
+ async function assertDaemonMaintenanceInstallationOwnership() {
2949
+ const manager = await resolveDaemonServiceManager();
2950
+ if (!manager) throw new Error("OpenMeld cannot verify the background service installation.");
2951
+ const status = await manager.status();
2952
+ if (!status.installed) return;
2953
+ if (!await matchesExpectedDaemonServiceManagerDefinition({
2954
+ controller: manager.controller,
2955
+ definitionPath: status.definitionPath ?? null,
2956
+ commandSpec: status.commandSpec
2957
+ })) throw new Error("OpenMeld background service belongs to a different installation. Automatic maintenance was stopped without changing it.");
2958
+ }
2959
+ function matchesExpectedDaemonServiceManagerCommand(input) {
2960
+ if (input.controller === "windows-service") {
2961
+ if (input.commandSpec) return matchesWindowsTaskInstallation(input.commandSpec, input.pathInput);
2962
+ return typeof input.definitionPath === "string" && input.definitionPath.length > 0 && input.commandSummary.includes(input.definitionPath);
2963
+ }
2964
+ if ((input.distribution ?? resolveOpenMeldDistribution()) === "binary") {
2965
+ if (input.controller === "launchd") {
2966
+ const stableExecutablePath = daemonServiceBinaryExecutablePath(input.pathInput);
2967
+ return [
2968
+ `${stableExecutablePath} service run`,
2969
+ `"${stableExecutablePath}" service run`,
2970
+ `'${stableExecutablePath}' service run`
2971
+ ].some((expectedPrefix) => input.commandSummary.includes(expectedPrefix));
2972
+ }
2973
+ return containsOpenMeldManagedBinaryPath(input.commandSummary, input.pathInput);
2974
+ }
2975
+ return resolveExpectedDaemonServiceManagerCommandPaths({
2976
+ controller: input.controller,
2977
+ includeLegacyExecutableWrappers: input.includeLegacyExecutableWrappers === true,
2978
+ pathInput: input.pathInput
2979
+ }).some((path) => input.commandSummary.includes(path));
2980
+ }
2981
+ async function matchesExpectedDaemonServiceManagerDefinition(input) {
2982
+ if (input.controller === "windows-service" && input.commandSpec) return matchesWindowsTaskInstallation(input.commandSpec, input.pathInput);
2983
+ if (typeof input.definitionPath !== "string" || input.definitionPath.trim().length === 0) return false;
2984
+ const definition = await readFile(input.definitionPath, "utf8").catch(() => null);
2985
+ if (definition === null) return false;
2986
+ if ((input.distribution ?? resolveOpenMeldDistribution()) === "binary") {
2987
+ if (input.controller === "launchd") {
2988
+ const stableExecutablePath = daemonServiceBinaryExecutablePath(input.pathInput);
2989
+ return definition.includes(`<string>${stableExecutablePath}</string>`);
2990
+ }
2991
+ return containsOpenMeldManagedBinaryPath(definition, input.pathInput);
2992
+ }
2993
+ return resolveExpectedDaemonServiceManagerCommandPaths({
2994
+ controller: input.controller ?? null,
2995
+ pathInput: input.pathInput
2996
+ }).some((path) => definition.includes(path));
2997
+ }
2998
+ function matchesWindowsTaskInstallation(spec, pathInput = {}) {
2999
+ return spec.args[0] === daemonServiceLauncherPath(pathInput) && spec.args[1] === "service" && spec.args[2] === "run" && resolveOpenMeldRootDir({ env: spec.env }) === resolveOpenMeldRootDir(pathInput);
3000
+ }
3001
+ function resolveExpectedDaemonServiceManagerCommandPaths(input) {
3002
+ if (input.controller === "launchd") return [daemonServiceExecutableWrapperPath(input.pathInput), ...input.includeLegacyExecutableWrappers === true ? [daemonServiceLegacyWrapperPath(input.pathInput)] : []];
3003
+ return [daemonServiceLauncherPath(input.pathInput)];
3004
+ }
3005
+ //#endregion
3006
+ //#region src/local-service/lifecycle/daemon-service-command-path.ts
3007
+ const COMMAND_TOKEN_PATTERN = /"([^"]*)"|'([^']*)'|(\S+)/g;
3008
+ const COMMAND_ARGUMENT_BOUNDARY_PATTERN = /\s/u;
3009
+ function tokenizeDaemonCommand(command) {
3010
+ const tokens = [];
3011
+ for (const match of command.matchAll(COMMAND_TOKEN_PATTERN)) {
3012
+ const token = match[1] ?? match[2] ?? match[3];
3013
+ if (token) tokens.push(token);
3014
+ }
3015
+ return tokens;
3016
+ }
3017
+ function normalizeDaemonCommandPath(path) {
3018
+ return path.trim().replaceAll("\\", "/").toLowerCase();
3019
+ }
3020
+ function daemonCommandContainsExactPath(command, path) {
3021
+ const normalizedCommand = normalizeDaemonCommandPath(command);
3022
+ const normalizedPath = normalizeDaemonCommandPath(path);
3023
+ let pathIndex = normalizedCommand.indexOf(normalizedPath);
3024
+ while (pathIndex >= 0) {
3025
+ const beforePath = normalizedCommand[pathIndex - 1];
3026
+ const afterPath = normalizedCommand[pathIndex + normalizedPath.length];
3027
+ if (isCommandArgumentBoundary(beforePath) && isCommandArgumentBoundary(afterPath)) return true;
3028
+ pathIndex = normalizedCommand.indexOf(normalizedPath, pathIndex + normalizedPath.length);
3029
+ }
3030
+ return false;
3031
+ }
3032
+ function extractDaemonCommandEntryPath(command, pathInput = {}) {
3033
+ const unquotedWrapperPath = extractUnquotedDaemonWrapperPath(command, pathInput);
3034
+ if (unquotedWrapperPath) return unquotedWrapperPath;
3035
+ const tokens = tokenizeDaemonCommand(command);
3036
+ if (tokens.length === 0) return null;
3037
+ const serviceRunIndex = findDaemonServiceCommandIndex(tokens);
3038
+ const candidateTokens = serviceRunIndex > 0 ? tokens.slice(0, serviceRunIndex) : tokens;
3039
+ for (let index = candidateTokens.length - 1; index >= 0; index -= 1) {
3040
+ const token = candidateTokens[index];
3041
+ if (!(token && looksLikeDaemonEntryPath(token, pathInput))) continue;
3042
+ return token;
3043
+ }
3044
+ return null;
3045
+ }
3046
+ function isDaemonRuntimeProcessCommand(command) {
3047
+ const serviceCommand = parseDaemonServiceProcessCommand(command);
3048
+ return serviceCommand?.action === "run" || serviceCommand?.action === "start" && serviceCommand.mode === "foreground";
3049
+ }
3050
+ function parseDaemonServiceProcessCommand(command) {
3051
+ const tokens = tokenizeDaemonCommand(command).map((token) => token.toLowerCase());
3052
+ const serviceCommandIndex = findDaemonServiceCommandIndex(tokens);
3053
+ if (serviceCommandIndex < 0) return null;
3054
+ const action = tokens[serviceCommandIndex + 1];
3055
+ if (action !== "run" && action !== "start") return null;
3056
+ return {
3057
+ action,
3058
+ mode: resolveDaemonServiceProcessMode(tokens.slice(serviceCommandIndex + 2))
3059
+ };
3060
+ }
3061
+ function resolveDaemonBundleIdFromEntryPath(entryPath, pathInput = {}) {
3062
+ const normalizedEntryPath = normalizeDaemonCommandPath(entryPath);
3063
+ const normalizedBundleRoot = `${normalizeDaemonCommandPath(daemonRuntimeBundlesPath(pathInput))}/`;
3064
+ if (!normalizedEntryPath.startsWith(normalizedBundleRoot)) return null;
3065
+ const bundleId = normalizedEntryPath.slice(normalizedBundleRoot.length).split("/")[0];
3066
+ return bundleId && bundleId.length > 0 ? bundleId : null;
3067
+ }
3068
+ function looksLikeDaemonEntryPath(token, pathInput) {
3069
+ return token.includes("/bundles/") || token.includes("openmeld/dist/openmeld.js") || token.endsWith("/openmeld.js") || token.endsWith("/openmeld-dev.js") || token.endsWith("/daemon-service-launcher.mjs") || isRecognizedDaemonServiceExecutableWrapperPath(token, pathInput) || isOpenMeldManagedBinaryPath(token, pathInput);
3070
+ }
3071
+ function findDaemonServiceCommandIndex(tokens) {
3072
+ return tokens.findIndex((token, index) => token === "service" && (tokens[index + 1] === "run" || tokens[index + 1] === "start"));
3073
+ }
3074
+ function resolveDaemonServiceProcessMode(serviceArguments) {
3075
+ let mode = null;
3076
+ for (let index = 0; index < serviceArguments.length; index += 1) {
3077
+ const argument = serviceArguments[index];
3078
+ let modeValue;
3079
+ if (argument === "--mode") modeValue = serviceArguments[index + 1];
3080
+ else if (argument?.startsWith("--mode=")) modeValue = argument.slice(7);
3081
+ if (modeValue === "foreground" || modeValue === "background") mode = modeValue;
3082
+ }
3083
+ return mode;
3084
+ }
3085
+ function isRecognizedDaemonServiceExecutableWrapperPath(token, pathInput) {
3086
+ const normalizedToken = normalizeDaemonCommandPath(token);
3087
+ return daemonServiceRecognizedExecutablePaths$1(pathInput).some((wrapperPath) => {
3088
+ const normalizedWrapperPath = normalizeDaemonCommandPath(wrapperPath);
3089
+ return normalizedToken === normalizedWrapperPath || normalizedToken.endsWith(`/${normalizeDaemonCommandPath(basename(wrapperPath))}`);
3090
+ });
3091
+ }
3092
+ function extractUnquotedDaemonWrapperPath(command, pathInput) {
3093
+ const normalizedCommand = normalizeDaemonCommandPath(command);
3094
+ const serviceRunIndex = normalizedCommand.indexOf(" service run");
3095
+ if (serviceRunIndex <= 0) return null;
3096
+ const commandPrefix = command.slice(0, serviceRunIndex);
3097
+ const normalizedPrefix = normalizedCommand.slice(0, serviceRunIndex);
3098
+ for (const wrapperPath of daemonServiceRecognizedExecutablePaths$1(pathInput)) {
3099
+ const normalizedWrapperPath = normalizeDaemonCommandPath(wrapperPath);
3100
+ const wrapperPathIndex = normalizedPrefix.lastIndexOf(normalizedWrapperPath);
3101
+ if (wrapperPathIndex >= 0 && daemonCommandContainsExactPath(commandPrefix, wrapperPath)) return commandPrefix.slice(wrapperPathIndex, wrapperPathIndex + normalizedWrapperPath.length);
3102
+ const wrapperName = basename(wrapperPath);
3103
+ if (!wrapperName.includes(" ")) continue;
3104
+ const normalizedSuffix = `/${normalizeDaemonCommandPath(wrapperName)}`;
3105
+ const wrapperNameIndex = normalizedPrefix.lastIndexOf(normalizedSuffix);
3106
+ if (wrapperNameIndex < 0 || wrapperNameIndex + normalizedSuffix.length !== normalizedPrefix.length) continue;
3107
+ return commandPrefix.slice(0, wrapperNameIndex + normalizedSuffix.length);
3108
+ }
3109
+ return null;
3110
+ }
3111
+ function isCommandArgumentBoundary(char) {
3112
+ return char === void 0 || char === "'" || char === "\"" || COMMAND_ARGUMENT_BOUNDARY_PATTERN.test(char);
3113
+ }
3114
+ //#endregion
3115
+ //#region src/local-service/lifecycle/daemon-service-process-inventory.ts
3116
+ const POSIX_PROCESS_LINE_PATTERN = /^(\d+)\s+(\d+)\s+(.+)$/;
3117
+ const TRAILING_PATH_SEPARATOR_PATTERN = /\/+$/u;
3118
+ const OPENMELD_PACKAGE_INSTALL_ENTRY_SEGMENT = "/node_modules/openmeld/dist/openmeld.js";
3119
+ const OPENMELD_DEV_LOCAL_ENTRY_SEGMENT = "/openmeld-dev.js";
3120
+ const ALL_OPENMELD_ENV_PRESETS = [
3121
+ "prod",
3122
+ "dev-local",
3123
+ "canary"
3124
+ ];
3125
+ const DAEMON_BIN_COMMAND_PATTERN_BY_PRESET = {
3126
+ prod: buildOpenMeldBinCommandPatternForPreset("prod"),
3127
+ "dev-local": buildOpenMeldBinCommandPatternForPreset("dev-local"),
3128
+ canary: buildOpenMeldBinCommandPatternForPreset("canary")
3129
+ };
3130
+ async function listDaemonOwnedProcesses(overrides = {}) {
3131
+ const listProcesses = overrides.listProcesses ?? listProcessesForCurrentPlatform;
3132
+ const ignoredProcessIds = new Set(Array.from(overrides.ignoreProcessIds ?? []).filter((pid) => Number.isInteger(pid) && pid > 0));
3133
+ return collapseLauncherWrapperProcesses((await listProcesses()).map((processInfo) => classifyDaemonOwnedProcess(processInfo, ignoredProcessIds, overrides.pathInput)).filter((processInfo) => processInfo !== null));
3134
+ }
3135
+ function classifyDaemonOwnedProcess(processInfo, ignoredProcessIds, pathInput = {}) {
3136
+ if (ignoredProcessIds.has(processInfo.pid)) return null;
3137
+ const normalizedCommand = normalizeProcessCommand(processInfo.command);
3138
+ const isRuntimeProcess = isDaemonRuntimeProcessCommand(normalizedCommand);
3139
+ const isLegacyDetachedProcess = normalizedCommand.includes("legacy-detached");
3140
+ if (!(isRuntimeProcess || isLegacyDetachedProcess)) return null;
3141
+ const launcherPath = normalizeProcessCommand(daemonServiceLauncherPath(pathInput));
3142
+ const wrapperPaths = daemonServiceRecognizedExecutablePaths(pathInput).map(normalizeProcessCommand);
3143
+ if (wrapperPaths.some((wrapperPath) => normalizedCommand.includes(wrapperPath) && !daemonCommandContainsExactPath(normalizedCommand, wrapperPath))) return null;
3144
+ if (!looksLikeCurrentLaneDaemonCandidate({
3145
+ launcherPath,
3146
+ normalizedCommand,
3147
+ wrapperPaths
3148
+ })) return null;
3149
+ if (resolveDaemonCommandLaneScope({
3150
+ launcherPath,
3151
+ normalizedCommand,
3152
+ pathInput
3153
+ }) !== "current_lane") return null;
3154
+ const ownership = resolveDaemonProcessOwnership(normalizedCommand, launcherPath, wrapperPaths, pathInput);
3155
+ const mode = parseDaemonServiceProcessCommand(normalizedCommand)?.mode ?? null;
3156
+ return {
3157
+ pid: processInfo.pid,
3158
+ parentPid: processInfo.parentPid,
3159
+ command: processInfo.command,
3160
+ mode,
3161
+ ownership
3162
+ };
3163
+ }
3164
+ async function listProcessesForCurrentPlatform() {
3165
+ if (process$1.platform === "win32") return await listWindowsProcesses();
3166
+ return await listPosixProcesses();
3167
+ }
3168
+ async function listPosixProcesses() {
3169
+ const output = await runCommand("ps", ["-axo", "pid=,ppid=,command="]);
3170
+ const processes = [];
3171
+ for (const line of output.split("\n")) {
3172
+ const trimmed = line.trim();
3173
+ if (trimmed.length === 0) continue;
3174
+ const match = trimmed.match(POSIX_PROCESS_LINE_PATTERN);
3175
+ if (!(match?.[1] && match[2] && match[3])) continue;
3176
+ processes.push({
3177
+ pid: Number(match[1]),
3178
+ parentPid: Number(match[2]),
3179
+ command: match[3]
3180
+ });
3181
+ }
3182
+ return processes;
3183
+ }
3184
+ function resolveDaemonProcessOwnership(normalizedCommand, launcherPath, wrapperPaths, pathInput) {
3185
+ const isRuntimeProcess = isDaemonRuntimeProcessCommand(normalizedCommand);
3186
+ if (normalizedCommand.includes(launcherPath) || wrapperPaths.some((wrapperPath) => daemonCommandContainsExactPath(normalizedCommand, wrapperPath)) || isRuntimeProcess && containsOpenMeldManagedBinaryPath(normalizedCommand, pathInput)) return "stable_launcher";
3187
+ if (normalizedCommand.includes("legacy-detached")) return "legacy_detached";
3188
+ if (isRuntimeProcess) return "cli_direct";
3189
+ return "unknown";
3190
+ }
3191
+ function looksLikeCurrentLaneDaemonCandidate(input) {
3192
+ return isDaemonRuntimeProcessCommand(input.normalizedCommand) || input.normalizedCommand.includes(input.launcherPath) || input.wrapperPaths.some((wrapperPath) => daemonCommandContainsExactPath(input.normalizedCommand, wrapperPath)) || input.normalizedCommand.includes("legacy-detached");
3193
+ }
3194
+ function resolveDaemonCommandLaneScope(input) {
3195
+ const managedVersionRoot = resolveDaemonCommandManagedVersionRoot(input.normalizedCommand);
3196
+ if (managedVersionRoot) return managedVersionRoot === normalizeRootPath(resolveOpenMeldRootDir(input.pathInput)) ? "current_lane" : "other_lane";
3197
+ const currentLane = resolveOpenMeldEnvPreset(input.pathInput);
3198
+ const managedLane = resolveManagedDaemonPathLane({
3199
+ normalizedCommand: input.normalizedCommand,
3200
+ pathInput: input.pathInput
3201
+ });
3202
+ if (managedLane) return managedLane === currentLane ? "current_lane" : "other_lane";
3203
+ if (hasExplicitOpenMeldHome(input.pathInput)) return "not_openmeld";
3204
+ const detectedLane = resolveDaemonCliCommandLane(input.normalizedCommand, input.pathInput);
3205
+ if (!detectedLane) return "not_openmeld";
3206
+ return detectedLane === currentLane ? "current_lane" : "other_lane";
3207
+ }
3208
+ function hasExplicitOpenMeldHome(pathInput) {
3209
+ const value = (pathInput.env ?? process$1.env)[OPENMELD_HOME_ENV_KEY];
3210
+ return typeof value === "string" && value.trim().length > 0;
3211
+ }
3212
+ function resolveDaemonCommandManagedVersionRoot(normalizedCommand) {
3213
+ for (const token of tokenizeDaemonCommand(normalizedCommand)) {
3214
+ const rootPath = resolveOpenMeldManagedVersionBinaryRootPath(token);
3215
+ if (rootPath) return normalizeRootPath(rootPath);
3216
+ }
3217
+ return null;
3218
+ }
3219
+ function resolveManagedDaemonPathLane(input) {
3220
+ const currentPreset = resolveOpenMeldEnvPreset(input.pathInput);
3221
+ for (const preset of ALL_OPENMELD_ENV_PRESETS) {
3222
+ const lanePathInput = resolveLanePathInput(input.pathInput, preset);
3223
+ const laneLauncherPath = normalizeProcessCommand(daemonServiceLauncherPath(lanePathInput));
3224
+ const laneWrapperPaths = daemonServiceRecognizedExecutablePaths(lanePathInput).map(normalizeProcessCommand);
3225
+ const laneRuntimeRoot = normalizeProcessCommand(daemonRuntimeRootPath(lanePathInput));
3226
+ const laneEntryPath = extractDaemonCommandEntryPath(input.normalizedCommand, lanePathInput);
3227
+ const laneExecutableNames = laneWrapperPaths.map((candidatePath) => basename(candidatePath));
3228
+ if (input.normalizedCommand.includes(laneLauncherPath) || laneWrapperPaths.some((wrapperPath) => daemonCommandContainsExactPath(input.normalizedCommand, wrapperPath)) || preset !== currentPreset && laneEntryPath !== null && laneExecutableNames.includes(normalizeProcessCommand(basename(laneEntryPath))) || input.normalizedCommand.includes(laneRuntimeRoot) || containsOpenMeldManagedBinaryPath(input.normalizedCommand, lanePathInput)) return preset;
3229
+ }
3230
+ return null;
3231
+ }
3232
+ function resolveDaemonCliCommandLane(normalizedCommand, pathInput) {
3233
+ if (!isDaemonRuntimeProcessCommand(normalizedCommand)) return null;
3234
+ if (matchesDaemonCliLane(normalizedCommand, "dev-local", pathInput)) return "dev-local";
3235
+ if (matchesDaemonCliLane(normalizedCommand, "canary", pathInput)) return "canary";
3236
+ if (matchesDaemonCliLane(normalizedCommand, "prod", pathInput)) return "prod";
3237
+ return null;
3238
+ }
3239
+ function matchesDaemonCliLane(normalizedCommand, preset, pathInput) {
3240
+ if (DAEMON_BIN_COMMAND_PATTERN_BY_PRESET[preset].test(normalizedCommand)) return true;
3241
+ if (preset === "dev-local") return normalizedCommand.includes(OPENMELD_DEV_LOCAL_ENTRY_SEGMENT);
3242
+ const canaryPackageInstallRoot = resolveCanaryPackageInstallRoot(pathInput);
3243
+ if (preset === "canary") return normalizedCommand.includes(canaryPackageInstallRoot) || normalizedCommand.includes("/.local/share/openmeld-canary/package-install/");
3244
+ return normalizedCommand.includes(OPENMELD_PACKAGE_INSTALL_ENTRY_SEGMENT) && !normalizedCommand.includes(canaryPackageInstallRoot) && !normalizedCommand.includes("/.local/share/openmeld-canary/package-install/") && !normalizedCommand.includes(OPENMELD_DEV_LOCAL_ENTRY_SEGMENT);
3245
+ }
3246
+ function collapseLauncherWrapperProcesses(processes) {
3247
+ const launcherPidSet = /* @__PURE__ */ new Set();
3248
+ for (const processInfo of processes) if (processInfo.ownership === "stable_launcher") launcherPidSet.add(processInfo.pid);
3249
+ if (launcherPidSet.size === 0) return processes;
3250
+ const collapsedProcesses = [];
3251
+ for (const processInfo of processes) {
3252
+ if (processInfo.ownership === "stable_launcher") {
3253
+ if (processes.some((candidate) => candidate.pid !== processInfo.pid && candidate.parentPid === processInfo.pid && candidate.ownership !== "stable_launcher")) continue;
3254
+ collapsedProcesses.push(processInfo);
3255
+ continue;
3256
+ }
3257
+ if (processInfo.parentPid !== null && launcherPidSet.has(processInfo.parentPid)) {
3258
+ collapsedProcesses.push({
3259
+ ...processInfo,
3260
+ ownership: processInfo.ownership === "unknown" ? processInfo.ownership : "stable_launcher"
3261
+ });
3262
+ continue;
3263
+ }
3264
+ collapsedProcesses.push(processInfo);
3265
+ }
3266
+ return collapsedProcesses;
3267
+ }
3268
+ async function listWindowsProcesses() {
3269
+ const output = await runCommand("powershell", [
3270
+ "-NoProfile",
3271
+ "-Command",
3272
+ "Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine | ConvertTo-Json -Compress"
3273
+ ]);
3274
+ const parsed = JSON.parse(output);
3275
+ const rows = Array.isArray(parsed) ? parsed : [parsed];
3276
+ const processes = [];
3277
+ for (const row of rows) {
3278
+ if (typeof row.ProcessId !== "number" || typeof row.ParentProcessId !== "number" || typeof row.CommandLine !== "string" || row.CommandLine.trim().length === 0) continue;
3279
+ processes.push({
3280
+ pid: row.ProcessId,
3281
+ parentPid: row.ParentProcessId,
3282
+ command: row.CommandLine
3283
+ });
3284
+ }
3285
+ return processes;
3286
+ }
3287
+ async function runCommand(command, args) {
3288
+ return await new Promise((resolve, reject) => {
3289
+ const child = spawn(command, args, {
3290
+ stdio: [
3291
+ "ignore",
3292
+ "pipe",
3293
+ "pipe"
3294
+ ],
3295
+ env: process$1.env,
3296
+ windowsHide: true
3297
+ });
3298
+ let stdout = "";
3299
+ let stderr = "";
3300
+ child.stdout?.on("data", (chunk) => {
3301
+ stdout += chunk.toString();
3302
+ });
3303
+ child.stderr?.on("data", (chunk) => {
3304
+ stderr += chunk.toString();
3305
+ });
3306
+ child.once("error", reject);
3307
+ child.once("close", (code) => {
3308
+ if (code !== 0) {
3309
+ reject(/* @__PURE__ */ new Error(`process inventory command failed: ${command} ${args.join(" ")} ${stderr.trim()}`));
3310
+ return;
3311
+ }
3312
+ resolve(stdout);
3313
+ });
3314
+ });
3315
+ }
3316
+ function buildOpenMeldBinCommandPatternForPreset(preset) {
3317
+ const aliases = resolveDaemonServiceIdentity({ env: { OPENMELD_ENV_PRESET: preset } }).cliEntryAliases.map(escapeRegex);
3318
+ return new RegExp(`(^|[\\s\\/])(${aliases.join("|")})(?:\\.cmd|\\.exe|\\.js)?(?=\\s|$)`, "u");
3319
+ }
3320
+ function escapeRegex(value) {
3321
+ return value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
3322
+ }
3323
+ function resolveCanaryPackageInstallRoot(pathInput = {}) {
3324
+ return normalizeProcessCommand(join(pathInput.homeDir ?? homedir(), ".local", "share", "openmeld-canary", "package-install"));
3325
+ }
3326
+ function resolveLanePathInput(pathInput, preset) {
3327
+ const currentPreset = resolveOpenMeldEnvPreset(pathInput);
3328
+ const env = {
3329
+ ...pathInput.env ?? process$1.env,
3330
+ OPENMELD_ENV_PRESET: preset
3331
+ };
3332
+ if (preset !== currentPreset && env["OPENMELD_HOME"]) delete env[OPENMELD_HOME_ENV_KEY];
3333
+ return {
3334
+ ...pathInput,
3335
+ env
3336
+ };
3337
+ }
3338
+ function normalizeProcessCommand(command) {
3339
+ return command.trim().toLowerCase().replaceAll("\\", "/");
3340
+ }
3341
+ function normalizeRootPath(path) {
3342
+ const normalized = normalizeProcessCommand(path);
3343
+ return normalized === "/" ? normalized : normalized.replace(TRAILING_PATH_SEPARATOR_PATTERN, "");
3344
+ }
3345
+ //#endregion
3346
+ //#region src/local-service/lifecycle/daemon-service-legacy-shared.ts
3347
+ const PROD_ENV_PRESET = "prod";
3348
+ function shouldInspectLegacySharedDaemonService(input = {}) {
3349
+ const env = input.env ?? process.env;
3350
+ if (String(env["OPENMELD_HOME"] ?? "").trim()) return false;
3351
+ return resolveOpenMeldEnvPreset(input) === PROD_ENV_PRESET;
3352
+ }
3353
+ function resolveLegacySharedDaemonPathInput(input = {}) {
3354
+ if (!shouldInspectLegacySharedDaemonService(input)) return null;
3355
+ return {
3356
+ ...input,
3357
+ env: {
3358
+ ...input.env ?? process.env,
3359
+ OPENMELD_ENV_PRESET: PROD_ENV_PRESET
3360
+ }
3361
+ };
3362
+ }
3363
+ function requiresLegacySharedDaemonServiceMigration(input) {
3364
+ if (hasLegacySharedServiceManagerResidual(input)) return true;
3365
+ return hasLegacyDetachedResidual(input);
3366
+ }
3367
+ async function inspectLegacySharedDaemonService(input = {}) {
3368
+ const pathInput = resolveLegacySharedDaemonPathInput(input);
3369
+ if (!pathInput) return null;
3370
+ const [installStatus, runtimeStatus, serviceManager, ownedProcesses] = await Promise.all([
3371
+ getDaemonStatus(pathInput),
3372
+ getDaemonRuntimeStatus(pathInput),
3373
+ resolveDaemonServiceManager(void 0, pathInput).catch(() => null),
3374
+ listDaemonOwnedProcesses({ pathInput }).catch(() => [])
3375
+ ]);
3376
+ const serviceManagerStatus = serviceManager ? await serviceManager.status().catch(() => null) : null;
3377
+ return {
3378
+ present: requiresLegacySharedDaemonServiceMigration({
3379
+ pathInput,
3380
+ runtimeStatus,
3381
+ serviceManager,
3382
+ serviceManagerStatus,
3383
+ ownedProcesses
3384
+ }),
3385
+ pathInput,
3386
+ installStatus,
3387
+ runtimeStatus,
3388
+ serviceManager,
3389
+ serviceManagerStatus,
3390
+ ownedProcesses
3391
+ };
3392
+ }
3393
+ function hasLegacySharedServiceManagerResidual(input) {
3394
+ if (!input.serviceManagerStatus?.installed) return false;
3395
+ if (!input.serviceManagerStatus.commandSummary) return true;
3396
+ return !matchesExpectedDaemonServiceManagerCommand({
3397
+ controller: input.serviceManager?.controller ?? null,
3398
+ commandSummary: input.serviceManagerStatus.commandSummary,
3399
+ commandSpec: input.serviceManagerStatus.commandSpec,
3400
+ definitionPath: input.serviceManagerStatus.definitionPath ?? null,
3401
+ includeLegacyExecutableWrappers: true,
3402
+ pathInput: input.pathInput
3403
+ });
3404
+ }
3405
+ function hasLegacyDetachedResidual(input) {
3406
+ if (input.runtimeStatus.serviceController === "legacy-detached") return true;
3407
+ return input.ownedProcesses.some((processInfo) => processInfo.ownership === "legacy_detached");
3408
+ }
3409
+ async function cleanupLegacySharedDaemonServiceState(input = {}) {
3410
+ const pathInput = resolveLegacySharedDaemonPathInput(input);
3411
+ if (!pathInput) return { removed: false };
3412
+ const legacySharedService = await inspectLegacySharedDaemonService(input);
3413
+ let removedServiceManager = false;
3414
+ if (legacySharedService?.present && legacySharedService.serviceManager && legacySharedService.serviceManagerStatus?.installed) {
3415
+ await legacySharedService.serviceManager.uninstall();
3416
+ await legacySharedService.serviceManager.waitUntilAbsent();
3417
+ removedServiceManager = true;
3418
+ }
3419
+ const uninstallResult = await uninstallDaemon(pathInput);
3420
+ return { removed: removedServiceManager || uninstallResult.removed };
3421
+ }
3422
+ //#endregion
3423
+ //#region src/local-service/lifecycle/daemon-service-runtime-observer.ts
3424
+ function resolveObservedDaemonRuntimeStatus(input) {
3425
+ const runtimeLeaseIssue = resolveRuntimeLeaseIssue(input.runtimeLease);
3426
+ const observedProcess = selectObservedRuntimeProcess(input.ownedProcesses);
3427
+ if (!runtimeLeaseIssue && input.runtimeLease) return {
3428
+ status: "running",
3429
+ mode: input.runtimeLease.mode,
3430
+ pid: input.runtimeLease.pid,
3431
+ startedAt: input.runtimeLease.startedAt,
3432
+ updatedAt: input.runtimeLease.updatedAt,
3433
+ managedBySystemService: input.runtimeLease.managedBySystemService,
3434
+ serviceController: input.runtimeLease.serviceController,
3435
+ autoStart: input.runtimeLease.managedBySystemService
3436
+ };
3437
+ if (observedProcess) return {
3438
+ status: "stale",
3439
+ mode: observedProcess.mode,
3440
+ pid: observedProcess.pid,
3441
+ startedAt: input.runtimeLease?.startedAt ?? null,
3442
+ updatedAt: input.runtimeLease?.updatedAt ?? null,
3443
+ managedBySystemService: observedProcess.ownership === "stable_launcher",
3444
+ serviceController: observedProcess.ownership === "legacy_detached" ? "legacy-detached" : "unknown",
3445
+ autoStart: observedProcess.ownership === "stable_launcher",
3446
+ reason: runtimeLeaseIssue ?? "runtime_lease_missing"
3447
+ };
3448
+ if (!input.runtimeLease) return {
3449
+ status: "not_running",
3450
+ mode: null,
3451
+ pid: null,
3452
+ startedAt: null,
3453
+ updatedAt: null,
3454
+ managedBySystemService: false,
3455
+ serviceController: "unknown",
3456
+ autoStart: false
3457
+ };
3458
+ return {
3459
+ status: "stale",
3460
+ mode: input.runtimeLease.mode,
3461
+ pid: input.runtimeLease.pid,
3462
+ startedAt: input.runtimeLease.startedAt,
3463
+ updatedAt: input.runtimeLease.updatedAt,
3464
+ managedBySystemService: input.runtimeLease.managedBySystemService,
3465
+ serviceController: input.runtimeLease.serviceController,
3466
+ autoStart: input.runtimeLease.managedBySystemService,
3467
+ reason: runtimeLeaseIssue ?? "runtime_lease_missing"
3468
+ };
3469
+ }
3470
+ function resolveObservedRuntimeCommandEntryPath(input) {
3471
+ const runtimePid = typeof input.runtimeStatus.pid === "number" ? input.runtimeStatus.pid : null;
3472
+ if (!runtimePid) return null;
3473
+ const runtimeProcess = input.ownedProcesses.find((processInfo) => processInfo.pid === runtimePid);
3474
+ if (!runtimeProcess) return null;
3475
+ return extractDaemonCommandEntryPath(runtimeProcess.command);
3476
+ }
3477
+ function resolveRuntimeLeaseIssue(runtimeLease) {
3478
+ if (!runtimeLease) return "runtime_lease_missing";
3479
+ if (!Number.isInteger(runtimeLease.pid) || runtimeLease.pid <= 0) return "invalid_pid";
3480
+ if (!isPidAlive(runtimeLease.pid)) return "process_not_alive";
3481
+ if (isRuntimeLeaseHeartbeatStale(runtimeLease)) return "heartbeat_stale";
3482
+ return null;
3483
+ }
3484
+ function selectObservedRuntimeProcess(ownedProcesses) {
3485
+ return [...ownedProcesses].sort((left, right) => {
3486
+ const priorityDifference = resolveOwnershipPriority(left.ownership) - resolveOwnershipPriority(right.ownership);
3487
+ if (priorityDifference !== 0) return priorityDifference;
3488
+ const modeDifference = resolveModePriority(left.mode) - resolveModePriority(right.mode);
3489
+ if (modeDifference !== 0) return modeDifference;
3490
+ return left.pid - right.pid;
3491
+ })[0] ?? null;
3492
+ }
3493
+ function resolveOwnershipPriority(ownership) {
3494
+ switch (ownership) {
3495
+ case "stable_launcher": return 0;
3496
+ case "legacy_detached": return 1;
3497
+ case "cli_direct": return 2;
3498
+ default: return 3;
3499
+ }
3500
+ }
3501
+ function resolveModePriority(mode) {
3502
+ switch (mode) {
3503
+ case "background": return 0;
3504
+ case "foreground": return 1;
3505
+ default: return 2;
3506
+ }
3507
+ }
3508
+ function isPidAlive(pid) {
3509
+ try {
3510
+ process$1.kill(pid, 0);
3511
+ return true;
3512
+ } catch {
3513
+ return false;
3514
+ }
3515
+ }
3516
+ function isRuntimeLeaseHeartbeatStale(runtimeLease) {
3517
+ const freshnessTimestamp = runtimeLease.heartbeatAt ?? runtimeLease.updatedAt;
3518
+ const heartbeatMs = Date.parse(freshnessTimestamp);
3519
+ if (Number.isNaN(heartbeatMs)) return true;
3520
+ return Date.now() - heartbeatMs > DAEMON_HEARTBEAT_STALE_MS;
3521
+ }
3522
+ //#endregion
3523
+ //#region src/local-service/lifecycle/daemon-service-runtime.ts
3524
+ const DEFAULT_SYSTEM_SERVICE_STOP_WAIT_MS = 3e3;
3525
+ const DEFAULT_SYSTEM_SERVICE_STOP_POLL_MS = 200;
3526
+ async function readCurrentObservedDaemonRuntimeStatus() {
3527
+ return await readObservedRuntimeState();
3528
+ }
3529
+ async function clearDaemonRuntimeStateIfDefinitelyStopped() {
3530
+ const context = await readCurrentDaemonRuntimeContext();
3531
+ if (!(context.effectiveRuntimeStatus === "not_running" || await isStoppedSystemServiceSnapshot(context))) return {
3532
+ context,
3533
+ cleared: false
3534
+ };
3535
+ await clearDaemonServiceRuntimeState();
3536
+ return {
3537
+ context,
3538
+ cleared: true
3539
+ };
3540
+ }
3541
+ async function isStoppedSystemServiceSnapshot(context) {
3542
+ if (context.runtimeStatus.status !== "stale" || !context.runtimeStatus.managedBySystemService || context.serviceManagerStatus?.running !== false) return false;
3543
+ return (await listDaemonOwnedProcesses({ ignoreProcessIds: [process$1.pid, process$1.ppid] })).length === 0;
3544
+ }
3545
+ async function readCurrentDaemonRuntimeContext(input = {}) {
3546
+ const status = input.status ?? await getDaemonStatus();
3547
+ const runtimeStatus = await readCurrentObservedDaemonRuntimeStatus();
3548
+ const { serviceManager, serviceManagerStatus, legacySharedService } = await resolveDaemonServiceManagerForRuntimeState({
3549
+ status,
3550
+ runtimeState: runtimeStatus
3551
+ });
3552
+ return {
3553
+ status,
3554
+ runtimeStatus,
3555
+ serviceManager,
3556
+ serviceManagerStatus,
3557
+ legacySharedService,
3558
+ effectiveRuntimeStatus: getEffectiveDaemonRuntimeStatus({
3559
+ runtimeState: runtimeStatus,
3560
+ serviceManagerStatus
3561
+ })
3562
+ };
3563
+ }
3564
+ async function resolveDaemonRuntimeState(status) {
3565
+ if (!status.installed) return null;
3566
+ return await readCurrentObservedDaemonRuntimeStatus();
3567
+ }
3568
+ async function resolveDaemonServiceManagerFromRuntimeState(runtimeState) {
3569
+ if (!runtimeState?.managedBySystemService) return null;
3570
+ if (runtimeState.serviceController === "legacy-detached") return null;
3571
+ return await resolveDaemonServiceManager(runtimeState.serviceController);
3572
+ }
3573
+ async function resolveDaemonServiceManagerForRuntimeState(input) {
3574
+ const initialManager = await resolveDaemonServiceManagerFromRuntimeState(input.runtimeState);
3575
+ const initialManagerStatus = initialManager ? await initialManager.status().catch(() => null) : null;
3576
+ if (input.status.installed && input.runtimeState?.managedBySystemService !== true && !initialManagerStatus?.installed) {
3577
+ const detectedManager = await resolveDaemonServiceManager().catch(() => null);
3578
+ if (detectedManager) {
3579
+ const detectedManagerStatus = await detectedManager.status().catch(() => null);
3580
+ if (detectedManagerStatus?.installed) return {
3581
+ serviceManager: detectedManager,
3582
+ serviceManagerStatus: detectedManagerStatus,
3583
+ legacySharedService: null
3584
+ };
3585
+ }
3586
+ }
3587
+ const legacySharedService = await inspectLegacySharedDaemonService().catch(() => null);
3588
+ if (legacySharedService?.present && legacySharedService.serviceManagerStatus?.installed) {
3589
+ const legacyManager = legacySharedService.serviceManager ?? await resolveDaemonServiceManager(legacySharedService.runtimeStatus.serviceController === "unknown" ? void 0 : legacySharedService.runtimeStatus.serviceController, legacySharedService.pathInput).catch(() => null);
3590
+ if (legacyManager) return {
3591
+ serviceManager: legacyManager,
3592
+ serviceManagerStatus: legacySharedService.serviceManagerStatus,
3593
+ legacySharedService
3594
+ };
3595
+ }
3596
+ return {
3597
+ serviceManager: initialManager,
3598
+ serviceManagerStatus: initialManagerStatus,
3599
+ legacySharedService
3600
+ };
3601
+ }
3602
+ function getEffectiveDaemonRuntimeStatus(input) {
3603
+ if (input.runtimeState.status === "running") return "running";
3604
+ if (!(input.runtimeState.managedBySystemService && input.serviceManagerStatus)) return input.runtimeState.status;
3605
+ if (input.runtimeState.status === "stale") {
3606
+ if (input.runtimeState.reason === "heartbeat_stale") return "stale";
3607
+ if (input.serviceManagerStatus.running) return "running";
3608
+ if (!input.serviceManagerStatus.enabled) return "not_running";
3609
+ }
3610
+ if (!input.serviceManagerStatus.running) return "not_running";
3611
+ return input.runtimeState.status;
3612
+ }
3613
+ async function waitForDaemonSystemServiceToStop(input) {
3614
+ const waitMs = input.waitMs ?? DEFAULT_SYSTEM_SERVICE_STOP_WAIT_MS;
3615
+ const pollMs = input.pollMs ?? DEFAULT_SYSTEM_SERVICE_STOP_POLL_MS;
3616
+ const deadlineMs = Date.now() + waitMs;
3617
+ while (Date.now() < deadlineMs) {
3618
+ const currentRuntime = await readCurrentObservedDaemonRuntimeStatus().catch(() => null);
3619
+ if ((await input.manager.status().catch(() => null))?.running === false && currentRuntime !== null && currentRuntime.status !== "running") return true;
3620
+ if (currentRuntime?.status === "stale" && !currentRuntime.managedBySystemService) return true;
3621
+ if (currentRuntime?.status === "not_running") return true;
3622
+ await sleep(pollMs);
3623
+ }
3624
+ const finalRuntime = await readCurrentObservedDaemonRuntimeStatus().catch(() => null);
3625
+ if (finalRuntime?.status === "not_running") return true;
3626
+ if (finalRuntime?.status === "stale" && !finalRuntime.managedBySystemService) return true;
3627
+ if (finalRuntime?.status === "running") return false;
3628
+ if (finalRuntime === null) return false;
3629
+ return (await input.manager.status().catch(() => null))?.running === false;
3630
+ }
3631
+ async function readObservedRuntimeState() {
3632
+ const ignoredProcessIds = [process$1.pid, process$1.ppid].filter((pid) => Number.isInteger(pid) && pid > 0);
3633
+ const [runtimeLease, ownedProcesses] = await Promise.all([readDaemonRuntimeLease().catch(() => null), listDaemonOwnedProcesses({ ignoreProcessIds: ignoredProcessIds })]);
3634
+ return resolveObservedDaemonRuntimeStatus({
3635
+ runtimeLease,
3636
+ ownedProcesses
3637
+ });
3638
+ }
3639
+ //#endregion
3640
+ export { readManagedCliInstallation as $, prepareDaemonServiceBundle as A, verifyCliBinaryCodeSignature as At, resolveDaemonServiceArtifact as B, readDaemonServiceContract as Bt, daemonServiceExecutableWrapperPath as C, resolveDaemonServiceUpdateWorkerLaunchdPlistPath as Ct, ensureDaemonServiceStableBinaryExecutable as D, resolveDaemonServiceUpdateWorkerWindowsScriptPath as Dt, discardPreparedDaemonServiceBundle as E, resolveDaemonServiceUpdateWorkerSystemdUnitPath as Et, restoreDaemonActiveBundleStateSnapshot as F, requestLocalSyncRouteCatalog as Ft, readRecentDaemonLifecycleEvents as G, formatDaemonLifecycleOriginSummary as H, runAuditedServiceManagerCarrierMutation as I, sendLocalDaemonControlPlaneRequest as It, runWithDaemonLifecycleCommandJournal as J, resolveRecentDaemonSignalStopCause as K, verifyDaemonActiveBundleIntegrity as L, clearDaemonServiceContract as Lt, resolveAlignedDaemonActiveBundleEntryPath as M, requestLocalAgentActivitySync as Mt, resolveDaemonBundleEntryPathFromState as N, requestLocalDaemonServiceUpdateReadiness as Nt, ensureDaemonServiceUpdateWorkerBinaryExecutable as O, downloadCliBinaryUpdateArtifact as Ot, resolveInstalledDaemonBundleFingerprint as P, requestLocalDaemonShutdown as Pt, pruneManagedInstallVersions as Q, writeDaemonServiceExecutableWrapper as R, isDaemonServiceContractIdentityReusable as Rt, daemonServiceBinaryExecutablePath as S, resolveDaemonServiceUpdateWorkerIdentity as St, daemonServiceUpdateWorkerBinaryPath as T, resolveDaemonServiceUpdateWorkerSystemdTimerUnitPath as Tt, readLatestDaemonLifecycleConnectionStateEvent as U, emitDaemonLifecycleEvent as V, upsertDaemonServiceContract as Vt, readLatestDaemonLifecycleOriginEvent as W, buildInstallSelfJsonPayload as X, collectLocalOperationFailure as Y, performManagedInstall as Z, matchesExpectedDaemonServiceManagerDefinition as _, package_default as _t, resolveDaemonRuntimeState as a, persistPendingDaemonServiceUpdate as at, cleanupInactiveDaemonServiceBundles as b, daemonServiceUpdateWorkerNpmEntryPath as bt, resolveObservedDaemonRuntimeStatus as c, buildNextVersionState as ct, inspectLegacySharedDaemonService as d, fetchLatestCliBinaryRelease as dt, resolveCliSelfVersion as et, listDaemonOwnedProcesses as f, fetchLatestPackageInfo as ft, assertDaemonMaintenanceInstallationOwnership as g, resolveBundledServiceRelease as gt, resolveDaemonBundleIdFromEntryPath as h, writeVersionState as ht, readCurrentObservedDaemonRuntimeStatus as i, completePendingDaemonServiceUpdate as it, readDaemonActiveBundleState as j, LocalDaemonControlPlaneClientError as jt, isDaemonBundleSourceAllowedForLane as k, resolveCliBinaryUpdatePlan as kt, resolveObservedRuntimeCommandEntryPath as l, compareSemver as lt, normalizeDaemonCommandPath as m, readVersionState as mt, getEffectiveDaemonRuntimeStatus as n, OPENMELD_VERSION as nt, resolveDaemonServiceManagerForRuntimeState as o, readLastDaemonServiceUpdate as ot, extractDaemonCommandEntryPath as p, isPlainReleaseVersion as pt, runDaemonServiceManagerAction as q, readCurrentDaemonRuntimeContext as r, DAEMON_SERVICE_UPDATE_JOB_SCHEMA as rt, waitForDaemonSystemServiceToStop as s, readPendingDaemonServiceUpdate as st, clearDaemonRuntimeStateIfDefinitelyStopped as t, withManagedInstallTransaction as tt, cleanupLegacySharedDaemonServiceState as u, ensureVersionStateReady as ut, isOpenMeldManagedBinaryPath as v, INDEPENDENT_MAINTENANCE_REGISTRATION as vt, daemonServiceLauncherPath as w, resolveDaemonServiceUpdateWorkerSystemdPathUnitPath as wt, clearDaemonServiceUpdateWorkerBinaryExecutable as x, hasIndependentMaintenanceRegistration as xt, activateDaemonServiceBundle as y, configureDaemonMaintenanceEnvironment as yt, writeDaemonServiceLauncher as z, isUnsafeProductionDeviceId as zt };
3641
+
3642
+ //# sourceMappingURL=daemon-service-runtime-DQW9gSLT.js.map