@f5xc-salesdemos/xcsh 18.63.0 → 18.63.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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5xc-salesdemos/xcsh",
|
|
4
|
-
"version": "18.63.
|
|
4
|
+
"version": "18.63.1",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5xc-salesdemos/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -48,12 +48,12 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
50
50
|
"@mozilla/readability": "^0.6",
|
|
51
|
-
"@f5xc-salesdemos/xcsh-stats": "18.63.
|
|
52
|
-
"@f5xc-salesdemos/pi-agent-core": "18.63.
|
|
53
|
-
"@f5xc-salesdemos/pi-ai": "18.63.
|
|
54
|
-
"@f5xc-salesdemos/pi-natives": "18.63.
|
|
55
|
-
"@f5xc-salesdemos/pi-tui": "18.63.
|
|
56
|
-
"@f5xc-salesdemos/pi-utils": "18.63.
|
|
51
|
+
"@f5xc-salesdemos/xcsh-stats": "18.63.1",
|
|
52
|
+
"@f5xc-salesdemos/pi-agent-core": "18.63.1",
|
|
53
|
+
"@f5xc-salesdemos/pi-ai": "18.63.1",
|
|
54
|
+
"@f5xc-salesdemos/pi-natives": "18.63.1",
|
|
55
|
+
"@f5xc-salesdemos/pi-tui": "18.63.1",
|
|
56
|
+
"@f5xc-salesdemos/pi-utils": "18.63.1",
|
|
57
57
|
"@sinclair/typebox": "^0.34",
|
|
58
58
|
"@xterm/headless": "^6.0",
|
|
59
59
|
"ajv": "^8.18",
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "18.63.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "18.63.1",
|
|
21
|
+
"commit": "cc43e44c0c304f8ed8778d3dc1566286cd656275",
|
|
22
|
+
"shortCommit": "cc43e44",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v18.63.
|
|
25
|
-
"commitDate": "2026-05-
|
|
26
|
-
"buildDate": "2026-05-
|
|
27
|
-
"dirty":
|
|
24
|
+
"tag": "v18.63.1",
|
|
25
|
+
"commitDate": "2026-05-13T17:59:16Z",
|
|
26
|
+
"buildDate": "2026-05-13T18:24:01.435Z",
|
|
27
|
+
"dirty": false,
|
|
28
28
|
"prNumber": "",
|
|
29
29
|
"repoUrl": "https://github.com/f5xc-salesdemos/xcsh",
|
|
30
30
|
"repoSlug": "f5xc-salesdemos/xcsh",
|
|
31
|
-
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/
|
|
32
|
-
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.63.
|
|
31
|
+
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/cc43e44c0c304f8ed8778d3dc1566286cd656275",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.63.1"
|
|
33
33
|
};
|
package/src/session/messages.ts
CHANGED
|
@@ -374,6 +374,12 @@ function repairToolResultOrdering(messages: Message[]): Message[] {
|
|
|
374
374
|
// When an assistant-with-tool-calls gets displaced (wedged between another assistant's
|
|
375
375
|
// tool_use and its tool_result), the first pass pushes it to result but the outer loop
|
|
376
376
|
// jumps past it — so its own tool_results are never resolved.
|
|
377
|
+
//
|
|
378
|
+
// Uses a non-mutating rebuild to avoid index corruption from splice-during-iteration
|
|
379
|
+
// (the prior splice approach corrupted indices in long conversations with 1000+ messages).
|
|
380
|
+
const indicesToRemove = new Set<number>();
|
|
381
|
+
const insertions: Array<{ afterIndex: number; messages: ToolResultMessage[] }> = [];
|
|
382
|
+
|
|
377
383
|
for (let i = 0; i < result.length; i++) {
|
|
378
384
|
const msg = result[i];
|
|
379
385
|
if (msg.role !== "assistant") continue;
|
|
@@ -381,7 +387,6 @@ function repairToolResultOrdering(messages: Message[]): Message[] {
|
|
|
381
387
|
const toolCalls = assistantMsg.content.filter((c): c is ToolCall => c.type === "toolCall");
|
|
382
388
|
if (toolCalls.length === 0) continue;
|
|
383
389
|
|
|
384
|
-
// Check if every tool call has a toolResult immediately following
|
|
385
390
|
const expectedIds = new Set(toolCalls.map(tc => tc.id));
|
|
386
391
|
let j = i + 1;
|
|
387
392
|
while (j < result.length && result[j].role === "toolResult") {
|
|
@@ -391,17 +396,18 @@ function repairToolResultOrdering(messages: Message[]): Message[] {
|
|
|
391
396
|
|
|
392
397
|
if (expectedIds.size === 0) continue;
|
|
393
398
|
|
|
394
|
-
// For missing tool calls: relocate existing result from later in array, or synthesize
|
|
395
399
|
const toInsert: ToolResultMessage[] = [];
|
|
396
400
|
for (const id of expectedIds) {
|
|
397
|
-
// Check if a toolResult for this ID exists later in result
|
|
398
401
|
const laterIndex = result.findIndex(
|
|
399
|
-
(m, idx) =>
|
|
402
|
+
(m, idx) =>
|
|
403
|
+
idx > j &&
|
|
404
|
+
!indicesToRemove.has(idx) &&
|
|
405
|
+
m.role === "toolResult" &&
|
|
406
|
+
(m as ToolResultMessage).toolCallId === id,
|
|
400
407
|
);
|
|
401
408
|
if (laterIndex !== -1) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
toInsert.push(relocated as ToolResultMessage);
|
|
409
|
+
toInsert.push(result[laterIndex] as ToolResultMessage);
|
|
410
|
+
indicesToRemove.add(laterIndex);
|
|
405
411
|
} else {
|
|
406
412
|
const toolCall = toolCalls.find(tc => tc.id === id);
|
|
407
413
|
toInsert.push({
|
|
@@ -414,9 +420,26 @@ function repairToolResultOrdering(messages: Message[]): Message[] {
|
|
|
414
420
|
} as ToolResultMessage);
|
|
415
421
|
}
|
|
416
422
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
423
|
+
if (toInsert.length > 0) {
|
|
424
|
+
insertions.push({ afterIndex: i, messages: toInsert });
|
|
425
|
+
repaired = true;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (insertions.length > 0 || indicesToRemove.size > 0) {
|
|
430
|
+
const rebuilt: Message[] = [];
|
|
431
|
+
const insertionMap = new Map(insertions.map(ins => [ins.afterIndex, ins.messages]));
|
|
432
|
+
for (let i = 0; i < result.length; i++) {
|
|
433
|
+
if (!indicesToRemove.has(i)) {
|
|
434
|
+
rebuilt.push(result[i]);
|
|
435
|
+
}
|
|
436
|
+
const ins = insertionMap.get(i);
|
|
437
|
+
if (ins) {
|
|
438
|
+
rebuilt.push(...ins);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
result.length = 0;
|
|
442
|
+
result.push(...rebuilt);
|
|
420
443
|
}
|
|
421
444
|
|
|
422
445
|
if (repaired) {
|
|
@@ -536,5 +559,39 @@ export function convertToLlm(messages: AgentMessage[]): Message[] {
|
|
|
536
559
|
}
|
|
537
560
|
})
|
|
538
561
|
.filter(m => m !== undefined);
|
|
539
|
-
|
|
562
|
+
const repaired = repairToolResultOrdering(converted);
|
|
563
|
+
return mergeConsecutiveUserTextMessages(repaired);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Merge consecutive user messages that contain only text into single messages.
|
|
568
|
+
* The Claude API internally merges consecutive same-role messages before validation,
|
|
569
|
+
* which shifts message indices. Pre-merging here keeps xcsh's indices aligned with
|
|
570
|
+
* the API's view, preventing phantom index mismatches in error reports.
|
|
571
|
+
*/
|
|
572
|
+
function mergeConsecutiveUserTextMessages(messages: Message[]): Message[] {
|
|
573
|
+
if (messages.length < 2) return messages;
|
|
574
|
+
|
|
575
|
+
const result: Message[] = [messages[0]];
|
|
576
|
+
for (let i = 1; i < messages.length; i++) {
|
|
577
|
+
const prev = result[result.length - 1];
|
|
578
|
+
const curr = messages[i];
|
|
579
|
+
|
|
580
|
+
if (
|
|
581
|
+
prev.role === "user" &&
|
|
582
|
+
curr.role === "user" &&
|
|
583
|
+
Array.isArray(prev.content) &&
|
|
584
|
+
Array.isArray(curr.content) &&
|
|
585
|
+
prev.content.every(c => c.type === "text") &&
|
|
586
|
+
curr.content.every(c => c.type === "text")
|
|
587
|
+
) {
|
|
588
|
+
result[result.length - 1] = {
|
|
589
|
+
...prev,
|
|
590
|
+
content: [...prev.content, ...curr.content],
|
|
591
|
+
};
|
|
592
|
+
} else {
|
|
593
|
+
result.push(curr);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
return result;
|
|
540
597
|
}
|