@raindrop-ai/claude-code 0.0.3 → 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.js CHANGED
@@ -645,7 +645,7 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
645
645
 
646
646
  // src/package-info.ts
647
647
  var PACKAGE_NAME = "@raindrop-ai/claude-code";
648
- var PACKAGE_VERSION = "0.0.1";
648
+ var PACKAGE_VERSION = "0.0.5";
649
649
 
650
650
  // src/shipper.ts
651
651
  var EventShipper2 = class extends EventShipper {
@@ -688,7 +688,7 @@ import { homedir, userInfo } from "os";
688
688
  import { dirname, join } from "path";
689
689
  var CONFIG_PATH = join(homedir(), ".config", "raindrop", "config.json");
690
690
  function loadConfig() {
691
- var _a, _b, _c, _d, _e, _f, _g, _h;
691
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
692
692
  let file = {};
693
693
  try {
694
694
  if (existsSync(CONFIG_PATH)) {
@@ -703,12 +703,25 @@ function loadConfig() {
703
703
  return "unknown";
704
704
  }
705
705
  })();
706
+ let customProperties = (_a = file.custom_properties) != null ? _a : {};
707
+ const envProps = process.env["RAINDROP_PROPERTIES"];
708
+ if (envProps) {
709
+ try {
710
+ const parsed = JSON.parse(envProps);
711
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
712
+ customProperties = { ...customProperties, ...parsed };
713
+ }
714
+ } catch (e) {
715
+ }
716
+ }
706
717
  return {
707
- writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : file.write_key) != null ? _b : "",
708
- endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : file.api_url) != null ? _d : "https://api.raindrop.ai/v1",
709
- userId: (_f = (_e = process.env["RAINDROP_USER_ID"]) != null ? _e : file.user_id) != null ? _f : systemUser,
710
- debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_g = file.debug) != null ? _g : false,
711
- enabled: (_h = file.enabled) != null ? _h : true
718
+ writeKey: (_c = (_b = process.env["RAINDROP_WRITE_KEY"]) != null ? _b : file.write_key) != null ? _c : "",
719
+ endpoint: (_e = (_d = process.env["RAINDROP_API_URL"]) != null ? _d : file.api_url) != null ? _e : "https://api.raindrop.ai/v1",
720
+ userId: (_g = (_f = process.env["RAINDROP_USER_ID"]) != null ? _f : file.user_id) != null ? _g : systemUser,
721
+ debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_h = file.debug) != null ? _h : false,
722
+ enabled: (_i = file.enabled) != null ? _i : true,
723
+ eventName: (_k = (_j = process.env["RAINDROP_EVENT_NAME"]) != null ? _j : file.event_name) != null ? _k : "claude_code_session",
724
+ customProperties
712
725
  };
713
726
  }
714
727
  function getConfigPath() {
@@ -728,10 +741,145 @@ function updateConfig(patch) {
728
741
  }
729
742
 
730
743
  // src/event-mapper.ts
731
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
744
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
745
+ import { execSync } from "child_process";
732
746
  import { randomUUID as randomUUID2 } from "crypto";
733
747
  import { tmpdir } from "os";
734
748
  import { join as join2 } from "path";
749
+
750
+ // src/transcript.ts
751
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
752
+ function parseTranscript(transcriptPath) {
753
+ var _a, _b, _c, _d, _e;
754
+ try {
755
+ if (!existsSync2(transcriptPath)) return void 0;
756
+ const content = readFileSync2(transcriptPath, "utf-8");
757
+ const lines = content.split("\n").filter((l) => l.trim());
758
+ const summary = {
759
+ totalInputTokens: 0,
760
+ totalOutputTokens: 0,
761
+ totalCacheReadTokens: 0,
762
+ totalCacheCreationTokens: 0,
763
+ turnCount: 0,
764
+ toolsUsed: [],
765
+ hasThinking: false
766
+ };
767
+ const toolNames = /* @__PURE__ */ new Set();
768
+ let lastUsage;
769
+ for (const line of lines) {
770
+ let entry;
771
+ try {
772
+ entry = JSON.parse(line);
773
+ } catch (e) {
774
+ continue;
775
+ }
776
+ if (entry.type === "system" && entry.subtype === "turn_duration") {
777
+ const durationMs = entry["durationMs"];
778
+ if (typeof durationMs === "number") {
779
+ summary.totalDurationMs = ((_a = summary.totalDurationMs) != null ? _a : 0) + durationMs;
780
+ }
781
+ const version = entry["version"];
782
+ if (typeof version === "string") {
783
+ summary.codeVersion = version;
784
+ }
785
+ const branch = entry["gitBranch"];
786
+ if (typeof branch === "string") {
787
+ summary.gitBranch = branch;
788
+ }
789
+ continue;
790
+ }
791
+ if (entry.type !== "assistant") continue;
792
+ const msg = entry.message;
793
+ if (!msg) continue;
794
+ summary.turnCount++;
795
+ if (msg.model) {
796
+ summary.model = msg.model;
797
+ }
798
+ if (msg.stop_reason) {
799
+ summary.stopReason = msg.stop_reason;
800
+ }
801
+ const entryVersion = entry["version"];
802
+ if (typeof entryVersion === "string") {
803
+ summary.codeVersion = entryVersion;
804
+ }
805
+ const entryBranch = entry["gitBranch"];
806
+ if (typeof entryBranch === "string") {
807
+ summary.gitBranch = entryBranch;
808
+ }
809
+ if (msg.usage) {
810
+ const u = msg.usage;
811
+ summary.totalInputTokens += (_b = u.input_tokens) != null ? _b : 0;
812
+ summary.totalOutputTokens += (_c = u.output_tokens) != null ? _c : 0;
813
+ summary.totalCacheReadTokens += (_d = u.cache_read_input_tokens) != null ? _d : 0;
814
+ summary.totalCacheCreationTokens += (_e = u.cache_creation_input_tokens) != null ? _e : 0;
815
+ if (u.service_tier) {
816
+ summary.serviceTier = u.service_tier;
817
+ }
818
+ lastUsage = u;
819
+ }
820
+ if (Array.isArray(msg.content)) {
821
+ for (const block of msg.content) {
822
+ if (block.type === "tool_use" && block.name) {
823
+ toolNames.add(block.name);
824
+ }
825
+ if (block.type === "thinking") {
826
+ summary.hasThinking = true;
827
+ }
828
+ }
829
+ }
830
+ }
831
+ if (lastUsage) {
832
+ summary.lastTurnInputTokens = lastUsage.input_tokens;
833
+ summary.lastTurnOutputTokens = lastUsage.output_tokens;
834
+ summary.lastTurnCacheReadTokens = lastUsage.cache_read_input_tokens;
835
+ }
836
+ summary.toolsUsed = [...toolNames].sort();
837
+ return summary;
838
+ } catch (e) {
839
+ return void 0;
840
+ }
841
+ }
842
+ function transcriptToProperties(summary) {
843
+ var _a, _b;
844
+ const props = {};
845
+ props["ai.usage.prompt_tokens"] = (_a = summary.lastTurnInputTokens) != null ? _a : summary.totalInputTokens;
846
+ props["ai.usage.completion_tokens"] = (_b = summary.lastTurnOutputTokens) != null ? _b : summary.totalOutputTokens;
847
+ if (summary.lastTurnCacheReadTokens !== void 0) {
848
+ props["ai.usage.cache_read_tokens"] = summary.lastTurnCacheReadTokens;
849
+ }
850
+ props["ai.usage.session_total.prompt_tokens"] = summary.totalInputTokens;
851
+ props["ai.usage.session_total.completion_tokens"] = summary.totalOutputTokens;
852
+ props["ai.usage.session_total.cache_read_tokens"] = summary.totalCacheReadTokens;
853
+ props["ai.usage.session_total.cache_creation_tokens"] = summary.totalCacheCreationTokens;
854
+ if (summary.model) {
855
+ props["ai.model"] = summary.model;
856
+ }
857
+ if (summary.serviceTier) {
858
+ props["ai.service_tier"] = summary.serviceTier;
859
+ }
860
+ if (summary.stopReason) {
861
+ props["ai.stop_reason"] = summary.stopReason;
862
+ }
863
+ if (summary.toolsUsed.length > 0) {
864
+ props["ai.tools_used"] = summary.toolsUsed.join(", ");
865
+ }
866
+ props["ai.turn_count"] = summary.turnCount;
867
+ if (summary.totalDurationMs !== void 0) {
868
+ props["ai.duration_ms"] = summary.totalDurationMs;
869
+ }
870
+ if (summary.codeVersion) {
871
+ props["claude_code.version"] = summary.codeVersion;
872
+ }
873
+ if (summary.gitBranch) {
874
+ props["git.branch"] = summary.gitBranch;
875
+ }
876
+ if (summary.hasThinking) {
877
+ props["ai.has_thinking"] = true;
878
+ }
879
+ return props;
880
+ }
881
+
882
+ // src/event-mapper.ts
735
883
  var MAX_ATTR_LENGTH = 32768;
736
884
  function truncate(value) {
737
885
  if (value === void 0) return void 0;
@@ -775,8 +923,8 @@ function writeState(key, value) {
775
923
  function readState(key) {
776
924
  try {
777
925
  const filePath = statePath(key);
778
- if (!existsSync2(filePath)) return void 0;
779
- return readFileSync2(filePath, "utf-8");
926
+ if (!existsSync3(filePath)) return void 0;
927
+ return readFileSync3(filePath, "utf-8");
780
928
  } catch (e) {
781
929
  return void 0;
782
930
  }
@@ -837,15 +985,19 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
837
985
  var _a;
838
986
  const convoId = payload.session_id;
839
987
  const baseProperties = {
988
+ ...config.customProperties,
840
989
  cwd: payload.cwd,
841
990
  permission_mode: payload.permission_mode,
842
991
  plugin_version: PACKAGE_VERSION,
992
+ sdk: PACKAGE_NAME,
993
+ sdk_version: PACKAGE_VERSION,
843
994
  ...payload.agent_id ? { agent_id: payload.agent_id } : {},
844
995
  ...payload.agent_type ? { agent_type: payload.agent_type } : {}
845
996
  };
846
997
  switch (payload.hook_event_name) {
847
998
  case "SessionStart":
848
999
  writeState(`model_${payload.session_id}`, (_a = payload.model) != null ? _a : "");
1000
+ tryCaptureAppendSystemPrompt(payload.session_id);
849
1001
  break;
850
1002
  case "UserPromptSubmit":
851
1003
  await handleUserPromptSubmit(payload, convoId, config, baseProperties, eventShipper, traceShipper);
@@ -860,10 +1012,13 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
860
1012
  handlePostToolUseFailure(payload, getCurrentEventId(payload.session_id), traceShipper);
861
1013
  break;
862
1014
  case "Stop":
863
- await handleStop(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
1015
+ await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper);
864
1016
  break;
865
1017
  case "StopFailure":
866
- await handleStopFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
1018
+ await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper, {
1019
+ error: payload.error,
1020
+ error_details: payload.error_details
1021
+ });
867
1022
  break;
868
1023
  case "SubagentStart":
869
1024
  handleSubagentStart(payload, getCurrentEventId(payload.session_id), traceShipper);
@@ -874,6 +1029,9 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
874
1029
  case "PermissionDenied":
875
1030
  handlePermissionDenied(payload, getCurrentEventId(payload.session_id), traceShipper);
876
1031
  break;
1032
+ case "InstructionsLoaded":
1033
+ handleInstructionsLoaded(payload);
1034
+ break;
877
1035
  case "PostCompact":
878
1036
  await handlePostCompact(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
879
1037
  break;
@@ -882,6 +1040,8 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
882
1040
  deleteState(turnEventKey(payload.session_id));
883
1041
  deleteState(rootSpanKey(payload.session_id));
884
1042
  deleteState(`model_${payload.session_id}`);
1043
+ deleteState(appendSystemPromptKey(payload.session_id));
1044
+ cleanupInstructions(payload.session_id);
885
1045
  break;
886
1046
  default:
887
1047
  if (config.debug) {
@@ -911,7 +1071,7 @@ async function handleUserPromptSubmit(payload, convoId, config, properties, even
911
1071
  isPending: true,
912
1072
  userId: config.userId,
913
1073
  convoId,
914
- eventName: "claude_code_session",
1074
+ eventName: config.eventName,
915
1075
  input: payload.prompt,
916
1076
  model,
917
1077
  properties
@@ -1031,7 +1191,7 @@ async function handlePostCompact(payload, eventId, config, properties, eventShip
1031
1191
  isPending: true,
1032
1192
  userId: config.userId,
1033
1193
  convoId: payload.session_id,
1034
- eventName: "claude_code_session",
1194
+ eventName: config.eventName,
1035
1195
  properties: {
1036
1196
  ...properties,
1037
1197
  compaction_trigger: payload.trigger,
@@ -1039,27 +1199,251 @@ async function handlePostCompact(payload, eventId, config, properties, eventShip
1039
1199
  }
1040
1200
  });
1041
1201
  }
1042
- async function handleStop(payload, eventId, config, properties, eventShipper) {
1043
- await eventShipper.finish(eventId, {
1044
- userId: config.userId,
1045
- output: payload.last_assistant_message,
1046
- properties
1047
- });
1202
+ function handleInstructionsLoaded(payload) {
1203
+ var _a;
1204
+ if (!payload.file_path || !payload.session_id) return;
1205
+ try {
1206
+ if (existsSync3(payload.file_path)) {
1207
+ const content = readFileSync3(payload.file_path, "utf-8");
1208
+ const MAX_INSTRUCTIONS_LENGTH = 8192;
1209
+ const truncated = content.length > MAX_INSTRUCTIONS_LENGTH ? content.slice(0, MAX_INSTRUCTIONS_LENGTH) + "\n...[truncated]" : content;
1210
+ const fileKey = safeKey(payload.file_path);
1211
+ const header = `# ${(_a = payload.memory_type) != null ? _a : "instructions"}: ${payload.file_path}
1212
+ `;
1213
+ writeState(
1214
+ `instr_${payload.session_id}_${fileKey}`,
1215
+ header + truncated
1216
+ );
1217
+ }
1218
+ } catch (e) {
1219
+ }
1048
1220
  }
1049
- async function handleStopFailure(payload, eventId, config, properties, eventShipper) {
1050
- await eventShipper.finish(eventId, {
1221
+ function gatherInstructions(sessionId) {
1222
+ try {
1223
+ if (!existsSync3(STATE_DIR)) return void 0;
1224
+ const prefix = safeKey(`instr_${sessionId}_`);
1225
+ const files = readdirSync(STATE_DIR).filter((f) => f.startsWith(prefix));
1226
+ if (files.length === 0) return void 0;
1227
+ const parts = [];
1228
+ for (const file of files.sort()) {
1229
+ try {
1230
+ parts.push(readFileSync3(join2(STATE_DIR, file), "utf-8"));
1231
+ } catch (e) {
1232
+ continue;
1233
+ }
1234
+ }
1235
+ return parts.length > 0 ? parts.join("\n\n---\n\n") : void 0;
1236
+ } catch (e) {
1237
+ return void 0;
1238
+ }
1239
+ }
1240
+ function cleanupInstructions(sessionId) {
1241
+ try {
1242
+ if (!existsSync3(STATE_DIR)) return;
1243
+ const prefix = safeKey(`instr_${sessionId}_`);
1244
+ for (const file of readdirSync(STATE_DIR).filter((f) => f.startsWith(prefix))) {
1245
+ try {
1246
+ unlinkSync(join2(STATE_DIR, file));
1247
+ } catch (e) {
1248
+ }
1249
+ }
1250
+ } catch (e) {
1251
+ }
1252
+ }
1253
+ var APPEND_FLAG = "--append-system-prompt";
1254
+ var APPEND_FILE_FLAG = "--append-system-prompt-file";
1255
+ var MAX_ANCESTOR_DEPTH = 15;
1256
+ var PS_TIMEOUT_MS = 3e3;
1257
+ function appendSystemPromptKey(sessionId) {
1258
+ return `append_sysprompt_${sessionId}`;
1259
+ }
1260
+ function tryCaptureAppendSystemPrompt(sessionId) {
1261
+ try {
1262
+ const content = readAncestorAppendSystemPrompt();
1263
+ if (content) {
1264
+ writeState(appendSystemPromptKey(sessionId), content);
1265
+ }
1266
+ } catch (e) {
1267
+ }
1268
+ }
1269
+ function readAncestorAppendSystemPrompt() {
1270
+ let pid;
1271
+ try {
1272
+ pid = process.ppid;
1273
+ } catch (e) {
1274
+ return void 0;
1275
+ }
1276
+ if (!pid || pid <= 1) return void 0;
1277
+ for (let depth = 0; depth < MAX_ANCESTOR_DEPTH && pid != null && pid > 1; depth++) {
1278
+ try {
1279
+ const args = getProcessArgs(pid);
1280
+ if (args && args.length > 0) {
1281
+ const content = extractAppendSystemPrompt(args);
1282
+ if (content) return content;
1283
+ }
1284
+ } catch (e) {
1285
+ }
1286
+ try {
1287
+ pid = getParentPid(pid);
1288
+ } catch (e) {
1289
+ break;
1290
+ }
1291
+ }
1292
+ return void 0;
1293
+ }
1294
+ function getProcessArgs(pid) {
1295
+ if (process.platform === "linux") {
1296
+ try {
1297
+ const raw = readFileSync3(`/proc/${pid}/cmdline`, "utf-8");
1298
+ const args = raw.split("\0").filter(Boolean);
1299
+ return args.length > 0 ? args : void 0;
1300
+ } catch (e) {
1301
+ }
1302
+ }
1303
+ try {
1304
+ const output = execSync(`ps -ww -o args= -p ${pid}`, {
1305
+ encoding: "utf-8",
1306
+ timeout: PS_TIMEOUT_MS,
1307
+ stdio: ["ignore", "pipe", "ignore"]
1308
+ });
1309
+ const trimmed = output.trim();
1310
+ if (!trimmed) return void 0;
1311
+ return trimmed.split(/\s+/);
1312
+ } catch (e) {
1313
+ return void 0;
1314
+ }
1315
+ }
1316
+ function getParentPid(pid) {
1317
+ try {
1318
+ const output = execSync(`ps -o ppid= -p ${pid}`, {
1319
+ encoding: "utf-8",
1320
+ timeout: PS_TIMEOUT_MS,
1321
+ stdio: ["ignore", "pipe", "ignore"]
1322
+ });
1323
+ const ppid = parseInt(output.trim(), 10);
1324
+ return Number.isFinite(ppid) && ppid > 0 ? ppid : void 0;
1325
+ } catch (e) {
1326
+ return void 0;
1327
+ }
1328
+ }
1329
+ function extractAppendSystemPrompt(args) {
1330
+ const parts = [];
1331
+ for (let i = 0; i < args.length; i++) {
1332
+ const arg = args[i];
1333
+ try {
1334
+ if (arg === APPEND_FILE_FLAG && i + 1 < args.length) {
1335
+ const filePath = args[i + 1];
1336
+ i++;
1337
+ try {
1338
+ if (existsSync3(filePath)) {
1339
+ parts.push(readFileSync3(filePath, "utf-8"));
1340
+ }
1341
+ } catch (e) {
1342
+ }
1343
+ continue;
1344
+ }
1345
+ if (arg.startsWith(APPEND_FILE_FLAG + "=")) {
1346
+ const filePath = arg.slice(APPEND_FILE_FLAG.length + 1);
1347
+ try {
1348
+ if (filePath && existsSync3(filePath)) {
1349
+ parts.push(readFileSync3(filePath, "utf-8"));
1350
+ }
1351
+ } catch (e) {
1352
+ }
1353
+ continue;
1354
+ }
1355
+ if (arg === APPEND_FLAG && i + 1 < args.length) {
1356
+ const valueParts = [];
1357
+ for (let j = i + 1; j < args.length; j++) {
1358
+ if (args[j].startsWith("--")) break;
1359
+ valueParts.push(args[j]);
1360
+ i = j;
1361
+ }
1362
+ if (valueParts.length > 0) {
1363
+ parts.push(valueParts.join(" "));
1364
+ }
1365
+ continue;
1366
+ }
1367
+ if (arg.startsWith(APPEND_FLAG + "=") && !arg.startsWith(APPEND_FILE_FLAG)) {
1368
+ const value = arg.slice(APPEND_FLAG.length + 1);
1369
+ if (value) {
1370
+ parts.push(value);
1371
+ }
1372
+ continue;
1373
+ }
1374
+ } catch (e) {
1375
+ continue;
1376
+ }
1377
+ }
1378
+ return parts.length > 0 ? parts.join("\n") : void 0;
1379
+ }
1380
+ function readAppendSystemPrompt(sessionId) {
1381
+ try {
1382
+ return readState(appendSystemPromptKey(sessionId)) || void 0;
1383
+ } catch (e) {
1384
+ return void 0;
1385
+ }
1386
+ }
1387
+ function enrichFromTranscript(payload, eventId, traceShipper) {
1388
+ var _a, _b;
1389
+ if (!payload.transcript_path) {
1390
+ return { summary: void 0, props: {} };
1391
+ }
1392
+ try {
1393
+ const summary = parseTranscript(payload.transcript_path);
1394
+ if (!summary) return { summary: void 0, props: {} };
1395
+ const props = transcriptToProperties(summary);
1396
+ const spanInputTokens = (_a = summary.lastTurnInputTokens) != null ? _a : summary.totalInputTokens;
1397
+ const spanOutputTokens = (_b = summary.lastTurnOutputTokens) != null ? _b : summary.totalOutputTokens;
1398
+ if (summary.model && (spanInputTokens > 0 || spanOutputTokens > 0)) {
1399
+ const parent = getParentContext(payload);
1400
+ const now = nowUnixNanoString();
1401
+ traceShipper.createSpan({
1402
+ name: summary.model,
1403
+ eventId,
1404
+ parent,
1405
+ startTimeUnixNano: now,
1406
+ endTimeUnixNano: now,
1407
+ attributes: [
1408
+ attrString("ai.operationId", "generateText"),
1409
+ attrString("gen_ai.response.model", summary.model),
1410
+ attrString("gen_ai.system", "anthropic"),
1411
+ attrInt("gen_ai.usage.prompt_tokens", spanInputTokens),
1412
+ attrInt("gen_ai.usage.completion_tokens", spanOutputTokens),
1413
+ ...summary.lastTurnCacheReadTokens != null && summary.lastTurnCacheReadTokens > 0 ? [attrInt("gen_ai.usage.cache_read_tokens", summary.lastTurnCacheReadTokens)] : []
1414
+ ]
1415
+ });
1416
+ }
1417
+ return { summary, props };
1418
+ } catch (e) {
1419
+ return { summary: void 0, props: {} };
1420
+ }
1421
+ }
1422
+ async function handleStopOrFailure(payload, eventId, config, properties, eventShipper, traceShipper, extraProperties) {
1423
+ const { summary, props: transcriptProps } = enrichFromTranscript(payload, eventId, traceShipper);
1424
+ const instructions = gatherInstructions(payload.session_id);
1425
+ const appendSysPrompt = readAppendSystemPrompt(payload.session_id);
1426
+ await eventShipper.patch(eventId, {
1427
+ isPending: false,
1051
1428
  userId: config.userId,
1429
+ convoId: payload.session_id,
1430
+ eventName: config.eventName,
1052
1431
  output: payload.last_assistant_message,
1432
+ ...(summary == null ? void 0 : summary.model) ? { model: summary.model } : {},
1053
1433
  properties: {
1054
1434
  ...properties,
1055
- error: payload.error,
1056
- error_details: payload.error_details
1435
+ ...transcriptProps,
1436
+ ...instructions ? { system_instructions: truncate(instructions) } : {},
1437
+ ...appendSysPrompt ? { append_system_prompt: truncate(appendSysPrompt) } : {},
1438
+ ...extraProperties
1057
1439
  }
1058
1440
  });
1059
1441
  }
1060
1442
  async function handleSessionEnd(payload, eventId, config, properties, eventShipper) {
1061
- await eventShipper.finish(eventId, {
1443
+ await eventShipper.patch(eventId, {
1444
+ isPending: false,
1062
1445
  userId: config.userId,
1446
+ eventName: config.eventName,
1063
1447
  properties: {
1064
1448
  ...properties,
1065
1449
  session_end_reason: payload.reason
@@ -1068,7 +1452,7 @@ async function handleSessionEnd(payload, eventId, config, properties, eventShipp
1068
1452
  }
1069
1453
 
1070
1454
  // src/local-debugger.ts
1071
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1455
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
1072
1456
  import { tmpdir as tmpdir2 } from "os";
1073
1457
  import { join as join3 } from "path";
1074
1458
  var DEFAULT_PORT = 5899;
@@ -1079,8 +1463,8 @@ var CACHE_FILE = join3(CACHE_DIR, "debugger_cache");
1079
1463
  var CACHE_TTL_MS = 5e3;
1080
1464
  function readCache() {
1081
1465
  try {
1082
- if (!existsSync3(CACHE_FILE)) return void 0;
1083
- const data = JSON.parse(readFileSync3(CACHE_FILE, "utf-8"));
1466
+ if (!existsSync4(CACHE_FILE)) return void 0;
1467
+ const data = JSON.parse(readFileSync4(CACHE_FILE, "utf-8"));
1084
1468
  if (Date.now() - data.ts > CACHE_TTL_MS) return void 0;
1085
1469
  return data;
1086
1470
  } catch (e) {
@@ -1153,9 +1537,12 @@ export {
1153
1537
  PACKAGE_VERSION,
1154
1538
  TraceShipper2 as TraceShipper,
1155
1539
  detectLocalDebugger,
1540
+ extractAppendSystemPrompt,
1156
1541
  getConfigPath,
1157
1542
  loadConfig,
1158
1543
  mapHookToRaindrop,
1159
1544
  mirrorEventToLocalDebugger,
1545
+ parseTranscript,
1546
+ transcriptToProperties,
1160
1547
  updateConfig
1161
1548
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raindrop-ai/claude-code",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Raindrop observability for Claude Code CLI — automatic session, tool call, and prompt tracing via hooks",
5
5
  "license": "MIT",
6
6
  "type": "module",