@lotics/cli 0.57.0 → 0.60.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.
package/README.md CHANGED
@@ -149,6 +149,42 @@ Edits mutate the file in place via an atomic temp-file + rename. Unknown OOXML c
149
149
 
150
150
  Run `lotics xlsx` or `lotics docx` with no subcommand for the full list.
151
151
 
152
+ ## Custom-code apps
153
+
154
+ ```bash
155
+ # Scaffold / pull / deploy a Vite+React+TS app project
156
+ lotics app create "Sales Desk" # scaffold + deploy v1
157
+ lotics app pull app_... # bootstrap an existing app locally
158
+ lotics app deploy -m "Add quote drawer" # build + upload a new version
159
+
160
+ # Regenerate .lotics/* WITHOUT a deploy: the .d.ts type companions (always) +
161
+ # the runtime app_fields.ts (when authenticated) — F/OPT maps that address
162
+ # fields + select options by stable display-name aliases instead of opaque ids.
163
+ lotics app codegen # import { F, OPT } from "../.lotics/app_fields"
164
+
165
+ # Execute a bound app workflow end-to-end (inputs: inline / @file / stdin)
166
+ lotics app workflow run issueInvoice '{"record_id":"rec_..."}'
167
+ cat inputs.json | lotics app workflow run importRates # bulk inputs bypass ARG_MAX
168
+ # Honest post-run harvest: created records + a paste-ready cleanup plan + the
169
+ # caveat (external/notification calls can't be auto-undone; sub-workflows may run).
170
+ lotics app workflow run issueInvoice '{...}' --print-created
171
+ lotics app workflow run issueInvoice '{...}' --cleanup # also deletes created records (NOT a rollback)
172
+
173
+ # Edit workflow bodies as files. `app pull` writes src/workflows/<alias>.ts (the
174
+ # faithful server source, wrapped + referencing its .lotics/workflows/<alias>.globals.d.ts);
175
+ # edit the body, then push it back through set_app_workflow — the server verifies it
176
+ # (deploy still never authors workflows). Bodies are locally typecheckable:
177
+ # tsc -p tsconfig.workflows.json
178
+ lotics app workflow pull # rewrite src/workflows/*.ts + globals from the server
179
+ lotics app workflow set issueInvoice # push the edited src/workflows/issueInvoice.ts
180
+
181
+ # Dev-link @lotics/ui to the monorepo's packages/ui/src for live HMR (monorepo only)
182
+ lotics ui link card # edits to packages/ui/src go live
183
+ lotics ui link card --remove # finalize: PR + publish, then drop the alias
184
+ ```
185
+
186
+ `app codegen` reads `package.json#lotics.queries` to decide which tables to put in `app_fields.ts`; widen the set with `package.json#lotics.codegen.tables` (an array of `tbl_…` ids) for tables the app only writes via workflows.
187
+
152
188
  ## SDK
153
189
 
154
190
  ```typescript
@@ -42,6 +42,63 @@ export type AppAgentDeclaration = {
42
42
  inputs?: Record<string, unknown>;
43
43
  outputs?: Record<string, unknown>;
44
44
  };
45
+ /**
46
+ * The `async function __workflow(...)` wrapper a workflow body sits inside —
47
+ * the SAME envelope the server compiles the body within at `set_app_workflow`
48
+ * verify time (GAP-59). Carried so a body that uses top-level `await` and ends
49
+ * with `return({...})` typechecks locally exactly as the server checks it. The
50
+ * server returns the canonical strings (`getAppWorkflowDts`); these are the
51
+ * offline fallback when the dts fetch fails so the file is still wrapped — a
52
+ * test pins them equal to the server's, so they can't drift.
53
+ */
54
+ export declare const FALLBACK_ENVELOPE_PREFIX = "async function __workflow(): Promise<__WorkflowReturn | void> {\n";
55
+ export declare const FALLBACK_ENVELOPE_SUFFIX = "\n}";
56
+ export interface WorkflowEnvelope {
57
+ prefix: string;
58
+ suffix: string;
59
+ }
60
+ /**
61
+ * Write `.lotics/workflows/<alias>.globals.d.ts` = the server-generated ambient
62
+ * declarations the body typechecks against. Idempotent. Returns the path.
63
+ */
64
+ export declare function writeWorkflowGlobals(projectDir: string, alias: string, dts: string): string;
65
+ /**
66
+ * Write `src/workflows/<alias>.ts` = header (triple-slash reference + comments)
67
+ * + the body wrapped in the `__workflow` envelope. Idempotent (a re-pull
68
+ * overwrites with the current server body). The raw `source` round-trips on
69
+ * `set` (the header + wrapper are stripped). Exported for direct unit testing —
70
+ * the surrounding pull shells out to `tar`/`npm`.
71
+ */
72
+ export declare function writeWorkflowFile(projectDir: string, alias: string, source: string, envelope?: WorkflowEnvelope): string;
73
+ /**
74
+ * Strip the CLI bookkeeping back off a workflow body before pushing it: the
75
+ * triple-slash reference + the `//` header comments + the `export {};` marker +
76
+ * blank lines, then the `__workflow` envelope (the opening
77
+ * `async function __workflow(...) {` line and the matching trailing `}`). `set`
78
+ * sends ONLY the JS-subset body the author edited — the server stays the single
79
+ * verifier.
80
+ *
81
+ * The strip is anchored on the GENERATED bookkeeping, never on "the file happens
82
+ * to start with comments": the leading comment/marker/blank block is only peeled
83
+ * when it is immediately followed by the `__workflow` wrapper opener (the exact
84
+ * shape `writeWorkflowFile` produces). A hand-written, wrapper-LESS body whose
85
+ * first lines are comments therefore round-trips unchanged — its comments are
86
+ * real source, not bookkeeping, and must not be silently eaten.
87
+ */
88
+ export declare function stripWorkflowHeader(content: string): string;
89
+ /**
90
+ * `lotics app codegen [path]` — regenerate every `.lotics/` artifact from the
91
+ * manifest + workspace schema, WITHOUT a deploy. The `.d.ts` companions are
92
+ * always written (synchronous, no network). When a `client` is available, the
93
+ * runtime `app_fields.ts` is also regenerated from the live schema of the tables
94
+ * the app's queries reference (+ the allowlist); a network failure is non-fatal
95
+ * (warn, keep the last-generated file) — so codegen still does useful work
96
+ * offline, mirroring `app create`'s tolerance of an offline npm registry.
97
+ */
98
+ export declare function appCodegen(args: {
99
+ projectDir?: string;
100
+ client?: LoticsClient;
101
+ }): Promise<void>;
45
102
  /**
46
103
  * Stamp the post-extraction manifest with server-authoritative meta. Called
47
104
  * by `appPull` after the source archive lands on disk.
@@ -106,8 +163,10 @@ export declare function appCreate(client: LoticsClient, args: {
106
163
  * 4. Regenerate `.lotics/app_workflows.d.ts` from the live workflows so
107
164
  * `useWorkflow<"alias">` is typed at pull time.
108
165
  * 5. Run `npm install`.
109
- * 6. (TODO) Generate `.lotics/types.ts` with workspace tables augmentation —
110
- * pending a `client.getWorkspaceSchema()` endpoint.
166
+ *
167
+ * Runtime field/option id aliases (`.lotics/app_fields.ts`) are generated on
168
+ * demand by `lotics app codegen`, which fetches the workspace schema — pull
169
+ * leaves it to that command so a schema fetch never blocks the bootstrap.
111
170
  */
112
171
  /**
113
172
  * `lotics app subdomain <new>` — rename the current app's public address.
@@ -166,3 +225,66 @@ export declare function appDev(client: LoticsClient, args: {
166
225
  port?: number;
167
226
  vitePort?: number;
168
227
  }): Promise<void>;
228
+ /**
229
+ * `lotics app workflow run <alias> '<json>'` — execute a bound app workflow
230
+ * end-to-end against the live workspace. `app_id` comes from the local manifest
231
+ * (like deploy/dev), the alias must be bound server-side via `set_app_workflow`.
232
+ *
233
+ * The full `{ status, message, data, files, side_effects }` JSON prints to
234
+ * stdout (pipeable / assertable); a one-line human summary goes to stderr. A
235
+ * `status: "error"` envelope exits non-zero so a script can branch on it — the
236
+ * transport already normalizes a gateway/timeout failure into the same
237
+ * `{ status: "error" }` shape, so a failed run is never a thrown HTML body.
238
+ *
239
+ * `--print-created` (alias `--report-effects`) renders the honest post-run
240
+ * harvest (GAP-58): created records grouped by table, a paste-ready
241
+ * `delete_records` per table, and the mandatory caveat about what cannot be
242
+ * auto-undone. `--cleanup` (DEFAULT OFF) additionally runs the deletes for the
243
+ * harvested records ONLY — never files, external integrations, or notifications.
244
+ * Neither is a rollback; a rollback is structurally impossible here.
245
+ */
246
+ export declare function appExecuteWorkflow(client: LoticsClient, args: {
247
+ alias: string;
248
+ inputs: Record<string, unknown>;
249
+ printCreated?: boolean;
250
+ cleanup?: boolean;
251
+ }): Promise<void>;
252
+ /**
253
+ * `lotics app workflow set <alias>` — push the edited `src/workflows/<alias>.ts`
254
+ * body to the server through `set_app_workflow` (the single author of
255
+ * `apps.workflows`). The body is read from disk (header stripped); the typed
256
+ * `inputs`/`outputs` schemas come from `package.json#lotics.workflows.<alias>`,
257
+ * so a pulled-then-edited app keeps its declared contract. The server re-verifies
258
+ * the body and echoes the bound `outputs` (declared, else DERIVED from
259
+ * `return({ data })`) — the same guarantee as calling `set_app_workflow` by hand,
260
+ * with no fetch/reconstruct/escape. Errors (missing file, unbound alias, verify
261
+ * failure) print to stderr and exit non-zero.
262
+ *
263
+ * This is a CLI convenience over the existing tool — `lotics app deploy` is still
264
+ * NOT an author of workflows; the single-author invariant holds.
265
+ */
266
+ export declare function appWorkflowSet(client: LoticsClient, args: {
267
+ alias: string;
268
+ }): Promise<void>;
269
+ /**
270
+ * `lotics app workflow pull` — rewrite every `src/workflows/<alias>.ts` from the
271
+ * server without a full `lotics app pull` (no source archive, no npm install).
272
+ * The alias set + bodies come from the live App row (the same source `app pull`
273
+ * uses); a legacy alias with no rendered source warns and is skipped.
274
+ */
275
+ export declare function appWorkflowPull(client: LoticsClient): Promise<void>;
276
+ /**
277
+ * `lotics ui link <component> [--remove]` — add or remove the `@lotics/ui`
278
+ * dev-link alias in the app's `vite.config.ts`, so edits to the monorepo's
279
+ * `packages/ui/src` go live (HMR) without a publish round-trip. `component` is
280
+ * advisory only — the alias is package-wide (one subpath regex covers every
281
+ * import); it's validated to exist under `packages/ui/src` so a typo fails here.
282
+ *
283
+ * Idempotent: linking twice is a no-op; `--remove` strips the one inserted
284
+ * entry and leaves the rest of `resolve.alias` intact.
285
+ */
286
+ export declare function appUiLink(args: {
287
+ projectDir?: string;
288
+ component: string;
289
+ remove?: boolean;
290
+ }): void;