@lotics/cli 0.264.0 → 0.266.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/AGENTS.md +9 -9
- package/README.md +4 -4
- package/dist/src/cli.js +212 -65
- package/docs/building_an_app.md +7 -4
- package/docs/cli_reference.md +7 -7
- package/docs/document_templates.md +7 -17
- package/docs/migration.md +7 -1
- package/package.json +1 -1
package/docs/building_an_app.md
CHANGED
|
@@ -79,14 +79,17 @@ distinction. Read what a field MEANS before you remove it.
|
|
|
79
79
|
lotics docs model # how to write model.json, with a worked example
|
|
80
80
|
lotics model apply model.json # check it, apply the tables, mint a version of every app
|
|
81
81
|
lotics model apply model.json --app orders # only the apps named; the tables are applied whole
|
|
82
|
+
lotics model apply model.json --plan # what the apply would change, writing nothing
|
|
82
83
|
lotics model pull -o model.json # the workspace's model, as the file apply reads
|
|
83
84
|
```
|
|
84
85
|
|
|
85
86
|
`model apply` checks the whole file first — every problem in one run, before anything is uploaded
|
|
86
|
-
or written. It then adopts or creates each table (
|
|
87
|
-
and given what it lacks; no stored value changes), writes the first rows only where every bound
|
|
88
|
-
table is empty, and mints one version per app, printing each app's id
|
|
89
|
-
(`unchanged` when there was nothing to mint). Applying the same file again mints nothing.
|
|
87
|
+
or written. It then adopts or creates each table (the table this workspace bound it to, else one of the same
|
|
88
|
+
label, is adopted and given what it lacks; no stored value changes), writes the first rows only where every bound
|
|
89
|
+
table is empty, and mints one version per app, printing each app's id, the version minted
|
|
90
|
+
(`unchanged` when there was nothing to mint) and its address. Applying the same file again mints nothing.
|
|
91
|
+
A table change is not undone by rolling an app back, so `--plan` first says what the apply would
|
|
92
|
+
create or change in the tables and which apps it would create, update or refuse — writing nothing.
|
|
90
93
|
|
|
91
94
|
**The model changes after the app exists, and applying it again is how it lands.** Edit the file,
|
|
92
95
|
apply it. An act whose write the model cannot say names its own `workflow`; that workflow's body is
|
package/docs/cli_reference.md
CHANGED
|
@@ -4,7 +4,7 @@ Per-command syntax, flags, contracts, and gotchas for the public `lotics` CLI. S
|
|
|
4
4
|
|
|
5
5
|
| Command | What it does |
|
|
6
6
|
|---|---|
|
|
7
|
-
| `lotics` / `lotics --help` | Show full help
|
|
7
|
+
| `lotics` / `lotics --help` | Show full help: capabilities, the verb list (§ COMMANDS), flags, config. `lotics <verb> --help` prints that verb's entries alone (`lotics model --help`, `lotics file download --help`); `lotics report --help` prints the report frame. |
|
|
8
8
|
| `lotics auth signup <email>` | Create account + org + API key, sends magic link email. Registers the new org as a profile; `--local` pins this directory to it (pointer) instead of setting the global default. |
|
|
9
9
|
| `lotics auth login <email>` | Sign in an account that already exists, on a machine holding no key. **Two steps, and it does not wait for the person.** The first prints the page to open — `https://lotics.ai/cli_login/<request_id>`, also mailed — and the code that page must show, records the request, and exits 0. They sign in there if asked, check the code and press Confirm. **Then the next command that needs a credential collects the key** before it does its own work, so the second step is just re-running whatever was wanted; a command run before Confirm exits 1 naming the page and the code again, and once the 15 minutes are up it says to ask again. The handful that run WITHOUT a credential — `docs` among them — claim nothing, so one of those run after Confirm still answers as though signed out. `--wait` keeps one command instead, holding the terminal until Confirm; `--local` pins this directory to that org rather than setting the global default, and implies `--wait` (a pin names THIS directory, so only the terminal that stays in it can write one). `--json` prints `organization_id`, `workspace_id` and `organization_name` when it finishes signed in, and `request_id`, `confirm_url`, `code`, `email`, `expires_at` when it is the first step. The request's secret is never printed and the org's key never leaves the store. |
|
|
10
10
|
| `lotics auth api-key [key]` | `whoami` → **upsert** the key's org as a profile in the global store (never overwrites). The profile records the instance the key was verified against (`LOTICS_API_URL`, default `https://api.lotics.ai`), and every later command for that org goes there. `--local` additionally pins this directory to it (pointer) instead of setting the global default. |
|
|
@@ -24,11 +24,11 @@ Per-command syntax, flags, contracts, and gotchas for the public `lotics` CLI. S
|
|
|
24
24
|
| `lotics workspace doctor` | Report workspace-wide dangling schema references via `GET /v1/workspaces/dangling-references` — every active app/workflow artifact whose prefixed schema id no longer resolves, printed as `<referent.kind> "<name>" (<id>) → <namespace> <id> (missing)`; healthy prints a one-line all-clear. **Exits non-zero (exit 1) on findings** so scripts can gate on it. Resolves the first workspace like every data command (runs before the global workspace resolution). Admin-only. |
|
|
25
25
|
| `lotics tools` | List tools by category with descriptions |
|
|
26
26
|
| `lotics tools <name>` | Full description + JSON Schema for one tool |
|
|
27
|
-
| `lotics run <tool> '<json>'` | Execute a tool (text output via toModelOutput). Args may also come from a file (`lotics run <tool> @args.json`) or stdin behind the `-` sentinel (`cat args.json \| lotics run <tool> -`) — both bypass the OS `ARG_MAX` limit for large payloads (a knowledge-doc `content`, a bulk update). A leading `@` on the args is unambiguously a file path (JSON args start with `{`). **Stdin is asked for, never guessed.** `lotics run <tool>` with no payload runs the tool with no arguments and returns at once
|
|
27
|
+
| `lotics run <tool> '<json>'` | Execute a tool (text output via toModelOutput). Args may also come from a file (`lotics run <tool> @args.json`) or stdin behind the `-` sentinel (`cat args.json \| lotics run <tool> -`) — both bypass the OS `ARG_MAX` limit for large payloads (a knowledge-doc `content`, a bulk update). A leading `@` on the args is unambiguously a file path (JSON args start with `{`). **Stdin is asked for, never guessed.** `lotics run <tool>` with no payload runs the tool with no arguments and returns at once. `lotics report` takes the same sentinel. In PowerShell use `@file`: quotes inside an inline argument are consumed by the shell, and the CLI reports the JSON it received with its quotes gone — the error names both escapes. |
|
|
28
28
|
| `lotics run <tool> --json '<json>'` | Execute a tool (full JSON output) |
|
|
29
29
|
| `lotics run <tool>` — **file cells** | A file in a tool's result carries its `fil_…` id and metadata and **no `url`**, on every tool and in both output modes. That is not a broken file — this surface resolves no URL for a cell. Reach the bytes with `lotics file download <file_id>`, which takes the id straight from the cell; the text output says so whenever a result carries one. |
|
|
30
30
|
| — | **Every tool is invoked here, including the ones that RUN something** (`run_app_workflow`, `run_app_agent`, `run_app_query`) and every one that changes an app (`set_app_query`, `set_app_workflow`, `set_app_agent`, `update_app`, `rollback_app`, the `sandbox_*` tools). A command exists only for work that touches a local file: `model apply`, `model pull`, `app create --custom`, `app deploy`. |
|
|
31
|
-
| — | **The exit code reports the WORK, not just the call — for the two tools that RUN one.** `run_app_workflow` and `run_app_agent` whose envelope carries a failed `status` (`error`/`failed`/`cancelled`) exit non-zero and print `<tool> → <status>: <message>` to stderr, so `lotics run … && next-step` cannot walk past a refused run. The rule is an allowlist of FAILURE — an unrecognized status exits 0, so a status added later never turns a working script red. A parked run (`awaiting_input`) is not a failure: it is waiting for an answer and the work is still live. Only a TOP-LEVEL `status` counts; one inside the data belongs to the data. Any OTHER tool's `status`
|
|
31
|
+
| — | **The exit code reports the WORK, not just the call — for the two tools that RUN one.** `run_app_workflow` and `run_app_agent` whose envelope carries a failed `status` (`error`/`failed`/`cancelled`) exit non-zero and print `<tool> → <status>: <message>` to stderr, so `lotics run … && next-step` cannot walk past a refused run. The rule is an allowlist of FAILURE — an unrecognized status exits 0, so a status added later never turns a working script red. A parked run (`awaiting_input`) is not a failure: it is waiting for an answer and the work is still live. Only a TOP-LEVEL `status` counts; one inside the data belongs to the data. Any OTHER tool's `status` is data, and exits 0. |
|
|
32
32
|
| `lotics run <tool> --print-created` | Report the records the call created, grouped by table, with a paste-ready `delete_records` per table and the mandatory caveat naming what cannot be auto-undone (external integrations, notifications, possible sub-workflows). Works for any tool that returns a `side_effects` block, not workflows alone. |
|
|
33
33
|
| `lotics run <tool> --cleanup` | Implies `--print-created`, then runs those deletes — harvested records **only**, never files / external calls / notifications. **Not a rollback**; a rollback is structurally impossible here. A partial cleanup exits non-zero so a script cannot read it as success. |
|
|
34
34
|
| `lotics file upload <file\|dir...>` (alias `lotics upload`) · `--stdin` · `--base64` · `--url <url>` | Upload files/directories. **The transport is chosen by size and is not a flag**: under 8 MiB the file is POSTed to `/v1/files` in one request, and several such files go in the same one; at or above it the CLI takes presigned part URLs and PUTs the bytes straight to object storage, so they never pass through the API. That threshold matches the AWS CLI's own `multipart_threshold`, and the number matters less than there being nothing to choose — one verb, any size, up to the 2 GiB a workspace may store. A large upload reads one part at a time, so memory stays flat regardless of file size, and a failure part-way abandons the parts already sent rather than leaving them billable and invisible. A directory expands to its immediate files; `--as <name>` renames a single upload. **Three alternative byte sources, for a caller that never had the bytes on disk** — an attachment decoded in memory, a generated document, a signed download link — each mutually exclusive with the others and with a path argument: `--stdin` takes raw bytes on stdin, `--base64` takes base64 on stdin (the shape attachments arrive in), `--url <url>` fetches the URL first. `--stdin`/`--base64` REQUIRE `--as`, because stdin carries no filename and the mime type is derived from it; `--url` falls back to `Content-Disposition` then the URL's last path segment. `--base64` decodes STRICTLY — `Buffer.from(s, "base64")` silently skips invalid characters and truncates on bad padding, so a corrupted pipe would otherwise store a short file that only fails when a human opens it. The `--url` fetch happens in the CLI, not the server: the URL comes from the operator running the command, so routing it through the backend would add an SSRF surface to buy what `curl` already does. |
|
|
@@ -37,14 +37,14 @@ Per-command syntax, flags, contracts, and gotchas for the public `lotics` CLI. S
|
|
|
37
37
|
| `lotics file delete <file_id>` | Archive a stored file, over the `delete_file` tool. **Refused while a record cell, a comment, a knowledge doc, a document template or a voice session still references it** — the refusal names the referents, so this is safe to try. The bytes are left in object storage; the row no longer serves them, which is what "deleted" means here. There is no `lotics delete`: the verb needs its noun. |
|
|
38
38
|
| `lotics knowledge list [--include-hidden]` | `GET /v1/knowledge_docs` — a table of id, name, tags, description (`--json` for the docs). **REST, not the `list_knowledge` tool**: the tool answers what the ASSISTANT may browse, and a hidden doc is out of that corpus by definition, so a tool-backed listing could never show one and the person who hid it would have no way back to it. Hidden docs are left out unless `--include-hidden` asks; those rows are marked `(hidden)`. |
|
|
39
39
|
| `lotics knowledge create --name <n> [--description <d>] [--tags <a,b>] (--from <file.md> \| --content <str>)` | Read the body client-side (a file XOR an inline string — exactly one required), then call `create_knowledge` with `{ name, description, content, tags? }` (description defaults to `""`). `--tags` files the doc as it is made, which is the only moment a corpus reliably gets labelled. Prints the new id to stdout. Large files ride the POST body fine. |
|
|
40
|
-
| `lotics knowledge get <id> [-o <file.md>]` | `GET /v1/knowledge_docs/{id}` (`getKnowledgeDoc`) → the doc with its **hydrated `content`** (the one content-read path for a non-sandbox client
|
|
40
|
+
| `lotics knowledge get <id> [-o <file.md>]` | `GET /v1/knowledge_docs/{id}` (`getKnowledgeDoc`) → the doc with its **hydrated `content`** (the one content-read path for a non-sandbox client). `-o` writes the body via `writeFileAtomic`; else the body goes to stdout. `--json` prints the full doc instead. |
|
|
41
41
|
| `lotics knowledge update <id> [--from <file.md> \| --content <str>] [--name <n>] [--description <d>] [--tags <a,b>]` | Call `update_knowledge` with **only** the provided fields (a body from --from/--content becomes `content`; the tool diffs + CASes the content change internally, so the CLI passes no `expected_content_file_id`). `--tags` REPLACES the doc's label set — the single-doc form, where the caller is looking at one doc and can state what it should carry. At least one field required; --from and --content are mutually exclusive. |
|
|
42
42
|
| `lotics knowledge tag <id...> [--add <a,b>] [--remove <c,d>]` | `PATCH /v1/knowledge_docs` with `{ knowledge_doc_ids, add_tags?, remove_tags? }` — one transaction over the whole set. A **DIFF applied to each doc's own labels**, never a replacement: the docs named on one command line carry different labels, so one array across them would strip whatever the others were filed under. Removal matches case-insensitively; adding a label a doc already carries writes nothing. Ids may be separate arguments or comma-separated. At least one of --add/--remove required. |
|
|
43
43
|
| `lotics knowledge hide <id...>` / `lotics knowledge unhide <id...>` | `PATCH /v1/knowledge_docs` with `{ knowledge_doc_ids, hidden }`. Hiding takes docs out of every **listing** — the Library's list, `list_knowledge`, and the corpus `grep_knowledge` searches — while leaving IAM untouched and keeping them readable **by id** (`read_knowledge` with an id, a code run staging one, an app agent's declared set). So it can never silently break an app that depends on a doc, and unhiding costs nothing. Refuses the no-argument form rather than reading it as "everything". |
|
|
44
44
|
| `lotics knowledge rm <id>` | Archive the doc via `delete_knowledge` (`{ knowledge_doc_id }`). The REST execute path does not gate `needsApproval`, so this runs unattended. |
|
|
45
|
-
| `lotics setup <model.json> [--email <addr>] [--json]` | **The whole first run, in one command.** Creates an account when this machine has no credential (the same call `auth signup` makes — `--name` and `--timezone` apply), then applies the model to its workspace, then prints the one-time sign-in link. **When that email already has an account it hands over to the `lotics auth login` flow** — it prints the sign-in page to open and the code it must show, and **exits 1 having created nothing**; the person presses Confirm and runs the same command again, which collects the key and carries on into the model. (`--wait` holds the terminal through the Confirm instead, finishing in one command.) The re-run is not refused for naming an `--email` it is now signed in as — that address IS the account it holds, not a second one. The file is a workspace MODEL, and it is read and checked before an account is created, because a file with a typo in it must not leave an organization behind. Then it is `lotics model apply` run on the new workspace: its tables, rows and apps; the sign-in link lands on its app when it has one, else on the workspace's app list. It exists because the two-command form has a seam where the FIRST command exists only to produce a credential for the second, and a caller pasting a prompt has to get both right. **`--email` is only for creating an account**: with a credential already resolvable it is REFUSED rather than obeyed, because the two can name different organizations and preferring either one silently writes into an org the caller did not name — the message says how to do each thing on purpose. Without it, `setup` applies the model to the account you already have. A path positional after the file is accepted and IGNORED with a warning — `setup` writes nothing to disk — so a prompt that passes one still runs. **`--json` prints one object on stdout and nothing else** — what `lotics model apply --json` does (`apps`, each with `alias`, `app_id`, `version_id`, `origin`, `findings
|
|
46
|
-
| `lotics model apply <model.json> [--app <alias> ...] [--json]` | **The model, applied to this workspace, through the `apply_model` tool.** The file is read and checked with the validator the server runs, every problem in one run, before anything is uploaded. Documents a row attaches by a path beside the file are uploaded first and the rows sent with their `fil_` ids; a path this workspace already recorded keeps its id, so a re-apply uploads nothing twice. Then the tool adopts or creates every table (an existing table of the same label is ADOPTED and given the fields, options and views it lacks; no stored value changes), writes first rows only where every bound table is empty, and mints a new version of each app the model declares — `--app` (repeatable, comma-separated) narrows which apps, while the tables are applied whole. Prints one line per app — alias, `app_id`,
|
|
47
|
-
| `lotics model pull [-o <model.json>]` | **This workspace's model, rebuilt from what owns each part** — the tables, fields, options, templates and roles the workspace holds, how rows are recognised, and each app's body from its current version — through the `get_model` tool, as the file `model apply` reads: to stdout, or to the file `-o` names. Applying what it wrote changes nothing. |
|
|
45
|
+
| `lotics setup <model.json> [--email <addr>] [--json]` | **The whole first run, in one command.** Creates an account when this machine has no credential (the same call `auth signup` makes — `--name` and `--timezone` apply), then applies the model to its workspace, then prints the one-time sign-in link. **When that email already has an account it hands over to the `lotics auth login` flow** — it prints the sign-in page to open and the code it must show, and **exits 1 having created nothing**; the person presses Confirm and runs the same command again, which collects the key and carries on into the model. (`--wait` holds the terminal through the Confirm instead, finishing in one command.) The re-run is not refused for naming an `--email` it is now signed in as — that address IS the account it holds, not a second one. The file is a workspace MODEL, and it is read and checked before an account is created, because a file with a typo in it must not leave an organization behind. Then it is `lotics model apply` run on the new workspace: its tables, rows and apps; the sign-in link lands on its app when it has one, else on the workspace's app list. It exists because the two-command form has a seam where the FIRST command exists only to produce a credential for the second, and a caller pasting a prompt has to get both right. **`--email` is only for creating an account**: with a credential already resolvable it is REFUSED rather than obeyed, because the two can name different organizations and preferring either one silently writes into an org the caller did not name — the message says how to do each thing on purpose. Without it, `setup` applies the model to the account you already have. A path positional after the file is accepted and IGNORED with a warning — `setup` writes nothing to disk — so a prompt that passes one still runs. **`--json` prints one object on stdout and nothing else** — what `lotics model apply --json` does (`tables`; `apps`, each with `alias`, `app_id`, `version_id`, `origin`, `address` and `findings`; and `findings`) plus `organization_id`, `workspace_id` and `signin_url`, and a `warnings` array carrying everything the prose form would have said out of band, such as a sign-in link that could not be minted. A warning is never merely silenced: when the command fails with an error before it can emit, the ones it had collected go to stderr alongside it. Reachable with no install: `npx -y @lotics/cli setup …`. |
|
|
46
|
+
| `lotics model apply <model.json> [--app <alias> ...] [--plan] [--json]` | **The model, applied to this workspace, through the `apply_model` tool.** The file is read and checked with the validator the server runs, every problem in one run, before anything is uploaded. Documents a row attaches by a path beside the file are uploaded first and the rows sent with their `fil_` ids; a path this workspace already recorded keeps its id, so a re-apply uploads nothing twice. Then the tool adopts or creates every table (the table this workspace bound the entity to, else an existing table of the same label, is ADOPTED and given the fields, options and views it lacks; no stored value changes), writes first rows only where every bound table is empty, and mints a new version of each app the model declares — `--app` (repeatable, comma-separated) narrows which apps, while the tables are applied whole. Prints one line per app — alias, `app_id`, `created`/`updated` with the version minted or `unchanged`, and the address it is served at — then the model's notes once, as the server states them. **`--plan` writes nothing and uploads nothing**: it prints what the apply would do to the tables (what it would create, what it leaves as the workspace has it, what the two disagree about), which apps it would create or update, and what it would refuse an app for, exiting 1 when it would refuse one; workflow bodies are checked only at apply, since they name fields a plan has not created. **A rollback restores an app's earlier version** (`lotics run rollback_app`); table changes and data writes stay. Resolves and ANNOUNCES its workspace first. `--json` prints `{workspace_id, tables, apps, findings}` on stdout (with `--plan`, each table and app is what the apply would do), or `{ok: false, findings}` when the file does not check. |
|
|
47
|
+
| `lotics model pull [-o <model.json>]` | **This workspace's model, rebuilt from what owns each part** — the tables, fields, options, templates and roles the workspace holds, how rows are recognised, and each app's body from its current version — through the `get_model` tool, as the file `model apply` reads: to stdout, or to the file `-o` names. What the workspace holds that a model cannot state is printed on stderr, never written into the file. Applying what it wrote changes nothing. |
|
|
48
48
|
| `lotics app create <name> --custom [path]` | **A custom-code app**: creates the app (`POST /v1/apps`), scaffolds a Vite + React + TypeScript project into `[path]` (default `./<name>`, refused when not empty — before the app row exists) that depends on `@lotics/app-sdk` alone and draws with plain React, and installs it (`npm install --ignore-scripts`), then writes the declarations of the app's live bindings (`get_app_types`) into `.lotics/`, which the project's `tsconfig.json` includes. `package.json#lotics` names the app and its workspace, which is how `app deploy` in that directory finds both. The app has no version until the first `lotics app deploy`. `--custom` is required: an app the runtime draws from a model is made by `lotics model apply`. The SDK's reference is `node_modules/@lotics/app-sdk/AGENTS.md` inside the project. |
|
|
49
49
|
| `lotics app deploy [-m <message>]` | **Build this directory and upload it as a new version of the live app.** Rewrites `.lotics/` with the declarations of the app's live bindings (`get_app_types`, replacing each file there), then runs the project's `npm run typecheck` (warned about when absent) and `npm run build`, tars the source (without `node_modules`, `dist`, `.git`, `*.tsbuildinfo`) and `dist/`, and posts both to `POST /v1/apps/{id}/versions` on the version `package.json#lotics.current_version_id` names, then stamps the new one there. The version carries the app's queries, workflows, agents and capabilities forward unchanged — those are written through their tools. A project with no `build` script, or whose `package.json#lotics` still declares `queries`, `workflows`, `agents` or `capabilities`, is refused before anything is built; the refusal names the tool that sets each. **A 409 because another version went live since this directory's last deploy** (a deploy from elsewhere, a rollback) prints the server's sentence and the version that is live; to ship this directory over it, set `current_version_id` to that version and deploy again. `-m` (or a bare positional) is the version's message, optional. The workspace comes from `package.json#lotics.workspace_id` unless `--workspace` / `LOTICS_WORKSPACE` names another. |
|
|
50
50
|
| `lotics docs` \| `lotics docs <area>[/<section>]` | **This CLI's own references, carried inside the binary** — the model reference, this index, and every doc under `docs/` — so the doc a reader opens always describes the binary answering. Capped at ONE PAGE: a doc that does not fit prints its opening and the addresses of what it holds (`lotics docs <area>/<section>`, each section's size beside it, or a table's row names), and every address prints within a page. A custom-code app's SDK reference ships inside `@lotics/app-sdk` in the app's `node_modules`. |
|
|
@@ -61,17 +61,15 @@ Form-mode data is scalar-only (text, numbers, checkboxes) — one value per posi
|
|
|
61
61
|
|
|
62
62
|
### Excel (`create_excel_template`)
|
|
63
63
|
|
|
64
|
-
1. Build a `.xlsx` in Excel (or
|
|
64
|
+
1. Build a `.xlsx` in Excel (or with any spreadsheet library) and put `{{marker}}`s in the cells that
|
|
65
65
|
should be filled. `lotics upload ./template.xlsx` → a `file_id`.
|
|
66
66
|
2. `create_excel_template` with that `template_file_id` and a `variables` map. Markers are
|
|
67
67
|
**validated at create time** — a structural error (mismatched loop, unknown helper, bad
|
|
68
68
|
placement) blocks the save, and declared variables with no matching marker come back in
|
|
69
69
|
`unmarked_variables` (skipped, not filled).
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
to re-check. Pass raw numbers / ISO dates / booleans at generate time — the cell's number
|
|
74
|
-
format handles display.
|
|
71
|
+
`validate_excel_template` checks an uploaded file's markers without creating a template. Pass
|
|
72
|
+
raw numbers / ISO dates / booleans at generate time — the cell's number format handles display.
|
|
75
73
|
|
|
76
74
|
### Word (`create_word_template`)
|
|
77
75
|
|
|
@@ -86,11 +84,6 @@ format handles display.
|
|
|
86
84
|
At generate time, `data` must provide a key for **every** marker — pass `""` for fields
|
|
87
85
|
that should render blank; a missing key fails with the full list of missing markers.
|
|
88
86
|
|
|
89
|
-
To read the uploaded file before marking it: `word_get_content`, `word_find_text`,
|
|
90
|
-
`word_get_table_data`. To add markers/loops/conditionals: `word_replace_text`,
|
|
91
|
-
`word_insert_loop`, `word_insert_conditional` — unmarking is `word_replace_text` putting the
|
|
92
|
-
plain text back.
|
|
93
|
-
|
|
94
87
|
### Email (`create_email_template`)
|
|
95
88
|
|
|
96
89
|
Inline HTML + Handlebars, no uploaded file. Declare `variables`, and optionally a default
|
|
@@ -106,14 +99,12 @@ the create-tool description for the reference; here is the capability:
|
|
|
106
99
|
Excel preserve their type via the cell's number format.
|
|
107
100
|
- **Repeating rows / line items** — one template row rendered once per item in a list, for
|
|
108
101
|
invoice lines, order rows, tables. Excel and the HTML/email engines use a Handlebars-style
|
|
109
|
-
`{{#each items}}…{{/each}}`; Word uses `{{FOR item IN items}}…{{$item.field}}…{{END-FOR item}}
|
|
110
|
-
(the `word_insert_loop` tool writes these command rows for you). The HTML and email types
|
|
102
|
+
`{{#each items}}…{{/each}}`; Word uses `{{FOR item IN items}}…{{$item.field}}…{{END-FOR item}}`. The HTML and email types
|
|
111
103
|
also offer an auto-rendered `table` variable — declare its columns and pass an array, no
|
|
112
104
|
hand-written loop. (Excel always uses the `{{#each}}` marker rows — it has no auto-rendered
|
|
113
105
|
`table` type; its variable types are string/number/date/boolean/array.)
|
|
114
106
|
- **Conditional sections** — a block shown only when a condition holds (a "paid" stamp, an
|
|
115
|
-
optional notes block). Excel/HTML/email use `{{#if}}…{{else}}…{{/if}}`; Word uses
|
|
116
|
-
`word_insert_conditional`.
|
|
107
|
+
optional notes block). Excel/HTML/email use `{{#if}}…{{else}}…{{/if}}`; Word uses `{{IF name}}…{{END-IF name}}`.
|
|
117
108
|
|
|
118
109
|
Run `lotics tools create_excel_template`, `create_word_template`, `create_pdf_template`, or
|
|
119
110
|
`create_email_template` for each engine's exact marker grammar and helper list — don't guess it.
|
|
@@ -132,8 +123,7 @@ lotics download <file_id> -o ./out/
|
|
|
132
123
|
`table`/`list`/loop variables. `filename` excludes the extension (the type sets it).
|
|
133
124
|
- Each `generate_*_from_template` returns a generated file object; take its `file_id` onward.
|
|
134
125
|
- In a workflow, a **generate step** calls the same tools and hands the `file_id` to the next
|
|
135
|
-
step (attach to a record, send as an attachment, etc.)
|
|
136
|
-
the platform docs.
|
|
126
|
+
step (attach to a record, send as an attachment, etc.).
|
|
137
127
|
|
|
138
128
|
## Discovering and managing templates
|
|
139
129
|
|
|
@@ -153,7 +143,7 @@ Call `get_template` before generating when you don't already know a template's v
|
|
|
153
143
|
```bash
|
|
154
144
|
lotics tools # all categories
|
|
155
145
|
lotics tools create_word_template # one tool: full description + input schema
|
|
156
|
-
lotics run <tool> '<json-args>' # execute (inline JSON, @file.json, or piped stdin)
|
|
146
|
+
lotics run <tool> '<json-args>' # execute (inline JSON, @file.json, or `-` for piped stdin)
|
|
157
147
|
```
|
|
158
148
|
|
|
159
149
|
The template tools live in the categories **PDF Templates**, **Excel Templates**,
|
package/docs/migration.md
CHANGED
|
@@ -18,6 +18,7 @@ templates and roles are the workspace's own.
|
|
|
18
18
|
| `lotics workspace build <model.json>` | `lotics model apply <model.json>` |
|
|
19
19
|
| `lotics app create --from <model.json>#<app>` | `lotics model apply <model.json> --app <app>` |
|
|
20
20
|
| `lotics app regenerate` | change the model file, then `lotics model apply` |
|
|
21
|
+
| `lotics scaffold diff` | `lotics model apply <model.json> --plan` — what the apply would change, writing nothing |
|
|
21
22
|
| `lotics scaffold export` | `lotics model pull [-o <model.json>]` — the workspace's model, rebuilt from what owns each part |
|
|
22
23
|
| `lotics app pull`, `app codegen`, `app check`, `app dev`, `app preview` | nothing local: read an app with `lotics run get_app`, and change it through its tools |
|
|
23
24
|
| `lotics app workflow set` / `app query set` / `app agent set` | `lotics run set_app_workflow` / `set_app_query` / `set_app_agent` — each mints a version |
|
|
@@ -25,11 +26,13 @@ templates and roles are the workspace's own.
|
|
|
25
26
|
| `lotics app rename`, `app subdomain`, `package.json#lotics.capabilities` | `lotics run update_app` (`name`, `public_subdomain`, `capabilities`) |
|
|
26
27
|
| `lotics app api publish` / `unpublish` | `lotics run publish_app_api` / `unpublish_app_api` |
|
|
27
28
|
| `lotics field rename` | `lotics run update_table`, then the same label in the model file |
|
|
29
|
+
| `lotics app kit` | nothing: a custom-code app depends on `@lotics/app-sdk` (below) |
|
|
30
|
+
| `@lotics/xlsx` / `@lotics/docx` to build a template's file | any `.xlsx` / `.docx` library, then `lotics upload` (`lotics docs document_templates`) |
|
|
28
31
|
| `lotics file preview` | `lotics file download <fil_id>`, then open it |
|
|
29
32
|
| `model.json#apply` (`[{package, bind}]`) | state the tables under `entities` — a model carrying `apply` is refused |
|
|
30
33
|
| `lotics library list` / `library show <slug>`, `lotics preset list` / `preset show <slug>` | the example models at `https://lotics.ai/presets/index.json`, each a complete `model.json` to adapt |
|
|
31
34
|
| `model.json#from` (with `variants`, `rename`) | state every table under `entities` — a model carrying `from` is refused |
|
|
32
|
-
| `lotics library init <apg_id>`, `lotics setup <apg_id
|
|
35
|
+
| `lotics library init <apg_id>`, `lotics setup <apg_id>`, `lotics app upgrade`, `lotics library fixtures` | nothing copies a package any more: write a `model.json` (`lotics docs model`), then `lotics setup model.json` or `lotics model apply model.json` |
|
|
33
36
|
|
|
34
37
|
`lotics tools` lists every tool, and `lotics tools <name>` prints its input.
|
|
35
38
|
|
|
@@ -42,6 +45,9 @@ rest.
|
|
|
42
45
|
**Authored workflow bodies** an act names (`workflow` on an act) are the live workflow's own body:
|
|
43
46
|
the apply keeps it, and `lotics run set_app_workflow` changes it.
|
|
44
47
|
|
|
48
|
+
**A model written before `party`** draws its people and organisations as things — a row with no
|
|
49
|
+
picture shows no initials: state `party` (`person` or `organization`) on those entities' `records`.
|
|
50
|
+
|
|
45
51
|
## Custom-code apps use `@lotics/app-sdk`
|
|
46
52
|
|
|
47
53
|
A hand-written app depends on `@lotics/app-sdk` alone — the hooks (`useQuery`, `useWorkflow`, …),
|