@treenity/mods 3.0.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.
- package/board/board.test.ts +212 -0
- package/board/client.ts +1 -0
- package/board/seed.ts +26 -0
- package/board/server.ts +5 -0
- package/board/types.ts +87 -0
- package/board/view.tsx +574 -0
- package/brahman/CLAUDE.md +18 -0
- package/brahman/brahman.test.ts +855 -0
- package/brahman/client.ts +2 -0
- package/brahman/helpers.ts +374 -0
- package/brahman/server.ts +2 -0
- package/brahman/service.ts +328 -0
- package/brahman/types.ts +727 -0
- package/brahman/view.tsx +73 -0
- package/brahman/views/action-cards.tsx +615 -0
- package/brahman/views/bot-view.tsx +76 -0
- package/brahman/views/chat-editor.tsx +782 -0
- package/brahman/views/chat-preview.tsx +266 -0
- package/brahman/views/menu-editor.tsx +451 -0
- package/brahman/views/page-layout.tsx +285 -0
- package/brahman/views/tstring-input.tsx +84 -0
- package/cafe/CLAUDE.md +7 -0
- package/cafe/seed.ts +8 -0
- package/cafe/server.ts +2 -0
- package/cafe/types.ts +32 -0
- package/canary/seed.ts +8 -0
- package/canary/server.ts +3 -0
- package/canary/service.ts +101 -0
- package/canary/types.ts +16 -0
- package/dist/board/client.d.ts +2 -0
- package/dist/board/client.d.ts.map +1 -0
- package/dist/board/client.js +2 -0
- package/dist/board/client.js.map +1 -0
- package/dist/board/seed.d.ts +2 -0
- package/dist/board/seed.d.ts.map +1 -0
- package/dist/board/seed.js +23 -0
- package/dist/board/seed.js.map +1 -0
- package/dist/board/server.d.ts +3 -0
- package/dist/board/server.d.ts.map +1 -0
- package/dist/board/server.js +5 -0
- package/dist/board/server.js.map +1 -0
- package/dist/board/types.d.ts +45 -0
- package/dist/board/types.d.ts.map +1 -0
- package/dist/board/types.js +82 -0
- package/dist/board/types.js.map +1 -0
- package/dist/board/view.d.ts +2 -0
- package/dist/board/view.d.ts.map +1 -0
- package/dist/board/view.js +254 -0
- package/dist/board/view.js.map +1 -0
- package/dist/brahman/client.d.ts +3 -0
- package/dist/brahman/client.d.ts.map +1 -0
- package/dist/brahman/client.js +3 -0
- package/dist/brahman/client.js.map +1 -0
- package/dist/brahman/helpers.d.ts +51 -0
- package/dist/brahman/helpers.d.ts.map +1 -0
- package/dist/brahman/helpers.js +321 -0
- package/dist/brahman/helpers.js.map +1 -0
- package/dist/brahman/server.d.ts +3 -0
- package/dist/brahman/server.d.ts.map +1 -0
- package/dist/brahman/server.js +3 -0
- package/dist/brahman/server.js.map +1 -0
- package/dist/brahman/service.d.ts +2 -0
- package/dist/brahman/service.d.ts.map +1 -0
- package/dist/brahman/service.js +310 -0
- package/dist/brahman/service.js.map +1 -0
- package/dist/brahman/types.d.ts +335 -0
- package/dist/brahman/types.d.ts.map +1 -0
- package/dist/brahman/types.js +633 -0
- package/dist/brahman/types.js.map +1 -0
- package/dist/brahman/view.d.ts +2 -0
- package/dist/brahman/view.d.ts.map +1 -0
- package/dist/brahman/view.js +47 -0
- package/dist/brahman/view.js.map +1 -0
- package/dist/brahman/views/action-cards.d.ts +60 -0
- package/dist/brahman/views/action-cards.d.ts.map +1 -0
- package/dist/brahman/views/action-cards.js +283 -0
- package/dist/brahman/views/action-cards.js.map +1 -0
- package/dist/brahman/views/bot-view.d.ts +5 -0
- package/dist/brahman/views/bot-view.d.ts.map +1 -0
- package/dist/brahman/views/bot-view.js +14 -0
- package/dist/brahman/views/bot-view.js.map +1 -0
- package/dist/brahman/views/chat-editor.d.ts +5 -0
- package/dist/brahman/views/chat-editor.d.ts.map +1 -0
- package/dist/brahman/views/chat-editor.js +306 -0
- package/dist/brahman/views/chat-editor.js.map +1 -0
- package/dist/brahman/views/chat-preview.d.ts +5 -0
- package/dist/brahman/views/chat-preview.d.ts.map +1 -0
- package/dist/brahman/views/chat-preview.js +145 -0
- package/dist/brahman/views/chat-preview.js.map +1 -0
- package/dist/brahman/views/menu-editor.d.ts +11 -0
- package/dist/brahman/views/menu-editor.d.ts.map +1 -0
- package/dist/brahman/views/menu-editor.js +171 -0
- package/dist/brahman/views/menu-editor.js.map +1 -0
- package/dist/brahman/views/page-layout.d.ts +5 -0
- package/dist/brahman/views/page-layout.d.ts.map +1 -0
- package/dist/brahman/views/page-layout.js +114 -0
- package/dist/brahman/views/page-layout.js.map +1 -0
- package/dist/brahman/views/tstring-input.d.ts +15 -0
- package/dist/brahman/views/tstring-input.d.ts.map +1 -0
- package/dist/brahman/views/tstring-input.js +23 -0
- package/dist/brahman/views/tstring-input.js.map +1 -0
- package/dist/cafe/seed.d.ts +2 -0
- package/dist/cafe/seed.d.ts.map +1 -0
- package/dist/cafe/seed.js +7 -0
- package/dist/cafe/seed.js.map +1 -0
- package/dist/cafe/server.d.ts +3 -0
- package/dist/cafe/server.d.ts.map +1 -0
- package/dist/cafe/server.js +3 -0
- package/dist/cafe/server.js.map +1 -0
- package/dist/cafe/types.d.ts +2 -0
- package/dist/cafe/types.d.ts.map +1 -0
- package/dist/cafe/types.js +31 -0
- package/dist/cafe/types.js.map +1 -0
- package/dist/canary/seed.d.ts +2 -0
- package/dist/canary/seed.d.ts.map +1 -0
- package/dist/canary/seed.js +7 -0
- package/dist/canary/seed.js.map +1 -0
- package/dist/canary/server.d.ts +4 -0
- package/dist/canary/server.d.ts.map +1 -0
- package/dist/canary/server.js +4 -0
- package/dist/canary/server.js.map +1 -0
- package/dist/canary/service.d.ts +2 -0
- package/dist/canary/service.d.ts.map +1 -0
- package/dist/canary/service.js +101 -0
- package/dist/canary/service.js.map +1 -0
- package/dist/canary/types.d.ts +9 -0
- package/dist/canary/types.d.ts.map +1 -0
- package/dist/canary/types.js +13 -0
- package/dist/canary/types.js.map +1 -0
- package/dist/doc/client.d.ts +3 -0
- package/dist/doc/client.d.ts.map +1 -0
- package/dist/doc/client.js +5 -0
- package/dist/doc/client.js.map +1 -0
- package/dist/doc/fs-codec.d.ts +2 -0
- package/dist/doc/fs-codec.d.ts.map +1 -0
- package/dist/doc/fs-codec.js +44 -0
- package/dist/doc/fs-codec.js.map +1 -0
- package/dist/doc/markdown.d.ts +13 -0
- package/dist/doc/markdown.d.ts.map +1 -0
- package/dist/doc/markdown.js +250 -0
- package/dist/doc/markdown.js.map +1 -0
- package/dist/doc/prefab.d.ts +2 -0
- package/dist/doc/prefab.d.ts.map +1 -0
- package/dist/doc/prefab.js +23 -0
- package/dist/doc/prefab.js.map +1 -0
- package/dist/doc/renderers.d.ts +2 -0
- package/dist/doc/renderers.d.ts.map +1 -0
- package/dist/doc/renderers.js +94 -0
- package/dist/doc/renderers.js.map +1 -0
- package/dist/doc/seed.d.ts +2 -0
- package/dist/doc/seed.d.ts.map +1 -0
- package/dist/doc/seed.js +9 -0
- package/dist/doc/seed.js.map +1 -0
- package/dist/doc/server.d.ts +6 -0
- package/dist/doc/server.d.ts.map +1 -0
- package/dist/doc/server.js +6 -0
- package/dist/doc/server.js.map +1 -0
- package/dist/doc/slash-command.d.ts +3 -0
- package/dist/doc/slash-command.d.ts.map +1 -0
- package/dist/doc/slash-command.js +123 -0
- package/dist/doc/slash-command.js.map +1 -0
- package/dist/doc/slash-menu.d.ts +15 -0
- package/dist/doc/slash-menu.d.ts.map +1 -0
- package/dist/doc/slash-menu.js +54 -0
- package/dist/doc/slash-menu.js.map +1 -0
- package/dist/doc/text.d.ts +2 -0
- package/dist/doc/text.d.ts.map +1 -0
- package/dist/doc/text.js +22 -0
- package/dist/doc/text.js.map +1 -0
- package/dist/doc/toolbar.d.ts +5 -0
- package/dist/doc/toolbar.d.ts.map +1 -0
- package/dist/doc/toolbar.js +15 -0
- package/dist/doc/toolbar.js.map +1 -0
- package/dist/doc/treenity-block-view.d.ts +2 -0
- package/dist/doc/treenity-block-view.d.ts.map +1 -0
- package/dist/doc/treenity-block-view.js +37 -0
- package/dist/doc/treenity-block-view.js.map +1 -0
- package/dist/doc/treenity-block.d.ts +3 -0
- package/dist/doc/treenity-block.d.ts.map +1 -0
- package/dist/doc/treenity-block.js +27 -0
- package/dist/doc/treenity-block.js.map +1 -0
- package/dist/doc/types.d.ts +2 -0
- package/dist/doc/types.d.ts.map +1 -0
- package/dist/doc/types.js +10 -0
- package/dist/doc/types.js.map +1 -0
- package/dist/launcher/client.d.ts +5 -0
- package/dist/launcher/client.d.ts.map +1 -0
- package/dist/launcher/client.js +5 -0
- package/dist/launcher/client.js.map +1 -0
- package/dist/launcher/icons.d.ts +2 -0
- package/dist/launcher/icons.d.ts.map +1 -0
- package/dist/launcher/icons.js +57 -0
- package/dist/launcher/icons.js.map +1 -0
- package/dist/launcher/seed.d.ts +2 -0
- package/dist/launcher/seed.d.ts.map +1 -0
- package/dist/launcher/seed.js +36 -0
- package/dist/launcher/seed.js.map +1 -0
- package/dist/launcher/server.d.ts +3 -0
- package/dist/launcher/server.d.ts.map +1 -0
- package/dist/launcher/server.js +3 -0
- package/dist/launcher/server.js.map +1 -0
- package/dist/launcher/types.d.ts +21 -0
- package/dist/launcher/types.d.ts.map +1 -0
- package/dist/launcher/types.js +47 -0
- package/dist/launcher/types.js.map +1 -0
- package/dist/launcher/view.d.ts +2 -0
- package/dist/launcher/view.d.ts.map +1 -0
- package/dist/launcher/view.js +187 -0
- package/dist/launcher/view.js.map +1 -0
- package/dist/launcher/widgets.d.ts +2 -0
- package/dist/launcher/widgets.d.ts.map +1 -0
- package/dist/launcher/widgets.js +73 -0
- package/dist/launcher/widgets.js.map +1 -0
- package/dist/mindmap/branch.d.ts +17 -0
- package/dist/mindmap/branch.d.ts.map +1 -0
- package/dist/mindmap/branch.js +47 -0
- package/dist/mindmap/branch.js.map +1 -0
- package/dist/mindmap/client.d.ts +3 -0
- package/dist/mindmap/client.d.ts.map +1 -0
- package/dist/mindmap/client.js +3 -0
- package/dist/mindmap/client.js.map +1 -0
- package/dist/mindmap/radial-tree.d.ts +14 -0
- package/dist/mindmap/radial-tree.d.ts.map +1 -0
- package/dist/mindmap/radial-tree.js +184 -0
- package/dist/mindmap/radial-tree.js.map +1 -0
- package/dist/mindmap/sidebar.d.ts +8 -0
- package/dist/mindmap/sidebar.d.ts.map +1 -0
- package/dist/mindmap/sidebar.js +24 -0
- package/dist/mindmap/sidebar.js.map +1 -0
- package/dist/mindmap/types.d.ts +8 -0
- package/dist/mindmap/types.d.ts.map +1 -0
- package/dist/mindmap/types.js +10 -0
- package/dist/mindmap/types.js.map +1 -0
- package/dist/mindmap/use-tree-data.d.ts +14 -0
- package/dist/mindmap/use-tree-data.d.ts.map +1 -0
- package/dist/mindmap/use-tree-data.js +95 -0
- package/dist/mindmap/use-tree-data.js.map +1 -0
- package/dist/mindmap/view.d.ts +3 -0
- package/dist/mindmap/view.d.ts.map +1 -0
- package/dist/mindmap/view.js +141 -0
- package/dist/mindmap/view.js.map +1 -0
- package/dist/sensor-demo/client.d.ts +2 -0
- package/dist/sensor-demo/client.d.ts.map +1 -0
- package/dist/sensor-demo/client.js +2 -0
- package/dist/sensor-demo/client.js.map +1 -0
- package/dist/sensor-demo/server.d.ts +2 -0
- package/dist/sensor-demo/server.d.ts.map +1 -0
- package/dist/sensor-demo/server.js +2 -0
- package/dist/sensor-demo/server.js.map +1 -0
- package/dist/sensor-demo/service.d.ts +2 -0
- package/dist/sensor-demo/service.d.ts.map +1 -0
- package/dist/sensor-demo/service.js +27 -0
- package/dist/sensor-demo/service.js.map +1 -0
- package/dist/sensor-demo/types.d.ts +15 -0
- package/dist/sensor-demo/types.d.ts.map +1 -0
- package/dist/sensor-demo/types.js +18 -0
- package/dist/sensor-demo/types.js.map +1 -0
- package/dist/sensor-demo/view.d.ts +2 -0
- package/dist/sensor-demo/view.d.ts.map +1 -0
- package/dist/sensor-demo/view.js +33 -0
- package/dist/sensor-demo/view.js.map +1 -0
- package/dist/sensor-generator/action.d.ts +2 -0
- package/dist/sensor-generator/action.d.ts.map +1 -0
- package/dist/sensor-generator/action.js +23 -0
- package/dist/sensor-generator/action.js.map +1 -0
- package/dist/sensor-generator/client.d.ts +2 -0
- package/dist/sensor-generator/client.d.ts.map +1 -0
- package/dist/sensor-generator/client.js +2 -0
- package/dist/sensor-generator/client.js.map +1 -0
- package/dist/sensor-generator/server.d.ts +2 -0
- package/dist/sensor-generator/server.d.ts.map +1 -0
- package/dist/sensor-generator/server.js +2 -0
- package/dist/sensor-generator/server.js.map +1 -0
- package/dist/sensor-generator/view.d.ts +2 -0
- package/dist/sensor-generator/view.d.ts.map +1 -0
- package/dist/sensor-generator/view.js +64 -0
- package/dist/sensor-generator/view.js.map +1 -0
- package/dist/sim/client.d.ts +2 -0
- package/dist/sim/client.d.ts.map +1 -0
- package/dist/sim/client.js +2 -0
- package/dist/sim/client.js.map +1 -0
- package/dist/sim/seed.d.ts +2 -0
- package/dist/sim/seed.d.ts.map +1 -0
- package/dist/sim/seed.js +50 -0
- package/dist/sim/seed.js.map +1 -0
- package/dist/sim/server.d.ts +3 -0
- package/dist/sim/server.d.ts.map +1 -0
- package/dist/sim/server.js +3 -0
- package/dist/sim/server.js.map +1 -0
- package/dist/sim/service.d.ts +4 -0
- package/dist/sim/service.d.ts.map +1 -0
- package/dist/sim/service.js +528 -0
- package/dist/sim/service.js.map +1 -0
- package/dist/sim/types.d.ts +63 -0
- package/dist/sim/types.d.ts.map +1 -0
- package/dist/sim/types.js +57 -0
- package/dist/sim/types.js.map +1 -0
- package/dist/sim/view.d.ts +2 -0
- package/dist/sim/view.d.ts.map +1 -0
- package/dist/sim/view.js +205 -0
- package/dist/sim/view.js.map +1 -0
- package/dist/table/client.d.ts +4 -0
- package/dist/table/client.d.ts.map +1 -0
- package/dist/table/client.js +4 -0
- package/dist/table/client.js.map +1 -0
- package/dist/table/edit.d.ts +2 -0
- package/dist/table/edit.d.ts.map +1 -0
- package/dist/table/edit.js +115 -0
- package/dist/table/edit.js.map +1 -0
- package/dist/table/server.d.ts +2 -0
- package/dist/table/server.d.ts.map +1 -0
- package/dist/table/server.js +2 -0
- package/dist/table/server.js.map +1 -0
- package/dist/table/types.d.ts +18 -0
- package/dist/table/types.d.ts.map +1 -0
- package/dist/table/types.js +13 -0
- package/dist/table/types.js.map +1 -0
- package/dist/table/use-debounced-sync.d.ts +8 -0
- package/dist/table/use-debounced-sync.d.ts.map +1 -0
- package/dist/table/use-debounced-sync.js +56 -0
- package/dist/table/use-debounced-sync.js.map +1 -0
- package/dist/table/view.d.ts +2 -0
- package/dist/table/view.d.ts.map +1 -0
- package/dist/table/view.js +199 -0
- package/dist/table/view.js.map +1 -0
- package/dist/tasks/server.d.ts +2 -0
- package/dist/tasks/server.d.ts.map +1 -0
- package/dist/tasks/server.js +2 -0
- package/dist/tasks/server.js.map +1 -0
- package/dist/tasks/types.d.ts +22 -0
- package/dist/tasks/types.d.ts.map +1 -0
- package/dist/tasks/types.js +34 -0
- package/dist/tasks/types.js.map +1 -0
- package/dist/three/client.d.ts +2 -0
- package/dist/three/client.d.ts.map +1 -0
- package/dist/three/client.js +2 -0
- package/dist/three/client.js.map +1 -0
- package/dist/three/seed.d.ts +2 -0
- package/dist/three/seed.d.ts.map +1 -0
- package/dist/three/seed.js +45 -0
- package/dist/three/seed.js.map +1 -0
- package/dist/three/server.d.ts +3 -0
- package/dist/three/server.d.ts.map +1 -0
- package/dist/three/server.js +3 -0
- package/dist/three/server.js.map +1 -0
- package/dist/three/types.d.ts +178 -0
- package/dist/three/types.d.ts.map +1 -0
- package/dist/three/types.js +209 -0
- package/dist/three/types.js.map +1 -0
- package/dist/three/view.d.ts +2 -0
- package/dist/three/view.d.ts.map +1 -0
- package/dist/three/view.js +307 -0
- package/dist/three/view.js.map +1 -0
- package/dist/todo/client.d.ts +3 -0
- package/dist/todo/client.d.ts.map +1 -0
- package/dist/todo/client.js +3 -0
- package/dist/todo/client.js.map +1 -0
- package/dist/todo/seed.d.ts +2 -0
- package/dist/todo/seed.d.ts.map +1 -0
- package/dist/todo/seed.js +8 -0
- package/dist/todo/seed.js.map +1 -0
- package/dist/todo/server.d.ts +3 -0
- package/dist/todo/server.d.ts.map +1 -0
- package/dist/todo/server.js +3 -0
- package/dist/todo/server.js.map +1 -0
- package/dist/todo/types.d.ts +15 -0
- package/dist/todo/types.d.ts.map +1 -0
- package/dist/todo/types.js +29 -0
- package/dist/todo/types.js.map +1 -0
- package/dist/todo/view.d.ts +2 -0
- package/dist/todo/view.d.ts.map +1 -0
- package/dist/todo/view.js +27 -0
- package/dist/todo/view.js.map +1 -0
- package/dist/whisper/client.d.ts +2 -0
- package/dist/whisper/client.d.ts.map +1 -0
- package/dist/whisper/client.js +2 -0
- package/dist/whisper/client.js.map +1 -0
- package/dist/whisper/inbox.d.ts +2 -0
- package/dist/whisper/inbox.d.ts.map +1 -0
- package/dist/whisper/inbox.js +50 -0
- package/dist/whisper/inbox.js.map +1 -0
- package/dist/whisper/route.d.ts +10 -0
- package/dist/whisper/route.d.ts.map +1 -0
- package/dist/whisper/route.js +154 -0
- package/dist/whisper/route.js.map +1 -0
- package/dist/whisper/seed.d.ts +2 -0
- package/dist/whisper/seed.d.ts.map +1 -0
- package/dist/whisper/seed.js +14 -0
- package/dist/whisper/seed.js.map +1 -0
- package/dist/whisper/server.d.ts +5 -0
- package/dist/whisper/server.d.ts.map +1 -0
- package/dist/whisper/server.js +5 -0
- package/dist/whisper/server.js.map +1 -0
- package/dist/whisper/service.d.ts +2 -0
- package/dist/whisper/service.d.ts.map +1 -0
- package/dist/whisper/service.js +26 -0
- package/dist/whisper/service.js.map +1 -0
- package/dist/whisper/types.d.ts +38 -0
- package/dist/whisper/types.d.ts.map +1 -0
- package/dist/whisper/types.js +45 -0
- package/dist/whisper/types.js.map +1 -0
- package/dist/whisper/view.d.ts +2 -0
- package/dist/whisper/view.d.ts.map +1 -0
- package/dist/whisper/view.js +40 -0
- package/dist/whisper/view.js.map +1 -0
- package/doc/CLAUDE.md +49 -0
- package/doc/client.ts +5 -0
- package/doc/editor.css +283 -0
- package/doc/fs-codec.test.ts +119 -0
- package/doc/fs-codec.ts +50 -0
- package/doc/markdown.test.ts +152 -0
- package/doc/markdown.ts +284 -0
- package/doc/prefab.ts +26 -0
- package/doc/renderers.tsx +126 -0
- package/doc/seed.ts +10 -0
- package/doc/server.ts +5 -0
- package/doc/slash-command.ts +136 -0
- package/doc/slash-menu.tsx +91 -0
- package/doc/text.ts +20 -0
- package/doc/toolbar.tsx +86 -0
- package/doc/treenity-block-view.tsx +116 -0
- package/doc/treenity-block.ts +31 -0
- package/doc/types.ts +10 -0
- package/launcher/client.ts +4 -0
- package/launcher/icons.tsx +234 -0
- package/launcher/launcher.css +64 -0
- package/launcher/seed.ts +41 -0
- package/launcher/server.ts +2 -0
- package/launcher/types.ts +53 -0
- package/launcher/view.tsx +401 -0
- package/launcher/widgets.tsx +171 -0
- package/mindmap/branch.tsx +163 -0
- package/mindmap/client.ts +2 -0
- package/mindmap/mindmap.css +243 -0
- package/mindmap/sidebar.tsx +127 -0
- package/mindmap/types.ts +10 -0
- package/mindmap/view.tsx +247 -0
- package/package.json +75 -0
- package/sensor-demo/CLAUDE.md +3 -0
- package/sensor-demo/client.ts +1 -0
- package/sensor-demo/server.ts +1 -0
- package/sensor-demo/service.ts +27 -0
- package/sensor-demo/types.ts +20 -0
- package/sensor-demo/view.tsx +64 -0
- package/sensor-generator/CLAUDE.md +3 -0
- package/sensor-generator/action.ts +28 -0
- package/sensor-generator/client.ts +1 -0
- package/sensor-generator/server.ts +1 -0
- package/sensor-generator/view.tsx +107 -0
- package/sim/CLAUDE.md +16 -0
- package/sim/client.ts +1 -0
- package/sim/seed.ts +55 -0
- package/sim/server.ts +2 -0
- package/sim/service.ts +594 -0
- package/sim/sim.test.ts +282 -0
- package/sim/types.ts +87 -0
- package/sim/view.tsx +446 -0
- package/table/client.ts +3 -0
- package/table/edit.tsx +241 -0
- package/table/server.ts +1 -0
- package/table/types.ts +22 -0
- package/table/use-debounced-sync.ts +67 -0
- package/table/view.tsx +339 -0
- package/tasks/CLAUDE.md +6 -0
- package/tasks/server.ts +1 -0
- package/tasks/types.ts +36 -0
- package/three/CLAUDE.md +6 -0
- package/three/client.ts +1 -0
- package/three/seed.ts +54 -0
- package/three/server.ts +2 -0
- package/three/types.ts +238 -0
- package/three/view.tsx +453 -0
- package/todo/client.ts +2 -0
- package/todo/seed.ts +9 -0
- package/todo/server.ts +2 -0
- package/todo/types.ts +32 -0
- package/todo/view.tsx +67 -0
- package/whisper/CLAUDE.md +16 -0
- package/whisper/client.ts +1 -0
- package/whisper/inbox.ts +54 -0
- package/whisper/route.ts +182 -0
- package/whisper/seed.ts +15 -0
- package/whisper/server.ts +4 -0
- package/whisper/service.ts +29 -0
- package/whisper/types.ts +51 -0
- package/whisper/view.tsx +81 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
// Page layout — DnD sortable list of actions
|
|
2
|
+
// Data model: command & positions are TOP-LEVEL node fields (not in a component).
|
|
3
|
+
// getComponent(node, PageConfig) returns the node itself when node.$type === 'brahman.page',
|
|
4
|
+
// so data must be on the node, not nested in node.page.
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
closestCenter,
|
|
8
|
+
DndContext,
|
|
9
|
+
type DragEndEvent,
|
|
10
|
+
KeyboardSensor,
|
|
11
|
+
PointerSensor,
|
|
12
|
+
useSensor,
|
|
13
|
+
useSensors,
|
|
14
|
+
} from '@dnd-kit/core';
|
|
15
|
+
import {
|
|
16
|
+
arrayMove,
|
|
17
|
+
SortableContext,
|
|
18
|
+
sortableKeyboardCoordinates,
|
|
19
|
+
useSortable,
|
|
20
|
+
verticalListSortingStrategy,
|
|
21
|
+
} from '@dnd-kit/sortable';
|
|
22
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
23
|
+
import type { NodeData } from '@treenity/core';
|
|
24
|
+
import { getDefaults } from '@treenity/core/comp';
|
|
25
|
+
import { Button } from '@treenity/react/components/ui/button';
|
|
26
|
+
import { Input } from '@treenity/react/components/ui/input';
|
|
27
|
+
import { Render } from '@treenity/react/context';
|
|
28
|
+
import { set, useChildren, useNavigate, usePath } from '@treenity/react/hooks';
|
|
29
|
+
import { trpc } from '@treenity/react/trpc';
|
|
30
|
+
import { ChevronDown, ChevronRight, GripVertical, Plus, Trash2 } from 'lucide-react';
|
|
31
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
32
|
+
import { ACTION_TYPES } from '../types';
|
|
33
|
+
import { actionIcon, actionSummary } from './action-cards';
|
|
34
|
+
|
|
35
|
+
// ── Action palette dropdown ──
|
|
36
|
+
|
|
37
|
+
function ActionPalette({ onSelect }: { onSelect: (type: string) => void }) {
|
|
38
|
+
const [open, setOpen] = useState(false);
|
|
39
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<div className="relative" ref={ref}>
|
|
43
|
+
<Button variant="outline" size="sm" onClick={() => setOpen(!open)}>
|
|
44
|
+
<Plus className="h-4 w-4 mr-1" /> Add action
|
|
45
|
+
</Button>
|
|
46
|
+
|
|
47
|
+
{open && (
|
|
48
|
+
<div className="absolute left-0 top-full mt-1 z-50 w-56 bg-popover border border-border rounded-md shadow-md py-1">
|
|
49
|
+
{ACTION_TYPES.map(at => (
|
|
50
|
+
<button
|
|
51
|
+
key={at.type}
|
|
52
|
+
type="button"
|
|
53
|
+
className="w-full text-left px-3 py-2 text-sm hover:bg-accent flex items-center gap-2"
|
|
54
|
+
onClick={() => { onSelect(at.type); setOpen(false); }}
|
|
55
|
+
>
|
|
56
|
+
{actionIcon(at.type)}
|
|
57
|
+
{at.label}
|
|
58
|
+
</button>
|
|
59
|
+
))}
|
|
60
|
+
</div>
|
|
61
|
+
)}
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ── Sortable action card ──
|
|
67
|
+
|
|
68
|
+
function SortableAction({
|
|
69
|
+
node,
|
|
70
|
+
onRemove,
|
|
71
|
+
onSelect,
|
|
72
|
+
expanded,
|
|
73
|
+
onToggle,
|
|
74
|
+
}: {
|
|
75
|
+
node: NodeData;
|
|
76
|
+
onRemove: () => void;
|
|
77
|
+
onSelect: () => void;
|
|
78
|
+
expanded: boolean;
|
|
79
|
+
onToggle: () => void;
|
|
80
|
+
}) {
|
|
81
|
+
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: node.$path });
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<div
|
|
85
|
+
ref={setNodeRef}
|
|
86
|
+
style={{ transform: CSS.Transform.toString(transform), transition }}
|
|
87
|
+
className="bg-card border border-border rounded-md group hover:border-primary/50"
|
|
88
|
+
>
|
|
89
|
+
{/* Header row */}
|
|
90
|
+
<div
|
|
91
|
+
className="flex items-center gap-2 px-3 py-2 cursor-pointer"
|
|
92
|
+
onClick={onToggle}
|
|
93
|
+
>
|
|
94
|
+
<div {...attributes} {...listeners} className="cursor-grab text-muted-foreground hover:text-foreground"
|
|
95
|
+
onClick={e => e.stopPropagation()}>
|
|
96
|
+
<GripVertical className="h-4 w-4" />
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div className="text-muted-foreground">
|
|
100
|
+
{expanded
|
|
101
|
+
? <ChevronDown className="h-3.5 w-3.5" />
|
|
102
|
+
: <ChevronRight className="h-3.5 w-3.5" />}
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<div className="flex items-center gap-2 flex-1 min-w-0">
|
|
106
|
+
{actionIcon(node.$type)}
|
|
107
|
+
<span className="text-xs font-medium text-muted-foreground uppercase">
|
|
108
|
+
{ACTION_TYPES.find(a => a.type === node.$type)?.label ?? node.$type.split('.').at(-1)}
|
|
109
|
+
</span>
|
|
110
|
+
{!expanded && (
|
|
111
|
+
<span className="text-sm truncate text-foreground/60">{actionSummary(node)}</span>
|
|
112
|
+
)}
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<button
|
|
116
|
+
type="button"
|
|
117
|
+
onClick={e => { e.stopPropagation(); onSelect(); }}
|
|
118
|
+
className="text-muted-foreground hover:text-foreground text-[10px] opacity-0 group-hover:opacity-100"
|
|
119
|
+
title="Select in tree"
|
|
120
|
+
>
|
|
121
|
+
↗
|
|
122
|
+
</button>
|
|
123
|
+
|
|
124
|
+
<button
|
|
125
|
+
type="button"
|
|
126
|
+
onClick={e => { e.stopPropagation(); onRemove(); }}
|
|
127
|
+
className="opacity-0 group-hover:opacity-100 text-muted-foreground hover:text-destructive transition-opacity"
|
|
128
|
+
>
|
|
129
|
+
<Trash2 className="h-3.5 w-3.5" />
|
|
130
|
+
</button>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
{/* Inline editor */}
|
|
134
|
+
{expanded && (
|
|
135
|
+
<div className="px-3 pb-3 border-t border-border/50 pt-3">
|
|
136
|
+
<Render value={node} />
|
|
137
|
+
</div>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ── Page layout view (registered as 'brahman.page' react handler) ──
|
|
144
|
+
|
|
145
|
+
export function PageLayoutView({ value }: { value: NodeData }) {
|
|
146
|
+
const navigate = useNavigate();
|
|
147
|
+
const node = usePath(value.$path);
|
|
148
|
+
const actionsPath = value.$path + '/_actions';
|
|
149
|
+
const children = useChildren(actionsPath, { watch: true, watchNew: true });
|
|
150
|
+
const [collapsed, setCollapsed] = useState<Set<string>>(new Set());
|
|
151
|
+
|
|
152
|
+
// Read command & positions from node top-level (getComponent returns node itself)
|
|
153
|
+
const command = (node?.command as string) ?? '';
|
|
154
|
+
const positions: string[] = (node?.positions as string[]) ?? [];
|
|
155
|
+
|
|
156
|
+
// Debounced save: update local state immediately, persist after 400ms idle
|
|
157
|
+
const [localCommand, setLocalCommand] = useState(command);
|
|
158
|
+
const timerRef = useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
159
|
+
|
|
160
|
+
// Sync local state when node changes externally
|
|
161
|
+
useEffect(() => { setLocalCommand(command); }, [command]);
|
|
162
|
+
|
|
163
|
+
const saveNode = useCallback((patch: Record<string, unknown>) => {
|
|
164
|
+
if (!node) return;
|
|
165
|
+
// Strip any leftover 'page' component that shouldn't exist
|
|
166
|
+
const { page: _drop, ...clean } = node as NodeData & { page?: unknown };
|
|
167
|
+
set({ ...clean, ...patch } as NodeData);
|
|
168
|
+
}, [node]);
|
|
169
|
+
|
|
170
|
+
const debouncedSave = useCallback((patch: Record<string, unknown>) => {
|
|
171
|
+
clearTimeout(timerRef.current);
|
|
172
|
+
timerRef.current = setTimeout(() => saveNode(patch), 400);
|
|
173
|
+
}, [saveNode]);
|
|
174
|
+
|
|
175
|
+
// Cleanup timer on unmount
|
|
176
|
+
useEffect(() => () => clearTimeout(timerRef.current), []);
|
|
177
|
+
|
|
178
|
+
// Sort children by positions, append any untracked
|
|
179
|
+
const tracked = new Set(positions);
|
|
180
|
+
const sorted = [
|
|
181
|
+
...positions.map(p => children.find(c => c.$path === p)).filter((c): c is NodeData => !!c),
|
|
182
|
+
...children.filter(c => !tracked.has(c.$path) && c.$type?.startsWith('brahman.action.')),
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
const sensors = useSensors(
|
|
186
|
+
useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
|
|
187
|
+
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
function handleDragEnd(event: DragEndEvent) {
|
|
191
|
+
const { active, over } = event;
|
|
192
|
+
if (!over || active.id === over.id) return;
|
|
193
|
+
const oldIndex = sorted.findIndex(c => c.$path === active.id);
|
|
194
|
+
const newIndex = sorted.findIndex(c => c.$path === over.id);
|
|
195
|
+
if (oldIndex === -1 || newIndex === -1) return;
|
|
196
|
+
const reordered = arrayMove(sorted.map(c => c.$path), oldIndex, newIndex);
|
|
197
|
+
saveNode({ positions: reordered });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async function addAction(type: string) {
|
|
201
|
+
const id = Date.now().toString(36);
|
|
202
|
+
const childPath = `${actionsPath}/${id}`;
|
|
203
|
+
|
|
204
|
+
// Ensure _actions dir exists as a real node
|
|
205
|
+
await trpc.set.mutate({ node: { $path: actionsPath, $type: 'dir' } as NodeData });
|
|
206
|
+
|
|
207
|
+
const defaults = getDefaults(type);
|
|
208
|
+
|
|
209
|
+
// Data on the node directly (findActionComp returns node when $type matches)
|
|
210
|
+
await trpc.set.mutate({
|
|
211
|
+
node: { $path: childPath, $type: type, ...defaults } as NodeData,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
saveNode({ positions: [...positions, childPath] });
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function removeAction(path: string) {
|
|
218
|
+
await trpc.remove.mutate({ path });
|
|
219
|
+
saveNode({ positions: positions.filter(p => p !== path) });
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function selectAction(path: string) {
|
|
223
|
+
navigate(path);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return (
|
|
227
|
+
<div className="space-y-4 max-w-2xl">
|
|
228
|
+
{/* Page command */}
|
|
229
|
+
<div className="flex items-center gap-3">
|
|
230
|
+
<label className="text-sm font-medium text-muted-foreground w-20">Command</label>
|
|
231
|
+
<Input
|
|
232
|
+
className="flex-1 font-mono"
|
|
233
|
+
placeholder="/command..."
|
|
234
|
+
value={localCommand}
|
|
235
|
+
onChange={e => {
|
|
236
|
+
setLocalCommand(e.target.value);
|
|
237
|
+
debouncedSave({ command: e.target.value });
|
|
238
|
+
}}
|
|
239
|
+
onBlur={() => {
|
|
240
|
+
// Flush pending save on blur
|
|
241
|
+
clearTimeout(timerRef.current);
|
|
242
|
+
if (localCommand !== command) saveNode({ command: localCommand });
|
|
243
|
+
}}
|
|
244
|
+
/>
|
|
245
|
+
</div>
|
|
246
|
+
|
|
247
|
+
{/* Actions list */}
|
|
248
|
+
<div className="space-y-1.5">
|
|
249
|
+
<div className="text-[11px] font-semibold text-muted-foreground uppercase tracking-wider">
|
|
250
|
+
Actions ({sorted.length})
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
|
|
254
|
+
<SortableContext items={sorted.map(c => c.$path)} strategy={verticalListSortingStrategy}>
|
|
255
|
+
<div className="space-y-1">
|
|
256
|
+
{sorted.map(child => (
|
|
257
|
+
<SortableAction
|
|
258
|
+
key={child.$path}
|
|
259
|
+
node={child}
|
|
260
|
+
onRemove={() => removeAction(child.$path)}
|
|
261
|
+
onSelect={() => selectAction(child.$path)}
|
|
262
|
+
expanded={!collapsed.has(child.$path)}
|
|
263
|
+
onToggle={() => setCollapsed(prev => {
|
|
264
|
+
const next = new Set(prev);
|
|
265
|
+
if (next.has(child.$path)) next.delete(child.$path);
|
|
266
|
+
else next.add(child.$path);
|
|
267
|
+
return next;
|
|
268
|
+
})}
|
|
269
|
+
/>
|
|
270
|
+
))}
|
|
271
|
+
</div>
|
|
272
|
+
</SortableContext>
|
|
273
|
+
</DndContext>
|
|
274
|
+
|
|
275
|
+
{sorted.length === 0 && (
|
|
276
|
+
<div className="text-sm text-muted-foreground text-center py-8 border border-dashed border-border rounded-md">
|
|
277
|
+
No actions yet. Add one below.
|
|
278
|
+
</div>
|
|
279
|
+
)}
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<ActionPalette onSelect={addAction} />
|
|
283
|
+
</div>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// TString editor — tabbed multilingual text input
|
|
2
|
+
// Used by message, question, and menu button editors
|
|
3
|
+
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
import type { TString } from '../types';
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
value: TString;
|
|
9
|
+
onChange: (next: TString) => void;
|
|
10
|
+
langs?: string[];
|
|
11
|
+
rows?: number;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function TStringInput({ value = {}, onChange, langs = ['ru', 'en'], rows = 3, placeholder }: Props) {
|
|
16
|
+
const [activeLang, setActiveLang] = useState(langs[0] ?? 'ru');
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<div>
|
|
20
|
+
<div className="flex gap-0.5 mb-1">
|
|
21
|
+
{langs.map(lang => (
|
|
22
|
+
<button
|
|
23
|
+
key={lang}
|
|
24
|
+
type="button"
|
|
25
|
+
onClick={() => setActiveLang(lang)}
|
|
26
|
+
className={`px-2.5 py-1 text-xs font-medium uppercase rounded-t transition-colors ${
|
|
27
|
+
activeLang === lang
|
|
28
|
+
? 'bg-muted text-foreground'
|
|
29
|
+
: 'text-muted-foreground hover:text-foreground'
|
|
30
|
+
}`}
|
|
31
|
+
>
|
|
32
|
+
{lang}
|
|
33
|
+
{value[lang] ? '' : ' *'}
|
|
34
|
+
</button>
|
|
35
|
+
))}
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<textarea
|
|
39
|
+
className="w-full px-3 py-2 text-sm bg-background border border-border rounded-md resize-none outline-none focus:border-primary transition-colors"
|
|
40
|
+
rows={rows}
|
|
41
|
+
placeholder={placeholder ?? `Text (${activeLang})`}
|
|
42
|
+
value={value[activeLang] ?? ''}
|
|
43
|
+
onChange={e => onChange({ ...value, [activeLang]: e.target.value })}
|
|
44
|
+
/>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Single-line TString input */
|
|
50
|
+
export function TStringLineInput({ value = {}, onChange, langs = ['ru', 'en'], placeholder }: Omit<Props, 'rows'>) {
|
|
51
|
+
const [activeLang, setActiveLang] = useState(langs[0] ?? 'ru');
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<div className="flex items-center gap-1 border border-border rounded-md overflow-hidden bg-background">
|
|
55
|
+
{langs.map(lang => (
|
|
56
|
+
<button
|
|
57
|
+
key={lang}
|
|
58
|
+
type="button"
|
|
59
|
+
onClick={() => setActiveLang(lang)}
|
|
60
|
+
className={`px-2 py-1 text-[10px] font-medium uppercase shrink-0 ${
|
|
61
|
+
activeLang === lang ? 'text-primary' : 'text-muted-foreground'
|
|
62
|
+
}`}
|
|
63
|
+
>
|
|
64
|
+
{lang}
|
|
65
|
+
</button>
|
|
66
|
+
))}
|
|
67
|
+
|
|
68
|
+
<input
|
|
69
|
+
type="text"
|
|
70
|
+
className="flex-1 px-2 py-1.5 text-sm outline-none bg-transparent"
|
|
71
|
+
placeholder={placeholder ?? `Text (${activeLang})`}
|
|
72
|
+
value={value[activeLang] ?? ''}
|
|
73
|
+
onChange={e => onChange({ ...value, [activeLang]: e.target.value })}
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Get first non-empty TString value for display */
|
|
80
|
+
export function tstringPreview(ts: TString | undefined, maxLen = 40): string {
|
|
81
|
+
if (!ts) return '';
|
|
82
|
+
const text = ts.ru || ts.en || Object.values(ts).find(v => v) || '';
|
|
83
|
+
return text.length > maxLen ? text.slice(0, maxLen) + '...' : text;
|
|
84
|
+
}
|
package/cafe/CLAUDE.md
ADDED
package/cafe/seed.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type NodeData } from '@treenity/core';
|
|
2
|
+
import { registerPrefab } from '@treenity/core/mod';
|
|
3
|
+
|
|
4
|
+
registerPrefab('cafe', 'seed', [
|
|
5
|
+
{ $path: 'cafe', $type: 'dir' },
|
|
6
|
+
{ $path: 'cafe/contact', $type: 'cafe.contact', recipient: 'owner@cafe.example' },
|
|
7
|
+
{ $path: 'cafe/pages', $type: 'dir' },
|
|
8
|
+
] as NodeData[]);
|
package/cafe/server.ts
ADDED
package/cafe/types.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Cafe use cases — domain types for a cafe landing page
|
|
2
|
+
import { registerType } from '@treenity/core/comp';
|
|
3
|
+
|
|
4
|
+
/** Mail delivery settings */
|
|
5
|
+
class CafeMailService {
|
|
6
|
+
/** @title SMTP host */
|
|
7
|
+
host = 'smtp.example.com';
|
|
8
|
+
/** @title Port */
|
|
9
|
+
port = 587;
|
|
10
|
+
/** @title Sender address @format email */
|
|
11
|
+
from = '';
|
|
12
|
+
}
|
|
13
|
+
registerType('cafe.mail', CafeMailService);
|
|
14
|
+
|
|
15
|
+
/** Contact form use case — receives form submissions, logs them */
|
|
16
|
+
class CafeContact {
|
|
17
|
+
/** @title Recipient @format email */
|
|
18
|
+
recipient = '';
|
|
19
|
+
/** @title Mail service */
|
|
20
|
+
mailService?: CafeMailService;
|
|
21
|
+
/** @title Last submission */
|
|
22
|
+
lastSubmission = '';
|
|
23
|
+
|
|
24
|
+
/** @description Submit contact form — validates and logs submission */
|
|
25
|
+
submit(data: { name: string; email: string; message: string }) {
|
|
26
|
+
if (!data.name || !data.email) throw new Error('Name and email required');
|
|
27
|
+
// For now: store last submission on the node. Later: create child node, send notification.
|
|
28
|
+
this.lastSubmission = JSON.stringify({ ...data, at: new Date().toISOString() });
|
|
29
|
+
console.log(`[cafe:contact] → ${this.recipient}: ${data.name} <${data.email}> "${data.message}"`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
registerType('cafe.contact', CafeContact);
|
package/canary/seed.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type NodeData } from '@treenity/core';
|
|
2
|
+
import { registerPrefab } from '@treenity/core/mod';
|
|
3
|
+
|
|
4
|
+
registerPrefab('canary', 'seed', [
|
|
5
|
+
{ $path: 'canary', $type: 'dir' },
|
|
6
|
+
{ $path: 'canary/runner', $type: 'canary.runner' },
|
|
7
|
+
{ $path: 'sys/autostart/canary', $type: 'ref', $ref: '/canary/runner' },
|
|
8
|
+
] as NodeData[]);
|
package/canary/server.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Canary smoke tests — run at server startup to verify core mechanics
|
|
2
|
+
|
|
3
|
+
import { getComponent, type NodeData, register } from '@treenity/core';
|
|
4
|
+
import { executeAction } from '@treenity/core/server/actions';
|
|
5
|
+
import '@treenity/core/contexts/service';
|
|
6
|
+
import { CanaryItem } from './types';
|
|
7
|
+
|
|
8
|
+
const PREFIX = '[canary]';
|
|
9
|
+
|
|
10
|
+
register('canary.runner', 'service', async (node, ctx) => {
|
|
11
|
+
const { store } = ctx;
|
|
12
|
+
const basePath = node.$path;
|
|
13
|
+
const itemPath = `${basePath}/test-item`;
|
|
14
|
+
let passed = 0;
|
|
15
|
+
let failed = 0;
|
|
16
|
+
|
|
17
|
+
async function assert(name: string, fn: () => Promise<void>) {
|
|
18
|
+
try {
|
|
19
|
+
await fn();
|
|
20
|
+
passed++;
|
|
21
|
+
} catch (err) {
|
|
22
|
+
failed++;
|
|
23
|
+
console.error(`${PREFIX} FAIL: ${name}`, err instanceof Error ? err.message : err);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ── 1. Create node via store.set ──
|
|
28
|
+
await assert('store.set creates node', async () => {
|
|
29
|
+
await store.set({
|
|
30
|
+
$path: itemPath,
|
|
31
|
+
$type: 'canary.item',
|
|
32
|
+
value: 0,
|
|
33
|
+
label: 'canary',
|
|
34
|
+
} as NodeData);
|
|
35
|
+
const n = await store.get(itemPath);
|
|
36
|
+
if (!n) throw new Error('node not found after set');
|
|
37
|
+
if (n.$type !== 'canary.item') throw new Error(`wrong type: ${n.$type}`);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ── 2. getComponent resolves node-level type ──
|
|
41
|
+
await assert('getComponent resolves main component', async () => {
|
|
42
|
+
const n = await store.get(itemPath);
|
|
43
|
+
const comp = getComponent(n!, CanaryItem);
|
|
44
|
+
if (!comp) throw new Error('getComponent returned undefined');
|
|
45
|
+
if (comp.value !== 0) throw new Error(`wrong value: ${comp.value}`);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// ── 3. Action mutates state (Immer draft) ──
|
|
49
|
+
await assert('action increment mutates via Immer', async () => {
|
|
50
|
+
await executeAction(store, itemPath, 'canary.item', undefined, 'increment', undefined);
|
|
51
|
+
const n = await store.get(itemPath);
|
|
52
|
+
if ((n as any).value !== 1) throw new Error(`expected 1, got ${(n as any).value}`);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ── 4. Action with parameters ──
|
|
56
|
+
await assert('action setLabel accepts params', async () => {
|
|
57
|
+
await executeAction(store, itemPath, 'canary.item', undefined, 'setLabel', { label: 'updated' });
|
|
58
|
+
const n = await store.get(itemPath);
|
|
59
|
+
if ((n as any).label !== 'updated') throw new Error(`expected "updated", got ${(n as any).label}`);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// ── 5. getChildren finds child nodes ──
|
|
63
|
+
await assert('getChildren returns created node', async () => {
|
|
64
|
+
const { items } = await store.getChildren(basePath);
|
|
65
|
+
const found = items.find(c => c.$path === itemPath);
|
|
66
|
+
if (!found) throw new Error('child not found');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// ── 6. ACL — node with deny should strip data ──
|
|
70
|
+
await assert('ACL deny strips node', async () => {
|
|
71
|
+
const aclPath = `${basePath}/acl-test`;
|
|
72
|
+
await store.set({
|
|
73
|
+
$path: aclPath,
|
|
74
|
+
$type: 'canary.item',
|
|
75
|
+
$acl: [{ g: 'public', p: 0 }],
|
|
76
|
+
value: 42,
|
|
77
|
+
label: 'secret',
|
|
78
|
+
} as NodeData);
|
|
79
|
+
const n = await store.get(aclPath);
|
|
80
|
+
// Node exists in store (we're running as system, no ACL filtering here)
|
|
81
|
+
if (!n) throw new Error('acl node not found');
|
|
82
|
+
if ((n as any).$acl?.[0]?.p !== 0) throw new Error('acl not set');
|
|
83
|
+
await store.remove(aclPath);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// ── 7. Remove node ──
|
|
87
|
+
await assert('store.remove deletes node', async () => {
|
|
88
|
+
await store.remove(itemPath);
|
|
89
|
+
const n = await store.get(itemPath);
|
|
90
|
+
if (n) throw new Error('node still exists after remove');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Report
|
|
94
|
+
if (failed > 0) {
|
|
95
|
+
console.error(`${PREFIX} ${passed} passed, ${failed} FAILED`);
|
|
96
|
+
} else {
|
|
97
|
+
console.log(`${PREFIX} ${passed} checks passed`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return { stop: async () => {} };
|
|
101
|
+
});
|
package/canary/types.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { registerType } from '@treenity/core/comp';
|
|
2
|
+
|
|
3
|
+
export class CanaryItem {
|
|
4
|
+
value = 0;
|
|
5
|
+
label = 'canary';
|
|
6
|
+
|
|
7
|
+
increment() {
|
|
8
|
+
this.value += 1;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
setLabel(data: { label: string }) {
|
|
12
|
+
this.label = data.label;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
registerType('canary.item', CanaryItem);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../board/client.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../board/client.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../board/seed.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Board seed — kanban at /board, typed columns with query mounts
|
|
2
|
+
import { registerPrefab } from '@treenity/core/mod';
|
|
3
|
+
registerPrefab('board', 'seed', [
|
|
4
|
+
{ $path: 'board', $type: 'board.kanban' },
|
|
5
|
+
{ $path: 'board/data', $type: 'dir' },
|
|
6
|
+
// Typed columns — each is a board.column + query mount
|
|
7
|
+
{ $path: 'board/backlog', $type: 'board.column', label: 'Backlog', color: 'border-zinc-400', order: 0,
|
|
8
|
+
mount: { $type: 't.mount.query' },
|
|
9
|
+
query: { $type: 'query', source: '/board/data', match: { status: 'backlog' } } },
|
|
10
|
+
{ $path: 'board/todo', $type: 'board.column', label: 'To Do', color: 'border-blue-400', order: 1,
|
|
11
|
+
mount: { $type: 't.mount.query' },
|
|
12
|
+
query: { $type: 'query', source: '/board/data', match: { status: 'todo' } } },
|
|
13
|
+
{ $path: 'board/doing', $type: 'board.column', label: 'In Progress', color: 'border-yellow-400', order: 2,
|
|
14
|
+
mount: { $type: 't.mount.query' },
|
|
15
|
+
query: { $type: 'query', source: '/board/data', match: { status: 'doing' } } },
|
|
16
|
+
{ $path: 'board/review', $type: 'board.column', label: 'Review', color: 'border-purple-400', order: 3,
|
|
17
|
+
mount: { $type: 't.mount.query' },
|
|
18
|
+
query: { $type: 'query', source: '/board/data', match: { status: 'review' } } },
|
|
19
|
+
{ $path: 'board/done', $type: 'board.column', label: 'Done', color: 'border-green-400', order: 4,
|
|
20
|
+
mount: { $type: 't.mount.query' },
|
|
21
|
+
query: { $type: 'query', source: '/board/data', match: { status: 'done' } } },
|
|
22
|
+
], undefined, { tier: 'core' });
|
|
23
|
+
//# sourceMappingURL=seed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.js","sourceRoot":"","sources":["../../board/seed.ts"],"names":[],"mappings":"AAAA,iEAAiE;AAGjE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE;IAC9B,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE;IACzC,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE;IAErC,uDAAuD;IACvD,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC;QACnG,KAAK,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE;QACjC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE;IAClF,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC;QAC9F,KAAK,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE;QACjC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;IAC/E,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC;QACvG,KAAK,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE;QACjC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;IAChF,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC;QACnG,KAAK,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE;QACjC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE;IACjF,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;QAC9F,KAAK,EAAE,EAAE,KAAK,EAAE,eAAe,EAAE;QACjC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;CAClE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../board/server.ts"],"names":[],"mappings":"AAGA,OAAO,SAAS,CAAC;AACjB,OAAO,QAAQ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../board/server.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,wEAAwE;AAExE,OAAO,SAAS,CAAC;AACjB,OAAO,QAAQ,CAAC"}
|