vskill 0.2.98 → 0.2.104
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/eval/__tests__/llm.test.js +16 -4
- package/dist/eval/__tests__/llm.test.js.map +1 -1
- package/dist/eval/llm.js +32 -6
- package/dist/eval/llm.js.map +1 -1
- package/dist/eval-server/api-routes.js +47 -10
- package/dist/eval-server/api-routes.js.map +1 -1
- package/dist/eval-server/benchmark-runner.js +1 -1
- package/dist/eval-server/benchmark-runner.js.map +1 -1
- package/dist/eval-server/error-classifier.d.ts +9 -0
- package/dist/eval-server/error-classifier.js +159 -0
- package/dist/eval-server/error-classifier.js.map +1 -0
- package/dist/eval-server/improve-routes.js +123 -7
- package/dist/eval-server/improve-routes.js.map +1 -1
- package/dist/eval-server/skill-create-routes.js +53 -12
- package/dist/eval-server/skill-create-routes.js.map +1 -1
- package/dist/eval-server/sse-helpers.d.ts +1 -1
- package/dist/eval-server/sse-helpers.js +6 -3
- package/dist/eval-server/sse-helpers.js.map +1 -1
- package/dist/eval-ui/assets/index-B1xlrc5s.css +1 -0
- package/dist/eval-ui/assets/index-Ce48QzJW.js +70 -0
- package/dist/eval-ui/assets/mergeEvalChanges-Dpbbs4d4.js +1 -0
- package/dist/eval-ui/index.html +2 -2
- package/dist/utils/__tests__/resolve-binary.test.d.ts +1 -0
- package/dist/utils/__tests__/resolve-binary.test.js +175 -0
- package/dist/utils/__tests__/resolve-binary.test.js.map +1 -0
- package/dist/utils/claude-cli.d.ts +1 -1
- package/dist/utils/claude-cli.js +14 -7
- package/dist/utils/claude-cli.js.map +1 -1
- package/dist/utils/claude-cli.test.js +14 -10
- package/dist/utils/claude-cli.test.js.map +1 -1
- package/dist/utils/resolve-binary.d.ts +21 -0
- package/dist/utils/resolve-binary.js +251 -0
- package/dist/utils/resolve-binary.js.map +1 -0
- package/package.json +1 -1
- package/dist/eval-ui/assets/index-COID0pSW.css +0 -1
- package/dist/eval-ui/assets/index-D3G2PY-G.js +0 -69
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function l(t){return{...t,expected_output:t.expected_output??"",files:Array.isArray(t.files)?t.files:[],assertions:Array.isArray(t.assertions)?t.assertions:[]}}function m(t,o,r){const a=o.filter((e,n)=>r.get(n)===!0);if(a.length===0)return t;const d=a.filter(e=>e.action==="remove"),f=a.filter(e=>e.action==="modify"),c=a.filter(e=>e.action==="add");let i=[...t.evals],v=t.evals.length>0?Math.max(...t.evals.map(e=>e.id))+1:1;const s=new Set(d.map(e=>e.evalId).filter(e=>e!=null));s.size>0&&(i=i.filter(e=>!s.has(e.id)));for(const e of f){if(e.evalId==null||!e.eval)continue;const n=i.findIndex(u=>u.id===e.evalId);n<0||(i[n]=l({...e.eval,id:e.evalId}))}for(const e of c)e.eval&&i.push(l({...e.eval,id:v++}));return{...t,evals:i}}export{m as mergeEvalChanges};
|
package/dist/eval-ui/index.html
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Skill Studio</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-Ce48QzJW.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-B1xlrc5s.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
const mockExecSync = vi.hoisted(() => vi.fn());
|
|
3
|
+
const mockExistsSync = vi.hoisted(() => vi.fn());
|
|
4
|
+
const mockReaddirSync = vi.hoisted(() => vi.fn());
|
|
5
|
+
const mockReadFileSync = vi.hoisted(() => vi.fn());
|
|
6
|
+
const mockHomedir = vi.hoisted(() => vi.fn());
|
|
7
|
+
vi.mock("node:child_process", () => ({
|
|
8
|
+
execSync: mockExecSync,
|
|
9
|
+
}));
|
|
10
|
+
vi.mock("node:fs", () => ({
|
|
11
|
+
existsSync: mockExistsSync,
|
|
12
|
+
readdirSync: mockReaddirSync,
|
|
13
|
+
readFileSync: mockReadFileSync,
|
|
14
|
+
}));
|
|
15
|
+
vi.mock("node:os", () => ({
|
|
16
|
+
homedir: mockHomedir,
|
|
17
|
+
}));
|
|
18
|
+
const { resolveCliBinary, enhancedPath, clearResolveCache } = await import("../resolve-binary.js");
|
|
19
|
+
describe("resolveCliBinary", () => {
|
|
20
|
+
const originalPlatform = process.platform;
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
vi.resetAllMocks();
|
|
23
|
+
clearResolveCache();
|
|
24
|
+
mockHomedir.mockReturnValue("/home/testuser");
|
|
25
|
+
mockExistsSync.mockReturnValue(false);
|
|
26
|
+
});
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
Object.defineProperty(process, "platform", { value: originalPlatform });
|
|
29
|
+
});
|
|
30
|
+
it("resolves via which on current PATH (strategy 1)", () => {
|
|
31
|
+
mockExecSync.mockReturnValueOnce(Buffer.from("/usr/local/bin/claude\n"));
|
|
32
|
+
const result = resolveCliBinary("claude");
|
|
33
|
+
expect(result).toBe("/usr/local/bin/claude");
|
|
34
|
+
expect(mockExecSync).toHaveBeenCalledWith("which claude", expect.objectContaining({ timeout: 3_000 }));
|
|
35
|
+
});
|
|
36
|
+
it("caches resolved paths", () => {
|
|
37
|
+
mockExecSync.mockReturnValueOnce(Buffer.from("/usr/local/bin/claude\n"));
|
|
38
|
+
const first = resolveCliBinary("claude");
|
|
39
|
+
const second = resolveCliBinary("claude");
|
|
40
|
+
expect(first).toBe(second);
|
|
41
|
+
// Only called once due to cache
|
|
42
|
+
expect(mockExecSync).toHaveBeenCalledTimes(1);
|
|
43
|
+
});
|
|
44
|
+
it("falls back to login shell which when current PATH fails (strategy 2)", () => {
|
|
45
|
+
// Strategy 1 fails
|
|
46
|
+
mockExecSync.mockImplementationOnce(() => {
|
|
47
|
+
throw new Error("not found");
|
|
48
|
+
});
|
|
49
|
+
// Strategy 2 succeeds
|
|
50
|
+
mockExecSync.mockReturnValueOnce(Buffer.from("/opt/homebrew/bin/claude\n"));
|
|
51
|
+
mockExistsSync.mockImplementation((p) => p === "/opt/homebrew/bin/claude");
|
|
52
|
+
const result = resolveCliBinary("claude");
|
|
53
|
+
expect(result).toBe("/opt/homebrew/bin/claude");
|
|
54
|
+
});
|
|
55
|
+
it("falls back to npm global bin (strategy 3)", () => {
|
|
56
|
+
// Strategy 1 fails
|
|
57
|
+
mockExecSync.mockImplementationOnce(() => {
|
|
58
|
+
throw new Error("not found");
|
|
59
|
+
});
|
|
60
|
+
// Strategy 2 fails
|
|
61
|
+
mockExecSync.mockImplementationOnce(() => {
|
|
62
|
+
throw new Error("not found");
|
|
63
|
+
});
|
|
64
|
+
// Strategy 3: npm config get prefix
|
|
65
|
+
mockExecSync.mockReturnValueOnce(Buffer.from("/usr/local\n"));
|
|
66
|
+
mockExistsSync.mockImplementation((p) => p === "/usr/local/bin/claude");
|
|
67
|
+
const result = resolveCliBinary("claude");
|
|
68
|
+
expect(result).toBe("/usr/local/bin/claude");
|
|
69
|
+
});
|
|
70
|
+
it("falls back to common paths (strategy 4)", () => {
|
|
71
|
+
// All execSync calls fail
|
|
72
|
+
mockExecSync.mockImplementation(() => {
|
|
73
|
+
throw new Error("not found");
|
|
74
|
+
});
|
|
75
|
+
// /home/testuser/.local/bin/claude exists
|
|
76
|
+
mockExistsSync.mockImplementation((p) => p === "/home/testuser/.local/bin/claude");
|
|
77
|
+
const result = resolveCliBinary("claude");
|
|
78
|
+
expect(result).toBe("/home/testuser/.local/bin/claude");
|
|
79
|
+
});
|
|
80
|
+
it("returns bare name when all strategies fail (strategy 5)", () => {
|
|
81
|
+
mockExecSync.mockImplementation(() => {
|
|
82
|
+
throw new Error("not found");
|
|
83
|
+
});
|
|
84
|
+
mockExistsSync.mockReturnValue(false);
|
|
85
|
+
const result = resolveCliBinary("claude");
|
|
86
|
+
expect(result).toBe("claude");
|
|
87
|
+
});
|
|
88
|
+
it("uses where on Windows", () => {
|
|
89
|
+
Object.defineProperty(process, "platform", { value: "win32" });
|
|
90
|
+
clearResolveCache();
|
|
91
|
+
mockExecSync.mockReturnValueOnce(Buffer.from("C:\\Users\\test\\AppData\\Roaming\\npm\\claude.cmd\n"));
|
|
92
|
+
const result = resolveCliBinary("claude");
|
|
93
|
+
expect(result).toBe("C:\\Users\\test\\AppData\\Roaming\\npm\\claude.cmd");
|
|
94
|
+
expect(mockExecSync).toHaveBeenCalledWith("where claude", expect.anything());
|
|
95
|
+
});
|
|
96
|
+
it("handles where returning multiple paths (Windows)", () => {
|
|
97
|
+
Object.defineProperty(process, "platform", { value: "win32" });
|
|
98
|
+
clearResolveCache();
|
|
99
|
+
mockExecSync.mockReturnValueOnce(Buffer.from("C:\\first\\claude.cmd\nC:\\second\\claude.cmd\n"));
|
|
100
|
+
const result = resolveCliBinary("claude");
|
|
101
|
+
expect(result).toBe("C:\\first\\claude.cmd");
|
|
102
|
+
});
|
|
103
|
+
it("skips login shell on Windows", () => {
|
|
104
|
+
Object.defineProperty(process, "platform", { value: "win32" });
|
|
105
|
+
clearResolveCache();
|
|
106
|
+
// which fails
|
|
107
|
+
mockExecSync.mockImplementationOnce(() => {
|
|
108
|
+
throw new Error("not found");
|
|
109
|
+
});
|
|
110
|
+
// npm config get prefix
|
|
111
|
+
mockExecSync.mockReturnValueOnce(Buffer.from("C:\\Users\\test\\AppData\\Roaming\\npm\n"));
|
|
112
|
+
mockExistsSync.mockImplementation((p) => p === "C:\\Users\\test\\AppData\\Roaming\\npm\\claude.cmd");
|
|
113
|
+
const result = resolveCliBinary("claude");
|
|
114
|
+
// Should NOT have tried login shell (no `-lc` call)
|
|
115
|
+
const calls = mockExecSync.mock.calls.map((c) => c[0]);
|
|
116
|
+
expect(calls).not.toContainEqual(expect.stringContaining("-lc"));
|
|
117
|
+
});
|
|
118
|
+
it("resolves different binaries independently", () => {
|
|
119
|
+
mockExecSync
|
|
120
|
+
.mockReturnValueOnce(Buffer.from("/usr/local/bin/claude\n"))
|
|
121
|
+
.mockReturnValueOnce(Buffer.from("/usr/local/bin/codex\n"));
|
|
122
|
+
const claude = resolveCliBinary("claude");
|
|
123
|
+
const codex = resolveCliBinary("codex");
|
|
124
|
+
expect(claude).toBe("/usr/local/bin/claude");
|
|
125
|
+
expect(codex).toBe("/usr/local/bin/codex");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe("enhancedPath", () => {
|
|
129
|
+
beforeEach(() => {
|
|
130
|
+
vi.resetAllMocks();
|
|
131
|
+
mockHomedir.mockReturnValue("/home/testuser");
|
|
132
|
+
mockExistsSync.mockReturnValue(false);
|
|
133
|
+
});
|
|
134
|
+
it("returns original PATH when no extra dirs exist", () => {
|
|
135
|
+
mockExecSync.mockImplementation(() => {
|
|
136
|
+
throw new Error("no npm");
|
|
137
|
+
});
|
|
138
|
+
mockExistsSync.mockReturnValue(false);
|
|
139
|
+
const result = enhancedPath("/usr/bin:/bin");
|
|
140
|
+
expect(result).toBe("/usr/bin:/bin");
|
|
141
|
+
});
|
|
142
|
+
it("appends existing extra directories", () => {
|
|
143
|
+
mockExecSync.mockImplementation(() => {
|
|
144
|
+
throw new Error("no npm");
|
|
145
|
+
});
|
|
146
|
+
mockExistsSync.mockImplementation((p) => p === "/opt/homebrew/bin" || p === "/usr/local/bin");
|
|
147
|
+
const result = enhancedPath("/usr/bin");
|
|
148
|
+
expect(result).toContain("/opt/homebrew/bin");
|
|
149
|
+
expect(result).toContain("/usr/local/bin");
|
|
150
|
+
expect(result.startsWith("/usr/bin:")).toBe(true);
|
|
151
|
+
});
|
|
152
|
+
it("does not duplicate paths already in PATH", () => {
|
|
153
|
+
mockExecSync.mockImplementation(() => {
|
|
154
|
+
throw new Error("no npm");
|
|
155
|
+
});
|
|
156
|
+
mockExistsSync.mockImplementation((p) => p === "/usr/local/bin");
|
|
157
|
+
const result = enhancedPath("/usr/bin:/usr/local/bin");
|
|
158
|
+
// /usr/local/bin should appear only once
|
|
159
|
+
const parts = result.split(":");
|
|
160
|
+
const count = parts.filter((p) => p === "/usr/local/bin").length;
|
|
161
|
+
expect(count).toBe(1);
|
|
162
|
+
});
|
|
163
|
+
it("uses process.env.PATH when no argument provided", () => {
|
|
164
|
+
const origPath = process.env.PATH;
|
|
165
|
+
process.env.PATH = "/test/path";
|
|
166
|
+
mockExecSync.mockImplementation(() => {
|
|
167
|
+
throw new Error("no npm");
|
|
168
|
+
});
|
|
169
|
+
mockExistsSync.mockReturnValue(false);
|
|
170
|
+
const result = enhancedPath();
|
|
171
|
+
expect(result).toBe("/test/path");
|
|
172
|
+
process.env.PATH = origPath;
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
//# sourceMappingURL=resolve-binary.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-binary.test.js","sourceRoot":"","sources":["../../../src/utils/__tests__/resolve-binary.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEzE,MAAM,YAAY,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AAC/C,MAAM,cAAc,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AACjD,MAAM,eAAe,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AAClD,MAAM,gBAAgB,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AACnD,MAAM,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AAE9C,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;IACnC,QAAQ,EAAE,YAAY;CACvB,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IACxB,UAAU,EAAE,cAAc;IAC1B,WAAW,EAAE,eAAe;IAC5B,YAAY,EAAE,gBAAgB;CAC/B,CAAC,CAAC,CAAC;AAEJ,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;IACxB,OAAO,EAAE,WAAW;CACrB,CAAC,CAAC,CAAC;AAEJ,MAAM,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CACxE,sBAAsB,CACvB,CAAC;AAEF,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAE1C,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;QACnB,iBAAiB,EAAE,CAAC;QACpB,WAAW,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC;QAC9C,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAC7C,MAAM,CAAC,YAAY,CAAC,CAAC,oBAAoB,CACvC,cAAc,EACd,MAAM,CAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAC5C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;QAEzE,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,gCAAgC;QAChC,MAAM,CAAC,YAAY,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,mBAAmB;QACnB,YAAY,CAAC,sBAAsB,CAAC,GAAG,EAAE;YACvC,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,sBAAsB;QACtB,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC,CAAC;QAC5E,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,0BAA0B,CAAC,CAAC;QAEnF,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,mBAAmB;QACnB,YAAY,CAAC,sBAAsB,CAAC,GAAG,EAAE;YACvC,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,mBAAmB;QACnB,YAAY,CAAC,sBAAsB,CAAC,GAAG,EAAE;YACvC,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,oCAAoC;QACpC,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;QAC9D,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,uBAAuB,CAAC,CAAC;QAEhF,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,0BAA0B;QAC1B,YAAY,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,0CAA0C;QAC1C,cAAc,CAAC,kBAAkB,CAC/B,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,kCAAkC,CACxD,CAAC;QAEF,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,YAAY,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;QAC/B,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/D,iBAAiB,EAAE,CAAC;QACpB,YAAY,CAAC,mBAAmB,CAC9B,MAAM,CAAC,IAAI,CAAC,sDAAsD,CAAC,CACpE,CAAC;QAEF,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;QAC1E,MAAM,CAAC,YAAY,CAAC,CAAC,oBAAoB,CACvC,cAAc,EACd,MAAM,CAAC,QAAQ,EAAE,CAClB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/D,iBAAiB,EAAE,CAAC;QACpB,YAAY,CAAC,mBAAmB,CAC9B,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAC/D,CAAC;QAEF,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/D,iBAAiB,EAAE,CAAC;QACpB,cAAc;QACd,YAAY,CAAC,sBAAsB,CAAC,GAAG,EAAE;YACvC,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,wBAAwB;QACxB,YAAY,CAAC,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC,CAAC;QAC1F,cAAc,CAAC,kBAAkB,CAC/B,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,oDAAoD,CAC1E,CAAC;QAEF,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAE1C,oDAAoD;QACpD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,YAAY;aACT,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;aAC3D,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;QAE9D,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAExC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,aAAa,EAAE,CAAC;QACnB,WAAW,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC;QAC9C,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,YAAY,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;QAE7C,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,YAAY,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,kBAAkB,CAC/B,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,mBAAmB,IAAI,CAAC,KAAK,gBAAgB,CACnE,CAAC;QAEF,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;QAExC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,YAAY,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,kBAAkB,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,KAAK,gBAAgB,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,YAAY,CAAC,yBAAyB,CAAC,CAAC;QAEvD,yCAAyC;QACzC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,gBAAgB,CAAC,CAAC,MAAM,CAAC;QACjE,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;QAChC,YAAY,CAAC,kBAAkB,CAAC,GAAG,EAAE;YACnC,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;QACH,cAAc,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAE9B,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/dist/utils/claude-cli.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { execSync } from "node:child_process";
|
|
2
|
+
import { resolveCliBinary } from "./resolve-binary.js";
|
|
2
3
|
/**
|
|
3
|
-
* Check if `claude` CLI binary is available
|
|
4
|
+
* Check if `claude` CLI binary is available (searches beyond current PATH).
|
|
4
5
|
*/
|
|
5
6
|
export function isClaudeCliAvailable() {
|
|
6
7
|
try {
|
|
7
|
-
|
|
8
|
+
const binary = resolveCliBinary("claude");
|
|
9
|
+
execSync(`"${binary}" --version`, { stdio: "ignore", timeout: 5_000 });
|
|
8
10
|
return true;
|
|
9
11
|
}
|
|
10
12
|
catch {
|
|
@@ -22,8 +24,9 @@ export function isClaudeCliAvailable() {
|
|
|
22
24
|
* @returns RegisterResult with success flag and optional stderr on failure
|
|
23
25
|
*/
|
|
24
26
|
export function registerMarketplace(source) {
|
|
27
|
+
const binary = resolveCliBinary("claude");
|
|
25
28
|
try {
|
|
26
|
-
execSync(`
|
|
29
|
+
execSync(`"${binary}" plugin marketplace add "${source}"`, {
|
|
27
30
|
stdio: ["pipe", "pipe", "pipe"],
|
|
28
31
|
timeout: 15_000,
|
|
29
32
|
});
|
|
@@ -39,8 +42,9 @@ export function registerMarketplace(source) {
|
|
|
39
42
|
* Used to clean up stale registrations before retrying.
|
|
40
43
|
*/
|
|
41
44
|
export function deregisterMarketplace(source) {
|
|
45
|
+
const binary = resolveCliBinary("claude");
|
|
42
46
|
try {
|
|
43
|
-
execSync(`
|
|
47
|
+
execSync(`"${binary}" plugin marketplace remove "${source}"`, {
|
|
44
48
|
stdio: "ignore",
|
|
45
49
|
timeout: 10_000,
|
|
46
50
|
});
|
|
@@ -55,8 +59,9 @@ export function deregisterMarketplace(source) {
|
|
|
55
59
|
* Returns marketplace source paths/URLs, or empty array on failure.
|
|
56
60
|
*/
|
|
57
61
|
export function listMarketplaces() {
|
|
62
|
+
const binary = resolveCliBinary("claude");
|
|
58
63
|
try {
|
|
59
|
-
const output = execSync("
|
|
64
|
+
const output = execSync(`"${binary}" plugin marketplace list`, {
|
|
60
65
|
stdio: ["pipe", "pipe", "pipe"],
|
|
61
66
|
timeout: 10_000,
|
|
62
67
|
}).toString().trim();
|
|
@@ -77,10 +82,11 @@ export function listMarketplaces() {
|
|
|
77
82
|
* @returns true on success, false on failure
|
|
78
83
|
*/
|
|
79
84
|
export function installNativePlugin(pluginName, marketplaceName, scope = "project") {
|
|
85
|
+
const binary = resolveCliBinary("claude");
|
|
80
86
|
const pluginKey = `${pluginName}@${marketplaceName}`;
|
|
81
87
|
const scopeFlag = scope === "user" ? "" : ` --scope ${scope}`;
|
|
82
88
|
try {
|
|
83
|
-
execSync(`
|
|
89
|
+
execSync(`"${binary}" plugin install "${pluginKey}"${scopeFlag}`, {
|
|
84
90
|
stdio: "ignore",
|
|
85
91
|
timeout: 30_000,
|
|
86
92
|
});
|
|
@@ -94,9 +100,10 @@ export function installNativePlugin(pluginName, marketplaceName, scope = "projec
|
|
|
94
100
|
* Uninstall a plugin from Claude Code's native system.
|
|
95
101
|
*/
|
|
96
102
|
export function uninstallNativePlugin(pluginName, marketplaceName) {
|
|
103
|
+
const binary = resolveCliBinary("claude");
|
|
97
104
|
const pluginKey = `${pluginName}@${marketplaceName}`;
|
|
98
105
|
try {
|
|
99
|
-
execSync(`
|
|
106
|
+
execSync(`"${binary}" plugin uninstall "${pluginKey}"`, {
|
|
100
107
|
stdio: "ignore",
|
|
101
108
|
timeout: 10_000,
|
|
102
109
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-cli.js","sourceRoot":"","sources":["../../src/utils/claude-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-cli.js","sourceRoot":"","sources":["../../src/utils/claude-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,10 @@ const mockExecSync = vi.fn();
|
|
|
3
3
|
vi.mock("node:child_process", () => ({
|
|
4
4
|
execSync: (...args) => mockExecSync(...args),
|
|
5
5
|
}));
|
|
6
|
+
// Mock resolveCliBinary to always return "claude" (bare name) for tests
|
|
7
|
+
vi.mock("./resolve-binary.js", () => ({
|
|
8
|
+
resolveCliBinary: () => "claude",
|
|
9
|
+
}));
|
|
6
10
|
const { isClaudeCliAvailable, registerMarketplace, deregisterMarketplace, listMarketplaces, installNativePlugin, uninstallNativePlugin, } = await import("./claude-cli.js");
|
|
7
11
|
beforeEach(() => {
|
|
8
12
|
vi.clearAllMocks();
|
|
@@ -14,7 +18,7 @@ describe("isClaudeCliAvailable", () => {
|
|
|
14
18
|
it("returns true when claude binary exists", () => {
|
|
15
19
|
mockExecSync.mockReturnValue(Buffer.from("1.0.0"));
|
|
16
20
|
expect(isClaudeCliAvailable()).toBe(true);
|
|
17
|
-
expect(mockExecSync).toHaveBeenCalledWith("claude --version
|
|
21
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" --version', {
|
|
18
22
|
stdio: "ignore",
|
|
19
23
|
timeout: 5_000,
|
|
20
24
|
});
|
|
@@ -34,7 +38,7 @@ describe("registerMarketplace", () => {
|
|
|
34
38
|
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
35
39
|
const result = registerMarketplace("/path/to/repo");
|
|
36
40
|
expect(result).toEqual({ success: true });
|
|
37
|
-
expect(mockExecSync).toHaveBeenCalledWith('claude plugin marketplace add "/path/to/repo"', { stdio: ["pipe", "pipe", "pipe"], timeout: 15_000 });
|
|
41
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" plugin marketplace add "/path/to/repo"', { stdio: ["pipe", "pipe", "pipe"], timeout: 15_000 });
|
|
38
42
|
});
|
|
39
43
|
it("returns failure result with stderr on error", () => {
|
|
40
44
|
const err = new Error("failed");
|
|
@@ -53,19 +57,19 @@ describe("registerMarketplace", () => {
|
|
|
53
57
|
it("quotes paths with spaces", () => {
|
|
54
58
|
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
55
59
|
registerMarketplace("/path/with spaces/repo");
|
|
56
|
-
expect(mockExecSync).toHaveBeenCalledWith('claude plugin marketplace add "/path/with spaces/repo"', expect.any(Object));
|
|
60
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" plugin marketplace add "/path/with spaces/repo"', expect.any(Object));
|
|
57
61
|
});
|
|
58
62
|
it("accepts GitHub HTTPS URL as source", () => {
|
|
59
63
|
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
60
64
|
const result = registerMarketplace("https://github.com/owner/repo");
|
|
61
65
|
expect(result).toEqual({ success: true });
|
|
62
|
-
expect(mockExecSync).toHaveBeenCalledWith('claude plugin marketplace add "https://github.com/owner/repo"', { stdio: ["pipe", "pipe", "pipe"], timeout: 15_000 });
|
|
66
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" plugin marketplace add "https://github.com/owner/repo"', { stdio: ["pipe", "pipe", "pipe"], timeout: 15_000 });
|
|
63
67
|
});
|
|
64
68
|
it("accepts GitHub owner/repo shorthand as source", () => {
|
|
65
69
|
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
66
70
|
const result = registerMarketplace("owner/repo");
|
|
67
71
|
expect(result).toEqual({ success: true });
|
|
68
|
-
expect(mockExecSync).toHaveBeenCalledWith('claude plugin marketplace add "owner/repo"', { stdio: ["pipe", "pipe", "pipe"], timeout: 15_000 });
|
|
72
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" plugin marketplace add "owner/repo"', { stdio: ["pipe", "pipe", "pipe"], timeout: 15_000 });
|
|
69
73
|
});
|
|
70
74
|
});
|
|
71
75
|
// ---------------------------------------------------------------------------
|
|
@@ -75,7 +79,7 @@ describe("deregisterMarketplace", () => {
|
|
|
75
79
|
it("calls claude plugin marketplace remove", () => {
|
|
76
80
|
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
77
81
|
expect(deregisterMarketplace("https://github.com/owner/repo")).toBe(true);
|
|
78
|
-
expect(mockExecSync).toHaveBeenCalledWith('claude plugin marketplace remove "https://github.com/owner/repo"', { stdio: "ignore", timeout: 10_000 });
|
|
82
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" plugin marketplace remove "https://github.com/owner/repo"', { stdio: "ignore", timeout: 10_000 });
|
|
79
83
|
});
|
|
80
84
|
it("returns false on failure", () => {
|
|
81
85
|
mockExecSync.mockImplementation(() => { throw new Error("fail"); });
|
|
@@ -106,17 +110,17 @@ describe("installNativePlugin", () => {
|
|
|
106
110
|
it("defaults to project scope", () => {
|
|
107
111
|
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
108
112
|
expect(installNativePlugin("frontend", "vskill")).toBe(true);
|
|
109
|
-
expect(mockExecSync).toHaveBeenCalledWith('claude plugin install "frontend@vskill" --scope project', { stdio: "ignore", timeout: 30_000 });
|
|
113
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" plugin install "frontend@vskill" --scope project', { stdio: "ignore", timeout: 30_000 });
|
|
110
114
|
});
|
|
111
115
|
it("passes --scope project explicitly", () => {
|
|
112
116
|
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
113
117
|
expect(installNativePlugin("frontend", "vskill", "project")).toBe(true);
|
|
114
|
-
expect(mockExecSync).toHaveBeenCalledWith('claude plugin install "frontend@vskill" --scope project', { stdio: "ignore", timeout: 30_000 });
|
|
118
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" plugin install "frontend@vskill" --scope project', { stdio: "ignore", timeout: 30_000 });
|
|
115
119
|
});
|
|
116
120
|
it("omits scope flag for user scope", () => {
|
|
117
121
|
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
118
122
|
expect(installNativePlugin("sw", "specweave", "user")).toBe(true);
|
|
119
|
-
expect(mockExecSync).toHaveBeenCalledWith('claude plugin install "sw@specweave"', { stdio: "ignore", timeout: 30_000 });
|
|
123
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" plugin install "sw@specweave"', { stdio: "ignore", timeout: 30_000 });
|
|
120
124
|
});
|
|
121
125
|
it("returns false when command fails", () => {
|
|
122
126
|
mockExecSync.mockImplementation(() => {
|
|
@@ -132,7 +136,7 @@ describe("uninstallNativePlugin", () => {
|
|
|
132
136
|
it("calls claude plugin uninstall with plugin@marketplace format", () => {
|
|
133
137
|
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
134
138
|
expect(uninstallNativePlugin("frontend", "vskill")).toBe(true);
|
|
135
|
-
expect(mockExecSync).toHaveBeenCalledWith('claude plugin uninstall "frontend@vskill"', { stdio: "ignore", timeout: 10_000 });
|
|
139
|
+
expect(mockExecSync).toHaveBeenCalledWith('"claude" plugin uninstall "frontend@vskill"', { stdio: "ignore", timeout: 10_000 });
|
|
136
140
|
});
|
|
137
141
|
it("returns false when command fails", () => {
|
|
138
142
|
mockExecSync.mockImplementation(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-cli.test.js","sourceRoot":"","sources":["../../src/utils/claude-cli.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAE9D,MAAM,YAAY,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AAC7B,EAAE,CAAC,IAAI,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,GAAG,IAAe,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC;CACxD,CAAC,CAAC,CAAC;AAEJ,MAAM,EACJ,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,GACtB,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAEpC,UAAU,CAAC,GAAG,EAAE;IACd,EAAE,CAAC,aAAa,EAAE,CAAC;AACrB,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAC9E,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,YAAY,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,CAAC,YAAY,CAAC,CAAC,oBAAoB,CAAC,
|
|
1
|
+
{"version":3,"file":"claude-cli.test.js","sourceRoot":"","sources":["../../src/utils/claude-cli.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a CLI binary name to its full absolute path.
|
|
3
|
+
*
|
|
4
|
+
* Tries multiple strategies in order:
|
|
5
|
+
* 1. Current PATH via `which` / `where`
|
|
6
|
+
* 2. Login shell PATH (picks up .zshrc/.bashrc additions)
|
|
7
|
+
* 3. npm global bin directory
|
|
8
|
+
* 4. Common installation directories per OS
|
|
9
|
+
* 5. Falls back to bare name (lets spawn produce a clear ENOENT error)
|
|
10
|
+
*
|
|
11
|
+
* Results are cached per binary name for the lifetime of the process.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveCliBinary(name: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Build an enhanced PATH string that includes common binary directories.
|
|
16
|
+
* Use this when spawning child processes to ensure they can find binaries
|
|
17
|
+
* even if the parent process has a limited PATH.
|
|
18
|
+
*/
|
|
19
|
+
export declare function enhancedPath(currentPath?: string): string;
|
|
20
|
+
/** Clear the resolution cache (useful for testing) */
|
|
21
|
+
export declare function clearResolveCache(): void;
|