Documentation
¶
Overview ¶
Package capture owns the single dest->source write-back path. apply substitutes ${secret:…} into a destination as cleartext and may drop source-only fields the rendered dest never carries; any flow that reads a destination back into the canonical source (import, reconcile write-back, a future "adopt") must invert both, in exactly one place, or it reintroduces a recurring class of bugs (cleartext-secret persistence, source-only field drift, backup bypass).
Capture is that place. It re-references secrets, preserves source-only fields, and routes every write through internal/source/writer.go.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Opts ¶
type Opts struct {
// Warn receives a human-readable warning when a ${secret:…} reference in
// the current source cannot be resolved (backend unavailable / locked), so
// re-referencing may have left cleartext in the written-back file. nil
// discards it. This is the guard that keeps a secret from silently landing
// in ~/.agentsync.
Warn io.Writer
}
Opts tunes a Capture call.
type Result ¶
type Result struct {
// Written lists the source-relative paths written, in write order.
Written []string
}
Result reports what Capture wrote.
func Capture ¶
Capture persists ingested — a canonical reconstructed from a destination — back into the canonical source at home. It is the single dest->source path; both import and reconcile build a single-item canonical and call it.
For every component present in ingested it, in one place:
- normalizes json.Number values in the MCP/LSP Extra passthrough maps to int64/float64 (normalizeExtraNumbers) so a UseNumber-decoded native integer is persisted as a TOML integer, not a string;
- re-references resolved secrets back to ${secret:…} against the current source (secrets.ReReferenceCanonical), so a live credential apply wrote into the destination is never persisted into ~/.agentsync;
- preserves MCP/LSP targeting the destination doesn't fully carry: `agents` is source-only (no native dest carries it) and is ALWAYS restored, so write-back can't silently broaden a server's exposure; `enabled` IS carried by some dests (Codex reads native `enabled` — issue #152), so the source value is restored only when the ingest carried none (nil) — a real native enable/disable round-trips, while a dest that omits `enabled` keeps the source state (so write-back still can't silently clear it);
- writes through internal/source/writer.go (never iox.AtomicWrite directly).
The current source MUST load for Capture to run: re-referencing and source-only field preservation both read it. source.Load returns an empty Canonical (no error) for an empty/absent home — the first-import / "adopt a foreign dest item" case — so steps 1–2 run as harmless no-ops there, which is correct (apply only substitutes from a source ${secret:…}, so a brand-new item carries no secret WE resolved). But source.Load DOES error on any malformed file anywhere in the tree, and that is exactly when a user is most likely re-importing. Writing in that state would skip re-referencing and persist a resolved cleartext secret into ~/.agentsync (a committed dotfiles repo) with no warning. So Capture fails CLOSED: it refuses to write and surfaces the load error rather than risk leaking a credential.