@mulmoclaude/core 1.6.0 → 1.7.0

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 (62) hide show
  1. package/assets/helps/google-calendar-collection.md +57 -3
  2. package/assets/helps/google.md +3 -2
  3. package/dist/calendarGrid-CaS9er8i.cjs +576 -0
  4. package/dist/calendarGrid-CaS9er8i.cjs.map +1 -0
  5. package/dist/calendarGrid-CrGxeCOG.js +397 -0
  6. package/dist/calendarGrid-CrGxeCOG.js.map +1 -0
  7. package/dist/collection/index.cjs +44 -44
  8. package/dist/collection/index.cjs.map +1 -1
  9. package/dist/collection/index.js +2 -2
  10. package/dist/collection/registry/server/index.cjs +2 -2
  11. package/dist/collection/registry/server/index.js +2 -2
  12. package/dist/collection/server/index.cjs +4 -4
  13. package/dist/collection/server/index.js +3 -3
  14. package/dist/collection-watchers/index.cjs +5 -5
  15. package/dist/collection-watchers/index.cjs.map +1 -1
  16. package/dist/collection-watchers/index.js +4 -4
  17. package/dist/{discovery--kRUWed0.cjs → discovery-DYcR83qx.cjs} +64 -53
  18. package/dist/discovery-DYcR83qx.cjs.map +1 -0
  19. package/dist/{discovery-CKR4TOX3.js → discovery-_fjsluLx.js} +43 -32
  20. package/dist/discovery-_fjsluLx.js.map +1 -0
  21. package/dist/feeds/index.cjs +4 -4
  22. package/dist/feeds/index.js +2 -2
  23. package/dist/feeds/server/index.cjs +6 -6
  24. package/dist/feeds/server/index.js +4 -4
  25. package/dist/google/apiClient.d.ts +6 -0
  26. package/dist/google/calendar.d.ts +79 -8
  27. package/dist/google/calendarPushState.d.ts +17 -0
  28. package/dist/google/collectionPush.d.ts +64 -0
  29. package/dist/google/collectionSync.d.ts +10 -0
  30. package/dist/google/index.cjs +712 -36
  31. package/dist/google/index.cjs.map +1 -1
  32. package/dist/google/index.d.ts +7 -3
  33. package/dist/google/index.js +683 -37
  34. package/dist/google/index.js.map +1 -1
  35. package/dist/google/pushDateTime.d.ts +10 -0
  36. package/dist/google/pushPlan.d.ts +73 -0
  37. package/dist/{ingestTypes-xX8VpQqh.cjs → ingestTypes-D1GQdG8e.cjs} +3 -3
  38. package/dist/{ingestTypes-xX8VpQqh.cjs.map → ingestTypes-D1GQdG8e.cjs.map} +1 -1
  39. package/dist/{ingestTypes-L59cIGgX.js → ingestTypes-XReG-li7.js} +2 -2
  40. package/dist/{ingestTypes-L59cIGgX.js.map → ingestTypes-XReG-li7.js.map} +1 -1
  41. package/dist/{promptSafety-CQ5Un4wi.js → promptSafety-C--op_6a.js} +3 -269
  42. package/dist/promptSafety-C--op_6a.js.map +1 -0
  43. package/dist/{promptSafety-DfZYNtjK.cjs → promptSafety-FD8cQn3e.cjs} +8 -358
  44. package/dist/promptSafety-FD8cQn3e.cjs.map +1 -0
  45. package/dist/remote-host/index.cjs +8 -0
  46. package/dist/remote-host/index.cjs.map +1 -1
  47. package/dist/remote-host/index.d.ts +21 -0
  48. package/dist/remote-host/index.js +8 -1
  49. package/dist/remote-host/index.js.map +1 -1
  50. package/dist/{server-D_6FLygK.js → server-BlIrtGKl.js} +4 -4
  51. package/dist/{server-D_6FLygK.js.map → server-BlIrtGKl.js.map} +1 -1
  52. package/dist/{server-gEOeV_Nv.cjs → server-l4TZ5Lbf.cjs} +21 -21
  53. package/dist/{server-gEOeV_Nv.cjs.map → server-l4TZ5Lbf.cjs.map} +1 -1
  54. package/package.json +1 -1
  55. package/dist/discovery--kRUWed0.cjs.map +0 -1
  56. package/dist/discovery-CKR4TOX3.js.map +0 -1
  57. package/dist/ids-BnTh3Hl0.cjs +0 -226
  58. package/dist/ids-BnTh3Hl0.cjs.map +0 -1
  59. package/dist/ids-s4GfmE93.js +0 -131
  60. package/dist/ids-s4GfmE93.js.map +0 -1
  61. package/dist/promptSafety-CQ5Un4wi.js.map +0 -1
  62. package/dist/promptSafety-DfZYNtjK.cjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { t as writeFileAtomic } from "./atomic-DPpdrJzO.js";
2
- import { a as isSafeSlug, c as COMPUTED_TYPES, g as fieldTextOrNull, h as fieldText, i as isSafeRecordId, l as FEED_SCHEDULES, m as storageKindFor, n as SAFE_SLUG_PATTERN, p as isReadOnlySchema, s as AGENT_INGEST_KIND, t as SAFE_RECORD_ID_PATTERN, u as INGEST_KINDS } from "./ids-s4GfmE93.js";
2
+ import { A as fieldTextOrNull, C as FEED_SCHEDULES, D as isReadOnlySchema, O as storageKindFor, S as COMPUTED_TYPES, g as SAFE_SLUG_PATTERN, h as SAFE_RECORD_ID_PATTERN, k as fieldText, v as isSafeRecordId, w as INGEST_KINDS, x as AGENT_INGEST_KIND, y as isSafeSlug } from "./calendarGrid-CrGxeCOG.js";
3
3
  import { t as projectRecordFields } from "./project-bU98ycsy.js";
4
4
  import { n as isSafeCustomViewI18nPath, r as isSafeCustomViewPath, t as isSafeActionTemplatePath } from "./templatePath-k_WNbL_Q.js";
5
5
  import { realpathSync, watch } from "node:fs";
@@ -305,6 +305,35 @@ async function readItem(dataDir, itemId, opts = {}) {
305
305
  throw err;
306
306
  }
307
307
  }
308
+ /** The symlink-containment refusal every record path shares: one check, one
309
+ * warn, one answer. Extracted because this is a security RULE applied at
310
+ * three sites (write pre-mkdir, write post-mkdir, delete) — a fix to the
311
+ * check must not be able to land at only one of them.
312
+ *
313
+ * `stage` names the call site so the warn stays as diagnosable as the three
314
+ * hand-written copies were.
315
+ *
316
+ * Scope, stated explicitly because a reviewer asks every time: this catches
317
+ * a symlink that EXISTS when we look — `isContainedInRoot` realpaths the
318
+ * closest existing ancestor, so a pre-planted escape is refused. It does not
319
+ * and cannot close the check-then-use race, where an ancestor is swapped for
320
+ * a symlink between this call and the `mkdir` / `open` / `unlink` that
321
+ * follows. Closing that needs directory-handle I/O anchored at the workspace
322
+ * (`openat` + `O_NOFOLLOW`), which `node:fs` does not expose — it would mean
323
+ * a different I/O layer, not a tighter check here.
324
+ *
325
+ * That race is deliberately outside this app's threat model: the process is
326
+ * loopback-bound and bearer-authed, so anyone able to swap directories inside
327
+ * the workspace is already the workspace owner — the same trust principal the
328
+ * writes belong to. Revisit if collections ever serve a lower-trust caller. */
329
+ function escapesWorkspace(dataDir, workspaceRoot, itemId, stage) {
330
+ if (isContainedInRoot(dataDir, workspaceRoot)) return false;
331
+ log.warn("collections", `${stage} refused: dataDir escapes workspace via symlink`, {
332
+ dataDir,
333
+ itemId
334
+ });
335
+ return true;
336
+ }
308
337
  /** Write a record. Ensures the directory exists, validates the id,
309
338
  * re-checks symlink containment after mkdir, and writes atomically.
310
339
  *
@@ -326,27 +355,15 @@ async function writeItem(dataDir, itemId, item, opts = {}) {
326
355
  itemId
327
356
  };
328
357
  const workspaceRoot = opts.workspaceRoot ?? getWorkspaceRoot();
329
- if (!isContainedInRoot(dataDir, workspaceRoot)) {
330
- log.warn("collections", "writeItem refused: dataDir escapes workspace via symlink (pre-mkdir)", {
331
- dataDir,
332
- itemId: safeId
333
- });
334
- return {
335
- kind: "path-escape",
336
- itemId: safeId
337
- };
338
- }
358
+ if (escapesWorkspace(dataDir, workspaceRoot, safeId, "writeItem (pre-mkdir)")) return {
359
+ kind: "path-escape",
360
+ itemId: safeId
361
+ };
339
362
  await mkdir(dataDir, { recursive: true });
340
- if (!isContainedInRoot(dataDir, workspaceRoot)) {
341
- log.warn("collections", "writeItem refused: dataDir escapes workspace via symlink (post-mkdir)", {
342
- dataDir,
343
- itemId: safeId
344
- });
345
- return {
346
- kind: "path-escape",
347
- itemId: safeId
348
- };
349
- }
363
+ if (escapesWorkspace(dataDir, workspaceRoot, safeId, "writeItem (post-mkdir)")) return {
364
+ kind: "path-escape",
365
+ itemId: safeId
366
+ };
350
367
  const filePath = itemFilePath(dataDir, safeId);
351
368
  const payload = `${JSON.stringify(item, null, 2)}\n`;
352
369
  if (opts.refuseOverwrite) {
@@ -383,16 +400,10 @@ async function deleteItem(dataDir, itemId, opts = {}) {
383
400
  kind: "invalid-id",
384
401
  itemId
385
402
  };
386
- if (!isContainedInRoot(dataDir, opts.workspaceRoot ?? getWorkspaceRoot())) {
387
- log.warn("collections", "deleteItem refused: dataDir escapes workspace via symlink", {
388
- dataDir,
389
- itemId: safeId
390
- });
391
- return {
392
- kind: "path-escape",
393
- itemId: safeId
394
- };
395
- }
403
+ if (escapesWorkspace(dataDir, opts.workspaceRoot ?? getWorkspaceRoot(), safeId, "deleteItem")) return {
404
+ kind: "path-escape",
405
+ itemId: safeId
406
+ };
396
407
  const filePath = itemFilePath(dataDir, safeId);
397
408
  try {
398
409
  await unlink(filePath);
@@ -2655,4 +2666,4 @@ function toDetail(collection) {
2655
2666
  //#endregion
2656
2667
  export { skillsStagingDir as $, deleteItem as A, itemFilePath as B, compileCsvQuery as C, MAX_QUERY_ROWS as D, DEFAULT_QUERY_ROWS as E, resolveCreateItemId as F, archiveDir as G, resolveTemplatePath as H, writeItem as I, getWorkspaceRoot as J, collectionsRegistriesConfigPath as K, SCHEMA_FILE as L, isRegularFile as M, listItems as N, BackendUnavailableError as O, readItem as P, setCollectionChangePublisher as Q, isContainedInRoot as R, queryCsv as S, CollectionQueryZ as T, safeRecordId as U, resolveDataDir as V, safeSlugName as W, log as X, isPresetSlug as Y, publishCollectionChange as Z, csvRowToItem as _, toDetail as a, encodeCsvRecordId as b, resolveMutateSet as c, storeFor as d, createForwardingLogger as et, checkpointSqliteDatabase as f, cacheDir as g, MAX_CSV_ROWS as h, resolvePrimaryField as i, generateItemId as j, isBackendUnavailable as k, collectionWritable as l, projectItemFields as m, discoverCollections as n, toSummary as o, pageFromFullRead as p, configureCollectionHost as q, loadCollection as r, CollectionSchemaZ as s, acceptParsedSchema as t, createHostSlot as tt, readOnlyRefusal as u, decodeCsvRecordId as v, compileJsonlQuery as w, normalizeCsvValue as x, dedupeByRecordId as y, isContainedInWorkspace as z };
2657
2668
 
2658
- //# sourceMappingURL=discovery-CKR4TOX3.js.map
2669
+ //# sourceMappingURL=discovery-_fjsluLx.js.map