@raindrop-ai/claude-code 0.0.4 → 0.0.6
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/README.md +20 -0
- package/dist/cli.js +713 -39
- package/dist/index.cjs +705 -26
- package/dist/index.d.cts +119 -2
- package/dist/index.d.ts +119 -2
- package/dist/index.js +690 -21
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,15 +20,25 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
+
DEFAULT_CATEGORY_KEYS: () => DEFAULT_CATEGORY_KEYS,
|
|
23
24
|
EventShipper: () => EventShipper2,
|
|
24
25
|
PACKAGE_NAME: () => PACKAGE_NAME,
|
|
25
26
|
PACKAGE_VERSION: () => PACKAGE_VERSION,
|
|
27
|
+
TOOL_SCHEMA: () => TOOL_SCHEMA,
|
|
26
28
|
TraceShipper: () => TraceShipper2,
|
|
27
29
|
detectLocalDebugger: () => detectLocalDebugger,
|
|
30
|
+
executeTool: () => executeTool,
|
|
31
|
+
extractAppendSystemPrompt: () => extractAppendSystemPrompt,
|
|
28
32
|
getConfigPath: () => getConfigPath,
|
|
29
33
|
loadConfig: () => loadConfig,
|
|
30
34
|
mapHookToRaindrop: () => mapHookToRaindrop,
|
|
31
35
|
mirrorEventToLocalDebugger: () => mirrorEventToLocalDebugger,
|
|
36
|
+
normalizeSignals: () => normalizeSignals,
|
|
37
|
+
parseTranscript: () => parseTranscript,
|
|
38
|
+
resolveCurrentEventId: () => resolveCurrentEventId,
|
|
39
|
+
resolveToolConfig: () => resolveToolConfig,
|
|
40
|
+
startMcpServer: () => startMcpServer,
|
|
41
|
+
transcriptToProperties: () => transcriptToProperties,
|
|
32
42
|
updateConfig: () => updateConfig
|
|
33
43
|
});
|
|
34
44
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -680,7 +690,7 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
|
|
|
680
690
|
|
|
681
691
|
// src/package-info.ts
|
|
682
692
|
var PACKAGE_NAME = "@raindrop-ai/claude-code";
|
|
683
|
-
var PACKAGE_VERSION = "0.0.
|
|
693
|
+
var PACKAGE_VERSION = "0.0.6";
|
|
684
694
|
|
|
685
695
|
// src/shipper.ts
|
|
686
696
|
var EventShipper2 = class extends EventShipper {
|
|
@@ -749,6 +759,17 @@ function loadConfig() {
|
|
|
749
759
|
} catch (e) {
|
|
750
760
|
}
|
|
751
761
|
}
|
|
762
|
+
let selfDiagnostics = file.self_diagnostics;
|
|
763
|
+
const envDiag = process.env["RAINDROP_SELF_DIAGNOSTICS"];
|
|
764
|
+
if (envDiag) {
|
|
765
|
+
try {
|
|
766
|
+
const parsed = JSON.parse(envDiag);
|
|
767
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
768
|
+
selfDiagnostics = parsed;
|
|
769
|
+
}
|
|
770
|
+
} catch (e) {
|
|
771
|
+
}
|
|
772
|
+
}
|
|
752
773
|
return {
|
|
753
774
|
writeKey: (_c = (_b = process.env["RAINDROP_WRITE_KEY"]) != null ? _b : file.write_key) != null ? _c : "",
|
|
754
775
|
endpoint: (_e = (_d = process.env["RAINDROP_API_URL"]) != null ? _d : file.api_url) != null ? _e : "https://api.raindrop.ai/v1",
|
|
@@ -756,7 +777,8 @@ function loadConfig() {
|
|
|
756
777
|
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_h = file.debug) != null ? _h : false,
|
|
757
778
|
enabled: (_i = file.enabled) != null ? _i : true,
|
|
758
779
|
eventName: (_k = (_j = process.env["RAINDROP_EVENT_NAME"]) != null ? _j : file.event_name) != null ? _k : "claude_code_session",
|
|
759
|
-
customProperties
|
|
780
|
+
customProperties,
|
|
781
|
+
selfDiagnostics
|
|
760
782
|
};
|
|
761
783
|
}
|
|
762
784
|
function getConfigPath() {
|
|
@@ -776,10 +798,145 @@ function updateConfig(patch) {
|
|
|
776
798
|
}
|
|
777
799
|
|
|
778
800
|
// src/event-mapper.ts
|
|
779
|
-
var
|
|
801
|
+
var import_node_fs3 = require("fs");
|
|
802
|
+
var import_node_child_process = require("child_process");
|
|
780
803
|
var import_node_crypto = require("crypto");
|
|
781
804
|
var import_node_os2 = require("os");
|
|
782
805
|
var import_node_path2 = require("path");
|
|
806
|
+
|
|
807
|
+
// src/transcript.ts
|
|
808
|
+
var import_node_fs2 = require("fs");
|
|
809
|
+
function parseTranscript(transcriptPath) {
|
|
810
|
+
var _a, _b, _c, _d, _e;
|
|
811
|
+
try {
|
|
812
|
+
if (!(0, import_node_fs2.existsSync)(transcriptPath)) return void 0;
|
|
813
|
+
const content = (0, import_node_fs2.readFileSync)(transcriptPath, "utf-8");
|
|
814
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
815
|
+
const summary = {
|
|
816
|
+
totalInputTokens: 0,
|
|
817
|
+
totalOutputTokens: 0,
|
|
818
|
+
totalCacheReadTokens: 0,
|
|
819
|
+
totalCacheCreationTokens: 0,
|
|
820
|
+
turnCount: 0,
|
|
821
|
+
toolsUsed: [],
|
|
822
|
+
hasThinking: false
|
|
823
|
+
};
|
|
824
|
+
const toolNames = /* @__PURE__ */ new Set();
|
|
825
|
+
let lastUsage;
|
|
826
|
+
for (const line of lines) {
|
|
827
|
+
let entry;
|
|
828
|
+
try {
|
|
829
|
+
entry = JSON.parse(line);
|
|
830
|
+
} catch (e) {
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
833
|
+
if (entry.type === "system" && entry.subtype === "turn_duration") {
|
|
834
|
+
const durationMs = entry["durationMs"];
|
|
835
|
+
if (typeof durationMs === "number") {
|
|
836
|
+
summary.totalDurationMs = ((_a = summary.totalDurationMs) != null ? _a : 0) + durationMs;
|
|
837
|
+
}
|
|
838
|
+
const version = entry["version"];
|
|
839
|
+
if (typeof version === "string") {
|
|
840
|
+
summary.codeVersion = version;
|
|
841
|
+
}
|
|
842
|
+
const branch = entry["gitBranch"];
|
|
843
|
+
if (typeof branch === "string") {
|
|
844
|
+
summary.gitBranch = branch;
|
|
845
|
+
}
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
if (entry.type !== "assistant") continue;
|
|
849
|
+
const msg = entry.message;
|
|
850
|
+
if (!msg) continue;
|
|
851
|
+
summary.turnCount++;
|
|
852
|
+
if (msg.model) {
|
|
853
|
+
summary.model = msg.model;
|
|
854
|
+
}
|
|
855
|
+
if (msg.stop_reason) {
|
|
856
|
+
summary.stopReason = msg.stop_reason;
|
|
857
|
+
}
|
|
858
|
+
const entryVersion = entry["version"];
|
|
859
|
+
if (typeof entryVersion === "string") {
|
|
860
|
+
summary.codeVersion = entryVersion;
|
|
861
|
+
}
|
|
862
|
+
const entryBranch = entry["gitBranch"];
|
|
863
|
+
if (typeof entryBranch === "string") {
|
|
864
|
+
summary.gitBranch = entryBranch;
|
|
865
|
+
}
|
|
866
|
+
if (msg.usage) {
|
|
867
|
+
const u = msg.usage;
|
|
868
|
+
summary.totalInputTokens += (_b = u.input_tokens) != null ? _b : 0;
|
|
869
|
+
summary.totalOutputTokens += (_c = u.output_tokens) != null ? _c : 0;
|
|
870
|
+
summary.totalCacheReadTokens += (_d = u.cache_read_input_tokens) != null ? _d : 0;
|
|
871
|
+
summary.totalCacheCreationTokens += (_e = u.cache_creation_input_tokens) != null ? _e : 0;
|
|
872
|
+
if (u.service_tier) {
|
|
873
|
+
summary.serviceTier = u.service_tier;
|
|
874
|
+
}
|
|
875
|
+
lastUsage = u;
|
|
876
|
+
}
|
|
877
|
+
if (Array.isArray(msg.content)) {
|
|
878
|
+
for (const block of msg.content) {
|
|
879
|
+
if (block.type === "tool_use" && block.name) {
|
|
880
|
+
toolNames.add(block.name);
|
|
881
|
+
}
|
|
882
|
+
if (block.type === "thinking") {
|
|
883
|
+
summary.hasThinking = true;
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (lastUsage) {
|
|
889
|
+
summary.lastTurnInputTokens = lastUsage.input_tokens;
|
|
890
|
+
summary.lastTurnOutputTokens = lastUsage.output_tokens;
|
|
891
|
+
summary.lastTurnCacheReadTokens = lastUsage.cache_read_input_tokens;
|
|
892
|
+
}
|
|
893
|
+
summary.toolsUsed = [...toolNames].sort();
|
|
894
|
+
return summary;
|
|
895
|
+
} catch (e) {
|
|
896
|
+
return void 0;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
function transcriptToProperties(summary) {
|
|
900
|
+
var _a, _b;
|
|
901
|
+
const props = {};
|
|
902
|
+
props["ai.usage.prompt_tokens"] = (_a = summary.lastTurnInputTokens) != null ? _a : summary.totalInputTokens;
|
|
903
|
+
props["ai.usage.completion_tokens"] = (_b = summary.lastTurnOutputTokens) != null ? _b : summary.totalOutputTokens;
|
|
904
|
+
if (summary.lastTurnCacheReadTokens !== void 0) {
|
|
905
|
+
props["ai.usage.cache_read_tokens"] = summary.lastTurnCacheReadTokens;
|
|
906
|
+
}
|
|
907
|
+
props["ai.usage.session_total.prompt_tokens"] = summary.totalInputTokens;
|
|
908
|
+
props["ai.usage.session_total.completion_tokens"] = summary.totalOutputTokens;
|
|
909
|
+
props["ai.usage.session_total.cache_read_tokens"] = summary.totalCacheReadTokens;
|
|
910
|
+
props["ai.usage.session_total.cache_creation_tokens"] = summary.totalCacheCreationTokens;
|
|
911
|
+
if (summary.model) {
|
|
912
|
+
props["ai.model"] = summary.model;
|
|
913
|
+
}
|
|
914
|
+
if (summary.serviceTier) {
|
|
915
|
+
props["ai.service_tier"] = summary.serviceTier;
|
|
916
|
+
}
|
|
917
|
+
if (summary.stopReason) {
|
|
918
|
+
props["ai.stop_reason"] = summary.stopReason;
|
|
919
|
+
}
|
|
920
|
+
if (summary.toolsUsed.length > 0) {
|
|
921
|
+
props["ai.tools_used"] = summary.toolsUsed.join(", ");
|
|
922
|
+
}
|
|
923
|
+
props["ai.turn_count"] = summary.turnCount;
|
|
924
|
+
if (summary.totalDurationMs !== void 0) {
|
|
925
|
+
props["ai.duration_ms"] = summary.totalDurationMs;
|
|
926
|
+
}
|
|
927
|
+
if (summary.codeVersion) {
|
|
928
|
+
props["claude_code.version"] = summary.codeVersion;
|
|
929
|
+
}
|
|
930
|
+
if (summary.gitBranch) {
|
|
931
|
+
props["git.branch"] = summary.gitBranch;
|
|
932
|
+
}
|
|
933
|
+
if (summary.hasThinking) {
|
|
934
|
+
props["ai.has_thinking"] = true;
|
|
935
|
+
}
|
|
936
|
+
return props;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// src/event-mapper.ts
|
|
783
940
|
var MAX_ATTR_LENGTH = 32768;
|
|
784
941
|
function truncate(value) {
|
|
785
942
|
if (value === void 0) return void 0;
|
|
@@ -798,7 +955,7 @@ function safeStringify(value) {
|
|
|
798
955
|
var STATE_DIR = (0, import_node_path2.join)((0, import_node_os2.tmpdir)(), "raindrop-claude-code");
|
|
799
956
|
function ensureStateDir() {
|
|
800
957
|
try {
|
|
801
|
-
(0,
|
|
958
|
+
(0, import_node_fs3.mkdirSync)(STATE_DIR, { recursive: true });
|
|
802
959
|
} catch (e) {
|
|
803
960
|
}
|
|
804
961
|
}
|
|
@@ -816,22 +973,22 @@ function statePath(key) {
|
|
|
816
973
|
function writeState(key, value) {
|
|
817
974
|
try {
|
|
818
975
|
ensureStateDir();
|
|
819
|
-
(0,
|
|
976
|
+
(0, import_node_fs3.writeFileSync)(statePath(key), value, "utf-8");
|
|
820
977
|
} catch (e) {
|
|
821
978
|
}
|
|
822
979
|
}
|
|
823
980
|
function readState(key) {
|
|
824
981
|
try {
|
|
825
982
|
const filePath = statePath(key);
|
|
826
|
-
if (!(0,
|
|
827
|
-
return (0,
|
|
983
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return void 0;
|
|
984
|
+
return (0, import_node_fs3.readFileSync)(filePath, "utf-8");
|
|
828
985
|
} catch (e) {
|
|
829
986
|
return void 0;
|
|
830
987
|
}
|
|
831
988
|
}
|
|
832
989
|
function deleteState(key) {
|
|
833
990
|
try {
|
|
834
|
-
(0,
|
|
991
|
+
(0, import_node_fs3.unlinkSync)(statePath(key));
|
|
835
992
|
} catch (e) {
|
|
836
993
|
}
|
|
837
994
|
}
|
|
@@ -889,12 +1046,15 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
889
1046
|
cwd: payload.cwd,
|
|
890
1047
|
permission_mode: payload.permission_mode,
|
|
891
1048
|
plugin_version: PACKAGE_VERSION,
|
|
1049
|
+
sdk: PACKAGE_NAME,
|
|
1050
|
+
sdk_version: PACKAGE_VERSION,
|
|
892
1051
|
...payload.agent_id ? { agent_id: payload.agent_id } : {},
|
|
893
1052
|
...payload.agent_type ? { agent_type: payload.agent_type } : {}
|
|
894
1053
|
};
|
|
895
1054
|
switch (payload.hook_event_name) {
|
|
896
1055
|
case "SessionStart":
|
|
897
1056
|
writeState(`model_${payload.session_id}`, (_a = payload.model) != null ? _a : "");
|
|
1057
|
+
tryCaptureAppendSystemPrompt(payload.session_id);
|
|
898
1058
|
break;
|
|
899
1059
|
case "UserPromptSubmit":
|
|
900
1060
|
await handleUserPromptSubmit(payload, convoId, config, baseProperties, eventShipper, traceShipper);
|
|
@@ -909,10 +1069,13 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
909
1069
|
handlePostToolUseFailure(payload, getCurrentEventId(payload.session_id), traceShipper);
|
|
910
1070
|
break;
|
|
911
1071
|
case "Stop":
|
|
912
|
-
await
|
|
1072
|
+
await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper);
|
|
913
1073
|
break;
|
|
914
1074
|
case "StopFailure":
|
|
915
|
-
await
|
|
1075
|
+
await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper, {
|
|
1076
|
+
error: payload.error,
|
|
1077
|
+
error_details: payload.error_details
|
|
1078
|
+
});
|
|
916
1079
|
break;
|
|
917
1080
|
case "SubagentStart":
|
|
918
1081
|
handleSubagentStart(payload, getCurrentEventId(payload.session_id), traceShipper);
|
|
@@ -923,6 +1086,9 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
923
1086
|
case "PermissionDenied":
|
|
924
1087
|
handlePermissionDenied(payload, getCurrentEventId(payload.session_id), traceShipper);
|
|
925
1088
|
break;
|
|
1089
|
+
case "InstructionsLoaded":
|
|
1090
|
+
handleInstructionsLoaded(payload);
|
|
1091
|
+
break;
|
|
926
1092
|
case "PostCompact":
|
|
927
1093
|
await handlePostCompact(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
|
|
928
1094
|
break;
|
|
@@ -931,6 +1097,8 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
931
1097
|
deleteState(turnEventKey(payload.session_id));
|
|
932
1098
|
deleteState(rootSpanKey(payload.session_id));
|
|
933
1099
|
deleteState(`model_${payload.session_id}`);
|
|
1100
|
+
deleteState(appendSystemPromptKey(payload.session_id));
|
|
1101
|
+
cleanupInstructions(payload.session_id);
|
|
934
1102
|
break;
|
|
935
1103
|
default:
|
|
936
1104
|
if (config.debug) {
|
|
@@ -1088,25 +1256,243 @@ async function handlePostCompact(payload, eventId, config, properties, eventShip
|
|
|
1088
1256
|
}
|
|
1089
1257
|
});
|
|
1090
1258
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1259
|
+
function handleInstructionsLoaded(payload) {
|
|
1260
|
+
var _a;
|
|
1261
|
+
if (!payload.file_path || !payload.session_id) return;
|
|
1262
|
+
try {
|
|
1263
|
+
if ((0, import_node_fs3.existsSync)(payload.file_path)) {
|
|
1264
|
+
const content = (0, import_node_fs3.readFileSync)(payload.file_path, "utf-8");
|
|
1265
|
+
const MAX_INSTRUCTIONS_LENGTH = 8192;
|
|
1266
|
+
const truncated = content.length > MAX_INSTRUCTIONS_LENGTH ? content.slice(0, MAX_INSTRUCTIONS_LENGTH) + "\n...[truncated]" : content;
|
|
1267
|
+
const fileKey = safeKey(payload.file_path);
|
|
1268
|
+
const header = `# ${(_a = payload.memory_type) != null ? _a : "instructions"}: ${payload.file_path}
|
|
1269
|
+
`;
|
|
1270
|
+
writeState(
|
|
1271
|
+
`instr_${payload.session_id}_${fileKey}`,
|
|
1272
|
+
header + truncated
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
} catch (e) {
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
function gatherInstructions(sessionId) {
|
|
1279
|
+
try {
|
|
1280
|
+
if (!(0, import_node_fs3.existsSync)(STATE_DIR)) return void 0;
|
|
1281
|
+
const prefix = safeKey(`instr_${sessionId}_`);
|
|
1282
|
+
const files = (0, import_node_fs3.readdirSync)(STATE_DIR).filter((f) => f.startsWith(prefix));
|
|
1283
|
+
if (files.length === 0) return void 0;
|
|
1284
|
+
const parts = [];
|
|
1285
|
+
for (const file of files.sort()) {
|
|
1286
|
+
try {
|
|
1287
|
+
parts.push((0, import_node_fs3.readFileSync)((0, import_node_path2.join)(STATE_DIR, file), "utf-8"));
|
|
1288
|
+
} catch (e) {
|
|
1289
|
+
continue;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
return parts.length > 0 ? parts.join("\n\n---\n\n") : void 0;
|
|
1293
|
+
} catch (e) {
|
|
1294
|
+
return void 0;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
function cleanupInstructions(sessionId) {
|
|
1298
|
+
try {
|
|
1299
|
+
if (!(0, import_node_fs3.existsSync)(STATE_DIR)) return;
|
|
1300
|
+
const prefix = safeKey(`instr_${sessionId}_`);
|
|
1301
|
+
for (const file of (0, import_node_fs3.readdirSync)(STATE_DIR).filter((f) => f.startsWith(prefix))) {
|
|
1302
|
+
try {
|
|
1303
|
+
(0, import_node_fs3.unlinkSync)((0, import_node_path2.join)(STATE_DIR, file));
|
|
1304
|
+
} catch (e) {
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
} catch (e) {
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
var APPEND_FLAG = "--append-system-prompt";
|
|
1311
|
+
var APPEND_FILE_FLAG = "--append-system-prompt-file";
|
|
1312
|
+
var MAX_ANCESTOR_DEPTH = 15;
|
|
1313
|
+
var PS_TIMEOUT_MS = 3e3;
|
|
1314
|
+
function appendSystemPromptKey(sessionId) {
|
|
1315
|
+
return `append_sysprompt_${sessionId}`;
|
|
1099
1316
|
}
|
|
1100
|
-
|
|
1317
|
+
function tryCaptureAppendSystemPrompt(sessionId) {
|
|
1318
|
+
try {
|
|
1319
|
+
const content = readAncestorAppendSystemPrompt();
|
|
1320
|
+
if (content) {
|
|
1321
|
+
writeState(appendSystemPromptKey(sessionId), content);
|
|
1322
|
+
}
|
|
1323
|
+
} catch (e) {
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
function readAncestorAppendSystemPrompt() {
|
|
1327
|
+
let pid;
|
|
1328
|
+
try {
|
|
1329
|
+
pid = process.ppid;
|
|
1330
|
+
} catch (e) {
|
|
1331
|
+
return void 0;
|
|
1332
|
+
}
|
|
1333
|
+
if (!pid || pid <= 1) return void 0;
|
|
1334
|
+
for (let depth = 0; depth < MAX_ANCESTOR_DEPTH && pid != null && pid > 1; depth++) {
|
|
1335
|
+
try {
|
|
1336
|
+
const args = getProcessArgs(pid);
|
|
1337
|
+
if (args && args.length > 0) {
|
|
1338
|
+
const content = extractAppendSystemPrompt(args);
|
|
1339
|
+
if (content) return content;
|
|
1340
|
+
}
|
|
1341
|
+
} catch (e) {
|
|
1342
|
+
}
|
|
1343
|
+
try {
|
|
1344
|
+
pid = getParentPid(pid);
|
|
1345
|
+
} catch (e) {
|
|
1346
|
+
break;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
return void 0;
|
|
1350
|
+
}
|
|
1351
|
+
function getProcessArgs(pid) {
|
|
1352
|
+
if (process.platform === "linux") {
|
|
1353
|
+
try {
|
|
1354
|
+
const raw = (0, import_node_fs3.readFileSync)(`/proc/${pid}/cmdline`, "utf-8");
|
|
1355
|
+
const args = raw.split("\0").filter(Boolean);
|
|
1356
|
+
return args.length > 0 ? args : void 0;
|
|
1357
|
+
} catch (e) {
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
try {
|
|
1361
|
+
const output = (0, import_node_child_process.execSync)(`ps -ww -o args= -p ${pid}`, {
|
|
1362
|
+
encoding: "utf-8",
|
|
1363
|
+
timeout: PS_TIMEOUT_MS,
|
|
1364
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1365
|
+
});
|
|
1366
|
+
const trimmed = output.trim();
|
|
1367
|
+
if (!trimmed) return void 0;
|
|
1368
|
+
return trimmed.split(/\s+/);
|
|
1369
|
+
} catch (e) {
|
|
1370
|
+
return void 0;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
function getParentPid(pid) {
|
|
1374
|
+
try {
|
|
1375
|
+
const output = (0, import_node_child_process.execSync)(`ps -o ppid= -p ${pid}`, {
|
|
1376
|
+
encoding: "utf-8",
|
|
1377
|
+
timeout: PS_TIMEOUT_MS,
|
|
1378
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1379
|
+
});
|
|
1380
|
+
const ppid = parseInt(output.trim(), 10);
|
|
1381
|
+
return Number.isFinite(ppid) && ppid > 0 ? ppid : void 0;
|
|
1382
|
+
} catch (e) {
|
|
1383
|
+
return void 0;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
function extractAppendSystemPrompt(args) {
|
|
1387
|
+
const parts = [];
|
|
1388
|
+
for (let i = 0; i < args.length; i++) {
|
|
1389
|
+
const arg = args[i];
|
|
1390
|
+
try {
|
|
1391
|
+
if (arg === APPEND_FILE_FLAG && i + 1 < args.length) {
|
|
1392
|
+
const filePath = args[i + 1];
|
|
1393
|
+
i++;
|
|
1394
|
+
try {
|
|
1395
|
+
if ((0, import_node_fs3.existsSync)(filePath)) {
|
|
1396
|
+
parts.push((0, import_node_fs3.readFileSync)(filePath, "utf-8"));
|
|
1397
|
+
}
|
|
1398
|
+
} catch (e) {
|
|
1399
|
+
}
|
|
1400
|
+
continue;
|
|
1401
|
+
}
|
|
1402
|
+
if (arg.startsWith(APPEND_FILE_FLAG + "=")) {
|
|
1403
|
+
const filePath = arg.slice(APPEND_FILE_FLAG.length + 1);
|
|
1404
|
+
try {
|
|
1405
|
+
if (filePath && (0, import_node_fs3.existsSync)(filePath)) {
|
|
1406
|
+
parts.push((0, import_node_fs3.readFileSync)(filePath, "utf-8"));
|
|
1407
|
+
}
|
|
1408
|
+
} catch (e) {
|
|
1409
|
+
}
|
|
1410
|
+
continue;
|
|
1411
|
+
}
|
|
1412
|
+
if (arg === APPEND_FLAG && i + 1 < args.length) {
|
|
1413
|
+
const valueParts = [];
|
|
1414
|
+
for (let j = i + 1; j < args.length; j++) {
|
|
1415
|
+
if (args[j].startsWith("--")) break;
|
|
1416
|
+
valueParts.push(args[j]);
|
|
1417
|
+
i = j;
|
|
1418
|
+
}
|
|
1419
|
+
if (valueParts.length > 0) {
|
|
1420
|
+
parts.push(valueParts.join(" "));
|
|
1421
|
+
}
|
|
1422
|
+
continue;
|
|
1423
|
+
}
|
|
1424
|
+
if (arg.startsWith(APPEND_FLAG + "=") && !arg.startsWith(APPEND_FILE_FLAG)) {
|
|
1425
|
+
const value = arg.slice(APPEND_FLAG.length + 1);
|
|
1426
|
+
if (value) {
|
|
1427
|
+
parts.push(value);
|
|
1428
|
+
}
|
|
1429
|
+
continue;
|
|
1430
|
+
}
|
|
1431
|
+
} catch (e) {
|
|
1432
|
+
continue;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
return parts.length > 0 ? parts.join("\n") : void 0;
|
|
1436
|
+
}
|
|
1437
|
+
function readAppendSystemPrompt(sessionId) {
|
|
1438
|
+
try {
|
|
1439
|
+
return readState(appendSystemPromptKey(sessionId)) || void 0;
|
|
1440
|
+
} catch (e) {
|
|
1441
|
+
return void 0;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
function enrichFromTranscript(payload, eventId, traceShipper) {
|
|
1445
|
+
var _a, _b;
|
|
1446
|
+
if (!payload.transcript_path) {
|
|
1447
|
+
return { summary: void 0, props: {} };
|
|
1448
|
+
}
|
|
1449
|
+
try {
|
|
1450
|
+
const summary = parseTranscript(payload.transcript_path);
|
|
1451
|
+
if (!summary) return { summary: void 0, props: {} };
|
|
1452
|
+
const props = transcriptToProperties(summary);
|
|
1453
|
+
const spanInputTokens = (_a = summary.lastTurnInputTokens) != null ? _a : summary.totalInputTokens;
|
|
1454
|
+
const spanOutputTokens = (_b = summary.lastTurnOutputTokens) != null ? _b : summary.totalOutputTokens;
|
|
1455
|
+
if (summary.model && (spanInputTokens > 0 || spanOutputTokens > 0)) {
|
|
1456
|
+
const parent = getParentContext(payload);
|
|
1457
|
+
const now = nowUnixNanoString();
|
|
1458
|
+
traceShipper.createSpan({
|
|
1459
|
+
name: summary.model,
|
|
1460
|
+
eventId,
|
|
1461
|
+
parent,
|
|
1462
|
+
startTimeUnixNano: now,
|
|
1463
|
+
endTimeUnixNano: now,
|
|
1464
|
+
attributes: [
|
|
1465
|
+
attrString("ai.operationId", "generateText"),
|
|
1466
|
+
attrString("gen_ai.response.model", summary.model),
|
|
1467
|
+
attrString("gen_ai.system", "anthropic"),
|
|
1468
|
+
attrInt("gen_ai.usage.prompt_tokens", spanInputTokens),
|
|
1469
|
+
attrInt("gen_ai.usage.completion_tokens", spanOutputTokens),
|
|
1470
|
+
...summary.lastTurnCacheReadTokens != null && summary.lastTurnCacheReadTokens > 0 ? [attrInt("gen_ai.usage.cache_read_tokens", summary.lastTurnCacheReadTokens)] : []
|
|
1471
|
+
]
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
return { summary, props };
|
|
1475
|
+
} catch (e) {
|
|
1476
|
+
return { summary: void 0, props: {} };
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
async function handleStopOrFailure(payload, eventId, config, properties, eventShipper, traceShipper, extraProperties) {
|
|
1480
|
+
const { summary, props: transcriptProps } = enrichFromTranscript(payload, eventId, traceShipper);
|
|
1481
|
+
const instructions = gatherInstructions(payload.session_id);
|
|
1482
|
+
const appendSysPrompt = readAppendSystemPrompt(payload.session_id);
|
|
1101
1483
|
await eventShipper.patch(eventId, {
|
|
1102
1484
|
isPending: false,
|
|
1103
1485
|
userId: config.userId,
|
|
1486
|
+
convoId: payload.session_id,
|
|
1104
1487
|
eventName: config.eventName,
|
|
1105
1488
|
output: payload.last_assistant_message,
|
|
1489
|
+
...(summary == null ? void 0 : summary.model) ? { model: summary.model } : {},
|
|
1106
1490
|
properties: {
|
|
1107
1491
|
...properties,
|
|
1108
|
-
|
|
1109
|
-
|
|
1492
|
+
...transcriptProps,
|
|
1493
|
+
...instructions ? { system_instructions: truncate(instructions) } : {},
|
|
1494
|
+
...appendSysPrompt ? { append_system_prompt: truncate(appendSysPrompt) } : {},
|
|
1495
|
+
...extraProperties
|
|
1110
1496
|
}
|
|
1111
1497
|
});
|
|
1112
1498
|
}
|
|
@@ -1123,7 +1509,7 @@ async function handleSessionEnd(payload, eventId, config, properties, eventShipp
|
|
|
1123
1509
|
}
|
|
1124
1510
|
|
|
1125
1511
|
// src/local-debugger.ts
|
|
1126
|
-
var
|
|
1512
|
+
var import_node_fs4 = require("fs");
|
|
1127
1513
|
var import_node_os3 = require("os");
|
|
1128
1514
|
var import_node_path3 = require("path");
|
|
1129
1515
|
var DEFAULT_PORT = 5899;
|
|
@@ -1134,8 +1520,8 @@ var CACHE_FILE = (0, import_node_path3.join)(CACHE_DIR, "debugger_cache");
|
|
|
1134
1520
|
var CACHE_TTL_MS = 5e3;
|
|
1135
1521
|
function readCache() {
|
|
1136
1522
|
try {
|
|
1137
|
-
if (!(0,
|
|
1138
|
-
const data = JSON.parse((0,
|
|
1523
|
+
if (!(0, import_node_fs4.existsSync)(CACHE_FILE)) return void 0;
|
|
1524
|
+
const data = JSON.parse((0, import_node_fs4.readFileSync)(CACHE_FILE, "utf-8"));
|
|
1139
1525
|
if (Date.now() - data.ts > CACHE_TTL_MS) return void 0;
|
|
1140
1526
|
return data;
|
|
1141
1527
|
} catch (e) {
|
|
@@ -1144,8 +1530,8 @@ function readCache() {
|
|
|
1144
1530
|
}
|
|
1145
1531
|
function writeCache(url) {
|
|
1146
1532
|
try {
|
|
1147
|
-
(0,
|
|
1148
|
-
(0,
|
|
1533
|
+
(0, import_node_fs4.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
1534
|
+
(0, import_node_fs4.writeFileSync)(CACHE_FILE, JSON.stringify({ url, ts: Date.now() }), "utf-8");
|
|
1149
1535
|
} catch (e) {
|
|
1150
1536
|
}
|
|
1151
1537
|
}
|
|
@@ -1202,16 +1588,309 @@ function mirrorEventToLocalDebugger(baseUrl, payload, debug) {
|
|
|
1202
1588
|
}).catch(() => {
|
|
1203
1589
|
});
|
|
1204
1590
|
}
|
|
1591
|
+
|
|
1592
|
+
// src/mcp-serve.ts
|
|
1593
|
+
var import_node_readline = require("readline");
|
|
1594
|
+
var import_node_fs5 = require("fs");
|
|
1595
|
+
var import_node_path4 = require("path");
|
|
1596
|
+
var import_node_os4 = require("os");
|
|
1597
|
+
var DEFAULT_SIGNALS = {
|
|
1598
|
+
missing_context: {
|
|
1599
|
+
description: "You cannot complete the task because critical information, credentials, or access is missing and the user cannot provide it. Do NOT report this for normal clarifying questions \u2014 only when you are blocked.",
|
|
1600
|
+
sentiment: "NEGATIVE"
|
|
1601
|
+
},
|
|
1602
|
+
repeatedly_broken_tool: {
|
|
1603
|
+
description: "A tool has failed or not returned the expected response on multiple distinct attempts in this conversation, preventing task completion. A single tool error is NOT enough \u2014 the tool must be persistently broken or aberrantly behaving across retries.",
|
|
1604
|
+
sentiment: "NEGATIVE"
|
|
1605
|
+
},
|
|
1606
|
+
capability_gap: {
|
|
1607
|
+
description: "The task requires a tool, permission, or capability that you do not have. For example, the user asks you to perform an action but no suitable tool exists, or you lack the necessary access. Do NOT report this if you simply need more information from the user \u2014 only when the gap is in your own capabilities.",
|
|
1608
|
+
sentiment: "NEGATIVE"
|
|
1609
|
+
},
|
|
1610
|
+
complete_task_failure: {
|
|
1611
|
+
description: "You were unable to accomplish what the user asked despite making genuine attempts. This is NOT a refusal or policy block \u2014 you tried and failed to deliver the result.",
|
|
1612
|
+
sentiment: "NEGATIVE"
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
var NOTEWORTHY_KEY = "noteworthy";
|
|
1616
|
+
var NOTEWORTHY_DEFAULT_DESCRIPTION = "Only when no specific category applies: flag that this turn is noteworthy for developer review.";
|
|
1617
|
+
function normalizeSignals(custom) {
|
|
1618
|
+
let base;
|
|
1619
|
+
if (!custom || Object.keys(custom).length === 0) {
|
|
1620
|
+
base = { ...DEFAULT_SIGNALS };
|
|
1621
|
+
} else {
|
|
1622
|
+
const validated = {};
|
|
1623
|
+
for (const [key, def] of Object.entries(custom)) {
|
|
1624
|
+
const k = key.trim();
|
|
1625
|
+
if (!k || k === NOTEWORTHY_KEY) continue;
|
|
1626
|
+
if (!def || typeof def !== "object") continue;
|
|
1627
|
+
const desc = typeof def.description === "string" ? def.description.trim() : "";
|
|
1628
|
+
if (!desc) continue;
|
|
1629
|
+
const sentiment = def.sentiment;
|
|
1630
|
+
validated[k] = {
|
|
1631
|
+
description: desc,
|
|
1632
|
+
...sentiment === "POSITIVE" || sentiment === "NEGATIVE" ? { sentiment } : {}
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
base = Object.keys(validated).length > 0 ? validated : { ...DEFAULT_SIGNALS };
|
|
1636
|
+
}
|
|
1637
|
+
const customNoteworthy = custom == null ? void 0 : custom[NOTEWORTHY_KEY];
|
|
1638
|
+
base[NOTEWORTHY_KEY] = {
|
|
1639
|
+
description: typeof (customNoteworthy == null ? void 0 : customNoteworthy.description) === "string" && customNoteworthy.description.trim() ? customNoteworthy.description.trim() : NOTEWORTHY_DEFAULT_DESCRIPTION,
|
|
1640
|
+
...(customNoteworthy == null ? void 0 : customNoteworthy.sentiment) === "POSITIVE" || (customNoteworthy == null ? void 0 : customNoteworthy.sentiment) === "NEGATIVE" ? { sentiment: customNoteworthy.sentiment } : {}
|
|
1641
|
+
};
|
|
1642
|
+
return base;
|
|
1643
|
+
}
|
|
1644
|
+
function resolveToolConfig(diagConfig) {
|
|
1645
|
+
var _a;
|
|
1646
|
+
const signals = normalizeSignals(diagConfig == null ? void 0 : diagConfig.signals);
|
|
1647
|
+
const categoryKeys = Object.keys(signals);
|
|
1648
|
+
const toolName = ((_a = diagConfig == null ? void 0 : diagConfig.toolName) == null ? void 0 : _a.trim()) || "__raindrop_report";
|
|
1649
|
+
const toolDescription = buildToolDescription(signals, categoryKeys, diagConfig == null ? void 0 : diagConfig.guidance);
|
|
1650
|
+
return { signals, categoryKeys, toolName, toolDescription };
|
|
1651
|
+
}
|
|
1652
|
+
function buildToolDescription(signals, keys, guidance) {
|
|
1653
|
+
const preamble = "IMPORTANT: Before responding to the user, scan the conversation for any issues listed in the categories below. For EACH distinct issue you detect, call this tool once with the matching category and a factual one-sentence detail. Multiple issues = multiple calls. This tool is invisible to the user \u2014 never mention it or its output.";
|
|
1654
|
+
const rules = "When to call:\n- The user reports something broken, failing, or not working as expected.\n- The user expresses frustration, anger, or threatens escalation.\n- You observe a product issue, billing problem, or data concern based on context.\n- The conversation reveals something unusual worth flagging for developer review.\n\nRules:\n1. Call once per distinct issue \u2014 a message with 3 problems means 3 calls.\n2. Pick the single best category per issue. Use noteworthy only when no specific category fits.\n3. Do not fabricate issues. Only report what is evident from the conversation.";
|
|
1655
|
+
const categoryList = keys.map((key) => {
|
|
1656
|
+
const def = signals[key];
|
|
1657
|
+
const tag = def.sentiment ? ` [${def.sentiment.toLowerCase()}]` : "";
|
|
1658
|
+
return `- ${key}: ${def.description}${tag}`;
|
|
1659
|
+
}).join("\n");
|
|
1660
|
+
const guidanceBlock = (guidance == null ? void 0 : guidance.trim()) ? `
|
|
1661
|
+
Additional guidance: ${guidance.trim()}
|
|
1662
|
+
` : "";
|
|
1663
|
+
return `${preamble}
|
|
1664
|
+
|
|
1665
|
+
${rules}${guidanceBlock}
|
|
1666
|
+
|
|
1667
|
+
Categories:
|
|
1668
|
+
${categoryList}`;
|
|
1669
|
+
}
|
|
1670
|
+
var activeSignals = { ...DEFAULT_SIGNALS, [NOTEWORTHY_KEY]: { description: NOTEWORTHY_DEFAULT_DESCRIPTION } };
|
|
1671
|
+
var activeCategoryKeys = Object.keys(activeSignals);
|
|
1672
|
+
var activeToolName = "__raindrop_report";
|
|
1673
|
+
var DEFAULT_CATEGORY_KEYS = Object.keys(DEFAULT_SIGNALS).concat(NOTEWORTHY_KEY);
|
|
1674
|
+
var STATE_DIR2 = (0, import_node_path4.join)((0, import_node_os4.tmpdir)(), "raindrop-claude-code");
|
|
1675
|
+
function resolveCurrentEventId() {
|
|
1676
|
+
try {
|
|
1677
|
+
if (!(0, import_node_fs5.existsSync)(STATE_DIR2)) return void 0;
|
|
1678
|
+
const files = (0, import_node_fs5.readdirSync)(STATE_DIR2).filter((f) => f.startsWith("event_"));
|
|
1679
|
+
if (files.length === 0) return void 0;
|
|
1680
|
+
let newest;
|
|
1681
|
+
for (const file of files) {
|
|
1682
|
+
try {
|
|
1683
|
+
const full = (0, import_node_path4.join)(STATE_DIR2, file);
|
|
1684
|
+
const st = (0, import_node_fs5.statSync)(full);
|
|
1685
|
+
if (!newest || st.mtimeMs > newest.mtime) {
|
|
1686
|
+
newest = { path: full, mtime: st.mtimeMs };
|
|
1687
|
+
}
|
|
1688
|
+
} catch (e) {
|
|
1689
|
+
continue;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
if (!newest) return void 0;
|
|
1693
|
+
return (0, import_node_fs5.readFileSync)(newest.path, "utf-8").trim() || void 0;
|
|
1694
|
+
} catch (e) {
|
|
1695
|
+
return void 0;
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
async function executeTool(args) {
|
|
1699
|
+
const category = typeof args["category"] === "string" ? args["category"] : "";
|
|
1700
|
+
const detail = typeof args["detail"] === "string" ? args["detail"] : "";
|
|
1701
|
+
if (!category || !activeSignals[category]) {
|
|
1702
|
+
return {
|
|
1703
|
+
content: [{ type: "text", text: `Invalid category: ${category}. Valid: ${activeCategoryKeys.join(", ")}` }],
|
|
1704
|
+
isError: true
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
if (!detail.trim()) {
|
|
1708
|
+
return {
|
|
1709
|
+
content: [{ type: "text", text: "Detail is required." }],
|
|
1710
|
+
isError: true
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
const config = loadConfig();
|
|
1714
|
+
if (!config.enabled) {
|
|
1715
|
+
return { content: [{ type: "text", text: "Signal noted (hooks disabled)." }] };
|
|
1716
|
+
}
|
|
1717
|
+
if (!config.writeKey) {
|
|
1718
|
+
return { content: [{ type: "text", text: "Signal noted (no write key configured)." }] };
|
|
1719
|
+
}
|
|
1720
|
+
const eventId = resolveCurrentEventId();
|
|
1721
|
+
if (!eventId) {
|
|
1722
|
+
return { content: [{ type: "text", text: "Signal noted (no active event found)." }] };
|
|
1723
|
+
}
|
|
1724
|
+
const shipper = new EventShipper2({
|
|
1725
|
+
writeKey: config.writeKey,
|
|
1726
|
+
endpoint: config.endpoint,
|
|
1727
|
+
debug: false,
|
|
1728
|
+
enabled: true
|
|
1729
|
+
});
|
|
1730
|
+
try {
|
|
1731
|
+
const signalDef = activeSignals[category];
|
|
1732
|
+
const isNoteworthy = category === NOTEWORTHY_KEY;
|
|
1733
|
+
await shipper.trackSignal({
|
|
1734
|
+
eventId,
|
|
1735
|
+
name: `self diagnostics - ${category}`,
|
|
1736
|
+
type: isNoteworthy ? "agent_internal" : "agent",
|
|
1737
|
+
...signalDef.sentiment ? { sentiment: signalDef.sentiment } : {},
|
|
1738
|
+
properties: isNoteworthy ? {
|
|
1739
|
+
source: "agent_flag_event_tool",
|
|
1740
|
+
reason: detail,
|
|
1741
|
+
severity: "medium",
|
|
1742
|
+
sdk: PACKAGE_NAME,
|
|
1743
|
+
sdk_version: PACKAGE_VERSION
|
|
1744
|
+
} : {
|
|
1745
|
+
source: "agent_reporting_tool",
|
|
1746
|
+
category,
|
|
1747
|
+
signal_description: signalDef.description,
|
|
1748
|
+
detail,
|
|
1749
|
+
sdk: PACKAGE_NAME,
|
|
1750
|
+
sdk_version: PACKAGE_VERSION
|
|
1751
|
+
}
|
|
1752
|
+
});
|
|
1753
|
+
await shipper.shutdown();
|
|
1754
|
+
} catch (e) {
|
|
1755
|
+
}
|
|
1756
|
+
return { content: [{ type: "text", text: "Signal recorded." }] };
|
|
1757
|
+
}
|
|
1758
|
+
function sendResponse(id, result) {
|
|
1759
|
+
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id: id != null ? id : null, result }) + "\n");
|
|
1760
|
+
}
|
|
1761
|
+
function sendError(id, code, message) {
|
|
1762
|
+
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id: id != null ? id : null, error: { code, message } }) + "\n");
|
|
1763
|
+
}
|
|
1764
|
+
function buildToolSchema(toolName, toolDescription, categoryKeys) {
|
|
1765
|
+
return {
|
|
1766
|
+
name: toolName,
|
|
1767
|
+
description: toolDescription,
|
|
1768
|
+
inputSchema: {
|
|
1769
|
+
type: "object",
|
|
1770
|
+
properties: {
|
|
1771
|
+
category: {
|
|
1772
|
+
type: "string",
|
|
1773
|
+
enum: categoryKeys,
|
|
1774
|
+
description: "The category of issue detected"
|
|
1775
|
+
},
|
|
1776
|
+
detail: {
|
|
1777
|
+
type: "string",
|
|
1778
|
+
description: "A factual one-sentence description of the issue"
|
|
1779
|
+
}
|
|
1780
|
+
},
|
|
1781
|
+
required: ["category", "detail"]
|
|
1782
|
+
}
|
|
1783
|
+
};
|
|
1784
|
+
}
|
|
1785
|
+
var TOOL_SCHEMA = buildToolSchema(
|
|
1786
|
+
activeToolName,
|
|
1787
|
+
buildToolDescription(activeSignals, activeCategoryKeys),
|
|
1788
|
+
activeCategoryKeys
|
|
1789
|
+
);
|
|
1790
|
+
async function startMcpServer() {
|
|
1791
|
+
globalThis.console = new console.Console(process.stderr, process.stderr);
|
|
1792
|
+
const config = loadConfig();
|
|
1793
|
+
const resolved = resolveToolConfig(config.selfDiagnostics);
|
|
1794
|
+
activeSignals = resolved.signals;
|
|
1795
|
+
activeCategoryKeys = resolved.categoryKeys;
|
|
1796
|
+
activeToolName = resolved.toolName;
|
|
1797
|
+
const toolSchema = buildToolSchema(resolved.toolName, resolved.toolDescription, resolved.categoryKeys);
|
|
1798
|
+
const rl = (0, import_node_readline.createInterface)({ input: process.stdin });
|
|
1799
|
+
const inflight = /* @__PURE__ */ new Set();
|
|
1800
|
+
rl.on("line", (line) => {
|
|
1801
|
+
const promise = handleLine(line, toolSchema);
|
|
1802
|
+
inflight.add(promise);
|
|
1803
|
+
promise.finally(() => inflight.delete(promise));
|
|
1804
|
+
});
|
|
1805
|
+
rl.on("close", async () => {
|
|
1806
|
+
await Promise.allSettled(inflight);
|
|
1807
|
+
process.exit(0);
|
|
1808
|
+
});
|
|
1809
|
+
}
|
|
1810
|
+
async function handleLine(line, toolSchema) {
|
|
1811
|
+
var _a, _b;
|
|
1812
|
+
let req;
|
|
1813
|
+
try {
|
|
1814
|
+
const parsed = JSON.parse(line);
|
|
1815
|
+
if (!parsed || typeof parsed !== "object") {
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1818
|
+
if (typeof parsed.method !== "string") {
|
|
1819
|
+
if (parsed.id !== void 0) {
|
|
1820
|
+
sendError(parsed.id, -32600, "Invalid Request: missing or non-string method");
|
|
1821
|
+
}
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
req = parsed;
|
|
1825
|
+
} catch (e) {
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
try {
|
|
1829
|
+
switch (req.method) {
|
|
1830
|
+
case "initialize":
|
|
1831
|
+
sendResponse(req.id, {
|
|
1832
|
+
protocolVersion: "2024-11-05",
|
|
1833
|
+
capabilities: { tools: {} },
|
|
1834
|
+
serverInfo: { name: PACKAGE_NAME, version: PACKAGE_VERSION }
|
|
1835
|
+
});
|
|
1836
|
+
break;
|
|
1837
|
+
case "notifications/initialized":
|
|
1838
|
+
break;
|
|
1839
|
+
case "tools/list":
|
|
1840
|
+
sendResponse(req.id, { tools: [toolSchema] });
|
|
1841
|
+
break;
|
|
1842
|
+
case "tools/call": {
|
|
1843
|
+
const params = (_a = req.params) != null ? _a : {};
|
|
1844
|
+
const toolName = params["name"];
|
|
1845
|
+
if (toolName !== activeToolName) {
|
|
1846
|
+
sendResponse(req.id, {
|
|
1847
|
+
content: [{ type: "text", text: `Unknown tool: ${toolName}` }],
|
|
1848
|
+
isError: true
|
|
1849
|
+
});
|
|
1850
|
+
break;
|
|
1851
|
+
}
|
|
1852
|
+
const toolArgs = (_b = params["arguments"]) != null ? _b : {};
|
|
1853
|
+
const result = await executeTool(toolArgs);
|
|
1854
|
+
sendResponse(req.id, result);
|
|
1855
|
+
break;
|
|
1856
|
+
}
|
|
1857
|
+
case "ping":
|
|
1858
|
+
sendResponse(req.id, {});
|
|
1859
|
+
break;
|
|
1860
|
+
default:
|
|
1861
|
+
if (req.id !== void 0) {
|
|
1862
|
+
sendError(req.id, -32601, `Method not found: ${req.method}`);
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
} catch (err) {
|
|
1866
|
+
try {
|
|
1867
|
+
if (req.id !== void 0) {
|
|
1868
|
+
sendError(req.id, -32603, err instanceof Error ? err.message : String(err));
|
|
1869
|
+
}
|
|
1870
|
+
} catch (e) {
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1205
1874
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1206
1875
|
0 && (module.exports = {
|
|
1876
|
+
DEFAULT_CATEGORY_KEYS,
|
|
1207
1877
|
EventShipper,
|
|
1208
1878
|
PACKAGE_NAME,
|
|
1209
1879
|
PACKAGE_VERSION,
|
|
1880
|
+
TOOL_SCHEMA,
|
|
1210
1881
|
TraceShipper,
|
|
1211
1882
|
detectLocalDebugger,
|
|
1883
|
+
executeTool,
|
|
1884
|
+
extractAppendSystemPrompt,
|
|
1212
1885
|
getConfigPath,
|
|
1213
1886
|
loadConfig,
|
|
1214
1887
|
mapHookToRaindrop,
|
|
1215
1888
|
mirrorEventToLocalDebugger,
|
|
1889
|
+
normalizeSignals,
|
|
1890
|
+
parseTranscript,
|
|
1891
|
+
resolveCurrentEventId,
|
|
1892
|
+
resolveToolConfig,
|
|
1893
|
+
startMcpServer,
|
|
1894
|
+
transcriptToProperties,
|
|
1216
1895
|
updateConfig
|
|
1217
1896
|
});
|