@tikoci/centrs 0.1.2 → 0.1.3
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 +59 -0
- package/GLOSSARY.txt +71 -0
- package/README.md +24 -8
- package/SECURITY.md +3 -3
- package/commands/api/README.md +27 -9
- package/commands/api/examples.md +109 -6
- package/commands/check/README.md +371 -53
- package/commands/check/examples.md +390 -0
- package/commands/devices/README.md +177 -37
- package/commands/devices/examples.md +148 -0
- package/commands/execute/README.md +39 -4
- package/commands/execute/examples.md +90 -6
- package/commands/retrieve/README.md +36 -50
- package/commands/retrieve/examples.md +40 -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 +32 -2
- package/commands/transfer/examples.md +66 -0
- package/docs/CONSTITUTION.md +36 -11
- package/docs/MATRIX.md +68 -172
- package/docs/errors/README.md +2 -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/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/usage/fanout-not-supported.md +16 -0
- package/package.json +6 -6
- package/src/api-fanout.ts +454 -0
- package/src/api.ts +91 -19
- package/src/cli/api.ts +135 -11
- package/src/cli/btest.ts +20 -2
- 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 +107 -6
- package/src/cli/mcp.ts +8 -1
- package/src/cli/retrieve.ts +135 -90
- package/src/cli/selection.ts +200 -0
- package/src/cli/settings.ts +286 -0
- package/src/cli/terminal.ts +22 -7
- package/src/cli/transfer.ts +171 -47
- package/src/cli.ts +7 -0
- package/src/core/error-catalog.ts +55 -0
- package/src/core/fanout.ts +143 -2
- package/src/devices.ts +212 -20
- package/src/discover.ts +7 -2
- package/src/execute-fanout.ts +438 -0
- package/src/execute.ts +120 -23
- package/src/index.ts +105 -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/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 +46 -0
- package/src/resolver/mac.ts +12 -3
- package/src/resolver/selection.ts +304 -0
- package/src/resolver/settings.ts +54 -5
- package/src/resolver/target.ts +20 -2
- package/src/retrieve-fanout.ts +225 -133
- package/src/retrieve.ts +39 -7
- package/src/settings.ts +1078 -0
- package/src/terminal.ts +11 -1
- package/src/transfer-fanout.ts +527 -0
- package/src/transfer.ts +61 -11
package/src/transfer.ts
CHANGED
|
@@ -39,6 +39,7 @@ import type { RouterOsProtocol } from "./protocols/index.ts";
|
|
|
39
39
|
import { SftpClient } from "./protocols/sftp.ts";
|
|
40
40
|
import {
|
|
41
41
|
type CdbResolution,
|
|
42
|
+
loadEnvFileDefaults,
|
|
42
43
|
parseDuration,
|
|
43
44
|
type ResolvedAuth,
|
|
44
45
|
type ResolvedSetting,
|
|
@@ -66,6 +67,20 @@ export const transferVerbs = [
|
|
|
66
67
|
] as const;
|
|
67
68
|
export type TransferVerb = (typeof transferVerbs)[number];
|
|
68
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Verbs that mutate the device (write path) — gated by `--yes` once up front in a
|
|
72
|
+
* fan-out. `download`/`list` only read the device (a download writes the *local*
|
|
73
|
+
* filesystem, not the router).
|
|
74
|
+
*/
|
|
75
|
+
export function isTransferWriteVerb(verb: TransferVerb): boolean {
|
|
76
|
+
return (
|
|
77
|
+
verb === "upload" ||
|
|
78
|
+
verb === "remove" ||
|
|
79
|
+
verb === "mkdir" ||
|
|
80
|
+
verb === "copy"
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
69
84
|
/**
|
|
70
85
|
* `--via` method names. These are transfer *methods*, finer than the grid
|
|
71
86
|
* transport: `rest`/`native` ride rest-api/native-api; `sftp`/`scp` ride ssh;
|
|
@@ -120,6 +135,14 @@ export interface TransferRequest {
|
|
|
120
135
|
name?: string;
|
|
121
136
|
cdbFile?: string;
|
|
122
137
|
cdbPassword?: string;
|
|
138
|
+
/** `download` fan-out: directory to write one file per target into. */
|
|
139
|
+
outDir?: string;
|
|
140
|
+
/** Fan-out write gate: confirm a mutating fan-out (upload/remove/mkdir/copy). */
|
|
141
|
+
yes?: boolean;
|
|
142
|
+
/** Fan-out TTY detection seam (defaults to `process.stdin.isTTY`). */
|
|
143
|
+
stdinIsTty?: boolean;
|
|
144
|
+
/** Fan-out confirmation prompt seam (defaults to the shared TTY prompt). */
|
|
145
|
+
confirm?: (prompt: string) => Promise<boolean>;
|
|
123
146
|
}
|
|
124
147
|
|
|
125
148
|
export type TransferOp = TransferVerb;
|
|
@@ -190,8 +213,9 @@ interface ResolvedTransferRequest {
|
|
|
190
213
|
export async function transfer(
|
|
191
214
|
request: TransferRequest,
|
|
192
215
|
env: Record<string, string | undefined> = Bun.env,
|
|
216
|
+
options: { cdbResolution?: CdbResolution } = {},
|
|
193
217
|
): Promise<TransferSuccessEnvelope> {
|
|
194
|
-
const resolved = await resolveTransferRequest(request, env);
|
|
218
|
+
const resolved = await resolveTransferRequest(request, env, options);
|
|
195
219
|
const backend = createFileBackend(resolved);
|
|
196
220
|
try {
|
|
197
221
|
return await runResolvedTransfer(resolved, backend);
|
|
@@ -778,8 +802,10 @@ function verifyReadSize(
|
|
|
778
802
|
export async function resolveTransferRequest(
|
|
779
803
|
request: TransferRequest,
|
|
780
804
|
env: Record<string, string | undefined>,
|
|
805
|
+
options: { cdbResolution?: CdbResolution } = {},
|
|
781
806
|
): Promise<ResolvedTransferRequest> {
|
|
782
807
|
validateTransferRequestShape(request);
|
|
808
|
+
const config = await loadEnvFileDefaults(env);
|
|
783
809
|
|
|
784
810
|
const direction: TransferDirection =
|
|
785
811
|
request.verb === "upload" ? "upload" : "download";
|
|
@@ -789,18 +815,24 @@ export async function resolveTransferRequest(
|
|
|
789
815
|
direction,
|
|
790
816
|
sizeHint,
|
|
791
817
|
env,
|
|
818
|
+
config,
|
|
792
819
|
);
|
|
793
820
|
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
821
|
+
// Fan-out passes the pre-resolved CDB record for a member (the CDB is loaded
|
|
822
|
+
// once in `expandCdbSelection`); single-target resolves it here.
|
|
823
|
+
const cdbResolution =
|
|
824
|
+
options.cdbResolution ??
|
|
825
|
+
(await resolveCdb(
|
|
826
|
+
{
|
|
827
|
+
targetInput: request.targetInput,
|
|
828
|
+
cdbFile: request.cdbFile,
|
|
829
|
+
cdbPassword: request.cdbPassword,
|
|
830
|
+
},
|
|
831
|
+
env,
|
|
832
|
+
config,
|
|
833
|
+
));
|
|
802
834
|
|
|
803
|
-
const format = resolveTransferFormat(request, env);
|
|
835
|
+
const format = resolveTransferFormat(request, env, config);
|
|
804
836
|
const validate = resolveBooleanSetting(
|
|
805
837
|
request.validate,
|
|
806
838
|
env,
|
|
@@ -808,6 +840,7 @@ export async function resolveTransferRequest(
|
|
|
808
840
|
true,
|
|
809
841
|
"validate",
|
|
810
842
|
cdbResolution?.overrides.validate,
|
|
843
|
+
config,
|
|
811
844
|
);
|
|
812
845
|
const insecure = resolveBooleanSetting(
|
|
813
846
|
request.insecure,
|
|
@@ -816,12 +849,14 @@ export async function resolveTransferRequest(
|
|
|
816
849
|
false,
|
|
817
850
|
"insecure",
|
|
818
851
|
cdbResolution?.overrides.insecure,
|
|
852
|
+
config,
|
|
819
853
|
);
|
|
820
854
|
const timeoutMs = resolveTransferTimeout(
|
|
821
855
|
request.timeout,
|
|
822
856
|
env,
|
|
823
857
|
protocol,
|
|
824
858
|
cdbResolution,
|
|
859
|
+
config,
|
|
825
860
|
);
|
|
826
861
|
const target = resolveTarget(
|
|
827
862
|
{
|
|
@@ -832,6 +867,7 @@ export async function resolveTransferRequest(
|
|
|
832
867
|
env,
|
|
833
868
|
protocol,
|
|
834
869
|
cdbResolution,
|
|
870
|
+
config,
|
|
835
871
|
);
|
|
836
872
|
const auth = resolveAuth(
|
|
837
873
|
{
|
|
@@ -841,6 +877,7 @@ export async function resolveTransferRequest(
|
|
|
841
877
|
},
|
|
842
878
|
env,
|
|
843
879
|
cdbResolution,
|
|
880
|
+
config,
|
|
844
881
|
);
|
|
845
882
|
|
|
846
883
|
const warnings: Warning[] = [
|
|
@@ -900,6 +937,7 @@ export function selectTransferMethod(
|
|
|
900
937
|
direction: TransferDirection,
|
|
901
938
|
uploadBytes: number | undefined,
|
|
902
939
|
env: Record<string, string | undefined>,
|
|
940
|
+
config: Record<string, string | undefined> = {},
|
|
903
941
|
): {
|
|
904
942
|
method: TransferMethod;
|
|
905
943
|
protocol: RouterOsProtocol;
|
|
@@ -911,6 +949,9 @@ export function selectTransferMethod(
|
|
|
911
949
|
"CENTRS_TRANSFER_VIA",
|
|
912
950
|
"auto",
|
|
913
951
|
"via",
|
|
952
|
+
undefined,
|
|
953
|
+
undefined,
|
|
954
|
+
config,
|
|
914
955
|
) as ResolvedSetting<string>;
|
|
915
956
|
const requested = via.value;
|
|
916
957
|
|
|
@@ -1062,6 +1103,7 @@ function parseVerifyMode(
|
|
|
1062
1103
|
function resolveTransferFormat(
|
|
1063
1104
|
request: TransferRequest,
|
|
1064
1105
|
env: Record<string, string | undefined>,
|
|
1106
|
+
config: Record<string, string | undefined> = {},
|
|
1065
1107
|
): ResolvedSetting<TransferOutputFormat> {
|
|
1066
1108
|
return resolveStringSetting(
|
|
1067
1109
|
request.format,
|
|
@@ -1079,6 +1121,8 @@ function resolveTransferFormat(
|
|
|
1079
1121
|
remediation: `Choose one of ${transferOutputFormats.join(", ")}.`,
|
|
1080
1122
|
});
|
|
1081
1123
|
},
|
|
1124
|
+
undefined,
|
|
1125
|
+
config,
|
|
1082
1126
|
) as ResolvedSetting<TransferOutputFormat>;
|
|
1083
1127
|
}
|
|
1084
1128
|
|
|
@@ -1087,6 +1131,7 @@ function resolveTransferTimeout(
|
|
|
1087
1131
|
env: Record<string, string | undefined>,
|
|
1088
1132
|
protocol: RouterOsProtocol,
|
|
1089
1133
|
cdb?: CdbResolution,
|
|
1134
|
+
config: Record<string, string | undefined> = {},
|
|
1090
1135
|
): ResolvedSetting<number> {
|
|
1091
1136
|
const resolved = resolveStringSetting(
|
|
1092
1137
|
timeout === undefined ? undefined : String(timeout),
|
|
@@ -1106,6 +1151,7 @@ function resolveTransferTimeout(
|
|
|
1106
1151
|
return parsed;
|
|
1107
1152
|
},
|
|
1108
1153
|
cdb?.overrides.timeoutMs,
|
|
1154
|
+
config,
|
|
1109
1155
|
) as ResolvedSetting<number>;
|
|
1110
1156
|
|
|
1111
1157
|
if (protocol === "rest-api" && resolved.value > 60_000) {
|
|
@@ -1156,7 +1202,11 @@ function writeLocalSink(
|
|
|
1156
1202
|
process.stdout.write(bytes);
|
|
1157
1203
|
return;
|
|
1158
1204
|
}
|
|
1159
|
-
|
|
1205
|
+
// Downloaded RouterOS artifacts (backups/exports) can carry credentials,
|
|
1206
|
+
// so a newly created destination file gets owner-only permissions
|
|
1207
|
+
// instead of the process umask default. Mode only applies on creation —
|
|
1208
|
+
// an existing destination keeps its current permissions.
|
|
1209
|
+
writeFileSync(local, bytes, { mode: 0o600 });
|
|
1160
1210
|
}
|
|
1161
1211
|
|
|
1162
1212
|
function localLabel(resolved: ResolvedTransferRequest): string {
|