@hearthscale/app 0.2.3 → 0.3.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/README.md CHANGED
@@ -86,7 +86,7 @@ the view as `hearthscale/web/key` while the page has the keyboard. The page
86
86
  keeps its address through a restart, and the app's tools drive it through
87
87
  `surface.command`.
88
88
 
89
- An app that names `peers` in `uses` talks to itself on other computers in
89
+ An app that names `peers` in `uses` talks to itself on other devices in
90
90
  rooms. A view opens a room with `hearthscale/peers/create` and shows the
91
91
  person its ticket to pass on; `hearthscale/peers/join` asks the person for
92
92
  a ticket in a sheet the shell draws, so the view never names one. Both
@@ -94,7 +94,7 @@ need a click. The view and the backend (`ctx.peers`) then send messages,
94
94
  JSON of at most 64 KiB, to the room's other members, hear
95
95
  theirs (`hearthscale/peers/message`, `ctx.peers.on('message')`) and leave.
96
96
  A room carries only these messages: no file, process or credential of
97
- either platform. It ends for everyone when the computer that opened it
97
+ either platform. It ends for everyone when the device that opened it
98
98
  leaves. A member keeps its place and joins again on its own after a drop
99
99
  or a restart; no message is kept.
100
100
 
package/dist/index.d.ts CHANGED
@@ -1,3 +1,21 @@
1
+ /**
2
+ * What a Server asks Hearthscale's api about models and what it answers:
3
+ * the models that suit one computer, best first for each kind, with the
4
+ * exact files of each. The Server keeps the last answer on disk.
5
+ */
6
+
7
+ /** A model's licence: its name, and whether it is open for commercial use. */
8
+ interface OfferedLicense {
9
+ name: string;
10
+ commercial: boolean;
11
+ }
12
+
13
+ /**
14
+ * Control: the first-party half of the inference contract — everything the
15
+ * OpenAI shape cannot express. Served by the Server (`hearthd`) beside the
16
+ * generation routes.
17
+ */
18
+
1
19
  /** Resolved publisher identity, independent of the model architecture.
2
20
  * `GET /v1/publishers/{owner}/picture` answers the picture of the Hub
3
21
  * user or organisation `repository` names first: its bytes as
@@ -11,14 +29,33 @@ interface ModelIdentity {
11
29
  /** The Hub repository whose publisher supplies the artwork; null for other sources. */
12
30
  repository: string | null;
13
31
  }
32
+ /** What a transcription model's card and file state about it. A list is empty,
33
+ * and a field null, where neither says. */
34
+ interface SpeechFacts {
35
+ /** The languages it hears, by their short codes. */
36
+ languages: string[];
37
+ /** The percent of words, or of characters in a language written without
38
+ * spaces, its publisher measured wrong on a public test set, by language. */
39
+ errors: Record<string, number>;
40
+ /** How long 30 s of speech took on a graphics device, as its publisher measured
41
+ * it on the reference computer most like its Server. */
42
+ seconds: number | null;
43
+ /** The same on the processor. */
44
+ processorSeconds: number | null;
45
+ /** It writes English from another language. */
46
+ translates: boolean | null;
47
+ /** It tells the language by itself. */
48
+ detects: boolean | null;
49
+ }
14
50
  /** A job kind a model runs: the JSON Schema (draft-07) of its input, every
15
51
  * object of it closed. A property of `"format": "asset"`, alone or as the
16
52
  * items of an array, names a file by its asset id on the app's side,
17
53
  * `contentMediaType` saying what it takes, and its `description` the
18
54
  * 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. */
55
+ * in the same place. A property of `"format": "model"` names another
56
+ * model of the same Server by its card id; it reaches the Server as that
57
+ * model's id. A property's `default` is what the model's saved settings
58
+ * give a job that leaves it out. */
22
59
  interface JobSpec {
23
60
  input: Record<string, unknown>;
24
61
  }
@@ -78,6 +115,8 @@ interface HubRepository {
78
115
  vision: boolean;
79
116
  tools: boolean;
80
117
  reasoning: boolean;
118
+ /** What a speech model's card states about it. */
119
+ speech: SpeechFacts | null;
81
120
  }
82
121
  /** A file that can fill a companion role: where it is, how big it is, and
83
122
  * whether its checksum is published. */
@@ -86,6 +125,28 @@ interface CompanionOption {
86
125
  path: string;
87
126
  sizeBytes: number;
88
127
  verifiable: boolean;
128
+ installed?: {
129
+ modelId: string;
130
+ path: string;
131
+ source: {
132
+ type: string;
133
+ repo: string;
134
+ revision: string;
135
+ };
136
+ sha256: string;
137
+ sizeBytes: number;
138
+ };
139
+ containsVision?: boolean;
140
+ /** The licence the recommendations state for a usual part of a family. */
141
+ license?: OfferedLicense;
142
+ }
143
+ /** A companion role of a candidate and the files that fill it. */
144
+ interface CompanionRole {
145
+ role: string;
146
+ label: string;
147
+ options: CompanionOption[];
148
+ /** A gated base or encoder repository whose files this caller cannot read. */
149
+ gated?: string;
89
150
  }
90
151
  /** One file of a repository a pull can name: the whole shard set where it
91
152
  * is a numbered shard, with the weights' projector beside it where the
@@ -110,23 +171,14 @@ interface HubCandidate {
110
171
  label: string;
111
172
  path: string;
112
173
  }[];
113
- /** The companion roles the repository does not supply; a pull names a
114
- * file for each, found in the model's family, the first unless the
115
- * person chooses another. */
116
- requires: {
117
- role: string;
118
- label: string;
119
- options: CompanionOption[];
120
- }[];
174
+ /** Companion roles whose files the pull selects from compatible installed
175
+ * components, the model's family or the encoder's own releases. */
176
+ requires: CompanionRole[];
121
177
  /** The companion roles the model loads where a pull names a file for
122
- * them, which the repository does not supply: `llm_vision`, the vision
178
+ * them: `llm_vision`, the vision
123
179
  * part of a language model encoder, for a family that reads reference
124
180
  * pictures through it. */
125
- offers: {
126
- role: string;
127
- label: string;
128
- options: CompanionOption[];
129
- }[];
181
+ offers: CompanionRole[];
130
182
  /** Whether the repository holds vision projectors beside the file. */
131
183
  projector: boolean;
132
184
  /** The projectors to choose from where there is more than one, each
@@ -140,6 +192,8 @@ interface HubCandidate {
140
192
  /** The task the model serves, as `CatalogRole` names it. */
141
193
  role: string;
142
194
  format: string;
195
+ /** For an adapter: model ids from a Server, card ids from the platform. */
196
+ fits?: string[];
143
197
  /** Why the file cannot be pulled, in the Server's words. */
144
198
  reason?: string;
145
199
  }
@@ -157,6 +211,8 @@ interface HubListing {
157
211
  repo: string;
158
212
  model: HubRepository;
159
213
  files: number;
214
+ /** The path of the file a press takes, where one can be taken. */
215
+ fileToTake: string | null;
160
216
  candidates: HubCandidate[];
161
217
  companions: CompanionOption[];
162
218
  capabilities: {
@@ -544,9 +600,11 @@ type SourceKind = 'app' | 'connector';
544
600
  type ToolOutcome = 'completed' | 'failed' | 'cancelled' | 'skipped' | 'unknown';
545
601
  type Decision = 'run' | 'refused';
546
602
  /**
547
- * Who or what let a call run, or refused it.
603
+ * Who or what let a call run, or refused it. A call whose arguments name
604
+ * no path the tool takes is refused by its path, in words that say how to
605
+ * name one.
548
606
  */
549
- type DecisionBy = 'level' | 'silent' | 'grant' | 'fence' | 'judge' | 'review' | 'person' | 'floor';
607
+ type DecisionBy = 'level' | 'silent' | 'grant' | 'fence' | 'judge' | 'review' | 'person' | 'floor' | 'path';
550
608
  type Risk = 'low' | 'high' | 'too_destructive';
551
609
  type Authorisation = 'explicitly_no' | 'neutral' | 'explicitly_yes';
552
610
  /**
@@ -604,7 +662,7 @@ type SurfaceOp = 'navigate' | 'evaluate' | 'screenshot' | 'show' | 'close';
604
662
  /**
605
663
  * One setting's value.
606
664
  */
607
- type SettingValue = string | number | boolean;
665
+ type SettingValue = string | number | boolean | string[];
608
666
  /**
609
667
  * What a model card answers on, and what a job runs: a role word of
610
668
  * the runtimes, such as chat, embedding, image or transcription.
@@ -706,6 +764,7 @@ type TriggerDeclaration = {
706
764
  name: string;
707
765
  keys?: string;
708
766
  hold?: boolean;
767
+ armed?: boolean;
709
768
  kind: 'hotkey';
710
769
  } | {
711
770
  name: string;
@@ -784,13 +843,12 @@ type SystemEvent = 'idle' | 'active' | 'lock' | 'unlock' | 'sleep' | 'wake' | 'p
784
843
  * `events`, `models`, `jobs` and `peers` alike, each only when its app
785
844
  * names it here. An agent's core tools need no namespace here.
786
845
  */
787
- type Uses = ('sessions' | 'sessions.create' | 'secrets' | 'notifications' | 'readers' | 'roots' | 'exec' | 'catalogue' | 'surface' | 'store' | 'db' | 'events' | 'models' | 'jobs' | 'terminals' | 'files.open' | 'surfaces.open' | 'peers' | 'index' | 'capture.microphone' | 'capture.system-sound' | 'capture.program-sound' | 'capture.screen' | 'capture.window' | 'capture.camera' | 'desktop.context' | 'desktop.actions') | 'net.ask' | 'desktop.overlay' | 'input.controller' | 'system.state';
846
+ 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.around' | 'desktop.overlay' | 'input.controller' | 'system.state';
788
847
  /**
789
- * The model an introduction card downloads on this computer's Server: one
790
- * its catalogue lists, by the id its device row gives it, or a file of a
791
- * Hugging Face repository.
848
+ * The model an introduction card downloads on this computer's Server: a
849
+ * file of a Hugging Face repository, or the best model of a kind.
792
850
  */
793
- type OnboardingDownload = string | HubFile;
851
+ type OnboardingDownload = HubFile | BestModel;
794
852
  /**
795
853
  * What a surface is: `view`, an MCP Apps document in a sandboxed frame,
796
854
  * which may reserve slots for the chat the shell draws for the app's own
@@ -936,6 +994,22 @@ type SettingDeclaration = {
936
994
  minLength?: number;
937
995
  maxLength?: number;
938
996
  pattern?: string;
997
+ /**
998
+ * The tool that lists the values to pick from, for a list only the
999
+ * computer knows, such as its microphones. It is called with `{}` and
1000
+ * answers `{ options: [{ value, label }] }`. The page calls it with no
1001
+ * press, so it is one the app declares, its views may call, and that
1002
+ * neither changes anything nor reaches out.
1003
+ */
1004
+ optionsFrom?: string;
1005
+ /**
1006
+ * The field takes several lines.
1007
+ */
1008
+ multiline?: boolean;
1009
+ /**
1010
+ * What the empty field shows.
1011
+ */
1012
+ placeholder?: string;
939
1013
  /**
940
1014
  * The value the platform holds until the person changes it.
941
1015
  */
@@ -975,19 +1049,56 @@ type SettingDeclaration = {
975
1049
  */
976
1050
  default: number;
977
1051
  type: 'integer';
1052
+ } | {
1053
+ /**
1054
+ * The setting's label.
1055
+ */
1056
+ title: string;
1057
+ /**
1058
+ * The tooltip of the setting's row.
1059
+ */
1060
+ description?: string;
1061
+ items: ListSettingItems;
1062
+ maxItems?: number;
1063
+ /**
1064
+ * What the empty field shows.
1065
+ */
1066
+ placeholder?: string;
1067
+ /**
1068
+ * The value the platform holds until the person changes it.
1069
+ */
1070
+ default: string[];
1071
+ type: 'array';
978
1072
  };
979
1073
  /**
980
- * One row of a settings group: a setting by its name, or a button that
981
- * calls one of the app's tools with `{}`. A tool whose result names a view
982
- * opens that view in a modal over the settings; any other shows its text
983
- * in a tooltip of the button.
1074
+ * The one type a list setting's entries have.
1075
+ */
1076
+ type StringType = 'string';
1077
+ /**
1078
+ * One row of a settings group: a setting by its name, with a button at the
1079
+ * end of its row where it names one, or a button alone. A button calls one of
1080
+ * the app's tools with `{}`. A tool whose result names a view opens that view
1081
+ * in a modal over the settings; any other shows its text in a tooltip of the
1082
+ * button.
984
1083
  */
985
1084
  type SettingsItem = {
986
1085
  property: string;
1086
+ /**
1087
+ * The row shows only while another setting holds a value.
1088
+ */
1089
+ when?: SettingsWhen;
1090
+ /**
1091
+ * The buttons beside the setting's control, in their order. A list or a
1092
+ * field of several lines fills its row and takes none.
1093
+ *
1094
+ * @minItems 1
1095
+ */
1096
+ actions?: SettingsAction[];
987
1097
  kind: 'property';
988
1098
  } | {
989
1099
  tool: string;
990
1100
  title: string;
1101
+ confirm?: SettingsConfirm;
991
1102
  kind: 'tool';
992
1103
  };
993
1104
  /**
@@ -1038,15 +1149,10 @@ type ProviderStatus = ('ready' | 'unreachable' | 'unauthenticated' | 'error') |
1038
1149
  */
1039
1150
  type CompletionOption = 'logprobs' | 'topLogprobs' | 'topK' | 'minP' | 'grammar' | 'stop' | 'seed';
1040
1151
  /**
1041
- * The kinds of model an app's Discover search lists, each a task word of
1042
- * the inference contract's `HubTask` whose models answer an app's
1043
- * requests: chat models in GGUF, one word for each kind of media and
1044
- * vector model a runtime of the Server installs from Hugging Face, and
1045
- * every format a runtime of the Server reads. Draft weights, which load
1046
- * only beside another model, are none of them, and an upscaler, which the
1047
- * Server takes from its catalogue alone, has no word.
1152
+ * The kinds of model an app's Discover search lists, each a `HubTask` word
1153
+ * of the inference contract. Draft weights and upscalers have none.
1048
1154
  */
1049
- type DiscoverTask = 'text' | 'image' | 'transcription' | 'diarization' | 'separation' | 'speech' | 'music' | 'embedding' | 'rerank' | 'all';
1155
+ type DiscoverTask = 'text' | 'image' | 'video' | 'transcription' | 'diarization' | 'separation' | 'speech' | 'music' | 'embedding' | 'rerank' | 'adapter' | 'all';
1050
1156
  /**
1051
1157
  * What an app asks to install on a Hearthscale Server: a card a Server
1052
1158
  * lists and does not hold, by its id, or a file of a Hugging Face
@@ -1166,6 +1272,10 @@ type ListenEvent = {
1166
1272
  stream: string;
1167
1273
  index: number;
1168
1274
  text: string;
1275
+ /**
1276
+ * The words after `text` that may still change.
1277
+ */
1278
+ tentative?: string;
1169
1279
  type: 'partial';
1170
1280
  } | {
1171
1281
  stream: string;
@@ -1194,7 +1304,7 @@ type NoticeAction = {
1194
1304
  title: string;
1195
1305
  id: string;
1196
1306
  };
1197
- type HotkeyPhase = 'pressed' | 'released';
1307
+ type HotkeyPhase = ('pressed' | 'released') | 'cancelled';
1198
1308
  type DeviceEvent = 'connected' | 'removed';
1199
1309
  type PowerSource = 'ac' | 'battery';
1200
1310
  /**
@@ -1430,6 +1540,15 @@ interface AskFacts {
1430
1540
  */
1431
1541
  label?: string;
1432
1542
  arguments?: string;
1543
+ /**
1544
+ * On a card of an app's or a connector's tool: what the call would do,
1545
+ * in one sentence the utility model wrote once the card was open.
1546
+ */
1547
+ plain?: string;
1548
+ /**
1549
+ * The utility model is still writing `plain`.
1550
+ */
1551
+ writing?: true;
1433
1552
  /**
1434
1553
  * The absolute path a file call would touch.
1435
1554
  */
@@ -1482,9 +1601,10 @@ interface AskFacts {
1482
1601
  [k: string]: unknown;
1483
1602
  };
1484
1603
  /**
1485
- * A connector card: the connector, and the tools waiting on a bulk
1486
- * card, or the sign-in's issuer, or the device code the person types
1487
- * at the verification address. An app's sign-in card carries the
1604
+ * A connector card: the connector by its id, with the name the person
1605
+ * knows it or its app by in `sourceName`, and the tools waiting on a
1606
+ * bulk card, or the sign-in's issuer, or the device code the person
1607
+ * types at the verification address. An app's sign-in card carries the
1488
1608
  * issuer, the scopes, and the code or the sign-in a window starts
1489
1609
  * with the authorization endpoint its browser opens.
1490
1610
  */
@@ -1720,7 +1840,7 @@ interface Manifest {
1720
1840
  * Semver, shown and never interpreted.
1721
1841
  */
1722
1842
  version: string;
1723
- api: 6;
1843
+ api: 7;
1724
1844
  description: string;
1725
1845
  icon?: Schemed;
1726
1846
  license?: string;
@@ -1869,6 +1989,17 @@ interface Budget {
1869
1989
  */
1870
1990
  interface ModelNeed {
1871
1991
  required: boolean;
1992
+ /**
1993
+ * The setting that holds the device this kind of model hears, which its
1994
+ * test on the app's page opens.
1995
+ */
1996
+ input?: string;
1997
+ /**
1998
+ * The tool that says which of a search's models the app recommends: it takes
1999
+ * `{ languages, models }` and answers `{ recommended: [{ repo, word }] }`, the
2000
+ * one it recommends most first. It runs with no press.
2001
+ */
2002
+ recommend?: string;
1872
2003
  /**
1873
2004
  * The Hugging Face tasks the kind's card states, every one of them.
1874
2005
  *
@@ -2045,6 +2176,27 @@ interface HubCompanion {
2045
2176
  role: string;
2046
2177
  repo: string;
2047
2178
  file: string;
2179
+ installed?: InstalledCompanion;
2180
+ }
2181
+ interface InstalledCompanion {
2182
+ modelId: string;
2183
+ path: string;
2184
+ source: InstalledCompanionSource;
2185
+ sha256: string;
2186
+ sizeBytes: number;
2187
+ }
2188
+ interface InstalledCompanionSource {
2189
+ type: string;
2190
+ repo: string;
2191
+ revision: string;
2192
+ }
2193
+ /**
2194
+ * The model of a kind that the app's own tool recommends, where its manifest
2195
+ * names one, else the first recommended for the user's device, else
2196
+ * the first of a search, found when the card opens.
2197
+ */
2198
+ interface BestModel {
2199
+ best: ModelKind;
2048
2200
  }
2049
2201
  /**
2050
2202
  * A right-click entry of the app's rail button: a call of one of the
@@ -2078,6 +2230,13 @@ interface SettingsSchema {
2078
2230
  [k: string]: SettingDeclaration;
2079
2231
  };
2080
2232
  }
2233
+ /**
2234
+ * The entries of a list setting: strings, each at most `maxLength` long.
2235
+ */
2236
+ interface ListSettingItems {
2237
+ type: StringType;
2238
+ maxLength?: number;
2239
+ }
2081
2240
  interface SettingsGroup {
2082
2241
  title: string;
2083
2242
  /**
@@ -2085,6 +2244,29 @@ interface SettingsGroup {
2085
2244
  */
2086
2245
  items: SettingsItem[];
2087
2246
  }
2247
+ /**
2248
+ * A setting and the value that shows a row.
2249
+ */
2250
+ interface SettingsWhen {
2251
+ property: string;
2252
+ is: unknown;
2253
+ }
2254
+ /**
2255
+ * A button beside a setting's control.
2256
+ */
2257
+ interface SettingsAction {
2258
+ tool: string;
2259
+ title: string;
2260
+ confirm?: SettingsConfirm;
2261
+ }
2262
+ /**
2263
+ * What a button asks before it runs its tool, for a press that cannot be undone.
2264
+ * The answer that goes ahead carries the button's own title.
2265
+ */
2266
+ interface SettingsConfirm {
2267
+ title: string;
2268
+ body: string;
2269
+ }
2088
2270
  interface Mentions {
2089
2271
  tool: string;
2090
2272
  }
@@ -2192,6 +2374,11 @@ interface ModelCard {
2192
2374
  * states them.
2193
2375
  */
2194
2376
  tasks?: string[];
2377
+ /**
2378
+ * What a transcription model's card and file state about it, where its
2379
+ * provider states it.
2380
+ */
2381
+ speech?: SpeechFacts;
2195
2382
  vision?: boolean;
2196
2383
  tools?: boolean;
2197
2384
  /**
@@ -2241,6 +2428,19 @@ interface ModelCard {
2241
2428
  * Server reports it.
2242
2429
  */
2243
2430
  progress?: DownloadProgressBytes;
2431
+ /**
2432
+ * For an adapter whose Server states them, the cards of the models it fits.
2433
+ */
2434
+ fits?: string[];
2435
+ /**
2436
+ * For an adapter whose Server states them, its prompt trigger words.
2437
+ */
2438
+ triggers?: string[];
2439
+ /**
2440
+ * The name of a licence that limits commercial use, where a Server's
2441
+ * recommendation states one.
2442
+ */
2443
+ limitingLicense?: string;
2244
2444
  }
2245
2445
  /**
2246
2446
  * A Hearthscale Server this computer names, as `ctx.models.servers` and
@@ -2267,6 +2467,11 @@ interface HubSearch {
2267
2467
  * The order of a Discover search: the inference contract's `HubSort`.
2268
2468
  */
2269
2469
  sort?: HubSort;
2470
+ /**
2471
+ * The short codes of the languages a speech model must hear, with commas
2472
+ * between them.
2473
+ */
2474
+ language?: string;
2270
2475
  }
2271
2476
  /**
2272
2477
  * A file of a Hugging Face repository to install on a Hearthscale Server,
@@ -2963,9 +3168,10 @@ interface AppSkill {
2963
3168
  interface HotkeyState {
2964
3169
  name: string;
2965
3170
  /**
2966
- * The keys that fire the hotkey now, the person's or else the
2967
- * declared ones; none where neither names any, or where another
2968
- * app's hotkey holds them.
3171
+ * The keys the hotkey names, the person's or else the declared ones;
3172
+ * none where neither names any, or where another app's hotkey holds
3173
+ * them. A hotkey declared with `armed: false` fires them only while
3174
+ * its backend arms it.
2969
3175
  */
2970
3176
  keys?: string;
2971
3177
  /**
@@ -3482,6 +3688,15 @@ type HostSlotNotification =
3482
3688
  session: string | null;
3483
3689
  };
3484
3690
  }
3691
+ /** The person asked to go back or forward in the tab, whose web page has
3692
+ * loaded none. Every view that fills a tab hears it, with or without a
3693
+ * slot, and moves through its own places. */
3694
+ | {
3695
+ method: 'hearthscale/ui/history';
3696
+ params: {
3697
+ direction: 'back' | 'forward';
3698
+ };
3699
+ }
3485
3700
  /** The tab's web page changed: its address, title, icon, load, history
3486
3701
  * or zoom. Sent once when the view starts and at each change. */
3487
3702
  | {
@@ -3620,6 +3835,14 @@ interface ViewHostMethods {
3620
3835
  params: Empty;
3621
3836
  result: Empty;
3622
3837
  };
3838
+ /** Opens the Server's window at Explore, at the models of `kind`, on a
3839
+ * click inside the view. A kind that no Explore task lists is refused. */
3840
+ 'hearthscale/ui/open-explore': {
3841
+ params: {
3842
+ kind: ModelKind;
3843
+ };
3844
+ result: Empty;
3845
+ };
3623
3846
  /** Keeps a JSON value for this view's tab, which the host gives back in
3624
3847
  * `hearthscale/widgetState`; it never reaches a model. The value takes
3625
3848
  * at most 65,536 UTF-16 code units as JSON text. */
@@ -4273,6 +4496,17 @@ interface ViewExtensionMethods {
4273
4496
  servers: ModelServer[];
4274
4497
  };
4275
4498
  };
4499
+ /** The cards Hearthscale recommends of a kind, best first and in every
4500
+ * state, this computer's own Server first. */
4501
+ 'hearthscale/models/recommended': {
4502
+ uses: 'models';
4503
+ params: {
4504
+ kind: ModelKind;
4505
+ };
4506
+ result: {
4507
+ cards: ModelCard[];
4508
+ };
4509
+ };
4276
4510
  /** A search of a Server's Discover: the public Hugging Face
4277
4511
  * repositories of `task` that `search` matches, as that Server answers
4278
4512
  * it. Needs a click, as it reads Hugging Face. */
@@ -4672,8 +4906,8 @@ type CapturedPart = {
4672
4906
  width: number;
4673
4907
  height: number;
4674
4908
  };
4675
- /** A transcription stream. The Server cuts the sound at pauses, and
4676
- * each part becomes a segment. */
4909
+ /** A transcription stream. The sound is cut at pauses unless `pauses` is
4910
+ * false, and each part becomes a segment. */
4677
4911
  interface Listening {
4678
4912
  readonly id: string;
4679
4913
  /** 16 kHz mono 16-bit little-endian PCM, at most 10 s at a time, such
@@ -4919,11 +5153,15 @@ interface AppContext {
4919
5153
  root: string;
4920
5154
  path?: string;
4921
5155
  }): Promise<boolean>;
4922
- /** With a hotkey trigger: the keys that fire each of the app's
4923
- * hotkeys now, the person's or else the declared ones, so the app
4924
- * can show them; `keys` is absent where none are set or another
4925
- * app's hotkey holds them, which `takenBy` names. */
5156
+ /** With a hotkey trigger: the keys of each of the app's hotkeys, the
5157
+ * person's or else the declared ones, so the app can show them;
5158
+ * `keys` is absent where none are set or another app's hotkey holds
5159
+ * them, which `takenBy` names. A hotkey declared with `armed: false`
5160
+ * fires its keys only while `arm` holds them. */
4926
5161
  hotkeys: {
5162
+ /** Makes a hotkey declared with `armed: false` hold its keys, or lets
5163
+ * them go: at every other moment they reach the program in front. */
5164
+ arm(name: string, on: boolean): Promise<void>;
4927
5165
  list(): Promise<HotkeyState[]>;
4928
5166
  /** Hears a move of the keys of any of them, with every one as
4929
5167
  * `list` answers it. */
@@ -4957,7 +5195,9 @@ interface AppContext {
4957
5195
  * taken in milliseconds since the Unix epoch on the computer that
4958
5196
  * captures, the clock every capture there shares: a part's moment is
4959
5197
  * `startedAt + at`. Sound comes as 16 kHz mono 16-bit PCM in parts of
4960
- * half a second, one after another, silence included; the screen, a window and the camera as a JPEG
5198
+ * half a second, or `part` ms from 50 to 500 for the microphone and
5199
+ * the computer's sound, one after another, silence included; the last
5200
+ * part may be shorter; the screen, a window and the camera as a JPEG
4961
5201
  * picture every `interval` ms (1000 unless named, at least 250), the
4962
5202
  * screen cut to `region` when named. `device` names a device of
4963
5203
  * `devices`; a window and a program need one. `echo` takes the
@@ -4976,6 +5216,7 @@ interface AppContext {
4976
5216
  };
4977
5217
  echo?: boolean;
4978
5218
  keep?: boolean;
5219
+ part?: number;
4979
5220
  }): Promise<{
4980
5221
  capture: string;
4981
5222
  startedAt: number;
@@ -4994,10 +5235,21 @@ interface AppContext {
4994
5235
  }) => void): () => void;
4995
5236
  };
4996
5237
  /** Other programs on the person's computer: what they show, with
4997
- * `desktop.context`, and typing into the one in front, with
4998
- * `desktop.actions`. */
5238
+ * `desktop.context`, the text around the cursor, with `desktop.around`,
5239
+ * and typing into the one in front, with `desktop.actions`. */
4999
5240
  desktop: {
5000
5241
  context(): Promise<DesktopContext>;
5242
+ /** With `desktop.around`: the text around the cursor of the focused field
5243
+ * in the program in front, up to 1024 characters each way. A password
5244
+ * field gives no text and answers `password: true`. Null where the
5245
+ * program does not tell it, or a Hearthscale window has the focus
5246
+ * anywhere but in a view of this app. */
5247
+ around(): Promise<{
5248
+ before: string;
5249
+ selected: string;
5250
+ after: string;
5251
+ password?: true;
5252
+ } | null>;
5001
5253
  /** Calls `on('change')` with each change from now on, and keeps the
5002
5254
  * backend up. */
5003
5255
  watch(): Promise<void>;
@@ -5006,12 +5258,21 @@ interface AppContext {
5006
5258
  on(event: 'ended', fn: (ended: {
5007
5259
  reason: string;
5008
5260
  }) => void): () => void;
5261
+ /** The window in front now, to name to `type` or `paste`, which then
5262
+ * refuse once another window is in front. Null where the system names no
5263
+ * window, as Wayland does: the text then goes to whichever window has the
5264
+ * focus. */
5265
+ front(): Promise<string | null>;
5009
5266
  /** Types the text into the focused field of the program in front. */
5010
- type(text: string): Promise<void>;
5267
+ type(text: string, options?: {
5268
+ front?: string | null;
5269
+ }): Promise<void>;
5011
5270
  /** Pastes the text there through the clipboard, which it restores. */
5012
- paste(text: string): Promise<void>;
5013
- /** Presses each combination in turn, such as `ctrl+a` or `enter`: a
5014
- * key with `ctrl`, `shift`, `alt` or `meta` before it. */
5271
+ paste(text: string, options?: {
5272
+ front?: string | null;
5273
+ }): Promise<void>;
5274
+ /** Presses each combination in turn, at most 200, such as `ctrl+a` or
5275
+ * `enter`: a key with `ctrl`, `shift`, `alt` or `meta` before it. */
5015
5276
  keys(keys: string[]): Promise<void>;
5016
5277
  };
5017
5278
  /** With `input.controller`: the person's game controllers, read also
@@ -5185,6 +5446,11 @@ interface AppContext {
5185
5446
  task?: string;
5186
5447
  state?: CardState;
5187
5448
  }): Promise<ModelList>;
5449
+ /** The cards Hearthscale recommends of a kind for each Server's computer,
5450
+ * best first and in every state, this computer's own Server first. A card
5451
+ * a Server does not hold yet goes to `install` by its id. Empty where a
5452
+ * Server has no answer. */
5453
+ recommended(kind: ModelKind): Promise<ModelCard[]>;
5188
5454
  /** The Hearthscale Servers this app may install on: this computer's
5189
5455
  * first, then each paired one, with whether each serves now. */
5190
5456
  servers(): Promise<ModelServer[]>;
@@ -5229,15 +5495,28 @@ interface AppContext {
5229
5495
  * the reason none can: this app's, or another app's under the
5230
5496
  * `sessions.create` grant. */
5231
5497
  effective(kind: ModelKind, app?: string): Promise<EffectiveModel>;
5498
+ /** The languages the person speaks to this app, as short codes, as they
5499
+ * chose them on its page; empty where they chose none. */
5500
+ languages(): Promise<string[]>;
5232
5501
  /** Opens a stream on the transcription card `model` names, or else on
5233
5502
  * the app's transcription model, which runs on a Hearthscale Server:
5234
5503
  * the sound written in goes out as text while it is spoken. Rejects
5235
- * when the model is not on a Server. `words` are hint words, such as
5236
- * names, for a model whose engine takes them. */
5504
+ * when the model is not on a Server. `words` are names and terms the
5505
+ * sound holds, which an engine that takes hints favours and the text of
5506
+ * any other is corrected to. `aliases` names, for a term, what the model
5507
+ * may write for it. With `pauses: false`, a pause ends no segment, and
5508
+ * one segment runs until `end`. `translate` writes English on a model
5509
+ * that translates, or not, over the setting the person saved on the
5510
+ * model; any other model writes what it hears. `filterSilence` leaves
5511
+ * out the sound that holds no voice. */
5237
5512
  listen(options?: {
5238
5513
  language?: string;
5239
5514
  model?: string;
5240
5515
  words?: string[];
5516
+ aliases?: Record<string, string[]>;
5517
+ pauses?: boolean;
5518
+ translate?: boolean;
5519
+ filterSilence?: boolean;
5241
5520
  }): Promise<Listening>;
5242
5521
  };
5243
5522
  /** With `sessions.create`: the projects of an app this one may start
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hearthscale/app",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "description": "The types a Hearthscale app's backend and views import: the backend's exports and context, the view's host methods, extensions and slots; and the typed call of a view's requests.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -39,7 +39,7 @@
39
39
  "rollup": "^4.62.2",
40
40
  "rollup-plugin-dts": "^6.5.1",
41
41
  "typescript": "^5.6.3",
42
- "@hearthscale/contract": "0.1.0"
42
+ "@hearthscale/contract": "0.3.0"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "node scripts/build.mjs",