@threadbase-sh/streamer 1.34.0 → 1.35.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/cli.cjs +92 -18
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +92 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -3
- package/dist/index.d.ts +16 -3
- package/dist/index.js +92 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -276,6 +276,12 @@ type WSMessage = {
|
|
|
276
276
|
};
|
|
277
277
|
/** The four cache-integrity resolution actions (POST /api/cache/alert/resolve). */
|
|
278
278
|
type CacheAlertResolveAction = "prune_all" | "prune_selected" | "ignore" | "reset_rescan";
|
|
279
|
+
type ServerWarmupState = "startup" | "cache_reset" | "conversation_refresh";
|
|
280
|
+
interface ServerWarmingUpResponse {
|
|
281
|
+
error: "Server is warming up";
|
|
282
|
+
code: "SERVER_WARMING_UP";
|
|
283
|
+
warmupState: ServerWarmupState;
|
|
284
|
+
}
|
|
279
285
|
interface SessionResponse {
|
|
280
286
|
id: string;
|
|
281
287
|
conversationId: string;
|
|
@@ -957,11 +963,12 @@ declare class CacheIntegrityMonitor {
|
|
|
957
963
|
private readonly log;
|
|
958
964
|
private readonly cacheDir;
|
|
959
965
|
private readonly rescan?;
|
|
966
|
+
private readonly runDuringReset?;
|
|
960
967
|
private _pending;
|
|
961
968
|
private ignoredIds;
|
|
962
969
|
private deferredUnlinks;
|
|
963
970
|
private unlinkTimes;
|
|
964
|
-
constructor(cache: ConversationCache, wsHub: WSHub, log: Logger, cacheDir: string, rescan?: (() => Promise<ScannerMeta[]>) | undefined);
|
|
971
|
+
constructor(cache: ConversationCache, wsHub: WSHub, log: Logger, cacheDir: string, rescan?: (() => Promise<ScannerMeta[]>) | undefined, runDuringReset?: (<T>(operation: () => Promise<T>) => Promise<T>) | undefined);
|
|
965
972
|
get pending(): PendingAlert | null;
|
|
966
973
|
private persist;
|
|
967
974
|
private classifySeverity;
|
|
@@ -1185,7 +1192,8 @@ declare class StreamerServer {
|
|
|
1185
1192
|
private scannerStale;
|
|
1186
1193
|
private refreshInFlight;
|
|
1187
1194
|
private binding;
|
|
1188
|
-
private
|
|
1195
|
+
private activeWarmups;
|
|
1196
|
+
private nextWarmupId;
|
|
1189
1197
|
private inFlightCacheWrites;
|
|
1190
1198
|
private apiKey;
|
|
1191
1199
|
private apiKeySource;
|
|
@@ -1246,6 +1254,11 @@ declare class StreamerServer {
|
|
|
1246
1254
|
private addSessionSubscriber;
|
|
1247
1255
|
private startGraceTimer;
|
|
1248
1256
|
get port(): number;
|
|
1257
|
+
private currentWarmupState;
|
|
1258
|
+
private beginWarmup;
|
|
1259
|
+
private finishWarmup;
|
|
1260
|
+
private withWarmup;
|
|
1261
|
+
private rejectIfWarmingUp;
|
|
1249
1262
|
listen(port: number, opts?: {
|
|
1250
1263
|
awaitReady?: boolean;
|
|
1251
1264
|
}): Promise<void>;
|
|
@@ -1448,4 +1461,4 @@ declare class ConversationWatcher {
|
|
|
1448
1461
|
private readNewLines;
|
|
1449
1462
|
}
|
|
1450
1463
|
|
|
1451
|
-
export { type AgentClient, type AgentClientOpts, type AgentConfig, type AppendArgs, type AskOption, type AskQuestion, CLAUDE_CODE_PROVIDER, CODEX_CLI_PROVIDER, type CacheAlertResolveAction, type ConversationListResponse, ConversationWatcher, type ConversationWriter, type DbConfig, type DiscoveredProcess, LiveSessionManager, type ManagedSession, PTYManager, type PTYManagerOptions, type PermissionOption, type ProcessLiveness, type ProgressDedupeLRU, type ProviderName, type ServerConfig, type SessionActivity, type SessionCursor, type SessionListPage, type SessionListQuery, type SessionOwnership, type SessionResponse, type SessionRunner, type SessionSortKey, type SessionStatus, SessionStore, type SortOrder, type StartFreshSessionOptions, type StartSessionOptions, StreamerServer, type UserMessage, WSHub, type WSMessage, createAgentClient, createConversationWriter, createPool, createProgressDedupeLRU, createProgressRoutes, discoverClaudeProcesses, generateApiKey, getDbConfig, isDbEnabled, isProviderName, isProviderResumable, loadOrCreateApiKey, maskConnectionString, readAgentConfig, validateApiKey };
|
|
1464
|
+
export { type AgentClient, type AgentClientOpts, type AgentConfig, type AppendArgs, type AskOption, type AskQuestion, CLAUDE_CODE_PROVIDER, CODEX_CLI_PROVIDER, type CacheAlertResolveAction, type ConversationListResponse, ConversationWatcher, type ConversationWriter, type DbConfig, type DiscoveredProcess, LiveSessionManager, type ManagedSession, PTYManager, type PTYManagerOptions, type PermissionOption, type ProcessLiveness, type ProgressDedupeLRU, type ProviderName, type ServerConfig, type ServerWarmingUpResponse, type ServerWarmupState, type SessionActivity, type SessionCursor, type SessionListPage, type SessionListQuery, type SessionOwnership, type SessionResponse, type SessionRunner, type SessionSortKey, type SessionStatus, SessionStore, type SortOrder, type StartFreshSessionOptions, type StartSessionOptions, StreamerServer, type UserMessage, WSHub, type WSMessage, createAgentClient, createConversationWriter, createPool, createProgressDedupeLRU, createProgressRoutes, discoverClaudeProcesses, generateApiKey, getDbConfig, isDbEnabled, isProviderName, isProviderResumable, loadOrCreateApiKey, maskConnectionString, readAgentConfig, validateApiKey };
|
package/dist/index.d.ts
CHANGED
|
@@ -276,6 +276,12 @@ type WSMessage = {
|
|
|
276
276
|
};
|
|
277
277
|
/** The four cache-integrity resolution actions (POST /api/cache/alert/resolve). */
|
|
278
278
|
type CacheAlertResolveAction = "prune_all" | "prune_selected" | "ignore" | "reset_rescan";
|
|
279
|
+
type ServerWarmupState = "startup" | "cache_reset" | "conversation_refresh";
|
|
280
|
+
interface ServerWarmingUpResponse {
|
|
281
|
+
error: "Server is warming up";
|
|
282
|
+
code: "SERVER_WARMING_UP";
|
|
283
|
+
warmupState: ServerWarmupState;
|
|
284
|
+
}
|
|
279
285
|
interface SessionResponse {
|
|
280
286
|
id: string;
|
|
281
287
|
conversationId: string;
|
|
@@ -957,11 +963,12 @@ declare class CacheIntegrityMonitor {
|
|
|
957
963
|
private readonly log;
|
|
958
964
|
private readonly cacheDir;
|
|
959
965
|
private readonly rescan?;
|
|
966
|
+
private readonly runDuringReset?;
|
|
960
967
|
private _pending;
|
|
961
968
|
private ignoredIds;
|
|
962
969
|
private deferredUnlinks;
|
|
963
970
|
private unlinkTimes;
|
|
964
|
-
constructor(cache: ConversationCache, wsHub: WSHub, log: Logger, cacheDir: string, rescan?: (() => Promise<ScannerMeta[]>) | undefined);
|
|
971
|
+
constructor(cache: ConversationCache, wsHub: WSHub, log: Logger, cacheDir: string, rescan?: (() => Promise<ScannerMeta[]>) | undefined, runDuringReset?: (<T>(operation: () => Promise<T>) => Promise<T>) | undefined);
|
|
965
972
|
get pending(): PendingAlert | null;
|
|
966
973
|
private persist;
|
|
967
974
|
private classifySeverity;
|
|
@@ -1185,7 +1192,8 @@ declare class StreamerServer {
|
|
|
1185
1192
|
private scannerStale;
|
|
1186
1193
|
private refreshInFlight;
|
|
1187
1194
|
private binding;
|
|
1188
|
-
private
|
|
1195
|
+
private activeWarmups;
|
|
1196
|
+
private nextWarmupId;
|
|
1189
1197
|
private inFlightCacheWrites;
|
|
1190
1198
|
private apiKey;
|
|
1191
1199
|
private apiKeySource;
|
|
@@ -1246,6 +1254,11 @@ declare class StreamerServer {
|
|
|
1246
1254
|
private addSessionSubscriber;
|
|
1247
1255
|
private startGraceTimer;
|
|
1248
1256
|
get port(): number;
|
|
1257
|
+
private currentWarmupState;
|
|
1258
|
+
private beginWarmup;
|
|
1259
|
+
private finishWarmup;
|
|
1260
|
+
private withWarmup;
|
|
1261
|
+
private rejectIfWarmingUp;
|
|
1249
1262
|
listen(port: number, opts?: {
|
|
1250
1263
|
awaitReady?: boolean;
|
|
1251
1264
|
}): Promise<void>;
|
|
@@ -1448,4 +1461,4 @@ declare class ConversationWatcher {
|
|
|
1448
1461
|
private readNewLines;
|
|
1449
1462
|
}
|
|
1450
1463
|
|
|
1451
|
-
export { type AgentClient, type AgentClientOpts, type AgentConfig, type AppendArgs, type AskOption, type AskQuestion, CLAUDE_CODE_PROVIDER, CODEX_CLI_PROVIDER, type CacheAlertResolveAction, type ConversationListResponse, ConversationWatcher, type ConversationWriter, type DbConfig, type DiscoveredProcess, LiveSessionManager, type ManagedSession, PTYManager, type PTYManagerOptions, type PermissionOption, type ProcessLiveness, type ProgressDedupeLRU, type ProviderName, type ServerConfig, type SessionActivity, type SessionCursor, type SessionListPage, type SessionListQuery, type SessionOwnership, type SessionResponse, type SessionRunner, type SessionSortKey, type SessionStatus, SessionStore, type SortOrder, type StartFreshSessionOptions, type StartSessionOptions, StreamerServer, type UserMessage, WSHub, type WSMessage, createAgentClient, createConversationWriter, createPool, createProgressDedupeLRU, createProgressRoutes, discoverClaudeProcesses, generateApiKey, getDbConfig, isDbEnabled, isProviderName, isProviderResumable, loadOrCreateApiKey, maskConnectionString, readAgentConfig, validateApiKey };
|
|
1464
|
+
export { type AgentClient, type AgentClientOpts, type AgentConfig, type AppendArgs, type AskOption, type AskQuestion, CLAUDE_CODE_PROVIDER, CODEX_CLI_PROVIDER, type CacheAlertResolveAction, type ConversationListResponse, ConversationWatcher, type ConversationWriter, type DbConfig, type DiscoveredProcess, LiveSessionManager, type ManagedSession, PTYManager, type PTYManagerOptions, type PermissionOption, type ProcessLiveness, type ProgressDedupeLRU, type ProviderName, type ServerConfig, type ServerWarmingUpResponse, type ServerWarmupState, type SessionActivity, type SessionCursor, type SessionListPage, type SessionListQuery, type SessionOwnership, type SessionResponse, type SessionRunner, type SessionSortKey, type SessionStatus, SessionStore, type SortOrder, type StartFreshSessionOptions, type StartSessionOptions, StreamerServer, type UserMessage, WSHub, type WSMessage, createAgentClient, createConversationWriter, createPool, createProgressDedupeLRU, createProgressRoutes, discoverClaudeProcesses, generateApiKey, getDbConfig, isDbEnabled, isProviderName, isProviderResumable, loadOrCreateApiKey, maskConnectionString, readAgentConfig, validateApiKey };
|
package/dist/index.js
CHANGED
|
@@ -5477,12 +5477,13 @@ function fingerprintOf(ids) {
|
|
|
5477
5477
|
return `sha256:${createHash2("sha256").update(sorted.join("\n")).digest("hex")}`;
|
|
5478
5478
|
}
|
|
5479
5479
|
var CacheIntegrityMonitor = class {
|
|
5480
|
-
constructor(cache, wsHub, log3, cacheDir, rescan) {
|
|
5480
|
+
constructor(cache, wsHub, log3, cacheDir, rescan, runDuringReset) {
|
|
5481
5481
|
this.cache = cache;
|
|
5482
5482
|
this.wsHub = wsHub;
|
|
5483
5483
|
this.log = log3;
|
|
5484
5484
|
this.cacheDir = cacheDir;
|
|
5485
5485
|
this.rescan = rescan;
|
|
5486
|
+
this.runDuringReset = runDuringReset;
|
|
5486
5487
|
const state = loadAlertState();
|
|
5487
5488
|
this._pending = state.pending ?? null;
|
|
5488
5489
|
this.ignoredIds = new Set(state.ignoredIds ?? []);
|
|
@@ -5492,6 +5493,7 @@ var CacheIntegrityMonitor = class {
|
|
|
5492
5493
|
log;
|
|
5493
5494
|
cacheDir;
|
|
5494
5495
|
rescan;
|
|
5496
|
+
runDuringReset;
|
|
5495
5497
|
_pending;
|
|
5496
5498
|
ignoredIds;
|
|
5497
5499
|
deferredUnlinks = [];
|
|
@@ -5695,18 +5697,20 @@ var CacheIntegrityMonitor = class {
|
|
|
5695
5697
|
}
|
|
5696
5698
|
case "reset_rescan": {
|
|
5697
5699
|
const backupPath = await this.ensureBackup(pending);
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5700
|
+
const reset = async () => {
|
|
5701
|
+
this.cache.clearAll();
|
|
5702
|
+
if (this.rescan) {
|
|
5701
5703
|
const metas = await this.rescan();
|
|
5702
5704
|
this.cache.upsertFromScannerMeta(metas);
|
|
5703
|
-
} catch (err) {
|
|
5704
|
-
this.log.error("cache-integrity reset rescan failed", {
|
|
5705
|
-
event: "cache_integrity.reset_rescan_failed",
|
|
5706
|
-
error: err instanceof Error ? err.message : String(err)
|
|
5707
|
-
});
|
|
5708
5705
|
}
|
|
5709
|
-
}
|
|
5706
|
+
};
|
|
5707
|
+
const resetPromise = this.runDuringReset ? this.runDuringReset(reset) : reset();
|
|
5708
|
+
void resetPromise.catch((err) => {
|
|
5709
|
+
this.log.error("cache-integrity reset rescan failed", {
|
|
5710
|
+
event: "cache_integrity.reset_rescan_failed",
|
|
5711
|
+
error: err instanceof Error ? err.message : String(err)
|
|
5712
|
+
});
|
|
5713
|
+
});
|
|
5710
5714
|
this.clearPending();
|
|
5711
5715
|
this.broadcastResolved(fingerprint, action);
|
|
5712
5716
|
return { ok: true, action, backupPath };
|
|
@@ -6697,7 +6701,8 @@ var StreamerServer = class {
|
|
|
6697
6701
|
// listener-level 'error' handler demotes EADDRINUSE to debug during this
|
|
6698
6702
|
// window so the self-healing kickstart-relaunch race doesn't spam warn.
|
|
6699
6703
|
binding = false;
|
|
6700
|
-
|
|
6704
|
+
activeWarmups = /* @__PURE__ */ new Map([[0, "startup"]]);
|
|
6705
|
+
nextWarmupId = 1;
|
|
6701
6706
|
// Every fire-and-forget task that runs a scan and then writes to this.cache
|
|
6702
6707
|
// in an async continuation (startup warm-up, background count refresh, …).
|
|
6703
6708
|
// close() awaits all of them before closing this.cache, so a scan's post-scan
|
|
@@ -7047,7 +7052,7 @@ var StreamerServer = class {
|
|
|
7047
7052
|
this.wsHub.addClient(ws);
|
|
7048
7053
|
const sessions = this.sessionStore.list(this.ptyAttachedIds());
|
|
7049
7054
|
ws.send(JSON.stringify({ type: "session_list", sessions }));
|
|
7050
|
-
if (this.
|
|
7055
|
+
if (!this.currentWarmupState()) {
|
|
7051
7056
|
ws.send(JSON.stringify({ type: "cache_ready" }));
|
|
7052
7057
|
}
|
|
7053
7058
|
const alertMsg = this.cacheMonitor?.wsMessage();
|
|
@@ -7256,6 +7261,39 @@ var StreamerServer = class {
|
|
|
7256
7261
|
const addr = this.httpServer.address();
|
|
7257
7262
|
return typeof addr === "object" && addr ? addr.port : 0;
|
|
7258
7263
|
}
|
|
7264
|
+
currentWarmupState() {
|
|
7265
|
+
let current = null;
|
|
7266
|
+
for (const state of this.activeWarmups.values()) current = state;
|
|
7267
|
+
return current;
|
|
7268
|
+
}
|
|
7269
|
+
beginWarmup(state) {
|
|
7270
|
+
const id = this.nextWarmupId++;
|
|
7271
|
+
this.activeWarmups.set(id, state);
|
|
7272
|
+
return id;
|
|
7273
|
+
}
|
|
7274
|
+
finishWarmup(id) {
|
|
7275
|
+
if (!this.activeWarmups.delete(id) || this.activeWarmups.size > 0) return;
|
|
7276
|
+
this.wsHub.broadcast({ type: "cache_ready" });
|
|
7277
|
+
}
|
|
7278
|
+
async withWarmup(state, operation) {
|
|
7279
|
+
const id = this.beginWarmup(state);
|
|
7280
|
+
try {
|
|
7281
|
+
return await operation();
|
|
7282
|
+
} finally {
|
|
7283
|
+
this.finishWarmup(id);
|
|
7284
|
+
}
|
|
7285
|
+
}
|
|
7286
|
+
rejectIfWarmingUp(res) {
|
|
7287
|
+
const warmupState = this.currentWarmupState();
|
|
7288
|
+
if (!warmupState) return false;
|
|
7289
|
+
const body = {
|
|
7290
|
+
error: "Server is warming up",
|
|
7291
|
+
code: "SERVER_WARMING_UP",
|
|
7292
|
+
warmupState
|
|
7293
|
+
};
|
|
7294
|
+
json(res, 503, body);
|
|
7295
|
+
return true;
|
|
7296
|
+
}
|
|
7259
7297
|
async listen(port, opts) {
|
|
7260
7298
|
const dbConfig = this.disableDb ? null : getDbConfig();
|
|
7261
7299
|
if (dbConfig) {
|
|
@@ -7313,6 +7351,11 @@ var StreamerServer = class {
|
|
|
7313
7351
|
async () => {
|
|
7314
7352
|
const scanner = await this.rescanForRefresh();
|
|
7315
7353
|
return [...scanner.getMetadataCache().values()];
|
|
7354
|
+
},
|
|
7355
|
+
(operation) => {
|
|
7356
|
+
const reset = this.withWarmup("cache_reset", operation);
|
|
7357
|
+
this.trackCacheWrite(reset);
|
|
7358
|
+
return reset;
|
|
7316
7359
|
}
|
|
7317
7360
|
);
|
|
7318
7361
|
for (const dir of this.projectsDirs()) {
|
|
@@ -7408,8 +7451,7 @@ var StreamerServer = class {
|
|
|
7408
7451
|
event: "cache.warmup_failed"
|
|
7409
7452
|
});
|
|
7410
7453
|
}).finally(() => {
|
|
7411
|
-
this.
|
|
7412
|
-
this.wsHub.broadcast({ type: "cache_ready" });
|
|
7454
|
+
this.finishWarmup(0);
|
|
7413
7455
|
resolveWarm();
|
|
7414
7456
|
});
|
|
7415
7457
|
}
|
|
@@ -7641,6 +7683,7 @@ var StreamerServer = class {
|
|
|
7641
7683
|
return this.checkRateLimit(this.sessionInputAttempts, sessionId, 500, 6e4);
|
|
7642
7684
|
}
|
|
7643
7685
|
async handleListConversations(url, res) {
|
|
7686
|
+
if (this.rejectIfWarmingUp(res)) return;
|
|
7644
7687
|
const limit = intParam(url, "limit", 50);
|
|
7645
7688
|
const offset = intParam(url, "offset", 0);
|
|
7646
7689
|
const sort = url.searchParams.get("sort") ?? "recent";
|
|
@@ -7648,7 +7691,7 @@ var StreamerServer = class {
|
|
|
7648
7691
|
const providerFilter = url.searchParams.get("provider") ?? void 0;
|
|
7649
7692
|
const bustCache = url.searchParams.get("refresh") === "1";
|
|
7650
7693
|
if (bustCache && this.cache) {
|
|
7651
|
-
const scanner2 = await this.rescanForRefresh();
|
|
7694
|
+
const scanner2 = await this.withWarmup("conversation_refresh", () => this.rescanForRefresh());
|
|
7652
7695
|
const metas2 = [...scanner2.getMetadataCache().values()];
|
|
7653
7696
|
try {
|
|
7654
7697
|
this.cache.upsertFromScannerMeta(metas2);
|
|
@@ -7729,6 +7772,7 @@ var StreamerServer = class {
|
|
|
7729
7772
|
json(res, 200, { conversations: adapted, hasMore: offset + limit < total, offset, total });
|
|
7730
7773
|
}
|
|
7731
7774
|
async handleConversationsCount(url, res) {
|
|
7775
|
+
if (this.rejectIfWarmingUp(res)) return;
|
|
7732
7776
|
const project = url.searchParams.get("project") ?? void 0;
|
|
7733
7777
|
const providerFilter = url.searchParams.get("provider") ?? void 0;
|
|
7734
7778
|
const bustCache = url.searchParams.get("refresh") === "1";
|
|
@@ -7756,7 +7800,7 @@ var StreamerServer = class {
|
|
|
7756
7800
|
// path — refresh=1 returns the cached total synchronously and this catches up.
|
|
7757
7801
|
refreshCountInBackground() {
|
|
7758
7802
|
this.trackCacheWrite(
|
|
7759
|
-
(async () => {
|
|
7803
|
+
this.withWarmup("conversation_refresh", async () => {
|
|
7760
7804
|
try {
|
|
7761
7805
|
const scanner = await this.getFreshScanner();
|
|
7762
7806
|
if (this.cache) {
|
|
@@ -7768,13 +7812,15 @@ var StreamerServer = class {
|
|
|
7768
7812
|
{ event: "count.refresh_failed" }
|
|
7769
7813
|
);
|
|
7770
7814
|
}
|
|
7771
|
-
})
|
|
7815
|
+
})
|
|
7772
7816
|
);
|
|
7773
7817
|
}
|
|
7774
7818
|
handleSessionsCount(res) {
|
|
7819
|
+
if (this.rejectIfWarmingUp(res)) return;
|
|
7775
7820
|
json(res, 200, { total: this.sessionStore.list(this.ptyAttachedIds()).length });
|
|
7776
7821
|
}
|
|
7777
7822
|
handleGetRecentSessions(url, res) {
|
|
7823
|
+
if (this.rejectIfWarmingUp(res)) return;
|
|
7778
7824
|
const limit = intParam(url, "limit", 20);
|
|
7779
7825
|
if (!this.cache) {
|
|
7780
7826
|
json(res, 200, { sessions: [], total: 0 });
|
|
@@ -8222,6 +8268,7 @@ var StreamerServer = class {
|
|
|
8222
8268
|
return isScannedSnapshotStale(conv.timestamp, mtimeMs);
|
|
8223
8269
|
}
|
|
8224
8270
|
async handleGetConversation(id, url, res, ifNoneMatch) {
|
|
8271
|
+
if (this.rejectIfWarmingUp(res)) return;
|
|
8225
8272
|
const conversation = await this.findConversationByUuid(id);
|
|
8226
8273
|
if (!conversation && this.cache) {
|
|
8227
8274
|
const isFirstLoad = !url.searchParams.has("before_index");
|
|
@@ -8549,6 +8596,7 @@ var StreamerServer = class {
|
|
|
8549
8596
|
});
|
|
8550
8597
|
}
|
|
8551
8598
|
async handleListSessions(url, res) {
|
|
8599
|
+
if (this.rejectIfWarmingUp(res)) return;
|
|
8552
8600
|
const now = Date.now();
|
|
8553
8601
|
if (!this.discoveryCache || now - this.discoveryCache.fetchedAt >= DISCOVERY_TTL_MS) {
|
|
8554
8602
|
try {
|
|
@@ -8581,6 +8629,7 @@ var StreamerServer = class {
|
|
|
8581
8629
|
}
|
|
8582
8630
|
}
|
|
8583
8631
|
handleGetSession(sessionId, res) {
|
|
8632
|
+
if (this.rejectIfWarmingUp(res)) return;
|
|
8584
8633
|
const session = this.sessionStore.get(sessionId, this.ptyAttachedIds());
|
|
8585
8634
|
if (session) {
|
|
8586
8635
|
if (!existsSync10(session.projectPath)) {
|
|
@@ -9032,12 +9081,21 @@ var StreamerServer = class {
|
|
|
9032
9081
|
json(res, 404, { error: "Discovered session not found" });
|
|
9033
9082
|
return;
|
|
9034
9083
|
}
|
|
9035
|
-
const {
|
|
9084
|
+
const { branch } = discSession;
|
|
9085
|
+
let { projectPath, projectName } = discSession;
|
|
9036
9086
|
const convId = discSession.id;
|
|
9037
9087
|
if (discSession.pid == null) {
|
|
9038
9088
|
json(res, 400, { error: "Session has no known PID" });
|
|
9039
9089
|
return;
|
|
9040
9090
|
}
|
|
9091
|
+
if (!projectPath) {
|
|
9092
|
+
const jsonlPath = this.findJsonlPath(convId);
|
|
9093
|
+
const jsonlCwd = jsonlPath ? await this.readCwdFromJsonl(jsonlPath) : null;
|
|
9094
|
+
if (jsonlCwd) {
|
|
9095
|
+
projectPath = jsonlCwd;
|
|
9096
|
+
projectName = projectName || basename5(jsonlCwd);
|
|
9097
|
+
}
|
|
9098
|
+
}
|
|
9041
9099
|
if (!projectPath) {
|
|
9042
9100
|
this.log.warn("adopt: refusing, working directory unknown", {
|
|
9043
9101
|
event: "adopt.no_project_path",
|
|
@@ -9050,6 +9108,22 @@ var StreamerServer = class {
|
|
|
9050
9108
|
});
|
|
9051
9109
|
return;
|
|
9052
9110
|
}
|
|
9111
|
+
const availability = classifyResumability(projectPath);
|
|
9112
|
+
if (!availability.resumable) {
|
|
9113
|
+
this.log.warn("adopt: refusing, project directory no longer exists", {
|
|
9114
|
+
event: "adopt.project_path_missing",
|
|
9115
|
+
sessionId,
|
|
9116
|
+
pid: discSession.pid,
|
|
9117
|
+
projectPath,
|
|
9118
|
+
reason: availability.unavailable_reason
|
|
9119
|
+
});
|
|
9120
|
+
json(res, 400, {
|
|
9121
|
+
error: "Cannot take over this session: its project directory no longer exists",
|
|
9122
|
+
code: "ADOPT_PROJECT_PATH_MISSING",
|
|
9123
|
+
reason: availability.unavailable_reason
|
|
9124
|
+
});
|
|
9125
|
+
return;
|
|
9126
|
+
}
|
|
9053
9127
|
this.ptyManager.killPid(discSession.pid);
|
|
9054
9128
|
const exited = await waitForProcessExit(discSession.pid, ADOPT_KILL_TIMEOUT_MS);
|
|
9055
9129
|
if (!exited) {
|