@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/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.4";
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 import_node_fs2 = require("fs");
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, import_node_fs2.mkdirSync)(STATE_DIR, { recursive: true });
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, import_node_fs2.writeFileSync)(statePath(key), value, "utf-8");
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, import_node_fs2.existsSync)(filePath)) return void 0;
827
- return (0, import_node_fs2.readFileSync)(filePath, "utf-8");
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, import_node_fs2.unlinkSync)(statePath(key));
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 handleStop(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
1053
+ await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper);
913
1054
  break;
914
1055
  case "StopFailure":
915
- await handleStopFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
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
- async function handleStop(payload, eventId, config, properties, eventShipper) {
1092
- await eventShipper.patch(eventId, {
1093
- isPending: false,
1094
- userId: config.userId,
1095
- eventName: config.eventName,
1096
- output: payload.last_assistant_message,
1097
- properties
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
- async function handleStopFailure(payload, eventId, config, properties, eventShipper) {
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
- error: payload.error,
1109
- error_details: payload.error_details
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 import_node_fs3 = require("fs");
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, import_node_fs3.existsSync)(CACHE_FILE)) return void 0;
1138
- const data = JSON.parse((0, import_node_fs3.readFileSync)(CACHE_FILE, "utf-8"));
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, import_node_fs3.mkdirSync)(CACHE_DIR, { recursive: true });
1148
- (0, import_node_fs3.writeFileSync)(CACHE_FILE, JSON.stringify({ url, ts: Date.now() }), "utf-8");
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.4";
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 };