lody 0.46.2-next.1 → 0.47.0
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 +244 -243
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -22780,7 +22780,7 @@ Event: ${getEventDescription(event)}`);
|
|
|
22780
22780
|
const mergedOptions = {
|
|
22781
22781
|
...options,
|
|
22782
22782
|
dsn: options.dsn ?? "https://080f9de535ff335a1a0440d0e385f796@o4510491299086336.ingest.us.sentry.io/4510559045681152",
|
|
22783
|
-
environment: options.environment ?? "
|
|
22783
|
+
environment: options.environment ?? "production",
|
|
22784
22784
|
sendClientReports: options.sendClientReports ?? true,
|
|
22785
22785
|
transport: options.transport ?? makeNodeTransport,
|
|
22786
22786
|
stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),
|
|
@@ -36820,7 +36820,7 @@ Mongoose Error Code: ${error2.code}` : ""}`
|
|
|
36820
36820
|
return client;
|
|
36821
36821
|
}
|
|
36822
36822
|
const name = "lody";
|
|
36823
|
-
const version$4 = "0.
|
|
36823
|
+
const version$4 = "0.47.0";
|
|
36824
36824
|
const description = "Lody Agent CLI tool for managing remote command execution";
|
|
36825
36825
|
const type = "module";
|
|
36826
36826
|
const main$3 = "dist/index.js";
|
|
@@ -37068,15 +37068,15 @@ Mongoose Error Code: ${error2.code}` : ""}`
|
|
|
37068
37068
|
return "dev";
|
|
37069
37069
|
}
|
|
37070
37070
|
};
|
|
37071
|
-
const getRuntimeEnv = () => normalizeRuntimeEnv("
|
|
37071
|
+
const getRuntimeEnv = () => normalizeRuntimeEnv("production");
|
|
37072
37072
|
const isDevEnv = () => getRuntimeEnv() === "dev";
|
|
37073
37073
|
const runtimeEnv = getRuntimeEnv();
|
|
37074
|
-
const environment$1 = "
|
|
37074
|
+
const environment$1 = "production";
|
|
37075
37075
|
const dsn = "https://080f9de535ff335a1a0440d0e385f796@o4510491299086336.ingest.us.sentry.io/4510559045681152";
|
|
37076
37076
|
const postHogHost = process.env.LODY_POSTHOG_HOST ?? "https://us.i.posthog.com";
|
|
37077
37077
|
const postHogKey = process.env.LODY_POSTHOG_KEY ?? "phc_LFS5i5WIwg4irAhrG5oJR04iYPhReVZ3DdFZOKqCkjG";
|
|
37078
|
-
const tracesSampleRate = Number(process.env.SENTRY_TRACES_SAMPLE_RATE) ||
|
|
37079
|
-
const profilesSampleRate = Number(process.env.SENTRY_PROFILES_SAMPLE_RATE) || 0.
|
|
37078
|
+
const tracesSampleRate = Number(process.env.SENTRY_TRACES_SAMPLE_RATE) || 0.2;
|
|
37079
|
+
const profilesSampleRate = Number(process.env.SENTRY_PROFILES_SAMPLE_RATE) || 0.1;
|
|
37080
37080
|
const sentryEnabled = runtimeEnv !== "dev" && true;
|
|
37081
37081
|
const postHogEnabled = runtimeEnv !== "dev" && process.env.LODY_POSTHOG_DISABLED !== "1";
|
|
37082
37082
|
const release = `${name}@${version$4}`;
|
|
@@ -64608,16 +64608,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
64608
64608
|
}
|
|
64609
64609
|
return _v4(options, buf, offset2);
|
|
64610
64610
|
}
|
|
64611
|
-
let LODY_AUTH_URL = "https://
|
|
64611
|
+
let LODY_AUTH_URL = "https://nautical-curlew-181.convex.cloud";
|
|
64612
64612
|
let LODY_AUTH_SITE_URL = "";
|
|
64613
|
-
let LODY_SERVER_URL = "https://lody
|
|
64614
|
-
let SITE_URL = "https://
|
|
64613
|
+
let LODY_SERVER_URL = "https://api.lody.ai";
|
|
64614
|
+
let SITE_URL = "https://lody.ai";
|
|
64615
64615
|
let SITE_APP_BASE_PATH = "";
|
|
64616
64616
|
const loadEnv = () => {
|
|
64617
|
-
LODY_AUTH_URL = "https://
|
|
64617
|
+
LODY_AUTH_URL = "https://nautical-curlew-181.convex.cloud";
|
|
64618
64618
|
LODY_AUTH_SITE_URL = "";
|
|
64619
|
-
LODY_SERVER_URL = "https://lody
|
|
64620
|
-
SITE_URL = "https://
|
|
64619
|
+
LODY_SERVER_URL = "https://api.lody.ai";
|
|
64620
|
+
SITE_URL = "https://lody.ai";
|
|
64621
64621
|
SITE_APP_BASE_PATH = process.env["SITE_APP_BASE_PATH"] ?? "";
|
|
64622
64622
|
};
|
|
64623
64623
|
const MACHINE_ID_FILE_NAME = "machine-id";
|
|
@@ -82846,7 +82846,6 @@ ${tailedOutput}` : null;
|
|
|
82846
82846
|
const LODY_PRESENCE_CHANNEL = "presence";
|
|
82847
82847
|
const LODY_PRESENCE_TTL_MS = 6e4;
|
|
82848
82848
|
const LODY_PRESENCE_HEARTBEAT_MS = 2e4;
|
|
82849
|
-
const LODY_PRESENCE_STREAM_HEARTBEAT_MS = 15e3;
|
|
82850
82849
|
const ActiveSessionStatusSchema = discriminatedUnion("type", [
|
|
82851
82850
|
object({
|
|
82852
82851
|
type: literal("running")
|
|
@@ -91165,7 +91164,8 @@ ${val.stack}`;
|
|
|
91165
91164
|
const requestUrl = this.subresourceEndpoint("/bootstrap");
|
|
91166
91165
|
const response = await this.http.fetchAuthorized(requestUrl, {
|
|
91167
91166
|
method: "GET",
|
|
91168
|
-
headers: this.mergeHeaders(input2.headers)
|
|
91167
|
+
headers: this.mergeHeaders(input2.headers),
|
|
91168
|
+
signal: input2.signal
|
|
91169
91169
|
}, this.timeoutConfig.connectTimeoutMs, "connect");
|
|
91170
91170
|
if (!response.ok) return {
|
|
91171
91171
|
ok: false,
|
|
@@ -92711,8 +92711,10 @@ stream:${scope2.streamId}`;
|
|
|
92711
92711
|
}
|
|
92712
92712
|
};
|
|
92713
92713
|
}
|
|
92714
|
-
async bootstrap() {
|
|
92715
|
-
const result = await this.client.bootstrap(
|
|
92714
|
+
async bootstrap(signal) {
|
|
92715
|
+
const result = await this.client.bootstrap({
|
|
92716
|
+
signal
|
|
92717
|
+
});
|
|
92716
92718
|
if (!result.ok) throw this.toTransportFailure(result.result);
|
|
92717
92719
|
return {
|
|
92718
92720
|
nextOffset: result.result.nextOffset,
|
|
@@ -93097,7 +93099,6 @@ stream:${scope2.streamId}`;
|
|
|
93097
93099
|
adaptor;
|
|
93098
93100
|
client;
|
|
93099
93101
|
reconnectConfig;
|
|
93100
|
-
heartbeatMs;
|
|
93101
93102
|
debug;
|
|
93102
93103
|
joinState;
|
|
93103
93104
|
constructor(options) {
|
|
@@ -93107,7 +93108,6 @@ stream:${scope2.streamId}`;
|
|
|
93107
93108
|
...DEFAULT_RECONNECT_CONFIG,
|
|
93108
93109
|
...options.reconnectConfig
|
|
93109
93110
|
};
|
|
93110
|
-
this.heartbeatMs = options.heartbeatMs ?? 15e3;
|
|
93111
93111
|
this.debug = options.debug ?? false;
|
|
93112
93112
|
this.client = new StreamsTransportClient({
|
|
93113
93113
|
streamUrl: options.streamUrl,
|
|
@@ -93188,18 +93188,15 @@ stream:${scope2.streamId}`;
|
|
|
93188
93188
|
};
|
|
93189
93189
|
}
|
|
93190
93190
|
async startJoin(state2) {
|
|
93191
|
+
state2.unsubscribeLocal = this.adaptor.subscribeLocalUpdates((update2) => {
|
|
93192
|
+
this.enqueueLocal(state2, normalizeEphemeralUpdate(update2));
|
|
93193
|
+
});
|
|
93191
93194
|
state2.requestController = new AbortController();
|
|
93192
93195
|
const firstOpen = this.waitForFirstOpen(state2);
|
|
93193
93196
|
this.runReadLoop(state2);
|
|
93194
93197
|
await firstOpen;
|
|
93195
93198
|
if (state2.closed) return;
|
|
93196
|
-
state2.unsubscribeLocal = this.adaptor.subscribeLocalUpdates((update2) => {
|
|
93197
|
-
this.enqueueLocal(state2, normalizeEphemeralUpdate(update2));
|
|
93198
|
-
});
|
|
93199
93199
|
this.setWriteStatus(state2, "ok");
|
|
93200
|
-
const fullState = normalizeEphemeralUpdate(await this.adaptor.encodeAll());
|
|
93201
|
-
if (fullState != null) state2.pendingLocal.pushBack(fullState);
|
|
93202
|
-
this.startHeartbeat(state2);
|
|
93203
93200
|
await this.flushPendingLocal(state2);
|
|
93204
93201
|
if (state2.status === "error" || state2.status === "disconnected") throw new Error(`ephemeral stream failed to join: ${state2.status}`);
|
|
93205
93202
|
}
|
|
@@ -93257,7 +93254,6 @@ stream:${scope2.streamId}`;
|
|
|
93257
93254
|
if (state2.closed) return;
|
|
93258
93255
|
state2.closed = true;
|
|
93259
93256
|
state2.unsubscribeLocal?.();
|
|
93260
|
-
if (state2.heartbeatTimer != null) clearInterval(state2.heartbeatTimer);
|
|
93261
93257
|
state2.requestController?.abort();
|
|
93262
93258
|
state2.retrySleepController.abort();
|
|
93263
93259
|
this.rejectFirstOpen(state2, closedSubscriptionError());
|
|
@@ -93285,7 +93281,6 @@ stream:${scope2.streamId}`;
|
|
|
93285
93281
|
]);
|
|
93286
93282
|
this.setReadStatus(state2, "ok");
|
|
93287
93283
|
this.resolveFirstOpen(state2);
|
|
93288
|
-
if (state2.unsubscribeLocal != null) this.enqueueFullState(state2);
|
|
93289
93284
|
}, async (update2) => {
|
|
93290
93285
|
if (update2.byteLength > 0) await this.adaptor.applyRemoteUpdates([
|
|
93291
93286
|
update2
|
|
@@ -93333,27 +93328,10 @@ stream:${scope2.streamId}`;
|
|
|
93333
93328
|
}
|
|
93334
93329
|
}
|
|
93335
93330
|
}
|
|
93336
|
-
startHeartbeat(state2) {
|
|
93337
|
-
if (this.heartbeatMs === false || this.heartbeatMs <= 0) return;
|
|
93338
|
-
state2.heartbeatTimer = setInterval(() => {
|
|
93339
|
-
this.enqueueFullState(state2);
|
|
93340
|
-
}, this.heartbeatMs);
|
|
93341
|
-
}
|
|
93342
|
-
async enqueueFullState(state2) {
|
|
93343
|
-
try {
|
|
93344
|
-
const update2 = await this.adaptor.encodeAll();
|
|
93345
|
-
this.enqueueLocal(state2, normalizeEphemeralUpdate(update2));
|
|
93346
|
-
} catch (error2) {
|
|
93347
|
-
this.logError("ephemeral encodeAll failed", error2, {
|
|
93348
|
-
streamUrl: this.streamUrl
|
|
93349
|
-
});
|
|
93350
|
-
this.setWriteStatus(state2, "error");
|
|
93351
|
-
}
|
|
93352
|
-
}
|
|
93353
93331
|
enqueueLocal(state2, update2) {
|
|
93354
93332
|
if (state2.closed || update2 == null || update2.byteLength === 0) return;
|
|
93355
93333
|
state2.pendingLocal.pushBack(update2);
|
|
93356
|
-
this.flushPendingLocal(state2);
|
|
93334
|
+
if (state2.writeStatus !== "connecting") this.flushPendingLocal(state2);
|
|
93357
93335
|
}
|
|
93358
93336
|
async flushPendingLocal(state2) {
|
|
93359
93337
|
if (state2.flushingLocal || state2.closed) return;
|
|
@@ -94115,7 +94093,7 @@ stream:${scope2.streamId}`;
|
|
|
94115
94093
|
async startJoin(state2) {
|
|
94116
94094
|
try {
|
|
94117
94095
|
state2.requestController ??= new AbortController();
|
|
94118
|
-
const joined = await this.performInitialJoinSync(state2.liveMode);
|
|
94096
|
+
const joined = await this.performInitialJoinSync(state2.liveMode, state2.requestController?.signal);
|
|
94119
94097
|
state2.cursor = joined.cursor;
|
|
94120
94098
|
state2.streamCursor = joined.streamCursor;
|
|
94121
94099
|
state2.liveMode = joined.liveMode;
|
|
@@ -94158,8 +94136,8 @@ stream:${scope2.streamId}`;
|
|
|
94158
94136
|
}
|
|
94159
94137
|
return cursor;
|
|
94160
94138
|
}
|
|
94161
|
-
async performInitialJoinSync(preferredLiveMode) {
|
|
94162
|
-
const initial = await this.finalizeDirectLocalAppendIfNeeded(await this.resolveInitialRemoteState());
|
|
94139
|
+
async performInitialJoinSync(preferredLiveMode, signal) {
|
|
94140
|
+
const initial = await this.finalizeDirectLocalAppendIfNeeded(await this.resolveInitialRemoteState(signal));
|
|
94163
94141
|
let cursor = initial.cursor;
|
|
94164
94142
|
let localExportRefVersion = cursor.serverLowerBoundVersion;
|
|
94165
94143
|
let streamCursor = initial.streamCursor;
|
|
@@ -94168,7 +94146,7 @@ stream:${scope2.streamId}`;
|
|
|
94168
94146
|
localExportRefVersion = exportedLocal.nextRefVersion;
|
|
94169
94147
|
if (exportedLocal.batch != null) {
|
|
94170
94148
|
cursor = await this.appendLocalBatch(cursor, exportedLocal.batch);
|
|
94171
|
-
const caughtUp = await this.catchup(cursor);
|
|
94149
|
+
const caughtUp = await this.catchup(cursor, void 0, void 0, void 0, signal);
|
|
94172
94150
|
cursor = caughtUp.cursor;
|
|
94173
94151
|
streamCursor = caughtUp.streamCursor;
|
|
94174
94152
|
}
|
|
@@ -94187,31 +94165,37 @@ stream:${scope2.streamId}`;
|
|
|
94187
94165
|
serverLowerBoundVersion: this.adapter.emptyVersion()
|
|
94188
94166
|
});
|
|
94189
94167
|
}
|
|
94190
|
-
async resolveInitialRemoteState() {
|
|
94168
|
+
async resolveInitialRemoteState(signal) {
|
|
94191
94169
|
const loaded = await this.remoteCursorStore.load(this.streamUrl);
|
|
94192
94170
|
const cursor = loaded ?? this.createInitialCursor();
|
|
94193
94171
|
try {
|
|
94194
|
-
if (loaded == null) return await this.bootstrapState(cursor
|
|
94172
|
+
if (loaded == null) return await this.bootstrapState(cursor, {
|
|
94173
|
+
signal
|
|
94174
|
+
});
|
|
94195
94175
|
const caughtUp = await this.catchupOrGone(cursor, {
|
|
94196
|
-
goneStrategy: "return-gone"
|
|
94176
|
+
goneStrategy: "return-gone",
|
|
94177
|
+
signal
|
|
94197
94178
|
});
|
|
94198
|
-
if ("kind" in caughtUp) return await this.recoverFromGoneWithLocalBootstrap(cursor);
|
|
94179
|
+
if ("kind" in caughtUp) return await this.recoverFromGoneWithLocalBootstrap(cursor, signal);
|
|
94199
94180
|
return caughtUp;
|
|
94200
94181
|
} catch (error2) {
|
|
94201
94182
|
if (!isStreamNotFoundError(error2) || !this.createStreamIfMissing) throw error2;
|
|
94202
94183
|
await this.ensureStreamExists();
|
|
94203
|
-
return await this.bootstrapState(this.createInitialCursor()
|
|
94184
|
+
return await this.bootstrapState(this.createInitialCursor(), {
|
|
94185
|
+
signal
|
|
94186
|
+
});
|
|
94204
94187
|
}
|
|
94205
94188
|
}
|
|
94206
94189
|
async bootstrapState(cursor, options = {}) {
|
|
94207
94190
|
const cursorManager = options.cursorManager ?? this.cursorManager;
|
|
94208
|
-
const result = await this.client.bootstrap();
|
|
94191
|
+
const result = await this.client.bootstrap(options.signal);
|
|
94209
94192
|
let saved = await cursorManager.applyBootstrapPayload(cursor, result.snapshot, result.updates, result.nextOffset);
|
|
94210
94193
|
let bootstrapCursor = result.streamCursor;
|
|
94211
94194
|
if (!result.upToDate) {
|
|
94212
94195
|
const caughtUp = await this.catchupOrGone(saved, {
|
|
94213
94196
|
streamCursor: bootstrapCursor,
|
|
94214
|
-
cursorManager
|
|
94197
|
+
cursorManager,
|
|
94198
|
+
signal: options.signal
|
|
94215
94199
|
});
|
|
94216
94200
|
if ("kind" in caughtUp) throw new Error("bootstrap catch-up unexpectedly returned gone");
|
|
94217
94201
|
saved = caughtUp.cursor;
|
|
@@ -94222,11 +94206,12 @@ stream:${scope2.streamId}`;
|
|
|
94222
94206
|
streamCursor: bootstrapCursor
|
|
94223
94207
|
};
|
|
94224
94208
|
}
|
|
94225
|
-
async catchup(cursor, live, streamCursor, onRemoteVersionApplied) {
|
|
94209
|
+
async catchup(cursor, live, streamCursor, onRemoteVersionApplied, signal) {
|
|
94226
94210
|
const result = await this.catchupOrGone(cursor, {
|
|
94227
94211
|
live,
|
|
94228
94212
|
streamCursor,
|
|
94229
|
-
onRemoteVersionApplied
|
|
94213
|
+
onRemoteVersionApplied,
|
|
94214
|
+
signal
|
|
94230
94215
|
});
|
|
94231
94216
|
if ("kind" in result) throw new Error("catchup unexpectedly returned gone");
|
|
94232
94217
|
return result;
|
|
@@ -94238,7 +94223,7 @@ stream:${scope2.streamId}`;
|
|
|
94238
94223
|
const cursorManager = options.cursorManager ?? this.cursorManager;
|
|
94239
94224
|
while (true) {
|
|
94240
94225
|
const requestOffset = current2.nextOffset;
|
|
94241
|
-
const response = await this.client.readFromOffset(requestOffset, currentStreamCursor, options.live);
|
|
94226
|
+
const response = await this.client.readFromOffset(requestOffset, currentStreamCursor, options.live, options.signal);
|
|
94242
94227
|
if (response.kind === "gone") {
|
|
94243
94228
|
if (goneStrategy === "return-gone") return StreamsCrdt2.GONE_CATCHUP;
|
|
94244
94229
|
return await this.bootstrapState({
|
|
@@ -94246,7 +94231,8 @@ stream:${scope2.streamId}`;
|
|
|
94246
94231
|
nextOffset: "-1",
|
|
94247
94232
|
serverLowerBoundVersion: this.adapter.emptyVersion()
|
|
94248
94233
|
}, {
|
|
94249
|
-
cursorManager
|
|
94234
|
+
cursorManager,
|
|
94235
|
+
signal: options.signal
|
|
94250
94236
|
});
|
|
94251
94237
|
}
|
|
94252
94238
|
const result = response.value;
|
|
@@ -94413,9 +94399,10 @@ stream:${scope2.streamId}`;
|
|
|
94413
94399
|
if (isolated == null) return null;
|
|
94414
94400
|
return this.createCursorManager(isolated, async (cursor) => cursor);
|
|
94415
94401
|
}
|
|
94416
|
-
async inferRemoteAndAppendLocal(bootstrapCursor, cursorManager) {
|
|
94402
|
+
async inferRemoteAndAppendLocal(bootstrapCursor, cursorManager, signal) {
|
|
94417
94403
|
const inferredRemote = await this.bootstrapState(bootstrapCursor, {
|
|
94418
|
-
cursorManager
|
|
94404
|
+
cursorManager,
|
|
94405
|
+
signal
|
|
94419
94406
|
});
|
|
94420
94407
|
let pendingAppend;
|
|
94421
94408
|
if (this.frozenLocalAppend != null) {
|
|
@@ -94425,23 +94412,26 @@ stream:${scope2.streamId}`;
|
|
|
94425
94412
|
const localBatch = this.exportUpdates(inferredRemote.cursor.serverLowerBoundVersion);
|
|
94426
94413
|
if (localBatch.batch != null) pendingAppend = await this.appendLocalBatchRemote(inferredRemote.cursor, localBatch.batch);
|
|
94427
94414
|
}
|
|
94428
|
-
const result = await this.bootstrapState(bootstrapCursor
|
|
94415
|
+
const result = await this.bootstrapState(bootstrapCursor, {
|
|
94416
|
+
signal
|
|
94417
|
+
});
|
|
94429
94418
|
if (pendingAppend != null) this.commitProducerAck(pendingAppend.producerAck);
|
|
94430
94419
|
return result;
|
|
94431
94420
|
}
|
|
94432
|
-
async recoverFromGoneWithLocalBootstrap(cursor) {
|
|
94421
|
+
async recoverFromGoneWithLocalBootstrap(cursor, signal) {
|
|
94433
94422
|
const isolatedCursorManager = await this.createIsolatedCursorManager();
|
|
94434
94423
|
const bootstrapCursor = {
|
|
94435
94424
|
...cursor,
|
|
94436
94425
|
nextOffset: "-1",
|
|
94437
94426
|
serverLowerBoundVersion: this.adapter.emptyVersion()
|
|
94438
94427
|
};
|
|
94439
|
-
if (isolatedCursorManager != null) return await this.inferRemoteAndAppendLocal(bootstrapCursor, isolatedCursorManager);
|
|
94428
|
+
if (isolatedCursorManager != null) return await this.inferRemoteAndAppendLocal(bootstrapCursor, isolatedCursorManager, signal);
|
|
94440
94429
|
const preservedLocalSnapshot = this.adapter.exportSnapshot();
|
|
94441
94430
|
let restoredLocalSnapshot = false;
|
|
94442
94431
|
try {
|
|
94443
94432
|
const inferredRemote = await this.bootstrapState(bootstrapCursor, {
|
|
94444
|
-
cursorManager: this.volatileCursorManager
|
|
94433
|
+
cursorManager: this.volatileCursorManager,
|
|
94434
|
+
signal
|
|
94445
94435
|
});
|
|
94446
94436
|
await this.adapter.applySnapshot(preservedLocalSnapshot);
|
|
94447
94437
|
restoredLocalSnapshot = true;
|
|
@@ -94453,7 +94443,9 @@ stream:${scope2.streamId}`;
|
|
|
94453
94443
|
const localBatch = this.exportUpdates(inferredRemote.cursor.serverLowerBoundVersion);
|
|
94454
94444
|
if (localBatch.batch != null) pendingAppend = await this.appendLocalBatchRemote(inferredRemote.cursor, localBatch.batch);
|
|
94455
94445
|
}
|
|
94456
|
-
const result = await this.bootstrapState(bootstrapCursor
|
|
94446
|
+
const result = await this.bootstrapState(bootstrapCursor, {
|
|
94447
|
+
signal
|
|
94448
|
+
});
|
|
94457
94449
|
if (pendingAppend != null) this.commitProducerAck(pendingAppend.producerAck);
|
|
94458
94450
|
return result;
|
|
94459
94451
|
} catch (error2) {
|
|
@@ -94490,6 +94482,8 @@ stream:${scope2.streamId}`;
|
|
|
94490
94482
|
...state2.cursor,
|
|
94491
94483
|
nextOffset: "-1",
|
|
94492
94484
|
serverLowerBoundVersion: this.adapter.emptyVersion()
|
|
94485
|
+
}, {
|
|
94486
|
+
signal: capturedController?.signal
|
|
94493
94487
|
});
|
|
94494
94488
|
state2.cursor = bootstrapped2.cursor;
|
|
94495
94489
|
state2.streamCursor = bootstrapped2.streamCursor;
|
|
@@ -94962,12 +94956,25 @@ stream:${scope2.streamId}`;
|
|
|
94962
94956
|
};
|
|
94963
94957
|
}
|
|
94964
94958
|
function EphemeralStoreAdaptor(store) {
|
|
94959
|
+
let applyingRemoteDepth = 0;
|
|
94965
94960
|
return {
|
|
94966
|
-
encodeAll: () => store.encodeAll(),
|
|
94967
94961
|
applyRemoteUpdates: (updates) => {
|
|
94968
|
-
|
|
94962
|
+
applyingRemoteDepth += 1;
|
|
94963
|
+
try {
|
|
94964
|
+
for (const update2 of updates) store.apply(update2);
|
|
94965
|
+
} finally {
|
|
94966
|
+
applyingRemoteDepth -= 1;
|
|
94967
|
+
}
|
|
94969
94968
|
},
|
|
94970
|
-
subscribeLocalUpdates: (listener) =>
|
|
94969
|
+
subscribeLocalUpdates: (listener) => {
|
|
94970
|
+
const unsubscribeLocalUpdates = store.subscribeLocalUpdates((update2) => {
|
|
94971
|
+
if (applyingRemoteDepth > 0) return;
|
|
94972
|
+
listener(update2);
|
|
94973
|
+
});
|
|
94974
|
+
return () => {
|
|
94975
|
+
unsubscribeLocalUpdates();
|
|
94976
|
+
};
|
|
94977
|
+
}
|
|
94971
94978
|
};
|
|
94972
94979
|
}
|
|
94973
94980
|
function isAfter(entry2, current2) {
|
|
@@ -95862,8 +95869,7 @@ stream:${scope2.streamId}`;
|
|
|
95862
95869
|
this.transport = new EphemeralStreamCrdt({
|
|
95863
95870
|
streamUrl: toLodyPresenceStreamUrl(durableStreamUrl),
|
|
95864
95871
|
auth: options.auth,
|
|
95865
|
-
adaptor: EphemeralStoreAdaptor(this.store)
|
|
95866
|
-
heartbeatMs: LODY_PRESENCE_STREAM_HEARTBEAT_MS
|
|
95872
|
+
adaptor: EphemeralStoreAdaptor(this.store)
|
|
95867
95873
|
});
|
|
95868
95874
|
this.machineTimer = setInterval(() => {
|
|
95869
95875
|
this.writeMachineHeartbeat();
|
|
@@ -114202,7 +114208,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
114202
114208
|
const agent = proxyUrl ? new distExports.HttpsProxyAgent(proxyUrl) : void 0;
|
|
114203
114209
|
const logger2 = getLogger("loro:websocket");
|
|
114204
114210
|
logger2.debug(`Creating WebSocket url=${sanitizeUrlForLogging(urlString)} proxy=${proxyUrl ? redactProxyUrl(proxyUrl) : "none"} agentValid=${!!agent}`);
|
|
114205
|
-
if (
|
|
114211
|
+
if (globalThis.Bun && proxyUrl) {
|
|
114206
114212
|
logger2.debug("Bun does not support WebSocket proxy yet: https://github.com/oven-sh/bun/issues/14522");
|
|
114207
114213
|
}
|
|
114208
114214
|
super(urlString, protocols, {
|
|
@@ -115713,12 +115719,12 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
115713
115719
|
}));
|
|
115714
115720
|
return result.nextOffset;
|
|
115715
115721
|
},
|
|
115716
|
-
longPollJson: async (streamId, state2,
|
|
115722
|
+
longPollJson: async (streamId, state2, readOptions) => {
|
|
115717
115723
|
const result = unwrapStreamResult("long-poll stream", streamId, await getStreamClient(streamId).readOnce({
|
|
115718
115724
|
offset: state2.nextOffset ?? "now",
|
|
115719
115725
|
cursor: state2.cursor,
|
|
115720
115726
|
live: "long-poll",
|
|
115721
|
-
signal:
|
|
115727
|
+
signal: readOptions?.signal
|
|
115722
115728
|
}));
|
|
115723
115729
|
return {
|
|
115724
115730
|
messages: result.payload === null ? [] : parseJsonBatchPayload(result.payload, streamId, "long-poll read"),
|
|
@@ -115727,13 +115733,13 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
115727
115733
|
upToDate: result.upToDate
|
|
115728
115734
|
};
|
|
115729
115735
|
},
|
|
115730
|
-
readJsonLive: async (streamId, state2, onBatch,
|
|
115736
|
+
readJsonLive: async (streamId, state2, onBatch, liveOptions) => {
|
|
115731
115737
|
const pendingMessages = [];
|
|
115732
115738
|
const streamClient = getStreamClient(streamId);
|
|
115733
115739
|
for await (const event of streamClient.live({
|
|
115734
115740
|
offset: state2.nextOffset ?? "now",
|
|
115735
115741
|
mode: "auto",
|
|
115736
|
-
signal:
|
|
115742
|
+
signal: liveOptions?.signal
|
|
115737
115743
|
})) {
|
|
115738
115744
|
switch (event.type) {
|
|
115739
115745
|
case "data":
|
|
@@ -117329,7 +117335,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
117329
117335
|
throw err2;
|
|
117330
117336
|
}
|
|
117331
117337
|
logger2.debug(`[${sessionId}] ${operationName} failed after ${attempt + 1} attempt(s) with transport error: ${formatErrorMessage(err2)}`);
|
|
117332
|
-
reportError(`agent-client:${operationName}`, err2 instanceof Error ? err2 : new Error(String(err2)));
|
|
117338
|
+
void reportError(`agent-client:${operationName}`, err2 instanceof Error ? err2 : new Error(String(err2)));
|
|
117333
117339
|
return void 0;
|
|
117334
117340
|
}
|
|
117335
117341
|
}
|
|
@@ -118931,6 +118937,7 @@ ${this.stack.split("\n").slice(1).join("\n")}` : this.toString();
|
|
|
118931
118937
|
case "idle":
|
|
118932
118938
|
return "idle";
|
|
118933
118939
|
}
|
|
118940
|
+
return "unknown";
|
|
118934
118941
|
};
|
|
118935
118942
|
class SessionHeartbeat {
|
|
118936
118943
|
constructor(sessionId, workspaceDocument, logger2, options = {}) {
|
|
@@ -120749,11 +120756,7 @@ path=/${options.repoFullName}.git
|
|
|
120749
120756
|
});
|
|
120750
120757
|
}
|
|
120751
120758
|
async function fetchAcpCapabilities(cliType, agentType, logger2, env2) {
|
|
120752
|
-
const
|
|
120753
|
-
const workdir = path__default.join(os__default.tmpdir(), "lody-acp-capabilities", `${cliType}-${safeAgentType}`);
|
|
120754
|
-
fs__default.mkdirSync(workdir, {
|
|
120755
|
-
recursive: true
|
|
120756
|
-
});
|
|
120759
|
+
const workdir = process.cwd();
|
|
120757
120760
|
let capturedCommands;
|
|
120758
120761
|
let commandsResolve;
|
|
120759
120762
|
const commandsPromise = new Promise((resolve2) => {
|
|
@@ -121905,91 +121908,94 @@ $mem | ConvertTo-Json -Compress
|
|
|
121905
121908
|
const runtime = this.createTurnRuntime(sessionId, turnId, userTurnId, session);
|
|
121906
121909
|
this.registerTurnRuntime(runtime);
|
|
121907
121910
|
const self2 = this;
|
|
121908
|
-
const program2 = scoped(acquireRelease(succeed(runtime), (
|
|
121911
|
+
const program2 = scoped(acquireRelease(succeed(runtime), (turnRuntime, exit2) => gen(function* () {
|
|
121909
121912
|
const wasInterrupted = isFailure(exit2) && isInterrupted(exit2.cause);
|
|
121910
|
-
const wasCancelled =
|
|
121913
|
+
const wasCancelled = turnRuntime.cancelRequested || self2.isTurnCancelled(sessionId, turnRuntime.turnId) || wasInterrupted;
|
|
121911
121914
|
if (wasCancelled) {
|
|
121912
121915
|
yield* self2.finalizeCancelledTurnEffect({
|
|
121913
121916
|
sessionId,
|
|
121914
121917
|
sessionDoc,
|
|
121915
|
-
turnId:
|
|
121918
|
+
turnId: turnRuntime.turnId,
|
|
121916
121919
|
userTurnId,
|
|
121917
|
-
session:
|
|
121918
|
-
pendingSession:
|
|
121919
|
-
terminateSession:
|
|
121920
|
-
reportTurnError: self2.shouldReportCancelledTurnError(
|
|
121920
|
+
session: turnRuntime.session,
|
|
121921
|
+
pendingSession: turnRuntime.pendingSession,
|
|
121922
|
+
terminateSession: turnRuntime.terminateSessionOnCancel,
|
|
121923
|
+
reportTurnError: self2.shouldReportCancelledTurnError(turnRuntime)
|
|
121921
121924
|
});
|
|
121922
121925
|
}
|
|
121923
|
-
self2.releaseTurnRuntime(sessionId,
|
|
121924
|
-
})).pipe(flatMap$1((
|
|
121925
|
-
yield* self2.tryPromise(() => self2.deps.createAssistantEntryForTurn(sessionId, sessionDoc,
|
|
121926
|
+
self2.releaseTurnRuntime(sessionId, turnRuntime.turnId);
|
|
121927
|
+
})).pipe(flatMap$1((turnRuntime) => gen(function* () {
|
|
121928
|
+
yield* self2.tryPromise(() => self2.deps.createAssistantEntryForTurn(sessionId, sessionDoc, turnRuntime.turnId, turnRuntime.session?.agentClient?.currentModel, userTurnId));
|
|
121926
121929
|
yield* self2.acquireSessionHeartbeat(sessionId);
|
|
121927
121930
|
if (userTurnId) {
|
|
121928
121931
|
yield* self2.tryPromise(() => self2.setDispatchProcessing(sessionId, sessionDoc, userTurnId));
|
|
121929
121932
|
}
|
|
121930
121933
|
const bindSession = (nextSession) => {
|
|
121931
|
-
|
|
121932
|
-
|
|
121934
|
+
runtime.session = nextSession;
|
|
121935
|
+
runtime.pendingSession = void 0;
|
|
121933
121936
|
};
|
|
121934
121937
|
const trackPendingSession = (pendingSession, pendingOptions) => gen(function* () {
|
|
121935
121938
|
const pending2 = yield* try_({
|
|
121936
121939
|
try: () => typeof pendingSession === "function" ? pendingSession() : pendingSession,
|
|
121937
121940
|
catch: (error2) => error2
|
|
121938
121941
|
});
|
|
121939
|
-
|
|
121942
|
+
runtime.pendingSession = pending2;
|
|
121940
121943
|
if (pendingOptions?.terminateOnCancel) {
|
|
121941
|
-
|
|
121944
|
+
runtime.terminateSessionOnCancel = true;
|
|
121942
121945
|
}
|
|
121943
121946
|
return yield* self2.tryPromise(() => pending2);
|
|
121944
121947
|
});
|
|
121945
121948
|
const abortIfCancelled = (cancelOptions) => gen(function* () {
|
|
121946
121949
|
if (cancelOptions?.terminateSession) {
|
|
121947
|
-
|
|
121950
|
+
runtime.terminateSessionOnCancel = true;
|
|
121948
121951
|
}
|
|
121949
121952
|
const userTurnWasCancelled = yield* self2.tryPromise(() => self2.isUserTurnCancelled(sessionDoc, userTurnId));
|
|
121950
|
-
if (!
|
|
121951
|
-
return;
|
|
121953
|
+
if (!runtime.cancelRequested && !self2.isTurnCancelled(sessionId, runtime.turnId) && !userTurnWasCancelled) {
|
|
121954
|
+
return void 0;
|
|
121952
121955
|
}
|
|
121953
121956
|
yield* self2.finalizeCancelledTurnEffect({
|
|
121954
121957
|
sessionId,
|
|
121955
121958
|
sessionDoc,
|
|
121956
|
-
turnId:
|
|
121959
|
+
turnId: runtime.turnId,
|
|
121957
121960
|
userTurnId,
|
|
121958
|
-
session:
|
|
121959
|
-
pendingSession:
|
|
121960
|
-
terminateSession: cancelOptions?.terminateSession ??
|
|
121961
|
-
reportTurnError: self2.shouldReportCancelledTurnError(
|
|
121961
|
+
session: runtime.session,
|
|
121962
|
+
pendingSession: runtime.pendingSession,
|
|
121963
|
+
terminateSession: cancelOptions?.terminateSession ?? runtime.terminateSessionOnCancel,
|
|
121964
|
+
reportTurnError: self2.shouldReportCancelledTurnError(runtime)
|
|
121962
121965
|
});
|
|
121963
|
-
|
|
121966
|
+
yield* fail(new SessionTurnCancelled({
|
|
121964
121967
|
sessionId,
|
|
121965
|
-
turnId:
|
|
121968
|
+
turnId: runtime.turnId
|
|
121966
121969
|
}));
|
|
121970
|
+
return void 0;
|
|
121967
121971
|
});
|
|
121968
|
-
const patchAssistantEntry = () => self2.tryPromise(() => self2.deps.createAssistantEntryForTurn(sessionId, sessionDoc,
|
|
121972
|
+
const patchAssistantEntry = () => self2.tryPromise(() => self2.deps.createAssistantEntryForTurn(sessionId, sessionDoc, runtime.turnId, runtime.session?.agentClient?.currentModel, userTurnId));
|
|
121969
121973
|
const prompt2 = (promptBlocks) => gen(function* () {
|
|
121970
|
-
const activeSession =
|
|
121974
|
+
const activeSession = runtime.session;
|
|
121971
121975
|
const agentClient = activeSession?.agentClient;
|
|
121972
121976
|
const acpSessionId = activeSession?.acpSessionId;
|
|
121973
121977
|
if (!agentClient || !acpSessionId) {
|
|
121974
|
-
|
|
121978
|
+
yield* fail(new Error("Agent session was not ready"));
|
|
121979
|
+
return void 0;
|
|
121975
121980
|
}
|
|
121976
|
-
|
|
121977
|
-
|
|
121981
|
+
runtime.terminateSessionOnCancel = false;
|
|
121982
|
+
runtime.promptStarted = true;
|
|
121978
121983
|
yield* acquireUseRelease(sync(() => {
|
|
121979
|
-
|
|
121984
|
+
runtime.promptInFlight = true;
|
|
121980
121985
|
return activeSession;
|
|
121981
121986
|
}), () => self2.tryPromise((signal) => agentClient.prompt(acpSessionId, promptBlocks, {
|
|
121982
121987
|
signal
|
|
121983
121988
|
})).pipe(catchAll((error2) => sync(() => {
|
|
121984
|
-
|
|
121989
|
+
runtime.promptFailed = true;
|
|
121985
121990
|
}).pipe(flatMap$1(() => fail(error2))))), () => sync(() => {
|
|
121986
|
-
|
|
121991
|
+
runtime.promptInFlight = false;
|
|
121987
121992
|
}));
|
|
121988
|
-
self2.deps.clearActiveTurnId(sessionId,
|
|
121993
|
+
self2.deps.clearActiveTurnId(sessionId, runtime.turnId);
|
|
121994
|
+
return void 0;
|
|
121989
121995
|
});
|
|
121990
121996
|
yield* body({
|
|
121991
|
-
turnId:
|
|
121992
|
-
runtime
|
|
121997
|
+
turnId: runtime.turnId,
|
|
121998
|
+
runtime,
|
|
121993
121999
|
bindSession,
|
|
121994
122000
|
trackPendingSession,
|
|
121995
122001
|
abortIfCancelled,
|
|
@@ -122662,7 +122668,8 @@ $mem | ConvertTo-Json -Compress
|
|
|
122662
122668
|
}, ({ turnId, runtime, bindSession, trackPendingSession, abortIfCancelled, patchAssistantEntry, prompt: prompt2 }) => gen(function* () {
|
|
122663
122669
|
yield* abortIfCancelled();
|
|
122664
122670
|
if (project?.kind === "local" && !workdir) {
|
|
122665
|
-
|
|
122671
|
+
yield* fail(new Error(`Local project not found in workspace: ${project.localProjectId}`));
|
|
122672
|
+
return void 0;
|
|
122666
122673
|
}
|
|
122667
122674
|
if (shouldPrepareWorktree) {
|
|
122668
122675
|
yield* self2.tryPromise(() => sessionDoc.setStatus(SessionStatusFactory.initializing("git-clone")));
|
|
@@ -122747,6 +122754,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
122747
122754
|
yield* abortIfCancelled();
|
|
122748
122755
|
self2.clearTurnCancellation(sessionId, turnId);
|
|
122749
122756
|
yield* self2.tryPromise(() => self2.deps.processMessageQueue(sessionId));
|
|
122757
|
+
return void 0;
|
|
122750
122758
|
}));
|
|
122751
122759
|
}
|
|
122752
122760
|
async cancelSession(message) {
|
|
@@ -123378,6 +123386,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
123378
123386
|
case "cli_token_invalid":
|
|
123379
123387
|
return "CLI token is invalid or has been revoked.";
|
|
123380
123388
|
}
|
|
123389
|
+
return "Machine access was denied.";
|
|
123381
123390
|
}
|
|
123382
123391
|
async markDispatchAccessDenied(sessionId, sessionDoc, userTurnId, reason) {
|
|
123383
123392
|
const message = this.getAccessDeniedMessage(reason);
|
|
@@ -124315,7 +124324,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
124315
124324
|
getActiveTurnId: (sessionId) => this.store.getActiveTurnId(sessionId),
|
|
124316
124325
|
clearActiveTurnId: (sessionId, turnId) => this.clearActiveTurnIdIfMatches(sessionId, turnId),
|
|
124317
124326
|
buildAcpPromptBlocks: async (args2) => await this.buildAcpPromptBlocks(args2),
|
|
124318
|
-
applyAcpModeAndModel: async (session,
|
|
124327
|
+
applyAcpModeAndModel: async (session, acpConfig) => await this.applyAcpModeAndModel(session, acpConfig),
|
|
124319
124328
|
createAssistantEntryForTurn: async (sessionId, sessionDoc, turnId, modelInfo, userTurnId) => await this.createAssistantEntryForTurn(sessionId, sessionDoc, turnId, modelInfo, userTurnId),
|
|
124320
124329
|
turnFinalization: {
|
|
124321
124330
|
finalizeACPState: async (sessionId) => await this.finalizeACPState(sessionId),
|
|
@@ -124620,7 +124629,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
124620
124629
|
trackPendingContextWindowPersist(sessionId, promise) {
|
|
124621
124630
|
const state2 = this.store.get(sessionId);
|
|
124622
124631
|
state2.pendingContextWindowHandlers.add(promise);
|
|
124623
|
-
promise.finally(() => {
|
|
124632
|
+
void promise.finally(() => {
|
|
124624
124633
|
state2.pendingContextWindowHandlers.delete(promise);
|
|
124625
124634
|
});
|
|
124626
124635
|
}
|
|
@@ -125088,7 +125097,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
125088
125097
|
}
|
|
125089
125098
|
}
|
|
125090
125099
|
setupSessionEventHandlers() {
|
|
125091
|
-
this.sessionManager.on("output",
|
|
125100
|
+
this.sessionManager.on("output", (output) => {
|
|
125092
125101
|
this.logger.debug(`Output from session [${output.sessionId}]: <${output.data.length} bytes>`);
|
|
125093
125102
|
});
|
|
125094
125103
|
this.sessionManager.on("onACPUpdateMessage", (sessionId, update2) => {
|
|
@@ -125098,53 +125107,59 @@ $mem | ConvertTo-Json -Compress
|
|
|
125098
125107
|
const promise = this.handleUsageUpdate(sessionId, acpSessionId, usage);
|
|
125099
125108
|
const usageState = this.store.get(sessionId);
|
|
125100
125109
|
usageState.pendingUsageHandlers.add(promise);
|
|
125101
|
-
promise.finally(() => {
|
|
125110
|
+
void promise.finally(() => {
|
|
125102
125111
|
usageState.pendingUsageHandlers.delete(promise);
|
|
125103
125112
|
});
|
|
125104
125113
|
});
|
|
125105
125114
|
this.sessionManager.on("onContextWindowUsageUpdate", (sessionId, usage) => {
|
|
125106
125115
|
this.enqueueContextWindowUsageUpdate(sessionId, usage);
|
|
125107
125116
|
});
|
|
125108
|
-
this.sessionManager.on("onRateLimitUpdate",
|
|
125109
|
-
|
|
125117
|
+
this.sessionManager.on("onRateLimitUpdate", (machineId, cliType, limits) => {
|
|
125118
|
+
void this.workspaceDocument.updateRateLimits(machineId, cliType, limits);
|
|
125110
125119
|
});
|
|
125111
|
-
this.sessionManager.on("error",
|
|
125112
|
-
|
|
125113
|
-
|
|
125114
|
-
|
|
125115
|
-
|
|
125116
|
-
|
|
125117
|
-
|
|
125118
|
-
|
|
125119
|
-
|
|
125120
|
+
this.sessionManager.on("error", (event) => {
|
|
125121
|
+
void (async () => {
|
|
125122
|
+
this.logger.error(`[${event.sessionId}] Session error event received:`, event);
|
|
125123
|
+
const sessionId = event.sessionId;
|
|
125124
|
+
this.stopMachineSessionHeartbeat(sessionId);
|
|
125125
|
+
await this.finalizeACPState(sessionId);
|
|
125126
|
+
await this.flushSessionUsage(sessionId);
|
|
125127
|
+
const sessionDoc = await this.workspaceDocument.getOrCreateSessionDoc(sessionId);
|
|
125128
|
+
await sessionDoc.setStatus(SessionStatusFactory.idle());
|
|
125129
|
+
this.logger.debug(`[${sessionId}] Status set to idle (via error event)`);
|
|
125130
|
+
})();
|
|
125120
125131
|
});
|
|
125121
|
-
this.sessionManager.on("exit",
|
|
125122
|
-
|
|
125123
|
-
|
|
125124
|
-
|
|
125125
|
-
this.
|
|
125126
|
-
|
|
125127
|
-
|
|
125128
|
-
|
|
125129
|
-
await this.finalizeACPState(sessionId);
|
|
125130
|
-
await this.flushSessionUsage(sessionId);
|
|
125131
|
-
const session = await this.workspaceDocument.getOrCreateSessionDoc(sessionId);
|
|
125132
|
-
await session.setStatus(SessionStatusFactory.idle());
|
|
125133
|
-
this.logger.debug(`[${sessionId}] Status set to idle (via exit event)`);
|
|
125134
|
-
});
|
|
125135
|
-
this.sessionManager.on("terminated", async (event) => {
|
|
125136
|
-
const sessionId = event.sessionId;
|
|
125137
|
-
if (!this.store.has(sessionId)) {
|
|
125138
|
-
this.logger.debug(`[${sessionId}] Ignoring terminated event for GC-cleaned session`);
|
|
125139
|
-
return;
|
|
125140
|
-
}
|
|
125141
|
-
try {
|
|
125132
|
+
this.sessionManager.on("exit", (exit2) => {
|
|
125133
|
+
void (async () => {
|
|
125134
|
+
const sessionId = exit2.sessionId;
|
|
125135
|
+
this.logger.debug(`[${sessionId}] Session exit event received (exitCode=${exit2.exitCode})`);
|
|
125136
|
+
if (!this.store.has(sessionId)) {
|
|
125137
|
+
this.logger.debug(`[${sessionId}] Ignoring exit event for GC-cleaned session`);
|
|
125138
|
+
return;
|
|
125139
|
+
}
|
|
125142
125140
|
this.stopMachineSessionHeartbeat(sessionId);
|
|
125143
125141
|
await this.finalizeACPState(sessionId);
|
|
125144
125142
|
await this.flushSessionUsage(sessionId);
|
|
125145
|
-
|
|
125146
|
-
|
|
125147
|
-
|
|
125143
|
+
const session = await this.workspaceDocument.getOrCreateSessionDoc(sessionId);
|
|
125144
|
+
await session.setStatus(SessionStatusFactory.idle());
|
|
125145
|
+
this.logger.debug(`[${sessionId}] Status set to idle (via exit event)`);
|
|
125146
|
+
})();
|
|
125147
|
+
});
|
|
125148
|
+
this.sessionManager.on("terminated", (event) => {
|
|
125149
|
+
void (async () => {
|
|
125150
|
+
const sessionId = event.sessionId;
|
|
125151
|
+
if (!this.store.has(sessionId)) {
|
|
125152
|
+
this.logger.debug(`[${sessionId}] Ignoring terminated event for GC-cleaned session`);
|
|
125153
|
+
return;
|
|
125154
|
+
}
|
|
125155
|
+
try {
|
|
125156
|
+
this.stopMachineSessionHeartbeat(sessionId);
|
|
125157
|
+
await this.finalizeACPState(sessionId);
|
|
125158
|
+
await this.flushSessionUsage(sessionId);
|
|
125159
|
+
} catch (error2) {
|
|
125160
|
+
this.logger.error(`[${sessionId}] Failed to handle termination event: ${formatErrorMessage(error2)}`);
|
|
125161
|
+
}
|
|
125162
|
+
})();
|
|
125148
125163
|
});
|
|
125149
125164
|
}
|
|
125150
125165
|
setupArchiveWatcher() {
|
|
@@ -125416,7 +125431,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
125416
125431
|
const batchWindowMs = state2.acpFlushCountInTurn === 0 ? MessageHandler.ACP_INITIAL_UPDATE_BATCH_WINDOW_MS : MessageHandler.ACP_SUBSEQUENT_UPDATE_BATCH_WINDOW_MS;
|
|
125417
125432
|
const timer2 = setTimeout(() => {
|
|
125418
125433
|
state2.acpFlushTimer = null;
|
|
125419
|
-
this.startACPUpdateFlush(sessionId);
|
|
125434
|
+
void this.startACPUpdateFlush(sessionId);
|
|
125420
125435
|
}, batchWindowMs);
|
|
125421
125436
|
timer2.unref?.();
|
|
125422
125437
|
state2.acpFlushTimer = timer2;
|
|
@@ -125429,7 +125444,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
125429
125444
|
if (state2.acpUpdateBuffer.length === 0) {
|
|
125430
125445
|
return;
|
|
125431
125446
|
}
|
|
125432
|
-
this.startACPUpdateFlush(sessionId);
|
|
125447
|
+
void this.startACPUpdateFlush(sessionId);
|
|
125433
125448
|
}
|
|
125434
125449
|
const inFlight = state2.acpFlushInFlight;
|
|
125435
125450
|
if (!inFlight) {
|
|
@@ -125585,11 +125600,11 @@ $mem | ConvertTo-Json -Compress
|
|
|
125585
125600
|
try {
|
|
125586
125601
|
await handleACPUpdateMessage(sessionDoc, queue2, {
|
|
125587
125602
|
logger: this.logger,
|
|
125588
|
-
getCurrentSessionTurnId: (
|
|
125589
|
-
const tid = this.store.getTurnId(
|
|
125603
|
+
getCurrentSessionTurnId: (currentSessionId) => {
|
|
125604
|
+
const tid = this.store.getTurnId(currentSessionId);
|
|
125590
125605
|
if (!tid) {
|
|
125591
|
-
captureException(new Error(`No turn id found for session ${
|
|
125592
|
-
throw new Error(`No turn id found for session ${
|
|
125606
|
+
void captureException(new Error(`No turn id found for session ${currentSessionId}`));
|
|
125607
|
+
throw new Error(`No turn id found for session ${currentSessionId}`);
|
|
125593
125608
|
}
|
|
125594
125609
|
return tid;
|
|
125595
125610
|
}
|
|
@@ -125967,7 +125982,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
125967
125982
|
});
|
|
125968
125983
|
attachedTo = "new_entry";
|
|
125969
125984
|
} else {
|
|
125970
|
-
const
|
|
125985
|
+
const failureMessage = latestAttachTarget.kind === "unavailable" ? `Session is ${latestAttachTarget.statusType} and the original assistant turn is no longer available for image upload` : "The original assistant turn is no longer available for image upload";
|
|
125971
125986
|
this.captureSessionImageUploadEvent(analyticsUserId, "session/image_upload_failed", {
|
|
125972
125987
|
entrypoint: dispatchContext.source === "local" ? "cli_command" : "session_runtime",
|
|
125973
125988
|
session_id: sessionId,
|
|
@@ -125977,13 +125992,13 @@ $mem | ConvertTo-Json -Compress
|
|
|
125977
125992
|
local_project_id: localProjectId,
|
|
125978
125993
|
repo_full_name: repoFullName,
|
|
125979
125994
|
failure_reason: "active_turn_unavailable",
|
|
125980
|
-
error_message:
|
|
125995
|
+
error_message: failureMessage
|
|
125981
125996
|
});
|
|
125982
125997
|
respond({
|
|
125983
125998
|
success: false,
|
|
125984
125999
|
workspaceId: this.workspaceId,
|
|
125985
126000
|
error: "active_turn_unavailable",
|
|
125986
|
-
message:
|
|
126001
|
+
message: failureMessage
|
|
125987
126002
|
});
|
|
125988
126003
|
return;
|
|
125989
126004
|
}
|
|
@@ -126000,7 +126015,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
126000
126015
|
});
|
|
126001
126016
|
if (!replaced) {
|
|
126002
126017
|
const latestAttachTarget = await this.resolveSessionImageUploadAttachTarget(sessionId, sessionDoc);
|
|
126003
|
-
const
|
|
126018
|
+
const failureMessage = latestAttachTarget.kind === "active_turn" ? "Session started a new assistant turn during image upload; retry after the turn completes" : latestAttachTarget.kind === "unavailable" ? `Session is ${latestAttachTarget.statusType} and no idle assistant entry can be created` : "Reserved assistant image entry is no longer available";
|
|
126004
126019
|
this.captureSessionImageUploadEvent(analyticsUserId, "session/image_upload_failed", {
|
|
126005
126020
|
entrypoint: dispatchContext.source === "local" ? "cli_command" : "session_runtime",
|
|
126006
126021
|
session_id: sessionId,
|
|
@@ -126010,13 +126025,13 @@ $mem | ConvertTo-Json -Compress
|
|
|
126010
126025
|
local_project_id: localProjectId,
|
|
126011
126026
|
repo_full_name: repoFullName,
|
|
126012
126027
|
failure_reason: "active_turn_unavailable",
|
|
126013
|
-
error_message:
|
|
126028
|
+
error_message: failureMessage
|
|
126014
126029
|
});
|
|
126015
126030
|
respond({
|
|
126016
126031
|
success: false,
|
|
126017
126032
|
workspaceId: this.workspaceId,
|
|
126018
126033
|
error: "active_turn_unavailable",
|
|
126019
|
-
message:
|
|
126034
|
+
message: failureMessage
|
|
126020
126035
|
});
|
|
126021
126036
|
return;
|
|
126022
126037
|
}
|
|
@@ -126254,20 +126269,22 @@ $mem | ConvertTo-Json -Compress
|
|
|
126254
126269
|
});
|
|
126255
126270
|
}
|
|
126256
126271
|
checkForOutcome();
|
|
126257
|
-
timeoutId = setTimeout(
|
|
126258
|
-
|
|
126259
|
-
|
|
126260
|
-
|
|
126261
|
-
|
|
126262
|
-
|
|
126272
|
+
timeoutId = setTimeout(() => {
|
|
126273
|
+
void (async () => {
|
|
126274
|
+
if (resolved) return;
|
|
126275
|
+
this.logger.warn(`Permission request timed out for session ${sessionId}`);
|
|
126276
|
+
this.logger.debug(`[${sessionId}] Permission request ${requestId} timed out after ${PERMISSION_REQUEST_TIMEOUT_MS}ms`);
|
|
126277
|
+
try {
|
|
126278
|
+
await updatePermissionOutcomeInHistory(doc, requestId, {
|
|
126279
|
+
outcome: "cancelled"
|
|
126280
|
+
}, this.logger);
|
|
126281
|
+
} catch (error2) {
|
|
126282
|
+
this.logger.error(`[${sessionId}] Failed to update permission timeout in history: ${formatErrorMessage(error2)}`);
|
|
126283
|
+
}
|
|
126284
|
+
void resolveWithOutcome({
|
|
126263
126285
|
outcome: "cancelled"
|
|
126264
|
-
}
|
|
126265
|
-
}
|
|
126266
|
-
this.logger.error(`[${sessionId}] Failed to update permission timeout in history: ${formatErrorMessage(error2)}`);
|
|
126267
|
-
}
|
|
126268
|
-
void resolveWithOutcome({
|
|
126269
|
-
outcome: "cancelled"
|
|
126270
|
-
});
|
|
126286
|
+
});
|
|
126287
|
+
})();
|
|
126271
126288
|
}, PERMISSION_REQUEST_TIMEOUT_MS);
|
|
126272
126289
|
});
|
|
126273
126290
|
}
|
|
@@ -127402,7 +127419,7 @@ $mem | ConvertTo-Json -Compress
|
|
|
127402
127419
|
}
|
|
127403
127420
|
const BROKER_STATE_FILE_PATH = path__default.join(os__default.homedir(), ".lody", "broker.json");
|
|
127404
127421
|
const createGitCredentialBrokerHandler = (options) => {
|
|
127405
|
-
|
|
127422
|
+
const handleRequest = async (req, res) => {
|
|
127406
127423
|
try {
|
|
127407
127424
|
if (req.method === "GET" && req.url === "/health") {
|
|
127408
127425
|
res.writeHead(200, {
|
|
@@ -127495,6 +127512,9 @@ $mem | ConvertTo-Json -Compress
|
|
|
127495
127512
|
}));
|
|
127496
127513
|
}
|
|
127497
127514
|
};
|
|
127515
|
+
return (req, res) => {
|
|
127516
|
+
void handleRequest(req, res);
|
|
127517
|
+
};
|
|
127498
127518
|
};
|
|
127499
127519
|
const DEFAULT_HEALTH_CHECK_INTERVAL_MS = 3e4;
|
|
127500
127520
|
const HEALTH_CHECK_TIMEOUT_MS = 5e3;
|
|
@@ -127600,15 +127620,17 @@ $mem | ConvertTo-Json -Compress
|
|
|
127600
127620
|
if (this.healthCheckTimer) {
|
|
127601
127621
|
return;
|
|
127602
127622
|
}
|
|
127603
|
-
this.healthCheckTimer = setInterval(
|
|
127604
|
-
|
|
127605
|
-
|
|
127606
|
-
|
|
127607
|
-
|
|
127608
|
-
|
|
127609
|
-
|
|
127610
|
-
|
|
127611
|
-
|
|
127623
|
+
this.healthCheckTimer = setInterval(() => {
|
|
127624
|
+
void (async () => {
|
|
127625
|
+
if (this.isRecovering) {
|
|
127626
|
+
return;
|
|
127627
|
+
}
|
|
127628
|
+
const isHealthy = await this.checkHealth();
|
|
127629
|
+
if (!isHealthy && this.env) {
|
|
127630
|
+
this.logger.debug("Git credential broker health check failed, attempting recovery...");
|
|
127631
|
+
await this.recover();
|
|
127632
|
+
}
|
|
127633
|
+
})();
|
|
127612
127634
|
}, DEFAULT_HEALTH_CHECK_INTERVAL_MS);
|
|
127613
127635
|
this.healthCheckTimer.unref();
|
|
127614
127636
|
}
|
|
@@ -133609,37 +133631,14 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
133609
133631
|
args: callbacks.args ?? [],
|
|
133610
133632
|
getStderrTail: () => stderrTail
|
|
133611
133633
|
});
|
|
133612
|
-
agentProcess.stdin
|
|
133613
|
-
|
|
133614
|
-
|
|
133615
|
-
|
|
133616
|
-
|
|
133617
|
-
|
|
133618
|
-
|
|
133619
|
-
|
|
133620
|
-
agentProcess.stdin.write(chunk);
|
|
133621
|
-
}
|
|
133622
|
-
},
|
|
133623
|
-
close() {
|
|
133624
|
-
if (agentProcess.stdin && !agentProcess.stdin.destroyed) {
|
|
133625
|
-
agentProcess.stdin.end();
|
|
133626
|
-
}
|
|
133627
|
-
}
|
|
133628
|
-
});
|
|
133629
|
-
const output = new ReadableStream({
|
|
133630
|
-
start(controller) {
|
|
133631
|
-
if (!agentProcess.stdout) {
|
|
133632
|
-
controller.error(new Error("Agent process stdout is not available"));
|
|
133633
|
-
return;
|
|
133634
|
-
}
|
|
133635
|
-
agentProcess.stdout.on("data", (chunk) => {
|
|
133636
|
-
controller.enqueue(chunk);
|
|
133637
|
-
});
|
|
133638
|
-
agentProcess.stdout.on("end", () => {
|
|
133639
|
-
controller.close();
|
|
133640
|
-
});
|
|
133641
|
-
}
|
|
133642
|
-
});
|
|
133634
|
+
if (!agentProcess.stdin) {
|
|
133635
|
+
throw new Error("Agent process stdin is not available");
|
|
133636
|
+
}
|
|
133637
|
+
if (!agentProcess.stdout) {
|
|
133638
|
+
throw new Error("Agent process stdout is not available");
|
|
133639
|
+
}
|
|
133640
|
+
const input2 = createStdinWritableStream(agentProcess.stdin);
|
|
133641
|
+
const output = createStdoutReadableStream(agentProcess.stdout);
|
|
133643
133642
|
const stream2 = ndJsonStream(input2, output);
|
|
133644
133643
|
this.logger.debug(`[${this.sessionId}] ndJsonStream created, calling createAcpClient`);
|
|
133645
133644
|
const { client, acpSessionId } = await createAcpClient({
|
|
@@ -134820,11 +134819,11 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
134820
134819
|
responses
|
|
134821
134820
|
});
|
|
134822
134821
|
} catch (error2) {
|
|
134823
|
-
const
|
|
134824
|
-
config2.logger.debug(`Local session control dispatch failed: ${
|
|
134822
|
+
const errorMessage = formatErrorMessage(error2);
|
|
134823
|
+
config2.logger.debug(`Local session control dispatch failed: ${errorMessage}`);
|
|
134825
134824
|
jsonResponse(res, 500, {
|
|
134826
134825
|
ok: false,
|
|
134827
|
-
error:
|
|
134826
|
+
error: errorMessage
|
|
134828
134827
|
});
|
|
134829
134828
|
}
|
|
134830
134829
|
}
|
|
@@ -135021,21 +135020,23 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
135021
135020
|
}
|
|
135022
135021
|
chunks.push(chunk);
|
|
135023
135022
|
});
|
|
135024
|
-
req.on("end",
|
|
135025
|
-
|
|
135026
|
-
|
|
135027
|
-
|
|
135028
|
-
|
|
135029
|
-
|
|
135030
|
-
|
|
135031
|
-
|
|
135032
|
-
|
|
135033
|
-
|
|
135034
|
-
|
|
135035
|
-
|
|
135036
|
-
|
|
135037
|
-
|
|
135038
|
-
|
|
135023
|
+
req.on("end", () => {
|
|
135024
|
+
void (async () => {
|
|
135025
|
+
if (res.headersSent || res.writableEnded || res.destroyed) {
|
|
135026
|
+
return;
|
|
135027
|
+
}
|
|
135028
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
135029
|
+
config2.logger.debug(`[local-control:${requestId}] request body received: bytes=${Buffer.byteLength(raw, "utf8")} path=${requestPath}`);
|
|
135030
|
+
if (requestPath === SESSION_CONTROL_PATH$1) {
|
|
135031
|
+
await handleSessionControlRequest(config2, raw, res, requestId);
|
|
135032
|
+
return;
|
|
135033
|
+
}
|
|
135034
|
+
if (requestPath === IMAGE_UPLOAD_PATH) {
|
|
135035
|
+
await handleImageUploadRequest(config2, raw, res, requestId);
|
|
135036
|
+
return;
|
|
135037
|
+
}
|
|
135038
|
+
await handleProjectControlRequest(config2, raw, res, requestId);
|
|
135039
|
+
})();
|
|
135039
135040
|
});
|
|
135040
135041
|
req.on("error", (error2) => {
|
|
135041
135042
|
config2.logger.debug(`[local-control:${requestId}] request stream error: ${error2.message}`);
|
|
@@ -136041,7 +136042,7 @@ export PATH=${toSingleQuotedShellString(ghShimBinDir)}:"$PATH"
|
|
|
136041
136042
|
this.retryTimers.clear();
|
|
136042
136043
|
this.unsubscribeWorkspaces?.();
|
|
136043
136044
|
this.unsubscribeWorkspaces = null;
|
|
136044
|
-
this.convex?.close();
|
|
136045
|
+
void this.convex?.close();
|
|
136045
136046
|
this.convex = null;
|
|
136046
136047
|
const runtimes = Array.from(this.runtimes.values());
|
|
136047
136048
|
this.runtimes.clear();
|
|
@@ -169751,7 +169752,7 @@ ${result.stderr}`;
|
|
|
169751
169752
|
if (error2 instanceof Error && error2.name === "CommanderError") {
|
|
169752
169753
|
process.exit(1);
|
|
169753
169754
|
} else {
|
|
169754
|
-
reportError("cli", error2, {
|
|
169755
|
+
void reportError("cli", error2, {
|
|
169755
169756
|
logger: cliLogger,
|
|
169756
169757
|
fatal: true
|
|
169757
169758
|
}).finally(() => process.exit(1));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lody",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "Lody Agent CLI tool for managing remote command execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@better-auth/api-key": "1.5.5",
|
|
29
29
|
"@convex-dev/better-auth": "0.11.2",
|
|
30
30
|
"@loro-dev/flock-wasm": "^0.2.1",
|
|
31
|
-
"@loro-dev/streams-crdt": "0.8.
|
|
31
|
+
"@loro-dev/streams-crdt": "0.8.1",
|
|
32
32
|
"@sentry/node": "^10.29.0",
|
|
33
33
|
"@types/cross-spawn": "^6.0.6",
|
|
34
34
|
"@types/iconv-lite": "^0.0.1",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"ws": "^8.18.3",
|
|
74
74
|
"zod": "^4.1.5",
|
|
75
75
|
"@lody/convex": "0.0.1",
|
|
76
|
-
"@lody/cli-supervisor": "0.0.1",
|
|
77
76
|
"@lody/loro-streams-rpc": "0.0.1",
|
|
77
|
+
"@lody/cli-supervisor": "0.0.1",
|
|
78
78
|
"@lody/shared": "0.0.1",
|
|
79
79
|
"loro-code": "0.0.1"
|
|
80
80
|
},
|