@yeaft/webchat-agent 0.1.811 → 0.1.813

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": "0.1.811",
3
+ "version": "0.1.813",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -28,6 +28,7 @@ import { STOCK_VP_IDS } from './stock-ids.js';
28
28
  /** Process-singleton VpLoader; lazily started on first subscribe. */
29
29
  let _loaderStarted = false;
30
30
  let _loader = null;
31
+ let _loaderDir = null;
31
32
 
32
33
  /**
33
34
  * Broadcast fan-out. VpLoader.onChange fires once per debounce batch for the
@@ -145,21 +146,33 @@ function _fanout(evt) {
145
146
  }
146
147
  }
147
148
 
148
- function ensureLoader(registry = defaultRegistry) {
149
- if (_loaderStarted) return { loader: _loader, fresh: false };
149
+ function ensureLoader(registry = defaultRegistry, options = {}) {
150
+ const desiredDir = registry === defaultRegistry && typeof options.dir === 'string' && options.dir.trim()
151
+ ? options.dir.trim()
152
+ : null;
153
+ if (_loaderStarted && _loaderDir === desiredDir) return { loader: _loader, fresh: false };
154
+
155
+ if (_loader) {
156
+ try { _loader.stop(); } catch { /* ignore */ }
157
+ }
150
158
  _loaderStarted = true;
159
+ _loader = null;
160
+ _loaderDir = desiredDir;
161
+ if (registry === defaultRegistry && registry.vpMap && typeof registry.vpMap.clear === 'function') {
162
+ registry.vpMap.clear();
163
+ }
151
164
  // For NON-default registries (unit tests seeding VPs manually) we MUST NOT
152
- // start VpLoader — its .start() scans DEFAULT_VP_LIB_DIR and push-imports
153
- // every on-disk VP into the test registry, overwriting/augmenting the
154
- // fixture. Tests don't need hot-reload anyway; `_broadcastChangeForTest`
155
- // drives the diff path directly.
165
+ // start VpLoader — its .start() scans the configured/default VP library and
166
+ // push-imports every on-disk VP into the test registry, overwriting or
167
+ // augmenting the fixture. Tests don't need hot-reload anyway;
168
+ // `_broadcastChangeForTest` drives the diff path directly.
156
169
  if (registry !== defaultRegistry) {
157
- _loader = null;
158
170
  captureState(registry);
159
171
  return { loader: null, fresh: true };
160
172
  }
161
173
  try {
162
174
  _loader = new VpLoader({
175
+ ...(desiredDir ? { dir: desiredDir } : {}),
163
176
  registry,
164
177
  onChange: (summary) => broadcastChange(summary, registry),
165
178
  });
@@ -228,10 +241,11 @@ export function buildVpSnapshot(registry = defaultRegistry) {
228
241
  *
229
242
  * @param {(event: object) => void} sendUnifyEvent
230
243
  * @param {import('./registry.js').Registry} [registry]
244
+ * @param {{dir?: string}} [options]
231
245
  * @returns {() => void} unsubscribe fn
232
246
  */
233
- export function handleVpSubscribe(sendUnifyEvent, registry = defaultRegistry) {
234
- const { loader, fresh } = ensureLoader(registry);
247
+ export function handleVpSubscribe(sendUnifyEvent, registry = defaultRegistry, options = {}) {
248
+ const { loader, fresh } = ensureLoader(registry, options);
235
249
  // task-338-F2 + task-339-followup: replay semantics.
236
250
  //
237
251
  // The loader's own start() already scans on first creation, so on a
@@ -245,9 +259,9 @@ export function handleVpSubscribe(sendUnifyEvent, registry = defaultRegistry) {
245
259
  // production path so the first snapshot always reflects current disk.
246
260
  //
247
261
  // For NON-default registries (unit tests that seed VPs manually), we
248
- // MUST skip the rescan: rescan against DEFAULT_VP_LIB_DIR would call
249
- // registry.removeVp() for seeded ids that don't exist on disk, wiping
250
- // the test fixture. See vp-bridge-live-diff.test.js and
262
+ // MUST skip the rescan: rescan against the configured/default VP library
263
+ // would call registry.removeVp() for seeded ids that don't exist on disk,
264
+ // wiping the test fixture. See vp-bridge-live-diff.test.js and
251
265
  // vp-bridge-first-subscribe-replay.test.js (test-seed preservation).
252
266
  //
253
267
  // On subsequent subscribes (page reload, reconnect, second web client)
@@ -277,6 +291,7 @@ export function _resetVpBridgeForTest() {
277
291
  }
278
292
  _loader = null;
279
293
  _loaderStarted = false;
294
+ _loaderDir = null;
280
295
  _subscribers.clear();
281
296
  _prevState.clear();
282
297
  }
@@ -1188,12 +1188,27 @@ function sendUnifyEvent(event, { groupId, vpId, turnId, threadId } = {}) {
1188
1188
  });
1189
1189
  }
1190
1190
 
1191
+ function configuredVpPaths() {
1192
+ const yeaftDir = ctx.CONFIG?.yeaftDir;
1193
+ if (typeof yeaftDir !== 'string' || !yeaftDir.trim()) return {};
1194
+ const root = yeaftDir.trim();
1195
+ return {
1196
+ libDir: join(root, 'virtual-persons'),
1197
+ memoryRoot: join(root, 'memory'),
1198
+ };
1199
+ }
1200
+
1191
1201
  export function handleUnifyVpSubscribe(_msg) {
1192
1202
  if (_vpUnsubscribe) {
1193
1203
  try { _vpUnsubscribe(); } catch { /* ignore */ }
1194
1204
  _vpUnsubscribe = null;
1195
1205
  }
1196
- _vpUnsubscribe = handleVpSubscribe(sendUnifyEvent);
1206
+ const { libDir } = configuredVpPaths();
1207
+ _vpUnsubscribe = handleVpSubscribe(
1208
+ sendUnifyEvent,
1209
+ undefined,
1210
+ libDir ? { dir: libDir } : {},
1211
+ );
1197
1212
  }
1198
1213
 
1199
1214
  /**
@@ -1207,9 +1222,12 @@ export function handleUnifyVpCreate(msg) {
1207
1222
  const requestId = msg && msg.requestId;
1208
1223
  const payload = msg && msg.payload;
1209
1224
  try {
1210
- const yeaftDir = ctx.CONFIG?.yeaftDir;
1211
- const memoryRoot = yeaftDir ? join(yeaftDir, 'memory') : undefined;
1212
- const { vpId } = createVp(payload || {}, memoryRoot ? { memoryRoot } : {});
1225
+ const { libDir, memoryRoot } = configuredVpPaths();
1226
+ const options = {
1227
+ ...(libDir ? { libDir } : {}),
1228
+ ...(memoryRoot ? { memoryRoot } : {}),
1229
+ };
1230
+ const { vpId } = createVp(payload || {}, options);
1213
1231
  sendVpCrudResult({ op: 'create', requestId, ok: true, vpId });
1214
1232
  } catch (err) {
1215
1233
  sendVpCrudResult({
@@ -1229,7 +1247,8 @@ export function handleUnifyVpUpdate(msg) {
1229
1247
  const requestId = msg && msg.requestId;
1230
1248
  const payload = msg && msg.payload;
1231
1249
  try {
1232
- const { vpId } = updateVp(payload || {});
1250
+ const { libDir } = configuredVpPaths();
1251
+ const { vpId } = updateVp(payload || {}, libDir ? { libDir } : {});
1233
1252
  sendVpCrudResult({ op: 'update', requestId, ok: true, vpId });
1234
1253
  } catch (err) {
1235
1254
  sendVpCrudResult({
@@ -1249,9 +1268,12 @@ export function handleUnifyVpDelete(msg) {
1249
1268
  const requestId = msg && msg.requestId;
1250
1269
  const vpId = msg && msg.vpId;
1251
1270
  try {
1252
- const yeaftDir = ctx.CONFIG?.yeaftDir;
1253
- const memoryRoot = yeaftDir ? join(yeaftDir, 'memory') : undefined;
1254
- deleteVp(vpId, memoryRoot ? { memoryRoot } : {});
1271
+ const { libDir, memoryRoot } = configuredVpPaths();
1272
+ const options = {
1273
+ ...(libDir ? { libDir } : {}),
1274
+ ...(memoryRoot ? { memoryRoot } : {}),
1275
+ };
1276
+ deleteVp(vpId, options);
1255
1277
  // vp-status: a deleted VP must not haunt the snapshot. We don't
1256
1278
  // know up front which groups the VP appeared in (the registry's
1257
1279
  // delete already detached it from every group), so sweep every
@@ -1282,7 +1304,8 @@ export function handleUnifyVpDelete(msg) {
1282
1304
  export function handleUnifyVpRead(msg) {
1283
1305
  const requestId = msg && msg.requestId;
1284
1306
  const vpId = msg && msg.vpId;
1285
- const vp = readVp(vpId);
1307
+ const { libDir } = configuredVpPaths();
1308
+ const vp = readVp(vpId, libDir ? { libDir } : {});
1286
1309
  if (!vp) {
1287
1310
  sendVpCrudResult({
1288
1311
  op: 'read',