firegoat 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +37 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -47,7 +47,7 @@ tests:
47
47
  - run: grep -q '"command":"acme deploy' "$FIREGOAT_SESSION"
48
48
  ```
49
49
 
50
- Whatever `setup` writes to `$FIREGOAT_OUT` is first on the agent's `PATH`.
50
+ Whatever `setup` writes to `$FIREGOAT_OUT` is first on the agent's `PATH`. That only helps for binaries called by bare name: if users run your CLI via `npx`/`uvx`, pack and install it like the npm example, or `npx` fetches the registry release.
51
51
 
52
52
  ### Can an agent find the right package from my docs alone?
53
53
 
package/dist/cli.js CHANGED
@@ -6947,7 +6947,7 @@ var require_public_api = __commonJS(function(exports) {
6947
6947
  // package.json
6948
6948
  var package_default = {
6949
6949
  name: "firegoat",
6950
- version: "0.9.2",
6950
+ version: "0.9.4",
6951
6951
  repository: {
6952
6952
  type: "git",
6953
6953
  url: "git+https://github.com/firegoat-ai/firegoat-cli.git"
@@ -7250,12 +7250,15 @@ async function runClaude(opts) {
7250
7250
  return;
7251
7251
  }
7252
7252
  });
7253
- const init = events[0];
7254
- if (init?.type !== "system" || init.subtype !== "init")
7253
+ const init = events.find((e) => e?.type === "system" && e.subtype === "init");
7254
+ if (!init) {
7255
+ const said = stdout.trim().split(`
7256
+ `)[0]?.slice(0, 300);
7255
7257
  return {
7256
7258
  ok: false,
7257
- reason: `claude did not start a session (exit ${exited.code ?? "by signal"}), see stderr.txt`
7259
+ reason: `claude did not start a session (exit ${exited.code ?? "by signal"})${said ? `: ${said}` : ", see stderr.txt"}`
7258
7260
  };
7261
+ }
7259
7262
  const sessionId = String(init.session_id);
7260
7263
  const result = events.findLast((e) => e?.type === "result");
7261
7264
  if (exited.timedOut)
@@ -7274,7 +7277,7 @@ async function runClaude(opts) {
7274
7277
  if (result.is_error === true || result.subtype !== "success")
7275
7278
  return {
7276
7279
  ok: false,
7277
- reason: `claude result is an error (subtype=${result.subtype})`,
7280
+ reason: `claude result is an error (subtype=${result.subtype})${result.result ? `: ${result.result.slice(0, 300)}` : ""}`,
7278
7281
  result,
7279
7282
  sessionId
7280
7283
  };
@@ -7557,6 +7560,15 @@ function findSession(configDir, sessionId) {
7557
7560
  }
7558
7561
  return null;
7559
7562
  }
7563
+ function usage(r) {
7564
+ const parts = [];
7565
+ if (r.cost !== null)
7566
+ parts.push(`$${r.cost.toFixed(2)}`);
7567
+ if (r.num_turns !== null)
7568
+ parts.push(`${r.num_turns} turns`);
7569
+ parts.push(`${Math.round(r.duration_ms / 1000)}s`);
7570
+ return parts.join(", ");
7571
+ }
7560
7572
  function newRunId() {
7561
7573
  const ts = new Date().toISOString().replace(/\.\d+Z$/, "Z").replace(/[-:]/g, "");
7562
7574
  return `${ts}-${randomBytes(2).toString("hex")}`;
@@ -7690,6 +7702,7 @@ async function evalCommand(args, root) {
7690
7702
  const firegoatDir = ensureFiregoatDir(root);
7691
7703
  const configDir = join3(firegoatDir, ".claude");
7692
7704
  mkdirSync2(configDir, { recursive: true });
7705
+ say(process.env.ANTHROPIC_API_KEY ? "auth: ANTHROPIC_API_KEY (claude bills the API key; unset it to use your claude login)" : "auth: your claude login");
7693
7706
  const loginProblem = checkLogin({
7694
7707
  bin: claudePath,
7695
7708
  env: claudeEnv(configDir),
@@ -7733,7 +7746,7 @@ async function evalCommand(args, root) {
7733
7746
  vars
7734
7747
  });
7735
7748
  results.push(r);
7736
- say(`${r.status.toUpperCase()} ${r.test}#${r.n} ${r.reason}`);
7749
+ say(`${r.status.toUpperCase()} ${r.test}#${r.n} ${r.reason} (${usage(r)})`);
7737
7750
  }
7738
7751
  const totals = { pass: 0, fail: 0, error: 0 };
7739
7752
  for (const r of results)
@@ -7741,8 +7754,9 @@ async function evalCommand(args, root) {
7741
7754
  const doc = { runId, runsDir: runDir, totals, runs: results };
7742
7755
  writeFileSync2(join3(runDir, "summary.json"), `${JSON.stringify(doc, null, 2)}
7743
7756
  `);
7757
+ const cost = results.reduce((sum, r) => sum + (r.cost ?? 0), 0);
7744
7758
  say(`
7745
- ${totals.pass} passed, ${totals.fail} failed, ${totals.error} not graded (${results.length} runs)`);
7759
+ ${totals.pass} passed, ${totals.fail} failed, ${totals.error} not graded (${results.length} runs, $${cost.toFixed(2)})`);
7746
7760
  say(`runs: ${runDir} (end_goal is for you to judge: see run.json per run)`);
7747
7761
  if (opts.json)
7748
7762
  console.log(JSON.stringify(doc, null, 2));
@@ -7787,8 +7801,10 @@ runs: 1
7787
7801
  # setup: uv build --wheel --out-dir "$FIREGOAT_OUT"
7788
7802
  # workdir_setup: uv venv && uv pip install "$FIREGOAT_OUT"/*.whl
7789
7803
  #
7790
- # a CLI binary:
7804
+ # a CLI binary users call by bare name (on PATH as is):
7791
7805
  # setup: go build -o "$FIREGOAT_OUT/mycli" ./cmd/mycli
7806
+ # (an npm/pypi CLI that users run via npx/uvx: pack + install it as above instead;
7807
+ # a binary on PATH does not stop "npx mycli" from fetching the registry release)
7792
7808
  #
7793
7809
  # Helper files (scripts, sample data) go in .firegoat/fixtures/ (committed), not inline here.
7794
7810
  # setup runs in this folder, so: setup: cp -R .firegoat/fixtures/. "$FIREGOAT_OUT"
@@ -7871,18 +7887,28 @@ ${INIT_HELP}`);
7871
7887
  const r = spawnSync2("npx", ["-y", ...SKILLS_ARGV], {
7872
7888
  cwd,
7873
7889
  env,
7874
- stdio: "inherit"
7890
+ stdio: interactive ? "inherit" : "pipe",
7891
+ encoding: "utf8"
7875
7892
  });
7876
7893
  if (r.error || r.status !== 0) {
7894
+ if (!interactive)
7895
+ process.stderr.write(`${r.stdout ?? ""}${r.stderr ?? ""}`);
7877
7896
  console.error(`firegoat init: installing the skills failed (${r.error?.message ?? `exit ${r.status}`}). Run it yourself: npx ${SKILLS_ARGV.join(" ")}`);
7878
7897
  return EXIT.notGraded;
7879
7898
  }
7899
+ console.log("installed skills firegoat-onboarding, suggesting-eval-prompts in .claude/skills/");
7900
+ const ignored = spawnSync2("git", ["check-ignore", "-q", ".claude/skills"], {
7901
+ cwd
7902
+ });
7903
+ if (ignored.status === 0)
7904
+ console.error("warning: git ignores .claude/skills, so teammates and CI won't get the skills. Commit them with: git add -f .claude/skills");
7880
7905
  }
7881
- console.log(`
7906
+ console.log(interactive ? `
7882
7907
  Paste this into your coding agent:
7883
7908
 
7884
7909
  ${AGENT_PROMPT}
7885
- `);
7910
+ ` : `
7911
+ Prompt for your coding agent: ${AGENT_PROMPT}`);
7886
7912
  if (interactive && copyToClipboard(AGENT_PROMPT))
7887
7913
  console.log("\x1B[32mPrompt copied!\x1B[0m");
7888
7914
  return EXIT.pass;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firegoat",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/firegoat-ai/firegoat-cli.git"