@raindrop-ai/claude-code 0.0.4 → 0.0.5
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 +4 -0
- package/dist/cli.js +400 -37
- package/dist/index.cjs +395 -25
- package/dist/index.d.cts +54 -2
- package/dist/index.d.ts +54 -2
- package/dist/index.js +387 -20
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -25,10 +25,13 @@ __export(src_exports, {
|
|
|
25
25
|
PACKAGE_VERSION: () => PACKAGE_VERSION,
|
|
26
26
|
TraceShipper: () => TraceShipper2,
|
|
27
27
|
detectLocalDebugger: () => detectLocalDebugger,
|
|
28
|
+
extractAppendSystemPrompt: () => extractAppendSystemPrompt,
|
|
28
29
|
getConfigPath: () => getConfigPath,
|
|
29
30
|
loadConfig: () => loadConfig,
|
|
30
31
|
mapHookToRaindrop: () => mapHookToRaindrop,
|
|
31
32
|
mirrorEventToLocalDebugger: () => mirrorEventToLocalDebugger,
|
|
33
|
+
parseTranscript: () => parseTranscript,
|
|
34
|
+
transcriptToProperties: () => transcriptToProperties,
|
|
32
35
|
updateConfig: () => updateConfig
|
|
33
36
|
});
|
|
34
37
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -680,7 +683,7 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
|
|
|
680
683
|
|
|
681
684
|
// src/package-info.ts
|
|
682
685
|
var PACKAGE_NAME = "@raindrop-ai/claude-code";
|
|
683
|
-
var PACKAGE_VERSION = "0.0.
|
|
686
|
+
var PACKAGE_VERSION = "0.0.5";
|
|
684
687
|
|
|
685
688
|
// src/shipper.ts
|
|
686
689
|
var EventShipper2 = class extends EventShipper {
|
|
@@ -776,10 +779,145 @@ function updateConfig(patch) {
|
|
|
776
779
|
}
|
|
777
780
|
|
|
778
781
|
// src/event-mapper.ts
|
|
779
|
-
var
|
|
782
|
+
var import_node_fs3 = require("fs");
|
|
783
|
+
var import_node_child_process = require("child_process");
|
|
780
784
|
var import_node_crypto = require("crypto");
|
|
781
785
|
var import_node_os2 = require("os");
|
|
782
786
|
var import_node_path2 = require("path");
|
|
787
|
+
|
|
788
|
+
// src/transcript.ts
|
|
789
|
+
var import_node_fs2 = require("fs");
|
|
790
|
+
function parseTranscript(transcriptPath) {
|
|
791
|
+
var _a, _b, _c, _d, _e;
|
|
792
|
+
try {
|
|
793
|
+
if (!(0, import_node_fs2.existsSync)(transcriptPath)) return void 0;
|
|
794
|
+
const content = (0, import_node_fs2.readFileSync)(transcriptPath, "utf-8");
|
|
795
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
796
|
+
const summary = {
|
|
797
|
+
totalInputTokens: 0,
|
|
798
|
+
totalOutputTokens: 0,
|
|
799
|
+
totalCacheReadTokens: 0,
|
|
800
|
+
totalCacheCreationTokens: 0,
|
|
801
|
+
turnCount: 0,
|
|
802
|
+
toolsUsed: [],
|
|
803
|
+
hasThinking: false
|
|
804
|
+
};
|
|
805
|
+
const toolNames = /* @__PURE__ */ new Set();
|
|
806
|
+
let lastUsage;
|
|
807
|
+
for (const line of lines) {
|
|
808
|
+
let entry;
|
|
809
|
+
try {
|
|
810
|
+
entry = JSON.parse(line);
|
|
811
|
+
} catch (e) {
|
|
812
|
+
continue;
|
|
813
|
+
}
|
|
814
|
+
if (entry.type === "system" && entry.subtype === "turn_duration") {
|
|
815
|
+
const durationMs = entry["durationMs"];
|
|
816
|
+
if (typeof durationMs === "number") {
|
|
817
|
+
summary.totalDurationMs = ((_a = summary.totalDurationMs) != null ? _a : 0) + durationMs;
|
|
818
|
+
}
|
|
819
|
+
const version = entry["version"];
|
|
820
|
+
if (typeof version === "string") {
|
|
821
|
+
summary.codeVersion = version;
|
|
822
|
+
}
|
|
823
|
+
const branch = entry["gitBranch"];
|
|
824
|
+
if (typeof branch === "string") {
|
|
825
|
+
summary.gitBranch = branch;
|
|
826
|
+
}
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
if (entry.type !== "assistant") continue;
|
|
830
|
+
const msg = entry.message;
|
|
831
|
+
if (!msg) continue;
|
|
832
|
+
summary.turnCount++;
|
|
833
|
+
if (msg.model) {
|
|
834
|
+
summary.model = msg.model;
|
|
835
|
+
}
|
|
836
|
+
if (msg.stop_reason) {
|
|
837
|
+
summary.stopReason = msg.stop_reason;
|
|
838
|
+
}
|
|
839
|
+
const entryVersion = entry["version"];
|
|
840
|
+
if (typeof entryVersion === "string") {
|
|
841
|
+
summary.codeVersion = entryVersion;
|
|
842
|
+
}
|
|
843
|
+
const entryBranch = entry["gitBranch"];
|
|
844
|
+
if (typeof entryBranch === "string") {
|
|
845
|
+
summary.gitBranch = entryBranch;
|
|
846
|
+
}
|
|
847
|
+
if (msg.usage) {
|
|
848
|
+
const u = msg.usage;
|
|
849
|
+
summary.totalInputTokens += (_b = u.input_tokens) != null ? _b : 0;
|
|
850
|
+
summary.totalOutputTokens += (_c = u.output_tokens) != null ? _c : 0;
|
|
851
|
+
summary.totalCacheReadTokens += (_d = u.cache_read_input_tokens) != null ? _d : 0;
|
|
852
|
+
summary.totalCacheCreationTokens += (_e = u.cache_creation_input_tokens) != null ? _e : 0;
|
|
853
|
+
if (u.service_tier) {
|
|
854
|
+
summary.serviceTier = u.service_tier;
|
|
855
|
+
}
|
|
856
|
+
lastUsage = u;
|
|
857
|
+
}
|
|
858
|
+
if (Array.isArray(msg.content)) {
|
|
859
|
+
for (const block of msg.content) {
|
|
860
|
+
if (block.type === "tool_use" && block.name) {
|
|
861
|
+
toolNames.add(block.name);
|
|
862
|
+
}
|
|
863
|
+
if (block.type === "thinking") {
|
|
864
|
+
summary.hasThinking = true;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
if (lastUsage) {
|
|
870
|
+
summary.lastTurnInputTokens = lastUsage.input_tokens;
|
|
871
|
+
summary.lastTurnOutputTokens = lastUsage.output_tokens;
|
|
872
|
+
summary.lastTurnCacheReadTokens = lastUsage.cache_read_input_tokens;
|
|
873
|
+
}
|
|
874
|
+
summary.toolsUsed = [...toolNames].sort();
|
|
875
|
+
return summary;
|
|
876
|
+
} catch (e) {
|
|
877
|
+
return void 0;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
function transcriptToProperties(summary) {
|
|
881
|
+
var _a, _b;
|
|
882
|
+
const props = {};
|
|
883
|
+
props["ai.usage.prompt_tokens"] = (_a = summary.lastTurnInputTokens) != null ? _a : summary.totalInputTokens;
|
|
884
|
+
props["ai.usage.completion_tokens"] = (_b = summary.lastTurnOutputTokens) != null ? _b : summary.totalOutputTokens;
|
|
885
|
+
if (summary.lastTurnCacheReadTokens !== void 0) {
|
|
886
|
+
props["ai.usage.cache_read_tokens"] = summary.lastTurnCacheReadTokens;
|
|
887
|
+
}
|
|
888
|
+
props["ai.usage.session_total.prompt_tokens"] = summary.totalInputTokens;
|
|
889
|
+
props["ai.usage.session_total.completion_tokens"] = summary.totalOutputTokens;
|
|
890
|
+
props["ai.usage.session_total.cache_read_tokens"] = summary.totalCacheReadTokens;
|
|
891
|
+
props["ai.usage.session_total.cache_creation_tokens"] = summary.totalCacheCreationTokens;
|
|
892
|
+
if (summary.model) {
|
|
893
|
+
props["ai.model"] = summary.model;
|
|
894
|
+
}
|
|
895
|
+
if (summary.serviceTier) {
|
|
896
|
+
props["ai.service_tier"] = summary.serviceTier;
|
|
897
|
+
}
|
|
898
|
+
if (summary.stopReason) {
|
|
899
|
+
props["ai.stop_reason"] = summary.stopReason;
|
|
900
|
+
}
|
|
901
|
+
if (summary.toolsUsed.length > 0) {
|
|
902
|
+
props["ai.tools_used"] = summary.toolsUsed.join(", ");
|
|
903
|
+
}
|
|
904
|
+
props["ai.turn_count"] = summary.turnCount;
|
|
905
|
+
if (summary.totalDurationMs !== void 0) {
|
|
906
|
+
props["ai.duration_ms"] = summary.totalDurationMs;
|
|
907
|
+
}
|
|
908
|
+
if (summary.codeVersion) {
|
|
909
|
+
props["claude_code.version"] = summary.codeVersion;
|
|
910
|
+
}
|
|
911
|
+
if (summary.gitBranch) {
|
|
912
|
+
props["git.branch"] = summary.gitBranch;
|
|
913
|
+
}
|
|
914
|
+
if (summary.hasThinking) {
|
|
915
|
+
props["ai.has_thinking"] = true;
|
|
916
|
+
}
|
|
917
|
+
return props;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// src/event-mapper.ts
|
|
783
921
|
var MAX_ATTR_LENGTH = 32768;
|
|
784
922
|
function truncate(value) {
|
|
785
923
|
if (value === void 0) return void 0;
|
|
@@ -798,7 +936,7 @@ function safeStringify(value) {
|
|
|
798
936
|
var STATE_DIR = (0, import_node_path2.join)((0, import_node_os2.tmpdir)(), "raindrop-claude-code");
|
|
799
937
|
function ensureStateDir() {
|
|
800
938
|
try {
|
|
801
|
-
(0,
|
|
939
|
+
(0, import_node_fs3.mkdirSync)(STATE_DIR, { recursive: true });
|
|
802
940
|
} catch (e) {
|
|
803
941
|
}
|
|
804
942
|
}
|
|
@@ -816,22 +954,22 @@ function statePath(key) {
|
|
|
816
954
|
function writeState(key, value) {
|
|
817
955
|
try {
|
|
818
956
|
ensureStateDir();
|
|
819
|
-
(0,
|
|
957
|
+
(0, import_node_fs3.writeFileSync)(statePath(key), value, "utf-8");
|
|
820
958
|
} catch (e) {
|
|
821
959
|
}
|
|
822
960
|
}
|
|
823
961
|
function readState(key) {
|
|
824
962
|
try {
|
|
825
963
|
const filePath = statePath(key);
|
|
826
|
-
if (!(0,
|
|
827
|
-
return (0,
|
|
964
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return void 0;
|
|
965
|
+
return (0, import_node_fs3.readFileSync)(filePath, "utf-8");
|
|
828
966
|
} catch (e) {
|
|
829
967
|
return void 0;
|
|
830
968
|
}
|
|
831
969
|
}
|
|
832
970
|
function deleteState(key) {
|
|
833
971
|
try {
|
|
834
|
-
(0,
|
|
972
|
+
(0, import_node_fs3.unlinkSync)(statePath(key));
|
|
835
973
|
} catch (e) {
|
|
836
974
|
}
|
|
837
975
|
}
|
|
@@ -889,12 +1027,15 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
889
1027
|
cwd: payload.cwd,
|
|
890
1028
|
permission_mode: payload.permission_mode,
|
|
891
1029
|
plugin_version: PACKAGE_VERSION,
|
|
1030
|
+
sdk: PACKAGE_NAME,
|
|
1031
|
+
sdk_version: PACKAGE_VERSION,
|
|
892
1032
|
...payload.agent_id ? { agent_id: payload.agent_id } : {},
|
|
893
1033
|
...payload.agent_type ? { agent_type: payload.agent_type } : {}
|
|
894
1034
|
};
|
|
895
1035
|
switch (payload.hook_event_name) {
|
|
896
1036
|
case "SessionStart":
|
|
897
1037
|
writeState(`model_${payload.session_id}`, (_a = payload.model) != null ? _a : "");
|
|
1038
|
+
tryCaptureAppendSystemPrompt(payload.session_id);
|
|
898
1039
|
break;
|
|
899
1040
|
case "UserPromptSubmit":
|
|
900
1041
|
await handleUserPromptSubmit(payload, convoId, config, baseProperties, eventShipper, traceShipper);
|
|
@@ -909,10 +1050,13 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
909
1050
|
handlePostToolUseFailure(payload, getCurrentEventId(payload.session_id), traceShipper);
|
|
910
1051
|
break;
|
|
911
1052
|
case "Stop":
|
|
912
|
-
await
|
|
1053
|
+
await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper);
|
|
913
1054
|
break;
|
|
914
1055
|
case "StopFailure":
|
|
915
|
-
await
|
|
1056
|
+
await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper, {
|
|
1057
|
+
error: payload.error,
|
|
1058
|
+
error_details: payload.error_details
|
|
1059
|
+
});
|
|
916
1060
|
break;
|
|
917
1061
|
case "SubagentStart":
|
|
918
1062
|
handleSubagentStart(payload, getCurrentEventId(payload.session_id), traceShipper);
|
|
@@ -923,6 +1067,9 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
923
1067
|
case "PermissionDenied":
|
|
924
1068
|
handlePermissionDenied(payload, getCurrentEventId(payload.session_id), traceShipper);
|
|
925
1069
|
break;
|
|
1070
|
+
case "InstructionsLoaded":
|
|
1071
|
+
handleInstructionsLoaded(payload);
|
|
1072
|
+
break;
|
|
926
1073
|
case "PostCompact":
|
|
927
1074
|
await handlePostCompact(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
|
|
928
1075
|
break;
|
|
@@ -931,6 +1078,8 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
931
1078
|
deleteState(turnEventKey(payload.session_id));
|
|
932
1079
|
deleteState(rootSpanKey(payload.session_id));
|
|
933
1080
|
deleteState(`model_${payload.session_id}`);
|
|
1081
|
+
deleteState(appendSystemPromptKey(payload.session_id));
|
|
1082
|
+
cleanupInstructions(payload.session_id);
|
|
934
1083
|
break;
|
|
935
1084
|
default:
|
|
936
1085
|
if (config.debug) {
|
|
@@ -1088,25 +1237,243 @@ async function handlePostCompact(payload, eventId, config, properties, eventShip
|
|
|
1088
1237
|
}
|
|
1089
1238
|
});
|
|
1090
1239
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1240
|
+
function handleInstructionsLoaded(payload) {
|
|
1241
|
+
var _a;
|
|
1242
|
+
if (!payload.file_path || !payload.session_id) return;
|
|
1243
|
+
try {
|
|
1244
|
+
if ((0, import_node_fs3.existsSync)(payload.file_path)) {
|
|
1245
|
+
const content = (0, import_node_fs3.readFileSync)(payload.file_path, "utf-8");
|
|
1246
|
+
const MAX_INSTRUCTIONS_LENGTH = 8192;
|
|
1247
|
+
const truncated = content.length > MAX_INSTRUCTIONS_LENGTH ? content.slice(0, MAX_INSTRUCTIONS_LENGTH) + "\n...[truncated]" : content;
|
|
1248
|
+
const fileKey = safeKey(payload.file_path);
|
|
1249
|
+
const header = `# ${(_a = payload.memory_type) != null ? _a : "instructions"}: ${payload.file_path}
|
|
1250
|
+
`;
|
|
1251
|
+
writeState(
|
|
1252
|
+
`instr_${payload.session_id}_${fileKey}`,
|
|
1253
|
+
header + truncated
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
} catch (e) {
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
function gatherInstructions(sessionId) {
|
|
1260
|
+
try {
|
|
1261
|
+
if (!(0, import_node_fs3.existsSync)(STATE_DIR)) return void 0;
|
|
1262
|
+
const prefix = safeKey(`instr_${sessionId}_`);
|
|
1263
|
+
const files = (0, import_node_fs3.readdirSync)(STATE_DIR).filter((f) => f.startsWith(prefix));
|
|
1264
|
+
if (files.length === 0) return void 0;
|
|
1265
|
+
const parts = [];
|
|
1266
|
+
for (const file of files.sort()) {
|
|
1267
|
+
try {
|
|
1268
|
+
parts.push((0, import_node_fs3.readFileSync)((0, import_node_path2.join)(STATE_DIR, file), "utf-8"));
|
|
1269
|
+
} catch (e) {
|
|
1270
|
+
continue;
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
return parts.length > 0 ? parts.join("\n\n---\n\n") : void 0;
|
|
1274
|
+
} catch (e) {
|
|
1275
|
+
return void 0;
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
function cleanupInstructions(sessionId) {
|
|
1279
|
+
try {
|
|
1280
|
+
if (!(0, import_node_fs3.existsSync)(STATE_DIR)) return;
|
|
1281
|
+
const prefix = safeKey(`instr_${sessionId}_`);
|
|
1282
|
+
for (const file of (0, import_node_fs3.readdirSync)(STATE_DIR).filter((f) => f.startsWith(prefix))) {
|
|
1283
|
+
try {
|
|
1284
|
+
(0, import_node_fs3.unlinkSync)((0, import_node_path2.join)(STATE_DIR, file));
|
|
1285
|
+
} catch (e) {
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
} catch (e) {
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
var APPEND_FLAG = "--append-system-prompt";
|
|
1292
|
+
var APPEND_FILE_FLAG = "--append-system-prompt-file";
|
|
1293
|
+
var MAX_ANCESTOR_DEPTH = 15;
|
|
1294
|
+
var PS_TIMEOUT_MS = 3e3;
|
|
1295
|
+
function appendSystemPromptKey(sessionId) {
|
|
1296
|
+
return `append_sysprompt_${sessionId}`;
|
|
1099
1297
|
}
|
|
1100
|
-
|
|
1298
|
+
function tryCaptureAppendSystemPrompt(sessionId) {
|
|
1299
|
+
try {
|
|
1300
|
+
const content = readAncestorAppendSystemPrompt();
|
|
1301
|
+
if (content) {
|
|
1302
|
+
writeState(appendSystemPromptKey(sessionId), content);
|
|
1303
|
+
}
|
|
1304
|
+
} catch (e) {
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
function readAncestorAppendSystemPrompt() {
|
|
1308
|
+
let pid;
|
|
1309
|
+
try {
|
|
1310
|
+
pid = process.ppid;
|
|
1311
|
+
} catch (e) {
|
|
1312
|
+
return void 0;
|
|
1313
|
+
}
|
|
1314
|
+
if (!pid || pid <= 1) return void 0;
|
|
1315
|
+
for (let depth = 0; depth < MAX_ANCESTOR_DEPTH && pid != null && pid > 1; depth++) {
|
|
1316
|
+
try {
|
|
1317
|
+
const args = getProcessArgs(pid);
|
|
1318
|
+
if (args && args.length > 0) {
|
|
1319
|
+
const content = extractAppendSystemPrompt(args);
|
|
1320
|
+
if (content) return content;
|
|
1321
|
+
}
|
|
1322
|
+
} catch (e) {
|
|
1323
|
+
}
|
|
1324
|
+
try {
|
|
1325
|
+
pid = getParentPid(pid);
|
|
1326
|
+
} catch (e) {
|
|
1327
|
+
break;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
return void 0;
|
|
1331
|
+
}
|
|
1332
|
+
function getProcessArgs(pid) {
|
|
1333
|
+
if (process.platform === "linux") {
|
|
1334
|
+
try {
|
|
1335
|
+
const raw = (0, import_node_fs3.readFileSync)(`/proc/${pid}/cmdline`, "utf-8");
|
|
1336
|
+
const args = raw.split("\0").filter(Boolean);
|
|
1337
|
+
return args.length > 0 ? args : void 0;
|
|
1338
|
+
} catch (e) {
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
try {
|
|
1342
|
+
const output = (0, import_node_child_process.execSync)(`ps -ww -o args= -p ${pid}`, {
|
|
1343
|
+
encoding: "utf-8",
|
|
1344
|
+
timeout: PS_TIMEOUT_MS,
|
|
1345
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1346
|
+
});
|
|
1347
|
+
const trimmed = output.trim();
|
|
1348
|
+
if (!trimmed) return void 0;
|
|
1349
|
+
return trimmed.split(/\s+/);
|
|
1350
|
+
} catch (e) {
|
|
1351
|
+
return void 0;
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
function getParentPid(pid) {
|
|
1355
|
+
try {
|
|
1356
|
+
const output = (0, import_node_child_process.execSync)(`ps -o ppid= -p ${pid}`, {
|
|
1357
|
+
encoding: "utf-8",
|
|
1358
|
+
timeout: PS_TIMEOUT_MS,
|
|
1359
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1360
|
+
});
|
|
1361
|
+
const ppid = parseInt(output.trim(), 10);
|
|
1362
|
+
return Number.isFinite(ppid) && ppid > 0 ? ppid : void 0;
|
|
1363
|
+
} catch (e) {
|
|
1364
|
+
return void 0;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
function extractAppendSystemPrompt(args) {
|
|
1368
|
+
const parts = [];
|
|
1369
|
+
for (let i = 0; i < args.length; i++) {
|
|
1370
|
+
const arg = args[i];
|
|
1371
|
+
try {
|
|
1372
|
+
if (arg === APPEND_FILE_FLAG && i + 1 < args.length) {
|
|
1373
|
+
const filePath = args[i + 1];
|
|
1374
|
+
i++;
|
|
1375
|
+
try {
|
|
1376
|
+
if ((0, import_node_fs3.existsSync)(filePath)) {
|
|
1377
|
+
parts.push((0, import_node_fs3.readFileSync)(filePath, "utf-8"));
|
|
1378
|
+
}
|
|
1379
|
+
} catch (e) {
|
|
1380
|
+
}
|
|
1381
|
+
continue;
|
|
1382
|
+
}
|
|
1383
|
+
if (arg.startsWith(APPEND_FILE_FLAG + "=")) {
|
|
1384
|
+
const filePath = arg.slice(APPEND_FILE_FLAG.length + 1);
|
|
1385
|
+
try {
|
|
1386
|
+
if (filePath && (0, import_node_fs3.existsSync)(filePath)) {
|
|
1387
|
+
parts.push((0, import_node_fs3.readFileSync)(filePath, "utf-8"));
|
|
1388
|
+
}
|
|
1389
|
+
} catch (e) {
|
|
1390
|
+
}
|
|
1391
|
+
continue;
|
|
1392
|
+
}
|
|
1393
|
+
if (arg === APPEND_FLAG && i + 1 < args.length) {
|
|
1394
|
+
const valueParts = [];
|
|
1395
|
+
for (let j = i + 1; j < args.length; j++) {
|
|
1396
|
+
if (args[j].startsWith("--")) break;
|
|
1397
|
+
valueParts.push(args[j]);
|
|
1398
|
+
i = j;
|
|
1399
|
+
}
|
|
1400
|
+
if (valueParts.length > 0) {
|
|
1401
|
+
parts.push(valueParts.join(" "));
|
|
1402
|
+
}
|
|
1403
|
+
continue;
|
|
1404
|
+
}
|
|
1405
|
+
if (arg.startsWith(APPEND_FLAG + "=") && !arg.startsWith(APPEND_FILE_FLAG)) {
|
|
1406
|
+
const value = arg.slice(APPEND_FLAG.length + 1);
|
|
1407
|
+
if (value) {
|
|
1408
|
+
parts.push(value);
|
|
1409
|
+
}
|
|
1410
|
+
continue;
|
|
1411
|
+
}
|
|
1412
|
+
} catch (e) {
|
|
1413
|
+
continue;
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return parts.length > 0 ? parts.join("\n") : void 0;
|
|
1417
|
+
}
|
|
1418
|
+
function readAppendSystemPrompt(sessionId) {
|
|
1419
|
+
try {
|
|
1420
|
+
return readState(appendSystemPromptKey(sessionId)) || void 0;
|
|
1421
|
+
} catch (e) {
|
|
1422
|
+
return void 0;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
function enrichFromTranscript(payload, eventId, traceShipper) {
|
|
1426
|
+
var _a, _b;
|
|
1427
|
+
if (!payload.transcript_path) {
|
|
1428
|
+
return { summary: void 0, props: {} };
|
|
1429
|
+
}
|
|
1430
|
+
try {
|
|
1431
|
+
const summary = parseTranscript(payload.transcript_path);
|
|
1432
|
+
if (!summary) return { summary: void 0, props: {} };
|
|
1433
|
+
const props = transcriptToProperties(summary);
|
|
1434
|
+
const spanInputTokens = (_a = summary.lastTurnInputTokens) != null ? _a : summary.totalInputTokens;
|
|
1435
|
+
const spanOutputTokens = (_b = summary.lastTurnOutputTokens) != null ? _b : summary.totalOutputTokens;
|
|
1436
|
+
if (summary.model && (spanInputTokens > 0 || spanOutputTokens > 0)) {
|
|
1437
|
+
const parent = getParentContext(payload);
|
|
1438
|
+
const now = nowUnixNanoString();
|
|
1439
|
+
traceShipper.createSpan({
|
|
1440
|
+
name: summary.model,
|
|
1441
|
+
eventId,
|
|
1442
|
+
parent,
|
|
1443
|
+
startTimeUnixNano: now,
|
|
1444
|
+
endTimeUnixNano: now,
|
|
1445
|
+
attributes: [
|
|
1446
|
+
attrString("ai.operationId", "generateText"),
|
|
1447
|
+
attrString("gen_ai.response.model", summary.model),
|
|
1448
|
+
attrString("gen_ai.system", "anthropic"),
|
|
1449
|
+
attrInt("gen_ai.usage.prompt_tokens", spanInputTokens),
|
|
1450
|
+
attrInt("gen_ai.usage.completion_tokens", spanOutputTokens),
|
|
1451
|
+
...summary.lastTurnCacheReadTokens != null && summary.lastTurnCacheReadTokens > 0 ? [attrInt("gen_ai.usage.cache_read_tokens", summary.lastTurnCacheReadTokens)] : []
|
|
1452
|
+
]
|
|
1453
|
+
});
|
|
1454
|
+
}
|
|
1455
|
+
return { summary, props };
|
|
1456
|
+
} catch (e) {
|
|
1457
|
+
return { summary: void 0, props: {} };
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
async function handleStopOrFailure(payload, eventId, config, properties, eventShipper, traceShipper, extraProperties) {
|
|
1461
|
+
const { summary, props: transcriptProps } = enrichFromTranscript(payload, eventId, traceShipper);
|
|
1462
|
+
const instructions = gatherInstructions(payload.session_id);
|
|
1463
|
+
const appendSysPrompt = readAppendSystemPrompt(payload.session_id);
|
|
1101
1464
|
await eventShipper.patch(eventId, {
|
|
1102
1465
|
isPending: false,
|
|
1103
1466
|
userId: config.userId,
|
|
1467
|
+
convoId: payload.session_id,
|
|
1104
1468
|
eventName: config.eventName,
|
|
1105
1469
|
output: payload.last_assistant_message,
|
|
1470
|
+
...(summary == null ? void 0 : summary.model) ? { model: summary.model } : {},
|
|
1106
1471
|
properties: {
|
|
1107
1472
|
...properties,
|
|
1108
|
-
|
|
1109
|
-
|
|
1473
|
+
...transcriptProps,
|
|
1474
|
+
...instructions ? { system_instructions: truncate(instructions) } : {},
|
|
1475
|
+
...appendSysPrompt ? { append_system_prompt: truncate(appendSysPrompt) } : {},
|
|
1476
|
+
...extraProperties
|
|
1110
1477
|
}
|
|
1111
1478
|
});
|
|
1112
1479
|
}
|
|
@@ -1123,7 +1490,7 @@ async function handleSessionEnd(payload, eventId, config, properties, eventShipp
|
|
|
1123
1490
|
}
|
|
1124
1491
|
|
|
1125
1492
|
// src/local-debugger.ts
|
|
1126
|
-
var
|
|
1493
|
+
var import_node_fs4 = require("fs");
|
|
1127
1494
|
var import_node_os3 = require("os");
|
|
1128
1495
|
var import_node_path3 = require("path");
|
|
1129
1496
|
var DEFAULT_PORT = 5899;
|
|
@@ -1134,8 +1501,8 @@ var CACHE_FILE = (0, import_node_path3.join)(CACHE_DIR, "debugger_cache");
|
|
|
1134
1501
|
var CACHE_TTL_MS = 5e3;
|
|
1135
1502
|
function readCache() {
|
|
1136
1503
|
try {
|
|
1137
|
-
if (!(0,
|
|
1138
|
-
const data = JSON.parse((0,
|
|
1504
|
+
if (!(0, import_node_fs4.existsSync)(CACHE_FILE)) return void 0;
|
|
1505
|
+
const data = JSON.parse((0, import_node_fs4.readFileSync)(CACHE_FILE, "utf-8"));
|
|
1139
1506
|
if (Date.now() - data.ts > CACHE_TTL_MS) return void 0;
|
|
1140
1507
|
return data;
|
|
1141
1508
|
} catch (e) {
|
|
@@ -1144,8 +1511,8 @@ function readCache() {
|
|
|
1144
1511
|
}
|
|
1145
1512
|
function writeCache(url) {
|
|
1146
1513
|
try {
|
|
1147
|
-
(0,
|
|
1148
|
-
(0,
|
|
1514
|
+
(0, import_node_fs4.mkdirSync)(CACHE_DIR, { recursive: true });
|
|
1515
|
+
(0, import_node_fs4.writeFileSync)(CACHE_FILE, JSON.stringify({ url, ts: Date.now() }), "utf-8");
|
|
1149
1516
|
} catch (e) {
|
|
1150
1517
|
}
|
|
1151
1518
|
}
|
|
@@ -1209,9 +1576,12 @@ function mirrorEventToLocalDebugger(baseUrl, payload, debug) {
|
|
|
1209
1576
|
PACKAGE_VERSION,
|
|
1210
1577
|
TraceShipper,
|
|
1211
1578
|
detectLocalDebugger,
|
|
1579
|
+
extractAppendSystemPrompt,
|
|
1212
1580
|
getConfigPath,
|
|
1213
1581
|
loadConfig,
|
|
1214
1582
|
mapHookToRaindrop,
|
|
1215
1583
|
mirrorEventToLocalDebugger,
|
|
1584
|
+
parseTranscript,
|
|
1585
|
+
transcriptToProperties,
|
|
1216
1586
|
updateConfig
|
|
1217
1587
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -275,6 +275,9 @@ interface HookPayload {
|
|
|
275
275
|
agent_transcript_path?: string;
|
|
276
276
|
trigger?: string;
|
|
277
277
|
compact_summary?: string;
|
|
278
|
+
file_path?: string;
|
|
279
|
+
memory_type?: string;
|
|
280
|
+
load_reason?: string;
|
|
278
281
|
}
|
|
279
282
|
interface MapperConfig {
|
|
280
283
|
userId: string;
|
|
@@ -283,9 +286,58 @@ interface MapperConfig {
|
|
|
283
286
|
customProperties: Record<string, unknown>;
|
|
284
287
|
}
|
|
285
288
|
declare function mapHookToRaindrop(payload: HookPayload, config: MapperConfig, eventShipper: EventShipper, traceShipper: TraceShipper): Promise<void>;
|
|
289
|
+
/**
|
|
290
|
+
* Parse command-line args for --append-system-prompt and
|
|
291
|
+
* --append-system-prompt-file flags. Handles both space-separated form
|
|
292
|
+
* (--flag value) and equals form (--flag=value). Supports both flags
|
|
293
|
+
* appearing together (they concatenate).
|
|
294
|
+
*
|
|
295
|
+
* Exported for testing.
|
|
296
|
+
*/
|
|
297
|
+
declare function extractAppendSystemPrompt(args: string[]): string | undefined;
|
|
286
298
|
|
|
287
299
|
declare const PACKAGE_NAME = "@raindrop-ai/claude-code";
|
|
288
|
-
declare const PACKAGE_VERSION = "0.0.
|
|
300
|
+
declare const PACKAGE_VERSION = "0.0.5";
|
|
301
|
+
|
|
302
|
+
interface TranscriptSummary {
|
|
303
|
+
/** Aggregated token usage across all turns */
|
|
304
|
+
totalInputTokens: number;
|
|
305
|
+
totalOutputTokens: number;
|
|
306
|
+
totalCacheReadTokens: number;
|
|
307
|
+
totalCacheCreationTokens: number;
|
|
308
|
+
/** Token usage for the most recent turn only */
|
|
309
|
+
lastTurnInputTokens?: number;
|
|
310
|
+
lastTurnOutputTokens?: number;
|
|
311
|
+
lastTurnCacheReadTokens?: number;
|
|
312
|
+
/** Model used (from most recent assistant message) */
|
|
313
|
+
model?: string;
|
|
314
|
+
/** Service tier */
|
|
315
|
+
serviceTier?: string;
|
|
316
|
+
/** Number of API turns (assistant messages) */
|
|
317
|
+
turnCount: number;
|
|
318
|
+
/** Unique tool names used in the session */
|
|
319
|
+
toolsUsed: string[];
|
|
320
|
+
/** Stop reason from last assistant message */
|
|
321
|
+
stopReason?: string;
|
|
322
|
+
/** Total turn duration in ms (from system entries) */
|
|
323
|
+
totalDurationMs?: number;
|
|
324
|
+
/** Claude Code version */
|
|
325
|
+
codeVersion?: string;
|
|
326
|
+
/** Git branch */
|
|
327
|
+
gitBranch?: string;
|
|
328
|
+
/** Whether thinking/reasoning content was used */
|
|
329
|
+
hasThinking: boolean;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Parse a Claude Code transcript JSONL file and extract a summary.
|
|
333
|
+
* Returns undefined if the file doesn't exist or can't be parsed.
|
|
334
|
+
*/
|
|
335
|
+
declare function parseTranscript(transcriptPath: string): TranscriptSummary | undefined;
|
|
336
|
+
/**
|
|
337
|
+
* Convert a TranscriptSummary into a flat properties object
|
|
338
|
+
* suitable for merging into event properties.
|
|
339
|
+
*/
|
|
340
|
+
declare function transcriptToProperties(summary: TranscriptSummary): Record<string, unknown>;
|
|
289
341
|
|
|
290
342
|
interface LocalDebuggerResult {
|
|
291
343
|
/** The resolved base URL (e.g. "http://localhost:5899/v1/"), or null if not detected. */
|
|
@@ -308,4 +360,4 @@ declare function detectLocalDebugger(debug: boolean): Promise<LocalDebuggerResul
|
|
|
308
360
|
*/
|
|
309
361
|
declare function mirrorEventToLocalDebugger(baseUrl: string, payload: Record<string, unknown>, debug: boolean): void;
|
|
310
362
|
|
|
311
|
-
export { EventShipper, type HookPayload, type LocalDebuggerResult, type MapperConfig, PACKAGE_NAME, PACKAGE_VERSION, type RaindropConfig, type SetupScope, TraceShipper, detectLocalDebugger, getConfigPath, loadConfig, mapHookToRaindrop, mirrorEventToLocalDebugger, updateConfig };
|
|
363
|
+
export { EventShipper, type HookPayload, type LocalDebuggerResult, type MapperConfig, PACKAGE_NAME, PACKAGE_VERSION, type RaindropConfig, type SetupScope, TraceShipper, type TranscriptSummary, detectLocalDebugger, extractAppendSystemPrompt, getConfigPath, loadConfig, mapHookToRaindrop, mirrorEventToLocalDebugger, parseTranscript, transcriptToProperties, updateConfig };
|