@ai-development-environment/control-agent 0.0.112 → 0.0.113
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/control-agent.js +1070 -248
- package/package.json +1 -1
package/dist/control-agent.js
CHANGED
|
@@ -3814,12 +3814,12 @@ var require_isexe = __commonJS({
|
|
|
3814
3814
|
if (typeof Promise !== "function") {
|
|
3815
3815
|
throw new TypeError("callback not provided");
|
|
3816
3816
|
}
|
|
3817
|
-
return new Promise(function(
|
|
3817
|
+
return new Promise(function(resolve11, reject) {
|
|
3818
3818
|
isexe(path, options || {}, function(er2, is) {
|
|
3819
3819
|
if (er2) {
|
|
3820
3820
|
reject(er2);
|
|
3821
3821
|
} else {
|
|
3822
|
-
|
|
3822
|
+
resolve11(is);
|
|
3823
3823
|
}
|
|
3824
3824
|
});
|
|
3825
3825
|
});
|
|
@@ -3885,27 +3885,27 @@ var require_which = __commonJS({
|
|
|
3885
3885
|
opt = {};
|
|
3886
3886
|
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
3887
3887
|
const found = [];
|
|
3888
|
-
const step = (i) => new Promise((
|
|
3888
|
+
const step = (i) => new Promise((resolve11, reject) => {
|
|
3889
3889
|
if (i === pathEnv.length)
|
|
3890
|
-
return opt.all && found.length ?
|
|
3890
|
+
return opt.all && found.length ? resolve11(found) : reject(getNotFoundError(cmd));
|
|
3891
3891
|
const ppRaw = pathEnv[i];
|
|
3892
3892
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
3893
3893
|
const pCmd = path.join(pathPart, cmd);
|
|
3894
3894
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
3895
|
-
|
|
3895
|
+
resolve11(subStep(p, i, 0));
|
|
3896
3896
|
});
|
|
3897
|
-
const subStep = (p, i, ii) => new Promise((
|
|
3897
|
+
const subStep = (p, i, ii) => new Promise((resolve11, reject) => {
|
|
3898
3898
|
if (ii === pathExt.length)
|
|
3899
|
-
return
|
|
3899
|
+
return resolve11(step(i + 1));
|
|
3900
3900
|
const ext = pathExt[ii];
|
|
3901
3901
|
isexe(p + ext, { pathExt: pathExtExe }, (er2, is) => {
|
|
3902
3902
|
if (!er2 && is) {
|
|
3903
3903
|
if (opt.all)
|
|
3904
3904
|
found.push(p + ext);
|
|
3905
3905
|
else
|
|
3906
|
-
return
|
|
3906
|
+
return resolve11(p + ext);
|
|
3907
3907
|
}
|
|
3908
|
-
return
|
|
3908
|
+
return resolve11(subStep(p, i, ii + 1));
|
|
3909
3909
|
});
|
|
3910
3910
|
});
|
|
3911
3911
|
return cb2 ? step(0).then((res) => cb2(null, res), cb2) : step(0);
|
|
@@ -4511,8 +4511,8 @@ function createClient(options) {
|
|
|
4511
4511
|
retryWait = async function randomisedExponentialBackoff(retries2) {
|
|
4512
4512
|
const retryDelaySeconds = Math.pow(2, retries2);
|
|
4513
4513
|
await new Promise(
|
|
4514
|
-
(
|
|
4515
|
-
|
|
4514
|
+
(resolve11) => setTimeout(
|
|
4515
|
+
resolve11,
|
|
4516
4516
|
retryDelaySeconds * 1e3 + // add random timeout from 300ms to 3s
|
|
4517
4517
|
Math.floor(Math.random() * (3e3 - 300) + 300)
|
|
4518
4518
|
)
|
|
@@ -4754,14 +4754,14 @@ function createClient(options) {
|
|
|
4754
4754
|
if (socket.readyState === WebSocketImpl.CLOSING) await throwOnClose;
|
|
4755
4755
|
let release2 = () => {
|
|
4756
4756
|
};
|
|
4757
|
-
const released = new Promise((
|
|
4757
|
+
const released = new Promise((resolve11) => release2 = resolve11);
|
|
4758
4758
|
return [
|
|
4759
4759
|
socket,
|
|
4760
4760
|
release2,
|
|
4761
4761
|
// resolves on release or rejects on error/close, whichever comes first.
|
|
4762
4762
|
// not racing with throwOnClose on purpose, it lives as long as the socket
|
|
4763
4763
|
// and every race would leak memory per operation
|
|
4764
|
-
new Promise((
|
|
4764
|
+
new Promise((resolve11, reject) => {
|
|
4765
4765
|
const unlisten = errorOrClosed(reject);
|
|
4766
4766
|
if (socket.readyState !== WebSocketImpl.OPEN)
|
|
4767
4767
|
throwOnClose.catch(reject);
|
|
@@ -4777,7 +4777,7 @@ function createClient(options) {
|
|
|
4777
4777
|
complete();
|
|
4778
4778
|
}
|
|
4779
4779
|
}
|
|
4780
|
-
|
|
4780
|
+
resolve11();
|
|
4781
4781
|
});
|
|
4782
4782
|
})
|
|
4783
4783
|
];
|
|
@@ -4922,7 +4922,7 @@ function createClient(options) {
|
|
|
4922
4922
|
const iterator = (async function* iterator2() {
|
|
4923
4923
|
for (; ; ) {
|
|
4924
4924
|
if (!pending.length) {
|
|
4925
|
-
await new Promise((
|
|
4925
|
+
await new Promise((resolve11) => deferred.resolve = resolve11);
|
|
4926
4926
|
}
|
|
4927
4927
|
while (pending.length) {
|
|
4928
4928
|
yield pending.shift();
|
|
@@ -5026,11 +5026,11 @@ async function writeArtifactTransferBytes(writer, bytes, position) {
|
|
|
5026
5026
|
}
|
|
5027
5027
|
}
|
|
5028
5028
|
async function artifactTransferRetryDelay(attempt, signal) {
|
|
5029
|
-
await new Promise((
|
|
5029
|
+
await new Promise((resolve11, reject) => {
|
|
5030
5030
|
const timeout = setTimeout(
|
|
5031
5031
|
() => {
|
|
5032
5032
|
signal.removeEventListener("abort", abort);
|
|
5033
|
-
|
|
5033
|
+
resolve11();
|
|
5034
5034
|
},
|
|
5035
5035
|
Math.min(4e3, 250 * 2 ** attempt)
|
|
5036
5036
|
);
|
|
@@ -5441,7 +5441,7 @@ var AgentGraphQLClient = class {
|
|
|
5441
5441
|
metadata.error || `Artifact transfer ${metadata.status.toLowerCase()}`
|
|
5442
5442
|
);
|
|
5443
5443
|
}
|
|
5444
|
-
await new Promise((
|
|
5444
|
+
await new Promise((resolve11) => setTimeout(resolve11, 1e3));
|
|
5445
5445
|
}
|
|
5446
5446
|
if (!Number.isSafeInteger(metadata.uploadLength) || !metadata.uploadLength || !metadata.checksum || !metadata.filename) {
|
|
5447
5447
|
throw new Error("Artifact transfer metadata is incomplete");
|
|
@@ -5815,7 +5815,7 @@ function createAgentSubscriptionClient(config) {
|
|
|
5815
5815
|
shouldRetry: () => true,
|
|
5816
5816
|
retryWait: async (retries) => {
|
|
5817
5817
|
const delay = Math.min(3e4, 1e3 * 2 ** Math.min(retries, 5));
|
|
5818
|
-
await new Promise((
|
|
5818
|
+
await new Promise((resolve11) => setTimeout(resolve11, delay));
|
|
5819
5819
|
},
|
|
5820
5820
|
on: {
|
|
5821
5821
|
connected: () => console.log("Connected to control-plane WebSocket"),
|
|
@@ -7954,6 +7954,16 @@ var DSYMS_ARTIFACT_FILENAME = "dSYMs.zip";
|
|
|
7954
7954
|
function resolveCollectDsyms(settings, action) {
|
|
7955
7955
|
return settings.collectDsyms ?? action === "ARCHIVE";
|
|
7956
7956
|
}
|
|
7957
|
+
var BUILD_ENDPOINT_PATHS = {
|
|
7958
|
+
consoleLogs: "/api/telemetry/console-logs",
|
|
7959
|
+
analyticsEvents: "/api/telemetry/analytics-events",
|
|
7960
|
+
apnsRegistration: "/api/ios/apns-devices",
|
|
7961
|
+
crashReports: "/api/public/crashes",
|
|
7962
|
+
dsyms: "/api/dsyms",
|
|
7963
|
+
dsymUploads: "/api/dsyms/uploads",
|
|
7964
|
+
dsymUpload: "/api/dsyms/uploads/{uploadId}",
|
|
7965
|
+
dsymUploadComplete: "/api/dsyms/uploads/{uploadId}/complete"
|
|
7966
|
+
};
|
|
7957
7967
|
var BUILD_REPORT_KINDS = ["TEST_RESULTS", "CODE_COVERAGE"];
|
|
7958
7968
|
function objectValue7(value, name) {
|
|
7959
7969
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -8218,26 +8228,6 @@ function parseBuildTelemetrySettings(value) {
|
|
|
8218
8228
|
if (value === void 0 || value === null) return void 0;
|
|
8219
8229
|
const input = objectValue7(value, "build job payload.telemetry");
|
|
8220
8230
|
return {
|
|
8221
|
-
localBaseUrl: httpUrl(
|
|
8222
|
-
input.localBaseUrl,
|
|
8223
|
-
"build job payload.telemetry.localBaseUrl"
|
|
8224
|
-
),
|
|
8225
|
-
remoteBaseUrl: httpUrl(
|
|
8226
|
-
input.remoteBaseUrl,
|
|
8227
|
-
"build job payload.telemetry.remoteBaseUrl"
|
|
8228
|
-
),
|
|
8229
|
-
selectedBaseUrl: httpUrl(
|
|
8230
|
-
input.selectedBaseUrl,
|
|
8231
|
-
"build job payload.telemetry.selectedBaseUrl"
|
|
8232
|
-
),
|
|
8233
|
-
consoleLogsUrl: httpUrl(
|
|
8234
|
-
input.consoleLogsUrl,
|
|
8235
|
-
"build job payload.telemetry.consoleLogsUrl"
|
|
8236
|
-
),
|
|
8237
|
-
analyticsEventsUrl: httpUrl(
|
|
8238
|
-
input.analyticsEventsUrl,
|
|
8239
|
-
"build job payload.telemetry.analyticsEventsUrl"
|
|
8240
|
-
),
|
|
8241
8231
|
consoleCollectionEnabled: booleanValue2(
|
|
8242
8232
|
input.consoleCollectionEnabled,
|
|
8243
8233
|
"build job payload.telemetry.consoleCollectionEnabled"
|
|
@@ -8248,6 +8238,40 @@ function parseBuildTelemetrySettings(value) {
|
|
|
8248
8238
|
)
|
|
8249
8239
|
};
|
|
8250
8240
|
}
|
|
8241
|
+
function parseBuildServer(value) {
|
|
8242
|
+
if (value == null) return void 0;
|
|
8243
|
+
const input = objectValue7(value, "build job payload.server");
|
|
8244
|
+
const selectedUrlKind = input.selectedUrlKind;
|
|
8245
|
+
if (selectedUrlKind !== "LOCAL" && selectedUrlKind !== "REMOTE" && selectedUrlKind !== "PROXY")
|
|
8246
|
+
throw new Error("Invalid build server URL kind");
|
|
8247
|
+
const origin2 = (value2, name) => {
|
|
8248
|
+
const result = httpUrl(value2, name);
|
|
8249
|
+
const parsed = new URL(result);
|
|
8250
|
+
if (parsed.pathname !== "/" || parsed.search || parsed.hash || parsed.username || parsed.password)
|
|
8251
|
+
throw new Error(`${name} must be an HTTP(S) origin`);
|
|
8252
|
+
return parsed.origin;
|
|
8253
|
+
};
|
|
8254
|
+
const server = {
|
|
8255
|
+
localBaseUrl: origin2(input.localBaseUrl, "server.localBaseUrl"),
|
|
8256
|
+
remoteBaseUrl: origin2(input.remoteBaseUrl, "server.remoteBaseUrl"),
|
|
8257
|
+
proxyBaseUrl: input.proxyBaseUrl == null ? null : origin2(input.proxyBaseUrl, "server.proxyBaseUrl"),
|
|
8258
|
+
selectedUrlKind,
|
|
8259
|
+
selectedBaseUrl: origin2(input.selectedBaseUrl, "server.selectedBaseUrl")
|
|
8260
|
+
};
|
|
8261
|
+
const selected = selectedUrlKind === "LOCAL" ? server.localBaseUrl : selectedUrlKind === "REMOTE" ? server.remoteBaseUrl : server.proxyBaseUrl;
|
|
8262
|
+
if (selected !== server.selectedBaseUrl)
|
|
8263
|
+
throw new Error("Selected server URL must match its configured base URL");
|
|
8264
|
+
return server;
|
|
8265
|
+
}
|
|
8266
|
+
function parseBuildEndpointPaths(value) {
|
|
8267
|
+
if (value == null) return void 0;
|
|
8268
|
+
const input = objectValue7(value, "build job payload.endpointPaths");
|
|
8269
|
+
for (const [key, expected] of Object.entries(BUILD_ENDPOINT_PATHS)) {
|
|
8270
|
+
if (input[key] !== expected)
|
|
8271
|
+
throw new Error(`Invalid build endpoint path: ${key}`);
|
|
8272
|
+
}
|
|
8273
|
+
return { ...BUILD_ENDPOINT_PATHS };
|
|
8274
|
+
}
|
|
8251
8275
|
function parseBuildSourceDiscoverPayload(value) {
|
|
8252
8276
|
return worktreeIdentity(objectValue7(value, "source discovery payload"));
|
|
8253
8277
|
}
|
|
@@ -8336,6 +8360,8 @@ function parseBuildJobPayload(value) {
|
|
|
8336
8360
|
advancedSettings,
|
|
8337
8361
|
scripts,
|
|
8338
8362
|
telemetry: parseBuildTelemetrySettings(input.telemetry),
|
|
8363
|
+
server: parseBuildServer(input.server),
|
|
8364
|
+
endpointPaths: parseBuildEndpointPaths(input.endpointPaths),
|
|
8339
8365
|
worktreeCoverage: input.worktreeCoverage === void 0 ? false : booleanValue2(
|
|
8340
8366
|
input.worktreeCoverage,
|
|
8341
8367
|
"build job payload.worktreeCoverage"
|
|
@@ -9567,7 +9593,7 @@ function captureCommand(options) {
|
|
|
9567
9593
|
outputTruncated: false
|
|
9568
9594
|
});
|
|
9569
9595
|
}
|
|
9570
|
-
return new Promise((
|
|
9596
|
+
return new Promise((resolve11, reject) => {
|
|
9571
9597
|
const stdoutChunks = [];
|
|
9572
9598
|
const stderrChunks = [];
|
|
9573
9599
|
let stdoutBytes = 0;
|
|
@@ -9663,7 +9689,7 @@ function captureCommand(options) {
|
|
|
9663
9689
|
clearTimeout(timeout);
|
|
9664
9690
|
if (killTimer) clearTimeout(killTimer);
|
|
9665
9691
|
options.signal.removeEventListener("abort", abort);
|
|
9666
|
-
|
|
9692
|
+
resolve11({
|
|
9667
9693
|
exitCode,
|
|
9668
9694
|
signal,
|
|
9669
9695
|
timedOut,
|
|
@@ -9751,11 +9777,11 @@ async function reapOrphanedCommandProcesses(agentId, signal = new AbortControlle
|
|
|
9751
9777
|
console.error(
|
|
9752
9778
|
`Terminating ${signalled.length} command process(es) left by a previous agent run.`
|
|
9753
9779
|
);
|
|
9754
|
-
await new Promise((
|
|
9755
|
-
const timer = setTimeout(
|
|
9780
|
+
await new Promise((resolve11) => {
|
|
9781
|
+
const timer = setTimeout(resolve11, TERMINATE_GRACE_MS);
|
|
9756
9782
|
timer.unref();
|
|
9757
|
-
if (signal.aborted)
|
|
9758
|
-
else signal.addEventListener("abort", () =>
|
|
9783
|
+
if (signal.aborted) resolve11();
|
|
9784
|
+
else signal.addEventListener("abort", () => resolve11(), { once: true });
|
|
9759
9785
|
});
|
|
9760
9786
|
for (const orphan of signalled) signalGroup(orphan.processGroup, "SIGKILL");
|
|
9761
9787
|
return signalled;
|
|
@@ -9811,14 +9837,14 @@ var runCommand = async (rawPayload, _timeoutMs, signal, _onLog, context) => {
|
|
|
9811
9837
|
`Could not append command output; retrying in ${delay}ms:`,
|
|
9812
9838
|
error instanceof Error ? error.message : error
|
|
9813
9839
|
);
|
|
9814
|
-
await new Promise((
|
|
9840
|
+
await new Promise((resolve11) => {
|
|
9815
9841
|
const onAbort = () => {
|
|
9816
9842
|
clearTimeout(retryTimer);
|
|
9817
|
-
|
|
9843
|
+
resolve11();
|
|
9818
9844
|
};
|
|
9819
9845
|
const retryTimer = setTimeout(() => {
|
|
9820
9846
|
signal.removeEventListener("abort", onAbort);
|
|
9821
|
-
|
|
9847
|
+
resolve11();
|
|
9822
9848
|
}, delay);
|
|
9823
9849
|
retryTimer.unref();
|
|
9824
9850
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
@@ -9856,7 +9882,7 @@ var runCommand = async (rawPayload, _timeoutMs, signal, _onLog, context) => {
|
|
|
9856
9882
|
}
|
|
9857
9883
|
};
|
|
9858
9884
|
try {
|
|
9859
|
-
return await new Promise((
|
|
9885
|
+
return await new Promise((resolve11, reject) => {
|
|
9860
9886
|
let cancelled = false;
|
|
9861
9887
|
let settled = false;
|
|
9862
9888
|
const child = spawn2(process.env.SHELL || "/bin/sh", ["-l", scriptPath], {
|
|
@@ -9923,7 +9949,7 @@ var runCommand = async (rawPayload, _timeoutMs, signal, _onLog, context) => {
|
|
|
9923
9949
|
signal.removeEventListener("abort", abort);
|
|
9924
9950
|
flush();
|
|
9925
9951
|
void uploadChain.then(
|
|
9926
|
-
() =>
|
|
9952
|
+
() => resolve11({
|
|
9927
9953
|
exitCode,
|
|
9928
9954
|
signal: closeSignal,
|
|
9929
9955
|
timedOut: false,
|
|
@@ -9964,8 +9990,8 @@ var RepositoryCoordinator = class {
|
|
|
9964
9990
|
async run(key, task) {
|
|
9965
9991
|
const previous = this.tails.get(key) ?? Promise.resolve();
|
|
9966
9992
|
let release2;
|
|
9967
|
-
const current = new Promise((
|
|
9968
|
-
release2 =
|
|
9993
|
+
const current = new Promise((resolve11) => {
|
|
9994
|
+
release2 = resolve11;
|
|
9969
9995
|
});
|
|
9970
9996
|
const tail = previous.then(() => current);
|
|
9971
9997
|
this.tails.set(key, tail);
|
|
@@ -12688,12 +12714,22 @@ if (typeof hookModule.default === "function") {
|
|
|
12688
12714
|
BUILD_PHASE: options.phase,
|
|
12689
12715
|
BUILD_CONTEXT_PATH: options.contextPath,
|
|
12690
12716
|
BUILD_ARTIFACT_DIRECTORY: options.input.artifactDirectory,
|
|
12717
|
+
...options.input.server ? {
|
|
12718
|
+
SERVER_LOCAL_BASE_URL: options.input.server.localBaseUrl,
|
|
12719
|
+
SERVER_REMOTE_BASE_URL: options.input.server.remoteBaseUrl,
|
|
12720
|
+
SERVER_PROXY_BASE_URL: options.input.server.proxyBaseUrl ?? "",
|
|
12721
|
+
SERVER_BASE_URL: options.input.server.selectedBaseUrl,
|
|
12722
|
+
SERVER_URL_KIND: options.input.server.selectedUrlKind
|
|
12723
|
+
} : {},
|
|
12724
|
+
...Object.fromEntries(
|
|
12725
|
+
Object.entries(options.input.endpointPaths ?? {}).map(
|
|
12726
|
+
([key, value]) => [
|
|
12727
|
+
`${key.replace(/[A-Z]/g, (letter) => `_${letter}`).toUpperCase()}_PATH`,
|
|
12728
|
+
value
|
|
12729
|
+
]
|
|
12730
|
+
)
|
|
12731
|
+
),
|
|
12691
12732
|
...options.input.telemetry ? {
|
|
12692
|
-
TELEMETRY_LOCAL_BASE_URL: options.input.telemetry.localBaseUrl,
|
|
12693
|
-
TELEMETRY_REMOTE_BASE_URL: options.input.telemetry.remoteBaseUrl,
|
|
12694
|
-
TELEMETRY_BASE_URL: options.input.telemetry.selectedBaseUrl,
|
|
12695
|
-
CONSOLE_LOGS_URL: options.input.telemetry.consoleLogsUrl,
|
|
12696
|
-
ANALYTICS_EVENTS_URL: options.input.telemetry.analyticsEventsUrl,
|
|
12697
12733
|
CONSOLE_LOG_COLLECTION_ENABLED: String(
|
|
12698
12734
|
options.input.telemetry.consoleCollectionEnabled
|
|
12699
12735
|
),
|
|
@@ -12879,14 +12915,14 @@ function normalizeTestResults(value) {
|
|
|
12879
12915
|
suite: null
|
|
12880
12916
|
});
|
|
12881
12917
|
}
|
|
12882
|
-
const
|
|
12918
|
+
const count3 = (result) => tests.filter((test) => test.result === result).length;
|
|
12883
12919
|
return {
|
|
12884
12920
|
summary: {
|
|
12885
12921
|
total: tests.length,
|
|
12886
|
-
passed:
|
|
12887
|
-
failed:
|
|
12888
|
-
skipped:
|
|
12889
|
-
expectedFailures:
|
|
12922
|
+
passed: count3("Passed"),
|
|
12923
|
+
failed: count3("Failed"),
|
|
12924
|
+
skipped: count3("Skipped"),
|
|
12925
|
+
expectedFailures: count3("Expected Failure"),
|
|
12890
12926
|
unknown: tests.filter(
|
|
12891
12927
|
(test) => !["Passed", "Failed", "Skipped", "Expected Failure"].includes(
|
|
12892
12928
|
String(test.result)
|
|
@@ -13018,9 +13054,9 @@ function changedLinesFromPatch(value) {
|
|
|
13018
13054
|
const match = /\+(\d+)(?:,(\d+))?/.exec(line);
|
|
13019
13055
|
if (!match) continue;
|
|
13020
13056
|
const start = Number(match[1]);
|
|
13021
|
-
const
|
|
13057
|
+
const count3 = match[2] === void 0 ? 1 : Number(match[2]);
|
|
13022
13058
|
const lines = result.get(path);
|
|
13023
|
-
for (let number = start; number < start +
|
|
13059
|
+
for (let number = start; number < start + count3; number += 1) {
|
|
13024
13060
|
lines.add(number);
|
|
13025
13061
|
}
|
|
13026
13062
|
}
|
|
@@ -13516,7 +13552,9 @@ var runIosBuild = async (payload, timeoutMs, signal, onLog, context) => {
|
|
|
13516
13552
|
source: input.source,
|
|
13517
13553
|
scheme: input.scheme,
|
|
13518
13554
|
configuration: input.configuration,
|
|
13519
|
-
telemetry: input.telemetry ?? null
|
|
13555
|
+
telemetry: input.telemetry ?? null,
|
|
13556
|
+
server: input.server ?? null,
|
|
13557
|
+
endpointPaths: input.endpointPaths ?? null
|
|
13520
13558
|
};
|
|
13521
13559
|
let buildResult = null;
|
|
13522
13560
|
let preflightResult = null;
|
|
@@ -15396,7 +15434,7 @@ function prependPathDirectory(directory, env = process.env) {
|
|
|
15396
15434
|
// src/process-runner.ts
|
|
15397
15435
|
import { spawn as spawn5 } from "node:child_process";
|
|
15398
15436
|
async function runProcess(options) {
|
|
15399
|
-
return new Promise((
|
|
15437
|
+
return new Promise((resolve11, reject) => {
|
|
15400
15438
|
let sequence = 0;
|
|
15401
15439
|
let timedOut = false;
|
|
15402
15440
|
let cancelled = false;
|
|
@@ -15491,7 +15529,7 @@ async function runProcess(options) {
|
|
|
15491
15529
|
clearTimeout(timeout);
|
|
15492
15530
|
options.signal.removeEventListener("abort", abort);
|
|
15493
15531
|
void logChain.then(
|
|
15494
|
-
() =>
|
|
15532
|
+
() => resolve11({ exitCode, signal, timedOut, cancelled })
|
|
15495
15533
|
);
|
|
15496
15534
|
});
|
|
15497
15535
|
});
|
|
@@ -16409,8 +16447,8 @@ async function fileExists(path) {
|
|
|
16409
16447
|
return false;
|
|
16410
16448
|
}
|
|
16411
16449
|
}
|
|
16412
|
-
async function findClaudeSessionFile(nativeId, home) {
|
|
16413
|
-
const projectsDir = join12(
|
|
16450
|
+
async function findClaudeSessionFile(nativeId, home, claudeHome = join12(home, ".claude")) {
|
|
16451
|
+
const projectsDir = join12(claudeHome, "projects");
|
|
16414
16452
|
let entries;
|
|
16415
16453
|
try {
|
|
16416
16454
|
entries = await readdir7(projectsDir, { withFileTypes: true });
|
|
@@ -16425,8 +16463,8 @@ async function findClaudeSessionFile(nativeId, home) {
|
|
|
16425
16463
|
}
|
|
16426
16464
|
return null;
|
|
16427
16465
|
}
|
|
16428
|
-
async function findCodexSessionFile(nativeId, home) {
|
|
16429
|
-
const sessionsDir = join12(
|
|
16466
|
+
async function findCodexSessionFile(nativeId, home, codexHome = join12(home, ".codex")) {
|
|
16467
|
+
const sessionsDir = join12(codexHome, "sessions");
|
|
16430
16468
|
const suffix = `-${nativeId}.jsonl`;
|
|
16431
16469
|
const walk = async (dir) => {
|
|
16432
16470
|
let entries;
|
|
@@ -16446,10 +16484,14 @@ async function findCodexSessionFile(nativeId, home) {
|
|
|
16446
16484
|
}
|
|
16447
16485
|
return null;
|
|
16448
16486
|
};
|
|
16449
|
-
return walk(sessionsDir);
|
|
16487
|
+
return await walk(sessionsDir) ?? walk(join12(codexHome, "archived_sessions"));
|
|
16450
16488
|
}
|
|
16451
16489
|
async function locateSessionFile(payload, home) {
|
|
16452
|
-
return payload.provider === "CLAUDE" ? findClaudeSessionFile(
|
|
16490
|
+
return payload.provider === "CLAUDE" ? findClaudeSessionFile(
|
|
16491
|
+
payload.nativeId,
|
|
16492
|
+
home,
|
|
16493
|
+
process.env.CLAUDE_CONFIG_DIR
|
|
16494
|
+
) : findCodexSessionFile(payload.nativeId, home, process.env.CODEX_HOME);
|
|
16453
16495
|
}
|
|
16454
16496
|
var readRunSession = async (payload) => {
|
|
16455
16497
|
const input = parseRunSessionReadPayload(payload);
|
|
@@ -16514,7 +16556,7 @@ async function optionalGit(cwd, args) {
|
|
|
16514
16556
|
}
|
|
16515
16557
|
function cappedGit(cwd, args, limit) {
|
|
16516
16558
|
const budget = limit - TRUNCATION_RESERVE;
|
|
16517
|
-
return new Promise((
|
|
16559
|
+
return new Promise((resolve11, reject) => {
|
|
16518
16560
|
const child = spawn6("git", args, {
|
|
16519
16561
|
cwd,
|
|
16520
16562
|
env: {
|
|
@@ -16564,7 +16606,7 @@ function cappedGit(cwd, args, limit) {
|
|
|
16564
16606
|
return;
|
|
16565
16607
|
}
|
|
16566
16608
|
const output = Buffer.concat(chunks).toString("utf8");
|
|
16567
|
-
|
|
16609
|
+
resolve11(
|
|
16568
16610
|
truncated ? `${output.trimEnd()}
|
|
16569
16611
|
|
|
16570
16612
|
[Truncated after ${budget} bytes]` : output.trim()
|
|
@@ -20107,11 +20149,11 @@ var mutationQueues = /* @__PURE__ */ new Map();
|
|
|
20107
20149
|
function objectValue15(value) {
|
|
20108
20150
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
20109
20151
|
}
|
|
20110
|
-
function resolveTailscaleExecutable(platform2 = process.platform,
|
|
20152
|
+
function resolveTailscaleExecutable(platform2 = process.platform, resolve11 = findExecutable, isExecutable2 = (path) => {
|
|
20111
20153
|
accessSync2(path, constants2.X_OK);
|
|
20112
20154
|
return true;
|
|
20113
20155
|
}) {
|
|
20114
|
-
const resolved =
|
|
20156
|
+
const resolved = resolve11("tailscale", {
|
|
20115
20157
|
overrideVariable: "CONTROL_AGENT_TAILSCALE_EXECUTABLE"
|
|
20116
20158
|
});
|
|
20117
20159
|
if (resolved) return resolved;
|
|
@@ -20320,8 +20362,8 @@ function tailscaleUpsertCommandSequence(route, previousRoute) {
|
|
|
20320
20362
|
async function serialized(agentId, work) {
|
|
20321
20363
|
const previous = mutationQueues.get(agentId) ?? Promise.resolve();
|
|
20322
20364
|
let release2;
|
|
20323
|
-
const current = new Promise((
|
|
20324
|
-
release2 =
|
|
20365
|
+
const current = new Promise((resolve11) => {
|
|
20366
|
+
release2 = resolve11;
|
|
20325
20367
|
});
|
|
20326
20368
|
const tail = previous.then(() => current);
|
|
20327
20369
|
mutationQueues.set(agentId, tail);
|
|
@@ -20581,7 +20623,7 @@ var JobExecutor = class {
|
|
|
20581
20623
|
);
|
|
20582
20624
|
if (this.stopping) return;
|
|
20583
20625
|
const delay = Math.min(3e4, 1e3 * 2 ** Math.min(retry++, 5));
|
|
20584
|
-
await new Promise((
|
|
20626
|
+
await new Promise((resolve11) => setTimeout(resolve11, delay));
|
|
20585
20627
|
}
|
|
20586
20628
|
}
|
|
20587
20629
|
}
|
|
@@ -20870,6 +20912,254 @@ var RunJournal = class {
|
|
|
20870
20912
|
|
|
20871
20913
|
// src/runs/claude-adapter.ts
|
|
20872
20914
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
20915
|
+
import { homedir as homedir11 } from "node:os";
|
|
20916
|
+
|
|
20917
|
+
// src/runs/claude-import.ts
|
|
20918
|
+
import { createReadStream as createReadStream4 } from "node:fs";
|
|
20919
|
+
import { createInterface } from "node:readline";
|
|
20920
|
+
|
|
20921
|
+
// src/runs/provider.ts
|
|
20922
|
+
function asRecord(value) {
|
|
20923
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
20924
|
+
}
|
|
20925
|
+
function firstString(value) {
|
|
20926
|
+
const keys = [
|
|
20927
|
+
"text",
|
|
20928
|
+
"result",
|
|
20929
|
+
"message",
|
|
20930
|
+
"summary",
|
|
20931
|
+
"content",
|
|
20932
|
+
"output",
|
|
20933
|
+
"items",
|
|
20934
|
+
"parts"
|
|
20935
|
+
];
|
|
20936
|
+
const pending = [value];
|
|
20937
|
+
const visited = /* @__PURE__ */ new WeakSet();
|
|
20938
|
+
while (pending.length) {
|
|
20939
|
+
const candidate = pending.pop();
|
|
20940
|
+
if (typeof candidate === "string" && candidate.trim()) return candidate;
|
|
20941
|
+
if (!candidate || typeof candidate !== "object") continue;
|
|
20942
|
+
if (visited.has(candidate)) continue;
|
|
20943
|
+
visited.add(candidate);
|
|
20944
|
+
if (Array.isArray(candidate)) {
|
|
20945
|
+
for (let index = candidate.length - 1; index >= 0; index -= 1) {
|
|
20946
|
+
pending.push(candidate[index]);
|
|
20947
|
+
}
|
|
20948
|
+
continue;
|
|
20949
|
+
}
|
|
20950
|
+
const record = asRecord(candidate);
|
|
20951
|
+
for (let index = keys.length - 1; index >= 0; index -= 1) {
|
|
20952
|
+
pending.push(record[keys[index]]);
|
|
20953
|
+
}
|
|
20954
|
+
}
|
|
20955
|
+
return void 0;
|
|
20956
|
+
}
|
|
20957
|
+
function answerArrays(value) {
|
|
20958
|
+
if (Array.isArray(value)) {
|
|
20959
|
+
return value.map(
|
|
20960
|
+
(entry) => Array.isArray(entry) ? entry.map(String) : typeof entry === "object" && entry ? Array.isArray(entry.answers) ? entry.answers.map(
|
|
20961
|
+
String
|
|
20962
|
+
) : [String(entry.answer ?? "")] : [String(entry)]
|
|
20963
|
+
);
|
|
20964
|
+
}
|
|
20965
|
+
const record = asRecord(value);
|
|
20966
|
+
return Object.values(record).map(
|
|
20967
|
+
(entry) => Array.isArray(asRecord(entry).answers) ? asRecord(entry).answers.map(String) : Array.isArray(entry) ? entry.map(String) : [String(entry ?? "")]
|
|
20968
|
+
);
|
|
20969
|
+
}
|
|
20970
|
+
|
|
20971
|
+
// src/runs/claude-import.ts
|
|
20972
|
+
var tokenFields = [
|
|
20973
|
+
"inputTokens",
|
|
20974
|
+
"outputTokens",
|
|
20975
|
+
"reasoningTokens",
|
|
20976
|
+
"cacheReadTokens",
|
|
20977
|
+
"cacheWriteTokens"
|
|
20978
|
+
];
|
|
20979
|
+
function amount(value) {
|
|
20980
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
20981
|
+
}
|
|
20982
|
+
function count(value) {
|
|
20983
|
+
return Math.floor(amount(value) ?? 0);
|
|
20984
|
+
}
|
|
20985
|
+
function textBlocks(content) {
|
|
20986
|
+
if (typeof content === "string") return content.trim();
|
|
20987
|
+
return Array.isArray(content) ? content.map(asRecord).filter(
|
|
20988
|
+
(block) => block.type === "text" && typeof block.text === "string"
|
|
20989
|
+
).map((block) => String(block.text).trim()).filter(Boolean).join("\n\n") : "";
|
|
20990
|
+
}
|
|
20991
|
+
function timestamp(value) {
|
|
20992
|
+
const date = typeof value === "string" || typeof value === "number" ? new Date(value) : void 0;
|
|
20993
|
+
return date && Number.isFinite(date.getTime()) ? date.toISOString() : void 0;
|
|
20994
|
+
}
|
|
20995
|
+
function claudeTranscriptMetadata(values) {
|
|
20996
|
+
const records = values.map(asRecord);
|
|
20997
|
+
const requests = /* @__PURE__ */ new Map();
|
|
20998
|
+
let model2;
|
|
20999
|
+
let effort;
|
|
21000
|
+
let lastAssistant = -1;
|
|
21001
|
+
let costIndex = -1;
|
|
21002
|
+
let costState;
|
|
21003
|
+
for (const [index, record] of records.entries()) {
|
|
21004
|
+
if (record.isSidechain === true) continue;
|
|
21005
|
+
if (record.type === "cost-state" && Object.keys(asRecord(record.modelUsage)).length) {
|
|
21006
|
+
costIndex = index;
|
|
21007
|
+
costState = record;
|
|
21008
|
+
}
|
|
21009
|
+
const message = asRecord(record.message);
|
|
21010
|
+
if (record.type !== "assistant" || typeof message.model !== "string" || message.model.startsWith("<"))
|
|
21011
|
+
continue;
|
|
21012
|
+
model2 = message.model;
|
|
21013
|
+
lastAssistant = index;
|
|
21014
|
+
const recordedEffort = record.perTurnEffort ?? record.effort;
|
|
21015
|
+
if (typeof recordedEffort === "string" || typeof recordedEffort === "number")
|
|
21016
|
+
effort = String(recordedEffort);
|
|
21017
|
+
if (!message.usage) continue;
|
|
21018
|
+
const usage2 = asRecord(message.usage);
|
|
21019
|
+
const key = `${model2}:${String(message.id ?? record.uuid ?? index)}`;
|
|
21020
|
+
const previous = requests.get(key);
|
|
21021
|
+
const current = {
|
|
21022
|
+
model: model2,
|
|
21023
|
+
inputTokens: count(usage2.input_tokens),
|
|
21024
|
+
outputTokens: count(usage2.output_tokens),
|
|
21025
|
+
reasoningTokens: count(
|
|
21026
|
+
asRecord(usage2.output_tokens_details).thinking_tokens
|
|
21027
|
+
),
|
|
21028
|
+
cacheReadTokens: count(usage2.cache_read_input_tokens),
|
|
21029
|
+
cacheWriteTokens: count(usage2.cache_creation_input_tokens),
|
|
21030
|
+
pricingSource: "claude-transcript"
|
|
21031
|
+
};
|
|
21032
|
+
if (previous)
|
|
21033
|
+
for (const field of tokenFields)
|
|
21034
|
+
current[field] = Math.max(previous[field] ?? 0, current[field] ?? 0);
|
|
21035
|
+
requests.set(key, current);
|
|
21036
|
+
}
|
|
21037
|
+
if (costState && costIndex >= lastAssistant) {
|
|
21038
|
+
const usage2 = Object.entries(asRecord(costState.modelUsage)).map(
|
|
21039
|
+
([model3, value]) => {
|
|
21040
|
+
const item = asRecord(value);
|
|
21041
|
+
return {
|
|
21042
|
+
model: model3,
|
|
21043
|
+
inputTokens: count(item.inputTokens),
|
|
21044
|
+
outputTokens: count(item.outputTokens),
|
|
21045
|
+
reasoningTokens: count(item.thinkingTokens),
|
|
21046
|
+
cacheReadTokens: count(item.cacheReadInputTokens),
|
|
21047
|
+
cacheWriteTokens: count(item.cacheCreationInputTokens),
|
|
21048
|
+
...costState.hasUnknownModelCost !== true && amount(item.costUSD) !== void 0 ? { estimatedCost: amount(item.costUSD) } : {},
|
|
21049
|
+
pricingSource: "claude-transcript"
|
|
21050
|
+
};
|
|
21051
|
+
}
|
|
21052
|
+
);
|
|
21053
|
+
return {
|
|
21054
|
+
model: model2,
|
|
21055
|
+
effort,
|
|
21056
|
+
usage: usage2,
|
|
21057
|
+
...costState.hasUnknownModelCost !== true && amount(costState.totalCostUSD) !== void 0 ? {
|
|
21058
|
+
estimatedCost: amount(costState.totalCostUSD),
|
|
21059
|
+
pricingSource: "claude-transcript"
|
|
21060
|
+
} : {}
|
|
21061
|
+
};
|
|
21062
|
+
}
|
|
21063
|
+
const totals = /* @__PURE__ */ new Map();
|
|
21064
|
+
for (const request of requests.values()) {
|
|
21065
|
+
const total = totals.get(request.model) ?? {
|
|
21066
|
+
model: request.model,
|
|
21067
|
+
pricingSource: "claude-transcript"
|
|
21068
|
+
};
|
|
21069
|
+
for (const field of tokenFields)
|
|
21070
|
+
total[field] = (total[field] ?? 0) + (request[field] ?? 0);
|
|
21071
|
+
totals.set(request.model, total);
|
|
21072
|
+
}
|
|
21073
|
+
return {
|
|
21074
|
+
model: model2,
|
|
21075
|
+
effort,
|
|
21076
|
+
...totals.size ? { usage: [...totals.values()] } : {}
|
|
21077
|
+
};
|
|
21078
|
+
}
|
|
21079
|
+
async function readClaudeTranscript(path) {
|
|
21080
|
+
const stream = createReadStream4(path, { encoding: "utf8" });
|
|
21081
|
+
const lines = createInterface({ input: stream, crlfDelay: Infinity });
|
|
21082
|
+
const records = [];
|
|
21083
|
+
try {
|
|
21084
|
+
for await (const line of lines) {
|
|
21085
|
+
try {
|
|
21086
|
+
const record = JSON.parse(line);
|
|
21087
|
+
if (["user", "assistant", "system", "result", "cost-state"].includes(
|
|
21088
|
+
record.type
|
|
21089
|
+
))
|
|
21090
|
+
records.push(record);
|
|
21091
|
+
} catch {
|
|
21092
|
+
}
|
|
21093
|
+
}
|
|
21094
|
+
return records;
|
|
21095
|
+
} finally {
|
|
21096
|
+
lines.close();
|
|
21097
|
+
stream.destroy();
|
|
21098
|
+
}
|
|
21099
|
+
}
|
|
21100
|
+
function claudeImportedHistory(messageValues, transcriptValues = []) {
|
|
21101
|
+
const metadata = /* @__PURE__ */ new Map();
|
|
21102
|
+
for (const value of transcriptValues) {
|
|
21103
|
+
const record = asRecord(value);
|
|
21104
|
+
if (typeof record.uuid === "string") metadata.set(record.uuid, record);
|
|
21105
|
+
}
|
|
21106
|
+
const messages = /* @__PURE__ */ new Map();
|
|
21107
|
+
for (const [index, value] of messageValues.entries()) {
|
|
21108
|
+
const message = asRecord(value);
|
|
21109
|
+
const id2 = String(message.uuid ?? index);
|
|
21110
|
+
messages.set(id2, { ...message, ...metadata.get(id2) });
|
|
21111
|
+
}
|
|
21112
|
+
const events = [];
|
|
21113
|
+
const replies = /* @__PURE__ */ new Map();
|
|
21114
|
+
let prompt;
|
|
21115
|
+
let finalReplyId;
|
|
21116
|
+
let kind = "SESSION";
|
|
21117
|
+
for (const [id2, record] of messages) {
|
|
21118
|
+
const message = asRecord(record.message);
|
|
21119
|
+
if (record.permissionMode === "plan") kind = "PLAN";
|
|
21120
|
+
const content = typeof message.content === "string" ? [{ type: "text", text: message.content }] : Array.isArray(message.content) ? message.content : [];
|
|
21121
|
+
if (record.type === "user" && record.isMeta !== true && !prompt)
|
|
21122
|
+
prompt = textBlocks(content) || void 0;
|
|
21123
|
+
if (record.type === "assistant") {
|
|
21124
|
+
const reply = textBlocks(content);
|
|
21125
|
+
if (reply) {
|
|
21126
|
+
const replyId = String(message.id ?? id2);
|
|
21127
|
+
const parts = replies.get(replyId) ?? /* @__PURE__ */ new Map();
|
|
21128
|
+
parts.set(id2, reply);
|
|
21129
|
+
replies.set(replyId, parts);
|
|
21130
|
+
finalReplyId = replyId;
|
|
21131
|
+
}
|
|
21132
|
+
}
|
|
21133
|
+
const blocks = content.length ? content.map(asRecord) : [void 0];
|
|
21134
|
+
for (const [index, block] of blocks.entries()) {
|
|
21135
|
+
const detail = block?.type === "text" && typeof block.text === "string" ? block.text : void 0;
|
|
21136
|
+
const summary = detail || (block?.type === "tool_use" ? String(block.name ?? "Tool call") : block?.type === "tool_result" ? textBlocks(block.content) || "Tool result" : String(
|
|
21137
|
+
block?.type ?? record.subtype ?? record.type ?? "Claude message"
|
|
21138
|
+
));
|
|
21139
|
+
events.push({
|
|
21140
|
+
id: `${id2}:${String(block?.id ?? index)}`,
|
|
21141
|
+
sequence: events.length,
|
|
21142
|
+
type: String(record.type ?? "message").toUpperCase(),
|
|
21143
|
+
summary: (summary.trim() || "Claude message").slice(0, 2e3),
|
|
21144
|
+
detailMarkdown: detail,
|
|
21145
|
+
createdAt: timestamp(record.timestamp),
|
|
21146
|
+
raw: {
|
|
21147
|
+
...record,
|
|
21148
|
+
...block ? { message: { ...message, content: [block] } } : {}
|
|
21149
|
+
}
|
|
21150
|
+
});
|
|
21151
|
+
}
|
|
21152
|
+
}
|
|
21153
|
+
return {
|
|
21154
|
+
...claudeTranscriptMetadata(
|
|
21155
|
+
transcriptValues.length ? transcriptValues : [...messages.values()]
|
|
21156
|
+
),
|
|
21157
|
+
kind,
|
|
21158
|
+
prompt,
|
|
21159
|
+
events,
|
|
21160
|
+
finalOutput: finalReplyId ? [...replies.get(finalReplyId).values()].join("\n\n") : void 0
|
|
21161
|
+
};
|
|
21162
|
+
}
|
|
20873
21163
|
|
|
20874
21164
|
// ../../node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
|
|
20875
21165
|
import { createRequire as nV } from "node:module";
|
|
@@ -46806,56 +47096,6 @@ async function Lze(e, t, n) {
|
|
|
46806
47096
|
return wD(o, { limit: n.limit, offset: n.offset, includeSystemMessages: n.includeSystemMessages });
|
|
46807
47097
|
}
|
|
46808
47098
|
|
|
46809
|
-
// src/runs/provider.ts
|
|
46810
|
-
function asRecord(value) {
|
|
46811
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
46812
|
-
}
|
|
46813
|
-
function firstString(value) {
|
|
46814
|
-
const keys = [
|
|
46815
|
-
"text",
|
|
46816
|
-
"result",
|
|
46817
|
-
"message",
|
|
46818
|
-
"summary",
|
|
46819
|
-
"content",
|
|
46820
|
-
"output",
|
|
46821
|
-
"items",
|
|
46822
|
-
"parts"
|
|
46823
|
-
];
|
|
46824
|
-
const pending = [value];
|
|
46825
|
-
const visited = /* @__PURE__ */ new WeakSet();
|
|
46826
|
-
while (pending.length) {
|
|
46827
|
-
const candidate = pending.pop();
|
|
46828
|
-
if (typeof candidate === "string" && candidate.trim()) return candidate;
|
|
46829
|
-
if (!candidate || typeof candidate !== "object") continue;
|
|
46830
|
-
if (visited.has(candidate)) continue;
|
|
46831
|
-
visited.add(candidate);
|
|
46832
|
-
if (Array.isArray(candidate)) {
|
|
46833
|
-
for (let index = candidate.length - 1; index >= 0; index -= 1) {
|
|
46834
|
-
pending.push(candidate[index]);
|
|
46835
|
-
}
|
|
46836
|
-
continue;
|
|
46837
|
-
}
|
|
46838
|
-
const record = asRecord(candidate);
|
|
46839
|
-
for (let index = keys.length - 1; index >= 0; index -= 1) {
|
|
46840
|
-
pending.push(record[keys[index]]);
|
|
46841
|
-
}
|
|
46842
|
-
}
|
|
46843
|
-
return void 0;
|
|
46844
|
-
}
|
|
46845
|
-
function answerArrays(value) {
|
|
46846
|
-
if (Array.isArray(value)) {
|
|
46847
|
-
return value.map(
|
|
46848
|
-
(entry) => Array.isArray(entry) ? entry.map(String) : typeof entry === "object" && entry ? Array.isArray(entry.answers) ? entry.answers.map(
|
|
46849
|
-
String
|
|
46850
|
-
) : [String(entry.answer ?? "")] : [String(entry)]
|
|
46851
|
-
);
|
|
46852
|
-
}
|
|
46853
|
-
const record = asRecord(value);
|
|
46854
|
-
return Object.values(record).map(
|
|
46855
|
-
(entry) => Array.isArray(asRecord(entry).answers) ? asRecord(entry).answers.map(String) : Array.isArray(entry) ? entry.map(String) : [String(entry ?? "")]
|
|
46856
|
-
);
|
|
46857
|
-
}
|
|
46858
|
-
|
|
46859
47099
|
// src/runs/claude-adapter.ts
|
|
46860
47100
|
function findClaudeCodeExecutable(options = {}) {
|
|
46861
47101
|
return findExecutable("claude", {
|
|
@@ -46895,7 +47135,7 @@ var MessageQueue = class {
|
|
|
46895
47135
|
if (value) return Promise.resolve({ value, done: false });
|
|
46896
47136
|
if (this.closed)
|
|
46897
47137
|
return Promise.resolve({ value: void 0, done: true });
|
|
46898
|
-
return new Promise((
|
|
47138
|
+
return new Promise((resolve11) => this.waiters.push(resolve11));
|
|
46899
47139
|
}
|
|
46900
47140
|
};
|
|
46901
47141
|
}
|
|
@@ -47065,8 +47305,8 @@ var ClaudeAdapter = class {
|
|
|
47065
47305
|
const requestId = options.toolUseID || randomUUID6();
|
|
47066
47306
|
const questions = questionsFromInput(toolInput);
|
|
47067
47307
|
await callbacks.onQuestion(requestId, questions);
|
|
47068
|
-
const answers = await new Promise((
|
|
47069
|
-
pendingQuestions.set(requestId, { input: toolInput, resolve:
|
|
47308
|
+
const answers = await new Promise((resolve11) => {
|
|
47309
|
+
pendingQuestions.set(requestId, { input: toolInput, resolve: resolve11 });
|
|
47070
47310
|
});
|
|
47071
47311
|
return {
|
|
47072
47312
|
behavior: "allow",
|
|
@@ -47160,39 +47400,51 @@ var ClaudeAdapter = class {
|
|
|
47160
47400
|
async discover(worktrees) {
|
|
47161
47401
|
const results = [];
|
|
47162
47402
|
for (const worktree of worktrees) {
|
|
47163
|
-
const sessions = await AEt({
|
|
47403
|
+
const sessions = await AEt({
|
|
47404
|
+
dir: worktree.folder,
|
|
47405
|
+
includeWorktrees: false
|
|
47406
|
+
});
|
|
47164
47407
|
for (const session of sessions) {
|
|
47165
|
-
const lastModifiedKey =
|
|
47408
|
+
const lastModifiedKey = `${session.lastModified ?? ""}:${session.fileSize ?? ""}`;
|
|
47166
47409
|
const cached = this.hydrationCache.get(session.sessionId);
|
|
47167
|
-
let
|
|
47168
|
-
let finalOutput;
|
|
47410
|
+
let history = {};
|
|
47169
47411
|
if (cached && cached.lastModified === lastModifiedKey) {
|
|
47170
|
-
|
|
47171
|
-
finalOutput = cached.finalOutput;
|
|
47412
|
+
history = cached.history;
|
|
47172
47413
|
} else {
|
|
47414
|
+
let transcript = [];
|
|
47173
47415
|
try {
|
|
47174
|
-
const
|
|
47416
|
+
const path = await findClaudeSessionFile(
|
|
47417
|
+
session.sessionId,
|
|
47418
|
+
homedir11(),
|
|
47419
|
+
process.env.CLAUDE_CONFIG_DIR
|
|
47420
|
+
);
|
|
47421
|
+
if (path) transcript = await readClaudeTranscript(path);
|
|
47422
|
+
history = claudeTranscriptMetadata(transcript);
|
|
47423
|
+
} catch {
|
|
47424
|
+
}
|
|
47425
|
+
try {
|
|
47426
|
+
const messages = await xEt(session.sessionId, {
|
|
47175
47427
|
dir: worktree.folder,
|
|
47176
|
-
|
|
47177
|
-
});
|
|
47178
|
-
const serialized2 = JSON.stringify(history);
|
|
47179
|
-
if (serialized2.includes('"permissionMode":"plan"')) kind = "PLAN";
|
|
47180
|
-
finalOutput = firstString([...history].reverse());
|
|
47181
|
-
this.hydrationCache.set(session.sessionId, {
|
|
47182
|
-
lastModified: lastModifiedKey,
|
|
47183
|
-
kind,
|
|
47184
|
-
finalOutput
|
|
47428
|
+
includeSystemMessages: true
|
|
47185
47429
|
});
|
|
47430
|
+
if (messages.length) {
|
|
47431
|
+
history = claudeImportedHistory(messages, transcript);
|
|
47432
|
+
if (history.model && history.usage) {
|
|
47433
|
+
this.hydrationCache.set(session.sessionId, {
|
|
47434
|
+
lastModified: lastModifiedKey,
|
|
47435
|
+
history
|
|
47436
|
+
});
|
|
47437
|
+
}
|
|
47438
|
+
}
|
|
47186
47439
|
} catch {
|
|
47187
47440
|
}
|
|
47188
47441
|
}
|
|
47189
47442
|
results.push({
|
|
47190
47443
|
nativeId: session.sessionId,
|
|
47191
47444
|
worktreeId: worktree.id,
|
|
47192
|
-
|
|
47445
|
+
...history,
|
|
47193
47446
|
status: "COMPLETED",
|
|
47194
|
-
prompt: session.firstPrompt || session.summary,
|
|
47195
|
-
finalOutput: finalOutput || session.summary,
|
|
47447
|
+
prompt: history.prompt || session.firstPrompt || session.summary,
|
|
47196
47448
|
branch: session.gitBranch || worktree.branch || void 0,
|
|
47197
47449
|
createdAt: session.createdAt ? new Date(session.createdAt).toISOString() : void 0,
|
|
47198
47450
|
updatedAt: new Date(session.lastModified).toISOString(),
|
|
@@ -47210,10 +47462,192 @@ import {
|
|
|
47210
47462
|
spawn as spawn8
|
|
47211
47463
|
} from "node:child_process";
|
|
47212
47464
|
import { mkdtemp as mkdtemp8, rm as rm14, writeFile as writeFile10 } from "node:fs/promises";
|
|
47213
|
-
import { tmpdir as tmpdir8 } from "node:os";
|
|
47465
|
+
import { homedir as homedir12, tmpdir as tmpdir8 } from "node:os";
|
|
47214
47466
|
import { join as join19 } from "node:path";
|
|
47215
|
-
import { createInterface } from "node:readline";
|
|
47467
|
+
import { createInterface as createInterface3 } from "node:readline";
|
|
47216
47468
|
import { promisify as promisify3 } from "node:util";
|
|
47469
|
+
|
|
47470
|
+
// src/runs/codex-import.ts
|
|
47471
|
+
import { createReadStream as createReadStream5 } from "node:fs";
|
|
47472
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
47473
|
+
var tokenFields2 = [
|
|
47474
|
+
"inputTokens",
|
|
47475
|
+
"outputTokens",
|
|
47476
|
+
"reasoningTokens",
|
|
47477
|
+
"cacheReadTokens",
|
|
47478
|
+
"cacheWriteTokens"
|
|
47479
|
+
];
|
|
47480
|
+
function count2(value) {
|
|
47481
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.floor(value) : 0;
|
|
47482
|
+
}
|
|
47483
|
+
function tokens(value, model2) {
|
|
47484
|
+
const raw = asRecord(value);
|
|
47485
|
+
const cached = count2(raw.cached_input_tokens);
|
|
47486
|
+
return {
|
|
47487
|
+
model: model2,
|
|
47488
|
+
inputTokens: Math.max(0, count2(raw.input_tokens) - cached),
|
|
47489
|
+
cacheReadTokens: cached,
|
|
47490
|
+
cacheWriteTokens: count2(raw.cache_write_input_tokens),
|
|
47491
|
+
outputTokens: count2(raw.output_tokens),
|
|
47492
|
+
reasoningTokens: count2(raw.reasoning_output_tokens),
|
|
47493
|
+
pricingSource: "codex-transcript"
|
|
47494
|
+
};
|
|
47495
|
+
}
|
|
47496
|
+
function codexTranscriptMetadata(records) {
|
|
47497
|
+
let model2;
|
|
47498
|
+
let effort;
|
|
47499
|
+
const turnModels = /* @__PURE__ */ new Map();
|
|
47500
|
+
const responseTurns = /* @__PURE__ */ new Set();
|
|
47501
|
+
let contextTurn = "unknown-turn";
|
|
47502
|
+
for (const record of records) {
|
|
47503
|
+
const context = asRecord(record.payload);
|
|
47504
|
+
if (record.type === "turn_context") {
|
|
47505
|
+
contextTurn = String(context.turn_id ?? "unknown-turn");
|
|
47506
|
+
if (typeof context.model === "string") model2 = context.model;
|
|
47507
|
+
if (typeof context.effort === "string") effort = context.effort;
|
|
47508
|
+
if (model2) turnModels.set(contextTurn, model2);
|
|
47509
|
+
}
|
|
47510
|
+
if (record.type === "token_usage_record" && context.usage)
|
|
47511
|
+
responseTurns.add(String(context.turn_id ?? contextTurn));
|
|
47512
|
+
}
|
|
47513
|
+
const totals = /* @__PURE__ */ new Map();
|
|
47514
|
+
const seenResponses = /* @__PURE__ */ new Set();
|
|
47515
|
+
let currentModel;
|
|
47516
|
+
let currentTurn = "unknown-turn";
|
|
47517
|
+
let previous = { model: "unknown" };
|
|
47518
|
+
const add = (usage2) => {
|
|
47519
|
+
const total = totals.get(usage2.model) ?? {
|
|
47520
|
+
model: usage2.model,
|
|
47521
|
+
pricingSource: usage2.pricingSource
|
|
47522
|
+
};
|
|
47523
|
+
for (const field of tokenFields2)
|
|
47524
|
+
total[field] = (total[field] ?? 0) + (usage2[field] ?? 0);
|
|
47525
|
+
totals.set(usage2.model, total);
|
|
47526
|
+
};
|
|
47527
|
+
for (const record of records) {
|
|
47528
|
+
const payload = asRecord(record.payload);
|
|
47529
|
+
if (record.type === "turn_context") {
|
|
47530
|
+
currentTurn = String(payload.turn_id ?? "unknown-turn");
|
|
47531
|
+
if (typeof payload.model === "string") currentModel = payload.model;
|
|
47532
|
+
}
|
|
47533
|
+
if (record.type === "token_usage_record") {
|
|
47534
|
+
const responseId = typeof payload.response_id === "string" ? payload.response_id : void 0;
|
|
47535
|
+
if (responseId && seenResponses.has(responseId)) continue;
|
|
47536
|
+
if (responseId) seenResponses.add(responseId);
|
|
47537
|
+
const responseModel = typeof payload.model === "string" ? payload.model : turnModels.get(String(payload.turn_id)) ?? currentModel;
|
|
47538
|
+
if (responseModel && payload.usage)
|
|
47539
|
+
add(tokens(payload.usage, responseModel));
|
|
47540
|
+
} else if (record.type === "event_msg" && payload.type === "token_count") {
|
|
47541
|
+
const raw = asRecord(payload.info).total_token_usage;
|
|
47542
|
+
if (!raw) continue;
|
|
47543
|
+
const cumulative = tokens(raw, currentModel ?? "unknown");
|
|
47544
|
+
const delta = {
|
|
47545
|
+
model: cumulative.model,
|
|
47546
|
+
pricingSource: "codex-transcript"
|
|
47547
|
+
};
|
|
47548
|
+
for (const field of tokenFields2)
|
|
47549
|
+
delta[field] = Math.max(
|
|
47550
|
+
0,
|
|
47551
|
+
(cumulative[field] ?? 0) - (previous[field] ?? 0)
|
|
47552
|
+
);
|
|
47553
|
+
previous = cumulative;
|
|
47554
|
+
if (!responseTurns.has(currentTurn)) add(delta);
|
|
47555
|
+
}
|
|
47556
|
+
}
|
|
47557
|
+
return {
|
|
47558
|
+
model: model2,
|
|
47559
|
+
effort,
|
|
47560
|
+
...totals.size ? { usage: [...totals.values()] } : {}
|
|
47561
|
+
};
|
|
47562
|
+
}
|
|
47563
|
+
async function readCodexTranscriptMetadata(path) {
|
|
47564
|
+
const records = [];
|
|
47565
|
+
const stream = createReadStream5(path, { encoding: "utf8" });
|
|
47566
|
+
const lines = createInterface2({ input: stream, crlfDelay: Infinity });
|
|
47567
|
+
try {
|
|
47568
|
+
for await (const line of lines) {
|
|
47569
|
+
try {
|
|
47570
|
+
const record = JSON.parse(line);
|
|
47571
|
+
if (record.type === "turn_context" || record.type === "token_usage_record" || record.type === "event_msg" && asRecord(record.payload).type === "token_count")
|
|
47572
|
+
records.push(record);
|
|
47573
|
+
} catch {
|
|
47574
|
+
}
|
|
47575
|
+
}
|
|
47576
|
+
return codexTranscriptMetadata(records);
|
|
47577
|
+
} finally {
|
|
47578
|
+
lines.close();
|
|
47579
|
+
stream.destroy();
|
|
47580
|
+
}
|
|
47581
|
+
}
|
|
47582
|
+
function timestamp2(value) {
|
|
47583
|
+
const date = typeof value === "number" ? new Date(value < 1e12 ? value * 1e3 : value) : typeof value === "string" ? new Date(value) : void 0;
|
|
47584
|
+
return date && Number.isFinite(date.getTime()) ? date.toISOString() : void 0;
|
|
47585
|
+
}
|
|
47586
|
+
function codexImportedHistory(threadValue) {
|
|
47587
|
+
const thread = asRecord(threadValue);
|
|
47588
|
+
const turns = Array.isArray(thread.turns) ? thread.turns : [];
|
|
47589
|
+
const events = [];
|
|
47590
|
+
let finalOutput;
|
|
47591
|
+
let kind = "SESSION";
|
|
47592
|
+
let status2;
|
|
47593
|
+
for (const value of turns) {
|
|
47594
|
+
const turn = asRecord(value);
|
|
47595
|
+
for (const itemValue of Array.isArray(turn.items) ? turn.items : []) {
|
|
47596
|
+
const item = asRecord(itemValue);
|
|
47597
|
+
if (item.type === "plan") kind = "PLAN";
|
|
47598
|
+
if (item.type === "agentMessage" && (item.phase === "final_answer" || item.phase == null) || item.type === "plan") {
|
|
47599
|
+
if (typeof item.text === "string") finalOutput = item.text;
|
|
47600
|
+
}
|
|
47601
|
+
const detail = typeof item.text === "string" ? item.text : typeof item.command === "string" ? item.command : void 0;
|
|
47602
|
+
const inProgress = [
|
|
47603
|
+
"inProgress",
|
|
47604
|
+
"in_progress",
|
|
47605
|
+
"running",
|
|
47606
|
+
"pending"
|
|
47607
|
+
].includes(String(item.status));
|
|
47608
|
+
events.push({
|
|
47609
|
+
id: `${String(turn.id ?? turns.indexOf(value))}:${String(item.id ?? events.length)}`,
|
|
47610
|
+
sequence: events.length,
|
|
47611
|
+
type: inProgress ? "ITEM_STARTED" : "ITEM_COMPLETED",
|
|
47612
|
+
summary: (detail || String(item.type ?? "Codex item")).slice(0, 2e3),
|
|
47613
|
+
detailMarkdown: detail,
|
|
47614
|
+
createdAt: timestamp2(
|
|
47615
|
+
item.createdAt ?? turn.startedAt ?? thread.createdAt
|
|
47616
|
+
),
|
|
47617
|
+
raw: {
|
|
47618
|
+
method: inProgress ? "item/started" : "item/completed",
|
|
47619
|
+
params: { threadId: thread.id, turnId: turn.id, item }
|
|
47620
|
+
}
|
|
47621
|
+
});
|
|
47622
|
+
}
|
|
47623
|
+
if (typeof turn.status === "string") {
|
|
47624
|
+
const inProgress = turn.status === "inProgress";
|
|
47625
|
+
status2 = turn.status === "failed" ? "FAILED" : turn.status === "interrupted" ? "CANCELLED" : void 0;
|
|
47626
|
+
const error = asRecord(turn.error);
|
|
47627
|
+
const detail = typeof error.message === "string" ? error.message : typeof turn.error === "string" ? turn.error : void 0;
|
|
47628
|
+
events.push({
|
|
47629
|
+
id: `${String(turn.id ?? turns.indexOf(value))}:status`,
|
|
47630
|
+
sequence: events.length,
|
|
47631
|
+
type: inProgress ? "TURN_STARTED" : "TURN_COMPLETED",
|
|
47632
|
+
summary: detail || `Turn ${turn.status}`,
|
|
47633
|
+
detailMarkdown: detail,
|
|
47634
|
+
createdAt: timestamp2(
|
|
47635
|
+
turn.completedAt ?? turn.startedAt ?? thread.updatedAt ?? thread.createdAt
|
|
47636
|
+
),
|
|
47637
|
+
raw: {
|
|
47638
|
+
method: inProgress ? "turn/started" : "turn/completed",
|
|
47639
|
+
params: {
|
|
47640
|
+
threadId: thread.id,
|
|
47641
|
+
turn: { ...turn, items: void 0, error: detail ?? turn.error }
|
|
47642
|
+
}
|
|
47643
|
+
}
|
|
47644
|
+
});
|
|
47645
|
+
}
|
|
47646
|
+
}
|
|
47647
|
+
return { events, finalOutput, kind, status: status2 };
|
|
47648
|
+
}
|
|
47649
|
+
|
|
47650
|
+
// src/runs/codex-adapter.ts
|
|
47217
47651
|
var execFileAsync2 = promisify3(execFile3);
|
|
47218
47652
|
function codexAppServerArgs(modelCatalogPath) {
|
|
47219
47653
|
return [
|
|
@@ -47309,10 +47743,10 @@ var CodexAppServer = class {
|
|
|
47309
47743
|
const text2 = String(chunk).trim();
|
|
47310
47744
|
if (text2) console.error(`codex app-server: ${text2}`);
|
|
47311
47745
|
});
|
|
47312
|
-
const lines =
|
|
47746
|
+
const lines = createInterface3({ input: child.stdout });
|
|
47313
47747
|
lines.on("line", (line) => this.receive(line));
|
|
47314
|
-
await new Promise((
|
|
47315
|
-
child.once("spawn",
|
|
47748
|
+
await new Promise((resolve11, reject) => {
|
|
47749
|
+
child.once("spawn", resolve11);
|
|
47316
47750
|
child.once("error", reject);
|
|
47317
47751
|
});
|
|
47318
47752
|
await this.requestDirect("initialize", {
|
|
@@ -47410,8 +47844,8 @@ var CodexAppServer = class {
|
|
|
47410
47844
|
}
|
|
47411
47845
|
requestDirect(method, params) {
|
|
47412
47846
|
const id2 = this.nextId++;
|
|
47413
|
-
return new Promise((
|
|
47414
|
-
this.pending.set(id2, { resolve:
|
|
47847
|
+
return new Promise((resolve11, reject) => {
|
|
47848
|
+
this.pending.set(id2, { resolve: resolve11, reject });
|
|
47415
47849
|
this.write({ id: id2, method, params });
|
|
47416
47850
|
});
|
|
47417
47851
|
}
|
|
@@ -47574,8 +48008,8 @@ var CodexAdapter = class {
|
|
|
47574
48008
|
let lastUsageSignature = "";
|
|
47575
48009
|
const pendingQuestions = /* @__PURE__ */ new Map();
|
|
47576
48010
|
let resolveCompletion;
|
|
47577
|
-
const completion = new Promise((
|
|
47578
|
-
resolveCompletion =
|
|
48011
|
+
const completion = new Promise((resolve11) => {
|
|
48012
|
+
resolveCompletion = resolve11;
|
|
47579
48013
|
});
|
|
47580
48014
|
const unsubscribe = this.server.listen(nativeId, (message) => {
|
|
47581
48015
|
void (async () => {
|
|
@@ -47720,7 +48154,8 @@ var CodexAdapter = class {
|
|
|
47720
48154
|
archived,
|
|
47721
48155
|
cursor,
|
|
47722
48156
|
limit: 100,
|
|
47723
|
-
sortDirection: "asc"
|
|
48157
|
+
sortDirection: "asc",
|
|
48158
|
+
sourceKinds: ["cli", "vscode", "exec", "appServer"]
|
|
47724
48159
|
})
|
|
47725
48160
|
);
|
|
47726
48161
|
const threads = Array.isArray(page.data) ? page.data : [];
|
|
@@ -47728,12 +48163,13 @@ var CodexAdapter = class {
|
|
|
47728
48163
|
const thread = asRecord(value);
|
|
47729
48164
|
const updatedAtKey = String(thread.updatedAt ?? "");
|
|
47730
48165
|
const cached = this.hydrationCache.get(String(thread.id));
|
|
47731
|
-
let
|
|
47732
|
-
|
|
47733
|
-
if (
|
|
47734
|
-
|
|
47735
|
-
|
|
48166
|
+
let history = {};
|
|
48167
|
+
const active = asRecord(thread.status).type === "active";
|
|
48168
|
+
if (active) this.hydrationCache.delete(String(thread.id));
|
|
48169
|
+
if (cached && cached.updatedAt === updatedAtKey && !active) {
|
|
48170
|
+
history = cached.history;
|
|
47736
48171
|
} else {
|
|
48172
|
+
let hydratedSuccessfully = false;
|
|
47737
48173
|
try {
|
|
47738
48174
|
const detail = asRecord(
|
|
47739
48175
|
await this.server.request("thread/read", {
|
|
@@ -47742,31 +48178,41 @@ var CodexAdapter = class {
|
|
|
47742
48178
|
})
|
|
47743
48179
|
);
|
|
47744
48180
|
const hydrated = asRecord(detail.thread);
|
|
47745
|
-
|
|
47746
|
-
|
|
47747
|
-
|
|
47748
|
-
|
|
48181
|
+
if (Array.isArray(hydrated.turns)) {
|
|
48182
|
+
history = codexImportedHistory(hydrated);
|
|
48183
|
+
hydratedSuccessfully = true;
|
|
48184
|
+
}
|
|
48185
|
+
} catch {
|
|
48186
|
+
}
|
|
48187
|
+
try {
|
|
48188
|
+
const path = typeof thread.path === "string" ? thread.path : await findCodexSessionFile(
|
|
48189
|
+
String(thread.id),
|
|
48190
|
+
homedir12(),
|
|
48191
|
+
process.env.CODEX_HOME
|
|
47749
48192
|
);
|
|
48193
|
+
if (path)
|
|
48194
|
+
Object.assign(
|
|
48195
|
+
history,
|
|
48196
|
+
await readCodexTranscriptMetadata(path)
|
|
48197
|
+
);
|
|
48198
|
+
} catch {
|
|
48199
|
+
}
|
|
48200
|
+
if (!active && hydratedSuccessfully && history.model && history.usage) {
|
|
47750
48201
|
this.hydrationCache.set(String(thread.id), {
|
|
47751
48202
|
updatedAt: updatedAtKey,
|
|
47752
|
-
|
|
47753
|
-
finalOutput
|
|
48203
|
+
history
|
|
47754
48204
|
});
|
|
47755
|
-
} catch {
|
|
47756
48205
|
}
|
|
47757
48206
|
}
|
|
47758
48207
|
results.push({
|
|
47759
48208
|
nativeId: String(thread.id),
|
|
47760
48209
|
worktreeId: worktree.id,
|
|
47761
|
-
|
|
47762
|
-
status:
|
|
47763
|
-
asRecord(thread.status).type ?? thread.status ?? "COMPLETED"
|
|
47764
|
-
).toUpperCase(),
|
|
48210
|
+
...history,
|
|
48211
|
+
status: active ? "IN_PROGRESS" : asRecord(thread.status).type === "systemError" ? "FAILED" : history.status ?? "COMPLETED",
|
|
47765
48212
|
archived,
|
|
47766
48213
|
prompt: String(
|
|
47767
48214
|
thread.preview ?? thread.name ?? "Imported Codex thread"
|
|
47768
48215
|
),
|
|
47769
|
-
finalOutput,
|
|
47770
48216
|
branch: firstString(asRecord(thread.gitInfo).branch) || worktree.branch || void 0,
|
|
47771
48217
|
createdAt: thread.createdAt ? new Date(Number(thread.createdAt) * 1e3).toISOString() : void 0,
|
|
47772
48218
|
updatedAt: thread.updatedAt ? new Date(Number(thread.updatedAt) * 1e3).toISOString() : void 0,
|
|
@@ -47785,13 +48231,13 @@ var CodexAdapter = class {
|
|
|
47785
48231
|
};
|
|
47786
48232
|
|
|
47787
48233
|
// src/runs/opencode-adapter.ts
|
|
47788
|
-
import { dirname as dirname12 } from "node:path";
|
|
48234
|
+
import { dirname as dirname12, resolve as resolve10 } from "node:path";
|
|
47789
48235
|
import { pathToFileURL } from "node:url";
|
|
47790
48236
|
|
|
47791
48237
|
// ../../node_modules/@opencode-ai/sdk/dist/v2/gen/core/serverSentEvents.gen.js
|
|
47792
48238
|
var createSseClient = ({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url, ...options }) => {
|
|
47793
48239
|
let lastEventId;
|
|
47794
|
-
const sleep = sseSleepFn ?? ((ms) => new Promise((
|
|
48240
|
+
const sleep = sseSleepFn ?? ((ms) => new Promise((resolve11) => setTimeout(resolve11, ms)));
|
|
47795
48241
|
const createStream = async function* () {
|
|
47796
48242
|
let retryDelay = sseDefaultRetryDelay ?? 3e3;
|
|
47797
48243
|
let attempt = 0;
|
|
@@ -53243,7 +53689,7 @@ async function createOpencodeServer(options) {
|
|
|
53243
53689
|
});
|
|
53244
53690
|
let clear = () => {
|
|
53245
53691
|
};
|
|
53246
|
-
const url = await new Promise((
|
|
53692
|
+
const url = await new Promise((resolve11, reject) => {
|
|
53247
53693
|
const id2 = setTimeout(() => {
|
|
53248
53694
|
clear();
|
|
53249
53695
|
stop(proc);
|
|
@@ -53268,7 +53714,7 @@ async function createOpencodeServer(options) {
|
|
|
53268
53714
|
}
|
|
53269
53715
|
clearTimeout(id2);
|
|
53270
53716
|
resolved = true;
|
|
53271
|
-
|
|
53717
|
+
resolve11(match[1]);
|
|
53272
53718
|
return;
|
|
53273
53719
|
}
|
|
53274
53720
|
}
|
|
@@ -53317,10 +53763,231 @@ async function createOpencode(options) {
|
|
|
53317
53763
|
};
|
|
53318
53764
|
}
|
|
53319
53765
|
|
|
53766
|
+
// src/runs/opencode-import.ts
|
|
53767
|
+
function opencodeModel(value) {
|
|
53768
|
+
const model2 = asRecord(value);
|
|
53769
|
+
const id2 = model2.modelID ?? model2.id;
|
|
53770
|
+
return typeof model2.providerID === "string" && typeof id2 === "string" ? `${model2.providerID}/${id2}` : void 0;
|
|
53771
|
+
}
|
|
53772
|
+
function opencodeTimestamp(value) {
|
|
53773
|
+
const date = typeof value === "number" ? new Date(value) : void 0;
|
|
53774
|
+
return date && Number.isFinite(date.getTime()) ? date.toISOString() : void 0;
|
|
53775
|
+
}
|
|
53776
|
+
function amount2(value) {
|
|
53777
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
53778
|
+
}
|
|
53779
|
+
function tokenUsage(value, model2) {
|
|
53780
|
+
const tokens2 = asRecord(value);
|
|
53781
|
+
const cache = asRecord(tokens2.cache);
|
|
53782
|
+
const count3 = (value2) => Math.floor(amount2(value2) ?? 0);
|
|
53783
|
+
return {
|
|
53784
|
+
model: model2,
|
|
53785
|
+
inputTokens: count3(tokens2.input),
|
|
53786
|
+
outputTokens: count3(tokens2.output),
|
|
53787
|
+
reasoningTokens: count3(tokens2.reasoning),
|
|
53788
|
+
cacheReadTokens: count3(cache.read),
|
|
53789
|
+
cacheWriteTokens: count3(cache.write),
|
|
53790
|
+
pricingSource: "opencode-history"
|
|
53791
|
+
};
|
|
53792
|
+
}
|
|
53793
|
+
var tokenFields3 = [
|
|
53794
|
+
"inputTokens",
|
|
53795
|
+
"outputTokens",
|
|
53796
|
+
"reasoningTokens",
|
|
53797
|
+
"cacheReadTokens",
|
|
53798
|
+
"cacheWriteTokens"
|
|
53799
|
+
];
|
|
53800
|
+
function textParts(parts) {
|
|
53801
|
+
return parts.filter((part) => part.type === "text" && typeof part.text === "string").map((part) => String(part.text).trim()).filter(Boolean).join("\n\n");
|
|
53802
|
+
}
|
|
53803
|
+
function userPrompt(parts) {
|
|
53804
|
+
const originalParts = parts.filter((part) => part.synthetic !== true);
|
|
53805
|
+
return textParts(originalParts) || originalParts.filter(
|
|
53806
|
+
(part) => part.type === "subtask" && typeof part.prompt === "string"
|
|
53807
|
+
).map((part) => String(part.prompt).trim()).filter(Boolean).join("\n\n");
|
|
53808
|
+
}
|
|
53809
|
+
function nativePart(value) {
|
|
53810
|
+
const part = asRecord(value);
|
|
53811
|
+
if (part.type !== "tool") return part;
|
|
53812
|
+
const state = asRecord(part.state);
|
|
53813
|
+
const time = asRecord(part.time);
|
|
53814
|
+
const content = Array.isArray(state.content) ? state.content.map(asRecord) : [];
|
|
53815
|
+
return {
|
|
53816
|
+
...part,
|
|
53817
|
+
tool: part.name,
|
|
53818
|
+
state: {
|
|
53819
|
+
...state,
|
|
53820
|
+
output: textParts(content),
|
|
53821
|
+
metadata: state.structured,
|
|
53822
|
+
time: { start: time.ran ?? time.created, end: time.completed }
|
|
53823
|
+
}
|
|
53824
|
+
};
|
|
53825
|
+
}
|
|
53826
|
+
function opencodeImportedHistory(sessionValue, messageValues) {
|
|
53827
|
+
const session = asRecord(sessionValue);
|
|
53828
|
+
const messages = /* @__PURE__ */ new Map();
|
|
53829
|
+
for (const [index, value] of messageValues.entries()) {
|
|
53830
|
+
const message = asRecord(value);
|
|
53831
|
+
const info = asRecord(message.info ?? message);
|
|
53832
|
+
messages.set(String(info.id ?? index), message);
|
|
53833
|
+
}
|
|
53834
|
+
const ordered = [...messages.entries()].sort(([, left], [, right]) => {
|
|
53835
|
+
const leftInfo = asRecord(left.info ?? left);
|
|
53836
|
+
const rightInfo = asRecord(right.info ?? right);
|
|
53837
|
+
return Number(asRecord(leftInfo.time).created ?? 0) - Number(asRecord(rightInfo.time).created ?? 0);
|
|
53838
|
+
});
|
|
53839
|
+
const events = [];
|
|
53840
|
+
const totals = /* @__PURE__ */ new Map();
|
|
53841
|
+
const unpricedModels = /* @__PURE__ */ new Set();
|
|
53842
|
+
let model2;
|
|
53843
|
+
let effort;
|
|
53844
|
+
let prompt;
|
|
53845
|
+
let finalOutput;
|
|
53846
|
+
let status2;
|
|
53847
|
+
let requestedModel;
|
|
53848
|
+
let requestedVariant;
|
|
53849
|
+
let agent;
|
|
53850
|
+
const addUsage = (usage2) => {
|
|
53851
|
+
const total = totals.get(usage2.model) ?? {
|
|
53852
|
+
model: usage2.model,
|
|
53853
|
+
pricingSource: "opencode-history"
|
|
53854
|
+
};
|
|
53855
|
+
for (const field of tokenFields3)
|
|
53856
|
+
total[field] = (total[field] ?? 0) + (usage2[field] ?? 0);
|
|
53857
|
+
if (usage2.estimatedCost === void 0) unpricedModels.add(usage2.model);
|
|
53858
|
+
else total.estimatedCost = (total.estimatedCost ?? 0) + usage2.estimatedCost;
|
|
53859
|
+
totals.set(usage2.model, total);
|
|
53860
|
+
};
|
|
53861
|
+
const emit = (id2, type, summary, properties, createdAt, detailMarkdown) => {
|
|
53862
|
+
events.push({
|
|
53863
|
+
id: id2,
|
|
53864
|
+
sequence: events.length,
|
|
53865
|
+
type: type.toUpperCase().replaceAll(".", "_"),
|
|
53866
|
+
summary: (summary.trim() || type).slice(0, 2e3),
|
|
53867
|
+
detailMarkdown,
|
|
53868
|
+
createdAt,
|
|
53869
|
+
raw: { type, properties }
|
|
53870
|
+
});
|
|
53871
|
+
};
|
|
53872
|
+
for (const [id2, message] of ordered) {
|
|
53873
|
+
const legacy = !!message.info;
|
|
53874
|
+
const original = asRecord(message.info ?? message);
|
|
53875
|
+
const role = original.role ?? original.type;
|
|
53876
|
+
const time = asRecord(original.time);
|
|
53877
|
+
const createdAt = opencodeTimestamp(
|
|
53878
|
+
time.created ?? asRecord(session.time).created
|
|
53879
|
+
);
|
|
53880
|
+
const parts = legacy ? Array.isArray(message.parts) ? message.parts.map(asRecord) : [] : Array.isArray(original.content) ? original.content.map(nativePart) : [];
|
|
53881
|
+
if (!legacy && ["user", "synthetic", "system", "compaction"].includes(String(role)))
|
|
53882
|
+
parts.push({
|
|
53883
|
+
id: "text",
|
|
53884
|
+
type: "text",
|
|
53885
|
+
text: role === "user" ? original.text : original.text ?? original.summary
|
|
53886
|
+
});
|
|
53887
|
+
if (!legacy && role === "shell")
|
|
53888
|
+
parts.push({
|
|
53889
|
+
id: original.callID ?? "shell",
|
|
53890
|
+
type: "tool",
|
|
53891
|
+
tool: "bash",
|
|
53892
|
+
state: {
|
|
53893
|
+
input: { command: original.command },
|
|
53894
|
+
output: original.output,
|
|
53895
|
+
status: time.completed ? "completed" : "running",
|
|
53896
|
+
time: { start: time.created, end: time.completed }
|
|
53897
|
+
}
|
|
53898
|
+
});
|
|
53899
|
+
const info = {
|
|
53900
|
+
...original,
|
|
53901
|
+
id: id2,
|
|
53902
|
+
sessionID: session.id,
|
|
53903
|
+
role,
|
|
53904
|
+
modelID: original.modelID ?? asRecord(original.model).id
|
|
53905
|
+
};
|
|
53906
|
+
delete info.content;
|
|
53907
|
+
emit(
|
|
53908
|
+
`message:${id2}`,
|
|
53909
|
+
"message.updated",
|
|
53910
|
+
`${String(role ?? "Message")} message`,
|
|
53911
|
+
{ info },
|
|
53912
|
+
createdAt
|
|
53913
|
+
);
|
|
53914
|
+
for (const [index, part] of parts.entries()) {
|
|
53915
|
+
const state = asRecord(part.state);
|
|
53916
|
+
const detail = typeof part.text === "string" ? part.text : void 0;
|
|
53917
|
+
const summary = detail ?? (part.type === "tool" ? String(part.tool ?? "Tool") : String(part.type ?? "Message part"));
|
|
53918
|
+
emit(
|
|
53919
|
+
`${id2}:part:${String(part.id ?? index)}`,
|
|
53920
|
+
"message.part.updated",
|
|
53921
|
+
summary,
|
|
53922
|
+
{ part: { ...part, sessionID: session.id, messageID: id2 } },
|
|
53923
|
+
opencodeTimestamp(
|
|
53924
|
+
asRecord(state.time).start ?? asRecord(part.time).created
|
|
53925
|
+
) ?? createdAt,
|
|
53926
|
+
detail
|
|
53927
|
+
);
|
|
53928
|
+
}
|
|
53929
|
+
if (role === "user" || role === "model-switched") {
|
|
53930
|
+
requestedModel = opencodeModel(original.model);
|
|
53931
|
+
requestedVariant = typeof asRecord(original.model).variant === "string" ? String(asRecord(original.model).variant) : void 0;
|
|
53932
|
+
if (role === "user" && !prompt) prompt = userPrompt(parts) || void 0;
|
|
53933
|
+
}
|
|
53934
|
+
if (role !== "assistant") continue;
|
|
53935
|
+
const actualModel = opencodeModel(original) ?? opencodeModel(original.model);
|
|
53936
|
+
if (actualModel) {
|
|
53937
|
+
model2 = actualModel;
|
|
53938
|
+
effort = typeof original.variant === "string" ? original.variant : typeof asRecord(original.model).variant === "string" ? String(asRecord(original.model).variant) : actualModel === requestedModel ? requestedVariant ?? "auto" : "auto";
|
|
53939
|
+
}
|
|
53940
|
+
agent = typeof original.agent === "string" ? original.agent : agent;
|
|
53941
|
+
const error = asRecord(original.error);
|
|
53942
|
+
status2 = original.error ? error.name === "MessageAbortedError" ? "CANCELLED" : "FAILED" : "COMPLETED";
|
|
53943
|
+
const responseText = textParts(parts);
|
|
53944
|
+
if (responseText && original.summary !== true && !["tool-calls", "tool_calls"].includes(String(original.finish)))
|
|
53945
|
+
finalOutput = responseText;
|
|
53946
|
+
const steps = parts.filter((part) => part.type === "step-finish");
|
|
53947
|
+
if (original.tokens || steps.length || amount2(original.cost) !== void 0) {
|
|
53948
|
+
const usage2 = tokenUsage(original.tokens, actualModel ?? "unknown");
|
|
53949
|
+
if (!original.tokens)
|
|
53950
|
+
for (const step of steps) {
|
|
53951
|
+
const stepUsage = tokenUsage(step.tokens, usage2.model);
|
|
53952
|
+
for (const field of tokenFields3)
|
|
53953
|
+
usage2[field] = (usage2[field] ?? 0) + (stepUsage[field] ?? 0);
|
|
53954
|
+
}
|
|
53955
|
+
usage2.estimatedCost = amount2(original.cost) ?? (steps.length && steps.every((step) => amount2(step.cost) !== void 0) ? steps.reduce((sum, step) => sum + amount2(step.cost), 0) : void 0);
|
|
53956
|
+
addUsage(usage2);
|
|
53957
|
+
}
|
|
53958
|
+
}
|
|
53959
|
+
if (session.tokens) {
|
|
53960
|
+
const usage2 = tokenUsage(session.tokens, "unknown");
|
|
53961
|
+
for (const field of tokenFields3)
|
|
53962
|
+
usage2[field] = Math.max(
|
|
53963
|
+
0,
|
|
53964
|
+
(usage2[field] ?? 0) - [...totals.values()].reduce((sum, row) => sum + (row[field] ?? 0), 0)
|
|
53965
|
+
);
|
|
53966
|
+
if (tokenFields3.some((field) => usage2[field])) addUsage(usage2);
|
|
53967
|
+
}
|
|
53968
|
+
for (const model3 of unpricedModels) {
|
|
53969
|
+
const usage2 = totals.get(model3);
|
|
53970
|
+
if (usage2) delete usage2.estimatedCost;
|
|
53971
|
+
}
|
|
53972
|
+
const estimatedCost = amount2(session.cost);
|
|
53973
|
+
return {
|
|
53974
|
+
events,
|
|
53975
|
+
...totals.size || session.tokens ? { usage: [...totals.values()] } : {},
|
|
53976
|
+
model: model2 ?? requestedModel ?? opencodeModel(session.model),
|
|
53977
|
+
effort: effort ?? requestedVariant ?? (typeof asRecord(session.model).variant === "string" ? String(asRecord(session.model).variant) : void 0),
|
|
53978
|
+
prompt,
|
|
53979
|
+
finalOutput,
|
|
53980
|
+
status: status2,
|
|
53981
|
+
kind: (agent ?? session.agent) === "plan" ? "PLAN" : "SESSION",
|
|
53982
|
+
...estimatedCost !== void 0 ? { estimatedCost, pricingSource: "opencode-history" } : {}
|
|
53983
|
+
};
|
|
53984
|
+
}
|
|
53985
|
+
|
|
53320
53986
|
// src/runs/opencode-adapter.ts
|
|
53321
53987
|
var QUESTION_RECONCILIATION_INTERVAL_MS = 1e3;
|
|
53322
53988
|
var QUESTION_RECONCILIATION_TIMEOUT_MS = 5e3;
|
|
53323
53989
|
var POST_ANSWER_COMPLETION_TIMEOUT_MS = 15 * 6e4;
|
|
53990
|
+
var IMPORT_PAGE_SIZE = 200;
|
|
53324
53991
|
function resultData(value) {
|
|
53325
53992
|
const record = asRecord(value);
|
|
53326
53993
|
return "data" in record ? record.data : value;
|
|
@@ -53516,11 +54183,11 @@ function responseItems(value) {
|
|
|
53516
54183
|
}
|
|
53517
54184
|
function waitForPoll(signal) {
|
|
53518
54185
|
if (signal.aborted) return Promise.resolve();
|
|
53519
|
-
return new Promise((
|
|
54186
|
+
return new Promise((resolve11) => {
|
|
53520
54187
|
const finish = () => {
|
|
53521
54188
|
clearTimeout(timer);
|
|
53522
54189
|
signal.removeEventListener("abort", finish);
|
|
53523
|
-
|
|
54190
|
+
resolve11();
|
|
53524
54191
|
};
|
|
53525
54192
|
const timer = setTimeout(finish, QUESTION_RECONCILIATION_INTERVAL_MS);
|
|
53526
54193
|
timer.unref();
|
|
@@ -53539,6 +54206,7 @@ var OpenCodeAdapter = class {
|
|
|
53539
54206
|
nativeDelete: true
|
|
53540
54207
|
};
|
|
53541
54208
|
runtime;
|
|
54209
|
+
hydrationCache = /* @__PURE__ */ new Map();
|
|
53542
54210
|
async client() {
|
|
53543
54211
|
if (!this.runtime) {
|
|
53544
54212
|
const executable = findExecutable("opencode", {
|
|
@@ -53838,14 +54506,14 @@ var OpenCodeAdapter = class {
|
|
|
53838
54506
|
}
|
|
53839
54507
|
const finalOutput = opencodeResponseText(response);
|
|
53840
54508
|
const info = asRecord(asRecord(response).info);
|
|
53841
|
-
const
|
|
54509
|
+
const tokens2 = asRecord(info.tokens);
|
|
53842
54510
|
await callbacks.onUsage({
|
|
53843
54511
|
model: input.run.model,
|
|
53844
|
-
inputTokens: Number(
|
|
53845
|
-
outputTokens: Number(
|
|
53846
|
-
reasoningTokens: Number(
|
|
53847
|
-
cacheReadTokens: Number(asRecord(
|
|
53848
|
-
cacheWriteTokens: Number(asRecord(
|
|
54512
|
+
inputTokens: Number(tokens2.input ?? 0),
|
|
54513
|
+
outputTokens: Number(tokens2.output ?? 0),
|
|
54514
|
+
reasoningTokens: Number(tokens2.reasoning ?? 0),
|
|
54515
|
+
cacheReadTokens: Number(asRecord(tokens2.cache).read ?? 0),
|
|
54516
|
+
cacheWriteTokens: Number(asRecord(tokens2.cache).write ?? 0),
|
|
53849
54517
|
estimatedCost: Number(info.cost ?? 0),
|
|
53850
54518
|
pricingSource: "opencode-sdk"
|
|
53851
54519
|
});
|
|
@@ -53913,64 +54581,209 @@ var OpenCodeAdapter = class {
|
|
|
53913
54581
|
const client2 = await this.client();
|
|
53914
54582
|
await client2.session.delete({ sessionID: nativeId, directory: cwd });
|
|
53915
54583
|
}
|
|
54584
|
+
async legacyHistory(client2, nativeId, directory) {
|
|
54585
|
+
const messages = [];
|
|
54586
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
54587
|
+
let before;
|
|
54588
|
+
do {
|
|
54589
|
+
const response = await client2.session.messages(
|
|
54590
|
+
{
|
|
54591
|
+
sessionID: nativeId,
|
|
54592
|
+
directory,
|
|
54593
|
+
limit: IMPORT_PAGE_SIZE,
|
|
54594
|
+
...before ? { before } : {}
|
|
54595
|
+
},
|
|
54596
|
+
{ throwOnError: true }
|
|
54597
|
+
);
|
|
54598
|
+
const page = resultData(response);
|
|
54599
|
+
if (!Array.isArray(page))
|
|
54600
|
+
throw new Error("Invalid legacy OpenCode message history");
|
|
54601
|
+
messages.push(...page);
|
|
54602
|
+
before = response.response?.headers.get("x-next-cursor") ?? void 0;
|
|
54603
|
+
if (before && seenCursors.has(before))
|
|
54604
|
+
throw new Error("Repeated legacy OpenCode message cursor");
|
|
54605
|
+
if (before) seenCursors.add(before);
|
|
54606
|
+
} while (before);
|
|
54607
|
+
return messages;
|
|
54608
|
+
}
|
|
54609
|
+
async importedHistory(client2, nativeId, directory, surface) {
|
|
54610
|
+
if (surface === "LEGACY")
|
|
54611
|
+
return this.legacyHistory(client2, nativeId, directory);
|
|
54612
|
+
const messages = [];
|
|
54613
|
+
let cursor;
|
|
54614
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
54615
|
+
try {
|
|
54616
|
+
do {
|
|
54617
|
+
const page = asRecord(
|
|
54618
|
+
resultData(
|
|
54619
|
+
await client2.v2.session.messages(
|
|
54620
|
+
{
|
|
54621
|
+
sessionID: nativeId,
|
|
54622
|
+
limit: IMPORT_PAGE_SIZE,
|
|
54623
|
+
...cursor ? { cursor } : { order: "asc" }
|
|
54624
|
+
},
|
|
54625
|
+
{ throwOnError: true }
|
|
54626
|
+
)
|
|
54627
|
+
)
|
|
54628
|
+
);
|
|
54629
|
+
if (!Array.isArray(page.data))
|
|
54630
|
+
throw new Error("Invalid OpenCode message history");
|
|
54631
|
+
messages.push(...page.data);
|
|
54632
|
+
cursor = typeof asRecord(page.cursor).next === "string" ? String(asRecord(page.cursor).next) : void 0;
|
|
54633
|
+
if (cursor && seenCursors.has(cursor))
|
|
54634
|
+
throw new Error("Repeated OpenCode message cursor");
|
|
54635
|
+
if (cursor) seenCursors.add(cursor);
|
|
54636
|
+
} while (cursor);
|
|
54637
|
+
} catch (error) {
|
|
54638
|
+
if (messages.length || cursor) throw error;
|
|
54639
|
+
return this.legacyHistory(client2, nativeId, directory);
|
|
54640
|
+
}
|
|
54641
|
+
if (messages.length) return messages;
|
|
54642
|
+
try {
|
|
54643
|
+
return await this.legacyHistory(client2, nativeId, directory);
|
|
54644
|
+
} catch (error) {
|
|
54645
|
+
const name = String(asRecord(error)._tag ?? asRecord(error).name ?? "");
|
|
54646
|
+
if (["NotFoundError", "SessionNotFoundError"].includes(name))
|
|
54647
|
+
return messages;
|
|
54648
|
+
throw error;
|
|
54649
|
+
}
|
|
54650
|
+
}
|
|
53916
54651
|
async discover(worktrees) {
|
|
53917
54652
|
const client2 = await this.client();
|
|
53918
54653
|
const results = [];
|
|
53919
|
-
const
|
|
53920
|
-
|
|
53921
|
-
);
|
|
53922
|
-
|
|
54654
|
+
const hydrationFailures = [];
|
|
54655
|
+
let hydratedCount = 0;
|
|
54656
|
+
const activeIds = /* @__PURE__ */ new Set();
|
|
54657
|
+
try {
|
|
54658
|
+
const active = asRecord(
|
|
54659
|
+
resultData(await client2.v2.session.active({ throwOnError: true }))
|
|
54660
|
+
);
|
|
54661
|
+
for (const id2 of Object.keys(asRecord(active.data))) activeIds.add(id2);
|
|
54662
|
+
} catch {
|
|
54663
|
+
}
|
|
53923
54664
|
for (const worktree of worktrees) {
|
|
53924
|
-
|
|
53925
|
-
|
|
53926
|
-
|
|
53927
|
-
|
|
53928
|
-
|
|
53929
|
-
|
|
53930
|
-
|
|
53931
|
-
|
|
53932
|
-
|
|
53933
|
-
|
|
54665
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
54666
|
+
let listed = false;
|
|
54667
|
+
let listError;
|
|
54668
|
+
try {
|
|
54669
|
+
let cursor;
|
|
54670
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
54671
|
+
do {
|
|
54672
|
+
const response = asRecord(
|
|
54673
|
+
resultData(
|
|
54674
|
+
await client2.v2.session.list(
|
|
54675
|
+
{
|
|
54676
|
+
directory: worktree.folder,
|
|
54677
|
+
limit: IMPORT_PAGE_SIZE,
|
|
54678
|
+
...cursor ? { cursor } : { order: "asc" }
|
|
54679
|
+
},
|
|
54680
|
+
{ throwOnError: true }
|
|
54681
|
+
)
|
|
54682
|
+
)
|
|
54683
|
+
);
|
|
54684
|
+
if (!Array.isArray(response.data))
|
|
54685
|
+
throw new Error("Invalid OpenCode session list");
|
|
54686
|
+
for (const value of response.data) {
|
|
54687
|
+
const session = asRecord(value);
|
|
54688
|
+
if (typeof session.id === "string")
|
|
54689
|
+
sessions.set(session.id, { session, surface: "V2" });
|
|
54690
|
+
}
|
|
54691
|
+
cursor = typeof asRecord(response.cursor).next === "string" ? String(asRecord(response.cursor).next) : void 0;
|
|
54692
|
+
if (cursor && seenCursors.has(cursor))
|
|
54693
|
+
throw new Error("Repeated OpenCode session cursor");
|
|
54694
|
+
if (cursor) seenCursors.add(cursor);
|
|
54695
|
+
} while (cursor);
|
|
54696
|
+
listed = true;
|
|
54697
|
+
} catch (error) {
|
|
54698
|
+
listError = error;
|
|
54699
|
+
}
|
|
54700
|
+
try {
|
|
54701
|
+
const legacy = resultData(
|
|
54702
|
+
await client2.session.list(
|
|
54703
|
+
{ directory: worktree.folder, limit: IMPORT_PAGE_SIZE },
|
|
54704
|
+
{ throwOnError: true }
|
|
53934
54705
|
)
|
|
53935
54706
|
);
|
|
53936
|
-
|
|
53937
|
-
|
|
54707
|
+
if (!Array.isArray(legacy))
|
|
54708
|
+
throw new Error("Invalid legacy OpenCode session list");
|
|
54709
|
+
for (const value of legacy) {
|
|
53938
54710
|
const session = asRecord(value);
|
|
53939
|
-
|
|
53940
|
-
|
|
53941
|
-
|
|
54711
|
+
if (typeof session.id === "string" && !sessions.has(session.id))
|
|
54712
|
+
sessions.set(session.id, { session, surface: "LEGACY" });
|
|
54713
|
+
}
|
|
54714
|
+
listed = true;
|
|
54715
|
+
} catch (error) {
|
|
54716
|
+
listError ??= error;
|
|
54717
|
+
}
|
|
54718
|
+
if (!listed) throw listError;
|
|
54719
|
+
try {
|
|
54720
|
+
const statuses = asRecord(
|
|
54721
|
+
resultData(
|
|
54722
|
+
await client2.session.status(
|
|
54723
|
+
{ directory: worktree.folder },
|
|
54724
|
+
{ throwOnError: true }
|
|
54725
|
+
)
|
|
54726
|
+
)
|
|
54727
|
+
);
|
|
54728
|
+
for (const [id2, value] of Object.entries(statuses))
|
|
54729
|
+
if (["busy", "retry"].includes(String(asRecord(value).type)))
|
|
54730
|
+
activeIds.add(id2);
|
|
54731
|
+
} catch {
|
|
54732
|
+
}
|
|
54733
|
+
for (const [nativeId, { session, surface }] of sessions) {
|
|
54734
|
+
const directory = session.directory ?? asRecord(session.location).directory;
|
|
54735
|
+
if (typeof directory === "string" && resolve10(directory) !== resolve10(worktree.folder))
|
|
54736
|
+
continue;
|
|
54737
|
+
const time = asRecord(session.time);
|
|
54738
|
+
const active = activeIds.has(nativeId);
|
|
54739
|
+
const key = JSON.stringify([
|
|
54740
|
+
surface,
|
|
54741
|
+
time.updated,
|
|
54742
|
+
session.cost,
|
|
54743
|
+
session.tokens,
|
|
54744
|
+
session.model
|
|
54745
|
+
]);
|
|
54746
|
+
const cached = this.hydrationCache.get(nativeId);
|
|
54747
|
+
if (active) this.hydrationCache.delete(nativeId);
|
|
54748
|
+
let history = {};
|
|
54749
|
+
if (!active && cached?.key === key) history = cached.history;
|
|
54750
|
+
else {
|
|
53942
54751
|
try {
|
|
53943
|
-
const messages =
|
|
53944
|
-
|
|
53945
|
-
|
|
53946
|
-
|
|
53947
|
-
|
|
53948
|
-
order: "desc"
|
|
53949
|
-
})
|
|
53950
|
-
)
|
|
53951
|
-
);
|
|
53952
|
-
finalOutput = firstString(
|
|
53953
|
-
Array.isArray(messages.data) ? messages.data[0] : messages
|
|
54752
|
+
const messages = await this.importedHistory(
|
|
54753
|
+
client2,
|
|
54754
|
+
nativeId,
|
|
54755
|
+
worktree.folder,
|
|
54756
|
+
surface
|
|
53954
54757
|
);
|
|
53955
|
-
|
|
54758
|
+
history = opencodeImportedHistory(session, messages);
|
|
54759
|
+
if (!active) this.hydrationCache.set(nativeId, { key, history });
|
|
54760
|
+
} catch (error) {
|
|
54761
|
+
const detail = error instanceof Error ? error.message : firstString(asRecord(error).message) ?? String(asRecord(error)._tag ?? error);
|
|
54762
|
+
hydrationFailures.push(`${nativeId}: ${detail}`);
|
|
53956
54763
|
}
|
|
53957
|
-
results.push({
|
|
53958
|
-
nativeId: String(session.id),
|
|
53959
|
-
worktreeId: worktree.id,
|
|
53960
|
-
kind: session.agent === "plan" ? "PLAN" : "SESSION",
|
|
53961
|
-
status: activeIds.has(String(session.id)) ? "IN_PROGRESS" : "COMPLETED",
|
|
53962
|
-
archived: Boolean(time.archived),
|
|
53963
|
-
model: typeof selectedModel.providerID === "string" && typeof selectedModel.id === "string" ? `${selectedModel.providerID}/${selectedModel.id}` : void 0,
|
|
53964
|
-
prompt: firstString(session.title ?? session.summary) || "Imported OpenCode session",
|
|
53965
|
-
finalOutput: finalOutput || firstString(session.summary),
|
|
53966
|
-
branch: worktree.branch || void 0,
|
|
53967
|
-
createdAt: time.created ? new Date(Number(time.created)).toISOString() : void 0,
|
|
53968
|
-
updatedAt: time.updated ? new Date(Number(time.updated)).toISOString() : void 0,
|
|
53969
|
-
rawMetadata: session
|
|
53970
|
-
});
|
|
53971
54764
|
}
|
|
53972
|
-
|
|
53973
|
-
|
|
54765
|
+
if (history.events) hydratedCount += 1;
|
|
54766
|
+
results.push({
|
|
54767
|
+
nativeId,
|
|
54768
|
+
worktreeId: worktree.id,
|
|
54769
|
+
...typeof session.cost === "number" && Number.isFinite(session.cost) && session.cost >= 0 ? { estimatedCost: session.cost, pricingSource: "opencode-history" } : {},
|
|
54770
|
+
...history,
|
|
54771
|
+
kind: history.kind ?? (session.agent === "plan" ? "PLAN" : "SESSION"),
|
|
54772
|
+
status: active ? "IN_PROGRESS" : history.status ?? "COMPLETED",
|
|
54773
|
+
archived: Boolean(time.archived),
|
|
54774
|
+
model: history.model,
|
|
54775
|
+
prompt: history.prompt,
|
|
54776
|
+
branch: worktree.branch || void 0,
|
|
54777
|
+
createdAt: opencodeTimestamp(time.created),
|
|
54778
|
+
updatedAt: opencodeTimestamp(time.updated),
|
|
54779
|
+
rawMetadata: session
|
|
54780
|
+
});
|
|
54781
|
+
}
|
|
54782
|
+
}
|
|
54783
|
+
if (hydrationFailures.length) {
|
|
54784
|
+
const detail = `OpenCode history unavailable for ${hydrationFailures.length} sessions: ${hydrationFailures.slice(0, 3).join("; ")}`;
|
|
54785
|
+
if (!hydratedCount) throw new Error(detail);
|
|
54786
|
+
console.warn(detail);
|
|
53974
54787
|
}
|
|
53975
54788
|
return results;
|
|
53976
54789
|
}
|
|
@@ -54707,10 +55520,19 @@ var RunManager = class {
|
|
|
54707
55520
|
{ ...catalog, capabilities: adapter.capabilities }
|
|
54708
55521
|
);
|
|
54709
55522
|
const runs = await adapter.discover(worktrees);
|
|
54710
|
-
|
|
54711
|
-
|
|
54712
|
-
|
|
54713
|
-
|
|
55523
|
+
let batch = [];
|
|
55524
|
+
let batchBytes = 0;
|
|
55525
|
+
for (const run of runs) {
|
|
55526
|
+
const bytes = Buffer.byteLength(JSON.stringify(run), "utf8");
|
|
55527
|
+
if (batch.length && batchBytes + bytes > 4 * 1024 * 1024) {
|
|
55528
|
+
await this.client.importProviderRuns(adapter.key, batch);
|
|
55529
|
+
batch = [];
|
|
55530
|
+
batchBytes = 0;
|
|
55531
|
+
}
|
|
55532
|
+
batch.push(run);
|
|
55533
|
+
batchBytes += bytes;
|
|
55534
|
+
}
|
|
55535
|
+
await this.client.importProviderRuns(adapter.key, batch);
|
|
54714
55536
|
} catch (error) {
|
|
54715
55537
|
await this.client.reportRunProviderImportStatus(
|
|
54716
55538
|
adapter.key,
|
|
@@ -54745,7 +55567,7 @@ var RunManager = class {
|
|
|
54745
55567
|
return await operation();
|
|
54746
55568
|
} catch (error) {
|
|
54747
55569
|
if (this.stopped || attempt >= attempts) throw error;
|
|
54748
|
-
await new Promise((
|
|
55570
|
+
await new Promise((resolve11) => setTimeout(resolve11, delay));
|
|
54749
55571
|
delay = Math.min(delay * 2, 3e4);
|
|
54750
55572
|
}
|
|
54751
55573
|
}
|
|
@@ -55025,9 +55847,9 @@ async function runAgentSession(config, signal, onUnhealthy) {
|
|
|
55025
55847
|
}
|
|
55026
55848
|
}
|
|
55027
55849
|
);
|
|
55028
|
-
await new Promise((
|
|
55029
|
-
if (signal.aborted)
|
|
55030
|
-
else signal.addEventListener("abort", () =>
|
|
55850
|
+
await new Promise((resolve11) => {
|
|
55851
|
+
if (signal.aborted) resolve11();
|
|
55852
|
+
else signal.addEventListener("abort", () => resolve11(), { once: true });
|
|
55031
55853
|
});
|
|
55032
55854
|
if (heartbeatTimer) clearTimeout(heartbeatTimer);
|
|
55033
55855
|
if (jobReconciliationTimer) clearTimeout(jobReconciliationTimer);
|
|
@@ -55094,7 +55916,7 @@ var defaultDependencies = {
|
|
|
55094
55916
|
inventory: collectInventory,
|
|
55095
55917
|
load: loadConfig,
|
|
55096
55918
|
save: saveConfig,
|
|
55097
|
-
wait: (milliseconds, signal) => new Promise((
|
|
55919
|
+
wait: (milliseconds, signal) => new Promise((resolve11, reject) => {
|
|
55098
55920
|
if (signal.aborted) {
|
|
55099
55921
|
reject(new Error("Development agent startup was cancelled"));
|
|
55100
55922
|
return;
|
|
@@ -55105,7 +55927,7 @@ var defaultDependencies = {
|
|
|
55105
55927
|
};
|
|
55106
55928
|
const timer = setTimeout(() => {
|
|
55107
55929
|
signal.removeEventListener("abort", onAbort);
|
|
55108
|
-
|
|
55930
|
+
resolve11();
|
|
55109
55931
|
}, milliseconds);
|
|
55110
55932
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
55111
55933
|
})
|