@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/src/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export {
|
|
|
17
17
|
apiListen,
|
|
18
18
|
apiMethods,
|
|
19
19
|
apiOutputFormats,
|
|
20
|
+
apiRequestSummaryFromRequest,
|
|
20
21
|
buildApiBody,
|
|
21
22
|
buildApiErrorEnvelope,
|
|
22
23
|
buildApiErrorEnvelopeFromResolved,
|
|
@@ -26,6 +27,7 @@ export {
|
|
|
26
27
|
mapMethodToVerb,
|
|
27
28
|
type NormalizedApiEndpoint,
|
|
28
29
|
normalizeApiEndpoint,
|
|
30
|
+
parseApiMethod,
|
|
29
31
|
type ResolvedApiRequest,
|
|
30
32
|
renderApiEnvelope,
|
|
31
33
|
renderApiStreamLine,
|
|
@@ -33,6 +35,18 @@ export {
|
|
|
33
35
|
runResolvedApi,
|
|
34
36
|
validateApiRequestShape,
|
|
35
37
|
} from "./api.ts";
|
|
38
|
+
export {
|
|
39
|
+
type ApiFanoutData,
|
|
40
|
+
type ApiFanoutEnvelope,
|
|
41
|
+
type ApiFanoutErrorEnvelope,
|
|
42
|
+
type ApiFanoutInternals,
|
|
43
|
+
type ApiFanoutOperationMeta,
|
|
44
|
+
type ApiFanoutOptions,
|
|
45
|
+
type ApiSelectionSummary,
|
|
46
|
+
apiFanout,
|
|
47
|
+
buildApiFanoutErrorEnvelope,
|
|
48
|
+
renderApiFanoutEnvelope,
|
|
49
|
+
} from "./api-fanout.ts";
|
|
36
50
|
export {
|
|
37
51
|
BTEST_CLIENT_CSV_HEADER,
|
|
38
52
|
BTEST_SERVER_CSV_HEADER,
|
|
@@ -75,13 +89,18 @@ export {
|
|
|
75
89
|
type Warning,
|
|
76
90
|
} from "./core/envelope.ts";
|
|
77
91
|
export {
|
|
92
|
+
buildFanoutEnvelope,
|
|
93
|
+
buildFanoutResolveFailure,
|
|
94
|
+
commonVia,
|
|
78
95
|
FANOUT_BACKOFF_BASE_MS,
|
|
79
96
|
FANOUT_CONCURRENCY_DEFAULTS,
|
|
80
97
|
FANOUT_MAX_RETRIES,
|
|
81
98
|
FANOUT_RETRYABLE_CODES,
|
|
99
|
+
fanoutExitCode,
|
|
82
100
|
isRetryableFanoutError,
|
|
83
101
|
resolveFanoutConcurrency,
|
|
84
102
|
runBoundedPool,
|
|
103
|
+
runFanout,
|
|
85
104
|
runWithRetry,
|
|
86
105
|
summarizeFanout,
|
|
87
106
|
} from "./core/fanout.ts";
|
|
@@ -99,6 +118,24 @@ export {
|
|
|
99
118
|
isCommandNode,
|
|
100
119
|
pathTokens,
|
|
101
120
|
} from "./core/inspect.ts";
|
|
121
|
+
export {
|
|
122
|
+
assertCapability,
|
|
123
|
+
type CapabilityRequirement,
|
|
124
|
+
checkCapability,
|
|
125
|
+
compareRouterOsVersion,
|
|
126
|
+
type DeviceVersion,
|
|
127
|
+
type DeviceVersionSource,
|
|
128
|
+
type PreflightState,
|
|
129
|
+
type PreflightVerdict,
|
|
130
|
+
parseRouterOsVersion,
|
|
131
|
+
probeDeviceVersion,
|
|
132
|
+
type RouterOsVersionParts,
|
|
133
|
+
type RouterOsVersionRange,
|
|
134
|
+
renderSupportedRanges,
|
|
135
|
+
routerOsVersionAtLeast,
|
|
136
|
+
versionFactFromComment,
|
|
137
|
+
versionInRange,
|
|
138
|
+
} from "./core/preflight.ts";
|
|
102
139
|
export {
|
|
103
140
|
encodeMndpPacket,
|
|
104
141
|
MNDP_BROADCAST_ADDRESS,
|
|
@@ -173,6 +210,7 @@ export {
|
|
|
173
210
|
type DevicesShowEnvelopeData,
|
|
174
211
|
type DevicesShowItem,
|
|
175
212
|
type DevicesWarning,
|
|
213
|
+
type DevicesWhereClause,
|
|
176
214
|
defaultCdbPath,
|
|
177
215
|
devicesOutputFormats,
|
|
178
216
|
editInteractiveOnlyError,
|
|
@@ -228,6 +266,7 @@ export {
|
|
|
228
266
|
canonicalizeExecuteCommand,
|
|
229
267
|
type ExecuteEnvelope,
|
|
230
268
|
type ExecuteErrorEnvelope,
|
|
269
|
+
type ExecuteGlobalContext,
|
|
231
270
|
type ExecuteOperationMeta,
|
|
232
271
|
type ExecuteOutputFormat,
|
|
233
272
|
type ExecuteRequest,
|
|
@@ -238,10 +277,207 @@ export {
|
|
|
238
277
|
executeOutputFormats,
|
|
239
278
|
isWriteShaped,
|
|
240
279
|
renderExecuteEnvelope,
|
|
280
|
+
resolveExecuteGlobalContext,
|
|
241
281
|
resolveExecuteRequest,
|
|
242
282
|
runResolvedExecute,
|
|
243
283
|
validateExecuteRequestShape,
|
|
244
284
|
} from "./execute.ts";
|
|
285
|
+
export {
|
|
286
|
+
buildExecuteFanoutErrorEnvelope,
|
|
287
|
+
type ExecuteFanoutData,
|
|
288
|
+
type ExecuteFanoutEnvelope,
|
|
289
|
+
type ExecuteFanoutErrorEnvelope,
|
|
290
|
+
type ExecuteFanoutInternals,
|
|
291
|
+
type ExecuteFanoutOperationMeta,
|
|
292
|
+
type ExecuteFanoutOptions,
|
|
293
|
+
type ExecuteSelectionSummary,
|
|
294
|
+
executeFanout,
|
|
295
|
+
renderExecuteFanoutEnvelope,
|
|
296
|
+
} from "./execute-fanout.ts";
|
|
297
|
+
// The lexer's own names are module-scoped and read naturally there; at the
|
|
298
|
+
// package root they need the `Explain` prefix every other explain export
|
|
299
|
+
// carries — a bare `Argument` says nothing about which of centrs's surfaces it
|
|
300
|
+
// belongs to. Aliasing at the re-export is the existing pattern here (see
|
|
301
|
+
// `occurrences as explainOccurrences` below).
|
|
302
|
+
//
|
|
303
|
+
// `ExplainArgument` and `ExplainArgumentToken` are the same SHAPE in two
|
|
304
|
+
// coordinate spaces: this one is what `lexArguments` returns, with spans
|
|
305
|
+
// relative to the statement it was handed; the `Token` is that rebased into
|
|
306
|
+
// document space by `explainCommand`. A consumer reading `explainCommand`'s
|
|
307
|
+
// result wants the latter.
|
|
308
|
+
export {
|
|
309
|
+
type Argument as ExplainArgument,
|
|
310
|
+
type ArgumentKind as ExplainArgumentKind,
|
|
311
|
+
type ArgumentReading as ExplainArgumentReading,
|
|
312
|
+
type ArgumentsRead as ExplainArgumentsRead,
|
|
313
|
+
type ArgumentsUnread as ExplainArgumentsUnread,
|
|
314
|
+
lexArguments as lexExplainArguments,
|
|
315
|
+
lexValueAnchors as lexExplainValueAnchors,
|
|
316
|
+
type ValueAnchor as ExplainValueAnchor,
|
|
317
|
+
type ValueAnchorKind as ExplainValueAnchorKind,
|
|
318
|
+
type ValueAnchorReading as ExplainValueAnchorReading,
|
|
319
|
+
} from "./explain/args.ts";
|
|
320
|
+
export {
|
|
321
|
+
DIRECTIVE_BODY,
|
|
322
|
+
HEAD_SCOPED_ARG_NAMES,
|
|
323
|
+
isScopeBrace,
|
|
324
|
+
matchBrace,
|
|
325
|
+
SCOPE_ARG_NAMES,
|
|
326
|
+
type ScopeBlock,
|
|
327
|
+
scopeBlocks,
|
|
328
|
+
scopeBodies,
|
|
329
|
+
scopeNameAt,
|
|
330
|
+
} from "./explain/blocks.ts";
|
|
331
|
+
export {
|
|
332
|
+
analyzeCoordinates,
|
|
333
|
+
byteSpanToRange,
|
|
334
|
+
byteToPosition,
|
|
335
|
+
type CharRun,
|
|
336
|
+
type CoordinateAnalysis,
|
|
337
|
+
coordinateDefects,
|
|
338
|
+
type Position,
|
|
339
|
+
positionToByte,
|
|
340
|
+
type Range,
|
|
341
|
+
runAtByte,
|
|
342
|
+
SUB,
|
|
343
|
+
} from "./explain/coordinates.ts";
|
|
344
|
+
export {
|
|
345
|
+
type Defect,
|
|
346
|
+
type DefectCode,
|
|
347
|
+
defectAt,
|
|
348
|
+
hasStructuralDefect,
|
|
349
|
+
isPositionalFact,
|
|
350
|
+
mergeDefects,
|
|
351
|
+
rebaseDefects,
|
|
352
|
+
} from "./explain/defects.ts";
|
|
353
|
+
export {
|
|
354
|
+
type DocumentAnalysis,
|
|
355
|
+
type Resolution,
|
|
356
|
+
resolveDocument,
|
|
357
|
+
resolveStatements,
|
|
358
|
+
type Span,
|
|
359
|
+
type StatementAnalysis,
|
|
360
|
+
type StatementResolution,
|
|
361
|
+
} from "./explain/pathresolve.ts";
|
|
362
|
+
export {
|
|
363
|
+
maskComments,
|
|
364
|
+
type QuotedStringScan,
|
|
365
|
+
type Segment,
|
|
366
|
+
type SegmentResult,
|
|
367
|
+
scanQuotedString,
|
|
368
|
+
segmentStatements,
|
|
369
|
+
} from "./explain/segment.ts";
|
|
370
|
+
export {
|
|
371
|
+
HIGHLIGHT_CLASS,
|
|
372
|
+
resolveSymbols,
|
|
373
|
+
type SymbolAnalysis,
|
|
374
|
+
type SymbolClass,
|
|
375
|
+
type SymbolOccurrence,
|
|
376
|
+
type SymbolRole,
|
|
377
|
+
} from "./explain/symbols.ts";
|
|
378
|
+
export type {
|
|
379
|
+
ExplainApiCandidateTransport,
|
|
380
|
+
ExplainExecuteTransport,
|
|
381
|
+
ExplainRestMethod,
|
|
382
|
+
ExplainRestRequest,
|
|
383
|
+
ExplainTransport,
|
|
384
|
+
ExplainTransportClassification,
|
|
385
|
+
ExplainUnknownTransport,
|
|
386
|
+
} from "./explain/transport.ts";
|
|
387
|
+
export {
|
|
388
|
+
VALUE_SHAPES,
|
|
389
|
+
type ValueContext as ExplainValueContext,
|
|
390
|
+
type ValueShape as ExplainValueShape,
|
|
391
|
+
type ValueShapeOptions as ExplainValueShapeOptions,
|
|
392
|
+
valueShapeHints as explainValueShapeHints,
|
|
393
|
+
} from "./explain/values.ts";
|
|
394
|
+
export {
|
|
395
|
+
type DocumentVerbSplit,
|
|
396
|
+
describeStatement,
|
|
397
|
+
isDirective,
|
|
398
|
+
type RunToken,
|
|
399
|
+
resolveVerb,
|
|
400
|
+
resolveVerbs,
|
|
401
|
+
runTokens,
|
|
402
|
+
type Sep,
|
|
403
|
+
type Split,
|
|
404
|
+
SUBMENU_DIRECTIVES,
|
|
405
|
+
splitRun,
|
|
406
|
+
VERBS,
|
|
407
|
+
type VerbAnalysis,
|
|
408
|
+
type VerbResolution,
|
|
409
|
+
type VerbSplit,
|
|
410
|
+
type VerbSplitCommandReading,
|
|
411
|
+
type VerbSplitMenuReading,
|
|
412
|
+
type VerbSplitRefusal,
|
|
413
|
+
} from "./explain/verbsplit.ts";
|
|
414
|
+
export {
|
|
415
|
+
classifyVerb,
|
|
416
|
+
containsWrite,
|
|
417
|
+
type Occurrence,
|
|
418
|
+
type OccurrenceClass,
|
|
419
|
+
// `occurrences` is too generic for the library root; the module-local name
|
|
420
|
+
// stays short because inside `write.ts` there is only one kind.
|
|
421
|
+
occurrences as explainOccurrences,
|
|
422
|
+
READ_VERBS,
|
|
423
|
+
ROOT_CMDS,
|
|
424
|
+
ROOT_DYNAMIC,
|
|
425
|
+
ROOT_WRITE,
|
|
426
|
+
WRITE_VERBS,
|
|
427
|
+
type WriteAnalysis,
|
|
428
|
+
type WriteVerdict,
|
|
429
|
+
} from "./explain/write.ts";
|
|
430
|
+
export {
|
|
431
|
+
buildExplainErrorEnvelope,
|
|
432
|
+
buildExplainFacetTip,
|
|
433
|
+
type ExplainArguments,
|
|
434
|
+
type ExplainArgumentToken,
|
|
435
|
+
type ExplainBlock,
|
|
436
|
+
type ExplainCanonical,
|
|
437
|
+
type ExplainCommandOptions,
|
|
438
|
+
type ExplainCommandReading,
|
|
439
|
+
type ExplainData,
|
|
440
|
+
type ExplainDiagnostic,
|
|
441
|
+
type ExplainEnvelope,
|
|
442
|
+
type ExplainEnvelopeOptions,
|
|
443
|
+
type ExplainErrorEnvelope,
|
|
444
|
+
type ExplainEvidence,
|
|
445
|
+
type ExplainFailOn,
|
|
446
|
+
type ExplainInput,
|
|
447
|
+
type ExplainMenuReading,
|
|
448
|
+
type ExplainOperationMeta,
|
|
449
|
+
type ExplainOutputFormat,
|
|
450
|
+
type ExplainPositionMapEntry,
|
|
451
|
+
type ExplainReading,
|
|
452
|
+
type ExplainRefusal,
|
|
453
|
+
type ExplainResolution,
|
|
454
|
+
type ExplainSeverity,
|
|
455
|
+
type ExplainSpan,
|
|
456
|
+
type ExplainSpanClass,
|
|
457
|
+
type ExplainSpanRange,
|
|
458
|
+
type ExplainStatement,
|
|
459
|
+
type ExplainStatementFacts,
|
|
460
|
+
type ExplainStructure,
|
|
461
|
+
type ExplainSubcommand,
|
|
462
|
+
type ExplainSubcommandFacts,
|
|
463
|
+
type ExplainSymbolClass,
|
|
464
|
+
type ExplainSymbolOccurrence,
|
|
465
|
+
type ExplainSymbols,
|
|
466
|
+
type ExplainToken,
|
|
467
|
+
type ExplainTokenClass,
|
|
468
|
+
type ExplainValueFacts,
|
|
469
|
+
type ExplainValueOccurrence,
|
|
470
|
+
type ExplainValueShapeFact,
|
|
471
|
+
type ExplainValues,
|
|
472
|
+
type ExplainValueTypeFact,
|
|
473
|
+
type ExplainVerdict,
|
|
474
|
+
explainCommand,
|
|
475
|
+
explainEnvelope,
|
|
476
|
+
explainExitCode,
|
|
477
|
+
explainFailOnLevels,
|
|
478
|
+
explainOutputFormats,
|
|
479
|
+
renderExplainEnvelope,
|
|
480
|
+
} from "./explain.ts";
|
|
245
481
|
export {
|
|
246
482
|
type ApiVerb,
|
|
247
483
|
createProtocolAdapter,
|
|
@@ -262,27 +498,45 @@ export {
|
|
|
262
498
|
type RouterOsProtocol,
|
|
263
499
|
} from "./protocols/index.ts";
|
|
264
500
|
export {
|
|
501
|
+
type AltitudeType,
|
|
265
502
|
applyCommentKv,
|
|
503
|
+
type BboxPredicate,
|
|
266
504
|
type CdbGroupExpansion,
|
|
267
505
|
type CdbGroupResolveInput,
|
|
268
506
|
type CdbGroupTarget,
|
|
269
507
|
type CdbResolution,
|
|
270
508
|
type CdbResolveInput,
|
|
509
|
+
type CommentKvGeoKey,
|
|
271
510
|
type CommentKvKey,
|
|
272
511
|
type CommentKvLayer,
|
|
273
512
|
type CommentKvOverrides,
|
|
274
513
|
type CommentKvResult,
|
|
275
514
|
type CommentKvUpdate,
|
|
276
515
|
type CommentKvWarning,
|
|
516
|
+
canonicalizeGeoKey,
|
|
277
517
|
coerceCommentKv,
|
|
278
518
|
commentKvAllowlist,
|
|
519
|
+
commentKvGeoKeys,
|
|
279
520
|
commentKvReservedKeys,
|
|
521
|
+
type DeviceLocation,
|
|
280
522
|
defaultPortForScheme,
|
|
523
|
+
deviceLocation,
|
|
281
524
|
expandCdbGroup,
|
|
525
|
+
expandSelection,
|
|
526
|
+
isDefaultRecordTarget,
|
|
527
|
+
type NearPredicate,
|
|
528
|
+
type ParsedGpsTuple,
|
|
529
|
+
parseAltitude,
|
|
530
|
+
parseAltitudeType,
|
|
531
|
+
parseBbox,
|
|
282
532
|
parseBoolean,
|
|
283
533
|
parseCommentKv,
|
|
284
534
|
parseDuration,
|
|
535
|
+
parseGpsTuple,
|
|
285
536
|
parseHostCandidate,
|
|
537
|
+
parseLatLon,
|
|
538
|
+
parseNear,
|
|
539
|
+
parseRawCommentFacts,
|
|
286
540
|
type ResolvedAuth,
|
|
287
541
|
type ResolvedSetting,
|
|
288
542
|
type ResolvedTarget,
|
|
@@ -296,7 +550,12 @@ export {
|
|
|
296
550
|
resolveOptionalIntegerSetting,
|
|
297
551
|
resolveStringSetting,
|
|
298
552
|
resolveTarget,
|
|
553
|
+
type SelectionExpansion,
|
|
554
|
+
type SelectionMember,
|
|
555
|
+
type SelectionResolveInput,
|
|
556
|
+
type SelectionWhereClause,
|
|
299
557
|
type TargetResolveInput,
|
|
558
|
+
type TargetSelection,
|
|
300
559
|
toCoreSource,
|
|
301
560
|
} from "./resolver/index.ts";
|
|
302
561
|
export {
|
|
@@ -326,11 +585,44 @@ export {
|
|
|
326
585
|
type RetrieveFanoutData,
|
|
327
586
|
type RetrieveFanoutEnvelope,
|
|
328
587
|
type RetrieveFanoutErrorEnvelope,
|
|
588
|
+
type RetrieveFanoutInternals,
|
|
329
589
|
type RetrieveFanoutOperationMeta,
|
|
330
|
-
type
|
|
590
|
+
type RetrieveFanoutOptions,
|
|
591
|
+
type RetrieveSelectionSummary,
|
|
331
592
|
renderRetrieveFanoutEnvelope,
|
|
593
|
+
retrieveFanout,
|
|
332
594
|
retrieveGroup,
|
|
333
595
|
} from "./retrieve-fanout.ts";
|
|
596
|
+
export {
|
|
597
|
+
buildSettingsErrorEnvelope,
|
|
598
|
+
renderSettingsEnvelope,
|
|
599
|
+
type SettingsCommand,
|
|
600
|
+
type SettingsDefaultDeviceSummary,
|
|
601
|
+
type SettingsEnvelope,
|
|
602
|
+
type SettingsErrorEnvelope,
|
|
603
|
+
type SettingsGetArgs,
|
|
604
|
+
type SettingsGetData,
|
|
605
|
+
type SettingsKeyDef,
|
|
606
|
+
type SettingsKeyEntry,
|
|
607
|
+
type SettingsOperationMeta,
|
|
608
|
+
type SettingsOutputFormat,
|
|
609
|
+
type SettingsPrintArgs,
|
|
610
|
+
type SettingsPrintData,
|
|
611
|
+
type SettingsResetArgs,
|
|
612
|
+
type SettingsResetData,
|
|
613
|
+
type SettingsSetArgs,
|
|
614
|
+
type SettingsSetData,
|
|
615
|
+
type SettingsSuccessEnvelope,
|
|
616
|
+
type SettingsUnrecognizedEntry,
|
|
617
|
+
type SettingsValue,
|
|
618
|
+
settingsGet,
|
|
619
|
+
settingsManagedKeys,
|
|
620
|
+
settingsOutputFormats,
|
|
621
|
+
settingsPrint,
|
|
622
|
+
settingsRefusedKeys,
|
|
623
|
+
settingsReset,
|
|
624
|
+
settingsSet,
|
|
625
|
+
} from "./settings.ts";
|
|
334
626
|
export {
|
|
335
627
|
buildSshTerminalArgv,
|
|
336
628
|
buildTerminalErrorEnvelope,
|
|
@@ -343,6 +635,7 @@ export {
|
|
|
343
635
|
export {
|
|
344
636
|
buildTransferErrorEnvelope,
|
|
345
637
|
FILE_READ_CHUNK_BYTES,
|
|
638
|
+
isTransferWriteVerb,
|
|
346
639
|
normalizeRemotePath,
|
|
347
640
|
REST_FILE_WRITE_CAP_BYTES,
|
|
348
641
|
renderTransferEnvelope,
|
|
@@ -365,6 +658,19 @@ export {
|
|
|
365
658
|
transferVerbs,
|
|
366
659
|
validateTransferRequestShape,
|
|
367
660
|
} from "./transfer.ts";
|
|
661
|
+
export {
|
|
662
|
+
buildTransferFanoutErrorEnvelope,
|
|
663
|
+
renderTransferFanoutEnvelope,
|
|
664
|
+
type TransferFanoutData,
|
|
665
|
+
type TransferFanoutEnvelope,
|
|
666
|
+
type TransferFanoutErrorEnvelope,
|
|
667
|
+
type TransferFanoutInternals,
|
|
668
|
+
type TransferFanoutOperationMeta,
|
|
669
|
+
type TransferFanoutOptions,
|
|
670
|
+
type TransferFanoutRequestSummary,
|
|
671
|
+
type TransferSelectionSummary,
|
|
672
|
+
transferFanout,
|
|
673
|
+
} from "./transfer-fanout.ts";
|
|
368
674
|
|
|
369
675
|
import { plannedProtocols, type RouterOsProtocol } from "./protocols/index.ts";
|
|
370
676
|
|
package/src/mcp/config.ts
CHANGED
|
@@ -46,16 +46,26 @@ export interface ResolveMcpConfigArgs {
|
|
|
46
46
|
cdbPassword?: string;
|
|
47
47
|
allowAdhocTargets?: boolean;
|
|
48
48
|
env?: Record<string, string | undefined>;
|
|
49
|
+
/**
|
|
50
|
+
* The `centrs.env` config tier (`src/resolver/config-file.ts`), loaded by
|
|
51
|
+
* the caller — `resolveMcpConfig` itself stays synchronous so it can keep
|
|
52
|
+
* serving as a default-parameter value (`server.ts`). `CENTRS_CDB_PASSWORD`
|
|
53
|
+
* deliberately never reads it, same as `resolveAuth`'s credential fields.
|
|
54
|
+
*/
|
|
55
|
+
config?: Record<string, string | undefined>;
|
|
49
56
|
}
|
|
50
57
|
|
|
51
58
|
export function resolveMcpConfig(
|
|
52
59
|
args: ResolveMcpConfigArgs = {},
|
|
53
60
|
): CentrsMcpConfig {
|
|
54
61
|
const env = args.env ?? Bun.env;
|
|
55
|
-
const
|
|
62
|
+
const config = args.config ?? {};
|
|
63
|
+
const explicitPath =
|
|
64
|
+
args.cdbFile ?? env[ENV_CDB_FILE] ?? config[ENV_CDB_FILE] ?? undefined;
|
|
56
65
|
const cdbFile = explicitPath ?? defaultCdbPath(env);
|
|
57
66
|
const allowAdhocTargets =
|
|
58
|
-
args.allowAdhocTargets ??
|
|
67
|
+
args.allowAdhocTargets ??
|
|
68
|
+
(env[ENV_ALLOW_ADHOC] ?? config[ENV_ALLOW_ADHOC]) === "1";
|
|
59
69
|
return {
|
|
60
70
|
cdbFile,
|
|
61
71
|
cdbFileExplicit: explicitPath !== undefined,
|
package/src/mcp/tools.ts
CHANGED
|
@@ -33,6 +33,8 @@ import {
|
|
|
33
33
|
isWriteShaped,
|
|
34
34
|
validateExecuteEnvelope,
|
|
35
35
|
} from "../execute.ts";
|
|
36
|
+
import type { CommentKvUpdate } from "../resolver/comment-kv.ts";
|
|
37
|
+
import { parseBbox, parseNear } from "../resolver/geo.ts";
|
|
36
38
|
import { parseDuration } from "../resolver/settings.ts";
|
|
37
39
|
import { buildRetrieveErrorEnvelope, retrieve } from "../retrieve.ts";
|
|
38
40
|
import {
|
|
@@ -416,6 +418,24 @@ export const devicesInputShape = {
|
|
|
416
418
|
.describe(
|
|
417
419
|
"Group filter for op=list; first-class group field for op=add/set.",
|
|
418
420
|
),
|
|
421
|
+
where: z
|
|
422
|
+
.array(z.string())
|
|
423
|
+
.optional()
|
|
424
|
+
.describe(
|
|
425
|
+
"op=list device-class filters `attr=value` (repeatable, AND-combined; e.g. board=RB5009 or lat=37.7749).",
|
|
426
|
+
),
|
|
427
|
+
near: z
|
|
428
|
+
.string()
|
|
429
|
+
.optional()
|
|
430
|
+
.describe(
|
|
431
|
+
"op=list geo filter `<lat>,<lon>,<radius>` (lat-first; radius m/km/mi/ft, bare = km).",
|
|
432
|
+
),
|
|
433
|
+
bbox: z
|
|
434
|
+
.string()
|
|
435
|
+
.optional()
|
|
436
|
+
.describe(
|
|
437
|
+
"op=list geo filter `<south>,<west>,<north>,<east>` (lat-first bounding box).",
|
|
438
|
+
),
|
|
419
439
|
user: z.string().optional().describe("CDB username for op=add/set."),
|
|
420
440
|
password: z
|
|
421
441
|
.string()
|
|
@@ -454,6 +474,30 @@ export const devicesInputShape = {
|
|
|
454
474
|
.boolean()
|
|
455
475
|
.optional()
|
|
456
476
|
.describe("For op=set, reject comment keys outside the allowlist."),
|
|
477
|
+
lat: z
|
|
478
|
+
.number()
|
|
479
|
+
.optional()
|
|
480
|
+
.describe(
|
|
481
|
+
"Latitude in decimal degrees (-90..90) for op=add/set; a comment-kv fact, paired with lon (issue #146).",
|
|
482
|
+
),
|
|
483
|
+
lon: z
|
|
484
|
+
.number()
|
|
485
|
+
.optional()
|
|
486
|
+
.describe(
|
|
487
|
+
"Longitude in decimal degrees (-180..180) for op=add/set; a comment-kv fact, paired with lat.",
|
|
488
|
+
),
|
|
489
|
+
altitude: z
|
|
490
|
+
.number()
|
|
491
|
+
.optional()
|
|
492
|
+
.describe(
|
|
493
|
+
"Altitude in meters for op=add/set (may be negative); a comment-kv fact.",
|
|
494
|
+
),
|
|
495
|
+
altitudeType: z
|
|
496
|
+
.enum(["MSL", "AGL"])
|
|
497
|
+
.optional()
|
|
498
|
+
.describe(
|
|
499
|
+
"Vertical datum for altitude, op=add/set (default MSL when altitude is set).",
|
|
500
|
+
),
|
|
457
501
|
confirm: z
|
|
458
502
|
.boolean()
|
|
459
503
|
.optional()
|
|
@@ -478,6 +522,56 @@ function requireDevicesTarget(
|
|
|
478
522
|
});
|
|
479
523
|
}
|
|
480
524
|
|
|
525
|
+
/**
|
|
526
|
+
* Lower the typed `lat`/`lon`/`altitude`/`altitudeType` MCP args into comment-kv
|
|
527
|
+
* updates — the same core surface the CLI's `--lat`/`--lon`/`--gps` flags lower
|
|
528
|
+
* into (`src/cli/devices.ts`). Light touch: no alias handling here (the MCP
|
|
529
|
+
* schema only exposes the canonical field names), range/enum/pairing
|
|
530
|
+
* validation happens once in `validateCommentKvUpdates` (`src/devices.ts`).
|
|
531
|
+
*/
|
|
532
|
+
function buildGeoUpdates(args: DevicesArgs): CommentKvUpdate[] {
|
|
533
|
+
const updates: CommentKvUpdate[] = [];
|
|
534
|
+
if (args.lat !== undefined) {
|
|
535
|
+
updates.push({ key: "lat", value: String(args.lat) });
|
|
536
|
+
}
|
|
537
|
+
if (args.lon !== undefined) {
|
|
538
|
+
updates.push({ key: "lon", value: String(args.lon) });
|
|
539
|
+
}
|
|
540
|
+
if (args.altitude !== undefined) {
|
|
541
|
+
updates.push({ key: "altitude", value: String(args.altitude) });
|
|
542
|
+
}
|
|
543
|
+
if (args.altitudeType !== undefined) {
|
|
544
|
+
updates.push({ key: "altitude-type", value: args.altitudeType });
|
|
545
|
+
}
|
|
546
|
+
return updates;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Parse the MCP `where` array (`["attr=value", …]`) into device-class clauses
|
|
551
|
+
* for op=list. Geo-alias canonicalization happens centrally in `matchesWhere`
|
|
552
|
+
* (`src/resolver/facts.ts`), so this only splits on the first `=`.
|
|
553
|
+
*/
|
|
554
|
+
function parseMcpWhereClauses(
|
|
555
|
+
where: readonly string[] | undefined,
|
|
556
|
+
): { key: string; value: string }[] | undefined {
|
|
557
|
+
if (where === undefined) {
|
|
558
|
+
return undefined;
|
|
559
|
+
}
|
|
560
|
+
return where.map((clause) => {
|
|
561
|
+
const eq = clause.indexOf("=");
|
|
562
|
+
if (eq <= 0) {
|
|
563
|
+
throw new CentrsError({
|
|
564
|
+
code: "input/invalid-command",
|
|
565
|
+
summary: `where clause must be \`attr=value\`; received: ${clause}`,
|
|
566
|
+
remediation:
|
|
567
|
+
"Pass device-class filters like `board=RB5009` or `lat=37.7749`.",
|
|
568
|
+
context: { where: clause },
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
return { key: clause.slice(0, eq), value: clause.slice(eq + 1) };
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
|
|
481
575
|
function resolveRecordType(recordType: string | undefined): number | undefined {
|
|
482
576
|
if (recordType === undefined) {
|
|
483
577
|
return undefined;
|
|
@@ -502,9 +596,49 @@ export async function handleDevices(
|
|
|
502
596
|
): Promise<McpEnvelope> {
|
|
503
597
|
try {
|
|
504
598
|
const cdb = await loadAllowlistCdb(config);
|
|
599
|
+
// GPS *setter* fields write via add/set only; the *query* selectors
|
|
600
|
+
// (where/near/bbox) select via list only. Reject the wrong-op combination
|
|
601
|
+
// instead of silently dropping the caller's input (mirrors the CLI's
|
|
602
|
+
// per-subcommand flag guard in src/cli/devices.ts).
|
|
603
|
+
if (
|
|
604
|
+
args.op !== "add" &&
|
|
605
|
+
args.op !== "set" &&
|
|
606
|
+
(args.lat !== undefined ||
|
|
607
|
+
args.lon !== undefined ||
|
|
608
|
+
args.altitude !== undefined ||
|
|
609
|
+
args.altitudeType !== undefined)
|
|
610
|
+
) {
|
|
611
|
+
throw new CentrsError({
|
|
612
|
+
code: "input/invalid-command",
|
|
613
|
+
summary: `GPS fields (lat/lon/altitude/altitudeType) are not valid for op="${args.op}".`,
|
|
614
|
+
remediation:
|
|
615
|
+
"Store GPS with op=add or op=set; drop the GPS fields for list/show/groups/edit/remove.",
|
|
616
|
+
context: { op: args.op },
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
if (
|
|
620
|
+
args.op !== "list" &&
|
|
621
|
+
(args.where !== undefined ||
|
|
622
|
+
args.near !== undefined ||
|
|
623
|
+
args.bbox !== undefined)
|
|
624
|
+
) {
|
|
625
|
+
throw new CentrsError({
|
|
626
|
+
code: "input/invalid-command",
|
|
627
|
+
summary: `Query selectors (where/near/bbox) are only valid for op="list", not op="${args.op}".`,
|
|
628
|
+
remediation:
|
|
629
|
+
"Use op=list with where/near/bbox to query the registry; for op=show name a target directly.",
|
|
630
|
+
context: { op: args.op },
|
|
631
|
+
});
|
|
632
|
+
}
|
|
505
633
|
switch (args.op) {
|
|
506
634
|
case "list":
|
|
507
|
-
return listDevices({
|
|
635
|
+
return listDevices({
|
|
636
|
+
cdb,
|
|
637
|
+
group: args.group,
|
|
638
|
+
where: parseMcpWhereClauses(args.where),
|
|
639
|
+
near: args.near !== undefined ? parseNear(args.near) : undefined,
|
|
640
|
+
bbox: args.bbox !== undefined ? parseBbox(args.bbox) : undefined,
|
|
641
|
+
});
|
|
508
642
|
case "groups":
|
|
509
643
|
return listGroups({ cdb, withMembers: true });
|
|
510
644
|
case "show": {
|
|
@@ -527,6 +661,7 @@ export async function handleDevices(
|
|
|
527
661
|
profile: args.profile,
|
|
528
662
|
session: args.session,
|
|
529
663
|
comment: args.comment,
|
|
664
|
+
commentKvUpdates: buildGeoUpdates(args),
|
|
530
665
|
savedPassword: args.savedPassword,
|
|
531
666
|
force: args.force,
|
|
532
667
|
}),
|
|
@@ -542,7 +677,7 @@ export async function handleDevices(
|
|
|
542
677
|
await setDevice({
|
|
543
678
|
cdb,
|
|
544
679
|
target,
|
|
545
|
-
updates: args.updates,
|
|
680
|
+
updates: [...buildGeoUpdates(args), ...(args.updates ?? [])],
|
|
546
681
|
user: args.user,
|
|
547
682
|
password: args.password,
|
|
548
683
|
group: args.group,
|