@lotics/cli 0.74.0 → 0.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -210,7 +210,12 @@ lotics package sync --workspace wsp_dev # migrate the dev installation only
210
210
  lotics package reset --workspace wsp_dev # DEV-ONLY: drop scaffolded tables, re-scaffold clean
211
211
 
212
212
  # Operate installations (workspace admin)
213
+ lotics package show apg_... # registry metadata + version history (trust badge, channel, yank)
213
214
  lotics package install apg_... --version 2 # scaffold + materialize + deploy + pin
215
+ lotics package install apg_... --config heading="Ops board" # per-knob overrides over contract defaults
216
+ lotics package config app_... --set show_done=false # edit a live installation's config (partial merge)
217
+ lotics package uninstall app_... [--archive-tables] # remove an installation; workflows stop firing
218
+ lotics package retire apg_... [--undo] # owner-org: refuse NEW installs (existing keep working + upgrading)
214
219
  lotics package doctor app_... # version pin vs latest + drift + local edits (exit 1 on findings)
215
220
  lotics package rebind-role app_... <alias> <grp_id> # re-point a package role at another group (re-materializes)
216
221
  lotics package upgrade app_... # preview, then apply (additive; overlay preserved)
@@ -117,6 +117,22 @@ export declare function runNpm(args: string[], cwd: string): Promise<void>;
117
117
  * the author fixes the config.
118
118
  */
119
119
  export declare function ensureAppTsconfig(projectDir: string): void;
120
+ /**
121
+ * Write the three `.lotics/app_{workflows,queries,agents}.d.ts` companions from
122
+ * the manifest's maps, then heal the app's tsconfig so they actually load. Called
123
+ * from `app create / pull / dev / deploy / codegen`, so the augmented `AppWorkflows`
124
+ * / `AppQueries` / `AppAgents` types stay in sync with the manifest.
125
+ *
126
+ * The heal is at the write boundary on purpose: a `.d.ts` written but not loaded is
127
+ * useless (a bare `.lotics` include is skipped by TypeScript's include-glob walk and
128
+ * loads zero of them), so `ensureAppTsconfig` couples "wrote the types" with "the
129
+ * program can see them" — no caller can do one without the other.
130
+ */
131
+ export declare function writeAppDts(projectDir: string, manifest: {
132
+ workflows?: Record<string, AppWorkflowDeclaration>;
133
+ queries?: Record<string, AppQueryDeclaration>;
134
+ agents?: Record<string, AppAgentDeclaration>;
135
+ }): string[];
120
136
  /**
121
137
  * `lotics app codegen [path]` — regenerate every `.lotics/` artifact from the
122
138
  * manifest + workspace schema, WITHOUT a deploy. The `.d.ts` companions are
@@ -386,7 +386,7 @@ export function ensureAppTsconfig(projectDir) {
386
386
  * loads zero of them), so `ensureAppTsconfig` couples "wrote the types" with "the
387
387
  * program can see them" — no caller can do one without the other.
388
388
  */
389
- function writeAppDts(projectDir, manifest) {
389
+ export function writeAppDts(projectDir, manifest) {
390
390
  const dotLotics = path.join(projectDir, ".lotics");
391
391
  fs.mkdirSync(dotLotics, { recursive: true });
392
392
  const written = [
package/dist/args.d.ts CHANGED
@@ -53,6 +53,14 @@ export declare function parseArgs(argv: string[]): {
53
53
  * `keep`.
54
54
  */
55
55
  resolve: string[];
56
+ /** `--config key=value` (repeatable): per-knob config overrides at `package install`. */
57
+ config: string[];
58
+ /** `--set key=value` (repeatable): per-knob config edits at `package config`. */
59
+ set: string[];
60
+ /** `--archive-tables`: also archive the scaffolded tables at `package uninstall`. */
61
+ archiveTables: boolean;
62
+ /** `--undo`: reverse a `package retire` / `package yank`. */
63
+ undo: boolean;
56
64
  version: boolean;
57
65
  help: boolean;
58
66
  };
package/dist/args.js CHANGED
@@ -31,6 +31,10 @@ export function parseArgs(argv) {
31
31
  cleanup: false,
32
32
  packageVersion: undefined,
33
33
  resolve: [],
34
+ config: [],
35
+ set: [],
36
+ archiveTables: false,
37
+ undo: false,
34
38
  version: false,
35
39
  help: false,
36
40
  };
@@ -106,6 +110,28 @@ export function parseArgs(argv) {
106
110
  flags.resolve.push(value);
107
111
  break;
108
112
  }
113
+ case "--config": {
114
+ const value = argv[++i];
115
+ if (value === undefined || value.startsWith("-")) {
116
+ throw new Error("--config requires a value: key=value (repeatable).");
117
+ }
118
+ flags.config.push(value);
119
+ break;
120
+ }
121
+ case "--set": {
122
+ const value = argv[++i];
123
+ if (value === undefined || value.startsWith("-")) {
124
+ throw new Error("--set requires a value: key=value (repeatable).");
125
+ }
126
+ flags.set.push(value);
127
+ break;
128
+ }
129
+ case "--archive-tables":
130
+ flags.archiveTables = true;
131
+ break;
132
+ case "--undo":
133
+ flags.undo = true;
134
+ break;
109
135
  case "--version":
110
136
  case "-v": {
111
137
  // Inside a `package` command, `--version` carries a value (the
package/dist/cli.js CHANGED
@@ -14,7 +14,7 @@ import { LoticsClient, API_BASE_URL } from "./client.js";
14
14
  import { resolveContext, deleteConfig, getConfigPath, loadGlobalConfig, saveGlobalConfig, loadLocalConfig, upsertProfile, removeProfile, setActiveOrg, setSelectedWorkspace, resolveProfileByNameOrId, checkForUpdate, } from "./config.js";
15
15
  import { VERSION } from "./version.js";
16
16
  import { appCreate, appPull, appDeploy, appDev, appSetSubdomain, appRename, appVersions, appCodegen, appExecuteWorkflow, appWorkflowSet, appWorkflowPull, appWorkflowCheck, appQuerySet, appUiLink, } from "./app_commands.js";
17
- import { packageInstall, packageEject, packageDoctor, packageUpgrade, parseResolveFlags, packageNew, packageBuild, packagePublish, packageDev, packageSync, packageReset, packageExtract, packageAdopt, packageFleetUpgrade, } from "./package_commands.js";
17
+ import { packageInstall, packageUninstall, packageConfig, packageRetire, packageShow, parseInstallConfigFlags, packageEject, packageDoctor, packageUpgrade, parseResolveFlags, packageNew, packageBuild, packagePublish, packageDev, packageSync, packageReset, packageExtract, packageAdopt, packageFleetUpgrade, packageYank, } from "./package_commands.js";
18
18
  import { parseArgs } from "./args.js";
19
19
  import { ingestJsonArgs } from "./inputs.js";
20
20
  import { runXlsxCommand } from "./xlsx.js";
@@ -103,9 +103,18 @@ COMMANDS
103
103
  dev server (--workspace <dev_ws> selects it)
104
104
  lotics package sync [path] Re-sync (additive migrate + materialize) into a dev ws
105
105
  lotics package reset [path] DEV-ONLY: drop scaffolded tables + re-scaffold clean
106
- lotics package install <package> [--version N]
106
+ lotics package install <package> [--version N] [--config key=value ...]
107
107
  Install an app package into this workspace
108
108
  (scaffolds the data model + deploys + materializes)
109
+ lotics package uninstall <app_id> [--archive-tables]
110
+ Remove an installation (archives artifacts; with the
111
+ flag also archives the scaffolded tables it created)
112
+ lotics package config <app_id> [--set key=value ...]
113
+ Show or edit an installation's config knobs
114
+ lotics package show <package_id> Registry metadata + version history
115
+ lotics package retire <package_id> [--undo]
116
+ Retire a package (refuse new installs, hide from other
117
+ orgs); existing installations keep working + upgrade
109
118
  lotics package upgrade <app_id> [--version N] [--resolve <key>=recreate|revert|keep|<id> ...]
110
119
  Preview-then-apply a package upgrade; refuses while
111
120
  any drift/modified finding lacks a --resolve, and
@@ -124,6 +133,7 @@ COMMANDS
124
133
  origin app (reads .lotics/adopt_binding.json;
125
134
  --version N pins a specific version)
126
135
  lotics package fleet-upgrade <package_id> [--version N]
136
+ lotics package yank <package_id> <version> [--undo]
127
137
  Upgrade EVERY installation of the package across
128
138
  your org: applies where the preview is clean,
129
139
  skips + reports findings (exit 1 unless all current)
@@ -699,7 +709,11 @@ async function main() {
699
709
  console.error(" lotics package dev [path] [--workspace <ws>] Sync into a dev workspace + run the app dev server");
700
710
  console.error(" lotics package sync [path] [--workspace <ws>] Re-sync (additive migrate + materialize) into a dev workspace");
701
711
  console.error(" lotics package reset [path] [--workspace <ws>] DEV-ONLY: drop scaffolded tables + re-scaffold clean");
702
- console.error(" lotics package install <package> [--version N] Install a package into this workspace");
712
+ console.error(" lotics package install <package> [--version N] [--config key=value ...] Install a package into this workspace");
713
+ console.error(" lotics package uninstall <app_id> [--archive-tables] Remove an installation (opt-in table archival)");
714
+ console.error(" lotics package config <app_id> [--set key=value ...] Show or edit an installation's config knobs");
715
+ console.error(" lotics package show <package_id> Registry metadata + version history (channel, yank, changelog)");
716
+ console.error(" lotics package retire <package_id> [--undo] Retire a package (refuse new installs; installs keep working)");
703
717
  console.error(" lotics package upgrade <app_id> [--version N] [--resolve ns.alias=recreate|<id>] Preview + apply an upgrade");
704
718
  console.error(" lotics package doctor [app_id] Health: version pin vs latest + binding drift");
705
719
  console.error(" lotics package rebind-role <app_id> <alias> <grp_id> Re-point a package role at another group");
@@ -707,6 +721,7 @@ async function main() {
707
721
  console.error(" lotics package extract <app_id> [path] Promote a bespoke app to a draft package project");
708
722
  console.error(" lotics package adopt <app_id> [path] Bind the published project onto the origin app");
709
723
  console.error(" lotics package fleet-upgrade <package_id> [--version N] Upgrade every org installation (clean ones apply; findings skip)");
724
+ console.error(" lotics package yank <package_id> <version> [--undo] Refuse new installs/upgrades of a broken published version (pinned installations keep running)");
710
725
  process.exit(1);
711
726
  }
712
727
  if (command === "run" && !subcommand) {
@@ -869,7 +884,48 @@ async function main() {
869
884
  process.exit(1);
870
885
  }
871
886
  }
872
- await packageInstall(client, { package_id: packageId, version });
887
+ const config = flags.config.length > 0 ? parseInstallConfigFlags(flags.config) : undefined;
888
+ await packageInstall(client, {
889
+ package_id: packageId,
890
+ version,
891
+ ...(config !== undefined ? { config } : {}),
892
+ });
893
+ return;
894
+ }
895
+ if (subcommand === "uninstall") {
896
+ const appId = toolArgs;
897
+ if (!appId) {
898
+ console.error("Usage: lotics package uninstall <app_id> [--archive-tables]");
899
+ process.exit(1);
900
+ }
901
+ await packageUninstall(client, { app_id: appId, archive_tables: flags.archiveTables });
902
+ return;
903
+ }
904
+ if (subcommand === "config") {
905
+ const appId = toolArgs;
906
+ if (!appId) {
907
+ console.error("Usage: lotics package config <app_id> [--set key=value ...]");
908
+ process.exit(1);
909
+ }
910
+ await packageConfig(client, { app_id: appId, sets: flags.set });
911
+ return;
912
+ }
913
+ if (subcommand === "retire") {
914
+ const packageId = toolArgs;
915
+ if (!packageId) {
916
+ console.error("Usage: lotics package retire <package_id> [--undo]");
917
+ process.exit(1);
918
+ }
919
+ await packageRetire(client, { package_id: packageId, undo: flags.undo });
920
+ return;
921
+ }
922
+ if (subcommand === "show") {
923
+ const packageId = toolArgs;
924
+ if (!packageId) {
925
+ console.error("Usage: lotics package show <package_id>");
926
+ process.exit(1);
927
+ }
928
+ await packageShow(client, { package_id: packageId });
873
929
  return;
874
930
  }
875
931
  if (subcommand === "eject") {
@@ -909,6 +965,16 @@ async function main() {
909
965
  await packageAdopt(client, { app_id: appId, version, projectDir: restArgs[0] });
910
966
  return;
911
967
  }
968
+ if (subcommand === "yank") {
969
+ const packageId = toolArgs;
970
+ const version = Number(restArgs[0]);
971
+ if (!packageId || !Number.isInteger(version) || version <= 0) {
972
+ console.error("Usage: lotics package yank <package_id> <version> [--undo]");
973
+ process.exit(1);
974
+ }
975
+ await packageYank(client, { package_id: packageId, version, undo: flags.undo });
976
+ return;
977
+ }
912
978
  if (subcommand === "fleet-upgrade") {
913
979
  const packageId = toolArgs;
914
980
  if (!packageId) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,90 @@
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.
9
+ *
10
+ * The fake API key satisfies `requireClient` (client construction is offline);
11
+ * every asserted path exits before any network call. Spawns run in an empty
12
+ * temp cwd so path-defaulting subcommands fail on the missing project file —
13
+ * which equally proves their dispatch reached the right handler.
14
+ */
15
+ import { beforeAll, describe, expect, it } from "vitest";
16
+ import { execFileSync, spawnSync } from "node:child_process";
17
+ import fs from "node:fs";
18
+ import os from "node:os";
19
+ import path from "node:path";
20
+ import { fileURLToPath } from "node:url";
21
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
22
+ const cliBin = path.join(packageRoot, "dist", "src", "cli.js");
23
+ const emptyCwd = fs.mkdtempSync(path.join(os.tmpdir(), "lotics-cli-dispatch-"));
24
+ function runCli(args) {
25
+ const result = spawnSync(process.execPath, [cliBin, ...args], {
26
+ cwd: emptyCwd,
27
+ env: {
28
+ ...process.env,
29
+ LOTICS_API_KEY: "ltk_dispatch_smoke_fake_key_never_used_on_wire",
30
+ // A pinned (fake) workspace skips the pre-dispatch auto-resolution,
31
+ // which would otherwise hit the network (`listWorkspaces`) before any
32
+ // usage gate. Nothing below ever reaches the wire.
33
+ LOTICS_WORKSPACE: "wsp_dispatch_smoke_fake",
34
+ LOTICS_ORG: "",
35
+ },
36
+ encoding: "utf-8",
37
+ timeout: 30_000,
38
+ });
39
+ return { status: result.status, stderr: result.stderr ?? "" };
40
+ }
41
+ beforeAll(() => {
42
+ // Bundle the real artifact from src (esbuild only — no tsgo; vitest's
43
+ // transform already type-agnostic). ~1s.
44
+ execFileSync(process.execPath, ["scripts/build_cli.mjs"], { cwd: packageRoot });
45
+ }, 120_000);
46
+ describe("lotics package <subcommand> dispatch", () => {
47
+ // Positional-requiring subcommands: a bare invocation must print the
48
+ // subcommand's OWN usage line — reaching it proves family routing AND that
49
+ // the usage gate fires before any network/filesystem work.
50
+ const usageCases = [
51
+ ["install", /Usage: lotics package install/],
52
+ ["uninstall", /Usage: lotics package uninstall/],
53
+ ["config", /Usage: lotics package config/],
54
+ ["retire", /Usage: lotics package retire <package_id>/],
55
+ ["show", /Usage: lotics package show <package_id>/],
56
+ ["upgrade", /Usage: lotics package upgrade/],
57
+ ["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/],
63
+ ];
64
+ for (const [sub, usage] of usageCases) {
65
+ it(`routes "package ${sub}" to its handler (usage on missing args)`, () => {
66
+ const { status, stderr } = runCli(["package", sub]);
67
+ expect(stderr).toMatch(usage);
68
+ expect(stderr).not.toMatch(/Unknown package subcommand/);
69
+ expect(status).toBe(1);
70
+ });
71
+ }
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)`, () => {
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/);
82
+ expect(status).toBe(1);
83
+ });
84
+ }
85
+ it("still rejects a genuinely unknown subcommand", () => {
86
+ const { status, stderr } = runCli(["package", "frobnicate"]);
87
+ expect(stderr).toMatch(/Unknown package subcommand/);
88
+ expect(status).toBe(1);
89
+ });
90
+ });
package/dist/client.d.ts CHANGED
@@ -200,6 +200,16 @@ export declare class LoticsClient {
200
200
  * through the `context` op for production parity.
201
201
  */
202
202
  config?: Record<string, string | number | boolean> | null;
203
+ /** Package registry id this app was installed from; null for a bespoke/ejected app. */
204
+ package_id?: string | null;
205
+ /** The installed package version (upgrade pin); null for a bespoke/ejected app. */
206
+ package_version?: number | null;
207
+ /**
208
+ * Package install join — per-namespace alias→id maps (entities/fields/
209
+ * options/templates/roles) plus the `workflows` artifact registry. Null for
210
+ * a bespoke app. Used to preview what `package uninstall` will archive.
211
+ */
212
+ binding?: Record<string, Record<string, string>> | null;
203
213
  }>;
204
214
  createApp(body: {
205
215
  name: string;
@@ -219,6 +229,7 @@ export declare class LoticsClient {
219
229
  */
220
230
  installAppPackage(package_id: string, body: {
221
231
  version?: number;
232
+ config?: Record<string, string | number | boolean>;
222
233
  }): Promise<{
223
234
  id: string;
224
235
  name: string;
@@ -227,6 +238,43 @@ export declare class LoticsClient {
227
238
  package_version: number | null;
228
239
  current_version_id: string | null;
229
240
  }>;
241
+ /**
242
+ * Uninstall a package installation (backs `lotics package uninstall`). Does
243
+ * everything DELETE does plus archives the installation's lifecycle
244
+ * artifacts; with `archive_tables` it also archives the scaffolded entity
245
+ * tables — refused server-side unless this installation created them
246
+ * (provenance) and nothing else references them. Admin-only.
247
+ */
248
+ uninstallAppPackage(app_id: string, body: {
249
+ archive_tables: boolean;
250
+ }): Promise<{
251
+ id: string;
252
+ uninstalled: boolean;
253
+ archived_table_ids: string[];
254
+ }>;
255
+ /**
256
+ * Partial-merge a package installation's config (backs `lotics package config
257
+ * --set`). Only the provided keys change; validated against the installed
258
+ * contract. Returns the full effective config. Admin-only.
259
+ */
260
+ updateAppPackageConfig(app_id: string, body: {
261
+ config: Record<string, string | number | boolean>;
262
+ }): Promise<{
263
+ config: Record<string, string | number | boolean>;
264
+ }>;
265
+ /**
266
+ * Retire (or `undo` un-retire) a registry package (backs `lotics package
267
+ * retire`). Retiring refuses NEW installs and hides the package from
268
+ * non-owning orgs; existing installations keep working and may still upgrade.
269
+ * Owner-org admin-only.
270
+ */
271
+ retireAppPackage(package_id: string, body: {
272
+ undo: boolean;
273
+ }): Promise<{
274
+ id: string;
275
+ name: string;
276
+ retired_at: string | null;
277
+ }>;
230
278
  /**
231
279
  * Eject an installation from its package — re-deploy the pinned version's
232
280
  * source as a workspace-owned app version, then sever the package link
@@ -287,6 +335,17 @@ export declare class LoticsClient {
287
335
  * per-installation consent flow. Backs `lotics package fleet-upgrade`.
288
336
  * Admin-only; org-scoped (no workspace header needed).
289
337
  */
338
+ /**
339
+ * Yank / unyank a published package version — refuses NEW installs/upgrades/
340
+ * adopts targeting it; pinned installations keep running. Owner-org
341
+ * admin-only. Backs `lotics package yank`.
342
+ */
343
+ yankAppPackageVersion(package_id: string, version: number, yanked: boolean): Promise<{
344
+ package_id: string;
345
+ version: number;
346
+ yanked_at: string | null;
347
+ latest_version: number;
348
+ }>;
290
349
  fleetUpgradeAppPackage(package_id: string, body: {
291
350
  version?: number;
292
351
  }): Promise<{
@@ -335,9 +394,22 @@ export declare class LoticsClient {
335
394
  description: string | null;
336
395
  latest_version: number;
337
396
  is_official: boolean;
397
+ retired_at: string | null;
398
+ /** Absent from a pre-deploy server — treat undefined as not-owned (the badge under-claims, never over-claims). */
399
+ owned_by_caller?: boolean;
338
400
  created_at: string;
339
401
  updated_at: string;
340
402
  }>;
403
+ /** Version history newest-first (no contract payloads) — backs `lotics package show`. Admin-only. */
404
+ listAppPackageVersions(package_id: string): Promise<{
405
+ versions: Array<{
406
+ version: number;
407
+ changelog: string | null;
408
+ channel: "release" | "dev";
409
+ yanked_at: string | null;
410
+ created_at: string;
411
+ }>;
412
+ }>;
341
413
  /**
342
414
  * Publish a new immutable package version — multipart upload of the alias-keyed
343
415
  * contract (JSON) + the prebuilt code bundle (a gzipped tarball carrying
@@ -349,6 +421,8 @@ export declare class LoticsClient {
349
421
  contract: unknown;
350
422
  bundle: Buffer;
351
423
  changelog?: string | null;
424
+ /** 'dev' = dev-loop publish: pinned by the dev installation, never the installable latest. */
425
+ channel?: "release" | "dev";
352
426
  }): Promise<{
353
427
  id: string;
354
428
  package_id: string;
package/dist/client.js CHANGED
@@ -212,6 +212,33 @@ export class LoticsClient {
212
212
  async installAppPackage(package_id, body) {
213
213
  return this.request("POST", `/v1/app-packages/${encodeURIComponent(package_id)}/installations`, body);
214
214
  }
215
+ /**
216
+ * Uninstall a package installation (backs `lotics package uninstall`). Does
217
+ * everything DELETE does plus archives the installation's lifecycle
218
+ * artifacts; with `archive_tables` it also archives the scaffolded entity
219
+ * tables — refused server-side unless this installation created them
220
+ * (provenance) and nothing else references them. Admin-only.
221
+ */
222
+ async uninstallAppPackage(app_id, body) {
223
+ return this.request("POST", `/v1/apps/${encodeURIComponent(app_id)}/uninstall`, body);
224
+ }
225
+ /**
226
+ * Partial-merge a package installation's config (backs `lotics package config
227
+ * --set`). Only the provided keys change; validated against the installed
228
+ * contract. Returns the full effective config. Admin-only.
229
+ */
230
+ async updateAppPackageConfig(app_id, body) {
231
+ return this.request("PATCH", `/v1/apps/${encodeURIComponent(app_id)}/package-config`, body);
232
+ }
233
+ /**
234
+ * Retire (or `undo` un-retire) a registry package (backs `lotics package
235
+ * retire`). Retiring refuses NEW installs and hides the package from
236
+ * non-owning orgs; existing installations keep working and may still upgrade.
237
+ * Owner-org admin-only.
238
+ */
239
+ async retireAppPackage(package_id, body) {
240
+ return this.request("POST", `/v1/app-packages/${encodeURIComponent(package_id)}/retire`, body);
241
+ }
215
242
  /**
216
243
  * Eject an installation from its package — re-deploy the pinned version's
217
244
  * source as a workspace-owned app version, then sever the package link
@@ -255,6 +282,14 @@ export class LoticsClient {
255
282
  * per-installation consent flow. Backs `lotics package fleet-upgrade`.
256
283
  * Admin-only; org-scoped (no workspace header needed).
257
284
  */
285
+ /**
286
+ * Yank / unyank a published package version — refuses NEW installs/upgrades/
287
+ * adopts targeting it; pinned installations keep running. Owner-org
288
+ * admin-only. Backs `lotics package yank`.
289
+ */
290
+ async yankAppPackageVersion(package_id, version, yanked) {
291
+ return this.request("POST", `/v1/app-packages/${encodeURIComponent(package_id)}/versions/${version}/yank`, { yanked });
292
+ }
258
293
  async fleetUpgradeAppPackage(package_id, body) {
259
294
  return this.request("POST", `/v1/app-packages/${encodeURIComponent(package_id)}/fleet-upgrade`, body);
260
295
  }
@@ -275,6 +310,10 @@ export class LoticsClient {
275
310
  async getAppPackage(package_id) {
276
311
  return this.request("GET", `/v1/app-packages/${encodeURIComponent(package_id)}`);
277
312
  }
313
+ /** Version history newest-first (no contract payloads) — backs `lotics package show`. Admin-only. */
314
+ async listAppPackageVersions(package_id) {
315
+ return this.request("GET", `/v1/app-packages/${encodeURIComponent(package_id)}/versions`);
316
+ }
278
317
  /**
279
318
  * Publish a new immutable package version — multipart upload of the alias-keyed
280
319
  * contract (JSON) + the prebuilt code bundle (a gzipped tarball carrying
@@ -288,6 +327,8 @@ export class LoticsClient {
288
327
  formData.append("bundle", new Blob([new Uint8Array(args.bundle)], { type: "application/gzip" }), "bundle.tar.gz");
289
328
  if (args.changelog)
290
329
  formData.append("changelog", args.changelog);
330
+ if (args.channel)
331
+ formData.append("channel", args.channel);
291
332
  const url = `${this.baseUrl}/v1/app-packages/${encodeURIComponent(package_id)}/versions`;
292
333
  const response = await fetch(url, {
293
334
  method: "POST",
@@ -176,13 +176,50 @@ export declare function packageUpgrade(client: LoticsClient, args: {
176
176
  version?: number;
177
177
  resolutions: Record<string, UpgradeResolutionValue>;
178
178
  }): Promise<void>;
179
+ /**
180
+ * `lotics package show <package_id>` — registry metadata + version history
181
+ * (trust badge, retirement, per-version channel/yank/changelog). The read
182
+ * surface for "what is this package and what shipped when".
183
+ */
184
+ export declare function packageShow(client: LoticsClient, args: {
185
+ package_id: string;
186
+ }): Promise<void>;
179
187
  export declare function packageInstall(client: LoticsClient, args: {
180
188
  package_id: string;
181
189
  version?: number;
190
+ config?: Record<string, string | number | boolean>;
182
191
  }): Promise<void>;
183
192
  export declare function packageEject(client: LoticsClient, args: {
184
193
  app_id: string;
185
194
  }): Promise<void>;
195
+ /** `--config key=value` (install): inferred types, server-validated. */
196
+ export declare function parseInstallConfigFlags(config: string[]): Record<string, string | number | boolean>;
197
+ /**
198
+ * `lotics package config <app_id>` — show the installation's effective config;
199
+ * with `--set key=value` (repeatable) partial-merge edits, each value parsed by
200
+ * the knob's current type. No `--set` prints the values.
201
+ */
202
+ export declare function packageConfig(client: LoticsClient, args: {
203
+ app_id: string;
204
+ sets: string[];
205
+ }): Promise<void>;
206
+ /**
207
+ * `lotics package uninstall <app_id> [--archive-tables]` — remove a package
208
+ * installation. Prints what will be archived (workflow artifacts, plus the
209
+ * scaffolded tables when the flag is set), then uninstalls.
210
+ */
211
+ export declare function packageUninstall(client: LoticsClient, args: {
212
+ app_id: string;
213
+ archive_tables: boolean;
214
+ }): Promise<void>;
215
+ /**
216
+ * `lotics package retire <package_id> [--undo]` — retire (or un-retire) a
217
+ * registry package. Owner-org admin-only.
218
+ */
219
+ export declare function packageRetire(client: LoticsClient, args: {
220
+ package_id: string;
221
+ undo: boolean;
222
+ }): Promise<void>;
186
223
  /**
187
224
  * `lotics package extract <app_id> [path]` — promote a bespoke app to a DRAFT
188
225
  * package project (docs/app_packages.md § Promotion). Calls the extract read,
@@ -220,6 +257,17 @@ export declare function packageAdopt(client: LoticsClient, args: {
220
257
  * installations are reported per line and the process exits 1 so a release
221
258
  * script can gate on "fleet fully current".
222
259
  */
260
+ /**
261
+ * `lotics package yank <package_id> <version> [--undo]` — mark a published
262
+ * version uninstallable (or restore it). New installs/upgrades/adopts refuse a
263
+ * yanked version and "latest" skips it; installations already pinned keep
264
+ * running. Owner-org admin-only.
265
+ */
266
+ export declare function packageYank(client: LoticsClient, args: {
267
+ package_id: string;
268
+ version: number;
269
+ undo: boolean;
270
+ }): Promise<void>;
223
271
  export declare function packageFleetUpgrade(client: LoticsClient, args: {
224
272
  package_id: string;
225
273
  version?: number;