apcore-cli 0.7.0 → 0.8.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 +123 -0
- package/README.md +37 -27
- package/dist/bin/apcore-cli.js +462 -178
- package/dist/bin/apcore-cli.js.map +1 -1
- package/dist/index.d.ts +128 -22
- package/dist/index.js +432 -152
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,129 @@ All notable changes to apcore-cli (TypeScript SDK) will be documented in this fi
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.8.0] - 2026-05-08
|
|
9
|
+
|
|
10
|
+
### Security
|
|
11
|
+
|
|
12
|
+
- **D11-008 — `AuditLogger.getUser` now includes `LOGNAME` in the env-var fallback chain** (`src/security/audit.ts:138`). The canonical user-resolution chain per spec `security.md` is `getlogin → pwd.getpwuid(getuid).pw_name → USER → LOGNAME → USERNAME → unknown`. The TS port collapsed the first two POSIX steps via `os.userInfo()` (correct) but then jumped from `USER` straight to `USERNAME`, dropping `LOGNAME`. On systems where only `LOGNAME` is set (some CI runners), audit entries fell through to `USERNAME` or `"unknown"` while Python/Rust/Go correctly resolved to `LOGNAME` — a cross-SDK divergence affecting the audit trail's user attribution. Fix inserts `process.env.LOGNAME` between `USER` and `USERNAME`.
|
|
13
|
+
|
|
14
|
+
### Removed (BREAKING)
|
|
15
|
+
|
|
16
|
+
- **D9-002 — root-level deprecation shims removed (FE-13 §11.3).** Pre-v0.8
|
|
17
|
+
`createCli()` registered 13 hidden root-level commands (`list`, `describe`,
|
|
18
|
+
`exec`, `init`, `validate`, `health`, `usage`, `enable`, `disable`,
|
|
19
|
+
`reload`, `config`, `completion`, `describe-pipeline`) that printed a
|
|
20
|
+
`WARNING: '<name>' as a root-level command is deprecated. ... Will be
|
|
21
|
+
removed in v0.8` line on stderr and forwarded to `apcli <name>`. Per
|
|
22
|
+
PROTOCOL_SPEC FE-13 §11.3 these shims are removed in v0.8 — the `apcli`
|
|
23
|
+
sub-group (or the renamed `builtinGroupName`) is now the only path to
|
|
24
|
+
built-in commands. Internal `_DEPRECATED_ROOT_COMMANDS`,
|
|
25
|
+
`_registerDeprecationShims`, `_collectShimForwardArgs`, and the
|
|
26
|
+
`__isDeprecationShim` collision-detection branch in `createCli`'s
|
|
27
|
+
`extraCommands` handler are deleted.
|
|
28
|
+
- **D9-W1 — raw mutable bindings `verboseHelp` / `docsUrl` no longer exported** from `src/main.ts:50,58`. The setter pair `setVerboseHelp` / `setDocsUrl` is the sanctioned API and remains exported. Mutable `let` exports are brittle as a public surface (live-binding semantics depend on the importer's bundler) and no embedder imports the raw bindings; the public surface now only includes the setters.
|
|
29
|
+
- **D9-W2 — `emitErrorJson` / `emitErrorTty` no longer exported** from `src/main.ts:158,180` and dropped from the `src/index.ts` public re-export list. Both are only consumed inside `main.ts` (`buildModuleCommand` action handler). Now annotated `@internal`.
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **`builtinGroupName?: string` option on `createCli`** — downstream branded CLIs that embed apcore-cli can now expose the built-in commands under a custom namespace (e.g. `mycorp-cli admin health` instead of `mycorp-cli apcli health`). `ApcliGroup` gains a `name` getter and the constructor option is threaded through `fromCliConfig` / `fromYaml` / `tryFromYaml` / `_build`. Default `"apcli"` is unchanged. Validated against `/^[a-z][a-z0-9_-]*$/`; invalid values exit 2. Two new module-level accessors `getReservedGroupNames()` / `setReservedGroupNames()` expose the live reserved-set so `cli.ts`'s `assertNotReserved` and `listCommands` honour the renamed group. Env var `APCORE_CLI_APCLI` and config keys `apcli.*` deliberately do NOT rename — they are apcore-cli-internal toggles, not user-facing. Cross-SDK parity with Python `create_cli(builtin_group_name=...)`. New `DEFAULT_BUILTIN_GROUP_NAME` constant exported from `./builtin-group.js`.
|
|
34
|
+
- **Client-side approval gate for `apcli enable / disable / reload / config set`** — new `requireApprovalForSystemCommand(moduleId, autoApprove)` helper in `src/system-cmd.ts` synthesises a minimal `ModuleDescriptor` with `annotations.requires_approval = true` and invokes `checkApproval(...)` before dispatching the executor call. `ApprovalDeniedError` / `ApprovalTimeoutError` propagate to `emitErrorAndExit` which maps them to exit 46 via `exitCodeForError`. `apcli config set` gains a `-y, --yes` flag for parity with the other three. Mirrors Python `_check_system_approval` and Rust `require_approval_for_system_command`. Audit D11-B-001 (see Fixed).
|
|
35
|
+
- **14 new tests in `tests/builtin-group.test.ts`** — `ApcliGroup builtin-group rename` describe block covers default name, custom name via both factories, validation of 6 invalid + 5 valid name shapes.
|
|
36
|
+
- **5 new tests in `tests/system-cmd.test.ts`** — `client-side approval gate (D11-B-001)` describe block covers `enable / disable / reload / config set` deny path on non-TTY without `--yes` (exit 46 + executor never called) and the `--yes` bypass.
|
|
37
|
+
- **D1-info-1 — `ApcliGroupError` typed exception** (`src/builtin-group.ts:101`, re-exported from `src/index.ts`) for cross-SDK error-class parity with Rust (`apcore_cli::ApcliGroupError`, re-exported at `lib.rs:183`). The previous plain `Error` throw on invalid `builtinGroupName` gave consumers no programmatic way to discriminate apcli config errors from generic ones. Existing `catch (e) { if (e instanceof Error) ... }` blocks continue to work; new code can use `instanceof ApcliGroupError`. The neighbouring throw at `builtin-group.ts:464` (caller-bug guard for `isSubcommandIncluded` invoked under wrong mode) stays as plain `Error` — out of scope for apcli config validation.
|
|
38
|
+
- **D1-004 — `Sandbox` builder methods `withExtensionsRoot` and `withMaxOutputBytes`** (`src/security/sandbox.ts`). Cross-SDK parity with Python `with_extensions_root` / `with_max_output_bytes` and the new Rust builders. Both fields drive runtime behaviour: `extensions_root` takes precedence over inherited `APCORE_EXTENSIONS_ROOT`, `max_output_bytes` replaces the per-stream output cap. The "future builder (Python parity)" comment at `sandbox.ts:77` is removed.
|
|
39
|
+
- **D1-006 — `allowedPrefixes?: string[]` option on `CreateCliOptions`** plumbed through `createCli → applyToolkitIntegration → loadBindingDisplayOverlay` so non-allowlisted `target:` entries are dropped before they pollute the display map. Mirrors Python `factory.py:78 allowed_prefixes` safety knob. New `ApplyToolkitIntegrationOptions` type exported.
|
|
40
|
+
- **D1-007 — `formatModuleList`, `formatModuleDetail`, `resolveFormat` re-exported from `src/index.ts`** alongside `formatExecResult`. The output-formatter feature spec declares contracts for all four; embedders building custom output paths can now consume the canonical formatters from the package root.
|
|
41
|
+
- **D5-003 — dedicated `tests/system-usage.test.ts`** covering the new `src/system-usage.ts` aggregator (period filtering, per-module aggregates, missing-audit-log fallback) — previously coverage for the aggregator was only incidental via the discovery-layer integration tests.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **D11-B-001 — `system-cmd.ts` skipped the client-side approval gate entirely**. Each of the four mutating subcommands (`enable`, `disable`, `reload`, `config set`) declared `--yes` but never read it; no `checkApproval(...)` call existed in the file. Operators on Python or Rust SDKs got an interactive 60s confirmation prompt; TS users got nothing — server-side enforcement was the only gate, and the `--yes` flag was completely dead. Fix wires `requireApprovalForSystemCommand(moduleId, opts.yes)` into all four action handlers (see Added). Description text updated from "Signal explicit intent (forwarded to server-side approval gate)" to "Skip approval prompt" — the original copy was misleading because nothing was actually forwarded.
|
|
46
|
+
- **D11-NEW-005 — TS RESERVED_NAMES exit code was 2, not 48**. `schema-parser.ts:101` previously called `process.exit(EXIT_CODES.INVALID_CLI_INPUT)` (=2) when a schema property collided with a reserved CLI option name. Spec mandates exit 48 (cross-SDK parity with Python `sys.exit(48)` and Rust `CliError::SchemaParserFailure → EXIT_SCHEMA_CIRCULAR_REF`). Fix changes to `EXIT_CODES.SCHEMA_CIRCULAR_REF`. The neighbour flag-collision branch already exited 48; both schema-author errors are now consistent. 6 existing tests updated from "exits 2" assertions to "exits 48".
|
|
47
|
+
- **D11-NEW-001 — `resolveRefs` dropped parent `required` when resolving `anyOf` / `oneOf` branches**. A schema like `{required: ["x"], anyOf: [{required: ["a"]}, {required: ["a"]}]}` resolved to `required: ["a"]` in TS — silently losing `"x"`. Per JSON Schema semantics, `parent.required` applies in addition to the branch intersection. Branch handling now preserves the parent node's `required` field (deduplicated, sibling-first ordering). Aligned with Python `ref_resolver.py:100-118`; Rust got the same fix in a sibling commit. 4 new ref-resolver regression tests.
|
|
48
|
+
- **D11-NEW-003 — `max_depth` over-counted plain nested-object recursion**. Previously a schema with >32 levels of nested object `properties` (no `$refs`) was rejected; the depth budget should only count `$ref` hops + composition-branch descents, not pure structural recursion. Aligned with Rust's interpretation of the spec ("Maximum $ref resolution recursion depth").
|
|
49
|
+
- **D11-NEW-004 — `schema_to_cli_options` flag-collision sites exited 2, not 48**. The two flag-collision sites in `src/schema-parser.ts` (regular flag collision, no-flag collision) previously exited 2 (`INVALID_CLI_INPUT`) instead of 48 (`SCHEMA_CIRCULAR_REF`) — observable: a CI / embedder checking `$? == 48` to detect schema-related failures missed the TS path. Fix matches Python `sys.exit(48)`. 2 updated schema-parser collision tests.
|
|
50
|
+
- **D11-W4 — `schema_to_cli_options` did not warn on `required` entries missing from `properties`** (`src/schema-parser.ts:81`). Python (`schema_parser.py:93-98`) and Rust (`schema_parser.rs:220-228`) iterate the schema `required` list and warn for entries not present in `properties`. The TS SDK skipped that loop, so schemas like `{required: ["foo"]}` with no matching property parsed silently — schema authors lost the cross-SDK guard rail. Now emits the same warning text as Python: `Required property '%s' not found in properties, skipping.` 3 new regression tests cover missing-only, all-present, and multiple-missing cases.
|
|
51
|
+
- **D10-info-1 — `APCORE_CLI_APCLI` env-var parser did not trim** (`src/builtin-group.ts:488`). Per spec invariant 2 in `features/builtin-group.md`, the parser is case-insensitive AND trim-on-read. The TS port lowercased but skipped the trim, so values like `" show "` or `"\thide\n"` silently fell through to the unknown-value warning branch — diverging from Python and Rust. Fix adds `.trim()` before `.toLowerCase()` and short-circuits to `null` when the trimmed value is empty (all-whitespace env is now treated as unset without emitting a warning, matching empty-string handling).
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- **`vitest.config.ts` `coverage.thresholds`** added — `lines / functions / statements: 85`, `branches: 75`. Cross-SDK CI parity with Python `pyproject.toml [tool.coverage.report] fail_under = 85` and Rust `make coverage --fail-under-lines 85`. Audit D5-004.
|
|
56
|
+
|
|
57
|
+
- **D8-W2 — `validateModuleId` extracted to dedicated `src/validate.ts`** for parallel-layout parity with Python (`apcore_cli/validate.py`) and Rust (`src/validate.rs`). Embedders reading multiple SDKs side-by-side previously had to grep for the helper inside `main.ts`. The existing import path is preserved via re-export from `main.ts`, so `discovery.ts` and tests need no changes. Adds an exported `MAX_MODULE_ID_LENGTH` constant for spec parity.
|
|
58
|
+
|
|
59
|
+
- **D1-W4 — `formatPreflightResult` / `firstFailedExitCode` annotated `@internal`** (`src/output.ts:406`). Both stay `export`ed because `main.ts` and `discovery.ts` import them across module boundaries, but they are not re-exported from `index.ts` and have no documented embedder use case. The `@internal` JSDoc tag now matches the import-graph reality so doc generators and human readers see they are not part of the package's stable API.
|
|
60
|
+
|
|
61
|
+
- **D6-TS-info — `@sinclair/typebox` ^0.32 → ^0.34** (`package.json:41`, resolves to 0.34.48). Cross-SDK dependency hygiene: Rust and Python pulled their matching schema-validation deps to current minors months ago; TS was the laggard. The only usage is the stable `Type.*` builder facade in `src/init-cmd.ts` (`Type.Object` / `Type.Array` / `Type.Optional` / `Type.String` / `Type.Number` / `Type.Boolean`), all of which are identical between 0.32 and 0.34 — no source changes required.
|
|
62
|
+
|
|
63
|
+
- **D6-001 — `apcore-toolkit` devDependency switched from local `link:` path to registry version `^0.6.0`**. The previous entry pointed at a developer's absolute local clone, which broke `pnpm install` for any other contributor. Clean clones now resolve `apcore-toolkit` identically to the peer-dependency declaration (`>=0.6.0`).
|
|
64
|
+
|
|
65
|
+
- **`apcli list` and `apcli describe` `--format` choices** are now validated
|
|
66
|
+
via Commander's `Option.choices(...)` against the canonical set
|
|
67
|
+
`[table, json, csv, yaml, jsonl, markdown, skill]`. Unknown values exit
|
|
68
|
+
with code 2 instead of silently no-op'ing. Issue
|
|
69
|
+
[aiperceivable/apcore-cli#20](https://github.com/aiperceivable/apcore-cli/issues/20).
|
|
70
|
+
- **Dependency bump**: peer-dep `apcore-js >= 0.21.0` (was `>= 0.19.0`) and the
|
|
71
|
+
optional `apcore-toolkit >= 0.6.0` (was `>= 0.5.0`). Aligns with upstream
|
|
72
|
+
`apcore 0.21.0` (Module.preview / PreflightResult.predicted_changes) and
|
|
73
|
+
`apcore-toolkit 0.6.0` (surface-aware formatters).
|
|
74
|
+
- **Issue #19 — drop "apcore" branding from embedded-mode `--help`**: top-level
|
|
75
|
+
CLI description now resolves from a new `description?: string` field on
|
|
76
|
+
`CreateCliOptions` (defaults to `${progName} CLI`); the `apcli` subgroup
|
|
77
|
+
description is now `Built-in commands` instead of `apcore-cli built-in
|
|
78
|
+
commands`; `--verbose` option text and the help footer drop the trailing
|
|
79
|
+
`apcore` from `(including built-in apcore options)`. Standalone bin entry
|
|
80
|
+
(`bin/apcore-cli.ts → main()`) passes `description="<prog> — execute apcore
|
|
81
|
+
modules from the command line"` explicitly so the standalone surface is
|
|
82
|
+
unchanged.
|
|
83
|
+
- **Conformance fixtures (`aiperceivable/apcore-cli/conformance/fixtures/apcli-visibility/`)**
|
|
84
|
+
refreshed to match the new debranded help output and to forward `version` /
|
|
85
|
+
`description` from the fixture inputs through `captureHelp()`.
|
|
86
|
+
|
|
87
|
+
### Added
|
|
88
|
+
|
|
89
|
+
- **`--format markdown` and `--format skill`** for `apcli list` and `apcli describe`
|
|
90
|
+
(issue [aiperceivable/apcore-cli#20](https://github.com/aiperceivable/apcore-cli/issues/20)).
|
|
91
|
+
Both delegate to `apcore-toolkit` (`formatModule` / `formatModules`, peer dep
|
|
92
|
+
≥0.6) so the output is byte-identical to the same toolkit call in the Python
|
|
93
|
+
and Rust SDKs. `--format skill` emits vendor-neutral SKILL.md content
|
|
94
|
+
directly loadable by Claude Code (`.claude/skills/<id>/SKILL.md`) and
|
|
95
|
+
Gemini CLI (`.gemini/skills/<id>/SKILL.md`):
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
apcore-cli apcli describe users.create --format skill > .claude/skills/users.create/SKILL.md
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
A new internal adapter `descriptorToScanned()` maps `ModuleDescriptor`
|
|
102
|
+
to the toolkit's `ScannedModule`. The `formatModuleList` and
|
|
103
|
+
`formatModuleDetail` functions are now `async` to support the dynamic
|
|
104
|
+
toolkit import (the existing five-format paths remain effectively
|
|
105
|
+
synchronous and complete before the returned promise resolves).
|
|
106
|
+
- **Issue #18 — host-app `--version` opt-in**: new `version?: string` field on
|
|
107
|
+
`CreateCliOptions`. When supplied, registers `-V/--version` with the host's
|
|
108
|
+
version string. **When omitted, the `--version` flag is no longer registered**
|
|
109
|
+
— embedded CLIs that do not opt in stop leaking the SDK's own version. The
|
|
110
|
+
standalone bin entry passes `version: VERSION` (the SDK package version)
|
|
111
|
+
explicitly so the `apcore-cli` binary's behaviour is preserved. The
|
|
112
|
+
`configureManHelp(...)` man-page generator falls back to the SDK version
|
|
113
|
+
when the host does not supply one, so manpages always carry a version stamp.
|
|
114
|
+
- **Issue #19 — `description?: string`** on `CreateCliOptions`.
|
|
115
|
+
- **Issue #17 — `system.usage` aggregator + `list --sort calls|errors|latency`**:
|
|
116
|
+
new module `src/system-usage.ts` reads `~/.apcore-cli/audit.jsonl`, filters
|
|
117
|
+
by period (default 24h), and returns per-module aggregates (`calls`,
|
|
118
|
+
`errors`, `avg latency_ms`). `list --sort {calls,errors,latency}` now
|
|
119
|
+
consults the aggregator instead of falling back to id-sort with a buried
|
|
120
|
+
`process.stderr.write("Warning: ...")`. When the audit log has no entries
|
|
121
|
+
in the period window the discovery layer prints a user-visible note to
|
|
122
|
+
stderr (`note: no usage data available for --sort <field>; sorted by id.
|
|
123
|
+
...`) and falls back to id-sort. Module-protocol registration of
|
|
124
|
+
`system.usage.summary` / `system.usage.module` as registry-callable
|
|
125
|
+
built-ins is tracked as a follow-up — today the readers are invoked
|
|
126
|
+
directly by the discovery layer.
|
|
127
|
+
- New file: `src/system-usage.ts`.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
8
131
|
## [0.7.0] - 2026-04-25
|
|
9
132
|
|
|
10
133
|
### Added
|
package/README.md
CHANGED
|
@@ -49,9 +49,9 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
|
|
|
49
49
|
pnpm add apcore-cli apcore-js
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
Requires Node.js 18+ and `apcore-js >= 0.
|
|
52
|
+
Requires Node.js 18+ and `apcore-js >= 0.21.0`.
|
|
53
53
|
|
|
54
|
-
**Optional:** install `apcore-toolkit` (>=0.
|
|
54
|
+
**Optional:** install `apcore-toolkit` (>=0.6.0) to enable display overlay and registry writer integration via `applyToolkitIntegration`, `DisplayResolver`, and `RegistryWriter`.
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
57
|
pnpm add apcore-cli apcore-js
|
|
@@ -118,6 +118,8 @@ async function main() {
|
|
|
118
118
|
executor,
|
|
119
119
|
progName: "myapp",
|
|
120
120
|
// expose: { mode: "include", include: ["admin.*"] },
|
|
121
|
+
// apcli: { mode: "exclude", exclude: ["init"] }, // hide init from the apcli group
|
|
122
|
+
// apcli: false, // or hide the entire apcli group
|
|
121
123
|
// extraCommands: [customCmd1, customCmd2],
|
|
122
124
|
});
|
|
123
125
|
cli.parse(process.argv);
|
|
@@ -198,10 +200,10 @@ apcore-cli apcli describe math.add
|
|
|
198
200
|
apcore-cli apcli exec math.add --a 5 --b 10
|
|
199
201
|
```
|
|
200
202
|
|
|
201
|
-
> **Migration note (v0.
|
|
202
|
-
> `
|
|
203
|
-
> inject a `registry`) never had root-level
|
|
204
|
-
>
|
|
203
|
+
> **Migration note (v0.8):** Root-level built-ins (`apcore-cli list`, `apcore-cli describe`, …) were removed in v0.8 — use `<cli> apcli <subcommand>`.
|
|
204
|
+
> Only the `apcli` group is supported; legacy root-level shims have been retired.
|
|
205
|
+
> Embedded integrations (host CLIs that inject a `registry`) never had root-level
|
|
206
|
+
> built-ins in the first place. See the full migration timeline in the spec repo:
|
|
205
207
|
> [`docs/features/builtin-group.md §11 Migration`](../apcore-cli/docs/features/builtin-group.md#11-migration).
|
|
206
208
|
|
|
207
209
|
The canonical 13 `apcli` subcommands:
|
|
@@ -230,7 +232,7 @@ The canonical 13 `apcli` subcommands:
|
|
|
230
232
|
|
|
231
233
|
| Command | Description |
|
|
232
234
|
|---------|-------------|
|
|
233
|
-
| `apcli init
|
|
235
|
+
| `apcli init module <id>` | Scaffold a new module (TS/JS/YAML binding) into the extensions or commands directory (see `registerInitCommand` in `src/init-cmd.ts`) |
|
|
234
236
|
| `apcli validate` | Validate modules and configuration against JSON Schema (see `registerValidateCommand` in `src/discovery.ts`) |
|
|
235
237
|
|
|
236
238
|
**Shell integration**
|
|
@@ -244,8 +246,8 @@ The canonical 13 `apcli` subcommands:
|
|
|
244
246
|
|
|
245
247
|
| Mode | Invocation | Notes |
|
|
246
248
|
|------|------------|-------|
|
|
247
|
-
| **Standalone** (`apcore-cli`) | `apcore-cli apcli <subcommand>` | Discovery flags (`--extensions-dir`, `--commands-dir`, `--binding`) are registered.
|
|
248
|
-
| **Embedded** (`createCli({ registry, … })`) | `<host-cli> apcli <subcommand>` | Discovery flags are gated off (injected registry already supplies modules).
|
|
249
|
+
| **Standalone** (`apcore-cli`) | `apcore-cli apcli <subcommand>` | Discovery flags (`--extensions-dir`, `--commands-dir`, `--binding`) are registered. Only the `apcli` group is supported (legacy root-level shims were removed in v0.8). |
|
|
250
|
+
| **Embedded** (`createCli({ registry, … })`) | `<host-cli> apcli <subcommand>` | Discovery flags are gated off (injected registry already supplies modules). Only the `apcli` group is supported. |
|
|
249
251
|
|
|
250
252
|
### Module Execution Options
|
|
251
253
|
|
|
@@ -257,7 +259,7 @@ When executing a module (e.g. `apcore-cli math.add`), these built-in options are
|
|
|
257
259
|
| `--yes` / `-y` | Bypass approval prompts |
|
|
258
260
|
| `--large-input` | Allow STDIN input larger than 10MB |
|
|
259
261
|
| `--format <fmt>` | Output format: `json`, `table`, `csv`, `yaml`, or `jsonl` |
|
|
260
|
-
| `--sandbox` | Run module in subprocess sandbox (
|
|
262
|
+
| `--sandbox` | Run module in a subprocess sandbox (re-exec with stripped env; 64MiB stdout/stderr cap; 300s default timeout). Hidden by default — set `APCORE_CLI_SANDBOX=1` to enable globally. |
|
|
261
263
|
| `--dry-run` | Run preflight checks (schema, ACL, approval) without executing (FE-11) |
|
|
262
264
|
| `--trace` | Emit execution pipeline trace (strategy, hooks, middleware timings) |
|
|
263
265
|
| `--stream` | Stream results line-by-line for stream-capable modules |
|
|
@@ -284,18 +286,20 @@ The `list` command supports enhanced filtering and inspection flags:
|
|
|
284
286
|
|
|
285
287
|
### Exit Codes
|
|
286
288
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
| `
|
|
290
|
-
|
|
291
|
-
| `
|
|
292
|
-
| `
|
|
293
|
-
| `
|
|
294
|
-
| `
|
|
295
|
-
| `
|
|
296
|
-
| `
|
|
297
|
-
| `
|
|
298
|
-
| `
|
|
289
|
+
The exit codes below are also exported as the `EXIT_CODES` const-object from `apcore-cli` (canonical source: `src/errors.ts`) and are mapped from thrown errors via `exitCodeForError()`.
|
|
290
|
+
|
|
291
|
+
| Code | `EXIT_CODES` key | Meaning |
|
|
292
|
+
|------|------------------|---------|
|
|
293
|
+
| `0` | `SUCCESS` | Success |
|
|
294
|
+
| `1` | `MODULE_EXECUTE_ERROR` / `MODULE_TIMEOUT` | Module execution error |
|
|
295
|
+
| `2` | `INVALID_CLI_INPUT` | Invalid CLI input |
|
|
296
|
+
| `44` | `MODULE_NOT_FOUND` / `MODULE_LOAD_ERROR` / `MODULE_DISABLED` / `DEPENDENCY_NOT_FOUND` / `DEPENDENCY_VERSION_MISMATCH` | Module not found / disabled / load error |
|
|
297
|
+
| `45` | `SCHEMA_VALIDATION_ERROR` | Schema validation error |
|
|
298
|
+
| `46` | `APPROVAL_DENIED` / `APPROVAL_TIMEOUT` | Approval denied or timed out |
|
|
299
|
+
| `47` | `CONFIG_NOT_FOUND` / `CONFIG_INVALID` | Configuration error |
|
|
300
|
+
| `48` | `SCHEMA_CIRCULAR_REF` | Schema circular reference |
|
|
301
|
+
| `77` | `ACL_DENIED` | ACL denied |
|
|
302
|
+
| `130` | *(no key — set by signal handler)* | Execution cancelled (Ctrl+C) |
|
|
299
303
|
|
|
300
304
|
## Configuration
|
|
301
305
|
|
|
@@ -320,6 +324,7 @@ apcore-cli uses a 4-tier configuration precedence:
|
|
|
320
324
|
| `APCORE_CLI_APPROVAL_TIMEOUT` | Default approval prompt timeout in seconds | `60` |
|
|
321
325
|
| `APCORE_CLI_STRATEGY` | Default execution strategy (`standard`, `internal`, `testing`, `performance`, `minimal`) | `standard` |
|
|
322
326
|
| `APCORE_CLI_GROUP_DEPTH` | Maximum nesting depth when rendering grouped module command trees | `2` |
|
|
327
|
+
| `APCORE_CLI_APCLI` | Override apcli group visibility (Tier 2). Accepts `show`/`1`/`true` → all, `hide`/`0`/`false` → none. Sealed by `apcli.disable_env: true`. | *(unset)* |
|
|
323
328
|
|
|
324
329
|
### Config File (`apcore.yaml`)
|
|
325
330
|
|
|
@@ -335,6 +340,11 @@ cli:
|
|
|
335
340
|
approval_timeout: 60 # seconds
|
|
336
341
|
strategy: standard # standard | internal | testing | performance | minimal
|
|
337
342
|
group_depth: 2 # grouped-module command-tree nesting depth
|
|
343
|
+
apcli: # built-in command group visibility (FE-13)
|
|
344
|
+
mode: all # all | none | include | exclude
|
|
345
|
+
include: [] # subcommand allowlist when mode=include
|
|
346
|
+
exclude: [] # subcommand denylist when mode=exclude
|
|
347
|
+
disable_env: false # set true to seal Tier 2 (APCORE_CLI_APCLI env var)
|
|
338
348
|
```
|
|
339
349
|
|
|
340
350
|
## Features
|
|
@@ -347,7 +357,7 @@ cli:
|
|
|
347
357
|
- **TTY-adaptive output** -- rich tables for terminals, JSON for pipes (configurable via `--format`)
|
|
348
358
|
- **Approval gate** -- TTY-aware HITL prompts for modules with `requires_approval: true`, with `--yes` bypass and 60s timeout
|
|
349
359
|
- **Schema validation** -- inputs validated against JSON Schema before execution, with `$ref`/`allOf`/`anyOf`/`oneOf` resolution
|
|
350
|
-
- **Security** -- API key auth (keyring + AES-256-GCM), append-only audit logging, subprocess sandboxing (
|
|
360
|
+
- **Security** -- API key auth (keyring + AES-256-GCM), append-only audit logging, subprocess sandboxing (re-exec model, env stripping, 64MiB output cap)
|
|
351
361
|
- **Shell completions** -- `apcore-cli completion bash|zsh|fish` generates completion scripts with dynamic module ID completion
|
|
352
362
|
- **Man pages** -- `apcore-cli man <command>` for single commands, or `--help --man` for a complete program man page. `configureManHelp()` provides one-line integration for downstream projects
|
|
353
363
|
- **Documentation URL** -- `setDocsUrl()` adds doc links to help footers and man pages
|
|
@@ -380,7 +390,7 @@ apcore-cli (the adapter)
|
|
|
380
390
|
+-- approval TTY-aware HITL approval
|
|
381
391
|
+-- output TTY-adaptive JSON/table output
|
|
382
392
|
+-- AuditLogger JSON Lines execution logging
|
|
383
|
-
+-- Sandbox Subprocess isolation (
|
|
393
|
+
+-- Sandbox Subprocess isolation (re-exec, env stripped, output capped)
|
|
384
394
|
|
|
|
385
395
|
v
|
|
386
396
|
apcore Registry + Executor (your modules, unchanged)
|
|
@@ -388,11 +398,11 @@ apcore Registry + Executor (your modules, unchanged)
|
|
|
388
398
|
|
|
389
399
|
## API Overview
|
|
390
400
|
|
|
391
|
-
**Classes:** `LazyModuleGroup`, `ConfigResolver`, `AuthProvider`, `ConfigEncryptor`, `AuditLogger`, `Sandbox`
|
|
401
|
+
**Classes:** `LazyModuleGroup`, `GroupedModuleGroup`, `ApcliGroup`, `ExposureFilter`, `CliApprovalHandler`, `ConfigResolver`, `AuthProvider`, `ConfigEncryptor`, `AuditLogger`, `Sandbox`
|
|
392
402
|
|
|
393
|
-
**Interfaces:** `CreateCliOptions`, `Registry`, `Executor`, `ModuleDescriptor`
|
|
403
|
+
**Interfaces:** `CreateCliOptions`, `Registry`, `Executor`, `ModuleDescriptor`, `APCore`, `ApcliConfig`, `ApcliMode`, `StrategyInfo`, `StrategyStep`
|
|
394
404
|
|
|
395
|
-
**Functions:** `createCli`, `main`, `buildModuleCommand`, `validateModuleId`, `collectInput`, `schemaToCliOptions`, `reconvertEnumValues`, `resolveRefs`, `checkApproval`, `
|
|
405
|
+
**Functions:** `createCli`, `main`, `buildModuleCommand`, `validateModuleId`, `collectInput`, `schemaToCliOptions`, `reconvertEnumValues`, `resolveRefs`, `checkApproval`, `formatExecResult`, `registerListCommand`, `registerDescribeCommand`, `registerExecCommand`, `registerValidateCommand`, `registerHealthCommand`, `registerUsageCommand`, `registerEnableCommand`, `registerDisableCommand`, `registerReloadCommand`, `registerConfigCommand`, `registerCompletionCommand`, `registerPipelineCommand`, `registerInitCommand`, `setAuditLogger`, `getAuditLogger`, `setVerboseHelp`, `setDocsUrl`, `configureManHelp`, `exitCodeForError`
|
|
396
406
|
|
|
397
407
|
**Errors:** `ApprovalTimeoutError`, `ApprovalDeniedError`, `AuthenticationError`, `ConfigDecryptionError`, `ModuleExecutionError`, `ModuleNotFoundError`, `SchemaValidationError`
|
|
398
408
|
|