Skip to content

ShellCommandKit: vend bridged Commands as instances + redact Sandbox.Denial#16

Merged
odrobnik merged 2 commits into
mainfrom
claude/command-base-factory
Jun 9, 2026
Merged

ShellCommandKit: vend bridged Commands as instances + redact Sandbox.Denial#16
odrobnik merged 2 commits into
mainfrom
claude/command-base-factory

Conversation

@odrobnik

@odrobnik odrobnik commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Completes ShellKit's role as the command-building base for the Cocoanetics CLI toolchain — the layer that every shellkit-compatible CLI (sqlite3, git, jq, …) is built on, with no bridge duplicated in each consumer.

Changes

  1. Shell.parsableCommand<P: ParsableCommand>(_:) -> Command — a public factory that builds (but doesn't register) a bridged Command, deriving the name exactly as register(_:) does (which now delegates to it). Lets a producer package (SwiftPorts) vend ready-to-install Command instances to an installer (SwiftBash) — previously the bridge was only reachable via register(_:), which stores into a Shell's in-memory map. The bridge type stays internal. Purely additive.
  2. Sandbox.Denial redaction in the bridge — the bridge funnelled every non-ExitCode/non-cancellation error through ArgumentParser's fullMessage(for:), which String(describing:)s a Sandbox.Denial and dumps the sandbox root + requested path. Now caught explicitly and rendered as just reason. Putting this in the base protects every bridged command once, instead of each embedder re-implementing it.

Verification

swift build + swift test green (incl. the existing ArgumentParserBridgeTests and a new factory test).

Landing

First of a coordinated 4-repo change (ShellKit → SQLiteKit → SwiftPorts → SwiftBash). Merge this first — the others depend on the factory (and inherit the redaction). Additive + backward-compatible, so it's safe to merge ahead of the rest.

🤖 Generated with Claude Code

odrobnik and others added 2 commits June 9, 2026 20:43
…mmand)

`ShellCommandKit` could bridge an ArgumentParser command into a ShellKit
`Command` only via `Shell.register(_:)`, which stores the bridge in a
shell's in-memory `commands` map. An external installer that maintains its
own registry — e.g. a filesystem-backed bin catalog that places commands
at `/usr/bin/…` so they're PATH-resolvable — had no way to obtain the
bridged `Command` instance to install.

Add `Shell.parsableCommand(_:)`, a public static factory that builds (but
does not register) a bridged `Command`, deriving its name from
`configuration.commandName` exactly as `register(_:)` does. `register(_:)`
now delegates to it, so there's a single bridging path. The bridge type
itself stays internal. Purely additive and backward-compatible.

This lets producer packages (e.g. SwiftPorts) vend ready-to-install
ShellKit `Command`s built on ShellKit's own bridge — no duplicate bridge
in each shell.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bridge funnelled every non-ExitCode/non-cancellation error through
ArgumentParser's `fullMessage(for:)`, which `String(describing:)`s a
`Sandbox.Denial` and dumps all its fields — including the sandbox root and
the requested path. For an app-as-sandbox embedder that leaks the container
path into ordinary command error output.

Catch `Sandbox.Denial` explicitly and print only its `reason`. Putting this
in the command-building base means every bridged command is protected once,
rather than each embedder re-implementing the redaction in its own bridge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant