@hearthscale/app 0.1.0 → 0.2.0

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