coding-agent-adapters 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +589 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +106 -6
- package/dist/index.d.ts +106 -6
- package/dist/index.js +587 -7
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var promises = require('fs/promises');
|
|
4
4
|
var path = require('path');
|
|
5
|
-
var
|
|
5
|
+
var adapterTypes = require('adapter-types');
|
|
6
6
|
|
|
7
7
|
// src/base-coding-adapter.ts
|
|
8
8
|
|
|
@@ -337,6 +337,16 @@ function generateAiderApprovalConfig(preset) {
|
|
|
337
337
|
summary: `Aider: ${def.description}`
|
|
338
338
|
};
|
|
339
339
|
}
|
|
340
|
+
function generateHermesApprovalConfig(preset) {
|
|
341
|
+
const def = getPresetDefinition(preset);
|
|
342
|
+
return {
|
|
343
|
+
preset,
|
|
344
|
+
cliFlags: [],
|
|
345
|
+
workspaceFiles: [],
|
|
346
|
+
envVars: {},
|
|
347
|
+
summary: `Hermes Agent: ${def.description}`
|
|
348
|
+
};
|
|
349
|
+
}
|
|
340
350
|
function generateApprovalConfig(adapterType, preset) {
|
|
341
351
|
switch (adapterType) {
|
|
342
352
|
case "claude":
|
|
@@ -347,6 +357,8 @@ function generateApprovalConfig(adapterType, preset) {
|
|
|
347
357
|
return generateCodexApprovalConfig(preset);
|
|
348
358
|
case "aider":
|
|
349
359
|
return generateAiderApprovalConfig(preset);
|
|
360
|
+
case "hermes":
|
|
361
|
+
return generateHermesApprovalConfig(preset);
|
|
350
362
|
default:
|
|
351
363
|
throw new Error(`Unknown adapter type: ${adapterType}`);
|
|
352
364
|
}
|
|
@@ -363,7 +375,7 @@ function getPresetDefinition(preset) {
|
|
|
363
375
|
}
|
|
364
376
|
|
|
365
377
|
// src/base-coding-adapter.ts
|
|
366
|
-
var BaseCodingAdapter = class extends
|
|
378
|
+
var BaseCodingAdapter = class extends adapterTypes.BaseCLIAdapter {
|
|
367
379
|
/**
|
|
368
380
|
* Coding agent CLIs use TUI menus that require arrow-key navigation.
|
|
369
381
|
*/
|
|
@@ -424,6 +436,13 @@ var BaseCodingAdapter = class extends ptyManager.BaseCLIAdapter {
|
|
|
424
436
|
result = result.replace(/ {2,}/g, " ");
|
|
425
437
|
return result;
|
|
426
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* Generate hook telemetry protocol configuration.
|
|
441
|
+
* Returns null by default — only Claude adapter supports hooks.
|
|
442
|
+
*/
|
|
443
|
+
getHookTelemetryProtocol(_options) {
|
|
444
|
+
return null;
|
|
445
|
+
}
|
|
427
446
|
/**
|
|
428
447
|
* Override detectExit to include installation instructions
|
|
429
448
|
*/
|
|
@@ -549,6 +568,7 @@ Docs: ${this.installation.docsUrl}`
|
|
|
549
568
|
};
|
|
550
569
|
|
|
551
570
|
// src/claude-adapter.ts
|
|
571
|
+
var CLAUDE_HOOK_MARKER_PREFIX = "PARALLAX_CLAUDE_HOOK";
|
|
552
572
|
var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
553
573
|
adapterType = "claude";
|
|
554
574
|
displayName = "Claude Code";
|
|
@@ -586,7 +606,8 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
586
606
|
responseType: "keys",
|
|
587
607
|
keys: ["enter"],
|
|
588
608
|
description: "Auto-approve tool permission prompts (file access, MCP tools, etc.)",
|
|
589
|
-
safe: true
|
|
609
|
+
safe: true,
|
|
610
|
+
once: true
|
|
590
611
|
},
|
|
591
612
|
{
|
|
592
613
|
pattern: /update available.*\[y\/n\]/i,
|
|
@@ -695,6 +716,7 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
695
716
|
getEnv(config) {
|
|
696
717
|
const env = {};
|
|
697
718
|
const credentials = this.getCredentials(config);
|
|
719
|
+
const adapterConfig = config.adapterConfig;
|
|
698
720
|
if (credentials.anthropicKey) {
|
|
699
721
|
env.ANTHROPIC_API_KEY = credentials.anthropicKey;
|
|
700
722
|
}
|
|
@@ -704,8 +726,110 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
704
726
|
if (!this.isInteractive(config)) {
|
|
705
727
|
env.CLAUDE_CODE_DISABLE_INTERACTIVE = "true";
|
|
706
728
|
}
|
|
729
|
+
if (adapterConfig?.claudeHookTelemetry) {
|
|
730
|
+
env.PARALLAX_CLAUDE_HOOK_TELEMETRY = "1";
|
|
731
|
+
env.PARALLAX_CLAUDE_HOOK_MARKER_PREFIX = adapterConfig.claudeHookMarkerPrefix || CLAUDE_HOOK_MARKER_PREFIX;
|
|
732
|
+
}
|
|
707
733
|
return env;
|
|
708
734
|
}
|
|
735
|
+
getHookTelemetryProtocol(options) {
|
|
736
|
+
if (options?.httpUrl) {
|
|
737
|
+
const httpHookBase = {
|
|
738
|
+
type: "http",
|
|
739
|
+
url: options.httpUrl,
|
|
740
|
+
timeout: 5
|
|
741
|
+
};
|
|
742
|
+
if (options.sessionId) {
|
|
743
|
+
httpHookBase.headers = { "X-Parallax-Session-Id": options.sessionId };
|
|
744
|
+
}
|
|
745
|
+
const hookEntry2 = [{ matcher: "", hooks: [{ ...httpHookBase }] }];
|
|
746
|
+
const hookEntryNoMatcher = [{ hooks: [{ ...httpHookBase }] }];
|
|
747
|
+
const settingsHooks2 = {
|
|
748
|
+
PermissionRequest: hookEntryNoMatcher,
|
|
749
|
+
PreToolUse: hookEntry2,
|
|
750
|
+
Stop: hookEntryNoMatcher,
|
|
751
|
+
Notification: hookEntry2,
|
|
752
|
+
TaskCompleted: hookEntryNoMatcher
|
|
753
|
+
};
|
|
754
|
+
return {
|
|
755
|
+
markerPrefix: "",
|
|
756
|
+
scriptPath: "",
|
|
757
|
+
scriptContent: "",
|
|
758
|
+
settingsHooks: settingsHooks2
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
const markerPrefix = options?.markerPrefix || CLAUDE_HOOK_MARKER_PREFIX;
|
|
762
|
+
const scriptPath = options?.scriptPath || ".claude/hooks/parallax-hook-telemetry.sh";
|
|
763
|
+
const scriptCommand = `"${"$"}CLAUDE_PROJECT_DIR"/${scriptPath}`;
|
|
764
|
+
const hookEntry = [{ matcher: "", hooks: [{ type: "command", command: scriptCommand }] }];
|
|
765
|
+
const settingsHooks = {
|
|
766
|
+
Notification: hookEntry,
|
|
767
|
+
PreToolUse: hookEntry,
|
|
768
|
+
TaskCompleted: hookEntry,
|
|
769
|
+
SessionEnd: hookEntry
|
|
770
|
+
};
|
|
771
|
+
const scriptContent = `#!/usr/bin/env bash
|
|
772
|
+
set -euo pipefail
|
|
773
|
+
|
|
774
|
+
INPUT="$(cat)"
|
|
775
|
+
[ -z "${"$"}INPUT" ] && exit 0
|
|
776
|
+
|
|
777
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
778
|
+
exit 0
|
|
779
|
+
fi
|
|
780
|
+
|
|
781
|
+
EVENT="$(printf '%s' "${"$"}INPUT" | jq -r '.hook_event_name // empty')"
|
|
782
|
+
[ -z "${"$"}EVENT" ] && exit 0
|
|
783
|
+
|
|
784
|
+
NOTIFICATION_TYPE="$(printf '%s' "${"$"}INPUT" | jq -r '.notification_type // empty')"
|
|
785
|
+
TOOL_NAME="$(printf '%s' "${"$"}INPUT" | jq -r '.tool_name // empty')"
|
|
786
|
+
MESSAGE="$(printf '%s' "${"$"}INPUT" | jq -r '.message // empty')"
|
|
787
|
+
|
|
788
|
+
printf '%s ' '${markerPrefix}'
|
|
789
|
+
jq -nc --arg event "${"$"}EVENT" --arg notification_type "${"$"}NOTIFICATION_TYPE" --arg tool_name "${"$"}TOOL_NAME" --arg message "${"$"}MESSAGE" '({event: $event}
|
|
790
|
+
+ (if $notification_type != "" then {notification_type: $notification_type} else {} end)
|
|
791
|
+
+ (if $tool_name != "" then {tool_name: $tool_name} else {} end)
|
|
792
|
+
+ (if $message != "" then {message: $message} else {} end))'
|
|
793
|
+
`;
|
|
794
|
+
return {
|
|
795
|
+
markerPrefix,
|
|
796
|
+
scriptPath,
|
|
797
|
+
scriptContent,
|
|
798
|
+
settingsHooks
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
getHookMarkers(output) {
|
|
802
|
+
const markers = [];
|
|
803
|
+
const markerRegex = /(?:^|\n)\s*([A-Z0-9_]+)\s+(\{[^\n\r]+\})/g;
|
|
804
|
+
let match;
|
|
805
|
+
while ((match = markerRegex.exec(output)) !== null) {
|
|
806
|
+
const markerToken = match[1];
|
|
807
|
+
if (!markerToken.includes("CLAUDE_HOOK")) {
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
const payload = match[2];
|
|
811
|
+
try {
|
|
812
|
+
const parsed = JSON.parse(payload);
|
|
813
|
+
const event = typeof parsed.event === "string" ? parsed.event : void 0;
|
|
814
|
+
if (!event) continue;
|
|
815
|
+
markers.push({
|
|
816
|
+
event,
|
|
817
|
+
notification_type: typeof parsed.notification_type === "string" ? parsed.notification_type : void 0,
|
|
818
|
+
tool_name: typeof parsed.tool_name === "string" ? parsed.tool_name : void 0,
|
|
819
|
+
message: typeof parsed.message === "string" ? parsed.message : void 0
|
|
820
|
+
});
|
|
821
|
+
} catch {
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
return markers;
|
|
825
|
+
}
|
|
826
|
+
getLatestHookMarker(output) {
|
|
827
|
+
const markers = this.getHookMarkers(output);
|
|
828
|
+
return markers.length > 0 ? markers[markers.length - 1] : null;
|
|
829
|
+
}
|
|
830
|
+
stripHookMarkers(output) {
|
|
831
|
+
return output.replace(/(?:^|\n)\s*[A-Z0-9_]*CLAUDE_HOOK[A-Z0-9_]*\s+\{[^\n\r]+\}\s*/g, "\n");
|
|
832
|
+
}
|
|
709
833
|
detectLogin(output) {
|
|
710
834
|
const stripped = this.stripAnsi(output);
|
|
711
835
|
if (stripped.includes("Not logged in") || stripped.includes("Please run /login") || stripped.includes("please log in") || stripped.includes("run /login")) {
|
|
@@ -738,6 +862,7 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
738
862
|
*/
|
|
739
863
|
detectBlockingPrompt(output) {
|
|
740
864
|
const stripped = this.stripAnsi(output);
|
|
865
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
741
866
|
const loginDetection = this.detectLogin(output);
|
|
742
867
|
if (loginDetection.required) {
|
|
743
868
|
return {
|
|
@@ -749,6 +874,27 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
749
874
|
instructions: loginDetection.instructions
|
|
750
875
|
};
|
|
751
876
|
}
|
|
877
|
+
if (marker?.event === "Notification") {
|
|
878
|
+
if (marker.notification_type === "permission_prompt") {
|
|
879
|
+
return {
|
|
880
|
+
detected: true,
|
|
881
|
+
type: "permission",
|
|
882
|
+
prompt: marker.message || "Claude permission prompt",
|
|
883
|
+
suggestedResponse: "keys:enter",
|
|
884
|
+
canAutoRespond: true,
|
|
885
|
+
instructions: "Claude is waiting for permission approval"
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
if (marker.notification_type === "elicitation_dialog") {
|
|
889
|
+
return {
|
|
890
|
+
detected: true,
|
|
891
|
+
type: "tool_wait",
|
|
892
|
+
prompt: marker.message || "Claude elicitation dialog",
|
|
893
|
+
canAutoRespond: false,
|
|
894
|
+
instructions: "Claude is waiting for required user input"
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
}
|
|
752
898
|
if (/how is claude doing this session\?\s*\(optional\)|1:\s*bad\s+2:\s*fine\s+3:\s*good\s+0:\s*dismiss/i.test(stripped)) {
|
|
753
899
|
return {
|
|
754
900
|
detected: true,
|
|
@@ -847,7 +993,11 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
847
993
|
*/
|
|
848
994
|
detectLoading(output) {
|
|
849
995
|
const stripped = this.stripAnsi(output);
|
|
996
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
850
997
|
const tail = stripped.slice(-500);
|
|
998
|
+
if (marker?.event === "PreToolUse") {
|
|
999
|
+
return true;
|
|
1000
|
+
}
|
|
851
1001
|
if (/esc\s+to\s+interrupt/i.test(tail)) {
|
|
852
1002
|
return true;
|
|
853
1003
|
}
|
|
@@ -868,7 +1018,14 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
868
1018
|
*/
|
|
869
1019
|
detectToolRunning(output) {
|
|
870
1020
|
const stripped = this.stripAnsi(output);
|
|
1021
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
871
1022
|
const tail = stripped.slice(-500);
|
|
1023
|
+
if (marker?.event === "PreToolUse" && marker.tool_name) {
|
|
1024
|
+
return {
|
|
1025
|
+
toolName: marker.tool_name.toLowerCase(),
|
|
1026
|
+
description: `${marker.tool_name} (hook)`
|
|
1027
|
+
};
|
|
1028
|
+
}
|
|
872
1029
|
const contextualMatch = tail.match(/Claude\s+in\s+([A-Za-z0-9._-]+)\s*\[(\w+_tool)\]/i);
|
|
873
1030
|
if (contextualMatch) {
|
|
874
1031
|
const appName = contextualMatch[1];
|
|
@@ -897,7 +1054,14 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
897
1054
|
*/
|
|
898
1055
|
detectTaskComplete(output) {
|
|
899
1056
|
const stripped = this.stripAnsi(output);
|
|
1057
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
900
1058
|
if (!stripped.trim()) return false;
|
|
1059
|
+
if (marker?.event === "TaskCompleted") {
|
|
1060
|
+
return true;
|
|
1061
|
+
}
|
|
1062
|
+
if (marker?.event === "Notification" && marker.notification_type === "idle_prompt") {
|
|
1063
|
+
return true;
|
|
1064
|
+
}
|
|
901
1065
|
if (/trust.*directory|do you want to|needs? your permission/i.test(stripped)) {
|
|
902
1066
|
return false;
|
|
903
1067
|
}
|
|
@@ -914,7 +1078,16 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
914
1078
|
}
|
|
915
1079
|
detectReady(output) {
|
|
916
1080
|
const stripped = this.stripAnsi(output);
|
|
1081
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
917
1082
|
if (!stripped.trim()) return false;
|
|
1083
|
+
if (marker?.event === "Notification") {
|
|
1084
|
+
if (marker.notification_type === "permission_prompt" || marker.notification_type === "elicitation_dialog") {
|
|
1085
|
+
return false;
|
|
1086
|
+
}
|
|
1087
|
+
if (marker.notification_type === "idle_prompt") {
|
|
1088
|
+
return true;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
918
1091
|
if (/trust.*directory|do you want to|needs? your permission/i.test(stripped)) {
|
|
919
1092
|
return false;
|
|
920
1093
|
}
|
|
@@ -925,7 +1098,8 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
925
1098
|
return hasConversationalReadyText || hasLegacyPrompt || hasShortcutsHint;
|
|
926
1099
|
}
|
|
927
1100
|
parseOutput(output) {
|
|
928
|
-
const
|
|
1101
|
+
const withoutHookMarkers = this.stripHookMarkers(output);
|
|
1102
|
+
const stripped = this.stripAnsi(withoutHookMarkers);
|
|
929
1103
|
const isComplete = this.isResponseComplete(stripped);
|
|
930
1104
|
if (!isComplete) {
|
|
931
1105
|
return null;
|
|
@@ -948,9 +1122,18 @@ var ClaudeAdapter = class extends BaseCodingAdapter {
|
|
|
948
1122
|
getHealthCheckCommand() {
|
|
949
1123
|
return "claude --version";
|
|
950
1124
|
}
|
|
1125
|
+
detectExit(output) {
|
|
1126
|
+
const stripped = this.stripAnsi(output);
|
|
1127
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
1128
|
+
if (marker?.event === "SessionEnd") {
|
|
1129
|
+
return { exited: true, code: 0 };
|
|
1130
|
+
}
|
|
1131
|
+
return super.detectExit(output);
|
|
1132
|
+
}
|
|
951
1133
|
};
|
|
952
1134
|
|
|
953
1135
|
// src/gemini-adapter.ts
|
|
1136
|
+
var GEMINI_HOOK_MARKER_PREFIX = "PARALLAX_GEMINI_HOOK";
|
|
954
1137
|
var GeminiAdapter = class extends BaseCodingAdapter {
|
|
955
1138
|
adapterType = "gemini";
|
|
956
1139
|
displayName = "Google Gemini";
|
|
@@ -1050,6 +1233,7 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1050
1233
|
getEnv(config) {
|
|
1051
1234
|
const env = {};
|
|
1052
1235
|
const credentials = this.getCredentials(config);
|
|
1236
|
+
const adapterConfig = config.adapterConfig;
|
|
1053
1237
|
if (credentials.googleKey) {
|
|
1054
1238
|
env.GOOGLE_API_KEY = credentials.googleKey;
|
|
1055
1239
|
env.GEMINI_API_KEY = credentials.googleKey;
|
|
@@ -1060,8 +1244,115 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1060
1244
|
if (!this.isInteractive(config)) {
|
|
1061
1245
|
env.NO_COLOR = "1";
|
|
1062
1246
|
}
|
|
1247
|
+
if (adapterConfig?.geminiHookTelemetry) {
|
|
1248
|
+
env.PARALLAX_GEMINI_HOOK_TELEMETRY = "1";
|
|
1249
|
+
env.PARALLAX_GEMINI_HOOK_MARKER_PREFIX = adapterConfig.geminiHookMarkerPrefix || GEMINI_HOOK_MARKER_PREFIX;
|
|
1250
|
+
}
|
|
1063
1251
|
return env;
|
|
1064
1252
|
}
|
|
1253
|
+
getHookTelemetryProtocol(options) {
|
|
1254
|
+
if (options?.httpUrl) {
|
|
1255
|
+
const sessionHeader = options.sessionId ? ` -H 'X-Parallax-Session-Id: ${options.sessionId}'` : "";
|
|
1256
|
+
const curlCommand = `bash -c 'curl -sf -X POST "${options.httpUrl}" -H "Content-Type: application/json"${sessionHeader} -d @- --max-time 4 2>/dev/null || echo "{\\"continue\\":true}"'`;
|
|
1257
|
+
const hookEntry2 = [{ matcher: "", hooks: [{ type: "command", command: curlCommand, timeout: 5e3 }] }];
|
|
1258
|
+
const hookEntryNoMatcher = [{ hooks: [{ type: "command", command: curlCommand, timeout: 5e3 }] }];
|
|
1259
|
+
const settingsHooks2 = {
|
|
1260
|
+
BeforeTool: hookEntry2,
|
|
1261
|
+
AfterTool: hookEntry2,
|
|
1262
|
+
AfterAgent: hookEntryNoMatcher,
|
|
1263
|
+
SessionEnd: hookEntryNoMatcher,
|
|
1264
|
+
Notification: hookEntry2
|
|
1265
|
+
};
|
|
1266
|
+
return {
|
|
1267
|
+
markerPrefix: "",
|
|
1268
|
+
scriptPath: "",
|
|
1269
|
+
scriptContent: "",
|
|
1270
|
+
settingsHooks: settingsHooks2
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
const markerPrefix = options?.markerPrefix || GEMINI_HOOK_MARKER_PREFIX;
|
|
1274
|
+
const scriptPath = options?.scriptPath || ".gemini/hooks/parallax-hook-telemetry.sh";
|
|
1275
|
+
const scriptCommand = `"${"$"}GEMINI_PROJECT_ROOT"/${scriptPath}`;
|
|
1276
|
+
const hookEntry = [{ matcher: "", hooks: [{ type: "command", command: scriptCommand }] }];
|
|
1277
|
+
const settingsHooks = {
|
|
1278
|
+
Notification: hookEntry,
|
|
1279
|
+
BeforeTool: hookEntry,
|
|
1280
|
+
AfterAgent: hookEntry,
|
|
1281
|
+
SessionEnd: hookEntry
|
|
1282
|
+
};
|
|
1283
|
+
const scriptContent = `#!/usr/bin/env bash
|
|
1284
|
+
set -euo pipefail
|
|
1285
|
+
|
|
1286
|
+
INPUT="$(cat)"
|
|
1287
|
+
[ -z "${"$"}INPUT" ] && exit 0
|
|
1288
|
+
|
|
1289
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
1290
|
+
# Valid no-op response
|
|
1291
|
+
printf '%s
|
|
1292
|
+
' '{"continue":true}'
|
|
1293
|
+
exit 0
|
|
1294
|
+
fi
|
|
1295
|
+
|
|
1296
|
+
EVENT="$(printf '%s' "${"$"}INPUT" | jq -r '.hookEventName // .hook_event_name // empty')"
|
|
1297
|
+
[ -z "${"$"}EVENT" ] && { printf '%s
|
|
1298
|
+
' '{"continue":true}'; exit 0; }
|
|
1299
|
+
|
|
1300
|
+
NOTIFICATION_TYPE="$(printf '%s' "${"$"}INPUT" | jq -r '.notificationType // .notification_type // empty')"
|
|
1301
|
+
TOOL_NAME="$(printf '%s' "${"$"}INPUT" | jq -r '.toolName // .tool_name // empty')"
|
|
1302
|
+
MESSAGE="$(printf '%s' "${"$"}INPUT" | jq -r '.message // empty')"
|
|
1303
|
+
|
|
1304
|
+
PAYLOAD="$(jq -nc \\
|
|
1305
|
+
--arg event "${"$"}EVENT" \\
|
|
1306
|
+
--arg notification_type "${"$"}NOTIFICATION_TYPE" \\
|
|
1307
|
+
--arg tool_name "${"$"}TOOL_NAME" \\
|
|
1308
|
+
--arg message "${"$"}MESSAGE" \\
|
|
1309
|
+
'({event: $event}
|
|
1310
|
+
+ (if $notification_type != "" then {notification_type: $notification_type} else {} end)
|
|
1311
|
+
+ (if $tool_name != "" then {tool_name: $tool_name} else {} end)
|
|
1312
|
+
+ (if $message != "" then {message: $message} else {} end))')"
|
|
1313
|
+
|
|
1314
|
+
MARKER="${markerPrefix} ${"$"}PAYLOAD"
|
|
1315
|
+
jq -nc --arg m "${"$"}MARKER" '{continue: true, suppressOutput: true, systemMessage: $m}'
|
|
1316
|
+
`;
|
|
1317
|
+
return {
|
|
1318
|
+
markerPrefix,
|
|
1319
|
+
scriptPath,
|
|
1320
|
+
scriptContent,
|
|
1321
|
+
settingsHooks
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
getHookMarkers(output) {
|
|
1325
|
+
const markers = [];
|
|
1326
|
+
const markerRegex = /(?:^|\n)\s*([A-Z0-9_]+)\s+(\{[^\n\r]+\})/g;
|
|
1327
|
+
let match;
|
|
1328
|
+
while ((match = markerRegex.exec(output)) !== null) {
|
|
1329
|
+
const markerToken = match[1];
|
|
1330
|
+
if (!markerToken.includes("GEMINI_HOOK")) {
|
|
1331
|
+
continue;
|
|
1332
|
+
}
|
|
1333
|
+
const payload = match[2];
|
|
1334
|
+
try {
|
|
1335
|
+
const parsed = JSON.parse(payload);
|
|
1336
|
+
const event = typeof parsed.event === "string" ? parsed.event : void 0;
|
|
1337
|
+
if (!event) continue;
|
|
1338
|
+
markers.push({
|
|
1339
|
+
event,
|
|
1340
|
+
notification_type: typeof parsed.notification_type === "string" ? parsed.notification_type : void 0,
|
|
1341
|
+
tool_name: typeof parsed.tool_name === "string" ? parsed.tool_name : void 0,
|
|
1342
|
+
message: typeof parsed.message === "string" ? parsed.message : void 0
|
|
1343
|
+
});
|
|
1344
|
+
} catch {
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
return markers;
|
|
1348
|
+
}
|
|
1349
|
+
getLatestHookMarker(output) {
|
|
1350
|
+
const markers = this.getHookMarkers(output);
|
|
1351
|
+
return markers.length > 0 ? markers[markers.length - 1] : null;
|
|
1352
|
+
}
|
|
1353
|
+
stripHookMarkers(output) {
|
|
1354
|
+
return output.replace(/(?:^|\n)\s*[A-Z0-9_]*GEMINI_HOOK[A-Z0-9_]*\s+\{[^\n\r]+\}\s*/g, "\n");
|
|
1355
|
+
}
|
|
1065
1356
|
detectLogin(output) {
|
|
1066
1357
|
const stripped = this.stripAnsi(output);
|
|
1067
1358
|
if (stripped.includes("API key not found") || /set (?:GOOGLE_API_KEY|GEMINI_API_KEY)/i.test(stripped) || stripped.includes("authentication required") || stripped.includes("Invalid API key") || stripped.includes("API key is not valid")) {
|
|
@@ -1112,6 +1403,17 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1112
1403
|
}
|
|
1113
1404
|
detectBlockingPrompt(output) {
|
|
1114
1405
|
const stripped = this.stripAnsi(output);
|
|
1406
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
1407
|
+
if (marker?.event === "Notification" && marker.notification_type === "ToolPermission") {
|
|
1408
|
+
return {
|
|
1409
|
+
detected: true,
|
|
1410
|
+
type: "permission",
|
|
1411
|
+
prompt: marker.message || "Gemini tool permission",
|
|
1412
|
+
suggestedResponse: "keys:enter",
|
|
1413
|
+
canAutoRespond: true,
|
|
1414
|
+
instructions: "Gemini is asking to allow a tool action"
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1115
1417
|
if (/apply.?this.?change\??/i.test(stripped) || /allow.?execution.?of/i.test(stripped) || /do.?you.?want.?to.?proceed\??/i.test(stripped) || /waiting.?for.?user.?confirmation/i.test(stripped)) {
|
|
1116
1418
|
return {
|
|
1117
1419
|
detected: true,
|
|
@@ -1207,7 +1509,11 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1207
1509
|
*/
|
|
1208
1510
|
detectLoading(output) {
|
|
1209
1511
|
const stripped = this.stripAnsi(output);
|
|
1512
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
1210
1513
|
const tail = stripped.slice(-500);
|
|
1514
|
+
if (marker?.event === "BeforeTool") {
|
|
1515
|
+
return true;
|
|
1516
|
+
}
|
|
1211
1517
|
if (/esc\s+to\s+cancel/i.test(tail)) {
|
|
1212
1518
|
return true;
|
|
1213
1519
|
}
|
|
@@ -1216,6 +1522,17 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1216
1522
|
}
|
|
1217
1523
|
return false;
|
|
1218
1524
|
}
|
|
1525
|
+
detectToolRunning(output) {
|
|
1526
|
+
const stripped = this.stripAnsi(output);
|
|
1527
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
1528
|
+
if (marker?.event === "BeforeTool" && marker.tool_name) {
|
|
1529
|
+
return {
|
|
1530
|
+
toolName: marker.tool_name.toLowerCase(),
|
|
1531
|
+
description: `${marker.tool_name} (hook)`
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
return null;
|
|
1535
|
+
}
|
|
1219
1536
|
/**
|
|
1220
1537
|
* Detect task completion for Gemini CLI.
|
|
1221
1538
|
*
|
|
@@ -1228,6 +1545,10 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1228
1545
|
*/
|
|
1229
1546
|
detectTaskComplete(output) {
|
|
1230
1547
|
const stripped = this.stripAnsi(output);
|
|
1548
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
1549
|
+
if (marker?.event === "AfterAgent") {
|
|
1550
|
+
return true;
|
|
1551
|
+
}
|
|
1231
1552
|
if (/◇\s+Ready/.test(stripped)) {
|
|
1232
1553
|
return true;
|
|
1233
1554
|
}
|
|
@@ -1238,6 +1559,13 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1238
1559
|
}
|
|
1239
1560
|
detectReady(output) {
|
|
1240
1561
|
const stripped = this.stripAnsi(output);
|
|
1562
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
1563
|
+
if (marker?.event === "Notification" && marker.notification_type === "ToolPermission") {
|
|
1564
|
+
return false;
|
|
1565
|
+
}
|
|
1566
|
+
if (marker?.event === "AfterAgent") {
|
|
1567
|
+
return true;
|
|
1568
|
+
}
|
|
1241
1569
|
const hasActiveOverlay = /interactive\s+shell\s+awaiting\s+input|press\s+tab\s+to\s+focus\s+shell/i.test(stripped) || /waiting\s+for\s+user\s+confirmation|apply.?this.?change|allow.?execution|do.?you.?want.?to.?proceed/i.test(stripped) || /do.?you.?want.?to.?continue\s*\([yY]\/[nN]\)\??|are.?you.?sure\??\s*\([yY]\/[nN]\)\??/i.test(stripped) || /enable.?checkpointing.?to.?recover.?your.?session.?after.?a.?crash/i.test(stripped) || /esc\s+to\s+cancel|esc\s+to\s+interrupt/i.test(stripped);
|
|
1242
1570
|
if (hasActiveOverlay) {
|
|
1243
1571
|
return false;
|
|
@@ -1255,7 +1583,8 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1255
1583
|
/gemini>\s*$/i.test(stripped);
|
|
1256
1584
|
}
|
|
1257
1585
|
parseOutput(output) {
|
|
1258
|
-
const
|
|
1586
|
+
const withoutHookMarkers = this.stripHookMarkers(output);
|
|
1587
|
+
const stripped = this.stripAnsi(withoutHookMarkers);
|
|
1259
1588
|
const isComplete = this.isResponseComplete(stripped);
|
|
1260
1589
|
if (!isComplete) {
|
|
1261
1590
|
return null;
|
|
@@ -1279,6 +1608,13 @@ var GeminiAdapter = class extends BaseCodingAdapter {
|
|
|
1279
1608
|
*/
|
|
1280
1609
|
detectExit(output) {
|
|
1281
1610
|
const stripped = this.stripAnsi(output);
|
|
1611
|
+
const marker = this.getLatestHookMarker(stripped);
|
|
1612
|
+
if (marker?.event === "SessionEnd") {
|
|
1613
|
+
return {
|
|
1614
|
+
exited: true,
|
|
1615
|
+
code: 0
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1282
1618
|
if (/folder.?trust.?level.?must.?be.?selected.*exiting/i.test(stripped)) {
|
|
1283
1619
|
return {
|
|
1284
1620
|
exited: true,
|
|
@@ -2128,6 +2464,213 @@ var AiderAdapter = class extends BaseCodingAdapter {
|
|
|
2128
2464
|
}
|
|
2129
2465
|
};
|
|
2130
2466
|
|
|
2467
|
+
// src/hermes-adapter.ts
|
|
2468
|
+
var HermesAdapter = class extends BaseCodingAdapter {
|
|
2469
|
+
adapterType = "hermes";
|
|
2470
|
+
displayName = "Hermes Agent";
|
|
2471
|
+
/** Prompt-toolkit TUI + spinner rendering needs a slightly longer settle. */
|
|
2472
|
+
readySettleMs = 400;
|
|
2473
|
+
installation = {
|
|
2474
|
+
command: 'pip install "hermes-agent[cli]"',
|
|
2475
|
+
alternatives: [
|
|
2476
|
+
'pipx install "hermes-agent[cli]"',
|
|
2477
|
+
'uv tool install "hermes-agent[cli]"'
|
|
2478
|
+
],
|
|
2479
|
+
docsUrl: "https://github.com/NousResearch/hermes-agent"
|
|
2480
|
+
};
|
|
2481
|
+
getWorkspaceFiles() {
|
|
2482
|
+
return [
|
|
2483
|
+
{
|
|
2484
|
+
relativePath: "AGENTS.md",
|
|
2485
|
+
description: "Project instructions and architecture notes loaded by Hermes context files",
|
|
2486
|
+
autoLoaded: true,
|
|
2487
|
+
type: "memory",
|
|
2488
|
+
format: "markdown"
|
|
2489
|
+
},
|
|
2490
|
+
{
|
|
2491
|
+
relativePath: "SOUL.md",
|
|
2492
|
+
description: "Optional persona/context file auto-injected into Hermes system prompt",
|
|
2493
|
+
autoLoaded: true,
|
|
2494
|
+
type: "memory",
|
|
2495
|
+
format: "markdown"
|
|
2496
|
+
},
|
|
2497
|
+
{
|
|
2498
|
+
relativePath: "cli-config.yaml",
|
|
2499
|
+
description: "Legacy/local Hermes CLI configuration file",
|
|
2500
|
+
autoLoaded: true,
|
|
2501
|
+
type: "config",
|
|
2502
|
+
format: "yaml"
|
|
2503
|
+
}
|
|
2504
|
+
];
|
|
2505
|
+
}
|
|
2506
|
+
getRecommendedModels(_credentials) {
|
|
2507
|
+
return {
|
|
2508
|
+
powerful: "anthropic/claude-opus-4.6",
|
|
2509
|
+
fast: "google/gemini-3-flash-preview"
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
getCommand() {
|
|
2513
|
+
return "hermes";
|
|
2514
|
+
}
|
|
2515
|
+
getArgs(_config) {
|
|
2516
|
+
return ["chat"];
|
|
2517
|
+
}
|
|
2518
|
+
getEnv(config) {
|
|
2519
|
+
const env = {};
|
|
2520
|
+
const credentials = this.getCredentials(config);
|
|
2521
|
+
if (credentials.openaiKey) {
|
|
2522
|
+
env.OPENROUTER_API_KEY = credentials.openaiKey;
|
|
2523
|
+
env.OPENAI_API_KEY = credentials.openaiKey;
|
|
2524
|
+
}
|
|
2525
|
+
if (credentials.anthropicKey) {
|
|
2526
|
+
env.ANTHROPIC_API_KEY = credentials.anthropicKey;
|
|
2527
|
+
}
|
|
2528
|
+
if (credentials.googleKey) {
|
|
2529
|
+
env.GOOGLE_API_KEY = credentials.googleKey;
|
|
2530
|
+
env.GEMINI_API_KEY = credentials.googleKey;
|
|
2531
|
+
}
|
|
2532
|
+
if (!this.isInteractive(config)) {
|
|
2533
|
+
env.HERMES_QUIET = "1";
|
|
2534
|
+
}
|
|
2535
|
+
return env;
|
|
2536
|
+
}
|
|
2537
|
+
detectLogin(output) {
|
|
2538
|
+
const stripped = this.stripAnsi(output);
|
|
2539
|
+
if (/isn.?t configured yet/i.test(stripped) || /no api keys or providers found/i.test(stripped) || /run setup now\?\s*\[y\/n\]/i.test(stripped)) {
|
|
2540
|
+
return {
|
|
2541
|
+
required: true,
|
|
2542
|
+
type: "api_key",
|
|
2543
|
+
instructions: "Hermes requires provider credentials. Run: hermes setup"
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2546
|
+
return { required: false };
|
|
2547
|
+
}
|
|
2548
|
+
detectBlockingPrompt(output) {
|
|
2549
|
+
const stripped = this.stripAnsi(output);
|
|
2550
|
+
const loginDetection = this.detectLogin(output);
|
|
2551
|
+
if (loginDetection.required) {
|
|
2552
|
+
return {
|
|
2553
|
+
detected: true,
|
|
2554
|
+
type: "login",
|
|
2555
|
+
prompt: loginDetection.instructions,
|
|
2556
|
+
canAutoRespond: false,
|
|
2557
|
+
instructions: loginDetection.instructions
|
|
2558
|
+
};
|
|
2559
|
+
}
|
|
2560
|
+
if (/Hermes needs your input|Other \(type your answer\)/i.test(stripped)) {
|
|
2561
|
+
return {
|
|
2562
|
+
detected: true,
|
|
2563
|
+
type: "tool_wait",
|
|
2564
|
+
prompt: "Hermes clarify prompt",
|
|
2565
|
+
canAutoRespond: false,
|
|
2566
|
+
instructions: "Hermes is waiting for clarify input (arrow keys + Enter or free text)."
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
if (/Sudo Password Required|password hidden|Password \(hidden\):/i.test(stripped)) {
|
|
2570
|
+
return {
|
|
2571
|
+
detected: true,
|
|
2572
|
+
type: "tool_wait",
|
|
2573
|
+
prompt: "Hermes sudo password prompt",
|
|
2574
|
+
canAutoRespond: false,
|
|
2575
|
+
instructions: "Hermes terminal tool is waiting for a sudo password or skip."
|
|
2576
|
+
};
|
|
2577
|
+
}
|
|
2578
|
+
if (/Dangerous Command|Allow once|Allow for this session|permanent allowlist|\bDeny\b/i.test(stripped)) {
|
|
2579
|
+
return {
|
|
2580
|
+
detected: true,
|
|
2581
|
+
type: "permission",
|
|
2582
|
+
prompt: "Hermes dangerous command approval",
|
|
2583
|
+
canAutoRespond: false,
|
|
2584
|
+
instructions: "Choose approval policy (once/session/always/deny)."
|
|
2585
|
+
};
|
|
2586
|
+
}
|
|
2587
|
+
return super.detectBlockingPrompt(output);
|
|
2588
|
+
}
|
|
2589
|
+
detectLoading(output) {
|
|
2590
|
+
const stripped = this.stripAnsi(output);
|
|
2591
|
+
const tail = stripped.slice(-1200);
|
|
2592
|
+
if (/(?:pondering|contemplating|musing|cogitating|ruminating|deliberating|mulling|reflecting|processing|reasoning|analyzing|computing|synthesizing|formulating|brainstorming)\.\.\.\s*\(\d+\.\d+s\)/i.test(tail)) {
|
|
2593
|
+
return true;
|
|
2594
|
+
}
|
|
2595
|
+
if (/\(\d+\.\d+s\)\s*$/.test(tail) && /(?:🔍|📄|💻|⚙️|📖|✍️|🔧|🌐|👆|⌨️|📋|🧠|📚|🎨|🐍|🔀|⚡|💬)/.test(tail)) {
|
|
2596
|
+
return true;
|
|
2597
|
+
}
|
|
2598
|
+
if (/⚕\s*❯\s*$/.test(tail)) {
|
|
2599
|
+
return true;
|
|
2600
|
+
}
|
|
2601
|
+
return false;
|
|
2602
|
+
}
|
|
2603
|
+
detectTaskComplete(output) {
|
|
2604
|
+
if (/╭─\s*⚕\s*Hermes/i.test(output)) {
|
|
2605
|
+
return true;
|
|
2606
|
+
}
|
|
2607
|
+
const stripped = this.stripAnsi(output);
|
|
2608
|
+
if (!stripped.trim()) return false;
|
|
2609
|
+
if (this.detectLoading(stripped)) {
|
|
2610
|
+
return false;
|
|
2611
|
+
}
|
|
2612
|
+
const hasIdlePrompt = /(?:^|\n)\s*❯\s*$/m.test(stripped);
|
|
2613
|
+
const hasToolFeed = /(?:^|\n)\s*┊\s+\S+/m.test(stripped);
|
|
2614
|
+
if (hasIdlePrompt && hasToolFeed) {
|
|
2615
|
+
return true;
|
|
2616
|
+
}
|
|
2617
|
+
return false;
|
|
2618
|
+
}
|
|
2619
|
+
detectReady(output) {
|
|
2620
|
+
const stripped = this.stripAnsi(output);
|
|
2621
|
+
const tail = stripped.slice(-800);
|
|
2622
|
+
if (!tail.trim()) return false;
|
|
2623
|
+
if (this.detectLoading(tail)) {
|
|
2624
|
+
return false;
|
|
2625
|
+
}
|
|
2626
|
+
if (/Hermes needs your input|Sudo Password Required|Dangerous Command/i.test(tail)) {
|
|
2627
|
+
return false;
|
|
2628
|
+
}
|
|
2629
|
+
if (/(?:⚕|⚠|🔐|\?|✎)\s*❯\s*$/.test(tail)) {
|
|
2630
|
+
return false;
|
|
2631
|
+
}
|
|
2632
|
+
return /(?:^|\n)\s*❯\s*$/m.test(tail);
|
|
2633
|
+
}
|
|
2634
|
+
parseOutput(output) {
|
|
2635
|
+
const raw = output;
|
|
2636
|
+
const stripped = this.stripAnsi(output);
|
|
2637
|
+
const complete = this.detectTaskComplete(raw) || this.detectReady(stripped);
|
|
2638
|
+
if (!complete) {
|
|
2639
|
+
return null;
|
|
2640
|
+
}
|
|
2641
|
+
let content = "";
|
|
2642
|
+
const boxMatch = raw.match(/╭─\s*⚕\s*Hermes[^\n]*\n([\s\S]*?)\n\s*╰/i);
|
|
2643
|
+
if (boxMatch?.[1]) {
|
|
2644
|
+
content = boxMatch[1].trim();
|
|
2645
|
+
}
|
|
2646
|
+
if (!content) {
|
|
2647
|
+
content = this.extractContent(stripped, /(?:^|\n)\s*(?:⚕|⚠|🔐|\?|✎)?\s*❯\s*$/gim);
|
|
2648
|
+
}
|
|
2649
|
+
return {
|
|
2650
|
+
type: this.containsQuestion(content) ? "question" : "response",
|
|
2651
|
+
content,
|
|
2652
|
+
isComplete: true,
|
|
2653
|
+
isQuestion: this.containsQuestion(content),
|
|
2654
|
+
metadata: {
|
|
2655
|
+
raw: output
|
|
2656
|
+
}
|
|
2657
|
+
};
|
|
2658
|
+
}
|
|
2659
|
+
getPromptPattern() {
|
|
2660
|
+
return /(?:^|\n)\s*(?:⚕|⚠|🔐|\?|✎)?\s*❯\s*$/i;
|
|
2661
|
+
}
|
|
2662
|
+
detectExit(output) {
|
|
2663
|
+
const stripped = this.stripAnsi(output);
|
|
2664
|
+
if (/Goodbye!\s*⚕/i.test(stripped)) {
|
|
2665
|
+
return { exited: true, code: 0 };
|
|
2666
|
+
}
|
|
2667
|
+
return super.detectExit(output);
|
|
2668
|
+
}
|
|
2669
|
+
getHealthCheckCommand() {
|
|
2670
|
+
return "hermes version";
|
|
2671
|
+
}
|
|
2672
|
+
};
|
|
2673
|
+
|
|
2131
2674
|
// src/pattern-loader.ts
|
|
2132
2675
|
var BASELINE_PATTERNS = {
|
|
2133
2676
|
claude: {
|
|
@@ -2251,6 +2794,41 @@ var BASELINE_PATTERNS = {
|
|
|
2251
2794
|
toolWait: [],
|
|
2252
2795
|
exit: [],
|
|
2253
2796
|
source: "baseline"
|
|
2797
|
+
},
|
|
2798
|
+
hermes: {
|
|
2799
|
+
ready: [
|
|
2800
|
+
"\u276F",
|
|
2801
|
+
"\u2695 Hermes",
|
|
2802
|
+
"Welcome to Hermes Agent"
|
|
2803
|
+
],
|
|
2804
|
+
auth: [
|
|
2805
|
+
"isn't configured yet",
|
|
2806
|
+
"no API keys or providers found",
|
|
2807
|
+
"Run setup now? [Y/n]"
|
|
2808
|
+
],
|
|
2809
|
+
blocking: [
|
|
2810
|
+
"Hermes needs your input",
|
|
2811
|
+
"Sudo Password Required",
|
|
2812
|
+
"Dangerous Command"
|
|
2813
|
+
],
|
|
2814
|
+
loading: [
|
|
2815
|
+
"deliberating...",
|
|
2816
|
+
"(0.0s)",
|
|
2817
|
+
"\u2695 \u276F"
|
|
2818
|
+
],
|
|
2819
|
+
turnComplete: [
|
|
2820
|
+
"\u256D\u2500 \u2695 Hermes",
|
|
2821
|
+
"\u276F"
|
|
2822
|
+
],
|
|
2823
|
+
toolWait: [
|
|
2824
|
+
"Hermes needs your input",
|
|
2825
|
+
"Sudo Password Required",
|
|
2826
|
+
"Dangerous Command"
|
|
2827
|
+
],
|
|
2828
|
+
exit: [
|
|
2829
|
+
"Goodbye! \u2695"
|
|
2830
|
+
],
|
|
2831
|
+
source: "baseline"
|
|
2254
2832
|
}
|
|
2255
2833
|
};
|
|
2256
2834
|
var patternCache = /* @__PURE__ */ new Map();
|
|
@@ -2321,14 +2899,16 @@ function createAllAdapters() {
|
|
|
2321
2899
|
new ClaudeAdapter(),
|
|
2322
2900
|
new GeminiAdapter(),
|
|
2323
2901
|
new CodexAdapter(),
|
|
2324
|
-
new AiderAdapter()
|
|
2902
|
+
new AiderAdapter(),
|
|
2903
|
+
new HermesAdapter()
|
|
2325
2904
|
];
|
|
2326
2905
|
}
|
|
2327
2906
|
var ADAPTER_TYPES = {
|
|
2328
2907
|
claude: ClaudeAdapter,
|
|
2329
2908
|
gemini: GeminiAdapter,
|
|
2330
2909
|
codex: CodexAdapter,
|
|
2331
|
-
aider: AiderAdapter
|
|
2910
|
+
aider: AiderAdapter,
|
|
2911
|
+
hermes: HermesAdapter
|
|
2332
2912
|
};
|
|
2333
2913
|
function createAdapter(type) {
|
|
2334
2914
|
const AdapterClass = ADAPTER_TYPES[type];
|
|
@@ -2385,6 +2965,7 @@ exports.ClaudeAdapter = ClaudeAdapter;
|
|
|
2385
2965
|
exports.CodexAdapter = CodexAdapter;
|
|
2386
2966
|
exports.GEMINI_TOOL_CATEGORIES = GEMINI_TOOL_CATEGORIES;
|
|
2387
2967
|
exports.GeminiAdapter = GeminiAdapter;
|
|
2968
|
+
exports.HermesAdapter = HermesAdapter;
|
|
2388
2969
|
exports.PRESET_DEFINITIONS = PRESET_DEFINITIONS;
|
|
2389
2970
|
exports.TOOL_CATEGORIES = TOOL_CATEGORIES;
|
|
2390
2971
|
exports.checkAdapters = checkAdapters;
|
|
@@ -2397,6 +2978,7 @@ exports.generateApprovalConfig = generateApprovalConfig;
|
|
|
2397
2978
|
exports.generateClaudeApprovalConfig = generateClaudeApprovalConfig;
|
|
2398
2979
|
exports.generateCodexApprovalConfig = generateCodexApprovalConfig;
|
|
2399
2980
|
exports.generateGeminiApprovalConfig = generateGeminiApprovalConfig;
|
|
2981
|
+
exports.generateHermesApprovalConfig = generateHermesApprovalConfig;
|
|
2400
2982
|
exports.getBaselinePatterns = getBaselinePatterns;
|
|
2401
2983
|
exports.getPresetDefinition = getPresetDefinition;
|
|
2402
2984
|
exports.hasDynamicPatterns = hasDynamicPatterns;
|