ai agent
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Minimal CLI for querying an exported RA3 Mod XML agent snapshot.
|
||||
*
|
||||
* This is intentionally not installed into PATH. It is meant for scripts,
|
||||
* debugging, and as a reference for MCP tool implementations.
|
||||
*
|
||||
* Usage examples:
|
||||
* node out/agent/cli.js --project D:/Mods/Example status
|
||||
* node out/agent/cli.js --snapshot /path/to/snapshot.json.gz find ExampleUnit
|
||||
* node out/agent/cli.js --project D:/Mods/Example refs ExampleUnit GameObject
|
||||
*/
|
||||
|
||||
import { readSnapshotFile, snapshotPathForProject } from "./snapshot";
|
||||
import {
|
||||
findAssets,
|
||||
findDefine,
|
||||
findReferenceGroups,
|
||||
isFileActive,
|
||||
listAssetsByType,
|
||||
resolveIncludeSource,
|
||||
statusFromSnapshot,
|
||||
} from "./query";
|
||||
|
||||
interface CliOptions {
|
||||
snapshotPath: string | null;
|
||||
projectDir: string | null;
|
||||
command: string;
|
||||
args: string[];
|
||||
}
|
||||
|
||||
function parseArgs(argv: string[]): CliOptions {
|
||||
const options: CliOptions = {
|
||||
snapshotPath: null,
|
||||
projectDir: null,
|
||||
command: "status",
|
||||
args: [],
|
||||
};
|
||||
const positional: string[] = [];
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const arg = argv[i];
|
||||
if (arg === "--snapshot" || arg === "-s") {
|
||||
options.snapshotPath = argv[++i] ?? null;
|
||||
} else if (arg === "--project" || arg === "-p") {
|
||||
options.projectDir = argv[++i] ?? null;
|
||||
} else if (arg === "--help" || arg === "-h") {
|
||||
options.command = "help";
|
||||
} else if (arg.startsWith("-")) {
|
||||
// ignore unknown flags
|
||||
} else {
|
||||
positional.push(arg);
|
||||
}
|
||||
}
|
||||
if (positional.length > 0) {
|
||||
options.command = positional[0];
|
||||
options.args = positional.slice(1);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function printHelp(): void {
|
||||
console.log(`RA3 Mod XML agent snapshot CLI
|
||||
|
||||
Usage:
|
||||
node out/agent/cli.js --project <dir> <command> [args...]
|
||||
node out/agent/cli.js --snapshot <file> <command> [args...]
|
||||
|
||||
Commands:
|
||||
status
|
||||
find <id> [type]
|
||||
refs <id> [type]
|
||||
list <type> [prefix]
|
||||
active <file>
|
||||
define <name>
|
||||
resolve <source>
|
||||
help
|
||||
`);
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const options = parseArgs(process.argv.slice(2));
|
||||
if (options.command === "help") {
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
const snapshotPath =
|
||||
options.snapshotPath ??
|
||||
(options.projectDir ? snapshotPathForProject(options.projectDir) : null);
|
||||
if (!snapshotPath) {
|
||||
console.error("No --project or --snapshot provided.");
|
||||
process.exitCode = 2;
|
||||
return;
|
||||
}
|
||||
const snapshot = await readSnapshotFile(snapshotPath);
|
||||
if (!snapshot) {
|
||||
console.error(`Snapshot not found or unreadable: ${snapshotPath}`);
|
||||
process.exitCode = 3;
|
||||
return;
|
||||
}
|
||||
|
||||
const [a, b] = options.args;
|
||||
switch (options.command) {
|
||||
case "status":
|
||||
console.log(JSON.stringify(statusFromSnapshot(snapshot), null, 2));
|
||||
break;
|
||||
case "find":
|
||||
if (!a) {
|
||||
console.error("find requires an id.");
|
||||
process.exitCode = 2;
|
||||
return;
|
||||
}
|
||||
console.log(JSON.stringify(findAssets(snapshot, a, b), null, 2));
|
||||
break;
|
||||
case "refs":
|
||||
if (!a) {
|
||||
console.error("refs requires an id.");
|
||||
process.exitCode = 2;
|
||||
return;
|
||||
}
|
||||
console.log(JSON.stringify(findReferenceGroups(snapshot, a, b), null, 2));
|
||||
break;
|
||||
case "list":
|
||||
if (!a) {
|
||||
console.error("list requires a type.");
|
||||
process.exitCode = 2;
|
||||
return;
|
||||
}
|
||||
console.log(JSON.stringify(listAssetsByType(snapshot, a, b ?? ""), null, 2));
|
||||
break;
|
||||
case "active":
|
||||
if (!a) {
|
||||
console.error("active requires a file path.");
|
||||
process.exitCode = 2;
|
||||
return;
|
||||
}
|
||||
console.log(JSON.stringify({ active: isFileActive(snapshot, a) }, null, 2));
|
||||
break;
|
||||
case "define":
|
||||
if (!a) {
|
||||
console.error("define requires a name.");
|
||||
process.exitCode = 2;
|
||||
return;
|
||||
}
|
||||
console.log(JSON.stringify(findDefine(snapshot, a), null, 2));
|
||||
break;
|
||||
case "resolve":
|
||||
if (!a) {
|
||||
console.error("resolve requires a source.");
|
||||
process.exitCode = 2;
|
||||
return;
|
||||
}
|
||||
console.log(JSON.stringify(resolveIncludeSource(snapshot, a), null, 2));
|
||||
break;
|
||||
default:
|
||||
console.error(`Unknown command: ${options.command}`);
|
||||
process.exitCode = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void main();
|
||||
Reference in New Issue
Block a user