@dxos/plugin-registry 0.8.4-main.937b3ca → 0.8.4-main.9be5663bfe

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/dist/lib/browser/cli/index.mjs +15 -19
  2. package/dist/lib/browser/cli/index.mjs.map +3 -3
  3. package/dist/lib/browser/index.mjs +50 -41
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/node-esm/cli/index.mjs +15 -18
  7. package/dist/lib/node-esm/cli/index.mjs.map +3 -3
  8. package/dist/lib/node-esm/index.mjs +51 -41
  9. package/dist/lib/node-esm/index.mjs.map +4 -4
  10. package/dist/lib/node-esm/meta.json +1 -1
  11. package/dist/types/src/RegistryPlugin.d.ts.map +1 -1
  12. package/dist/types/src/capabilities/app-graph-builder.d.ts +6 -0
  13. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  14. package/dist/types/src/capabilities/index.d.ts +5 -3
  15. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  16. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  17. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  18. package/dist/types/src/capabilities/react-surface.d.ts +5 -0
  19. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  20. package/dist/types/src/cli/commands/disable.d.ts +2 -2
  21. package/dist/types/src/cli/commands/enable.d.ts +2 -2
  22. package/dist/types/src/cli/plugin.d.ts.map +1 -1
  23. package/dist/types/src/cli/storage.d.ts +4 -4
  24. package/dist/types/src/cli/storage.d.ts.map +1 -1
  25. package/dist/types/src/components/PluginDetail/PluginDetail.d.ts +11 -0
  26. package/dist/types/src/components/PluginDetail/PluginDetail.d.ts.map +1 -0
  27. package/dist/types/src/components/PluginDetail/PluginDetail.stories.d.ts +39 -0
  28. package/dist/types/src/components/PluginDetail/PluginDetail.stories.d.ts.map +1 -0
  29. package/dist/types/src/components/PluginDetail/index.d.ts +2 -0
  30. package/dist/types/src/components/PluginDetail/index.d.ts.map +1 -0
  31. package/dist/types/src/components/PluginList/PluginItem.d.ts.map +1 -0
  32. package/dist/types/src/components/PluginList/PluginList.d.ts.map +1 -0
  33. package/dist/types/src/components/PluginList/PluginList.stories.d.ts +38 -0
  34. package/dist/types/src/components/PluginList/PluginList.stories.d.ts.map +1 -0
  35. package/dist/types/src/components/PluginList/index.d.ts +2 -0
  36. package/dist/types/src/components/PluginList/index.d.ts.map +1 -0
  37. package/dist/types/src/components/index.d.ts +0 -1
  38. package/dist/types/src/components/index.d.ts.map +1 -1
  39. package/dist/types/src/containers/LoadPluginDialog/LoadPluginDialog.d.ts +4 -0
  40. package/dist/types/src/containers/LoadPluginDialog/LoadPluginDialog.d.ts.map +1 -0
  41. package/dist/types/src/containers/LoadPluginDialog/index.d.ts +2 -0
  42. package/dist/types/src/containers/LoadPluginDialog/index.d.ts.map +1 -0
  43. package/dist/types/src/containers/PluginArticle/PluginArticle.d.ts +7 -0
  44. package/dist/types/src/containers/PluginArticle/PluginArticle.d.ts.map +1 -0
  45. package/dist/types/src/containers/PluginArticle/index.d.ts +2 -0
  46. package/dist/types/src/containers/PluginArticle/index.d.ts.map +1 -0
  47. package/dist/types/src/containers/PluginRegistry/PluginRegistry.d.ts +10 -0
  48. package/dist/types/src/containers/PluginRegistry/PluginRegistry.d.ts.map +1 -0
  49. package/dist/types/src/containers/PluginRegistry/index.d.ts +2 -0
  50. package/dist/types/src/containers/PluginRegistry/index.d.ts.map +1 -0
  51. package/dist/types/src/containers/index.d.ts +6 -0
  52. package/dist/types/src/containers/index.d.ts.map +1 -0
  53. package/dist/types/src/meta.d.ts +5 -1
  54. package/dist/types/src/meta.d.ts.map +1 -1
  55. package/dist/types/src/operations/index.d.ts +3 -0
  56. package/dist/types/src/operations/index.d.ts.map +1 -0
  57. package/dist/types/src/operations/open-plugin-registry.d.ts +5 -0
  58. package/dist/types/src/operations/open-plugin-registry.d.ts.map +1 -0
  59. package/dist/types/src/translations.d.ts +19 -15
  60. package/dist/types/src/translations.d.ts.map +1 -1
  61. package/dist/types/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +41 -31
  63. package/src/RegistryPlugin.tsx +9 -7
  64. package/src/capabilities/app-graph-builder.ts +149 -0
  65. package/src/capabilities/index.ts +9 -3
  66. package/src/capabilities/operation-handler.ts +16 -0
  67. package/src/capabilities/react-surface.tsx +95 -0
  68. package/src/cli/plugin.ts +4 -3
  69. package/src/cli/storage.ts +14 -21
  70. package/src/components/{PluginDetail.stories.tsx → PluginDetail/PluginDetail.stories.tsx} +6 -6
  71. package/src/components/PluginDetail/PluginDetail.tsx +84 -0
  72. package/src/components/PluginDetail/index.ts +5 -0
  73. package/src/components/{PluginItem.tsx → PluginList/PluginItem.tsx} +16 -12
  74. package/src/components/PluginList/PluginList.stories.tsx +87 -0
  75. package/src/components/PluginList/index.ts +5 -0
  76. package/src/components/index.ts +0 -1
  77. package/src/containers/LoadPluginDialog/LoadPluginDialog.tsx +85 -0
  78. package/src/containers/LoadPluginDialog/index.ts +5 -0
  79. package/src/containers/PluginArticle/PluginArticle.tsx +28 -0
  80. package/src/containers/PluginArticle/index.ts +5 -0
  81. package/src/containers/PluginRegistry/PluginRegistry.tsx +94 -0
  82. package/src/containers/PluginRegistry/index.ts +5 -0
  83. package/src/containers/index.ts +10 -0
  84. package/src/meta.ts +12 -5
  85. package/src/operations/index.ts +7 -0
  86. package/src/operations/open-plugin-registry.ts +21 -0
  87. package/src/translations.ts +19 -15
  88. package/dist/lib/browser/app-graph-builder-P3ZGGFAR.mjs +0 -166
  89. package/dist/lib/browser/app-graph-builder-P3ZGGFAR.mjs.map +0 -7
  90. package/dist/lib/browser/chunk-VOAOTNGS.mjs +0 -19
  91. package/dist/lib/browser/chunk-VOAOTNGS.mjs.map +0 -7
  92. package/dist/lib/browser/operation-resolver-P5PKLPRT.mjs +0 -24
  93. package/dist/lib/browser/operation-resolver-P5PKLPRT.mjs.map +0 -7
  94. package/dist/lib/browser/react-surface-IIM6T7IA.mjs +0 -337
  95. package/dist/lib/browser/react-surface-IIM6T7IA.mjs.map +0 -7
  96. package/dist/lib/node-esm/app-graph-builder-56JXLOGZ.mjs +0 -167
  97. package/dist/lib/node-esm/app-graph-builder-56JXLOGZ.mjs.map +0 -7
  98. package/dist/lib/node-esm/chunk-SALMIZ2W.mjs +0 -21
  99. package/dist/lib/node-esm/chunk-SALMIZ2W.mjs.map +0 -7
  100. package/dist/lib/node-esm/operation-resolver-3ZB5W3T3.mjs +0 -25
  101. package/dist/lib/node-esm/operation-resolver-3ZB5W3T3.mjs.map +0 -7
  102. package/dist/lib/node-esm/react-surface-F67P7RC3.mjs +0 -338
  103. package/dist/lib/node-esm/react-surface-F67P7RC3.mjs.map +0 -7
  104. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts +0 -6
  105. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
  106. package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
  107. package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
  108. package/dist/types/src/capabilities/operation-resolver/index.d.ts +0 -3
  109. package/dist/types/src/capabilities/operation-resolver/index.d.ts.map +0 -1
  110. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts +0 -5
  111. package/dist/types/src/capabilities/operation-resolver/operation-resolver.d.ts.map +0 -1
  112. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  113. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  114. package/dist/types/src/capabilities/react-surface/react-surface.d.ts +0 -5
  115. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  116. package/dist/types/src/components/PluginDetail.d.ts +0 -9
  117. package/dist/types/src/components/PluginDetail.d.ts.map +0 -1
  118. package/dist/types/src/components/PluginDetail.stories.d.ts +0 -32
  119. package/dist/types/src/components/PluginDetail.stories.d.ts.map +0 -1
  120. package/dist/types/src/components/PluginItem.d.ts.map +0 -1
  121. package/dist/types/src/components/PluginList.d.ts.map +0 -1
  122. package/dist/types/src/components/PluginList.stories.d.ts +0 -34
  123. package/dist/types/src/components/PluginList.stories.d.ts.map +0 -1
  124. package/dist/types/src/components/RegistryContainer.d.ts +0 -8
  125. package/dist/types/src/components/RegistryContainer.d.ts.map +0 -1
  126. package/src/capabilities/app-graph-builder/app-graph-builder.ts +0 -136
  127. package/src/capabilities/app-graph-builder/index.ts +0 -7
  128. package/src/capabilities/operation-resolver/index.ts +0 -7
  129. package/src/capabilities/operation-resolver/operation-resolver.ts +0 -23
  130. package/src/capabilities/react-surface/index.ts +0 -7
  131. package/src/capabilities/react-surface/react-surface.tsx +0 -99
  132. package/src/components/PluginDetail.tsx +0 -79
  133. package/src/components/PluginList.stories.tsx +0 -77
  134. package/src/components/RegistryContainer.tsx +0 -83
  135. /package/dist/types/src/components/{PluginItem.d.ts → PluginList/PluginItem.d.ts} +0 -0
  136. /package/dist/types/src/components/{PluginList.d.ts → PluginList/PluginList.d.ts} +0 -0
  137. /package/src/components/{PluginList.tsx → PluginList/PluginList.tsx} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-registry",
3
- "version": "0.8.4-main.937b3ca",
3
+ "version": "0.8.4-main.9be5663bfe",
4
4
  "description": "Braneframe plugin gallery",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -12,17 +12,25 @@
12
12
  "author": "DXOS.org",
13
13
  "sideEffects": true,
14
14
  "type": "module",
15
+ "imports": {
16
+ "#capabilities": "./src/capabilities/index.ts",
17
+ "#components": "./src/components/index.ts",
18
+ "#containers": "./src/containers/index.ts",
19
+ "#meta": "./src/meta.ts",
20
+ "#operations": "./src/operations/index.ts",
21
+ "#types": "./src/types.ts"
22
+ },
15
23
  "exports": {
16
24
  ".": {
25
+ "source": "./src/index.ts",
17
26
  "browser": "./dist/lib/browser/index.mjs",
18
27
  "node": "./dist/lib/node-esm/index.mjs",
19
- "source": "./src/index.ts",
20
28
  "types": "./dist/types/src/index.d.ts"
21
29
  },
22
30
  "./cli": {
31
+ "source": "./src/cli/index.ts",
23
32
  "browser": "./dist/lib/browser/cli/index.mjs",
24
33
  "node": "./dist/lib/node-esm/cli/index.mjs",
25
- "source": "./src/cli/index.ts",
26
34
  "types": "./dist/types/src/cli/index.d.ts"
27
35
  }
28
36
  },
@@ -35,44 +43,46 @@
35
43
  "src"
36
44
  ],
37
45
  "dependencies": {
38
- "@effect-atom/atom-react": "^0.4.6",
39
- "@effect/cli": "0.72.1",
40
- "@dxos/app-framework": "0.8.4-main.937b3ca",
41
- "@dxos/cli-util": "0.8.4-main.937b3ca",
42
- "@dxos/echo": "0.8.4-main.937b3ca",
43
- "@dxos/client-protocol": "0.8.4-main.937b3ca",
44
- "@dxos/invariant": "0.8.4-main.937b3ca",
45
- "@dxos/effect": "0.8.4-main.937b3ca",
46
- "@dxos/operation": "0.8.4-main.937b3ca",
47
- "@dxos/plugin-graph": "0.8.4-main.937b3ca",
48
- "@dxos/plugin-observability": "0.8.4-main.937b3ca",
49
- "@dxos/react-ui-form": "0.8.4-main.937b3ca",
50
- "@dxos/react-ui-stack": "0.8.4-main.937b3ca",
51
- "@dxos/react-ui-mosaic": "0.8.4-main.937b3ca",
52
- "@dxos/util": "0.8.4-main.937b3ca"
46
+ "@effect-atom/atom-react": "^0.5.0",
47
+ "@effect/cli": "0.73.2",
48
+ "yaml": "^2.8.2",
49
+ "@dxos/app-toolkit": "0.8.4-main.9be5663bfe",
50
+ "@dxos/app-framework": "0.8.4-main.9be5663bfe",
51
+ "@dxos/cli-util": "0.8.4-main.9be5663bfe",
52
+ "@dxos/client-protocol": "0.8.4-main.9be5663bfe",
53
+ "@dxos/echo": "0.8.4-main.9be5663bfe",
54
+ "@dxos/invariant": "0.8.4-main.9be5663bfe",
55
+ "@dxos/plugin-graph": "0.8.4-main.9be5663bfe",
56
+ "@dxos/effect": "0.8.4-main.9be5663bfe",
57
+ "@dxos/plugin-observability": "0.8.4-main.9be5663bfe",
58
+ "@dxos/react-ui-form": "0.8.4-main.9be5663bfe",
59
+ "@dxos/react-ui-mosaic": "0.8.4-main.9be5663bfe",
60
+ "@dxos/util": "0.8.4-main.9be5663bfe",
61
+ "@dxos/react-ui-stack": "0.8.4-main.9be5663bfe",
62
+ "@dxos/operation": "0.8.4-main.9be5663bfe"
53
63
  },
54
64
  "devDependencies": {
55
- "@effect-atom/atom-react": "^0.4.6",
56
- "@effect/platform": "0.93.6",
65
+ "@effect-atom/atom-react": "^0.5.0",
66
+ "@effect/platform": "0.94.4",
57
67
  "@types/react": "~19.2.7",
58
68
  "@types/react-dom": "~19.2.3",
59
- "effect": "3.19.11",
69
+ "effect": "3.20.0",
60
70
  "react": "~19.2.3",
61
71
  "react-dom": "~19.2.3",
62
- "vite": "7.1.9",
63
- "@dxos/random": "0.8.4-main.937b3ca",
64
- "@dxos/storybook-utils": "0.8.4-main.937b3ca",
65
- "@dxos/ui-theme": "0.8.4-main.937b3ca",
66
- "@dxos/react-ui": "0.8.4-main.937b3ca"
72
+ "vite": "^7.1.11",
73
+ "@dxos/random": "0.8.4-main.9be5663bfe",
74
+ "@dxos/storybook-utils": "0.8.4-main.9be5663bfe",
75
+ "@dxos/ui-theme": "0.8.4-main.9be5663bfe",
76
+ "@dxos/react-ui": "0.8.4-main.9be5663bfe"
67
77
  },
68
78
  "peerDependencies": {
69
- "@effect-atom/atom-react": "^0.4.6",
70
- "@effect/platform": "0.93.6",
71
- "effect": "3.19.11",
79
+ "@effect-atom/atom-react": "^0.5.0",
80
+ "@effect/platform": "0.94.4",
81
+ "effect": "3.20.0",
72
82
  "react": "~19.2.3",
73
83
  "react-dom": "~19.2.3",
74
- "@dxos/react-ui": "0.8.4-main.937b3ca",
75
- "@dxos/ui-theme": "0.8.4-main.937b3ca"
84
+ "@dxos/react-ui": "0.8.4-main.9be5663bfe",
85
+ "@dxos/ui-theme": "0.8.4-main.9be5663bfe"
76
86
  },
77
87
  "publishConfig": {
78
88
  "access": "public"
@@ -2,16 +2,18 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Common, Plugin } from '@dxos/app-framework';
5
+ import { Plugin } from '@dxos/app-framework';
6
+ import { AppPlugin } from '@dxos/app-toolkit';
7
+
8
+ import { AppGraphBuilder, OperationHandler, ReactSurface } from '#capabilities';
9
+ import { meta } from '#meta';
6
10
 
7
- import { AppGraphBuilder, OperationResolver, ReactSurface } from './capabilities';
8
- import { meta } from './meta';
9
11
  import { translations } from './translations';
10
12
 
11
13
  export const RegistryPlugin = Plugin.define(meta).pipe(
12
- Common.Plugin.addTranslationsModule({ translations }),
13
- Common.Plugin.addSurfaceModule({ activate: ReactSurface }),
14
- Common.Plugin.addOperationResolverModule({ activate: OperationResolver }),
15
- Common.Plugin.addAppGraphModule({ activate: AppGraphBuilder }),
14
+ AppPlugin.addAppGraphModule({ activate: AppGraphBuilder }),
15
+ AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),
16
+ AppPlugin.addSurfaceModule({ activate: ReactSurface }),
17
+ AppPlugin.addTranslationsModule({ translations }),
16
18
  Plugin.make,
17
19
  );
@@ -0,0 +1,149 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Option from 'effect/Option';
7
+
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { AppCapabilities, LayoutOperation, SettingsOperation } from '@dxos/app-toolkit';
10
+ import { Operation } from '@dxos/operation';
11
+ import { GraphBuilder, Node, NodeMatcher } from '@dxos/plugin-graph';
12
+
13
+ import { REGISTRY_ID, REGISTRY_KEY, registryCategoryId, meta } from '#meta';
14
+
15
+ import { LOAD_PLUGIN_DIALOG } from '../containers';
16
+
17
+ export default Capability.makeModule(
18
+ Effect.fnUntraced(function* () {
19
+ const capabilities = yield* Capability.Service;
20
+
21
+ const extensions = yield* Effect.all([
22
+ GraphBuilder.createExtension({
23
+ id: 'open-registry',
24
+ match: NodeMatcher.whenRoot,
25
+ actions: () =>
26
+ Effect.succeed([
27
+ {
28
+ id: 'open-registry',
29
+ data: () => Operation.invoke(SettingsOperation.OpenPluginRegistry),
30
+ properties: {
31
+ label: ['open-plugin-registry.label', { ns: meta.id }],
32
+ icon: 'ph--squares-four--regular',
33
+ disposition: 'menu',
34
+ },
35
+ },
36
+ ]),
37
+ }),
38
+ GraphBuilder.createExtension({
39
+ id: 'registry',
40
+ match: NodeMatcher.whenRoot,
41
+ connector: () =>
42
+ Effect.succeed([
43
+ Node.make({
44
+ id: REGISTRY_ID,
45
+ type: meta.id,
46
+ properties: {
47
+ label: ['plugin-registry.label', { ns: meta.id }],
48
+ icon: 'ph--squares-four--regular',
49
+ disposition: 'pin-end',
50
+ testId: 'treeView.pluginRegistry',
51
+ },
52
+ nodes: [
53
+ Node.make({
54
+ id: registryCategoryId('all'),
55
+ type: 'category',
56
+ data: registryCategoryId('all'),
57
+ properties: {
58
+ label: ['all-plugins.label', { ns: meta.id }],
59
+ icon: 'ph--squares-four--regular',
60
+ key: REGISTRY_KEY,
61
+ testId: 'pluginRegistry.all',
62
+ },
63
+ }),
64
+ Node.make({
65
+ id: registryCategoryId('installed'),
66
+ type: 'category',
67
+ data: registryCategoryId('installed'),
68
+ properties: {
69
+ label: ['installed-plugins.label', { ns: meta.id }],
70
+ icon: 'ph--check--regular',
71
+ key: REGISTRY_KEY,
72
+ testId: 'pluginRegistry.installed',
73
+ },
74
+ }),
75
+ Node.make({
76
+ id: registryCategoryId('recommended'),
77
+ type: 'category',
78
+ data: registryCategoryId('recommended'),
79
+ properties: {
80
+ label: ['recommended-plugins.label', { ns: meta.id }],
81
+ icon: 'ph--star--regular',
82
+ key: REGISTRY_KEY,
83
+ testId: 'pluginRegistry.recommended',
84
+ },
85
+ }),
86
+ Node.make({
87
+ id: registryCategoryId('labs'),
88
+ type: 'category',
89
+ data: registryCategoryId('labs'),
90
+ properties: {
91
+ label: ['labs-plugins.label', { ns: meta.id }],
92
+ icon: 'ph--flask--regular',
93
+ key: REGISTRY_KEY,
94
+ testId: 'pluginRegistry.labs',
95
+ },
96
+ }),
97
+ ],
98
+ }),
99
+ ]),
100
+ }),
101
+ GraphBuilder.createExtension({
102
+ id: 'actions',
103
+ match: NodeMatcher.whenAny(NodeMatcher.whenId(`root/${REGISTRY_ID}`), (node) =>
104
+ node.properties.key === REGISTRY_KEY ? Option.some(node) : Option.none(),
105
+ ),
106
+ actions: () =>
107
+ Effect.succeed([
108
+ {
109
+ id: 'load-by-url',
110
+ data: Effect.fnUntraced(function* () {
111
+ yield* Operation.invoke(LayoutOperation.UpdateDialog, {
112
+ subject: LOAD_PLUGIN_DIALOG,
113
+ state: true,
114
+ });
115
+ }),
116
+ properties: {
117
+ label: ['load-by-url.label', { ns: meta.id }],
118
+ icon: 'ph--cloud-arrow-down--regular',
119
+ disposition: 'list-item-primary',
120
+ },
121
+ },
122
+ ]),
123
+ }),
124
+ GraphBuilder.createExtension({
125
+ id: 'plugins',
126
+ match: NodeMatcher.whenId(`root/${REGISTRY_ID}`),
127
+ connector: () => {
128
+ const manager = capabilities.get(Capabilities.PluginManager);
129
+ return Effect.succeed(
130
+ manager.getPlugins().map((plugin) =>
131
+ Node.make({
132
+ id: plugin.meta.id,
133
+ type: 'org.dxos.plugin',
134
+ data: plugin,
135
+ properties: {
136
+ label: plugin.meta.name ?? plugin.meta.id,
137
+ icon: plugin.meta.icon ?? 'ph--circle--regular',
138
+ disposition: 'hidden',
139
+ },
140
+ }),
141
+ ),
142
+ );
143
+ },
144
+ }),
145
+ ]);
146
+
147
+ return Capability.contributes(AppCapabilities.AppGraphBuilder, extensions);
148
+ }),
149
+ );
@@ -2,6 +2,12 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export * from './app-graph-builder';
6
- export * from './operation-resolver';
7
- export * from './react-surface';
5
+ import { Capability } from '@dxos/app-framework';
6
+ import { OperationHandlerSet } from '@dxos/operation';
7
+
8
+ export const AppGraphBuilder = Capability.lazy('AppGraphBuilder', () => import('./app-graph-builder'));
9
+ export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
10
+ 'OperationHandler',
11
+ () => import('./operation-handler'),
12
+ );
13
+ export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import type { OperationHandlerSet } from '@dxos/operation';
9
+
10
+ import { RegistryOperationHandlerSet } from '#operations';
11
+
12
+ export default Capability.makeModule<OperationHandlerSet.OperationHandlerSet>(
13
+ Effect.fnUntraced(function* () {
14
+ return Capability.contributes(Capabilities.OperationHandler, RegistryOperationHandlerSet);
15
+ }),
16
+ );
@@ -0,0 +1,95 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import React, { useMemo } from 'react';
7
+
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { Surface, usePluginManager } from '@dxos/app-framework/ui';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
11
+
12
+ import { LOAD_PLUGIN_DIALOG, LoadPluginDialog, PluginArticle, PluginRegistry } from '#containers';
13
+ import { registryCategoryId } from '#meta';
14
+
15
+ export default Capability.makeModule(() =>
16
+ Effect.succeed(
17
+ Capability.contributes(Capabilities.ReactSurface, [
18
+ Surface.create({
19
+ id: 'all',
20
+ role: 'article',
21
+ filter: AppSurface.literalSection(registryCategoryId('all')),
22
+ component: () => {
23
+ const manager = usePluginManager();
24
+ const filtered = useMemo(
25
+ () => manager.getPlugins().filter(({ meta }) => !manager.getCore().includes(meta.id)),
26
+ [],
27
+ );
28
+
29
+ return <PluginRegistry id={registryCategoryId('all')} plugins={filtered} />;
30
+ },
31
+ }),
32
+ Surface.create({
33
+ id: 'installed',
34
+ role: 'article',
35
+ filter: AppSurface.literalSection(registryCategoryId('installed')),
36
+ component: () => {
37
+ const manager = usePluginManager();
38
+ const filtered = useMemo(
39
+ () =>
40
+ manager
41
+ .getPlugins()
42
+ .filter(({ meta }) => !manager.getCore().includes(meta.id))
43
+ .filter(({ meta }) => manager.getEnabled().includes(meta.id)),
44
+ [],
45
+ );
46
+
47
+ return <PluginRegistry id={registryCategoryId('installed')} plugins={filtered} />;
48
+ },
49
+ }),
50
+ Surface.create({
51
+ id: 'recommended',
52
+ role: 'article',
53
+ filter: AppSurface.literalSection(registryCategoryId('recommended')),
54
+ component: () => {
55
+ const manager = usePluginManager();
56
+ const filtered = useMemo(
57
+ () =>
58
+ manager
59
+ .getPlugins()
60
+ .filter(({ meta }) => !manager.getCore().includes(meta.id))
61
+ .filter(({ meta }) => !meta.tags?.includes('labs')),
62
+ [],
63
+ );
64
+
65
+ return <PluginRegistry id={registryCategoryId('recommended')} plugins={filtered} />;
66
+ },
67
+ }),
68
+ Surface.create({
69
+ id: 'labs',
70
+ role: 'article',
71
+ filter: AppSurface.literalSection(registryCategoryId('labs')),
72
+ component: () => {
73
+ const manager = usePluginManager();
74
+ const filtered = useMemo(() => manager.getPlugins().filter(({ meta }) => meta.tags?.includes('labs')), []);
75
+
76
+ return <PluginRegistry id={registryCategoryId('labs')} plugins={filtered} />;
77
+ },
78
+ }),
79
+ Surface.create({
80
+ id: 'plugin-details',
81
+ role: 'article',
82
+ filter: AppSurface.pluginSection(),
83
+ component: ({ data: { subject } }) => {
84
+ return <PluginArticle subject={subject} />;
85
+ },
86
+ }),
87
+ Surface.create({
88
+ id: LOAD_PLUGIN_DIALOG,
89
+ role: 'dialog',
90
+ filter: AppSurface.componentDialog(LOAD_PLUGIN_DIALOG),
91
+ component: () => <LoadPluginDialog />,
92
+ }),
93
+ ]),
94
+ ),
95
+ );
package/src/cli/plugin.ts CHANGED
@@ -2,14 +2,15 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Common, Plugin } from '@dxos/app-framework';
5
+ import { Plugin } from '@dxos/app-framework';
6
+ import { AppPlugin } from '@dxos/app-toolkit';
6
7
 
7
- import { meta } from '../meta';
8
+ import { meta } from '#meta';
8
9
 
9
10
  import { plugin } from './commands';
10
11
 
11
12
  export const RegistryPlugin = Plugin.define(meta).pipe(
12
- Common.Plugin.addCommandModule({
13
+ AppPlugin.addCommandModule({
13
14
  commands: [plugin],
14
15
  }),
15
16
  Plugin.make,
@@ -6,37 +6,31 @@ import * as FileSystem from '@effect/platform/FileSystem';
6
6
  import * as Path from '@effect/platform/Path';
7
7
  import * as Effect from 'effect/Effect';
8
8
  import * as Schema from 'effect/Schema';
9
+ import * as Yaml from 'yaml';
9
10
 
10
- import { DX_CONFIG, getProfilePath } from '@dxos/client-protocol';
11
+ import { DX_CONFIG } from '@dxos/client-protocol';
11
12
 
12
13
  // TODO(wittjosiah): Factor out to app-framework?
13
14
 
14
- const PLUGINS_FILE = 'plugins.json';
15
-
16
15
  const PluginsSchema = Schema.Array(Schema.String);
17
16
 
18
- /**
19
- * Get the path to the plugins configuration file for a profile.
20
- */
21
- const getPluginsPath = (profile: string): Effect.Effect<string, never, Path.Path> =>
22
- Effect.gen(function* () {
23
- const path = yield* Path.Path;
24
- return path.join(getProfilePath(DX_CONFIG, profile), PLUGINS_FILE);
25
- });
17
+ /** CLI-only: path to plugins/<profile>.yml (sibling to profile/). */
18
+ const getPluginsConfigPath = (profile: string) => `${DX_CONFIG}/plugins/${profile}.yml`;
26
19
 
27
20
  /**
28
- * Load enabled plugins from profile storage.
21
+ * Load enabled plugins from plugins/<profile>.yml (sibling to profile/).
29
22
  * Returns the list of enabled plugin IDs, or an empty array if the file doesn't exist.
30
23
  */
31
24
  export const loadEnabledPlugins = Effect.fn(function* ({ profile }: { profile: string }) {
32
25
  const fs = yield* FileSystem.FileSystem;
33
- const pluginsPath = yield* getPluginsPath(profile);
26
+ const pluginsPath = getPluginsConfigPath(profile);
34
27
 
35
28
  const content = yield* fs
36
29
  .readFileString(pluginsPath)
37
30
  .pipe(Effect.catchTag('SystemError', () => Effect.succeed('[]')));
38
31
 
39
- const parsed = yield* Schema.decodeUnknown(Schema.parseJson(PluginsSchema))(content).pipe(
32
+ const raw = Yaml.parse(content);
33
+ const parsed = yield* Schema.decodeUnknown(PluginsSchema)(raw ?? []).pipe(
40
34
  Effect.catchAll(() => Effect.succeed([] as string[])),
41
35
  );
42
36
 
@@ -44,14 +38,13 @@ export const loadEnabledPlugins = Effect.fn(function* ({ profile }: { profile: s
44
38
  });
45
39
 
46
40
  /**
47
- * Save enabled plugins to profile storage.
41
+ * Save enabled plugins to plugins/<profile>.yml.
48
42
  */
49
43
  export const saveEnabledPlugins = Effect.fn(function* ({ profile, enabled }: { profile: string; enabled: string[] }) {
50
44
  const fs = yield* FileSystem.FileSystem;
51
- const pluginsPath = yield* getPluginsPath(profile);
52
- const profileDir = getProfilePath(DX_CONFIG, profile);
53
-
54
- yield* fs.makeDirectory(profileDir, { recursive: true });
55
- const encoded = Schema.encodeSync(Schema.parseJson(PluginsSchema))(enabled);
56
- yield* fs.writeFileString(pluginsPath, encoded + '\n');
45
+ const path = yield* Path.Path;
46
+ const pluginsPath = getPluginsConfigPath(profile);
47
+ yield* fs.makeDirectory(path.dirname(pluginsPath), { recursive: true });
48
+ const encoded = Yaml.stringify(enabled);
49
+ yield* fs.writeFileString(pluginsPath, encoded);
57
50
  });
@@ -5,18 +5,18 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
 
7
7
  import { Plugin } from '@dxos/app-framework';
8
- import { faker } from '@dxos/random';
8
+ import { random } from '@dxos/random';
9
9
  import { withLayout, withTheme } from '@dxos/react-ui/testing';
10
10
 
11
- import { translations } from '../translations';
12
-
11
+ import { translations } from '../../translations';
13
12
  import { PluginDetail } from './PluginDetail';
14
13
 
15
14
  const meta = {
16
- title: 'plugins/plugin-registry/PluginDetail',
15
+ title: 'plugins/plugin-registry/components/PluginDetail',
17
16
  component: PluginDetail,
18
- decorators: [withTheme, withLayout({ layout: 'column' })],
17
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
19
18
  parameters: {
19
+ layout: 'fullscreen',
20
20
  translations,
21
21
  },
22
22
  } satisfies Meta<typeof PluginDetail>;
@@ -30,7 +30,7 @@ export const Default: Story = {
30
30
  plugin: Plugin.define({
31
31
  id: 'example.com/plugin/test-plugin',
32
32
  name: 'Test Plugin',
33
- description: faker.lorem.paragraphs(2),
33
+ description: random.lorem.paragraphs(2),
34
34
  icon: 'ph--bug--regular',
35
35
  iconHue: 'sky',
36
36
  homePage: 'https://example.com',
@@ -0,0 +1,84 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import React from 'react';
6
+
7
+ import { type Plugin } from '@dxos/app-framework';
8
+ import { Icon, Input, Link, ScrollArea, useTranslation } from '@dxos/react-ui';
9
+ import { composable, composableProps, getStyles, mx } from '@dxos/ui-theme';
10
+
11
+ import { meta } from '#meta';
12
+
13
+ export type PluginDetailProps = {
14
+ plugin: Plugin.Plugin;
15
+ enabled?: boolean;
16
+ onEnabledChange?: (enabled: boolean) => void;
17
+ };
18
+
19
+ export const PluginDetail = composable<HTMLDivElement, PluginDetailProps>(
20
+ ({ plugin, enabled, onEnabledChange, ...props }, forwardedRef) => {
21
+ const { t } = useTranslation(meta.id);
22
+ const {
23
+ id,
24
+ name,
25
+ description,
26
+ homePage,
27
+ source,
28
+ screenshots,
29
+ icon = 'ph--circle--regular',
30
+ iconHue = 'neutral',
31
+ } = plugin.meta;
32
+ const styles = getStyles(iconHue);
33
+
34
+ return (
35
+ <ScrollArea.Root {...composableProps(props)} orientation='vertical' ref={forwardedRef}>
36
+ <ScrollArea.Viewport>
37
+ <div role='none' className='dx-document grid grid-cols-[min-content_1fr] gap-4 p-4'>
38
+ <div role='none'>
39
+ <Icon classNames={mx('p-1 rounded-md', styles.fill, styles.surfaceText)} icon={icon} size={14} />
40
+ </div>
41
+ <div role='none' className='flex flex-col gap-6'>
42
+ <div role='none' className='grid grid-cols-[1fr_min-content] gap-x-3 w-full pt-1'>
43
+ <h2 className='text-xl'>{name}</h2>
44
+ <Input.Root>
45
+ <Input.Switch classNames='self-center' checked={enabled} onCheckedChange={onEnabledChange} />
46
+ </Input.Root>
47
+ <p className='pt-0.5 text-sm text-description'>{id}</p>
48
+ </div>
49
+ <div role='none'>
50
+ <p className='text-description'>{description}</p>
51
+ </div>
52
+ {screenshots && screenshots.length > 0 && (
53
+ <div role='none' className='flex flex-col gap-2'>
54
+ <h2>Preview</h2>
55
+ <img src={screenshots[0]} alt={name} className='aspect-video object-fit' />
56
+ </div>
57
+ )}
58
+ <div role='none' className='flex flex-col gap-2'>
59
+ <h2>Resources</h2>
60
+ <div className='flex gap-2'>
61
+ {homePage && (
62
+ <Link href={homePage} target='_blank' rel='noreferrer' classNames='text-sm text-description'>
63
+ {t('home-page.label')}
64
+ <Icon icon='ph--arrow-square-out--bold' size={3} classNames='inline-block leading-none mx-1' />
65
+ </Link>
66
+ )}
67
+
68
+ {source && (
69
+ <Link href={source} target='_blank' rel='noreferrer' classNames='text-sm text-description'>
70
+ {t('source.label')}
71
+ <Icon icon='ph--arrow-square-out--bold' size={3} classNames='inline-block leading-none mx-1' />
72
+ </Link>
73
+ )}
74
+ </div>
75
+ </div>
76
+ </div>
77
+ </div>
78
+ </ScrollArea.Viewport>
79
+ </ScrollArea.Root>
80
+ );
81
+ },
82
+ );
83
+
84
+ PluginDetail.displayName = 'PluginDetail';
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './PluginDetail';