@review-agent/core 0.1.1 → 0.1.2

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.
package/dist/index.d.ts CHANGED
@@ -466,7 +466,7 @@ declare const RECORD_VERSION: 1;
466
466
  /** The version of this engine, on every record it writes. Kept in step with
467
467
  * `packages/core/package.json` by `record.test.ts` — a record whose engine version is a guess is
468
468
  * worth less than no record at all (design §4.7). */
469
- declare const ENGINE_VERSION = "0.1.1";
469
+ declare const ENGINE_VERSION = "0.1.2";
470
470
  type RecordedSkill = {
471
471
  id: string;
472
472
  path: string;
package/dist/index.js CHANGED
@@ -16,8 +16,61 @@ import { z as z3 } from "zod";
16
16
 
17
17
  // src/cli-process.ts
18
18
  import { spawn } from "child_process";
19
+ import { accessSync, constants, realpathSync, statSync } from "fs";
20
+ import { posix, win32 } from "path";
19
21
  import { z } from "zod";
20
- var claudeBinary = () => process.env.REVIEW_AGENT_CLAUDE_BIN ?? "claude";
22
+ var resolveClaudeBinary = (a) => {
23
+ const platform = a.platform ?? process.platform;
24
+ const path = platform === "win32" ? win32 : posix;
25
+ const isExecutableFile = a.isExecutableFile ?? executableFileTest(platform);
26
+ const real = a.realpath ?? realpathOrSelf;
27
+ const avoid = real(path.resolve(a.avoidDir));
28
+ const inside = (candidate) => {
29
+ const rel = path.relative(avoid, real(candidate));
30
+ return rel === "" || !(rel === ".." || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel));
31
+ };
32
+ const named = a.env.REVIEW_AGENT_CLAUDE_BIN;
33
+ if (named !== void 0 && named !== "") {
34
+ if (!path.isAbsolute(named)) {
35
+ throw new Error("REVIEW_AGENT_CLAUDE_BIN must be an absolute path to the Claude Code binary; a relative one could resolve inside the code under review");
36
+ }
37
+ if (inside(named)) {
38
+ throw new Error("REVIEW_AGENT_CLAUDE_BIN points inside the checkout of the code under review; refusing to run it");
39
+ }
40
+ return named;
41
+ }
42
+ const names = platform === "win32" ? ["claude.exe"] : ["claude"];
43
+ for (const dir of pathEntries(a.env, platform)) {
44
+ if (dir === "" || !path.isAbsolute(dir)) continue;
45
+ for (const name of names) {
46
+ const candidate = path.join(dir, name);
47
+ if (!isExecutableFile(candidate) || inside(candidate)) continue;
48
+ return candidate;
49
+ }
50
+ }
51
+ throw new Error(platform === "win32" ? "Claude Code was not found: no claude.exe in an absolute PATH directory. Install it with Anthropic's installer (irm https://claude.ai/install.ps1 | iex) or WinGet, or set REVIEW_AGENT_CLAUDE_BIN to the absolute path of claude.exe" : "Claude Code was not found: no executable `claude` in an absolute PATH directory. Install Claude Code, or set REVIEW_AGENT_CLAUDE_BIN to its absolute path");
52
+ };
53
+ var pathEntries = (env, platform) => {
54
+ const key = platform === "win32" ? Object.keys(env).find((k) => k.toUpperCase() === "PATH") : "PATH";
55
+ const value = key === void 0 ? void 0 : env[key];
56
+ return (value ?? "").split(platform === "win32" ? ";" : ":");
57
+ };
58
+ var executableFileTest = (platform) => (p) => {
59
+ try {
60
+ if (!statSync(p).isFile()) return false;
61
+ if (platform !== "win32") accessSync(p, constants.X_OK);
62
+ return true;
63
+ } catch {
64
+ return false;
65
+ }
66
+ };
67
+ var realpathOrSelf = (p) => {
68
+ try {
69
+ return realpathSync(p);
70
+ } catch {
71
+ return p;
72
+ }
73
+ };
21
74
  var CHILD_ENV_ALLOWLIST = [
22
75
  "PATH",
23
76
  "HOME",
@@ -76,7 +129,14 @@ var spawnClaude = (a) => new Promise((resolve3, reject) => {
76
129
  reject(new Error(refusal));
77
130
  return;
78
131
  }
79
- const child = spawn(claudeBinary(), a.argv, {
132
+ let bin;
133
+ try {
134
+ bin = resolveClaudeBinary({ env: process.env, avoidDir: a.cwd });
135
+ } catch (e) {
136
+ reject(e instanceof Error ? e : new Error(String(e)));
137
+ return;
138
+ }
139
+ const child = spawn(bin, a.argv, {
80
140
  cwd: a.cwd,
81
141
  env: childEnv(a.extraEnv),
82
142
  signal: a.signal,
@@ -857,7 +917,7 @@ var runRecheckPass = async (a) => {
857
917
 
858
918
  // src/record.ts
859
919
  var RECORD_VERSION = 1;
860
- var ENGINE_VERSION = "0.1.1";
920
+ var ENGINE_VERSION = "0.1.2";
861
921
  var buildReviewRecord = (a) => {
862
922
  const { request, settings, result, startedAt, finishedAt } = a;
863
923
  return {
@@ -912,10 +972,10 @@ import {
912
972
  existsSync,
913
973
  mkdirSync,
914
974
  readdirSync,
915
- realpathSync,
975
+ realpathSync as realpathSync2,
916
976
  renameSync,
917
977
  rmSync,
918
- statSync
978
+ statSync as statSync2
919
979
  } from "fs";
920
980
  import { isAbsolute, join, relative as relative2, resolve as resolve2 } from "path";
921
981
  import { createHash as createHash2, randomUUID } from "crypto";
@@ -933,8 +993,8 @@ var SkillError = class extends Error {
933
993
  var materialiseDir = (source, id) => {
934
994
  if (!isAbsolute(source.path)) throw new SkillError(id, "path must be absolute");
935
995
  if (!existsSync(source.path)) throw new SkillError(id, "no such directory");
936
- const real = realpathSync(source.path);
937
- if (!statSync(real).isDirectory()) throw new SkillError(id, "not a directory");
996
+ const real = realpathSync2(source.path);
997
+ if (!statSync2(real).isDirectory()) throw new SkillError(id, "not a directory");
938
998
  return real;
939
999
  };
940
1000
  var GITHUB_REPO = /^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@review-agent/core",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "engines": {