File size: 3,329 Bytes
c4ae742 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | #!/usr/bin/env node
// Slack analyzer CLI. Usage:
// node index.mjs path/to/recording.zip --out result.json
// env: OPENAI_API_KEY (required), OPENAI_BASE_URL, OPENAI_MODEL
import fs from "node:fs/promises";
import path from "node:path";
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const importerMod = require("../scripts/slack/importer.js");
const rulesMod = require("../scripts/slack/rules.js");
const clientMod = require("../scripts/slack/client.js");
function loadJSZip() {
const candidates = [
"jszip",
"../vendor/jszip.min.js",
"../discord-cli/node_modules/jszip"
];
for (const candidate of candidates) {
try {
const mod = require(candidate);
return mod && mod.default ? mod.default : mod;
} catch (_) {
// Try the next fallback.
}
}
throw new Error(
"Unable to load JSZip. Run npm install in slack-cli, or keep ../vendor/jszip.min.js available."
);
}
const JSZip = loadJSZip();
function parseArgs(argv) {
const args = { _: [] };
for (let i = 2; i < argv.length; i += 1) {
const a = argv[i];
if (a === "--out") args.out = argv[++i];
else if (a === "--help" || a === "-h") args.help = true;
else args._.push(a);
}
return args;
}
function usage() {
process.stdout.write("Usage: node index.mjs <recording.zip> [--out result.json]\n");
process.stdout.write("Env: OPENAI_API_KEY (required), OPENAI_BASE_URL, OPENAI_MODEL\n");
}
async function main() {
const args = parseArgs(process.argv);
if (args.help || args._.length < 1) { usage(); process.exit(args.help ? 0 : 1); }
const zipPath = path.resolve(args._[0]);
const outPath = args.out ? path.resolve(args.out) : null;
const apiKey = process.env.OPENAI_API_KEY;
if (!apiKey) { process.stderr.write("OPENAI_API_KEY is required\n"); process.exit(2); }
const baseURL = process.env.OPENAI_BASE_URL || "https://api.openai.com/v1/responses";
const model = process.env.OPENAI_MODEL || "gpt-5.4";
const buffer = await fs.readFile(zipPath);
const parsed = await importerMod.readZip({ arrayBuffer: () => Promise.resolve(buffer), name: path.basename(zipPath) }, JSZip);
const evidence = importerMod.buildEvidence(parsed);
const flags = rulesMod.runLocalRules(evidence);
process.stderr.write(`[info] requests=${evidence.requests.length} endpoints=${Object.keys(evidence.endpoints).length} flags=${flags.length}\n`);
const { result } = await clientMod.analyze(evidence, flags, {
apiKey,
baseURL,
apiMode: /chat\/completions/.test(baseURL) ? "chat" : "responses",
model
});
const optimizedResult = rulesMod.optimizeResult ? rulesMod.optimizeResult(result, evidence) : result;
const validated = (optimizedResult.recommended_rubrics || []).map((r) => ({
...r,
_validation: rulesMod.validateCheckerKey(r.checker_key, evidence)
}));
const finalOut = {
...optimizedResult,
recommended_rubrics: validated,
local_flags: flags
};
const json = JSON.stringify(finalOut, null, 2);
if (outPath) {
await fs.writeFile(outPath, json);
process.stderr.write(`[info] wrote ${outPath}\n`);
} else {
process.stdout.write(json + "\n");
}
}
main().catch((e) => {
process.stderr.write("[error] " + (e && e.stack ? e.stack : e) + "\n");
process.exit(1);
});
|