@pellux/goodvibes-sdk 0.33.37 → 0.34.0
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/dist/client-auth/control-plane-auth-snapshot.d.ts +23 -0
- package/dist/client-auth/control-plane-auth-snapshot.d.ts.map +1 -1
- package/dist/client-auth/oauth-types.d.ts +18 -0
- package/dist/client-auth/oauth-types.d.ts.map +1 -1
- package/dist/client-auth/types.d.ts +26 -0
- package/dist/client-auth/types.d.ts.map +1 -1
- package/dist/client.d.ts +22 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/contracts/artifacts/operator-contract.json +1463 -10
- package/dist/events/knowledge.d.ts +31 -0
- package/dist/events/knowledge.d.ts.map +1 -1
- package/dist/events/tasks.d.ts +58 -0
- package/dist/events/tasks.d.ts.map +1 -1
- package/dist/events/transport.d.ts +60 -0
- package/dist/events/transport.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-config.d.ts +6 -0
- package/dist/platform/agents/wrfc-config.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-config.js +6 -0
- package/dist/platform/agents/wrfc-controller.d.ts +74 -0
- package/dist/platform/agents/wrfc-controller.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-controller.js +368 -9
- package/dist/platform/agents/wrfc-reporting.d.ts +60 -0
- package/dist/platform/agents/wrfc-reporting.d.ts.map +1 -1
- package/dist/platform/agents/wrfc-reporting.js +131 -7
- package/dist/platform/agents/wrfc-types.d.ts +12 -0
- package/dist/platform/agents/wrfc-types.d.ts.map +1 -1
- package/dist/platform/config/manager.d.ts +11 -0
- package/dist/platform/config/manager.d.ts.map +1 -1
- package/dist/platform/config/manager.js +17 -1
- package/dist/platform/config/schema-domain-core.d.ts +2 -0
- package/dist/platform/config/schema-domain-core.d.ts.map +1 -1
- package/dist/platform/config/schema-domain-core.js +17 -0
- package/dist/platform/config/schema-shared.d.ts +6 -0
- package/dist/platform/config/schema-shared.d.ts.map +1 -1
- package/dist/platform/config/schema-types.d.ts +9 -2
- package/dist/platform/config/schema-types.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog-calendar.d.ts +9 -0
- package/dist/platform/control-plane/method-catalog-calendar.d.ts.map +1 -0
- package/dist/platform/control-plane/method-catalog-calendar.js +117 -0
- package/dist/platform/control-plane/method-catalog-channels.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog-channels.js +174 -0
- package/dist/platform/control-plane/method-catalog-control-automation.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog-control-automation.js +10 -4
- package/dist/platform/control-plane/method-catalog-email.d.ts +9 -0
- package/dist/platform/control-plane/method-catalog-email.d.ts.map +1 -0
- package/dist/platform/control-plane/method-catalog-email.js +101 -0
- package/dist/platform/control-plane/method-catalog-knowledge.js +4 -4
- package/dist/platform/control-plane/method-catalog-runtime.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog-runtime.js +13 -0
- package/dist/platform/control-plane/method-catalog.d.ts.map +1 -1
- package/dist/platform/control-plane/method-catalog.js +4 -0
- package/dist/platform/control-plane/routes/automation.js +2 -2
- package/dist/platform/control-plane/routes/operator.d.ts.map +1 -1
- package/dist/platform/control-plane/routes/operator.js +2 -0
- package/dist/platform/control-plane/routes/sessions.js +1 -1
- package/dist/platform/daemon/http/router.d.ts.map +1 -1
- package/dist/platform/daemon/http/router.js +12 -2
- package/dist/platform/daemon/http-listener.d.ts +17 -0
- package/dist/platform/daemon/http-listener.d.ts.map +1 -1
- package/dist/platform/daemon/http-listener.js +186 -7
- package/dist/platform/knowledge/knowledge-api.d.ts +1 -1
- package/dist/platform/knowledge/knowledge-api.d.ts.map +1 -1
- package/dist/platform/knowledge/knowledge-api.js +1 -1
- package/dist/platform/runtime/store/helpers/reducers/lifecycle.d.ts.map +1 -1
- package/dist/platform/runtime/store/helpers/reducers/lifecycle.js +4 -0
- package/dist/platform/runtime/store/helpers/reducers/sync.d.ts.map +1 -1
- package/dist/platform/runtime/store/helpers/reducers/sync.js +4 -0
- package/dist/platform/security/http-auth.d.ts.map +1 -1
- package/dist/platform/security/http-auth.js +11 -4
- package/dist/platform/security/user-auth.d.ts +98 -2
- package/dist/platform/security/user-auth.d.ts.map +1 -1
- package/dist/platform/security/user-auth.js +195 -18
- package/dist/platform/sessions/manager.d.ts +19 -2
- package/dist/platform/sessions/manager.d.ts.map +1 -1
- package/dist/platform/sessions/manager.js +43 -6
- package/dist/platform/state/memory-registry.d.ts +1 -1
- package/dist/platform/state/memory-registry.d.ts.map +1 -1
- package/dist/platform/state/memory-registry.js +2 -2
- package/dist/platform/state/memory-store.d.ts +1 -1
- package/dist/platform/state/memory-store.d.ts.map +1 -1
- package/dist/platform/state/memory-store.js +2 -2
- package/dist/platform/version.js +1 -1
- package/package.json +9 -9
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import { createHash, randomBytes, scryptSync, timingSafeEqual } from 'crypto';
|
|
2
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { chmodSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
const DEFAULT_SESSION_TTL_MS = 3_600_000;
|
|
6
6
|
const DEFAULT_MAX_SESSIONS = 1000;
|
|
7
|
+
const DEFAULT_MAX_ACCOUNT_LOCKS = 10_000;
|
|
7
8
|
const SCRYPT_KEY_LENGTH = 64;
|
|
9
|
+
/** Default scrypt cost parameters matching Node.js defaults (N=16384, r=8, p=1). */
|
|
10
|
+
const DEFAULT_SCRYPT_PARAMS = { N: 16384, r: 8, p: 1 };
|
|
8
11
|
function toBase64(value) {
|
|
9
12
|
return value.toString('base64');
|
|
10
13
|
}
|
|
11
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Hash format: base64(salt):N:r:p:base64(derived)
|
|
16
|
+
* The cost parameters are stored in the hash so old hashes can be verified
|
|
17
|
+
* even after the default params change.
|
|
18
|
+
*/
|
|
19
|
+
function hashPassword(password, params = DEFAULT_SCRYPT_PARAMS, salt) {
|
|
12
20
|
const actualSalt = salt ?? randomBytes(16);
|
|
13
|
-
const derived = scryptSync(password, actualSalt, SCRYPT_KEY_LENGTH);
|
|
14
|
-
return `${toBase64(actualSalt)}:${toBase64(derived)}`;
|
|
21
|
+
const derived = scryptSync(password, actualSalt, SCRYPT_KEY_LENGTH, { N: params.N, r: params.r, p: params.p });
|
|
22
|
+
return `${toBase64(actualSalt)}:${params.N}:${params.r}:${params.p}:${toBase64(derived)}`;
|
|
15
23
|
}
|
|
16
24
|
/**
|
|
17
25
|
* Generate a cryptographically random one-time password.
|
|
@@ -21,15 +29,43 @@ function generateInitialPassword() {
|
|
|
21
29
|
return randomBytes(16).toString('hex');
|
|
22
30
|
}
|
|
23
31
|
function verifyPassword(password, passwordHash) {
|
|
24
|
-
const
|
|
32
|
+
const parts = passwordHash.split(':');
|
|
33
|
+
// Legacy format: salt:hash (2 parts) — uses DEFAULT_SCRYPT_PARAMS for backward compat.
|
|
34
|
+
// New format: salt:N:r:p:hash (5 parts)
|
|
35
|
+
let saltEncoded;
|
|
36
|
+
let hashEncoded;
|
|
37
|
+
let params;
|
|
38
|
+
if (parts.length === 2) {
|
|
39
|
+
// Legacy hash: no cost params stored — use defaults.
|
|
40
|
+
[saltEncoded, hashEncoded] = parts;
|
|
41
|
+
params = DEFAULT_SCRYPT_PARAMS;
|
|
42
|
+
}
|
|
43
|
+
else if (parts.length === 5) {
|
|
44
|
+
const N = Number(parts[1]);
|
|
45
|
+
const r = Number(parts[2]);
|
|
46
|
+
const p = Number(parts[3]);
|
|
47
|
+
if (!Number.isInteger(N) || N < 1 || !Number.isInteger(r) || r < 1 || !Number.isInteger(p) || p < 1)
|
|
48
|
+
return false;
|
|
49
|
+
saltEncoded = parts[0];
|
|
50
|
+
hashEncoded = parts[4];
|
|
51
|
+
params = { N, r, p };
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
25
56
|
if (!saltEncoded || !hashEncoded)
|
|
26
57
|
return false;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
58
|
+
try {
|
|
59
|
+
const salt = Buffer.from(saltEncoded, 'base64');
|
|
60
|
+
const expected = Buffer.from(hashEncoded, 'base64');
|
|
61
|
+
const actual = scryptSync(password, salt, SCRYPT_KEY_LENGTH, { N: params.N, r: params.r, p: params.p });
|
|
62
|
+
if (actual.length !== expected.length)
|
|
63
|
+
return false;
|
|
64
|
+
return timingSafeEqual(actual, expected);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
31
67
|
return false;
|
|
32
|
-
|
|
68
|
+
}
|
|
33
69
|
}
|
|
34
70
|
function fingerprintToken(token) {
|
|
35
71
|
return createHash('sha256').update(token).digest('hex').slice(0, 16);
|
|
@@ -59,7 +95,8 @@ function readBootstrapUsers(filePath) {
|
|
|
59
95
|
* some Linux fs drivers).
|
|
60
96
|
*/
|
|
61
97
|
function atomicWriteSecretFile(filePath, content) {
|
|
62
|
-
|
|
98
|
+
const dir = dirname(filePath);
|
|
99
|
+
mkdirSync(dir, { recursive: true });
|
|
63
100
|
const tmpPath = filePath + '.tmp';
|
|
64
101
|
writeFileSync(tmpPath, content, { encoding: 'utf-8', mode: 0o600 });
|
|
65
102
|
try {
|
|
@@ -68,7 +105,23 @@ function atomicWriteSecretFile(filePath, content) {
|
|
|
68
105
|
catch (error) {
|
|
69
106
|
logger.warn('User auth secret temp chmod failed', { path: tmpPath, error: String(error) });
|
|
70
107
|
}
|
|
108
|
+
// fsync the file data before rename so the content survives power loss.
|
|
109
|
+
const fd = openSync(tmpPath, 'r+');
|
|
110
|
+
try {
|
|
111
|
+
fsyncSync(fd);
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
closeSync(fd);
|
|
115
|
+
}
|
|
71
116
|
renameSync(tmpPath, filePath);
|
|
117
|
+
// fsync the parent directory so the directory entry (rename) is durable.
|
|
118
|
+
const dirFd = openSync(dir, 'r');
|
|
119
|
+
try {
|
|
120
|
+
fsyncSync(dirFd);
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
closeSync(dirFd);
|
|
124
|
+
}
|
|
72
125
|
try {
|
|
73
126
|
chmodSync(filePath, 0o600);
|
|
74
127
|
}
|
|
@@ -158,11 +211,17 @@ function detectBootstrapCredentialDrift(users, credentialPath, userStorePath) {
|
|
|
158
211
|
export class UserAuthManager {
|
|
159
212
|
users = new Map();
|
|
160
213
|
sessions = new Map();
|
|
214
|
+
/** Per-username failure counters for account-level lockout (independent of IP throttling). */
|
|
215
|
+
accountLocks = new Map();
|
|
161
216
|
sessionTtlMs;
|
|
162
217
|
maxSessions;
|
|
218
|
+
maxAccountLocks;
|
|
163
219
|
userStorePath;
|
|
164
220
|
bootstrapCredentialPath;
|
|
165
221
|
persistUsers;
|
|
222
|
+
scryptParams;
|
|
223
|
+
/** Injectable clock — defaults to Date.now for production. */
|
|
224
|
+
nowFn;
|
|
166
225
|
constructor(config) {
|
|
167
226
|
if (!config.bootstrapFilePath)
|
|
168
227
|
throw new Error('UserAuthManager requires an explicit bootstrapFilePath.');
|
|
@@ -170,9 +229,12 @@ export class UserAuthManager {
|
|
|
170
229
|
throw new Error('UserAuthManager requires an explicit bootstrapCredentialPath.');
|
|
171
230
|
this.sessionTtlMs = config.sessionTtlMs ?? DEFAULT_SESSION_TTL_MS;
|
|
172
231
|
this.maxSessions = config.maxSessions ?? DEFAULT_MAX_SESSIONS;
|
|
232
|
+
this.maxAccountLocks = config.maxAccountLocks ?? DEFAULT_MAX_ACCOUNT_LOCKS;
|
|
173
233
|
this.userStorePath = config.bootstrapFilePath;
|
|
174
234
|
this.bootstrapCredentialPath = config.bootstrapCredentialPath;
|
|
175
235
|
this.persistUsers = config.users === undefined;
|
|
236
|
+
this.scryptParams = config.scryptParams ?? DEFAULT_SCRYPT_PARAMS;
|
|
237
|
+
this.nowFn = config.nowFn ?? (() => Date.now());
|
|
176
238
|
const seedUsers = config.users ?? loadOrBootstrapUsers(this.userStorePath, this.bootstrapCredentialPath);
|
|
177
239
|
for (const user of seedUsers) {
|
|
178
240
|
this.users.set(user.username, user);
|
|
@@ -184,14 +246,129 @@ export class UserAuthManager {
|
|
|
184
246
|
detectBootstrapCredentialDrift(seedUsers, this.bootstrapCredentialPath, this.userStorePath);
|
|
185
247
|
}
|
|
186
248
|
}
|
|
187
|
-
static hashPassword(password) {
|
|
188
|
-
return hashPassword(password);
|
|
249
|
+
static hashPassword(password, params) {
|
|
250
|
+
return hashPassword(password, params ?? DEFAULT_SCRYPT_PARAMS);
|
|
189
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Authenticate username/password with per-account lockout.
|
|
254
|
+
* - Does NOT leak whether a username exists (same generic error path for unknown users).
|
|
255
|
+
* - Records failures against the username bucket (not IP) with escalating backoff.
|
|
256
|
+
* - Returns lockedUntilMs when the account is temporarily locked.
|
|
257
|
+
* - Returns usedBootstrapCredential=true when the matched credential originated from
|
|
258
|
+
* the bootstrap credential file, so callers can defer retirement until a non-bootstrap
|
|
259
|
+
* login succeeds.
|
|
260
|
+
*/
|
|
190
261
|
authenticate(username, password) {
|
|
262
|
+
const now = this.nowFn();
|
|
263
|
+
const lockState = this.accountLocks.get(username);
|
|
264
|
+
// Check account lock (before touching user store — avoids user-existence side-channel).
|
|
265
|
+
if (lockState && lockState.lockedUntil > now) {
|
|
266
|
+
// Still locked — record the attempt but keep the lock window intact.
|
|
267
|
+
lockState.failures++;
|
|
268
|
+
return { ok: false, lockedUntilMs: lockState.lockedUntil };
|
|
269
|
+
}
|
|
191
270
|
const user = this.users.get(username);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
271
|
+
// Always verify something with constant-time cost so unknown usernames
|
|
272
|
+
// have the same timing profile as known usernames with wrong password.
|
|
273
|
+
const hashToCheck = user?.passwordHash ?? 'dGVzdHNhbHQ=:16384:8:1:dGVzdGhhc2h0ZXN0aGFzaHRlc3RoYXNodGVzdGhhc2g=';
|
|
274
|
+
const passwordOk = user !== undefined && verifyPassword(password, hashToCheck);
|
|
275
|
+
if (!passwordOk) {
|
|
276
|
+
this._recordLoginFailure(username, now);
|
|
277
|
+
// Check if this failure just triggered a lock.
|
|
278
|
+
const newLock = this.accountLocks.get(username);
|
|
279
|
+
const lockedUntilMs = newLock && newLock.lockedUntil > now ? newLock.lockedUntil : undefined;
|
|
280
|
+
return lockedUntilMs !== undefined ? { ok: false, lockedUntilMs } : { ok: false };
|
|
281
|
+
}
|
|
282
|
+
// Determine whether this login used the bootstrap credential.
|
|
283
|
+
// Compare against the credential file contents without leaking timing info
|
|
284
|
+
// (we already confirmed the password is correct at this point).
|
|
285
|
+
const bootstrapCred = readBootstrapCredentialFile(this.bootstrapCredentialPath);
|
|
286
|
+
const usedBootstrapCredential = bootstrapCred !== null
|
|
287
|
+
&& bootstrapCred.username === username
|
|
288
|
+
&& bootstrapCred.password === password;
|
|
289
|
+
// Success — clear failure count.
|
|
290
|
+
this.accountLocks.delete(username);
|
|
291
|
+
return { ok: true, user, usedBootstrapCredential };
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Record a login failure for the given username and apply escalating backoff.
|
|
295
|
+
*
|
|
296
|
+
* Thresholds are anchored ABOVE the per-IP login budget (default 5/min) so
|
|
297
|
+
* the first account lock cannot fire before the IP limiter has already
|
|
298
|
+
* throttled further attempts. This preserves the 401-then-429-by-IP contract
|
|
299
|
+
* for in-budget attempts.
|
|
300
|
+
*
|
|
301
|
+
* 1-5 failures: no lock (IP budget exhaustion fires at attempt 6+)
|
|
302
|
+
* 6-9 failures: 30-second lock
|
|
303
|
+
* 10-19 failures: 5-minute lock
|
|
304
|
+
* 20+ failures: 30-minute lock
|
|
305
|
+
*
|
|
306
|
+
* Note: failures also increment during an active lock window (when the account
|
|
307
|
+
* is already locked and another attempt arrives). This means a lock can expire
|
|
308
|
+
* with a failure count already in a higher tier, causing the next lock after
|
|
309
|
+
* expiry to jump directly to that tier. This is intentional: repeated attempts
|
|
310
|
+
* during a lock are themselves failures and escalate the penalty schedule.
|
|
311
|
+
*/
|
|
312
|
+
_recordLoginFailure(username, now) {
|
|
313
|
+
const existing = this.accountLocks.get(username);
|
|
314
|
+
if (!existing) {
|
|
315
|
+
// New entry — evict if at cap before inserting.
|
|
316
|
+
this._evictAccountLockIfNeeded(now);
|
|
317
|
+
}
|
|
318
|
+
const state = existing ?? { failures: 0, lockedUntil: 0 };
|
|
319
|
+
state.failures++;
|
|
320
|
+
const f = state.failures;
|
|
321
|
+
let lockDurationMs = 0;
|
|
322
|
+
if (f >= 20)
|
|
323
|
+
lockDurationMs = 30 * 60_000;
|
|
324
|
+
else if (f >= 10)
|
|
325
|
+
lockDurationMs = 5 * 60_000;
|
|
326
|
+
else if (f >= 6)
|
|
327
|
+
lockDurationMs = 30_000;
|
|
328
|
+
state.lockedUntil = lockDurationMs > 0 ? now + lockDurationMs : 0;
|
|
329
|
+
this.accountLocks.set(username, state);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Evict account lock entries when the map is at capacity.
|
|
333
|
+
* Prefers entries with expired locks + no recent failures (stale entries).
|
|
334
|
+
* Falls back to the entry with the oldest/soonest-expired lock.
|
|
335
|
+
* Preserves no-username-enumeration: eviction policy is time-based, not
|
|
336
|
+
* user-existence-based.
|
|
337
|
+
*/
|
|
338
|
+
_evictAccountLockIfNeeded(now) {
|
|
339
|
+
if (this.accountLocks.size < this.maxAccountLocks)
|
|
340
|
+
return;
|
|
341
|
+
// First sweep: remove all fully stale entries (lock expired AND low failure count).
|
|
342
|
+
for (const [key, state] of this.accountLocks.entries()) {
|
|
343
|
+
if (state.lockedUntil <= now && state.failures < 6) {
|
|
344
|
+
this.accountLocks.delete(key);
|
|
345
|
+
if (this.accountLocks.size < this.maxAccountLocks)
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// Second sweep: remove the entry with the smallest lockedUntil (most expired).
|
|
350
|
+
let oldestKey;
|
|
351
|
+
let oldestUntil = Infinity;
|
|
352
|
+
for (const [key, state] of this.accountLocks.entries()) {
|
|
353
|
+
if (state.lockedUntil < oldestUntil) {
|
|
354
|
+
oldestUntil = state.lockedUntil;
|
|
355
|
+
oldestKey = key;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (oldestKey !== undefined) {
|
|
359
|
+
this.accountLocks.delete(oldestKey);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Expose account lock state for testing.
|
|
364
|
+
* Returns a defensive copy so callers cannot mutate internal state.
|
|
365
|
+
* Use the injected nowFn (via UserAuthManager constructor) to advance time in tests.
|
|
366
|
+
*/
|
|
367
|
+
getAccountLockState(username) {
|
|
368
|
+
const state = this.accountLocks.get(username);
|
|
369
|
+
if (!state)
|
|
370
|
+
return undefined;
|
|
371
|
+
return { failures: state.failures, lockedUntil: state.lockedUntil };
|
|
195
372
|
}
|
|
196
373
|
getUser(username) {
|
|
197
374
|
const user = this.users.get(username);
|
|
@@ -286,7 +463,7 @@ export class UserAuthManager {
|
|
|
286
463
|
throw new Error('Password must be at least 8 characters.');
|
|
287
464
|
const user = {
|
|
288
465
|
username: normalized,
|
|
289
|
-
passwordHash: hashPassword(password),
|
|
466
|
+
passwordHash: hashPassword(password, this.scryptParams),
|
|
290
467
|
roles: [...new Set(roles.filter(Boolean))],
|
|
291
468
|
};
|
|
292
469
|
this.users.set(normalized, user);
|
|
@@ -315,7 +492,7 @@ export class UserAuthManager {
|
|
|
315
492
|
throw new Error('Password must be at least 8 characters.');
|
|
316
493
|
this.users.set(normalized, {
|
|
317
494
|
...existing,
|
|
318
|
-
passwordHash: hashPassword(nextPassword),
|
|
495
|
+
passwordHash: hashPassword(nextPassword, this.scryptParams),
|
|
319
496
|
});
|
|
320
497
|
this.revokeSessionsForUser(normalized);
|
|
321
498
|
this.persist();
|
|
@@ -11,6 +11,8 @@ export interface SessionMeta {
|
|
|
11
11
|
timestamp: number;
|
|
12
12
|
titleSource?: ConversationTitleSource | undefined;
|
|
13
13
|
returnContext?: SessionReturnContextSummary | undefined;
|
|
14
|
+
/** File format version written into the JSONL meta line. Present on files saved after schemaVersion was introduced. Missing on older files (treat as version 0). */
|
|
15
|
+
schemaVersion?: number | undefined;
|
|
14
16
|
}
|
|
15
17
|
/**
|
|
16
18
|
* Summary info for listing saved sessions.
|
|
@@ -34,6 +36,13 @@ export interface SessionInfo {
|
|
|
34
36
|
* Line 0: { type: 'meta', ...SessionMeta }
|
|
35
37
|
* Line N: { type: 'message', ...message fields }
|
|
36
38
|
*/
|
|
39
|
+
/**
|
|
40
|
+
* Current schema version written to session files.
|
|
41
|
+
* Increment when the file format changes in a backward-incompatible way.
|
|
42
|
+
* Readers accept: version undefined (legacy, treated as 0), version <= CURRENT, and
|
|
43
|
+
* version > CURRENT (future — logged as a warning, accepted with best-effort parsing).
|
|
44
|
+
*/
|
|
45
|
+
export declare const CURRENT_SESSION_SCHEMA_VERSION = 1;
|
|
37
46
|
export declare class SessionManager {
|
|
38
47
|
private sessionsDir;
|
|
39
48
|
constructor(baseDir: string, options?: {
|
|
@@ -46,8 +55,16 @@ export declare class SessionManager {
|
|
|
46
55
|
*/
|
|
47
56
|
private _cleanupOrphanTempFiles;
|
|
48
57
|
/**
|
|
49
|
-
* Atomically write content to filePath via a temp file + fsync + rename.
|
|
50
|
-
* Protects against partial writes on
|
|
58
|
+
* Atomically write content to filePath via a temp file + fsync(file) + rename + fsync(dir).
|
|
59
|
+
* Protects against partial writes and directory-entry reversion on power loss:
|
|
60
|
+
* 1. Write content to a tmp file in the same directory.
|
|
61
|
+
* 2. fsync the tmp file to flush its data to storage.
|
|
62
|
+
* 3. rename the tmp file into place (atomic on POSIX).
|
|
63
|
+
* 4. fsync the parent directory to flush the directory entry — without
|
|
64
|
+
* this step, on power loss after rename the directory entry can
|
|
65
|
+
* revert and the renamed file disappears.
|
|
66
|
+
* Mirrors the reference implementation in platform/security/user-auth.ts
|
|
67
|
+
* (atomicWriteSecretFile), which performs both fsyncs.
|
|
51
68
|
*/
|
|
52
69
|
private _atomicWrite;
|
|
53
70
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/platform/sessions/manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACxF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAIvE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IAClD,aAAa,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/platform/sessions/manager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACxF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAIvE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IAClD,aAAa,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;IACxD,oKAAoK;IACpK,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IAClD,aAAa,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;CACzD;AAED;;;;;;;GAOG;AACH;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAEhD,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE;IAM/H;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IA0B/B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,YAAY;IAoBpB;;;;OAIG;IACH,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,EAAE,WAAW,EACjB,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE;IAwC9C;;;OAGG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,EAAE,WAAW,EAAE,CAAA;KAAE;IAgE1F;;OAEG;IACH,IAAI,IAAI,WAAW,EAAE;IA+FrB;;;OAGG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI;IAiCzC;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAoB5C;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAY1B;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;QAAE,OAAO,EAAE,WAAW,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAuD9F;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CASnC"}
|
|
@@ -11,6 +11,13 @@ import { resolveScopedDirectory } from '../runtime/surface-root.js';
|
|
|
11
11
|
* Line 0: { type: 'meta', ...SessionMeta }
|
|
12
12
|
* Line N: { type: 'message', ...message fields }
|
|
13
13
|
*/
|
|
14
|
+
/**
|
|
15
|
+
* Current schema version written to session files.
|
|
16
|
+
* Increment when the file format changes in a backward-incompatible way.
|
|
17
|
+
* Readers accept: version undefined (legacy, treated as 0), version <= CURRENT, and
|
|
18
|
+
* version > CURRENT (future — logged as a warning, accepted with best-effort parsing).
|
|
19
|
+
*/
|
|
20
|
+
export const CURRENT_SESSION_SCHEMA_VERSION = 1;
|
|
14
21
|
export class SessionManager {
|
|
15
22
|
sessionsDir;
|
|
16
23
|
constructor(baseDir, options) {
|
|
@@ -51,21 +58,37 @@ export class SessionManager {
|
|
|
51
58
|
}
|
|
52
59
|
}
|
|
53
60
|
/**
|
|
54
|
-
* Atomically write content to filePath via a temp file + fsync + rename.
|
|
55
|
-
* Protects against partial writes on
|
|
61
|
+
* Atomically write content to filePath via a temp file + fsync(file) + rename + fsync(dir).
|
|
62
|
+
* Protects against partial writes and directory-entry reversion on power loss:
|
|
63
|
+
* 1. Write content to a tmp file in the same directory.
|
|
64
|
+
* 2. fsync the tmp file to flush its data to storage.
|
|
65
|
+
* 3. rename the tmp file into place (atomic on POSIX).
|
|
66
|
+
* 4. fsync the parent directory to flush the directory entry — without
|
|
67
|
+
* this step, on power loss after rename the directory entry can
|
|
68
|
+
* revert and the renamed file disappears.
|
|
69
|
+
* Mirrors the reference implementation in platform/security/user-auth.ts
|
|
70
|
+
* (atomicWriteSecretFile), which performs both fsyncs.
|
|
56
71
|
*/
|
|
57
72
|
_atomicWrite(filePath, content) {
|
|
58
73
|
const tmpPath = join(this.sessionsDir, `.tmp-${process.pid}-${Date.now()}`);
|
|
59
74
|
writeFileSync(tmpPath, content, 'utf-8');
|
|
60
|
-
// fsync to flush
|
|
61
|
-
const
|
|
75
|
+
// fsync the file to flush data buffers before rename
|
|
76
|
+
const fileFd = openSync(tmpPath, 'r+');
|
|
62
77
|
try {
|
|
63
|
-
fsyncSync(
|
|
78
|
+
fsyncSync(fileFd);
|
|
64
79
|
}
|
|
65
80
|
finally {
|
|
66
|
-
closeSync(
|
|
81
|
+
closeSync(fileFd);
|
|
67
82
|
}
|
|
68
83
|
renameSync(tmpPath, filePath);
|
|
84
|
+
// fsync the directory to flush the directory entry (makes rename durable)
|
|
85
|
+
const dirFd = openSync(this.sessionsDir, 'r');
|
|
86
|
+
try {
|
|
87
|
+
fsyncSync(dirFd);
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
closeSync(dirFd);
|
|
91
|
+
}
|
|
69
92
|
}
|
|
70
93
|
/**
|
|
71
94
|
* Save conversation messages to a JSONL session file.
|
|
@@ -82,6 +105,7 @@ export class SessionManager {
|
|
|
82
105
|
// First line: meta record
|
|
83
106
|
const metaRecord = {
|
|
84
107
|
type: 'meta',
|
|
108
|
+
schemaVersion: CURRENT_SESSION_SCHEMA_VERSION,
|
|
85
109
|
timestamp: meta.timestamp,
|
|
86
110
|
title: meta.title,
|
|
87
111
|
model: meta.model,
|
|
@@ -135,6 +159,14 @@ export class SessionManager {
|
|
|
135
159
|
continue;
|
|
136
160
|
}
|
|
137
161
|
if (record.type === 'meta') {
|
|
162
|
+
const fileVersion = typeof record.schemaVersion === 'number' ? record.schemaVersion : 0;
|
|
163
|
+
if (fileVersion > CURRENT_SESSION_SCHEMA_VERSION) {
|
|
164
|
+
logger.warn('SessionManager: session file has a newer schemaVersion — loading with best-effort parsing', {
|
|
165
|
+
name,
|
|
166
|
+
fileVersion,
|
|
167
|
+
currentVersion: CURRENT_SESSION_SCHEMA_VERSION,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
138
170
|
meta = {
|
|
139
171
|
title: String(record.title ?? ''),
|
|
140
172
|
model: String(record.model ?? ''),
|
|
@@ -144,6 +176,7 @@ export class SessionManager {
|
|
|
144
176
|
returnContext: (record.returnContext && typeof record.returnContext === 'object')
|
|
145
177
|
? record.returnContext
|
|
146
178
|
: undefined,
|
|
179
|
+
schemaVersion: fileVersion,
|
|
147
180
|
};
|
|
148
181
|
}
|
|
149
182
|
else if (record.type === 'message') {
|
|
@@ -196,6 +229,7 @@ export class SessionManager {
|
|
|
196
229
|
try {
|
|
197
230
|
const first = JSON.parse(lines[0]);
|
|
198
231
|
if (first.type === 'meta') {
|
|
232
|
+
const fileVersion = typeof first.schemaVersion === 'number' ? first.schemaVersion : 0;
|
|
199
233
|
meta = {
|
|
200
234
|
title: String(first.title ?? ''),
|
|
201
235
|
model: String(first.model ?? ''),
|
|
@@ -205,6 +239,7 @@ export class SessionManager {
|
|
|
205
239
|
returnContext: (first.returnContext && typeof first.returnContext === 'object')
|
|
206
240
|
? first.returnContext
|
|
207
241
|
: undefined,
|
|
242
|
+
schemaVersion: fileVersion,
|
|
208
243
|
};
|
|
209
244
|
}
|
|
210
245
|
}
|
|
@@ -273,6 +308,7 @@ export class SessionManager {
|
|
|
273
308
|
const record = JSON.parse(firstLine);
|
|
274
309
|
if (record.type !== 'meta')
|
|
275
310
|
return null;
|
|
311
|
+
const fileVersion = typeof record.schemaVersion === 'number' ? record.schemaVersion : 0;
|
|
276
312
|
return {
|
|
277
313
|
title: String(record.title ?? ''),
|
|
278
314
|
model: String(record.model ?? ''),
|
|
@@ -282,6 +318,7 @@ export class SessionManager {
|
|
|
282
318
|
returnContext: (record.returnContext && typeof record.returnContext === 'object')
|
|
283
319
|
? record.returnContext
|
|
284
320
|
: undefined,
|
|
321
|
+
schemaVersion: fileVersion,
|
|
285
322
|
};
|
|
286
323
|
}
|
|
287
324
|
catch (err) {
|
|
@@ -19,7 +19,7 @@ export declare class MemoryRegistry {
|
|
|
19
19
|
rebuildVectorsAsync(): Promise<MemoryVectorStats>;
|
|
20
20
|
vectorStats(): MemoryVectorStats;
|
|
21
21
|
doctor(): Promise<MemoryDoctorReport>;
|
|
22
|
-
reviewQueue(limit?: number): MemoryRecord[];
|
|
22
|
+
reviewQueue(limit?: number, scope?: MemoryScope): MemoryRecord[];
|
|
23
23
|
exportBundle(filter?: MemorySearchFilter): MemoryBundle;
|
|
24
24
|
importBundle(bundle: MemoryBundle): Promise<MemoryImportResult>;
|
|
25
25
|
get(id: string): MemoryRecord | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-registry.d.ts","sourceRoot":"","sources":["../../../src/platform/state/memory-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACnN,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,SAAS,CAAyB;gBAE9B,KAAK,EAAE,WAAW;IAI9B,QAAQ,IAAI,WAAW;IAIvB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAOrC,OAAO,CAAC,MAAM;IAIR,GAAG,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAMxD,MAAM,CAAC,MAAM,GAAE,kBAAuB,GAAG,YAAY,EAAE;IAIvD,cAAc,CAAC,MAAM,GAAE,kBAAuB,GAAG,0BAA0B,EAAE;IAI7E,cAAc,IAAI,iBAAiB;IAI7B,mBAAmB,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAIvD,WAAW,IAAI,iBAAiB;IAI1B,MAAM,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAI3C,WAAW,CAAC,KAAK,SAAK,GAAG,YAAY,EAAE;
|
|
1
|
+
{"version":3,"file":"memory-registry.d.ts","sourceRoot":"","sources":["../../../src/platform/state/memory-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACnN,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,SAAS,CAAyB;gBAE9B,KAAK,EAAE,WAAW;IAI9B,QAAQ,IAAI,WAAW;IAIvB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAOrC,OAAO,CAAC,MAAM;IAIR,GAAG,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAMxD,MAAM,CAAC,MAAM,GAAE,kBAAuB,GAAG,YAAY,EAAE;IAIvD,cAAc,CAAC,MAAM,GAAE,kBAAuB,GAAG,0BAA0B,EAAE;IAI7E,cAAc,IAAI,iBAAiB;IAI7B,mBAAmB,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAIvD,WAAW,IAAI,iBAAiB;IAI1B,MAAM,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAI3C,WAAW,CAAC,KAAK,SAAK,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,YAAY,EAAE;IAI5D,YAAY,CAAC,MAAM,GAAE,kBAAuB,GAAG,YAAY;IAIrD,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAMrE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAI9B,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAMtF,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,EAAE;IAIlC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,KAAK,CAAC,EAAE,WAAW,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,YAAY,GAAG,IAAI;IAM3H,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,YAAY,GAAG,IAAI;IAMjE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAM3B,MAAM,IAAI,YAAY,EAAE;CAGzB"}
|
|
@@ -44,8 +44,8 @@ export class MemoryRegistry {
|
|
|
44
44
|
async doctor() {
|
|
45
45
|
return this.store.doctor();
|
|
46
46
|
}
|
|
47
|
-
reviewQueue(limit = 10) {
|
|
48
|
-
return this.store.reviewQueue(limit);
|
|
47
|
+
reviewQueue(limit = 10, scope) {
|
|
48
|
+
return this.store.reviewQueue(limit, scope);
|
|
49
49
|
}
|
|
50
50
|
exportBundle(filter = {}) {
|
|
51
51
|
return this.store.exportBundle(filter);
|
|
@@ -148,7 +148,7 @@ export declare class MemoryStore {
|
|
|
148
148
|
/** Search records with an optional filter. */
|
|
149
149
|
search(filter?: MemorySearchFilter): MemoryRecord[];
|
|
150
150
|
searchSemantic(filter?: MemorySearchFilter): MemorySemanticSearchResult[];
|
|
151
|
-
reviewQueue(limit?: number): MemoryRecord[];
|
|
151
|
+
reviewQueue(limit?: number, scope?: MemoryScope): MemoryRecord[];
|
|
152
152
|
exportBundle(filter?: MemorySearchFilter): MemoryBundle;
|
|
153
153
|
importBundle(bundle: MemoryBundle): Promise<MemoryImportResult>;
|
|
154
154
|
/** Create a directed link between two records. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../../src/platform/state/memory-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAEL,KAAK,iBAAiB,EAEvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAEL,+BAA+B,EAC/B,KAAK,2BAA2B,EACjC,MAAM,wBAAwB,CAAC;AAkBhC,MAAM,MAAM,WAAW,GACnB,UAAU,GACV,YAAY,GACZ,UAAU,GACV,SAAS,GACT,MAAM,GACN,MAAM,GACN,SAAS,GACT,cAAc,GACd,WAAW,CAAC;AAEhB,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAEzD,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,cAAc,CAAC;AAEhF,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,kBAAkB,CAAC;IACzB,4FAA4F;IAC5F,GAAG,EAAE,MAAM,CAAC;IACZ,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,+DAA+D;IAC/D,KAAK,EAAE,WAAW,CAAC;IACnB,sEAAsE;IACtE,GAAG,EAAE,WAAW,CAAC;IACjB,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,oCAAoC;IACpC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,mDAAmD;IACnD,UAAU,EAAE,cAAc,EAAE,CAAC;IAC7B,oCAAoC;IACpC,WAAW,EAAE,iBAAiB,CAAC;IAC/B,0FAA0F;IAC1F,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,sCAAsC;IACtC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,GAAG,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC/B,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,8DAA8D;IAC9D,WAAW,CAAC,EAAE,iBAAiB,GAAG,iBAAiB,EAAE,GAAG,SAAS,CAAC;IAClE,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,sEAAsE;IACtE,eAAe,CAAC,EAAE,kBAAkB,EAAE,GAAG,SAAS,CAAC;IACnD,mDAAmD;IACnD,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,GAAG,EAAE,WAAW,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,SAAS,CAAC;IAC1C,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;QACtC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAClC,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,IAAI,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,WAAW,GAAG,KAAK,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,EAAE,+BAA+B,CAAC;IACnD,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,2BAA2B,CAAC;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAItD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,yBAAyB,CAA2C;IAC5E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAkC;gBAExD,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,kBAAkB;IAY7D,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAS3B,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,2DAA2D;IACrD,GAAG,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC;IAmDxD,sCAAsC;IACtC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI;IAapC,8CAA8C;IAC9C,MAAM,CAAC,MAAM,GAAE,kBAAuB,GAAG,YAAY,EAAE;IAkFvD,cAAc,CAAC,MAAM,GAAE,kBAAuB,GAAG,0BAA0B,EAAE;IA8C7E,WAAW,CAAC,KAAK,SAAK,GAAG,YAAY,EAAE;
|
|
1
|
+
{"version":3,"file":"memory-store.d.ts","sourceRoot":"","sources":["../../../src/platform/state/memory-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -207,8 +207,8 @@ export class MemoryStore {
|
|
|
207
207
|
.sort((a, b) => b.score - a.score || a.distance - b.distance || b.record.updatedAt - a.record.updatedAt)
|
|
208
208
|
.slice(0, requestedLimit);
|
|
209
209
|
}
|
|
210
|
-
reviewQueue(limit = 10) {
|
|
211
|
-
const records = this.search({ limit: Math.max(limit * 4, 25) });
|
|
210
|
+
reviewQueue(limit = 10, scope) {
|
|
211
|
+
const records = this.search({ limit: Math.max(limit * 4, 25), ...(scope ? { scope } : {}) });
|
|
212
212
|
const candidates = records.filter((record) => isReviewCandidate(record));
|
|
213
213
|
return candidates
|
|
214
214
|
.sort((a, b) => reviewQueueScore(b) - reviewQueueScore(a) || b.updatedAt - a.updatedAt || b.createdAt - a.createdAt)
|
package/dist/platform/version.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
let version = '0.
|
|
3
|
+
let version = '0.34.0';
|
|
4
4
|
try {
|
|
5
5
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', '..', 'package.json'), 'utf-8'));
|
|
6
6
|
version = pkg.version ?? version;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "TypeScript SDK for building GoodVibes operator, peer, web, mobile, and daemon-connected apps with typed contracts, auth, realtime events, and transport layers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"goodvibes",
|
|
@@ -453,14 +453,14 @@
|
|
|
453
453
|
"sideEffects": false,
|
|
454
454
|
"type": "module",
|
|
455
455
|
"dependencies": {
|
|
456
|
-
"@pellux/goodvibes-contracts": "0.
|
|
457
|
-
"@pellux/goodvibes-daemon-sdk": "0.
|
|
458
|
-
"@pellux/goodvibes-errors": "0.
|
|
459
|
-
"@pellux/goodvibes-operator-sdk": "0.
|
|
460
|
-
"@pellux/goodvibes-peer-sdk": "0.
|
|
461
|
-
"@pellux/goodvibes-transport-core": "0.
|
|
462
|
-
"@pellux/goodvibes-transport-http": "0.
|
|
463
|
-
"@pellux/goodvibes-transport-realtime": "0.
|
|
456
|
+
"@pellux/goodvibes-contracts": "0.34.0",
|
|
457
|
+
"@pellux/goodvibes-daemon-sdk": "0.34.0",
|
|
458
|
+
"@pellux/goodvibes-errors": "0.34.0",
|
|
459
|
+
"@pellux/goodvibes-operator-sdk": "0.34.0",
|
|
460
|
+
"@pellux/goodvibes-peer-sdk": "0.34.0",
|
|
461
|
+
"@pellux/goodvibes-transport-core": "0.34.0",
|
|
462
|
+
"@pellux/goodvibes-transport-http": "0.34.0",
|
|
463
|
+
"@pellux/goodvibes-transport-realtime": "0.34.0"
|
|
464
464
|
},
|
|
465
465
|
"optionalDependencies": {
|
|
466
466
|
"@agentclientprotocol/sdk": "^0.21.0",
|