@treenity/mods 3.0.1 → 3.0.3

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 (125) hide show
  1. package/agent/client.ts +2 -0
  2. package/agent/guardian.ts +492 -0
  3. package/agent/seed.ts +74 -0
  4. package/agent/server.ts +4 -0
  5. package/agent/service.ts +644 -0
  6. package/agent/types.ts +184 -0
  7. package/agent/view.tsx +431 -0
  8. package/board/view.tsx +1 -1
  9. package/brahman/helpers.ts +7 -7
  10. package/brahman/service.ts +24 -24
  11. package/brahman/types.ts +21 -21
  12. package/brahman/views/action-cards.tsx +33 -23
  13. package/brahman/views/bot-view.tsx +3 -2
  14. package/brahman/views/chat-editor.tsx +119 -124
  15. package/brahman/views/menu-editor.tsx +75 -89
  16. package/brahman/views/page-layout.tsx +10 -8
  17. package/brahman/views/tstring-input.tsx +25 -15
  18. package/canary/service.ts +18 -18
  19. package/dist/board/view.js +1 -1
  20. package/dist/board/view.js.map +1 -1
  21. package/dist/brahman/helpers.d.ts +1 -1
  22. package/dist/brahman/helpers.d.ts.map +1 -1
  23. package/dist/brahman/helpers.js +6 -6
  24. package/dist/brahman/helpers.js.map +1 -1
  25. package/dist/brahman/service.js +24 -24
  26. package/dist/brahman/service.js.map +1 -1
  27. package/dist/brahman/types.d.ts +1 -1
  28. package/dist/brahman/types.d.ts.map +1 -1
  29. package/dist/brahman/types.js +21 -21
  30. package/dist/brahman/types.js.map +1 -1
  31. package/dist/brahman/views/action-cards.d.ts.map +1 -1
  32. package/dist/brahman/views/action-cards.js +7 -4
  33. package/dist/brahman/views/action-cards.js.map +1 -1
  34. package/dist/brahman/views/bot-view.d.ts.map +1 -1
  35. package/dist/brahman/views/bot-view.js +2 -1
  36. package/dist/brahman/views/bot-view.js.map +1 -1
  37. package/dist/brahman/views/chat-editor.d.ts.map +1 -1
  38. package/dist/brahman/views/chat-editor.js +27 -18
  39. package/dist/brahman/views/chat-editor.js.map +1 -1
  40. package/dist/brahman/views/menu-editor.d.ts.map +1 -1
  41. package/dist/brahman/views/menu-editor.js +12 -16
  42. package/dist/brahman/views/menu-editor.js.map +1 -1
  43. package/dist/brahman/views/page-layout.d.ts.map +1 -1
  44. package/dist/brahman/views/page-layout.js +1 -1
  45. package/dist/brahman/views/page-layout.js.map +1 -1
  46. package/dist/brahman/views/tstring-input.d.ts.map +1 -1
  47. package/dist/brahman/views/tstring-input.js +7 -3
  48. package/dist/brahman/views/tstring-input.js.map +1 -1
  49. package/dist/canary/service.js +18 -18
  50. package/dist/canary/service.js.map +1 -1
  51. package/dist/doc/fs-codec.js +1 -1
  52. package/dist/doc/fs-codec.js.map +1 -1
  53. package/dist/doc/renderers.d.ts.map +1 -1
  54. package/dist/doc/renderers.js +2 -1
  55. package/dist/doc/renderers.js.map +1 -1
  56. package/dist/doc/toolbar.d.ts.map +1 -1
  57. package/dist/doc/toolbar.js +5 -5
  58. package/dist/doc/toolbar.js.map +1 -1
  59. package/dist/launcher/types.js +2 -2
  60. package/dist/launcher/types.js.map +1 -1
  61. package/dist/launcher/view.js +2 -2
  62. package/dist/launcher/view.js.map +1 -1
  63. package/dist/mindmap/branch.d.ts +10 -0
  64. package/dist/mindmap/branch.d.ts.map +1 -1
  65. package/dist/mindmap/branch.js +42 -9
  66. package/dist/mindmap/branch.js.map +1 -1
  67. package/dist/mindmap/sidebar.d.ts.map +1 -1
  68. package/dist/mindmap/sidebar.js +4 -3
  69. package/dist/mindmap/sidebar.js.map +1 -1
  70. package/dist/mindmap/view.d.ts.map +1 -1
  71. package/dist/mindmap/view.js +35 -4
  72. package/dist/mindmap/view.js.map +1 -1
  73. package/dist/sensor-demo/service.js +6 -5
  74. package/dist/sensor-demo/service.js.map +1 -1
  75. package/dist/sensor-generator/action.js +1 -1
  76. package/dist/sensor-generator/action.js.map +1 -1
  77. package/dist/sim/service.js +41 -41
  78. package/dist/sim/service.js.map +1 -1
  79. package/dist/table/view.js.map +1 -1
  80. package/dist/todo/types.js +2 -2
  81. package/dist/todo/types.js.map +1 -1
  82. package/dist/todo/view.js +6 -4
  83. package/dist/todo/view.js.map +1 -1
  84. package/dist/whisper/inbox.js +3 -3
  85. package/dist/whisper/inbox.js.map +1 -1
  86. package/dist/whisper/route.d.ts +1 -1
  87. package/dist/whisper/route.d.ts.map +1 -1
  88. package/dist/whisper/route.js +13 -13
  89. package/dist/whisper/route.js.map +1 -1
  90. package/doc/CLAUDE.md +1 -1
  91. package/doc/fs-codec.ts +1 -1
  92. package/doc/renderers.tsx +4 -3
  93. package/doc/toolbar.tsx +12 -9
  94. package/launcher/types.ts +2 -2
  95. package/launcher/view.tsx +12 -8
  96. package/mcp/mcp-server.ts +393 -0
  97. package/mcp/server.ts +2 -0
  98. package/mcp/service.ts +18 -0
  99. package/mcp/types.ts +6 -0
  100. package/mindmap/branch.tsx +121 -22
  101. package/mindmap/mindmap.css +52 -0
  102. package/mindmap/sidebar.tsx +9 -6
  103. package/mindmap/view.tsx +40 -4
  104. package/package.json +30 -3
  105. package/sensor-demo/service.ts +6 -5
  106. package/sensor-generator/action.ts +1 -1
  107. package/sim/service.ts +41 -41
  108. package/table/view.tsx +7 -2
  109. package/todo/types.ts +2 -2
  110. package/todo/view.tsx +9 -10
  111. package/whisper/inbox.ts +3 -3
  112. package/whisper/route.ts +13 -13
  113. package/board/board.test.ts +0 -212
  114. package/brahman/brahman.test.ts +0 -855
  115. package/dist/mindmap/radial-tree.d.ts +0 -14
  116. package/dist/mindmap/radial-tree.d.ts.map +0 -1
  117. package/dist/mindmap/radial-tree.js +0 -184
  118. package/dist/mindmap/radial-tree.js.map +0 -1
  119. package/dist/mindmap/use-tree-data.d.ts +0 -14
  120. package/dist/mindmap/use-tree-data.d.ts.map +0 -1
  121. package/dist/mindmap/use-tree-data.js +0 -95
  122. package/dist/mindmap/use-tree-data.js.map +0 -1
  123. package/doc/fs-codec.test.ts +0 -119
  124. package/doc/markdown.test.ts +0 -152
  125. package/sim/sim.test.ts +0 -282
@@ -1,14 +0,0 @@
1
- import 'd3-transition';
2
- import type { TreeItem } from './use-tree-data';
3
- type Props = {
4
- data: TreeItem;
5
- selectedPath: string | null;
6
- onSelect: (path: string) => void;
7
- onToggle: (path: string) => void;
8
- branchColors: Map<string, string>;
9
- width: number;
10
- height: number;
11
- };
12
- export declare function MindMapTree({ data, selectedPath, onSelect, onToggle, branchColors, width, height }: Props): import("react/jsx-runtime").JSX.Element;
13
- export {};
14
- //# sourceMappingURL=radial-tree.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"radial-tree.d.ts","sourceRoot":"","sources":["../../mindmap/radial-tree.tsx"],"names":[],"mappings":"AAKA,OAAO,eAAe,CAAC;AAGvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAkGF,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,2CA6QzG"}
@@ -1,184 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // Miro-style mind map — horizontal balanced tree with organic bezier curves
3
- // Pure SVG: text labels + colored branches, no foreignObject
4
- import { hierarchy, tree as d3tree } from 'd3-hierarchy';
5
- import { select } from 'd3-selection';
6
- import 'd3-transition';
7
- import { zoom as d3zoom, zoomIdentity } from 'd3-zoom';
8
- import { useCallback, useEffect, useMemo, useRef } from 'react';
9
- // Type → icon mapping (simple SVG paths)
10
- const TYPE_ICONS = {
11
- dir: 'M2 4h5l2 2h9v12H2V4z',
12
- ref: 'M10 2a8 8 0 100 16 8 8 0 000-16zm1 4v4l3.5 2.1-.8 1.3L9 11V6h2z',
13
- user: 'M12 4a4 4 0 110 8 4 4 0 010-8zM12 14c-4.42 0-8 1.79-8 4v2h16v-2c0-2.21-3.58-4-8-4z',
14
- root: 'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z',
15
- };
16
- function getIcon(type) {
17
- if (TYPE_ICONS[type])
18
- return TYPE_ICONS[type];
19
- const base = type.split('.')[0];
20
- return TYPE_ICONS[base] ?? null;
21
- }
22
- // Measure text width roughly (8px per char at 13px font, 6.5px at 11px)
23
- function textWidth(str, fontSize) {
24
- return str.length * fontSize * 0.62;
25
- }
26
- function splitTree(root) {
27
- const left = [];
28
- const right = [];
29
- root.children.forEach((child, i) => {
30
- const tagged = { ...child, _side: (i % 2 === 0 ? 'right' : 'left') };
31
- if (i % 2 === 0)
32
- right.push(tagged);
33
- else
34
- left.push(tagged);
35
- });
36
- return { ...root, children: [...right, ...left] };
37
- }
38
- function tagSide(item, side) {
39
- return {
40
- ...item,
41
- _side: item._side ?? side,
42
- children: item.children.map(c => tagSide(c, side)),
43
- };
44
- }
45
- function buildSide(root, children, side) {
46
- return {
47
- ...root,
48
- _side: undefined,
49
- children: children.map(c => tagSide(c, side)),
50
- };
51
- }
52
- // Organic cubic bezier — Miro-style smooth S-curve
53
- function linkPath(sx, sy, tx, ty) {
54
- const dx = tx - sx;
55
- const cp = Math.abs(dx) * 0.5;
56
- return `M${sx},${sy} C${sx + (dx > 0 ? cp : -cp)},${sy} ${tx - (dx > 0 ? cp : -cp)},${ty} ${tx},${ty}`;
57
- }
58
- function layoutHalf(root, children, side, height) {
59
- if (children.length === 0)
60
- return null;
61
- const subtree = buildSide(root, children, side);
62
- const h = hierarchy(subtree, d => d.children);
63
- const nodeCount = h.descendants().length;
64
- const treeHeight = Math.max(height * 0.8, nodeCount * 32);
65
- const layout = d3tree()
66
- .size([treeHeight, 220 * Math.max(1, h.height)])
67
- .separation((a, b) => (a.parent === b.parent ? 1 : 1.5));
68
- layout(h);
69
- // Convert: d3tree gives vertical layout (x=vertical, y=horizontal)
70
- // We flip and mirror for left side
71
- for (const node of h.descendants()) {
72
- const lNode = node;
73
- if (side === 'left') {
74
- lNode._rx = -lNode.y;
75
- lNode._ry = lNode.x - treeHeight / 2;
76
- }
77
- else {
78
- lNode._rx = lNode.y;
79
- lNode._ry = lNode.x - treeHeight / 2;
80
- }
81
- }
82
- return h;
83
- }
84
- export function MindMapTree({ data, selectedPath, onSelect, onToggle, branchColors, width, height }) {
85
- const svgRef = useRef(null);
86
- const gRef = useRef(null);
87
- const zoomRef = useRef(null);
88
- // Split into left/right halves
89
- const { leftNodes, rightNodes } = useMemo(() => {
90
- const split = splitTree(data);
91
- const leftChildren = [];
92
- const rightChildren = [];
93
- for (const c of split.children) {
94
- if (c._side === 'left')
95
- leftChildren.push(c);
96
- else
97
- rightChildren.push(c);
98
- }
99
- const left = layoutHalf(data, leftChildren, 'left', height);
100
- const right = layoutHalf(data, rightChildren, 'right', height);
101
- return {
102
- leftNodes: left ? left.descendants().slice(1) : [],
103
- rightNodes: right ? right.descendants().slice(1) : [],
104
- };
105
- }, [data, height]);
106
- const allNodes = useMemo(() => [...leftNodes, ...rightNodes], [leftNodes, rightNodes]);
107
- // Build links from parent→child coords
108
- const links = useMemo(() => {
109
- const result = [];
110
- for (const node of allNodes) {
111
- const parent = node.parent;
112
- if (!parent)
113
- continue;
114
- const sx = parent.depth === 0 ? 0 : parent._rx;
115
- const sy = parent.depth === 0 ? 0 : parent._ry;
116
- const tx = node._rx;
117
- const ty = node._ry;
118
- const color = branchColors.get(node.data.path) ?? 'var(--text-3)';
119
- const strokeWidth = Math.max(1.5, 3.5 - node.depth * 0.6);
120
- result.push({
121
- key: `${parent.data.path}->${node.data.path}`,
122
- path: linkPath(sx, sy, tx, ty),
123
- color,
124
- width: strokeWidth,
125
- source: parent,
126
- target: node,
127
- });
128
- }
129
- return result;
130
- }, [allNodes, branchColors]);
131
- // Zoom
132
- useEffect(() => {
133
- if (!svgRef.current || !gRef.current)
134
- return;
135
- const svg = select(svgRef.current);
136
- const g = select(gRef.current);
137
- const zoomBehavior = d3zoom()
138
- .scaleExtent([0.1, 4])
139
- .on('zoom', event => {
140
- g.attr('transform', event.transform.toString());
141
- });
142
- svg.call(zoomBehavior);
143
- const initialTransform = zoomIdentity.translate(width / 2, height / 2).scale(0.85);
144
- svg.call(zoomBehavior.transform, initialTransform);
145
- zoomRef.current = zoomBehavior;
146
- return () => { svg.on('.zoom', null); };
147
- }, [width, height]);
148
- // Fit view
149
- const fitView = useCallback(() => {
150
- if (!svgRef.current || !zoomRef.current || !gRef.current)
151
- return;
152
- const svg = select(svgRef.current);
153
- const bounds = gRef.current.getBBox();
154
- if (!bounds.width || !bounds.height)
155
- return;
156
- const pad = 60;
157
- const scale = Math.min((width - pad * 2) / bounds.width, (height - pad * 2) / bounds.height, 1.5);
158
- const tx = width / 2 - (bounds.x + bounds.width / 2) * scale;
159
- const ty = height / 2 - (bounds.y + bounds.height / 2) * scale;
160
- svg.transition().duration(400).call(zoomRef.current.transform, zoomIdentity.translate(tx, ty).scale(scale));
161
- }, [width, height]);
162
- // Auto-fit on data change
163
- useEffect(() => {
164
- const t = setTimeout(fitView, 80);
165
- return () => clearTimeout(t);
166
- }, [data, fitView]);
167
- const rootName = data.name === '/' ? '/' : data.name;
168
- const rootColor = branchColors.get(data.path) ?? 'var(--text)';
169
- return (_jsxs("div", { className: "mm-tree-wrap", children: [_jsx("div", { className: "mm-toolbar", children: _jsx("button", { className: "mm-btn", onClick: fitView, title: "Fit view", children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("path", { d: "M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7" }) }) }) }), _jsx("svg", { ref: svgRef, width: width, height: height, className: "mm-svg", children: _jsxs("g", { ref: gRef, children: [links.map(l => (_jsx("path", { d: l.path, fill: "none", stroke: l.color, strokeWidth: l.width, strokeOpacity: 0.7, strokeLinecap: "round", className: "mm-link" }, l.key))), _jsxs("g", { className: `mm-node mm-root${selectedPath === data.path ? ' mm-node-selected' : ''}`, onClick: () => onSelect(data.path), onDoubleClick: () => onToggle(data.path), children: [_jsx("rect", { x: -textWidth(rootName, 16) / 2 - 24, y: -20, width: textWidth(rootName, 16) + 48, height: 40, rx: 20, className: "mm-root-bg" }), _jsx("text", { textAnchor: "middle", dominantBaseline: "central", className: "mm-root-label", children: rootName })] }), allNodes.map(node => {
170
- const d = node.data;
171
- const x = node._rx;
172
- const y = node._ry;
173
- const color = branchColors.get(d.path) ?? 'var(--text-2)';
174
- const isLeft = d._side === 'left';
175
- const isSelected = selectedPath === d.path;
176
- const icon = getIcon(d.type);
177
- const hasChildren = d.childCount > 0;
178
- const label = d.name;
179
- // Type badge (short)
180
- const shortType = d.type.includes('.') ? d.type.split('.').pop() : '';
181
- return (_jsxs("g", { transform: `translate(${x},${y})`, className: `mm-node${isSelected ? ' mm-node-selected' : ''}`, onClick: () => onSelect(d.path), onDoubleClick: () => onToggle(d.path), children: [_jsx("rect", { x: isLeft ? -textWidth(label, 13) - 30 : -10, y: -14, width: textWidth(label, 13) + 50, height: 28, fill: "transparent", className: "mm-hit" }), isSelected && (_jsx("rect", { x: isLeft ? -textWidth(label, 13) - 26 : -6, y: -12, width: textWidth(label, 13) + 42, height: 24, rx: 12, className: "mm-select-bg", fill: color, fillOpacity: 0.1 })), _jsx("circle", { cx: 0, cy: 0, r: hasChildren && !d.expanded ? 4 : 3, fill: color, className: "mm-dot" }), icon && (_jsx("g", { transform: `translate(${isLeft ? -22 : 8}, -8) scale(0.7)`, children: _jsx("path", { d: icon, fill: color, fillOpacity: 0.6 }) })), _jsx("text", { x: isLeft ? -12 : (icon ? 24 : 12), textAnchor: isLeft ? 'end' : 'start', dominantBaseline: "central", className: "mm-label", fill: color, children: label }), shortType && node.depth <= 2 && (_jsx("text", { x: isLeft ? -12 - textWidth(label, 13) - 8 : (icon ? 24 : 12) + textWidth(label, 13) + 8, textAnchor: isLeft ? 'end' : 'start', dominantBaseline: "central", className: "mm-type-tag", fill: color, children: shortType })), hasChildren && !d.expanded && (_jsxs("g", { transform: `translate(${isLeft ? 8 : -8 + (icon ? 24 : 12) + textWidth(label, 13) + (shortType && node.depth <= 2 ? textWidth(shortType, 10) + 16 : 8)}, 0)`, className: "mm-count-badge", onClick: e => { e.stopPropagation(); onToggle(d.path); }, children: [_jsx("circle", { r: 8, fill: color, fillOpacity: 0.15 }), _jsx("text", { textAnchor: "middle", dominantBaseline: "central", fill: color, fontSize: "9", fontWeight: "600", children: d.childCount })] }))] }, d.path));
182
- })] }) })] }));
183
- }
184
- //# sourceMappingURL=radial-tree.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"radial-tree.js","sourceRoot":"","sources":["../../mindmap/radial-tree.tsx"],"names":[],"mappings":"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"}
@@ -1,14 +0,0 @@
1
- import type { NodeData } from '@treenity/core';
2
- export type TreeItem = {
3
- path: string;
4
- name: string;
5
- type: string;
6
- node: NodeData;
7
- components: [string, Record<string, unknown>][];
8
- childCount: number;
9
- children: TreeItem[];
10
- expanded: boolean;
11
- depth: number;
12
- };
13
- export declare function useTreeData(rootPath: string, expanded: Set<string>, maxChildren?: number): TreeItem | null;
14
- //# sourceMappingURL=use-tree-data.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-tree-data.d.ts","sourceRoot":"","sources":["../../mindmap/use-tree-data.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAM/C,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AA8DF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,WAAW,SAAK,mBA4CpF"}
@@ -1,95 +0,0 @@
1
- // useTreeData — bridge between Treenity cache and D3 hierarchy
2
- // Lazily loads children for expanded paths, builds nested tree structure
3
- import * as cache from '@treenity/react/cache';
4
- import { getComponents } from '@treenity/react/mods/editor-ui/node-utils';
5
- import { trpc } from '@treenity/react/trpc';
6
- import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
7
- // Fetch children for a path if not already in cache
8
- function ensureChildren(path) {
9
- const existing = cache.getChildren(path);
10
- if (existing.length)
11
- return;
12
- trpc.getChildren
13
- .query({ path, watch: true, watchNew: true })
14
- .then((r) => cache.putMany(r.items, path));
15
- }
16
- function basename(path) {
17
- if (path === '/')
18
- return '/';
19
- const i = path.lastIndexOf('/');
20
- return i < 0 ? path : path.slice(i + 1);
21
- }
22
- function buildTree(rootNode, expanded, depth, maxChildren) {
23
- const children = cache.getChildren(rootNode.$path);
24
- const isExpanded = expanded.has(rootNode.$path);
25
- const comps = getComponents(rootNode);
26
- const childItems = [];
27
- if (isExpanded) {
28
- const limited = children.slice(0, maxChildren);
29
- for (const child of limited) {
30
- childItems.push(buildTree(child, expanded, depth + 1, maxChildren));
31
- }
32
- // Overflow indicator
33
- if (children.length > maxChildren) {
34
- childItems.push({
35
- path: rootNode.$path + '/__more__',
36
- name: `+${children.length - maxChildren} more`,
37
- type: '__overflow__',
38
- node: rootNode,
39
- components: [],
40
- childCount: 0,
41
- children: [],
42
- expanded: false,
43
- depth: depth + 1,
44
- });
45
- }
46
- }
47
- return {
48
- path: rootNode.$path,
49
- name: basename(rootNode.$path),
50
- type: rootNode.$type,
51
- node: rootNode,
52
- components: comps,
53
- childCount: children.length,
54
- children: childItems,
55
- expanded: isExpanded,
56
- depth,
57
- };
58
- }
59
- export function useTreeData(rootPath, expanded, maxChildren = 50) {
60
- const [version, setVersion] = useState(0);
61
- const loadedRef = useRef(null);
62
- // Initial fetch for root's children
63
- useEffect(() => {
64
- if (loadedRef.current === rootPath)
65
- return;
66
- loadedRef.current = rootPath;
67
- ensureChildren(rootPath);
68
- }, [rootPath]);
69
- // Fetch children for newly expanded paths
70
- useEffect(() => {
71
- for (const p of expanded)
72
- ensureChildren(p);
73
- }, [expanded]);
74
- // Subscribe to children changes for root + all expanded paths
75
- useEffect(() => {
76
- const paths = [rootPath, ...expanded];
77
- const unsubs = paths.map(p => cache.subscribeChildren(p, () => setVersion(v => v + 1)));
78
- return () => unsubs.forEach(u => u());
79
- }, [rootPath, [...expanded].join(',')]);
80
- // Subscribe to root node changes
81
- useEffect(() => {
82
- return cache.subscribePath(rootPath, () => setVersion(v => v + 1));
83
- }, [rootPath]);
84
- // Get root node from cache
85
- const rootNode = useSyncExternalStore(useCallback((cb) => cache.subscribePath(rootPath, cb), [rootPath]), useCallback(() => cache.get(rootPath), [rootPath]));
86
- // Build hierarchy from cache data
87
- const tree = useMemo(() => {
88
- if (!rootNode)
89
- return null;
90
- return buildTree(rootNode, expanded, 0, maxChildren);
91
- // eslint-disable-next-line react-hooks/exhaustive-deps
92
- }, [rootNode, expanded, version, maxChildren]);
93
- return tree;
94
- }
95
- //# sourceMappingURL=use-tree-data.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-tree-data.js","sourceRoot":"","sources":["../../mindmap/use-tree-data.ts"],"names":[],"mappings":"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"}
@@ -1,119 +0,0 @@
1
- import type { Tree } from '@treenity/core/tree';
2
- import { createFsTree } from '@treenity/core/tree/fs';
3
- import assert from 'node:assert/strict';
4
- import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
5
- import { tmpdir } from 'node:os';
6
- import { join } from 'node:path';
7
- import { afterEach, beforeEach, describe, it } from 'node:test';
8
-
9
- // Register the codec — side effect import
10
- import './fs-codec';
11
-
12
- describe('doc fs-codec', () => {
13
- let dir: string;
14
- let store: Tree;
15
-
16
- beforeEach(async () => {
17
- dir = await mkdtemp(join(tmpdir(), 'treenity-doc-codec-'));
18
- store = await createFsTree(dir);
19
- });
20
-
21
- afterEach(async () => {
22
- if (dir) await rm(dir, { recursive: true, force: true });
23
- });
24
-
25
- it('decode: .md file → doc.page node', async () => {
26
- await writeFile(join(dir, 'readme.md'), '# Hello World\n\nSome content here.\n');
27
-
28
- const node = await store.get('/readme');
29
- assert.equal(node?.$type, 'doc.page');
30
- assert.equal((node as any).title, 'Hello World');
31
-
32
- const content = JSON.parse((node as any).content);
33
- assert.equal(content.type, 'doc');
34
- assert.ok(content.content.length > 0);
35
- });
36
-
37
- it('decode: .md without H1 — empty title', async () => {
38
- await writeFile(join(dir, 'notes.md'), 'Just a paragraph.\n\n## Second heading\n');
39
-
40
- const node = await store.get('/notes');
41
- assert.equal(node?.$type, 'doc.page');
42
- assert.equal((node as any).title, '');
43
-
44
- const content = JSON.parse((node as any).content);
45
- assert.equal(content.content[0].type, 'paragraph');
46
- assert.equal(content.content[1].type, 'heading');
47
- });
48
-
49
- it('encode: doc.page node → .md file', async () => {
50
- const tiptapDoc = {
51
- type: 'doc',
52
- content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Hello from Tiptap' }] }],
53
- };
54
-
55
- await store.set({
56
- $path: '/output',
57
- $type: 'doc.page',
58
- title: 'My Doc',
59
- content: JSON.stringify(tiptapDoc),
60
- } as any);
61
-
62
- const raw = await readFile(join(dir, 'output.md'), 'utf-8');
63
- assert.ok(raw.startsWith('# My Doc'));
64
- assert.ok(raw.includes('Hello from Tiptap'));
65
- });
66
-
67
- it('encode: no title — no H1 prefix', async () => {
68
- const tiptapDoc = {
69
- type: 'doc',
70
- content: [{ type: 'paragraph', content: [{ type: 'text', text: 'Just text' }] }],
71
- };
72
-
73
- await store.set({
74
- $path: '/bare',
75
- $type: 'doc.page',
76
- title: '',
77
- content: JSON.stringify(tiptapDoc),
78
- } as any);
79
-
80
- const raw = await readFile(join(dir, 'bare.md'), 'utf-8');
81
- assert.ok(!raw.startsWith('#'));
82
- assert.ok(raw.includes('Just text'));
83
- });
84
-
85
- it('roundtrip: .md → node → .md preserves content', async () => {
86
- const original = '# Project Notes\n\nThis is **bold** and *italic*.\n\n- item one\n- item two\n\n```ts\nconst x = 1;\n```\n';
87
- await writeFile(join(dir, 'notes.md'), original);
88
-
89
- // Decode
90
- const node = await store.get('/notes');
91
- assert.equal(node?.$type, 'doc.page');
92
- assert.equal((node as any).title, 'Project Notes');
93
-
94
- // Encode back
95
- await store.set(node!);
96
- const result = await readFile(join(dir, 'notes.md'), 'utf-8');
97
-
98
- // Verify key elements survived roundtrip
99
- assert.ok(result.includes('# Project Notes'));
100
- assert.ok(result.includes('**bold**'));
101
- assert.ok(result.includes('*italic*'));
102
- assert.ok(result.includes('- item one'));
103
- assert.ok(result.includes('```ts'));
104
- assert.ok(result.includes('const x = 1;'));
105
- });
106
-
107
- it('getChildren lists .md files as doc.page', async () => {
108
- await writeFile(join(dir, 'a.md'), '# Alpha\n\nContent A\n');
109
- await writeFile(join(dir, 'b.md'), '# Beta\n\nContent B\n');
110
- await writeFile(join(dir, 'c.txt'), 'plain text');
111
-
112
- const { items } = await store.getChildren('/');
113
- const types = Object.fromEntries(items.map(n => [n.$path, n.$type]));
114
-
115
- assert.equal(types['/a'], 'doc.page');
116
- assert.equal(types['/b'], 'doc.page');
117
- assert.equal(types['/c'], 'text/plain');
118
- });
119
- });
@@ -1,152 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import { describe, it } from 'node:test';
3
- import { mdToTiptap, type TiptapNode, tiptapToMd } from './markdown';
4
-
5
- describe('mdToTiptap', () => {
6
- it('parses heading', () => {
7
- const doc = mdToTiptap('# Hello');
8
- assert.equal(doc.type, 'doc');
9
- assert.equal(doc.content?.[0].type, 'heading');
10
- assert.equal(doc.content?.[0].attrs?.level, 1);
11
- assert.equal(doc.content?.[0].content?.[0].text, 'Hello');
12
- });
13
-
14
- it('parses multiple heading levels', () => {
15
- const doc = mdToTiptap('## Second\n### Third');
16
- assert.equal(doc.content?.[0].attrs?.level, 2);
17
- assert.equal(doc.content?.[1].attrs?.level, 3);
18
- });
19
-
20
- it('parses paragraph', () => {
21
- const doc = mdToTiptap('Just some text');
22
- assert.equal(doc.content?.[0].type, 'paragraph');
23
- assert.equal(doc.content?.[0].content?.[0].text, 'Just some text');
24
- });
25
-
26
- it('parses bold and italic', () => {
27
- const doc = mdToTiptap('This is **bold** and *italic*');
28
- const nodes = doc.content?.[0].content ?? [];
29
- assert.ok(nodes.some((n) => n.text === 'bold' && n.marks?.[0]?.type === 'bold'));
30
- assert.ok(nodes.some((n) => n.text === 'italic' && n.marks?.[0]?.type === 'italic'));
31
- });
32
-
33
- it('parses inline code', () => {
34
- const doc = mdToTiptap('Use `foo()` here');
35
- const nodes = doc.content?.[0].content ?? [];
36
- assert.ok(nodes.some((n) => n.text === 'foo()' && n.marks?.[0]?.type === 'code'));
37
- });
38
-
39
- it('parses bullet list', () => {
40
- const doc = mdToTiptap('- one\n- two\n- three');
41
- assert.equal(doc.content?.[0].type, 'bulletList');
42
- assert.equal(doc.content?.[0].content?.length, 3);
43
- });
44
-
45
- it('parses ordered list', () => {
46
- const doc = mdToTiptap('1. first\n2. second');
47
- assert.equal(doc.content?.[0].type, 'orderedList');
48
- assert.equal(doc.content?.[0].content?.length, 2);
49
- });
50
-
51
- it('parses code block', () => {
52
- const doc = mdToTiptap('```ts\nconst x = 1;\n```');
53
- assert.equal(doc.content?.[0].type, 'codeBlock');
54
- assert.equal(doc.content?.[0].attrs?.language, 'ts');
55
- assert.equal(doc.content?.[0].content?.[0].text, 'const x = 1;');
56
- });
57
-
58
- it('parses blockquote', () => {
59
- const doc = mdToTiptap('> quoted text');
60
- assert.equal(doc.content?.[0].type, 'blockquote');
61
- });
62
-
63
- it('parses horizontal rule', () => {
64
- const doc = mdToTiptap('---');
65
- assert.equal(doc.content?.[0].type, 'horizontalRule');
66
- });
67
-
68
- it('handles empty input', () => {
69
- const doc = mdToTiptap('');
70
- assert.equal(doc.type, 'doc');
71
- assert.ok(doc.content?.length);
72
- });
73
-
74
- it('handles mixed content', () => {
75
- const md = '# Title\n\nSome text\n\n- item 1\n- item 2\n\n```\ncode\n```';
76
- const doc = mdToTiptap(md);
77
- const types = doc.content?.map((c) => c.type);
78
- assert.deepEqual(types, ['heading', 'paragraph', 'bulletList', 'codeBlock']);
79
- });
80
- });
81
-
82
- describe('tiptapToMd', () => {
83
- it('converts heading', () => {
84
- const doc: TiptapNode = {
85
- type: 'doc',
86
- content: [{ type: 'heading', attrs: { level: 2 }, content: [{ type: 'text', text: 'Title' }] }],
87
- };
88
- assert.equal(tiptapToMd(doc), '## Title');
89
- });
90
-
91
- it('converts paragraph with marks', () => {
92
- const doc: TiptapNode = {
93
- type: 'doc',
94
- content: [{
95
- type: 'paragraph',
96
- content: [
97
- { type: 'text', text: 'Hello ' },
98
- { type: 'text', text: 'world', marks: [{ type: 'bold' }] },
99
- ],
100
- }],
101
- };
102
- assert.equal(tiptapToMd(doc), 'Hello **world**');
103
- });
104
-
105
- it('converts bullet list', () => {
106
- const doc: TiptapNode = {
107
- type: 'doc',
108
- content: [{
109
- type: 'bulletList',
110
- content: [
111
- { type: 'listItem', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'a' }] }] },
112
- { type: 'listItem', content: [{ type: 'paragraph', content: [{ type: 'text', text: 'b' }] }] },
113
- ],
114
- }],
115
- };
116
- assert.equal(tiptapToMd(doc), '- a\n- b');
117
- });
118
-
119
- it('converts code block', () => {
120
- const doc: TiptapNode = {
121
- type: 'doc',
122
- content: [{ type: 'codeBlock', attrs: { language: 'js' }, content: [{ type: 'text', text: 'x = 1' }] }],
123
- };
124
- assert.equal(tiptapToMd(doc), '```js\nx = 1\n```');
125
- });
126
-
127
- it('converts horizontal rule', () => {
128
- const doc: TiptapNode = { type: 'doc', content: [{ type: 'horizontalRule' }] };
129
- assert.equal(tiptapToMd(doc), '---');
130
- });
131
- });
132
-
133
- describe('roundtrip md → tiptap → md', () => {
134
- it('preserves basic structure', () => {
135
- const original = '# Hello\n\nSome paragraph\n\n- one\n- two';
136
- const tiptap = mdToTiptap(original);
137
- const result = tiptapToMd(tiptap);
138
- // Should contain the same elements (whitespace may differ)
139
- assert.ok(result.includes('# Hello'));
140
- assert.ok(result.includes('Some paragraph'));
141
- assert.ok(result.includes('- one'));
142
- assert.ok(result.includes('- two'));
143
- });
144
-
145
- it('preserves code block', () => {
146
- const original = '```ts\nconst x = 1;\n```';
147
- const tiptap = mdToTiptap(original);
148
- const result = tiptapToMd(tiptap);
149
- assert.ok(result.includes('```ts'));
150
- assert.ok(result.includes('const x = 1;'));
151
- });
152
- });