@treenity/mods 3.0.1 → 3.0.2
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/view.tsx +1 -1
- package/brahman/helpers.ts +7 -7
- package/brahman/service.ts +24 -24
- package/brahman/types.ts +21 -21
- package/brahman/views/action-cards.tsx +33 -23
- package/brahman/views/bot-view.tsx +3 -2
- package/brahman/views/chat-editor.tsx +119 -124
- package/brahman/views/menu-editor.tsx +75 -89
- package/brahman/views/page-layout.tsx +10 -8
- package/brahman/views/tstring-input.tsx +25 -15
- package/canary/service.ts +18 -18
- package/dist/board/view.js +1 -1
- package/dist/board/view.js.map +1 -1
- package/dist/brahman/helpers.d.ts +1 -1
- package/dist/brahman/helpers.d.ts.map +1 -1
- package/dist/brahman/helpers.js +6 -6
- package/dist/brahman/helpers.js.map +1 -1
- package/dist/brahman/service.js +24 -24
- package/dist/brahman/service.js.map +1 -1
- package/dist/brahman/types.d.ts +1 -1
- package/dist/brahman/types.d.ts.map +1 -1
- package/dist/brahman/types.js +21 -21
- package/dist/brahman/types.js.map +1 -1
- package/dist/brahman/views/action-cards.d.ts.map +1 -1
- package/dist/brahman/views/action-cards.js +7 -4
- package/dist/brahman/views/action-cards.js.map +1 -1
- package/dist/brahman/views/bot-view.d.ts.map +1 -1
- package/dist/brahman/views/bot-view.js +2 -1
- package/dist/brahman/views/bot-view.js.map +1 -1
- package/dist/brahman/views/chat-editor.d.ts.map +1 -1
- package/dist/brahman/views/chat-editor.js +27 -18
- package/dist/brahman/views/chat-editor.js.map +1 -1
- package/dist/brahman/views/menu-editor.d.ts.map +1 -1
- package/dist/brahman/views/menu-editor.js +12 -16
- package/dist/brahman/views/menu-editor.js.map +1 -1
- package/dist/brahman/views/page-layout.d.ts.map +1 -1
- package/dist/brahman/views/page-layout.js +1 -1
- package/dist/brahman/views/page-layout.js.map +1 -1
- package/dist/brahman/views/tstring-input.d.ts.map +1 -1
- package/dist/brahman/views/tstring-input.js +7 -3
- package/dist/brahman/views/tstring-input.js.map +1 -1
- package/dist/canary/service.js +18 -18
- package/dist/canary/service.js.map +1 -1
- package/dist/doc/fs-codec.js +1 -1
- package/dist/doc/fs-codec.js.map +1 -1
- package/dist/doc/renderers.d.ts.map +1 -1
- package/dist/doc/renderers.js +2 -1
- package/dist/doc/renderers.js.map +1 -1
- package/dist/doc/toolbar.d.ts.map +1 -1
- package/dist/doc/toolbar.js +5 -5
- package/dist/doc/toolbar.js.map +1 -1
- package/dist/launcher/types.js +2 -2
- package/dist/launcher/types.js.map +1 -1
- package/dist/launcher/view.js +2 -2
- package/dist/launcher/view.js.map +1 -1
- package/dist/mindmap/branch.d.ts +10 -0
- package/dist/mindmap/branch.d.ts.map +1 -1
- package/dist/mindmap/branch.js +42 -9
- package/dist/mindmap/branch.js.map +1 -1
- package/dist/mindmap/sidebar.d.ts.map +1 -1
- package/dist/mindmap/sidebar.js +4 -3
- package/dist/mindmap/sidebar.js.map +1 -1
- package/dist/mindmap/view.d.ts.map +1 -1
- package/dist/mindmap/view.js +35 -4
- package/dist/mindmap/view.js.map +1 -1
- package/dist/sensor-demo/service.js +6 -5
- package/dist/sensor-demo/service.js.map +1 -1
- package/dist/sensor-generator/action.js +1 -1
- package/dist/sensor-generator/action.js.map +1 -1
- package/dist/sim/service.js +41 -41
- package/dist/sim/service.js.map +1 -1
- package/dist/table/view.js.map +1 -1
- package/dist/todo/types.js +2 -2
- package/dist/todo/types.js.map +1 -1
- package/dist/todo/view.js +6 -4
- package/dist/todo/view.js.map +1 -1
- package/dist/whisper/inbox.js +3 -3
- package/dist/whisper/inbox.js.map +1 -1
- package/dist/whisper/route.d.ts +1 -1
- package/dist/whisper/route.d.ts.map +1 -1
- package/dist/whisper/route.js +13 -13
- package/dist/whisper/route.js.map +1 -1
- package/doc/CLAUDE.md +1 -1
- package/doc/fs-codec.ts +1 -1
- package/doc/renderers.tsx +4 -3
- package/doc/toolbar.tsx +12 -9
- package/launcher/types.ts +2 -2
- package/launcher/view.tsx +12 -8
- package/mindmap/branch.tsx +121 -22
- package/mindmap/mindmap.css +52 -0
- package/mindmap/sidebar.tsx +9 -6
- package/mindmap/view.tsx +40 -4
- package/package.json +27 -3
- package/sensor-demo/service.ts +6 -5
- package/sensor-generator/action.ts +1 -1
- package/sim/service.ts +41 -41
- package/table/view.tsx +7 -2
- package/todo/types.ts +2 -2
- package/todo/view.tsx +9 -10
- package/whisper/inbox.ts +3 -3
- package/whisper/route.ts +13 -13
- package/board/board.test.ts +0 -212
- package/brahman/brahman.test.ts +0 -855
- package/doc/fs-codec.test.ts +0 -119
- package/doc/markdown.test.ts +0 -152
- package/sim/sim.test.ts +0 -282
package/dist/todo/view.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { register } from '@treenity/core';
|
|
3
3
|
import { useChildren, usePath } from '@treenity/react/hooks';
|
|
4
|
+
import { Button } from '@treenity/react/ui/button';
|
|
5
|
+
import { Input } from '@treenity/react/ui/input';
|
|
4
6
|
import { useState } from 'react';
|
|
5
7
|
import { TodoItem, TodoList } from './types';
|
|
6
8
|
function TodoListView({ value }) {
|
|
@@ -13,14 +15,14 @@ function TodoListView({ value }) {
|
|
|
13
15
|
await list.add({ title: draft });
|
|
14
16
|
setDraft('');
|
|
15
17
|
};
|
|
16
|
-
return (_jsxs("div", { className: "max-w-md mx-auto p-4", children: [_jsx("h2", { className: "text-xl font-bold mb-4", children: list.title }), _jsxs("div", { className: "flex gap-2 mb-4", children: [_jsx(
|
|
18
|
+
return (_jsxs("div", { className: "max-w-md mx-auto p-4", children: [_jsx("h2", { className: "text-xl font-bold mb-4", children: list.title }), _jsxs("div", { className: "flex gap-2 mb-4", children: [_jsx(Input, { className: "flex-1", placeholder: "What needs to be done?", value: draft, onChange: e => setDraft(e.target.value), onKeyDown: e => e.key === 'Enter' && handleAdd() }), _jsx(Button, { size: "sm", onClick: handleAdd, children: "Add" })] }), _jsx("ul", { className: "space-y-1", children: children.map(child => (_jsx(TodoItemRow, { value: child }, child.$path))) })] }));
|
|
17
19
|
}
|
|
18
20
|
function TodoItemRow({ value }) {
|
|
19
21
|
const item = usePath(value.$path, TodoItem);
|
|
20
|
-
return (_jsxs("li", { className: "flex items-center gap-2 px-3 py-2 rounded\n hover:bg-
|
|
22
|
+
return (_jsxs("li", { className: "flex items-center gap-2 px-3 py-2 rounded\n hover:bg-muted cursor-pointer", onClick: () => item.toggle(), children: [_jsx("span", { className: `w-4 h-4 rounded border flex items-center
|
|
21
23
|
justify-center text-xs ${item.done
|
|
22
|
-
? 'bg-
|
|
23
|
-
: 'border-
|
|
24
|
+
? 'bg-primary border-primary text-primary-foreground'
|
|
25
|
+
: 'border-input'}`, children: item.done ? '✓' : '' }), _jsx("span", { className: item.done ? 'line-through text-muted-foreground' : '', children: item.title })] }));
|
|
24
26
|
}
|
|
25
27
|
register('todo.list', 'react', TodoListView);
|
|
26
28
|
register('todo.item', 'react', TodoItemRow);
|
package/dist/todo/view.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../todo/view.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAiB,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE7C,SAAS,YAAY,CAAC,EAAE,KAAK,EAAuB;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEvC,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE;QAC3B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;YAAE,OAAO;QAC1B,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACjC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACf,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,sBAAsB,aACnC,aAAI,SAAS,EAAC,wBAAwB,YAAE,IAAI,CAAC,KAAK,GAAM,EAExD,eAAK,SAAS,EAAC,iBAAiB,aAC9B,
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../todo/view.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAiB,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE7C,SAAS,YAAY,CAAC,EAAE,KAAK,EAAuB;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEvC,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE;QAC3B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;YAAE,OAAO;QAC1B,MAAM,IAAI,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;QACjC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACf,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAC,sBAAsB,aACnC,aAAI,SAAS,EAAC,wBAAwB,YAAE,IAAI,CAAC,KAAK,GAAM,EAExD,eAAK,SAAS,EAAC,iBAAiB,aAC9B,KAAC,KAAK,IACJ,SAAS,EAAC,QAAQ,EAClB,WAAW,EAAC,wBAAwB,EACpC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACvC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,OAAO,IAAI,SAAS,EAAE,GAChD,EACF,KAAC,MAAM,IAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,SAAS,oBAAc,IAC9C,EAEN,aAAI,SAAS,EAAC,WAAW,YACtB,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CACrB,KAAC,WAAW,IAAmB,KAAK,EAAE,KAAK,IAAzB,KAAK,CAAC,KAAK,CAAkB,CAChD,CAAC,GACC,IACD,CACP,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,KAAK,EAAuB;IACjD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAE5C,OAAO,CACL,cACE,SAAS,EAAC,kFACsB,EAChC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,aAE5B,eAAM,SAAS,EAAE;iCACU,IAAI,CAAC,IAAI;oBAChC,CAAC,CAAC,mDAAmD;oBACrD,CAAC,CAAC,cAAc,EAAE,YACnB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAChB,EACP,eAAM,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC,EAAE,YACnE,IAAI,CAAC,KAAK,GACN,IACJ,CACN,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,WAAW,EAAE,OAAO,EAAE,YAAmB,CAAC,CAAC;AACpD,QAAQ,CAAC,WAAW,EAAE,OAAO,EAAE,WAAkB,CAAC,CAAC"}
|
package/dist/whisper/inbox.js
CHANGED
|
@@ -15,7 +15,7 @@ register('whisper.inbox', 'service', async (node, ctx) => {
|
|
|
15
15
|
throw new Error(`missing config on ${node.$path}`);
|
|
16
16
|
const sent = new Set();
|
|
17
17
|
// Mark existing COMPLETED transcriptions as already processed
|
|
18
|
-
const { items } = await ctx.
|
|
18
|
+
const { items } = await ctx.tree.getChildren(config.source);
|
|
19
19
|
for (const child of items) {
|
|
20
20
|
if (child.$type !== 'whisper.transcription')
|
|
21
21
|
continue;
|
|
@@ -26,7 +26,7 @@ register('whisper.inbox', 'service', async (node, ctx) => {
|
|
|
26
26
|
const unsub = ctx.subscribe(config.source, (event) => {
|
|
27
27
|
if (event.type !== 'set' && event.type !== 'patch')
|
|
28
28
|
return;
|
|
29
|
-
ctx.
|
|
29
|
+
ctx.tree.get(event.path).then(async (n) => {
|
|
30
30
|
if (!n || n.$type !== 'whisper.transcription')
|
|
31
31
|
return;
|
|
32
32
|
if (sent.has(n.$path))
|
|
@@ -37,7 +37,7 @@ register('whisper.inbox', 'service', async (node, ctx) => {
|
|
|
37
37
|
sent.add(n.$path);
|
|
38
38
|
const taskId = `t-${Date.now()}`;
|
|
39
39
|
const taskPath = `${config.target}/tasks/${taskId}`;
|
|
40
|
-
await ctx.
|
|
40
|
+
await ctx.tree.set(createNode(taskPath, 'agent.task', {
|
|
41
41
|
prompt: text,
|
|
42
42
|
status: 'pending',
|
|
43
43
|
createdAt: Date.now(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../whisper/inbox.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,8EAA8E;AAE9E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAiB,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEpD,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;AAEnE,SAAS,OAAO,CAAC,IAAc;IAC7B,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC7C,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAC3E,CAAC;AAED,QAAQ,CAAC,eAAe,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;IACvD,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAEhE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,8DAA8D;IAC9D,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../../whisper/inbox.ts"],"names":[],"mappings":"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"}
|
package/dist/whisper/route.d.ts
CHANGED
|
@@ -6,5 +6,5 @@ export type WhisperRouteConfig = {
|
|
|
6
6
|
language: string;
|
|
7
7
|
audioDir: string;
|
|
8
8
|
};
|
|
9
|
-
export declare function createWhisperHandler(cfg: WhisperRouteConfig): (req: IncomingMessage, res: ServerResponse,
|
|
9
|
+
export declare function createWhisperHandler(cfg: WhisperRouteConfig): (req: IncomingMessage, res: ServerResponse, tree: Tree) => Promise<void>;
|
|
10
10
|
//# sourceMappingURL=route.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../whisper/route.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAGhD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAwDtE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,kBAAkB,IAM5C,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../whisper/route.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAGhD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAwDtE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,kBAAkB,IAM5C,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,IAAI,mBAuGpE"}
|
package/dist/whisper/route.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// POST ?id=channel-id with audio body → create node immediately, transcribe in background, update node
|
|
3
3
|
import { pipeline } from '@huggingface/transformers';
|
|
4
4
|
import { createNode } from '@treenity/core';
|
|
5
|
-
import {
|
|
5
|
+
import { newComponent } from '@treenity/core/comp';
|
|
6
6
|
import { execFile } from 'node:child_process';
|
|
7
7
|
import { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
8
8
|
import { join, resolve } from 'node:path';
|
|
@@ -58,7 +58,7 @@ export function createWhisperHandler(cfg) {
|
|
|
58
58
|
const audioDir = resolve(cfg.audioDir);
|
|
59
59
|
// Pre-warm the pipeline
|
|
60
60
|
getTranscriber(cfg.model);
|
|
61
|
-
return async (req, res,
|
|
61
|
+
return async (req, res, tree) => {
|
|
62
62
|
if (req.method !== 'POST') {
|
|
63
63
|
return respond(res, 405, { error: 'Method not allowed' });
|
|
64
64
|
}
|
|
@@ -89,17 +89,17 @@ export function createWhisperHandler(cfg) {
|
|
|
89
89
|
await writeFile(filePath, body);
|
|
90
90
|
// Ensure {servicePath}/{id} dir exists
|
|
91
91
|
const idDirPath = `${cfg.nodePath}/${id}`;
|
|
92
|
-
if (!(await
|
|
93
|
-
await
|
|
94
|
-
checklist:
|
|
92
|
+
if (!(await tree.get(idDirPath))) {
|
|
93
|
+
await tree.set(createNode(idDirPath, 'whisper.channel', {}, {
|
|
94
|
+
checklist: newComponent(WhisperChecklist, {}),
|
|
95
95
|
}));
|
|
96
96
|
}
|
|
97
97
|
// 1. Create node immediately with audio — appears in tree right away
|
|
98
98
|
const nodePath = `${idDirPath}/${noteId}`;
|
|
99
99
|
const node = createNode(nodePath, 'whisper.transcription', {}, {
|
|
100
|
-
audio:
|
|
101
|
-
text:
|
|
102
|
-
meta:
|
|
100
|
+
audio: newComponent(WhisperAudio, { filename, size: body.length, mime }),
|
|
101
|
+
text: newComponent(WhisperText, { content: '...' }),
|
|
102
|
+
meta: newComponent(WhisperMeta, {
|
|
103
103
|
model: cfg.model,
|
|
104
104
|
language: cfg.language,
|
|
105
105
|
duration: 0,
|
|
@@ -107,7 +107,7 @@ export function createWhisperHandler(cfg) {
|
|
|
107
107
|
transcribedAt: Date.now(),
|
|
108
108
|
}),
|
|
109
109
|
});
|
|
110
|
-
await
|
|
110
|
+
await tree.set(node);
|
|
111
111
|
console.log(`[whisper] ${filename} → ${nodePath} (processing...)`);
|
|
112
112
|
// 2. Respond immediately — client sees the node path
|
|
113
113
|
respond(res, 200, { path: nodePath, status: 'processing' });
|
|
@@ -126,18 +126,18 @@ export function createWhisperHandler(cfg) {
|
|
|
126
126
|
const duration = outputChunks?.length
|
|
127
127
|
? (outputChunks[outputChunks.length - 1].timestamp[1] ?? 0)
|
|
128
128
|
: 0;
|
|
129
|
-
const updated = await
|
|
129
|
+
const updated = await tree.get(nodePath);
|
|
130
130
|
if (!updated)
|
|
131
131
|
return;
|
|
132
|
-
updated.text =
|
|
133
|
-
updated.meta =
|
|
132
|
+
updated.text = newComponent(WhisperText, { content: text });
|
|
133
|
+
updated.meta = newComponent(WhisperMeta, {
|
|
134
134
|
model: cfg.model,
|
|
135
135
|
language: cfg.language,
|
|
136
136
|
duration,
|
|
137
137
|
segments: outputChunks?.length ?? 0,
|
|
138
138
|
transcribedAt: Date.now(),
|
|
139
139
|
});
|
|
140
|
-
await
|
|
140
|
+
await tree.set(updated);
|
|
141
141
|
console.log(`[whisper] ${nodePath} done (${outputChunks?.length ?? 0} seg, ${duration}s)`);
|
|
142
142
|
})
|
|
143
143
|
.catch((err) => console.error(`[whisper] ${nodePath} transcription failed:`, err))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../whisper/route.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,uGAAuG;AAEvG,OAAO,EAA2C,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC9F,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../../whisper/route.ts"],"names":[],"mappings":"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"}
|
package/doc/CLAUDE.md
CHANGED
|
@@ -32,7 +32,7 @@ Tiptap WYSIWYG with:
|
|
|
32
32
|
## Files
|
|
33
33
|
|
|
34
34
|
```
|
|
35
|
-
types.ts — DocPage class +
|
|
35
|
+
types.ts — DocPage class + registerType
|
|
36
36
|
fs-codec.ts — text/markdown decode/encode for FS store
|
|
37
37
|
markdown.ts — mdToTiptap / tiptapToMd converters
|
|
38
38
|
text.ts — text context (Tiptap → plain text/markdown)
|
package/doc/fs-codec.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Markdown file ↔ doc.page node codec for FS
|
|
1
|
+
// Markdown file ↔ doc.page node codec for FS tree
|
|
2
2
|
// Decode: .md file → doc.page node (title from first H1, content as Tiptap JSON)
|
|
3
3
|
// Encode: doc.page node → .md file (Tiptap JSON → markdown)
|
|
4
4
|
// Paths are extensionless — encode appends .md
|
package/doc/renderers.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import TaskList from '@tiptap/extension-task-list';
|
|
|
8
8
|
import { EditorContent, useEditor } from '@tiptap/react';
|
|
9
9
|
import StarterKit from '@tiptap/starter-kit';
|
|
10
10
|
import { register } from '@treenity/core';
|
|
11
|
+
import { Input } from '@treenity/react/ui/input';
|
|
11
12
|
import { common, createLowlight } from 'lowlight';
|
|
12
13
|
import { useCallback, useEffect, useRef } from 'react';
|
|
13
14
|
import { SlashCommand } from './slash-command';
|
|
@@ -70,15 +71,15 @@ function DocPageView({ value, onChange }: BlockProps) {
|
|
|
70
71
|
{/* Title */}
|
|
71
72
|
<div className="mb-5">
|
|
72
73
|
{onChange ? (
|
|
73
|
-
<
|
|
74
|
+
<Input
|
|
74
75
|
type="text"
|
|
75
76
|
value={value.title || ''}
|
|
76
77
|
onChange={(e) => onChange({ ...value, title: e.target.value })}
|
|
77
78
|
placeholder="Untitled"
|
|
78
|
-
className="w-full text-2xl font-semibold tracking-tight bg-transparent border-none outline-none text-
|
|
79
|
+
className="w-full text-2xl font-semibold tracking-tight bg-transparent border-none shadow-none outline-none text-foreground placeholder:text-muted-foreground/50"
|
|
79
80
|
/>
|
|
80
81
|
) : (
|
|
81
|
-
value.title && <h1 className="text-2xl font-semibold tracking-tight text-
|
|
82
|
+
value.title && <h1 className="text-2xl font-semibold tracking-tight text-foreground">{value.title}</h1>
|
|
82
83
|
)}
|
|
83
84
|
</div>
|
|
84
85
|
|
package/doc/toolbar.tsx
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { Editor } from '@tiptap/react';
|
|
2
|
+
import { cn } from '@treenity/react/lib/utils';
|
|
3
|
+
import { Button } from '@treenity/react/ui/button';
|
|
2
4
|
import {
|
|
3
5
|
Bold,
|
|
4
6
|
Code,
|
|
@@ -17,28 +19,29 @@ function Btn({ active, onClick, title, children }: {
|
|
|
17
19
|
active?: boolean; onClick: () => void; title: string; children: React.ReactNode;
|
|
18
20
|
}) {
|
|
19
21
|
return (
|
|
20
|
-
<
|
|
22
|
+
<Button
|
|
23
|
+
variant="ghost"
|
|
24
|
+
size="sm"
|
|
21
25
|
onMouseDown={(e) => { e.preventDefault(); onClick(); }}
|
|
22
26
|
title={title}
|
|
23
|
-
className={
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}`}
|
|
27
|
+
className={cn(
|
|
28
|
+
'h-7 w-7 p-0',
|
|
29
|
+
active && 'bg-accent text-accent-foreground',
|
|
30
|
+
)}
|
|
28
31
|
>
|
|
29
32
|
{children}
|
|
30
|
-
</
|
|
33
|
+
</Button>
|
|
31
34
|
);
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
function Sep() {
|
|
35
|
-
return <span className="w-px h-4 bg-
|
|
38
|
+
return <span className="w-px h-4 bg-border mx-1 flex-shrink-0" />;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
export function Toolbar({ editor }: { editor: Editor }) {
|
|
39
42
|
const sz = 14;
|
|
40
43
|
return (
|
|
41
|
-
<div className="doc-toolbar flex items-center flex-wrap gap-0.5 px-1 py-1 mb-2 border-b border-
|
|
44
|
+
<div className="doc-toolbar flex items-center flex-wrap gap-0.5 px-1 py-1 mb-2 border-b border-border">
|
|
42
45
|
<Btn active={editor.isActive('bold')} onClick={() => editor.chain().focus().toggleBold().run()} title="Bold (⌘B)">
|
|
43
46
|
<Bold size={sz} />
|
|
44
47
|
</Btn>
|
package/launcher/types.ts
CHANGED
|
@@ -17,7 +17,7 @@ export class Launcher {
|
|
|
17
17
|
const id = data.id || data.path.split('/').at(-1) || Date.now().toString(36);
|
|
18
18
|
const refPath = `${ctx.node.$path}/${id}`;
|
|
19
19
|
|
|
20
|
-
await ctx.
|
|
20
|
+
await ctx.tree.set({ $path: refPath, $type: 'ref', $ref: data.path } as NodeData);
|
|
21
21
|
|
|
22
22
|
// Auto-place in layout as 1×1
|
|
23
23
|
const items: { i: string; x: number; y: number; w: number; h: number }[] = JSON.parse(this.layout || '[]');
|
|
@@ -37,7 +37,7 @@ export class Launcher {
|
|
|
37
37
|
async removeApp(data: { /** Child id (last path segment) */ id: string }) {
|
|
38
38
|
if (!data.id?.trim()) throw new Error('id required');
|
|
39
39
|
const ctx = getCtx();
|
|
40
|
-
await ctx.
|
|
40
|
+
await ctx.tree.remove(`${ctx.node.$path}/${data.id}`);
|
|
41
41
|
|
|
42
42
|
const items: { i: string }[] = JSON.parse(this.layout || '[]');
|
|
43
43
|
this.layout = JSON.stringify(items.filter(it => it.i !== data.id));
|
package/launcher/view.tsx
CHANGED
|
@@ -51,22 +51,26 @@ function EditOverlay({
|
|
|
51
51
|
}) {
|
|
52
52
|
return (
|
|
53
53
|
<>
|
|
54
|
-
<
|
|
55
|
-
|
|
54
|
+
<Button
|
|
55
|
+
variant="ghost"
|
|
56
|
+
size="sm"
|
|
57
|
+
className="launcher-btn absolute -right-1 -top-1 z-10 h-5 w-5 rounded-full bg-red-700 p-0 hover:bg-red-600"
|
|
56
58
|
onClick={(e) => { e.stopPropagation(); onRemove(); }}
|
|
57
59
|
onMouseDown={(e) => e.stopPropagation()}
|
|
58
60
|
>
|
|
59
61
|
<X className="h-3 w-3 text-white" />
|
|
60
|
-
</
|
|
62
|
+
</Button>
|
|
61
63
|
|
|
62
64
|
<DropdownMenu>
|
|
63
65
|
<DropdownMenuTrigger asChild>
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
+
<Button
|
|
67
|
+
variant="ghost"
|
|
68
|
+
size="sm"
|
|
69
|
+
className="launcher-btn absolute -left-1 -top-1 z-10 h-auto min-w-5 rounded-full bg-blue-600 px-1.5 py-0.5 text-[9px] font-medium text-white hover:bg-blue-500"
|
|
66
70
|
onMouseDown={(e) => e.stopPropagation()}
|
|
67
71
|
>
|
|
68
72
|
{contextLabel(ctx)}
|
|
69
|
-
</
|
|
73
|
+
</Button>
|
|
70
74
|
</DropdownMenuTrigger>
|
|
71
75
|
<DropdownMenuContent align="start" className="min-w-24">
|
|
72
76
|
{CONTEXTS.map((c) => (
|
|
@@ -112,8 +116,8 @@ function AppItem({
|
|
|
112
116
|
|
|
113
117
|
if (!target) {
|
|
114
118
|
return (
|
|
115
|
-
<div className="flex h-full w-full items-center justify-center rounded-2xl bg-
|
|
116
|
-
<span className="text-xs text-
|
|
119
|
+
<div className="flex h-full w-full items-center justify-center rounded-2xl bg-muted/50">
|
|
120
|
+
<span className="text-xs text-muted-foreground">...</span>
|
|
117
121
|
</div>
|
|
118
122
|
);
|
|
119
123
|
}
|
package/mindmap/branch.tsx
CHANGED
|
@@ -3,19 +3,30 @@
|
|
|
3
3
|
|
|
4
4
|
import type { NodeData } from '@treenity/core';
|
|
5
5
|
import { useChildren } from '@treenity/react/hooks';
|
|
6
|
-
import { createContext, useContext } from 'react';
|
|
6
|
+
import { createContext, useContext, useEffect, useRef } from 'react';
|
|
7
|
+
|
|
8
|
+
export type EditingAt = {
|
|
9
|
+
parentPath: string;
|
|
10
|
+
side: 'left' | 'right';
|
|
11
|
+
color: string;
|
|
12
|
+
} | null;
|
|
7
13
|
|
|
8
14
|
export type MindMapState = {
|
|
9
15
|
expanded: Set<string>;
|
|
10
16
|
selectedPath: string | null;
|
|
17
|
+
editingAt: EditingAt;
|
|
11
18
|
onToggle: (path: string) => void;
|
|
12
19
|
onSelect: (path: string) => void;
|
|
20
|
+
onAddChild: (parentPath: string, side: 'left' | 'right', color: string) => void;
|
|
21
|
+
onCommitAdd: (parentPath: string, name: string) => void;
|
|
22
|
+
onCancelAdd: () => void;
|
|
23
|
+
onDelete: (path: string) => void;
|
|
13
24
|
};
|
|
14
25
|
|
|
15
26
|
export const MindMapCtx = createContext<MindMapState>(null!);
|
|
16
27
|
|
|
17
28
|
const LEVEL_W = 200;
|
|
18
|
-
const SPACING =
|
|
29
|
+
const SPACING = 40;
|
|
19
30
|
|
|
20
31
|
function basename(path: string): string {
|
|
21
32
|
if (path === '/') return '/';
|
|
@@ -41,7 +52,7 @@ type BranchProps = {
|
|
|
41
52
|
};
|
|
42
53
|
|
|
43
54
|
export function MindMapBranch({ node, side, color, depth }: BranchProps) {
|
|
44
|
-
const { expanded, selectedPath, onToggle, onSelect } = useContext(MindMapCtx);
|
|
55
|
+
const { expanded, selectedPath, onToggle, onSelect, onAddChild } = useContext(MindMapCtx);
|
|
45
56
|
const isExpanded = expanded.has(node.$path);
|
|
46
57
|
const isLeft = side === 'left';
|
|
47
58
|
const isSelected = selectedPath === node.$path;
|
|
@@ -50,8 +61,7 @@ export function MindMapBranch({ node, side, color, depth }: BranchProps) {
|
|
|
50
61
|
const strokeW = Math.max(1.5, 3 - depth * 0.4);
|
|
51
62
|
|
|
52
63
|
return (
|
|
53
|
-
<g>
|
|
54
|
-
{/* Click = expand/collapse */}
|
|
64
|
+
<g className="mm-branch">
|
|
55
65
|
<g
|
|
56
66
|
className={`mm-node${isSelected ? ' mm-node-selected' : ''}`}
|
|
57
67
|
onClick={() => onToggle(node.$path)}
|
|
@@ -60,9 +70,9 @@ export function MindMapBranch({ node, side, color, depth }: BranchProps) {
|
|
|
60
70
|
{/* Dot */}
|
|
61
71
|
<circle r={isSelected ? 5 : 3.5} fill={color} className="mm-dot" />
|
|
62
72
|
|
|
63
|
-
{/* Label */}
|
|
73
|
+
{/* Label — offset from dot to avoid overlap with child curves */}
|
|
64
74
|
<text
|
|
65
|
-
x={isLeft ? -
|
|
75
|
+
x={isLeft ? -14 : 14}
|
|
66
76
|
textAnchor={isLeft ? 'end' : 'start'}
|
|
67
77
|
dominantBaseline="central"
|
|
68
78
|
className="mm-label"
|
|
@@ -74,7 +84,7 @@ export function MindMapBranch({ node, side, color, depth }: BranchProps) {
|
|
|
74
84
|
{/* Type tag */}
|
|
75
85
|
{type && depth <= 2 && (
|
|
76
86
|
<text
|
|
77
|
-
x={isLeft ? -
|
|
87
|
+
x={isLeft ? -14 - name.length * 7.5 - 6 : 14 + name.length * 7.5 + 6}
|
|
78
88
|
textAnchor={isLeft ? 'end' : 'start'}
|
|
79
89
|
dominantBaseline="central"
|
|
80
90
|
className="mm-type-tag"
|
|
@@ -86,14 +96,24 @@ export function MindMapBranch({ node, side, color, depth }: BranchProps) {
|
|
|
86
96
|
|
|
87
97
|
{/* Hit area */}
|
|
88
98
|
<rect
|
|
89
|
-
x={isLeft ? -
|
|
90
|
-
y={-
|
|
91
|
-
width={name.length * 8 +
|
|
92
|
-
height={
|
|
99
|
+
x={isLeft ? -14 - name.length * 8 : -6}
|
|
100
|
+
y={-16}
|
|
101
|
+
width={name.length * 8 + 24}
|
|
102
|
+
height={32}
|
|
93
103
|
fill="transparent"
|
|
94
104
|
/>
|
|
95
105
|
</g>
|
|
96
106
|
|
|
107
|
+
{/* "+" add child button — visible on hover */}
|
|
108
|
+
<g
|
|
109
|
+
className="mm-add-btn"
|
|
110
|
+
transform={`translate(${isLeft ? -14 - name.length * 7.5 - 20 : 14 + name.length * 7.5 + 20},0)`}
|
|
111
|
+
onClick={e => { e.stopPropagation(); onAddChild(node.$path, side, color); }}
|
|
112
|
+
>
|
|
113
|
+
<circle r={9} className="mm-add-bg" />
|
|
114
|
+
<text textAnchor="middle" dominantBaseline="central" className="mm-add-icon">+</text>
|
|
115
|
+
</g>
|
|
116
|
+
|
|
97
117
|
{/* Children (only fetched when expanded) */}
|
|
98
118
|
{isExpanded && (
|
|
99
119
|
<BranchChildren
|
|
@@ -108,6 +128,61 @@ export function MindMapBranch({ node, side, color, depth }: BranchProps) {
|
|
|
108
128
|
);
|
|
109
129
|
}
|
|
110
130
|
|
|
131
|
+
// Inline input for naming new nodes
|
|
132
|
+
function InlineInput({ x, y, side, onCommit, onCancel }: {
|
|
133
|
+
x: number;
|
|
134
|
+
y: number;
|
|
135
|
+
side: 'left' | 'right';
|
|
136
|
+
onCommit: (name: string) => void;
|
|
137
|
+
onCancel: () => void;
|
|
138
|
+
}) {
|
|
139
|
+
const ref = useRef<HTMLInputElement>(null);
|
|
140
|
+
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
// Focus after foreignObject mounts
|
|
143
|
+
setTimeout(() => ref.current?.focus(), 50);
|
|
144
|
+
}, []);
|
|
145
|
+
|
|
146
|
+
const handleKey = (e: React.KeyboardEvent) => {
|
|
147
|
+
e.stopPropagation();
|
|
148
|
+
if (e.key === 'Enter') {
|
|
149
|
+
const val = ref.current?.value.trim();
|
|
150
|
+
if (val) onCommit(val);
|
|
151
|
+
else onCancel();
|
|
152
|
+
}
|
|
153
|
+
if (e.key === 'Escape') onCancel();
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const handleBlur = () => {
|
|
157
|
+
const val = ref.current?.value.trim();
|
|
158
|
+
if (val) onCommit(val);
|
|
159
|
+
else onCancel();
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const isLeft = side === 'left';
|
|
163
|
+
const inputW = 140;
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<g transform={`translate(${x},${y})`}>
|
|
167
|
+
<circle r={3.5} fill="var(--accent)" />
|
|
168
|
+
<foreignObject
|
|
169
|
+
x={isLeft ? -inputW - 14 : 14}
|
|
170
|
+
y={-12}
|
|
171
|
+
width={inputW}
|
|
172
|
+
height={24}
|
|
173
|
+
>
|
|
174
|
+
<input
|
|
175
|
+
ref={ref}
|
|
176
|
+
className="mm-inline-input"
|
|
177
|
+
placeholder="node name..."
|
|
178
|
+
onKeyDown={handleKey}
|
|
179
|
+
onBlur={handleBlur}
|
|
180
|
+
/>
|
|
181
|
+
</foreignObject>
|
|
182
|
+
</g>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
111
186
|
type ChildrenProps = {
|
|
112
187
|
path: string;
|
|
113
188
|
side: 'left' | 'right';
|
|
@@ -117,17 +192,22 @@ type ChildrenProps = {
|
|
|
117
192
|
};
|
|
118
193
|
|
|
119
194
|
function BranchChildren({ path, side, color, depth, strokeW }: ChildrenProps) {
|
|
195
|
+
const { editingAt, onCommitAdd, onCancelAdd } = useContext(MindMapCtx);
|
|
120
196
|
const children = useChildren(path, { watch: true, watchNew: true });
|
|
121
|
-
if (children.length === 0) return null;
|
|
122
197
|
|
|
123
198
|
const isLeft = side === 'left';
|
|
124
199
|
const dx = isLeft ? -LEVEL_W : LEVEL_W;
|
|
125
|
-
const
|
|
200
|
+
const isEditing = editingAt?.parentPath === path;
|
|
201
|
+
const totalCount = children.length + (isEditing ? 1 : 0);
|
|
202
|
+
|
|
203
|
+
if (totalCount === 0) return null;
|
|
204
|
+
|
|
205
|
+
const totalH = (totalCount - 1) * SPACING;
|
|
126
206
|
const startY = -totalH / 2;
|
|
127
207
|
|
|
128
208
|
return (
|
|
129
209
|
<>
|
|
130
|
-
{/* Curves
|
|
210
|
+
{/* Curves to existing children */}
|
|
131
211
|
{children.map((child, i) => {
|
|
132
212
|
const cy = startY + i * SPACING;
|
|
133
213
|
return (
|
|
@@ -144,20 +224,39 @@ function BranchChildren({ path, side, color, depth, strokeW }: ChildrenProps) {
|
|
|
144
224
|
);
|
|
145
225
|
})}
|
|
146
226
|
|
|
147
|
-
{/*
|
|
227
|
+
{/* Curve to new node slot */}
|
|
228
|
+
{isEditing && (
|
|
229
|
+
<path
|
|
230
|
+
d={sCurve(dx, startY + children.length * SPACING)}
|
|
231
|
+
fill="none"
|
|
232
|
+
stroke="var(--accent)"
|
|
233
|
+
strokeWidth={strokeW}
|
|
234
|
+
strokeOpacity={0.5}
|
|
235
|
+
strokeLinecap="round"
|
|
236
|
+
strokeDasharray="6 4"
|
|
237
|
+
/>
|
|
238
|
+
)}
|
|
239
|
+
|
|
240
|
+
{/* Existing child nodes */}
|
|
148
241
|
{children.map((child, i) => {
|
|
149
242
|
const cy = startY + i * SPACING;
|
|
150
243
|
return (
|
|
151
244
|
<g key={child.$path} transform={`translate(${dx},${cy})`}>
|
|
152
|
-
<MindMapBranch
|
|
153
|
-
node={child}
|
|
154
|
-
side={side}
|
|
155
|
-
color={color}
|
|
156
|
-
depth={depth + 1}
|
|
157
|
-
/>
|
|
245
|
+
<MindMapBranch node={child} side={side} color={color} depth={depth + 1} />
|
|
158
246
|
</g>
|
|
159
247
|
);
|
|
160
248
|
})}
|
|
249
|
+
|
|
250
|
+
{/* Inline input for new node */}
|
|
251
|
+
{isEditing && (
|
|
252
|
+
<InlineInput
|
|
253
|
+
x={dx}
|
|
254
|
+
y={startY + children.length * SPACING}
|
|
255
|
+
side={side}
|
|
256
|
+
onCommit={name => onCommitAdd(path, name)}
|
|
257
|
+
onCancel={onCancelAdd}
|
|
258
|
+
/>
|
|
259
|
+
)}
|
|
161
260
|
</>
|
|
162
261
|
);
|
|
163
262
|
}
|