zcode-acp-server 0.78.0 → 0.79.1
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/README.md +1 -1
- package/dist/closed-sessions.d.ts +44 -0
- package/dist/closed-sessions.d.ts.map +1 -0
- package/dist/closed-sessions.js +128 -0
- package/dist/closed-sessions.js.map +1 -0
- package/dist/code-fingerprint.json +2 -2
- package/dist/handlers/session.d.ts.map +1 -1
- package/dist/handlers/session.js +30 -8
- package/dist/handlers/session.js.map +1 -1
- package/dist/remote/hub-server.d.ts.map +1 -1
- package/dist/remote/hub-server.js +84 -0
- package/dist/remote/hub-server.js.map +1 -1
- package/dist/remote/session-close-endpoint.d.ts.map +1 -1
- package/dist/remote/session-close-endpoint.js +7 -0
- package/dist/remote/session-close-endpoint.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +6 -0
- package/dist/server.js.map +1 -1
- package/dist/translators/index.d.ts +1 -1
- package/dist/translators/index.d.ts.map +1 -1
- package/dist/translators/index.js +1 -1
- package/dist/translators/index.js.map +1 -1
- package/dist/translators/tool-helpers.d.ts +9 -0
- package/dist/translators/tool-helpers.d.ts.map +1 -1
- package/dist/translators/tool-helpers.js +44 -0
- package/dist/translators/tool-helpers.js.map +1 -1
- package/docs/REMOTE-CLIENTS.md +15 -0
- package/docs/TROUBLESHOOTING.md +22 -6
- package/docs/adr/0006-remote-session-close.md +35 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -353,7 +353,7 @@ Thanks to everyone who has contributed (updated automatically from the
|
|
|
353
353
|
<a href="https://github.com/william0wang/zcode-acp/graphs/contributors">
|
|
354
354
|
<!-- release-please re-stamps &v= on every release: the new URL busts the
|
|
355
355
|
contrib.rocks and GitHub camo image caches. -->
|
|
356
|
-
<img src="https://contrib.rocks/image?repo=william0wang/zcode-acp&v=0.
|
|
356
|
+
<img src="https://contrib.rocks/image?repo=william0wang/zcode-acp&v=0.79.1" alt="Contributors" /> <!-- x-release-please-version -->
|
|
357
357
|
</a>
|
|
358
358
|
|
|
359
359
|
## Related Projects
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge-side remote-close record (ADR-0006 persistence amendment).
|
|
3
|
+
*
|
|
4
|
+
* A remote close retires the conversation from discovery with an IN-MEMORY
|
|
5
|
+
* stamp (`server.discoveryRetiredAt`) — and a serve-origin bridge then
|
|
6
|
+
* EXITS itself (last conversation closed), so the stamp dies with the
|
|
7
|
+
* process. When the hub incubates the next serve bridge and a client's
|
|
8
|
+
* reconnect ladder session/loads the conversation, the fresh process has no
|
|
9
|
+
* retirement memory: the load re-arms discovery, the heartbeat re-advertises
|
|
10
|
+
* the sid, the hub clears its close tombstone, and the conversation the user
|
|
11
|
+
* closed resurrects on every surface (observed live 2026-10-28: closed
|
|
12
|
+
* 00:48, resurrected by an auto load at 01:07 with a real turn).
|
|
13
|
+
*
|
|
14
|
+
* This store is the durable half of the retirement: the close endpoint
|
|
15
|
+
* records EVERY id spelling of the conversation (editor aliases + backend
|
|
16
|
+
* sess_ id), the auto-load retirement gate reads it (`loadSession`), and
|
|
17
|
+
* genuine use (`markSessionActive` — a prompt, a user-intent load) clears
|
|
18
|
+
* it, preserving ADR-0006's self-heal: touching the session reopens it.
|
|
19
|
+
*
|
|
20
|
+
* Same durability rules as the lazy-alias store: a tiny JSON file under
|
|
21
|
+
* ~/.zcode/v2 shared by every bridge process, written only via temp+rename.
|
|
22
|
+
* Best-effort by design — read failures read as "nothing closed", write
|
|
23
|
+
* failures are logged and simply do not stick.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* True when this id spelling belongs to a remotely closed conversation the
|
|
27
|
+
* user has not touched since (within the TTL). The auto-load retirement gate
|
|
28
|
+
* consults this; a USER-intent load or real use clears the record instead.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isClosedSessionId(sid: string | undefined): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Record every id spelling of a remotely closed conversation (the close
|
|
33
|
+
* endpoint's alias set plus the backend sess_ id). TTL-expired entries are
|
|
34
|
+
* pruned at write.
|
|
35
|
+
*/
|
|
36
|
+
export declare function recordClosedSessionIds(sids: Array<string | undefined>): void;
|
|
37
|
+
/**
|
|
38
|
+
* Clear the close record for a conversation's id spellings — genuine use
|
|
39
|
+
* (`markSessionActive`): a prompt turn or a user-intent load reopens the
|
|
40
|
+
* conversation and the next serve-bridge respawn must not re-retire it.
|
|
41
|
+
* No-op (no write) when nothing is recorded.
|
|
42
|
+
*/
|
|
43
|
+
export declare function clearClosedSessionIds(sids: Array<string | undefined>): void;
|
|
44
|
+
//# sourceMappingURL=closed-sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"closed-sessions.d.ts","sourceRoot":"","sources":["../src/closed-sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA0DH;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIlE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,CAU5E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,CAY3E"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge-side remote-close record (ADR-0006 persistence amendment).
|
|
3
|
+
*
|
|
4
|
+
* A remote close retires the conversation from discovery with an IN-MEMORY
|
|
5
|
+
* stamp (`server.discoveryRetiredAt`) — and a serve-origin bridge then
|
|
6
|
+
* EXITS itself (last conversation closed), so the stamp dies with the
|
|
7
|
+
* process. When the hub incubates the next serve bridge and a client's
|
|
8
|
+
* reconnect ladder session/loads the conversation, the fresh process has no
|
|
9
|
+
* retirement memory: the load re-arms discovery, the heartbeat re-advertises
|
|
10
|
+
* the sid, the hub clears its close tombstone, and the conversation the user
|
|
11
|
+
* closed resurrects on every surface (observed live 2026-10-28: closed
|
|
12
|
+
* 00:48, resurrected by an auto load at 01:07 with a real turn).
|
|
13
|
+
*
|
|
14
|
+
* This store is the durable half of the retirement: the close endpoint
|
|
15
|
+
* records EVERY id spelling of the conversation (editor aliases + backend
|
|
16
|
+
* sess_ id), the auto-load retirement gate reads it (`loadSession`), and
|
|
17
|
+
* genuine use (`markSessionActive` — a prompt, a user-intent load) clears
|
|
18
|
+
* it, preserving ADR-0006's self-heal: touching the session reopens it.
|
|
19
|
+
*
|
|
20
|
+
* Same durability rules as the lazy-alias store: a tiny JSON file under
|
|
21
|
+
* ~/.zcode/v2 shared by every bridge process, written only via temp+rename.
|
|
22
|
+
* Best-effort by design — read failures read as "nothing closed", write
|
|
23
|
+
* failures are logged and simply do not stick.
|
|
24
|
+
*/
|
|
25
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
26
|
+
import path from "node:path";
|
|
27
|
+
import process from "node:process";
|
|
28
|
+
import { warn, zcodeHomeDir } from "./utils.js";
|
|
29
|
+
/** Store file lives next to the lazy-alias store under ~/.zcode/v2/. */
|
|
30
|
+
const STORE_FILENAME = "acp-closed-sessions.json";
|
|
31
|
+
/**
|
|
32
|
+
* Entries older than this expire: a conversation closed this long ago
|
|
33
|
+
* without a single bridge-side touch stays closed in any practical sense,
|
|
34
|
+
* and the expiry bounds staleness mistakes (a desktop-side reopen that never
|
|
35
|
+
* passed through a bridge would otherwise keep the App's tab retired
|
|
36
|
+
* forever).
|
|
37
|
+
*/
|
|
38
|
+
const TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
39
|
+
/** Resolved at call time so tests can stub HOME/ZCODE_HOME without re-importing. */
|
|
40
|
+
function storePath() {
|
|
41
|
+
return path.join(zcodeHomeDir(), "v2", STORE_FILENAME);
|
|
42
|
+
}
|
|
43
|
+
function readTable() {
|
|
44
|
+
try {
|
|
45
|
+
const p = storePath();
|
|
46
|
+
if (!existsSync(p))
|
|
47
|
+
return {};
|
|
48
|
+
const raw = JSON.parse(readFileSync(p, "utf8"));
|
|
49
|
+
if (typeof raw !== "object" || raw === null)
|
|
50
|
+
return {};
|
|
51
|
+
const out = {};
|
|
52
|
+
for (const [sid, at] of Object.entries(raw)) {
|
|
53
|
+
if (typeof at === "number")
|
|
54
|
+
out[sid] = at;
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Corrupt or unreadable reads as nothing closed — never fatal.
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function persist(table) {
|
|
64
|
+
try {
|
|
65
|
+
const p = storePath();
|
|
66
|
+
const dir = path.dirname(p);
|
|
67
|
+
mkdirSync(dir, { recursive: true });
|
|
68
|
+
const tmp = `${p}.tmp-${process.pid}`;
|
|
69
|
+
writeFileSync(tmp, JSON.stringify(table, null, 2));
|
|
70
|
+
renameSync(tmp, p);
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
warn(`closed-sessions: store write failed ` +
|
|
74
|
+
`(${e instanceof Error ? e.message : String(e)}) — the close record will not stick`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* True when this id spelling belongs to a remotely closed conversation the
|
|
79
|
+
* user has not touched since (within the TTL). The auto-load retirement gate
|
|
80
|
+
* consults this; a USER-intent load or real use clears the record instead.
|
|
81
|
+
*/
|
|
82
|
+
export function isClosedSessionId(sid) {
|
|
83
|
+
if (typeof sid !== "string" || sid.length === 0)
|
|
84
|
+
return false;
|
|
85
|
+
const at = readTable()[sid];
|
|
86
|
+
return at !== undefined && Date.now() - at <= TTL_MS;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Record every id spelling of a remotely closed conversation (the close
|
|
90
|
+
* endpoint's alias set plus the backend sess_ id). TTL-expired entries are
|
|
91
|
+
* pruned at write.
|
|
92
|
+
*/
|
|
93
|
+
export function recordClosedSessionIds(sids) {
|
|
94
|
+
const ids = sids.filter((sid) => typeof sid === "string" && sid.length > 0);
|
|
95
|
+
if (ids.length === 0)
|
|
96
|
+
return;
|
|
97
|
+
const table = readTable();
|
|
98
|
+
const now = Date.now();
|
|
99
|
+
for (const [sid, at] of Object.entries(table)) {
|
|
100
|
+
if (now - at > TTL_MS)
|
|
101
|
+
delete table[sid];
|
|
102
|
+
}
|
|
103
|
+
for (const sid of new Set(ids))
|
|
104
|
+
table[sid] = now;
|
|
105
|
+
persist(table);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Clear the close record for a conversation's id spellings — genuine use
|
|
109
|
+
* (`markSessionActive`): a prompt turn or a user-intent load reopens the
|
|
110
|
+
* conversation and the next serve-bridge respawn must not re-retire it.
|
|
111
|
+
* No-op (no write) when nothing is recorded.
|
|
112
|
+
*/
|
|
113
|
+
export function clearClosedSessionIds(sids) {
|
|
114
|
+
const ids = sids.filter((sid) => typeof sid === "string" && sid.length > 0);
|
|
115
|
+
if (ids.length === 0)
|
|
116
|
+
return;
|
|
117
|
+
const table = readTable();
|
|
118
|
+
let touched = false;
|
|
119
|
+
for (const sid of new Set(ids)) {
|
|
120
|
+
if (sid in table) {
|
|
121
|
+
delete table[sid];
|
|
122
|
+
touched = true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (touched)
|
|
126
|
+
persist(table);
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=closed-sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"closed-sessions.js","sourceRoot":"","sources":["../src/closed-sessions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,OAAO,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEhD,wEAAwE;AACxE,MAAM,cAAc,GAAG,0BAA0B,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAExC,oFAAoF;AACpF,SAAS,SAAS;IAChB,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;AACzD,CAAC;AAED,SAAS,SAAS;IAChB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAA4B,CAAC;QAC3E,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,EAAE,CAAC;QACvD,MAAM,GAAG,GAA2B,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5C,IAAI,OAAO,EAAE,KAAK,QAAQ;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QAC5C,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,KAA6B;IAC5C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAC5B,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,OAAO,CAAC,GAAG,EAAE,CAAC;QACtC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACnD,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CACF,sCAAsC;YACpC,IAAI,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,qCAAqC,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC;IAC5B,OAAO,EAAE,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,MAAM,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAA+B;IACpE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3F,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC7B,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,KAAK,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9C,IAAI,GAAG,GAAG,EAAE,GAAG,MAAM;YAAE,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC;QAAE,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACjD,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAA+B;IACnE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAiB,EAAE,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3F,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC7B,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,GAAG,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,IAAI,GAAG,IAAI,KAAK,EAAE,CAAC;YACjB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC;YAClB,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;IACD,IAAI,OAAO;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/handlers/session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,KAAK,GAAG,MAAM,0BAA0B,CAAC;AAGrD,OAAO,EAAwB,KAAK,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAGxF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1E,OAAO,KAAK,EAGV,YAAY,EAGb,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/handlers/session.ts"],"names":[],"mappings":"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"}
|
package/dist/handlers/session.js
CHANGED
|
@@ -33,7 +33,8 @@ import { effectiveWorkflowGate, effectiveWorkflowGateNow, ensureWorkflowPolicyPu
|
|
|
33
33
|
import { messages } from "../i18n.js";
|
|
34
34
|
import { lookupLazySession, lookupModelChoiceByZcodeSid, recordMaterializedSession, rememberLazySession, } from "../lazy-sessions.js";
|
|
35
35
|
import { refreshTerminalTabTitle } from "../terminal-title.js";
|
|
36
|
-
import {
|
|
36
|
+
import { isClosedSessionId } from "../closed-sessions.js";
|
|
37
|
+
import { buildDiffContent, EventTranslator, extractLocations, formatTurnError, isBackendLostError, isGatewayBlipTurnError, isTransientTurnError, ProjectionDiffer, } from "../translators/index.js";
|
|
37
38
|
import { clientConnectionRoot, log, warn, zcodeHomeDir } from "../utils.js";
|
|
38
39
|
import { dispatchEvent } from "./dispatch.js";
|
|
39
40
|
import { emitSessionTurnState, sendAvailableCommandsDeferred, sendSessionUpdate, sendTextChunk, withReplayBatch, } from "./io.js";
|
|
@@ -1257,8 +1258,14 @@ export async function loadSession(server, params, cx, opts = {}) {
|
|
|
1257
1258
|
// on every surface and the auto-409 gate disarms with it. The response
|
|
1258
1259
|
// discloses the suppression via `_meta.zcode.sessionClosed: true` so the
|
|
1259
1260
|
// client can retire its tab locally. "user" (the default — old clients)
|
|
1260
|
-
// keeps the manual-reopen re-arm exactly as before.
|
|
1261
|
-
|
|
1261
|
+
// keeps the manual-reopen re-arm exactly as before. Retirement is checked
|
|
1262
|
+
// BOTH in memory AND in the durable close record: a serve-origin bridge
|
|
1263
|
+
// EXITS on last close, so the hub-incubated successor process has no
|
|
1264
|
+
// in-memory stamp — without the durable lookup a reconnect ladder's auto
|
|
1265
|
+
// load resurrected the closed conversation on the fresh bridge (observed
|
|
1266
|
+
// 2026-10-28: closed 00:48, auto-loaded back to life 01:07).
|
|
1267
|
+
const retiredForAuto = readLoadIntent(params) === "auto" &&
|
|
1268
|
+
(server.isDiscoveryRetired(acpSid) || isClosedSessionId(acpSid) || isClosedSessionId(zcodeSid));
|
|
1262
1269
|
if (!alreadyLive) {
|
|
1263
1270
|
// Same mcpServers contract as resume: the client may re-declare them on
|
|
1264
1271
|
// load; a stored set keeps riding along when it doesn't (#193).
|
|
@@ -1876,17 +1883,32 @@ export async function runOneTurn(server, opts) {
|
|
|
1876
1883
|
suppressRetryNotice = true;
|
|
1877
1884
|
continue;
|
|
1878
1885
|
}
|
|
1879
|
-
//
|
|
1880
|
-
// failures,
|
|
1881
|
-
//
|
|
1886
|
+
// Transient failures and one-shot gateway blips are retried; everything
|
|
1887
|
+
// else (send failures, terminal turn errors, cancellation) propagates
|
|
1888
|
+
// to the caller.
|
|
1882
1889
|
if (e instanceof TurnFailedError) {
|
|
1883
1890
|
const transient = isTransientTurnError(e.turnError);
|
|
1884
|
-
|
|
1891
|
+
// A relay gateway's transient fault arrives as a request-failure
|
|
1892
|
+
// cause code the upstream classifier marked non-retryable — its
|
|
1893
|
+
// verdict judges the request shape, not the gateway's health
|
|
1894
|
+
// (observed 2026-10-28: intermittent 400 invalid_request_error from
|
|
1895
|
+
// a forwarding gateway, resend succeeded). Give those a bounded
|
|
1896
|
+
// resend too; quota/context-exceeded/model-not-found stay terminal.
|
|
1897
|
+
const gatewayBlip = !transient && isGatewayBlipTurnError(e.turnError);
|
|
1898
|
+
if (attempt < MAX_TURN_ATTEMPTS && !turn.cancelled && (transient || gatewayBlip)) {
|
|
1885
1899
|
lastTurnError = e.turnError;
|
|
1886
1900
|
continue;
|
|
1887
1901
|
}
|
|
1888
|
-
if (!transient)
|
|
1902
|
+
if (!transient && !gatewayBlip)
|
|
1889
1903
|
throw turnFailureRequestError(e);
|
|
1904
|
+
// Retries exhausted on a transient/gateway-blip failure: degrade
|
|
1905
|
+
// gracefully below (user-visible notice + end_turn, goal-loop
|
|
1906
|
+
// pauses via its structured throw) instead of a hard error that
|
|
1907
|
+
// stops the session. A cancelled turn keeps the raw propagate.
|
|
1908
|
+
if (turn.cancelled)
|
|
1909
|
+
throw e;
|
|
1910
|
+
lastTurnError = e.turnError;
|
|
1911
|
+
break;
|
|
1890
1912
|
}
|
|
1891
1913
|
throw e;
|
|
1892
1914
|
}
|