@lotics/cli 0.75.0 → 0.76.1

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,20 +1,74 @@
1
1
  import { LoticsClient, type PackageBinding, type ExtractFinding } from "./client.js";
2
+ import { type KnowledgeUpgradeEntry, type KnowledgeResolution, type ModificationResolution } from "@lotics/shared/schemas/packages";
2
3
  /** One dev workspace's pinned installation of this package (manifest bookkeeping). */
3
4
  interface PackageDevInstallation {
4
5
  app_id: string;
5
6
  version: number;
6
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
+ }
7
41
  /**
8
42
  * The `package.json#lotics.package` block of a package project. `id` is null
9
43
  * until the first publish (which creates the registry package); `version` tracks
10
44
  * the latest version this project has published; `dev` maps a dev workspace id to
11
45
  * the installation it scaffold-syncs into.
12
46
  */
47
+ /** A package project's kind — mirrors the registry `packages.kind` (immutable after create). */
48
+ export type PackageKind = "app" | "content";
13
49
  interface PackageManifest {
14
50
  id: string | null;
15
51
  name: string;
16
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;
17
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[];
18
72
  dev: Record<string, PackageDevInstallation>;
19
73
  }
20
74
  interface PackageProjectFile {
@@ -58,6 +112,7 @@ export declare function parseAdoptBindingFile(raw: unknown, expectedAppId: strin
58
112
  app_id: string;
59
113
  workspace_id: string;
60
114
  binding: PackageBinding;
115
+ knowledge_binding: Record<string, string>;
61
116
  };
62
117
  /**
63
118
  * Render an extraction report grouped by severity (errors, then warnings, then
@@ -70,6 +125,48 @@ export declare function formatExtractReport(report: ExtractFinding[]): {
70
125
  lines: string[];
71
126
  hasError: boolean;
72
127
  };
128
+ /**
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>;
73
170
  /**
74
171
  * Copy the project's source tree into `sourceStage` with explicit TOP-LEVEL
75
172
  * excludes, writing a sanitized `package.json` in place of the on-disk one.
@@ -82,15 +179,16 @@ export declare function stagePackageSource(projectDir: string, sourceStage: stri
82
179
  /** The minimal, valid starting contract a `package new` scaffold ships. */
83
180
  export declare function starterContract(name: string): Record<string, unknown>;
84
181
  /**
85
- * `lotics package new <name> [path]` — scaffold a package project. Reuses the
86
- * app starter (Vite+React+TS) for the code surface, swaps its app manifest for a
87
- * package manifest, and adds a starter `contract.json`. The project publishes
88
- * with `lotics package publish` and runs against a dev workspace with
89
- * `lotics package dev`.
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`.
90
187
  */
91
188
  export declare function packageNew(args: {
92
189
  name: string;
93
190
  targetPath?: string;
191
+ kind?: PackageKind;
94
192
  }): Promise<void>;
95
193
  /**
96
194
  * `lotics package build [path]` — build the publishable bundle and write it to
@@ -167,41 +265,142 @@ export declare function packageDoctor(client: LoticsClient, args: {
167
265
  app_id?: string;
168
266
  }): Promise<void>;
169
267
  /**
170
- * Preview-then-apply upgrade. Prints the additive plan + informational
171
- * removals; refuses (exit 1, with the exact --resolve syntax) while any
172
- * binding drift lacks a resolution.
268
+ * Preview-then-apply an app-installation upgrade. Prints the additive plan +
269
+ * informational removals + any bundled-knowledge changes; refuses (exit 1, with
270
+ * the exact --resolve syntax) while any binding drift, modified core artifact, or
271
+ * consent-requiring bundled-knowledge doc lacks a resolution.
272
+ *
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).
173
278
  */
174
279
  export declare function packageUpgrade(client: LoticsClient, args: {
175
280
  app_id: string;
176
281
  version?: number;
177
- resolutions: Record<string, UpgradeResolutionValue>;
282
+ resolve: string[];
283
+ bindTo: string[];
284
+ applyAll: boolean;
285
+ }): Promise<void>;
286
+ /**
287
+ * `lotics package show <package_id>` — registry metadata + version history
288
+ * (trust badge, retirement, per-version channel/yank/changelog). The read
289
+ * surface for "what is this package and what shipped when". Kind-agnostic — a
290
+ * content package shows here the same way.
291
+ */
292
+ export declare function packageShow(client: LoticsClient, args: {
293
+ package_id: string;
294
+ }): Promise<void>;
295
+ /**
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.
317
+ */
318
+ export declare function routeContentResolveFlags(resolve: string[], knowledgeAliases: ReadonlySet<string>, templateAliases: ReadonlySet<string>): {
319
+ knowledge: Record<string, KnowledgeResolution>;
320
+ templates: Record<string, ModificationResolution>;
321
+ };
322
+ /**
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 resolution — a 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).
333
+ */
334
+ export declare function packageUpgradeKnowledge(client: LoticsClient, args: {
335
+ installation_id: string;
336
+ version?: number;
337
+ /** Raw `--resolve <alias>=<value>` flags, routed to knowledge/templates after the preview. */
338
+ resolve: string[];
339
+ bind_to: Record<string, string>;
340
+ applyAll: boolean;
178
341
  }): Promise<void>;
342
+ /** Parse repeated `--bind-to alias=kdc_id` flags into an alias → doc-id consent map. */
343
+ export declare function parseBindToFlags(bindTo: string[]): Record<string, string>;
179
344
  export declare function packageInstall(client: LoticsClient, args: {
180
345
  package_id: string;
181
346
  version?: number;
347
+ /** Content-kind only: adopt a same-named workspace doc on a knowledge collision. */
348
+ bind_to?: Record<string, string>;
349
+ /** App-kind only: per-knob config overrides applied over the contract defaults. */
350
+ config?: Record<string, string | number | boolean>;
182
351
  }): Promise<void>;
352
+ /**
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
356
+ * `--keep-content`) archives its package-bound docs AND templates, listing each
357
+ * archived id.
358
+ * - anything else (an `app_id`) → an APP installation: archives its workflow
359
+ * artifacts and — with `--archive-tables` — the scaffolded entity tables
360
+ * (provenance- + reference-gated server-side).
361
+ * A flag used on the wrong path is a loud error, never silently ignored.
362
+ */
363
+ export declare function packageUninstall(client: LoticsClient, args: {
364
+ id: string;
365
+ keep_content: boolean;
366
+ archive_tables: boolean;
367
+ }): Promise<void>;
368
+ /**
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).
373
+ */
374
+ export declare function packageListContent(client: LoticsClient): Promise<void>;
183
375
  export declare function packageEject(client: LoticsClient, args: {
184
376
  app_id: string;
185
377
  }): Promise<void>;
378
+ /** `--config key=value` (install): inferred types, server-validated. */
379
+ export declare function parseInstallConfigFlags(config: string[]): Record<string, string | number | boolean>;
380
+ /**
381
+ * `lotics package config <app_id>` — show the installation's effective config;
382
+ * with `--set key=value` (repeatable) partial-merge edits, each value parsed by
383
+ * the knob's current type. No `--set` prints the values.
384
+ */
385
+ export declare function packageConfig(client: LoticsClient, args: {
386
+ app_id: string;
387
+ sets: string[];
388
+ }): Promise<void>;
186
389
  /**
187
- * `lotics package extract <app_id> [path]` — promote a bespoke app to a DRAFT
188
- * package project (docs/app_packages.md § Promotion). Calls the extract read,
189
- * prints the findings report grouped by severity, then ALWAYS emits the draft
190
- * project (a broken contract is still the reviewable starting point): the app's
191
- * current source archive (same mechanics as `lotics app pull`) with the app
192
- * manifest swapped for an unpublished package manifest, `contract.json`, the
193
- * file-backed templates staged at their `bytes_ref` paths, and
194
- * `.lotics/adopt_binding.json` (the origin pin the `adopt` step reads back).
195
- * Exits non-zero when any `error` finding exists — the draft is written, but
196
- * publish re-validates and nothing should ship unreviewed.
390
+ * `lotics package retire <package_id> [--undo]` — retire (or un-retire) a
391
+ * registry package. Owner-org admin-only.
197
392
  */
393
+ export declare function packageRetire(client: LoticsClient, args: {
394
+ package_id: string;
395
+ undo: boolean;
396
+ }): Promise<void>;
198
397
  export declare function packageExtract(client: LoticsClient, args: {
199
398
  app_id: string;
200
399
  targetPath?: string;
201
400
  }): Promise<void>;
202
401
  /**
203
402
  * `lotics package adopt <app_id> [path]` — bind the published package project
204
- * onto the origin app (docs/app_packages.md § Promotion). Reads the project
403
+ * onto the origin app (docs/packages.md § Promotion). Reads the project
205
404
  * manifest (must be published — refuses otherwise), resolves the version
206
405
  * (`--version N` else the manifest's), and reads `.lotics/adopt_binding.json`,
207
406
  * REFUSING a pin recorded for a different app. On success the app becomes