@tikoci/centrs 0.1.9-next.24 → 0.1.9
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/CHANGELOG.md +121 -6
- package/GLOSSARY.txt +9 -1
- package/README.md +43 -29
- package/commands/api/AGENTS.md +3 -2
- package/commands/api/README.md +8 -1
- package/commands/btest/README.md +9 -0
- package/commands/btest/examples.md +7 -0
- package/commands/devices/README.md +160 -30
- package/commands/devices/examples.md +168 -2
- package/commands/execute/README.md +13 -2
- package/commands/explain/README.md +223 -3
- package/commands/explain/examples.md +8 -1
- package/commands/retrieve/README.md +24 -3
- package/commands/retrieve/examples.md +84 -0
- package/commands/settings/README.md +6 -0
- package/commands/settings/examples.md +17 -0
- package/commands/transfer/README.md +25 -0
- package/commands/transfer/examples.md +46 -0
- package/docs/CLI.md +53 -11
- package/docs/MATRIX.md +5 -3
- package/docs/errors/cdb/encrypt-failed.md +10 -0
- package/docs/errors/cdb/password-required.md +5 -4
- package/docs/errors/cdb/plaintext-backups.md +11 -0
- package/docs/errors/input/empty-stdin.md +27 -0
- package/docs/errors/input/invalid-routeros-path.md +25 -3
- package/docs/errors/input/invalid-stdin.md +28 -0
- package/docs/errors/usage/stdin-is-tty.md +21 -0
- package/package.json +11 -7
- package/src/api-fanout.ts +2 -0
- package/src/api.ts +12 -0
- package/src/btest.ts +7 -0
- package/src/cli/api.ts +19 -2
- package/src/cli/btest.ts +9 -0
- package/src/cli/common.ts +1 -0
- package/src/cli/devices.ts +248 -15
- package/src/cli/execute.ts +12 -3
- package/src/cli/retrieve.ts +9 -0
- package/src/cli/settings.ts +28 -6
- package/src/cli/terminal.ts +9 -0
- package/src/cli/transfer.ts +10 -1
- package/src/core/error-catalog.ts +28 -2
- package/src/core/menu-path.ts +89 -0
- package/src/devices.ts +378 -33
- package/src/execute-fanout.ts +2 -0
- package/src/execute.ts +7 -0
- package/src/explain/blocks.ts +2 -2
- package/src/explain/catalog.ts +22 -12
- package/src/explain/pasted-prompt.ts +198 -0
- package/src/explain/pathresolve.ts +2 -2
- package/src/explain/segment.ts +2 -2
- package/src/explain/symbols.ts +2 -2
- package/src/explain/verbsplit.ts +2 -2
- package/src/explain/write.ts +2 -2
- package/src/explain.ts +2 -0
- package/src/index.ts +5 -0
- package/src/mcp/safety.ts +7 -6
- package/src/mcp/tools.ts +30 -68
- package/src/protocols/adapter.ts +2 -0
- package/src/protocols/btest-session.ts +10 -30
- package/src/protocols/ec-srp5.ts +19 -10
- package/src/protocols/mac-telnet-console.ts +2 -2
- package/src/resolver/cdb.ts +66 -9
- package/src/resolver/index.ts +1 -0
- package/src/resolver/quickchr-provider.ts +5 -0
- package/src/resolver/selection.ts +15 -4
- package/src/retrieve-fanout.ts +2 -0
- package/src/retrieve.ts +11 -0
- package/src/settings.ts +24 -8
- package/src/terminal.ts +7 -0
- package/src/transfer-fanout.ts +2 -0
- package/src/transfer.ts +79 -14
package/CHANGELOG.md
CHANGED
|
@@ -10,13 +10,36 @@ Each stable version has one section. Work in progress goes under
|
|
|
10
10
|
`## X.Y.Z — next`, which is what `@next` installs (`X.Y.Z-next.N`); the stable
|
|
11
11
|
release dates that heading. A `-next.N` build has no section of its own.
|
|
12
12
|
|
|
13
|
-
## 0.1.9 —
|
|
13
|
+
## 0.1.9 — 2026-11-03
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
part of this section.
|
|
15
|
+
The `0.1.9-next.0` preview cut (2026-10-13) carried part of this section.
|
|
17
16
|
|
|
18
17
|
### Added
|
|
19
18
|
|
|
19
|
+
- `explain` publishes a syntactic statement tree (#497, #522): statement
|
|
20
|
+
`id`/`parent`, substitution `owner`, and block ownership/index links let
|
|
21
|
+
consumers locate nested source without inferring ancestry from spans.
|
|
22
|
+
Stored script and callback bodies remain opaque; ownership does not claim
|
|
23
|
+
execution or lexical inheritance.
|
|
24
|
+
- `devices add`/`set --password-stdin` reads the record password from stdin,
|
|
25
|
+
so automation can write a credential without it showing in argv or `ps`
|
|
26
|
+
(#582). One trailing `\n` or `\r\n` is stripped. Empty input is
|
|
27
|
+
`input/empty-stdin`, non-UTF-8 bytes or a leading byte-order mark are
|
|
28
|
+
`input/invalid-stdin`, a terminal on stdin is `usage/stdin-is-tty`, and
|
|
29
|
+
combining it with `--password` is `usage/conflicting-flags`. Other `devices`
|
|
30
|
+
subcommands refuse the flag.
|
|
31
|
+
- `explain` offers a non-applied repair tip for pasted console prompts
|
|
32
|
+
(#370, #567, #578), including `[user@host] /menu>` and HotLock `>>` forms.
|
|
33
|
+
The candidate preserves command separators and names the menu context;
|
|
34
|
+
multiline repairs render as fenced code. The original analysis stays intact.
|
|
35
|
+
- `--match user=<name>|target=<addr>|<record-type>` on `retrieve`, `execute`,
|
|
36
|
+
`api`, `transfer`, `terminal` and `btest client` picks one of several CDB
|
|
37
|
+
records saved for the same `<router>` (#583), as `devices show --match`
|
|
38
|
+
does. One address saved under two users was `identity/ambiguous` on every
|
|
39
|
+
command, and the error named a `--match` they rejected. The flag is
|
|
40
|
+
single-target: with a fan-out selection or `--quickchr` it is
|
|
41
|
+
`usage/conflicting-flags`, and with no CDB record in play it is
|
|
42
|
+
`identity/no-match` rather than ignored.
|
|
20
43
|
- **Live `explain` over rest-api + native-api is `CHR-passed`** (#236).
|
|
21
44
|
Examples 7–16, 19, 24, 48 and 52–53 pass on both transports on stable
|
|
22
45
|
7.24.5 and long-term 7.23.8. `runtimeAcceptance` stays `not-proven`.
|
|
@@ -92,9 +115,33 @@ part of this section.
|
|
|
92
115
|
client, its controller.
|
|
93
116
|
- `execute --cmr` accepts a command that opens with a relative menu change
|
|
94
117
|
(`/system; identity/print`); its `:parse` return was read as incomplete.
|
|
118
|
+
- CDB encryption lifecycle (#558). `devices init --encrypt` creates an
|
|
119
|
+
encrypted empty CDB; `devices encrypt` converts an existing open CDB in place
|
|
120
|
+
with a fresh salt, keeping its records, unknown fields, and file mode. Both
|
|
121
|
+
need a non-empty `--cdb-password` / `CENTRS_CDB_PASSWORD`; a password alone
|
|
122
|
+
still never converts. Conversion keeps every backup and writes a plaintext
|
|
123
|
+
snapshot unless `--no-backup` is passed. It warns with `cdb/plaintext-backups`.
|
|
124
|
+
An already-encrypted file is verified and left unchanged. Library:
|
|
125
|
+
`initCdb({ encrypt })`, `encryptCdb({ skipBackup })`. `init` results now
|
|
126
|
+
include `encrypted`. `init` and `encrypt` refuse flags they would otherwise
|
|
127
|
+
ignore (`--user`, `--group`, `--via`, …) with `input/invalid-command`.
|
|
95
128
|
|
|
96
129
|
### Changed
|
|
97
130
|
|
|
131
|
+
- Bun 1.4.4 is the minimum supported version (`engines.bun: >=1.4.4 <2`, was
|
|
132
|
+
`>=1.3.11 <2`). The CI/release/Pages `packageManager` pin, Docker image and
|
|
133
|
+
`@types/bun` now use 1.4.4 together (0.1.8 shipped on 1.3.14; #438).
|
|
134
|
+
- **Breaking:** `devices show`, `add` and `set` no longer print the record password
|
|
135
|
+
(#551). Text and JSON carry `passwordSet: boolean` instead, and
|
|
136
|
+
`--show-password` on those three subcommands opts back in; other subcommands
|
|
137
|
+
refuse the flag. The `--explain` record's password field reads `<redacted>`
|
|
138
|
+
unless the flag is given, as does an unknown-tcode tail that may hold the
|
|
139
|
+
password. **Library consumers:** exported `showDevice`,
|
|
140
|
+
`addDevice` and `setDevice` now redact too. `DevicesShowItem` has no
|
|
141
|
+
`password` field; pass `showPassword: true` to get
|
|
142
|
+
`DevicesShowItemWithPassword`. MCP output is unchanged (it already redacted)
|
|
143
|
+
and now uses the same core redaction. Dialing with CDB credentials is
|
|
144
|
+
unaffected: the resolver and MCP allowlist read the raw record.
|
|
98
145
|
- **Breaking:** permission and edge-auth failures get their own error codes
|
|
99
146
|
(#541). Three codes change for `--json` and library readers:
|
|
100
147
|
- A REST policy refusal (HTTP 500 `not enough permissions (9)` or `std
|
|
@@ -181,9 +228,7 @@ part of this section.
|
|
|
181
228
|
`/cmr/upgrade/trigger`, `/cmr/upgrade/job/run-next`) are pinned as writes in
|
|
182
229
|
every spelling, over `execute`, `api` and MCP `mcp=ro`. On 7.26beta1 a
|
|
183
230
|
controller login with only `read` + `api` can run them (#456).
|
|
184
|
-
-
|
|
185
|
-
version local development already used; `@types/bun` moves with it (#438).
|
|
186
|
-
`engines.bun` stays `>=1.3.11 <2`. The `typescript` peer stays `^6.0.3`:
|
|
231
|
+
- The `typescript` peer stays `^6.0.3`:
|
|
187
232
|
the source passes `tsc --noEmit` under TypeScript 7.0.2, but typedoc 0.28 (the
|
|
188
233
|
API reference build) supports TypeScript up to 6.0.x only.
|
|
189
234
|
- QA records a CHR leg in `qa-history` only when its test step passed or
|
|
@@ -201,6 +246,60 @@ part of this section.
|
|
|
201
246
|
|
|
202
247
|
### Fixed
|
|
203
248
|
|
|
249
|
+
- Help now lists SSH for `execute --via`, the offline analyzer before device
|
|
250
|
+
validation for `execute` and `api /execute`, and `devices --match` on
|
|
251
|
+
`show`/`set`/`remove`. `devices --group` names `add`/`set`, and
|
|
252
|
+
`devices init --help` / `encrypt --help` show only the flags they accept.
|
|
253
|
+
The generated CLI reference includes both file-command help sections.
|
|
254
|
+
- Offline `explain` withdraws unsupported readings of unlisted bare paths
|
|
255
|
+
and space-for-`=` arguments (#211, #350), distinguishes command operands
|
|
256
|
+
from menu blocks (#496), and correctly reads `where` arrays, column-0
|
|
257
|
+
array comments and nested relative submenu blocks (#502, #503, #351).
|
|
258
|
+
- Offline `explain` rejects CHR-grounded group, operator, escape, variable,
|
|
259
|
+
name and glued-token faults (#505, #511, #506, #518), including unquoted
|
|
260
|
+
`?`, backticks, second argument `=` and non-ASCII bytes (#358, #371).
|
|
261
|
+
Quoted values and accepted controls retain their supported readings.
|
|
262
|
+
A stray top-level `}` or `]` warns `discarded-close` and marks the
|
|
263
|
+
unread tail; the execution gate refuses it because RouterOS would discard
|
|
264
|
+
part of the submitted script (#504).
|
|
265
|
+
- `explain` block spans use analyzed UTF-8 byte offsets, matching statements
|
|
266
|
+
and tokens even after Unicode text (#523, #524).
|
|
267
|
+
- `settings get <attr>` works in text mode (#587). It crashed reading
|
|
268
|
+
`typed.source` because the text renderer treated `get`'s single entry as
|
|
269
|
+
`print`'s key-to-entry map; `--json` was unaffected. It now prints one
|
|
270
|
+
`key: value [source: …]` line in `print`'s format, under the canonical attr
|
|
271
|
+
name, and the JSON envelope names that key in `meta.operation.attr`. A fault
|
|
272
|
+
after the arguments parse is now `internal/settings-failed` (exit 1), not
|
|
273
|
+
`input/invalid-command` with `--help` advice.
|
|
274
|
+
- **`retrieve` and `api` can no longer send a non-read** (#586). A `#` or
|
|
275
|
+
`?` in the path cut the appended `/print` off the REST URL, so
|
|
276
|
+
`retrieve '/system/reboot#' --no-validate --attribute uptime` posted
|
|
277
|
+
`/rest/system/reboot` and rebooted CHR 7.24.5 without `--yes`; `api` with a
|
|
278
|
+
projection did the same. Both now require every path segment to be a
|
|
279
|
+
RouterOS menu name (letters, digits, hyphens; case folds) on every
|
|
280
|
+
transport, even with `--validate=false`, failing
|
|
281
|
+
`input/invalid-routeros-path` before resolution. The REST adapter also
|
|
282
|
+
refuses any request path containing `?`, `#`, `\`, control characters or a
|
|
283
|
+
dot segment (including `%2e%2e`), for every command. Reported by
|
|
284
|
+
routeros-muse.
|
|
285
|
+
- `devices set <target> key=` removes the comment token instead of storing an
|
|
286
|
+
empty value, as documented (#590). Removing an absent token is a no-op;
|
|
287
|
+
`--password ""` still clears the password, and bare `password=`/`user=`
|
|
288
|
+
stay `cdb/reserved-key`.
|
|
289
|
+
- `transfer` honors a CDB record's `via=` preference (#591). A record with
|
|
290
|
+
`via=ssh` drove `execute` over SSH but transfer ignored it and needed
|
|
291
|
+
`--via sftp`. Transfer now maps the record's transport to a method
|
|
292
|
+
(`ssh`→`sftp`, `rest-api`→`rest`, `native-api`→`native`) after `--via` and
|
|
293
|
+
`CENTRS_TRANSFER_VIA`, and accepts `--via ssh` as an alias of `sftp`. A
|
|
294
|
+
record transport that cannot carry files fails `settings/invalid-via`
|
|
295
|
+
naming the record; a record-pinned REST upload over 60 KB names the record
|
|
296
|
+
in its `transport/unsupported-operation` remediation.
|
|
297
|
+
- The `explain` catalog generator skips the CLI Reference's new
|
|
298
|
+
`compare-versions` widget page (2026-10-30). The page carries no command
|
|
299
|
+
entry, and it aborted the catalog drift report. The refreshed catalog adds
|
|
300
|
+
10 published paths (`/interface/wifi/easymesh/*`,
|
|
301
|
+
`/app/settings/remove-certificate`, three `/system/resource/hardware`
|
|
302
|
+
commands), and the `/cmr/client` gates drop `!powerpc`.
|
|
204
303
|
- `retrieve --sample`, `--follow` and `--wait` no longer report a validation
|
|
205
304
|
verdict the gate never gave (#537). A cancellation before the gate ran now
|
|
206
305
|
reports the device stage `not reached` (`interrupted` for `--sample` and
|
|
@@ -277,6 +376,12 @@ part of this section.
|
|
|
277
376
|
`:for from=1 counter=i to=2` binds `i`, so later `$` references link;
|
|
278
377
|
previously the argument name was declared and a reordered `counter=` left
|
|
279
378
|
`$i` unbound.
|
|
379
|
+
- EC-SRP5 hashes shared `z` and the REDP1 loop seed minimal-length, as
|
|
380
|
+
RouterOS does (#565). centrs padded both to 32 bytes, following `mtwei.c`.
|
|
381
|
+
As a result, about 1 in 256 MAC-Telnet logins failed on a short `z`. On
|
|
382
|
+
both MAC-Telnet and btest, every login failed for an account whose salt hit
|
|
383
|
+
the REDP1 edge, about 1 in 317 password changes. btest's `z`-only workaround
|
|
384
|
+
(#516) is replaced by the shared fix.
|
|
280
385
|
- mac-telnet with an explicit directed-broadcast `--host` (`192.168.74.255`)
|
|
281
386
|
sends the owning interface's real MAC (#546, #547). On Linux, `connect()` to
|
|
282
387
|
a broadcast reports `0.0.0.0`, so the session fell back to a synthetic
|
|
@@ -286,6 +391,16 @@ part of this section.
|
|
|
286
391
|
|
|
287
392
|
### Maintenance
|
|
288
393
|
|
|
394
|
+
- QA allows 50 minutes per CHR leg so the full integration suite can finish
|
|
395
|
+
(#611).
|
|
396
|
+
- The explain corpus uses schema 5 and one reader, with pinned channel
|
|
397
|
+
sessions, a regenerated highlight slice and a wiresage conformance gate
|
|
398
|
+
(#498, #514, #515). Bounded-execution tests use deterministic structural
|
|
399
|
+
work guards instead of depth-cap timing (#521).
|
|
400
|
+
- The explain contract records proposed topic checks and related live reads
|
|
401
|
+
(#493), the CHR-grounded context submission matrix (#574), and import
|
|
402
|
+
verbose dry-run behavior (#520). These are design/grounding evidence;
|
|
403
|
+
`--context`, topic checks and contextual reads are not shipped CLI options.
|
|
289
404
|
- Releases are one dispatch from `main` (#484, #485). `@next` publishes
|
|
290
405
|
`X.Y.Z-next.<run_number>` with no commit, PR or tag, and reuses main's QA
|
|
291
406
|
run on the commit instead of sweeping every channel again. `@latest` creates
|
package/GLOSSARY.txt
CHANGED
|
@@ -94,6 +94,7 @@ cwd
|
|
|
94
94
|
datagram
|
|
95
95
|
davidanson
|
|
96
96
|
DDNS
|
|
97
|
+
dsv # `:serialize to=dsv` delimiter-separated-values format (RouterOS 7.x); the #374 comma-value control pins offline acceptance of a `delimiter=,` value
|
|
97
98
|
dialable # an endpoint a client can actually connect to (advertised AND reachable)
|
|
98
99
|
defconf
|
|
99
100
|
demux
|
|
@@ -116,6 +117,7 @@ fat-chr
|
|
|
116
117
|
figcaption
|
|
117
118
|
FlaUI
|
|
118
119
|
frontends
|
|
120
|
+
frontmatter # YAML metadata block at the top of a Markdown file (e.g. instruction applyTo headers)
|
|
119
121
|
haakonnessjoen
|
|
120
122
|
Hammerspoon
|
|
121
123
|
HMAC
|
|
@@ -373,6 +375,8 @@ underflows
|
|
|
373
375
|
Werror
|
|
374
376
|
|
|
375
377
|
# MTWEI / EC-SRP vocabulary (src/protocols/mtwei.ts, mac-telnet auth)
|
|
378
|
+
# libucrypto: RouterOS's shared cryptography library; EC-SRP5 encoding source.
|
|
379
|
+
libucrypto
|
|
376
380
|
# docrypto: mtwei.c's client EC-SRP proof function (mtwei_docrypto), ported to TS.
|
|
377
381
|
docrypto
|
|
378
382
|
# redp: REDP1 (IEEE P1363.2) random-point derivation used in the MTWEI tangle.
|
|
@@ -721,8 +725,11 @@ remoteap # caps-man definition module for `/caps-man/remote-cap`
|
|
|
721
725
|
seccfg # caps-man definition module for `/caps-man/security`
|
|
722
726
|
ifaces # CLI-Reference definition module for `/tool/graphing/interface`
|
|
723
727
|
datapath # `/caps-man/datapath` — the real CLI menu behind `dpathcfg`
|
|
724
|
-
easymesh # `/interface/wifi/easymesh` —
|
|
728
|
+
easymesh # `/interface/wifi/easymesh` — once a doc spelling of `/interface/wifi/wps-push-button`; published as its own ungated menu since 2026-10-30, in no CHR tree through 7.26beta3
|
|
725
729
|
wps # Wi-Fi Protected Setup — `/interface/wifi/wps-push-button`
|
|
730
|
+
bss # Wi-Fi basic service set — `/interface/wifi/easymesh/bss`
|
|
731
|
+
dpp # Wi-Fi Device Provisioning Protocol — `/interface/wifi/easymesh/dpp-trigger`
|
|
732
|
+
overcurrent # `/system/resource/hardware/reset-overcurrent`, gated by syscap `usb-hub`
|
|
726
733
|
qos # switch-chip quality of service — `/interface/ethernet/switch/qos`, a real menu segment R1 must never drop
|
|
727
734
|
qca # Qualcomm Atheros — the `wireless-qca` package gate
|
|
728
735
|
multiswitch # syscap gate: more than one switch chip
|
|
@@ -807,6 +814,7 @@ zzznotamenu # a menu name no RouterOS build has — `/ip { zzznotamenu { print }
|
|
|
807
814
|
# #361 absent-menu controls. Deliberate NON-words: each names a path no RouterOS
|
|
808
815
|
# build has, or quotes a published gate verbatim, so the spelling is load-bearing.
|
|
809
816
|
nosuch # a top-level menu no RouterOS build has — `/nosuch` is `bad command name nosuch` on CHR 7.23.7, the `validation/unknown-path` control (#361)
|
|
817
|
+
nosuchcmd # a root command no RouterOS build has — `:local varID [nosuchcmd where name=x]` is `bad command name nosuchcmd (line 1 column 15)` on CHR 7.25 and 7.23.8, the #374 unknown-command control
|
|
810
818
|
nosuchmenu # a submenu no RouterOS build has — `/ip/nosuchmenu/print` is `syntax error (line 1 column 15)` on CHR 7.23.7, pointing at the `/` after it (#361)
|
|
811
819
|
nosuchverb # a command no RouterOS build has under a real menu — `/ip/address/nosuchverb` is `bad command name nosuchverb` on CHR 7.23.7 (#361)
|
|
812
820
|
qqq # the second segment of the parse-oracle row `/zzz qqq print`, captured on CHR 7.23.3 (GH#230)
|
package/README.md
CHANGED
|
@@ -4,21 +4,21 @@
|
|
|
4
4
|
CLI (with an MCP server; TUI and HTTP proxy frontends planned) for talking to
|
|
5
5
|
MikroTik RouterOS devices through a regularized, validated interface.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
installing centrs or connecting to a router:
|
|
7
|
+
Stable releases are published on npm under `latest`. To try the offline
|
|
8
|
+
analyzer without installing centrs or connecting to a router:
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
bunx @tikoci/centrs@
|
|
11
|
+
bunx @tikoci/centrs@latest explain '/ip/address print' --json
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Use `bunx @tikoci/centrs@
|
|
15
|
-
`bunx @tikoci/centrs@
|
|
14
|
+
Use `bunx @tikoci/centrs@latest --help` to inspect the release CLI, and
|
|
15
|
+
`bunx @tikoci/centrs@latest --version` (`-V`; `--json` for an envelope) to print
|
|
16
16
|
the exact version for scripts and field reports. The dist-tag follows standard
|
|
17
|
-
SemVer semantics: a plain version (`0.1.
|
|
18
|
-
`next` forward with it, while a `next` build (`0.1.
|
|
17
|
+
SemVer semantics: a plain version (`0.1.9`) publishes to `latest` and carries
|
|
18
|
+
`next` forward with it, while a `next` build (`0.1.10-next.23`) publishes to
|
|
19
19
|
`next` only and never moves `latest`. A `next` build is described by the
|
|
20
|
-
`##
|
|
21
|
-
leading edge and can equal `@latest` between cuts —
|
|
20
|
+
next version's `## X.Y.Z — next` section of [`CHANGELOG.md`](CHANGELOG.md).
|
|
21
|
+
So `@next` is the leading edge and can equal `@latest` between cuts —
|
|
22
22
|
`npm view @tikoci/centrs dist-tags` is the authority.
|
|
23
23
|
|
|
24
24
|
The full flag reference for every command is generated from the CLI metadata
|
|
@@ -40,7 +40,8 @@ product; without them this would just be a worse `curl`.
|
|
|
40
40
|
> Check current dist-tags with
|
|
41
41
|
> `npm view @tikoci/centrs dist-tags --json`. The library, device registry, and
|
|
42
42
|
> first MCP server phases are CHR-verified; the CLI is wired (`coded`);
|
|
43
|
-
> encrypted-CDB writes are
|
|
43
|
+
> encrypted-CDB reads and writes are supported, and the TUI/proxy frontends
|
|
44
|
+
> are planned.
|
|
44
45
|
> `docs/MATRIX.md` is the single source of truth for what works today — treat
|
|
45
46
|
> anything not green there as not-yet-shipped.
|
|
46
47
|
|
|
@@ -49,9 +50,10 @@ product; without them this would just be a worse `curl`.
|
|
|
49
50
|
- **Frontends:** TypeScript API, CLI, MCP server (Phase 1 + first Phase 2 CDB
|
|
50
51
|
mutation `CHR-passed` — see `commands/mcp/`), TUI and HTTP proxy/daemon
|
|
51
52
|
(future).
|
|
52
|
-
- **Protocols:** REST API
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
- **Protocols:** REST API and native API for reads and writes; SSH / MAC-Telnet
|
|
54
|
+
for execution and interactive terminals; SFTP for file transfer; MNDP for
|
|
55
|
+
discovery; bandwidth test for peer measurement. SNMP, RoMON and WinBox
|
|
56
|
+
Terminal are planned. centrs picks the protocol for you (and lets you pin one
|
|
55
57
|
with `via=` or `--via`).
|
|
56
58
|
- **Commands:** every router-facing command resolves a *target* — a router you
|
|
57
59
|
name on the CLI — to a real address, credentials, and a protocol, then runs.
|
|
@@ -60,12 +62,14 @@ product; without them this would just be a worse `curl`.
|
|
|
60
62
|
|
|
61
63
|
| Command | Purpose |
|
|
62
64
|
| ---------- | ------- |
|
|
63
|
-
| `retrieve` | Read RouterOS state over REST/native API
|
|
64
|
-
| `execute` | Run RouterOS CLI-shaped read/write commands (add/set/remove) over native API
|
|
65
|
+
| `retrieve` | Read RouterOS state over REST/native API. `--follow` keeps a menu's rows current over native API (snapshot, then a line per change; NDJSON); `--sample <interval>` re-reads it on a timer for counters; `--query` filters on the router with the `print where` grammar; `--wait` retries until a read succeeds (or an optional `--until` condition holds), up to a deadline. SNMP OID/MIB reads are planned. |
|
|
66
|
+
| `execute` | Run RouterOS CLI-shaped read/write commands (add/set/remove) over native API, REST, SSH or MAC-Telnet. |
|
|
65
67
|
| `api` | Structured RouterOS API passthrough (gh-api style): one command per operation, structured in/out, can write, over REST or native API. Follow changes with `api … <menu>/listen`; `--stream` streams any command's replies (native API; NDJSON). |
|
|
66
68
|
| `terminal` | Open an interactive console, primarily SSH or MAC-Telnet. |
|
|
69
|
+
| `transfer` | Upload, download and manage device files over REST/native API or SFTP; `upload` and `download` are shortcuts. |
|
|
70
|
+
| `btest` | Run a MikroTik bandwidth-test client or server over TCP/UDP. |
|
|
67
71
|
| `check` | Probe reachability and management protocol availability. **Designed, not implemented** — see `docs/MATRIX.md`. |
|
|
68
|
-
| `explain` | Analyze
|
|
72
|
+
| `explain` | Analyze RouterOS source offline, or add read-only device evidence over REST/native API, including path schemas, completion candidates and value types. Runtime acceptance remains unproven. |
|
|
69
73
|
| `devices` | View and maintain the CDB-backed device registry (the only writer). |
|
|
70
74
|
| `discover` | Discover MNDP neighbors and optionally save them into the CDB. |
|
|
71
75
|
| `settings` | Manage centrs's own settings (`centrs.env`, `__default__`) and run first-time setup. |
|
|
@@ -92,7 +96,9 @@ stores:
|
|
|
92
96
|
comment carries `identity=edge1`. Every other comment token stays inert prose.
|
|
93
97
|
See `commands/devices/README.md` (Identity model) for the full resolution rules.
|
|
94
98
|
- **`user` / `password`** — the credentials centrs connects with. They stay in
|
|
95
|
-
the CDB
|
|
99
|
+
the CDB. `devices show` / `add` / `set` withhold the password and report
|
|
100
|
+
`passwordSet` (`--show-password` reveals it); MCP results/resources always
|
|
101
|
+
redact it.
|
|
96
102
|
- **`group`, `profile`, `session`, port** — used as-is.
|
|
97
103
|
|
|
98
104
|
So `centrs retrieve edge1 /ip/address` works with no flags: `edge1` is looked
|
|
@@ -168,18 +174,24 @@ so you can always see *why* a given port or transport was chosen.
|
|
|
168
174
|
|
|
169
175
|
`devices` is the only command that writes the CDB, and it does so safely
|
|
170
176
|
(timestamped backup, atomic rename, unknown WinBox fields preserved verbatim).
|
|
171
|
-
Encrypted-CDB
|
|
172
|
-
|
|
177
|
+
Encrypted-CDB reads and writes work with `--cdb-password` /
|
|
178
|
+
`CENTRS_CDB_PASSWORD`; writes decrypt, mutate and re-encrypt with a fresh salt.
|
|
179
|
+
`devices init --encrypt` creates an encrypted registry, and `devices encrypt`
|
|
180
|
+
explicitly converts an existing open CDB. Conversion retains existing backups
|
|
181
|
+
and warns that plaintext copies remain. The manual WinBox round-trip is still
|
|
182
|
+
pending; see the per-command contract for the current evidence and limits.
|
|
173
183
|
The full contract — identity resolution, ambiguity handling, write strategy,
|
|
174
184
|
and the comment grammar — lives in `commands/devices/README.md` and
|
|
175
185
|
`docs/CONSTITUTION.md` (Identity and CDB).
|
|
176
186
|
|
|
177
187
|
## The result envelope, validation, and errors
|
|
178
188
|
|
|
179
|
-
- **Validation is on by default** (`validate=true`).
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
- **Validation is on by default** (`validate=true`). CLI-shaped `execute` and
|
|
190
|
+
`api /execute` scripts pass the offline analyzer before device validation.
|
|
191
|
+
Reads are checked through `/console/inspect`; CLI-shaped commands through
|
|
192
|
+
`[:parse]`. Set `validate=false` (per device or per call) only as a deliberate
|
|
193
|
+
escape hatch.
|
|
194
|
+
- **Every call returns one envelope:** `{ ok, data?, warnings, tips, error?, meta }`,
|
|
183
195
|
with provenance and source-of-truth reporting in `meta`.
|
|
184
196
|
- **Errors are typed values**, not thrown strings, with slash-namespaced codes
|
|
185
197
|
(`routeros/…`, `transport/…`, `validation/…`, `cdb/…`) and a `details_url`
|
|
@@ -213,8 +225,8 @@ GitHub issues it links are the roadmap.
|
|
|
213
225
|
|
|
214
226
|
Requirements:
|
|
215
227
|
|
|
216
|
-
- Bun 1.
|
|
217
|
-
Bun 2.x not yet validated).
|
|
228
|
+
- Bun 1.4.4 or newer within 1.x (`engines.bun`: `>=1.4.4 <2`; CI runs the
|
|
229
|
+
`packageManager` version in `package.json`; Bun 2.x not yet validated).
|
|
218
230
|
- Git.
|
|
219
231
|
- `uv`, only for `bun run lint:actions` (zizmor workflow audit).
|
|
220
232
|
- For integration tests: QEMU plus `@tikoci/quickchr` (handles CHR image
|
|
@@ -250,7 +262,9 @@ bun run explain:value-census # value-surface census (#225)
|
|
|
250
262
|
|
|
251
263
|
## Done definition (short version)
|
|
252
264
|
|
|
253
|
-
|
|
254
|
-
real CHR via `bun run test:integration`.
|
|
255
|
-
|
|
256
|
-
|
|
265
|
+
Live capabilities require every applicable example in `commands/<name>/examples.md`
|
|
266
|
+
green on real CHR via `bun run test:integration`. Offline analysis requires its
|
|
267
|
+
command README's full baseline acceptance criteria, including committed
|
|
268
|
+
CHR-grounded semantic evidence. The fixture-backed `devices` and `settings`
|
|
269
|
+
integration suites retain their command-specific contracts. Full rule:
|
|
270
|
+
[`docs/CONSTITUTION.md` → Done definition](docs/CONSTITUTION.md#done-definition).
|
package/commands/api/AGENTS.md
CHANGED
|
@@ -87,8 +87,9 @@ stack-language access without centrs modelling the whole query grammar.
|
|
|
87
87
|
|
|
88
88
|
## CONFIRMED ON CHR (Phase 0 grounding spikes — CHR 7.23.1, 2026-06-29)
|
|
89
89
|
|
|
90
|
-
Probes:
|
|
91
|
-
`api-grounding-spike2.ts` (duration/monitor + query
|
|
90
|
+
Probes (phase-0 lab history, not runnable methods): `api-grounding-spike.ts`
|
|
91
|
+
(listen/CRUD/execute) and `api-grounding-spike2.ts` (duration/monitor + query
|
|
92
|
+
forms + inspect path). Raw
|
|
92
93
|
native codec for the listen probe; `fetch` for REST; `connectNativeApi().talk()`
|
|
93
94
|
for native.
|
|
94
95
|
|
package/commands/api/README.md
CHANGED
|
@@ -51,7 +51,14 @@ centrs api <router> <endpoint> [flags]
|
|
|
51
51
|
segment (`ip/address/*1`) addresses one row for GET/PATCH/DELETE; PUT and
|
|
52
52
|
POST reject it with `input/invalid-path`. A trailing `/listen` segment is
|
|
53
53
|
the menu's `listen` command, which implies `--stream` + `--via native-api`
|
|
54
|
-
and requires GET (`ip/address/*1/listen` follows one row).
|
|
54
|
+
and requires GET (`ip/address/*1/listen` follows one row). After that
|
|
55
|
+
normalization every menu segment must be a RouterOS menu name (letters,
|
|
56
|
+
digits, hyphens; case folds), or the request fails with
|
|
57
|
+
`input/invalid-routeros-path` before any transport is chosen, whatever
|
|
58
|
+
`--validate` says. A `#` or `?` once cut `/print` off a projected GET's
|
|
59
|
+
REST URL and posted the bare command (`/system/reboot#` rebooted CHR 7.24.5,
|
|
60
|
+
#586); the grammar and retrieve's REST guard are described in
|
|
61
|
+
[retrieve → Validation](../retrieve/README.md#validation).
|
|
55
62
|
|
|
56
63
|
The HTTP method (`-X`, default `GET`) is honored **literally** against RouterOS's
|
|
57
64
|
REST mapping — `GET`→print/get, **`PUT`→add**, `PATCH`→set, `DELETE`→remove,
|
package/commands/btest/README.md
CHANGED
|
@@ -139,6 +139,15 @@ is net-new — `mtwei.ts` only implements the client. A bad proof (or a client t
|
|
|
139
139
|
will not offer EC-SRP5 against an `authenticate=yes` server) maps to
|
|
140
140
|
`transport/auth-failed`. Legacy pre-6.43 double-MD5 is out of scope for v1.
|
|
141
141
|
|
|
142
|
+
The shared core hashes minimal-length big-endian integers in the REDP1 loop
|
|
143
|
+
and for shared-point `z`; public keys and the REDP1 input keep their fixed
|
|
144
|
+
32-byte X encoding (#565). The distinction is grounded in RouterOS
|
|
145
|
+
`libucrypto.so` 6.49.23/7.25 and `tikoci/m2ir`'s live WinBox discriminators.
|
|
146
|
+
`test/fixtures/ec-srp5.json` pins calculated regression transcripts;
|
|
147
|
+
`test/integration/ec-srp5.test.ts` forces the encoding edges against a real
|
|
148
|
+
CHR btest client, including a short `z` and a leading-zero REDP1 input
|
|
149
|
+
(confirmed on CHR 7.23.8 and 7.25).
|
|
150
|
+
|
|
142
151
|
## Output
|
|
143
152
|
|
|
144
153
|
btest runs over time, so it emits **live records** during the run plus a final
|
|
@@ -99,6 +99,13 @@ and non-zero throughput. This is the example that exercises the net-new
|
|
|
99
99
|
server-side EC-SRP5 verifier against real RouterOS (TCP keeps the gated path off
|
|
100
100
|
the SLIRP UDP-reverse-NAT question).
|
|
101
101
|
|
|
102
|
+
`test/integration/ec-srp5.test.ts` also exercises this exchange with chosen
|
|
103
|
+
test salts and ephemeral scalars, one edge per pass: a short REDP1 loop hash
|
|
104
|
+
input, a REDP1 input whose leading zero must stay, and that input again with a
|
|
105
|
+
forced short shared `z`. RouterOS's client proof must match the minimal-length
|
|
106
|
+
derivation. This discriminator stops at the
|
|
107
|
+
proof; the normal btest suites cover completed sessions and throughput (#565).
|
|
108
|
+
|
|
102
109
|
### 4. Wrong credentials are rejected
|
|
103
110
|
|
|
104
111
|
> *Designed, not yet gated* — the auth-reject path is asserted by the loopback
|