160 lines
4.1 KiB
TypeScript
160 lines
4.1 KiB
TypeScript
/**
|
|
* 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();
|