@dxos/plugin-native 0.12.0-next-73daef452f1464b62efdbca75fb0067c1066f264 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/PLUGIN.mdl +64 -16
  2. package/dist/lib/NativeCapabilities.mjs +1 -1
  3. package/dist/lib/NativeCapabilities.mjs.map +1 -1
  4. package/dist/lib/Update.mjs.map +1 -1
  5. package/dist/lib/capabilities.browser.mjs +42 -0
  6. package/dist/lib/capabilities.browser.mjs.map +1 -0
  7. package/dist/lib/capabilities.mjs +1 -3
  8. package/dist/lib/capabilities.mjs.map +1 -1
  9. package/dist/lib/capabilities.node.mjs.map +1 -1
  10. package/dist/lib/capabilities.tauri.mjs +42 -0
  11. package/dist/lib/capabilities.tauri.mjs.map +1 -0
  12. package/dist/lib/capabilities.workerd.mjs.map +1 -1
  13. package/dist/lib/chunk-NativeSettings.mjs +15 -77
  14. package/dist/lib/chunk-NativeSettings.mjs.map +1 -1
  15. package/dist/lib/chunk-PLUGIN.mjs +6 -0
  16. package/dist/lib/chunk-PLUGIN.mjs.map +1 -0
  17. package/dist/lib/chunk-ollama.mjs +75 -41
  18. package/dist/lib/chunk-ollama.mjs.map +1 -1
  19. package/dist/lib/chunk-react-surface.mjs +2 -2
  20. package/dist/lib/chunk-react-surface.mjs.map +1 -1
  21. package/dist/lib/chunk-settings.mjs +2 -2
  22. package/dist/lib/chunk-settings.mjs.map +1 -1
  23. package/dist/lib/chunk-spotlight-listener.mjs +6 -5
  24. package/dist/lib/chunk-spotlight-listener.mjs.map +1 -1
  25. package/dist/lib/chunk-updater.mjs +18 -15
  26. package/dist/lib/chunk-updater.mjs.map +1 -1
  27. package/dist/lib/containers.mjs.map +1 -1
  28. package/dist/lib/index.mjs +0 -1
  29. package/dist/lib/meta.mjs +1 -1
  30. package/dist/lib/meta.mjs.map +1 -1
  31. package/dist/lib/translations.mjs.map +1 -1
  32. package/dist/types/src/capabilities/gen/browser.d.ts +9 -0
  33. package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -0
  34. package/dist/types/src/capabilities/gen/tauri.d.ts +9 -0
  35. package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -0
  36. package/dist/types/src/capabilities/ollama.d.ts.map +1 -1
  37. package/dist/types/src/capabilities/spotlight-listener.d.ts.map +1 -1
  38. package/dist/types/src/capabilities/updater.d.ts +1 -1
  39. package/dist/types/src/constants.d.ts +2 -1
  40. package/dist/types/src/constants.d.ts.map +1 -1
  41. package/dist/types/src/containers/NativeSettings/NativeSettings.d.ts +1 -1
  42. package/dist/types/src/containers/NativeSettings/NativeSettings.d.ts.map +1 -1
  43. package/dist/types/src/containers/NativeSettings/index.d.ts +1 -1
  44. package/dist/types/src/containers/NativeSettings/index.d.ts.map +1 -1
  45. package/dist/types/src/containers/index.d.ts.map +1 -1
  46. package/dist/types/src/index.d.ts +1 -2
  47. package/dist/types/src/index.d.ts.map +1 -1
  48. package/dist/types/src/translations.d.ts.map +1 -1
  49. package/dist/types/src/types/NativeCapabilities.d.ts +3 -3
  50. package/dist/types/src/types/NativeCapabilities.d.ts.map +1 -1
  51. package/dist/types/src/types/Update.d.ts +1 -31
  52. package/dist/types/src/types/Update.d.ts.map +1 -1
  53. package/dist/types/src/types/index.d.ts +4 -4
  54. package/dist/types/src/types/index.d.ts.map +1 -1
  55. package/dist/types/tsconfig.tsbuildinfo +1 -1
  56. package/dx.config.ts +1 -1
  57. package/package.json +23 -22
  58. package/src/capabilities/gen/browser.ts +66 -0
  59. package/src/capabilities/gen/node.ts +4 -4
  60. package/src/capabilities/gen/tauri.ts +66 -0
  61. package/src/capabilities/gen/workerd.ts +4 -4
  62. package/src/capabilities/index.ts +5 -5
  63. package/src/capabilities/ollama.ts +65 -35
  64. package/src/capabilities/react-surface.ts +2 -2
  65. package/src/capabilities/settings.ts +2 -2
  66. package/src/capabilities/spotlight-listener.ts +8 -4
  67. package/src/capabilities/updater.ts +12 -6
  68. package/src/constants.ts +2 -1
  69. package/src/containers/NativeSettings/NativeSettings.tsx +17 -120
  70. package/src/containers/NativeSettings/index.ts +1 -1
  71. package/src/containers/index.ts +1 -1
  72. package/src/index.ts +1 -2
  73. package/src/meta.ts +1 -1
  74. package/src/translations.ts +2 -2
  75. package/src/types/NativeCapabilities.ts +5 -5
  76. package/src/types/Update.ts +4 -21
  77. package/src/types/index.ts +4 -4
package/PLUGIN.mdl CHANGED
@@ -17,9 +17,11 @@ Each extension is defined in the Appendix or resolved via its URI.
17
17
  |-------------|--------------------------------|
18
18
  | `type` | `org.dxos.mdl.type@1.0` |
19
19
  | `feat` | `org.dxos.mdl.feat@1.0` |
20
- | `test` | `org.dxos.mdl.test@1.0` |
20
+ | `scenario` | `org.dxos.mdl.scenario@1.0` |
21
21
  | `component` | `org.dxos.mdl.component@1.0` |
22
22
  | `op` | `org.dxos.mdl.op@1.0` |
23
+ | `test` | `org.dxos.mdl.test@1.0` |
24
+ | `step` | `org.dxos.mdl.step@1.0` |
23
25
 
24
26
  ## Types
25
27
 
@@ -40,8 +42,7 @@ type UpdateState
40
42
  kind: UpdateStatus
41
43
  version?: string # set when kind = available
42
44
  checkedAt?: number # epoch ms; set when kind = up-to-date
43
- downloaded?: number # bytes received; set when kind = downloading
44
- contentLength?: number # total bytes; set when kind = downloading
45
+ progress?: { completed: number, total: number, unit: 'bytes' } # set when kind = downloading
45
46
  error?: string # set when kind = failed
46
47
  ```
47
48
 
@@ -57,8 +58,8 @@ component NativeSettings
57
58
  settings: Settings
58
59
  onSettingsChange(patch: Partial<Settings>)
59
60
  state:
60
- pending: null | 'check' | 'install' | 'relaunch'
61
- status: UpdateState # derived from UpdateManager capability
61
+ pending: null | 'check' | 'install' | 'apply'
62
+ status: UpdateState # derived from AppCapabilities.UpdateManager (shared with plugin-pwa)
62
63
  actions:
63
64
  checkForUpdate()
64
65
  installUpdate()
@@ -111,11 +112,11 @@ feat F-1: Spotlight Window Integration
111
112
 
112
113
  req F-1.1:
113
114
  when: the main Composer window receives a spotlight:invoke Tauri event with operation = 'open'
114
- then: the LayoutOperation.Open intent is dispatched with the provided payload
115
+ then: the LayoutOperation.Open intent is dispatched with the payload, decoded against its input schema
115
116
 
116
117
  req F-1.2:
117
118
  when: the main Composer window receives a spotlight:invoke event with operation = 'switch-workspace'
118
- then: the LayoutOperation.SwitchWorkspace intent is dispatched with the provided payload
119
+ then: the LayoutOperation.SwitchWorkspace intent is dispatched with the payload, decoded against its input schema
119
120
 
120
121
  req F-1.3:
121
122
  when: a spotlight:invoke event is handled successfully
@@ -124,6 +125,10 @@ feat F-1: Spotlight Window Integration
124
125
  req F-1.4:
125
126
  when: a spotlight:invoke event carries an unrecognised operation
126
127
  then: a warning is logged and no intent is dispatched
128
+
129
+ req F-1.5:
130
+ when: a spotlight:invoke payload does not decode against the operation's input schema
131
+ then: the error is logged and no intent is dispatched
127
132
  ```
128
133
 
129
134
  ```mdl
@@ -169,16 +174,16 @@ feat F-3: Ollama Sidecar
169
174
  ## Acceptance
170
175
 
171
176
  ```mdl
172
- test T-1: Spotlight open dispatches LayoutOperation.Open
177
+ scenario T-1: Spotlight open dispatches LayoutOperation.Open
173
178
  given: Composer is running and SpotlightListener is active
174
- when: a spotlight:invoke Tauri event arrives with operation = 'open' and payload { spaceId: 'abc' }
179
+ when: a spotlight:invoke Tauri event arrives with operation = 'open' and payload { subject: ['root/abc/home'], disposition: 'add' }
175
180
  then:
176
- - LayoutOperation.Open is invoked with { spaceId: 'abc' }
181
+ - LayoutOperation.Open is invoked with { subject: ['root/abc/home'], disposition: 'add' }
177
182
  - main window is visible and focused
178
183
  ```
179
184
 
180
185
  ```mdl
181
- test T-2: Unknown spotlight operation is silently dropped
186
+ scenario T-2: Unknown spotlight operation is silently dropped
182
187
  given: SpotlightListener is active
183
188
  when: a spotlight:invoke event arrives with operation = 'foobar'
184
189
  then:
@@ -187,7 +192,7 @@ test T-2: Unknown spotlight operation is silently dropped
187
192
  ```
188
193
 
189
194
  ```mdl
190
- test T-3: Update check transitions status atom
195
+ scenario T-3: Update check transitions status atom
191
196
  given: Updater module is active on a supported platform
192
197
  when: CheckForUpdate is called
193
198
  then:
@@ -197,7 +202,7 @@ test T-3: Update check transitions status atom
197
202
  ```
198
203
 
199
204
  ```mdl
200
- test T-4: Failed update check transitions to failed status
205
+ scenario T-4: Failed update check transitions to failed status
201
206
  given: Updater module is active
202
207
  when: the Tauri updater plugin throws an error during check
203
208
  then:
@@ -206,7 +211,7 @@ test T-4: Failed update check transitions to failed status
206
211
  ```
207
212
 
208
213
  ```mdl
209
- test T-5: Dev-server build disables updater
214
+ scenario T-5: Dev-server build disables updater
210
215
  given: the app is served on a port outside TAURI_LOCALHOST_PORTS
211
216
  when: the Updater module activates
212
217
  then:
@@ -216,6 +221,49 @@ test T-5: Dev-server build disables updater
216
221
 
217
222
  ---
218
223
 
224
+ ## QA
225
+
226
+ Executable tests. Each step carries a human instruction (`do`) and, where the step maps to an
227
+ invocable operation, an agent binding (`invoke`). Report failures by test and step number.
228
+
229
+ ```mdl
230
+ test QA-1: Check for an OTA update
231
+ desc: |
232
+ The plugin contributes no runtime operation — `CheckForUpdate`, `InstallUpdate`, and
233
+ `RelaunchApp` are direct calls into the Tauri updater/shell plugins from native-only code
234
+ (`Updater` module, `SpotlightListener`), not `Operation.make` entries reachable through the
235
+ debug port or any web session. There is also no invocation surface to run this against: the
236
+ agent debug port drives a running Composer web page, and this plugin only activates inside
237
+ the Tauri desktop shell (`isTauri && !isMobile && !isPopover`, see `plugin-defs.core.tsx`) —
238
+ a build this environment cannot launch or attach to. Every step is therefore blocked.
239
+ actors: human
240
+ covers: [F-2.1, F-2.2, T-3]
241
+ status: blocked
242
+ given:
243
+ - a Tauri desktop build of Composer is installed and running (macOS, Linux, or Windows)
244
+ - an OTA update is actually available for the running version
245
+ steps:
246
+ - name: Check for an update
247
+ do: Open Settings → App, and click "Check for updates" (or wait for the hourly background check).
248
+ expect: the status line transitions checking → available, showing the new version string
249
+ blocked: |
250
+ No `Operation.make` exists for `CheckForUpdate` — it is a direct Tauri updater plugin
251
+ call from `Updater`'s background fiber, invisible to the agent debug port. It also cannot
252
+ run inside this session at all: the port attaches to a web page, and this feature only
253
+ exists in a Tauri desktop build. A human tester with a real desktop build and a genuine
254
+ pending release is the only way to exercise this.
255
+ - name: Install and relaunch
256
+ do: Click "Update Now", wait for the download to finish, then click "Relaunch".
257
+ expect: the app downloads the update, shows a "Relaunch" toast, and restarts on the new version
258
+ blocked: Same as the previous step — `InstallUpdate`/`RelaunchApp` are native-only and have no operation key.
259
+ after:
260
+ - name: (nothing to undo)
261
+ do: No fixture was created; an update, once installed, cannot be un-installed by this test.
262
+ expect: n/a
263
+ ```
264
+
265
+ ---
266
+
219
267
  ## Appendix: Extension Definitions
220
268
 
221
269
  Extension block types used in this document are defined below using
@@ -243,8 +291,8 @@ ext feat
243
291
  ```
244
292
 
245
293
  ```mdl
246
- ext test
247
- uri: org.dxos.mdl.test@1.0
294
+ ext scenario
295
+ uri: org.dxos.mdl.scenario@1.0
248
296
  desc: An acceptance scenario expressed as given / when / then steps.
249
297
  fields:
250
298
  given?: Step | Step[]
@@ -1,5 +1,6 @@
1
1
  import { t as __exportAll } from "./chunk-rolldown-runtime.mjs";
2
2
  import * as Capability from "@dxos/app-framework/Capability";
3
+ import { UpdateManager } from "@dxos/app-toolkit/AppCapabilities";
3
4
  import { meta } from "#meta";
4
5
  //#region src/types/NativeCapabilities.ts
5
6
  var NativeCapabilities_exports = /* @__PURE__ */ __exportAll({
@@ -7,7 +8,6 @@ var NativeCapabilities_exports = /* @__PURE__ */ __exportAll({
7
8
  UpdateManager: () => UpdateManager
8
9
  });
9
10
  var Settings = Capability.makeSingleton()(`${meta.profile.key}.capability.settings`);
10
- var UpdateManager = Capability.makeSingleton()(`${meta.profile.key}.capability.updateManager`);
11
11
  //#endregion
12
12
  export { Settings, UpdateManager, NativeCapabilities_exports as t };
13
13
 
@@ -1 +1 @@
1
- {"version":3,"file":"NativeCapabilities.mjs","names":[],"sources":["../../src/types/NativeCapabilities.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport type * as Atom from 'effect/unstable/reactivity/Atom';\n\nimport * as Capability from '@dxos/app-framework/Capability';\n\nimport { meta } from '#meta';\n\n// Inline imports to avoid `Settings` / `Update` namespace aliases colliding with the\n// capability constants exported below.\nexport const Settings = Capability.makeSingleton<Atom.Writable<import('./Settings').Settings>>()(\n `${meta.profile.key}.capability.settings`,\n);\nexport const UpdateManager = Capability.makeSingleton<import('./Update').Manager>()(\n `${meta.profile.key}.capability.updateManager`,\n);\n"],"mappings":";;;;;;;;AAcA,IAAa,WAAW,WAAW,cAA4D,CAAC,CAC9F,GAAG,KAAK,QAAQ,IAAI,qBACtB;AACA,IAAa,gBAAgB,WAAW,cAA0C,CAAC,CACjF,GAAG,KAAK,QAAQ,IAAI,0BACtB"}
1
+ {"version":3,"file":"NativeCapabilities.mjs","names":[],"sources":["../../src/types/NativeCapabilities.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport type * as Atom from 'effect/reactivity/Atom';\n\nimport * as Capability from '@dxos/app-framework/Capability';\n\nimport { meta } from '#meta';\n\n// Inline imports to avoid `Settings` / `Update` namespace aliases colliding with the\n// capability constants exported below.\nexport const Settings = Capability.makeSingleton<Atom.Writable<import('./Settings.ts').Settings>>()(\n `${meta.profile.key}.capability.settings`,\n);\n// Re-exported rather than declared: plugin-pwa contributes the same capability, so a settings surface\n// resolves one identifier and gets whichever platform is present.\nexport { UpdateManager } from '@dxos/app-toolkit/AppCapabilities';\n"],"mappings":";;;;;;;;;AAcA,IAAa,WAAW,WAAW,cAA+D,CAAC,CACjG,GAAG,KAAK,QAAQ,IAAI,qBACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"Update.mjs","names":[],"sources":["../../src/types/Update.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport type * as Atom from 'effect/unstable/reactivity/Atom';\n\n// @import-as-namespace\n\nexport type Status =\n // The platform has no OTA channel at all.\n | { kind: 'unsupported' }\n // The platform supports OTA, but this build is served by the dev server.\n | { kind: 'dev' }\n | { kind: 'idle' }\n | { kind: 'checking' }\n | { kind: 'up-to-date'; checkedAt: number }\n | { kind: 'available'; version: string }\n | { kind: 'downloading'; downloaded: number; contentLength: number }\n | { kind: 'ready' }\n | { kind: 'failed'; error: string };\n\nexport type Manager = {\n status: Atom.Writable<Status>;\n check: () => Promise<void>;\n install: () => Promise<void>;\n relaunch: () => Promise<void>;\n};\n"],"mappings":""}
1
+ {"version":3,"file":"Update.mjs","names":[],"sources":["../../src/types/Update.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\n// The update surface is shared with the web (`plugin-pwa` contributes the same capability), so the\n// shape lives in app-toolkit and this module only re-exports it. Kept as a module rather than deleted\n// so `#types`' `Update` namespace and the existing imports keep resolving.\nexport type { Manager, Progress, Status } from '@dxos/app-toolkit/AppUpdate';\n"],"mappings":""}
@@ -0,0 +1,42 @@
1
+ import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
2
+ import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
3
+ import * as Capabilities from "@dxos/app-framework/Capabilities";
4
+ import * as Capability from "@dxos/app-framework/Capability";
5
+ import * as AppCapabilities from "@dxos/app-toolkit/AppCapabilities";
6
+ import * as AppCapability from "@dxos/app-toolkit/AppCapability";
7
+ import * as AssistantCapabilities from "@dxos/plugin-assistant/AssistantCapabilities";
8
+ import { translations } from "#translations";
9
+ import { NativeCapabilities, NativeEvents } from "#types";
10
+ import { meta } from "#meta";
11
+ //#region src/capabilities/gen/browser.ts
12
+ var NativeSettings = AppCapability.settings(() => import("./chunk-settings.mjs"), {
13
+ activatesOn: ActivationEvents.Idle,
14
+ provides: [NativeCapabilities.Settings]
15
+ });
16
+ var Ollama = Capability.lazyModule("Ollama", {
17
+ requires: [Capabilities.AtomRegistry],
18
+ provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],
19
+ activatesOn: ActivationEvents.Startup
20
+ }, () => import("./chunk-ollama.mjs"));
21
+ var PluginAsset = AppCapability.pluginAsset({
22
+ pluginId: meta.profile.key,
23
+ path: "PLUGIN.mdl",
24
+ content: PLUGIN_default,
25
+ mimeType: "application/x-mdl"
26
+ });
27
+ var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article"] });
28
+ var SpotlightListener = Capability.lazyModule("SpotlightListener", {
29
+ requires: [Capabilities.OperationInvoker],
30
+ provides: [],
31
+ activatesOn: NativeEvents.Start
32
+ }, () => import("./chunk-spotlight-listener.mjs"));
33
+ var Translations = AppCapability.translations(translations);
34
+ var Updater = Capability.lazyModule("Updater", {
35
+ requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],
36
+ provides: [NativeCapabilities.UpdateManager],
37
+ activatesOn: NativeEvents.Start
38
+ }, () => import("./chunk-updater.mjs"));
39
+ //#endregion
40
+ export { NativeSettings, Ollama, PluginAsset, ReactSurface, SpotlightListener, Translations, Updater };
41
+
42
+ //# sourceMappingURL=capabilities.browser.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.browser.mjs","names":[],"sources":["../../src/capabilities/gen/browser.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'browser' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as AssistantCapabilities from '@dxos/plugin-assistant/AssistantCapabilities';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { NativeCapabilities, NativeEvents } from '#types';\n\nimport pluginSpec from '../../../PLUGIN.mdl?raw';\n\nexport const NativeSettings = AppCapability.settings(() => import('../settings.ts'), {\n activatesOn: ActivationEvents.Idle,\n provides: [NativeCapabilities.Settings],\n});\n\n// Startup, not `AssistantEvents.Start`: `AiService` snapshots its multi-arity `AiModelResolver`\n// require once during startup, so the sidecar resolver contributed in a later round is invisible to\n// it and every `built-in` model fails to resolve. Activation stays cheap — it builds the manager and\n// a lazy layer; the sidecar process spawns on first use, not here.\nexport const Ollama = Capability.lazyModule(\n 'Ollama',\n {\n requires: [Capabilities.AtomRegistry],\n provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],\n activatesOn: ActivationEvents.Startup,\n },\n () => import('../ollama.ts'),\n);\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n\nexport const ReactSurface = AppCapability.surface(() => import('../react-surface.ts'), {\n roles: ['org.dxos.role.article'],\n});\n\nexport const SpotlightListener = Capability.lazyModule(\n 'SpotlightListener',\n { requires: [Capabilities.OperationInvoker], provides: [], activatesOn: NativeEvents.Start },\n () => import('../spotlight-listener.ts'),\n);\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const Updater = Capability.lazyModule(\n 'Updater',\n {\n requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],\n provides: [NativeCapabilities.UpdateManager],\n activatesOn: NativeEvents.Start,\n },\n () => import('../updater.ts'),\n);\n"],"mappings":";;;;;;;;;;;AAmBA,IAAa,iBAAiB,cAAc,eAAe,OAAO,yBAAmB;CACnF,aAAa,iBAAiB;CAC9B,UAAU,CAAC,mBAAmB,QAAQ;AACxC,CAAC;AAMD,IAAa,SAAS,WAAW,WAC/B,UACA;CACE,UAAU,CAAC,aAAa,YAAY;CACpC,UAAU,CAAC,gBAAgB,iBAAiB,sBAAsB,aAAa;CAC/E,aAAa,iBAAiB;AAChC,SACM,OAAO,qBACf;AAEA,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AAED,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAwB,EACrF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AAED,IAAa,oBAAoB,WAAW,WAC1C,qBACA;CAAE,UAAU,CAAC,aAAa,gBAAgB;CAAG,UAAU,CAAC;CAAG,aAAa,aAAa;AAAM,SACrF,OAAO,iCACf;AAEA,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,UAAU,WAAW,WAChC,WACA;CACE,UAAU,CAAC,aAAa,cAAc,aAAa,gBAAgB;CACnE,UAAU,CAAC,mBAAmB,aAAa;CAC3C,aAAa,aAAa;AAC5B,SACM,OAAO,sBACf"}
@@ -1,3 +1,4 @@
1
+ import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
1
2
  import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
2
3
  import * as Capabilities from "@dxos/app-framework/Capabilities";
3
4
  import * as Capability from "@dxos/app-framework/Capability";
@@ -7,9 +8,6 @@ import * as AssistantCapabilities from "@dxos/plugin-assistant/AssistantCapabili
7
8
  import { translations } from "#translations";
8
9
  import { NativeCapabilities, NativeEvents } from "#types";
9
10
  import { meta } from "#meta";
10
- //#region PLUGIN.mdl?raw
11
- var PLUGIN_default = "---\nid: org.dxos.plugin.native\nname: NativePlugin\nversion: 0.1.0\n---\n\nA Tauri-based native platform integration plugin for DXOS Composer that enables desktop-specific\ncapabilities on macOS, Linux, and Windows. It manages Spotlight window integration, over-the-air\napplication updates, and an Ollama sidecar process for local AI model inference.\n\n## Extensions\n\nThe following extension dialects are used in this document.\nEach extension is defined in the Appendix or resolved via its URI.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `test` | `org.dxos.mdl.test@1.0` |\n| `component` | `org.dxos.mdl.component@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n\n## Types\n\n```mdl\ntype Settings\n fields:\n # No user-visible settings fields yet; reserved for future configuration.\n```\n\n```mdl\ntype UpdateStatus\n literals: unsupported | idle | checking | up-to-date | available | downloading | ready | failed\n```\n\n```mdl\ntype UpdateState\n fields:\n kind: UpdateStatus\n version?: string # set when kind = available\n checkedAt?: number # epoch ms; set when kind = up-to-date\n downloaded?: number # bytes received; set when kind = downloading\n contentLength?: number # total bytes; set when kind = downloading\n error?: string # set when kind = failed\n```\n\n## Components\n\n```mdl\ncomponent NativeSettings\n desc: |\n Settings panel section rendered inside the global Settings dialog under the\n App (native) plugin entry. Shows the current update status and exposes\n Check / Update Now / Relaunch actions depending on the UpdateState.\n props:\n settings: Settings\n onSettingsChange(patch: Partial<Settings>)\n state:\n pending: null | 'check' | 'install' | 'relaunch'\n status: UpdateState # derived from UpdateManager capability\n actions:\n checkForUpdate()\n installUpdate()\n relaunchApp()\n layout: |\n ┌─────────────────────────────────────────┐\n │ Updates │\n ├─────────────────────────────────────────┤\n │ [status description] [Check / Update]│\n └─────────────────────────────────────────┘\n```\n\n## Operations\n\n```mdl\nop CheckForUpdate\n desc: |\n Initiates an OTA update check via the Tauri updater plugin.\n Updates the UpdateManager status atom as the check progresses.\n input: void\n output: void\n effects: [http]\n note: No-op on unsupported platforms; guarded by SUPPORTS_OTA list.\n```\n\n```mdl\nop InstallUpdate\n desc: |\n Downloads and installs a pending update, streaming progress events to the\n UpdateManager status atom. Does not relaunch the app automatically.\n input: void\n output: void\n effects: [http, fs]\n note: Only valid when UpdateManager status kind = available.\n```\n\n```mdl\nop RelaunchApp\n desc: |\n Relaunches the Tauri app process to apply the installed update.\n input: void\n output: void\n effects: [process]\n```\n\n## Features\n\n```mdl\nfeat F-1: Spotlight Window Integration\n\n req F-1.1:\n when: the main Composer window receives a spotlight:invoke Tauri event with operation = 'open'\n then: the LayoutOperation.Open intent is dispatched with the provided payload\n\n req F-1.2:\n when: the main Composer window receives a spotlight:invoke event with operation = 'switch-workspace'\n then: the LayoutOperation.SwitchWorkspace intent is dispatched with the provided payload\n\n req F-1.3:\n when: a spotlight:invoke event is handled successfully\n then: the main Composer window is shown and brought to focus\n\n req F-1.4:\n when: a spotlight:invoke event carries an unrecognised operation\n then: a warning is logged and no intent is dispatched\n```\n\n```mdl\nfeat F-2: Over-the-Air Updates\n\n req F-2.1:\n when: the Updater module activates on a supported platform (macOS, Linux, Windows) in production\n then: a background Effect fiber is started that checks for updates immediately and repeats hourly\n\n req F-2.2:\n when: an update is available and successfully downloaded\n then: a toast notification is shown with a Relaunch action; the status atom transitions to ready\n\n req F-2.3:\n when: the Tauri updater check throws\n then: the status atom transitions to failed with a human-readable error string\n\n req F-2.4:\n when: the app is running in a dev-server build (port not in TAURI_LOCALHOST_PORTS)\n then: the updater is disabled and status remains unsupported\n\n req F-2.5:\n when: the Updater module is torn down\n then: the background update-check fiber is interrupted cleanly\n```\n\n```mdl\nfeat F-3: Ollama Sidecar\n\n req F-3.1:\n when: the AssistantEvents.SetupAiServiceProviders event fires\n then: the Ollama sidecar binary is spawned via Tauri shell on localhost port 21434\n\n req F-3.2:\n when: the Ollama sidecar is running\n then: it is registered as an AiModelResolver under AppCapabilities.AiModelResolver\n\n req F-3.3:\n when: the Ollama capability is torn down\n then: the sidecar process is killed and the managed runtime is disposed\n```\n\n## Acceptance\n\n```mdl\ntest T-1: Spotlight open dispatches LayoutOperation.Open\n given: Composer is running and SpotlightListener is active\n when: a spotlight:invoke Tauri event arrives with operation = 'open' and payload { spaceId: 'abc' }\n then:\n - LayoutOperation.Open is invoked with { spaceId: 'abc' }\n - main window is visible and focused\n```\n\n```mdl\ntest T-2: Unknown spotlight operation is silently dropped\n given: SpotlightListener is active\n when: a spotlight:invoke event arrives with operation = 'foobar'\n then:\n - no intent is dispatched\n - a warning log entry is emitted with the unknown operation name\n```\n\n```mdl\ntest T-3: Update check transitions status atom\n given: Updater module is active on a supported platform\n when: CheckForUpdate is called\n then:\n - status transitions to checking while the HTTP call is in-flight\n - status transitions to up-to-date if no update is available\n - status transitions to available with a version string if an update exists\n```\n\n```mdl\ntest T-4: Failed update check transitions to failed status\n given: Updater module is active\n when: the Tauri updater plugin throws an error during check\n then:\n - status transitions to failed\n - status.error contains a human-readable description\n```\n\n```mdl\ntest T-5: Dev-server build disables updater\n given: the app is served on a port outside TAURI_LOCALHOST_PORTS\n when: the Updater module activates\n then:\n - status is set to unsupported immediately\n - no HTTP update check is performed\n```\n\n---\n\n## Appendix: Extension Definitions\n\nExtension block types used in this document are defined below using\nthe core `ext` primitive — the only construct the base language provides.\n\n```mdl\next type\n uri: org.dxos.mdl.type@1.0\n desc: A named data structure with typed fields and optional literals.\n fields:\n desc?: Prose\n fields?: FieldMap # name[?]: TypeExpr (# inline comment)\n literals?: UnionList # a | b | c\n extends?: TypeRef[]\n```\n\n```mdl\next feat\n uri: org.dxos.mdl.feat@1.0\n desc: A named feature grouping one or more requirements.\n fields:\n desc?: Prose\n req: RequirementList\n nesting: self # feat blocks may contain feat blocks\n```\n\n```mdl\next test\n uri: org.dxos.mdl.test@1.0\n desc: An acceptance scenario expressed as given / when / then steps.\n fields:\n given?: Step | Step[]\n when?: Step | Step[]\n then: Step | Step[]\n tags?: TagList\n```\n\n```mdl\next component\n uri: org.dxos.mdl.component@1.0\n desc: A UI component with props, internal state, slots, actions, and events.\n fields:\n desc?: Prose\n props?: FieldMap # external inputs (immutable inside component)\n state?: FieldMap # internal reactive state\n slots?: FieldMap # named ReactNode injection points\n actions?: ActionMap # methods the component exposes or handles\n emits?: EventMap # events the component raises to its parent\n layout?: CodeBlock # ASCII sketch of visual structure (non-normative)\n```\n\n```mdl\next op\n uri: org.dxos.mdl.op@1.0\n desc: |\n A named operation with typed inputs, outputs, and declared errors.\n Pure ops have no effects or requires. Effectful ops declare both.\n fields:\n desc?: Prose\n input?: FieldMap # named input parameters\n output?: TypeExpr # return type\n errors?: ErrorMap # name: Prose (when this error occurs)\n effects?: EffectList # echo:read | echo:write | http | fs | ...\n requires?: ServiceList # injected service dependencies\n note?: Prose # implementation guidance (non-normative)\n```\n";
12
- //#endregion
13
11
  //#region src/capabilities/index.ts
14
12
  var NativeSettings = AppCapability.settings(() => import("./chunk-settings.mjs"), {
15
13
  activatesOn: ActivationEvents.Idle,
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\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 AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as AssistantCapabilities from '@dxos/plugin-assistant/AssistantCapabilities';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { NativeCapabilities, NativeEvents } from '#types';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../../PLUGIN.mdl?raw';\n\nexport const NativeSettings = AppCapability.settings(() => import('./settings'), {\n activatesOn: ActivationEvents.Idle,\n provides: [NativeCapabilities.Settings],\n});\n// Startup, not `AssistantEvents.Start`: `AiService` snapshots its multi-arity `AiModelResolver`\n// require once during startup, so the sidecar resolver contributed in a later round is invisible to\n// it and every `built-in` model fails to resolve. Activation stays cheap — it builds the manager and\n// a lazy layer; the sidecar process spawns on first use, not here.\nexport const Ollama = Capability.lazyModule(\n 'Ollama',\n {\n requires: [Capabilities.AtomRegistry],\n provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],\n activatesOn: ActivationEvents.Startup,\n },\n () => import('./ollama'),\n);\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface'), {\n roles: ['org.dxos.role.article'],\n});\nexport const SpotlightListener = Capability.lazyModule(\n 'SpotlightListener',\n { requires: [Capabilities.OperationInvoker], provides: [], activatesOn: NativeEvents.Start },\n () => import('./spotlight-listener'),\n);\nexport const Translations = AppCapability.translations(translations);\nexport const Updater = Capability.lazyModule(\n 'Updater',\n {\n requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],\n provides: [NativeCapabilities.UpdateManager],\n activatesOn: NativeEvents.Start,\n },\n () => import('./updater'),\n);\n"],"mappings":";;;;;;;;;;;;;AAkBA,IAAa,iBAAiB,cAAc,eAAe,OAAO,yBAAe;CAC/E,aAAa,iBAAiB;CAC9B,UAAU,CAAC,mBAAmB,QAAQ;AACxC,CAAC;AAKD,IAAa,SAAS,WAAW,WAC/B,UACA;CACE,UAAU,CAAC,aAAa,YAAY;CACpC,UAAU,CAAC,gBAAgB,iBAAiB,sBAAsB,aAAa;CAC/E,aAAa,iBAAiB;AAChC,SACM,OAAO,qBACf;AACA,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AACD,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAoB,EACjF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AACD,IAAa,oBAAoB,WAAW,WAC1C,qBACA;CAAE,UAAU,CAAC,aAAa,gBAAgB;CAAG,UAAU,CAAC;CAAG,aAAa,aAAa;AAAM,SACrF,OAAO,iCACf;AACA,IAAa,eAAe,cAAc,aAAa,YAAY;AACnE,IAAa,UAAU,WAAW,WAChC,WACA;CACE,UAAU,CAAC,aAAa,cAAc,aAAa,gBAAgB;CACnE,UAAU,CAAC,mBAAmB,aAAa;CAC3C,aAAa,aAAa;AAC5B,SACM,OAAO,sBACf"}
1
+ {"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\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 AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as AssistantCapabilities from '@dxos/plugin-assistant/AssistantCapabilities';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { NativeCapabilities, NativeEvents } from '#types';\n\n// eslint-disable-next-line import/no-relative-packages\nimport pluginSpec from '../../PLUGIN.mdl?raw';\n\nexport const NativeSettings = AppCapability.settings(() => import('./settings.ts'), {\n activatesOn: ActivationEvents.Idle,\n provides: [NativeCapabilities.Settings],\n});\n// Startup, not `AssistantEvents.Start`: `AiService` snapshots its multi-arity `AiModelResolver`\n// require once during startup, so the sidecar resolver contributed in a later round is invisible to\n// it and every `built-in` model fails to resolve. Activation stays cheap — it builds the manager and\n// a lazy layer; the sidecar process spawns on first use, not here.\nexport const Ollama = Capability.lazyModule(\n 'Ollama',\n {\n requires: [Capabilities.AtomRegistry],\n provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],\n activatesOn: ActivationEvents.Startup,\n },\n () => import('./ollama.ts'),\n);\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\nexport const ReactSurface = AppCapability.surface(() => import('./react-surface.ts'), {\n roles: ['org.dxos.role.article'],\n});\nexport const SpotlightListener = Capability.lazyModule(\n 'SpotlightListener',\n { requires: [Capabilities.OperationInvoker], provides: [], activatesOn: NativeEvents.Start },\n () => import('./spotlight-listener.ts'),\n);\nexport const Translations = AppCapability.translations(translations);\nexport const Updater = Capability.lazyModule(\n 'Updater',\n {\n requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],\n provides: [NativeCapabilities.UpdateManager],\n activatesOn: NativeEvents.Start,\n },\n () => import('./updater.ts'),\n);\n"],"mappings":";;;;;;;;;;;AAkBA,IAAa,iBAAiB,cAAc,eAAe,OAAO,yBAAkB;CAClF,aAAa,iBAAiB;CAC9B,UAAU,CAAC,mBAAmB,QAAQ;AACxC,CAAC;AAKD,IAAa,SAAS,WAAW,WAC/B,UACA;CACE,UAAU,CAAC,aAAa,YAAY;CACpC,UAAU,CAAC,gBAAgB,iBAAiB,sBAAsB,aAAa;CAC/E,aAAa,iBAAiB;AAChC,SACM,OAAO,qBACf;AACA,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AACD,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAuB,EACpF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AACD,IAAa,oBAAoB,WAAW,WAC1C,qBACA;CAAE,UAAU,CAAC,aAAa,gBAAgB;CAAG,UAAU,CAAC;CAAG,aAAa,aAAa;AAAM,SACrF,OAAO,iCACf;AACA,IAAa,eAAe,cAAc,aAAa,YAAY;AACnE,IAAa,UAAU,WAAW,WAChC,WACA;CACE,UAAU,CAAC,aAAa,cAAc,aAAa,gBAAgB;CACnE,UAAU,CAAC,mBAAmB,aAAa;CAC3C,aAAa,aAAa;AAC5B,SACM,OAAO,sBACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as AssistantCapabilities from '@dxos/plugin-assistant/AssistantCapabilities';\n\nimport { translations } from '#translations';\nimport { NativeCapabilities, NativeEvents } from '#types';\n\nexport const NativeSettings = AppCapability.settings(() => import('../settings'), {\n activatesOn: ActivationEvents.Idle,\n provides: [NativeCapabilities.Settings],\n});\n\n// Startup, not `AssistantEvents.Start`: `AiService` snapshots its multi-arity `AiModelResolver`\n// require once during startup, so the sidecar resolver contributed in a later round is invisible to\n// it and every `built-in` model fails to resolve. Activation stays cheap — it builds the manager and\n// a lazy layer; the sidecar process spawns on first use, not here.\nexport const Ollama = Capability.lazyModule(\n 'Ollama',\n {\n requires: [Capabilities.AtomRegistry],\n provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],\n activatesOn: ActivationEvents.Startup,\n },\n () => import('../ollama'),\n);\n\nexport const SpotlightListener = Capability.lazyModule(\n 'SpotlightListener',\n { requires: [Capabilities.OperationInvoker], provides: [], activatesOn: NativeEvents.Start },\n () => import('../spotlight-listener'),\n);\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const Updater = Capability.lazyModule(\n 'Updater',\n {\n requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],\n provides: [NativeCapabilities.UpdateManager],\n activatesOn: NativeEvents.Start,\n },\n () => import('../updater'),\n);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;;;;;;AAgBA,IAAa,iBAAiB,cAAc,eAAe,OAAO,yBAAgB;CAChF,aAAa,iBAAiB;CAC9B,UAAU,CAAC,mBAAmB,QAAQ;AACxC,CAAC;AAMD,IAAa,SAAS,WAAW,WAC/B,UACA;CACE,UAAU,CAAC,aAAa,YAAY;CACpC,UAAU,CAAC,gBAAgB,iBAAiB,sBAAsB,aAAa;CAC/E,aAAa,iBAAiB;AAChC,SACM,OAAO,qBACf;AAEA,IAAa,oBAAoB,WAAW,WAC1C,qBACA;CAAE,UAAU,CAAC,aAAa,gBAAgB;CAAG,UAAU,CAAC;CAAG,aAAa,aAAa;AAAM,SACrF,OAAO,iCACf;AAEA,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,UAAU,WAAW,WAChC,WACA;CACE,UAAU,CAAC,aAAa,cAAc,aAAa,gBAAgB;CACnE,UAAU,CAAC,mBAAmB,aAAa;CAC3C,aAAa,aAAa;AAC5B,SACM,OAAO,sBACf;AAEA,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA"}
1
+ {"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as AssistantCapabilities from '@dxos/plugin-assistant/AssistantCapabilities';\n\nimport { translations } from '#translations';\nimport { NativeCapabilities, NativeEvents } from '#types';\n\nexport const NativeSettings = AppCapability.settings(() => import('../settings.ts'), {\n activatesOn: ActivationEvents.Idle,\n provides: [NativeCapabilities.Settings],\n});\n\n// Startup, not `AssistantEvents.Start`: `AiService` snapshots its multi-arity `AiModelResolver`\n// require once during startup, so the sidecar resolver contributed in a later round is invisible to\n// it and every `built-in` model fails to resolve. Activation stays cheap — it builds the manager and\n// a lazy layer; the sidecar process spawns on first use, not here.\nexport const Ollama = Capability.lazyModule(\n 'Ollama',\n {\n requires: [Capabilities.AtomRegistry],\n provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],\n activatesOn: ActivationEvents.Startup,\n },\n () => import('../ollama.ts'),\n);\n\nexport const SpotlightListener = Capability.lazyModule(\n 'SpotlightListener',\n { requires: [Capabilities.OperationInvoker], provides: [], activatesOn: NativeEvents.Start },\n () => import('../spotlight-listener.ts'),\n);\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const Updater = Capability.lazyModule(\n 'Updater',\n {\n requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],\n provides: [NativeCapabilities.UpdateManager],\n activatesOn: NativeEvents.Start,\n },\n () => import('../updater.ts'),\n);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;;;;;;AAgBA,IAAa,iBAAiB,cAAc,eAAe,OAAO,yBAAmB;CACnF,aAAa,iBAAiB;CAC9B,UAAU,CAAC,mBAAmB,QAAQ;AACxC,CAAC;AAMD,IAAa,SAAS,WAAW,WAC/B,UACA;CACE,UAAU,CAAC,aAAa,YAAY;CACpC,UAAU,CAAC,gBAAgB,iBAAiB,sBAAsB,aAAa;CAC/E,aAAa,iBAAiB;AAChC,SACM,OAAO,qBACf;AAEA,IAAa,oBAAoB,WAAW,WAC1C,qBACA;CAAE,UAAU,CAAC,aAAa,gBAAgB;CAAG,UAAU,CAAC;CAAG,aAAa,aAAa;AAAM,SACrF,OAAO,iCACf;AAEA,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,UAAU,WAAW,WAChC,WACA;CACE,UAAU,CAAC,aAAa,cAAc,aAAa,gBAAgB;CACnE,UAAU,CAAC,mBAAmB,aAAa;CAC3C,aAAa,aAAa;AAC5B,SACM,OAAO,sBACf;AAEA,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA"}
@@ -0,0 +1,42 @@
1
+ import { t as PLUGIN_default } from "./chunk-PLUGIN.mjs";
2
+ import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
3
+ import * as Capabilities from "@dxos/app-framework/Capabilities";
4
+ import * as Capability from "@dxos/app-framework/Capability";
5
+ import * as AppCapabilities from "@dxos/app-toolkit/AppCapabilities";
6
+ import * as AppCapability from "@dxos/app-toolkit/AppCapability";
7
+ import * as AssistantCapabilities from "@dxos/plugin-assistant/AssistantCapabilities";
8
+ import { translations } from "#translations";
9
+ import { NativeCapabilities, NativeEvents } from "#types";
10
+ import { meta } from "#meta";
11
+ //#region src/capabilities/gen/tauri.ts
12
+ var NativeSettings = AppCapability.settings(() => import("./chunk-settings.mjs"), {
13
+ activatesOn: ActivationEvents.Idle,
14
+ provides: [NativeCapabilities.Settings]
15
+ });
16
+ var Ollama = Capability.lazyModule("Ollama", {
17
+ requires: [Capabilities.AtomRegistry],
18
+ provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],
19
+ activatesOn: ActivationEvents.Startup
20
+ }, () => import("./chunk-ollama.mjs"));
21
+ var PluginAsset = AppCapability.pluginAsset({
22
+ pluginId: meta.profile.key,
23
+ path: "PLUGIN.mdl",
24
+ content: PLUGIN_default,
25
+ mimeType: "application/x-mdl"
26
+ });
27
+ var ReactSurface = AppCapability.surface(() => import("./chunk-react-surface.mjs"), { roles: ["org.dxos.role.article"] });
28
+ var SpotlightListener = Capability.lazyModule("SpotlightListener", {
29
+ requires: [Capabilities.OperationInvoker],
30
+ provides: [],
31
+ activatesOn: NativeEvents.Start
32
+ }, () => import("./chunk-spotlight-listener.mjs"));
33
+ var Translations = AppCapability.translations(translations);
34
+ var Updater = Capability.lazyModule("Updater", {
35
+ requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],
36
+ provides: [NativeCapabilities.UpdateManager],
37
+ activatesOn: NativeEvents.Start
38
+ }, () => import("./chunk-updater.mjs"));
39
+ //#endregion
40
+ export { NativeSettings, Ollama, PluginAsset, ReactSurface, SpotlightListener, Translations, Updater };
41
+
42
+ //# sourceMappingURL=capabilities.tauri.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.tauri.mjs","names":[],"sources":["../../src/capabilities/gen/tauri.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'tauri' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as AssistantCapabilities from '@dxos/plugin-assistant/AssistantCapabilities';\n\nimport { meta } from '#meta';\nimport { translations } from '#translations';\nimport { NativeCapabilities, NativeEvents } from '#types';\n\nimport pluginSpec from '../../../PLUGIN.mdl?raw';\n\nexport const NativeSettings = AppCapability.settings(() => import('../settings.ts'), {\n activatesOn: ActivationEvents.Idle,\n provides: [NativeCapabilities.Settings],\n});\n\n// Startup, not `AssistantEvents.Start`: `AiService` snapshots its multi-arity `AiModelResolver`\n// require once during startup, so the sidecar resolver contributed in a later round is invisible to\n// it and every `built-in` model fails to resolve. Activation stays cheap — it builds the manager and\n// a lazy layer; the sidecar process spawns on first use, not here.\nexport const Ollama = Capability.lazyModule(\n 'Ollama',\n {\n requires: [Capabilities.AtomRegistry],\n provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],\n activatesOn: ActivationEvents.Startup,\n },\n () => import('../ollama.ts'),\n);\n\nexport const PluginAsset = AppCapability.pluginAsset({\n pluginId: meta.profile.key,\n path: 'PLUGIN.mdl',\n content: pluginSpec,\n mimeType: 'application/x-mdl',\n});\n\nexport const ReactSurface = AppCapability.surface(() => import('../react-surface.ts'), {\n roles: ['org.dxos.role.article'],\n});\n\nexport const SpotlightListener = Capability.lazyModule(\n 'SpotlightListener',\n { requires: [Capabilities.OperationInvoker], provides: [], activatesOn: NativeEvents.Start },\n () => import('../spotlight-listener.ts'),\n);\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const Updater = Capability.lazyModule(\n 'Updater',\n {\n requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],\n provides: [NativeCapabilities.UpdateManager],\n activatesOn: NativeEvents.Start,\n },\n () => import('../updater.ts'),\n);\n"],"mappings":";;;;;;;;;;;AAmBA,IAAa,iBAAiB,cAAc,eAAe,OAAO,yBAAmB;CACnF,aAAa,iBAAiB;CAC9B,UAAU,CAAC,mBAAmB,QAAQ;AACxC,CAAC;AAMD,IAAa,SAAS,WAAW,WAC/B,UACA;CACE,UAAU,CAAC,aAAa,YAAY;CACpC,UAAU,CAAC,gBAAgB,iBAAiB,sBAAsB,aAAa;CAC/E,aAAa,iBAAiB;AAChC,SACM,OAAO,qBACf;AAEA,IAAa,cAAc,cAAc,YAAY;CACnD,UAAU,KAAK,QAAQ;CACvB,MAAM;CACN,SAAS;CACT,UAAU;AACZ,CAAC;AAED,IAAa,eAAe,cAAc,cAAc,OAAO,8BAAwB,EACrF,OAAO,CAAC,uBAAuB,EACjC,CAAC;AAED,IAAa,oBAAoB,WAAW,WAC1C,qBACA;CAAE,UAAU,CAAC,aAAa,gBAAgB;CAAG,UAAU,CAAC;CAAG,aAAa,aAAa;AAAM,SACrF,OAAO,iCACf;AAEA,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,UAAU,WAAW,WAChC,WACA;CACE,UAAU,CAAC,aAAa,cAAc,aAAa,gBAAgB;CACnE,UAAU,CAAC,mBAAmB,aAAa;CAC3C,aAAa,aAAa;AAC5B,SACM,OAAO,sBACf"}
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.workerd.mjs","names":[],"sources":["../../src/capabilities/gen/workerd.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capabilities from '@dxos/app-framework/Capabilities';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as AssistantCapabilities from '@dxos/plugin-assistant/AssistantCapabilities';\n\nimport { translations } from '#translations';\nimport { NativeCapabilities, NativeEvents } from '#types';\n\nexport const NativeSettings = AppCapability.settings(() => import('../settings'), {\n activatesOn: ActivationEvents.Idle,\n provides: [NativeCapabilities.Settings],\n});\n\n// Startup, not `AssistantEvents.Start`: `AiService` snapshots its multi-arity `AiModelResolver`\n// require once during startup, so the sidecar resolver contributed in a later round is invisible to\n// it and every `built-in` model fails to resolve. Activation stays cheap — it builds the manager and\n// a lazy layer; the sidecar process spawns on first use, not here.\nexport const Ollama = Capability.lazyModule(\n 'Ollama',\n {\n requires: [Capabilities.AtomRegistry],\n provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],\n activatesOn: ActivationEvents.Startup,\n },\n () => import('../ollama'),\n);\n\nexport const SpotlightListener = Capability.lazyModule(\n 'SpotlightListener',\n { requires: [Capabilities.OperationInvoker], provides: [], activatesOn: NativeEvents.Start },\n () => import('../spotlight-listener'),\n);\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const Updater = Capability.lazyModule(\n 'Updater',\n {\n requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],\n provides: [NativeCapabilities.UpdateManager],\n activatesOn: NativeEvents.Start,\n },\n () => import('../updater'),\n);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;;;;;;AAgBA,IAAa,iBAAiB,cAAc,eAAe,OAAO,yBAAgB;CAChF,aAAa,iBAAiB;CAC9B,UAAU,CAAC,mBAAmB,QAAQ;AACxC,CAAC;AAMD,IAAa,SAAS,WAAW,WAC/B,UACA;CACE,UAAU,CAAC,aAAa,YAAY;CACpC,UAAU,CAAC,gBAAgB,iBAAiB,sBAAsB,aAAa;CAC/E,aAAa,iBAAiB;AAChC,SACM,OAAO,qBACf;AAEA,IAAa,oBAAoB,WAAW,WAC1C,qBACA;CAAE,UAAU,CAAC,aAAa,gBAAgB;CAAG,UAAU,CAAC;CAAG,aAAa,aAAa;AAAM,SACrF,OAAO,iCACf;AAEA,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,UAAU,WAAW,WAChC,WACA;CACE,UAAU,CAAC,aAAa,cAAc,aAAa,gBAAgB;CACnE,UAAU,CAAC,mBAAmB,aAAa;CAC3C,aAAa,aAAa;AAC5B,SACM,OAAO,sBACf;AAEA,IAAa,cAAc,KAAA;AAC3B,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 * 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 AppCapabilities from '@dxos/app-toolkit/AppCapabilities';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as AssistantCapabilities from '@dxos/plugin-assistant/AssistantCapabilities';\n\nimport { translations } from '#translations';\nimport { NativeCapabilities, NativeEvents } from '#types';\n\nexport const NativeSettings = AppCapability.settings(() => import('../settings.ts'), {\n activatesOn: ActivationEvents.Idle,\n provides: [NativeCapabilities.Settings],\n});\n\n// Startup, not `AssistantEvents.Start`: `AiService` snapshots its multi-arity `AiModelResolver`\n// require once during startup, so the sidecar resolver contributed in a later round is invisible to\n// it and every `built-in` model fails to resolve. Activation stays cheap — it builds the manager and\n// a lazy layer; the sidecar process spawns on first use, not here.\nexport const Ollama = Capability.lazyModule(\n 'Ollama',\n {\n requires: [Capabilities.AtomRegistry],\n provides: [AppCapabilities.AiModelResolver, AssistantCapabilities.OllamaManager],\n activatesOn: ActivationEvents.Startup,\n },\n () => import('../ollama.ts'),\n);\n\nexport const SpotlightListener = Capability.lazyModule(\n 'SpotlightListener',\n { requires: [Capabilities.OperationInvoker], provides: [], activatesOn: NativeEvents.Start },\n () => import('../spotlight-listener.ts'),\n);\n\nexport const Translations = AppCapability.translations(translations);\n\nexport const Updater = Capability.lazyModule(\n 'Updater',\n {\n requires: [Capabilities.AtomRegistry, Capabilities.OperationInvoker],\n provides: [NativeCapabilities.UpdateManager],\n activatesOn: NativeEvents.Start,\n },\n () => import('../updater.ts'),\n);\n\nexport const PluginAsset = undefined;\nexport const ReactSurface = undefined;\n"],"mappings":";;;;;;;;;AAgBA,IAAa,iBAAiB,cAAc,eAAe,OAAO,yBAAmB;CACnF,aAAa,iBAAiB;CAC9B,UAAU,CAAC,mBAAmB,QAAQ;AACxC,CAAC;AAMD,IAAa,SAAS,WAAW,WAC/B,UACA;CACE,UAAU,CAAC,aAAa,YAAY;CACpC,UAAU,CAAC,gBAAgB,iBAAiB,sBAAsB,aAAa;CAC/E,aAAa,iBAAiB;AAChC,SACM,OAAO,qBACf;AAEA,IAAa,oBAAoB,WAAW,WAC1C,qBACA;CAAE,UAAU,CAAC,aAAa,gBAAgB;CAAG,UAAU,CAAC;CAAG,aAAa,aAAa;AAAM,SACrF,OAAO,iCACf;AAEA,IAAa,eAAe,cAAc,aAAa,YAAY;AAEnE,IAAa,UAAU,WAAW,WAChC,WACA;CACE,UAAU,CAAC,aAAa,cAAc,aAAa,gBAAgB;CACnE,UAAU,CAAC,mBAAmB,aAAa;CAC3C,aAAa,aAAa;AAC5B,SACM,OAAO,sBACf;AAEA,IAAa,cAAc,KAAA;AAC3B,IAAa,eAAe,KAAA"}
@@ -1,33 +1,21 @@
1
1
  import { NativeCapabilities } from "#types";
2
2
  import { meta } from "#meta";
3
- import { useState } from "react";
3
+ import "react";
4
4
  import * as Schema from "effect/Schema";
5
- import { useCapability } from "@dxos/app-framework/ui";
6
- import * as Match from "effect/Match";
7
- import { useAtomValue } from "@effect/atom-react/Hooks";
8
- import { formatDistanceToNow } from "date-fns/formatDistanceToNow";
9
- import { Button, useTranslation } from "@dxos/react-ui";
5
+ import * as Hooks from "@dxos/app-framework/Hooks";
6
+ import * as ToolkitHooks from "@dxos/app-toolkit/Hooks";
7
+ import * as SettingsScope from "@dxos/app-toolkit/SettingsScope";
10
8
  import { Form } from "@dxos/react-ui-form";
9
+ import * as UiHooks from "@dxos/react-ui/Hooks";
11
10
  import { jsx } from "react/jsx-runtime";
12
11
  //#region src/containers/NativeSettings/NativeSettings.tsx
13
12
  /** Update status comes from the update-manager capability, so this panel takes no settings props. */
14
13
  var NativeSettings = () => {
15
- const { t } = useTranslation(meta.profile.key);
16
- const manager = useCapability(NativeCapabilities.UpdateManager);
17
- const status = useAtomValue(manager.status);
18
- const [pending, setPending] = useState(null);
19
- const runAction = (kind, action) => async () => {
20
- setPending(kind);
21
- try {
22
- await action();
23
- } finally {
24
- setPending(null);
25
- }
26
- };
27
- const { description, button } = renderUpdateRow(status, pending, t, {
28
- onCheck: runAction("check", manager.check),
29
- onInstall: runAction("install", manager.install),
30
- onRelaunch: runAction("relaunch", manager.relaunch)
14
+ const { t } = UiHooks.useTranslation(meta.profile.key);
15
+ const manager = Hooks.useCapability(NativeCapabilities.UpdateManager);
16
+ const { description, button } = ToolkitHooks.useUpdateRow({
17
+ manager,
18
+ t
31
19
  });
32
20
  return /* @__PURE__ */ jsx(Form.Root, {
33
21
  schema: Schema.Struct({}),
@@ -35,9 +23,11 @@ var NativeSettings = () => {
35
23
  variant: "settings",
36
24
  children: /* @__PURE__ */ jsx(Form.Viewport, {
37
25
  scroll: true,
38
- children: /* @__PURE__ */ jsx(Form.Content, { children: /* @__PURE__ */ jsx(Form.Section, {
39
- title: meta.profile.name ?? meta.profile.key,
40
- children: /* @__PURE__ */ jsx(Form.Row, {
26
+ children: /* @__PURE__ */ jsx(Form.Content, { children: /* @__PURE__ */ jsx(Form.FieldSet, {
27
+ label: meta.profile.name ?? meta.profile.key,
28
+ actions: /* @__PURE__ */ jsx(SettingsScope.Root, { prefix: meta.profile.key }),
29
+ children: /* @__PURE__ */ jsx(Form.Field, {
30
+ standalone: true,
41
31
  label: t("settings.updates.label"),
42
32
  description,
43
33
  children: button
@@ -46,58 +36,6 @@ var NativeSettings = () => {
46
36
  })
47
37
  });
48
38
  };
49
- var renderUpdateRow = (status, pending, t, { onCheck, onInstall, onRelaunch }) => {
50
- const isChecking = pending === "check" || status.kind === "checking";
51
- const isInstalling = pending === "install" || status.kind === "downloading";
52
- const checkButton = (disabled = false) => /* @__PURE__ */ jsx(Button, {
53
- disabled: disabled || isChecking || isInstalling || pending === "relaunch",
54
- onClick: () => void onCheck(),
55
- children: isChecking ? t("settings.updates.checking.label") : t("settings.updates.check.label")
56
- });
57
- return Match.value(status).pipe(Match.withReturnType(), Match.when({ kind: "unsupported" }, () => ({
58
- description: t("settings.updates.unsupported.message"),
59
- button: checkButton(true)
60
- })), Match.when({ kind: "dev" }, () => ({
61
- description: t("settings.updates.dev.message"),
62
- button: checkButton(true)
63
- })), Match.when({ kind: "idle" }, () => ({
64
- description: isChecking ? t("settings.updates.checking.message") : t("settings.updates.idle.message"),
65
- button: checkButton()
66
- })), Match.when({ kind: "checking" }, () => ({
67
- description: t("settings.updates.checking.message"),
68
- button: checkButton()
69
- })), Match.when({ kind: "up-to-date" }, (s) => ({
70
- description: isChecking ? t("settings.updates.checking.message") : t("settings.updates.up-to-date.message", { checkedAt: formatDistanceToNow(new Date(s.checkedAt), { addSuffix: true }) }),
71
- button: checkButton()
72
- })), Match.when({ kind: "available" }, (s) => ({
73
- description: t("settings.updates.available.message", { version: s.version }),
74
- button: /* @__PURE__ */ jsx(Button, {
75
- variant: "primary",
76
- disabled: isInstalling,
77
- onClick: () => void onInstall(),
78
- children: isInstalling ? t("settings.updates.downloading.label") : t("settings.updates.update-now.label")
79
- })
80
- })), Match.when({ kind: "downloading" }, (s) => {
81
- return {
82
- description: t("settings.updates.downloading.message", { percent: s.contentLength > 0 ? Math.round(s.downloaded / s.contentLength * 100) : 0 }),
83
- button: /* @__PURE__ */ jsx(Button, {
84
- disabled: true,
85
- children: t("settings.updates.downloading.label")
86
- })
87
- };
88
- }), Match.when({ kind: "ready" }, () => ({
89
- description: t("settings.updates.ready.message"),
90
- button: /* @__PURE__ */ jsx(Button, {
91
- variant: "primary",
92
- disabled: pending === "relaunch",
93
- onClick: () => void onRelaunch(),
94
- children: t("settings.updates.relaunch.label")
95
- })
96
- })), Match.when({ kind: "failed" }, (s) => ({
97
- description: t("settings.updates.failed.message", { error: s.error }),
98
- button: checkButton()
99
- })), Match.exhaustive);
100
- };
101
39
  NativeSettings.displayName = "NativeSettings";
102
40
  //#endregion
103
41
  export { NativeSettings as default };
@@ -1 +1 @@
1
- {"version":3,"file":"chunk-NativeSettings.mjs","names":[],"sources":["../../src/containers/NativeSettings/NativeSettings.tsx"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport { formatDistanceToNow } from 'date-fns/formatDistanceToNow';\nimport * as Match from 'effect/Match';\nimport * as Schema from 'effect/Schema';\nimport React, { type ReactNode, useState } from 'react';\n\nimport { useCapability } from '@dxos/app-framework/ui';\nimport { type AppSurface } from '@dxos/app-toolkit/ui';\nimport { Button, useTranslation } from '@dxos/react-ui';\nimport { Form } from '@dxos/react-ui-form';\n\nimport { meta } from '#meta';\nimport { NativeCapabilities, Settings, Update } from '#types';\n\nexport type NativeSettingsProps = AppSurface.SettingsProps<Settings.Settings>;\n\ntype Pending = null | 'check' | 'install' | 'relaunch';\n\ntype UpdateActions = {\n onCheck: () => Promise<void>;\n onInstall: () => Promise<void>;\n onRelaunch: () => Promise<void>;\n};\n\ntype UpdateRow = {\n description: string;\n button: ReactNode;\n};\n\n/** Update status comes from the update-manager capability, so this panel takes no settings props. */\nexport const NativeSettings = () => {\n const { t } = useTranslation(meta.profile.key);\n const manager = useCapability(NativeCapabilities.UpdateManager);\n const status = useAtomValue(manager.status);\n\n // UI-level pending flag. The status atom can flip between `checking` and `up-to-date` faster\n // than the user can perceive, so we also gate the button on the click handler's lifetime to\n // guarantee no duplicate triggers and a visible busy state.\n const [pending, setPending] = useState<Pending>(null);\n\n const runAction = (kind: Exclude<Pending, null>, action: () => Promise<void>) => async () => {\n setPending(kind);\n try {\n await action();\n } finally {\n setPending(null);\n }\n };\n\n const { description, button } = renderUpdateRow(status, pending, t, {\n onCheck: runAction('check', manager.check),\n onInstall: runAction('install', manager.install),\n onRelaunch: runAction('relaunch', manager.relaunch),\n });\n\n return (\n <Form.Root schema={Schema.Struct({})} values={{}} variant='settings'>\n <Form.Viewport scroll>\n <Form.Content>\n <Form.Section title={meta.profile.name ?? meta.profile.key}>\n <Form.Row label={t('settings.updates.label')} description={description}>\n {button}\n </Form.Row>\n </Form.Section>\n </Form.Content>\n </Form.Viewport>\n </Form.Root>\n );\n};\n\nconst renderUpdateRow = (\n status: Update.Status,\n pending: Pending,\n t: (key: string, options?: Record<string, unknown>) => string,\n { onCheck, onInstall, onRelaunch }: UpdateActions,\n): UpdateRow => {\n const isChecking = pending === 'check' || status.kind === 'checking';\n const isInstalling = pending === 'install' || status.kind === 'downloading';\n\n const checkButton = (disabled = false) => (\n <Button disabled={disabled || isChecking || isInstalling || pending === 'relaunch'} onClick={() => void onCheck()}>\n {isChecking ? t('settings.updates.checking.label') : t('settings.updates.check.label')}\n </Button>\n );\n\n return Match.value(status).pipe(\n Match.withReturnType<UpdateRow>(),\n Match.when({ kind: 'unsupported' }, () => ({\n description: t('settings.updates.unsupported.message'),\n button: checkButton(true),\n })),\n Match.when({ kind: 'dev' }, () => ({\n description: t('settings.updates.dev.message'),\n button: checkButton(true),\n })),\n Match.when({ kind: 'idle' }, () => ({\n description: isChecking ? t('settings.updates.checking.message') : t('settings.updates.idle.message'),\n button: checkButton(),\n })),\n Match.when({ kind: 'checking' }, () => ({\n description: t('settings.updates.checking.message'),\n button: checkButton(),\n })),\n Match.when({ kind: 'up-to-date' }, (s) => ({\n description: isChecking\n ? t('settings.updates.checking.message')\n : t('settings.updates.up-to-date.message', {\n checkedAt: formatDistanceToNow(new Date(s.checkedAt), { addSuffix: true }),\n }),\n button: checkButton(),\n })),\n Match.when({ kind: 'available' }, (s) => ({\n description: t('settings.updates.available.message', { version: s.version }),\n button: (\n <Button variant='primary' disabled={isInstalling} onClick={() => void onInstall()}>\n {isInstalling ? t('settings.updates.downloading.label') : t('settings.updates.update-now.label')}\n </Button>\n ),\n })),\n Match.when({ kind: 'downloading' }, (s) => {\n const percent = s.contentLength > 0 ? Math.round((s.downloaded / s.contentLength) * 100) : 0;\n return {\n description: t('settings.updates.downloading.message', { percent }),\n button: <Button disabled>{t('settings.updates.downloading.label')}</Button>,\n };\n }),\n Match.when({ kind: 'ready' }, () => ({\n description: t('settings.updates.ready.message'),\n button: (\n <Button variant='primary' disabled={pending === 'relaunch'} onClick={() => void onRelaunch()}>\n {t('settings.updates.relaunch.label')}\n </Button>\n ),\n })),\n Match.when({ kind: 'failed' }, (s) => ({\n description: t('settings.updates.failed.message', { error: s.error }),\n button: checkButton(),\n })),\n Match.exhaustive,\n );\n};\n\nNativeSettings.displayName = 'NativeSettings';\n"],"mappings":";;;;;;;;;;;;;AAkCA,IAAa,uBAAuB;CAClC,MAAM,EAAE,MAAM,eAAe,KAAK,QAAQ,GAAG;CAC7C,MAAM,UAAU,cAAc,mBAAmB,aAAa;CAC9D,MAAM,SAAS,aAAa,QAAQ,MAAM;CAK1C,MAAM,CAAC,SAAS,cAAc,SAAkB,IAAI;CAEpD,MAAM,aAAa,MAA8B,WAAgC,YAAY;EAC3F,WAAW,IAAI;EACf,IAAI;GACF,MAAM,OAAO;EACf,UAAU;GACR,WAAW,IAAI;EACjB;CACF;CAEA,MAAM,EAAE,aAAa,WAAW,gBAAgB,QAAQ,SAAS,GAAG;EAClE,SAAS,UAAU,SAAS,QAAQ,KAAK;EACzC,WAAW,UAAU,WAAW,QAAQ,OAAO;EAC/C,YAAY,UAAU,YAAY,QAAQ,QAAQ;CACpD,CAAC;CAED,OACE,oBAAC,KAAK,MAAN;EAAW,QAAQ,OAAO,OAAO,CAAC,CAAC;EAAG,QAAQ,CAAC;EAAG,SAAQ;EACxD,UAAA,oBAAC,KAAK,UAAN;GAAe,QAAA;GACb,UAAA,oBAAC,KAAK,SAAN,EAAA,UACE,oBAAC,KAAK,SAAN;IAAc,OAAO,KAAK,QAAQ,QAAQ,KAAK,QAAQ;IACrD,UAAA,oBAAC,KAAK,KAAN;KAAU,OAAO,EAAE,wBAAwB;KAAgB;KACxD,UAAA;IACO,CAAA;GACE,CAAA,EACF,CAAA;EACD,CAAA;CACN,CAAA;AAEf;AAEA,IAAM,mBACJ,QACA,SACA,GACA,EAAE,SAAS,WAAW,iBACR;CACd,MAAM,aAAa,YAAY,WAAW,OAAO,SAAS;CAC1D,MAAM,eAAe,YAAY,aAAa,OAAO,SAAS;CAE9D,MAAM,eAAe,WAAW,UAC9B,oBAAC,QAAD;EAAQ,UAAU,YAAY,cAAc,gBAAgB,YAAY;EAAY,eAAe,KAAK,QAAQ;EAC7G,UAAA,aAAa,EAAE,iCAAiC,IAAI,EAAE,8BAA8B;CAC/E,CAAA;CAGV,OAAO,MAAM,MAAM,MAAM,CAAC,CAAC,KACzB,MAAM,eAA0B,GAChC,MAAM,KAAK,EAAE,MAAM,cAAc,UAAU;EACzC,aAAa,EAAE,sCAAsC;EACrD,QAAQ,YAAY,IAAI;CAC1B,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,MAAM,UAAU;EACjC,aAAa,EAAE,8BAA8B;EAC7C,QAAQ,YAAY,IAAI;CAC1B,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,OAAO,UAAU;EAClC,aAAa,aAAa,EAAE,mCAAmC,IAAI,EAAE,+BAA+B;EACpG,QAAQ,YAAY;CACtB,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,WAAW,UAAU;EACtC,aAAa,EAAE,mCAAmC;EAClD,QAAQ,YAAY;CACtB,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,aAAa,IAAI,OAAO;EACzC,aAAa,aACT,EAAE,mCAAmC,IACrC,EAAE,uCAAuC,EACvC,WAAW,oBAAoB,IAAI,KAAK,EAAE,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC,EAC3E,CAAC;EACL,QAAQ,YAAY;CACtB,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,YAAY,IAAI,OAAO;EACxC,aAAa,EAAE,sCAAsC,EAAE,SAAS,EAAE,QAAQ,CAAC;EAC3E,QACE,oBAAC,QAAD;GAAQ,SAAQ;GAAU,UAAU;GAAc,eAAe,KAAK,UAAU;GAC7E,UAAA,eAAe,EAAE,oCAAoC,IAAI,EAAE,mCAAmC;EACzF,CAAA;CAEZ,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,cAAc,IAAI,MAAM;EAEzC,OAAO;GACL,aAAa,EAAE,wCAAwC,EAAE,SAF3C,EAAE,gBAAgB,IAAI,KAAK,MAAO,EAAE,aAAa,EAAE,gBAAiB,GAAG,IAAI,EAExB,CAAC;GAClE,QAAQ,oBAAC,QAAD;IAAQ,UAAA;IAAU,UAAA,EAAE,oCAAoC;GAAU,CAAA;EAC5E;CACF,CAAC,GACD,MAAM,KAAK,EAAE,MAAM,QAAQ,UAAU;EACnC,aAAa,EAAE,gCAAgC;EAC/C,QACE,oBAAC,QAAD;GAAQ,SAAQ;GAAU,UAAU,YAAY;GAAY,eAAe,KAAK,WAAW;GACxF,UAAA,EAAE,iCAAiC;EAC9B,CAAA;CAEZ,EAAE,GACF,MAAM,KAAK,EAAE,MAAM,SAAS,IAAI,OAAO;EACrC,aAAa,EAAE,mCAAmC,EAAE,OAAO,EAAE,MAAM,CAAC;EACpE,QAAQ,YAAY;CACtB,EAAE,GACF,MAAM,UACR;AACF;AAEA,eAAe,cAAc"}
1
+ {"version":3,"file":"chunk-NativeSettings.mjs","names":[],"sources":["../../src/containers/NativeSettings/NativeSettings.tsx"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\nimport React from 'react';\n\nimport * as Hooks from '@dxos/app-framework/Hooks';\nimport type * as AppSurface from '@dxos/app-toolkit/AppSurface';\nimport * as ToolkitHooks from '@dxos/app-toolkit/Hooks';\nimport * as SettingsScope from '@dxos/app-toolkit/SettingsScope';\nimport { Form } from '@dxos/react-ui-form';\nimport * as UiHooks from '@dxos/react-ui/Hooks';\n\nimport { meta } from '#meta';\nimport { NativeCapabilities, Settings } from '#types';\n\nexport type NativeSettingsProps = AppSurface.SettingsProps<Settings.Settings>;\n\n/** Update status comes from the update-manager capability, so this panel takes no settings props. */\nexport const NativeSettings = () => {\n const { t } = UiHooks.useTranslation(meta.profile.key);\n const manager = Hooks.useCapability(NativeCapabilities.UpdateManager);\n const { description, button } = ToolkitHooks.useUpdateRow({ manager, t });\n\n return (\n <Form.Root schema={Schema.Struct({})} values={{}} variant='settings'>\n <Form.Viewport scroll>\n <Form.Content>\n <Form.FieldSet\n label={meta.profile.name ?? meta.profile.key}\n actions={<SettingsScope.Root prefix={meta.profile.key} />}\n >\n <Form.Field standalone label={t('settings.updates.label')} description={description}>\n {button}\n </Form.Field>\n </Form.FieldSet>\n </Form.Content>\n </Form.Viewport>\n </Form.Root>\n );\n};\n\nNativeSettings.displayName = 'NativeSettings';\n"],"mappings":";;;;;;;;;;;;AAoBA,IAAa,uBAAuB;CAClC,MAAM,EAAE,MAAM,QAAQ,eAAe,KAAK,QAAQ,GAAG;CACrD,MAAM,UAAU,MAAM,cAAc,mBAAmB,aAAa;CACpE,MAAM,EAAE,aAAa,WAAW,aAAa,aAAa;EAAE;EAAS;CAAE,CAAC;CAExE,OACE,oBAAC,KAAK,MAAN;EAAW,QAAQ,OAAO,OAAO,CAAC,CAAC;EAAG,QAAQ,CAAC;EAAG,SAAQ;EACxD,UAAA,oBAAC,KAAK,UAAN;GAAe,QAAA;GACb,UAAA,oBAAC,KAAK,SAAN,EAAA,UACE,oBAAC,KAAK,UAAN;IACE,OAAO,KAAK,QAAQ,QAAQ,KAAK,QAAQ;IACzC,SAAS,oBAAC,cAAc,MAAf,EAAoB,QAAQ,KAAK,QAAQ,IAAM,CAAA;IAExD,UAAA,oBAAC,KAAK,OAAN;KAAY,YAAA;KAAW,OAAO,EAAE,wBAAwB;KAAgB;KACrE,UAAA;IACS,CAAA;GACC,CAAA,EACH,CAAA;EACD,CAAA;CACN,CAAA;AAEf;AAEA,eAAe,cAAc"}
@@ -0,0 +1,6 @@
1
+ //#region PLUGIN.mdl?raw
2
+ var PLUGIN_default = "---\nid: org.dxos.plugin.native\nname: NativePlugin\nversion: 0.1.0\n---\n\nA Tauri-based native platform integration plugin for DXOS Composer that enables desktop-specific\ncapabilities on macOS, Linux, and Windows. It manages Spotlight window integration, over-the-air\napplication updates, and an Ollama sidecar process for local AI model inference.\n\n## Extensions\n\nThe following extension dialects are used in this document.\nEach extension is defined in the Appendix or resolved via its URI.\n\n| Term | URI |\n|-------------|--------------------------------|\n| `type` | `org.dxos.mdl.type@1.0` |\n| `feat` | `org.dxos.mdl.feat@1.0` |\n| `scenario` | `org.dxos.mdl.scenario@1.0` |\n| `component` | `org.dxos.mdl.component@1.0` |\n| `op` | `org.dxos.mdl.op@1.0` |\n| `test` | `org.dxos.mdl.test@1.0` |\n| `step` | `org.dxos.mdl.step@1.0` |\n\n## Types\n\n```mdl\ntype Settings\n fields:\n # No user-visible settings fields yet; reserved for future configuration.\n```\n\n```mdl\ntype UpdateStatus\n literals: unsupported | idle | checking | up-to-date | available | downloading | ready | failed\n```\n\n```mdl\ntype UpdateState\n fields:\n kind: UpdateStatus\n version?: string # set when kind = available\n checkedAt?: number # epoch ms; set when kind = up-to-date\n progress?: { completed: number, total: number, unit: 'bytes' } # set when kind = downloading\n error?: string # set when kind = failed\n```\n\n## Components\n\n```mdl\ncomponent NativeSettings\n desc: |\n Settings panel section rendered inside the global Settings dialog under the\n App (native) plugin entry. Shows the current update status and exposes\n Check / Update Now / Relaunch actions depending on the UpdateState.\n props:\n settings: Settings\n onSettingsChange(patch: Partial<Settings>)\n state:\n pending: null | 'check' | 'install' | 'apply'\n status: UpdateState # derived from AppCapabilities.UpdateManager (shared with plugin-pwa)\n actions:\n checkForUpdate()\n installUpdate()\n relaunchApp()\n layout: |\n ┌─────────────────────────────────────────┐\n │ Updates │\n ├─────────────────────────────────────────┤\n │ [status description] [Check / Update]│\n └─────────────────────────────────────────┘\n```\n\n## Operations\n\n```mdl\nop CheckForUpdate\n desc: |\n Initiates an OTA update check via the Tauri updater plugin.\n Updates the UpdateManager status atom as the check progresses.\n input: void\n output: void\n effects: [http]\n note: No-op on unsupported platforms; guarded by SUPPORTS_OTA list.\n```\n\n```mdl\nop InstallUpdate\n desc: |\n Downloads and installs a pending update, streaming progress events to the\n UpdateManager status atom. Does not relaunch the app automatically.\n input: void\n output: void\n effects: [http, fs]\n note: Only valid when UpdateManager status kind = available.\n```\n\n```mdl\nop RelaunchApp\n desc: |\n Relaunches the Tauri app process to apply the installed update.\n input: void\n output: void\n effects: [process]\n```\n\n## Features\n\n```mdl\nfeat F-1: Spotlight Window Integration\n\n req F-1.1:\n when: the main Composer window receives a spotlight:invoke Tauri event with operation = 'open'\n then: the LayoutOperation.Open intent is dispatched with the payload, decoded against its input schema\n\n req F-1.2:\n when: the main Composer window receives a spotlight:invoke event with operation = 'switch-workspace'\n then: the LayoutOperation.SwitchWorkspace intent is dispatched with the payload, decoded against its input schema\n\n req F-1.3:\n when: a spotlight:invoke event is handled successfully\n then: the main Composer window is shown and brought to focus\n\n req F-1.4:\n when: a spotlight:invoke event carries an unrecognised operation\n then: a warning is logged and no intent is dispatched\n\n req F-1.5:\n when: a spotlight:invoke payload does not decode against the operation's input schema\n then: the error is logged and no intent is dispatched\n```\n\n```mdl\nfeat F-2: Over-the-Air Updates\n\n req F-2.1:\n when: the Updater module activates on a supported platform (macOS, Linux, Windows) in production\n then: a background Effect fiber is started that checks for updates immediately and repeats hourly\n\n req F-2.2:\n when: an update is available and successfully downloaded\n then: a toast notification is shown with a Relaunch action; the status atom transitions to ready\n\n req F-2.3:\n when: the Tauri updater check throws\n then: the status atom transitions to failed with a human-readable error string\n\n req F-2.4:\n when: the app is running in a dev-server build (port not in TAURI_LOCALHOST_PORTS)\n then: the updater is disabled and status remains unsupported\n\n req F-2.5:\n when: the Updater module is torn down\n then: the background update-check fiber is interrupted cleanly\n```\n\n```mdl\nfeat F-3: Ollama Sidecar\n\n req F-3.1:\n when: the AssistantEvents.SetupAiServiceProviders event fires\n then: the Ollama sidecar binary is spawned via Tauri shell on localhost port 21434\n\n req F-3.2:\n when: the Ollama sidecar is running\n then: it is registered as an AiModelResolver under AppCapabilities.AiModelResolver\n\n req F-3.3:\n when: the Ollama capability is torn down\n then: the sidecar process is killed and the managed runtime is disposed\n```\n\n## Acceptance\n\n```mdl\nscenario T-1: Spotlight open dispatches LayoutOperation.Open\n given: Composer is running and SpotlightListener is active\n when: a spotlight:invoke Tauri event arrives with operation = 'open' and payload { subject: ['root/abc/home'], disposition: 'add' }\n then:\n - LayoutOperation.Open is invoked with { subject: ['root/abc/home'], disposition: 'add' }\n - main window is visible and focused\n```\n\n```mdl\nscenario T-2: Unknown spotlight operation is silently dropped\n given: SpotlightListener is active\n when: a spotlight:invoke event arrives with operation = 'foobar'\n then:\n - no intent is dispatched\n - a warning log entry is emitted with the unknown operation name\n```\n\n```mdl\nscenario T-3: Update check transitions status atom\n given: Updater module is active on a supported platform\n when: CheckForUpdate is called\n then:\n - status transitions to checking while the HTTP call is in-flight\n - status transitions to up-to-date if no update is available\n - status transitions to available with a version string if an update exists\n```\n\n```mdl\nscenario T-4: Failed update check transitions to failed status\n given: Updater module is active\n when: the Tauri updater plugin throws an error during check\n then:\n - status transitions to failed\n - status.error contains a human-readable description\n```\n\n```mdl\nscenario T-5: Dev-server build disables updater\n given: the app is served on a port outside TAURI_LOCALHOST_PORTS\n when: the Updater module activates\n then:\n - status is set to unsupported immediately\n - no HTTP update check is performed\n```\n\n---\n\n## QA\n\nExecutable tests. Each step carries a human instruction (`do`) and, where the step maps to an\ninvocable operation, an agent binding (`invoke`). Report failures by test and step number.\n\n```mdl\ntest QA-1: Check for an OTA update\n desc: |\n The plugin contributes no runtime operation — `CheckForUpdate`, `InstallUpdate`, and\n `RelaunchApp` are direct calls into the Tauri updater/shell plugins from native-only code\n (`Updater` module, `SpotlightListener`), not `Operation.make` entries reachable through the\n debug port or any web session. There is also no invocation surface to run this against: the\n agent debug port drives a running Composer web page, and this plugin only activates inside\n the Tauri desktop shell (`isTauri && !isMobile && !isPopover`, see `plugin-defs.core.tsx`) —\n a build this environment cannot launch or attach to. Every step is therefore blocked.\n actors: human\n covers: [F-2.1, F-2.2, T-3]\n status: blocked\n given:\n - a Tauri desktop build of Composer is installed and running (macOS, Linux, or Windows)\n - an OTA update is actually available for the running version\n steps:\n - name: Check for an update\n do: Open Settings → App, and click \"Check for updates\" (or wait for the hourly background check).\n expect: the status line transitions checking → available, showing the new version string\n blocked: |\n No `Operation.make` exists for `CheckForUpdate` — it is a direct Tauri updater plugin\n call from `Updater`'s background fiber, invisible to the agent debug port. It also cannot\n run inside this session at all: the port attaches to a web page, and this feature only\n exists in a Tauri desktop build. A human tester with a real desktop build and a genuine\n pending release is the only way to exercise this.\n - name: Install and relaunch\n do: Click \"Update Now\", wait for the download to finish, then click \"Relaunch\".\n expect: the app downloads the update, shows a \"Relaunch\" toast, and restarts on the new version\n blocked: Same as the previous step — `InstallUpdate`/`RelaunchApp` are native-only and have no operation key.\n after:\n - name: (nothing to undo)\n do: No fixture was created; an update, once installed, cannot be un-installed by this test.\n expect: n/a\n```\n\n---\n\n## Appendix: Extension Definitions\n\nExtension block types used in this document are defined below using\nthe core `ext` primitive — the only construct the base language provides.\n\n```mdl\next type\n uri: org.dxos.mdl.type@1.0\n desc: A named data structure with typed fields and optional literals.\n fields:\n desc?: Prose\n fields?: FieldMap # name[?]: TypeExpr (# inline comment)\n literals?: UnionList # a | b | c\n extends?: TypeRef[]\n```\n\n```mdl\next feat\n uri: org.dxos.mdl.feat@1.0\n desc: A named feature grouping one or more requirements.\n fields:\n desc?: Prose\n req: RequirementList\n nesting: self # feat blocks may contain feat blocks\n```\n\n```mdl\next scenario\n uri: org.dxos.mdl.scenario@1.0\n desc: An acceptance scenario expressed as given / when / then steps.\n fields:\n given?: Step | Step[]\n when?: Step | Step[]\n then: Step | Step[]\n tags?: TagList\n```\n\n```mdl\next component\n uri: org.dxos.mdl.component@1.0\n desc: A UI component with props, internal state, slots, actions, and events.\n fields:\n desc?: Prose\n props?: FieldMap # external inputs (immutable inside component)\n state?: FieldMap # internal reactive state\n slots?: FieldMap # named ReactNode injection points\n actions?: ActionMap # methods the component exposes or handles\n emits?: EventMap # events the component raises to its parent\n layout?: CodeBlock # ASCII sketch of visual structure (non-normative)\n```\n\n```mdl\next op\n uri: org.dxos.mdl.op@1.0\n desc: |\n A named operation with typed inputs, outputs, and declared errors.\n Pure ops have no effects or requires. Effectful ops declare both.\n fields:\n desc?: Prose\n input?: FieldMap # named input parameters\n output?: TypeExpr # return type\n errors?: ErrorMap # name: Prose (when this error occurs)\n effects?: EffectList # echo:read | echo:write | http | fs | ...\n requires?: ServiceList # injected service dependencies\n note?: Prose # implementation guidance (non-normative)\n```\n";
3
+ //#endregion
4
+ export { PLUGIN_default as t };
5
+
6
+ //# sourceMappingURL=chunk-PLUGIN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-PLUGIN.mjs","names":[],"sources":[],"mappings":""}