@lotics/cli 0.83.0 → 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.
package/README.md CHANGED
@@ -227,7 +227,7 @@ lotics package config app_... --set show_done=false # edit a live inst
227
227
  lotics uninstall app_... [--archive-tables] # remove an installation; workflows stop firing
228
228
  lotics package doctor app_... # version pin vs latest + drift + local edits (exit 1 on findings)
229
229
  lotics upgrade app_... # preview, then apply (additive; overlay preserved)
230
- lotics upgrade apg_... # FLEET: upgrade EVERY org installation (clean ones apply; findings skip, exit 1)
230
+ lotics upgrade apg_... # APP package → FLEET: upgrade EVERY org installation (clean ones apply; findings skip, exit 1)
231
231
  lotics upgrade app_... --resolve fields.deal.stage=recreate # resolve reported drift
232
232
  lotics upgrade app_... --resolve queries.tasks=keep # consent for a local edit (or =revert)
233
233
  lotics upgrade app_... --resolve template.quote=revert # a locally-edited template (clean ones auto-update; or =keep)
@@ -238,7 +238,7 @@ lotics package eject app_... # one-way: sever the package link
238
238
  lotics workspace doctor # dangling schema references across the workspace (exit 1 on findings)
239
239
  ```
240
240
 
241
- After the first publish **the origin is the master** — develop it in its workspace (`app pull` / `app deploy` / `app workflow set` / table tools), and `lotics app release` snapshots each version. Its **binding-aware re-extract** keeps aliases stable through the origin's current binding, so re-extraction never churns the upgrade diff (which is why extract-again is the loop, not a hazard).
241
+ After the first publish **the origin is the master** — develop it in its workspace (`app pull` / `app deploy` / `app workflow set` / table tools), and `lotics app release` snapshots each version. Its **binding-aware re-extract** keeps aliases stable through the origin's current binding, so re-extraction never churns the upgrade diff (which is why extract-again is the loop, not a hazard). Release is also the **bundled-knowledge declaration surface**: run from the app project, the manifest's `lotics.knowledge` (`[{alias,doc_id}]`) re-declares which docs the package bundles — an alias added ships as a new doc, a bound alias dropped surfaces to consumers as `removed` (archive|keep), a present one re-snapshots; a bare id from elsewhere reconstructs the current corpus from the pin (never drops it). So a published app package evolves its bundled docs across versions without ejecting.
242
242
 
243
243
  ### Content packages
244
244
 
@@ -257,15 +257,16 @@ lotics run release_content '{"package_id":"apg_...","changelog":"v2: revised SOP
257
257
  lotics install apg_... # app OR content, shape-branched
258
258
  lotics install apg_... --bind-to policy=kdc_... # adopt an existing doc as package-managed
259
259
 
260
- # Discover installed content (the source for a pci_ id — install prints it once)
261
- lotics package list-content # id · package · version (standalone content installs)
260
+ # Discover installed content (each row leads with the PACKAGE id)
261
+ lotics package list-content # package id · package · version (standalone content installs)
262
262
 
263
- # Refresh a standalone content install (pci_ id from install / list-content) — one gate over docs + templates
264
- lotics upgrade pci_... # preview, then apply
265
- lotics upgrade pci_... --resolve knowledge.policy=apply # a doc: apply|keep|archive|recreate|unbind
266
- lotics upgrade pci_... --resolve template.quote=revert # a locally-edited template: revert|keep (clean ones auto-update)
267
- lotics upgrade pci_... --apply-all # accept upstream for every doc + template (OVERWRITES local edits)
268
- lotics uninstall pci_... --keep-content # remove the pin; keep docs + templates (default archives them)
263
+ # Refresh this workspace's content install addressed by PACKAGE id (one install per
264
+ # package per workspace, so the package id is the address; one gate over docs + templates)
265
+ lotics upgrade apg_... # CONTENT package → preview, then apply (this workspace's install)
266
+ lotics upgrade apg_... --resolve knowledge.policy=apply # a doc: apply|keep|archive|recreate|unbind
267
+ lotics upgrade apg_... --resolve template.quote=revert # a locally-edited template: revert|keep (clean ones auto-update)
268
+ lotics upgrade apg_... --apply-all # accept upstream for every doc + template (OVERWRITES local edits)
269
+ lotics uninstall apg_... --keep-content # remove the pin; keep docs + templates (default archives them)
269
270
  ```
270
271
 
271
272
  A package's knowledge can also arrive **bundled with an app**. Upgrading such an app (`lotics upgrade <app_id>`) previews its bundled-knowledge changes alongside the plan and resolves them in the SAME namespaced grammar — `--resolve knowledge.<alias>=apply|keep|archive|recreate|unbind` (the flags pass to the server verbatim; no routing, no ambiguity), `--bind-to` consents an added-doc collision, `--apply-all` takes the package's version for every consent-requiring doc.
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, packageUninstall, packageListContent, packageConfig, packageShow, parseInstallConfigFlags, packageEject, packageDoctor, packageUpgrade, packageUpgradeKnowledge, parseBindToFlags, appPublish, appRelease, appUnpublish, packageFleetUpgrade, packageYank, } from "./package_commands.js";
17
+ import { packageInstall, packageUninstall, packageListContent, packageConfig, packageShow, parseInstallConfigFlags, packageEject, packageDoctor, packageUpgrade, packageUpgradeByPackageId, redirectContentPciForm, parseBindToFlags, appPublish, appRelease, appUnpublish, 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";
@@ -114,18 +114,19 @@ COMMANDS
114
114
  Install a package (app: scaffolds/deploys/materializes,
115
115
  --config sets its knobs; content: installs the doc corpus,
116
116
  --bind-to consents to adopt a same-named doc on a collision)
117
- lotics uninstall <app_id|pci_id> [--archive-tables] [--keep-content]
117
+ lotics uninstall <app_id|package_id> [--archive-tables] [--keep-content]
118
118
  Uninstall — dispatched by id. App (app_id): archives
119
119
  artifacts (+ --archive-tables also archives scaffolded
120
- tables). Content (pci_): archives its package-bound docs
121
- unless --keep-content
122
- lotics upgrade <app_id|pci_id|package_id> [--version N] [--resolve <key>=... ] [--bind-to ...] [--apply-all]
120
+ tables). Content package (apg_): archives its package-bound
121
+ docs unless --keep-content
122
+ lotics upgrade <app_id|package_id> [--version N] [--resolve <key>=... ] [--bind-to ...] [--apply-all]
123
123
  Preview-then-apply an upgrade, dispatched by id. App
124
124
  (app_id): refuses while any drift/modified/bundled-knowledge
125
- finding lacks a --resolve. Content (pci_): --resolve
126
- <alias>=apply|keep|archive|recreate|unbind. Package (apg_):
127
- FLEET every installation across your org (clean apply,
128
- findings skip). --apply-all accepts the package's version
125
+ finding lacks a --resolve. Package (apg_): a CONTENT package
126
+ upgrades THIS workspace's install (--resolve
127
+ <alias>=apply|keep|archive|recreate|unbind); an APP package
128
+ FLEET-upgrades every installation across your org (clean
129
+ apply, findings skip). --apply-all accepts the package's version
129
130
  lotics package doctor [app_id] Installation health: version pin vs latest, binding
130
131
  drift, locally modified core, knowledge drift/edits
131
132
  (exit 1 on findings)
@@ -135,7 +136,8 @@ COMMANDS
135
136
  (re-deploys the pinned source as a bespoke app)
136
137
  lotics package show <package_id> Registry metadata + version history
137
138
  lotics package list-content List the workspace's content installations
138
- (standalone content installs) — source for a pci_ id
139
+ (standalone content installs) — each row leads with
140
+ the package id for upgrade/uninstall
139
141
  lotics package yank <package_id> <version> [--undo]
140
142
  Refuse new installs/upgrades of a broken published
141
143
  version (pinned installations keep running)
@@ -713,8 +715,8 @@ async function main() {
713
715
  console.error("Usage (low-traffic consumer / registry ops — author verbs live on `lotics app`):");
714
716
  console.error(" The high-traffic consumer verbs are top-level:");
715
717
  console.error(" lotics install <package_id> [--version N] [--bind-to <alias>=<kdc_id>] [--config key=value ...] Install a package (app or content)");
716
- console.error(" lotics uninstall <app_id|pci_id> [--archive-tables] [--keep-content] Uninstall — dispatched by id (app vs content)");
717
- console.error(" lotics upgrade <app_id|pci_id|package_id> [--version N] [--resolve <key>=... ] [--bind-to ...] [--apply-all] Upgrade — app / content / whole fleet (apg_)");
718
+ console.error(" lotics uninstall <app_id|package_id> [--archive-tables] [--keep-content] Uninstall — dispatched by id (app vs content)");
719
+ console.error(" lotics upgrade <app_id|package_id> [--version N] [--resolve <key>=... ] [--bind-to ...] [--apply-all] Upgrade — app install / content install / whole app fleet (apg_)");
718
720
  console.error(" lotics package doctor [app_id] Health: version pin vs latest + binding/knowledge drift");
719
721
  console.error(" lotics package config <app_id> [--set key=value ...] Show or edit an installation's config knobs");
720
722
  console.error(" lotics package eject <app_id> Sever an installation's package link");
@@ -902,12 +904,17 @@ async function main() {
902
904
  if (command === "uninstall") {
903
905
  const id = subcommand;
904
906
  if (!id) {
905
- console.error("Usage: lotics uninstall <app_id|pci_id> [--archive-tables] [--keep-content]");
907
+ console.error("Usage: lotics uninstall <app_id|package_id> [--archive-tables] [--keep-content]");
906
908
  console.error("Dispatched by id: an app installation (app_id; --archive-tables to also archive its " +
907
- "scaffolded tables) or a standalone content installation (pci_ id from `lotics install` / " +
909
+ "scaffolded tables) or a content package (apg_ id from `lotics install` / " +
908
910
  "lotics package list-content; --keep-content to retain its docs).");
909
911
  process.exit(1);
910
912
  }
913
+ // A `pci_` resource id is retired from human sight — redirect to the package-id form.
914
+ if (id.startsWith("pci_")) {
915
+ await redirectContentPciForm(client, id, "uninstall");
916
+ return;
917
+ }
911
918
  await packageUninstall(client, {
912
919
  id,
913
920
  keep_content: flags.keepContent,
@@ -918,9 +925,9 @@ async function main() {
918
925
  if (command === "upgrade") {
919
926
  const target = subcommand;
920
927
  if (!target) {
921
- console.error("Usage: lotics upgrade <app_id | pci_id | package_id> [--version N] [--resolve <key>=... ...] [--bind-to ...] [--apply-all]");
922
- console.error("Dispatched by id: an app installation (app_id), a standalone content installation (pci_ id), " +
923
- "or a package id (apg_ fleet-upgrades every installation across your org).");
928
+ console.error("Usage: lotics upgrade <app_id | package_id> [--version N] [--resolve <key>=... ...] [--bind-to ...] [--apply-all]");
929
+ console.error("Dispatched by id: an app installation (app_id), or a package id (apg_) — a CONTENT package " +
930
+ "upgrades this workspace's install; an APP package fleet-upgrades every installation across your org.");
924
931
  process.exit(1);
925
932
  }
926
933
  let version;
@@ -931,22 +938,24 @@ async function main() {
931
938
  process.exit(1);
932
939
  }
933
940
  }
934
- // A package id fleet-upgrades every installation across the org; a `pci_` id
935
- // is a standalone content installation; anything else is an app installation.
936
- if (target.startsWith("apg_")) {
937
- await packageFleetUpgrade(client, { package_id: target, version });
941
+ // A `pci_` resource id is retired from human sight redirect to the package-id form.
942
+ if (target.startsWith("pci_")) {
943
+ await redirectContentPciForm(client, target, "upgrade");
938
944
  return;
939
945
  }
940
- if (target.startsWith("pci_")) {
941
- await packageUpgradeKnowledge(client, {
942
- installation_id: target,
946
+ // A package id (apg_) is kind-branched: a content package upgrades THIS
947
+ // workspace's install; an app package fleet-upgrades the whole org.
948
+ if (target.startsWith("apg_")) {
949
+ await packageUpgradeByPackageId(client, {
950
+ package_id: target,
943
951
  version,
944
952
  resolve: flags.resolve,
945
- bind_to: parseBindToFlags(flags.bindTo),
953
+ bindTo: flags.bindTo,
946
954
  applyAll: flags.applyAll,
947
955
  });
948
956
  return;
949
957
  }
958
+ // Anything else is an app installation (addressed by its app id).
950
959
  await packageUpgrade(client, {
951
960
  app_id: target,
952
961
  version,
@@ -1019,8 +1028,8 @@ async function main() {
1019
1028
  // `lotics package <verb>` forms loudly with a redirect, never a silent no-op.
1020
1029
  const movedVerbs = {
1021
1030
  install: "lotics install <package_id>",
1022
- uninstall: "lotics uninstall <app_id|pci_id>",
1023
- upgrade: "lotics upgrade <app_id|pci_id|package_id>",
1031
+ uninstall: "lotics uninstall <app_id|package_id>",
1032
+ upgrade: "lotics upgrade <app_id|package_id>",
1024
1033
  "fleet-upgrade": "lotics upgrade <package_id>",
1025
1034
  };
1026
1035
  if (subcommand !== undefined && subcommand in movedVerbs) {
@@ -1330,8 +1339,10 @@ async function main() {
1330
1339
  console.log(JSON.stringify({ error: result.error }, null, 2));
1331
1340
  }
1332
1341
  else {
1342
+ // Execution errors (not-found, refusals) carry the server's message;
1343
+ // the input already passed schema validation, so no schema hint —
1344
+ // validation 400s bring the server's own hint via throwResponseError.
1333
1345
  console.error(result.error);
1334
- console.error(`\nHint: run "lotics tools ${toolName}" to see the expected input schema.`);
1335
1346
  }
1336
1347
  process.exit(1);
1337
1348
  }
@@ -104,8 +104,8 @@ describe("lotics top-level consumer-verb dispatch", () => {
104
104
  // bare invocation — reaching it fires before any network work.
105
105
  const usageCases = [
106
106
  ["install", /Usage: lotics install <package_id>/],
107
- ["uninstall", /Usage: lotics uninstall <app_id\|pci_id>/],
108
- ["upgrade", /Usage: lotics upgrade <app_id \| pci_id \| package_id>/],
107
+ ["uninstall", /Usage: lotics uninstall <app_id\|package_id>/],
108
+ ["upgrade", /Usage: lotics upgrade <app_id \| package_id>/],
109
109
  ];
110
110
  for (const [verb, usage] of usageCases) {
111
111
  it(`routes top-level "${verb}" to its handler (usage on missing id)`, () => {
@@ -115,6 +115,19 @@ describe("lotics top-level consumer-verb dispatch", () => {
115
115
  expect(status).toBe(1);
116
116
  });
117
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
+ }
118
131
  });
119
132
  describe("lotics app author-verb dispatch", () => {
120
133
  // `app publish` (no id, empty cwd) must fail on the missing local app
package/dist/client.d.ts CHANGED
@@ -542,31 +542,60 @@ export declare class LoticsClient {
542
542
  /**
543
543
  * Preview a release — the dry run behind `lotics app release`. Runs the
544
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, and
546
- * any extract findings (an `error` blocks the apply). No writes. Admin,
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,
547
550
  * owning-org only.
548
551
  */
549
- previewPackageRelease(app_id: string): Promise<{
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<{
550
559
  package_id: string;
551
560
  version: number;
552
561
  added_aliases: string[];
553
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
+ };
554
569
  findings: ExtractFinding[];
555
570
  }>;
556
571
  /**
557
572
  * Release — snapshot the origin app into the next registry version. The server
558
573
  * binding-aware-extracts it, repackages its deployed source + dist as the
559
574
  * bundle, publishes the next `release`-channel version with the changelog, and
560
- * re-pins the origin. Error findings from extract surface as a 409. Admin,
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,
561
579
  * owning-org only. Backs `lotics app release --yes`.
562
580
  */
563
581
  releasePackage(app_id: string, body: {
564
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
+ }>;
565
588
  }): Promise<{
566
589
  package_id: string;
567
590
  version: number;
568
591
  added_aliases: string[];
569
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
+ };
570
599
  }>;
571
600
  /**
572
601
  * Dry-run preview of a first-release — the `GET` behind `lotics app publish`
package/dist/client.js CHANGED
@@ -353,18 +353,29 @@ export class LoticsClient {
353
353
  /**
354
354
  * Preview a release — the dry run behind `lotics app release`. Runs the
355
355
  * binding-aware extract of the origin (aliases stable through the app's current
356
- * binding) and reports the next version number, the new + changed aliases, and
357
- * any extract findings (an `error` blocks the apply). No writes. Admin,
356
+ * binding) and reports the next version number, the new + changed aliases, the
357
+ * bundled-knowledge delta, and any extract findings (an `error` blocks the
358
+ * apply). An optional `knowledge` declaration (from the pulled app manifest)
359
+ * re-declares the bundle set — added/dropped/changed docs surface in the delta;
360
+ * omitted, the current corpus is reconstructed from the pin. No writes. Admin,
358
361
  * owning-org only.
359
362
  */
360
- async previewPackageRelease(app_id) {
361
- return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/package-release`);
363
+ async previewPackageRelease(app_id, opts = {}) {
364
+ const params = new URLSearchParams();
365
+ if (opts.knowledge !== undefined && opts.knowledge.length > 0) {
366
+ params.set("knowledge", JSON.stringify(opts.knowledge));
367
+ }
368
+ const query = params.toString();
369
+ return this.request("GET", `/v1/apps/${encodeURIComponent(app_id)}/package-release${query ? `?${query}` : ""}`);
362
370
  }
363
371
  /**
364
372
  * Release — snapshot the origin app into the next registry version. The server
365
373
  * binding-aware-extracts it, repackages its deployed source + dist as the
366
374
  * bundle, publishes the next `release`-channel version with the changelog, and
367
- * re-pins the origin. Error findings from extract surface as a 409. Admin,
375
+ * re-pins the origin. An optional `knowledge` declaration re-declares the
376
+ * bundled-knowledge set (added/dropped/re-snapshotted docs; omitted preserves
377
+ * the current corpus). Error findings from extract surface as a 409; a
378
+ * missing/archived declared doc is a 400, a foreign-package doc a 409. Admin,
368
379
  * owning-org only. Backs `lotics app release --yes`.
369
380
  */
370
381
  async releasePackage(app_id, body) {
@@ -127,7 +127,12 @@ function inputDeclToTsType(decl) {
127
127
  return null;
128
128
  })
129
129
  .filter((v) => v !== null);
130
- const inner = literals.length > 0 ? literals.join(" | ") : "string";
130
+ // The literal union keeps autocomplete for hand-typed ids, but a package
131
+ // app addresses options through the runtime-resolved OPT map (typed
132
+ // string — consumer workspaces bind DIFFERENT concrete ids), so the
133
+ // input must also accept string. `(string & {})` widens without
134
+ // collapsing the union in intellisense.
135
+ const inner = literals.length > 0 ? `${literals.join(" | ")} | (string & {})` : "string";
131
136
  return decl.multi === true ? `ReadonlyArray<${inner}>` : inner;
132
137
  }
133
138
  case "date_range":
@@ -193,7 +198,11 @@ function outputDeclToTsType(decl) {
193
198
  ? JSON.stringify(o.value)
194
199
  : null)
195
200
  .filter((v) => v !== null);
196
- const inner = literals.length > 0 ? literals.join(" | ") : "string";
201
+ // Same widening on the READ side: a package app's runtime output value is
202
+ // the CONSUMER workspace's concrete opt_ id, not the origin's literal —
203
+ // exhaustive narrowing over origin literals would be unsound. `(string & {})`
204
+ // keeps autocomplete without lying about the value space.
205
+ const inner = literals.length > 0 ? `${literals.join(" | ")} | (string & {})` : "string";
197
206
  return decl.multi === true ? `ReadonlyArray<${inner}>` : inner;
198
207
  }
199
208
  case "object": {
@@ -77,8 +77,8 @@ describe("generateAppWorkflowsDts", () => {
77
77
  });
78
78
  expect(dts).toContain("record_id: string;"); // required → NOT nullable
79
79
  expect(dts).toContain("due?: string | null;"); // optional scalar → clearable
80
- expect(dts).toContain('status?: "opt_done" | null;');
81
- expect(dts).toContain('tags?: ReadonlyArray<"opt_a"> | null;'); // optional multi
80
+ expect(dts).toContain('status?: "opt_done" | (string & {}) | null;');
81
+ expect(dts).toContain('tags?: ReadonlyArray<"opt_a" | (string & {})> | null;'); // optional multi
82
82
  // The object itself is a top-level optional → nullable; its NESTED optional
83
83
  // field mirrors the backend's plain `.optional()` (no `| null`).
84
84
  expect(dts).toContain("note?: string;");
@@ -94,7 +94,7 @@ describe("generateAppWorkflowsDts", () => {
94
94
  },
95
95
  },
96
96
  });
97
- expect(dts).toContain('owner: string; tags: ReadonlyArray<"a" | "b">');
97
+ expect(dts).toContain('owner: string; tags: ReadonlyArray<"a" | "b" | (string & {})>');
98
98
  });
99
99
  it("types a multi file input as ReadonlyArray<string>, single file as string", () => {
100
100
  const dts = generateAppWorkflowsDts({
@@ -79,24 +79,28 @@ export declare function packageShow(client: LoticsClient, args: {
79
79
  package_id: string;
80
80
  }): Promise<void>;
81
81
  /**
82
- * Preview-then-apply a STANDALONE content installation upgrade knowledge docs
83
- * AND document templates behind one review gate. Prints the per-alias plan;
84
- * refuses (exit 1, with the exact `--resolve` syntax) while any consent-requiring
85
- * entry lacks a resolution a modified knowledge change/removal or drift, or a
86
- * locally-edited changed template. `--apply-all` auto-resolves EVERY consent entry
87
- * by accepting the package's version (knowledge changed→apply, removed→archive,
88
- * drifted→recreate; template→revert) — an explicit bulk "take upstream" that
89
- * discards local edits. `--resolve knowledge.<alias>=<value>` /
90
- * `--resolve template.<alias>=revert|keep` and `--bind-to <alias>=<kdc_id>`
91
- * resolve entries individually — the ONE namespaced grammar, passed to the
92
- * server verbatim.
82
+ * CLEAN BREAK for an explicit `pci_` argument on `upgrade` / `uninstall`: the
83
+ * `pci_` resource id is retired from human sight content installs are addressed
84
+ * by their PACKAGE id. Prints a loud redirect, best-effort resolving the `pci_`
85
+ * back to its package id (via list-content) so the exact command is spelled out.
86
+ * The header prints synchronously first, so the redirect is observable even when
87
+ * the best-effort resolution can't reach the registry.
93
88
  */
94
- export declare function packageUpgradeKnowledge(client: LoticsClient, args: {
95
- installation_id: string;
89
+ export declare function redirectContentPciForm(client: LoticsClient, pci_id: string, verb: "upgrade" | "uninstall"): Promise<never>;
90
+ /**
91
+ * `lotics upgrade <apg_>` — the package-id upgrade path, kind-branched. `kind` is a
92
+ * DERIVED display hint (`contractHasAppSurface`): `'content'` means no app surface.
93
+ * - a CONTENT package upgrades THIS workspace's standalone content installation
94
+ * (resolved from the package id — the anchor is unique per workspace, so the
95
+ * `pci_` never surfaces), through the same content review gate.
96
+ * - an APP-surface package FLEET-upgrades every installation across the org
97
+ * (unchanged) — the resolve/bind/apply-all flags don't apply to a fleet run.
98
+ */
99
+ export declare function packageUpgradeByPackageId(client: LoticsClient, args: {
100
+ package_id: string;
96
101
  version?: number;
97
- /** Raw `--resolve <alias>=<value>` flags, routed to knowledge/templates after the preview. */
98
102
  resolve: string[];
99
- bind_to: Record<string, string>;
103
+ bindTo: string[];
100
104
  applyAll: boolean;
101
105
  }): Promise<void>;
102
106
  /** Parse repeated `--bind-to alias=kdc_id` flags into an alias → doc-id consent map. */
@@ -110,9 +114,11 @@ export declare function packageInstall(client: LoticsClient, args: {
110
114
  config?: Record<string, string | number | boolean>;
111
115
  }): Promise<void>;
112
116
  /**
113
- * `lotics uninstall <app_id|pci_id>` — ONE top-level command over both installation
114
- * kinds, dispatched by the id form (mirrors `lotics upgrade`):
115
- * - a `pci_` id a STANDALONE CONTENT installation: deletes the row and (unless
117
+ * `lotics uninstall <app_id|package_id>` — ONE top-level command over both
118
+ * installation kinds, dispatched by the id form (mirrors `lotics upgrade`):
119
+ * - a package id (`apg_`)THIS workspace's STANDALONE CONTENT installation
120
+ * (content installs are addressed by package id, UNIQUE per workspace, so the
121
+ * `pci_` resource id never surfaces): deletes the row and (unless
116
122
  * `--keep-content`) archives its package-bound docs AND templates, listing each
117
123
  * archived id.
118
124
  * - anything else (an `app_id`) → an APP installation: archives its workflow
@@ -129,8 +135,9 @@ export declare function packageUninstall(client: LoticsClient, args: {
129
135
  * `lotics package list-content` — list the selected workspace's STANDALONE
130
136
  * content installations (an app-bundled corpus rides its app's
131
137
  * `binding.knowledge` and shows on the Apps surface instead), each with its
132
- * registry status. The read surface that surfaces a `pci_` id for
133
- * `upgrade` / `uninstall` (install prints it once; nothing else did before).
138
+ * registry status. The what-is-installed listing: each row leads with the PACKAGE
139
+ * id the address for `lotics upgrade <package_id>` / `lotics uninstall
140
+ * <package_id>` (the `pci_` resource id stays hidden).
134
141
  */
135
142
  export declare function packageListContent(client: LoticsClient): Promise<void>;
136
143
  export declare function packageEject(client: LoticsClient, args: {
@@ -185,9 +192,15 @@ export declare function appPublish(client: LoticsClient, args: {
185
192
  * § Promotion). The origin is the permanent working copy; a release binding-aware-
186
193
  * extracts it (stable aliases), repackages its DEPLOYED source + dist as the
187
194
  * bundle, publishes the next version, and re-pins the origin. Prints the preview
188
- * first (next version, new + changed aliases, findings); applies only with
189
- * `--yes`, else exits 1 so a review step can't be skipped. An `error` finding
190
- * blocks the apply.
195
+ * first (next version, new + changed aliases, the bundled-knowledge delta,
196
+ * findings); applies only with `--yes`, else exits 1 so a review step can't be
197
+ * skipped. An `error` finding blocks the apply.
198
+ *
199
+ * Run from the pulled app project, the manifest's `lotics.knowledge` (alias →
200
+ * doc_id) is the bundle DECLARATION — it re-declares which docs the package owns
201
+ * (add/drop/re-snapshot). Forwarded only when non-empty; empty (or a bare id from
202
+ * elsewhere) sends nothing, so the current corpus is reconstructed from the pin
203
+ * (never silently dropped).
191
204
  */
192
205
  export declare function appRelease(client: LoticsClient, args: {
193
206
  app_id?: string;
@@ -206,14 +219,3 @@ export declare function packageYank(client: LoticsClient, args: {
206
219
  version: number;
207
220
  undo: boolean;
208
221
  }): Promise<void>;
209
- /**
210
- * `lotics upgrade <package_id> [--version N]` (fleet path) — bring every
211
- * installation of the package across the caller's org to the target version.
212
- * Hands-off applies only where the preview is clean; skipped/failed
213
- * installations are reported per line and the process exits 1 so a release
214
- * script can gate on "fleet fully current".
215
- */
216
- export declare function packageFleetUpgrade(client: LoticsClient, args: {
217
- package_id: string;
218
- version?: number;
219
- }): Promise<void>;