@oh-my-pi/pi-coding-agent 17.2.11 → 17.2.12
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/CHANGELOG.md +13 -0
- package/dist/{CHANGELOG-d9xenpn9.md → CHANGELOG-k9ghy5sn.md} +13 -0
- package/dist/cli.js +10795 -10791
- package/dist/types/advisor/runtime.d.ts +1 -1
- package/dist/types/config/custom-models.d.ts +31 -0
- package/dist/types/config/model-config-values.d.ts +19 -0
- package/dist/types/config/model-patch.d.ts +93 -0
- package/dist/types/config/model-provider-discovery.d.ts +51 -0
- package/dist/types/config/model-registry.d.ts +5 -52
- package/dist/types/config/settings.d.ts +5 -3
- package/dist/types/debug/raw-sse-buffer.d.ts +9 -0
- package/dist/types/discovery/agent-plugin-format.d.ts +6 -13
- package/dist/types/discovery/contained-path.d.ts +2 -3
- package/dist/types/eval/executor-base.d.ts +8 -2
- package/dist/types/eval/kernel-session-registry.d.ts +60 -0
- package/dist/types/export/share.d.ts +1 -1
- package/dist/types/lsp/diagnostics.d.ts +96 -0
- package/dist/types/lsp/index.d.ts +7 -128
- package/dist/types/lsp/servers.d.ts +72 -0
- package/dist/types/lsp/tool.d.ts +42 -0
- package/dist/types/lsp/workspace-diagnostics.d.ts +12 -0
- package/dist/types/lsp/writethrough.d.ts +33 -0
- package/dist/types/mcp/transports/header-policy.d.ts +2 -1
- package/dist/types/modes/components/agent-hub-projection.d.ts +2 -7
- package/dist/types/modes/components/agent-hub-renderer.d.ts +0 -7
- package/dist/types/modes/theme/color.d.ts +19 -0
- package/dist/types/modes/theme/loader.d.ts +19 -0
- package/dist/types/modes/theme/schema.d.ts +175 -0
- package/dist/types/modes/theme/symbols.d.ts +28 -0
- package/dist/types/modes/theme/theme-class.d.ts +244 -0
- package/dist/types/modes/theme/theme.d.ts +9 -280
- package/dist/types/modes/theme/tui-adapters.d.ts +13 -0
- package/dist/types/registry/agent-registry.d.ts +1 -3
- package/dist/types/secrets/index.d.ts +3 -1
- package/dist/types/secrets/message-transform.d.ts +40 -0
- package/dist/types/secrets/obfuscator.d.ts +0 -108
- package/dist/types/secrets/placeholder-scan.d.ts +95 -0
- package/dist/types/secrets/placeholder.d.ts +94 -0
- package/dist/types/secrets/replacement.d.ts +82 -0
- package/dist/types/session/agent-session-types.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/session-handoff.d.ts +3 -3
- package/dist/types/session/session-manager.d.ts +32 -0
- package/dist/types/session/session-provider-boundary.d.ts +1 -1
- package/dist/types/session/turn-recovery.d.ts +2 -2
- package/dist/types/slash-commands/builtin-collaboration.d.ts +2 -0
- package/dist/types/slash-commands/builtin-completions.d.ts +36 -0
- package/dist/types/slash-commands/builtin-control.d.ts +2 -0
- package/dist/types/slash-commands/builtin-lifecycle.d.ts +3 -0
- package/dist/types/slash-commands/builtin-marketplace.d.ts +11 -0
- package/dist/types/slash-commands/builtin-modes.d.ts +5 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -1
- package/dist/types/slash-commands/builtin-session.d.ts +2 -0
- package/dist/types/tools/gh-common.d.ts +69 -0
- package/dist/types/tools/gh-pr-checkout.d.ts +84 -0
- package/dist/types/tools/gh-pr-diff.d.ts +102 -0
- package/dist/types/tools/gh-run-watch.d.ts +78 -0
- package/dist/types/tools/gh-search.d.ts +61 -0
- package/dist/types/tools/gh-types.d.ts +340 -0
- package/dist/types/tools/gh-view.d.ts +88 -0
- package/dist/types/tools/gh.d.ts +4 -201
- package/dist/types/tools/read-archive.d.ts +16 -0
- package/dist/types/tools/read-format.d.ts +104 -0
- package/dist/types/tools/read-path-resolution.d.ts +19 -0
- package/dist/types/tools/read-pdf-images.d.ts +12 -0
- package/dist/types/tools/read-renderer.d.ts +24 -0
- package/dist/types/tools/read-selector.d.ts +27 -0
- package/dist/types/tools/read-sqlite.d.ts +16 -0
- package/dist/types/tools/read-summary.d.ts +19 -0
- package/dist/types/tools/read.d.ts +1 -23
- package/dist/types/tools/shell-tokenize.d.ts +2 -1
- package/dist/types/utils/changelog.d.ts +0 -5
- package/package.json +13 -13
- package/src/advisor/runtime.ts +12 -7
- package/src/config/custom-models.ts +188 -0
- package/src/config/model-config-values.ts +128 -0
- package/src/config/model-patch.ts +252 -0
- package/src/config/model-provider-discovery.ts +132 -0
- package/src/config/model-registry.ts +64 -704
- package/src/config/settings.ts +7 -3
- package/src/debug/raw-sse-buffer.ts +20 -0
- package/src/discovery/agent-plugin-format.ts +7 -7
- package/src/discovery/contained-path.ts +2 -5
- package/src/edit/hashline/diff.ts +5 -1
- package/src/eval/executor-base.ts +39 -6
- package/src/eval/jl/executor.ts +82 -371
- package/src/eval/kernel-session-registry.ts +398 -0
- package/src/eval/py/executor.ts +53 -261
- package/src/eval/rb/executor.ts +36 -279
- package/src/export/share.ts +2 -1
- package/src/lsp/diagnostics.ts +516 -0
- package/src/lsp/index.ts +20 -2819
- package/src/lsp/servers.ts +296 -0
- package/src/lsp/tool.ts +1352 -0
- package/src/lsp/workspace-diagnostics.ts +170 -0
- package/src/lsp/writethrough.ts +561 -0
- package/src/mcp/transports/header-policy.ts +1 -1
- package/src/modes/components/agent-hub-projection.ts +2 -2
- package/src/modes/components/agent-hub-renderer.ts +3 -7
- package/src/modes/controllers/command-controller.ts +4 -1
- package/src/modes/theme/color.ts +133 -0
- package/src/modes/theme/loader.ts +178 -0
- package/src/modes/theme/schema.ts +263 -0
- package/src/modes/theme/symbols.ts +1000 -0
- package/src/modes/theme/theme-class.ts +611 -0
- package/src/modes/theme/theme.ts +27 -2453
- package/src/modes/theme/tui-adapters.ts +279 -0
- package/src/registry/agent-registry.ts +2 -2
- package/src/secrets/index.ts +6 -12
- package/src/secrets/message-transform.ts +287 -0
- package/src/secrets/obfuscator.ts +39 -1303
- package/src/secrets/placeholder-scan.ts +506 -0
- package/src/secrets/placeholder.ts +309 -0
- package/src/secrets/replacement.ts +216 -0
- package/src/session/agent-session-types.ts +6 -0
- package/src/session/agent-session.ts +113 -7
- package/src/session/indexed-session-storage.ts +7 -2
- package/src/session/session-advisors.ts +32 -34
- package/src/session/session-handoff.ts +39 -20
- package/src/session/session-manager.ts +67 -3
- package/src/session/session-provider-boundary.ts +3 -6
- package/src/session/turn-recovery.ts +21 -12
- package/src/slash-commands/builtin-collaboration.ts +504 -0
- package/src/slash-commands/builtin-completions.ts +291 -0
- package/src/slash-commands/builtin-control.ts +78 -0
- package/src/slash-commands/builtin-lifecycle.ts +506 -0
- package/src/slash-commands/builtin-marketplace.ts +567 -0
- package/src/slash-commands/builtin-modes.ts +518 -0
- package/src/slash-commands/builtin-registry.ts +21 -3000
- package/src/slash-commands/builtin-session.ts +592 -0
- package/src/task/executor.ts +17 -14
- package/src/tools/gh-common.ts +288 -0
- package/src/tools/gh-pr-checkout.ts +679 -0
- package/src/tools/gh-pr-diff.ts +473 -0
- package/src/tools/gh-run-watch.ts +1015 -0
- package/src/tools/gh-search.ts +500 -0
- package/src/tools/gh-types.ts +379 -0
- package/src/tools/gh-view.ts +612 -0
- package/src/tools/gh.ts +109 -3821
- package/src/tools/read-archive.ts +209 -0
- package/src/tools/read-format.ts +593 -0
- package/src/tools/read-path-resolution.ts +36 -0
- package/src/tools/read-pdf-images.ts +250 -0
- package/src/tools/read-renderer.ts +289 -0
- package/src/tools/read-selector.ts +84 -0
- package/src/tools/read-sqlite.ts +215 -0
- package/src/tools/read-summary.ts +199 -0
- package/src/tools/read.ts +77 -1820
- package/src/tools/shell-tokenize.ts +1 -1
- package/src/utils/changelog.ts +1 -1
- package/src/utils/title-generator.ts +3 -1
- package/src/web/search/providers/zai.ts +12 -3
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { logger } from "@oh-my-pi/pi-utils";
|
|
2
|
+
import { throwIfAborted } from "../tools/tool-errors";
|
|
3
|
+
import {
|
|
4
|
+
getActiveClients,
|
|
5
|
+
getActiveOrPendingClient,
|
|
6
|
+
getOrCreateClient,
|
|
7
|
+
type LspServerStatus,
|
|
8
|
+
notifySaved,
|
|
9
|
+
sendNotification,
|
|
10
|
+
sendRequest,
|
|
11
|
+
setIdleTimeout,
|
|
12
|
+
shutdownClientInstance,
|
|
13
|
+
syncContent,
|
|
14
|
+
WARMUP_TIMEOUT_MS,
|
|
15
|
+
} from "./client";
|
|
16
|
+
import { getServersForFile, type LspConfig, loadConfig } from "./config";
|
|
17
|
+
import { MUX_RESTART_METHOD } from "./mux/protocol";
|
|
18
|
+
import type { LspClient, ServerConfig } from "./types";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* LSP actions that do not mutate the workspace or language-server state.
|
|
22
|
+
* Anything not in this set (rename, code_actions with apply, rename_file,
|
|
23
|
+
* reload, raw request, etc.) is classified as write-tier.
|
|
24
|
+
*/
|
|
25
|
+
export const LSP_READONLY_ACTIONS: ReadonlySet<string> = new Set([
|
|
26
|
+
"diagnostics",
|
|
27
|
+
"definition",
|
|
28
|
+
"type_definition",
|
|
29
|
+
"implementation",
|
|
30
|
+
"references",
|
|
31
|
+
"hover",
|
|
32
|
+
"symbols",
|
|
33
|
+
"status",
|
|
34
|
+
"capabilities",
|
|
35
|
+
]);
|
|
36
|
+
|
|
37
|
+
export interface LspStartupServerInfo {
|
|
38
|
+
name: string;
|
|
39
|
+
status: "connecting" | "ready" | "error" | "available";
|
|
40
|
+
fileTypes: string[];
|
|
41
|
+
error?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Result from warming up LSP servers */
|
|
45
|
+
export interface LspWarmupResult {
|
|
46
|
+
servers: Array<LspStartupServerInfo & { status: "ready" | "error" }>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Options for warming up LSP servers */
|
|
50
|
+
export interface LspWarmupOptions {
|
|
51
|
+
/** Called when starting to connect to servers */
|
|
52
|
+
onConnecting?: (serverNames: string[]) => void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function discoverStartupLspServers(
|
|
56
|
+
cwd: string,
|
|
57
|
+
status: LspStartupServerInfo["status"] = "connecting",
|
|
58
|
+
): LspStartupServerInfo[] {
|
|
59
|
+
const config = loadConfig(cwd);
|
|
60
|
+
return getLspServers(config).map(([name, serverConfig]) => ({
|
|
61
|
+
name,
|
|
62
|
+
status,
|
|
63
|
+
fileTypes: serverConfig.fileTypes,
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Warm up LSP servers for a directory by connecting to all detected servers.
|
|
69
|
+
* This should be called at startup to avoid cold-start delays.
|
|
70
|
+
*
|
|
71
|
+
* @param cwd - Working directory to detect and start servers for
|
|
72
|
+
* @param options - Optional callbacks for progress reporting
|
|
73
|
+
* @returns Status of each server that was started
|
|
74
|
+
*/
|
|
75
|
+
export async function warmupLspServers(cwd: string, options?: LspWarmupOptions): Promise<LspWarmupResult> {
|
|
76
|
+
const config = loadConfig(cwd);
|
|
77
|
+
setIdleTimeout(config.idleTimeoutMs);
|
|
78
|
+
const servers: LspWarmupResult["servers"] = [];
|
|
79
|
+
const lspServers = getLspServers(config);
|
|
80
|
+
|
|
81
|
+
// Notify caller which servers we're connecting to
|
|
82
|
+
if (lspServers.length > 0 && options?.onConnecting) {
|
|
83
|
+
options.onConnecting(lspServers.map(([name]) => name));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Start all detected servers in parallel with a short timeout
|
|
87
|
+
// Servers that don't respond quickly will be initialized lazily on first use
|
|
88
|
+
const results = await Promise.allSettled(
|
|
89
|
+
lspServers.map(async ([name, serverConfig]) => {
|
|
90
|
+
const client = await getOrCreateClient(serverConfig, cwd, serverConfig.warmupTimeoutMs ?? WARMUP_TIMEOUT_MS);
|
|
91
|
+
return { name, client, fileTypes: serverConfig.fileTypes };
|
|
92
|
+
}),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
for (let i = 0; i < results.length; i++) {
|
|
96
|
+
const result = results[i];
|
|
97
|
+
const [name, serverConfig] = lspServers[i];
|
|
98
|
+
if (result.status === "fulfilled") {
|
|
99
|
+
servers.push({
|
|
100
|
+
name: result.value.name,
|
|
101
|
+
status: "ready",
|
|
102
|
+
fileTypes: result.value.fileTypes,
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
const errorMsg = result.reason?.message ?? String(result.reason);
|
|
106
|
+
logger.warn("LSP server failed to start", { server: name, error: errorMsg });
|
|
107
|
+
servers.push({
|
|
108
|
+
name,
|
|
109
|
+
status: "error",
|
|
110
|
+
fileTypes: serverConfig.fileTypes,
|
|
111
|
+
error: errorMsg,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { servers };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get status of currently active LSP servers.
|
|
121
|
+
*/
|
|
122
|
+
export function getLspStatus(): LspServerStatus[] {
|
|
123
|
+
return getActiveClients();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Sync in-memory file content to all applicable LSP servers.
|
|
128
|
+
* Sends didOpen (if new) or didChange (if already open).
|
|
129
|
+
*
|
|
130
|
+
* @param absolutePath - Absolute path to the file
|
|
131
|
+
* @param content - The new file content
|
|
132
|
+
* @param cwd - Working directory for LSP config resolution
|
|
133
|
+
* @param servers - Servers to sync to
|
|
134
|
+
*/
|
|
135
|
+
export async function syncFileContent(
|
|
136
|
+
absolutePath: string,
|
|
137
|
+
content: string,
|
|
138
|
+
cwd: string,
|
|
139
|
+
servers: Array<[string, ServerConfig]>,
|
|
140
|
+
signal?: AbortSignal,
|
|
141
|
+
createMissing = true,
|
|
142
|
+
): Promise<void> {
|
|
143
|
+
throwIfAborted(signal);
|
|
144
|
+
await Promise.allSettled(
|
|
145
|
+
servers.map(async ([_serverName, serverConfig]) => {
|
|
146
|
+
throwIfAborted(signal);
|
|
147
|
+
if (serverConfig.createClient) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const client = createMissing
|
|
151
|
+
? await getOrCreateClient(serverConfig, cwd, undefined, signal)
|
|
152
|
+
: await getActiveOrPendingClient(serverConfig, cwd, signal);
|
|
153
|
+
if (!client) return;
|
|
154
|
+
throwIfAborted(signal);
|
|
155
|
+
await syncContent(client, absolutePath, content, signal);
|
|
156
|
+
}),
|
|
157
|
+
);
|
|
158
|
+
throwIfAborted(signal);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Notify all LSP servers that a file was saved.
|
|
163
|
+
* Assumes content was already synced via syncFileContent.
|
|
164
|
+
*
|
|
165
|
+
* @param absolutePath - Absolute path to the file
|
|
166
|
+
* @param cwd - Working directory for LSP config resolution
|
|
167
|
+
* @param servers - Servers to notify
|
|
168
|
+
*/
|
|
169
|
+
export async function notifyFileSaved(
|
|
170
|
+
absolutePath: string,
|
|
171
|
+
cwd: string,
|
|
172
|
+
servers: Array<[string, ServerConfig]>,
|
|
173
|
+
signal?: AbortSignal,
|
|
174
|
+
createMissing = true,
|
|
175
|
+
): Promise<void> {
|
|
176
|
+
throwIfAborted(signal);
|
|
177
|
+
await Promise.allSettled(
|
|
178
|
+
servers.map(async ([_serverName, serverConfig]) => {
|
|
179
|
+
throwIfAborted(signal);
|
|
180
|
+
if (serverConfig.createClient) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const client = createMissing
|
|
184
|
+
? await getOrCreateClient(serverConfig, cwd, undefined, signal)
|
|
185
|
+
: await getActiveOrPendingClient(serverConfig, cwd, signal);
|
|
186
|
+
if (!client) return;
|
|
187
|
+
await notifySaved(client, absolutePath, signal);
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
190
|
+
throwIfAborted(signal);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Cache config per cwd to avoid repeated file I/O
|
|
194
|
+
export const configCache = new Map<string, LspConfig>();
|
|
195
|
+
|
|
196
|
+
export function getConfig(cwd: string): LspConfig {
|
|
197
|
+
let config = configCache.get(cwd);
|
|
198
|
+
if (!config) {
|
|
199
|
+
config = loadConfig(cwd);
|
|
200
|
+
setIdleTimeout(config.idleTimeoutMs);
|
|
201
|
+
configCache.set(cwd, config);
|
|
202
|
+
}
|
|
203
|
+
return config;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function isCustomLinter(serverConfig: ServerConfig): boolean {
|
|
207
|
+
return Boolean(serverConfig.createClient);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function splitServers(servers: Array<[string, ServerConfig]>): {
|
|
211
|
+
lspServers: Array<[string, ServerConfig]>;
|
|
212
|
+
customLinterServers: Array<[string, ServerConfig]>;
|
|
213
|
+
} {
|
|
214
|
+
const lspServers: Array<[string, ServerConfig]> = [];
|
|
215
|
+
const customLinterServers: Array<[string, ServerConfig]> = [];
|
|
216
|
+
for (const entry of servers) {
|
|
217
|
+
if (isCustomLinter(entry[1])) {
|
|
218
|
+
customLinterServers.push(entry);
|
|
219
|
+
} else {
|
|
220
|
+
lspServers.push(entry);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return { lspServers, customLinterServers };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function getLspServers(config: LspConfig): Array<[string, ServerConfig]> {
|
|
227
|
+
return (Object.entries(config.servers) as Array<[string, ServerConfig]>).filter(
|
|
228
|
+
([, serverConfig]) => !isCustomLinter(serverConfig),
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function getLspServersForFile(config: LspConfig, filePath: string): Array<[string, ServerConfig]> {
|
|
233
|
+
return getServersForFile(config, filePath).filter(([, serverConfig]) => !isCustomLinter(serverConfig));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function getLspServerForFile(config: LspConfig, filePath: string): [string, ServerConfig] | null {
|
|
237
|
+
const servers = getLspServersForFile(config, filePath);
|
|
238
|
+
return servers.length > 0 ? servers[0] : null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function isProjectAwareLspServer(serverConfig: ServerConfig): boolean {
|
|
242
|
+
return !serverConfig.createClient && !serverConfig.isLinter;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** True when an LSP error indicates the server doesn't implement the requested method. */
|
|
246
|
+
export function isMethodNotFoundError(err: unknown): boolean {
|
|
247
|
+
if (!(err instanceof Error)) return false;
|
|
248
|
+
const msg = err.message.toLowerCase();
|
|
249
|
+
return (
|
|
250
|
+
msg.includes("method not found") ||
|
|
251
|
+
msg.includes("unhandled method") ||
|
|
252
|
+
msg.includes("not supported") ||
|
|
253
|
+
msg.includes("-32601")
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export async function reloadServer(client: LspClient, serverName: string, signal?: AbortSignal): Promise<string> {
|
|
258
|
+
throwIfAborted(signal);
|
|
259
|
+
// rust-analyzer exposes a real reload request. Every other server rejects it
|
|
260
|
+
// with method-not-found — that alone justifies the generic fallback. A caller
|
|
261
|
+
// cancel or tool timeout must propagate, never be mistaken for an unsupported
|
|
262
|
+
// method and swallowed into a bogus "Restarted" (issue #6369).
|
|
263
|
+
try {
|
|
264
|
+
await sendRequest(client, "rust-analyzer/reloadWorkspace", null, signal);
|
|
265
|
+
return `Reloaded ${serverName}`;
|
|
266
|
+
} catch (err) {
|
|
267
|
+
throwIfAborted(signal);
|
|
268
|
+
if (!isMethodNotFoundError(err)) throw err;
|
|
269
|
+
// Method not supported — fall through to the generic reload.
|
|
270
|
+
}
|
|
271
|
+
// workspace/didChangeConfiguration is a notification per spec; sending it
|
|
272
|
+
// as a request hangs until the tool deadline on servers that route it to
|
|
273
|
+
// the notification handler and never respond.
|
|
274
|
+
try {
|
|
275
|
+
await sendNotification(client, "workspace/didChangeConfiguration", { settings: {} }, signal);
|
|
276
|
+
return `Reloaded ${serverName}`;
|
|
277
|
+
} catch {
|
|
278
|
+
throwIfAborted(signal);
|
|
279
|
+
// The reload notification could not be delivered — the connection is
|
|
280
|
+
// wedged or the process already died. Tear the client down (removing it
|
|
281
|
+
// from the registry by identity and awaiting confirmed process exit) so
|
|
282
|
+
// the next request cold-starts a fresh client. A kill that never confirms
|
|
283
|
+
// exit is not a restart: surface the teardown failure truthfully.
|
|
284
|
+
//
|
|
285
|
+
// On a broker-shared link a per-session teardown only detaches this
|
|
286
|
+
// process while the wedged server keeps serving everyone else — ask the
|
|
287
|
+
// mux to kill the shared server first (best-effort; it also severs us).
|
|
288
|
+
if (client.proc.sharedMux) {
|
|
289
|
+
await sendNotification(client, MUX_RESTART_METHOD, undefined, AbortSignal.timeout(2_000)).catch(() => {});
|
|
290
|
+
}
|
|
291
|
+
if (!(await shutdownClientInstance(client))) {
|
|
292
|
+
throw new Error(`Failed to restart ${serverName}: server process did not exit after kill`);
|
|
293
|
+
}
|
|
294
|
+
return `Restarted ${serverName}`;
|
|
295
|
+
}
|
|
296
|
+
}
|