@threadbase-sh/streamer 1.70.1 → 1.70.3
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/api/handlers/sessions.handlers.d.ts.map +1 -1
- package/dist/cli.cjs +86 -26
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +86 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +86 -26
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/services/prompts/promptRegistry.d.ts +33 -0
- package/dist/services/prompts/promptRegistry.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9831,6 +9831,58 @@ var PromptRegistry = class {
|
|
|
9831
9831
|
this.publish(entry);
|
|
9832
9832
|
return copyPrompt(entry.prompt);
|
|
9833
9833
|
}
|
|
9834
|
+
/**
|
|
9835
|
+
* The provider's prompt left the screen.
|
|
9836
|
+
*
|
|
9837
|
+
* Distinct from `transition` because the detector cannot tell a teardown it
|
|
9838
|
+
* observed on its own from one OUR OWN write caused. On a screen-scraped gate
|
|
9839
|
+
* the answer keys remove the box, and pty-manager's sendKeys fires the close
|
|
9840
|
+
* synchronously from inside the write — so the close always arrives before
|
|
9841
|
+
* the answer that caused it has settled, and reporting it as a cancel failed
|
|
9842
|
+
* every answer whose bytes had already landed (#720).
|
|
9843
|
+
*
|
|
9844
|
+
* While an answer is writing, the close is deferred and the answer decides:
|
|
9845
|
+
* `resolved` if the write landed, the deferred close if it did not. Success
|
|
9846
|
+
* is the adapter's own result, never the prompt's absence from the screen —
|
|
9847
|
+
* a prompt that does not vanish when answered (a multi-select form) simply
|
|
9848
|
+
* never reaches here, and is settled by the same adapter result (#721).
|
|
9849
|
+
*
|
|
9850
|
+
* ONLY this path defers. `replaced` from a different gate taking the screen,
|
|
9851
|
+
* `unavailable` from invalidateSession and `expired` all still go through
|
|
9852
|
+
* `transition` and still win, because none of them was caused by our write.
|
|
9853
|
+
*/
|
|
9854
|
+
providerClosed(promptId, reason) {
|
|
9855
|
+
const entry = this.byId.get(promptId);
|
|
9856
|
+
if (!entry) return null;
|
|
9857
|
+
if (entry.prompt.state !== "open" && entry.prompt.state !== "updated") return null;
|
|
9858
|
+
if (entry.answering) {
|
|
9859
|
+
entry.deferredClose = reason;
|
|
9860
|
+
return null;
|
|
9861
|
+
}
|
|
9862
|
+
return this.transition(promptId, "cancelled", reason);
|
|
9863
|
+
}
|
|
9864
|
+
/**
|
|
9865
|
+
* Run a provider write that may close the prompt as a side effect, so the
|
|
9866
|
+
* close it causes is deferred rather than applied. For callers outside this
|
|
9867
|
+
* class that write without going through `answer()` — the legacy permission
|
|
9868
|
+
* route. `performAnswer` manages the same two fields directly, because it
|
|
9869
|
+
* needs the deferred value in its own control flow.
|
|
9870
|
+
*
|
|
9871
|
+
* The write's own failure needs no unwinding here: pty-manager fires the
|
|
9872
|
+
* close as the last statement of a successful sendKeys, so a throw means no
|
|
9873
|
+
* close was ever deferred and the record is still open for the caller.
|
|
9874
|
+
*/
|
|
9875
|
+
whileAnswering(promptId, write) {
|
|
9876
|
+
const entry = this.byId.get(promptId);
|
|
9877
|
+
if (!entry) return write();
|
|
9878
|
+
entry.answering = true;
|
|
9879
|
+
try {
|
|
9880
|
+
return write();
|
|
9881
|
+
} finally {
|
|
9882
|
+
entry.answering = false;
|
|
9883
|
+
entry.deferredClose = void 0;
|
|
9884
|
+
}
|
|
9885
|
+
}
|
|
9834
9886
|
invalidateSession(sessionId, reason = "session_ended") {
|
|
9835
9887
|
const transitioned = [];
|
|
9836
9888
|
for (const entry of this.bySession.get(sessionId)?.values() ?? []) {
|
|
@@ -9908,21 +9960,33 @@ var PromptRegistry = class {
|
|
|
9908
9960
|
const responseError = this.validateResponses(prompt, answer);
|
|
9909
9961
|
if (responseError) return { ok: false, code: responseError };
|
|
9910
9962
|
if (!entry.adapter) return { ok: false, code: "prompt_unavailable" };
|
|
9963
|
+
entry.answering = true;
|
|
9911
9964
|
let adapterResult;
|
|
9965
|
+
let threw = false;
|
|
9912
9966
|
try {
|
|
9913
9967
|
adapterResult = await entry.adapter({ prompt: copyPrompt(prompt), answer });
|
|
9914
9968
|
} catch {
|
|
9915
|
-
|
|
9969
|
+
threw = true;
|
|
9970
|
+
adapterResult = { ok: false, code: "provider_error" };
|
|
9971
|
+
} finally {
|
|
9972
|
+
entry.answering = false;
|
|
9916
9973
|
}
|
|
9974
|
+
const deferred = entry.deferredClose;
|
|
9975
|
+
entry.deferredClose = void 0;
|
|
9976
|
+
const settle = (outcome) => {
|
|
9977
|
+
if (deferred) this.providerClosed(prompt.promptId, deferred);
|
|
9978
|
+
return outcome;
|
|
9979
|
+
};
|
|
9980
|
+
if (threw) return settle({ ok: false, code: "provider_error" });
|
|
9917
9981
|
if (entry.prompt.state !== "open" && entry.prompt.state !== "updated") {
|
|
9918
|
-
return { ok: false, code: terminalError(entry.prompt.state) };
|
|
9982
|
+
return settle({ ok: false, code: terminalError(entry.prompt.state) });
|
|
9919
9983
|
}
|
|
9920
9984
|
if (entry.prompt.revision !== answer.revision) {
|
|
9921
|
-
return {
|
|
9985
|
+
return settle({
|
|
9922
9986
|
ok: false,
|
|
9923
9987
|
code: "prompt_revision_mismatch",
|
|
9924
9988
|
currentRevision: entry.prompt.revision
|
|
9925
|
-
};
|
|
9989
|
+
});
|
|
9926
9990
|
}
|
|
9927
9991
|
if (!adapterResult.ok) {
|
|
9928
9992
|
if (adapterResult.terminal) {
|
|
@@ -9932,7 +9996,7 @@ var PromptRegistry = class {
|
|
|
9932
9996
|
adapterResult.terminal.reason
|
|
9933
9997
|
);
|
|
9934
9998
|
}
|
|
9935
|
-
return { ok: false, code: adapterResult.code };
|
|
9999
|
+
return settle({ ok: false, code: adapterResult.code });
|
|
9936
10000
|
}
|
|
9937
10001
|
return { ok: true, prompt: this.transition(prompt.promptId, "resolved", "answered") };
|
|
9938
10002
|
}
|
|
@@ -11143,10 +11207,7 @@ var SessionHandlers = class {
|
|
|
11143
11207
|
if (gate === null) {
|
|
11144
11208
|
const prior2 = this.pendingPermission.get(sessionId);
|
|
11145
11209
|
if (!prior2) return;
|
|
11146
|
-
|
|
11147
|
-
if (prompt2?.state === "open" || prompt2?.state === "updated") {
|
|
11148
|
-
this.promptRegistry.transition(prompt2.promptId, "cancelled", "provider_closed");
|
|
11149
|
-
}
|
|
11210
|
+
if (prior2.promptId) this.promptRegistry.providerClosed(prior2.promptId, "provider_closed");
|
|
11150
11211
|
this.pendingPermission.delete(sessionId);
|
|
11151
11212
|
this.pendingPermissionKey.delete(sessionId);
|
|
11152
11213
|
this.broadcastToSession(sessionId, { type: "permission_cancelled", sessionId });
|
|
@@ -11371,7 +11432,13 @@ var SessionHandlers = class {
|
|
|
11371
11432
|
return;
|
|
11372
11433
|
}
|
|
11373
11434
|
try {
|
|
11374
|
-
this.
|
|
11435
|
+
this.promptRegistry.whileAnswering(
|
|
11436
|
+
gate.promptId ?? "",
|
|
11437
|
+
() => this.ptyManager.sendKeys(
|
|
11438
|
+
sessionId,
|
|
11439
|
+
option.answerKeys ?? permissionAnswerKeys(option.index)
|
|
11440
|
+
)
|
|
11441
|
+
);
|
|
11375
11442
|
} catch (err) {
|
|
11376
11443
|
const message = err instanceof Error ? err.message : "Failed to send answer";
|
|
11377
11444
|
json(res, 400, { ok: false, reason: message });
|
|
@@ -18448,23 +18515,16 @@ var StreamerServer = class {
|
|
|
18448
18515
|
* it.
|
|
18449
18516
|
*/
|
|
18450
18517
|
async resolveConversationTarget(sessionId) {
|
|
18451
|
-
|
|
18452
|
-
|
|
18453
|
-
|
|
18454
|
-
|
|
18455
|
-
|
|
18456
|
-
|
|
18457
|
-
|
|
18458
|
-
if (boundId != null && boundId !== sessionId) {
|
|
18459
|
-
historyId = boundId;
|
|
18460
|
-
registryProvider = row?.provider;
|
|
18461
|
-
jsonlPath = this.conversationHandlers.findJsonlPath(boundId);
|
|
18462
|
-
conv = await this.conversationHandlers.findConversationByUuid(boundId);
|
|
18463
|
-
}
|
|
18464
|
-
}
|
|
18518
|
+
const row = this.managedSessionsRepo?.get(sessionId) ?? null;
|
|
18519
|
+
const liveSession = this.sessionStore.getManaged(sessionId);
|
|
18520
|
+
const resumeId = (row ? resumeIdForRow(row) : null) ?? (liveSession?.provider === CODEX_CLI_PROVIDER ? liveSession.boundConversationId ?? null : null);
|
|
18521
|
+
const historyId = resumeId ?? sessionId;
|
|
18522
|
+
const managedProvider = row?.provider ?? liveSession?.provider;
|
|
18523
|
+
const jsonlPath = this.conversationHandlers.findJsonlPath(historyId);
|
|
18524
|
+
const conv = await this.conversationHandlers.findConversationByUuid(historyId);
|
|
18465
18525
|
const cachedConvMeta = this.cache?.getMetaById(historyId);
|
|
18466
18526
|
const cachedPath = cachedConvMeta?.filePath ? toNativeFilePath(cachedConvMeta.filePath) : null;
|
|
18467
|
-
const cachedCodexPath = (
|
|
18527
|
+
const cachedCodexPath = (managedProvider === CODEX_CLI_PROVIDER || cachedConvMeta?.provider === CODEX_CLI_PROVIDER) && cachedPath != null && existsSync16(cachedPath) ? cachedPath : null;
|
|
18468
18528
|
const jsonlCwd = jsonlPath ? await this.conversationHandlers.readCwdFromJsonl(jsonlPath) : null;
|
|
18469
18529
|
const projectPath = jsonlCwd ?? conv?.projectPath ?? (cachedCodexPath ? cachedConvMeta?.projectPath : null);
|
|
18470
18530
|
if (!projectPath) {
|
|
@@ -18474,7 +18534,7 @@ var StreamerServer = class {
|
|
|
18474
18534
|
return { ok: false, reason: "no_project_path" };
|
|
18475
18535
|
}
|
|
18476
18536
|
const provider = coerceProviderForRunner(
|
|
18477
|
-
conv?.provider ?? cachedConvMeta?.provider ??
|
|
18537
|
+
conv?.provider ?? cachedConvMeta?.provider ?? managedProvider
|
|
18478
18538
|
);
|
|
18479
18539
|
return {
|
|
18480
18540
|
ok: true,
|