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