@lotics/cli 0.262.0 → 0.264.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.
@@ -122,71 +122,11 @@ export interface ToolExecuteResult {
122
122
  field_errors?: Record<string, string> | Record<string, string[]>;
123
123
  breaking_changes?: readonly ToolBreakingChange[];
124
124
  }
125
- /**
126
- * A settled (or in-flight) app-agent run, the transcript-excluded projection
127
- * `GET /v1/apps/{app_id}/agent-runs` returns. `output` is the STRUCTURED result
128
- * for a typed agent (an object) or the final text for a free-text agent (a
129
- * string); `status` is `running` until the run settles to `completed` / `error`
130
- * / `aborted`. The authoritative record `lotics app agent run` reports from
131
- * (never the stream).
132
- */
133
- export interface AppAgentRunSummary {
134
- id: string;
135
- app_id: string;
136
- agent_alias: string;
137
- session_id: string;
138
- status: string;
139
- input: Record<string, unknown> | null;
140
- output: string | Record<string, unknown> | null;
141
- usage: {
142
- input_tokens: number;
143
- output_tokens: number;
144
- } | null;
145
- error_message: string | null;
146
- triggered_by_member_id: string | null;
147
- started_at: string;
148
- completed_at: string | null;
149
- /** Single-run GET only, while `status` is "awaiting_input": the pending ask
150
- * derived from the transcript — what /continue answers. */
151
- pending_interactive?: {
152
- tool_call_id: string;
153
- tool_name: string;
154
- input: Record<string, unknown>;
155
- };
156
- }
157
125
  export interface ToolInfo {
158
126
  name: string;
159
127
  description: string;
160
128
  input_schema: unknown;
161
129
  }
162
- /**
163
- * What `POST /v1/apps/{app_id}/upgrade` reports it did — an offer applied in
164
- * part, and every part it declined to touch named back.
165
- *
166
- * Both `skipped_*` lists are aliases the owner has EDITED since the copy, so
167
- * the new version's body was left alone; `dropped_fields` are columns the new
168
- * version stopped declaring and that still hold the owner's data. Neither is an
169
- * error, and both are the reason this result is printed rather than counted.
170
- */
171
- export interface AppUpgradeResult {
172
- app_id: string;
173
- from_version: number;
174
- to_version: number;
175
- deployed: {
176
- version_id: string;
177
- version_number: number;
178
- };
179
- created_fields: Array<{
180
- entity: string;
181
- field: string;
182
- }>;
183
- skipped_workflows: string[];
184
- skipped_agents: string[];
185
- dropped_fields: Array<{
186
- entity: string;
187
- field: string;
188
- }>;
189
- }
190
130
  /**
191
131
  * A single knowledge doc with its HYDRATED body — the shape of
192
132
  * `GET /v1/knowledge_docs/{id}`, and the one content-read path a non-sandbox
@@ -223,253 +163,6 @@ export interface FileUploadResult {
223
163
  error: string;
224
164
  }>;
225
165
  }
226
- /** One finding from the extract behind a package publish. */
227
- export interface ExtractFinding {
228
- severity: "error" | "warning" | "info";
229
- area: string;
230
- message: string;
231
- }
232
- export interface StarterPublishRequest {
233
- /** The package to release into. Omitted, the origin apps resolve it. */
234
- starter_id?: string;
235
- /** The origin apps that ship, in alias-minting order. */
236
- app_ids: string[];
237
- /** Live knowledge doc ids to bundle. Omitted keeps the previous version's set; [] drops them all. */
238
- knowledge_doc_ids?: string[];
239
- /** First publish only: alias fixes before v1 freezes them. */
240
- renames?: Array<{
241
- from: string;
242
- to: string;
243
- }>;
244
- /** First publish only: the listing name; defaults to the workspace's. */
245
- name?: string;
246
- /** First publish only: the listing description; defaults to the first app's. */
247
- description?: string;
248
- /** First publish only: the listing icon; defaults to the first app's. */
249
- icon?: string;
250
- /** First publish only: the listing accent colour; defaults to the first app's. */
251
- color?: string;
252
- }
253
- export interface StarterPublishPreview {
254
- /** The starter this would publish into, or null when it would mint one. */
255
- starter_id: string | null;
256
- starter_name: string;
257
- version: number;
258
- /** The entities it would carry. */
259
- entities: Array<{
260
- alias: string;
261
- label: string;
262
- }>;
263
- apps: Array<{
264
- alias: string;
265
- app_id: string;
266
- name: string;
267
- }>;
268
- /** Empty after v1 — the aliases froze there. */
269
- renamable_aliases: {
270
- entities: string[];
271
- fields: string[];
272
- options: string[];
273
- roles: string[];
274
- templates: string[];
275
- };
276
- added_aliases: string[];
277
- changed_artifacts: string[];
278
- knowledge: {
279
- added: string[];
280
- removed: string[];
281
- changed: string[];
282
- };
283
- findings: ExtractFinding[];
284
- }
285
- /** A publish is a job; this is the row the requester polls. */
286
- export interface StarterPublish {
287
- id: string;
288
- status: "pending" | "building" | "completed" | "failed";
289
- /** Null until a first publish completes. */
290
- starter_id: string | null;
291
- version_id: string | null;
292
- version: number | null;
293
- app_ids: string[];
294
- building_app_alias: string | null;
295
- apps_built: number;
296
- error: string | null;
297
- created_at: string;
298
- started_at: string | null;
299
- finished_at: string | null;
300
- }
301
- /**
302
- * A published version's contract — the artifact set a copy of it creates.
303
- *
304
- * Narrowed to what a caller CHECKING a copy reads back. The authoritative shape
305
- * is `packageContractSchema`, which lives in `@lotics/shared` — a specifier a
306
- * published `.d.ts` cannot resolve, so it is declared here rather than imported,
307
- * the same trade the publish shapes above make.
308
- */
309
- export interface StarterVersionContract {
310
- /**
311
- * One table per entity, scaffolded under `label`, with the columns it
312
- * declares — a copy whose table landed with the right NAME and the wrong
313
- * columns is the failure a table-name check cannot see.
314
- */
315
- entities: Array<{
316
- alias: string;
317
- label: string;
318
- description?: string;
319
- fields: Array<{
320
- alias: string;
321
- label: string;
322
- type: string;
323
- }>;
324
- }>;
325
- templates: Array<{
326
- alias: string;
327
- label: string;
328
- }>;
329
- apps: Array<{
330
- alias: string;
331
- name: string;
332
- /** The named queries the app's shipped source invokes. */
333
- queries: Array<{
334
- alias: string;
335
- /** Param name → declaration. `required` defaults to TRUE when absent. */
336
- params?: Record<string, {
337
- required?: boolean;
338
- }>;
339
- }>;
340
- }>;
341
- /** The knowledge docs the starter ships, keyed by alias. */
342
- knowledge: Record<string, {
343
- name: string;
344
- }>;
345
- /** Sample rows per entity alias — `row_count` is the contract's own count of them. */
346
- fixtures: Record<string, {
347
- row_count: number;
348
- }>;
349
- }
350
- /** Advisory knowledge warnings surfaced by a copy (never block). */
351
- export interface KnowledgeWarnings {
352
- /** `knowledge_expects` doc names with no matching workspace doc. */
353
- missing_expected_docs: string[];
354
- }
355
- /**
356
- * An option's mark as stored and read back — `storedOptionMarkSchema` in
357
- * `@lotics/shared`, typed structurally here because a published `.d.ts` cannot
358
- * resolve that specifier.
359
- */
360
- export interface OptionMark {
361
- kind: string;
362
- name: string;
363
- }
364
- /**
365
- * A workspace MODEL on the wire — a package contract with no apps, plus the
366
- * first rows that travel beside it keyed by entity alias.
367
- *
368
- * The contract's authoritative shape is `packageContractSchema` in
369
- * `@lotics/shared`, a specifier a published `.d.ts` cannot resolve — so the wire
370
- * body is typed structurally here, the same trade `StarterVersionContract`
371
- * makes. The CLI passes a value it has already parsed through that schema.
372
- */
373
- export interface ScaffoldWorkspaceRequest {
374
- contract: Record<string, unknown>;
375
- rows?: Record<string, Array<{
376
- ref: string;
377
- fields: Record<string, unknown>;
378
- }>>;
379
- /** Bind an entity whose label already names a table here. Absent, a colliding label is refused. */
380
- adopt?: boolean;
381
- }
382
- export interface ScaffoldWorkspaceResult {
383
- /** Every entity the model declares, in contract order. */
384
- entities: Array<{
385
- alias: string;
386
- table_id: string;
387
- /** False when a table of that label already existed and was adopted. */
388
- created: boolean;
389
- /**
390
- * What this run put ON that table — the delta a schema write is confirmed by.
391
- * Absent from an instance too old to state it, so the line omits the counts
392
- * rather than reporting a run that added nothing.
393
- */
394
- created_fields?: number;
395
- created_options?: number;
396
- created_views?: number;
397
- /** Fields it already had, given the model's default or format — no stored value moved. */
398
- settled_fields?: number;
399
- /**
400
- * How the table was FOUND: created by this run, through the binding the
401
- * workspace already held, or by its label. Absent from an instance too old
402
- * to state it — which is exactly an instance that binds by label always, so
403
- * the line says nothing rather than claiming an id join that did not happen.
404
- */
405
- bound_by?: "created" | "id" | "label";
406
- }>;
407
- /**
408
- * Every role the model declares. `created` is false when a GROUP of that name
409
- * was already here and the role bound to it — which is how a role silently
410
- * inherits another workspace's membership, and why the line prints it the way
411
- * an entity's does.
412
- */
413
- roles: Array<{
414
- alias: string;
415
- group_id: string;
416
- created: boolean;
417
- }>;
418
- /**
419
- * Ids of the rows written, per entity alias — the handle for deleting them
420
- * again, and what `scaffold apply --documents` joins its rows to.
421
- */
422
- record_ids: Record<string, string[]>;
423
- /** Rows were sent and none were written, because the run adopted a table. */
424
- rows_skipped: boolean;
425
- /**
426
- * Entity aliases whose ADOPTED table kept a row rule of its own — the model
427
- * states a different one, and the table's is what every door enforces.
428
- *
429
- * Absent from an instance too old to state it, which is why the caller reads
430
- * it as "not reported" rather than as "none": a run over an adopted table
431
- * whose rule nobody named is the one a reader has to be told about.
432
- */
433
- carried_rules?: string[];
434
- /**
435
- * Options of an ADOPTED field that kept a mark other than the model's, by
436
- * binding key — every surface draws the live one. Absent from an instance too
437
- * old to state it, for the reason `carried_rules` is.
438
- */
439
- kept_marks?: Array<{
440
- alias: string;
441
- model: OptionMark;
442
- live: OptionMark;
443
- }>;
444
- /**
445
- * ADOPTED fields the model marks whose marks the run did not write, by binding
446
- * key, with the live options that wear none and that the model does not mark.
447
- * Absent from an instance too old to state it, for the reason `carried_rules` is.
448
- */
449
- unwritten_marks?: Array<{
450
- alias: string;
451
- bare: string[];
452
- }>;
453
- /**
454
- * Bound aliases this workspace calls something other than the model does.
455
- *
456
- * Never a refusal: the binding says the two are one thing, so a moved name is
457
- * a RENAME and which side is right is the author's to decide. Absent from an
458
- * instance too old to state it.
459
- */
460
- drift?: Array<{
461
- kind: string;
462
- /** `order`, `order.state`, `order.state:open` — the alias's own binding key. */
463
- alias: string;
464
- id: string;
465
- /** The table a field or an option sits on: neither is addressable on its own. */
466
- on?: string;
467
- /** The field an option belongs to, for the same reason. */
468
- under?: string;
469
- model_label: string;
470
- live_label: string;
471
- }>;
472
- }
473
166
  /** One bound alias: the live thing it names, and what the workspace calls that now. */
474
167
  export interface BoundTarget {
475
168
  id: string;
@@ -506,37 +199,6 @@ export interface ModelBinding {
506
199
  /** A model's app alias → the app created for it here. Absent from an instance too old to bind one. */
507
200
  apps?: Record<string, BoundTarget>;
508
201
  }
509
- /**
510
- * A workspace read BACK as a model — the inverse of the scaffold above.
511
- *
512
- * `entities` and `roles` are the model file's own two keys, whose authoritative
513
- * shapes are `contractEntitySchema` / `contractRoleSchema` in `@lotics/shared` —
514
- * specifiers a published `.d.ts` cannot resolve, so they are typed here as what
515
- * this client does with them, which is hand them on whole. The same trade
516
- * `ScaffoldWorkspaceRequest` makes in the other direction.
517
- *
518
- * `findings` are about the export rather than part of it: a workspace holds
519
- * things a model file cannot express, and a file that dropped them silently
520
- * would be read as the whole workspace.
521
- */
522
- export interface WorkspaceModelExport {
523
- contract: {
524
- entities: Array<Record<string, unknown>>;
525
- roles: Array<Record<string, unknown>>;
526
- templates: Array<Record<string, unknown>>;
527
- };
528
- findings: Array<{
529
- severity: "error" | "warning" | "info";
530
- area: string;
531
- message: string;
532
- }>;
533
- /**
534
- * Labels of the entities the link closure added — the tables the caller did not
535
- * name and a link pulled in. Absent from an instance too old to state it, which
536
- * is why the printout says nothing rather than "0 pulled in".
537
- */
538
- pulled_in?: string[];
539
- }
540
202
  /**
541
203
  * A request the API refused. The message carries the status and the server's
542
204
  * sentence, which is what reaches a person; `status` and `body` are for the
@@ -549,146 +211,11 @@ export declare class LoticsRequestError extends Error {
549
211
  constructor(message: string, status: number, body: Record<string, unknown>);
550
212
  }
551
213
  /**
552
- * The website: where a person goes when the CLI cannot finish the job, and where
553
- * the presets are SERVED FROM. Held beside the API base so the pair is read
554
- * together, named once rather than inlined at each message that points
555
- * somewhere, and overridable for the same reason the API base is — a run against
556
- * a local site must read that site's presets, not production's.
214
+ * The website: where a person goes when the CLI cannot finish the job. Held
215
+ * beside the API base and overridable for the same reason — a run against a
216
+ * local stack points at that stack's site.
557
217
  */
558
218
  export declare const WEB_APP_URL: string;
559
- /** One package on the public shelf — what a chooser decides with, nothing else. */
560
- export interface OfficialStarter {
561
- id: string;
562
- name: string;
563
- description: string | null;
564
- icon: string | null;
565
- latest_version: number;
566
- /**
567
- * The apps the copy creates. A name and a sentence leave the chooser
568
- * guessing; these are what someone's own words get matched against when
569
- * deciding between a package and a model.
570
- */
571
- apps: Array<{
572
- alias: string;
573
- name: string;
574
- description?: string;
575
- }>;
576
- /** How many tables the copy creates — the other half of "what is in this?". */
577
- table_count: number;
578
- }
579
- /**
580
- * The starters Lotics publishes, fetched with no credential.
581
- *
582
- * A plain function rather than a `LoticsClient` method because there is no key
583
- * to build a client around — and that is the point of the endpoint. "Is there a
584
- * starter for what I do, or should I build?" is decided before an account
585
- * exists, so needing one to ask means signing up to find out the answer was no.
586
- */
587
- export declare function fetchOfficialStarters(apiUrl: string): Promise<OfficialStarter[]>;
588
- /**
589
- * One keyless GET of JSON, bounded — the shape every read that predates an
590
- * account takes.
591
- *
592
- * Bounded because these are the FIRST commands a new user runs and a hang with
593
- * nothing on screen is the worst version of the failure; `config.ts` bounds its
594
- * own unattended fetch for the same reason, and `docs/network_reliability.md` is
595
- * a log of connections from our users' networks degrading rather than refusing,
596
- * which is the shape that hangs.
597
- *
598
- * A transport failure THROWS and a status is RETURNED, because only the first is
599
- * "check your connection": a status means the server replied and the network is
600
- * demonstrably fine, and a caller that answered both the same way would tell an
601
- * owner their package is missing every time the link drops.
602
- */
603
- export declare function getPublicJson(url: string, what: string): Promise<{
604
- ok: true;
605
- body: unknown;
606
- } | {
607
- ok: false;
608
- status: number;
609
- }>;
610
- /**
611
- * One official package READ WHOLE, with no credential — or the status that says
612
- * the shelf does not serve it.
613
- *
614
- * The shelf row says what a package is; this says what is in it — entities with
615
- * their fields, the roles, each template's metadata and each app's name. Never a
616
- * workflow body: this is a read for deciding and for writing a model from, not a
617
- * copy.
618
- *
619
- * Unauthenticated for the same reason the shelf is: a preset is READ rather than
620
- * instantiated, and the whole point of reading one is that it happens before an
621
- * account exists. Only official packages are served — the `is_official` filter,
622
- * exactly as on the shelf — so a caller's OWN package answers a status here and
623
- * is read through the authenticated pair instead. A transport failure still
624
- * throws: "unreachable" is not "not on the shelf", and answering both the same
625
- * way would tell an owner their package is missing every time the link drops.
626
- */
627
- export declare function readOfficialStarter(apiUrl: string, starter_id: string): Promise<{
628
- ok: true;
629
- package: OfficialStarterRead;
630
- } | {
631
- ok: false;
632
- status: number;
633
- }>;
634
- /** The same read for a caller with nothing to fall back to — a refusal is the end. */
635
- export declare function getOfficialStarter(apiUrl: string, starter_id: string): Promise<OfficialStarterRead>;
636
- /** A column as the public read shows it: enough to write a model field from. */
637
- export interface OfficialStarterField {
638
- alias: string;
639
- label: string;
640
- type: string;
641
- }
642
- /** A table as the public read shows it: its columns. */
643
- export interface OfficialStarterEntity {
644
- alias: string;
645
- label: string;
646
- description?: string;
647
- fields: OfficialStarterField[];
648
- }
649
- /**
650
- * What the public read of one package carries.
651
- *
652
- * Every namespace is declared structurally, NARROWED to what a reader turning
653
- * this into a model needs — fields carry their type, apps only their name — the
654
- * same trade `StarterVersionContract` makes: a published `.d.ts` cannot resolve
655
- * `@lotics/shared`. `packageContractSchema` is the definition, and the CLI
656
- * parses a preset's block through `modelPresetSchema` before resolving a `from`
657
- * file against it.
658
- */
659
- export interface OfficialStarterRead {
660
- id: string;
661
- name: string;
662
- description: string | null;
663
- latest_version: number;
664
- contract: {
665
- entities: OfficialStarterEntity[];
666
- roles: Array<{
667
- alias: string;
668
- label: string;
669
- }>;
670
- templates: Array<{
671
- alias: string;
672
- label: string;
673
- type: string;
674
- }>;
675
- /** The apps a copy creates. */
676
- apps: Array<{
677
- alias: string;
678
- name: string;
679
- description?: string;
680
- }>;
681
- /** Sample rows per entity alias — how many, never the rows. */
682
- fixtures: Record<string, {
683
- row_count: number;
684
- }>;
685
- knowledge: Record<string, {
686
- name: string;
687
- description: string;
688
- }>;
689
- knowledge_expects: string[];
690
- };
691
- }
692
219
  /**
693
220
  * What a terminal holds while it waits to be let in: the handle the server knows
694
221
  * the request by, the `secret` that proves this is the same terminal that asked,
@@ -720,9 +247,8 @@ export type CliLoginState = {
720
247
  /**
721
248
  * Ask Lotics to mail a sign-in link, and read back whether it was confirmed.
722
249
  *
723
- * Plain functions rather than `LoticsClient` methods for the same reason
724
- * `fetchOfficialStarters` is one: there is no key to build a client around, and
725
- * that is the whole point — this is the pair a terminal holding NO credential
250
+ * Plain functions rather than `LoticsClient` methods: there is no key to build
251
+ * a client around, and that is the whole point — this is the pair a terminal holding NO credential
726
252
  * uses to obtain one. Sending an `Authorization` header would make the endpoint
727
253
  * answerable only to callers who no longer need it.
728
254
  *
@@ -734,12 +260,9 @@ export declare function pollCliLogin(apiUrl: string, request_id: string, secret:
734
260
  export declare class LoticsClient {
735
261
  private apiKey;
736
262
  private workspaceId;
737
- /** The active "View as" target member id, if any. Read-only after
738
- * construction — surfaced so `lotics app dev` can show it in the banner. */
739
- readonly viewAsMemberId: string | undefined;
740
- /** API URL the client is configured against. Read-only after construction.
741
- * Surfaced for callers that need to display it (`lotics app dev`'s banner) or
742
- * to hand it on (the wrapper page's RPC target, the scaffold's font proxy). */
263
+ /** The active "View as" target member id, if any; sent on every request. */
264
+ private readonly viewAsMemberId;
265
+ /** The instance this client sends every request to. */
743
266
  readonly baseUrl: string;
744
267
  constructor(options: LoticsClientOptions);
745
268
  private throwResponseError;
@@ -748,7 +271,7 @@ export declare class LoticsClient {
748
271
  * `x-posthog-session-id` and `x-request-id` onto the per-request Logger, so
749
272
  * they ride EVERY log line that request emits — the validation 400, the tool
750
273
  * error, the timing. Sending them is therefore the whole of the correlation
751
- * work: it turns an anonymous API-key request into "`app workflow set`, from
274
+ * work: it turns an anonymous API-key request into "`app deploy`, from
752
275
  * cli 0.117.0, the fourth command of this session".
753
276
  *
754
277
  * The request id is minted HERE, with the other headers, so it cannot reach
@@ -806,26 +329,6 @@ export declare class LoticsClient {
806
329
  timezone?: string;
807
330
  default_currency?: string;
808
331
  }): Promise<WorkspaceInfo>;
809
- /**
810
- * Apply a workspace MODEL to the current workspace — the from-scratch half of
811
- * the starter pipeline, on a contract nobody published.
812
- *
813
- * Additive: with `adopt`, an entity whose label already names a table here
814
- * binds to it and gains the fields, options and views it is missing; without
815
- * `adopt`, that label is refused. Nothing is ever modified or deleted, and
816
- * rows land only where every bound table is empty. Admin-only.
817
- */
818
- scaffoldWorkspace(body: ScaffoldWorkspaceRequest): Promise<ScaffoldWorkspaceResult>;
819
- /**
820
- * Read this workspace's schema back as a model — the tables it has (or only
821
- * the ones named), their fields, options and views, plus its roles.
822
- *
823
- * A pure read, and admin-only for the same reason the scaffold is: the whole
824
- * schema is what comes back.
825
- */
826
- exportWorkspaceModel(opts?: {
827
- tables?: string[];
828
- }): Promise<WorkspaceModelExport>;
829
332
  /**
830
333
  * What each alias of a workspace model became here, with what this workspace
831
334
  * calls every one of them now.
@@ -836,31 +339,6 @@ export declare class LoticsClient {
836
339
  * is the memory of.
837
340
  */
838
341
  getModelBinding(): Promise<ModelBinding>;
839
- /**
840
- * Forget what one alias is bound to here — the escape from a binding whose
841
- * target has been deleted. Forgets everything addressed under it too: an
842
- * entity owns its fields, its options and its rows.
843
- */
844
- deleteModelBinding(kind: string, alias: string): Promise<{
845
- forgotten: number;
846
- }>;
847
- /**
848
- * This workspace's tables, id and display name — the label side of every
849
- * alias bind, and the one reading of `query_tables` the CLI has.
850
- *
851
- * Here rather than at each caller because the tool answers a row shape
852
- * (`table_id` / `table_name`) that four commands were each unpacking by hand,
853
- * and four unpackings of one wire shape are four places a field rename breaks.
854
- */
855
- listTables(): Promise<Array<{
856
- id: string;
857
- name: string;
858
- }>>;
859
- /** This workspace's document templates, id and name — the same reading, one level over. */
860
- listTemplates(): Promise<Array<{
861
- id: string;
862
- name: string;
863
- }>>;
864
342
  /**
865
343
  * Record which file each of a model's document PATHS was uploaded as.
866
344
  *
@@ -872,14 +350,6 @@ export declare class LoticsClient {
872
350
  recordModelDocuments(documents: Record<string, string>): Promise<{
873
351
  recorded: number;
874
352
  }>;
875
- /**
876
- * Record which app each of a plan's app aliases became — stated by the create
877
- * that made it, since an app row is made from a name and the alias is the
878
- * author's file. What a sibling act naming that app resolves through.
879
- */
880
- recordModelApps(apps: Record<string, string>): Promise<{
881
- recorded: number;
882
- }>;
883
353
  /** Renames (and re-settings) the CURRENT workspace — the endpoint reads the
884
354
  * target from the request's workspace, never a path id. */
885
355
  updateWorkspace(body: {
@@ -944,74 +414,6 @@ export declare class LoticsClient {
944
414
  remove_tags?: string[];
945
415
  hidden?: boolean;
946
416
  }): Promise<KnowledgeDocSummary[]>;
947
- getApp(app_id: string): Promise<{
948
- id: string;
949
- name: string;
950
- /** What the app is for. Heads the capability catalog the member's chat agent
951
- * reads every turn the app is open, so it is where a standing process is
952
- * stated. Null when unset. */
953
- description?: string | null;
954
- workspace_id: string;
955
- current_version_id: string | null;
956
- /** Launcher icon — a Lucide name, or an image ref. Null when unset. */
957
- icon?: string | null;
958
- /** Launcher theme — `{ color }` is a palette token. Null when unset. */
959
- theme?: {
960
- color?: string | null;
961
- } | null;
962
- /**
963
- * Live alias → workflow declaration map from `apps.workflows`. Source of
964
- * truth for `lotics app pull` — supersedes the manifest embedded in the
965
- * source archive so agent-authored bindings (via `set_app_workflow`)
966
- * survive the pull/edit/deploy loop. Null/undefined on apps that have
967
- * never had a workflow declared.
968
- *
969
- * `table_ids` is the set of tables the bound BODY touches, recorded when the
970
- * body was verified. It is what makes a table an app only ever WRITES to
971
- * addressable: codegen covers every table a query reads, and a workflow
972
- * writing a table no screen reads had no `F`/`OPT` entry, so its body
973
- * carried pasted `fld_`/`opt_` literals that a rename breaks silently
974
- * instead of failing `tsc`. Absent on a binding written before the server
975
- * recorded it — the set widens what codegen covers, it does not define it.
976
- */
977
- workflows?: Record<string, {
978
- workflow_id: string;
979
- inputs?: Record<string, unknown>;
980
- outputs?: Record<string, unknown>;
981
- description?: string;
982
- table_ids?: string[];
983
- }> | null;
984
- /**
985
- * Live alias → query declaration map from `apps.queries`. Source of truth
986
- * for `lotics app pull`. Null/undefined on apps with no declared queries.
987
- */
988
- queries?: Record<string, {
989
- ast: unknown;
990
- params?: Record<string, unknown>;
991
- description?: string;
992
- }> | null;
993
- /**
994
- * Live alias → agent declaration map from `apps.agents`. Source of truth for
995
- * `lotics app pull` — supersedes the source archive so `set_app_agent`
996
- * authoring survives the pull. Null/undefined on apps with no declared
997
- * agents. Drives `useAgentRun` typing.
998
- */
999
- agents?: Record<string, {
1000
- instructions?: string;
1001
- tool_names?: string[];
1002
- model_tier?: string;
1003
- inputs?: Record<string, unknown>;
1004
- outputs?: Record<string, unknown>;
1005
- /**
1006
- * The app's own queries/workflows this agent may call through
1007
- * `run_app_query` / `run_app_workflow`. These are REFERENCES that never
1008
- * appear in the client bundle, so anything asking "is this alias still
1009
- * used" must read them or it will answer no for an agent-driven app.
1010
- */
1011
- query_aliases?: string[];
1012
- workflow_aliases?: string[];
1013
- }> | null;
1014
- }>;
1015
417
  createApp(body: {
1016
418
  name: string;
1017
419
  description?: string;
@@ -1026,204 +428,6 @@ export declare class LoticsClient {
1026
428
  workspace_id: string;
1027
429
  current_version_id: string | null;
1028
430
  }>;
1029
- /**
1030
- * Take a starter off the shelf, or `undo` to put it back (backs `opctl
1031
- * library unpublish`). It hides from non-owning orgs and can no longer be
1032
- * copied; copies already made are unaffected — they never linked back.
1033
- * Owner-org admin-only.
1034
- */
1035
- unpublishStarter(starter_id: string, body: {
1036
- undo: boolean;
1037
- }): Promise<{
1038
- id: string;
1039
- name: string;
1040
- retired_at: string | null;
1041
- }>;
1042
- /**
1043
- * Edit a starter's registry listing — the name and description a stranger
1044
- * reads before copying, and what every copy's app row is created from.
1045
- *
1046
- * A version is an immutable snapshot; the listing is not. Omit a field to
1047
- * leave it, pass `description: null` to clear it. Owner-org admin-only.
1048
- */
1049
- editStarterListing(starter_id: string, body: {
1050
- name?: string;
1051
- description?: string | null;
1052
- icon?: string | null;
1053
- theme?: {
1054
- color?: string | null;
1055
- } | null;
1056
- }): Promise<{
1057
- id: string;
1058
- name: string;
1059
- description: string | null;
1060
- icon: string | null;
1061
- theme: Record<string, unknown> | null;
1062
- }>;
1063
- /**
1064
- * The starters this organization can copy — Lotics-reviewed ones plus its own,
1065
- * never a catalogue of everything published. The server returns exactly what
1066
- * instantiate would accept, so the list cannot offer a refusal. Admin-only.
1067
- */
1068
- listStarters(): Promise<Array<{
1069
- id: string;
1070
- name: string;
1071
- description: string | null;
1072
- latest_version: number;
1073
- is_official: boolean;
1074
- owned_by_caller: boolean;
1075
- /** The apps a copy creates — the same contents the public shelf names. */
1076
- apps: Array<{
1077
- alias: string;
1078
- name: string;
1079
- description?: string;
1080
- }>;
1081
- /** How many tables the copy creates. */
1082
- table_count: number;
1083
- }>>;
1084
- /**
1085
- * Copy a starter into the current workspace.
1086
- *
1087
- * Server-side this scaffolds the schema, creates the templates, docs and
1088
- * sample records, creates every app the starter carries and deploys each
1089
- * from its prebuilt dist — no build anywhere. `apps` reports each deploy;
1090
- * one that failed carries its `error` and the copy is complete around it.
1091
- * Admin-only.
1092
- */
1093
- instantiateStarter(starter_id: string, body: {
1094
- version?: number;
1095
- no_sample_data?: boolean;
1096
- adopt?: boolean;
1097
- /**
1098
- * The labels THIS workspace calls the package's entities and fields.
1099
- *
1100
- * Scaffold adopts by label, so binding renames the contract's labels
1101
- * before it runs and the copy lands on the tables the caller already has.
1102
- * A bound field whose type differs from the one the contract declares is
1103
- * refused — the type is the contract, only the naming moves. Structural
1104
- * for the same reason the rest of this file's wire shapes are;
1105
- * `packageBindSchema` in `@lotics/shared` is the definition.
1106
- */
1107
- bind?: Record<string, {
1108
- label?: string;
1109
- fields?: Record<string, string>;
1110
- }>;
1111
- /** The copier's own account each connection alias pushes through, by `cac_` id. */
1112
- connections?: Record<string, string>;
1113
- }): Promise<{
1114
- /** Each app's deploy, in contract order. `error` set and `deployed` null when one did not land. */
1115
- apps: Array<{
1116
- alias: string;
1117
- app_id: string;
1118
- name: string;
1119
- deployed: {
1120
- version_id: string;
1121
- version_number: number;
1122
- } | null;
1123
- error: string | null;
1124
- }>;
1125
- starter_id: string;
1126
- version: number;
1127
- binding: Record<string, Record<string, string>>;
1128
- sample_record_ids: Record<string, string[]>;
1129
- knowledge_warnings: KnowledgeWarnings;
1130
- }>;
1131
- /**
1132
- * Which starter this app is the origin of. 404 when it has published none.
1133
- *
1134
- * The app row carries no pin, so this is the only app→starter direction there
1135
- * is — provenance lives on the published version. Admin-only.
1136
- */
1137
- getAppOriginStarter(app_id: string): Promise<{
1138
- starter_id: string;
1139
- latest_version: number;
1140
- }>;
1141
- /**
1142
- * Apply the latest version of the package this app was copied from.
1143
- *
1144
- * The other provenance direction from `getAppOriginStarter`, and the only one
1145
- * that writes: that one answers which package this app PUBLISHED, this one
1146
- * reads what a copy recorded and re-derives the app against a later release.
1147
- *
1148
- * The offer is partial by design and the result says how partial: schema is
1149
- * additive (`created_fields`, and a `dropped_fields` the new version stopped
1150
- * declaring is left standing), and an artifact the owner has edited is kept
1151
- * and named (`skipped_workflows` / `skipped_agents`). An app with no
1152
- * provenance is a 400, and one already on the latest release a 409 — both
1153
- * refusals, both before any write. Admin-only.
1154
- */
1155
- upgradeApp(app_id: string,
1156
- /** Apply the new release even though it breaks what this app's published API
1157
- * promises, snapshotting the broken contract as a new version. */
1158
- opts?: {
1159
- acknowledge_breaking_api_change?: boolean;
1160
- connections?: Record<string, string>;
1161
- }): Promise<AppUpgradeResult>;
1162
- /**
1163
- * Capture live records from this workspace as a starter's sample data.
1164
- *
1165
- * The alias-keyed shape is produced SERVER-side, because the contract alias
1166
- * space is minted by extract and exists nowhere a project can read it. Pure
1167
- * read — the caller writes the returned files into the project and reviews
1168
- * them, which matters: these rows are copied verbatim into every workspace
1169
- * that takes the starter. Admin-only.
1170
- */
1171
- captureStarterFixtures(app_id: string, opts?: {
1172
- entities?: string[];
1173
- limit?: number;
1174
- }): Promise<{
1175
- app_id: string;
1176
- available_entity_aliases: string[];
1177
- captured: Array<{
1178
- entity_alias: string;
1179
- content_ref: string;
1180
- file: {
1181
- rows: Array<{
1182
- ref: string;
1183
- fields: Record<string, unknown>;
1184
- }>;
1185
- };
1186
- notes: string[];
1187
- }>;
1188
- }>;
1189
- /**
1190
- * Fetch a registry starter's metadata (`latest_version` and the Lotics-backed
1191
- * `is_official` trust badge). Admin-only; cross-tenant by id.
1192
- */
1193
- getStarter(starter_id: string): Promise<{
1194
- id: string;
1195
- name: string;
1196
- description: string | null;
1197
- latest_version: number;
1198
- is_official: boolean;
1199
- retired_at: string | null;
1200
- /** Whether the CALLING org owns it — the copy-time trust badge, without exposing the owner's org id. */
1201
- owned_by_caller: boolean;
1202
- /** The shelf tile. Null = unset; a copy's app tiles come from the contract. */
1203
- icon: string | null;
1204
- theme: Record<string, unknown> | null;
1205
- created_at: string;
1206
- updated_at: string;
1207
- }>;
1208
- /** Version history newest-first (no contract payloads) — backs `opctl library show`. Admin-only. */
1209
- listStarterVersions(starter_id: string): Promise<{
1210
- versions: Array<{
1211
- version: number;
1212
- changelog: string | null;
1213
- created_at: string;
1214
- }>;
1215
- }>;
1216
- /**
1217
- * One version's contract — what a copy of it is supposed to produce. The
1218
- * history above omits it (heavy per row); this is the read that carries it,
1219
- * so a check compares a copy against the declaration itself rather than
1220
- * against a description of it. Admin-only; cross-tenant by id like
1221
- * `getStarter`.
1222
- */
1223
- getStarterVersion(starter_id: string, version: number): Promise<{
1224
- version: number;
1225
- contract: StarterVersionContract;
1226
- }>;
1227
431
  /**
1228
432
  * Workspace-wide dangling-reference sweep — active app/workflow artifacts
1229
433
  * whose prefixed schema ids no longer resolve. Backs
@@ -1239,71 +443,10 @@ export declare class LoticsClient {
1239
443
  };
1240
444
  }>>;
1241
445
  /**
1242
- * Preview publishing a set of this workspace's apps as one starter version —
1243
- * the GET behind `opctl library publish` (no `--yes`). The server runs the
1244
- * same extraction the publish runs and reports which starter it would
1245
- * release into (null: it would mint one), the next version, the aliases a
1246
- * first publish can still rename, the diff against the current version, the
1247
- * knowledge delta, and the findings (an `error` blocks the publish). No
1248
- * writes. Admin-only.
1249
- */
1250
- previewStarterPublish(opts: StarterPublishRequest): Promise<StarterPublishPreview>;
1251
- /**
1252
- * Publish this workspace's apps as a starter version — a JOB, because every
1253
- * app is built once against sentinel field keys and eleven builds outlast a
1254
- * request. Everything a request can refuse is refused here with nothing
1255
- * written: a blocking finding or another publish still running for this
1256
- * org (409), a missing deploy or a bad declaration (400). The response is
1257
- * the job to poll with `getStarterPublish`. Admin-only.
1258
- */
1259
- requestStarterPublish(body: StarterPublishRequest & {
1260
- changelog?: string | null;
1261
- }): Promise<StarterPublish>;
1262
- /** The state of a publish: which app is building, and the version once every dist is in. */
1263
- getStarterPublish(publish_id: string): Promise<StarterPublish>;
1264
- /**
1265
- * The ROW RULE each of these tables declares — `private_filters` as stored, or
1266
- * `null` where the table has none.
1267
- *
1268
- * `GET /v1/tables/{id}` rather than the `get_table` tool beside it: the rule is
1269
- * an IAM fact about who may read a row, and the tool's output is the schema an
1270
- * agent writes records against, which is why it carries fields and not this.
1271
- * One call per id. A table this credential may not read — 403, or 404 for one
1272
- * that is gone — is DROPPED: the only caller warns about rules it can see, and
1273
- * a table it cannot read is not evidence of one. EVERY other failure throws.
1274
- * An expired key, a 500, a timeout and an offline host all mean the scan has
1275
- * no answer, and swallowing them would render as "this table declares no
1276
- * rule" — the guard at its quietest exactly where it knows least.
1277
- *
1278
- * The filter is carried untyped: a published `.d.ts` cannot name
1279
- * `@lotics/shared`'s filter schema, and the one reader asks a single question
1280
- * of the tree rather than interpreting it.
1281
- */
1282
- getTableRowRules(tableIds: string[]): Promise<Array<{
1283
- id: string;
1284
- name: string;
1285
- private_filters: unknown;
1286
- }>>;
1287
- /**
1288
- * The organization's member groups — the directory `lotics app codegen` turns
1289
- * into the `GRP` alias map.
1290
- *
1291
- * Over the HTTP route rather than `query_member_groups`, because the tool is
1292
- * admin-only and the route is member-visible by design (`docs/iam.md` § Groups:
1293
- * reading the directory is not administration). Codegen runs for every author,
1294
- * so an admin-only read here would leave a non-admin's `GRP` empty and their
1295
- * app unbuildable.
1296
- */
1297
- getMemberGroups(): Promise<Array<{
1298
- id: string;
1299
- name: string;
1300
- }>>;
1301
- /**
1302
- * Resolve the display name + fields (incl. select options) of the given tables
1303
- * — the schema `lotics app codegen` turns into the runtime `.lotics/app_fields.ts`
1304
- * alias maps. One `get_table` call per id (the tool surface has no batch
1305
- * variant); a missing/inaccessible table is dropped rather than throwing, so a
1306
- * stale id in the scope set never fails codegen.
446
+ * Resolve the display name + fields (incl. select options) of the given tables.
447
+ * One `get_table` call per id (the tool surface has no batch variant); a
448
+ * missing/inaccessible table is dropped rather than throwing, so a stale id in
449
+ * the scope set never fails the caller.
1307
450
  */
1308
451
  getWorkspaceSchema(tableIds: string[]): Promise<Array<{
1309
452
  id: string;
@@ -1319,379 +462,28 @@ export declare class LoticsClient {
1319
462
  }>;
1320
463
  }>;
1321
464
  }>>;
1322
- /**
1323
- * Rename an app's public subdomain — the label its origin is built on.
1324
- * Mirrors PUT /v1/apps/{app_id}/subdomain, and returns the finished `origin`
1325
- * because only the instance knows the domain and scheme it serves apps on.
1326
- * The old subdomain stops resolving once the change lands.
1327
- */
1328
- setAppSubdomain(app_id: string, public_subdomain: string): Promise<{
1329
- app_id: string;
1330
- public_subdomain: string;
1331
- origin: string;
1332
- }>;
1333
- /**
1334
- * Publish the app's API — the owner's promise about what its declared queries
1335
- * and workflows return to a caller outside the app.
1336
- *
1337
- * Snapshots the contract and answers the version it took, plus what the
1338
- * published surface exposes that the owner may not have intended. A query
1339
- * that does not name its columns is refused (400) before anything is written:
1340
- * the app cannot promise field names it never stated.
1341
- */
1342
- publishAppApi(app_id: string): Promise<{
1343
- app_id: string;
1344
- contract_version: number;
1345
- published_at: string;
1346
- warnings: string[];
1347
- }>;
1348
- /** End the promise. `unpublished: false` means the app was publishing nothing,
1349
- * which this leaves unchanged. The superseded snapshot stays, so a later
1350
- * publish continues the numbering rather than reusing a version. */
1351
- unpublishAppApi(app_id: string): Promise<{
1352
- app_id: string;
1353
- unpublished: boolean;
1354
- }>;
1355
- /** Whether the app is publishing an API, and which contract version. */
1356
- getAppApiPublication(app_id: string): Promise<{
1357
- published: boolean;
1358
- contract_version: number | null;
1359
- published_at: string | null;
1360
- }>;
1361
- /**
1362
- * The published API as an OpenAPI 3.1 document — what a consumer's own
1363
- * generator reads. Rendered from the live SNAPSHOT rather than the manifest,
1364
- * so it describes what the app has promised; 404 while nothing is published.
1365
- */
1366
- getAppOpenApiDocument(app_id: string): Promise<Record<string, unknown>>;
1367
- getAppVersion(app_id: string, version_id: string): Promise<{
1368
- id: string;
1369
- app_id: string;
1370
- version: number;
1371
- r2_prefix: string;
1372
- entry_html_path: string;
1373
- build_status: string;
1374
- }>;
1375
- getAppVersionSourceUrl(app_id: string, version_id: string): Promise<string>;
1376
- /** Deploy history for an app — newest first. Backs `lotics app versions`. */
1377
- listAppVersions(app_id: string, opts?: {
1378
- limit?: number;
1379
- offset?: number;
1380
- }): Promise<{
1381
- current_version_id: string | null;
1382
- versions: Array<{
1383
- id: string;
1384
- version: number;
1385
- message: string | null;
1386
- build_status: string;
1387
- bundle_size_bytes: number | null;
1388
- created_at: string;
1389
- created_by: string | null;
1390
- created_by_name: string | null;
1391
- }>;
1392
- }>;
1393
465
  /**
1394
466
  * Run a named query declared in the app's manifest, scoped to the app's IAM
1395
467
  * principal. Mirrors POST /v1/apps/{app_id}/query.
1396
468
  */
1397
469
  appQuery(app_id: string, body: AppQueryBody): Promise<AppQueryResult>;
1398
- appMembers(app_id: string, group_id?: string): Promise<{
1399
- members: Array<{
1400
- id: string;
1401
- name: string | null;
1402
- email: string | null;
1403
- image: string | null;
1404
- }>;
1405
- }>;
1406
- /**
1407
- * Resolve the full option set (key, label, color) of a named query's select
1408
- * columns, and the units of its figures read per row — the picker companion
1409
- * to `appQuery`. Mirrors
1410
- * POST /v1/apps/{app_id}/field-options.
1411
- */
1412
- appFieldOptions(app_id: string, alias: string): Promise<{
1413
- fields: Record<string, {
1414
- label: string;
1415
- options: Array<{
1416
- key: string;
1417
- label: string;
1418
- color: string;
1419
- }>;
1420
- }>;
1421
- units: Record<string, {
1422
- vocabulary: "unit" | "currency";
1423
- options: Array<{
1424
- key: string;
1425
- label: string;
1426
- }>;
1427
- }>;
1428
- }>;
1429
- /**
1430
- * What the app's writes will change — each bound workflow's record-write subset, each query's column
1431
- * sources, the fields they name. Mirrors GET /v1/apps/{app_id}/write_model; the dev server hands it to
1432
- * the app's SDK whole, so its parts stay opaque here.
1433
- */
1434
- appWriteModel(app_id: string): Promise<unknown>;
1435
- /**
1436
- * Execute a workflow by alias declared in package.json#lotics.workflows.
1437
- * Mirrors POST /v1/apps/{app_id}/workflows/{alias}/execute.
1438
- */
1439
- appWorkflow(app_id: string, alias: string, inputs: unknown, minted_ids?: readonly string[]): Promise<unknown>;
1440
- /**
1441
- * Bind (create or replace) an app workflow by alias via the `set_app_workflow`
1442
- * tool — the SINGLE author of `apps.workflows` + the workflow row. `source` is
1443
- * the verbatim JS-subset body (no `on({...})` trigger). `inputs`/`outputs` are
1444
- * the typed schemas declared in `package.json#lotics.workflows.<alias>`. The
1445
- * server re-verifies the body and echoes the bound `outputs` (declared, else
1446
- * DERIVED from `return({ data })`), so the CLI can show the author what shape
1447
- * `result.data` will carry. Wraps the tool rather than a bespoke endpoint so
1448
- * the file flow stays a convenience over the existing single-author contract.
1449
- */
1450
- setAppWorkflow(app_id: string, alias: string, body: {
1451
- source: string;
1452
- inputs?: Record<string, unknown>;
1453
- outputs?: Record<string, unknown>;
1454
- name?: string;
1455
- description?: string;
1456
- /** The `body_sha` this push was built on. Makes the write conditional: the
1457
- * server refuses it when the live body has moved since, rather than
1458
- * letting a stale copy overwrite an edit its author never saw. */
1459
- expected_body_sha?: string;
1460
- /** Carry out this write even though it breaks what the app's published API
1461
- * promises, snapshotting the broken contract as a new version. */
1462
- acknowledge_breaking_api_change?: boolean;
1463
- /** Run every check the write makes and answer its issues, writing nothing. */
1464
- verify_only?: boolean;
1465
- }): Promise<ToolExecuteResult>;
1466
- /**
1467
- * Bind (create or replace) an app query by alias via the `set_app_query` tool
1468
- * — the deploy-free authoring path for `apps.queries`, parallel to
1469
- * `setAppWorkflow`. `declaration` is the `{ ast, params? }` from
1470
- * `package.json#lotics.queries.<alias>`. The server validates it exactly as a
1471
- * deploy validates the manifest. Note: `apps.queries` is manifest-authoritative,
1472
- * so the next `lotics app deploy` overwrites this from the manifest.
1473
- */
1474
- setAppQuery(app_id: string, alias: string, declaration: {
1475
- ast: unknown;
1476
- params?: Record<string, unknown> | null;
1477
- description?: string | null;
1478
- },
1479
- /** The fingerprint this edit was based on — makes the write conditional. */
1480
- expected_sha?: string,
1481
- /** Carry out this write even though it breaks what the app's published API
1482
- * promises, snapshotting the broken contract as a new version. */
1483
- acknowledge_breaking_api_change?: boolean): Promise<ToolExecuteResult>;
1484
- /**
1485
- * Bind (create or replace) an app agent by alias via the `set_app_agent` tool
1486
- * — the deploy-free authoring path for `apps.agents`, parallel to
1487
- * `setAppWorkflow`/`setAppQuery`.
1488
- *
1489
- * `set_app_agent` REPLACES the whole declaration, so this takes the whole
1490
- * declaration. `lotics app agent set` is the caller that assembles it (prose
1491
- * from `src/agents/<alias>.md`, typed fields from the manifest) precisely so
1492
- * no caller has to remember that a partial payload silently drops
1493
- * `instructions`, `outputs` and the model pin.
1494
- */
1495
- setAppAgent(app_id: string, alias: string,
1496
- /** ONLY the fields being changed. The server merges against the stored
1497
- * declaration, so nothing a caller omits is lost and a field the server adds
1498
- * later needs no change here. Pass `null` to clear an optional field. */
1499
- patch: Record<string, unknown>,
1500
- /** Carry out this write even though it breaks what the app's published API
1501
- * promises, snapshotting the broken contract as a new version. An agent's
1502
- * alias and its declared `inputs`/`outputs` are in the published contract,
1503
- * so the same answer `setAppQuery` takes is owed here. */
1504
- acknowledge_breaking_api_change?: boolean): Promise<ToolExecuteResult>;
1505
- /**
1506
- * Fetch one app workflow's faithful source + bound input/output schemas via
1507
- * `get_app_workflow`. `source` is the JS-subset body re-rendered from the
1508
- * persisted step tree (incl. the `return({ data })` clause, opaque field/option
1509
- * keys) — the exact text `lotics app workflow set` would push back. Feeds
1510
- * `lotics app pull`, which writes it to `src/workflows/<alias>.ts`.
1511
- */
1512
- getAppWorkflow(app_id: string, alias: string): Promise<ToolExecuteResult>;
1513
- /**
1514
- * The app's capability catalog exactly as a chat or MCP caller reads it —
1515
- * every query, workflow and agent alias the caller's scope reaches, with the
1516
- * description each is chosen BY. One read for the whole app, so a check over
1517
- * what those readers see costs one request rather than one per alias.
1518
- */
1519
- getAppCapabilities(app_id: string): Promise<ToolExecuteResult>;
1520
- /**
1521
- * Fetch the server-generated workspace `.d.ts` + the wrapper envelope that
1522
- * make a `src/workflows/<alias>.ts` body locally typecheckable (GAP-59).
1523
- * The server is the single source of the type model — the CLI never
1524
- * re-implements it. `envelope_prefix`/`envelope_suffix` are the exact
1525
- * `async function __workflow(): …` wrapper the server compiles inside, so the
1526
- * local typecheck mirrors the set-time verdict. Mirrors
1527
- * POST /v1/apps/{app_id}/workflows/{alias}/dts.
1528
- *
1529
- * `declaration` (the manifest's `{ inputs?, outputs? }`) is posted as the body
1530
- * `{ declaration }` ONLY when the alias isn't `set` on the server yet — the
1531
- * server then synthesizes the dts from the declared schemas instead of 400ing
1532
- * "no workflow alias". A registered alias needs no declaration (the server's
1533
- * own bound contract wins), so the field is omitted in that case.
1534
- */
1535
- getAppWorkflowDts(app_id: string, alias: string, declaration?: {
1536
- inputs?: Record<string, unknown>;
1537
- outputs?: Record<string, unknown>;
1538
- }): Promise<{
1539
- dts: string;
1540
- envelope_prefix: string;
1541
- envelope_suffix: string;
1542
- }>;
1543
- /**
1544
- * Open a streaming agent run and return the RAW streamed `Response` (the
1545
- * caller reads `res.body`). Unlike `request`, this does not buffer/parse the
1546
- * body — it's the SSE stream the `lotics app dev` harness proxies to the
1547
- * iframe. Mirrors POST /v1/apps/{app_id}/agents/{alias}/runs.
1548
- */
1549
- appAgentRunStream(app_id: string, alias: string, body: {
1550
- session_id: string;
1551
- input: Record<string, unknown>;
1552
- }, signal?: AbortSignal): Promise<Response>;
1553
- /**
1554
- * Continue a PARKED (`awaiting_input`) agent run with the user's answer to its
1555
- * pending `ask_user_choice` — returns the RAW streamed continuation `Response`,
1556
- * exactly like `appAgentRunStream`. Mirrors
1557
- * POST /v1/apps/{app_id}/agent-runs/{run_id}/continue.
1558
- */
1559
- appAgentRunContinueStream(app_id: string, run_id: string, body: {
1560
- tool_call_id: string;
1561
- output: Record<string, unknown>;
1562
- }, signal?: AbortSignal): Promise<Response>;
1563
- /**
1564
- * A session's app-agent run history, oldest-first (the run just started is the
1565
- * last, and its exact id is on the stream response's `x-app-agent-run-id`
1566
- * header). Transcript excluded; structured `output`/`input` included. Mirrors
1567
- * GET /v1/apps/{app_id}/agent-runs.
1568
- */
1569
- listAgentRuns(app_id: string, session_id: string): Promise<{
1570
- runs: AppAgentRunSummary[];
1571
- }>;
1572
- /**
1573
- * A single run by id — the poll read a client follows after its stream drops
1574
- * (a parked `awaiting_input` row carries `pending_interactive` so the question
1575
- * survives reconnection). Mirrors GET /v1/apps/{app_id}/agent-runs/{run_id}.
1576
- */
1577
- getAgentRun(app_id: string, run_id: string): Promise<{
1578
- run: AppAgentRunSummary;
1579
- }>;
1580
- /**
1581
- * Request cancellation of an in-flight (or parked) run. Mirrors
1582
- * POST /v1/apps/{app_id}/agent-runs/{run_id}/cancel.
1583
- */
1584
- cancelAgentRun(app_id: string, run_id: string): Promise<{
1585
- ok: true;
1586
- }>;
1587
- /**
1588
- * Mint a presigned URL for uploading a file into an app. Mirrors
1589
- * POST /v1/apps/{app_id}/files/upload-url.
1590
- */
1591
- appRequestFileUpload(app_id: string, body: {
1592
- filename: string;
1593
- mime_type: string;
1594
- file_size: number;
1595
- }): Promise<{
1596
- file_id: string;
1597
- file_storage_key: string;
1598
- upload_url: string;
1599
- }>;
1600
470
  /**
1601
- * Finalize a presigned upload once the bytes are in storage. Mirrors
1602
- * POST /v1/apps/{app_id}/files/complete.
471
+ * Upload a custom app's build as a new version of the live app — `POST /v1/apps/{id}/versions`.
472
+ * The version carries the app's queries, workflows, agents and capabilities forward unchanged;
473
+ * those are written through their own tools.
1603
474
  */
1604
- appCompleteFileUpload(app_id: string, body: {
1605
- file_id: string;
1606
- file_storage_key: string;
1607
- filename: string;
1608
- }): Promise<{
1609
- file: {
1610
- id: string;
1611
- filename: string;
1612
- mime_type: string;
1613
- url?: string;
1614
- thumbnail_url?: string;
1615
- };
1616
- }>;
1617
- /** A file of the app under another name — a new file over the same bytes, for a save to put in the old one's place. */
1618
- appRenameFile(app_id: string, file_id: string, filename: string): Promise<{
1619
- file: {
1620
- id: string;
1621
- filename: string;
1622
- mime_type: string;
1623
- url?: string;
1624
- thumbnail_url?: string;
1625
- size?: number | null;
1626
- created_at?: string;
1627
- };
1628
- }>;
1629
- appGetRecordComments(app_id: string, record_id: string): Promise<unknown[]>;
1630
- appCreateRecordComment(app_id: string, record_id: string, body: {
1631
- content: string;
1632
- file_ids?: string[];
1633
- }): Promise<unknown>;
1634
- appUpdateRecordComment(app_id: string, record_id: string, comment_id: string, body: {
1635
- content: string;
1636
- file_ids?: string[];
1637
- files?: unknown[];
1638
- }): Promise<unknown>;
1639
- appDeleteRecordComment(app_id: string, record_id: string, comment_id: string): Promise<void>;
1640
- appGetTableCommentCounts(app_id: string, table_id: string): Promise<Record<string, number>>;
1641
475
  deployAppVersion(args: {
1642
476
  app_id: string;
1643
477
  source_archive: Buffer;
1644
478
  dist_archive: Buffer;
479
+ /** The version this deploy was built on; the server refuses one that is no longer current. */
1645
480
  prev_version_id?: string | null;
1646
481
  message?: string | null;
1647
- /**
1648
- * Alias → query declaration map ECHOED BACK from the live row (see
1649
- * `readLiveQueries`), not read from the manifest. Every key the row holds
1650
- * must survive the round trip — `description` included — because a server
1651
- * that treats a present map as authoritative writes exactly what it is
1652
- * sent, so a lossy echo silently strips whatever it forgot.
1653
- */
1654
- queries?: Record<string, {
1655
- ast: unknown;
1656
- params?: Record<string, unknown>;
1657
- description?: string;
1658
- }>;
1659
- /**
1660
- * Opt-in app capabilities from `package.json#lotics.capabilities`. The CLI
1661
- * sends this on every deploy (defaulting to `{}`): the manifest is
1662
- * authoritative, so an empty/absent block turns every capability off.
1663
- * `comments: true` enables the members-only `useComments` primitive.
1664
- */
1665
- capabilities?: {
1666
- comments?: boolean;
1667
- };
1668
- /**
1669
- * The manifest's `lotics.workflows` KEYS — the workflow aliases the deployed
1670
- * code declares (NOT the bindings; `set_app_workflow` / `remove_app_workflow`
1671
- * own `apps.workflows`). Recorded on the new version so `remove_app_workflow`
1672
- * refuses to unbind an alias the served version still calls. Always sent
1673
- * (empty array when none declared).
1674
- */
1675
- workflow_aliases?: string[];
1676
- agent_aliases?: string[];
1677
- query_aliases?: string[];
1678
- /**
1679
- * Ship this version even though its manifest breaks what the app's published
1680
- * API promises, snapshotting the broken contract as a new version. A
1681
- * multipart field is text, so it goes over as the two spellings the server's
1682
- * own schema admits.
1683
- */
1684
- acknowledge_breaking_api_change?: boolean;
1685
482
  }): Promise<{
1686
483
  version_id: string;
1687
484
  version_number: number;
1688
485
  bundle_size_bytes: number;
1689
- /**
1690
- * The origin this version is served from. Optional because a server that
1691
- * predates it answers without one, and the CLI prints the address only when
1692
- * the instance stated it — composing it here would re-derive the scheme and
1693
- * the apps domain the server owns.
1694
- */
486
+ /** The origin this version is served from; composing it here would re-derive what the server owns. */
1695
487
  origin?: string;
1696
488
  }>;
1697
489
  downloadFile(url: string, outputPath: string): Promise<string>;