@evident-ai/cli 3.6.1-dev.4f2b317 → 3.6.1-dev.5d5fa2a
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 +395 -79
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1256,6 +1256,36 @@ function effectiveCorrelatedRun(messages, userMessageId) {
|
|
|
1256
1256
|
function extractReplyTextForMessage(messages, opencodeUserMessageId) {
|
|
1257
1257
|
return lastText(effectiveCorrelatedRun(messages, opencodeUserMessageId));
|
|
1258
1258
|
}
|
|
1259
|
+
function isRecord(value) {
|
|
1260
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1261
|
+
}
|
|
1262
|
+
function projectV2ToolContent(content) {
|
|
1263
|
+
if (!isRecord(content) || content.type !== "tool" || typeof content.name !== "string" || !isRecord(content.state)) {
|
|
1264
|
+
return null;
|
|
1265
|
+
}
|
|
1266
|
+
const { state } = content;
|
|
1267
|
+
const status2 = state.status;
|
|
1268
|
+
if (status2 !== "streaming" && status2 !== "running" && status2 !== "completed" && status2 !== "error") {
|
|
1269
|
+
return null;
|
|
1270
|
+
}
|
|
1271
|
+
const projectedState = {
|
|
1272
|
+
status: status2 === "streaming" ? "pending" : status2
|
|
1273
|
+
};
|
|
1274
|
+
if (status2 !== "streaming" && isRecord(state.input)) projectedState.input = state.input;
|
|
1275
|
+
const output = Array.isArray(state.content) ? state.content.filter(
|
|
1276
|
+
(entry) => isRecord(entry) && entry.type === "text" && typeof entry.text === "string"
|
|
1277
|
+
).map((entry) => entry.text) : [];
|
|
1278
|
+
if (output.length > 0) projectedState.output = output.join("\n");
|
|
1279
|
+
if (status2 === "error" && isRecord(state.error) && typeof state.error.message === "string") {
|
|
1280
|
+
projectedState.error = state.error.message;
|
|
1281
|
+
}
|
|
1282
|
+
return {
|
|
1283
|
+
type: "tool",
|
|
1284
|
+
tool: content.name,
|
|
1285
|
+
...typeof content.id === "string" ? { callID: content.id } : {},
|
|
1286
|
+
state: projectedState
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1259
1289
|
|
|
1260
1290
|
// ../../packages/types/src/telemetry/index.ts
|
|
1261
1291
|
var TelemetryEventTypes = {
|
|
@@ -1445,7 +1475,7 @@ import ora4 from "ora";
|
|
|
1445
1475
|
import { select as select4 } from "@inquirer/prompts";
|
|
1446
1476
|
|
|
1447
1477
|
// src/lib/telemetry.ts
|
|
1448
|
-
var CLI_VERSION = (true ? "3.6.1-dev.
|
|
1478
|
+
var CLI_VERSION = (true ? "3.6.1-dev.5d5fa2a" : void 0) ?? process.env.npm_package_version ?? "unknown";
|
|
1449
1479
|
function getCliVersion() {
|
|
1450
1480
|
return CLI_VERSION;
|
|
1451
1481
|
}
|
|
@@ -3075,7 +3105,7 @@ function buildSessionArchive(input) {
|
|
|
3075
3105
|
};
|
|
3076
3106
|
return { ...archive, content_fingerprint: fingerprintArchive(archive) };
|
|
3077
3107
|
}
|
|
3078
|
-
function
|
|
3108
|
+
function isRecord2(value) {
|
|
3079
3109
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3080
3110
|
}
|
|
3081
3111
|
function errorMessage2(error2) {
|
|
@@ -3213,7 +3243,7 @@ async function exportV2SessionMessages(client, sessionId, signal) {
|
|
|
3213
3243
|
}
|
|
3214
3244
|
const path = `${basePath}?${params.toString()}`;
|
|
3215
3245
|
const { body } = await requestPage(client, sessionId, path, signal);
|
|
3216
|
-
if (!
|
|
3246
|
+
if (!isRecord2(body) || !Array.isArray(body.data) || !isRecord2(body.cursor)) {
|
|
3217
3247
|
throw invalidResponse("v2", sessionId, path, "expected a {data: [], cursor: {\u2026}} envelope");
|
|
3218
3248
|
}
|
|
3219
3249
|
messages.push(...body.data);
|
|
@@ -3260,7 +3290,7 @@ function readWatermarks(path, log3) {
|
|
|
3260
3290
|
}
|
|
3261
3291
|
try {
|
|
3262
3292
|
const parsed = JSON.parse(content);
|
|
3263
|
-
if (!
|
|
3293
|
+
if (!isRecord3(parsed)) throw new Error("invalid watermark object");
|
|
3264
3294
|
const entries = Object.entries(parsed);
|
|
3265
3295
|
if (!entries.every(([sessionId, value]) => sessionId.length > 0 && isWatermark(value))) {
|
|
3266
3296
|
throw new Error("invalid watermark entry");
|
|
@@ -3283,12 +3313,12 @@ function recordUpload(path, sessionId, entry, watermarks) {
|
|
|
3283
3313
|
watermarks.clear();
|
|
3284
3314
|
for (const [id, watermark] of updated) watermarks.set(id, watermark);
|
|
3285
3315
|
}
|
|
3286
|
-
function
|
|
3316
|
+
function isRecord3(value) {
|
|
3287
3317
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3288
3318
|
}
|
|
3289
3319
|
function isWatermark(value) {
|
|
3290
|
-
if (!
|
|
3291
|
-
return typeof value.fingerprint === "string" && typeof value.uploaded_at === "string" && typeof value.key === "string";
|
|
3320
|
+
if (!isRecord3(value)) return false;
|
|
3321
|
+
return typeof value.fingerprint === "string" && typeof value.uploaded_at === "string" && typeof value.key === "string" && (!("conversation_id" in value) || value.conversation_id === null || typeof value.conversation_id === "string");
|
|
3292
3322
|
}
|
|
3293
3323
|
function isMissingFile3(error2) {
|
|
3294
3324
|
return error2 instanceof Error && "code" in error2 && error2.code === "ENOENT";
|
|
@@ -3310,7 +3340,7 @@ var shell_contract_default = {
|
|
|
3310
3340
|
"session-db-verify",
|
|
3311
3341
|
"archive-put"
|
|
3312
3342
|
],
|
|
3313
|
-
archiveStdinMaxBytes:
|
|
3343
|
+
archiveStdinMaxBytes: 33554432
|
|
3314
3344
|
};
|
|
3315
3345
|
|
|
3316
3346
|
// src/lib/runner-synchroniser.ts
|
|
@@ -3450,9 +3480,15 @@ function runSynchroniser(args, opts) {
|
|
|
3450
3480
|
var MAX_SESSION_ARCHIVE_BYTES = MAX_ARCHIVE_STDIN_BYTES;
|
|
3451
3481
|
var EXIT_ARCHIVE_CONFIG_MISSING = 50;
|
|
3452
3482
|
var EXIT_ARCHIVE_ACCESS_DENIED = 51;
|
|
3453
|
-
function transportFailure(bytes, reason) {
|
|
3483
|
+
function transportFailure(bytes, reason, exitCode) {
|
|
3454
3484
|
const message = reason === "missing-executable" ? "runner-synchroniser is unavailable; session archival requires a hosted runner." : reason === "timeout" ? "runner-synchroniser timed out before the archive upload completed." : "session archive upload did not complete.";
|
|
3455
|
-
return {
|
|
3485
|
+
return {
|
|
3486
|
+
kind: "transport-failed",
|
|
3487
|
+
bytes,
|
|
3488
|
+
reason,
|
|
3489
|
+
message,
|
|
3490
|
+
...exitCode !== void 0 ? { exitCode } : {}
|
|
3491
|
+
};
|
|
3456
3492
|
}
|
|
3457
3493
|
function isJson(body) {
|
|
3458
3494
|
try {
|
|
@@ -3497,10 +3533,157 @@ async function uploadSessionArchive(key, body, options) {
|
|
|
3497
3533
|
}
|
|
3498
3534
|
return transportFailure(
|
|
3499
3535
|
bytes.byteLength,
|
|
3500
|
-
result.code === null ? "spawn-failed" : "process-failed"
|
|
3536
|
+
result.code === null ? "spawn-failed" : "process-failed",
|
|
3537
|
+
result.code ?? void 0
|
|
3501
3538
|
);
|
|
3502
3539
|
}
|
|
3503
3540
|
|
|
3541
|
+
// src/lib/opencode/session-binding-resolution.ts
|
|
3542
|
+
var SESSION_BINDING_PROJECTION_CHUNK_SIZE = 500;
|
|
3543
|
+
var SESSION_BINDING_PROJECTION_TIMEOUT_MS = 1e4;
|
|
3544
|
+
function isRecord4(value) {
|
|
3545
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3546
|
+
}
|
|
3547
|
+
function isProjectionSource(value) {
|
|
3548
|
+
return value === "current" || value === "invocation" || value === "history";
|
|
3549
|
+
}
|
|
3550
|
+
function emptySessionBindingProjection() {
|
|
3551
|
+
return {
|
|
3552
|
+
current: /* @__PURE__ */ new Map(),
|
|
3553
|
+
invocation: /* @__PURE__ */ new Map(),
|
|
3554
|
+
history: /* @__PURE__ */ new Map(),
|
|
3555
|
+
conflicts: /* @__PURE__ */ new Set()
|
|
3556
|
+
};
|
|
3557
|
+
}
|
|
3558
|
+
function requestedSessionIds(sessions) {
|
|
3559
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3560
|
+
for (const session of sessions) {
|
|
3561
|
+
if (session.id.length > 0) ids.add(session.id);
|
|
3562
|
+
if (typeof session.parentID === "string" && session.parentID.length > 0) {
|
|
3563
|
+
ids.add(session.parentID);
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
return [...ids];
|
|
3567
|
+
}
|
|
3568
|
+
function parseProjectionResponse(value, requestedIds) {
|
|
3569
|
+
if (!isRecord4(value) || !Array.isArray(value.bindings) || !Array.isArray(value.conflicts)) {
|
|
3570
|
+
return null;
|
|
3571
|
+
}
|
|
3572
|
+
const projection = emptySessionBindingProjection();
|
|
3573
|
+
for (const candidate of value.bindings) {
|
|
3574
|
+
if (!isRecord4(candidate) || typeof candidate.opencode_session_id !== "string" || typeof candidate.conversation_id !== "string" || !isProjectionSource(candidate.source) || !requestedIds.has(candidate.opencode_session_id) || projection.conflicts.has(candidate.opencode_session_id)) {
|
|
3575
|
+
return null;
|
|
3576
|
+
}
|
|
3577
|
+
const bindings = projection[candidate.source];
|
|
3578
|
+
if (bindings.has(candidate.opencode_session_id)) return null;
|
|
3579
|
+
bindings.set(candidate.opencode_session_id, candidate.conversation_id);
|
|
3580
|
+
}
|
|
3581
|
+
for (const conflict of value.conflicts) {
|
|
3582
|
+
if (typeof conflict !== "string" || !requestedIds.has(conflict) || projection.conflicts.has(conflict) || projection.current.has(conflict) || projection.invocation.has(conflict) || projection.history.has(conflict)) {
|
|
3583
|
+
return null;
|
|
3584
|
+
}
|
|
3585
|
+
projection.conflicts.add(conflict);
|
|
3586
|
+
}
|
|
3587
|
+
return projection;
|
|
3588
|
+
}
|
|
3589
|
+
async function fetchSessionBindingProjection({
|
|
3590
|
+
apiUrl,
|
|
3591
|
+
runnerId,
|
|
3592
|
+
authHeader,
|
|
3593
|
+
sessions,
|
|
3594
|
+
signal,
|
|
3595
|
+
fetchImpl = fetch
|
|
3596
|
+
}) {
|
|
3597
|
+
const ids = requestedSessionIds(sessions);
|
|
3598
|
+
const projection = emptySessionBindingProjection();
|
|
3599
|
+
const failures = [];
|
|
3600
|
+
if (ids.length === 0) return { projection, complete: true, failures };
|
|
3601
|
+
for (let offset = 0; offset < ids.length; offset += SESSION_BINDING_PROJECTION_CHUNK_SIZE) {
|
|
3602
|
+
const chunk = ids.slice(offset, offset + SESSION_BINDING_PROJECTION_CHUNK_SIZE);
|
|
3603
|
+
const chunkIndex = Math.floor(offset / SESSION_BINDING_PROJECTION_CHUNK_SIZE) + 1;
|
|
3604
|
+
try {
|
|
3605
|
+
const response = await fetchImpl(
|
|
3606
|
+
`${apiUrl}/runners/${runnerId}/conversations/session-bindings`,
|
|
3607
|
+
{
|
|
3608
|
+
method: "POST",
|
|
3609
|
+
headers: {
|
|
3610
|
+
Authorization: authHeader,
|
|
3611
|
+
"Content-Type": "application/json"
|
|
3612
|
+
},
|
|
3613
|
+
body: JSON.stringify({ opencode_session_ids: chunk }),
|
|
3614
|
+
signal: signal ?? AbortSignal.timeout(SESSION_BINDING_PROJECTION_TIMEOUT_MS)
|
|
3615
|
+
}
|
|
3616
|
+
);
|
|
3617
|
+
if (!response.ok) {
|
|
3618
|
+
failures.push({ chunk: chunkIndex, kind: "http", status: response.status });
|
|
3619
|
+
continue;
|
|
3620
|
+
}
|
|
3621
|
+
const result = parseProjectionResponse(await response.json(), new Set(chunk));
|
|
3622
|
+
if (result === null) {
|
|
3623
|
+
failures.push({ chunk: chunkIndex, kind: "invalid-response" });
|
|
3624
|
+
continue;
|
|
3625
|
+
}
|
|
3626
|
+
for (const source of ["current", "invocation", "history"]) {
|
|
3627
|
+
for (const [sessionId, conversationId] of result[source]) {
|
|
3628
|
+
projection[source].set(sessionId, conversationId);
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
for (const conflict of result.conflicts) projection.conflicts.add(conflict);
|
|
3632
|
+
} catch (error2) {
|
|
3633
|
+
failures.push({
|
|
3634
|
+
chunk: chunkIndex,
|
|
3635
|
+
kind: "network",
|
|
3636
|
+
message: error2 instanceof Error ? error2.message : String(error2)
|
|
3637
|
+
});
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
return { projection, complete: failures.length === 0, failures };
|
|
3641
|
+
}
|
|
3642
|
+
function directResolution(sessionId, sources) {
|
|
3643
|
+
const localBinding = sources.ledger.get(sessionId);
|
|
3644
|
+
if (localBinding) return { conversation_id: localBinding, source: "ledger" };
|
|
3645
|
+
const watermarkedBinding = sources.watermarks.get(sessionId)?.conversation_id;
|
|
3646
|
+
if (typeof watermarkedBinding === "string" && watermarkedBinding.length > 0) {
|
|
3647
|
+
return { conversation_id: watermarkedBinding, source: "watermark" };
|
|
3648
|
+
}
|
|
3649
|
+
if (sources.projection.conflicts.has(sessionId)) return { reason: "conflict" };
|
|
3650
|
+
for (const source of ["current", "invocation", "history"]) {
|
|
3651
|
+
const conversationId = sources.projection[source].get(sessionId);
|
|
3652
|
+
if (conversationId) return { conversation_id: conversationId, source };
|
|
3653
|
+
}
|
|
3654
|
+
return null;
|
|
3655
|
+
}
|
|
3656
|
+
function isResolved(resolution) {
|
|
3657
|
+
return "conversation_id" in resolution;
|
|
3658
|
+
}
|
|
3659
|
+
function resolveSessionBindings(sessions, sources) {
|
|
3660
|
+
const resolutions = /* @__PURE__ */ new Map();
|
|
3661
|
+
for (const session of sessions) {
|
|
3662
|
+
resolutions.set(session.id, directResolution(session.id, sources) ?? { reason: "unmapped" });
|
|
3663
|
+
}
|
|
3664
|
+
let assignedParent = true;
|
|
3665
|
+
while (assignedParent) {
|
|
3666
|
+
assignedParent = false;
|
|
3667
|
+
for (const session of sessions) {
|
|
3668
|
+
const resolution = resolutions.get(session.id);
|
|
3669
|
+
if (isResolved(resolution) || resolution.reason !== "unmapped") continue;
|
|
3670
|
+
if (typeof session.parentID !== "string" || session.parentID.length === 0) continue;
|
|
3671
|
+
const parent = resolutions.get(session.parentID) ?? directResolution(session.parentID, sources) ?? { reason: "unmapped" };
|
|
3672
|
+
if (isResolved(parent)) {
|
|
3673
|
+
resolutions.set(session.id, {
|
|
3674
|
+
conversation_id: parent.conversation_id,
|
|
3675
|
+
source: "parent"
|
|
3676
|
+
});
|
|
3677
|
+
assignedParent = true;
|
|
3678
|
+
} else if (parent.reason === "conflict" || parent.reason === "parent-conflict") {
|
|
3679
|
+
resolutions.set(session.id, { reason: "parent-conflict" });
|
|
3680
|
+
assignedParent = true;
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
return resolutions;
|
|
3685
|
+
}
|
|
3686
|
+
|
|
3504
3687
|
// src/lib/opencode/session-archive-run.ts
|
|
3505
3688
|
var SESSION_ARCHIVE_UPLOAD_TIMEOUT_MS = 6e4;
|
|
3506
3689
|
function updatedAt(session) {
|
|
@@ -3513,6 +3696,12 @@ function sessionArchiveKey(prefix, sessionId) {
|
|
|
3513
3696
|
function failureMessage(error2) {
|
|
3514
3697
|
return error2 instanceof Error ? error2.message : String(error2);
|
|
3515
3698
|
}
|
|
3699
|
+
function countMessageParts(messages) {
|
|
3700
|
+
return messages.reduce((count, message) => {
|
|
3701
|
+
if (typeof message !== "object" || message === null || !("parts" in message)) return count;
|
|
3702
|
+
return count + (Array.isArray(message.parts) ? message.parts.length : 0);
|
|
3703
|
+
}, 0);
|
|
3704
|
+
}
|
|
3516
3705
|
function isBudgetExpired(deadline, now, signal) {
|
|
3517
3706
|
return signal?.aborted === true || now() >= deadline;
|
|
3518
3707
|
}
|
|
@@ -3552,6 +3741,19 @@ async function runSessionArchive({
|
|
|
3552
3741
|
skippedBudgetIds: [],
|
|
3553
3742
|
neverWatermarkedFailures: 0,
|
|
3554
3743
|
unmappedIds: [],
|
|
3744
|
+
conflictedIds: [],
|
|
3745
|
+
unresolved: 0,
|
|
3746
|
+
conflicts: 0,
|
|
3747
|
+
reconciliationComplete: deps.reconciliationComplete ?? true,
|
|
3748
|
+
reconciliationIncomplete: 0,
|
|
3749
|
+
bindingSourceCounts: {
|
|
3750
|
+
ledger: 0,
|
|
3751
|
+
watermark: 0,
|
|
3752
|
+
current: 0,
|
|
3753
|
+
invocation: 0,
|
|
3754
|
+
history: 0,
|
|
3755
|
+
parent: 0
|
|
3756
|
+
},
|
|
3555
3757
|
archivedSessionIds: [],
|
|
3556
3758
|
failures: [],
|
|
3557
3759
|
staleSince: null
|
|
@@ -3560,6 +3762,22 @@ async function runSessionArchive({
|
|
|
3560
3762
|
const upload = deps.upload ?? uploadSessionArchive;
|
|
3561
3763
|
const exportMessages = deps.exportMessages ?? exportSessionMessages;
|
|
3562
3764
|
const writeWatermark = deps.recordWatermark ?? recordUpload;
|
|
3765
|
+
const resolutions = resolveSessionBindings(sessions, {
|
|
3766
|
+
ledger: deps.bindings,
|
|
3767
|
+
watermarks: deps.watermarks,
|
|
3768
|
+
projection: deps.projection ?? emptySessionBindingProjection()
|
|
3769
|
+
});
|
|
3770
|
+
for (const [sessionId, resolution] of resolutions) {
|
|
3771
|
+
if ("conversation_id" in resolution) {
|
|
3772
|
+
summary.bindingSourceCounts[resolution.source]++;
|
|
3773
|
+
} else if (resolution.reason === "conflict" || resolution.reason === "parent-conflict") {
|
|
3774
|
+
summary.conflictedIds.push(sessionId);
|
|
3775
|
+
} else {
|
|
3776
|
+
summary.unmappedIds.push(sessionId);
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
summary.unresolved = summary.unmappedIds.length + summary.conflictedIds.length;
|
|
3780
|
+
summary.conflicts = summary.conflictedIds.length;
|
|
3563
3781
|
const failedWatermarks = [];
|
|
3564
3782
|
const recordFailedWatermark = (watermark) => {
|
|
3565
3783
|
if (watermark) failedWatermarks.push(watermark.uploaded_at);
|
|
@@ -3573,8 +3791,22 @@ async function runSessionArchive({
|
|
|
3573
3791
|
summary.skippedBudget = summary.skippedBudgetIds.length;
|
|
3574
3792
|
break;
|
|
3575
3793
|
}
|
|
3576
|
-
const
|
|
3577
|
-
|
|
3794
|
+
const resolution = resolutions.get(session.id) ?? { reason: "unmapped" };
|
|
3795
|
+
const resolved = "conversation_id" in resolution;
|
|
3796
|
+
const conversationId = resolved ? resolution.conversation_id : null;
|
|
3797
|
+
const bindingSource = resolved ? resolution.source : "unmapped";
|
|
3798
|
+
if (!resolved && !summary.reconciliationComplete) {
|
|
3799
|
+
summary.failed++;
|
|
3800
|
+
summary.reconciliationIncomplete++;
|
|
3801
|
+
summary.failures.push({
|
|
3802
|
+
sessionId: session.id,
|
|
3803
|
+
outcome: "reconciliation-incomplete",
|
|
3804
|
+
reason: resolution.reason,
|
|
3805
|
+
archived: false
|
|
3806
|
+
});
|
|
3807
|
+
recordFailedWatermark(deps.watermarks.get(session.id));
|
|
3808
|
+
continue;
|
|
3809
|
+
}
|
|
3578
3810
|
const exportBudget = createBudgetSignal(deps.signal, remainingMs);
|
|
3579
3811
|
let messages;
|
|
3580
3812
|
try {
|
|
@@ -3611,7 +3843,7 @@ async function runSessionArchive({
|
|
|
3611
3843
|
messages,
|
|
3612
3844
|
apiVersion: deps.client.version,
|
|
3613
3845
|
conversationId,
|
|
3614
|
-
bindingSource
|
|
3846
|
+
bindingSource,
|
|
3615
3847
|
runnerId: deps.runnerId,
|
|
3616
3848
|
archivedAt
|
|
3617
3849
|
});
|
|
@@ -3648,6 +3880,11 @@ async function runSessionArchive({
|
|
|
3648
3880
|
outcome: outcome.kind,
|
|
3649
3881
|
...reason !== void 0 ? { reason } : {},
|
|
3650
3882
|
..."message" in outcome ? { message: outcome.message } : {},
|
|
3883
|
+
bytes: outcome.bytes,
|
|
3884
|
+
byteLimit: MAX_SESSION_ARCHIVE_BYTES,
|
|
3885
|
+
messageCount: messages.length,
|
|
3886
|
+
partCount: countMessageParts(messages),
|
|
3887
|
+
..."exitCode" in outcome && outcome.exitCode !== void 0 ? { exitCode: outcome.exitCode } : {},
|
|
3651
3888
|
archived: false
|
|
3652
3889
|
});
|
|
3653
3890
|
recordFailedWatermark(existing);
|
|
@@ -3663,7 +3900,8 @@ async function runSessionArchive({
|
|
|
3663
3900
|
const watermark = {
|
|
3664
3901
|
fingerprint: snapshot.content_fingerprint,
|
|
3665
3902
|
uploaded_at: new Date(now()).toISOString(),
|
|
3666
|
-
key
|
|
3903
|
+
key,
|
|
3904
|
+
conversation_id: conversationId
|
|
3667
3905
|
};
|
|
3668
3906
|
try {
|
|
3669
3907
|
writeWatermark(deps.watermarkPath, session.id, watermark, deps.watermarks);
|
|
@@ -4620,8 +4858,15 @@ function collectSubagentSessions(messages, userMessageId) {
|
|
|
4620
4858
|
for (const message of assistants) {
|
|
4621
4859
|
const parts = Array.isArray(message.parts) ? message.parts : [];
|
|
4622
4860
|
for (const part of parts) {
|
|
4623
|
-
if (!part || typeof part !== "object" || part.type !== "tool"
|
|
4861
|
+
if (!part || typeof part !== "object" || part.type !== "tool") continue;
|
|
4862
|
+
const childSession = part.childSession;
|
|
4863
|
+
if (childSession) {
|
|
4864
|
+
if (seen.has(childSession.sessionId)) continue;
|
|
4865
|
+
seen.add(childSession.sessionId);
|
|
4866
|
+
refs.push(childSession);
|
|
4624
4867
|
continue;
|
|
4868
|
+
}
|
|
4869
|
+
if (part.tool !== "task") continue;
|
|
4625
4870
|
const state = part.state;
|
|
4626
4871
|
if (!state || typeof state !== "object") continue;
|
|
4627
4872
|
const metadata = state.metadata;
|
|
@@ -5223,14 +5468,14 @@ async function probeOpenCodeRequestReadiness(port, client) {
|
|
|
5223
5468
|
|
|
5224
5469
|
// src/lib/opencode/session-v2.ts
|
|
5225
5470
|
var ALL_HTTP_STATUSES2 = Array.from({ length: 500 }, (_, index) => index + 100);
|
|
5226
|
-
function
|
|
5471
|
+
function isRecord5(value) {
|
|
5227
5472
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5228
5473
|
}
|
|
5229
5474
|
function finiteNumber2(value) {
|
|
5230
5475
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
5231
5476
|
}
|
|
5232
5477
|
function adaptTime(value) {
|
|
5233
|
-
if (!
|
|
5478
|
+
if (!isRecord5(value)) return void 0;
|
|
5234
5479
|
const created = finiteNumber2(value.created);
|
|
5235
5480
|
const completed = finiteNumber2(value.completed);
|
|
5236
5481
|
if (created === void 0 && completed === void 0) return void 0;
|
|
@@ -5240,11 +5485,11 @@ function adaptTime(value) {
|
|
|
5240
5485
|
};
|
|
5241
5486
|
}
|
|
5242
5487
|
function adaptTokens(value) {
|
|
5243
|
-
if (!
|
|
5488
|
+
if (!isRecord5(value)) return void 0;
|
|
5244
5489
|
const input = finiteNumber2(value.input);
|
|
5245
5490
|
const output = finiteNumber2(value.output);
|
|
5246
5491
|
const reasoning = finiteNumber2(value.reasoning);
|
|
5247
|
-
const cache =
|
|
5492
|
+
const cache = isRecord5(value.cache) ? {
|
|
5248
5493
|
...finiteNumber2(value.cache.read) !== void 0 ? { read: finiteNumber2(value.cache.read) } : {},
|
|
5249
5494
|
...finiteNumber2(value.cache.write) !== void 0 ? { write: finiteNumber2(value.cache.write) } : {}
|
|
5250
5495
|
} : void 0;
|
|
@@ -5268,7 +5513,7 @@ function adaptMessageInfo(value, role) {
|
|
|
5268
5513
|
if (typeof value.finish === "string") info.finish = value.finish;
|
|
5269
5514
|
if ("error" in value) info.error = value.error;
|
|
5270
5515
|
if (typeof value.agent === "string") info.agent = value.agent;
|
|
5271
|
-
if (
|
|
5516
|
+
if (isRecord5(value.model)) {
|
|
5272
5517
|
if (typeof value.model.id === "string") info.modelID = value.model.id;
|
|
5273
5518
|
if (typeof value.model.providerID === "string") info.providerID = value.model.providerID;
|
|
5274
5519
|
}
|
|
@@ -5277,8 +5522,16 @@ function adaptMessageInfo(value, role) {
|
|
|
5277
5522
|
if (tokens) info.tokens = tokens;
|
|
5278
5523
|
return info;
|
|
5279
5524
|
}
|
|
5525
|
+
function v2ChildSessionEvidence(content) {
|
|
5526
|
+
const state = isRecord5(content.state) ? content.state : null;
|
|
5527
|
+
const metadata = state && isRecord5(state.metadata) ? state.metadata : null;
|
|
5528
|
+
const sessionId = typeof metadata?.sessionID === "string" && metadata.sessionID.length > 0 ? metadata.sessionID : typeof metadata?.sessionId === "string" && metadata.sessionId.length > 0 ? metadata.sessionId : null;
|
|
5529
|
+
if (sessionId === null) return null;
|
|
5530
|
+
const time = isRecord5(content.time) ? content.time : null;
|
|
5531
|
+
return { sessionId, startedAtMs: finiteNumber2(time?.created) ?? null };
|
|
5532
|
+
}
|
|
5280
5533
|
function adaptV2Message(value) {
|
|
5281
|
-
if (!
|
|
5534
|
+
if (!isRecord5(value) || typeof value.id !== "string" || typeof value.type !== "string") {
|
|
5282
5535
|
return null;
|
|
5283
5536
|
}
|
|
5284
5537
|
if (value.type === "user") {
|
|
@@ -5291,7 +5544,13 @@ function adaptV2Message(value) {
|
|
|
5291
5544
|
if (value.type !== "assistant" || !Array.isArray(value.content)) return null;
|
|
5292
5545
|
const parts = [];
|
|
5293
5546
|
for (const content of value.content) {
|
|
5294
|
-
if (!
|
|
5547
|
+
if (!isRecord5(content) || typeof content.type !== "string") return null;
|
|
5548
|
+
const toolPart = projectV2ToolContent(content);
|
|
5549
|
+
if (toolPart) {
|
|
5550
|
+
const childSession = v2ChildSessionEvidence(content);
|
|
5551
|
+
parts.push(childSession ? { ...toolPart, childSession } : toolPart);
|
|
5552
|
+
continue;
|
|
5553
|
+
}
|
|
5295
5554
|
if (content.type === "text") {
|
|
5296
5555
|
if (typeof content.text !== "string") return null;
|
|
5297
5556
|
parts.push({ type: "text", text: content.text });
|
|
@@ -5305,23 +5564,23 @@ function adaptV2Message(value) {
|
|
|
5305
5564
|
};
|
|
5306
5565
|
}
|
|
5307
5566
|
function adaptFormTool(value) {
|
|
5308
|
-
if (!
|
|
5567
|
+
if (!isRecord5(value) || typeof value.messageID !== "string" || typeof value.id !== "string") {
|
|
5309
5568
|
return void 0;
|
|
5310
5569
|
}
|
|
5311
5570
|
return { messageID: value.messageID, callID: value.id };
|
|
5312
5571
|
}
|
|
5313
5572
|
function adaptV2FormWire(value) {
|
|
5314
|
-
if (!
|
|
5573
|
+
if (!isRecord5(value) || typeof value.id !== "string" || typeof value.sessionID !== "string") {
|
|
5315
5574
|
return null;
|
|
5316
5575
|
}
|
|
5317
5576
|
return value;
|
|
5318
5577
|
}
|
|
5319
5578
|
function adaptV2FormField(value, header) {
|
|
5320
|
-
if (!
|
|
5579
|
+
if (!isRecord5(value)) return null;
|
|
5321
5580
|
const question = typeof value.title === "string" ? value.title : typeof value.question === "string" ? value.question : typeof value.key === "string" ? value.key : null;
|
|
5322
5581
|
if (!question) return null;
|
|
5323
5582
|
const options = Array.isArray(value.options) ? value.options.flatMap((option) => {
|
|
5324
|
-
if (!
|
|
5583
|
+
if (!isRecord5(option)) return [];
|
|
5325
5584
|
const label = typeof option.label === "string" ? option.label : typeof option.value === "string" ? option.value : null;
|
|
5326
5585
|
if (!label) return [];
|
|
5327
5586
|
return [
|
|
@@ -5339,7 +5598,7 @@ function adaptV2Form(value) {
|
|
|
5339
5598
|
const header = typeof form.title === "string" ? form.title : "";
|
|
5340
5599
|
const questions = form.fields.map((field) => adaptV2FormField(field, header)).filter((question) => question !== null);
|
|
5341
5600
|
if (questions.length === 0) return null;
|
|
5342
|
-
const tool =
|
|
5601
|
+
const tool = isRecord5(form.metadata) ? adaptFormTool(form.metadata.tool) : void 0;
|
|
5343
5602
|
return {
|
|
5344
5603
|
id: form.id,
|
|
5345
5604
|
sessionID: form.sessionID,
|
|
@@ -5349,7 +5608,7 @@ function adaptV2Form(value) {
|
|
|
5349
5608
|
};
|
|
5350
5609
|
}
|
|
5351
5610
|
function adaptV2FormList(value) {
|
|
5352
|
-
if (!
|
|
5611
|
+
if (!isRecord5(value) || !Array.isArray(value.data)) return null;
|
|
5353
5612
|
return value.data.map(adaptV2Form).filter((form) => form !== null);
|
|
5354
5613
|
}
|
|
5355
5614
|
function adaptPattern(value) {
|
|
@@ -5360,7 +5619,7 @@ function adaptPattern(value) {
|
|
|
5360
5619
|
return void 0;
|
|
5361
5620
|
}
|
|
5362
5621
|
function adaptV2PermissionWire(value) {
|
|
5363
|
-
if (!
|
|
5622
|
+
if (!isRecord5(value) || typeof value.id !== "string" || typeof value.sessionID !== "string") {
|
|
5364
5623
|
return null;
|
|
5365
5624
|
}
|
|
5366
5625
|
if (typeof value.permission !== "string" && typeof value.action !== "string") return null;
|
|
@@ -5372,12 +5631,12 @@ function adaptV2Permission(value) {
|
|
|
5372
5631
|
const type = permission.permission ?? permission.action;
|
|
5373
5632
|
if (!type) return null;
|
|
5374
5633
|
const pattern = adaptPattern(permission.pattern) ?? adaptPattern(permission.patterns) ?? adaptPattern(permission.resources);
|
|
5375
|
-
const time =
|
|
5634
|
+
const time = isRecord5(permission.time) ? finiteNumber2(permission.time.created) !== void 0 ? { created: finiteNumber2(permission.time.created) } : void 0 : void 0;
|
|
5376
5635
|
return {
|
|
5377
5636
|
id: permission.id,
|
|
5378
5637
|
type,
|
|
5379
5638
|
sessionID: permission.sessionID,
|
|
5380
|
-
metadata:
|
|
5639
|
+
metadata: isRecord5(permission.metadata) ? permission.metadata : {},
|
|
5381
5640
|
raw: permission,
|
|
5382
5641
|
...pattern !== void 0 ? { pattern } : {},
|
|
5383
5642
|
...typeof permission.messageID === "string" ? { messageID: permission.messageID } : {},
|
|
@@ -5387,12 +5646,12 @@ function adaptV2Permission(value) {
|
|
|
5387
5646
|
};
|
|
5388
5647
|
}
|
|
5389
5648
|
function adaptV2PermissionList(value) {
|
|
5390
|
-
if (!
|
|
5649
|
+
if (!isRecord5(value) || !Array.isArray(value.data)) return null;
|
|
5391
5650
|
return value.data.map(adaptV2Permission).filter((permission) => permission !== null);
|
|
5392
5651
|
}
|
|
5393
5652
|
function adaptV2Session(value) {
|
|
5394
|
-
if (!
|
|
5395
|
-
const time =
|
|
5653
|
+
if (!isRecord5(value) || typeof value.id !== "string" || value.id.length === 0) return null;
|
|
5654
|
+
const time = isRecord5(value.time) ? {
|
|
5396
5655
|
...finiteNumber2(value.time.created) !== void 0 ? { created: finiteNumber2(value.time.created) } : {},
|
|
5397
5656
|
...finiteNumber2(value.time.updated) !== void 0 ? { updated: finiteNumber2(value.time.updated) } : {}
|
|
5398
5657
|
} : void 0;
|
|
@@ -5404,7 +5663,7 @@ function adaptV2Session(value) {
|
|
|
5404
5663
|
};
|
|
5405
5664
|
}
|
|
5406
5665
|
function adaptV2SessionList(value) {
|
|
5407
|
-
if (!
|
|
5666
|
+
if (!isRecord5(value) || !Array.isArray(value.data) || !isRecord5(value.cursor)) return null;
|
|
5408
5667
|
return {
|
|
5409
5668
|
data: value.data.map(adaptV2Session).filter((session) => session !== null),
|
|
5410
5669
|
cursor: value.cursor
|
|
@@ -5413,18 +5672,18 @@ function adaptV2SessionList(value) {
|
|
|
5413
5672
|
function adaptV2Location(value) {
|
|
5414
5673
|
const candidates = [
|
|
5415
5674
|
value,
|
|
5416
|
-
|
|
5417
|
-
|
|
5675
|
+
isRecord5(value) ? value.data : void 0,
|
|
5676
|
+
isRecord5(value) ? value.location : void 0
|
|
5418
5677
|
];
|
|
5419
5678
|
for (const candidate of candidates) {
|
|
5420
|
-
if (!
|
|
5679
|
+
if (!isRecord5(candidate) || typeof candidate.directory !== "string") continue;
|
|
5421
5680
|
const directory = candidate.directory.trim();
|
|
5422
5681
|
if (directory) return directory;
|
|
5423
5682
|
}
|
|
5424
5683
|
return null;
|
|
5425
5684
|
}
|
|
5426
5685
|
function adaptV2Messages(value) {
|
|
5427
|
-
if (!
|
|
5686
|
+
if (!isRecord5(value) || !Array.isArray(value.data)) return [];
|
|
5428
5687
|
return value.data.slice().reverse().map(adaptV2Message).filter((message) => message !== null);
|
|
5429
5688
|
}
|
|
5430
5689
|
async function readJson(response) {
|
|
@@ -5439,7 +5698,7 @@ async function readJson(response) {
|
|
|
5439
5698
|
async function readData(client, path, init) {
|
|
5440
5699
|
const response = await client.request(path, init);
|
|
5441
5700
|
const body = await readJson(response);
|
|
5442
|
-
if (!
|
|
5701
|
+
if (!isRecord5(body) || !("data" in body)) {
|
|
5443
5702
|
throw new Error(`OpenCode V2 response for ${path} was missing its data envelope`);
|
|
5444
5703
|
}
|
|
5445
5704
|
return body.data;
|
|
@@ -5474,7 +5733,7 @@ async function createV2Session(client, directory) {
|
|
|
5474
5733
|
headers: { "Content-Type": "application/json" },
|
|
5475
5734
|
body: JSON.stringify({ location: { directory } })
|
|
5476
5735
|
});
|
|
5477
|
-
if (!
|
|
5736
|
+
if (!isRecord5(data) || typeof data.id !== "string" || data.id.length === 0) {
|
|
5478
5737
|
throw new Error("OpenCode V2 create session response was missing data.id");
|
|
5479
5738
|
}
|
|
5480
5739
|
return data.id;
|
|
@@ -5619,8 +5878,8 @@ async function sendV2Prompt(client, sessionId, text, options, onInvalidModelSele
|
|
|
5619
5878
|
`OpenCode V2 prompt response could not be read: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
5620
5879
|
);
|
|
5621
5880
|
}
|
|
5622
|
-
const data =
|
|
5623
|
-
if (!
|
|
5881
|
+
const data = isRecord5(body) && "data" in body ? body.data : void 0;
|
|
5882
|
+
if (!isRecord5(data) || typeof data.id !== "string" || data.id.length === 0) {
|
|
5624
5883
|
throw new OpenCodeV2PromptAckError("OpenCode V2 prompt response was missing data.id");
|
|
5625
5884
|
}
|
|
5626
5885
|
return data.id;
|
|
@@ -5629,7 +5888,7 @@ async function getV2SessionMessages(client, sessionId) {
|
|
|
5629
5888
|
const path = `/api/session/${encodeURIComponent(sessionId)}/message?order=desc&limit=200`;
|
|
5630
5889
|
try {
|
|
5631
5890
|
const body = await readJson(await client.request(path));
|
|
5632
|
-
if (!
|
|
5891
|
+
if (!isRecord5(body) || !Array.isArray(body.data) || !isRecord5(body.cursor)) return null;
|
|
5633
5892
|
return adaptV2Messages(body);
|
|
5634
5893
|
} catch (error2) {
|
|
5635
5894
|
console.error(
|
|
@@ -5668,7 +5927,7 @@ async function interruptV2Session(client, sessionId) {
|
|
|
5668
5927
|
async function getV2ActiveSessions(client) {
|
|
5669
5928
|
try {
|
|
5670
5929
|
const body = await readJson(await client.request("/api/session/active"));
|
|
5671
|
-
if (!
|
|
5930
|
+
if (!isRecord5(body) || !isRecord5(body.data)) return null;
|
|
5672
5931
|
return body.data;
|
|
5673
5932
|
} catch (error2) {
|
|
5674
5933
|
console.error(
|
|
@@ -5684,8 +5943,8 @@ async function isV2SessionOngoing(client, sessionId) {
|
|
|
5684
5943
|
}
|
|
5685
5944
|
function sessionErrorReason2(value) {
|
|
5686
5945
|
if (typeof value === "string" && value.trim()) return value.trim().slice(0, 500);
|
|
5687
|
-
if (
|
|
5688
|
-
const data =
|
|
5946
|
+
if (isRecord5(value)) {
|
|
5947
|
+
const data = isRecord5(value.data) ? value.data : void 0;
|
|
5689
5948
|
const reason = typeof data?.message === "string" && data.message || typeof value.message === "string" && value.message || typeof value.name === "string" && value.name;
|
|
5690
5949
|
if (reason) return reason.replace(/\s+/g, " ").trim().slice(0, 500);
|
|
5691
5950
|
}
|
|
@@ -5701,17 +5960,17 @@ function adaptV2SessionErrorEvent(value) {
|
|
|
5701
5960
|
return null;
|
|
5702
5961
|
}
|
|
5703
5962
|
}
|
|
5704
|
-
if (!
|
|
5963
|
+
if (!isRecord5(parsed)) return null;
|
|
5705
5964
|
try {
|
|
5706
5965
|
const establishedShape = parseSessionErrorFrame(JSON.stringify(parsed));
|
|
5707
5966
|
if (establishedShape) return establishedShape;
|
|
5708
5967
|
} catch (error2) {
|
|
5709
5968
|
void error2;
|
|
5710
5969
|
}
|
|
5711
|
-
const candidates = [parsed, parsed.payload, parsed.data].filter(
|
|
5970
|
+
const candidates = [parsed, parsed.payload, parsed.data].filter(isRecord5);
|
|
5712
5971
|
for (const event of candidates) {
|
|
5713
5972
|
if (event.type !== "session.error") continue;
|
|
5714
|
-
const properties = [event.properties, event.data, event].find(
|
|
5973
|
+
const properties = [event.properties, event.data, event].find(isRecord5);
|
|
5715
5974
|
if (!properties) continue;
|
|
5716
5975
|
const sessionId = typeof properties.sessionID === "string" && properties.sessionID || typeof properties.sessionId === "string" && properties.sessionId;
|
|
5717
5976
|
if (!sessionId) continue;
|
|
@@ -5847,7 +6106,7 @@ function parseCodexUsageHeaders(headers) {
|
|
|
5847
6106
|
function normalizeProbeModel(model) {
|
|
5848
6107
|
return model.endsWith("-fast") ? model.slice(0, -"-fast".length) : model;
|
|
5849
6108
|
}
|
|
5850
|
-
function
|
|
6109
|
+
function isRecord6(value) {
|
|
5851
6110
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5852
6111
|
}
|
|
5853
6112
|
function unsupportedProbeModels(reason, port) {
|
|
@@ -5858,14 +6117,14 @@ async function resolveV1ProbeModels(client, port) {
|
|
|
5858
6117
|
try {
|
|
5859
6118
|
const response = await client.request("/config/providers");
|
|
5860
6119
|
const body = await response.json();
|
|
5861
|
-
if (!
|
|
6120
|
+
if (!isRecord6(body) || !Array.isArray(body.providers)) {
|
|
5862
6121
|
return unsupportedProbeModels("V1 provider response did not contain a providers array", port);
|
|
5863
6122
|
}
|
|
5864
6123
|
const provider = body.providers.find(
|
|
5865
|
-
(candidate) =>
|
|
6124
|
+
(candidate) => isRecord6(candidate) && candidate.id === "openai"
|
|
5866
6125
|
);
|
|
5867
|
-
if (!provider || !
|
|
5868
|
-
const defaults2 =
|
|
6126
|
+
if (!provider || !isRecord6(provider.models)) return { status: "supported", models: [] };
|
|
6127
|
+
const defaults2 = isRecord6(body.default) ? body.default : void 0;
|
|
5869
6128
|
const candidates = [
|
|
5870
6129
|
...typeof defaults2?.openai === "string" ? [defaults2.openai] : [],
|
|
5871
6130
|
...Object.keys(provider.models)
|
|
@@ -5887,14 +6146,14 @@ async function resolveV2ProbeModels(client, port) {
|
|
|
5887
6146
|
try {
|
|
5888
6147
|
const response = await client.request(path);
|
|
5889
6148
|
const body = await response.json();
|
|
5890
|
-
if (!
|
|
6149
|
+
if (!isRecord6(body) || !Array.isArray(body.data)) {
|
|
5891
6150
|
return unsupportedProbeModels(`V2 GET ${path} did not contain a provider data array`, port);
|
|
5892
6151
|
}
|
|
5893
6152
|
const provider = body.data.find(
|
|
5894
|
-
(candidate) =>
|
|
6153
|
+
(candidate) => isRecord6(candidate) && candidate.id === "openai"
|
|
5895
6154
|
);
|
|
5896
6155
|
if (!provider) return { status: "supported", models: [] };
|
|
5897
|
-
if (!
|
|
6156
|
+
if (!isRecord6(provider.models)) {
|
|
5898
6157
|
return unsupportedProbeModels(
|
|
5899
6158
|
"V2 provider response has no safe OpenAI model catalogue",
|
|
5900
6159
|
port
|
|
@@ -6004,7 +6263,7 @@ var CONNECT_KEY_MAX_ATTEMPTS = 3;
|
|
|
6004
6263
|
var CONNECT_KEY_RETRY_DELAY_MS = 250;
|
|
6005
6264
|
var INTEGRATION_LIST_MAX_READS = 10;
|
|
6006
6265
|
var INTEGRATION_LIST_RETRY_DELAY_MS = 1e3;
|
|
6007
|
-
function
|
|
6266
|
+
function isRecord7(value) {
|
|
6008
6267
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6009
6268
|
}
|
|
6010
6269
|
var sleep2 = (milliseconds) => new Promise((resolve5) => setTimeout(resolve5, milliseconds));
|
|
@@ -6020,7 +6279,7 @@ function readOpenCodeCredentials(homeDir, log3) {
|
|
|
6020
6279
|
} catch (error2) {
|
|
6021
6280
|
return null;
|
|
6022
6281
|
}
|
|
6023
|
-
return
|
|
6282
|
+
return isRecord7(parsed) ? parsed : null;
|
|
6024
6283
|
} catch (error2) {
|
|
6025
6284
|
const code = error2.code;
|
|
6026
6285
|
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
@@ -6033,7 +6292,7 @@ function classifyOpenCodeCredentials(credentials2) {
|
|
|
6033
6292
|
const importable = [];
|
|
6034
6293
|
const unsupported = [];
|
|
6035
6294
|
for (const [integrationId, value] of Object.entries(credentials2)) {
|
|
6036
|
-
if (!
|
|
6295
|
+
if (!isRecord7(value) || typeof value.type !== "string") {
|
|
6037
6296
|
unsupported.push({ integrationId, reason: "unrecognised credential entry" });
|
|
6038
6297
|
continue;
|
|
6039
6298
|
}
|
|
@@ -6048,7 +6307,7 @@ function classifyOpenCodeCredentials(credentials2) {
|
|
|
6048
6307
|
unsupported.push({ integrationId, reason: "unrecognised credential entry" });
|
|
6049
6308
|
continue;
|
|
6050
6309
|
}
|
|
6051
|
-
if (value.metadata === void 0 ||
|
|
6310
|
+
if (value.metadata === void 0 || isRecord7(value.metadata) && Object.keys(value.metadata).length === 0) {
|
|
6052
6311
|
importable.push({ integrationId, key: value.key });
|
|
6053
6312
|
} else {
|
|
6054
6313
|
unsupported.push({ integrationId, reason: "needs the interactive connect flow" });
|
|
@@ -6125,10 +6384,10 @@ async function importOpenCodeCredentials({
|
|
|
6125
6384
|
return result;
|
|
6126
6385
|
}
|
|
6127
6386
|
function parseIntegrationList(value) {
|
|
6128
|
-
if (!
|
|
6387
|
+
if (!isRecord7(value) || !Array.isArray(value.data)) return null;
|
|
6129
6388
|
const integrationIds = /* @__PURE__ */ new Set();
|
|
6130
6389
|
for (const integration of value.data) {
|
|
6131
|
-
if (!
|
|
6390
|
+
if (!isRecord7(integration) || typeof integration.id !== "string" || !Array.isArray(integration.connections)) {
|
|
6132
6391
|
return null;
|
|
6133
6392
|
}
|
|
6134
6393
|
if (integration.connections.length > 0) integrationIds.add(integration.id);
|
|
@@ -17004,11 +17263,11 @@ function logSessionArchiveSummary(state, phase, summary) {
|
|
|
17004
17263
|
const everyUploadFailed = summary.uploadAttempts > 0 && summary.uploadFailures === summary.uploadAttempts;
|
|
17005
17264
|
const staleSince = everyUploadFailed && summary.staleSince !== null ? `; archive stale since ${summary.staleSince}` : "";
|
|
17006
17265
|
const neverWatermarked = summary.neverWatermarkedFailures > 0 ? `; ${summary.neverWatermarkedFailures} failed session(s) had no prior successful upload` : "";
|
|
17007
|
-
const warning2 = summary.failed > 0 || summary.failures.length > 0 || everyUploadFailed;
|
|
17266
|
+
const warning2 = summary.failed > 0 || summary.failures.length > 0 || everyUploadFailed || !summary.reconciliationComplete;
|
|
17008
17267
|
logSessionArchiveActivity(state, phase, {
|
|
17009
17268
|
type: "info",
|
|
17010
17269
|
level: warning2 ? "warn" : "info",
|
|
17011
|
-
message: `Session archive: inspected ${summary.inspected}, uploaded ${summary.uploaded}, unchanged ${summary.unchanged}, failed ${summary.failed}, skipped budget ${summary.skippedBudget}, unmapped ${summary.unmappedIds.length}` + staleSince + neverWatermarked,
|
|
17270
|
+
message: `Session archive: inspected ${summary.inspected}, uploaded ${summary.uploaded}, unchanged ${summary.unchanged}, failed ${summary.failed}, skipped budget ${summary.skippedBudget}, unmapped ${summary.unmappedIds.length}, conflicts ${summary.conflicts}, reconciliation incomplete ${summary.reconciliationIncomplete}; bindings ledger ${summary.bindingSourceCounts.ledger}, watermark ${summary.bindingSourceCounts.watermark}, current ${summary.bindingSourceCounts.current}, invocation ${summary.bindingSourceCounts.invocation}, history ${summary.bindingSourceCounts.history}, parent ${summary.bindingSourceCounts.parent}` + staleSince + neverWatermarked,
|
|
17012
17271
|
metadata: {
|
|
17013
17272
|
outcome: "archive-run-complete",
|
|
17014
17273
|
sessions_inspected: summary.inspected,
|
|
@@ -17019,22 +17278,41 @@ function logSessionArchiveSummary(state, phase, summary) {
|
|
|
17019
17278
|
uploads_failed: summary.uploadFailures,
|
|
17020
17279
|
sessions_skipped_budget: summary.skippedBudget,
|
|
17021
17280
|
sessions_unmapped: summary.unmappedIds.length,
|
|
17281
|
+
sessions_unresolved: summary.unresolved,
|
|
17282
|
+
sessions_conflicted: summary.conflicts,
|
|
17283
|
+
sessions_reconciliation_incomplete: summary.reconciliationIncomplete,
|
|
17284
|
+
binding_reconciliation_complete: summary.reconciliationComplete,
|
|
17285
|
+
bindings_from_ledger: summary.bindingSourceCounts.ledger,
|
|
17286
|
+
bindings_from_watermark: summary.bindingSourceCounts.watermark,
|
|
17287
|
+
bindings_from_current: summary.bindingSourceCounts.current,
|
|
17288
|
+
bindings_from_invocation: summary.bindingSourceCounts.invocation,
|
|
17289
|
+
bindings_from_history: summary.bindingSourceCounts.history,
|
|
17290
|
+
bindings_from_parent: summary.bindingSourceCounts.parent,
|
|
17022
17291
|
sessions_without_prior_watermark: summary.neverWatermarkedFailures,
|
|
17023
17292
|
...everyUploadFailed && summary.staleSince !== null ? { stale_since: summary.staleSince } : {}
|
|
17024
17293
|
}
|
|
17025
17294
|
});
|
|
17026
17295
|
for (const failure of summary.failures) {
|
|
17027
17296
|
const permanentSizeFailure = failure.reason === "too-large";
|
|
17028
|
-
const
|
|
17297
|
+
const hasPayloadDetails = failure.bytes !== void 0 && failure.byteLimit !== void 0 && failure.messageCount !== void 0 && failure.partCount !== void 0;
|
|
17298
|
+
const payloadDetails = hasPayloadDetails ? `; payload bytes=${failure.bytes} limit=${failure.byteLimit} messages=${failure.messageCount} parts=${failure.partCount}` : "";
|
|
17299
|
+
const safeMessage = !hasPayloadDetails && failure.message ? `: ${redactDiagnosticText(failure.message).slice(0, 200)}` : "";
|
|
17029
17300
|
logSessionArchiveActivity(state, phase, {
|
|
17030
17301
|
type: "info",
|
|
17031
17302
|
level: "warn",
|
|
17032
|
-
message: `Session archive: session ${failure.sessionId} ` + (permanentSizeFailure ? "failed permanently (too-large payload)" : `failed (${failure.outcome}`) + (permanentSizeFailure ? "" : failure.reason ? `, reason=${failure.reason})` : ")") + safeMessage,
|
|
17303
|
+
message: `Session archive: session ${failure.sessionId} ` + (permanentSizeFailure ? "failed permanently (too-large payload)" : `failed (${failure.outcome}`) + (permanentSizeFailure ? "" : failure.reason ? `, reason=${failure.reason})` : ")") + payloadDetails + (failure.exitCode !== void 0 ? `; child exit code=${failure.exitCode}` : "") + safeMessage,
|
|
17033
17304
|
metadata: {
|
|
17034
17305
|
outcome: failure.outcome,
|
|
17035
17306
|
session_id: failure.sessionId,
|
|
17036
17307
|
archived: failure.archived,
|
|
17037
|
-
...failure.reason !== void 0 ? { reason: failure.reason } : {}
|
|
17308
|
+
...failure.reason !== void 0 ? { reason: failure.reason } : {},
|
|
17309
|
+
...failure.exitCode !== void 0 ? { child_exit_code: failure.exitCode } : {},
|
|
17310
|
+
...hasPayloadDetails ? {
|
|
17311
|
+
payload_bytes: failure.bytes,
|
|
17312
|
+
payload_limit_bytes: failure.byteLimit,
|
|
17313
|
+
message_count: failure.messageCount,
|
|
17314
|
+
part_count: failure.partCount
|
|
17315
|
+
} : {}
|
|
17038
17316
|
}
|
|
17039
17317
|
});
|
|
17040
17318
|
}
|
|
@@ -17049,6 +17327,17 @@ function logSessionArchiveSummary(state, phase, summary) {
|
|
|
17049
17327
|
}
|
|
17050
17328
|
});
|
|
17051
17329
|
}
|
|
17330
|
+
if (summary.conflictedIds.length > 0) {
|
|
17331
|
+
logSessionArchiveActivity(state, phase, {
|
|
17332
|
+
type: "info",
|
|
17333
|
+
level: "warn",
|
|
17334
|
+
message: `Session archive: ${summary.conflictedIds.length} session(s) have conflicting conversation identities: ${summary.conflictedIds.join(", ")}`,
|
|
17335
|
+
metadata: {
|
|
17336
|
+
outcome: "conflicted-session-bindings",
|
|
17337
|
+
sessions_conflicted: summary.conflicts
|
|
17338
|
+
}
|
|
17339
|
+
});
|
|
17340
|
+
}
|
|
17052
17341
|
}
|
|
17053
17342
|
async function drainSessionDeletionReports(state) {
|
|
17054
17343
|
const path = sessionDeletionReportPath(homedir8(), process.env);
|
|
@@ -17507,21 +17796,48 @@ async function runSessionArchiveBatch(state, phase, sessions, budgetMs, signal)
|
|
|
17507
17796
|
});
|
|
17508
17797
|
return null;
|
|
17509
17798
|
}
|
|
17799
|
+
const bindings = readSessionBindings(
|
|
17800
|
+
sessionBindingLedgerPath(homedir8(), process.env),
|
|
17801
|
+
(message) => logSessionArchiveActivity(state, phase, {
|
|
17802
|
+
type: "info",
|
|
17803
|
+
level: "warn",
|
|
17804
|
+
message: redactDiagnosticText(message),
|
|
17805
|
+
metadata: { outcome: "binding-ledger-read-failed" }
|
|
17806
|
+
})
|
|
17807
|
+
);
|
|
17808
|
+
const reconciliation = await fetchSessionBindingProjection({
|
|
17809
|
+
apiUrl: getApiUrlConfig(),
|
|
17810
|
+
runnerId: state.agentId,
|
|
17811
|
+
authHeader: state.authHeader,
|
|
17812
|
+
sessions,
|
|
17813
|
+
signal
|
|
17814
|
+
});
|
|
17815
|
+
if (!reconciliation.complete) {
|
|
17816
|
+
const failure = reconciliation.failures[0];
|
|
17817
|
+
const detail = failure.kind === "http" ? `HTTP ${failure.status} for chunk ${failure.chunk}` : failure.kind === "network" ? `network failure for chunk ${failure.chunk}: ${redactDiagnosticText(failure.message ?? "unknown error").slice(0, 200)}` : `invalid response for chunk ${failure.chunk}`;
|
|
17818
|
+
logSessionArchiveActivity(state, phase, {
|
|
17819
|
+
type: "info",
|
|
17820
|
+
level: "warn",
|
|
17821
|
+
message: `Session archive: binding reconciliation incomplete for runner ${state.agentId}; ${reconciliation.failures.length} chunk(s) failed (${detail}), unresolved sessions will not replace existing archives`,
|
|
17822
|
+
metadata: {
|
|
17823
|
+
outcome: "binding-reconciliation-incomplete",
|
|
17824
|
+
runner_id: state.agentId,
|
|
17825
|
+
failed_chunks: reconciliation.failures.length,
|
|
17826
|
+
first_failed_chunk: failure.chunk,
|
|
17827
|
+
first_failure_kind: failure.kind,
|
|
17828
|
+
...failure.status !== void 0 ? { http_status: failure.status } : {}
|
|
17829
|
+
}
|
|
17830
|
+
});
|
|
17831
|
+
}
|
|
17510
17832
|
const summary = await runSessionArchive({
|
|
17511
17833
|
sessions,
|
|
17512
17834
|
deps: {
|
|
17513
17835
|
client,
|
|
17514
17836
|
runnerId: state.agentId,
|
|
17515
17837
|
keyPrefix: config.keyPrefix,
|
|
17516
|
-
bindings
|
|
17517
|
-
|
|
17518
|
-
|
|
17519
|
-
type: "info",
|
|
17520
|
-
level: "warn",
|
|
17521
|
-
message: redactDiagnosticText(message),
|
|
17522
|
-
metadata: { outcome: "binding-ledger-read-failed" }
|
|
17523
|
-
})
|
|
17524
|
-
),
|
|
17838
|
+
bindings,
|
|
17839
|
+
projection: reconciliation.projection,
|
|
17840
|
+
reconciliationComplete: reconciliation.complete,
|
|
17525
17841
|
watermarks: state.sessionArchiveWatermarks,
|
|
17526
17842
|
watermarkPath,
|
|
17527
17843
|
signal,
|