@dxos/plugin-conductor 0.12.0-next-73daef452f1464b62efdbca75fb0067c1066f264 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PLUGIN.mdl +73 -20
- package/dist/lib/capabilities.browser.mjs +20 -0
- package/dist/lib/capabilities.browser.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +1 -3
- package/dist/lib/capabilities.mjs.map +1 -1
- package/dist/lib/capabilities.node.mjs.map +1 -1
- package/dist/lib/capabilities.tauri.mjs +20 -0
- package/dist/lib/capabilities.tauri.mjs.map +1 -0
- package/dist/lib/capabilities.workerd.mjs.map +1 -1
- package/dist/lib/chunk-CanvasArticle.mjs +70 -32
- package/dist/lib/chunk-CanvasArticle.mjs.map +1 -1
- package/dist/lib/chunk-PLUGIN.mjs +6 -0
- package/dist/lib/chunk-PLUGIN.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +2 -2
- package/dist/lib/chunk-react-surface.mjs.map +1 -1
- package/dist/lib/containers.mjs.map +1 -1
- package/dist/lib/index.mjs +0 -1
- package/dist/lib/meta.mjs.map +1 -1
- package/dist/lib/translations.mjs.map +1 -1
- package/dist/types/src/capabilities/gen/browser.d.ts +6 -0
- package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/node.d.ts.map +1 -1
- package/dist/types/src/capabilities/gen/tauri.d.ts +6 -0
- package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/workerd.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/containers/CanvasArticle/CanvasArticle.d.ts +2 -2
- package/dist/types/src/containers/CanvasArticle/CanvasArticle.d.ts.map +1 -1
- package/dist/types/src/containers/CanvasArticle/index.d.ts +1 -1
- package/dist/types/src/containers/CanvasArticle/index.d.ts.map +1 -1
- package/dist/types/src/containers/index.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/index.d.ts +1 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +27 -24
- package/src/capabilities/gen/browser.ts +30 -0
- package/src/capabilities/gen/node.ts +2 -2
- package/src/capabilities/gen/tauri.ts +30 -0
- package/src/capabilities/gen/workerd.ts +2 -2
- package/src/capabilities/index.ts +3 -3
- package/src/capabilities/react-surface.ts +2 -2
- package/src/containers/CanvasArticle/CanvasArticle.tsx +75 -50
- package/src/containers/CanvasArticle/index.ts +1 -1
- package/src/containers/index.ts +1 -1
- package/src/index.ts +2 -3
- package/src/meta.ts +1 -1
- package/src/plugin.test.ts +2 -2
- package/src/translations.ts +2 -2
- package/src/types/index.ts +1 -1
package/PLUGIN.mdl
CHANGED
|
@@ -15,9 +15,10 @@ Each extension is defined in the Appendix or resolved via its URI.
|
|
|
15
15
|
|-------------|--------------------------------|
|
|
16
16
|
| `type` | `org.dxos.mdl.type@1.0` |
|
|
17
17
|
| `feat` | `org.dxos.mdl.feat@1.0` |
|
|
18
|
-
| `
|
|
18
|
+
| `scenario` | `org.dxos.mdl.scenario@1.0` |
|
|
19
19
|
| `component` | `org.dxos.mdl.component@1.0` |
|
|
20
20
|
| `op` | `org.dxos.mdl.op@1.0` |
|
|
21
|
+
| `test` | `org.dxos.mdl.test@1.0` |
|
|
21
22
|
|
|
22
23
|
## Types
|
|
23
24
|
|
|
@@ -178,15 +179,6 @@ op ifElseSelect
|
|
|
178
179
|
|
|
179
180
|
Effectful operations — mutate persistent state or call external services.
|
|
180
181
|
|
|
181
|
-
```mdl
|
|
182
|
-
op createComputeGraph
|
|
183
|
-
desc: Creates a new CanvasBoard with an empty ComputeGraph and adds it to the target space.
|
|
184
|
-
input:
|
|
185
|
-
target?: Space | Collection
|
|
186
|
-
output: string # DXN of created CanvasBoard
|
|
187
|
-
effects: [echo:write]
|
|
188
|
-
```
|
|
189
|
-
|
|
190
182
|
```mdl
|
|
191
183
|
op appendToQueue
|
|
192
184
|
desc: Appends items to an ECHO queue or collection identified by DXN.
|
|
@@ -323,7 +315,7 @@ feat F-7: Persistence and Collaboration
|
|
|
323
315
|
## Acceptance
|
|
324
316
|
|
|
325
317
|
```mdl
|
|
326
|
-
|
|
318
|
+
scenario T-1: Create empty graph
|
|
327
319
|
given: user opens the Create Object menu
|
|
328
320
|
when: user selects "Compute Graph"
|
|
329
321
|
then:
|
|
@@ -332,7 +324,7 @@ test T-1: Create empty graph
|
|
|
332
324
|
```
|
|
333
325
|
|
|
334
326
|
```mdl
|
|
335
|
-
|
|
327
|
+
scenario T-2: Add constant node and read value
|
|
336
328
|
given: an empty canvas
|
|
337
329
|
when: user adds a constant node, sets value "hello", connects it to a text node
|
|
338
330
|
then:
|
|
@@ -341,7 +333,7 @@ test T-2: Add constant node and read value
|
|
|
341
333
|
```
|
|
342
334
|
|
|
343
335
|
```mdl
|
|
344
|
-
|
|
336
|
+
scenario T-3: Boolean AND gate
|
|
345
337
|
given: two switch nodes with values true and false connected to an AND node
|
|
346
338
|
when: graph executes
|
|
347
339
|
then:
|
|
@@ -350,7 +342,7 @@ test T-3: Boolean AND gate
|
|
|
350
342
|
```
|
|
351
343
|
|
|
352
344
|
```mdl
|
|
353
|
-
|
|
345
|
+
scenario T-4: JSONPath transform
|
|
354
346
|
given: a constant node with value { "a": { "b": 42 } } connected to a json-transform node
|
|
355
347
|
when: expression "$.a.b" is set on the transform node
|
|
356
348
|
then:
|
|
@@ -358,7 +350,7 @@ test T-4: JSONPath transform
|
|
|
358
350
|
```
|
|
359
351
|
|
|
360
352
|
```mdl
|
|
361
|
-
|
|
353
|
+
scenario T-5: GPT node invocation
|
|
362
354
|
given: a thread node connected to a GPT node with a system prompt
|
|
363
355
|
when: graph executes with AiService available
|
|
364
356
|
then:
|
|
@@ -368,7 +360,7 @@ test T-5: GPT node invocation
|
|
|
368
360
|
```
|
|
369
361
|
|
|
370
362
|
```mdl
|
|
371
|
-
|
|
363
|
+
scenario T-6: Append to queue
|
|
372
364
|
given: a make-queue node connected to an append node; constant node provides input items
|
|
373
365
|
when: graph executes
|
|
374
366
|
then:
|
|
@@ -377,7 +369,7 @@ test T-6: Append to queue
|
|
|
377
369
|
```
|
|
378
370
|
|
|
379
371
|
```mdl
|
|
380
|
-
|
|
372
|
+
scenario T-7: Collaborative edit
|
|
381
373
|
given: two peers have the same CanvasBoard open
|
|
382
374
|
when: peer A moves a node on the canvas
|
|
383
375
|
then:
|
|
@@ -386,7 +378,7 @@ test T-7: Collaborative edit
|
|
|
386
378
|
```
|
|
387
379
|
|
|
388
380
|
```mdl
|
|
389
|
-
|
|
381
|
+
scenario T-8: NotExecuted propagation
|
|
390
382
|
given: an if node whose condition is false, connected to a text node on the true port
|
|
391
383
|
when: graph executes
|
|
392
384
|
then:
|
|
@@ -394,6 +386,67 @@ test T-8: NotExecuted propagation
|
|
|
394
386
|
- text node renders nothing (no error thrown)
|
|
395
387
|
```
|
|
396
388
|
|
|
389
|
+
## QA
|
|
390
|
+
|
|
391
|
+
Executable tests. Each step carries a human instruction (`do`) and, where the step maps to an
|
|
392
|
+
invocable operation, an agent binding (`invoke`). Report failures by test and step number.
|
|
393
|
+
|
|
394
|
+
```mdl
|
|
395
|
+
test QA-1: Build and run a small compute graph
|
|
396
|
+
desc: |
|
|
397
|
+
The core canvas round-trip — create a graph, wire a constant into a JSON transform, and read
|
|
398
|
+
the reactive result. None of the node kernels (`evalConstant`, `jsonTransform`, ...) are
|
|
399
|
+
registered operations: they run inside the graph's own reactive controller when the canvas
|
|
400
|
+
triggers evaluation, not through the operation invoker, so this test is entirely human — the
|
|
401
|
+
same gap plugin-chess documents for move-less game creation.
|
|
402
|
+
actors: human
|
|
403
|
+
covers: [F-1.1, F-1.2, F-1.3, F-2.1, F-2.2, F-3.1, F-3.2, T-1, T-2]
|
|
404
|
+
status: unverified
|
|
405
|
+
given:
|
|
406
|
+
- an identity exists
|
|
407
|
+
- space: a space is open
|
|
408
|
+
- collection: a collection in that space, to create into
|
|
409
|
+
- no CanvasBoard named "QA Graph" exists — ABORT rather than deleting one this test did not
|
|
410
|
+
create
|
|
411
|
+
steps:
|
|
412
|
+
- name: Create the graph
|
|
413
|
+
do: In the navtree, click + on a collection and choose Compute Graph. Name it "QA Graph".
|
|
414
|
+
expect: an empty CanvasBoard/ComputeGraph opens on the canvas
|
|
415
|
+
note: |
|
|
416
|
+
NO `invoke` — "Create object" for CanvasBoard constructs the object locally and only
|
|
417
|
+
calls `space.addObject` (see `create-object.ts`); there is no dedicated
|
|
418
|
+
`createComputeGraph` operation despite F-1.1's phrasing, so this step is human-only.
|
|
419
|
+
- name: Add a constant node
|
|
420
|
+
do: Drag "Constant" from the node palette onto the canvas. Set its value to 42 and
|
|
421
|
+
valueType to "number".
|
|
422
|
+
expect: a constant node appears on the canvas showing 42
|
|
423
|
+
- name: Add a JSON transform node
|
|
424
|
+
do: Drag "JSON Transform" onto the canvas. Set its expression to "$".
|
|
425
|
+
expect: a JSON transform node appears on the canvas
|
|
426
|
+
- name: Wire them together
|
|
427
|
+
do: Drag from the constant node's output port to the JSON transform node's input port.
|
|
428
|
+
expect: a ComputeEdge connects the two nodes
|
|
429
|
+
- name: Read the result
|
|
430
|
+
do: Click the JSON transform node to inspect its output, or connect a text/output node to it.
|
|
431
|
+
expect: the transform node's output shows 42 (its own re-evaluation, triggered by the
|
|
432
|
+
upstream constant, per F-3.1's topological order)
|
|
433
|
+
after:
|
|
434
|
+
- name: Delete the graph
|
|
435
|
+
do: Right-click "QA Graph" in the navtree and choose Delete.
|
|
436
|
+
invoke: |
|
|
437
|
+
org.dxos.operation.space.removeObjects {
|
|
438
|
+
objects: [(await space.db.query(dxos.Filter.type(dxos.DXN.make('org.dxos.type.canvasBoard'))).run()).objects
|
|
439
|
+
.find((o) => o.name === 'QA Graph')
|
|
440
|
+
?? (() => { throw new Error("CanvasBoard QA Graph not found — refusing to remove an unrelated object"); })()],
|
|
441
|
+
target: $given.collection
|
|
442
|
+
}
|
|
443
|
+
expect: the row leaves the navtree and its plank closes
|
|
444
|
+
note: |
|
|
445
|
+
No captured id exists — the create step has no `invoke` (see above) — so this resolves
|
|
446
|
+
"QA Graph" by typename AND name — a name match alone would delete any object carrying it, and throws rather than removing anything when the name does not
|
|
447
|
+
match, since `given` guarantees no pre-existing board carries it.
|
|
448
|
+
```
|
|
449
|
+
|
|
397
450
|
---
|
|
398
451
|
|
|
399
452
|
## Appendix: Extension Definitions
|
|
@@ -420,8 +473,8 @@ ext feat
|
|
|
420
473
|
```
|
|
421
474
|
|
|
422
475
|
```mdl
|
|
423
|
-
ext
|
|
424
|
-
uri: org.dxos.mdl.
|
|
476
|
+
ext scenario
|
|
477
|
+
uri: org.dxos.mdl.scenario@1.0
|
|
425
478
|
desc: An acceptance scenario expressed as given / when / then steps.
|
|
426
479
|
fields:
|
|
427
480
|
given?: Step | Step[]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
|
|
2
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
3
|
+
import * as SpaceCapability from "@dxos/plugin-space/SpaceCapability";
|
|
4
|
+
import { translations } from "#translations";
|
|
5
|
+
import { meta } from "#meta";
|
|
6
|
+
//#region src/capabilities/gen/browser.ts
|
|
7
|
+
var CreateObject = SpaceCapability.createObject(() => import("./chunk-create-object.mjs"));
|
|
8
|
+
var PluginAsset = AppCapability.pluginAsset({
|
|
9
|
+
pluginId: meta.profile.key,
|
|
10
|
+
path: "PLUGIN.mdl",
|
|
11
|
+
content: PLUGIN_default,
|
|
12
|
+
mimeType: "application/x-mdl"
|
|
13
|
+
});
|
|
14
|
+
var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article", "org.dxos.role.section"] });
|
|
15
|
+
var Schema = AppCapability.schema(() => import("./chunk-schema.mjs"));
|
|
16
|
+
var Translations = AppCapability.translations(translations);
|
|
17
|
+
//#endregion
|
|
18
|
+
export { CreateObject, PluginAsset, ReactSurface, Schema, Translations };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=capabilities.browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.browser.mjs","names":[],"sources":["../../src/capabilities/gen/browser.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'browser' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\nimport pluginSpec from '../../../PLUGIN.mdl?raw';\n\nexport const CreateObject = SpaceCapability.createObject(() => import('../create-object.ts'));\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n\nexport const ReactSurface = AppCapability.surface(() => import('../react-surface.ts'), {\n roles: ['org.dxos.role.article', 'org.dxos.role.section'],\n});\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;AAcA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,4BAAsB;AAE5F,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AAED,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAwB,EACrF,OAAO,CAAC,yBAAyB,uBAAuB,EAC1D,CAAC;AAED,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
+
import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
|
|
1
2
|
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
2
3
|
import * as SpaceCapability from "@dxos/plugin-space/SpaceCapability";
|
|
3
4
|
import { translations } from "#translations";
|
|
4
5
|
import { meta } from "#meta";
|
|
5
|
-
//#region PLUGIN.mdl?raw
|
|
6
|
-
var PLUGIN_default = "---\nid: org.dxos.plugin.conductor\nname: ConductorPlugin\nversion: 0.1.0\n---\n\nVisual node-based compute graph plugin for `DXOS` Composer — wire data sources, AI models, logic, and transformations into reactive pipelines that execute in the local-first runtime.\n\n## Extensions\n\nThe following extension dialects are used in this document.\nEach extension is defined in the Appendix or resolved via its URI.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `test` | `org.dxos.mdl.test@1.0` |\n| `component` | `org.dxos.mdl.component@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n\n## Types\n\n```mdl\ntype ComputeValueType\n literals: string | number | boolean | object\n```\n\n```mdl\ntype NodeType\n literals:\n input | output | constant | template | switch | rng |\n audio | chat | text | json | json-transform | surface |\n beacon | scope | reducer | thread | queue | make-queue | append |\n and | or | not | if | if-else |\n function | gpt | gpt-realtime |\n database | text-to-image\n```\n\n```mdl\ntype ComputeNode\n desc: A node in the compute graph persisted via ECHO.\n extends: [Graph.Node]\n fields:\n inputSchema?: JsonSchema\n outputSchema?: JsonSchema\n subgraph?: Ref<ComputeGraph> # composition: nested graph\n function?: Ref<PersistentOperation> # composition: reusable function node\n valueType?: ComputeValueType # for constant/template nodes\n value?: any # for constant and template nodes\n enabled?: boolean # for switch nodes\n```\n\n```mdl\ntype ComputeEdge\n desc: A directed edge connecting an output port on one node to an input port on another.\n extends: [Graph.Edge]\n fields:\n input: string # target node input property name\n output: string # source node output property name\n```\n\n```mdl\ntype ComputeGraph\n desc: Persistent ECHO object holding the full node-edge graph plus special I/O reference nodes.\n fields:\n graph: Graph.Graph\n input?: ComputeNode\n output?: ComputeNode\n```\n\n```mdl\ntype ValueBag\n desc: A set of named asynchronous value effects passed between nodes.\n fields:\n _tag: \"ValueBag\"\n values: Record<string, ValueEffect<any>>\n```\n\n## Components\n\n```mdl\ncomponent CanvasArticle\n desc: Full-screen canvas editor for a ComputeGraph; renders as an article or a section embed.\n props:\n role: \"article\" | \"section\"\n subject: CanvasBoard\n attendableId?: string\n state:\n graph: CanvasGraphModel<ComputeShape>\n controller?: ComputeGraphController\n registry: ShapeRegistry\n layout?: ComputeShapeLayout\n slots:\n toolbar?: ReactNode # injected by AppSurface frame\n layout: |\n ┌──────────────────────────────────────────────┐\n │ [toolbar — zoom, tools, minimap] │\n ├──────────────────────────────────────────────┤\n │ │\n │ ┌──────┐ ┌──────┐ ┌──────┐ │\n │ │ node │───▶│ node │───▶│ node │ │\n │ └──────┘ └──────┘ └──────┘ │\n │ │\n │ canvas — pan / zoom / connect nodes │\n └──────────────────────────────────────────────┘\n```\n\n## Operations\n\nPure operations — no effects, no service dependencies.\n\n```mdl\nop evalConstant\n desc: Returns the scalar value stored on a constant node.\n input:\n node: ComputeNode\n output: Scalar\n errors:\n MissingValue: node has no value set\n```\n\n```mdl\nop jsonTransform\n desc: Evaluates a JSONPath expression over an input value.\n input:\n input: any\n expression: string\n output: any\n errors:\n InvalidExpression: JSONPath expression could not be parsed\n```\n\n```mdl\nop boolAnd\n desc: Logical AND of two boolean inputs.\n input:\n a: boolean\n b: boolean\n output: boolean\n```\n\n```mdl\nop boolOr\n desc: Logical OR of two boolean inputs.\n input:\n a: boolean\n b: boolean\n output: boolean\n```\n\n```mdl\nop boolNot\n desc: Logical NOT of a boolean input.\n input:\n input: boolean\n output: boolean\n```\n\n```mdl\nop ifRoute\n desc: Routes a value to the true or false output port based on a condition.\n input:\n condition: boolean\n value: any\n output: IfOutput # { true?: any; false?: any }\n```\n\n```mdl\nop ifElseSelect\n desc: Ternary — returns trueValue or falseValue depending on condition.\n input:\n condition: boolean\n true: any\n false: any\n output: any\n```\n\nEffectful operations — mutate persistent state or call external services.\n\n```mdl\nop createComputeGraph\n desc: Creates a new CanvasBoard with an empty ComputeGraph and adds it to the target space.\n input:\n target?: Space | Collection\n output: string # DXN of created CanvasBoard\n effects: [echo:write]\n```\n\n```mdl\nop appendToQueue\n desc: Appends items to an ECHO queue or collection identified by DXN.\n input:\n id: string # DXN — dxn:queue or dxn:echo\n items: any[]\n output: void\n effects: [echo:write, feed:write]\n errors:\n UnsupportedDXN: DXN kind not supported\n SpaceMismatch: ECHO DXN belongs to a different space\n```\n\n```mdl\nop createQueue\n desc: Allocates a new append-only Feed and returns a Ref to it.\n input:\n output: Ref<Feed>\n effects: [feed:write]\n```\n\n```mdl\nop invokeGpt\n desc: Sends the current conversation thread to the configured AI model and streams the reply.\n input:\n thread: Ref<Thread>\n tools?: Tool[]\n systemPrompt?: string\n output: Message\n effects: [http]\n requires: [AiService]\n errors:\n ModelUnavailable: AI service could not be reached\n```\n\n```mdl\nop invokeFunction\n desc: Deserialises a PersistentOperation from ECHO and invokes it with the provided input bag.\n input:\n function: Ref<PersistentOperation>\n input: any\n output: any\n effects: [echo:read]\n requires: [Database.Service, OperationRegistry.Service]\n errors:\n FunctionNotFound: referenced operation does not exist\n InvocationFailed: operation returned an error\n```\n\n## Features\n\n```mdl\nfeat F-1: Canvas Editor\n\n req F-1.1: User can create a new compute graph via the \"Create object\" entry.\n req F-1.2: Canvas renders nodes as draggable, resizable shapes on an infinite panning surface.\n req F-1.3:\n when: user drags from an output port to an input port\n then: a ComputeEdge is created connecting the two ports\n req F-1.4:\n when: a ComputeEdge is deleted\n then: downstream nodes stop receiving values from the disconnected output\n```\n\n```mdl\nfeat F-2: Node Palette\n\n req F-2.1: Toolbar exposes all built-in NodeTypes; user can drag them onto the canvas.\n req F-2.2: Constant nodes display an inline editor for their scalar value and valueType.\n req F-2.3: Template nodes render a text input with {{variable}} interpolation.\n req F-2.4: Function nodes allow selecting a PersistentOperation from the space.\n```\n\n```mdl\nfeat F-3: Reactive Execution\n\n req F-3.1:\n when: any upstream node value changes\n then: ComputeGraphController re-evaluates dependent nodes in topological order\n\n req F-3.2: Node execution is lazy; nodes only run when their outputs are consumed.\n\n req F-3.3:\n when: a node fails with ConductorError\n then: downstream nodes receive a NotExecuted marker and do not throw\n\n req F-3.4:\n when: a node emits a ValueBag\n then: individual output ports can resolve at different times (async bag semantics)\n```\n\n```mdl\nfeat F-4: AI Integration\n\n req F-4.1: GPT node connects to AiService; configuration includes model, system prompt, and tools.\n req F-4.2:\n when: GPT node executes\n then: op:invokeGpt streams the model response back to the output port\n\n req F-4.3: Function node can reference any PersistentOperation registered in the space.\n```\n\n```mdl\nfeat F-5: Data Sources and Sinks\n\n req F-5.1: Queue node reads messages from a Feed referenced by DXN.\n req F-5.2: Append node writes items to a Feed or ECHO collection referenced by DXN.\n req F-5.3: Database node exposes ECHO space contents as a query tool for AI nodes.\n req F-5.4: Thread node surfaces a conversation thread with its message history.\n```\n\n```mdl\nfeat F-6: Logic and Control Flow\n\n req F-6.1: If node routes a value to true or false output port based on a boolean condition.\n req F-6.2: IfElse node selects one of two values using a ternary condition.\n req F-6.3: Reducer node collects an array of values from multiple upstream ports.\n req F-6.4: And / Or / Not nodes implement standard boolean combinators.\n```\n\n```mdl\nfeat F-7: Persistence and Collaboration\n\n req F-7.1: ComputeGraph is stored as an ECHO object; graph topology is replicated to peers.\n req F-7.2:\n when: a peer modifies a node value or edge\n then: all collaborators see the change reflected on the canvas in real time\n\n req F-7.3:\n when: a CanvasBoard is embedded as a section in another document\n then: the graph renders in the section aspect-square container and remains interactive\n```\n\n## Acceptance\n\n```mdl\ntest T-1: Create empty graph\n given: user opens the Create Object menu\n when: user selects \"Compute Graph\"\n then:\n - a new CanvasBoard with an empty ComputeGraph is created in the space\n - the canvas opens with no nodes\n```\n\n```mdl\ntest T-2: Add constant node and read value\n given: an empty canvas\n when: user adds a constant node, sets value \"hello\", connects it to a text node\n then:\n - text node receives \"hello\" on its input port\n - text node renders \"hello\"\n```\n\n```mdl\ntest T-3: Boolean AND gate\n given: two switch nodes with values true and false connected to an AND node\n when: graph executes\n then:\n - AND node output is false\n - switching both inputs to true produces output true\n```\n\n```mdl\ntest T-4: JSONPath transform\n given: a constant node with value { \"a\": { \"b\": 42 } } connected to a json-transform node\n when: expression \"$.a.b\" is set on the transform node\n then:\n - output port value is [42]\n```\n\n```mdl\ntest T-5: GPT node invocation\n given: a thread node connected to a GPT node with a system prompt\n when: graph executes with AiService available\n then:\n - GPT node output port receives a Message\n - Message content is non-empty\n errors: [ModelUnavailable]\n```\n\n```mdl\ntest T-6: Append to queue\n given: a make-queue node connected to an append node; constant node provides input items\n when: graph executes\n then:\n - queue contains the appended items\n - downstream queue node reads them back\n```\n\n```mdl\ntest T-7: Collaborative edit\n given: two peers have the same CanvasBoard open\n when: peer A moves a node on the canvas\n then:\n - peer B sees the node in the new position within one replication round-trip\n tags: [collaborative]\n```\n\n```mdl\ntest T-8: NotExecuted propagation\n given: an if node whose condition is false, connected to a text node on the true port\n when: graph executes\n then:\n - text node receives a NotExecuted marker\n - text node renders nothing (no error thrown)\n```\n\n---\n\n## Appendix: Extension Definitions\n\n```mdl\next type\n uri: org.dxos.mdl.type@1.0\n desc: A named data structure with typed fields and optional literals.\n fields:\n desc?: Prose\n fields?: FieldMap\n literals?: UnionList\n extends?: TypeRef[]\n```\n\n```mdl\next feat\n uri: org.dxos.mdl.feat@1.0\n desc: A named feature grouping one or more requirements.\n fields:\n desc?: Prose\n req: RequirementList\n nesting: self\n```\n\n```mdl\next test\n uri: org.dxos.mdl.test@1.0\n desc: An acceptance scenario expressed as given / when / then steps.\n fields:\n given?: Step | Step[]\n when?: Step | Step[]\n then: Step | Step[]\n tags?: TagList\n```\n\n```mdl\next component\n uri: org.dxos.mdl.component@1.0\n desc: A UI component with props, internal state, slots, actions, and events.\n fields:\n desc?: Prose\n props?: FieldMap\n state?: FieldMap\n slots?: FieldMap\n actions?: ActionMap\n emits?: EventMap\n layout?: CodeBlock\n```\n\n```mdl\next op\n uri: org.dxos.mdl.op@1.0\n desc: |\n A named operation with typed inputs, outputs, and declared errors.\n Pure ops have no effects or requires. Effectful ops declare both.\n fields:\n desc?: Prose\n input?: FieldMap\n output?: TypeExpr\n errors?: ErrorMap\n effects?: EffectList\n requires?: ServiceList\n note?: Prose\n```\n";
|
|
7
|
-
//#endregion
|
|
8
6
|
//#region src/capabilities/index.ts
|
|
9
7
|
var CreateObject = SpaceCapability.createObject(() => import("./chunk-create-object.mjs"));
|
|
10
8
|
var PluginAsset = AppCapability.pluginAsset({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../../PLUGIN.mdl?raw';\n\nexport const CreateObject = SpaceCapability.createObject(() => import('./create-object'));\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface'), {\n roles: ['org.dxos.role.article', 'org.dxos.role.section'],\n});\nexport const Schema = AppCapability.schema(() => import('./schema'));\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../../PLUGIN.mdl?raw';\n\nexport const CreateObject = SpaceCapability.createObject(() => import('./create-object.ts'));\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface.ts'), {\n roles: ['org.dxos.role.article', 'org.dxos.role.section'],\n});\nexport const Schema = AppCapability.schema(() => import('./schema.ts'));\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;AAaA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,4BAAqB;AAC3F,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AACD,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAuB,EACpF,OAAO,CAAC,yBAAyB,uBAAuB,EAC1D,CAAC;AACD,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAc;AACtE,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport { translations } from '#translations';\n\nexport const CreateObject = SpaceCapability.createObject(() => import('../create-object'));\n\nexport const Schema = AppCapability.schema(() => import('../schema'));\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;AAWA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,
|
|
1
|
+
{"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport { translations } from '#translations';\n\nexport const CreateObject = SpaceCapability.createObject(() => import('../create-object.ts'));\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;AAWA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,4BAAsB;AAE5F,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
|
|
2
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
3
|
+
import * as SpaceCapability from "@dxos/plugin-space/SpaceCapability";
|
|
4
|
+
import { translations } from "#translations";
|
|
5
|
+
import { meta } from "#meta";
|
|
6
|
+
//#region src/capabilities/gen/tauri.ts
|
|
7
|
+
var CreateObject = SpaceCapability.createObject(() => import("./chunk-create-object.mjs"));
|
|
8
|
+
var PluginAsset = AppCapability.pluginAsset({
|
|
9
|
+
pluginId: meta.profile.key,
|
|
10
|
+
path: "PLUGIN.mdl",
|
|
11
|
+
content: PLUGIN_default,
|
|
12
|
+
mimeType: "application/x-mdl"
|
|
13
|
+
});
|
|
14
|
+
var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article", "org.dxos.role.section"] });
|
|
15
|
+
var Schema = AppCapability.schema(() => import("./chunk-schema.mjs"));
|
|
16
|
+
var Translations = AppCapability.translations(translations);
|
|
17
|
+
//#endregion
|
|
18
|
+
export { CreateObject, PluginAsset, ReactSurface, Schema, Translations };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=capabilities.tauri.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.tauri.mjs","names":[],"sources":["../../src/capabilities/gen/tauri.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'tauri' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\nimport pluginSpec from '../../../PLUGIN.mdl?raw';\n\nexport const CreateObject = SpaceCapability.createObject(() => import('../create-object.ts'));\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n\nexport const ReactSurface = AppCapability.surface(() => import('../react-surface.ts'), {\n roles: ['org.dxos.role.article', 'org.dxos.role.section'],\n});\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;AAcA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,4BAAsB;AAE5F,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AAED,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAwB,EACrF,OAAO,CAAC,yBAAyB,uBAAuB,EAC1D,CAAC;AAED,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.workerd.mjs","names":[],"sources":["../../src/capabilities/gen/workerd.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport { translations } from '#translations';\n\nexport const CreateObject = SpaceCapability.createObject(() => import('../create-object'));\n\nexport const Schema = AppCapability.schema(() => import('../schema'));\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;AAWA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,
|
|
1
|
+
{"version":3,"file":"capabilities.workerd.mjs","names":[],"sources":["../../src/capabilities/gen/workerd.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.\n\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as SpaceCapability from '@dxos/plugin-space/SpaceCapability';\n\nimport { translations } from '#translations';\n\nexport const CreateObject = SpaceCapability.createObject(() => import('../create-object.ts'));\n\nexport const Schema = AppCapability.schema(() => import('../schema.ts'));\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;AAWA,IAAa,eAAe,gBAAgB,mBAAmB,OAAO,4BAAsB;AAE5F,IAAa,SAAS,cAAc,aAAa,OAAO,qBAAe;AAEvE,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA"}
|
|
@@ -1,61 +1,100 @@
|
|
|
1
|
-
import { Fragment, useEffect, useMemo
|
|
1
|
+
import { Fragment, useCallback, useEffect, useMemo } from "react";
|
|
2
2
|
import { Database, Obj } from "@dxos/echo";
|
|
3
3
|
import * as Effect from "effect/Effect";
|
|
4
4
|
import * as Operation from "@dxos/compute/Operation";
|
|
5
5
|
import * as Capabilities from "@dxos/app-framework/Capabilities";
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import { CanvasGraphModel, Editor, KeyboardContainer, ShapeRegistry } from "@dxos/react-ui-canvas-editor";
|
|
6
|
+
import * as AppSurface from "@dxos/app-toolkit/AppSurface";
|
|
7
|
+
import { KeyboardContainer, ShapeRegistry } from "@dxos/react-ui-canvas-editor";
|
|
9
8
|
import { ComputeGraphModel } from "@dxos/conductor";
|
|
10
9
|
import { AiService } from "@dxos/ai";
|
|
10
|
+
import * as Hooks from "@dxos/app-framework/Hooks";
|
|
11
11
|
import * as Credential from "@dxos/compute/Credential";
|
|
12
12
|
import * as OperationRegistry from "@dxos/compute/OperationRegistry";
|
|
13
13
|
import * as ServiceResolver from "@dxos/compute/ServiceResolver";
|
|
14
14
|
import { useObject } from "@dxos/echo-react";
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { Bullets, ComputeContext, ComputeGraphController, boardSceneId, computeNodeRegistry, computeShapes, createComputeProjection, createEchoStore } from "@dxos/react-ui-canvas-compute";
|
|
16
|
+
import { SceneView, createSceneViewAtoms, useRegistry, useSceneProjection } from "@dxos/react-ui-canvas/scene";
|
|
17
|
+
import * as Layout from "@dxos/react-ui/Layout";
|
|
17
18
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
18
19
|
//#region src/containers/CanvasArticle/CanvasArticle.tsx
|
|
20
|
+
/**
|
|
21
|
+
* The board on the scene engine (MIGRATION.md M4): `SceneView` over an ECHO store of the board's own
|
|
22
|
+
* layout, with the compute projection keeping the compute graph in step. The editor's own canvas,
|
|
23
|
+
* graph model and monitor are gone — the store is the persistence and the projection is the mirror.
|
|
24
|
+
*/
|
|
19
25
|
var CanvasArticle = ({ role, subject, attendableId: _attendableId }) => {
|
|
20
|
-
const [canvas] = useObject(subject);
|
|
21
|
-
const id = Obj.getURI(canvas);
|
|
22
|
-
const graph = useMemo(() => CanvasGraphModel.create(canvas.layout, (fn) => Obj.update(subject, fn)), [subject, canvas.layout]);
|
|
23
|
-
useEffect(() => Obj.subscribe(subject, () => graph.sync()), [subject, graph]);
|
|
24
26
|
const controller = useGraphController(subject);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
controller
|
|
30
|
-
graph,
|
|
31
|
-
editorRef
|
|
27
|
+
if (!controller) return null;
|
|
28
|
+
return /* @__PURE__ */ jsx(CanvasScene, {
|
|
29
|
+
role,
|
|
30
|
+
subject,
|
|
31
|
+
controller
|
|
32
32
|
});
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
};
|
|
34
|
+
CanvasArticle.displayName = "CanvasArticle";
|
|
35
|
+
var CanvasScene = ({ role, subject, controller }) => {
|
|
36
|
+
const id = Obj.getURI(subject);
|
|
37
|
+
const registry = useRegistry();
|
|
38
|
+
const shapeRegistry = useMemo(() => new ShapeRegistry(computeShapes), []);
|
|
39
|
+
const store = useMemo(() => createEchoStore(subject), [subject]);
|
|
40
|
+
const sceneId = useMemo(() => boardSceneId(subject), [subject]);
|
|
41
|
+
const atoms = useMemo(() => createSceneViewAtoms(sceneId), [sceneId]);
|
|
42
|
+
const createProjection = useCallback((options) => createComputeProjection({
|
|
43
|
+
...options,
|
|
44
|
+
controller
|
|
45
|
+
}), [controller]);
|
|
46
|
+
const projection = useSceneProjection({
|
|
47
|
+
store,
|
|
48
|
+
atoms,
|
|
49
|
+
createProjection
|
|
50
|
+
});
|
|
51
|
+
const resize = useCallback((nodeId, delta) => {
|
|
52
|
+
const node = registry.get(projection.scene).nodes[nodeId];
|
|
53
|
+
if (node) projection.apply({
|
|
54
|
+
kind: "update",
|
|
55
|
+
id: nodeId,
|
|
56
|
+
values: { size: {
|
|
57
|
+
width: node.size.width,
|
|
58
|
+
height: node.size.height + delta
|
|
59
|
+
} }
|
|
60
|
+
});
|
|
61
|
+
}, [registry, projection]);
|
|
35
62
|
const Root = role === AppSurface.Section.role ? Container : Fragment;
|
|
36
63
|
return /* @__PURE__ */ jsx(ComputeContext.Provider, {
|
|
37
|
-
value: {
|
|
64
|
+
value: {
|
|
65
|
+
controller,
|
|
66
|
+
registry: shapeRegistry,
|
|
67
|
+
resize
|
|
68
|
+
},
|
|
38
69
|
children: /* @__PURE__ */ jsx(Root, { children: /* @__PURE__ */ jsx(KeyboardContainer, {
|
|
39
70
|
id,
|
|
40
|
-
children: /* @__PURE__ */ jsxs(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
71
|
+
children: /* @__PURE__ */ jsxs(SceneView.Root, {
|
|
72
|
+
store,
|
|
73
|
+
root: sceneId,
|
|
74
|
+
atoms,
|
|
75
|
+
nodes: computeNodeRegistry,
|
|
76
|
+
projection,
|
|
77
|
+
children: [
|
|
78
|
+
/* @__PURE__ */ jsx(SceneView.Canvas, { overlay: /* @__PURE__ */ jsx(Bullets, {
|
|
79
|
+
controller,
|
|
80
|
+
projection
|
|
81
|
+
}) }),
|
|
82
|
+
/* @__PURE__ */ jsx(SceneView.Navigation, {}),
|
|
83
|
+
/* @__PURE__ */ jsx(SceneView.Actions, {}),
|
|
84
|
+
/* @__PURE__ */ jsx(SceneView.Debug, {}),
|
|
85
|
+
/* @__PURE__ */ jsx(SceneView.Palette, {})
|
|
86
|
+
]
|
|
48
87
|
})
|
|
49
88
|
}) })
|
|
50
89
|
});
|
|
51
90
|
};
|
|
52
|
-
var Container = (props) => /* @__PURE__ */ jsx(Flex, {
|
|
91
|
+
var Container = (props) => /* @__PURE__ */ jsx(Layout.Flex, {
|
|
53
92
|
...props,
|
|
54
|
-
classNames: "aspect-square"
|
|
93
|
+
classNames: "aspect-square w-full max-h-full min-h-0"
|
|
55
94
|
});
|
|
56
95
|
var useGraphController = (canvas) => {
|
|
57
96
|
const db = Obj.getDatabase(canvas);
|
|
58
|
-
const processManagerRuntime = useCapability(Capabilities.ProcessManagerRuntime);
|
|
97
|
+
const processManagerRuntime = Hooks.useCapability(Capabilities.ProcessManagerRuntime);
|
|
59
98
|
const [computeGraph] = useObject(canvas.computeGraph);
|
|
60
99
|
const controller = useMemo(() => {
|
|
61
100
|
if (!canvas.computeGraph?.target || !db) return null;
|
|
@@ -82,7 +121,6 @@ var useGraphController = (canvas) => {
|
|
|
82
121
|
}, [canvas.computeGraph?.target, controller]);
|
|
83
122
|
return controller;
|
|
84
123
|
};
|
|
85
|
-
CanvasArticle.displayName = "CanvasArticle";
|
|
86
124
|
//#endregion
|
|
87
125
|
export { CanvasArticle as default };
|
|
88
126
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-CanvasArticle.mjs","names":[],"sources":["../../src/containers/CanvasArticle/CanvasArticle.tsx"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport type * as Exit from 'effect/Exit';\nimport React, { Fragment, useEffect, useMemo
|
|
1
|
+
{"version":3,"file":"chunk-CanvasArticle.mjs","names":[],"sources":["../../src/containers/CanvasArticle/CanvasArticle.tsx"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport type * as Exit from 'effect/Exit';\nimport React, { Fragment, useCallback, useEffect, useMemo } from 'react';\n\nimport { AiService } from '@dxos/ai';\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport * as Credential from '@dxos/compute/Credential';\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationRegistry from '@dxos/compute/OperationRegistry';\nimport * as ServiceResolver from '@dxos/compute/ServiceResolver';\nimport { ComputeGraphModel } from '@dxos/conductor';\nimport { Database, Obj } from '@dxos/echo';\nimport { useObject } from '@dxos/echo-react';\nimport {\n Bullets,\n ComputeContext,\n ComputeGraphController,\n boardSceneId,\n computeNodeRegistry,\n computeShapes,\n createComputeProjection,\n createEchoStore,\n} from '@dxos/react-ui-canvas-compute';\nimport { type CanvasBoard, KeyboardContainer, ShapeRegistry } from '@dxos/react-ui-canvas-editor';\nimport {\n type FreehandProjectionOptions,\n SceneView,\n createSceneViewAtoms,\n useRegistry,\n useSceneProjection,\n} from '@dxos/react-ui-canvas/scene';\nimport * as Layout from '@dxos/react-ui/Layout';\n\nexport type CanvasArticleProps = AppSurface.ObjectArticleProps<CanvasBoard.CanvasBoard>;\n\n/**\n * The board on the scene engine (MIGRATION.md M4): `SceneView` over an ECHO store of the board's own\n * layout, with the compute projection keeping the compute graph in step. The editor's own canvas,\n * graph model and monitor are gone — the store is the persistence and the projection is the mirror.\n */\nexport const CanvasArticle = ({ role, subject, attendableId: _attendableId }: CanvasArticleProps) => {\n const controller = useGraphController(subject);\n if (!controller) {\n return null;\n }\n\n // The scene is everything below: a board without its compute graph has no projection to render through.\n return <CanvasScene role={role} subject={subject} controller={controller} />;\n};\n\nCanvasArticle.displayName = 'CanvasArticle';\n\ntype CanvasSceneProps = Pick<CanvasArticleProps, 'role' | 'subject'> & { controller: ComputeGraphController };\n\nconst CanvasScene = ({ role, subject, controller }: CanvasSceneProps) => {\n const id = Obj.getURI(subject);\n const registry = useRegistry();\n const shapeRegistry = useMemo(() => new ShapeRegistry(computeShapes), []);\n const store = useMemo(() => createEchoStore(subject), [subject]);\n const sceneId = useMemo(() => boardSceneId(subject), [subject]);\n const atoms = useMemo(() => createSceneViewAtoms(sceneId), [sceneId]);\n const createProjection = useCallback(\n (options: FreehandProjectionOptions) => createComputeProjection({ ...options, controller }),\n [controller],\n );\n const projection = useSceneProjection({ store, atoms, createProjection });\n\n // A function body opening grows its node through the model, so its links re-route with it.\n const resize = useCallback(\n (nodeId: string, delta: number) => {\n const node = registry.get(projection.scene).nodes[nodeId];\n if (node) {\n projection.apply({\n kind: 'update',\n id: nodeId,\n values: { size: { width: node.size.width, height: node.size.height + delta } },\n });\n }\n },\n [registry, projection],\n );\n\n const Root = role === AppSurface.Section.role ? Container : Fragment;\n\n return (\n <ComputeContext.Provider value={{ controller, registry: shapeRegistry, resize }}>\n <Root>\n <KeyboardContainer id={id}>\n <SceneView.Root\n store={store}\n root={sceneId}\n atoms={atoms}\n nodes={computeNodeRegistry}\n projection={projection}\n >\n <SceneView.Canvas overlay={<Bullets controller={controller} projection={projection} />} />\n <SceneView.Navigation />\n <SceneView.Actions />\n <SceneView.Debug />\n <SceneView.Palette />\n </SceneView.Root>\n </KeyboardContainer>\n </Root>\n </ComputeContext.Provider>\n );\n};\n\nconst Container = (props: Layout.FlexProps) => (\n <Layout.Flex {...props} classNames='aspect-square w-full max-h-full min-h-0' />\n);\n\nconst useGraphController = (canvas: CanvasBoard.CanvasBoard) => {\n const db = Obj.getDatabase(canvas);\n const processManagerRuntime = Hooks.useCapability(Capabilities.ProcessManagerRuntime);\n const [computeGraph] = useObject(canvas.computeGraph);\n const controller = useMemo(() => {\n if (!canvas.computeGraph?.target || !db) {\n return null;\n }\n const spaceId = db.spaceId;\n const model = new ComputeGraphModel(canvas.computeGraph?.target);\n const spaceLayer = ServiceResolver.provide(\n { space: spaceId },\n AiService.AiService,\n Database.Service,\n Credential.CredentialsService,\n Operation.Service,\n OperationRegistry.Service,\n );\n const computeGraphRuntime = {\n runPromiseExit: <A, E>(effect: Effect.Effect<A, E, any>): Promise<Exit.Exit<A, E>> =>\n processManagerRuntime.runPromiseExit(effect.pipe(Effect.provide(spaceLayer)) as any) as Promise<\n Exit.Exit<A, E>\n >,\n };\n const controller = new ComputeGraphController(computeGraphRuntime, model);\n return controller;\n }, [computeGraph, db, processManagerRuntime]);\n\n useEffect(() => {\n if (!controller) {\n return;\n }\n\n void controller.open();\n return () => {\n void controller.close();\n };\n }, [controller]);\n\n // Structural edits from other peers (or undo) land in the object, not through the model.\n useEffect(() => {\n const root = canvas.computeGraph?.target;\n if (!root || !controller) {\n return;\n }\n\n return Obj.subscribe(root, () => controller.graph.sync());\n }, [canvas.computeGraph?.target, controller]);\n\n return controller;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA8CA,IAAa,iBAAiB,EAAE,MAAM,SAAS,cAAc,oBAAwC;CACnG,MAAM,aAAa,mBAAmB,OAAO;CAC7C,IAAI,CAAC,YACH,OAAO;CAIT,OAAO,oBAAC,aAAD;EAAmB;EAAe;EAAqB;CAAa,CAAA;AAC7E;AAEA,cAAc,cAAc;AAI5B,IAAM,eAAe,EAAE,MAAM,SAAS,iBAAmC;CACvE,MAAM,KAAK,IAAI,OAAO,OAAO;CAC7B,MAAM,WAAW,YAAY;CAC7B,MAAM,gBAAgB,cAAc,IAAI,cAAc,aAAa,GAAG,CAAC,CAAC;CACxE,MAAM,QAAQ,cAAc,gBAAgB,OAAO,GAAG,CAAC,OAAO,CAAC;CAC/D,MAAM,UAAU,cAAc,aAAa,OAAO,GAAG,CAAC,OAAO,CAAC;CAC9D,MAAM,QAAQ,cAAc,qBAAqB,OAAO,GAAG,CAAC,OAAO,CAAC;CACpE,MAAM,mBAAmB,aACtB,YAAuC,wBAAwB;EAAE,GAAG;EAAS;CAAW,CAAC,GAC1F,CAAC,UAAU,CACb;CACA,MAAM,aAAa,mBAAmB;EAAE;EAAO;EAAO;CAAiB,CAAC;CAGxE,MAAM,SAAS,aACZ,QAAgB,UAAkB;EACjC,MAAM,OAAO,SAAS,IAAI,WAAW,KAAK,CAAC,CAAC,MAAM;EAClD,IAAI,MACF,WAAW,MAAM;GACf,MAAM;GACN,IAAI;GACJ,QAAQ,EAAE,MAAM;IAAE,OAAO,KAAK,KAAK;IAAO,QAAQ,KAAK,KAAK,SAAS;GAAM,EAAE;EAC/E,CAAC;CAEL,GACA,CAAC,UAAU,UAAU,CACvB;CAEA,MAAM,OAAO,SAAS,WAAW,QAAQ,OAAO,YAAY;CAE5D,OACE,oBAAC,eAAe,UAAhB;EAAyB,OAAO;GAAE;GAAY,UAAU;GAAe;EAAO;EAC5E,UAAA,oBAAC,MAAD,EAAA,UACE,oBAAC,mBAAD;GAAuB;GACrB,UAAA,qBAAC,UAAU,MAAX;IACS;IACP,MAAM;IACC;IACP,OAAO;IACK;IALd,UAAA;KAOE,oBAAC,UAAU,QAAX,EAAkB,SAAS,oBAAC,SAAD;MAAqB;MAAwB;KAAa,CAAA,EAAI,CAAA;KACzF,oBAAC,UAAU,YAAX,CAAuB,CAAA;KACvB,oBAAC,UAAU,SAAX,CAAoB,CAAA;KACpB,oBAAC,UAAU,OAAX,CAAkB,CAAA;KAClB,oBAAC,UAAU,SAAX,CAAoB,CAAA;IACN;;EACC,CAAA,EACf,CAAA;CACiB,CAAA;AAE7B;AAEA,IAAM,aAAa,UACjB,oBAAC,OAAO,MAAR;CAAa,GAAI;CAAO,YAAW;AAA2C,CAAA;AAGhF,IAAM,sBAAsB,WAAoC;CAC9D,MAAM,KAAK,IAAI,YAAY,MAAM;CACjC,MAAM,wBAAwB,MAAM,cAAc,aAAa,qBAAqB;CACpF,MAAM,CAAC,gBAAgB,UAAU,OAAO,YAAY;CACpD,MAAM,aAAa,cAAc;EAC/B,IAAI,CAAC,OAAO,cAAc,UAAU,CAAC,IACnC,OAAO;EAET,MAAM,UAAU,GAAG;EACnB,MAAM,QAAQ,IAAI,kBAAkB,OAAO,cAAc,MAAM;EAC/D,MAAM,aAAa,gBAAgB,QACjC,EAAE,OAAO,QAAQ,GACjB,UAAU,WACV,SAAS,SACT,WAAW,oBACX,UAAU,SACV,kBAAkB,OACpB;EAQA,OAAO,IADgB,uBAAuB,EAL5C,iBAAuB,WACrB,sBAAsB,eAAe,OAAO,KAAK,OAAO,QAAQ,UAAU,CAAC,CAAQ,EAIzC,GAAqB,KAC5D;CACT,GAAG;EAAC;EAAc;EAAI;CAAqB,CAAC;CAE5C,gBAAgB;EACd,IAAI,CAAC,YACH;EAGF,WAAgB,KAAK;EACrB,aAAa;GACX,WAAgB,MAAM;EACxB;CACF,GAAG,CAAC,UAAU,CAAC;CAGf,gBAAgB;EACd,MAAM,OAAO,OAAO,cAAc;EAClC,IAAI,CAAC,QAAQ,CAAC,YACZ;EAGF,OAAO,IAAI,UAAU,YAAY,WAAW,MAAM,KAAK,CAAC;CAC1D,GAAG,CAAC,OAAO,cAAc,QAAQ,UAAU,CAAC;CAE5C,OAAO;AACT"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region PLUGIN.mdl?raw
|
|
2
|
+
var PLUGIN_default = "---\nid: org.dxos.plugin.conductor\nname: ConductorPlugin\nversion: 0.1.0\n---\n\nVisual node-based compute graph plugin for `DXOS` Composer — wire data sources, AI models, logic, and transformations into reactive pipelines that execute in the local-first runtime.\n\n## Extensions\n\nThe following extension dialects are used in this document.\nEach extension is defined in the Appendix or resolved via its URI.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `scenario` | `org.dxos.mdl.scenario@1.0` |\n| `component` | `org.dxos.mdl.component@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n| `test` | `org.dxos.mdl.test@1.0` |\n\n## Types\n\n```mdl\ntype ComputeValueType\n literals: string | number | boolean | object\n```\n\n```mdl\ntype NodeType\n literals:\n input | output | constant | template | switch | rng |\n audio | chat | text | json | json-transform | surface |\n beacon | scope | reducer | thread | queue | make-queue | append |\n and | or | not | if | if-else |\n function | gpt | gpt-realtime |\n database | text-to-image\n```\n\n```mdl\ntype ComputeNode\n desc: A node in the compute graph persisted via ECHO.\n extends: [Graph.Node]\n fields:\n inputSchema?: JsonSchema\n outputSchema?: JsonSchema\n subgraph?: Ref<ComputeGraph> # composition: nested graph\n function?: Ref<PersistentOperation> # composition: reusable function node\n valueType?: ComputeValueType # for constant/template nodes\n value?: any # for constant and template nodes\n enabled?: boolean # for switch nodes\n```\n\n```mdl\ntype ComputeEdge\n desc: A directed edge connecting an output port on one node to an input port on another.\n extends: [Graph.Edge]\n fields:\n input: string # target node input property name\n output: string # source node output property name\n```\n\n```mdl\ntype ComputeGraph\n desc: Persistent ECHO object holding the full node-edge graph plus special I/O reference nodes.\n fields:\n graph: Graph.Graph\n input?: ComputeNode\n output?: ComputeNode\n```\n\n```mdl\ntype ValueBag\n desc: A set of named asynchronous value effects passed between nodes.\n fields:\n _tag: \"ValueBag\"\n values: Record<string, ValueEffect<any>>\n```\n\n## Components\n\n```mdl\ncomponent CanvasArticle\n desc: Full-screen canvas editor for a ComputeGraph; renders as an article or a section embed.\n props:\n role: \"article\" | \"section\"\n subject: CanvasBoard\n attendableId?: string\n state:\n graph: CanvasGraphModel<ComputeShape>\n controller?: ComputeGraphController\n registry: ShapeRegistry\n layout?: ComputeShapeLayout\n slots:\n toolbar?: ReactNode # injected by AppSurface frame\n layout: |\n ┌──────────────────────────────────────────────┐\n │ [toolbar — zoom, tools, minimap] │\n ├──────────────────────────────────────────────┤\n │ │\n │ ┌──────┐ ┌──────┐ ┌──────┐ │\n │ │ node │───▶│ node │───▶│ node │ │\n │ └──────┘ └──────┘ └──────┘ │\n │ │\n │ canvas — pan / zoom / connect nodes │\n └──────────────────────────────────────────────┘\n```\n\n## Operations\n\nPure operations — no effects, no service dependencies.\n\n```mdl\nop evalConstant\n desc: Returns the scalar value stored on a constant node.\n input:\n node: ComputeNode\n output: Scalar\n errors:\n MissingValue: node has no value set\n```\n\n```mdl\nop jsonTransform\n desc: Evaluates a JSONPath expression over an input value.\n input:\n input: any\n expression: string\n output: any\n errors:\n InvalidExpression: JSONPath expression could not be parsed\n```\n\n```mdl\nop boolAnd\n desc: Logical AND of two boolean inputs.\n input:\n a: boolean\n b: boolean\n output: boolean\n```\n\n```mdl\nop boolOr\n desc: Logical OR of two boolean inputs.\n input:\n a: boolean\n b: boolean\n output: boolean\n```\n\n```mdl\nop boolNot\n desc: Logical NOT of a boolean input.\n input:\n input: boolean\n output: boolean\n```\n\n```mdl\nop ifRoute\n desc: Routes a value to the true or false output port based on a condition.\n input:\n condition: boolean\n value: any\n output: IfOutput # { true?: any; false?: any }\n```\n\n```mdl\nop ifElseSelect\n desc: Ternary — returns trueValue or falseValue depending on condition.\n input:\n condition: boolean\n true: any\n false: any\n output: any\n```\n\nEffectful operations — mutate persistent state or call external services.\n\n```mdl\nop appendToQueue\n desc: Appends items to an ECHO queue or collection identified by DXN.\n input:\n id: string # DXN — dxn:queue or dxn:echo\n items: any[]\n output: void\n effects: [echo:write, feed:write]\n errors:\n UnsupportedDXN: DXN kind not supported\n SpaceMismatch: ECHO DXN belongs to a different space\n```\n\n```mdl\nop createQueue\n desc: Allocates a new append-only Feed and returns a Ref to it.\n input:\n output: Ref<Feed>\n effects: [feed:write]\n```\n\n```mdl\nop invokeGpt\n desc: Sends the current conversation thread to the configured AI model and streams the reply.\n input:\n thread: Ref<Thread>\n tools?: Tool[]\n systemPrompt?: string\n output: Message\n effects: [http]\n requires: [AiService]\n errors:\n ModelUnavailable: AI service could not be reached\n```\n\n```mdl\nop invokeFunction\n desc: Deserialises a PersistentOperation from ECHO and invokes it with the provided input bag.\n input:\n function: Ref<PersistentOperation>\n input: any\n output: any\n effects: [echo:read]\n requires: [Database.Service, OperationRegistry.Service]\n errors:\n FunctionNotFound: referenced operation does not exist\n InvocationFailed: operation returned an error\n```\n\n## Features\n\n```mdl\nfeat F-1: Canvas Editor\n\n req F-1.1: User can create a new compute graph via the \"Create object\" entry.\n req F-1.2: Canvas renders nodes as draggable, resizable shapes on an infinite panning surface.\n req F-1.3:\n when: user drags from an output port to an input port\n then: a ComputeEdge is created connecting the two ports\n req F-1.4:\n when: a ComputeEdge is deleted\n then: downstream nodes stop receiving values from the disconnected output\n```\n\n```mdl\nfeat F-2: Node Palette\n\n req F-2.1: Toolbar exposes all built-in NodeTypes; user can drag them onto the canvas.\n req F-2.2: Constant nodes display an inline editor for their scalar value and valueType.\n req F-2.3: Template nodes render a text input with {{variable}} interpolation.\n req F-2.4: Function nodes allow selecting a PersistentOperation from the space.\n```\n\n```mdl\nfeat F-3: Reactive Execution\n\n req F-3.1:\n when: any upstream node value changes\n then: ComputeGraphController re-evaluates dependent nodes in topological order\n\n req F-3.2: Node execution is lazy; nodes only run when their outputs are consumed.\n\n req F-3.3:\n when: a node fails with ConductorError\n then: downstream nodes receive a NotExecuted marker and do not throw\n\n req F-3.4:\n when: a node emits a ValueBag\n then: individual output ports can resolve at different times (async bag semantics)\n```\n\n```mdl\nfeat F-4: AI Integration\n\n req F-4.1: GPT node connects to AiService; configuration includes model, system prompt, and tools.\n req F-4.2:\n when: GPT node executes\n then: op:invokeGpt streams the model response back to the output port\n\n req F-4.3: Function node can reference any PersistentOperation registered in the space.\n```\n\n```mdl\nfeat F-5: Data Sources and Sinks\n\n req F-5.1: Queue node reads messages from a Feed referenced by DXN.\n req F-5.2: Append node writes items to a Feed or ECHO collection referenced by DXN.\n req F-5.3: Database node exposes ECHO space contents as a query tool for AI nodes.\n req F-5.4: Thread node surfaces a conversation thread with its message history.\n```\n\n```mdl\nfeat F-6: Logic and Control Flow\n\n req F-6.1: If node routes a value to true or false output port based on a boolean condition.\n req F-6.2: IfElse node selects one of two values using a ternary condition.\n req F-6.3: Reducer node collects an array of values from multiple upstream ports.\n req F-6.4: And / Or / Not nodes implement standard boolean combinators.\n```\n\n```mdl\nfeat F-7: Persistence and Collaboration\n\n req F-7.1: ComputeGraph is stored as an ECHO object; graph topology is replicated to peers.\n req F-7.2:\n when: a peer modifies a node value or edge\n then: all collaborators see the change reflected on the canvas in real time\n\n req F-7.3:\n when: a CanvasBoard is embedded as a section in another document\n then: the graph renders in the section aspect-square container and remains interactive\n```\n\n## Acceptance\n\n```mdl\nscenario T-1: Create empty graph\n given: user opens the Create Object menu\n when: user selects \"Compute Graph\"\n then:\n - a new CanvasBoard with an empty ComputeGraph is created in the space\n - the canvas opens with no nodes\n```\n\n```mdl\nscenario T-2: Add constant node and read value\n given: an empty canvas\n when: user adds a constant node, sets value \"hello\", connects it to a text node\n then:\n - text node receives \"hello\" on its input port\n - text node renders \"hello\"\n```\n\n```mdl\nscenario T-3: Boolean AND gate\n given: two switch nodes with values true and false connected to an AND node\n when: graph executes\n then:\n - AND node output is false\n - switching both inputs to true produces output true\n```\n\n```mdl\nscenario T-4: JSONPath transform\n given: a constant node with value { \"a\": { \"b\": 42 } } connected to a json-transform node\n when: expression \"$.a.b\" is set on the transform node\n then:\n - output port value is [42]\n```\n\n```mdl\nscenario T-5: GPT node invocation\n given: a thread node connected to a GPT node with a system prompt\n when: graph executes with AiService available\n then:\n - GPT node output port receives a Message\n - Message content is non-empty\n errors: [ModelUnavailable]\n```\n\n```mdl\nscenario T-6: Append to queue\n given: a make-queue node connected to an append node; constant node provides input items\n when: graph executes\n then:\n - queue contains the appended items\n - downstream queue node reads them back\n```\n\n```mdl\nscenario T-7: Collaborative edit\n given: two peers have the same CanvasBoard open\n when: peer A moves a node on the canvas\n then:\n - peer B sees the node in the new position within one replication round-trip\n tags: [collaborative]\n```\n\n```mdl\nscenario T-8: NotExecuted propagation\n given: an if node whose condition is false, connected to a text node on the true port\n when: graph executes\n then:\n - text node receives a NotExecuted marker\n - text node renders nothing (no error thrown)\n```\n\n## QA\n\nExecutable tests. Each step carries a human instruction (`do`) and, where the step maps to an\ninvocable operation, an agent binding (`invoke`). Report failures by test and step number.\n\n```mdl\ntest QA-1: Build and run a small compute graph\n desc: |\n The core canvas round-trip — create a graph, wire a constant into a JSON transform, and read\n the reactive result. None of the node kernels (`evalConstant`, `jsonTransform`, ...) are\n registered operations: they run inside the graph's own reactive controller when the canvas\n triggers evaluation, not through the operation invoker, so this test is entirely human — the\n same gap plugin-chess documents for move-less game creation.\n actors: human\n covers: [F-1.1, F-1.2, F-1.3, F-2.1, F-2.2, F-3.1, F-3.2, T-1, T-2]\n status: unverified\n given:\n - an identity exists\n - space: a space is open\n - collection: a collection in that space, to create into\n - no CanvasBoard named \"QA Graph\" exists — ABORT rather than deleting one this test did not\n create\n steps:\n - name: Create the graph\n do: In the navtree, click + on a collection and choose Compute Graph. Name it \"QA Graph\".\n expect: an empty CanvasBoard/ComputeGraph opens on the canvas\n note: |\n NO `invoke` — \"Create object\" for CanvasBoard constructs the object locally and only\n calls `space.addObject` (see `create-object.ts`); there is no dedicated\n `createComputeGraph` operation despite F-1.1's phrasing, so this step is human-only.\n - name: Add a constant node\n do: Drag \"Constant\" from the node palette onto the canvas. Set its value to 42 and\n valueType to \"number\".\n expect: a constant node appears on the canvas showing 42\n - name: Add a JSON transform node\n do: Drag \"JSON Transform\" onto the canvas. Set its expression to \"$\".\n expect: a JSON transform node appears on the canvas\n - name: Wire them together\n do: Drag from the constant node's output port to the JSON transform node's input port.\n expect: a ComputeEdge connects the two nodes\n - name: Read the result\n do: Click the JSON transform node to inspect its output, or connect a text/output node to it.\n expect: the transform node's output shows 42 (its own re-evaluation, triggered by the\n upstream constant, per F-3.1's topological order)\n after:\n - name: Delete the graph\n do: Right-click \"QA Graph\" in the navtree and choose Delete.\n invoke: |\n org.dxos.operation.space.removeObjects {\n objects: [(await space.db.query(dxos.Filter.type(dxos.DXN.make('org.dxos.type.canvasBoard'))).run()).objects\n .find((o) => o.name === 'QA Graph')\n ?? (() => { throw new Error(\"CanvasBoard QA Graph not found — refusing to remove an unrelated object\"); })()],\n target: $given.collection\n }\n expect: the row leaves the navtree and its plank closes\n note: |\n No captured id exists — the create step has no `invoke` (see above) — so this resolves\n \"QA Graph\" by typename AND name — a name match alone would delete any object carrying it, and throws rather than removing anything when the name does not\n match, since `given` guarantees no pre-existing board carries it.\n```\n\n---\n\n## Appendix: Extension Definitions\n\n```mdl\next type\n uri: org.dxos.mdl.type@1.0\n desc: A named data structure with typed fields and optional literals.\n fields:\n desc?: Prose\n fields?: FieldMap\n literals?: UnionList\n extends?: TypeRef[]\n```\n\n```mdl\next feat\n uri: org.dxos.mdl.feat@1.0\n desc: A named feature grouping one or more requirements.\n fields:\n desc?: Prose\n req: RequirementList\n nesting: self\n```\n\n```mdl\next scenario\n uri: org.dxos.mdl.scenario@1.0\n desc: An acceptance scenario expressed as given / when / then steps.\n fields:\n given?: Step | Step[]\n when?: Step | Step[]\n then: Step | Step[]\n tags?: TagList\n```\n\n```mdl\next component\n uri: org.dxos.mdl.component@1.0\n desc: A UI component with props, internal state, slots, actions, and events.\n fields:\n desc?: Prose\n props?: FieldMap\n state?: FieldMap\n slots?: FieldMap\n actions?: ActionMap\n emits?: EventMap\n layout?: CodeBlock\n```\n\n```mdl\next op\n uri: org.dxos.mdl.op@1.0\n desc: |\n A named operation with typed inputs, outputs, and declared errors.\n Pure ops have no effects or requires. Effectful ops declare both.\n fields:\n desc?: Prose\n input?: FieldMap\n output?: TypeExpr\n errors?: ErrorMap\n effects?: EffectList\n requires?: ServiceList\n note?: Prose\n```\n";
|
|
3
|
+
//#endregion
|
|
4
|
+
export { PLUGIN_default as t };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=chunk-PLUGIN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-PLUGIN.mjs","names":[],"sources":[],"mappings":""}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
2
|
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
3
|
import * as Capabilities from "@dxos/app-framework/Capabilities";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import * as Surface from "@dxos/app-framework/Surface";
|
|
5
|
+
import * as AppSurface from "@dxos/app-toolkit/AppSurface";
|
|
6
6
|
import { CanvasBoard } from "@dxos/react-ui-canvas-editor";
|
|
7
7
|
import { CanvasArticle } from "#containers";
|
|
8
8
|
//#region src/capabilities/react-surface.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-react-surface.mjs","names":[],"sources":["../../src/capabilities/react-surface.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport
|
|
1
|
+
{"version":3,"file":"chunk-react-surface.mjs","names":[],"sources":["../../src/capabilities/react-surface.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Surface from '@dxos/app-framework/Surface';\nimport * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport { CanvasBoard } from '@dxos/react-ui-canvas-editor';\n\nimport { CanvasArticle } from '#containers';\n\nexport default Capability.makeModule(() =>\n Effect.succeed(\n Capability.contribute(\n Capabilities.ReactSurface,\n Surface.create({\n id: 'root',\n // TODO(wittjosiah): Split into multiple surfaces if this filter proves too strict for non-article roles.\n filter: AppSurface.oneOf(\n AppSurface.object(AppSurface.Article, CanvasBoard.CanvasBoard),\n AppSurface.object(AppSurface.Section, CanvasBoard.CanvasBoard),\n ),\n component: CanvasArticle,\n props: ({ role, data: { subject, attendableId } }) => ({ role, subject, attendableId }),\n }),\n ),\n ),\n);\n"],"mappings":";;;;;;;;AAcA,IAAA,wBAAe,WAAW,iBACxB,OAAO,QACL,WAAW,WACT,aAAa,cACb,QAAQ,OAAO;CACb,IAAI;CAEJ,QAAQ,WAAW,MACjB,WAAW,OAAO,WAAW,SAAS,YAAY,WAAW,GAC7D,WAAW,OAAO,WAAW,SAAS,YAAY,WAAW,CAC/D;CACA,WAAW;CACX,QAAQ,EAAE,MAAM,MAAM,EAAE,SAAS,sBAAsB;EAAE;EAAM;EAAS;CAAa;AACvF,CAAC,CACH,CACF,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"containers.mjs","names":[],"sources":["../../src/containers/index.ts"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type ComponentType, lazy } from 'react';\n\nexport const CanvasArticle: ComponentType<any> = lazy(() => import('./CanvasArticle'));\n"],"mappings":";;AAMA,IAAa,gBAAoC,WAAW,OAAO,
|
|
1
|
+
{"version":3,"file":"containers.mjs","names":[],"sources":["../../src/containers/index.ts"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type ComponentType, lazy } from 'react';\n\nexport const CanvasArticle: ComponentType<any> = lazy(() => import('./CanvasArticle/index.ts'));\n"],"mappings":";;AAMA,IAAa,gBAAoC,WAAW,OAAO,4BAA2B"}
|
package/dist/lib/index.mjs
CHANGED
package/dist/lib/meta.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta.mjs","names":[],"sources":["../../dx.config.ts","../../src/meta.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.conductor',\n name: 'Conductor',\n author: 'DXOS',\n description: trim`\n Conductor is a visual node-based compute graph plugin for DXOS Composer.\n It lets you compose reactive data pipelines by connecting typed input and output ports on a\n drag-and-drop infinite canvas — no code required for common automation patterns.\n\n Each node in the graph is a first-class ECHO object, so the full pipeline topology is\n replicated to every collaborator in real time via the local-first runtime.\n Built-in node types cover constants, templates, boolean logic, control flow, JSON transforms,\n ECHO database access, append-only queues, and conversation threads.\n\n AI orchestration is a first-class concern: the GPT node connects to plugin-assistant's AiService\n and supports tool calling, streaming replies, and configurable system prompts.\n Function nodes can invoke any Skill operation registered in the space, making it straightforward\n to compose multi-step agent workflows visually and share them across teams.\n `,\n icon: { key: 'ph--infinity--regular', hue: 'sky' },\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-conductor',\n spec: 'PLUGIN.mdl',\n tags: ['labs'],\n screenshots: [{ dark: 'https://media.dxos.network/plugin-details-canvas-dark.png' }],\n },\n});\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\n\nimport config from '../dx.config';\n\nexport const meta = Plugin.getMetaFromConfig(config);\n"],"mappings":";;;;AAOA,IAAA,oBAAe,QAAQ,KAAK,EAC1B,QAAQ;CACN,KAAK;CACL,MAAM;CACN,QAAQ;CACR,aAAa,IAAI;;;;;;;;;;;;;;;CAejB,MAAM;EAAE,KAAK;EAAyB,KAAK;CAAM;CACjD,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,MAAM;CACb,aAAa,CAAC,EAAE,MAAM,4DAA4D,CAAC;AACrF,EACF,CAAC;;;ACzBD,IAAa,OAAO,OAAO,kBAAkB,iBAAM"}
|
|
1
|
+
{"version":3,"file":"meta.mjs","names":[],"sources":["../../dx.config.ts","../../src/meta.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Config2 } from '@dxos/app-framework/config';\nimport { trim } from '@dxos/util';\n\nexport default Config2.make({\n plugin: {\n key: 'org.dxos.plugin.conductor',\n name: 'Conductor',\n author: 'DXOS',\n description: trim`\n Conductor is a visual node-based compute graph plugin for DXOS Composer.\n It lets you compose reactive data pipelines by connecting typed input and output ports on a\n drag-and-drop infinite canvas — no code required for common automation patterns.\n\n Each node in the graph is a first-class ECHO object, so the full pipeline topology is\n replicated to every collaborator in real time via the local-first runtime.\n Built-in node types cover constants, templates, boolean logic, control flow, JSON transforms,\n ECHO database access, append-only queues, and conversation threads.\n\n AI orchestration is a first-class concern: the GPT node connects to plugin-assistant's AiService\n and supports tool calling, streaming replies, and configurable system prompts.\n Function nodes can invoke any Skill operation registered in the space, making it straightforward\n to compose multi-step agent workflows visually and share them across teams.\n `,\n icon: { key: 'ph--infinity--regular', hue: 'sky' },\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-conductor',\n spec: 'PLUGIN.mdl',\n tags: ['labs'],\n screenshots: [{ dark: 'https://media.dxos.network/plugin-details-canvas-dark.png' }],\n },\n});\n","//\n// Copyright 2023 DXOS.org\n//\n\nimport * as Plugin from '@dxos/app-framework/Plugin';\n\nimport config from '../dx.config.ts';\n\nexport const meta = Plugin.getMetaFromConfig(config);\n"],"mappings":";;;;AAOA,IAAA,oBAAe,QAAQ,KAAK,EAC1B,QAAQ;CACN,KAAK;CACL,MAAM;CACN,QAAQ;CACR,aAAa,IAAI;;;;;;;;;;;;;;;CAejB,MAAM;EAAE,KAAK;EAAyB,KAAK;CAAM;CACjD,QAAQ;CACR,MAAM;CACN,MAAM,CAAC,MAAM;CACb,aAAa,CAAC,EAAE,MAAM,4DAA4D,CAAC;AACrF,EACF,CAAC;;;ACzBD,IAAa,OAAO,OAAO,kBAAkB,iBAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translations.mjs","names":[],"sources":["../../src/translations.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Type } from '@dxos/echo';\nimport {
|
|
1
|
+
{"version":3,"file":"translations.mjs","names":[],"sources":["../../src/translations.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Type } from '@dxos/echo';\nimport { CanvasBoard } from '@dxos/react-ui-canvas-editor/types';\nimport type * as Theme from '@dxos/react-ui/Theme';\n\nimport { meta } from '#meta';\n\nexport const translations = [\n {\n 'en-US': {\n [Type.getTypename(CanvasBoard.CanvasBoard)]: {\n 'typename.label': 'Circuit',\n 'typename.label_zero': 'Circuits',\n 'typename.label_one': 'Circuit',\n 'typename.label_other': 'Circuits',\n 'object-name.placeholder': 'New circuit',\n 'add-object.label': 'Add circuit',\n 'rename-object.label': 'Rename circuit',\n 'delete-object.label': 'Delete circuit',\n 'object-deleted.label': 'Circuit deleted',\n },\n [meta.profile.key]: {\n 'plugin.name': 'Conductor',\n 'content.placeholder': 'Enter text...',\n },\n },\n },\n] as const satisfies Theme.Resource[];\n"],"mappings":";;;;AAUA,IAAa,eAAe,CAC1B,EACE,SAAS;EACN,KAAK,YAAY,YAAY,WAAW,IAAI;EAC3C,kBAAkB;EAClB,uBAAuB;EACvB,sBAAsB;EACtB,wBAAwB;EACxB,2BAA2B;EAC3B,oBAAoB;EACpB,uBAAuB;EACvB,uBAAuB;EACvB,wBAAwB;CAC1B;EACC,KAAK,QAAQ,MAAM;EAClB,eAAe;EACf,uBAAuB;CACzB;AACF,EACF,CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const CreateObject: import("@dxos/app-framework/Capability").Module<void>;
|
|
2
|
+
export declare const PluginAsset: import("@dxos/app-framework/Capability").Module<void>;
|
|
3
|
+
export declare const ReactSurface: import("@dxos/app-framework/Capability").Module<void>;
|
|
4
|
+
export declare const Schema: import("@dxos/app-framework/Capability").Module<void>;
|
|
5
|
+
export declare const Translations: import("@dxos/app-framework/Capability").Module<void>;
|
|
6
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../../../src/capabilities/gen/browser.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,YAAY,uDAAoE,CAAC;AAE9F,eAAO,MAAM,WAAW,uDAKtB,CAAC;AAEH,eAAO,MAAM,YAAY,uDAEvB,CAAC;AAEH,eAAO,MAAM,MAAM,uDAAqD,CAAC;AAEzE,eAAO,MAAM,YAAY,uDAA2C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../../../src/capabilities/gen/node.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../../../src/capabilities/gen/node.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,YAAY,uDAAoE,CAAC;AAE9F,eAAO,MAAM,MAAM,uDAAqD,CAAC;AAEzE,eAAO,MAAM,YAAY,uDAA2C,CAAC;AAErE,eAAO,MAAM,WAAW,WAAY,CAAC;AACrC,eAAO,MAAM,YAAY,WAAY,CAAC"}
|