@lotics/cli 0.76.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,28 +265,113 @@ 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;
178
285
  }): Promise<void>;
179
286
  /**
180
287
  * `lotics package show <package_id>` — registry metadata + version history
181
288
  * (trust badge, retirement, per-version channel/yank/changelog). The read
182
- * surface for "what is this package and what shipped when".
289
+ * surface for "what is this package and what shipped when". Kind-agnostic — a
290
+ * content package shows here the same way.
183
291
  */
184
292
  export declare function packageShow(client: LoticsClient, args: {
185
293
  package_id: string;
186
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;
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>;
187
344
  export declare function packageInstall(client: LoticsClient, args: {
188
345
  package_id: string;
189
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. */
190
350
  config?: Record<string, string | number | boolean>;
191
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>;
192
375
  export declare function packageEject(client: LoticsClient, args: {
193
376
  app_id: string;
194
377
  }): Promise<void>;
@@ -203,15 +386,6 @@ export declare function packageConfig(client: LoticsClient, args: {
203
386
  app_id: string;
204
387
  sets: string[];
205
388
  }): 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
389
  /**
216
390
  * `lotics package retire <package_id> [--undo]` — retire (or un-retire) a
217
391
  * registry package. Owner-org admin-only.
@@ -220,25 +394,13 @@ export declare function packageRetire(client: LoticsClient, args: {
220
394
  package_id: string;
221
395
  undo: boolean;
222
396
  }): Promise<void>;
223
- /**
224
- * `lotics package extract <app_id> [path]` — promote a bespoke app to a DRAFT
225
- * package project (docs/app_packages.md § Promotion). Calls the extract read,
226
- * prints the findings report grouped by severity, then ALWAYS emits the draft
227
- * project (a broken contract is still the reviewable starting point): the app's
228
- * current source archive (same mechanics as `lotics app pull`) with the app
229
- * manifest swapped for an unpublished package manifest, `contract.json`, the
230
- * file-backed templates staged at their `bytes_ref` paths, and
231
- * `.lotics/adopt_binding.json` (the origin pin the `adopt` step reads back).
232
- * Exits non-zero when any `error` finding exists — the draft is written, but
233
- * publish re-validates and nothing should ship unreviewed.
234
- */
235
397
  export declare function packageExtract(client: LoticsClient, args: {
236
398
  app_id: string;
237
399
  targetPath?: string;
238
400
  }): Promise<void>;
239
401
  /**
240
402
  * `lotics package adopt <app_id> [path]` — bind the published package project
241
- * onto the origin app (docs/app_packages.md § Promotion). Reads the project
403
+ * onto the origin app (docs/packages.md § Promotion). Reads the project
242
404
  * manifest (must be published — refuses otherwise), resolves the version
243
405
  * (`--version N` else the manifest's), and reads `.lotics/adopt_binding.json`,
244
406
  * REFUSING a pin recorded for a different app. On success the app becomes