@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.d.ts
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 };
|
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.
|
|
648
|
+
var PACKAGE_VERSION = "0.0.5";
|
|
649
649
|
|
|
650
650
|
// src/shipper.ts
|
|
651
651
|
var EventShipper2 = class extends EventShipper {
|
|
@@ -741,10 +741,145 @@ function updateConfig(patch) {
|
|
|
741
741
|
}
|
|
742
742
|
|
|
743
743
|
// src/event-mapper.ts
|
|
744
|
-
import { existsSync as
|
|
744
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
745
|
+
import { execSync } from "child_process";
|
|
745
746
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
746
747
|
import { tmpdir } from "os";
|
|
747
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
|
|
748
883
|
var MAX_ATTR_LENGTH = 32768;
|
|
749
884
|
function truncate(value) {
|
|
750
885
|
if (value === void 0) return void 0;
|
|
@@ -788,8 +923,8 @@ function writeState(key, value) {
|
|
|
788
923
|
function readState(key) {
|
|
789
924
|
try {
|
|
790
925
|
const filePath = statePath(key);
|
|
791
|
-
if (!
|
|
792
|
-
return
|
|
926
|
+
if (!existsSync3(filePath)) return void 0;
|
|
927
|
+
return readFileSync3(filePath, "utf-8");
|
|
793
928
|
} catch (e) {
|
|
794
929
|
return void 0;
|
|
795
930
|
}
|
|
@@ -854,12 +989,15 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
854
989
|
cwd: payload.cwd,
|
|
855
990
|
permission_mode: payload.permission_mode,
|
|
856
991
|
plugin_version: PACKAGE_VERSION,
|
|
992
|
+
sdk: PACKAGE_NAME,
|
|
993
|
+
sdk_version: PACKAGE_VERSION,
|
|
857
994
|
...payload.agent_id ? { agent_id: payload.agent_id } : {},
|
|
858
995
|
...payload.agent_type ? { agent_type: payload.agent_type } : {}
|
|
859
996
|
};
|
|
860
997
|
switch (payload.hook_event_name) {
|
|
861
998
|
case "SessionStart":
|
|
862
999
|
writeState(`model_${payload.session_id}`, (_a = payload.model) != null ? _a : "");
|
|
1000
|
+
tryCaptureAppendSystemPrompt(payload.session_id);
|
|
863
1001
|
break;
|
|
864
1002
|
case "UserPromptSubmit":
|
|
865
1003
|
await handleUserPromptSubmit(payload, convoId, config, baseProperties, eventShipper, traceShipper);
|
|
@@ -874,10 +1012,13 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
874
1012
|
handlePostToolUseFailure(payload, getCurrentEventId(payload.session_id), traceShipper);
|
|
875
1013
|
break;
|
|
876
1014
|
case "Stop":
|
|
877
|
-
await
|
|
1015
|
+
await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper);
|
|
878
1016
|
break;
|
|
879
1017
|
case "StopFailure":
|
|
880
|
-
await
|
|
1018
|
+
await handleStopOrFailure(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper, traceShipper, {
|
|
1019
|
+
error: payload.error,
|
|
1020
|
+
error_details: payload.error_details
|
|
1021
|
+
});
|
|
881
1022
|
break;
|
|
882
1023
|
case "SubagentStart":
|
|
883
1024
|
handleSubagentStart(payload, getCurrentEventId(payload.session_id), traceShipper);
|
|
@@ -888,6 +1029,9 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
888
1029
|
case "PermissionDenied":
|
|
889
1030
|
handlePermissionDenied(payload, getCurrentEventId(payload.session_id), traceShipper);
|
|
890
1031
|
break;
|
|
1032
|
+
case "InstructionsLoaded":
|
|
1033
|
+
handleInstructionsLoaded(payload);
|
|
1034
|
+
break;
|
|
891
1035
|
case "PostCompact":
|
|
892
1036
|
await handlePostCompact(payload, getCurrentEventId(payload.session_id), config, baseProperties, eventShipper);
|
|
893
1037
|
break;
|
|
@@ -896,6 +1040,8 @@ async function mapHookToRaindrop(payload, config, eventShipper, traceShipper) {
|
|
|
896
1040
|
deleteState(turnEventKey(payload.session_id));
|
|
897
1041
|
deleteState(rootSpanKey(payload.session_id));
|
|
898
1042
|
deleteState(`model_${payload.session_id}`);
|
|
1043
|
+
deleteState(appendSystemPromptKey(payload.session_id));
|
|
1044
|
+
cleanupInstructions(payload.session_id);
|
|
899
1045
|
break;
|
|
900
1046
|
default:
|
|
901
1047
|
if (config.debug) {
|
|
@@ -1053,25 +1199,243 @@ async function handlePostCompact(payload, eventId, config, properties, eventShip
|
|
|
1053
1199
|
}
|
|
1054
1200
|
});
|
|
1055
1201
|
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
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
|
+
}
|
|
1064
1220
|
}
|
|
1065
|
-
|
|
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);
|
|
1066
1426
|
await eventShipper.patch(eventId, {
|
|
1067
1427
|
isPending: false,
|
|
1068
1428
|
userId: config.userId,
|
|
1429
|
+
convoId: payload.session_id,
|
|
1069
1430
|
eventName: config.eventName,
|
|
1070
1431
|
output: payload.last_assistant_message,
|
|
1432
|
+
...(summary == null ? void 0 : summary.model) ? { model: summary.model } : {},
|
|
1071
1433
|
properties: {
|
|
1072
1434
|
...properties,
|
|
1073
|
-
|
|
1074
|
-
|
|
1435
|
+
...transcriptProps,
|
|
1436
|
+
...instructions ? { system_instructions: truncate(instructions) } : {},
|
|
1437
|
+
...appendSysPrompt ? { append_system_prompt: truncate(appendSysPrompt) } : {},
|
|
1438
|
+
...extraProperties
|
|
1075
1439
|
}
|
|
1076
1440
|
});
|
|
1077
1441
|
}
|
|
@@ -1088,7 +1452,7 @@ async function handleSessionEnd(payload, eventId, config, properties, eventShipp
|
|
|
1088
1452
|
}
|
|
1089
1453
|
|
|
1090
1454
|
// src/local-debugger.ts
|
|
1091
|
-
import { existsSync as
|
|
1455
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
1092
1456
|
import { tmpdir as tmpdir2 } from "os";
|
|
1093
1457
|
import { join as join3 } from "path";
|
|
1094
1458
|
var DEFAULT_PORT = 5899;
|
|
@@ -1099,8 +1463,8 @@ var CACHE_FILE = join3(CACHE_DIR, "debugger_cache");
|
|
|
1099
1463
|
var CACHE_TTL_MS = 5e3;
|
|
1100
1464
|
function readCache() {
|
|
1101
1465
|
try {
|
|
1102
|
-
if (!
|
|
1103
|
-
const data = JSON.parse(
|
|
1466
|
+
if (!existsSync4(CACHE_FILE)) return void 0;
|
|
1467
|
+
const data = JSON.parse(readFileSync4(CACHE_FILE, "utf-8"));
|
|
1104
1468
|
if (Date.now() - data.ts > CACHE_TTL_MS) return void 0;
|
|
1105
1469
|
return data;
|
|
1106
1470
|
} catch (e) {
|
|
@@ -1173,9 +1537,12 @@ export {
|
|
|
1173
1537
|
PACKAGE_VERSION,
|
|
1174
1538
|
TraceShipper2 as TraceShipper,
|
|
1175
1539
|
detectLocalDebugger,
|
|
1540
|
+
extractAppendSystemPrompt,
|
|
1176
1541
|
getConfigPath,
|
|
1177
1542
|
loadConfig,
|
|
1178
1543
|
mapHookToRaindrop,
|
|
1179
1544
|
mirrorEventToLocalDebugger,
|
|
1545
|
+
parseTranscript,
|
|
1546
|
+
transcriptToProperties,
|
|
1180
1547
|
updateConfig
|
|
1181
1548
|
};
|
package/package.json
CHANGED