@smartkomm/plexus-cli 0.1.0 → 0.1.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
@@ -23,6 +23,12 @@ plexus-cli <command> --help # per-command help (clipanion auto-generates it)
23
23
 
24
24
  ### The agent skill
25
25
 
26
+ `plexus-cli agent tools --json` exposes the shared agent tool schemas.
27
+ `plexus-cli agent invoke --tool <name> --json` accepts tool input as JSON on
28
+ stdin. Commands use the same parser as ordinary CLI invocations; workspace
29
+ files are relative to the current directory. See the
30
+ [shared-tools recipe](playbooks/agents/use-shared-tools.md).
31
+
26
32
  On every start the installed CLI keeps an agent skill current for Claude Code
27
33
  (`~/.claude/skills/plexus-cli/`) and Codex (`~/.codex/skills/plexus-cli/`) — whichever
28
34
  of the two exists: `SKILL.md` plus every playbook as `references/`, each marked with the
@@ -127,16 +133,17 @@ and bootstraps a deterministic platform-admin token with the rdu admin key
127
133
  | **catalog** | `catalog {plan,apply} --file catalog.json` · `catalog export --out catalog.json` — articles with the programs selling them, packages, need-based tiers and Word templates of a tenant, by stable key; a DOCX is replaced only when its SHA-256 differs; export → plan is `same`. Recipe [playbooks/config/set-up-billing-catalog.md](./playbooks/config/set-up-billing-catalog.md) |
128
134
  | **applications** | `applications {list,counts} --offer <slug>` · `applications show <id>` · `applications store <id> [--json]` (the process store, every address resolved — [playbooks/applications/inspect-process-store.md](./playbooks/applications/inspect-process-store.md)) · `applications start-test --offer --run <key\|id> --stage <key\|id> (--applicant <email> \| --party <id>) [--staff-input <key>=true\|false …]` (every staff input the offer declares, once each) · `applications discard-test <id>` — recipe [playbooks/applications/start-a-test-application.md](./playbooks/applications/start-a-test-application.md) |
129
135
  | **retention** | `retention plan` (read-only) · `retention apply [--confirm --expect <n>]` — a tenant's applications past their retention period, and their erasure by hand (dry run without `--confirm`; a count other than `--expect` erases nothing). Nothing erases on a schedule; recipe and the DSGVO duty: [playbooks/retention/erase-due-applications.md](./playbooks/retention/erase-due-applications.md). `retention parties plan` · `retention parties apply [--confirm --expect <n>]` — the same for persons past the tenant's deletion rule (hard delete with history and files; blocked persons are listed and skipped, `--expect` counts the deletable ones): [playbooks/retention/erase-due-parties.md](./playbooks/retention/erase-due-parties.md) |
130
- | **test-actions** | `test-actions list --application <id> [--node]` · `test-actions run --application <id> --action <id> [--node] [--no-auto-submit]` — the test-mode popover of a test application (scenarios, `auto-fill-files`, `submit-form`, …); recipe [playbooks/test-actions/drive-a-test-application.md](./playbooks/test-actions/drive-a-test-application.md) |
136
+ | **test-actions** | `test-actions list --application <id> [--node]` · `test-actions run --application <id> --action <id> [--node] [--no-auto-submit] [--param key=value …]` (`--param`: the action's params, values JSON like `call`'s, e.g. `--param confirmed=true` for an action that asks first) — the test-mode popover of a test application (scenarios, `auto-fill-files`, `submit-form`, …); recipe [playbooks/test-actions/drive-a-test-application.md](./playbooks/test-actions/drive-a-test-application.md) |
131
137
  | **migrations** | `migrations status [--recent]` — the deployed release's pending migrations; exit 1 while one is not `success` (recipe [playbooks/worker-ops/verify-migrations.md](./playbooks/worker-ops/verify-migrations.md)) |
132
- | **tokens** | `tokens list`, `tokens create <name>`, `tokens revoke <id>` — minting needs `_platform.apiTokens.manage` (opt-in) or the tenant right `administration.apiTokens.manage` (every `tenant_admin` holds it); list and revoke your own always work. `tokens create <name> --for <email> [--output <csv>] [--quiet]` mints one FOR a tenant administrator to hand over (`_platform.users.manage` AND `_platform.apiTokens.manage`; the target must hold `administration.apiTokens.manage` in a tenant) — recipe [playbooks/users/cli-access-for-tenant-admin.md](./playbooks/users/cli-access-for-tenant-admin.md) |
138
+ | **tokens** | `tokens list`, `tokens create <name>`, `tokens revoke <id>` — minting needs `_platform.apiTokens.manage` (opt-in) or the tenant right `administration.apiTokens.manage` (every `tenant_admin` holds it); list and revoke your own always work. `tokens create <name> --for <email> [--output <csv>] [--quiet]` mints one FOR a tenant administrator or platform operator to hand over (`_platform.users.manage` AND `_platform.apiTokens.manage`; the target must hold `administration.apiTokens.manage` in a tenant, or the platform right `_platform.apiTokens.manage`) — recipe [playbooks/users/cli-access-for-tenant-admin.md](./playbooks/users/cli-access-for-tenant-admin.md) |
133
139
  | **users** | `users {list,show,add,remove,set-group,unset-group,groups,set-platform-admin,set-platform-permission,create,provision,provision-platform-admin,provision-platform-user,set-password,login-trail,set-email,delete,doctor,relink-auth}` — `login-trail <email> [--since 24h]` lists refusals, letters with the relay's answer, sessions and the last password change; `remove` / `unset-group` / `delete` are refused while a `wip` or published workflow's assignment rule names the person (replace them first: „Person ersetzen" in the workflow editor, then publish); `--replace-with <configKey>` hands their active applications over (required while they are responsible for any) and never rewrites a rule |
134
140
  | **platform** | `platform {tenants,users,workers}` |
135
141
  | **stammdaten** | `stammdaten persons [-q] [--limit] [--all] [--deleted]`, `stammdaten persons purge <partyId> [--confirm]` (the only hard delete of a person, plan unless `--confirm`) |
136
142
  | **admission** | `admission laeufe` · `assignment simulate --dir <bundle> --env-json '<json>'\|--env-file <f> [--creator <label>] [--rotation-previous <slot>=<key>]… [--open <key>=<n>]… [--left <key>]…` (evaluate an offer bundle's assignment rule — `graph.assignmentRules` in its `workflow.json`, every slot, the matched row per slot — offline; recipe `playbooks/offer/assignment-rule.md`) |
137
- | **generator** | Contract generators (`finanzen_vertraege.contracts.manage`): `generator {list,show,usages,runs}` · `generator {create,update,clone,seal,archive,restore,delete-draft}` · `generator source {export,save}` · `generator scenarios {test,approve}` · `generator {export,apply}` (one-file round trip) · `generator template {list,upload}` · `generator setup {plan,apply}` (offer setup by catalog keys). **Combined generators**: `generator combined export <key@rev> [--out]` writes the declaration (mask, parts pinned as `key@revision`, names) · `generator combined save <file>` writes it back — onto the exported revision (guarded by `expectedSourceRevision`; an unedited export writes nothing) or, without `id`, as the first draft of a new key · `generator combined plan <key@rev> --input <json>` (sandbox: which parts run, what each misses) · `generator combined create --key … --name … --name-en …` (empty draft); seal/clone/archive with the ordinary verbs. The server's `[generator/…]` refusals print verbatim. Recipe [playbooks/resolver/manage-contract-resolver.md](./playbooks/resolver/manage-contract-resolver.md). |
143
+ | **generator** | Contract generators (`finanzen_vertraege.contracts.manage`): `generator {list,show,usages,runs}` · `generator {create,update,clone,seal,archive,restore,delete-draft}` · `generator source {export,save}` · `generator scenarios {test,approve}` · `generator {export,apply}` (one-file round trip) · `generator template {list,upload}` · `generator setup {plan,apply}` (offer setup by catalog keys). **Combined generators**: `generator combined export <key@rev> [--out]` writes the declaration (mask, parts pinned as `key@revision`, names) · `generator combined save <file>` writes it back — onto the exported revision (guarded by `expectedSourceRevision`; an unedited export writes nothing) or, without `id`, as the first draft of a new key · `generator combined plan <key@rev> --input <json> [--strict]` (sandbox: which parts run, what each misses; exits 0 like `generator test`, with `--strict` 1 when the input would not generate — a missing field, an undecided part, a roster issue, a part's refusal) · `generator combined create --key … --name … --name-en …` (empty draft); seal/clone/archive with the ordinary verbs. The server's `[generator/…]` refusals print verbatim. Recipe [playbooks/resolver/manage-contract-resolver.md](./playbooks/resolver/manage-contract-resolver.md). |
138
144
  | **imports** | `imports {status,trigger,trigger-all}` |
139
145
  | **feedback** | `feedback {list,screenshot,to-issue,sync,set-status}` |
146
+ | **demo** | `demo videos` (the catalogue: id, date, title, length) · `demo link create (--to <name> [--email] \| --from <utf-8 csv> [--out <csv>]) [--video <id>] [--campaign] [--note]` · `demo link list [--campaign]` · `demo link stats [<code> \| --campaign]` · `demo link revoke <code>` · `demo link delete <code> [--confirm]` (erases the link with everything recorded; a dry run without `--confirm`) — personalised links to the public demo video page and their viewing statistics (a visit counts once the page was visible 5 s or the visitor interacted; watched seconds come from the player, `%` = how much the best single visit actually played). Needs `_platform.demoLinks.manage`; recipe [playbooks/marketing/demo-video-links.md](./playbooks/marketing/demo-video-links.md) |
140
147
  | **notifications** | Operator's log (`_platform.notifications.monitor`): `notifications {list,show,retry,sweeper-status,self-test}`; `list` filters by `--status`, `--template`, `--to`, `--since 24h` and shows the relay's answer (`smtp`). Why a sign-in failed: `users login-trail <email> --since 24h` (recipe [playbooks/notifications/trace-a-login.md](./playbooks/notifications/trace-a-login.md)). School's wording (tenant-scoped, `notifications._self.access` / `.mail.configure`): `notifications letters {list,show,set,reset}` · `notifications chrome {show,set}` — see ["The words a school sends"](#the-words-a-school-sends-notifications-letters--chrome). |
141
148
  | **offer** | `offer {create,show,set,delete,restore,list,status}` · `offer run {add,set,archive,restore}` · `offer level {add,rename,move,remove,restore}` · `offer capacity set` · `offer unit {create,ensure-pedagogy}` (make a school applyable: create unit + pedagogy bridge) · `offer {export,validate,plan,diff,apply}` |
142
149
  | **offer form** | `offer form {list,show,add,set,rm}` · `offer form section {add,set,move,rm}` · `offer form field {add,set,move,rm}` · `offer form outcome {add,set,rm}` · `offer form effect {add,set,rm}` · `offer form repeated {add,set,rm}` · `offer form computed {add,set,rm}` · `offer form scenario {add,set,rm}` (test-mode prefills; `--prefill k=v` typed by field; `add --from <id>` derives a variant) · `offer form env set --keys … --sample <scenario>=<json>` (the `$env` keys the form reads) (offline bundle authoring; every mutator runs the real publish-gate validators before writing). `field set` covers all editable props (bucket/placeholder/help-text/enum/enum-ref/enum-list-key/multiple/required-for/docRef/consent + validation expressions; enum/enum-ref/enum-list-key are mutually exclusive — `--enum-list-key` binds a tenant `custom_field_lists` key, `--multiple` makes it multi-select); `effect set` is per-kind (bucket/identity/orgKind/from/to/relKind/target/map); `section set --parent` reparents; `section set --visible-to <key,…>` restricts who on the school's side reads the section's values (`""` clears); `field/section move --before\|--after\|--to-top\|--to-bottom` reorders. Every SmartForm text is ONE `{ de, en }` field: a German text needs its English in the same call (`--label-en`, `--placeholder-en`, `--help-text-en`, …) — the German is never copied into `en`. |
@@ -165,7 +172,14 @@ an empty database once, joins an active seed, or preserves a completed seed.
165
172
  Failed/incomplete seeds and untracked populated databases require an explicit
166
173
  rebuild. Without `--if-needed`, `seed` is destructive. `--applicants none` and
167
174
  `--finance-showcase none` select the lean fixtures; switching local profiles
168
- preserves existing data until an explicit rebuild. Recipe:
175
+ preserves existing data until an explicit rebuild. `--only <cases>` drives just
176
+ those applicant cases and implies `--finance-showcase none` unless
177
+ `--finance-showcase` is given. At most `PLEXUS_SEED_SLOTS` (default 2) seeds run at
178
+ once on one machine, across all checkouts: a seed waits for a free slot (an
179
+ `flock` under `~/.cache/plexus/seed-slots/`, printing who holds them) and keeps it
180
+ until its run is terminal; `--timeout` bounds the wait and the seed together. A
181
+ failed run is reported at once with its phase and error; five unreadable status
182
+ polls in a row end the command with the last error. Recipe:
169
183
  [Initialize or rebuild local demo data](playbooks/worker-ops/rebuild-local-data.md).
170
184
 
171
185
  Every command supports `--json` (raw output; default is a table). Network commands
@@ -513,6 +527,11 @@ argument, an unknown one or a wrong type is named with the expected type
513
527
  (`q=2026` stays `"2026"`). A function the snapshot does not know (explicit `--kind`) is
514
528
  called unchecked, with a note on stderr.
515
529
 
530
+ A refusal prints as `[CODE] <German sentence>` on stderr (every command, not only
531
+ `call`): the server sends `{ de, en }` and the CLI shows the German, which is
532
+ what playbooks quote. A stored text in a result (a failure, a reason) prints as its German
533
+ in tables and as the raw `{ de, en }` under `--json`.
534
+
516
535
  `functions` / `describe` read a committed snapshot (`spec.snapshot.json`).
517
536
  Regenerate it with the tool's in-repo `spec` script (run from
518
537
  `app/tools/plexus-cli/`) after changing a public function's arguments, return
@@ -605,11 +624,24 @@ offers/<tenant>/<offerSlug>/
605
624
  plexus-cli offer export --tenant test --slug grundschule-havelland --out offers/test/gymnasium
606
625
  # edit bundle.yaml (slugs/label/unit/stages/runs) + the JSON blobs
607
626
  plexus-cli offer validate --dir offers/test/gymnasium # offline, real publish gate
608
- plexus-cli offer plan --dir offers/test/gymnasium # remote↔local diff (smartform/workflow = ∅ when absent)
627
+ plexus-cli offer plan --dir offers/test/gymnasium # stamp resolver pins from the env + validate + remote↔local diff (smartform/workflow = ∅ when absent)
609
628
  plexus-cli --env <env> offer apply [--publish] --dir offers/test/gymnasium
610
629
  plexus-cli offer status --tenant test --slug gymnasium-havelland # applyable?
611
630
  ```
612
631
 
632
+ **Resolver pins are stamped from the environment.** A contract node pins
633
+ `resolver: { key, revision }`; publish stamps what that sealed revision says
634
+ (`inputSchema`, `parties`, `schemaDigest`, and `parts` for a combined
635
+ generator). `offer plan` and `offer apply` fetch the same stamp
636
+ (`workflow:getResolverPinStamps`) and write it onto the in-memory bundle
637
+ before validating, so a new combined pin produces `$node.<n>.contracts`
638
+ offline exactly as it will after publish, and the generator's parameters are
639
+ checked against the node's inputs. A pin the environment cannot stamp (no such
640
+ revision, not sealed) is a blocking `[resolver/pinNotStamped]` issue.
641
+ `offer validate` stays offline: it warns about each unstamped pin, and its
642
+ `contract` / `contracts` address checks on such a node are only as good as
643
+ that guess.
644
+
613
645
  **Stage identity.** `program.stages[]` entries are `{ key, name, gradeLevel? }`; `key`
614
646
  is required (`offer validate`). `offer apply` matches levels **by key**: a changed name
615
647
  renames the same row, a new key adds a level, a removed key archives it (refused while
@@ -698,6 +730,11 @@ apply for removals).
698
730
  ### `apply` — the core verb
699
731
  - **Dry-run unless `--confirm`.** The dry-run output *is* the plan: aggregate
700
732
  `created / updated / deleted / unchanged` counts, plus:
733
+ - `+ create <target> <key>` — each row the apply **inserts** (admission custom fields /
734
+ derived attributes included), so `created` is exactly the number of these rows. A
735
+ member of a permission group is named `<group>/<config key or login address>`
736
+ (`foundation.permissionGroups.members`). A deployment that predates the list prints one
737
+ `+ create (unnamed)` line instead.
701
738
  - `~ update <target> <key>` — each config row the apply **patches** (admission custom
702
739
  fields / derived attributes included, dry run too); an idempotent row counts as
703
740
  unchanged, so `updated` is exactly the number of these rows.