mulmoclaude 1.2.0 → 1.4.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 (96) hide show
  1. package/README.md +1 -1
  2. package/client/assets/{PluginScopedRoot-CjiZ2FJI.js → PluginScopedRoot-DYk4nRpW.js} +1 -1
  3. package/client/assets/index-7QnbsZZr.css +2 -0
  4. package/client/assets/{index-yQkLdtMk.js → index-C3SRVT2p.js} +84 -85
  5. package/client/assets/{marp-Bs_qwoKZ.js → marp-DxctLEy1.js} +12 -3
  6. package/client/index.html +3 -3
  7. package/package.json +7 -6
  8. package/server/agent/attachmentConverter.ts +0 -25
  9. package/server/agent/mcp-server.ts +27 -8
  10. package/server/api/auth/viewToken.ts +16 -8
  11. package/server/api/routes/agent.ts +49 -11
  12. package/server/api/routes/collections.ts +274 -102
  13. package/server/api/routes/files.ts +57 -54
  14. package/server/api/routes/mulmo-script.ts +257 -895
  15. package/server/api/routes/wiki/history.ts +17 -19
  16. package/server/build/dispatcher.mjs +2 -2
  17. package/server/events/collection-change.ts +1 -5
  18. package/server/events/file-change.ts +1 -6
  19. package/server/events/pub-sub/index.ts +15 -2
  20. package/server/events/relay-client.ts +6 -1
  21. package/server/events/session-store/index.ts +11 -2
  22. package/server/index.ts +51 -78
  23. package/server/plugins/diagnostics.ts +0 -6
  24. package/server/plugins/mulmoscript-server.ts +58 -0
  25. package/server/prompts/system/system.md +2 -3
  26. package/server/remoteHost/handlers/getCollection.ts +5 -4
  27. package/server/remoteHost/handlers/getFeed.ts +10 -5
  28. package/server/remoteHost/handlers/googleCalendar.ts +50 -3
  29. package/server/remoteHost/handlers/index.ts +3 -1
  30. package/server/services/translation/index.ts +10 -3
  31. package/server/utils/errors.ts +7 -21
  32. package/server/utils/files/html-store.ts +2 -16
  33. package/server/utils/files/journal-io.ts +0 -12
  34. package/server/utils/files/plugins-io.ts +2 -11
  35. package/server/utils/files/safe.ts +39 -0
  36. package/server/utils/httpError.ts +6 -0
  37. package/server/utils/text.ts +7 -23
  38. package/server/utils/time.ts +0 -3
  39. package/server/workspace/collections/index.ts +6 -4
  40. package/server/workspace/collections/remoteView.ts +31 -22
  41. package/server/workspace/collections/watcher.ts +1 -0
  42. package/server/workspace/custom-dirs.ts +16 -6
  43. package/server/workspace/journal/state.ts +1 -9
  44. package/server/workspace/memory/topic-index-hook.ts +0 -9
  45. package/server/workspace/memory/topic-io.ts +0 -4
  46. package/server/workspace/reference-dirs.ts +8 -3
  47. package/server/workspace/skills/external/catalog.ts +24 -13
  48. package/server/workspace/skills/writer.ts +20 -16
  49. package/server/workspace/wiki-pages/snapshot.ts +13 -12
  50. package/src/components/SettingsGoogleTab.vue +4 -1
  51. package/src/components/StackView.vue +12 -1
  52. package/src/composables/collections/uiHost.ts +2 -1
  53. package/src/composables/useChatScroll.ts +18 -6
  54. package/src/composables/useFileDropZone.ts +3 -15
  55. package/src/composables/useFileSelection.ts +4 -1
  56. package/src/composables/useStickToBottom.ts +51 -0
  57. package/src/config/apiRoutes.ts +20 -0
  58. package/src/config/roles.ts +0 -4
  59. package/src/lang/de.ts +0 -30
  60. package/src/lang/en.ts +0 -30
  61. package/src/lang/es.ts +0 -30
  62. package/src/lang/fr.ts +0 -30
  63. package/src/lang/ja.ts +0 -30
  64. package/src/lang/ko.ts +0 -30
  65. package/src/lang/pt-BR.ts +0 -30
  66. package/src/lang/zh.ts +0 -30
  67. package/src/plugins/accounting/index.ts +0 -2
  68. package/src/plugins/api.ts +0 -6
  69. package/src/plugins/canvas/index.ts +0 -2
  70. package/src/plugins/chart/index.ts +0 -2
  71. package/src/plugins/editImages/index.ts +0 -2
  72. package/src/plugins/generateImage/index.ts +0 -2
  73. package/src/plugins/manageSkills/index.ts +0 -2
  74. package/src/plugins/markdown/index.ts +0 -2
  75. package/src/plugins/photoLocations/index.ts +0 -2
  76. package/src/plugins/presentCollection/index.ts +0 -2
  77. package/src/plugins/presentForm/index.ts +0 -2
  78. package/src/plugins/presentHtml/index.ts +0 -2
  79. package/src/plugins/presentMulmoScript/definition.ts +11 -116
  80. package/src/plugins/presentMulmoScript/index.ts +62 -12
  81. package/src/plugins/presentSVG/index.ts +0 -2
  82. package/src/plugins/skill/index.ts +0 -3
  83. package/src/plugins/spreadsheet/engine/parser.ts +0 -103
  84. package/src/plugins/spreadsheet/index.ts +0 -2
  85. package/src/plugins/textResponse/index.ts +0 -3
  86. package/src/plugins/wiki/index.ts +0 -2
  87. package/src/types/notification.ts +0 -10
  88. package/src/utils/api.ts +0 -4
  89. package/src/utils/dom/scrollable.ts +15 -0
  90. package/src/utils/errors.ts +7 -38
  91. package/client/assets/index-D5nJbMO1.css +0 -2
  92. package/server/api/routes/mulmoScriptValidate.ts +0 -101
  93. package/server/utils/mulmoErrorCapture.ts +0 -93
  94. package/src/plugins/presentMulmoScript/Preview.vue +0 -23
  95. package/src/plugins/presentMulmoScript/View.vue +0 -1949
  96. package/src/plugins/presentMulmoScript/helpers.ts +0 -206
@@ -452,6 +452,53 @@ function pipeWithErrorHandling(stream: ReadStream, res: Response<ErrorResponse>)
452
452
  stream.pipe(res);
453
453
  }
454
454
 
455
+ // Apply the UI-visibility filters (hidden dirs, sensitive files,
456
+ // symlinks, .gitignore matches) to a single directory entry and stat
457
+ // it. Returns the resolved child paths + stat, or null when the entry
458
+ // should not surface. The recursive walk and the shallow lazy-expand
459
+ // path share this so the filter policy lives in exactly one place.
460
+ async function resolveVisibleChild(
461
+ entry: Dirent,
462
+ absPath: string,
463
+ relPath: string,
464
+ localFilter: GitignoreFilter | undefined,
465
+ ): Promise<{ childRel: string; childAbs: string; childStat: Stats } | null> {
466
+ if (HIDDEN_DIRS.has(entry.name)) return null;
467
+ if (!entry.isDirectory() && isSensitivePath(entry.name)) return null;
468
+ if (entry.isSymbolicLink()) return null;
469
+ const childRel = relPath ? path.join(relPath, entry.name) : entry.name;
470
+ // .gitignore check: for directories, append trailing / so
471
+ // directory-only patterns (e.g. "node_modules/") match.
472
+ if (localFilter) {
473
+ const testPath = entry.isDirectory() ? `${childRel}/` : childRel;
474
+ if (localFilter.ignores(testPath)) return null;
475
+ }
476
+ const childAbs = path.join(absPath, entry.name);
477
+ const childStat = await statSafeAsync(childAbs);
478
+ if (!childStat) return null;
479
+ return { childRel, childAbs, childStat };
480
+ }
481
+
482
+ // Await a directory's child-node promises, drop the filtered-out nulls,
483
+ // sort (dirs before files, alphabetical within type), and wrap them in
484
+ // the parent's `dir` TreeNode. Shared by the recursive and shallow
485
+ // builders so the assembly + ordering is defined once.
486
+ async function assembleDirNode(childPromises: Promise<TreeNode | null>[], relPath: string, modifiedMs: number): Promise<TreeNode> {
487
+ const resolved = await Promise.all(childPromises);
488
+ const children = resolved.filter((childNode): childNode is TreeNode => childNode !== null);
489
+ children.sort((leftChild, rightChild) => {
490
+ if (leftChild.type !== rightChild.type) return leftChild.type === "dir" ? -1 : 1;
491
+ return leftChild.name.localeCompare(rightChild.name);
492
+ });
493
+ return {
494
+ name: relPath ? path.basename(relPath) : "",
495
+ path: relPath,
496
+ type: "dir",
497
+ modifiedMs,
498
+ children,
499
+ };
500
+ }
501
+
455
502
  // Async workspace tree walker — recurses through the workspace with
456
503
  // the same security filters as the original sync implementation
457
504
  // (hidden dirs, sensitive files, symlinks all rejected) and the same
@@ -489,55 +536,23 @@ export async function buildTreeAsync(absPath: string, relPath: string, gitFilter
489
536
  // root .gitignore (it's for git, not the UI). Pass a fresh empty
490
537
  // filter so children pick up THEIR .gitignore files.
491
538
  const localFilter = gitFilter ? gitFilter.childForDir(absPath) : new GitignoreFilter();
492
- // Build every surviving child concurrently. Filter:
493
- // skip hidden dirs, sensitive files, symlinks, .gitignore matches,
494
- // and entries that fail to stat.
539
+ // Build every surviving child concurrently, recursing into the ones
540
+ // that pass the visibility filter.
495
541
  const childPromises: Promise<TreeNode | null>[] = entries.map(async (entry): Promise<TreeNode | null> => {
496
- if (HIDDEN_DIRS.has(entry.name)) return null;
497
- if (!entry.isDirectory() && isSensitivePath(entry.name)) return null;
498
- if (entry.isSymbolicLink()) return null;
499
- const childRel = relPath ? path.join(relPath, entry.name) : entry.name;
500
- // .gitignore check: for directories, append trailing / so
501
- // directory-only patterns (e.g. "node_modules/") match.
502
- if (localFilter) {
503
- const testPath = entry.isDirectory() ? `${childRel}/` : childRel;
504
- if (localFilter.ignores(testPath)) return null;
505
- }
506
- const childAbs = path.join(absPath, entry.name);
507
- const childStat = await statSafeAsync(childAbs);
508
- if (!childStat) return null;
509
- return buildTreeAsync(childAbs, childRel, localFilter);
510
- });
511
- const resolved = await Promise.all(childPromises);
512
- const children = resolved.filter((childNode): childNode is TreeNode => childNode !== null);
513
- children.sort((leftChild, rightChild) => {
514
- if (leftChild.type !== rightChild.type) return leftChild.type === "dir" ? -1 : 1;
515
- return leftChild.name.localeCompare(rightChild.name);
542
+ const child = await resolveVisibleChild(entry, absPath, relPath, localFilter);
543
+ if (!child) return null;
544
+ return buildTreeAsync(child.childAbs, child.childRel, localFilter);
516
545
  });
517
- return {
518
- name: relPath ? path.basename(relPath) : "",
519
- path: relPath,
520
- type: "dir",
521
- modifiedMs: stat.mtimeMs,
522
- children,
523
- };
546
+ return assembleDirNode(childPromises, relPath, stat.mtimeMs);
524
547
  }
525
548
 
526
549
  // Map a single directory entry to a shallow TreeNode, applying the
527
550
  // same hidden/sensitive/symlink/gitignore filters as the recursive
528
551
  // walk. Returns null for entries that should not surface in the UI.
529
552
  async function dirEntryToNode(entry: Dirent, absPath: string, relPath: string, localFilter: GitignoreFilter | undefined): Promise<TreeNode | null> {
530
- if (HIDDEN_DIRS.has(entry.name)) return null;
531
- if (!entry.isDirectory() && isSensitivePath(entry.name)) return null;
532
- if (entry.isSymbolicLink()) return null;
533
- const childRel = relPath ? path.join(relPath, entry.name) : entry.name;
534
- if (localFilter) {
535
- const testPath = entry.isDirectory() ? `${childRel}/` : childRel;
536
- if (localFilter.ignores(testPath)) return null;
537
- }
538
- const childAbs = path.join(absPath, entry.name);
539
- const childStat = await statSafeAsync(childAbs);
540
- if (!childStat) return null;
553
+ const child = await resolveVisibleChild(entry, absPath, relPath, localFilter);
554
+ if (!child) return null;
555
+ const { childRel, childStat } = child;
541
556
  if (childStat.isDirectory()) {
542
557
  return {
543
558
  name: entry.name,
@@ -580,19 +595,7 @@ export async function listDirShallow(absPath: string, relPath: string, gitFilter
580
595
  // filter so children pick up THEIR .gitignore files.
581
596
  const localFilter = gitFilter ? gitFilter.childForDir(absPath) : new GitignoreFilter();
582
597
  const childPromises = entries.map((entry) => dirEntryToNode(entry, absPath, relPath, localFilter));
583
- const resolved = await Promise.all(childPromises);
584
- const children = resolved.filter((childNode): childNode is TreeNode => childNode !== null);
585
- children.sort((leftChild, rightChild) => {
586
- if (leftChild.type !== rightChild.type) return leftChild.type === "dir" ? -1 : 1;
587
- return leftChild.name.localeCompare(rightChild.name);
588
- });
589
- return {
590
- name: relPath ? path.basename(relPath) : "",
591
- path: relPath,
592
- type: "dir",
593
- modifiedMs: stat.mtimeMs,
594
- children,
595
- };
598
+ return assembleDirNode(childPromises, relPath, stat.mtimeMs);
596
599
  }
597
600
 
598
601
  router.get(API_ROUTES.files.tree, async (_req: Request<object, unknown, unknown, object>, res: Response<TreeNode | ErrorResponse>) => {