@lotics/cli 0.315.14 → 0.315.17
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 +3 -1
- package/dist/src/cli.js +2037 -1975
- package/docs/cli_reference.md +3 -2
- package/docs/knowledge_docs.md +19 -8
- package/package.json +1 -1
package/docs/cli_reference.md
CHANGED
|
@@ -37,13 +37,14 @@ Per-command syntax, flags, contracts, and gotchas for the public `lotics` CLI. S
|
|
|
37
37
|
| `lotics file download <file_id> [<path>]` · `-o <dir>` | (alias `lotics download`) Download a stored file: `GET /v1/files/{id}/signed_url` → fetch the presigned URL and write it where you asked. **The two spellings mean two different things, and neither is read by shape: the positional `<path>` is the FILE to write, `-o <dir>` is the DIRECTORY to save into.** That is `cp` and `curl -o`, so nothing here consults an extension. A named file is written as named, its parent created, overwriting what is there — the point of naming it is that the next command opens that exact path. A directory is created if missing and written into under the stored filename (the response's `Content-Disposition`), taking a free spelling beside a file of that name already there so a repeat download never clobbers the first; with no destination at all, that filename lands in cwd. Give the destination once — a positional and `-o` together is refused, as is a positional that names an existing directory or ends in a separator (`a directory goes in -o`). The first argument is a **file id**, so a path in that slot is refused rather than sent as an id. The written path goes to **stdout** (under `--json`, `{file_id, path, filename, stored_filename}`) and the narration to stderr, so a download pipes into whatever opens it. `lotics file download record <record_id> <field_key> [-o <dir>]` spreads every file on a record's file field over a DIRECTORY — there is no single file for N files to be. |
|
|
38
38
|
| `lotics file list [--limit <n>] [--cursor <token>]` | The workspace's files, newest first — id, upload time, bytes, MIME type, filename on stdout, one per line (`--json` for the object). `GET /v1/files` with no `file_ids`. A file holding the content of a knowledge doc or template you cannot use is left out. **A page, not a dump**: the store only ever grows, so the last line prints the command for the next page and `next_cursor` is null on the last one. The cursor is opaque and keyset — pass it back as given — so an upload landing mid-sweep cannot make a walk skip or repeat a row. Every other file verb takes an id, so this is the only answer to "what is in here" short of reading Postgres. |
|
|
39
39
|
| `lotics file delete <file_id>` | Archive a stored file, over the `delete_file` tool. Deleting an original deletes every version of it; a file's current version cannot be deleted on its own, and a document template's file, or a version of it, only by a member who manages the template. **Refused while a record cell, a comment, a knowledge doc, a document template, a voice session or a pending change request still references the file or a version it takes along** — 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. |
|
|
40
|
-
| `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)`. |
|
|
40
|
+
| `lotics knowledge list [--include-hidden \| --deleted]` | `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)`. **`--deleted` is the one tool-backed form**: it calls `list_knowledge` with `deleted: true` and prints the deleted docs you can manage (id, name, deleted time, description); it cannot be combined with `--include-hidden`. |
|
|
41
41
|
| `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. |
|
|
42
42
|
| `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. |
|
|
43
43
|
| `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. |
|
|
44
44
|
| `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. |
|
|
45
45
|
| `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". |
|
|
46
|
-
| `lotics knowledge rm <id
|
|
46
|
+
| `lotics knowledge rm <id...>` | Delete docs via `delete_knowledge` (`{ knowledge_doc_ids }`), in one call: every id must be a live doc you manage that no app or workflow names, or nothing is deleted. Sharing and history are kept. The REST execute path does not gate `needsApproval`, so this runs unattended. |
|
|
47
|
+
| `lotics knowledge restore <id...>` | Bring deleted docs back via `restore_knowledge` (`{ knowledge_doc_ids }`), in one call: every id must be a deleted doc you manage, or nothing is restored. Refuses the no-argument form. |
|
|
47
48
|
| `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 — the design decisions an apply would refuse it for too (`lotics docs design`), since a new workspace holds no rows to change them — 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 …`. |
|
|
48
49
|
| `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 against the model's own rules with the validator the server runs, every problem in one run, before anything is uploaded. **The apply refuses an app leaving out a treatment its rows call for** (`lotics docs design`) — judged by the server beside the workspace's rows, before it writes anything — until the app adopts it or states why not under the `declines` key the refusal names; the refusal carries each refused app's patch adopting its decisions, to merge in the order printed. Where the model's own rules pass, one refusal carries everything decidable before the first write — those decisions, what compiling each app finds, a field that cannot leave its table and what the caller may not change — so one pass fixes them. 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. **Where the file was pulled (`-o`) or applied in this workspace before, only what it changed since is sent**, as a `patch`: what changed in the workspace since and the file does not touch stays. An item named by its `alias` that the file puts in a new place — an act among an app's acts, a field between two others — is sent as a move beside the patch: inside an app it is built into the app, an option of a select takes its new place among that select's options on the table, and a table's fields and views, the roles, the templates and the apps themselves keep the order the workspace holds, said as a note. A list whose items carry no `alias` — an app's columns, a section's fields, the sections — is sent whole in its new order. What the file takes out is sent as a removal: it goes where an apply rebuilds it (an app's acts and columns, a write rule), a field leaves its table, and it is refused, naming the tool that deletes it, where an apply never deletes it (a table, a view, an app); an option leaves every app and stays on its table, said in the notes. **A field the file no longer states leaves its table** — a field an earlier apply stated, or one the pulled file stated — only where no live row holds a value in it and nothing outside the model's own apps reads it: no formula, rollup or lookup, no figure's unit or currency, no `default_from` copy, no unique set, no query, agent, table check or workflow body of the workspace. A row in the trash does not count, since no write can clear it: its value goes with the field, and the notes say how many rows it went for. Otherwise nothing is applied and the refusal names the field, how many live rows hold a value and what reads it; a workflow body the author wrote on an app the apply rebuilds that still names the field keeps it on the table, said in the apply's findings, and the next apply sends its removal again until nothing names it. A field such an app names leaves only once the app is rebuilt, with each leaving field it reads, so where one of them reads a field the file changes, nothing is applied and the refusal names both: apply the file without that change first. A field of the table no model ever stated is left as it is. **A label the file changes is a rename**: a field's and a select option's label, and a table's description, are written onto the table as the file states them, each named in the notes. **A declared workflow whose `inputs` or `outputs` the file changes** keeps the body set on it where the body still meets them; where it does not, the apply lands and the workflow stands on no body again — every call refused — until `set_app_workflow` sets one that does, said on the app's line. A file stating a `null` a patch would read as a removal sends the whole model, said on stderr, and so does a reorder sent to a server that takes no move. A patch builds the apps it states or moves an item of, each other app whose build it changes and each app whose live version names a field or option its tables no longer hold, `--app` naming others; one whose every key and move lies inside one app's body leaves the tables as they stand — its `tables` is empty — and checks and builds that app alone, beside any other app whose build reads what it changed. The copy each change is read against is kept per workspace and file under `~/.lotics/model_bases`: an apply narrowed by `--app` leaves in it the other apps as they were, so the next apply sends their edits again, and an apply that fails — refused, or cut off — leaves none, so the next sends the whole model. 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, or the patch builds — `--app` (repeatable, comma-separated) narrows which apps, while the tables are applied whole. Prints one line per app it built — 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. **What it would change, writing nothing, is `lotics model check`.** **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, or `{ok: false, findings}` when the file does not check. |
|
|
49
50
|
| `lotics model check <model.json> [--app <alias> ...] [--json]` | **What applying the model would change, through the `check_model` tool, writing nothing.** The file is read and checked as `model apply` checks it, then sent the same way — whole, or as what it changed since its base — and nothing is uploaded or kept. It prints what the apply would do to the schema (what it would add, each kind counted — tables, fields, options, constraints — what it leaves as the workspace has it, what the two disagree about), which apps it would create or update, what it would refuse an app for — the decisions among its findings, read beside the workspace's rows, with each refused app's patch — and what it would refuse of the model beside its apps (a field that cannot leave its table, a template nothing stores), all in the one run, exiting 1 when it would refuse anything; its notes name each field it would take off a table and each label it would rename; workflow bodies are checked only at apply, since they name fields a check has not created. `check_model` only reads, so a key holding read access alone runs this where `model apply` is refused, and so does a private instance whose licence admits reads only: it needs `schema:read`, and `data:read` when the file states an app or is sent as what it changed. Resolves and ANNOUNCES its workspace first. `--json` prints `{workspace_id, tables, apps, findings}` — each table and app what the apply would do, an app the patches change carrying its body as they leave it as `draft` — and `designs`, each refused app's patch in merge order, or `{ok: false, findings}` when the file does not check. |
|
package/docs/knowledge_docs.md
CHANGED
|
@@ -152,8 +152,9 @@ Retrieval addresses **lines**. Every rule below follows from that one fact.
|
|
|
152
152
|
40 and its exception on line 90 can be retrieved apart. Use `context_lines` when reading, and
|
|
153
153
|
keep related clauses adjacent when writing.
|
|
154
154
|
|
|
155
|
-
Markdown headings are ordinary text — useful for a human
|
|
156
|
-
|
|
155
|
+
Markdown headings are ordinary text — useful for a human (a doc's `##` headings outside its
|
|
156
|
+
blocks, two or more, are listed on its page as its sections) and for orienting a
|
|
157
|
+
`read_knowledge`, but they carry no retrieval weight of their own.
|
|
157
158
|
|
|
158
159
|
**The description is the discovery hint.** It is what the agent sees in the tree before it has
|
|
159
160
|
read a byte of the body, so it is the only clue for *what term to grep for*. Write it to name
|
|
@@ -214,6 +215,15 @@ statement about discovery, so it cannot silently break an app that depends on a
|
|
|
214
215
|
Reach for it instead of `rm` whenever the material still matters: last year's tariff schedule, a
|
|
215
216
|
handbook a newer one replaced, the raw source a curated doc was written from.
|
|
216
217
|
|
|
218
|
+
## Deleting and restoring
|
|
219
|
+
|
|
220
|
+
`lotics knowledge rm <id...>` deletes docs: they leave every listing, search and read. **Their sharing
|
|
221
|
+
and version history are kept**, so a deleted doc is recoverable. `lotics knowledge list --deleted`
|
|
222
|
+
shows the deleted docs you manage, and `lotics knowledge restore <id...>` brings them back with the
|
|
223
|
+
access they had (`restore_knowledge` in chat). A restore is all or none: every id must be a deleted
|
|
224
|
+
doc you manage, or nothing changes. A doc with no owner is restored only by an admin, who becomes its
|
|
225
|
+
owner. A doc that an app or workflow still names cannot be deleted.
|
|
226
|
+
|
|
217
227
|
## Formatting — what a doc draws
|
|
218
228
|
|
|
219
229
|
A doc is markdown with GFM tables. Beyond that it draws a few blocks, each in syntax you already write; the platform draws them in its own style, so every doc looks alike.
|
|
@@ -222,10 +232,10 @@ A doc is markdown with GFM tables. Beyond that it draws a few blocks, each in sy
|
|
|
222
232
|
|---|---|
|
|
223
233
|
| `> [!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]` or `[!CAUTION]` opening a blockquote | a callout in that tone |
|
|
224
234
|
| `<Note>`, `<Info>`, `<Tip>`, `<Check>`, `<Warning>`, `<Danger>` | the same callouts |
|
|
225
|
-
| a ```mermaid fence | a diagram: flowchart, sequence, timeline, gantt, `pie`, `xychart-beta`, `quadrantChart` (a 2x2) |
|
|
235
|
+
| a ```mermaid fence | a diagram: flowchart, sequence, timeline, gantt, `pie`, `xychart-beta`, `quadrantChart` (a 2x2; quadrant-1, top right, is drawn as the target), in the platform's theme; a flowchart's or a 2x2's own colour statements are dropped |
|
|
226
236
|
| `<Steps>` holding `<Step title="…">` | a numbered walk |
|
|
227
237
|
| `<Tabs>` holding `<Tab title="…">` | switchable panels |
|
|
228
|
-
| `<Columns cols={2}>` (or `<CardGroup>`) holding `<Card title="…" href="…">` | side-by-side cards that stack on a phone |
|
|
238
|
+
| `<Columns cols={2}>` (or `<CardGroup>`) holding `<Card title="…" href="…" icon="…">` | side-by-side cards that stack on a phone; `icon` is a glyph from the model reference (a select option's mark), and a name it lacks is refused with the nearest |
|
|
229
239
|
| a table whose header cells are all empty | a table with no header row (a key/value table) |
|
|
230
240
|
| `<Accordion title="…">`, `<AccordionGroup>`, or `<details>` with a one-line `<summary>…</summary>` | a section that opens on press |
|
|
231
241
|
|
|
@@ -241,10 +251,11 @@ lotics knowledge get kdc_... -o doc.md # read a body to a file (omit -o for std
|
|
|
241
251
|
lotics tools update_knowledge # full input schema for any knowledge tool
|
|
242
252
|
```
|
|
243
253
|
|
|
244
|
-
The Knowledge category covers `list_knowledge`, `create_knowledge`, `update_knowledge`,
|
|
245
|
-
`delete_knowledge` — fronted by the `lotics knowledge list | create | get |
|
|
246
|
-
unhide | rm` commands, and all but `delete_knowledge`
|
|
247
|
-
|
|
254
|
+
The Knowledge category covers `list_knowledge`, `create_knowledge`, `update_knowledge`,
|
|
255
|
+
`delete_knowledge` and `restore_knowledge` — fronted by the `lotics knowledge list | create | get |
|
|
256
|
+
update | tag | hide | unhide | rm | restore` commands, and all but `delete_knowledge` and
|
|
257
|
+
`restore_knowledge` reachable over MCP as well, so a corpus can be
|
|
258
|
+
authored from whichever surface you already work in. `list` (without `--deleted`), `tag`, `hide` and `unhide` go over REST rather than a tool, because
|
|
248
259
|
they are a person's view of the corpus: the tools answer what the ASSISTANT may browse, and a
|
|
249
260
|
hidden doc is out of that set by definition. Sharing a doc to other members is `share_resource` / `unshare_resource` on the
|
|
250
261
|
CLI or in chat (category **Admin**).
|