linkshell-cli 0.3.11 → 0.3.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.
@@ -10,6 +10,8 @@ import { listCodexStoredSessions, loadCodexStoredTimeline } from "./codex-sessio
10
10
  import { resolveAgentCommand } from "./provider-resolver.js";
11
11
  const PERMISSION_TIMEOUT_MS = 5 * 60_000;
12
12
  const MAX_TIMELINE_ITEMS = 200;
13
+ const MAX_SNAPSHOT_ITEMS = 80;
14
+ const MAX_SNAPSHOT_TEXT_BYTES = 128 * 1024;
13
15
  function id(prefix) {
14
16
  return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
15
17
  }
@@ -23,6 +25,62 @@ function stringify(value) {
23
25
  return String(value);
24
26
  }
25
27
  }
28
+ function truncateUtf8(value, maxBytes = MAX_SNAPSHOT_TEXT_BYTES) {
29
+ if (!value)
30
+ return value;
31
+ if (Buffer.byteLength(value, "utf8") <= maxBytes)
32
+ return value;
33
+ let end = Math.min(value.length, maxBytes);
34
+ while (end > 0 && Buffer.byteLength(value.slice(0, end), "utf8") > maxBytes) {
35
+ end = Math.floor(end * 0.9);
36
+ }
37
+ return `${value.slice(0, end)}\n\n[truncated by LinkShell: original ${Buffer.byteLength(value, "utf8")} bytes]`;
38
+ }
39
+ function snapshotContentBlocks(blocks, options = {}) {
40
+ if (!blocks)
41
+ return undefined;
42
+ return blocks.map((block) => block.type === "image" && options.stripImages !== false
43
+ ? { ...block, data: undefined, text: block.text || "图片附件" }
44
+ : { ...block, text: truncateUtf8(block.text) });
45
+ }
46
+ function snapshotTimelineItem(item, options = {}) {
47
+ return {
48
+ ...item,
49
+ content: snapshotContentBlocks(item.content, options),
50
+ text: truncateUtf8(item.text),
51
+ toolCall: item.toolCall
52
+ ? {
53
+ ...item.toolCall,
54
+ input: truncateUtf8(item.toolCall.input),
55
+ output: truncateUtf8(item.toolCall.output),
56
+ }
57
+ : undefined,
58
+ commandExecution: item.commandExecution
59
+ ? {
60
+ ...item.commandExecution,
61
+ command: truncateUtf8(item.commandExecution.command, 16 * 1024),
62
+ output: truncateUtf8(item.commandExecution.output),
63
+ }
64
+ : undefined,
65
+ fileChange: item.fileChange
66
+ ? {
67
+ ...item.fileChange,
68
+ diff: truncateUtf8(item.fileChange.diff),
69
+ summary: truncateUtf8(item.fileChange.summary),
70
+ }
71
+ : undefined,
72
+ permission: item.permission
73
+ ? {
74
+ ...item.permission,
75
+ toolInput: truncateUtf8(item.permission.toolInput),
76
+ context: truncateUtf8(item.permission.context),
77
+ }
78
+ : undefined,
79
+ };
80
+ }
81
+ function snapshotTimelineItems(items) {
82
+ return items.slice(-MAX_SNAPSHOT_ITEMS).map((item) => snapshotTimelineItem(item));
83
+ }
26
84
  function asRecord(value) {
27
85
  return typeof value === "object" && value ? value : undefined;
28
86
  }
@@ -1308,7 +1366,7 @@ export class AgentWorkspaceProxy {
1308
1366
  hostDeviceId: this.input.hostDeviceId,
1309
1367
  payload: {
1310
1368
  conversation: existingConversation,
1311
- snapshot: this.timelines.get(existingConversation.id) ?? [],
1369
+ snapshot: snapshotTimelineItems(this.timelines.get(existingConversation.id) ?? []),
1312
1370
  },
1313
1371
  }));
1314
1372
  return existingConversation;
@@ -1355,7 +1413,7 @@ export class AgentWorkspaceProxy {
1355
1413
  this.input.send(createEnvelope({
1356
1414
  type: "agent.v2.conversation.opened",
1357
1415
  hostDeviceId: this.input.hostDeviceId,
1358
- payload: { conversation, snapshot: this.timelines.get(conversation.id) ?? [] },
1416
+ payload: { conversation, snapshot: snapshotTimelineItems(this.timelines.get(conversation.id) ?? []) },
1359
1417
  }));
1360
1418
  return conversation;
1361
1419
  }
@@ -1394,7 +1452,7 @@ export class AgentWorkspaceProxy {
1394
1452
  this.input.send(createEnvelope({
1395
1453
  type: "agent.v2.conversation.opened",
1396
1454
  hostDeviceId: this.input.hostDeviceId,
1397
- payload: { conversation, snapshot: this.timelines.get(conversation.id) ?? [] },
1455
+ payload: { conversation, snapshot: snapshotTimelineItems(this.timelines.get(conversation.id) ?? []) },
1398
1456
  }));
1399
1457
  return conversation;
1400
1458
  }
@@ -2550,7 +2608,7 @@ export class AgentWorkspaceProxy {
2550
2608
  this.input.send(createEnvelope({
2551
2609
  type: "agent.v2.event",
2552
2610
  hostDeviceId: this.input.hostDeviceId,
2553
- payload: { conversationId, conversation, item },
2611
+ payload: { conversationId, conversation, item: snapshotTimelineItem(item, { stripImages: false }) },
2554
2612
  }));
2555
2613
  }
2556
2614
  emitConversation(conversation) {
@@ -2603,8 +2661,8 @@ export class AgentWorkspaceProxy {
2603
2661
  }
2604
2662
  const conversations = [...this.conversations.values()];
2605
2663
  const items = conversationId
2606
- ? this.timelines.get(conversationId) ?? []
2607
- : [...this.timelines.values()].flat();
2664
+ ? snapshotTimelineItems(this.timelines.get(conversationId) ?? [])
2665
+ : [];
2608
2666
  this.input.send(createEnvelope({
2609
2667
  type: "agent.v2.snapshot",
2610
2668
  hostDeviceId: this.input.hostDeviceId,