@lotics/cli 0.294.1 → 0.295.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/dist/src/cli.js +2290 -1072
- package/docs/cli_reference.md +1 -1
- package/docs/design.md +26 -10
- package/docs/examples.md +18 -7
- package/package.json +1 -1
package/docs/cli_reference.md
CHANGED
|
@@ -43,7 +43,7 @@ Per-command syntax, flags, contracts, and gotchas for the public `lotics` CLI. S
|
|
|
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
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 — 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 …`. |
|
|
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 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. 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. 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) and is refused, naming the tool that deletes it, where an apply never deletes it (a table, a field, an option, an app). A file
|
|
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 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. 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) and is refused, naming the tool that deletes it, where an apply never deletes it (a table, a field, an option, an app). 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 and each other app whose build it changes, `--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. **`--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 — the decisions among its findings, read beside the workspace's rows, with each refused app's patch — 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, 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. |
|
|
47
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. With `-o`, what it wrote is the copy the next `model apply` of that file reads its changes against. |
|
|
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 pull [app_id] [path]` | **A custom-code app's live source, as a project ready to deploy on it.** The target is `[path]`, else this directory when it is the app's project (or no app is named), else `./<name>`. **The app's own project is brought up to date in place** — but only when it holds no edit since the version `package.json#lotics.current_version_id` names: its source (packed as a deploy packs it) is compared with that version's archive, ignoring `.lotics/` and `package.json#lotics`, and any difference refuses the pull, naming the changed files; a pull never merges, so local work is never lost. Already at the live version is a no-op that says so. **An empty or new directory receives the source whole**; any other directory is refused. Downloads come from `GET /v1/apps/{id}/versions/{version_id}/source`. `package.json#lotics` is then set to exactly the app, its workspace and the pulled version, dropping every other key an older CLI wrote there, so the next `lotics app deploy` builds on the live version; then `.lotics/` is written (`get_app_types`) and dependencies installed (`npm ci` with a lockfile, else `npm install`, both `--ignore-scripts`). A JSON app has no source tree: the server's refusal names `get_model`, and `lotics model pull` is its pull. |
|
package/docs/design.md
CHANGED
|
@@ -16,8 +16,11 @@ rows in time, a template's act — until the model states it or declines it.
|
|
|
16
16
|
|
|
17
17
|
1. **People and jobs, before any table.** Name each person by the work they do, then each JOB in one
|
|
18
18
|
sentence: who does it, what exists when it is done, the record it moves. The sentence is the app's
|
|
19
|
-
`name` and `description`.
|
|
20
|
-
app holding every table, is no job's screen.
|
|
19
|
+
`name` and `description`. A job is a desk a person works every day from its own list; one app per job,
|
|
20
|
+
each one register over one entity — an app per table, or one app holding every table, is no job's screen.
|
|
21
|
+
A list worked only in passing on the way through another job — the rates a quote is priced from, the
|
|
22
|
+
transfers its receipts are matched to, the statement sent from its records — is a block, a section or an
|
|
23
|
+
act of that job's app, never an app of its own. A small business usually lands at four to six.
|
|
21
24
|
2. **The entities the jobs touch.** A status is a state the work sits in, six options or fewer: a touch
|
|
22
25
|
("called") is a row of a log, a money fact ("paid in full") a formula the figure shows. A quantity is a
|
|
23
26
|
number with its `unit`, never words in a text field; a quantity of several kinds is child rows, one per
|
|
@@ -51,18 +54,18 @@ then check again. A note refuses nothing.
|
|
|
51
54
|
|---|---|---|
|
|
52
55
|
| People or organisations | `records.<entity>.party`, with a photo or logo as its `image` | `model/records` |
|
|
53
56
|
| Things with a photo, a scan or a paper | `records.<entity>.image`; `layout: "cards"` where the picture is how a row is found | `model/records`, `model/cards` |
|
|
54
|
-
| Read by their day | `layout: "calendar"`; on a record, an `agenda` block | `model/calendar`, `model/
|
|
57
|
+
| Read by their day | `layout: "calendar"`; on a record, an `agenda` block | `model/calendar`, `model/timeline-and-agenda` |
|
|
55
58
|
| Booked on a resource | `layout: "lanes"` with `lanes`, and `write_rules` `no_overlap` | `model/lanes`, `model/write-rules` |
|
|
56
59
|
| A plan of spans | `layout: "gantt"` with `gantt` | `model/gantt` |
|
|
57
60
|
| Who did what on which day | `layout: "roster"` with `roster` | `model/roster` |
|
|
58
|
-
| A log of what happened | a `timeline` block | `model/
|
|
61
|
+
| A log of what happened | a `timeline` block | `model/timeline-and-agenda` |
|
|
59
62
|
| Opened to be worked on | the record's `sections`, in the order the work reaches them — `at` where it moves in steps | `model/record-page` |
|
|
60
63
|
| Rows that each belong to another row | a `rows` block on that row's record | `model/blocks` |
|
|
61
|
-
| Moving through a status | an act per move, `status.history`, and the register's `readings` | `model/acts`, `model/
|
|
64
|
+
| Moving through a status | an act per move, `status.history`, and the register's `readings` | `model/acts`, `model/status`, `model/readings` |
|
|
62
65
|
| Counted over a period | the register's `tabs` over one `period`; an `open` tab's `where` reads only what was true at the period's end, never a status the row moves on from | `model/tabs` |
|
|
63
|
-
| Papers a case gathers | a rows block with `expect`; the papers made, an act's `templates` | `model/blocks`, `model/
|
|
64
|
-
| Papers to read | an act's `intake` with `fills` | `model/
|
|
65
|
-
| Calls and visits | an act's `record` | `model/
|
|
66
|
+
| Papers a case gathers | a rows block with `expect`; the papers made, an act's `templates` | `model/blocks`, `model/papers-and-recordings` |
|
|
67
|
+
| Papers to read | an act's `intake` with `fills` | `model/papers-and-recordings` |
|
|
68
|
+
| Calls and visits | an act's `record` | `model/papers-and-recordings` |
|
|
66
69
|
| Documents covering lines | a rows block with `under` | `model/blocks` |
|
|
67
70
|
| Rows on file a record takes in | a rows block with `pick` | `model/blocks` |
|
|
68
71
|
| One owner's question across jobs | a dashboard app | `model/dashboards` |
|
|
@@ -141,13 +144,26 @@ status holds it, `set` to the next), at the foot of the section whose work it en
|
|
|
141
144
|
condition a person sets. A value decided as a row reaches an outcome — why it was lost, refused, voided — is that
|
|
142
145
|
act's `asks`, never a field the reader must remember to fill. An act reaching past the workspace — sending an invoice
|
|
143
146
|
to a service, a letter by mail — runs its `workflow`, and what the workflow keeps from the answer (an invoice's id,
|
|
144
|
-
its link) is named in `writes`, the act's as what it sets is.
|
|
147
|
+
its link) is named in `writes`, the act's as what it sets is. A stage the work only steps aside into from one step
|
|
148
|
+
and leaves only back to it — a pause, a repair — is a detour: its option and its section stand before that step,
|
|
149
|
+
entered by its own act; listed after, it reads as the work's next step.
|
|
150
|
+
|
|
151
|
+
#### Stages
|
|
152
|
+
|
|
153
|
+
Name each job's work plan by its shape: a status a person sets; a pipeline, where who holds the row and for how long
|
|
154
|
+
matter; or tasks, where only how many are done counts (`records.<entity>.task`). A pipeline states each stage once in
|
|
155
|
+
`records.<entity>.status.stages` — its `owner` (a member field, a link's member field, or a `role`) and its target
|
|
156
|
+
`within` days — and the server holds it: only the owner's acts move the row on, and a level an amount skips stands
|
|
157
|
+
named with why. Late rows, rows due soon, a warning the line draws and rows waiting on the reader stand first in a
|
|
158
|
+
register; a register whose job is a strict order, a first-come queue, states `register.attention: false`.
|
|
145
159
|
|
|
146
160
|
#### History
|
|
147
161
|
|
|
148
162
|
`records.<entity>.status.history` names a child the app's own writes append one row to per status move: its
|
|
149
163
|
link to the row, the new status, the moment and who. It keeps when each row entered each status and who
|
|
150
|
-
moved it
|
|
164
|
+
moved it — what the rail reads. A record's activity shows every move as a change, so `record.history: true` adds
|
|
165
|
+
nothing — and beside `record.activity: false`, which shows them nowhere, it is
|
|
166
|
+
refused. Worked: `examples/approval`.
|
|
151
167
|
|
|
152
168
|
#### Readings
|
|
153
169
|
|
package/docs/examples.md
CHANGED
|
@@ -468,7 +468,7 @@ Every key: the `model` reference, at the pages each section names under **Keys**
|
|
|
468
468
|
|
|
469
469
|
**Read.** `records.customer.party: "organization"` and its `image` (the logo); a `timeline` of touches, a `trend` of its orders, and its papers `expect`ed by kind.
|
|
470
470
|
|
|
471
|
-
**Keys.** `model/records`, `model/blocks`, `model/reading-blocks`
|
|
471
|
+
**Keys.** `model/records`, `model/timeline-and-agenda`, `model/blocks`, `model/reading-blocks`
|
|
472
472
|
|
|
473
473
|
**Not when.** A list of customers is not a job by itself: the customer is a link on the desk whose rows name it, unless the job is the account itself.
|
|
474
474
|
|
|
@@ -701,7 +701,7 @@ Every key: the `model` reference, at the pages each section names under **Keys**
|
|
|
701
701
|
|
|
702
702
|
**Read.** `expect` blocks for the papers brought (one line per kind, the missing ones empty), an act's `templates` for the forms made (ticked and made at once, kept in `into`), and `intake` reading the papers brought.
|
|
703
703
|
|
|
704
|
-
**Keys.** `model/blocks`, `model/
|
|
704
|
+
**Keys.** `model/blocks`, `model/papers-and-recordings`
|
|
705
705
|
|
|
706
706
|
**Not when.** A record that needs no papers, or one paper made once — a single `template` act.
|
|
707
707
|
|
|
@@ -1113,7 +1113,7 @@ Every key: the `model` reference, at the pages each section names under **Keys**
|
|
|
1113
1113
|
|
|
1114
1114
|
**Read.** An act's `record` (into the `timeline` child: audio, transcript, when and who) and `fills` (the touch's fields an agent fills from the transcript).
|
|
1115
1115
|
|
|
1116
|
-
**Keys.** `model/
|
|
1116
|
+
**Keys.** `model/papers-and-recordings`, `model/timeline-and-agenda`
|
|
1117
1117
|
|
|
1118
1118
|
**Not when.** Calls made and logged elsewhere — a `timeline` with its own add keeps the note.
|
|
1119
1119
|
|
|
@@ -1441,7 +1441,7 @@ Every key: the `model` reference, at the pages each section names under **Keys**
|
|
|
1441
1441
|
|
|
1442
1442
|
**Read.** `records.de_nghi.status` with its `history` (each move: when and who), sections staged by `at`, and `register.readings` leading with the headline number.
|
|
1443
1443
|
|
|
1444
|
-
**Keys.** `model/
|
|
1444
|
+
**Keys.** `model/status`, `model/record-page`, `model/readings`
|
|
1445
1445
|
|
|
1446
1446
|
**Not when.** Rows that never move — a reference list (a price list, a catalog) has no status and no headline number.
|
|
1447
1447
|
|
|
@@ -1479,6 +1479,7 @@ Every key: the `model` reference, at the pages each section names under **Keys**
|
|
|
1479
1479
|
"options": [
|
|
1480
1480
|
{"alias": "nhap", "color": "slate"},
|
|
1481
1481
|
{"alias": "cho_duyet", "color": "amber"},
|
|
1482
|
+
{"alias": "cho_chu_tich", "color": "violet"},
|
|
1482
1483
|
{"alias": "da_duyet", "color": "blue"},
|
|
1483
1484
|
{"alias": "da_chi", "color": "green"},
|
|
1484
1485
|
{"alias": "tu_choi", "color": "rose"}
|
|
@@ -1502,7 +1503,17 @@ Every key: the `model` reference, at the pages each section names under **Keys**
|
|
|
1502
1503
|
"de_nghi": {
|
|
1503
1504
|
"title": "noi_dung",
|
|
1504
1505
|
"subtitle": ["du_an"],
|
|
1505
|
-
"status": {
|
|
1506
|
+
"status": {
|
|
1507
|
+
"field": "trang_thai",
|
|
1508
|
+
"closed": ["da_chi", "tu_choi"],
|
|
1509
|
+
"history": "lich_su_duyet",
|
|
1510
|
+
"stages": {
|
|
1511
|
+
"nhap": {"owner": "nguoi_de_nghi"},
|
|
1512
|
+
"cho_duyet": {"owner": {"role": "giam_doc"}, "within": 1},
|
|
1513
|
+
"cho_chu_tich": {"owner": {"role": "chu_tich"}, "within": 2},
|
|
1514
|
+
"da_duyet": {"owner": {"role": "ke_toan"}, "within": 2}
|
|
1515
|
+
}
|
|
1516
|
+
},
|
|
1506
1517
|
"figure": "so_tien",
|
|
1507
1518
|
"limits": {"da_duyet_du_an": "ngan_sach_du_an"},
|
|
1508
1519
|
"due": ["han_thanh_toan"],
|
|
@@ -1544,7 +1555,7 @@ Every key: the `model` reference, at the pages each section names under **Keys**
|
|
|
1544
1555
|
},
|
|
1545
1556
|
{
|
|
1546
1557
|
"title": "Duyệt",
|
|
1547
|
-
"at": ["cho_duyet"],
|
|
1558
|
+
"at": ["cho_duyet", "cho_chu_tich"],
|
|
1548
1559
|
"fields": ["nguoi_duyet", "duyet_luc", "ly_do_tu_choi"],
|
|
1549
1560
|
"acts": ["rut_lai"]
|
|
1550
1561
|
},
|
|
@@ -1562,7 +1573,7 @@ Every key: the `model` reference, at the pages each section names under **Keys**
|
|
|
1562
1573
|
{
|
|
1563
1574
|
"alias": "rut_lai",
|
|
1564
1575
|
"label": "Rút lại",
|
|
1565
|
-
"when": {"trang_thai": ["cho_duyet"]},
|
|
1576
|
+
"when": {"trang_thai": ["cho_duyet", "cho_chu_tich"]},
|
|
1566
1577
|
"set": {"trang_thai": "nhap"},
|
|
1567
1578
|
"confirm": true
|
|
1568
1579
|
}
|