apcore-cli 0.6.0 → 0.7.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
@@ -1,5 +1,146 @@
1
1
  import { Command } from 'commander';
2
2
 
3
+ /**
4
+ * Determines which modules are exposed as CLI commands.
5
+ *
6
+ * Filtering modes:
7
+ * - `all`: every discovered module becomes a CLI command (default).
8
+ * - `include`: only modules matching at least one include pattern are exposed.
9
+ * - `exclude`: all modules are exposed except those matching any exclude pattern.
10
+ */
11
+ declare class ExposureFilter {
12
+ static readonly VALID_MODES: readonly ["all", "include", "exclude", "none"];
13
+ readonly _mode: string;
14
+ private readonly _compiledInclude;
15
+ private readonly _compiledExclude;
16
+ constructor(mode?: string, include?: string[], exclude?: string[]);
17
+ /** Return true if the module should be exposed as a CLI command. */
18
+ isExposed(moduleId: string): boolean;
19
+ /** Partition moduleIds into [exposed, hidden] lists. */
20
+ filterModules(moduleIds: string[]): [string[], string[]];
21
+ /**
22
+ * Create an ExposureFilter from a parsed config dict.
23
+ *
24
+ * Expected: `{ expose: { mode: "include", include: ["admin.*"] } }`
25
+ */
26
+ static fromConfig(config: Record<string, unknown>): ExposureFilter;
27
+ }
28
+
29
+ /**
30
+ * Built-in Command Group (FE-13).
31
+ *
32
+ * Encapsulates visibility resolution and subcommand filtering for the
33
+ * reserved `apcli` group. Instantiated once by createCli() and attached
34
+ * to the root command.
35
+ *
36
+ * Shape mirrors `src/exposure.ts` ExposureFilter: private constructor,
37
+ * named static factories, and a small set of predicate methods.
38
+ * See the feature spec §4.2–4.7 for authoritative semantics.
39
+ */
40
+ /**
41
+ * Resolved visibility mode.
42
+ *
43
+ * `"auto"` is an internal sentinel — it is never returned from
44
+ * {@link ApcliGroup.resolveVisibility} and is rejected when supplied via
45
+ * user config (CliConfig or apcore.yaml).
46
+ */
47
+ type ApcliMode = "auto" | "all" | "none" | "include" | "exclude";
48
+ /**
49
+ * User-facing apcli config shape.
50
+ *
51
+ * Boolean shorthand maps to `{mode: "all"}` / `{mode: "none"}`.
52
+ * Object form rejects `"auto"` per spec §4.2 (internal sentinel only).
53
+ */
54
+ type ApcliConfig = boolean | {
55
+ mode?: Exclude<ApcliMode, "auto">;
56
+ include?: string[];
57
+ exclude?: string[];
58
+ disableEnv?: boolean;
59
+ };
60
+ /** Set of group names reserved by apcore-cli (checked in cli.ts). */
61
+ declare const RESERVED_GROUP_NAMES: ReadonlySet<string>;
62
+ /**
63
+ * Visibility configuration for the built-in `apcli` command group.
64
+ *
65
+ * Instantiated via {@link ApcliGroup.fromCliConfig} (Tier 1) or
66
+ * {@link ApcliGroup.fromYaml} (Tier 3). The constructor is private to
67
+ * preserve the Tier-1-vs-Tier-3 flag distinction.
68
+ */
69
+ declare class ApcliGroup {
70
+ private readonly _mode;
71
+ private readonly _include;
72
+ private readonly _exclude;
73
+ private readonly _disableEnv;
74
+ private readonly _registryInjected;
75
+ private readonly _fromCliConfig;
76
+ private constructor();
77
+ /**
78
+ * Tier 1 constructor — config came from `createCli({ apcli })`.
79
+ *
80
+ * A non-auto mode from this tier wins over env var and yaml.
81
+ */
82
+ static fromCliConfig(config: ApcliConfig | undefined, opts: {
83
+ registryInjected: boolean;
84
+ }): ApcliGroup;
85
+ /**
86
+ * Tier 3 constructor — config came from `apcore.yaml`.
87
+ *
88
+ * Env var (Tier 2) may override the yaml-supplied mode.
89
+ */
90
+ static fromYaml(config: unknown, opts: {
91
+ registryInjected: boolean;
92
+ }): ApcliGroup;
93
+ /**
94
+ * Non-panicking Tier 3 factory (A-001 parity with Rust's `try_from_yaml`).
95
+ * Returns `[instance, null]` on success or `[null, errorMessage]` on invalid input.
96
+ * Use this in programmatic contexts where throwing/exiting is unwanted.
97
+ */
98
+ static tryFromYaml(config: unknown, opts: {
99
+ registryInjected: boolean;
100
+ }): [ApcliGroup, null] | [null, string];
101
+ private static _build;
102
+ /**
103
+ * Normalize an include/exclude list. Non-array → warn and return [].
104
+ *
105
+ * Unknown but well-formed entries emit a WARNING (spec §7 error table,
106
+ * T-APCLI-25) but are retained in the returned list for forward-compat —
107
+ * if apcore-cli later adds a subcommand named `foo`, existing configs
108
+ * continue to work without a config change. At runtime, unknown names
109
+ * simply never match any registered subcommand.
110
+ */
111
+ private static _normalizeList;
112
+ /**
113
+ * Resolve effective visibility mode after applying tier precedence.
114
+ *
115
+ * Returns one of `"all" | "none" | "include" | "exclude"` — never `"auto"`.
116
+ *
117
+ * Tier order (spec §4.4):
118
+ * 1. CliConfig non-auto wins outright.
119
+ * 2. `APCORE_CLI_APCLI` env var (unless sealed by disableEnv).
120
+ * 3. yaml non-auto.
121
+ * 4. Auto-detect from registryInjected.
122
+ */
123
+ resolveVisibility(): "all" | "none" | "include" | "exclude";
124
+ /**
125
+ * True iff `subcommand` passes the include/exclude filter.
126
+ *
127
+ * Callers MUST first check {@link resolveVisibility} — this method throws
128
+ * under modes `"all"` or `"none"` (caller bug per spec §4.6).
129
+ */
130
+ isSubcommandIncluded(subcommand: string): boolean;
131
+ /** True iff the `apcli` group itself should appear in root `--help`. */
132
+ isGroupVisible(): boolean;
133
+ /**
134
+ * Parse APCORE_CLI_APCLI. Case-insensitive.
135
+ *
136
+ * - `show` / `1` / `true` → `"all"`
137
+ * - `hide` / `0` / `false` → `"none"`
138
+ * - Empty / unset → `null`
139
+ * - Anything else → warn and return `null`
140
+ */
141
+ private _parseEnv;
142
+ }
143
+
3
144
  /**
4
145
  * LazyModuleGroup — Dynamic command loading from Registry.
5
146
  *
@@ -14,7 +155,21 @@ interface Registry {
14
155
  listModules(): ModuleDescriptor[];
15
156
  getModule(moduleId: string): ModuleDescriptor | null;
16
157
  }
17
- /** Placeholder for apcore-js Executor. */
158
+ /** Strategy info returned by Executor.describePipeline(). */
159
+ interface StrategyInfo {
160
+ name: string;
161
+ stepCount: number;
162
+ stepNames: string[];
163
+ description: string;
164
+ }
165
+ /** A step in the executor strategy (shape parity with apcore-js Step). */
166
+ interface StrategyStep {
167
+ name: string;
168
+ pure?: boolean;
169
+ removable: boolean;
170
+ timeoutMs?: number;
171
+ }
172
+ /** Placeholder for apcore-js Executor. Shape-compatible with apcore-js >= 0.19.0. */
18
173
  interface Executor {
19
174
  execute(moduleId: string, input: Record<string, unknown>): Promise<unknown>;
20
175
  /** Validate inputs without executing. Returns a PreflightResult. */
@@ -27,33 +182,45 @@ interface Executor {
27
182
  stream?(moduleId: string, input: Record<string, unknown>): AsyncIterable<unknown>;
28
183
  /** Call a module (synchronous-style, used by system commands). */
29
184
  call?(moduleId: string, input: Record<string, unknown>): Promise<unknown>;
185
+ /**
186
+ * Describe the executor's currently-set strategy. Returns StrategyInfo
187
+ * (apcore-js >= 0.18.0). Takes no arguments — to introspect a different
188
+ * strategy, use `Executor.listStrategies()` (static) via `executor.constructor`.
189
+ */
190
+ describePipeline?(): StrategyInfo;
191
+ /** The current execution strategy object, exposing step metadata. */
192
+ currentStrategy?: {
193
+ readonly steps: readonly StrategyStep[];
194
+ };
30
195
  }
31
196
  /** Result of a preflight validation check. */
32
197
  interface PreflightCheck {
33
- check: string;
34
- passed: boolean;
35
- error?: unknown;
36
- warnings?: string[];
198
+ readonly check: string;
199
+ readonly passed: boolean;
200
+ readonly error?: unknown;
201
+ readonly warnings?: string[];
37
202
  }
38
- /** Result of executor.validate(). */
203
+ /** Result of executor.validate() — parity with apcore-js PreflightResult. */
39
204
  interface PreflightResult {
40
- valid: boolean;
41
- requires_approval: boolean;
42
- checks: PreflightCheck[];
205
+ readonly valid: boolean;
206
+ readonly requiresApproval: boolean;
207
+ readonly checks: readonly PreflightCheck[];
208
+ readonly errors?: ReadonlyArray<Record<string, unknown>>;
43
209
  }
44
- /** A single step in a pipeline trace. */
210
+ /** A single step in a pipeline trace — parity with apcore-js StepTrace. */
45
211
  interface PipelineTraceStep {
46
- name: string;
47
- duration_ms: number;
48
- skipped: boolean;
49
- skip_reason?: string;
212
+ readonly name: string;
213
+ readonly durationMs: number;
214
+ readonly skipped: boolean;
215
+ readonly skipReason?: string | null;
50
216
  }
51
- /** Pipeline execution trace returned by callWithTrace(). */
217
+ /** Pipeline execution trace returned by callWithTrace() — parity with apcore-js PipelineTrace. */
52
218
  interface PipelineTrace {
53
- strategy_name: string;
54
- total_duration_ms: number;
55
- success: boolean;
56
- steps: PipelineTraceStep[];
219
+ readonly moduleId?: string;
220
+ readonly strategyName: string;
221
+ readonly totalDurationMs: number;
222
+ readonly success: boolean;
223
+ readonly steps: readonly PipelineTraceStep[];
57
224
  }
58
225
  /** Placeholder for apcore-js ModuleDescriptor. */
59
226
  interface ModuleDescriptor {
@@ -67,8 +234,6 @@ interface ModuleDescriptor {
67
234
  annotations?: Record<string, unknown>;
68
235
  metadata?: Record<string, unknown>;
69
236
  }
70
- /** Built-in command names that cannot be overridden by modules. */
71
- declare const BUILTIN_COMMANDS: string[];
72
237
  /**
73
238
  * Dynamically loads apcore modules as Commander subcommands from Registry.
74
239
  */
@@ -124,6 +289,16 @@ declare class GroupedModuleGroup extends LazyModuleGroup {
124
289
  /** Cached LazyGroup instances */
125
290
  private groupCache;
126
291
  private groupMapBuilt;
292
+ /** Exposure filter (FE-12) — controls which modules appear as CLI commands */
293
+ exposureFilter: ExposureFilter;
294
+ /** Effective group depth (CLAUDE.md v0.6.0): constructor arg > APCORE_CLI_GROUP_DEPTH env > 1. */
295
+ readonly groupDepth: number;
296
+ constructor(registry: Registry, executor: Executor, helpTextMaxLength?: number, exposureFilter?: ExposureFilter, groupDepth?: number);
297
+ /**
298
+ * Resolve group depth from constructor arg > APCORE_CLI_GROUP_DEPTH env > default 1.
299
+ * Invalid env values (non-integer, non-positive) fall through to the default.
300
+ */
301
+ static resolveGroupDepth(explicit: number | undefined): number;
127
302
  /**
128
303
  * Determine (groupName | null, commandName) for a module from its display overlay.
129
304
  *
@@ -135,10 +310,18 @@ declare class GroupedModuleGroup extends LazyModuleGroup {
135
310
  static resolveGroup(moduleId: string, descriptor: ModuleDescriptor, groupDepth?: number): [string | null, string];
136
311
  /**
137
312
  * Build the group map from registry modules.
313
+ *
314
+ * FE-13: hard-fails with exit 2 when a module resolves to the reserved
315
+ * `apcli` namespace in any of three ways — explicit `display.cli.group`,
316
+ * auto-grouped dotted prefix, or top-level alias/id. See spec §4.10.
138
317
  */
139
318
  buildGroupMap(): void;
140
319
  /**
141
- * List all available command names: builtins + group names + top-level module names.
320
+ * List all available command names: group names + top-level module names.
321
+ *
322
+ * FE-13: the built-in subcommand list is no longer folded in here — those
323
+ * commands live under the `apcli` prefix and are registered directly by
324
+ * `createCli`.
142
325
  */
143
326
  listCommands(): string[];
144
327
  /**
@@ -153,21 +336,8 @@ declare class GroupedModuleGroup extends LazyModuleGroup {
153
336
  isGroupMapBuilt(): boolean;
154
337
  }
155
338
 
156
- /**
157
- * CLI entry point — createCli / main equivalents.
158
- *
159
- * Protocol spec: CLI bootstrapping & command registration
160
- * Implements: F1 (dry-run), F3 (enhanced errors), F4 (trace),
161
- * F5 (approval handler), F6 (stream), F8 (strategy), F9 (output formats),
162
- * F11 (extra commands)
163
- */
164
-
165
- /** Whether --verbose was passed (controls help detail level). */
166
- declare let verboseHelp: boolean;
167
339
  /** Set the verbose help flag. When false, built-in options are hidden from help. */
168
340
  declare function setVerboseHelp(verbose: boolean): void;
169
- /** Base URL for online documentation. Null means no docs link shown. */
170
- declare let docsUrl: string | null;
171
341
  /**
172
342
  * Set the base URL for online documentation links shown in help and man pages.
173
343
  * Pass null to disable. Command-level help appends `/commands/{name}` automatically.
@@ -204,17 +374,49 @@ declare function emitErrorJson(e: unknown, exitCode: number): void;
204
374
  * Emit human-readable error to stderr with guidance fields.
205
375
  */
206
376
  declare function emitErrorTty(e: unknown, exitCode: number): void;
377
+ /**
378
+ * APCore unified client facade (apcore-js >= 0.18.0).
379
+ * Exposes registry and executor as top-level properties.
380
+ */
381
+ interface APCore {
382
+ registry: Registry;
383
+ executor: Executor;
384
+ }
207
385
  /** Options for createCli. */
208
386
  interface CreateCliOptions {
209
387
  extensionsDir?: string;
210
388
  progName?: string;
211
389
  verbose?: boolean;
390
+ /**
391
+ * APCore unified client instance (apcore-js >= 0.18.0).
392
+ * Mutually exclusive with registry/executor — providing app alongside
393
+ * either of those will throw.
394
+ */
395
+ app?: APCore;
212
396
  /** Pre-populated Registry instance. Skips filesystem discovery when provided. */
213
397
  registry?: Registry;
214
398
  /** Pre-built Executor instance. Used alongside registry. */
215
399
  executor?: Executor;
216
400
  /** Extra commands to register after built-in commands (FE-11 F11). */
217
401
  extraCommands?: Command[];
402
+ /** Exposure filter config or instance (FE-12). */
403
+ expose?: Record<string, unknown> | ExposureFilter;
404
+ /** Path to convention-based commands directory (apcore-toolkit ConventionScanner). */
405
+ commandsDir?: string;
406
+ /** Path to binding.yaml for display overlay (apcore-toolkit DisplayResolver). */
407
+ bindingPath?: string;
408
+ /**
409
+ * Built-in apcli group configuration (FE-13).
410
+ *
411
+ * Accepts:
412
+ * - `true` / `false` (shorthand for `{mode: "all"}` / `{mode: "none"}`)
413
+ * - A config object (see {@link ApcliConfig})
414
+ * - A pre-built {@link ApcliGroup} instance (Tier 1 override)
415
+ *
416
+ * When absent, Tier 3 (apcore.yaml `apcli:` block) is consulted, falling
417
+ * back to auto-detect: standalone → visible, embedded → hidden.
418
+ */
419
+ apcli?: ApcliConfig | ApcliGroup;
218
420
  }
219
421
  /**
220
422
  * Build and return the top-level Commander program.
@@ -224,12 +426,6 @@ interface CreateCliOptions {
224
426
  * @param verbose Show verbose help output
225
427
  */
226
428
  declare function createCli(extensionsDirOrOpts?: string | CreateCliOptions, progName?: string, verbose?: boolean): Command;
227
- /**
228
- * Optionally apply apcore-toolkit features (DisplayResolver, RegistryWriter).
229
- *
230
- * Uses dynamic import so the dependency remains optional — if apcore-toolkit
231
- * is not installed, a warning is printed and the CLI continues without it.
232
- */
233
429
  declare function applyToolkitIntegration(commandsDir?: string, bindingPath?: string): Promise<void>;
234
430
  /**
235
431
  * Parse argv and run the CLI. Handles top-level error catching and exit codes.
@@ -244,7 +440,11 @@ declare function main(progName?: string): void;
244
440
  declare function buildModuleCommand(moduleDef: ModuleDescriptor, executor: Executor, helpTextMaxLength?: number, cmdName?: string, verbose?: boolean): Command;
245
441
  /**
246
442
  * Validate that a module ID conforms to the expected format.
247
- * Pattern: [a-z][a-z0-9_]*(.[a-z][a-z0-9_])* — max 128 chars.
443
+ * Pattern: [a-z][a-z0-9_]*(.[a-z][a-z0-9_])* — max 192 chars.
444
+ *
445
+ * Length limit tracks PROTOCOL_SPEC §2.7 EBNF constraint #1 — bumped from
446
+ * 128 to 192 in spec 1.6.0-draft to accommodate Java/.NET deep-namespace
447
+ * FQN-derived IDs. Filesystem-safe (192 + ".binding.yaml".length = 205 < 255).
248
448
  */
249
449
  declare function validateModuleId(moduleId: string): void;
250
450
  /**
@@ -282,40 +482,30 @@ declare class CliApprovalHandler {
282
482
  /**
283
483
  * Check if module requires approval and handle accordingly.
284
484
  * Returns normally if approved (or approval not required).
285
- * Calls process.exit(46) if denied/timed out/non-TTY.
485
+ * Throws ApprovalDeniedError or ApprovalTimeoutError on denial/timeout so the
486
+ * caller (buildModuleCommand action) can run audit flush and tear-down before
487
+ * the process exits via the shared error path.
286
488
  */
287
489
  declare function checkApproval(moduleDef: ModuleDescriptor, autoApprove: boolean, timeout?: number): Promise<void>;
288
490
 
289
491
  /**
290
- * Display overlay helpers shared resolution logic for CLI surfaces.
291
- */
292
-
293
- /**
294
- * Extract resolved display overlay from a ModuleDescriptor's metadata.
295
- */
296
- declare function getDisplay(descriptor: ModuleDescriptor): Record<string, unknown>;
297
- /**
298
- * Return [displayName, description, tags] resolved from the display overlay.
492
+ * ConfigResolver 4-tier config resolution (CLI flag > env > file > default).
299
493
  *
300
- * Falls back to scanner-provided values when no overlay is present.
301
- */
302
- declare function getCliDisplayFields(descriptor: ModuleDescriptor): [string, string, string[]];
303
-
304
- /**
305
- * Init command — scaffold new apcore modules (Phase 1).
306
- */
307
-
308
- /**
309
- * Register the init command group on the CLI program.
494
+ * Protocol spec: Configuration resolution
310
495
  */
311
- declare function registerInitCommand(cli: Command): void;
312
-
313
496
  /**
314
- * ConfigResolver 4-tier config resolution (CLI flag > env > file > default).
497
+ * Default configuration values.
315
498
  *
316
- * Protocol spec: Configuration resolution
499
+ * Audit D9 (config cleanup, v0.6.x): the entries `sandbox.enabled`,
500
+ * `cli.auto_approve`, `cli.stdin_buffer_limit`, and the eight `apcore-cli.*`
501
+ * namespace aliases were removed because no production code path reads
502
+ * them via `resolve()`. Sandbox is configured via the `--sandbox` CLI flag,
503
+ * auto-approve via `--yes`, the stdin buffer is hard-coded, and namespace
504
+ * aliases are registered separately by `apcore-js`'s Config Bus when
505
+ * `registerConfigNamespace()` runs at `createCli` startup. The cross-key
506
+ * file-lookup mechanism (`NAMESPACE_TO_LEGACY` / `LEGACY_TO_NAMESPACE`)
507
+ * still works regardless — it does not depend on these DEFAULTS entries.
317
508
  */
318
- /** Default configuration values. */
319
509
  declare const DEFAULTS: Record<string, unknown>;
320
510
  /**
321
511
  * Register the apcore-cli Config Bus namespace (apcore >= 0.15.0).
@@ -334,6 +524,13 @@ declare class ConfigResolver {
334
524
  private readonly configPath;
335
525
  private fileCache;
336
526
  private fileCacheLoaded;
527
+ /**
528
+ * Raw parsed yaml root (pre-flatten). Populated alongside `fileCache`
529
+ * on load. Used by `resolveObject()` to walk nested paths without
530
+ * invoking `flattenDict` — see FE-13 spec §4.8 M1 note.
531
+ * `null` when no config file is present or parsing fails.
532
+ */
533
+ private _rawConfig;
337
534
  constructor(cliFlags?: Record<string, unknown>, configPath?: string);
338
535
  /**
339
536
  * Resolve a single configuration key across all four tiers.
@@ -343,6 +540,26 @@ declare class ConfigResolver {
343
540
  * Load a value from the config file using a dot-separated key path.
344
541
  */
345
542
  private resolveFromFile;
543
+ /**
544
+ * Resolve a configuration key to its raw nested value (FE-13).
545
+ *
546
+ * Unlike `resolve()`, this method does NOT flatten the yaml tree — it
547
+ * walks the dot-separated path directly against the parsed yaml root.
548
+ * This lets callers retrieve non-leaf structures (booleans, arrays,
549
+ * objects) such as the `apcli` visibility config, which is naturally
550
+ * shaped as a nested object in apcore.yaml.
551
+ *
552
+ * Semantics:
553
+ * - Returns `null` when no config file is loaded or when the path is
554
+ * not present / descends into a non-object node (including arrays).
555
+ * - Returns the raw value (boolean / array / object / scalar) when the
556
+ * full path resolves to a leaf or intermediate node.
557
+ *
558
+ * Intentionally DOES NOT consult DEFAULTS, env vars, or CLI flags — it is
559
+ * strictly a yaml-tree accessor. Scalar `resolve()` semantics are
560
+ * unaffected.
561
+ */
562
+ resolveObject(key: string): unknown;
346
563
  /**
347
564
  * Load and flatten a YAML config file.
348
565
  */
@@ -354,15 +571,23 @@ declare class ConfigResolver {
354
571
  }
355
572
 
356
573
  /**
357
- * Discovery commands list, describe, validate (FE-04, FE-11).
358
- *
359
- * Protocol spec: Module discovery & introspection
574
+ * Register the `list` subcommand on the given group (FE-13).
360
575
  */
361
-
576
+ declare function registerListCommand(apcliGroup: Command, registry: Registry, exposureFilter?: ExposureFilter): void;
577
+ /**
578
+ * Register the `describe` subcommand on the given group (FE-13).
579
+ */
580
+ declare function registerDescribeCommand(apcliGroup: Command, registry: Registry): void;
362
581
  /**
363
- * Register list and describe commands on the CLI group.
582
+ * Register the `exec` subcommand on the given group (FE-13).
583
+ *
584
+ * Generic dispatch: `apcli exec <module-id> [--format fmt] [--input json]`.
585
+ * Unlike the per-module commands built by `buildModuleCommand`, this command
586
+ * does not derive options from the module's input schema — inputs are passed
587
+ * as a JSON object via `--input`. This mirrors the apcli-flavoured generic
588
+ * dispatch contract in the builtin-group feature spec.
364
589
  */
365
- declare function registerDiscoveryCommands(cli: Command, registry: Registry): void;
590
+ declare function registerExecCommand(apcliGroup: Command, registry: Registry, executor: Executor): void;
366
591
  /**
367
592
  * Register the standalone validate command.
368
593
  */
@@ -374,22 +599,6 @@ declare function registerValidateCommand(cli: Command, registry: Registry, execu
374
599
  * Protocol spec: Output formatting (FE-09 enhanced)
375
600
  */
376
601
 
377
- /**
378
- * Resolve output format with TTY-adaptive default.
379
- */
380
- declare function resolveFormat(explicitFormat?: string): string;
381
- /**
382
- * Truncate text to maxLength, appending '...' if needed.
383
- */
384
- declare function truncate(text: string, maxLength?: number): string;
385
- /**
386
- * Format and print a list of modules.
387
- */
388
- declare function formatModuleList(modules: ModuleDescriptor[], format: string, filterTags?: string[], showDeps?: boolean): void;
389
- /**
390
- * Format and print full module metadata.
391
- */
392
- declare function formatModuleDetail(moduleDef: ModuleDescriptor, format: string): void;
393
602
  /**
394
603
  * Format and print module execution result.
395
604
  *
@@ -397,14 +606,6 @@ declare function formatModuleDetail(moduleDef: ModuleDescriptor, format: string)
397
606
  * The `fields` option allows dot-path field selection on dict results.
398
607
  */
399
608
  declare function formatExecResult(result: unknown, format?: string, fields?: string): void;
400
- /**
401
- * Format and print a PreflightResult to stdout.
402
- */
403
- declare function formatPreflightResult(result: PreflightResult, format?: string): void;
404
- /**
405
- * Return the exit code for the first failed check in a PreflightResult.
406
- */
407
- declare function firstFailedExitCode(result: PreflightResult): number;
408
609
 
409
610
  /**
410
611
  * JSON Schema $ref resolver.
@@ -423,17 +624,6 @@ declare function resolveRefs(schema: Record<string, unknown>, maxDepth?: number,
423
624
  * Protocol spec: Schema-driven argument parsing
424
625
  */
425
626
 
426
- /** Sentinel type marker for boolean flags. */
427
- declare const BOOLEAN_FLAG: unique symbol;
428
- type TypeResult = "string" | "int" | "float" | typeof BOOLEAN_FLAG | "file";
429
- /**
430
- * Map JSON Schema type to a type identifier.
431
- */
432
- declare function mapType(propName: string, propSchema: Record<string, unknown>): TypeResult;
433
- /**
434
- * Extract help text from schema property, preferring x-llm-description.
435
- */
436
- declare function extractHelp(propSchema: Record<string, unknown>, maxLength?: number): string | undefined;
437
627
  /**
438
628
  * Convert a JSON Schema `properties` object into an array of
439
629
  * Commander option configurations.
@@ -446,11 +636,6 @@ declare function schemaToCliOptions(schema: Record<string, unknown>, maxHelpLeng
446
636
  * Protocol spec: Shell integration
447
637
  */
448
638
 
449
- /**
450
- * Build a complete roff man page for the entire program.
451
- * Covers all registered commands including downstream business commands.
452
- */
453
- declare function buildProgramManPage(program: Command, progName: string, version: string, description?: string, docsUrl?: string): string;
454
639
  /**
455
640
  * Configure --help --man support on a Commander program.
456
641
  * When --man is passed with --help, outputs a complete roff man page
@@ -461,21 +646,53 @@ declare function buildProgramManPage(program: Command, progName: string, version
461
646
  */
462
647
  declare function configureManHelp(program: Command, progName: string, version: string, description?: string, docsUrl?: string): void;
463
648
  /**
464
- * Register completion and man commands.
649
+ * Register the `completion` subcommand on `host` (typically the apcli group
650
+ * per spec §4.1, or the root program during the transition period).
651
+ *
652
+ * The completion-script generator enumerates the actually-registered set of
653
+ * subcommands from the root program's Commander tree at generation time
654
+ * (spec §4.13).
465
655
  */
466
- declare function registerShellCommands(cli: Command, progName?: string): void;
656
+ declare function registerCompletionCommand(host: Command): void;
467
657
 
468
658
  /**
469
659
  * System management commands — health, usage, enable, disable, reload, config (FE-11 F2).
470
660
  *
471
- * Each delegates to system.* modules via executor.
472
- * No-op if system modules are unavailable (graceful probe).
661
+ * Each registrar delegates to the corresponding system.* module via the
662
+ * executor. The six registrars are pure attach-only operations and are
663
+ * dispatched by `createCli()`'s FE-13 apcli group integration.
473
664
  */
474
665
 
475
666
  /**
476
- * Register system management commands. No-op if system modules are not available.
667
+ * Attach the `health` subcommand to the passed apcliGroup.
477
668
  */
478
- declare function registerSystemCommands(cli: Command, executor: Executor): Promise<void>;
669
+ declare function registerHealthCommand(apcliGroup: Command, executor: Executor): void;
670
+ /**
671
+ * Attach the `usage` subcommand to the passed apcliGroup.
672
+ */
673
+ declare function registerUsageCommand(apcliGroup: Command, executor: Executor): void;
674
+ /**
675
+ * Attach the `enable` subcommand to the passed apcliGroup.
676
+ */
677
+ declare function registerEnableCommand(apcliGroup: Command, executor: Executor): void;
678
+ /**
679
+ * Attach the `disable` subcommand to the passed apcliGroup.
680
+ */
681
+ declare function registerDisableCommand(apcliGroup: Command, executor: Executor): void;
682
+ /**
683
+ * Attach the `reload` subcommand to the passed apcliGroup.
684
+ */
685
+ declare function registerReloadCommand(apcliGroup: Command, executor: Executor): void;
686
+ /**
687
+ * Attach the `config` subcommand (with `get` and `set` children) to the
688
+ * passed apcliGroup.
689
+ *
690
+ * Signature note: config reads/writes go through `executor.call()` to
691
+ * `system.config.get` / `system.control.update_config`, so this registrar
692
+ * takes an {@link Executor} (not a Registry). The FE-13 dispatcher table
693
+ * entry for `config` sets `requiresExecutor: true` accordingly.
694
+ */
695
+ declare function registerConfigCommand(apcliGroup: Command, executor: Executor): void;
479
696
 
480
697
  /**
481
698
  * Pipeline strategy commands — describe-pipeline (FE-11 F8).
@@ -486,6 +703,15 @@ declare function registerSystemCommands(cli: Command, executor: Executor): Promi
486
703
  */
487
704
  declare function registerPipelineCommand(cli: Command, executor: Executor): void;
488
705
 
706
+ /**
707
+ * Init command — scaffold new apcore modules (Phase 1).
708
+ */
709
+
710
+ /**
711
+ * Register the init command group on the CLI program.
712
+ */
713
+ declare function registerInitCommand(cli: Command): void;
714
+
489
715
  /**
490
716
  * Error classes and exit code mapping for apcore-cli.
491
717
  *
@@ -527,6 +753,8 @@ declare const EXIT_CODES: {
527
753
  readonly MODULE_NOT_FOUND: 44;
528
754
  readonly MODULE_LOAD_ERROR: 44;
529
755
  readonly MODULE_DISABLED: 44;
756
+ readonly DEPENDENCY_NOT_FOUND: 44;
757
+ readonly DEPENDENCY_VERSION_MISMATCH: 44;
530
758
  readonly SCHEMA_VALIDATION_ERROR: 45;
531
759
  readonly APPROVAL_DENIED: 46;
532
760
  readonly APPROVAL_TIMEOUT: 46;
@@ -562,10 +790,6 @@ declare const LEVELS: {
562
790
  type LogLevel = keyof typeof LEVELS;
563
791
  declare function setLogLevel(level: string): void;
564
792
  declare function getLogLevel(): LogLevel;
565
- declare function debug(message: string): void;
566
- declare function info(message: string): void;
567
- declare function warn(message: string): void;
568
- declare function error(message: string): void;
569
793
 
570
794
  /**
571
795
  * AuditLogger — JSONL audit trail.
@@ -584,6 +808,7 @@ declare function getAuditLogger(): AuditLogger | null;
584
808
  declare class AuditLogger {
585
809
  static readonly DEFAULT_PATH: string;
586
810
  private readonly logPath;
811
+ private writeFailureWarned;
587
812
  constructor(path?: string);
588
813
  private ensureDirectory;
589
814
  logExecution(moduleId: string, inputData: Record<string, unknown>, status: ExecutionStatus, exitCode: number, durationMs: number): void;
@@ -591,19 +816,31 @@ declare class AuditLogger {
591
816
  private getUser;
592
817
  }
593
818
 
594
- /**
595
- * ConfigEncryptor — Keyring + AES-256-GCM fallback.
596
- *
597
- * Protocol spec: Security — config encryption
598
- */
599
819
  /**
600
820
  * Encrypts and decrypts configuration values. Prefers OS keyring for key
601
- * storage, falling back to AES-256-GCM with a derived key.
821
+ * storage, falling back to AES-256-GCM with a key derived from
822
+ * APCORE_CLI_CONFIG_PASSPHRASE when set, or from hostname+username
823
+ * (obfuscation-only) as a last resort.
824
+ *
825
+ * Wire format v2: enc:v2:<base64(salt(16)+nonce(12)+tag(16)+ciphertext)>
826
+ * Legacy format: enc:<base64(nonce(12)+tag(16)+ciphertext)> (read-only)
602
827
  */
603
828
  declare class ConfigEncryptor {
604
829
  static readonly SERVICE_NAME = "apcore-cli";
830
+ private static weakFallbackWarned;
605
831
  /**
606
832
  * Encrypt and store a configuration value.
833
+ *
834
+ * Cross-SDK contract (D10-003, 2026-04-26): when the OS keyring is
835
+ * detected as available but `setPassword` then throws (locked keyring,
836
+ * transient backend failure, permission revoked, etc.), the error is
837
+ * propagated wrapped in a `ConfigDecryptionError`. Previously TS
838
+ * caught the exception and silently fell through to AES file encryption
839
+ * — a quiet downgrade that surprised users who expected a hard failure.
840
+ * Python lets the keyring exception propagate raw; Rust returns
841
+ * `ConfigDecryptionError::KeyringError`. The fall-through to AES is
842
+ * still reached when `getKeytar()` returns `null` (keyring
843
+ * genuinely unavailable on this platform / install).
607
844
  */
608
845
  store(key: string, value: string): Promise<string>;
609
846
  /**
@@ -613,6 +850,8 @@ declare class ConfigEncryptor {
613
850
  private deriveKey;
614
851
  private aesEncrypt;
615
852
  private aesDecrypt;
853
+ /** Decrypt legacy v1-format values: nonce(12)+tag(16)+ct, static salt. */
854
+ private aesDecryptV1;
616
855
  }
617
856
 
618
857
  /**
@@ -635,6 +874,15 @@ declare class AuthProvider {
635
874
  getApiKey(): Promise<string | null>;
636
875
  /**
637
876
  * Add authentication headers to an outgoing request.
877
+ *
878
+ * Cross-SDK contract (D10-002, 2026-04-26): the input `headers` object
879
+ * is mutated **in place** and the same reference is returned. Callers
880
+ * that share the headers reference (the documented pattern in
881
+ * apcore-cli/docs/features/security.md §AuthProvider) can read
882
+ * `headers.Authorization` after the call without re-binding the
883
+ * return value. Python and Rust both mutate-and-return; TS previously
884
+ * spread into a new object, which silently broke shared-reference
885
+ * callers.
638
886
  */
639
887
  authenticateRequest(headers: Record<string, string>): Promise<Record<string, string>>;
640
888
  /**
@@ -646,23 +894,31 @@ declare class AuthProvider {
646
894
  /**
647
895
  * Sandbox — Subprocess isolation for module execution.
648
896
  *
649
- * Protocol spec: Security — sandboxed execution
897
+ * Protocol spec: Security — sandboxed execution (tech-design §8.6.4).
898
+ *
899
+ * Uses a re-exec model: spawns `node <this-binary> --internal-sandbox-runner
900
+ * <module_id>` with a stripped environment and isolated HOME/TMPDIR.
901
+ * The child reads JSON from stdin, runs the module via a fresh
902
+ * Registry+Executor, and writes JSON to stdout.
650
903
  */
651
904
 
652
905
  /**
653
906
  * Executes modules in an isolated subprocess to limit the blast radius
654
907
  * of untrusted or third-party modules.
655
908
  *
656
- * When disabled, delegates directly to the Executor.
909
+ * When disabled (the default), delegates directly to the Executor.
910
+ * When enabled, spawns a restricted child process via re-exec with
911
+ * `--internal-sandbox-runner <module_id>`.
657
912
  */
658
913
  declare class Sandbox {
659
914
  private readonly enabled;
660
- constructor(enabled?: boolean);
915
+ private readonly timeoutSeconds;
916
+ constructor(enabled?: boolean, timeoutSeconds?: number);
661
917
  /**
662
918
  * Execute a module, optionally inside a sandboxed subprocess.
663
919
  */
664
920
  execute(moduleId: string, inputData: Record<string, unknown>, executor: Executor): Promise<unknown>;
665
- private sandboxedExecute;
921
+ private _sandboxedExecute;
666
922
  }
667
923
 
668
- export { ApprovalDeniedError, ApprovalTimeoutError, AuditLogger, AuthProvider, AuthenticationError, BUILTIN_COMMANDS, CliApprovalHandler, ConfigDecryptionError, ConfigEncryptor, ConfigResolver, type CreateCliOptions, DEFAULTS, EXIT_CODES, type Executor, type ExitCode, GroupedModuleGroup, LazyGroup, LazyModuleGroup, type ModuleDescriptor, ModuleExecutionError, ModuleNotFoundError, type OptionConfig, type PipelineTrace, type PipelineTraceStep, type PreflightCheck, type PreflightResult, type Registry, Sandbox, SchemaValidationError, applyToolkitIntegration, buildModuleCommand, buildProgramManPage, checkApproval, collectInput, configureManHelp, createCli, debug, docsUrl, emitErrorJson, emitErrorTty, error, exitCodeForError, extractHelp, firstFailedExitCode, formatExecResult, formatModuleDetail, formatModuleList, formatPreflightResult, getAuditLogger, getCliDisplayFields, getDisplay, getLogLevel, info, main, mapType, reconvertEnumValues, registerConfigNamespace, registerDiscoveryCommands, registerInitCommand, registerPipelineCommand, registerShellCommands, registerSystemCommands, registerValidateCommand, resolveFormat, resolveRefs, schemaToCliOptions, setAuditLogger, setDocsUrl, setLogLevel, setVerboseHelp, truncate, validateModuleId, verboseHelp, warn };
924
+ export { type APCore, type ApcliConfig, ApcliGroup, type ApcliMode, 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, emitErrorJson, emitErrorTty, exitCodeForError, formatExecResult, getAuditLogger, getLogLevel, main, reconvertEnumValues, registerCompletionCommand, registerConfigCommand, registerConfigNamespace, registerDescribeCommand, registerDisableCommand, registerEnableCommand, registerExecCommand, registerHealthCommand, registerInitCommand, registerListCommand, registerPipelineCommand, registerReloadCommand, registerUsageCommand, registerValidateCommand, resolveRefs, schemaToCliOptions, setAuditLogger, setDocsUrl, setLogLevel, setVerboseHelp, validateModuleId };