openmeld 0.3.236 → 0.3.237
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-me-membership-C_ytPYUu.js → add-me-membership-BEqSnfgo.js} +2 -2
- package/dist/{add-me-membership-C_ytPYUu.js.map → add-me-membership-BEqSnfgo.js.map} +1 -1
- package/dist/{agents-mFz8qI_p.js → agents-_Hh6L3Fi.js} +9 -9
- package/dist/{agents-mFz8qI_p.js.map → agents-_Hh6L3Fi.js.map} +1 -1
- package/dist/{api-client-foundation-BzGnJzcb.js → api-client-foundation-CGc8AuMo.js} +3 -3
- package/dist/{api-client-foundation-BzGnJzcb.js.map → api-client-foundation-CGc8AuMo.js.map} +1 -1
- package/dist/{api-client-foundation-BVVqHzYr.js → api-client-foundation-ZuYF2Uah.js} +1 -1
- package/dist/{auth-session-CjxqNKvh.js → auth-session-B3oyTcSI.js} +2 -2
- package/dist/{auth-session-CjxqNKvh.js.map → auth-session-B3oyTcSI.js.map} +1 -1
- package/dist/auth-session-CoFlCq7_.js +4 -0
- package/dist/{channel-BW2_rI6u.js → channel-BB6aEY--.js} +3 -3
- package/dist/{channel-BW2_rI6u.js.map → channel-BB6aEY--.js.map} +1 -1
- package/dist/{command-DApK5Fss.js → command-D71NHS4j.js} +19 -19
- package/dist/command-D71NHS4j.js.map +1 -0
- package/dist/{computer-connection-LX1R7jD0.js → computer-connection-DyL3C3HO.js} +2 -2
- package/dist/{computer-connection-LX1R7jD0.js.map → computer-connection-DyL3C3HO.js.map} +1 -1
- package/dist/{computer-connection-review-CSe-ljcH.js → computer-connection-review-BXuXP6KH.js} +5 -5
- package/dist/{computer-connection-review-CSe-ljcH.js.map → computer-connection-review-BXuXP6KH.js.map} +1 -1
- package/dist/{computer-disconnect-CELa6Aef.js → computer-disconnect-BXZKVvxj.js} +7 -7
- package/dist/{computer-disconnect-CELa6Aef.js.map → computer-disconnect-BXZKVvxj.js.map} +1 -1
- package/dist/{computer-setup-continuation-BfsOJDh1.js → computer-setup-continuation-DOvxRtAh.js} +3 -3
- package/dist/{computer-setup-continuation-BfsOJDh1.js.map → computer-setup-continuation-DOvxRtAh.js.map} +1 -1
- package/dist/{context-D3GnSqg8.js → context-43g3bIde.js} +3 -3
- package/dist/{context-D3GnSqg8.js.map → context-43g3bIde.js.map} +1 -1
- package/dist/{daemon-device-id-OMqh2F9_.js → daemon-device-id-Dwm7CHtX.js} +4 -4
- package/dist/{daemon-device-id-OMqh2F9_.js.map → daemon-device-id-Dwm7CHtX.js.map} +1 -1
- package/dist/{daemon-lifecycle-journal-BHCda5cr.js → daemon-lifecycle-journal-DrDyXoUO.js} +2 -2
- package/dist/{daemon-lifecycle-journal-BHCda5cr.js.map → daemon-lifecycle-journal-DrDyXoUO.js.map} +1 -1
- package/dist/{daemon-service-runtime-DYq2FIVh.js → daemon-service-runtime-D-tDDWWf.js} +2 -2
- package/dist/{daemon-service-runtime-DYq2FIVh.js.map → daemon-service-runtime-D-tDDWWf.js.map} +1 -1
- package/dist/{daemon-service-update-coordinator-BUsyLme1.js → daemon-service-update-coordinator-ykoOjGCd.js} +10 -10
- package/dist/{daemon-service-update-coordinator-BUsyLme1.js.map → daemon-service-update-coordinator-ykoOjGCd.js.map} +1 -1
- package/dist/{dispatch-owned-runtime-BbFZbSCZ.js → dispatch-owned-runtime-eRa3wkl9.js} +6 -6
- package/dist/{dispatch-owned-runtime-BbFZbSCZ.js.map → dispatch-owned-runtime-eRa3wkl9.js.map} +1 -1
- package/dist/{dist-Ccpvj1tf.js → dist-CaCD0K8a.js} +2 -2
- package/dist/{dist-Ccpvj1tf.js.map → dist-CaCD0K8a.js.map} +1 -1
- package/dist/{dist-Co4QfNdK.js → dist-DEjtwiDJ.js} +2 -2
- package/dist/{dist-Co4QfNdK.js.map → dist-DEjtwiDJ.js.map} +1 -1
- package/dist/{dist-Be3IwaFl.js → dist-DGNsLSYJ.js} +1 -1
- package/dist/{elapsed-time-LyPBZcr1.js → elapsed-time-BnibmBPb.js} +5 -5
- package/dist/{elapsed-time-LyPBZcr1.js.map → elapsed-time-BnibmBPb.js.map} +1 -1
- package/dist/{entry-7fJyrzKV.js → entry-CVxgr9uQ.js} +7 -7
- package/dist/{entry-7fJyrzKV.js.map → entry-CVxgr9uQ.js.map} +1 -1
- package/dist/{installation-inventory-UQLiccH6.js → installation-inventory-HHLOQ2g7.js} +3 -3
- package/dist/{installation-inventory-UQLiccH6.js.map → installation-inventory-HHLOQ2g7.js.map} +1 -1
- package/dist/{installer-nI8qVBer.js → installer-Bg4KA0DR.js} +2 -2
- package/dist/{installer-nI8qVBer.js.map → installer-Bg4KA0DR.js.map} +1 -1
- package/dist/{meta-api-JNwpu5-2.js → meta-api-CjvtAPvQ.js} +4 -4
- package/dist/{meta-api-JNwpu5-2.js.map → meta-api-CjvtAPvQ.js.map} +1 -1
- package/dist/{openmeld-maintenance-worker-BgWOmRDu.js → openmeld-maintenance-worker-Cwv6_5UL.js} +9 -9
- package/dist/{openmeld-maintenance-worker-BgWOmRDu.js.map → openmeld-maintenance-worker-Cwv6_5UL.js.map} +1 -1
- package/dist/{openmeld-DDUAg1-S.js → openmeld-o_rTSEOO.js} +31 -31
- package/dist/{openmeld-DDUAg1-S.js.map → openmeld-o_rTSEOO.js.map} +1 -1
- package/dist/{openmeld-tools-update-join-CK54PNzJ.js → openmeld-tools-update-join-IFQf70sm.js} +4 -4
- package/dist/{openmeld-tools-update-join-CK54PNzJ.js.map → openmeld-tools-update-join-IFQf70sm.js.map} +1 -1
- package/dist/openmeld.js +4 -4
- package/dist/{prepare-provider-runtime-DAiq8vyv.js → prepare-provider-runtime-B_huS5DY.js} +890 -39
- package/dist/prepare-provider-runtime-B_huS5DY.js.map +1 -0
- package/dist/{prepare-session-executor-CFqmUlIh.js → prepare-session-executor-WWjgnqsh.js} +18 -18
- package/dist/{prepare-session-executor-CFqmUlIh.js.map → prepare-session-executor-WWjgnqsh.js.map} +1 -1
- package/dist/{process-channel-CTPL81j6.js → process-channel-C2dB41fO.js} +2 -2
- package/dist/{process-channel-CTPL81j6.js.map → process-channel-C2dB41fO.js.map} +1 -1
- package/dist/{runtime-B5qYKA19.js → runtime-DjEQja8c.js} +16 -16
- package/dist/{runtime-B5qYKA19.js.map → runtime-DjEQja8c.js.map} +1 -1
- package/dist/{runtime-agent-controller-reporting-submission-DLxVsqpW.js → runtime-agent-controller-reporting-submission-CRS5CwMp.js} +14 -25
- package/dist/runtime-agent-controller-reporting-submission-CRS5CwMp.js.map +1 -0
- package/dist/{runtime-transport-DyBmX7ds.js → runtime-transport-B-GZhwVt.js} +3 -1
- package/dist/{runtime-transport-DyBmX7ds.js.map → runtime-transport-B-GZhwVt.js.map} +1 -1
- package/dist/{service-CP8OUj6f.js → service-CleUczqJ.js} +18 -18
- package/dist/{service-CP8OUj6f.js.map → service-CleUczqJ.js.map} +1 -1
- package/dist/{service-account-authorization-CdyvPbvg.js → service-account-authorization-s1bXEswT.js} +2 -2
- package/dist/{service-account-authorization-CdyvPbvg.js.map → service-account-authorization-s1bXEswT.js.map} +1 -1
- package/dist/{service-account-control-DoUzhuAB.js → service-account-control-CjZ5uqK4.js} +9 -9
- package/dist/{service-account-control-DoUzhuAB.js.map → service-account-control-CjZ5uqK4.js.map} +1 -1
- package/dist/{service-control-capabilities-DBwPbnh8.js → service-control-capabilities-Bcho1Rwq.js} +1 -1
- package/dist/{service-control-capabilities-aDlHjg5W.js → service-control-capabilities-D5izhuhD.js} +3 -3
- package/dist/{service-control-capabilities-aDlHjg5W.js.map → service-control-capabilities-D5izhuhD.js.map} +1 -1
- package/dist/{state-BEY9weSc.js → state-CbrhgfNh.js} +2 -2
- package/dist/{state-BEY9weSc.js.map → state-CbrhgfNh.js.map} +1 -1
- package/dist/{updates-api-D4T5RACL.js → updates-api-B7x39-DR.js} +9 -9
- package/dist/{updates-api-D4T5RACL.js.map → updates-api-B7x39-DR.js.map} +1 -1
- package/dist/upgrade-636PQBli.js +4 -0
- package/dist/{upgrade-BplZgGrz.js → upgrade-BQSA2LfT.js} +7 -7
- package/dist/{upgrade-BplZgGrz.js.map → upgrade-BQSA2LfT.js.map} +1 -1
- package/package.json +10 -10
- package/dist/auth-session-CCLabxRT.js +0 -4
- package/dist/command-DApK5Fss.js.map +0 -1
- package/dist/prepare-provider-runtime-DAiq8vyv.js.map +0 -1
- package/dist/runtime-agent-controller-reporting-submission-DLxVsqpW.js.map +0 -1
- package/dist/upgrade-foZUS_GZ.js +0 -4
package/dist/{service-account-authorization-CdyvPbvg.js → service-account-authorization-s1bXEswT.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { D as openMeldRootDir, F as resolveOpenMeldRootDir, I as resolveOpenMeldServiceOwnedPathInput } from "./paths-De9xdA2h.js";
|
|
4
|
-
import { D as ServiceAccountAdmissionError, M as withAuthSessionTransitionMutationLock, O as admitServiceAccountOperation, w as withAdmittedServiceSession, y as readServiceAdmissionSessionWithOwnership } from "./auth-session-
|
|
4
|
+
import { D as ServiceAccountAdmissionError, M as withAuthSessionTransitionMutationLock, O as admitServiceAccountOperation, w as withAdmittedServiceSession, y as readServiceAdmissionSessionWithOwnership } from "./auth-session-B3oyTcSI.js";
|
|
5
5
|
import { r as readDaemonRuntimeLease } from "./daemon-runtime-lease-Bv6vhqOe.js";
|
|
6
6
|
import { i as readDaemonServiceContract } from "./daemon-service-contract-COPKbCy_.js";
|
|
7
7
|
import { t as resolveOpenMeldEnvironmentTarget } from "./openmeld-environment-target-BgYR6ozy.js";
|
|
@@ -53,4 +53,4 @@ async function admitServiceAccountStop(input) {
|
|
|
53
53
|
//#endregion
|
|
54
54
|
export { resolveServiceAccountIdentity as n, runServiceAccountCarrier as r, admitServiceAccountStop as t };
|
|
55
55
|
|
|
56
|
-
//# sourceMappingURL=service-account-authorization-
|
|
56
|
+
//# sourceMappingURL=service-account-authorization-s1bXEswT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-account-authorization-
|
|
1
|
+
{"version":3,"file":"service-account-authorization-s1bXEswT.js","names":[],"sources":["../src/local-service/lifecycle/service-account-authorization.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport type { ServiceAccountAdmissionIdentity } from \"@openmeld/schemas\";\nimport {\n readServiceAdmissionSessionWithOwnership,\n type StoredAuthSession,\n withAdmittedServiceSession,\n} from \"../../config/auth-session\";\nimport { withAuthSessionTransitionMutationLock } from \"../../config/auth-session-transition-lock\";\nimport { readDaemonRuntimeLease } from \"../../config/daemon-runtime-lease\";\nimport { readDaemonServiceContract } from \"../../config/daemon-service-contract\";\nimport { resolveOpenMeldEnvironmentTarget } from \"../../config/openmeld-environment-target\";\nimport {\n openMeldRootDir,\n resolveOpenMeldRootDir,\n resolveOpenMeldServiceOwnedPathInput,\n} from \"../../config/paths\";\nimport {\n admitServiceAccountOperation,\n ServiceAccountAdmissionError,\n} from \"../../config/service-account-admission\";\n\ntype Contract = NonNullable<\n Awaited<ReturnType<typeof readDaemonServiceContract>>\n>;\nfunction refused(reason: string, message: string): never {\n throw new ServiceAccountAdmissionError(reason, message);\n}\n\nexport async function resolveServiceAccountIdentity(\n session: StoredAuthSession,\n contract: Contract\n): Promise<ServiceAccountAdmissionIdentity> {\n const target = await resolveOpenMeldEnvironmentTarget();\n if (\n resolve(openMeldRootDir()) !==\n resolve(resolveOpenMeldRootDir(resolveOpenMeldServiceOwnedPathInput())) ||\n contract.lane !== target.preset ||\n contract.gatewayUrl !== target.gatewayUrl ||\n session.authBaseUrl !== target.authBaseUrl ||\n !contract.ownerUserId ||\n contract.ownerUserId !== session.user?.id ||\n !contract.connectedComputerId\n ) {\n refused(\n \"ownership_mismatch\",\n \"This Service does not match the signed-in account or environment. Reconnect it through OpenMeld setup before trying again.\"\n );\n }\n return {\n accountId: contract.ownerUserId,\n authBaseUrl: session.authBaseUrl,\n clientId: session.clientId,\n gatewayUrl: target.gatewayUrl,\n lane: target.preset,\n deviceId: contract.deviceId,\n contractGeneration: contract.generation,\n };\n}\n\nexport async function runServiceAccountCarrier<T>(\n id: string,\n run: () => Promise<T>\n): Promise<T> {\n const session = await withAuthSessionTransitionMutationLock(async () => {\n const local = await readServiceAdmissionSessionWithOwnership();\n const contract = await readDaemonServiceContract();\n if (!contract || contract.desiredState !== \"background\") {\n refused(\n \"cancelled\",\n \"This Service startup is no longer authorized. Start the Service again from the matching account.\"\n );\n }\n await admitServiceAccountOperation({\n id,\n operation: \"start\",\n identity: await resolveServiceAccountIdentity(local, contract),\n });\n return local;\n });\n return await withAdmittedServiceSession(session, run);\n}\n\nexport async function admitServiceAccountStop(input: {\n id: string;\n ownerUserId: string;\n deviceId: string;\n contractGeneration: number;\n commit: () => void;\n}): Promise<void> {\n await withAuthSessionTransitionMutationLock(async () => {\n const session = await readServiceAdmissionSessionWithOwnership();\n const contract = await readDaemonServiceContract();\n const lease = await readDaemonRuntimeLease();\n if (\n !(contract && lease) ||\n lease.pid !== process.pid ||\n contract.generation !== input.contractGeneration ||\n contract.ownerUserId !== input.ownerUserId ||\n contract.deviceId !== input.deviceId\n ) {\n refused(\n \"ownership_changed\",\n \"The running Service changed before this Stop was accepted. Check its status and try again.\"\n );\n }\n await admitServiceAccountOperation({\n id: input.id,\n operation: \"stop\",\n identity: await resolveServiceAccountIdentity(session, contract),\n commit: input.commit,\n });\n });\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAS,QAAQ,QAAgB,SAAwB;CACvD,MAAM,IAAI,6BAA6B,QAAQ,OAAO;AACxD;AAEA,eAAsB,8BACpB,SACA,UAC0C;CAC1C,MAAM,SAAS,MAAM,iCAAiC;CACtD,IACE,QAAQ,gBAAgB,CAAC,MACvB,QAAQ,uBAAuB,qCAAqC,CAAC,CAAC,KACxE,SAAS,SAAS,OAAO,UACzB,SAAS,eAAe,OAAO,cAC/B,QAAQ,gBAAgB,OAAO,eAC/B,CAAC,SAAS,eACV,SAAS,gBAAgB,QAAQ,MAAM,MACvC,CAAC,SAAS,qBAEV,QACE,sBACA,4HACF;CAEF,OAAO;EACL,WAAW,SAAS;EACpB,aAAa,QAAQ;EACrB,UAAU,QAAQ;EAClB,YAAY,OAAO;EACnB,MAAM,OAAO;EACb,UAAU,SAAS;EACnB,oBAAoB,SAAS;CAC/B;AACF;AAEA,eAAsB,yBACpB,IACA,KACY;CAiBZ,OAAO,MAAM,2BAA2B,MAhBlB,sCAAsC,YAAY;EACtE,MAAM,QAAQ,MAAM,yCAAyC;EAC7D,MAAM,WAAW,MAAM,0BAA0B;EACjD,IAAI,CAAC,YAAY,SAAS,iBAAiB,cACzC,QACE,aACA,kGACF;EAEF,MAAM,6BAA6B;GACjC;GACA,WAAW;GACX,UAAU,MAAM,8BAA8B,OAAO,QAAQ;EAC/D,CAAC;EACD,OAAO;CACT,CAAC,GACgD,GAAG;AACtD;AAEA,eAAsB,wBAAwB,OAM5B;CAChB,MAAM,sCAAsC,YAAY;EACtD,MAAM,UAAU,MAAM,yCAAyC;EAC/D,MAAM,WAAW,MAAM,0BAA0B;EACjD,MAAM,QAAQ,MAAM,uBAAuB;EAC3C,IACE,EAAE,YAAY,UACd,MAAM,QAAQ,QAAQ,OACtB,SAAS,eAAe,MAAM,sBAC9B,SAAS,gBAAgB,MAAM,eAC/B,SAAS,aAAa,MAAM,UAE5B,QACE,qBACA,4FACF;EAEF,MAAM,6BAA6B;GACjC,IAAI,MAAM;GACV,WAAW;GACX,UAAU,MAAM,8BAA8B,SAAS,QAAQ;GAC/D,QAAQ,MAAM;EAChB,CAAC;CACH,CAAC;AACH"}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { A as readServiceAccountAdmission, D as ServiceAccountAdmissionError, M as withAuthSessionTransitionMutationLock, d as getAuthSessionState, j as reserveServiceAccountAdmission, k as cancelServiceAccountAdmission, o as buildStoredAuthSessionIdentity, w as withAdmittedServiceSession, y as readServiceAdmissionSessionWithOwnership } from "./auth-session-
|
|
4
|
-
import { T as createQuietPresenter, d as runDaemonServiceDetached, m as runDaemonStop, mt as fetchAuthUserSnapshot } from "./service-
|
|
3
|
+
import { A as readServiceAccountAdmission, D as ServiceAccountAdmissionError, M as withAuthSessionTransitionMutationLock, d as getAuthSessionState, j as reserveServiceAccountAdmission, k as cancelServiceAccountAdmission, o as buildStoredAuthSessionIdentity, w as withAdmittedServiceSession, y as readServiceAdmissionSessionWithOwnership } from "./auth-session-B3oyTcSI.js";
|
|
4
|
+
import { T as createQuietPresenter, d as runDaemonServiceDetached, m as runDaemonStop, mt as fetchAuthUserSnapshot } from "./service-CleUczqJ.js";
|
|
5
5
|
import { r as serviceAccountControlRequestSchema } from "./service-account-admission-BfdJ-kKR.js";
|
|
6
|
-
import { r as readCurrentDaemonRuntimeContext } from "./daemon-service-runtime-
|
|
7
|
-
import "./daemon-device-id-
|
|
6
|
+
import { r as readCurrentDaemonRuntimeContext } from "./daemon-service-runtime-D-tDDWWf.js";
|
|
7
|
+
import "./daemon-device-id-Dwm7CHtX.js";
|
|
8
8
|
import { r as readDaemonRuntimeLease } from "./daemon-runtime-lease-Bv6vhqOe.js";
|
|
9
9
|
import { i as readProcessStartIdentity } from "./process-identity-BRbhGGTM.js";
|
|
10
|
-
import { Wt as resolveInstalledDaemonSystemServiceCommandSpec } from "./daemon-service-update-coordinator-
|
|
10
|
+
import { Wt as resolveInstalledDaemonSystemServiceCommandSpec } from "./daemon-service-update-coordinator-ykoOjGCd.js";
|
|
11
11
|
import { K as withDaemonServiceRunLock } from "./daemon-state-Dte9re5V.js";
|
|
12
12
|
import { a as upsertDaemonServiceContract, i as readDaemonServiceContract } from "./daemon-service-contract-COPKbCy_.js";
|
|
13
|
-
import { n as resolveServiceAccountIdentity } from "./service-account-authorization-
|
|
14
|
-
import { S as requestLocalDaemonShutdown, y as LocalDaemonControlPlaneClientError } from "./daemon-lifecycle-journal-
|
|
13
|
+
import { n as resolveServiceAccountIdentity } from "./service-account-authorization-s1bXEswT.js";
|
|
14
|
+
import { S as requestLocalDaemonShutdown, y as LocalDaemonControlPlaneClientError } from "./daemon-lifecycle-journal-DrDyXoUO.js";
|
|
15
15
|
import { S as resolveDaemonServiceManager } from "./daemon-service-manager-BXAp21GH.js";
|
|
16
|
-
import { n as resolveRuntimeContext } from "./context-
|
|
16
|
+
import { n as resolveRuntimeContext } from "./context-43g3bIde.js";
|
|
17
17
|
import { setTimeout } from "node:timers/promises";
|
|
18
18
|
//#region src/commands/service-account-control.ts
|
|
19
19
|
function refused(reason, message) {
|
|
@@ -145,4 +145,4 @@ async function requestAccountCheckedServiceStop({ id, manager }) {
|
|
|
145
145
|
//#endregion
|
|
146
146
|
export { runServiceAccountControl as t };
|
|
147
147
|
|
|
148
|
-
//# sourceMappingURL=service-account-control-
|
|
148
|
+
//# sourceMappingURL=service-account-control-CjZ5uqK4.js.map
|
package/dist/{service-account-control-DoUzhuAB.js.map → service-account-control-CjZ5uqK4.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-account-control-DoUzhuAB.js","names":["delay"],"sources":["../src/commands/service-account-control.ts"],"sourcesContent":["import { setTimeout as delay } from \"node:timers/promises\";\nimport {\n SERVICE_ACCOUNT_STOP_REFUSED_CODE,\n type ServiceAccountControlRequest,\n serviceAccountControlRequestSchema,\n} from \"@openmeld/schemas\";\nimport {\n buildStoredAuthSessionIdentity,\n getAuthSessionState,\n readServiceAdmissionSessionWithOwnership,\n type StoredAuthSession,\n withAdmittedServiceSession,\n} from \"../config/auth-session\";\nimport { withAuthSessionTransitionMutationLock } from \"../config/auth-session-transition-lock\";\nimport { readDaemonRuntimeLease } from \"../config/daemon-runtime-lease\";\nimport {\n readDaemonServiceContract,\n upsertDaemonServiceContract,\n} from \"../config/daemon-service-contract\";\nimport { withDaemonServiceRunLock } from \"../config/daemon-state\";\nimport {\n cancelServiceAccountAdmission,\n readServiceAccountAdmission,\n reserveServiceAccountAdmission,\n ServiceAccountAdmissionError,\n} from \"../config/service-account-admission\";\nimport {\n LocalDaemonControlPlaneClientError,\n requestLocalDaemonShutdown,\n} from \"../local-service/control-plane/client\";\nimport { CONTROLLED_SHUTDOWN_REQUEST_TIMEOUT_MS } from \"../local-service/core/constants\";\nimport { resolveInstalledDaemonSystemServiceCommandSpec } from \"../local-service/lifecycle/daemon-service-command-spec\";\nimport {\n type DaemonServiceManager,\n resolveDaemonServiceManager,\n} from \"../local-service/lifecycle/daemon-service-manager\";\nimport { readCurrentDaemonRuntimeContext } from \"../local-service/lifecycle/daemon-service-runtime\";\nimport { resolveServiceAccountIdentity } from \"../local-service/lifecycle/service-account-authorization\";\nimport { resolveRuntimeContext } from \"../runtime/context\";\nimport { readProcessStartIdentity } from \"../system/process-identity\";\nimport { fetchAuthUserSnapshot } from \"./auth-device-session-client\";\nimport { runDaemonServiceDetached, runDaemonStop } from \"./service\";\nimport { createQuietPresenter } from \"./service-output\";\n\ntype Contract = NonNullable<\n Awaited<ReturnType<typeof readDaemonServiceContract>>\n>;\n\nfunction refused(reason: string, message: string): never {\n throw new ServiceAccountAdmissionError(reason, message);\n}\n\nexport async function runServiceAccountControl(\n request: ServiceAccountControlRequest,\n expectedSessionIdentity?: string\n): Promise<void> {\n const parsed = serviceAccountControlRequestSchema.safeParse(request);\n if (!parsed.success) {\n refused(\n \"missing_account\",\n \"Choose a signed-in account before controlling this Service.\"\n );\n }\n const input = parsed.data;\n const auth = await getAuthSessionState();\n if (auth.state !== \"valid\" || !auth.session) {\n refused(\n \"authentication_required\",\n \"Sign in to the CLI with the matching account and try again.\"\n );\n }\n const preparedSession = auth.session;\n if (preparedSession.user?.id !== input.expectedAccount) {\n refused(\n \"account_mismatch\",\n \"The CLI is signed in to a different account. Sign in with the matching account and try again.\"\n );\n }\n // The shared Auth endpoint proves the principal. Local metadata alone does not.\n const user = await fetchAuthUserSnapshot({\n authBaseUrl: preparedSession.authBaseUrl,\n accessToken: preparedSession.accessToken,\n });\n if (user.id !== input.expectedAccount) {\n refused(\n \"account_mismatch\",\n \"The CLI session belongs to a different account. Sign in again and retry.\"\n );\n }\n\n await withDaemonServiceRunLock(async () => {\n const contract = await readDaemonServiceContract();\n if (!contract) {\n refused(\n \"ownership_unknown\",\n \"Connect this computer through OpenMeld setup before controlling its Service.\"\n );\n }\n const observed = await readCurrentDaemonRuntimeContext();\n const lease = await readDaemonRuntimeLease();\n if (\n input.operation === \"start\" &&\n observed.effectiveRuntimeStatus !== \"not_running\"\n ) {\n refused(\n \"busy\",\n \"The Service is already running or its state is uncertain. Check Service status before trying again.\"\n );\n }\n if (\n input.operation === \"stop\" &&\n (observed.effectiveRuntimeStatus !== \"running\" ||\n !lease ||\n lease.generation !== contract.generation)\n ) {\n refused(\n \"ownership_unknown\",\n \"OpenMeld could not verify the running Service. Check Service status before trying again.\"\n );\n }\n\n let boundSession: StoredAuthSession = preparedSession;\n const reservation = await withAuthSessionTransitionMutationLock(\n async () => {\n boundSession = await readServiceAdmissionSessionWithOwnership();\n if (\n (expectedSessionIdentity !== undefined &&\n buildStoredAuthSessionIdentity(boundSession) !==\n expectedSessionIdentity) ||\n boundSession.accessToken !== preparedSession.accessToken ||\n boundSession.createdAt !== preparedSession.createdAt ||\n boundSession.user?.id !== input.expectedAccount\n ) {\n refused(\n \"account_changed\",\n \"The CLI sign-in changed before this action was accepted. Check the account and try again.\"\n );\n }\n const current = await readDaemonServiceContract();\n if (!current || JSON.stringify(current) !== JSON.stringify(contract)) {\n refused(\n \"ownership_changed\",\n \"The Service changed before this action was accepted. Check its status and try again.\"\n );\n }\n const identity = await resolveServiceAccountIdentity(\n boundSession,\n contract\n );\n if (\n input.operation === \"start\" &&\n contract.desiredState !== \"background\"\n ) {\n identity.contractGeneration += 1;\n }\n return await reserveServiceAccountAdmission({\n operation: input.operation,\n identity,\n ...(input.operation === \"stop\" && lease\n ? {\n target: {\n ownerPid: lease.pid,\n ownerProcessStartedAt:\n readProcessStartIdentity(lease.pid) ??\n refused(\n \"ownership_unknown\",\n \"OpenMeld could not identify the Service process. Check its status and try again.\"\n ),\n },\n }\n : {}),\n });\n }\n );\n\n try {\n await withAdmittedServiceSession(boundSession, async () => {\n if (input.operation === \"stop\") {\n await stopReservedService(contract, reservation.id, lease?.pid ?? 0);\n return;\n }\n const manager =\n contract.serviceController === \"legacy-detached\"\n ? null\n : await resolveDaemonServiceManager(contract.serviceController);\n if (\n contract.serviceController !== \"legacy-detached\" &&\n !(manager && (await manager.status()).installed)\n ) {\n refused(\n \"installation_required\",\n \"This Service needs setup before it can start. Run OpenMeld setup and try again.\"\n );\n }\n await upsertDaemonServiceContract({\n ...contract,\n desiredState: \"background\",\n });\n if (contract.serviceController === \"legacy-detached\") {\n const runtime = await resolveRuntimeContext({ view: \"agent\" });\n await runDaemonServiceDetached({\n accountAdmissionId: reservation.id,\n deviceId: contract.deviceId,\n gatewayUrl: contract.gatewayUrl,\n heartbeatMs: contract.heartbeatMs,\n runtime,\n presenter: createQuietPresenter(runtime),\n mode: \"background\",\n });\n } else if (manager) {\n // Refresh the existing stopped supervisor definition with an immutable\n // generation argument. Never install a missing Service.\n await manager.deactivate();\n await manager.install(\n await resolveInstalledDaemonSystemServiceCommandSpec({\n controller: manager.controller,\n accountAdmissionId: reservation.id,\n })\n );\n await manager.start();\n }\n await waitForAdmittedService(reservation.id);\n });\n } finally {\n await cancelServiceAccountAdmission(reservation.id);\n }\n });\n}\n\nasync function waitForAdmittedService(id: string): Promise<void> {\n const deadline = Date.now() + 15_000;\n while (Date.now() < deadline) {\n const current = await readServiceAccountAdmission();\n const runtime = await readCurrentDaemonRuntimeContext();\n if (\n current?.id === id &&\n current.state === \"admitted\" &&\n current.carrier?.ownerPid === runtime.runtimeStatus.pid &&\n runtime.effectiveRuntimeStatus === \"running\"\n ) {\n return;\n }\n await delay(50);\n }\n refused(\n \"startup_unconfirmed\",\n \"OpenMeld could not confirm that this Service started. Check Service status before trying again.\"\n );\n}\n\nasync function stopReservedService(\n contract: Contract,\n id: string,\n pid: number\n): Promise<void> {\n const manager =\n contract.serviceController === \"legacy-detached\"\n ? null\n : await resolveDaemonServiceManager(contract.serviceController);\n await requestAccountCheckedServiceStop({ id, manager });\n const admitted = await readServiceAccountAdmission();\n if (\n admitted?.id !== id ||\n admitted.state !== \"admitted\" ||\n admitted.carrier?.ownerPid !== pid\n ) {\n refused(\n \"admission_unconfirmed\",\n \"OpenMeld could not verify that the matching Service accepted Stop. Check Service status before trying again.\"\n );\n }\n const current = await readCurrentDaemonRuntimeContext();\n if (current.runtimeStatus.pid !== null && current.runtimeStatus.pid !== pid) {\n refused(\n \"ownership_changed\",\n \"Another Service instance is now running. Its state was left unchanged.\"\n );\n }\n await runDaemonStop(\n { json: true, view: \"agent\" },\n {\n completedControlledShutdownOwnerPid: pid,\n }\n );\n}\n\nexport async function requestAccountCheckedServiceStop({\n id,\n manager,\n}: {\n id: string;\n manager: Pick<\n DaemonServiceManager,\n \"status\" | \"disableAutostart\" | \"enableAutostart\"\n > | null;\n}): Promise<void> {\n const wasEnabled = manager ? (await manager.status()).enabled : false;\n if (manager) {\n await manager.disableAutostart();\n }\n // No compatibility fallback: only the verified carrier may admit this stop.\n try {\n const shutdown = await requestLocalDaemonShutdown({\n payload: {\n accountAdmissionId: id,\n mode: \"graceful\",\n gracePeriodMs: 2000,\n },\n timeoutMs: CONTROLLED_SHUTDOWN_REQUEST_TIMEOUT_MS,\n });\n if (!shutdown.accepted) {\n throw new Error(\"The Service did not confirm controlled shutdown.\");\n }\n } catch (error) {\n if (\n manager &&\n wasEnabled &&\n error instanceof LocalDaemonControlPlaneClientError &&\n error.code === SERVICE_ACCOUNT_STOP_REFUSED_CODE\n ) {\n try {\n await manager.enableAutostart();\n } catch (restoreError) {\n throw new AggregateError(\n [error, restoreError],\n \"Stop was refused and its previous autostart setting could not be restored.\"\n );\n }\n }\n if (\n !(\n error instanceof LocalDaemonControlPlaneClientError &&\n error.code === SERVICE_ACCOUNT_STOP_REFUSED_CODE\n )\n ) {\n const detail = error instanceof Error ? error.message : String(error);\n refused(\n \"stop_unconfirmed\",\n `Stop may already be in progress. ${manager ? \"Autostart remains disabled. \" : \"\"}Check Service status before trying again. ${detail}`\n );\n }\n throw error;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service-account-control-CjZ5uqK4.js","names":["delay"],"sources":["../src/commands/service-account-control.ts"],"sourcesContent":["import { setTimeout as delay } from \"node:timers/promises\";\nimport {\n SERVICE_ACCOUNT_STOP_REFUSED_CODE,\n type ServiceAccountControlRequest,\n serviceAccountControlRequestSchema,\n} from \"@openmeld/schemas\";\nimport {\n buildStoredAuthSessionIdentity,\n getAuthSessionState,\n readServiceAdmissionSessionWithOwnership,\n type StoredAuthSession,\n withAdmittedServiceSession,\n} from \"../config/auth-session\";\nimport { withAuthSessionTransitionMutationLock } from \"../config/auth-session-transition-lock\";\nimport { readDaemonRuntimeLease } from \"../config/daemon-runtime-lease\";\nimport {\n readDaemonServiceContract,\n upsertDaemonServiceContract,\n} from \"../config/daemon-service-contract\";\nimport { withDaemonServiceRunLock } from \"../config/daemon-state\";\nimport {\n cancelServiceAccountAdmission,\n readServiceAccountAdmission,\n reserveServiceAccountAdmission,\n ServiceAccountAdmissionError,\n} from \"../config/service-account-admission\";\nimport {\n LocalDaemonControlPlaneClientError,\n requestLocalDaemonShutdown,\n} from \"../local-service/control-plane/client\";\nimport { CONTROLLED_SHUTDOWN_REQUEST_TIMEOUT_MS } from \"../local-service/core/constants\";\nimport { resolveInstalledDaemonSystemServiceCommandSpec } from \"../local-service/lifecycle/daemon-service-command-spec\";\nimport {\n type DaemonServiceManager,\n resolveDaemonServiceManager,\n} from \"../local-service/lifecycle/daemon-service-manager\";\nimport { readCurrentDaemonRuntimeContext } from \"../local-service/lifecycle/daemon-service-runtime\";\nimport { resolveServiceAccountIdentity } from \"../local-service/lifecycle/service-account-authorization\";\nimport { resolveRuntimeContext } from \"../runtime/context\";\nimport { readProcessStartIdentity } from \"../system/process-identity\";\nimport { fetchAuthUserSnapshot } from \"./auth-device-session-client\";\nimport { runDaemonServiceDetached, runDaemonStop } from \"./service\";\nimport { createQuietPresenter } from \"./service-output\";\n\ntype Contract = NonNullable<\n Awaited<ReturnType<typeof readDaemonServiceContract>>\n>;\n\nfunction refused(reason: string, message: string): never {\n throw new ServiceAccountAdmissionError(reason, message);\n}\n\nexport async function runServiceAccountControl(\n request: ServiceAccountControlRequest,\n expectedSessionIdentity?: string\n): Promise<void> {\n const parsed = serviceAccountControlRequestSchema.safeParse(request);\n if (!parsed.success) {\n refused(\n \"missing_account\",\n \"Choose a signed-in account before controlling this Service.\"\n );\n }\n const input = parsed.data;\n const auth = await getAuthSessionState();\n if (auth.state !== \"valid\" || !auth.session) {\n refused(\n \"authentication_required\",\n \"Sign in to the CLI with the matching account and try again.\"\n );\n }\n const preparedSession = auth.session;\n if (preparedSession.user?.id !== input.expectedAccount) {\n refused(\n \"account_mismatch\",\n \"The CLI is signed in to a different account. Sign in with the matching account and try again.\"\n );\n }\n // The shared Auth endpoint proves the principal. Local metadata alone does not.\n const user = await fetchAuthUserSnapshot({\n authBaseUrl: preparedSession.authBaseUrl,\n accessToken: preparedSession.accessToken,\n });\n if (user.id !== input.expectedAccount) {\n refused(\n \"account_mismatch\",\n \"The CLI session belongs to a different account. Sign in again and retry.\"\n );\n }\n\n await withDaemonServiceRunLock(async () => {\n const contract = await readDaemonServiceContract();\n if (!contract) {\n refused(\n \"ownership_unknown\",\n \"Connect this computer through OpenMeld setup before controlling its Service.\"\n );\n }\n const observed = await readCurrentDaemonRuntimeContext();\n const lease = await readDaemonRuntimeLease();\n if (\n input.operation === \"start\" &&\n observed.effectiveRuntimeStatus !== \"not_running\"\n ) {\n refused(\n \"busy\",\n \"The Service is already running or its state is uncertain. Check Service status before trying again.\"\n );\n }\n if (\n input.operation === \"stop\" &&\n (observed.effectiveRuntimeStatus !== \"running\" ||\n !lease ||\n lease.generation !== contract.generation)\n ) {\n refused(\n \"ownership_unknown\",\n \"OpenMeld could not verify the running Service. Check Service status before trying again.\"\n );\n }\n\n let boundSession: StoredAuthSession = preparedSession;\n const reservation = await withAuthSessionTransitionMutationLock(\n async () => {\n boundSession = await readServiceAdmissionSessionWithOwnership();\n if (\n (expectedSessionIdentity !== undefined &&\n buildStoredAuthSessionIdentity(boundSession) !==\n expectedSessionIdentity) ||\n boundSession.accessToken !== preparedSession.accessToken ||\n boundSession.createdAt !== preparedSession.createdAt ||\n boundSession.user?.id !== input.expectedAccount\n ) {\n refused(\n \"account_changed\",\n \"The CLI sign-in changed before this action was accepted. Check the account and try again.\"\n );\n }\n const current = await readDaemonServiceContract();\n if (!current || JSON.stringify(current) !== JSON.stringify(contract)) {\n refused(\n \"ownership_changed\",\n \"The Service changed before this action was accepted. Check its status and try again.\"\n );\n }\n const identity = await resolveServiceAccountIdentity(\n boundSession,\n contract\n );\n if (\n input.operation === \"start\" &&\n contract.desiredState !== \"background\"\n ) {\n identity.contractGeneration += 1;\n }\n return await reserveServiceAccountAdmission({\n operation: input.operation,\n identity,\n ...(input.operation === \"stop\" && lease\n ? {\n target: {\n ownerPid: lease.pid,\n ownerProcessStartedAt:\n readProcessStartIdentity(lease.pid) ??\n refused(\n \"ownership_unknown\",\n \"OpenMeld could not identify the Service process. Check its status and try again.\"\n ),\n },\n }\n : {}),\n });\n }\n );\n\n try {\n await withAdmittedServiceSession(boundSession, async () => {\n if (input.operation === \"stop\") {\n await stopReservedService(contract, reservation.id, lease?.pid ?? 0);\n return;\n }\n const manager =\n contract.serviceController === \"legacy-detached\"\n ? null\n : await resolveDaemonServiceManager(contract.serviceController);\n if (\n contract.serviceController !== \"legacy-detached\" &&\n !(manager && (await manager.status()).installed)\n ) {\n refused(\n \"installation_required\",\n \"This Service needs setup before it can start. Run OpenMeld setup and try again.\"\n );\n }\n await upsertDaemonServiceContract({\n ...contract,\n desiredState: \"background\",\n });\n if (contract.serviceController === \"legacy-detached\") {\n const runtime = await resolveRuntimeContext({ view: \"agent\" });\n await runDaemonServiceDetached({\n accountAdmissionId: reservation.id,\n deviceId: contract.deviceId,\n gatewayUrl: contract.gatewayUrl,\n heartbeatMs: contract.heartbeatMs,\n runtime,\n presenter: createQuietPresenter(runtime),\n mode: \"background\",\n });\n } else if (manager) {\n // Refresh the existing stopped supervisor definition with an immutable\n // generation argument. Never install a missing Service.\n await manager.deactivate();\n await manager.install(\n await resolveInstalledDaemonSystemServiceCommandSpec({\n controller: manager.controller,\n accountAdmissionId: reservation.id,\n })\n );\n await manager.start();\n }\n await waitForAdmittedService(reservation.id);\n });\n } finally {\n await cancelServiceAccountAdmission(reservation.id);\n }\n });\n}\n\nasync function waitForAdmittedService(id: string): Promise<void> {\n const deadline = Date.now() + 15_000;\n while (Date.now() < deadline) {\n const current = await readServiceAccountAdmission();\n const runtime = await readCurrentDaemonRuntimeContext();\n if (\n current?.id === id &&\n current.state === \"admitted\" &&\n current.carrier?.ownerPid === runtime.runtimeStatus.pid &&\n runtime.effectiveRuntimeStatus === \"running\"\n ) {\n return;\n }\n await delay(50);\n }\n refused(\n \"startup_unconfirmed\",\n \"OpenMeld could not confirm that this Service started. Check Service status before trying again.\"\n );\n}\n\nasync function stopReservedService(\n contract: Contract,\n id: string,\n pid: number\n): Promise<void> {\n const manager =\n contract.serviceController === \"legacy-detached\"\n ? null\n : await resolveDaemonServiceManager(contract.serviceController);\n await requestAccountCheckedServiceStop({ id, manager });\n const admitted = await readServiceAccountAdmission();\n if (\n admitted?.id !== id ||\n admitted.state !== \"admitted\" ||\n admitted.carrier?.ownerPid !== pid\n ) {\n refused(\n \"admission_unconfirmed\",\n \"OpenMeld could not verify that the matching Service accepted Stop. Check Service status before trying again.\"\n );\n }\n const current = await readCurrentDaemonRuntimeContext();\n if (current.runtimeStatus.pid !== null && current.runtimeStatus.pid !== pid) {\n refused(\n \"ownership_changed\",\n \"Another Service instance is now running. Its state was left unchanged.\"\n );\n }\n await runDaemonStop(\n { json: true, view: \"agent\" },\n {\n completedControlledShutdownOwnerPid: pid,\n }\n );\n}\n\nexport async function requestAccountCheckedServiceStop({\n id,\n manager,\n}: {\n id: string;\n manager: Pick<\n DaemonServiceManager,\n \"status\" | \"disableAutostart\" | \"enableAutostart\"\n > | null;\n}): Promise<void> {\n const wasEnabled = manager ? (await manager.status()).enabled : false;\n if (manager) {\n await manager.disableAutostart();\n }\n // No compatibility fallback: only the verified carrier may admit this stop.\n try {\n const shutdown = await requestLocalDaemonShutdown({\n payload: {\n accountAdmissionId: id,\n mode: \"graceful\",\n gracePeriodMs: 2000,\n },\n timeoutMs: CONTROLLED_SHUTDOWN_REQUEST_TIMEOUT_MS,\n });\n if (!shutdown.accepted) {\n throw new Error(\"The Service did not confirm controlled shutdown.\");\n }\n } catch (error) {\n if (\n manager &&\n wasEnabled &&\n error instanceof LocalDaemonControlPlaneClientError &&\n error.code === SERVICE_ACCOUNT_STOP_REFUSED_CODE\n ) {\n try {\n await manager.enableAutostart();\n } catch (restoreError) {\n throw new AggregateError(\n [error, restoreError],\n \"Stop was refused and its previous autostart setting could not be restored.\"\n );\n }\n }\n if (\n !(\n error instanceof LocalDaemonControlPlaneClientError &&\n error.code === SERVICE_ACCOUNT_STOP_REFUSED_CODE\n )\n ) {\n const detail = error instanceof Error ? error.message : String(error);\n refused(\n \"stop_unconfirmed\",\n `Stop may already be in progress. ${manager ? \"Autostart remains disabled. \" : \"\"}Check Service status before trying again. ${detail}`\n );\n }\n throw error;\n }\n}\n"],"mappings":"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"}
|
package/dist/{service-control-capabilities-aDlHjg5W.js → service-control-capabilities-D5izhuhD.js}
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { a as serviceControlCarrierCapabilitySchema, i as serviceControlCapabilitiesSchema } from "./service-account-admission-BfdJ-kKR.js";
|
|
4
|
-
import { M as resolveAlignedDaemonActiveBundleEntryPath, S as daemonServiceBinaryExecutablePath, j as readDaemonActiveBundleState, r as readCurrentDaemonRuntimeContext } from "./daemon-service-runtime-
|
|
4
|
+
import { M as resolveAlignedDaemonActiveBundleEntryPath, S as daemonServiceBinaryExecutablePath, j as readDaemonActiveBundleState, r as readCurrentDaemonRuntimeContext } from "./daemon-service-runtime-D-tDDWWf.js";
|
|
5
5
|
import { i as readDaemonServiceContract } from "./daemon-service-contract-COPKbCy_.js";
|
|
6
|
-
import { w as sendLocalDaemonControlPlaneRequest } from "./daemon-lifecycle-journal-
|
|
6
|
+
import { w as sendLocalDaemonControlPlaneRequest } from "./daemon-lifecycle-journal-DrDyXoUO.js";
|
|
7
7
|
import { S as resolveDaemonServiceManager } from "./daemon-service-manager-BXAp21GH.js";
|
|
8
8
|
import { realpath } from "node:fs/promises";
|
|
9
9
|
import { execFile } from "node:child_process";
|
|
@@ -73,4 +73,4 @@ async function readServiceControlCapabilities(platform = process.platform) {
|
|
|
73
73
|
//#endregion
|
|
74
74
|
export { readServiceControlCapabilities as t };
|
|
75
75
|
|
|
76
|
-
//# sourceMappingURL=service-control-capabilities-
|
|
76
|
+
//# sourceMappingURL=service-control-capabilities-D5izhuhD.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-control-capabilities-
|
|
1
|
+
{"version":3,"file":"service-control-capabilities-D5izhuhD.js","names":[],"sources":["../src/commands/service-control-capabilities.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { realpath } from \"node:fs/promises\";\nimport { promisify } from \"node:util\";\nimport {\n serviceControlCapabilitiesSchema,\n serviceControlCarrierCapabilitySchema,\n} from \"@openmeld/schemas\";\nimport { readDaemonServiceContract } from \"../config/daemon-service-contract\";\nimport { sendLocalDaemonControlPlaneRequest } from \"../local-service/control-plane/client\";\nimport {\n daemonServiceBinaryExecutablePath,\n readDaemonActiveBundleState,\n resolveAlignedDaemonActiveBundleEntryPath,\n} from \"../local-service/lifecycle/daemon-service-bundle\";\nimport { resolveDaemonServiceManager } from \"../local-service/lifecycle/daemon-service-manager\";\nimport { readCurrentDaemonRuntimeContext } from \"../local-service/lifecycle/daemon-service-runtime\";\n\nasync function resolveCarrierProbe(\n platform: \"darwin\" | \"win32\",\n expectedVersion: string,\n binary: boolean\n) {\n if (platform === \"darwin\") {\n return {\n executable: await realpath(daemonServiceBinaryExecutablePath()),\n canonicalEntry: null,\n protocol: \"account-checked-service-control-v1\",\n };\n }\n // Probe the aligned immutable GUI carrier directly. For npm, bypass the\n // repairing launcher and use its verified JS entry with Start's exact Node.\n const entry = await resolveAlignedDaemonActiveBundleEntryPath({\n expectedVersion,\n });\n return entry\n ? {\n executable: await realpath(binary ? entry : process.execPath),\n canonicalEntry: binary ? null : await realpath(entry),\n protocol: binary\n ? \"account-checked-service-control-v3\"\n : \"account-checked-service-control-v2\",\n }\n : null;\n}\n\n/** Read only: never invoke the repairing npm launcher or a lifecycle operation. */\nexport async function readServiceControlCapabilities(\n platform: NodeJS.Platform = process.platform\n) {\n const unsupported = { deviceId: null, start: false, stop: false };\n if (platform !== \"darwin\" && platform !== \"win32\") {\n return unsupported;\n }\n const contract = await readDaemonServiceContract();\n const bundle = await readDaemonActiveBundleState();\n const binary = bundle?.bundleFormat === \"binary_v1\";\n if (\n contract?.serviceController !==\n (platform === \"win32\" ? \"windows-service\" : \"launchd\") ||\n !(\n binary ||\n (platform === \"win32\" && bundle?.bundleFormat === \"self_contained_v1\")\n )\n ) {\n return unsupported;\n }\n const manager = await resolveDaemonServiceManager(contract.serviceController);\n if (!(manager && (await manager.status()).installed)) {\n return unsupported;\n }\n // Guarded Start refreshes the supervisor command to this canonical executable.\n // Verify the executable that answered, so an old CLI delegating elsewhere\n // cannot advertise another binary's capability as its own.\n const probe = await resolveCarrierProbe(\n platform,\n contract.daemonVersion,\n binary\n );\n if (!probe) {\n return unsupported;\n }\n const { executable, canonicalEntry, protocol } = probe;\n const { stdout } = await promisify(execFile)(\n executable,\n [\n ...(canonicalEntry ? [canonicalEntry] : []),\n \"service\",\n \"control-carrier-capability\",\n \"--json\",\n ],\n { timeout: 10_000, maxBuffer: 16_384, windowsHide: true }\n );\n const carrier = serviceControlCarrierCapabilitySchema.safeParse(\n JSON.parse(stdout)\n );\n if (\n !carrier.success ||\n carrier.data.protocol !== protocol ||\n (await realpath(carrier.data.executable)) !== executable\n ) {\n return unsupported;\n }\n if (\n carrier.data.protocol === \"account-checked-service-control-v2\" &&\n (await realpath(carrier.data.entryScript)) !== canonicalEntry\n ) {\n return unsupported;\n }\n if (\n JSON.stringify(await readDaemonActiveBundleState()) !==\n JSON.stringify(bundle)\n ) {\n return unsupported;\n }\n const runtime = await readCurrentDaemonRuntimeContext();\n if (runtime.effectiveRuntimeStatus === \"not_running\") {\n return { deviceId: contract.deviceId, start: true, stop: false };\n }\n if (runtime.effectiveRuntimeStatus !== \"running\") {\n return unsupported;\n }\n const response = await sendLocalDaemonControlPlaneRequest({\n request: { v: 1, command: \"account_control_capabilities\" },\n });\n return serviceControlCapabilitiesSchema.parse({\n deviceId: contract.deviceId,\n start: false,\n stop:\n response.code === \"service.account_control_capabilities\" &&\n response.payload.supported,\n });\n}\n"],"mappings":";;;;;;;;;;;AAiBA,eAAe,oBACb,UACA,iBACA,QACA;CACA,IAAI,aAAa,UACf,OAAO;EACL,YAAY,MAAM,SAAS,kCAAkC,CAAC;EAC9D,gBAAgB;EAChB,UAAU;CACZ;CAIF,MAAM,QAAQ,MAAM,0CAA0C,EAC5D,gBACF,CAAC;CACD,OAAO,QACH;EACE,YAAY,MAAM,SAAS,SAAS,QAAQ,QAAQ,QAAQ;EAC5D,gBAAgB,SAAS,OAAO,MAAM,SAAS,KAAK;EACpD,UAAU,SACN,uCACA;CACN,IACA;AACN;;AAGA,eAAsB,+BACpB,WAA4B,QAAQ,UACpC;CACA,MAAM,cAAc;EAAE,UAAU;EAAM,OAAO;EAAO,MAAM;CAAM;CAChE,IAAI,aAAa,YAAY,aAAa,SACxC,OAAO;CAET,MAAM,WAAW,MAAM,0BAA0B;CACjD,MAAM,SAAS,MAAM,4BAA4B;CACjD,MAAM,SAAS,QAAQ,iBAAiB;CACxC,IACE,UAAU,uBACP,aAAa,UAAU,oBAAoB,cAC9C,EACE,UACC,aAAa,WAAW,QAAQ,iBAAiB,sBAGpD,OAAO;CAET,MAAM,UAAU,MAAM,4BAA4B,SAAS,iBAAiB;CAC5E,IAAI,EAAE,YAAY,MAAM,QAAQ,OAAO,EAAA,CAAG,YACxC,OAAO;CAKT,MAAM,QAAQ,MAAM,oBAClB,UACA,SAAS,eACT,MACF;CACA,IAAI,CAAC,OACH,OAAO;CAET,MAAM,EAAE,YAAY,gBAAgB,aAAa;CACjD,MAAM,EAAE,WAAW,MAAM,UAAU,QAAQ,CAAC,CAC1C,YACA;EACE,GAAI,iBAAiB,CAAC,cAAc,IAAI,CAAC;EACzC;EACA;EACA;CACF,GACA;EAAE,SAAS;EAAQ,WAAW;EAAQ,aAAa;CAAK,CAC1D;CACA,MAAM,UAAU,sCAAsC,UACpD,KAAK,MAAM,MAAM,CACnB;CACA,IACE,CAAC,QAAQ,WACT,QAAQ,KAAK,aAAa,YACzB,MAAM,SAAS,QAAQ,KAAK,UAAU,MAAO,YAE9C,OAAO;CAET,IACE,QAAQ,KAAK,aAAa,wCACzB,MAAM,SAAS,QAAQ,KAAK,WAAW,MAAO,gBAE/C,OAAO;CAET,IACE,KAAK,UAAU,MAAM,4BAA4B,CAAC,MAClD,KAAK,UAAU,MAAM,GAErB,OAAO;CAET,MAAM,UAAU,MAAM,gCAAgC;CACtD,IAAI,QAAQ,2BAA2B,eACrC,OAAO;EAAE,UAAU,SAAS;EAAU,OAAO;EAAM,MAAM;CAAM;CAEjE,IAAI,QAAQ,2BAA2B,WACrC,OAAO;CAET,MAAM,WAAW,MAAM,mCAAmC,EACxD,SAAS;EAAE,GAAG;EAAG,SAAS;CAA+B,EAC3D,CAAC;CACD,OAAO,iCAAiC,MAAM;EAC5C,UAAU,SAAS;EACnB,OAAO;EACP,MACE,SAAS,SAAS,0CAClB,SAAS,QAAQ;CACrB,CAAC;AACH"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { D as openMeldRootDir, P as resolveOpenMeldEnvPreset, V as skillsDir, z as runtimeLogsDir } from "./paths-De9xdA2h.js";
|
|
4
4
|
import { t as isBinaryDistribution } from "./distribution-BDQT2ilb.js";
|
|
5
|
-
import { d as compareSemver, l as OPENMELD_VERSION } from "./daemon-lifecycle-journal-
|
|
5
|
+
import { d as compareSemver, l as OPENMELD_VERSION } from "./daemon-lifecycle-journal-DrDyXoUO.js";
|
|
6
6
|
import { createHash, randomUUID, verify } from "node:crypto";
|
|
7
7
|
import path, { basename, dirname, join, relative, resolve } from "node:path";
|
|
8
8
|
import { lstat, mkdir, readFile, readdir, readlink, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -746,4 +746,4 @@ function pathsEqual(left, right) {
|
|
|
746
746
|
//#endregion
|
|
747
747
|
export { readOpenMeldSkillMarker as a, replaceSkillDirectory as c, readSelectedSkillDocument as d, withSkillsInstallLock as f, OFFICIAL_CLI_SKILL_URL as h, isOpenMeldManagedSkillDir as i, downloadOfficialSkillUpdate as l, hashBundledSkillAssets as m, resolveSkillsInstallStates as n, writeOpenMeldSkillMarker as o, computeDirectoryContentHash as p, ensureLocalSkills as r, recoverSkillReplacement as s, resolveSkillInstallStateForTarget as t, loadSelectedSkillAssets as u };
|
|
748
748
|
|
|
749
|
-
//# sourceMappingURL=state-
|
|
749
|
+
//# sourceMappingURL=state-CbrhgfNh.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-BEY9weSc.js","names":["getErrorCode"],"sources":["../../../packages/schemas/dist/official-cli-skill.js","../src/skills/bundled.ts","../src/skills/bundled-assets-fs.ts","../src/skills/bundled-assets.ts","../src/skills/content-hash.ts","../src/skills/install-lock.ts","../src/skills/official-release.ts","../src/skills/replace-directory.ts","../src/skills/store.ts","../src/skills/state.ts"],"sourcesContent":["import * as z$1 from \"zod/v4\";\n//#region src/official-cli-skill.ts\nconst OFFICIAL_CLI_SKILL_CONTRACT = \"openmeld-skills-contract-2026-09-explicit-space-recipients-v1\";\nconst OFFICIAL_CLI_SKILL_URL = \"https://openmeld.ai/skills/openmeld-cli/SKILL.md\";\nconst OFFICIAL_CLI_SKILL_MAX_BYTES = 1048576;\nconst OFFICIAL_CLI_SKILL_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAFZjFHrQ/QLsJQpHkAbKBRG57fEazhm7zc0dMa54ilWQ=\n-----END PUBLIC KEY-----\n`;\nconst officialCliSkillPayloadSchema = z$1.object({\n\tschemaVersion: z$1.literal(1),\n\trevision: z$1.number().int().positive(),\n\tminimumCliVersion: z$1.string().regex(/^\\d+\\.\\d+\\.\\d+$/),\n\tcontractVersion: z$1.string().min(1).max(128),\n\tfiles: z$1.array(z$1.object({\n\t\tpath: z$1.string().regex(/^(?:SKILL\\.md|(?:playbooks|references)\\/[a-z0-9-]+\\.md)$/),\n\t\tcontent: z$1.string().min(1).max(131072)\n\t}).strict()).min(1).max(32)\n}).strict().superRefine((value, context) => {\n\tconst paths = value.files.map((file) => file.path);\n\tif (!paths.includes(\"SKILL.md\") || new Set(paths).size !== paths.length) context.addIssue({\n\t\tcode: \"custom\",\n\t\tmessage: \"Skill entry is required and paths must be unique\"\n\t});\n});\nconst officialCliSkillReleaseSchema = z$1.object({\n\tpayload: z$1.string().min(1).max(524288),\n\tsignature: z$1.string().regex(/^[A-Za-z0-9+/]{86}==$/)\n}).strict();\nconst officialCliSkillChannelSchema = z$1.object({\n\tschemaVersion: z$1.literal(1),\n\treleases: z$1.array(officialCliSkillReleaseSchema).min(1).max(16)\n}).strict();\n//#endregion\nexport { OFFICIAL_CLI_SKILL_CONTRACT, OFFICIAL_CLI_SKILL_MAX_BYTES, OFFICIAL_CLI_SKILL_PUBLIC_KEY, OFFICIAL_CLI_SKILL_URL, officialCliSkillChannelSchema, officialCliSkillPayloadSchema, officialCliSkillReleaseSchema };\n\n//# sourceMappingURL=official-cli-skill.js.map","import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst CLI_PACKAGE_JSON = \"package.json\";\n\nexport type BundledSkillsLocation = {\n cliRootDir: string;\n skillsRootDir: string;\n};\n\n/**\n * Locate the on-disk bundled skills directory for the npm distribution by\n * walking up from this module to the CLI package root (a directory that has\n * both package.json and skills/). Returns null under the binary distribution,\n * where import.meta.url is a virtual path and the skills are embedded instead —\n * callers in that mode go through bundled-assets.ts, not this function.\n */\nexport function resolveBundledSkillsLocation(): BundledSkillsLocation | null {\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const cliRootDir = resolveCliRootDir(moduleDir);\n if (!cliRootDir) {\n return null;\n }\n return {\n cliRootDir,\n skillsRootDir: path.join(cliRootDir, \"skills\"),\n };\n}\n\nfunction resolveCliRootDir(fromDir: string): string | null {\n let current = fromDir;\n for (;;) {\n const packageJsonPath = path.join(current, CLI_PACKAGE_JSON);\n const hasPackageJson = existsSync(packageJsonPath);\n const hasSkillsDir = existsSync(path.join(current, \"skills\"));\n if (hasPackageJson && hasSkillsDir) {\n return current;\n }\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport { resolveBundledSkillsLocation } from \"./bundled\";\nimport type { BundledSkillAsset } from \"./bundled-assets\";\n\n/**\n * npm-distribution source: read the bundled skills from the on-disk `skills/`\n * directory next to the CLI package. Assets are sorted by relative path so the\n * order (and therefore any content hash computed from them) is stable and\n * matches the embedded distribution.\n */\nexport async function loadFsBundledSkillAssets(): Promise<BundledSkillAsset[]> {\n const location = resolveBundledSkillsLocation();\n if (!location) {\n throw new Error(\"unable to resolve bundled OpenMeld skills directory\");\n }\n const assets = await collectSkillAssets(\n location.skillsRootDir,\n location.skillsRootDir\n );\n return sortBundledSkillAssets(assets);\n}\n\nexport function sortBundledSkillAssets(\n assets: BundledSkillAsset[]\n): BundledSkillAsset[] {\n return [...assets].sort((left, right) =>\n left.relativePath.localeCompare(right.relativePath)\n );\n}\n\nasync function collectSkillAssets(\n dir: string,\n rootDir: string\n): Promise<BundledSkillAsset[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const assets: BundledSkillAsset[] = [];\n for (const entry of entries) {\n const absolutePath = join(dir, entry.name);\n if (entry.isDirectory()) {\n assets.push(...(await collectSkillAssets(absolutePath, rootDir)));\n continue;\n }\n if (!entry.isFile()) {\n continue;\n }\n assets.push({\n relativePath: toPosixRelativePath(relative(rootDir, absolutePath)),\n content: await readFile(absolutePath),\n });\n }\n return assets;\n}\n\nfunction toPosixRelativePath(value: string): string {\n return value.split(\"\\\\\").join(\"/\");\n}\n","import { createHash } from \"node:crypto\";\nimport { isBinaryDistribution } from \"../runtime/distribution\";\nimport { loadFsBundledSkillAssets } from \"./bundled-assets-fs\";\n\n/**\n * One bundled skill file, addressed by its POSIX path relative to the skills/\n * root (e.g. \"README.md\", \"openmeld-cli/SKILL.md\"). This is the single shape\n * both distribution forms produce, so downstream skill install and bundle-hash\n * logic never branches on how the files were sourced.\n */\nexport type BundledSkillAsset = {\n relativePath: string;\n content: Buffer;\n};\n\n/**\n * Load the OpenMeld-managed skill files that ship with this CLI build.\n *\n * - npm distribution: read from the on-disk `skills/` directory.\n * - binary distribution: read from files embedded into the single binary at\n * compile time. The embedded module is a Bun-only island resolved only by\n * `bun build --compile`; the npm build never reaches this branch and marks\n * the module external, so its `with { type: \"file\" }` imports are never\n * parsed by tsdown.\n */\nexport async function loadBundledSkillAssets(): Promise<BundledSkillAsset[]> {\n if (isBinaryDistribution()) {\n const embedded = await import(\"./bundled-assets-embedded\");\n return embedded.loadEmbeddedBundledSkillAssets();\n }\n return loadFsBundledSkillAssets();\n}\n\n/**\n * Content hash over an ordered list of skill assets. Byte-for-byte compatible\n * with `computeDirectoryContentHash` (same `file:<relativePath>\\n<content>\\n`\n * framing) so the embedded and on-disk sources produce identical hashes as long\n * as `assets` is sorted by relative path (as `loadBundledSkillAssets` returns\n * it). This is the single skills-hash algorithm for both distribution forms.\n */\nexport function hashBundledSkillAssets(assets: BundledSkillAsset[]): string {\n const hash = createHash(\"sha256\");\n for (const asset of assets) {\n hash.update(`file:${asset.relativePath}\\n`);\n hash.update(asset.content);\n hash.update(\"\\n\");\n }\n return hash.digest(\"hex\");\n}\n\nconst OPENMELD_CLI_SKILL_ID = \"openmeld-cli\";\nconst OPENMELD_CLI_SKILL_FILE = \"SKILL.md\";\n\n/**\n * Read one OpenMeld CLI skill document by its path relative to the skill root\n * (e.g. \"SKILL.md\", \"references/commands.md\"). Works in both distribution forms\n * via loadBundledSkillAssets, so `openmeld prompt --raw` renders the bundled\n * markdown from the embedded binary too.\n */\nexport async function readBundledOpenMeldCliSkillDocumentByPath(\n skillRelativePath: string\n): Promise<string> {\n const targetPath = `${OPENMELD_CLI_SKILL_ID}/${skillRelativePath}`;\n const assets = await loadBundledSkillAssets();\n const asset = assets.find((item) => item.relativePath === targetPath);\n if (!asset) {\n throw new Error(\n `bundled OpenMeld CLI skill document is missing: ${skillRelativePath}`\n );\n }\n return asset.content.toString(\"utf8\");\n}\n\nexport function readBundledOpenMeldCliSkillDocument(): Promise<string> {\n return readBundledOpenMeldCliSkillDocumentByPath(OPENMELD_CLI_SKILL_FILE);\n}\n","import { createHash } from \"node:crypto\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\n\nexport async function computeDirectoryContentHash(input: {\n rootDir: string;\n ignoredNames?: string[];\n}): Promise<string> {\n const ignoredNames = new Set(input.ignoredNames ?? []);\n const files = await collectFiles({\n dir: input.rootDir,\n rootDir: input.rootDir,\n ignoredNames,\n });\n const hash = createHash(\"sha256\");\n for (const file of files) {\n hash.update(`file:${file.relativePath}\\n`);\n hash.update(file.content);\n hash.update(\"\\n\");\n }\n return hash.digest(\"hex\");\n}\n\nasync function collectFiles(input: {\n dir: string;\n rootDir: string;\n ignoredNames: Set<string>;\n}): Promise<Array<{ relativePath: string; content: Buffer }>> {\n const entries = await readdir(input.dir, { withFileTypes: true }).catch(\n (error: unknown) => {\n if (getErrorCode(error) === \"ENOENT\") {\n return [];\n }\n warnDirectoryReadError(input.dir, error);\n throw error;\n }\n );\n entries.sort((a, b) => a.name.localeCompare(b.name));\n\n const files: Array<{ relativePath: string; content: Buffer }> = [];\n for (const entry of entries) {\n if (input.ignoredNames.has(entry.name)) {\n continue;\n }\n const absolutePath = join(input.dir, entry.name);\n if (entry.isDirectory()) {\n files.push(\n ...(await collectFiles({\n dir: absolutePath,\n rootDir: input.rootDir,\n ignoredNames: input.ignoredNames,\n }))\n );\n continue;\n }\n if (!entry.isFile()) {\n continue;\n }\n const content = await readFile(absolutePath);\n files.push({\n relativePath: normalizeRelativePath(\n relative(input.rootDir, absolutePath)\n ),\n content,\n });\n }\n return files;\n}\n\nfunction normalizeRelativePath(value: string): string {\n return value.split(\"\\\\\").join(\"/\");\n}\n\nfunction getErrorCode(error: unknown): string | undefined {\n if (!error || typeof error !== \"object\") {\n return undefined;\n }\n const code = (error as { code?: unknown }).code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nfunction warnDirectoryReadError(dir: string, error: unknown): void {\n const reason = error instanceof Error ? error.message : String(error);\n process.stderr.write(\n `[openmeld] failed to read directory while hashing skills content (${dir}): ${reason}\\n`\n );\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { runtimeLogsDir } from \"../config/paths\";\n\nconst heldLock = new AsyncLocalStorage<boolean>();\nconst pendingLocks = new Map<string, Promise<unknown>>();\nexport function withSkillsInstallLock<T>(run: () => Promise<T>): Promise<T> {\n if (heldLock.getStore()) {\n return run();\n }\n const key = runtimeLogsDir();\n const previous = pendingLocks.get(key) ?? Promise.resolve();\n const current = previous\n .catch(() => undefined)\n .then(() => acquireSkillsInstallLock(() => heldLock.run(true, run)));\n pendingLocks.set(key, current);\n return current.finally(() => {\n if (pendingLocks.get(key) === current) {\n pendingLocks.delete(key);\n }\n });\n}\n\nconst LOCK_FILE_NAME = \"skills-install.lock\";\nconst LOCK_ACQUIRE_MAX_ATTEMPTS = 3;\n\nasync function acquireSkillsInstallLock<T>(run: () => Promise<T>): Promise<T> {\n const logsDir = runtimeLogsDir();\n await mkdir(logsDir, { recursive: true });\n const lockPath = join(logsDir, LOCK_FILE_NAME);\n\n let acquired = false;\n const lockContents = `${JSON.stringify({\n pid: process.pid,\n createdAt: new Date().toISOString(),\n })}\\n`;\n for (let attempt = 0; attempt < LOCK_ACQUIRE_MAX_ATTEMPTS; attempt += 1) {\n try {\n await writeFile(lockPath, lockContents, {\n encoding: \"utf8\",\n flag: \"wx\",\n });\n acquired = true;\n break;\n } catch (error) {\n if (getErrorCode(error) !== \"EEXIST\") {\n throw error;\n }\n\n const recovered = await recoverStaleSkillsInstallLock(lockPath);\n if (!recovered) {\n throw new Error(\n \"another skills installation is already running; retry after it finishes\"\n );\n }\n\n try {\n await writeFile(lockPath, lockContents, {\n encoding: \"utf8\",\n flag: \"wx\",\n });\n acquired = true;\n break;\n } catch (retryError) {\n if (getErrorCode(retryError) !== \"EEXIST\") {\n throw retryError;\n }\n }\n }\n }\n\n if (!acquired) {\n throw new Error(\n \"another skills installation is already running; retry after it finishes\"\n );\n }\n\n try {\n return await run();\n } finally {\n await rm(lockPath, { force: true }).catch(() => undefined);\n }\n}\n\nasync function recoverStaleSkillsInstallLock(\n lockPath: string\n): Promise<boolean> {\n const lockRaw = await readFile(lockPath, \"utf8\").catch((error: unknown) => {\n if (getErrorCode(error) === \"ENOENT\") {\n return \"\";\n }\n throw error;\n });\n if (!lockRaw) {\n return true;\n }\n\n const parsed = parseLockMeta(lockRaw);\n const pid = resolveLockPid(parsed);\n if (!pid) {\n const metadata = await stat(lockPath).catch(() => null);\n if (metadata && Date.now() - metadata.mtimeMs < 30_000) {\n return false;\n }\n }\n if (pid && isPidAlive(pid)) {\n return false;\n }\n\n const latestLockRaw = await readFile(lockPath, \"utf8\").catch(\n (error: unknown) => {\n if (getErrorCode(error) === \"ENOENT\") {\n return \"\";\n }\n throw error;\n }\n );\n if (!latestLockRaw) {\n return true;\n }\n const latestParsed = parseLockMeta(latestLockRaw);\n const latestPid = resolveLockPid(latestParsed);\n if (\n !isSameLockSnapshot({\n beforeRaw: lockRaw,\n beforePid: pid,\n afterRaw: latestLockRaw,\n afterPid: latestPid,\n })\n ) {\n return false;\n }\n\n await rm(lockPath, { force: true }).catch((error: unknown) => {\n if (getErrorCode(error) === \"ENOENT\") {\n return undefined;\n }\n throw error;\n });\n return true;\n}\n\nfunction parseLockMeta(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n}\n\nfunction resolveLockPid(meta: unknown): number | null {\n if (!meta || typeof meta !== \"object\") {\n return null;\n }\n const pid = (meta as Record<string, unknown>).pid;\n return typeof pid === \"number\" && Number.isInteger(pid) && pid > 0\n ? pid\n : null;\n}\n\nfunction isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return getErrorCode(error) !== \"ESRCH\";\n }\n}\n\nfunction getErrorCode(error: unknown): string | undefined {\n if (!error || typeof error !== \"object\") {\n return undefined;\n }\n const code = (error as { code?: unknown }).code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nfunction isSameLockSnapshot(input: {\n beforeRaw: string;\n beforePid: number | null;\n afterRaw: string;\n afterPid: number | null;\n}): boolean {\n if (input.beforeRaw !== input.afterRaw) {\n return false;\n }\n return input.beforePid === input.afterPid;\n}\n","import { randomUUID, verify } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n OFFICIAL_CLI_SKILL_CONTRACT,\n OFFICIAL_CLI_SKILL_MAX_BYTES,\n OFFICIAL_CLI_SKILL_PUBLIC_KEY,\n type OfficialCliSkillPayload,\n type OfficialCliSkillRelease,\n officialCliSkillChannelSchema,\n officialCliSkillPayloadSchema,\n officialCliSkillReleaseSchema,\n} from \"@openmeld/schemas\";\nimport { openMeldRootDir, resolveOpenMeldEnvPreset } from \"../config/paths\";\nimport { compareSemver } from \"../config/version-state\";\nimport { OPENMELD_VERSION } from \"../runtime/version\";\nimport { loadBundledSkillAssets } from \"./bundled-assets\";\nimport { withSkillsInstallLock } from \"./install-lock\";\n\nconst CACHE_FILE = \"official-cli-skill.json\";\n\nexport function verifyOfficialSkillRelease(value: unknown): {\n release: OfficialCliSkillRelease;\n payload: OfficialCliSkillPayload;\n} {\n const envelope = officialCliSkillReleaseSchema.safeParse(value);\n if (\n !(\n envelope.success &&\n verify(\n null,\n Buffer.from(envelope.data.payload),\n OFFICIAL_CLI_SKILL_PUBLIC_KEY,\n Buffer.from(envelope.data.signature, \"base64\")\n )\n )\n ) {\n throw new Error(\"OpenMeld Skill signature is invalid\");\n }\n const payload = officialCliSkillPayloadSchema.safeParse(\n JSON.parse(envelope.data.payload)\n );\n if (!payload.success) {\n throw new Error(\"OpenMeld Skill content is invalid\");\n }\n return { release: envelope.data, payload: payload.data };\n}\n\nfunction isCompatible(\n payload: OfficialCliSkillPayload,\n cliVersion = OPENMELD_VERSION\n): boolean {\n return (\n payload.contractVersion === OFFICIAL_CLI_SKILL_CONTRACT &&\n compareSemver(cliVersion, payload.minimumCliVersion) >= 0\n );\n}\n\nexport function selectOfficialSkillRelease(\n value: unknown,\n cliVersion = OPENMELD_VERSION\n) {\n const channel = officialCliSkillChannelSchema.safeParse(value);\n if (!channel.success) {\n throw new Error(\"OpenMeld Skill channel is invalid\");\n }\n return (\n channel.data.releases\n .map(verifyOfficialSkillRelease)\n .filter(({ payload }) => isCompatible(payload, cliVersion))\n .sort((a, b) => b.payload.revision - a.payload.revision)[0] ?? null\n );\n}\n\nasync function readCachedRelease() {\n const raw = await readFile(join(openMeldRootDir(), CACHE_FILE), \"utf8\").catch(\n (error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n );\n if (!raw) {\n return null;\n }\n try {\n return verifyOfficialSkillRelease(JSON.parse(raw));\n } catch (error) {\n process.stderr.write(\n `[openmeld] cached Skill rejected: ${error instanceof Error ? error.message : String(error)}\\n`\n );\n return null;\n }\n}\n\n// Local-only selection is shared by install, prompt, and component status.\nexport async function loadSelectedSkillAssets() {\n const cached = await readCachedRelease();\n if (!(cached && isCompatible(cached.payload))) {\n return {\n assets: await loadBundledSkillAssets(),\n version: OPENMELD_VERSION,\n };\n }\n return {\n assets: [\n ...cached.payload.files.map((file) => ({\n relativePath: `openmeld-cli/${file.path}`,\n content: Buffer.from(file.content),\n })),\n ].sort((a, b) => a.relativePath.localeCompare(b.relativePath)),\n version: `skill-r${cached.payload.revision}`,\n contentRelease: {\n revision: cached.payload.revision,\n minimumCliVersion: cached.payload.minimumCliVersion,\n },\n };\n}\n\nexport async function readSelectedSkillDocument(path: string): Promise<string> {\n const { assets } = await loadSelectedSkillAssets();\n const asset = assets.find(\n (file) => file.relativePath === `openmeld-cli/${path}`\n );\n if (!asset) {\n throw new Error(`OpenMeld Skill document is missing: ${path}`);\n }\n return asset.content.toString(\"utf8\");\n}\n\nexport function resolveOfficialSkillChannelUrl(): string | null {\n if (resolveOpenMeldEnvPreset() === \"prod\") {\n return \"https://openmeld.ai/skills/openmeld-cli/channel.json\";\n }\n const override = process.env.OPENMELD_CLI_SKILL_CHANNEL_URL;\n if (!(override && process.env.OPENMELD_HOME)) {\n return null;\n }\n const url = new URL(override);\n if (\n url.protocol !== \"http:\" ||\n ![\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname) ||\n url.username ||\n url.password\n ) {\n throw new Error(\"Isolated Skill updates require an explicit localhost URL\");\n }\n return url.href;\n}\n\nexport async function downloadOfficialSkillUpdate(): Promise<\n \"updated\" | \"current\" | \"incompatible\" | \"lane_isolated\"\n> {\n const url = resolveOfficialSkillChannelUrl();\n if (!url) {\n return \"lane_isolated\";\n }\n const response = await fetch(url, {\n signal: AbortSignal.timeout(5000),\n redirect: \"error\",\n });\n if (!(response.ok && response.body)) {\n throw new Error(`OpenMeld Skill download failed (HTTP ${response.status})`);\n }\n const chunks: Uint8Array[] = [];\n let size = 0;\n for await (const chunk of response.body) {\n size += chunk.byteLength;\n if (size > OFFICIAL_CLI_SKILL_MAX_BYTES) {\n throw new Error(\"OpenMeld Skill download exceeds the size limit\");\n }\n chunks.push(chunk);\n }\n const selected = selectOfficialSkillRelease(\n JSON.parse(Buffer.concat(chunks).toString(\"utf8\"))\n );\n if (!selected) {\n return \"incompatible\";\n }\n return withSkillsInstallLock(async () => {\n const cached = await readCachedRelease();\n if (cached && cached.payload.revision >= selected.payload.revision) {\n return \"current\";\n }\n await mkdir(openMeldRootDir(), { recursive: true });\n const cache = join(openMeldRootDir(), CACHE_FILE);\n const staged = `${cache}.${randomUUID()}.tmp`;\n try {\n await writeFile(staged, JSON.stringify(selected.release), {\n flag: \"wx\",\n mode: 0o600,\n });\n await rename(staged, cache);\n } finally {\n await rm(staged, { force: true });\n }\n return \"updated\";\n });\n}\n","import { randomUUID } from \"node:crypto\";\nimport { lstat, readFile, readlink, rename, rm } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\n\n// Callers hold the skills install lock. Recover a process exit between renames.\nexport async function recoverSkillReplacement(target: string): Promise<void> {\n const previous = join(\n dirname(target),\n `.${basename(target)}.openmeld-previous`\n );\n if (!(await exists(previous))) {\n return;\n }\n if (!(await isManagedReplacement(previous, basename(target)))) {\n throw new Error(\"OpenMeld Skill backup conflicts with an unmanaged path\");\n }\n if (await exists(target)) {\n if (!(await isManagedReplacement(target, basename(target)))) {\n throw new Error(\"OpenMeld Skill recovery would affect an unmanaged path\");\n }\n await rm(previous, { recursive: true, force: true });\n } else {\n await rename(previous, target);\n }\n}\n\nexport async function replaceSkillDirectory(\n target: string,\n prepare: (staged: string) => Promise<void>\n): Promise<void> {\n await recoverSkillReplacement(target);\n const staged = join(\n dirname(target),\n `.${basename(target)}.openmeld-staged-${randomUUID()}`\n );\n const previous = join(\n dirname(target),\n `.${basename(target)}.openmeld-previous`\n );\n try {\n await prepare(staged);\n const hadPrevious = await exists(target);\n if (hadPrevious) {\n await rename(target, previous);\n }\n try {\n await rename(staged, target);\n } catch (error) {\n if (hadPrevious) {\n await rename(previous, target);\n }\n throw error;\n }\n // A cleanup failure must not roll back a committed replacement.\n await rm(previous, { recursive: true, force: true }).catch(() => undefined);\n } finally {\n await rm(staged, { recursive: true, force: true }).catch(() => undefined);\n }\n}\n\nasync function isManagedReplacement(\n path: string,\n skillId: string\n): Promise<boolean> {\n const raw = await readFile(join(path, \".openmeld-skill.json\"), \"utf8\").catch(\n () => null\n );\n if (raw) {\n try {\n const marker = JSON.parse(raw);\n return marker.managedBy === \"openmeld\" && marker.skillId === skillId;\n } catch {\n return false;\n }\n }\n // Legacy dangling links have no readable marker and carry no directory data.\n if ((await lstat(path)).isSymbolicLink()) {\n const destination = resolve(dirname(path), await readlink(path));\n return basename(destination) === skillId && !(await exists(destination));\n }\n return false;\n}\n\nfunction exists(path: string): Promise<boolean> {\n return lstat(path).then(\n () => true,\n (error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") {\n return false;\n }\n throw error;\n }\n );\n}\n","import { lstat, mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport path, { dirname, join, relative } from \"node:path\";\nimport { skillsDir } from \"../config/paths\";\nimport {\n type BundledSkillAsset,\n hashBundledSkillAssets,\n} from \"./bundled-assets\";\nimport { sortBundledSkillAssets } from \"./bundled-assets-fs\";\nimport { computeDirectoryContentHash } from \"./content-hash\";\nimport { withSkillsInstallLock } from \"./install-lock\";\nimport { loadSelectedSkillAssets } from \"./official-release\";\nimport {\n recoverSkillReplacement,\n replaceSkillDirectory,\n} from \"./replace-directory\";\n\nexport const OPENMELD_SKILL_MARKER_FILE = \".openmeld-skill.json\";\n\nexport type OpenMeldSkillMarker = {\n managedBy: \"openmeld\";\n skillId: string;\n mode: \"source\" | \"symlink\" | \"copy\";\n contentHash?: string;\n version?: string;\n updatedAt: string;\n};\n\nexport type LocalSkill = {\n id: string;\n name: string;\n absolutePath: string;\n relativePath: string;\n contentHash?: string;\n version?: string;\n};\n\nconst OPENMELD_CLI_SKILL_FILE = \"SKILL.md\";\nconst SKILL_NAME_REGEX = /^name:\\s*(.+)$/m;\n\nexport function ensureLocalSkills(): Promise<LocalSkill[]> {\n return withSkillsInstallLock(ensureLocalSkillsLocked);\n}\n\nasync function ensureLocalSkillsLocked(): Promise<LocalSkill[]> {\n const storePath = skillsDir();\n await mkdir(storePath, { recursive: true });\n\n const { assets, version: bundledVersion } = await loadSelectedSkillAssets();\n if (assets.length === 0) {\n return listLocalSkills();\n }\n const skillGroups = groupAssetsBySkill(assets);\n\n for (const [skillId, skillAssets] of skillGroups) {\n const targetDir = join(storePath, skillId);\n await recoverSkillReplacement(targetDir);\n const sourceContentHash = hashBundledSkillAssets(skillAssets);\n const existingMarker = await readOpenMeldSkillMarker(targetDir);\n const existing = await lstat(targetDir).catch(\n (error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n );\n if (existing && (!existingMarker || existing.isSymbolicLink())) {\n throw new Error(\n `OpenMeld Skill source conflicts with an unmanaged path: ${targetDir}`\n );\n }\n const isUpToDate =\n existingMarker?.managedBy === \"openmeld\" &&\n existingMarker.skillId === skillId &&\n existingMarker.mode === \"source\" &&\n existingMarker.contentHash === sourceContentHash &&\n existingMarker.version === bundledVersion &&\n (await computeDirectoryContentHash({\n rootDir: targetDir,\n ignoredNames: [OPENMELD_SKILL_MARKER_FILE],\n })) === sourceContentHash;\n if (isUpToDate) {\n continue;\n }\n\n await replaceSkillDirectory(targetDir, async (stagedDir) => {\n for (const asset of skillAssets) {\n const filePath = join(stagedDir, asset.relativePath);\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, asset.content);\n }\n await writeOpenMeldSkillMarker({\n skillDir: stagedDir,\n skillId,\n mode: \"source\",\n contentHash: sourceContentHash,\n version: bundledVersion,\n });\n });\n }\n\n return listLocalSkills();\n}\n\n// Group loaded assets by their first path segment (the skill id). Top-level\n// files (e.g. skills/README.md) belong to no skill and are dropped, and a group\n// without a SKILL.md is dropped too — matching the previous \"only install skill\n// directories that contain SKILL.md\" behavior. Each group's paths are made\n// skill-relative and sorted so the per-skill hash matches the source tree.\nfunction groupAssetsBySkill(\n assets: BundledSkillAsset[]\n): Map<string, BundledSkillAsset[]> {\n const groups = new Map<string, BundledSkillAsset[]>();\n for (const asset of assets) {\n const slashIndex = asset.relativePath.indexOf(\"/\");\n if (slashIndex < 0) {\n continue;\n }\n const skillId = asset.relativePath.slice(0, slashIndex);\n const skillRelativePath = asset.relativePath.slice(slashIndex + 1);\n const group = groups.get(skillId) ?? [];\n group.push({ relativePath: skillRelativePath, content: asset.content });\n groups.set(skillId, group);\n }\n for (const [skillId, group] of [...groups.entries()]) {\n if (group.some((asset) => asset.relativePath === OPENMELD_CLI_SKILL_FILE)) {\n groups.set(skillId, sortBundledSkillAssets(group));\n } else {\n groups.delete(skillId);\n }\n }\n return groups;\n}\n\nexport async function listLocalSkills(): Promise<LocalSkill[]> {\n const storePath = skillsDir();\n const skillDirs = await discoverSkillDirs(storePath, 0, 6);\n const skills: LocalSkill[] = [];\n\n for (const skillDir of skillDirs) {\n const skillFile = join(skillDir, \"SKILL.md\");\n const raw = await readFile(skillFile, \"utf8\").catch(() => \"\");\n if (!raw) {\n continue;\n }\n const skillId = path.basename(skillDir);\n const skillName = readSkillName(raw) ?? skillId;\n const marker = await readOpenMeldSkillMarker(skillDir);\n skills.push({\n id: skillId,\n name: skillName,\n absolutePath: skillDir,\n relativePath: relative(storePath, skillDir) || skillId,\n ...(marker?.contentHash ? { contentHash: marker.contentHash } : {}),\n ...(marker?.version ? { version: marker.version } : {}),\n });\n }\n\n skills.sort((a, b) => a.relativePath.localeCompare(b.relativePath));\n return skills;\n}\n\nexport async function writeOpenMeldSkillMarker(input: {\n skillDir: string;\n skillId: string;\n mode: \"source\" | \"symlink\" | \"copy\";\n contentHash?: string;\n version?: string;\n}): Promise<void> {\n const markerPath = join(input.skillDir, OPENMELD_SKILL_MARKER_FILE);\n const marker: OpenMeldSkillMarker = {\n managedBy: \"openmeld\",\n skillId: input.skillId,\n mode: input.mode,\n ...(input.contentHash ? { contentHash: input.contentHash } : {}),\n ...(input.version ? { version: input.version } : {}),\n updatedAt: new Date().toISOString(),\n };\n await writeFile(markerPath, `${JSON.stringify(marker, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function isOpenMeldManagedSkillDir(\n skillDir: string\n): Promise<boolean> {\n const marker = await readOpenMeldSkillMarker(skillDir);\n return marker?.managedBy === \"openmeld\";\n}\n\nexport async function readOpenMeldSkillMarker(\n skillDir: string\n): Promise<OpenMeldSkillMarker | null> {\n const markerPath = join(skillDir, OPENMELD_SKILL_MARKER_FILE);\n const raw = await readFile(markerPath, \"utf8\").catch(() => null);\n if (!raw) {\n return null;\n }\n try {\n const parsed = JSON.parse(raw) as Partial<OpenMeldSkillMarker>;\n if (parsed.managedBy !== \"openmeld\") {\n return null;\n }\n if (\n typeof parsed.skillId !== \"string\" ||\n parsed.skillId.trim().length === 0\n ) {\n return null;\n }\n if (\n parsed.mode !== \"source\" &&\n parsed.mode !== \"symlink\" &&\n parsed.mode !== \"copy\"\n ) {\n return null;\n }\n return {\n managedBy: \"openmeld\",\n skillId: parsed.skillId.trim(),\n mode: parsed.mode,\n ...(typeof parsed.contentHash === \"string\" &&\n parsed.contentHash.trim().length > 0\n ? { contentHash: parsed.contentHash.trim() }\n : {}),\n ...(typeof parsed.version === \"string\" && parsed.version.trim().length > 0\n ? { version: parsed.version.trim() }\n : {}),\n updatedAt:\n typeof parsed.updatedAt === \"string\" &&\n parsed.updatedAt.trim().length > 0\n ? parsed.updatedAt\n : new Date().toISOString(),\n };\n } catch {\n return null;\n }\n}\n\nasync function discoverSkillDirs(\n dir: string,\n depth: number,\n maxDepth: number\n): Promise<string[]> {\n if (depth > maxDepth) {\n return [];\n }\n\n const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);\n if (entries.length === 0) {\n return [];\n }\n\n const hasSkill = entries.some(\n (entry) => entry.isFile() && entry.name === \"SKILL.md\"\n );\n if (hasSkill) {\n return [dir];\n }\n\n const nested = await Promise.all(\n entries\n .filter(\n (entry) => entry.isDirectory() && !entry.name.includes(\".openmeld-\")\n )\n .map((entry) =>\n discoverSkillDirs(join(dir, entry.name), depth + 1, maxDepth)\n )\n );\n\n return nested.flat();\n}\n\nfunction readSkillName(rawSkillFile: string): string | undefined {\n const match = rawSkillFile.match(SKILL_NAME_REGEX);\n if (!match) {\n return undefined;\n }\n const candidate = match[1]?.trim();\n return candidate && candidate.length > 0 ? candidate : undefined;\n}\n","import { lstat, readlink } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { computeDirectoryContentHash } from \"./content-hash\";\nimport type { SkillsInstallTarget } from \"./installer\";\nimport {\n type LocalSkill,\n type OpenMeldSkillMarker,\n readOpenMeldSkillMarker,\n} from \"./store\";\n\nexport type SkillInstallState =\n | \"missing\"\n | \"outdated\"\n | \"up_to_date\"\n | \"external_conflict\";\n\nexport type SkillInstallStateResult = {\n targetId: string;\n targetDir: string;\n targetType: \"agent\" | \"custom\";\n skillId: string;\n skillDir: string;\n state: SkillInstallState;\n targetMode?: OpenMeldSkillMarker[\"mode\"];\n sourceHash?: string;\n targetHash?: string;\n sourceVersion?: string;\n targetVersion?: string;\n reason?: string;\n};\n\ntype SourceSnapshot = {\n hash?: string;\n version?: string;\n};\n\ntype TargetSnapshot =\n | {\n exists: false;\n }\n | {\n exists: true;\n isSymlink: boolean;\n marker: OpenMeldSkillMarker | null;\n symlinkTargetPath: string;\n destinationExists: boolean;\n };\n\nexport async function resolveSkillsInstallStates(input: {\n skills: LocalSkill[];\n targets: SkillsInstallTarget[];\n}): Promise<SkillInstallStateResult[]> {\n const states: SkillInstallStateResult[] = [];\n for (const target of input.targets) {\n for (const skill of input.skills) {\n states.push(\n await resolveSkillInstallStateForTarget({\n skill,\n target,\n })\n );\n }\n }\n return states;\n}\n\nexport async function resolveSkillInstallStateForTarget(input: {\n skill: LocalSkill;\n target: SkillsInstallTarget;\n}): Promise<SkillInstallStateResult> {\n const base = createBaseResult(input);\n const source = await resolveSourceSnapshot(input.skill);\n const target = await resolveTargetSnapshot(base.skillDir);\n\n if (!target.exists) {\n return createStateResult({\n base,\n source,\n state: \"missing\",\n });\n }\n\n if (target.marker?.managedBy !== \"openmeld\") {\n if (\n isLegacyOpenMeldSkillSymlink({\n skillId: input.skill.id,\n target,\n })\n ) {\n return createStateResult({\n base,\n source,\n state: \"outdated\",\n targetMode: \"symlink\",\n reason: \"legacy OpenMeld skill link found; update required\",\n });\n }\n\n return createStateResult({\n base,\n source,\n state: \"external_conflict\",\n reason:\n \"existing non-OpenMeld skill detected; skipped to avoid overwrite\",\n });\n }\n\n if (!target.isSymlink && target.marker.contentHash) {\n const entry = await lstat(join(base.skillDir, \"SKILL.md\")).catch(\n () => null\n );\n if (!entry?.isFile()) {\n return createStateResult({\n base,\n source,\n state: \"outdated\",\n targetMarker: target.marker,\n reason: \"OpenMeld Skill entry is missing\",\n });\n }\n const actualHash = await computeDirectoryContentHash({\n rootDir: base.skillDir,\n ignoredNames: [\".openmeld-skill.json\"],\n });\n if (actualHash !== target.marker.contentHash) {\n return createStateResult({\n base,\n source,\n state: \"external_conflict\",\n targetMarker: target.marker,\n reason: \"OpenMeld Skill files were modified locally; kept your changes\",\n });\n }\n }\n\n const upToDate = isUpToDate({\n source,\n targetMarker: target.marker,\n isSymlink: target.isSymlink,\n symlinkTargetPath: target.symlinkTargetPath,\n sourceSkillDir: input.skill.absolutePath,\n });\n if (upToDate) {\n return createStateResult({\n base,\n source,\n targetMarker: target.marker,\n state: \"up_to_date\",\n reason: \"already up-to-date\",\n });\n }\n\n return createStateResult({\n base,\n source,\n targetMarker: target.marker,\n state: \"outdated\",\n reason: target.isSymlink\n ? \"OpenMeld skill link points to a different OpenMeld skills store; update required\"\n : \"OpenMeld skill content changed; update required\",\n });\n}\n\nfunction createBaseResult(input: {\n skill: LocalSkill;\n target: SkillsInstallTarget;\n}): Omit<SkillInstallStateResult, \"state\"> {\n const skillDir = join(input.target.dir, input.skill.id);\n return {\n targetId: input.target.id,\n targetDir: input.target.dir,\n targetType: input.target.type,\n skillId: input.skill.id,\n skillDir,\n };\n}\n\nasync function resolveSourceSnapshot(\n skill: LocalSkill\n): Promise<SourceSnapshot> {\n const sourceMarker = await readOpenMeldSkillMarker(skill.absolutePath);\n return {\n ...((skill.contentHash ?? sourceMarker?.contentHash)\n ? { hash: skill.contentHash ?? sourceMarker?.contentHash }\n : {}),\n ...((skill.version ?? sourceMarker?.version)\n ? { version: skill.version ?? sourceMarker?.version }\n : {}),\n };\n}\n\nasync function resolveTargetSnapshot(\n skillDir: string\n): Promise<TargetSnapshot> {\n const stats = await lstat(skillDir).catch(() => null);\n if (!stats) {\n return { exists: false };\n }\n\n let marker = await readOpenMeldSkillMarker(skillDir);\n let symlinkTargetPath = \"\";\n if (stats.isSymbolicLink()) {\n symlinkTargetPath = await resolveSymlinkTarget(skillDir).catch(() => \"\");\n if (!marker && symlinkTargetPath) {\n marker = await readOpenMeldSkillMarker(symlinkTargetPath);\n }\n }\n\n return {\n exists: true,\n isSymlink: stats.isSymbolicLink(),\n marker,\n symlinkTargetPath,\n destinationExists: symlinkTargetPath\n ? Boolean(await lstat(symlinkTargetPath).catch(() => null))\n : true,\n };\n}\n\nfunction isLegacyOpenMeldSkillSymlink(input: {\n skillId: string;\n target: Extract<TargetSnapshot, { exists: true }>;\n}): boolean {\n if (\n !(input.target.isSymlink && input.target.symlinkTargetPath) ||\n input.target.destinationExists\n ) {\n return false;\n }\n\n return basename(input.target.symlinkTargetPath) === input.skillId;\n}\n\nfunction isUpToDate(input: {\n source: SourceSnapshot;\n targetMarker: OpenMeldSkillMarker;\n isSymlink: boolean;\n symlinkTargetPath: string;\n sourceSkillDir: string;\n}): boolean {\n if (input.isSymlink) {\n // A symlinked target mirrors whatever store it points at, and its marker is\n // read through the link, so a matching hash/version only proves that other\n // store's state. The link is current only when it resolves to this store's\n // skill directory; anything else must be reinstalled before the foreign\n // store drifts or disappears.\n return (\n input.symlinkTargetPath.length > 0 &&\n pathsEqual(input.symlinkTargetPath, input.sourceSkillDir)\n );\n }\n return hasMatchingHashAndVersion(input.source, input.targetMarker);\n}\n\nfunction hasMatchingHashAndVersion(\n source: SourceSnapshot,\n targetMarker: OpenMeldSkillMarker\n): boolean {\n if (\n !(\n source.hash &&\n targetMarker.contentHash &&\n source.hash === targetMarker.contentHash\n )\n ) {\n return false;\n }\n return (\n !(source.version && targetMarker.version) ||\n source.version === targetMarker.version\n );\n}\n\nfunction createStateResult(input: {\n base: Omit<SkillInstallStateResult, \"state\">;\n source: SourceSnapshot;\n state: SkillInstallState;\n targetMode?: OpenMeldSkillMarker[\"mode\"];\n targetMarker?: OpenMeldSkillMarker;\n reason?: string;\n}): SkillInstallStateResult {\n return {\n ...input.base,\n state: input.state,\n ...(input.source.hash ? { sourceHash: input.source.hash } : {}),\n ...(input.source.version ? { sourceVersion: input.source.version } : {}),\n ...(input.targetMarker?.contentHash\n ? { targetHash: input.targetMarker.contentHash }\n : {}),\n ...(input.targetMarker?.mode\n ? { targetMode: input.targetMarker.mode }\n : {}),\n ...(input.targetMode ? { targetMode: input.targetMode } : {}),\n ...(input.targetMarker?.version\n ? { targetVersion: input.targetMarker.version }\n : {}),\n ...(input.reason ? { reason: input.reason } : {}),\n };\n}\n\nasync function resolveSymlinkTarget(linkPath: string): Promise<string> {\n const target = await readlink(linkPath);\n return resolve(dirname(linkPath), target);\n}\n\nfunction pathsEqual(left: string, right: string): boolean {\n return resolve(left) === resolve(right);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"state-CbrhgfNh.js","names":["getErrorCode"],"sources":["../../../packages/schemas/dist/official-cli-skill.js","../src/skills/bundled.ts","../src/skills/bundled-assets-fs.ts","../src/skills/bundled-assets.ts","../src/skills/content-hash.ts","../src/skills/install-lock.ts","../src/skills/official-release.ts","../src/skills/replace-directory.ts","../src/skills/store.ts","../src/skills/state.ts"],"sourcesContent":["import * as z$1 from \"zod/v4\";\n//#region src/official-cli-skill.ts\nconst OFFICIAL_CLI_SKILL_CONTRACT = \"openmeld-skills-contract-2026-09-explicit-space-recipients-v1\";\nconst OFFICIAL_CLI_SKILL_URL = \"https://openmeld.ai/skills/openmeld-cli/SKILL.md\";\nconst OFFICIAL_CLI_SKILL_MAX_BYTES = 1048576;\nconst OFFICIAL_CLI_SKILL_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAFZjFHrQ/QLsJQpHkAbKBRG57fEazhm7zc0dMa54ilWQ=\n-----END PUBLIC KEY-----\n`;\nconst officialCliSkillPayloadSchema = z$1.object({\n\tschemaVersion: z$1.literal(1),\n\trevision: z$1.number().int().positive(),\n\tminimumCliVersion: z$1.string().regex(/^\\d+\\.\\d+\\.\\d+$/),\n\tcontractVersion: z$1.string().min(1).max(128),\n\tfiles: z$1.array(z$1.object({\n\t\tpath: z$1.string().regex(/^(?:SKILL\\.md|(?:playbooks|references)\\/[a-z0-9-]+\\.md)$/),\n\t\tcontent: z$1.string().min(1).max(131072)\n\t}).strict()).min(1).max(32)\n}).strict().superRefine((value, context) => {\n\tconst paths = value.files.map((file) => file.path);\n\tif (!paths.includes(\"SKILL.md\") || new Set(paths).size !== paths.length) context.addIssue({\n\t\tcode: \"custom\",\n\t\tmessage: \"Skill entry is required and paths must be unique\"\n\t});\n});\nconst officialCliSkillReleaseSchema = z$1.object({\n\tpayload: z$1.string().min(1).max(524288),\n\tsignature: z$1.string().regex(/^[A-Za-z0-9+/]{86}==$/)\n}).strict();\nconst officialCliSkillChannelSchema = z$1.object({\n\tschemaVersion: z$1.literal(1),\n\treleases: z$1.array(officialCliSkillReleaseSchema).min(1).max(16)\n}).strict();\n//#endregion\nexport { OFFICIAL_CLI_SKILL_CONTRACT, OFFICIAL_CLI_SKILL_MAX_BYTES, OFFICIAL_CLI_SKILL_PUBLIC_KEY, OFFICIAL_CLI_SKILL_URL, officialCliSkillChannelSchema, officialCliSkillPayloadSchema, officialCliSkillReleaseSchema };\n\n//# sourceMappingURL=official-cli-skill.js.map","import { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst CLI_PACKAGE_JSON = \"package.json\";\n\nexport type BundledSkillsLocation = {\n cliRootDir: string;\n skillsRootDir: string;\n};\n\n/**\n * Locate the on-disk bundled skills directory for the npm distribution by\n * walking up from this module to the CLI package root (a directory that has\n * both package.json and skills/). Returns null under the binary distribution,\n * where import.meta.url is a virtual path and the skills are embedded instead —\n * callers in that mode go through bundled-assets.ts, not this function.\n */\nexport function resolveBundledSkillsLocation(): BundledSkillsLocation | null {\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const cliRootDir = resolveCliRootDir(moduleDir);\n if (!cliRootDir) {\n return null;\n }\n return {\n cliRootDir,\n skillsRootDir: path.join(cliRootDir, \"skills\"),\n };\n}\n\nfunction resolveCliRootDir(fromDir: string): string | null {\n let current = fromDir;\n for (;;) {\n const packageJsonPath = path.join(current, CLI_PACKAGE_JSON);\n const hasPackageJson = existsSync(packageJsonPath);\n const hasSkillsDir = existsSync(path.join(current, \"skills\"));\n if (hasPackageJson && hasSkillsDir) {\n return current;\n }\n const parent = path.dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n}\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport { resolveBundledSkillsLocation } from \"./bundled\";\nimport type { BundledSkillAsset } from \"./bundled-assets\";\n\n/**\n * npm-distribution source: read the bundled skills from the on-disk `skills/`\n * directory next to the CLI package. Assets are sorted by relative path so the\n * order (and therefore any content hash computed from them) is stable and\n * matches the embedded distribution.\n */\nexport async function loadFsBundledSkillAssets(): Promise<BundledSkillAsset[]> {\n const location = resolveBundledSkillsLocation();\n if (!location) {\n throw new Error(\"unable to resolve bundled OpenMeld skills directory\");\n }\n const assets = await collectSkillAssets(\n location.skillsRootDir,\n location.skillsRootDir\n );\n return sortBundledSkillAssets(assets);\n}\n\nexport function sortBundledSkillAssets(\n assets: BundledSkillAsset[]\n): BundledSkillAsset[] {\n return [...assets].sort((left, right) =>\n left.relativePath.localeCompare(right.relativePath)\n );\n}\n\nasync function collectSkillAssets(\n dir: string,\n rootDir: string\n): Promise<BundledSkillAsset[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const assets: BundledSkillAsset[] = [];\n for (const entry of entries) {\n const absolutePath = join(dir, entry.name);\n if (entry.isDirectory()) {\n assets.push(...(await collectSkillAssets(absolutePath, rootDir)));\n continue;\n }\n if (!entry.isFile()) {\n continue;\n }\n assets.push({\n relativePath: toPosixRelativePath(relative(rootDir, absolutePath)),\n content: await readFile(absolutePath),\n });\n }\n return assets;\n}\n\nfunction toPosixRelativePath(value: string): string {\n return value.split(\"\\\\\").join(\"/\");\n}\n","import { createHash } from \"node:crypto\";\nimport { isBinaryDistribution } from \"../runtime/distribution\";\nimport { loadFsBundledSkillAssets } from \"./bundled-assets-fs\";\n\n/**\n * One bundled skill file, addressed by its POSIX path relative to the skills/\n * root (e.g. \"README.md\", \"openmeld-cli/SKILL.md\"). This is the single shape\n * both distribution forms produce, so downstream skill install and bundle-hash\n * logic never branches on how the files were sourced.\n */\nexport type BundledSkillAsset = {\n relativePath: string;\n content: Buffer;\n};\n\n/**\n * Load the OpenMeld-managed skill files that ship with this CLI build.\n *\n * - npm distribution: read from the on-disk `skills/` directory.\n * - binary distribution: read from files embedded into the single binary at\n * compile time. The embedded module is a Bun-only island resolved only by\n * `bun build --compile`; the npm build never reaches this branch and marks\n * the module external, so its `with { type: \"file\" }` imports are never\n * parsed by tsdown.\n */\nexport async function loadBundledSkillAssets(): Promise<BundledSkillAsset[]> {\n if (isBinaryDistribution()) {\n const embedded = await import(\"./bundled-assets-embedded\");\n return embedded.loadEmbeddedBundledSkillAssets();\n }\n return loadFsBundledSkillAssets();\n}\n\n/**\n * Content hash over an ordered list of skill assets. Byte-for-byte compatible\n * with `computeDirectoryContentHash` (same `file:<relativePath>\\n<content>\\n`\n * framing) so the embedded and on-disk sources produce identical hashes as long\n * as `assets` is sorted by relative path (as `loadBundledSkillAssets` returns\n * it). This is the single skills-hash algorithm for both distribution forms.\n */\nexport function hashBundledSkillAssets(assets: BundledSkillAsset[]): string {\n const hash = createHash(\"sha256\");\n for (const asset of assets) {\n hash.update(`file:${asset.relativePath}\\n`);\n hash.update(asset.content);\n hash.update(\"\\n\");\n }\n return hash.digest(\"hex\");\n}\n\nconst OPENMELD_CLI_SKILL_ID = \"openmeld-cli\";\nconst OPENMELD_CLI_SKILL_FILE = \"SKILL.md\";\n\n/**\n * Read one OpenMeld CLI skill document by its path relative to the skill root\n * (e.g. \"SKILL.md\", \"references/commands.md\"). Works in both distribution forms\n * via loadBundledSkillAssets, so `openmeld prompt --raw` renders the bundled\n * markdown from the embedded binary too.\n */\nexport async function readBundledOpenMeldCliSkillDocumentByPath(\n skillRelativePath: string\n): Promise<string> {\n const targetPath = `${OPENMELD_CLI_SKILL_ID}/${skillRelativePath}`;\n const assets = await loadBundledSkillAssets();\n const asset = assets.find((item) => item.relativePath === targetPath);\n if (!asset) {\n throw new Error(\n `bundled OpenMeld CLI skill document is missing: ${skillRelativePath}`\n );\n }\n return asset.content.toString(\"utf8\");\n}\n\nexport function readBundledOpenMeldCliSkillDocument(): Promise<string> {\n return readBundledOpenMeldCliSkillDocumentByPath(OPENMELD_CLI_SKILL_FILE);\n}\n","import { createHash } from \"node:crypto\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\n\nexport async function computeDirectoryContentHash(input: {\n rootDir: string;\n ignoredNames?: string[];\n}): Promise<string> {\n const ignoredNames = new Set(input.ignoredNames ?? []);\n const files = await collectFiles({\n dir: input.rootDir,\n rootDir: input.rootDir,\n ignoredNames,\n });\n const hash = createHash(\"sha256\");\n for (const file of files) {\n hash.update(`file:${file.relativePath}\\n`);\n hash.update(file.content);\n hash.update(\"\\n\");\n }\n return hash.digest(\"hex\");\n}\n\nasync function collectFiles(input: {\n dir: string;\n rootDir: string;\n ignoredNames: Set<string>;\n}): Promise<Array<{ relativePath: string; content: Buffer }>> {\n const entries = await readdir(input.dir, { withFileTypes: true }).catch(\n (error: unknown) => {\n if (getErrorCode(error) === \"ENOENT\") {\n return [];\n }\n warnDirectoryReadError(input.dir, error);\n throw error;\n }\n );\n entries.sort((a, b) => a.name.localeCompare(b.name));\n\n const files: Array<{ relativePath: string; content: Buffer }> = [];\n for (const entry of entries) {\n if (input.ignoredNames.has(entry.name)) {\n continue;\n }\n const absolutePath = join(input.dir, entry.name);\n if (entry.isDirectory()) {\n files.push(\n ...(await collectFiles({\n dir: absolutePath,\n rootDir: input.rootDir,\n ignoredNames: input.ignoredNames,\n }))\n );\n continue;\n }\n if (!entry.isFile()) {\n continue;\n }\n const content = await readFile(absolutePath);\n files.push({\n relativePath: normalizeRelativePath(\n relative(input.rootDir, absolutePath)\n ),\n content,\n });\n }\n return files;\n}\n\nfunction normalizeRelativePath(value: string): string {\n return value.split(\"\\\\\").join(\"/\");\n}\n\nfunction getErrorCode(error: unknown): string | undefined {\n if (!error || typeof error !== \"object\") {\n return undefined;\n }\n const code = (error as { code?: unknown }).code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nfunction warnDirectoryReadError(dir: string, error: unknown): void {\n const reason = error instanceof Error ? error.message : String(error);\n process.stderr.write(\n `[openmeld] failed to read directory while hashing skills content (${dir}): ${reason}\\n`\n );\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { runtimeLogsDir } from \"../config/paths\";\n\nconst heldLock = new AsyncLocalStorage<boolean>();\nconst pendingLocks = new Map<string, Promise<unknown>>();\nexport function withSkillsInstallLock<T>(run: () => Promise<T>): Promise<T> {\n if (heldLock.getStore()) {\n return run();\n }\n const key = runtimeLogsDir();\n const previous = pendingLocks.get(key) ?? Promise.resolve();\n const current = previous\n .catch(() => undefined)\n .then(() => acquireSkillsInstallLock(() => heldLock.run(true, run)));\n pendingLocks.set(key, current);\n return current.finally(() => {\n if (pendingLocks.get(key) === current) {\n pendingLocks.delete(key);\n }\n });\n}\n\nconst LOCK_FILE_NAME = \"skills-install.lock\";\nconst LOCK_ACQUIRE_MAX_ATTEMPTS = 3;\n\nasync function acquireSkillsInstallLock<T>(run: () => Promise<T>): Promise<T> {\n const logsDir = runtimeLogsDir();\n await mkdir(logsDir, { recursive: true });\n const lockPath = join(logsDir, LOCK_FILE_NAME);\n\n let acquired = false;\n const lockContents = `${JSON.stringify({\n pid: process.pid,\n createdAt: new Date().toISOString(),\n })}\\n`;\n for (let attempt = 0; attempt < LOCK_ACQUIRE_MAX_ATTEMPTS; attempt += 1) {\n try {\n await writeFile(lockPath, lockContents, {\n encoding: \"utf8\",\n flag: \"wx\",\n });\n acquired = true;\n break;\n } catch (error) {\n if (getErrorCode(error) !== \"EEXIST\") {\n throw error;\n }\n\n const recovered = await recoverStaleSkillsInstallLock(lockPath);\n if (!recovered) {\n throw new Error(\n \"another skills installation is already running; retry after it finishes\"\n );\n }\n\n try {\n await writeFile(lockPath, lockContents, {\n encoding: \"utf8\",\n flag: \"wx\",\n });\n acquired = true;\n break;\n } catch (retryError) {\n if (getErrorCode(retryError) !== \"EEXIST\") {\n throw retryError;\n }\n }\n }\n }\n\n if (!acquired) {\n throw new Error(\n \"another skills installation is already running; retry after it finishes\"\n );\n }\n\n try {\n return await run();\n } finally {\n await rm(lockPath, { force: true }).catch(() => undefined);\n }\n}\n\nasync function recoverStaleSkillsInstallLock(\n lockPath: string\n): Promise<boolean> {\n const lockRaw = await readFile(lockPath, \"utf8\").catch((error: unknown) => {\n if (getErrorCode(error) === \"ENOENT\") {\n return \"\";\n }\n throw error;\n });\n if (!lockRaw) {\n return true;\n }\n\n const parsed = parseLockMeta(lockRaw);\n const pid = resolveLockPid(parsed);\n if (!pid) {\n const metadata = await stat(lockPath).catch(() => null);\n if (metadata && Date.now() - metadata.mtimeMs < 30_000) {\n return false;\n }\n }\n if (pid && isPidAlive(pid)) {\n return false;\n }\n\n const latestLockRaw = await readFile(lockPath, \"utf8\").catch(\n (error: unknown) => {\n if (getErrorCode(error) === \"ENOENT\") {\n return \"\";\n }\n throw error;\n }\n );\n if (!latestLockRaw) {\n return true;\n }\n const latestParsed = parseLockMeta(latestLockRaw);\n const latestPid = resolveLockPid(latestParsed);\n if (\n !isSameLockSnapshot({\n beforeRaw: lockRaw,\n beforePid: pid,\n afterRaw: latestLockRaw,\n afterPid: latestPid,\n })\n ) {\n return false;\n }\n\n await rm(lockPath, { force: true }).catch((error: unknown) => {\n if (getErrorCode(error) === \"ENOENT\") {\n return undefined;\n }\n throw error;\n });\n return true;\n}\n\nfunction parseLockMeta(value: string): unknown {\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n}\n\nfunction resolveLockPid(meta: unknown): number | null {\n if (!meta || typeof meta !== \"object\") {\n return null;\n }\n const pid = (meta as Record<string, unknown>).pid;\n return typeof pid === \"number\" && Number.isInteger(pid) && pid > 0\n ? pid\n : null;\n}\n\nfunction isPidAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return getErrorCode(error) !== \"ESRCH\";\n }\n}\n\nfunction getErrorCode(error: unknown): string | undefined {\n if (!error || typeof error !== \"object\") {\n return undefined;\n }\n const code = (error as { code?: unknown }).code;\n return typeof code === \"string\" ? code : undefined;\n}\n\nfunction isSameLockSnapshot(input: {\n beforeRaw: string;\n beforePid: number | null;\n afterRaw: string;\n afterPid: number | null;\n}): boolean {\n if (input.beforeRaw !== input.afterRaw) {\n return false;\n }\n return input.beforePid === input.afterPid;\n}\n","import { randomUUID, verify } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n OFFICIAL_CLI_SKILL_CONTRACT,\n OFFICIAL_CLI_SKILL_MAX_BYTES,\n OFFICIAL_CLI_SKILL_PUBLIC_KEY,\n type OfficialCliSkillPayload,\n type OfficialCliSkillRelease,\n officialCliSkillChannelSchema,\n officialCliSkillPayloadSchema,\n officialCliSkillReleaseSchema,\n} from \"@openmeld/schemas\";\nimport { openMeldRootDir, resolveOpenMeldEnvPreset } from \"../config/paths\";\nimport { compareSemver } from \"../config/version-state\";\nimport { OPENMELD_VERSION } from \"../runtime/version\";\nimport { loadBundledSkillAssets } from \"./bundled-assets\";\nimport { withSkillsInstallLock } from \"./install-lock\";\n\nconst CACHE_FILE = \"official-cli-skill.json\";\n\nexport function verifyOfficialSkillRelease(value: unknown): {\n release: OfficialCliSkillRelease;\n payload: OfficialCliSkillPayload;\n} {\n const envelope = officialCliSkillReleaseSchema.safeParse(value);\n if (\n !(\n envelope.success &&\n verify(\n null,\n Buffer.from(envelope.data.payload),\n OFFICIAL_CLI_SKILL_PUBLIC_KEY,\n Buffer.from(envelope.data.signature, \"base64\")\n )\n )\n ) {\n throw new Error(\"OpenMeld Skill signature is invalid\");\n }\n const payload = officialCliSkillPayloadSchema.safeParse(\n JSON.parse(envelope.data.payload)\n );\n if (!payload.success) {\n throw new Error(\"OpenMeld Skill content is invalid\");\n }\n return { release: envelope.data, payload: payload.data };\n}\n\nfunction isCompatible(\n payload: OfficialCliSkillPayload,\n cliVersion = OPENMELD_VERSION\n): boolean {\n return (\n payload.contractVersion === OFFICIAL_CLI_SKILL_CONTRACT &&\n compareSemver(cliVersion, payload.minimumCliVersion) >= 0\n );\n}\n\nexport function selectOfficialSkillRelease(\n value: unknown,\n cliVersion = OPENMELD_VERSION\n) {\n const channel = officialCliSkillChannelSchema.safeParse(value);\n if (!channel.success) {\n throw new Error(\"OpenMeld Skill channel is invalid\");\n }\n return (\n channel.data.releases\n .map(verifyOfficialSkillRelease)\n .filter(({ payload }) => isCompatible(payload, cliVersion))\n .sort((a, b) => b.payload.revision - a.payload.revision)[0] ?? null\n );\n}\n\nasync function readCachedRelease() {\n const raw = await readFile(join(openMeldRootDir(), CACHE_FILE), \"utf8\").catch(\n (error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n );\n if (!raw) {\n return null;\n }\n try {\n return verifyOfficialSkillRelease(JSON.parse(raw));\n } catch (error) {\n process.stderr.write(\n `[openmeld] cached Skill rejected: ${error instanceof Error ? error.message : String(error)}\\n`\n );\n return null;\n }\n}\n\n// Local-only selection is shared by install, prompt, and component status.\nexport async function loadSelectedSkillAssets() {\n const cached = await readCachedRelease();\n if (!(cached && isCompatible(cached.payload))) {\n return {\n assets: await loadBundledSkillAssets(),\n version: OPENMELD_VERSION,\n };\n }\n return {\n assets: [\n ...cached.payload.files.map((file) => ({\n relativePath: `openmeld-cli/${file.path}`,\n content: Buffer.from(file.content),\n })),\n ].sort((a, b) => a.relativePath.localeCompare(b.relativePath)),\n version: `skill-r${cached.payload.revision}`,\n contentRelease: {\n revision: cached.payload.revision,\n minimumCliVersion: cached.payload.minimumCliVersion,\n },\n };\n}\n\nexport async function readSelectedSkillDocument(path: string): Promise<string> {\n const { assets } = await loadSelectedSkillAssets();\n const asset = assets.find(\n (file) => file.relativePath === `openmeld-cli/${path}`\n );\n if (!asset) {\n throw new Error(`OpenMeld Skill document is missing: ${path}`);\n }\n return asset.content.toString(\"utf8\");\n}\n\nexport function resolveOfficialSkillChannelUrl(): string | null {\n if (resolveOpenMeldEnvPreset() === \"prod\") {\n return \"https://openmeld.ai/skills/openmeld-cli/channel.json\";\n }\n const override = process.env.OPENMELD_CLI_SKILL_CHANNEL_URL;\n if (!(override && process.env.OPENMELD_HOME)) {\n return null;\n }\n const url = new URL(override);\n if (\n url.protocol !== \"http:\" ||\n ![\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname) ||\n url.username ||\n url.password\n ) {\n throw new Error(\"Isolated Skill updates require an explicit localhost URL\");\n }\n return url.href;\n}\n\nexport async function downloadOfficialSkillUpdate(): Promise<\n \"updated\" | \"current\" | \"incompatible\" | \"lane_isolated\"\n> {\n const url = resolveOfficialSkillChannelUrl();\n if (!url) {\n return \"lane_isolated\";\n }\n const response = await fetch(url, {\n signal: AbortSignal.timeout(5000),\n redirect: \"error\",\n });\n if (!(response.ok && response.body)) {\n throw new Error(`OpenMeld Skill download failed (HTTP ${response.status})`);\n }\n const chunks: Uint8Array[] = [];\n let size = 0;\n for await (const chunk of response.body) {\n size += chunk.byteLength;\n if (size > OFFICIAL_CLI_SKILL_MAX_BYTES) {\n throw new Error(\"OpenMeld Skill download exceeds the size limit\");\n }\n chunks.push(chunk);\n }\n const selected = selectOfficialSkillRelease(\n JSON.parse(Buffer.concat(chunks).toString(\"utf8\"))\n );\n if (!selected) {\n return \"incompatible\";\n }\n return withSkillsInstallLock(async () => {\n const cached = await readCachedRelease();\n if (cached && cached.payload.revision >= selected.payload.revision) {\n return \"current\";\n }\n await mkdir(openMeldRootDir(), { recursive: true });\n const cache = join(openMeldRootDir(), CACHE_FILE);\n const staged = `${cache}.${randomUUID()}.tmp`;\n try {\n await writeFile(staged, JSON.stringify(selected.release), {\n flag: \"wx\",\n mode: 0o600,\n });\n await rename(staged, cache);\n } finally {\n await rm(staged, { force: true });\n }\n return \"updated\";\n });\n}\n","import { randomUUID } from \"node:crypto\";\nimport { lstat, readFile, readlink, rename, rm } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\n\n// Callers hold the skills install lock. Recover a process exit between renames.\nexport async function recoverSkillReplacement(target: string): Promise<void> {\n const previous = join(\n dirname(target),\n `.${basename(target)}.openmeld-previous`\n );\n if (!(await exists(previous))) {\n return;\n }\n if (!(await isManagedReplacement(previous, basename(target)))) {\n throw new Error(\"OpenMeld Skill backup conflicts with an unmanaged path\");\n }\n if (await exists(target)) {\n if (!(await isManagedReplacement(target, basename(target)))) {\n throw new Error(\"OpenMeld Skill recovery would affect an unmanaged path\");\n }\n await rm(previous, { recursive: true, force: true });\n } else {\n await rename(previous, target);\n }\n}\n\nexport async function replaceSkillDirectory(\n target: string,\n prepare: (staged: string) => Promise<void>\n): Promise<void> {\n await recoverSkillReplacement(target);\n const staged = join(\n dirname(target),\n `.${basename(target)}.openmeld-staged-${randomUUID()}`\n );\n const previous = join(\n dirname(target),\n `.${basename(target)}.openmeld-previous`\n );\n try {\n await prepare(staged);\n const hadPrevious = await exists(target);\n if (hadPrevious) {\n await rename(target, previous);\n }\n try {\n await rename(staged, target);\n } catch (error) {\n if (hadPrevious) {\n await rename(previous, target);\n }\n throw error;\n }\n // A cleanup failure must not roll back a committed replacement.\n await rm(previous, { recursive: true, force: true }).catch(() => undefined);\n } finally {\n await rm(staged, { recursive: true, force: true }).catch(() => undefined);\n }\n}\n\nasync function isManagedReplacement(\n path: string,\n skillId: string\n): Promise<boolean> {\n const raw = await readFile(join(path, \".openmeld-skill.json\"), \"utf8\").catch(\n () => null\n );\n if (raw) {\n try {\n const marker = JSON.parse(raw);\n return marker.managedBy === \"openmeld\" && marker.skillId === skillId;\n } catch {\n return false;\n }\n }\n // Legacy dangling links have no readable marker and carry no directory data.\n if ((await lstat(path)).isSymbolicLink()) {\n const destination = resolve(dirname(path), await readlink(path));\n return basename(destination) === skillId && !(await exists(destination));\n }\n return false;\n}\n\nfunction exists(path: string): Promise<boolean> {\n return lstat(path).then(\n () => true,\n (error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") {\n return false;\n }\n throw error;\n }\n );\n}\n","import { lstat, mkdir, readdir, readFile, writeFile } from \"node:fs/promises\";\nimport path, { dirname, join, relative } from \"node:path\";\nimport { skillsDir } from \"../config/paths\";\nimport {\n type BundledSkillAsset,\n hashBundledSkillAssets,\n} from \"./bundled-assets\";\nimport { sortBundledSkillAssets } from \"./bundled-assets-fs\";\nimport { computeDirectoryContentHash } from \"./content-hash\";\nimport { withSkillsInstallLock } from \"./install-lock\";\nimport { loadSelectedSkillAssets } from \"./official-release\";\nimport {\n recoverSkillReplacement,\n replaceSkillDirectory,\n} from \"./replace-directory\";\n\nexport const OPENMELD_SKILL_MARKER_FILE = \".openmeld-skill.json\";\n\nexport type OpenMeldSkillMarker = {\n managedBy: \"openmeld\";\n skillId: string;\n mode: \"source\" | \"symlink\" | \"copy\";\n contentHash?: string;\n version?: string;\n updatedAt: string;\n};\n\nexport type LocalSkill = {\n id: string;\n name: string;\n absolutePath: string;\n relativePath: string;\n contentHash?: string;\n version?: string;\n};\n\nconst OPENMELD_CLI_SKILL_FILE = \"SKILL.md\";\nconst SKILL_NAME_REGEX = /^name:\\s*(.+)$/m;\n\nexport function ensureLocalSkills(): Promise<LocalSkill[]> {\n return withSkillsInstallLock(ensureLocalSkillsLocked);\n}\n\nasync function ensureLocalSkillsLocked(): Promise<LocalSkill[]> {\n const storePath = skillsDir();\n await mkdir(storePath, { recursive: true });\n\n const { assets, version: bundledVersion } = await loadSelectedSkillAssets();\n if (assets.length === 0) {\n return listLocalSkills();\n }\n const skillGroups = groupAssetsBySkill(assets);\n\n for (const [skillId, skillAssets] of skillGroups) {\n const targetDir = join(storePath, skillId);\n await recoverSkillReplacement(targetDir);\n const sourceContentHash = hashBundledSkillAssets(skillAssets);\n const existingMarker = await readOpenMeldSkillMarker(targetDir);\n const existing = await lstat(targetDir).catch(\n (error: NodeJS.ErrnoException) => {\n if (error.code === \"ENOENT\") {\n return null;\n }\n throw error;\n }\n );\n if (existing && (!existingMarker || existing.isSymbolicLink())) {\n throw new Error(\n `OpenMeld Skill source conflicts with an unmanaged path: ${targetDir}`\n );\n }\n const isUpToDate =\n existingMarker?.managedBy === \"openmeld\" &&\n existingMarker.skillId === skillId &&\n existingMarker.mode === \"source\" &&\n existingMarker.contentHash === sourceContentHash &&\n existingMarker.version === bundledVersion &&\n (await computeDirectoryContentHash({\n rootDir: targetDir,\n ignoredNames: [OPENMELD_SKILL_MARKER_FILE],\n })) === sourceContentHash;\n if (isUpToDate) {\n continue;\n }\n\n await replaceSkillDirectory(targetDir, async (stagedDir) => {\n for (const asset of skillAssets) {\n const filePath = join(stagedDir, asset.relativePath);\n await mkdir(dirname(filePath), { recursive: true });\n await writeFile(filePath, asset.content);\n }\n await writeOpenMeldSkillMarker({\n skillDir: stagedDir,\n skillId,\n mode: \"source\",\n contentHash: sourceContentHash,\n version: bundledVersion,\n });\n });\n }\n\n return listLocalSkills();\n}\n\n// Group loaded assets by their first path segment (the skill id). Top-level\n// files (e.g. skills/README.md) belong to no skill and are dropped, and a group\n// without a SKILL.md is dropped too — matching the previous \"only install skill\n// directories that contain SKILL.md\" behavior. Each group's paths are made\n// skill-relative and sorted so the per-skill hash matches the source tree.\nfunction groupAssetsBySkill(\n assets: BundledSkillAsset[]\n): Map<string, BundledSkillAsset[]> {\n const groups = new Map<string, BundledSkillAsset[]>();\n for (const asset of assets) {\n const slashIndex = asset.relativePath.indexOf(\"/\");\n if (slashIndex < 0) {\n continue;\n }\n const skillId = asset.relativePath.slice(0, slashIndex);\n const skillRelativePath = asset.relativePath.slice(slashIndex + 1);\n const group = groups.get(skillId) ?? [];\n group.push({ relativePath: skillRelativePath, content: asset.content });\n groups.set(skillId, group);\n }\n for (const [skillId, group] of [...groups.entries()]) {\n if (group.some((asset) => asset.relativePath === OPENMELD_CLI_SKILL_FILE)) {\n groups.set(skillId, sortBundledSkillAssets(group));\n } else {\n groups.delete(skillId);\n }\n }\n return groups;\n}\n\nexport async function listLocalSkills(): Promise<LocalSkill[]> {\n const storePath = skillsDir();\n const skillDirs = await discoverSkillDirs(storePath, 0, 6);\n const skills: LocalSkill[] = [];\n\n for (const skillDir of skillDirs) {\n const skillFile = join(skillDir, \"SKILL.md\");\n const raw = await readFile(skillFile, \"utf8\").catch(() => \"\");\n if (!raw) {\n continue;\n }\n const skillId = path.basename(skillDir);\n const skillName = readSkillName(raw) ?? skillId;\n const marker = await readOpenMeldSkillMarker(skillDir);\n skills.push({\n id: skillId,\n name: skillName,\n absolutePath: skillDir,\n relativePath: relative(storePath, skillDir) || skillId,\n ...(marker?.contentHash ? { contentHash: marker.contentHash } : {}),\n ...(marker?.version ? { version: marker.version } : {}),\n });\n }\n\n skills.sort((a, b) => a.relativePath.localeCompare(b.relativePath));\n return skills;\n}\n\nexport async function writeOpenMeldSkillMarker(input: {\n skillDir: string;\n skillId: string;\n mode: \"source\" | \"symlink\" | \"copy\";\n contentHash?: string;\n version?: string;\n}): Promise<void> {\n const markerPath = join(input.skillDir, OPENMELD_SKILL_MARKER_FILE);\n const marker: OpenMeldSkillMarker = {\n managedBy: \"openmeld\",\n skillId: input.skillId,\n mode: input.mode,\n ...(input.contentHash ? { contentHash: input.contentHash } : {}),\n ...(input.version ? { version: input.version } : {}),\n updatedAt: new Date().toISOString(),\n };\n await writeFile(markerPath, `${JSON.stringify(marker, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function isOpenMeldManagedSkillDir(\n skillDir: string\n): Promise<boolean> {\n const marker = await readOpenMeldSkillMarker(skillDir);\n return marker?.managedBy === \"openmeld\";\n}\n\nexport async function readOpenMeldSkillMarker(\n skillDir: string\n): Promise<OpenMeldSkillMarker | null> {\n const markerPath = join(skillDir, OPENMELD_SKILL_MARKER_FILE);\n const raw = await readFile(markerPath, \"utf8\").catch(() => null);\n if (!raw) {\n return null;\n }\n try {\n const parsed = JSON.parse(raw) as Partial<OpenMeldSkillMarker>;\n if (parsed.managedBy !== \"openmeld\") {\n return null;\n }\n if (\n typeof parsed.skillId !== \"string\" ||\n parsed.skillId.trim().length === 0\n ) {\n return null;\n }\n if (\n parsed.mode !== \"source\" &&\n parsed.mode !== \"symlink\" &&\n parsed.mode !== \"copy\"\n ) {\n return null;\n }\n return {\n managedBy: \"openmeld\",\n skillId: parsed.skillId.trim(),\n mode: parsed.mode,\n ...(typeof parsed.contentHash === \"string\" &&\n parsed.contentHash.trim().length > 0\n ? { contentHash: parsed.contentHash.trim() }\n : {}),\n ...(typeof parsed.version === \"string\" && parsed.version.trim().length > 0\n ? { version: parsed.version.trim() }\n : {}),\n updatedAt:\n typeof parsed.updatedAt === \"string\" &&\n parsed.updatedAt.trim().length > 0\n ? parsed.updatedAt\n : new Date().toISOString(),\n };\n } catch {\n return null;\n }\n}\n\nasync function discoverSkillDirs(\n dir: string,\n depth: number,\n maxDepth: number\n): Promise<string[]> {\n if (depth > maxDepth) {\n return [];\n }\n\n const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);\n if (entries.length === 0) {\n return [];\n }\n\n const hasSkill = entries.some(\n (entry) => entry.isFile() && entry.name === \"SKILL.md\"\n );\n if (hasSkill) {\n return [dir];\n }\n\n const nested = await Promise.all(\n entries\n .filter(\n (entry) => entry.isDirectory() && !entry.name.includes(\".openmeld-\")\n )\n .map((entry) =>\n discoverSkillDirs(join(dir, entry.name), depth + 1, maxDepth)\n )\n );\n\n return nested.flat();\n}\n\nfunction readSkillName(rawSkillFile: string): string | undefined {\n const match = rawSkillFile.match(SKILL_NAME_REGEX);\n if (!match) {\n return undefined;\n }\n const candidate = match[1]?.trim();\n return candidate && candidate.length > 0 ? candidate : undefined;\n}\n","import { lstat, readlink } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { computeDirectoryContentHash } from \"./content-hash\";\nimport type { SkillsInstallTarget } from \"./installer\";\nimport {\n type LocalSkill,\n type OpenMeldSkillMarker,\n readOpenMeldSkillMarker,\n} from \"./store\";\n\nexport type SkillInstallState =\n | \"missing\"\n | \"outdated\"\n | \"up_to_date\"\n | \"external_conflict\";\n\nexport type SkillInstallStateResult = {\n targetId: string;\n targetDir: string;\n targetType: \"agent\" | \"custom\";\n skillId: string;\n skillDir: string;\n state: SkillInstallState;\n targetMode?: OpenMeldSkillMarker[\"mode\"];\n sourceHash?: string;\n targetHash?: string;\n sourceVersion?: string;\n targetVersion?: string;\n reason?: string;\n};\n\ntype SourceSnapshot = {\n hash?: string;\n version?: string;\n};\n\ntype TargetSnapshot =\n | {\n exists: false;\n }\n | {\n exists: true;\n isSymlink: boolean;\n marker: OpenMeldSkillMarker | null;\n symlinkTargetPath: string;\n destinationExists: boolean;\n };\n\nexport async function resolveSkillsInstallStates(input: {\n skills: LocalSkill[];\n targets: SkillsInstallTarget[];\n}): Promise<SkillInstallStateResult[]> {\n const states: SkillInstallStateResult[] = [];\n for (const target of input.targets) {\n for (const skill of input.skills) {\n states.push(\n await resolveSkillInstallStateForTarget({\n skill,\n target,\n })\n );\n }\n }\n return states;\n}\n\nexport async function resolveSkillInstallStateForTarget(input: {\n skill: LocalSkill;\n target: SkillsInstallTarget;\n}): Promise<SkillInstallStateResult> {\n const base = createBaseResult(input);\n const source = await resolveSourceSnapshot(input.skill);\n const target = await resolveTargetSnapshot(base.skillDir);\n\n if (!target.exists) {\n return createStateResult({\n base,\n source,\n state: \"missing\",\n });\n }\n\n if (target.marker?.managedBy !== \"openmeld\") {\n if (\n isLegacyOpenMeldSkillSymlink({\n skillId: input.skill.id,\n target,\n })\n ) {\n return createStateResult({\n base,\n source,\n state: \"outdated\",\n targetMode: \"symlink\",\n reason: \"legacy OpenMeld skill link found; update required\",\n });\n }\n\n return createStateResult({\n base,\n source,\n state: \"external_conflict\",\n reason:\n \"existing non-OpenMeld skill detected; skipped to avoid overwrite\",\n });\n }\n\n if (!target.isSymlink && target.marker.contentHash) {\n const entry = await lstat(join(base.skillDir, \"SKILL.md\")).catch(\n () => null\n );\n if (!entry?.isFile()) {\n return createStateResult({\n base,\n source,\n state: \"outdated\",\n targetMarker: target.marker,\n reason: \"OpenMeld Skill entry is missing\",\n });\n }\n const actualHash = await computeDirectoryContentHash({\n rootDir: base.skillDir,\n ignoredNames: [\".openmeld-skill.json\"],\n });\n if (actualHash !== target.marker.contentHash) {\n return createStateResult({\n base,\n source,\n state: \"external_conflict\",\n targetMarker: target.marker,\n reason: \"OpenMeld Skill files were modified locally; kept your changes\",\n });\n }\n }\n\n const upToDate = isUpToDate({\n source,\n targetMarker: target.marker,\n isSymlink: target.isSymlink,\n symlinkTargetPath: target.symlinkTargetPath,\n sourceSkillDir: input.skill.absolutePath,\n });\n if (upToDate) {\n return createStateResult({\n base,\n source,\n targetMarker: target.marker,\n state: \"up_to_date\",\n reason: \"already up-to-date\",\n });\n }\n\n return createStateResult({\n base,\n source,\n targetMarker: target.marker,\n state: \"outdated\",\n reason: target.isSymlink\n ? \"OpenMeld skill link points to a different OpenMeld skills store; update required\"\n : \"OpenMeld skill content changed; update required\",\n });\n}\n\nfunction createBaseResult(input: {\n skill: LocalSkill;\n target: SkillsInstallTarget;\n}): Omit<SkillInstallStateResult, \"state\"> {\n const skillDir = join(input.target.dir, input.skill.id);\n return {\n targetId: input.target.id,\n targetDir: input.target.dir,\n targetType: input.target.type,\n skillId: input.skill.id,\n skillDir,\n };\n}\n\nasync function resolveSourceSnapshot(\n skill: LocalSkill\n): Promise<SourceSnapshot> {\n const sourceMarker = await readOpenMeldSkillMarker(skill.absolutePath);\n return {\n ...((skill.contentHash ?? sourceMarker?.contentHash)\n ? { hash: skill.contentHash ?? sourceMarker?.contentHash }\n : {}),\n ...((skill.version ?? sourceMarker?.version)\n ? { version: skill.version ?? sourceMarker?.version }\n : {}),\n };\n}\n\nasync function resolveTargetSnapshot(\n skillDir: string\n): Promise<TargetSnapshot> {\n const stats = await lstat(skillDir).catch(() => null);\n if (!stats) {\n return { exists: false };\n }\n\n let marker = await readOpenMeldSkillMarker(skillDir);\n let symlinkTargetPath = \"\";\n if (stats.isSymbolicLink()) {\n symlinkTargetPath = await resolveSymlinkTarget(skillDir).catch(() => \"\");\n if (!marker && symlinkTargetPath) {\n marker = await readOpenMeldSkillMarker(symlinkTargetPath);\n }\n }\n\n return {\n exists: true,\n isSymlink: stats.isSymbolicLink(),\n marker,\n symlinkTargetPath,\n destinationExists: symlinkTargetPath\n ? Boolean(await lstat(symlinkTargetPath).catch(() => null))\n : true,\n };\n}\n\nfunction isLegacyOpenMeldSkillSymlink(input: {\n skillId: string;\n target: Extract<TargetSnapshot, { exists: true }>;\n}): boolean {\n if (\n !(input.target.isSymlink && input.target.symlinkTargetPath) ||\n input.target.destinationExists\n ) {\n return false;\n }\n\n return basename(input.target.symlinkTargetPath) === input.skillId;\n}\n\nfunction isUpToDate(input: {\n source: SourceSnapshot;\n targetMarker: OpenMeldSkillMarker;\n isSymlink: boolean;\n symlinkTargetPath: string;\n sourceSkillDir: string;\n}): boolean {\n if (input.isSymlink) {\n // A symlinked target mirrors whatever store it points at, and its marker is\n // read through the link, so a matching hash/version only proves that other\n // store's state. The link is current only when it resolves to this store's\n // skill directory; anything else must be reinstalled before the foreign\n // store drifts or disappears.\n return (\n input.symlinkTargetPath.length > 0 &&\n pathsEqual(input.symlinkTargetPath, input.sourceSkillDir)\n );\n }\n return hasMatchingHashAndVersion(input.source, input.targetMarker);\n}\n\nfunction hasMatchingHashAndVersion(\n source: SourceSnapshot,\n targetMarker: OpenMeldSkillMarker\n): boolean {\n if (\n !(\n source.hash &&\n targetMarker.contentHash &&\n source.hash === targetMarker.contentHash\n )\n ) {\n return false;\n }\n return (\n !(source.version && targetMarker.version) ||\n source.version === targetMarker.version\n );\n}\n\nfunction createStateResult(input: {\n base: Omit<SkillInstallStateResult, \"state\">;\n source: SourceSnapshot;\n state: SkillInstallState;\n targetMode?: OpenMeldSkillMarker[\"mode\"];\n targetMarker?: OpenMeldSkillMarker;\n reason?: string;\n}): SkillInstallStateResult {\n return {\n ...input.base,\n state: input.state,\n ...(input.source.hash ? { sourceHash: input.source.hash } : {}),\n ...(input.source.version ? { sourceVersion: input.source.version } : {}),\n ...(input.targetMarker?.contentHash\n ? { targetHash: input.targetMarker.contentHash }\n : {}),\n ...(input.targetMarker?.mode\n ? { targetMode: input.targetMarker.mode }\n : {}),\n ...(input.targetMode ? { targetMode: input.targetMode } : {}),\n ...(input.targetMarker?.version\n ? { targetVersion: input.targetMarker.version }\n : {}),\n ...(input.reason ? { reason: input.reason } : {}),\n };\n}\n\nasync function resolveSymlinkTarget(linkPath: string): Promise<string> {\n const target = await readlink(linkPath);\n return resolve(dirname(linkPath), target);\n}\n\nfunction pathsEqual(left: string, right: string): boolean {\n return resolve(left) === resolve(right);\n}\n"],"mappings":"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"}
|