apcore-cli 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,81 @@ 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.9.0] - 2026-05-13
9
+
10
+ ### Fixed (2026-05-13 — cross-SDK audit D10/D11/D1)
11
+
12
+ - **`ConfigEncryptor` LOGNAME key-derivation chain** (D10-001) — PBKDF2 username fallback was `USER → USERNAME → "unknown"` (3-tier); now `USER → LOGNAME → USERNAME → "unknown"` (4-tier) matching the spec and Rust. `src/security/config-encryptor.ts:183, 219`.
13
+ - **Sandbox stdin write lacks `'error'` listener** (D11-008) — `child.stdin.on('error', () => {})` added before `write()` so an EPIPE event from a child that exits early no longer surfaces as an uncaught exception. `src/security/sandbox.ts:153`.
14
+ - **`buildSandboxEnv` drops explicitly-empty env values** (D11-009) — `if (process.env[key])` changed to `if (process.env[key] !== undefined)` so `PATH=""` is forwarded uniformly with Python and Rust. `src/security/sandbox.ts:264`.
15
+ - **`exec --trace` flag ignored when used without `--strategy`** (D11-011) — condition `if (opts.strategy && executor.callWithTrace)` changed to `if ((opts.trace || opts.strategy) && executor.callWithTrace)`. `--trace` alone now routes through `callWithTrace` matching Python. `src/discovery.ts:345`.
16
+ - **CLI brand string in auth error messages** (D11-006) — remediation strings now say `apcli config set auth.api_key` (canonical FE-13 name). `src/security/auth.ts:46`.
17
+ - **`requestApproval` missing `requires_approval=false` short-circuit** (D11-014) — returns `approved/not_required` when the request explicitly carries `requires_approval: false`, matching Rust. `src/approval.ts:63`.
18
+ - **`AuthProvider` missing `config.encryptor` peer-attribute fallback** (D11-005) — `getEncryptor()` now walks explicit constructor arg → `config.encryptor` peer attribute → fresh instance, matching Python's three-tier chain. `src/security/auth.ts:22`.
19
+ - **`APCLI_SUBCOMMAND_NAMES` and `DEFAULT_BUILTIN_GROUP_NAME` not re-exported** (D1 re-audit) — both constants added to `src/index.ts:27` export block. Python and Rust already re-exported both.
20
+ - **Standalone bin entrypoint used deprecated `verbose:` field internally** (D9 re-audit) — `src/main.ts:848` `createCli` call now passes canonical `allOptions: verboseHelp`.
21
+ - **Stale `cli.ts` placeholder-type TODO** (D9-W2) — TODO comment updated to document the actual `apcore-js` Registry/ModuleDescriptor shape gap (method names diverge: `listModules`/`getModule` vs `list`/`getDefinition`/`moduleId`), replacing the generic "until available" wording.
22
+
23
+ ### Added
24
+
25
+ - **`CreateCliOptions.allOptions` field** (D1-W5) — canonical successor to the deprecated `verbose` field. Embedders should migrate `createCli({ verbose: true })` → `createCli({ allOptions: true })`. `verbose` remains for backward compat through v0.9 and will be removed in v0.10. `src/main.ts:251`.
26
+ - **`setLogLevel` / `getLogLevel` documented as intentionally TS-only** (D1-W4) — `src/index.ts:96-102` now carries a cross-SDK parity note explaining that Python and Rust delegate to their native logging channels.
27
+ - **`getAuditLogger` documented as intentionally TS-only** (D1 re-audit) — `src/index.ts:106` now carries a note. Only the setter (`setAuditLogger`) is the canonical cross-SDK API.
28
+
29
+ ### Fixed
30
+
31
+ - **CSV `--format csv` heterogeneous-keys data loss** — `formatExecResult` previously derived CSV headers from `Object.keys(rows[0])` only, silently dropping fields that first appeared in later rows. Surfaced via aisee-cli's `summarizeAction()` which emits optional `description` / `solution` fields. The header is now the **union of keys across all rows** in insertion-order. `src/output.ts:340-357`.
32
+ - **CSV line terminator** — now `\r\n` per RFC 4180 (was `\n`). Existing Excel + downstream-parser compatibility improves significantly.
33
+ - **CSV nested-value serialization** — now goes through the toolkit's canonical JSON encoder (compact, insertion-order, unicode-preserved). Behavior was already correct via `JSON.stringify`, but the contract is now enforced at the toolkit layer.
34
+
35
+ ### Changed
36
+
37
+ - **User-visible help/man/completion/error text no longer leaks the `apcore` / `apcore-js` framework name** to end users of downstream CLIs built on apcore-cli. Affected strings: footer hint (`Use --verbose to show all options (including built-in apcore options)` → `… (including built-in options)`, `src/main.ts:947`), `init` group description (`Scaffold new apcore modules` → `Scaffold new modules`, `src/init-cmd.ts:82`), top-level CLI description (`… execute apcore modules from the command line` → `… execute modules from the command line`, `src/main.ts:835`), standalone unwired-registry error message (`Error: no apcore-js registry wired.` → `Error: no module registry wired.`, `src/main.ts:619`), and man-page `ENVIRONMENT` text (`Path to the apcore extensions directory.` → `Path to the extensions directory.`, `src/shell.ts:302`). README's `--verbose` row updated to match. Two `tests/main.test.ts` assertions (`:891`, `:916`) updated to the new error string. Logger names, source comments, type comments, and environment-variable identifiers (`APCORE_*`) are unchanged — only descriptive copy that appears in `--help`, shell completion, `man` output, or user-facing error messages. Cross-SDK parity with Python 0.8.1 and Rust 0.8.1.
38
+
39
+ ### Changed (breaking CLI surface)
40
+
41
+ - **Global `--verbose` flag renamed to `--all-options`** — The help-display flag is now `--all-options`; use `apcore-cli module --help --all-options` to reveal hidden built-in options. `verbose` is removed from the reserved schema property names set — module schemas may now freely define `verbose: boolean` for runtime output control. Tracked in [apcore-cli#21](https://github.com/aiperceivable/apcore-cli/issues/21).
42
+
43
+ ### Changed (breaking peer-dep semantics)
44
+
45
+ - **`apcore-toolkit` promoted from optional to REQUIRED peer dependency** (`>=0.7.0`). All `--format` operations now go through the toolkit's reference implementation for csv/jsonl/markdown/skill (was only markdown/skill). Consumers that did not install the optional peer must add it. `package.json` peer-dependency-meta `optional: true` removed.
46
+
47
+ ### Removed
48
+
49
+ - `csvCellString` and `escapeCsvField` private helpers — replaced by `apcore_toolkit.formatCsv()` and the toolkit's RFC 4180 internals.
50
+
51
+ ### Why
52
+
53
+ Per-SDK CSV reimplementations had accumulated divergence: Python emitted Python repr `{'k': 'v'}`, TS dropped heterogeneous keys, Rust used `\n` not CRLF. The spec MUST language couldn't enforce conformance on downstream consumers (e.g. aisee-cli) that reimplemented. See ADR-09 in `apcore-cli/docs/tech-design.md` for the byte-equivalent vs SDK-native tier split.
54
+
55
+ ### Migration
56
+
57
+ Downstream consumers using only `json` / `table` formats are unaffected at runtime but need `apcore-toolkit@^0.7` installed alongside `apcore-cli@^0.9` (previously optional). aisee-cli and similar adapters get the CSV bug fix automatically on upgrade.
58
+
59
+
60
+ ## [0.8.1] - 2026-05-09
61
+
62
+ ### Fixed
63
+
64
+ - **Init-time deadlock under Bun (`src/security/sandbox.ts`).** The
65
+ sandbox runner's 5 `await import('node:child_process|os|path|fs')`
66
+ calls were hoisted to static `import` statements at the top of
67
+ `sandbox.ts`. The dynamic-import pattern was a holdover from when
68
+ apcore-cli targeted both Node and browser; the CLI is Node-only by
69
+ nature (`#!/usr/bin/env node`, `process.argv[1]` re-exec, child-
70
+ process spawning), so deferring the imports added no value and
71
+ contributed to the Bun deadlock chain when the CLI was loaded via
72
+ `bun run dist/bin/apcore-cli.js`. Verified end-to-end on Bun 1.3.13:
73
+ `--version` returns in 108 ms (was: indefinite hang on Bun 1.2.x).
74
+ No public API change.
75
+ - **C-SNAKE/1 — schema kwargs forwarded under commander's camelCase keys instead of the schema's snake_case property names** (`src/main.ts:985-998`). Commander stores parsed flag values under camelCased attribute names (`--has-solution` → `options.hasSolution`); the action handler previously passed `Object.entries(options)` straight into `schemaKwargs`, so modules reading `input["has_solution"]` always saw `undefined`. Single-word flags (`--module`, `--page`) coincidentally worked because their camelCase form matches the schema name. Multi-word fields (`has_solution`, `sort_by`, `sort_order`) were silently dropped. The fix iterates `schemaOptions` and writes each value back under its original `propName`, matching Python click's auto-derived parameter name and Rust clap's explicit `Arg::new(prop_name)` semantics. Cross-SDK parity restored.
76
+ - **C-SNAKE/2 — boolean `--flag/--no-flag` pair was registered as a single comma-combined commander option** (`src/main.ts:957-975`). The schema-parser produced `flags: "--<flag>, --no-<flag>"` and the registration loop forwarded that string to `cmd.option(...)`. Commander does not parse the comma form the way Python click's `--flag/--no-flag` does — it routes both forms to the negated attribute and stores `false` for both, so `--has-solution` did not flip the value to `true`. Boolean schema flags now register as two separate `Option`s (`--<flag>` carrying the schema default + help, plus a hidden `--no-<flag>` companion); commander's auto-negation routes both to the same camelCase attribute and applies the correct value.
77
+
78
+ ### Added
79
+
80
+ - **`tests/conformance/snake-case-kwargs.test.ts`** — runs the cross-language Algorithm C-SNAKE fixture (`apcore-cli/conformance/fixtures/snake-case-kwargs/cases.json`) against `buildModuleCommand`. Five cases cover positive flag, negation, default fallback, snake_case string flags, and a multi-flag combination. The same fixture is consumed verbatim by the Python and Rust SDK runners.
81
+
82
+
8
83
  ## [0.8.0] - 2026-05-08
9
84
 
10
85
  ### Security
package/README.md CHANGED
@@ -8,7 +8,7 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
8
8
 
9
9
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
10
10
  [![Node](https://img.shields.io/badge/node-18%2B-blue.svg)](https://nodejs.org)
11
- [![Tests](https://img.shields.io/badge/tests-275%2B%20passed-brightgreen.svg)]()
11
+ [![Tests](https://img.shields.io/badge/tests-passing-brightgreen.svg)]()
12
12
 
13
13
  | | |
14
14
  |---|---|
@@ -46,16 +46,15 @@ Terminal adapter for apcore. Execute AI-Perceivable modules from the command lin
46
46
  ## Installation
47
47
 
48
48
  ```bash
49
- pnpm add apcore-cli apcore-js
49
+ pnpm add apcore-cli apcore-js apcore-toolkit
50
50
  ```
51
51
 
52
- Requires Node.js 18+ and `apcore-js >= 0.21.0`.
52
+ Requires Node.js 18+, `apcore-js >= 0.21.0`, and `apcore-toolkit >= 0.7.0` (required peer dep as of v0.9.0).
53
53
 
54
- **Optional:** install `apcore-toolkit` (>=0.6.0) to enable display overlay and registry writer integration via `applyToolkitIntegration`, `DisplayResolver`, and `RegistryWriter`.
54
+ **v0.9.0 breaking change:** `apcore-toolkit` is now a **required** peer dependency (previously optional). All `--format` operations route through the toolkit's byte-equivalent reference implementations for csv / jsonl / markdown / skill. See [tech-design ADR-09](https://github.com/aiperceivable/apcore-cli/blob/main/docs/tech-design.md) for the rationale and migration notes.
55
55
 
56
56
  ```bash
57
- pnpm add apcore-cli apcore-js
58
- pnpm add -D apcore-toolkit # optional, for display overlay / registry writer
57
+ pnpm add apcore-cli apcore-js apcore-toolkit
59
58
  ```
60
59
 
61
60
  ## Quick Start
@@ -151,7 +150,7 @@ your-project/
151
150
  No changes to your project. Just install and run:
152
151
 
153
152
  ```bash
154
- pnpm add apcore-cli apcore-js
153
+ pnpm add apcore-cli apcore-js apcore-toolkit
155
154
  apcore-cli --extensions-dir ./extensions list
156
155
  apcore-cli --extensions-dir ./extensions math.add --a 5 --b 10
157
156
  ```
@@ -185,7 +184,7 @@ apcore-cli [OPTIONS] COMMAND [ARGS]
185
184
  | `--log-level` | `WARNING` | Logging: `DEBUG`, `INFO`, `WARNING`, `ERROR` |
186
185
  | `--version` | | Show version and exit |
187
186
  | `--help` | | Show help and exit |
188
- | `--verbose` | | Show all options in help (including built-in apcore options) |
187
+ | `--all-options` | | Show all options in help (including built-in options) |
189
188
  | `--man` | | Output man page in roff format (use with `--help`) |
190
189
 
191
190
  ### Built-in Commands (the `apcli` group)
@@ -235,12 +234,17 @@ The canonical 13 `apcli` subcommands:
235
234
  | `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`) |
236
235
  | `apcli validate` | Validate modules and configuration against JSON Schema (see `registerValidateCommand` in `src/discovery.ts`) |
237
236
 
238
- **Shell integration**
237
+ **Shell integration** (under `apcli` group)
239
238
 
240
239
  | Command | Description |
241
240
  |---------|-------------|
242
241
  | `apcli completion <shell>` | Generate shell completion script for bash / zsh / fish (see `registerCompletionCommand` in `src/shell.ts`) |
243
- | `man [command]` (root) | Generate a man page in roff format for a single command or the whole program (see `configureManHelp` in `src/shell.ts`). Stays at the root (meta-command). |
242
+
243
+ **Root meta-commands** (NOT under `apcli` — invoked directly on the host CLI)
244
+
245
+ | Command | Description |
246
+ |---------|-------------|
247
+ | `<cli> --help --man [command]` | Generate a man page in roff format for a single command or the whole program (see `configureManHelp` in `src/shell.ts`). This is a root-level option, not an `apcli` subcommand. |
244
248
 
245
249
  #### Standalone vs. embedded surfaces
246
250
 
@@ -251,14 +255,14 @@ The canonical 13 `apcli` subcommands:
251
255
 
252
256
  ### Module Execution Options
253
257
 
254
- When executing a module (e.g. `apcore-cli math.add`), these built-in options are available (hidden by default; use `--verbose` to show in `--help`):
258
+ When executing a module (e.g. `apcore-cli math.add`), these built-in options are available (hidden by default; use `--all-options` to show in `--help`):
255
259
 
256
260
  | Option | Description |
257
261
  |--------|-------------|
258
262
  | `--input -` | Read JSON input from STDIN |
259
263
  | `--yes` / `-y` | Bypass approval prompts |
260
264
  | `--large-input` | Allow STDIN input larger than 10MB |
261
- | `--format <fmt>` | Output format: `json`, `table`, `csv`, `yaml`, or `jsonl` |
265
+ | `--format <fmt>` | Output format: `json`, `table`, `csv`, `yaml`, `jsonl`, `markdown`, `skill`. **v0.9.0:** `csv` / `jsonl` are byte-identical across SDKs via `apcore-toolkit.formatCsv` / `formatJsonl`. Fixes the prior heterogeneous-keys data-loss bug (header was derived from first row only). |
262
266
  | `--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. |
263
267
  | `--dry-run` | Run preflight checks (schema, ACL, approval) without executing (FE-11) |
264
268
  | `--trace` | Emit execution pipeline trace (strategy, hooks, middleware timings) |