wicked-crew-api-types 0.170.0 → 0.172.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.
Files changed (2) hide show
  1. package/index.d.ts +782 -9
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -375,6 +375,13 @@ export interface HealthCapabilities {
375
375
  * body is strict there, so the field would be refused).
376
376
  */
377
377
  chatArtifacts?: ChatArtifactsCapabilities;
378
+ /**
379
+ * (api-types 0.172.0, DES-APPS-001) PRESENT means the app store is served: `GET|POST /apps`, `GET /apps/:app`, and
380
+ * the human-only edits, undo, redo and restore. The flags of {@link AppsCapabilities} are about the OTHER routes:
381
+ * each says whether that route serves for real yet (rather than `501`). A skin shows Apps only when this is
382
+ * present. ABSENT on an older daemon.
383
+ */
384
+ apps?: AppsCapabilities;
378
385
  }
379
386
 
380
387
  /** {@link HealthCapabilities.chatArtifacts} (api-types 0.169.0). */
@@ -393,9 +400,17 @@ export interface ChatArtifactsCapabilities {
393
400
  demo: boolean;
394
401
  /**
395
402
  * (api-types 0.170.0) The daemon runs the chat-artifacts TEST configuration (DES §13 A2): every operation resolves,
396
- * and Go on a proposal records a stub dispatch and starts NOTHING. A skin says so on the card. ABSENT otherwise.
403
+ * and Go on a proposal of a kind in {@link stubOps} records a stub dispatch and starts NOTHING (a skin says so on that
404
+ * card). With `stubOps` absent (a daemon before 0.171.0), that is every kind. ABSENT in production.
397
405
  */
398
406
  stub?: true;
407
+ /**
408
+ * (api-types 0.171.0, slice A3) The operations whose Go records a stub dispatch and starts nothing under the TEST
409
+ * configuration; every other advertised operation starts real work (A3: `create` is real, `refine`, `theme` and
410
+ * `demo` stay stubs until their slices). ABSENT in production. A skin says "starts nothing" only for these kinds;
411
+ * before this field, `stub: true` meant every kind.
412
+ */
413
+ stubOps?: ArtifactProposalKind[];
399
414
  }
400
415
 
401
416
  // ── A run's working document (program DES-POWER-MODE §8.3, §9; api-types 0.148.0) ──────────────────
@@ -1257,6 +1272,22 @@ export interface AgentSession {
1257
1272
  * before the field: check `GET /health.capabilities.runChatId` before grouping runs by chat.
1258
1273
  */
1259
1274
  chat_id?: string;
1275
+ /**
1276
+ * (api-types 0.171.0, DES-CHAT-ARTIFACTS-001 §4.3, slice A3) The chat proposal this run answers
1277
+ * (`<chatId>:<turnId>`, or a crew-made `<chatId>:retry:<runId>`), read back from the `run.launched`
1278
+ * entry after a restart. ABSENT on a run no proposal started.
1279
+ */
1280
+ proposal_id?: string;
1281
+ /** (api-types 0.171.0) The artifact a proposal-bound run makes (`<mount>/<doc>`, the mount a project id or `_unfiled`),
1282
+ * so a skin finds an Unfiled run's document. ABSENT on a run no proposal started. */
1283
+ artifact_ref?: string;
1284
+ /**
1285
+ * (api-types 0.171.0, §6.2) A proposal-bound attempt ended without landing: the engine run failed or was stopped,
1286
+ * crew's landing check failed (no file, the document floor, the announce), or a daemon restart interrupted it
1287
+ * ("interrupted by a restart"). The chat and the document are released, and the chat holds a retry proposal
1288
+ * (`<chatId>:retry:<runId>`: Try again into the same document). ABSENT when the attempt landed or is still going.
1289
+ */
1290
+ landing_failed?: { reason: string; at: number };
1260
1291
  /**
1261
1292
  * (crew#552) The onboarding run this run was CHAINED from (a `capture-learnings` run the daemon
1262
1293
  * launched when that onboarding completed) — read back from the `run.launched` entry after a
@@ -7619,6 +7650,16 @@ export interface InteractiveDemoStepDraft {
7619
7650
  export interface InteractiveDocCreateRequest {
7620
7651
  /** The doc name; the bridge slugifies it (409 when taken or retired). */
7621
7652
  name?: string;
7653
+ /**
7654
+ * (api-types 0.171.0, DES-CHAT-ARTIFACTS-001 §5.2) The chat a proposal's create comes from. Accepted ONLY with
7655
+ * `proposal_id`, and only when that chat holds a `proposal_accepting` record of the caller's whose identity names
7656
+ * this document in this mount and whose stored resolution lists every `repo_ref(s)`: then an Unfiled document may
7657
+ * name those repositories (`unfiled_doc_repo` is lifted through the record, nothing else). Anything else is a 400
7658
+ * `proposal_grant_refused` and nothing is created. Crew sends these itself on a proposal's Go.
7659
+ */
7660
+ chat_id?: string;
7661
+ /** (api-types 0.171.0) The proposal (`<chatId>:<turnId>` or `<chatId>:retry:<runId>`); see `chat_id`. */
7662
+ proposal_id?: string;
7622
7663
  /** Omitted = a plain html doc (`html` required); `source` = generated from brief/sources; `demo` = a recording. */
7623
7664
  kind?: 'source' | 'demo';
7624
7665
  /** A plain html doc's content (or a `source` doc's seed). */
@@ -7680,9 +7721,11 @@ export interface InteractiveDocCreateRefusal {
7680
7721
  * Unfiled mount; `invalid_repo_ref` — junk spelling / shape / over the cap; `ambiguous_repo_ref`
7681
7722
  * — a name or basename shared by several member repos (name it by id); `project_mismatch` — the
7682
7723
  * body's `project` is not the route's project (or is present on the Unfiled mount). The proxy
7683
- * canonicalizes an OMITTED `project` from the route.
7724
+ * canonicalizes an OMITTED `project` from the route. `proposal_grant_refused` (api-types 0.171.0) — `chat_id`
7725
+ * without `proposal_id` (or the reverse), or no `proposal_accepting` record of the caller's in that chat that names
7726
+ * this document, this mount and every requested repository.
7684
7727
  */
7685
- code: 'repo_not_in_project' | 'unfiled_doc_repo' | 'invalid_repo_ref' | 'ambiguous_repo_ref' | 'project_mismatch';
7728
+ code: 'repo_not_in_project' | 'unfiled_doc_repo' | 'invalid_repo_ref' | 'ambiguous_repo_ref' | 'project_mismatch' | 'proposal_grant_refused';
7686
7729
  /** The refs the request named, as spelled (best-effort stringified when malformed). */
7687
7730
  requested: string[];
7688
7731
  /** The subset of `requested` that matched no member repo (`repo_not_in_project` only). */
@@ -8488,6 +8531,11 @@ export interface ArtifactProposal {
8488
8531
  sources: ProposalSource[];
8489
8532
  /** Repositories (names), each in the chat's scope. */
8490
8533
  repos: string[];
8534
+ /** (api-types 0.171.0) The same repositories by registry id, in the same order (two checkouts may share a name). */
8535
+ repoRefs?: string[];
8536
+ /** (api-types 0.171.0) A crew-made retry (`sourceRunId`): the document it fills again (`<mount>/<doc>`), the same
8537
+ * artifact as the failed attempt's. ABSENT on a turn's proposal (its document name derives from the pid). */
8538
+ artifactRef?: string;
8491
8539
  /** `null` for a theme (no run). */
8492
8540
  helpers: ProposalHelpers | null;
8493
8541
  /** `null` for a theme. */
@@ -8509,12 +8557,15 @@ export interface ArtifactProposal {
8509
8557
  }
8510
8558
 
8511
8559
  /**
8512
- * What a person may change before Go (typed per kind; crew re-checks every edit with the rules of §4.2). In this
8513
- * release (slice A2) crew takes `title`, `brief`, `sources` and `helpers` on a create, `ask` and `helpers` on a refine,
8514
- * `name` and `patch` on a theme, and `audience`, `show` and `helpers` on a demo; `project`, `repos`, `url` and `allow`
8515
- * are refused (400 `edits_invalid`) until the slices whose forms edit them. A source the person adds that cannot be used
8516
- * is refused too, never dropped. An interrupted (accepting) proposal resumes with its accepted choices: only its
8517
- * `helpers` may change.
8560
+ * What a person may change before Go (typed per kind; crew re-checks every edit with the rules of §4.2). Crew takes
8561
+ * `title`, `brief`, `sources`, `helpers`, `repos` and `project` on a create (api-types 0.171.0, slice A3: New document's
8562
+ * "answer this proposal" mode), `ask` and `helpers` on a refine, `name` and `patch` on a theme, and `audience`, `show`
8563
+ * and `helpers` on a demo; `url` and `allow` are refused (400 `edits_invalid`) until the slices whose forms edit them.
8564
+ * `project` changes only in a chat filed in no project: then every source, repository and turn of the conversation is
8565
+ * re-checked against the target project, and what is outside it is struck (a `message:` source whole, when any of its
8566
+ * records is outside). `repos` must be in the chat's scope (and, with a target project, members of it). A source or
8567
+ * repository the person adds that cannot be used is refused, never dropped. An interrupted (accepting) proposal
8568
+ * resumes with its accepted choices: only its `helpers` may change.
8518
8569
  */
8519
8570
  export interface ProposalEdits {
8520
8571
  /** create */
@@ -8619,6 +8670,15 @@ export type ChatProposalFrame = {
8619
8670
  project_id?: string;
8620
8671
  };
8621
8672
 
8673
+ /**
8674
+ * `/ws` (api-types 0.171.0, DES-CHAT-ARTIFACTS-001 §6.2, slice A3): a proposal-bound attempt ended without landing — the
8675
+ * engine run failed or was stopped, crew's landing check refused it (no draft file, the document floor, a source file
8676
+ * changed during the run, the announce), or a daemon restart interrupted it. The run's DTO carries the same
8677
+ * `landing_failed`, the chat and the document are released, and the chat holds a retry proposal
8678
+ * (`<chatId>:retry:<session>`, a `chatProposal` frame).
8679
+ */
8680
+ export type RunLandingFailedFrame = { type: 'landingFailed'; session: string; artifact_ref: string; reason: string };
8681
+
8622
8682
  // ── System chat: history, close, attachments (api-types 0.137.0, DES-SYSTEM-CHAT "Crew") ────────
8623
8683
  //
8624
8684
  // The floating system chat's past-chats rail, its Close, and its uploads. Capabilities:
@@ -14265,3 +14325,716 @@ export interface PutVoiceDashboardBody {
14265
14325
  layout: string[];
14266
14326
  widgets: VoiceWidgetManifest[];
14267
14327
  }
14328
+
14329
+ // ── Apps (DES-APPS-001 rev 11, slice K2a; api-types 0.172.0) ──────────────────────────────────────
14330
+ //
14331
+ // An app is a git repo crew owns under `~/.wicked/apps/<slug>`: `apps.json` (an {@link AppSpec}),
14332
+ // `queries/<id>.<sql|graphql|json>` (each query's text) and `apps.lock.json` (an {@link AppLock},
14333
+ // written by crew's check, never by an agent or a person). Every version is one commit on the repo's
14334
+ // `main`; crew keeps, outside the repo, a RECEIPT per (app, tree) saying how the tree was accepted, and
14335
+ // only a tree holding one ever runs against a source.
14336
+
14337
+ /** The `schema` value of every v1 `apps.json`. */
14338
+ export type AppSpecSchemaId = 'wicked.apps/v1';
14339
+
14340
+ /**
14341
+ * `apps.json`, the whole app: pages of components on a 12-column grid, the named queries and actions
14342
+ * they bind, the theme and the hosts a link may open. No app code: the `wicked-apps` runtime interprets
14343
+ * this document and nothing else (DES §7.1).
14344
+ *
14345
+ * Identifiers: page and component ids match `^[A-Za-z][A-Za-z0-9_-]{0,63}$` and are unique across the
14346
+ * app; query and action ids match `^[a-z][a-z0-9_]{0,63}$` (a query id is a file name, so lower case
14347
+ * only) and are unique among queries and among actions. crew refuses an unknown key anywhere in the
14348
+ * document, so a field a newer studio writes reaches an older daemon as a refused edit, never as a
14349
+ * silently dropped one.
14350
+ *
14351
+ * The whole document is at most 2 MB of JSON, nests at most 16 deep, holds no list longer than its stated
14352
+ * limit (200 for any list not given one) and no object with more than 256 keys, and never uses the key
14353
+ * `__proto__`.
14354
+ */
14355
+ export interface AppSpec {
14356
+ schema: AppSpecSchemaId;
14357
+ /** The app's title (1-120 characters). */
14358
+ name: string;
14359
+ /** At most 2,000 characters. */
14360
+ description?: string;
14361
+ theme?: AppTheme;
14362
+ /** 1-20 pages; the first is the one an app opens on. */
14363
+ pages: AppPage[];
14364
+ /** At most 100. */
14365
+ queries: AppQuery[];
14366
+ /** At most 50. */
14367
+ actions: AppAction[];
14368
+ /**
14369
+ * Exact host names (lower case, no scheme, no port) a link component may open, over https only. The
14370
+ * host shows the full URL before opening it (DES §7.1). At most 50.
14371
+ */
14372
+ linkHosts: string[];
14373
+ }
14374
+
14375
+ /** Colours are `#rrggbb`. */
14376
+ export interface AppTheme {
14377
+ /** `auto` follows the viewer's setting (the default). */
14378
+ mode?: 'light' | 'dark' | 'auto';
14379
+ accent?: string;
14380
+ /** Chart series colours in order (at most 12). */
14381
+ palette?: string[];
14382
+ density?: 'comfortable' | 'compact';
14383
+ }
14384
+
14385
+ export interface AppPage {
14386
+ id: string;
14387
+ /** 1-80 characters. */
14388
+ title: string;
14389
+ /** At most 100 per page. */
14390
+ components: AppComponent[];
14391
+ }
14392
+
14393
+ /**
14394
+ * A component's place on its page's 12-column grid: column `x` (0-11), row `y` (0-999), `w` columns
14395
+ * (1-12, `x + w <= 12`) and `h` rows (1-50). Below 640 px the runtime stacks components by (`y`, `x`).
14396
+ */
14397
+ export interface AppBox {
14398
+ x: number;
14399
+ y: number;
14400
+ w: number;
14401
+ h: number;
14402
+ }
14403
+
14404
+ /** What every component carries. */
14405
+ export interface AppComponentBase {
14406
+ id: string;
14407
+ box: AppBox;
14408
+ /** At most 120 characters; shown above the component. */
14409
+ title?: string;
14410
+ /** Hidden below 640 px. */
14411
+ hideOnPhone?: boolean;
14412
+ }
14413
+
14414
+ export type AppComponent =
14415
+ | AppTableComponent
14416
+ | AppChartComponent
14417
+ | AppKpiComponent
14418
+ | AppTextComponent
14419
+ | AppFilterComponent
14420
+ | AppFormComponent
14421
+ | AppButtonComponent
14422
+ | AppImageComponent
14423
+ | AppLinkComponent;
14424
+
14425
+ export type AppComponentType = AppComponent['type'];
14426
+
14427
+ /**
14428
+ * Where a query or action parameter's value comes from on the page (DES §4 "Binding"):
14429
+ * - `filter.<id>`: the value of filter component `<id>` (a `date-range` filter gives
14430
+ * `filter.<id>.from` and `filter.<id>.to`);
14431
+ * - `form.<field>`: a field of the form the binding sits on;
14432
+ * - `row.<column>`: a column of the row a table's row action was pressed on;
14433
+ * - `url.<name>`: a parameter of the page's URL.
14434
+ * Viewer values are never bindings: a parameter declared `from: 'viewer.*'` is filled by the server.
14435
+ */
14436
+ export type AppBindingRef = `filter.${string}` | `form.${string}` | `row.${string}` | `url.${string}`;
14437
+ // The template type is the shape; crew's grammar is the rule: `filter.<component id>` with an optional
14438
+ // `.from`/`.to`, `form.<field name>`, `row.<output column>`, `url.<^[A-Za-z_][A-Za-z0-9_]{0,63}$>`.
14439
+
14440
+ /** A component reading a query: the query's id, and a binding for any of its parameters. */
14441
+ export interface AppQueryBinding {
14442
+ query: string;
14443
+ params?: Record<string, AppBindingRef>;
14444
+ }
14445
+
14446
+ /** A control that runs an action: its label, the action's id, and a binding for any of its parameters. */
14447
+ export interface AppActionBinding {
14448
+ /** 1-60 characters. */
14449
+ label: string;
14450
+ action: string;
14451
+ params?: Record<string, AppBindingRef>;
14452
+ }
14453
+
14454
+ /** How a value is shown. `decimals` is 0-10; a currency names its ISO 4217 code. */
14455
+ export type AppFormat =
14456
+ | { kind: 'currency'; currency: string; decimals?: number }
14457
+ | { kind: 'text' | 'number' | 'percent' | 'date' | 'datetime' | 'duration'; decimals?: number };
14458
+
14459
+ export interface AppTableColumn {
14460
+ /** A declared output column of the table's query. */
14461
+ column: string;
14462
+ label?: string;
14463
+ format?: AppFormat;
14464
+ }
14465
+
14466
+ export interface AppTableComponent extends AppComponentBase {
14467
+ type: 'table';
14468
+ data: AppQueryBinding;
14469
+ /** Shown columns in order; absent = every declared output column. */
14470
+ columns?: AppTableColumn[];
14471
+ /** A button on every row (at most 4); its parameters may bind `row.<column>`. */
14472
+ rowActions?: AppActionBinding[];
14473
+ /** Rows per page, 5-500. */
14474
+ pageSize?: number;
14475
+ }
14476
+
14477
+ export interface AppChartSeries {
14478
+ /** A declared output column of the chart's query. */
14479
+ column: string;
14480
+ label?: string;
14481
+ color?: string;
14482
+ }
14483
+
14484
+ export interface AppChartComponent extends AppComponentBase {
14485
+ type: 'chart';
14486
+ chart: 'line' | 'bar' | 'area' | 'pie';
14487
+ data: AppQueryBinding;
14488
+ /** The category (x axis, or pie slice) column. */
14489
+ x: string;
14490
+ /** 1-12 series; a pie has exactly one. */
14491
+ series: AppChartSeries[];
14492
+ stacked?: boolean;
14493
+ }
14494
+
14495
+ export interface AppKpiComponent extends AppComponentBase {
14496
+ type: 'kpi';
14497
+ data: AppQueryBinding;
14498
+ /** The column of the first row shown as the figure. */
14499
+ value: string;
14500
+ format?: AppFormat;
14501
+ /** A column of the first row shown as the change beside the figure. */
14502
+ delta?: string;
14503
+ /** A line under the figure, at most 120 characters ("vs previous 90 days"). */
14504
+ caption?: string;
14505
+ }
14506
+
14507
+ /** Author text, always rendered as text (never HTML or markdown). At most 4,000 characters. */
14508
+ export interface AppTextComponent extends AppComponentBase {
14509
+ type: 'text';
14510
+ text: string;
14511
+ style?: 'heading' | 'body' | 'caption';
14512
+ }
14513
+
14514
+ /** `value` and `label` are at most 200 characters each. */
14515
+ export interface AppFilterOption {
14516
+ value: string;
14517
+ label?: string;
14518
+ }
14519
+
14520
+ /** A select filter's choices: a query's columns, or a fixed list of at most 200. */
14521
+ export type AppFilterOptions =
14522
+ | { kind: 'query'; query: AppQueryBinding; value: string; label?: string }
14523
+ | { kind: 'values'; values: AppFilterOption[] };
14524
+
14525
+ export interface AppFilterComponent extends AppComponentBase {
14526
+ type: 'filter';
14527
+ filter: 'select' | 'date-range' | 'search';
14528
+ label?: string;
14529
+ /** `select` only: the choices, from a query (its `value` and optional `label` columns) or a fixed list. */
14530
+ options?: AppFilterOptions;
14531
+ /** The value before the viewer picks one: a `select`/`search` string, or `{ lastDays }` for a `date-range`. */
14532
+ default?: string | { lastDays: number };
14533
+ }
14534
+
14535
+ export interface AppFormField {
14536
+ /** `^[a-z][a-z0-9_]{0,63}$`; bound as `form.<name>`. */
14537
+ name: string;
14538
+ label?: string;
14539
+ input: 'text' | 'textarea' | 'number' | 'date' | 'checkbox' | 'select';
14540
+ required?: boolean;
14541
+ /** `select` only (at most 200). */
14542
+ options?: AppFilterOption[];
14543
+ }
14544
+
14545
+ export interface AppFormComponent extends AppComponentBase {
14546
+ type: 'form';
14547
+ /** 1-30 fields. */
14548
+ fields: AppFormField[];
14549
+ /** The action the form submits; its parameters bind `form.<name>`. */
14550
+ submit: AppActionBinding;
14551
+ }
14552
+
14553
+ export interface AppButtonComponent extends AppComponentBase {
14554
+ type: 'button';
14555
+ action: AppActionBinding;
14556
+ }
14557
+
14558
+ /**
14559
+ * An image carried in the spec: `src` is a `data:image/(png|jpeg|gif|webp);base64,…` URI whose DECODED
14560
+ * payload is at most 256 KB (262,144 bytes; the URI itself is about a third longer); `alt` is at most
14561
+ * 300 characters. No network images (the frame's CSP has none) and no SVG.
14562
+ */
14563
+ export interface AppImageComponent extends AppComponentBase {
14564
+ type: 'image';
14565
+ src: string;
14566
+ alt: string;
14567
+ }
14568
+
14569
+ /**
14570
+ * Where a link goes: another page of the app (with URL parameters bound like a query's), or out to an
14571
+ * `https://` URL whose host is in {@link AppSpec.linkHosts} (no credentials, no port).
14572
+ */
14573
+ export type AppLinkTarget = { kind: 'page'; page: string; params?: Record<string, AppBindingRef> } | { kind: 'href'; href: string };
14574
+
14575
+ export interface AppLinkComponent extends AppComponentBase {
14576
+ type: 'link';
14577
+ label: string;
14578
+ to: AppLinkTarget;
14579
+ }
14580
+
14581
+ /** A source kind a query reads; it names the text file: `sql` `.sql`, `graphql` `.graphql`, else `.json`. */
14582
+ export type AppQueryKind = 'sql' | 'graphql' | 'rest' | 'mcp' | 'crew';
14583
+
14584
+ /** A declared output column's type. A value the source cannot confirm is validated on every row (DES §7.2). */
14585
+ export type AppColumnType = 'string' | 'number' | 'integer' | 'boolean' | 'date' | 'datetime';
14586
+
14587
+ export interface AppOutputColumn {
14588
+ /** `^[A-Za-z_][A-Za-z0-9_-]{0,127}$` (alias an SQL expression, e.g. `AS order_total`). */
14589
+ name: string;
14590
+ type: AppColumnType;
14591
+ nullable?: boolean;
14592
+ }
14593
+
14594
+ /** `load` (the default; cached 5 s), `every` N seconds (an integer, 15-86,400), or `events` (the built-in `crew` source only). */
14595
+ export type AppRefresh = { mode: 'load' } | { mode: 'every'; seconds: number } | { mode: 'events' };
14596
+
14597
+ /**
14598
+ * One parameter, a JSON Schema subset (no `pattern`: an agent-written regular expression would run on
14599
+ * the server). Names match `^[A-Za-z_][A-Za-z0-9_]{0,63}$`. `from` makes it VIEWER-BOUND: the server fills
14600
+ * it from verified claims and refuses a client value for it, and no component may bind it.
14601
+ *
14602
+ * Constraints apply to their type only: `format`, `minLength` and `maxLength` to strings, `minimum` and
14603
+ * `maximum` to numbers and integers; an `array` takes neither `enum` nor `default`. Bounds are not
14604
+ * reversed; lengths count Unicode code points, as JSON Schema does. A `default` and every `enum` value
14605
+ * satisfy the whole declaration (a `date` is a real calendar date, years 0001-9999; a `date-time` is
14606
+ * RFC 3339 with seconds 00-59, any fraction, `Z` or an offset); strings in a `default` or an `enum` are at
14607
+ * most 1,000 and 200 characters. A REQUIRED parameter with neither `from` nor a `default` must be bound at every
14608
+ * component that uses its query or action.
14609
+ */
14610
+ export interface AppParamSchema {
14611
+ type: 'string' | 'number' | 'integer' | 'boolean' | 'array';
14612
+ /** `array` only. */
14613
+ items?: { type: 'string' | 'number' | 'integer' };
14614
+ format?: 'date' | 'date-time' | 'uuid' | 'email';
14615
+ enum?: Array<string | number>;
14616
+ minimum?: number;
14617
+ maximum?: number;
14618
+ minLength?: number;
14619
+ maxLength?: number;
14620
+ default?: string | number | boolean;
14621
+ description?: string;
14622
+ from?: 'viewer.email' | 'viewer.name' | 'viewer.id' | 'viewer.groups';
14623
+ }
14624
+
14625
+ /** A query's or action's parameters: a JSON Schema object (at most 30 properties). */
14626
+ export interface AppParamsSchema {
14627
+ type: 'object';
14628
+ properties: Record<string, AppParamSchema>;
14629
+ required?: string[];
14630
+ }
14631
+
14632
+ /**
14633
+ * A named read (DES §4 "Query"). Its text is `queries/<id>.<ext>` ({@link AppQueryKind}); the browser
14634
+ * only ever sends the id and parameter values.
14635
+ */
14636
+ export interface AppQuery {
14637
+ id: string;
14638
+ /** The source's name in crew's registry, or `crew` (the built-in source). */
14639
+ source: string;
14640
+ kind: AppQueryKind;
14641
+ description?: string;
14642
+ params?: AppParamsSchema;
14643
+ /** 1-200 declared output columns; the result is projected to exactly these. */
14644
+ output: AppOutputColumn[];
14645
+ /** REST, GraphQL, MCP and crew (never SQL): where the rows are (a JSONPath subset, e.g. `$.items[*]`). */
14646
+ rowPath?: string;
14647
+ /** REST, GraphQL, MCP and crew (never SQL): where "another page exists" is read. */
14648
+ morePath?: string;
14649
+ refresh?: AppRefresh;
14650
+ /** A public app may hold only public queries (DES §9.3). */
14651
+ public?: boolean;
14652
+ }
14653
+
14654
+ /** A value an action sends: a parameter, a literal fixed by the app (a string of at most 1,000 characters), a viewer claim, or crew's `now` or new uuid. */
14655
+ export type AppValue =
14656
+ | AppParamValue
14657
+ | { kind: 'literal'; value: string | number | boolean | null }
14658
+ | { kind: 'viewer'; claim: 'email' | 'name' | 'id' }
14659
+ | { kind: 'crew'; value: 'now' | 'uuid' };
14660
+
14661
+ /** A declared parameter of the action. */
14662
+ export interface AppParamValue {
14663
+ kind: 'param';
14664
+ name: string;
14665
+ }
14666
+
14667
+ /**
14668
+ * An API action (DES §4 "Action"): one REST operation or MCP write tool by its registry tool name, or
14669
+ * one GraphQL mutation document with one root field (at most 16 KB of UTF-8).
14670
+ */
14671
+ export interface AppApiAction {
14672
+ id: string;
14673
+ kind: 'api';
14674
+ source: string;
14675
+ /** The mutation's single root field is the source stage's check. */
14676
+ call: { kind: 'tool'; tool: string } | { kind: 'mutation'; mutation: string };
14677
+ /** At most 50. */
14678
+ args: Record<string, AppValue>;
14679
+ params?: AppParamsSchema;
14680
+ /** Shown on the card as "The app says" (at most 500 characters). */
14681
+ description?: string;
14682
+ }
14683
+
14684
+ /**
14685
+ * A declared Postgres row write (DES §7.4): crew generates the one statement. `table` is
14686
+ * schema-qualified (`support.tickets`, plain identifiers); `key` binds every primary-key column to a
14687
+ * REQUIRED parameter; `set` is every column for an insert (each key column set from its own key
14688
+ * parameter), the changed columns for an update (never a key column), and absent for a delete. Whether
14689
+ * the columns are the table's real ones is the source stage's check.
14690
+ */
14691
+ export interface AppRowWriteAction {
14692
+ id: string;
14693
+ kind: 'row-write';
14694
+ source: string;
14695
+ table: string;
14696
+ op: 'insert' | 'update' | 'delete';
14697
+ /** At most 200 columns. */
14698
+ set?: Record<string, AppValue>;
14699
+ /** 1-16 columns. */
14700
+ key: Record<string, AppParamValue>;
14701
+ params?: AppParamsSchema;
14702
+ description?: string;
14703
+ }
14704
+
14705
+ export type AppAction = AppApiAction | AppRowWriteAction;
14706
+
14707
+ /**
14708
+ * `apps.lock.json`, written by crew's check and committed with the tree it checked; never by an agent or
14709
+ * a person (an edit that names it is refused). It pins what each query and action USES (DES §4):
14710
+ * per source the kind, connection descriptor and its hash; per query the hash of its text and its
14711
+ * contract hash; per action its declaration hash and contract hash; per upload the snapshot digest.
14712
+ * Never a secret, never snapshot bytes. Hashes are lower-case hex SHA-256.
14713
+ */
14714
+ export interface AppLock {
14715
+ schema: 'wicked.apps.lock/v1';
14716
+ sources: Record<string, AppLockSource>;
14717
+ queries: Record<string, AppLockQuery>;
14718
+ actions: Record<string, AppLockAction>;
14719
+ uploads: Record<string, { digest: string }>;
14720
+ }
14721
+
14722
+ export interface AppLockSource {
14723
+ kind: string;
14724
+ /** The non-secret connection descriptor (DES §4 "Source"). */
14725
+ descriptor: Record<string, unknown>;
14726
+ descriptorHash: string;
14727
+ }
14728
+
14729
+ export interface AppLockQuery {
14730
+ source: string;
14731
+ textHash: string;
14732
+ contractHash: string;
14733
+ }
14734
+
14735
+ export interface AppLockAction {
14736
+ source: string;
14737
+ actionHash: string;
14738
+ contractHash: string;
14739
+ }
14740
+
14741
+ // ── Apps: the store and its routes (DES §6.4, §7.6, §9.1) ────────────────────────────────────────
14742
+
14743
+ /**
14744
+ * How a tree was accepted (DES §9.1). Only `you`, `reviewed` and `restored` make a tree part of the
14745
+ * app's ACCEPTED HISTORY (undo, redo and restore move only within it); `published` binds a tree that
14746
+ * already held one of those to a publish manifest.
14747
+ */
14748
+ export type AppReceiptKind = 'you' | 'reviewed' | 'restored' | 'published';
14749
+
14750
+ /**
14751
+ * crew's record that a tree of THIS app passed a check and was accepted. Keyed by (app, tree): the same
14752
+ * tree in another app holds nothing there. Minted only by crew: on a human actor's edit, undo, redo or
14753
+ * restore, on an `apps-turn` run whose review by a distinct seat named the tree, and on a consented
14754
+ * publish. Never stored in the app repo (agent seats mount it).
14755
+ */
14756
+ export interface AppReceipt {
14757
+ kind: AppReceiptKind;
14758
+ tree: string;
14759
+ /** The version that landed with it. */
14760
+ version: number;
14761
+ /** Unix millis. */
14762
+ at: number;
14763
+ /** Who accepted it: the person, or for `reviewed` the actor who launched the turn. */
14764
+ actor: Actor;
14765
+ /**
14766
+ * `restored`: the version restored, and that version's own provenance followed through any chain of
14767
+ * restores (`originKind` is `you` or `reviewed`, `originVersion` the version that first held it).
14768
+ */
14769
+ restoredFrom?: { version: number; originKind: 'you' | 'reviewed'; originVersion: number };
14770
+ /** `reviewed`: the turn's run and the seats that built and reviewed it (always distinct). */
14771
+ review?: { runId: string; builder: string; reviewer: string };
14772
+ /** `published`: the publish run, the manifest digest and each produced artifact's digest. */
14773
+ publish?: { runId: string; manifestDigest: string; artifacts: Record<string, string> };
14774
+ }
14775
+
14776
+ /** Which checks ran before a version landed (DES §6.2 "Checks are staged by what changed"). */
14777
+ export interface AppCheckSummary {
14778
+ /**
14779
+ * `spec`: schema, bindings, link hosts and file confinement only (a layout, prop, theme or label
14780
+ * change). `data`: those plus the read policy and the per-kind source check for what changed.
14781
+ * `full`: those for every query and action (an undo, redo or restore, against today's sources).
14782
+ */
14783
+ level: 'spec' | 'data' | 'full';
14784
+ /** Queries and actions the source stage checked (empty at `spec`). */
14785
+ checked: string[];
14786
+ }
14787
+
14788
+ /** One version: one commit on the app repo's `main`. */
14789
+ export interface AppVersion {
14790
+ /** 1, 2, 3, … per app (the strip's `v14`). */
14791
+ version: number;
14792
+ commit: string;
14793
+ tree: string;
14794
+ /** The version it was made on; `null` for the first. */
14795
+ base: number | null;
14796
+ /** Unix millis. */
14797
+ at: number;
14798
+ /** A person (`human`), a seat that built a turn (`seat`), or crew itself (`crew`, an app's first version). */
14799
+ author: { kind: 'human' | 'seat' | 'crew'; id: string };
14800
+ /** The receipt it landed with; `null` = this tree never runs against a source. */
14801
+ receipt: AppReceipt | null;
14802
+ /** One line for the strip ("Moved the KPIs above the charts"), at most 200 characters. */
14803
+ summary: string;
14804
+ check: AppCheckSummary;
14805
+ }
14806
+
14807
+ /**
14808
+ * The undo pointer (DES §6.4), kept per app by crew so every tab agrees. `states` are the versions of
14809
+ * the accepted history in order and `pointer` indexes the current one. Undo lands `states[pointer-1]`'s
14810
+ * tree as a new version and moves the pointer back; redo lands `states[pointer+1]`'s; a new edit,
14811
+ * landed turn or restore drops everything after the pointer and appends itself.
14812
+ */
14813
+ export interface AppHistory {
14814
+ states: number[];
14815
+ pointer: number;
14816
+ canUndo: boolean;
14817
+ canRedo: boolean;
14818
+ }
14819
+
14820
+ /** A turn in flight: the app is read-only for edits, undo, redo and restore until it ends (`409 turn_in_flight`). */
14821
+ export interface AppTurnState {
14822
+ runId: string;
14823
+ /** Unix millis. */
14824
+ startedAt: number;
14825
+ /** The version the turn builds on. */
14826
+ base: number;
14827
+ /** The actor id that launched it. */
14828
+ actor: string;
14829
+ }
14830
+
14831
+ /** `GET /apps` item. */
14832
+ export interface AppSummary {
14833
+ /** `^[a-z][a-z0-9-]{0,47}$`; `check` and `uploads` are reserved. */
14834
+ slug: string;
14835
+ name: string;
14836
+ projectId: string;
14837
+ /** The app repo's id in crew's repo registry. */
14838
+ repoId: string;
14839
+ /** Unix millis. */
14840
+ createdAt: number;
14841
+ head: { version: number; tree: string; receipt: AppReceiptKind | null };
14842
+ turn: AppTurnState | null;
14843
+ }
14844
+
14845
+ /** `GET /apps` (observer); `?project=<id>` keeps one project's apps. */
14846
+ export interface AppsListResponse {
14847
+ apps: AppSummary[];
14848
+ }
14849
+
14850
+ /** `POST /apps` (operator): a new app, an empty repo in the project with crew's first version. */
14851
+ export interface CreateAppBody {
14852
+ slug: string;
14853
+ /** The app's title; defaults to the slug. */
14854
+ name?: string;
14855
+ projectId: string;
14856
+ }
14857
+
14858
+ /** The app at head: the spec, the lock, every query's text, the versions and the undo pointer. */
14859
+ export interface AppDetail extends AppSummary {
14860
+ spec: AppSpec;
14861
+ lock: AppLock;
14862
+ /** Query id → its text at head. */
14863
+ queryText: Record<string, string>;
14864
+ /** Oldest first. */
14865
+ versions: AppVersion[];
14866
+ history: AppHistory;
14867
+ }
14868
+
14869
+ /** `GET /apps/:app` (observer), and `POST /apps` (201). */
14870
+ export interface AppDetailResponse {
14871
+ app: AppDetail;
14872
+ }
14873
+
14874
+ /**
14875
+ * One change in an edit burst. `spec` replaces `apps.json`; `query-text` writes the text of a query the
14876
+ * resulting spec declares (crew removes the text of a query the spec no longer declares). Nothing else
14877
+ * in the repo can be written: `apps.lock.json` is crew's.
14878
+ */
14879
+ export type AppEditOp = { op: 'spec'; spec: AppSpec } | { op: 'query-text'; query: string; text: string };
14880
+
14881
+ /**
14882
+ * `POST /apps/:app/edits` (HUMAN operator only): one `you` version from one edit burst (1-50 ops). `base`
14883
+ * is the head version the edit was made on: a stale one is `409 stale_base`, and while a turn runs every
14884
+ * edit is `409 turn_in_flight`.
14885
+ */
14886
+ export interface AppEditsBody {
14887
+ base: number;
14888
+ ops: AppEditOp[];
14889
+ /** The strip's line; crew writes one when absent. */
14890
+ summary?: string;
14891
+ }
14892
+
14893
+ /** `POST /apps/:app/undo` and `/redo` (HUMAN operator only). */
14894
+ export interface AppHistoryMoveBody {
14895
+ base: number;
14896
+ }
14897
+
14898
+ /**
14899
+ * `POST /apps/:app/restore` (HUMAN operator only): land `version` (a version number, or a commit of the
14900
+ * app repo) as a new version, only when its tree holds an accepted receipt for this app.
14901
+ */
14902
+ export interface AppRestoreBody {
14903
+ base: number;
14904
+ version: number | string;
14905
+ }
14906
+
14907
+ /** The answer to an edit, undo, redo or restore that landed: the app after it, and the version it made. */
14908
+ export interface AppLandedResponse {
14909
+ app: AppDetail;
14910
+ landed: AppVersion;
14911
+ }
14912
+
14913
+ /**
14914
+ * `POST /apps/:app/turns` (operator): one chat message becomes one governed `apps-turn` run (Build → Check →
14915
+ * Review) on the head version. While it runs the app is read-only for edits, undo, redo and restore, and a second
14916
+ * turn is `409 turn_in_flight`.
14917
+ */
14918
+ export interface AppTurnBody {
14919
+ /** The head version the message was written on; a stale one is `409 stale_base`. */
14920
+ base: number;
14921
+ /** 1-8,000 characters. */
14922
+ message: string;
14923
+ /** Component ids the message is about (the composer's chips), at most 20. */
14924
+ about?: string[];
14925
+ }
14926
+
14927
+ /** `POST /apps/:app/turns` 202. */
14928
+ export interface AppTurnResponse {
14929
+ runId: string;
14930
+ turn: AppTurnState;
14931
+ }
14932
+
14933
+ /** `POST /apps/:app/query` (observer): run one named query of an accepted version (DES §7.2). */
14934
+ export interface AppQueryBody {
14935
+ /** A version number, or a commit of the app repo; its tree must hold an accepted receipt. */
14936
+ version: number | string;
14937
+ query: string;
14938
+ params?: Record<string, unknown>;
14939
+ }
14940
+
14941
+ /** One cell: values are rendered as text by the runtime. */
14942
+ export type AppCell = string | number | boolean | null;
14943
+
14944
+ /** `POST /apps/:app/query` 200 (DES §7.2). `rows` are aligned with `columns`. */
14945
+ export interface AppQueryResponse {
14946
+ columns: AppOutputColumn[];
14947
+ rows: AppCell[][];
14948
+ truncated: boolean;
14949
+ hasMore: boolean;
14950
+ ms: number;
14951
+ /** Unix millis of the cached answer, `null` when it ran now. */
14952
+ cachedAt: number | null;
14953
+ }
14954
+
14955
+ /** One reason a check refused a tree. `path` is a JSON path into `apps.json`, or a repo path. */
14956
+ export interface AppCheckFinding {
14957
+ stage: 'spec' | 'files' | 'policy' | 'source';
14958
+ code: string;
14959
+ path: string;
14960
+ message: string;
14961
+ }
14962
+
14963
+ /**
14964
+ * Every refusal the app routes answer, by `code`:
14965
+ * - 400 `bad_request`; 403 `human_only` (the route needs a human operator: an agent-kind token is refused);
14966
+ * - 404 `unknown_app`, `unknown_version`, `unknown_query`, `unknown_project`;
14967
+ * - 409 `stale_base` (with `head`), `turn_in_flight` (with `turn`), `not_accepted` (the tree holds no
14968
+ * accepted receipt for this app), `nothing_to_undo`, `nothing_to_redo`, `slug_taken` (with
14969
+ * `suggestion`), `source_check_unavailable` (the tree has queries or actions and this daemon cannot
14970
+ * run the source stage yet, so nothing lands);
14971
+ * - 422 `check_failed` (with `findings`), `reserved_slug`;
14972
+ * - 429 `rate_limited` (with `retryAfterMs`: a query queue or a per-viewer rate is full, DES §7.5);
14973
+ * - 501 `not_implemented` (a route a later slice serves; nothing happened);
14974
+ * - 503 `apps_unavailable`.
14975
+ */
14976
+ export interface AppErrorBody {
14977
+ code:
14978
+ | 'bad_request'
14979
+ | 'human_only'
14980
+ | 'unknown_app'
14981
+ | 'unknown_version'
14982
+ | 'unknown_query'
14983
+ | 'unknown_project'
14984
+ | 'stale_base'
14985
+ | 'turn_in_flight'
14986
+ | 'not_accepted'
14987
+ | 'nothing_to_undo'
14988
+ | 'nothing_to_redo'
14989
+ | 'slug_taken'
14990
+ | 'source_check_unavailable'
14991
+ | 'check_failed'
14992
+ | 'reserved_slug'
14993
+ | 'not_implemented'
14994
+ | 'rate_limited'
14995
+ | 'apps_unavailable';
14996
+ error: string;
14997
+ /** `rate_limited`: when to try again (also sent as `Retry-After`). */
14998
+ retryAfterMs?: number;
14999
+ head?: number;
15000
+ turn?: AppTurnState;
15001
+ findings?: AppCheckFinding[];
15002
+ suggestion?: string;
15003
+ }
15004
+
15005
+ /**
15006
+ * {@link HealthCapabilities.apps} (api-types 0.172.0): present when crew serves the app store
15007
+ * (`/api/v1/apps`, list, add, read, edits, undo, redo, restore); each flag is true only once its slice
15008
+ * serves that route for real rather than answering `501`.
15009
+ */
15010
+ export interface AppsCapabilities {
15011
+ /** `POST /apps/:app/query` runs queries (until then it checks the receipt, then answers `501`). */
15012
+ query: boolean;
15013
+ /** `POST /apps/:app/actions/:id/prepare|run|grant`, `GET …/actions/records/:id`. */
15014
+ actions: boolean;
15015
+ /** `POST /apps/:app/turns` launches `apps-turn` runs. */
15016
+ turns: boolean;
15017
+ /** `POST /apps/:app/publish`. */
15018
+ publish: boolean;
15019
+ /** `POST /apps/uploads`. */
15020
+ uploads: boolean;
15021
+ /** The read policy and the per-kind source check run, so a change to queries or actions can land. */
15022
+ sourceCheck: boolean;
15023
+ }
15024
+
15025
+ /**
15026
+ * `POST /repos` body. `create: true` (api-types 0.172.0, DES-APPS-001): crew makes `<apps root>/<name>`
15027
+ * (`~/.wicked/apps` by default), runs `git init` with one empty commit and registers it; no onboarding
15028
+ * run starts (`onboardRunId: null`), and `rootPath`/`gitUrl` are refused beside it. A taken name is
15029
+ * `409 slug_taken` with a `suggestion`.
15030
+ */
15031
+ export interface RegisterRepoBody {
15032
+ name: string;
15033
+ rootPath?: string;
15034
+ gitUrl?: string;
15035
+ create?: true;
15036
+ projectId?: string;
15037
+ channel?: 'studio' | 'cli' | 'api';
15038
+ actor?: string;
15039
+ autoCapture?: boolean;
15040
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-crew-api-types",
3
- "version": "0.170.0",
3
+ "version": "0.172.0",
4
4
  "description": "The wire contract of the wicked-crew daemon's /api/v1 REST surface and /ws CoreEvent frames \u2014 types only, zero runtime",
5
5
  "type": "module",
6
6
  "types": "./index.d.ts",