apcore-cli 0.8.1 → 0.9.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 +70 -0
- package/README.md +16 -12
- package/dist/bin/apcore-cli.js +173 -81
- package/dist/bin/apcore-cli.js.map +1 -1
- package/dist/index.d.ts +56 -6
- package/dist/index.js +174 -81
- package/dist/index.js.map +1 -1
- package/package.json +3 -8
package/dist/index.js
CHANGED
|
@@ -34,6 +34,12 @@ function exitCodeForError(error) {
|
|
|
34
34
|
if (error instanceof SchemaValidationError) {
|
|
35
35
|
return EXIT_CODES.SCHEMA_VALIDATION_ERROR;
|
|
36
36
|
}
|
|
37
|
+
if (error instanceof MaxDepthExceededError || error instanceof CircularRefError) {
|
|
38
|
+
return EXIT_CODES.SCHEMA_CIRCULAR_REF;
|
|
39
|
+
}
|
|
40
|
+
if (error instanceof UnresolvableRefError) {
|
|
41
|
+
return EXIT_CODES.SCHEMA_VALIDATION_ERROR;
|
|
42
|
+
}
|
|
37
43
|
if (error instanceof ModuleNotFoundError) {
|
|
38
44
|
return EXIT_CODES.MODULE_NOT_FOUND;
|
|
39
45
|
}
|
|
@@ -73,7 +79,7 @@ function exitCodeForError(error) {
|
|
|
73
79
|
}
|
|
74
80
|
return EXIT_CODES.MODULE_EXECUTE_ERROR;
|
|
75
81
|
}
|
|
76
|
-
var ApprovalTimeoutError, AuthenticationError, ConfigDecryptionError, ModuleExecutionError, ApprovalDeniedError, SchemaValidationError, ModuleNotFoundError, EXIT_CODES;
|
|
82
|
+
var ApprovalTimeoutError, AuthenticationError, ConfigDecryptionError, ModuleExecutionError, ApprovalDeniedError, SchemaValidationError, MaxDepthExceededError, CircularRefError, UnresolvableRefError, ModuleNotFoundError, EXIT_CODES;
|
|
77
83
|
var init_errors = __esm({
|
|
78
84
|
"src/errors.ts"() {
|
|
79
85
|
"use strict";
|
|
@@ -109,11 +115,30 @@ var init_errors = __esm({
|
|
|
109
115
|
}
|
|
110
116
|
};
|
|
111
117
|
SchemaValidationError = class extends Error {
|
|
118
|
+
code = "SCHEMA_VALIDATION_ERROR";
|
|
112
119
|
constructor(message = "Schema validation failed") {
|
|
113
120
|
super(message);
|
|
114
121
|
this.name = "SchemaValidationError";
|
|
115
122
|
}
|
|
116
123
|
};
|
|
124
|
+
MaxDepthExceededError = class extends Error {
|
|
125
|
+
constructor(message = "Schema $ref resolution depth exceeded") {
|
|
126
|
+
super(message);
|
|
127
|
+
this.name = "MaxDepthExceededError";
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
CircularRefError = class extends Error {
|
|
131
|
+
constructor(message = "Circular $ref detected in schema") {
|
|
132
|
+
super(message);
|
|
133
|
+
this.name = "CircularRefError";
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
UnresolvableRefError = class extends Error {
|
|
137
|
+
constructor(message = "Unresolvable $ref in schema") {
|
|
138
|
+
super(message);
|
|
139
|
+
this.name = "UnresolvableRefError";
|
|
140
|
+
}
|
|
141
|
+
};
|
|
117
142
|
ModuleNotFoundError = class extends Error {
|
|
118
143
|
constructor(message = "Module not found") {
|
|
119
144
|
super(message);
|
|
@@ -406,7 +431,7 @@ var init_config_encryptor = __esm({
|
|
|
406
431
|
_ConfigEncryptor.weakFallbackWarned = true;
|
|
407
432
|
}
|
|
408
433
|
const hostname2 = os3.hostname();
|
|
409
|
-
const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
|
|
434
|
+
const username = process.env.USER ?? process.env.LOGNAME ?? process.env.USERNAME ?? "unknown";
|
|
410
435
|
const material = `${hostname2}:${username}`;
|
|
411
436
|
return crypto2.pbkdf2Sync(material, salt, PBKDF2_ITERATIONS, 32, "sha256");
|
|
412
437
|
}
|
|
@@ -438,7 +463,7 @@ var init_config_encryptor = __esm({
|
|
|
438
463
|
const tag = data.subarray(12, 28);
|
|
439
464
|
const ct = data.subarray(28);
|
|
440
465
|
const hostname2 = os3.hostname();
|
|
441
|
-
const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
|
|
466
|
+
const username = process.env.USER ?? process.env.LOGNAME ?? process.env.USERNAME ?? "unknown";
|
|
442
467
|
const passphrase = process.env.APCORE_CLI_CONFIG_PASSPHRASE;
|
|
443
468
|
const materials = passphrase ? [passphrase, `${hostname2}:${username}`] : [`${hostname2}:${username}`];
|
|
444
469
|
for (const material of materials) {
|
|
@@ -468,10 +493,26 @@ var init_auth = __esm({
|
|
|
468
493
|
init_config_encryptor();
|
|
469
494
|
AuthProvider = class {
|
|
470
495
|
config;
|
|
471
|
-
|
|
496
|
+
_encryptor;
|
|
472
497
|
constructor(config, encryptor) {
|
|
473
498
|
this.config = config;
|
|
474
|
-
this.
|
|
499
|
+
this._encryptor = encryptor;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Resolve the active ConfigEncryptor instance.
|
|
503
|
+
*
|
|
504
|
+
* D11-005 (2026-05-12): three-tier fallback chain matching Python's
|
|
505
|
+
* `_get_encryptor` (auth.py:33): explicit constructor arg > peer attribute
|
|
506
|
+
* `config.encryptor` (set by embedders injecting forced-AES test fixtures
|
|
507
|
+
* or shared instances) > fresh `new ConfigEncryptor()`. Previously TS
|
|
508
|
+
* skipped the peer-attribute tier, silently giving embedders a different
|
|
509
|
+
* encryptor than the one they wired on the config.
|
|
510
|
+
*/
|
|
511
|
+
getEncryptor() {
|
|
512
|
+
if (this._encryptor) return this._encryptor;
|
|
513
|
+
const fromConfig = this.config.encryptor;
|
|
514
|
+
if (fromConfig) return fromConfig;
|
|
515
|
+
return new ConfigEncryptor();
|
|
475
516
|
}
|
|
476
517
|
/**
|
|
477
518
|
* Retrieve the API key from the configured sources.
|
|
@@ -489,11 +530,11 @@ var init_auth = __esm({
|
|
|
489
530
|
const strResult = String(result);
|
|
490
531
|
if (strResult.startsWith("keyring:") || strResult.startsWith("enc:")) {
|
|
491
532
|
try {
|
|
492
|
-
return await this.
|
|
533
|
+
return await this.getEncryptor().retrieve(strResult, "auth.api_key");
|
|
493
534
|
} catch (err) {
|
|
494
535
|
if (err instanceof ConfigDecryptionError) {
|
|
495
536
|
throw new AuthenticationError(
|
|
496
|
-
"Failed to decrypt stored API key. Re-
|
|
537
|
+
"Failed to decrypt stored API key. Re-store with 'apcli config set auth.api_key'."
|
|
497
538
|
);
|
|
498
539
|
}
|
|
499
540
|
throw err;
|
|
@@ -522,7 +563,7 @@ var init_auth = __esm({
|
|
|
522
563
|
}
|
|
523
564
|
if (/[\r\n]/.test(key)) {
|
|
524
565
|
throw new AuthenticationError(
|
|
525
|
-
"Malformed API key: contains invalid characters (CR/LF). Re-
|
|
566
|
+
"Malformed API key: contains invalid characters (CR/LF). Re-store with 'apcli config set auth.api_key'."
|
|
526
567
|
);
|
|
527
568
|
}
|
|
528
569
|
headers.Authorization = `Bearer ${key.trim()}`;
|
|
@@ -550,7 +591,7 @@ import { join as join4, resolve as resolvePath } from "path";
|
|
|
550
591
|
function buildSandboxEnv(tmpDir) {
|
|
551
592
|
const env = {};
|
|
552
593
|
for (const key of SANDBOX_ALLOW_KEYS) {
|
|
553
|
-
if (process.env[key]) env[key] = process.env[key];
|
|
594
|
+
if (process.env[key] !== void 0) env[key] = process.env[key];
|
|
554
595
|
}
|
|
555
596
|
for (const [key, val] of Object.entries(process.env)) {
|
|
556
597
|
if (key.startsWith(SANDBOX_ALLOW_PREFIX) && !key.startsWith(SANDBOX_DENY_PREFIX) && !SANDBOX_DENY_KEYS.includes(key)) {
|
|
@@ -655,11 +696,20 @@ var init_sandbox = __esm({
|
|
|
655
696
|
}
|
|
656
697
|
stderr += chunk.toString();
|
|
657
698
|
});
|
|
699
|
+
child.stdin.on("error", () => {
|
|
700
|
+
});
|
|
658
701
|
child.stdin.write(JSON.stringify(inputData));
|
|
659
702
|
child.stdin.end();
|
|
660
703
|
return new Promise((resolve2, reject) => {
|
|
704
|
+
const cleanup = () => {
|
|
705
|
+
try {
|
|
706
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
707
|
+
} catch {
|
|
708
|
+
}
|
|
709
|
+
};
|
|
661
710
|
const timer = setTimeout(() => {
|
|
662
711
|
child.kill("SIGKILL");
|
|
712
|
+
cleanup();
|
|
663
713
|
reject(
|
|
664
714
|
new ModuleExecutionError(
|
|
665
715
|
`Sandbox module '${moduleId}' timed out after ${this.timeoutSeconds}s.`
|
|
@@ -668,10 +718,7 @@ var init_sandbox = __esm({
|
|
|
668
718
|
}, this.timeoutSeconds * 1e3);
|
|
669
719
|
child.on("close", (code) => {
|
|
670
720
|
clearTimeout(timer);
|
|
671
|
-
|
|
672
|
-
rmSync(tmpDir, { recursive: true, force: true });
|
|
673
|
-
} catch {
|
|
674
|
-
}
|
|
721
|
+
cleanup();
|
|
675
722
|
if (sizeExceeded) {
|
|
676
723
|
const limitMiB = Math.floor(outputCap / (1024 * 1024));
|
|
677
724
|
reject(new ModuleExecutionError(
|
|
@@ -695,6 +742,7 @@ var init_sandbox = __esm({
|
|
|
695
742
|
});
|
|
696
743
|
child.on("error", (err) => {
|
|
697
744
|
clearTimeout(timer);
|
|
745
|
+
cleanup();
|
|
698
746
|
reject(new ModuleExecutionError(`Failed to spawn sandbox process: ${err.message}`));
|
|
699
747
|
});
|
|
700
748
|
});
|
|
@@ -761,27 +809,21 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
761
809
|
if ("$ref" in obj) {
|
|
762
810
|
const refPath = obj.$ref;
|
|
763
811
|
if (depth >= maxDepth) {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
`
|
|
812
|
+
throw new MaxDepthExceededError(
|
|
813
|
+
`$ref resolution depth exceeded maximum of ${maxDepth} for module '${moduleId}'.`
|
|
767
814
|
);
|
|
768
|
-
process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
|
|
769
815
|
}
|
|
770
816
|
if (visited.has(refPath)) {
|
|
771
|
-
|
|
772
|
-
`
|
|
773
|
-
`
|
|
817
|
+
throw new CircularRefError(
|
|
818
|
+
`Circular $ref detected in schema for module '${moduleId}' at path '${refPath}'.`
|
|
774
819
|
);
|
|
775
|
-
process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
|
|
776
820
|
}
|
|
777
821
|
const parts = refPath.split("/");
|
|
778
822
|
const key = parts[parts.length - 1];
|
|
779
823
|
if (!(key in defs)) {
|
|
780
|
-
|
|
781
|
-
`
|
|
782
|
-
`
|
|
824
|
+
throw new UnresolvableRefError(
|
|
825
|
+
`Unresolvable $ref '${refPath}' in schema for module '${moduleId}'.`
|
|
783
826
|
);
|
|
784
|
-
process.exit(EXIT_CODES.SCHEMA_VALIDATION_ERROR);
|
|
785
827
|
}
|
|
786
828
|
const newVisited = new Set(visited);
|
|
787
829
|
newVisited.add(refPath);
|
|
@@ -882,17 +924,12 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
|
|
|
882
924
|
return merged;
|
|
883
925
|
}
|
|
884
926
|
}
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
visited,
|
|
892
|
-
depth,
|
|
893
|
-
maxDepth,
|
|
894
|
-
moduleId
|
|
895
|
-
);
|
|
927
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
928
|
+
if (k === "allOf" || k === "anyOf" || k === "oneOf" || k === "$ref") {
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
if (typeof v === "object" && v !== null && !Array.isArray(v)) {
|
|
932
|
+
obj[k] = resolveNode(v, defs, visited, depth, maxDepth, moduleId);
|
|
896
933
|
}
|
|
897
934
|
}
|
|
898
935
|
return obj;
|
|
@@ -941,7 +978,7 @@ var RESERVED_NAMES = /* @__PURE__ */ new Set([
|
|
|
941
978
|
"format",
|
|
942
979
|
"fields",
|
|
943
980
|
"sandbox",
|
|
944
|
-
"
|
|
981
|
+
"all_options",
|
|
945
982
|
"dry_run",
|
|
946
983
|
"trace",
|
|
947
984
|
"stream",
|
|
@@ -1089,6 +1126,14 @@ var CliApprovalHandler = class {
|
|
|
1089
1126
|
}
|
|
1090
1127
|
async requestApproval(request) {
|
|
1091
1128
|
const moduleId = request.module_id ?? "unknown";
|
|
1129
|
+
if (request.requires_approval === false) {
|
|
1130
|
+
return { status: "approved", approved_by: "not_required" };
|
|
1131
|
+
}
|
|
1132
|
+
const moduleDef = request.module_def;
|
|
1133
|
+
const annotationsForCheck = moduleDef?.annotations;
|
|
1134
|
+
if (annotationsForCheck && annotationsForCheck.requires_approval === false) {
|
|
1135
|
+
return { status: "approved", approved_by: "not_required" };
|
|
1136
|
+
}
|
|
1092
1137
|
if (this.autoApprove) {
|
|
1093
1138
|
return { status: "approved", approved_by: "auto_approve" };
|
|
1094
1139
|
}
|
|
@@ -1197,7 +1242,8 @@ async function promptWithTimeout(moduleDef, timeout) {
|
|
|
1197
1242
|
init_esm_shims();
|
|
1198
1243
|
init_errors();
|
|
1199
1244
|
import yaml from "js-yaml";
|
|
1200
|
-
|
|
1245
|
+
import { formatCsv, formatJsonl } from "apcore-toolkit";
|
|
1246
|
+
var TOOLKIT_MISSING_HINT = "The 'markdown' and 'skill' output formats require the apcore-toolkit peer dependency. Install with: npm install apcore-toolkit@^0.7";
|
|
1201
1247
|
function descriptorToScanned(m) {
|
|
1202
1248
|
const metadata = m.metadata ?? {};
|
|
1203
1249
|
const display = metadata["display"] ?? null;
|
|
@@ -1218,11 +1264,6 @@ function descriptorToScanned(m) {
|
|
|
1218
1264
|
warnings: []
|
|
1219
1265
|
};
|
|
1220
1266
|
}
|
|
1221
|
-
function csvCellString(value) {
|
|
1222
|
-
if (value === null || value === void 0) return "";
|
|
1223
|
-
if (typeof value === "object") return JSON.stringify(value);
|
|
1224
|
-
return String(value);
|
|
1225
|
-
}
|
|
1226
1267
|
function resolveFormat(explicitFormat) {
|
|
1227
1268
|
if (explicitFormat !== void 0) {
|
|
1228
1269
|
return explicitFormat;
|
|
@@ -1425,30 +1466,18 @@ function formatExecResult(result, format, fields) {
|
|
|
1425
1466
|
}
|
|
1426
1467
|
const effective = resolveFormat(format);
|
|
1427
1468
|
if (effective === "csv") {
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
const header = keys.map(escapeCsvField).join(",");
|
|
1432
|
-
const row = keys.map((k) => escapeCsvField(csvCellString(obj[k]))).join(",");
|
|
1433
|
-
process.stdout.write(header + "\n" + row + "\n");
|
|
1434
|
-
} else if (Array.isArray(effective_result) && effective_result.length > 0 && typeof effective_result[0] === "object") {
|
|
1435
|
-
const keys = Object.keys(effective_result[0]);
|
|
1436
|
-
const header = keys.map(escapeCsvField).join(",");
|
|
1437
|
-
const rows = effective_result.map((item) => {
|
|
1438
|
-
const obj = item;
|
|
1439
|
-
return keys.map((k) => escapeCsvField(csvCellString(obj[k]))).join(",");
|
|
1440
|
-
});
|
|
1441
|
-
process.stdout.write(header + "\n" + rows.join("\n") + "\n");
|
|
1469
|
+
const rows = toRowsForTabular(effective_result);
|
|
1470
|
+
if (rows !== null) {
|
|
1471
|
+
process.stdout.write(formatCsv(rows));
|
|
1442
1472
|
} else {
|
|
1443
1473
|
process.stdout.write(JSON.stringify(effective_result) + "\n");
|
|
1444
1474
|
}
|
|
1445
1475
|
} else if (effective === "yaml") {
|
|
1446
1476
|
process.stdout.write(yaml.dump(effective_result, { lineWidth: -1 }));
|
|
1447
1477
|
} else if (effective === "jsonl") {
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
}
|
|
1478
|
+
const rows = toRowsForTabular(effective_result);
|
|
1479
|
+
if (rows !== null) {
|
|
1480
|
+
process.stdout.write(formatJsonl(rows));
|
|
1452
1481
|
} else {
|
|
1453
1482
|
process.stdout.write(JSON.stringify(effective_result) + "\n");
|
|
1454
1483
|
}
|
|
@@ -1465,11 +1494,19 @@ function formatExecResult(result, format, fields) {
|
|
|
1465
1494
|
process.stdout.write(String(effective_result) + "\n");
|
|
1466
1495
|
}
|
|
1467
1496
|
}
|
|
1468
|
-
function
|
|
1469
|
-
if (value
|
|
1470
|
-
|
|
1497
|
+
function toRowsForTabular(value) {
|
|
1498
|
+
if (value === null || value === void 0) return null;
|
|
1499
|
+
if (Array.isArray(value)) {
|
|
1500
|
+
if (value.length === 0) return null;
|
|
1501
|
+
if (!value.every((item) => typeof item === "object" && item !== null && !Array.isArray(item))) {
|
|
1502
|
+
return null;
|
|
1503
|
+
}
|
|
1504
|
+
return value;
|
|
1505
|
+
}
|
|
1506
|
+
if (typeof value === "object") {
|
|
1507
|
+
return [value];
|
|
1471
1508
|
}
|
|
1472
|
-
return
|
|
1509
|
+
return null;
|
|
1473
1510
|
}
|
|
1474
1511
|
function formatPreflightResult(result, format) {
|
|
1475
1512
|
const resolved = resolveFormat(format);
|
|
@@ -1607,7 +1644,7 @@ function renderTemplate(template, context) {
|
|
|
1607
1644
|
return result;
|
|
1608
1645
|
}
|
|
1609
1646
|
function registerInitCommand(cli) {
|
|
1610
|
-
const initGroup = cli.command("init").description("Scaffold new
|
|
1647
|
+
const initGroup = cli.command("init").description("Scaffold new modules.");
|
|
1611
1648
|
initGroup.command("module <module-id>").description("Create a new module from a template.\n\nMODULE_ID is the module identifier (e.g., ops.deploy, user.create).").option(
|
|
1612
1649
|
"--style <style>",
|
|
1613
1650
|
"Module style: decorator (@module), convention (plain function), or binding (YAML).",
|
|
@@ -2135,7 +2172,7 @@ function buildProgramManPage(program, progName, version, description, docsUrl2)
|
|
|
2135
2172
|
s.push(".SH ENVIRONMENT");
|
|
2136
2173
|
s.push(".TP");
|
|
2137
2174
|
s.push("\\fBAPCORE_EXTENSIONS_ROOT\\fR");
|
|
2138
|
-
s.push("Path to the
|
|
2175
|
+
s.push("Path to the extensions directory.");
|
|
2139
2176
|
s.push(".TP");
|
|
2140
2177
|
s.push("\\fBAPCORE_CLI_AUTO_APPROVE\\fR");
|
|
2141
2178
|
s.push("Set to \\fB1\\fR to bypass approval prompts.");
|
|
@@ -2160,7 +2197,7 @@ function buildProgramManPage(program, progName, version, description, docsUrl2)
|
|
|
2160
2197
|
${meaning}`);
|
|
2161
2198
|
}
|
|
2162
2199
|
s.push(".SH SEE ALSO");
|
|
2163
|
-
s.push(`\\fB${progName} \\-\\-help \\-\\-
|
|
2200
|
+
s.push(`\\fB${progName} \\-\\-help \\-\\-all\\-options\\fR for full option list.`);
|
|
2164
2201
|
if (docsUrl2) {
|
|
2165
2202
|
s.push(`.PP
|
|
2166
2203
|
Full documentation at \\fI${roffEscape(docsUrl2)}\\fR`);
|
|
@@ -2512,7 +2549,7 @@ function registerExecCommand(apcliGroup, registry, executor) {
|
|
|
2512
2549
|
return;
|
|
2513
2550
|
}
|
|
2514
2551
|
let result;
|
|
2515
|
-
if (opts.strategy && executor.callWithTrace) {
|
|
2552
|
+
if ((opts.trace || opts.strategy) && executor.callWithTrace) {
|
|
2516
2553
|
const [res] = await executor.callWithTrace(moduleId, merged, { strategy: opts.strategy });
|
|
2517
2554
|
result = res;
|
|
2518
2555
|
} else {
|
|
@@ -3573,15 +3610,18 @@ function validateModuleId(moduleId) {
|
|
|
3573
3610
|
// src/main.ts
|
|
3574
3611
|
var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
|
|
3575
3612
|
var verboseHelp = false;
|
|
3613
|
+
function setAllOptionsHelp(allOptions) {
|
|
3614
|
+
verboseHelp = allOptions;
|
|
3615
|
+
}
|
|
3576
3616
|
function setVerboseHelp(verbose) {
|
|
3577
|
-
|
|
3617
|
+
setAllOptionsHelp(verbose);
|
|
3578
3618
|
}
|
|
3579
3619
|
var docsUrl = null;
|
|
3580
3620
|
function setDocsUrl(url) {
|
|
3581
3621
|
docsUrl = url;
|
|
3582
3622
|
}
|
|
3583
3623
|
function hasVerboseFlag() {
|
|
3584
|
-
return process.argv.includes("--
|
|
3624
|
+
return process.argv.includes("--all-options");
|
|
3585
3625
|
}
|
|
3586
3626
|
function resolveIntOption(cliValue, envValue, defaultValue) {
|
|
3587
3627
|
if (cliValue !== void 0 && Number.isFinite(cliValue) && cliValue > 0) {
|
|
@@ -3614,6 +3654,37 @@ try {
|
|
|
3614
3654
|
VERSION = pkg.version;
|
|
3615
3655
|
} catch {
|
|
3616
3656
|
}
|
|
3657
|
+
function validateInputSchema(schema, input) {
|
|
3658
|
+
const required = schema.required;
|
|
3659
|
+
if (required && Array.isArray(required)) {
|
|
3660
|
+
for (const field of required) {
|
|
3661
|
+
const val = input[field];
|
|
3662
|
+
if (val === null || val === void 0) {
|
|
3663
|
+
return `'${field}' is required`;
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
const properties = schema.properties;
|
|
3668
|
+
if (properties) {
|
|
3669
|
+
for (const [field, propSchema] of Object.entries(properties)) {
|
|
3670
|
+
const val = input[field];
|
|
3671
|
+
if (val === null || val === void 0) continue;
|
|
3672
|
+
const expectedType = propSchema.type;
|
|
3673
|
+
if (!expectedType) continue;
|
|
3674
|
+
const actualType = typeof val;
|
|
3675
|
+
if (expectedType === "string" && actualType !== "string") {
|
|
3676
|
+
return `'${field}' must be a string, got ${actualType}`;
|
|
3677
|
+
}
|
|
3678
|
+
if ((expectedType === "integer" || expectedType === "number") && actualType !== "number") {
|
|
3679
|
+
return `'${field}' must be a number, got ${actualType}`;
|
|
3680
|
+
}
|
|
3681
|
+
if (expectedType === "boolean" && actualType !== "boolean") {
|
|
3682
|
+
return `'${field}' must be a boolean, got ${actualType}`;
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3686
|
+
return null;
|
|
3687
|
+
}
|
|
3617
3688
|
function emitErrorJson(e, exitCode) {
|
|
3618
3689
|
const err = e instanceof Error ? e : new Error(String(e));
|
|
3619
3690
|
const errRecord = err;
|
|
@@ -3662,7 +3733,7 @@ function emitErrorTty(e, exitCode) {
|
|
|
3662
3733
|
Exit code: ${exitCode}
|
|
3663
3734
|
`);
|
|
3664
3735
|
}
|
|
3665
|
-
function createCli(extensionsDirOrOpts, progName,
|
|
3736
|
+
function createCli(extensionsDirOrOpts, progName, allOptions = false) {
|
|
3666
3737
|
let extensionsDir;
|
|
3667
3738
|
let registry;
|
|
3668
3739
|
let executor;
|
|
@@ -3677,7 +3748,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3677
3748
|
if (typeof extensionsDirOrOpts === "object" && extensionsDirOrOpts !== null) {
|
|
3678
3749
|
extensionsDir = extensionsDirOrOpts.extensionsDir;
|
|
3679
3750
|
progName = extensionsDirOrOpts.progName ?? progName;
|
|
3680
|
-
|
|
3751
|
+
allOptions = extensionsDirOrOpts.allOptions ?? extensionsDirOrOpts.verbose ?? allOptions;
|
|
3681
3752
|
app = extensionsDirOrOpts.app;
|
|
3682
3753
|
registry = extensionsDirOrOpts.registry;
|
|
3683
3754
|
executor = extensionsDirOrOpts.executor;
|
|
@@ -3691,7 +3762,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3691
3762
|
} else {
|
|
3692
3763
|
extensionsDir = extensionsDirOrOpts;
|
|
3693
3764
|
}
|
|
3694
|
-
verboseHelp =
|
|
3765
|
+
verboseHelp = allOptions;
|
|
3695
3766
|
registerConfigNamespace();
|
|
3696
3767
|
try {
|
|
3697
3768
|
const auditLogger = new AuditLogger();
|
|
@@ -3724,7 +3795,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3724
3795
|
}
|
|
3725
3796
|
}
|
|
3726
3797
|
const registryInjected = registry !== void 0;
|
|
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("--
|
|
3798
|
+
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("--all-options", "Show all options in help output (including built-in options)");
|
|
3728
3799
|
if (appVersion) {
|
|
3729
3800
|
program.version(appVersion, "-V, --version", "Print version");
|
|
3730
3801
|
}
|
|
@@ -3795,7 +3866,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
|
|
|
3795
3866
|
_registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exposureFilter);
|
|
3796
3867
|
program.addHelpText("after", [
|
|
3797
3868
|
"",
|
|
3798
|
-
"Use --help --
|
|
3869
|
+
"Use --help --all-options to show all options (including built-in options).",
|
|
3799
3870
|
"Use --help --man to display a formatted man page."
|
|
3800
3871
|
].join("\n"));
|
|
3801
3872
|
configureManHelp(program, resolvedProgName, appVersion ?? VERSION);
|
|
@@ -3833,7 +3904,7 @@ var _ALWAYS_REGISTERED = /* @__PURE__ */ new Set(["exec"]);
|
|
|
3833
3904
|
function _registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exposureFilter) {
|
|
3834
3905
|
const emitUnwiredError = () => {
|
|
3835
3906
|
process.stderr.write(
|
|
3836
|
-
"Error: no
|
|
3907
|
+
"Error: no module registry wired. In standalone mode, pass --extensions-dir <path> to enable module discovery.\n"
|
|
3837
3908
|
);
|
|
3838
3909
|
process.exit(EXIT_CODES.CONFIG_INVALID);
|
|
3839
3910
|
};
|
|
@@ -3945,9 +4016,9 @@ function main(progName) {
|
|
|
3945
4016
|
verboseHelp = hasVerboseFlag();
|
|
3946
4017
|
const program = createCli({
|
|
3947
4018
|
progName,
|
|
3948
|
-
|
|
4019
|
+
allOptions: verboseHelp,
|
|
3949
4020
|
version: VERSION,
|
|
3950
|
-
description: `${progName ?? "apcore-cli"} \u2014 execute
|
|
4021
|
+
description: `${progName ?? "apcore-cli"} \u2014 execute modules from the command line`
|
|
3951
4022
|
});
|
|
3952
4023
|
try {
|
|
3953
4024
|
program.parse(process.argv);
|
|
@@ -3975,7 +4046,17 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
|
|
|
3975
4046
|
if (inputSchema && typeof inputSchema === "object" && inputSchema.properties) {
|
|
3976
4047
|
try {
|
|
3977
4048
|
resolvedSchema = resolveRefs(inputSchema, 32, moduleId);
|
|
3978
|
-
} catch {
|
|
4049
|
+
} catch (err) {
|
|
4050
|
+
if (err instanceof MaxDepthExceededError || err instanceof CircularRefError) {
|
|
4051
|
+
process.stderr.write(`Error: ${err.message}
|
|
4052
|
+
`);
|
|
4053
|
+
process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
|
|
4054
|
+
}
|
|
4055
|
+
if (err instanceof UnresolvableRefError) {
|
|
4056
|
+
process.stderr.write(`Error: ${err.message}
|
|
4057
|
+
`);
|
|
4058
|
+
process.exit(EXIT_CODES.SCHEMA_VALIDATION_ERROR);
|
|
4059
|
+
}
|
|
3979
4060
|
resolvedSchema = inputSchema;
|
|
3980
4061
|
}
|
|
3981
4062
|
schemaOptions = schemaToCliOptions(resolvedSchema, helpTextMaxLength);
|
|
@@ -4020,7 +4101,7 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
|
|
|
4020
4101
|
cmd.addOption(approvalTokenOpt);
|
|
4021
4102
|
const footerParts = [];
|
|
4022
4103
|
if (!verbose) {
|
|
4023
|
-
footerParts.push("Use --
|
|
4104
|
+
footerParts.push("Use --all-options to show all options (including built-in options).");
|
|
4024
4105
|
}
|
|
4025
4106
|
if (docsUrl) {
|
|
4026
4107
|
footerParts.push(`Docs: ${docsUrl}/commands/${effectiveCmdName}`);
|
|
@@ -4116,6 +4197,12 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
|
|
|
4116
4197
|
}
|
|
4117
4198
|
process.exit(preflight.valid ? 0 : firstFailedExitCode(preflight));
|
|
4118
4199
|
}
|
|
4200
|
+
if (resolvedSchema.properties) {
|
|
4201
|
+
const validationErr = validateInputSchema(resolvedSchema, merged);
|
|
4202
|
+
if (validationErr) {
|
|
4203
|
+
throw new SchemaValidationError(`Validation failed: ${validationErr}`);
|
|
4204
|
+
}
|
|
4205
|
+
}
|
|
4119
4206
|
if (approvalToken) {
|
|
4120
4207
|
merged._approval_token = approvalToken;
|
|
4121
4208
|
}
|
|
@@ -4669,6 +4756,7 @@ init_errors();
|
|
|
4669
4756
|
init_logger();
|
|
4670
4757
|
init_security();
|
|
4671
4758
|
export {
|
|
4759
|
+
APCLI_SUBCOMMAND_NAMES,
|
|
4672
4760
|
ApcliGroup,
|
|
4673
4761
|
ApcliGroupError,
|
|
4674
4762
|
ApprovalDeniedError,
|
|
@@ -4676,21 +4764,25 @@ export {
|
|
|
4676
4764
|
AuditLogger,
|
|
4677
4765
|
AuthProvider,
|
|
4678
4766
|
AuthenticationError,
|
|
4767
|
+
CircularRefError,
|
|
4679
4768
|
CliApprovalHandler,
|
|
4680
4769
|
ConfigDecryptionError,
|
|
4681
4770
|
ConfigEncryptor,
|
|
4682
4771
|
ConfigResolver,
|
|
4683
4772
|
DEFAULTS,
|
|
4773
|
+
DEFAULT_BUILTIN_GROUP_NAME,
|
|
4684
4774
|
EXIT_CODES,
|
|
4685
4775
|
ExposureFilter,
|
|
4686
4776
|
GroupedModuleGroup,
|
|
4687
4777
|
LazyGroup,
|
|
4688
4778
|
LazyModuleGroup,
|
|
4779
|
+
MaxDepthExceededError,
|
|
4689
4780
|
ModuleExecutionError,
|
|
4690
4781
|
ModuleNotFoundError,
|
|
4691
4782
|
RESERVED_GROUP_NAMES,
|
|
4692
4783
|
Sandbox,
|
|
4693
4784
|
SchemaValidationError,
|
|
4785
|
+
UnresolvableRefError,
|
|
4694
4786
|
applyToolkitIntegration,
|
|
4695
4787
|
buildModuleCommand,
|
|
4696
4788
|
checkApproval,
|
|
@@ -4722,6 +4814,7 @@ export {
|
|
|
4722
4814
|
resolveFormat,
|
|
4723
4815
|
resolveRefs,
|
|
4724
4816
|
schemaToCliOptions,
|
|
4817
|
+
setAllOptionsHelp,
|
|
4725
4818
|
setAuditLogger,
|
|
4726
4819
|
setDocsUrl,
|
|
4727
4820
|
setLogLevel,
|