@yeaft/webchat-agent 0.1.70 → 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/cli.js +15 -3
- package/connection/upgrade.js +2 -3
- package/crew/persistence.js +2 -15
- package/crew/session.js +54 -15
- package/package.json +1 -1
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 /
|
|
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
|
});
|
package/connection/upgrade.js
CHANGED
|
@@ -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 /
|
|
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
|
|
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/crew/persistence.js
CHANGED
|
@@ -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
|
-
//
|
|
77
|
-
|
|
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
|
// =====================================================================
|
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
|
-
*
|
|
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
|
-
|
|
346
|
-
await
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
|