@lotics/cli 0.71.0 → 0.74.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 +38 -0
- package/dist/app_commands.d.ts +13 -0
- package/dist/app_commands.js +3 -3
- package/dist/args.d.ts +17 -0
- package/dist/args.js +35 -2
- package/dist/args.test.js +49 -0
- package/dist/cli.js +235 -3
- package/dist/client.d.ts +321 -0
- package/dist/client.js +164 -0
- package/dist/dev/rpc_handler.d.ts +1 -1
- package/dist/dev/rpc_handler.js +10 -2
- package/dist/dev/rpc_handler.test.js +24 -6
- package/dist/generate_app_fields.d.ts +2 -0
- package/dist/generate_app_fields.js +1 -1
- package/dist/generate_package_fields.d.ts +48 -0
- package/dist/generate_package_fields.js +104 -0
- package/dist/generate_package_fields.test.d.ts +1 -0
- package/dist/generate_package_fields.test.js +51 -0
- package/dist/package_commands.d.ts +227 -0
- package/dist/package_commands.js +957 -0
- package/dist/package_commands.test.d.ts +1 -0
- package/dist/package_commands.test.js +303 -0
- package/dist/src/cli.js +1420 -138
- package/dist/starter_template.d.ts +1 -1
- package/dist/starter_template.js +10 -4
- package/package.json +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegen: emit a RUNTIME `.lotics/app_fields.ts` for a PACKAGE project from
|
|
3
|
+
* its `contract.json`.
|
|
4
|
+
*
|
|
5
|
+
* The bespoke twin (`generate_app_fields.ts`) bakes this workspace's concrete
|
|
6
|
+
* `fld_…`/`opt_…` ids at authoring time — correct when source and workspace
|
|
7
|
+
* co-live, fundamentally wrong for a package (one bundle, many workspaces,
|
|
8
|
+
* different ids in each). A package project instead resolves the SAME `F` /
|
|
9
|
+
* `OPT` surface at MODULE LOAD from the installation's binding via the SDK's
|
|
10
|
+
* `getAppBinding()` (the `binding` RPC op), using top-level await — the ESM
|
|
11
|
+
* graph waits for the binding before any importer evaluates, so
|
|
12
|
+
* `F.TASKS.title` is a plain string everywhere, including module-top-level
|
|
13
|
+
* constants. Extracted bespoke sources therefore compile unchanged: same
|
|
14
|
+
* import path, same shapes, same alias naming (contract aliases derive from
|
|
15
|
+
* the same display names the bespoke codegen slugifies).
|
|
16
|
+
*
|
|
17
|
+
* A missing alias fails LOUD at boot (the binding is adopt/install-verified
|
|
18
|
+
* complete, so a miss means the generated file is stale relative to the
|
|
19
|
+
* installed contract version) — never a silent undefined key in a write.
|
|
20
|
+
*
|
|
21
|
+
* Requires the app build to target es2022+ (the starter's `build.target`) —
|
|
22
|
+
* top-level await does not exist below it.
|
|
23
|
+
*/
|
|
24
|
+
/** The subset of a contract this generator reads (structural, not zod-validated —
|
|
25
|
+
* publish is the validating boundary; codegen must work on drafts too). */
|
|
26
|
+
export interface PackageContractShape {
|
|
27
|
+
entities?: Array<{
|
|
28
|
+
alias: string;
|
|
29
|
+
fields?: Array<{
|
|
30
|
+
alias: string;
|
|
31
|
+
options?: Array<{
|
|
32
|
+
alias: string;
|
|
33
|
+
}>;
|
|
34
|
+
}>;
|
|
35
|
+
}>;
|
|
36
|
+
roles?: Array<{
|
|
37
|
+
alias: string;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generate the full package `.lotics/app_fields.ts` source. Valid contract
|
|
42
|
+
* aliases are slug-grammar (`^[a-z][a-z0-9_]*$`) and emit as bare identifiers
|
|
43
|
+
* — but this also runs on unvalidated DRAFTS (dev/sync pre-publish), so every
|
|
44
|
+
* key goes through `propKey`, which quotes anything that isn't a valid
|
|
45
|
+
* identifier instead of emitting broken TypeScript into a "DO NOT EDIT" file.
|
|
46
|
+
* Pure; same contract → same bytes.
|
|
47
|
+
*/
|
|
48
|
+
export declare function generatePackageAppFields(contract: PackageContractShape): string;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegen: emit a RUNTIME `.lotics/app_fields.ts` for a PACKAGE project from
|
|
3
|
+
* its `contract.json`.
|
|
4
|
+
*
|
|
5
|
+
* The bespoke twin (`generate_app_fields.ts`) bakes this workspace's concrete
|
|
6
|
+
* `fld_…`/`opt_…` ids at authoring time — correct when source and workspace
|
|
7
|
+
* co-live, fundamentally wrong for a package (one bundle, many workspaces,
|
|
8
|
+
* different ids in each). A package project instead resolves the SAME `F` /
|
|
9
|
+
* `OPT` surface at MODULE LOAD from the installation's binding via the SDK's
|
|
10
|
+
* `getAppBinding()` (the `binding` RPC op), using top-level await — the ESM
|
|
11
|
+
* graph waits for the binding before any importer evaluates, so
|
|
12
|
+
* `F.TASKS.title` is a plain string everywhere, including module-top-level
|
|
13
|
+
* constants. Extracted bespoke sources therefore compile unchanged: same
|
|
14
|
+
* import path, same shapes, same alias naming (contract aliases derive from
|
|
15
|
+
* the same display names the bespoke codegen slugifies).
|
|
16
|
+
*
|
|
17
|
+
* A missing alias fails LOUD at boot (the binding is adopt/install-verified
|
|
18
|
+
* complete, so a miss means the generated file is stale relative to the
|
|
19
|
+
* installed contract version) — never a silent undefined key in a write.
|
|
20
|
+
*
|
|
21
|
+
* Requires the app build to target es2022+ (the starter's `build.target`) —
|
|
22
|
+
* top-level await does not exist below it.
|
|
23
|
+
*/
|
|
24
|
+
import { propKey } from "./generate_app_fields.js";
|
|
25
|
+
const HEADER = `// Auto-generated by 'lotics package new/extract/dev/sync' from contract.json.
|
|
26
|
+
// DO NOT EDIT — regenerated whenever the contract changes.
|
|
27
|
+
//
|
|
28
|
+
// Package apps resolve F/OPT/ROLE at MODULE LOAD from the installation's
|
|
29
|
+
// binding (contract alias → THIS workspace's concrete id) via the SDK's
|
|
30
|
+
// \`binding\` RPC. Top-level await: the module graph waits for the binding
|
|
31
|
+
// before any importer evaluates, so every entry is a plain string.
|
|
32
|
+
import { getAppBinding } from "@lotics/app-sdk";
|
|
33
|
+
|
|
34
|
+
const binding = await getAppBinding();
|
|
35
|
+
|
|
36
|
+
function bound(map: Record<string, string>, key: string, kind: string): string {
|
|
37
|
+
const id = map[key];
|
|
38
|
+
if (id === undefined) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
\`app_fields: \${kind} "\${key}" is not in this installation's binding — \` +
|
|
41
|
+
\`the generated app_fields.ts is stale relative to the installed contract version.\`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return id;
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
/**
|
|
48
|
+
* Generate the full package `.lotics/app_fields.ts` source. Valid contract
|
|
49
|
+
* aliases are slug-grammar (`^[a-z][a-z0-9_]*$`) and emit as bare identifiers
|
|
50
|
+
* — but this also runs on unvalidated DRAFTS (dev/sync pre-publish), so every
|
|
51
|
+
* key goes through `propKey`, which quotes anything that isn't a valid
|
|
52
|
+
* identifier instead of emitting broken TypeScript into a "DO NOT EDIT" file.
|
|
53
|
+
* Pure; same contract → same bytes.
|
|
54
|
+
*/
|
|
55
|
+
export function generatePackageAppFields(contract) {
|
|
56
|
+
const entities = contract.entities ?? [];
|
|
57
|
+
const roles = contract.roles ?? [];
|
|
58
|
+
const fieldBlocks = [];
|
|
59
|
+
for (const entity of entities) {
|
|
60
|
+
const lines = (entity.fields ?? []).map((field) => ` ${propKey(field.alias)}: bound(binding.fields, ${JSON.stringify(`${entity.alias}.${field.alias}`)}, "field"),`);
|
|
61
|
+
if (lines.length === 0)
|
|
62
|
+
continue;
|
|
63
|
+
fieldBlocks.push(` ${propKey(entity.alias.toUpperCase())}: {\n${lines.join("\n")}\n },`);
|
|
64
|
+
}
|
|
65
|
+
const optionBlocks = [];
|
|
66
|
+
for (const entity of entities) {
|
|
67
|
+
const perField = [];
|
|
68
|
+
for (const field of entity.fields ?? []) {
|
|
69
|
+
const options = field.options ?? [];
|
|
70
|
+
if (options.length === 0)
|
|
71
|
+
continue;
|
|
72
|
+
const lines = options.map((option) => ` ${propKey(option.alias)}: bound(binding.options, ${JSON.stringify(`${entity.alias}.${field.alias}:${option.alias}`)}, "option"),`);
|
|
73
|
+
perField.push(` ${propKey(field.alias)}: {\n${lines.join("\n")}\n },`);
|
|
74
|
+
}
|
|
75
|
+
if (perField.length > 0) {
|
|
76
|
+
optionBlocks.push(` ${propKey(entity.alias.toUpperCase())}: {\n${perField.join("\n")}\n },`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const fMap = fieldBlocks.length > 0
|
|
80
|
+
? `export const F = {\n${fieldBlocks.join("\n")}\n} as const;`
|
|
81
|
+
: `export const F = {} as const;`;
|
|
82
|
+
const optMap = optionBlocks.length > 0
|
|
83
|
+
? `export const OPT = {\n${optionBlocks.join("\n")}\n} as const;`
|
|
84
|
+
: `export const OPT = {} as const;`;
|
|
85
|
+
const roleMap = roles.length > 0
|
|
86
|
+
? `export const ROLE = {\n${roles
|
|
87
|
+
.map((role) => ` ${propKey(role.alias)}: bound(binding.roles, ${JSON.stringify(role.alias)}, "role"),`)
|
|
88
|
+
.join("\n")}\n} as const;`
|
|
89
|
+
: `export const ROLE = {} as const;`;
|
|
90
|
+
return `${HEADER}
|
|
91
|
+
${fMap}
|
|
92
|
+
|
|
93
|
+
${optMap}
|
|
94
|
+
|
|
95
|
+
${roleMap}
|
|
96
|
+
|
|
97
|
+
/** Field-id alias map: \`F[<ENTITY>][<field>]\` is this installation's \`fld_…\` id. */
|
|
98
|
+
export type AppFields = typeof F;
|
|
99
|
+
/** Select-option alias map: \`OPT[<ENTITY>][<field>][<option>]\` is this installation's \`opt_…\` id. */
|
|
100
|
+
export type AppOptions = typeof OPT;
|
|
101
|
+
/** Role alias map: \`ROLE[<role>]\` is this installation's \`grp_…\` id. */
|
|
102
|
+
export type AppRoles = typeof ROLE;
|
|
103
|
+
`;
|
|
104
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
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" }],
|
|
18
|
+
};
|
|
19
|
+
describe("generatePackageAppFields", () => {
|
|
20
|
+
it("emits runtime-resolved F/OPT/ROLE keyed by contract aliases", () => {
|
|
21
|
+
const src = generatePackageAppFields(contract);
|
|
22
|
+
// Resolves through the SDK binding at module load (top-level await).
|
|
23
|
+
expect(src).toContain('import { getAppBinding } from "@lotics/app-sdk";');
|
|
24
|
+
expect(src).toContain("const binding = await getAppBinding();");
|
|
25
|
+
// F: uppercased entity alias, fully-qualified binding keys.
|
|
26
|
+
expect(src).toContain('title: bound(binding.fields, "tasks.title", "field")');
|
|
27
|
+
expect(src).toContain('name: bound(binding.fields, "projects.name", "field")');
|
|
28
|
+
expect(src).toMatch(/TASKS: \{/);
|
|
29
|
+
expect(src).toMatch(/PROJECTS: \{/);
|
|
30
|
+
// OPT: qualified entity.field:opt keys; option-less fields absent.
|
|
31
|
+
expect(src).toContain('to_do: bound(binding.options, "tasks.status:to_do", "option")');
|
|
32
|
+
expect(src).toContain('done: bound(binding.options, "tasks.status:done", "option")');
|
|
33
|
+
expect(src).not.toContain('"tasks.title:');
|
|
34
|
+
// ROLE map from contract roles.
|
|
35
|
+
expect(src).toContain('approver: bound(binding.roles, "approver", "role")');
|
|
36
|
+
// No concrete id in any VALUE position — the module is workspace-agnostic.
|
|
37
|
+
// (Doc comments legitimately name the id prefixes, so match quoted ids.)
|
|
38
|
+
expect(src).not.toMatch(/"(fld|opt|tbl|grp)_/);
|
|
39
|
+
});
|
|
40
|
+
it("emits valid empty maps for an empty contract", () => {
|
|
41
|
+
const src = generatePackageAppFields({});
|
|
42
|
+
expect(src).toContain("export const F = {} as const;");
|
|
43
|
+
expect(src).toContain("export const OPT = {} as const;");
|
|
44
|
+
expect(src).toContain("export const ROLE = {} as const;");
|
|
45
|
+
// Still imports the SDK so the module shape is uniform.
|
|
46
|
+
expect(src).toContain("const binding = await getAppBinding();");
|
|
47
|
+
});
|
|
48
|
+
it("is deterministic — same contract, same bytes", () => {
|
|
49
|
+
expect(generatePackageAppFields(contract)).toBe(generatePackageAppFields(contract));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { LoticsClient, type PackageBinding, type ExtractFinding } from "./client.js";
|
|
2
|
+
/** One dev workspace's pinned installation of this package (manifest bookkeeping). */
|
|
3
|
+
interface PackageDevInstallation {
|
|
4
|
+
app_id: string;
|
|
5
|
+
version: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The `package.json#lotics.package` block of a package project. `id` is null
|
|
9
|
+
* until the first publish (which creates the registry package); `version` tracks
|
|
10
|
+
* the latest version this project has published; `dev` maps a dev workspace id to
|
|
11
|
+
* the installation it scaffold-syncs into.
|
|
12
|
+
*/
|
|
13
|
+
interface PackageManifest {
|
|
14
|
+
id: string | null;
|
|
15
|
+
name: string;
|
|
16
|
+
description: string | null;
|
|
17
|
+
version: number | null;
|
|
18
|
+
dev: Record<string, PackageDevInstallation>;
|
|
19
|
+
}
|
|
20
|
+
interface PackageProjectFile {
|
|
21
|
+
/** Parsed package.json, carrying the `lotics.package` manifest under `lotics`. */
|
|
22
|
+
pkgJson: Record<string, unknown>;
|
|
23
|
+
manifest: PackageManifest;
|
|
24
|
+
}
|
|
25
|
+
/** Read the package project's manifest, failing loud when the dir isn't one. */
|
|
26
|
+
export declare function readPackageProject(projectDir: string): PackageProjectFile;
|
|
27
|
+
/** Persist an updated manifest back into the project's package.json (atomic write). */
|
|
28
|
+
export declare function writePackageManifest(projectDir: string, project: PackageProjectFile): void;
|
|
29
|
+
/**
|
|
30
|
+
* The package.json to ship INSIDE `source.tar.gz`: the on-disk manifest with the
|
|
31
|
+
* author-local `lotics.package.dev` map stripped. `dev` is the author's private
|
|
32
|
+
* dev-workspace → installation bookkeeping; it must never reach a consumer (every
|
|
33
|
+
* install carries the source, and `lotics app pull` ejects it). Returns a
|
|
34
|
+
* sanitized copy — the on-disk package.json is left untouched. `id`/`name`/
|
|
35
|
+
* `description`/`version` are the package's stable identity and stay.
|
|
36
|
+
*/
|
|
37
|
+
export declare function sanitizePackageJsonForSource(pkgJson: Record<string, unknown>): Record<string, unknown>;
|
|
38
|
+
/**
|
|
39
|
+
* Transform an app project's package.json (the source archive `lotics app pull`
|
|
40
|
+
* downloads, carrying the `lotics.app_id`/`workspace_id` app manifest) into a
|
|
41
|
+
* package project's `PackageProjectFile`: the app manifest is stripped ENTIRELY
|
|
42
|
+
* and a fresh, unpublished `lotics.package` manifest (id/version null) is
|
|
43
|
+
* grafted. Pure — returns a new value, never mutates the input;
|
|
44
|
+
* `writePackageManifest` writes it (atomic). The bespoke→package promotion's
|
|
45
|
+
* manifest inversion.
|
|
46
|
+
*/
|
|
47
|
+
export declare function draftPackageProjectFromApp(appPkgJson: Record<string, unknown>, args: {
|
|
48
|
+
name: string;
|
|
49
|
+
description: string | null;
|
|
50
|
+
}): PackageProjectFile;
|
|
51
|
+
/**
|
|
52
|
+
* Parse + validate `.lotics/adopt_binding.json` against the app being adopted.
|
|
53
|
+
* REFUSES a pin recorded for a different app: a binding maps ONE workspace's
|
|
54
|
+
* concrete ids, so replaying it onto another app would bind the wrong objects.
|
|
55
|
+
* Pure; the CLI never interprets the binding, only round-trips it to the server.
|
|
56
|
+
*/
|
|
57
|
+
export declare function parseAdoptBindingFile(raw: unknown, expectedAppId: string): {
|
|
58
|
+
app_id: string;
|
|
59
|
+
workspace_id: string;
|
|
60
|
+
binding: PackageBinding;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Render an extraction report grouped by severity (errors, then warnings, then
|
|
64
|
+
* info), one ` [<severity>] <area>: <message>` line each, and classify whether
|
|
65
|
+
* any `error` finding is present. An `error` ⇒ the draft is not publishable
|
|
66
|
+
* as-is, so `lotics package extract` exits non-zero. Pure — the command prints
|
|
67
|
+
* `lines` to stderr and gates on `hasError`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function formatExtractReport(report: ExtractFinding[]): {
|
|
70
|
+
lines: string[];
|
|
71
|
+
hasError: boolean;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Copy the project's source tree into `sourceStage` with explicit TOP-LEVEL
|
|
75
|
+
* excludes, writing a sanitized `package.json` in place of the on-disk one.
|
|
76
|
+
* Deliberately not tar `--exclude` flags: those match at any depth (a nested
|
|
77
|
+
* `templates/dist/` would be silently dropped) and GNU tar vs bsdtar (macOS)
|
|
78
|
+
* disagree on `./`-prefixed patterns, which broke the sanitized-package.json
|
|
79
|
+
* graft on macOS.
|
|
80
|
+
*/
|
|
81
|
+
export declare function stagePackageSource(projectDir: string, sourceStage: string): void;
|
|
82
|
+
/** The minimal, valid starting contract a `package new` scaffold ships. */
|
|
83
|
+
export declare function starterContract(name: string): Record<string, unknown>;
|
|
84
|
+
/**
|
|
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`.
|
|
90
|
+
*/
|
|
91
|
+
export declare function packageNew(args: {
|
|
92
|
+
name: string;
|
|
93
|
+
targetPath?: string;
|
|
94
|
+
}): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* `lotics package build [path]` — build the publishable bundle and write it to
|
|
97
|
+
* `bundle.tar.gz` in the project. Mostly a local sanity check / CI artifact;
|
|
98
|
+
* `publish` and `dev`/`sync` build the bundle in memory directly.
|
|
99
|
+
*/
|
|
100
|
+
export declare function packageBuild(args: {
|
|
101
|
+
projectDir?: string;
|
|
102
|
+
}): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* `lotics package publish [path] [-m <changelog>]` — publish a new version.
|
|
105
|
+
*/
|
|
106
|
+
export declare function packagePublish(client: LoticsClient, args: {
|
|
107
|
+
projectDir?: string;
|
|
108
|
+
changelog?: string;
|
|
109
|
+
}): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Fail loud unless `workspace` is a throwaway dev workspace. The dev/sync
|
|
112
|
+
* scaffold path publishes a new version and scaffold-installs package tables into
|
|
113
|
+
* the resolved workspace, so the target MUST be a dev workspace — this mirrors
|
|
114
|
+
* the server-side `package reset` gate so a forgotten `--workspace` (prod
|
|
115
|
+
* selected) can never scaffold package tables into prod. Fails closed: an absent
|
|
116
|
+
* `is_dev` (a server that doesn't yet serialize it) is treated as non-dev.
|
|
117
|
+
*/
|
|
118
|
+
export declare function assertDevWorkspace(workspace: {
|
|
119
|
+
id: string;
|
|
120
|
+
name: string;
|
|
121
|
+
is_dev?: boolean;
|
|
122
|
+
}): void;
|
|
123
|
+
/**
|
|
124
|
+
* `lotics package sync [path]` — re-run the scaffold-sync into the dev workspace
|
|
125
|
+
* (the continuous loop: edit contract → sync additively migrates + re-materializes).
|
|
126
|
+
*/
|
|
127
|
+
export declare function packageSync(client: LoticsClient, args: {
|
|
128
|
+
projectDir?: string;
|
|
129
|
+
}): Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* `lotics package dev [path] [--workspace <dev_ws>] [--view-as <member>]` —
|
|
132
|
+
* scaffold-sync the package into the dev workspace, then run the existing app
|
|
133
|
+
* dev server against the resulting installation (HMR over the local source, RPC
|
|
134
|
+
* forwarded to the live installation). The inner loop: edit contract → re-run to
|
|
135
|
+
* sync; edit code → hot reload.
|
|
136
|
+
*/
|
|
137
|
+
export declare function packageDev(client: LoticsClient, args: {
|
|
138
|
+
projectDir?: string;
|
|
139
|
+
port?: number;
|
|
140
|
+
vitePort?: number;
|
|
141
|
+
}): Promise<void>;
|
|
142
|
+
/**
|
|
143
|
+
* `lotics package reset [path]` — DEV-ONLY, hard-gated. Drops the dev
|
|
144
|
+
* installation's package-owned scaffolded tables and re-scaffolds them clean. The
|
|
145
|
+
* backend refuses any workspace not flagged as a dev workspace, so this can never
|
|
146
|
+
* erase a real workspace's data. The dev installation is resolved from the
|
|
147
|
+
* project manifest's pin for the selected workspace.
|
|
148
|
+
*/
|
|
149
|
+
export declare function packageReset(client: LoticsClient, args: {
|
|
150
|
+
projectDir?: string;
|
|
151
|
+
}): Promise<void>;
|
|
152
|
+
export type UpgradeResolutionValue = "recreate" | "revert" | "keep" | {
|
|
153
|
+
bind_to: string;
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Parse repeated `--resolve <key>=<value>` flags. Drift entries
|
|
157
|
+
* (`<namespace>.<alias>`) take `recreate` or an existing id; modified
|
|
158
|
+
* artifacts (`<kind>.<alias>`) take `revert` or `keep`. Any other value is a
|
|
159
|
+
* bind_to id; the server validates value-kind against what the key resolves.
|
|
160
|
+
*/
|
|
161
|
+
export declare function parseResolveFlags(resolve: string[]): Record<string, UpgradeResolutionValue>;
|
|
162
|
+
/**
|
|
163
|
+
* Health check: version pin vs. registry latest + binding drift. Exits
|
|
164
|
+
* non-zero when drift is found so scripts can gate on it.
|
|
165
|
+
*/
|
|
166
|
+
export declare function packageDoctor(client: LoticsClient, args: {
|
|
167
|
+
app_id?: string;
|
|
168
|
+
}): Promise<void>;
|
|
169
|
+
/**
|
|
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.
|
|
173
|
+
*/
|
|
174
|
+
export declare function packageUpgrade(client: LoticsClient, args: {
|
|
175
|
+
app_id: string;
|
|
176
|
+
version?: number;
|
|
177
|
+
resolutions: Record<string, UpgradeResolutionValue>;
|
|
178
|
+
}): Promise<void>;
|
|
179
|
+
export declare function packageInstall(client: LoticsClient, args: {
|
|
180
|
+
package_id: string;
|
|
181
|
+
version?: number;
|
|
182
|
+
}): Promise<void>;
|
|
183
|
+
export declare function packageEject(client: LoticsClient, args: {
|
|
184
|
+
app_id: string;
|
|
185
|
+
}): Promise<void>;
|
|
186
|
+
/**
|
|
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.
|
|
197
|
+
*/
|
|
198
|
+
export declare function packageExtract(client: LoticsClient, args: {
|
|
199
|
+
app_id: string;
|
|
200
|
+
targetPath?: string;
|
|
201
|
+
}): Promise<void>;
|
|
202
|
+
/**
|
|
203
|
+
* `lotics package adopt <app_id> [path]` — bind the published package project
|
|
204
|
+
* onto the origin app (docs/app_packages.md § Promotion). Reads the project
|
|
205
|
+
* manifest (must be published — refuses otherwise), resolves the version
|
|
206
|
+
* (`--version N` else the manifest's), and reads `.lotics/adopt_binding.json`,
|
|
207
|
+
* REFUSING a pin recorded for a different app. On success the app becomes
|
|
208
|
+
* installation #1 and is upgradeable again; a server ConflictError (naming the
|
|
209
|
+
* unfaithful aliases) surfaces verbatim.
|
|
210
|
+
*/
|
|
211
|
+
export declare function packageAdopt(client: LoticsClient, args: {
|
|
212
|
+
app_id: string;
|
|
213
|
+
version?: number;
|
|
214
|
+
projectDir?: string;
|
|
215
|
+
}): Promise<void>;
|
|
216
|
+
/**
|
|
217
|
+
* `lotics package fleet-upgrade <package_id> [--version N]` — bring every
|
|
218
|
+
* installation of the package across the caller's org to the target version.
|
|
219
|
+
* Hands-off applies only where the preview is clean; skipped/failed
|
|
220
|
+
* installations are reported per line and the process exits 1 so a release
|
|
221
|
+
* script can gate on "fleet fully current".
|
|
222
|
+
*/
|
|
223
|
+
export declare function packageFleetUpgrade(client: LoticsClient, args: {
|
|
224
|
+
package_id: string;
|
|
225
|
+
version?: number;
|
|
226
|
+
}): Promise<void>;
|
|
227
|
+
export {};
|