@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,24 +1,24 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { generatePackageAppFields } from "./generate_package_fields.js";
3
- const contract = {
4
- entities: [
5
- {
6
- alias: "tasks",
7
- fields: [
8
- { alias: "title" },
9
- {
10
- alias: "status",
11
- options: [{ alias: "to_do" }, { alias: "doing" }, { alias: "done" }],
12
- },
13
- ],
14
- },
15
- { alias: "projects", fields: [{ alias: "name" }] },
16
- ],
17
- roles: [{ alias: "approver" }],
3
+ // A live installation binding — fully-qualified alias → concrete id. The
4
+ // generator sources the alias SET here (never a contract file); the emitted
5
+ // module resolves the SAME keys through `getAppBinding()` at runtime.
6
+ const binding = {
7
+ fields: {
8
+ "tasks.title": "fld_title",
9
+ "tasks.status": "fld_status",
10
+ "projects.name": "fld_name",
11
+ },
12
+ options: {
13
+ "tasks.status:to_do": "opt_todo",
14
+ "tasks.status:doing": "opt_doing",
15
+ "tasks.status:done": "opt_done",
16
+ },
17
+ roles: { approver: "grp_approver" },
18
18
  };
19
19
  describe("generatePackageAppFields", () => {
20
- it("emits runtime-resolved F/OPT/ROLE keyed by contract aliases", () => {
21
- const src = generatePackageAppFields(contract);
20
+ it("emits runtime-resolved F/OPT/ROLE keyed by the binding's aliases", () => {
21
+ const src = generatePackageAppFields(binding);
22
22
  // Resolves through the SDK binding at module load (top-level await).
23
23
  expect(src).toContain('import { getAppBinding } from "@lotics/app-sdk";');
24
24
  expect(src).toContain("const binding = await getAppBinding();");
@@ -31,21 +31,29 @@ describe("generatePackageAppFields", () => {
31
31
  expect(src).toContain('to_do: bound(binding.options, "tasks.status:to_do", "option")');
32
32
  expect(src).toContain('done: bound(binding.options, "tasks.status:done", "option")');
33
33
  expect(src).not.toContain('"tasks.title:');
34
- // ROLE map from contract roles.
34
+ // ROLE map from the binding's roles.
35
35
  expect(src).toContain('approver: bound(binding.roles, "approver", "role")');
36
36
  // No concrete id in any VALUE position — the module is workspace-agnostic.
37
37
  // (Doc comments legitimately name the id prefixes, so match quoted ids.)
38
38
  expect(src).not.toMatch(/"(fld|opt|tbl|grp)_/);
39
39
  });
40
- it("emits valid empty maps for an empty contract", () => {
41
- const src = generatePackageAppFields({});
40
+ it("emits valid empty maps for an empty binding", () => {
41
+ const src = generatePackageAppFields({ fields: {}, options: {}, roles: {} });
42
42
  expect(src).toContain("export const F = {} as const;");
43
43
  expect(src).toContain("export const OPT = {} as const;");
44
44
  expect(src).toContain("export const ROLE = {} as const;");
45
45
  // Still imports the SDK so the module shape is uniform.
46
46
  expect(src).toContain("const binding = await getAppBinding();");
47
47
  });
48
- it("is deterministic same contract, same bytes", () => {
49
- expect(generatePackageAppFields(contract)).toBe(generatePackageAppFields(contract));
48
+ it("quotes an alias that is not a valid identifier", () => {
49
+ const src = generatePackageAppFields({
50
+ fields: { "tasks.2nd_field": "fld_x" },
51
+ options: {},
52
+ roles: {},
53
+ });
54
+ expect(src).toContain('"2nd_field": bound(binding.fields, "tasks.2nd_field", "field")');
55
+ });
56
+ it("is deterministic — same binding, same bytes", () => {
57
+ expect(generatePackageAppFields(binding)).toBe(generatePackageAppFields(binding));
50
58
  });
51
59
  });
@@ -1,262 +1,46 @@
1
- import { LoticsClient, type PackageBinding, type ExtractFinding } from "./client.js";
2
- import { type KnowledgeUpgradeEntry, type KnowledgeResolution, type ModificationResolution } from "@lotics/shared/schemas/packages";
3
- /** One dev workspace's pinned installation of this package (manifest bookkeeping). */
4
- interface PackageDevInstallation {
5
- app_id: string;
6
- version: number;
7
- }
8
- /**
9
- * One package-managed knowledge doc's authoring metadata, from
10
- * `package.json#lotics.package.knowledge` (alias this). The content lives in a
11
- * sibling `knowledge/<alias>.md` file; `build`/`publish` sha256 the file and fold
12
- * both into the contract's `knowledge` namespace. Round-trips through the manifest
13
- * so a manifest write (e.g. stamping the package id on first publish) never drops
14
- * it — and it therefore ships in `source.tar.gz` for eject/extract.
15
- */
16
- interface PackageKnowledgeManifestEntry {
17
- name: string;
18
- description: string | null;
19
- active_by_default: boolean;
20
- }
21
- /** The 5 document-template kinds a package template may declare (== the contract's). */
22
- export type PackageTemplateKind = "html" | "email" | "excel" | "word" | "pdf-form";
23
- /**
24
- * One package-managed document template's authoring metadata, from
25
- * `package.json#lotics.package.templates` (alias this). The template file lives
26
- * at `templates/<file>`; `build`/`publish` fold it into the contract's
27
- * `templates` namespace an inline kind (html/email) reads the file as `content`,
28
- * a file-backed kind (excel/word/pdf-form) records `bytes_ref: templates/<file>`
29
- * (the bytes ride in `source.tar.gz`, like a knowledge doc's content) — then
30
- * `foldTemplateShasIntoContract` computes each `content_sha256`. This is how a
31
- * CONTENT package declares standalone templates (an app package authors them in
32
- * `contract.json` directly). Round-trips through the manifest so a manifest write
33
- * never drops it.
34
- */
35
- interface PackageTemplateManifestEntry {
36
- name: string;
37
- type: PackageTemplateKind;
38
- /** The template file's name within the project's `templates/` dir. */
39
- file: string;
40
- }
41
- /**
42
- * The `package.json#lotics.package` block of a package project. `id` is null
43
- * until the first publish (which creates the registry package); `version` tracks
44
- * the latest version this project has published; `dev` maps a dev workspace id to
45
- * the installation it scaffold-syncs into.
46
- */
47
- /** A package project's kind — mirrors the registry `packages.kind` (immutable after create). */
48
- export type PackageKind = "app" | "content";
49
- interface PackageManifest {
50
- id: string | null;
51
- name: string;
52
- description: string | null;
53
- /**
54
- * 'app' (the full materialized blueprint) | 'content' (a standalone content
55
- * package). Threaded to `createPackage` on first publish and used locally to
56
- * gate the build (a content package has no app source to compile). Defaults to
57
- * 'app' for a manifest written before content packaging.
58
- */
59
- kind: PackageKind;
60
- version: number | null;
61
- /** alias → knowledge-doc authoring metadata (content in `knowledge/<alias>.md`). */
62
- knowledge: Record<string, PackageKnowledgeManifestEntry>;
63
- /** alias → document-template authoring metadata (file in `templates/<file>`). */
64
- templates: Record<string, PackageTemplateManifestEntry>;
65
- /**
66
- * Doc NAMES the package's agents route to but the package does not own —
67
- * install/health WARN when a name has no doc in the workspace. Lives under
68
- * `lotics.package` (one coherent home for everything package-related), NOT a
69
- * sibling of it.
70
- */
71
- knowledge_expects: string[];
72
- dev: Record<string, PackageDevInstallation>;
73
- }
74
- interface PackageProjectFile {
75
- /** Parsed package.json, carrying the `lotics.package` manifest under `lotics`. */
76
- pkgJson: Record<string, unknown>;
77
- manifest: PackageManifest;
78
- }
79
- /** Read the package project's manifest, failing loud when the dir isn't one. */
80
- export declare function readPackageProject(projectDir: string): PackageProjectFile;
81
- /** Persist an updated manifest back into the project's package.json (atomic write). */
82
- export declare function writePackageManifest(projectDir: string, project: PackageProjectFile): void;
83
- /**
84
- * The package.json to ship INSIDE `source.tar.gz`: the on-disk manifest with the
85
- * author-local `lotics.package.dev` map stripped. `dev` is the author's private
86
- * dev-workspace → installation bookkeeping; it must never reach a consumer (every
87
- * install carries the source, and `lotics app pull` ejects it). Returns a
88
- * sanitized copy — the on-disk package.json is left untouched. `id`/`name`/
89
- * `description`/`version` are the package's stable identity and stay.
90
- */
91
- export declare function sanitizePackageJsonForSource(pkgJson: Record<string, unknown>): Record<string, unknown>;
92
- /**
93
- * Transform an app project's package.json (the source archive `lotics app pull`
94
- * downloads, carrying the `lotics.app_id`/`workspace_id` app manifest) into a
95
- * package project's `PackageProjectFile`: the app manifest is stripped ENTIRELY
96
- * and a fresh, unpublished `lotics.package` manifest (id/version null) is
97
- * grafted. Pure — returns a new value, never mutates the input;
98
- * `writePackageManifest` writes it (atomic). The bespoke→package promotion's
99
- * manifest inversion.
100
- */
101
- export declare function draftPackageProjectFromApp(appPkgJson: Record<string, unknown>, args: {
102
- name: string;
103
- description: string | null;
104
- }): PackageProjectFile;
105
- /**
106
- * Parse + validate `.lotics/adopt_binding.json` against the app being adopted.
107
- * REFUSES a pin recorded for a different app: a binding maps ONE workspace's
108
- * concrete ids, so replaying it onto another app would bind the wrong objects.
109
- * Pure; the CLI never interprets the binding, only round-trips it to the server.
110
- */
111
- export declare function parseAdoptBindingFile(raw: unknown, expectedAppId: string): {
112
- app_id: string;
113
- workspace_id: string;
114
- binding: PackageBinding;
115
- knowledge_binding: Record<string, string>;
116
- };
117
- /**
118
- * Render an extraction report grouped by severity (errors, then warnings, then
119
- * info), one ` [<severity>] <area>: <message>` line each, and classify whether
120
- * any `error` finding is present. An `error` ⇒ the draft is not publishable
121
- * as-is, so `lotics package extract` exits non-zero. Pure — the command prints
122
- * `lines` to stderr and gates on `hasError`.
1
+ import { LoticsClient, type ExtractFinding } from "./client.js";
2
+ import { type UpgradeResolutions } from "@lotics/shared/schemas/packages";
3
+ /**
4
+ * Read the local APP project's manifest (`package.json#lotics.app_id` +
5
+ * `lotics.knowledge`) — what `lotics app pull` writes. `lotics app publish` /
6
+ * `release` run from a pulled app project resolve the app id from it, and
7
+ * `publish` forwards the package-managed knowledge declaration to the server
8
+ * (agents reference docs by free text, so the author declares which the package
9
+ * owns). Returns null when the dir has no package.json. `app_id` is null when the
10
+ * manifest is a package/non-app project.
11
+ */
12
+ export declare function readLocalAppManifest(projectDir: string): {
13
+ app_id: string | null;
14
+ knowledge: Array<{
15
+ alias: string;
16
+ doc_id: string;
17
+ }>;
18
+ } | null;
19
+ /** Parse repeated `--rename old=new` flags into `{ from, to }[]` (first-publish alias fixes). */
20
+ export declare function parseRenameFlags(renames: string[]): Array<{
21
+ from: string;
22
+ to: string;
23
+ }>;
24
+ /**
25
+ * Render a package-extract report grouped by severity (errors, then warnings,
26
+ * then info), one ` [<severity>] <area>: <message>` line each, and classify
27
+ * whether any `error` finding is present. Shared by the release preview display.
28
+ * Pure the command prints `lines` to stderr and gates on `hasError`.
123
29
  */
124
30
  export declare function formatExtractReport(report: ExtractFinding[]): {
125
31
  lines: string[];
126
32
  hasError: boolean;
127
33
  };
128
34
  /**
129
- * Fold a package project's knowledge corpus into its contract before publish:
130
- * per `lotics.package.knowledge` alias, read `knowledge/<alias>.md`, sha256 the
131
- * bytes, and emit the contract's `knowledge` namespace (alias {name,
132
- * description, content_ref, content_sha256, active_by_default}) +
133
- * `knowledge_expects` (from `lotics.package.knowledge_expects`). This is the ONE
134
- * place the sha is computed it can't be hand-authored, which is why knowledge
135
- * (unlike a template `bytes_ref`) is derived rather than written into
136
- * contract.json. The content files themselves ride in `source.tar.gz`
137
- * automatically: `knowledge/` is a top-level dir, so `stagePackageSource` copies
138
- * it like any other source (the same mechanism that carries template bytes). Pure
139
- * w.r.t. `contract` — returns a new object; the server re-validates the folded
140
- * namespace at publish.
141
- */
142
- export declare function foldKnowledgeIntoContract(projectDir: string, project: PackageProjectFile, contract: Record<string, unknown>): Record<string, unknown>;
143
- /**
144
- * Fold a CONTENT package's manifest-declared templates into its contract before
145
- * publish: per `lotics.package.templates` alias, an INLINE kind (html/email) reads
146
- * `templates/<file>` into the contract template's `content`; a FILE-BACKED kind
147
- * (excel/word/pdf-form) records `bytes_ref: templates/<file>` (the bytes ride in
148
- * `source.tar.gz` — `templates/` is a top-level dir `stagePackageSource` copies,
149
- * the same mechanism that carries knowledge content + app-package template bytes).
150
- * The per-template `content_sha256` is NOT computed here — `foldTemplateShasIntoContract`
151
- * runs after and derives it (inline: the utf-8 content; file-backed: the file bytes).
152
- *
153
- * Appends to any templates the contract already declares (an app package authors
154
- * templates in `contract.json` directly; the manifest path is how a content
155
- * package — with no `contract.json` templates — declares them). An alias in BOTH
156
- * is a loud error. Pure w.r.t. `contract` — returns a new object.
157
- */
158
- export declare function foldTemplatesIntoContract(projectDir: string, project: PackageProjectFile, contract: unknown): Record<string, unknown>;
159
- /**
160
- * Fold a freshly-computed `content_sha256` into every template of a package
161
- * contract before publish — the modified-detection reference the install/upgrade
162
- * flow compares live content against. Like knowledge's sha (foldKnowledge…), it
163
- * can't be hand-authored: an INLINE template's sha covers its utf-8 `content`; a
164
- * FILE-BACKED template's sha covers the `bytes_ref` file's bytes (the same bytes
165
- * that ride in `source.tar.gz` and install stores verbatim). Always recomputed
166
- * (never trusted from contract.json), so the published contract's sha is exact.
167
- * Pure w.r.t. `contract` — returns a new object; the server re-validates.
168
- */
169
- export declare function foldTemplateShasIntoContract(projectDir: string, contract: Record<string, unknown>): Record<string, unknown>;
170
- /**
171
- * Copy the project's source tree into `sourceStage` with explicit TOP-LEVEL
172
- * excludes, writing a sanitized `package.json` in place of the on-disk one.
173
- * Deliberately not tar `--exclude` flags: those match at any depth (a nested
174
- * `templates/dist/` would be silently dropped) and GNU tar vs bsdtar (macOS)
175
- * disagree on `./`-prefixed patterns, which broke the sanitized-package.json
176
- * graft on macOS.
177
- */
178
- export declare function stagePackageSource(projectDir: string, sourceStage: string): void;
179
- /** The minimal, valid starting contract a `package new` scaffold ships. */
180
- export declare function starterContract(name: string): Record<string, unknown>;
181
- /**
182
- * `lotics package new <name> [path] [--kind content]` — scaffold a package
183
- * project. An `app` package reuses the app starter (Vite+React+TS) for the code
184
- * surface, swaps its app manifest for a package manifest, and adds a starter
185
- * `contract.json`; a `content` package scaffolds a docs-only corpus (no app
186
- * source). The project publishes with `lotics package publish`.
187
- */
188
- export declare function packageNew(args: {
189
- name: string;
190
- targetPath?: string;
191
- kind?: PackageKind;
192
- }): Promise<void>;
193
- /**
194
- * `lotics package build [path]` — build the publishable bundle and write it to
195
- * `bundle.tar.gz` in the project. Mostly a local sanity check / CI artifact;
196
- * `publish` and `dev`/`sync` build the bundle in memory directly.
197
- */
198
- export declare function packageBuild(args: {
199
- projectDir?: string;
200
- }): Promise<void>;
201
- /**
202
- * `lotics package publish [path] [-m <changelog>]` — publish a new version.
203
- */
204
- export declare function packagePublish(client: LoticsClient, args: {
205
- projectDir?: string;
206
- changelog?: string;
207
- }): Promise<void>;
208
- /**
209
- * Fail loud unless `workspace` is a throwaway dev workspace. The dev/sync
210
- * scaffold path publishes a new version and scaffold-installs package tables into
211
- * the resolved workspace, so the target MUST be a dev workspace — this mirrors
212
- * the server-side `package reset` gate so a forgotten `--workspace` (prod
213
- * selected) can never scaffold package tables into prod. Fails closed: an absent
214
- * `is_dev` (a server that doesn't yet serialize it) is treated as non-dev.
215
- */
216
- export declare function assertDevWorkspace(workspace: {
217
- id: string;
218
- name: string;
219
- is_dev?: boolean;
220
- }): void;
221
- /**
222
- * `lotics package sync [path]` — re-run the scaffold-sync into the dev workspace
223
- * (the continuous loop: edit contract → sync additively migrates + re-materializes).
224
- */
225
- export declare function packageSync(client: LoticsClient, args: {
226
- projectDir?: string;
227
- }): Promise<void>;
228
- /**
229
- * `lotics package dev [path] [--workspace <dev_ws>] [--view-as <member>]` —
230
- * scaffold-sync the package into the dev workspace, then run the existing app
231
- * dev server against the resulting installation (HMR over the local source, RPC
232
- * forwarded to the live installation). The inner loop: edit contract → re-run to
233
- * sync; edit code → hot reload.
234
- */
235
- export declare function packageDev(client: LoticsClient, args: {
236
- projectDir?: string;
237
- port?: number;
238
- vitePort?: number;
239
- }): Promise<void>;
240
- /**
241
- * `lotics package reset [path]` — DEV-ONLY, hard-gated. Drops the dev
242
- * installation's package-owned scaffolded tables and re-scaffolds them clean. The
243
- * backend refuses any workspace not flagged as a dev workspace, so this can never
244
- * erase a real workspace's data. The dev installation is resolved from the
245
- * project manifest's pin for the selected workspace.
246
- */
247
- export declare function packageReset(client: LoticsClient, args: {
248
- projectDir?: string;
249
- }): Promise<void>;
250
- export type UpgradeResolutionValue = "recreate" | "revert" | "keep" | {
251
- bind_to: string;
252
- };
253
- /**
254
- * Parse repeated `--resolve <key>=<value>` flags. Drift entries
255
- * (`<namespace>.<alias>`) take `recreate` or an existing id; modified
256
- * artifacts (`<kind>.<alias>`) take `revert` or `keep`. Any other value is a
257
- * bind_to id; the server validates value-kind against what the key resolves.
35
+ * Parse repeated `--resolve <key>=<value>` flags into the ONE namespaced
36
+ * resolutions map every upgrade wire takes. Keys pass through verbatim — a
37
+ * drifted binding entry (`<namespace>.<alias>`), a modified artifact
38
+ * (`<kind>.<alias>`), a bundled/standalone knowledge doc (`knowledge.<alias>`),
39
+ * or a live-role re-point (`roles.<alias>`). A value that is one of the
40
+ * resolution verbs stays a verb; anything else is a `{ bind_to }` id. The
41
+ * server validates value-kind against what each key resolves.
258
42
  */
259
- export declare function parseResolveFlags(resolve: string[]): Record<string, UpgradeResolutionValue>;
43
+ export declare function parseResolveFlags(resolve: string[]): UpgradeResolutions;
260
44
  /**
261
45
  * Health check: version pin vs. registry latest + binding drift. Exits
262
46
  * non-zero when drift is found so scripts can gate on it.
@@ -270,11 +54,13 @@ export declare function packageDoctor(client: LoticsClient, args: {
270
54
  * the exact --resolve syntax) while any binding drift, modified core artifact, or
271
55
  * consent-requiring bundled-knowledge doc lacks a resolution.
272
56
  *
273
- * `--resolve` is shared across the finding classes: a key naming a bundled
274
- * knowledge doc routes to `knowledge_resolutions` (apply|keep|archive|recreate|
275
- * unbind), everything else to core `resolutions`; `--bind-to` consents an
276
- * added-knowledge-doc name collision; `--apply-all` accepts the package's version
277
- * for every consent-requiring knowledge doc (overwriting local edits).
57
+ * `--resolve` speaks ONE namespaced grammar, passed to the server verbatim: a
58
+ * drifted binding entry (`<namespace>.<alias>`), a modified artifact
59
+ * (`<kind>.<alias>`), a bundled knowledge doc (`knowledge.<alias>`
60
+ * apply|keep|archive|recreate|unbind), or a live-role re-point
61
+ * (`roles.<alias>=<grp_id>`). `--bind-to` consents an added-knowledge-doc name
62
+ * collision; `--apply-all` accepts the package's version for every
63
+ * consent-requiring knowledge doc (overwriting local edits).
278
64
  */
279
65
  export declare function packageUpgrade(client: LoticsClient, args: {
280
66
  app_id: string;
@@ -293,50 +79,28 @@ export declare function packageShow(client: LoticsClient, args: {
293
79
  package_id: string;
294
80
  }): Promise<void>;
295
81
  /**
296
- * Route an app-install upgrade's `--resolve` entries into the core-artifact
297
- * bucket vs the bundled-knowledge bucket. `--resolve` is shared between the two
298
- * finding classes, so each key is matched against the preview: a key that names a
299
- * bundled knowledge doc resolves that doc (its value validated against the doc's
300
- * change class here the app path has no separate knowledge-only parser);
301
- * anything else stays a core resolution (a `<namespace>.<alias>` drift, a
302
- * `<kind>.<alias>` modified core, or a key the server validates). A key that is
303
- * BOTH a knowledge alias and a core-artifact key is ambiguous — throw rather than
304
- * guess which the operator meant.
305
- */
306
- export declare function routeAppUpgradeResolve(resolve: string[], knowledgeEntries: KnowledgeUpgradeEntry[], coreKeys: ReadonlySet<string>): {
307
- coreResolve: string[];
308
- knowledgeResolutions: Record<string, KnowledgeResolution>;
309
- };
310
- /**
311
- * Route a STANDALONE content upgrade's shared `--resolve <alias>=<value>` flags
312
- * into the knowledge vs templates buckets by matching each alias against the two
313
- * preview namespaces. A doc alias takes apply|keep|archive|recreate|unbind; a
314
- * template alias takes revert|keep. An alias present in BOTH namespaces is
315
- * ambiguous → loud error (no guess). An alias in NEITHER → error. The value is
316
- * validated against the namespace it routes to. Exported for testing.
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.
317
88
  */
318
- export declare function routeContentResolveFlags(resolve: string[], knowledgeAliases: ReadonlySet<string>, templateAliases: ReadonlySet<string>): {
319
- knowledge: Record<string, KnowledgeResolution>;
320
- templates: Record<string, ModificationResolution>;
321
- };
89
+ export declare function redirectContentPciForm(client: LoticsClient, pci_id: string, verb: "upgrade" | "uninstall"): Promise<never>;
322
90
  /**
323
- * Preview-then-apply a STANDALONE content installation upgrade knowledge docs
324
- * AND document templates behind one review gate. Prints the per-alias plan;
325
- * refuses (exit 1, with the exact `--resolve` syntax) while any consent-requiring
326
- * entry lacks a resolutiona modified knowledge change/removal or drift, or a
327
- * locally-edited changed template. `--apply-all` auto-resolves EVERY consent entry
328
- * by accepting the package's version (knowledge changed→apply, removed→archive,
329
- * drifted→recreate; template→revert) — an explicit bulk "take upstream" that
330
- * discards local edits. `--resolve <alias>=<value>` and `--bind-to <alias>=<kdc_id>`
331
- * resolve entries individually (`--resolve` is routed to the right namespace by
332
- * matching the alias against the preview).
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 idthe 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.
333
98
  */
334
- export declare function packageUpgradeKnowledge(client: LoticsClient, args: {
335
- installation_id: string;
99
+ export declare function packageUpgradeByPackageId(client: LoticsClient, args: {
100
+ package_id: string;
336
101
  version?: number;
337
- /** Raw `--resolve <alias>=<value>` flags, routed to knowledge/templates after the preview. */
338
102
  resolve: string[];
339
- bind_to: Record<string, string>;
103
+ bindTo: string[];
340
104
  applyAll: boolean;
341
105
  }): Promise<void>;
342
106
  /** Parse repeated `--bind-to alias=kdc_id` flags into an alias → doc-id consent map. */
@@ -350,9 +114,11 @@ export declare function packageInstall(client: LoticsClient, args: {
350
114
  config?: Record<string, string | number | boolean>;
351
115
  }): Promise<void>;
352
116
  /**
353
- * `lotics package uninstall <app_id|pci_id>` — ONE command over both installation
354
- * kinds, dispatched by the id form (mirrors `package upgrade`):
355
- * - 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
356
122
  * `--keep-content`) archives its package-bound docs AND templates, listing each
357
123
  * archived id.
358
124
  * - anything else (an `app_id`) → an APP installation: archives its workflow
@@ -366,10 +132,12 @@ export declare function packageUninstall(client: LoticsClient, args: {
366
132
  archive_tables: boolean;
367
133
  }): Promise<void>;
368
134
  /**
369
- * `lotics package list-content` — list the selected workspace's package-managed
370
- * content installations (standalone `pci_` corpora + app-bundled ones), each
371
- * with its registry status. The read surface that surfaces a standalone `pci_` id
372
- * for `upgrade` / `uninstall` (install prints it once; nothing else did before).
135
+ * `lotics package list-content` — list the selected workspace's STANDALONE
136
+ * content installations (an app-bundled corpus rides its app's
137
+ * `binding.knowledge` and shows on the Apps surface instead), each with its
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).
373
141
  */
374
142
  export declare function packageListContent(client: LoticsClient): Promise<void>;
375
143
  export declare function packageEject(client: LoticsClient, args: {
@@ -387,38 +155,59 @@ export declare function packageConfig(client: LoticsClient, args: {
387
155
  sets: string[];
388
156
  }): Promise<void>;
389
157
  /**
390
- * `lotics package retire <package_id> [--undo]` — retire (or un-retire) a
391
- * registry package. Owner-org admin-only.
158
+ * `lotics app unpublish <app_id|package_id> [--undo]` — take a published package
159
+ * off the shelf (or `--undo` restore it): new installs refuse it and it hides
160
+ * from other orgs, while existing installations keep working and may still
161
+ * upgrade. Given an app id (an installation of the package) it resolves the
162
+ * package from the app; a package id targets it directly. Owner-org admin-only.
392
163
  */
393
- export declare function packageRetire(client: LoticsClient, args: {
394
- package_id: string;
164
+ export declare function appUnpublish(client: LoticsClient, args: {
165
+ id: string;
395
166
  undo: boolean;
396
167
  }): Promise<void>;
397
- export declare function packageExtract(client: LoticsClient, args: {
398
- app_id: string;
399
- targetPath?: string;
400
- }): Promise<void>;
401
168
  /**
402
- * `lotics package adopt <app_id> [path]` bind the published package project
403
- * onto the origin app (docs/packages.md § Promotion). Reads the project
404
- * manifest (must be published refuses otherwise), resolves the version
405
- * (`--version N` else the manifest's), and reads `.lotics/adopt_binding.json`,
406
- * REFUSING a pin recorded for a different app. On success the app becomes
407
- * installation #1 and is upgradeable again; a server ConflictError (naming the
408
- * unfaithful aliases) surfaces verbatim.
409
- */
410
- export declare function packageAdopt(client: LoticsClient, args: {
411
- app_id: string;
412
- version?: number;
169
+ * `lotics app publish [app_id|.] [--rename old=new ...] [-m <changelog>] [--yes]`
170
+ * FIRST-RELEASE a bespoke app as a package (docs/packages.md § Promotion). Nothing
171
+ * starts as a package. Mirrors `app release`'s preview→apply UX: it first shows the
172
+ * dry-run preview (GET, no writes) the package name, the auto-minted RENAMABLE
173
+ * aliases (the exact `--rename` keys, so v1's frozen aliases are inspected first,
174
+ * never a blind publish), and the extract findings then APPLIES only with
175
+ * `--yes` (else exits 1 with the re-run hint). On apply the server extracts the
176
+ * contract, creates the registry package, publishes v1 from the DEPLOYED source +
177
+ * dist, and pins the origin as installation #1. `--rename old=new` fixes an
178
+ * auto-minted alias before v1 freezes it; an `error` finding blocks the apply. An
179
+ * already-linked app releases with `lotics app release` instead. The app id is the
180
+ * positional (`.`/omitted → resolved from the local app project manifest).
181
+ */
182
+ export declare function appPublish(client: LoticsClient, args: {
183
+ app_id?: string;
184
+ renames: string[];
185
+ changelog?: string;
186
+ yes: boolean;
413
187
  projectDir?: string;
414
188
  }): Promise<void>;
415
189
  /**
416
- * `lotics package fleet-upgrade <package_id> [--version N]` — bring every
417
- * installation of the package across the caller's org to the target version.
418
- * Hands-off applies only where the preview is clean; skipped/failed
419
- * installations are reported per line and the process exits 1 so a release
420
- * script can gate on "fleet fully current".
190
+ * `lotics app release [app_id|.] -m <changelog> [--yes]` — snapshot an
191
+ * adopted/installed origin app into its next registry version (docs/packages.md
192
+ * § Promotion). The origin is the permanent working copy; a release binding-aware-
193
+ * extracts it (stable aliases), repackages its DEPLOYED source + dist as the
194
+ * bundle, publishes the next version, and re-pins the origin. Prints the preview
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).
421
204
  */
205
+ export declare function appRelease(client: LoticsClient, args: {
206
+ app_id?: string;
207
+ changelog: string;
208
+ yes: boolean;
209
+ projectDir?: string;
210
+ }): Promise<void>;
422
211
  /**
423
212
  * `lotics package yank <package_id> <version> [--undo]` — mark a published
424
213
  * version uninstallable (or restore it). New installs/upgrades/adopts refuse a
@@ -430,8 +219,3 @@ export declare function packageYank(client: LoticsClient, args: {
430
219
  version: number;
431
220
  undo: boolean;
432
221
  }): Promise<void>;
433
- export declare function packageFleetUpgrade(client: LoticsClient, args: {
434
- package_id: string;
435
- version?: number;
436
- }): Promise<void>;
437
- export {};