@dxos/plugin-registry 0.8.4-main.74a063c4e0 → 0.8.4-main.765dc60934

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 (192) hide show
  1. package/LICENSE +102 -5
  2. package/dist/lib/neutral/RegistryPlugin.mjs +27 -0
  3. package/dist/lib/neutral/RegistryPlugin.mjs.map +7 -0
  4. package/dist/lib/{browser/cli/index.mjs → neutral/RegistryPlugin.node.mjs} +29 -95
  5. package/dist/lib/neutral/RegistryPlugin.node.mjs.map +7 -0
  6. package/dist/lib/neutral/chunk-A6F6X6M4.mjs +31 -0
  7. package/dist/lib/neutral/chunk-A6F6X6M4.mjs.map +7 -0
  8. package/dist/lib/neutral/chunk-XK2JMH3H.mjs +33 -0
  9. package/dist/lib/neutral/chunk-XK2JMH3H.mjs.map +7 -0
  10. package/dist/lib/neutral/index.mjs +23 -0
  11. package/dist/lib/neutral/index.mjs.map +7 -0
  12. package/dist/lib/neutral/meta.json +1 -0
  13. package/dist/lib/neutral/open-plugin-registry-II735N76.mjs +15 -0
  14. package/dist/lib/neutral/open-plugin-registry-II735N76.mjs.map +7 -0
  15. package/dist/lib/neutral/plugin.mjs +18 -0
  16. package/dist/lib/neutral/plugin.mjs.map +7 -0
  17. package/dist/lib/neutral/translations.mjs +67 -0
  18. package/dist/lib/neutral/translations.mjs.map +7 -0
  19. package/dist/types/src/RegistryPlugin.d.ts +1 -0
  20. package/dist/types/src/RegistryPlugin.d.ts.map +1 -1
  21. package/dist/types/src/{cli/plugin.d.ts → RegistryPlugin.node.d.ts} +2 -1
  22. package/dist/types/src/RegistryPlugin.node.d.ts.map +1 -0
  23. package/dist/types/src/RegistryPlugin.test.d.ts +2 -0
  24. package/dist/types/src/RegistryPlugin.test.d.ts.map +1 -0
  25. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  26. package/dist/types/src/capabilities/dev-plugin-loader.d.ts +11 -0
  27. package/dist/types/src/capabilities/dev-plugin-loader.d.ts.map +1 -0
  28. package/dist/types/src/capabilities/index.d.ts +11 -1
  29. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  30. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  31. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -1
  32. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  33. package/dist/types/src/capabilities/settings.d.ts +14 -0
  34. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  35. package/dist/types/src/{cli/commands → commands}/disable.d.ts +2 -2
  36. package/dist/types/src/commands/disable.d.ts.map +1 -0
  37. package/dist/types/src/{cli/commands → commands}/enable.d.ts +2 -2
  38. package/dist/types/src/commands/enable.d.ts.map +1 -0
  39. package/dist/types/src/commands/index.d.ts.map +1 -0
  40. package/dist/types/src/commands/list.d.ts +7 -0
  41. package/dist/types/src/commands/list.d.ts.map +1 -0
  42. package/dist/types/src/commands/util.d.ts.map +1 -0
  43. package/dist/types/src/components/DisableDependentsAlert/DisableDependentsAlert.d.ts +24 -0
  44. package/dist/types/src/components/DisableDependentsAlert/DisableDependentsAlert.d.ts.map +1 -0
  45. package/dist/types/src/components/DisableDependentsAlert/index.d.ts +2 -0
  46. package/dist/types/src/components/DisableDependentsAlert/index.d.ts.map +1 -0
  47. package/dist/types/src/components/PluginDetail/PluginDetail.d.ts +63 -6
  48. package/dist/types/src/components/PluginDetail/PluginDetail.d.ts.map +1 -1
  49. package/dist/types/src/components/PluginDetail/PluginDetail.stories.d.ts +55 -24
  50. package/dist/types/src/components/PluginDetail/PluginDetail.stories.d.ts.map +1 -1
  51. package/dist/types/src/components/PluginFailureBadge/PluginFailureBadge.d.ts +20 -0
  52. package/dist/types/src/components/PluginFailureBadge/PluginFailureBadge.d.ts.map +1 -0
  53. package/dist/types/src/components/PluginFailureBadge/index.d.ts +2 -0
  54. package/dist/types/src/components/PluginFailureBadge/index.d.ts.map +1 -0
  55. package/dist/types/src/components/PluginList/PluginItem.d.ts +29 -2
  56. package/dist/types/src/components/PluginList/PluginItem.d.ts.map +1 -1
  57. package/dist/types/src/components/PluginList/PluginList.d.ts +18 -3
  58. package/dist/types/src/components/PluginList/PluginList.d.ts.map +1 -1
  59. package/dist/types/src/components/PluginList/PluginList.stories.d.ts +55 -20
  60. package/dist/types/src/components/PluginList/PluginList.stories.d.ts.map +1 -1
  61. package/dist/types/src/components/RegistrySettings/RegistrySettings.d.ts +18 -0
  62. package/dist/types/src/components/RegistrySettings/RegistrySettings.d.ts.map +1 -0
  63. package/dist/types/src/components/RegistrySettings/index.d.ts +2 -0
  64. package/dist/types/src/components/RegistrySettings/index.d.ts.map +1 -0
  65. package/dist/types/src/components/index.d.ts +3 -0
  66. package/dist/types/src/components/index.d.ts.map +1 -1
  67. package/dist/types/src/containers/BaseRegistryArticle/BaseRegistryArticle.d.ts +20 -0
  68. package/dist/types/src/containers/BaseRegistryArticle/BaseRegistryArticle.d.ts.map +1 -0
  69. package/dist/types/src/containers/BaseRegistryArticle/index.d.ts +2 -0
  70. package/dist/types/src/containers/BaseRegistryArticle/index.d.ts.map +1 -0
  71. package/dist/types/src/containers/LoadPluginDialog/LoadPluginDialog.d.ts.map +1 -1
  72. package/dist/types/src/containers/PluginArticle/PluginArticle.d.ts.map +1 -1
  73. package/dist/types/src/containers/PublicRegistryArticle/PublicRegistryArticle.d.ts +8 -0
  74. package/dist/types/src/containers/PublicRegistryArticle/PublicRegistryArticle.d.ts.map +1 -0
  75. package/dist/types/src/containers/PublicRegistryArticle/index.d.ts +2 -0
  76. package/dist/types/src/containers/PublicRegistryArticle/index.d.ts.map +1 -0
  77. package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts +14 -0
  78. package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts.map +1 -0
  79. package/dist/types/src/containers/RegistryArticle/index.d.ts +2 -0
  80. package/dist/types/src/containers/RegistryArticle/index.d.ts.map +1 -0
  81. package/dist/types/src/containers/RegistrySettingsContainer/RegistrySettingsContainer.d.ts +13 -0
  82. package/dist/types/src/containers/RegistrySettingsContainer/RegistrySettingsContainer.d.ts.map +1 -0
  83. package/dist/types/src/containers/RegistrySettingsContainer/index.d.ts +2 -0
  84. package/dist/types/src/containers/RegistrySettingsContainer/index.d.ts.map +1 -0
  85. package/dist/types/src/containers/index.d.ts +3 -1
  86. package/dist/types/src/containers/index.d.ts.map +1 -1
  87. package/dist/types/src/hooks/index.d.ts +5 -0
  88. package/dist/types/src/hooks/index.d.ts.map +1 -0
  89. package/dist/types/src/hooks/use-auto-tags.d.ts +20 -0
  90. package/dist/types/src/hooks/use-auto-tags.d.ts.map +1 -0
  91. package/dist/types/src/hooks/use-disable-confirmation.d.ts +19 -0
  92. package/dist/types/src/hooks/use-disable-confirmation.d.ts.map +1 -0
  93. package/dist/types/src/hooks/use-registry-plugins.d.ts +15 -0
  94. package/dist/types/src/hooks/use-registry-plugins.d.ts.map +1 -0
  95. package/dist/types/src/hooks/use-update-available.d.ts +18 -0
  96. package/dist/types/src/hooks/use-update-available.d.ts.map +1 -0
  97. package/dist/types/src/index.d.ts +1 -1
  98. package/dist/types/src/index.d.ts.map +1 -1
  99. package/dist/types/src/meta.d.ts +2 -0
  100. package/dist/types/src/meta.d.ts.map +1 -1
  101. package/dist/types/src/operations/index.d.ts +1 -1
  102. package/dist/types/src/operations/index.d.ts.map +1 -1
  103. package/dist/types/src/operations/open-plugin-registry.d.ts +1 -1
  104. package/dist/types/src/operations/open-plugin-registry.d.ts.map +1 -1
  105. package/dist/types/src/plugin.d.ts +4 -0
  106. package/dist/types/src/plugin.d.ts.map +1 -0
  107. package/dist/types/src/storage.d.ts.map +1 -0
  108. package/dist/types/src/translations.d.ts +54 -20
  109. package/dist/types/src/translations.d.ts.map +1 -1
  110. package/dist/types/src/types.d.ts +30 -1
  111. package/dist/types/src/types.d.ts.map +1 -1
  112. package/dist/types/tsconfig.tsbuildinfo +1 -1
  113. package/package.json +47 -34
  114. package/src/{cli/plugin.ts → RegistryPlugin.node.ts} +2 -0
  115. package/src/RegistryPlugin.test.ts +24 -0
  116. package/src/RegistryPlugin.tsx +11 -4
  117. package/src/capabilities/app-graph-builder.ts +68 -17
  118. package/src/capabilities/dev-plugin-loader.ts +39 -0
  119. package/src/capabilities/index.ts +3 -1
  120. package/src/capabilities/operation-handler.ts +1 -1
  121. package/src/capabilities/react-surface.tsx +88 -38
  122. package/src/capabilities/settings.ts +34 -0
  123. package/src/components/DisableDependentsAlert/DisableDependentsAlert.tsx +69 -0
  124. package/src/components/DisableDependentsAlert/index.ts +5 -0
  125. package/src/components/PluginDetail/PluginDetail.stories.tsx +3 -2
  126. package/src/components/PluginDetail/PluginDetail.tsx +203 -15
  127. package/src/components/PluginFailureBadge/PluginFailureBadge.tsx +68 -0
  128. package/src/components/PluginFailureBadge/index.ts +5 -0
  129. package/src/components/PluginList/PluginItem.tsx +113 -11
  130. package/src/components/PluginList/PluginList.stories.tsx +1 -1
  131. package/src/components/PluginList/PluginList.tsx +32 -4
  132. package/src/components/RegistrySettings/RegistrySettings.tsx +120 -0
  133. package/src/components/RegistrySettings/index.ts +5 -0
  134. package/src/components/index.ts +3 -0
  135. package/src/containers/BaseRegistryArticle/BaseRegistryArticle.tsx +178 -0
  136. package/src/containers/BaseRegistryArticle/index.ts +5 -0
  137. package/src/containers/LoadPluginDialog/LoadPluginDialog.tsx +6 -3
  138. package/src/containers/PluginArticle/PluginArticle.tsx +360 -10
  139. package/src/containers/PublicRegistryArticle/PublicRegistryArticle.tsx +192 -0
  140. package/src/containers/PublicRegistryArticle/index.ts +5 -0
  141. package/src/containers/RegistryArticle/RegistryArticle.tsx +53 -0
  142. package/src/containers/RegistryArticle/index.ts +5 -0
  143. package/src/containers/RegistrySettingsContainer/RegistrySettingsContainer.tsx +59 -0
  144. package/src/containers/RegistrySettingsContainer/index.ts +5 -0
  145. package/src/containers/index.ts +3 -1
  146. package/src/hooks/index.ts +8 -0
  147. package/src/hooks/use-auto-tags.ts +51 -0
  148. package/src/hooks/use-disable-confirmation.ts +58 -0
  149. package/src/hooks/use-registry-plugins.ts +29 -0
  150. package/src/hooks/use-update-available.ts +31 -0
  151. package/src/index.ts +1 -1
  152. package/src/meta.ts +5 -0
  153. package/src/operations/index.ts +1 -1
  154. package/src/operations/open-plugin-registry.ts +1 -1
  155. package/src/plugin.ts +11 -0
  156. package/src/translations.ts +44 -4
  157. package/src/types.ts +33 -1
  158. package/dist/lib/browser/cli/index.mjs.map +0 -7
  159. package/dist/lib/browser/index.mjs +0 -71
  160. package/dist/lib/browser/index.mjs.map +0 -7
  161. package/dist/lib/browser/meta.json +0 -1
  162. package/dist/lib/node-esm/cli/index.mjs +0 -221
  163. package/dist/lib/node-esm/cli/index.mjs.map +0 -7
  164. package/dist/lib/node-esm/index.mjs +0 -73
  165. package/dist/lib/node-esm/index.mjs.map +0 -7
  166. package/dist/lib/node-esm/meta.json +0 -1
  167. package/dist/types/src/cli/commands/disable.d.ts.map +0 -1
  168. package/dist/types/src/cli/commands/enable.d.ts.map +0 -1
  169. package/dist/types/src/cli/commands/index.d.ts.map +0 -1
  170. package/dist/types/src/cli/commands/list.d.ts +0 -7
  171. package/dist/types/src/cli/commands/list.d.ts.map +0 -1
  172. package/dist/types/src/cli/commands/util.d.ts.map +0 -1
  173. package/dist/types/src/cli/index.d.ts +0 -3
  174. package/dist/types/src/cli/index.d.ts.map +0 -1
  175. package/dist/types/src/cli/plugin.d.ts.map +0 -1
  176. package/dist/types/src/cli/storage.d.ts.map +0 -1
  177. package/dist/types/src/containers/PluginRegistry/PluginRegistry.d.ts +0 -14
  178. package/dist/types/src/containers/PluginRegistry/PluginRegistry.d.ts.map +0 -1
  179. package/dist/types/src/containers/PluginRegistry/index.d.ts +0 -2
  180. package/dist/types/src/containers/PluginRegistry/index.d.ts.map +0 -1
  181. package/src/cli/index.ts +0 -6
  182. package/src/containers/PluginRegistry/PluginRegistry.tsx +0 -94
  183. package/src/containers/PluginRegistry/index.ts +0 -5
  184. /package/dist/types/src/{cli/commands → commands}/index.d.ts +0 -0
  185. /package/dist/types/src/{cli/commands → commands}/util.d.ts +0 -0
  186. /package/dist/types/src/{cli/storage.d.ts → storage.d.ts} +0 -0
  187. /package/src/{cli/commands → commands}/disable.ts +0 -0
  188. /package/src/{cli/commands → commands}/enable.ts +0 -0
  189. /package/src/{cli/commands → commands}/index.ts +0 -0
  190. /package/src/{cli/commands → commands}/list.ts +0 -0
  191. /package/src/{cli/commands → commands}/util.ts +0 -0
  192. /package/src/{cli/storage.ts → storage.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/plugin-registry",
3
- "version": "0.8.4-main.74a063c4e0",
3
+ "version": "0.8.4-main.765dc60934",
4
4
  "description": "Braneframe plugin gallery",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/dxos/dxos"
10
10
  },
11
- "license": "MIT",
11
+ "license": "FSL-1.1-Apache-2.0",
12
12
  "author": "DXOS.org",
13
13
  "sideEffects": true,
14
14
  "type": "module",
@@ -18,26 +18,36 @@
18
18
  "#containers": "./src/containers/index.ts",
19
19
  "#meta": "./src/meta.ts",
20
20
  "#operations": "./src/operations/index.ts",
21
+ "#plugin": {
22
+ "source": {
23
+ "node": "./src/RegistryPlugin.node.ts",
24
+ "default": "./src/RegistryPlugin.tsx"
25
+ },
26
+ "types": "./dist/types/src/RegistryPlugin.d.ts",
27
+ "node": "./dist/lib/neutral/RegistryPlugin.node.mjs",
28
+ "default": "./dist/lib/neutral/RegistryPlugin.mjs"
29
+ },
30
+ "#translations": "./src/translations.ts",
21
31
  "#types": "./src/types.ts"
22
32
  },
23
33
  "exports": {
24
34
  ".": {
25
35
  "source": "./src/index.ts",
26
- "browser": "./dist/lib/browser/index.mjs",
27
- "node": "./dist/lib/node-esm/index.mjs",
28
- "types": "./dist/types/src/index.d.ts"
36
+ "types": "./dist/types/src/index.d.ts",
37
+ "default": "./dist/lib/neutral/index.mjs"
38
+ },
39
+ "./plugin": {
40
+ "source": "./src/plugin.ts",
41
+ "types": "./dist/types/src/plugin.d.ts",
42
+ "default": "./dist/lib/neutral/plugin.mjs"
29
43
  },
30
- "./cli": {
31
- "source": "./src/cli/index.ts",
32
- "browser": "./dist/lib/browser/cli/index.mjs",
33
- "node": "./dist/lib/node-esm/cli/index.mjs",
34
- "types": "./dist/types/src/cli/index.d.ts"
44
+ "./translations": {
45
+ "source": "./src/translations.ts",
46
+ "types": "./dist/types/src/translations.d.ts",
47
+ "default": "./dist/lib/neutral/translations.mjs"
35
48
  }
36
49
  },
37
50
  "types": "dist/types/src/index.d.ts",
38
- "typesVersions": {
39
- "*": {}
40
- },
41
51
  "files": [
42
52
  "dist",
43
53
  "src"
@@ -46,20 +56,22 @@
46
56
  "@effect-atom/atom-react": "^0.5.0",
47
57
  "@effect/cli": "0.73.2",
48
58
  "yaml": "^2.8.2",
49
- "@dxos/app-framework": "0.8.4-main.74a063c4e0",
50
- "@dxos/app-toolkit": "0.8.4-main.74a063c4e0",
51
- "@dxos/cli-util": "0.8.4-main.74a063c4e0",
52
- "@dxos/client-protocol": "0.8.4-main.74a063c4e0",
53
- "@dxos/effect": "0.8.4-main.74a063c4e0",
54
- "@dxos/invariant": "0.8.4-main.74a063c4e0",
55
- "@dxos/operation": "0.8.4-main.74a063c4e0",
56
- "@dxos/plugin-observability": "0.8.4-main.74a063c4e0",
57
- "@dxos/react-ui-form": "0.8.4-main.74a063c4e0",
58
- "@dxos/plugin-graph": "0.8.4-main.74a063c4e0",
59
- "@dxos/react-ui-stack": "0.8.4-main.74a063c4e0",
60
- "@dxos/react-ui-mosaic": "0.8.4-main.74a063c4e0",
61
- "@dxos/util": "0.8.4-main.74a063c4e0",
62
- "@dxos/echo": "0.8.4-main.74a063c4e0"
59
+ "@dxos/app-framework": "0.8.4-main.765dc60934",
60
+ "@dxos/app-toolkit": "0.8.4-main.765dc60934",
61
+ "@dxos/compute": "0.8.4-main.765dc60934",
62
+ "@dxos/client-protocol": "0.8.4-main.765dc60934",
63
+ "@dxos/context": "0.8.4-main.765dc60934",
64
+ "@dxos/echo": "0.8.4-main.765dc60934",
65
+ "@dxos/effect": "0.8.4-main.765dc60934",
66
+ "@dxos/log": "0.8.4-main.765dc60934",
67
+ "@dxos/invariant": "0.8.4-main.765dc60934",
68
+ "@dxos/plugin-graph": "0.8.4-main.765dc60934",
69
+ "@dxos/react-ui-form": "0.8.4-main.765dc60934",
70
+ "@dxos/plugin-observability": "0.8.4-main.765dc60934",
71
+ "@dxos/react-ui-stack": "0.8.4-main.765dc60934",
72
+ "@dxos/util": "0.8.4-main.765dc60934",
73
+ "@dxos/react-ui-mosaic": "0.8.4-main.765dc60934",
74
+ "@dxos/cli-util": "0.8.4-main.765dc60934"
63
75
  },
64
76
  "devDependencies": {
65
77
  "@effect-atom/atom-react": "^0.5.0",
@@ -69,11 +81,12 @@
69
81
  "effect": "3.20.0",
70
82
  "react": "~19.2.3",
71
83
  "react-dom": "~19.2.3",
72
- "vite": "^7.1.11",
73
- "@dxos/random": "0.8.4-main.74a063c4e0",
74
- "@dxos/react-ui": "0.8.4-main.74a063c4e0",
75
- "@dxos/ui-theme": "0.8.4-main.74a063c4e0",
76
- "@dxos/storybook-utils": "0.8.4-main.74a063c4e0"
84
+ "vite": "^8.0.13",
85
+ "@dxos/plugin-testing": "0.8.4-main.765dc60934",
86
+ "@dxos/random": "0.8.4-main.765dc60934",
87
+ "@dxos/storybook-utils": "0.8.4-main.765dc60934",
88
+ "@dxos/react-ui": "0.8.4-main.765dc60934",
89
+ "@dxos/ui-theme": "0.8.4-main.765dc60934"
77
90
  },
78
91
  "peerDependencies": {
79
92
  "@effect-atom/atom-react": "^0.5.0",
@@ -81,8 +94,8 @@
81
94
  "effect": "3.20.0",
82
95
  "react": "~19.2.3",
83
96
  "react-dom": "~19.2.3",
84
- "@dxos/react-ui": "0.8.4-main.74a063c4e0",
85
- "@dxos/ui-theme": "0.8.4-main.74a063c4e0"
97
+ "@dxos/react-ui": "0.8.4-main.765dc60934",
98
+ "@dxos/ui-theme": "0.8.4-main.765dc60934"
86
99
  },
87
100
  "publishConfig": {
88
101
  "access": "public"
@@ -15,3 +15,5 @@ export const RegistryPlugin = Plugin.define(meta).pipe(
15
15
  }),
16
16
  Plugin.make,
17
17
  );
18
+
19
+ export default RegistryPlugin;
@@ -0,0 +1,24 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import { createComposerTestApp } from '@dxos/plugin-testing/harness';
8
+
9
+ import { RegistryPlugin } from '#plugin';
10
+
11
+ import { meta } from './meta';
12
+
13
+ const moduleId = (name: string) => `${meta.id}.module.${name}`;
14
+
15
+ describe('RegistryPlugin', () => {
16
+ test('modules activate on the expected events', async ({ expect }) => {
17
+ await using harness = await createComposerTestApp({
18
+ plugins: [RegistryPlugin()],
19
+ });
20
+
21
+ // CLI commands activate on startup.
22
+ expect(harness.manager.getActive()).toContain(moduleId('cli-commands'));
23
+ });
24
+ });
@@ -2,18 +2,25 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { Plugin } from '@dxos/app-framework';
5
+ import { ActivationEvents, Plugin } from '@dxos/app-framework';
6
6
  import { AppPlugin } from '@dxos/app-toolkit';
7
7
 
8
- import { AppGraphBuilder, OperationHandler, ReactSurface } from '#capabilities';
8
+ import { AppGraphBuilder, DevPluginLoader, OperationHandler, ReactSurface, RegistrySettings } from '#capabilities';
9
9
  import { meta } from '#meta';
10
-
11
- import { translations } from './translations';
10
+ import { translations } from '#translations';
12
11
 
13
12
  export const RegistryPlugin = Plugin.define(meta).pipe(
14
13
  AppPlugin.addAppGraphModule({ activate: AppGraphBuilder }),
15
14
  AppPlugin.addOperationHandlerModule({ activate: OperationHandler }),
15
+ AppPlugin.addSettingsModule({ activate: RegistrySettings }),
16
16
  AppPlugin.addSurfaceModule({ activate: ReactSurface }),
17
17
  AppPlugin.addTranslationsModule({ translations }),
18
+ Plugin.addModule({
19
+ id: 'dev-plugin-loader',
20
+ activatesOn: ActivationEvents.Startup,
21
+ activate: DevPluginLoader,
22
+ }),
18
23
  Plugin.make,
19
24
  );
25
+
26
+ export default RegistryPlugin;
@@ -3,17 +3,39 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
- import * as Option from 'effect/Option';
7
6
 
8
- import { Capabilities, Capability } from '@dxos/app-framework';
7
+ import { Capabilities, Capability, type Registry, Plugin } from '@dxos/app-framework';
9
8
  import { AppCapabilities, LayoutOperation, SettingsOperation } from '@dxos/app-toolkit';
10
- import { Operation } from '@dxos/operation';
9
+ import { Operation } from '@dxos/compute';
11
10
  import { GraphBuilder, Node, NodeMatcher } from '@dxos/plugin-graph';
12
11
 
13
12
  import { REGISTRY_ID, REGISTRY_KEY, registryCategoryId, meta } from '#meta';
14
13
 
15
14
  import { LOAD_PLUGIN_DIALOG } from '../containers';
16
15
 
16
+ /**
17
+ * Turns a registry catalog entry into a minimal {@link Plugin.Plugin} so it
18
+ * can be attached as the graph node's `data`. The synthesized plugin has no
19
+ * modules and only exists so the article surface can render details for
20
+ * registry plugins that haven't been installed yet.
21
+ */
22
+ const toDisplayPlugin = (entry: Registry.Plugin): Plugin.Plugin =>
23
+ ({
24
+ [Plugin.PluginTypeId]: Plugin.PluginTypeId,
25
+ meta: {
26
+ id: entry.id,
27
+ name: entry.name,
28
+ description: entry.description,
29
+ homePage: entry.homePage,
30
+ source: entry.source,
31
+ screenshots: entry.screenshots,
32
+ tags: entry.tags,
33
+ icon: entry.icon,
34
+ iconHue: entry.iconHue,
35
+ },
36
+ modules: [],
37
+ }) as Plugin.Plugin;
38
+
17
39
  export default Capability.makeModule(
18
40
  Effect.fnUntraced(function* () {
19
41
  const capabilities = yield* Capability.Service;
@@ -47,18 +69,19 @@ export default Capability.makeModule(
47
69
  label: ['plugin-registry.label', { ns: meta.id }],
48
70
  icon: 'ph--squares-four--regular',
49
71
  disposition: 'pin-end',
72
+ position: 'hoist',
50
73
  testId: 'treeView.pluginRegistry',
51
74
  },
52
75
  nodes: [
53
76
  Node.make({
54
- id: registryCategoryId('all'),
77
+ id: registryCategoryId('official'),
55
78
  type: 'category',
56
- data: registryCategoryId('all'),
79
+ data: registryCategoryId('official'),
57
80
  properties: {
58
- label: ['all-plugins.label', { ns: meta.id }],
81
+ label: ['official-plugins.label', { ns: meta.id }],
59
82
  icon: 'ph--squares-four--regular',
60
83
  key: REGISTRY_KEY,
61
- testId: 'pluginRegistry.all',
84
+ testId: 'pluginRegistry.official',
62
85
  },
63
86
  }),
64
87
  Node.make({
@@ -94,15 +117,24 @@ export default Capability.makeModule(
94
117
  testId: 'pluginRegistry.labs',
95
118
  },
96
119
  }),
120
+ Node.make({
121
+ id: registryCategoryId('registry'),
122
+ type: 'category',
123
+ data: registryCategoryId('registry'),
124
+ properties: {
125
+ label: ['registry-plugins.label', { ns: meta.id }],
126
+ icon: 'ph--users-three--regular',
127
+ key: REGISTRY_KEY,
128
+ testId: 'pluginRegistry.registry',
129
+ },
130
+ }),
97
131
  ],
98
132
  }),
99
133
  ]),
100
134
  }),
101
135
  GraphBuilder.createExtension({
102
136
  id: 'actions',
103
- match: NodeMatcher.whenAny(NodeMatcher.whenId(`root/${REGISTRY_ID}`), (node) =>
104
- node.properties.key === REGISTRY_KEY ? Option.some(node) : Option.none(),
105
- ),
137
+ match: NodeMatcher.whenId(`root/${REGISTRY_ID}`),
106
138
  actions: () =>
107
139
  Effect.succeed([
108
140
  {
@@ -124,11 +156,29 @@ export default Capability.makeModule(
124
156
  GraphBuilder.createExtension({
125
157
  id: 'plugins',
126
158
  match: NodeMatcher.whenId(`root/${REGISTRY_ID}`),
127
- connector: () => {
159
+ connector: (_node, get) => {
128
160
  const manager = capabilities.get(Capabilities.PluginManager);
129
- return Effect.succeed(
130
- manager.getPlugins().map((plugin) =>
131
- Node.make({
161
+ const installedIds = new Set(manager.getPlugins().map((plugin) => plugin.meta.id));
162
+
163
+ const installedNodes = manager.getPlugins().map((plugin) =>
164
+ Node.make({
165
+ id: plugin.meta.id,
166
+ type: 'org.dxos.plugin',
167
+ data: plugin,
168
+ properties: {
169
+ label: plugin.meta.name ?? plugin.meta.id,
170
+ icon: plugin.meta.icon ?? 'ph--circle--regular',
171
+ disposition: 'hidden',
172
+ },
173
+ }),
174
+ );
175
+
176
+ const registryEntries = get(manager.pluginRegistry.plugins).entries;
177
+ const registryNodes = registryEntries
178
+ .filter((entry) => !installedIds.has(entry.id))
179
+ .map((entry) => {
180
+ const plugin = toDisplayPlugin(entry);
181
+ return Node.make({
132
182
  id: plugin.meta.id,
133
183
  type: 'org.dxos.plugin',
134
184
  data: plugin,
@@ -137,9 +187,10 @@ export default Capability.makeModule(
137
187
  icon: plugin.meta.icon ?? 'ph--circle--regular',
138
188
  disposition: 'hidden',
139
189
  },
140
- }),
141
- ),
142
- );
190
+ });
191
+ });
192
+
193
+ return Effect.succeed([...installedNodes, ...registryNodes]);
143
194
  },
144
195
  }),
145
196
  ]);
@@ -0,0 +1,39 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import { log } from '@dxos/log';
9
+
10
+ import { RegistryCapabilities } from '../types';
11
+
12
+ /**
13
+ * Startup module that auto-loads a locally-served dev plugin when the user has
14
+ * the toggle enabled in registry settings. Failures (dev server offline, 404,
15
+ * timeout) are logged and swallowed so a stale dev URL never blocks app boot —
16
+ * the toggle stays on, the next reload retries.
17
+ */
18
+ export default Capability.makeModule(
19
+ Effect.fnUntraced(function* () {
20
+ const manager = yield* Capability.get(Capabilities.PluginManager);
21
+ const registry = yield* Capability.get(Capabilities.AtomRegistry);
22
+ const settingsAtom = yield* Capability.get(RegistryCapabilities.Settings);
23
+
24
+ const settings = registry.get(settingsAtom);
25
+ const url = settings.devPluginUrl?.trim();
26
+ if (!settings.devPluginEnabled || !url) {
27
+ return [];
28
+ }
29
+
30
+ log.info('loading dev plugin from registry settings', { url });
31
+ yield* manager.add(url).pipe(
32
+ Effect.flatMap((plugin) => manager.enable(plugin.meta.id)),
33
+ Effect.tapError((error) => Effect.sync(() => log.warn('dev plugin auto-load failed', { url, error }))),
34
+ Effect.ignore,
35
+ );
36
+
37
+ return [];
38
+ }),
39
+ );
@@ -3,11 +3,13 @@
3
3
  //
4
4
 
5
5
  import { Capability } from '@dxos/app-framework';
6
- import { OperationHandlerSet } from '@dxos/operation';
6
+ import { OperationHandlerSet } from '@dxos/compute';
7
7
 
8
8
  export const AppGraphBuilder = Capability.lazy('AppGraphBuilder', () => import('./app-graph-builder'));
9
+ export const DevPluginLoader = Capability.lazy('DevPluginLoader', () => import('./dev-plugin-loader'));
9
10
  export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
10
11
  'OperationHandler',
11
12
  () => import('./operation-handler'),
12
13
  );
13
14
  export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
15
+ export const RegistrySettings = Capability.lazy('RegistrySettings', () => import('./settings'));
@@ -5,7 +5,7 @@
5
5
  import * as Effect from 'effect/Effect';
6
6
 
7
7
  import { Capabilities, Capability } from '@dxos/app-framework';
8
- import type { OperationHandlerSet } from '@dxos/operation';
8
+ import type { OperationHandlerSet } from '@dxos/compute';
9
9
 
10
10
  import { RegistryOperationHandlerSet } from '#operations';
11
11
 
@@ -3,93 +3,143 @@
3
3
  //
4
4
 
5
5
  import * as Effect from 'effect/Effect';
6
- import React, { useMemo } from 'react';
6
+ import React, { type ComponentProps, useMemo } from 'react';
7
7
 
8
- import { Capabilities, Capability } from '@dxos/app-framework';
8
+ import { Capabilities, Capability, Plugin } from '@dxos/app-framework';
9
9
  import { Surface, usePluginManager } from '@dxos/app-framework/ui';
10
+ import { AppCapabilities } from '@dxos/app-toolkit';
10
11
  import { AppSurface } from '@dxos/app-toolkit/ui';
11
12
 
12
- import { LOAD_PLUGIN_DIALOG, LoadPluginDialog, PluginArticle, PluginRegistry } from '#containers';
13
- import { registryCategoryId } from '#meta';
13
+ import { DisableDependentsAlert } from '#components';
14
+ import {
15
+ LOAD_PLUGIN_DIALOG,
16
+ LoadPluginDialog,
17
+ PluginArticle,
18
+ PublicRegistryArticle,
19
+ RegistryArticle,
20
+ RegistrySettingsContainer,
21
+ } from '#containers';
22
+ import { DISABLE_DEPENDENTS_DIALOG, meta, registryCategoryId } from '#meta';
23
+
24
+ import { useAutoTags, useRegistryPlugins, useRemotePluginIds } from '../hooks';
14
25
 
15
26
  export default Capability.makeModule(() =>
16
27
  Effect.succeed(
17
28
  Capability.contributes(Capabilities.ReactSurface, [
18
29
  Surface.create({
19
- id: 'all',
20
- role: 'article',
21
- filter: AppSurface.literalSection(registryCategoryId('all')),
30
+ id: 'official',
31
+ filter: AppSurface.literal(AppSurface.Article, registryCategoryId('official')),
22
32
  component: () => {
23
33
  const manager = usePluginManager();
24
- const filtered = useMemo(
25
- () => manager.getPlugins().filter(({ meta }) => !manager.getCore().includes(meta.id)),
26
- [],
34
+ const remoteIds = useRemotePluginIds();
35
+ const core = useMemo(() => manager.getCore(), [manager]);
36
+ const predicate = useMemo<PluginPredicate>(
37
+ () =>
38
+ ({ meta }) =>
39
+ !core.includes(meta.id) && !remoteIds.has(meta.id),
40
+ [core, remoteIds],
27
41
  );
28
42
 
29
- return <PluginRegistry id={registryCategoryId('all')} plugins={filtered} />;
43
+ return <FilteredRegistryArticle id={registryCategoryId('official')} filter={predicate} />;
30
44
  },
31
45
  }),
32
46
  Surface.create({
33
47
  id: 'installed',
34
- role: 'article',
35
- filter: AppSurface.literalSection(registryCategoryId('installed')),
48
+ filter: AppSurface.literal(AppSurface.Article, registryCategoryId('installed')),
36
49
  component: () => {
37
50
  const manager = usePluginManager();
38
- const filtered = useMemo(
51
+ const core = useMemo(() => manager.getCore(), [manager]);
52
+ const enabled = useMemo(() => manager.getEnabled(), [manager]);
53
+ const predicate = useMemo<PluginPredicate>(
39
54
  () =>
40
- manager
41
- .getPlugins()
42
- .filter(({ meta }) => !manager.getCore().includes(meta.id))
43
- .filter(({ meta }) => manager.getEnabled().includes(meta.id)),
44
- [],
55
+ ({ meta }) =>
56
+ !core.includes(meta.id) && enabled.includes(meta.id),
57
+ [core, enabled],
45
58
  );
46
59
 
47
- return <PluginRegistry id={registryCategoryId('installed')} plugins={filtered} />;
60
+ return <FilteredRegistryArticle id={registryCategoryId('installed')} filter={predicate} />;
48
61
  },
49
62
  }),
50
63
  Surface.create({
51
64
  id: 'recommended',
52
- role: 'article',
53
- filter: AppSurface.literalSection(registryCategoryId('recommended')),
65
+ filter: AppSurface.literal(AppSurface.Article, registryCategoryId('recommended')),
54
66
  component: () => {
55
67
  const manager = usePluginManager();
56
- const filtered = useMemo(
68
+ const remoteIds = useRemotePluginIds();
69
+ const core = useMemo(() => manager.getCore(), [manager]);
70
+ const predicate = useMemo<PluginPredicate>(
57
71
  () =>
58
- manager
59
- .getPlugins()
60
- .filter(({ meta }) => !manager.getCore().includes(meta.id))
61
- .filter(({ meta }) => !meta.tags?.includes('labs')),
62
- [],
72
+ ({ meta }) =>
73
+ !core.includes(meta.id) && !remoteIds.has(meta.id) && !meta.tags?.includes('labs'),
74
+ [core, remoteIds],
63
75
  );
64
76
 
65
- return <PluginRegistry id={registryCategoryId('recommended')} plugins={filtered} />;
77
+ return <FilteredRegistryArticle id={registryCategoryId('recommended')} filter={predicate} />;
66
78
  },
67
79
  }),
68
80
  Surface.create({
69
81
  id: 'labs',
70
- role: 'article',
71
- filter: AppSurface.literalSection(registryCategoryId('labs')),
82
+ filter: AppSurface.literal(AppSurface.Article, registryCategoryId('labs')),
72
83
  component: () => {
73
- const manager = usePluginManager();
74
- const filtered = useMemo(() => manager.getPlugins().filter(({ meta }) => meta.tags?.includes('labs')), []);
84
+ const predicate = useMemo<PluginPredicate>(
85
+ () =>
86
+ ({ meta }) =>
87
+ meta.tags?.includes('labs') ?? false,
88
+ [],
89
+ );
75
90
 
76
- return <PluginRegistry id={registryCategoryId('labs')} plugins={filtered} />;
91
+ return <FilteredRegistryArticle id={registryCategoryId('labs')} filter={predicate} />;
77
92
  },
78
93
  }),
94
+ Surface.create({
95
+ id: 'registry',
96
+ filter: AppSurface.literal(AppSurface.Article, registryCategoryId('registry')),
97
+ component: () => <PublicRegistryArticle id={registryCategoryId('registry')} />,
98
+ }),
79
99
  Surface.create({
80
100
  id: 'plugin-details',
81
- role: 'article',
82
- filter: AppSurface.pluginSection(),
101
+ filter: AppSurface.subject(AppSurface.Article, Plugin.isPlugin),
83
102
  component: ({ data: { subject } }) => {
84
103
  return <PluginArticle subject={subject} />;
85
104
  },
86
105
  }),
87
106
  Surface.create({
88
107
  id: LOAD_PLUGIN_DIALOG,
89
- role: 'dialog',
90
- filter: AppSurface.componentDialog(LOAD_PLUGIN_DIALOG),
108
+ filter: AppSurface.component(AppSurface.Dialog, LOAD_PLUGIN_DIALOG),
91
109
  component: () => <LoadPluginDialog />,
92
110
  }),
111
+ Surface.create({
112
+ id: DISABLE_DEPENDENTS_DIALOG,
113
+ filter: AppSurface.component<ComponentProps<typeof DisableDependentsAlert>>(
114
+ AppSurface.Dialog,
115
+ DISABLE_DEPENDENTS_DIALOG,
116
+ ),
117
+ component: ({ data }) => <DisableDependentsAlert {...data.props} />,
118
+ }),
119
+ Surface.create({
120
+ id: 'plugin-settings',
121
+ role: 'article',
122
+ filter: (data): data is { subject: AppCapabilities.Settings } =>
123
+ AppCapabilities.isSettings(data.subject) && data.subject.prefix === meta.id,
124
+ component: ({ data: { subject } }) => <RegistrySettingsContainer subject={subject} />,
125
+ }),
93
126
  ]),
94
127
  ),
95
128
  );
129
+
130
+ type PluginPredicate = (plugin: Plugin.Plugin) => boolean;
131
+
132
+ /**
133
+ * Renders the {@link RegistryArticle} surface filtered by an arbitrary
134
+ * predicate computed against the live plugin list. Centralises the
135
+ * `usePluginManager` + `useRegistryPlugins` + `useAutoTags` wiring shared
136
+ * by every category surface.
137
+ */
138
+ const FilteredRegistryArticle = ({ id, filter }: { id: string; filter: PluginPredicate }) => {
139
+ const manager = usePluginManager();
140
+ const { entries } = useRegistryPlugins();
141
+ const extraTagsById = useAutoTags(entries);
142
+ const filtered = useMemo(() => manager.getPlugins().filter(filter), [manager, filter]);
143
+
144
+ return <RegistryArticle id={id} plugins={filtered} extraTagsById={extraTagsById} />;
145
+ };
@@ -0,0 +1,34 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+
7
+ import { Capability, PLUGIN_DEV_SERVER_PORT } from '@dxos/app-framework';
8
+ import { AppCapabilities } from '@dxos/app-toolkit';
9
+ import { createKvsStore } from '@dxos/effect';
10
+
11
+ import { meta } from '#meta';
12
+
13
+ import { RegistryCapabilities, RegistrySettingsSchema } from '../types';
14
+
15
+ const DEFAULT_DEV_PLUGIN_URL = `http://localhost:${PLUGIN_DEV_SERVER_PORT}/manifest.json`;
16
+
17
+ export default Capability.makeModule(() =>
18
+ Effect.sync(() => {
19
+ const settingsAtom = createKvsStore({
20
+ key: meta.id,
21
+ schema: RegistrySettingsSchema,
22
+ defaultValue: () => ({ devPluginUrl: DEFAULT_DEV_PLUGIN_URL }),
23
+ });
24
+
25
+ return [
26
+ Capability.contributes(RegistryCapabilities.Settings, settingsAtom),
27
+ Capability.contributes(AppCapabilities.Settings, {
28
+ prefix: meta.id,
29
+ schema: RegistrySettingsSchema,
30
+ atom: settingsAtom,
31
+ }),
32
+ ];
33
+ }),
34
+ );