#!/usr/bin/env node /** * @file The git credential helper AgentHub installs on its own network git * commands (`-c credential.helper=!node `, see git-credentials.js). * Speaks git's credential protocol: `get` reads `key=value` lines on stdin * and answers `username=` / `password=` for a matching protocol + host — * first from `AGENTHUB_GIT_ONCE` (a credential typed for this one command), * then from the store file named by `AGENTHUB_GIT_CRED_FILE`. `store` and * `erase` do nothing: AgentHub saves only what the user asked it to keep, and * only after git has proved it works. Prints nothing else, ever. * @author Nguyễn Ngọc Trí Vĩ */ const fs = require("node:fs"); if (process.argv[2] !== "get") process.exit(0); let input = ""; process.stdin.on("data", (c) => (input += c)); process.stdin.on("end", () => { const want = {}; for (const line of input.split("\n")) { const i = line.indexOf("="); if (i > 0) want[line.slice(0, i)] = line.slice(i + 1); } const protocol = String(want.protocol || "").toLowerCase(); const host = String(want.host || "").toLowerCase(); const matches = (r) => r && r.protocol === protocol && r.host === host && r.password; let hit = null; try { const once = JSON.parse(process.env.AGENTHUB_GIT_ONCE || "null"); if (matches(once)) hit = once; } catch { /* malformed: fall through to the store */ } if (!hit && process.env.AGENTHUB_GIT_CRED_FILE) { try { const rows = JSON.parse(fs.readFileSync(process.env.AGENTHUB_GIT_CRED_FILE, "utf8")); hit = (Array.isArray(rows) ? rows : []).find(matches) || null; } catch { /* no store yet */ } } // A helper that answers nothing lets git fail with its own auth error, // which the dashboard turns into the login form. if (hit) process.stdout.write(`username=${hit.username}\npassword=${hit.password}\n`); });