@dopame/acde-linux-x64 0.0.0-stage → 0.0.10
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.
- package/LICENSE +8 -0
- package/bin/acde +66 -0
- package/bin/acde.cmd +45 -0
- package/bin/acdebin-dbg +4 -0
- package/bin/app/brand/art.mjs +53 -0
- package/bin/app/brand/brand.css +39 -0
- package/bin/app/brand/lockup.mjs +17 -0
- package/bin/app/brand/mark.mjs +124 -0
- package/bin/app/dist/broker.js +1 -0
- package/bin/app/dist/web.js +1 -0
- package/bin/app/greet/index.html +177 -0
- package/bin/app/greet/package.json +16 -0
- package/bin/app/package.json +35 -0
- package/lib/acde/LICENSE +8 -0
- package/lib/acde/dist/chunk-0n69bv5q.js +1 -0
- package/lib/acde/dist/chunk-1cw92x19.js +1 -0
- package/lib/acde/dist/chunk-458e14zb.js +1 -0
- package/lib/acde/dist/chunk-88mxgp54.js +1 -0
- package/lib/acde/dist/chunk-8dv09ven.js +1 -0
- package/lib/acde/dist/chunk-8fxsj5h6.js +1 -0
- package/lib/acde/dist/chunk-8pf3kk8v.js +1 -0
- package/lib/acde/dist/chunk-8r65bz1e.js +1 -0
- package/lib/acde/dist/chunk-9hpnkmxn.js +1 -0
- package/lib/acde/dist/chunk-a7w41xr9.js +1 -0
- package/lib/acde/dist/chunk-db7qqt8a.js +1 -0
- package/lib/acde/dist/chunk-e3rzr5fj.js +1 -0
- package/lib/acde/dist/chunk-ehms6xjp.js +1 -0
- package/lib/acde/dist/chunk-ggykhab6.js +1 -0
- package/lib/acde/dist/chunk-gt70e8h2.js +1 -0
- package/lib/acde/dist/chunk-hcf0xd5c.js +1 -0
- package/lib/acde/dist/chunk-hdrvz9sa.js +1 -0
- package/lib/acde/dist/chunk-jjq2mn94.js +1 -0
- package/lib/acde/dist/chunk-k8f4m94e.js +7 -0
- package/lib/acde/dist/chunk-mtgy1bm0.js +1 -0
- package/lib/acde/dist/chunk-mtw6p7kv.js +1 -0
- package/lib/acde/dist/chunk-nwkq7cpp.js +1 -0
- package/lib/acde/dist/chunk-nyr54266.js +1 -0
- package/lib/acde/dist/chunk-p0h5kspx.js +1 -0
- package/lib/acde/dist/chunk-pdj3h86e.js +1 -0
- package/lib/acde/dist/chunk-q9dbzac5.js +1 -0
- package/lib/acde/dist/chunk-qrhbrjzk.js +1 -0
- package/lib/acde/dist/chunk-s8p0y5ap.js +1 -0
- package/lib/acde/dist/chunk-t0xqxe00.js +1 -0
- package/lib/acde/dist/chunk-tgn5c2mw.js +1 -0
- package/lib/acde/dist/chunk-wmj6zwvn.js +1 -0
- package/lib/acde/dist/chunk-wnk81fkc.js +1 -0
- package/lib/acde/dist/chunk-x208z38w.js +1 -0
- package/lib/acde/dist/chunk-xq76vbg6.js +1 -0
- package/lib/acde/dist/chunk-xr9gh5x2.js +1 -0
- package/lib/acde/dist/chunk-yytnhz6e.js +1 -0
- package/lib/acde/dist/chunk-z0ts25s1.js +1 -0
- package/lib/acde/dist/chunk-zdyw1ckt.js +1 -0
- package/lib/acde/dist/cli.js +1 -0
- package/lib/acde/dist/driver/index.js +1 -0
- package/lib/acde/dist/e2e/index.js +1 -0
- package/lib/acde/dist/types/configs.d.ts +1 -0
- package/lib/acde/dist/types/driver/acde.d.ts +106 -0
- package/lib/acde/dist/types/driver/clock.d.ts +32 -0
- package/lib/acde/dist/types/driver/expect.d.ts +60 -0
- package/lib/acde/dist/types/driver/format.d.ts +16 -0
- package/lib/acde/dist/types/driver/index.d.ts +13 -0
- package/lib/acde/dist/types/driver/input.d.ts +75 -0
- package/lib/acde/dist/types/driver/locator.d.ts +151 -0
- package/lib/acde/dist/types/driver/logs.d.ts +26 -0
- package/lib/acde/dist/types/driver/png.d.ts +31 -0
- package/lib/acde/dist/types/driver/poll.d.ts +4 -0
- package/lib/acde/dist/types/driver/screenshot.d.ts +37 -0
- package/lib/acde/dist/types/driver/trace.d.ts +26 -0
- package/lib/acde/dist/types/driver/types.d.ts +213 -0
- package/lib/acde/dist/types/driver/video.d.ts +14 -0
- package/lib/acde/dist/types/driver/window.d.ts +77 -0
- package/lib/acde/dist/types/e2e/index.d.ts +78 -0
- package/lib/acde/dist/types/e2e/settings.d.ts +39 -0
- package/lib/acde/dist/types/ipc.d.ts +24 -0
- package/lib/acde/dist/types/paths.d.ts +5 -0
- package/lib/acde/dist/types/pm.d.ts +20 -0
- package/lib/acde/dist/types/runtime.d.ts +49 -0
- package/lib/acde/dist/types/sessions.d.ts +80 -0
- package/lib/acde/dist/types/sockets.d.ts +4 -0
- package/lib/acde/launcher.d.mts +25 -0
- package/lib/acde/launcher.mjs +1 -0
- package/lib/acde/package.json +31 -0
- package/lib/acde/skills/acde/SKILL.md +114 -0
- package/lib/acde/skills/acde/references/guide/agents.md +50 -0
- package/lib/acde/skills/acde/references/guide/assets.md +40 -0
- package/lib/acde/skills/acde/references/guide/backend.md +94 -0
- package/lib/acde/skills/acde/references/guide/capabilities.md +157 -0
- package/lib/acde/skills/acde/references/guide/config.md +73 -0
- package/lib/acde/skills/acde/references/guide/desktop.md +165 -0
- package/lib/acde/skills/acde/references/guide/dev.md +66 -0
- package/lib/acde/skills/acde/references/guide/doctor.md +144 -0
- package/lib/acde/skills/acde/references/guide/files.md +181 -0
- package/lib/acde/skills/acde/references/guide/frameworks.md +74 -0
- package/lib/acde/skills/acde/references/guide/install.md +34 -0
- package/lib/acde/skills/acde/references/guide/mcp.md +64 -0
- package/lib/acde/skills/acde/references/guide/open.md +107 -0
- package/lib/acde/skills/acde/references/guide/services.md +147 -0
- package/lib/acde/skills/acde/references/guide/testing.md +378 -0
- package/lib/acde/skills/acde/references/guide/tools.md +291 -0
- package/lib/acde/skills/acde/references/guide/window.md +167 -0
- package/lib/acde/skills/acde/references/reference/cli.md +221 -0
- package/lib/acde/skills/acde/references/reference/config.md +51 -0
- package/lib/acde/skills/acde/references/reference/env.md +44 -0
- package/lib/acde/skills/acde/references/reference/manifest.md +92 -0
- package/lib/acde/skills/acde/references/reference/modules.md +586 -0
- package/lib/acde/skills/acde/references/reference/platforms.md +23 -0
- package/lib/acde/skills/acde/references/reference/service.md +47 -0
- package/lib/acde/skills/acde/references/reference/testing.md +265 -0
- package/lib/acde/skills/acde/references/reference/web.md +94 -0
- package/lib/acde/skills/acde/references/start/first-app.md +87 -0
- package/lib/acde/skills/acde/references/start/install.md +232 -0
- package/lib/acde/skills/acde/references/start/project.md +77 -0
- package/lib/acde/templates/app/acde.config.jsonc +27 -0
- package/lib/acde/templates/app/gitignore +2 -0
- package/lib/acde/templates/app/index.html +22 -0
- package/lib/acde/templates/app/package.json +5 -0
- package/lib/acde/templates/app/src/i18n.js +26 -0
- package/lib/acde/templates/app/src/locales/en.js +4 -0
- package/lib/acde/templates/app/src/locales/zh.js +4 -0
- package/lib/acde/templates/app/src/main.js +5 -0
- package/lib/acde/templates/backend/server.ts +7 -0
- package/lib/acde/templates/backend/src/main.js +6 -0
- package/lib/acde/templates/desktop/acde.config.jsonc +17 -0
- package/lib/acde/templates/desktop/gitignore +2 -0
- package/lib/acde/templates/desktop/index.html +19 -0
- package/lib/acde/templates/desktop/package.json +5 -0
- package/lib/acde/templates/desktop/src/desktop.js +16 -0
- package/lib/acde/templates/desktop/src/i18n.js +26 -0
- package/lib/acde/templates/desktop/src/locales/en.js +4 -0
- package/lib/acde/templates/desktop/src/locales/zh.js +4 -0
- package/lib/acde/templates/framework/acde.config.jsonc +26 -0
- package/lib/acde-api/LICENSE +5 -0
- package/lib/acde-api/config.schema.json +563 -0
- package/lib/acde-api/package.json +51 -0
- package/lib/acde-api/src/app.d.ts +36 -0
- package/lib/acde-api/src/frame.d.ts +15 -0
- package/lib/acde-api/src/frame.js +1 -0
- package/lib/acde-api/src/index.d.ts +11 -0
- package/lib/acde-api/src/index.js +1 -0
- package/lib/acde-api/src/modules/app-modules.d.ts +81 -0
- package/lib/acde-api/src/modules/modules.d.ts +113 -0
- package/lib/acde-api/src/modules/shell-modules.d.ts +32 -0
- package/lib/acde-api/src/runtime/level.d.ts +1 -0
- package/lib/acde-api/src/runtime/level.js +1 -0
- package/lib/acde-api/src/runtime/load.d.ts +8 -0
- package/lib/acde-api/src/runtime/load.js +1 -0
- package/lib/acde-api/src/runtime/places.d.ts +3 -0
- package/lib/acde-api/src/runtime/places.js +1 -0
- package/lib/acde-api/src/runtime/platforms.d.ts +5 -0
- package/lib/acde-api/src/runtime/platforms.js +1 -0
- package/lib/acde-api/src/shell.d.ts +14 -0
- package/lib/acde-api/src/types/capabilities.d.ts +34 -0
- package/lib/acde-api/src/types/config.d.ts +55 -0
- package/lib/acde-api/src/types/events.d.ts +151 -0
- package/lib/acde-api/src/types/manifest.d.ts +83 -0
- package/lib/acde-api/src/types/office.d.ts +118 -0
- package/lib/acde-api/src/types/page.d.ts +1090 -0
- package/lib/acde-api/src/types/permissions.d.ts +50 -0
- package/lib/acde-api/src/types/service.d.ts +35 -0
- package/lib/acde-api/src/validate.d.ts +64 -0
- package/lib/acde-api/src/validate.js +1 -0
- package/lib/acde-api/src/vite.d.ts +3 -0
- package/lib/acde-api/src/vite.js +9 -0
- package/package.json +11 -4
- package/README.md +0 -3
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
# acde: modules
|
|
2
|
+
|
|
3
|
+
Every module has both named exports and a default export:
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
import { fs } from 'acde:fs'
|
|
7
|
+
import fs from 'acde:fs'
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Types are in `@dopame/acde-api`: `@dopame/acde-api/app` declares the modules an app can import, `@dopame/acde-api/shell` adds the shell modules, and the package root declares all of them. For how capabilities are requested and approved, see [Capabilities](../guide/capabilities.md).
|
|
11
|
+
|
|
12
|
+
Who can import what. "App" is an app of its own package; a "system app" ships in a desktop's package (the `apps` of a desktop config). A name in a cell is the capability the app must declare:
|
|
13
|
+
|
|
14
|
+
| Module | App | System app | Desktop page |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| `acde:window` | ✓ | ✓ | |
|
|
17
|
+
| `acde:capabilities` | ✓ | ✓ | ✓ |
|
|
18
|
+
| `acde:apps` | ✓ | ✓ | ✓ |
|
|
19
|
+
| `acde:open` | ✓ (opening an app needs `open`) | ✓ (same) | ✓ |
|
|
20
|
+
| `acde:fs` | `fs` | `fs` | ✓ |
|
|
21
|
+
| `acde:terminal` | `terminal` | `terminal` | ✓ |
|
|
22
|
+
| `acde:network` | `network` | `network` | ✓ |
|
|
23
|
+
| `acde:office` | `office` | `office` | ✓ |
|
|
24
|
+
| `acde:openPath` `acde:handlers` | `openFiles` | `openFiles` | ✓ |
|
|
25
|
+
| `acde:launch` | `launch` or `slots` | `launch` or `slots` | ✓ |
|
|
26
|
+
| `acde:windows` `acde:packages` `acde:session` `acde:desktops` `acde:inspect` `acde:desktop` `acde:setDefault` `acde:permissions` (shell modules) | | The module's name: `"windows": true` | ✓ |
|
|
27
|
+
| `acde:<service>` | The service's name in `services` | The same | ✓ |
|
|
28
|
+
|
|
29
|
+
A module the platform lacks is missing for everyone there (see [Platform support](platforms.md)). An import that is not allowed fails with a `TypeError` whose message names the missing declaration, such as `acde:terminal needs "terminal" in the capabilities of Notes`. Desktop services cannot import `acde:` modules; a service that the desktop grants shell modules gets them from `ctx.import()`; see [Service API](service.md).
|
|
30
|
+
|
|
31
|
+
Events are subscribed with `on(type, handler)`, which returns an unsubscribe function. `on()` throws a `TypeError` for an event type the module does not have, such as `acde:window has no nosuch event (activate, deactivate, …)`. Two modules take a callback instead: `acde:terminal` (`subscribe`) and `acde:network` (`watch`).
|
|
32
|
+
|
|
33
|
+
## acde:window
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
interface AcdeWindow {
|
|
37
|
+
readonly id: number
|
|
38
|
+
readonly state: WindowState
|
|
39
|
+
readonly output: WindowOutput
|
|
40
|
+
readonly hostControls: boolean
|
|
41
|
+
readonly minimizable: boolean
|
|
42
|
+
readonly host: WindowHost
|
|
43
|
+
mount(app: WindowApp): void
|
|
44
|
+
setTitle(title: string): void
|
|
45
|
+
setMenus(menus: readonly AppMenu[]): void
|
|
46
|
+
close(): Promise<boolean>
|
|
47
|
+
minimize(): Promise<void>
|
|
48
|
+
requestAttention(): Promise<void>
|
|
49
|
+
requestState(state: WindowState): void
|
|
50
|
+
requestMode(mode: WindowMode): void
|
|
51
|
+
setGrabHint(rect: WindowRect, edges?: readonly ('top' | 'bottom' | 'left' | 'right')[]): void
|
|
52
|
+
setBackdrop(rect: WindowRect | null, effect?: { radius?: number; blur?: number; saturate?: number; brightness?: number }): void
|
|
53
|
+
requestActivate(): void
|
|
54
|
+
requestGrab(kind: 'pointer' | 'keyboard'): void
|
|
55
|
+
releaseGrab(kind: 'pointer' | 'keyboard'): void
|
|
56
|
+
shortcut(combo: string): Promise<void>
|
|
57
|
+
unshortcut(combo: string): Promise<void>
|
|
58
|
+
on(name: 'beforeclose', handler: () => boolean | void | Promise<boolean | void>): () => boolean
|
|
59
|
+
on<R extends AppRequest = AppRequest>(name: 'request', handler: (request: SystemRequest | R) => void): () => boolean
|
|
60
|
+
on(name: 'activate' | 'deactivate', handler: () => void): () => boolean
|
|
61
|
+
on(name: 'state', handler: (event: { readonly state: WindowState; readonly previous: WindowState }) => void): () => boolean
|
|
62
|
+
on(name: 'output', handler: (output: WindowOutput) => void): () => boolean
|
|
63
|
+
on(name: 'hostcontrols', handler: (hostControls: boolean) => void): () => boolean
|
|
64
|
+
on(name: 'minimizable', handler: (minimizable: boolean) => void): () => boolean
|
|
65
|
+
on(name: 'shortcut', handler: (event: ShortcutEvent) => void): () => boolean
|
|
66
|
+
on(name: 'grab', handler: (event: { readonly kind: 'pointer' | 'keyboard'; readonly granted: boolean }) => void): () => boolean
|
|
67
|
+
on(name: 'grablost', handler: (event: { readonly kind: 'lost'; readonly reason: 'esc' | 'other_window' | 'focus_lost' | 'denied' }) => void): () => boolean
|
|
68
|
+
on(name: 'suspend' | 'resume', handler: () => void): () => boolean
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
type WindowState = 'normal' | 'minimized' | 'filled' | 'fullscreen'
|
|
72
|
+
type WindowMode = 'free' | 'fixed' | 'pinned'
|
|
73
|
+
|
|
74
|
+
interface WindowRect { x: number; y: number; width: number; height: number }
|
|
75
|
+
interface WindowOutput { width: number; height: number; scale: number; workArea: WindowRect }
|
|
76
|
+
|
|
77
|
+
interface ShortcutEvent { type: 'shortcut'; window: number; key: string; title: 'session' | 'desktop' | 'app' }
|
|
78
|
+
|
|
79
|
+
interface AppMenu {
|
|
80
|
+
id: string
|
|
81
|
+
label: string
|
|
82
|
+
items: ({ type: 'separator' } | AppMenuItem)[]
|
|
83
|
+
}
|
|
84
|
+
interface AppMenuItem {
|
|
85
|
+
id: string
|
|
86
|
+
label: string
|
|
87
|
+
shortcut?: string
|
|
88
|
+
checked?: boolean
|
|
89
|
+
disabled?: boolean
|
|
90
|
+
onSelect?(): void | Promise<void>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface WindowApp {
|
|
94
|
+
mount(element: Element, host: WindowHost): () => void
|
|
95
|
+
}
|
|
96
|
+
interface WindowHost {
|
|
97
|
+
setTitle(title: string): void
|
|
98
|
+
setMenus(menus: readonly AppMenu[]): void
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- Full screen is a state: `requestState('fullscreen')`. `requestMode('fullscreen')` throws a `TypeError`, and so does an unknown state. `requestState` has no result; follow the `state` event. See [Window state](../guide/window.md#window-state).
|
|
103
|
+
- `close()` closes the window without asking `beforeclose`.
|
|
104
|
+
- `minimize()` rejects with `status: 409`, `code: 'unavailable'` for a window that cannot be minimized (`minimizable` is `false`): `window 1048576 cannot be minimized: it fills the host window, which only the host window's own controls minimize here` for the app's window in a session that runs a single app, on macOS and headless. `requestState('minimized')` changes nothing there.
|
|
105
|
+
- `suspend` and `resume` are declared, but the runtime does not send them yet.
|
|
106
|
+
- Coordinates are logical pixels of the page (the content area). Shortcut combos are written like `ctrl+alt+t`: keys are xkb keysym names, the key names X11 and Wayland use (`t`, `return`, `escape`, `f5`, `space`; case doesn't matter), and Shift is part of the combo.
|
|
107
|
+
|
|
108
|
+
## acde:capabilities
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
interface AcdeCapabilities {
|
|
112
|
+
readonly level: number
|
|
113
|
+
readonly platform: 'linux' | 'win32' | 'darwin'
|
|
114
|
+
readonly mode: 'session' | 'desktop' | 'standalone'
|
|
115
|
+
readonly window: { readonly backdrop: 'full' | 'approximated' | 'unsupported' }
|
|
116
|
+
get(name: string): CapabilityStatus
|
|
117
|
+
list(): CapabilityStatus[]
|
|
118
|
+
request(name: string): Promise<CapabilityStatus>
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface CapabilityStatus {
|
|
122
|
+
name: string
|
|
123
|
+
kind: 'system' | 'service'
|
|
124
|
+
state: 'available' | 'not-asked' | 'asking' | 'not-declared' | 'unsupported' | 'service-not-running' | 'shell-only' | 'denied'
|
|
125
|
+
reason: string
|
|
126
|
+
optional: boolean
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`level` is the contract level (1). `request(name)` asks the user for a capability that needs approval and resolves with its status after the answer; for anything else it resolves at once. A capability that needs approval is `available` only once the user allowed it: `not-asked` before the prompt, `asking` while it waits, `denied` after a denial or after the approval was taken back. A call that the approval stops fails with `status: 403`, the `capability`, and one of the codes `not_asked`, `asking`, `denied`. Names are capability names, `fs.<place>` for a shared place (`fs.downloads`), service names, and `notifications` (the standard `Notification` API: `available`, or `unsupported` where this way of running has no notifications). See [Capabilities](../guide/capabilities.md#acdecapabilities).
|
|
131
|
+
|
|
132
|
+
## acde:fs
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
interface AcdeFs {
|
|
136
|
+
roots(): Promise<FinderRoot[]>
|
|
137
|
+
list(root: string, path?: string, hidden?: boolean): Promise<{ root: FinderRoot; path: string; entries: FinderEntry[]; truncated: boolean; skipped?: number }>
|
|
138
|
+
stat(root: string, path: string): Promise<FinderEntry & { path: string }>
|
|
139
|
+
readText(root: string, path: string): Promise<{ text: string; modifiedMs: number; size: number; version: string }>
|
|
140
|
+
readBytes(root: string, path: string): Promise<{ data: Uint8Array; modifiedMs: number; size: number; version: string }>
|
|
141
|
+
readRange(root: string, path: string, offset: number, length: number, options?: { ifVersion?: string }): Promise<{
|
|
142
|
+
data: Uint8Array; offset: number; size: number; modifiedMs: number; version: string
|
|
143
|
+
}>
|
|
144
|
+
writeFile(root: string, path: string, data: string | Uint8Array, options?: {
|
|
145
|
+
create?: 'always' | 'new' | 'never'
|
|
146
|
+
ifVersion?: string
|
|
147
|
+
ifModifiedMs?: number
|
|
148
|
+
mkdirs?: boolean
|
|
149
|
+
}): Promise<FinderEntry>
|
|
150
|
+
openWrite(root: string, path: string, options?: {
|
|
151
|
+
keepExistingData?: boolean
|
|
152
|
+
create?: 'always' | 'new' | 'never'
|
|
153
|
+
ifVersion?: string
|
|
154
|
+
mkdirs?: boolean
|
|
155
|
+
}): Promise<{ id: string; size: number }>
|
|
156
|
+
writeChunk(id: string, offset: number, data: string | Uint8Array): Promise<void>
|
|
157
|
+
truncateWrite(id: string, size: number): Promise<void>
|
|
158
|
+
commitWrite(id: string): Promise<FinderEntry>
|
|
159
|
+
abortWrite(id: string): Promise<void>
|
|
160
|
+
mkdir(root: string, path: string, options?: { recursive?: boolean }): Promise<FinderEntry>
|
|
161
|
+
rename(root: string, from: string, to: string): Promise<FinderEntry>
|
|
162
|
+
delete(root: string, path: string): Promise<{ status: 'deleted'; path: string }>
|
|
163
|
+
copy(fromRoot: string, fromPath: string, toRoot: string, toDir: string): Promise<FinderEntry & { path: string }>
|
|
164
|
+
preview(root: string, path: string): Promise<FinderPreview>
|
|
165
|
+
download(root: string, path: string): Promise<{ name: string; contentType: string; data: Uint8Array }>
|
|
166
|
+
revoke(root: string): Promise<void>
|
|
167
|
+
locate(path: string): Promise<{ root: string; path: string }>
|
|
168
|
+
openPath(root: string, path: string): Promise<{ root: string; path: string; file: string }>
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
interface FinderRoot {
|
|
172
|
+
id: string
|
|
173
|
+
label: string
|
|
174
|
+
source: 'private' | 'place' | 'granted' | 'desktop' | 'downloads' | 'default'
|
|
175
|
+
place?: 'desktop' | 'documents' | 'downloads' | 'music' | 'pictures' | 'videos'
|
|
176
|
+
path?: string
|
|
177
|
+
mode: 'writable' | 'read_only' | 'unavailable'
|
|
178
|
+
reason: string | null
|
|
179
|
+
exists: boolean
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
interface FinderEntry {
|
|
183
|
+
name: string
|
|
184
|
+
kind: 'directory' | 'file' | 'symlink' | 'other'
|
|
185
|
+
size: number
|
|
186
|
+
modifiedMs: number
|
|
187
|
+
target?: string
|
|
188
|
+
version?: string
|
|
189
|
+
inPlace?: true
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
interface FinderPreview {
|
|
193
|
+
path: string
|
|
194
|
+
name: string
|
|
195
|
+
size: number
|
|
196
|
+
modifiedMs: number
|
|
197
|
+
kind: 'text' | 'image' | 'binary' | 'too_large'
|
|
198
|
+
content?: string
|
|
199
|
+
truncated?: boolean
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
- `root` is the `id` of an item of `roots()`: `private`, a shared place's name, or `folder-…` for a picked folder; never a path. An app's roots have `source` `private`, `place` (with `place`), or `granted`, and no `path`.
|
|
204
|
+
- `path` is there only for system apps that name shared places, and for the desktop page. `locate` and `openPath` work only for them; in other apps they reject with `EACCES`.
|
|
205
|
+
- The desktop page's roots are folders by path (`source` `desktop`, `downloads`, `default`, or `granted`), and their `id` is the path.
|
|
206
|
+
- `list` leaves hidden entries out unless `hidden` is `true`; `skipped` counts entries whose names are not valid Unicode.
|
|
207
|
+
- `copy` copies a file or a folder from one root into the folder `toDir` of another; a taken name gets a number (`todo 2.md`), and `path` is where the copy is in `toRoot`.
|
|
208
|
+
- `revoke` gives back a folder the user picked.
|
|
209
|
+
- `version` is an opaque string for one state of a file; pass it as `ifVersion` and a write (or a `readRange`) of a file that changed since fails with `ECONFLICT`. `inPlace` marks a write that could not go through a temporary file. See [Safe writes](../guide/files.md#safe-writes).
|
|
210
|
+
- `openWrite` starts a write in parts: `writeChunk` at any offset, `truncateWrite`, then `commitWrite` puts the file in place (or `abortWrite`). A write left alone for 10 minutes is given up. See [Large files](../guide/files.md#large-files).
|
|
211
|
+
- Limits: `readText` / `readBytes` / `writeFile` 64 MiB; `readRange` / `writeChunk` 16 MiB a call; `list` 5000 entries (`truncated`); `preview` text 256 KiB.
|
|
212
|
+
- `download` answers the type the system knows for the file's name as `contentType`: `text/markdown` for `note.md`, `image/png` for `shot.png`, and `application/octet-stream` for a name it knows no type for (`data.xyz`). The types come from the system, as described under [Files and links](../guide/open.md#files-and-links).
|
|
213
|
+
- Errors have `code` and `status`; see [Files and folders](../guide/files.md#errors).
|
|
214
|
+
|
|
215
|
+
## acde:open
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
interface AcdeOpen {
|
|
219
|
+
(app: string, request?: null, options?: OpenWindowOptions): Promise<{ window: number }>
|
|
220
|
+
<R extends AppRequest>(app: string, request: R, options?: OpenWindowOptions): Promise<{ window: number }>
|
|
221
|
+
(app: string, request: SystemRequest): Promise<Opened>
|
|
222
|
+
(request: SystemRequest): Promise<Opened>
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
type AppRequest<K extends string = string, Fields extends object = Record<never, never>> = { readonly kind: K } & { readonly [P in keyof Fields]: Fields[P] }
|
|
226
|
+
|
|
227
|
+
type SystemRequest =
|
|
228
|
+
| { kind: 'open-file'; handle?: FileSystemFileHandle | FileSystemDirectoryHandle; url?: string; root?: string; path?: string; file?: string | null }
|
|
229
|
+
| { kind: 'open-link'; url: string }
|
|
230
|
+
|
|
231
|
+
interface OpenWindowOptions { parent?: number; modal?: boolean }
|
|
232
|
+
interface Opened { kind: 'acde' | 'native'; id: string; window?: number }
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
- `open(app)` and `open(app, request)` need the `open` capability to allow `app`. A request to an app must have a `kind` that the target lists in its `requests` (400 `untyped_request`, 409 `not_accepted`).
|
|
236
|
+
- `open(request)` with a system request and no app needs `openFiles`: the system picks the app. With an app, the target must declare the file's type (`mimeTypes`) or the link's scheme (`schemes`).
|
|
237
|
+
- A receiving app gets a file as `{ kind: 'open-file', handle }`; a system app that names shared places also gets `url`. Send a file with `handle` (one this page got from a picker, a drop, or a request) or, where the caller knows paths, with `url`.
|
|
238
|
+
- A receiver types its own requests with `AppRequest<K, Fields>`: `type ShowImage = AppRequest<'show-image', { image: string }>`, then `self.on<ShowImage>('request', …)` narrows by `kind`. `SystemRequest` and `AppRequest` are also in `acde:window`'s `request` event (above).
|
|
239
|
+
|
|
240
|
+
See [Opening apps](../guide/open.md).
|
|
241
|
+
|
|
242
|
+
## acde:apps
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
interface AcdeAppList {
|
|
246
|
+
list(): Promise<DesktopApp[]>
|
|
247
|
+
open: AcdeOpen
|
|
248
|
+
on(type: 'changed', handler: (event: { type: 'appschanged'; apps: readonly DesktopApp[] }) => void): () => boolean
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
interface DesktopApp { id: string; label: string; icon: string; script: string }
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
`list()` gives the apps that can run here; `open` is the function of `acde:open`. `changed` fires with the new list when it changes. In 0.0.9 it also fires when the user denies a camera or microphone that an app requires, or takes that approval back, because the app leaves the list; after 0.0.9, a denial keeps the app in the list. Installing packages and native programs are in [`acde:packages`](#acdepackages).
|
|
255
|
+
|
|
256
|
+
## acde:openPath / acde:handlers / acde:setDefault
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
function openPath(path: string, options?: { app?: string; select?: boolean }): Promise<{ kind: 'acde' | 'native'; id: string; window?: number }>
|
|
260
|
+
function handlers(path: string): Promise<{ mime: string; association: string | null; handlers: OpenHandler[] }>
|
|
261
|
+
function setDefault(association: string, handler: string): Promise<string>
|
|
262
|
+
|
|
263
|
+
interface OpenHandler {
|
|
264
|
+
kind: 'acde' | 'native'
|
|
265
|
+
id: string
|
|
266
|
+
label: string
|
|
267
|
+
icon: string
|
|
268
|
+
default: boolean
|
|
269
|
+
system?: boolean
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`path` can be a path or a URI. `openPath` and `handlers` need `openFiles`; for an app the file must be inside one of its roots (404 `outside_roots`). `setDefault` is a shell module. `association` is the key a choice is remembered under: the MIME type, or on Windows the file's extension (`.md`); `mime` is `''` when the system knows no type for the file. `system` marks the program that is the system's own default (Windows).
|
|
274
|
+
|
|
275
|
+
## acde:launch
|
|
276
|
+
|
|
277
|
+
Needs `launch` (for `start`) or `slots` (for `embed`).
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
interface AcdeLaunch {
|
|
281
|
+
start(argv: readonly string[], options?: LaunchOptions): Promise<number>
|
|
282
|
+
embed(argv: readonly string[], options?: LaunchOptions): Promise<number>
|
|
283
|
+
close(window: number): Promise<boolean>
|
|
284
|
+
list(): NativeWindow[]
|
|
285
|
+
on<K extends WindowsEventType>(type: K, handler: (event: WindowsEventMap[K]) => void): () => boolean
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
interface LaunchOptions { cwd?: string; env?: Record<string, string> }
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
`start` runs a native program and `embed` runs one embedded in the app's own window (Dopame OS only). `close` closes a window the app started; any other window is rejected with 403 `forbidden`. The events are those of [`acde:windows`](#acdewindows).
|
|
292
|
+
|
|
293
|
+
## acde:terminal
|
|
294
|
+
|
|
295
|
+
Needs `terminal`.
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
interface AcdeTerminals {
|
|
299
|
+
open(cols: number, rows: number): Promise<{ id: string }>
|
|
300
|
+
subscribe(id: string, callback: (events: TerminalEvent[]) => void): Promise<void>
|
|
301
|
+
input(id: string, data: string): Promise<{ ok: true }>
|
|
302
|
+
resize(id: string, cols: number, rows: number): Promise<{ cols: number; rows: number }>
|
|
303
|
+
close(id: string): Promise<{ closed: string }>
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
type TerminalEvent =
|
|
307
|
+
| { type: 'output'; data: string }
|
|
308
|
+
| { type: 'cwd'; path: string }
|
|
309
|
+
| { type: 'exit'; code: number | null; signal: number | null }
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## acde:network
|
|
313
|
+
|
|
314
|
+
Linux only (Dopame OS, or any Linux with NetworkManager). Needs `network`.
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
interface AcdeNetwork {
|
|
318
|
+
state(): Promise<NetworkState>
|
|
319
|
+
networks(scan?: boolean): Promise<WifiNetwork[]>
|
|
320
|
+
connect(ssid: string, password?: string): Promise<void>
|
|
321
|
+
activate(iface: string): Promise<void>
|
|
322
|
+
disconnect(iface: string): Promise<void>
|
|
323
|
+
setWifiEnabled(on: boolean): Promise<void>
|
|
324
|
+
watch(callback: (state: NetworkState) => void): void
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
interface NetworkState {
|
|
328
|
+
wifiEnabled: boolean
|
|
329
|
+
connectivity: 'full' | 'limited' | 'portal' | 'none' | 'unknown'
|
|
330
|
+
primary: 'wifi' | 'ethernet' | string | null
|
|
331
|
+
devices: NetworkDevice[]
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
interface NetworkDevice {
|
|
335
|
+
iface: string
|
|
336
|
+
type: 'wifi' | 'ethernet'
|
|
337
|
+
state: 'connected' | 'connecting' | 'disconnecting' | 'disconnected' | 'unavailable' | 'unmanaged' | 'failed'
|
|
338
|
+
connection: string | null
|
|
339
|
+
ip4: string | null
|
|
340
|
+
ssid?: string
|
|
341
|
+
strength?: number
|
|
342
|
+
carrier?: boolean
|
|
343
|
+
speed?: number
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
interface WifiNetwork {
|
|
347
|
+
ssid: string
|
|
348
|
+
strength: number
|
|
349
|
+
secure: boolean
|
|
350
|
+
band: '2.4GHz' | '5GHz'
|
|
351
|
+
active: boolean
|
|
352
|
+
saved: boolean
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
## acde:session
|
|
357
|
+
|
|
358
|
+
Shell module: only the desktop page and the system apps of its package (with `"session": true` in their capabilities) can import it; an ordinary app cannot, even if it declares `session`.
|
|
359
|
+
|
|
360
|
+
```ts
|
|
361
|
+
interface AcdeSession {
|
|
362
|
+
own(): boolean
|
|
363
|
+
logout(): Promise<void>
|
|
364
|
+
reboot(): Promise<void>
|
|
365
|
+
poweroff(): Promise<void>
|
|
366
|
+
setLanguage(tag: string): Promise<void>
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
`own()`: whether this is a real Dopame OS session (`false` in the host window of `acde dev`). After `setLanguage`, pages receive `languagechange`.
|
|
371
|
+
|
|
372
|
+
## acde:desktops
|
|
373
|
+
|
|
374
|
+
Shell module.
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
interface AcdeDesktops {
|
|
378
|
+
list(): Promise<{ desktops: DesktopInfo[]; current: string }>
|
|
379
|
+
choose(id: string, remember?: boolean): Promise<void>
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
interface DesktopInfo {
|
|
383
|
+
kind: 'acde' | 'session'
|
|
384
|
+
id: string
|
|
385
|
+
name: string
|
|
386
|
+
description: string | null
|
|
387
|
+
package: string | null
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
`kind: 'session'` is another Wayland session on the system (GNOME, KDE, ...).
|
|
392
|
+
|
|
393
|
+
## acde:packages
|
|
394
|
+
|
|
395
|
+
Shell module.
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
interface AcdePackages {
|
|
399
|
+
refresh(): Promise<DesktopApp[]>
|
|
400
|
+
install(dir: string): Promise<{ id: string; dir: string; apps: DesktopApp[] }>
|
|
401
|
+
natives(): Promise<NativeApp[]>
|
|
402
|
+
runNative(id: string): Promise<number>
|
|
403
|
+
on(type: 'changed', handler: (event: { type: 'appschanged'; apps: readonly DesktopApp[] }) => void): () => boolean
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
interface NativeApp {
|
|
407
|
+
id: string
|
|
408
|
+
name: string
|
|
409
|
+
comment: string | null
|
|
410
|
+
icon: string
|
|
411
|
+
keywords: string[]
|
|
412
|
+
wmClass: string | null
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
`natives()` lists the system's native programs (`.desktop` files, Linux only).
|
|
417
|
+
|
|
418
|
+
## acde:windows
|
|
419
|
+
|
|
420
|
+
Shell module: every window of the session.
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
interface AcdeWindows {
|
|
424
|
+
on<K extends WindowsEventType>(type: K, handler: (event: WindowsEventMap[K]) => void): () => boolean
|
|
425
|
+
list(): NativeWindow[]
|
|
426
|
+
close(id: number): void
|
|
427
|
+
requestState(id: number, state: WindowState): Promise<void>
|
|
428
|
+
kill(id: number): Promise<boolean>
|
|
429
|
+
focus(id: number): Promise<void>
|
|
430
|
+
hide(id: number): Promise<void>
|
|
431
|
+
show(id: number): Promise<void>
|
|
432
|
+
invokeMenu(id: number, menu: string, item: string): Promise<void>
|
|
433
|
+
stats(): Promise<Record<string, number>>
|
|
434
|
+
animate(id: number, options: {
|
|
435
|
+
opacity?: number; scale?: number; dx?: number; dy?: number
|
|
436
|
+
duration?: number; delay?: number
|
|
437
|
+
easing?: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out'
|
|
438
|
+
}): Promise<void>
|
|
439
|
+
shortcut(combo: string, scope?: 'session' | 'desktop'): Promise<void>
|
|
440
|
+
unshortcut(combo: string, scope?: 'session' | 'desktop'): Promise<void>
|
|
441
|
+
launch(argv: string[], options?: { cwd?: string; env?: Record<string, string>; slot?: boolean }): number | Promise<number>
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
interface NativeWindow { id: number; appId: string | null; title: string | null; web?: boolean; state: WindowState }
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
`WindowsEventType`: `open` `close` `title` `state` `activate` `minsize` `parent` `menus` `crash` `hang` `responsive` `attention` `ready` `show` `animated`. Every event is `{ type: 'window<name>', window: number, … }`:
|
|
448
|
+
|
|
449
|
+
| Event | Extra fields |
|
|
450
|
+
| --- | --- |
|
|
451
|
+
| `open` | `appId`, `title`, `web`, `icon` |
|
|
452
|
+
| `title` | `appId`, `title` |
|
|
453
|
+
| `state` | `state`, `previous` |
|
|
454
|
+
| `minsize` | `width`, `height` |
|
|
455
|
+
| `parent` | `parent` |
|
|
456
|
+
| `menus` | `menus`: the app's menus, each item with `action: boolean` instead of `onSelect` |
|
|
457
|
+
| `crash` | `reason` |
|
|
458
|
+
|
|
459
|
+
- A window's state changes are reported by `state`; full screen and minimizing have no events of their own. `requestState` rejects an unknown state with a `TypeError`.
|
|
460
|
+
- `close(id)` asks the app (`beforeclose`); `kill(id)` ends the window without asking.
|
|
461
|
+
- `animate` may finish at once where the runtime cannot animate; `animated` still fires.
|
|
462
|
+
- Every row of `list()` has the window's current `state`, and `list()` has every window, also in a system app that started after a window opened.
|
|
463
|
+
- An app starts native programs with [`acde:launch`](#acdelaunch), not with `launch` here.
|
|
464
|
+
|
|
465
|
+
## acde:desktop
|
|
466
|
+
|
|
467
|
+
Shell module.
|
|
468
|
+
|
|
469
|
+
```ts
|
|
470
|
+
interface AcdeDesktop {
|
|
471
|
+
apps(): Promise<{ apps: DesktopApp[] }>
|
|
472
|
+
pin(element: Element, options?: { margin?: number; reserve?: PanelReserve }): PinnedPanel
|
|
473
|
+
setDoubleClick(action: 'fill' | 'minimize' | 'none'): void
|
|
474
|
+
setFrameTheme(theme: FrameTheme | null): void
|
|
475
|
+
on(type: 'notification', handler: (e: NotificationEvent) => void): () => boolean
|
|
476
|
+
on(type: 'download', handler: (e: DownloadEvent) => void): () => boolean
|
|
477
|
+
on(type: 'screenshot', handler: (e: { type: 'screenshot'; path: string; width: number; height: number } | { type: 'screenshot'; path: string; error: string }) => void): () => boolean
|
|
478
|
+
on(type: 'shortcut', handler: (e: ShortcutEvent) => void): () => boolean
|
|
479
|
+
on(type: 'edge', handler: (e: { type: 'screenedge'; edge: 'top' | 'right' | 'bottom' | 'left'; entered: boolean; output: string }) => void): () => boolean
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
interface PanelReserve { edge: 'top' | 'bottom' | 'left' | 'right'; thickness?: number }
|
|
483
|
+
interface PinnedPanel {
|
|
484
|
+
update(): void
|
|
485
|
+
unpin(): void
|
|
486
|
+
reserve(reserve: PanelReserve | null): void
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
interface FrameTheme {
|
|
490
|
+
active?: FrameColors
|
|
491
|
+
inactive?: FrameColors
|
|
492
|
+
light?: { active?: FrameColors; inactive?: FrameColors }
|
|
493
|
+
buttonStyle?: 'dots' | 'glyphs'
|
|
494
|
+
buttonSide?: 'left' | 'right'
|
|
495
|
+
titleAlign?: 'center' | 'start'
|
|
496
|
+
}
|
|
497
|
+
interface FrameColors { background?: string; title?: string; line?: string; buttons?: string }
|
|
498
|
+
|
|
499
|
+
interface NotificationEvent {
|
|
500
|
+
type: 'notification'
|
|
501
|
+
window: number
|
|
502
|
+
app: string | null
|
|
503
|
+
label: string | null
|
|
504
|
+
title: string
|
|
505
|
+
body: string
|
|
506
|
+
icon: string
|
|
507
|
+
tag: string
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
interface DownloadEvent {
|
|
511
|
+
type: 'download'
|
|
512
|
+
window: number
|
|
513
|
+
app: string | null
|
|
514
|
+
path: string
|
|
515
|
+
name: string
|
|
516
|
+
size: number
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
- `edge` fires when the pointer reaches (`entered: true`) or leaves an edge of the screen, once per edge (twice in a corner); `output` is the screen's name, `host` in a host window. It takes no focus, for a desktop that shows its hidden menu bar or Dock.
|
|
521
|
+
- `light`: the title bar colors for windows whose page does not declare dark support (`color-scheme` without `dark`); `active` / `inactive` are then for pages that do. Every `setFrameTheme` call gives the whole theme; a bad value throws a `TypeError`, and an unknown key is ignored with a warning in the log.
|
|
522
|
+
- A system app that declares `"desktop": true` gets `apps()`, `setDoubleClick`, `setFrameTheme`, and the `notification`, `download` and `edge` events; `pin`, `screenshot` and `shortcut` are the desktop page's only.
|
|
523
|
+
|
|
524
|
+
See [Desktops](../guide/desktop.md#panels).
|
|
525
|
+
|
|
526
|
+
## acde:permissions
|
|
527
|
+
|
|
528
|
+
Shell module: the approval prompts and the decisions about them.
|
|
529
|
+
|
|
530
|
+
```ts
|
|
531
|
+
interface AcdePermissions {
|
|
532
|
+
pending(): Promise<PermissionPrompt[]>
|
|
533
|
+
answer(id: number, allow: boolean): Promise<void>
|
|
534
|
+
list(app?: string): Promise<PermissionDecision[]>
|
|
535
|
+
revoke(app: string, capability: string): Promise<boolean>
|
|
536
|
+
on(type: 'prompt', handler: (event: PermissionPrompt & { type: 'permissionprompt' }) => void): () => boolean
|
|
537
|
+
on(type: 'answered', handler: (event: { type: 'permissionanswered'; id: number; app: string; capability: string; allowed: boolean }) => void): () => boolean
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
interface PermissionPrompt {
|
|
541
|
+
id: number
|
|
542
|
+
app: string
|
|
543
|
+
label: string
|
|
544
|
+
capability: string
|
|
545
|
+
reason: 'request'
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
interface PermissionDecision {
|
|
549
|
+
app: string
|
|
550
|
+
label: string | null
|
|
551
|
+
capability: string
|
|
552
|
+
decision: 'granted' | 'denied'
|
|
553
|
+
folder?: { label: string; exists: boolean }
|
|
554
|
+
}
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
A prompt's `capability` is `camera` or `microphone`, the only capabilities that ask; in a decision it can also be `fs.folder-…`, a folder the user picked for the app (with `folder`). `revoke` resolves to `false` when there was no decision. In 0.0.9, a prompt for a camera or microphone that the app requires comes when the app starts, with `reason: 'launch'`; after 0.0.9, every prompt comes on first use, with `reason: 'request'`. See [Desktops](../guide/desktop.md#camera-and-microphone-prompts).
|
|
558
|
+
|
|
559
|
+
## acde:inspect
|
|
560
|
+
|
|
561
|
+
Shell module, also given to desktop services as `ctx.inspect`. Turns the screen into a text semantic tree and acts on it by ref; meant for AI agents. `acde inspect` / `acde act` and MCP are built on it.
|
|
562
|
+
|
|
563
|
+
```ts
|
|
564
|
+
interface AcdeInspect {
|
|
565
|
+
snapshot(options?: {
|
|
566
|
+
window?: string; ref?: string; all?: boolean; diff?: boolean
|
|
567
|
+
limit?: number; find?: string; tree?: boolean; offscreen?: boolean
|
|
568
|
+
}): Promise<{ text: string; windows: InspectWindow[]; trees: Record<string, InspectNode[]> }>
|
|
569
|
+
act(ref: string, action: InspectAction, arg?: string | number | readonly string[] | null): Promise<{ ok: boolean; text: string }>
|
|
570
|
+
run(steps: readonly { ref: string; action: InspectAction; text?: InspectArg }[]): Promise<{ ok: boolean; text: string }>
|
|
571
|
+
open(name: string): Promise<{ ok: boolean; text: string }>
|
|
572
|
+
query(options: { selector: string; window?: string; ref?: string; limit?: number; attributes?: readonly string[] }): Promise<{ window: string; count: number; nodes: InspectMatch[] }>
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
type InspectAction = 'click' | 'double' | 'right' | 'hover' | 'drag' | 'type' | 'settext' | 'select' | 'key' | 'scroll' | 'focus' | 'close' | 'minimize' | 'restore' | 'fill' | 'fullscreen'
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
Window refs are `w0` (the desktop), `w1`, ...; element refs look like `w3.12`. The text form has one node per line:
|
|
579
|
+
|
|
580
|
+
```text
|
|
581
|
+
- button "New Folder" [pressed] [w1.52]
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
## acde:office
|
|
585
|
+
|
|
586
|
+
Linux only. An editing service for office documents (text, spreadsheets, presentations), used by Dopame's bundled office apps; the API is still subject to change.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Platform support
|
|
2
|
+
|
|
3
|
+
The host window used for development (`acde dev`) runs on macOS, Windows, and Linux; Dopame OS itself is Linux. The runtime is built for macOS on Apple silicon and Intel, Linux on x86_64, and Windows on x64; see [Install](../start/install.md#supported-platforms).
|
|
4
|
+
|
|
5
|
+
| | macOS | Windows | Linux (development) | Dopame OS |
|
|
6
|
+
| --- | --- | --- | --- | --- |
|
|
7
|
+
| Page rendering (requires a GPU) | Metal | DX12 | Vulkan (a hardware driver) | Vulkan |
|
|
8
|
+
| `acde:fs`, file pickers | ✓ | ✓ | ✓ | ✓ |
|
|
9
|
+
| Sound, clipboard | ✓ | ✓ | ✓ | ✓ |
|
|
10
|
+
| System notifications | ✓ | Only in a desktop, which shows them | ✓ | Shown by the desktop |
|
|
11
|
+
| App backends | ✓ | ✓ (see [Backend](../guide/backend.md#on-windows)) | ✓ | ✓ |
|
|
12
|
+
| `acde:terminal` (`terminal`) | ✓ | ✓ | ✓ | ✓ |
|
|
13
|
+
| Camera and microphone (`camera`, `microphone`) | ✓ | | ✓ | ✓ |
|
|
14
|
+
| `acde:network`, `acde:office` (`network`, `office`) | | | ✓ | ✓ |
|
|
15
|
+
| Native programs embedded in a window (`slots`) | | | | ✓ |
|
|
16
|
+
| WebGPU, voice input | | | ✓ | ✓ |
|
|
17
|
+
| Native programs (`.desktop`) | | | ✓ | ✓ |
|
|
18
|
+
| Headless (`--headless`, `acde test`) | ✓ | ✓ | ✓ (requires a GPU) | |
|
|
19
|
+
|
|
20
|
+
- Capabilities a platform lacks are not faked. An app that **requires** one does not start there (`Notes needs "network" (unsupported on this platform)`) and is left out of the app list; one that lists it in `optional` starts, `load()` gives `null` for the module, and `acde:capabilities` reports `state: 'unsupported'`. See [Capabilities](../guide/capabilities.md#optional-capabilities).
|
|
21
|
+
- `acde check --platform windows` (or `macos`, `linux`) tells you before you run there: `error: macos (standalone): app "notes" requires network, which this mode lacks`, or a `note:` when the capability is optional. The data is `PLATFORM_SUPPORT` in `@dopame/acde-api`, per platform and way of running: `session` (Dopame OS), `desktop` (a desktop in the host window), `standalone` (a single app in the host window). A page reads its own from `acde:capabilities` (`platform`, `mode`).
|
|
22
|
+
- The runtime draws pages only on the GPU, so Linux CI without a GPU cannot run headless. macOS CI runners can.
|
|
23
|
+
- On Linux the runtime needs the **hardware Vulkan driver** of the machine's GPU; a software renderer (lavapipe / llvmpipe) is not accepted. Without one, `acde dev` fails at startup with a log line that says so and names the GPU the system has: `web layer unavailable: the system has a GPU (card0, kernel driver i915) but no usable Vulkan driver was found: install the GPU's Vulkan driver (for example vulkan-intel, vulkan-radeon, nvidia-utils) or point VK_DRIVER_FILES at its ICD (…)`. The fix is to install the driver, then check that `vulkaninfo --summary` lists the GPU: for Mesa, `vulkan-intel` or `vulkan-radeon` on Arch, `mesa-vulkan-drivers` on Debian, Ubuntu and Fedora; for NVIDIA, the vendor's driver.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Service API
|
|
2
|
+
|
|
3
|
+
The default export of a desktop service module is a `ServiceFactory`. See [Services](../guide/services.md) for usage.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
type ServiceFactory = (context: ServiceContext) => ServiceInstance | Promise<ServiceInstance>
|
|
7
|
+
|
|
8
|
+
interface ServiceInstance {
|
|
9
|
+
readonly api: Readonly<Record<string, object>>
|
|
10
|
+
readonly sync?: readonly string[]
|
|
11
|
+
close?(): unknown
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ServiceContext {
|
|
15
|
+
readonly name: string
|
|
16
|
+
readonly package: string
|
|
17
|
+
readonly state: string
|
|
18
|
+
readonly native: Readonly<Record<string, unknown>> | null
|
|
19
|
+
readonly env: Readonly<Record<string, string | undefined>>
|
|
20
|
+
readonly inspect?: AcdeInspect
|
|
21
|
+
log(line: string): void
|
|
22
|
+
spawn(argv: readonly string[], options?: SpawnOptions): ServiceProcess
|
|
23
|
+
import<K extends keyof ServiceModuleTypes>(specifier: `acde:${K}`): Promise<{ readonly default: ServiceModuleTypes[K] } & { readonly [N in K]: ServiceModuleTypes[K] }>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// ServiceModuleTypes: windows, packages, session, desktops, inspect, setDefault, and desktop with apps() only
|
|
27
|
+
|
|
28
|
+
interface SpawnOptions {
|
|
29
|
+
readonly cwd?: string
|
|
30
|
+
readonly env?: Readonly<Record<string, string>>
|
|
31
|
+
onLine?(line: string): void
|
|
32
|
+
onExit?(code: number | null, signal: number | null): void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface ServiceProcess {
|
|
36
|
+
readonly pid: number
|
|
37
|
+
write(text: string): boolean
|
|
38
|
+
end(): void
|
|
39
|
+
kill(signal?: 'SIGTERM' | 'SIGKILL' | 'SIGINT' | 'SIGHUP'): boolean
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
- `api`: namespace → object. Each namespace becomes the module `acde:<namespace>`; functions on the object become callable methods, and strings / numbers / booleans become read-only fields.
|
|
44
|
+
- `sync`: a list of `"namespace.method"` entries. These methods are called once when a page starts, the results are cached in the page, and from then on they return synchronously in the page (good for configuration that doesn't change).
|
|
45
|
+
- `close()`: called when the desktop stops.
|
|
46
|
+
- An app lists the **service name** (the key in the desktop config's `services`) in its own `services`, and the runtime then gives it every namespace of that service. `acde check` and `acde build` let an import of a namespace that is not the service's own name pass with a `note:`, because they cannot know a service's namespaces (see [Services](../guide/services.md#call-it)). A service name cannot be that of a system module or capability, and a namespace with such a name is left out.
|
|
47
|
+
- `import('acde:windows')`: resolves to the module (`{ windows, default }`) when the desktop grants it to this service: `"services": { "clock": { "module": "services/clock.ts", "modules": ["windows"] } }` in `acde.config.jsonc`, which `acde build` writes into the manifest as `"services": [{ "name": "clock", "modules": ["windows"] }]` (see [Manifest](manifest.md#desktopmanifest)). Otherwise it rejects with `acde:windows is a shell module: list it in the modules of service "clock" in the desktop manifest`. A service cannot use a static `import` of an `acde:` module (the build rejects it). A service gets the modules a desktop page gets, with two exceptions: `acde:desktop` is `apps()` only, and `acde:permissions` is not given. Calls that the types declare as promises return promises in a service too. See [Services](../guide/services.md#shell-modules-in-a-service).
|