@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 CHANGED
@@ -20,6 +20,10 @@ This saves your write key and configures Claude Code hooks. Every session will n
20
20
 
21
21
  - Every prompt turn as a separate event, grouped by session
22
22
  - Tool calls with inputs, outputs, and real durations
23
+ - Token usage per turn and per session (input, output, cache read, cache creation)
24
+ - Model name, service tier, and stop reason
25
+ - CLAUDE.md and rules file contents
26
+ - `--append-system-prompt` / `--append-system-prompt-file` content (best-effort)
23
27
  - Subagent spawns and completions
24
28
  - Permission denials and context compaction
25
29
  - Nested trace view (tools under root, subagent tools under subagent)
package/dist/cli.js CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/event-mapper.ts
4
- import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "fs";
4
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, readdirSync, unlinkSync, writeFileSync } from "fs";
5
+ import { execSync } from "child_process";
5
6
  import { randomUUID as randomUUID2 } from "crypto";
6
7
  import { tmpdir } from "os";
7
8
  import { join } from "path";
@@ -653,7 +654,7 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
653
654
 
654
655
  // src/package-info.ts
655
656
  var PACKAGE_NAME = "@raindrop-ai/claude-code";
656
- var PACKAGE_VERSION = "0.0.4";
657
+ var PACKAGE_VERSION = "0.0.5";
657
658
 
658
659
  // src/shipper.ts
659
660
  var EventShipper2 = class extends EventShipper {
@@ -690,6 +691,138 @@ var TraceShipper2 = class extends TraceShipper {
690
691
  }
691
692
  };
692
693
 
694
+ // src/transcript.ts
695
+ import { existsSync, readFileSync } from "fs";
696
+ function parseTranscript(transcriptPath) {
697
+ var _a, _b, _c, _d, _e;
698
+ try {
699
+ if (!existsSync(transcriptPath)) return void 0;
700
+ const content = readFileSync(transcriptPath, "utf-8");
701
+ const lines = content.split("\n").filter((l) => l.trim());
702
+ const summary = {
703
+ totalInputTokens: 0,
704
+ totalOutputTokens: 0,
705
+ totalCacheReadTokens: 0,
706
+ totalCacheCreationTokens: 0,
707
+ turnCount: 0,
708
+ toolsUsed: [],
709
+ hasThinking: false
710
+ };
711
+ const toolNames = /* @__PURE__ */ new Set();
712
+ let lastUsage;
713
+ for (const line of lines) {
714
+ let entry;
715
+ try {
716
+ entry = JSON.parse(line);
717
+ } catch (e) {
718
+ continue;
719
+ }
720
+ if (entry.type === "system" && entry.subtype === "turn_duration") {
721
+ const durationMs = entry["durationMs"];
722
+ if (typeof durationMs === "number") {
723
+ summary.totalDurationMs = ((_a = summary.totalDurationMs) != null ? _a : 0) + durationMs;
724
+ }
725
+ const version = entry["version"];
726
+ if (typeof version === "string") {
727
+ summary.codeVersion = version;
728
+ }
729
+ const branch = entry["gitBranch"];
730
+ if (typeof branch === "string") {
731
+ summary.gitBranch = branch;
732
+ }
733
+ continue;
734
+ }
735
+ if (entry.type !== "assistant") continue;
736
+ const msg = entry.message;
737
+ if (!msg) continue;
738
+ summary.turnCount++;
739
+ if (msg.model) {
740
+ summary.model = msg.model;
741
+ }
742
+ if (msg.stop_reason) {
743
+ summary.stopReason = msg.stop_reason;
744
+ }
745
+ const entryVersion = entry["version"];
746
+ if (typeof entryVersion === "string") {
747
+ summary.codeVersion = entryVersion;
748
+ }
749
+ const entryBranch = entry["gitBranch"];
750
+ if (typeof entryBranch === "string") {
751
+ summary.gitBranch = entryBranch;
752
+ }
753
+ if (msg.usage) {
754
+ const u = msg.usage;
755
+ summary.totalInputTokens += (_b = u.input_tokens) != null ? _b : 0;
756
+ summary.totalOutputTokens += (_c = u.output_tokens) != null ? _c : 0;
757
+ summary.totalCacheReadTokens += (_d = u.cache_read_input_tokens) != null ? _d : 0;
758
+ summary.totalCacheCreationTokens += (_e = u.cache_creation_input_tokens) != null ? _e : 0;
759
+ if (u.service_tier) {
760
+ summary.serviceTier = u.service_tier;
761
+ }
762
+ lastUsage = u;
763
+ }
764
+ if (Array.isArray(msg.content)) {
765
+ for (const block of msg.content) {
766
+ if (block.type === "tool_use" && block.name) {
767
+ toolNames.add(block.name);
768
+ }
769
+ if (block.type === "thinking") {
770
+ summary.hasThinking = true;
771
+ }
772
+ }
773
+ }
774
+ }
775
+ if (lastUsage) {
776
+ summary.lastTurnInputTokens = lastUsage.input_tokens;
777
+ summary.lastTurnOutputTokens = lastUsage.output_tokens;
778
+ summary.lastTurnCacheReadTokens = lastUsage.cache_read_input_tokens;
779
+ }
780
+ summary.toolsUsed = [...toolNames].sort();
781
+ return summary;
782
+ } catch (e) {
783
+ return void 0;
784
+ }
785
+ }
786
+ function transcriptToProperties(summary) {
787
+ var _a, _b;
788
+ const props = {};
789
+ props["ai.usage.prompt_tokens"] = (_a = summary.lastTurnInputTokens) != null ? _a : summary.totalInputTokens;
790
+ props["ai.usage.completion_tokens"] = (_b = summary.lastTurnOutputTokens) != null ? _b : summary.totalOutputTokens;
791
+ if (summary.lastTurnCacheReadTokens !== void 0) {
792
+ props["ai.usage.cache_read_tokens"] = summary.lastTurnCacheReadTokens;
793
+ }
794
+ props["ai.usage.session_total.prompt_tokens"] = summary.totalInputTokens;
795
+ props["ai.usage.session_total.completion_tokens"] = summary.totalOutputTokens;
796
+ props["ai.usage.session_total.cache_read_tokens"] = summary.totalCacheReadTokens;
797
+ props["ai.usage.session_total.cache_creation_tokens"] = summary.totalCacheCreationTokens;
798
+ if (summary.model) {
799
+ props["ai.model"] = summary.model;
800
+ }
801
+ if (summary.serviceTier) {
802
+ props["ai.service_tier"] = summary.serviceTier;
803
+ }
804
+ if (summary.stopReason) {
805
+ props["ai.stop_reason"] = summary.stopReason;
806
+ }
807
+ if (summary.toolsUsed.length > 0) {
808
+ props["ai.tools_used"] = summary.toolsUsed.join(", ");
809
+ }
810
+ props["ai.turn_count"] = summary.turnCount;
811
+ if (summary.totalDurationMs !== void 0) {
812
+ props["ai.duration_ms"] = summary.totalDurationMs;
813
+ }
814
+ if (summary.codeVersion) {
815
+ props["claude_code.version"] = summary.codeVersion;
816
+ }
817
+ if (summary.gitBranch) {
818
+ props["git.branch"] = summary.gitBranch;
819
+ }
820
+ if (summary.hasThinking) {
821
+ props["ai.has_thinking"] = true;
822
+ }
823
+ return props;
824
+ }
825
+
693
826
  // src/event-mapper.ts
694
827
  var MAX_ATTR_LENGTH = 32768;
695
828
  function truncate(value) {
@@ -734,8 +867,8 @@ function writeState(key, value) {
734
867
  function readState(key) {
735
868
  try {
736
869
  const filePath = statePath(key);
737
- if (!existsSync(filePath)) return void 0;
738
- return readFileSync(filePath, "utf-8");
870
+ if (!existsSync2(filePath)) return void 0;
871
+ return readFileSync2(filePath, "utf-8");
739
872
  } catch (e) {
740
873
  return void 0;
741
874
  }
@@ -800,12 +933,15 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
800
933
  cwd: payload.cwd,
801
934
  permission_mode: payload.permission_mode,
802
935
  plugin_version: PACKAGE_VERSION,
936
+ sdk: PACKAGE_NAME,
937
+ sdk_version: PACKAGE_VERSION,
803
938
  ...payload.agent_id ? { agent_id: payload.agent_id } : {},
804
939
  ...payload.agent_type ? { agent_type: payload.agent_type } : {}
805
940
  };
806
941
  switch (payload.hook_event_name) {
807
942
  case "SessionStart":
808
943
  writeState(`model_${payload.session_id}`, (_a = payload.model) != null ? _a : "");
944
+ tryCaptureAppendSystemPrompt(payload.session_id);
809
945
  break;
810
946
  case "UserPromptSubmit":
811
947
  await handleUserPromptSubmit(payload, convoId, config, baseProperties, eventShipper, traceShipper);
@@ -820,10 +956,13 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
820
956
  handlePostToolUseFailure(payload, getCurrentEventId(payload.session_id), traceShipper);
821
957
  break;
822
958
  case "Stop":
823
- await handleStop(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
959
+ await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper);
824
960
  break;
825
961
  case "StopFailure":
826
- await handleStopFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
962
+ await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper, {
963
+ error: payload.error,
964
+ error_details: payload.error_details
965
+ });
827
966
  break;
828
967
  case "SubagentStart":
829
968
  handleSubagentStart(payload, getCurrentEventId(payload.session_id), traceShipper);
@@ -834,6 +973,9 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
834
973
  case "PermissionDenied":
835
974
  handlePermissionDenied(payload, getCurrentEventId(payload.session_id), traceShipper);
836
975
  break;
976
+ case "InstructionsLoaded":
977
+ handleInstructionsLoaded(payload);
978
+ break;
837
979
  case "PostCompact":
838
980
  await handlePostCompact(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
839
981
  break;
@@ -842,6 +984,8 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
842
984
  deleteState(turnEventKey(payload.session_id));
843
985
  deleteState(rootSpanKey(payload.session_id));
844
986
  deleteState(`model_${payload.session_id}`);
987
+ deleteState(appendSystemPromptKey(payload.session_id));
988
+ cleanupInstructions(payload.session_id);
845
989
  break;
846
990
  default:
847
991
  if (config.debug) {
@@ -999,25 +1143,243 @@ async function handlePostCompact(payload, eventId, config, properties, eventShip
999
1143
  }
1000
1144
  });
1001
1145
  }
1002
- async function handleStop(payload, eventId, config, properties, eventShipper) {
1003
- await eventShipper.patch(eventId, {
1004
- isPending: false,
1005
- userId: config.userId,
1006
- eventName: config.eventName,
1007
- output: payload.last_assistant_message,
1008
- properties
1009
- });
1146
+ function handleInstructionsLoaded(payload) {
1147
+ var _a;
1148
+ if (!payload.file_path || !payload.session_id) return;
1149
+ try {
1150
+ if (existsSync2(payload.file_path)) {
1151
+ const content = readFileSync2(payload.file_path, "utf-8");
1152
+ const MAX_INSTRUCTIONS_LENGTH = 8192;
1153
+ const truncated = content.length > MAX_INSTRUCTIONS_LENGTH ? content.slice(0, MAX_INSTRUCTIONS_LENGTH) + "\n...[truncated]" : content;
1154
+ const fileKey = safeKey(payload.file_path);
1155
+ const header = `# ${(_a = payload.memory_type) != null ? _a : "instructions"}: ${payload.file_path}
1156
+ `;
1157
+ writeState(
1158
+ `instr_${payload.session_id}_${fileKey}`,
1159
+ header + truncated
1160
+ );
1161
+ }
1162
+ } catch (e) {
1163
+ }
1164
+ }
1165
+ function gatherInstructions(sessionId) {
1166
+ try {
1167
+ if (!existsSync2(STATE_DIR)) return void 0;
1168
+ const prefix = safeKey(`instr_${sessionId}_`);
1169
+ const files = readdirSync(STATE_DIR).filter((f) => f.startsWith(prefix));
1170
+ if (files.length === 0) return void 0;
1171
+ const parts = [];
1172
+ for (const file of files.sort()) {
1173
+ try {
1174
+ parts.push(readFileSync2(join(STATE_DIR, file), "utf-8"));
1175
+ } catch (e) {
1176
+ continue;
1177
+ }
1178
+ }
1179
+ return parts.length > 0 ? parts.join("\n\n---\n\n") : void 0;
1180
+ } catch (e) {
1181
+ return void 0;
1182
+ }
1183
+ }
1184
+ function cleanupInstructions(sessionId) {
1185
+ try {
1186
+ if (!existsSync2(STATE_DIR)) return;
1187
+ const prefix = safeKey(`instr_${sessionId}_`);
1188
+ for (const file of readdirSync(STATE_DIR).filter((f) => f.startsWith(prefix))) {
1189
+ try {
1190
+ unlinkSync(join(STATE_DIR, file));
1191
+ } catch (e) {
1192
+ }
1193
+ }
1194
+ } catch (e) {
1195
+ }
1196
+ }
1197
+ var APPEND_FLAG = "--append-system-prompt";
1198
+ var APPEND_FILE_FLAG = "--append-system-prompt-file";
1199
+ var MAX_ANCESTOR_DEPTH = 15;
1200
+ var PS_TIMEOUT_MS = 3e3;
1201
+ function appendSystemPromptKey(sessionId) {
1202
+ return `append_sysprompt_${sessionId}`;
1203
+ }
1204
+ function tryCaptureAppendSystemPrompt(sessionId) {
1205
+ try {
1206
+ const content = readAncestorAppendSystemPrompt();
1207
+ if (content) {
1208
+ writeState(appendSystemPromptKey(sessionId), content);
1209
+ }
1210
+ } catch (e) {
1211
+ }
1010
1212
  }
1011
- async function handleStopFailure(payload, eventId, config, properties, eventShipper) {
1213
+ function readAncestorAppendSystemPrompt() {
1214
+ let pid;
1215
+ try {
1216
+ pid = process.ppid;
1217
+ } catch (e) {
1218
+ return void 0;
1219
+ }
1220
+ if (!pid || pid <= 1) return void 0;
1221
+ for (let depth = 0; depth < MAX_ANCESTOR_DEPTH && pid != null && pid > 1; depth++) {
1222
+ try {
1223
+ const args2 = getProcessArgs(pid);
1224
+ if (args2 && args2.length > 0) {
1225
+ const content = extractAppendSystemPrompt(args2);
1226
+ if (content) return content;
1227
+ }
1228
+ } catch (e) {
1229
+ }
1230
+ try {
1231
+ pid = getParentPid(pid);
1232
+ } catch (e) {
1233
+ break;
1234
+ }
1235
+ }
1236
+ return void 0;
1237
+ }
1238
+ function getProcessArgs(pid) {
1239
+ if (process.platform === "linux") {
1240
+ try {
1241
+ const raw = readFileSync2(`/proc/${pid}/cmdline`, "utf-8");
1242
+ const args2 = raw.split("\0").filter(Boolean);
1243
+ return args2.length > 0 ? args2 : void 0;
1244
+ } catch (e) {
1245
+ }
1246
+ }
1247
+ try {
1248
+ const output = execSync(`ps -ww -o args= -p ${pid}`, {
1249
+ encoding: "utf-8",
1250
+ timeout: PS_TIMEOUT_MS,
1251
+ stdio: ["ignore", "pipe", "ignore"]
1252
+ });
1253
+ const trimmed = output.trim();
1254
+ if (!trimmed) return void 0;
1255
+ return trimmed.split(/\s+/);
1256
+ } catch (e) {
1257
+ return void 0;
1258
+ }
1259
+ }
1260
+ function getParentPid(pid) {
1261
+ try {
1262
+ const output = execSync(`ps -o ppid= -p ${pid}`, {
1263
+ encoding: "utf-8",
1264
+ timeout: PS_TIMEOUT_MS,
1265
+ stdio: ["ignore", "pipe", "ignore"]
1266
+ });
1267
+ const ppid = parseInt(output.trim(), 10);
1268
+ return Number.isFinite(ppid) && ppid > 0 ? ppid : void 0;
1269
+ } catch (e) {
1270
+ return void 0;
1271
+ }
1272
+ }
1273
+ function extractAppendSystemPrompt(args2) {
1274
+ const parts = [];
1275
+ for (let i = 0; i < args2.length; i++) {
1276
+ const arg = args2[i];
1277
+ try {
1278
+ if (arg === APPEND_FILE_FLAG && i + 1 < args2.length) {
1279
+ const filePath = args2[i + 1];
1280
+ i++;
1281
+ try {
1282
+ if (existsSync2(filePath)) {
1283
+ parts.push(readFileSync2(filePath, "utf-8"));
1284
+ }
1285
+ } catch (e) {
1286
+ }
1287
+ continue;
1288
+ }
1289
+ if (arg.startsWith(APPEND_FILE_FLAG + "=")) {
1290
+ const filePath = arg.slice(APPEND_FILE_FLAG.length + 1);
1291
+ try {
1292
+ if (filePath && existsSync2(filePath)) {
1293
+ parts.push(readFileSync2(filePath, "utf-8"));
1294
+ }
1295
+ } catch (e) {
1296
+ }
1297
+ continue;
1298
+ }
1299
+ if (arg === APPEND_FLAG && i + 1 < args2.length) {
1300
+ const valueParts = [];
1301
+ for (let j = i + 1; j < args2.length; j++) {
1302
+ if (args2[j].startsWith("--")) break;
1303
+ valueParts.push(args2[j]);
1304
+ i = j;
1305
+ }
1306
+ if (valueParts.length > 0) {
1307
+ parts.push(valueParts.join(" "));
1308
+ }
1309
+ continue;
1310
+ }
1311
+ if (arg.startsWith(APPEND_FLAG + "=") && !arg.startsWith(APPEND_FILE_FLAG)) {
1312
+ const value = arg.slice(APPEND_FLAG.length + 1);
1313
+ if (value) {
1314
+ parts.push(value);
1315
+ }
1316
+ continue;
1317
+ }
1318
+ } catch (e) {
1319
+ continue;
1320
+ }
1321
+ }
1322
+ return parts.length > 0 ? parts.join("\n") : void 0;
1323
+ }
1324
+ function readAppendSystemPrompt(sessionId) {
1325
+ try {
1326
+ return readState(appendSystemPromptKey(sessionId)) || void 0;
1327
+ } catch (e) {
1328
+ return void 0;
1329
+ }
1330
+ }
1331
+ function enrichFromTranscript(payload, eventId, traceShipper) {
1332
+ var _a, _b;
1333
+ if (!payload.transcript_path) {
1334
+ return { summary: void 0, props: {} };
1335
+ }
1336
+ try {
1337
+ const summary = parseTranscript(payload.transcript_path);
1338
+ if (!summary) return { summary: void 0, props: {} };
1339
+ const props = transcriptToProperties(summary);
1340
+ const spanInputTokens = (_a = summary.lastTurnInputTokens) != null ? _a : summary.totalInputTokens;
1341
+ const spanOutputTokens = (_b = summary.lastTurnOutputTokens) != null ? _b : summary.totalOutputTokens;
1342
+ if (summary.model && (spanInputTokens > 0 || spanOutputTokens > 0)) {
1343
+ const parent = getParentContext(payload);
1344
+ const now = nowUnixNanoString();
1345
+ traceShipper.createSpan({
1346
+ name: summary.model,
1347
+ eventId,
1348
+ parent,
1349
+ startTimeUnixNano: now,
1350
+ endTimeUnixNano: now,
1351
+ attributes: [
1352
+ attrString("ai.operationId", "generateText"),
1353
+ attrString("gen_ai.response.model", summary.model),
1354
+ attrString("gen_ai.system", "anthropic"),
1355
+ attrInt("gen_ai.usage.prompt_tokens", spanInputTokens),
1356
+ attrInt("gen_ai.usage.completion_tokens", spanOutputTokens),
1357
+ ...summary.lastTurnCacheReadTokens != null && summary.lastTurnCacheReadTokens > 0 ? [attrInt("gen_ai.usage.cache_read_tokens", summary.lastTurnCacheReadTokens)] : []
1358
+ ]
1359
+ });
1360
+ }
1361
+ return { summary, props };
1362
+ } catch (e) {
1363
+ return { summary: void 0, props: {} };
1364
+ }
1365
+ }
1366
+ async function handleStopOrFailure(payload, eventId, config, properties, eventShipper, traceShipper, extraProperties) {
1367
+ const { summary, props: transcriptProps } = enrichFromTranscript(payload, eventId, traceShipper);
1368
+ const instructions = gatherInstructions(payload.session_id);
1369
+ const appendSysPrompt = readAppendSystemPrompt(payload.session_id);
1012
1370
  await eventShipper.patch(eventId, {
1013
1371
  isPending: false,
1014
1372
  userId: config.userId,
1373
+ convoId: payload.session_id,
1015
1374
  eventName: config.eventName,
1016
1375
  output: payload.last_assistant_message,
1376
+ ...(summary == null ? void 0 : summary.model) ? { model: summary.model } : {},
1017
1377
  properties: {
1018
1378
  ...properties,
1019
- error: payload.error,
1020
- error_details: payload.error_details
1379
+ ...transcriptProps,
1380
+ ...instructions ? { system_instructions: truncate(instructions) } : {},
1381
+ ...appendSysPrompt ? { append_system_prompt: truncate(appendSysPrompt) } : {},
1382
+ ...extraProperties
1021
1383
  }
1022
1384
  });
1023
1385
  }
@@ -1034,7 +1396,7 @@ async function handleSessionEnd(payload, eventId, config, properties, eventShipp
1034
1396
  }
1035
1397
 
1036
1398
  // src/config.ts
1037
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
1399
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
1038
1400
  import { homedir, userInfo } from "os";
1039
1401
  import { dirname, join as join2 } from "path";
1040
1402
  var CONFIG_PATH = join2(homedir(), ".config", "raindrop", "config.json");
@@ -1042,8 +1404,8 @@ function loadConfig() {
1042
1404
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1043
1405
  let file = {};
1044
1406
  try {
1045
- if (existsSync2(CONFIG_PATH)) {
1046
- file = JSON.parse(readFileSync2(CONFIG_PATH, "utf-8"));
1407
+ if (existsSync3(CONFIG_PATH)) {
1408
+ file = JSON.parse(readFileSync3(CONFIG_PATH, "utf-8"));
1047
1409
  }
1048
1410
  } catch (e) {
1049
1411
  }
@@ -1083,8 +1445,8 @@ function updateConfig(patch) {
1083
1445
  mkdirSync2(dir, { recursive: true });
1084
1446
  let existing = {};
1085
1447
  try {
1086
- if (existsSync2(CONFIG_PATH)) {
1087
- existing = JSON.parse(readFileSync2(CONFIG_PATH, "utf-8"));
1448
+ if (existsSync3(CONFIG_PATH)) {
1449
+ existing = JSON.parse(readFileSync3(CONFIG_PATH, "utf-8"));
1088
1450
  }
1089
1451
  } catch (e) {
1090
1452
  }
@@ -1092,7 +1454,7 @@ function updateConfig(patch) {
1092
1454
  }
1093
1455
 
1094
1456
  // src/local-debugger.ts
1095
- import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
1457
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
1096
1458
  import { tmpdir as tmpdir2 } from "os";
1097
1459
  import { join as join3 } from "path";
1098
1460
  var DEFAULT_PORT = 5899;
@@ -1103,8 +1465,8 @@ var CACHE_FILE = join3(CACHE_DIR, "debugger_cache");
1103
1465
  var CACHE_TTL_MS = 5e3;
1104
1466
  function readCache() {
1105
1467
  try {
1106
- if (!existsSync3(CACHE_FILE)) return void 0;
1107
- const data = JSON.parse(readFileSync3(CACHE_FILE, "utf-8"));
1468
+ if (!existsSync4(CACHE_FILE)) return void 0;
1469
+ const data = JSON.parse(readFileSync4(CACHE_FILE, "utf-8"));
1108
1470
  if (Date.now() - data.ts > CACHE_TTL_MS) return void 0;
1109
1471
  return data;
1110
1472
  } catch (e) {
@@ -1173,7 +1535,7 @@ function mirrorEventToLocalDebugger(baseUrl, payload, debug) {
1173
1535
  }
1174
1536
 
1175
1537
  // src/hook-handler.ts
1176
- import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
1538
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
1177
1539
  import { join as join4 } from "path";
1178
1540
  import { tmpdir as tmpdir3 } from "os";
1179
1541
  var STDIN_TIMEOUT_MS = 5e3;
@@ -1182,8 +1544,8 @@ function getOtlpTraceId(sessionId) {
1182
1544
  try {
1183
1545
  const key = `rootspan_${sessionId}`.replace(/[^a-zA-Z0-9_\-]/g, "_");
1184
1546
  const filePath = join4(STATE_DIR2, key);
1185
- if (!existsSync4(filePath)) return void 0;
1186
- const ctx = JSON.parse(readFileSync4(filePath, "utf-8"));
1547
+ if (!existsSync5(filePath)) return void 0;
1548
+ const ctx = JSON.parse(readFileSync5(filePath, "utf-8"));
1187
1549
  if (!ctx.traceIdB64) return void 0;
1188
1550
  return Buffer.from(ctx.traceIdB64, "base64").toString("hex");
1189
1551
  } catch (e) {
@@ -1302,11 +1664,11 @@ async function handleHook() {
1302
1664
  }
1303
1665
 
1304
1666
  // src/setup.ts
1305
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
1667
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
1306
1668
  import { homedir as homedir2, userInfo as userInfo2 } from "os";
1307
1669
  import { dirname as dirname2, join as join5, resolve } from "path";
1308
1670
  import { createInterface } from "readline";
1309
- import { execSync } from "child_process";
1671
+ import { execSync as execSync2 } from "child_process";
1310
1672
  function getClaudeSettingsPath(scope, cwd) {
1311
1673
  if (scope === "project") {
1312
1674
  return resolve(cwd, ".claude", "settings.json");
@@ -1325,8 +1687,9 @@ var CORE_HOOK_EVENTS = [
1325
1687
  "SessionEnd"
1326
1688
  ];
1327
1689
  var VERSIONED_HOOK_EVENTS = [
1328
- { minVersion: "2.1.78", events: ["StopFailure"] },
1329
1690
  { minVersion: "2.1.76", events: ["PostCompact"] },
1691
+ { minVersion: "2.1.78", events: ["StopFailure"] },
1692
+ { minVersion: "2.1.78", events: ["InstructionsLoaded"] },
1330
1693
  { minVersion: "2.1.89", events: ["PermissionDenied"] }
1331
1694
  ];
1332
1695
  function parseVersion(version) {
@@ -1345,7 +1708,7 @@ function isVersionAtLeast(current, required) {
1345
1708
  }
1346
1709
  function detectClaudeCodeVersion() {
1347
1710
  try {
1348
- const output = execSync("claude --version", {
1711
+ const output = execSync2("claude --version", {
1349
1712
  encoding: "utf-8",
1350
1713
  timeout: 5e3,
1351
1714
  stdio: ["ignore", "pipe", "ignore"]
@@ -1424,8 +1787,8 @@ async function runSetup(args2) {
1424
1787
  mkdirSync4(configDir, { recursive: true });
1425
1788
  let existingConfig = {};
1426
1789
  try {
1427
- if (existsSync5(configPath)) {
1428
- existingConfig = JSON.parse(readFileSync5(configPath, "utf-8"));
1790
+ if (existsSync6(configPath)) {
1791
+ existingConfig = JSON.parse(readFileSync6(configPath, "utf-8"));
1429
1792
  }
1430
1793
  } catch (e) {
1431
1794
  }
@@ -1449,9 +1812,9 @@ async function runSetup(args2) {
1449
1812
  const settingsDir = dirname2(settingsPath);
1450
1813
  mkdirSync4(settingsDir, { recursive: true });
1451
1814
  let settings = {};
1452
- if (existsSync5(settingsPath)) {
1815
+ if (existsSync6(settingsPath)) {
1453
1816
  try {
1454
- settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
1817
+ settings = JSON.parse(readFileSync6(settingsPath, "utf-8"));
1455
1818
  } catch (e) {
1456
1819
  console.warn(` Warning: could not parse ${settingsPath}, creating fresh`);
1457
1820
  settings = {};
@@ -1481,7 +1844,7 @@ async function runSetup(args2) {
1481
1844
  console.log(` Updated Claude Code hooks in ${settingsPath} (${scopeLabel})`);
1482
1845
  const whichCmd = process.platform === "win32" ? "where" : "which";
1483
1846
  try {
1484
- execSync(`${whichCmd} raindrop-claude-code`, { stdio: "ignore" });
1847
+ execSync2(`${whichCmd} raindrop-claude-code`, { stdio: "ignore" });
1485
1848
  } catch (e) {
1486
1849
  console.log(`
1487
1850
  Warning: 'raindrop-claude-code' is not in your PATH.