@remixhq/core 0.1.14 → 0.1.16
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/api.d.ts +1 -1
- package/dist/collab.d.ts +2 -2
- package/dist/collab.js +1 -1
- package/dist/{contracts-NbV3P_Rl.d.ts → contracts-CHmD-fMj.d.ts} +1 -1
- package/dist/history.d.ts +64 -0
- package/dist/history.js +529 -0
- package/dist/index.d.ts +1 -1
- package/package.json +6 -2
- package/dist/chunk-2WGZS7CD.js +0 -0
- package/dist/chunk-34WDQCPF.js +0 -242
- package/dist/chunk-4276ARDF.js +0 -303
- package/dist/chunk-4L3ZBZUQ.js +0 -281
- package/dist/chunk-54CBEP2W.js +0 -570
- package/dist/chunk-55K5GHAZ.js +0 -252
- package/dist/chunk-5H5CZKGN.js +0 -691
- package/dist/chunk-5NTOJXEZ.js +0 -223
- package/dist/chunk-7WUKH3ZD.js +0 -221
- package/dist/chunk-AE2HPMUZ.js +0 -80
- package/dist/chunk-AEAOYVIL.js +0 -200
- package/dist/chunk-B5S3PUIR.js +0 -388
- package/dist/chunk-BJFCN2C3.js +0 -46
- package/dist/chunk-BNKPTE2U.js +0 -401
- package/dist/chunk-C5NBNU32.js +0 -240
- package/dist/chunk-CJFGQE7D.js +0 -46
- package/dist/chunk-CUUXZSKW.js +0 -611
- package/dist/chunk-DCU3646I.js +0 -12
- package/dist/chunk-DEWAIK5X.js +0 -11
- package/dist/chunk-DRD6EVTT.js +0 -447
- package/dist/chunk-DXCL6I4Q.js +0 -399
- package/dist/chunk-E4KAGBU7.js +0 -134
- package/dist/chunk-E6AYE22H.js +0 -343
- package/dist/chunk-EF3677RE.js +0 -93
- package/dist/chunk-EVWDYCBL.js +0 -223
- package/dist/chunk-EW4PWFHB.js +0 -46
- package/dist/chunk-FAZUMWBS.js +0 -93
- package/dist/chunk-GEHSFPCD.js +0 -93
- package/dist/chunk-GFOBGYW4.js +0 -252
- package/dist/chunk-INDDXWAH.js +0 -92
- package/dist/chunk-IXWQWFYT.js +0 -342
- package/dist/chunk-J3J4PBQ7.js +0 -710
- package/dist/chunk-K54U353Z.js +0 -691
- package/dist/chunk-K57ZFDGC.js +0 -15
- package/dist/chunk-NDA7EJJA.js +0 -286
- package/dist/chunk-NK2DA4X6.js +0 -357
- package/dist/chunk-OBYR4JHZ.js +0 -374
- package/dist/chunk-OJMTW22J.js +0 -286
- package/dist/chunk-OMUDRPUI.js +0 -195
- package/dist/chunk-ONKKRS2C.js +0 -239
- package/dist/chunk-OWFBBWU7.js +0 -196
- package/dist/chunk-OZRXDDEL.js +0 -46
- package/dist/chunk-P7EM3N73.js +0 -46
- package/dist/chunk-POYB6MCQ.js +0 -373
- package/dist/chunk-PR5QKMHM.js +0 -46
- package/dist/chunk-R44EOUS4.js +0 -288
- package/dist/chunk-R7FVSCQW.js +0 -415
- package/dist/chunk-RIP2MIZL.js +0 -710
- package/dist/chunk-RKMMEML5.js +0 -46
- package/dist/chunk-RM2BGDBB.js +0 -400
- package/dist/chunk-RREREIGW.js +0 -710
- package/dist/chunk-TQHLFQY4.js +0 -448
- package/dist/chunk-TY3SSQQK.js +0 -688
- package/dist/chunk-UGKPOCN5.js +0 -710
- package/dist/chunk-UIGKSCTD.js +0 -406
- package/dist/chunk-UWIVJRTI.js +0 -343
- package/dist/chunk-VA6WXRWB.js +0 -636
- package/dist/chunk-XC2FV57P.js +0 -385
- package/dist/chunk-XOQIADCH.js +0 -223
- package/dist/chunk-ZAQZKEH4.js +0 -46
- package/dist/chunk-ZBMOGUSJ.js +0 -17
- package/dist/chunk-ZXP6ENQY.js +0 -244
- package/dist/index.cjs +0 -1269
- package/dist/index.d.cts +0 -482
package/dist/api.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CoreConfig } from './config.js';
|
|
2
2
|
import { T as TokenProvider } from './tokenProvider-BWTusyj4.js';
|
|
3
|
-
import {
|
|
3
|
+
import { T as TurnUsage } from './contracts-CHmD-fMj.js';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
6
|
type HistoryImportProvider = "claude_code" | "cursor";
|
package/dist/collab.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as CollabApiClient,
|
|
2
|
-
export {
|
|
1
|
+
import { C as CollabApiClient, a as TurnUsagePayload, b as CollabFinalizeTurnResult, c as CollabRecordingPreflight, d as CollabApproveMode, e as CollabApproveResult, M as MergeRequestQueue, f as MergeRequest, I as InvitationScopeType, g as CollabMember, J as JsonObject, A as AppDeltaResponse, h as CollabStatus, i as MergeRequestReview } from './contracts-CHmD-fMj.js';
|
|
2
|
+
export { j as AppHeadResponse, k as AppMember, l as AppMemberRole, m as AppReconcileResponse, n as CollabFinalizeTurnAutoSync, o as CollabFinalizeTurnMode, p as CollabPendingFinalizeState, q as CollabPendingFinalizeSummary, r as CollabRecordingPreflightStatus, s as CollabRepoStateKind, t as CollabStatusBlockedReason, u as CollabStatusRecommendedAction, v as CollabTurn, w as MembershipScopeType, x as MergeRequestStatus, y as ModelCall, O as OrganizationMember, z as OrganizationMemberRole, P as ProjectMember, B as ProjectMemberRole, R as ReconcilePreflightResponse, S as ServerToolUsage, D as SyncLocalResponse, E as SyncUpstreamResponse, T as TurnUsage, F as TurnUsageCaptureSource, G as TurnUsageConfidence, H as TurnUsagePreviousPatch } from './contracts-CHmD-fMj.js';
|
|
3
3
|
import { B as BranchBindingMode } from './binding-WiIRI2fl.js';
|
|
4
4
|
|
|
5
5
|
declare function collabFinalizeTurn(params: {
|
package/dist/collab.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "./chunk-HZNEDSRS.js";
|
|
1
2
|
import {
|
|
2
3
|
getCollabBindingPath,
|
|
3
4
|
readCollabBinding,
|
|
@@ -8,7 +9,6 @@ import {
|
|
|
8
9
|
writeCollabBindingSnapshot,
|
|
9
10
|
writeJsonAtomic
|
|
10
11
|
} from "./chunk-YCFLOHJV.js";
|
|
11
|
-
import "./chunk-HZNEDSRS.js";
|
|
12
12
|
import {
|
|
13
13
|
applyUnifiedDiffToWorktree,
|
|
14
14
|
assertRepoSnapshotUnchanged,
|
|
@@ -674,4 +674,4 @@ type CollabApiClient = {
|
|
|
674
674
|
}): Promise<unknown>;
|
|
675
675
|
};
|
|
676
676
|
|
|
677
|
-
export type { AppDeltaResponse as A,
|
|
677
|
+
export type { AppDeltaResponse as A, ProjectMemberRole as B, CollabApiClient as C, SyncLocalResponse as D, SyncUpstreamResponse as E, TurnUsageCaptureSource as F, TurnUsageConfidence as G, TurnUsagePreviousPatch as H, InvitationScopeType as I, JsonObject as J, MergeRequestQueue as M, OrganizationMember as O, ProjectMember as P, ReconcilePreflightResponse as R, ServerToolUsage as S, TurnUsage as T, TurnUsagePayload as a, CollabFinalizeTurnResult as b, CollabRecordingPreflight as c, CollabApproveMode as d, CollabApproveResult as e, MergeRequest as f, CollabMember as g, CollabStatus as h, MergeRequestReview as i, AppHeadResponse as j, AppMember as k, AppMemberRole as l, AppReconcileResponse as m, CollabFinalizeTurnAutoSync as n, CollabFinalizeTurnMode as o, CollabPendingFinalizeState as p, CollabPendingFinalizeSummary as q, CollabRecordingPreflightStatus as r, CollabRepoStateKind as s, CollabStatusBlockedReason as t, CollabStatusRecommendedAction as u, CollabTurn as v, MembershipScopeType as w, MergeRequestStatus as x, ModelCall as y, OrganizationMemberRole as z };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { T as TurnUsage } from './contracts-CHmD-fMj.js';
|
|
2
|
+
|
|
3
|
+
type TranscriptEvent = Record<string, unknown>;
|
|
4
|
+
type ReadTranscriptResult = {
|
|
5
|
+
ok: true;
|
|
6
|
+
events: TranscriptEvent[];
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
reason: "transcript_not_found" | "transcript_unreadable";
|
|
10
|
+
};
|
|
11
|
+
declare function readAndParseTranscript(transcriptPath: string): Promise<ReadTranscriptResult>;
|
|
12
|
+
|
|
13
|
+
declare const HARVESTER_WARNING_CODES: readonly ["cache_split_unavailable", "unknown_server_tool", "transcript_truncated", "subagent_model_differs", "server_tool_count_mismatch"];
|
|
14
|
+
type HarvesterWarningCode = (typeof HARVESTER_WARNING_CODES)[number];
|
|
15
|
+
type HarvestWarning = {
|
|
16
|
+
code: HarvesterWarningCode;
|
|
17
|
+
message: string;
|
|
18
|
+
};
|
|
19
|
+
type HarvestUsageInput = {
|
|
20
|
+
events: TranscriptEvent[];
|
|
21
|
+
sessionId: string;
|
|
22
|
+
promptText: string;
|
|
23
|
+
submittedAt: string;
|
|
24
|
+
checkSubsequentEvent?: boolean;
|
|
25
|
+
nextBoundaryAt?: string | null;
|
|
26
|
+
agent: {
|
|
27
|
+
name: "claude-code";
|
|
28
|
+
version: string | null;
|
|
29
|
+
sessionId: string | null;
|
|
30
|
+
turnId: string | null;
|
|
31
|
+
plan: string | null;
|
|
32
|
+
};
|
|
33
|
+
capturedAt: string;
|
|
34
|
+
extensions: Record<string, unknown> | null;
|
|
35
|
+
};
|
|
36
|
+
type HarvestUsageFailureReason = "no_user_boundary_found" | "no_messages_for_turn";
|
|
37
|
+
type HarvestUsageResult = {
|
|
38
|
+
ok: true;
|
|
39
|
+
usage: TurnUsage;
|
|
40
|
+
boundaryAt: string | null;
|
|
41
|
+
} | {
|
|
42
|
+
ok: false;
|
|
43
|
+
reason: HarvestUsageFailureReason;
|
|
44
|
+
};
|
|
45
|
+
declare function harvestClaudeCodeUsage(input: HarvestUsageInput): HarvestUsageResult;
|
|
46
|
+
type SlicedTurn = {
|
|
47
|
+
sessionId: string;
|
|
48
|
+
promptId: string | null;
|
|
49
|
+
promptText: string | null;
|
|
50
|
+
assistantText: string | null;
|
|
51
|
+
occurredAt: string;
|
|
52
|
+
gitBranch: string | null;
|
|
53
|
+
cwd: string | null;
|
|
54
|
+
usage: TurnUsage;
|
|
55
|
+
};
|
|
56
|
+
type SliceTranscriptInput = {
|
|
57
|
+
events: TranscriptEvent[];
|
|
58
|
+
sessionId: string;
|
|
59
|
+
capturedAt: string;
|
|
60
|
+
extensions?: Record<string, unknown> | null;
|
|
61
|
+
};
|
|
62
|
+
declare function sliceTranscriptIntoTurns(input: SliceTranscriptInput): SlicedTurn[];
|
|
63
|
+
|
|
64
|
+
export { HARVESTER_WARNING_CODES, type HarvestUsageFailureReason, type HarvestUsageInput, type HarvestUsageResult, type HarvestWarning, type HarvesterWarningCode, type ReadTranscriptResult, type SliceTranscriptInput, type SlicedTurn, type TranscriptEvent, harvestClaudeCodeUsage, readAndParseTranscript, sliceTranscriptIntoTurns };
|
package/dist/history.js
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
// src/history/claudeCodeTranscript.ts
|
|
2
|
+
import fs from "fs/promises";
|
|
3
|
+
async function readAndParseTranscript(transcriptPath) {
|
|
4
|
+
let raw;
|
|
5
|
+
try {
|
|
6
|
+
raw = await fs.readFile(transcriptPath, "utf8");
|
|
7
|
+
} catch (err) {
|
|
8
|
+
const code = err && typeof err === "object" && "code" in err ? err.code : null;
|
|
9
|
+
if (code === "ENOENT") {
|
|
10
|
+
return { ok: false, reason: "transcript_not_found" };
|
|
11
|
+
}
|
|
12
|
+
return { ok: false, reason: "transcript_unreadable" };
|
|
13
|
+
}
|
|
14
|
+
const events = [];
|
|
15
|
+
for (const line of raw.split("\n")) {
|
|
16
|
+
const trimmed = line.trim();
|
|
17
|
+
if (!trimmed) continue;
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(trimmed);
|
|
20
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
21
|
+
events.push(parsed);
|
|
22
|
+
}
|
|
23
|
+
} catch {
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { ok: true, events };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/history/claudeCodeUsageHarvester.ts
|
|
30
|
+
var HARVESTER_WARNING_CODES = [
|
|
31
|
+
"cache_split_unavailable",
|
|
32
|
+
"unknown_server_tool",
|
|
33
|
+
"transcript_truncated",
|
|
34
|
+
"subagent_model_differs",
|
|
35
|
+
"server_tool_count_mismatch"
|
|
36
|
+
];
|
|
37
|
+
var BOUNDARY_TIMESTAMP_TOLERANCE_MS = 500;
|
|
38
|
+
function parseTimestamp(value) {
|
|
39
|
+
if (typeof value !== "string") return null;
|
|
40
|
+
const ms = Date.parse(value);
|
|
41
|
+
return Number.isFinite(ms) ? ms : null;
|
|
42
|
+
}
|
|
43
|
+
function extractUserContentText(message) {
|
|
44
|
+
if (!message || typeof message !== "object") return null;
|
|
45
|
+
const content = message.content;
|
|
46
|
+
if (typeof content === "string") return content;
|
|
47
|
+
if (Array.isArray(content)) {
|
|
48
|
+
const textBlocks = content.filter((block) => Boolean(block) && typeof block === "object").filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text);
|
|
49
|
+
if (textBlocks.length === 0) return null;
|
|
50
|
+
return textBlocks.join("\n");
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function isUserBoundary(event) {
|
|
55
|
+
return event.type === "user" && event.isMeta !== true && event.isSidechain !== true;
|
|
56
|
+
}
|
|
57
|
+
function extractAssistantContentText(turnEvents) {
|
|
58
|
+
const chunks = [];
|
|
59
|
+
for (const ev of turnEvents) {
|
|
60
|
+
if (ev.type !== "assistant") continue;
|
|
61
|
+
const text = extractUserContentText(ev.message);
|
|
62
|
+
if (text && text.length > 0) chunks.push(text);
|
|
63
|
+
}
|
|
64
|
+
if (chunks.length === 0) return null;
|
|
65
|
+
const deduped = [];
|
|
66
|
+
for (const chunk of chunks) {
|
|
67
|
+
if (deduped[deduped.length - 1] !== chunk) deduped.push(chunk);
|
|
68
|
+
}
|
|
69
|
+
return deduped.join("\n");
|
|
70
|
+
}
|
|
71
|
+
function findBoundary(sessionEvents, promptText, submittedAt, upperMs) {
|
|
72
|
+
const isWithinUpperBound = (ev) => {
|
|
73
|
+
if (upperMs === null) return true;
|
|
74
|
+
const ms = parseTimestamp(ev.timestamp);
|
|
75
|
+
return ms !== null && ms < upperMs;
|
|
76
|
+
};
|
|
77
|
+
let contentMatch = null;
|
|
78
|
+
for (let i = sessionEvents.length - 1; i >= 0; i--) {
|
|
79
|
+
const ev = sessionEvents[i];
|
|
80
|
+
if (!isUserBoundary(ev)) continue;
|
|
81
|
+
if (!isWithinUpperBound(ev)) continue;
|
|
82
|
+
const text = extractUserContentText(ev.message);
|
|
83
|
+
if (text !== null && text === promptText) {
|
|
84
|
+
contentMatch = ev;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (contentMatch) return { boundary: contentMatch, usedFallback: false };
|
|
89
|
+
const submittedMs = parseTimestamp(submittedAt);
|
|
90
|
+
if (submittedMs === null) return { boundary: null, usedFallback: false };
|
|
91
|
+
for (let i = sessionEvents.length - 1; i >= 0; i--) {
|
|
92
|
+
const ev = sessionEvents[i];
|
|
93
|
+
if (!isUserBoundary(ev)) continue;
|
|
94
|
+
if (!isWithinUpperBound(ev)) continue;
|
|
95
|
+
const ms = parseTimestamp(ev.timestamp);
|
|
96
|
+
if (ms === null) continue;
|
|
97
|
+
if (ms >= submittedMs - BOUNDARY_TIMESTAMP_TOLERANCE_MS) {
|
|
98
|
+
return { boundary: ev, usedFallback: true };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { boundary: null, usedFallback: false };
|
|
102
|
+
}
|
|
103
|
+
function asNumberOrNull(value) {
|
|
104
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
105
|
+
}
|
|
106
|
+
function asStringOrNull(value) {
|
|
107
|
+
return typeof value === "string" ? value : null;
|
|
108
|
+
}
|
|
109
|
+
function extractAssistantMessage(event) {
|
|
110
|
+
const message = event.message;
|
|
111
|
+
if (!message || typeof message !== "object") return null;
|
|
112
|
+
const msg = message;
|
|
113
|
+
if (msg.role !== "assistant" && msg.role !== void 0) {
|
|
114
|
+
}
|
|
115
|
+
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
116
|
+
const usage = msg.usage && typeof msg.usage === "object" ? msg.usage : null;
|
|
117
|
+
return {
|
|
118
|
+
id: asStringOrNull(msg.id),
|
|
119
|
+
model: asStringOrNull(msg.model),
|
|
120
|
+
content,
|
|
121
|
+
usage
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function usageIsComplete(usage) {
|
|
125
|
+
if (!usage) return false;
|
|
126
|
+
const hasInput = typeof usage.input_tokens === "number";
|
|
127
|
+
const hasOutput = typeof usage.output_tokens === "number";
|
|
128
|
+
const hasCacheRead = typeof usage.cache_read_input_tokens === "number";
|
|
129
|
+
return hasInput && hasOutput && hasCacheRead;
|
|
130
|
+
}
|
|
131
|
+
function buildModelCall(event, msg) {
|
|
132
|
+
const usage = msg.usage ?? {};
|
|
133
|
+
const cacheCreation = usage.cache_creation && typeof usage.cache_creation === "object" ? usage.cache_creation : null;
|
|
134
|
+
const has5m = cacheCreation && typeof cacheCreation.ephemeral_5m_input_tokens === "number";
|
|
135
|
+
const has1h = cacheCreation && typeof cacheCreation.ephemeral_1h_input_tokens === "number";
|
|
136
|
+
const cacheWrite5mTokens = has5m ? cacheCreation.ephemeral_5m_input_tokens : null;
|
|
137
|
+
const cacheWrite1hTokens = has1h ? cacheCreation.ephemeral_1h_input_tokens : null;
|
|
138
|
+
const splitAvailable = has5m || has1h;
|
|
139
|
+
const cacheWriteTokens = splitAvailable ? null : asNumberOrNull(usage.cache_creation_input_tokens);
|
|
140
|
+
return {
|
|
141
|
+
provider: "anthropic",
|
|
142
|
+
model: msg.model,
|
|
143
|
+
tier: asStringOrNull(usage.service_tier),
|
|
144
|
+
requestId: asStringOrNull(event.requestId),
|
|
145
|
+
timestamp: asStringOrNull(event.timestamp),
|
|
146
|
+
isSidechain: event.isSidechain === true,
|
|
147
|
+
inputTokens: asNumberOrNull(usage.input_tokens),
|
|
148
|
+
outputTokens: asNumberOrNull(usage.output_tokens),
|
|
149
|
+
cacheReadTokens: asNumberOrNull(usage.cache_read_input_tokens),
|
|
150
|
+
cacheWriteTokens,
|
|
151
|
+
cacheWrite5mTokens,
|
|
152
|
+
cacheWrite1hTokens,
|
|
153
|
+
reasoningTokens: null,
|
|
154
|
+
audioInputTokens: null,
|
|
155
|
+
imageInputTokens: null
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function scanServerToolUses(content) {
|
|
159
|
+
const uses = [];
|
|
160
|
+
for (const block of content) {
|
|
161
|
+
if (!block || typeof block !== "object") continue;
|
|
162
|
+
const b = block;
|
|
163
|
+
const id = b.id;
|
|
164
|
+
if (typeof id !== "string" || !id.startsWith("srvtoolu_")) continue;
|
|
165
|
+
const name = typeof b.name === "string" ? b.name : "";
|
|
166
|
+
switch (name) {
|
|
167
|
+
case "web_search":
|
|
168
|
+
uses.push({ tool: "web_search", unit: "per_request", isKnown: true, id, source: "direct" });
|
|
169
|
+
break;
|
|
170
|
+
case "web_fetch":
|
|
171
|
+
uses.push({ tool: "web_fetch", unit: "per_request", isKnown: true, id, source: "direct" });
|
|
172
|
+
break;
|
|
173
|
+
case "code_execution":
|
|
174
|
+
uses.push({ tool: "code_execution", unit: "invocation", isKnown: true, id, source: "direct" });
|
|
175
|
+
break;
|
|
176
|
+
default:
|
|
177
|
+
uses.push({ tool: name || "unknown", unit: "invocation", isKnown: false, id, source: "direct" });
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return uses;
|
|
182
|
+
}
|
|
183
|
+
function buildClientToolNameMap(turnEvents) {
|
|
184
|
+
const map = /* @__PURE__ */ new Map();
|
|
185
|
+
for (const ev of turnEvents) {
|
|
186
|
+
if (ev.type !== "assistant") continue;
|
|
187
|
+
const msg = ev.message;
|
|
188
|
+
if (!msg || typeof msg !== "object") continue;
|
|
189
|
+
const content = msg.content;
|
|
190
|
+
if (!Array.isArray(content)) continue;
|
|
191
|
+
for (const block of content) {
|
|
192
|
+
if (!block || typeof block !== "object") continue;
|
|
193
|
+
const b = block;
|
|
194
|
+
if (b.type !== "tool_use") continue;
|
|
195
|
+
const id = b.id;
|
|
196
|
+
const name = b.name;
|
|
197
|
+
if (typeof id !== "string" || typeof name !== "string") continue;
|
|
198
|
+
if (!id.startsWith("toolu_")) continue;
|
|
199
|
+
map.set(id, name);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return map;
|
|
203
|
+
}
|
|
204
|
+
function scanEmbeddedServerToolUses(turnEvents, clientToolNames) {
|
|
205
|
+
const uses = [];
|
|
206
|
+
for (const ev of turnEvents) {
|
|
207
|
+
if (ev.type !== "user") continue;
|
|
208
|
+
const tur = ev.toolUseResult;
|
|
209
|
+
if (!tur || typeof tur !== "object") continue;
|
|
210
|
+
const results = tur.results;
|
|
211
|
+
if (!Array.isArray(results)) continue;
|
|
212
|
+
let parentToolName = "";
|
|
213
|
+
const userMsg = ev.message;
|
|
214
|
+
if (userMsg && typeof userMsg === "object") {
|
|
215
|
+
const userContent = userMsg.content;
|
|
216
|
+
if (Array.isArray(userContent)) {
|
|
217
|
+
for (const block of userContent) {
|
|
218
|
+
if (!block || typeof block !== "object") continue;
|
|
219
|
+
const b = block;
|
|
220
|
+
if (b.type !== "tool_result") continue;
|
|
221
|
+
const parentId = b.tool_use_id;
|
|
222
|
+
if (typeof parentId === "string") {
|
|
223
|
+
parentToolName = clientToolNames.get(parentId) ?? "";
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
for (const entry of results) {
|
|
230
|
+
if (!entry || typeof entry !== "object") continue;
|
|
231
|
+
const srvId = entry.tool_use_id;
|
|
232
|
+
if (typeof srvId !== "string" || !srvId.startsWith("srvtoolu_")) continue;
|
|
233
|
+
if (parentToolName === "WebFetch") {
|
|
234
|
+
uses.push({ tool: "web_fetch", unit: "per_request", isKnown: true, id: srvId, source: "embedded" });
|
|
235
|
+
} else {
|
|
236
|
+
uses.push({ tool: "web_search", unit: "per_request", isKnown: true, id: srvId, source: "embedded" });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return uses;
|
|
241
|
+
}
|
|
242
|
+
function dedupeByServerToolId(records) {
|
|
243
|
+
const seen = /* @__PURE__ */ new Map();
|
|
244
|
+
for (const r of records) {
|
|
245
|
+
const existing = seen.get(r.id);
|
|
246
|
+
if (!existing) {
|
|
247
|
+
seen.set(r.id, r);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (existing.source === "embedded" && r.source === "direct") {
|
|
251
|
+
seen.set(r.id, r);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return Array.from(seen.values());
|
|
255
|
+
}
|
|
256
|
+
function aggregateServerTools(uses) {
|
|
257
|
+
const map = /* @__PURE__ */ new Map();
|
|
258
|
+
let sawUnknown = false;
|
|
259
|
+
let sawEmbedded = false;
|
|
260
|
+
for (const use of uses) {
|
|
261
|
+
if (!use.isKnown) sawUnknown = true;
|
|
262
|
+
if (use.source === "embedded") sawEmbedded = true;
|
|
263
|
+
const key = `anthropic|${use.tool}|${use.unit}`;
|
|
264
|
+
const existing = map.get(key);
|
|
265
|
+
if (existing) {
|
|
266
|
+
existing.quantity += 1;
|
|
267
|
+
} else {
|
|
268
|
+
map.set(key, { provider: "anthropic", tool: use.tool, unit: use.unit, quantity: 1 });
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return { serverTools: Array.from(map.values()), sawUnknown, sawEmbedded };
|
|
272
|
+
}
|
|
273
|
+
function sumCrossCheckCounts(usageBlocks) {
|
|
274
|
+
const totals = /* @__PURE__ */ new Map();
|
|
275
|
+
const keyFor = (raw) => {
|
|
276
|
+
if (raw === "web_search_requests") return "web_search";
|
|
277
|
+
if (raw === "web_fetch_requests") return "web_fetch";
|
|
278
|
+
return null;
|
|
279
|
+
};
|
|
280
|
+
for (const usage of usageBlocks) {
|
|
281
|
+
const stu = usage.server_tool_use;
|
|
282
|
+
if (!stu || typeof stu !== "object") continue;
|
|
283
|
+
for (const [rawKey, rawVal] of Object.entries(stu)) {
|
|
284
|
+
const mapped = keyFor(rawKey);
|
|
285
|
+
if (!mapped) continue;
|
|
286
|
+
if (typeof rawVal !== "number" || !Number.isFinite(rawVal)) continue;
|
|
287
|
+
totals.set(mapped, (totals.get(mapped) ?? 0) + rawVal);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return totals;
|
|
291
|
+
}
|
|
292
|
+
function primaryToolCounts(serverTools) {
|
|
293
|
+
const map = /* @__PURE__ */ new Map();
|
|
294
|
+
for (const entry of serverTools) {
|
|
295
|
+
map.set(entry.tool, (map.get(entry.tool) ?? 0) + entry.quantity);
|
|
296
|
+
}
|
|
297
|
+
return map;
|
|
298
|
+
}
|
|
299
|
+
function resolveVersion(events) {
|
|
300
|
+
for (const ev of events) {
|
|
301
|
+
if (typeof ev.version === "string" && ev.version.trim()) return ev.version.trim();
|
|
302
|
+
}
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
function buildTurnUsage(args) {
|
|
306
|
+
const assistantEvents = args.turnEvents.filter((ev) => ev.type === "assistant");
|
|
307
|
+
if (assistantEvents.length === 0) {
|
|
308
|
+
return { ok: false, reason: "no_messages_for_turn" };
|
|
309
|
+
}
|
|
310
|
+
const warnings = [...args.initialWarnings];
|
|
311
|
+
const calls = [];
|
|
312
|
+
const usageBlocks = [];
|
|
313
|
+
let anyIncomplete = false;
|
|
314
|
+
let anyComplete = false;
|
|
315
|
+
let sawLumpSumFallback = false;
|
|
316
|
+
const collectedServerToolUses = [];
|
|
317
|
+
const mainModels = /* @__PURE__ */ new Set();
|
|
318
|
+
const sidechainModels = /* @__PURE__ */ new Set();
|
|
319
|
+
for (const ev of assistantEvents) {
|
|
320
|
+
const msg = extractAssistantMessage(ev);
|
|
321
|
+
if (!msg) continue;
|
|
322
|
+
if (usageIsComplete(msg.usage)) {
|
|
323
|
+
anyComplete = true;
|
|
324
|
+
} else {
|
|
325
|
+
anyIncomplete = true;
|
|
326
|
+
}
|
|
327
|
+
if (msg.usage) usageBlocks.push(msg.usage);
|
|
328
|
+
const call = buildModelCall(ev, msg);
|
|
329
|
+
calls.push(call);
|
|
330
|
+
if (call.cacheWrite5mTokens === null && call.cacheWrite1hTokens === null && call.cacheWriteTokens !== null) {
|
|
331
|
+
sawLumpSumFallback = true;
|
|
332
|
+
}
|
|
333
|
+
collectedServerToolUses.push(...scanServerToolUses(msg.content));
|
|
334
|
+
if (call.model) {
|
|
335
|
+
if (call.isSidechain) sidechainModels.add(call.model);
|
|
336
|
+
else mainModels.add(call.model);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (calls.length === 0) {
|
|
340
|
+
return { ok: false, reason: "no_messages_for_turn" };
|
|
341
|
+
}
|
|
342
|
+
if (sawLumpSumFallback) {
|
|
343
|
+
warnings.push({
|
|
344
|
+
code: "cache_split_unavailable",
|
|
345
|
+
message: "Assistant message reported lump-sum cache_creation_input_tokens without the 5m/1h split."
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
const clientToolNames = buildClientToolNameMap(args.turnEvents);
|
|
349
|
+
const embeddedUses = scanEmbeddedServerToolUses(args.turnEvents, clientToolNames);
|
|
350
|
+
const merged = dedupeByServerToolId([...collectedServerToolUses, ...embeddedUses]);
|
|
351
|
+
const { serverTools, sawUnknown, sawEmbedded } = aggregateServerTools(merged);
|
|
352
|
+
if (sawUnknown) {
|
|
353
|
+
warnings.push({
|
|
354
|
+
code: "unknown_server_tool",
|
|
355
|
+
message: "Encountered a server tool whose name is not in the known list (web_search, web_fetch, code_execution)."
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
const crossCheck = sumCrossCheckCounts(usageBlocks);
|
|
359
|
+
const primary = primaryToolCounts(serverTools);
|
|
360
|
+
const allTools = /* @__PURE__ */ new Set([...crossCheck.keys(), ...primary.keys()]);
|
|
361
|
+
for (const tool of allTools) {
|
|
362
|
+
const crossVal = crossCheck.get(tool) ?? 0;
|
|
363
|
+
const primVal = primary.get(tool) ?? 0;
|
|
364
|
+
if (crossVal === primVal) continue;
|
|
365
|
+
if (sawEmbedded && crossVal === 0) continue;
|
|
366
|
+
warnings.push({
|
|
367
|
+
code: "server_tool_count_mismatch",
|
|
368
|
+
message: `Server-tool ${tool} count mismatch: srvtoolu_ scan=${primVal}, usage.server_tool_use=${crossVal}. Trusting srvtoolu_ count.`
|
|
369
|
+
});
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
const subagentMismatch = mainModels.size > 0 && sidechainModels.size > 0 && [...sidechainModels].some((m) => !mainModels.has(m));
|
|
373
|
+
if (subagentMismatch) {
|
|
374
|
+
warnings.push({
|
|
375
|
+
code: "subagent_model_differs",
|
|
376
|
+
message: "At least one sidechain ModelCall uses a model different from the main-chain model in this turn."
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
let confidence;
|
|
380
|
+
if (!anyComplete && anyIncomplete) confidence = "unknown";
|
|
381
|
+
else if (anyIncomplete) confidence = "partial";
|
|
382
|
+
else if (anyComplete) confidence = "exact";
|
|
383
|
+
else confidence = "unknown";
|
|
384
|
+
if (args.checkSubsequentEvent) {
|
|
385
|
+
const lastAssistantMs = (() => {
|
|
386
|
+
const msList = assistantEvents.map((ev) => parseTimestamp(ev.timestamp)).filter((ms) => ms !== null);
|
|
387
|
+
return msList.length ? Math.max(...msList) : null;
|
|
388
|
+
})();
|
|
389
|
+
const hasSubsequent = lastAssistantMs !== null && args.sessionEvents.some((ev) => {
|
|
390
|
+
const ms = parseTimestamp(ev.timestamp);
|
|
391
|
+
if (ms === null || ms <= lastAssistantMs) return false;
|
|
392
|
+
if (args.upperMs !== null && ms >= args.upperMs) return false;
|
|
393
|
+
return true;
|
|
394
|
+
});
|
|
395
|
+
if (!hasSubsequent && confidence === "exact") {
|
|
396
|
+
confidence = "partial";
|
|
397
|
+
warnings.push({
|
|
398
|
+
code: "transcript_truncated",
|
|
399
|
+
message: "Previous turn has no subsequent event after its last assistant message; transcript may be truncated."
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const resolvedVersion = args.agent.version ?? resolveVersion(args.turnEvents) ?? resolveVersion(args.sessionEvents);
|
|
404
|
+
const usage = {
|
|
405
|
+
schemaVersion: 1,
|
|
406
|
+
capturedAt: args.capturedAt,
|
|
407
|
+
captureSource: args.captureSource,
|
|
408
|
+
confidence,
|
|
409
|
+
agent: {
|
|
410
|
+
name: args.agent.name,
|
|
411
|
+
version: resolvedVersion,
|
|
412
|
+
sessionId: args.agent.sessionId,
|
|
413
|
+
turnId: args.agent.turnId,
|
|
414
|
+
plan: args.agent.plan
|
|
415
|
+
},
|
|
416
|
+
calls,
|
|
417
|
+
serverTools,
|
|
418
|
+
warnings,
|
|
419
|
+
extensions: args.extensions
|
|
420
|
+
};
|
|
421
|
+
return { ok: true, usage };
|
|
422
|
+
}
|
|
423
|
+
function harvestClaudeCodeUsage(input) {
|
|
424
|
+
const sessionEvents = input.events.filter((ev) => ev.sessionId === input.sessionId);
|
|
425
|
+
const upperMs = input.nextBoundaryAt ? parseTimestamp(input.nextBoundaryAt) : null;
|
|
426
|
+
const { boundary, usedFallback } = findBoundary(
|
|
427
|
+
sessionEvents,
|
|
428
|
+
input.promptText,
|
|
429
|
+
input.submittedAt,
|
|
430
|
+
upperMs
|
|
431
|
+
);
|
|
432
|
+
if (!boundary) {
|
|
433
|
+
return { ok: false, reason: "no_user_boundary_found" };
|
|
434
|
+
}
|
|
435
|
+
const boundaryMs = parseTimestamp(boundary.timestamp);
|
|
436
|
+
if (boundaryMs === null) {
|
|
437
|
+
return { ok: false, reason: "no_user_boundary_found" };
|
|
438
|
+
}
|
|
439
|
+
const turnEvents = sessionEvents.filter((ev) => {
|
|
440
|
+
const ms = parseTimestamp(ev.timestamp);
|
|
441
|
+
if (ms === null || ms <= boundaryMs) return false;
|
|
442
|
+
if (upperMs !== null && ms >= upperMs) return false;
|
|
443
|
+
return true;
|
|
444
|
+
});
|
|
445
|
+
const initialWarnings = [];
|
|
446
|
+
if (usedFallback) {
|
|
447
|
+
initialWarnings.push({
|
|
448
|
+
code: "transcript_truncated",
|
|
449
|
+
message: "Prompt-text equality match failed; used timestamp-tolerance fallback to locate the user boundary."
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
const built = buildTurnUsage({
|
|
453
|
+
sessionEvents,
|
|
454
|
+
turnEvents,
|
|
455
|
+
upperMs,
|
|
456
|
+
initialWarnings,
|
|
457
|
+
agent: input.agent,
|
|
458
|
+
capturedAt: input.capturedAt,
|
|
459
|
+
captureSource: "hook",
|
|
460
|
+
extensions: input.extensions,
|
|
461
|
+
checkSubsequentEvent: input.checkSubsequentEvent === true
|
|
462
|
+
});
|
|
463
|
+
if (!built.ok) return built;
|
|
464
|
+
return {
|
|
465
|
+
ok: true,
|
|
466
|
+
usage: built.usage,
|
|
467
|
+
boundaryAt: typeof boundary.timestamp === "string" ? boundary.timestamp : null
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
function sliceTranscriptIntoTurns(input) {
|
|
471
|
+
const sessionEvents = input.events.filter((ev) => ev.sessionId === input.sessionId);
|
|
472
|
+
const boundaries = sessionEvents.filter(isUserBoundary);
|
|
473
|
+
const result = [];
|
|
474
|
+
for (let i = 0; i < boundaries.length; i++) {
|
|
475
|
+
const boundary = boundaries[i];
|
|
476
|
+
const nextBoundary = boundaries[i + 1] ?? null;
|
|
477
|
+
const boundaryMs = parseTimestamp(boundary.timestamp);
|
|
478
|
+
if (boundaryMs === null) continue;
|
|
479
|
+
const occurredAt = asStringOrNull(boundary.timestamp);
|
|
480
|
+
if (occurredAt === null) continue;
|
|
481
|
+
const upperMs = nextBoundary ? parseTimestamp(nextBoundary.timestamp) : null;
|
|
482
|
+
const turnEvents = sessionEvents.filter((ev) => {
|
|
483
|
+
const ms = parseTimestamp(ev.timestamp);
|
|
484
|
+
if (ms === null || ms <= boundaryMs) return false;
|
|
485
|
+
if (upperMs !== null && ms >= upperMs) return false;
|
|
486
|
+
return true;
|
|
487
|
+
});
|
|
488
|
+
const promptId = asStringOrNull(boundary.promptId);
|
|
489
|
+
const promptText = extractUserContentText(boundary.message);
|
|
490
|
+
const assistantText = extractAssistantContentText(turnEvents);
|
|
491
|
+
const gitBranch = asStringOrNull(boundary.gitBranch);
|
|
492
|
+
const cwd = asStringOrNull(boundary.cwd);
|
|
493
|
+
const built = buildTurnUsage({
|
|
494
|
+
sessionEvents,
|
|
495
|
+
turnEvents,
|
|
496
|
+
upperMs,
|
|
497
|
+
initialWarnings: [],
|
|
498
|
+
agent: {
|
|
499
|
+
name: "claude-code",
|
|
500
|
+
version: null,
|
|
501
|
+
sessionId: input.sessionId,
|
|
502
|
+
turnId: promptId,
|
|
503
|
+
plan: null
|
|
504
|
+
},
|
|
505
|
+
capturedAt: input.capturedAt,
|
|
506
|
+
captureSource: "historical_import",
|
|
507
|
+
extensions: input.extensions ?? null,
|
|
508
|
+
checkSubsequentEvent: false
|
|
509
|
+
});
|
|
510
|
+
if (!built.ok) continue;
|
|
511
|
+
result.push({
|
|
512
|
+
sessionId: input.sessionId,
|
|
513
|
+
promptId,
|
|
514
|
+
promptText,
|
|
515
|
+
assistantText,
|
|
516
|
+
occurredAt,
|
|
517
|
+
gitBranch,
|
|
518
|
+
cwd,
|
|
519
|
+
usage: built.usage
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
return result;
|
|
523
|
+
}
|
|
524
|
+
export {
|
|
525
|
+
HARVESTER_WARNING_CODES,
|
|
526
|
+
harvestClaudeCodeUsage,
|
|
527
|
+
readAndParseTranscript,
|
|
528
|
+
sliceTranscriptIntoTurns
|
|
529
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -4,4 +4,4 @@ export { S as SessionStore, a as StoredSession, c as createStoredSessionTokenPro
|
|
|
4
4
|
export { createLocalSessionStore, createSupabaseAuthHelpers } from './auth.js';
|
|
5
5
|
export { AgentMemoryItem, AgentMemoryKind, AgentMemorySearchItem, AgentMemorySearchResponse, AgentMemorySummary, AgentMemoryTimelineResponse, ApiClient, AppContext, AppContextAccessPath, AppReconcileResponse, Bundle, BundlePlatform, BundleStatus, ChangeStepDiffResponse, InitiateBundleRequest, InvitationRecord, MergeRequest, MergeRequestReview, MergeRequestStatus, ReconcilePreflightResponse, SyncLocalResponse, SyncUpstreamResponse, createApiClient } from './api.js';
|
|
6
6
|
import 'zod';
|
|
7
|
-
import './contracts-
|
|
7
|
+
import './contracts-CHmD-fMj.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remixhq/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Remix core library",
|
|
5
5
|
"homepage": "https://github.com/RemixDotOne/remix-core",
|
|
6
6
|
"license": "MIT",
|
|
@@ -46,6 +46,10 @@
|
|
|
46
46
|
"types": "./dist/errors.d.ts",
|
|
47
47
|
"import": "./dist/errors.js"
|
|
48
48
|
},
|
|
49
|
+
"./history": {
|
|
50
|
+
"types": "./dist/history.d.ts",
|
|
51
|
+
"import": "./dist/history.js"
|
|
52
|
+
},
|
|
49
53
|
"./repo": {
|
|
50
54
|
"types": "./dist/repo.d.ts",
|
|
51
55
|
"import": "./dist/repo.js"
|
|
@@ -55,7 +59,7 @@
|
|
|
55
59
|
"dist"
|
|
56
60
|
],
|
|
57
61
|
"scripts": {
|
|
58
|
-
"build": "tsup src/index.ts src/api.ts src/auth.ts src/binding.ts src/collab.ts src/config.ts src/errors.ts src/repo.ts --dts --format esm",
|
|
62
|
+
"build": "tsup src/index.ts src/api.ts src/auth.ts src/binding.ts src/collab.ts src/config.ts src/errors.ts src/history.ts src/repo.ts --dts --format esm --clean",
|
|
59
63
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
60
64
|
"test": "vitest run",
|
|
61
65
|
"prepack": "npm run build"
|
package/dist/chunk-2WGZS7CD.js
DELETED
|
File without changes
|