openmeld 0.3.206 → 0.3.207

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/{add-me-membership-BkHWMxE4.js → add-me-membership-1JHMjZoR.js} +2 -2
  2. package/dist/{add-me-membership-BkHWMxE4.js.map → add-me-membership-1JHMjZoR.js.map} +1 -1
  3. package/dist/{agents-BOTlKiwS.js → agents-CIDsThyG.js} +150 -108
  4. package/dist/agents-CIDsThyG.js.map +1 -0
  5. package/dist/{api-client-foundation-6ms5gSu8.js → api-client-foundation-D6_NXHPV.js} +1 -1
  6. package/dist/{api-client-foundation-DpgDs0rw.js → api-client-foundation-DSurenul.js} +3 -3
  7. package/dist/{api-client-foundation-DpgDs0rw.js.map → api-client-foundation-DSurenul.js.map} +1 -1
  8. package/dist/auth-session-B7QMhHwh.js +4 -0
  9. package/dist/{auth-session-BjSqMLTz.js → auth-session-CO5XtFaq.js} +266 -75
  10. package/dist/auth-session-CO5XtFaq.js.map +1 -0
  11. package/dist/{base-url-CRAYNW-4.js → base-url-BE3pFiOZ.js} +1 -1
  12. package/dist/{base-url-9A557X2K.js → base-url-C6sHRNGu.js} +2 -2
  13. package/dist/{base-url-9A557X2K.js.map → base-url-C6sHRNGu.js.map} +1 -1
  14. package/dist/cli-binary-manifest-DiUulkp0.js +117 -0
  15. package/dist/cli-binary-manifest-DiUulkp0.js.map +1 -0
  16. package/dist/{command-CkbzbvXy.js → command-Bzt9zgnI.js} +13 -11
  17. package/dist/{command-CkbzbvXy.js.map → command-Bzt9zgnI.js.map} +1 -1
  18. package/dist/computer-connection-BOl79Ftf.js +54 -0
  19. package/dist/computer-connection-BOl79Ftf.js.map +1 -0
  20. package/dist/computer-connection-review-BTOvbJYL.js +39 -0
  21. package/dist/computer-connection-review-BTOvbJYL.js.map +1 -0
  22. package/dist/{computer-setup-continuation-Cd9nhLQ-.js → computer-setup-continuation-DmKdhR5u.js} +4 -4
  23. package/dist/{computer-setup-continuation-Cd9nhLQ-.js.map → computer-setup-continuation-DmKdhR5u.js.map} +1 -1
  24. package/dist/control-plane-D9jDcbMZ.js +1211 -0
  25. package/dist/control-plane-D9jDcbMZ.js.map +1 -0
  26. package/dist/daemon-local-state-file-jOXuXrky.js +45 -0
  27. package/dist/daemon-local-state-file-jOXuXrky.js.map +1 -0
  28. package/dist/daemon-runtime-lease-Dd4hdHNo.js +50 -0
  29. package/dist/daemon-runtime-lease-Dd4hdHNo.js.map +1 -0
  30. package/dist/{daemon-runtime-lease-BG9g0a6Z.js → daemon-runtime-lease-y3n1K0-C.js} +1 -1
  31. package/dist/{daemon-service-manager-DqVtRLBY.js → daemon-service-manager-Bh0LoLed.js} +1 -1
  32. package/dist/{daemon-service-manager-BVipiZwK.js → daemon-service-manager-GiMCiTmu.js} +99 -85
  33. package/dist/daemon-service-manager-GiMCiTmu.js.map +1 -0
  34. package/dist/daemon-service-runtime-DQW9gSLT.js +3642 -0
  35. package/dist/daemon-service-runtime-DQW9gSLT.js.map +1 -0
  36. package/dist/{daemon-state-BwIoDq7_.js → daemon-state-C37ZtIZK.js} +11 -5
  37. package/dist/daemon-state-C37ZtIZK.js.map +1 -0
  38. package/dist/{dist-CxadJClH.js → dist-D-kJdWZE.js} +726 -579
  39. package/dist/dist-D-kJdWZE.js.map +1 -0
  40. package/dist/dist-DTG_Vqc7.js +4 -0
  41. package/dist/distribution-DY2fBeSW.js +72 -0
  42. package/dist/distribution-DY2fBeSW.js.map +1 -0
  43. package/dist/{elapsed-time-C7P-nWIO.js → elapsed-time-CcoM2R3N.js} +7 -4
  44. package/dist/{elapsed-time-C7P-nWIO.js.map → elapsed-time-CcoM2R3N.js.map} +1 -1
  45. package/dist/{installation-inventory-P49sTjhe.js → installation-inventory-DJlwXa1q.js} +7 -6
  46. package/dist/{installation-inventory-P49sTjhe.js.map → installation-inventory-DJlwXa1q.js.map} +1 -1
  47. package/dist/{lock-CvBnBcFK.js → lock-Dxp6o_t_.js} +56 -7
  48. package/dist/lock-Dxp6o_t_.js.map +1 -0
  49. package/dist/{openmeld-ChOHuaqH.js → openmeld-CiL4AiB0.js} +226 -21
  50. package/dist/openmeld-CiL4AiB0.js.map +1 -0
  51. package/dist/openmeld-dev.js +1 -1
  52. package/dist/openmeld-environment-target-NtJYJe1D.js +256 -0
  53. package/dist/openmeld-environment-target-NtJYJe1D.js.map +1 -0
  54. package/dist/{openmeld-maintenance-worker-C7WykyDt.js → openmeld-maintenance-worker-DjdmRASI.js} +9 -8
  55. package/dist/{openmeld-maintenance-worker-C7WykyDt.js.map → openmeld-maintenance-worker-DjdmRASI.js.map} +1 -1
  56. package/dist/{openmeld-tools-update-coordinator-BBZhGo1A.js → openmeld-tools-update-coordinator-D9Skj8IE.js} +52 -4013
  57. package/dist/openmeld-tools-update-coordinator-D9Skj8IE.js.map +1 -0
  58. package/dist/openmeld.js +3 -3
  59. package/dist/{prepare-session-executor-CLmDoHom.js → prepare-session-executor-B0NtjHEL.js} +15 -13
  60. package/dist/{prepare-session-executor-CLmDoHom.js.map → prepare-session-executor-B0NtjHEL.js.map} +1 -1
  61. package/dist/{profiles-BCecj4Pj.js → runtime-transport-QIZmAo4-.js} +936 -2127
  62. package/dist/runtime-transport-QIZmAo4-.js.map +1 -0
  63. package/dist/service-account-authorization-Dt8kGvq8.js +56 -0
  64. package/dist/service-account-authorization-Dt8kGvq8.js.map +1 -0
  65. package/dist/service-control-capabilities-BU5F75zi.js +54 -0
  66. package/dist/service-control-capabilities-BU5F75zi.js.map +1 -0
  67. package/dist/service-control-capabilities-CzUB1ovW.js +4 -0
  68. package/dist/upgrade-DLECkjMt.js +4 -0
  69. package/dist/{upgrade-l_5Tge_z.js → upgrade-NxpTydHp.js} +6 -4
  70. package/dist/upgrade-NxpTydHp.js.map +1 -0
  71. package/package.json +2 -2
  72. package/dist/agents-BOTlKiwS.js.map +0 -1
  73. package/dist/auth-session-BjSqMLTz.js.map +0 -1
  74. package/dist/auth-session-ahQ5VXiF.js +0 -4
  75. package/dist/daemon-runtime-lease-CXlGR-iA.js +0 -87
  76. package/dist/daemon-runtime-lease-CXlGR-iA.js.map +0 -1
  77. package/dist/daemon-service-manager-BVipiZwK.js.map +0 -1
  78. package/dist/daemon-state-BwIoDq7_.js.map +0 -1
  79. package/dist/dist-0boZRalP.js +0 -4
  80. package/dist/dist-CxadJClH.js.map +0 -1
  81. package/dist/lock-CvBnBcFK.js.map +0 -1
  82. package/dist/openmeld-ChOHuaqH.js.map +0 -1
  83. package/dist/openmeld-tools-update-coordinator-BBZhGo1A.js.map +0 -1
  84. package/dist/profiles-BCecj4Pj.js.map +0 -1
  85. package/dist/upgrade-BKEAZKre.js +0 -4
  86. package/dist/upgrade-l_5Tge_z.js.map +0 -1
@@ -1,17 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { ht as skillsDir, lt as resolveOpenMeldEnvPreset, mt as runtimeLogsDir, tt as openMeldRootDir } from "./lock-CvBnBcFK.js";
4
- import { An as resolveSkillsAgentRegistry, Ko as compareSemver, On as canManageRegistryAgentSkillTargets, _o as OPENMELD_VERSION, kn as detectInstalledSkillsAgents } from "./openmeld-tools-update-coordinator-BBZhGo1A.js";
5
- import { S as isBinaryDistribution } from "./auth-session-BjSqMLTz.js";
6
- import { T as updateConfiguredSkillsConfig, g as getConfiguredSkillsConfig, y as resolveRuntimeSkillsCustomTargetId } from "./base-url-9A557X2K.js";
3
+ import { _t as skillsDir, dt as resolveOpenMeldEnvPreset, gt as runtimeLogsDir, rt as openMeldRootDir } from "./lock-Dxp6o_t_.js";
4
+ import { An as resolveSkillsAgentRegistry, On as canManageRegistryAgentSkillTargets, kn as detectInstalledSkillsAgents } from "./openmeld-tools-update-coordinator-D9Skj8IE.js";
5
+ import { t as isBinaryDistribution } from "./distribution-DY2fBeSW.js";
6
+ import { lt as compareSemver, nt as OPENMELD_VERSION } from "./daemon-service-runtime-DQW9gSLT.js";
7
+ import { T as updateConfiguredSkillsConfig, g as getConfiguredSkillsConfig, y as resolveRuntimeSkillsCustomTargetId } from "./base-url-C6sHRNGu.js";
7
8
  import { createHash, randomUUID, verify } from "node:crypto";
8
9
  import path, { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
9
10
  import { cp, lstat, mkdir, readFile, readdir, readlink, realpath, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
10
11
  import * as z$1 from "zod/v4";
11
12
  import { existsSync } from "node:fs";
12
13
  import process$1 from "node:process";
13
- import { fileURLToPath } from "node:url";
14
14
  import { AsyncLocalStorage } from "node:async_hooks";
15
+ import { fileURLToPath } from "node:url";
15
16
  const OFFICIAL_CLI_SKILL_URL = "https://openmeld.ai/skills/openmeld-cli/SKILL.md";
16
17
  const OFFICIAL_CLI_SKILL_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
17
18
  MCowBQYDK2VwAyEAFZjFHrQ/QLsJQpHkAbKBRG57fEazhm7zc0dMa54ilWQ=
@@ -1097,4 +1098,4 @@ function normalizeInstallRecordForCompare(input) {
1097
1098
  //#endregion
1098
1099
  export { readSelectedSkillDocument as _, mergeTargetsByDir as a, withSkillsInstallLock as b, summarizeSkillState as c, resolveSkillsInstallStates as d, ensureLocalSkills as f, loadSelectedSkillAssets as g, downloadOfficialSkillUpdate as h, filterTargetsWithInstalledOpenMeldSkills as i, installSkillsToTargets as l, readOpenMeldSkillMarker as m, collectSkillsReadinessSnapshot as n, persistDetectedInstallStateFromCheck as o, isOpenMeldManagedSkillDir as p, compareInstallRecords as r, resolveTrackedInstallTargets as s, buildAgentTargets as t, resolveSkillInstallStateForTarget as u, hashBundledSkillAssets as v, OFFICIAL_CLI_SKILL_URL as x, computeDirectoryContentHash as y };
1099
1100
 
1100
- //# sourceMappingURL=installation-inventory-P49sTjhe.js.map
1101
+ //# sourceMappingURL=installation-inventory-DJlwXa1q.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"installation-inventory-P49sTjhe.js","names":["getErrorCode","process"],"sources":["../../../packages/schemas/dist/official-cli-skill.js","../src/skills/install-lock.ts","../src/skills/replace-directory.ts","../src/skills/content-hash.ts","../src/skills/bundled.ts","../src/skills/bundled-assets-fs.ts","../src/skills/bundled-assets.ts","../src/skills/official-release.ts","../src/skills/store.ts","../src/skills/state.ts","../src/skills/installer.ts","../src/skills/installation-inventory.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 { 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 } 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 { 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 { 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 { 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 { 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","import { cp, mkdir, readFile, realpath, symlink } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport process from \"node:process\";\nimport { withSkillsInstallLock } from \"./install-lock\";\n\n// biome-ignore lint/performance/noBarrelFile: Keep the existing installer lock API while the source store shares its owner.\nexport { withSkillsInstallLock } from \"./install-lock\";\n\nimport {\n recoverSkillReplacement,\n replaceSkillDirectory,\n} from \"./replace-directory\";\nimport type { SkillInstallStateResult } from \"./state\";\nimport { resolveSkillInstallStateForTarget } from \"./state\";\nimport type { LocalSkill } from \"./store\";\nimport { writeOpenMeldSkillMarker } from \"./store\";\n\nexport type SkillsInstallMode = \"symlink\" | \"copy\" | \"unknown\";\nexport type SkillsInstallStatus = \"installed\" | \"skipped\" | \"failed\";\n\nexport type SkillsInstallTarget = {\n id: string;\n dir: string;\n type: \"agent\" | \"custom\";\n};\n\nexport type SkillsInstallResult = {\n targetId: string;\n targetDir: string;\n targetType: \"agent\" | \"custom\";\n skillId: string;\n status: SkillsInstallStatus;\n mode: SkillsInstallMode;\n degraded: boolean;\n reason?: string;\n};\n\nexport function installSkillsToTargets(input: {\n skills: LocalSkill[];\n targets: SkillsInstallTarget[];\n}): Promise<SkillsInstallResult[]> {\n return withSkillsInstallLock(() => installSkillsToTargetsLocked(input));\n}\n\nasync function installSkillsToTargetsLocked(input: {\n skills: LocalSkill[];\n targets: SkillsInstallTarget[];\n}): Promise<SkillsInstallResult[]> {\n const results: SkillsInstallResult[] = [];\n\n for (const target of input.targets) {\n for (const skill of input.skills) {\n const result = await installOneSkillToTarget({\n skill,\n target,\n });\n results.push(result);\n }\n }\n\n return results;\n}\n\nasync function installOneSkillToTarget(input: {\n skill: LocalSkill;\n target: SkillsInstallTarget;\n}): Promise<SkillsInstallResult> {\n const targetDir = input.target.dir;\n const failInstall = (reason: string): SkillsInstallResult => ({\n targetId: input.target.id,\n targetDir,\n targetType: input.target.type,\n skillId: input.skill.id,\n status: \"failed\",\n mode: \"unknown\",\n degraded: false,\n reason,\n });\n\n if (!isAbsolute(targetDir)) {\n return failInstall(\"target dir must be an absolute path\");\n }\n\n const skillId = input.skill.id;\n if (\n skillId.trim().length === 0 ||\n isAbsolute(skillId) ||\n skillId === \".\" ||\n skillId === \"..\" ||\n skillId.includes(\"/\") ||\n skillId.includes(\"\\\\\")\n ) {\n return failInstall(\"skill id would escape target dir\");\n }\n\n const resolvedTargetDir = resolve(targetDir);\n const resolvedSkillDir = resolve(resolvedTargetDir, skillId);\n const skillRelativePath = relative(resolvedTargetDir, resolvedSkillDir);\n if (\n skillRelativePath === \"..\" ||\n skillRelativePath.startsWith(\"../\") ||\n skillRelativePath.startsWith(\"..\\\\\")\n ) {\n return failInstall(\"skill id would escape target dir\");\n }\n\n const skillTargetDir = resolvedSkillDir;\n\n await mkdir(targetDir, { recursive: true });\n await recoverSkillReplacement(skillTargetDir);\n const state = await resolveSkillInstallStateForTarget({\n skill: input.skill,\n target: input.target,\n });\n if (state.state === \"external_conflict\") {\n return {\n targetId: input.target.id,\n targetDir,\n targetType: input.target.type,\n skillId: input.skill.id,\n status: \"skipped\",\n mode: resolveSkippedInstallMode(state),\n degraded: false,\n reason: state.reason,\n };\n }\n\n if (state.state === \"up_to_date\") {\n return {\n targetId: input.target.id,\n targetDir,\n targetType: input.target.type,\n skillId: input.skill.id,\n status: \"skipped\",\n mode: resolveSkippedInstallMode(state),\n degraded: false,\n reason: state.reason,\n };\n }\n\n const installation: { mode: SkillsInstallMode } = { mode: \"symlink\" };\n try {\n await readFile(join(input.skill.absolutePath, \"SKILL.md\"), \"utf8\");\n await replaceSkillDirectory(skillTargetDir, async (stagedDir) => {\n const symlinked = await tryCreateSymlink({\n sourceDir: input.skill.absolutePath,\n targetDir: stagedDir,\n });\n if (symlinked) {\n return;\n }\n installation.mode = \"copy\";\n await cp(input.skill.absolutePath, stagedDir, {\n recursive: true,\n errorOnExist: true,\n force: false,\n });\n await writeOpenMeldSkillMarker({\n skillDir: stagedDir,\n skillId: input.skill.id,\n mode: \"copy\",\n ...(input.skill.contentHash\n ? { contentHash: input.skill.contentHash }\n : {}),\n ...(input.skill.version ? { version: input.skill.version } : {}),\n });\n });\n return {\n targetId: input.target.id,\n targetDir,\n targetType: input.target.type,\n skillId: input.skill.id,\n status: \"installed\",\n mode: installation.mode,\n degraded: installation.mode === \"copy\",\n ...(installation.mode === \"copy\"\n ? { reason: \"symlink failed; fell back to copy\" }\n : {}),\n };\n } catch (error) {\n return failInstall(\n error instanceof Error\n ? error.message\n : \"failed to install skill to target\"\n );\n }\n}\n\nfunction resolveSkippedInstallMode(\n state: SkillInstallStateResult\n): SkillsInstallMode {\n if (state.targetMode === \"copy\") {\n return \"copy\";\n }\n if (state.targetMode === \"symlink\") {\n return \"symlink\";\n }\n return \"unknown\";\n}\n\nasync function tryCreateSymlink(input: {\n sourceDir: string;\n targetDir: string;\n}): Promise<boolean> {\n try {\n await mkdir(dirname(input.targetDir), { recursive: true });\n\n const targetParentDir = dirname(input.targetDir);\n const resolvedTargetParentDir = await realpath(targetParentDir).catch(\n () => targetParentDir\n );\n const resolvedSourceDir = await realpath(input.sourceDir).catch(\n () => input.sourceDir\n );\n const relativeTarget = relative(resolvedTargetParentDir, resolvedSourceDir);\n await symlink(\n process.platform === \"win32\" ? resolvedSourceDir : relativeTarget,\n input.targetDir,\n process.platform === \"win32\" ? \"junction\" : undefined\n );\n return true;\n } catch {\n return false;\n }\n}\n","import { stat } from \"node:fs/promises\";\nimport { skillsDir } from \"../config/paths\";\nimport {\n getConfiguredSkillsConfig,\n type RuntimeSkillsConfig,\n type RuntimeSkillsCustomTarget,\n type RuntimeSkillsInstallRecord,\n resolveRuntimeSkillsCustomTargetId,\n updateConfiguredSkillsConfig,\n} from \"../config/runtime-config\";\nimport {\n canManageRegistryAgentSkillTargets,\n detectInstalledSkillsAgents,\n resolveSkillsAgentRegistry,\n} from \"./agents\";\nimport type { SkillsInstallTarget } from \"./installer\";\nimport {\n resolveSkillInstallStateForTarget,\n resolveSkillsInstallStates,\n type SkillInstallStateResult,\n} from \"./state\";\nimport { ensureLocalSkills, type LocalSkill } from \"./store\";\n\nexport type SkillsReadinessSnapshot = {\n status: \"up_to_date\" | \"action_required\" | \"no_targets\";\n targetCount: number;\n summary: {\n upToDate: number;\n outdated: number;\n missing: number;\n externalConflict: number;\n };\n};\n\nexport async function collectSkillsReadinessSnapshot(): Promise<SkillsReadinessSnapshot> {\n const skillsConfig = await getConfiguredSkillsConfig();\n const registry = resolveSkillsAgentRegistry(skillsConfig);\n const installedAgents = await detectInstalledSkillsAgents(registry);\n const localSkills = await ensureLocalSkills();\n const detectedAgentTargets = buildAgentTargets(installedAgents, registry);\n const trackedTargets = await resolveTrackedInstallTargets({\n skillsConfig,\n registry,\n localSkills,\n onlyOpenMeldInstalledTargets: false,\n });\n const checkTargets = mergeTargetsByDir({\n primary: detectedAgentTargets,\n secondary: trackedTargets,\n });\n const states = await resolveSkillsInstallStates({\n skills: localSkills,\n targets: checkTargets,\n });\n await persistDetectedInstallStateFromCheck({ states });\n const summary = summarizeSkillState(states);\n const hasIssues =\n summary.outdated > 0 || summary.missing > 0 || summary.externalConflict > 0;\n let status: SkillsReadinessSnapshot[\"status\"] = \"up_to_date\";\n if (checkTargets.length === 0) {\n status = \"no_targets\";\n } else if (hasIssues) {\n status = \"action_required\";\n }\n return {\n status,\n targetCount: checkTargets.length,\n summary,\n };\n}\n\nexport function buildAgentTargets(\n agents: string[],\n registry: ReturnType<typeof resolveSkillsAgentRegistry>\n): SkillsInstallTarget[] {\n return agents.flatMap((agentName) => {\n const config = registry[agentName];\n if (!config?.globalSkillsDir || config.skillsInstallable !== true) {\n return [];\n }\n return [\n {\n id: agentName,\n dir: config.globalSkillsDir,\n type: \"agent\" as const,\n },\n ];\n });\n}\n\nfunction isLikelyCustomTargetId(value: string): boolean {\n return value.startsWith(\"custom-\");\n}\n\nexport function resolveTrackedInstallTargets(input: {\n skillsConfig: RuntimeSkillsConfig | null;\n registry: ReturnType<typeof resolveSkillsAgentRegistry>;\n localSkills: LocalSkill[];\n onlyOpenMeldInstalledTargets: boolean;\n}): Promise<SkillsInstallTarget[]> {\n const installs = input.skillsConfig?.installs ?? [];\n const customTargets = input.skillsConfig?.customTargets ?? [];\n const customTargetByDir = buildCustomTargetByDir(customTargets);\n const byTargetDir = new Map<string, SkillsInstallTarget>();\n seedTrackedTargetsFromCustomTargets({\n byTargetDir,\n customTargetByDir,\n });\n seedTrackedTargetsFromInstallRecords({\n byTargetDir,\n installs,\n registry: input.registry,\n customTargetByDir,\n });\n\n const candidates = sortTrackedTargets([...byTargetDir.values()]);\n const allowRegistryDefaults = canManageRegistryAgentSkillTargets();\n const laneSafeCandidates = allowRegistryDefaults\n ? candidates\n : candidates.filter(\n (target) =>\n target.type === \"custom\" ||\n input.registry[target.id]?.globalSkillsDirSource === \"config-override\"\n );\n return filterTrackedTargetsByState({\n candidates: laneSafeCandidates,\n localSkills: input.localSkills,\n onlyOpenMeldInstalledTargets: input.onlyOpenMeldInstalledTargets,\n });\n}\n\nfunction buildCustomTargetByDir(\n customTargets: RuntimeSkillsCustomTarget[]\n): Map<string, RuntimeSkillsCustomTarget> {\n const customTargetByDir = new Map<string, RuntimeSkillsCustomTarget>();\n for (const customTarget of customTargets) {\n const id = resolveRuntimeSkillsCustomTargetId({\n dir: customTarget.dir,\n ...(customTarget.id ? { id: customTarget.id } : {}),\n });\n customTargetByDir.set(customTarget.dir, {\n id,\n name: customTarget.name,\n dir: customTarget.dir,\n });\n }\n return customTargetByDir;\n}\n\nfunction seedTrackedTargetsFromCustomTargets(input: {\n byTargetDir: Map<string, SkillsInstallTarget>;\n customTargetByDir: Map<string, RuntimeSkillsCustomTarget>;\n}): void {\n for (const customTarget of input.customTargetByDir.values()) {\n input.byTargetDir.set(customTarget.dir, {\n id:\n customTarget.id ??\n resolveRuntimeSkillsCustomTargetId({ dir: customTarget.dir }),\n dir: customTarget.dir,\n type: \"custom\",\n });\n }\n}\n\nfunction seedTrackedTargetsFromInstallRecords(input: {\n byTargetDir: Map<string, SkillsInstallTarget>;\n installs: RuntimeSkillsInstallRecord[];\n registry: ReturnType<typeof resolveSkillsAgentRegistry>;\n customTargetByDir: Map<string, RuntimeSkillsCustomTarget>;\n}): void {\n for (const install of input.installs) {\n const trackedTarget = buildTrackedTargetFromInstallRecord({\n install,\n registry: input.registry,\n customTargetByDir: input.customTargetByDir,\n });\n input.byTargetDir.set(install.targetDir, trackedTarget);\n }\n}\n\nfunction buildTrackedTargetFromInstallRecord(input: {\n install: RuntimeSkillsInstallRecord;\n registry: ReturnType<typeof resolveSkillsAgentRegistry>;\n customTargetByDir: Map<string, RuntimeSkillsCustomTarget>;\n}): SkillsInstallTarget {\n const knownAgentDir = input.registry[input.install.targetId]?.globalSkillsDir;\n const targetType: SkillsInstallTarget[\"type\"] =\n knownAgentDir && knownAgentDir === input.install.targetDir\n ? \"agent\"\n : \"custom\";\n if (targetType === \"agent\") {\n return {\n id: input.install.targetId,\n dir: input.install.targetDir,\n type: \"agent\",\n };\n }\n\n const customTarget = input.customTargetByDir.get(input.install.targetDir);\n const fallbackCustomId = isLikelyCustomTargetId(input.install.targetId)\n ? input.install.targetId\n : undefined;\n const resolvedCustomId = customTarget?.id ?? fallbackCustomId;\n return {\n id: resolveRuntimeSkillsCustomTargetId({\n dir: input.install.targetDir,\n ...(resolvedCustomId ? { id: resolvedCustomId } : {}),\n }),\n dir: input.install.targetDir,\n type: \"custom\",\n };\n}\n\nfunction sortTrackedTargets(\n targets: SkillsInstallTarget[]\n): SkillsInstallTarget[] {\n return [...targets].sort((a, b) =>\n `${a.id}:${a.dir}`.localeCompare(`${b.id}:${b.dir}`)\n );\n}\n\nexport function mergeTargetsByDir(input: {\n primary: SkillsInstallTarget[];\n secondary: SkillsInstallTarget[];\n}): SkillsInstallTarget[] {\n const byDir = new Map<string, SkillsInstallTarget>();\n for (const target of input.secondary) {\n byDir.set(target.dir, target);\n }\n for (const target of input.primary) {\n byDir.set(target.dir, target);\n }\n return sortTrackedTargets([...byDir.values()]);\n}\n\nasync function filterInstalledTrackedTargets(input: {\n candidates: SkillsInstallTarget[];\n localSkills: LocalSkill[];\n}): Promise<SkillsInstallTarget[]> {\n const installedOnly: SkillsInstallTarget[] = [];\n for (const candidate of input.candidates) {\n const hasInstalledOpenMeldSkill = await targetHasInstalledOpenMeldSkill({\n target: candidate,\n localSkills: input.localSkills,\n });\n if (!hasInstalledOpenMeldSkill) {\n continue;\n }\n installedOnly.push(candidate);\n }\n return installedOnly;\n}\n\nexport async function filterTargetsWithInstalledOpenMeldSkills(input: {\n targets: SkillsInstallTarget[];\n localSkills: LocalSkill[];\n}): Promise<SkillsInstallTarget[]> {\n const existingTargets = await filterExistingTargetDirs(input.targets);\n return filterInstalledTrackedTargets({\n candidates: existingTargets,\n localSkills: input.localSkills,\n });\n}\n\nasync function filterTrackedTargetsByState(input: {\n candidates: SkillsInstallTarget[];\n localSkills: LocalSkill[];\n onlyOpenMeldInstalledTargets: boolean;\n}): Promise<SkillsInstallTarget[]> {\n const existingTargets = await filterExistingTargetDirs(input.candidates);\n if (!input.onlyOpenMeldInstalledTargets) {\n return existingTargets;\n }\n\n return filterInstalledTrackedTargets({\n candidates: existingTargets,\n localSkills: input.localSkills,\n });\n}\n\nasync function filterExistingTargetDirs(\n candidates: SkillsInstallTarget[]\n): Promise<SkillsInstallTarget[]> {\n const existing: SkillsInstallTarget[] = [];\n for (const candidate of candidates) {\n const targetDirStats = await stat(candidate.dir).catch(() => null);\n if (!targetDirStats?.isDirectory()) {\n continue;\n }\n existing.push(candidate);\n }\n return existing;\n}\n\nexport function summarizeSkillState(states: SkillInstallStateResult[]): {\n upToDate: number;\n outdated: number;\n missing: number;\n externalConflict: number;\n} {\n return {\n upToDate: states.filter((state) => state.state === \"up_to_date\").length,\n outdated: states.filter((state) => state.state === \"outdated\").length,\n missing: states.filter((state) => state.state === \"missing\").length,\n externalConflict: states.filter(\n (state) => state.state === \"external_conflict\"\n ).length,\n };\n}\n\nasync function targetHasInstalledOpenMeldSkill(input: {\n target: SkillsInstallTarget;\n localSkills: LocalSkill[];\n}): Promise<boolean> {\n const targetDirStats = await stat(input.target.dir).catch(() => null);\n if (!targetDirStats?.isDirectory()) {\n return false;\n }\n\n for (const skill of input.localSkills) {\n const state = await resolveSkillInstallStateForTarget({\n skill,\n target: input.target,\n });\n if (state.state === \"up_to_date\" || state.state === \"outdated\") {\n return true;\n }\n }\n\n return false;\n}\n\nexport async function persistDetectedInstallStateFromCheck(input: {\n states: SkillInstallStateResult[];\n}): Promise<void> {\n const discoveredByTargetDir = new Map<string, SkillInstallStateResult[]>();\n for (const state of input.states) {\n if (!(state.state === \"up_to_date\" || state.state === \"outdated\")) {\n continue;\n }\n const list = discoveredByTargetDir.get(state.targetDir) ?? [];\n list.push(state);\n discoveredByTargetDir.set(state.targetDir, list);\n }\n\n if (discoveredByTargetDir.size === 0) {\n return;\n }\n\n await updateConfiguredSkillsConfig((currentSkillsConfig) => {\n const byTargetDir = new Map<string, RuntimeSkillsInstallRecord>();\n for (const record of currentSkillsConfig?.installs ?? []) {\n byTargetDir.set(record.targetDir, record);\n }\n\n const now = new Date().toISOString();\n for (const [targetDir, group] of discoveredByTargetDir) {\n const first = group[0];\n if (!first) {\n continue;\n }\n const mode: RuntimeSkillsInstallRecord[\"mode\"] = group.some(\n (state) => state.targetMode === \"copy\"\n )\n ? \"copy\"\n : \"symlink\";\n const skillIds = Array.from(\n new Set(group.map((state) => state.skillId))\n ).sort((a, b) => a.localeCompare(b));\n\n byTargetDir.set(targetDir, {\n targetId: first.targetId,\n targetDir,\n mode,\n status: \"installed\",\n skillIds,\n updatedAt: now,\n });\n }\n\n const nextInstalls = [...byTargetDir.values()].sort(compareInstallRecords);\n const previousInstalls = [...(currentSkillsConfig?.installs ?? [])]\n .sort(compareInstallRecords)\n .map(normalizeInstallRecordForCompare);\n const nextComparable = nextInstalls.map(normalizeInstallRecordForCompare);\n if (JSON.stringify(previousInstalls) === JSON.stringify(nextComparable)) {\n return currentSkillsConfig;\n }\n\n return {\n storeDir: currentSkillsConfig?.storeDir ?? skillsDir(),\n ...(currentSkillsConfig?.agents\n ? { agents: currentSkillsConfig.agents }\n : {}),\n ...(currentSkillsConfig?.customTargets\n ? { customTargets: currentSkillsConfig.customTargets }\n : {}),\n installs: nextInstalls,\n };\n });\n}\n\nexport function compareInstallRecords(\n left: RuntimeSkillsInstallRecord,\n right: RuntimeSkillsInstallRecord\n): number {\n const byTargetId = left.targetId.localeCompare(right.targetId);\n if (byTargetId !== 0) {\n return byTargetId;\n }\n return left.targetDir.localeCompare(right.targetDir);\n}\n\nfunction normalizeInstallRecordForCompare(\n input: RuntimeSkillsInstallRecord\n): Omit<RuntimeSkillsInstallRecord, \"updatedAt\"> {\n return {\n targetId: input.targetId,\n targetDir: input.targetDir,\n mode: input.mode,\n status: input.status,\n skillIds: [...input.skillIds].sort((a, b) => a.localeCompare(b)),\n ...(input.reason ? { reason: input.reason } : {}),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"installation-inventory-DJlwXa1q.js","names":["getErrorCode","process"],"sources":["../../../packages/schemas/dist/official-cli-skill.js","../src/skills/install-lock.ts","../src/skills/replace-directory.ts","../src/skills/content-hash.ts","../src/skills/bundled.ts","../src/skills/bundled-assets-fs.ts","../src/skills/bundled-assets.ts","../src/skills/official-release.ts","../src/skills/store.ts","../src/skills/state.ts","../src/skills/installer.ts","../src/skills/installation-inventory.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 { 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 } 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 { 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 { 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 { 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 { 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","import { cp, mkdir, readFile, realpath, symlink } from \"node:fs/promises\";\nimport { dirname, isAbsolute, join, relative, resolve } from \"node:path\";\nimport process from \"node:process\";\nimport { withSkillsInstallLock } from \"./install-lock\";\n\n// biome-ignore lint/performance/noBarrelFile: Keep the existing installer lock API while the source store shares its owner.\nexport { withSkillsInstallLock } from \"./install-lock\";\n\nimport {\n recoverSkillReplacement,\n replaceSkillDirectory,\n} from \"./replace-directory\";\nimport type { SkillInstallStateResult } from \"./state\";\nimport { resolveSkillInstallStateForTarget } from \"./state\";\nimport type { LocalSkill } from \"./store\";\nimport { writeOpenMeldSkillMarker } from \"./store\";\n\nexport type SkillsInstallMode = \"symlink\" | \"copy\" | \"unknown\";\nexport type SkillsInstallStatus = \"installed\" | \"skipped\" | \"failed\";\n\nexport type SkillsInstallTarget = {\n id: string;\n dir: string;\n type: \"agent\" | \"custom\";\n};\n\nexport type SkillsInstallResult = {\n targetId: string;\n targetDir: string;\n targetType: \"agent\" | \"custom\";\n skillId: string;\n status: SkillsInstallStatus;\n mode: SkillsInstallMode;\n degraded: boolean;\n reason?: string;\n};\n\nexport function installSkillsToTargets(input: {\n skills: LocalSkill[];\n targets: SkillsInstallTarget[];\n}): Promise<SkillsInstallResult[]> {\n return withSkillsInstallLock(() => installSkillsToTargetsLocked(input));\n}\n\nasync function installSkillsToTargetsLocked(input: {\n skills: LocalSkill[];\n targets: SkillsInstallTarget[];\n}): Promise<SkillsInstallResult[]> {\n const results: SkillsInstallResult[] = [];\n\n for (const target of input.targets) {\n for (const skill of input.skills) {\n const result = await installOneSkillToTarget({\n skill,\n target,\n });\n results.push(result);\n }\n }\n\n return results;\n}\n\nasync function installOneSkillToTarget(input: {\n skill: LocalSkill;\n target: SkillsInstallTarget;\n}): Promise<SkillsInstallResult> {\n const targetDir = input.target.dir;\n const failInstall = (reason: string): SkillsInstallResult => ({\n targetId: input.target.id,\n targetDir,\n targetType: input.target.type,\n skillId: input.skill.id,\n status: \"failed\",\n mode: \"unknown\",\n degraded: false,\n reason,\n });\n\n if (!isAbsolute(targetDir)) {\n return failInstall(\"target dir must be an absolute path\");\n }\n\n const skillId = input.skill.id;\n if (\n skillId.trim().length === 0 ||\n isAbsolute(skillId) ||\n skillId === \".\" ||\n skillId === \"..\" ||\n skillId.includes(\"/\") ||\n skillId.includes(\"\\\\\")\n ) {\n return failInstall(\"skill id would escape target dir\");\n }\n\n const resolvedTargetDir = resolve(targetDir);\n const resolvedSkillDir = resolve(resolvedTargetDir, skillId);\n const skillRelativePath = relative(resolvedTargetDir, resolvedSkillDir);\n if (\n skillRelativePath === \"..\" ||\n skillRelativePath.startsWith(\"../\") ||\n skillRelativePath.startsWith(\"..\\\\\")\n ) {\n return failInstall(\"skill id would escape target dir\");\n }\n\n const skillTargetDir = resolvedSkillDir;\n\n await mkdir(targetDir, { recursive: true });\n await recoverSkillReplacement(skillTargetDir);\n const state = await resolveSkillInstallStateForTarget({\n skill: input.skill,\n target: input.target,\n });\n if (state.state === \"external_conflict\") {\n return {\n targetId: input.target.id,\n targetDir,\n targetType: input.target.type,\n skillId: input.skill.id,\n status: \"skipped\",\n mode: resolveSkippedInstallMode(state),\n degraded: false,\n reason: state.reason,\n };\n }\n\n if (state.state === \"up_to_date\") {\n return {\n targetId: input.target.id,\n targetDir,\n targetType: input.target.type,\n skillId: input.skill.id,\n status: \"skipped\",\n mode: resolveSkippedInstallMode(state),\n degraded: false,\n reason: state.reason,\n };\n }\n\n const installation: { mode: SkillsInstallMode } = { mode: \"symlink\" };\n try {\n await readFile(join(input.skill.absolutePath, \"SKILL.md\"), \"utf8\");\n await replaceSkillDirectory(skillTargetDir, async (stagedDir) => {\n const symlinked = await tryCreateSymlink({\n sourceDir: input.skill.absolutePath,\n targetDir: stagedDir,\n });\n if (symlinked) {\n return;\n }\n installation.mode = \"copy\";\n await cp(input.skill.absolutePath, stagedDir, {\n recursive: true,\n errorOnExist: true,\n force: false,\n });\n await writeOpenMeldSkillMarker({\n skillDir: stagedDir,\n skillId: input.skill.id,\n mode: \"copy\",\n ...(input.skill.contentHash\n ? { contentHash: input.skill.contentHash }\n : {}),\n ...(input.skill.version ? { version: input.skill.version } : {}),\n });\n });\n return {\n targetId: input.target.id,\n targetDir,\n targetType: input.target.type,\n skillId: input.skill.id,\n status: \"installed\",\n mode: installation.mode,\n degraded: installation.mode === \"copy\",\n ...(installation.mode === \"copy\"\n ? { reason: \"symlink failed; fell back to copy\" }\n : {}),\n };\n } catch (error) {\n return failInstall(\n error instanceof Error\n ? error.message\n : \"failed to install skill to target\"\n );\n }\n}\n\nfunction resolveSkippedInstallMode(\n state: SkillInstallStateResult\n): SkillsInstallMode {\n if (state.targetMode === \"copy\") {\n return \"copy\";\n }\n if (state.targetMode === \"symlink\") {\n return \"symlink\";\n }\n return \"unknown\";\n}\n\nasync function tryCreateSymlink(input: {\n sourceDir: string;\n targetDir: string;\n}): Promise<boolean> {\n try {\n await mkdir(dirname(input.targetDir), { recursive: true });\n\n const targetParentDir = dirname(input.targetDir);\n const resolvedTargetParentDir = await realpath(targetParentDir).catch(\n () => targetParentDir\n );\n const resolvedSourceDir = await realpath(input.sourceDir).catch(\n () => input.sourceDir\n );\n const relativeTarget = relative(resolvedTargetParentDir, resolvedSourceDir);\n await symlink(\n process.platform === \"win32\" ? resolvedSourceDir : relativeTarget,\n input.targetDir,\n process.platform === \"win32\" ? \"junction\" : undefined\n );\n return true;\n } catch {\n return false;\n }\n}\n","import { stat } from \"node:fs/promises\";\nimport { skillsDir } from \"../config/paths\";\nimport {\n getConfiguredSkillsConfig,\n type RuntimeSkillsConfig,\n type RuntimeSkillsCustomTarget,\n type RuntimeSkillsInstallRecord,\n resolveRuntimeSkillsCustomTargetId,\n updateConfiguredSkillsConfig,\n} from \"../config/runtime-config\";\nimport {\n canManageRegistryAgentSkillTargets,\n detectInstalledSkillsAgents,\n resolveSkillsAgentRegistry,\n} from \"./agents\";\nimport type { SkillsInstallTarget } from \"./installer\";\nimport {\n resolveSkillInstallStateForTarget,\n resolveSkillsInstallStates,\n type SkillInstallStateResult,\n} from \"./state\";\nimport { ensureLocalSkills, type LocalSkill } from \"./store\";\n\nexport type SkillsReadinessSnapshot = {\n status: \"up_to_date\" | \"action_required\" | \"no_targets\";\n targetCount: number;\n summary: {\n upToDate: number;\n outdated: number;\n missing: number;\n externalConflict: number;\n };\n};\n\nexport async function collectSkillsReadinessSnapshot(): Promise<SkillsReadinessSnapshot> {\n const skillsConfig = await getConfiguredSkillsConfig();\n const registry = resolveSkillsAgentRegistry(skillsConfig);\n const installedAgents = await detectInstalledSkillsAgents(registry);\n const localSkills = await ensureLocalSkills();\n const detectedAgentTargets = buildAgentTargets(installedAgents, registry);\n const trackedTargets = await resolveTrackedInstallTargets({\n skillsConfig,\n registry,\n localSkills,\n onlyOpenMeldInstalledTargets: false,\n });\n const checkTargets = mergeTargetsByDir({\n primary: detectedAgentTargets,\n secondary: trackedTargets,\n });\n const states = await resolveSkillsInstallStates({\n skills: localSkills,\n targets: checkTargets,\n });\n await persistDetectedInstallStateFromCheck({ states });\n const summary = summarizeSkillState(states);\n const hasIssues =\n summary.outdated > 0 || summary.missing > 0 || summary.externalConflict > 0;\n let status: SkillsReadinessSnapshot[\"status\"] = \"up_to_date\";\n if (checkTargets.length === 0) {\n status = \"no_targets\";\n } else if (hasIssues) {\n status = \"action_required\";\n }\n return {\n status,\n targetCount: checkTargets.length,\n summary,\n };\n}\n\nexport function buildAgentTargets(\n agents: string[],\n registry: ReturnType<typeof resolveSkillsAgentRegistry>\n): SkillsInstallTarget[] {\n return agents.flatMap((agentName) => {\n const config = registry[agentName];\n if (!config?.globalSkillsDir || config.skillsInstallable !== true) {\n return [];\n }\n return [\n {\n id: agentName,\n dir: config.globalSkillsDir,\n type: \"agent\" as const,\n },\n ];\n });\n}\n\nfunction isLikelyCustomTargetId(value: string): boolean {\n return value.startsWith(\"custom-\");\n}\n\nexport function resolveTrackedInstallTargets(input: {\n skillsConfig: RuntimeSkillsConfig | null;\n registry: ReturnType<typeof resolveSkillsAgentRegistry>;\n localSkills: LocalSkill[];\n onlyOpenMeldInstalledTargets: boolean;\n}): Promise<SkillsInstallTarget[]> {\n const installs = input.skillsConfig?.installs ?? [];\n const customTargets = input.skillsConfig?.customTargets ?? [];\n const customTargetByDir = buildCustomTargetByDir(customTargets);\n const byTargetDir = new Map<string, SkillsInstallTarget>();\n seedTrackedTargetsFromCustomTargets({\n byTargetDir,\n customTargetByDir,\n });\n seedTrackedTargetsFromInstallRecords({\n byTargetDir,\n installs,\n registry: input.registry,\n customTargetByDir,\n });\n\n const candidates = sortTrackedTargets([...byTargetDir.values()]);\n const allowRegistryDefaults = canManageRegistryAgentSkillTargets();\n const laneSafeCandidates = allowRegistryDefaults\n ? candidates\n : candidates.filter(\n (target) =>\n target.type === \"custom\" ||\n input.registry[target.id]?.globalSkillsDirSource === \"config-override\"\n );\n return filterTrackedTargetsByState({\n candidates: laneSafeCandidates,\n localSkills: input.localSkills,\n onlyOpenMeldInstalledTargets: input.onlyOpenMeldInstalledTargets,\n });\n}\n\nfunction buildCustomTargetByDir(\n customTargets: RuntimeSkillsCustomTarget[]\n): Map<string, RuntimeSkillsCustomTarget> {\n const customTargetByDir = new Map<string, RuntimeSkillsCustomTarget>();\n for (const customTarget of customTargets) {\n const id = resolveRuntimeSkillsCustomTargetId({\n dir: customTarget.dir,\n ...(customTarget.id ? { id: customTarget.id } : {}),\n });\n customTargetByDir.set(customTarget.dir, {\n id,\n name: customTarget.name,\n dir: customTarget.dir,\n });\n }\n return customTargetByDir;\n}\n\nfunction seedTrackedTargetsFromCustomTargets(input: {\n byTargetDir: Map<string, SkillsInstallTarget>;\n customTargetByDir: Map<string, RuntimeSkillsCustomTarget>;\n}): void {\n for (const customTarget of input.customTargetByDir.values()) {\n input.byTargetDir.set(customTarget.dir, {\n id:\n customTarget.id ??\n resolveRuntimeSkillsCustomTargetId({ dir: customTarget.dir }),\n dir: customTarget.dir,\n type: \"custom\",\n });\n }\n}\n\nfunction seedTrackedTargetsFromInstallRecords(input: {\n byTargetDir: Map<string, SkillsInstallTarget>;\n installs: RuntimeSkillsInstallRecord[];\n registry: ReturnType<typeof resolveSkillsAgentRegistry>;\n customTargetByDir: Map<string, RuntimeSkillsCustomTarget>;\n}): void {\n for (const install of input.installs) {\n const trackedTarget = buildTrackedTargetFromInstallRecord({\n install,\n registry: input.registry,\n customTargetByDir: input.customTargetByDir,\n });\n input.byTargetDir.set(install.targetDir, trackedTarget);\n }\n}\n\nfunction buildTrackedTargetFromInstallRecord(input: {\n install: RuntimeSkillsInstallRecord;\n registry: ReturnType<typeof resolveSkillsAgentRegistry>;\n customTargetByDir: Map<string, RuntimeSkillsCustomTarget>;\n}): SkillsInstallTarget {\n const knownAgentDir = input.registry[input.install.targetId]?.globalSkillsDir;\n const targetType: SkillsInstallTarget[\"type\"] =\n knownAgentDir && knownAgentDir === input.install.targetDir\n ? \"agent\"\n : \"custom\";\n if (targetType === \"agent\") {\n return {\n id: input.install.targetId,\n dir: input.install.targetDir,\n type: \"agent\",\n };\n }\n\n const customTarget = input.customTargetByDir.get(input.install.targetDir);\n const fallbackCustomId = isLikelyCustomTargetId(input.install.targetId)\n ? input.install.targetId\n : undefined;\n const resolvedCustomId = customTarget?.id ?? fallbackCustomId;\n return {\n id: resolveRuntimeSkillsCustomTargetId({\n dir: input.install.targetDir,\n ...(resolvedCustomId ? { id: resolvedCustomId } : {}),\n }),\n dir: input.install.targetDir,\n type: \"custom\",\n };\n}\n\nfunction sortTrackedTargets(\n targets: SkillsInstallTarget[]\n): SkillsInstallTarget[] {\n return [...targets].sort((a, b) =>\n `${a.id}:${a.dir}`.localeCompare(`${b.id}:${b.dir}`)\n );\n}\n\nexport function mergeTargetsByDir(input: {\n primary: SkillsInstallTarget[];\n secondary: SkillsInstallTarget[];\n}): SkillsInstallTarget[] {\n const byDir = new Map<string, SkillsInstallTarget>();\n for (const target of input.secondary) {\n byDir.set(target.dir, target);\n }\n for (const target of input.primary) {\n byDir.set(target.dir, target);\n }\n return sortTrackedTargets([...byDir.values()]);\n}\n\nasync function filterInstalledTrackedTargets(input: {\n candidates: SkillsInstallTarget[];\n localSkills: LocalSkill[];\n}): Promise<SkillsInstallTarget[]> {\n const installedOnly: SkillsInstallTarget[] = [];\n for (const candidate of input.candidates) {\n const hasInstalledOpenMeldSkill = await targetHasInstalledOpenMeldSkill({\n target: candidate,\n localSkills: input.localSkills,\n });\n if (!hasInstalledOpenMeldSkill) {\n continue;\n }\n installedOnly.push(candidate);\n }\n return installedOnly;\n}\n\nexport async function filterTargetsWithInstalledOpenMeldSkills(input: {\n targets: SkillsInstallTarget[];\n localSkills: LocalSkill[];\n}): Promise<SkillsInstallTarget[]> {\n const existingTargets = await filterExistingTargetDirs(input.targets);\n return filterInstalledTrackedTargets({\n candidates: existingTargets,\n localSkills: input.localSkills,\n });\n}\n\nasync function filterTrackedTargetsByState(input: {\n candidates: SkillsInstallTarget[];\n localSkills: LocalSkill[];\n onlyOpenMeldInstalledTargets: boolean;\n}): Promise<SkillsInstallTarget[]> {\n const existingTargets = await filterExistingTargetDirs(input.candidates);\n if (!input.onlyOpenMeldInstalledTargets) {\n return existingTargets;\n }\n\n return filterInstalledTrackedTargets({\n candidates: existingTargets,\n localSkills: input.localSkills,\n });\n}\n\nasync function filterExistingTargetDirs(\n candidates: SkillsInstallTarget[]\n): Promise<SkillsInstallTarget[]> {\n const existing: SkillsInstallTarget[] = [];\n for (const candidate of candidates) {\n const targetDirStats = await stat(candidate.dir).catch(() => null);\n if (!targetDirStats?.isDirectory()) {\n continue;\n }\n existing.push(candidate);\n }\n return existing;\n}\n\nexport function summarizeSkillState(states: SkillInstallStateResult[]): {\n upToDate: number;\n outdated: number;\n missing: number;\n externalConflict: number;\n} {\n return {\n upToDate: states.filter((state) => state.state === \"up_to_date\").length,\n outdated: states.filter((state) => state.state === \"outdated\").length,\n missing: states.filter((state) => state.state === \"missing\").length,\n externalConflict: states.filter(\n (state) => state.state === \"external_conflict\"\n ).length,\n };\n}\n\nasync function targetHasInstalledOpenMeldSkill(input: {\n target: SkillsInstallTarget;\n localSkills: LocalSkill[];\n}): Promise<boolean> {\n const targetDirStats = await stat(input.target.dir).catch(() => null);\n if (!targetDirStats?.isDirectory()) {\n return false;\n }\n\n for (const skill of input.localSkills) {\n const state = await resolveSkillInstallStateForTarget({\n skill,\n target: input.target,\n });\n if (state.state === \"up_to_date\" || state.state === \"outdated\") {\n return true;\n }\n }\n\n return false;\n}\n\nexport async function persistDetectedInstallStateFromCheck(input: {\n states: SkillInstallStateResult[];\n}): Promise<void> {\n const discoveredByTargetDir = new Map<string, SkillInstallStateResult[]>();\n for (const state of input.states) {\n if (!(state.state === \"up_to_date\" || state.state === \"outdated\")) {\n continue;\n }\n const list = discoveredByTargetDir.get(state.targetDir) ?? [];\n list.push(state);\n discoveredByTargetDir.set(state.targetDir, list);\n }\n\n if (discoveredByTargetDir.size === 0) {\n return;\n }\n\n await updateConfiguredSkillsConfig((currentSkillsConfig) => {\n const byTargetDir = new Map<string, RuntimeSkillsInstallRecord>();\n for (const record of currentSkillsConfig?.installs ?? []) {\n byTargetDir.set(record.targetDir, record);\n }\n\n const now = new Date().toISOString();\n for (const [targetDir, group] of discoveredByTargetDir) {\n const first = group[0];\n if (!first) {\n continue;\n }\n const mode: RuntimeSkillsInstallRecord[\"mode\"] = group.some(\n (state) => state.targetMode === \"copy\"\n )\n ? \"copy\"\n : \"symlink\";\n const skillIds = Array.from(\n new Set(group.map((state) => state.skillId))\n ).sort((a, b) => a.localeCompare(b));\n\n byTargetDir.set(targetDir, {\n targetId: first.targetId,\n targetDir,\n mode,\n status: \"installed\",\n skillIds,\n updatedAt: now,\n });\n }\n\n const nextInstalls = [...byTargetDir.values()].sort(compareInstallRecords);\n const previousInstalls = [...(currentSkillsConfig?.installs ?? [])]\n .sort(compareInstallRecords)\n .map(normalizeInstallRecordForCompare);\n const nextComparable = nextInstalls.map(normalizeInstallRecordForCompare);\n if (JSON.stringify(previousInstalls) === JSON.stringify(nextComparable)) {\n return currentSkillsConfig;\n }\n\n return {\n storeDir: currentSkillsConfig?.storeDir ?? skillsDir(),\n ...(currentSkillsConfig?.agents\n ? { agents: currentSkillsConfig.agents }\n : {}),\n ...(currentSkillsConfig?.customTargets\n ? { customTargets: currentSkillsConfig.customTargets }\n : {}),\n installs: nextInstalls,\n };\n });\n}\n\nexport function compareInstallRecords(\n left: RuntimeSkillsInstallRecord,\n right: RuntimeSkillsInstallRecord\n): number {\n const byTargetId = left.targetId.localeCompare(right.targetId);\n if (byTargetId !== 0) {\n return byTargetId;\n }\n return left.targetDir.localeCompare(right.targetDir);\n}\n\nfunction normalizeInstallRecordForCompare(\n input: RuntimeSkillsInstallRecord\n): Omit<RuntimeSkillsInstallRecord, \"updatedAt\"> {\n return {\n targetId: input.targetId,\n targetDir: input.targetDir,\n mode: input.mode,\n status: input.status,\n skillIds: [...input.skillIds].sort((a, b) => a.localeCompare(b)),\n ...(input.reason ? { reason: input.reason } : {}),\n };\n}\n"],"mappings":"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"}
@@ -861,7 +861,40 @@ async function acquireLock(input) {
861
861
  }
862
862
  async function releaseLock(lock) {
863
863
  if (!await unlinkOwnedDirectoryEntry(lock)) return;
864
- await rmdir(lock.path);
864
+ await rmdir(lock.path).catch((error) => {
865
+ if (!["ENOENT", "ENOTEMPTY"].includes(getErrorCode(error) ?? "")) throw error;
866
+ });
867
+ }
868
+ /** Attach a waiting native process before granting it permission to exec. */
869
+ async function attachLockProcess(lock, pid) {
870
+ const ownerProcessStartedAt = readProcessStartIdentity(pid);
871
+ if (!ownerProcessStartedAt?.startsWith("ps:")) throw new Error("Cannot establish native command process identity.");
872
+ const parent = await open(resolveOwnerEntryPath(lock.path, lock.ownerId), "r");
873
+ try {
874
+ const meta = parseOpenMeldLockMeta(await parent.readFile("utf8"));
875
+ if (meta?.ownerId !== lock.ownerId || meta.pid !== process$1.pid || meta.ownerProcessStartedAt !== CURRENT_PROCESS_START_IDENTITY) throw new Error("Native command does not own the lifecycle lock.");
876
+ const participant = {
877
+ path: lock.path,
878
+ ownerId: randomUUID()
879
+ };
880
+ const contents = `${JSON.stringify({
881
+ ownerId: participant.ownerId,
882
+ parentOwnerId: lock.ownerId,
883
+ pid,
884
+ ownerProcessStartedAt,
885
+ at: (/* @__PURE__ */ new Date()).toISOString()
886
+ })}\n`;
887
+ await writeFile(resolveOwnerEntryPath(lock.path, participant.ownerId), contents, {
888
+ encoding: "utf8",
889
+ flag: "wx",
890
+ mode: 384
891
+ });
892
+ const snapshot = await readLockSnapshot(lock.path);
893
+ if (readProcessStartIdentity(pid) !== ownerProcessStartedAt || !(snapshot.ownerEntryNames ?? [snapshot.ownerEntryName]).includes(`${encodeURIComponent(participant.ownerId)}.owner.json`)) throw new Error("Native command lifecycle attachment could not be verified.");
894
+ return participant;
895
+ } finally {
896
+ await parent.close();
897
+ }
865
898
  }
866
899
  function releaseLockSync(lock) {
867
900
  try {
@@ -1048,10 +1081,26 @@ async function readLockSnapshot(path, remainingRaceRetries = 2) {
1048
1081
  await handle.close();
1049
1082
  }
1050
1083
  }
1051
- async function readDirectoryLockSnapshot(path, pathStats) {
1084
+ async function readDirectoryLockSnapshot(path, pathStats, selectedEntry) {
1052
1085
  const ownerEntries = (await readdir(path, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".owner.json")).map((entry) => entry.name).sort();
1053
- const ownerEntryName = ownerEntries.length === 1 ? ownerEntries[0] : null;
1086
+ const ownerEntryName = selectedEntry ?? (ownerEntries.length === 1 ? ownerEntries[0] : null);
1054
1087
  const directoryIdentity = `${pathStats.dev}:${pathStats.ino}:${pathStats.mtimeMs}`;
1088
+ if (!selectedEntry && ownerEntries.length > 1) {
1089
+ const snapshots = await Promise.all(ownerEntries.map((entry) => readDirectoryLockSnapshot(path, pathStats, entry)));
1090
+ const recognized = snapshots.every((snapshot) => typeof snapshot.meta?.ownerId === "string" && snapshot.ownerEntryName === `${encodeURIComponent(snapshot.meta.ownerId)}.owner.json` && typeof snapshot.meta.ownerProcessStartedAt === "string" && snapshot.meta.ownerProcessStartedAt.startsWith("ps:") && snapshot.pid !== null);
1091
+ return {
1092
+ exists: true,
1093
+ fileIdentity: snapshots.map((snapshot) => snapshot.fileIdentity).join("|"),
1094
+ ownerEntryName: null,
1095
+ ownerEntryNames: recognized ? ownerEntries : void 0,
1096
+ modifiedAtMs: Number(pathStats.mtimeMs),
1097
+ metaRaw: null,
1098
+ meta: null,
1099
+ pid: recognized ? snapshots[0]?.pid ?? null : null,
1100
+ hasStaleOwner: recognized && snapshots.every((snapshot) => snapshot.hasStaleOwner),
1101
+ storageKind: "directory"
1102
+ };
1103
+ }
1055
1104
  if (!ownerEntryName) return {
1056
1105
  exists: true,
1057
1106
  fileIdentity: `${directoryIdentity}:empty-or-malformed`,
@@ -1105,8 +1154,8 @@ function resolveLockContentionState(snapshot) {
1105
1154
  return "unknown";
1106
1155
  }
1107
1156
  async function cleanupStaleDirectoryLock(path, snapshot) {
1108
- if (snapshot.ownerEntryName) try {
1109
- await unlink(join(path, snapshot.ownerEntryName));
1157
+ for (const entry of snapshot.ownerEntryNames ?? (snapshot.ownerEntryName ? [snapshot.ownerEntryName] : [])) try {
1158
+ await unlink(join(path, entry));
1110
1159
  } catch (error) {
1111
1160
  if (getErrorCode(error) === "ENOENT") return false;
1112
1161
  throw error;
@@ -1209,6 +1258,6 @@ function toErrorMessage(error) {
1209
1258
  return error instanceof Error ? error.message : String(error);
1210
1259
  }
1211
1260
  //#endregion
1212
- export { openMeldManagedVersionBinaryPath as $, formatLocalMachineIssueMessage as A, deviceOpenClawProfileWorkspaceDir as B, LocalMachineFailureError as C, createServiceSpawnPendingIssue as D, createOrphanedSetupConcurrencyIssue as E, accountProfileWorkspacePath as F, isPublishedOpenMeldHome as G, deviceSkillsCustomTargetsPath as H, accountsDir as I, normalizeAccountKey as J, legacyAccountProfileSpacesDir as K, deviceAgentRuntimePath as L, accountProfileLocalMetaPath as M, accountProfileSpaceCacheDir as N, isLocalMachineFailureError as O, accountProfileViewPath as P, openMeldManagedBinaryPath as Q, deviceOpenClawProfileBootstrapPath as R, isProcessIdentityAlive as S, createActiveSetupConcurrencyIssue as T, deviceSkillsInstallsPath as U, devicePreferencesPath as V, deviceSkillsStorePath as W, openMeldBackupsDir as X, normalizeOpenMeldProfileId as Y, openMeldBinDir as Z, resolveCliContextId as _, systemDir as _t, readLockMeta as a, profileViewPath as at, resolveOpenMeldLaneDescriptor as b, repairOrphanedLegacyLocks as c, resolveOpenMeldCliEntryNameFromArgv as ct, tryCleanupStaleLock as d, resolveOpenMeldServiceOwnedPathInput as dt, openMeldManagedVersionDir as et, LEGACY_OPENMELD_AGENT_SESSION_ENV_KEY as f, resolveOpenMeldServiceScope as ft, resolveCliContext as g, spacesDir as gt, readCliContextState as h, skillsDir as ht, isOpenMeldOrphanedLockError as i, profileDir as it, OPENMELD_HOME_ENV_KEY as j, toRecognizedLocalMachineFailureError as k, resolveOpenMeldOrphanedLockIssue as l, resolveOpenMeldEnvPreset as lt, listCliContextStates as m, runtimeLogsDir as mt, buildOpenMeldOrphanedLockAction as n, openMeldVersionsDir as nt, releaseLock as o, resolveDefaultOpenMeldHomeDirname as ot, OPENMELD_CLI_CONTEXT_ENV_KEY as p, runtimeDir as pt, legacyRuntimeConfigPath as q, isOpenMeldLockError as r, organizationSkillReleaseDir as rt, releaseLockSync as s, resolveExplicitOpenMeldEnvPreset as st, acquireLock as t, openMeldRootDir as tt, runWithHeldLock as u, resolveOpenMeldRootDir as ut, writeCliContextState as v, assessLocalMachineFailure as w, CURRENT_PROCESS_START_IDENTITY as x, formatLaneScopeSentence as y, deviceOpenClawProfileDir as z };
1261
+ export { openMeldBinDir as $, isLocalMachineFailureError as A, deviceOpenClawProfileBootstrapPath as B, isProcessIdentityAlive as C, createActiveSetupConcurrencyIssue as D, assessLocalMachineFailure as E, accountProfileSpaceCacheDir as F, deviceSkillsInstallsPath as G, deviceOpenClawProfileWorkspaceDir as H, accountProfileViewPath as I, legacyAccountProfileSpacesDir as J, deviceSkillsStorePath as K, accountProfileWorkspacePath as L, formatLocalMachineIssueMessage as M, OPENMELD_HOME_ENV_KEY as N, createOrphanedSetupConcurrencyIssue as O, accountProfileLocalMetaPath as P, openMeldBackupsDir as Q, accountsDir as R, CURRENT_PROCESS_START_IDENTITY as S, LocalMachineFailureError as T, devicePreferencesPath as U, deviceOpenClawProfileDir as V, deviceSkillsCustomTargetsPath as W, normalizeAccountKey as X, legacyRuntimeConfigPath as Y, normalizeOpenMeldProfileId as Z, resolveCliContext as _, skillsDir as _t, isOpenMeldOrphanedLockError as a, organizationSkillReleaseDir as at, formatLaneScopeSentence as b, releaseLockSync as c, resolveDefaultOpenMeldHomeDirname as ct, runWithHeldLock as d, resolveOpenMeldEnvPreset as dt, openMeldManagedBinaryPath as et, tryCleanupStaleLock as f, resolveOpenMeldRootDir as ft, readCliContextState as g, runtimeLogsDir as gt, listCliContextStates as h, runtimeDir as ht, isOpenMeldLockError as i, openMeldVersionsDir as it, toRecognizedLocalMachineFailureError as j, createServiceSpawnPendingIssue as k, repairOrphanedLegacyLocks as l, resolveExplicitOpenMeldEnvPreset as lt, OPENMELD_CLI_CONTEXT_ENV_KEY as m, resolveOpenMeldServiceScope as mt, attachLockProcess as n, openMeldManagedVersionDir as nt, readLockMeta as o, profileDir as ot, LEGACY_OPENMELD_AGENT_SESSION_ENV_KEY as p, resolveOpenMeldServiceOwnedPathInput as pt, isPublishedOpenMeldHome as q, buildOpenMeldOrphanedLockAction as r, openMeldRootDir as rt, releaseLock as s, profileViewPath as st, acquireLock as t, openMeldManagedVersionBinaryPath as tt, resolveOpenMeldOrphanedLockIssue as u, resolveOpenMeldCliEntryNameFromArgv as ut, resolveCliContextId as v, spacesDir as vt, readProcessStartIdentity as w, resolveOpenMeldLaneDescriptor as x, writeCliContextState as y, systemDir as yt, deviceAgentRuntimePath as z };
1213
1262
 
1214
- //# sourceMappingURL=lock-CvBnBcFK.js.map
1263
+ //# sourceMappingURL=lock-Dxp6o_t_.js.map