@agentcommunity/aid-doctor
Version:
CLI tool for Agent Interface Discovery (AID) - validate and check AID records
253 lines (248 loc) • 9.11 kB
JavaScript
;
var commander = require('commander');
var aid = require('@agentcommunity/aid');
var chalk = require('chalk');
var ora = require('ora');
var inquirer = require('inquirer');
var clipboardy = require('clipboardy');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var chalk__default = /*#__PURE__*/_interopDefault(chalk);
var ora__default = /*#__PURE__*/_interopDefault(ora);
var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
var clipboardy__default = /*#__PURE__*/_interopDefault(clipboardy);
function buildTxtRecord(formData) {
const parts = ["v=aid1"];
if (formData.uri) parts.push(`uri=${formData.uri}`);
const protoKey = parts.join(";").length > 200 ? "p" : "proto";
if (formData.proto) parts.push(`${protoKey}=${formData.proto}`);
if (formData.auth) parts.push(`auth=${formData.auth}`);
if (formData.desc) parts.push(`desc=${formData.desc}`);
return parts.join(";");
}
function validateTxtRecord(record) {
try {
aid.parse(record);
return { isValid: true };
} catch (error) {
return { isValid: false, error: error instanceof Error ? error.message : "Invalid" };
}
}
// src/cli.ts
var program = new commander.Command();
program.name("aid-doctor").description("CLI tool for Agent Interface Discovery (AID)").version("0.1.0");
function formatDiscoveryResult(result, domain) {
const { record, queryName } = result;
const lines = [
chalk__default.default.green(`\u2705 AID Record Found for ${domain}`),
"",
chalk__default.default.bold("Record Details:"),
` Domain: ${chalk__default.default.cyan(domain)}`,
` Query: ${chalk__default.default.gray(queryName)}`,
` Version: ${chalk__default.default.yellow(record.v)}`,
` Protocol: ${chalk__default.default.magenta(record.proto)}`,
` URI: ${chalk__default.default.blue(record.uri)}`
];
if (record.auth) {
lines.push(` Auth: ${chalk__default.default.yellow(record.auth)}`);
}
if (record.desc) {
lines.push(` Description: ${chalk__default.default.white(record.desc)}`);
}
return lines.join("\n");
}
function formatError(error, domain) {
if (error instanceof aid.AidError) {
const codeColor = error.code >= 1003 ? chalk__default.default.red : chalk__default.default.yellow;
return [
chalk__default.default.red(`\u274C AID Discovery Failed for ${domain}`),
"",
` Error Code: ${codeColor(error.code)} (${error.errorCode})`,
` Message: ${error.message}`
].join("\n");
}
return [
chalk__default.default.red(`\u274C Unexpected Error for ${domain}`),
"",
` ${error instanceof Error ? error.message : String(error)}`
].join("\n");
}
program.command("check <domain>").description("Check a domain for AID records and display a human-readable report").option("-p, --protocol <protocol>", "Try protocol-specific subdomain first").option("-t, --timeout <ms>", "DNS query timeout in milliseconds", "5000").option("--code", "Exit with the specific error code on failure (for scripting)").action(
async (domain, options) => {
const spinner = ora__default.default(`Checking AID record for ${domain}...`).start();
try {
const result = await aid.discover(domain, {
...options.protocol && { protocol: options.protocol },
timeout: Number.parseInt(options.timeout)
});
if (result.record.proto !== "local" && process.env.AID_SKIP_SECURITY !== "1") {
spinner.text = "Validating redirect policy...";
await aid.enforceRedirectPolicy(result.record.uri, Number.parseInt(options.timeout));
}
spinner.stop();
console.log(formatDiscoveryResult(result, domain));
process.exit(0);
} catch (error) {
spinner.stop();
console.log(formatError(error, domain));
if (options.code && error instanceof aid.AidError) {
process.exit(error.code);
} else {
process.exit(1);
}
}
}
);
program.command("json <domain>").description("Check a domain for AID records and output machine-readable JSON").option("-p, --protocol <protocol>", "Try protocol-specific subdomain first").option("-t, --timeout <ms>", "DNS query timeout in milliseconds", "5000").action(async (domain, options) => {
try {
const result = await aid.discover(domain, {
...options.protocol && { protocol: options.protocol },
timeout: Number.parseInt(options.timeout)
});
if (result.record.proto !== "local") {
await aid.enforceRedirectPolicy(result.record.uri, Number.parseInt(options.timeout));
}
console.log(
JSON.stringify(
{
success: true,
domain,
queryName: result.queryName,
record: result.record,
timestamp: (/* @__PURE__ */ new Date()).toISOString()
},
null,
2
)
);
process.exit(0);
} catch (error) {
if (error instanceof aid.AidError) {
console.log(
JSON.stringify(
{
success: false,
domain,
error: {
code: error.code,
errorCode: error.errorCode,
message: error.message
},
timestamp: (/* @__PURE__ */ new Date()).toISOString()
},
null,
2
)
);
process.exit(error.code);
} else {
console.log(
JSON.stringify(
{
success: false,
domain,
error: {
code: 1,
errorCode: "UNKNOWN_ERROR",
message: error instanceof Error ? error.message : String(error)
},
timestamp: (/* @__PURE__ */ new Date()).toISOString()
},
null,
2
)
);
process.exit(1);
}
}
});
program.command("generate").description("Run an interactive prompt to generate a new AID record").action(async () => {
console.log(chalk__default.default.bold.cyan("AID Record Generator"));
console.log(chalk__default.default.gray("This tool will guide you through creating a valid DNS TXT record.\n"));
const answers = await inquirer__default.default.prompt([
{
type: "input",
name: "domain",
message: "What is the primary domain for your agent?",
validate: (input) => input ? true : "Domain cannot be empty."
},
{
type: "input",
name: "uri",
message: "What is the full URI of your agent's endpoint?",
validate: (input) => {
try {
new URL(input);
return true;
} catch {
return "Please enter a valid URI (e.g., https://api.example.com/agent).";
}
}
},
{
type: "list",
name: "proto",
message: "Select the communication protocol:",
choices: Object.keys(aid.PROTOCOL_TOKENS),
default: "mcp"
},
{
type: "list",
name: "auth",
message: "Select the authentication method (if any):",
choices: ["none", ...Object.keys(aid.AUTH_TOKENS)],
filter: (val) => val === "none" ? "" : val
},
{
type: "input",
name: "desc",
message: "Enter a short description (optional):",
validate: (input) => {
if (!input) return true;
const byteLength = new TextEncoder().encode(input).length;
return byteLength <= 60 || `Description is ${byteLength} bytes (max 60).`;
}
}
]);
const formData = answers;
const txtRecord = buildTxtRecord(formData);
const validation = validateTxtRecord(txtRecord);
console.log(chalk__default.default.green("\n--- Generation Complete ---\n"));
console.log(chalk__default.default.bold("Host:"));
console.log(chalk__default.default.yellow(`_agent.${formData.domain}`));
console.log("");
console.log(chalk__default.default.bold("Type:"));
console.log(chalk__default.default.yellow("TXT"));
console.log("");
console.log(chalk__default.default.bold("Value:"));
console.log(chalk__default.default.yellow(txtRecord));
console.log("");
if (validation.isValid) {
try {
await clipboardy__default.default.write(txtRecord);
console.log(
chalk__default.default.bold.green("\u2705 Success! The TXT record value has been copied to your clipboard.")
);
} catch {
console.log(chalk__default.default.red("Could not copy to clipboard. Please copy the value manually."));
}
} else {
console.log(chalk__default.default.bold.red(`\u{1F525} Validation Failed: ${validation.error}`));
}
});
program.command("version").description("Show version information").action(() => {
console.log(
[
chalk__default.default.bold("aid-doctor") + " - Agent Interface Discovery CLI",
`Version: ${chalk__default.default.green("0.1.0")}`,
`Node: ${chalk__default.default.gray(process.version)}`,
`Platform: ${chalk__default.default.gray(process.platform)}`,
"",
"For more information, visit:",
chalk__default.default.blue("https://aid.agentcommunity.org")
].join("\n")
);
});
program.parse();
//# sourceMappingURL=cli.cjs.map
//# sourceMappingURL=cli.cjs.map