@mulmoclaude/core 2.0.0 → 2.0.2

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 (79) hide show
  1. package/assets/helps/error-recovery.md +32 -0
  2. package/dist/{atomic-C_7YpMiM.cjs → atomic-DhUk8uiM.cjs} +2 -2
  3. package/dist/{atomic-C_7YpMiM.cjs.map → atomic-DhUk8uiM.cjs.map} +1 -1
  4. package/dist/collection/registry/server/index.cjs +21 -26
  5. package/dist/collection/registry/server/index.cjs.map +1 -1
  6. package/dist/collection/registry/server/index.js +18 -23
  7. package/dist/collection/registry/server/index.js.map +1 -1
  8. package/dist/collection/server/index.cjs +2 -2
  9. package/dist/collection/server/index.js +2 -2
  10. package/dist/collection-watchers/index.cjs +3 -3
  11. package/dist/collection-watchers/index.cjs.map +1 -1
  12. package/dist/collection-watchers/index.js +3 -3
  13. package/dist/{discovery-DSLgRQhN.cjs → discovery-B_sHig7n.cjs} +5 -5
  14. package/dist/{discovery-DSLgRQhN.cjs.map → discovery-B_sHig7n.cjs.map} +1 -1
  15. package/dist/{discovery-BSedPW8A.js → discovery-BvnXyUel.js} +3 -3
  16. package/dist/{discovery-BSedPW8A.js.map → discovery-BvnXyUel.js.map} +1 -1
  17. package/dist/dist-CsgSfWwR.cjs.map +1 -1
  18. package/dist/dist-D8zokgGo.js.map +1 -1
  19. package/dist/feeds/paths.cjs +1 -1
  20. package/dist/feeds/server/index.cjs +5 -5
  21. package/dist/feeds/server/index.cjs.map +1 -1
  22. package/dist/feeds/server/index.js +4 -4
  23. package/dist/feeds/server/index.js.map +1 -1
  24. package/dist/file-change/index.cjs +1 -1
  25. package/dist/file-change/index.cjs.map +1 -1
  26. package/dist/files/index.cjs +3 -3
  27. package/dist/files/index.cjs.map +1 -1
  28. package/dist/google/index.cjs +7 -6
  29. package/dist/google/index.cjs.map +1 -1
  30. package/dist/google/index.js +5 -4
  31. package/dist/google/index.js.map +1 -1
  32. package/dist/notifier/index.cjs +1 -1
  33. package/dist/notifier/index.js +1 -1
  34. package/dist/{notifier-CKFVVwDP.cjs → notifier-DZJj0sOh.cjs} +2 -2
  35. package/dist/{notifier-CKFVVwDP.cjs.map → notifier-DZJj0sOh.cjs.map} +1 -1
  36. package/dist/{notifier-CQD8NljP.js → notifier-DhnwR82U.js} +2 -2
  37. package/dist/{notifier-CQD8NljP.js.map → notifier-DhnwR82U.js.map} +1 -1
  38. package/dist/plugin-vue/i18n.cjs.map +1 -1
  39. package/dist/plugin-vue/index.cjs +39 -10
  40. package/dist/plugin-vue/index.cjs.map +1 -1
  41. package/dist/plugin-vue/index.js +39 -10
  42. package/dist/plugin-vue/index.js.map +1 -1
  43. package/dist/{relPath-CgGi4-Nv.cjs → relPath-CTAjGdCL.cjs} +2 -2
  44. package/dist/{relPath-CgGi4-Nv.cjs.map → relPath-CTAjGdCL.cjs.map} +1 -1
  45. package/dist/remote-host/server/index.cjs +3 -2
  46. package/dist/remote-host/server/index.cjs.map +1 -1
  47. package/dist/remote-host/server/index.js +3 -2
  48. package/dist/remote-host/server/index.js.map +1 -1
  49. package/dist/remote-host-CtQjagPt.cjs.map +1 -1
  50. package/dist/{rolldown-runtime-D6vf50IK.cjs → rolldown-runtime-VH7oDXx4.cjs} +1 -1
  51. package/dist/scheduler/index.cjs +6 -4
  52. package/dist/scheduler/index.cjs.map +1 -1
  53. package/dist/scheduler/index.js +5 -3
  54. package/dist/scheduler/index.js.map +1 -1
  55. package/dist/{server-B78f_bnY.js → server-DJt6USBQ.js} +11 -7
  56. package/dist/{server-B78f_bnY.js.map → server-DJt6USBQ.js.map} +1 -1
  57. package/dist/{server-By4oSql2.cjs → server-DoyGZMPS.cjs} +14 -10
  58. package/dist/{server-By4oSql2.cjs.map → server-DoyGZMPS.cjs.map} +1 -1
  59. package/dist/skill-bridge/index.cjs +1 -1
  60. package/dist/skill-bridge/index.cjs.map +1 -1
  61. package/dist/utils/fetch.cjs +1 -1
  62. package/dist/utils/fetch.cjs.map +1 -1
  63. package/dist/utils/fetch.js +1 -1
  64. package/dist/utils/fetch.js.map +1 -1
  65. package/dist/whisper/client.cjs.map +1 -1
  66. package/dist/whisper/client.js.map +1 -1
  67. package/dist/whisper/index.cjs +1 -1
  68. package/dist/whisper/index.cjs.map +1 -1
  69. package/dist/wiki/index.cjs +2 -1
  70. package/dist/wiki/index.cjs.map +1 -1
  71. package/dist/wiki/index.js +2 -1
  72. package/dist/wiki/index.js.map +1 -1
  73. package/dist/wiki/paths.cjs +1 -1
  74. package/dist/wiki/server/index.cjs +5 -3
  75. package/dist/wiki/server/index.cjs.map +1 -1
  76. package/dist/wiki/server/index.js +4 -2
  77. package/dist/wiki/server/index.js.map +1 -1
  78. package/dist/workspace-setup/index.js.map +1 -1
  79. package/package.json +6 -6
@@ -863,3 +863,35 @@ afterwards; the load happens once at boot.
863
863
  Do NOT tell the user to re-check the spelling in `.env`, add the key
864
864
  again, or move it elsewhere; the file is already correct, and it is being
865
865
  read. The conflict is the whole problem.
866
+
867
+ ## A tool your own instructions describe returns "No such tool available"
868
+
869
+ ### Symptoms
870
+
871
+ - The Plugin Instructions section of your system prompt documents a tool
872
+ (`mcp__mulmoclaude__google`, `mcp__mulmoclaude__manageSpotify`, any
873
+ plugin-backed name), but calling it errors with `No such tool available`.
874
+ - `ToolSearch select:<that name>` reports no matching deferred tool either.
875
+ - Static tools in the same session (`presentDocument`, `presentForm`, …) work.
876
+
877
+ ### Cause
878
+
879
+ The tool surface is published by a separate MCP broker process, and plugin-backed
880
+ tools register there a moment after the session's tool list is first taken. A
881
+ session that captured the list too early keeps one that lacks exactly those
882
+ tools — while the system prompt, built in the server where the plugin IS
883
+ registered, still describes them.
884
+
885
+ ### Fix
886
+
887
+ Tell the user plainly that the tool is unavailable in THIS session and that
888
+ starting a new chat re-takes the tool list. Do NOT invent a fallback: reading
889
+ the account's stored credentials, shelling out to a provider CLI, or
890
+ reconstructing the call by hand is worse than the missing tool, and it is not
891
+ what the user asked for.
892
+
893
+ If a new chat has the same gap, the broker did not publish the tool at all.
894
+ Ask the user for the server log around the session start — the broker prints
895
+ `[mcp-server] publishing N tools: …` and, when a promised tool is missing,
896
+ `[mcp-server] advertised but NOT published (check plugin load above): …`. That
897
+ second line, with the plugin-load errors above it, is what a bug report needs.
@@ -1,4 +1,4 @@
1
- const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.cjs");
1
+ const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
2
2
  let node_fs = require("node:fs");
3
3
  let node_path = require("node:path");
4
4
  node_path = require_rolldown_runtime.__toESM(node_path, 1);
@@ -99,4 +99,4 @@ Object.defineProperty(exports, "writeFileAtomicSync", {
99
99
  }
100
100
  });
101
101
 
102
- //# sourceMappingURL=atomic-C_7YpMiM.cjs.map
102
+ //# sourceMappingURL=atomic-DhUk8uiM.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"atomic-C_7YpMiM.cjs","names":[],"sources":["../src/files/atomic.ts"],"sourcesContent":["// rename(2) is atomic on POSIX; Node's Windows fallback (copy+unlink) is still safer than truncating in place.\n// Readers always see either the old file or the new — never a half-written one.\n//\n// Single source of truth for atomic file writes across the whole monorepo\n// (host, core, plugins). Previously copy-pasted four times, so a Windows retry\n// fix landed in only one (#2399, precedent #2222).\n\nimport { mkdirSync, promises, renameSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { randomBytes } from \"node:crypto\";\n\nexport interface WriteAtomicOptions {\n mode?: number;\n /** Give the staging file a random suffix so concurrent writers to the same\n * destination can't collide at the OS layer.\n *\n * Defaults to `true`, and opting out is almost always wrong. A shared\n * `${filePath}.tmp` means two writers of one file race: the second write\n * overwrites the first's staging file, or one rename/unlink pulls it out\n * from under the other, surfacing as `ENOENT … rename '<file>.tmp'`. That is\n * not theoretical — it fired in production on session meta, where ten\n * distinct callers (`setClaudeSessionId`, `backfillOrigin`,\n * `incrementUserQueryCount`, …) all write the same `<sessionId>.json`\n * (#2222).\n *\n * Pass `false` only when you specifically need the staging path to be\n * predictable (e.g. a single-writer token file, or a test that pre-creates\n * it to force a write failure). */\n uniqueTmp?: boolean;\n}\n\n// Unique staging names are the safe default: the cost is a random suffix, the\n// cost of the alternative is a lost update under concurrency (#2222).\nconst DEFAULT_UNIQUE_TMP = true;\n\nfunction tmpPathFor(filePath: string, uniqueTmp: boolean | undefined): string {\n return (uniqueTmp ?? DEFAULT_UNIQUE_TMP) ? `${filePath}.${randomBytes(6).toString(\"hex\")}.tmp` : `${filePath}.tmp`;\n}\n\n// On Windows, AV / Search Indexer / Defender briefly hold handles and rename trips EPERM/EBUSY/EACCES. Retry loop is\n// gated to Windows because POSIX EPERM means a real perm problem (read-only fs, sticky, cross-device) — retrying\n// just adds latency before the inevitable throw.\nconst IS_WINDOWS = process.platform === \"win32\";\nconst RENAME_RETRY_DELAYS_MS = [30, 100, 300] as const;\n\nfunction hasErrnoCode(err: unknown): err is { code: string } {\n return typeof err === \"object\" && err !== null && \"code\" in err && typeof err.code === \"string\";\n}\n\n// `isWindows` is a parameter (defaulting to the real platform) so the safety-critical decision is testable on any OS.\nexport function isTransientRenameError(err: unknown, isWindows: boolean = IS_WINDOWS): boolean {\n if (!isWindows || !hasErrnoCode(err)) return false;\n return err.code === \"EPERM\" || err.code === \"EBUSY\" || err.code === \"EACCES\";\n}\n\n// Injectable so a test can drive the retry path (fail-then-succeed rename, no-op sleep, isWindows=true) on any OS.\nexport interface RenameRetryDeps {\n rename: (fromPath: string, toPath: string) => Promise<void>;\n sleep: (millis: number) => Promise<void>;\n isWindows: boolean;\n}\n\nconst defaultRenameRetryDeps: RenameRetryDeps = {\n rename: (fromPath, toPath) => promises.rename(fromPath, toPath),\n sleep: (millis) => new Promise((resolve) => setTimeout(resolve, millis)),\n isWindows: IS_WINDOWS,\n};\n\nexport async function renameWithWindowsRetry(fromPath: string, toPath: string, deps: RenameRetryDeps = defaultRenameRetryDeps): Promise<void> {\n for (const delayMs of RENAME_RETRY_DELAYS_MS) {\n try {\n await deps.rename(fromPath, toPath);\n return;\n } catch (err) {\n if (!isTransientRenameError(err, deps.isWindows)) throw err;\n await deps.sleep(delayMs);\n }\n }\n // Final attempt — let any error propagate.\n await deps.rename(fromPath, toPath);\n}\n\n// Atomics.wait parks the thread instead of busy-spinning. Only on the Windows-rename retry path, total ≤ ~430ms.\nconst SYNC_SLEEP_BUF = new Int32Array(new SharedArrayBuffer(4));\nfunction sleepSync(millis: number): void {\n Atomics.wait(SYNC_SLEEP_BUF, 0, 0, millis);\n}\n\n// Deliberate async/sync twin of RenameRetryDeps: `sleep` blocks the thread instead of returning a Promise.\nexport interface RenameRetryDepsSync {\n rename: (fromPath: string, toPath: string) => void;\n sleep: (millis: number) => void;\n isWindows: boolean;\n}\n\nconst defaultRenameRetryDepsSync: RenameRetryDepsSync = {\n rename: (fromPath, toPath) => renameSync(fromPath, toPath),\n sleep: sleepSync,\n isWindows: IS_WINDOWS,\n};\n\nexport function renameSyncWithWindowsRetry(fromPath: string, toPath: string, deps: RenameRetryDepsSync = defaultRenameRetryDepsSync): void {\n for (const delayMs of RENAME_RETRY_DELAYS_MS) {\n try {\n deps.rename(fromPath, toPath);\n return;\n } catch (err) {\n if (!isTransientRenameError(err, deps.isWindows)) throw err;\n deps.sleep(delayMs);\n }\n }\n deps.rename(fromPath, toPath);\n}\n\n// Forcing utf-8 on a Uint8Array would re-encode the bytes — wrong for PNGs and other binary blobs.\nfunction writeOptionsFor(content: string | Uint8Array, mode: number | undefined): { encoding?: \"utf-8\" | undefined; mode?: number | undefined } {\n return typeof content === \"string\" ? { encoding: \"utf-8\", mode } : { mode };\n}\n\nexport async function writeFileAtomic(filePath: string, content: string | Uint8Array, opts: WriteAtomicOptions = {}): Promise<void> {\n const tmp = tmpPathFor(filePath, opts.uniqueTmp);\n await promises.mkdir(path.dirname(filePath), { recursive: true });\n try {\n await promises.writeFile(tmp, content, writeOptionsFor(content, opts.mode));\n await renameWithWindowsRetry(tmp, filePath);\n } catch (err) {\n await promises.unlink(tmp).catch(() => {});\n throw err;\n }\n}\n\nexport function writeFileAtomicSync(filePath: string, content: string | Uint8Array, opts: WriteAtomicOptions = {}): void {\n const tmp = tmpPathFor(filePath, opts.uniqueTmp);\n mkdirSync(path.dirname(filePath), { recursive: true });\n try {\n writeFileSync(tmp, content, writeOptionsFor(content, opts.mode));\n renameSyncWithWindowsRetry(tmp, filePath);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // best-effort cleanup\n }\n throw err;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"atomic-DhUk8uiM.cjs","names":[],"sources":["../src/files/atomic.ts"],"sourcesContent":["// rename(2) is atomic on POSIX; Node's Windows fallback (copy+unlink) is still safer than truncating in place.\n// Readers always see either the old file or the new — never a half-written one.\n//\n// Single source of truth for atomic file writes across the whole monorepo\n// (host, core, plugins). Previously copy-pasted four times, so a Windows retry\n// fix landed in only one (#2399, precedent #2222).\n\nimport { mkdirSync, promises, renameSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { randomBytes } from \"node:crypto\";\n\nexport interface WriteAtomicOptions {\n mode?: number;\n /** Give the staging file a random suffix so concurrent writers to the same\n * destination can't collide at the OS layer.\n *\n * Defaults to `true`, and opting out is almost always wrong. A shared\n * `${filePath}.tmp` means two writers of one file race: the second write\n * overwrites the first's staging file, or one rename/unlink pulls it out\n * from under the other, surfacing as `ENOENT … rename '<file>.tmp'`. That is\n * not theoretical — it fired in production on session meta, where ten\n * distinct callers (`setClaudeSessionId`, `backfillOrigin`,\n * `incrementUserQueryCount`, …) all write the same `<sessionId>.json`\n * (#2222).\n *\n * Pass `false` only when you specifically need the staging path to be\n * predictable (e.g. a single-writer token file, or a test that pre-creates\n * it to force a write failure). */\n uniqueTmp?: boolean;\n}\n\n// Unique staging names are the safe default: the cost is a random suffix, the\n// cost of the alternative is a lost update under concurrency (#2222).\nconst DEFAULT_UNIQUE_TMP = true;\n\nfunction tmpPathFor(filePath: string, uniqueTmp: boolean | undefined): string {\n return (uniqueTmp ?? DEFAULT_UNIQUE_TMP) ? `${filePath}.${randomBytes(6).toString(\"hex\")}.tmp` : `${filePath}.tmp`;\n}\n\n// On Windows, AV / Search Indexer / Defender briefly hold handles and rename trips EPERM/EBUSY/EACCES. Retry loop is\n// gated to Windows because POSIX EPERM means a real perm problem (read-only fs, sticky, cross-device) — retrying\n// just adds latency before the inevitable throw.\nconst IS_WINDOWS = process.platform === \"win32\";\nconst RENAME_RETRY_DELAYS_MS = [30, 100, 300] as const;\n\nfunction hasErrnoCode(err: unknown): err is { code: string } {\n return typeof err === \"object\" && err !== null && \"code\" in err && typeof err.code === \"string\";\n}\n\n// `isWindows` is a parameter (defaulting to the real platform) so the safety-critical decision is testable on any OS.\nexport function isTransientRenameError(err: unknown, isWindows: boolean = IS_WINDOWS): boolean {\n if (!isWindows || !hasErrnoCode(err)) return false;\n return err.code === \"EPERM\" || err.code === \"EBUSY\" || err.code === \"EACCES\";\n}\n\n// Injectable so a test can drive the retry path (fail-then-succeed rename, no-op sleep, isWindows=true) on any OS.\nexport interface RenameRetryDeps {\n rename: (fromPath: string, toPath: string) => Promise<void>;\n sleep: (millis: number) => Promise<void>;\n isWindows: boolean;\n}\n\nconst defaultRenameRetryDeps: RenameRetryDeps = {\n rename: (fromPath, toPath) => promises.rename(fromPath, toPath),\n sleep: (millis) => new Promise((resolve) => setTimeout(resolve, millis)),\n isWindows: IS_WINDOWS,\n};\n\nexport async function renameWithWindowsRetry(fromPath: string, toPath: string, deps: RenameRetryDeps = defaultRenameRetryDeps): Promise<void> {\n for (const delayMs of RENAME_RETRY_DELAYS_MS) {\n try {\n await deps.rename(fromPath, toPath);\n return;\n } catch (err) {\n if (!isTransientRenameError(err, deps.isWindows)) throw err;\n await deps.sleep(delayMs);\n }\n }\n // Final attempt — let any error propagate.\n await deps.rename(fromPath, toPath);\n}\n\n// Atomics.wait parks the thread instead of busy-spinning. Only on the Windows-rename retry path, total ≤ ~430ms.\nconst SYNC_SLEEP_BUF = new Int32Array(new SharedArrayBuffer(4));\nfunction sleepSync(millis: number): void {\n Atomics.wait(SYNC_SLEEP_BUF, 0, 0, millis);\n}\n\n// Deliberate async/sync twin of RenameRetryDeps: `sleep` blocks the thread instead of returning a Promise.\nexport interface RenameRetryDepsSync {\n rename: (fromPath: string, toPath: string) => void;\n sleep: (millis: number) => void;\n isWindows: boolean;\n}\n\nconst defaultRenameRetryDepsSync: RenameRetryDepsSync = {\n rename: (fromPath, toPath) => renameSync(fromPath, toPath),\n sleep: sleepSync,\n isWindows: IS_WINDOWS,\n};\n\nexport function renameSyncWithWindowsRetry(fromPath: string, toPath: string, deps: RenameRetryDepsSync = defaultRenameRetryDepsSync): void {\n for (const delayMs of RENAME_RETRY_DELAYS_MS) {\n try {\n deps.rename(fromPath, toPath);\n return;\n } catch (err) {\n if (!isTransientRenameError(err, deps.isWindows)) throw err;\n deps.sleep(delayMs);\n }\n }\n deps.rename(fromPath, toPath);\n}\n\n// Forcing utf-8 on a Uint8Array would re-encode the bytes — wrong for PNGs and other binary blobs.\nfunction writeOptionsFor(content: string | Uint8Array, mode: number | undefined): { encoding?: \"utf-8\" | undefined; mode?: number | undefined } {\n return typeof content === \"string\" ? { encoding: \"utf-8\", mode } : { mode };\n}\n\nexport async function writeFileAtomic(filePath: string, content: string | Uint8Array, opts: WriteAtomicOptions = {}): Promise<void> {\n const tmp = tmpPathFor(filePath, opts.uniqueTmp);\n await promises.mkdir(path.dirname(filePath), { recursive: true });\n try {\n await promises.writeFile(tmp, content, writeOptionsFor(content, opts.mode));\n await renameWithWindowsRetry(tmp, filePath);\n } catch (err) {\n await promises.unlink(tmp).catch(() => {});\n throw err;\n }\n}\n\nexport function writeFileAtomicSync(filePath: string, content: string | Uint8Array, opts: WriteAtomicOptions = {}): void {\n const tmp = tmpPathFor(filePath, opts.uniqueTmp);\n mkdirSync(path.dirname(filePath), { recursive: true });\n try {\n writeFileSync(tmp, content, writeOptionsFor(content, opts.mode));\n renameSyncWithWindowsRetry(tmp, filePath);\n } catch (err) {\n try {\n unlinkSync(tmp);\n } catch {\n // best-effort cleanup\n }\n throw err;\n }\n}\n"],"mappings":"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"}
@@ -1,12 +1,12 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_rolldown_runtime = require("../../../rolldown-runtime-D6vf50IK.cjs");
2
+ const require_rolldown_runtime = require("../../../rolldown-runtime-VH7oDXx4.cjs");
3
3
  const require_dist = require("../../../dist-CsgSfWwR.cjs");
4
- const require_atomic = require("../../../atomic-C_7YpMiM.cjs");
5
- const require_relPath = require("../../../relPath-CgGi4-Nv.cjs");
4
+ const require_atomic = require("../../../atomic-DhUk8uiM.cjs");
5
+ const require_relPath = require("../../../relPath-CTAjGdCL.cjs");
6
6
  const require_utils_fetch = require("../../../utils/fetch.cjs");
7
- const require_discovery = require("../../../discovery-DSLgRQhN.cjs");
7
+ const require_discovery = require("../../../discovery-B_sHig7n.cjs");
8
8
  const require_templatePath = require("../../../templatePath-27vUZowm.cjs");
9
- const require_server = require("../../../server-By4oSql2.cjs");
9
+ const require_server = require("../../../server-DoyGZMPS.cjs");
10
10
  const require_skill_bridge_index = require("../../../skill-bridge/index.cjs");
11
11
  const require_types = require("../../../types-CNqkLT4M.cjs");
12
12
  let node_fs = require("node:fs");
@@ -145,7 +145,8 @@ async function loadFromNetwork(descriptor) {
145
145
  status: STATUS_BAD_GATEWAY$2,
146
146
  error: `registry responded ${res.status}`
147
147
  };
148
- const parsed = require_types.parseRegistryIndex(await res.json().catch(() => null), descriptor.name);
148
+ const json = await res.json().catch(() => null);
149
+ const parsed = require_types.parseRegistryIndex(json, descriptor.name);
149
150
  if (!parsed.ok) {
150
151
  require_discovery.log.warn("collections-registry", "index invalid", {
151
152
  registry: descriptor.name,
@@ -626,7 +627,8 @@ function bridgeAllowlistFiles(bundle) {
626
627
  * mirror files left over from a previous install so we can prune them after
627
628
  * writing the new ones. */
628
629
  async function listFilesRecursive(root, prefix = "") {
629
- const entries = await (0, node_fs_promises.readdir)(prefix ? node_path.default.join(root, ...prefix.split("/")) : root, { withFileTypes: true }).catch(() => []);
630
+ const dir = prefix ? node_path.default.join(root, ...prefix.split("/")) : root;
631
+ const entries = await (0, node_fs_promises.readdir)(dir, { withFileTypes: true }).catch(() => []);
630
632
  const out = [];
631
633
  for (const entry of entries) {
632
634
  const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
@@ -935,35 +937,28 @@ var DOUBLE_QUOTE_ESCAPES = {
935
937
  t: " "
936
938
  };
937
939
  var unescapeDoubleQuote = (next) => DOUBLE_QUOTE_ESCAPES[next] ?? next;
938
- function parseDoubleQuoted(value) {
940
+ function scanQuotedScalar(value, quote, readEscape) {
939
941
  const out = [];
940
942
  for (let i = 1; i < value.length; i += 1) {
941
- const char = value.charAt(i);
942
- if (char === "\\" && i + 1 < value.length) {
943
- out.push(unescapeDoubleQuote(value.charAt(i + 1)));
943
+ const escaped = readEscape(value, i);
944
+ if (escaped !== null) {
945
+ out.push(escaped);
944
946
  i += 1;
945
947
  continue;
946
948
  }
947
- if (char === "\"") return isOnlyTrailingComment(value.slice(i + 1)) ? out.join("") : null;
949
+ const char = value.charAt(i);
950
+ if (char === quote) return isOnlyTrailingComment(value.slice(i + 1)) ? out.join("") : null;
948
951
  out.push(char);
949
952
  }
950
953
  return null;
951
954
  }
955
+ var readDoubleQuoteEscape = (value, index) => value.charAt(index) === "\\" && index + 1 < value.length ? unescapeDoubleQuote(value.charAt(index + 1)) : null;
956
+ var readSingleQuoteEscape = (value, index) => value.charAt(index) === "'" && value[index + 1] === "'" ? "'" : null;
957
+ function parseDoubleQuoted(value) {
958
+ return scanQuotedScalar(value, "\"", readDoubleQuoteEscape);
959
+ }
952
960
  function parseSingleQuoted(value) {
953
- const out = [];
954
- for (let i = 1; i < value.length; i += 1) {
955
- const char = value.charAt(i);
956
- if (char === "'") {
957
- if (value[i + 1] === "'") {
958
- out.push("'");
959
- i += 1;
960
- continue;
961
- }
962
- return isOnlyTrailingComment(value.slice(i + 1)) ? out.join("") : null;
963
- }
964
- out.push(char);
965
- }
966
- return null;
961
+ return scanQuotedScalar(value, "'", readSingleQuoteEscape);
967
962
  }
968
963
  function stripPlainComment(value) {
969
964
  for (let i = 0; i < value.length; i += 1) if (value[i] === "#" && (i === 0 || isYamlSpace(value[i - 1]))) return value.slice(0, i);