aboutsummaryrefslogtreecommitdiff
path: root/duet.el
Commit message (Collapse)AuthorAgeFilesLines
* feat: add the transport-backend registry and contract checksCraig Jennings2026-06-061-1/+251
| | | | | | | | | | This is the seam every transport plugs into (Phase 2 in the design spec). A duet-backend struct carries a scorer, a command builder, capability flags, and contract metadata; duet-register-backend keeps a registry where re-registering a name replaces the prior backend, which is how a user or plugin overrides a built-in. duet--select-backend asks every backend to score an endpoint pair and picks the lowest cost, breaking ties toward the most recently registered. The failure-normalizer interface turns a raw process failure into a class, a cause, evidence, a safety outcome, and next actions. Backends supply a pattern table via duet-define-cli-failure-patterns; anything unmatched falls back to a minimal normalizer that covers launch failure, missing executable, stall, signal, and unknown exit. This is what will let DUET explain a failure instead of dumping stderr. Secrets are redacted before they reach a log: a pattern keeps its group-1 field label and strips the value, and a backend with no secret surface declares :none rather than an empty pattern list, so a forgotten declaration (nil) stays distinguishable from a deliberate one. The tiered contract checks (minimum, publishable, capability) return a list of violations a backend author asserts is empty in one ERT test. The built-in rsync and TRAMP backends register through this same API in Phase 3, once their command builders land; here the machinery is exercised by fake backends.
* feat: add duet--classify-pathCraig Jennings2026-06-061-0/+42
| | | | | | | | duet--classify-path turns a path string into a plist describing where it lives and how to reach it: :locality (local or remote), :method, :user, :host, :port, :localname, and :hop for multi-hop paths. It's the pure foundation the transfer-spec and connection layers build on (Phase 1 in the design spec). TRAMP does the dissection, so any path file-remote-p recognizes is remote and everything else is local. A local path is expanded, so a leading ~ resolves to the home directory. A remote localname is kept verbatim because a ~ there is the remote home, not this machine's. Classification never signals: an incomplete string like /ssh:host that TRAMP rejects as a remote name falls back to local, since validating raw TRAMP input belongs to the connection reader, not here. I probed TRAMP's real contract before writing the tests (port comes back as a string, a multi-hop path reports the final host with the leading hops in :hop), so the Normal/Boundary/Error cases assert what TRAMP actually returns rather than what I'd have guessed.
* chore: scaffold the Duet package skeletonCraig Jennings2026-06-061-0/+48
Initial skeleton for Duet, a two-pane file commander built on dirvish/dired: the package header and entry-command stub, the README, and the test directory. Pre-alpha — no functionality yet.