@tikoci/centrs 0.1.2 → 0.1.4
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 +98 -0
- package/GLOSSARY.txt +284 -0
- package/LICENSE +21 -0
- package/README.md +55 -11
- package/SECURITY.md +3 -3
- package/commands/AGENTS.md +7 -1
- package/commands/api/README.md +46 -27
- package/commands/api/examples.md +124 -6
- package/commands/btest/README.md +21 -32
- package/commands/check/README.md +376 -53
- package/commands/check/examples.md +390 -0
- package/commands/devices/README.md +177 -37
- package/commands/devices/examples.md +148 -0
- package/commands/discover/README.md +5 -11
- package/commands/execute/README.md +73 -26
- package/commands/execute/examples.md +131 -9
- package/commands/explain/README.md +1716 -0
- package/commands/explain/examples.md +606 -0
- package/commands/retrieve/README.md +55 -71
- package/commands/retrieve/examples.md +56 -9
- package/commands/settings/README.md +286 -22
- package/commands/settings/examples.md +408 -0
- package/commands/terminal/README.md +6 -0
- package/commands/transfer/README.md +57 -19
- package/commands/transfer/examples.md +95 -0
- package/docs/CLI.md +353 -0
- package/docs/CONSTITUTION.md +102 -26
- package/docs/MATRIX.md +106 -173
- package/docs/errors/README.md +5 -1
- package/docs/errors/cdb/empty-selection.md +19 -0
- package/docs/errors/input/incomplete-gps.md +9 -0
- package/docs/errors/input/invalid-altitude.md +9 -0
- package/docs/errors/input/invalid-bbox.md +9 -0
- package/docs/errors/input/invalid-coordinate.md +9 -0
- package/docs/errors/input/invalid-radius.md +9 -0
- package/docs/errors/internal/settings-failed.md +9 -0
- package/docs/errors/quickchr/machine-not-found.md +22 -0
- package/docs/errors/quickchr/machine-stopped.md +20 -0
- package/docs/errors/quickchr/package-unavailable.md +27 -0
- package/docs/errors/quickchr/unsupported-via.md +35 -0
- package/docs/errors/quickchr/unsupported.md +35 -0
- package/docs/errors/routeros/version-unsupported.md +26 -0
- package/docs/errors/settings/consequential-value.md +26 -0
- package/docs/errors/settings/invalid-boolean.md +21 -3
- package/docs/errors/settings/invalid-format.md +18 -3
- package/docs/errors/settings/invalid-integer.md +18 -3
- package/docs/errors/settings/invalid-timeout.md +20 -3
- package/docs/errors/settings/invalid-via.md +22 -3
- package/docs/errors/settings/reserved-key.md +29 -0
- package/docs/errors/settings/skip-env-file-active.md +25 -0
- package/docs/errors/settings/unknown-key.md +25 -0
- package/docs/errors/transport/provider-trust.md +29 -0
- package/docs/errors/usage/fanout-not-supported.md +16 -0
- package/docs/errors/usage/stdin-ignored.md +28 -0
- package/docs/errors/validation/unknown-attribute.md +37 -4
- package/package.json +49 -14
- package/src/api-fanout.ts +469 -0
- package/src/api.ts +171 -56
- package/src/cli/api.ts +156 -13
- package/src/cli/btest.ts +38 -4
- package/src/cli/common.ts +11 -0
- package/src/cli/devices.ts +235 -6
- package/src/cli/discover.ts +3 -1
- package/src/cli/execute.ts +129 -9
- package/src/cli/explain.ts +503 -0
- package/src/cli/mcp.ts +8 -1
- package/src/cli/retrieve.ts +167 -90
- package/src/cli/selection.ts +260 -0
- package/src/cli/settings.ts +286 -0
- package/src/cli/terminal.ts +22 -7
- package/src/cli/transfer.ts +192 -51
- package/src/cli.ts +22 -2
- package/src/core/envelope.ts +5 -2
- package/src/core/error-catalog.ts +95 -0
- package/src/core/fanout.ts +143 -2
- package/src/core/preflight.ts +306 -0
- package/src/core/routeros-string.ts +24 -0
- package/src/devices.ts +212 -20
- package/src/discover.ts +7 -2
- package/src/errors.ts +1 -0
- package/src/execute-fanout.ts +453 -0
- package/src/execute.ts +216 -68
- package/src/explain/arg-tokens.ts +114 -0
- package/src/explain/args.ts +1403 -0
- package/src/explain/blocks.ts +132 -0
- package/src/explain/brace-slots.ts +143 -0
- package/src/explain/brace-tokens.ts +38 -0
- package/src/explain/catalog.ts +1345 -0
- package/src/explain/coordinates.ts +329 -0
- package/src/explain/defects.ts +217 -0
- package/src/explain/is-known-menu.ts +17 -0
- package/src/explain/menus.ts +664 -0
- package/src/explain/operator-tokens.ts +310 -0
- package/src/explain/operators.ts +458 -0
- package/src/explain/path-tokens.ts +150 -0
- package/src/explain/pathresolve.ts +1324 -0
- package/src/explain/quoted-string.ts +241 -0
- package/src/explain/scope-brace.ts +308 -0
- package/src/explain/segment.ts +757 -0
- package/src/explain/string-tokens.ts +67 -0
- package/src/explain/symbol-values.ts +520 -0
- package/src/explain/symbols.ts +1597 -0
- package/src/explain/token-ranges.ts +72 -0
- package/src/explain/transport.ts +497 -0
- package/src/explain/value-tokens.ts +80 -0
- package/src/explain/values.ts +357 -0
- package/src/explain/verbs.ts +64 -0
- package/src/explain/verbsplit.ts +813 -0
- package/src/explain/write.ts +815 -0
- package/src/explain.ts +2152 -0
- package/src/index.ts +307 -1
- package/src/mcp/config.ts +12 -2
- package/src/mcp/tools.ts +137 -2
- package/src/protocols/adapter.ts +38 -18
- package/src/protocols/index.ts +11 -5
- package/src/protocols/mac-telnet-console.ts +61 -17
- package/src/resolver/cdb.ts +10 -2
- package/src/resolver/comment-kv.ts +58 -4
- package/src/resolver/config-file.ts +136 -0
- package/src/resolver/facts.ts +78 -0
- package/src/resolver/geo.ts +453 -0
- package/src/resolver/index.ts +65 -0
- package/src/resolver/mac.ts +12 -3
- package/src/resolver/quickchr-provider.ts +597 -0
- package/src/resolver/selection.ts +391 -0
- package/src/resolver/service-endpoint.ts +155 -0
- package/src/resolver/settings.ts +54 -5
- package/src/resolver/target.ts +21 -3
- package/src/retrieve-fanout.ts +239 -133
- package/src/retrieve.ts +120 -25
- package/src/settings.ts +1078 -0
- package/src/terminal.ts +11 -1
- package/src/transfer-fanout.ts +544 -0
- package/src/transfer.ts +133 -40
package/docs/MATRIX.md
CHANGED
|
@@ -30,137 +30,99 @@ A cell advances only with the matching evidence in the same change.
|
|
|
30
30
|
| transfer | `CHR-passed` | `CHR-passed` | `CHR-passed` | — | — | — | — | — |
|
|
31
31
|
| devices | — | — | — | — | — | — | — | — |
|
|
32
32
|
| discover | — | — | — | — | — | `CHR-passed` | — | — |
|
|
33
|
-
| check | `
|
|
33
|
+
| check | `designed` | `designed` | `designed` | `designed` | `not-started` | `not-started` | `not-started` | `not-started` |
|
|
34
|
+
| explain | `designed` | `designed` | — | — | — | — | — | — |
|
|
34
35
|
| settings | — | — | — | — | — | — | — | — |
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
`
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
`commands/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
in
|
|
62
|
-
(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
`
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
`
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
`
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
`
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
method within the rest-api/native-api cells**, not a grid column — it needs
|
|
116
|
-
inbound reachability (router → centrs) so it is never auto-selected.
|
|
117
|
-
|
|
118
|
-
`settings` is `designed` and transport-less (like `devices`), so its grid row
|
|
119
|
-
stays `—`. `commands/settings/README.md` describes the `centrs.env` + `__default__`
|
|
120
|
-
front-end (interactive first-time setup plus `settings get/set/reset/print`); no
|
|
121
|
-
code yet.
|
|
122
|
-
|
|
123
|
-
### Transport-base readiness (below the command grid)
|
|
37
|
+
## Status pointers
|
|
38
|
+
|
|
39
|
+
Detailed command contracts live in `commands/<name>/README.md`; example evidence
|
|
40
|
+
lives in `commands/<name>/examples.md` and the named integration tests. Keep this
|
|
41
|
+
section short enough that the grid remains the status surface.
|
|
42
|
+
|
|
43
|
+
- `devices` is transport-less, so its row stays `—`; command state is
|
|
44
|
+
`CHR-passed` by fixture-backed integration tests in `test/integration/devices.test.ts`.
|
|
45
|
+
- `settings` is transport-less, so its row stays `—`; command state is
|
|
46
|
+
`CHR-passed` by fixture-backed integration tests in `test/integration/settings.test.ts`.
|
|
47
|
+
- `retrieve`, `api`, `execute`, and `transfer` share the target-selection and
|
|
48
|
+
fan-out contracts from `docs/CONSTITUTION.md`; command-specific boundaries and
|
|
49
|
+
evidence are in their command READMEs and integration tests.
|
|
50
|
+
- There is no `update` command. RouterOS CLI-shaped writes ride `execute`; the
|
|
51
|
+
structured operation surface is `api`.
|
|
52
|
+
- `api --stream` absorbs the former `stream`/`tail` surface; native-api stream
|
|
53
|
+
details are in `commands/api/README.md` and `src/protocols/native-api.ts`.
|
|
54
|
+
- `discover / mndp` is grounded by `commands/discover/README.md`,
|
|
55
|
+
`src/data/mndp.ts`, `src/data/mndp-cache.ts`, and
|
|
56
|
+
`test/integration/discover.test.ts`.
|
|
57
|
+
- `check` is `designed` (`commands/check/README.md`): a reach + health battery
|
|
58
|
+
whose reads ride the execute-capable transports (rest-api/native-api/ssh/
|
|
59
|
+
mac-telnet), so those four cells are `designed`; `snmp` and `romon`/
|
|
60
|
+
`winbox-terminal` stay `not-started`. Its per-host fan-out is the machinery the
|
|
61
|
+
IP-scan discovery (#149) will iterate; the L2-default timing evidence (#136) is
|
|
62
|
+
recorded in the README before the cells advance past `designed`.
|
|
63
|
+
- `explain` is `designed` (`commands/explain/README.md`): the explain →
|
|
64
|
+
validate → run knowledge tier — canonical structure, LSP-like
|
|
65
|
+
spans/diagnostics, transport classification (api-able vs execute, `curl`
|
|
66
|
+
rendering), and live schema/completion facts. Its offline mode is the
|
|
67
|
+
canonicalizer only and opens no protocol connection (evidence is
|
|
68
|
+
unit/fixture tests); the
|
|
69
|
+
live probes (`/console/inspect` + `:parse`) ride rest-api/native-api, so
|
|
70
|
+
those two cells are `designed`. The surface was decided in the 2026-07-19
|
|
71
|
+
design round (#90) and the spec is **ratified** on the phase-0 grounding
|
|
72
|
+
lab (#185, ratification PR #187). Phase 0.5 has since promoted the ratified
|
|
73
|
+
lab logic into the library — `src/explain/{segment,blocks,coordinates,defects,
|
|
74
|
+
pathresolve,verbsplit,write,symbols,menus,verbs,args,values,brace-slots}.ts`
|
|
75
|
+
with frozen fixtures under `test/fixtures/explain/` — and phase 1 has composed
|
|
76
|
+
them into one analysis and envelope in `src/explain.ts` (`explainCommand` /
|
|
77
|
+
`explainEnvelope`, #202a). **`centrs explain '<input>'` is a real command as
|
|
78
|
+
of #202b** (`src/cli/explain.ts`), and #202c adds statement argument reading,
|
|
79
|
+
the closed Q8 transport classifier, equivalent centrs invocations, and
|
|
80
|
+
opt-in `--curl`. All offline examples, including 1, 2, 6 and 23, run green in
|
|
81
|
+
`test/unit/explain.test.ts`. The row nonetheless stays `designed`: offline
|
|
82
|
+
mode occupies no protocol cell, and the two `designed` cells are the live
|
|
83
|
+
`/console/inspect` + `:parse` probes, which are phase 2. The live grammar
|
|
84
|
+
(`explain <router> '<input>'`) is parsed and refused with
|
|
85
|
+
`usage/not-implemented` rather than degraded to an offline run. Cells advance
|
|
86
|
+
only when the live probes land and their examples run green per the done rule.
|
|
87
|
+
`src/explain/menus.ts` and `src/explain/catalog.ts` are the **generated**
|
|
88
|
+
files in that set — the RouterOS menu-vs-command table (#207, from pinned
|
|
89
|
+
restraml typed trees) and the path catalog (#228, those trees unioned with
|
|
90
|
+
MikroTik's published CLI Reference, carrying kind, per-entry provenance and
|
|
91
|
+
the published applicability gate). Regenerate with `bun run explain:menus` /
|
|
92
|
+
`bun run explain:catalog`; both are drift-checked in QA. They keep the offline
|
|
93
|
+
analyzer offline; do not hand-edit them. The catalog's **command axis is read**
|
|
94
|
+
by `pathresolve.ts`, `verbsplit.ts` and `write.ts` (#228 step 2); #235 also
|
|
95
|
+
reads its menu/settings kind, unioned with `menus.ts` behind
|
|
96
|
+
`src/explain/is-known-menu.ts`, for both a context-applied relative bare path
|
|
97
|
+
and an absolute one. Both changes are inside the offline canonicalizer, so
|
|
98
|
+
this grid is unchanged by them.
|
|
99
|
+
- `transfer / ssh` means the SFTP-backed transfer method. Deferred file-transfer
|
|
100
|
+
methods such as `scp`, `fetch`, and `ftp` are tracked in
|
|
101
|
+
`commands/transfer/README.md`; `fetch` is not a grid column.
|
|
102
|
+
- SSH grounding for `execute` and `terminal` lives in
|
|
103
|
+
`commands/execute/README.md`, `commands/terminal/README.md`,
|
|
104
|
+
`src/protocols/ssh.ts`, `src/protocols/sftp.ts`, and `src/terminal.ts`.
|
|
105
|
+
- MAC-Telnet grounding for `execute` and `terminal` lives in
|
|
106
|
+
`commands/execute/README.md`, `commands/terminal/README.md`, and the
|
|
107
|
+
`src/protocols/mac-telnet*.ts` module headers.
|
|
108
|
+
- Transport wire-format and delivery caveats belong in `src/protocols/*.ts`
|
|
109
|
+
module headers. Do not expand this file with per-packet or per-router findings.
|
|
110
|
+
|
|
111
|
+
Beyond the grid: post-`CHR-passed` hardening, ergonomics, and research work is
|
|
112
|
+
tracked in GitHub issues (`dry-july` and successors). Those issues may point back
|
|
113
|
+
to this matrix for current status, but they are not additional cell states.
|
|
114
|
+
|
|
115
|
+
### Transport-base readiness
|
|
124
116
|
|
|
125
117
|
The grid above tracks command cells. The transports those cells ride are
|
|
126
118
|
implemented and grounded in their `src/protocols/*.ts` **module headers** — the
|
|
127
|
-
single home for wire-format, auth, and delivery facts
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
`test/unit/native-api.test.ts`, `test/integration/native-api.test.ts`
|
|
135
|
-
(transport), and `test/integration/native-api-retrieve.test.ts` (command).
|
|
136
|
-
- **mac-telnet** (`src/protocols/mac-telnet.ts` + `mtwei.ts` +
|
|
137
|
-
`mac-telnet-console.ts` + `MacTelnetAdapter` in `adapter.ts`): packet/control
|
|
138
|
-
codec, session state machine, both auth methods (classic MD5 + MTWEI EC-SRP),
|
|
139
|
-
the interactive-console reader, and the UDP datagram transport with route
|
|
140
|
-
discovery. The deep findings — auth (MTWEI-required / MD5-refused /
|
|
141
|
-
`END_AUTH`≠success), console (ANSI terminal-size probe, ~10s prime stall,
|
|
142
|
-
one-time license gate, `:put [:parse]` syntax+semantic gate, silent writes),
|
|
143
|
-
reliability (byte-counter retransmit + empty-ACK keepalive), and the
|
|
144
|
-
real-device UDP-delivery facts (real egress MAC required; broadcast-only reply;
|
|
145
|
-
per-NIC directed-broadcast reach via `discoverMacTelnetRoute`; bind `0.0.0.0`)
|
|
146
|
-
— are documented in those module headers. Two cells are `CHR-passed`:
|
|
147
|
-
- **`execute / mac-telnet`**: `executeEnvelope` (resolver → `MacTelnetAdapter` →
|
|
148
|
-
UDP transport) runs reads, REST-verified writes, and the validation-reject
|
|
149
|
-
path. Green via `test/integration/mac-telnet-console.test.ts` (examples
|
|
150
|
-
19–21); transport/auth alone via `test/integration/mac-telnet.test.ts` (MTWEI
|
|
151
|
-
login + MD5 refusal). Unit: `test/unit/{mtwei,mac-telnet,mac-telnet-console}.test.ts`.
|
|
152
|
-
- **`terminal / mac-telnet`**: the interactive relay over the same console
|
|
153
|
-
reader (`MacTelnetConsole.attachInteractive`), orchestrated in
|
|
154
|
-
`src/terminal.ts` over an injectable `TerminalIo`, reusing the execute
|
|
155
|
-
resolver and the shared `resolveMacTelnetRoute`. Green via
|
|
156
|
-
`test/integration/terminal-mac-telnet.test.ts` (T1–T3) driving the real
|
|
157
|
-
`centrs terminal` binary through the subprocess harness.
|
|
158
|
-
- **Evidence caveat:** the CHR integration runs over the quickchr
|
|
159
|
-
`socket-connect` **L2 bridge** (`test/integration/mactelnet-l2-bridge.ts`), so
|
|
160
|
-
the real `createUdpMacTelnetTransport` egress/broadcast path is *not* exercised
|
|
161
|
-
in CI — the RB1100AHx4 / RouterOS 7.24beta1 real-device run grounded the
|
|
162
|
-
UDP-delivery facts (and caught the synthetic-source-MAC break). A full-TTY
|
|
163
|
-
`terminal` test (real PTY via `script(1)`/node-pty) is likewise deferred.
|
|
119
|
+
single home for wire-format, auth, and delivery facts.
|
|
120
|
+
|
|
121
|
+
| Transport | Status pointer |
|
|
122
|
+
| --------- | -------------- |
|
|
123
|
+
| native-api | Used by `retrieve`, `api`, `execute`, and `transfer`; wire facts in `src/protocols/native-api.ts`. |
|
|
124
|
+
| ssh / sftp | Used by `transfer`, `execute`, and `terminal`; facts in `src/protocols/ssh.ts`, `src/protocols/sftp.ts`, and `src/terminal.ts`. |
|
|
125
|
+
| mac-telnet | Used by `execute` and `terminal`; facts in `src/protocols/mac-telnet.ts`, `src/protocols/mac-telnet-console.ts`, `src/protocols/mtwei.ts`, and `src/protocols/adapter.ts`. |
|
|
164
126
|
|
|
165
127
|
### Frontend surfaces (orthogonal to the command grid)
|
|
166
128
|
|
|
@@ -169,9 +131,9 @@ core and carry their own state, tracked here:
|
|
|
169
131
|
|
|
170
132
|
| Surface | State | Spec | Notes |
|
|
171
133
|
| ------- | ----- | ---- | ----- |
|
|
172
|
-
| ts-api | `CHR-passed` | `src/index.ts` | Root
|
|
173
|
-
| cli | `coded` | `src/cli/` | `retrieve`/`execute`/`transfer`/`terminal`/`devices`/`discover`/`btest`
|
|
174
|
-
| mcp | `CHR-passed` | `commands/mcp/` | Scoped-verb stdio MCP server;
|
|
134
|
+
| ts-api | `CHR-passed` | `src/index.ts` | Root TypeScript library surface; everything else adapts it. |
|
|
135
|
+
| cli | `coded` | `src/cli/` | Every command in `cliCommands` (`src/cli.ts`) is wired: `retrieve`/`execute`/`api`/`transfer`/`terminal`/`explain`/`devices`/`discover`/`btest`/`mcp`/`settings`, plus the `upload`/`download` shortcuts. |
|
|
136
|
+
| mcp | `CHR-passed` | `commands/mcp/` | Scoped-verb stdio MCP server; details in `commands/mcp/README.md` and `test/integration/mcp.test.ts`. |
|
|
175
137
|
| tui | `not-started` | `src/tui.ts` | Stub. |
|
|
176
138
|
| proxy | `not-started` | `src/webproxy.ts` | Stub. |
|
|
177
139
|
|
|
@@ -183,46 +145,17 @@ are documented in `commands/mcp/README.md` and `commands/mcp/examples.md`.
|
|
|
183
145
|
|
|
184
146
|
### Peer measurement (`btest`) — orthogonal to the command grid
|
|
185
147
|
|
|
186
|
-
`btest` is the MikroTik
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
from the `:parse` / `/console/inspect` gate. v1 scope (decided with the user):
|
|
190
|
-
**both** client and server, **EC-SRP5 + unauthenticated**, **TCP and UDP** (legacy
|
|
191
|
-
pre-6.43 double-MD5 is out of scope).
|
|
148
|
+
`btest` is the MikroTik bandwidth test (peer measurement, TCP/UDP port 2000),
|
|
149
|
+
not a RouterOS-command transport. It sits outside the command×protocol grid as
|
|
150
|
+
its own capability axis and is exempt from the RouterOS command-validation gate.
|
|
192
151
|
|
|
193
152
|
| Mode | State | Evidence |
|
|
194
153
|
| -------------- | ------------ | -------- |
|
|
195
|
-
| btest / server | `CHR-passed` |
|
|
196
|
-
| btest / client | `CHR-passed` |
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
orchestrator + CLI, and the honest grounding caveat (the server gets direct CHR
|
|
201
|
-
evidence over the QEMU SLIRP gateway `10.0.2.2`; the client gets direct CHR
|
|
202
|
-
evidence over a host→guest `tcp:2000` forward (the forward carries TCP; UDP rides
|
|
203
|
-
the guest→host gateway instead, below); UDP-receive was
|
|
204
|
-
previously a soft smoke test because the SLIRP reverse path was believed to block
|
|
205
|
-
real validation and a `connect()` socket filter was silently dropping all received
|
|
206
|
-
datagrams — RouterOS sends UDP data **from a different source port** than the
|
|
207
|
-
negotiated `serverUdpPort`, so the BSD receive filter rejected every packet;
|
|
208
|
-
fixed by removing `connect()` and addressing sends explicitly, validated against
|
|
209
|
-
a real RouterOS device at 163–203 Mbps receive and 104 Mbps bidirectional, and
|
|
210
|
-
**CI now gates UDP client receive/both** — the server→client return rides the
|
|
211
|
-
guest→host SLIRP gateway (`10.0.2.2:clientUdpPort`), needing no UDP forward and no
|
|
212
|
-
quickchr change (#88 closed; the `connect()` filter fix in #86 is what enabled it);
|
|
213
|
-
TCP
|
|
214
|
-
`connection-count` reaches the server's command packet (#84) and centrs opens the
|
|
215
|
-
negotiated extra TCP data connections — multi-connection **fan-out** (#87),
|
|
216
|
-
grounded byte-for-byte against RouterOS 7.23.1 (secondary join
|
|
217
|
-
`[token:u16 BE][0x02][0 …]`) and CHR-gated for the realized fan-out
|
|
218
|
-
(`activeConnections == count`; no throughput-rise assertion — the SLIRP loopback is
|
|
219
|
-
bandwidth-bound); authenticated sessions stay single-stream (warned); TCP
|
|
220
|
-
`direction=both` demuxes the server's
|
|
221
|
-
interleaved status frames so the client paces its TX from feedback and does not
|
|
222
|
-
starve server→client RX (#85 fixed); the Windows unit tier skips UDP-loopback
|
|
223
|
-
tests (#69); NDJSON is not adopted) are
|
|
224
|
-
documented in `commands/btest/README.md` and the `src/protocols/btest.ts`,
|
|
225
|
-
`src/protocols/btest-session.ts`, and `src/protocols/ec-srp5.ts` module headers.
|
|
154
|
+
| btest / server | `CHR-passed` | `test/integration/btest.test.ts`; details in `commands/btest/README.md`. |
|
|
155
|
+
| btest / client | `CHR-passed` | `test/integration/btest-client.test.ts`; details in `commands/btest/README.md`. |
|
|
156
|
+
|
|
157
|
+
Wire, auth, TCP/UDP, and CI caveats live in `commands/btest/README.md` and the
|
|
158
|
+
`src/protocols/btest*.ts` / `src/protocols/ec-srp5.ts` module headers.
|
|
226
159
|
|
|
227
160
|
## Priority order
|
|
228
161
|
|
|
@@ -230,18 +163,18 @@ Do not start a later item until the earlier cell or dependency checkpoint has
|
|
|
230
163
|
matching evidence. The grid above is the live status; per-item detail lives in
|
|
231
164
|
the linked `commands/<name>/`.
|
|
232
165
|
|
|
233
|
-
1. **retrieve / rest-api** — `CHR-passed
|
|
166
|
+
1. **retrieve / rest-api** — `CHR-passed` (`commands/retrieve/`).
|
|
234
167
|
2. **CDB resolution + metadata overrides** — `CHR-passed` (`commands/devices/`).
|
|
235
|
-
3. **CDB groups +
|
|
236
|
-
4. **execute / native-api + rest-api** — `CHR-passed` (`commands/execute/`).
|
|
168
|
+
3. **CDB groups + fan-out** — `CHR-passed` (`commands/devices/`, fan-out core).
|
|
169
|
+
4. **execute / native-api + rest-api** — `CHR-passed` (`commands/execute/`).
|
|
237
170
|
5. **devices** (CDB mutation + provenance) — `CHR-passed` (`commands/devices/`).
|
|
238
171
|
6. **retrieve / snmp** — `not-started` (future: SNMP OID/MIB reads + MikroTik MIB cache).
|
|
239
|
-
7. **ssh** for transfer/execute/terminal —
|
|
240
|
-
8. **mac-telnet** for execute/terminal — both `CHR-passed
|
|
172
|
+
7. **ssh** for transfer/execute/terminal — all three `CHR-passed`.
|
|
173
|
+
8. **mac-telnet** for execute/terminal — both `CHR-passed`.
|
|
241
174
|
9. **RoMON / WinBox Terminal for execute** — `not-started` (see Open questions).
|
|
242
175
|
10. **discover / mndp** — `CHR-passed` (`commands/discover/`).
|
|
243
|
-
11. **MCP, TUI, proxy** —
|
|
244
|
-
12. **btest (peer measurement)** — server
|
|
176
|
+
11. **MCP, TUI, proxy** — MCP `CHR-passed`; TUI/proxy `not-started`.
|
|
177
|
+
12. **btest (peer measurement)** — server and client both `CHR-passed`.
|
|
245
178
|
|
|
246
179
|
## Open questions (decisions needed before the affected cell can advance)
|
|
247
180
|
|
package/docs/errors/README.md
CHANGED
|
@@ -47,10 +47,14 @@ Codes are slash-namespaced `family/slug`. The families and where they originate:
|
|
|
47
47
|
- `input/*` — malformed caller input (paths, MACs, arguments).
|
|
48
48
|
- `internal/*` — centrs bugs / unreachable states.
|
|
49
49
|
- `mndp/*` — MNDP wire codec and listener (`src/data/mndp.ts`).
|
|
50
|
+
- `quickchr/*` — the quickchr named-live-provider (`--quickchr <name>`): optional
|
|
51
|
+
package availability, descriptor version support, and machine lookup/liveness
|
|
52
|
+
(`src/resolver/quickchr-provider.ts`).
|
|
50
53
|
- `routeros/*` — RouterOS-surfaced faults mapped by the grounded vocabulary in
|
|
51
54
|
`src/core/routeros-errors.ts` (REST `detail` and native-api `!trap`, identical
|
|
52
55
|
on CHR 7.23).
|
|
53
|
-
- `settings/*` — settings/value parsing (`src/resolver/settings.ts`)
|
|
56
|
+
- `settings/*` — settings/value parsing (`src/resolver/settings.ts`) and the
|
|
57
|
+
`centrs settings` command's own registry/refusal rules (`src/settings.ts`).
|
|
54
58
|
- `target/*` — turning a `<router>` into a transport endpoint.
|
|
55
59
|
- `transport/*` — connection, TLS, DNS, and timeout plumbing.
|
|
56
60
|
- `usage/*` — how a command was invoked (arity, conflicting flags, confirmation).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# `cdb/empty-selection`
|
|
2
|
+
|
|
3
|
+
The target selection matched no CDB records.
|
|
4
|
+
|
|
5
|
+
## Fix
|
|
6
|
+
|
|
7
|
+
A fan-out selection involving `--where` / `--all` / `--default` / positionals (on
|
|
8
|
+
its own or mixed with `--group`) resolved to zero targets. This is reported as a
|
|
9
|
+
warning on an `ok: true` fan-out envelope with `summary { total: 0, ok: 0, failed:
|
|
10
|
+
0 }`, not a hard failure — there was simply nothing to run.
|
|
11
|
+
|
|
12
|
+
A **group-only** empty (bare `--group`, no other selector) is reported as
|
|
13
|
+
[`cdb/empty-group`](empty-group.md) instead, naming the group that matched nothing;
|
|
14
|
+
this page covers every other empty selection.
|
|
15
|
+
|
|
16
|
+
Check the selector: run `centrs devices list` (and `centrs devices groups`) to see
|
|
17
|
+
the registered records, groups, and the facts a `--where <attr>=<value>` can match.
|
|
18
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) (Target selection) for the
|
|
19
|
+
selector grammar.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# `input/incomplete-gps`
|
|
2
|
+
|
|
3
|
+
lat/lon (or a --gps tuple) were not given as a complete pair.
|
|
4
|
+
|
|
5
|
+
## Fix
|
|
6
|
+
|
|
7
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) for the centrs error
|
|
8
|
+
contract. This stub will be expanded with the typical trigger and remediation
|
|
9
|
+
for `input/incomplete-gps`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# `input/invalid-altitude`
|
|
2
|
+
|
|
3
|
+
The altitude is not a number, or altitude-type is not MSL/AGL.
|
|
4
|
+
|
|
5
|
+
## Fix
|
|
6
|
+
|
|
7
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) for the centrs error
|
|
8
|
+
contract. This stub will be expanded with the typical trigger and remediation
|
|
9
|
+
for `input/invalid-altitude`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# `input/invalid-bbox`
|
|
2
|
+
|
|
3
|
+
The --bbox is not four lat-first corners with south<=north and west<=east.
|
|
4
|
+
|
|
5
|
+
## Fix
|
|
6
|
+
|
|
7
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) for the centrs error
|
|
8
|
+
contract. This stub will be expanded with the typical trigger and remediation
|
|
9
|
+
for `input/invalid-bbox`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# `input/invalid-coordinate`
|
|
2
|
+
|
|
3
|
+
The latitude or longitude is not a number in its valid range.
|
|
4
|
+
|
|
5
|
+
## Fix
|
|
6
|
+
|
|
7
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) for the centrs error
|
|
8
|
+
contract. This stub will be expanded with the typical trigger and remediation
|
|
9
|
+
for `input/invalid-coordinate`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# `input/invalid-radius`
|
|
2
|
+
|
|
3
|
+
The --near radius is not a number with an optional m/km/mi/ft suffix.
|
|
4
|
+
|
|
5
|
+
## Fix
|
|
6
|
+
|
|
7
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) for the centrs error
|
|
8
|
+
contract. This stub will be expanded with the typical trigger and remediation
|
|
9
|
+
for `input/invalid-radius`.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# `internal/settings-failed`
|
|
2
|
+
|
|
3
|
+
The settings command failed with an unexpected internal error.
|
|
4
|
+
|
|
5
|
+
## Fix
|
|
6
|
+
|
|
7
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) for the centrs error
|
|
8
|
+
contract. This stub will be expanded with the typical trigger and remediation
|
|
9
|
+
for `internal/settings-failed`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# `quickchr/machine-not-found`
|
|
2
|
+
|
|
3
|
+
No quickchr machine is registered under the name passed to `--quickchr <name>`.
|
|
4
|
+
|
|
5
|
+
## Typical trigger
|
|
6
|
+
|
|
7
|
+
The name does not match any machine quickchr knows about — a typo, a machine
|
|
8
|
+
that was never created, or one that has been removed. centrs raises this both
|
|
9
|
+
when `QuickCHR.get(name)` returns nothing and when the descriptor call reports
|
|
10
|
+
quickchr's own `MACHINE_NOT_FOUND`.
|
|
11
|
+
|
|
12
|
+
## Fix
|
|
13
|
+
|
|
14
|
+
- List the registered machines with `quickchr list` and pass an existing name.
|
|
15
|
+
- Create/start the machine first if it does not exist yet (`quickchr start
|
|
16
|
+
<name>`).
|
|
17
|
+
- Names are exact — check for typos and case.
|
|
18
|
+
|
|
19
|
+
If the machine exists but is not running, you will see
|
|
20
|
+
[`quickchr/machine-stopped`](./machine-stopped.md) instead.
|
|
21
|
+
|
|
22
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) → Resolution providers.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# `quickchr/machine-stopped`
|
|
2
|
+
|
|
3
|
+
The named quickchr machine exists but is not running, so it has no live
|
|
4
|
+
connection facts (host, forwarded ports, credentials) for centrs to dial.
|
|
5
|
+
|
|
6
|
+
## Typical trigger
|
|
7
|
+
|
|
8
|
+
`--quickchr <name>` named a real machine, but its VM is stopped. quickchr only
|
|
9
|
+
knows the forwarded loopback ports and running-state auth while the machine is
|
|
10
|
+
up, so a stopped machine cannot yield a `ServiceEndpointMap`.
|
|
11
|
+
|
|
12
|
+
## Fix
|
|
13
|
+
|
|
14
|
+
- Start it: `quickchr start <name>`, then retry `--quickchr <name>`.
|
|
15
|
+
- Confirm state with `quickchr list` / `quickchr inspect <name>`.
|
|
16
|
+
|
|
17
|
+
This is a per-target failure: in a fan-out over several `--quickchr` targets,
|
|
18
|
+
one stopped machine fails only its own row, not the whole run.
|
|
19
|
+
|
|
20
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) → Resolution providers.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# `quickchr/package-unavailable`
|
|
2
|
+
|
|
3
|
+
The optional `@tikoci/quickchr` package is not installed, so a `--quickchr
|
|
4
|
+
<name>` target cannot be resolved into connection facts.
|
|
5
|
+
|
|
6
|
+
## Typical trigger
|
|
7
|
+
|
|
8
|
+
You passed `--quickchr <name>` (or otherwise resolved a quickchr target) in an
|
|
9
|
+
install that does not have `@tikoci/quickchr`. centrs declares it as an
|
|
10
|
+
**optional dependency** and loads it through a runtime import, so a normal
|
|
11
|
+
install without it works for every non-quickchr path and only fails here.
|
|
12
|
+
|
|
13
|
+
## Fix
|
|
14
|
+
|
|
15
|
+
- Install the package: `bun add @tikoci/quickchr` (0.4.5+ — 0.4.4 introduced
|
|
16
|
+
the descriptor v1 API but advertises dead TLS endpoints on a stock CHR;
|
|
17
|
+
see quickchr#95).
|
|
18
|
+
- Or bypass quickchr entirely and target the device directly with `--host`
|
|
19
|
+
(plus `--username`/`--password`/`--ssh-key` or a CDB record).
|
|
20
|
+
|
|
21
|
+
This code is raised **only** when the module is genuinely not found. An
|
|
22
|
+
installed package that throws while loading reports
|
|
23
|
+
[`quickchr/unsupported`](./unsupported.md) instead, so the two are never
|
|
24
|
+
confused.
|
|
25
|
+
|
|
26
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) → Resolution providers for
|
|
27
|
+
the named-live-provider contract.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# `quickchr/unsupported-via`
|
|
2
|
+
|
|
3
|
+
The quickchr machine resolved fine, but the chosen `--via` has no usable
|
|
4
|
+
service on it. The descriptor is per-service; centrs reads exactly the
|
|
5
|
+
endpoint for the chosen protocol and never falls back to another transport.
|
|
6
|
+
|
|
7
|
+
## Typical trigger
|
|
8
|
+
|
|
9
|
+
Any of:
|
|
10
|
+
|
|
11
|
+
- The `--via` is a protocol the descriptor does not forward. quickchr v1
|
|
12
|
+
forwards `rest-api`, `native-api`, and `ssh` only — `mac-telnet`, `romon`,
|
|
13
|
+
`btest`, and `winbox-terminal` are never available on a quickchr target.
|
|
14
|
+
- The service exists but quickchr marked it `available: false` (the error
|
|
15
|
+
carries the provider's `unavailableReason`).
|
|
16
|
+
- `--via ssh` (or `transfer --via sftp`/`scp`): the SSH endpoint reports no
|
|
17
|
+
batch-capable auth mode (`batchModes` is empty), so a non-interactive
|
|
18
|
+
handoff is impossible. centrs fails typed here rather than prompt for a
|
|
19
|
+
password or silently pick another transport.
|
|
20
|
+
|
|
21
|
+
## Fix
|
|
22
|
+
|
|
23
|
+
- Pick one of the machine's live services; the error's `availableServices`
|
|
24
|
+
context lists them (typically `--via rest-api` / `--via native-api` /
|
|
25
|
+
`--via ssh`).
|
|
26
|
+
- For the SSH/sftp gate, verify key-based login works from quickchr's side
|
|
27
|
+
(`quickchr ssh <name>`); once quickchr has a verified key, the descriptor
|
|
28
|
+
advertises `private-key` in `batchModes` and centrs will use it.
|
|
29
|
+
- If the machine should be forwarding the service but is not, inspect it with
|
|
30
|
+
`quickchr inspect <name>`.
|
|
31
|
+
- To use a transport quickchr does not forward, target the device directly
|
|
32
|
+
(`--host`/CDB record) instead of `--quickchr`.
|
|
33
|
+
|
|
34
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) → Resolution providers for
|
|
35
|
+
why a provider's missing service is a typed error, never a silent fallback.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# `quickchr/unsupported`
|
|
2
|
+
|
|
3
|
+
The installed `@tikoci/quickchr` cannot give centrs a usable descriptor: it is
|
|
4
|
+
too old to expose the descriptor API, it failed to load, or it emitted a
|
|
5
|
+
descriptor centrs cannot read.
|
|
6
|
+
|
|
7
|
+
## Typical trigger
|
|
8
|
+
|
|
9
|
+
Any of:
|
|
10
|
+
|
|
11
|
+
- The installed quickchr predates the `QuickCHR.get(name).descriptor()` API
|
|
12
|
+
(before 0.4.4), so the descriptor entry point is missing.
|
|
13
|
+
- The package is installed but throws while loading (a broken/partial install),
|
|
14
|
+
which is a real fault — distinct from
|
|
15
|
+
[`quickchr/package-unavailable`](./package-unavailable.md), which means "not
|
|
16
|
+
installed at all".
|
|
17
|
+
- The descriptor is malformed or pre-v1: no numeric `descriptorVersion`, no
|
|
18
|
+
`services` map, or missing `name`/`version`/`arch`. centrs rejects it rather
|
|
19
|
+
than crash on a later field access or silently treat `services` as empty
|
|
20
|
+
(which would hide a provider contract violation).
|
|
21
|
+
- The descriptor version is **newer** than centrs supports
|
|
22
|
+
(`descriptorVersion` > 1); a newer quickchr speaks a schema this centrs
|
|
23
|
+
predates.
|
|
24
|
+
|
|
25
|
+
## Fix
|
|
26
|
+
|
|
27
|
+
- Upgrade quickchr to a release that emits descriptor v1: `bun add
|
|
28
|
+
@tikoci/quickchr` (0.4.5+ — 0.4.4 has the API but a descriptor endpoint
|
|
29
|
+
bug, quickchr#95).
|
|
30
|
+
- If the descriptor looks wrong, inspect the machine directly with `quickchr
|
|
31
|
+
inspect <name>` — it may be in a transient state.
|
|
32
|
+
- If the descriptor is newer than centrs supports, upgrade centrs.
|
|
33
|
+
|
|
34
|
+
See [`docs/CONSTITUTION.md`](../../CONSTITUTION.md) → Resolution providers for
|
|
35
|
+
the descriptor contract and the supported version boundary.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# `routeros/version-unsupported`
|
|
2
|
+
|
|
3
|
+
The device's RouterOS version does not provide the operation this command
|
|
4
|
+
needs. centrs pre-flighted the generated command against the device's known
|
|
5
|
+
version (a live read, or the stored CDB `version=` fact) and refused it before
|
|
6
|
+
touching the router, instead of letting the device return a raw protocol
|
|
7
|
+
error.
|
|
8
|
+
|
|
9
|
+
Distinct from `routeros/unsupported-capability`, where the chosen *protocol*
|
|
10
|
+
cannot carry the operation at all regardless of device version.
|
|
11
|
+
|
|
12
|
+
## Context fields
|
|
13
|
+
|
|
14
|
+
- `capability` — stable slug of the missing operation.
|
|
15
|
+
- `version` — the device version that was checked.
|
|
16
|
+
- `versionSource` — `live`, `cdb-fact`, or `caller`. A `cdb-fact` version is
|
|
17
|
+
stale-by-nature; it was recorded by `discover --save` or `devices --check`.
|
|
18
|
+
- `supported` — the version windows where RouterOS provides the operation
|
|
19
|
+
(inclusive `min`, optional exclusive `maxExclusive` for backport windows).
|
|
20
|
+
|
|
21
|
+
## Fix
|
|
22
|
+
|
|
23
|
+
Upgrade RouterOS to one of the versions listed in `supported`. If the device
|
|
24
|
+
was already upgraded and the check used a stale stored fact
|
|
25
|
+
(`versionSource: "cdb-fact"`), refresh the record's `version=` comment fact
|
|
26
|
+
and retry.
|