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/CHANGELOG.md +52 -0
- package/README.md +16 -12
- package/dist/bin/apcore-cli.js +135 -81
- package/dist/bin/apcore-cli.js.map +1 -1
- package/dist/index.d.ts +55 -6
- package/dist/index.js +136 -81
- package/dist/index.js.map +1 -1
- package/package.json +3 -8
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
|
-
/**
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
495
|
+
_encryptor;
|
|
472
496
|
constructor(config, encryptor) {
|
|
473
497
|
this.config = config;
|
|
474
|
-
this.
|
|
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.
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
765
|
-
|
|
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
|
-
|
|
772
|
-
`
|
|
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
|
-
|
|
781
|
-
`
|
|
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
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
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
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
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");
|
|
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
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
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
|
|
1469
|
-
if (value
|
|
1470
|
-
|
|
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
|
|
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
|
|
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
|
|
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 \\-\\-
|
|
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
|
-
|
|
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("--
|
|
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,
|
|
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
|
-
|
|
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 =
|
|
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("--
|
|
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 --
|
|
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
|
|
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
|
-
|
|
3987
|
+
allOptions: verboseHelp,
|
|
3949
3988
|
version: VERSION,
|
|
3950
|
-
description: `${progName ?? "apcore-cli"} \u2014 execute
|
|
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 --
|
|
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,
|