"""agent-browser ``credential.read`` plugin (agent-browser.plugin.v1). agent-browser writes ONE JSON envelope on stdin:: {"protocol": "agent-browser.plugin.v1", "type": "credential.resolve", "capability": "credential.read", "request": {"profileName": "...", "itemRef": "...", "url": "..."}} and expects one JSON object on stdout:: {"protocol": "agent-browser.plugin.v1", "success": true, "credential": {"username": ..., "password": ..., "url": ..., "usernameSelector": ..., "passwordSelector": ..., "submitSelector": ...}} The plugin is a thin proxy: it forwards (itemRef, url) to the broker over the unix socket and relays the credential. The broker enforces the item's adapter policy and origin validation before releasing anything. Secret values go agent-browser-stdin -> plugin -> agent-browser; the agent model never sees them. """ from __future__ import annotations import json import sys from .errors import BrokerError from .server import call PROTOCOL = "agent-browser.plugin.v1" def _fail(message): sys.stdout.write(json.dumps({ "protocol": PROTOCOL, "success": False, "error": str(message)[:300], }) + "\n") def main(): try: raw = sys.stdin.read(64 * 1024) envelope = json.loads(raw) except Exception: _fail("bad plugin envelope") return 1 if (envelope.get("protocol") != PROTOCOL or envelope.get("type") != "credential.resolve"): _fail("unsupported plugin request") return 1 req = envelope.get("request") or {} item_ref = req.get("itemRef") url = req.get("url") if not item_ref: _fail("missing itemRef") return 1 try: cred = call("resolve", {"ref": item_ref, "url": url}) except BrokerError as e: _fail(f"{e.code}: {e.message}") return 0 # a clean denial is still a protocol-level response sys.stdout.write(json.dumps({ "protocol": PROTOCOL, "success": True, "credential": cred, }) + "\n") return 0 if __name__ == "__main__": sys.exit(main())