@react-grab/claude-code 0.0.77 → 0.0.80
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/cli.cjs +498 -4
- package/dist/cli.js +498 -4
- package/dist/client.cjs +36 -14
- package/dist/client.d.cts +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.global.js +4 -4
- package/dist/client.js +36 -14
- package/dist/server.cjs +99 -32
- package/dist/server.js +99 -31
- package/package.json +6 -2
package/dist/client.js
CHANGED
|
@@ -67,19 +67,33 @@ async function* streamSSE(stream, signal) {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
async function* streamFromServer(serverUrl, context, signal) {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
const sessionId = context.sessionId;
|
|
71
|
+
const handleAbort = () => {
|
|
72
|
+
if (sessionId) {
|
|
73
|
+
fetch(`${serverUrl}/abort/${sessionId}`, { method: "POST" }).catch(
|
|
74
|
+
() => {
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
signal.addEventListener("abort", handleAbort);
|
|
80
|
+
try {
|
|
81
|
+
const response = await fetch(`${serverUrl}/agent`, {
|
|
82
|
+
method: "POST",
|
|
83
|
+
headers: { "Content-Type": "application/json" },
|
|
84
|
+
body: JSON.stringify(context),
|
|
85
|
+
signal
|
|
86
|
+
});
|
|
87
|
+
if (!response.ok) {
|
|
88
|
+
throw new Error(`Server error: ${response.status}`);
|
|
89
|
+
}
|
|
90
|
+
if (!response.body) {
|
|
91
|
+
throw new Error("No response body");
|
|
92
|
+
}
|
|
93
|
+
yield* streamSSE(response.body, signal);
|
|
94
|
+
} finally {
|
|
95
|
+
signal.removeEventListener("abort", handleAbort);
|
|
81
96
|
}
|
|
82
|
-
yield* streamSSE(response.body, signal);
|
|
83
97
|
}
|
|
84
98
|
var createClaudeAgentProvider = (providerOptions = {}) => {
|
|
85
99
|
const { serverUrl = DEFAULT_SERVER_URL, getOptions } = providerOptions;
|
|
@@ -116,6 +130,7 @@ var createClaudeAgentProvider = (providerOptions = {}) => {
|
|
|
116
130
|
yield* streamFromServer(serverUrl, mergedContext, signal);
|
|
117
131
|
},
|
|
118
132
|
supportsResume: true,
|
|
133
|
+
supportsFollowUp: true,
|
|
119
134
|
checkConnection: async () => {
|
|
120
135
|
const now = Date.now();
|
|
121
136
|
if (connectionCache && now - connectionCache.timestamp < CONNECTION_CHECK_TTL_MS) {
|
|
@@ -142,19 +157,26 @@ var createClaudeAgentProvider = (providerOptions = {}) => {
|
|
|
142
157
|
var attachAgent = async () => {
|
|
143
158
|
if (typeof window === "undefined") return;
|
|
144
159
|
const provider = createClaudeAgentProvider();
|
|
160
|
+
const attach = (api2) => {
|
|
161
|
+
api2.setAgent({ provider, storage: sessionStorage });
|
|
162
|
+
};
|
|
145
163
|
const api = window.__REACT_GRAB__;
|
|
146
164
|
if (api) {
|
|
147
|
-
api
|
|
165
|
+
attach(api);
|
|
148
166
|
return;
|
|
149
167
|
}
|
|
150
168
|
window.addEventListener(
|
|
151
169
|
"react-grab:init",
|
|
152
170
|
(event) => {
|
|
153
171
|
const customEvent = event;
|
|
154
|
-
customEvent.detail
|
|
172
|
+
attach(customEvent.detail);
|
|
155
173
|
},
|
|
156
174
|
{ once: true }
|
|
157
175
|
);
|
|
176
|
+
const apiAfterListener = window.__REACT_GRAB__;
|
|
177
|
+
if (apiAfterListener) {
|
|
178
|
+
attach(apiAfterListener);
|
|
179
|
+
}
|
|
158
180
|
};
|
|
159
181
|
attachAgent();
|
|
160
182
|
|
package/dist/server.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var child_process = require('child_process');
|
|
4
4
|
var url = require('url');
|
|
5
5
|
var http = require('http');
|
|
6
6
|
var http2 = require('http2');
|
|
@@ -8,7 +8,6 @@ var stream = require('stream');
|
|
|
8
8
|
var crypto = require('crypto');
|
|
9
9
|
var path = require('path');
|
|
10
10
|
var events = require('events');
|
|
11
|
-
var child_process = require('child_process');
|
|
12
11
|
var readline = require('readline');
|
|
13
12
|
var fs = require('fs');
|
|
14
13
|
var promises = require('fs/promises');
|
|
@@ -36,7 +35,6 @@ function _interopNamespace(e) {
|
|
|
36
35
|
return Object.freeze(n);
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
var net__default = /*#__PURE__*/_interopDefault(net);
|
|
40
38
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
41
39
|
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
42
40
|
|
|
@@ -8762,8 +8760,7 @@ var ProcessTransport = class {
|
|
|
8762
8760
|
env.CLAUDE_CODE_ENTRYPOINT = "sdk-ts";
|
|
8763
8761
|
}
|
|
8764
8762
|
const fs2 = getFsImplementation();
|
|
8765
|
-
|
|
8766
|
-
if (!isPathCommand && !fs2.existsSync(pathToClaudeCodeExecutable)) {
|
|
8763
|
+
if (!fs2.existsSync(pathToClaudeCodeExecutable)) {
|
|
8767
8764
|
const errorMessage = isNativeBinary(pathToClaudeCodeExecutable) ? `Claude Code native binary not found at ${pathToClaudeCodeExecutable}. Please ensure Claude Code is installed via native installer or specify a valid path with options.pathToClaudeCodeExecutable.` : `Claude Code executable not found at ${pathToClaudeCodeExecutable}. Is options.pathToClaudeCodeExecutable set?`;
|
|
8768
8765
|
throw new ReferenceError(errorMessage);
|
|
8769
8766
|
}
|
|
@@ -14577,7 +14574,12 @@ function query({
|
|
|
14577
14574
|
} else if (systemPrompt.type === "preset") {
|
|
14578
14575
|
appendSystemPrompt = systemPrompt.append;
|
|
14579
14576
|
}
|
|
14580
|
-
let pathToClaudeCodeExecutable = rest.pathToClaudeCodeExecutable
|
|
14577
|
+
let pathToClaudeCodeExecutable = rest.pathToClaudeCodeExecutable;
|
|
14578
|
+
if (!pathToClaudeCodeExecutable) {
|
|
14579
|
+
const filename = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('server.cjs', document.baseURI).href)));
|
|
14580
|
+
const dirname2 = path.join(filename, "..");
|
|
14581
|
+
pathToClaudeCodeExecutable = path.join(dirname2, "cli.js");
|
|
14582
|
+
}
|
|
14581
14583
|
process.env.CLAUDE_AGENT_SDK_VERSION = "0.1.46";
|
|
14582
14584
|
const {
|
|
14583
14585
|
abortController = createAbortController(),
|
|
@@ -14696,30 +14698,55 @@ function query({
|
|
|
14696
14698
|
var DEFAULT_PORT = 4567;
|
|
14697
14699
|
|
|
14698
14700
|
// src/server.ts
|
|
14699
|
-
var VERSION = "0.0.
|
|
14701
|
+
var VERSION = "0.0.80";
|
|
14702
|
+
var resolveClaudePath = () => {
|
|
14703
|
+
const command = process.platform === "win32" ? "where claude" : "which claude";
|
|
14704
|
+
try {
|
|
14705
|
+
const result = child_process.execSync(command, { encoding: "utf8" }).trim();
|
|
14706
|
+
return result.split("\n")[0];
|
|
14707
|
+
} catch {
|
|
14708
|
+
return "claude";
|
|
14709
|
+
}
|
|
14710
|
+
};
|
|
14711
|
+
var claudeSessionMap = /* @__PURE__ */ new Map();
|
|
14712
|
+
var abortedSessions = /* @__PURE__ */ new Set();
|
|
14713
|
+
var lastClaudeSessionId;
|
|
14700
14714
|
var isTextBlock = (block) => block.type === "text";
|
|
14701
14715
|
var createServer = () => {
|
|
14702
14716
|
const app = new Hono2();
|
|
14703
|
-
app.use("
|
|
14717
|
+
app.use("*", cors());
|
|
14704
14718
|
app.post("/agent", async (context) => {
|
|
14705
14719
|
const body = await context.req.json();
|
|
14706
|
-
const { content, prompt, options } = body;
|
|
14707
|
-
const
|
|
14720
|
+
const { content, prompt, options, sessionId } = body;
|
|
14721
|
+
const claudeSessionId = sessionId ? claudeSessionMap.get(sessionId) : void 0;
|
|
14722
|
+
const isFollowUp = Boolean(claudeSessionId);
|
|
14723
|
+
const userPrompt = isFollowUp ? prompt : `${prompt}
|
|
14708
14724
|
|
|
14709
14725
|
${content}`;
|
|
14710
14726
|
return streamSSE(context, async (stream2) => {
|
|
14727
|
+
const isAborted2 = () => sessionId && abortedSessions.has(sessionId);
|
|
14711
14728
|
try {
|
|
14712
14729
|
await stream2.writeSSE({ data: "Thinking...", event: "status" });
|
|
14730
|
+
const env = { ...process.env };
|
|
14731
|
+
delete env.NODE_OPTIONS;
|
|
14732
|
+
delete env.VSCODE_INSPECTOR_OPTIONS;
|
|
14713
14733
|
const queryResult = query({
|
|
14714
|
-
prompt:
|
|
14734
|
+
prompt: userPrompt,
|
|
14715
14735
|
options: {
|
|
14716
|
-
pathToClaudeCodeExecutable:
|
|
14736
|
+
pathToClaudeCodeExecutable: resolveClaudePath(),
|
|
14717
14737
|
cwd: process.cwd(),
|
|
14718
14738
|
includePartialMessages: true,
|
|
14719
|
-
|
|
14739
|
+
env,
|
|
14740
|
+
...options,
|
|
14741
|
+
...isFollowUp && claudeSessionId ? { resume: claudeSessionId } : {}
|
|
14720
14742
|
}
|
|
14721
14743
|
});
|
|
14744
|
+
let capturedClaudeSessionId;
|
|
14722
14745
|
for await (const message of queryResult) {
|
|
14746
|
+
if (isAborted2()) break;
|
|
14747
|
+
if (!capturedClaudeSessionId && message.session_id) {
|
|
14748
|
+
capturedClaudeSessionId = message.session_id;
|
|
14749
|
+
}
|
|
14723
14750
|
if (message.type === "assistant") {
|
|
14724
14751
|
const textContent = message.message.content.filter(isTextBlock).map((block) => block.text).join(" ");
|
|
14725
14752
|
if (textContent) {
|
|
@@ -14733,37 +14760,77 @@ ${content}`;
|
|
|
14733
14760
|
});
|
|
14734
14761
|
}
|
|
14735
14762
|
}
|
|
14736
|
-
|
|
14763
|
+
if (!isAborted2() && capturedClaudeSessionId) {
|
|
14764
|
+
lastClaudeSessionId = capturedClaudeSessionId;
|
|
14765
|
+
if (sessionId) {
|
|
14766
|
+
claudeSessionMap.set(sessionId, capturedClaudeSessionId);
|
|
14767
|
+
}
|
|
14768
|
+
}
|
|
14769
|
+
if (!isAborted2()) {
|
|
14770
|
+
await stream2.writeSSE({ data: "", event: "done" });
|
|
14771
|
+
}
|
|
14737
14772
|
} catch (error) {
|
|
14738
|
-
|
|
14739
|
-
|
|
14740
|
-
|
|
14741
|
-
|
|
14742
|
-
|
|
14773
|
+
if (!isAborted2()) {
|
|
14774
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
14775
|
+
const stderr = error instanceof Error && "stderr" in error ? String(error.stderr) : void 0;
|
|
14776
|
+
const fullError = stderr && stderr.trim() ? `${errorMessage}
|
|
14777
|
+
|
|
14778
|
+
stderr:
|
|
14779
|
+
${stderr.trim()}` : errorMessage;
|
|
14780
|
+
await stream2.writeSSE({
|
|
14781
|
+
data: `Error: ${fullError}`,
|
|
14782
|
+
event: "error"
|
|
14783
|
+
});
|
|
14784
|
+
}
|
|
14785
|
+
} finally {
|
|
14786
|
+
if (sessionId) {
|
|
14787
|
+
abortedSessions.delete(sessionId);
|
|
14788
|
+
}
|
|
14743
14789
|
}
|
|
14744
14790
|
});
|
|
14745
14791
|
});
|
|
14792
|
+
app.post("/abort/:sessionId", (context) => {
|
|
14793
|
+
const { sessionId } = context.req.param();
|
|
14794
|
+
abortedSessions.add(sessionId);
|
|
14795
|
+
return context.json({ status: "ok" });
|
|
14796
|
+
});
|
|
14797
|
+
app.post("/undo", async (context) => {
|
|
14798
|
+
if (!lastClaudeSessionId) {
|
|
14799
|
+
return context.json({ status: "error", message: "No session to undo" });
|
|
14800
|
+
}
|
|
14801
|
+
try {
|
|
14802
|
+
const env = { ...process.env };
|
|
14803
|
+
delete env.NODE_OPTIONS;
|
|
14804
|
+
delete env.VSCODE_INSPECTOR_OPTIONS;
|
|
14805
|
+
const queryResult = query({
|
|
14806
|
+
prompt: "/rewind",
|
|
14807
|
+
options: {
|
|
14808
|
+
pathToClaudeCodeExecutable: resolveClaudePath(),
|
|
14809
|
+
cwd: process.cwd(),
|
|
14810
|
+
env,
|
|
14811
|
+
resume: lastClaudeSessionId
|
|
14812
|
+
}
|
|
14813
|
+
});
|
|
14814
|
+
for await (const message of queryResult) {
|
|
14815
|
+
if (message.type === "result") break;
|
|
14816
|
+
}
|
|
14817
|
+
return context.json({ status: "ok" });
|
|
14818
|
+
} catch (error) {
|
|
14819
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
14820
|
+
return context.json({ status: "error", message: errorMessage });
|
|
14821
|
+
}
|
|
14822
|
+
});
|
|
14746
14823
|
app.get("/health", (context) => {
|
|
14747
14824
|
return context.json({ status: "ok", provider: "claude" });
|
|
14748
14825
|
});
|
|
14749
14826
|
return app;
|
|
14750
14827
|
};
|
|
14751
|
-
var isPortInUse = (port) => new Promise((resolve) => {
|
|
14752
|
-
const server = net__default.default.createServer();
|
|
14753
|
-
server.once("error", () => resolve(true));
|
|
14754
|
-
server.once("listening", () => {
|
|
14755
|
-
server.close();
|
|
14756
|
-
resolve(false);
|
|
14757
|
-
});
|
|
14758
|
-
server.listen(port);
|
|
14759
|
-
});
|
|
14760
14828
|
var startServer = async (port = DEFAULT_PORT) => {
|
|
14761
|
-
if (await isPortInUse(port)) {
|
|
14762
|
-
return;
|
|
14763
|
-
}
|
|
14764
14829
|
const app = createServer();
|
|
14765
14830
|
serve({ fetch: app.fetch, port });
|
|
14766
|
-
console.log(
|
|
14831
|
+
console.log(
|
|
14832
|
+
`${import_picocolors.default.magenta("\u269B")} ${import_picocolors.default.bold("React Grab")} ${import_picocolors.default.gray(VERSION)} ${import_picocolors.default.dim("(Claude Code)")}`
|
|
14833
|
+
);
|
|
14767
14834
|
console.log(`- Local: ${import_picocolors.default.cyan(`http://localhost:${port}`)}`);
|
|
14768
14835
|
};
|
|
14769
14836
|
if ((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('server.cjs', document.baseURI).href)) === url.pathToFileURL(process.argv[1]).href) {
|
package/dist/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { execSync, spawn } from 'child_process';
|
|
2
2
|
import { pathToFileURL, fileURLToPath } from 'url';
|
|
3
3
|
import { createServer as createServer$1 } from 'http';
|
|
4
4
|
import { Http2ServerRequest } from 'http2';
|
|
@@ -6,7 +6,6 @@ import { Readable } from 'stream';
|
|
|
6
6
|
import crypto, { randomUUID } from 'crypto';
|
|
7
7
|
import { dirname, join } from 'path';
|
|
8
8
|
import { setMaxListeners } from 'events';
|
|
9
|
-
import { spawn } from 'child_process';
|
|
10
9
|
import { createInterface } from 'readline';
|
|
11
10
|
import * as fs from 'fs';
|
|
12
11
|
import { realpathSync } from 'fs';
|
|
@@ -8736,8 +8735,7 @@ var ProcessTransport = class {
|
|
|
8736
8735
|
env.CLAUDE_CODE_ENTRYPOINT = "sdk-ts";
|
|
8737
8736
|
}
|
|
8738
8737
|
const fs2 = getFsImplementation();
|
|
8739
|
-
|
|
8740
|
-
if (!isPathCommand && !fs2.existsSync(pathToClaudeCodeExecutable)) {
|
|
8738
|
+
if (!fs2.existsSync(pathToClaudeCodeExecutable)) {
|
|
8741
8739
|
const errorMessage = isNativeBinary(pathToClaudeCodeExecutable) ? `Claude Code native binary not found at ${pathToClaudeCodeExecutable}. Please ensure Claude Code is installed via native installer or specify a valid path with options.pathToClaudeCodeExecutable.` : `Claude Code executable not found at ${pathToClaudeCodeExecutable}. Is options.pathToClaudeCodeExecutable set?`;
|
|
8742
8740
|
throw new ReferenceError(errorMessage);
|
|
8743
8741
|
}
|
|
@@ -14551,7 +14549,12 @@ function query({
|
|
|
14551
14549
|
} else if (systemPrompt.type === "preset") {
|
|
14552
14550
|
appendSystemPrompt = systemPrompt.append;
|
|
14553
14551
|
}
|
|
14554
|
-
let pathToClaudeCodeExecutable = rest.pathToClaudeCodeExecutable
|
|
14552
|
+
let pathToClaudeCodeExecutable = rest.pathToClaudeCodeExecutable;
|
|
14553
|
+
if (!pathToClaudeCodeExecutable) {
|
|
14554
|
+
const filename = fileURLToPath(import.meta.url);
|
|
14555
|
+
const dirname2 = join(filename, "..");
|
|
14556
|
+
pathToClaudeCodeExecutable = join(dirname2, "cli.js");
|
|
14557
|
+
}
|
|
14555
14558
|
process.env.CLAUDE_AGENT_SDK_VERSION = "0.1.46";
|
|
14556
14559
|
const {
|
|
14557
14560
|
abortController = createAbortController(),
|
|
@@ -14670,30 +14673,55 @@ function query({
|
|
|
14670
14673
|
var DEFAULT_PORT = 4567;
|
|
14671
14674
|
|
|
14672
14675
|
// src/server.ts
|
|
14673
|
-
var VERSION = "0.0.
|
|
14676
|
+
var VERSION = "0.0.80";
|
|
14677
|
+
var resolveClaudePath = () => {
|
|
14678
|
+
const command = process.platform === "win32" ? "where claude" : "which claude";
|
|
14679
|
+
try {
|
|
14680
|
+
const result = execSync(command, { encoding: "utf8" }).trim();
|
|
14681
|
+
return result.split("\n")[0];
|
|
14682
|
+
} catch {
|
|
14683
|
+
return "claude";
|
|
14684
|
+
}
|
|
14685
|
+
};
|
|
14686
|
+
var claudeSessionMap = /* @__PURE__ */ new Map();
|
|
14687
|
+
var abortedSessions = /* @__PURE__ */ new Set();
|
|
14688
|
+
var lastClaudeSessionId;
|
|
14674
14689
|
var isTextBlock = (block) => block.type === "text";
|
|
14675
14690
|
var createServer = () => {
|
|
14676
14691
|
const app = new Hono2();
|
|
14677
|
-
app.use("
|
|
14692
|
+
app.use("*", cors());
|
|
14678
14693
|
app.post("/agent", async (context) => {
|
|
14679
14694
|
const body = await context.req.json();
|
|
14680
|
-
const { content, prompt, options } = body;
|
|
14681
|
-
const
|
|
14695
|
+
const { content, prompt, options, sessionId } = body;
|
|
14696
|
+
const claudeSessionId = sessionId ? claudeSessionMap.get(sessionId) : void 0;
|
|
14697
|
+
const isFollowUp = Boolean(claudeSessionId);
|
|
14698
|
+
const userPrompt = isFollowUp ? prompt : `${prompt}
|
|
14682
14699
|
|
|
14683
14700
|
${content}`;
|
|
14684
14701
|
return streamSSE(context, async (stream2) => {
|
|
14702
|
+
const isAborted2 = () => sessionId && abortedSessions.has(sessionId);
|
|
14685
14703
|
try {
|
|
14686
14704
|
await stream2.writeSSE({ data: "Thinking...", event: "status" });
|
|
14705
|
+
const env = { ...process.env };
|
|
14706
|
+
delete env.NODE_OPTIONS;
|
|
14707
|
+
delete env.VSCODE_INSPECTOR_OPTIONS;
|
|
14687
14708
|
const queryResult = query({
|
|
14688
|
-
prompt:
|
|
14709
|
+
prompt: userPrompt,
|
|
14689
14710
|
options: {
|
|
14690
|
-
pathToClaudeCodeExecutable:
|
|
14711
|
+
pathToClaudeCodeExecutable: resolveClaudePath(),
|
|
14691
14712
|
cwd: process.cwd(),
|
|
14692
14713
|
includePartialMessages: true,
|
|
14693
|
-
|
|
14714
|
+
env,
|
|
14715
|
+
...options,
|
|
14716
|
+
...isFollowUp && claudeSessionId ? { resume: claudeSessionId } : {}
|
|
14694
14717
|
}
|
|
14695
14718
|
});
|
|
14719
|
+
let capturedClaudeSessionId;
|
|
14696
14720
|
for await (const message of queryResult) {
|
|
14721
|
+
if (isAborted2()) break;
|
|
14722
|
+
if (!capturedClaudeSessionId && message.session_id) {
|
|
14723
|
+
capturedClaudeSessionId = message.session_id;
|
|
14724
|
+
}
|
|
14697
14725
|
if (message.type === "assistant") {
|
|
14698
14726
|
const textContent = message.message.content.filter(isTextBlock).map((block) => block.text).join(" ");
|
|
14699
14727
|
if (textContent) {
|
|
@@ -14707,37 +14735,77 @@ ${content}`;
|
|
|
14707
14735
|
});
|
|
14708
14736
|
}
|
|
14709
14737
|
}
|
|
14710
|
-
|
|
14738
|
+
if (!isAborted2() && capturedClaudeSessionId) {
|
|
14739
|
+
lastClaudeSessionId = capturedClaudeSessionId;
|
|
14740
|
+
if (sessionId) {
|
|
14741
|
+
claudeSessionMap.set(sessionId, capturedClaudeSessionId);
|
|
14742
|
+
}
|
|
14743
|
+
}
|
|
14744
|
+
if (!isAborted2()) {
|
|
14745
|
+
await stream2.writeSSE({ data: "", event: "done" });
|
|
14746
|
+
}
|
|
14711
14747
|
} catch (error) {
|
|
14712
|
-
|
|
14713
|
-
|
|
14714
|
-
|
|
14715
|
-
|
|
14716
|
-
|
|
14748
|
+
if (!isAborted2()) {
|
|
14749
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
14750
|
+
const stderr = error instanceof Error && "stderr" in error ? String(error.stderr) : void 0;
|
|
14751
|
+
const fullError = stderr && stderr.trim() ? `${errorMessage}
|
|
14752
|
+
|
|
14753
|
+
stderr:
|
|
14754
|
+
${stderr.trim()}` : errorMessage;
|
|
14755
|
+
await stream2.writeSSE({
|
|
14756
|
+
data: `Error: ${fullError}`,
|
|
14757
|
+
event: "error"
|
|
14758
|
+
});
|
|
14759
|
+
}
|
|
14760
|
+
} finally {
|
|
14761
|
+
if (sessionId) {
|
|
14762
|
+
abortedSessions.delete(sessionId);
|
|
14763
|
+
}
|
|
14717
14764
|
}
|
|
14718
14765
|
});
|
|
14719
14766
|
});
|
|
14767
|
+
app.post("/abort/:sessionId", (context) => {
|
|
14768
|
+
const { sessionId } = context.req.param();
|
|
14769
|
+
abortedSessions.add(sessionId);
|
|
14770
|
+
return context.json({ status: "ok" });
|
|
14771
|
+
});
|
|
14772
|
+
app.post("/undo", async (context) => {
|
|
14773
|
+
if (!lastClaudeSessionId) {
|
|
14774
|
+
return context.json({ status: "error", message: "No session to undo" });
|
|
14775
|
+
}
|
|
14776
|
+
try {
|
|
14777
|
+
const env = { ...process.env };
|
|
14778
|
+
delete env.NODE_OPTIONS;
|
|
14779
|
+
delete env.VSCODE_INSPECTOR_OPTIONS;
|
|
14780
|
+
const queryResult = query({
|
|
14781
|
+
prompt: "/rewind",
|
|
14782
|
+
options: {
|
|
14783
|
+
pathToClaudeCodeExecutable: resolveClaudePath(),
|
|
14784
|
+
cwd: process.cwd(),
|
|
14785
|
+
env,
|
|
14786
|
+
resume: lastClaudeSessionId
|
|
14787
|
+
}
|
|
14788
|
+
});
|
|
14789
|
+
for await (const message of queryResult) {
|
|
14790
|
+
if (message.type === "result") break;
|
|
14791
|
+
}
|
|
14792
|
+
return context.json({ status: "ok" });
|
|
14793
|
+
} catch (error) {
|
|
14794
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
14795
|
+
return context.json({ status: "error", message: errorMessage });
|
|
14796
|
+
}
|
|
14797
|
+
});
|
|
14720
14798
|
app.get("/health", (context) => {
|
|
14721
14799
|
return context.json({ status: "ok", provider: "claude" });
|
|
14722
14800
|
});
|
|
14723
14801
|
return app;
|
|
14724
14802
|
};
|
|
14725
|
-
var isPortInUse = (port) => new Promise((resolve) => {
|
|
14726
|
-
const server = net.createServer();
|
|
14727
|
-
server.once("error", () => resolve(true));
|
|
14728
|
-
server.once("listening", () => {
|
|
14729
|
-
server.close();
|
|
14730
|
-
resolve(false);
|
|
14731
|
-
});
|
|
14732
|
-
server.listen(port);
|
|
14733
|
-
});
|
|
14734
14803
|
var startServer = async (port = DEFAULT_PORT) => {
|
|
14735
|
-
if (await isPortInUse(port)) {
|
|
14736
|
-
return;
|
|
14737
|
-
}
|
|
14738
14804
|
const app = createServer();
|
|
14739
14805
|
serve({ fetch: app.fetch, port });
|
|
14740
|
-
console.log(
|
|
14806
|
+
console.log(
|
|
14807
|
+
`${import_picocolors.default.magenta("\u269B")} ${import_picocolors.default.bold("React Grab")} ${import_picocolors.default.gray(VERSION)} ${import_picocolors.default.dim("(Claude Code)")}`
|
|
14808
|
+
);
|
|
14741
14809
|
console.log(`- Local: ${import_picocolors.default.cyan(`http://localhost:${port}`)}`);
|
|
14742
14810
|
};
|
|
14743
14811
|
if (import.meta.url === pathToFileURL(process.argv[1]).href) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-grab/claude-code",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.80",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"react-grab-claude-code": "./dist/cli.js"
|
|
@@ -24,14 +24,18 @@
|
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
26
|
"devDependencies": {
|
|
27
|
+
"@types/cross-spawn": "^6.0.6",
|
|
28
|
+
"@types/kill-port": "^2.0.3",
|
|
27
29
|
"tsup": "^8.4.0"
|
|
28
30
|
},
|
|
29
31
|
"dependencies": {
|
|
30
32
|
"@anthropic-ai/claude-agent-sdk": "^0.1.0",
|
|
31
33
|
"@hono/node-server": "^1.19.6",
|
|
34
|
+
"cross-spawn": "^7.0.6",
|
|
32
35
|
"hono": "^4.0.0",
|
|
36
|
+
"kill-port": "^2.0.1",
|
|
33
37
|
"picocolors": "^1.1.1",
|
|
34
|
-
"react-grab": "0.0.
|
|
38
|
+
"react-grab": "0.0.80"
|
|
35
39
|
},
|
|
36
40
|
"scripts": {
|
|
37
41
|
"dev": "tsup --watch",
|