apcore-cli 0.8.1 → 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.
package/dist/index.d.ts CHANGED
@@ -69,6 +69,13 @@ type ApcliConfig = boolean | {
69
69
  exclude?: string[];
70
70
  disableEnv?: boolean;
71
71
  };
72
+ /**
73
+ * Default name of the built-in command group. Overridable per ApcliGroup
74
+ * instance via the `name` constructor option, or via createCli's
75
+ * `builtinGroupName` option. Cross-SDK parity with Python
76
+ * `DEFAULT_BUILTIN_GROUP_NAME` (2026-05-08).
77
+ */
78
+ declare const DEFAULT_BUILTIN_GROUP_NAME = "apcli";
72
79
  /**
73
80
  * Set of group names reserved by apcore-cli when no rename is configured.
74
81
  * Default mirrors {@link DEFAULT_BUILTIN_GROUP_NAME}; when `builtinGroupName`
@@ -76,6 +83,16 @@ type ApcliConfig = boolean | {
76
83
  * is applied per-instance during the cli.ts collision check.
77
84
  */
78
85
  declare const RESERVED_GROUP_NAMES: ReadonlySet<string>;
86
+ /**
87
+ * Canonical set of apcli subcommand names.
88
+ *
89
+ * Declarative mirror of the registration TABLE in `src/main.ts`
90
+ * (`_registerApcliSubcommands`). Used by `_normalizeList` to warn on
91
+ * unknown entries in include/exclude lists (spec §7 error table / T-APCLI-25).
92
+ *
93
+ * Keep in sync with main.ts TABLE if subcommands are added or removed.
94
+ */
95
+ declare const APCLI_SUBCOMMAND_NAMES: ReadonlySet<string>;
79
96
  /**
80
97
  * Visibility configuration for the built-in `apcli` command group.
81
98
  *
@@ -178,7 +195,7 @@ declare class ApcliGroup {
178
195
  * Protocol spec: CLI command structure & lazy loading
179
196
  */
180
197
 
181
- /** Placeholder for apcore-js Registry. */
198
+ /** CLI-internal Registry shim (see D9-W2 note above). */
182
199
  interface Registry {
183
200
  listModules(): ModuleDescriptor[];
184
201
  getModule(moduleId: string): ModuleDescriptor | null;
@@ -375,7 +392,9 @@ declare class GroupedModuleGroup extends LazyModuleGroup {
375
392
  */
376
393
  declare function validateModuleId(moduleId: string): void;
377
394
 
378
- /** Set the verbose help flag. When false, built-in options are hidden from help. */
395
+ /** Set the all-options help flag. When false, built-in options are hidden from help. */
396
+ declare function setAllOptionsHelp(allOptions: boolean): void;
397
+ /** @deprecated Use {@link setAllOptionsHelp} instead. Kept for backward compatibility. */
379
398
  declare function setVerboseHelp(verbose: boolean): void;
380
399
  /**
381
400
  * Set the base URL for online documentation links shown in help and man pages.
@@ -417,6 +436,12 @@ interface APCore {
417
436
  interface CreateCliOptions {
418
437
  extensionsDir?: string;
419
438
  progName?: string;
439
+ /**
440
+ * Show all options in help output (controls `--all-options` behaviour;
441
+ * parameter was named `verbose` prior to v0.9.0).
442
+ */
443
+ allOptions?: boolean;
444
+ /** @deprecated Use {@link allOptions} instead. Kept for backward compatibility with pre-v0.9.0 callers. */
420
445
  verbose?: boolean;
421
446
  /**
422
447
  * APCore unified client instance (apcore-js >= 0.18.0).
@@ -493,9 +518,10 @@ interface CreateCliOptions {
493
518
  *
494
519
  * @param extensionsDirOrOpts Path to extensions directory, or a CreateCliOptions object.
495
520
  * @param progName Program name shown in help (default: apcore-cli)
496
- * @param verbose Show verbose help output
521
+ * @param allOptions Show all options in help output (controls `--all-options` behaviour;
522
+ * parameter was named `verbose` prior to v0.9.0)
497
523
  */
498
- declare function createCli(extensionsDirOrOpts?: string | CreateCliOptions, progName?: string, verbose?: boolean): Command;
524
+ declare function createCli(extensionsDirOrOpts?: string | CreateCliOptions, progName?: string, allOptions?: boolean): Command;
499
525
  /** Options bag for {@link applyToolkitIntegration}. */
500
526
  interface ApplyToolkitIntegrationOptions {
501
527
  /**
@@ -826,6 +852,18 @@ declare class ApprovalDeniedError extends Error {
826
852
  declare class SchemaValidationError extends Error {
827
853
  constructor(message?: string);
828
854
  }
855
+ /** Thrown when $ref resolution depth exceeds the configured maximum. */
856
+ declare class MaxDepthExceededError extends Error {
857
+ constructor(message?: string);
858
+ }
859
+ /** Thrown when a circular $ref is detected during schema resolution. */
860
+ declare class CircularRefError extends Error {
861
+ constructor(message?: string);
862
+ }
863
+ /** Thrown when a $ref target cannot be found in $defs/definitions. */
864
+ declare class UnresolvableRefError extends Error {
865
+ constructor(message?: string);
866
+ }
829
867
  /** Thrown when a module is not found. */
830
868
  declare class ModuleNotFoundError extends Error {
831
869
  constructor(message?: string);
@@ -950,8 +988,19 @@ declare class ConfigEncryptor {
950
988
  */
951
989
  declare class AuthProvider {
952
990
  private readonly config;
953
- private readonly encryptor;
991
+ private readonly _encryptor?;
954
992
  constructor(config: ConfigResolver, encryptor?: ConfigEncryptor);
993
+ /**
994
+ * Resolve the active ConfigEncryptor instance.
995
+ *
996
+ * D11-005 (2026-05-12): three-tier fallback chain matching Python's
997
+ * `_get_encryptor` (auth.py:33): explicit constructor arg > peer attribute
998
+ * `config.encryptor` (set by embedders injecting forced-AES test fixtures
999
+ * or shared instances) > fresh `new ConfigEncryptor()`. Previously TS
1000
+ * skipped the peer-attribute tier, silently giving embedders a different
1001
+ * encryptor than the one they wired on the config.
1002
+ */
1003
+ private getEncryptor;
955
1004
  /**
956
1005
  * Retrieve the API key from the configured sources.
957
1006
  * Handles keyring: and enc: prefixes via ConfigEncryptor.
@@ -1027,4 +1076,4 @@ declare class Sandbox {
1027
1076
  private _sandboxedExecute;
1028
1077
  }
1029
1078
 
1030
- export { type APCore, type ApcliConfig, ApcliGroup, ApcliGroupError, type ApcliMode, type ApplyToolkitIntegrationOptions, ApprovalDeniedError, ApprovalTimeoutError, AuditLogger, AuthProvider, AuthenticationError, CliApprovalHandler, ConfigDecryptionError, ConfigEncryptor, ConfigResolver, type CreateCliOptions, DEFAULTS, EXIT_CODES, type Executor, type ExitCode, ExposureFilter, GroupedModuleGroup, LazyGroup, LazyModuleGroup, type ModuleDescriptor, ModuleExecutionError, ModuleNotFoundError, type OptionConfig, type PipelineTrace, type PipelineTraceStep, type PreflightCheck, type PreflightResult, RESERVED_GROUP_NAMES, type Registry, Sandbox, SchemaValidationError, type StrategyInfo, type StrategyStep, applyToolkitIntegration, buildModuleCommand, checkApproval, collectInput, configureManHelp, createCli, exitCodeForError, formatExecResult, formatModuleDetail, formatModuleList, getAuditLogger, getLogLevel, main, reconvertEnumValues, registerCompletionCommand, registerConfigCommand, registerConfigNamespace, registerDescribeCommand, registerDisableCommand, registerEnableCommand, registerExecCommand, registerHealthCommand, registerInitCommand, registerListCommand, registerPipelineCommand, registerReloadCommand, registerUsageCommand, registerValidateCommand, resolveFormat, resolveRefs, schemaToCliOptions, setAuditLogger, setDocsUrl, setLogLevel, setVerboseHelp, validateModuleId };
1079
+ export { APCLI_SUBCOMMAND_NAMES, type APCore, type ApcliConfig, ApcliGroup, ApcliGroupError, type ApcliMode, type ApplyToolkitIntegrationOptions, ApprovalDeniedError, ApprovalTimeoutError, AuditLogger, AuthProvider, AuthenticationError, CircularRefError, CliApprovalHandler, ConfigDecryptionError, ConfigEncryptor, ConfigResolver, type CreateCliOptions, DEFAULTS, DEFAULT_BUILTIN_GROUP_NAME, EXIT_CODES, type Executor, type ExitCode, ExposureFilter, GroupedModuleGroup, LazyGroup, LazyModuleGroup, MaxDepthExceededError, type ModuleDescriptor, ModuleExecutionError, ModuleNotFoundError, type OptionConfig, type PipelineTrace, type PipelineTraceStep, type PreflightCheck, type PreflightResult, RESERVED_GROUP_NAMES, type Registry, Sandbox, SchemaValidationError, type StrategyInfo, type StrategyStep, UnresolvableRefError, applyToolkitIntegration, buildModuleCommand, checkApproval, collectInput, configureManHelp, createCli, exitCodeForError, formatExecResult, formatModuleDetail, formatModuleList, getAuditLogger, getLogLevel, main, reconvertEnumValues, registerCompletionCommand, registerConfigCommand, registerConfigNamespace, registerDescribeCommand, registerDisableCommand, registerEnableCommand, registerExecCommand, registerHealthCommand, registerInitCommand, registerListCommand, registerPipelineCommand, registerReloadCommand, registerUsageCommand, registerValidateCommand, resolveFormat, resolveRefs, schemaToCliOptions, setAllOptionsHelp, setAuditLogger, setDocsUrl, setLogLevel, setVerboseHelp, validateModuleId };
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";
@@ -114,6 +120,24 @@ var init_errors = __esm({
114
120
  this.name = "SchemaValidationError";
115
121
  }
116
122
  };
123
+ MaxDepthExceededError = class extends Error {
124
+ constructor(message = "Schema $ref resolution depth exceeded") {
125
+ super(message);
126
+ this.name = "MaxDepthExceededError";
127
+ }
128
+ };
129
+ CircularRefError = class extends Error {
130
+ constructor(message = "Circular $ref detected in schema") {
131
+ super(message);
132
+ this.name = "CircularRefError";
133
+ }
134
+ };
135
+ UnresolvableRefError = class extends Error {
136
+ constructor(message = "Unresolvable $ref in schema") {
137
+ super(message);
138
+ this.name = "UnresolvableRefError";
139
+ }
140
+ };
117
141
  ModuleNotFoundError = class extends Error {
118
142
  constructor(message = "Module not found") {
119
143
  super(message);
@@ -406,7 +430,7 @@ var init_config_encryptor = __esm({
406
430
  _ConfigEncryptor.weakFallbackWarned = true;
407
431
  }
408
432
  const hostname2 = os3.hostname();
409
- const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
433
+ const username = process.env.USER ?? process.env.LOGNAME ?? process.env.USERNAME ?? "unknown";
410
434
  const material = `${hostname2}:${username}`;
411
435
  return crypto2.pbkdf2Sync(material, salt, PBKDF2_ITERATIONS, 32, "sha256");
412
436
  }
@@ -438,7 +462,7 @@ var init_config_encryptor = __esm({
438
462
  const tag = data.subarray(12, 28);
439
463
  const ct = data.subarray(28);
440
464
  const hostname2 = os3.hostname();
441
- const username = process.env.USER ?? process.env.USERNAME ?? "unknown";
465
+ const username = process.env.USER ?? process.env.LOGNAME ?? process.env.USERNAME ?? "unknown";
442
466
  const passphrase = process.env.APCORE_CLI_CONFIG_PASSPHRASE;
443
467
  const materials = passphrase ? [passphrase, `${hostname2}:${username}`] : [`${hostname2}:${username}`];
444
468
  for (const material of materials) {
@@ -468,10 +492,26 @@ var init_auth = __esm({
468
492
  init_config_encryptor();
469
493
  AuthProvider = class {
470
494
  config;
471
- encryptor;
495
+ _encryptor;
472
496
  constructor(config, encryptor) {
473
497
  this.config = config;
474
- this.encryptor = encryptor ?? new ConfigEncryptor();
498
+ this._encryptor = encryptor;
499
+ }
500
+ /**
501
+ * Resolve the active ConfigEncryptor instance.
502
+ *
503
+ * D11-005 (2026-05-12): three-tier fallback chain matching Python's
504
+ * `_get_encryptor` (auth.py:33): explicit constructor arg > peer attribute
505
+ * `config.encryptor` (set by embedders injecting forced-AES test fixtures
506
+ * or shared instances) > fresh `new ConfigEncryptor()`. Previously TS
507
+ * skipped the peer-attribute tier, silently giving embedders a different
508
+ * encryptor than the one they wired on the config.
509
+ */
510
+ getEncryptor() {
511
+ if (this._encryptor) return this._encryptor;
512
+ const fromConfig = this.config.encryptor;
513
+ if (fromConfig) return fromConfig;
514
+ return new ConfigEncryptor();
475
515
  }
476
516
  /**
477
517
  * Retrieve the API key from the configured sources.
@@ -489,11 +529,11 @@ var init_auth = __esm({
489
529
  const strResult = String(result);
490
530
  if (strResult.startsWith("keyring:") || strResult.startsWith("enc:")) {
491
531
  try {
492
- return await this.encryptor.retrieve(strResult, "auth.api_key");
532
+ return await this.getEncryptor().retrieve(strResult, "auth.api_key");
493
533
  } catch (err) {
494
534
  if (err instanceof ConfigDecryptionError) {
495
535
  throw new AuthenticationError(
496
- "Failed to decrypt stored API key. Re-configure with 'apcore-cli config set auth.api_key'."
536
+ "Failed to decrypt stored API key. Re-store with 'apcli config set auth.api_key'."
497
537
  );
498
538
  }
499
539
  throw err;
@@ -522,7 +562,7 @@ var init_auth = __esm({
522
562
  }
523
563
  if (/[\r\n]/.test(key)) {
524
564
  throw new AuthenticationError(
525
- "Malformed API key: contains invalid characters (CR/LF). Re-configure with 'apcore-cli config set auth.api_key'."
565
+ "Malformed API key: contains invalid characters (CR/LF). Re-store with 'apcli config set auth.api_key'."
526
566
  );
527
567
  }
528
568
  headers.Authorization = `Bearer ${key.trim()}`;
@@ -550,7 +590,7 @@ import { join as join4, resolve as resolvePath } from "path";
550
590
  function buildSandboxEnv(tmpDir) {
551
591
  const env = {};
552
592
  for (const key of SANDBOX_ALLOW_KEYS) {
553
- if (process.env[key]) env[key] = process.env[key];
593
+ if (process.env[key] !== void 0) env[key] = process.env[key];
554
594
  }
555
595
  for (const [key, val] of Object.entries(process.env)) {
556
596
  if (key.startsWith(SANDBOX_ALLOW_PREFIX) && !key.startsWith(SANDBOX_DENY_PREFIX) && !SANDBOX_DENY_KEYS.includes(key)) {
@@ -655,11 +695,20 @@ var init_sandbox = __esm({
655
695
  }
656
696
  stderr += chunk.toString();
657
697
  });
698
+ child.stdin.on("error", () => {
699
+ });
658
700
  child.stdin.write(JSON.stringify(inputData));
659
701
  child.stdin.end();
660
702
  return new Promise((resolve2, reject) => {
703
+ const cleanup = () => {
704
+ try {
705
+ rmSync(tmpDir, { recursive: true, force: true });
706
+ } catch {
707
+ }
708
+ };
661
709
  const timer = setTimeout(() => {
662
710
  child.kill("SIGKILL");
711
+ cleanup();
663
712
  reject(
664
713
  new ModuleExecutionError(
665
714
  `Sandbox module '${moduleId}' timed out after ${this.timeoutSeconds}s.`
@@ -668,10 +717,7 @@ var init_sandbox = __esm({
668
717
  }, this.timeoutSeconds * 1e3);
669
718
  child.on("close", (code) => {
670
719
  clearTimeout(timer);
671
- try {
672
- rmSync(tmpDir, { recursive: true, force: true });
673
- } catch {
674
- }
720
+ cleanup();
675
721
  if (sizeExceeded) {
676
722
  const limitMiB = Math.floor(outputCap / (1024 * 1024));
677
723
  reject(new ModuleExecutionError(
@@ -695,6 +741,7 @@ var init_sandbox = __esm({
695
741
  });
696
742
  child.on("error", (err) => {
697
743
  clearTimeout(timer);
744
+ cleanup();
698
745
  reject(new ModuleExecutionError(`Failed to spawn sandbox process: ${err.message}`));
699
746
  });
700
747
  });
@@ -761,27 +808,21 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
761
808
  if ("$ref" in obj) {
762
809
  const refPath = obj.$ref;
763
810
  if (depth >= maxDepth) {
764
- process.stderr.write(
765
- `Error: $ref resolution depth exceeded maximum of ${maxDepth} for module '${moduleId}'.
766
- `
811
+ throw new MaxDepthExceededError(
812
+ `$ref resolution depth exceeded maximum of ${maxDepth} for module '${moduleId}'.`
767
813
  );
768
- process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
769
814
  }
770
815
  if (visited.has(refPath)) {
771
- process.stderr.write(
772
- `Error: Circular $ref detected in schema for module '${moduleId}' at path '${refPath}'.
773
- `
816
+ throw new CircularRefError(
817
+ `Circular $ref detected in schema for module '${moduleId}' at path '${refPath}'.`
774
818
  );
775
- process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
776
819
  }
777
820
  const parts = refPath.split("/");
778
821
  const key = parts[parts.length - 1];
779
822
  if (!(key in defs)) {
780
- process.stderr.write(
781
- `Error: Unresolvable $ref '${refPath}' in schema for module '${moduleId}'.
782
- `
823
+ throw new UnresolvableRefError(
824
+ `Unresolvable $ref '${refPath}' in schema for module '${moduleId}'.`
783
825
  );
784
- process.exit(EXIT_CODES.SCHEMA_VALIDATION_ERROR);
785
826
  }
786
827
  const newVisited = new Set(visited);
787
828
  newVisited.add(refPath);
@@ -882,17 +923,12 @@ function resolveNode(node, defs, visited, depth, maxDepth, moduleId) {
882
923
  return merged;
883
924
  }
884
925
  }
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
- );
926
+ for (const [k, v] of Object.entries(obj)) {
927
+ if (k === "allOf" || k === "anyOf" || k === "oneOf" || k === "$ref") {
928
+ continue;
929
+ }
930
+ if (typeof v === "object" && v !== null && !Array.isArray(v)) {
931
+ obj[k] = resolveNode(v, defs, visited, depth, maxDepth, moduleId);
896
932
  }
897
933
  }
898
934
  return obj;
@@ -941,7 +977,7 @@ var RESERVED_NAMES = /* @__PURE__ */ new Set([
941
977
  "format",
942
978
  "fields",
943
979
  "sandbox",
944
- "verbose",
980
+ "all_options",
945
981
  "dry_run",
946
982
  "trace",
947
983
  "stream",
@@ -1089,6 +1125,14 @@ var CliApprovalHandler = class {
1089
1125
  }
1090
1126
  async requestApproval(request) {
1091
1127
  const moduleId = request.module_id ?? "unknown";
1128
+ if (request.requires_approval === false) {
1129
+ return { status: "approved", approved_by: "not_required" };
1130
+ }
1131
+ const moduleDef = request.module_def;
1132
+ const annotationsForCheck = moduleDef?.annotations;
1133
+ if (annotationsForCheck && annotationsForCheck.requires_approval === false) {
1134
+ return { status: "approved", approved_by: "not_required" };
1135
+ }
1092
1136
  if (this.autoApprove) {
1093
1137
  return { status: "approved", approved_by: "auto_approve" };
1094
1138
  }
@@ -1197,7 +1241,8 @@ async function promptWithTimeout(moduleDef, timeout) {
1197
1241
  init_esm_shims();
1198
1242
  init_errors();
1199
1243
  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";
1244
+ import { formatCsv, formatJsonl } from "apcore-toolkit";
1245
+ 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
1246
  function descriptorToScanned(m) {
1202
1247
  const metadata = m.metadata ?? {};
1203
1248
  const display = metadata["display"] ?? null;
@@ -1218,11 +1263,6 @@ function descriptorToScanned(m) {
1218
1263
  warnings: []
1219
1264
  };
1220
1265
  }
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
1266
  function resolveFormat(explicitFormat) {
1227
1267
  if (explicitFormat !== void 0) {
1228
1268
  return explicitFormat;
@@ -1425,30 +1465,18 @@ function formatExecResult(result, format, fields) {
1425
1465
  }
1426
1466
  const effective = resolveFormat(format);
1427
1467
  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");
1468
+ const rows = toRowsForTabular(effective_result);
1469
+ if (rows !== null) {
1470
+ process.stdout.write(formatCsv(rows));
1442
1471
  } else {
1443
1472
  process.stdout.write(JSON.stringify(effective_result) + "\n");
1444
1473
  }
1445
1474
  } else if (effective === "yaml") {
1446
1475
  process.stdout.write(yaml.dump(effective_result, { lineWidth: -1 }));
1447
1476
  } 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
- }
1477
+ const rows = toRowsForTabular(effective_result);
1478
+ if (rows !== null) {
1479
+ process.stdout.write(formatJsonl(rows));
1452
1480
  } else {
1453
1481
  process.stdout.write(JSON.stringify(effective_result) + "\n");
1454
1482
  }
@@ -1465,11 +1493,19 @@ function formatExecResult(result, format, fields) {
1465
1493
  process.stdout.write(String(effective_result) + "\n");
1466
1494
  }
1467
1495
  }
1468
- function escapeCsvField(value) {
1469
- if (value.includes(",") || value.includes('"') || value.includes("\n") || value.includes("\r")) {
1470
- return '"' + value.replace(/"/g, '""') + '"';
1496
+ function toRowsForTabular(value) {
1497
+ if (value === null || value === void 0) return null;
1498
+ if (Array.isArray(value)) {
1499
+ if (value.length === 0) return null;
1500
+ if (!value.every((item) => typeof item === "object" && item !== null && !Array.isArray(item))) {
1501
+ return null;
1502
+ }
1503
+ return value;
1504
+ }
1505
+ if (typeof value === "object") {
1506
+ return [value];
1471
1507
  }
1472
- return value;
1508
+ return null;
1473
1509
  }
1474
1510
  function formatPreflightResult(result, format) {
1475
1511
  const resolved = resolveFormat(format);
@@ -1607,7 +1643,7 @@ function renderTemplate(template, context) {
1607
1643
  return result;
1608
1644
  }
1609
1645
  function registerInitCommand(cli) {
1610
- const initGroup = cli.command("init").description("Scaffold new apcore modules.");
1646
+ const initGroup = cli.command("init").description("Scaffold new modules.");
1611
1647
  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
1648
  "--style <style>",
1613
1649
  "Module style: decorator (@module), convention (plain function), or binding (YAML).",
@@ -2135,7 +2171,7 @@ function buildProgramManPage(program, progName, version, description, docsUrl2)
2135
2171
  s.push(".SH ENVIRONMENT");
2136
2172
  s.push(".TP");
2137
2173
  s.push("\\fBAPCORE_EXTENSIONS_ROOT\\fR");
2138
- s.push("Path to the apcore extensions directory.");
2174
+ s.push("Path to the extensions directory.");
2139
2175
  s.push(".TP");
2140
2176
  s.push("\\fBAPCORE_CLI_AUTO_APPROVE\\fR");
2141
2177
  s.push("Set to \\fB1\\fR to bypass approval prompts.");
@@ -2160,7 +2196,7 @@ function buildProgramManPage(program, progName, version, description, docsUrl2)
2160
2196
  ${meaning}`);
2161
2197
  }
2162
2198
  s.push(".SH SEE ALSO");
2163
- s.push(`\\fB${progName} \\-\\-help \\-\\-verbose\\fR for full option list.`);
2199
+ s.push(`\\fB${progName} \\-\\-help \\-\\-all\\-options\\fR for full option list.`);
2164
2200
  if (docsUrl2) {
2165
2201
  s.push(`.PP
2166
2202
  Full documentation at \\fI${roffEscape(docsUrl2)}\\fR`);
@@ -2512,7 +2548,7 @@ function registerExecCommand(apcliGroup, registry, executor) {
2512
2548
  return;
2513
2549
  }
2514
2550
  let result;
2515
- if (opts.strategy && executor.callWithTrace) {
2551
+ if ((opts.trace || opts.strategy) && executor.callWithTrace) {
2516
2552
  const [res] = await executor.callWithTrace(moduleId, merged, { strategy: opts.strategy });
2517
2553
  result = res;
2518
2554
  } else {
@@ -3573,15 +3609,18 @@ function validateModuleId(moduleId) {
3573
3609
  // src/main.ts
3574
3610
  var __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
3575
3611
  var verboseHelp = false;
3612
+ function setAllOptionsHelp(allOptions) {
3613
+ verboseHelp = allOptions;
3614
+ }
3576
3615
  function setVerboseHelp(verbose) {
3577
- verboseHelp = verbose;
3616
+ setAllOptionsHelp(verbose);
3578
3617
  }
3579
3618
  var docsUrl = null;
3580
3619
  function setDocsUrl(url) {
3581
3620
  docsUrl = url;
3582
3621
  }
3583
3622
  function hasVerboseFlag() {
3584
- return process.argv.includes("--verbose");
3623
+ return process.argv.includes("--all-options");
3585
3624
  }
3586
3625
  function resolveIntOption(cliValue, envValue, defaultValue) {
3587
3626
  if (cliValue !== void 0 && Number.isFinite(cliValue) && cliValue > 0) {
@@ -3662,7 +3701,7 @@ function emitErrorTty(e, exitCode) {
3662
3701
  Exit code: ${exitCode}
3663
3702
  `);
3664
3703
  }
3665
- function createCli(extensionsDirOrOpts, progName, verbose = false) {
3704
+ function createCli(extensionsDirOrOpts, progName, allOptions = false) {
3666
3705
  let extensionsDir;
3667
3706
  let registry;
3668
3707
  let executor;
@@ -3677,7 +3716,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
3677
3716
  if (typeof extensionsDirOrOpts === "object" && extensionsDirOrOpts !== null) {
3678
3717
  extensionsDir = extensionsDirOrOpts.extensionsDir;
3679
3718
  progName = extensionsDirOrOpts.progName ?? progName;
3680
- verbose = extensionsDirOrOpts.verbose ?? verbose;
3719
+ allOptions = extensionsDirOrOpts.allOptions ?? extensionsDirOrOpts.verbose ?? allOptions;
3681
3720
  app = extensionsDirOrOpts.app;
3682
3721
  registry = extensionsDirOrOpts.registry;
3683
3722
  executor = extensionsDirOrOpts.executor;
@@ -3691,7 +3730,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
3691
3730
  } else {
3692
3731
  extensionsDir = extensionsDirOrOpts;
3693
3732
  }
3694
- verboseHelp = verbose;
3733
+ verboseHelp = allOptions;
3695
3734
  registerConfigNamespace();
3696
3735
  try {
3697
3736
  const auditLogger = new AuditLogger();
@@ -3724,7 +3763,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
3724
3763
  }
3725
3764
  }
3726
3765
  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)");
3766
+ 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
3767
  if (appVersion) {
3729
3768
  program.version(appVersion, "-V, --version", "Print version");
3730
3769
  }
@@ -3795,7 +3834,7 @@ function createCli(extensionsDirOrOpts, progName, verbose = false) {
3795
3834
  _registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exposureFilter);
3796
3835
  program.addHelpText("after", [
3797
3836
  "",
3798
- "Use --help --verbose to show all options (including built-in options).",
3837
+ "Use --help --all-options to show all options (including built-in options).",
3799
3838
  "Use --help --man to display a formatted man page."
3800
3839
  ].join("\n"));
3801
3840
  configureManHelp(program, resolvedProgName, appVersion ?? VERSION);
@@ -3833,7 +3872,7 @@ var _ALWAYS_REGISTERED = /* @__PURE__ */ new Set(["exec"]);
3833
3872
  function _registerApcliSubcommands(apcliGroup, apcliCfg, registry, executor, exposureFilter) {
3834
3873
  const emitUnwiredError = () => {
3835
3874
  process.stderr.write(
3836
- "Error: no apcore-js registry wired. In standalone mode, pass --extensions-dir <path> to enable module discovery.\n"
3875
+ "Error: no module registry wired. In standalone mode, pass --extensions-dir <path> to enable module discovery.\n"
3837
3876
  );
3838
3877
  process.exit(EXIT_CODES.CONFIG_INVALID);
3839
3878
  };
@@ -3945,9 +3984,9 @@ function main(progName) {
3945
3984
  verboseHelp = hasVerboseFlag();
3946
3985
  const program = createCli({
3947
3986
  progName,
3948
- verbose: verboseHelp,
3987
+ allOptions: verboseHelp,
3949
3988
  version: VERSION,
3950
- description: `${progName ?? "apcore-cli"} \u2014 execute apcore modules from the command line`
3989
+ description: `${progName ?? "apcore-cli"} \u2014 execute modules from the command line`
3951
3990
  });
3952
3991
  try {
3953
3992
  program.parse(process.argv);
@@ -3975,7 +4014,17 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
3975
4014
  if (inputSchema && typeof inputSchema === "object" && inputSchema.properties) {
3976
4015
  try {
3977
4016
  resolvedSchema = resolveRefs(inputSchema, 32, moduleId);
3978
- } catch {
4017
+ } catch (err) {
4018
+ if (err instanceof MaxDepthExceededError || err instanceof CircularRefError) {
4019
+ process.stderr.write(`Error: ${err.message}
4020
+ `);
4021
+ process.exit(EXIT_CODES.SCHEMA_CIRCULAR_REF);
4022
+ }
4023
+ if (err instanceof UnresolvableRefError) {
4024
+ process.stderr.write(`Error: ${err.message}
4025
+ `);
4026
+ process.exit(EXIT_CODES.SCHEMA_VALIDATION_ERROR);
4027
+ }
3979
4028
  resolvedSchema = inputSchema;
3980
4029
  }
3981
4030
  schemaOptions = schemaToCliOptions(resolvedSchema, helpTextMaxLength);
@@ -4020,7 +4069,7 @@ function buildModuleCommand(moduleDef, executor, helpTextMaxLength = 1e3, cmdNam
4020
4069
  cmd.addOption(approvalTokenOpt);
4021
4070
  const footerParts = [];
4022
4071
  if (!verbose) {
4023
- footerParts.push("Use --verbose to show all options (including built-in apcore options).");
4072
+ footerParts.push("Use --all-options to show all options (including built-in options).");
4024
4073
  }
4025
4074
  if (docsUrl) {
4026
4075
  footerParts.push(`Docs: ${docsUrl}/commands/${effectiveCmdName}`);
@@ -4669,6 +4718,7 @@ init_errors();
4669
4718
  init_logger();
4670
4719
  init_security();
4671
4720
  export {
4721
+ APCLI_SUBCOMMAND_NAMES,
4672
4722
  ApcliGroup,
4673
4723
  ApcliGroupError,
4674
4724
  ApprovalDeniedError,
@@ -4676,21 +4726,25 @@ export {
4676
4726
  AuditLogger,
4677
4727
  AuthProvider,
4678
4728
  AuthenticationError,
4729
+ CircularRefError,
4679
4730
  CliApprovalHandler,
4680
4731
  ConfigDecryptionError,
4681
4732
  ConfigEncryptor,
4682
4733
  ConfigResolver,
4683
4734
  DEFAULTS,
4735
+ DEFAULT_BUILTIN_GROUP_NAME,
4684
4736
  EXIT_CODES,
4685
4737
  ExposureFilter,
4686
4738
  GroupedModuleGroup,
4687
4739
  LazyGroup,
4688
4740
  LazyModuleGroup,
4741
+ MaxDepthExceededError,
4689
4742
  ModuleExecutionError,
4690
4743
  ModuleNotFoundError,
4691
4744
  RESERVED_GROUP_NAMES,
4692
4745
  Sandbox,
4693
4746
  SchemaValidationError,
4747
+ UnresolvableRefError,
4694
4748
  applyToolkitIntegration,
4695
4749
  buildModuleCommand,
4696
4750
  checkApproval,
@@ -4722,6 +4776,7 @@ export {
4722
4776
  resolveFormat,
4723
4777
  resolveRefs,
4724
4778
  schemaToCliOptions,
4779
+ setAllOptionsHelp,
4725
4780
  setAuditLogger,
4726
4781
  setDocsUrl,
4727
4782
  setLogLevel,