Skip to content

feat(abgui): a console for typing abctl commands with the connection already applied - #10

Merged
TheJakeBraun merged 1 commit into
mainfrom
feat/console
Aug 15, 2026
Merged

TheJakeBraun merged 1 commit into
mainfrom
feat/console

Conversation

@TheJakeBraun

Copy link
Copy Markdown
Contributor

The GUI will always cover less of abctl than abctl covers, and the gap is where people go back to a terminal — re-deriving the connection by hand, and running in whatever directory the shell happened to be in.

That second part isn't hypothetical: resolving gitops/ against the wrong working directory is the bug that made GUI writes land in a tree nobody was looking at.

What it does

Type a command, press Return, read all three streams. It runs through the ordinary client seam, so a typed command is threaded with --context, runs in the chosen workspace, and is recorded and redacted by RecordingRunner exactly like one a button issued — it shows up in the Command Log and the per-verb timing roll-up alongside everything else, because as far as the app is concerned there is no difference.

runConsole deliberately does not map the exit code to an error the way every other client method does: a non-zero exit is a result to render, not a failure to swallow. diff --exit-on-diff returning 3 is drift, not breakage.

Safety, in the order it matters

  • No --yes is ever added. What you type is what runs.
  • A write verb without --yes is flagged before you press Run — abctl will ask on stdin, the console gives it none, and the command aborts having changed nothing. Safe, but baffling if you expected it to run.
  • A write verb with --yes gets abgui's own confirmation naming the command and the context. A typed --yes is the only route in this app to a tenant write that no button asked about, so it doesn't get to be the one that skips asking.
  • sync without --apply is a dry run and is not treated as a write — confirming a dry run would teach people to click through the dialog.

Parsing

CommandLineParser handles quotes and backslash escapes because no shell is involved: a config named Corp WiFi.mobileconfig must arrive as one argument, or the command fails for a reason that looks nothing like the cause.

It is deliberately not a shell — no pipes, redirection or variable expansion. Those would be promises with nothing behind them, and a $TOKEN that silently expanded would put a secret on argv, which this app never does.

Verification

Go untouched and green. 5 new Swift tests: tokenizing with quotes and escapes, the dropped leading abctl (only as the first token), an explicitly quoted empty argument surviving, and both halves of write detection including that a bare sync is not a write. macOS CI is the compile gate.

🤖 Generated with Claude Code

…already applied

The GUI will always cover less of abctl than abctl covers, and the gap is where
people go back to a terminal — re-deriving the connection by hand, and running
in whatever directory the shell happened to be in. That second part is not
hypothetical: resolving `gitops/` against the wrong working directory is the
bug that made GUI writes land in a tree nobody was looking at.

New Console screen. Type a command, press Return, read all three streams.

It runs through the ORDINARY client seam, so a typed command is threaded with
`--context`, runs in the chosen workspace, and is recorded and redacted by
`RecordingRunner` exactly like one a button issued. It appears in the Command
Log and the per-verb timing roll-up alongside everything else, because as far
as the app is concerned there is no difference.

`runConsole` deliberately does NOT map the exit code to an error the way every
other client method does: a non-zero exit is a result to render, not a failure
to swallow. `diff --exit-on-diff` returning 3 is drift, not breakage, and the
console colours it accordingly.

Safety, in the order it matters:

- No `--yes` is ever added. What you type is what runs.
- A write verb typed WITHOUT `--yes` is flagged before you press Run, because
  abctl will ask on stdin, the console gives it none, and the command aborts
  having changed nothing. Safe, but baffling if you expected it to run.
- A write verb typed WITH `--yes` gets abgui's own confirmation naming the
  command and the context. A typed `--yes` is the only route in this app to a
  tenant write that no button asked about, so it does not get to be the one
  that skips asking.
- `sync` without `--apply` is a dry run and is not treated as a write —
  confirming a dry run would teach people to click through the dialog.

`CommandLineParser` handles quotes and backslash escapes because no shell is
involved: a config named `Corp WiFi.mobileconfig` must arrive as one argument.
It is deliberately not a shell — no pipes, redirection or variable expansion —
since those would be promises with nothing behind them, and a `$TOKEN` that
silently expanded would put a secret on argv, which this app never does.

Go untouched and green. 5 new Swift tests cover tokenizing, the dropped leading
`abctl`, an explicitly quoted empty argument, and both halves of write
detection (including that a bare `sync` is not a write).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@TheJakeBraun
TheJakeBraun merged commit 138b1a8 into main Aug 15, 2026
6 checks passed
@TheJakeBraun
TheJakeBraun deleted the feat/console branch August 15, 2026 23:26
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