@hearthscale/app 0.1.0 → 0.2.1

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/dist/index.d.ts CHANGED
@@ -1,3 +1,172 @@
1
+ /** Resolved publisher identity, independent of the model architecture.
2
+ * `GET /v1/publishers/{owner}/picture` answers the picture of the Hub
3
+ * user or organisation `repository` names first: its bytes as
4
+ * `image/png`, `image/jpeg`, `image/webp`, `image/gif` or
5
+ * `image/svg+xml`, with `cache-control: max-age=86400`. A 404
6
+ * `invalid_request` says no picture is known for the owner, and a 400
7
+ * `invalid_request` refuses a name that is not one Hub path segment of
8
+ * ASCII letters, digits, `-`, `_` and `.`. */
9
+ interface ModelIdentity {
10
+ publisher: string;
11
+ /** The Hub repository whose publisher supplies the artwork; null for other sources. */
12
+ repository: string | null;
13
+ }
14
+ /** A job kind a model runs: the JSON Schema (draft-07) of its input, every
15
+ * object of it closed. A property of `"format": "asset"`, alone or as the
16
+ * items of an array, names a file by its asset id on the app's side,
17
+ * `contentMediaType` saying what it takes, and its `description` the
18
+ * limits the model sets on it; it reaches the Server as a `RenderUpload`
19
+ * in the same place. A property's `default` is what the model's saved
20
+ * settings give a job that leaves it out, as an image model's picture
21
+ * size, steps and guidance. */
22
+ interface JobSpec {
23
+ input: Record<string, unknown>;
24
+ }
25
+ /** The plan of a load or a media job against the memory as it stands, in
26
+ * MiB. A loaded model's process holds the graphics and system memory, and
27
+ * may fill the growth beside them as it keeps conversations ready; a
28
+ * job's process holds them at most while it runs. */
29
+ interface MemoryPlan {
30
+ graphicsMib: number;
31
+ systemMib: number;
32
+ growthMib: number;
33
+ /** The graphics and system memory together, written as the words write
34
+ * an amount of memory. */
35
+ takes: string;
36
+ /** The context a language model's load takes, shorter than its settings
37
+ * ask where the memory free now holds no more; absent for a media job. */
38
+ contextTokens?: number;
39
+ /** Whether the broker takes the load or the job now: it starts at once,
40
+ * or once the busy models and jobs it waits for finish. It is the check
41
+ * a load or a job meets as it starts, on the memory free now, and the
42
+ * catalogue says it changed when it does. */
43
+ ready: boolean;
44
+ /** The plan in words, or why the load cannot start now: the limit that
45
+ * stops it, the system memory free or what Windows can still commit,
46
+ * and what the person closes or changes. */
47
+ words: string;
48
+ }
49
+ interface DownloadProgressBytes {
50
+ receivedBytes: number;
51
+ totalBytes: number;
52
+ }
53
+ /** The order of a Discover search; trending first where `sort` names
54
+ * none. */
55
+ type HubSort = 'trending' | 'downloads' | 'likes' | 'updated';
56
+ /** One Hugging Face repository as Discover lists it: who published it, the
57
+ * model it quantises, how it is used, and what its header states of its
58
+ * size, its architecture and its window. */
59
+ interface HubRepository {
60
+ identity: ModelIdentity;
61
+ formats: string[];
62
+ tasks: string[];
63
+ repo: string;
64
+ author: string;
65
+ /** The repository the weights were quantised from, where the card
66
+ * names one. */
67
+ baseModel: string | null;
68
+ downloads: number;
69
+ likes: number;
70
+ /** A gated repository's files are read only with the Hugging Face token
71
+ * the Server holds. */
72
+ gated: boolean;
73
+ updatedAt: string | null;
74
+ pipeline: string | null;
75
+ architecture: string | null;
76
+ params: number | null;
77
+ contextLength: number | null;
78
+ vision: boolean;
79
+ tools: boolean;
80
+ reasoning: boolean;
81
+ }
82
+ /** A file that can fill a companion role: where it is, how big it is, and
83
+ * whether its checksum is published. */
84
+ interface CompanionOption {
85
+ repo: string;
86
+ path: string;
87
+ sizeBytes: number;
88
+ verifiable: boolean;
89
+ }
90
+ /** One file of a repository a pull can name: the whole shard set where it
91
+ * is a numbered shard, with the weights' projector beside it where the
92
+ * repository holds one. */
93
+ interface HubCandidate {
94
+ /** The model id the pull makes, with the projector a lone one picks. */
95
+ id: string;
96
+ /** The name the pulled model goes by where no other model of the
97
+ * library shares it, as `CatalogModel.label` names it. */
98
+ name: string;
99
+ path: string;
100
+ quantization: string;
101
+ /** Every byte the pull writes for this file, its set and its projector. */
102
+ sizeBytes: number;
103
+ engine: string;
104
+ /** Whether every byte of it publishes a checksum; a pull refuses the
105
+ * rest by name rather than downloading them unverified. */
106
+ verifiable: boolean;
107
+ /** The files the repository supplies beside the weights. */
108
+ components: {
109
+ role: string;
110
+ label: string;
111
+ path: string;
112
+ }[];
113
+ /** The companion roles the repository does not supply; a pull names a
114
+ * file for each, found in the model's family, the first unless the
115
+ * person chooses another. */
116
+ requires: {
117
+ role: string;
118
+ label: string;
119
+ options: CompanionOption[];
120
+ }[];
121
+ /** The companion roles the model loads where a pull names a file for
122
+ * them, which the repository does not supply: `llm_vision`, the vision
123
+ * part of a language model encoder, for a family that reads reference
124
+ * pictures through it. */
125
+ offers: {
126
+ role: string;
127
+ label: string;
128
+ options: CompanionOption[];
129
+ }[];
130
+ /** Whether the repository holds vision projectors beside the file. */
131
+ projector: boolean;
132
+ /** The projectors to choose from where there is more than one, each
133
+ * with the model id a pull with it makes. */
134
+ projectorOptions: {
135
+ path: string;
136
+ id: string;
137
+ sizeBytes: number;
138
+ verifiable: boolean;
139
+ }[];
140
+ /** The task the model serves, as `CatalogRole` names it. */
141
+ role: string;
142
+ format: string;
143
+ /** Why the file cannot be pulled, in the Server's words. */
144
+ reason?: string;
145
+ }
146
+ /** `GET /control/discover?task=&q=&sort=` answers the repositories of one
147
+ * task that `q` matches, or with no `q` the whole set, at most 30, as
148
+ * `HubRepository[]`; and `GET /control/discover/{owner}/{repo}` one
149
+ * repository as `HubListing`: the files a runtime of the Server runs, how
150
+ * many files it publishes in all, so a repository whose listing yields
151
+ * no candidate is one no runtime there runs, and every file a pull of
152
+ * another repository's model can name as a companion. Both read Hugging
153
+ * Face on a person's act and on nothing else, and with no token, so they
154
+ * reach the public repositories alone; the Server's own window reads the
155
+ * same answers from `/local/discover`, with the token the person stored. */
156
+ interface HubListing {
157
+ repo: string;
158
+ model: HubRepository;
159
+ files: number;
160
+ candidates: HubCandidate[];
161
+ companions: CompanionOption[];
162
+ capabilities: {
163
+ vision: boolean;
164
+ tools: boolean;
165
+ reasoning: boolean;
166
+ tasks: string[];
167
+ };
168
+ }
169
+
1
170
  /**
2
171
  * The platform half of the contract, generated from the Rust types of
3
172
  * the `contract` crate by `npm run contract` in `apps/platform/scripts`.
@@ -50,12 +219,26 @@ type Entry = {
50
219
  } | {
51
220
  attached: SessionRoot[];
52
221
  type: 'session.roots';
222
+ } | {
223
+ level: PermissionLevel;
224
+ type: 'session.level';
53
225
  } | {
54
226
  turn: string;
55
227
  model: string;
56
228
  provider: string;
57
229
  location: ModelLocation;
58
230
  revision: string;
231
+ /**
232
+ * The turn block the message that started the turn carries for
233
+ * the model in this and every later request; none when nothing it
234
+ * tells changed since the turns before.
235
+ */
236
+ block?: TurnBlock;
237
+ /**
238
+ * A hash of the apps the window showed and of their tools, when the
239
+ * block named them.
240
+ */
241
+ shown?: string;
59
242
  type: 'turn.started';
60
243
  } | {
61
244
  turn: string;
@@ -76,11 +259,6 @@ type Entry = {
76
259
  provider: string;
77
260
  error?: string;
78
261
  type: 'agent.message';
79
- } | {
80
- turn: string;
81
- partId: string;
82
- text: string;
83
- type: 'agent.part';
84
262
  } | {
85
263
  callId: string;
86
264
  turn: string;
@@ -283,12 +461,18 @@ type PrincipalRef = {
283
461
  };
284
462
  /**
285
463
  * Where a message or a call came from: the person, the person while a
286
- * turn ran, an app's backend, an agent, a view, or a window's own act
287
- * outside any conversation.
464
+ * turn ran, an app's backend, an agent, a view, a window's own act
465
+ * outside any conversation, or the platform's own words to the agent.
288
466
  */
289
- type Origin = 'user' | 'steer' | 'app' | 'agent' | 'view' | 'surface';
467
+ type Origin = 'user' | 'steer' | 'app' | 'agent' | 'view' | 'surface' | 'core';
290
468
  type MountMode = 'read' | 'read-write';
291
469
  type RootKind = 'home' | 'workspace' | 'project' | 'memory' | 'skill' | 'folder' | 'file';
470
+ /**
471
+ * `manual` is Supervised, `auto` is Auto, `skip` is Full access and
472
+ * `bypass` is Bypass all permissions, which only an app's own level
473
+ * holds.
474
+ */
475
+ type PermissionLevel = 'manual' | 'auto' | 'skip' | 'bypass';
292
476
  type ModelLocation = 'local' | 'lan' | 'cloud';
293
477
  type StopReason = ('end_turn' | 'length' | 'budget' | 'cancelled' | 'error' | 'refused' | 'app_disabled' | 'app_update' | 'interrupted') | 'no_result';
294
478
  /**
@@ -341,6 +525,11 @@ type Content = {
341
525
  */
342
526
  type AgentPart = {
343
527
  text: string;
528
+ /**
529
+ * The words came as the model's reasoning, and stand as its
530
+ * answer because the reply held no other words and no call.
531
+ */
532
+ reasoning?: true;
344
533
  kind: 'text';
345
534
  } | {
346
535
  text: string;
@@ -363,7 +552,7 @@ type Authorisation = 'explicitly_no' | 'neutral' | 'explicitly_yes';
363
552
  /**
364
553
  * The rights a grant may hold; a closed list.
365
554
  */
366
- type Right = 'fs.read' | 'fs.write' | 'net.host' | 'connector' | 'capability' | 'sessions.create' | 'terminal' | 'reader';
555
+ type Right = ('fs.read' | 'fs.write' | 'net.host' | 'connector' | 'capability' | 'sessions.create' | 'terminal' | 'reader') | 'account' | 'device';
367
556
  /**
368
557
  * How a program ended: at its end, with an error or a limit, stopped, or
369
558
  * lost with a daemon that did not stop cleanly.
@@ -383,12 +572,16 @@ type AskKind = CoreAskKind | AppAskKind;
383
572
  /**
384
573
  * What a card asks about, besides an app's own question.
385
574
  */
386
- type CoreAskKind = ('tool' | 'root' | 'connector.tools' | 'connector.login' | 'app.login' | 'terminal' | 'app.dev' | 'sandbox.violation') | 'question' | 'elicitation';
575
+ type CoreAskKind = ('tool' | 'root' | 'connector.tools' | 'connector.login' | 'app.login' | 'terminal' | 'app.dev' | 'sandbox.violation') | 'pair' | 'question' | 'elicitation' | 'net.host' | 'account' | 'model.install' | 'device';
387
576
  /**
388
577
  * An app's own question kind, `app:<id>/<kind>`.
389
578
  */
390
579
  type AppAskKind = `app:${string}`;
391
580
  type PathShape = 'folder' | 'file';
581
+ /**
582
+ * A family of devices a view picks from, as the person's pick names it.
583
+ */
584
+ type DeviceFamily = 'hid' | 'usb' | 'serial' | 'bluetooth';
392
585
  type GrantScope = 'session' | 'always';
393
586
  type AskOutcome = 'answered' | 'expired' | 'closed' | 'covered';
394
587
  /**
@@ -413,10 +606,38 @@ type SurfaceOp = 'navigate' | 'evaluate' | 'screenshot' | 'show' | 'close';
413
606
  */
414
607
  type SettingValue = string | number | boolean;
415
608
  /**
416
- * The kinds a job runs on: every kind but chat.
609
+ * What a model card answers on, and what a job runs: a role word of
610
+ * the runtimes, such as chat, embedding, image or transcription.
611
+ */
612
+ type ModelKind = string;
613
+ /**
614
+ * How soon a Hearthscale Server runs a completion or a job: `interactive`
615
+ * for work a person waits on (a conversation's turn, a press or a key
616
+ * inside a view, a tool call such work started), before the `batch` work
617
+ * an app does on its own. The platform decides it; no caller names it.
417
618
  */
418
- type JobKind = 'embedding' | 'image' | 'music' | 'speech' | 'transcription';
619
+ type Priority = 'interactive' | 'batch';
419
620
  type JobStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled';
621
+ type CardState = ('ready' | 'absent' | 'unavailable') | 'downloading';
622
+ /**
623
+ * The card a request runs on, or the reason in words that none can.
624
+ */
625
+ type EffectiveModel = {
626
+ card: string;
627
+ source: ModelSource;
628
+ } | {
629
+ card: null;
630
+ reason: string;
631
+ };
632
+ /**
633
+ * Where a chosen card comes from: the session's own model, the card the
634
+ * person gave the app, the role of its kind, or, where none of them names
635
+ * one, the recommendation: an agent author's, else a Server's for its
636
+ * computer, else the first card its computer holds with room to spare. A
637
+ * utility role that names no card takes the chat choice under this last
638
+ * source.
639
+ */
640
+ type ModelSource = 'session' | 'app' | 'role' | 'recommended';
420
641
  type SessionStatus = 'idle' | 'running' | 'requires_action' | 'terminated';
421
642
  /**
422
643
  * One picture for both colour schemes, or one per scheme.
@@ -441,11 +662,11 @@ type PaymentKind = 'free' | 'optional' | 'paid';
441
662
  * An entry of `environment.network`.
442
663
  */
443
664
  type NetworkEntry = string;
444
- type Lifetime = 'service';
445
665
  /**
446
- * The kinds a model card answers on.
666
+ * An entry of `environment.listen`: a port no system service holds.
447
667
  */
448
- type ModelKind = 'chat' | 'embedding' | 'image' | 'music' | 'speech' | 'transcription';
668
+ type ListenPort = number;
669
+ type Lifetime = 'service';
449
670
  type Reasoning = 'none' | 'auto' | 'high';
450
671
  /**
451
672
  * A relative path inside the package, forward slashes, never leaving it.
@@ -458,16 +679,118 @@ type PackagePath = string;
458
679
  type AgentRoot = 'home' | 'workspace' | 'memory';
459
680
  /**
460
681
  * Who may call a tool, as MCP Apps names them: `model`, the agents;
461
- * `app`, the app's own views.
682
+ * `app`, the app's own views; and `person`, a call that a person's press
683
+ * or key in any app's view or in a window started, through apps' own code
684
+ * with no agent deciding a call on its way, such as a tool that sends,
685
+ * answers, pays or deletes.
686
+ */
687
+ type ToolVisibility = 'model' | 'app' | 'person';
688
+ /**
689
+ * How an account proves itself: an OAuth sign-in, or fields the person
690
+ * fills in, a password or a key among them.
691
+ */
692
+ type AccountKind = 'oauth' | 'fields';
693
+ /**
694
+ * What a field of an account holds: words, a secret the keychain keeps,
695
+ * a server as `host[:port]`, or an address whose host the account
696
+ * reaches.
697
+ */
698
+ type AccountFieldKind = 'text' | 'secret' | 'host' | 'url';
699
+ /**
700
+ * An event that starts the app's backend. The person's desktop client
701
+ * fires a hotkey, a tray item, a device in use, a program, a device and
702
+ * a system event; the platform fires a time, a folder and another app's
703
+ * event.
704
+ */
705
+ type TriggerDeclaration = {
706
+ name: string;
707
+ keys?: string;
708
+ hold?: boolean;
709
+ kind: 'hotkey';
710
+ } | {
711
+ name: string;
712
+ title: string;
713
+ kind: 'tray';
714
+ } | {
715
+ name: string;
716
+ kind: 'inbound';
717
+ } | {
718
+ name: string;
719
+ kind: 'time';
720
+ } | {
721
+ name: string;
722
+ kind: 'folder';
723
+ } | {
724
+ name: string;
725
+ /**
726
+ * @minItems 1
727
+ */
728
+ devices: InUseDevice[];
729
+ kind: 'device-in-use';
730
+ } | {
731
+ name: string;
732
+ /**
733
+ * @minItems 1
734
+ */
735
+ programs?: ProgramName[];
736
+ /**
737
+ * @minItems 1
738
+ */
739
+ events: ProgramEvent[];
740
+ kind: 'program';
741
+ } | {
742
+ name: string;
743
+ /**
744
+ * @minItems 1
745
+ */
746
+ filters: DeviceFilter[];
747
+ kind: 'device';
748
+ } | {
749
+ name: string;
750
+ /**
751
+ * @minItems 1
752
+ */
753
+ events: SystemEvent[];
754
+ idleSeconds?: number;
755
+ kind: 'system';
756
+ } | {
757
+ name: string;
758
+ app: string;
759
+ event: string;
760
+ kind: 'event';
761
+ };
762
+ /**
763
+ * A device another program uses.
462
764
  */
463
- type ToolVisibility = 'model' | 'app';
765
+ type InUseDevice = 'microphone' | 'camera';
766
+ /**
767
+ * The file name of a program a program trigger names.
768
+ */
769
+ type ProgramName = string;
770
+ /**
771
+ * What a program does: it starts, it ends, or its window comes to the
772
+ * front.
773
+ */
774
+ type ProgramEvent = 'start' | 'end' | 'front';
775
+ /**
776
+ * An event of the computer: `idle`, no input for `idleSeconds`;
777
+ * `active`, input again after it; `power`, a move between mains power
778
+ * and the battery; `network`, going online or offline.
779
+ */
780
+ type SystemEvent = 'idle' | 'active' | 'lock' | 'unlock' | 'sleep' | 'wake' | 'power' | 'network';
464
781
  /**
465
782
  * The namespaces `uses` may name: the backend's channel namespaces, the
466
783
  * view extensions, and `files.open`. A backend and a view reach `store`,
467
784
  * `events`, `models`, `jobs` and `peers` alike, each only when its app
468
785
  * names it here. An agent's core tools need no namespace here.
469
786
  */
470
- type Uses = 'sessions' | 'sessions.create' | 'secrets' | 'notifications' | 'readers' | 'roots' | 'exec' | 'catalogue' | 'oauth' | 'surface' | 'store' | 'events' | 'models' | 'jobs' | 'terminals' | 'files.open' | 'surfaces.open' | 'peers';
787
+ type Uses = ('sessions' | 'sessions.create' | 'secrets' | 'notifications' | 'readers' | 'roots' | 'exec' | 'catalogue' | 'surface' | 'store' | 'db' | 'events' | 'models' | 'jobs' | 'terminals' | 'files.open' | 'surfaces.open' | 'peers' | 'index' | 'capture.microphone' | 'capture.system-sound' | 'capture.program-sound' | 'capture.screen' | 'capture.window' | 'capture.camera' | 'desktop.context' | 'desktop.actions') | 'net.ask' | 'desktop.overlay' | 'input.controller' | 'system.state';
788
+ /**
789
+ * The model an introduction card downloads on this computer's Server: one
790
+ * its catalogue lists, by the id its device row gives it, or a file of a
791
+ * Hugging Face repository.
792
+ */
793
+ type OnboardingDownload = string | HubFile;
471
794
  /**
472
795
  * What a surface is: `view`, an MCP Apps document in a sandboxed frame,
473
796
  * which may reserve slots for the chat the shell draws for the app's own
@@ -558,9 +881,12 @@ type SurfaceDeclaration = {
558
881
  * a tab of a tile; `inline` draws it in a transcript, under the result of
559
882
  * each of the app's tools whose `view` names it; `modal` draws it over a
560
883
  * tile of its app when a view of the app opens it with
561
- * `hearthscale/ui/open-modal`.
884
+ * `hearthscale/ui/open-modal`; `overlay` draws it over the person's other
885
+ * programs, in a window of its own that never takes the focus, when the
886
+ * app's backend shows it with `ctx.overlay.view`; `popover` draws it at
887
+ * the tray icon, whose menu opens it, until it loses the focus.
562
888
  */
563
- type Placement = 'rail' | 'tab' | 'inline' | 'modal';
889
+ type Placement = 'rail' | 'tab' | 'inline' | 'modal' | 'overlay' | 'popover';
564
890
  /**
565
891
  * What a view surface opens: a file extension, or a scheme of web
566
892
  * addresses.
@@ -670,31 +996,71 @@ type SettingsItem = {
670
996
  */
671
997
  type McpServerDeclaration = RemoteMcpServer | BundledMcpServer;
672
998
  /**
673
- * The device capabilities a view may ask for, each a consent fact, as the
674
- * MCP Apps sandbox permissions name them.
999
+ * What a view may use of the computer, each a consent fact: a device
1000
+ * capability as the MCP Apps sandbox permissions name it, a word; or a
1001
+ * family of devices the view opens through the browser's device API,
1002
+ * with the filters that name the devices the person may pick for it.
1003
+ * Neither a filter nor a pick reaches a keyboard, a mouse, a security
1004
+ * key, a smart card, or a device of the USB mass storage, audio or video
1005
+ * classes.
675
1006
  */
676
- type ViewPermission = 'camera' | 'microphone' | 'geolocation' | 'clipboard-write';
677
- /**
678
- * The card a request runs on, or the reason in words that none can.
679
- */
680
- type EffectiveModel = {
681
- card: string;
682
- source: ModelSource;
1007
+ type ViewPermission = ('camera' | 'microphone' | 'geolocation' | 'clipboard-write') | {
1008
+ /**
1009
+ * @minItems 1
1010
+ */
1011
+ 'device.hid': HidFilter[];
683
1012
  } | {
684
- card: null;
685
- reason: string;
1013
+ /**
1014
+ * @minItems 1
1015
+ */
1016
+ 'device.usb': UsbFilter[];
1017
+ } | {
1018
+ /**
1019
+ * @minItems 1
1020
+ */
1021
+ 'device.serial': SerialFilter[];
1022
+ } | {
1023
+ /**
1024
+ * @minItems 1
1025
+ */
1026
+ 'device.bluetooth': BluetoothFilter[];
1027
+ } | {
1028
+ 'device.midi': MidiAccess;
686
1029
  };
687
1030
  /**
688
- * Where a chosen card comes from: the session's own model, the card the
689
- * person gave the app, the role of its kind, or the daemon's rule.
1031
+ * A GATT service as Web Bluetooth names it.
690
1032
  */
691
- type ModelSource = 'session' | 'app' | 'role' | 'automatic';
1033
+ type GattService = string;
1034
+ type ProviderStatus = ('ready' | 'unreachable' | 'unauthenticated' | 'error') | 'stopped';
692
1035
  /**
693
- * One frame of a streamed completion.
1036
+ * One option of a completion beyond its sampling, as `CompletionOptions`
1037
+ * names it, which a chat card takes where its provider reads it.
1038
+ */
1039
+ type CompletionOption = 'logprobs' | 'topLogprobs' | 'topK' | 'minP' | 'grammar' | 'stop' | 'seed';
1040
+ /**
1041
+ * The kinds of model an app's Discover search lists, each a task word of
1042
+ * the inference contract's `HubTask` whose models answer an app's
1043
+ * requests: chat models in GGUF, one word for each kind of media and
1044
+ * vector model a runtime of the Server installs from Hugging Face, and
1045
+ * every format a runtime of the Server reads. Draft weights, which load
1046
+ * only beside another model, are none of them, and an upscaler, which the
1047
+ * Server takes from its catalogue alone, has no word.
1048
+ */
1049
+ type DiscoverTask = 'text' | 'image' | 'transcription' | 'diarization' | 'separation' | 'speech' | 'music' | 'embedding' | 'rerank' | 'all';
1050
+ /**
1051
+ * What an app asks to install on a Hearthscale Server: a card a Server
1052
+ * lists and does not hold, by its id, or a file of a Hugging Face
1053
+ * repository.
1054
+ */
1055
+ type InstallTarget = string | HubInstall;
1056
+ /**
1057
+ * One frame of a streamed completion. A text frame of a request that
1058
+ * asks for `logprobs` carries the tokens its text is made of.
694
1059
  */
695
1060
  type CompletionDelta = {
696
1061
  text: string;
697
1062
  reasoning?: boolean;
1063
+ logprobs?: TokenLogprob[];
698
1064
  } | {
699
1065
  done: true;
700
1066
  toolCalls?: ToolCall[];
@@ -703,11 +1069,40 @@ type CompletionDelta = {
703
1069
  error?: string;
704
1070
  };
705
1071
  type CompletionStop = 'end_turn' | 'tool_calls' | 'length' | 'cancelled' | 'error';
1072
+ /**
1073
+ * A statement's parameters: in order for `?` and `?N`, or by name for
1074
+ * `:name`, `@name` and `$name`.
1075
+ */
1076
+ type DbParams = DbValue[] | {
1077
+ [k: string]: DbValue;
1078
+ };
1079
+ /**
1080
+ * One value of a statement or a row: null, a boolean (stored as 0 or 1),
1081
+ * an integer, a real, text, or bytes.
1082
+ */
1083
+ type DbValue = null | boolean | number | string | {
1084
+ $bytes: string;
1085
+ };
1086
+ /**
1087
+ * What an app reads of an account attached to it: an access token the
1088
+ * platform refreshes, or the fields, its secrets included.
1089
+ */
1090
+ type AccountCredential = {
1091
+ accessToken: string;
1092
+ kind: 'oauth';
1093
+ } | {
1094
+ fields: {
1095
+ [k: string]: string;
1096
+ };
1097
+ kind: 'fields';
1098
+ };
706
1099
  type ChatRole = 'system' | 'user' | 'assistant' | 'tool';
707
1100
  type ChatContent = string | ChatContentPart[];
708
1101
  /**
709
- * A part of a message's content: text, or a picture by its asset, which
710
- * the model registry turns into its data URL.
1102
+ * A part of a message's content: text; a picture by its asset, which the
1103
+ * model registry turns into its data URL; or untrusted text, such as a
1104
+ * mail or a page, which the registry fences as data with `source` as its
1105
+ * label and explains in the system message.
711
1106
  */
712
1107
  type ChatContentPart = {
713
1108
  text: string;
@@ -716,6 +1111,10 @@ type ChatContentPart = {
716
1111
  asset: string;
717
1112
  mediaType: string;
718
1113
  type: 'image';
1114
+ } | {
1115
+ text: string;
1116
+ source: string;
1117
+ type: 'untrusted';
719
1118
  };
720
1119
  /**
721
1120
  * A frame on `GET /terminals/:id/stream`: the snapshot once, then the
@@ -736,7 +1135,7 @@ type TerminalStatus = 'running' | 'exited';
736
1135
  * What a view's `openai/resources/write` of an opened file did: saved
737
1136
  * with the new version's ETag; nothing written because the version on
738
1137
  * disk is another, which `etag` names; or nothing written because the
739
- * bytes exceed `max_bytes`.
1138
+ * bytes exceed `maxBytes`.
740
1139
  */
741
1140
  type ResourceWriteResult = {
742
1141
  etag: string;
@@ -750,19 +1149,95 @@ type ResourceWriteResult = {
750
1149
  };
751
1150
  /**
752
1151
  * What a patch compares: the working tree with the index, the index with
753
- * `HEAD`, or the current branch with a base.
1152
+ * `HEAD`, the current branch with a base from where they part, or one
1153
+ * commit with its first parent.
1154
+ */
1155
+ type VcsScope = 'working' | 'staged' | 'branch' | 'commit';
1156
+ /**
1157
+ * What a transcription stream tells an app's backend: the open
1158
+ * segment's text so far, a segment's final text with its start and end in
1159
+ * seconds of the sound written to the stream, counted from its first
1160
+ * sample, a failure, and the end after the last segment. A stream that is
1161
+ * written every part of a capture from its first holds the capture's own
1162
+ * time: a segment's start in milliseconds is the `at` of the capture's
1163
+ * sound at that point.
1164
+ */
1165
+ type ListenEvent = {
1166
+ stream: string;
1167
+ index: number;
1168
+ text: string;
1169
+ type: 'partial';
1170
+ } | {
1171
+ stream: string;
1172
+ index: number;
1173
+ start: number;
1174
+ end: number;
1175
+ text: string;
1176
+ type: 'segment';
1177
+ } | {
1178
+ stream: string;
1179
+ index?: number;
1180
+ message: string;
1181
+ type: 'error';
1182
+ } | {
1183
+ stream: string;
1184
+ type: 'done';
1185
+ };
1186
+ /**
1187
+ * A button of a notice: one opens an `https:` address, the other tells
1188
+ * the app's backend its `id`.
1189
+ */
1190
+ type NoticeAction = {
1191
+ title: string;
1192
+ url: string;
1193
+ } | {
1194
+ title: string;
1195
+ id: string;
1196
+ };
1197
+ type HotkeyPhase = 'pressed' | 'released';
1198
+ type DeviceEvent = 'connected' | 'removed';
1199
+ type PowerSource = 'ac' | 'battery';
1200
+ /**
1201
+ * How a path changed: `created`, made or moved in; `changed`; or
1202
+ * `removed`, removed or moved out.
1203
+ */
1204
+ type FolderChange = 'created' | 'changed' | 'removed';
1205
+ /**
1206
+ * What changed about a controller.
754
1207
  */
755
- type VcsScope = 'working' | 'staged' | 'branch';
1208
+ type ControllerEvent = ('connected' | 'disconnected') | 'input';
756
1209
  /**
757
- * What one job takes.
1210
+ * The scheme of colours Hearthscale shows, which follows the system's
1211
+ * unless the person chose one.
758
1212
  */
759
- type JobInput = ImageJobInput | MusicJobInput | SpeechJobInput | TranscriptionJobInput | EmbeddingJobInput;
1213
+ type ColourScheme = 'dark' | 'light';
1214
+ /**
1215
+ * A media key: play/pause, next track, previous track or stop.
1216
+ */
1217
+ type MediaKey = 'play-pause' | 'next' | 'previous' | 'stop';
1218
+ /**
1219
+ * Where a view over other programs shows, in screen points: beside the
1220
+ * pointer where it is when the view shows; at an edge or a corner of the
1221
+ * work area of the screen the pointer is on then, `margin` points in from
1222
+ * it; or filling a rectangle of the screen.
1223
+ */
1224
+ type OverlayAnchor = {
1225
+ at: 'pointer';
1226
+ } | {
1227
+ place: ScreenPlace;
1228
+ margin?: number;
1229
+ at: 'screen';
1230
+ } | {
1231
+ x: number;
1232
+ y: number;
1233
+ width: number;
1234
+ height: number;
1235
+ at: 'rect';
1236
+ };
760
1237
  /**
761
- * How a sign-in reaches the person: `loopback` opens their browser and
762
- * comes back to this computer; `device` shows a code to enter on any
763
- * device.
1238
+ * An edge or a corner of a screen.
764
1239
  */
765
- type OAuthGrant = 'loopback' | 'device';
1240
+ type ScreenPlace = 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
766
1241
  interface ForkPoint {
767
1242
  session: string;
768
1243
  leaf: string;
@@ -787,6 +1262,19 @@ interface SessionRoot {
787
1262
  mode: MountMode;
788
1263
  kind: RootKind;
789
1264
  }
1265
+ /**
1266
+ * A turn's block and the message it follows.
1267
+ */
1268
+ interface TurnBlock {
1269
+ /**
1270
+ * The id of the message that started the turn.
1271
+ */
1272
+ after: string;
1273
+ /**
1274
+ * The block as the model reads it after that message.
1275
+ */
1276
+ text: string;
1277
+ }
790
1278
  /**
791
1279
  * One item of the composer's `@` list, as an MCP resource link: the
792
1280
  * address the app resolves it by, its name, and the words the list shows
@@ -872,7 +1360,10 @@ interface ReviewRecord {
872
1360
  /**
873
1361
  * One durable allowance. `fs.write` implies `fs.read`. A grant with
874
1362
  * `session` belongs to that session and its helpers, and ends with it.
875
- * `pin` is the hash of a tool's name, description, schemas and flags.
1363
+ * `pin` is, on a tool's grant, the hash of its name, description, schemas
1364
+ * and flags; on a `net.host` grant, the SHA-256 of the server certificate
1365
+ * the person accepted for the host, in hexadecimal, which the relay then
1366
+ * trusts for it.
876
1367
  */
877
1368
  interface Grant {
878
1369
  principal: PrincipalRef;
@@ -953,7 +1444,16 @@ interface AskFacts {
953
1444
  * so.
954
1445
  */
955
1446
  paths?: string[];
1447
+ /**
1448
+ * On a `net.host` card, the one host asked for.
1449
+ */
956
1450
  hosts?: string[];
1451
+ /**
1452
+ * On a `net.host` card: the SHA-256 of the certificate the host
1453
+ * presented, which no authority the system trusts signed, in
1454
+ * hexadecimal; allowing the host trusts it.
1455
+ */
1456
+ certificate?: string;
957
1457
  stderr?: string;
958
1458
  /**
959
1459
  * The command still runs, and the fence holds its connection to the
@@ -961,7 +1461,8 @@ interface AskFacts {
961
1461
  */
962
1462
  running?: true;
963
1463
  /**
964
- * What a backend wants a folder for, on a `root` card it raised.
1464
+ * What a backend wants a folder for, on a `root` card it raised, or
1465
+ * a host for, on a `net.host` card.
965
1466
  */
966
1467
  purpose?: string;
967
1468
  /**
@@ -973,8 +1474,9 @@ interface AskFacts {
973
1474
  */
974
1475
  text?: string;
975
1476
  /**
976
- * On an elicitation card: the form, as the JSON Schema object the
977
- * server sent.
1477
+ * On a card with a form: the form, as a JSON Schema object. An
1478
+ * elicitation card's is the one its server sent; an account card's
1479
+ * names the account's fields, a secret one `writeOnly`.
978
1480
  */
979
1481
  schema?: {
980
1482
  [k: string]: unknown;
@@ -994,6 +1496,28 @@ interface AskFacts {
994
1496
  scopes?: string[];
995
1497
  login?: string;
996
1498
  authorizationEndpoint?: string;
1499
+ /**
1500
+ * On a `pair` card: the computer that asks to drive this one, by its
1501
+ * name and its endpoint id.
1502
+ */
1503
+ computer?: string;
1504
+ endpointId?: string;
1505
+ /**
1506
+ * On a `model.install` card: the model, by the name its Server shows
1507
+ * it under, and what it takes on that Server's disk once installed.
1508
+ */
1509
+ model?: string;
1510
+ sizeBytes?: number;
1511
+ /**
1512
+ * On a `model.install` card: the Server on another computer that
1513
+ * installs the model once the person there approves; none for this
1514
+ * computer's own.
1515
+ */
1516
+ server?: string;
1517
+ /**
1518
+ * On a `device` card: the family of the devices its options offer.
1519
+ */
1520
+ family?: DeviceFamily;
997
1521
  }
998
1522
  interface ToolSummary {
999
1523
  name: string;
@@ -1022,6 +1546,21 @@ interface OptionGrant {
1022
1546
  scope: GrantScope;
1023
1547
  pin?: string;
1024
1548
  }
1549
+ /**
1550
+ * A place in an app a notice opens: a surface the app places in the rail
1551
+ * or a tab, at `path` inside a view.
1552
+ */
1553
+ interface NoticeOpen {
1554
+ surface: string;
1555
+ path?: string;
1556
+ }
1557
+ /**
1558
+ * A file opened in an app, by an address only the host resolves.
1559
+ */
1560
+ interface OpenedFile {
1561
+ name: string;
1562
+ resourceUri: string;
1563
+ }
1025
1564
  /**
1026
1565
  * What the chips of a view hold from its last `ui/update-model-context`:
1027
1566
  * the id the host gave that update, and its blocks.
@@ -1080,19 +1619,21 @@ interface Room {
1080
1619
  }
1081
1620
  /**
1082
1621
  * One job as `POST /models/jobs` answers it and `job.progress` frames it.
1083
- * The result is one asset per output: a picture, a WAV, a text or a JSON
1084
- * document, owned by the session the job ran for or else by the app.
1085
1622
  */
1086
1623
  interface Job {
1087
1624
  id: string;
1088
- kind: JobKind;
1625
+ kind: ModelKind;
1089
1626
  app: string;
1090
1627
  session?: string;
1091
1628
  /**
1092
1629
  * The tool call that submitted it, for a job a tool started.
1093
1630
  */
1094
1631
  callId?: string;
1095
- card: string;
1632
+ /**
1633
+ * The card it runs on.
1634
+ */
1635
+ model: string;
1636
+ priority: Priority;
1096
1637
  status: JobStatus;
1097
1638
  submittedAt: string;
1098
1639
  /**
@@ -1101,12 +1642,57 @@ interface Job {
1101
1642
  */
1102
1643
  waiting?: string;
1103
1644
  progress?: JobProgress;
1104
- result?: string[];
1645
+ /**
1646
+ * What a completed job made, in the order its runtime gave them.
1647
+ */
1648
+ outputs?: JobOutput[];
1649
+ /**
1650
+ * What a completed job states beside its outputs, such as the seeds
1651
+ * of its pictures or the times of a transcript's segments.
1652
+ */
1653
+ data?: {
1654
+ [k: string]: unknown;
1655
+ };
1105
1656
  error?: string;
1106
1657
  finishedAt?: string;
1107
1658
  }
1659
+ /**
1660
+ * Where a running job stands: the share done, the step it is on in its
1661
+ * runtime's words, and the asset of the latest picture of the work in
1662
+ * progress, where its runtime makes them.
1663
+ */
1108
1664
  interface JobProgress {
1109
1665
  fraction?: number;
1666
+ phase?: string;
1667
+ preview?: string;
1668
+ }
1669
+ /**
1670
+ * One output of a job, under the file name its runtime gave it: an asset
1671
+ * owned by the session the job ran for or else by the app, or a file
1672
+ * written into the folder the request names, at its path inside that
1673
+ * mount.
1674
+ */
1675
+ interface JobOutput {
1676
+ name: string;
1677
+ mediaType: string;
1678
+ asset?: string;
1679
+ path?: string;
1680
+ }
1681
+ /**
1682
+ * Where a download of a model of a Hearthscale Server stands: its card;
1683
+ * `downloading`, with what has arrived, while it runs; and once it ends,
1684
+ * the state it left the card in, with the Server's words where a failed
1685
+ * download left it absent or the model cannot run.
1686
+ */
1687
+ interface ModelDownload {
1688
+ card: string;
1689
+ state: CardState;
1690
+ /**
1691
+ * How much of a download has arrived: the inference contract's
1692
+ * `DownloadProgressBytes`.
1693
+ */
1694
+ progress?: DownloadProgressBytes;
1695
+ reason?: string;
1110
1696
  }
1111
1697
  /**
1112
1698
  * A program of a session that runs now.
@@ -1153,12 +1739,7 @@ interface Manifest {
1153
1739
  [k: string]: AgentDefinition;
1154
1740
  };
1155
1741
  models?: {
1156
- chat?: ModelNeed;
1157
- embedding?: ModelNeed;
1158
- image?: ModelNeed;
1159
- music?: ModelNeed;
1160
- speech?: ModelNeed;
1161
- transcription?: ModelNeed;
1742
+ [k: string]: ModelNeed;
1162
1743
  };
1163
1744
  tools?: ToolDeclaration[];
1164
1745
  capabilities?: Capabilities;
@@ -1167,11 +1748,27 @@ interface Manifest {
1167
1748
  * kind, each with the title its card shows: a sign-in, a handoff.
1168
1749
  */
1169
1750
  asks?: AskDeclaration[];
1751
+ /**
1752
+ * The person's accounts the app uses, by provider: the person
1753
+ * attaches each, and the app reads its credential, never its sign-in.
1754
+ */
1755
+ accounts?: AccountNeed[];
1756
+ /**
1757
+ * Kinds of account the package adds to the ones Hearthscale names.
1758
+ */
1759
+ providers?: AccountProvider[];
1170
1760
  /**
1171
1761
  * The file formats the app's backend turns into text for the read
1172
1762
  * tool, each an id and the extensions it claims.
1173
1763
  */
1174
1764
  formats?: FormatDeclaration[];
1765
+ /**
1766
+ * The events that start the app's backend and reach its
1767
+ * `ctx.triggers.on(name)`, each a consent fact.
1768
+ *
1769
+ * @minItems 1
1770
+ */
1771
+ triggers?: TriggerDeclaration[];
1175
1772
  uses?: Uses[];
1176
1773
  recommends?: string[];
1177
1774
  onboarding?: Onboarding;
@@ -1215,6 +1812,12 @@ interface Environment {
1215
1812
  * and its web surfaces. Each is a consent fact.
1216
1813
  */
1217
1814
  network?: NetworkEntry[];
1815
+ /**
1816
+ * The ports of this computer's loopback the backend listens on, for
1817
+ * programs on this computer to connect to. Each is a consent fact,
1818
+ * and a backend that listens is a service.
1819
+ */
1820
+ listen?: ListenPort[];
1218
1821
  lifetime?: Lifetime;
1219
1822
  }
1220
1823
  interface AgentDefinition {
@@ -1266,6 +1869,12 @@ interface Budget {
1266
1869
  */
1267
1870
  interface ModelNeed {
1268
1871
  required: boolean;
1872
+ /**
1873
+ * The Hugging Face tasks the kind's card states, every one of them.
1874
+ *
1875
+ * @minItems 1
1876
+ */
1877
+ tasks?: string[];
1269
1878
  }
1270
1879
  interface ToolDeclaration {
1271
1880
  name: string;
@@ -1294,13 +1903,96 @@ interface ToolDeclaration {
1294
1903
  visibility?: ToolVisibility[];
1295
1904
  }
1296
1905
  interface Capabilities {
1906
+ /**
1907
+ * The tools other apps' agents reach: declared ones, or ones the
1908
+ * app's MCP servers serve.
1909
+ */
1297
1910
  tools?: string[];
1298
1911
  skills?: PackagePath[];
1912
+ /**
1913
+ * The events the app's backend publishes with `ctx.events.publish`,
1914
+ * which other apps hear through an `event` trigger. Each is a
1915
+ * consent fact.
1916
+ *
1917
+ * @minItems 1
1918
+ */
1919
+ events?: EventOffer[];
1920
+ }
1921
+ /**
1922
+ * An event an app offers: its name, what it means, and the JSON Schema
1923
+ * of the data each one carries, which the platform holds every publish
1924
+ * to.
1925
+ */
1926
+ interface EventOffer {
1927
+ name: string;
1928
+ description: string;
1929
+ data: {
1930
+ [k: string]: unknown;
1931
+ };
1299
1932
  }
1300
1933
  interface AskDeclaration {
1301
1934
  kind: string;
1302
1935
  title: string;
1303
1936
  }
1937
+ /**
1938
+ * An account an app's manifest uses: the provider, the OAuth scopes the
1939
+ * app asks for beyond the provider's own, and why, as the person reads
1940
+ * it on the enable card and the account card.
1941
+ */
1942
+ interface AccountNeed {
1943
+ provider: string;
1944
+ scopes?: string[];
1945
+ purpose: string;
1946
+ }
1947
+ /**
1948
+ * A kind of account. `hosts` are the servers every account of it
1949
+ * reaches; a `host` or `url` field adds its own.
1950
+ */
1951
+ interface AccountProvider {
1952
+ id: string;
1953
+ name: string;
1954
+ kind: AccountKind;
1955
+ oauth?: ProviderOAuth;
1956
+ fields?: AccountField[];
1957
+ hosts: NetworkEntry[];
1958
+ }
1959
+ /**
1960
+ * Where an OAuth account signs in: the issuer's endpoints, the client
1961
+ * the service registered for Hearthscale, the scopes every sign-in asks
1962
+ * for, the OpenID Connect `userinfo` address that names the account, and
1963
+ * the service's own fields on the authorization address, such as
1964
+ * `access_type`.
1965
+ */
1966
+ interface ProviderOAuth {
1967
+ issuer: string;
1968
+ authorization: string;
1969
+ token: string;
1970
+ revocation?: string;
1971
+ userinfo: string;
1972
+ clientId: string;
1973
+ /**
1974
+ * For a service that demands one even from a desktop client, where
1975
+ * it is no secret.
1976
+ */
1977
+ clientSecret?: string;
1978
+ scopes: string[];
1979
+ params?: {
1980
+ [k: string]: string;
1981
+ };
1982
+ }
1983
+ /**
1984
+ * One field of an account the person fills in. The first `text` field
1985
+ * names the account.
1986
+ */
1987
+ interface AccountField {
1988
+ name: string;
1989
+ label: string;
1990
+ kind: AccountFieldKind;
1991
+ /**
1992
+ * The person may leave it empty.
1993
+ */
1994
+ optional?: boolean;
1995
+ }
1304
1996
  interface FormatDeclaration {
1305
1997
  id: string;
1306
1998
  /**
@@ -1308,6 +2000,13 @@ interface FormatDeclaration {
1308
2000
  */
1309
2001
  extensions: string[];
1310
2002
  }
2003
+ /**
2004
+ * The devices a device trigger hears: a vendor's, or one product of it.
2005
+ */
2006
+ interface DeviceFilter {
2007
+ vendorId: string;
2008
+ productId?: string;
2009
+ }
1311
2010
  interface Onboarding {
1312
2011
  version: number;
1313
2012
  /**
@@ -1320,17 +2019,33 @@ interface OnboardingCard {
1320
2019
  text?: string;
1321
2020
  image?: ServedPicture;
1322
2021
  rows?: OnboardingRow[];
1323
- /**
1324
- * A model this computer's engine can pull, by the id its device row
1325
- * gives it.
1326
- */
1327
- download?: string;
2022
+ download?: OnboardingDownload;
1328
2023
  }
1329
2024
  interface OnboardingRow {
1330
2025
  icon: ChatIconRole;
1331
2026
  title: string;
1332
2027
  text: string;
1333
2028
  }
2029
+ /**
2030
+ * A file of a Hugging Face repository that an app's introduction card
2031
+ * installs on this computer's Server: a `HubInstall` without the Server.
2032
+ */
2033
+ interface HubFile {
2034
+ kind: ModelKind;
2035
+ repo: string;
2036
+ file: string;
2037
+ projector?: string;
2038
+ companions?: HubCompanion[];
2039
+ }
2040
+ /**
2041
+ * The file that fills one companion role of a Hugging Face install: a
2042
+ * weights file of any repository, as a candidate's `requires` offers it.
2043
+ */
2044
+ interface HubCompanion {
2045
+ role: string;
2046
+ repo: string;
2047
+ file: string;
2048
+ }
1334
2049
  /**
1335
2050
  * A right-click entry of the app's rail button: a call of one of the
1336
2051
  * app's tools with these arguments, `{}` when absent. A result that names
@@ -1374,10 +2089,32 @@ interface Mentions {
1374
2089
  tool: string;
1375
2090
  }
1376
2091
  /**
1377
- * A remote MCP server, by its address.
2092
+ * A remote MCP server, by its address, with the sign-in its service
2093
+ * documents where the server publishes no OAuth metadata.
1378
2094
  */
1379
2095
  interface RemoteMcpServer {
1380
2096
  url: string;
2097
+ oauth?: RemoteOAuth;
2098
+ }
2099
+ /**
2100
+ * The sign-in of a remote MCP server that publishes no OAuth metadata, as
2101
+ * its service documents it: the public client the service issued, its
2102
+ * endpoints, and the scopes a sign-in asks for. With a device endpoint the person types a code at the service;
2103
+ * without one the browser comes back to this computer, which needs the
2104
+ * authorization endpoint.
2105
+ */
2106
+ interface RemoteOAuth {
2107
+ clientId: string;
2108
+ endpoints: OAuthEndpoints;
2109
+ scopes?: string[];
2110
+ }
2111
+ /**
2112
+ * The endpoints of an authorization server that publishes no metadata.
2113
+ */
2114
+ interface OAuthEndpoints {
2115
+ authorization?: string;
2116
+ token: string;
2117
+ device?: string;
1381
2118
  }
1382
2119
  /**
1383
2120
  * A JavaScript file in the package the platform runs in the app's
@@ -1388,6 +2125,190 @@ interface BundledMcpServer {
1388
2125
  entry: string;
1389
2126
  env?: string[];
1390
2127
  }
2128
+ /**
2129
+ * The HID devices a filter names: a vendor's, one product of it, the
2130
+ * devices of a usage page or of one usage of it, or both.
2131
+ */
2132
+ interface HidFilter {
2133
+ vendorId?: string;
2134
+ productId?: string;
2135
+ usagePage?: string;
2136
+ usage?: string;
2137
+ }
2138
+ /**
2139
+ * The USB devices a filter names: a vendor's, one product of it, the
2140
+ * devices of a class, or both.
2141
+ */
2142
+ interface UsbFilter {
2143
+ vendorId?: string;
2144
+ productId?: string;
2145
+ classCode?: string;
2146
+ }
2147
+ /**
2148
+ * The serial ports a filter names: those of a USB vendor's devices, or of
2149
+ * one product of it.
2150
+ */
2151
+ interface SerialFilter {
2152
+ usbVendorId: string;
2153
+ usbProductId?: string;
2154
+ }
2155
+ /**
2156
+ * The Bluetooth devices a filter names: those that offer every one of
2157
+ * the GATT services, those whose name starts with the prefix, or both.
2158
+ */
2159
+ interface BluetoothFilter {
2160
+ /**
2161
+ * @minItems 1
2162
+ */
2163
+ services?: GattService[];
2164
+ namePrefix?: string;
2165
+ }
2166
+ /**
2167
+ * What MIDI a view takes: the notes and controls of every port, and with
2168
+ * `sysex` the system exclusive messages, which can change a device's
2169
+ * settings and its firmware.
2170
+ */
2171
+ interface MidiAccess {
2172
+ sysex?: boolean;
2173
+ }
2174
+ /**
2175
+ * One model card: `<provider>/<model>`, what it answers on and the window
2176
+ * one request gets, as its provider publishes them. A card with no window
2177
+ * is listed and cannot run.
2178
+ */
2179
+ interface ModelCard {
2180
+ id: string;
2181
+ kind: ModelKind;
2182
+ provider: string;
2183
+ label: string;
2184
+ contextTokens?: number;
2185
+ params?: number;
2186
+ /**
2187
+ * The size of the model's files, where its provider states it.
2188
+ */
2189
+ sizeBytes?: number;
2190
+ /**
2191
+ * The Hugging Face task words of the model, where its provider
2192
+ * states them.
2193
+ */
2194
+ tasks?: string[];
2195
+ vision?: boolean;
2196
+ tools?: boolean;
2197
+ /**
2198
+ * Whether the model reasons before it answers, where its provider
2199
+ * states it.
2200
+ */
2201
+ reasoning?: boolean;
2202
+ /**
2203
+ * The job kinds the card runs, by kind word, each with the input it
2204
+ * takes.
2205
+ */
2206
+ jobs?: {
2207
+ /**
2208
+ * One job kind a card runs: the input it takes, a JSON Schema object, as
2209
+ * the inference contract's `JobSpec` states it. A property of
2210
+ * `"format": "asset"`, alone or as the items of an array, takes the id of
2211
+ * an asset its app holds, whose media type fits the property's
2212
+ * `contentMediaType`.
2213
+ */
2214
+ [k: string]: JobSpec;
2215
+ };
2216
+ /**
2217
+ * The completion options a chat card's provider reads; a completion
2218
+ * that names another is refused before it is sent.
2219
+ */
2220
+ options?: CompletionOption[];
2221
+ location: ModelLocation;
2222
+ state: CardState;
2223
+ /**
2224
+ * The model's publisher as a Server resolves it; cards of other
2225
+ * providers have none.
2226
+ */
2227
+ identity?: ModelIdentity;
2228
+ /**
2229
+ * Why an unavailable card cannot run, or why the last download of an
2230
+ * absent one failed, in its provider's words, where the provider
2231
+ * states it.
2232
+ */
2233
+ reason?: string;
2234
+ /**
2235
+ * What loading the card's model, or a job of it, takes now, where a
2236
+ * Server plans it.
2237
+ */
2238
+ memory?: MemoryPlan;
2239
+ /**
2240
+ * How much of a downloading card's model has arrived, where its
2241
+ * Server reports it.
2242
+ */
2243
+ progress?: DownloadProgressBytes;
2244
+ }
2245
+ /**
2246
+ * A Hearthscale Server this computer names, as `ctx.models.servers` and
2247
+ * `GET /models/servers` list it: its id, which the ids of its cards start
2248
+ * with; its name; whether it is this computer's own; and whether it
2249
+ * serves now, with its words where it does not.
2250
+ */
2251
+ interface ModelServer {
2252
+ id: string;
2253
+ name: string;
2254
+ here: boolean;
2255
+ status: ProviderStatus;
2256
+ message?: string;
2257
+ }
2258
+ /**
2259
+ * A search of a Hearthscale Server's Discover: the words it looks for,
2260
+ * where there are any, the kind of model it lists, and its order,
2261
+ * trending first where it names none.
2262
+ */
2263
+ interface HubSearch {
2264
+ search?: string;
2265
+ task: DiscoverTask;
2266
+ /**
2267
+ * The order of a Discover search: the inference contract's `HubSort`.
2268
+ */
2269
+ sort?: HubSort;
2270
+ }
2271
+ /**
2272
+ * A file of a Hugging Face repository to install on a Hearthscale Server,
2273
+ * as its Discover lists the repository: the Server, by its id; the kind
2274
+ * the app runs the model as, which names the install on that Server; the
2275
+ * repository and the file; the vision projector where the file has more
2276
+ * than one to choose from; and a file for each companion role the
2277
+ * repository does not supply.
2278
+ */
2279
+ interface HubInstall {
2280
+ server: string;
2281
+ kind: ModelKind;
2282
+ repo: string;
2283
+ file: string;
2284
+ projector?: string;
2285
+ companions?: HubCompanion[];
2286
+ }
2287
+ /**
2288
+ * The answer of an install an app asked for: the card the model installs
2289
+ * as, once the person allowed it, or null where they did not.
2290
+ */
2291
+ interface ModelInstalled {
2292
+ card: string | null;
2293
+ }
2294
+ /**
2295
+ * One token of an answer: its text, its log probability, and the
2296
+ * likeliest tokens the model weighed in its place, as many as the
2297
+ * request's `topLogprobs` asks.
2298
+ */
2299
+ interface TokenLogprob {
2300
+ token: string;
2301
+ logprob: number;
2302
+ top: TokenAlternative[];
2303
+ }
2304
+ /**
2305
+ * A token the model weighed in another's place, with its log
2306
+ * probability.
2307
+ */
2308
+ interface TokenAlternative {
2309
+ token: string;
2310
+ logprob: number;
2311
+ }
1391
2312
  /**
1392
2313
  * What `net.fetch` takes.
1393
2314
  */
@@ -1398,9 +2319,15 @@ interface FetchParams {
1398
2319
  [k: string]: string;
1399
2320
  };
1400
2321
  body?: string;
2322
+ /**
2323
+ * The longest the request may take, its redirects included, in
2324
+ * milliseconds: 1 to 600000.
2325
+ */
2326
+ timeoutMs?: number;
1401
2327
  }
1402
2328
  /**
1403
- * What `net.fetch` answers.
2329
+ * What `net.fetch` answers: `url` is the address that answered, after
2330
+ * the redirects.
1404
2331
  */
1405
2332
  interface FetchAnswer {
1406
2333
  status: number;
@@ -1408,6 +2335,27 @@ interface FetchAnswer {
1408
2335
  [k: string]: string;
1409
2336
  };
1410
2337
  body: string;
2338
+ url: string;
2339
+ }
2340
+ /**
2341
+ * What a statement changed: the rows, and the row id it last inserted.
2342
+ */
2343
+ interface DbChange {
2344
+ changes: number;
2345
+ lastInsertRowid: number;
2346
+ }
2347
+ /**
2348
+ * An account as an app it is attached to reads it: its kind, its name,
2349
+ * the servers it reaches, and whether the app's sign-in of it ended and
2350
+ * needs a new one. No other app's use of it shows.
2351
+ */
2352
+ interface AppAccount {
2353
+ id: string;
2354
+ provider: string;
2355
+ providerName: string;
2356
+ name: string;
2357
+ hosts: string[];
2358
+ lapsed: boolean;
1411
2359
  }
1412
2360
  /**
1413
2361
  * The body of `POST /models/complete` and of one model call of a turn.
@@ -1429,6 +2377,23 @@ interface CompletionRequest {
1429
2377
  * read again rather than partly from an earlier request's cache.
1430
2378
  */
1431
2379
  repeatable?: true;
2380
+ /**
2381
+ * The context, in tokens, the request needs at least: a Hearthscale
2382
+ * Server loads the model with at least this many, or refuses the
2383
+ * request in words before it runs. Other providers serve the window
2384
+ * they have.
2385
+ */
2386
+ context?: number;
2387
+ /**
2388
+ * A usable chat card an app's own completion runs on; absent, the
2389
+ * card the app runs chat on. A turn's model call names none.
2390
+ */
2391
+ model?: string;
2392
+ /**
2393
+ * What an app's own completion asks of the runtime beyond its
2394
+ * sampling. A turn's model call names none.
2395
+ */
2396
+ options?: CompletionOptions;
1432
2397
  }
1433
2398
  /**
1434
2399
  * One message of a request, in the OpenAI v1 roles.
@@ -1461,6 +2426,47 @@ interface CompletionFormat {
1461
2426
  [k: string]: unknown;
1462
2427
  };
1463
2428
  }
2429
+ /**
2430
+ * What a completion asks of the runtime beyond its sampling. Each option
2431
+ * runs only on a card whose `options` names it.
2432
+ */
2433
+ interface CompletionOptions {
2434
+ /**
2435
+ * The log probability of each token of the answer, on the text
2436
+ * frames.
2437
+ */
2438
+ logprobs?: boolean;
2439
+ /**
2440
+ * How many of the likeliest other tokens each token names, with
2441
+ * `logprobs`.
2442
+ */
2443
+ topLogprobs?: number;
2444
+ /**
2445
+ * Samples among this many likeliest tokens only; 0 turns it off.
2446
+ */
2447
+ topK?: number;
2448
+ /**
2449
+ * Leaves out every token less likely than this share of the likeliest
2450
+ * one.
2451
+ */
2452
+ minP?: number;
2453
+ /**
2454
+ * A GBNF grammar the answer follows; a request with `format` names
2455
+ * none.
2456
+ */
2457
+ grammar?: string;
2458
+ /**
2459
+ * Texts that end the answer where it would write them.
2460
+ *
2461
+ * @minItems 1
2462
+ */
2463
+ stop?: string[];
2464
+ /**
2465
+ * The sampler's seed: the same request with the same seed gives the
2466
+ * same answer as far as the runtime allows.
2467
+ */
2468
+ seed?: number;
2469
+ }
1464
2470
  /**
1465
2471
  * What a conversation's requests have spent, by the log.
1466
2472
  */
@@ -1497,13 +2503,6 @@ interface ProjectRecord {
1497
2503
  createdAt: string;
1498
2504
  folder: string;
1499
2505
  }
1500
- /**
1501
- * A file opened in an app, by an address only the host resolves.
1502
- */
1503
- interface OpenedFile {
1504
- name: string;
1505
- resourceUri: string;
1506
- }
1507
2506
  /**
1508
2507
  * One folder as `GET /fs/list` answers it.
1509
2508
  */
@@ -1524,6 +2523,10 @@ interface FsRead {
1524
2523
  size: number;
1525
2524
  binary: boolean;
1526
2525
  text?: string;
2526
+ /**
2527
+ * Set when the text holds only the file's first part.
2528
+ */
2529
+ cut?: true;
1527
2530
  }
1528
2531
  /**
1529
2532
  * What one repository answers about itself.
@@ -1560,6 +2563,35 @@ interface VcsDiff {
1560
2563
  interface VcsFile {
1561
2564
  text: string;
1562
2565
  }
2566
+ /**
2567
+ * `GET /vcs/log`: the commits of the current branch that a base does not
2568
+ * hold, newest first.
2569
+ */
2570
+ interface VcsLog {
2571
+ commits: VcsCommit[];
2572
+ /**
2573
+ * The branch holds more commits than the log answers.
2574
+ */
2575
+ truncated: boolean;
2576
+ }
2577
+ /**
2578
+ * One commit as a log lists it.
2579
+ */
2580
+ interface VcsCommit {
2581
+ /**
2582
+ * The commit's full id.
2583
+ */
2584
+ sha: string;
2585
+ /**
2586
+ * The first line of its message.
2587
+ */
2588
+ subject: string;
2589
+ author: string;
2590
+ /**
2591
+ * When it was made, as an ISO 8601 date.
2592
+ */
2593
+ date: string;
2594
+ }
1563
2595
  /**
1564
2596
  * One terminal as `POST /terminals` answers it and as its stream's first
1565
2597
  * frame carries it.
@@ -1653,6 +2685,10 @@ interface VcsDiffQuery {
1653
2685
  * The ref a `branch` scope compares the current branch against.
1654
2686
  */
1655
2687
  base?: string;
2688
+ /**
2689
+ * The full id of the commit a `commit` scope reads.
2690
+ */
2691
+ commit?: string;
1656
2692
  /**
1657
2693
  * Root-relative pathspecs the patch is narrowed to.
1658
2694
  */
@@ -1661,49 +2697,59 @@ interface VcsDiffQuery {
1661
2697
  /**
1662
2698
  * `GET /vcs/file`: one file whole, as a scope's new side holds it, which
1663
2699
  * the diff panel's unmodified runs are read from: the working tree's copy
1664
- * for `working`, the index's for `staged` and `HEAD`'s for `branch`.
2700
+ * for `working`, the index's for `staged`, `HEAD`'s for `branch` and the
2701
+ * commit's for `commit`.
1665
2702
  */
1666
2703
  interface VcsFileQuery {
1667
2704
  root: string;
1668
2705
  scope: VcsScope;
2706
+ /**
2707
+ * The full id of the commit a `commit` scope reads.
2708
+ */
2709
+ commit?: string;
1669
2710
  /**
1670
2711
  * Relative to the repository's top, as the patch names it.
1671
2712
  */
1672
2713
  path: string;
1673
2714
  }
1674
2715
  /**
1675
- * What one job of each kind takes, by kind. Audio and images cross as
1676
- * assets.
2716
+ * One job an app asks for: the kind, the input the card's schema for
2717
+ * the kind takes, the card it runs on where the caller names one, and the
2718
+ * folder of one of the app's writable mounts its outputs are written to
2719
+ * where it names one.
1677
2720
  */
1678
- interface JobInputs {
1679
- image: ImageJobInput;
1680
- music: MusicJobInput;
1681
- speech: SpeechJobInput;
1682
- transcription: TranscriptionJobInput;
1683
- embedding: EmbeddingJobInput;
1684
- }
1685
- interface ImageJobInput {
1686
- prompt: string;
1687
- size?: string;
1688
- }
1689
- interface MusicJobInput {
1690
- prompt: string;
1691
- seconds: number;
1692
- lyrics?: string;
1693
- }
1694
- interface SpeechJobInput {
1695
- text: string;
1696
- voice?: string;
2721
+ interface JobRequest {
2722
+ kind: ModelKind;
2723
+ input: {
2724
+ [k: string]: unknown;
2725
+ };
2726
+ /**
2727
+ * A usable card of the kind; absent, the card the app runs the kind
2728
+ * on.
2729
+ */
2730
+ model?: string;
2731
+ save?: MountPath;
1697
2732
  }
1698
2733
  /**
1699
- * `audio` is an asset.
2734
+ * A path inside a mount, as the backend names files: the mount's handle
2735
+ * and the path under it.
1700
2736
  */
1701
- interface TranscriptionJobInput {
1702
- audio: string;
1703
- language?: string;
2737
+ interface MountPath {
2738
+ root: string;
2739
+ path: string;
1704
2740
  }
1705
- interface EmbeddingJobInput {
1706
- texts: string[];
2741
+ /**
2742
+ * The cards an app's backend or view may run a request on or install, as
2743
+ * `ctx.models.list` and `hearthscale/models/list` answer them: every card
2744
+ * of the kind, the task and the state asked, in catalogue order, the
2745
+ * usable ones where no state is asked, and the app's choice of each
2746
+ * kind, by kind word.
2747
+ */
2748
+ interface ModelList {
2749
+ cards: ModelCard[];
2750
+ chosen: {
2751
+ [k: string]: EffectiveModel;
2752
+ };
1707
2753
  }
1708
2754
  /**
1709
2755
  * The executor's answer to a command: what the command answers the body,
@@ -1718,14 +2764,6 @@ interface SurfaceResult {
1718
2764
  shown?: boolean;
1719
2765
  error?: string;
1720
2766
  }
1721
- /**
1722
- * A path inside a mount, as the backend names files: the mount's handle
1723
- * and the path under it.
1724
- */
1725
- interface MountPath {
1726
- root: string;
1727
- path: string;
1728
- }
1729
2767
  /**
1730
2768
  * What a tool body answers: content for the model and the view that
1731
2769
  * renders the result.
@@ -1804,112 +2842,366 @@ interface TurnOutcome {
1804
2842
  result?: Structured;
1805
2843
  }
1806
2844
  /**
1807
- * One enabled app as `apps.list` lists it.
2845
+ * A document an app puts in the shared index: its source, which names it
2846
+ * for the app and replaces what was put under it before, its title, and
2847
+ * its text by page.
2848
+ */
2849
+ interface IndexDocument {
2850
+ source: string;
2851
+ title?: string;
2852
+ pages: IndexPage[];
2853
+ }
2854
+ /**
2855
+ * One page of a document's text, with its number where the document has
2856
+ * pages.
2857
+ */
2858
+ interface IndexPage {
2859
+ text: string;
2860
+ page?: number;
2861
+ }
2862
+ /**
2863
+ * One answer of a search of the shared index: the passage, the document
2864
+ * it came from and its page, and how well it answers the query.
2865
+ */
2866
+ interface IndexHit {
2867
+ source: string;
2868
+ title?: string;
2869
+ page?: number;
2870
+ text: string;
2871
+ score: number;
2872
+ }
2873
+ /**
2874
+ * One enabled app as `apps.list` lists it.
2875
+ */
2876
+ interface AppListing {
2877
+ id: string;
2878
+ name: string;
2879
+ description: string;
2880
+ /**
2881
+ * The icon's file in the app's package per colour scheme, which a page
2882
+ * loads from `/apps/<id>/ui/<file>`; null when it has none.
2883
+ */
2884
+ icon: SchemedIcon | null;
2885
+ agent: boolean;
2886
+ capabilities: string[];
2887
+ }
2888
+ /**
2889
+ * One chat card an app's sessions may run on, as `models.for` lists it.
2890
+ */
2891
+ interface ModelListing {
2892
+ id: string;
2893
+ name: string;
2894
+ provider: string;
2895
+ }
2896
+ /**
2897
+ * One project as `projects.list` lists it.
2898
+ */
2899
+ interface ProjectListing {
2900
+ id: string;
2901
+ name: string;
2902
+ folder: string;
2903
+ }
2904
+ /**
2905
+ * An app's own question to the person during a tool call: a choice, a
2906
+ * sign-in, a handoff; `kind` is one the manifest's `asks` declares. It
2907
+ * widens nothing.
2908
+ */
2909
+ interface AppQuestion {
2910
+ kind: string;
2911
+ text: string;
2912
+ }
2913
+ /**
2914
+ * The person's answer to an app's question.
2915
+ */
2916
+ interface AppAnswer {
2917
+ allow: boolean;
2918
+ option?: string;
2919
+ }
2920
+ /**
2921
+ * A durable entry in one of the app's own sessions, or a transient event
2922
+ * for the app's views.
2923
+ */
2924
+ interface AppEvent {
2925
+ name: string;
2926
+ session?: string;
2927
+ data: unknown;
2928
+ durable: boolean;
2929
+ context?: string;
2930
+ }
2931
+ /**
2932
+ * An OS notification an app asks for. A press opens `session`, a
2933
+ * conversation of the app or one it started, or else the place `open`
2934
+ * names in the app's own surface.
2935
+ */
2936
+ interface AppNotice {
2937
+ title: string;
2938
+ body: string;
2939
+ session?: string;
2940
+ open?: NoticeOpen;
2941
+ /**
2942
+ * At most two buttons, where the system draws them.
2943
+ */
2944
+ actions?: NoticeAction[];
2945
+ }
2946
+ /**
2947
+ * A skill an app adds while it runs, with `ctx.skills.add`: its name, a
2948
+ * lowercase kebab-case word of at most 64 characters; its title and its
2949
+ * description, each one line; and the body of its `SKILL.md`, the
2950
+ * instructions an agent reads. The app's own agents carry it, and the
2951
+ * composer's `/` lists it, as they do the skills of its package.
2952
+ */
2953
+ interface AppSkill {
2954
+ name: string;
2955
+ title: string;
2956
+ description: string;
2957
+ body: string;
2958
+ }
2959
+ /**
2960
+ * A hotkey trigger of an app, as its backend reads it with
2961
+ * `ctx.triggers.hotkeys`.
2962
+ */
2963
+ interface HotkeyState {
2964
+ name: string;
2965
+ /**
2966
+ * The keys that fire the hotkey now, the person's or else the
2967
+ * declared ones; none where neither names any, or where another
2968
+ * app's hotkey holds them.
2969
+ */
2970
+ keys?: string;
2971
+ /**
2972
+ * The app whose hotkey holds the keys this one names.
2973
+ */
2974
+ takenBy?: string;
2975
+ }
2976
+ /**
2977
+ * What a hotkey fires with. A `hold` hotkey fires `pressed` and
2978
+ * `released`; any other only `pressed`.
2979
+ */
2980
+ interface HotkeyFire {
2981
+ phase: HotkeyPhase;
2982
+ }
2983
+ /**
2984
+ * What a device-in-use trigger fires with: one of its devices, and
2985
+ * whether another program uses it now.
2986
+ */
2987
+ interface InUseFire {
2988
+ device: InUseDevice;
2989
+ inUse: boolean;
2990
+ }
2991
+ /**
2992
+ * What a program trigger fires with: one of its events, and the
2993
+ * program's file name.
2994
+ */
2995
+ interface ProgramFire {
2996
+ event: ProgramEvent;
2997
+ program: string;
2998
+ }
2999
+ /**
3000
+ * What a device trigger fires with: the device's ids, which one of its
3001
+ * filters names, and the name the device gives itself.
3002
+ */
3003
+ interface DeviceFire {
3004
+ event: DeviceEvent;
3005
+ vendorId: string;
3006
+ productId: string;
3007
+ name?: string;
3008
+ }
3009
+ /**
3010
+ * What a system trigger fires with: one of its events, the power source
3011
+ * after a `power` event, and whether the computer is online after a
3012
+ * `network` event.
3013
+ */
3014
+ interface SystemFire {
3015
+ event: SystemEvent;
3016
+ power?: PowerSource;
3017
+ online?: boolean;
3018
+ }
3019
+ /**
3020
+ * What a time trigger fires with: the alarm that came due, and the data
3021
+ * it was set with.
3022
+ */
3023
+ interface AlarmFire {
3024
+ alarm: string;
3025
+ data?: unknown;
3026
+ }
3027
+ /**
3028
+ * What a folder trigger fires with: the mount, the path inside it that
3029
+ * changed, and how. With `many`, the path is the watched place, which
3030
+ * changed in more places than fire one by one.
3031
+ */
3032
+ interface FolderFire {
3033
+ root: string;
3034
+ path: string;
3035
+ change: FolderChange;
3036
+ many?: true;
3037
+ }
3038
+ /**
3039
+ * What an event trigger fires with: the app that published, its event,
3040
+ * and the data, which matches the schema that app's offer names.
3041
+ */
3042
+ interface EventFire {
3043
+ app: string;
3044
+ event: string;
3045
+ data: unknown;
3046
+ }
3047
+ /**
3048
+ * An alarm a backend sets with `ctx.alarms.set`: the time trigger it
3049
+ * fires, the first time, a repeat in minutes on a fixed schedule from
3050
+ * that first time, and the data it fires with. Without `at` the first
3051
+ * fire is `every` minutes from now.
1808
3052
  */
1809
- interface AppListing {
1810
- id: string;
1811
- name: string;
1812
- description: string;
3053
+ interface AlarmRequest {
3054
+ trigger: string;
1813
3055
  /**
1814
- * The icon's file in the app's package per colour scheme, which a page
1815
- * loads from `/apps/<id>/ui/<file>`; null when it has none.
3056
+ * An ISO 8601 time with its offset, such as `Date.toISOString()`
3057
+ * writes.
1816
3058
  */
1817
- icon: SchemedIcon | null;
1818
- agent: boolean;
1819
- capabilities: string[];
1820
- }
1821
- /**
1822
- * One chat card an app's sessions may run on, as `models.for` lists it.
1823
- */
1824
- interface ModelListing {
1825
- id: string;
1826
- name: string;
1827
- provider: string;
3059
+ at?: string;
3060
+ every?: number;
3061
+ data?: unknown;
1828
3062
  }
1829
3063
  /**
1830
- * One project as `projects.list` lists it.
3064
+ * An alarm as `ctx.alarms` lists it; `at` is the next time it fires, in
3065
+ * UTC.
1831
3066
  */
1832
- interface ProjectListing {
3067
+ interface Alarm {
1833
3068
  id: string;
1834
- name: string;
1835
- folder: string;
3069
+ trigger: string;
3070
+ at: string;
3071
+ every?: number;
3072
+ data?: unknown;
1836
3073
  }
1837
3074
  /**
1838
- * An app's own question to the person during a tool call: a choice, a
1839
- * sign-in, a handoff; `kind` is one the manifest's `asks` declares. It
1840
- * widens nothing.
3075
+ * How the person reads dates and numbers on the computer they use: a
3076
+ * BCP 47 locale, with the hour cycle (`-u-hc-`) and the first day of the
3077
+ * week (`-u-fw-`) where the system's settings state them, and the IANA
3078
+ * time zone.
1841
3079
  */
1842
- interface AppQuestion {
1843
- kind: string;
1844
- text: string;
3080
+ interface Region {
3081
+ locale: string;
3082
+ timeZone: string;
1845
3083
  }
1846
3084
  /**
1847
- * The person's answer to an app's question.
3085
+ * A device a capture can take, as `ctx.capture.devices` lists it: a
3086
+ * microphone or a camera by the window page's id, a screen by its
3087
+ * display, a window by its capture source, and a program by its process.
3088
+ * The ids hold while the computer's window runs.
1848
3089
  */
1849
- interface AppAnswer {
1850
- allow: boolean;
1851
- option?: string;
3090
+ interface CaptureDevice {
3091
+ id: string;
3092
+ /**
3093
+ * The device's name, a window's title, or a program's file name.
3094
+ */
3095
+ name: string;
3096
+ /**
3097
+ * The file name of the program a window belongs to, where it is
3098
+ * known.
3099
+ */
3100
+ program?: string;
1852
3101
  }
1853
3102
  /**
1854
- * A durable entry in one of the app's own sessions, or a transient event
1855
- * for the app's views.
3103
+ * What other programs show, as far as the computer can read it.
1856
3104
  */
1857
- interface AppEvent {
1858
- name: string;
1859
- session?: string;
1860
- data: unknown;
1861
- durable: boolean;
1862
- context?: string;
3105
+ interface DesktopContext {
3106
+ /**
3107
+ * The program in front.
3108
+ */
3109
+ program?: string;
3110
+ /**
3111
+ * The title of the window in front.
3112
+ */
3113
+ window?: string;
3114
+ /**
3115
+ * The selected text.
3116
+ */
3117
+ selection?: string;
3118
+ clipboard?: string;
3119
+ pointer?: ScreenPoint;
1863
3120
  }
1864
3121
  /**
1865
- * An OS notification an app asks for.
3122
+ * A point on the screen, in the screen's own pixels.
1866
3123
  */
1867
- interface AppNotice {
1868
- title: string;
1869
- body: string;
1870
- session?: string;
3124
+ interface ScreenPoint {
3125
+ x: number;
3126
+ y: number;
1871
3127
  }
1872
3128
  /**
1873
- * A sign-in to an online service of the app's own, with the app's own
1874
- * client registered at that service.
3129
+ * A game controller, as `ctx.controllers.list` answers it and each of its
3130
+ * changes carries it.
1875
3131
  */
1876
- interface OAuthLogin {
3132
+ interface Controller {
1877
3133
  /**
1878
- * The authorization server's identifier, an https address without a
1879
- * query or a fragment; its metadata names the endpoints unless
1880
- * `endpoints` does.
3134
+ * The controller's id while the computer's window runs.
1881
3135
  */
1882
- issuer: string;
3136
+ id: string;
3137
+ name: string;
1883
3138
  /**
1884
- * Absent when the server registers clients itself (RFC 7591).
3139
+ * Whether it rumbles.
1885
3140
  */
1886
- clientId?: string;
3141
+ rumble: boolean;
1887
3142
  /**
1888
- * For a server that demands one even from a desktop client.
3143
+ * Each button it has, by its name, from 0, up, to 1, fully down; a
3144
+ * trigger that is pressed in part is between.
1889
3145
  */
1890
- clientSecret?: string;
1891
- scopes?: string[];
3146
+ buttons: {
3147
+ [k: string]: number;
3148
+ };
3149
+ /**
3150
+ * Each axis of its sticks, by its name, from -1 to 1; up is 1.
3151
+ */
3152
+ axes: {
3153
+ [k: string]: number;
3154
+ };
3155
+ }
3156
+ /**
3157
+ * One change of a controller, `POST /sensors/controllers`, which the apps
3158
+ * that watch the controllers hear as `controllers.change`.
3159
+ */
3160
+ interface ControllerChange {
3161
+ event: ControllerEvent;
3162
+ /**
3163
+ * The controller after the change.
3164
+ */
3165
+ controller: Controller;
3166
+ }
3167
+ /**
3168
+ * The state of the computer, `ctx.system.state()`, and each change of it,
3169
+ * `POST /sensors/system`, which the apps that watch it hear as
3170
+ * `system.change`. `locked` and `power` are absent where the system does
3171
+ * not tell the client, and `battery` where the computer has none or does
3172
+ * not say its level.
3173
+ */
3174
+ interface SystemState {
1892
3175
  /**
1893
- * The RFC 8707 resource the token is for.
3176
+ * How long the person has given no input, in whole seconds.
1894
3177
  */
1895
- resource?: string;
1896
- endpoints?: OAuthEndpoints;
1897
- grant?: OAuthGrant;
3178
+ idleSeconds: number;
3179
+ locked?: boolean;
3180
+ power?: PowerSource;
1898
3181
  /**
1899
- * The server's own fields on the authorization address, such as
1900
- * `access_type`.
3182
+ * The battery's charge, from 0 to 1.
1901
3183
  */
1902
- params?: {
1903
- [k: string]: string;
1904
- };
3184
+ battery?: number;
3185
+ online: boolean;
3186
+ displays: DisplayState[];
3187
+ theme: ColourScheme;
1905
3188
  }
1906
3189
  /**
1907
- * The endpoints of an authorization server that publishes no metadata.
3190
+ * One display of the computer: its size in points, and how many pixels
3191
+ * one point takes.
1908
3192
  */
1909
- interface OAuthEndpoints {
1910
- authorization?: string;
1911
- token: string;
1912
- device?: string;
3193
+ interface DisplayState {
3194
+ width: number;
3195
+ height: number;
3196
+ scale: number;
3197
+ }
3198
+ /**
3199
+ * A media key that went down on the computer, `POST /sensors/media-keys`,
3200
+ * which the apps that watch the state of the computer hear as
3201
+ * `system.media-key`. The key still reaches the program it is meant for.
3202
+ */
3203
+ interface MediaKeyPress {
3204
+ key: MediaKey;
1913
3205
  }
1914
3206
 
1915
3207
  /**
@@ -1935,25 +3227,30 @@ interface OAuthEndpoints {
1935
3227
  * `{}`, `openai/files` holds `{}` when the app names `files.open` in
1936
3228
  * `uses`, and `hearthscale` holds `HearthscaleHostCapability`. In the host
1937
3229
  * context, `displayMode` and `availableDisplayModes` follow
1938
- * `MCP_DISPLAY_MODES` and the surface's placements, and
1939
- * `containerDimensions` is the size of the view's frame, `width` and
1940
- * `height` in a tab or a modal and `width` and `maxHeight` under a
1941
- * result, sent again on each change.
3230
+ * `MCP_DISPLAY_MODES` and the surface's placements, `pip` alone in an
3231
+ * overlay or a popover, and `containerDimensions` is the size of the
3232
+ * view's frame, `width` and `height` in a tab, a modal, an overlay or a
3233
+ * popover and `width` and `maxHeight` under a result, sent again on each
3234
+ * change.
1942
3235
  *
1943
3236
  * Every block a view sends with `ui/update-model-context` shows as a
1944
3237
  * removable chip above the composer of each chat on screen in the same
1945
3238
  * window, and rides the next message sent there as a `context` part; no
1946
3239
  * block reaches a model without a chip, whatever its
1947
- * `annotations.audience` says.
3240
+ * `annotations.audience` says. An update that aims at one of the view's
3241
+ * own `chat` or `composer` slots (`ModelContextOptions`) shows its chips
3242
+ * on that slot's composer alone, and they ride only a message sent there,
3243
+ * to a conversation of the view's app.
1948
3244
  */
1949
3245
 
1950
3246
  /** The extensions a view calls as `hearthscale/<extension>/…`, each only
1951
3247
  * when its app names it in `uses`: the app's own conversations and
1952
- * projects, its store, its backend's events, its folders, its models,
1953
- * its jobs, its terminals, opening a surface, and its rooms. Opening a
3248
+ * projects, its store, its database, its backend's events, its folders,
3249
+ * its models, its jobs, its terminals, opening a surface, and its
3250
+ * rooms. Opening a
1954
3251
  * file is OpenAI's `openai/files/open`, which `files.open` in `uses`
1955
3252
  * gates. */
1956
- declare const VIEW_EXTENSIONS: readonly ["sessions", "store", "events", "roots", "models", "jobs", "terminals", "surfaces.open", "peers"];
3253
+ declare const VIEW_EXTENSIONS: readonly ["sessions", "store", "db", "events", "roots", "models", "jobs", "terminals", "surfaces.open", "peers"];
1957
3254
  type ViewExtension = (typeof VIEW_EXTENSIONS)[number];
1958
3255
  /** `hostCapabilities.experimental.hearthscale`: the extensions this view
1959
3256
  * may call. The `hearthscale/ui/*` methods are offered to every view. */
@@ -1965,6 +3262,42 @@ interface HearthscaleHostCapability {
1965
3262
  interface ViewHostContext {
1966
3263
  /** The look the host wears, as one style sheet of `@layer` bodies. */
1967
3264
  'hearthscale/appearance': string;
3265
+ /** The address of the app's own package files under `assets/`, which the
3266
+ * view fetches, streams with byte ranges, and loads worklets from. */
3267
+ 'hearthscale/assets': {
3268
+ url: string;
3269
+ };
3270
+ /** The address an asset of the view's conversation, or else of its app,
3271
+ * streams from: this address and the asset's id, read whole or by one
3272
+ * byte range, by `fetch` or as the source of a picture, a sound or a
3273
+ * video, as `resources/read` of `hearthscale-asset://<asset>` reads it
3274
+ * whole. It answers while the view is hosted. */
3275
+ 'hearthscale/assetBytes': {
3276
+ url: string;
3277
+ };
3278
+ /** The path of the app's data folder, where its backend keeps files,
3279
+ * which the view reads with `hearthscale/fs/*`. */
3280
+ 'hearthscale/data': {
3281
+ path: string;
3282
+ };
3283
+ /** The address a file of the app's data folder streams from: this
3284
+ * address and the file's path inside the folder, its parts joined by
3285
+ * `/` and each percent-encoded, read whole or by one byte range, by
3286
+ * `fetch` or as the source of a picture, a sound or a video, where
3287
+ * `hearthscale/fs/raw` reads a file of at most 64 MiB whole. It answers
3288
+ * while the view is hosted. */
3289
+ 'hearthscale/dataBytes': {
3290
+ url: string;
3291
+ };
3292
+ /** The address a model's publisher picture loads from as the source of
3293
+ * a picture: this address, the Hearthscale Server the model comes from
3294
+ * (a card's `provider`, or the Server a Discover search ran on), `/`,
3295
+ * and the Hugging Face user or organisation that publishes it (the
3296
+ * first part of its `identity.repository`). It answers 404 for a
3297
+ * publisher the Server knows no picture of. */
3298
+ 'hearthscale/publishers': {
3299
+ url: string;
3300
+ };
1968
3301
  /** The app's settings; absent for an app that declares none. */
1969
3302
  'hearthscale/settings'?: SettingValues;
1970
3303
  /** What the view's chips hold from its last `ui/update-model-context`;
@@ -1995,6 +3328,15 @@ interface ContentBlockMeta {
1995
3328
  interface ModelContextAnswer {
1996
3329
  updateId: string;
1997
3330
  }
3331
+ /** `_meta['hearthscale/modelContext']` on a `ui/update-model-context`
3332
+ * request. `slot`, the id of a `chat` or `composer` slot the view
3333
+ * reserves now, aims the update's chips at that slot alone: they show on
3334
+ * its composer, ride only a message sent there, to a conversation of the
3335
+ * view's app, and go when the view goes. Any other id is refused. Absent,
3336
+ * the chips show above every composer on screen in the window. */
3337
+ interface ModelContextOptions {
3338
+ slot?: string;
3339
+ }
1998
3340
  /** `_meta['openai/message']` on a `ui/message` request. */
1999
3341
  interface MessageOptions {
2000
3342
  /** `active`, also when absent: the conversation whose transcript shows
@@ -2009,16 +3351,19 @@ interface MessageOptions {
2009
3351
  * composer for the person to send. */
2010
3352
  send?: boolean;
2011
3353
  }
2012
- /** The tool input a view gets when its surface opens a file. */
3354
+ /** The tool input a view gets when its surface opens a file: one the
3355
+ * person opened, or a file or an asset another app handed its app, which
3356
+ * the view reads and never writes. */
2013
3357
  interface FileInput {
2014
3358
  file: OpenedFile;
2015
3359
  }
2016
3360
  /** `_meta['openai/resource']` on a `resources/read` of an opened file:
2017
- * whether its bytes come as text or as a base64 blob; absent, by the
2018
- * file's kind. The host answers the read, the subscription and its
2019
- * `notifications/resources/updated` itself. */
3361
+ * whether its bytes come as text or as a base64 blob; absent, as a blob
3362
+ * when the file holds a zero byte and as text otherwise. The host answers
3363
+ * the read, the subscription and its `notifications/resources/updated`
3364
+ * itself. */
2020
3365
  interface ResourceReadOptions {
2021
- representation: 'text' | 'blob';
3366
+ representation?: 'text' | 'blob';
2022
3367
  }
2023
3368
  /** `_meta['openai/resource']` on the content a read of an opened file
2024
3369
  * answers: the version read, and whether `openai/resources/write` may
@@ -2052,8 +3397,14 @@ type ResourceWrite = {
2052
3397
  * its own authority and the view never reads or types into; `web`, the
2053
3398
  * tab's web page on the app's own partition, which reaches only the hosts
2054
3399
  * the app declares, and which the view drives with `hearthscale/web/*`.
2055
- * A view reserves at most one `web` slot. */
2056
- declare const HOST_SLOT_KINDS: readonly ["chat", "composer", "cards", "terminal", "web"];
3400
+ * A view reserves at most one `web` slot. `model`, the shell's model
3401
+ * picker for one kind of model the app runs: the app's usable models of
3402
+ * that kind with their publishers' pictures, the ones a Server can
3403
+ * download or install for it, each with the memory it takes and its
3404
+ * download; a pick sets the app's model of that kind, the choice its page
3405
+ * in Settings shows, and the picker follows that choice wherever it
3406
+ * changes. */
3407
+ declare const HOST_SLOT_KINDS: readonly ["chat", "composer", "cards", "terminal", "web", "model"];
2057
3408
  type HostSlotKind = (typeof HOST_SLOT_KINDS)[number];
2058
3409
  /** The distances, in the view's CSS pixels, from each edge of the view to
2059
3410
  * the same edge of a slot. The shell anchors the slot by them in its own
@@ -2064,24 +3415,48 @@ interface SlotInsets {
2064
3415
  right: number;
2065
3416
  bottom: number;
2066
3417
  }
3418
+ /** A rectangle of a view, in its CSS pixels from its top left corner. */
3419
+ interface SlotHole {
3420
+ left: number;
3421
+ top: number;
3422
+ width: number;
3423
+ height: number;
3424
+ }
2067
3425
  /** One rectangle a view reserves for the shell's trusted parts. */
2068
3426
  interface HostSlot {
2069
3427
  /** The view's own name for the slot, unique among its slots. */
2070
3428
  id: string;
2071
3429
  kind: HostSlotKind;
2072
3430
  /** On a `chat` or `composer` slot: the conversation of the view's app
2073
- * it shows. Null or absent, it shows a new conversation, which the
2074
- * first message creates in `project` when one is named, and
2075
- * `hearthscale/ui/slot-session` tells the view its id. */
3431
+ * it shows; null, a new conversation, which the first message creates
3432
+ * in `project` when one is named, and `hearthscale/ui/slot-session`
3433
+ * tells the view its id. Absent, the first chat slot of a rail tab
3434
+ * shows the tab's conversation, and any other slot a new one. A
3435
+ * conversation the first chat slot of a rail tab names, null among
3436
+ * them, becomes the tab's. */
2076
3437
  session?: string | null;
2077
3438
  project?: string;
3439
+ /** On a `chat` or `composer` slot: false draws the composer with no
3440
+ * model picker, for an app whose models are chosen only on its page in
3441
+ * Settings; the rest of the composer's footer keeps its place. Absent,
3442
+ * the composer shows the picker. */
3443
+ modelPicker?: boolean;
2078
3444
  /** On a `terminal` slot: the folder its shell starts in, inside a folder
2079
3445
  * the person gave the view's app. The slot's id, letters, digits, `-`
2080
3446
  * and `_`, names the shell in the view's tab: the same id takes up the
2081
3447
  * shell it opened while the platform holds it, and the shell ends with
2082
3448
  * the tab. */
2083
3449
  cwd?: string;
3450
+ /** On a `model` slot: the kind of model it chooses, one the app's
3451
+ * manifest names in `models` or its agent runs on. */
3452
+ model?: ModelKind;
2084
3453
  insets: SlotInsets;
3454
+ /** On a `chat` slot: at most `SLOT_HOLES_MAX` rectangles where the
3455
+ * view's own drawing shows through the chat and takes the pointer,
3456
+ * such as a bar of its own that floats over the chat. A hole stops at
3457
+ * the top of the composer, so the composer and the requests on it
3458
+ * always show. */
3459
+ holes?: SlotHole[];
2085
3460
  }
2086
3461
  /** The notifications the host sends every view that reserved a slot. */
2087
3462
  type HostSlotNotification =
@@ -2096,13 +3471,15 @@ type HostSlotNotification =
2096
3471
  };
2097
3472
  }
2098
3473
  /** The chat or the composer in the slot shows another conversation of
2099
- * the app: the one its first message created, a fork, or a helper. The
2100
- * shell shows it at once; the view's next report of the slot names it. */
3474
+ * the app: the one its first message created, a fork, a helper, or one
3475
+ * the window opened in the slot's tab; null is a new conversation the
3476
+ * window opened there. The shell shows it at once; the view's next
3477
+ * report of the slot names it. */
2101
3478
  | {
2102
3479
  method: 'hearthscale/ui/slot-session';
2103
3480
  params: {
2104
3481
  id: string;
2105
- session: string;
3482
+ session: string | null;
2106
3483
  };
2107
3484
  }
2108
3485
  /** The tab's web page changed: its address, title, icon, load, history
@@ -2135,6 +3512,14 @@ type HostSlotNotification =
2135
3512
  params: {
2136
3513
  id: string;
2137
3514
  } & WebLogin;
3515
+ }
3516
+ /** The person pressed a key that `hearthscale/web/keys` names while the
3517
+ * tab's page had the keyboard; the page did not hear it. */
3518
+ | {
3519
+ method: 'hearthscale/web/key';
3520
+ params: {
3521
+ key: string;
3522
+ };
2138
3523
  };
2139
3524
  /** The web page of a view's tab as the view hears it. The page lives as
2140
3525
  * long as the tab, whether or not the view reserves its `web` slot, and
@@ -2155,7 +3540,8 @@ type Empty = Record<never, never>;
2155
3540
  /** The host methods beyond MCP Apps that every view may call. */
2156
3541
  interface ViewHostMethods {
2157
3542
  /** Reserves rectangles of a view that fills a tab, each for a part the
2158
- * shell draws and answers there: the chat, the composer or the cards.
3543
+ * shell draws and answers there: the chat, the composer, the cards, the
3544
+ * person's shell, the tab's web page or a model picker.
2159
3545
  * The list replaces the last one; an empty list gives every rectangle
2160
3546
  * back, and a new document of the view starts with none. A slot is cut
2161
3547
  * to the view. A slot below `SLOT_MIN_WIDTH` or `SLOT_MIN_HEIGHT`, or
@@ -2163,10 +3549,26 @@ interface ViewHostMethods {
2163
3549
  * never receives what the person types there. Requests of the app dock
2164
3550
  * on the composer of its slot or in its `cards` slot, and a press on a
2165
3551
  * card counts only once the slot has kept its place for a moment. A
2166
- * view in a transcript reserves none. */
3552
+ * view in a transcript reserves none. With `animate`, the parts glide
3553
+ * to their new places over the shell's slow duration, as the view moves
3554
+ * its own layout, such as a sidebar it folds; without, they move at
3555
+ * once. */
2167
3556
  'hearthscale/ui/slots': {
2168
3557
  params: {
2169
3558
  slots: HostSlot[];
3559
+ animate?: boolean;
3560
+ };
3561
+ result: Empty;
3562
+ };
3563
+ /** Lays the tab's web page and the chat, the composer and the model
3564
+ * picker of the view's slots under the view while `covered`, so a menu,
3565
+ * a dialog or a tip the view draws over them shows above them; they
3566
+ * show through where the view draws nothing, and take no pointer. The terminal and the cards lie
3567
+ * above the view however it is covered. A new document of the view
3568
+ * starts uncovered. */
3569
+ 'hearthscale/ui/cover': {
3570
+ params: {
3571
+ covered: boolean;
2170
3572
  };
2171
3573
  result: Empty;
2172
3574
  };
@@ -2198,7 +3600,7 @@ interface ViewHostMethods {
2198
3600
  * tile dims under the modal, and the modal's view fills the tile on a
2199
3601
  * clear plate and draws its own box. It takes `input` as its tool
2200
3602
  * input, `{}` when absent, and the tool its surface names is called
2201
- * with it. One modal per tile: another replaces it. The app's
3603
+ * with it. One modal per tab: another replaces it. The app's
2202
3604
  * requests draw above the modal. */
2203
3605
  'hearthscale/ui/open-modal': {
2204
3606
  params: {
@@ -2214,7 +3616,7 @@ interface ViewHostMethods {
2214
3616
  };
2215
3617
  /** Keeps a JSON value for this view's tab, which the host gives back in
2216
3618
  * `hearthscale/widgetState`; it never reaches a model. The value takes
2217
- * at most 64 KiB as JSON text. */
3619
+ * at most 65,536 UTF-16 code units as JSON text. */
2218
3620
  'hearthscale/ui/set-widget-state': {
2219
3621
  params: {
2220
3622
  state: unknown;
@@ -2235,15 +3637,15 @@ interface ViewHostMethods {
2235
3637
  files: OpenedFile[];
2236
3638
  };
2237
3639
  };
2238
- /** Stores `blob`, base64 of at most 64 MiB, as an
2239
- * asset of the conversation the view belongs to, else of its app; the
2240
- * view reads it back as `hearthscale-asset://<asset>` and hands `asset`
2241
- * to its tools. */
3640
+ /** Stores `blob`'s bytes as an asset of the conversation the view
3641
+ * belongs to, else of its app, streamed as they are read and held to
3642
+ * the room the disk gives the assets; the view reads it back as
3643
+ * `hearthscale-asset://<asset>` and hands `asset` to its tools. */
2242
3644
  'hearthscale/ui/upload-file': {
2243
3645
  params: {
2244
3646
  name: string;
2245
3647
  mediaType: string;
2246
- blob: string;
3648
+ blob: Blob;
2247
3649
  };
2248
3650
  result: {
2249
3651
  asset: string;
@@ -2270,9 +3672,9 @@ interface ViewHostMethods {
2270
3672
  };
2271
3673
  result: Empty;
2272
3674
  };
2273
- /** Finds text in the page, the next match with `next`, backwards
2274
- * unless `forward`; empty text ends the find and clears its marks. The
2275
- * matches arrive as `hearthscale/web/found`. */
3675
+ /** Finds text in the page, the next match with `next`, forwards
3676
+ * unless `forward` is false; empty text ends the find and clears its
3677
+ * marks. The matches arrive as `hearthscale/web/found`. */
2276
3678
  'hearthscale/web/find': {
2277
3679
  params: {
2278
3680
  text: string;
@@ -2300,16 +3702,6 @@ interface ViewHostMethods {
2300
3702
  png: string;
2301
3703
  };
2302
3704
  };
2303
- /** Lays the page under the view while `covered`, so a menu or a mark the
2304
- * view draws over the slot shows above it; the page shows through
2305
- * where the view is transparent and takes no pointer. Uncovered, the
2306
- * page lies over its slot. */
2307
- 'hearthscale/web/cover': {
2308
- params: {
2309
- covered: boolean;
2310
- };
2311
- result: Empty;
2312
- };
2313
3705
  /** Opens a new tab of the calling view's surface in its tile, after its
2314
3706
  * tab, with its page on `url` when one is given, and its view starting
2315
3707
  * from `state` as the state it saved; needs a click. */
@@ -2349,13 +3741,63 @@ interface ViewHostMethods {
2349
3741
  result: Empty;
2350
3742
  };
2351
3743
  /** Whether a download of the app's pages asks where to save it, with
2352
- * the system's dialog, or goes to the system's downloads folder. */
3744
+ * the system's dialog, or goes to the app's downloads folder. */
2353
3745
  'hearthscale/web/downloads': {
2354
3746
  params: {
2355
3747
  ask: boolean;
2356
3748
  };
2357
3749
  result: Empty;
2358
3750
  };
3751
+ /** The folder the downloads of the app's pages go to; null for the
3752
+ * system's downloads folder. */
3753
+ 'hearthscale/web/downloads-folder': {
3754
+ params: Empty;
3755
+ result: {
3756
+ folder: string | null;
3757
+ };
3758
+ };
3759
+ /** With `pick`, the person picks the folder the downloads of the app's
3760
+ * pages go to with the system's dialog, which keeps the folder before
3761
+ * for a cancelled pick; without it, they go to the system's downloads
3762
+ * folder again. Answers the folder they go to now. Needs a click. */
3763
+ 'hearthscale/web/set-downloads-folder': {
3764
+ params: {
3765
+ pick: boolean;
3766
+ };
3767
+ result: {
3768
+ folder: string | null;
3769
+ };
3770
+ };
3771
+ /** The keys the app's views take from their pages: while a page has the
3772
+ * keyboard, a press of one of them reaches the view of the page's tab
3773
+ * as `hearthscale/web/key`, and the page does not hear it. A key is
3774
+ * written as the shell's keybindings write it (`Control+F`, `Meta+L`,
3775
+ * `F6`); the list replaces the one before. */
3776
+ 'hearthscale/web/keys': {
3777
+ params: {
3778
+ keys: string[];
3779
+ };
3780
+ result: Empty;
3781
+ };
3782
+ /** The person's contact details the system's keychain keeps for the
3783
+ * app's pages; null before the person saves any. When the person
3784
+ * presses a field of a page's form that names one of them in its
3785
+ * `autocomplete`, or moves into one with Tab, the host fills the
3786
+ * empty fields of that form that name one. */
3787
+ 'hearthscale/web/contact': {
3788
+ params: Empty;
3789
+ result: {
3790
+ contact: WebContact | null;
3791
+ };
3792
+ };
3793
+ /** Keeps the person's contact details, or forgets them with null; needs
3794
+ * a click. */
3795
+ 'hearthscale/web/set-contact': {
3796
+ params: {
3797
+ contact: WebContact | null;
3798
+ };
3799
+ result: Empty;
3800
+ };
2359
3801
  /** The origins and accounts the system's keychain keeps passwords of
2360
3802
  * the app's pages for. No view reads a password: the host fills a
2361
3803
  * sign-in form of a page with the password of the page's own origin
@@ -2457,6 +3899,24 @@ type WebLogin = {
2457
3899
  origin: string;
2458
3900
  username: string;
2459
3901
  };
3902
+ /** The person's contact details, each one a form may ask for by its
3903
+ * `autocomplete`: `given-name`, `family-name` and `name`; `email`;
3904
+ * `tel`; `organization`; `street-address`, and `address-line1` and
3905
+ * `address-line2` from its lines; `address-level2`, the city;
3906
+ * `address-level1`, the region; `postal-code`; and `country-name` and
3907
+ * `country`. */
3908
+ type WebContact = {
3909
+ givenName?: string;
3910
+ familyName?: string;
3911
+ email?: string;
3912
+ tel?: string;
3913
+ organization?: string;
3914
+ street?: string;
3915
+ city?: string;
3916
+ region?: string;
3917
+ postalCode?: string;
3918
+ country?: string;
3919
+ };
2460
3920
  /** A download of one of the app's pages, as its tab's view hears it. */
2461
3921
  type WebDownload = {
2462
3922
  id: string;
@@ -2473,8 +3933,9 @@ type WebDownload = {
2473
3933
  * changes is its app's own, a terminal line it types goes at its app's
2474
3934
  * level as one a page types, and the platform's log names the app. An
2475
3935
  * act that sends the person's words, deletes what cannot come back,
2476
- * opens something on the person's screen or puts the app in a room runs
2477
- * only on a click inside the view. */
3936
+ * opens something on the person's screen, puts the app in a room, reads
3937
+ * Hugging Face or installs a model runs only on a click inside the
3938
+ * view. */
2478
3939
  interface ViewExtensionMethods {
2479
3940
  /** The app's own conversations, newest first; archived ones only when
2480
3941
  * asked. Without `spawnedBy` the list holds the conversations no helper
@@ -2620,6 +4081,44 @@ interface ViewExtensionMethods {
2620
4081
  };
2621
4082
  result: Empty;
2622
4083
  };
4084
+ /** The rows one statement of the app's database answers, each an object
4085
+ * by column name; bytes are `{ $bytes: base64 }`. Parameters are an
4086
+ * array for `?` and `?N`, or an object for `:name`, `@name` and
4087
+ * `$name`. */
4088
+ 'hearthscale/db/query': {
4089
+ uses: 'db';
4090
+ params: {
4091
+ sql: string;
4092
+ params?: DbParams;
4093
+ };
4094
+ result: {
4095
+ rows: Record<string, unknown>[];
4096
+ };
4097
+ };
4098
+ /** Runs one statement with its parameters, or, with none, every
4099
+ * statement of the text. */
4100
+ 'hearthscale/db/exec': {
4101
+ uses: 'db';
4102
+ params: {
4103
+ sql: string;
4104
+ params?: DbParams;
4105
+ };
4106
+ result: DbChange;
4107
+ };
4108
+ /** Runs statements in one transaction: all of them change the database
4109
+ * or none does. */
4110
+ 'hearthscale/db/batch': {
4111
+ uses: 'db';
4112
+ params: {
4113
+ statements: {
4114
+ sql: string;
4115
+ params?: DbParams;
4116
+ }[];
4117
+ };
4118
+ result: {
4119
+ results: DbChange[];
4120
+ };
4121
+ };
2623
4122
  'hearthscale/roots/list': {
2624
4123
  uses: 'roots';
2625
4124
  params: Empty;
@@ -2642,11 +4141,13 @@ interface ViewExtensionMethods {
2642
4141
  };
2643
4142
  /** A folder's folders and files by name, hidden ones left out. Every
2644
4143
  * path of `hearthscale/fs/*` and `hearthscale/vcs/*` is absolute on the
2645
- * platform's machine and lies inside a folder or file the person gave
2646
- * the app; one outside, or in a folder that holds credentials, is
2647
- * refused in words. Each reads and never writes. */
4144
+ * platform's machine and lies inside the app's own data folder
4145
+ * (`hearthscale/data`) or a folder or file the person gave the app; one
4146
+ * outside, or in a folder that holds credentials, is refused in words.
4147
+ * Each reads and never writes. `list`, `read` and `raw` need no entry
4148
+ * in `uses`: without `roots`, the data folder is all they reach. */
2648
4149
  'hearthscale/fs/list': {
2649
- uses: 'roots';
4150
+ uses: null;
2650
4151
  params: {
2651
4152
  path: string;
2652
4153
  };
@@ -2654,7 +4155,7 @@ interface ViewExtensionMethods {
2654
4155
  };
2655
4156
  /** A file's size, and its head as text unless it is binary. */
2656
4157
  'hearthscale/fs/read': {
2657
- uses: 'roots';
4158
+ uses: null;
2658
4159
  params: {
2659
4160
  path: string;
2660
4161
  };
@@ -2663,7 +4164,7 @@ interface ViewExtensionMethods {
2663
4164
  /** A whole file of at most 64 MiB, in base64, with the media type of
2664
4165
  * its extension. */
2665
4166
  'hearthscale/fs/raw': {
2666
- uses: 'roots';
4167
+ uses: null;
2667
4168
  params: {
2668
4169
  path: string;
2669
4170
  };
@@ -2704,6 +4205,16 @@ interface ViewExtensionMethods {
2704
4205
  };
2705
4206
  result: VcsRefs;
2706
4207
  };
4208
+ /** The commits of the current branch that `base` does not hold, newest
4209
+ * first. */
4210
+ 'hearthscale/vcs/log': {
4211
+ uses: 'roots';
4212
+ params: {
4213
+ root: string;
4214
+ base: string;
4215
+ };
4216
+ result: VcsLog;
4217
+ };
2707
4218
  /** One scope's patch. */
2708
4219
  'hearthscale/vcs/diff': {
2709
4220
  uses: 'roots';
@@ -2716,9 +4227,10 @@ interface ViewExtensionMethods {
2716
4227
  params: VcsFileQuery;
2717
4228
  result: VcsFile;
2718
4229
  };
2719
- /** One streaming completion on the app's chat card or the chat role;
2720
- * the frames arrive as `hearthscale/models/delta` with `stream`, and
2721
- * the call answers once the stream has ended. */
4230
+ /** One streaming completion on the usable chat card the request's
4231
+ * `model` names, or else on the app's chat card or the chat role; the
4232
+ * frames arrive as `hearthscale/models/delta` with `stream`, and the
4233
+ * call answers once the stream has ended. */
2722
4234
  'hearthscale/models/complete': {
2723
4235
  uses: 'models';
2724
4236
  params: {
@@ -2734,12 +4246,68 @@ interface ViewExtensionMethods {
2734
4246
  };
2735
4247
  result: Empty;
2736
4248
  };
2737
- 'hearthscale/jobs/submit': {
2738
- uses: 'jobs';
4249
+ /** The cards of a kind, a Hugging Face task and a state, the usable ones
4250
+ * the app may name as `model` unless another state is named, each with
4251
+ * what it takes, and the app's choice of the kind, or of each kind. */
4252
+ 'hearthscale/models/list': {
4253
+ uses: 'models';
4254
+ params: {
4255
+ kind?: ModelKind;
4256
+ task?: string;
4257
+ state?: CardState;
4258
+ };
4259
+ result: ModelList;
4260
+ };
4261
+ /** The Hearthscale Servers the app may install on: this computer's
4262
+ * first, then each paired one, with whether each serves now. */
4263
+ 'hearthscale/models/servers': {
4264
+ uses: 'models';
4265
+ params: Empty;
4266
+ result: {
4267
+ servers: ModelServer[];
4268
+ };
4269
+ };
4270
+ /** A search of a Server's Discover: the public Hugging Face
4271
+ * repositories of `task` that `search` matches, as that Server answers
4272
+ * it. Needs a click, as it reads Hugging Face. */
4273
+ 'hearthscale/models/discover': {
4274
+ uses: 'models';
4275
+ params: HubSearch & {
4276
+ server: string;
4277
+ };
4278
+ result: {
4279
+ repositories: HubRepository[];
4280
+ };
4281
+ };
4282
+ /** One public repository as a Server's Discover lists its files: the
4283
+ * ones a runtime there runs whose model answers an app's requests,
4284
+ * each with the companion files it needs. Needs a click. */
4285
+ 'hearthscale/models/repository': {
4286
+ uses: 'models';
4287
+ params: {
4288
+ server: string;
4289
+ repo: string;
4290
+ };
4291
+ result: {
4292
+ listing: HubListing;
4293
+ };
4294
+ };
4295
+ /** Asks the person to install a model on a Hearthscale Server, on a
4296
+ * card at every level: a card a Server lists, or a file of a Hugging
4297
+ * Face repository. `card` is the card the model installs as, or null
4298
+ * where the person declined. Needs a click. */
4299
+ 'hearthscale/models/install': {
4300
+ uses: 'models';
2739
4301
  params: {
2740
- kind: JobKind;
2741
- input: JobInput;
4302
+ target: InstallTarget;
2742
4303
  };
4304
+ result: ModelInstalled;
4305
+ };
4306
+ /** One job on the card `model` names, or else on the card the app runs
4307
+ * the kind on; its outputs are assets of the app. */
4308
+ 'hearthscale/jobs/submit': {
4309
+ uses: 'jobs';
4310
+ params: Omit<JobRequest, 'save'>;
2743
4311
  result: {
2744
4312
  job: Job;
2745
4313
  };
@@ -2816,11 +4384,18 @@ interface ViewExtensionMethods {
2816
4384
  result: Empty;
2817
4385
  };
2818
4386
  /** Opens a surface of this app, or of `app`, that its manifest places
2819
- * in the rail or a tab, beside the view's tile; `session` is a
2820
- * conversation of that app a chat opens on, `path` the address a view
2821
- * opens on, as a deep link gives it. With `session` and no `surface`,
2822
- * the conversation opens in its own app, as a notification's click
2823
- * opens it; `app`, when given, must be that app. Needs a click. */
4387
+ * in the rail or a tab, beside the view's tile, on `path`, the address
4388
+ * a view opens on, as a deep link gives it. With `file`, the absolute
4389
+ * path of a file inside a folder or a file the person gave this app or
4390
+ * its data folder, or `asset`, an asset this app holds, it hands `app`
4391
+ * the file and opens its view surface whose `opens` names the file's
4392
+ * kind, `surface` or else the first, on it, and only once it opens:
4393
+ * `app` gets a grant to read that one file, which lasts while this app
4394
+ * is switched on and reaches the file, or for a file of the data folder
4395
+ * and for an asset an asset of its own. With `session` and no `surface`, the conversation
4396
+ * opens in its own app, as a notification's click opens it; `app`,
4397
+ * when given, must be that app. A `surface` and a `session` together
4398
+ * are refused, and so are a `path` and a file. Needs a click. */
2824
4399
  'hearthscale/surfaces/open': {
2825
4400
  uses: 'surfaces.open';
2826
4401
  params: {
@@ -2828,6 +4403,8 @@ interface ViewExtensionMethods {
2828
4403
  surface?: string;
2829
4404
  session?: string;
2830
4405
  path?: string;
4406
+ file?: string;
4407
+ asset?: string;
2831
4408
  };
2832
4409
  result: Empty;
2833
4410
  };
@@ -2882,8 +4459,10 @@ type ViewExtensionMethod = keyof ViewExtensionMethods;
2882
4459
  /** The notifications the host sends a view, each only to a view whose app
2883
4460
  * names the extension in `uses`: a conversation of the app changed or
2884
4461
  * went, a project of any app changed, the app's backend emitted an
2885
- * event, a completion or a terminal of the view moved, a job of the app
2886
- * moved, a room of the app changed, ended or carried a message. */
4462
+ * event, a completion or a terminal of the view moved, a model of a
4463
+ * Server downloads or its download ended, the app's model of a kind
4464
+ * changed, a job of the app moved, a room of the app changed, ended or
4465
+ * carried a message. */
2887
4466
  type ViewExtensionNotification = {
2888
4467
  method: 'hearthscale/sessions/changed';
2889
4468
  params: {
@@ -2912,6 +4491,20 @@ type ViewExtensionNotification = {
2912
4491
  stream: string;
2913
4492
  delta: CompletionDelta;
2914
4493
  };
4494
+ } | {
4495
+ method: 'hearthscale/models/download';
4496
+ params: {
4497
+ download: ModelDownload;
4498
+ };
4499
+ }
4500
+ /** The app's choice of a kind as `hearthscale/models/list` answers it in
4501
+ * `chosen`. */
4502
+ | {
4503
+ method: 'hearthscale/models/chosen';
4504
+ params: {
4505
+ kind: ModelKind;
4506
+ chosen: EffectiveModel;
4507
+ };
2915
4508
  } | {
2916
4509
  method: 'hearthscale/jobs/progress';
2917
4510
  params: {
@@ -2957,9 +4550,23 @@ type ViewExtensionNotification = {
2957
4550
  * the view may call in `getHostCapabilities().experimental.hearthscale`.
2958
4551
  */
2959
4552
 
2960
- /** One extension call, typed by its method: the request's params in, its
2961
- * result out. A refusal rejects with the host's words. */
2962
- type ViewExtensionCall = <M extends ViewExtensionMethod>(method: M, params: ViewExtensionMethods[M]['params']) => Promise<ViewExtensionMethods[M]['result']>;
4553
+ /** Every request beyond MCP Apps a view sends its host: the methods every
4554
+ * view may call and the extensions its app's `uses` opens, each with its
4555
+ * params and its result. */
4556
+ type ViewMethods = ViewHostMethods & ViewExtensionMethods;
4557
+ /** One request of a method map, typed by its method: its params in, its
4558
+ * result out, the params left out where each of them is optional. A
4559
+ * refusal rejects with the MCP SDK's `McpError`, whose message is
4560
+ * `MCP error <code>: ` followed by the host's words. */
4561
+ type CallOf<Methods> = <M extends keyof Methods & string>(method: M, ...params: Record<never, never> extends ParamsOf<Methods[M]> ? [params?: ParamsOf<Methods[M]>] : [params: ParamsOf<Methods[M]>]) => Promise<ResultOf<Methods[M]>>;
4562
+ type ParamsOf<Method> = Method extends {
4563
+ params: infer P;
4564
+ } ? P : never;
4565
+ type ResultOf<Method> = Method extends {
4566
+ result: infer R;
4567
+ } ? R : never;
4568
+ /** One request beyond MCP Apps, typed by its method. */
4569
+ type HostCall = CallOf<ViewMethods>;
2963
4570
 
2964
4571
  /**
2965
4572
  * `@hearthscale/app`: the types an app's backend and its views import,
@@ -2970,13 +4577,23 @@ type ViewExtensionCall = <M extends ViewExtensionMethod>(method: M, params: View
2970
4577
  * are handles inside mounts, and no callable crosses to the core.
2971
4578
  */
2972
4579
 
4580
+ /** The kinds of trigger a manifest declares. */
4581
+ type TriggerKind = NonNullable<Manifest['triggers']>[number]['kind'];
4582
+
4583
+ /** A value of the app's database as a backend sees it: bytes are a
4584
+ * `Uint8Array`. A view sees them as `{ $bytes: base64 }` (`DbParams`). */
4585
+ type RowValue = null | boolean | number | string | Uint8Array;
4586
+ /** A statement's parameters in a backend: in order for `?` and `?N`, or
4587
+ * by name for `:name`, `@name` and `$name`. */
4588
+ type StatementParams = RowValue[] | Record<string, RowValue>;
2973
4589
  /** A relayed TCP or TLS stream. Bytes have no message boundaries; the
2974
4590
  * protocol on top is the app's. */
2975
4591
  interface Connection {
2976
4592
  readonly id: string;
2977
4593
  readonly state: 'plain' | 'tls';
2978
4594
  write(bytes: Uint8Array | string): Promise<void>;
2979
- /** Upgrades the same socket to TLS after the app's protocol exchange. */
4595
+ /** Upgrades the same socket to TLS after the app's protocol exchange;
4596
+ * a connection a listener accepted refuses it. */
2980
4597
  startTls(): Promise<void>;
2981
4598
  close(): Promise<void>;
2982
4599
  on(event: 'data', fn: (bytes: Uint8Array) => void): () => void;
@@ -2986,6 +4603,84 @@ interface Connection {
2986
4603
  message: string;
2987
4604
  }) => void): () => void;
2988
4605
  }
4606
+ /** A port the backend listens on. Closing it stops new connections and
4607
+ * keeps the open ones. */
4608
+ interface Listener {
4609
+ readonly port: number;
4610
+ close(): Promise<void>;
4611
+ }
4612
+ /** What `ctx.handoff` hands an agent, and where its answer goes. */
4613
+ interface Handoff {
4614
+ /** The app whose agent answers; this app when absent. */
4615
+ app?: string;
4616
+ title?: string;
4617
+ /** What the agent is asked. */
4618
+ text: string;
4619
+ material?: ({
4620
+ kind: 'text';
4621
+ text: string;
4622
+ source: string;
4623
+ } | {
4624
+ kind: 'file';
4625
+ root: string;
4626
+ path: string;
4627
+ source: string;
4628
+ })[];
4629
+ answer?: 'reply' | 'clipboard' | 'caret' | 'selection' | 'notification' | 'overlay' | {
4630
+ file: MountPath;
4631
+ };
4632
+ }
4633
+ /** A note an app shows over the person's other programs. */
4634
+ interface OverlayNote {
4635
+ text: string;
4636
+ title?: string;
4637
+ /** Where the note shows: by the pointer, at the top or the bottom of
4638
+ * the screen, or by the tray; by the pointer when absent. */
4639
+ at?: 'cursor' | 'top' | 'bottom' | 'tray';
4640
+ /** The milliseconds after which the note hides itself. */
4641
+ hideAfter?: number;
4642
+ }
4643
+ /** What `ctx.capture` captures. */
4644
+ type CaptureSource = 'microphone' | 'system-sound' | 'program-sound' | 'screen' | 'window' | 'camera';
4645
+ /** A part of a capture: sound as 16 kHz 16-bit little-endian mono PCM
4646
+ * with its loudness in dBFS and whether it holds a voice, half a second
4647
+ * after the part before it, silence included; or one picture of the
4648
+ * screen, a window or the camera. `at` is the milliseconds from the
4649
+ * capture's start to the part's first sample or to when the picture was
4650
+ * taken. */
4651
+ type CapturedPart = {
4652
+ capture: string;
4653
+ kind: 'audio';
4654
+ seq: number;
4655
+ at: number;
4656
+ pcm: Uint8Array;
4657
+ level: number;
4658
+ voice: boolean;
4659
+ } | {
4660
+ capture: string;
4661
+ kind: 'frame';
4662
+ seq: number;
4663
+ at: number;
4664
+ image: Uint8Array;
4665
+ mediaType: string;
4666
+ width: number;
4667
+ height: number;
4668
+ };
4669
+ /** A transcription stream. The Server cuts the sound at pauses, and
4670
+ * each part becomes a segment. */
4671
+ interface Listening {
4672
+ readonly id: string;
4673
+ /** 16 kHz mono 16-bit little-endian PCM, at most 10 s at a time, such
4674
+ * as a part of `ctx.capture`. */
4675
+ write(pcm: Uint8Array): Promise<void>;
4676
+ /** No more sound: the last segments and `done` follow. */
4677
+ end(): Promise<void>;
4678
+ /** Drops the stream at once; answers whether it was open. */
4679
+ close(): Promise<boolean>;
4680
+ on<T extends ListenEvent['type']>(event: T, fn: (event: Extract<ListenEvent, {
4681
+ type: T;
4682
+ }>) => void): () => void;
4683
+ }
2989
4684
  /** A sandboxed run of one program in the app's environment. */
2990
4685
  interface Run {
2991
4686
  readonly id: string;
@@ -2996,8 +4691,10 @@ interface Run {
2996
4691
  cancel(): Promise<void>;
2997
4692
  on(event: 'output', fn: (output: string) => void): () => void;
2998
4693
  }
2999
- /** What a backend reaches. A namespace the manifest's `uses` does not
3000
- * name is absent from this object. */
4694
+ /** What a backend reaches. Every member and method is present; a call
4695
+ * whose `uses` entry, trigger or manifest part is missing rejects, and a
4696
+ * hook (`on`, `register`) throws, with `capability.denied:` and the
4697
+ * words that name what is missing. */
3001
4698
  interface AppContext {
3002
4699
  readonly app: {
3003
4700
  id: string;
@@ -3009,7 +4706,8 @@ interface AppContext {
3009
4706
  /** Aborts when the host is disposed. */
3010
4707
  readonly signal: AbortSignal;
3011
4708
  log(level: 'debug' | 'info' | 'warn' | 'error', message: string): Promise<void>;
3012
- roots?: {
4709
+ /** With `roots` in `uses`. */
4710
+ roots: {
3013
4711
  list(): Promise<Mount[]>;
3014
4712
  /** Raises the folder card; the person's pick becomes a mount, which
3015
4713
  * the request answers. The host restarts with it once its calls and
@@ -3017,17 +4715,43 @@ interface AppContext {
3017
4715
  * next call; asked outside any call, the answer comes first. */
3018
4716
  request(purpose: string, shape: 'folder' | 'file'): Promise<Mount | null>;
3019
4717
  };
3020
- fs?: {
4718
+ /** Files on the app's mounts: its data folder, `data`, and the folders
4719
+ * and files the person granted it. A write to `data` runs from any
4720
+ * call; a write to another mount only inside a tool declared
4721
+ * mutating. */
4722
+ fs: {
3021
4723
  read(path: MountPath, options?: {
3022
4724
  offset?: number;
3023
4725
  limit?: number;
3024
4726
  }): Promise<string>;
4727
+ /** A file's bytes, or the bytes of a range of it. */
4728
+ readBytes(path: MountPath, range?: {
4729
+ offset: number;
4730
+ length: number;
4731
+ }): Promise<Uint8Array>;
3025
4732
  list(path: MountPath): Promise<{
3026
4733
  dirs: string[];
3027
4734
  files: string[];
3028
4735
  }>;
4736
+ /** A file or a folder, its size and when it last changed; null where
4737
+ * nothing is. */
4738
+ stat(path: MountPath): Promise<{
4739
+ kind: 'file' | 'folder';
4740
+ size: number;
4741
+ modified: string | null;
4742
+ } | null>;
3029
4743
  write(path: MountPath, text: string): Promise<void>;
4744
+ writeBytes(path: MountPath, bytes: Uint8Array | ArrayBuffer | string): Promise<void>;
3030
4745
  edit(path: MountPath, oldText: string, newText: string): Promise<void>;
4746
+ /** Makes a folder and the folders above it. */
4747
+ mkdir(path: MountPath): Promise<void>;
4748
+ /** Moves a file or a folder to another path of the same mount. */
4749
+ rename(path: MountPath, to: string): Promise<void>;
4750
+ /** Removes a file, an empty folder, or with `recursive` a folder and
4751
+ * all it holds. Nothing there is not a failure. */
4752
+ remove(path: MountPath, options?: {
4753
+ recursive?: boolean;
4754
+ }): Promise<void>;
3031
4755
  /** Copies an asset's bytes to a path inside a read-write mount. */
3032
4756
  export(asset: string, path: MountPath): Promise<void>;
3033
4757
  };
@@ -3044,16 +4768,38 @@ interface AppContext {
3044
4768
  import(path: MountPath, mediaType: string): Promise<string>;
3045
4769
  release(id: string): Promise<void>;
3046
4770
  };
3047
- net?: {
4771
+ /** With a host in `environment.network`, a port in
4772
+ * `environment.listen`, `accounts`, or `net.ask` in `uses`. */
4773
+ net: {
3048
4774
  fetch(params: FetchParams): Promise<FetchAnswer>;
3049
4775
  connect(host: string, port: number, tls: boolean): Promise<Connection>;
4776
+ /** Listens on a port `environment.listen` declares, on this
4777
+ * computer's loopback. Each connection reaches `onConnection` before
4778
+ * its first bytes, so hooks set there hear them all. With a port in
4779
+ * `environment.listen`. */
4780
+ listen(port: number, onConnection: (connection: Connection) => void): Promise<Listener>;
4781
+ /** Asks the person to let the backend reach a host they named in the
4782
+ * app, `name[:port]`, on a card at every level, only inside a call a
4783
+ * person's press started. With `tls`, the card shows the
4784
+ * certificate the host presents on that port (443 by default) when
4785
+ * no authority the system trusts signed it, and allowing the host
4786
+ * trusts that certificate. Answers whether the person allowed it;
4787
+ * the backend reaches the host from then on. With `net.ask` in
4788
+ * `uses`. */
4789
+ ask(request: {
4790
+ host: string;
4791
+ purpose: string;
4792
+ tls?: boolean;
4793
+ }): Promise<boolean>;
3050
4794
  };
3051
- exec?: {
4795
+ /** With `exec` in `uses`. */
4796
+ exec: {
3052
4797
  run(argv: string[], cwd: MountPath, options?: {
3053
4798
  wall?: number;
3054
4799
  }): Promise<Run>;
3055
4800
  };
3056
- surface?: {
4801
+ /** With `surface` in `uses`. */
4802
+ surface: {
3057
4803
  /** A tab command on the session's executor surface, from inside a
3058
4804
  * body whose tool is declared outbound: on the page of the app's
3059
4805
  * first surface placed in the rail or a tab, a `web` surface's own
@@ -3061,41 +4807,331 @@ interface AppContext {
3061
4807
  * runs from any body. Rejects with the error the window met. */
3062
4808
  command(op: SurfaceOp, args?: Record<string, unknown>): Promise<SurfaceAnswer>;
3063
4809
  };
3064
- store?: {
4810
+ /** With `store` in `uses`. */
4811
+ store: {
3065
4812
  get(key: string): Promise<unknown>;
3066
4813
  set(key: string, value: unknown): Promise<void>;
3067
4814
  delete(key: string): Promise<void>;
3068
4815
  };
3069
- secrets?: {
4816
+ /** The app's SQLite database, with FTS5 and the JSON functions. Values
4817
+ * are null, booleans (stored as 0 and 1), numbers, strings and bytes;
4818
+ * parameters an array for `?` and `?N`, or an object for `:name`,
4819
+ * `@name` and `$name`. With `db` in `uses`. */
4820
+ db: {
4821
+ /** The rows one statement answers, each by column name. */
4822
+ query(sql: string, params?: StatementParams): Promise<Record<string, RowValue>[]>;
4823
+ /** Runs one statement with its parameters, or, with none, every
4824
+ * statement of the text. */
4825
+ exec(sql: string, params?: StatementParams): Promise<DbChange>;
4826
+ /** Runs statements in one transaction: all change the database or
4827
+ * none does. */
4828
+ batch(statements: {
4829
+ sql: string;
4830
+ params?: StatementParams;
4831
+ }[]): Promise<DbChange[]>;
4832
+ };
4833
+ /** With `secrets` in `uses`. */
4834
+ secrets: {
3070
4835
  get(name: string): Promise<string | null>;
3071
4836
  set(name: string, value: string): Promise<void>;
3072
4837
  delete(name: string): Promise<void>;
3073
4838
  };
3074
- oauth?: {
3075
- /** True once a token for the issuer covers the scopes: at once when
3076
- * one is held, else after the person's sign-in card and the grant;
3077
- * false when the person or the service said no. Rejects with the
3078
- * reason when the request, the manifest's `network` or the service
3079
- * does not allow a sign-in. A sign-in replaces the scopes held, so
3080
- * each call names every scope the app needs. */
3081
- login(request: OAuthLogin): Promise<boolean>;
3082
- /** The access token, refreshed when it is past half its lifetime;
3083
- * null when the app must sign in again. A token the service revoked
3084
- * early still comes back: after a 401, `logout` and `login` again. */
3085
- token(issuer: string): Promise<string | null>;
3086
- /** Forgets the tokens for the issuer, revoked at the service where
3087
- * its metadata names a revocation endpoint. Null, or the words when
3088
- * the service did not confirm the revocation and may still hold the
3089
- * access. */
3090
- logout(issuer: string): Promise<string | null>;
3091
- };
3092
- events?: {
4839
+ /** The person's accounts of the kinds the manifest's `accounts` names,
4840
+ * which Hearthscale holds: the app reads the credential of one the
4841
+ * person attached to it, never its sign-in. With `accounts` in the
4842
+ * manifest. */
4843
+ accounts: {
4844
+ /** The accounts the person attached to the app. */
4845
+ list(): Promise<AppAccount[]>;
4846
+ /** Asks the person for an account of a kind the manifest names, on a
4847
+ * card at every level, only inside a call a person's press started:
4848
+ * one they hold, a new one to fill in, or a sign-in. Answers the
4849
+ * account, attached to the app, or null when the person declines. */
4850
+ add(provider: string): Promise<AppAccount | null>;
4851
+ /** What the app reaches the account's servers with: an access token
4852
+ * Hearthscale refreshes, or the fields the person filled in, the
4853
+ * password among them. */
4854
+ credential(id: string): Promise<AccountCredential>;
4855
+ };
4856
+ /** The app's own events to its views and conversations, with
4857
+ * `events` in `uses`; and the events it offers other apps in
4858
+ * `capabilities.events`, which every enabled app whose `event` trigger
4859
+ * names it hears. */
4860
+ events: {
3093
4861
  emit(event: AppEvent): Promise<void>;
4862
+ /** Publishes an offered event; rejects with the words of a misfit
4863
+ * when the data does not match the offer's schema, or is over 64 KiB
4864
+ * as JSON. */
4865
+ publish(event: string, data: unknown): Promise<void>;
4866
+ };
4867
+ /** With an agent in the manifest: the skills the app adds while it
4868
+ * runs, such as the person's own recipes. The platform keeps them; the
4869
+ * app's agents carry them and the composer's `/` lists them, as the
4870
+ * skills of its package; they go when the app is removed. */
4871
+ skills: {
4872
+ /** Adds a skill, or replaces the one of the same name. At most 100. */
4873
+ add(skill: AppSkill): Promise<void>;
4874
+ /** Answers whether there was a skill by that name. */
4875
+ remove(name: string): Promise<boolean>;
4876
+ list(): Promise<AppSkill[]>;
4877
+ };
4878
+ /** With `sessions`: one turn of an agent on what the app hands it, in a
4879
+ * new conversation of this app or, with `sessions.create`, another
4880
+ * app's. The material reaches the model fenced as untrusted, each with
4881
+ * its source. Once the turn ends, the answer goes where `answer`
4882
+ * names, which needs `desktop.actions` for the clipboard, the caret and
4883
+ * the selection, `notifications` for a notification, `desktop.overlay`
4884
+ * for a note over other programs and `roots` for a file, and comes
4885
+ * back in the result. From inside a tool body, the
4886
+ * tool must be declared `mutating`. */
4887
+ handoff(request: Handoff): Promise<{
4888
+ session: string;
4889
+ text: string;
4890
+ stopReason: string;
4891
+ }>;
4892
+ /** With `triggers` in the manifest: each trigger's handler, called
4893
+ * with the data its kind carries: `HotkeyFire`, `InUseFire`,
4894
+ * `ProgramFire`, `DeviceFire`, `SystemFire`, `AlarmFire`, `FolderFire`
4895
+ * or `EventFire`, the JSON body of an inbound call, or null for a tray
4896
+ * item. A trigger starts the backend when it is not up. With a folder
4897
+ * trigger, `watch` and `unwatch` name the places it hears. */
4898
+ triggers: {
4899
+ on(name: string, fn: (data: unknown, trigger: {
4900
+ kind: TriggerKind;
4901
+ }) => void): () => void;
4902
+ /** Watches a place inside a mount, the `data` folder or a granted
4903
+ * folder or file, for a folder trigger. The platform keeps the watch
4904
+ * while the backend is stopped and across restarts, until the backend
4905
+ * unwatches it, the grant goes, or the app is disabled or removed. */
4906
+ watch(name: string, at: {
4907
+ root: string;
4908
+ path?: string;
4909
+ }): Promise<void>;
4910
+ /** Ends a folder trigger's watch of one place, or every watch of the
4911
+ * trigger when no place is named. Answers whether any ended. */
4912
+ unwatch(name: string, at?: {
4913
+ root: string;
4914
+ path?: string;
4915
+ }): Promise<boolean>;
4916
+ /** With a hotkey trigger: the keys that fire each of the app's
4917
+ * hotkeys now, the person's or else the declared ones, so the app
4918
+ * can show them; `keys` is absent where none are set or another
4919
+ * app's hotkey holds them, which `takenBy` names. */
4920
+ hotkeys: {
4921
+ list(): Promise<HotkeyState[]>;
4922
+ /** Hears a move of the keys of any of them, with every one as
4923
+ * `list` answers it. */
4924
+ on(event: 'change', fn: (hotkeys: HotkeyState[]) => void): () => void;
4925
+ };
4926
+ };
4927
+ /** With a time trigger in the manifest: alarms the platform keeps and
4928
+ * fires at their time, starting the backend when it is stopped. A time
4929
+ * missed while the computer slept or the platform was stopped fires
4930
+ * once when it can. */
4931
+ alarms: {
4932
+ /** Sets an alarm; `at` is a `Date` or an ISO time with its offset,
4933
+ * `every` repeats it that many minutes after each fire. */
4934
+ set(alarm: Omit<AlarmRequest, 'at'> & {
4935
+ at?: string | Date;
4936
+ }): Promise<Alarm>;
4937
+ /** Answers whether there was such an alarm. */
4938
+ clear(id: string): Promise<boolean>;
4939
+ /** The app's alarms, the soonest first. */
4940
+ list(): Promise<Alarm[]>;
4941
+ };
4942
+ /** With the `capture.<source>` entry of each source in `uses`. */
4943
+ capture: {
4944
+ /** The devices of a source the manifest's `uses` names: microphones,
4945
+ * cameras, screens, the windows of other programs, or the programs
4946
+ * that play sound. The ids hold while the person's window runs. */
4947
+ devices(source: CaptureSource): Promise<CaptureDevice[]>;
4948
+ /** Starts capturing a source of the person's computer, which the
4949
+ * manifest's `uses` names as `capture.<source>`, and answers the
4950
+ * capture's id and `startedAt`, when its first sample or picture was
4951
+ * taken in milliseconds since the Unix epoch on the computer that
4952
+ * captures, the clock every capture there shares: a part's moment is
4953
+ * `startedAt + at`. Sound comes as 16 kHz mono 16-bit PCM in parts of
4954
+ * half a second, one after another, silence included; the screen, a window and the camera as a JPEG
4955
+ * picture every `interval` ms (1000 unless named, at least 250), the
4956
+ * screen cut to `region` when named. `device` names a device of
4957
+ * `devices`; a window and a program need one. `echo` takes the
4958
+ * computer's own sound out of the microphone. `keep` records a sound
4959
+ * capture whole, as one WAV asset of the app when it ends. Rejects
4960
+ * with the reason when the person stopped all sensors or the computer
4961
+ * cannot serve the source. A capture keeps the backend up. */
4962
+ start(source: CaptureSource, options?: {
4963
+ device?: string;
4964
+ interval?: number;
4965
+ region?: {
4966
+ x: number;
4967
+ y: number;
4968
+ width: number;
4969
+ height: number;
4970
+ };
4971
+ echo?: boolean;
4972
+ keep?: boolean;
4973
+ }): Promise<{
4974
+ capture: string;
4975
+ startedAt: number;
4976
+ }>;
4977
+ /** Answers whether the capture ran; for a capture with `keep`, the id
4978
+ * of the recording's asset. */
4979
+ stop(capture: string): Promise<boolean | string>;
4980
+ on(event: 'chunk', fn: (part: CapturedPart) => void): () => void;
4981
+ /** A capture the app did not stop ended: its device stopped, the
4982
+ * person stopped all sensors, or the window that captured closed.
4983
+ * `asset` is the recording of a capture with `keep`. */
4984
+ on(event: 'ended', fn: (ended: {
4985
+ capture: string;
4986
+ reason: string;
4987
+ asset?: string;
4988
+ }) => void): () => void;
4989
+ };
4990
+ /** Other programs on the person's computer: what they show, with
4991
+ * `desktop.context`, and typing into the one in front, with
4992
+ * `desktop.actions`. */
4993
+ desktop: {
4994
+ context(): Promise<DesktopContext>;
4995
+ /** Calls `on('change')` with each change from now on, and keeps the
4996
+ * backend up. */
4997
+ watch(): Promise<void>;
4998
+ unwatch(): Promise<boolean>;
4999
+ on(event: 'change', fn: (context: DesktopContext) => void): () => void;
5000
+ on(event: 'ended', fn: (ended: {
5001
+ reason: string;
5002
+ }) => void): () => void;
5003
+ /** Types the text into the focused field of the program in front. */
5004
+ type(text: string): Promise<void>;
5005
+ /** Pastes the text there through the clipboard, which it restores. */
5006
+ paste(text: string): Promise<void>;
5007
+ /** Presses each combination in turn, such as `ctrl+a` or `enter`: a
5008
+ * key with `ctrl`, `shift`, `alt` or `meta` before it. */
5009
+ keys(keys: string[]): Promise<void>;
5010
+ };
5011
+ /** With `input.controller`: the person's game controllers, read also
5012
+ * while another program has the focus. The first hook of `change`
5013
+ * watches them, which keeps the backend up, and the last one that goes
5014
+ * ends the watch; a watch that ends or cannot start says why on
5015
+ * `ended`. */
5016
+ controllers: {
5017
+ list(): Promise<Controller[]>;
5018
+ /** Runs a controller's strong and weak motors, each from 0 to 1, for
5019
+ * `ms` milliseconds, up to 10000, in place of its last rumble. A
5020
+ * motor the call does not name stays still. */
5021
+ rumble(controller: string, rumble: {
5022
+ strong?: number;
5023
+ weak?: number;
5024
+ ms: number;
5025
+ }): Promise<void>;
5026
+ on(event: 'change', fn: (change: ControllerChange) => void): () => void;
5027
+ on(event: 'ended', fn: (ended: {
5028
+ reason: string;
5029
+ }) => void): () => void;
5030
+ };
5031
+ /** With `system.state`: the state of the person's computer. The first
5032
+ * hook of `change` or `mediaKey` watches it, which keeps the backend
5033
+ * up; `change` hears each change but the idle time's, and `mediaKey`
5034
+ * each media key the person presses, which still reaches the program it
5035
+ * is meant for. The last hook that goes ends the watch. */
5036
+ system: {
5037
+ state(): Promise<SystemState>;
5038
+ on(event: 'change', fn: (state: SystemState) => void): () => void;
5039
+ on(event: 'mediaKey', fn: (press: MediaKeyPress) => void): () => void;
5040
+ on(event: 'ended', fn: (ended: {
5041
+ reason: string;
5042
+ }) => void): () => void;
5043
+ };
5044
+ /** With `desktop.overlay`: one note of the app over the person's other
5045
+ * programs, which never takes the focus; a note shown replaces the
5046
+ * app's last. And the app's views its manifest places in `overlay`,
5047
+ * each in a window of its own over the other programs that never takes
5048
+ * the focus, up to 8 at once. */
5049
+ overlay: {
5050
+ show(note: OverlayNote): Promise<void>;
5051
+ hide(): Promise<void>;
5052
+ /** Shows a view surface over the other programs, and answers its id.
5053
+ * It opens with `input` as its tool input, `{}` when absent, and the
5054
+ * tool its surface names is called with it. With `clickThrough`, the
5055
+ * pointer's presses pass through it to the programs below. It takes
5056
+ * the size its view reports, from 48 to 720 points on each side, or
5057
+ * fills the rectangle its anchor names, within its screen's work
5058
+ * area. A view shown keeps the backend up. Rejects with the reason
5059
+ * when the person stopped all sensors or the computer cannot show
5060
+ * it. */
5061
+ view(surface: string, options: {
5062
+ anchor: OverlayAnchor;
5063
+ clickThrough: boolean;
5064
+ input?: Record<string, unknown>;
5065
+ }): Promise<string>;
5066
+ /** Answers whether the view showed. */
5067
+ close(overlay: string): Promise<boolean>;
5068
+ /** A view the app did not close closed: the view asked to close or
5069
+ * reported no size within 10 seconds, the person stopped all sensors,
5070
+ * or the window that showed it closed, loaded again or attached to
5071
+ * the platform again. */
5072
+ on(event: 'closed', fn: (closed: {
5073
+ overlay: string;
5074
+ reason: string;
5075
+ }) => void): () => void;
5076
+ };
5077
+ /** With `index` in `uses`: the shared index, where the app finds again
5078
+ * what it put and the text files of the places it watches. */
5079
+ index: {
5080
+ /** Puts a document in place of what was put under its source;
5081
+ * answers how many passages it holds. */
5082
+ put(document: IndexDocument): Promise<number>;
5083
+ /** Answers whether there was a document under the source. */
5084
+ remove(source: string): Promise<boolean>;
5085
+ /** The passages that best answer the query, best first; ten unless
5086
+ * a limit is named. */
5087
+ search(query: string, limit?: number): Promise<IndexHit[]>;
5088
+ /** Indexes every text file at or under a path of a mount, under the
5089
+ * source `file:<mount>/<path>`, and again whenever one changes, also
5090
+ * after a restart while the app may read the path. */
5091
+ watch(path: MountPath): Promise<void>;
5092
+ /** Stops a watch and removes what it indexed; answers whether there
5093
+ * was one. */
5094
+ unwatch(path: MountPath): Promise<boolean>;
5095
+ };
5096
+ /** With `notifications` in `uses`: a system notification. A press
5097
+ * opens `session` or the place `open` names; a button with an `id`
5098
+ * tells the backend through `notifications.on('action')`, starting it
5099
+ * when it is not up. */
5100
+ notify(notice: AppNotice): Promise<void>;
5101
+ notifications: {
5102
+ on(event: 'action', fn: (press: {
5103
+ id: string;
5104
+ }) => void): () => void;
3094
5105
  };
3095
- notify?(notice: AppNotice): Promise<void>;
3096
5106
  /** Drawn in the conversation at every level, from inside a tool body. */
3097
5107
  ask(question: AppQuestion): Promise<AppAnswer>;
3098
- sessions?: {
5108
+ /** How the person reads dates and numbers, as the window of the computer
5109
+ * they use states it: a BCP 47 locale with the hour cycle and the first
5110
+ * day of the week of the system's settings, and the IANA time zone.
5111
+ * Rejects while no window has stated it. */
5112
+ region(): Promise<Region>;
5113
+ surfaces: {
5114
+ /** Brings a surface this app's manifest places in the rail or a tab, or
5115
+ * with `surfaces.open` in `uses` one of `app`, to the front beside the
5116
+ * conversation of the tool call, opening it there when no tab shows
5117
+ * it; answers what the window does, in words. A view opens at `path`,
5118
+ * which starts with `/`, or on `file` or `asset`: a file of this
5119
+ * app's mounts or an asset it holds, which it hands `app` to open in
5120
+ * its view surface `surface`, whose `opens` names the file's kind.
5121
+ * `app` reads a granted file through a grant to read that one file,
5122
+ * and gets a file of the data folder and an asset as an asset of its
5123
+ * own. A hand-off to another app runs only inside a call a person's
5124
+ * press started. Rejects outside a conversation's tool call, or while
5125
+ * no window shows the conversation. */
5126
+ show(surface: string, options?: {
5127
+ app?: string;
5128
+ path?: string;
5129
+ file?: MountPath;
5130
+ asset?: string;
5131
+ }): Promise<string>;
5132
+ };
5133
+ /** With `sessions` in `uses`. */
5134
+ sessions: {
3099
5135
  /** This app's sessions and the ones it started in other apps. */
3100
5136
  list(): Promise<SessionListing[]>;
3101
5137
  open(id: string): Promise<OpenedSession>;
@@ -3125,12 +5161,60 @@ interface AppContext {
3125
5161
  /** Called with every setting's value when the person changed one. */
3126
5162
  on(event: 'changed', fn: (values: SettingValues) => void): () => void;
3127
5163
  };
3128
- models?: {
3129
- /** One streaming completion on the card this app runs chat on, or
3130
- * the chat role; `format` asks for JSON against a schema. A call
3131
- * inside a tool body counts against the budget of the turn that
3132
- * made the call. */
5164
+ /** With `models` in `uses`. */
5165
+ models: {
5166
+ /** One streaming completion on the usable chat card `model` names, or
5167
+ * else on the card this app runs chat on, or the chat role; `format`
5168
+ * asks for JSON against a schema, and `options` what the card's
5169
+ * `options` names. A call inside a tool body counts against the
5170
+ * budget of the turn that made the call. */
3133
5171
  complete(request: CompletionRequest, signal?: AbortSignal): AsyncIterable<CompletionDelta>;
5172
+ /** The cards of a kind, a Hugging Face task and a state, the usable
5173
+ * ones this app may name as `model` unless another state is named,
5174
+ * each with its abilities and the input of each job kind it runs, and
5175
+ * this app's choice of the kind, or of each kind. */
5176
+ list(options?: {
5177
+ kind?: ModelKind;
5178
+ task?: string;
5179
+ state?: CardState;
5180
+ }): Promise<ModelList>;
5181
+ /** The Hearthscale Servers this app may install on: this computer's
5182
+ * first, then each paired one, with whether each serves now. */
5183
+ servers(): Promise<ModelServer[]>;
5184
+ /** A search of a Server's Discover: the public Hugging Face
5185
+ * repositories of `task` that `search` matches, of the kinds the
5186
+ * runtimes there run, as that Server answers it. It reads Hugging
5187
+ * Face, with no token, so only inside a call a person's press
5188
+ * started. */
5189
+ discover(server: string, search: HubSearch): Promise<HubRepository[]>;
5190
+ /** One public repository, `<owner>/<name>`, as a Server's Discover
5191
+ * lists its files: the ones a runtime there runs whose model answers
5192
+ * an app's requests, each with its size, its projector choices and
5193
+ * the companion files it needs. Only inside a call a person's press
5194
+ * started. */
5195
+ repository(server: string, repo: string): Promise<HubListing>;
5196
+ /** Asks the person to install a model on a Hearthscale Server, on a
5197
+ * card at every level that names the model, its size and, for a
5198
+ * Server on another computer, that Server, only inside a call a
5199
+ * person's press started: a card a Server lists and does not hold, by
5200
+ * its id, or a file of a Hugging Face repository on the Server it
5201
+ * names, of the kind named. Answers the card the model installs as
5202
+ * once the person allowed it, and null where they declined; a Server
5203
+ * on another computer installs it once the person there approves
5204
+ * too. Another install of the same target while one waits is
5205
+ * refused. Once ready, the model becomes this app's model of its
5206
+ * kind, where the app names the kind and has no model of it. */
5207
+ install(target: InstallTarget): Promise<string | null>;
5208
+ /** A model of a Server downloads, with what has arrived, or its
5209
+ * download ended, with the state it left the card in. */
5210
+ on(event: 'download', fn: (download: ModelDownload) => void): () => void;
5211
+ /** This app's model of a kind changed: the person chose it, gave the
5212
+ * kind back to the default, or a model installed for this app became
5213
+ * it once ready; the choice as `list` answers it in `chosen`. */
5214
+ on(event: 'chosen', fn: (choice: {
5215
+ kind: ModelKind;
5216
+ chosen: EffectiveModel;
5217
+ }) => void): () => void;
3134
5218
  /** The chat cards an app's sessions may run on: this app's, or
3135
5219
  * another app's under the `sessions.create` grant. */
3136
5220
  for(app?: string): Promise<ModelListing[]>;
@@ -3138,10 +5222,20 @@ interface AppContext {
3138
5222
  * the reason none can: this app's, or another app's under the
3139
5223
  * `sessions.create` grant. */
3140
5224
  effective(kind: ModelKind, app?: string): Promise<EffectiveModel>;
5225
+ /** Opens a stream on the transcription card `model` names, or else on
5226
+ * the app's transcription model, which runs on a Hearthscale Server:
5227
+ * the sound written in goes out as text while it is spoken. Rejects
5228
+ * when the model is not on a Server. `words` are hint words, such as
5229
+ * names, for a model whose engine takes them. */
5230
+ listen(options?: {
5231
+ language?: string;
5232
+ model?: string;
5233
+ words?: string[];
5234
+ }): Promise<Listening>;
3141
5235
  };
3142
5236
  /** With `sessions.create`: the projects of an app this one may start
3143
5237
  * conversations in. */
3144
- projects?: {
5238
+ projects: {
3145
5239
  list(app?: string): Promise<ProjectListing[]>;
3146
5240
  };
3147
5241
  /** With `catalogue`: the bus. A search reads the catalogue, never
@@ -3151,7 +5245,7 @@ interface AppContext {
3151
5245
  * call, in its conversation and at its level, and ends with it; the
3152
5246
  * signal cancels it earlier. A refused or failed call rejects with the
3153
5247
  * words. */
3154
- capabilities?: {
5248
+ capabilities: {
3155
5249
  search(queries: string | string[], limit?: number): Promise<string>;
3156
5250
  call(name: string, input?: Record<string, unknown>, options?: {
3157
5251
  signal?: AbortSignal;
@@ -3159,12 +5253,16 @@ interface AppContext {
3159
5253
  };
3160
5254
  /** With `readers`: a reader for a format the manifest declares under
3161
5255
  * `formats`; the read tool hands it the file's bytes. */
3162
- readers?: {
5256
+ readers: {
3163
5257
  register(format: string, read: (bytes: Uint8Array, name: string) => Promise<string> | string): () => void;
3164
5258
  };
3165
- jobs?: {
3166
- /** One job on the card this app runs that kind on. */
3167
- submit(kind: JobKind, input: JobInput): Promise<Job>;
5259
+ /** With `jobs` in `uses`. */
5260
+ jobs: {
5261
+ /** One job on the card `model` names, or else on the card this app
5262
+ * runs the kind on, with the input the card takes for the kind; its
5263
+ * outputs are written into the folder `save` names, or else kept as
5264
+ * assets. */
5265
+ submit(request: JobRequest): Promise<Job>;
3168
5266
  get(id: string): Promise<Job>;
3169
5267
  cancel(id: string): Promise<Job>;
3170
5268
  on(event: 'progress', fn: (job: Job) => void): () => void;
@@ -3173,7 +5271,7 @@ interface AppContext {
3173
5271
  * room through a view of the app; a backend sends to the room's other
3174
5272
  * members, hears their messages, and may leave. While the app is in a
3175
5273
  * room, an event of it starts the backend when it is not up. */
3176
- peers?: {
5274
+ peers: {
3177
5275
  list(): Promise<Room[]>;
3178
5276
  /** Sends `data`, at most 64 KiB as JSON, to every other
3179
5277
  * member; inside a tool body, the tool is declared outbound. */
@@ -3227,4 +5325,4 @@ interface Backend {
3227
5325
  tools?: Record<string, ToolBody>;
3228
5326
  }
3229
5327
 
3230
- export type { AppAnswer, AppContext, AppEvent, AppListing, AppNotice, AppQuestion, Backend, CallContext, CapabilityAnswer, ChatContentPart, ChatMessage, CompletionDelta, CompletionRequest, CompletionStop, Connection, Content, ContentBlockMeta, EffectiveModel, FetchAnswer, FetchParams, FileInput, HearthscaleHostCapability, HostSlot, HostSlotKind, HostSlotNotification, Job, JobInput, JobInputs, JobKind, Manifest, MessageOptions, ModelContextAnswer, ModelKind, ModelListing, ModelSource, Mount, MountPath, OAuthLogin, OpenedSession, Origin, PrincipalRef, ProjectListing, ResourcePath, ResourceReadOptions, ResourceVersion, Room, Run, Sampling, Session, SessionCell, SessionCreate, SessionListing, SessionProcess, SessionRoot, SessionStatus, SettingValues, SlotInsets, StopReason, Structured, SurfaceAnswer, SurfaceOp, SurfaceResult, TerminalFrame, TerminalSnapshot, ToolAnswer, ToolBody, ToolCall, ToolDefinition, ToolRun, TurnOutcome, Usage, ViewExtension, ViewExtensionCall, ViewExtensionMethod, ViewExtensionMethods, ViewExtensionNotification, ViewHostContext, ViewHostMethods, WebPageState };
5328
+ export type { AccountCredential, Alarm, AlarmFire, AlarmRequest, AppAccount, AppAnswer, AppContext, AppEvent, AppListing, AppNotice, AppQuestion, AppSkill, Backend, CallContext, CallOf, CapabilityAnswer, CaptureDevice, CaptureSource, CapturedPart, CardState, ChatContentPart, ChatMessage, CompanionOption, CompletionDelta, CompletionOptions, CompletionRequest, CompletionStop, Connection, Content, ContentBlockMeta, Controller, ControllerChange, DbChange, DbParams, DesktopContext, DeviceFire, DiscoverTask, EffectiveModel, Entry, EventFire, FetchAnswer, FetchParams, FileInput, FolderFire, Handoff, HearthscaleHostCapability, HostCall, HostSlot, HostSlotKind, HostSlotNotification, HotkeyFire, HotkeyState, HubCandidate, HubCompanion, HubInstall, HubListing, HubRepository, HubSearch, HubSort, InUseFire, IndexDocument, IndexHit, InstallTarget, Job, JobOutput, JobProgress, JobRequest, JobSpec, ListenEvent, Listener, Listening, Manifest, MediaKeyPress, MessageOptions, ModelCard, ModelContextAnswer, ModelContextOptions, ModelDownload, ModelKind, ModelList, ModelListing, ModelServer, ModelSource, Mount, MountPath, OpenedSession, Origin, OverlayAnchor, OverlayNote, PrincipalRef, ProgramFire, ProjectListing, Region, ResourcePath, ResourceReadOptions, ResourceVersion, Room, RowValue, Run, Sampling, Session, SessionCell, SessionCreate, SessionListing, SessionProcess, SessionRoot, SessionStatus, SettingValues, SlotInsets, StatementParams, StopReason, Structured, SurfaceAnswer, SurfaceOp, SurfaceResult, SystemFire, SystemState, TerminalFrame, TerminalSnapshot, TokenLogprob, ToolAnswer, ToolBody, ToolCall, ToolDefinition, ToolRun, TurnOutcome, Usage, ViewExtension, ViewExtensionMethod, ViewExtensionMethods, ViewExtensionNotification, ViewHostContext, ViewHostMethods, ViewMethods, WebPageState };