@tracemarketplace/cli 0.0.22 → 0.0.24

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/src/flush.ts CHANGED
@@ -75,6 +75,23 @@ interface IngestResponse {
75
75
  trace_id?: string;
76
76
  }
77
77
 
78
+ export function prepareTraceForUpload(
79
+ trace: NormalizedTrace,
80
+ options: { homeDir?: string } = {},
81
+ ): NormalizedTrace {
82
+ const { homeDir = homedir() } = options;
83
+
84
+ // Keep session-sized raw payloads local until they have a separate upload path.
85
+ return redactTrace(
86
+ {
87
+ ...trace,
88
+ raw_json: null,
89
+ raw_json_format: null,
90
+ },
91
+ { homeDir },
92
+ );
93
+ }
94
+
78
95
  export function collectIdleSessionSources(
79
96
  sessions: Record<string, SessionUploadState>,
80
97
  now = new Date()
@@ -90,7 +107,10 @@ export function collectIdleSessionSources(
90
107
 
91
108
  interface ChunkExistsResponse {
92
109
  exists: boolean;
110
+ pending?: boolean;
111
+ status?: "queued" | "running" | "retry_wait" | "completed" | "duplicate" | "failed_terminal" | "payload_expired" | "missing";
93
112
  trace_id?: string;
113
+ retry_after_ms?: number;
94
114
  }
95
115
 
96
116
  export async function verifyUnconfirmedChunks(
@@ -100,20 +120,9 @@ export async function verifyUnconfirmedChunks(
100
120
  ): Promise<void> {
101
121
  for (const [key, session] of Object.entries(state.sessions)) {
102
122
  if (session.confirmedChunkIndex >= session.nextChunkIndex) continue;
103
-
104
- // Check if timed out — reset to re-submit from last confirmed point
105
- if (session.unconfirmedSince) {
106
- const age = now.getTime() - Date.parse(session.unconfirmedSince);
107
- if (age >= UNCONFIRMED_RESUBMIT_MS) {
108
- state.sessions[key] = {
109
- ...session,
110
- nextChunkIndex: session.confirmedChunkIndex,
111
- openChunkStartTurn: session.confirmedOpenChunkStartTurn,
112
- unconfirmedSince: null,
113
- };
114
- continue;
115
- }
116
- }
123
+ const timedOut = session.unconfirmedSince
124
+ ? now.getTime() - Date.parse(session.unconfirmedSince) >= UNCONFIRMED_RESUBMIT_MS
125
+ : false;
117
126
 
118
127
  // Check each unconfirmed chunk sequentially — stop at first missing one
119
128
  for (let i = session.confirmedChunkIndex; i < session.nextChunkIndex; i++) {
@@ -124,20 +133,52 @@ export async function verifyUnconfirmedChunks(
124
133
  chunk_index: String(i),
125
134
  });
126
135
  const result = await client.get(`/api/v1/traces/exists?${params}`) as ChunkExistsResponse;
127
- if (!result.exists) break;
128
- state.sessions[key] = {
129
- ...state.sessions[key]!,
130
- confirmedChunkIndex: i + 1,
131
- confirmedOpenChunkStartTurn: state.sessions[key]!.openChunkStartTurn,
132
- unconfirmedSince: i + 1 >= session.nextChunkIndex ? null : state.sessions[key]!.unconfirmedSince,
133
- };
136
+ if (result.exists) {
137
+ state.sessions[key] = {
138
+ ...state.sessions[key]!,
139
+ confirmedChunkIndex: i + 1,
140
+ confirmedOpenChunkStartTurn: state.sessions[key]!.openChunkStartTurn,
141
+ unconfirmedSince: i + 1 >= session.nextChunkIndex ? null : state.sessions[key]!.unconfirmedSince,
142
+ };
143
+ continue;
144
+ }
145
+
146
+ if (result.pending) {
147
+ break;
148
+ }
149
+
150
+ if (result.status === "failed_terminal" || result.status === "payload_expired") {
151
+ resetSessionToConfirmedBaseline(state, key, session);
152
+ break;
153
+ }
154
+
155
+ if (timedOut) {
156
+ resetSessionToConfirmedBaseline(state, key, session);
157
+ }
158
+ break;
134
159
  } catch {
160
+ if (timedOut) {
161
+ resetSessionToConfirmedBaseline(state, key, session);
162
+ }
135
163
  break;
136
164
  }
137
165
  }
138
166
  }
139
167
  }
140
168
 
169
+ function resetSessionToConfirmedBaseline(
170
+ state: ReturnType<typeof loadState>,
171
+ key: string,
172
+ session: SessionUploadState,
173
+ ): void {
174
+ state.sessions[key] = {
175
+ ...session,
176
+ nextChunkIndex: session.confirmedChunkIndex,
177
+ openChunkStartTurn: session.confirmedOpenChunkStartTurn,
178
+ unconfirmedSince: null,
179
+ };
180
+ }
181
+
141
182
  export async function flushTrackedSessions(
142
183
  config: Config,
143
184
  sources: SessionSource[],
@@ -400,7 +441,7 @@ async function uploadTraceChunk(
400
441
  sync = false,
401
442
  ): Promise<ChunkUploadResult> {
402
443
  // Client-side regex redaction runs before transmission; Presidio runs server-side async.
403
- const payloadTrace = redactTrace(trace, { homeDir: homedir() });
444
+ const payloadTrace = prepareTraceForUpload(trace);
404
445
  const jsonSize = JSON.stringify({ trace: payloadTrace, source_tool: payloadTrace.source_tool }).length;
405
446
  console.error(`[upload] ${payloadTrace.source_session_id} payload=${Math.round(jsonSize/1024)}KB turns=${payloadTrace.turn_count}`);
406
447