apcore-cli 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,6 +35,12 @@ function exitCodeForError(error) {
35
35
  if (error instanceof SchemaValidationError) {
36
36
  return EXIT_CODES.SCHEMA_VALIDATION_ERROR;
37
37
  }
38
+ if (error instanceof MaxDepthExceededError || error instanceof CircularRefError) {
39
+ return EXIT_CODES.SCHEMA_CIRCULAR_REF;
40
+ }
41
+ if (error instanceof UnresolvableRefError) {
42
+ return EXIT_CODES.SCHEMA_VALIDATION_ERROR;
43
+ }
38
44
  if (error instanceof ModuleNotFoundError) {
39
45
  return EXIT_CODES.MODULE_NOT_FOUND;
40
46
  }
@@ -74,7 +80,7 @@ function exitCodeForError(error) {
74
80
  }
75
81
  return EXIT_CODES.MODULE_EXECUTE_ERROR;
76
82
  }
77
- var ApprovalTimeoutError, AuthenticationError, ConfigDecryptionError, ModuleExecutionError, ApprovalDeniedError, SchemaValidationError, ModuleNotFoundError, EXIT_CODES;
83
+ var ApprovalTimeoutError, AuthenticationError, ConfigDecryptionError, ModuleExecutionError, ApprovalDeniedError, SchemaValidationError, MaxDepthExceededError, CircularRefError, UnresolvableRefError, ModuleNotFoundError, EXIT_CODES;
78
84
  var init_errors = __esm({
79
85
  "src/errors.ts"() {
80
86
  "use strict";
@@ -115,6 +121,24 @@ var init_errors = __esm({
115
121
  this.name = "SchemaValidationError";
116
122
  }
117
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
+ };
118
142
  ModuleNotFoundError = class extends Error {
119
143
  constructor(message = "Module not found") {
120
144
  super(message);
@@ -155,8 +179,13 @@ var init_errors = __esm({
155
179
  var sandbox_exports = {};
156
180
  __export(sandbox_exports, {
157
181
  Sandbox: () => Sandbox,
182
+ _buildSandboxEnvForTesting: () => _buildSandboxEnvForTesting,
158
183
  runSandboxRunner: () => runSandboxRunner
159
184
  });
185
+ import { spawn } from "child_process";
186
+ import { mkdtempSync, rmSync } from "fs";
187
+ import { tmpdir } from "os";
188
+ import { join, resolve as resolvePath } from "path";
160
189
  async function runSandboxRunner(moduleId) {
161
190
  const extensionsRoot = process.env.APCORE_EXTENSIONS_ROOT ?? "./extensions";
162
191
  const apcore = await import("apcore-js").catch(() => {
@@ -191,10 +220,13 @@ async function runSandboxRunner(moduleId) {
191
220
  process.exit(1);
192
221
  }
193
222
  }
223
+ function _buildSandboxEnvForTesting(tmpDir) {
224
+ return buildSandboxEnv(tmpDir);
225
+ }
194
226
  function buildSandboxEnv(tmpDir) {
195
227
  const env = {};
196
228
  for (const key of SANDBOX_ALLOW_KEYS) {
197
- if (process.env[key]) env[key] = process.env[key];
229
+ if (process.env[key] !== void 0) env[key] = process.env[key];
198
230
  }
199
231
  for (const [key, val] of Object.entries(process.env)) {
200
232
  if (key.startsWith(SANDBOX_ALLOW_PREFIX) && !key.startsWith(SANDBOX_DENY_PREFIX) && !SANDBOX_DENY_KEYS.includes(key)) {
@@ -260,13 +292,8 @@ var init_sandbox = __esm({
260
292
  return this._sandboxedExecute(moduleId, inputData);
261
293
  }
262
294
  async _sandboxedExecute(moduleId, inputData) {
263
- const { spawn } = await import("child_process");
264
- const { tmpdir } = await import("os");
265
- const { join: join4 } = await import("path");
266
- const { mkdtempSync, rmSync } = await import("fs");
267
- const tmpDir = mkdtempSync(join4(tmpdir(), "apcore_sandbox_"));
295
+ const tmpDir = mkdtempSync(join(tmpdir(), "apcore_sandbox_"));
268
296
  const env = buildSandboxEnv(tmpDir);
269
- const { resolve: resolvePath } = await import("path");
270
297
  if (this.extensionsRoot !== null) {
271
298
  env.APCORE_EXTENSIONS_ROOT = resolvePath(this.extensionsRoot);
272
299
  } else if (env.APCORE_EXTENSIONS_ROOT) {
@@ -304,11 +331,20 @@ var init_sandbox = __esm({
304
331
  }
305
332
  stderr += chunk.toString();
306
333
  });
334
+ child.stdin.on("error", () => {
335
+ });
307
336
  child.stdin.write(JSON.stringify(inputData));
308
337
  child.stdin.end();
309
338
  return new Promise((resolve2, reject) => {
339
+ const cleanup = () => {
340
+ try {
341
+ rmSync(tmpDir, { recursive: true, force: true });
342
+ } catch {
343
+ }
344
+ };
310
345
  const timer = setTimeout(() => {
311
346
  child.kill("SIGKILL");
347
+ cleanup();
312
348
  reject(
313
349
  new ModuleExecutionError(
314
350
  `Sandbox module '${moduleId}' timed out after ${this.timeoutSeconds}s.`
@@ -317,10 +353,7 @@ var init_sandbox = __esm({
317
353
  }, this.timeoutSeconds * 1e3);
318
354
  child.on("close", (code) => {
319
355
  clearTimeout(timer);
320
- try {
321
- rmSync(tmpDir, { recursive: true, force: true });
322
- } catch {
323
- }
356
+ cleanup();
324
357
  if (sizeExceeded) {
325
358
  const limitMiB = Math.floor(outputCap / (1024 * 1024));
326
359
  reject(new ModuleExecutionError(
@@ -344,6 +377,7 @@ var init_sandbox = __esm({
344
377
  });
345
378
  child.on("error", (err) => {
346
379
  clearTimeout(timer);
380
+ cleanup();
347
381
  reject(new ModuleExecutionError(`Failed to spawn sandbox process: ${err.message}`));
348
382
  });
349
383
  });
@@ -376,27 +410,21 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
376
410
  if ("$ref" in obj) {
377
411
  const refPath = obj.$ref;
378
412
  if (depth >= maxDepth) {
379
- process.stderr.write(
380
- `Error: $ref resolution depth exceeded maximum of ${maxDepth} for module '${moduleId}'.
381
- `
413
+ throw new MaxDepthExceededError(
414
+ `$ref resolution depth exceeded maximum of ${maxDepth} for module '${moduleId}'.`
382
415
  );
383
- process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
384
416
  }
385
417
  if (visited.has(refPath)) {
386
- process.stderr.write(
387
- `Error: Circular $ref detected in schema for module '${moduleId}' at path '${refPath}'.
388
- `
418
+ throw new CircularRefError(
419
+ `Circular $ref detected in schema for module '${moduleId}' at path '${refPath}'.`
389
420
  );
390
- process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
391
421
  }
392
422
  const parts = refPath.split("/");
393
423
  const key = parts[parts.length - 1];
394
424
  if (!(key in defs)) {
395
- process.stderr.write(
396
- `Error: Unresolvable $ref '${refPath}' in schema for module '${moduleId}'.
397
- `
425
+ throw new UnresolvableRefError(
426
+ `Unresolvable $ref '${refPath}' in schema for module '${moduleId}'.`
398
427
  );
399
- process.exit(EXIT_CODES.SCHEMA_VALIDATION_ERROR);
400
428
  }
401
429
  const newVisited = new Set(visited);
402
430
  newVisited.add(refPath);
@@ -497,17 +525,12 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
497
525
  return merged;
498
526
  }
499
527
  }
500
- if ("properties" in obj && typeof obj.properties === "object" && obj.properties !== null) {
501
- const props = obj.properties;
502
- for (const [propName, propSchema] of Object.entries(props)) {
503
- props[propName] = resolveNode(
504
- propSchema,
505
- defs,
506
- visited,
507
- depth,
508
- maxDepth,
509
- moduleId
510
- );
528
+ for (const [k, v] of Object.entries(obj)) {
529
+ if (k === "allOf" || k === "anyOf" || k === "oneOf" || k === "$ref") {
530
+ continue;
531
+ }
532
+ if (typeof v === "object" && v !== null && !Array.isArray(v)) {
533
+ obj[k] = resolveNode(v, defs, visited, depth, maxDepth, moduleId);
511
534
  }
512
535
  }
513
536
  return obj;
@@ -704,7 +727,7 @@ var init_schema_parser = __esm({
704
727
  "format",
705
728
  "fields",
706
729
  "sandbox",
707
- "verbose",
730
+ "all_options",
708
731
  "dry_run",
709
732
  "trace",
710
733
  "stream",
@@ -817,6 +840,14 @@ var init_approval = __esm({
817
840
  }
818
841
  async requestApproval(request) {
819
842
  const moduleId = request.module_id ?? "unknown";
843
+ if (request.requires_approval === false) {
844
+ return { status: "approved", approved_by: "not_required" };
845
+ }
846
+ const moduleDef = request.module_def;
847
+ const annotationsForCheck = moduleDef?.annotations;
848
+ if (annotationsForCheck && annotationsForCheck.requires_approval === false) {
849
+ return { status: "approved", approved_by: "not_required" };
850
+ }
820
851
  if (this.autoApprove) {
821
852
  return { status: "approved", approved_by: "auto_approve" };
822
853
  }
@@ -853,6 +884,7 @@ var init_approval = __esm({
853
884
 
854
885
  // src/output.ts
855
886
  import yaml from "js-yaml";
887
+ import { formatCsv, formatJsonl } from "apcore-toolkit";
856
888
  function descriptorToScanned(m) {
857
889
  const metadata = m.metadata ?? {};
858
890
  const display = metadata["display"] ?? null;
@@ -873,11 +905,6 @@ function descriptorToScanned(m) {
873
905
  warnings: []
874
906
  };
875
907
  }
876
- function csvCellString(value) {
877
- if (value === null || value === void 0) return "";
878
- if (typeof value === "object") return JSON.stringify(value);
879
- return String(value);
880
- }
881
908
  function resolveFormat(explicitFormat) {
882
909
  if (explicitFormat !== void 0) {
883
910
  return explicitFormat;
@@ -1080,30 +1107,18 @@ function formatExecResult(result, format, fields) {
1080
1107
  }
1081
1108
  const effective = resolveFormat(format);
1082
1109
  if (effective === "csv") {
1083
- if (typeof effective_result === "object" && !Array.isArray(effective_result) && effective_result !== null) {
1084
- const obj = effective_result;
1085
- const keys = Object.keys(obj);
1086
- const header = keys.map(escapeCsvField).join(",");
1087
- const row = keys.map((k) => escapeCsvField(csvCellString(obj[k]))).join(",");
1088
- process.stdout.write(header + "\n" + row + "\n");
1089
- } else if (Array.isArray(effective_result) && effective_result.length > 0 && typeof effective_result[0] === "object") {
1090
- const keys = Object.keys(effective_result[0]);
1091
- const header = keys.map(escapeCsvField).join(",");
1092
- const rows = effective_result.map((item) => {
1093
- const obj = item;
1094
- return keys.map((k) => escapeCsvField(csvCellString(obj[k]))).join(",");
1095
- });
1096
- process.stdout.write(header + "\n" + rows.join("\n") + "\n");
1110
+ const rows = toRowsForTabular(effective_result);
1111
+ if (rows !== null) {
1112
+ process.stdout.write(formatCsv(rows));
1097
1113
  } else {
1098
1114
  process.stdout.write(JSON.stringify(effective_result) + "\n");
1099
1115
  }
1100
1116
  } else if (effective === "yaml") {
1101
1117
  process.stdout.write(yaml.dump(effective_result, { lineWidth: -1 }));
1102
1118
  } else if (effective === "jsonl") {
1103
- if (Array.isArray(effective_result)) {
1104
- for (const item of effective_result) {
1105
- process.stdout.write(JSON.stringify(item) + "\n");
1106
- }
1119
+ const rows = toRowsForTabular(effective_result);
1120
+ if (rows !== null) {
1121
+ process.stdout.write(formatJsonl(rows));
1107
1122
  } else {
1108
1123
  process.stdout.write(JSON.stringify(effective_result) + "\n");
1109
1124
  }
@@ -1120,11 +1135,19 @@ function formatExecResult(result, format, fields) {
1120
1135
  process.stdout.write(String(effective_result) + "\n");
1121
1136
  }
1122
1137
  }
1123
- function escapeCsvField(value) {
1124
- if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
1125
- return '"' + value.replace(/"/g, '""') + '"';
1138
+ function toRowsForTabular(value) {
1139
+ if (value === null || value === void 0) return null;
1140
+ if (Array.isArray(value)) {
1141
+ if (value.length === 0) return null;
1142
+ if (!value.every((item) => typeof item === "object" && item !== null && !Array.isArray(item))) {
1143
+ return null;
1144
+ }
1145
+ return value;
1146
+ }
1147
+ if (typeof value === "object") {
1148
+ return [value];
1126
1149
  }
1127
- return value;
1150
+ return null;
1128
1151
  }
1129
1152
  function formatPreflightResult(result, format) {
1130
1153
  const resolved = resolveFormat(format);
@@ -1205,7 +1228,7 @@ var init_output = __esm({
1205
1228
  "use strict";
1206
1229
  init_esm_shims();
1207
1230
  init_errors();
1208
- TOOLKIT_MISSING_HINT = "The 'markdown' and 'skill' output formats require the apcore-toolkit peer dependency. Install with: npm install apcore-toolkit@^0.6";
1231
+ TOOLKIT_MISSING_HINT = "The 'markdown' and 'skill' output formats require the apcore-toolkit peer dependency. Install with: npm install apcore-toolkit@^0.7";
1209
1232
  }
1210
1233
  });
1211
1234
 
@@ -1236,7 +1259,7 @@ function renderTemplate(template, context) {
1236
1259
  return result;
1237
1260
  }
1238
1261
  function registerInitCommand(cli) {
1239
- const initGroup = cli.command("init").description("Scaffold new apcore modules.");
1262
+ const initGroup = cli.command("init").description("Scaffold new modules.");
1240
1263
  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(
1241
1264
  "--style <style>",
1242
1265
  "Module style: decorator (@module), convention (plain function), or binding (YAML).",
@@ -1812,7 +1835,7 @@ function buildProgramManPage(program, progName, version, description, docsUrl2)
1812
1835
  s.push(".SH ENVIRONMENT");
1813
1836
  s.push(".TP");
1814
1837
  s.push("\\fBAPCORE_EXTENSIONS_ROOT\\fR");
1815
- s.push("Path to the apcore extensions directory.");
1838
+ s.push("Path to the extensions directory.");
1816
1839
  s.push(".TP");
1817
1840
  s.push("\\fBAPCORE_CLI_AUTO_APPROVE\\fR");
1818
1841
  s.push("Set to \\fB1\\fR to bypass approval prompts.");
@@ -1837,7 +1860,7 @@ function buildProgramManPage(program, progName, version, description, docsUrl2)
1837
1860
  ${meaning}`);
1838
1861
  }
1839
1862
  s.push(".SH SEE ALSO");
1840
- s.push(`\\fB${progName} \\-\\-help \\-\\-verbose\\fR for full option list.`);
1863
+ s.push(`\\fB${progName} \\-\\-help \\-\\-all\\-options\\fR for full option list.`);
1841
1864
  if (docsUrl2) {
1842
1865
  s.push(`.PP
1843
1866
  Full documentation at \\fI${roffEscape(docsUrl2)}\\fR`);
@@ -2244,7 +2267,7 @@ var init_config_encryptor = __esm({
2244
2267
  _ConfigEncryptor.weakFallbackWarned = true;
2245
2268
  }
2246
2269
  const hostname2 = os3.hostname();
2247
- const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
2270
+ const username = process.env.USER ?? process.env.LOGNAME ?? process.env.USERNAME ?? "unknown";
2248
2271
  const material = `${hostname2}:${username}`;
2249
2272
  return crypto2.pbkdf2Sync(material, salt, PBKDF2_ITERATIONS, 32, "sha256");
2250
2273
  }
@@ -2276,7 +2299,7 @@ var init_config_encryptor = __esm({
2276
2299
  const tag = data.subarray(12, 28);
2277
2300
  const ct = data.subarray(28);
2278
2301
  const hostname2 = os3.hostname();
2279
- const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
2302
+ const username = process.env.USER ?? process.env.LOGNAME ?? process.env.USERNAME ?? "unknown";
2280
2303
  const passphrase = process.env.APCORE_CLI_CONFIG_PASSPHRASE;
2281
2304
  const materials = passphrase ? [passphrase, `${hostname2}:${username}`] : [`${hostname2}:${username}`];
2282
2305
  for (const material of materials) {
@@ -2306,10 +2329,26 @@ var init_auth = __esm({
2306
2329
  init_config_encryptor();
2307
2330
  AuthProvider = class {
2308
2331
  config;
2309
- encryptor;
2332
+ _encryptor;
2310
2333
  constructor(config, encryptor) {
2311
2334
  this.config = config;
2312
- this.encryptor = encryptor ?? new ConfigEncryptor();
2335
+ this._encryptor = encryptor;
2336
+ }
2337
+ /**
2338
+ * Resolve the active ConfigEncryptor instance.
2339
+ *
2340
+ * D11-005 (2026-05-12): three-tier fallback chain matching Python's
2341
+ * `_get_encryptor` (auth.py:33): explicit constructor arg > peer attribute
2342
+ * `config.encryptor` (set by embedders injecting forced-AES test fixtures
2343
+ * or shared instances) > fresh `new ConfigEncryptor()`. Previously TS
2344
+ * skipped the peer-attribute tier, silently giving embedders a different
2345
+ * encryptor than the one they wired on the config.
2346
+ */
2347
+ getEncryptor() {
2348
+ if (this._encryptor) return this._encryptor;
2349
+ const fromConfig = this.config.encryptor;
2350
+ if (fromConfig) return fromConfig;
2351
+ return new ConfigEncryptor();
2313
2352
  }
2314
2353
  /**
2315
2354
  * Retrieve the API key from the configured sources.
@@ -2327,11 +2366,11 @@ var init_auth = __esm({
2327
2366
  const strResult = String(result);
2328
2367
  if (strResult.startsWith("keyring:") || strResult.startsWith("enc:")) {
2329
2368
  try {
2330
- return await this.encryptor.retrieve(strResult, "auth.api_key");
2369
+ return await this.getEncryptor().retrieve(strResult, "auth.api_key");
2331
2370
  } catch (err) {
2332
2371
  if (err instanceof ConfigDecryptionError) {
2333
2372
  throw new AuthenticationError(
2334
- "Failed to decrypt stored API key. Re-configure with 'apcore-cli config set auth.api_key'."
2373
+ "Failed to decrypt stored API key. Re-store with 'apcli config set auth.api_key'."
2335
2374
  );
2336
2375
  }
2337
2376
  throw err;
@@ -2360,7 +2399,7 @@ var init_auth = __esm({
2360
2399
  }
2361
2400
  if (/[\r\n]/.test(key)) {
2362
2401
  throw new AuthenticationError(
2363
- "Malformed API key: contains invalid characters (CR/LF). Re-configure with 'apcore-cli config set auth.api_key'."
2402
+ "Malformed API key: contains invalid characters (CR/LF). Re-store with 'apcli config set auth.api_key'."
2364
2403
  );
2365
2404
  }
2366
2405
  headers.Authorization = `Bearer ${key.trim()}`;
@@ -2582,7 +2621,7 @@ function registerExecCommand(apcliGroup, registry, executor) {
2582
2621
  return;
2583
2622
  }
2584
2623
  let result;
2585
- if (opts.strategy && executor.callWithTrace) {
2624
+ if ((opts.trace || opts.strategy) && executor.callWithTrace) {
2586
2625
  const [res] = await executor.callWithTrace(moduleId, merged, { strategy: opts.strategy });
2587
2626
  result = res;
2588
2627
  } else {
@@ -3698,6 +3737,7 @@ __export(main_exports, {
3698
3737
  reconvertEnumValues: () => reconvertEnumValues,
3699
3738
  resolveIntOption: () => resolveIntOption,
3700
3739
  resolveStringOption: () => resolveStringOption,
3740
+ setAllOptionsHelp: () => setAllOptionsHelp,
3701
3741
  setDocsUrl: () => setDocsUrl,
3702
3742
  setVerboseHelp: () => setVerboseHelp,
3703
3743
  validateModuleId: () => validateModuleId
@@ -3706,14 +3746,17 @@ import { readFileSync as readFileSync3 } from "fs";
3706
3746
  import { fileURLToPath as fileURLToPath2 } from "url";
3707
3747
  import * as path5 from "path";
3708
3748
  import { Command as Command5, CommanderError, Option as Option4 } from "commander";
3749
+ function setAllOptionsHelp(allOptions) {
3750
+ verboseHelp = allOptions;
3751
+ }
3709
3752
  function setVerboseHelp(verbose) {
3710
- verboseHelp = verbose;
3753
+ setAllOptionsHelp(verbose);
3711
3754
  }
3712
3755
  function setDocsUrl(url) {
3713
3756
  docsUrl = url;
3714
3757
  }
3715
3758
  function hasVerboseFlag() {
3716
- return process.argv.includes("--verbose");
3759
+ return process.argv.includes("--all-options");
3717
3760
  }
3718
3761
  function resolveIntOption(cliValue, envValue, defaultValue) {
3719
3762
  if (cliValue !== void 0 && Number.isFinite(cliValue) && cliValue > 0) {
@@ -3788,7 +3831,7 @@ function emitErrorTty(e, exitCode) {
3788
3831
  Exit code: ${exitCode}
3789
3832
  `);
3790
3833
  }
3791
- function createCli(extensionsDirOrOpts, progName, verbose = false) {
3834
+ function createCli(extensionsDirOrOpts, progName, allOptions = false) {
3792
3835
  let extensionsDir;
3793
3836
  let registry;
3794
3837
  let executor;
@@ -3803,7 +3846,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
3803
3846
  if (typeof extensionsDirOrOpts === "object" && extensionsDirOrOpts !== null) {
3804
3847
  extensionsDir = extensionsDirOrOpts.extensionsDir;
3805
3848
  progName = extensionsDirOrOpts.progName ?? progName;
3806
- verbose = extensionsDirOrOpts.verbose ?? verbose;
3849
+ allOptions = extensionsDirOrOpts.allOptions ?? extensionsDirOrOpts.verbose ?? allOptions;
3807
3850
  app = extensionsDirOrOpts.app;
3808
3851
  registry = extensionsDirOrOpts.registry;
3809
3852
  executor = extensionsDirOrOpts.executor;
@@ -3817,7 +3860,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
3817
3860
  } else {
3818
3861
  extensionsDir = extensionsDirOrOpts;
3819
3862
  }
3820
- verboseHelp = verbose;
3863
+ verboseHelp = allOptions;
3821
3864
  registerConfigNamespace();
3822
3865
  try {
3823
3866
  const auditLogger = new AuditLogger();
@@ -3850,7 +3893,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
3850
3893
  }
3851
3894
  }
3852
3895
  const registryInjected = registry !== void 0;
3853
- 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)");
3896
+ 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)");
3854
3897
  if (appVersion) {
3855
3898
  program.version(appVersion, "-V, --version", "Print version");
3856
3899
  }
@@ -3921,7 +3964,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
3921
3964
  _registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exposureFilter);
3922
3965
  program.addHelpText("after", [
3923
3966
  "",
3924
- "Use --help --verbose to show all options (including built-in options).",
3967
+ "Use --help --all-options to show all options (including built-in options).",
3925
3968
  "Use --help --man to display a formatted man page."
3926
3969
  ].join("\n"));
3927
3970
  configureManHelp(program, resolvedProgName, appVersion ?? VERSION);
@@ -3958,7 +4001,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
3958
4001
  function _registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exposureFilter) {
3959
4002
  const emitUnwiredError = () => {
3960
4003
  process.stderr.write(
3961
- "Error: no apcore-js registry wired. In standalone mode, pass --extensions-dir <path> to enable module discovery.\n"
4004
+ "Error: no module registry wired. In standalone mode, pass --extensions-dir <path> to enable module discovery.\n"
3962
4005
  );
3963
4006
  process.exit(EXIT_CODES.CONFIG_INVALID);
3964
4007
  };
@@ -4072,9 +4115,9 @@ function main(progName) {
4072
4115
  verboseHelp = hasVerboseFlag();
4073
4116
  const program = createCli({
4074
4117
  progName,
4075
- verbose: verboseHelp,
4118
+ allOptions: verboseHelp,
4076
4119
  version: VERSION,
4077
- description: `${progName ?? "apcore-cli"} \u2014 execute apcore modules from the command line`
4120
+ description: `${progName ?? "apcore-cli"} \u2014 execute modules from the command line`
4078
4121
  });
4079
4122
  try {
4080
4123
  program.parse(process.argv);
@@ -4102,7 +4145,17 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
4102
4145
  if (inputSchema && typeof inputSchema === "object" && inputSchema.properties) {
4103
4146
  try {
4104
4147
  resolvedSchema = resolveRefs(inputSchema, 32, moduleId);
4105
- } catch {
4148
+ } catch (err) {
4149
+ if (err instanceof MaxDepthExceededError || err instanceof CircularRefError) {
4150
+ process.stderr.write(`Error: ${err.message}
4151
+ `);
4152
+ process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
4153
+ }
4154
+ if (err instanceof UnresolvableRefError) {
4155
+ process.stderr.write(`Error: ${err.message}
4156
+ `);
4157
+ process.exit(EXIT_CODES.SCHEMA_VALIDATION_ERROR);
4158
+ }
4106
4159
  resolvedSchema = inputSchema;
4107
4160
  }
4108
4161
  schemaOptions = schemaToCliOptions(resolvedSchema, helpTextMaxLength);
@@ -4147,7 +4200,7 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
4147
4200
  cmd.addOption(approvalTokenOpt);
4148
4201
  const footerParts = [];
4149
4202
  if (!verbose) {
4150
- footerParts.push("Use --verbose to show all options (including built-in apcore options).");
4203
+ footerParts.push("Use --all-options to show all options (including built-in options).");
4151
4204
  }
4152
4205
  if (docsUrl) {
4153
4206
  footerParts.push(`Docs: ${docsUrl}/commands/${effectiveCmdName}`);
@@ -4156,7 +4209,15 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
4156
4209
  cmd.addHelpText("after", "\n" + footerParts.join("\n") + "\n");
4157
4210
  }
4158
4211
  for (const opt of schemaOptions) {
4159
- if (opt.parseArg) {
4212
+ if (opt.isBooleanFlag) {
4213
+ const flagBase = opt.name.replace(/_/g, "-");
4214
+ cmd.addOption(
4215
+ new Option4(`--${flagBase}`, opt.description).default(
4216
+ opt.defaultValue
4217
+ )
4218
+ );
4219
+ cmd.addOption(new Option4(`--no-${flagBase}`).hideHelp());
4220
+ } else if (opt.parseArg) {
4160
4221
  cmd.option(opt.flags, opt.description, opt.parseArg, opt.defaultValue);
4161
4222
  } else {
4162
4223
  cmd.option(opt.flags, opt.description, opt.defaultValue);
@@ -4180,24 +4241,12 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
4180
4241
  );
4181
4242
  const approvalToken = options.approvalToken;
4182
4243
  const schemaKwargs = {};
4183
- const builtinKeys = /* @__PURE__ */ new Set([
4184
- "input",
4185
- "yes",
4186
- "largeInput",
4187
- "format",
4188
- "fields",
4189
- "sandbox",
4190
- "verbose",
4191
- "dryRun",
4192
- "trace",
4193
- "stream",
4194
- "strategy",
4195
- "approvalTimeout",
4196
- "approvalToken"
4197
- ]);
4198
- for (const [k, v] of Object.entries(options)) {
4199
- if (!builtinKeys.has(k)) {
4200
- schemaKwargs[k] = v;
4244
+ for (const opt of schemaOptions) {
4245
+ const commanderKey = opt.name.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
4246
+ if (commanderKey in options) {
4247
+ schemaKwargs[opt.name] = options[commanderKey];
4248
+ } else if (opt.name in options) {
4249
+ schemaKwargs[opt.name] = options[opt.name];
4201
4250
  }
4202
4251
  }
4203
4252
  let merged = {};