chainlesschain 0.81.0 → 0.143.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.
Files changed (209) hide show
  1. package/bin/chainlesschain.js +0 -0
  2. package/package.json +1 -1
  3. package/src/commands/a2a.js +62 -0
  4. package/src/commands/activitypub.js +61 -0
  5. package/src/commands/agent-network.js +254 -1
  6. package/src/commands/agent.js +117 -0
  7. package/src/commands/audit.js +302 -0
  8. package/src/commands/automation.js +271 -1
  9. package/src/commands/bi.js +61 -0
  10. package/src/commands/bm25.js +78 -0
  11. package/src/commands/browse.js +64 -0
  12. package/src/commands/ccron.js +78 -0
  13. package/src/commands/codegen.js +224 -0
  14. package/src/commands/collab.js +341 -0
  15. package/src/commands/compliance.js +1075 -0
  16. package/src/commands/compt.js +78 -0
  17. package/src/commands/consol.js +231 -0
  18. package/src/commands/cowork.js +263 -0
  19. package/src/commands/crosschain.js +62 -0
  20. package/src/commands/dao.js +62 -0
  21. package/src/commands/dbevo.js +284 -0
  22. package/src/commands/dev.js +252 -0
  23. package/src/commands/did.js +358 -0
  24. package/src/commands/dlp.js +61 -0
  25. package/src/commands/economy.js +56 -0
  26. package/src/commands/encrypt.js +341 -0
  27. package/src/commands/evolution.js +56 -0
  28. package/src/commands/evomap.js +61 -0
  29. package/src/commands/export.js +256 -1
  30. package/src/commands/fflag.js +178 -0
  31. package/src/commands/fusion.js +258 -0
  32. package/src/commands/git.js +45 -0
  33. package/src/commands/governance.js +325 -0
  34. package/src/commands/hardening.js +411 -0
  35. package/src/commands/hmemory.js +56 -0
  36. package/src/commands/hook.js +148 -0
  37. package/src/commands/import.js +252 -0
  38. package/src/commands/incentive.js +322 -0
  39. package/src/commands/inference.js +42 -0
  40. package/src/commands/infra.js +244 -0
  41. package/src/commands/instinct.js +260 -0
  42. package/src/commands/ipfs.js +318 -0
  43. package/src/commands/itbudget.js +45 -0
  44. package/src/commands/kg.js +387 -0
  45. package/src/commands/llm.js +263 -0
  46. package/src/commands/lowcode.js +44 -0
  47. package/src/commands/matrix.js +62 -0
  48. package/src/commands/mcp.js +221 -0
  49. package/src/commands/mcpscaf.js +41 -0
  50. package/src/commands/meminj.js +41 -0
  51. package/src/commands/memory.js +248 -0
  52. package/src/commands/multimodal.js +296 -0
  53. package/src/commands/nlprog.js +356 -0
  54. package/src/commands/nostr.js +62 -0
  55. package/src/commands/note.js +244 -0
  56. package/src/commands/ops.js +354 -0
  57. package/src/commands/orchestrate.js +166 -0
  58. package/src/commands/orchgov.js +45 -0
  59. package/src/commands/org.js +277 -0
  60. package/src/commands/p2p.js +390 -0
  61. package/src/commands/pdfp.js +78 -0
  62. package/src/commands/perception.js +290 -0
  63. package/src/commands/perf.js +39 -0
  64. package/src/commands/perm.js +45 -0
  65. package/src/commands/permmem.js +251 -0
  66. package/src/commands/pipeline.js +57 -1
  67. package/src/commands/planmode.js +45 -0
  68. package/src/commands/plugin-ecosystem.js +273 -0
  69. package/src/commands/pqc.js +393 -0
  70. package/src/commands/promcomp.js +82 -0
  71. package/src/commands/quantization.js +351 -0
  72. package/src/commands/rcache.js +271 -0
  73. package/src/commands/recommend.js +382 -0
  74. package/src/commands/runtime.js +307 -0
  75. package/src/commands/scim.js +262 -0
  76. package/src/commands/seshhook.js +41 -0
  77. package/src/commands/seshsearch.js +41 -0
  78. package/src/commands/seshtail.js +41 -0
  79. package/src/commands/seshu.js +41 -0
  80. package/src/commands/session.js +258 -0
  81. package/src/commands/sganal.js +78 -0
  82. package/src/commands/siem.js +40 -0
  83. package/src/commands/skill.js +267 -1
  84. package/src/commands/slotfill.js +41 -0
  85. package/src/commands/social.js +290 -0
  86. package/src/commands/sso.js +186 -1
  87. package/src/commands/svccont.js +45 -0
  88. package/src/commands/sync.js +256 -0
  89. package/src/commands/tech.js +338 -0
  90. package/src/commands/tenant.js +351 -0
  91. package/src/commands/tms.js +45 -0
  92. package/src/commands/tokens.js +269 -0
  93. package/src/commands/topiccls.js +45 -0
  94. package/src/commands/trust.js +249 -0
  95. package/src/commands/uprof.js +45 -0
  96. package/src/commands/vcheck.js +78 -0
  97. package/src/commands/wallet.js +277 -0
  98. package/src/commands/webfetch.js +41 -0
  99. package/src/commands/workflow.js +171 -0
  100. package/src/commands/zkp.js +62 -0
  101. package/src/harness/prompt-compressor.js +331 -0
  102. package/src/index.js +65 -1
  103. package/src/lib/a2a-protocol.js +105 -0
  104. package/src/lib/activitypub-bridge.js +105 -0
  105. package/src/lib/agent-coordinator.js +325 -0
  106. package/src/lib/agent-economy.js +105 -0
  107. package/src/lib/agent-network.js +387 -0
  108. package/src/lib/agent-router.js +395 -0
  109. package/src/lib/aiops.js +478 -0
  110. package/src/lib/app-builder.js +105 -0
  111. package/src/lib/audit-logger.js +379 -0
  112. package/src/lib/automation-engine.js +330 -0
  113. package/src/lib/autonomous-agent.js +105 -0
  114. package/src/lib/autonomous-developer.js +350 -0
  115. package/src/lib/bi-engine.js +105 -0
  116. package/src/lib/bm25-search.js +81 -0
  117. package/src/lib/browser-automation.js +105 -0
  118. package/src/lib/code-agent.js +323 -0
  119. package/src/lib/collaboration-governance.js +364 -0
  120. package/src/lib/community-governance.js +436 -0
  121. package/src/lib/compliance-framework-reporter.js +105 -0
  122. package/src/lib/compliance-manager.js +434 -0
  123. package/src/lib/compression-telemetry.js +81 -0
  124. package/src/lib/content-recommendation.js +469 -0
  125. package/src/lib/content-recommender.js +105 -0
  126. package/src/lib/cowork-cron.js +81 -0
  127. package/src/lib/cowork-task-runner.js +105 -0
  128. package/src/lib/cross-chain.js +105 -0
  129. package/src/lib/crypto-manager.js +350 -0
  130. package/src/lib/dao-governance.js +105 -0
  131. package/src/lib/dbevo.js +338 -0
  132. package/src/lib/decentral-infra.js +340 -0
  133. package/src/lib/did-manager.js +367 -0
  134. package/src/lib/dlp-engine.js +105 -0
  135. package/src/lib/evolution-system.js +105 -0
  136. package/src/lib/evomap-manager.js +105 -0
  137. package/src/lib/execution-backend.js +105 -0
  138. package/src/lib/feature-flags.js +85 -0
  139. package/src/lib/git-integration.js +105 -0
  140. package/src/lib/hardening-manager.js +348 -0
  141. package/src/lib/hierarchical-memory.js +105 -0
  142. package/src/lib/hook-manager.js +380 -0
  143. package/src/lib/inference-network.js +105 -0
  144. package/src/lib/instinct-manager.js +332 -0
  145. package/src/lib/ipfs-storage.js +334 -0
  146. package/src/lib/iteration-budget.js +105 -0
  147. package/src/lib/knowledge-exporter.js +381 -0
  148. package/src/lib/knowledge-graph.js +432 -0
  149. package/src/lib/knowledge-importer.js +379 -0
  150. package/src/lib/llm-providers.js +391 -0
  151. package/src/lib/matrix-bridge.js +105 -0
  152. package/src/lib/mcp-registry.js +333 -0
  153. package/src/lib/mcp-scaffold.js +81 -0
  154. package/src/lib/memory-injection.js +81 -0
  155. package/src/lib/memory-manager.js +330 -0
  156. package/src/lib/multimodal.js +346 -0
  157. package/src/lib/nl-programming.js +343 -0
  158. package/src/lib/nostr-bridge.js +105 -0
  159. package/src/lib/note-versioning.js +327 -0
  160. package/src/lib/orchestrator.js +105 -0
  161. package/src/lib/org-manager.js +323 -0
  162. package/src/lib/p2p-manager.js +387 -0
  163. package/src/lib/pdf-parser.js +81 -0
  164. package/src/lib/perception.js +346 -0
  165. package/src/lib/perf-tuning.js +109 -1
  166. package/src/lib/permanent-memory.js +320 -0
  167. package/src/lib/permission-engine.js +81 -0
  168. package/src/lib/pipeline-orchestrator.js +105 -0
  169. package/src/lib/plan-mode.js +81 -0
  170. package/src/lib/plugin-ecosystem.js +377 -0
  171. package/src/lib/pqc-manager.js +368 -0
  172. package/src/lib/prompt-compressor.js +1 -10
  173. package/src/lib/protocol-fusion.js +417 -0
  174. package/src/lib/quantization.js +325 -0
  175. package/src/lib/response-cache.js +327 -0
  176. package/src/lib/scim-manager.js +329 -0
  177. package/src/lib/service-container.js +81 -0
  178. package/src/lib/session-consolidator.js +105 -0
  179. package/src/lib/session-hooks.js +81 -0
  180. package/src/lib/session-manager.js +329 -0
  181. package/src/lib/session-search.js +81 -0
  182. package/src/lib/session-tail.js +81 -0
  183. package/src/lib/session-usage.js +83 -0
  184. package/src/lib/siem-exporter.js +105 -0
  185. package/src/lib/skill-loader.js +377 -0
  186. package/src/lib/slot-filler.js +81 -0
  187. package/src/lib/social-graph-analytics.js +81 -0
  188. package/src/lib/social-graph.js +81 -0
  189. package/src/lib/social-manager.js +326 -0
  190. package/src/lib/sso-manager.js +332 -0
  191. package/src/lib/sub-agent-registry.js +110 -0
  192. package/src/lib/sync-manager.js +326 -0
  193. package/src/lib/task-model-selector.js +81 -0
  194. package/src/lib/tech-learning-engine.js +369 -0
  195. package/src/lib/tenant-saas.js +460 -0
  196. package/src/lib/threat-intel.js +335 -0
  197. package/src/lib/todo-manager.js +105 -0
  198. package/src/lib/token-incentive.js +293 -0
  199. package/src/lib/token-tracker.js +329 -0
  200. package/src/lib/topic-classifier.js +105 -0
  201. package/src/lib/trust-security.js +390 -0
  202. package/src/lib/ueba.js +389 -0
  203. package/src/lib/universal-runtime.js +325 -0
  204. package/src/lib/user-profile.js +81 -0
  205. package/src/lib/version-checker.js +81 -0
  206. package/src/lib/wallet-manager.js +326 -0
  207. package/src/lib/web-fetch.js +81 -0
  208. package/src/lib/workflow-engine.js +322 -0
  209. package/src/lib/zkp-engine.js +105 -0
@@ -188,3 +188,335 @@ export function generateInstinctPrompt(db) {
188
188
 
189
189
  return lines.join("\n");
190
190
  }
191
+
192
+ /* ═══════════════════════════════════════════════════════════════
193
+ * V2 Surface — Instinct governance layer.
194
+ * Tracks per-user instinct profile maturity + observation lifecycle
195
+ * independent of legacy SQLite instincts table.
196
+ * ═══════════════════════════════════════════════════════════════ */
197
+
198
+ export const PROFILE_MATURITY_V2 = Object.freeze({
199
+ PENDING: "pending",
200
+ ACTIVE: "active",
201
+ DORMANT: "dormant",
202
+ ARCHIVED: "archived",
203
+ });
204
+
205
+ export const OBSERVATION_LIFECYCLE_V2 = Object.freeze({
206
+ CAPTURED: "captured",
207
+ REVIEWED: "reviewed",
208
+ REINFORCED: "reinforced",
209
+ DISCARDED: "discarded",
210
+ PROMOTED: "promoted",
211
+ });
212
+
213
+ const PROFILE_TRANSITIONS_V2 = new Map([
214
+ ["pending", new Set(["active", "archived"])],
215
+ ["active", new Set(["dormant", "archived"])],
216
+ ["dormant", new Set(["active", "archived"])],
217
+ ["archived", new Set()],
218
+ ]);
219
+ const PROFILE_TERMINALS_V2 = new Set(["archived"]);
220
+
221
+ const OBS_TRANSITIONS_V2 = new Map([
222
+ ["captured", new Set(["reviewed", "discarded"])],
223
+ ["reviewed", new Set(["reinforced", "discarded", "promoted"])],
224
+ ["reinforced", new Set(["promoted", "discarded"])],
225
+ ["discarded", new Set()],
226
+ ["promoted", new Set()],
227
+ ]);
228
+ const OBS_TERMINALS_V2 = new Set(["discarded", "promoted"]);
229
+
230
+ export const INSTINCT_DEFAULT_MAX_ACTIVE_PROFILES_PER_USER = 5;
231
+ export const INSTINCT_DEFAULT_MAX_PENDING_OBS_PER_PROFILE = 100;
232
+ export const INSTINCT_DEFAULT_PROFILE_IDLE_MS = 1000 * 60 * 60 * 24 * 60; // 60 days
233
+ export const INSTINCT_DEFAULT_OBS_STUCK_MS = 1000 * 60 * 60 * 24 * 14; // 14 days
234
+
235
+ const _profilesV2 = new Map();
236
+ const _observationsV2 = new Map();
237
+ let _maxActiveProfilesPerUserV2 = INSTINCT_DEFAULT_MAX_ACTIVE_PROFILES_PER_USER;
238
+ let _maxPendingObsPerProfileV2 = INSTINCT_DEFAULT_MAX_PENDING_OBS_PER_PROFILE;
239
+ let _profileIdleMsV2 = INSTINCT_DEFAULT_PROFILE_IDLE_MS;
240
+ let _obsStuckMsV2 = INSTINCT_DEFAULT_OBS_STUCK_MS;
241
+
242
+ function _posIntInstinctV2(n, label) {
243
+ const v = Math.floor(Number(n));
244
+ if (!Number.isFinite(v) || v <= 0)
245
+ throw new Error(`${label} must be a positive integer`);
246
+ return v;
247
+ }
248
+
249
+ export function getMaxActiveProfilesPerUserV2() {
250
+ return _maxActiveProfilesPerUserV2;
251
+ }
252
+ export function setMaxActiveProfilesPerUserV2(n) {
253
+ _maxActiveProfilesPerUserV2 = _posIntInstinctV2(
254
+ n,
255
+ "maxActiveProfilesPerUser",
256
+ );
257
+ }
258
+ export function getMaxPendingObsPerProfileV2() {
259
+ return _maxPendingObsPerProfileV2;
260
+ }
261
+ export function setMaxPendingObsPerProfileV2(n) {
262
+ _maxPendingObsPerProfileV2 = _posIntInstinctV2(n, "maxPendingObsPerProfile");
263
+ }
264
+ export function getProfileIdleMsV2() {
265
+ return _profileIdleMsV2;
266
+ }
267
+ export function setProfileIdleMsV2(n) {
268
+ _profileIdleMsV2 = _posIntInstinctV2(n, "profileIdleMs");
269
+ }
270
+ export function getObsStuckMsV2() {
271
+ return _obsStuckMsV2;
272
+ }
273
+ export function setObsStuckMsV2(n) {
274
+ _obsStuckMsV2 = _posIntInstinctV2(n, "obsStuckMs");
275
+ }
276
+
277
+ export function getActiveProfileCountV2(userId) {
278
+ let n = 0;
279
+ for (const p of _profilesV2.values()) {
280
+ if (p.userId === userId && p.status === "active") n += 1;
281
+ }
282
+ return n;
283
+ }
284
+
285
+ export function getPendingObsCountV2(profileId) {
286
+ let n = 0;
287
+ for (const o of _observationsV2.values()) {
288
+ if (
289
+ o.profileId === profileId &&
290
+ (o.status === "captured" || o.status === "reviewed")
291
+ )
292
+ n += 1;
293
+ }
294
+ return n;
295
+ }
296
+
297
+ function _copyProfileV2(p) {
298
+ return { ...p, metadata: { ...p.metadata } };
299
+ }
300
+ function _copyObsV2(o) {
301
+ return { ...o, metadata: { ...o.metadata } };
302
+ }
303
+
304
+ export function registerProfileV2(
305
+ id,
306
+ { userId, category, metadata = {}, now = Date.now() } = {},
307
+ ) {
308
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
309
+ if (!userId || typeof userId !== "string")
310
+ throw new Error("userId must be a string");
311
+ if (!category || typeof category !== "string")
312
+ throw new Error("category must be a string");
313
+ if (_profilesV2.has(id)) throw new Error(`profile ${id} already exists`);
314
+ const p = {
315
+ id,
316
+ userId,
317
+ category,
318
+ status: "pending",
319
+ createdAt: now,
320
+ lastSeenAt: now,
321
+ activatedAt: null,
322
+ archivedAt: null,
323
+ metadata: { ...metadata },
324
+ };
325
+ _profilesV2.set(id, p);
326
+ return _copyProfileV2(p);
327
+ }
328
+
329
+ export function getProfileV2(id) {
330
+ const p = _profilesV2.get(id);
331
+ return p ? _copyProfileV2(p) : null;
332
+ }
333
+
334
+ export function listProfilesV2({ userId, category, status } = {}) {
335
+ const out = [];
336
+ for (const p of _profilesV2.values()) {
337
+ if (userId && p.userId !== userId) continue;
338
+ if (category && p.category !== category) continue;
339
+ if (status && p.status !== status) continue;
340
+ out.push(_copyProfileV2(p));
341
+ }
342
+ return out;
343
+ }
344
+
345
+ export function setProfileStatusV2(id, next, { now = Date.now() } = {}) {
346
+ const p = _profilesV2.get(id);
347
+ if (!p) throw new Error(`profile ${id} not found`);
348
+ if (!PROFILE_TRANSITIONS_V2.has(next))
349
+ throw new Error(`unknown profile status: ${next}`);
350
+ if (PROFILE_TERMINALS_V2.has(p.status))
351
+ throw new Error(`profile ${id} is in terminal state ${p.status}`);
352
+ const allowed = PROFILE_TRANSITIONS_V2.get(p.status);
353
+ if (!allowed.has(next))
354
+ throw new Error(`cannot transition profile from ${p.status} to ${next}`);
355
+ if (next === "active") {
356
+ if (p.status === "pending") {
357
+ const count = getActiveProfileCountV2(p.userId);
358
+ if (count >= _maxActiveProfilesPerUserV2)
359
+ throw new Error(
360
+ `user ${p.userId} already at active-profile cap (${_maxActiveProfilesPerUserV2})`,
361
+ );
362
+ }
363
+ if (!p.activatedAt) p.activatedAt = now;
364
+ }
365
+ if (next === "archived" && !p.archivedAt) p.archivedAt = now;
366
+ p.status = next;
367
+ p.lastSeenAt = now;
368
+ return _copyProfileV2(p);
369
+ }
370
+
371
+ export function activateProfileV2(id, opts) {
372
+ return setProfileStatusV2(id, "active", opts);
373
+ }
374
+ export function dormantProfileV2(id, opts) {
375
+ return setProfileStatusV2(id, "dormant", opts);
376
+ }
377
+ export function archiveProfileV2(id, opts) {
378
+ return setProfileStatusV2(id, "archived", opts);
379
+ }
380
+
381
+ export function touchProfileV2(id, { now = Date.now() } = {}) {
382
+ const p = _profilesV2.get(id);
383
+ if (!p) throw new Error(`profile ${id} not found`);
384
+ p.lastSeenAt = now;
385
+ return _copyProfileV2(p);
386
+ }
387
+
388
+ export function createObservationV2(
389
+ id,
390
+ { profileId, signal, metadata = {}, now = Date.now() } = {},
391
+ ) {
392
+ if (!id || typeof id !== "string") throw new Error("id must be a string");
393
+ if (!profileId || typeof profileId !== "string")
394
+ throw new Error("profileId must be a string");
395
+ if (!signal || typeof signal !== "string")
396
+ throw new Error("signal must be a string");
397
+ if (_observationsV2.has(id))
398
+ throw new Error(`observation ${id} already exists`);
399
+ const count = getPendingObsCountV2(profileId);
400
+ if (count >= _maxPendingObsPerProfileV2)
401
+ throw new Error(
402
+ `profile ${profileId} already at pending-obs cap (${_maxPendingObsPerProfileV2})`,
403
+ );
404
+ const o = {
405
+ id,
406
+ profileId,
407
+ signal,
408
+ status: "captured",
409
+ createdAt: now,
410
+ lastSeenAt: now,
411
+ reviewedAt: null,
412
+ settledAt: null,
413
+ metadata: { ...metadata },
414
+ };
415
+ _observationsV2.set(id, o);
416
+ return _copyObsV2(o);
417
+ }
418
+
419
+ export function getObservationV2(id) {
420
+ const o = _observationsV2.get(id);
421
+ return o ? _copyObsV2(o) : null;
422
+ }
423
+
424
+ export function listObservationsV2({ profileId, status } = {}) {
425
+ const out = [];
426
+ for (const o of _observationsV2.values()) {
427
+ if (profileId && o.profileId !== profileId) continue;
428
+ if (status && o.status !== status) continue;
429
+ out.push(_copyObsV2(o));
430
+ }
431
+ return out;
432
+ }
433
+
434
+ export function setObservationStatusV2(id, next, { now = Date.now() } = {}) {
435
+ const o = _observationsV2.get(id);
436
+ if (!o) throw new Error(`observation ${id} not found`);
437
+ if (!OBS_TRANSITIONS_V2.has(next))
438
+ throw new Error(`unknown observation status: ${next}`);
439
+ if (OBS_TERMINALS_V2.has(o.status))
440
+ throw new Error(`observation ${id} is in terminal state ${o.status}`);
441
+ const allowed = OBS_TRANSITIONS_V2.get(o.status);
442
+ if (!allowed.has(next))
443
+ throw new Error(
444
+ `cannot transition observation from ${o.status} to ${next}`,
445
+ );
446
+ if (next === "reviewed" && !o.reviewedAt) o.reviewedAt = now;
447
+ if (OBS_TERMINALS_V2.has(next) && !o.settledAt) o.settledAt = now;
448
+ o.status = next;
449
+ o.lastSeenAt = now;
450
+ return _copyObsV2(o);
451
+ }
452
+
453
+ export function reviewObservationV2(id, opts) {
454
+ return setObservationStatusV2(id, "reviewed", opts);
455
+ }
456
+ export function reinforceObservationV2(id, opts) {
457
+ return setObservationStatusV2(id, "reinforced", opts);
458
+ }
459
+ export function promoteObservationV2(id, opts) {
460
+ return setObservationStatusV2(id, "promoted", opts);
461
+ }
462
+ export function discardObservationV2(id, opts) {
463
+ return setObservationStatusV2(id, "discarded", opts);
464
+ }
465
+
466
+ export function autoDormantIdleProfilesV2({ now = Date.now() } = {}) {
467
+ const flipped = [];
468
+ for (const p of _profilesV2.values()) {
469
+ if (p.status !== "active") continue;
470
+ if (now - p.lastSeenAt > _profileIdleMsV2) {
471
+ p.status = "dormant";
472
+ p.lastSeenAt = now;
473
+ flipped.push(_copyProfileV2(p));
474
+ }
475
+ }
476
+ return flipped;
477
+ }
478
+
479
+ export function autoDiscardStaleObservationsV2({ now = Date.now() } = {}) {
480
+ const flipped = [];
481
+ for (const o of _observationsV2.values()) {
482
+ if (o.status !== "captured" && o.status !== "reviewed") continue;
483
+ if (now - o.lastSeenAt > _obsStuckMsV2) {
484
+ o.status = "discarded";
485
+ o.lastSeenAt = now;
486
+ if (!o.settledAt) o.settledAt = now;
487
+ flipped.push(_copyObsV2(o));
488
+ }
489
+ }
490
+ return flipped;
491
+ }
492
+
493
+ export function getInstinctManagerStatsV2() {
494
+ const profilesByStatus = {};
495
+ for (const v of Object.values(PROFILE_MATURITY_V2)) profilesByStatus[v] = 0;
496
+ for (const p of _profilesV2.values()) profilesByStatus[p.status] += 1;
497
+
498
+ const observationsByStatus = {};
499
+ for (const v of Object.values(OBSERVATION_LIFECYCLE_V2))
500
+ observationsByStatus[v] = 0;
501
+ for (const o of _observationsV2.values()) observationsByStatus[o.status] += 1;
502
+
503
+ return {
504
+ totalProfilesV2: _profilesV2.size,
505
+ totalObservationsV2: _observationsV2.size,
506
+ maxActiveProfilesPerUser: _maxActiveProfilesPerUserV2,
507
+ maxPendingObsPerProfile: _maxPendingObsPerProfileV2,
508
+ profileIdleMs: _profileIdleMsV2,
509
+ obsStuckMs: _obsStuckMsV2,
510
+ profilesByStatus,
511
+ observationsByStatus,
512
+ };
513
+ }
514
+
515
+ export function _resetStateInstinctManagerV2() {
516
+ _profilesV2.clear();
517
+ _observationsV2.clear();
518
+ _maxActiveProfilesPerUserV2 = INSTINCT_DEFAULT_MAX_ACTIVE_PROFILES_PER_USER;
519
+ _maxPendingObsPerProfileV2 = INSTINCT_DEFAULT_MAX_PENDING_OBS_PER_PROFILE;
520
+ _profileIdleMsV2 = INSTINCT_DEFAULT_PROFILE_IDLE_MS;
521
+ _obsStuckMsV2 = INSTINCT_DEFAULT_OBS_STUCK_MS;
522
+ }
@@ -573,3 +573,337 @@ export function _resetState() {
573
573
  };
574
574
  _quotaBytes = DEFAULT_QUOTA_BYTES;
575
575
  }
576
+
577
+ /* ═════════════════════════════════════════════════════════ *
578
+ * Phase 17 V2 — Gateway Maturity + Pin Lifecycle
579
+ * ═════════════════════════════════════════════════════════ */
580
+
581
+ export const GATEWAY_MATURITY_V2 = Object.freeze({
582
+ ONBOARDING: "onboarding",
583
+ ACTIVE: "active",
584
+ DEGRADED: "degraded",
585
+ OFFLINE: "offline",
586
+ RETIRED: "retired",
587
+ });
588
+
589
+ export const PIN_LIFECYCLE_V2 = Object.freeze({
590
+ PENDING: "pending",
591
+ PINNED: "pinned",
592
+ UNPINNED: "unpinned",
593
+ FAILED: "failed",
594
+ });
595
+
596
+ const GATEWAY_TRANSITIONS_V2 = new Map([
597
+ ["onboarding", new Set(["active", "retired"])],
598
+ ["active", new Set(["degraded", "offline", "retired"])],
599
+ ["degraded", new Set(["active", "offline", "retired"])],
600
+ ["offline", new Set(["active", "retired"])],
601
+ ]);
602
+ const GATEWAY_TERMINALS_V2 = new Set(["retired"]);
603
+
604
+ const PIN_TRANSITIONS_V2 = new Map([
605
+ ["pending", new Set(["pinned", "failed", "unpinned"])],
606
+ ["pinned", new Set(["unpinned"])],
607
+ ["failed", new Set(["pending", "unpinned"])],
608
+ ]);
609
+ const PIN_TERMINALS_V2 = new Set(["unpinned"]);
610
+
611
+ export const IPFS_DEFAULT_MAX_ACTIVE_GATEWAYS_PER_OPERATOR = 20;
612
+ export const IPFS_DEFAULT_MAX_PENDING_PINS_PER_OWNER = 100;
613
+ export const IPFS_DEFAULT_GATEWAY_IDLE_MS = 60 * 86400000; // 60d
614
+ export const IPFS_DEFAULT_PIN_PENDING_MS = 24 * 3600000; // 24h
615
+
616
+ let _maxActiveGatewaysPerOperatorV2 =
617
+ IPFS_DEFAULT_MAX_ACTIVE_GATEWAYS_PER_OPERATOR;
618
+ let _maxPendingPinsPerOwnerV2 = IPFS_DEFAULT_MAX_PENDING_PINS_PER_OWNER;
619
+ let _gatewayIdleMsV2 = IPFS_DEFAULT_GATEWAY_IDLE_MS;
620
+ let _pinPendingMsV2 = IPFS_DEFAULT_PIN_PENDING_MS;
621
+
622
+ function _positiveIntV2(n, label) {
623
+ const v = Math.floor(Number(n));
624
+ if (!Number.isFinite(v) || v <= 0)
625
+ throw new Error(`${label} must be a positive integer`);
626
+ return v;
627
+ }
628
+
629
+ export function getDefaultMaxActiveGatewaysPerOperatorV2() {
630
+ return IPFS_DEFAULT_MAX_ACTIVE_GATEWAYS_PER_OPERATOR;
631
+ }
632
+ export function getMaxActiveGatewaysPerOperatorV2() {
633
+ return _maxActiveGatewaysPerOperatorV2;
634
+ }
635
+ export function setMaxActiveGatewaysPerOperatorV2(n) {
636
+ return (_maxActiveGatewaysPerOperatorV2 = _positiveIntV2(
637
+ n,
638
+ "maxActiveGatewaysPerOperator",
639
+ ));
640
+ }
641
+ export function getDefaultMaxPendingPinsPerOwnerV2() {
642
+ return IPFS_DEFAULT_MAX_PENDING_PINS_PER_OWNER;
643
+ }
644
+ export function getMaxPendingPinsPerOwnerV2() {
645
+ return _maxPendingPinsPerOwnerV2;
646
+ }
647
+ export function setMaxPendingPinsPerOwnerV2(n) {
648
+ return (_maxPendingPinsPerOwnerV2 = _positiveIntV2(
649
+ n,
650
+ "maxPendingPinsPerOwner",
651
+ ));
652
+ }
653
+ export function getDefaultGatewayIdleMsV2() {
654
+ return IPFS_DEFAULT_GATEWAY_IDLE_MS;
655
+ }
656
+ export function getGatewayIdleMsV2() {
657
+ return _gatewayIdleMsV2;
658
+ }
659
+ export function setGatewayIdleMsV2(ms) {
660
+ return (_gatewayIdleMsV2 = _positiveIntV2(ms, "gatewayIdleMs"));
661
+ }
662
+ export function getDefaultPinPendingMsV2() {
663
+ return IPFS_DEFAULT_PIN_PENDING_MS;
664
+ }
665
+ export function getPinPendingMsV2() {
666
+ return _pinPendingMsV2;
667
+ }
668
+ export function setPinPendingMsV2(ms) {
669
+ return (_pinPendingMsV2 = _positiveIntV2(ms, "pinPendingMs"));
670
+ }
671
+
672
+ const _gatewaysV2 = new Map();
673
+ const _pinsV2 = new Map();
674
+
675
+ export function registerGatewayV2(
676
+ _db,
677
+ { gatewayId, operatorId, endpoint, initialStatus, metadata } = {},
678
+ ) {
679
+ if (!gatewayId) throw new Error("gatewayId is required");
680
+ if (!operatorId) throw new Error("operatorId is required");
681
+ if (!endpoint) throw new Error("endpoint is required");
682
+ if (_gatewaysV2.has(gatewayId))
683
+ throw new Error(`Gateway ${gatewayId} already exists`);
684
+ const status = initialStatus || GATEWAY_MATURITY_V2.ONBOARDING;
685
+ if (!Object.values(GATEWAY_MATURITY_V2).includes(status))
686
+ throw new Error(`Invalid initial status: ${status}`);
687
+ if (GATEWAY_TERMINALS_V2.has(status))
688
+ throw new Error(`Cannot register in terminal status: ${status}`);
689
+ if (status === GATEWAY_MATURITY_V2.ACTIVE) {
690
+ if (getActiveGatewayCount(operatorId) >= _maxActiveGatewaysPerOperatorV2)
691
+ throw new Error(
692
+ `Operator ${operatorId} reached active-gateway cap (${_maxActiveGatewaysPerOperatorV2})`,
693
+ );
694
+ }
695
+ const now = Date.now();
696
+ const record = {
697
+ gatewayId,
698
+ operatorId,
699
+ endpoint,
700
+ status,
701
+ metadata: metadata || {},
702
+ createdAt: now,
703
+ updatedAt: now,
704
+ lastHeartbeatAt: now,
705
+ };
706
+ _gatewaysV2.set(gatewayId, record);
707
+ return { ...record, metadata: { ...record.metadata } };
708
+ }
709
+
710
+ export function getGatewayV2(gatewayId) {
711
+ const r = _gatewaysV2.get(gatewayId);
712
+ return r ? { ...r, metadata: { ...r.metadata } } : null;
713
+ }
714
+
715
+ export function setGatewayMaturityV2(_db, gatewayId, newStatus, patch = {}) {
716
+ const record = _gatewaysV2.get(gatewayId);
717
+ if (!record) throw new Error(`Unknown gateway: ${gatewayId}`);
718
+ if (!Object.values(GATEWAY_MATURITY_V2).includes(newStatus))
719
+ throw new Error(`Invalid status: ${newStatus}`);
720
+ const allowed = GATEWAY_TRANSITIONS_V2.get(record.status) || new Set();
721
+ if (!allowed.has(newStatus))
722
+ throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
723
+ if (newStatus === GATEWAY_MATURITY_V2.ACTIVE) {
724
+ if (
725
+ getActiveGatewayCount(record.operatorId) >=
726
+ _maxActiveGatewaysPerOperatorV2
727
+ )
728
+ throw new Error(
729
+ `Operator ${record.operatorId} reached active-gateway cap (${_maxActiveGatewaysPerOperatorV2})`,
730
+ );
731
+ }
732
+ record.status = newStatus;
733
+ record.updatedAt = Date.now();
734
+ if (patch.reason !== undefined) record.lastReason = patch.reason;
735
+ if (patch.metadata)
736
+ record.metadata = { ...record.metadata, ...patch.metadata };
737
+ return { ...record, metadata: { ...record.metadata } };
738
+ }
739
+
740
+ export function activateGateway(db, id, reason) {
741
+ return setGatewayMaturityV2(db, id, GATEWAY_MATURITY_V2.ACTIVE, { reason });
742
+ }
743
+ export function degradeGateway(db, id, reason) {
744
+ return setGatewayMaturityV2(db, id, GATEWAY_MATURITY_V2.DEGRADED, { reason });
745
+ }
746
+ export function offlineGateway(db, id, reason) {
747
+ return setGatewayMaturityV2(db, id, GATEWAY_MATURITY_V2.OFFLINE, { reason });
748
+ }
749
+ export function retireGateway(db, id, reason) {
750
+ return setGatewayMaturityV2(db, id, GATEWAY_MATURITY_V2.RETIRED, { reason });
751
+ }
752
+
753
+ export function touchGatewayHeartbeat(gatewayId) {
754
+ const record = _gatewaysV2.get(gatewayId);
755
+ if (!record) throw new Error(`Unknown gateway: ${gatewayId}`);
756
+ record.lastHeartbeatAt = Date.now();
757
+ record.updatedAt = record.lastHeartbeatAt;
758
+ return { ...record, metadata: { ...record.metadata } };
759
+ }
760
+
761
+ export function registerPinV2(
762
+ _db,
763
+ { pinId, ownerId, cid, initialStatus, metadata } = {},
764
+ ) {
765
+ if (!pinId) throw new Error("pinId is required");
766
+ if (!ownerId) throw new Error("ownerId is required");
767
+ if (!cid) throw new Error("cid is required");
768
+ if (_pinsV2.has(pinId)) throw new Error(`Pin ${pinId} already exists`);
769
+ const status = initialStatus || PIN_LIFECYCLE_V2.PENDING;
770
+ if (!Object.values(PIN_LIFECYCLE_V2).includes(status))
771
+ throw new Error(`Invalid initial status: ${status}`);
772
+ if (PIN_TERMINALS_V2.has(status))
773
+ throw new Error(`Cannot register in terminal status: ${status}`);
774
+ if (status === PIN_LIFECYCLE_V2.PENDING) {
775
+ if (getPendingPinCount(ownerId) >= _maxPendingPinsPerOwnerV2)
776
+ throw new Error(
777
+ `Owner ${ownerId} reached pending-pin cap (${_maxPendingPinsPerOwnerV2})`,
778
+ );
779
+ }
780
+ const now = Date.now();
781
+ const record = {
782
+ pinId,
783
+ ownerId,
784
+ cid,
785
+ status,
786
+ metadata: metadata || {},
787
+ createdAt: now,
788
+ updatedAt: now,
789
+ };
790
+ _pinsV2.set(pinId, record);
791
+ return { ...record, metadata: { ...record.metadata } };
792
+ }
793
+
794
+ export function getPinV2(pinId) {
795
+ const r = _pinsV2.get(pinId);
796
+ return r ? { ...r, metadata: { ...r.metadata } } : null;
797
+ }
798
+
799
+ export function setPinStatusV2(_db, pinId, newStatus, patch = {}) {
800
+ const record = _pinsV2.get(pinId);
801
+ if (!record) throw new Error(`Unknown pin: ${pinId}`);
802
+ if (!Object.values(PIN_LIFECYCLE_V2).includes(newStatus))
803
+ throw new Error(`Invalid status: ${newStatus}`);
804
+ const allowed = PIN_TRANSITIONS_V2.get(record.status) || new Set();
805
+ if (!allowed.has(newStatus))
806
+ throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
807
+ record.status = newStatus;
808
+ record.updatedAt = Date.now();
809
+ if (newStatus === PIN_LIFECYCLE_V2.PINNED && !record.pinnedAt)
810
+ record.pinnedAt = record.updatedAt;
811
+ if (patch.reason !== undefined) record.lastReason = patch.reason;
812
+ if (patch.metadata)
813
+ record.metadata = { ...record.metadata, ...patch.metadata };
814
+ return { ...record, metadata: { ...record.metadata } };
815
+ }
816
+
817
+ export function confirmPin(db, pinId, reason) {
818
+ return setPinStatusV2(db, pinId, PIN_LIFECYCLE_V2.PINNED, { reason });
819
+ }
820
+ export function failPin(db, pinId, reason) {
821
+ return setPinStatusV2(db, pinId, PIN_LIFECYCLE_V2.FAILED, { reason });
822
+ }
823
+ export function unpinV2(db, pinId, reason) {
824
+ return setPinStatusV2(db, pinId, PIN_LIFECYCLE_V2.UNPINNED, { reason });
825
+ }
826
+
827
+ export function getActiveGatewayCount(operatorId) {
828
+ let n = 0;
829
+ for (const r of _gatewaysV2.values()) {
830
+ if (r.status !== GATEWAY_MATURITY_V2.ACTIVE) continue;
831
+ if (operatorId && r.operatorId !== operatorId) continue;
832
+ n++;
833
+ }
834
+ return n;
835
+ }
836
+
837
+ export function getPendingPinCount(ownerId) {
838
+ let n = 0;
839
+ for (const r of _pinsV2.values()) {
840
+ if (r.status !== PIN_LIFECYCLE_V2.PENDING) continue;
841
+ if (ownerId && r.ownerId !== ownerId) continue;
842
+ n++;
843
+ }
844
+ return n;
845
+ }
846
+
847
+ export function autoOfflineStaleGateways(_db, nowMs) {
848
+ const now = nowMs ?? Date.now();
849
+ const flipped = [];
850
+ for (const r of _gatewaysV2.values()) {
851
+ if (
852
+ r.status === GATEWAY_MATURITY_V2.ACTIVE ||
853
+ r.status === GATEWAY_MATURITY_V2.DEGRADED
854
+ ) {
855
+ if (now - r.lastHeartbeatAt > _gatewayIdleMsV2) {
856
+ r.status = GATEWAY_MATURITY_V2.OFFLINE;
857
+ r.updatedAt = now;
858
+ r.lastReason = "heartbeat_timeout";
859
+ flipped.push(r.gatewayId);
860
+ }
861
+ }
862
+ }
863
+ return { flipped, count: flipped.length };
864
+ }
865
+
866
+ export function autoFailStalePendingPins(_db, nowMs) {
867
+ const now = nowMs ?? Date.now();
868
+ const flipped = [];
869
+ for (const r of _pinsV2.values()) {
870
+ if (r.status === PIN_LIFECYCLE_V2.PENDING) {
871
+ if (now - r.createdAt > _pinPendingMsV2) {
872
+ r.status = PIN_LIFECYCLE_V2.FAILED;
873
+ r.updatedAt = now;
874
+ r.lastReason = "pending_timeout";
875
+ flipped.push(r.pinId);
876
+ }
877
+ }
878
+ }
879
+ return { flipped, count: flipped.length };
880
+ }
881
+
882
+ export function getIpfsStatsV2() {
883
+ const gatewaysByStatus = {};
884
+ for (const s of Object.values(GATEWAY_MATURITY_V2)) gatewaysByStatus[s] = 0;
885
+ const pinsByStatus = {};
886
+ for (const s of Object.values(PIN_LIFECYCLE_V2)) pinsByStatus[s] = 0;
887
+ for (const r of _gatewaysV2.values()) gatewaysByStatus[r.status]++;
888
+ for (const r of _pinsV2.values()) pinsByStatus[r.status]++;
889
+ return {
890
+ totalGatewaysV2: _gatewaysV2.size,
891
+ totalPinsV2: _pinsV2.size,
892
+ maxActiveGatewaysPerOperator: _maxActiveGatewaysPerOperatorV2,
893
+ maxPendingPinsPerOwner: _maxPendingPinsPerOwnerV2,
894
+ gatewayIdleMs: _gatewayIdleMsV2,
895
+ pinPendingMs: _pinPendingMsV2,
896
+ gatewaysByStatus,
897
+ pinsByStatus,
898
+ };
899
+ }
900
+
901
+ export function _resetStateV2() {
902
+ _maxActiveGatewaysPerOperatorV2 =
903
+ IPFS_DEFAULT_MAX_ACTIVE_GATEWAYS_PER_OPERATOR;
904
+ _maxPendingPinsPerOwnerV2 = IPFS_DEFAULT_MAX_PENDING_PINS_PER_OWNER;
905
+ _gatewayIdleMsV2 = IPFS_DEFAULT_GATEWAY_IDLE_MS;
906
+ _pinPendingMsV2 = IPFS_DEFAULT_PIN_PENDING_MS;
907
+ _gatewaysV2.clear();
908
+ _pinsV2.clear();
909
+ }