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/bin/apcore-cli.js
CHANGED
|
@@ -157,6 +157,10 @@ __export(sandbox_exports, {
|
|
|
157
157
|
Sandbox: () => Sandbox,
|
|
158
158
|
runSandboxRunner: () => runSandboxRunner
|
|
159
159
|
});
|
|
160
|
+
import { spawn } from "child_process";
|
|
161
|
+
import { mkdtempSync, rmSync } from "fs";
|
|
162
|
+
import { tmpdir } from "os";
|
|
163
|
+
import { join, resolve as resolvePath } from "path";
|
|
160
164
|
async function runSandboxRunner(moduleId) {
|
|
161
165
|
const extensionsRoot = process.env.APCORE_EXTENSIONS_ROOT ?? "./extensions";
|
|
162
166
|
const apcore = await import("apcore-js").catch(() => {
|
|
@@ -205,7 +209,7 @@ function buildSandboxEnv(tmpDir) {
|
|
|
205
209
|
env.TMPDIR = tmpDir;
|
|
206
210
|
return env;
|
|
207
211
|
}
|
|
208
|
-
var SANDBOX_ALLOW_KEYS, SANDBOX_ALLOW_PREFIX, SANDBOX_DENY_PREFIX, SANDBOX_DENY_KEYS,
|
|
212
|
+
var SANDBOX_ALLOW_KEYS, SANDBOX_ALLOW_PREFIX, SANDBOX_DENY_PREFIX, SANDBOX_DENY_KEYS, SANDBOX_DEFAULT_OUTPUT_SIZE_LIMIT, Sandbox;
|
|
209
213
|
var init_sandbox = __esm({
|
|
210
214
|
"src/security/sandbox.ts"() {
|
|
211
215
|
"use strict";
|
|
@@ -215,14 +219,41 @@ var init_sandbox = __esm({
|
|
|
215
219
|
SANDBOX_ALLOW_PREFIX = "APCORE_";
|
|
216
220
|
SANDBOX_DENY_PREFIX = "APCORE_AUTH_";
|
|
217
221
|
SANDBOX_DENY_KEYS = ["APCORE_AUTH_API_KEY"];
|
|
218
|
-
|
|
222
|
+
SANDBOX_DEFAULT_OUTPUT_SIZE_LIMIT = 64 * 1024 * 1024;
|
|
219
223
|
Sandbox = class {
|
|
224
|
+
/** Default post-capture stdout+stderr byte budget for sandboxed children. */
|
|
225
|
+
static DEFAULT_MAX_OUTPUT_BYTES = SANDBOX_DEFAULT_OUTPUT_SIZE_LIMIT;
|
|
220
226
|
enabled;
|
|
221
227
|
timeoutSeconds;
|
|
228
|
+
extensionsRoot = null;
|
|
229
|
+
maxOutputBytes = SANDBOX_DEFAULT_OUTPUT_SIZE_LIMIT;
|
|
222
230
|
constructor(enabled = false, timeoutSeconds = 300) {
|
|
223
231
|
this.enabled = enabled;
|
|
224
232
|
this.timeoutSeconds = timeoutSeconds;
|
|
225
233
|
}
|
|
234
|
+
/**
|
|
235
|
+
* Set the extensions root that is forwarded to the sandboxed runner via
|
|
236
|
+
* `APCORE_EXTENSIONS_ROOT`. The path is resolved to absolute when injected
|
|
237
|
+
* so the child (whose cwd is the fresh sandbox tempdir) can locate modules.
|
|
238
|
+
*
|
|
239
|
+
* Builder-style — returns `this` so call sites can chain. Mirrors Python's
|
|
240
|
+
* `Sandbox.with_extensions_root` (D1-004 cross-SDK parity).
|
|
241
|
+
*/
|
|
242
|
+
withExtensionsRoot(extensionsRoot) {
|
|
243
|
+
this.extensionsRoot = extensionsRoot;
|
|
244
|
+
return this;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Cap the post-capture stdout+stderr byte budget for the sandboxed
|
|
248
|
+
* subprocess. Default: 64 MiB (`Sandbox.DEFAULT_MAX_OUTPUT_BYTES`).
|
|
249
|
+
*
|
|
250
|
+
* Builder-style — returns `this`. Mirrors Python's
|
|
251
|
+
* `Sandbox.with_max_output_bytes` (D1-004 cross-SDK parity).
|
|
252
|
+
*/
|
|
253
|
+
withMaxOutputBytes(maxOutputBytes) {
|
|
254
|
+
this.maxOutputBytes = maxOutputBytes;
|
|
255
|
+
return this;
|
|
256
|
+
}
|
|
226
257
|
/**
|
|
227
258
|
* Execute a module, optionally inside a sandboxed subprocess.
|
|
228
259
|
*/
|
|
@@ -233,12 +264,13 @@ var init_sandbox = __esm({
|
|
|
233
264
|
return this._sandboxedExecute(moduleId, inputData);
|
|
234
265
|
}
|
|
235
266
|
async _sandboxedExecute(moduleId, inputData) {
|
|
236
|
-
const
|
|
237
|
-
const { tmpdir } = await import("os");
|
|
238
|
-
const { join: join3 } = await import("path");
|
|
239
|
-
const { mkdtempSync, rmSync } = await import("fs");
|
|
240
|
-
const tmpDir = mkdtempSync(join3(tmpdir(), "apcore_sandbox_"));
|
|
267
|
+
const tmpDir = mkdtempSync(join(tmpdir(), "apcore_sandbox_"));
|
|
241
268
|
const env = buildSandboxEnv(tmpDir);
|
|
269
|
+
if (this.extensionsRoot !== null) {
|
|
270
|
+
env.APCORE_EXTENSIONS_ROOT = resolvePath(this.extensionsRoot);
|
|
271
|
+
} else if (env.APCORE_EXTENSIONS_ROOT) {
|
|
272
|
+
env.APCORE_EXTENSIONS_ROOT = resolvePath(env.APCORE_EXTENSIONS_ROOT);
|
|
273
|
+
}
|
|
242
274
|
const binaryPath = process.argv[1];
|
|
243
275
|
const child = spawn(process.execPath, [binaryPath, "--internal-sandbox-runner", moduleId], {
|
|
244
276
|
env,
|
|
@@ -247,11 +279,14 @@ var init_sandbox = __esm({
|
|
|
247
279
|
});
|
|
248
280
|
let stdout = "";
|
|
249
281
|
let stderr = "";
|
|
250
|
-
let
|
|
282
|
+
let stdoutBytes = 0;
|
|
283
|
+
let stderrBytes = 0;
|
|
251
284
|
let sizeExceeded = false;
|
|
285
|
+
const outputCap = this.maxOutputBytes;
|
|
252
286
|
child.stdout.on("data", (chunk) => {
|
|
253
|
-
|
|
254
|
-
|
|
287
|
+
if (sizeExceeded) return;
|
|
288
|
+
stdoutBytes += chunk.length;
|
|
289
|
+
if (stdoutBytes > outputCap) {
|
|
255
290
|
sizeExceeded = true;
|
|
256
291
|
child.kill("SIGKILL");
|
|
257
292
|
return;
|
|
@@ -259,6 +294,13 @@ var init_sandbox = __esm({
|
|
|
259
294
|
stdout += chunk.toString();
|
|
260
295
|
});
|
|
261
296
|
child.stderr.on("data", (chunk) => {
|
|
297
|
+
if (sizeExceeded) return;
|
|
298
|
+
stderrBytes += chunk.length;
|
|
299
|
+
if (stderrBytes > outputCap) {
|
|
300
|
+
sizeExceeded = true;
|
|
301
|
+
child.kill("SIGKILL");
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
262
304
|
stderr += chunk.toString();
|
|
263
305
|
});
|
|
264
306
|
child.stdin.write(JSON.stringify(inputData));
|
|
@@ -279,7 +321,10 @@ var init_sandbox = __esm({
|
|
|
279
321
|
} catch {
|
|
280
322
|
}
|
|
281
323
|
if (sizeExceeded) {
|
|
282
|
-
|
|
324
|
+
const limitMiB = Math.floor(outputCap / (1024 * 1024));
|
|
325
|
+
reject(new ModuleExecutionError(
|
|
326
|
+
`Sandbox module '${moduleId}' output exceeded ${limitMiB}MiB limit.`
|
|
327
|
+
));
|
|
283
328
|
return;
|
|
284
329
|
}
|
|
285
330
|
if (code !== 0) {
|
|
@@ -400,6 +445,10 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
400
445
|
properties: {},
|
|
401
446
|
required: []
|
|
402
447
|
};
|
|
448
|
+
if (typeof obj.properties === "object" && obj.properties !== null) {
|
|
449
|
+
Object.assign(merged.properties, obj.properties);
|
|
450
|
+
}
|
|
451
|
+
const siblingRequired = Array.isArray(obj.required) ? obj.required.slice() : [];
|
|
403
452
|
const allRequiredSets = [];
|
|
404
453
|
for (const subSchema of obj[keyword]) {
|
|
405
454
|
const resolved = resolveNode(
|
|
@@ -420,6 +469,7 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
420
469
|
allRequiredSets.push(new Set(resolved.required));
|
|
421
470
|
}
|
|
422
471
|
}
|
|
472
|
+
let branchRequired = [];
|
|
423
473
|
if (allRequiredSets.length > 0) {
|
|
424
474
|
let intersection = allRequiredSets[0];
|
|
425
475
|
for (let i = 1; i < allRequiredSets.length; i++) {
|
|
@@ -427,10 +477,17 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
427
477
|
[...intersection].filter((x) => allRequiredSets[i].has(x))
|
|
428
478
|
);
|
|
429
479
|
}
|
|
430
|
-
|
|
431
|
-
}
|
|
432
|
-
|
|
480
|
+
branchRequired = [...intersection];
|
|
481
|
+
}
|
|
482
|
+
const seen = /* @__PURE__ */ new Set();
|
|
483
|
+
const combinedRequired = [];
|
|
484
|
+
for (const r of [...siblingRequired, ...branchRequired]) {
|
|
485
|
+
if (!seen.has(r)) {
|
|
486
|
+
seen.add(r);
|
|
487
|
+
combinedRequired.push(r);
|
|
488
|
+
}
|
|
433
489
|
}
|
|
490
|
+
merged.required = combinedRequired;
|
|
434
491
|
for (const [k, v] of Object.entries(obj)) {
|
|
435
492
|
if (k !== keyword && !(k in merged)) {
|
|
436
493
|
merged[k] = v;
|
|
@@ -446,7 +503,7 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
446
503
|
propSchema,
|
|
447
504
|
defs,
|
|
448
505
|
visited,
|
|
449
|
-
depth
|
|
506
|
+
depth,
|
|
450
507
|
maxDepth,
|
|
451
508
|
moduleId
|
|
452
509
|
);
|
|
@@ -462,6 +519,30 @@ var init_ref_resolver = __esm({
|
|
|
462
519
|
}
|
|
463
520
|
});
|
|
464
521
|
|
|
522
|
+
// src/logger.ts
|
|
523
|
+
function setLogLevel(level) {
|
|
524
|
+
const upper = level.toUpperCase();
|
|
525
|
+
if (upper in LEVELS) {
|
|
526
|
+
currentLevel = upper;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
function shouldLog(level) {
|
|
530
|
+
return LEVELS[level] >= LEVELS[currentLevel];
|
|
531
|
+
}
|
|
532
|
+
function warn(message) {
|
|
533
|
+
if (shouldLog("WARNING")) process.stderr.write(`WARNING: ${message}
|
|
534
|
+
`);
|
|
535
|
+
}
|
|
536
|
+
var LEVELS, currentLevel;
|
|
537
|
+
var init_logger = __esm({
|
|
538
|
+
"src/logger.ts"() {
|
|
539
|
+
"use strict";
|
|
540
|
+
init_esm_shims();
|
|
541
|
+
LEVELS = { DEBUG: 0, INFO: 1, WARNING: 2, ERROR: 3 };
|
|
542
|
+
currentLevel = "WARNING";
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
|
|
465
546
|
// src/schema-parser.ts
|
|
466
547
|
function mapType(propName, propSchema) {
|
|
467
548
|
const schemaType = propSchema.type;
|
|
@@ -499,6 +580,13 @@ function schemaToCliOptions(schema, maxHelpLength = 1e3) {
|
|
|
499
580
|
const requiredList = schema.required ?? [];
|
|
500
581
|
const options = [];
|
|
501
582
|
const flagNames = {};
|
|
583
|
+
for (const reqName of requiredList) {
|
|
584
|
+
if (!(reqName in properties)) {
|
|
585
|
+
warn(
|
|
586
|
+
`Required property '${reqName}' not found in properties, skipping.`
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
502
590
|
for (const [propName, propSchema] of Object.entries(properties)) {
|
|
503
591
|
const flagName = "--" + propName.replace(/_/g, "-");
|
|
504
592
|
if (RESERVED_NAMES.has(propName)) {
|
|
@@ -506,14 +594,14 @@ function schemaToCliOptions(schema, maxHelpLength = 1e3) {
|
|
|
506
594
|
`Error: Module schema property '${propName}' conflicts with a reserved CLI option name. Rename the property.
|
|
507
595
|
`
|
|
508
596
|
);
|
|
509
|
-
process.exit(EXIT_CODES.
|
|
597
|
+
process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
|
|
510
598
|
}
|
|
511
599
|
if (flagName in flagNames) {
|
|
512
600
|
process.stderr.write(
|
|
513
601
|
`Error: Flag name collision: properties '${propName}' and '${flagNames[flagName]}' both map to '${flagName}'.
|
|
514
602
|
`
|
|
515
603
|
);
|
|
516
|
-
process.exit(EXIT_CODES.
|
|
604
|
+
process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
|
|
517
605
|
}
|
|
518
606
|
flagNames[flagName] = propName;
|
|
519
607
|
const typeResult = mapType(propName, propSchema);
|
|
@@ -529,7 +617,7 @@ function schemaToCliOptions(schema, maxHelpLength = 1e3) {
|
|
|
529
617
|
`Error: Flag name collision: boolean property '${propName}' auto-generates '${noFlag}' which is already used by property '${flagNames[noFlag]}'.
|
|
530
618
|
`
|
|
531
619
|
);
|
|
532
|
-
process.exit(EXIT_CODES.
|
|
620
|
+
process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
|
|
533
621
|
}
|
|
534
622
|
flagNames[noFlag] = propName;
|
|
535
623
|
const defaultVal = propSchema.default ?? false;
|
|
@@ -606,6 +694,7 @@ var init_schema_parser = __esm({
|
|
|
606
694
|
"use strict";
|
|
607
695
|
init_esm_shims();
|
|
608
696
|
init_errors();
|
|
697
|
+
init_logger();
|
|
609
698
|
BOOLEAN_FLAG = /* @__PURE__ */ Symbol("BOOLEAN_FLAG");
|
|
610
699
|
RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
611
700
|
"input",
|
|
@@ -763,6 +852,26 @@ var init_approval = __esm({
|
|
|
763
852
|
|
|
764
853
|
// src/output.ts
|
|
765
854
|
import yaml from "js-yaml";
|
|
855
|
+
function descriptorToScanned(m) {
|
|
856
|
+
const metadata = m.metadata ?? {};
|
|
857
|
+
const display = metadata["display"] ?? null;
|
|
858
|
+
return {
|
|
859
|
+
moduleId: m.id,
|
|
860
|
+
description: m.description ?? "",
|
|
861
|
+
inputSchema: m.inputSchema ?? {},
|
|
862
|
+
outputSchema: m.outputSchema ?? {},
|
|
863
|
+
tags: m.tags ?? [],
|
|
864
|
+
target: "",
|
|
865
|
+
version: "1.0.0",
|
|
866
|
+
annotations: m.annotations ?? null,
|
|
867
|
+
documentation: null,
|
|
868
|
+
suggestedAlias: null,
|
|
869
|
+
examples: [],
|
|
870
|
+
metadata,
|
|
871
|
+
display,
|
|
872
|
+
warnings: []
|
|
873
|
+
};
|
|
874
|
+
}
|
|
766
875
|
function csvCellString(value) {
|
|
767
876
|
if (value === null || value === void 0) return "";
|
|
768
877
|
if (typeof value === "object") return JSON.stringify(value);
|
|
@@ -791,7 +900,7 @@ function formatTable(headers, rows) {
|
|
|
791
900
|
);
|
|
792
901
|
return [headerLine, sep2, ...dataLines].join("\n") + "\n";
|
|
793
902
|
}
|
|
794
|
-
function formatModuleList(modules, format, filterTags, showDeps = false, exposureFilter) {
|
|
903
|
+
async function formatModuleList(modules, format, filterTags, showDeps = false, exposureFilter) {
|
|
795
904
|
if (format === "table") {
|
|
796
905
|
if (modules.length === 0 && filterTags && filterTags.length > 0) {
|
|
797
906
|
process.stdout.write(
|
|
@@ -836,6 +945,17 @@ function formatModuleList(modules, format, filterTags, showDeps = false, exposur
|
|
|
836
945
|
return entry;
|
|
837
946
|
});
|
|
838
947
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
948
|
+
} else if (format === "markdown" || format === "skill") {
|
|
949
|
+
let toolkit;
|
|
950
|
+
try {
|
|
951
|
+
toolkit = await import("apcore-toolkit");
|
|
952
|
+
} catch {
|
|
953
|
+
throw new Error(TOOLKIT_MISSING_HINT);
|
|
954
|
+
}
|
|
955
|
+
const scanned = modules.map(descriptorToScanned);
|
|
956
|
+
process.stdout.write(
|
|
957
|
+
toolkit.formatModules(scanned, { style: format, display: true }) + "\n"
|
|
958
|
+
);
|
|
839
959
|
}
|
|
840
960
|
}
|
|
841
961
|
function annotationsToDict(annotations) {
|
|
@@ -849,7 +969,7 @@ function annotationsToDict(annotations) {
|
|
|
849
969
|
}
|
|
850
970
|
return Object.keys(result).length > 0 ? result : null;
|
|
851
971
|
}
|
|
852
|
-
function formatModuleDetail(moduleDef, format) {
|
|
972
|
+
async function formatModuleDetail(moduleDef, format) {
|
|
853
973
|
if (format === "table") {
|
|
854
974
|
process.stdout.write(`
|
|
855
975
|
Module: ${moduleDef.id}
|
|
@@ -920,6 +1040,16 @@ Tags: ${tags.join(", ")}
|
|
|
920
1040
|
}
|
|
921
1041
|
}
|
|
922
1042
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
1043
|
+
} else if (format === "markdown" || format === "skill") {
|
|
1044
|
+
let toolkit;
|
|
1045
|
+
try {
|
|
1046
|
+
toolkit = await import("apcore-toolkit");
|
|
1047
|
+
} catch {
|
|
1048
|
+
throw new Error(TOOLKIT_MISSING_HINT);
|
|
1049
|
+
}
|
|
1050
|
+
process.stdout.write(
|
|
1051
|
+
toolkit.formatModule(descriptorToScanned(moduleDef), { style: format, display: true }) + "\n"
|
|
1052
|
+
);
|
|
923
1053
|
}
|
|
924
1054
|
}
|
|
925
1055
|
function selectFields(result, fields) {
|
|
@@ -1068,35 +1198,13 @@ function firstFailedExitCode(result) {
|
|
|
1068
1198
|
}
|
|
1069
1199
|
return EXIT_CODES.MODULE_EXECUTE_ERROR;
|
|
1070
1200
|
}
|
|
1201
|
+
var TOOLKIT_MISSING_HINT;
|
|
1071
1202
|
var init_output = __esm({
|
|
1072
1203
|
"src/output.ts"() {
|
|
1073
1204
|
"use strict";
|
|
1074
1205
|
init_esm_shims();
|
|
1075
1206
|
init_errors();
|
|
1076
|
-
|
|
1077
|
-
});
|
|
1078
|
-
|
|
1079
|
-
// src/logger.ts
|
|
1080
|
-
function setLogLevel(level) {
|
|
1081
|
-
const upper = level.toUpperCase();
|
|
1082
|
-
if (upper in LEVELS) {
|
|
1083
|
-
currentLevel = upper;
|
|
1084
|
-
}
|
|
1085
|
-
}
|
|
1086
|
-
function shouldLog(level) {
|
|
1087
|
-
return LEVELS[level] >= LEVELS[currentLevel];
|
|
1088
|
-
}
|
|
1089
|
-
function warn(message) {
|
|
1090
|
-
if (shouldLog("WARNING")) process.stderr.write(`WARNING: ${message}
|
|
1091
|
-
`);
|
|
1092
|
-
}
|
|
1093
|
-
var LEVELS, currentLevel;
|
|
1094
|
-
var init_logger = __esm({
|
|
1095
|
-
"src/logger.ts"() {
|
|
1096
|
-
"use strict";
|
|
1097
|
-
init_esm_shims();
|
|
1098
|
-
LEVELS = { DEBUG: 0, INFO: 1, WARNING: 2, ERROR: 3 };
|
|
1099
|
-
currentLevel = "WARNING";
|
|
1207
|
+
TOOLKIT_MISSING_HINT = "The 'markdown' and 'skill' output formats require the apcore-toolkit peer dependency. Install with: npm install apcore-toolkit@^0.6";
|
|
1100
1208
|
}
|
|
1101
1209
|
});
|
|
1102
1210
|
|
|
@@ -1853,8 +1961,8 @@ var init_audit = __esm({
|
|
|
1853
1961
|
);
|
|
1854
1962
|
logPath;
|
|
1855
1963
|
writeFailureWarned = false;
|
|
1856
|
-
constructor(
|
|
1857
|
-
this.logPath =
|
|
1964
|
+
constructor(path6) {
|
|
1965
|
+
this.logPath = path6 ?? _AuditLogger.DEFAULT_PATH;
|
|
1858
1966
|
this.ensureDirectory();
|
|
1859
1967
|
}
|
|
1860
1968
|
ensureDirectory() {
|
|
@@ -1900,16 +2008,112 @@ var init_audit = __esm({
|
|
|
1900
2008
|
try {
|
|
1901
2009
|
return os.userInfo().username;
|
|
1902
2010
|
} catch {
|
|
1903
|
-
return process.env.USER ?? process.env.USERNAME ?? "unknown";
|
|
2011
|
+
return process.env.USER ?? process.env.LOGNAME ?? process.env.USERNAME ?? "unknown";
|
|
1904
2012
|
}
|
|
1905
2013
|
}
|
|
1906
2014
|
};
|
|
1907
2015
|
}
|
|
1908
2016
|
});
|
|
1909
2017
|
|
|
2018
|
+
// src/system-usage.ts
|
|
2019
|
+
import * as fs4 from "fs";
|
|
2020
|
+
import * as os2 from "os";
|
|
2021
|
+
import * as path4 from "path";
|
|
2022
|
+
function computeSummary(options = {}) {
|
|
2023
|
+
const auditPath = options.auditPath ?? DEFAULT_AUDIT_PATH;
|
|
2024
|
+
const period = options.period ?? "24h";
|
|
2025
|
+
const cutoff = (options.now ?? /* @__PURE__ */ new Date()).getTime() - PERIOD_TO_MS[period];
|
|
2026
|
+
if (!fs4.existsSync(auditPath)) {
|
|
2027
|
+
return /* @__PURE__ */ new Map();
|
|
2028
|
+
}
|
|
2029
|
+
let raw;
|
|
2030
|
+
try {
|
|
2031
|
+
raw = fs4.readFileSync(auditPath, "utf-8");
|
|
2032
|
+
} catch {
|
|
2033
|
+
return /* @__PURE__ */ new Map();
|
|
2034
|
+
}
|
|
2035
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2036
|
+
const errors = /* @__PURE__ */ new Map();
|
|
2037
|
+
const latencySum = /* @__PURE__ */ new Map();
|
|
2038
|
+
for (const line of raw.split("\n")) {
|
|
2039
|
+
const trimmed = line.trim();
|
|
2040
|
+
if (!trimmed) continue;
|
|
2041
|
+
let entry;
|
|
2042
|
+
try {
|
|
2043
|
+
entry = JSON.parse(trimmed);
|
|
2044
|
+
} catch {
|
|
2045
|
+
continue;
|
|
2046
|
+
}
|
|
2047
|
+
const ts = typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
|
|
2048
|
+
if (Number.isNaN(ts) || ts < cutoff) continue;
|
|
2049
|
+
const moduleId = typeof entry.module_id === "string" ? entry.module_id : null;
|
|
2050
|
+
if (!moduleId) continue;
|
|
2051
|
+
counts.set(moduleId, (counts.get(moduleId) ?? 0) + 1);
|
|
2052
|
+
if (entry.status === "error") {
|
|
2053
|
+
errors.set(moduleId, (errors.get(moduleId) ?? 0) + 1);
|
|
2054
|
+
}
|
|
2055
|
+
const duration = entry.duration_ms;
|
|
2056
|
+
if (typeof duration === "number") {
|
|
2057
|
+
latencySum.set(moduleId, (latencySum.get(moduleId) ?? 0) + duration);
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
const out = /* @__PURE__ */ new Map();
|
|
2061
|
+
for (const [id, calls] of counts) {
|
|
2062
|
+
out.set(id, {
|
|
2063
|
+
module_id: id,
|
|
2064
|
+
calls,
|
|
2065
|
+
errors: errors.get(id) ?? 0,
|
|
2066
|
+
latency_ms: calls > 0 ? (latencySum.get(id) ?? 0) / calls : 0
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
return out;
|
|
2070
|
+
}
|
|
2071
|
+
function sortModulesByUsage(modules, field, options = {}) {
|
|
2072
|
+
const reverse = options.reverse ?? true;
|
|
2073
|
+
const summary = computeSummary({
|
|
2074
|
+
auditPath: options.auditPath,
|
|
2075
|
+
period: options.period
|
|
2076
|
+
});
|
|
2077
|
+
if (summary.size === 0) {
|
|
2078
|
+
modules.sort((a, b) => (a.id ?? a.module_id ?? "").localeCompare(b.id ?? b.module_id ?? ""));
|
|
2079
|
+
if (reverse) modules.reverse();
|
|
2080
|
+
return { used: false };
|
|
2081
|
+
}
|
|
2082
|
+
const key = (m) => {
|
|
2083
|
+
const id = m.id ?? m.module_id ?? "";
|
|
2084
|
+
const s = summary.get(id);
|
|
2085
|
+
if (!s) return 0;
|
|
2086
|
+
return field === "latency" ? s.latency_ms : field === "calls" ? s.calls : s.errors;
|
|
2087
|
+
};
|
|
2088
|
+
modules.sort((a, b) => {
|
|
2089
|
+
const diff = key(a) - key(b);
|
|
2090
|
+
if (diff !== 0) return reverse ? -diff : diff;
|
|
2091
|
+
return (a.id ?? a.module_id ?? "").localeCompare(b.id ?? b.module_id ?? "");
|
|
2092
|
+
});
|
|
2093
|
+
return { used: true };
|
|
2094
|
+
}
|
|
2095
|
+
var PERIOD_TO_MS, DEFAULT_AUDIT_PATH;
|
|
2096
|
+
var init_system_usage = __esm({
|
|
2097
|
+
"src/system-usage.ts"() {
|
|
2098
|
+
"use strict";
|
|
2099
|
+
init_esm_shims();
|
|
2100
|
+
PERIOD_TO_MS = {
|
|
2101
|
+
"1h": 60 * 60 * 1e3,
|
|
2102
|
+
"24h": 24 * 60 * 60 * 1e3,
|
|
2103
|
+
"7d": 7 * 24 * 60 * 60 * 1e3,
|
|
2104
|
+
"30d": 30 * 24 * 60 * 60 * 1e3
|
|
2105
|
+
};
|
|
2106
|
+
DEFAULT_AUDIT_PATH = path4.join(
|
|
2107
|
+
os2.homedir(),
|
|
2108
|
+
".apcore-cli",
|
|
2109
|
+
"audit.jsonl"
|
|
2110
|
+
);
|
|
2111
|
+
}
|
|
2112
|
+
});
|
|
2113
|
+
|
|
1910
2114
|
// src/security/config-encryptor.ts
|
|
1911
2115
|
import * as crypto2 from "crypto";
|
|
1912
|
-
import * as
|
|
2116
|
+
import * as os3 from "os";
|
|
1913
2117
|
async function getKeytar() {
|
|
1914
2118
|
if (keytarModule) return keytarModule;
|
|
1915
2119
|
try {
|
|
@@ -2038,7 +2242,7 @@ var init_config_encryptor = __esm({
|
|
|
2038
2242
|
);
|
|
2039
2243
|
_ConfigEncryptor.weakFallbackWarned = true;
|
|
2040
2244
|
}
|
|
2041
|
-
const hostname2 =
|
|
2245
|
+
const hostname2 = os3.hostname();
|
|
2042
2246
|
const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
|
|
2043
2247
|
const material = `${hostname2}:${username}`;
|
|
2044
2248
|
return crypto2.pbkdf2Sync(material, salt, PBKDF2_ITERATIONS, 32, "sha256");
|
|
@@ -2070,7 +2274,7 @@ var init_config_encryptor = __esm({
|
|
|
2070
2274
|
const nonce = data.subarray(0, 12);
|
|
2071
2275
|
const tag = data.subarray(12, 28);
|
|
2072
2276
|
const ct = data.subarray(28);
|
|
2073
|
-
const hostname2 =
|
|
2277
|
+
const hostname2 = os3.hostname();
|
|
2074
2278
|
const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
|
|
2075
2279
|
const passphrase = process.env.APCORE_CLI_CONFIG_PASSPHRASE;
|
|
2076
2280
|
const materials = passphrase ? [passphrase, `${hostname2}:${username}`] : [`${hostname2}:${username}`];
|
|
@@ -2230,7 +2434,9 @@ function getAnnotationFlag(moduleDef, flag) {
|
|
|
2230
2434
|
return ann[attr] === true;
|
|
2231
2435
|
}
|
|
2232
2436
|
function registerListCommand(apcliGroup, registry, exposureFilter) {
|
|
2233
|
-
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).
|
|
2437
|
+
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(
|
|
2438
|
+
new Option2("--format <format>", "Output format.").choices(["table", "json", "csv", "yaml", "jsonl", "markdown", "skill"])
|
|
2439
|
+
).option("-s, --search <query>", "Filter by substring match on ID and description.").addOption(
|
|
2234
2440
|
new Option2("--status <status>", "Filter by module status.").choices(["enabled", "disabled", "all"]).default("enabled")
|
|
2235
2441
|
).option("-a, --annotation <flag>", "Filter by annotation flag (AND logic). Repeatable.", collectAnnotation, []).addOption(
|
|
2236
2442
|
new Option2("--sort <field>", "Sort order.").choices(["id", "calls", "errors", "latency"]).default("id")
|
|
@@ -2280,14 +2486,18 @@ function registerListCommand(apcliGroup, registry, exposureFilter) {
|
|
|
2280
2486
|
}
|
|
2281
2487
|
}
|
|
2282
2488
|
if (opts.sort === "calls" || opts.sort === "errors" || opts.sort === "latency") {
|
|
2283
|
-
|
|
2284
|
-
|
|
2489
|
+
const { used } = sortModulesByUsage(modules, opts.sort, { reverse: !opts.reverse });
|
|
2490
|
+
if (!used) {
|
|
2491
|
+
process.stderr.write(
|
|
2492
|
+
`note: no usage data available for --sort ${opts.sort}; sorted by id. Run some modules first to populate ~/.apcore-cli/audit.jsonl.
|
|
2285
2493
|
`
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2494
|
+
);
|
|
2495
|
+
}
|
|
2496
|
+
} else {
|
|
2497
|
+
modules.sort((a, b) => (a.id ?? "").localeCompare(b.id ?? ""));
|
|
2498
|
+
if (opts.reverse) {
|
|
2499
|
+
modules.reverse();
|
|
2500
|
+
}
|
|
2291
2501
|
}
|
|
2292
2502
|
let showExposureCol = false;
|
|
2293
2503
|
if (exposureFilter && opts.exposure !== "all") {
|
|
@@ -2302,12 +2512,14 @@ function registerListCommand(apcliGroup, registry, exposureFilter) {
|
|
|
2302
2512
|
}
|
|
2303
2513
|
const fmt = resolveFormat(opts.format);
|
|
2304
2514
|
const filterTagsArg = opts.tag.length > 0 ? opts.tag : void 0;
|
|
2305
|
-
formatModuleList(modules, fmt, filterTagsArg, opts.deps, showExposureCol ? exposureFilter : void 0);
|
|
2515
|
+
void formatModuleList(modules, fmt, filterTagsArg, opts.deps, showExposureCol ? exposureFilter : void 0);
|
|
2306
2516
|
});
|
|
2307
2517
|
apcliGroup.addCommand(listCmd);
|
|
2308
2518
|
}
|
|
2309
2519
|
function registerDescribeCommand(apcliGroup, registry) {
|
|
2310
|
-
const describeCmd = new Command2("describe").description("Show metadata, schema, and annotations for a module.").argument("<module-id>", "Module ID to describe").
|
|
2520
|
+
const describeCmd = new Command2("describe").description("Show metadata, schema, and annotations for a module.").argument("<module-id>", "Module ID to describe").addOption(
|
|
2521
|
+
new Option2("--format <format>", "Output format.").choices(["table", "json", "csv", "yaml", "jsonl", "markdown", "skill"])
|
|
2522
|
+
).action((moduleId, opts) => {
|
|
2311
2523
|
validateModuleId(moduleId);
|
|
2312
2524
|
const moduleDef = registry.getModule(moduleId);
|
|
2313
2525
|
if (!moduleDef) {
|
|
@@ -2318,7 +2530,7 @@ function registerDescribeCommand(apcliGroup, registry) {
|
|
|
2318
2530
|
process.exit(EXIT_CODES.MODULE_NOT_FOUND);
|
|
2319
2531
|
}
|
|
2320
2532
|
const fmt = resolveFormat(opts.format);
|
|
2321
|
-
formatModuleDetail(moduleDef, fmt);
|
|
2533
|
+
void formatModuleDetail(moduleDef, fmt);
|
|
2322
2534
|
});
|
|
2323
2535
|
apcliGroup.addCommand(describeCmd);
|
|
2324
2536
|
}
|
|
@@ -2445,6 +2657,7 @@ var init_discovery = __esm({
|
|
|
2445
2657
|
init_main();
|
|
2446
2658
|
init_output();
|
|
2447
2659
|
init_audit();
|
|
2660
|
+
init_system_usage();
|
|
2448
2661
|
TAG_PATTERN = /^[a-z][a-z0-9_-]*$/;
|
|
2449
2662
|
}
|
|
2450
2663
|
});
|
|
@@ -2469,6 +2682,15 @@ function emitErrorAndExit(e) {
|
|
|
2469
2682
|
`);
|
|
2470
2683
|
process.exit(exitCodeForError(e));
|
|
2471
2684
|
}
|
|
2685
|
+
async function requireApprovalForSystemCommand(moduleId, autoApprove) {
|
|
2686
|
+
const syntheticModuleDef = {
|
|
2687
|
+
id: moduleId,
|
|
2688
|
+
name: moduleId,
|
|
2689
|
+
description: `system command: ${moduleId}`,
|
|
2690
|
+
annotations: { requires_approval: true }
|
|
2691
|
+
};
|
|
2692
|
+
await checkApproval(syntheticModuleDef, autoApprove, void 0);
|
|
2693
|
+
}
|
|
2472
2694
|
function formatHealthSummaryTty(result) {
|
|
2473
2695
|
const summary = result.summary ?? {};
|
|
2474
2696
|
const modules = result.modules ?? [];
|
|
@@ -2609,9 +2831,10 @@ function registerUsageCommand(apcliGroup, executor) {
|
|
|
2609
2831
|
apcliGroup.addCommand(usageCmd);
|
|
2610
2832
|
}
|
|
2611
2833
|
function registerEnableCommand(apcliGroup, executor) {
|
|
2612
|
-
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", "
|
|
2834
|
+
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) => {
|
|
2613
2835
|
const fmt = resolveFormat(opts.format);
|
|
2614
2836
|
try {
|
|
2837
|
+
await requireApprovalForSystemCommand("system.control.toggle_feature", opts.yes);
|
|
2615
2838
|
const result = await callSystemModule(executor, "system.control.toggle_feature", {
|
|
2616
2839
|
module_id: moduleId,
|
|
2617
2840
|
enabled: true,
|
|
@@ -2629,9 +2852,10 @@ function registerEnableCommand(apcliGroup, executor) {
|
|
|
2629
2852
|
apcliGroup.addCommand(enableCmd);
|
|
2630
2853
|
}
|
|
2631
2854
|
function registerDisableCommand(apcliGroup, executor) {
|
|
2632
|
-
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", "
|
|
2855
|
+
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) => {
|
|
2633
2856
|
const fmt = resolveFormat(opts.format);
|
|
2634
2857
|
try {
|
|
2858
|
+
await requireApprovalForSystemCommand("system.control.toggle_feature", opts.yes);
|
|
2635
2859
|
const result = await callSystemModule(executor, "system.control.toggle_feature", {
|
|
2636
2860
|
module_id: moduleId,
|
|
2637
2861
|
enabled: false,
|
|
@@ -2649,9 +2873,10 @@ function registerDisableCommand(apcliGroup, executor) {
|
|
|
2649
2873
|
apcliGroup.addCommand(disableCmd);
|
|
2650
2874
|
}
|
|
2651
2875
|
function registerReloadCommand(apcliGroup, executor) {
|
|
2652
|
-
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", "
|
|
2876
|
+
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) => {
|
|
2653
2877
|
const fmt = resolveFormat(opts.format);
|
|
2654
2878
|
try {
|
|
2879
|
+
await requireApprovalForSystemCommand("system.control.reload_module", opts.yes);
|
|
2655
2880
|
const result = await callSystemModule(executor, "system.control.reload_module", {
|
|
2656
2881
|
module_id: moduleId,
|
|
2657
2882
|
reason: opts.reason
|
|
@@ -2689,7 +2914,7 @@ function registerConfigCommand(apcliGroup, executor) {
|
|
|
2689
2914
|
}
|
|
2690
2915
|
});
|
|
2691
2916
|
configGroup.addCommand(configGetCmd);
|
|
2692
|
-
const configSetCmd = new Command3("set").description("Update a runtime configuration value (audit-logged;
|
|
2917
|
+
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) => {
|
|
2693
2918
|
const fmt = resolveFormat(opts.format);
|
|
2694
2919
|
let parsedValue;
|
|
2695
2920
|
try {
|
|
@@ -2698,6 +2923,7 @@ function registerConfigCommand(apcliGroup, executor) {
|
|
|
2698
2923
|
parsedValue = value;
|
|
2699
2924
|
}
|
|
2700
2925
|
try {
|
|
2926
|
+
await requireApprovalForSystemCommand("system.control.update_config", opts.yes);
|
|
2701
2927
|
const result = await callSystemModule(executor, "system.control.update_config", {
|
|
2702
2928
|
key,
|
|
2703
2929
|
value: parsedValue,
|
|
@@ -2724,6 +2950,7 @@ var init_system_cmd = __esm({
|
|
|
2724
2950
|
"src/system-cmd.ts"() {
|
|
2725
2951
|
"use strict";
|
|
2726
2952
|
init_esm_shims();
|
|
2953
|
+
init_approval();
|
|
2727
2954
|
init_errors();
|
|
2728
2955
|
init_output();
|
|
2729
2956
|
}
|
|
@@ -2905,14 +3132,33 @@ var init_strategy = __esm({
|
|
|
2905
3132
|
});
|
|
2906
3133
|
|
|
2907
3134
|
// src/builtin-group.ts
|
|
2908
|
-
|
|
3135
|
+
function setReservedGroupNames(names) {
|
|
3136
|
+
_effectiveReservedNames = names;
|
|
3137
|
+
}
|
|
3138
|
+
function _validateBuiltinGroupName(name) {
|
|
3139
|
+
if (!name || !_NAME_REGEX.test(name)) {
|
|
3140
|
+
throw new ApcliGroupError(
|
|
3141
|
+
`builtinGroupName ${JSON.stringify(name)} must match /^[a-z][a-z0-9_-]*$/ (non-empty, lowercase, alphanumeric + '_' / '-', leading letter).`
|
|
3142
|
+
);
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
var ApcliGroupError, DEFAULT_BUILTIN_GROUP_NAME, RESERVED_GROUP_NAMES, _effectiveReservedNames, _NAME_REGEX, VALID_USER_MODES, APCLI_SUBCOMMAND_NAMES, ApcliGroup;
|
|
2909
3146
|
var init_builtin_group = __esm({
|
|
2910
3147
|
"src/builtin-group.ts"() {
|
|
2911
3148
|
"use strict";
|
|
2912
3149
|
init_esm_shims();
|
|
2913
3150
|
init_errors();
|
|
2914
3151
|
init_logger();
|
|
2915
|
-
|
|
3152
|
+
ApcliGroupError = class extends Error {
|
|
3153
|
+
constructor(message) {
|
|
3154
|
+
super(message);
|
|
3155
|
+
this.name = "ApcliGroupError";
|
|
3156
|
+
}
|
|
3157
|
+
};
|
|
3158
|
+
DEFAULT_BUILTIN_GROUP_NAME = "apcli";
|
|
3159
|
+
RESERVED_GROUP_NAMES = /* @__PURE__ */ new Set([DEFAULT_BUILTIN_GROUP_NAME]);
|
|
3160
|
+
_effectiveReservedNames = RESERVED_GROUP_NAMES;
|
|
3161
|
+
_NAME_REGEX = /^[a-z][a-z0-9_-]*$/;
|
|
2916
3162
|
VALID_USER_MODES = /* @__PURE__ */ new Set([
|
|
2917
3163
|
"all",
|
|
2918
3164
|
"none",
|
|
@@ -2941,6 +3187,7 @@ var init_builtin_group = __esm({
|
|
|
2941
3187
|
_disableEnv;
|
|
2942
3188
|
_registryInjected;
|
|
2943
3189
|
_fromCliConfig;
|
|
3190
|
+
_name;
|
|
2944
3191
|
constructor(init) {
|
|
2945
3192
|
this._mode = init.mode;
|
|
2946
3193
|
this._include = init.include;
|
|
@@ -2948,6 +3195,16 @@ var init_builtin_group = __esm({
|
|
|
2948
3195
|
this._disableEnv = init.disableEnv;
|
|
2949
3196
|
this._registryInjected = init.registryInjected;
|
|
2950
3197
|
this._fromCliConfig = init.fromCliConfig;
|
|
3198
|
+
this._name = init.name;
|
|
3199
|
+
}
|
|
3200
|
+
/**
|
|
3201
|
+
* Resolved name for the built-in command group (default `"apcli"`).
|
|
3202
|
+
* Overridable via createCli's `builtinGroupName` option for downstream
|
|
3203
|
+
* branded CLIs that want a custom namespace. Cross-SDK parity with
|
|
3204
|
+
* Python `ApcliGroup.name` (2026-05-08).
|
|
3205
|
+
*/
|
|
3206
|
+
get name() {
|
|
3207
|
+
return this._name;
|
|
2951
3208
|
}
|
|
2952
3209
|
/**
|
|
2953
3210
|
* Tier 1 constructor — config came from `createCli({ apcli })`.
|
|
@@ -2968,6 +3225,18 @@ var init_builtin_group = __esm({
|
|
|
2968
3225
|
* Env var (Tier 2) may override the yaml-supplied mode.
|
|
2969
3226
|
*/
|
|
2970
3227
|
static fromYaml(config, opts) {
|
|
3228
|
+
if (config !== null && config !== void 0 && typeof config !== "boolean" && (typeof config !== "object" || Array.isArray(config))) {
|
|
3229
|
+
const got = Array.isArray(config) ? "array" : typeof config;
|
|
3230
|
+
warn(
|
|
3231
|
+
`apcore.yaml apcli has unexpected type ${got}; using auto-detect.`
|
|
3232
|
+
);
|
|
3233
|
+
return _ApcliGroup._build(
|
|
3234
|
+
void 0,
|
|
3235
|
+
opts,
|
|
3236
|
+
/*fromCliConfig*/
|
|
3237
|
+
false
|
|
3238
|
+
);
|
|
3239
|
+
}
|
|
2971
3240
|
return _ApcliGroup._build(
|
|
2972
3241
|
config,
|
|
2973
3242
|
opts,
|
|
@@ -2981,8 +3250,12 @@ var init_builtin_group = __esm({
|
|
|
2981
3250
|
* Use this in programmatic contexts where throwing/exiting is unwanted.
|
|
2982
3251
|
*/
|
|
2983
3252
|
static tryFromYaml(config, opts) {
|
|
2984
|
-
if (config !== null && config !== void 0 && typeof config !== "boolean" && typeof config !== "object") {
|
|
2985
|
-
|
|
3253
|
+
if (config !== null && config !== void 0 && typeof config !== "boolean" && (typeof config !== "object" || Array.isArray(config))) {
|
|
3254
|
+
const got = Array.isArray(config) ? "array" : typeof config;
|
|
3255
|
+
return [
|
|
3256
|
+
null,
|
|
3257
|
+
`apcore.yaml 'apcli:' must be a bool, object, or null; got ${got}`
|
|
3258
|
+
];
|
|
2986
3259
|
}
|
|
2987
3260
|
if (config !== null && config !== void 0 && typeof config === "object" && !Array.isArray(config)) {
|
|
2988
3261
|
const mode = config["mode"];
|
|
@@ -2999,6 +3272,8 @@ var init_builtin_group = __esm({
|
|
|
2999
3272
|
// Internal builder — shared by both factories
|
|
3000
3273
|
// -------------------------------------------------------------------------
|
|
3001
3274
|
static _build(config, opts, fromCliConfig) {
|
|
3275
|
+
const name = opts.name ?? DEFAULT_BUILTIN_GROUP_NAME;
|
|
3276
|
+
_validateBuiltinGroupName(name);
|
|
3002
3277
|
if (config === true) {
|
|
3003
3278
|
return new _ApcliGroup({
|
|
3004
3279
|
mode: "all",
|
|
@@ -3006,7 +3281,8 @@ var init_builtin_group = __esm({
|
|
|
3006
3281
|
exclude: [],
|
|
3007
3282
|
disableEnv: false,
|
|
3008
3283
|
registryInjected: opts.registryInjected,
|
|
3009
|
-
fromCliConfig
|
|
3284
|
+
fromCliConfig,
|
|
3285
|
+
name
|
|
3010
3286
|
});
|
|
3011
3287
|
}
|
|
3012
3288
|
if (config === false) {
|
|
@@ -3016,7 +3292,8 @@ var init_builtin_group = __esm({
|
|
|
3016
3292
|
exclude: [],
|
|
3017
3293
|
disableEnv: false,
|
|
3018
3294
|
registryInjected: opts.registryInjected,
|
|
3019
|
-
fromCliConfig
|
|
3295
|
+
fromCliConfig,
|
|
3296
|
+
name
|
|
3020
3297
|
});
|
|
3021
3298
|
}
|
|
3022
3299
|
if (config === void 0 || config === null) {
|
|
@@ -3026,7 +3303,8 @@ var init_builtin_group = __esm({
|
|
|
3026
3303
|
exclude: [],
|
|
3027
3304
|
disableEnv: false,
|
|
3028
3305
|
registryInjected: opts.registryInjected,
|
|
3029
|
-
fromCliConfig
|
|
3306
|
+
fromCliConfig,
|
|
3307
|
+
name
|
|
3030
3308
|
});
|
|
3031
3309
|
}
|
|
3032
3310
|
if (typeof config !== "object" || Array.isArray(config)) {
|
|
@@ -3074,7 +3352,8 @@ var init_builtin_group = __esm({
|
|
|
3074
3352
|
exclude,
|
|
3075
3353
|
disableEnv,
|
|
3076
3354
|
registryInjected: opts.registryInjected,
|
|
3077
|
-
fromCliConfig
|
|
3355
|
+
fromCliConfig,
|
|
3356
|
+
name
|
|
3078
3357
|
});
|
|
3079
3358
|
}
|
|
3080
3359
|
/**
|
|
@@ -3167,7 +3446,8 @@ var init_builtin_group = __esm({
|
|
|
3167
3446
|
*/
|
|
3168
3447
|
_parseEnv(raw) {
|
|
3169
3448
|
if (raw === void 0 || raw === "") return null;
|
|
3170
|
-
const normalized = raw.toLowerCase();
|
|
3449
|
+
const normalized = raw.trim().toLowerCase();
|
|
3450
|
+
if (normalized === "") return null;
|
|
3171
3451
|
if (normalized === "show" || normalized === "1" || normalized === "true") {
|
|
3172
3452
|
return "all";
|
|
3173
3453
|
}
|
|
@@ -3376,6 +3656,34 @@ var init_canonical_help = __esm({
|
|
|
3376
3656
|
}
|
|
3377
3657
|
});
|
|
3378
3658
|
|
|
3659
|
+
// src/validate.ts
|
|
3660
|
+
function validateModuleId(moduleId) {
|
|
3661
|
+
if (moduleId.length > MAX_MODULE_ID_LENGTH) {
|
|
3662
|
+
process.stderr.write(
|
|
3663
|
+
`Error: Invalid module ID format: '${moduleId}'. Maximum length is ${MAX_MODULE_ID_LENGTH} characters.
|
|
3664
|
+
`
|
|
3665
|
+
);
|
|
3666
|
+
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3667
|
+
}
|
|
3668
|
+
if (!MODULE_ID_PATTERN.test(moduleId)) {
|
|
3669
|
+
process.stderr.write(
|
|
3670
|
+
`Error: Invalid module ID format: '${moduleId}'.
|
|
3671
|
+
`
|
|
3672
|
+
);
|
|
3673
|
+
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
var MODULE_ID_PATTERN, MAX_MODULE_ID_LENGTH;
|
|
3677
|
+
var init_validate = __esm({
|
|
3678
|
+
"src/validate.ts"() {
|
|
3679
|
+
"use strict";
|
|
3680
|
+
init_esm_shims();
|
|
3681
|
+
init_errors();
|
|
3682
|
+
MODULE_ID_PATTERN = /^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/;
|
|
3683
|
+
MAX_MODULE_ID_LENGTH = 192;
|
|
3684
|
+
}
|
|
3685
|
+
});
|
|
3686
|
+
|
|
3379
3687
|
// src/main.ts
|
|
3380
3688
|
var main_exports = {};
|
|
3381
3689
|
__export(main_exports, {
|
|
@@ -3384,9 +3692,6 @@ __export(main_exports, {
|
|
|
3384
3692
|
clearBindingDisplayMap: () => clearBindingDisplayMap,
|
|
3385
3693
|
collectInput: () => collectInput,
|
|
3386
3694
|
createCli: () => createCli,
|
|
3387
|
-
docsUrl: () => docsUrl,
|
|
3388
|
-
emitErrorJson: () => emitErrorJson,
|
|
3389
|
-
emitErrorTty: () => emitErrorTty,
|
|
3390
3695
|
lookupBindingDisplay: () => lookupBindingDisplay,
|
|
3391
3696
|
main: () => main,
|
|
3392
3697
|
reconvertEnumValues: () => reconvertEnumValues,
|
|
@@ -3394,12 +3699,11 @@ __export(main_exports, {
|
|
|
3394
3699
|
resolveStringOption: () => resolveStringOption,
|
|
3395
3700
|
setDocsUrl: () => setDocsUrl,
|
|
3396
3701
|
setVerboseHelp: () => setVerboseHelp,
|
|
3397
|
-
validateModuleId: () => validateModuleId
|
|
3398
|
-
verboseHelp: () => verboseHelp
|
|
3702
|
+
validateModuleId: () => validateModuleId
|
|
3399
3703
|
});
|
|
3400
|
-
import { readFileSync as
|
|
3704
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
3401
3705
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3402
|
-
import * as
|
|
3706
|
+
import * as path5 from "path";
|
|
3403
3707
|
import { Command as Command5, CommanderError, Option as Option4 } from "commander";
|
|
3404
3708
|
function setVerboseHelp(verbose) {
|
|
3405
3709
|
verboseHelp = verbose;
|
|
@@ -3491,6 +3795,10 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3491
3795
|
let app;
|
|
3492
3796
|
let expose;
|
|
3493
3797
|
let apcliOption;
|
|
3798
|
+
let appVersion;
|
|
3799
|
+
let appDescription;
|
|
3800
|
+
let allowedPrefixes;
|
|
3801
|
+
let builtinGroupName;
|
|
3494
3802
|
if (typeof extensionsDirOrOpts === "object" && extensionsDirOrOpts !== null) {
|
|
3495
3803
|
extensionsDir = extensionsDirOrOpts.extensionsDir;
|
|
3496
3804
|
progName = extensionsDirOrOpts.progName ?? progName;
|
|
@@ -3501,6 +3809,10 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3501
3809
|
extraCommands = extensionsDirOrOpts.extraCommands;
|
|
3502
3810
|
expose = extensionsDirOrOpts.expose;
|
|
3503
3811
|
apcliOption = extensionsDirOrOpts.apcli;
|
|
3812
|
+
appVersion = extensionsDirOrOpts.version;
|
|
3813
|
+
appDescription = extensionsDirOrOpts.description;
|
|
3814
|
+
builtinGroupName = extensionsDirOrOpts.builtinGroupName;
|
|
3815
|
+
allowedPrefixes = extensionsDirOrOpts.allowedPrefixes;
|
|
3504
3816
|
} else {
|
|
3505
3817
|
extensionsDir = extensionsDirOrOpts;
|
|
3506
3818
|
}
|
|
@@ -3511,7 +3823,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3511
3823
|
setAuditLogger(auditLogger);
|
|
3512
3824
|
} catch {
|
|
3513
3825
|
}
|
|
3514
|
-
const resolvedProgName = progName ??
|
|
3826
|
+
const resolvedProgName = progName ?? path5.basename(process.argv[1] ?? "apcore-cli") ?? "apcore-cli";
|
|
3515
3827
|
const cliLogLevel = process.env.APCORE_CLI_LOGGING_LEVEL ?? process.env.APCORE_LOGGING_LEVEL ?? "WARNING";
|
|
3516
3828
|
setLogLevel(cliLogLevel);
|
|
3517
3829
|
if (app && (registry || executor)) {
|
|
@@ -3537,7 +3849,10 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3537
3849
|
}
|
|
3538
3850
|
}
|
|
3539
3851
|
const registryInjected = registry !== void 0;
|
|
3540
|
-
const program = new Command5(resolvedProgName).exitOverride().
|
|
3852
|
+
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)");
|
|
3853
|
+
if (appVersion) {
|
|
3854
|
+
program.version(appVersion, "-V, --version", "Print version");
|
|
3855
|
+
}
|
|
3541
3856
|
program.configureHelp({ formatHelp: canonicalFormatHelp });
|
|
3542
3857
|
if (!registryInjected) {
|
|
3543
3858
|
program.option("--extensions-dir <path>", "Path to extensions directory");
|
|
@@ -3545,21 +3860,39 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3545
3860
|
program.option("--binding <path>", "Path to binding.yaml for display overlay");
|
|
3546
3861
|
}
|
|
3547
3862
|
let apcliCfg;
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3863
|
+
try {
|
|
3864
|
+
if (apcliOption instanceof ApcliGroup) {
|
|
3865
|
+
if (builtinGroupName !== void 0 && builtinGroupName !== "apcli" && apcliOption.name !== builtinGroupName) {
|
|
3866
|
+
throw new Error(
|
|
3867
|
+
`builtinGroupName=${JSON.stringify(builtinGroupName)} conflicts with the name on the supplied ApcliGroup (${JSON.stringify(apcliOption.name)}). Pass only one.`
|
|
3868
|
+
);
|
|
3869
|
+
}
|
|
3870
|
+
apcliCfg = apcliOption;
|
|
3871
|
+
} else if (apcliOption !== void 0) {
|
|
3872
|
+
apcliCfg = ApcliGroup.fromCliConfig(apcliOption, {
|
|
3873
|
+
registryInjected,
|
|
3874
|
+
name: builtinGroupName
|
|
3875
|
+
});
|
|
3876
|
+
} else {
|
|
3877
|
+
let yamlVal = null;
|
|
3878
|
+
try {
|
|
3879
|
+
const resolver = new ConfigResolver();
|
|
3880
|
+
yamlVal = resolver.resolveObject("apcli");
|
|
3881
|
+
} catch {
|
|
3882
|
+
yamlVal = null;
|
|
3883
|
+
}
|
|
3884
|
+
apcliCfg = ApcliGroup.fromYaml(yamlVal, {
|
|
3885
|
+
registryInjected,
|
|
3886
|
+
name: builtinGroupName
|
|
3887
|
+
});
|
|
3559
3888
|
}
|
|
3560
|
-
|
|
3889
|
+
} catch (e) {
|
|
3890
|
+
process.stderr.write(`Error: ${e instanceof Error ? e.message : String(e)}
|
|
3891
|
+
`);
|
|
3892
|
+
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3561
3893
|
}
|
|
3562
|
-
|
|
3894
|
+
setReservedGroupNames(/* @__PURE__ */ new Set([apcliCfg.name]));
|
|
3895
|
+
const apcliGroup = program.command(apcliCfg.name, { hidden: !apcliCfg.isGroupVisible() }).description("Built-in commands");
|
|
3563
3896
|
if (registry) {
|
|
3564
3897
|
program._registry = registry;
|
|
3565
3898
|
if (executor) {
|
|
@@ -3585,17 +3918,17 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3585
3918
|
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3586
3919
|
}
|
|
3587
3920
|
_registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exposureFilter);
|
|
3588
|
-
_registerDeprecationShims(program, apcliGroup, registryInjected, resolvedProgName);
|
|
3589
3921
|
program.addHelpText("after", [
|
|
3590
3922
|
"",
|
|
3591
|
-
"Use --help --verbose to show all options (including built-in
|
|
3923
|
+
"Use --help --verbose to show all options (including built-in options).",
|
|
3592
3924
|
"Use --help --man to display a formatted man page."
|
|
3593
3925
|
].join("\n"));
|
|
3594
|
-
configureManHelp(program, resolvedProgName, VERSION);
|
|
3926
|
+
configureManHelp(program, resolvedProgName, appVersion ?? VERSION);
|
|
3595
3927
|
if (extraCommands && extraCommands.length > 0) {
|
|
3928
|
+
const _reservedForExtra = /* @__PURE__ */ new Set([apcliCfg.name]);
|
|
3596
3929
|
for (const cmd of extraCommands) {
|
|
3597
3930
|
const cmdName = cmd.name();
|
|
3598
|
-
if (
|
|
3931
|
+
if (_reservedForExtra.has(cmdName)) {
|
|
3599
3932
|
process.stderr.write(
|
|
3600
3933
|
`Error: extraCommands name '${cmdName}' is reserved
|
|
3601
3934
|
`
|
|
@@ -3604,21 +3937,11 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3604
3937
|
}
|
|
3605
3938
|
const existing = program.commands.find((c) => c.name() === cmdName);
|
|
3606
3939
|
if (existing) {
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
warn(
|
|
3610
|
-
`extraCommands '${cmdName}' overrides the deprecation shim for the same name. The shim will be removed.`
|
|
3611
|
-
);
|
|
3612
|
-
const cmds = program.commands;
|
|
3613
|
-
const idx = cmds.indexOf(existing);
|
|
3614
|
-
if (idx >= 0) cmds.splice(idx, 1);
|
|
3615
|
-
} else {
|
|
3616
|
-
process.stderr.write(
|
|
3617
|
-
`Error: extraCommands name '${cmdName}' collides with an existing command
|
|
3940
|
+
process.stderr.write(
|
|
3941
|
+
`Error: extraCommands name '${cmdName}' collides with an existing command
|
|
3618
3942
|
`
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
}
|
|
3943
|
+
);
|
|
3944
|
+
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
3622
3945
|
}
|
|
3623
3946
|
program.addCommand(cmd);
|
|
3624
3947
|
}
|
|
@@ -3627,7 +3950,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3627
3950
|
const opts = thisCommand.opts();
|
|
3628
3951
|
const commandsDir = opts.commandsDir;
|
|
3629
3952
|
const bindingPath = opts.binding;
|
|
3630
|
-
await applyToolkitIntegration(commandsDir, bindingPath);
|
|
3953
|
+
await applyToolkitIntegration(commandsDir, bindingPath, { allowedPrefixes });
|
|
3631
3954
|
});
|
|
3632
3955
|
return program;
|
|
3633
3956
|
}
|
|
@@ -3677,40 +4000,13 @@ function _registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exp
|
|
|
3677
4000
|
entry.register(apcliGroup, registry, executor);
|
|
3678
4001
|
}
|
|
3679
4002
|
}
|
|
3680
|
-
function _registerDeprecationShims(root, apcliGroup, registryInjected, cliName) {
|
|
3681
|
-
if (registryInjected) return;
|
|
3682
|
-
for (const name of _DEPRECATED_ROOT_COMMANDS) {
|
|
3683
|
-
const apcliSub = apcliGroup.commands.find((c) => c.name() === name);
|
|
3684
|
-
if (!apcliSub) continue;
|
|
3685
|
-
if (root.commands.some((c) => c.name() === name)) continue;
|
|
3686
|
-
const shim = root.command(name).description(`[DEPRECATED] Use '${cliName} apcli ${name}' instead.`).allowUnknownOption(true).allowExcessArguments(true).helpOption(false);
|
|
3687
|
-
shim.__isDeprecationShim = true;
|
|
3688
|
-
shim.action(async function() {
|
|
3689
|
-
process.stderr.write(
|
|
3690
|
-
`WARNING: '${name}' as a root-level command is deprecated. Use '${cliName} apcli ${name}' instead.
|
|
3691
|
-
Will be removed in v0.8. See: https://aiperceivable.github.io/apcore-cli/features/builtin-group/#11-migration
|
|
3692
|
-
`
|
|
3693
|
-
);
|
|
3694
|
-
const tail = _collectShimForwardArgs(this);
|
|
3695
|
-
await apcliSub.parseAsync(tail, { from: "user" });
|
|
3696
|
-
});
|
|
3697
|
-
}
|
|
3698
|
-
}
|
|
3699
|
-
function _collectShimForwardArgs(shim) {
|
|
3700
|
-
const shimArgs = (shim.args ?? []).slice();
|
|
3701
|
-
if (shimArgs.length > 0) return shimArgs;
|
|
3702
|
-
const shimName = shim.name();
|
|
3703
|
-
const idx = process.argv.indexOf(shimName);
|
|
3704
|
-
if (idx < 0) return [];
|
|
3705
|
-
return process.argv.slice(idx + 1);
|
|
3706
|
-
}
|
|
3707
4003
|
function lookupBindingDisplay(moduleId) {
|
|
3708
4004
|
return bindingDisplayMap.get(moduleId);
|
|
3709
4005
|
}
|
|
3710
4006
|
function clearBindingDisplayMap() {
|
|
3711
4007
|
bindingDisplayMap.clear();
|
|
3712
4008
|
}
|
|
3713
|
-
async function applyToolkitIntegration(commandsDir, bindingPath) {
|
|
4009
|
+
async function applyToolkitIntegration(commandsDir, bindingPath, options = {}) {
|
|
3714
4010
|
if (!commandsDir && !bindingPath) {
|
|
3715
4011
|
return;
|
|
3716
4012
|
}
|
|
@@ -3730,14 +4026,14 @@ async function applyToolkitIntegration(commandsDir, bindingPath) {
|
|
|
3730
4026
|
}
|
|
3731
4027
|
if (bindingPath) {
|
|
3732
4028
|
try {
|
|
3733
|
-
await loadBindingDisplayOverlay(toolkit, bindingPath);
|
|
4029
|
+
await loadBindingDisplayOverlay(toolkit, bindingPath, options.allowedPrefixes);
|
|
3734
4030
|
} catch (err) {
|
|
3735
4031
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3736
4032
|
warn(`apcore-toolkit: failed to load binding '${bindingPath}': ${msg}`);
|
|
3737
4033
|
}
|
|
3738
4034
|
}
|
|
3739
4035
|
}
|
|
3740
|
-
async function loadBindingDisplayOverlay(toolkit, bindingPath) {
|
|
4036
|
+
async function loadBindingDisplayOverlay(toolkit, bindingPath, allowedPrefixes) {
|
|
3741
4037
|
const BindingLoaderCtor = toolkit.BindingLoader;
|
|
3742
4038
|
const DisplayResolverCtor = toolkit.DisplayResolver;
|
|
3743
4039
|
if (!BindingLoaderCtor || !DisplayResolverCtor) {
|
|
@@ -3747,11 +4043,23 @@ async function loadBindingDisplayOverlay(toolkit, bindingPath) {
|
|
|
3747
4043
|
const scanned = loader.load(bindingPath);
|
|
3748
4044
|
const resolver = new DisplayResolverCtor();
|
|
3749
4045
|
const resolved = resolver.resolve(scanned, { bindingPath });
|
|
4046
|
+
const prefixes = allowedPrefixes && allowedPrefixes.length > 0 ? allowedPrefixes : null;
|
|
4047
|
+
const isTargetAllowed = (target) => {
|
|
4048
|
+
if (!prefixes) return true;
|
|
4049
|
+
if (typeof target !== "string" || target.length === 0) return true;
|
|
4050
|
+
return prefixes.some((p) => target.startsWith(p));
|
|
4051
|
+
};
|
|
3750
4052
|
for (const mod of resolved) {
|
|
3751
4053
|
if (!mod || typeof mod !== "object") continue;
|
|
3752
4054
|
const entry = mod;
|
|
3753
4055
|
const id = typeof entry.moduleId === "string" ? entry.moduleId : null;
|
|
3754
4056
|
if (!id) continue;
|
|
4057
|
+
if (!isTargetAllowed(entry.target)) {
|
|
4058
|
+
warn(
|
|
4059
|
+
`apcore-toolkit: dropped binding entry '${id}' \u2014 target '${String(entry.target)}' is outside allowedPrefixes`
|
|
4060
|
+
);
|
|
4061
|
+
continue;
|
|
4062
|
+
}
|
|
3755
4063
|
const meta = entry.metadata ?? {};
|
|
3756
4064
|
const display = meta.display;
|
|
3757
4065
|
if (display && typeof display === "object" && !Array.isArray(display)) {
|
|
@@ -3761,7 +4069,12 @@ async function loadBindingDisplayOverlay(toolkit, bindingPath) {
|
|
|
3761
4069
|
}
|
|
3762
4070
|
function main(progName) {
|
|
3763
4071
|
verboseHelp = hasVerboseFlag();
|
|
3764
|
-
const program = createCli(
|
|
4072
|
+
const program = createCli({
|
|
4073
|
+
progName,
|
|
4074
|
+
verbose: verboseHelp,
|
|
4075
|
+
version: VERSION,
|
|
4076
|
+
description: `${progName ?? "apcore-cli"} \u2014 execute apcore modules from the command line`
|
|
4077
|
+
});
|
|
3765
4078
|
try {
|
|
3766
4079
|
program.parse(process.argv);
|
|
3767
4080
|
} catch (error) {
|
|
@@ -3842,7 +4155,15 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
|
|
|
3842
4155
|
cmd.addHelpText("after", "\n" + footerParts.join("\n") + "\n");
|
|
3843
4156
|
}
|
|
3844
4157
|
for (const opt of schemaOptions) {
|
|
3845
|
-
if (opt.
|
|
4158
|
+
if (opt.isBooleanFlag) {
|
|
4159
|
+
const flagBase = opt.name.replace(/_/g, "-");
|
|
4160
|
+
cmd.addOption(
|
|
4161
|
+
new Option4(`--${flagBase}`, opt.description).default(
|
|
4162
|
+
opt.defaultValue
|
|
4163
|
+
)
|
|
4164
|
+
);
|
|
4165
|
+
cmd.addOption(new Option4(`--no-${flagBase}`).hideHelp());
|
|
4166
|
+
} else if (opt.parseArg) {
|
|
3846
4167
|
cmd.option(opt.flags, opt.description, opt.parseArg, opt.defaultValue);
|
|
3847
4168
|
} else {
|
|
3848
4169
|
cmd.option(opt.flags, opt.description, opt.defaultValue);
|
|
@@ -3866,24 +4187,12 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
|
|
|
3866
4187
|
);
|
|
3867
4188
|
const approvalToken = options.approvalToken;
|
|
3868
4189
|
const schemaKwargs = {};
|
|
3869
|
-
const
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
"sandbox",
|
|
3876
|
-
"verbose",
|
|
3877
|
-
"dryRun",
|
|
3878
|
-
"trace",
|
|
3879
|
-
"stream",
|
|
3880
|
-
"strategy",
|
|
3881
|
-
"approvalTimeout",
|
|
3882
|
-
"approvalToken"
|
|
3883
|
-
]);
|
|
3884
|
-
for (const [k, v] of Object.entries(options)) {
|
|
3885
|
-
if (!builtinKeys.has(k)) {
|
|
3886
|
-
schemaKwargs[k] = v;
|
|
4190
|
+
for (const opt of schemaOptions) {
|
|
4191
|
+
const commanderKey = opt.name.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
4192
|
+
if (commanderKey in options) {
|
|
4193
|
+
schemaKwargs[opt.name] = options[commanderKey];
|
|
4194
|
+
} else if (opt.name in options) {
|
|
4195
|
+
schemaKwargs[opt.name] = options[opt.name];
|
|
3887
4196
|
}
|
|
3888
4197
|
}
|
|
3889
4198
|
let merged = {};
|
|
@@ -4068,22 +4377,6 @@ Pipeline Trace (strategy: ${trace.strategyName}, ${stepCount} steps, ${trace.tot
|
|
|
4068
4377
|
});
|
|
4069
4378
|
return cmd;
|
|
4070
4379
|
}
|
|
4071
|
-
function validateModuleId(moduleId) {
|
|
4072
|
-
if (moduleId.length > 192) {
|
|
4073
|
-
process.stderr.write(
|
|
4074
|
-
`Error: Invalid module ID format: '${moduleId}'. Maximum length is 192 characters.
|
|
4075
|
-
`
|
|
4076
|
-
);
|
|
4077
|
-
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
4078
|
-
}
|
|
4079
|
-
if (!/^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$/.test(moduleId)) {
|
|
4080
|
-
process.stderr.write(
|
|
4081
|
-
`Error: Invalid module ID format: '${moduleId}'.
|
|
4082
|
-
`
|
|
4083
|
-
);
|
|
4084
|
-
process.exit(EXIT_CODES.INVALID_CLI_INPUT);
|
|
4085
|
-
}
|
|
4086
|
-
}
|
|
4087
4380
|
async function collectInput(stdinFlag, cliKwargs = {}, largeInput) {
|
|
4088
4381
|
const cliKwargsNonNull = {};
|
|
4089
4382
|
for (const [k, v] of Object.entries(cliKwargs)) {
|
|
@@ -4102,7 +4395,7 @@ async function collectInput(stdinFlag, cliKwargs = {}, largeInput) {
|
|
|
4102
4395
|
} else {
|
|
4103
4396
|
source = `file '${stdinFlag}'`;
|
|
4104
4397
|
try {
|
|
4105
|
-
raw =
|
|
4398
|
+
raw = readFileSync3(stdinFlag, "utf-8");
|
|
4106
4399
|
} catch (err) {
|
|
4107
4400
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4108
4401
|
process.stderr.write(`Error: Could not read input ${source}: ${msg}
|
|
@@ -4181,7 +4474,7 @@ function reconvertEnumValues(kwargs, options) {
|
|
|
4181
4474
|
}
|
|
4182
4475
|
return result;
|
|
4183
4476
|
}
|
|
4184
|
-
var __dirname2, verboseHelp, docsUrl, VERSION, _ALWAYS_REGISTERED,
|
|
4477
|
+
var __dirname2, verboseHelp, docsUrl, VERSION, _ALWAYS_REGISTERED, bindingDisplayMap;
|
|
4185
4478
|
var init_main = __esm({
|
|
4186
4479
|
"src/main.ts"() {
|
|
4187
4480
|
"use strict";
|
|
@@ -4204,31 +4497,17 @@ var init_main = __esm({
|
|
|
4204
4497
|
init_exposure();
|
|
4205
4498
|
init_audit();
|
|
4206
4499
|
init_canonical_help();
|
|
4207
|
-
|
|
4500
|
+
init_validate();
|
|
4501
|
+
__dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
|
|
4208
4502
|
verboseHelp = false;
|
|
4209
4503
|
docsUrl = null;
|
|
4210
4504
|
VERSION = "0.0.0";
|
|
4211
4505
|
try {
|
|
4212
|
-
const pkg = JSON.parse(
|
|
4506
|
+
const pkg = JSON.parse(readFileSync3(path5.resolve(__dirname2, "../package.json"), "utf-8"));
|
|
4213
4507
|
VERSION = pkg.version;
|
|
4214
4508
|
} catch {
|
|
4215
4509
|
}
|
|
4216
4510
|
_ALWAYS_REGISTERED = /* @__PURE__ */ new Set(["exec"]);
|
|
4217
|
-
_DEPRECATED_ROOT_COMMANDS = [
|
|
4218
|
-
"list",
|
|
4219
|
-
"describe",
|
|
4220
|
-
"exec",
|
|
4221
|
-
"init",
|
|
4222
|
-
"validate",
|
|
4223
|
-
"health",
|
|
4224
|
-
"usage",
|
|
4225
|
-
"enable",
|
|
4226
|
-
"disable",
|
|
4227
|
-
"reload",
|
|
4228
|
-
"config",
|
|
4229
|
-
"completion",
|
|
4230
|
-
"describe-pipeline"
|
|
4231
|
-
];
|
|
4232
4511
|
bindingDisplayMap = /* @__PURE__ */ new Map();
|
|
4233
4512
|
}
|
|
4234
4513
|
});
|