@mulmoclaude/core 1.13.0 → 1.14.1

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 (156) hide show
  1. package/assets/helps/error-recovery.md +12 -1
  2. package/dist/atomic-C_7YpMiM.cjs.map +1 -1
  3. package/dist/atomic-DPpdrJzO.js.map +1 -1
  4. package/dist/{calendarGrid-CrGxeCOG.js → calendarGrid-Csy2rpjp.js} +65 -36
  5. package/dist/{calendarGrid-CrGxeCOG.js.map → calendarGrid-Csy2rpjp.js.map} +1 -1
  6. package/dist/{calendarGrid-CaS9er8i.cjs → calendarGrid-p8K-7cuB.cjs} +65 -36
  7. package/dist/{calendarGrid-CaS9er8i.cjs.map → calendarGrid-p8K-7cuB.cjs.map} +1 -1
  8. package/dist/collection/core/actionVisible.d.ts +3 -3
  9. package/dist/collection/core/completion.d.ts +5 -5
  10. package/dist/collection/core/schemaZ.d.ts +4 -4
  11. package/dist/collection/index.cjs +7 -10
  12. package/dist/collection/index.cjs.map +1 -1
  13. package/dist/collection/index.js +7 -10
  14. package/dist/collection/index.js.map +1 -1
  15. package/dist/collection/registry/registryIndex.d.ts +1 -1
  16. package/dist/collection/registry/server/index.cjs +15 -13
  17. package/dist/collection/registry/server/index.cjs.map +1 -1
  18. package/dist/collection/registry/server/index.js +15 -13
  19. package/dist/collection/registry/server/index.js.map +1 -1
  20. package/dist/collection/server/csvQuery.d.ts +7 -2
  21. package/dist/collection/server/csvStore.d.ts +2 -1
  22. package/dist/collection/server/discovery.d.ts +2 -2
  23. package/dist/collection/server/index.cjs +3 -3
  24. package/dist/collection/server/index.js +3 -3
  25. package/dist/collection/server/io.d.ts +3 -3
  26. package/dist/collection/server/manageTool.d.ts +3 -3
  27. package/dist/collection/server/store.d.ts +3 -3
  28. package/dist/collection/server/validate.d.ts +1 -1
  29. package/dist/collection-watchers/index.cjs +10 -25
  30. package/dist/collection-watchers/index.cjs.map +1 -1
  31. package/dist/collection-watchers/index.js +10 -25
  32. package/dist/collection-watchers/index.js.map +1 -1
  33. package/dist/{discovery-D-ZJ6a6z.js → discovery-BSedPW8A.js} +64 -36
  34. package/dist/discovery-BSedPW8A.js.map +1 -0
  35. package/dist/{discovery-DAoMnBYM.cjs → discovery-DSLgRQhN.cjs} +64 -36
  36. package/dist/discovery-DSLgRQhN.cjs.map +1 -0
  37. package/dist/{dist-21pMsI1a.cjs → dist-CsgSfWwR.cjs} +22 -1
  38. package/dist/{dist-21pMsI1a.cjs.map → dist-CsgSfWwR.cjs.map} +1 -1
  39. package/dist/{dist-DP1FTGnO.js → dist-D8zokgGo.js} +11 -2
  40. package/dist/{dist-DP1FTGnO.js.map → dist-D8zokgGo.js.map} +1 -1
  41. package/dist/feeds/index.cjs +2 -2
  42. package/dist/feeds/index.js +2 -2
  43. package/dist/feeds/server/host.d.ts +2 -2
  44. package/dist/feeds/server/index.cjs +35 -29
  45. package/dist/feeds/server/index.cjs.map +1 -1
  46. package/dist/feeds/server/index.js +35 -29
  47. package/dist/feeds/server/index.js.map +1 -1
  48. package/dist/feeds/server/refreshResult.d.ts +2 -2
  49. package/dist/files/index.cjs +3 -2
  50. package/dist/files/index.cjs.map +1 -1
  51. package/dist/files/index.js +3 -2
  52. package/dist/files/index.js.map +1 -1
  53. package/dist/google/calendar.d.ts +47 -33
  54. package/dist/google/collectionPush.d.ts +13 -8
  55. package/dist/google/collectionSync.d.ts +2 -2
  56. package/dist/google/index.cjs +63 -38
  57. package/dist/google/index.cjs.map +1 -1
  58. package/dist/google/index.d.ts +2 -2
  59. package/dist/google/index.js +61 -38
  60. package/dist/google/index.js.map +1 -1
  61. package/dist/{graph-DjE1Az1C.cjs → graph-BZJxiv1E.cjs} +10 -12
  62. package/dist/graph-BZJxiv1E.cjs.map +1 -0
  63. package/dist/{graph-BcwqiSpR.js → graph-Ce7xsDTt.js} +10 -12
  64. package/dist/graph-Ce7xsDTt.js.map +1 -0
  65. package/dist/{ingestTypes-D1GQdG8e.cjs → ingestTypes-CPR-h-OZ.cjs} +2 -2
  66. package/dist/{ingestTypes-D1GQdG8e.cjs.map → ingestTypes-CPR-h-OZ.cjs.map} +1 -1
  67. package/dist/{ingestTypes-XReG-li7.js → ingestTypes-F2IJhOLJ.js} +2 -2
  68. package/dist/{ingestTypes-XReG-li7.js.map → ingestTypes-F2IJhOLJ.js.map} +1 -1
  69. package/dist/notifier/index.cjs +1 -1
  70. package/dist/notifier/index.js +1 -1
  71. package/dist/notifier/types.d.ts +4 -4
  72. package/dist/{notifier-C3IhYxqh.cjs → notifier-CKFVVwDP.cjs} +36 -25
  73. package/dist/notifier-CKFVVwDP.cjs.map +1 -0
  74. package/dist/{notifier-CMFlw74b.js → notifier-CQD8NljP.js} +36 -25
  75. package/dist/notifier-CQD8NljP.js.map +1 -0
  76. package/dist/plugin-vue/index.cjs +4 -2
  77. package/dist/plugin-vue/index.cjs.map +1 -1
  78. package/dist/plugin-vue/index.js +4 -2
  79. package/dist/plugin-vue/index.js.map +1 -1
  80. package/dist/{project-B9NSyr6L.js → project-B0j_Vf_Q.js} +7 -2
  81. package/dist/project-B0j_Vf_Q.js.map +1 -0
  82. package/dist/{project-CCtT_fQr.cjs → project-C1ep9pvo.cjs} +7 -2
  83. package/dist/project-C1ep9pvo.cjs.map +1 -0
  84. package/dist/{promptSafety-FD8cQn3e.cjs → promptSafety-DUZ5BiW5.cjs} +106 -88
  85. package/dist/promptSafety-DUZ5BiW5.cjs.map +1 -0
  86. package/dist/{promptSafety-C--op_6a.js → promptSafety-DgHMF4Pz.js} +106 -88
  87. package/dist/promptSafety-DgHMF4Pz.js.map +1 -0
  88. package/dist/remote-host/index.cjs +2 -1
  89. package/dist/remote-host/index.d.ts +10 -0
  90. package/dist/remote-host/index.js +2 -2
  91. package/dist/remote-host/server/hostRunner.d.ts +7 -2
  92. package/dist/remote-host/server/index.cjs +14 -11
  93. package/dist/remote-host/server/index.cjs.map +1 -1
  94. package/dist/remote-host/server/index.js +13 -10
  95. package/dist/remote-host/server/index.js.map +1 -1
  96. package/dist/{remote-host-DkDVxNim.cjs → remote-host-CtQjagPt.cjs} +53 -1
  97. package/dist/remote-host-CtQjagPt.cjs.map +1 -0
  98. package/dist/remote-host-Dba4lF3Z.js +82 -0
  99. package/dist/remote-host-Dba4lF3Z.js.map +1 -0
  100. package/dist/remote-view/index.cjs +6 -4
  101. package/dist/remote-view/index.cjs.map +1 -1
  102. package/dist/remote-view/index.d.ts +1 -1
  103. package/dist/remote-view/index.js +6 -4
  104. package/dist/remote-view/index.js.map +1 -1
  105. package/dist/scheduler/adapter.d.ts +4 -4
  106. package/dist/scheduler/index.cjs +35 -3
  107. package/dist/scheduler/index.cjs.map +1 -1
  108. package/dist/scheduler/index.js +35 -3
  109. package/dist/scheduler/index.js.map +1 -1
  110. package/dist/scheduler/task-manager.d.ts +2 -2
  111. package/dist/{server-B_b0bLSW.cjs → server-1c6gB372.cjs} +54 -31
  112. package/dist/server-1c6gB372.cjs.map +1 -0
  113. package/dist/{server-Ci_A3chZ.js → server-Dv_L7l0y.js} +54 -31
  114. package/dist/server-Dv_L7l0y.js.map +1 -0
  115. package/dist/skill-bridge/index.cjs +3 -4
  116. package/dist/skill-bridge/index.cjs.map +1 -1
  117. package/dist/skill-bridge/index.js +3 -4
  118. package/dist/skill-bridge/index.js.map +1 -1
  119. package/dist/types-BKVZrtyc.js.map +1 -1
  120. package/dist/types-CNqkLT4M.cjs.map +1 -1
  121. package/dist/utils/fetch.cjs.map +1 -1
  122. package/dist/utils/fetch.d.ts +1 -1
  123. package/dist/utils/fetch.js.map +1 -1
  124. package/dist/utils/index.cjs +1 -1
  125. package/dist/utils/index.js +1 -1
  126. package/dist/whisper/client.cjs.map +1 -1
  127. package/dist/whisper/client.d.ts +3 -3
  128. package/dist/whisper/client.js.map +1 -1
  129. package/dist/whisper/index.cjs +2 -6
  130. package/dist/whisper/index.cjs.map +1 -1
  131. package/dist/whisper/index.js +2 -6
  132. package/dist/whisper/index.js.map +1 -1
  133. package/dist/wiki/index.cjs +4 -4
  134. package/dist/wiki/index.cjs.map +1 -1
  135. package/dist/wiki/index.js +4 -4
  136. package/dist/wiki/index.js.map +1 -1
  137. package/dist/wiki/server/index.cjs +15 -12
  138. package/dist/wiki/server/index.cjs.map +1 -1
  139. package/dist/wiki/server/index.js +15 -12
  140. package/dist/wiki/server/index.js.map +1 -1
  141. package/package.json +6 -6
  142. package/dist/discovery-D-ZJ6a6z.js.map +0 -1
  143. package/dist/discovery-DAoMnBYM.cjs.map +0 -1
  144. package/dist/graph-BcwqiSpR.js.map +0 -1
  145. package/dist/graph-DjE1Az1C.cjs.map +0 -1
  146. package/dist/notifier-C3IhYxqh.cjs.map +0 -1
  147. package/dist/notifier-CMFlw74b.js.map +0 -1
  148. package/dist/project-B9NSyr6L.js.map +0 -1
  149. package/dist/project-CCtT_fQr.cjs.map +0 -1
  150. package/dist/promptSafety-C--op_6a.js.map +0 -1
  151. package/dist/promptSafety-FD8cQn3e.cjs.map +0 -1
  152. package/dist/remote-host-D_BRFHcI.js +0 -36
  153. package/dist/remote-host-D_BRFHcI.js.map +0 -1
  154. package/dist/remote-host-DkDVxNim.cjs.map +0 -1
  155. package/dist/server-B_b0bLSW.cjs.map +0 -1
  156. package/dist/server-Ci_A3chZ.js.map +0 -1
@@ -3,6 +3,15 @@
3
3
  function isRecord(value) {
4
4
  return typeof value === "object" && value !== null && !Array.isArray(value);
5
5
  }
6
+ /** Narrow `unknown` to any object (not null, arrays allowed).
7
+ * Use `isRecord` when you need to access string keys. */
8
+ function isObj(value) {
9
+ return typeof value === "object" && value !== null;
10
+ }
11
+ /** String array (every element is a string). */
12
+ function isStringArray(value) {
13
+ return Array.isArray(value) && value.every((val) => typeof val === "string");
14
+ }
6
15
  /** An array of unknowns. Prefer this over a bare `Array.isArray` in typed code:
7
16
  * `Array.isArray(x: unknown)` narrows to `any[]`, silently reintroducing
8
17
  * `any`, whereas this keeps the element type `unknown`. */
@@ -89,12 +98,24 @@ Object.defineProperty(exports, "isErrorWithCode", {
89
98
  return isErrorWithCode;
90
99
  }
91
100
  });
101
+ Object.defineProperty(exports, "isObj", {
102
+ enumerable: true,
103
+ get: function() {
104
+ return isObj;
105
+ }
106
+ });
92
107
  Object.defineProperty(exports, "isRecord", {
93
108
  enumerable: true,
94
109
  get: function() {
95
110
  return isRecord;
96
111
  }
97
112
  });
113
+ Object.defineProperty(exports, "isStringArray", {
114
+ enumerable: true,
115
+ get: function() {
116
+ return isStringArray;
117
+ }
118
+ });
98
119
  Object.defineProperty(exports, "isUnknownArray", {
99
120
  enumerable: true,
100
121
  get: function() {
@@ -102,4 +123,4 @@ Object.defineProperty(exports, "isUnknownArray", {
102
123
  }
103
124
  });
104
125
 
105
- //# sourceMappingURL=dist-21pMsI1a.cjs.map
126
+ //# sourceMappingURL=dist-CsgSfWwR.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dist-21pMsI1a.cjs","names":[],"sources":["../../common/dist/index.js"],"sourcesContent":["// General-purpose runtime type guards, shared across the MulmoClaude host,\n// bridges, and plugins. This is a leaf package — pure and dependency-free — so\n// any tier can import it without creating an uphill edge.\n//\n// These originated as `server/utils/types.ts` (#504), which centralised 40+\n// hand-written inline `typeof x === \"object\"` checks. They are promoted here so\n// the same guards stop being re-hand-written in every bridge and plugin too.\n/** Narrow `unknown` to a plain object (not null, not array). */\nexport function isRecord(value) {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n/** Narrow `unknown` to any object (not null, arrays allowed).\n * Use `isRecord` when you need to access string keys. */\nexport function isObj(value) {\n return typeof value === \"object\" && value !== null;\n}\n/** Non-empty string after trimming whitespace. */\nexport function isNonEmptyString(value) {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n/** Record whose values are all strings. */\nexport function isStringRecord(value) {\n if (!isRecord(value))\n return false;\n return Object.values(value).every((val) => typeof val === \"string\");\n}\n/** String array (every element is a string). */\nexport function isStringArray(value) {\n return Array.isArray(value) && value.every((val) => typeof val === \"string\");\n}\n/** An array of unknowns. Prefer this over a bare `Array.isArray` in typed code:\n * `Array.isArray(x: unknown)` narrows to `any[]`, silently reintroducing\n * `any`, whereas this keeps the element type `unknown`. */\nexport function isUnknownArray(value) {\n return Array.isArray(value);\n}\n/** Error-like object with a `code` property (e.g. Node.js fs errors). */\nexport function isErrorWithCode(value) {\n return isRecord(value) && typeof value.code === \"string\";\n}\n/** Check that a record has a specific key with a string value. */\nexport function hasStringProp(value, key) {\n return isRecord(value) && typeof value[key] === \"string\";\n}\n/** Check that a record has a specific key with a number value. */\nexport function hasNumberProp(value, key) {\n return isRecord(value) && typeof value[key] === \"number\";\n}\n/** Split a comma-separated env value into trimmed, non-empty entries.\n * `lowercase` folds case for identifiers compared case-insensitively\n * (JIDs, email addresses, hex pubkeys). Absent/empty input → empty list. */\nexport function parseCsvList(raw, opts) {\n return (raw ?? \"\")\n .split(\",\")\n .map((entry) => (opts?.lowercase ? entry.trim().toLowerCase() : entry.trim()))\n .filter(Boolean);\n}\n/** A comma-separated env value as a Set — the canonical allowlist shape,\n * where an empty set is the \"allow all\" sentinel (`set.size === 0`). */\nexport function parseCsvSet(raw, opts) {\n return new Set(parseCsvList(raw, opts));\n}\n/** Normalise an unknown thrown value into a human-readable string. Isomorphic\n * (host, bridges, plugins, Vue) — this is the single home for the helper that\n * #2217 could only consolidate for server code, since `@mulmoclaude/core/utils`\n * is server-only.\n *\n * A non-Error object with a non-empty string `details` (gRPC convention) or\n * `message` field surfaces that field — `details` wins — instead of the\n * `[object Object]` a bare `String(err)` would print; an empty-string field\n * falls through. `fallback` covers the error-boundary idiom where a thrown\n * non-Error should read as a descriptive message rather than `String(err)`\n * noise; omit it in logging contexts where `String(err)` is fine. */\nexport function errorMessage(err, fallback) {\n if (err instanceof Error)\n return err.message;\n if (hasStringProp(err, \"details\") && err.details)\n return err.details;\n if (hasStringProp(err, \"message\") && err.message)\n return err.message;\n if (fallback !== undefined)\n return fallback;\n return String(err);\n}\n/** `Date` → `YYYY-MM-DD` in UTC — for dates that must not shift with the\n * host's local timezone (tool-trace search dirs, API date keys). Isomorphic\n * single source (#2480): the host re-exports it from `server/utils/date.ts`,\n * x-plugin imports it directly. The `@receptron/task-scheduler` copy stays\n * local on purpose — that leaf package is published independently and kept\n * dependency-free. Wall-clock questions use the host's `toLocalIsoDate`. */\nexport function toUtcIsoDate(timestamp) {\n const year = timestamp.getUTCFullYear();\n const month = String(timestamp.getUTCMonth() + 1).padStart(2, \"0\");\n const day = String(timestamp.getUTCDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n// A Map, not an object literal: `{}[char]` reads through the prototype chain,\n// so a future caller widening the regex would silently get `[object Object]`\n// for keys like `constructor`.\nconst HTML_ESCAPES = new Map([\n [\"&\", \"&amp;\"],\n [\"<\", \"&lt;\"],\n [\">\", \"&gt;\"],\n ['\"', \"&quot;\"],\n [\"'\", \"&#39;\"],\n]);\n/** HTML-escape text destined for markup or an attribute value — the fixed\n * five-character map, nothing more. Lives here rather than in\n * `@mulmoclaude/core/wiki` (#2483) because `@mulmoclaude/markdown-utils` is a\n * leaf that core depends on and so cannot import back up; core/wiki\n * re-exports this, keeping its consumers' import path unchanged.\n *\n * Escaping `&` first is what makes a single pass safe — the entities this\n * introduces contain none of the other four characters, so nothing is\n * double-escaped. Not a sanitiser: it neither strips tags nor validates URLs. */\nexport function escapeHtml(value) {\n return value.replace(/[&<>\"']/g, (char) => HTML_ESCAPES.get(char) ?? char);\n}\nexport { scanEnvOptions, snakeToLowerCamel } from \"./envScan.js\";\n"],"mappings":";;AAQA,SAAgB,SAAS,OAAO;CAC5B,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC9E;;;;AAuBA,SAAgB,eAAe,OAAO;CAClC,OAAO,MAAM,QAAQ,KAAK;AAC9B;;AAEA,SAAgB,gBAAgB,OAAO;CACnC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;AAEA,SAAgB,cAAc,OAAO,KAAK;CACtC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;AAEA,SAAgB,cAAc,OAAO,KAAK;CACtC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;;;;;;;;;;;AA0BA,SAAgB,aAAa,KAAK,UAAU;CACxC,IAAI,eAAe,OACf,OAAO,IAAI;CACf,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,SACrC,OAAO,IAAI;CACf,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,SACrC,OAAO,IAAI;CACf,IAAI,aAAa,KAAA,GACb,OAAO;CACX,OAAO,OAAO,GAAG;AACrB;AAgBA,IAAM,+BAAe,IAAI,IAAI;CACzB,CAAC,KAAK,OAAO;CACb,CAAC,KAAK,MAAM;CACZ,CAAC,KAAK,MAAM;CACZ,CAAC,MAAK,QAAQ;CACd,CAAC,KAAK,OAAO;AACjB,CAAC;;;;;;;;;;AAUD,SAAgB,WAAW,OAAO;CAC9B,OAAO,MAAM,QAAQ,aAAa,SAAS,aAAa,IAAI,IAAI,KAAK,IAAI;AAC7E"}
1
+ {"version":3,"file":"dist-CsgSfWwR.cjs","names":[],"sources":["../../common/dist/index.js"],"sourcesContent":["// General-purpose runtime type guards, shared across the MulmoClaude host,\n// bridges, and plugins. This is a leaf package — pure and dependency-free — so\n// any tier can import it without creating an uphill edge.\n//\n// These originated as `server/utils/types.ts` (#504), which centralised 40+\n// hand-written inline `typeof x === \"object\"` checks. They are promoted here so\n// the same guards stop being re-hand-written in every bridge and plugin too.\n/** Narrow `unknown` to a plain object (not null, not array). */\nexport function isRecord(value) {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n/** Narrow `unknown` to any object (not null, arrays allowed).\n * Use `isRecord` when you need to access string keys. */\nexport function isObj(value) {\n return typeof value === \"object\" && value !== null;\n}\n/** Non-empty string after trimming whitespace. */\nexport function isNonEmptyString(value) {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n/** Record whose values are all strings. */\nexport function isStringRecord(value) {\n if (!isRecord(value))\n return false;\n return Object.values(value).every((val) => typeof val === \"string\");\n}\n/** String array (every element is a string). */\nexport function isStringArray(value) {\n return Array.isArray(value) && value.every((val) => typeof val === \"string\");\n}\n/** An array of unknowns. Prefer this over a bare `Array.isArray` in typed code:\n * `Array.isArray(x: unknown)` narrows to `any[]`, silently reintroducing\n * `any`, whereas this keeps the element type `unknown`. */\nexport function isUnknownArray(value) {\n return Array.isArray(value);\n}\n/** Error-like object with a `code` property (e.g. Node.js fs errors). */\nexport function isErrorWithCode(value) {\n return isRecord(value) && typeof value.code === \"string\";\n}\n/** Check that a record has a specific key with a string value. */\nexport function hasStringProp(value, key) {\n return isRecord(value) && typeof value[key] === \"string\";\n}\n/** Check that a record has a specific key with a number value. */\nexport function hasNumberProp(value, key) {\n return isRecord(value) && typeof value[key] === \"number\";\n}\n/** Split a comma-separated env value into trimmed, non-empty entries.\n * `lowercase` folds case for identifiers compared case-insensitively\n * (JIDs, email addresses, hex pubkeys). Absent/empty input → empty list. */\nexport function parseCsvList(raw, opts) {\n return (raw ?? \"\")\n .split(\",\")\n .map((entry) => (opts?.lowercase ? entry.trim().toLowerCase() : entry.trim()))\n .filter(Boolean);\n}\n/** A comma-separated env value as a Set — the canonical allowlist shape,\n * where an empty set is the \"allow all\" sentinel (`set.size === 0`). */\nexport function parseCsvSet(raw, opts) {\n return new Set(parseCsvList(raw, opts));\n}\n/** Normalise an unknown thrown value into a human-readable string. Isomorphic\n * (host, bridges, plugins, Vue) — this is the single home for the helper that\n * #2217 could only consolidate for server code, since `@mulmoclaude/core/utils`\n * is server-only.\n *\n * A non-Error object with a non-empty string `details` (gRPC convention) or\n * `message` field surfaces that field — `details` wins — instead of the\n * `[object Object]` a bare `String(err)` would print; an empty-string field\n * falls through. `fallback` covers the error-boundary idiom where a thrown\n * non-Error should read as a descriptive message rather than `String(err)`\n * noise; omit it in logging contexts where `String(err)` is fine. */\nexport function errorMessage(err, fallback) {\n if (err instanceof Error)\n return err.message;\n if (hasStringProp(err, \"details\") && err.details)\n return err.details;\n if (hasStringProp(err, \"message\") && err.message)\n return err.message;\n if (fallback !== undefined)\n return fallback;\n return String(err);\n}\n/** `Date` → `YYYY-MM-DD` in UTC — for dates that must not shift with the\n * host's local timezone (tool-trace search dirs, API date keys). Isomorphic\n * single source (#2480): the host re-exports it from `server/utils/date.ts`,\n * x-plugin imports it directly. The `@receptron/task-scheduler` copy stays\n * local on purpose — that leaf package is published independently and kept\n * dependency-free. Wall-clock questions use the host's `toLocalIsoDate`. */\nexport function toUtcIsoDate(timestamp) {\n const year = timestamp.getUTCFullYear();\n const month = String(timestamp.getUTCMonth() + 1).padStart(2, \"0\");\n const day = String(timestamp.getUTCDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n// A Map, not an object literal: `{}[char]` reads through the prototype chain,\n// so a future caller widening the regex would silently get `[object Object]`\n// for keys like `constructor`.\nconst HTML_ESCAPES = new Map([\n [\"&\", \"&amp;\"],\n [\"<\", \"&lt;\"],\n [\">\", \"&gt;\"],\n ['\"', \"&quot;\"],\n [\"'\", \"&#39;\"],\n]);\n/** HTML-escape text destined for markup or an attribute value — the fixed\n * five-character map, nothing more. Lives here rather than in\n * `@mulmoclaude/core/wiki` (#2483) because `@mulmoclaude/markdown-utils` is a\n * leaf that core depends on and so cannot import back up; core/wiki\n * re-exports this, keeping its consumers' import path unchanged.\n *\n * Escaping `&` first is what makes a single pass safe — the entities this\n * introduces contain none of the other four characters, so nothing is\n * double-escaped. Not a sanitiser: it neither strips tags nor validates URLs. */\nexport function escapeHtml(value) {\n return value.replace(/[&<>\"']/g, (char) => HTML_ESCAPES.get(char) ?? char);\n}\nexport { scanEnvOptions, snakeToLowerCamel } from \"./envScan.js\";\n"],"mappings":";;AAQA,SAAgB,SAAS,OAAO;CAC5B,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC9E;;;AAGA,SAAgB,MAAM,OAAO;CACzB,OAAO,OAAO,UAAU,YAAY,UAAU;AAClD;;AAYA,SAAgB,cAAc,OAAO;CACjC,OAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,OAAO,QAAQ,OAAO,QAAQ,QAAQ;AAC/E;;;;AAIA,SAAgB,eAAe,OAAO;CAClC,OAAO,MAAM,QAAQ,KAAK;AAC9B;;AAEA,SAAgB,gBAAgB,OAAO;CACnC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;AAEA,SAAgB,cAAc,OAAO,KAAK;CACtC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;AAEA,SAAgB,cAAc,OAAO,KAAK;CACtC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;;;;;;;;;;;AA0BA,SAAgB,aAAa,KAAK,UAAU;CACxC,IAAI,eAAe,OACf,OAAO,IAAI;CACf,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,SACrC,OAAO,IAAI;CACf,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,SACrC,OAAO,IAAI;CACf,IAAI,aAAa,KAAA,GACb,OAAO;CACX,OAAO,OAAO,GAAG;AACrB;AAgBA,IAAM,+BAAe,IAAI,IAAI;CACzB,CAAC,KAAK,OAAO;CACb,CAAC,KAAK,MAAM;CACZ,CAAC,KAAK,MAAM;CACZ,CAAC,MAAK,QAAQ;CACd,CAAC,KAAK,OAAO;AACjB,CAAC;;;;;;;;;;AAUD,SAAgB,WAAW,OAAO;CAC9B,OAAO,MAAM,QAAQ,aAAa,SAAS,aAAa,IAAI,IAAI,KAAK,IAAI;AAC7E"}
@@ -3,6 +3,15 @@
3
3
  function isRecord(value) {
4
4
  return typeof value === "object" && value !== null && !Array.isArray(value);
5
5
  }
6
+ /** Narrow `unknown` to any object (not null, arrays allowed).
7
+ * Use `isRecord` when you need to access string keys. */
8
+ function isObj(value) {
9
+ return typeof value === "object" && value !== null;
10
+ }
11
+ /** String array (every element is a string). */
12
+ function isStringArray(value) {
13
+ return Array.isArray(value) && value.every((val) => typeof val === "string");
14
+ }
6
15
  /** An array of unknowns. Prefer this over a bare `Array.isArray` in typed code:
7
16
  * `Array.isArray(x: unknown)` narrows to `any[]`, silently reintroducing
8
17
  * `any`, whereas this keeps the element type `unknown`. */
@@ -59,6 +68,6 @@ function escapeHtml(value) {
59
68
  return value.replace(/[&<>"']/g, (char) => HTML_ESCAPES.get(char) ?? char);
60
69
  }
61
70
  //#endregion
62
- export { isErrorWithCode as a, hasStringProp as i, escapeHtml as n, isRecord as o, hasNumberProp as r, isUnknownArray as s, errorMessage as t };
71
+ export { isErrorWithCode as a, isStringArray as c, hasStringProp as i, isUnknownArray as l, escapeHtml as n, isObj as o, hasNumberProp as r, isRecord as s, errorMessage as t };
63
72
 
64
- //# sourceMappingURL=dist-DP1FTGnO.js.map
73
+ //# sourceMappingURL=dist-D8zokgGo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dist-DP1FTGnO.js","names":[],"sources":["../../common/dist/index.js"],"sourcesContent":["// General-purpose runtime type guards, shared across the MulmoClaude host,\n// bridges, and plugins. This is a leaf package — pure and dependency-free — so\n// any tier can import it without creating an uphill edge.\n//\n// These originated as `server/utils/types.ts` (#504), which centralised 40+\n// hand-written inline `typeof x === \"object\"` checks. They are promoted here so\n// the same guards stop being re-hand-written in every bridge and plugin too.\n/** Narrow `unknown` to a plain object (not null, not array). */\nexport function isRecord(value) {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n/** Narrow `unknown` to any object (not null, arrays allowed).\n * Use `isRecord` when you need to access string keys. */\nexport function isObj(value) {\n return typeof value === \"object\" && value !== null;\n}\n/** Non-empty string after trimming whitespace. */\nexport function isNonEmptyString(value) {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n/** Record whose values are all strings. */\nexport function isStringRecord(value) {\n if (!isRecord(value))\n return false;\n return Object.values(value).every((val) => typeof val === \"string\");\n}\n/** String array (every element is a string). */\nexport function isStringArray(value) {\n return Array.isArray(value) && value.every((val) => typeof val === \"string\");\n}\n/** An array of unknowns. Prefer this over a bare `Array.isArray` in typed code:\n * `Array.isArray(x: unknown)` narrows to `any[]`, silently reintroducing\n * `any`, whereas this keeps the element type `unknown`. */\nexport function isUnknownArray(value) {\n return Array.isArray(value);\n}\n/** Error-like object with a `code` property (e.g. Node.js fs errors). */\nexport function isErrorWithCode(value) {\n return isRecord(value) && typeof value.code === \"string\";\n}\n/** Check that a record has a specific key with a string value. */\nexport function hasStringProp(value, key) {\n return isRecord(value) && typeof value[key] === \"string\";\n}\n/** Check that a record has a specific key with a number value. */\nexport function hasNumberProp(value, key) {\n return isRecord(value) && typeof value[key] === \"number\";\n}\n/** Split a comma-separated env value into trimmed, non-empty entries.\n * `lowercase` folds case for identifiers compared case-insensitively\n * (JIDs, email addresses, hex pubkeys). Absent/empty input → empty list. */\nexport function parseCsvList(raw, opts) {\n return (raw ?? \"\")\n .split(\",\")\n .map((entry) => (opts?.lowercase ? entry.trim().toLowerCase() : entry.trim()))\n .filter(Boolean);\n}\n/** A comma-separated env value as a Set — the canonical allowlist shape,\n * where an empty set is the \"allow all\" sentinel (`set.size === 0`). */\nexport function parseCsvSet(raw, opts) {\n return new Set(parseCsvList(raw, opts));\n}\n/** Normalise an unknown thrown value into a human-readable string. Isomorphic\n * (host, bridges, plugins, Vue) — this is the single home for the helper that\n * #2217 could only consolidate for server code, since `@mulmoclaude/core/utils`\n * is server-only.\n *\n * A non-Error object with a non-empty string `details` (gRPC convention) or\n * `message` field surfaces that field — `details` wins — instead of the\n * `[object Object]` a bare `String(err)` would print; an empty-string field\n * falls through. `fallback` covers the error-boundary idiom where a thrown\n * non-Error should read as a descriptive message rather than `String(err)`\n * noise; omit it in logging contexts where `String(err)` is fine. */\nexport function errorMessage(err, fallback) {\n if (err instanceof Error)\n return err.message;\n if (hasStringProp(err, \"details\") && err.details)\n return err.details;\n if (hasStringProp(err, \"message\") && err.message)\n return err.message;\n if (fallback !== undefined)\n return fallback;\n return String(err);\n}\n/** `Date` → `YYYY-MM-DD` in UTC — for dates that must not shift with the\n * host's local timezone (tool-trace search dirs, API date keys). Isomorphic\n * single source (#2480): the host re-exports it from `server/utils/date.ts`,\n * x-plugin imports it directly. The `@receptron/task-scheduler` copy stays\n * local on purpose — that leaf package is published independently and kept\n * dependency-free. Wall-clock questions use the host's `toLocalIsoDate`. */\nexport function toUtcIsoDate(timestamp) {\n const year = timestamp.getUTCFullYear();\n const month = String(timestamp.getUTCMonth() + 1).padStart(2, \"0\");\n const day = String(timestamp.getUTCDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n// A Map, not an object literal: `{}[char]` reads through the prototype chain,\n// so a future caller widening the regex would silently get `[object Object]`\n// for keys like `constructor`.\nconst HTML_ESCAPES = new Map([\n [\"&\", \"&amp;\"],\n [\"<\", \"&lt;\"],\n [\">\", \"&gt;\"],\n ['\"', \"&quot;\"],\n [\"'\", \"&#39;\"],\n]);\n/** HTML-escape text destined for markup or an attribute value — the fixed\n * five-character map, nothing more. Lives here rather than in\n * `@mulmoclaude/core/wiki` (#2483) because `@mulmoclaude/markdown-utils` is a\n * leaf that core depends on and so cannot import back up; core/wiki\n * re-exports this, keeping its consumers' import path unchanged.\n *\n * Escaping `&` first is what makes a single pass safe — the entities this\n * introduces contain none of the other four characters, so nothing is\n * double-escaped. Not a sanitiser: it neither strips tags nor validates URLs. */\nexport function escapeHtml(value) {\n return value.replace(/[&<>\"']/g, (char) => HTML_ESCAPES.get(char) ?? char);\n}\nexport { scanEnvOptions, snakeToLowerCamel } from \"./envScan.js\";\n"],"mappings":";;AAQA,SAAgB,SAAS,OAAO;CAC5B,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC9E;;;;AAuBA,SAAgB,eAAe,OAAO;CAClC,OAAO,MAAM,QAAQ,KAAK;AAC9B;;AAEA,SAAgB,gBAAgB,OAAO;CACnC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;AAEA,SAAgB,cAAc,OAAO,KAAK;CACtC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;AAEA,SAAgB,cAAc,OAAO,KAAK;CACtC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;;;;;;;;;;;AA0BA,SAAgB,aAAa,KAAK,UAAU;CACxC,IAAI,eAAe,OACf,OAAO,IAAI;CACf,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,SACrC,OAAO,IAAI;CACf,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,SACrC,OAAO,IAAI;CACf,IAAI,aAAa,KAAA,GACb,OAAO;CACX,OAAO,OAAO,GAAG;AACrB;AAgBA,IAAM,+BAAe,IAAI,IAAI;CACzB,CAAC,KAAK,OAAO;CACb,CAAC,KAAK,MAAM;CACZ,CAAC,KAAK,MAAM;CACZ,CAAC,MAAK,QAAQ;CACd,CAAC,KAAK,OAAO;AACjB,CAAC;;;;;;;;;;AAUD,SAAgB,WAAW,OAAO;CAC9B,OAAO,MAAM,QAAQ,aAAa,SAAS,aAAa,IAAI,IAAI,KAAK,IAAI;AAC7E"}
1
+ {"version":3,"file":"dist-D8zokgGo.js","names":[],"sources":["../../common/dist/index.js"],"sourcesContent":["// General-purpose runtime type guards, shared across the MulmoClaude host,\n// bridges, and plugins. This is a leaf package — pure and dependency-free — so\n// any tier can import it without creating an uphill edge.\n//\n// These originated as `server/utils/types.ts` (#504), which centralised 40+\n// hand-written inline `typeof x === \"object\"` checks. They are promoted here so\n// the same guards stop being re-hand-written in every bridge and plugin too.\n/** Narrow `unknown` to a plain object (not null, not array). */\nexport function isRecord(value) {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n/** Narrow `unknown` to any object (not null, arrays allowed).\n * Use `isRecord` when you need to access string keys. */\nexport function isObj(value) {\n return typeof value === \"object\" && value !== null;\n}\n/** Non-empty string after trimming whitespace. */\nexport function isNonEmptyString(value) {\n return typeof value === \"string\" && value.trim().length > 0;\n}\n/** Record whose values are all strings. */\nexport function isStringRecord(value) {\n if (!isRecord(value))\n return false;\n return Object.values(value).every((val) => typeof val === \"string\");\n}\n/** String array (every element is a string). */\nexport function isStringArray(value) {\n return Array.isArray(value) && value.every((val) => typeof val === \"string\");\n}\n/** An array of unknowns. Prefer this over a bare `Array.isArray` in typed code:\n * `Array.isArray(x: unknown)` narrows to `any[]`, silently reintroducing\n * `any`, whereas this keeps the element type `unknown`. */\nexport function isUnknownArray(value) {\n return Array.isArray(value);\n}\n/** Error-like object with a `code` property (e.g. Node.js fs errors). */\nexport function isErrorWithCode(value) {\n return isRecord(value) && typeof value.code === \"string\";\n}\n/** Check that a record has a specific key with a string value. */\nexport function hasStringProp(value, key) {\n return isRecord(value) && typeof value[key] === \"string\";\n}\n/** Check that a record has a specific key with a number value. */\nexport function hasNumberProp(value, key) {\n return isRecord(value) && typeof value[key] === \"number\";\n}\n/** Split a comma-separated env value into trimmed, non-empty entries.\n * `lowercase` folds case for identifiers compared case-insensitively\n * (JIDs, email addresses, hex pubkeys). Absent/empty input → empty list. */\nexport function parseCsvList(raw, opts) {\n return (raw ?? \"\")\n .split(\",\")\n .map((entry) => (opts?.lowercase ? entry.trim().toLowerCase() : entry.trim()))\n .filter(Boolean);\n}\n/** A comma-separated env value as a Set — the canonical allowlist shape,\n * where an empty set is the \"allow all\" sentinel (`set.size === 0`). */\nexport function parseCsvSet(raw, opts) {\n return new Set(parseCsvList(raw, opts));\n}\n/** Normalise an unknown thrown value into a human-readable string. Isomorphic\n * (host, bridges, plugins, Vue) — this is the single home for the helper that\n * #2217 could only consolidate for server code, since `@mulmoclaude/core/utils`\n * is server-only.\n *\n * A non-Error object with a non-empty string `details` (gRPC convention) or\n * `message` field surfaces that field — `details` wins — instead of the\n * `[object Object]` a bare `String(err)` would print; an empty-string field\n * falls through. `fallback` covers the error-boundary idiom where a thrown\n * non-Error should read as a descriptive message rather than `String(err)`\n * noise; omit it in logging contexts where `String(err)` is fine. */\nexport function errorMessage(err, fallback) {\n if (err instanceof Error)\n return err.message;\n if (hasStringProp(err, \"details\") && err.details)\n return err.details;\n if (hasStringProp(err, \"message\") && err.message)\n return err.message;\n if (fallback !== undefined)\n return fallback;\n return String(err);\n}\n/** `Date` → `YYYY-MM-DD` in UTC — for dates that must not shift with the\n * host's local timezone (tool-trace search dirs, API date keys). Isomorphic\n * single source (#2480): the host re-exports it from `server/utils/date.ts`,\n * x-plugin imports it directly. The `@receptron/task-scheduler` copy stays\n * local on purpose — that leaf package is published independently and kept\n * dependency-free. Wall-clock questions use the host's `toLocalIsoDate`. */\nexport function toUtcIsoDate(timestamp) {\n const year = timestamp.getUTCFullYear();\n const month = String(timestamp.getUTCMonth() + 1).padStart(2, \"0\");\n const day = String(timestamp.getUTCDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n// A Map, not an object literal: `{}[char]` reads through the prototype chain,\n// so a future caller widening the regex would silently get `[object Object]`\n// for keys like `constructor`.\nconst HTML_ESCAPES = new Map([\n [\"&\", \"&amp;\"],\n [\"<\", \"&lt;\"],\n [\">\", \"&gt;\"],\n ['\"', \"&quot;\"],\n [\"'\", \"&#39;\"],\n]);\n/** HTML-escape text destined for markup or an attribute value — the fixed\n * five-character map, nothing more. Lives here rather than in\n * `@mulmoclaude/core/wiki` (#2483) because `@mulmoclaude/markdown-utils` is a\n * leaf that core depends on and so cannot import back up; core/wiki\n * re-exports this, keeping its consumers' import path unchanged.\n *\n * Escaping `&` first is what makes a single pass safe — the entities this\n * introduces contain none of the other four characters, so nothing is\n * double-escaped. Not a sanitiser: it neither strips tags nor validates URLs. */\nexport function escapeHtml(value) {\n return value.replace(/[&<>\"']/g, (char) => HTML_ESCAPES.get(char) ?? char);\n}\nexport { scanEnvOptions, snakeToLowerCamel } from \"./envScan.js\";\n"],"mappings":";;AAQA,SAAgB,SAAS,OAAO;CAC5B,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC9E;;;AAGA,SAAgB,MAAM,OAAO;CACzB,OAAO,OAAO,UAAU,YAAY,UAAU;AAClD;;AAYA,SAAgB,cAAc,OAAO;CACjC,OAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,OAAO,QAAQ,OAAO,QAAQ,QAAQ;AAC/E;;;;AAIA,SAAgB,eAAe,OAAO;CAClC,OAAO,MAAM,QAAQ,KAAK;AAC9B;;AAEA,SAAgB,gBAAgB,OAAO;CACnC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;AAEA,SAAgB,cAAc,OAAO,KAAK;CACtC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;AAEA,SAAgB,cAAc,OAAO,KAAK;CACtC,OAAO,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS;AACpD;;;;;;;;;;;;AA0BA,SAAgB,aAAa,KAAK,UAAU;CACxC,IAAI,eAAe,OACf,OAAO,IAAI;CACf,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,SACrC,OAAO,IAAI;CACf,IAAI,cAAc,KAAK,SAAS,KAAK,IAAI,SACrC,OAAO,IAAI;CACf,IAAI,aAAa,KAAA,GACb,OAAO;CACX,OAAO,OAAO,GAAG;AACrB;AAgBA,IAAM,+BAAe,IAAI,IAAI;CACzB,CAAC,KAAK,OAAO;CACb,CAAC,KAAK,MAAM;CACZ,CAAC,KAAK,MAAM;CACZ,CAAC,MAAK,QAAQ;CACd,CAAC,KAAK,OAAO;AACjB,CAAC;;;;;;;;;;AAUD,SAAgB,WAAW,OAAO;CAC9B,OAAO,MAAM,QAAQ,aAAa,SAAS,aAAa,IAAI,IAAI,KAAK,IAAI;AAC7E"}
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_calendarGrid = require("../calendarGrid-CaS9er8i.cjs");
3
- const require_ingestTypes = require("../ingestTypes-D1GQdG8e.cjs");
2
+ const require_calendarGrid = require("../calendarGrid-p8K-7cuB.cjs");
3
+ const require_ingestTypes = require("../ingestTypes-CPR-h-OZ.cjs");
4
4
  exports.AGENT_INGEST_KIND = require_ingestTypes.AGENT_INGEST_KIND;
5
5
  exports.DEFAULT_FEED_MAX_ITEMS = require_ingestTypes.DEFAULT_FEED_MAX_ITEMS;
6
6
  exports.FEED_SCHEDULES = require_calendarGrid.FEED_SCHEDULES;
@@ -1,3 +1,3 @@
1
- import { C as FEED_SCHEDULES, w as INGEST_KINDS } from "../calendarGrid-CrGxeCOG.js";
2
- import { n as DEFAULT_FEED_MAX_ITEMS, r as isFeedSchedule, t as AGENT_INGEST_KIND } from "../ingestTypes-XReG-li7.js";
1
+ import { C as FEED_SCHEDULES, w as INGEST_KINDS } from "../calendarGrid-Csy2rpjp.js";
2
+ import { n as DEFAULT_FEED_MAX_ITEMS, r as isFeedSchedule, t as AGENT_INGEST_KIND } from "../ingestTypes-F2IJhOLJ.js";
3
3
  export { AGENT_INGEST_KIND, DEFAULT_FEED_MAX_ITEMS, FEED_SCHEDULES, INGEST_KINDS, isFeedSchedule };
@@ -20,9 +20,9 @@ export type AgentWorkerRunner = (args: {
20
20
  message: string;
21
21
  roleId: string;
22
22
  hidden: boolean;
23
- onComplete?: (outcome: {
23
+ onComplete?: ((outcome: {
24
24
  didError: boolean;
25
- }) => void | Promise<void>;
25
+ }) => void | Promise<void>) | undefined;
26
26
  }) => Promise<AgentWorkerResult>;
27
27
  /** Public alias of the shared `StructuredLogger` — same shape as `CollectionLogger`. */
28
28
  export type FeedsLogger = StructuredLogger;
@@ -1,12 +1,13 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_rolldown_runtime = require("../../rolldown-runtime-D6vf50IK.cjs");
3
- const require_calendarGrid = require("../../calendarGrid-CaS9er8i.cjs");
4
- const require_project = require("../../project-CCtT_fQr.cjs");
5
- const require_discovery = require("../../discovery-DAoMnBYM.cjs");
6
- const require_server = require("../../server-B_b0bLSW.cjs");
3
+ const require_dist = require("../../dist-CsgSfWwR.cjs");
4
+ const require_calendarGrid = require("../../calendarGrid-p8K-7cuB.cjs");
5
+ const require_project = require("../../project-C1ep9pvo.cjs");
6
+ const require_discovery = require("../../discovery-DSLgRQhN.cjs");
7
+ const require_server = require("../../server-1c6gB372.cjs");
7
8
  const require_feeds_paths = require("../paths.cjs");
8
- const require_ingestTypes = require("../../ingestTypes-D1GQdG8e.cjs");
9
- const require_notifier = require("../../notifier-C3IhYxqh.cjs");
9
+ const require_ingestTypes = require("../../ingestTypes-CPR-h-OZ.cjs");
10
+ const require_notifier = require("../../notifier-CKFVVwDP.cjs");
10
11
  let node_path = require("node:path");
11
12
  node_path = require_rolldown_runtime.__toESM(node_path, 1);
12
13
  let node_crypto = require("node:crypto");
@@ -145,10 +146,10 @@ function stripIpv6Brackets(hostname) {
145
146
  * `[::ffff:127.0.0.1]` as `::ffff:7f00:1`, so matching only the dotted form
146
147
  * would wave the mapped loopback through any URL-sourced check. */
147
148
  function mappedIpv4Value(lower) {
148
- const dotted = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(lower);
149
- if (dotted) return ipv4ToInt(dotted[1]);
150
- const hex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(lower);
151
- if (hex) return Number.parseInt(hex[1], 16) * 65536 + Number.parseInt(hex[2], 16);
149
+ const dotted = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(lower)?.[1];
150
+ if (dotted !== void 0) return ipv4ToInt(dotted);
151
+ const [, high, low] = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(lower) ?? [];
152
+ if (high !== void 0 && low !== void 0) return Number.parseInt(high, 16) * 65536 + Number.parseInt(low, 16);
152
153
  return null;
153
154
  }
154
155
  /** Blocks loopback/unspecified, fc00::/7 unique-local, fe80::/10 link-local,
@@ -159,7 +160,7 @@ function isBlockedIpv6(address) {
159
160
  if (lower === "::1" || lower === "::") return true;
160
161
  const mapped = mappedIpv4Value(lower);
161
162
  if (mapped !== null) return isBlockedIpv4Value(mapped);
162
- const [head] = lower.split(":");
163
+ const [head = ""] = lower.split(":");
163
164
  if (head.length === 0) return false;
164
165
  const leading = Number.parseInt(head, 16);
165
166
  if (Number.isNaN(leading)) return false;
@@ -374,7 +375,7 @@ function parseSegment(segment, tokens) {
374
375
  });
375
376
  if (bracketStart === -1) return;
376
377
  for (const match of segment.slice(bracketStart).matchAll(BRACKET_RE)) {
377
- const [, inner] = match;
378
+ const [, inner = ""] = match;
378
379
  if (inner.length > 0) tokens.push({
379
380
  kind: "index",
380
381
  index: Number(inner)
@@ -389,11 +390,10 @@ function tokenize(path) {
389
390
  function step(current, token) {
390
391
  if (current === null || current === void 0) return void 0;
391
392
  if (token.kind === "key") {
392
- if (typeof current !== "object" || Array.isArray(current)) return void 0;
393
- const record = current;
394
- return Object.hasOwn(record, token.key) ? record[token.key] : void 0;
393
+ if (!require_dist.isRecord(current)) return void 0;
394
+ return Object.hasOwn(current, token.key) ? current[token.key] : void 0;
395
395
  }
396
- return Array.isArray(current) ? current[token.index] : void 0;
396
+ return require_dist.isUnknownArray(current) ? current[token.index] : void 0;
397
397
  }
398
398
  /** Resolve a dot/bracket path against `root`, or `undefined` on any miss. */
399
399
  function getByPath(root, path) {
@@ -422,10 +422,9 @@ function asKeyString(value) {
422
422
  * shape — so a tag like `<guid isPermaLink="false">id</guid>` maps to
423
423
  * its text without the caller needing to write `.#text`. */
424
424
  function unwrapTextNode(value) {
425
- if (value && typeof value === "object" && !Array.isArray(value)) {
426
- const obj = value;
427
- if (typeof obj["#text"] === "string") return obj["#text"];
428
- if (typeof obj["#cdata"] === "string") return obj["#cdata"];
425
+ if (require_dist.isRecord(value)) {
426
+ if (typeof value["#text"] === "string") return value["#text"];
427
+ if (typeof value["#cdata"] === "string") return value["#cdata"];
429
428
  }
430
429
  return value;
431
430
  }
@@ -512,9 +511,16 @@ function defaultFeedState(slug) {
512
511
  consecutiveFailures: 0
513
512
  };
514
513
  }
514
+ /** The stored cursor, keeping only the string entries its type promises. A
515
+ * hand-edited state file can hold anything; a non-string entry is unreadable
516
+ * to every retriever, so carrying it forward would only re-persist junk. */
517
+ function readCursor(value) {
518
+ if (!require_dist.isRecord(value)) return {};
519
+ return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"));
520
+ }
515
521
  function normalizeState(slug, parsed) {
516
522
  const base = defaultFeedState(slug);
517
- const cursor = parsed.cursor && typeof parsed.cursor === "object" ? parsed.cursor : base.cursor;
523
+ const cursor = parsed.cursor === void 0 ? base.cursor : readCursor(parsed.cursor);
518
524
  return {
519
525
  slug,
520
526
  lastFetchedAt: typeof parsed.lastFetchedAt === "string" ? parsed.lastFetchedAt : base.lastFetchedAt,
@@ -529,9 +535,10 @@ async function readFeedState(workspaceRoot, target) {
529
535
  const { slug } = target;
530
536
  try {
531
537
  const raw = await (0, node_fs_promises.readFile)(stateFilePath(target, workspaceRoot), "utf-8");
532
- return normalizeState(slug, JSON.parse(raw));
538
+ const parsed = JSON.parse(raw);
539
+ return normalizeState(slug, require_dist.isRecord(parsed) ? parsed : {});
533
540
  } catch (err) {
534
- if (err.code !== "ENOENT") log.warn("feeds", "failed to read feed state, using default", {
541
+ if (!require_dist.isErrorWithCode(err) || err.code !== "ENOENT") log.warn("feeds", "failed to read feed state, using default", {
535
542
  slug,
536
543
  error: String(err)
537
544
  });
@@ -576,8 +583,8 @@ function result(slug, patch) {
576
583
  async function refreshViaAgent(workspaceRoot, collection, opts) {
577
584
  const hidden = opts?.hidden ?? true;
578
585
  const { slug } = collection;
579
- const ingest = collection.schema.ingest;
580
- if (!ingest || ingest.kind !== "agent") return result(slug, { errors: ["collection has no agent ingest config"] });
586
+ const { ingest } = collection.schema;
587
+ if (ingest?.kind !== "agent") return result(slug, { errors: ["collection has no agent ingest config"] });
581
588
  const workerRunner = workerRunnerOrNull();
582
589
  if (!workerRunner) return result(slug, { errors: ["agent ingest worker runner not configured"] });
583
590
  const template = await require_server.readSkillTemplate(collection.skillDir, ingest.template);
@@ -681,10 +688,9 @@ async function onWorkerSuccess(state, collection) {
681
688
  //#region src/feeds/server/engine.ts
682
689
  var ONE_HOUR_MS = 36e5;
683
690
  var ONE_DAY_MS = 864e5;
684
- /** Feed schemas carry the rich `IngestSpec` (validated at discovery —
685
- * `source === "feed"` requires `ingest`), but the canonical
686
- * `CollectionSchema.ingest` only promises the minimal `CollectionIngest`.
687
- * Narrow here so the engine can read the retrieval fields type-safely. */
691
+ /** A feed's retrieval config, or undefined. `CollectionSchema.ingest` and the
692
+ * engine's `IngestSpec` are both `IngestZ`'s inferred union, so this is a
693
+ * rename, not a narrowing — the engine keeps its own vocabulary at the seam. */
688
694
  function feedIngest(schema) {
689
695
  return schema.ingest;
690
696
  }