@lotics/cli 0.76.1 → 0.86.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.
@@ -1,11 +1,14 @@
1
1
  /**
2
- * Dispatch smoke test over the BUILT CLI artifact — every `package` subcommand
3
- * must route to its own handler, proven by its usage/refusal line appearing on
4
- * a bare invocation. The dispatch in cli.ts is one hand-rolled argv walk with
5
- * subcommand names repeated across command families (`doctor` exists in both
6
- * `workspace` and `package`) and split positional conventions (`toolArgs` +
7
- * `restArgs`), and nothing else tests it: `package yank` shipped dispatched
8
- * inside the WORKSPACE family and surfaced only on the first live invocation.
2
+ * Dispatch smoke test over the BUILT CLI artifact — every `package` subcommand,
3
+ * the top-level consumer verbs (`install`/`uninstall`/`upgrade`), and the app
4
+ * author verbs (publish/release/unpublish) must route to their own handler,
5
+ * proven by the usage/refusal line appearing on a bare invocation. The dispatch
6
+ * in cli.ts is one hand-rolled argv walk with subcommand names repeated across
7
+ * command families (`doctor` exists in both `workspace` and `package`) and split
8
+ * positional conventions (top-level verbs read the id from `subcommand`; the
9
+ * `package` family from `toolArgs`), and nothing else tests it: `package yank`
10
+ * shipped dispatched inside the WORKSPACE family and surfaced only on the first
11
+ * live invocation.
9
12
  *
10
13
  * The fake API key satisfies `requireClient` (client construction is offline);
11
14
  * every asserted path exits before any network call. Spawns run in an empty
@@ -48,18 +51,11 @@ describe("lotics package <subcommand> dispatch", () => {
48
51
  // subcommand's OWN usage line — reaching it proves family routing AND that
49
52
  // the usage gate fires before any network/filesystem work.
50
53
  const usageCases = [
51
- ["install", /Usage: lotics package install/],
52
- ["uninstall", /Usage: lotics package uninstall/],
53
54
  ["config", /Usage: lotics package config/],
54
- ["retire", /Usage: lotics package retire <package_id>/],
55
55
  ["show", /Usage: lotics package show <package_id>/],
56
- ["upgrade", /Usage: lotics package upgrade/],
57
56
  ["yank", /Usage: lotics package yank <package_id> <version>/],
58
- ["rebind-role", /Usage: lotics package rebind-role/],
59
- ["fleet-upgrade", /Usage: lotics package fleet-upgrade/],
60
- ["extract", /Usage: lotics package extract/],
61
- ["adopt", /Usage: lotics package adopt/],
62
- ["new", /Usage: lotics package new/],
57
+ // Folded into the upgrade grammar — the removed verb must redirect loudly.
58
+ ["rebind-role", /folded into the upgrade grammar[\s\S]*--resolve roles\./],
63
59
  ];
64
60
  for (const [sub, usage] of usageCases) {
65
61
  it(`routes "package ${sub}" to its handler (usage on missing args)`, () => {
@@ -69,16 +65,30 @@ describe("lotics package <subcommand> dispatch", () => {
69
65
  expect(status).toBe(1);
70
66
  });
71
67
  }
72
- // Path-defaulting subcommands: in an empty cwd they must fail on the missing
73
- // package project their handler's message, not the dispatcher's. (`sync`
74
- // is excluded: it validates the dev workspace over the network BEFORE
75
- // reading the project, so it can't be smoke-tested offline.)
76
- const projectCases = ["build", "publish"];
77
- for (const sub of projectCases) {
78
- it(`routes "package ${sub}" to its handler (missing project in empty cwd)`, () => {
68
+ // The high-traffic consumer verbs MOVED to the top level. The old
69
+ // `lotics package <verb>` forms must REJECT with a redirect (never silently
70
+ // do nothing) proving the removal is loud and points to the new form.
71
+ const movedForms = [
72
+ ["install", /moved to the top level.*lotics install/],
73
+ ["uninstall", /moved to the top level.*lotics uninstall/],
74
+ ["upgrade", /moved to the top level.*lotics upgrade/],
75
+ ["fleet-upgrade", /moved to the top level.*lotics upgrade <package_id>/],
76
+ ];
77
+ for (const [sub, redirect] of movedForms) {
78
+ it(`rejects the moved "package ${sub}" form with a top-level redirect`, () => {
79
79
  const { status, stderr } = runCli(["package", sub]);
80
- expect(stderr).toMatch(/No package\.json in|not a package project/);
81
- expect(stderr).not.toMatch(/Unknown package subcommand/);
80
+ expect(stderr).toMatch(redirect);
81
+ expect(status).toBe(1);
82
+ });
83
+ }
84
+ // Deleted author-loop + package-project surfaces must be GONE, not silently
85
+ // absorbed: each now falls through to the unknown-subcommand refusal. Content
86
+ // packages are published via the `publish_content`/`release_content` tools
87
+ // (`lotics run …`), apps via `lotics app publish`/`release`.
88
+ for (const sub of ["dev", "sync", "reset", "extract", "adopt", "retire", "release", "new", "build", "publish"]) {
89
+ it(`rejects the removed "package ${sub}" subcommand`, () => {
90
+ const { status, stderr } = runCli(["package", sub]);
91
+ expect(stderr).toMatch(/Unknown package subcommand/);
82
92
  expect(status).toBe(1);
83
93
  });
84
94
  }
@@ -88,3 +98,58 @@ describe("lotics package <subcommand> dispatch", () => {
88
98
  expect(status).toBe(1);
89
99
  });
90
100
  });
101
+ describe("lotics top-level consumer-verb dispatch", () => {
102
+ // The noun-less consumer verbs route from the top level (the package id is the
103
+ // second positional → `subcommand`), each proven by its OWN usage line on a
104
+ // bare invocation — reaching it fires before any network work.
105
+ const usageCases = [
106
+ ["install", /Usage: lotics install <package_id>/],
107
+ ["uninstall", /Usage: lotics uninstall <app_id\|package_id>/],
108
+ ["upgrade", /Usage: lotics upgrade <app_id \| package_id>/],
109
+ ];
110
+ for (const [verb, usage] of usageCases) {
111
+ it(`routes top-level "${verb}" to its handler (usage on missing id)`, () => {
112
+ const { status, stderr } = runCli([verb]);
113
+ expect(stderr).toMatch(usage);
114
+ expect(stderr).not.toMatch(/Unknown command/);
115
+ expect(status).toBe(1);
116
+ });
117
+ }
118
+ // CLEAN BREAK: content installs are addressed by their PACKAGE id — an explicit
119
+ // `pci_` resource id must get a loud redirect to the package-id form. The redirect
120
+ // header prints SYNCHRONOUSLY (before the best-effort list-content resolution that
121
+ // spells out the exact command), so it is observable without a live registry; the
122
+ // process exits 1 either way (best-effort resolution fails on the fake key).
123
+ for (const verb of ["upgrade", "uninstall"]) {
124
+ it(`redirects an explicit pci_ id on "${verb}" to the package-id form`, () => {
125
+ const { status, stderr } = runCli([verb, "pci_dispatch_smoke_fake"]);
126
+ expect(stderr).toMatch(/addressed by their PACKAGE id now/);
127
+ expect(stderr).not.toMatch(/Unknown command/);
128
+ expect(status).toBe(1);
129
+ });
130
+ }
131
+ });
132
+ describe("lotics app author-verb dispatch", () => {
133
+ // `app publish` (no id, empty cwd) must fail on the missing local app
134
+ // manifest — its handler's message, proving routing without any network.
135
+ it('routes "app publish" to its handler (no app id in empty cwd)', () => {
136
+ const { status, stderr } = runCli(["app", "publish"]);
137
+ expect(stderr).toMatch(/No app id/);
138
+ expect(stderr).not.toMatch(/Unknown app subcommand/);
139
+ expect(status).toBe(1);
140
+ });
141
+ // `app release` requires -m before any resolution.
142
+ it('routes "app release" to its handler (usage on missing -m)', () => {
143
+ const { status, stderr } = runCli(["app", "release"]);
144
+ expect(stderr).toMatch(/Usage: lotics app release/);
145
+ expect(stderr).not.toMatch(/Unknown app subcommand/);
146
+ expect(status).toBe(1);
147
+ });
148
+ // `app unpublish` requires an id.
149
+ it('routes "app unpublish" to its handler (usage on missing id)', () => {
150
+ const { status, stderr } = runCli(["app", "unpublish"]);
151
+ expect(stderr).toMatch(/Usage: lotics app unpublish/);
152
+ expect(stderr).not.toMatch(/Unknown app subcommand/);
153
+ expect(status).toBe(1);
154
+ });
155
+ });
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { KnowledgeUpgradeEntry, KnowledgeUpgradeResolutions, ContentUpgradeResolutions, ModifiedArtifact, PackageContentBinding } from "@lotics/shared/schemas/packages";
1
+ import type { KnowledgeUpgradeEntry, ModifiedArtifact, PackageContentBinding, UpgradeResolutions } from "@lotics/shared/schemas/packages";
2
2
  /**
3
3
  * The error message for a non-ok response. A genuine JSON error (a 4xx carrying
4
4
  * a `message`) surfaces verbatim; a non-JSON body (a gateway HTML page), any
@@ -44,14 +44,6 @@ export interface WorkspaceInfo {
44
44
  default_currency: string;
45
45
  organization_id: string;
46
46
  created_at: string;
47
- /**
48
- * Whether this is a throwaway app-package dev workspace (set with
49
- * `lotics workspace create <name> --dev`). Gates the destructive package
50
- * dev/sync scaffold + the server-side `package reset`. Optional because the
51
- * list endpoint only carries it once the server serializes `is_dev`; an absent
52
- * value is treated as non-dev by the guard (fail closed).
53
- */
54
- is_dev?: boolean;
55
47
  }
56
48
  export interface ToolExecuteResult {
57
49
  result: unknown;
@@ -74,23 +66,7 @@ export interface FileUploadResult {
74
66
  error: string;
75
67
  }>;
76
68
  }
77
- /**
78
- * A materialized app package's binding — alias → this workspace's concrete id,
79
- * one string-map per namespace. Mirrors the server's `bindingSchema`. The
80
- * `workflows` map is the entity-lifecycle table-workflow ROW ledger (an artifact
81
- * registry, not a schema binding), carried in the same shape. The CLI never
82
- * interprets these maps — it round-trips them verbatim between `extract` (which
83
- * emits the origin workspace's) and `adopt` (which replays it onto the app).
84
- */
85
- export interface PackageBinding {
86
- entities: Record<string, string>;
87
- fields: Record<string, string>;
88
- options: Record<string, string>;
89
- templates: Record<string, string>;
90
- roles: Record<string, string>;
91
- workflows: Record<string, string>;
92
- }
93
- /** One finding from a bespoke→package extraction (`extractPackage`). */
69
+ /** One finding from a package publish/release extract. */
94
70
  export interface ExtractFinding {
95
71
  severity: "error" | "warning" | "info";
96
72
  area: string;
@@ -143,16 +119,9 @@ export declare class LoticsClient {
143
119
  /** The workspace id the client targets (the `x-workspace-id` header), if resolved. */
144
120
  getWorkspaceId(): string | undefined;
145
121
  listWorkspaces(): Promise<WorkspaceInfo[]>;
146
- /**
147
- * Resolve one workspace's info by id from the org's workspace list (the only
148
- * API-key-accessible source carrying `is_dev`). Returns null when the
149
- * workspace isn't visible to these credentials.
150
- */
151
- getWorkspaceInfo(id: string): Promise<WorkspaceInfo | null>;
152
122
  createWorkspace(body: {
153
123
  name: string;
154
124
  timezone?: string;
155
- is_dev?: boolean;
156
125
  }): Promise<WorkspaceInfo>;
157
126
  deleteWorkspace(id: string): Promise<{
158
127
  id: string;
@@ -277,7 +246,7 @@ export declare class LoticsClient {
277
246
  /**
278
247
  * Uninstall a standalone content package — delete the installation row. By
279
248
  * default the package-bound docs are ARCHIVED; `keep_content` retains them as
280
- * ordinary workspace docs. Admin-only. Backs `lotics package uninstall`.
249
+ * ordinary workspace docs. Admin-only. Backs `lotics uninstall`.
281
250
  */
282
251
  uninstallContentPackage(installation_id: string, opts?: {
283
252
  keep_content?: boolean;
@@ -314,7 +283,7 @@ export declare class LoticsClient {
314
283
  */
315
284
  applyContentInstallationUpgrade(installation_id: string, body: {
316
285
  version?: number;
317
- resolutions?: ContentUpgradeResolutions;
286
+ resolutions?: UpgradeResolutions;
318
287
  }): Promise<ContentInstallation>;
319
288
  /**
320
289
  * List a workspace's package-managed knowledge installations, each folded with
@@ -331,7 +300,7 @@ export declare class LoticsClient {
331
300
  } | null;
332
301
  }>>;
333
302
  /**
334
- * Uninstall a package installation (backs `lotics package uninstall`). Does
303
+ * Uninstall a package installation (backs `lotics uninstall`). Does
335
304
  * everything DELETE does plus archives the installation's lifecycle
336
305
  * artifacts; with `archive_tables` it also archives the scaffolded entity
337
306
  * tables — refused server-side unless this installation created them
@@ -355,10 +324,11 @@ export declare class LoticsClient {
355
324
  config: Record<string, string | number | boolean>;
356
325
  }>;
357
326
  /**
358
- * Retire (or `undo` un-retire) a registry package (backs `lotics package
359
- * retire`). Retiring refuses NEW installs and hides the package from
360
- * non-owning orgs; existing installations keep working and may still upgrade.
361
- * Owner-org admin-only.
327
+ * Retire (or `undo` un-retire) a registry package (backs `lotics app
328
+ * unpublish` the endpoint/audit action keep the `retire` name to avoid API
329
+ * churn). Retiring refuses NEW installs and hides the package from non-owning
330
+ * orgs; existing installations keep working and may still upgrade. Owner-org
331
+ * admin-only.
362
332
  */
363
333
  retirePackage(package_id: string, body: {
364
334
  undo: boolean;
@@ -380,65 +350,12 @@ export declare class LoticsClient {
380
350
  workspace_id: string;
381
351
  current_version_id: string | null;
382
352
  }>;
383
- /**
384
- * Extract a DRAFT app package from an existing bespoke app — the promotion
385
- * read (docs/packages.md § Promotion). Pure: nothing is written. Returns
386
- * the alias-keyed draft `contract` (opaque to the CLI — the server is the
387
- * validating authority), the origin workspace's `binding` (which doubles as
388
- * the adopt binding), a findings `report` (any `error` ⇒ not publishable
389
- * as-is), and the file-backed `template_files` the CLI must stage into the
390
- * project at their `bytes_ref` paths. Backs `lotics package extract`.
391
- * Admin-only.
392
- */
393
- extractPackage(app_id: string, opts?: {
394
- knowledge?: Array<{
395
- alias: string;
396
- doc_id: string;
397
- }>;
398
- }): Promise<{
399
- contract: unknown;
400
- binding: PackageBinding;
401
- report: ExtractFinding[];
402
- template_files: Array<{
403
- bytes_ref: string;
404
- file_id: string;
405
- filename: string;
406
- }>;
407
- /** Knowledge doc content to write to `knowledge/<alias>.md` in the draft project. */
408
- knowledge_files: Array<{
409
- content_ref: string;
410
- content: string;
411
- }>;
412
- /** alias → the origin workspace's kdc_ id (the adopt knowledge binding). */
413
- knowledge_binding: Record<string, string>;
414
- }>;
415
- /**
416
- * Adopt a published package onto an EXISTING (bespoke or ejected) app — the
417
- * final promotion step. The workspace already holds the concrete objects, so
418
- * nothing is scaffolded or rewritten: the server verifies the `binding` is
419
- * complete, live, and FAITHFUL to the version's contract, then writes only the
420
- * installation pin (the app becomes installation #1, upgradeable again). A
421
- * ConflictError names the aliases that diverge. `version` omitted adopts the
422
- * latest. Backs `lotics package adopt`. Admin-only.
423
- */
424
- adoptPackage(app_id: string, body: {
425
- package_id: string;
426
- version?: number;
427
- binding: PackageBinding;
428
- /** alias → this workspace's kdc_ id for the contract's knowledge docs (from extract). */
429
- knowledge_binding?: Record<string, string>;
430
- }): Promise<{
431
- id: string;
432
- name: string;
433
- package_id: string | null;
434
- package_version: number | null;
435
- }>;
436
353
  /**
437
354
  * Fleet upgrade — bring every installation of a package across the CALLER'S
438
355
  * org to the target version (latest when omitted) in one call. Hands-off
439
356
  * applies only where the preview is clean; installations with breaking/
440
357
  * drift/modified-core findings are skipped and reported for the normal
441
- * per-installation consent flow. Backs `lotics package fleet-upgrade`.
358
+ * per-installation consent flow. Backs `lotics upgrade <package_id>` (fleet).
442
359
  * Admin-only; org-scoped (no workspace header needed).
443
360
  */
444
361
  /**
@@ -472,27 +389,6 @@ export declare class LoticsClient {
472
389
  message?: string;
473
390
  }>;
474
391
  }>;
475
- /**
476
- * Create a registry app package — the Lotics-owned, workspace-agnostic
477
- * blueprint. `lotics package publish` calls this on first publish (when the
478
- * local manifest has no `package_id`), then publishes version 1 against the
479
- * returned id. Admin-only.
480
- */
481
- createPackage(body: {
482
- name: string;
483
- description?: string | null;
484
- /** 'app' (default) | 'content'. Immutable after create. */
485
- kind?: PackageKind;
486
- }): Promise<{
487
- id: string;
488
- name: string;
489
- description: string | null;
490
- kind: PackageKind;
491
- latest_version: number;
492
- is_official: boolean;
493
- created_at: string;
494
- updated_at: string;
495
- }>;
496
392
  /**
497
393
  * Fetch a registry app package's metadata (incl. `kind`, `latest_version` and
498
394
  * the Lotics-backed `is_official` trust badge). Admin-only; cross-tenant by id.
@@ -520,27 +416,6 @@ export declare class LoticsClient {
520
416
  created_at: string;
521
417
  }>;
522
418
  }>;
523
- /**
524
- * Publish a new immutable package version — multipart upload of the alias-keyed
525
- * contract (JSON) + the prebuilt code bundle (a gzipped tarball carrying
526
- * `source.tar.gz` + `dist.tar.gz` members). The server validates the contract +
527
- * bundle, then allocates the next monotonic version. The `contract` is opaque
528
- * JSON to the transport (the server is the validating authority). Admin-only.
529
- */
530
- publishPackageVersion(package_id: string, args: {
531
- contract: unknown;
532
- bundle: Buffer;
533
- changelog?: string | null;
534
- /** 'dev' = dev-loop publish: pinned by the dev installation, never the installable latest. */
535
- channel?: "release" | "dev";
536
- }): Promise<{
537
- id: string;
538
- package_id: string;
539
- version: number;
540
- bundle_r2_prefix: string;
541
- changelog: string | null;
542
- created_at: string;
543
- }>;
544
419
  /**
545
420
  * Upgrade a package installation to a newer published version — extends the
546
421
  * binding additively, re-materializes the target version's
@@ -551,21 +426,15 @@ export declare class LoticsClient {
551
426
  upgradePackage(app_id: string, body: {
552
427
  version?: number;
553
428
  /**
554
- * Per preview finding: drifted binding entries (`<namespace>.<alias>`)
555
- * take `"recreate"` or `{ bind_to: "<id>" }`; locally modified
556
- * artifacts (`<kind>.<alias>`) take `"revert"` or `"keep"`. Required
557
- * for every finding anything unresolved refuses the upgrade.
558
- */
559
- resolutions?: Record<string, "recreate" | "revert" | "keep" | {
560
- bind_to: string;
561
- }>;
562
- /**
563
- * Per bundled-knowledge finding: a consent resolution
564
- * (`apply`/`keep`/`archive`/`recreate`/`unbind`) per alias + `bind_to`
565
- * consents for added-doc name collisions. Consent-requiring docs left
566
- * unresolved refuse the upgrade; unmodified changes apply automatically.
429
+ * ONE map, one namespaced grammar, per preview finding: a drifted binding
430
+ * entry (`<namespace>.<alias>`) takes `"recreate"` or `{ bind_to }`; a
431
+ * modified artifact (`<kind>.<alias>`) takes `"revert"` or `"keep"`; a
432
+ * bundled knowledge doc (`knowledge.<alias>`) takes
433
+ * `apply|keep|archive|recreate|unbind` or `{ bind_to: "<kdc_id>" }`; and
434
+ * `roles.<alias> = { bind_to: "<grp_id>" }` re-points a LIVE role.
435
+ * Required for every finding — anything unresolved refuses the upgrade.
567
436
  */
568
- knowledge_resolutions?: KnowledgeUpgradeResolutions;
437
+ resolutions?: UpgradeResolutions;
569
438
  }): Promise<{
570
439
  id: string;
571
440
  name: string;
@@ -614,24 +483,10 @@ export declare class LoticsClient {
614
483
  /**
615
484
  * Bundled package-managed knowledge docs the version bump adds/changes/
616
485
  * removes/drifts — the app-install analogue of a standalone knowledge
617
- * upgrade's `entries`. Consent-requiring docs resolve via `knowledge_resolutions`.
486
+ * upgrade's `entries`. Consent-requiring docs resolve via `knowledge.<alias>` resolutions.
618
487
  */
619
488
  knowledge: KnowledgeUpgradeEntry[];
620
489
  }>;
621
- /**
622
- * Re-bind a package role to a different workspace group (the current group
623
- * still exists). Re-materializes at the pinned version; refuses over
624
- * modified-core findings. Admin-only.
625
- */
626
- rebindPackageRole(app_id: string, body: {
627
- role_alias: string;
628
- group_id: string;
629
- }): Promise<{
630
- app_id: string;
631
- role_alias: string;
632
- group_id: string;
633
- previous_group_id: string | null;
634
- }>;
635
490
  /**
636
491
  * Workspace-wide dangling-reference sweep — active app/workflow artifacts
637
492
  * whose prefixed schema ids no longer resolve. Backs
@@ -655,6 +510,8 @@ export declare class LoticsClient {
655
510
  app_id: string;
656
511
  package_id: string;
657
512
  package_name: string;
513
+ /** The author's origin copy (installation #1) — doctor frames modified core as staged release work, not drift. */
514
+ is_origin: boolean;
658
515
  installed_version: number;
659
516
  latest_version: number;
660
517
  update_available: boolean;
@@ -683,18 +540,119 @@ export declare class LoticsClient {
683
540
  missing_expected_docs: string[];
684
541
  }>;
685
542
  /**
686
- * Reset a package installation in a DEV workspace drop the package-owned
687
- * scaffolded tables and re-scaffold clean. Hard-gated server-side to dev
688
- * workspaces (a non-dev workspace is refused). Returns the resulting app.
689
- * Admin-only.
543
+ * Preview a release the dry run behind `lotics app release`. Runs the
544
+ * binding-aware extract of the origin (aliases stable through the app's current
545
+ * binding) and reports the next version number, the new + changed aliases, the
546
+ * bundled-knowledge delta, and any extract findings (an `error` blocks the
547
+ * apply). An optional `knowledge` declaration (from the pulled app manifest)
548
+ * re-declares the bundle set — added/dropped/changed docs surface in the delta;
549
+ * omitted, the current corpus is reconstructed from the pin. No writes. Admin,
550
+ * owning-org only.
690
551
  */
691
- resetPackage(app_id: string): Promise<{
692
- id: string;
693
- name: string;
694
- workspace_id: string;
695
- package_id: string | null;
696
- package_version: number | null;
697
- current_version_id: string | null;
552
+ previewPackageRelease(app_id: string, opts?: {
553
+ /** alias → doc_id re-declaring the bundled-knowledge set (from the manifest). */
554
+ knowledge?: Array<{
555
+ alias: string;
556
+ doc_id: string;
557
+ }>;
558
+ }): Promise<{
559
+ package_id: string;
560
+ version: number;
561
+ added_aliases: string[];
562
+ changed_artifacts: string[];
563
+ /** Absent from a pre-declaration server (deploy skew) — treat as empty delta. */
564
+ knowledge?: {
565
+ added: string[];
566
+ removed: string[];
567
+ changed: string[];
568
+ };
569
+ findings: ExtractFinding[];
570
+ }>;
571
+ /**
572
+ * Release — snapshot the origin app into the next registry version. The server
573
+ * binding-aware-extracts it, repackages its deployed source + dist as the
574
+ * bundle, publishes the next `release`-channel version with the changelog, and
575
+ * re-pins the origin. An optional `knowledge` declaration re-declares the
576
+ * bundled-knowledge set (added/dropped/re-snapshotted docs; omitted preserves
577
+ * the current corpus). Error findings from extract surface as a 409; a
578
+ * missing/archived declared doc is a 400, a foreign-package doc a 409. Admin,
579
+ * owning-org only. Backs `lotics app release --yes`.
580
+ */
581
+ releasePackage(app_id: string, body: {
582
+ changelog: string;
583
+ /** alias → doc_id re-declaring the bundled-knowledge set (from the manifest). */
584
+ knowledge?: Array<{
585
+ alias: string;
586
+ doc_id: string;
587
+ }>;
588
+ }): Promise<{
589
+ package_id: string;
590
+ version: number;
591
+ added_aliases: string[];
592
+ changed_artifacts: string[];
593
+ /** Absent from a pre-declaration server (deploy skew) — treat as empty delta. */
594
+ knowledge?: {
595
+ added: string[];
596
+ removed: string[];
597
+ changed: string[];
598
+ };
599
+ }>;
600
+ /**
601
+ * Dry-run preview of a first-release — the `GET` behind `lotics app publish`
602
+ * (no `--yes`), the publish-side analogue of `previewPackageRelease`. The
603
+ * server runs the same fresh-alias extract + `src/` scan the apply runs
604
+ * (through any `renames`) and returns the package name it would mint, the
605
+ * auto-minted RENAMABLE aliases (the exact `--rename` keys), and the extract
606
+ * findings (an `error` blocks the apply). No writes. Admin-only.
607
+ */
608
+ previewPublishAppPackage(app_id: string, opts?: {
609
+ renames?: Array<{
610
+ from: string;
611
+ to: string;
612
+ }>;
613
+ /** alias → doc_id for the app's package-managed knowledge (from its manifest). */
614
+ knowledge?: Array<{
615
+ alias: string;
616
+ doc_id: string;
617
+ }>;
618
+ }): Promise<{
619
+ app_id: string;
620
+ package_name: string;
621
+ renamable_aliases: {
622
+ entities: string[];
623
+ fields: string[];
624
+ options: string[];
625
+ roles: string[];
626
+ templates: string[];
627
+ workflows: string[];
628
+ };
629
+ findings: ExtractFinding[];
630
+ }>;
631
+ /**
632
+ * First-release apply — mint a package from a BESPOKE app and publish v1 in one
633
+ * call (the `POST` behind `lotics app publish --yes`). The server extracts an
634
+ * alias-keyed contract from the app (fresh aliases; `renames` fixes them before
635
+ * v1 freezes), creates the registry package (name/description from the app),
636
+ * publishes v1 from the app's deployed source + dist, and pins the origin as
637
+ * installation #1. Error findings from extract surface as a 409. An
638
+ * already-linked app must use `releasePackage` instead. Admin-only. Backs
639
+ * `lotics app publish <app_id>`.
640
+ */
641
+ publishAppAsPackage(app_id: string, body: {
642
+ renames?: Array<{
643
+ from: string;
644
+ to: string;
645
+ }>;
646
+ changelog?: string | null;
647
+ /** alias → doc_id for the app's package-managed knowledge (from its manifest). */
648
+ knowledge?: Array<{
649
+ alias: string;
650
+ doc_id: string;
651
+ }>;
652
+ }): Promise<{
653
+ package_id: string;
654
+ version: number;
655
+ app_id: string;
698
656
  }>;
699
657
  /**
700
658
  * Resolve the display name + fields (incl. select options) of the given tables