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/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
- encryptor;
496
+ _encryptor;
472
497
  constructor(config, encryptor) {
473
498
  this.config = config;
474
- this.encryptor = encryptor ?? new ConfigEncryptor();
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.encryptor.retrieve(strResult, "auth.api_key");
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-configure with 'apcore-cli config set auth.api_key'."
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-configure with 'apcore-cli config set auth.api_key'."
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
- try {
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
- process.stderr.write(
765
- `Error: $ref resolution depth exceeded maximum of ${maxDepth} for module '${moduleId}'.
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
- process.stderr.write(
772
- `Error: Circular $ref detected in schema for module '${moduleId}' at path '${refPath}'.
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
- process.stderr.write(
781
- `Error: Unresolvable $ref '${refPath}' in schema for module '${moduleId}'.
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
- if ("properties" in obj && typeof obj.properties === "object" && obj.properties !== null) {
886
- const props = obj.properties;
887
- for (const [propName, propSchema] of Object.entries(props)) {
888
- props[propName] = resolveNode(
889
- propSchema,
890
- defs,
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
- "verbose",
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
- var TOOLKIT_MISSING_HINT = "The 'markdown' and 'skill' output formats require the apcore-toolkit peer dependency. Install with: npm install apcore-toolkit@^0.6";
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
- if (typeof effective_result === "object" && !Array.isArray(effective_result) && effective_result !== null) {
1429
- const obj = effective_result;
1430
- const keys = Object.keys(obj);
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
- if (Array.isArray(effective_result)) {
1449
- for (const item of effective_result) {
1450
- process.stdout.write(JSON.stringify(item) + "\n");
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 escapeCsvField(value) {
1469
- if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
1470
- return '"' + value.replace(/"/g, '""') + '"';
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 value;
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 apcore modules.");
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 apcore extensions directory.");
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 \\-\\-verbose\\fR for full option list.`);
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
- verboseHelp = verbose;
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("--verbose");
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, verbose = false) {
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
- verbose = extensionsDirOrOpts.verbose ?? verbose;
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 = verbose;
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("--verbose", "Show all options in help output (including built-in options)");
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 --verbose to show all options (including built-in options).",
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 apcore-js registry wired. In standalone mode, pass --extensions-dir <path> to enable module discovery.\n"
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
- verbose: verboseHelp,
4019
+ allOptions: verboseHelp,
3949
4020
  version: VERSION,
3950
- description: `${progName ?? "apcore-cli"} \u2014 execute apcore modules from the command line`
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 --verbose to show all options (including built-in apcore options).");
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,