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