Skip to content

feat!: remove the v1 line-based socket protocol#75

Merged
arzafran merged 1 commit into
mainfrom
refactor/delete-v1-protocol
Jul 8, 2026
Merged

feat!: remove the v1 line-based socket protocol#75
arzafran merged 1 commit into
mainfrom
refactor/delete-v1-protocol

Conversation

@arzafran

@arzafran arzafran commented Jul 8, 2026

Copy link
Copy Markdown
Member

What this does

Programa's terminal socket has spoken two protocols side by side: an old space-delimited
line protocol ("v1") and a newer JSON-RPC protocol ("v2"). Every consumer — the CLI, the
shell integration, the automated tests, and the remote daemon — now speaks v2 exclusively,
so this PR deletes the old protocol and everything that only existed to serve it.

Breaking change for anyone with custom scripts: if you (or a script, alias, or tool)
talk to Programa's socket directly with the old space-delimited commands (list_windows,
focus_window "id", report_pwd ..., etc.) instead of through the programa CLI, those
commands will now get a JSON error (v1_removed) instead of a response. Everyone using the
programa CLI is already unaffected — it moved to v2 in #74.

Summary

  • TerminalController.processCommand now dispatches JSON unconditionally. A non-JSON line
    gets a terse v1_removed JSON error pointing at the v2 protocol instead of being routed
    into the old ~90-case command switch.
  • Deleted the v1 switch and every handler function that became unreferenced once it was
    gone, along with their v1-only argument-parsing helpers (parseOptions/
    parseOptionsNoStop, resolveTabForReport, withReportTargetSurface,
    upsertSidebarMetadata/clearSidebarMetadata/listSidebarMetadata,
    schedulePanelMetadataMutation, parseReadScreenArgs, plus two small structs used only
    by read_screen argument parsing).
  • Kept as shared helpers — verified each still has a live v2 caller before touching it:
    • setShortcut, simulateShortcut, activateApp, isTerminalFocused, readTerminalText,
      renderStats, layoutDebug, bonsplitUnderflowCount/resetBonsplitUnderflowCount,
      emptyPanelCount/resetEmptyPanelCount, focusFromNotification, flashCount/
      resetFlashCounts, panelSnapshot/panelSnapshotReset, captureScreenshot — each of
      v2's debug.* methods calls straight into these as its implementation core, so the old
      v1-named function stayed even though its switch case line is gone.
    • Self.socketFastPathState (the shell-activity dedup state) and
      tailTerminalLines/readTerminalTextBase64(terminalPanel:...) — used directly by
      v2SurfaceReportShellState and v2SurfaceReadText/screen-snapshot code respectively.
  • Auth resolution: auth was never actually a v1 switch command in the way the rest of
    the protocol was — authResponseIfNeeded intercepts auth <password> (v1-style line) and
    auth.login (v2 JSON-RPC) as a connection-level preamble before any protocol dispatch,
    and both paths already did real password verification. The only wrinkle: the v1 switch had
    a fallback case "auth" that answered "OK: Authentication not required" for the (fairly
    common) case where the CLI has a locally-resolvable password but the server's access mode
    doesn't actually require one — deleting the switch would have made the CLI's raw auth <password> line hit the new v1_removed error and fail auth in that case. Fixed by
    migrating the CLI's auth call (CLI/programa.swift) from the raw auth <password> line to
    auth.login — the v2 protocol already has a symmetric fallback case for the "not required"
    scenario (v2's auth.login case returns authenticated: true, required: false), so no new
    server-side method was needed, only the client-side call.
  • Removed the now-dead isV2: false branch's backing data (focusIntentV1Commands) from the
    socket focus-mutation policy, since no code path can produce isV2: false for a real
    command anymore. Updated the one unit test that exercised that branch by v1 command name to
    cover the v2 equivalent instead (window.focus, debug.shortcut.simulate).
  • Docs: docs/v2-api-migration.md collapses from a migration-tracking doc into a short
    "v1 was removed" note that keeps the v1->v2 method-name mapping table for anyone reading old
    scripts or commits. docs/socket-focus-steal-audit.todo.md and
    docs/agent-browser-port-spec.md (both are audit/planning docs from the earlier migration)
    get a short annotation marking their v1-specific sections historical, without rewriting
    their audit trail. CLAUDE.md's socket-threading-policy examples are reworded from v1
    command names (report_*) to their v2 equivalents (surface.report_*) — the policy itself
    is unchanged, it always governed v2 telemetry too.

Line delta: Sources/TerminalController.swift goes from 12834 to 9615 lines (-3219).
Net repo diff: +156 / -3410 across 7 files.

Test Plan

  • xcodebuild ... -scheme programa -- BUILD SUCCEEDED
  • xcodebuild ... -scheme programa-cli -- BUILD SUCCEEDED
  • xcodebuild ... -scheme programa-unit build-for-testing -- TEST BUILD SUCCEEDED
  • Grepped programaTests/ for every deleted function name -- the handful of matches are
    all unrelated identically-named methods on other types (TabManager.closeWorkspace,
    KeyboardShortcutSettings.setShortcut, AppDelegate.moveWorkspaceToWindow, etc.), not
    calls into the deleted TerminalController wrappers (which were private to that
    file, so cross-file access was never possible) -- confirmed by the test target
    compiling cleanly.
    • programaTests/TerminalControllerSocketSecurityTests.swift: updated
      testSocketCommandPolicyDistinguishesFocusIntent (see above); left
      testPasswordModeRejectsUnauthenticatedCommands untouched since it only exercises the
      pre-protocol auth gate, which is unaffected by this change.
  • tests_v2/ is the CI gate for full runtime verification (never run locally per repo
    policy). Traced through the relevant tests by hand: test_cli_global_flags_and_v1_error_contract.py's
    ping calls already go through the CLI's v2 system.ping, and its implicit auth call
    (via SocketPasswordResolver) now goes through the migrated auth.login path -- both
    unaffected by the v1 deletion.

Not merging -- please review.

v2 JSON-RPC is now the only socket protocol. All consumers were migrated
first (CLI in #74, shell integration in #72, tests in #71/#73; the remote
daemon was already v2-only), so this deletes the v1 line dispatch itself
and everything that only existed to serve it.

- TerminalController.processCommand now dispatches JSON unconditionally;
  a non-JSON line gets a terse v1_removed error instead of being routed
  to the old space-delimited command switch.
- Deletes the v1 switch (~90 cases) and every handler function that
  becomes unreferenced, plus their v1-only parsing helpers
  (parseOptions/parseOptionsNoStop, resolveTabForReport,
  withReportTargetSurface, upsertSidebarMetadata/clearSidebarMetadata/
  listSidebarMetadata, schedulePanelMetadataMutation,
  parseReadScreenArgs). Debug handlers that v2's debug.* methods reuse
  as their implementation core (setShortcut, simulateShortcut,
  activateApp, isTerminalFocused, readTerminalText, renderStats,
  layoutDebug, bonsplit/empty-panel/flash counters,
  focusFromNotification, panelSnapshot(Reset), captureScreenshot) are
  kept, since they're still live v2 entry points, not v1 relics.
  Self.socketFastPathState and tailTerminalLines/
  readTerminalTextBase64(terminalPanel:) stay too - v2 surface-telemetry
  and screen-read methods depend on them directly.
- auth was already a connection-level preamble (authResponseIfNeeded,
  handled before any protocol dispatch) supporting both a raw
  auth-plus-password line and v2 auth.login; only the CLI's raw-line
  call needed migrating, which this does (auth.login now).
- Removes the now-unreachable isV2:false focus-intent allowlist
  (focusIntentV1Commands) and updates the one unit test that exercised
  it directly to cover the v2 equivalent instead.
- Docs: v2-api-migration.md collapses to a short removal note plus the
  v1->v2 name mapping (kept for reference); socket-focus-steal-audit.todo.md
  and agent-browser-port-spec.md get historical annotations; CLAUDE.md's
  socket-threading-policy examples are reworded to v2 method names.

TerminalController.swift: 12834 -> 9615 lines (-3219). Net repo diff:
+156/-3410 across 7 files.

Breaking change: any external script or tool that still speaks the old
space-delimited socket protocol directly (rather than through the CLI)
will now get a v1_removed JSON error instead of a response. Use the CLI
or the v2 JSON-RPC protocol described in docs/v2-api-migration.md.
@arzafran arzafran merged commit e1e2b09 into main Jul 8, 2026
7 of 8 checks passed
@arzafran arzafran mentioned this pull request Jul 8, 2026
2 tasks
arzafran added a commit that referenced this pull request Jul 8, 2026
The macOS Compatibility smoke test still sent raw v1 lines (ping,
send) and failed on main after the v1 protocol removal (#75) with a
v1_removed error — the one consumer the migration inventory missed
because it greps workflows for test paths, not inline socket writes.
Ported to system.ping and surface.send_text.
@arzafran arzafran deleted the refactor/delete-v1-protocol branch July 10, 2026 16:05
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