@yeaft/webchat-agent 1.0.475 → 1.0.477

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "1.0.475",
3
+ "version": "1.0.477",
4
4
  "description": "Remote worker agent for Yeaft Web Code Agent — connects the native Yeaft engine, CLI providers, and workbench tools",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -290,49 +290,49 @@ export function migrateRegisteredWorkDirSessions(yeaftDir) {
290
290
  }
291
291
 
292
292
  /**
293
- * Scan the `.yeaft/sessions/` directory under `workDir` and return every
294
- * session meta we can read. Read-only: never touches the registry.
293
+ * List every Session owned by `yeaftDir` whose normalized workDir matches.
294
+ * Workdir-local `.yeaft/sessions` is also read as a legacy import fallback;
295
+ * those rows are marked `legacyImport` and never replace a current row with
296
+ * the same Session id. The normal Session snapshot may repair its own manifest;
297
+ * this query never writes the legacy workdir registry.
295
298
  *
296
- * Each returned record carries `workDir` (the normalized path we scanned).
297
- * This utility deliberately does NOT decorate `alreadyRegistered` — that
298
- * cross-references the central workdir registry, which is a separate
299
- * concern owned by the handler / caller (see
300
- * `handleYeaftScanWorkdirSessions`). Keeping the utility layer-pure makes
301
- * it usable from contexts that don't have / don't care about the registry
302
- * (e.g. CLI tools, future per-workdir snapshots).
303
- *
304
- * Returns `[]` for missing dir / empty dir / unreadable dir — never throws.
305
- * Sort is `createdAt` descending (most-recent first) because the restore
306
- * UI typically cares about "the session I made yesterday".
307
- *
308
- * @param {string} workDir — the working directory to scan.
299
+ * @param {string} workDir working directory to match
300
+ * @param {string|null} yeaftDir Agent-owned data root; omit for legacy scans
309
301
  * @returns {Array<object>}
310
302
  */
311
- export function scanWorkdirSessions(workDir) {
303
+ export function scanWorkdirSessions(workDir, yeaftDir = null) {
312
304
  const normalized = normalizeWorkDir(workDir);
313
305
  if (!normalized) return [];
306
+
307
+ // Session storage is Agent-owned. The workDir-local `.yeaft/sessions`
308
+ // location below is only a legacy import source; querying a folder must
309
+ // start from the Agent manifest so sidebar UI metadata cannot hide an
310
+ // otherwise valid Session from the create/resume picker.
311
+ const currentSessions = yeaftDir
312
+ ? snapshotSessions(yeaftDir).filter(meta => normalizeWorkDir(meta.workDir) === normalized)
313
+ : [];
314
+ const seen = new Set(currentSessions.map(meta => meta.id));
314
315
  const groupYeaftDir = yeaftDirForWorkDir(normalized);
315
316
  const root = sessionsRoot(groupYeaftDir);
316
- if (!existsSync(root)) return [];
317
- const out = [];
318
- let entries;
317
+ const legacySessions = [];
318
+ let entries = [];
319
319
  try {
320
- entries = readdirSync(root);
321
- } catch {
322
- return [];
323
- }
320
+ if (existsSync(root)) entries = readdirSync(root);
321
+ } catch { /* treat an unreadable legacy root as empty */ }
324
322
  for (const name of entries) {
325
- if (name.startsWith('.')) continue; // skip .archived-* and dotfiles
323
+ if (name.startsWith('.') || seen.has(name)) continue;
326
324
  const dir = join(root, name);
327
325
  try { if (!statSync(dir).isDirectory()) continue; } catch { continue; }
328
326
  const meta = loadSessionMeta(dir);
329
- if (!meta) continue;
330
- out.push({
327
+ if (!meta || seen.has(meta.id)) continue;
328
+ legacySessions.push({
331
329
  ...meta,
332
330
  workDir: normalized,
331
+ legacyImport: true,
333
332
  });
334
333
  }
335
- return out.sort((a, b) => String(b.createdAt || '').localeCompare(String(a.createdAt || '')));
334
+ return [...currentSessions, ...legacySessions]
335
+ .sort((a, b) => String(b.createdAt || '').localeCompare(String(a.createdAt || '')));
336
336
  }
337
337
 
338
338
  /**
@@ -3595,13 +3595,13 @@ export function handleYeaftScanWorkdirSessions(msg) {
3595
3595
  const workDir = String(msg && msg.workDir || '').trim();
3596
3596
  if (!workDir) throw new SessionCrudError('invalid_workdir', null, 'workDir required');
3597
3597
  const yeaftDir = ctx.CONFIG?.yeaftDir;
3598
- // scanWorkdirSessions is now a compatibility no-op because Session data is
3599
- // user-level only. Keep the decoration shape stable for older clients.
3600
- const sessions = scanWorkdirSessions(workDir);
3598
+ // Current rows come from the Agent manifest; workDir-local rows remain a
3599
+ // legacy import fallback. Keep the decoration shape stable for old clients.
3600
+ const sessions = scanWorkdirSessions(workDir, yeaftDir);
3601
3601
  const registry = readWorkDirRegistry(yeaftDir);
3602
3602
  const decorated = sessions.map(s => ({
3603
3603
  ...s,
3604
- alreadyRegistered: Object.prototype.hasOwnProperty.call(registry, s.id),
3604
+ alreadyRegistered: !s.legacyImport || Object.prototype.hasOwnProperty.call(registry, s.id),
3605
3605
  }));
3606
3606
  sendSessionCrudResult({ op: 'scan_workdir', requestId, ok: true, sessions: decorated });
3607
3607
  } catch (err) {