···77struct KeyCommand: ParsableCommand {
88 static let configuration = CommandConfiguration(
99 commandName: "key",
1010- abstract: "Send a key event to a terminal pane.",
1010+ abstract: "Send a keyboard shortcut or special key to a terminal pane.",
1111 discussion: """
1212 With one positional argument, the key is sent to the current pane.
1313 With two positional arguments, the first is the target (auto-resolved) and
1414 the second is the key token.
1515+1616+ Printable punctuation currently follows ANSI-style key token semantics.
1717+ For shifted symbols, prefer modifier combos such as shift-1 or shift-left-bracket.
1518 """
1619 )
1720···6164 guard let normalized = KeyTokens.normalize(rawToken) else {
6265 throw ExitError(
6366 code: CLIErrorCode.unsupportedKey,
6464- message: "The key token '\(rawToken.lowercased())' is not supported in v1."
6767+ message: "The key token '\(rawToken.lowercased())' is not supported."
6568 )
6669 }
6770
···8899## What changed in this revision
10101111-Compared with the initial draft, this version makes `key` safer and more script-friendly:
1111+Compared with the initial draft, this version makes `key` broader and more script-friendly:
12121313-- define a strict input grammar with aliases (`return` -> `enter`, `escape` -> `esc`, `pgup` -> `pageup`, ...)
1313+- normalize aliases (`return` -> `enter`, `escape` -> `esc`, `pgup` -> `pageup`, ...)
1414+- accept modifier prefixes and combinations such as `cmd-c`, `shift-tab`, `opt-enter`, `cmd-shift-k`
1515+- accept additional named keys such as `delete-forward`, `insert`, and `f1`...`f12`
1616+- keep CLI token acceptance aligned with the runtime's ANSI-style NSEvent materialization
1417- add `--repeat <n>` as first-class input instead of forcing shell loops
1518- split `requested` vs `normalized` in output so callers can debug token normalization
1619- add `delivery` counters for machine verification (`attempted` / `delivered`)
···1922## Contract goals
20232124- `key` should be deterministic for agent loops and TUI automation.
2525+- v1 follows ANSI-style key token semantics for shortcuts, special keys, and supported punctuation.
2626+- full layout-aware fidelity across keyboard layouts is out of scope for v1.
2227- output must clearly answer:
2328 - what was requested
2429 - what token was actually accepted
···5459Rules:
55605661- exactly one positional `<token>` is required
5757-- parsing is case-insensitive
5862- surrounding spaces are ignored
5963- canonical token form is lowercase kebab-case
6464+- modifier names and named-key aliases are parsed case-insensitively
6565+- single printable letters preserve case semantics: lowercase stays plain (`a`), uppercase implies `shift` (`A` -> `shift-a`)
6666+- mixed-case modifier combos keep that printable-letter rule, for example `Cmd-A` -> `cmd-shift-a` and `Ctrl-A` -> `shift-ctrl-a`
60676168### Canonical tokens
62696363-- `enter`
6464-- `esc`
6565-- `tab`
6666-- `backspace`
6767-- `up`
6868-- `down`
6969-- `left`
7070-- `right`
7171-- `pageup`
7272-- `pagedown`
7373-- `home`
7474-- `end`
7575-- `ctrl-c`
7676-- `ctrl-d`
7777-- `ctrl-l`
7070+Canonical normalized tokens now include:
7171+7272+- navigation keys such as `tab`, `up`, `down`, `left`, `right`, `pageup`, `pagedown`, `home`, `end`
7373+- editing keys such as `enter`, `backspace`, `delete-forward`, `insert`
7474+- printable keys such as letters, digits, and supported ANSI punctuation tokens
7575+- control combinations such as `ctrl-c`, `ctrl-d`, `ctrl-l`, `ctrl-z`
7676+- shortcut combinations such as `cmd-c`, `cmd-shift-k`, `shift-tab`, `opt-enter`
7777+- function keys `f1`...`f12`
78787979### Accepted aliases (normalized to canonical)
8080···8686- `arrow-right` -> `right`
8787- `pgup` -> `pageup`
8888- `pgdn` -> `pagedown`
8989-- `ctrl+c` -> `ctrl-c`
9090-- `ctrl+d` -> `ctrl-d`
9191-- `ctrl+l` -> `ctrl-l`
8989+- `forward-delete` / `deleteforward` -> `delete-forward`
9090+- `ins` -> `insert`
9191+- punctuation aliases such as `[` -> `left-bracket`, `]` -> `right-bracket`, `,` -> `comma`, `'` -> `quote`
9292+- `command-*` -> `cmd-*`
9393+- `alt-*` / `option-*` -> `opt-*`
9494+- `ctrl+*` -> `ctrl-*`
9595+9696+### ANSI punctuation note
9797+9898+- prefer canonical ANSI-style punctuation tokens such as `minus`, `equal`, `comma`, `period`, `slash`, `backslash`, `quote`, `left-bracket`
9999+- express shifted symbols via modifier combos such as `shift-1`, `shift-quote`, `shift-left-bracket`
100100+- raw shifted symbol literals such as `!`, `@`, `{`, `}` are intentionally unsupported in v1
9210193102### `--repeat`
94103···162171- `normalized`: string
163172 - canonical token used by runtime
164173 - must be one of the canonical tokens listed above
165165-- `category`: `"navigation"` | `"editing"` | `"control"`
174174+- `category`: `"navigation"` | `"editing"` | `"control"` | `"shortcut"` | `"function"`
166175167176### `delivery`
168177···216225 "schema_version": "prowl.cli.key.v1",
217226 "error": {
218227 "code": "UNSUPPORTED_KEY",
219219- "message": "The key token 'ctrl-z' is not supported in v1",
228228+ "message": "The key token 'hyper-k' is not supported.",
220229 "details": {
221221- "token": "ctrl-z"
230230+ "token": "hyper-k"
222231 }
223232 }
224233}
+1-1
supacode/CLIService/KeyCommandHandler.swift
···7070 guard let category = KeyTokens.category(for: input.token) else {
7171 return errorResponse(
7272 code: CLIErrorCode.unsupportedKey,
7373- message: "The key token '\(input.token)' is not supported in v1."
7373+ message: "The key token '\(input.token)' is not supported."
7474 )
7575 }
7676