@f5-sales-demo/xcsh 19.85.5 → 19.85.7
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "19.85.
|
|
4
|
+
"version": "19.85.7",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -56,13 +56,13 @@
|
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
58
58
|
"@mozilla/readability": "^0.6",
|
|
59
|
-
"@f5-sales-demo/xcsh-stats": "19.85.
|
|
60
|
-
"@f5-sales-demo/pi-agent-core": "19.85.
|
|
61
|
-
"@f5-sales-demo/pi-ai": "19.85.
|
|
62
|
-
"@f5-sales-demo/pi-natives": "19.85.
|
|
63
|
-
"@f5-sales-demo/pi-resource-management": "19.85.
|
|
64
|
-
"@f5-sales-demo/pi-tui": "19.85.
|
|
65
|
-
"@f5-sales-demo/pi-utils": "19.85.
|
|
59
|
+
"@f5-sales-demo/xcsh-stats": "19.85.7",
|
|
60
|
+
"@f5-sales-demo/pi-agent-core": "19.85.7",
|
|
61
|
+
"@f5-sales-demo/pi-ai": "19.85.7",
|
|
62
|
+
"@f5-sales-demo/pi-natives": "19.85.7",
|
|
63
|
+
"@f5-sales-demo/pi-resource-management": "19.85.7",
|
|
64
|
+
"@f5-sales-demo/pi-tui": "19.85.7",
|
|
65
|
+
"@f5-sales-demo/pi-utils": "19.85.7",
|
|
66
66
|
"@sinclair/typebox": "^0.34",
|
|
67
67
|
"@xterm/headless": "^6.0",
|
|
68
68
|
"ajv": "^8.20",
|
|
@@ -82,13 +82,25 @@ class RpcHostToolAdapter<TParams extends TSchema = TSchema, TTheme extends Theme
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* How long a host tool may go with NO response — neither a `host_tool_result` nor a
|
|
87
|
+
* `host_tool_update` — before we give up on it. An unanswered call (e.g. an Office
|
|
88
|
+
* task-pane whose WebView the host suspended when it lost focus) would otherwise hang
|
|
89
|
+
* the agent turn forever, and since turns are queued behind the active one, every
|
|
90
|
+
* later turn wedges too. This is IDLE time, reset by each streamed update, so a
|
|
91
|
+
* legitimately slow-but-progressing tool is never cut off — only true silence trips it.
|
|
92
|
+
*/
|
|
93
|
+
export const HOST_TOOL_IDLE_TIMEOUT_MS = 60_000;
|
|
94
|
+
|
|
85
95
|
export class RpcHostToolBridge {
|
|
86
96
|
#output: RpcHostToolOutput;
|
|
87
97
|
#definitions = new Map<string, RpcHostToolDefinition>();
|
|
88
98
|
#pendingCalls = new Map<string, PendingHostToolCall>();
|
|
99
|
+
#idleTimeoutMs: number;
|
|
89
100
|
|
|
90
|
-
constructor(output: RpcHostToolOutput) {
|
|
101
|
+
constructor(output: RpcHostToolOutput, opts?: { idleTimeoutMs?: number }) {
|
|
91
102
|
this.#output = output;
|
|
103
|
+
this.#idleTimeoutMs = opts?.idleTimeoutMs ?? HOST_TOOL_IDLE_TIMEOUT_MS;
|
|
92
104
|
}
|
|
93
105
|
|
|
94
106
|
getToolNames(): string[] {
|
|
@@ -141,7 +153,23 @@ export class RpcHostToolBridge {
|
|
|
141
153
|
const { promise, resolve, reject } = Promise.withResolvers<AgentToolResult<unknown>>();
|
|
142
154
|
let settled = false;
|
|
143
155
|
|
|
156
|
+
// ---- idle timer (reset by updates; fires → cancel + reject) ----
|
|
157
|
+
let idleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
158
|
+
const clearIdle = (): void => {
|
|
159
|
+
if (idleTimer !== undefined) {
|
|
160
|
+
clearTimeout(idleTimer);
|
|
161
|
+
idleTimer = undefined;
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
const armIdle = (): void => {
|
|
165
|
+
clearIdle();
|
|
166
|
+
idleTimer = setTimeout(onIdleTimeout, this.#idleTimeoutMs);
|
|
167
|
+
// Don't keep the process alive just for this backstop.
|
|
168
|
+
if (typeof idleTimer === "object" && "unref" in idleTimer) idleTimer.unref();
|
|
169
|
+
};
|
|
170
|
+
|
|
144
171
|
const cleanup = () => {
|
|
172
|
+
clearIdle();
|
|
145
173
|
signal?.removeEventListener("abort", onAbort);
|
|
146
174
|
this.#pendingCalls.delete(id);
|
|
147
175
|
};
|
|
@@ -158,6 +186,23 @@ export class RpcHostToolBridge {
|
|
|
158
186
|
reject(new Error(`Host tool "${definition.name}" was aborted`));
|
|
159
187
|
};
|
|
160
188
|
|
|
189
|
+
const onIdleTimeout = () => {
|
|
190
|
+
if (settled) return;
|
|
191
|
+
settled = true;
|
|
192
|
+
cleanup();
|
|
193
|
+
this.#output({
|
|
194
|
+
type: "host_tool_cancel",
|
|
195
|
+
id: Snowflake.next() as string,
|
|
196
|
+
targetId: id,
|
|
197
|
+
});
|
|
198
|
+
reject(
|
|
199
|
+
new Error(
|
|
200
|
+
`Host tool "${definition.name}" did not respond within ${this.#idleTimeoutMs / 1000}s ` +
|
|
201
|
+
"(the host may be unresponsive — a suspended Office WebView loses its connection)",
|
|
202
|
+
),
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
161
206
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
162
207
|
this.#pendingCalls.set(id, {
|
|
163
208
|
resolve: result => {
|
|
@@ -172,7 +217,11 @@ export class RpcHostToolBridge {
|
|
|
172
217
|
cleanup();
|
|
173
218
|
reject(error);
|
|
174
219
|
},
|
|
175
|
-
onUpdate
|
|
220
|
+
onUpdate: partial => {
|
|
221
|
+
// A streamed update proves the host is alive — reset the idle clock.
|
|
222
|
+
armIdle();
|
|
223
|
+
onUpdate?.(partial);
|
|
224
|
+
},
|
|
176
225
|
});
|
|
177
226
|
|
|
178
227
|
this.#output({
|
|
@@ -183,6 +232,9 @@ export class RpcHostToolBridge {
|
|
|
183
232
|
arguments: args,
|
|
184
233
|
});
|
|
185
234
|
|
|
235
|
+
// Start the idle clock AFTER sending the call.
|
|
236
|
+
armIdle();
|
|
237
|
+
|
|
186
238
|
return promise;
|
|
187
239
|
}
|
|
188
240
|
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "19.85.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "19.85.7",
|
|
21
|
+
"commit": "9ca40d6aab40f53a85bba28e4ff8b0f6ceed1782",
|
|
22
|
+
"shortCommit": "9ca40d6",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.85.
|
|
25
|
-
"commitDate": "2026-07-
|
|
26
|
-
"buildDate": "2026-07-
|
|
24
|
+
"tag": "v19.85.7",
|
|
25
|
+
"commitDate": "2026-07-24T13:17:17Z",
|
|
26
|
+
"buildDate": "2026-07-24T13:42:27.292Z",
|
|
27
27
|
"dirty": true,
|
|
28
28
|
"prNumber": "",
|
|
29
29
|
"repoUrl": "https://github.com/f5-sales-demo/xcsh",
|
|
30
30
|
"repoSlug": "f5-sales-demo/xcsh",
|
|
31
|
-
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/
|
|
32
|
-
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.85.
|
|
31
|
+
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/9ca40d6aab40f53a85bba28e4ff8b0f6ceed1782",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v19.85.7"
|
|
33
33
|
};
|
|
@@ -280,7 +280,7 @@ export const TERRAFORM_INDEX: TerraformIndex = {
|
|
|
280
280
|
"Advertise_policy object controls how and where a service represented by a given virtual_host object is advertised to consumers. configuration",
|
|
281
281
|
required: ["name", "namespace", "address", "protocol", "skip_xff_append"],
|
|
282
282
|
minimal_config:
|
|
283
|
-
'resource "xcsh_advertise_policy" "example" {\n name = "example-advertise-policy"\n namespace = "staging"\n\n address = "example-value"\n protocol = "
|
|
283
|
+
'resource "xcsh_advertise_policy" "example" {\n name = "example-advertise-policy"\n namespace = "staging"\n\n address = "example-value"\n protocol = "TCP"\n skip_xff_append = true\n}',
|
|
284
284
|
dependencies: {
|
|
285
285
|
requires: [],
|
|
286
286
|
},
|
|
@@ -861,7 +861,7 @@ export const TERRAFORM_INDEX: TerraformIndex = {
|
|
|
861
861
|
description: "Endpoint will create the object in the storage backend for namespace metadata.namespace",
|
|
862
862
|
required: ["name", "namespace", "health_check_port", "port", "protocol"],
|
|
863
863
|
minimal_config:
|
|
864
|
-
'resource "xcsh_endpoint" "example" {\n name = "example-endpoint"\n namespace = "staging"\n\n health_check_port = 1\n port = 1\n protocol = "
|
|
864
|
+
'resource "xcsh_endpoint" "example" {\n name = "example-endpoint"\n namespace = "staging"\n\n health_check_port = 1\n port = 1\n protocol = "TCP"\n}',
|
|
865
865
|
dependencies: {
|
|
866
866
|
requires: [],
|
|
867
867
|
},
|