@yeaft/webchat-agent 0.1.911 → 0.1.913
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.
|
@@ -37,7 +37,7 @@ import { handleRestartAgent, handleUpgradeAgent } from './upgrade.js';
|
|
|
37
37
|
import { loadMcpServers, updateMcpConfig } from '../mcp.js';
|
|
38
38
|
import { getLlmConfig, updateLlmConfig, getYeaftSettings, updateYeaftSettings, getSearchSettings, updateSearchSettings, fetchTavilyUsage } from '../yeaft/config-api.js';
|
|
39
39
|
import { fetchModelsDev } from '../yeaft/llm/models-dev.js';
|
|
40
|
-
import { handleYeaftSessionSend, handleYeaftModeSwitch, handleYeaftModelSwitch, resetYeaftSession, handleYeaftLoadHistory, handleYeaftLoadMoreHistory, handleYeaftAbortThread, handleYeaftAbortAll, handleYeaftAbortTurn, handleYeaftVpSubscribe, handleYeaftVpCreate, handleYeaftVpUpdate, handleYeaftVpDelete, handleYeaftVpRead, handleYeaftListSessions, handleYeaftCreateSession, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, broadcastLanguageChange, broadcastYeaftSessionSnapshotEager } from '../yeaft/web-bridge.js';
|
|
40
|
+
import { handleYeaftSessionSend, handleYeaftModeSwitch, handleYeaftModelSwitch, resetYeaftSession, handleYeaftLoadHistory, handleYeaftLoadMoreHistory, handleYeaftAbortThread, handleYeaftAbortAll, handleYeaftAbortTurn, handleYeaftVpSubscribe, handleYeaftVpCreate, handleYeaftVpUpdate, handleYeaftVpDelete, handleYeaftVpRead, handleYeaftListSessions, handleYeaftCreateSession, handleYeaftRenameSession, handleYeaftUpdateSession, handleYeaftUpdateSessionConfig, handleYeaftArchiveSession, handleYeaftDeleteSession, handleYeaftSessionAddMember, handleYeaftSessionRemoveMember, handleYeaftSessionSetDefaultVp, handleYeaftScanWorkdirSessions, handleYeaftRestoreSession, handleYeaftDreamTrigger, handleYeaftFetchToolStats, handleYeaftFetchDebugHistory, broadcastLanguageChange, broadcastYeaftSessionSnapshotEager } from '../yeaft/web-bridge.js';
|
|
41
41
|
|
|
42
42
|
export async function handleMessage(msg) {
|
|
43
43
|
switch (msg.type) {
|
|
@@ -578,6 +578,16 @@ export async function handleMessage(msg) {
|
|
|
578
578
|
case 'yeaft_session_set_default_vp':
|
|
579
579
|
handleYeaftSessionSetDefaultVp(msg);
|
|
580
580
|
break;
|
|
581
|
+
// feat-yeaft-session-restore: probe + register a session by workdir.
|
|
582
|
+
// `scan_workdir` is read-only (lists what's on disk + flags whether it's
|
|
583
|
+
// already in the central registry); `restore` writes the registry entry
|
|
584
|
+
// and triggers a snapshot rebroadcast so the sidebar updates.
|
|
585
|
+
case 'yeaft_scan_workdir_sessions':
|
|
586
|
+
handleYeaftScanWorkdirSessions(msg);
|
|
587
|
+
break;
|
|
588
|
+
case 'yeaft_restore_session':
|
|
589
|
+
handleYeaftRestoreSession(msg);
|
|
590
|
+
break;
|
|
581
591
|
// Phase 2: session_send is just group_chat (N≥1 fan-out already works).
|
|
582
592
|
case 'yeaft_session_send':
|
|
583
593
|
handleYeaftSessionSend(msg);
|
package/package.json
CHANGED
package/yeaft/sessions/index.js
CHANGED
|
@@ -152,6 +152,86 @@ export function unregisterSessionWorkDir(defaultYeaftDir, sessionId) {
|
|
|
152
152
|
writeWorkDirRegistry(defaultYeaftDir, registry);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Scan the `.yeaft/sessions/` directory under `workDir` and return every
|
|
157
|
+
* session meta we can read. Read-only: never touches the registry.
|
|
158
|
+
*
|
|
159
|
+
* Each returned record carries `workDir` (the normalized path we scanned).
|
|
160
|
+
* This utility deliberately does NOT decorate `alreadyRegistered` — that
|
|
161
|
+
* cross-references the central workdir registry, which is a separate
|
|
162
|
+
* concern owned by the handler / caller (see
|
|
163
|
+
* `handleYeaftScanWorkdirSessions`). Keeping the utility layer-pure makes
|
|
164
|
+
* it usable from contexts that don't have / don't care about the registry
|
|
165
|
+
* (e.g. CLI tools, future per-workdir snapshots).
|
|
166
|
+
*
|
|
167
|
+
* Returns `[]` for missing dir / empty dir / unreadable dir — never throws.
|
|
168
|
+
* Sort is `createdAt` descending (most-recent first) because the restore
|
|
169
|
+
* UI typically cares about "the session I made yesterday".
|
|
170
|
+
*
|
|
171
|
+
* @param {string} workDir — the working directory to scan.
|
|
172
|
+
* @returns {Array<object>}
|
|
173
|
+
*/
|
|
174
|
+
export function scanWorkdirSessions(workDir) {
|
|
175
|
+
const normalized = normalizeWorkDir(workDir);
|
|
176
|
+
if (!normalized) return [];
|
|
177
|
+
const groupYeaftDir = yeaftDirForWorkDir(normalized);
|
|
178
|
+
const root = sessionsRoot(groupYeaftDir);
|
|
179
|
+
if (!existsSync(root)) return [];
|
|
180
|
+
const out = [];
|
|
181
|
+
let entries;
|
|
182
|
+
try {
|
|
183
|
+
entries = readdirSync(root);
|
|
184
|
+
} catch {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
for (const name of entries) {
|
|
188
|
+
if (name.startsWith('.')) continue; // skip .archived-* and dotfiles
|
|
189
|
+
const dir = join(root, name);
|
|
190
|
+
try { if (!statSync(dir).isDirectory()) continue; } catch { continue; }
|
|
191
|
+
const meta = loadSessionMeta(dir);
|
|
192
|
+
if (!meta) continue;
|
|
193
|
+
out.push({
|
|
194
|
+
...meta,
|
|
195
|
+
workDir: normalized,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
return out.sort((a, b) => String(b.createdAt || '').localeCompare(String(a.createdAt || '')));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Register `(sessionId, workDir)` in the central registry so the next
|
|
203
|
+
* `snapshotSessions()` includes this session.
|
|
204
|
+
*
|
|
205
|
+
* Validates that `<workDir>/.yeaft/sessions/<sessionId>/group.json` exists
|
|
206
|
+
* and is parseable. Throws:
|
|
207
|
+
* - `not_found` — the session dir is not on disk at this workdir
|
|
208
|
+
* - `corrupt_meta` — the dir exists but `group.json` is missing / unreadable
|
|
209
|
+
* / can't be parsed. Surfaced as a distinct code so the
|
|
210
|
+
* UI can tell the user "the file is broken" instead of
|
|
211
|
+
* "you picked the wrong workdir" (review finding I1).
|
|
212
|
+
*
|
|
213
|
+
* Idempotent: if the same `(sessionId, workDir)` is already registered,
|
|
214
|
+
* we still rewrite the entry (with the normalized path) and return the
|
|
215
|
+
* fresh meta — no error.
|
|
216
|
+
*
|
|
217
|
+
* @param {string} defaultYeaftDir
|
|
218
|
+
* @param {string} sessionId
|
|
219
|
+
* @param {string} workDir
|
|
220
|
+
* @returns {object} the session meta, with `workDir` set to the normalized path.
|
|
221
|
+
*/
|
|
222
|
+
export function restoreSessionToRegistry(defaultYeaftDir, sessionId, workDir) {
|
|
223
|
+
if (!sessionId) throw new SessionCrudError('invalid_session_id', null);
|
|
224
|
+
const normalized = normalizeWorkDir(workDir);
|
|
225
|
+
if (!normalized) throw new SessionCrudError('invalid_workdir', sessionId);
|
|
226
|
+
const groupYeaftDir = yeaftDirForWorkDir(normalized);
|
|
227
|
+
const dir = join(sessionsRoot(groupYeaftDir), sessionId);
|
|
228
|
+
if (!existsSync(dir)) throw new SessionCrudError('not_found', sessionId);
|
|
229
|
+
const meta = loadSessionMeta(dir);
|
|
230
|
+
if (!meta) throw new SessionCrudError('corrupt_meta', sessionId, `group.json missing or unreadable at ${dir}`);
|
|
231
|
+
registerSessionWorkDir(defaultYeaftDir, sessionId, normalized);
|
|
232
|
+
return { ...meta, workDir: normalized };
|
|
233
|
+
}
|
|
234
|
+
|
|
155
235
|
export function resolveSessionYeaftDir(defaultYeaftDir, sessionId) {
|
|
156
236
|
if (!defaultYeaftDir || !sessionId) return defaultYeaftDir;
|
|
157
237
|
const defaultGroupDir = join(sessionsRoot(defaultYeaftDir), sessionId);
|
package/yeaft/web-bridge.js
CHANGED
|
@@ -43,6 +43,9 @@ import {
|
|
|
43
43
|
snapshotSessions,
|
|
44
44
|
resolveSessionYeaftDir,
|
|
45
45
|
sessionsRoot,
|
|
46
|
+
scanWorkdirSessions,
|
|
47
|
+
restoreSessionToRegistry,
|
|
48
|
+
readWorkDirRegistry,
|
|
46
49
|
} from './sessions/session-crud.js';
|
|
47
50
|
import { openSession, loadSessionMeta } from './sessions/session-store.js';
|
|
48
51
|
import { loadSessionConfig, resolveSessionConfig, SessionConfigError } from './sessions/session-config.js';
|
|
@@ -1501,6 +1504,63 @@ export function handleYeaftCreateSession(msg) {
|
|
|
1501
1504
|
}
|
|
1502
1505
|
}
|
|
1503
1506
|
|
|
1507
|
+
/**
|
|
1508
|
+
* `yeaft_scan_workdir_sessions` — read-only probe: list every yeaft
|
|
1509
|
+
* session physically present under `<workDir>/.yeaft/sessions/` along with
|
|
1510
|
+
* an `alreadyRegistered` flag (so the restore UI can disable sessions
|
|
1511
|
+
* already visible in the sidebar). Never mutates the registry; never
|
|
1512
|
+
* throws on missing/empty directories.
|
|
1513
|
+
*
|
|
1514
|
+
* Pairs with `handleYeaftRestoreSession` for the "Restore session from a
|
|
1515
|
+
* workdir" flow — see plan rosy-snuggling-waterfall.md.
|
|
1516
|
+
*/
|
|
1517
|
+
export function handleYeaftScanWorkdirSessions(msg) {
|
|
1518
|
+
const requestId = msg && msg.requestId;
|
|
1519
|
+
try {
|
|
1520
|
+
const workDir = String(msg && msg.workDir || '').trim();
|
|
1521
|
+
if (!workDir) throw new SessionCrudError('invalid_workdir', null, 'workDir required');
|
|
1522
|
+
const yeaftDir = ctx.CONFIG?.yeaftDir;
|
|
1523
|
+
// scanWorkdirSessions is a layer-pure utility — it doesn't read the
|
|
1524
|
+
// central workdir registry. The handler is the right layer to fold in
|
|
1525
|
+
// `alreadyRegistered` because that flag couples the per-workdir scan
|
|
1526
|
+
// to a specific agent's registry (the same scan from a CLI tool or
|
|
1527
|
+
// a different agent would compare against a different registry).
|
|
1528
|
+
const sessions = scanWorkdirSessions(workDir);
|
|
1529
|
+
const registry = readWorkDirRegistry(yeaftDir);
|
|
1530
|
+
const decorated = sessions.map(s => ({
|
|
1531
|
+
...s,
|
|
1532
|
+
alreadyRegistered: Object.prototype.hasOwnProperty.call(registry, s.id),
|
|
1533
|
+
}));
|
|
1534
|
+
sendSessionCrudResult({ op: 'scan_workdir', requestId, ok: true, sessions: decorated });
|
|
1535
|
+
} catch (err) {
|
|
1536
|
+
sendSessionCrudResult({ op: 'scan_workdir', requestId, ok: false, error: sessionErrorPayload(err) });
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
/**
|
|
1541
|
+
* `yeaft_restore_session` — register `(sessionId, workDir)` in the
|
|
1542
|
+
* central workdir registry so the next `snapshotSessions()` includes
|
|
1543
|
+
* the session. Validates the session dir exists; rebroadcasts the
|
|
1544
|
+
* snapshot on success so connected sidebars refresh.
|
|
1545
|
+
*
|
|
1546
|
+
* Idempotent: re-restoring an already-registered session succeeds.
|
|
1547
|
+
*/
|
|
1548
|
+
export function handleYeaftRestoreSession(msg) {
|
|
1549
|
+
const requestId = msg && msg.requestId;
|
|
1550
|
+
const sessionId = msg && msg.sessionId;
|
|
1551
|
+
const workDir = String(msg && msg.workDir || '').trim();
|
|
1552
|
+
try {
|
|
1553
|
+
if (!sessionId) throw new SessionCrudError('invalid_session_id', null);
|
|
1554
|
+
if (!workDir) throw new SessionCrudError('invalid_workdir', sessionId);
|
|
1555
|
+
const yeaftDir = ctx.CONFIG?.yeaftDir;
|
|
1556
|
+
const meta = restoreSessionToRegistry(yeaftDir, sessionId, workDir);
|
|
1557
|
+
sendSessionCrudResult({ op: 'restore', requestId, ok: true, session: meta });
|
|
1558
|
+
sendSessionSnapshotBroadcast();
|
|
1559
|
+
} catch (err) {
|
|
1560
|
+
sendSessionCrudResult({ op: 'restore', requestId, ok: false, error: sessionErrorPayload(err) });
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1504
1564
|
export function handleYeaftRenameSession(msg) {
|
|
1505
1565
|
const requestId = msg && msg.requestId;
|
|
1506
1566
|
// fix-yeaft-delete-and-agent-revert: accept legacy `groupId` in
|