@yeaft/webchat-agent 0.1.69 → 0.1.73

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/claude.js CHANGED
@@ -408,7 +408,7 @@ async function processClaudeOutput(conversationId, claudeQuery, state) {
408
408
 
409
409
  // 计算上下文使用百分比
410
410
  const inputTokens = message.usage?.input_tokens || 0;
411
- const maxContextTokens = 128000; // API max_prompt_tokens 限制
411
+ const maxContextTokens = ctx.CONFIG?.maxContextTokens || 128000;
412
412
  if (inputTokens > 0) {
413
413
  ctx.sendToServer({
414
414
  type: 'context_usage',
@@ -497,6 +497,35 @@ async function processClaudeOutput(conversationId, claudeQuery, state) {
497
497
 
498
498
  console.log(`[RolePlay] Auto-continuing to role: ${to}`);
499
499
 
500
+ // ★ Pre-send compact check for RolePlay auto-continue
501
+ const rpAutoCompactThreshold = ctx.CONFIG?.autoCompactThreshold || 110000;
502
+ const rpEstimatedNewTokens = Math.ceil(prompt.length / 3);
503
+ const rpEstimatedTotal = inputTokens + rpEstimatedNewTokens;
504
+
505
+ if (rpEstimatedTotal > rpAutoCompactThreshold) {
506
+ console.log(`[RolePlay] Pre-send compact: estimated ${rpEstimatedTotal} tokens (last: ${inputTokens} + new: ~${rpEstimatedNewTokens}) exceeds threshold ${rpAutoCompactThreshold}`);
507
+ ctx.sendToServer({
508
+ type: 'compact_status',
509
+ conversationId,
510
+ status: 'compacting',
511
+ message: `Auto-compacting before RolePlay continue: estimated ${rpEstimatedTotal} tokens (threshold: ${rpAutoCompactThreshold})`
512
+ });
513
+ // Store pending message and compact first
514
+ const userMessage = {
515
+ type: 'user',
516
+ message: { role: 'user', content: prompt }
517
+ };
518
+ state._pendingUserMessage = userMessage;
519
+ state.turnActive = true;
520
+ state.turnResultReceived = false;
521
+ state.inputStream.enqueue({
522
+ type: 'user',
523
+ message: { role: 'user', content: '/compact' }
524
+ });
525
+ sendConversationList();
526
+ break;
527
+ }
528
+
500
529
  // Re-activate the turn
501
530
  state.turnActive = true;
502
531
  state.turnResultReceived = false;
@@ -531,6 +560,18 @@ async function processClaudeOutput(conversationId, claudeQuery, state) {
531
560
  workDir: state.workDir
532
561
  });
533
562
  sendConversationList();
563
+
564
+ // ★ Send pending user message after compact completes
565
+ if (state._pendingUserMessage && state.inputStream) {
566
+ const pendingMsg = state._pendingUserMessage;
567
+ state._pendingUserMessage = null;
568
+ console.log(`[${conversationId}] Sending pending message after compact`);
569
+ state.turnActive = true;
570
+ state.turnResultReceived = false;
571
+ sendOutput(conversationId, pendingMsg);
572
+ state.inputStream.enqueue(pendingMsg);
573
+ sendConversationList();
574
+ }
534
575
  continue;
535
576
  }
536
577
 
package/cli.js CHANGED
@@ -152,6 +152,19 @@ function upgrade() {
152
152
  } else {
153
153
  execSync(`npm install -g ${pkg.name}@latest`, { stdio: 'inherit' });
154
154
  console.log(`Successfully upgraded to ${latest}`);
155
+
156
+ // If PM2 is managing yeaft-agent, restart it so the new version takes effect
157
+ try {
158
+ const pm2List = execSync('pm2 jlist', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
159
+ const apps = JSON.parse(pm2List);
160
+ if (Array.isArray(apps) && apps.some(app => app.name === 'yeaft-agent')) {
161
+ console.log('Restarting yeaft-agent via PM2...');
162
+ execSync('pm2 restart yeaft-agent', { stdio: 'inherit' });
163
+ console.log('PM2 service restarted.');
164
+ }
165
+ } catch {
166
+ // PM2 not installed or not managing yeaft-agent — nothing to do
167
+ }
155
168
  }
156
169
  } catch (e) {
157
170
  console.error('Upgrade failed:', e.message);
@@ -185,11 +198,11 @@ function upgradeWindows(latestVersion) {
185
198
  'echo [Upgrade] Waiting for CLI process (PID %PID%) to exit... >> "%LOGFILE%"',
186
199
  '',
187
200
  ':WAIT_LOOP',
188
- 'tasklist /FI "PID eq %PID%" 2>NUL | findstr /I "%PID%" >NUL',
201
+ 'tasklist /FI "PID eq %PID%" /NH 2>NUL | findstr /C:"%PID%" >NUL',
189
202
  'if errorlevel 1 goto PID_EXITED',
190
203
  'set /A COUNT+=1',
191
204
  'if %COUNT% GEQ %MAX_WAIT% (',
192
- ' echo [Upgrade] Timeout waiting for PID %PID% to exit >> "%LOGFILE%"',
205
+ ' echo [Upgrade] Timeout waiting for PID %PID% to exit after %MAX_WAIT% iterations >> "%LOGFILE%"',
193
206
  ' goto PID_EXITED',
194
207
  ')',
195
208
  'ping -n 3 127.0.0.1 >NUL',
@@ -210,7 +223,6 @@ function upgradeWindows(latestVersion) {
210
223
 
211
224
  writeFileSync(batPath, batLines.join('\r\n'));
212
225
  const child = spawn('cmd.exe', ['/c', batPath], {
213
- detached: true,
214
226
  stdio: 'ignore',
215
227
  windowsHide: true,
216
228
  });
@@ -152,11 +152,11 @@ function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, latestV
152
152
  // Wait for old process to exit (PM2 already deleted before exit, so no auto-restart race)
153
153
  batLines.push(
154
154
  ':WAIT_LOOP',
155
- 'tasklist /FI "PID eq %PID%" 2>NUL | findstr /I "%PID%" >NUL',
155
+ 'tasklist /FI "PID eq %PID%" /NH 2>NUL | findstr /C:"%PID%" >NUL',
156
156
  'if errorlevel 1 goto PID_EXITED',
157
157
  'set /A COUNT+=1',
158
158
  'if %COUNT% GEQ %MAX_WAIT% (',
159
- ' echo [Upgrade] Timeout waiting for PID %PID% to exit after 60s >> "%LOGFILE%"',
159
+ ' echo [Upgrade] Timeout waiting for PID %PID% to exit after %MAX_WAIT% iterations >> "%LOGFILE%"',
160
160
  ' goto PID_EXITED',
161
161
  ')',
162
162
  'ping -n 3 127.0.0.1 >NUL',
@@ -201,7 +201,6 @@ function spawnWindowsUpgradeScript(pkgName, installDir, isGlobalInstall, latestV
201
201
 
202
202
  writeFileSync(batPath, batLines.join('\r\n'));
203
203
  const child = spawn('cmd.exe', ['/c', batPath], {
204
- detached: true,
205
204
  stdio: 'ignore',
206
205
  windowsHide: true
207
206
  });
package/conversation.js CHANGED
@@ -515,6 +515,34 @@ export async function handleUserInput(msg) {
515
515
  };
516
516
 
517
517
  console.log(`[${conversationId}] Sending: ${prompt.substring(0, 100)}...`);
518
+
519
+ // ★ Pre-send compact check: estimate total tokens and compact before sending if needed
520
+ const autoCompactThreshold = ctx.CONFIG?.autoCompactThreshold || 110000;
521
+ const lastInputTokens = state.lastResultInputTokens || 0;
522
+ const estimatedNewTokens = Math.ceil(effectivePrompt.length / 3); // conservative: ~3 chars per token
523
+ const estimatedTotal = lastInputTokens + estimatedNewTokens;
524
+
525
+ if (estimatedTotal > autoCompactThreshold && state.inputStream) {
526
+ console.log(`[${conversationId}] Pre-send compact: estimated ${estimatedTotal} tokens (last: ${lastInputTokens} + new: ~${estimatedNewTokens}) exceeds threshold ${autoCompactThreshold}`);
527
+ ctx.sendToServer({
528
+ type: 'compact_status',
529
+ conversationId,
530
+ status: 'compacting',
531
+ message: `Auto-compacting before send: estimated ${estimatedTotal} tokens (threshold: ${autoCompactThreshold})`
532
+ });
533
+ // Send /compact first, then the user message will be sent after compact completes
534
+ // by storing it as a pending message
535
+ state._pendingUserMessage = userMessage;
536
+ state.turnActive = true;
537
+ state.turnResultReceived = false;
538
+ sendConversationList();
539
+ state.inputStream.enqueue({
540
+ type: 'user',
541
+ message: { role: 'user', content: '/compact' }
542
+ });
543
+ return;
544
+ }
545
+
518
546
  state.turnActive = true;
519
547
  state.turnResultReceived = false; // 重置 per-turn 去重标志
520
548
  sendConversationList(); // 在 turnActive=true 后通知 server,确保 processing 状态正确
@@ -62,7 +62,6 @@ export async function removeFromCrewIndex(sessionId) {
62
62
  const { crewSessions } = await import('./session.js');
63
63
 
64
64
  const index = await loadCrewIndex();
65
- const entry = index.find(e => e.sessionId === sessionId);
66
65
  const filtered = index.filter(e => e.sessionId !== sessionId);
67
66
  if (filtered.length !== index.length) {
68
67
  await saveCrewIndex(filtered);
@@ -73,20 +72,8 @@ export async function removeFromCrewIndex(sessionId) {
73
72
  crewSessions.delete(sessionId);
74
73
  console.log(`[Crew] Removed session ${sessionId} from active sessions`);
75
74
  }
76
- // 删除磁盘上的 session 数据文件
77
- const sharedDir = entry?.sharedDir;
78
- if (sharedDir) {
79
- try {
80
- for (const file of ['session.json', 'messages.json']) {
81
- await fs.unlink(join(sharedDir, file)).catch(() => {});
82
- }
83
- // Clean up message shard files
84
- await cleanupMessageShards(sharedDir);
85
- console.log(`[Crew] Cleaned session files in ${sharedDir}`);
86
- } catch (e) {
87
- console.warn(`[Crew] Failed to clean session files:`, e.message);
88
- }
89
- }
75
+ // 注意:不再删除磁盘上的 session.json、messages.json 等文件
76
+ // 这些文件在 recreate 时会被复用(合并统计数据 + 恢复消息历史)
90
77
  }
91
78
 
92
79
  // =====================================================================
@@ -6,10 +6,10 @@ import { sendCrewMessage, sendCrewOutput, sendStatusUpdate, endRoleStreaming } f
6
6
  import { saveRoleSessionId, clearRoleSessionId, classifyRoleError, createRoleQuery } from './role-query.js';
7
7
  import { parseRoutes, executeRoute, dispatchToRole } from './routing.js';
8
8
  import { parseCompletedTasks, updateFeatureIndex, appendChangelog, saveRoleWorkSummary, updateKanban } from './task-files.js';
9
+ import ctx from '../context.js';
9
10
 
10
- // Context 使用率阈值常量
11
- const MAX_CONTEXT = 128000; // API max_prompt_tokens 限制
12
- const CLEAR_THRESHOLD = 0.85; // 85% → 直接 clear + rebuild(不再走 compact)
11
+ // Context 使用率常量(运行时从 ctx.CONFIG 读取)
12
+ const getMaxContext = () => ctx.CONFIG?.maxContextTokens || 128000;
13
13
 
14
14
  /**
15
15
  * 处理角色的流式输出
@@ -99,14 +99,11 @@ export async function processRoleOutput(session, roleName, roleQuery, roleState)
99
99
  sessionId: session.id,
100
100
  role: roleName,
101
101
  inputTokens,
102
- maxTokens: MAX_CONTEXT,
103
- percentage: Math.min(100, Math.round((inputTokens / MAX_CONTEXT) * 100))
102
+ maxTokens: getMaxContext(),
103
+ percentage: Math.min(100, Math.round((inputTokens / getMaxContext()) * 100))
104
104
  });
105
105
  }
106
106
 
107
- const contextPercentage = inputTokens / MAX_CONTEXT;
108
- const needClear = contextPercentage >= CLEAR_THRESHOLD;
109
-
110
107
  // 解析路由
111
108
  const routes = parseRoutes(roleState.accumulatedText);
112
109
 
@@ -136,8 +133,8 @@ export async function processRoleOutput(session, roleName, roleQuery, roleState)
136
133
  }
137
134
  }
138
135
 
139
- // 保存 accumulatedText 供后续 saveRoleWorkSummary 使用(清空前)
140
- const turnText = roleState.accumulatedText;
136
+ // 保存本 turn 文本(供 routing.js 预检时 saveRoleWorkSummary 使用)
137
+ roleState.lastTurnText = roleState.accumulatedText;
141
138
  roleState.accumulatedText = '';
142
139
  roleState.turnActive = false;
143
140
 
@@ -149,57 +146,7 @@ export async function processRoleOutput(session, roleName, roleQuery, roleState)
149
146
 
150
147
  sendStatusUpdate(session);
151
148
 
152
- // Context 超限:保存工作摘要后 clear + rebuild
153
- if (needClear) {
154
- console.log(`[Crew] ${roleName} context at ${Math.round(contextPercentage * 100)}%, clearing and rebuilding`);
155
-
156
- // 保存工作摘要到 feature 文件
157
- await saveRoleWorkSummary(session, roleName, turnText).catch(e =>
158
- console.warn(`[Crew] Failed to save work summary for ${roleName}:`, e.message));
159
-
160
- // Clear 角色
161
- await clearRoleSessionId(session.sharedDir, roleName);
162
- roleState.claudeSessionId = null;
163
-
164
- if (roleState.abortController) roleState.abortController.abort();
165
- roleState.query = null;
166
- roleState.inputStream = null;
167
-
168
- sendCrewMessage({
169
- type: 'crew_role_cleared',
170
- sessionId: session.id,
171
- role: roleName,
172
- contextPercentage: Math.round(contextPercentage * 100),
173
- reason: 'context_limit'
174
- });
175
-
176
- // 继承 task 到路由(如有)
177
- const currentTask = roleState.currentTask;
178
- if (routes.length > 0) {
179
- for (const route of routes) {
180
- if (!route.taskId && currentTask) {
181
- route.taskId = currentTask.taskId;
182
- route.taskTitle = currentTask.taskTitle;
183
- }
184
- }
185
- }
186
-
187
- // 执行路由
188
- if (routes.length > 0) {
189
- session.round++;
190
- const results = await Promise.allSettled(routes.map(route =>
191
- executeRoute(session, roleName, route)
192
- ));
193
- for (const r of results) {
194
- if (r.status === 'rejected') {
195
- console.warn(`[Crew] Route execution failed:`, r.reason);
196
- }
197
- }
198
- }
199
- return; // query 已清空,退出
200
- }
201
-
202
- // 执行路由(无需 clear 时)
149
+ // 执行路由
203
150
  if (routes.length > 0) {
204
151
  session.round++;
205
152
 
package/crew/routing.js CHANGED
@@ -4,8 +4,9 @@
4
4
  */
5
5
  import { join } from 'path';
6
6
  import { sendCrewMessage, sendCrewOutput, sendStatusUpdate } from './ui-messages.js';
7
- import { ensureTaskFile, appendTaskRecord, readTaskFile, updateKanban, readKanban } from './task-files.js';
8
- import { createRoleQuery } from './role-query.js';
7
+ import { ensureTaskFile, appendTaskRecord, readTaskFile, updateKanban, readKanban, saveRoleWorkSummary } from './task-files.js';
8
+ import { createRoleQuery, clearRoleSessionId } from './role-query.js';
9
+ import ctx from '../context.js';
9
10
 
10
11
  /** Format role label */
11
12
  function roleLabel(r) {
@@ -193,6 +194,39 @@ export async function dispatchToRole(session, roleName, content, fromSource, tas
193
194
  timestamp: Date.now()
194
195
  });
195
196
 
197
+ // ★ Pre-send compact check: estimate total tokens and clear+rebuild if needed
198
+ const autoCompactThreshold = ctx.CONFIG?.autoCompactThreshold || 110000;
199
+ const lastInputTokens = roleState.lastInputTokens || 0;
200
+ const estimatedNewTokens = Math.ceil((typeof content === 'string' ? content.length : 0) / 3);
201
+ const estimatedTotal = lastInputTokens + estimatedNewTokens;
202
+
203
+ if (lastInputTokens > 0 && estimatedTotal > autoCompactThreshold) {
204
+ console.log(`[Crew] Pre-send compact for ${roleName}: estimated ${estimatedTotal} tokens (last: ${lastInputTokens} + new: ~${estimatedNewTokens}) exceeds threshold ${autoCompactThreshold}`);
205
+
206
+ // Save work summary before clearing (use lastTurnText since accumulatedText is cleared after result)
207
+ await saveRoleWorkSummary(session, roleName, roleState.lastTurnText || roleState.accumulatedText || '').catch(e =>
208
+ console.warn(`[Crew] Failed to save work summary for ${roleName}:`, e.message));
209
+
210
+ // Clear role session and rebuild
211
+ await clearRoleSessionId(session.sharedDir, roleName);
212
+ roleState.claudeSessionId = null;
213
+
214
+ if (roleState.abortController) roleState.abortController.abort();
215
+ roleState.query = null;
216
+ roleState.inputStream = null;
217
+
218
+ sendCrewMessage({
219
+ type: 'crew_role_cleared',
220
+ sessionId: session.id,
221
+ role: roleName,
222
+ contextPercentage: Math.round((lastInputTokens / (ctx.CONFIG?.maxContextTokens || 128000)) * 100),
223
+ reason: 'pre_send_compact'
224
+ });
225
+
226
+ // Recreate the query (fresh Claude process)
227
+ roleState = await createRoleQuery(session, roleName);
228
+ }
229
+
196
230
  // 发送
197
231
  roleState.lastDispatchContent = content;
198
232
  roleState.lastDispatchFrom = fromSource;
package/crew/session.js CHANGED
@@ -147,6 +147,9 @@ export async function createCrewSession(msg) {
147
147
  : join(projectDir, sharedDirRel || '.crew');
148
148
  const decisionMaker = roles.find(r => r.isDecisionMaker)?.name || roles[0]?.name || null;
149
149
 
150
+ // 尝试读取旧 session.json,合并统计数据(deleteCrewDir 保留了该文件)
151
+ const oldMeta = await loadSessionMeta(sharedDir);
152
+
150
153
  const session = {
151
154
  id: sessionId,
152
155
  projectDir,
@@ -156,28 +159,41 @@ export async function createCrewSession(msg) {
156
159
  roleStates: new Map(),
157
160
  decisionMaker,
158
161
  status: 'initializing',
159
- round: 0,
160
- costUsd: 0,
161
- totalInputTokens: 0,
162
- totalOutputTokens: 0,
162
+ round: oldMeta?.round || 0,
163
+ costUsd: oldMeta?.costUsd || 0,
164
+ totalInputTokens: oldMeta?.totalInputTokens || 0,
165
+ totalOutputTokens: oldMeta?.totalOutputTokens || 0,
163
166
  messageHistory: [],
164
167
  uiMessages: [],
165
168
  humanMessageQueue: [],
166
169
  waitingHumanContext: null,
167
170
  pendingRoutes: [],
168
- features: new Map(),
169
- _completedTaskIds: new Set(),
171
+ features: new Map((oldMeta?.features || []).map(f => [f.taskId, f])),
172
+ _completedTaskIds: new Set(oldMeta?._completedTaskIds || []),
170
173
  initProgress: null,
171
174
  userId,
172
175
  username,
173
176
  agentId: ctx.CONFIG?.agentName || null,
174
177
  teamType,
175
178
  language,
176
- createdAt: Date.now()
179
+ createdAt: oldMeta?.createdAt || Date.now()
177
180
  };
178
181
 
182
+ if (oldMeta) {
183
+ console.log(`[Crew] Merged stats from previous session: round=${session.round}, cost=$${session.costUsd.toFixed(4)}, inputTokens=${session.totalInputTokens}, outputTokens=${session.totalOutputTokens}`);
184
+ // 恢复旧消息历史(deleteCrewDir 保留了 messages*.json)
185
+ const loaded = await loadSessionMessages(sharedDir);
186
+ if (loaded.messages.length > 0) {
187
+ session.uiMessages = loaded.messages;
188
+ console.log(`[Crew] Restored ${loaded.messages.length} messages from previous session`);
189
+ }
190
+ }
191
+
179
192
  crewSessions.set(sessionId, session);
180
193
 
194
+ // 如果有旧消息,检查是否有更早的分片
195
+ const hasOlderMessages = oldMeta ? await getMaxShardIndex(sharedDir) > 0 : false;
196
+
181
197
  sendCrewMessage({
182
198
  type: 'crew_session_created',
183
199
  sessionId,
@@ -196,7 +212,10 @@ export async function createCrewSession(msg) {
196
212
  })),
197
213
  decisionMaker,
198
214
  userId,
199
- username
215
+ username,
216
+ // 旧消息(recreate 时保留的历史)
217
+ uiMessages: session.uiMessages.length > 0 ? session.uiMessages : undefined,
218
+ hasOlderMessages: hasOlderMessages || undefined
200
219
  });
201
220
 
202
221
  sendStatusUpdate(session);
@@ -335,19 +354,39 @@ export async function handleCheckCrewExists(msg) {
335
354
  }
336
355
 
337
356
  /**
338
- * 删除工作目录下的 .crew 目录(保留 context/ 历史记录)
357
+ * 删除 Crew 定义文件(模板/角色配置),保留所有用户数据和工作产出
358
+ *
359
+ * 删除: CLAUDE.md(共享模板)、roles/(角色模板)
360
+ * 清空: sessions/ 下的文件(旧角色的 Claude Code session IDs,已失效)
361
+ * 清除: crew-index 中的旧 entry(防止 createCrewSession 走 resume 而非 create)
362
+ * 保留: context/、session.json、messages*.json 及任何其他生成文件(截图、设计文档等)
339
363
  */
340
364
  export async function handleDeleteCrewDir(msg) {
341
365
  const { projectDir } = msg;
342
366
  if (!isValidProjectDir(projectDir)) return;
343
367
  const crewDir = join(projectDir, '.crew');
344
368
  try {
345
- const entries = await fs.readdir(crewDir);
346
- await Promise.all(
347
- entries
348
- .filter(name => name !== 'context')
349
- .map(name => fs.rm(join(crewDir, name), { recursive: true, force: true }))
350
- );
369
+ // 删除 Crew 模板定义
370
+ await fs.rm(join(crewDir, 'CLAUDE.md'), { force: true }).catch(() => {});
371
+ await fs.rm(join(crewDir, 'roles'), { recursive: true, force: true }).catch(() => {});
372
+
373
+ // 清空 sessions/ 内容(旧角色的 session IDs 已失效),保留目录本身
374
+ const sessionsDir = join(crewDir, 'sessions');
375
+ try {
376
+ const sessionFiles = await fs.readdir(sessionsDir);
377
+ await Promise.all(
378
+ sessionFiles.map(f => fs.rm(join(sessionsDir, f), { recursive: true, force: true }).catch(() => {}))
379
+ );
380
+ } catch { /* sessions/ may not exist */ }
381
+
382
+ // 清除 crew-index 中的旧 entry(不删文件),确保新建时走 create → loadSessionMeta 合并统计
383
+ const normalizedDir = projectDir.replace(/\/+$/, '');
384
+ const index = await loadCrewIndex();
385
+ const match = index.find(e => e.projectDir.replace(/\/+$/, '') === normalizedDir);
386
+ if (match) {
387
+ await removeFromCrewIndex(match.sessionId);
388
+ console.log(`[Crew] Cleared index entry for ${projectDir} (sessionId: ${match.sessionId})`);
389
+ }
351
390
  } catch {}
352
391
  }
353
392
 
package/index.js CHANGED
@@ -74,7 +74,11 @@ const CONFIG = {
74
74
  return raw.split(',').map(s => s.trim()).filter(Boolean);
75
75
  })(),
76
76
  // disallowedTools 会在 loadMcpServers() 中计算
77
- disallowedTools: []
77
+ disallowedTools: [],
78
+ // 最大上下文 tokens(用于百分比计算的分母)
79
+ maxContextTokens: parseInt(process.env.MAX_CONTEXT_TOKENS || fileConfig.maxContextTokens, 10) || 128000,
80
+ // Auto-compact 阈值(tokens):context 超过此值时自动触发 compact
81
+ autoCompactThreshold: parseInt(process.env.AUTO_COMPACT_THRESHOLD || fileConfig.autoCompactThreshold, 10) || 110000
78
82
  };
79
83
 
80
84
  // 初始化共享上下文
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "0.1.69",
3
+ "version": "0.1.73",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",