@dxos/plugin-devtools 0.12.0-next-2800d0376abcc62d5544afdd744b16b2b960434e → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/PLUGIN.mdl +144 -57
  2. package/dist/lib/Devtools.mjs +9 -1
  3. package/dist/lib/Devtools.mjs.map +1 -1
  4. package/dist/lib/capabilities.browser.mjs +45 -0
  5. package/dist/lib/capabilities.browser.mjs.map +1 -0
  6. package/dist/lib/capabilities.mjs +9 -7
  7. package/dist/lib/capabilities.mjs.map +1 -1
  8. package/dist/lib/capabilities.node.mjs +7 -3
  9. package/dist/lib/capabilities.node.mjs.map +1 -1
  10. package/dist/lib/capabilities.tauri.mjs +45 -0
  11. package/dist/lib/capabilities.tauri.mjs.map +1 -0
  12. package/dist/lib/capabilities.workerd.mjs +2 -2
  13. package/dist/lib/capabilities.workerd.mjs.map +1 -1
  14. package/dist/lib/{chunk-CliPanel.mjs → chunk-CliArticle.mjs} +28 -24
  15. package/dist/lib/chunk-CliArticle.mjs.map +1 -0
  16. package/dist/lib/chunk-DebugGraph.mjs +12 -8
  17. package/dist/lib/chunk-DebugGraph.mjs.map +1 -1
  18. package/dist/lib/chunk-DevtoolsCards.mjs +108 -0
  19. package/dist/lib/chunk-DevtoolsCards.mjs.map +1 -0
  20. package/dist/lib/chunk-DevtoolsOverviewContainer.mjs +59 -22
  21. package/dist/lib/chunk-DevtoolsOverviewContainer.mjs.map +1 -1
  22. package/dist/lib/chunk-GithubPanel.mjs +13 -10
  23. package/dist/lib/chunk-GithubPanel.mjs.map +1 -1
  24. package/dist/lib/chunk-PLUGIN.mjs +6 -0
  25. package/dist/lib/chunk-PLUGIN.mjs.map +1 -0
  26. package/dist/lib/{chunk-RegistryPanel.mjs → chunk-RegistryArticle.mjs} +26 -25
  27. package/dist/lib/chunk-RegistryArticle.mjs.map +1 -0
  28. package/dist/lib/chunk-ToolsExplorerContainer.mjs +22 -0
  29. package/dist/lib/chunk-ToolsExplorerContainer.mjs.map +1 -0
  30. package/dist/lib/chunk-app-graph-builder.mjs +323 -312
  31. package/dist/lib/chunk-app-graph-builder.mjs.map +1 -1
  32. package/dist/lib/chunk-react-context.mjs +1 -1
  33. package/dist/lib/chunk-react-context.mjs.map +1 -1
  34. package/dist/lib/chunk-react-surface.mjs +244 -92
  35. package/dist/lib/chunk-react-surface.mjs.map +1 -1
  36. package/dist/lib/containers.mjs +4 -3
  37. package/dist/lib/containers.mjs.map +1 -1
  38. package/dist/lib/index.mjs +0 -1
  39. package/dist/lib/meta.mjs +2 -2
  40. package/dist/lib/meta.mjs.map +1 -1
  41. package/dist/lib/translations.mjs +55 -49
  42. package/dist/lib/translations.mjs.map +1 -1
  43. package/dist/types/src/capabilities/DevtoolsCards.d.ts +28 -0
  44. package/dist/types/src/capabilities/DevtoolsCards.d.ts.map +1 -0
  45. package/dist/types/src/capabilities/DevtoolsSurfaces.d.ts +19 -6
  46. package/dist/types/src/capabilities/DevtoolsSurfaces.d.ts.map +1 -1
  47. package/dist/types/src/capabilities/app-graph-builder.d.ts +19 -0
  48. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  49. package/dist/types/src/capabilities/app-graph-builder.test.d.ts +2 -0
  50. package/dist/types/src/capabilities/app-graph-builder.test.d.ts.map +1 -0
  51. package/dist/types/src/capabilities/gen/browser.d.ts +8 -0
  52. package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -0
  53. package/dist/types/src/capabilities/gen/tauri.d.ts +8 -0
  54. package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -0
  55. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  56. package/dist/types/src/containers/CliArticle/CliArticle.d.ts +8 -0
  57. package/dist/types/src/containers/CliArticle/CliArticle.d.ts.map +1 -0
  58. package/dist/types/src/containers/{CliPanel/CliPanel.stories.d.ts → CliArticle/CliArticle.stories.d.ts} +34 -4
  59. package/dist/types/src/containers/CliArticle/CliArticle.stories.d.ts.map +1 -0
  60. package/dist/types/src/containers/CliArticle/index.d.ts +2 -0
  61. package/dist/types/src/containers/CliArticle/index.d.ts.map +1 -0
  62. package/dist/types/src/containers/{CliPanel → CliArticle}/useCliApp.d.ts +1 -1
  63. package/dist/types/src/containers/CliArticle/useCliApp.d.ts.map +1 -0
  64. package/dist/types/src/containers/DebugGraph/DebugGraph.d.ts +2 -1
  65. package/dist/types/src/containers/DebugGraph/DebugGraph.d.ts.map +1 -1
  66. package/dist/types/src/containers/DebugGraph/index.d.ts +1 -1
  67. package/dist/types/src/containers/DebugGraph/index.d.ts.map +1 -1
  68. package/dist/types/src/containers/DevtoolsOverviewContainer/DevtoolsOverviewContainer.d.ts.map +1 -1
  69. package/dist/types/src/containers/DevtoolsOverviewContainer/index.d.ts +1 -1
  70. package/dist/types/src/containers/DevtoolsOverviewContainer/index.d.ts.map +1 -1
  71. package/dist/types/src/containers/GithubPanel/GithubComponent.d.ts.map +1 -1
  72. package/dist/types/src/containers/GithubPanel/GithubComponent.stories.d.ts +31 -1
  73. package/dist/types/src/containers/GithubPanel/GithubComponent.stories.d.ts.map +1 -1
  74. package/dist/types/src/containers/GithubPanel/index.d.ts +1 -1
  75. package/dist/types/src/containers/GithubPanel/index.d.ts.map +1 -1
  76. package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts +8 -0
  77. package/dist/types/src/containers/RegistryArticle/RegistryArticle.d.ts.map +1 -0
  78. package/dist/types/src/containers/RegistryArticle/index.d.ts +2 -0
  79. package/dist/types/src/containers/RegistryArticle/index.d.ts.map +1 -0
  80. package/dist/types/src/containers/ToolsExplorerContainer/ToolsExplorerContainer.d.ts +8 -0
  81. package/dist/types/src/containers/ToolsExplorerContainer/ToolsExplorerContainer.d.ts.map +1 -0
  82. package/dist/types/src/containers/ToolsExplorerContainer/index.d.ts +2 -0
  83. package/dist/types/src/containers/ToolsExplorerContainer/index.d.ts.map +1 -0
  84. package/dist/types/src/containers/index.d.ts +3 -2
  85. package/dist/types/src/containers/index.d.ts.map +1 -1
  86. package/dist/types/src/index.d.ts +1 -2
  87. package/dist/types/src/index.d.ts.map +1 -1
  88. package/dist/types/src/translations.d.ts +31 -1
  89. package/dist/types/src/translations.d.ts.map +1 -1
  90. package/dist/types/src/types/Devtools.d.ts +6 -0
  91. package/dist/types/src/types/Devtools.d.ts.map +1 -1
  92. package/dist/types/src/types/index.d.ts +2 -2
  93. package/dist/types/src/types/index.d.ts.map +1 -1
  94. package/dist/types/tsconfig.tsbuildinfo +1 -1
  95. package/dx.config.ts +2 -2
  96. package/package.json +43 -39
  97. package/src/capabilities/DevtoolsCards.tsx +140 -0
  98. package/src/capabilities/DevtoolsSurfaces.tsx +32 -38
  99. package/src/capabilities/app-graph-builder.test.ts +75 -0
  100. package/src/capabilities/app-graph-builder.ts +324 -313
  101. package/src/capabilities/gen/browser.ts +61 -0
  102. package/src/capabilities/gen/node.ts +4 -4
  103. package/src/capabilities/gen/tauri.ts +61 -0
  104. package/src/capabilities/gen/workerd.ts +2 -2
  105. package/src/capabilities/index.ts +7 -7
  106. package/src/capabilities/react-context.tsx +1 -1
  107. package/src/capabilities/react-surface.ts +223 -85
  108. package/src/containers/{CliPanel/CliPanel.stories.tsx → CliArticle/CliArticle.stories.tsx} +9 -10
  109. package/src/containers/{CliPanel/CliPanel.tsx → CliArticle/CliArticle.tsx} +7 -7
  110. package/src/containers/CliArticle/index.ts +5 -0
  111. package/src/containers/{CliPanel → CliArticle}/useCliApp.ts +17 -12
  112. package/src/containers/DebugGraph/DebugGraph.tsx +7 -6
  113. package/src/containers/DebugGraph/index.ts +1 -1
  114. package/src/containers/DevtoolsOverviewContainer/DevtoolsOverviewContainer.tsx +72 -32
  115. package/src/containers/DevtoolsOverviewContainer/index.ts +1 -1
  116. package/src/containers/GithubPanel/GithubComponent.stories.tsx +2 -2
  117. package/src/containers/GithubPanel/GithubComponent.tsx +14 -11
  118. package/src/containers/GithubPanel/GithubPanel.tsx +2 -2
  119. package/src/containers/GithubPanel/index.ts +1 -1
  120. package/src/containers/{RegistryPanel/RegistryPanel.tsx → RegistryArticle/RegistryArticle.tsx} +11 -10
  121. package/src/containers/RegistryArticle/index.ts +5 -0
  122. package/src/containers/ToolsExplorerContainer/ToolsExplorerContainer.tsx +26 -0
  123. package/src/containers/ToolsExplorerContainer/index.ts +5 -0
  124. package/src/containers/index.ts +6 -5
  125. package/src/index.ts +1 -2
  126. package/src/meta.ts +1 -1
  127. package/src/plugin.test.ts +2 -2
  128. package/src/translations.ts +7 -3
  129. package/src/types/Devtools.ts +10 -0
  130. package/src/types/index.ts +2 -2
  131. package/dist/lib/chunk-CliPanel.mjs.map +0 -1
  132. package/dist/lib/chunk-RegistryPanel.mjs.map +0 -1
  133. package/dist/types/src/containers/CliPanel/CliPanel.d.ts +0 -6
  134. package/dist/types/src/containers/CliPanel/CliPanel.d.ts.map +0 -1
  135. package/dist/types/src/containers/CliPanel/CliPanel.stories.d.ts.map +0 -1
  136. package/dist/types/src/containers/CliPanel/index.d.ts +0 -2
  137. package/dist/types/src/containers/CliPanel/index.d.ts.map +0 -1
  138. package/dist/types/src/containers/CliPanel/useCliApp.d.ts.map +0 -1
  139. package/dist/types/src/containers/RegistryPanel/RegistryPanel.d.ts +0 -6
  140. package/dist/types/src/containers/RegistryPanel/RegistryPanel.d.ts.map +0 -1
  141. package/dist/types/src/containers/RegistryPanel/index.d.ts +0 -2
  142. package/dist/types/src/containers/RegistryPanel/index.d.ts.map +0 -1
  143. package/src/containers/CliPanel/index.ts +0 -5
  144. package/src/containers/RegistryPanel/index.ts +0 -5
@@ -9,11 +9,11 @@ var setupDevtools = () => {
9
9
  globalThis.composer ??= {};
10
10
  globalThis.composer.changeStorageVersionInMetadata = async (version) => {
11
11
  const { changeStorageVersionInMetadata } = await import("@dxos/client-services/testing");
12
- const { createStorageObjects } = await import("@dxos/client-services");
12
+ const { Storage } = await import("@dxos/client-services");
13
13
  const client = window.dxos.client;
14
14
  const config = client.config;
15
15
  await client.destroy();
16
- const { storage } = createStorageObjects(config.values?.runtime?.client?.storage ?? create(Runtime_Client_StorageSchema, {}));
16
+ const { storage } = Storage.createStorageObjects(config.values?.runtime?.client?.storage ?? create(Runtime_Client_StorageSchema, {}));
17
17
  await changeStorageVersionInMetadata(storage, version);
18
18
  location.pathname = "/";
19
19
  };
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.workerd.mjs","names":[],"sources":["../../src/capabilities/gen/workerd.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.\n\nimport { create } from '@bufbuild/protobuf';\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport { Runtime_Client_StorageSchema } from '@dxos/protocols/buf/dxos/config_pb';\nimport { type Client } from '@dxos/react-client';\n\nimport { translations } from '#translations';\n\nconst setupDevtools = () => {\n (globalThis as any).composer ??= {};\n\n // Used to test how composer handles breaking protocol changes.\n (globalThis as any).composer.changeStorageVersionInMetadata = async (version: number) => {\n const { changeStorageVersionInMetadata } = await import('@dxos/client-services/testing');\n const { createStorageObjects } = await import('@dxos/client-services');\n const client: Client = (window as any).dxos.client;\n const config = client.config;\n await client.destroy();\n const { storage } = createStorageObjects(\n config.values?.runtime?.client?.storage ?? create(Runtime_Client_StorageSchema, {}),\n );\n await changeStorageVersionInMetadata(storage, version);\n location.pathname = '/';\n };\n};\n\nexport const SetupDevtools = Capability.inlineModule('setup-devtools', { provides: [] }, () =>\n Effect.sync(() => setupDevtools()),\n);\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const AppGraphBuilder = undefined;\nexport const PluginAsset = undefined;\nexport const ReactContext = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;;;;AAgBA,IAAM,sBAAsB;CAC1B,WAAoB,aAAa,CAAC;CAGlC,WAAoB,SAAS,iCAAiC,OAAO,YAAoB;EACvF,MAAM,EAAE,mCAAmC,MAAM,OAAO;EACxD,MAAM,EAAE,yBAAyB,MAAM,OAAO;EAC9C,MAAM,SAAkB,OAAe,KAAK;EAC5C,MAAM,SAAS,OAAO;EACtB,MAAM,OAAO,QAAQ;EACrB,MAAM,EAAE,YAAY,qBAClB,OAAO,QAAQ,SAAS,QAAQ,WAAW,OAAO,8BAA8B,CAAC,CAAC,CACpF;EACA,MAAM,+BAA+B,SAAS,OAAO;EACrD,SAAS,WAAW;CACtB;AACF;AAEA,IAAa,gBAAgB,WAAW,aAAa,kBAAkB,EAAE,UAAU,CAAC,EAAE,SACpF,OAAO,WAAW,cAAc,CAAC,CACnC;AAEA,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,kBAAkB,KAAA;AAC/B,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA;AAC5B,IAAa,eAAe,KAAA"}
1
+ {"version":3,"file":"capabilities.workerd.mjs","names":[],"sources":["../../src/capabilities/gen/workerd.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.\n\nimport { create } from '@bufbuild/protobuf';\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport { Runtime_Client_StorageSchema } from '@dxos/protocols/buf/dxos/config_pb';\nimport { type Client } from '@dxos/react-client';\n\nimport { translations } from '#translations';\n\nconst setupDevtools = () => {\n (globalThis as any).composer ??= {};\n\n // Used to test how composer handles breaking protocol changes.\n (globalThis as any).composer.changeStorageVersionInMetadata = async (version: number) => {\n const { changeStorageVersionInMetadata } = await import('@dxos/client-services/testing');\n const { Storage } = await import('@dxos/client-services');\n const client: Client = (window as any).dxos.client;\n const config = client.config;\n await client.destroy();\n const { storage } = Storage.createStorageObjects(\n config.values?.runtime?.client?.storage ?? create(Runtime_Client_StorageSchema, {}),\n );\n await changeStorageVersionInMetadata(storage, version);\n location.pathname = '/';\n };\n};\n\nexport const SetupDevtools = Capability.inlineModule('setup-devtools', { provides: [] }, () =>\n Effect.sync(() => setupDevtools()),\n);\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const AppGraphBuilder = undefined;\nexport const PluginAsset = undefined;\nexport const ReactContext = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;;;;AAgBA,IAAM,sBAAsB;CAC1B,WAAoB,aAAa,CAAC;CAGlC,WAAoB,SAAS,iCAAiC,OAAO,YAAoB;EACvF,MAAM,EAAE,mCAAmC,MAAM,OAAO;EACxD,MAAM,EAAE,YAAY,MAAM,OAAO;EACjC,MAAM,SAAkB,OAAe,KAAK;EAC5C,MAAM,SAAS,OAAO;EACtB,MAAM,OAAO,QAAQ;EACrB,MAAM,EAAE,YAAY,QAAQ,qBAC1B,OAAO,QAAQ,SAAS,QAAQ,WAAW,OAAO,8BAA8B,CAAC,CAAC,CACpF;EACA,MAAM,+BAA+B,SAAS,OAAO;EACrD,SAAS,WAAW;CACtB;AACF;AAEA,IAAa,gBAAgB,WAAW,aAAa,kBAAkB,EAAE,UAAU,CAAC,EAAE,SACpF,OAAO,WAAW,cAAc,CAAC,CACnC;AAEA,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,kBAAkB,KAAA;AAC/B,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA;AAC5B,IAAa,eAAe,KAAA"}
@@ -3,21 +3,22 @@ import * as Capability from "@dxos/app-framework/Capability";
3
3
  import * as Plugin from "@dxos/app-framework/Plugin";
4
4
  import { useEffect, useMemo } from "react";
5
5
  import * as Capabilities from "@dxos/app-framework/Capabilities";
6
- import { useCapabilities, usePluginManager } from "@dxos/app-framework/ui";
7
6
  import { Placeholder } from "@dxos/devtools";
8
7
  import { jsx } from "react/jsx-runtime";
8
+ import * as Hooks from "@dxos/app-framework/Hooks";
9
9
  import { useClient } from "@dxos/react-client";
10
- import { Panel } from "@dxos/react-ui";
11
10
  import { Terminal } from "@dxos/react-ui-terminal";
11
+ import * as Panel from "@dxos/react-ui/Panel";
12
+ import * as Command from "effect/cli/Command";
13
+ import * as Options from "effect/cli/Flag";
12
14
  import * as Layer from "effect/Layer";
13
- import * as Command from "effect/unstable/cli/Command";
14
- import * as Options from "effect/unstable/cli/Flag";
15
15
  import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
16
+ import * as PluginManagerProvider from "@dxos/app-framework/PluginManagerProvider";
16
17
  import { CommandConfig } from "@dxos/cli-util";
17
- import { ClientService, ConfigService } from "@dxos/client";
18
+ import { fromClient, fromConfig } from "@dxos/client";
18
19
  import * as Operation from "@dxos/compute/Operation";
19
- import { EffectEx } from "@dxos/effect";
20
- //#region src/containers/CliPanel/useCliApp.ts
20
+ import * as EffectEx from "@dxos/effect/EffectEx";
21
+ //#region src/containers/CliArticle/useCliApp.ts
21
22
  var OPERATIONS_UNAVAILABLE = "Operations are not available in the devtools terminal.";
22
23
  /**
23
24
  * Commands that create objects invoke operations, which this surface has no runtime for. Failing
@@ -44,9 +45,9 @@ var operationLayer = Layer.succeed(Operation.Service, {
44
45
  * Returns `undefined` until something contributes commands — there is no shell to offer yet.
45
46
  */
46
47
  var useCliApp = (client) => {
47
- const manager = usePluginManager();
48
- const commands = useCapabilities(Capabilities.Command);
49
- const contributed = useCapabilities(Capabilities.Layer);
48
+ const manager = PluginManagerProvider.usePluginManager();
49
+ const commands = Hooks.useCapabilities(Capabilities.Command);
50
+ const contributed = Hooks.useCapabilities(Capabilities.Layer);
50
51
  useEffect(() => {
51
52
  EffectEx.runDetached(manager.activate(ActivationEvents.CommandsRequested));
52
53
  }, [manager]);
@@ -54,15 +55,15 @@ var useCliApp = (client) => {
54
55
  const [first, ...rest] = commands;
55
56
  if (!first) return;
56
57
  const command = Command.make("dx").pipe(Command.withSharedFlags({
57
- json: Options.boolean("json").pipe(Options.withDescription("JSON output.")),
58
- verbose: Options.boolean("verbose").pipe(Options.withAlias("v"), Options.withDescription("Verbose output."))
58
+ json: Options.Boolean("json").pipe(Options.withDefault(false), Options.withDescription("JSON output.")),
59
+ verbose: Options.Boolean("verbose").pipe(Options.withDefault(false), Options.withAlias("v"), Options.withDescription("Verbose output."))
59
60
  }), Command.withSubcommands([first, ...rest]), Command.provide((input) => Layer.succeed(CommandConfig, {
60
61
  json: "json" in input ? input.json : false,
61
62
  verbose: "verbose" in input ? input.verbose : false,
62
63
  profile: "default",
63
64
  logLevel: "info"
64
65
  })));
65
- const hostLayer = Layer.mergeAll(ClientService.fromClient(client), ConfigService.fromConfig(client.config), Layer.succeed(Plugin.Service, manager), Layer.succeed(Capability.Service, manager.capabilities), operationLayer);
66
+ const hostLayer = Layer.mergeAll(fromClient(client), fromConfig(client.config), Layer.succeed(Plugin.Service, manager), Layer.succeed(Capability.Service, manager.capabilities), operationLayer);
66
67
  return {
67
68
  command,
68
69
  layer: Layer.orDie(Layer.mergeAll(hostLayer, ...contributed))
@@ -75,7 +76,7 @@ var useCliApp = (client) => {
75
76
  ]);
76
77
  };
77
78
  //#endregion
78
- //#region src/containers/CliPanel/CliPanel.tsx
79
+ //#region src/containers/CliArticle/CliArticle.tsx
79
80
  var BOLD = "\x1B[1m";
80
81
  var DIM = "\x1B[2m";
81
82
  var RESET = "\x1B[0m";
@@ -87,17 +88,20 @@ var BANNER = `${BOLD}DXOS CLI${RESET}\n${DIM}The dx commands, running against th
87
88
  * services are built once per client, so state the handlers hold survives between commands the way
88
89
  * it does in a long-lived shell.
89
90
  */
90
- var CliPanel = () => {
91
+ var CliArticle = ({ role }) => {
91
92
  const cli = useCliApp(useClient());
92
- return /* @__PURE__ */ jsx(Panel.Root, { children: /* @__PURE__ */ jsx(Panel.Content, { children: cli ? /* @__PURE__ */ jsx(Terminal, {
93
- command: cli.command,
94
- layer: cli.layer,
95
- name: "dx",
96
- banner: BANNER
97
- }) : /* @__PURE__ */ jsx(Placeholder, { label: "No commands" }) }) });
93
+ return /* @__PURE__ */ jsx(Panel.Root, {
94
+ role,
95
+ children: /* @__PURE__ */ jsx(Panel.Body, { children: cli ? /* @__PURE__ */ jsx(Terminal, {
96
+ command: cli.command,
97
+ layer: cli.layer,
98
+ name: "dx",
99
+ banner: BANNER
100
+ }) : /* @__PURE__ */ jsx(Placeholder, { label: "No commands" }) })
101
+ });
98
102
  };
99
- CliPanel.displayName = "CliPanel";
103
+ CliArticle.displayName = "CliArticle";
100
104
  //#endregion
101
- export { CliPanel, CliPanel as default };
105
+ export { CliArticle, CliArticle as default };
102
106
 
103
- //# sourceMappingURL=chunk-CliPanel.mjs.map
107
+ //# sourceMappingURL=chunk-CliArticle.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-CliArticle.mjs","names":[],"sources":["../../src/containers/CliArticle/useCliApp.ts","../../src/containers/CliArticle/CliArticle.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Command from 'effect/cli/Command';\nimport * as Options from 'effect/cli/Flag';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport { useEffect, useMemo } from 'react';\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport * as Plugin from '@dxos/app-framework/Plugin';\nimport * as PluginManagerProvider from '@dxos/app-framework/PluginManagerProvider';\nimport { CommandConfig, type CommandServices } from '@dxos/cli-util';\nimport { type Client, fromClient, fromConfig } from '@dxos/client';\nimport * as Operation from '@dxos/compute/Operation';\nimport * as EffectEx from '@dxos/effect/EffectEx';\n\nconst OPERATIONS_UNAVAILABLE = 'Operations are not available in the devtools terminal.';\n\n/**\n * Commands that create objects invoke operations, which this surface has no runtime for. Failing\n * with a stated reason beats the bare \"Service not found\" a missing layer would produce.\n */\nconst operationLayer = Layer.succeed(Operation.Service, {\n invoke: () => Effect.die(OPERATIONS_UNAVAILABLE),\n schedule: () => Effect.die(OPERATIONS_UNAVAILABLE),\n invokePromise: async () => ({ error: new Error(OPERATIONS_UNAVAILABLE) }),\n});\n\n/**\n * Builds the `dx` command tree and the services its handlers need.\n *\n * Mounting is the demand signal: command modules are gated on `CommandsRequested`, which nothing\n * else in the app fires, so a plugin's commands stay off the critical path until a terminal opens.\n * The capability is read through its atom, so commands appear as they activate and enabling or\n * disabling a plugin later rebuilds the tree rather than leaving the terminal on the set that\n * existed when it mounted.\n *\n * The root mirrors the binary's, minus the options that only mean something on a filesystem\n * (`--config`, `--profile`); everything else resolves the same way, including `--space-id`\n * defaulting to the first available space.\n *\n * Returns `undefined` until something contributes commands — there is no shell to offer yet.\n */\nexport const useCliApp = (client: Client) => {\n const manager = PluginManagerProvider.usePluginManager();\n const commands = Hooks.useCapabilities(Capabilities.Command);\n const contributed = Hooks.useCapabilities(Capabilities.Layer);\n\n useEffect(() => {\n EffectEx.runDetached(manager.activate(ActivationEvents.CommandsRequested));\n }, [manager]);\n\n return useMemo(() => {\n // Destructured rather than passed as an array so the non-empty shape `withSubcommands` requires\n // is carried by the type instead of asserted.\n const [first, ...rest] = commands;\n if (!first) {\n return undefined;\n }\n\n const command = Command.make('dx').pipe(\n // Shared so they parse anywhere in the line — a plain command config is only read when `dx`\n // itself is the leaf.\n Command.withSharedFlags({\n json: Options.Boolean('json').pipe(Options.withDefault(false), Options.withDescription('JSON output.')),\n verbose: Options.Boolean('verbose').pipe(\n Options.withDefault(false),\n Options.withAlias('v'),\n Options.withDescription('Verbose output.'),\n ),\n }),\n Command.withSubcommands([first, ...rest]),\n // After the subcommands so the config reaches them: `provide` wraps the handler it is applied\n // to, and `withSubcommands` replaces that handler with one that dispatches to the children.\n // The input widens to a union across the tree, hence the presence checks.\n Command.provide((input) =>\n Layer.succeed(CommandConfig, {\n json: 'json' in input ? input.json : false,\n verbose: 'verbose' in input ? input.verbose : false,\n profile: 'default',\n logLevel: 'info',\n }),\n ),\n );\n\n // Annotated so a service this host owes is a build error naming it, rather than a\n // \"Service not found\" the first time someone runs the command that needed it.\n const hostLayer: Layer.Layer<CommandServices, never, never> = Layer.mergeAll(\n fromClient(client),\n fromConfig(client.config),\n Layer.succeed(Plugin.Service, manager),\n Layer.succeed(Capability.Service, manager.capabilities),\n operationLayer,\n );\n\n // Plugins carry anything further their own commands need. A contributed layer may fail to\n // build, and the shell runs on a fiber with nowhere to report that, so it dies here instead\n // of being smuggled into the terminal as an unhandled error channel.\n const layer = Layer.orDie(Layer.mergeAll(hostLayer, ...contributed));\n\n return { command, layer };\n }, [client, manager, commands, contributed]);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { Placeholder } from '@dxos/devtools';\nimport { useClient } from '@dxos/react-client';\nimport { Terminal } from '@dxos/react-ui-terminal';\nimport * as Panel from '@dxos/react-ui/Panel';\n\nimport { useCliApp } from './useCliApp.ts';\n\nconst BOLD = '\\x1b[1m';\nconst DIM = '\\x1b[2m';\nconst RESET = '\\x1b[0m';\n\nconst BANNER = `${BOLD}DXOS CLI${RESET}\\n${DIM}The dx commands, running against this client. Type \"help\" for the list.${RESET}`;\n\n/**\n * Runs the `dx` CLI against the client backing this app.\n *\n * The command tree is assembled from the commands the installed plugins contribute, and it and its\n * services are built once per client, so state the handlers hold survives between commands the way\n * it does in a long-lived shell.\n */\nexport const CliArticle = ({ role }: { role?: string }) => {\n const client = useClient();\n const cli = useCliApp(client);\n\n // No ScrollArea: xterm owns its own viewport and scrollback.\n return (\n <Panel.Root role={role}>\n <Panel.Body>\n {cli ? (\n <Terminal command={cli.command} layer={cli.layer} name='dx' banner={BANNER} />\n ) : (\n <Placeholder label='No commands' />\n )}\n </Panel.Body>\n </Panel.Root>\n );\n};\n\nCliArticle.displayName = 'CliArticle';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAqBA,IAAM,yBAAyB;;;;;AAM/B,IAAM,iBAAiB,MAAM,QAAQ,UAAU,SAAS;CACtD,cAAc,OAAO,IAAI,sBAAsB;CAC/C,gBAAgB,OAAO,IAAI,sBAAsB;CACjD,eAAe,aAAa,EAAE,uBAAO,IAAI,MAAM,sBAAsB,EAAE;AACzE,CAAC;;;;;;;;;;;;;;;;AAiBD,IAAa,aAAa,WAAmB;CAC3C,MAAM,UAAU,sBAAsB,iBAAiB;CACvD,MAAM,WAAW,MAAM,gBAAgB,aAAa,OAAO;CAC3D,MAAM,cAAc,MAAM,gBAAgB,aAAa,KAAK;CAE5D,gBAAgB;EACd,SAAS,YAAY,QAAQ,SAAS,iBAAiB,iBAAiB,CAAC;CAC3E,GAAG,CAAC,OAAO,CAAC;CAEZ,OAAO,cAAc;EAGnB,MAAM,CAAC,OAAO,GAAG,QAAQ;EACzB,IAAI,CAAC,OACH;EAGF,MAAM,UAAU,QAAQ,KAAK,IAAI,CAAC,CAAC,KAGjC,QAAQ,gBAAgB;GACtB,MAAM,QAAQ,QAAQ,MAAM,CAAC,CAAC,KAAK,QAAQ,YAAY,KAAK,GAAG,QAAQ,gBAAgB,cAAc,CAAC;GACtG,SAAS,QAAQ,QAAQ,SAAS,CAAC,CAAC,KAClC,QAAQ,YAAY,KAAK,GACzB,QAAQ,UAAU,GAAG,GACrB,QAAQ,gBAAgB,iBAAiB,CAC3C;EACF,CAAC,GACD,QAAQ,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC,GAIxC,QAAQ,SAAS,UACf,MAAM,QAAQ,eAAe;GAC3B,MAAM,UAAU,QAAQ,MAAM,OAAO;GACrC,SAAS,aAAa,QAAQ,MAAM,UAAU;GAC9C,SAAS;GACT,UAAU;EACZ,CAAC,CACH,CACF;EAIA,MAAM,YAAwD,MAAM,SAClE,WAAW,MAAM,GACjB,WAAW,OAAO,MAAM,GACxB,MAAM,QAAQ,OAAO,SAAS,OAAO,GACrC,MAAM,QAAQ,WAAW,SAAS,QAAQ,YAAY,GACtD,cACF;EAOA,OAAO;GAAE;GAAS,OAFJ,MAAM,MAAM,MAAM,SAAS,WAAW,GAAG,WAAW,CAEhD;EAAM;CAC1B,GAAG;EAAC;EAAQ;EAAS;EAAU;CAAW,CAAC;AAC7C;;;AC9FA,IAAM,OAAO;AACb,IAAM,MAAM;AACZ,IAAM,QAAQ;AAEd,IAAM,SAAS,GAAG,KAAK,UAAU,MAAM,IAAI,IAAI,yEAAyE;;;;;;;;AASxH,IAAa,cAAc,EAAE,WAA8B;CAEzD,MAAM,MAAM,UADG,UACO,CAAM;CAG5B,OACE,oBAAC,MAAM,MAAP;EAAkB;EAChB,UAAA,oBAAC,MAAM,MAAP,EAAA,UACG,MACC,oBAAC,UAAD;GAAU,SAAS,IAAI;GAAS,OAAO,IAAI;GAAO,MAAK;GAAK,QAAQ;EAAS,CAAA,IAE7E,oBAAC,aAAD,EAAa,OAAM,cAAe,CAAA,EAE1B,CAAA;CACF,CAAA;AAEhB;AAEA,WAAW,cAAc"}
@@ -1,17 +1,21 @@
1
1
  import "react";
2
2
  import { Tree } from "@dxos/devtools";
3
3
  import { jsx } from "react/jsx-runtime";
4
- import { Panel, ScrollArea } from "@dxos/react-ui";
4
+ import * as Panel from "@dxos/react-ui/Panel";
5
5
  import * as AppGraph from "@dxos/app-graph/AppGraph";
6
+ import * as ScrollArea from "@dxos/react-ui/ScrollArea";
6
7
  //#region src/containers/DebugGraph/DebugGraph.tsx
7
- var DebugGraph = ({ graph, root }) => {
8
- return /* @__PURE__ */ jsx(Panel.Root, { children: /* @__PURE__ */ jsx(Panel.Content, {
9
- asChild: true,
10
- children: /* @__PURE__ */ jsx(ScrollArea.Root, {
11
- orientation: "all",
12
- children: /* @__PURE__ */ jsx(ScrollArea.Viewport, { children: /* @__PURE__ */ jsx(Tree, { data: AppGraph.toJSON(graph, root) }) })
8
+ var DebugGraph = ({ role, graph, root }) => {
9
+ return /* @__PURE__ */ jsx(Panel.Root, {
10
+ role,
11
+ children: /* @__PURE__ */ jsx(Panel.Body, {
12
+ asChild: true,
13
+ children: /* @__PURE__ */ jsx(ScrollArea.Root, {
14
+ orientation: "all",
15
+ children: /* @__PURE__ */ jsx(ScrollArea.Viewport, { children: /* @__PURE__ */ jsx(Tree, { data: AppGraph.toJSON(graph, root) }) })
16
+ })
13
17
  })
14
- }) });
18
+ });
15
19
  };
16
20
  DebugGraph.displayName = "DebugGraph";
17
21
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-DebugGraph.mjs","names":[],"sources":["../../src/containers/DebugGraph/DebugGraph.tsx"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport React from 'react';\n\nimport * as AppGraph from '@dxos/app-graph/AppGraph';\nimport { Tree } from '@dxos/devtools';\nimport { Panel, ScrollArea } from '@dxos/react-ui';\n\nexport type DebugGraphProps = { graph: AppGraph.Graph; root: string };\n\nexport const DebugGraph = ({ graph, root }: DebugGraphProps) => {\n return (\n <Panel.Root>\n <Panel.Content asChild>\n <ScrollArea.Root orientation='all'>\n <ScrollArea.Viewport>\n <Tree data={AppGraph.toJSON(graph, root)} />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </Panel.Content>\n </Panel.Root>\n );\n};\n\nDebugGraph.displayName = 'DebugGraph';\n"],"mappings":";;;;;;AAYA,IAAa,cAAc,EAAE,OAAO,WAA4B;CAC9D,OACE,oBAAC,MAAM,MAAP,EAAA,UACE,oBAAC,MAAM,SAAP;EAAe,SAAA;EACb,UAAA,oBAAC,WAAW,MAAZ;GAAiB,aAAY;GAC3B,UAAA,oBAAC,WAAW,UAAZ,EAAA,UACE,oBAAC,MAAD,EAAM,MAAM,SAAS,OAAO,OAAO,IAAI,EAAI,CAAA,EACxB,CAAA;EACN,CAAA;CACJ,CAAA,EACL,CAAA;AAEhB;AAEA,WAAW,cAAc"}
1
+ {"version":3,"file":"chunk-DebugGraph.mjs","names":[],"sources":["../../src/containers/DebugGraph/DebugGraph.tsx"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport React from 'react';\n\nimport * as AppGraph from '@dxos/app-graph/AppGraph';\nimport { Tree } from '@dxos/devtools';\nimport * as Panel from '@dxos/react-ui/Panel';\nimport * as ScrollArea from '@dxos/react-ui/ScrollArea';\n\nexport type DebugGraphProps = { role?: string; graph: AppGraph.Graph; root: string };\n\nexport const DebugGraph = ({ role, graph, root }: DebugGraphProps) => {\n return (\n <Panel.Root role={role}>\n <Panel.Body asChild>\n <ScrollArea.Root orientation='all'>\n <ScrollArea.Viewport>\n <Tree data={AppGraph.toJSON(graph, root)} />\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n </Panel.Body>\n </Panel.Root>\n );\n};\n\nDebugGraph.displayName = 'DebugGraph';\n"],"mappings":";;;;;;;AAaA,IAAa,cAAc,EAAE,MAAM,OAAO,WAA4B;CACpE,OACE,oBAAC,MAAM,MAAP;EAAkB;EAChB,UAAA,oBAAC,MAAM,MAAP;GAAY,SAAA;GACV,UAAA,oBAAC,WAAW,MAAZ;IAAiB,aAAY;IAC3B,UAAA,oBAAC,WAAW,UAAZ,EAAA,UACE,oBAAC,MAAD,EAAM,MAAM,SAAS,OAAO,OAAO,IAAI,EAAI,CAAA,EACxB,CAAA;GACN,CAAA;EACP,CAAA;CACF,CAAA;AAEhB;AAEA,WAAW,cAAc"}
@@ -0,0 +1,108 @@
1
+ import { Devtools } from "#types";
2
+ import { useCallback, useMemo, useState } from "react";
3
+ import * as Surface from "@dxos/app-framework/Surface";
4
+ import { EdgeCard, IndexerCard, QueriesCard, SurfaceProfilerCard, SwarmTraceCard, SyncCard, useEdgeStatus, useIndexerRows, useQueryMetrics, useSwarmTrace, useSyncRows } from "@dxos/devtools";
5
+ import { jsx } from "react/jsx-runtime";
6
+ import * as AppSurface from "@dxos/app-toolkit/AppSurface";
7
+ import * as Hooks from "@dxos/app-framework/Hooks";
8
+ import * as DebugOperation from "@dxos/plugin-debug/DebugOperation";
9
+ import { SpaceState, useSpaces } from "@dxos/react-client/echo";
10
+ //#region src/capabilities/DevtoolsCards.tsx
11
+ /** Surfaces hosting the debug tooling; they and everything rendered inside them are not listed. */
12
+ var DEBUG_HOSTS = /* @__PURE__ */ new Set(["devtoolsOverview", "debugDrawer"]);
13
+ /** Whether a mounted surface is part of the debug tooling rather than the app being inspected. */
14
+ var isDebugSurface = ({ id, role, ancestors }) => role.endsWith(".devtoolsOverview") || id !== void 0 && DEBUG_HOSTS.has(id) || ancestors.some((ancestor) => DEBUG_HOSTS.has(ancestor));
15
+ var isDevtoolsCardData = (data) => typeof data === "object" && data !== null && "stats" in data && "surfaceProfilerStats" in data;
16
+ /**
17
+ * The card role narrowed to the stack's data. `Surface.makeFilter` types its data by the token, so
18
+ * the binding is built directly, as `AppSurface.subject` does.
19
+ */
20
+ var devtoolsCard = { bindings: [{
21
+ role: AppSurface.DevtoolsOverview.role,
22
+ guard: isDevtoolsCardData
23
+ }] };
24
+ var EdgeCardSurface = ({ stats }) => {
25
+ const { status, refresh, copy } = useEdgeStatus();
26
+ const spaces = useSpaces({ all: true });
27
+ const spaceNames = useMemo(() => {
28
+ const names = {};
29
+ for (const space of spaces) {
30
+ const name = space.state.get() === SpaceState.SPACE_READY ? space.properties.name : void 0;
31
+ if (typeof name === "string") names[space.id] = name;
32
+ }
33
+ return names;
34
+ }, [spaces]);
35
+ return /* @__PURE__ */ jsx(EdgeCard, {
36
+ edge: stats.edge,
37
+ status,
38
+ spaceNames,
39
+ onRefresh: refresh,
40
+ onCopy: copy
41
+ });
42
+ };
43
+ /** The profiler card with the surface highlight overlay's flag, which lives on `window`, mirrored in state. */
44
+ var SurfaceProfilerCardSurface = ({ surfaceProfilerStats, onClearSurfaceProfiler }) => {
45
+ const [debug, setDebug] = useState(() => Surface.isDebugEnabled());
46
+ const handleDebugChange = useCallback((enabled) => {
47
+ Surface.setDebug(enabled);
48
+ setDebug(enabled);
49
+ }, []);
50
+ const selected = Surface.useSelected();
51
+ const mounted = Surface.useMounted();
52
+ const detail = useMemo(() => {
53
+ if (!selected) return;
54
+ const metrics = new Map(Surface.getMetrics().map((metric) => [metric.id, metric]));
55
+ return mounted.filter((surface) => surface.role === selected && !isDebugSurface(surface)).map(({ id, role, data }) => ({
56
+ id,
57
+ data,
58
+ metric: metrics.get(`surface/${id}/${role}`)
59
+ }));
60
+ }, [selected, mounted]);
61
+ return /* @__PURE__ */ jsx(SurfaceProfilerCard, {
62
+ stats: surfaceProfilerStats,
63
+ debug,
64
+ onDebugChange: handleDebugChange,
65
+ onClear: onClearSurfaceProfiler,
66
+ selected,
67
+ onSelect: Surface.select,
68
+ detail
69
+ });
70
+ };
71
+ var SwarmTraceCardSurface = () => {
72
+ const { messages, spaceCount, available, clear } = useSwarmTrace();
73
+ return /* @__PURE__ */ jsx(SwarmTraceCard, {
74
+ messages,
75
+ spaceCount,
76
+ available,
77
+ onClear: clear
78
+ });
79
+ };
80
+ var SyncCardSurface = () => {
81
+ const { spaces, copy } = useSyncRows();
82
+ return /* @__PURE__ */ jsx(SyncCard, {
83
+ spaces,
84
+ onCopy: copy
85
+ });
86
+ };
87
+ var IndexerCardSurface = () => {
88
+ const { spaces, refresh, copy } = useIndexerRows();
89
+ return /* @__PURE__ */ jsx(IndexerCard, {
90
+ spaces,
91
+ onRefresh: refresh,
92
+ onCopy: copy
93
+ });
94
+ };
95
+ /** The slowest queries; the header button shows every query on the devtools Queries page. */
96
+ var QueriesCardSurface = () => {
97
+ const { queries } = useQueryMetrics();
98
+ const { invokePromise } = Hooks.useOperationInvoker();
99
+ const handleOpen = useCallback(() => void invokePromise(DebugOperation.OpenPage, { nodeId: Devtools.getNodePath(Devtools.Echo.Queries) }), [invokePromise]);
100
+ return /* @__PURE__ */ jsx(QueriesCard, {
101
+ queries,
102
+ onOpen: handleOpen
103
+ });
104
+ };
105
+ //#endregion
106
+ export { SwarmTraceCardSurface as a, isDebugSurface as c, SurfaceProfilerCardSurface as i, IndexerCardSurface as n, SyncCardSurface as o, QueriesCardSurface as r, devtoolsCard as s, EdgeCardSurface as t };
107
+
108
+ //# sourceMappingURL=chunk-DevtoolsCards.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-DevtoolsCards.mjs","names":[],"sources":["../../src/capabilities/DevtoolsCards.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// Card surfaces whose data comes from a hook rather than the stack's `DevtoolsCardData`.\n\nimport React, { useCallback, useMemo, useState } from 'react';\n\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport * as Surface from '@dxos/app-framework/Surface';\nimport * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport {\n EdgeCard,\n IndexerCard,\n QueriesCard,\n type Stats,\n SurfaceProfilerCard,\n type SurfaceProfilerStats,\n SwarmTraceCard,\n SyncCard,\n useEdgeStatus,\n useIndexerRows,\n useQueryMetrics,\n useSwarmTrace,\n useSyncRows,\n} from '@dxos/devtools';\nimport * as DebugOperation from '@dxos/plugin-debug/DebugOperation';\nimport { SpaceState, useSpaces } from '@dxos/react-client/echo';\n\nimport { Devtools } from '#types';\n\n/** Surfaces hosting the debug tooling; they and everything rendered inside them are not listed. */\nconst DEBUG_HOSTS = new Set(['devtoolsOverview', 'debugDrawer']);\n\n/** Whether a mounted surface is part of the debug tooling rather than the app being inspected. */\nexport const isDebugSurface = ({ id, role, ancestors }: Surface.Mounted): boolean =>\n role.endsWith('.devtoolsOverview') ||\n (id !== undefined && DEBUG_HOSTS.has(id)) ||\n ancestors.some((ancestor) => DEBUG_HOSTS.has(ancestor));\n\n/** Data the stats stack passes to every `AppSurface.DevtoolsOverview` card. */\nexport type DevtoolsCardData = {\n stats: Stats;\n surfaceProfilerStats: SurfaceProfilerStats[];\n onClearSurfaceProfiler?: () => void;\n};\n\nexport const isDevtoolsCardData = (data: unknown): data is DevtoolsCardData =>\n typeof data === 'object' && data !== null && 'stats' in data && 'surfaceProfilerStats' in data;\n\n/**\n * The card role narrowed to the stack's data. `Surface.makeFilter` types its data by the token, so\n * the binding is built directly, as `AppSurface.subject` does.\n */\nexport const devtoolsCard: Surface.Filter<DevtoolsCardData> = {\n bindings: [{ role: AppSurface.DevtoolsOverview.role, guard: isDevtoolsCardData }],\n};\n\nexport type EdgeCardSurfaceProps = Pick<DevtoolsCardData, 'stats'>;\n\nexport const EdgeCardSurface = ({ stats }: EdgeCardSurfaceProps) => {\n const { status, refresh, copy } = useEdgeStatus();\n const spaces = useSpaces({ all: true });\n const spaceNames = useMemo(() => {\n const names: Record<string, string> = {};\n for (const space of spaces) {\n const name = space.state.get() === SpaceState.SPACE_READY ? space.properties.name : undefined;\n if (typeof name === 'string') {\n names[space.id] = name;\n }\n }\n return names;\n }, [spaces]);\n return <EdgeCard edge={stats.edge} status={status} spaceNames={spaceNames} onRefresh={refresh} onCopy={copy} />;\n};\n\nexport type SurfaceProfilerCardSurfaceProps = Pick<DevtoolsCardData, 'surfaceProfilerStats' | 'onClearSurfaceProfiler'>;\n\n/** The profiler card with the surface highlight overlay's flag, which lives on `window`, mirrored in state. */\nexport const SurfaceProfilerCardSurface = ({\n surfaceProfilerStats,\n onClearSurfaceProfiler,\n}: SurfaceProfilerCardSurfaceProps) => {\n const [debug, setDebug] = useState(() => Surface.isDebugEnabled());\n const handleDebugChange = useCallback((enabled: boolean) => {\n Surface.setDebug(enabled);\n setDebug(enabled);\n }, []);\n\n // The selected role's surfaces with their data and dispatch metrics, following mounts and unmounts.\n const selected = Surface.useSelected();\n const mounted = Surface.useMounted();\n const detail = useMemo(() => {\n if (!selected) {\n return undefined;\n }\n const metrics = new Map(Surface.getMetrics().map((metric) => [metric.id, metric]));\n return mounted\n .filter((surface) => surface.role === selected && !isDebugSurface(surface))\n .map(({ id, role, data }) => ({ id, data, metric: metrics.get(`surface/${id}/${role}`) }));\n }, [selected, mounted]);\n\n return (\n <SurfaceProfilerCard\n stats={surfaceProfilerStats}\n debug={debug}\n onDebugChange={handleDebugChange}\n onClear={onClearSurfaceProfiler}\n selected={selected}\n onSelect={Surface.select}\n detail={detail}\n />\n );\n};\n\nexport const SwarmTraceCardSurface = () => {\n const { messages, spaceCount, available, clear } = useSwarmTrace();\n return <SwarmTraceCard messages={messages} spaceCount={spaceCount} available={available} onClear={clear} />;\n};\n\nexport const SyncCardSurface = () => {\n const { spaces, copy } = useSyncRows();\n return <SyncCard spaces={spaces} onCopy={copy} />;\n};\n\nexport const IndexerCardSurface = () => {\n const { spaces, refresh, copy } = useIndexerRows();\n return <IndexerCard spaces={spaces} onRefresh={refresh} onCopy={copy} />;\n};\n\n/** The slowest queries; the header button shows every query on the devtools Queries page. */\nexport const QueriesCardSurface = () => {\n const { queries } = useQueryMetrics();\n const { invokePromise } = Hooks.useOperationInvoker();\n const handleOpen = useCallback(\n () => void invokePromise(DebugOperation.OpenPage, { nodeId: Devtools.getNodePath(Devtools.Echo.Queries) }),\n [invokePromise],\n );\n return <QueriesCard queries={queries} onOpen={handleOpen} />;\n};\n"],"mappings":";;;;;;;;;;;AAgCA,IAAM,8BAAc,IAAI,IAAI,CAAC,oBAAoB,aAAa,CAAC;;AAG/D,IAAa,kBAAkB,EAAE,IAAI,MAAM,gBACzC,KAAK,SAAS,mBAAmB,KAChC,OAAO,KAAA,KAAa,YAAY,IAAI,EAAE,KACvC,UAAU,MAAM,aAAa,YAAY,IAAI,QAAQ,CAAC;AASxD,IAAa,sBAAsB,SACjC,OAAO,SAAS,YAAY,SAAS,QAAQ,WAAW,QAAQ,0BAA0B;;;;;AAM5F,IAAa,eAAiD,EAC5D,UAAU,CAAC;CAAE,MAAM,WAAW,iBAAiB;CAAM,OAAO;AAAmB,CAAC,EAClF;AAIA,IAAa,mBAAmB,EAAE,YAAkC;CAClE,MAAM,EAAE,QAAQ,SAAS,SAAS,cAAc;CAChD,MAAM,SAAS,UAAU,EAAE,KAAK,KAAK,CAAC;CACtC,MAAM,aAAa,cAAc;EAC/B,MAAM,QAAgC,CAAC;EACvC,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,OAAO,MAAM,MAAM,IAAI,MAAM,WAAW,cAAc,MAAM,WAAW,OAAO,KAAA;GACpF,IAAI,OAAO,SAAS,UAClB,MAAM,MAAM,MAAM;EAEtB;EACA,OAAO;CACT,GAAG,CAAC,MAAM,CAAC;CACX,OAAO,oBAAC,UAAD;EAAU,MAAM,MAAM;EAAc;EAAoB;EAAY,WAAW;EAAS,QAAQ;CAAO,CAAA;AAChH;;AAKA,IAAa,8BAA8B,EACzC,sBACA,6BACqC;CACrC,MAAM,CAAC,OAAO,YAAY,eAAe,QAAQ,eAAe,CAAC;CACjE,MAAM,oBAAoB,aAAa,YAAqB;EAC1D,QAAQ,SAAS,OAAO;EACxB,SAAS,OAAO;CAClB,GAAG,CAAC,CAAC;CAGL,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,SAAS,cAAc;EAC3B,IAAI,CAAC,UACH;EAEF,MAAM,UAAU,IAAI,IAAI,QAAQ,WAAW,CAAC,CAAC,KAAK,WAAW,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC;EACjF,OAAO,QACJ,QAAQ,YAAY,QAAQ,SAAS,YAAY,CAAC,eAAe,OAAO,CAAC,CAAA,CACzE,KAAK,EAAE,IAAI,MAAM,YAAY;GAAE;GAAI;GAAM,QAAQ,QAAQ,IAAI,WAAW,GAAG,GAAG,MAAM;EAAE,EAAE;CAC7F,GAAG,CAAC,UAAU,OAAO,CAAC;CAEtB,OACE,oBAAC,qBAAD;EACE,OAAO;EACA;EACP,eAAe;EACf,SAAS;EACC;EACV,UAAU,QAAQ;EACV;CACT,CAAA;AAEL;AAEA,IAAa,8BAA8B;CACzC,MAAM,EAAE,UAAU,YAAY,WAAW,UAAU,cAAc;CACjE,OAAO,oBAAC,gBAAD;EAA0B;EAAsB;EAAuB;EAAW,SAAS;CAAQ,CAAA;AAC5G;AAEA,IAAa,wBAAwB;CACnC,MAAM,EAAE,QAAQ,SAAS,YAAY;CACrC,OAAO,oBAAC,UAAD;EAAkB;EAAQ,QAAQ;CAAO,CAAA;AAClD;AAEA,IAAa,2BAA2B;CACtC,MAAM,EAAE,QAAQ,SAAS,SAAS,eAAe;CACjD,OAAO,oBAAC,aAAD;EAAqB;EAAQ,WAAW;EAAS,QAAQ;CAAO,CAAA;AACzE;;AAGA,IAAa,2BAA2B;CACtC,MAAM,EAAE,YAAY,gBAAgB;CACpC,MAAM,EAAE,kBAAkB,MAAM,oBAAoB;CACpD,MAAM,aAAa,kBACX,KAAK,cAAc,eAAe,UAAU,EAAE,QAAQ,SAAS,YAAY,SAAS,KAAK,OAAO,EAAE,CAAC,GACzG,CAAC,aAAa,CAChB;CACA,OAAO,oBAAC,aAAD;EAAsB;EAAS,QAAQ;CAAa,CAAA;AAC7D"}
@@ -1,37 +1,74 @@
1
- import { useCallback, useMemo } from "react";
2
- import { Surface } from "@dxos/app-framework/ui";
1
+ import { c as isDebugSurface } from "./chunk-DevtoolsCards.mjs";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import * as Surface from "@dxos/app-framework/Surface";
3
4
  import { StatsPanel, useStats } from "@dxos/devtools";
4
5
  import { jsx } from "react/jsx-runtime";
5
- import { AppSurface } from "@dxos/app-toolkit/ui";
6
+ import * as AppSurface from "@dxos/app-toolkit/AppSurface";
6
7
  //#region src/containers/DevtoolsOverviewContainer/DevtoolsOverviewContainer.tsx
8
+ /**
9
+ * The stats stack: one poll of the client's stats, fanned out to every card contributed to the role.
10
+ * The profiler and dispatch metrics are sampled on each refresh rather than subscribed to: this
11
+ * container is itself a profiled surface, so a live subscription would record an entry for every
12
+ * re-render the notification caused and loop at frame rate, flushing every other surface out of the
13
+ * profiler's window — which is what made the Surfaces card's count wander with no interaction.
14
+ */
7
15
  var DevtoolsOverviewContainer = () => {
8
16
  const [stats, refreshStats] = useStats();
9
- const surfaceProfilerStats = Surface.useProfilerStats();
10
- const surfaceMetrics = Surface.useMetrics();
17
+ const getProfilerStats = Surface.useProfilerSnapshot();
11
18
  const clearSurfaceProfiler = Surface.useProfilerClear();
12
- const handleClearSurfaceProfiler = useCallback(() => {
13
- clearSurfaceProfiler?.();
14
- Surface.clearMetrics();
15
- }, [clearSurfaceProfiler]);
16
- const enrichedStats = useMemo(() => {
17
- const byId = new Map(surfaceMetrics.map((metric) => [metric.id, metric]));
18
- return surfaceProfilerStats.map((stat) => {
19
- const metric = byId.get(stat.id);
19
+ const mounted = Surface.useMounted();
20
+ const [surfaceProfilerStats, setSurfaceProfilerStats] = useState([]);
21
+ const sampleProfiler = useCallback(() => {
22
+ const timings = new Map(getProfilerStats().map((stat) => [stat.id, stat]));
23
+ const metrics = new Map(Surface.getMetrics().map((metric) => [metric.id, metric]));
24
+ setSurfaceProfilerStats(mounted.filter((surface) => !isDebugSurface(surface)).map(({ id, role }) => {
25
+ const profilerId = `surface/${id}/${role}`;
26
+ const timing = timings.get(profilerId) ?? {
27
+ id: profilerId,
28
+ mountCount: 0,
29
+ updateCount: 0,
30
+ totalRenders: 0,
31
+ avgActualDuration: 0,
32
+ maxActualDuration: 0,
33
+ avgBaseDuration: 0,
34
+ lastActualDuration: 0,
35
+ lastCommitTime: 0
36
+ };
37
+ const metric = metrics.get(profilerId);
20
38
  return metric ? {
21
- ...stat,
39
+ ...timing,
22
40
  candidates: metric.candidates,
23
41
  truncated: metric.truncated,
24
42
  errors: metric.errors,
25
43
  dataUnstable: metric.dataUnstable
26
- } : stat;
27
- });
28
- }, [surfaceProfilerStats, surfaceMetrics]);
29
- return /* @__PURE__ */ jsx(StatsPanel, {
44
+ } : timing;
45
+ }).sort((a, b) => b.maxActualDuration - a.maxActualDuration || a.id.localeCompare(b.id)));
46
+ }, [getProfilerStats, mounted]);
47
+ useEffect(sampleProfiler, [sampleProfiler]);
48
+ const handleRefresh = useCallback(() => {
49
+ refreshStats();
50
+ sampleProfiler();
51
+ }, [refreshStats, sampleProfiler]);
52
+ const handleClearSurfaceProfiler = useCallback(() => {
53
+ clearSurfaceProfiler?.();
54
+ Surface.clearMetrics();
55
+ sampleProfiler();
56
+ }, [clearSurfaceProfiler, sampleProfiler]);
57
+ const data = useMemo(() => ({
30
58
  stats,
31
- surfaceProfilerStats: enrichedStats,
32
- onRefresh: refreshStats,
33
- onClearSurfaceProfiler: handleClearSurfaceProfiler,
34
- children: /* @__PURE__ */ jsx(Surface.Surface, { type: AppSurface.DevtoolsOverview })
59
+ surfaceProfilerStats,
60
+ onClearSurfaceProfiler: handleClearSurfaceProfiler
61
+ }), [
62
+ stats,
63
+ surfaceProfilerStats,
64
+ handleClearSurfaceProfiler
65
+ ]);
66
+ return /* @__PURE__ */ jsx(StatsPanel, {
67
+ onRefresh: handleRefresh,
68
+ children: /* @__PURE__ */ jsx(Surface.Surface, {
69
+ type: AppSurface.DevtoolsOverview,
70
+ data
71
+ })
35
72
  });
36
73
  };
37
74
  DevtoolsOverviewContainer.displayName = "DevtoolsOverviewContainer";
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-DevtoolsOverviewContainer.mjs","names":[],"sources":["../../src/containers/DevtoolsOverviewContainer/DevtoolsOverviewContainer.tsx"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useCallback, useMemo } from 'react';\n\nimport { Surface } from '@dxos/app-framework/ui';\nimport { AppSurface } from '@dxos/app-toolkit/ui';\nimport { StatsPanel, useStats } from '@dxos/devtools';\n\nexport const DevtoolsOverviewContainer = () => {\n const [stats, refreshStats] = useStats();\n const surfaceProfilerStats = Surface.useProfilerStats();\n const surfaceMetrics = Surface.useMetrics();\n const clearSurfaceProfiler = Surface.useProfilerClear();\n\n // The panel joins profiler stats with dispatch metrics, so reset must clear both.\n const handleClearSurfaceProfiler = useCallback(() => {\n clearSurfaceProfiler?.();\n Surface.clearMetrics();\n }, [clearSurfaceProfiler]);\n\n // Join dispatch metrics onto the render-timing stats (both keyed by `surface/<id>/<role>`).\n const enrichedStats = useMemo(() => {\n const byId = new Map(surfaceMetrics.map((metric) => [metric.id, metric]));\n return surfaceProfilerStats.map((stat) => {\n const metric = byId.get(stat.id);\n return metric\n ? {\n ...stat,\n candidates: metric.candidates,\n truncated: metric.truncated,\n errors: metric.errors,\n dataUnstable: metric.dataUnstable,\n }\n : stat;\n });\n }, [surfaceProfilerStats, surfaceMetrics]);\n\n return (\n <StatsPanel\n stats={stats}\n surfaceProfilerStats={enrichedStats}\n onRefresh={refreshStats}\n onClearSurfaceProfiler={handleClearSurfaceProfiler}\n >\n <Surface.Surface type={AppSurface.DevtoolsOverview} />\n </StatsPanel>\n );\n};\n\nDevtoolsOverviewContainer.displayName = 'DevtoolsOverviewContainer';\n"],"mappings":";;;;;;AAUA,IAAa,kCAAkC;CAC7C,MAAM,CAAC,OAAO,gBAAgB,SAAS;CACvC,MAAM,uBAAuB,QAAQ,iBAAiB;CACtD,MAAM,iBAAiB,QAAQ,WAAW;CAC1C,MAAM,uBAAuB,QAAQ,iBAAiB;CAGtD,MAAM,6BAA6B,kBAAkB;EACnD,uBAAuB;EACvB,QAAQ,aAAa;CACvB,GAAG,CAAC,oBAAoB,CAAC;CAGzB,MAAM,gBAAgB,cAAc;EAClC,MAAM,OAAO,IAAI,IAAI,eAAe,KAAK,WAAW,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC;EACxE,OAAO,qBAAqB,KAAK,SAAS;GACxC,MAAM,SAAS,KAAK,IAAI,KAAK,EAAE;GAC/B,OAAO,SACH;IACE,GAAG;IACH,YAAY,OAAO;IACnB,WAAW,OAAO;IAClB,QAAQ,OAAO;IACf,cAAc,OAAO;GACvB,IACA;EACN,CAAC;CACH,GAAG,CAAC,sBAAsB,cAAc,CAAC;CAEzC,OACE,oBAAC,YAAD;EACS;EACP,sBAAsB;EACtB,WAAW;EACX,wBAAwB;EAExB,UAAA,oBAAC,QAAQ,SAAT,EAAiB,MAAM,WAAW,iBAAmB,CAAA;CAC3C,CAAA;AAEhB;AAEA,0BAA0B,cAAc"}
1
+ {"version":3,"file":"chunk-DevtoolsOverviewContainer.mjs","names":[],"sources":["../../src/containers/DevtoolsOverviewContainer/DevtoolsOverviewContainer.tsx"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport * as Surface from '@dxos/app-framework/Surface';\nimport * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport { StatsPanel, type SurfaceProfilerStats, useStats } from '@dxos/devtools';\n\nimport { type DevtoolsCardData, isDebugSurface } from '../../capabilities/DevtoolsCards.tsx';\n\n/**\n * The stats stack: one poll of the client's stats, fanned out to every card contributed to the role.\n * The profiler and dispatch metrics are sampled on each refresh rather than subscribed to: this\n * container is itself a profiled surface, so a live subscription would record an entry for every\n * re-render the notification caused and loop at frame rate, flushing every other surface out of the\n * profiler's window — which is what made the Surfaces card's count wander with no interaction.\n */\nexport const DevtoolsOverviewContainer = () => {\n const [stats, refreshStats] = useStats();\n const getProfilerStats = Surface.useProfilerSnapshot();\n const clearSurfaceProfiler = Surface.useProfilerClear();\n // Resampled as surfaces mount and unmount: with a restored layout this container mounts at boot,\n // before most of the app, so a single sample on mount would list only what existed then.\n const mounted = Surface.useMounted();\n const [surfaceProfilerStats, setSurfaceProfilerStats] = useState<SurfaceProfilerStats[]>([]);\n\n // One row per surface mounted right now (the profiler records renders, not mounts), with its\n // cumulative render timings and dispatch metrics joined on `surface/<id>/<role>` where they exist.\n // The debug tooling's own surfaces are left out so the panel does not measure itself.\n const sampleProfiler = useCallback(() => {\n const timings = new Map(getProfilerStats().map((stat) => [stat.id, stat]));\n const metrics = new Map(Surface.getMetrics().map((metric) => [metric.id, metric]));\n setSurfaceProfilerStats(\n mounted\n .filter((surface) => !isDebugSurface(surface))\n .map(({ id, role }) => {\n // Mirrors the profiler's own id, which prints an anonymous surface as `undefined`.\n const profilerId = `surface/${id}/${role}`;\n const timing = timings.get(profilerId) ?? {\n id: profilerId,\n mountCount: 0,\n updateCount: 0,\n totalRenders: 0,\n avgActualDuration: 0,\n maxActualDuration: 0,\n avgBaseDuration: 0,\n lastActualDuration: 0,\n lastCommitTime: 0,\n };\n const metric = metrics.get(profilerId);\n return metric\n ? {\n ...timing,\n candidates: metric.candidates,\n truncated: metric.truncated,\n errors: metric.errors,\n dataUnstable: metric.dataUnstable,\n }\n : timing;\n })\n .sort((a, b) => b.maxActualDuration - a.maxActualDuration || a.id.localeCompare(b.id)),\n );\n }, [getProfilerStats, mounted]);\n useEffect(sampleProfiler, [sampleProfiler]);\n\n const handleRefresh = useCallback(() => {\n refreshStats();\n sampleProfiler();\n }, [refreshStats, sampleProfiler]);\n\n // The profiler card joins profiler stats with dispatch metrics, so reset must clear both.\n const handleClearSurfaceProfiler = useCallback(() => {\n clearSurfaceProfiler?.();\n Surface.clearMetrics();\n sampleProfiler();\n }, [clearSurfaceProfiler, sampleProfiler]);\n\n const data = useMemo<DevtoolsCardData>(\n () => ({ stats, surfaceProfilerStats, onClearSurfaceProfiler: handleClearSurfaceProfiler }),\n [stats, surfaceProfilerStats, handleClearSurfaceProfiler],\n );\n\n return (\n <StatsPanel onRefresh={handleRefresh}>\n <Surface.Surface type={AppSurface.DevtoolsOverview} data={data} />\n </StatsPanel>\n );\n};\n\nDevtoolsOverviewContainer.displayName = 'DevtoolsOverviewContainer';\n"],"mappings":";;;;;;;;;;;;;;AAmBA,IAAa,kCAAkC;CAC7C,MAAM,CAAC,OAAO,gBAAgB,SAAS;CACvC,MAAM,mBAAmB,QAAQ,oBAAoB;CACrD,MAAM,uBAAuB,QAAQ,iBAAiB;CAGtD,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,CAAC,sBAAsB,2BAA2B,SAAiC,CAAC,CAAC;CAK3F,MAAM,iBAAiB,kBAAkB;EACvC,MAAM,UAAU,IAAI,IAAI,iBAAiB,CAAC,CAAC,KAAK,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;EACzE,MAAM,UAAU,IAAI,IAAI,QAAQ,WAAW,CAAC,CAAC,KAAK,WAAW,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC;EACjF,wBACE,QACG,QAAQ,YAAY,CAAC,eAAe,OAAO,CAAC,CAAA,CAC5C,KAAK,EAAE,IAAI,WAAW;GAErB,MAAM,aAAa,WAAW,GAAG,GAAG;GACpC,MAAM,SAAS,QAAQ,IAAI,UAAU,KAAK;IACxC,IAAI;IACJ,YAAY;IACZ,aAAa;IACb,cAAc;IACd,mBAAmB;IACnB,mBAAmB;IACnB,iBAAiB;IACjB,oBAAoB;IACpB,gBAAgB;GAClB;GACA,MAAM,SAAS,QAAQ,IAAI,UAAU;GACrC,OAAO,SACH;IACE,GAAG;IACH,YAAY,OAAO;IACnB,WAAW,OAAO;IAClB,QAAQ,OAAO;IACf,cAAc,OAAO;GACvB,IACA;EACN,CAAC,CAAA,CACA,MAAM,GAAG,MAAM,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC,CACzF;CACF,GAAG,CAAC,kBAAkB,OAAO,CAAC;CAC9B,UAAU,gBAAgB,CAAC,cAAc,CAAC;CAE1C,MAAM,gBAAgB,kBAAkB;EACtC,aAAa;EACb,eAAe;CACjB,GAAG,CAAC,cAAc,cAAc,CAAC;CAGjC,MAAM,6BAA6B,kBAAkB;EACnD,uBAAuB;EACvB,QAAQ,aAAa;EACrB,eAAe;CACjB,GAAG,CAAC,sBAAsB,cAAc,CAAC;CAEzC,MAAM,OAAO,eACJ;EAAE;EAAO;EAAsB,wBAAwB;CAA2B,IACzF;EAAC;EAAO;EAAsB;CAA0B,CAC1D;CAEA,OACE,oBAAC,YAAD;EAAY,WAAW;EACrB,UAAA,oBAAC,QAAQ,SAAT;GAAiB,MAAM,WAAW;GAAwB;EAAO,CAAA;CACvD,CAAA;AAEhB;AAEA,0BAA0B,cAAc"}
@@ -1,7 +1,10 @@
1
1
  import { meta } from "#meta";
2
2
  import { createContext, useContext, useEffect, useState } from "react";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
- import { Flex, IconButton, ScrollArea, useTranslation } from "@dxos/react-ui";
4
+ import * as ScrollArea from "@dxos/react-ui/ScrollArea";
5
+ import * as Button from "@dxos/react-ui/Button";
6
+ import * as Hooks from "@dxos/react-ui/Hooks";
7
+ import * as Layout from "@dxos/react-ui/Layout";
5
8
  //#region src/containers/GithubPanel/GithubComponent.tsx
6
9
  var DEFAULT_REPO = "dxos/dxos";
7
10
  var DEFAULT_LIMIT = 20;
@@ -54,10 +57,10 @@ var Root = ({ repo = DEFAULT_REPO, limit = DEFAULT_LIMIT, children }) => {
54
57
  });
55
58
  };
56
59
  var Header = () => {
57
- const { t } = useTranslation(meta.profile.key);
60
+ const { t } = Hooks.useTranslation(meta.profile.key);
58
61
  const { repo, pulls, unavailable } = useComponentContext();
59
62
  return /* @__PURE__ */ jsxs("header", {
60
- className: "flex items-center justify-between gap-1 px-4 py-3 dx-modal-surface border-b border-subdued-separator",
63
+ className: "flex items-center justify-between gap-1 px-4 py-3 dx-modal-surface border-b border-separator-subtle",
61
64
  children: [/* @__PURE__ */ jsxs("a", {
62
65
  href: `https://github.com/${repo}`,
63
66
  target: "_blank",
@@ -65,7 +68,7 @@ var Header = () => {
65
68
  className: "text-sm font-medium truncate",
66
69
  children: ["@", repo]
67
70
  }), /* @__PURE__ */ jsx("div", {
68
- className: "text-xs text-description",
71
+ className: "text-xs text-fg-muted",
69
72
  children: unavailable ? t("github-unavailable.message") : pulls.length > 0 ? t("recent-prs.label", { count: pulls.length }) : t("github-loading.message")
70
73
  })]
71
74
  });
@@ -85,7 +88,7 @@ var formatRelative = (iso) => {
85
88
  for (const [unit, secondsInUnit] of RELATIVE_UNITS) if (absDiff >= secondsInUnit) return formatter.format(Math.round(diffSeconds / secondsInUnit), unit);
86
89
  return formatter.format(Math.round(diffSeconds), "second");
87
90
  };
88
- var PullRow = ({ pull }) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Flex, {
91
+ var PullRow = ({ pull }) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Layout.Flex, {
89
92
  asChild: true,
90
93
  align: "start",
91
94
  gap: "sm",
@@ -98,14 +101,14 @@ var PullRow = ({ pull }) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ *
98
101
  src: pull.user.avatar_url,
99
102
  alt: "",
100
103
  className: "size-6 rounded-full shrink-0"
101
- }), /* @__PURE__ */ jsxs(Flex, {
104
+ }), /* @__PURE__ */ jsxs(Layout.Flex, {
102
105
  column: true,
103
106
  classNames: "min-w-0 flex-1",
104
107
  children: [/* @__PURE__ */ jsx("span", {
105
108
  className: "text-sm leading-6 truncate",
106
109
  children: pull.title
107
110
  }), /* @__PURE__ */ jsxs("span", {
108
- className: "text-xs text-description truncate",
111
+ className: "text-xs text-fg-muted truncate",
109
112
  children: [
110
113
  "#",
111
114
  pull.number,
@@ -129,9 +132,9 @@ var Content = () => {
129
132
  });
130
133
  };
131
134
  var StatusBar = () => {
132
- const { t } = useTranslation(meta.profile.key);
135
+ const { t } = Hooks.useTranslation(meta.profile.key);
133
136
  const { repo } = useComponentContext();
134
- return /* @__PURE__ */ jsx(IconButton, {
137
+ return /* @__PURE__ */ jsx(Button.Root, {
135
138
  icon: "ph--github-logo--regular",
136
139
  label: t("view-on-github.button"),
137
140
  variant: "primary",
@@ -150,7 +153,7 @@ var GithubComponent = {
150
153
  //#endregion
151
154
  //#region src/containers/GithubPanel/GithubPanel.tsx
152
155
  var GithubPanel = () => /* @__PURE__ */ jsx(GithubComponent.Root, { children: /* @__PURE__ */ jsxs("div", {
153
- className: "h-full grid grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden h-full w-full",
156
+ className: "dx-fill grid grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden",
154
157
  children: [
155
158
  /* @__PURE__ */ jsx(GithubComponent.Header, {}),
156
159
  /* @__PURE__ */ jsx(GithubComponent.Content, {}),
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-GithubPanel.mjs","names":[],"sources":["../../src/containers/GithubPanel/GithubComponent.tsx","../../src/containers/GithubPanel/GithubPanel.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { type ReactNode, createContext, useContext, useEffect, useState } from 'react';\n\nimport { Flex, IconButton, ScrollArea, useTranslation } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\n\nconst DEFAULT_REPO = 'dxos/dxos';\nconst DEFAULT_LIMIT = 20;\n\ntype GithubUser = {\n login: string;\n avatar_url: string;\n html_url: string;\n};\n\ntype GithubPullRequest = {\n number: number;\n title: string;\n html_url: string;\n merged_at: string | null;\n user: GithubUser;\n};\n\ntype ComponentContextValue = {\n repo: string;\n pulls: GithubPullRequest[];\n unavailable: boolean;\n};\n\nconst ComponentContext = createContext<ComponentContextValue | null>(null);\n\nconst useComponentContext = () => {\n const ctx = useContext(ComponentContext);\n if (!ctx) {\n throw new Error('GithubComponent.* parts must be rendered inside GithubComponent.Root.');\n }\n return ctx;\n};\n\nexport type GithubComponentRootProps = {\n /** `<owner>/<name>`. Defaults to `dxos/dxos`. */\n repo?: string;\n /** Maximum number of merged PRs to fetch. */\n limit?: number;\n children?: ReactNode;\n};\n\nconst Root = ({ repo = DEFAULT_REPO, limit = DEFAULT_LIMIT, children }: GithubComponentRootProps) => {\n const [pulls, setPulls] = useState<GithubPullRequest[]>([]);\n const [unavailable, setUnavailable] = useState(false);\n\n useEffect(() => {\n const controller = new AbortController();\n setPulls([]);\n setUnavailable(false);\n void (async () => {\n try {\n const url = new URL(`https://api.github.com/repos/${repo}/pulls`);\n url.searchParams.set('state', 'closed');\n url.searchParams.set('sort', 'updated');\n url.searchParams.set('direction', 'desc');\n url.searchParams.set('per_page', String(limit * 2));\n const response = await fetch(url.toString(), {\n signal: controller.signal,\n headers: { Accept: 'application/vnd.github+json' },\n });\n if (!response.ok) {\n setUnavailable(true);\n return;\n }\n const items = (await response.json()) as GithubPullRequest[];\n setPulls(items.filter((pull) => pull.merged_at !== null).slice(0, limit));\n setUnavailable(false);\n } catch {\n if (controller.signal.aborted) {\n return;\n }\n setPulls([]);\n setUnavailable(true);\n }\n })();\n return () => controller.abort();\n }, [repo, limit]);\n\n return <ComponentContext.Provider value={{ repo, pulls, unavailable }}>{children}</ComponentContext.Provider>;\n};\n\nconst Header = () => {\n const { t } = useTranslation(meta.profile.key);\n const { repo, pulls, unavailable } = useComponentContext();\n return (\n <header className='flex items-center justify-between gap-1 px-4 py-3 dx-modal-surface border-b border-subdued-separator'>\n <a\n href={`https://github.com/${repo}`}\n target='_blank'\n rel='noopener noreferrer'\n className='text-sm font-medium truncate'\n >\n @{repo}\n </a>\n <div className='text-xs text-description'>\n {unavailable\n ? t('github-unavailable.message')\n : pulls.length > 0\n ? t('recent-prs.label', { count: pulls.length })\n : t('github-loading.message')}\n </div>\n </header>\n );\n};\n\nconst RELATIVE_UNITS: Array<[Intl.RelativeTimeFormatUnit, number]> = [\n ['year', 60 * 60 * 24 * 365],\n ['month', 60 * 60 * 24 * 30],\n ['week', 60 * 60 * 24 * 7],\n ['day', 60 * 60 * 24],\n ['hour', 60 * 60],\n ['minute', 60],\n];\n\nconst formatRelative = (iso: string): string => {\n const formatter = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' });\n const diffSeconds = (Date.parse(iso) - Date.now()) / 1000;\n const absDiff = Math.abs(diffSeconds);\n for (const [unit, secondsInUnit] of RELATIVE_UNITS) {\n if (absDiff >= secondsInUnit) {\n return formatter.format(Math.round(diffSeconds / secondsInUnit), unit);\n }\n }\n return formatter.format(Math.round(diffSeconds), 'second');\n};\n\nconst PullRow = ({ pull }: { pull: GithubPullRequest }) => (\n <li>\n <Flex asChild align='start' gap='sm' classNames='px-trim-sm py-trim-xs rounded-sm hover:bg-hover-surface'>\n <a href={pull.html_url} target='_blank' rel='noopener noreferrer'>\n <img src={pull.user.avatar_url} alt='' className='size-6 rounded-full shrink-0' />\n <Flex column classNames='min-w-0 flex-1'>\n {/* `leading-6` gives the title the avatar's line box, so the two align on their own. */}\n <span className='text-sm leading-6 truncate'>{pull.title}</span>\n <span className='text-xs text-description truncate'>\n #{pull.number} · {pull.user.login} · {pull.merged_at ? formatRelative(pull.merged_at) : ''}\n </span>\n </Flex>\n </a>\n </Flex>\n </li>\n);\n\nconst Content = () => {\n const { pulls } = useComponentContext();\n return (\n <ScrollArea.Root orientation='vertical'>\n <ScrollArea.Viewport>\n <ul className='flex flex-col p-1'>\n {pulls.map((pull) => (\n <PullRow key={pull.number} pull={pull} />\n ))}\n </ul>\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n );\n};\n\nconst StatusBar = () => {\n const { t } = useTranslation(meta.profile.key);\n const { repo } = useComponentContext();\n return (\n <IconButton\n icon='ph--github-logo--regular'\n label={t('view-on-github.button')}\n variant='primary'\n classNames='w-full'\n onClick={() => {\n window.open(`https://github.com/${repo}`, '_blank', 'noopener,noreferrer');\n }}\n />\n );\n};\n\nexport const GithubComponent = {\n Root,\n Header,\n Content,\n StatusBar,\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { GithubComponent } from './GithubComponent';\n\nexport const GithubPanel = () => (\n <GithubComponent.Root>\n <div className='h-full grid grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden h-full w-full'>\n <GithubComponent.Header />\n <GithubComponent.Content />\n <GithubComponent.StatusBar />\n </div>\n </GithubComponent.Root>\n);\n\nGithubPanel.displayName = 'GithubPanel';\n"],"mappings":"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"}
1
+ {"version":3,"file":"chunk-GithubPanel.mjs","names":[],"sources":["../../src/containers/GithubPanel/GithubComponent.tsx","../../src/containers/GithubPanel/GithubPanel.tsx"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { type ReactNode, createContext, useContext, useEffect, useState } from 'react';\n\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as ScrollArea from '@dxos/react-ui/ScrollArea';\n\nimport { meta } from '#meta';\n\nconst DEFAULT_REPO = 'dxos/dxos';\nconst DEFAULT_LIMIT = 20;\n\ntype GithubUser = {\n login: string;\n avatar_url: string;\n html_url: string;\n};\n\ntype GithubPullRequest = {\n number: number;\n title: string;\n html_url: string;\n merged_at: string | null;\n user: GithubUser;\n};\n\ntype ComponentContextValue = {\n repo: string;\n pulls: GithubPullRequest[];\n unavailable: boolean;\n};\n\nconst ComponentContext = createContext<ComponentContextValue | null>(null);\n\nconst useComponentContext = () => {\n const ctx = useContext(ComponentContext);\n if (!ctx) {\n throw new Error('GithubComponent.* parts must be rendered inside GithubComponent.Root.');\n }\n return ctx;\n};\n\nexport type GithubComponentRootProps = {\n /** `<owner>/<name>`. Defaults to `dxos/dxos`. */\n repo?: string;\n /** Maximum number of merged PRs to fetch. */\n limit?: number;\n children?: ReactNode;\n};\n\nconst Root = ({ repo = DEFAULT_REPO, limit = DEFAULT_LIMIT, children }: GithubComponentRootProps) => {\n const [pulls, setPulls] = useState<GithubPullRequest[]>([]);\n const [unavailable, setUnavailable] = useState(false);\n\n useEffect(() => {\n const controller = new AbortController();\n setPulls([]);\n setUnavailable(false);\n void (async () => {\n try {\n const url = new URL(`https://api.github.com/repos/${repo}/pulls`);\n url.searchParams.set('state', 'closed');\n url.searchParams.set('sort', 'updated');\n url.searchParams.set('direction', 'desc');\n url.searchParams.set('per_page', String(limit * 2));\n const response = await fetch(url.toString(), {\n signal: controller.signal,\n headers: { Accept: 'application/vnd.github+json' },\n });\n if (!response.ok) {\n setUnavailable(true);\n return;\n }\n const items = (await response.json()) as GithubPullRequest[];\n setPulls(items.filter((pull) => pull.merged_at !== null).slice(0, limit));\n setUnavailable(false);\n } catch {\n if (controller.signal.aborted) {\n return;\n }\n setPulls([]);\n setUnavailable(true);\n }\n })();\n return () => controller.abort();\n }, [repo, limit]);\n\n return <ComponentContext.Provider value={{ repo, pulls, unavailable }}>{children}</ComponentContext.Provider>;\n};\n\nconst Header = () => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const { repo, pulls, unavailable } = useComponentContext();\n return (\n <header className='flex items-center justify-between gap-1 px-4 py-3 dx-modal-surface border-b border-separator-subtle'>\n <a\n href={`https://github.com/${repo}`}\n target='_blank'\n rel='noopener noreferrer'\n className='text-sm font-medium truncate'\n >\n @{repo}\n </a>\n <div className='text-xs text-fg-muted'>\n {unavailable\n ? t('github-unavailable.message')\n : pulls.length > 0\n ? t('recent-prs.label', { count: pulls.length })\n : t('github-loading.message')}\n </div>\n </header>\n );\n};\n\nconst RELATIVE_UNITS: Array<[Intl.RelativeTimeFormatUnit, number]> = [\n ['year', 60 * 60 * 24 * 365],\n ['month', 60 * 60 * 24 * 30],\n ['week', 60 * 60 * 24 * 7],\n ['day', 60 * 60 * 24],\n ['hour', 60 * 60],\n ['minute', 60],\n];\n\nconst formatRelative = (iso: string): string => {\n const formatter = new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' });\n const diffSeconds = (Date.parse(iso) - Date.now()) / 1000;\n const absDiff = Math.abs(diffSeconds);\n for (const [unit, secondsInUnit] of RELATIVE_UNITS) {\n if (absDiff >= secondsInUnit) {\n return formatter.format(Math.round(diffSeconds / secondsInUnit), unit);\n }\n }\n return formatter.format(Math.round(diffSeconds), 'second');\n};\n\nconst PullRow = ({ pull }: { pull: GithubPullRequest }) => (\n <li>\n <Layout.Flex asChild align='start' gap='sm' classNames='px-trim-sm py-trim-xs rounded-sm hover:bg-hover-surface'>\n <a href={pull.html_url} target='_blank' rel='noopener noreferrer'>\n <img src={pull.user.avatar_url} alt='' className='size-6 rounded-full shrink-0' />\n <Layout.Flex column classNames='min-w-0 flex-1'>\n {/* `leading-6` gives the title the avatar's line box, so the two align on their own. */}\n <span className='text-sm leading-6 truncate'>{pull.title}</span>\n <span className='text-xs text-fg-muted truncate'>\n #{pull.number} · {pull.user.login} · {pull.merged_at ? formatRelative(pull.merged_at) : ''}\n </span>\n </Layout.Flex>\n </a>\n </Layout.Flex>\n </li>\n);\n\nconst Content = () => {\n const { pulls } = useComponentContext();\n return (\n <ScrollArea.Root orientation='vertical'>\n <ScrollArea.Viewport>\n <ul className='flex flex-col p-1'>\n {pulls.map((pull) => (\n <PullRow key={pull.number} pull={pull} />\n ))}\n </ul>\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n );\n};\n\nconst StatusBar = () => {\n const { t } = Hooks.useTranslation(meta.profile.key);\n const { repo } = useComponentContext();\n return (\n <Button.Root\n icon='ph--github-logo--regular'\n label={t('view-on-github.button')}\n variant='primary'\n classNames='w-full'\n onClick={() => {\n window.open(`https://github.com/${repo}`, '_blank', 'noopener,noreferrer');\n }}\n />\n );\n};\n\nexport const GithubComponent = {\n Root,\n Header,\n Content,\n StatusBar,\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { GithubComponent } from './GithubComponent.tsx';\n\nexport const GithubPanel = () => (\n <GithubComponent.Root>\n <div className='dx-fill grid grid-rows-[auto_minmax(0,1fr)_auto] overflow-hidden'>\n <GithubComponent.Header />\n <GithubComponent.Content />\n <GithubComponent.StatusBar />\n </div>\n </GithubComponent.Root>\n);\n\nGithubPanel.displayName = 'GithubPanel';\n"],"mappings":";;;;;;;;AAaA,IAAM,eAAe;AACrB,IAAM,gBAAgB;AAsBtB,IAAM,mBAAmB,cAA4C,IAAI;AAEzE,IAAM,4BAA4B;CAChC,MAAM,MAAM,WAAW,gBAAgB;CACvC,IAAI,CAAC,KACH,MAAM,IAAI,MAAM,uEAAuE;CAEzF,OAAO;AACT;AAUA,IAAM,QAAQ,EAAE,OAAO,cAAc,QAAQ,eAAe,eAAyC;CACnG,MAAM,CAAC,OAAO,YAAY,SAA8B,CAAC,CAAC;CAC1D,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CAEpD,gBAAgB;EACd,MAAM,aAAa,IAAI,gBAAgB;EACvC,SAAS,CAAC,CAAC;EACX,eAAe,KAAK;EACpB,CAAM,YAAY;GAChB,IAAI;IACF,MAAM,MAAM,IAAI,IAAI,gCAAgC,KAAK,OAAO;IAChE,IAAI,aAAa,IAAI,SAAS,QAAQ;IACtC,IAAI,aAAa,IAAI,QAAQ,SAAS;IACtC,IAAI,aAAa,IAAI,aAAa,MAAM;IACxC,IAAI,aAAa,IAAI,YAAY,OAAO,QAAQ,CAAC,CAAC;IAClD,MAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;KAC3C,QAAQ,WAAW;KACnB,SAAS,EAAE,QAAQ,8BAA8B;IACnD,CAAC;IACD,IAAI,CAAC,SAAS,IAAI;KAChB,eAAe,IAAI;KACnB;IACF;IACA,MAAM,QAAS,MAAM,SAAS,KAAK;IACnC,SAAS,MAAM,QAAQ,SAAS,KAAK,cAAc,IAAI,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC;IACxE,eAAe,KAAK;GACtB,QAAQ;IACN,IAAI,WAAW,OAAO,SACpB;IAEF,SAAS,CAAC,CAAC;IACX,eAAe,IAAI;GACrB;EACF,EAAA,CAAG;EACH,aAAa,WAAW,MAAM;CAChC,GAAG,CAAC,MAAM,KAAK,CAAC;CAEhB,OAAO,oBAAC,iBAAiB,UAAlB;EAA2B,OAAO;GAAE;GAAM;GAAO;EAAY;EAAI;CAAoC,CAAA;AAC9G;AAEA,IAAM,eAAe;CACnB,MAAM,EAAE,MAAM,MAAM,eAAe,KAAK,QAAQ,GAAG;CACnD,MAAM,EAAE,MAAM,OAAO,gBAAgB,oBAAoB;CACzD,OACE,qBAAC,UAAD;EAAQ,WAAU;EAAlB,UAAA,CACE,qBAAC,KAAD;GACE,MAAM,sBAAsB;GAC5B,QAAO;GACP,KAAI;GACJ,WAAU;GAJZ,UAAA,CAKA,KACI,IACD;EACH,CAAA,GAAA,oBAAC,OAAD;GAAK,WAAU;GACZ,UAAA,cACG,EAAE,4BAA4B,IAC9B,MAAM,SAAS,IACb,EAAE,oBAAoB,EAAE,OAAO,MAAM,OAAO,CAAC,IAC7C,EAAE,wBAAwB;EAC7B,CAAA,CACC;;AAEZ;AAEA,IAAM,iBAA+D;CACnE,CAAC,QAAQ,OAAkB;CAC3B,CAAC,SAAS,MAAiB;CAC3B,CAAC,QAAQ,MAAgB;CACzB,CAAC,OAAO,KAAY;CACpB,CAAC,QAAQ,IAAO;CAChB,CAAC,UAAU,EAAE;AACf;AAEA,IAAM,kBAAkB,QAAwB;CAC9C,MAAM,YAAY,IAAI,KAAK,mBAAmB,KAAA,GAAW,EAAE,SAAS,OAAO,CAAC;CAC5E,MAAM,eAAe,KAAK,MAAM,GAAG,IAAI,KAAK,IAAI,KAAK;CACrD,MAAM,UAAU,KAAK,IAAI,WAAW;CACpC,KAAK,MAAM,CAAC,MAAM,kBAAkB,gBAClC,IAAI,WAAW,eACb,OAAO,UAAU,OAAO,KAAK,MAAM,cAAc,aAAa,GAAG,IAAI;CAGzE,OAAO,UAAU,OAAO,KAAK,MAAM,WAAW,GAAG,QAAQ;AAC3D;AAEA,IAAM,WAAW,EAAE,WACjB,oBAAC,MAAD,EAAA,UACE,oBAAC,OAAO,MAAR;CAAa,SAAA;CAAQ,OAAM;CAAQ,KAAI;CAAK,YAAW;CACrD,UAAA,qBAAC,KAAD;EAAG,MAAM,KAAK;EAAU,QAAO;EAAS,KAAI;EAA5C,UAAA,CACE,oBAAC,OAAD;GAAK,KAAK,KAAK,KAAK;GAAY,KAAI;GAAG,WAAU;EAAgC,CAAA,GACjF,qBAAC,OAAO,MAAR;GAAa,QAAA;GAAO,YAAW;GAA/B,UAAA,CAEE,oBAAC,QAAD;IAAM,WAAU;IAA8B,UAAA,KAAK;GAAY,CAAA,GAC/D,qBAAC,QAAD;IAAM,WAAU;IAAhB,UAAA;KAAgD;KAC5C,KAAK;KAAO;KAAI,KAAK,KAAK;KAAM;KAAI,KAAK,YAAY,eAAe,KAAK,SAAS,IAAI;IACpF;GACK,CAAA,CAAA;EACZ,CAAA,CAAA;;AACQ,CAAA,EACX,CAAA;AAGN,IAAM,gBAAgB;CACpB,MAAM,EAAE,UAAU,oBAAoB;CACtC,OACE,oBAAC,WAAW,MAAZ;EAAiB,aAAY;EAC3B,UAAA,oBAAC,WAAW,UAAZ,EAAA,UACE,oBAAC,MAAD;GAAI,WAAU;GACX,UAAA,MAAM,KAAK,SACV,oBAAC,SAAD,EAAiC,KAAO,GAA1B,KAAK,MAAqB,CACzC;EACC,CAAA,EACe,CAAA;CACN,CAAA;AAErB;AAEA,IAAM,kBAAkB;CACtB,MAAM,EAAE,MAAM,MAAM,eAAe,KAAK,QAAQ,GAAG;CACnD,MAAM,EAAE,SAAS,oBAAoB;CACrC,OACE,oBAAC,OAAO,MAAR;EACE,MAAK;EACL,OAAO,EAAE,uBAAuB;EAChC,SAAQ;EACR,YAAW;EACX,eAAe;GACb,OAAO,KAAK,sBAAsB,QAAQ,UAAU,qBAAqB;EAC3E;CACD,CAAA;AAEL;AAEA,IAAa,kBAAkB;CAC7B;CACA;CACA;CACA;AACF;;;ACxLA,IAAa,oBACX,oBAAC,gBAAgB,MAAjB,EAAA,UACE,qBAAC,OAAD;CAAK,WAAU;CAAf,UAAA;EACE,oBAAC,gBAAgB,QAAjB,CAAyB,CAAA;EACzB,oBAAC,gBAAgB,SAAjB,CAA0B,CAAA;EAC1B,oBAAC,gBAAgB,WAAjB,CAA4B,CAAA;CACzB;AACe,CAAA,EAAA,CAAA;AAGxB,YAAY,cAAc"}