← back to Kickbacks Ai Upstream
src/adapters/types.ts
107 lines
/** Result of a never-throwing real-install operation. */
export interface OpResult {
ok: boolean;
/** Human-readable reason on failure / status note. */
reason?: string;
}
export interface PreflightResult extends OpResult {
compatible: boolean;
/** Target version string if locatable, else null. */
version: string | null;
}
export interface RestoreResult extends OpResult {
restored: boolean;
}
export interface PatchParams {
tier: 0 | 1 | 2 | 3;
adText: string;
iconRef: string;
iconUrl: string;
clickToken: string;
/** Advertiser landing URL. Rendered as the ad anchor's real `href` so the
* VS Code webview host opens it externally on click — the only click-out
* that survives Claude Code's `default-src 'none'` webview CSP (an in-page
* fetch to the loopback is CSP-blocked; postMessage reaches CC's extension,
* not ours). The loopback is used only for the fire-and-forget click metric
* (revived by the companion extension.js connect-src patch). */
clickUrl: string;
/** Correlation id minted at patch time (`<adId>.<rand>` / `debug.<rand>`);
* threaded into the block's loopback /click ping + relayed dlog lines and
* the X-Vibe-Corr metrics header so one grep reconstructs the event chain
* (webview → loopback → ext metric → backend ingest). */
corr: string;
loopbackPort: number;
loopbackToken: string;
/** Webview-reachable loopback base (scheme/host/port + /vibe-ads/<token>).
* On VS Code Remote/Server the webview runs on the client, so raw
* 127.0.0.1 is unreachable — callers resolve this via
* vscode.env.asExternalUri before applyPatch. */
loopbackBase: string;
/** When true the injected block relays timestamped lifecycle events to the
* loopback /log route (→ ~/.vibe-ads/debug.log) for headless diagnosis.
* Resolved from VIBE_ADS_DEBUG / the debug.enabled sentinel at patch time. */
debug?: boolean;
/** When true the injected block also renders the auction ad in Claude
* Code's usage-limit banner (mirror of the spinner ad; spec §3). Resolved
* from the server bannerEnabled flag ⊕ the local debug override at patch
* time. Empty/false ⇒ the block never touches the banner. */
bannerOn?: boolean;
/** W3: cumulative-visible-time threshold (in ms) an ad must accumulate
* before it counts as "shown". Server-authoritative via
* /v1/portfolio.view_threshold_seconds; falls back to 15_000 ms when the
* server did not specify. Baked into the block as
* `__VIBE_ADS_VIEW_THRESHOLD_MS__`. */
viewThresholdMs?: number;
}
/** Ground-truth snapshot for the `Kickbacks: Diagnose` command — everything
* needed to tell a cosmetic flash from a real miss without reading the bundle
* by hand. `bareVerbPresent` is the key tell: a verb word exists in the live
* file but `hasArray` is false ⇒ the bundle format changed (fix the regex);
* neither present ⇒ the file was stripped/corrupted (reinstall Claude Code). */
export interface AdapterDiagnostics {
name: string;
target: string;
targetExists: boolean;
version: string | null;
compatible: boolean;
reason?: string;
isPatched: boolean;
backup: { exists: boolean; path: string | null; hasArray: boolean; hasBlock: boolean };
live: { hasArray: boolean; bareVerbPresent: boolean };
}
/** A patch target (Claude Code now; Codex later). All methods are
* absolute-path, never-throw, and return typed results. */
export interface TargetAdapter {
readonly name: string;
preflight(): PreflightResult;
version(): string | null;
applyPatch(p: PatchParams): OpResult;
/** `keepCsp` (claude-code only) reverts the visible patch but keeps the
* loopback connect-src CSP relaxation — see ClaudeCodeAdapter.restore.
* Routine deactivate passes it; explicit teardown does not. */
restore(opts?: { keepCsp?: boolean }): RestoreResult;
/** True iff the target currently carries our injected block. Cheap
* (one file read); lets a reassert tick no-op when already applied so it
* only does work when the patch actually drifted (CC overwrite / fresh
* load). Optional: adapters without a meaningful notion may omit it. */
isPatched?(): boolean;
/** Ground-truth diagnostics for the user-facing diagnose command. Optional:
* adapters that don't implement it are simply summarised by preflight(). */
diagnose?(): AdapterDiagnostics;
/** Apply ONLY the invisible structural relaxation the loopback needs (the
* connect-src CSP insertion on the sibling extension.js) WITHOUT injecting
* any ad block. Lets activation prime the surface on every boot — even when
* no ad is in hand yet, even signed out — so loopback telemetry works the
* moment an ad arrives instead of waiting for a reassert tick or a manual
* reload. Idempotent, never throws, reversible via restore() (same keepCsp
* contract as applyPatch's CSP layer). A later applyPatch is a no-op on the
* CSP it already inserted. Optional: adapters with no structural layer may
* omit it. */
prime?(): OpResult;
}