@tikoci/centrs 0.1.9-next.27 → 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 +64 -6
- package/README.md +15 -13
- package/commands/devices/README.md +89 -28
- package/commands/devices/examples.md +112 -1
- package/commands/execute/README.md +2 -2
- package/commands/retrieve/README.md +2 -2
- package/commands/settings/README.md +6 -0
- package/commands/settings/examples.md +17 -0
- package/docs/CLI.md +43 -9
- package/docs/errors/input/empty-stdin.md +27 -0
- package/docs/errors/input/invalid-stdin.md +28 -0
- package/docs/errors/usage/stdin-is-tty.md +21 -0
- package/package.json +4 -4
- package/src/cli/api.ts +1 -1
- package/src/cli/common.ts +1 -0
- package/src/cli/devices.ts +189 -24
- package/src/cli/execute.ts +3 -3
- package/src/cli/settings.ts +28 -6
- package/src/core/error-catalog.ts +15 -0
- package/src/devices.ts +224 -24
- package/src/index.ts +1 -0
- package/src/mcp/safety.ts +7 -6
- package/src/mcp/tools.ts +30 -68
- package/src/resolver/cdb.ts +9 -8
- package/src/resolver/selection.ts +4 -4
- package/src/settings.ts +23 -8
package/CHANGELOG.md
CHANGED
|
@@ -10,13 +10,24 @@ 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.
|
|
20
31
|
- `explain` offers a non-applied repair tip for pasted console prompts
|
|
21
32
|
(#370, #567, #578), including `[user@host] /menu>` and HotLock `>>` forms.
|
|
22
33
|
The candidate preserves command separators and names the menu context;
|
|
@@ -117,6 +128,20 @@ part of this section.
|
|
|
117
128
|
|
|
118
129
|
### Changed
|
|
119
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.
|
|
120
145
|
- **Breaking:** permission and edge-auth failures get their own error codes
|
|
121
146
|
(#541). Three codes change for `--json` and library readers:
|
|
122
147
|
- A REST policy refusal (HTTP 500 `not enough permissions (9)` or `std
|
|
@@ -203,9 +228,7 @@ part of this section.
|
|
|
203
228
|
`/cmr/upgrade/trigger`, `/cmr/upgrade/job/run-next`) are pinned as writes in
|
|
204
229
|
every spelling, over `execute`, `api` and MCP `mcp=ro`. On 7.26beta1 a
|
|
205
230
|
controller login with only `read` + `api` can run them (#456).
|
|
206
|
-
-
|
|
207
|
-
version local development already used; `@types/bun` moves with it (#438).
|
|
208
|
-
`engines.bun` stays `>=1.3.11 <2`. The `typescript` peer stays `^6.0.3`:
|
|
231
|
+
- The `typescript` peer stays `^6.0.3`:
|
|
209
232
|
the source passes `tsc --noEmit` under TypeScript 7.0.2, but typedoc 0.28 (the
|
|
210
233
|
API reference build) supports TypeScript up to 6.0.x only.
|
|
211
234
|
- QA records a CHR leg in `qa-history` only when its test step passed or
|
|
@@ -223,6 +246,31 @@ part of this section.
|
|
|
223
246
|
|
|
224
247
|
### Fixed
|
|
225
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.
|
|
226
274
|
- **`retrieve` and `api` can no longer send a non-read** (#586). A `#` or
|
|
227
275
|
`?` in the path cut the appended `/print` off the REST URL, so
|
|
228
276
|
`retrieve '/system/reboot#' --no-validate --attribute uptime` posted
|
|
@@ -343,6 +391,16 @@ part of this section.
|
|
|
343
391
|
|
|
344
392
|
### Maintenance
|
|
345
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.
|
|
346
404
|
- Releases are one dispatch from `main` (#484, #485). `@next` publishes
|
|
347
405
|
`X.Y.Z-next.<run_number>` with no commit, PR or tag, and reuses main's QA
|
|
348
406
|
run on the commit instead of sweeping every channel again. `@latest` creates
|
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
|
|
@@ -63,7 +63,7 @@ product; without them this would just be a worse `curl`.
|
|
|
63
63
|
| Command | Purpose |
|
|
64
64
|
| ---------- | ------- |
|
|
65
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
|
|
66
|
+
| `execute` | Run RouterOS CLI-shaped read/write commands (add/set/remove) over native API, REST, SSH or MAC-Telnet. |
|
|
67
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). |
|
|
68
68
|
| `terminal` | Open an interactive console, primarily SSH or MAC-Telnet. |
|
|
69
69
|
| `transfer` | Upload, download and manage device files over REST/native API or SFTP; `upload` and `download` are shortcuts. |
|
|
@@ -96,7 +96,9 @@ stores:
|
|
|
96
96
|
comment carries `identity=edge1`. Every other comment token stays inert prose.
|
|
97
97
|
See `commands/devices/README.md` (Identity model) for the full resolution rules.
|
|
98
98
|
- **`user` / `password`** — the credentials centrs connects with. They stay in
|
|
99
|
-
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.
|
|
100
102
|
- **`group`, `profile`, `session`, port** — used as-is.
|
|
101
103
|
|
|
102
104
|
So `centrs retrieve edge1 /ip/address` works with no flags: `edge1` is looked
|
|
@@ -223,8 +225,8 @@ GitHub issues it links are the roadmap.
|
|
|
223
225
|
|
|
224
226
|
Requirements:
|
|
225
227
|
|
|
226
|
-
- Bun 1.
|
|
227
|
-
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).
|
|
228
230
|
- Git.
|
|
229
231
|
- `uv`, only for `bun run lint:actions` (zizmor workflow audit).
|
|
230
232
|
- For integration tests: QEMU plus `@tikoci/quickchr` (handles CHR image
|
|
@@ -310,32 +310,27 @@ is no group-definition record. A group is the set of all entries whose
|
|
|
310
310
|
`group` value matches by exact, case-sensitive string compare. An entry with
|
|
311
311
|
`group=""` belongs to no group.
|
|
312
312
|
|
|
313
|
-
`--group <G>` on
|
|
313
|
+
`--group <G>` on a router-facing fan-out command resolves to the membership set.
|
|
314
314
|
`discover --save` writes MNDP records with `group=discovered`
|
|
315
315
|
unless the caller supplies another group.
|
|
316
316
|
|
|
317
317
|
### Promotion (discovered → managed)
|
|
318
318
|
|
|
319
319
|
There is no `promote` verb. Moving one device out of `group=discovered` and
|
|
320
|
-
giving it credentials
|
|
321
|
-
…`. A **bulk** promotion (a whole discovered class at once) is the same call with
|
|
322
|
-
a target selector picking the records:
|
|
320
|
+
giving it credentials uses `set` on that target:
|
|
323
321
|
|
|
324
322
|
```bash
|
|
325
|
-
devices set --group
|
|
326
|
-
--user admin --password … --force
|
|
323
|
+
centrs devices set <target> --group prod --user admin --password …
|
|
327
324
|
```
|
|
328
325
|
|
|
329
|
-
`--group`
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
setter today; `examples.md` reflects that current flag until the `--new-group`
|
|
334
|
-
split lands.)
|
|
326
|
+
On `devices add`/`set`, `--group` writes the first-class group field; on
|
|
327
|
+
`devices list` it filters. Bulk `set`/`remove` selection and a separate
|
|
328
|
+
`--new-group` flag remain designed, not implemented. Both mutations currently
|
|
329
|
+
require one target, with `--match` to disambiguate saved records.
|
|
335
330
|
|
|
336
331
|
## Fanout (multi-target invocations)
|
|
337
332
|
|
|
338
|
-
|
|
333
|
+
Router-facing fan-out commands may receive multiple positional targets, one or more `--group`
|
|
339
334
|
flags, `--all`, `--default`, `--where <attr>=<value>` (device-class), and/or the
|
|
340
335
|
geo selectors `--near <lat>,<lon>,<radius>` / `--bbox <south>,<west>,<north>,<east>`
|
|
341
336
|
(see "Geo query" above) — see `docs/CONSTITUTION.md` (Target selection grammar).
|
|
@@ -365,21 +360,24 @@ centrs devices encrypt [--no-backup] # explicitly encrypt an existing open CD
|
|
|
365
360
|
centrs devices list [--group G] [--where attr=value]
|
|
366
361
|
[--near lat,lon,radius] [--bbox south,west,north,east]
|
|
367
362
|
[--format json|yaml|text]
|
|
368
|
-
centrs devices show <target> [--explain] [--via <protocol>] [--match <
|
|
363
|
+
centrs devices show <target> [--explain] [--via <protocol>] [--match <selector>]
|
|
364
|
+
[--show-password]
|
|
369
365
|
centrs devices groups [--members]
|
|
370
|
-
centrs devices discover [--timeout 15s] [--group G] #
|
|
371
|
-
centrs devices add <target> [--user U] [--password P] [--
|
|
366
|
+
centrs devices discover [--timeout 15s] [--group G] # designed, not implemented; use `centrs discover --save`
|
|
367
|
+
centrs devices add <target> [--user U] [--password P|--password-stdin] [--group G]
|
|
372
368
|
[--profile P|--profile-none|--profile-own]
|
|
373
369
|
[--session S] [--comment "text k=v"]
|
|
374
370
|
[--record-type ipAdmin|ipUser|macTarget|...]
|
|
375
371
|
[--gps lat,lon[,altitude[,altitude-type]]]
|
|
376
372
|
[--lat D] [--lon D] [--altitude M] [--altitude-type MSL|AGL]
|
|
377
|
-
|
|
373
|
+
[--show-password]
|
|
374
|
+
centrs devices set <target> [--match <selector>] [--user U] [--password P|--password-stdin] [--group G]
|
|
378
375
|
[--profile P|--profile-none|--profile-own]
|
|
379
376
|
[--session S] [k=v ...]
|
|
380
377
|
[--gps lat,lon[,altitude[,altitude-type]]]
|
|
381
378
|
[--lat D] [--lon D] [--altitude M] [--altitude-type MSL|AGL]
|
|
382
|
-
|
|
379
|
+
[--show-password]
|
|
380
|
+
centrs devices remove <target> [--match <selector>]
|
|
383
381
|
centrs devices edit <target> # future: clack/TUI wizard
|
|
384
382
|
```
|
|
385
383
|
|
|
@@ -423,18 +421,79 @@ is no `update`.
|
|
|
423
421
|
existing `(target, user)` it errors `cdb/already-exists` unless `--force`
|
|
424
422
|
overwrites; the same `target` under a *different* `--user` is a new record,
|
|
425
423
|
not a collision.
|
|
426
|
-
- `set` modifies
|
|
427
|
-
(`--user`, `--password`, `--
|
|
428
|
-
comment lookup/override keys change via `k=v` positionals.
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
`--new-group` *writes* the group field (no overload). Against a missing target
|
|
432
|
-
it errors `cdb/not-found-target`; a multi-record `set` needs `--force`. Writing
|
|
424
|
+
- `set` modifies one matched record. First-class fields change via flags
|
|
425
|
+
(`--user`, `--password`, `--group`, `--profile[-none|-own]`, `--session`);
|
|
426
|
+
comment lookup/override keys change via `k=v` positionals. The positional
|
|
427
|
+
target and optional `--match` select the record. Against a missing target
|
|
428
|
+
it errors `cdb/not-found-target`. Writing
|
|
433
429
|
a first-class field name as a `k=v` positional (e.g. `user=x`) stays refused
|
|
434
430
|
with `cdb/reserved-key` — the flag is the only path. Unknown comment keys warn
|
|
435
431
|
(`cdb/unknown-option`), or error under `--strict`.
|
|
436
|
-
- `remove` (aliases `rm`, `delete`) removes
|
|
437
|
-
|
|
432
|
+
- `remove` (aliases `rm`, `delete`) removes one matched entry. The positional
|
|
433
|
+
target and optional `--match` select the record; group-wide deletion is not
|
|
434
|
+
implemented.
|
|
435
|
+
|
|
436
|
+
### Record password channels
|
|
437
|
+
|
|
438
|
+
`add` and `set` take the record password one of two ways:
|
|
439
|
+
|
|
440
|
+
- `--password <secret>` — argv. Simple, but `ps` can show the value while the
|
|
441
|
+
process runs, and shell history can keep the command after it exits.
|
|
442
|
+
- `--password-stdin` — read from stdin, so the value never appears in argv. For
|
|
443
|
+
automation and harnesses that spawn centrs (`printf '%s' "$PW" | centrs
|
|
444
|
+
devices set <t> --password-stdin`, or `centrs devices set <t>
|
|
445
|
+
--password-stdin < pw.txt`).
|
|
446
|
+
|
|
447
|
+
`--password-stdin` rules:
|
|
448
|
+
|
|
449
|
+
- Exactly one trailing newline (`\n` or `\r\n`) is stripped, so `echo pw |`
|
|
450
|
+
works. Any other whitespace is part of the password.
|
|
451
|
+
- The rest must be valid UTF-8 with no leading byte-order mark; otherwise it
|
|
452
|
+
is `input/invalid-stdin`. The CDB stores record strings as UTF-8 and drops a
|
|
453
|
+
leading BOM on read, so either would store a different credential than the
|
|
454
|
+
bytes piped in.
|
|
455
|
+
- Empty input (nothing, or only that one newline) is `input/empty-stdin`.
|
|
456
|
+
Clearing a stored password stays a deliberate `--password ""`, never an empty
|
|
457
|
+
pipe.
|
|
458
|
+
- A terminal on stdin is refused with `usage/stdin-is-tty`; centrs does not
|
|
459
|
+
prompt.
|
|
460
|
+
- `--password` together with `--password-stdin` is `usage/conflicting-flags`.
|
|
461
|
+
There is no precedence order between them.
|
|
462
|
+
- Only `add` and `set` accept it; every other subcommand refuses it with
|
|
463
|
+
`input/invalid-command`.
|
|
464
|
+
- The value is never echoed in errors. Success envelopes are the same as with
|
|
465
|
+
`--password`.
|
|
466
|
+
|
|
467
|
+
There is no environment-variable channel for the record password:
|
|
468
|
+
`CENTRS_PASSWORD` is the dial credential, not a CDB field.
|
|
469
|
+
|
|
470
|
+
### Record password in output
|
|
471
|
+
|
|
472
|
+
`show`, `add` and `set` withhold the stored record password by default, in text
|
|
473
|
+
and JSON (#551). Each entry always carries `passwordSet: boolean` (true when a
|
|
474
|
+
non-empty password is stored); text prints `password: (set, hidden)` or
|
|
475
|
+
`(not set)`. `--show-password` returns the cleartext `password` on those three
|
|
476
|
+
subcommands; every other subcommand refuses it with `input/invalid-command`.
|
|
477
|
+
The `--explain` record's password field reads `<redacted>` without the flag.
|
|
478
|
+
When an unknown-tcode `rawTail` comes before any decoded password field, the
|
|
479
|
+
tail may hold the password, so without the flag its `value` reads
|
|
480
|
+
`<redacted: N bytes, may contain password>` instead of the bytes. Such a
|
|
481
|
+
record decodes to an empty password, so `passwordSet` is `false` (it reports
|
|
482
|
+
the password centrs decoded and would dial with); the `cdb/unknown-field`
|
|
483
|
+
warning then carries `context.mayContainPassword: true`.
|
|
484
|
+
There is no encryption gate: the opt-in works the same on an open or encrypted
|
|
485
|
+
CDB. `passwordSet` is not the WinBox `savedPassword` ("keep password") flag.
|
|
486
|
+
|
|
487
|
+
The library matches the CLI: exported `showDevice` / `addDevice` / `setDevice`
|
|
488
|
+
redact by default and take `showPassword?: boolean` (default `false`); with
|
|
489
|
+
`showPassword: true` the entry type is `DevicesShowItemWithPassword`. MCP
|
|
490
|
+
(`centrs_devices`) never passes it, so MCP output never carries the password.
|
|
491
|
+
|
|
492
|
+
Dialing does not read this envelope. The resolver and the MCP allowlist gate
|
|
493
|
+
read the raw record through an internal lookup (`lookupDeviceRecord`, not
|
|
494
|
+
exported from the package root), so a CDB-credentialed dial still sends the
|
|
495
|
+
stored password. The public entry type has no `password` field, so a caller
|
|
496
|
+
that reached for the envelope instead fails to type-check.
|
|
438
497
|
|
|
439
498
|
`--profile <name>` sets a named WinBox profile; `--profile-none` /
|
|
440
499
|
`--profile-own` write the WinBox sentinels `<none>` / `<own>`. `profile` and
|
|
@@ -498,7 +557,9 @@ be recovered.
|
|
|
498
557
|
`init` and `encrypt` act on the CDB file, not on records: they accept only
|
|
499
558
|
`--cdb-file`, `--cdb-password`, `--format`/`--json`, plus `--encrypt` (`init`)
|
|
500
559
|
or `--no-backup` (`encrypt`). Any other flag is `input/invalid-command`
|
|
501
|
-
instead of being silently ignored.
|
|
560
|
+
instead of being silently ignored. `devices init --help` and
|
|
561
|
+
`devices encrypt --help` show only those accepted flags; the same metadata
|
|
562
|
+
generates their sections in [`docs/CLI.md`](../../docs/CLI.md).
|
|
502
563
|
|
|
503
564
|
Close WinBox and other CDB writers before conversion. If they share this path,
|
|
504
565
|
they must reopen it using the CDB password; a stale writer can overwrite the
|
|
@@ -94,7 +94,8 @@ centrs devices show 192.0.2.5 --cdb-file $CDB --explain
|
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
`data.record` is the raw `WinBoxCdbRecord` (tag/marker/tcode/value). Useful
|
|
97
|
-
for diagnosing unknown-field preservation.
|
|
97
|
+
for diagnosing unknown-field preservation. The password field value reads
|
|
98
|
+
`<redacted>` unless `--show-password` is passed (example 60).
|
|
98
99
|
|
|
99
100
|
## groups
|
|
100
101
|
|
|
@@ -720,3 +721,113 @@ A fresh path, so it does not depend on example 57 having already converted
|
|
|
720
721
|
is retained, so
|
|
721
722
|
`cdb/plaintext-backups` still warns. Test: `centrs devices encryption (#558)`
|
|
722
723
|
in `test/integration/devices.test.ts`.
|
|
724
|
+
|
|
725
|
+
## Record password in output
|
|
726
|
+
|
|
727
|
+
`show`, `add` and `set` withhold the stored record password by default, in text
|
|
728
|
+
and JSON and in the library envelopes (#551). Every entry carries
|
|
729
|
+
`passwordSet: boolean`; `--show-password` (library: `showPassword: true`) opts in.
|
|
730
|
+
`passwordSet` is not the WinBox `savedPassword` flag. MCP never returns the
|
|
731
|
+
password and has no opt-in.
|
|
732
|
+
|
|
733
|
+
### 60. `show` withholds the password and reports `passwordSet`
|
|
734
|
+
|
|
735
|
+
```bash
|
|
736
|
+
centrs devices show 192.0.2.5 --cdb-file $CDB --explain --json
|
|
737
|
+
centrs devices show 192.0.2.5 --cdb-file $CDB
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
`data.entry` has `passwordSet: true` and no `password` key. The `--explain`
|
|
741
|
+
record's password field (tag 3) reads `<redacted>`. Text prints
|
|
742
|
+
`password: (set, hidden)`, or `(not set)` for an empty password.
|
|
743
|
+
|
|
744
|
+
### 61. `--show-password` returns the password on `show`, `add` and `set`
|
|
745
|
+
|
|
746
|
+
```bash
|
|
747
|
+
centrs devices show 192.0.2.5 --cdb-file $CDB --show-password --json
|
|
748
|
+
centrs devices add 198.51.100.57 --user writer --password pw57 --cdb-file $CDB --json
|
|
749
|
+
centrs devices set 198.51.100.57 --group lab --cdb-file $CDB --show-password --json
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
`show` returns `data.entry.password: "secret"`. The `add` without the flag
|
|
753
|
+
returns `passwordSet: true` and no `password`; the `set` with it returns
|
|
754
|
+
`data.entry.password: "pw57"`.
|
|
755
|
+
|
|
756
|
+
### 62. `--show-password` is refused outside `show` / `add` / `set`
|
|
757
|
+
|
|
758
|
+
```bash
|
|
759
|
+
centrs devices list --cdb-file $CDB --show-password --json
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
`input/invalid-command` with `error.context: { subcommand: "list", flag:
|
|
763
|
+
"--show-password" }`, the same refusal other subcommand-scoped flags use.
|
|
764
|
+
|
|
765
|
+
## Record password on stdin
|
|
766
|
+
|
|
767
|
+
`--password-stdin` (#582) reads the record password from fd 0 so it never rides
|
|
768
|
+
argv. These run as subprocesses (`test/integration/cli-process.ts`), because
|
|
769
|
+
only a child process can be handed real stdin bytes. The newline, empty and TTY
|
|
770
|
+
rules are also unit-tested in `test/unit/devices-password-stdin.test.ts`.
|
|
771
|
+
|
|
772
|
+
### 63. `add --password-stdin` stores the piped value
|
|
773
|
+
|
|
774
|
+
```bash
|
|
775
|
+
printf 'piped pw\n' | centrs devices add 192.0.2.77 --user robot --password-stdin --cdb-file $CDB --json
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
`ok: true`. The stored password is `piped pw`: one trailing newline is
|
|
779
|
+
stripped, the inner space is kept.
|
|
780
|
+
|
|
781
|
+
### 64. `set --password-stdin` strips a trailing CRLF
|
|
782
|
+
|
|
783
|
+
```bash
|
|
784
|
+
printf 'rotated\r\n' | centrs devices set 192.0.2.5 --password-stdin --cdb-file $CDB --json
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
`ok: true`. The stored password is `rotated`; group and comment are unchanged.
|
|
788
|
+
|
|
789
|
+
### 65. Empty stdin is refused
|
|
790
|
+
|
|
791
|
+
```bash
|
|
792
|
+
printf '' | centrs devices set 192.0.2.5 --password-stdin --cdb-file $CDB --json
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
Errors with `input/empty-stdin` (also for a lone `\n`). The CDB is not written
|
|
796
|
+
and no backup is made.
|
|
797
|
+
|
|
798
|
+
### 66. `--password` with `--password-stdin` conflicts
|
|
799
|
+
|
|
800
|
+
```bash
|
|
801
|
+
echo stdin-secret | centrs devices set 192.0.2.5 --password argv-secret --password-stdin --cdb-file $CDB --json
|
|
802
|
+
echo stdin-secret | centrs devices set 192.0.2.5 --password --password-stdin --cdb-file $CDB --json
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
Both error with `usage/conflicting-flags`. Neither value appears in the error;
|
|
806
|
+
`--password` cannot consume `--password-stdin` as a literal credential.
|
|
807
|
+
|
|
808
|
+
### 67. Non-UTF-8 or BOM-prefixed stdin is refused
|
|
809
|
+
|
|
810
|
+
```bash
|
|
811
|
+
printf 'pw\377\n' | centrs devices set 192.0.2.5 --password-stdin --cdb-file $CDB --json
|
|
812
|
+
printf '\357\273\277pw\n' | centrs devices set 192.0.2.5 --password-stdin --cdb-file $CDB --json
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
Both error with `input/invalid-stdin`: the first is not valid UTF-8, the second
|
|
816
|
+
starts with a byte-order mark. The bytes are not echoed, the CDB is not written
|
|
817
|
+
and no backup is made.
|
|
818
|
+
|
|
819
|
+
## File-command help
|
|
820
|
+
|
|
821
|
+
### 68. `init` and `encrypt` show only their accepted flags
|
|
822
|
+
|
|
823
|
+
```bash
|
|
824
|
+
centrs devices init --help
|
|
825
|
+
centrs devices encrypt --help
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
Both exit 0 without reading or writing a CDB. Each shows its own usage, the
|
|
829
|
+
CDB path/password and output flags, plus `--encrypt` for `init` or
|
|
830
|
+
`--no-backup` for `encrypt`. Record and selection flags are absent, including
|
|
831
|
+
`--user`, `--password-stdin`, `--show-password`, `--group` and `--match`.
|
|
832
|
+
Test: `devices file-command help is scoped without opening a CDB` in
|
|
833
|
+
`test/integration/cli-smoke.test.ts` (network-free).
|
|
@@ -146,8 +146,8 @@ selection**, examples F1–F5). `romon` and `winbox-terminal` remain
|
|
|
146
146
|
all-strings). Unlike `jo`-style KV builders, there is no per-value
|
|
147
147
|
type-forcing escape, because the device, not centrs, owns value typing.
|
|
148
148
|
- On an empty-CDB resolution failure, execute (like retrieve) emits the
|
|
149
|
-
`tip/no-devices` tip, steering toward `centrs
|
|
150
|
-
`centrs
|
|
149
|
+
`tip/no-devices` tip, steering toward `centrs discover --save` /
|
|
150
|
+
`centrs devices add`.
|
|
151
151
|
- Protocol surfaces are native API, REST, mac-telnet, and SSH. RoMON and
|
|
152
152
|
WinBox Terminal are later. SNMP is retrieve-only and must reject execute.
|
|
153
153
|
- For a MAC target not resolved from CDB, auto-selection defaults to
|
|
@@ -583,5 +583,5 @@ reach green is forbidden. See `docs/CONSTITUTION.md` for the full done rule.
|
|
|
583
583
|
- **ssh / mac-telnet / romon / winbox-terminal** — execute surfaces, not
|
|
584
584
|
retrieve surfaces.
|
|
585
585
|
- **tips** — when a `<router>` fails to resolve against an empty CDB, retrieve
|
|
586
|
-
emits
|
|
587
|
-
`centrs devices
|
|
586
|
+
emits `tip/no-devices`, steering toward `centrs discover --save` and
|
|
587
|
+
`centrs devices add`.
|
|
@@ -156,6 +156,12 @@ centrs settings reset [<attr>] # clear one/all back to built-in
|
|
|
156
156
|
elsewhere (`src/cli/api.ts`'s `exitCode`), never a bare non-zero without an
|
|
157
157
|
envelope. `settings` has no fan-out surface, so the constitution's `2`
|
|
158
158
|
("partial" fan-out result) never applies here.
|
|
159
|
+
- **`get` output:** text mode renders the one entry exactly as `print`
|
|
160
|
+
renders that key — `key: value [source: kind (key)]` under the canonical
|
|
161
|
+
attr name, plus any `Tips:` footer (examples.md #33). `get`'s `data` is the
|
|
162
|
+
bare `{ source, value }` entry, so the JSON/YAML envelope names the key in
|
|
163
|
+
`meta.operation.attr` (canonical name, whichever spelling was asked for).
|
|
164
|
+
A blank `<attr>` is refused at parse time as `input/invalid-command`.
|
|
159
165
|
- **Agent-facing:** every subcommand emits the standard envelope
|
|
160
166
|
(`ok`/`data`/`meta`/`error`) regardless of TTY — `--format json` is
|
|
161
167
|
honored on `settings` itself exactly like every other command, so an agent
|
|
@@ -406,3 +406,20 @@ XDG_CONFIG_HOME=$SETTINGS_DIR centrs settings print --cdb-file /tmp/does-not-exi
|
|
|
406
406
|
device configured" rather than `cdb/not-found`, since reporting settings
|
|
407
407
|
should not require a CDB to exist at all). `data.defaultDevice = {
|
|
408
408
|
configured: false }`.
|
|
409
|
+
|
|
410
|
+
## Text output
|
|
411
|
+
|
|
412
|
+
### 33. Get renders one entry in text mode, like print
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
XDG_CONFIG_HOME=$SETTINGS_DIR CENTRS_MAX_RESULTS=7 centrs settings get CENTRS_MAX_RESULTS
|
|
416
|
+
XDG_CONFIG_HOME=$SETTINGS_DIR centrs settings get ssh-key
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
`ok: true`, exit 0. Text mode prints the single entry as one line in the
|
|
420
|
+
same `key: value [source: kind (key)]` format `print` uses, under the
|
|
421
|
+
canonical attr name whichever spelling was asked for: `max-results: 7
|
|
422
|
+
[source: env (CENTRS_MAX_RESULTS)]`, then `ssh-key: (unset) [source:
|
|
423
|
+
default (ssh-key)]` followed by its `Tips:` footer. `get`'s `data` is the bare
|
|
424
|
+
entry, so the JSON envelope names the key in `meta.operation.attr`. A
|
|
425
|
+
credential-shaped key renders `(redacted)`, never the secret.
|
package/docs/CLI.md
CHANGED
|
@@ -11,7 +11,7 @@ implemented flags live in each command's `commands/<name>/README.md`.
|
|
|
11
11
|
| Command | Summary |
|
|
12
12
|
| ------- | ------- |
|
|
13
13
|
| [`retrieve`](#retrieve) | Read RouterOS values through the shared core using the selected protocol. |
|
|
14
|
-
| [`execute`](#execute) | Run a RouterOS read or write command via native API, REST, or mac-telnet. |
|
|
14
|
+
| [`execute`](#execute) | Run a RouterOS read or write command via native API, REST, SSH, or mac-telnet. |
|
|
15
15
|
| [`api`](#api) | Structured RouterOS API passthrough (gh-api style) over REST or native API. |
|
|
16
16
|
| [`transfer`](#transfer) | Copy files to/from a RouterOS device and manage device files (rest/native/sftp). |
|
|
17
17
|
| [`terminal`](#terminal) | Open an interactive RouterOS console (ssh or mac-telnet). |
|
|
@@ -71,7 +71,7 @@ Usage: centrs retrieve <target> <routeros-path> [flags] | centrs retrieve <targe
|
|
|
71
71
|
|
|
72
72
|
## execute
|
|
73
73
|
|
|
74
|
-
Run a RouterOS read or write command via native API, REST, or mac-telnet.
|
|
74
|
+
Run a RouterOS read or write command via native API, REST, SSH, or mac-telnet.
|
|
75
75
|
|
|
76
76
|
```text
|
|
77
77
|
Usage: centrs execute <target> <command> [flags] | centrs execute <target...> -- <command> [flags] | centrs execute --host <host|url> [--] <command> [flags] | centrs execute --group <name> <command> [flags]
|
|
@@ -79,7 +79,7 @@ Usage: centrs execute <target> <command> [flags] | centrs execute <target...> --
|
|
|
79
79
|
|
|
80
80
|
| Flag | Value | Description |
|
|
81
81
|
| ---- | ----- | ----------- |
|
|
82
|
-
| `--via` | <native-api\|rest-api\|mac-telnet> | Pin the protocol selector; no silent downgrade when set. A bare MAC target defaults to mac-telnet. |
|
|
82
|
+
| `--via` | <native-api\|rest-api\|ssh\|mac-telnet> | Pin the protocol selector; no silent downgrade when set. A bare MAC target defaults to mac-telnet. |
|
|
83
83
|
| `--group` | `<name>` | Fan out across every CDB record in the group (repeatable; de-duped by record index). |
|
|
84
84
|
| `--where` | `<attr>`=`<value>` | Device-class selector over CDB facts + core fields (repeatable, AND-combined). |
|
|
85
85
|
| `--near` | `<lat>`,`<lon>`,`<radius>` | Geo selector: devices whose GPS is within radius (m/km/mi/ft; bare number = km). Lat-first. |
|
|
@@ -101,7 +101,7 @@ Usage: centrs execute <target> <command> [flags] | centrs execute <target...> --
|
|
|
101
101
|
| `--match` | <user=name\|target=addr\|record-type> | Pick one of several CDB records saved for `<router>` (as `devices show --match`); single target only. |
|
|
102
102
|
| `--resolve` | <none\|arp> | Resolve a MAC-address target to an IP via the host ARP cache (default none). |
|
|
103
103
|
| `--timeout` | `<duration>` | Per-request timeout (for REST, max 60s). |
|
|
104
|
-
| `--validate / --no-validate` | | Run RouterOS :parse
|
|
104
|
+
| `--validate / --no-validate` | | Run offline analysis, then RouterOS :parse, plus `/console/inspect` for structured commands over native API/REST (default true; `--validate=false` disables both stages). |
|
|
105
105
|
| `--yes` | | Confirm write-shaped add/set/remove commands in non-interactive runs. |
|
|
106
106
|
| `--max-results` | `<bytes>` | Fail if the rendered envelope exceeds this byte budget. |
|
|
107
107
|
| `--format` | <text\|json\|yaml> | Output format for the CLI response. Defaults to text; use --json or --format json for the structured envelope. |
|
|
@@ -150,7 +150,7 @@ Usage: centrs api <router> <endpoint> [flags] | centrs api --host <host|url> <en
|
|
|
150
150
|
| `--match` | <user=name\|target=addr\|record-type> | Pick one of several CDB records saved for `<router>` (as `devices show --match`); single target only. |
|
|
151
151
|
| `--resolve` | <none\|arp> | Resolve a MAC-address target to an IP via the host ARP cache (default none). |
|
|
152
152
|
| `--timeout` | `<duration>` | Per-request timeout (for REST, max 60s). |
|
|
153
|
-
| `--validate / --no-validate` | |
|
|
153
|
+
| `--validate / --no-validate` | | Validate structured requests with `/console/inspect`; `/execute` scripts run offline analysis, then RouterOS :parse (default true; `--validate=false` disables both stages). |
|
|
154
154
|
| `--format` | <json\|ndjson\|yaml\|text> | Output format. Defaults to json for api; `CENTRS_FORMAT` overrides. |
|
|
155
155
|
| `--json` | | Shortcut for `--format json`. |
|
|
156
156
|
| `--verbose` | | Include additional context in text output, on stderr. |
|
|
@@ -271,17 +271,19 @@ Usage: centrs devices <init|encrypt|list|show|groups|add|edit|set|remove> [args]
|
|
|
271
271
|
| `--encrypt` | | `init` only — require encrypted creation with a non-empty CDB password; refuse an existing open CDB. |
|
|
272
272
|
| `--no-backup` | | `encrypt` only — skip the plaintext pre-conversion snapshot. Without that snapshot, a forgotten password cannot be recovered. |
|
|
273
273
|
| `--cdb-file` | `<path>` | Override the resolved CDB path (default `~/.config/tikoci/winbox.cdb`). |
|
|
274
|
-
| `--cdb-password` | `<secret>` |
|
|
274
|
+
| `--cdb-password` | `<secret>` | CDB password for encrypted reads, writes, explicit encrypted initialization and conversion. Falls back to `CENTRS_CDB_PASSWORD`; a password alone never converts an open CDB. |
|
|
275
275
|
| `--via` | `<protocol>` | Resolve and report the protocol source for provenance examples; no network IO is performed. |
|
|
276
|
-
| `--group` | `<name>` | `list` filter / `add`,`
|
|
276
|
+
| `--group` | `<name>` | `list` filter / `add`,`set` first-class group field for the target entry. |
|
|
277
277
|
| `--where` | `<attr=value>` | `list` only — repeatable device-class filter over CDB facts (AND-combined), e.g. `--where lat=37.7749`. |
|
|
278
278
|
| `--near` | `<lat>`,`<lon>`,`<radius>` | `list` only — GPS filter: devices within radius (m/km/mi/ft; bare number = km). Lat-first. |
|
|
279
279
|
| `--bbox` | `<south>`,`<west>`,`<north>`,`<east>` | `list` only — GPS filter: devices inside the lat-first bounding box. |
|
|
280
280
|
| `--members` | | `groups` only — expand each group's membership. |
|
|
281
|
-
| `--explain` | | `show` only — include the raw `WinBoxCdbRecord` in `data.record
|
|
282
|
-
| `--match` | <user=…\|target=…\|record-type> | `show` — disambiguate when `<router>` matches several records: `user=<name>`, `target=<addr>`, or a record-type token. |
|
|
281
|
+
| `--explain` | | `show` only — include the raw `WinBoxCdbRecord` in `data.record` (its password field reads `<redacted>` unless `--show-password`). |
|
|
282
|
+
| `--match` | <user=…\|target=…\|record-type> | `show`,`set`,`remove` — disambiguate when `<router>` matches several records: `user=<name>`, `target=<addr>`, or a record-type token. |
|
|
283
283
|
| `--user` | `<name>` | `add`,`set` — first-class CDB user field. |
|
|
284
284
|
| `--password` | `<secret>` | `add`,`set` — first-class CDB password field. |
|
|
285
|
+
| `--password-stdin` | | `add`,`set` — read the record password from stdin (one trailing newline stripped) so it never rides argv. Conflicts with `--password`. |
|
|
286
|
+
| `--show-password` | | `show`,`add`,`set` — include the record password in cleartext. By default output carries `passwordSet` and withholds the password. |
|
|
285
287
|
| `--profile` | `<name>` | `add`,`set` — named WinBox profile (Workspace). |
|
|
286
288
|
| `--profile-none` | | `add`,`set` — write the WinBox `<none>` profile sentinel. |
|
|
287
289
|
| `--profile-own` | | `add`,`set` — write the WinBox `<own>` profile sentinel. |
|
|
@@ -298,6 +300,38 @@ Usage: centrs devices <init|encrypt|list|show|groups|add|edit|set|remove> [args]
|
|
|
298
300
|
| `--format` | <text\|json\|yaml> | Output format for the CLI response. |
|
|
299
301
|
| `--json` | | Shortcut for `--format json`. |
|
|
300
302
|
|
|
303
|
+
### devices init
|
|
304
|
+
|
|
305
|
+
Create an empty CDB at the resolved path; existing readable files are left unchanged.
|
|
306
|
+
|
|
307
|
+
```text
|
|
308
|
+
Usage: centrs devices init [flags]
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
| Flag | Value | Description |
|
|
312
|
+
| ---- | ----- | ----------- |
|
|
313
|
+
| `--encrypt` | | `init` only — require encrypted creation with a non-empty CDB password; refuse an existing open CDB. |
|
|
314
|
+
| `--cdb-file` | `<path>` | Override the resolved CDB path (default `~/.config/tikoci/winbox.cdb`). |
|
|
315
|
+
| `--cdb-password` | `<secret>` | CDB password for encrypted reads, writes, explicit encrypted initialization and conversion. Falls back to `CENTRS_CDB_PASSWORD`; a password alone never converts an open CDB. |
|
|
316
|
+
| `--format` | <text\|json\|yaml> | Output format for the CLI response. |
|
|
317
|
+
| `--json` | | Shortcut for `--format json`. |
|
|
318
|
+
|
|
319
|
+
### devices encrypt
|
|
320
|
+
|
|
321
|
+
Encrypt an existing CDB in place, or verify an already-encrypted file; existing backups remain unchanged.
|
|
322
|
+
|
|
323
|
+
```text
|
|
324
|
+
Usage: centrs devices encrypt [flags]
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
| Flag | Value | Description |
|
|
328
|
+
| ---- | ----- | ----------- |
|
|
329
|
+
| `--no-backup` | | `encrypt` only — skip the plaintext pre-conversion snapshot. Without that snapshot, a forgotten password cannot be recovered. |
|
|
330
|
+
| `--cdb-file` | `<path>` | Override the resolved CDB path (default `~/.config/tikoci/winbox.cdb`). |
|
|
331
|
+
| `--cdb-password` | `<secret>` | CDB password for encrypted reads, writes, explicit encrypted initialization and conversion. Falls back to `CENTRS_CDB_PASSWORD`; a password alone never converts an open CDB. |
|
|
332
|
+
| `--format` | <text\|json\|yaml> | Output format for the CLI response. |
|
|
333
|
+
| `--json` | | Shortcut for `--format json`. |
|
|
334
|
+
|
|
301
335
|
## discover
|
|
302
336
|
|
|
303
337
|
Discover RouterOS neighbors over MNDP and optionally save them into the CDB.
|