@dxos/plugin-registry 0.8.4-main.422d1c7879 → 0.8.4-main.4f23b4e393

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 (193) hide show
  1. package/dist/lib/neutral/RegistryPlugin.mjs +27 -0
  2. package/dist/lib/neutral/RegistryPlugin.mjs.map +7 -0
  3. package/dist/lib/{browser/cli/index.mjs → neutral/RegistryPlugin.node.mjs} +29 -95
  4. package/dist/lib/neutral/RegistryPlugin.node.mjs.map +7 -0
  5. package/dist/lib/neutral/chunk-XK2JMH3H.mjs +33 -0
  6. package/dist/lib/neutral/chunk-XK2JMH3H.mjs.map +7 -0
  7. package/dist/lib/neutral/chunk-YV7A523U.mjs +29 -0
  8. package/dist/lib/neutral/chunk-YV7A523U.mjs.map +7 -0
  9. package/dist/lib/neutral/index.mjs +21 -0
  10. package/dist/lib/neutral/index.mjs.map +7 -0
  11. package/dist/lib/neutral/meta.json +1 -0
  12. package/dist/lib/neutral/open-plugin-registry-II735N76.mjs +15 -0
  13. package/dist/lib/neutral/open-plugin-registry-II735N76.mjs.map +7 -0
  14. package/dist/lib/neutral/plugin.mjs +18 -0
  15. package/dist/lib/neutral/plugin.mjs.map +7 -0
  16. package/dist/lib/neutral/translations.mjs +61 -0
  17. package/dist/lib/neutral/translations.mjs.map +7 -0
  18. package/dist/types/src/RegistryPlugin.d.ts +1 -0
  19. package/dist/types/src/RegistryPlugin.d.ts.map +1 -1
  20. package/dist/types/src/{cli/plugin.d.ts → RegistryPlugin.node.d.ts} +2 -1
  21. package/dist/types/src/RegistryPlugin.node.d.ts.map +1 -0
  22. package/dist/types/src/RegistryPlugin.test.d.ts +2 -0
  23. package/dist/types/src/RegistryPlugin.test.d.ts.map +1 -0
  24. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  25. package/dist/types/src/capabilities/dev-plugin-loader.d.ts +11 -0
  26. package/dist/types/src/capabilities/dev-plugin-loader.d.ts.map +1 -0
  27. package/dist/types/src/capabilities/index.d.ts +11 -2
  28. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  29. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  30. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -1
  31. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  32. package/dist/types/src/capabilities/settings.d.ts +14 -0
  33. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  34. package/dist/types/src/{cli/commands → commands}/disable.d.ts +2 -2
  35. package/dist/types/src/commands/disable.d.ts.map +1 -0
  36. package/dist/types/src/{cli/commands → commands}/enable.d.ts +2 -2
  37. package/dist/types/src/commands/enable.d.ts.map +1 -0
  38. package/dist/types/src/commands/index.d.ts.map +1 -0
  39. package/dist/types/src/commands/list.d.ts +7 -0
  40. package/dist/types/src/commands/list.d.ts.map +1 -0
  41. package/dist/types/src/commands/util.d.ts.map +1 -0
  42. package/dist/types/src/components/PluginDetail/PluginDetail.d.ts +26 -2
  43. package/dist/types/src/components/PluginDetail/PluginDetail.d.ts.map +1 -1
  44. package/dist/types/src/components/PluginDetail/PluginDetail.stories.d.ts +49 -23
  45. package/dist/types/src/components/PluginDetail/PluginDetail.stories.d.ts.map +1 -1
  46. package/dist/types/src/components/PluginFailureBadge/PluginFailureBadge.d.ts +20 -0
  47. package/dist/types/src/components/PluginFailureBadge/PluginFailureBadge.d.ts.map +1 -0
  48. package/dist/types/src/components/PluginFailureBadge/index.d.ts +2 -0
  49. package/dist/types/src/components/PluginFailureBadge/index.d.ts.map +1 -0
  50. package/dist/types/src/components/PluginList/PluginItem.d.ts +17 -3
  51. package/dist/types/src/components/PluginList/PluginItem.d.ts.map +1 -1
  52. package/dist/types/src/components/PluginList/PluginList.d.ts +14 -4
  53. package/dist/types/src/components/PluginList/PluginList.d.ts.map +1 -1
  54. package/dist/types/src/components/PluginList/PluginList.stories.d.ts +49 -23
  55. package/dist/types/src/components/PluginList/PluginList.stories.d.ts.map +1 -1
  56. package/dist/types/src/components/RegistrySettings/RegistrySettings.d.ts +18 -0
  57. package/dist/types/src/components/RegistrySettings/RegistrySettings.d.ts.map +1 -0
  58. package/dist/types/src/components/RegistrySettings/index.d.ts +2 -0
  59. package/dist/types/src/components/RegistrySettings/index.d.ts.map +1 -0
  60. package/dist/types/src/components/index.d.ts +2 -0
  61. package/dist/types/src/components/index.d.ts.map +1 -1
  62. package/dist/types/src/containers/BaseRegistryArticle/BaseRegistryArticle.d.ts +20 -0
  63. package/dist/types/src/containers/BaseRegistryArticle/BaseRegistryArticle.d.ts.map +1 -0
  64. package/dist/types/src/containers/BaseRegistryArticle/index.d.ts +2 -0
  65. package/dist/types/src/containers/BaseRegistryArticle/index.d.ts.map +1 -0
  66. package/dist/types/src/containers/LoadPluginDialog/LoadPluginDialog.d.ts.map +1 -1
  67. package/dist/types/src/containers/PluginArticle/PluginArticle.d.ts.map +1 -1
  68. package/dist/types/src/containers/PublicRegistryArticle/PublicRegistryArticle.d.ts +8 -0
  69. package/dist/types/src/containers/PublicRegistryArticle/PublicRegistryArticle.d.ts.map +1 -0
  70. package/dist/types/src/containers/PublicRegistryArticle/index.d.ts +2 -0
  71. package/dist/types/src/containers/PublicRegistryArticle/index.d.ts.map +1 -0
  72. package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts +14 -0
  73. package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts.map +1 -0
  74. package/dist/types/src/containers/RegistryArticle/index.d.ts +2 -0
  75. package/dist/types/src/containers/RegistryArticle/index.d.ts.map +1 -0
  76. package/dist/types/src/containers/RegistrySettingsContainer/RegistrySettingsContainer.d.ts +13 -0
  77. package/dist/types/src/containers/RegistrySettingsContainer/RegistrySettingsContainer.d.ts.map +1 -0
  78. package/dist/types/src/containers/RegistrySettingsContainer/index.d.ts +2 -0
  79. package/dist/types/src/containers/RegistrySettingsContainer/index.d.ts.map +1 -0
  80. package/dist/types/src/containers/index.d.ts +3 -2
  81. package/dist/types/src/containers/index.d.ts.map +1 -1
  82. package/dist/types/src/hooks/index.d.ts +2 -1
  83. package/dist/types/src/hooks/index.d.ts.map +1 -1
  84. package/dist/types/src/hooks/use-auto-tags.d.ts +4 -4
  85. package/dist/types/src/hooks/use-auto-tags.d.ts.map +1 -1
  86. package/dist/types/src/hooks/use-registry-plugins.d.ts +15 -0
  87. package/dist/types/src/hooks/use-registry-plugins.d.ts.map +1 -0
  88. package/dist/types/src/hooks/use-update-available.d.ts +18 -0
  89. package/dist/types/src/hooks/use-update-available.d.ts.map +1 -0
  90. package/dist/types/src/index.d.ts +1 -1
  91. package/dist/types/src/index.d.ts.map +1 -1
  92. package/dist/types/src/meta.d.ts.map +1 -1
  93. package/dist/types/src/operations/index.d.ts +1 -1
  94. package/dist/types/src/operations/index.d.ts.map +1 -1
  95. package/dist/types/src/operations/open-plugin-registry.d.ts +1 -1
  96. package/dist/types/src/operations/open-plugin-registry.d.ts.map +1 -1
  97. package/dist/types/src/plugin.d.ts +4 -0
  98. package/dist/types/src/plugin.d.ts.map +1 -0
  99. package/dist/types/src/{cli/storage.d.ts → storage.d.ts} +1 -1
  100. package/dist/types/src/storage.d.ts.map +1 -0
  101. package/dist/types/src/translations.d.ts +48 -23
  102. package/dist/types/src/translations.d.ts.map +1 -1
  103. package/dist/types/src/types.d.ts +28 -10
  104. package/dist/types/src/types.d.ts.map +1 -1
  105. package/dist/types/tsconfig.tsbuildinfo +1 -1
  106. package/package.json +46 -36
  107. package/src/{cli/plugin.ts → RegistryPlugin.node.ts} +2 -0
  108. package/src/RegistryPlugin.test.ts +24 -0
  109. package/src/RegistryPlugin.tsx +9 -7
  110. package/src/capabilities/app-graph-builder.ts +25 -17
  111. package/src/capabilities/dev-plugin-loader.ts +39 -0
  112. package/src/capabilities/index.ts +3 -2
  113. package/src/capabilities/operation-handler.ts +1 -1
  114. package/src/capabilities/react-surface.tsx +63 -47
  115. package/src/capabilities/settings.ts +34 -0
  116. package/src/components/PluginDetail/PluginDetail.stories.tsx +3 -2
  117. package/src/components/PluginDetail/PluginDetail.tsx +105 -15
  118. package/src/components/PluginFailureBadge/PluginFailureBadge.tsx +68 -0
  119. package/src/components/PluginFailureBadge/index.ts +5 -0
  120. package/src/components/PluginList/PluginItem.tsx +46 -7
  121. package/src/components/PluginList/PluginList.stories.tsx +1 -1
  122. package/src/components/PluginList/PluginList.tsx +28 -5
  123. package/src/components/RegistrySettings/RegistrySettings.tsx +120 -0
  124. package/src/components/RegistrySettings/index.ts +5 -0
  125. package/src/components/index.ts +2 -0
  126. package/src/containers/BaseRegistryArticle/BaseRegistryArticle.tsx +163 -0
  127. package/src/containers/BaseRegistryArticle/index.ts +5 -0
  128. package/src/containers/LoadPluginDialog/LoadPluginDialog.tsx +4 -3
  129. package/src/containers/PluginArticle/PluginArticle.tsx +296 -32
  130. package/src/containers/PublicRegistryArticle/PublicRegistryArticle.tsx +192 -0
  131. package/src/containers/PublicRegistryArticle/index.ts +5 -0
  132. package/src/containers/RegistryArticle/RegistryArticle.tsx +53 -0
  133. package/src/containers/RegistryArticle/index.ts +5 -0
  134. package/src/containers/RegistrySettingsContainer/RegistrySettingsContainer.tsx +59 -0
  135. package/src/containers/RegistrySettingsContainer/index.ts +5 -0
  136. package/src/containers/index.ts +3 -2
  137. package/src/hooks/index.ts +2 -1
  138. package/src/hooks/use-auto-tags.ts +7 -8
  139. package/src/hooks/use-registry-plugins.ts +29 -0
  140. package/src/hooks/use-update-available.ts +31 -0
  141. package/src/index.ts +1 -1
  142. package/src/meta.ts +2 -0
  143. package/src/operations/index.ts +1 -1
  144. package/src/operations/open-plugin-registry.ts +1 -1
  145. package/src/plugin.ts +11 -0
  146. package/src/translations.ts +33 -3
  147. package/src/types.ts +21 -14
  148. package/dist/lib/browser/cli/index.mjs.map +0 -7
  149. package/dist/lib/browser/index.mjs +0 -78
  150. package/dist/lib/browser/index.mjs.map +0 -7
  151. package/dist/lib/browser/meta.json +0 -1
  152. package/dist/lib/node-esm/cli/index.mjs +0 -221
  153. package/dist/lib/node-esm/cli/index.mjs.map +0 -7
  154. package/dist/lib/node-esm/index.mjs +0 -80
  155. package/dist/lib/node-esm/index.mjs.map +0 -7
  156. package/dist/lib/node-esm/meta.json +0 -1
  157. package/dist/types/src/capabilities/state.d.ts +0 -7
  158. package/dist/types/src/capabilities/state.d.ts.map +0 -1
  159. package/dist/types/src/cli/commands/disable.d.ts.map +0 -1
  160. package/dist/types/src/cli/commands/enable.d.ts.map +0 -1
  161. package/dist/types/src/cli/commands/index.d.ts.map +0 -1
  162. package/dist/types/src/cli/commands/list.d.ts +0 -7
  163. package/dist/types/src/cli/commands/list.d.ts.map +0 -1
  164. package/dist/types/src/cli/commands/util.d.ts.map +0 -1
  165. package/dist/types/src/cli/index.d.ts +0 -3
  166. package/dist/types/src/cli/index.d.ts.map +0 -1
  167. package/dist/types/src/cli/plugin.d.ts.map +0 -1
  168. package/dist/types/src/cli/storage.d.ts.map +0 -1
  169. package/dist/types/src/containers/CommunityRegistry/CommunityRegistry.d.ts +0 -8
  170. package/dist/types/src/containers/CommunityRegistry/CommunityRegistry.d.ts.map +0 -1
  171. package/dist/types/src/containers/CommunityRegistry/index.d.ts +0 -2
  172. package/dist/types/src/containers/CommunityRegistry/index.d.ts.map +0 -1
  173. package/dist/types/src/containers/PluginRegistry/PluginRegistry.d.ts +0 -14
  174. package/dist/types/src/containers/PluginRegistry/PluginRegistry.d.ts.map +0 -1
  175. package/dist/types/src/containers/PluginRegistry/index.d.ts +0 -2
  176. package/dist/types/src/containers/PluginRegistry/index.d.ts.map +0 -1
  177. package/dist/types/src/hooks/use-community-plugins.d.ts +0 -16
  178. package/dist/types/src/hooks/use-community-plugins.d.ts.map +0 -1
  179. package/src/capabilities/state.ts +0 -40
  180. package/src/cli/index.ts +0 -6
  181. package/src/containers/CommunityRegistry/CommunityRegistry.tsx +0 -181
  182. package/src/containers/CommunityRegistry/index.ts +0 -5
  183. package/src/containers/PluginRegistry/PluginRegistry.tsx +0 -98
  184. package/src/containers/PluginRegistry/index.ts +0 -5
  185. package/src/hooks/use-community-plugins.ts +0 -35
  186. /package/dist/types/src/{cli/commands → commands}/index.d.ts +0 -0
  187. /package/dist/types/src/{cli/commands → commands}/util.d.ts +0 -0
  188. /package/src/{cli/commands → commands}/disable.ts +0 -0
  189. /package/src/{cli/commands → commands}/enable.ts +0 -0
  190. /package/src/{cli/commands → commands}/index.ts +0 -0
  191. /package/src/{cli/commands → commands}/list.ts +0 -0
  192. /package/src/{cli/commands → commands}/util.ts +0 -0
  193. /package/src/{cli/storage.ts → storage.ts} +0 -0
@@ -0,0 +1,192 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { useAtomValue } from '@effect-atom/atom-react';
6
+ import * as Effect from 'effect/Effect';
7
+ import React, { useCallback, useMemo, useState } from 'react';
8
+
9
+ import { type Registry, Plugin, UrlLoader } from '@dxos/app-framework';
10
+ import { useOperationInvoker, usePluginManager } from '@dxos/app-framework/ui';
11
+ import { runAndForwardErrors } from '@dxos/effect';
12
+ import { ObservabilityOperation } from '@dxos/plugin-observability';
13
+ import { useTranslation } from '@dxos/react-ui';
14
+ import { composable } from '@dxos/ui-theme';
15
+
16
+ import { meta } from '#meta';
17
+
18
+ import { useAutoTags, useRegistryPlugins, useUpdateAvailableIds } from '../../hooks';
19
+ import { BaseRegistryArticle } from '../BaseRegistryArticle';
20
+
21
+ const sortEntries = (a: Registry.Plugin, b: Registry.Plugin) => (a.name ?? a.id).localeCompare(b.name ?? b.id);
22
+
23
+ const sortPlugins = (a: Plugin.Plugin, b: Plugin.Plugin) =>
24
+ (a.meta.name ?? a.meta.id).localeCompare(b.meta.name ?? b.meta.id);
25
+
26
+ /**
27
+ * Turns a registry catalog entry into a minimal Plugin object so we can reuse
28
+ * {@link BaseRegistryArticle} for rendering. The synthesized plugin has no
29
+ * modules — it exists only for display until the user installs it.
30
+ */
31
+ const toDisplayPlugin = (plugin: Registry.Plugin): Plugin.Plugin =>
32
+ ({
33
+ [Plugin.PluginTypeId]: Plugin.PluginTypeId,
34
+ meta: {
35
+ id: plugin.id,
36
+ name: plugin.name,
37
+ description: plugin.description,
38
+ homePage: plugin.homePage,
39
+ source: plugin.source,
40
+ screenshots: plugin.screenshots,
41
+ tags: plugin.tags,
42
+ icon: plugin.icon,
43
+ iconHue: plugin.iconHue,
44
+ },
45
+ modules: [],
46
+ }) as Plugin.Plugin;
47
+
48
+ export type PublicRegistryArticleProps = {
49
+ id: string;
50
+ };
51
+
52
+ export const PublicRegistryArticle = composable<HTMLDivElement, PublicRegistryArticleProps>(
53
+ ({ id, ...props }, forwardedRef) => {
54
+ const { t } = useTranslation(meta.id);
55
+ const manager = usePluginManager();
56
+ const { invoke } = useOperationInvoker();
57
+ const { entries, loading, error } = useRegistryPlugins();
58
+ const plugins = useAtomValue(manager.plugins);
59
+ const installedIds = useMemo(() => plugins.map((plugin) => plugin.meta.id), [plugins]);
60
+ const extraTagsById = useAutoTags(entries);
61
+
62
+ // Snapshot of installed plugin ids at mount time. Used to sort installed
63
+ // plugins to the top without having newly-installed rows jump up mid-session.
64
+ const [installedSnapshot] = useState<ReadonlySet<string>>(
65
+ () => new Set(manager.getPlugins().map((plugin) => plugin.meta.id)),
66
+ );
67
+
68
+ const [installingIds, setInstallingIds] = useState<readonly string[]>([]);
69
+ const [updatingIds, setUpdatingIds] = useState<readonly string[]>([]);
70
+ const updateAvailableIds = useUpdateAvailableIds(entries);
71
+
72
+ const sortedEntries = useMemo(() => [...entries].sort(sortEntries), [entries]);
73
+ const moduleUrlById = useMemo(() => {
74
+ const map: Record<string, string> = {};
75
+ for (const entry of sortedEntries) {
76
+ map[entry.id] = entry.moduleUrl;
77
+ }
78
+ return map;
79
+ }, [sortedEntries]);
80
+
81
+ // Maps plugin id → current registry version (i.e. plugin.version from the catalog).
82
+ const versionById = useMemo(() => {
83
+ const map: Record<string, string> = {};
84
+ for (const entry of sortedEntries) {
85
+ map[entry.id] = entry.version;
86
+ }
87
+ return map;
88
+ }, [sortedEntries]);
89
+
90
+ // Single list with installed-at-mount plugins sorted to the top. Sort order
91
+ // is based on the mount-time snapshot so rows don't jump as the user
92
+ // installs plugins during the session.
93
+ const items = useMemo(() => {
94
+ const catalogIds = new Set(sortedEntries.map((entry) => entry.id));
95
+ const remoteIds = new Set(UrlLoader.getRemoteEntries().map((entry) => entry.id));
96
+ const fromCatalog = sortedEntries.map(toDisplayPlugin);
97
+ const fromUrlOnly = plugins.filter((plugin) => remoteIds.has(plugin.meta.id) && !catalogIds.has(plugin.meta.id));
98
+ const installedFirst = [...fromCatalog, ...fromUrlOnly].sort((a, b) => {
99
+ const aInstalled = installedSnapshot.has(a.meta.id);
100
+ const bInstalled = installedSnapshot.has(b.meta.id);
101
+ if (aInstalled !== bInstalled) {
102
+ return aInstalled ? -1 : 1;
103
+ }
104
+ return sortPlugins(a, b);
105
+ });
106
+ return installedFirst;
107
+ }, [sortedEntries, installedSnapshot, plugins]);
108
+
109
+ const handleInstall = useCallback(
110
+ (pluginId: string) => {
111
+ const moduleUrl = moduleUrlById[pluginId];
112
+ const version = versionById[pluginId];
113
+ if (!moduleUrl) {
114
+ return;
115
+ }
116
+ setInstallingIds((prev) => (prev.includes(pluginId) ? prev : [...prev, pluginId]));
117
+ void Effect.gen(function* () {
118
+ const plugin = yield* manager.add(moduleUrl);
119
+ yield* manager.enable(plugin.meta.id);
120
+ // Persist the installed version for future update detection.
121
+ if (version) {
122
+ UrlLoader.setInstalledVersion(plugin.meta.id, version);
123
+ }
124
+ yield* invoke(ObservabilityOperation.SendEvent, {
125
+ name: 'plugins.install',
126
+ properties: { plugin: plugin.meta.id, source: 'registry' },
127
+ });
128
+ }).pipe(
129
+ Effect.ensuring(Effect.sync(() => setInstallingIds((prev) => prev.filter((pid) => pid !== pluginId)))),
130
+ runAndForwardErrors,
131
+ );
132
+ },
133
+ [invoke, manager, moduleUrlById, versionById],
134
+ );
135
+
136
+ const handleUpdate = useCallback(
137
+ (pluginId: string) => {
138
+ const moduleUrl = moduleUrlById[pluginId];
139
+ const version = versionById[pluginId];
140
+ if (!moduleUrl) {
141
+ return;
142
+ }
143
+ setUpdatingIds((prev) => (prev.includes(pluginId) ? prev : [...prev, pluginId]));
144
+ void Effect.gen(function* () {
145
+ // Unload the old version then re-install from the new URL.
146
+ yield* manager.remove(pluginId);
147
+ const plugin = yield* manager.add(moduleUrl);
148
+ yield* manager.enable(plugin.meta.id);
149
+ if (version) {
150
+ UrlLoader.setInstalledVersion(plugin.meta.id, version);
151
+ }
152
+ yield* invoke(ObservabilityOperation.SendEvent, {
153
+ name: 'plugins.update',
154
+ properties: { plugin: plugin.meta.id, source: 'registry' },
155
+ });
156
+ }).pipe(
157
+ Effect.ensuring(Effect.sync(() => setUpdatingIds((prev) => prev.filter((pid) => pid !== pluginId)))),
158
+ runAndForwardErrors,
159
+ );
160
+ },
161
+ [invoke, manager, moduleUrlById, versionById],
162
+ );
163
+
164
+ const empty = error ? (
165
+ <div className='p-4 text-description'>{t('registry.error.label', { message: error.message })}</div>
166
+ ) : loading ? (
167
+ <div className='p-4 text-description'>{t('registry.loading.label')}</div>
168
+ ) : (
169
+ <div className='p-4 text-description'>{t('registry.empty.label')}</div>
170
+ );
171
+
172
+ return (
173
+ <BaseRegistryArticle
174
+ {...props}
175
+ id={id}
176
+ source='registry'
177
+ plugins={items}
178
+ installed={installedIds}
179
+ installing={installingIds}
180
+ updating={updatingIds}
181
+ updateAvailableIds={updateAvailableIds}
182
+ extraTagsById={extraTagsById}
183
+ onInstall={handleInstall}
184
+ onUpdate={handleUpdate}
185
+ empty={empty}
186
+ ref={forwardedRef}
187
+ />
188
+ );
189
+ },
190
+ );
191
+
192
+ PublicRegistryArticle.displayName = 'PublicRegistryArticle';
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export { PublicRegistryArticle as default, PublicRegistryArticle } from './PublicRegistryArticle';
@@ -0,0 +1,53 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { useAtomValue } from '@effect-atom/atom-react';
6
+ import React, { useMemo } from 'react';
7
+
8
+ import { type Plugin, type PluginManager } from '@dxos/app-framework';
9
+ import { usePluginManager } from '@dxos/app-framework/ui';
10
+ import { composable } from '@dxos/ui-theme';
11
+
12
+ import { BaseRegistryArticle } from '../BaseRegistryArticle';
13
+
14
+ const sortByPluginMeta = (a: Plugin.Plugin, b: Plugin.Plugin) =>
15
+ (a.meta.name ?? a.meta.id).localeCompare(b.meta.name ?? b.meta.id);
16
+
17
+ export type RegistryArticleProps = {
18
+ id: string;
19
+ plugins: Plugin.Plugin[];
20
+ /**
21
+ * Map from plugin id → display-only tags (e.g. `registry`, `local`) computed by the caller.
22
+ */
23
+ extraTagsById?: Record<string, readonly string[]>;
24
+ };
25
+
26
+ export const RegistryArticle = composable<HTMLDivElement, RegistryArticleProps>(
27
+ ({ id, plugins: pluginsProp, extraTagsById, ...props }, forwardedRef) => {
28
+ const manager = usePluginManager();
29
+ const failed = useAtomValue(manager.failed);
30
+ const plugins = useMemo(() => [...pluginsProp].sort(sortByPluginMeta), [pluginsProp]);
31
+ const failuresById = useMemo(
32
+ () =>
33
+ failed.reduce<Record<string, PluginManager.PluginFailure>>((acc, failure) => {
34
+ acc[failure.id] = failure;
35
+ return acc;
36
+ }, {}),
37
+ [failed],
38
+ );
39
+
40
+ return (
41
+ <BaseRegistryArticle
42
+ {...props}
43
+ id={id}
44
+ plugins={plugins}
45
+ extraTagsById={extraTagsById}
46
+ failuresById={failuresById}
47
+ ref={forwardedRef}
48
+ />
49
+ );
50
+ },
51
+ );
52
+
53
+ RegistryArticle.displayName = 'RegistryArticle';
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export { RegistryArticle as default, RegistryArticle } from './RegistryArticle';
@@ -0,0 +1,59 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { useAtomValue } from '@effect-atom/atom-react';
6
+ import * as Effect from 'effect/Effect';
7
+ import React, { useCallback } from 'react';
8
+
9
+ import { useSettingsState, usePluginManager } from '@dxos/app-framework/ui';
10
+ import { type AppCapabilities } from '@dxos/app-toolkit';
11
+ import { runAndForwardErrors } from '@dxos/effect';
12
+
13
+ import { RegistrySettings } from '../../components';
14
+ import { type RegistrySettings as RegistrySettingsType } from '../../types';
15
+
16
+ export type RegistrySettingsContainerProps = {
17
+ subject: AppCapabilities.Settings;
18
+ };
19
+
20
+ /**
21
+ * Wires the {@link RegistrySettings} presentational component to the plugin
22
+ * manager and the settings atom: subscribes to `manager.devPluginIds` for the
23
+ * "currently loaded" indicator and exposes enable/disable callbacks that drive
24
+ * the manager's add/enable/remove flow.
25
+ */
26
+ export const RegistrySettingsContainer = ({ subject }: RegistrySettingsContainerProps) => {
27
+ const manager = usePluginManager();
28
+ const { settings, updateSettings } = useSettingsState<RegistrySettingsType>(subject.atom);
29
+ const activeDevPluginIds = useAtomValue(manager.devPluginIds);
30
+
31
+ const onEnableDev = useCallback(
32
+ async (url: string) => {
33
+ await runAndForwardErrors(
34
+ Effect.gen(function* () {
35
+ const plugin = yield* manager.add(url);
36
+ yield* manager.enable(plugin.meta.id);
37
+ }),
38
+ );
39
+ },
40
+ [manager],
41
+ );
42
+
43
+ const onDisableDev = useCallback(
44
+ async (id: string) => {
45
+ await runAndForwardErrors(manager.remove(id));
46
+ },
47
+ [manager],
48
+ );
49
+
50
+ return (
51
+ <RegistrySettings
52
+ settings={settings}
53
+ onSettingsChange={updateSettings}
54
+ activeDevPluginIds={activeDevPluginIds}
55
+ onEnableDev={onEnableDev}
56
+ onDisableDev={onDisableDev}
57
+ />
58
+ );
59
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ export { RegistrySettingsContainer as default } from './RegistrySettingsContainer';
@@ -5,7 +5,8 @@
5
5
  import { type ComponentType, lazy } from 'react';
6
6
 
7
7
  export { LOAD_PLUGIN_DIALOG } from './LoadPluginDialog/LoadPluginDialog';
8
- export const CommunityRegistry: ComponentType<any> = lazy(() => import('./CommunityRegistry'));
9
8
  export const LoadPluginDialog: ComponentType<any> = lazy(() => import('./LoadPluginDialog'));
10
9
  export const PluginArticle: ComponentType<any> = lazy(() => import('./PluginArticle'));
11
- export const PluginRegistry: ComponentType<any> = lazy(() => import('./PluginRegistry'));
10
+ export const PublicRegistryArticle: ComponentType<any> = lazy(() => import('./PublicRegistryArticle'));
11
+ export const RegistryArticle: ComponentType<any> = lazy(() => import('./RegistryArticle'));
12
+ export const RegistrySettingsContainer: ComponentType<any> = lazy(() => import('./RegistrySettingsContainer'));
@@ -3,4 +3,5 @@
3
3
  //
4
4
 
5
5
  export * from './use-auto-tags';
6
- export * from './use-community-plugins';
6
+ export * from './use-registry-plugins';
7
+ export * from './use-update-available';
@@ -4,12 +4,11 @@
4
4
 
5
5
  import { useMemo } from 'react';
6
6
 
7
- import { UrlLoader } from '@dxos/app-framework';
8
- import { type PluginEntry } from '@dxos/protocols';
7
+ import { type Registry, UrlLoader } from '@dxos/app-framework';
9
8
 
10
9
  /**
11
10
  * Auto-tags that are derived at display time rather than persisted to `Plugin.Meta`.
12
- * - `community`: plugin id appears in the community registry manifest.
11
+ * - `registry`: plugin id appears in the registry catalog manifest.
13
12
  * - `local`: plugin was loaded from a `localhost` / `127.0.0.1` / `::1` URL.
14
13
  */
15
14
  export type AutoTagsMap = Record<string, readonly string[]>;
@@ -18,9 +17,9 @@ export type AutoTagsMap = Record<string, readonly string[]>;
18
17
  * Computes the per-plugin-id extra tags the UI should display.
19
18
  *
20
19
  * Reads the persisted remote-plugin entries synchronously to derive `local`, and
21
- * adds `community` for any plugin id found in the supplied community manifest entries.
20
+ * adds `registry` for any plugin id found in the supplied registry manifest entries.
22
21
  */
23
- export const useAutoTags = (communityEntries: readonly PluginEntry[]): AutoTagsMap =>
22
+ export const useAutoTags = (registryEntries: readonly Registry.Plugin[]): AutoTagsMap =>
24
23
  useMemo(() => {
25
24
  const byId: Record<string, string[]> = {};
26
25
  const addTag = (id: string, tag: string) => {
@@ -37,12 +36,12 @@ export const useAutoTags = (communityEntries: readonly PluginEntry[]): AutoTagsM
37
36
  addTag(entry.id, 'local');
38
37
  }
39
38
  }
40
- for (const entry of communityEntries) {
41
- addTag(entry.meta.id, 'community');
39
+ for (const entry of registryEntries) {
40
+ addTag(entry.id, 'registry');
42
41
  }
43
42
 
44
43
  return byId;
45
- }, [communityEntries]);
44
+ }, [registryEntries]);
46
45
 
47
46
  /**
48
47
  * Returns the set of plugin ids known to originate from a remote URL (not bundled).
@@ -0,0 +1,29 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { useAtomValue } from '@effect-atom/atom-react';
6
+
7
+ import { type Registry } from '@dxos/app-framework';
8
+ import { usePluginManager } from '@dxos/app-framework/ui';
9
+
10
+ /**
11
+ * Reads the registry plugin catalog from `manager.pluginRegistry.plugins`.
12
+ * The catalog is loaded once when the plugin manager is constructed (with a
13
+ * provider) so this hook is purely reactive — subscribers re-render as the
14
+ * `{entries, loading, error}` state settles.
15
+ */
16
+ export const useRegistryPlugins = (): Registry.PluginsState => {
17
+ const manager = usePluginManager();
18
+ return useAtomValue(manager.pluginRegistry.plugins);
19
+ };
20
+
21
+ /**
22
+ * Returns the live `Registry.Manager` from the plugin manager so callers can
23
+ * issue `listVersions` / `getPlugin` calls directly. The catalog state itself
24
+ * is best read through {@link useRegistryPlugins} above.
25
+ */
26
+ export const useRegistryPluginProvider = (): Registry.Manager => {
27
+ const manager = usePluginManager();
28
+ return manager.pluginRegistry;
29
+ };
@@ -0,0 +1,31 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type Registry, UrlLoader } from '@dxos/app-framework';
6
+
7
+ /**
8
+ * Returns a set of plugin ids for which the registry has a newer version
9
+ * than what was recorded at install time.
10
+ *
11
+ * Only flags plugins where a version was recorded at install time AND it differs
12
+ * from the catalog's current version. Legacy installs (no version stored) are ignored.
13
+ *
14
+ * NOTE: this is intentionally NOT memoised. The installed-version side of the
15
+ * comparison lives in localStorage and is mutated by `manager.add` /
16
+ * `manager.remove` / `UrlLoader.setInstalledVersion` outside React's view, so a
17
+ * memo keyed on `entries` would happily return stale data for the rest of the
18
+ * session after an update completes (the bug that produced "Update button
19
+ * reappears after Updating…"). The loop is O(catalog size) sync reads — cheap
20
+ * enough to do every render.
21
+ */
22
+ export const useUpdateAvailableIds = (entries: readonly Registry.Plugin[]): ReadonlySet<string> => {
23
+ const ids = new Set<string>();
24
+ for (const entry of entries) {
25
+ const installedVersion = UrlLoader.getInstalledVersion(entry.id);
26
+ if (installedVersion !== undefined && installedVersion !== entry.version) {
27
+ ids.add(entry.id);
28
+ }
29
+ }
30
+ return ids;
31
+ };
package/src/index.ts CHANGED
@@ -3,4 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './meta';
6
- export * from './RegistryPlugin';
6
+ export * from './storage';
package/src/meta.ts CHANGED
@@ -25,4 +25,6 @@ export const meta: Plugin.Meta = {
25
25
  Plugin management system for discovering, installing, and configuring workspace extensions.
26
26
  Browse available plugins and customize your workspace capabilities.
27
27
  `,
28
+ icon: 'ph--squares-four--regular',
29
+ tags: ['system'],
28
30
  };
@@ -2,6 +2,6 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { OperationHandlerSet } from '@dxos/operation';
5
+ import { OperationHandlerSet } from '@dxos/compute';
6
6
 
7
7
  export const RegistryOperationHandlerSet = OperationHandlerSet.lazy(() => import('./open-plugin-registry'));
@@ -5,7 +5,7 @@
5
5
  import * as Effect from 'effect/Effect';
6
6
 
7
7
  import { LayoutOperation, SettingsOperation, getSpacePath } from '@dxos/app-toolkit';
8
- import { Operation } from '@dxos/operation';
8
+ import { Operation } from '@dxos/compute';
9
9
 
10
10
  import { REGISTRY_ID } from '#meta';
11
11
 
package/src/plugin.ts ADDED
@@ -0,0 +1,11 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { Plugin } from '@dxos/app-framework';
6
+
7
+ import { meta } from './meta';
8
+
9
+ export const RegistryPlugin = Plugin.lazy(meta, () => import('#plugin'));
10
+
11
+ export { RegistryOperationHandlerSet } from './operations';
@@ -14,23 +14,53 @@ export const translations = [
14
14
  'details.label': 'Details',
15
15
  'home-page.label': 'Website',
16
16
  'source.label': 'Source',
17
- 'plugin-registry.label': 'Plugin Registry',
17
+ 'plugin-registry.label': 'Plugins',
18
+ 'plugin-settings.label': 'Plugin Settings',
18
19
  'official-plugins.label': 'Official',
19
20
  'installed-plugins.label': 'Enabled',
20
21
  'recommended-plugins.label': 'Recommended',
21
22
  'labs-plugins.label': 'Labs',
22
- 'community-plugins.label': 'Community',
23
+ 'registry-plugins.label': 'Registry',
23
24
  'load-by-url.label': 'Load from URL',
24
25
  'load-by-url-dialog.title': 'Load Plugin from URL',
25
26
  'plugin-url.label': 'Plugin URL',
26
27
  'load-plugin.label': 'Load Plugin',
27
28
  'loading.label': 'Loading...',
29
+ 'filter.label': 'Filter plugins',
30
+ 'filter.placeholder': 'Filter…',
31
+ 'registry.loading.label': 'Loading registry plugins…',
32
+ 'registry.error.label': 'Failed to load registry plugins: {{message}}',
33
+ 'registry.empty.label': 'No registry plugins available.',
34
+ 'dev-plugin.section.title': 'Dev plugin',
35
+ 'dev-plugin.description':
36
+ 'Load a plugin from a local Vite dev server (the `composerPlugin` defaults to port 3967). Composer reattaches it on every reload, surviving HMR — useful when iterating on a community plugin against a live registry version.',
37
+ 'dev-plugin.url.label': 'Manifest URL',
38
+ 'dev-plugin.url.description':
39
+ 'Defaults to the local dev server. Edit if your dev server runs on a different port.',
40
+ 'dev-plugin.toggle.label': 'Dev plugin',
41
+ 'dev-plugin.toggle.description':
42
+ 'Stays on across reloads. If the dev server is offline at boot, a warning is logged and the next reload retries.',
43
+ 'dev-plugin.enable.label': 'Enable',
44
+ 'dev-plugin.disable.label': 'Disable',
45
+ 'dev-plugin.busy.label': 'Loading…',
46
+ 'dev-plugin.not-loaded.message':
47
+ 'Dev plugin is enabled but not currently loaded. Check that the dev server is running, then reload.',
28
48
  'coming-soon.label': 'Coming soon!',
29
49
  'open-plugin-registry.label': 'Open plugin registry',
30
- 'settings.label': 'Settings',
31
50
  'install.label': 'Install',
32
51
  'installing.label': 'Installing…',
33
52
  'uninstall.label': 'Uninstall',
53
+ 'update.label': 'Update',
54
+ 'updating.label': 'Updating…',
55
+ 'versions.label': 'Versions',
56
+ 'installed.label': 'installed',
57
+ 'install-version.label': 'Install version',
58
+ 'failure-badge.label': 'Plugin failure details',
59
+ 'failure-title.label': 'Plugin {{phase}} failed: {{reason}}',
60
+ 'failure-phase-load.label': 'load',
61
+ 'failure-phase-activation.label': 'activation',
62
+ 'failure-reason-timeout.label': 'timed out',
63
+ 'failure-reason-error.label': 'error',
34
64
  },
35
65
  },
36
66
  },
package/src/types.ts CHANGED
@@ -6,28 +6,35 @@ import { type Atom } from '@effect-atom/atom-react';
6
6
  import * as Schema from 'effect/Schema';
7
7
 
8
8
  import { Capability } from '@dxos/app-framework';
9
- import { type PluginEntry } from '@dxos/protocols';
10
-
11
- import { meta } from '#meta';
12
-
13
- export type CommunityPluginsState = {
14
- entries: readonly PluginEntry[];
15
- loading: boolean;
16
- error: Error | null;
17
- };
18
-
19
- export namespace RegistryCapabilities {
20
- export const State = Capability.make<Atom.Atom<CommunityPluginsState>>(`${meta.id}.capability.state`);
21
- }
22
9
 
23
10
  export const RegistrySettingsSchema = Schema.mutable(
24
11
  Schema.Struct({
25
12
  experimental: Schema.optional(Schema.Boolean),
13
+ /**
14
+ * Manifest URL for a plugin served by a local Vite dev server. The
15
+ * registry settings panel pre-fills this with `localhost:3967`; authors
16
+ * iterating on a different port can edit it.
17
+ */
18
+ devPluginUrl: Schema.optional(Schema.String),
19
+ /**
20
+ * When true, the registry plugin attempts to load `devPluginUrl` on every
21
+ * app boot. Failures (dev server offline, manifest 404) are logged and
22
+ * the flag stays on so the next boot retries — the user explicitly turns
23
+ * it off when they're done iterating.
24
+ */
25
+ devPluginEnabled: Schema.optional(Schema.Boolean),
26
26
  }),
27
27
  );
28
28
 
29
29
  export type RegistrySettings = Schema.Schema.Type<typeof RegistrySettingsSchema>;
30
30
 
31
+ /**
32
+ * Per-plugin capabilities exposed by `@dxos/plugin-registry`.
33
+ */
34
+ export namespace RegistryCapabilities {
35
+ export const Settings = Capability.make<Atom.Writable<RegistrySettings>>('@dxos/plugin-registry/settings');
36
+ }
37
+
31
38
  export const RegistryTagType = Schema.Literal(
32
39
  'new',
33
40
  'beta',
@@ -35,7 +42,7 @@ export const RegistryTagType = Schema.Literal(
35
42
  'popular',
36
43
  'featured',
37
44
  'experimental',
38
- 'community',
45
+ 'registry',
39
46
  'local',
40
47
  );
41
48
 
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../src/cli/plugin.ts", "../../../../src/cli/commands/index.ts", "../../../../src/cli/commands/disable.ts", "../../../../src/cli/storage.ts", "../../../../src/cli/commands/enable.ts", "../../../../src/cli/commands/list.ts", "../../../../src/cli/commands/util.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppPlugin } from '@dxos/app-toolkit';\n\nimport { meta } from '#meta';\n\nimport { plugin } from './commands';\n\nexport const RegistryPlugin = Plugin.define(meta).pipe(\n AppPlugin.addCommandModule({\n commands: [plugin],\n }),\n Plugin.make,\n);\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Command from '@effect/cli/Command';\n\nimport { disable } from './disable';\nimport { enable } from './enable';\nimport { list } from './list';\n\nexport const plugin: Command.Command<any, any, any, any> = Command.make('plugin').pipe(\n Command.withDescription('Manage plugins.'),\n Command.withSubcommands([enable, disable, list]),\n);\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Args from '@effect/cli/Args';\nimport * as Command from '@effect/cli/Command';\nimport * as Console from 'effect/Console';\nimport * as Effect from 'effect/Effect';\n\nimport { Plugin } from '@dxos/app-framework';\nimport { CommandConfig } from '@dxos/cli-util';\nimport { invariant } from '@dxos/invariant';\n\nimport { saveEnabledPlugins } from '../storage';\n\nexport const handler = Effect.fn(function* ({ id }: { id: string }) {\n const { json, profile } = yield* CommandConfig;\n const manager = yield* Plugin.Service;\n\n const plugins = manager.getPlugins();\n const plugin = plugins.find((p: Plugin.Plugin) => p.meta.id === id);\n invariant(plugin, `Plugin not found: ${id}`);\n\n const core = manager.getCore();\n invariant(!core.includes(id), `Cannot disable core plugin: ${id}`);\n\n const disabled = yield* manager.disable(id);\n invariant(disabled, `Failed to disable plugin: ${id}`);\n\n // Save enabled plugins to storage\n const enabledPlugins = manager.getEnabled();\n yield* saveEnabledPlugins({ profile, enabled: [...enabledPlugins] });\n\n if (json) {\n yield* Console.log(JSON.stringify({ id, enabled: false }, null, 2));\n } else {\n yield* Console.log(`Plugin \"${plugin.meta.name ?? id}\" disabled.`);\n }\n});\n\nexport const disable = Command.make(\n 'disable',\n {\n id: Args.text({ name: 'id' }).pipe(Args.withDescription('The ID of the plugin to disable.')),\n },\n handler,\n).pipe(Command.withDescription('Disable a plugin.'));\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as FileSystem from '@effect/platform/FileSystem';\nimport * as Path from '@effect/platform/Path';\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\nimport * as Yaml from 'yaml';\n\nimport { DX_CONFIG } from '@dxos/client-protocol';\n\n// TODO(wittjosiah): Factor out to app-framework?\n\nconst PluginsSchema = Schema.Array(Schema.String);\n\n/** CLI-only: path to plugins/<profile>.yml (sibling to profile/). */\nconst getPluginsConfigPath = (profile: string) => `${DX_CONFIG}/plugins/${profile}.yml`;\n\n/**\n * Load enabled plugins from plugins/<profile>.yml (sibling to profile/).\n * Returns the list of enabled plugin IDs, or an empty array if the file doesn't exist.\n */\nexport const loadEnabledPlugins = Effect.fn(function* ({ profile }: { profile: string }) {\n const fs = yield* FileSystem.FileSystem;\n const pluginsPath = getPluginsConfigPath(profile);\n\n const content = yield* fs\n .readFileString(pluginsPath)\n .pipe(Effect.catchTag('SystemError', () => Effect.succeed('[]')));\n\n const raw = Yaml.parse(content);\n const parsed = yield* Schema.decodeUnknown(PluginsSchema)(raw ?? []).pipe(\n Effect.catchAll(() => Effect.succeed([] as string[])),\n );\n\n return parsed;\n});\n\n/**\n * Save enabled plugins to plugins/<profile>.yml.\n */\nexport const saveEnabledPlugins = Effect.fn(function* ({ profile, enabled }: { profile: string; enabled: string[] }) {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n const pluginsPath = getPluginsConfigPath(profile);\n yield* fs.makeDirectory(path.dirname(pluginsPath), { recursive: true });\n const encoded = Yaml.stringify(enabled);\n yield* fs.writeFileString(pluginsPath, encoded);\n});\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Args from '@effect/cli/Args';\nimport * as Command from '@effect/cli/Command';\nimport * as Console from 'effect/Console';\nimport * as Effect from 'effect/Effect';\n\nimport { Plugin } from '@dxos/app-framework';\nimport { CommandConfig } from '@dxos/cli-util';\nimport { invariant } from '@dxos/invariant';\n\nimport { saveEnabledPlugins } from '../storage';\n\nexport const handler = Effect.fn(function* ({ id }: { id: string }) {\n const { json, profile } = yield* CommandConfig;\n const manager = yield* Plugin.Service;\n\n const plugins = manager.getPlugins();\n const plugin = plugins.find((p: Plugin.Plugin) => p.meta.id === id);\n invariant(plugin, `Plugin not found: ${id}`);\n\n const enabled = yield* manager.enable(id);\n invariant(enabled, `Failed to enable plugin: ${id}`);\n\n // Save enabled plugins to storage\n const enabledPlugins = manager.getEnabled();\n yield* saveEnabledPlugins({ profile, enabled: [...enabledPlugins] });\n\n if (json) {\n yield* Console.log(JSON.stringify({ id, enabled: true }, null, 2));\n } else {\n yield* Console.log(`Plugin \"${plugin.meta.name ?? id}\" enabled.`);\n }\n});\n\nexport const enable = Command.make(\n 'enable',\n {\n id: Args.text({ name: 'id' }).pipe(Args.withDescription('The ID of the plugin to enable.')),\n },\n handler,\n).pipe(Command.withDescription('Enable a plugin.'));\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Command from '@effect/cli/Command';\nimport * as Console from 'effect/Console';\nimport * as Effect from 'effect/Effect';\n\nimport { Plugin } from '@dxos/app-framework';\nimport { CommandConfig, printList } from '@dxos/cli-util';\n\nimport { type FormattedPlugin, printPlugin } from './util';\n\nexport const handler = Effect.fn(function* () {\n const { json } = yield* CommandConfig;\n const manager = yield* Plugin.Service;\n\n const plugins = manager.getPlugins();\n const enabled = manager.getEnabled();\n const core = manager.getCore();\n\n const formattedPlugins: FormattedPlugin[] = plugins.map((plugin: Plugin.Plugin) => {\n const isEnabled = enabled.includes(plugin.meta.id);\n const isCore = core.includes(plugin.meta.id);\n return {\n id: plugin.meta.id,\n name: plugin.meta.name ?? plugin.meta.id,\n enabled: isEnabled,\n core: isCore,\n };\n });\n\n if (json) {\n yield* Console.log(JSON.stringify(formattedPlugins, null, 2));\n } else {\n const formatted = formattedPlugins.map(printPlugin);\n yield* Console.log(printList(formatted));\n }\n});\n\nexport const list = Command.make('list', {}, handler).pipe(Command.withDescription('List all available plugins.'));\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { FormBuilder } from '@dxos/cli-util';\n\nexport type FormattedPlugin = {\n id: string;\n name: string;\n enabled: boolean;\n core: boolean;\n};\n\n/**\n * Pretty prints a plugin with ANSI colors.\n */\nexport const printPlugin = (plugin: FormattedPlugin) => {\n const status = plugin.core ? 'core' : plugin.enabled ? 'enabled' : 'disabled';\n return FormBuilder.make({ title: plugin.name }).pipe(\n FormBuilder.set('id', plugin.id),\n FormBuilder.set('status', status),\n FormBuilder.build,\n );\n};\n"],
5
- "mappings": "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",
6
- "names": ["Plugin", "AppPlugin", "meta", "Command", "Args", "Command", "Console", "Effect", "Plugin", "CommandConfig", "invariant", "FileSystem", "Path", "Effect", "Schema", "Yaml", "DX_CONFIG", "PluginsSchema", "Array", "String", "getPluginsConfigPath", "profile", "DX_CONFIG", "loadEnabledPlugins", "fn", "fs", "FileSystem", "pluginsPath", "content", "readFileString", "pipe", "catchTag", "succeed", "raw", "parse", "parsed", "decodeUnknown", "catchAll", "saveEnabledPlugins", "enabled", "path", "Path", "makeDirectory", "dirname", "recursive", "encoded", "stringify", "writeFileString", "handler", "fn", "id", "json", "profile", "CommandConfig", "manager", "Plugin", "Service", "plugins", "getPlugins", "plugin", "find", "p", "meta", "invariant", "core", "getCore", "includes", "disabled", "disable", "enabledPlugins", "getEnabled", "saveEnabledPlugins", "enabled", "log", "JSON", "stringify", "name", "make", "text", "pipe", "withDescription", "Args", "Command", "Console", "Effect", "Plugin", "CommandConfig", "invariant", "handler", "fn", "id", "json", "profile", "CommandConfig", "manager", "Plugin", "Service", "plugins", "getPlugins", "plugin", "find", "p", "meta", "invariant", "enabled", "enable", "enabledPlugins", "getEnabled", "saveEnabledPlugins", "log", "JSON", "stringify", "name", "make", "text", "pipe", "withDescription", "Command", "Console", "Effect", "Plugin", "CommandConfig", "printList", "FormBuilder", "printPlugin", "plugin", "status", "core", "enabled", "FormBuilder", "make", "title", "name", "pipe", "set", "id", "build", "handler", "fn", "json", "CommandConfig", "manager", "Plugin", "Service", "plugins", "getPlugins", "enabled", "getEnabled", "core", "getCore", "formattedPlugins", "map", "plugin", "isEnabled", "includes", "meta", "id", "isCore", "name", "log", "JSON", "stringify", "formatted", "printPlugin", "printList", "list", "make", "pipe", "withDescription", "plugin", "make", "pipe", "withDescription", "withSubcommands", "enable", "disable", "list", "RegistryPlugin", "Plugin", "define", "meta", "pipe", "AppPlugin", "addCommandModule", "commands", "plugin", "make"]
7
- }