apcore-cli 0.7.0 → 0.8.0
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 +123 -0
- package/README.md +37 -27
- package/dist/bin/apcore-cli.js +462 -178
- package/dist/bin/apcore-cli.js.map +1 -1
- package/dist/index.d.ts +128 -22
- package/dist/index.js +432 -152
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -220,8 +220,8 @@ var init_audit = __esm({
|
|
|
220
220
|
);
|
|
221
221
|
logPath;
|
|
222
222
|
writeFailureWarned = false;
|
|
223
|
-
constructor(
|
|
224
|
-
this.logPath =
|
|
223
|
+
constructor(path6) {
|
|
224
|
+
this.logPath = path6 ?? _AuditLogger.DEFAULT_PATH;
|
|
225
225
|
this.ensureDirectory();
|
|
226
226
|
}
|
|
227
227
|
ensureDirectory() {
|
|
@@ -267,7 +267,7 @@ var init_audit = __esm({
|
|
|
267
267
|
try {
|
|
268
268
|
return os.userInfo().username;
|
|
269
269
|
} catch {
|
|
270
|
-
return process.env.USER ?? process.env.USERNAME ?? "unknown";
|
|
270
|
+
return process.env.USER ?? process.env.LOGNAME ?? process.env.USERNAME ?? "unknown";
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
};
|
|
@@ -276,7 +276,7 @@ var init_audit = __esm({
|
|
|
276
276
|
|
|
277
277
|
// src/security/config-encryptor.ts
|
|
278
278
|
import * as crypto2 from "crypto";
|
|
279
|
-
import * as
|
|
279
|
+
import * as os3 from "os";
|
|
280
280
|
async function getKeytar() {
|
|
281
281
|
if (keytarModule) return keytarModule;
|
|
282
282
|
try {
|
|
@@ -405,7 +405,7 @@ var init_config_encryptor = __esm({
|
|
|
405
405
|
);
|
|
406
406
|
_ConfigEncryptor.weakFallbackWarned = true;
|
|
407
407
|
}
|
|
408
|
-
const hostname2 =
|
|
408
|
+
const hostname2 = os3.hostname();
|
|
409
409
|
const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
|
|
410
410
|
const material = `${hostname2}:${username}`;
|
|
411
411
|
return crypto2.pbkdf2Sync(material, salt, PBKDF2_ITERATIONS, 32, "sha256");
|
|
@@ -437,7 +437,7 @@ var init_config_encryptor = __esm({
|
|
|
437
437
|
const nonce = data.subarray(0, 12);
|
|
438
438
|
const tag = data.subarray(12, 28);
|
|
439
439
|
const ct = data.subarray(28);
|
|
440
|
-
const hostname2 =
|
|
440
|
+
const hostname2 = os3.hostname();
|
|
441
441
|
const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
|
|
442
442
|
const passphrase = process.env.APCORE_CLI_CONFIG_PASSPHRASE;
|
|
443
443
|
const materials = passphrase ? [passphrase, `${hostname2}:${username}`] : [`${hostname2}:${username}`];
|
|
@@ -557,7 +557,7 @@ function buildSandboxEnv(tmpDir) {
|
|
|
557
557
|
env.TMPDIR = tmpDir;
|
|
558
558
|
return env;
|
|
559
559
|
}
|
|
560
|
-
var SANDBOX_ALLOW_KEYS, SANDBOX_ALLOW_PREFIX, SANDBOX_DENY_PREFIX, SANDBOX_DENY_KEYS,
|
|
560
|
+
var SANDBOX_ALLOW_KEYS, SANDBOX_ALLOW_PREFIX, SANDBOX_DENY_PREFIX, SANDBOX_DENY_KEYS, SANDBOX_DEFAULT_OUTPUT_SIZE_LIMIT, Sandbox;
|
|
561
561
|
var init_sandbox = __esm({
|
|
562
562
|
"src/security/sandbox.ts"() {
|
|
563
563
|
"use strict";
|
|
@@ -567,14 +567,41 @@ var init_sandbox = __esm({
|
|
|
567
567
|
SANDBOX_ALLOW_PREFIX = "APCORE_";
|
|
568
568
|
SANDBOX_DENY_PREFIX = "APCORE_AUTH_";
|
|
569
569
|
SANDBOX_DENY_KEYS = ["APCORE_AUTH_API_KEY"];
|
|
570
|
-
|
|
570
|
+
SANDBOX_DEFAULT_OUTPUT_SIZE_LIMIT = 64 * 1024 * 1024;
|
|
571
571
|
Sandbox = class {
|
|
572
|
+
/** Default post-capture stdout+stderr byte budget for sandboxed children. */
|
|
573
|
+
static DEFAULT_MAX_OUTPUT_BYTES = SANDBOX_DEFAULT_OUTPUT_SIZE_LIMIT;
|
|
572
574
|
enabled;
|
|
573
575
|
timeoutSeconds;
|
|
576
|
+
extensionsRoot = null;
|
|
577
|
+
maxOutputBytes = SANDBOX_DEFAULT_OUTPUT_SIZE_LIMIT;
|
|
574
578
|
constructor(enabled = false, timeoutSeconds = 300) {
|
|
575
579
|
this.enabled = enabled;
|
|
576
580
|
this.timeoutSeconds = timeoutSeconds;
|
|
577
581
|
}
|
|
582
|
+
/**
|
|
583
|
+
* Set the extensions root that is forwarded to the sandboxed runner via
|
|
584
|
+
* `APCORE_EXTENSIONS_ROOT`. The path is resolved to absolute when injected
|
|
585
|
+
* so the child (whose cwd is the fresh sandbox tempdir) can locate modules.
|
|
586
|
+
*
|
|
587
|
+
* Builder-style — returns `this` so call sites can chain. Mirrors Python's
|
|
588
|
+
* `Sandbox.with_extensions_root` (D1-004 cross-SDK parity).
|
|
589
|
+
*/
|
|
590
|
+
withExtensionsRoot(extensionsRoot) {
|
|
591
|
+
this.extensionsRoot = extensionsRoot;
|
|
592
|
+
return this;
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Cap the post-capture stdout+stderr byte budget for the sandboxed
|
|
596
|
+
* subprocess. Default: 64 MiB (`Sandbox.DEFAULT_MAX_OUTPUT_BYTES`).
|
|
597
|
+
*
|
|
598
|
+
* Builder-style — returns `this`. Mirrors Python's
|
|
599
|
+
* `Sandbox.with_max_output_bytes` (D1-004 cross-SDK parity).
|
|
600
|
+
*/
|
|
601
|
+
withMaxOutputBytes(maxOutputBytes) {
|
|
602
|
+
this.maxOutputBytes = maxOutputBytes;
|
|
603
|
+
return this;
|
|
604
|
+
}
|
|
578
605
|
/**
|
|
579
606
|
* Execute a module, optionally inside a sandboxed subprocess.
|
|
580
607
|
*/
|
|
@@ -587,10 +614,16 @@ var init_sandbox = __esm({
|
|
|
587
614
|
async _sandboxedExecute(moduleId, inputData) {
|
|
588
615
|
const { spawn } = await import("child_process");
|
|
589
616
|
const { tmpdir } = await import("os");
|
|
590
|
-
const { join:
|
|
617
|
+
const { join: join4 } = await import("path");
|
|
591
618
|
const { mkdtempSync, rmSync } = await import("fs");
|
|
592
|
-
const tmpDir = mkdtempSync(
|
|
619
|
+
const tmpDir = mkdtempSync(join4(tmpdir(), "apcore_sandbox_"));
|
|
593
620
|
const env = buildSandboxEnv(tmpDir);
|
|
621
|
+
const { resolve: resolvePath } = await import("path");
|
|
622
|
+
if (this.extensionsRoot !== null) {
|
|
623
|
+
env.APCORE_EXTENSIONS_ROOT = resolvePath(this.extensionsRoot);
|
|
624
|
+
} else if (env.APCORE_EXTENSIONS_ROOT) {
|
|
625
|
+
env.APCORE_EXTENSIONS_ROOT = resolvePath(env.APCORE_EXTENSIONS_ROOT);
|
|
626
|
+
}
|
|
594
627
|
const binaryPath = process.argv[1];
|
|
595
628
|
const child = spawn(process.execPath, [binaryPath, "--internal-sandbox-runner", moduleId], {
|
|
596
629
|
env,
|
|
@@ -599,11 +632,14 @@ var init_sandbox = __esm({
|
|
|
599
632
|
});
|
|
600
633
|
let stdout = "";
|
|
601
634
|
let stderr = "";
|
|
602
|
-
let
|
|
635
|
+
let stdoutBytes = 0;
|
|
636
|
+
let stderrBytes = 0;
|
|
603
637
|
let sizeExceeded = false;
|
|
638
|
+
const outputCap = this.maxOutputBytes;
|
|
604
639
|
child.stdout.on("data", (chunk) => {
|
|
605
|
-
|
|
606
|
-
|
|
640
|
+
if (sizeExceeded) return;
|
|
641
|
+
stdoutBytes += chunk.length;
|
|
642
|
+
if (stdoutBytes > outputCap) {
|
|
607
643
|
sizeExceeded = true;
|
|
608
644
|
child.kill("SIGKILL");
|
|
609
645
|
return;
|
|
@@ -611,6 +647,13 @@ var init_sandbox = __esm({
|
|
|
611
647
|
stdout += chunk.toString();
|
|
612
648
|
});
|
|
613
649
|
child.stderr.on("data", (chunk) => {
|
|
650
|
+
if (sizeExceeded) return;
|
|
651
|
+
stderrBytes += chunk.length;
|
|
652
|
+
if (stderrBytes > outputCap) {
|
|
653
|
+
sizeExceeded = true;
|
|
654
|
+
child.kill("SIGKILL");
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
614
657
|
stderr += chunk.toString();
|
|
615
658
|
});
|
|
616
659
|
child.stdin.write(JSON.stringify(inputData));
|
|
@@ -631,7 +674,10 @@ var init_sandbox = __esm({
|
|
|
631
674
|
} catch {
|
|
632
675
|
}
|
|
633
676
|
if (sizeExceeded) {
|
|
634
|
-
|
|
677
|
+
const limitMiB = Math.floor(outputCap / (1024 * 1024));
|
|
678
|
+
reject(new ModuleExecutionError(
|
|
679
|
+
`Sandbox module '${moduleId}' output exceeded ${limitMiB}MiB limit.`
|
|
680
|
+
));
|
|
635
681
|
return;
|
|
636
682
|
}
|
|
637
683
|
if (code !== 0) {
|
|
@@ -685,9 +731,9 @@ init_esm_shims();
|
|
|
685
731
|
// src/main.ts
|
|
686
732
|
init_esm_shims();
|
|
687
733
|
init_errors();
|
|
688
|
-
import { readFileSync as
|
|
734
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
689
735
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
690
|
-
import * as
|
|
736
|
+
import * as path5 from "path";
|
|
691
737
|
import { Command as Command5, CommanderError, Option as Option4 } from "commander";
|
|
692
738
|
|
|
693
739
|
// src/ref-resolver.ts
|
|
@@ -786,6 +832,10 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
786
832
|
properties: {},
|
|
787
833
|
required: []
|
|
788
834
|
};
|
|
835
|
+
if (typeof obj.properties === "object" && obj.properties !== null) {
|
|
836
|
+
Object.assign(merged.properties, obj.properties);
|
|
837
|
+
}
|
|
838
|
+
const siblingRequired = Array.isArray(obj.required) ? obj.required.slice() : [];
|
|
789
839
|
const allRequiredSets = [];
|
|
790
840
|
for (const subSchema of obj[keyword]) {
|
|
791
841
|
const resolved = resolveNode(
|
|
@@ -806,6 +856,7 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
806
856
|
allRequiredSets.push(new Set(resolved.required));
|
|
807
857
|
}
|
|
808
858
|
}
|
|
859
|
+
let branchRequired = [];
|
|
809
860
|
if (allRequiredSets.length > 0) {
|
|
810
861
|
let intersection = allRequiredSets[0];
|
|
811
862
|
for (let i = 1; i < allRequiredSets.length; i++) {
|
|
@@ -813,10 +864,17 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
813
864
|
[...intersection].filter((x) => allRequiredSets[i].has(x))
|
|
814
865
|
);
|
|
815
866
|
}
|
|
816
|
-
|
|
817
|
-
} else {
|
|
818
|
-
merged.required = [];
|
|
867
|
+
branchRequired = [...intersection];
|
|
819
868
|
}
|
|
869
|
+
const seen = /* @__PURE__ */ new Set();
|
|
870
|
+
const combinedRequired = [];
|
|
871
|
+
for (const r of [...siblingRequired, ...branchRequired]) {
|
|
872
|
+
if (!seen.has(r)) {
|
|
873
|
+
seen.add(r);
|
|
874
|
+
combinedRequired.push(r);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
merged.required = combinedRequired;
|
|
820
878
|
for (const [k, v] of Object.entries(obj)) {
|
|
821
879
|
if (k !== keyword && !(k in merged)) {
|
|
822
880
|
merged[k] = v;
|
|
@@ -832,7 +890,7 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
832
890
|
propSchema,
|
|
833
891
|
defs,
|
|
834
892
|
visited,
|
|
835
|
-
depth
|
|
893
|
+
depth,
|
|
836
894
|
maxDepth,
|
|
837
895
|
moduleId
|
|
838
896
|
);
|
|
@@ -844,6 +902,7 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
844
902
|
// src/schema-parser.ts
|
|
845
903
|
init_esm_shims();
|
|
846
904
|
init_errors();
|
|
905
|
+
init_logger();
|
|
847
906
|
var BOOLEAN_FLAG = /* @__PURE__ */ Symbol("BOOLEAN_FLAG");
|
|
848
907
|
function mapType(propName, propSchema) {
|
|
849
908
|
const schemaType = propSchema.type;
|
|
@@ -896,6 +955,13 @@ function schemaToCliOptions(schema, maxHelpLength = 1e3) {
|
|
|
896
955
|
const requiredList = schema.required ?? [];
|
|
897
956
|
const options = [];
|
|
898
957
|
const flagNames = {};
|
|
958
|
+
for (const reqName of requiredList) {
|
|
959
|
+
if (!(reqName in properties)) {
|
|
960
|
+
warn(
|
|
961
|
+
`Required property '${reqName}' not found in properties, skipping.`
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
899
965
|
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
900
966
|
const flagName = "--" + propName.replace(/_/g, "-");
|
|
901
967
|
if (RESERVED_NAMES.has(propName)) {
|
|
@@ -903,14 +969,14 @@ function schemaToCliOptions(schema, maxHelpLength = 1e3) {
|
|
|
903
969
|
`Error: Module schema property '${propName}' conflicts with a reserved CLI option name. Rename the property.
|
|
904
970
|
`
|
|
905
971
|
);
|
|
906
|
-
process.exit(EXIT_CODES.
|
|
972
|
+
process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
|
|
907
973
|
}
|
|
908
974
|
if (flagName in flagNames) {
|
|
909
975
|
process.stderr.write(
|
|
910
976
|
`Error: Flag name collision: properties '${propName}' and '${flagNames[flagName]}' both map to '${flagName}'.
|
|
911
977
|
`
|
|
912
978
|
);
|
|
913
|
-
process.exit(EXIT_CODES.
|
|
979
|
+
process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
|
|
914
980
|
}
|
|
915
981
|
flagNames[flagName] = propName;
|
|
916
982
|
const typeResult = mapType(propName, propSchema);
|
|
@@ -926,7 +992,7 @@ function schemaToCliOptions(schema, maxHelpLength = 1e3) {
|
|
|
926
992
|
`Error: Flag name collision: boolean property '${propName}' auto-generates '${noFlag}' which is already used by property '${flagNames[noFlag]}'.
|
|
927
993
|
`
|
|
928
994
|
);
|
|
929
|
-
process.exit(EXIT_CODES.
|
|
995
|
+
process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
|
|
930
996
|
}
|
|
931
997
|
flagNames[noFlag] = propName;
|
|
932
998
|
const defaultVal = propSchema.default ?? false;
|
|
@@ -1132,6 +1198,27 @@ async function promptWithTimeout(moduleDef, timeout) {
|
|
|
1132
1198
|
init_esm_shims();
|
|
1133
1199
|
init_errors();
|
|
1134
1200
|
import yaml from "js-yaml";
|
|
1201
|
+
var TOOLKIT_MISSING_HINT = "The 'markdown' and 'skill' output formats require the apcore-toolkit peer dependency. Install with: npm install apcore-toolkit@^0.6";
|
|
1202
|
+
function descriptorToScanned(m) {
|
|
1203
|
+
const metadata = m.metadata ?? {};
|
|
1204
|
+
const display = metadata["display"] ?? null;
|
|
1205
|
+
return {
|
|
1206
|
+
moduleId: m.id,
|
|
1207
|
+
description: m.description ?? "",
|
|
1208
|
+
inputSchema: m.inputSchema ?? {},
|
|
1209
|
+
outputSchema: m.outputSchema ?? {},
|
|
1210
|
+
tags: m.tags ?? [],
|
|
1211
|
+
target: "",
|
|
1212
|
+
version: "1.0.0",
|
|
1213
|
+
annotations: m.annotations ?? null,
|
|
1214
|
+
documentation: null,
|
|
1215
|
+
suggestedAlias: null,
|
|
1216
|
+
examples: [],
|
|
1217
|
+
metadata,
|
|
1218
|
+
display,
|
|
1219
|
+
warnings: []
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1135
1222
|
function csvCellString(value) {
|
|
1136
1223
|
if (value === null || value === void 0) return "";
|
|
1137
1224
|
if (typeof value === "object") return JSON.stringify(value);
|
|
@@ -1160,7 +1247,7 @@ function formatTable(headers, rows) {
|
|
|
1160
1247
|
);
|
|
1161
1248
|
return [headerLine, sep2, ...dataLines].join("\n") + "\n";
|
|
1162
1249
|
}
|
|
1163
|
-
function formatModuleList(modules, format, filterTags, showDeps = false, exposureFilter) {
|
|
1250
|
+
async function formatModuleList(modules, format, filterTags, showDeps = false, exposureFilter) {
|
|
1164
1251
|
if (format === "table") {
|
|
1165
1252
|
if (modules.length === 0 && filterTags && filterTags.length > 0) {
|
|
1166
1253
|
process.stdout.write(
|
|
@@ -1205,6 +1292,17 @@ function formatModuleList(modules, format, filterTags, showDeps = false, exposur
|
|
|
1205
1292
|
return entry;
|
|
1206
1293
|
});
|
|
1207
1294
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
1295
|
+
} else if (format === "markdown" || format === "skill") {
|
|
1296
|
+
let toolkit;
|
|
1297
|
+
try {
|
|
1298
|
+
toolkit = await import("apcore-toolkit");
|
|
1299
|
+
} catch {
|
|
1300
|
+
throw new Error(TOOLKIT_MISSING_HINT);
|
|
1301
|
+
}
|
|
1302
|
+
const scanned = modules.map(descriptorToScanned);
|
|
1303
|
+
process.stdout.write(
|
|
1304
|
+
toolkit.formatModules(scanned, { style: format, display: true }) + "\n"
|
|
1305
|
+
);
|
|
1208
1306
|
}
|
|
1209
1307
|
}
|
|
1210
1308
|
function annotationsToDict(annotations) {
|
|
@@ -1218,7 +1316,7 @@ function annotationsToDict(annotations) {
|
|
|
1218
1316
|
}
|
|
1219
1317
|
return Object.keys(result).length > 0 ? result : null;
|
|
1220
1318
|
}
|
|
1221
|
-
function formatModuleDetail(moduleDef, format) {
|
|
1319
|
+
async function formatModuleDetail(moduleDef, format) {
|
|
1222
1320
|
if (format === "table") {
|
|
1223
1321
|
process.stdout.write(`
|
|
1224
1322
|
Module: ${moduleDef.id}
|
|
@@ -1289,6 +1387,16 @@ Tags: ${tags.join(", ")}
|
|
|
1289
1387
|
}
|
|
1290
1388
|
}
|
|
1291
1389
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
1390
|
+
} else if (format === "markdown" || format === "skill") {
|
|
1391
|
+
let toolkit;
|
|
1392
|
+
try {
|
|
1393
|
+
toolkit = await import("apcore-toolkit");
|
|
1394
|
+
} catch {
|
|
1395
|
+
throw new Error(TOOLKIT_MISSING_HINT);
|
|
1396
|
+
}
|
|
1397
|
+
process.stdout.write(
|
|
1398
|
+
toolkit.formatModule(descriptorToScanned(moduleDef), { style: format, display: true }) + "\n"
|
|
1399
|
+
);
|
|
1292
1400
|
}
|
|
1293
1401
|
}
|
|
1294
1402
|
function selectFields(result, fields) {
|
|
@@ -2133,6 +2241,98 @@ init_esm_shims();
|
|
|
2133
2241
|
import { Command as Command2, Option as Option2 } from "commander";
|
|
2134
2242
|
init_errors();
|
|
2135
2243
|
init_audit();
|
|
2244
|
+
|
|
2245
|
+
// src/system-usage.ts
|
|
2246
|
+
init_esm_shims();
|
|
2247
|
+
import * as fs4 from "fs";
|
|
2248
|
+
import * as os2 from "os";
|
|
2249
|
+
import * as path4 from "path";
|
|
2250
|
+
var PERIOD_TO_MS = {
|
|
2251
|
+
"1h": 60 * 60 * 1e3,
|
|
2252
|
+
"24h": 24 * 60 * 60 * 1e3,
|
|
2253
|
+
"7d": 7 * 24 * 60 * 60 * 1e3,
|
|
2254
|
+
"30d": 30 * 24 * 60 * 60 * 1e3
|
|
2255
|
+
};
|
|
2256
|
+
var DEFAULT_AUDIT_PATH = path4.join(
|
|
2257
|
+
os2.homedir(),
|
|
2258
|
+
".apcore-cli",
|
|
2259
|
+
"audit.jsonl"
|
|
2260
|
+
);
|
|
2261
|
+
function computeSummary(options = {}) {
|
|
2262
|
+
const auditPath = options.auditPath ?? DEFAULT_AUDIT_PATH;
|
|
2263
|
+
const period = options.period ?? "24h";
|
|
2264
|
+
const cutoff = (options.now ?? /* @__PURE__ */ new Date()).getTime() - PERIOD_TO_MS[period];
|
|
2265
|
+
if (!fs4.existsSync(auditPath)) {
|
|
2266
|
+
return /* @__PURE__ */ new Map();
|
|
2267
|
+
}
|
|
2268
|
+
let raw;
|
|
2269
|
+
try {
|
|
2270
|
+
raw = fs4.readFileSync(auditPath, "utf-8");
|
|
2271
|
+
} catch {
|
|
2272
|
+
return /* @__PURE__ */ new Map();
|
|
2273
|
+
}
|
|
2274
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2275
|
+
const errors = /* @__PURE__ */ new Map();
|
|
2276
|
+
const latencySum = /* @__PURE__ */ new Map();
|
|
2277
|
+
for (const line of raw.split("\n")) {
|
|
2278
|
+
const trimmed = line.trim();
|
|
2279
|
+
if (!trimmed) continue;
|
|
2280
|
+
let entry;
|
|
2281
|
+
try {
|
|
2282
|
+
entry = JSON.parse(trimmed);
|
|
2283
|
+
} catch {
|
|
2284
|
+
continue;
|
|
2285
|
+
}
|
|
2286
|
+
const ts = typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
|
|
2287
|
+
if (Number.isNaN(ts) || ts < cutoff) continue;
|
|
2288
|
+
const moduleId = typeof entry.module_id === "string" ? entry.module_id : null;
|
|
2289
|
+
if (!moduleId) continue;
|
|
2290
|
+
counts.set(moduleId, (counts.get(moduleId) ?? 0) + 1);
|
|
2291
|
+
if (entry.status === "error") {
|
|
2292
|
+
errors.set(moduleId, (errors.get(moduleId) ?? 0) + 1);
|
|
2293
|
+
}
|
|
2294
|
+
const duration = entry.duration_ms;
|
|
2295
|
+
if (typeof duration === "number") {
|
|
2296
|
+
latencySum.set(moduleId, (latencySum.get(moduleId) ?? 0) + duration);
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
const out = /* @__PURE__ */ new Map();
|
|
2300
|
+
for (const [id, calls] of counts) {
|
|
2301
|
+
out.set(id, {
|
|
2302
|
+
module_id: id,
|
|
2303
|
+
calls,
|
|
2304
|
+
errors: errors.get(id) ?? 0,
|
|
2305
|
+
latency_ms: calls > 0 ? (latencySum.get(id) ?? 0) / calls : 0
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2308
|
+
return out;
|
|
2309
|
+
}
|
|
2310
|
+
function sortModulesByUsage(modules, field, options = {}) {
|
|
2311
|
+
const reverse = options.reverse ?? true;
|
|
2312
|
+
const summary = computeSummary({
|
|
2313
|
+
auditPath: options.auditPath,
|
|
2314
|
+
period: options.period
|
|
2315
|
+
});
|
|
2316
|
+
if (summary.size === 0) {
|
|
2317
|
+
modules.sort((a, b) => (a.id ?? a.module_id ?? "").localeCompare(b.id ?? b.module_id ?? ""));
|
|
2318
|
+
if (reverse) modules.reverse();
|
|
2319
|
+
return { used: false };
|
|
2320
|
+
}
|
|
2321
|
+
const key = (m) => {
|
|
2322
|
+
const id = m.id ?? m.module_id ?? "";
|
|
2323
|
+
const s = summary.get(id);
|
|
2324
|
+
if (!s) return 0;
|
|
2325
|
+
return field === "latency" ? s.latency_ms : field === "calls" ? s.calls : s.errors;
|
|
2326
|
+
};
|
|
2327
|
+
modules.sort((a, b) => {
|
|
2328
|
+
const diff = key(a) - key(b);
|
|
2329
|
+
if (diff !== 0) return reverse ? -diff : diff;
|
|
2330
|
+
return (a.id ?? a.module_id ?? "").localeCompare(b.id ?? b.module_id ?? "");
|
|
2331
|
+
});
|
|
2332
|
+
return { used: true };
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
// src/discovery.ts
|
|
2136
2336
|
var TAG_PATTERN = /^[a-z][a-z0-9_-]*$/;
|
|
2137
2337
|
function validateTag(tag) {
|
|
2138
2338
|
if (!TAG_PATTERN.test(tag)) {
|
|
@@ -2166,7 +2366,9 @@ function getAnnotationFlag(moduleDef, flag) {
|
|
|
2166
2366
|
return ann[attr] === true;
|
|
2167
2367
|
}
|
|
2168
2368
|
function registerListCommand(apcliGroup, registry, exposureFilter) {
|
|
2169
|
-
const listCmd = new Command2("list").description("List available modules in the registry.").option("--tag <tag>", "Filter modules by tag (AND logic). Repeatable.", collectTag, []).option("--flat", "Show flat list (no grouping).", false).
|
|
2369
|
+
const listCmd = new Command2("list").description("List available modules in the registry.").option("--tag <tag>", "Filter modules by tag (AND logic). Repeatable.", collectTag, []).option("--flat", "Show flat list (no grouping).", false).addOption(
|
|
2370
|
+
new Option2("--format <format>", "Output format.").choices(["table", "json", "csv", "yaml", "jsonl", "markdown", "skill"])
|
|
2371
|
+
).option("-s, --search <query>", "Filter by substring match on ID and description.").addOption(
|
|
2170
2372
|
new Option2("--status <status>", "Filter by module status.").choices(["enabled", "disabled", "all"]).default("enabled")
|
|
2171
2373
|
).option("-a, --annotation <flag>", "Filter by annotation flag (AND logic). Repeatable.", collectAnnotation, []).addOption(
|
|
2172
2374
|
new Option2("--sort <field>", "Sort order.").choices(["id", "calls", "errors", "latency"]).default("id")
|
|
@@ -2216,14 +2418,18 @@ function registerListCommand(apcliGroup, registry, exposureFilter) {
|
|
|
2216
2418
|
}
|
|
2217
2419
|
}
|
|
2218
2420
|
if (opts.sort === "calls" || opts.sort === "errors" || opts.sort === "latency") {
|
|
2219
|
-
|
|
2220
|
-
|
|
2421
|
+
const { used } = sortModulesByUsage(modules, opts.sort, { reverse: !opts.reverse });
|
|
2422
|
+
if (!used) {
|
|
2423
|
+
process.stderr.write(
|
|
2424
|
+
`note: no usage data available for --sort ${opts.sort}; sorted by id. Run some modules first to populate ~/.apcore-cli/audit.jsonl.
|
|
2221
2425
|
`
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2426
|
+
);
|
|
2427
|
+
}
|
|
2428
|
+
} else {
|
|
2429
|
+
modules.sort((a, b) => (a.id ?? "").localeCompare(b.id ?? ""));
|
|
2430
|
+
if (opts.reverse) {
|
|
2431
|
+
modules.reverse();
|
|
2432
|
+
}
|
|
2227
2433
|
}
|
|
2228
2434
|
let showExposureCol = false;
|
|
2229
2435
|
if (exposureFilter && opts.exposure !== "all") {
|
|
@@ -2238,12 +2444,14 @@ function registerListCommand(apcliGroup, registry, exposureFilter) {
|
|
|
2238
2444
|
}
|
|
2239
2445
|
const fmt = resolveFormat(opts.format);
|
|
2240
2446
|
const filterTagsArg = opts.tag.length > 0 ? opts.tag : void 0;
|
|
2241
|
-
formatModuleList(modules, fmt, filterTagsArg, opts.deps, showExposureCol ? exposureFilter : void 0);
|
|
2447
|
+
void formatModuleList(modules, fmt, filterTagsArg, opts.deps, showExposureCol ? exposureFilter : void 0);
|
|
2242
2448
|
});
|
|
2243
2449
|
apcliGroup.addCommand(listCmd);
|
|
2244
2450
|
}
|
|
2245
2451
|
function registerDescribeCommand(apcliGroup, registry) {
|
|
2246
|
-
const describeCmd = new Command2("describe").description("Show metadata, schema, and annotations for a module.").argument("<module-id>", "Module ID to describe").
|
|
2452
|
+
const describeCmd = new Command2("describe").description("Show metadata, schema, and annotations for a module.").argument("<module-id>", "Module ID to describe").addOption(
|
|
2453
|
+
new Option2("--format <format>", "Output format.").choices(["table", "json", "csv", "yaml", "jsonl", "markdown", "skill"])
|
|
2454
|
+
).action((moduleId, opts) => {
|
|
2247
2455
|
validateModuleId(moduleId);
|
|
2248
2456
|
const moduleDef = registry.getModule(moduleId);
|
|
2249
2457
|
if (!moduleDef) {
|
|
@@ -2254,7 +2462,7 @@ function registerDescribeCommand(apcliGroup, registry) {
|
|
|
2254
2462
|
process.exit(EXIT_CODES.MODULE_NOT_FOUND);
|
|
2255
2463
|
}
|
|
2256
2464
|
const fmt = resolveFormat(opts.format);
|
|
2257
|
-
formatModuleDetail(moduleDef, fmt);
|
|
2465
|
+
void formatModuleDetail(moduleDef, fmt);
|
|
2258
2466
|
});
|
|
2259
2467
|
apcliGroup.addCommand(describeCmd);
|
|
2260
2468
|
}
|
|
@@ -2374,8 +2582,8 @@ function registerValidateCommand(cli, registry, executor) {
|
|
|
2374
2582
|
|
|
2375
2583
|
// src/system-cmd.ts
|
|
2376
2584
|
init_esm_shims();
|
|
2377
|
-
init_errors();
|
|
2378
2585
|
import { Command as Command3 } from "commander";
|
|
2586
|
+
init_errors();
|
|
2379
2587
|
async function callSystemModule(executor, moduleId, inputs) {
|
|
2380
2588
|
if (executor.call) {
|
|
2381
2589
|
return executor.call(moduleId, inputs);
|
|
@@ -2394,6 +2602,15 @@ function emitErrorAndExit(e) {
|
|
|
2394
2602
|
`);
|
|
2395
2603
|
process.exit(exitCodeForError(e));
|
|
2396
2604
|
}
|
|
2605
|
+
async function requireApprovalForSystemCommand(moduleId, autoApprove) {
|
|
2606
|
+
const syntheticModuleDef = {
|
|
2607
|
+
id: moduleId,
|
|
2608
|
+
name: moduleId,
|
|
2609
|
+
description: `system command: ${moduleId}`,
|
|
2610
|
+
annotations: { requires_approval: true }
|
|
2611
|
+
};
|
|
2612
|
+
await checkApproval(syntheticModuleDef, autoApprove, void 0);
|
|
2613
|
+
}
|
|
2397
2614
|
function formatHealthSummaryTty(result) {
|
|
2398
2615
|
const summary = result.summary ?? {};
|
|
2399
2616
|
const modules = result.modules ?? [];
|
|
@@ -2534,9 +2751,10 @@ function registerUsageCommand(apcliGroup, executor) {
|
|
|
2534
2751
|
apcliGroup.addCommand(usageCmd);
|
|
2535
2752
|
}
|
|
2536
2753
|
function registerEnableCommand(apcliGroup, executor) {
|
|
2537
|
-
const enableCmd = new Command3("enable").description("Enable a disabled module at runtime.").argument("<module-id>", "Module ID to enable").requiredOption("--reason <reason>", "Reason for enabling (required for audit).").option("-y, --yes", "
|
|
2754
|
+
const enableCmd = new Command3("enable").description("Enable a disabled module at runtime.").argument("<module-id>", "Module ID to enable").requiredOption("--reason <reason>", "Reason for enabling (required for audit).").option("-y, --yes", "Skip approval prompt (audit D11-B-001 cross-SDK parity).", false).option("--format <format>", "Output format.").action(async (moduleId, opts) => {
|
|
2538
2755
|
const fmt = resolveFormat(opts.format);
|
|
2539
2756
|
try {
|
|
2757
|
+
await requireApprovalForSystemCommand("system.control.toggle_feature", opts.yes);
|
|
2540
2758
|
const result = await callSystemModule(executor, "system.control.toggle_feature", {
|
|
2541
2759
|
module_id: moduleId,
|
|
2542
2760
|
enabled: true,
|
|
@@ -2554,9 +2772,10 @@ function registerEnableCommand(apcliGroup, executor) {
|
|
|
2554
2772
|
apcliGroup.addCommand(enableCmd);
|
|
2555
2773
|
}
|
|
2556
2774
|
function registerDisableCommand(apcliGroup, executor) {
|
|
2557
|
-
const disableCmd = new Command3("disable").description("Disable a module at runtime (calls are rejected until re-enabled).").argument("<module-id>", "Module ID to disable").requiredOption("--reason <reason>", "Reason for disabling (required for audit).").option("-y, --yes", "
|
|
2775
|
+
const disableCmd = new Command3("disable").description("Disable a module at runtime (calls are rejected until re-enabled).").argument("<module-id>", "Module ID to disable").requiredOption("--reason <reason>", "Reason for disabling (required for audit).").option("-y, --yes", "Skip approval prompt (audit D11-B-001 cross-SDK parity).", false).option("--format <format>", "Output format.").action(async (moduleId, opts) => {
|
|
2558
2776
|
const fmt = resolveFormat(opts.format);
|
|
2559
2777
|
try {
|
|
2778
|
+
await requireApprovalForSystemCommand("system.control.toggle_feature", opts.yes);
|
|
2560
2779
|
const result = await callSystemModule(executor, "system.control.toggle_feature", {
|
|
2561
2780
|
module_id: moduleId,
|
|
2562
2781
|
enabled: false,
|
|
@@ -2574,9 +2793,10 @@ function registerDisableCommand(apcliGroup, executor) {
|
|
|
2574
2793
|
apcliGroup.addCommand(disableCmd);
|
|
2575
2794
|
}
|
|
2576
2795
|
function registerReloadCommand(apcliGroup, executor) {
|
|
2577
|
-
const reloadCmd = new Command3("reload").description("Hot-reload a module from disk.").argument("<module-id>", "Module ID to reload").requiredOption("--reason <reason>", "Reason for reload (required for audit).").option("-y, --yes", "
|
|
2796
|
+
const reloadCmd = new Command3("reload").description("Hot-reload a module from disk.").argument("<module-id>", "Module ID to reload").requiredOption("--reason <reason>", "Reason for reload (required for audit).").option("-y, --yes", "Skip approval prompt (audit D11-B-001 cross-SDK parity).", false).option("--format <format>", "Output format.").action(async (moduleId, opts) => {
|
|
2578
2797
|
const fmt = resolveFormat(opts.format);
|
|
2579
2798
|
try {
|
|
2799
|
+
await requireApprovalForSystemCommand("system.control.reload_module", opts.yes);
|
|
2580
2800
|
const result = await callSystemModule(executor, "system.control.reload_module", {
|
|
2581
2801
|
module_id: moduleId,
|
|
2582
2802
|
reason: opts.reason
|
|
@@ -2614,7 +2834,7 @@ function registerConfigCommand(apcliGroup, executor) {
|
|
|
2614
2834
|
}
|
|
2615
2835
|
});
|
|
2616
2836
|
configGroup.addCommand(configGetCmd);
|
|
2617
|
-
const configSetCmd = new Command3("set").description("Update a runtime configuration value (audit-logged;
|
|
2837
|
+
const configSetCmd = new Command3("set").description("Update a runtime configuration value (audit-logged; client-side approval gate applies).").argument("<key>", "Configuration key (dot-path)").argument("<value>", "New value").requiredOption("--reason <reason>", "Reason for config change (required for audit).").option("-y, --yes", "Skip approval prompt (audit D11-B-001 cross-SDK parity).", false).option("--format <format>", "Output format.").action(async (key, value, opts) => {
|
|
2618
2838
|
const fmt = resolveFormat(opts.format);
|
|
2619
2839
|
let parsedValue;
|
|
2620
2840
|
try {
|
|
@@ -2623,6 +2843,7 @@ function registerConfigCommand(apcliGroup, executor) {
|
|
|
2623
2843
|
parsedValue = value;
|
|
2624
2844
|
}
|
|
2625
2845
|
try {
|
|
2846
|
+
await requireApprovalForSystemCommand("system.control.update_config", opts.yes);
|
|
2626
2847
|
const result = await callSystemModule(executor, "system.control.update_config", {
|
|
2627
2848
|
key,
|
|
2628
2849
|
value: parsedValue,
|
|
@@ -2818,7 +3039,29 @@ function registerPipelineCommand(cli, executor) {
|
|
|
2818
3039
|
init_esm_shims();
|
|
2819
3040
|
init_errors();
|
|
2820
3041
|
init_logger();
|
|
2821
|
-
var
|
|
3042
|
+
var ApcliGroupError = class extends Error {
|
|
3043
|
+
constructor(message) {
|
|
3044
|
+
super(message);
|
|
3045
|
+
this.name = "ApcliGroupError";
|
|
3046
|
+
}
|
|
3047
|
+
};
|
|
3048
|
+
var DEFAULT_BUILTIN_GROUP_NAME = "apcli";
|
|
3049
|
+
var RESERVED_GROUP_NAMES = /* @__PURE__ */ new Set([DEFAULT_BUILTIN_GROUP_NAME]);
|
|
3050
|
+
var _effectiveReservedNames = RESERVED_GROUP_NAMES;
|
|
3051
|
+
function getReservedGroupNames() {
|
|
3052
|
+
return _effectiveReservedNames;
|
|
3053
|
+
}
|
|
3054
|
+
function setReservedGroupNames(names) {
|
|
3055
|
+
_effectiveReservedNames = names;
|
|
3056
|
+
}
|
|
3057
|
+
var _NAME_REGEX = /^[a-z][a-z0-9_-]*$/;
|
|
3058
|
+
function _validateBuiltinGroupName(name) {
|
|
3059
|
+
if (!name || !_NAME_REGEX.test(name)) {
|
|
3060
|
+
throw new ApcliGroupError(
|
|
3061
|
+
`builtinGroupName ${JSON.stringify(name)} must match /^[a-z][a-z0-9_-]*$/ (non-empty, lowercase, alphanumeric + '_' / '-', leading letter).`
|
|
3062
|
+
);
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
2822
3065
|
var VALID_USER_MODES = /* @__PURE__ */ new Set([
|
|
2823
3066
|
"all",
|
|
2824
3067
|
"none",
|
|
@@ -2847,6 +3090,7 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
2847
3090
|
_disableEnv;
|
|
2848
3091
|
_registryInjected;
|
|
2849
3092
|
_fromCliConfig;
|
|
3093
|
+
_name;
|
|
2850
3094
|
constructor(init) {
|
|
2851
3095
|
this._mode = init.mode;
|
|
2852
3096
|
this._include = init.include;
|
|
@@ -2854,6 +3098,16 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
2854
3098
|
this._disableEnv = init.disableEnv;
|
|
2855
3099
|
this._registryInjected = init.registryInjected;
|
|
2856
3100
|
this._fromCliConfig = init.fromCliConfig;
|
|
3101
|
+
this._name = init.name;
|
|
3102
|
+
}
|
|
3103
|
+
/**
|
|
3104
|
+
* Resolved name for the built-in command group (default `"apcli"`).
|
|
3105
|
+
* Overridable via createCli's `builtinGroupName` option for downstream
|
|
3106
|
+
* branded CLIs that want a custom namespace. Cross-SDK parity with
|
|
3107
|
+
* Python `ApcliGroup.name` (2026-05-08).
|
|
3108
|
+
*/
|
|
3109
|
+
get name() {
|
|
3110
|
+
return this._name;
|
|
2857
3111
|
}
|
|
2858
3112
|
/**
|
|
2859
3113
|
* Tier 1 constructor — config came from `createCli({ apcli })`.
|
|
@@ -2874,6 +3128,18 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
2874
3128
|
* Env var (Tier 2) may override the yaml-supplied mode.
|
|
2875
3129
|
*/
|
|
2876
3130
|
static fromYaml(config, opts) {
|
|
3131
|
+
if (config !== null && config !== void 0 && typeof config !== "boolean" && (typeof config !== "object" || Array.isArray(config))) {
|
|
3132
|
+
const got = Array.isArray(config) ? "array" : typeof config;
|
|
3133
|
+
warn(
|
|
3134
|
+
`apcore.yaml apcli has unexpected type ${got}; using auto-detect.`
|
|
3135
|
+
);
|
|
3136
|
+
return _ApcliGroup._build(
|
|
3137
|
+
void 0,
|
|
3138
|
+
opts,
|
|
3139
|
+
/*fromCliConfig*/
|
|
3140
|
+
false
|
|
3141
|
+
);
|
|
3142
|
+
}
|
|
2877
3143
|
return _ApcliGroup._build(
|
|
2878
3144
|
config,
|
|
2879
3145
|
opts,
|
|
@@ -2887,8 +3153,12 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
2887
3153
|
* Use this in programmatic contexts where throwing/exiting is unwanted.
|
|
2888
3154
|
*/
|
|
2889
3155
|
static tryFromYaml(config, opts) {
|
|
2890
|
-
if (config !== null && config !== void 0 && typeof config !== "boolean" && typeof config !== "object") {
|
|
2891
|
-
|
|
3156
|
+
if (config !== null && config !== void 0 && typeof config !== "boolean" && (typeof config !== "object" || Array.isArray(config))) {
|
|
3157
|
+
const got = Array.isArray(config) ? "array" : typeof config;
|
|
3158
|
+
return [
|
|
3159
|
+
null,
|
|
3160
|
+
`apcore.yaml 'apcli:' must be a bool, object, or null; got ${got}`
|
|
3161
|
+
];
|
|
2892
3162
|
}
|
|
2893
3163
|
if (config !== null && config !== void 0 && typeof config === "object" && !Array.isArray(config)) {
|
|
2894
3164
|
const mode = config["mode"];
|
|
@@ -2905,6 +3175,8 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
2905
3175
|
// Internal builder — shared by both factories
|
|
2906
3176
|
// -------------------------------------------------------------------------
|
|
2907
3177
|
static _build(config, opts, fromCliConfig) {
|
|
3178
|
+
const name = opts.name ?? DEFAULT_BUILTIN_GROUP_NAME;
|
|
3179
|
+
_validateBuiltinGroupName(name);
|
|
2908
3180
|
if (config === true) {
|
|
2909
3181
|
return new _ApcliGroup({
|
|
2910
3182
|
mode: "all",
|
|
@@ -2912,7 +3184,8 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
2912
3184
|
exclude: [],
|
|
2913
3185
|
disableEnv: false,
|
|
2914
3186
|
registryInjected: opts.registryInjected,
|
|
2915
|
-
fromCliConfig
|
|
3187
|
+
fromCliConfig,
|
|
3188
|
+
name
|
|
2916
3189
|
});
|
|
2917
3190
|
}
|
|
2918
3191
|
if (config === false) {
|
|
@@ -2922,7 +3195,8 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
2922
3195
|
exclude: [],
|
|
2923
3196
|
disableEnv: false,
|
|
2924
3197
|
registryInjected: opts.registryInjected,
|
|
2925
|
-
fromCliConfig
|
|
3198
|
+
fromCliConfig,
|
|
3199
|
+
name
|
|
2926
3200
|
});
|
|
2927
3201
|
}
|
|
2928
3202
|
if (config === void 0 || config === null) {
|
|
@@ -2932,7 +3206,8 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
2932
3206
|
exclude: [],
|
|
2933
3207
|
disableEnv: false,
|
|
2934
3208
|
registryInjected: opts.registryInjected,
|
|
2935
|
-
fromCliConfig
|
|
3209
|
+
fromCliConfig,
|
|
3210
|
+
name
|
|
2936
3211
|
});
|
|
2937
3212
|
}
|
|
2938
3213
|
if (typeof config !== "object" || Array.isArray(config)) {
|
|
@@ -2980,7 +3255,8 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
2980
3255
|
exclude,
|
|
2981
3256
|
disableEnv,
|
|
2982
3257
|
registryInjected: opts.registryInjected,
|
|
2983
|
-
fromCliConfig
|
|
3258
|
+
fromCliConfig,
|
|
3259
|
+
name
|
|
2984
3260
|
});
|
|
2985
3261
|
}
|
|
2986
3262
|
/**
|
|
@@ -3073,7 +3349,8 @@ var ApcliGroup = class _ApcliGroup {
|
|
|
3073
3349
|
*/
|
|
3074
3350
|
_parseEnv(raw) {
|
|
3075
3351
|
if (raw === void 0 || raw === "") return null;
|
|
3076
|
-
const normalized = raw.toLowerCase();
|
|
3352
|
+
const normalized = raw.trim().toLowerCase();
|
|
3353
|
+
if (normalized === "") return null;
|
|
3077
3354
|
if (normalized === "show" || normalized === "1" || normalized === "true") {
|
|
3078
3355
|
return "all";
|
|
3079
3356
|
}
|
|
@@ -3272,8 +3549,30 @@ function canonicalFormatHelp(cmd, helper) {
|
|
|
3272
3549
|
return sections.join("\n\n") + "\n";
|
|
3273
3550
|
}
|
|
3274
3551
|
|
|
3552
|
+
// src/validate.ts
|
|
3553
|
+
init_esm_shims();
|
|
3554
|
+
init_errors();
|
|
3555
|
+
var MODULE_ID_PATTERN = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/;
|
|
3556
|
+
var MAX_MODULE_ID_LENGTH = 192;
|
|
3557
|
+
function validateModuleId(moduleId) {
|
|
3558
|
+
if (moduleId.length > MAX_MODULE_ID_LENGTH) {
|
|
3559
|
+
process.stderr.write(
|
|
3560
|
+
`Error: Invalid module ID format: '${moduleId}'. Maximum length is ${MAX_MODULE_ID_LENGTH} characters.
|
|
3561
|
+
`
|
|
3562
|
+
);
|
|
3563
|
+
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3564
|
+
}
|
|
3565
|
+
if (!MODULE_ID_PATTERN.test(moduleId)) {
|
|
3566
|
+
process.stderr.write(
|
|
3567
|
+
`Error: Invalid module ID format: '${moduleId}'.
|
|
3568
|
+
`
|
|
3569
|
+
);
|
|
3570
|
+
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3571
|
+
}
|
|
3572
|
+
}
|
|
3573
|
+
|
|
3275
3574
|
// src/main.ts
|
|
3276
|
-
var __dirname2 =
|
|
3575
|
+
var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
|
|
3277
3576
|
var verboseHelp = false;
|
|
3278
3577
|
function setVerboseHelp(verbose) {
|
|
3279
3578
|
verboseHelp = verbose;
|
|
@@ -3312,7 +3611,7 @@ function resolveStringOption(cliValue, envValue) {
|
|
|
3312
3611
|
}
|
|
3313
3612
|
var VERSION = "0.0.0";
|
|
3314
3613
|
try {
|
|
3315
|
-
const pkg = JSON.parse(
|
|
3614
|
+
const pkg = JSON.parse(readFileSync3(path5.resolve(__dirname2, "../package.json"), "utf-8"));
|
|
3316
3615
|
VERSION = pkg.version;
|
|
3317
3616
|
} catch {
|
|
3318
3617
|
}
|
|
@@ -3372,6 +3671,10 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3372
3671
|
let app;
|
|
3373
3672
|
let expose;
|
|
3374
3673
|
let apcliOption;
|
|
3674
|
+
let appVersion;
|
|
3675
|
+
let appDescription;
|
|
3676
|
+
let allowedPrefixes;
|
|
3677
|
+
let builtinGroupName;
|
|
3375
3678
|
if (typeof extensionsDirOrOpts === "object" && extensionsDirOrOpts !== null) {
|
|
3376
3679
|
extensionsDir = extensionsDirOrOpts.extensionsDir;
|
|
3377
3680
|
progName = extensionsDirOrOpts.progName ?? progName;
|
|
@@ -3382,6 +3685,10 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3382
3685
|
extraCommands = extensionsDirOrOpts.extraCommands;
|
|
3383
3686
|
expose = extensionsDirOrOpts.expose;
|
|
3384
3687
|
apcliOption = extensionsDirOrOpts.apcli;
|
|
3688
|
+
appVersion = extensionsDirOrOpts.version;
|
|
3689
|
+
appDescription = extensionsDirOrOpts.description;
|
|
3690
|
+
builtinGroupName = extensionsDirOrOpts.builtinGroupName;
|
|
3691
|
+
allowedPrefixes = extensionsDirOrOpts.allowedPrefixes;
|
|
3385
3692
|
} else {
|
|
3386
3693
|
extensionsDir = extensionsDirOrOpts;
|
|
3387
3694
|
}
|
|
@@ -3392,7 +3699,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3392
3699
|
setAuditLogger(auditLogger);
|
|
3393
3700
|
} catch {
|
|
3394
3701
|
}
|
|
3395
|
-
const resolvedProgName = progName ??
|
|
3702
|
+
const resolvedProgName = progName ?? path5.basename(process.argv[1] ?? "apcore-cli") ?? "apcore-cli";
|
|
3396
3703
|
const cliLogLevel = process.env.APCORE_CLI_LOGGING_LEVEL ?? process.env.APCORE_LOGGING_LEVEL ?? "WARNING";
|
|
3397
3704
|
setLogLevel(cliLogLevel);
|
|
3398
3705
|
if (app && (registry || executor)) {
|
|
@@ -3418,7 +3725,10 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3418
3725
|
}
|
|
3419
3726
|
}
|
|
3420
3727
|
const registryInjected = registry !== void 0;
|
|
3421
|
-
const program = new Command5(resolvedProgName).exitOverride().
|
|
3728
|
+
const program = new Command5(resolvedProgName).exitOverride().helpOption("-h, --help", "Print help").addHelpCommand("help [command]", "Print this message or the help of the given subcommand(s)").description(appDescription ?? `${resolvedProgName} CLI`).option("--log-level <level>", "Logging level (DEBUG|INFO|WARNING|ERROR)", "WARNING").option("--verbose", "Show all options in help output (including built-in options)");
|
|
3729
|
+
if (appVersion) {
|
|
3730
|
+
program.version(appVersion, "-V, --version", "Print version");
|
|
3731
|
+
}
|
|
3422
3732
|
program.configureHelp({ formatHelp: canonicalFormatHelp });
|
|
3423
3733
|
if (!registryInjected) {
|
|
3424
3734
|
program.option("--extensions-dir <path>", "Path to extensions directory");
|
|
@@ -3426,21 +3736,39 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3426
3736
|
program.option("--binding <path>", "Path to binding.yaml for display overlay");
|
|
3427
3737
|
}
|
|
3428
3738
|
let apcliCfg;
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3739
|
+
try {
|
|
3740
|
+
if (apcliOption instanceof ApcliGroup) {
|
|
3741
|
+
if (builtinGroupName !== void 0 && builtinGroupName !== "apcli" && apcliOption.name !== builtinGroupName) {
|
|
3742
|
+
throw new Error(
|
|
3743
|
+
`builtinGroupName=${JSON.stringify(builtinGroupName)} conflicts with the name on the supplied ApcliGroup (${JSON.stringify(apcliOption.name)}). Pass only one.`
|
|
3744
|
+
);
|
|
3745
|
+
}
|
|
3746
|
+
apcliCfg = apcliOption;
|
|
3747
|
+
} else if (apcliOption !== void 0) {
|
|
3748
|
+
apcliCfg = ApcliGroup.fromCliConfig(apcliOption, {
|
|
3749
|
+
registryInjected,
|
|
3750
|
+
name: builtinGroupName
|
|
3751
|
+
});
|
|
3752
|
+
} else {
|
|
3753
|
+
let yamlVal = null;
|
|
3754
|
+
try {
|
|
3755
|
+
const resolver = new ConfigResolver();
|
|
3756
|
+
yamlVal = resolver.resolveObject("apcli");
|
|
3757
|
+
} catch {
|
|
3758
|
+
yamlVal = null;
|
|
3759
|
+
}
|
|
3760
|
+
apcliCfg = ApcliGroup.fromYaml(yamlVal, {
|
|
3761
|
+
registryInjected,
|
|
3762
|
+
name: builtinGroupName
|
|
3763
|
+
});
|
|
3440
3764
|
}
|
|
3441
|
-
|
|
3765
|
+
} catch (e) {
|
|
3766
|
+
process.stderr.write(`Error: ${e instanceof Error ? e.message : String(e)}
|
|
3767
|
+
`);
|
|
3768
|
+
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3442
3769
|
}
|
|
3443
|
-
|
|
3770
|
+
setReservedGroupNames(/* @__PURE__ */ new Set([apcliCfg.name]));
|
|
3771
|
+
const apcliGroup = program.command(apcliCfg.name, { hidden: !apcliCfg.isGroupVisible() }).description("Built-in commands");
|
|
3444
3772
|
if (registry) {
|
|
3445
3773
|
program._registry = registry;
|
|
3446
3774
|
if (executor) {
|
|
@@ -3466,17 +3794,17 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3466
3794
|
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3467
3795
|
}
|
|
3468
3796
|
_registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exposureFilter);
|
|
3469
|
-
_registerDeprecationShims(program, apcliGroup, registryInjected, resolvedProgName);
|
|
3470
3797
|
program.addHelpText("after", [
|
|
3471
3798
|
"",
|
|
3472
|
-
"Use --help --verbose to show all options (including built-in
|
|
3799
|
+
"Use --help --verbose to show all options (including built-in options).",
|
|
3473
3800
|
"Use --help --man to display a formatted man page."
|
|
3474
3801
|
].join("\n"));
|
|
3475
|
-
configureManHelp(program, resolvedProgName, VERSION);
|
|
3802
|
+
configureManHelp(program, resolvedProgName, appVersion ?? VERSION);
|
|
3476
3803
|
if (extraCommands && extraCommands.length > 0) {
|
|
3804
|
+
const _reservedForExtra = /* @__PURE__ */ new Set([apcliCfg.name]);
|
|
3477
3805
|
for (const cmd of extraCommands) {
|
|
3478
3806
|
const cmdName = cmd.name();
|
|
3479
|
-
if (
|
|
3807
|
+
if (_reservedForExtra.has(cmdName)) {
|
|
3480
3808
|
process.stderr.write(
|
|
3481
3809
|
`Error: extraCommands name '${cmdName}' is reserved
|
|
3482
3810
|
`
|
|
@@ -3485,21 +3813,11 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3485
3813
|
}
|
|
3486
3814
|
const existing = program.commands.find((c) => c.name() === cmdName);
|
|
3487
3815
|
if (existing) {
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
warn(
|
|
3491
|
-
`extraCommands '${cmdName}' overrides the deprecation shim for the same name. The shim will be removed.`
|
|
3492
|
-
);
|
|
3493
|
-
const cmds = program.commands;
|
|
3494
|
-
const idx = cmds.indexOf(existing);
|
|
3495
|
-
if (idx >= 0) cmds.splice(idx, 1);
|
|
3496
|
-
} else {
|
|
3497
|
-
process.stderr.write(
|
|
3498
|
-
`Error: extraCommands name '${cmdName}' collides with an existing command
|
|
3816
|
+
process.stderr.write(
|
|
3817
|
+
`Error: extraCommands name '${cmdName}' collides with an existing command
|
|
3499
3818
|
`
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
}
|
|
3819
|
+
);
|
|
3820
|
+
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3503
3821
|
}
|
|
3504
3822
|
program.addCommand(cmd);
|
|
3505
3823
|
}
|
|
@@ -3508,7 +3826,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3508
3826
|
const opts = thisCommand.opts();
|
|
3509
3827
|
const commandsDir = opts.commandsDir;
|
|
3510
3828
|
const bindingPath = opts.binding;
|
|
3511
|
-
await applyToolkitIntegration(commandsDir, bindingPath);
|
|
3829
|
+
await applyToolkitIntegration(commandsDir, bindingPath, { allowedPrefixes });
|
|
3512
3830
|
});
|
|
3513
3831
|
return program;
|
|
3514
3832
|
}
|
|
@@ -3559,53 +3877,11 @@ function _registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exp
|
|
|
3559
3877
|
entry.register(apcliGroup, registry, executor);
|
|
3560
3878
|
}
|
|
3561
3879
|
}
|
|
3562
|
-
var _DEPRECATED_ROOT_COMMANDS = [
|
|
3563
|
-
"list",
|
|
3564
|
-
"describe",
|
|
3565
|
-
"exec",
|
|
3566
|
-
"init",
|
|
3567
|
-
"validate",
|
|
3568
|
-
"health",
|
|
3569
|
-
"usage",
|
|
3570
|
-
"enable",
|
|
3571
|
-
"disable",
|
|
3572
|
-
"reload",
|
|
3573
|
-
"config",
|
|
3574
|
-
"completion",
|
|
3575
|
-
"describe-pipeline"
|
|
3576
|
-
];
|
|
3577
|
-
function _registerDeprecationShims(root, apcliGroup, registryInjected, cliName) {
|
|
3578
|
-
if (registryInjected) return;
|
|
3579
|
-
for (const name of _DEPRECATED_ROOT_COMMANDS) {
|
|
3580
|
-
const apcliSub = apcliGroup.commands.find((c) => c.name() === name);
|
|
3581
|
-
if (!apcliSub) continue;
|
|
3582
|
-
if (root.commands.some((c) => c.name() === name)) continue;
|
|
3583
|
-
const shim = root.command(name).description(`[DEPRECATED] Use '${cliName} apcli ${name}' instead.`).allowUnknownOption(true).allowExcessArguments(true).helpOption(false);
|
|
3584
|
-
shim.__isDeprecationShim = true;
|
|
3585
|
-
shim.action(async function() {
|
|
3586
|
-
process.stderr.write(
|
|
3587
|
-
`WARNING: '${name}' as a root-level command is deprecated. Use '${cliName} apcli ${name}' instead.
|
|
3588
|
-
Will be removed in v0.8. See: https://aiperceivable.github.io/apcore-cli/features/builtin-group/#11-migration
|
|
3589
|
-
`
|
|
3590
|
-
);
|
|
3591
|
-
const tail = _collectShimForwardArgs(this);
|
|
3592
|
-
await apcliSub.parseAsync(tail, { from: "user" });
|
|
3593
|
-
});
|
|
3594
|
-
}
|
|
3595
|
-
}
|
|
3596
|
-
function _collectShimForwardArgs(shim) {
|
|
3597
|
-
const shimArgs = (shim.args ?? []).slice();
|
|
3598
|
-
if (shimArgs.length > 0) return shimArgs;
|
|
3599
|
-
const shimName = shim.name();
|
|
3600
|
-
const idx = process.argv.indexOf(shimName);
|
|
3601
|
-
if (idx < 0) return [];
|
|
3602
|
-
return process.argv.slice(idx + 1);
|
|
3603
|
-
}
|
|
3604
3880
|
var bindingDisplayMap = /* @__PURE__ */ new Map();
|
|
3605
3881
|
function lookupBindingDisplay(moduleId) {
|
|
3606
3882
|
return bindingDisplayMap.get(moduleId);
|
|
3607
3883
|
}
|
|
3608
|
-
async function applyToolkitIntegration(commandsDir, bindingPath) {
|
|
3884
|
+
async function applyToolkitIntegration(commandsDir, bindingPath, options = {}) {
|
|
3609
3885
|
if (!commandsDir && !bindingPath) {
|
|
3610
3886
|
return;
|
|
3611
3887
|
}
|
|
@@ -3625,14 +3901,14 @@ async function applyToolkitIntegration(commandsDir, bindingPath) {
|
|
|
3625
3901
|
}
|
|
3626
3902
|
if (bindingPath) {
|
|
3627
3903
|
try {
|
|
3628
|
-
await loadBindingDisplayOverlay(toolkit, bindingPath);
|
|
3904
|
+
await loadBindingDisplayOverlay(toolkit, bindingPath, options.allowedPrefixes);
|
|
3629
3905
|
} catch (err) {
|
|
3630
3906
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3631
3907
|
warn(`apcore-toolkit: failed to load binding '${bindingPath}': ${msg}`);
|
|
3632
3908
|
}
|
|
3633
3909
|
}
|
|
3634
3910
|
}
|
|
3635
|
-
async function loadBindingDisplayOverlay(toolkit, bindingPath) {
|
|
3911
|
+
async function loadBindingDisplayOverlay(toolkit, bindingPath, allowedPrefixes) {
|
|
3636
3912
|
const BindingLoaderCtor = toolkit.BindingLoader;
|
|
3637
3913
|
const DisplayResolverCtor = toolkit.DisplayResolver;
|
|
3638
3914
|
if (!BindingLoaderCtor || !DisplayResolverCtor) {
|
|
@@ -3642,11 +3918,23 @@ async function loadBindingDisplayOverlay(toolkit, bindingPath) {
|
|
|
3642
3918
|
const scanned = loader.load(bindingPath);
|
|
3643
3919
|
const resolver = new DisplayResolverCtor();
|
|
3644
3920
|
const resolved = resolver.resolve(scanned, { bindingPath });
|
|
3921
|
+
const prefixes = allowedPrefixes && allowedPrefixes.length > 0 ? allowedPrefixes : null;
|
|
3922
|
+
const isTargetAllowed = (target) => {
|
|
3923
|
+
if (!prefixes) return true;
|
|
3924
|
+
if (typeof target !== "string" || target.length === 0) return true;
|
|
3925
|
+
return prefixes.some((p) => target.startsWith(p));
|
|
3926
|
+
};
|
|
3645
3927
|
for (const mod of resolved) {
|
|
3646
3928
|
if (!mod || typeof mod !== "object") continue;
|
|
3647
3929
|
const entry = mod;
|
|
3648
3930
|
const id = typeof entry.moduleId === "string" ? entry.moduleId : null;
|
|
3649
3931
|
if (!id) continue;
|
|
3932
|
+
if (!isTargetAllowed(entry.target)) {
|
|
3933
|
+
warn(
|
|
3934
|
+
`apcore-toolkit: dropped binding entry '${id}' \u2014 target '${String(entry.target)}' is outside allowedPrefixes`
|
|
3935
|
+
);
|
|
3936
|
+
continue;
|
|
3937
|
+
}
|
|
3650
3938
|
const meta = entry.metadata ?? {};
|
|
3651
3939
|
const display = meta.display;
|
|
3652
3940
|
if (display && typeof display === "object" && !Array.isArray(display)) {
|
|
@@ -3656,7 +3944,12 @@ async function loadBindingDisplayOverlay(toolkit, bindingPath) {
|
|
|
3656
3944
|
}
|
|
3657
3945
|
function main(progName) {
|
|
3658
3946
|
verboseHelp = hasVerboseFlag();
|
|
3659
|
-
const program = createCli(
|
|
3947
|
+
const program = createCli({
|
|
3948
|
+
progName,
|
|
3949
|
+
verbose: verboseHelp,
|
|
3950
|
+
version: VERSION,
|
|
3951
|
+
description: `${progName ?? "apcore-cli"} \u2014 execute apcore modules from the command line`
|
|
3952
|
+
});
|
|
3660
3953
|
try {
|
|
3661
3954
|
program.parse(process.argv);
|
|
3662
3955
|
} catch (error) {
|
|
@@ -3963,22 +4256,6 @@ Pipeline Trace (strategy: ${trace.strategyName}, ${stepCount} steps, ${trace.tot
|
|
|
3963
4256
|
});
|
|
3964
4257
|
return cmd;
|
|
3965
4258
|
}
|
|
3966
|
-
function validateModuleId(moduleId) {
|
|
3967
|
-
if (moduleId.length > 192) {
|
|
3968
|
-
process.stderr.write(
|
|
3969
|
-
`Error: Invalid module ID format: '${moduleId}'. Maximum length is 192 characters.
|
|
3970
|
-
`
|
|
3971
|
-
);
|
|
3972
|
-
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3973
|
-
}
|
|
3974
|
-
if (!/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/.test(moduleId)) {
|
|
3975
|
-
process.stderr.write(
|
|
3976
|
-
`Error: Invalid module ID format: '${moduleId}'.
|
|
3977
|
-
`
|
|
3978
|
-
);
|
|
3979
|
-
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3980
|
-
}
|
|
3981
|
-
}
|
|
3982
4259
|
async function collectInput(stdinFlag, cliKwargs = {}, largeInput) {
|
|
3983
4260
|
const cliKwargsNonNull = {};
|
|
3984
4261
|
for (const [k, v] of Object.entries(cliKwargs)) {
|
|
@@ -3997,7 +4274,7 @@ async function collectInput(stdinFlag, cliKwargs = {}, largeInput) {
|
|
|
3997
4274
|
} else {
|
|
3998
4275
|
source = `file '${stdinFlag}'`;
|
|
3999
4276
|
try {
|
|
4000
|
-
raw =
|
|
4277
|
+
raw = readFileSync3(stdinFlag, "utf-8");
|
|
4001
4278
|
} catch (err) {
|
|
4002
4279
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4003
4280
|
process.stderr.write(`Error: Could not read input ${source}: ${msg}
|
|
@@ -4083,7 +4360,7 @@ import { Command as Command6 } from "commander";
|
|
|
4083
4360
|
init_logger();
|
|
4084
4361
|
init_errors();
|
|
4085
4362
|
function assertNotReserved(kind, name, moduleId) {
|
|
4086
|
-
if (!
|
|
4363
|
+
if (!getReservedGroupNames().has(name)) return;
|
|
4087
4364
|
let msg;
|
|
4088
4365
|
if (kind === "group") {
|
|
4089
4366
|
msg = `Error: Module '${moduleId}': display.cli.group '${name}' is reserved. Use a different CLI alias or set display.cli.group to another value.
|
|
@@ -4337,8 +4614,9 @@ var GroupedModuleGroup = class _GroupedModuleGroup extends LazyModuleGroup {
|
|
|
4337
4614
|
*/
|
|
4338
4615
|
listCommands() {
|
|
4339
4616
|
this.buildGroupMap();
|
|
4617
|
+
const reserved = getReservedGroupNames();
|
|
4340
4618
|
const groupNames = [...this.groupMap.keys()].filter(
|
|
4341
|
-
(g) => !
|
|
4619
|
+
(g) => !reserved.has(g)
|
|
4342
4620
|
);
|
|
4343
4621
|
const topNames = [...this.topLevelModules.keys()];
|
|
4344
4622
|
return [.../* @__PURE__ */ new Set([...groupNames, ...topNames])].sort();
|
|
@@ -4397,6 +4675,7 @@ init_logger();
|
|
|
4397
4675
|
init_security();
|
|
4398
4676
|
export {
|
|
4399
4677
|
ApcliGroup,
|
|
4678
|
+
ApcliGroupError,
|
|
4400
4679
|
ApprovalDeniedError,
|
|
4401
4680
|
ApprovalTimeoutError,
|
|
4402
4681
|
AuditLogger,
|
|
@@ -4423,10 +4702,10 @@ export {
|
|
|
4423
4702
|
collectInput,
|
|
4424
4703
|
configureManHelp,
|
|
4425
4704
|
createCli,
|
|
4426
|
-
emitErrorJson,
|
|
4427
|
-
emitErrorTty,
|
|
4428
4705
|
exitCodeForError,
|
|
4429
4706
|
formatExecResult,
|
|
4707
|
+
formatModuleDetail,
|
|
4708
|
+
formatModuleList,
|
|
4430
4709
|
getAuditLogger,
|
|
4431
4710
|
getLogLevel,
|
|
4432
4711
|
main,
|
|
@@ -4445,6 +4724,7 @@ export {
|
|
|
4445
4724
|
registerReloadCommand,
|
|
4446
4725
|
registerUsageCommand,
|
|
4447
4726
|
registerValidateCommand,
|
|
4727
|
+
resolveFormat,
|
|
4448
4728
|
resolveRefs,
|
|
4449
4729
|
schemaToCliOptions,
|
|
4450
4730
|
setAuditLogger,
|