happy-imou-cloud 2.0.13 → 2.0.14
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/BaseReasoningProcessor-CB7luAdI.mjs +320 -0
- package/dist/BaseReasoningProcessor-Cwhs4PwS.cjs +323 -0
- package/dist/ProviderSelectionHandler-CmDe9yDh.cjs +265 -0
- package/dist/ProviderSelectionHandler-DnnCwXqU.mjs +261 -0
- package/dist/{api-D1meoL-9.mjs → api-Bad69WzY.mjs} +2 -2
- package/dist/{api-DH5-IqeM.cjs → api-CaqY_2x_.cjs} +2 -2
- package/dist/{command-CMvWClny.mjs → command-D9ZaQZQN.mjs} +4 -3
- package/dist/{command-Ch8Dgidj.cjs → command-DkVbAV9p.cjs} +4 -3
- package/dist/{index-Cxrx9m5D.mjs → index-naa51zV7.mjs} +1102 -50
- package/dist/{index-CryJfCh5.cjs → index-oxTpdQx2.cjs} +1106 -50
- package/dist/index.cjs +5 -4
- package/dist/index.mjs +5 -4
- package/dist/lib.cjs +1 -1
- package/dist/lib.mjs +1 -1
- package/dist/{persistence-9Iu0wGNM.mjs → persistence-4BmGePWc.mjs} +1 -1
- package/dist/{persistence-Bl3FYvwd.cjs → persistence-Byr0hWCR.cjs} +1 -1
- package/dist/{registerKillSessionHandler-BjkY-oUn.cjs → registerKillSessionHandler-CodtiIoq.cjs} +549 -4
- package/dist/{registerKillSessionHandler-BElGmD1E.mjs → registerKillSessionHandler-HO4ql8g-.mjs} +541 -5
- package/dist/{runClaude-CDZxAF3l.cjs → runClaude-C3UNcGqk.cjs} +583 -747
- package/dist/{runClaude-D7dF4RDM.mjs → runClaude-Ev-A-kLN.mjs} +575 -738
- package/dist/{runCodex-DnGz1XES.mjs → runCodex-BwFOTxMW.mjs} +9 -215
- package/dist/{runCodex-Cik8VzFs.cjs → runCodex-CNM6wz69.cjs} +20 -226
- package/dist/{runGemini-B8tXMHeL.mjs → runGemini-CXctVflO.mjs} +8 -7
- package/dist/{runGemini-BM2BQ4I7.cjs → runGemini-DqfqSBsP.cjs} +16 -15
- package/package.json +1 -1
- package/scripts/release-smoke.mjs +6 -5
- package/dist/ConversationHistory-V3VLmjJf.cjs +0 -868
- package/dist/ConversationHistory-_ciJNIgH.mjs +0 -856
- package/dist/createKeepAliveController-C5cQlDRr.mjs +0 -51
- package/dist/createKeepAliveController-DO8H6d5E.cjs +0 -54
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var node_crypto = require('node:crypto');
|
|
4
|
-
var api = require('./api-
|
|
4
|
+
var api = require('./api-CaqY_2x_.cjs');
|
|
5
5
|
require('cross-spawn');
|
|
6
6
|
require('@agentclientprotocol/sdk');
|
|
7
|
-
var index = require('./index-
|
|
7
|
+
var index = require('./index-oxTpdQx2.cjs');
|
|
8
8
|
require('ps-list');
|
|
9
9
|
require('fs');
|
|
10
10
|
require('path');
|
|
@@ -13,11 +13,12 @@ require('child_process');
|
|
|
13
13
|
var fs$1 = require('node:fs');
|
|
14
14
|
var path = require('node:path');
|
|
15
15
|
var os = require('node:os');
|
|
16
|
-
require('
|
|
16
|
+
var node_child_process = require('node:child_process');
|
|
17
|
+
require('node:readline');
|
|
18
|
+
require('./persistence-Byr0hWCR.cjs');
|
|
17
19
|
var promises = require('node:fs/promises');
|
|
18
20
|
var fs = require('fs/promises');
|
|
19
21
|
require('crypto');
|
|
20
|
-
var node_child_process = require('node:child_process');
|
|
21
22
|
require('chalk');
|
|
22
23
|
require('node:events');
|
|
23
24
|
require('axios');
|
|
@@ -25,11 +26,9 @@ require('tweetnacl');
|
|
|
25
26
|
require('open');
|
|
26
27
|
var React = require('react');
|
|
27
28
|
var ink = require('ink');
|
|
28
|
-
var
|
|
29
|
+
var ProviderSelectionHandler = require('./ProviderSelectionHandler-CmDe9yDh.cjs');
|
|
29
30
|
var types = require('./types-DVk3crez.cjs');
|
|
30
|
-
var registerKillSessionHandler = require('./registerKillSessionHandler-
|
|
31
|
-
var node_readline = require('node:readline');
|
|
32
|
-
var node_url = require('node:url');
|
|
31
|
+
var registerKillSessionHandler = require('./registerKillSessionHandler-CodtiIoq.cjs');
|
|
33
32
|
require('socket.io-client');
|
|
34
33
|
require('expo-server-sdk');
|
|
35
34
|
var node_util = require('node:util');
|
|
@@ -43,8 +42,8 @@ require('fastify');
|
|
|
43
42
|
require('fastify-type-provider-zod');
|
|
44
43
|
require('http');
|
|
45
44
|
require('util');
|
|
45
|
+
require('node:url');
|
|
46
46
|
|
|
47
|
-
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
48
47
|
class Session {
|
|
49
48
|
path;
|
|
50
49
|
logPath;
|
|
@@ -82,7 +81,7 @@ class Session {
|
|
|
82
81
|
this._onModeChange = opts.onModeChange;
|
|
83
82
|
this.hookSettingsPath = opts.hookSettingsPath;
|
|
84
83
|
this.jsRuntime = opts.jsRuntime ?? "node";
|
|
85
|
-
this.keepAliveController =
|
|
84
|
+
this.keepAliveController = ProviderSelectionHandler.createKeepAliveController({
|
|
86
85
|
initialMode: this.mode,
|
|
87
86
|
initialThinking: this.thinking,
|
|
88
87
|
send: (thinking, mode) => {
|
|
@@ -204,27 +203,6 @@ class Session {
|
|
|
204
203
|
};
|
|
205
204
|
}
|
|
206
205
|
|
|
207
|
-
class Future {
|
|
208
|
-
_resolve;
|
|
209
|
-
_reject;
|
|
210
|
-
_promise;
|
|
211
|
-
constructor() {
|
|
212
|
-
this._promise = new Promise((resolve, reject) => {
|
|
213
|
-
this._resolve = resolve;
|
|
214
|
-
this._reject = reject;
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
resolve(value) {
|
|
218
|
-
this._resolve(value);
|
|
219
|
-
}
|
|
220
|
-
reject(reason) {
|
|
221
|
-
this._reject(reason);
|
|
222
|
-
}
|
|
223
|
-
get promise() {
|
|
224
|
-
return this._promise;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
206
|
class InvalidateSync {
|
|
229
207
|
_invalidated = false;
|
|
230
208
|
_invalidatedDouble = false;
|
|
@@ -633,7 +611,7 @@ async function claudeLocalLauncher(session) {
|
|
|
633
611
|
session.addSessionFoundCallback(scannerSessionCallback);
|
|
634
612
|
let exitReason = null;
|
|
635
613
|
const processAbortController = new AbortController();
|
|
636
|
-
let exutFuture = new Future();
|
|
614
|
+
let exutFuture = new index.Future();
|
|
637
615
|
try {
|
|
638
616
|
async function abort() {
|
|
639
617
|
if (!processAbortController.signal.aborted) {
|
|
@@ -718,6 +696,50 @@ async function claudeLocalLauncher(session) {
|
|
|
718
696
|
return exitReason || { type: "exit", code: 0 };
|
|
719
697
|
}
|
|
720
698
|
|
|
699
|
+
function parseCompact(message) {
|
|
700
|
+
const trimmed = message.trim();
|
|
701
|
+
if (trimmed === "/compact") {
|
|
702
|
+
return {
|
|
703
|
+
isCompact: true,
|
|
704
|
+
originalMessage: trimmed
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
if (trimmed.startsWith("/compact ")) {
|
|
708
|
+
return {
|
|
709
|
+
isCompact: true,
|
|
710
|
+
originalMessage: trimmed
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
return {
|
|
714
|
+
isCompact: false,
|
|
715
|
+
originalMessage: message
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
function parseClear(message) {
|
|
719
|
+
const trimmed = message.trim();
|
|
720
|
+
return {
|
|
721
|
+
isClear: trimmed === "/clear"
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
function parseSpecialCommand(message) {
|
|
725
|
+
const compactResult = parseCompact(message);
|
|
726
|
+
if (compactResult.isCompact) {
|
|
727
|
+
return {
|
|
728
|
+
type: "compact",
|
|
729
|
+
originalMessage: compactResult.originalMessage
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
const clearResult = parseClear(message);
|
|
733
|
+
if (clearResult.isClear) {
|
|
734
|
+
return {
|
|
735
|
+
type: "clear"
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
return {
|
|
739
|
+
type: null
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
|
|
721
743
|
const RemoteModeDisplay = ({ messageBuffer, logPath, onExit, onSwitchToLocal }) => {
|
|
722
744
|
const [messages, setMessages] = React.useState([]);
|
|
723
745
|
const [confirmationMode, setConfirmationMode] = React.useState(null);
|
|
@@ -843,699 +865,577 @@ const RemoteModeDisplay = ({ messageBuffer, logPath, onExit, onSwitchToLocal })
|
|
|
843
865
|
));
|
|
844
866
|
};
|
|
845
867
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
}
|
|
850
|
-
queue = [];
|
|
851
|
-
readResolve;
|
|
852
|
-
readReject;
|
|
853
|
-
isDone = false;
|
|
854
|
-
hasError;
|
|
855
|
-
started = false;
|
|
856
|
-
/**
|
|
857
|
-
* Implements async iterable protocol
|
|
858
|
-
*/
|
|
859
|
-
[Symbol.asyncIterator]() {
|
|
860
|
-
if (this.started) {
|
|
861
|
-
throw new Error("Stream can only be iterated once");
|
|
862
|
-
}
|
|
863
|
-
this.started = true;
|
|
864
|
-
return this;
|
|
865
|
-
}
|
|
866
|
-
/**
|
|
867
|
-
* Gets the next value from the stream
|
|
868
|
-
*/
|
|
869
|
-
async next() {
|
|
870
|
-
if (this.queue.length > 0) {
|
|
871
|
-
return Promise.resolve({
|
|
872
|
-
done: false,
|
|
873
|
-
value: this.queue.shift()
|
|
874
|
-
});
|
|
875
|
-
}
|
|
876
|
-
if (this.isDone) {
|
|
877
|
-
return Promise.resolve({ done: true, value: void 0 });
|
|
878
|
-
}
|
|
879
|
-
if (this.hasError) {
|
|
880
|
-
return Promise.reject(this.hasError);
|
|
881
|
-
}
|
|
882
|
-
return new Promise((resolve, reject) => {
|
|
883
|
-
this.readResolve = resolve;
|
|
884
|
-
this.readReject = reject;
|
|
885
|
-
});
|
|
886
|
-
}
|
|
887
|
-
/**
|
|
888
|
-
* Adds a value to the stream
|
|
889
|
-
*/
|
|
890
|
-
enqueue(value) {
|
|
891
|
-
if (this.readResolve) {
|
|
892
|
-
const resolve = this.readResolve;
|
|
893
|
-
this.readResolve = void 0;
|
|
894
|
-
this.readReject = void 0;
|
|
895
|
-
resolve({ done: false, value });
|
|
896
|
-
} else {
|
|
897
|
-
this.queue.push(value);
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
/**
|
|
901
|
-
* Marks the stream as complete
|
|
902
|
-
*/
|
|
903
|
-
done() {
|
|
904
|
-
this.isDone = true;
|
|
905
|
-
if (this.readResolve) {
|
|
906
|
-
const resolve = this.readResolve;
|
|
907
|
-
this.readResolve = void 0;
|
|
908
|
-
this.readReject = void 0;
|
|
909
|
-
resolve({ done: true, value: void 0 });
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
/**
|
|
913
|
-
* Propagates an error through the stream
|
|
914
|
-
*/
|
|
915
|
-
error(error) {
|
|
916
|
-
this.hasError = error;
|
|
917
|
-
if (this.readReject) {
|
|
918
|
-
const reject = this.readReject;
|
|
919
|
-
this.readResolve = void 0;
|
|
920
|
-
this.readReject = void 0;
|
|
921
|
-
reject(error);
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
/**
|
|
925
|
-
* Implements async iterator cleanup
|
|
926
|
-
*/
|
|
927
|
-
async return() {
|
|
928
|
-
this.isDone = true;
|
|
929
|
-
if (this.returned) {
|
|
930
|
-
this.returned();
|
|
931
|
-
}
|
|
932
|
-
return Promise.resolve({ done: true, value: void 0 });
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
class AbortError extends Error {
|
|
937
|
-
constructor(message) {
|
|
938
|
-
super(message);
|
|
939
|
-
this.name = "AbortError";
|
|
940
|
-
}
|
|
868
|
+
function getClaudeSettingsPath() {
|
|
869
|
+
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
|
|
870
|
+
return path.join(claudeConfigDir, "settings.json");
|
|
941
871
|
}
|
|
942
|
-
|
|
943
|
-
const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('runClaude-CDZxAF3l.cjs', document.baseURI).href)));
|
|
944
|
-
const __dirname$1 = path.join(__filename$1, "..");
|
|
945
|
-
function getGlobalClaudeVersion() {
|
|
872
|
+
function readClaudeSettings() {
|
|
946
873
|
try {
|
|
947
|
-
const
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
api.logger.debug(`[
|
|
956
|
-
return
|
|
957
|
-
} catch {
|
|
874
|
+
const settingsPath = getClaudeSettingsPath();
|
|
875
|
+
if (!fs$1.existsSync(settingsPath)) {
|
|
876
|
+
api.logger.debug(`[ClaudeSettings] No Claude settings file found at ${settingsPath}`);
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
const settingsContent = fs$1.readFileSync(settingsPath, "utf-8");
|
|
880
|
+
const settings = JSON.parse(settingsContent);
|
|
881
|
+
api.logger.debug(`[ClaudeSettings] Successfully read Claude settings from ${settingsPath}`);
|
|
882
|
+
api.logger.debug(`[ClaudeSettings] includeCoAuthoredBy: ${settings.includeCoAuthoredBy}`);
|
|
883
|
+
return settings;
|
|
884
|
+
} catch (error) {
|
|
885
|
+
api.logger.debug(`[ClaudeSettings] Error reading Claude settings: ${error}`);
|
|
958
886
|
return null;
|
|
959
887
|
}
|
|
960
888
|
}
|
|
961
|
-
function
|
|
962
|
-
const
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
const pathKey = process.platform === "win32" ? "Path" : "PATH";
|
|
966
|
-
const actualPathKey = Object.keys(env).find((k) => k.toLowerCase() === "path") || pathKey;
|
|
967
|
-
if (env[actualPathKey]) {
|
|
968
|
-
const cleanPath = env[actualPathKey].split(pathSep).filter((p) => {
|
|
969
|
-
const normalizedP = p.replace(/\\/g, "/").toLowerCase();
|
|
970
|
-
const normalizedCwd = cwd.replace(/\\/g, "/").toLowerCase();
|
|
971
|
-
return !normalizedP.startsWith(normalizedCwd);
|
|
972
|
-
}).join(pathSep);
|
|
973
|
-
env[actualPathKey] = cleanPath;
|
|
974
|
-
api.logger.debug(`[Claude SDK] Cleaned PATH, removed local paths from: ${cwd}`);
|
|
975
|
-
}
|
|
976
|
-
if (index.isBun()) {
|
|
977
|
-
Object.keys(env).forEach((key) => {
|
|
978
|
-
if (key.startsWith("BUN_")) {
|
|
979
|
-
delete env[key];
|
|
980
|
-
}
|
|
981
|
-
});
|
|
982
|
-
api.logger.debug("[Claude SDK] Removed Bun-specific environment variables for Node.js compatibility");
|
|
889
|
+
function shouldIncludeCoAuthoredBy() {
|
|
890
|
+
const settings = readClaudeSettings();
|
|
891
|
+
if (!settings || settings.includeCoAuthoredBy === void 0) {
|
|
892
|
+
return true;
|
|
983
893
|
}
|
|
984
|
-
return
|
|
894
|
+
return settings.includeCoAuthoredBy;
|
|
985
895
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
}).trim();
|
|
1008
|
-
if (result && fs$1.existsSync(result)) {
|
|
1009
|
-
api.logger.debug(`[Claude SDK] Found global claude path via which: ${result}`);
|
|
1010
|
-
return result;
|
|
1011
|
-
}
|
|
1012
|
-
} catch {
|
|
1013
|
-
}
|
|
896
|
+
|
|
897
|
+
const BASE_SYSTEM_PROMPT = (() => index.trimIdent(`
|
|
898
|
+
Help human.
|
|
899
|
+
`))();
|
|
900
|
+
const CO_AUTHORED_CREDITS = (() => index.trimIdent(`
|
|
901
|
+
When making commit messages, instead of just giving co-credit to Claude, also give credit to Happy like so:
|
|
902
|
+
|
|
903
|
+
<main commit message>
|
|
904
|
+
|
|
905
|
+
Generated with [Claude Code](https://claude.ai/code)
|
|
906
|
+
via [Happy](https://happy.engineering)
|
|
907
|
+
|
|
908
|
+
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
909
|
+
Co-Authored-By: Happy <yesreply@happy.engineering>
|
|
910
|
+
`))();
|
|
911
|
+
const systemPrompt = (() => {
|
|
912
|
+
const includeCoAuthored = shouldIncludeCoAuthoredBy();
|
|
913
|
+
if (includeCoAuthored) {
|
|
914
|
+
return BASE_SYSTEM_PROMPT + "\n\n" + CO_AUTHORED_CREDITS;
|
|
915
|
+
} else {
|
|
916
|
+
return BASE_SYSTEM_PROMPT;
|
|
1014
917
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
function
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
api.logger.debug(`[Claude SDK] Using HAPPY_CLAUDE_PATH: ${process.env.HAPPY_CLAUDE_PATH}`);
|
|
1021
|
-
return process.env.HAPPY_CLAUDE_PATH;
|
|
1022
|
-
}
|
|
1023
|
-
if (process.env.HAPPY_USE_BUNDLED_CLAUDE === "1") {
|
|
1024
|
-
api.logger.debug(`[Claude SDK] Forced bundled version: ${nodeModulesPath}`);
|
|
1025
|
-
return nodeModulesPath;
|
|
1026
|
-
}
|
|
1027
|
-
const globalPath = findGlobalClaudePath();
|
|
1028
|
-
if (!globalPath) {
|
|
1029
|
-
api.logger.debug(`[Claude SDK] No global claude found, using bundled: ${nodeModulesPath}`);
|
|
1030
|
-
return nodeModulesPath;
|
|
1031
|
-
}
|
|
1032
|
-
const globalVersion = getGlobalClaudeVersion();
|
|
1033
|
-
api.logger.debug(`[Claude SDK] Global version: ${globalVersion || "unknown"}`);
|
|
1034
|
-
if (!globalVersion) {
|
|
1035
|
-
api.logger.debug(`[Claude SDK] Cannot compare versions, using global: ${globalPath}`);
|
|
1036
|
-
return globalPath;
|
|
1037
|
-
}
|
|
1038
|
-
return globalPath;
|
|
1039
|
-
}
|
|
1040
|
-
function logDebug(message) {
|
|
1041
|
-
if (process.env.DEBUG) {
|
|
1042
|
-
api.logger.debug(message);
|
|
1043
|
-
console.log(message);
|
|
918
|
+
})();
|
|
919
|
+
|
|
920
|
+
function getToolDescriptor(toolName) {
|
|
921
|
+
if (toolName === "exit_plan_mode" || toolName === "ExitPlanMode") {
|
|
922
|
+
return { edit: false, exitPlan: true };
|
|
1044
923
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
for await (const message of stream) {
|
|
1048
|
-
if (abort?.aborted) break;
|
|
1049
|
-
stdin.write(JSON.stringify(message) + "\n");
|
|
924
|
+
if (toolName === "Edit" || toolName === "MultiEdit" || toolName === "Write" || toolName === "NotebookEdit") {
|
|
925
|
+
return { edit: true, exitPlan: false };
|
|
1050
926
|
}
|
|
1051
|
-
|
|
927
|
+
return { edit: false, exitPlan: false };
|
|
1052
928
|
}
|
|
1053
929
|
|
|
1054
|
-
class
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
this.processExitPromise = processExitPromise;
|
|
1059
|
-
this.canCallTool = canCallTool;
|
|
1060
|
-
this.readMessages();
|
|
1061
|
-
this.sdkMessages = this.readSdkMessages();
|
|
1062
|
-
}
|
|
1063
|
-
pendingControlResponses = /* @__PURE__ */ new Map();
|
|
1064
|
-
cancelControllers = /* @__PURE__ */ new Map();
|
|
1065
|
-
sdkMessages;
|
|
1066
|
-
inputStream = new Stream();
|
|
1067
|
-
canCallTool;
|
|
1068
|
-
/**
|
|
1069
|
-
* Set an error on the stream
|
|
1070
|
-
*/
|
|
1071
|
-
setError(error) {
|
|
1072
|
-
this.inputStream.error(error);
|
|
930
|
+
class ClaudeAcpPermissionHandler extends registerKillSessionHandler.BasePermissionHandler {
|
|
931
|
+
currentPermissionMode = "default";
|
|
932
|
+
constructor(session) {
|
|
933
|
+
super(session);
|
|
1073
934
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
*/
|
|
1077
|
-
next(...args) {
|
|
1078
|
-
return this.sdkMessages.next(...args);
|
|
935
|
+
getLogPrefix() {
|
|
936
|
+
return "[ClaudeACP]";
|
|
1079
937
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
}
|
|
1084
|
-
return Promise.resolve({ done: true, value: void 0 });
|
|
938
|
+
setPermissionMode(mode) {
|
|
939
|
+
this.currentPermissionMode = mode;
|
|
940
|
+
api.logger.debug(`${this.getLogPrefix()} Permission mode set to: ${mode}`);
|
|
1085
941
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
942
|
+
shouldAutoApprove(toolName) {
|
|
943
|
+
const descriptor = getToolDescriptor(toolName);
|
|
944
|
+
switch (this.currentPermissionMode) {
|
|
945
|
+
case "bypassPermissions":
|
|
946
|
+
case "yolo":
|
|
947
|
+
return true;
|
|
948
|
+
case "acceptEdits":
|
|
949
|
+
return descriptor.edit;
|
|
950
|
+
default:
|
|
951
|
+
return false;
|
|
1089
952
|
}
|
|
1090
|
-
return Promise.reject(e);
|
|
1091
|
-
}
|
|
1092
|
-
[Symbol.asyncIterator]() {
|
|
1093
|
-
return this.sdkMessages;
|
|
1094
953
|
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
handler(controlResponse.response);
|
|
1110
|
-
}
|
|
1111
|
-
continue;
|
|
1112
|
-
} else if (message.type === "control_request") {
|
|
1113
|
-
await this.handleControlRequest(message);
|
|
1114
|
-
continue;
|
|
1115
|
-
} else if (message.type === "control_cancel_request") {
|
|
1116
|
-
this.handleControlCancelRequest(message);
|
|
1117
|
-
continue;
|
|
1118
|
-
}
|
|
1119
|
-
this.inputStream.enqueue(message);
|
|
1120
|
-
} catch (e) {
|
|
1121
|
-
api.logger.debug(line);
|
|
954
|
+
async handleToolCall(toolCallId, toolName, input) {
|
|
955
|
+
if (this.shouldAutoApprove(toolName)) {
|
|
956
|
+
const decision = this.currentPermissionMode === "bypassPermissions" || this.currentPermissionMode === "yolo" ? "approved_for_session" : "approved";
|
|
957
|
+
this.session.updateAgentState((currentState) => ({
|
|
958
|
+
...currentState,
|
|
959
|
+
completedRequests: {
|
|
960
|
+
...currentState.completedRequests,
|
|
961
|
+
[toolCallId]: {
|
|
962
|
+
tool: toolName,
|
|
963
|
+
arguments: input,
|
|
964
|
+
createdAt: Date.now(),
|
|
965
|
+
completedAt: Date.now(),
|
|
966
|
+
status: "approved",
|
|
967
|
+
decision
|
|
1122
968
|
}
|
|
1123
969
|
}
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
this.inputStream.error(error);
|
|
1128
|
-
} finally {
|
|
1129
|
-
this.inputStream.done();
|
|
1130
|
-
this.cleanupControllers();
|
|
1131
|
-
rl.close();
|
|
970
|
+
}));
|
|
971
|
+
api.logger.debug(`${this.getLogPrefix()} Auto-approved tool ${toolName} (${toolCallId}) in ${this.currentPermissionMode} mode`);
|
|
972
|
+
return { decision };
|
|
1132
973
|
}
|
|
974
|
+
return this.registerPendingRequest(
|
|
975
|
+
toolCallId,
|
|
976
|
+
toolName,
|
|
977
|
+
input,
|
|
978
|
+
` in ${this.currentPermissionMode} mode`
|
|
979
|
+
);
|
|
1133
980
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
function normalizeClaudeBackendError(error) {
|
|
984
|
+
const record = typeof error === "object" && error !== null ? error : null;
|
|
985
|
+
const text = index.formatDisplayMessage(error).trim();
|
|
986
|
+
const stderrText = record ? index.formatDisplayMessage(record.stderr).trim() : "";
|
|
987
|
+
const detailText = record ? index.formatDisplayMessage(record.detail).trim() : "";
|
|
988
|
+
const searchable = [text, stderrText, detailText].filter(Boolean).join("\n").trim();
|
|
989
|
+
return searchable || "Claude ACP backend exited unexpectedly";
|
|
990
|
+
}
|
|
991
|
+
async function claudeAcpRemoteLauncher(session) {
|
|
992
|
+
const hasTTY = process.stdout.isTTY && process.stdin.isTTY;
|
|
993
|
+
const messageBuffer = new registerKillSessionHandler.MessageBuffer({ enabled: hasTTY });
|
|
994
|
+
let inkInstance = null;
|
|
995
|
+
let shouldExit = false;
|
|
996
|
+
let abortController = new AbortController();
|
|
997
|
+
let runtimeHandle = null;
|
|
998
|
+
let unsubscribeRuntimeMessages = null;
|
|
999
|
+
let currentModeHash = null;
|
|
1000
|
+
let pending = null;
|
|
1001
|
+
let accumulatedResponse = "";
|
|
1002
|
+
let isResponseInProgress = false;
|
|
1003
|
+
let taskStartedSent = false;
|
|
1004
|
+
let currentAssistantMessageId = null;
|
|
1005
|
+
let currentThinkingMessageId = null;
|
|
1006
|
+
let shouldInjectHistoryOnNextSession = false;
|
|
1007
|
+
let readyAlreadySent = false;
|
|
1008
|
+
const permissionHandler = new ClaudeAcpPermissionHandler(session.client);
|
|
1009
|
+
const selectionHandler = new ProviderSelectionHandler.ProviderSelectionHandler(session.client, "Claude");
|
|
1010
|
+
const conversationHistory = new registerKillSessionHandler.ConversationHistory({
|
|
1011
|
+
maxMessages: 20,
|
|
1012
|
+
maxCharacters: 5e4
|
|
1013
|
+
});
|
|
1014
|
+
const rotateAbortController = () => {
|
|
1015
|
+
const activeController = abortController;
|
|
1016
|
+
abortController = new AbortController();
|
|
1017
|
+
return activeController;
|
|
1018
|
+
};
|
|
1019
|
+
const sendReady = () => {
|
|
1020
|
+
session.client.sendSessionEvent({ type: "ready" });
|
|
1021
|
+
try {
|
|
1022
|
+
session.api.push().sendToAllDevices(
|
|
1023
|
+
"It's ready!",
|
|
1024
|
+
"Claude is waiting for your command",
|
|
1025
|
+
{ sessionId: session.client.sessionId }
|
|
1026
|
+
);
|
|
1027
|
+
} catch (pushError) {
|
|
1028
|
+
api.logger.debug("[ClaudeACP] Failed to send ready push", pushError);
|
|
1140
1029
|
}
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1030
|
+
};
|
|
1031
|
+
const emitStatusMessage = (message) => {
|
|
1032
|
+
messageBuffer.addMessage(message, "status");
|
|
1033
|
+
session.client.sendSessionEvent({ type: "message", message });
|
|
1034
|
+
};
|
|
1035
|
+
const emitUserVisibleErrorMessage = (message) => {
|
|
1036
|
+
emitStatusMessage(message);
|
|
1037
|
+
session.client.sendAgentMessage("claude", {
|
|
1038
|
+
type: "message",
|
|
1039
|
+
message
|
|
1040
|
+
});
|
|
1041
|
+
};
|
|
1042
|
+
const resetTurnState = () => {
|
|
1043
|
+
accumulatedResponse = "";
|
|
1044
|
+
isResponseInProgress = false;
|
|
1045
|
+
taskStartedSent = false;
|
|
1046
|
+
currentAssistantMessageId = null;
|
|
1047
|
+
currentThinkingMessageId = null;
|
|
1048
|
+
session.onThinkingChange(false);
|
|
1049
|
+
};
|
|
1050
|
+
const emitFinalAssistantMessage = () => {
|
|
1051
|
+
const finalMessage = accumulatedResponse.trim();
|
|
1052
|
+
if (!finalMessage) {
|
|
1053
|
+
accumulatedResponse = "";
|
|
1054
|
+
isResponseInProgress = false;
|
|
1055
|
+
return;
|
|
1148
1056
|
}
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
/**
|
|
1154
|
-
* Send control request to Claude process
|
|
1155
|
-
*/
|
|
1156
|
-
request(request, childStdin) {
|
|
1157
|
-
const requestId = Math.random().toString(36).substring(2, 15);
|
|
1158
|
-
const sdkRequest = {
|
|
1159
|
-
request_id: requestId,
|
|
1160
|
-
type: "control_request",
|
|
1161
|
-
request
|
|
1162
|
-
};
|
|
1163
|
-
return new Promise((resolve, reject) => {
|
|
1164
|
-
this.pendingControlResponses.set(requestId, (response) => {
|
|
1165
|
-
if (response.subtype === "success") {
|
|
1166
|
-
resolve(response);
|
|
1167
|
-
} else {
|
|
1168
|
-
reject(new Error(response.error));
|
|
1169
|
-
}
|
|
1170
|
-
});
|
|
1171
|
-
childStdin.write(JSON.stringify(sdkRequest) + "\n");
|
|
1057
|
+
conversationHistory.addAssistantMessage(finalMessage);
|
|
1058
|
+
session.client.sendAgentMessage("claude", {
|
|
1059
|
+
type: "message",
|
|
1060
|
+
message: finalMessage
|
|
1172
1061
|
});
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
async handleControlRequest(request) {
|
|
1179
|
-
if (!this.childStdin) {
|
|
1180
|
-
logDebug("Cannot handle control request - no stdin available");
|
|
1062
|
+
accumulatedResponse = "";
|
|
1063
|
+
isResponseInProgress = false;
|
|
1064
|
+
};
|
|
1065
|
+
const disposeRuntimeHandle = async () => {
|
|
1066
|
+
if (!runtimeHandle) {
|
|
1181
1067
|
return;
|
|
1182
1068
|
}
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1069
|
+
const activeHandle = runtimeHandle;
|
|
1070
|
+
runtimeHandle = null;
|
|
1071
|
+
unsubscribeRuntimeMessages?.();
|
|
1072
|
+
unsubscribeRuntimeMessages = null;
|
|
1185
1073
|
try {
|
|
1186
|
-
|
|
1187
|
-
const controlResponse = {
|
|
1188
|
-
type: "control_response",
|
|
1189
|
-
response: {
|
|
1190
|
-
subtype: "success",
|
|
1191
|
-
request_id: request.request_id,
|
|
1192
|
-
response
|
|
1193
|
-
}
|
|
1194
|
-
};
|
|
1195
|
-
this.childStdin.write(JSON.stringify(controlResponse) + "\n");
|
|
1074
|
+
await activeHandle.dispose();
|
|
1196
1075
|
} catch (error) {
|
|
1197
|
-
|
|
1198
|
-
type: "control_response",
|
|
1199
|
-
response: {
|
|
1200
|
-
subtype: "error",
|
|
1201
|
-
request_id: request.request_id,
|
|
1202
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1203
|
-
}
|
|
1204
|
-
};
|
|
1205
|
-
this.childStdin.write(JSON.stringify(controlErrorResponse) + "\n");
|
|
1206
|
-
} finally {
|
|
1207
|
-
this.cancelControllers.delete(request.request_id);
|
|
1076
|
+
api.logger.debug("[ClaudeACP] Error disposing runtime handle:", error);
|
|
1208
1077
|
}
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
this.cancelControllers.delete(request.request_id);
|
|
1078
|
+
};
|
|
1079
|
+
const queueHistoryInjectionForRestart = (reason) => {
|
|
1080
|
+
messageBuffer.addMessage("\u2550".repeat(40), "status");
|
|
1081
|
+
if (conversationHistory.hasHistory()) {
|
|
1082
|
+
shouldInjectHistoryOnNextSession = true;
|
|
1083
|
+
const message = `${reason} Preserving ${conversationHistory.size()} earlier messages of context.`;
|
|
1084
|
+
emitStatusMessage(message);
|
|
1085
|
+
api.logger.debug(`[ClaudeACP] Will inject conversation history after restart: ${conversationHistory.getSummary()}`);
|
|
1086
|
+
return;
|
|
1219
1087
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
if (!this.canCallTool) {
|
|
1228
|
-
throw new Error("canCallTool callback is not provided.");
|
|
1229
|
-
}
|
|
1230
|
-
return this.canCallTool(request.request.tool_name, request.request.input, {
|
|
1231
|
-
signal
|
|
1088
|
+
emitStatusMessage(reason);
|
|
1089
|
+
};
|
|
1090
|
+
const setupRuntimeMessageHandler = (activeRuntimeHandle) => {
|
|
1091
|
+
const forwardAgentMessage = (agentMessage) => {
|
|
1092
|
+
registerKillSessionHandler.forwardAgentMessageToProviderSession(agentMessage, {
|
|
1093
|
+
provider: "claude",
|
|
1094
|
+
send: (body) => session.client.sendAgentMessage("claude", body)
|
|
1232
1095
|
});
|
|
1233
|
-
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1096
|
+
};
|
|
1097
|
+
unsubscribeRuntimeMessages?.();
|
|
1098
|
+
unsubscribeRuntimeMessages = activeRuntimeHandle.onMessage((msg) => {
|
|
1099
|
+
switch (msg.type) {
|
|
1100
|
+
case "model-output": {
|
|
1101
|
+
const text = msg.textDelta ?? msg.fullText ?? "";
|
|
1102
|
+
if (!text) {
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
if (!isResponseInProgress) {
|
|
1106
|
+
if (currentThinkingMessageId) {
|
|
1107
|
+
messageBuffer.removeMessage(currentThinkingMessageId);
|
|
1108
|
+
currentThinkingMessageId = null;
|
|
1109
|
+
}
|
|
1110
|
+
currentAssistantMessageId = messageBuffer.addMessage(text, "assistant");
|
|
1111
|
+
isResponseInProgress = true;
|
|
1112
|
+
} else if (currentAssistantMessageId) {
|
|
1113
|
+
const updated = messageBuffer.updateMessage(currentAssistantMessageId, text);
|
|
1114
|
+
if (!updated) {
|
|
1115
|
+
currentAssistantMessageId = messageBuffer.addMessage(text, "assistant");
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
accumulatedResponse += text;
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
case "status": {
|
|
1122
|
+
if (msg.status === "running") {
|
|
1123
|
+
session.onThinkingChange(true);
|
|
1124
|
+
if (!taskStartedSent) {
|
|
1125
|
+
session.client.sendAgentMessage("claude", {
|
|
1126
|
+
type: "task_started",
|
|
1127
|
+
id: node_crypto.randomUUID()
|
|
1128
|
+
});
|
|
1129
|
+
taskStartedSent = true;
|
|
1130
|
+
}
|
|
1131
|
+
if (!isResponseInProgress && !currentThinkingMessageId) {
|
|
1132
|
+
currentThinkingMessageId = messageBuffer.addMessage("Thinking...", "system");
|
|
1133
|
+
}
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
if (msg.status === "idle" || msg.status === "stopped") {
|
|
1137
|
+
session.onThinkingChange(false);
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
if (msg.status === "error") {
|
|
1141
|
+
messageBuffer.addMessage(`Error: ${normalizeClaudeBackendError(msg.detail)}`, "status");
|
|
1142
|
+
}
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
case "tool-call": {
|
|
1146
|
+
const toolArgs = index.truncateDisplayMessage(msg.args, 100);
|
|
1147
|
+
messageBuffer.addMessage(
|
|
1148
|
+
`Executing: ${msg.toolName}${toolArgs ? ` ${toolArgs}` : ""}`,
|
|
1149
|
+
"tool"
|
|
1150
|
+
);
|
|
1151
|
+
forwardAgentMessage(msg);
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
case "tool-result": {
|
|
1155
|
+
const resultText = index.truncateDisplayMessage(msg.result, 200);
|
|
1156
|
+
messageBuffer.addMessage(resultText ? `Result: ${resultText}` : "Tool completed", "result");
|
|
1157
|
+
forwardAgentMessage(msg);
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
case "fs-edit": {
|
|
1161
|
+
messageBuffer.addMessage(`File edit: ${msg.description}`, "tool");
|
|
1162
|
+
forwardAgentMessage(msg);
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
case "terminal-output": {
|
|
1166
|
+
const output = index.formatDisplayMessage(msg.data);
|
|
1167
|
+
messageBuffer.addMessage(output, "result");
|
|
1168
|
+
forwardAgentMessage({
|
|
1169
|
+
...msg,
|
|
1170
|
+
data: output
|
|
1171
|
+
});
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
case "permission-request": {
|
|
1175
|
+
forwardAgentMessage(msg);
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
case "token-count": {
|
|
1179
|
+
forwardAgentMessage(msg);
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
case "exec-approval-request":
|
|
1183
|
+
case "patch-apply-begin":
|
|
1184
|
+
case "patch-apply-end": {
|
|
1185
|
+
forwardAgentMessage(msg);
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
case "event": {
|
|
1189
|
+
if (msg.name === "thinking") {
|
|
1190
|
+
const payload = msg.payload;
|
|
1191
|
+
const thinkingText = typeof payload?.text === "string" ? payload.text : "";
|
|
1192
|
+
if (thinkingText) {
|
|
1193
|
+
session.client.sendAgentMessage("claude", {
|
|
1194
|
+
type: "thinking",
|
|
1195
|
+
text: thinkingText
|
|
1196
|
+
});
|
|
1197
|
+
if (!isResponseInProgress) {
|
|
1198
|
+
const preview = `[Thinking] ${thinkingText.substring(0, 100)}...`;
|
|
1199
|
+
if (currentThinkingMessageId) {
|
|
1200
|
+
messageBuffer.updateMessage(currentThinkingMessageId, preview, { mode: "replace" });
|
|
1201
|
+
} else {
|
|
1202
|
+
currentThinkingMessageId = messageBuffer.addMessage(preview, "system");
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
default:
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1332
1212
|
});
|
|
1333
|
-
}
|
|
1334
|
-
const cleanup = () => {
|
|
1335
|
-
if (!child.killed) {
|
|
1336
|
-
child.kill("SIGTERM");
|
|
1337
|
-
}
|
|
1338
1213
|
};
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1214
|
+
const createRuntimeHandle = async (mode) => {
|
|
1215
|
+
const { session: nextRuntimeHandle, factoryResult } = await registerKillSessionHandler.launchRuntimeHandleWithFactoryResult({
|
|
1216
|
+
provider: "claude",
|
|
1217
|
+
cwd: session.path,
|
|
1218
|
+
createBackendResult: (opts) => index.createClaudeBackend({
|
|
1219
|
+
...opts,
|
|
1220
|
+
baseArgs: session.claudeArgs,
|
|
1221
|
+
mcpServers: session.mcpServers,
|
|
1222
|
+
permissionHandler,
|
|
1223
|
+
permissionMode: mode.permissionMode,
|
|
1224
|
+
model: mode.model,
|
|
1225
|
+
fallbackModel: mode.fallbackModel,
|
|
1226
|
+
customSystemPrompt: mode.customSystemPrompt ? `${mode.customSystemPrompt}
|
|
1227
|
+
|
|
1228
|
+
${systemPrompt}` : void 0,
|
|
1229
|
+
appendSystemPrompt: mode.appendSystemPrompt ? `${mode.appendSystemPrompt}
|
|
1230
|
+
|
|
1231
|
+
${systemPrompt}` : systemPrompt,
|
|
1232
|
+
allowedTools: mode.allowedTools ? mode.allowedTools.concat(session.allowedTools ?? []) : session.allowedTools,
|
|
1233
|
+
disallowedTools: mode.disallowedTools,
|
|
1234
|
+
settingsPath: session.hookSettingsPath
|
|
1235
|
+
})
|
|
1351
1236
|
});
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1237
|
+
api.logger.debug("[ClaudeACP] Started Claude ACP backend", {
|
|
1238
|
+
command: factoryResult.command,
|
|
1239
|
+
args: factoryResult.args
|
|
1240
|
+
});
|
|
1241
|
+
runtimeHandle = nextRuntimeHandle;
|
|
1242
|
+
setupRuntimeMessageHandler(nextRuntimeHandle);
|
|
1243
|
+
session.consumeOneTimeFlags();
|
|
1244
|
+
return nextRuntimeHandle;
|
|
1245
|
+
};
|
|
1246
|
+
const abortActiveTurn = async () => {
|
|
1247
|
+
const activeController = rotateAbortController();
|
|
1248
|
+
activeController.abort();
|
|
1249
|
+
session.onThinkingChange(false);
|
|
1250
|
+
if (runtimeHandle) {
|
|
1251
|
+
await runtimeHandle.cancel().catch((error) => {
|
|
1252
|
+
api.logger.debug("[ClaudeACP] Error cancelling runtime handle:", error);
|
|
1253
|
+
});
|
|
1366
1254
|
}
|
|
1367
|
-
});
|
|
1368
|
-
return query2;
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
function parseCompact(message) {
|
|
1372
|
-
const trimmed = message.trim();
|
|
1373
|
-
if (trimmed === "/compact") {
|
|
1374
|
-
return {
|
|
1375
|
-
isCompact: true,
|
|
1376
|
-
originalMessage: trimmed
|
|
1377
|
-
};
|
|
1378
|
-
}
|
|
1379
|
-
if (trimmed.startsWith("/compact ")) {
|
|
1380
|
-
return {
|
|
1381
|
-
isCompact: true,
|
|
1382
|
-
originalMessage: trimmed
|
|
1383
|
-
};
|
|
1384
|
-
}
|
|
1385
|
-
return {
|
|
1386
|
-
isCompact: false,
|
|
1387
|
-
originalMessage: message
|
|
1388
1255
|
};
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1256
|
+
const completeSyntheticTurn = () => {
|
|
1257
|
+
session.client.sendAgentMessage("claude", {
|
|
1258
|
+
type: "task_complete",
|
|
1259
|
+
id: node_crypto.randomUUID()
|
|
1260
|
+
});
|
|
1394
1261
|
};
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
type: "clear"
|
|
1408
|
-
};
|
|
1409
|
-
}
|
|
1410
|
-
return {
|
|
1411
|
-
type: null
|
|
1262
|
+
const handleClearCommand = async () => {
|
|
1263
|
+
api.logger.debug("[ClaudeACP] /clear command received - resetting runtime and local history");
|
|
1264
|
+
conversationHistory.clear();
|
|
1265
|
+
shouldInjectHistoryOnNextSession = false;
|
|
1266
|
+
await disposeRuntimeHandle();
|
|
1267
|
+
session.clearSessionId();
|
|
1268
|
+
currentModeHash = null;
|
|
1269
|
+
permissionHandler.reset();
|
|
1270
|
+
selectionHandler.reset();
|
|
1271
|
+
resetTurnState();
|
|
1272
|
+
emitStatusMessage("Context was reset");
|
|
1273
|
+
completeSyntheticTurn();
|
|
1412
1274
|
};
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
/**
|
|
1441
|
-
* Mark the iterable as complete
|
|
1442
|
-
*/
|
|
1443
|
-
end() {
|
|
1444
|
-
if (this.isDone) {
|
|
1445
|
-
return;
|
|
1446
|
-
}
|
|
1447
|
-
this.isDone = true;
|
|
1448
|
-
this.cleanup();
|
|
1275
|
+
const handleSwitchToLocal = async () => {
|
|
1276
|
+
const message = "Daemon-spawned Claude ACP sessions stay in remote mode.";
|
|
1277
|
+
api.logger.debug("[ClaudeACP] Ignoring switch request because daemon sessions are remote-only");
|
|
1278
|
+
emitStatusMessage(message);
|
|
1279
|
+
};
|
|
1280
|
+
const handleAbort = async () => {
|
|
1281
|
+
api.logger.debug("[ClaudeACP] Abort requested - stopping current task");
|
|
1282
|
+
await abortActiveTurn();
|
|
1283
|
+
};
|
|
1284
|
+
if (hasTTY) {
|
|
1285
|
+
console.clear();
|
|
1286
|
+
inkInstance = ink.render(React.createElement(RemoteModeDisplay, {
|
|
1287
|
+
messageBuffer,
|
|
1288
|
+
logPath: process.env.DEBUG ? session.logPath : void 0,
|
|
1289
|
+
onExit: async () => {
|
|
1290
|
+
shouldExit = true;
|
|
1291
|
+
await handleAbort();
|
|
1292
|
+
},
|
|
1293
|
+
onSwitchToLocal: () => {
|
|
1294
|
+
void handleSwitchToLocal();
|
|
1295
|
+
}
|
|
1296
|
+
}), {
|
|
1297
|
+
exitOnCtrlC: false,
|
|
1298
|
+
patchConsole: false
|
|
1299
|
+
});
|
|
1449
1300
|
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
if (this.isDone) {
|
|
1455
|
-
return;
|
|
1301
|
+
if (hasTTY) {
|
|
1302
|
+
process.stdin.resume();
|
|
1303
|
+
if (process.stdin.isTTY) {
|
|
1304
|
+
process.stdin.setRawMode(true);
|
|
1456
1305
|
}
|
|
1457
|
-
|
|
1458
|
-
this.isDone = true;
|
|
1459
|
-
this.cleanup();
|
|
1306
|
+
process.stdin.setEncoding("utf8");
|
|
1460
1307
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
if (
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1308
|
+
session.client.rpcHandlerManager.registerHandler("abort", handleAbort);
|
|
1309
|
+
session.client.rpcHandlerManager.registerHandler("switch", handleSwitchToLocal);
|
|
1310
|
+
try {
|
|
1311
|
+
while (!shouldExit) {
|
|
1312
|
+
let message = pending;
|
|
1313
|
+
pending = null;
|
|
1314
|
+
if (!message) {
|
|
1315
|
+
const waitSignal = abortController.signal;
|
|
1316
|
+
const batch = await session.queue.waitForMessagesAndGetAsString(waitSignal);
|
|
1317
|
+
if (!batch) {
|
|
1318
|
+
if (waitSignal.aborted && !shouldExit) {
|
|
1319
|
+
continue;
|
|
1320
|
+
}
|
|
1321
|
+
break;
|
|
1322
|
+
}
|
|
1323
|
+
message = batch;
|
|
1324
|
+
}
|
|
1325
|
+
if (!message) {
|
|
1326
|
+
break;
|
|
1327
|
+
}
|
|
1328
|
+
if (runtimeHandle && currentModeHash && message.hash !== currentModeHash) {
|
|
1329
|
+
queueHistoryInjectionForRestart("Starting new Claude ACP session (execution settings changed)...");
|
|
1330
|
+
await disposeRuntimeHandle();
|
|
1331
|
+
session.clearSessionId();
|
|
1332
|
+
currentModeHash = null;
|
|
1333
|
+
pending = message;
|
|
1334
|
+
permissionHandler.reset();
|
|
1335
|
+
selectionHandler.reset();
|
|
1336
|
+
resetTurnState();
|
|
1337
|
+
continue;
|
|
1338
|
+
}
|
|
1339
|
+
currentModeHash = message.hash;
|
|
1340
|
+
readyAlreadySent = false;
|
|
1341
|
+
const specialCommand = parseSpecialCommand(message.message);
|
|
1342
|
+
if (specialCommand.type === "clear") {
|
|
1343
|
+
await handleClearCommand();
|
|
1344
|
+
if (!shouldExit && !pending && session.queue.size() === 0 && !readyAlreadySent) {
|
|
1345
|
+
sendReady();
|
|
1346
|
+
readyAlreadySent = true;
|
|
1347
|
+
}
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
permissionHandler.setPermissionMode(message.mode.permissionMode);
|
|
1351
|
+
messageBuffer.addMessage(message.message, "user");
|
|
1352
|
+
let shouldClearHistoryAfterTurn = false;
|
|
1353
|
+
try {
|
|
1354
|
+
const activeRuntimeHandle = runtimeHandle ?? await createRuntimeHandle(message.mode);
|
|
1355
|
+
let promptToSend = message.message;
|
|
1356
|
+
if (shouldInjectHistoryOnNextSession && conversationHistory.hasHistory()) {
|
|
1357
|
+
const historyContext = conversationHistory.getContextForNewSession(
|
|
1358
|
+
"Continue from the prior Claude ACP session using the conversation below as context."
|
|
1359
|
+
);
|
|
1360
|
+
promptToSend = historyContext + promptToSend;
|
|
1361
|
+
api.logger.debug(`[ClaudeACP] Injected conversation history context (${historyContext.length} chars)`);
|
|
1362
|
+
}
|
|
1363
|
+
if (specialCommand.type === "compact") {
|
|
1364
|
+
emitStatusMessage("Compaction started");
|
|
1365
|
+
}
|
|
1366
|
+
conversationHistory.addUserMessage(message.message);
|
|
1367
|
+
await activeRuntimeHandle.sendPrompt(promptToSend);
|
|
1368
|
+
await registerKillSessionHandler.waitForResponseCompleteWithAbort(activeRuntimeHandle.backend, abortController.signal);
|
|
1369
|
+
shouldInjectHistoryOnNextSession = false;
|
|
1370
|
+
shouldClearHistoryAfterTurn = specialCommand.type === "compact";
|
|
1371
|
+
} catch (error) {
|
|
1372
|
+
api.logger.warn("[ClaudeACP] Error in Claude ACP session:", error);
|
|
1373
|
+
const isAbortError = error instanceof Error && error.name === "AbortError";
|
|
1374
|
+
const isExpectedInterruption = isAbortError || abortController.signal.aborted || shouldExit;
|
|
1375
|
+
if (isExpectedInterruption) {
|
|
1376
|
+
session.client.sendAgentMessage("claude", {
|
|
1377
|
+
type: "turn_aborted",
|
|
1378
|
+
id: node_crypto.randomUUID()
|
|
1379
|
+
});
|
|
1380
|
+
emitStatusMessage("Aborted by user");
|
|
1381
|
+
} else {
|
|
1382
|
+
const errorMessage = normalizeClaudeBackendError(error);
|
|
1383
|
+
emitUserVisibleErrorMessage(errorMessage);
|
|
1384
|
+
if (conversationHistory.hasHistory()) {
|
|
1385
|
+
shouldInjectHistoryOnNextSession = true;
|
|
1386
|
+
}
|
|
1387
|
+
await disposeRuntimeHandle();
|
|
1388
|
+
session.clearSessionId();
|
|
1389
|
+
currentModeHash = null;
|
|
1390
|
+
}
|
|
1391
|
+
} finally {
|
|
1392
|
+
emitFinalAssistantMessage();
|
|
1393
|
+
if (shouldClearHistoryAfterTurn) {
|
|
1394
|
+
conversationHistory.clear();
|
|
1395
|
+
emitStatusMessage("Compaction completed");
|
|
1396
|
+
}
|
|
1397
|
+
if (!shouldExit) {
|
|
1398
|
+
session.client.sendAgentMessage("claude", {
|
|
1399
|
+
type: "task_complete",
|
|
1400
|
+
id: node_crypto.randomUUID()
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
permissionHandler.reset();
|
|
1404
|
+
selectionHandler.reset();
|
|
1405
|
+
resetTurnState();
|
|
1406
|
+
if (!shouldExit && !pending && session.queue.size() === 0 && !readyAlreadySent) {
|
|
1407
|
+
sendReady();
|
|
1408
|
+
readyAlreadySent = true;
|
|
1409
|
+
}
|
|
1471
1410
|
}
|
|
1472
1411
|
}
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1412
|
+
} finally {
|
|
1413
|
+
await disposeRuntimeHandle();
|
|
1414
|
+
permissionHandler.reset();
|
|
1415
|
+
selectionHandler.reset();
|
|
1416
|
+
if (process.stdin.isTTY) {
|
|
1417
|
+
try {
|
|
1418
|
+
process.stdin.setRawMode(false);
|
|
1419
|
+
} catch {
|
|
1420
|
+
}
|
|
1480
1421
|
}
|
|
1481
|
-
if (
|
|
1482
|
-
|
|
1483
|
-
|
|
1422
|
+
if (hasTTY) {
|
|
1423
|
+
try {
|
|
1424
|
+
process.stdin.pause();
|
|
1425
|
+
} catch {
|
|
1484
1426
|
}
|
|
1485
|
-
return { done: true, value: void 0 };
|
|
1486
1427
|
}
|
|
1487
|
-
|
|
1488
|
-
this.waiters.push({ resolve, reject });
|
|
1428
|
+
session.client.rpcHandlerManager.registerHandler("abort", async () => {
|
|
1489
1429
|
});
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
async return(_value) {
|
|
1495
|
-
this.end();
|
|
1496
|
-
return { done: true, value: void 0 };
|
|
1497
|
-
}
|
|
1498
|
-
/**
|
|
1499
|
-
* AsyncIterableIterator throw implementation
|
|
1500
|
-
*/
|
|
1501
|
-
async throw(e) {
|
|
1502
|
-
this.setError(e instanceof Error ? e : new Error(String(e)));
|
|
1503
|
-
throw this.error;
|
|
1504
|
-
}
|
|
1505
|
-
/**
|
|
1506
|
-
* Make this iterable
|
|
1507
|
-
*/
|
|
1508
|
-
[Symbol.asyncIterator]() {
|
|
1509
|
-
if (this.started) {
|
|
1510
|
-
throw new Error("PushableAsyncIterable can only be iterated once");
|
|
1430
|
+
session.client.rpcHandlerManager.registerHandler("switch", async () => {
|
|
1431
|
+
});
|
|
1432
|
+
if (inkInstance) {
|
|
1433
|
+
inkInstance.unmount();
|
|
1511
1434
|
}
|
|
1512
|
-
|
|
1513
|
-
return this;
|
|
1514
|
-
}
|
|
1515
|
-
/**
|
|
1516
|
-
* Check if the iterable is done
|
|
1517
|
-
*/
|
|
1518
|
-
get done() {
|
|
1519
|
-
return this.isDone;
|
|
1520
|
-
}
|
|
1521
|
-
/**
|
|
1522
|
-
* Check if the iterable has an error
|
|
1523
|
-
*/
|
|
1524
|
-
get hasError() {
|
|
1525
|
-
return this.error !== null;
|
|
1526
|
-
}
|
|
1527
|
-
/**
|
|
1528
|
-
* Get the current queue size
|
|
1529
|
-
*/
|
|
1530
|
-
get queueSize() {
|
|
1531
|
-
return this.queue.length;
|
|
1532
|
-
}
|
|
1533
|
-
/**
|
|
1534
|
-
* Get the number of waiting consumers
|
|
1535
|
-
*/
|
|
1536
|
-
get waiterCount() {
|
|
1537
|
-
return this.waiters.length;
|
|
1435
|
+
messageBuffer.clear();
|
|
1538
1436
|
}
|
|
1437
|
+
api.logger.debug("[ClaudeACP] Remote launcher returning: exit");
|
|
1438
|
+
return "exit";
|
|
1539
1439
|
}
|
|
1540
1440
|
|
|
1541
1441
|
async function awaitFileExist(file, timeout = 1e4) {
|
|
@@ -1551,58 +1451,6 @@ async function awaitFileExist(file, timeout = 1e4) {
|
|
|
1551
1451
|
return false;
|
|
1552
1452
|
}
|
|
1553
1453
|
|
|
1554
|
-
function getClaudeSettingsPath() {
|
|
1555
|
-
const claudeConfigDir = process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), ".claude");
|
|
1556
|
-
return path.join(claudeConfigDir, "settings.json");
|
|
1557
|
-
}
|
|
1558
|
-
function readClaudeSettings() {
|
|
1559
|
-
try {
|
|
1560
|
-
const settingsPath = getClaudeSettingsPath();
|
|
1561
|
-
if (!fs$1.existsSync(settingsPath)) {
|
|
1562
|
-
api.logger.debug(`[ClaudeSettings] No Claude settings file found at ${settingsPath}`);
|
|
1563
|
-
return null;
|
|
1564
|
-
}
|
|
1565
|
-
const settingsContent = fs$1.readFileSync(settingsPath, "utf-8");
|
|
1566
|
-
const settings = JSON.parse(settingsContent);
|
|
1567
|
-
api.logger.debug(`[ClaudeSettings] Successfully read Claude settings from ${settingsPath}`);
|
|
1568
|
-
api.logger.debug(`[ClaudeSettings] includeCoAuthoredBy: ${settings.includeCoAuthoredBy}`);
|
|
1569
|
-
return settings;
|
|
1570
|
-
} catch (error) {
|
|
1571
|
-
api.logger.debug(`[ClaudeSettings] Error reading Claude settings: ${error}`);
|
|
1572
|
-
return null;
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
function shouldIncludeCoAuthoredBy() {
|
|
1576
|
-
const settings = readClaudeSettings();
|
|
1577
|
-
if (!settings || settings.includeCoAuthoredBy === void 0) {
|
|
1578
|
-
return true;
|
|
1579
|
-
}
|
|
1580
|
-
return settings.includeCoAuthoredBy;
|
|
1581
|
-
}
|
|
1582
|
-
|
|
1583
|
-
const BASE_SYSTEM_PROMPT = (() => index.trimIdent(`
|
|
1584
|
-
Help human.
|
|
1585
|
-
`))();
|
|
1586
|
-
const CO_AUTHORED_CREDITS = (() => index.trimIdent(`
|
|
1587
|
-
When making commit messages, instead of just giving co-credit to Claude, also give credit to Happy like so:
|
|
1588
|
-
|
|
1589
|
-
<main commit message>
|
|
1590
|
-
|
|
1591
|
-
Generated with [Claude Code](https://claude.ai/code)
|
|
1592
|
-
via [Happy](https://happy.engineering)
|
|
1593
|
-
|
|
1594
|
-
Co-Authored-By: Claude <noreply@anthropic.com>
|
|
1595
|
-
Co-Authored-By: Happy <yesreply@happy.engineering>
|
|
1596
|
-
`))();
|
|
1597
|
-
const systemPrompt = (() => {
|
|
1598
|
-
const includeCoAuthored = shouldIncludeCoAuthoredBy();
|
|
1599
|
-
if (includeCoAuthored) {
|
|
1600
|
-
return BASE_SYSTEM_PROMPT + "\n\n" + CO_AUTHORED_CREDITS;
|
|
1601
|
-
} else {
|
|
1602
|
-
return BASE_SYSTEM_PROMPT;
|
|
1603
|
-
}
|
|
1604
|
-
})();
|
|
1605
|
-
|
|
1606
1454
|
async function claudeRemote(opts) {
|
|
1607
1455
|
let startFrom = opts.sessionId;
|
|
1608
1456
|
if (opts.sessionId && !index.claudeCheckSession(opts.sessionId, opts.path, opts.transcriptPath)) {
|
|
@@ -1685,7 +1533,7 @@ async function claudeRemote(opts) {
|
|
|
1685
1533
|
}
|
|
1686
1534
|
}
|
|
1687
1535
|
};
|
|
1688
|
-
let messages = new PushableAsyncIterable();
|
|
1536
|
+
let messages = new index.PushableAsyncIterable();
|
|
1689
1537
|
messages.push({
|
|
1690
1538
|
type: "user",
|
|
1691
1539
|
message: {
|
|
@@ -1693,7 +1541,7 @@ async function claudeRemote(opts) {
|
|
|
1693
1541
|
content: initial.message
|
|
1694
1542
|
}
|
|
1695
1543
|
});
|
|
1696
|
-
const response = query({
|
|
1544
|
+
const response = index.query({
|
|
1697
1545
|
prompt: messages,
|
|
1698
1546
|
options: sdkOptions
|
|
1699
1547
|
});
|
|
@@ -1749,7 +1597,7 @@ async function claudeRemote(opts) {
|
|
|
1749
1597
|
}
|
|
1750
1598
|
}
|
|
1751
1599
|
} catch (e) {
|
|
1752
|
-
if (e instanceof AbortError) {
|
|
1600
|
+
if (e instanceof index.AbortError) {
|
|
1753
1601
|
api.logger.debug(`[claudeRemote] Aborted`);
|
|
1754
1602
|
} else {
|
|
1755
1603
|
throw e;
|
|
@@ -1806,16 +1654,6 @@ function getToolName(toolName) {
|
|
|
1806
1654
|
return toTitleCase(toolName);
|
|
1807
1655
|
}
|
|
1808
1656
|
|
|
1809
|
-
function getToolDescriptor(toolName) {
|
|
1810
|
-
if (toolName === "exit_plan_mode" || toolName === "ExitPlanMode") {
|
|
1811
|
-
return { edit: false, exitPlan: true };
|
|
1812
|
-
}
|
|
1813
|
-
if (toolName === "Edit" || toolName === "MultiEdit" || toolName === "Write" || toolName === "NotebookEdit") {
|
|
1814
|
-
return { edit: true, exitPlan: false };
|
|
1815
|
-
}
|
|
1816
|
-
return { edit: false, exitPlan: false };
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
1657
|
class PermissionHandler {
|
|
1820
1658
|
toolCalls = [];
|
|
1821
1659
|
responses = /* @__PURE__ */ new Map();
|
|
@@ -2832,7 +2670,7 @@ async function claudeRemoteLauncher(session, options = {}) {
|
|
|
2832
2670
|
previousSessionId = session.sessionId;
|
|
2833
2671
|
const controller = new AbortController();
|
|
2834
2672
|
abortController = controller;
|
|
2835
|
-
abortFuture = new Future();
|
|
2673
|
+
abortFuture = new index.Future();
|
|
2836
2674
|
let modeHash = null;
|
|
2837
2675
|
let mode = null;
|
|
2838
2676
|
try {
|
|
@@ -2968,7 +2806,7 @@ async function loop(opts) {
|
|
|
2968
2806
|
jsRuntime: opts.jsRuntime
|
|
2969
2807
|
});
|
|
2970
2808
|
opts.onSessionReady?.(session);
|
|
2971
|
-
return await
|
|
2809
|
+
return await ProviderSelectionHandler.runModeLoop({
|
|
2972
2810
|
startingMode: opts.startingMode ?? "local",
|
|
2973
2811
|
onIteration: (mode) => {
|
|
2974
2812
|
api.logger.debug(`[loop] Iteration with mode: ${mode}`);
|
|
@@ -2985,9 +2823,7 @@ async function loop(opts) {
|
|
|
2985
2823
|
return { type: "exit", value: result.code };
|
|
2986
2824
|
},
|
|
2987
2825
|
remote: async () => {
|
|
2988
|
-
const reason = await claudeRemoteLauncher(session
|
|
2989
|
-
allowSwitchToLocal: opts.startedBy !== "daemon"
|
|
2990
|
-
});
|
|
2826
|
+
const reason = opts.startedBy === "daemon" ? await claudeAcpRemoteLauncher(session) : await claudeRemoteLauncher(session);
|
|
2991
2827
|
if (reason === "switch") {
|
|
2992
2828
|
return { type: "switch", mode: "local" };
|
|
2993
2829
|
}
|
|
@@ -3001,7 +2837,7 @@ async function extractSDKMetadata() {
|
|
|
3001
2837
|
const abortController = new AbortController();
|
|
3002
2838
|
try {
|
|
3003
2839
|
api.logger.debug("[metadataExtractor] Starting SDK metadata extraction");
|
|
3004
|
-
const sdkQuery = query({
|
|
2840
|
+
const sdkQuery = index.query({
|
|
3005
2841
|
prompt: "hello",
|
|
3006
2842
|
options: {
|
|
3007
2843
|
allowedTools: ["Bash(echo)"],
|