@remnic/core 9.3.691 → 9.3.693

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 (113) hide show
  1. package/dist/access-boundary.d.ts +6 -5
  2. package/dist/access-boundary.js +12 -12
  3. package/dist/access-cli.js +71 -18
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +5 -4
  6. package/dist/access-http.js +16 -16
  7. package/dist/access-mcp.d.ts +7 -4
  8. package/dist/access-mcp.js +15 -15
  9. package/dist/access-operations.d.ts +12 -6
  10. package/dist/access-operations.js +16 -14
  11. package/dist/access-schema.js +3 -3
  12. package/dist/{access-service-CKnFdxH-.d.ts → access-service-DxCpgyVW.d.ts} +96 -2
  13. package/dist/access-service.d.ts +5 -4
  14. package/dist/access-service.js +11 -11
  15. package/dist/access-surface-catalog.d.ts +5 -4
  16. package/dist/access-surface-catalog.js +2 -0
  17. package/dist/access-surface-catalog.js.map +1 -1
  18. package/dist/bootstrap.d.ts +4 -3
  19. package/dist/{chunk-QNG35H27.js → chunk-4IQNAOP3.js} +5 -141
  20. package/dist/chunk-4IQNAOP3.js.map +1 -0
  21. package/dist/{chunk-VH2DHBHG.js → chunk-5HGPDRQZ.js} +2 -2
  22. package/dist/chunk-5HGPDRQZ.js.map +1 -0
  23. package/dist/chunk-6C2BMUZA.js +444 -0
  24. package/dist/chunk-6C2BMUZA.js.map +1 -0
  25. package/dist/{chunk-UUMYB3FR.js → chunk-6ZNIUGXB.js} +10 -10
  26. package/dist/{chunk-IPJD7WJH.js → chunk-E6BOD3UJ.js} +2 -2
  27. package/dist/{chunk-TJ5IIQIR.js → chunk-F7BVJ3IE.js} +40 -369
  28. package/dist/chunk-F7BVJ3IE.js.map +1 -0
  29. package/dist/{chunk-D3DNGQNQ.js → chunk-FM7KLRKN.js} +2 -2
  30. package/dist/{chunk-7MOTEVAA.js → chunk-HRUULBBV.js} +3 -1
  31. package/dist/chunk-HRUULBBV.js.map +1 -0
  32. package/dist/chunk-HXNMDPHN.js +149 -0
  33. package/dist/chunk-HXNMDPHN.js.map +1 -0
  34. package/dist/{chunk-7UVDIWLL.js → chunk-JNKH2XWQ.js} +36 -6
  35. package/dist/chunk-JNKH2XWQ.js.map +1 -0
  36. package/dist/{chunk-IPLYGWQF.js → chunk-KQAFEZQX.js} +5 -5
  37. package/dist/{chunk-OOO7ZKOD.js → chunk-KYH53EFD.js} +3 -3
  38. package/dist/{chunk-LQ6JI4VH.js → chunk-LD53WPMU.js} +4 -4
  39. package/dist/{chunk-KO6OL4I7.js → chunk-MQTPUPLP.js} +297 -17
  40. package/dist/chunk-MQTPUPLP.js.map +1 -0
  41. package/dist/{chunk-TSGREOYY.js → chunk-RHWFMBO5.js} +33 -6
  42. package/dist/chunk-RHWFMBO5.js.map +1 -0
  43. package/dist/{chunk-5CEJH5ZN.js → chunk-TAPSNIMA.js} +4 -4
  44. package/dist/{chunk-K7I24ZO2.js → chunk-THKNO6OX.js} +22 -21
  45. package/dist/{chunk-K7I24ZO2.js.map → chunk-THKNO6OX.js.map} +1 -1
  46. package/dist/{chunk-QLRYXOAD.js → chunk-UDJLF3BO.js} +2 -2
  47. package/dist/{chunk-NCRDCTEJ.js → chunk-WYB44HHV.js} +21 -7
  48. package/dist/chunk-WYB44HHV.js.map +1 -0
  49. package/dist/{chunk-WRFKZEO6.js → chunk-YQGHW5ML.js} +4 -4
  50. package/dist/{cli-CrSW_KRq.d.ts → cli-DoQsv4ut.d.ts} +2 -2
  51. package/dist/cli.d.ts +6 -5
  52. package/dist/cli.js +26 -25
  53. package/dist/contradiction/index.js +4 -4
  54. package/dist/explicit-capture.d.ts +4 -3
  55. package/dist/index.d.ts +6 -5
  56. package/dist/index.js +33 -31
  57. package/dist/index.js.map +1 -1
  58. package/dist/mcp-memory-inspector-app.d.ts +5 -4
  59. package/dist/namespaces/migrate.js +8 -8
  60. package/dist/namespaces/search.js +7 -7
  61. package/dist/operator-toolkit.js +11 -10
  62. package/dist/orchestration/maintenance.d.ts +112 -0
  63. package/dist/orchestration/maintenance.js +39 -0
  64. package/dist/orchestration/maintenance.js.map +1 -0
  65. package/dist/{orchestrator-DvswGK76.d.ts → orchestrator-CNJCYjZ1.d.ts} +9 -33
  66. package/dist/orchestrator.d.ts +2 -1
  67. package/dist/orchestrator.js +13 -11
  68. package/dist/schemas.d.ts +28 -28
  69. package/dist/search/factory.js +6 -6
  70. package/dist/search/index.js +11 -11
  71. package/dist/search/lancedb-backend.js +2 -2
  72. package/dist/search/meilisearch-backend.js +2 -2
  73. package/dist/search/orama-backend.js +2 -2
  74. package/dist/transfer/autodetect.js +1 -1
  75. package/dist/transfer/backup.js +1 -1
  76. package/dist/transfer/capsule-export.js +2 -2
  77. package/dist/transfer/types.d.ts +12 -12
  78. package/package.json +12 -2
  79. package/src/access-boundary.ts +2 -1
  80. package/src/access-cli.ts +65 -2
  81. package/src/access-http.ts +20 -0
  82. package/src/access-mcp.ts +29 -0
  83. package/src/access-operations.ts +46 -0
  84. package/src/access-service.ts +55 -0
  85. package/src/access-surface-catalog.test.ts +1 -1
  86. package/src/access-surface-catalog.ts +2 -0
  87. package/src/cli.ts +1 -0
  88. package/src/coding/coding-namespace.ts +1 -1
  89. package/src/coding/session-delta-surfaces.test.ts +383 -0
  90. package/src/coding/session-delta-surfaces.ts +325 -0
  91. package/src/coding/session-delta.test.ts +411 -0
  92. package/src/coding/session-delta.ts +442 -0
  93. package/src/orchestration/maintenance.test.ts +738 -0
  94. package/src/orchestration/maintenance.ts +557 -0
  95. package/src/orchestrator-flush.test.ts +0 -599
  96. package/src/orchestrator.ts +33 -419
  97. package/dist/chunk-7MOTEVAA.js.map +0 -1
  98. package/dist/chunk-7UVDIWLL.js.map +0 -1
  99. package/dist/chunk-KO6OL4I7.js.map +0 -1
  100. package/dist/chunk-NCRDCTEJ.js.map +0 -1
  101. package/dist/chunk-QNG35H27.js.map +0 -1
  102. package/dist/chunk-TJ5IIQIR.js.map +0 -1
  103. package/dist/chunk-TSGREOYY.js.map +0 -1
  104. package/dist/chunk-VH2DHBHG.js.map +0 -1
  105. /package/dist/{chunk-UUMYB3FR.js.map → chunk-6ZNIUGXB.js.map} +0 -0
  106. /package/dist/{chunk-IPJD7WJH.js.map → chunk-E6BOD3UJ.js.map} +0 -0
  107. /package/dist/{chunk-D3DNGQNQ.js.map → chunk-FM7KLRKN.js.map} +0 -0
  108. /package/dist/{chunk-IPLYGWQF.js.map → chunk-KQAFEZQX.js.map} +0 -0
  109. /package/dist/{chunk-OOO7ZKOD.js.map → chunk-KYH53EFD.js.map} +0 -0
  110. /package/dist/{chunk-LQ6JI4VH.js.map → chunk-LD53WPMU.js.map} +0 -0
  111. /package/dist/{chunk-5CEJH5ZN.js.map → chunk-TAPSNIMA.js.map} +0 -0
  112. /package/dist/{chunk-QLRYXOAD.js.map → chunk-UDJLF3BO.js.map} +0 -0
  113. /package/dist/{chunk-WRFKZEO6.js.map → chunk-YQGHW5ML.js.map} +0 -0
@@ -6,14 +6,8 @@ import {
6
6
  wearableSourceLabel
7
7
  } from "./chunk-5KBNNUXS.js";
8
8
  import {
9
- ensureContradictionScanCron,
10
- ensureDaySummaryCron,
11
- ensureGraphEdgeDecayCron,
12
- ensureNightlyGovernanceCron,
13
- ensurePatternReinforcementCron,
14
- ensureProceduralMiningCron,
15
- graphEdgeDecayCadenceToCronExpr
16
- } from "./chunk-666A3MOW.js";
9
+ MaintenanceScheduler
10
+ } from "./chunk-6C2BMUZA.js";
17
11
  import {
18
12
  migrateFromEngram
19
13
  } from "./chunk-7HYPN2GC.js";
@@ -188,12 +182,12 @@ import {
188
182
  import {
189
183
  formatDaySummaryMemories
190
184
  } from "./chunk-EO5QWINU.js";
191
- import {
192
- RoutingRulesStore
193
- } from "./chunk-WIWPSQYU.js";
194
185
  import {
195
186
  normalizeReplaySessionKey
196
187
  } from "./chunk-2PRQG7PV.js";
188
+ import {
189
+ RoutingRulesStore
190
+ } from "./chunk-WIWPSQYU.js";
197
191
  import {
198
192
  compareVerifiedEpisodeResults,
199
193
  searchVerifiedEpisodes
@@ -215,12 +209,13 @@ import {
215
209
  PolicyRuntimeManager
216
210
  } from "./chunk-33JBK2XP.js";
217
211
  import {
218
- NamespaceCatalog,
219
- planNamespaceMaintenance,
220
- runNamespaceMaintenanceBatchPlan,
221
212
  runNamespaceMaintenanceFanout,
222
213
  summarizeNamespaceMaintenanceHealth
223
- } from "./chunk-QNG35H27.js";
214
+ } from "./chunk-HXNMDPHN.js";
215
+ import {
216
+ NamespaceCatalog,
217
+ planNamespaceMaintenance
218
+ } from "./chunk-4IQNAOP3.js";
224
219
  import {
225
220
  NamespaceStorageRouter
226
221
  } from "./chunk-W4ELOUNX.js";
@@ -316,7 +311,7 @@ import {
316
311
  lcmReadSessionIdsForNamespaces,
317
312
  resolveCodingNamespaceOverlay,
318
313
  resolveScopeProfilePlan
319
- } from "./chunk-7MOTEVAA.js";
314
+ } from "./chunk-HRUULBBV.js";
320
315
  import {
321
316
  listTrustZoneRecords,
322
317
  searchTrustZoneRecords
@@ -333,11 +328,11 @@ import {
333
328
  } from "./chunk-6HMYUWXR.js";
334
329
  import {
335
330
  NamespaceSearchRouter
336
- } from "./chunk-IPJD7WJH.js";
331
+ } from "./chunk-E6BOD3UJ.js";
337
332
  import {
338
333
  createConversationIndexRuntime,
339
334
  createSearchBackend
340
- } from "./chunk-UUMYB3FR.js";
335
+ } from "./chunk-6ZNIUGXB.js";
341
336
  import {
342
337
  NoopSearchBackend
343
338
  } from "./chunk-CYEPCZN5.js";
@@ -442,9 +437,6 @@ import {
442
437
  isSafeRouteNamespace,
443
438
  selectRouteRule
444
439
  } from "./chunk-U3PN77QT.js";
445
- import {
446
- resolveHomeDir
447
- } from "./chunk-JUC24CTX.js";
448
440
  import {
449
441
  log
450
442
  } from "./chunk-NU3CSQ4H.js";
@@ -2393,10 +2385,6 @@ function resolvePersistedMemoryRelativePath(options) {
2393
2385
  }
2394
2386
  return path2.join(subtree, `${options.memoryId}.md`);
2395
2387
  }
2396
- function qmdMaintenanceSkipReasonForError(error) {
2397
- const message = error instanceof Error ? error.message : String(error);
2398
- return /^QMD (?:update|embed) skipped by .*min-interval gate$/.test(message) ? "throttled" : null;
2399
- }
2400
2388
  var Orchestrator = class _Orchestrator {
2401
2389
  storage;
2402
2390
  storageRouter;
@@ -2406,6 +2394,12 @@ var Orchestrator = class _Orchestrator {
2406
2394
  namespaceStorageDirHintsLoaded = false;
2407
2395
  namespaceSearchRouter;
2408
2396
  qmd;
2397
+ /**
2398
+ * Maintenance scheduler (issue #1526 PR1). Owns cron auto-registration,
2399
+ * debounced QMD index maintenance, and consolidation scheduling. Job
2400
+ * runners (consolidation/pattern-reinforcement/governance) stay here.
2401
+ */
2402
+ maintenanceScheduler;
2409
2403
  conversationQmd;
2410
2404
  conversationFaiss;
2411
2405
  conversationIndexBackend;
@@ -2514,17 +2508,9 @@ var Orchestrator = class _Orchestrator {
2514
2508
  queueProcessing = false;
2515
2509
  heartbeatObserverChains = /* @__PURE__ */ new Map();
2516
2510
  recentExtractionFingerprints = /* @__PURE__ */ new Map();
2517
- nonZeroExtractionsSinceConsolidation = 0;
2518
- lastConsolidationRunAtMs = 0;
2519
- consolidationInFlight = false;
2520
2511
  consolidationObservers = /* @__PURE__ */ new Set();
2521
- qmdMaintenanceTimer = null;
2522
2512
  wearablesServiceInstance = null;
2523
2513
  wearablesAutoSyncHandle = null;
2524
- qmdMaintenancePending = false;
2525
- qmdMaintenanceInFlight = false;
2526
- lastQmdEmbedAtMs = 0;
2527
- lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map();
2528
2514
  lastQmdReprobeAtMs = 0;
2529
2515
  tierMigrationInFlight = false;
2530
2516
  lastTierMigrationRunAtMs = 0;
@@ -2600,11 +2586,7 @@ var Orchestrator = class _Orchestrator {
2600
2586
  await this.wearablesAutoSyncHandle.stop();
2601
2587
  this.wearablesAutoSyncHandle = null;
2602
2588
  }
2603
- if (this.qmdMaintenanceTimer) {
2604
- clearTimeout(this.qmdMaintenanceTimer);
2605
- this.qmdMaintenanceTimer = null;
2606
- }
2607
- this.qmdMaintenancePending = false;
2589
+ this.maintenanceScheduler.dispose();
2608
2590
  await this.namespaceSearchRouter.dispose();
2609
2591
  await this.disposeSearchBackendIfNeeded();
2610
2592
  if (this.conversationQmd && this.conversationQmd !== this.qmd) {
@@ -2932,21 +2914,6 @@ var Orchestrator = class _Orchestrator {
2932
2914
  this.rememberNamespaceStorageDirHint(record.namespace, record.storageDir);
2933
2915
  }
2934
2916
  }
2935
- /**
2936
- * Shared namespace maintenance planner (issue #1500). This extends the
2937
- * #1499 catalog-union QMD helper into a reusable contract: configured
2938
- * namespaces are always considered, dynamic catalog namespaces are admitted
2939
- * only when their live router root still matches real memory data, and branch
2940
- * namespaces are opt-in. Recurring jobs use the per-cycle budget; startup and
2941
- * recovery discovery paths use the same safety filters without that cycle
2942
- * budget so every live namespace is ensured/synced.
2943
- */
2944
- async namespaceMaintenancePlan(jobName) {
2945
- return planNamespaceMaintenance(this.config, {
2946
- jobName,
2947
- catalog: this.namespaceCatalog
2948
- });
2949
- }
2950
2917
  async maintenanceNamespaces(jobName = "qmd", budgetMode = "unbounded") {
2951
2918
  const plan = await planNamespaceMaintenance(this.config, {
2952
2919
  jobName,
@@ -3148,6 +3115,16 @@ var Orchestrator = class _Orchestrator {
3148
3115
  }
3149
3116
  }
3150
3117
  this.qmd = createSearchBackend(config);
3118
+ this.maintenanceScheduler = new MaintenanceScheduler({
3119
+ config,
3120
+ // Live accessor: the orchestrator reassigns this.qmd to NoopSearchBackend
3121
+ // after construction when the collection is missing (initialize /
3122
+ // startupSearchSync); the scheduler must read the current backend so
3123
+ // debounced maintenance never runs against a stale/disposed one.
3124
+ getQmd: () => this.qmd,
3125
+ namespaceSearchRouter: this.namespaceSearchRouter,
3126
+ namespaceCatalog: this.namespaceCatalog
3127
+ });
3151
3128
  const conversationIndexRuntime = createConversationIndexRuntime(config, {
3152
3129
  getQmd: () => this.conversationQmd,
3153
3130
  getFaiss: () => this.conversationFaiss
@@ -3708,48 +3685,7 @@ var Orchestrator = class _Orchestrator {
3708
3685
  }
3709
3686
  }
3710
3687
  if (signal.aborted) return;
3711
- if (this.config.daySummaryEnabled) {
3712
- try {
3713
- await this.autoRegisterDaySummaryCron();
3714
- } catch (err) {
3715
- log.debug(`day-summary cron auto-register failed (non-fatal): ${err}`);
3716
- }
3717
- }
3718
- if (this.config.nightlyGovernanceCronAutoRegister) {
3719
- try {
3720
- await this.autoRegisterNightlyGovernanceCron();
3721
- } catch (err) {
3722
- log.debug(`nightly governance cron auto-register failed (non-fatal): ${err}`);
3723
- }
3724
- }
3725
- if (this.config.procedural?.proceduralMiningCronAutoRegister) {
3726
- try {
3727
- await this.autoRegisterProceduralMiningCron();
3728
- } catch (err) {
3729
- log.debug(`procedural mining cron auto-register failed (non-fatal): ${err}`);
3730
- }
3731
- }
3732
- if (this.config.contradictionScan?.enabled) {
3733
- try {
3734
- await this.autoRegisterContradictionScanCron();
3735
- } catch (err) {
3736
- log.debug(`contradiction scan cron auto-register failed (non-fatal): ${err}`);
3737
- }
3738
- }
3739
- if (this.config.patternReinforcementEnabled) {
3740
- try {
3741
- await this.autoRegisterPatternReinforcementCron();
3742
- } catch (err) {
3743
- log.debug(`pattern reinforcement cron auto-register failed (non-fatal): ${err}`);
3744
- }
3745
- }
3746
- if (this.config.graphEdgeDecayEnabled) {
3747
- try {
3748
- await this.autoRegisterGraphEdgeDecayCron();
3749
- } catch (err) {
3750
- log.debug(`graph edge decay cron auto-register failed (non-fatal): ${err}`);
3751
- }
3752
- }
3688
+ await this.maintenanceScheduler.autoRegisterCrons(signal);
3753
3689
  if (signal.aborted) return;
3754
3690
  if (this.config.lifecyclePolicyEnabled && this.config.qmdTierMigrationEnabled) {
3755
3691
  try {
@@ -3904,147 +3840,6 @@ var Orchestrator = class _Orchestrator {
3904
3840
  }
3905
3841
  return true;
3906
3842
  }
3907
- /**
3908
- * Auto-register the engram-day-summary cron job in OpenClaw.
3909
- * Reconciles model and timezone on every startup so config changes propagate.
3910
- * Fire-and-forget — never blocks init or crashes on failure.
3911
- * Issues #1474, #1475.
3912
- */
3913
- async autoRegisterDaySummaryCron() {
3914
- const home = resolveHomeDir();
3915
- const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
3916
- try {
3917
- if (!existsSync(jobsPath)) {
3918
- log.debug(
3919
- "day-summary cron: jobs.json not found, skipping auto-register"
3920
- );
3921
- return;
3922
- }
3923
- const rawSummaryModel = this.config.summaryModel;
3924
- const taskPrimary = this.config.taskModelChain?.primary;
3925
- const isGateway = this.config.modelSource === "gateway";
3926
- const model = isGateway ? rawSummaryModel || taskPrimary || void 0 : void 0;
3927
- const fallbacks = [];
3928
- if (model && taskPrimary && model === taskPrimary) {
3929
- const seen = new Set(model ? [model] : []);
3930
- const addUnique = (value) => {
3931
- if (typeof value !== "string") return;
3932
- const trimmed = value.trim();
3933
- if (trimmed.length > 0 && !seen.has(trimmed)) {
3934
- seen.add(trimmed);
3935
- fallbacks.push(trimmed);
3936
- }
3937
- };
3938
- for (const fb of this.config.taskModelChain?.fallbacks ?? []) addUnique(fb);
3939
- const gwDefaults = this.config.gatewayConfig?.agents?.defaults?.model;
3940
- addUnique(gwDefaults?.primary);
3941
- if (Array.isArray(gwDefaults?.fallbacks)) {
3942
- for (const fb of gwDefaults.fallbacks) addUnique(fb);
3943
- }
3944
- }
3945
- const timezone = this.config.daySummaryTimezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
3946
- const result = await ensureDaySummaryCron(jobsPath, {
3947
- timezone,
3948
- ...model ? { model } : {},
3949
- ...fallbacks.length > 0 ? { fallbacks } : {}
3950
- });
3951
- if (result.created) {
3952
- log.info(
3953
- `day-summary cron auto-registered (${result.jobId}, 23:47 ${timezone}${model ? `, model: ${model}` : ""})`
3954
- );
3955
- } else if (result.updated) {
3956
- log.info(
3957
- `day-summary cron reconciled (${result.jobId}, timezone: ${timezone}${model ? `, model: ${model}` : ""})`
3958
- );
3959
- } else {
3960
- log.debug("day-summary cron already up to date");
3961
- }
3962
- } catch (err) {
3963
- log.debug(`day-summary cron auto-register error: ${err}`);
3964
- }
3965
- }
3966
- async autoRegisterNightlyGovernanceCron() {
3967
- const home = resolveHomeDir();
3968
- const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
3969
- try {
3970
- if (!existsSync(jobsPath)) {
3971
- log.debug("nightly governance cron: jobs.json not found, skipping auto-register");
3972
- return;
3973
- }
3974
- const created = await ensureNightlyGovernanceCron(jobsPath, {
3975
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
3976
- });
3977
- if (created.created) {
3978
- log.info(
3979
- `nightly governance cron auto-registered (${created.jobId}, 02:23 ${Intl.DateTimeFormat().resolvedOptions().timeZone})`
3980
- );
3981
- } else {
3982
- log.debug("nightly governance cron already exists, skipping auto-register");
3983
- }
3984
- } catch (err) {
3985
- log.debug(`nightly governance cron auto-register error: ${err}`);
3986
- }
3987
- }
3988
- async autoRegisterProceduralMiningCron() {
3989
- const home = resolveHomeDir();
3990
- const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
3991
- try {
3992
- if (!existsSync(jobsPath)) {
3993
- log.debug("procedural mining cron: jobs.json not found, skipping auto-register");
3994
- return;
3995
- }
3996
- const created = await ensureProceduralMiningCron(jobsPath, {
3997
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
3998
- });
3999
- if (created.created) {
4000
- log.info(`procedural mining cron auto-registered (${created.jobId})`);
4001
- } else {
4002
- log.debug("procedural mining cron already exists, skipping auto-register");
4003
- }
4004
- } catch (err) {
4005
- log.debug(`procedural mining cron auto-register error: ${err}`);
4006
- }
4007
- }
4008
- async autoRegisterContradictionScanCron() {
4009
- const home = resolveHomeDir();
4010
- const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
4011
- try {
4012
- if (!existsSync(jobsPath)) {
4013
- log.debug("contradiction scan cron: jobs.json not found, skipping auto-register");
4014
- return;
4015
- }
4016
- const created = await ensureContradictionScanCron(jobsPath, {
4017
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
4018
- });
4019
- if (created.created) {
4020
- log.info(`contradiction scan cron auto-registered (${created.jobId})`);
4021
- } else {
4022
- log.debug("contradiction scan cron already exists, skipping auto-register");
4023
- }
4024
- } catch (err) {
4025
- log.debug(`contradiction scan cron auto-register error: ${err}`);
4026
- }
4027
- }
4028
- async autoRegisterPatternReinforcementCron() {
4029
- const home = resolveHomeDir();
4030
- const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
4031
- try {
4032
- if (!existsSync(jobsPath)) {
4033
- log.debug("pattern reinforcement cron: jobs.json not found, skipping auto-register");
4034
- return;
4035
- }
4036
- const created = await ensurePatternReinforcementCron(jobsPath, {
4037
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
4038
- });
4039
- if (created.created) {
4040
- log.info(`pattern reinforcement cron auto-registered (${created.jobId})`);
4041
- } else {
4042
- log.debug("pattern reinforcement cron already exists, skipping auto-register");
4043
- }
4044
- } catch (err) {
4045
- log.debug(`pattern reinforcement cron auto-register error: ${err}`);
4046
- }
4047
- }
4048
3843
  /**
4049
3844
  * Run the pattern-reinforcement maintenance job (issue #687 PR 2/4).
4050
3845
  *
@@ -4170,28 +3965,6 @@ var Orchestrator = class _Orchestrator {
4170
3965
  { enabled: this.config.dreamsPhases.deepSleep.enabled }
4171
3966
  );
4172
3967
  }
4173
- async autoRegisterGraphEdgeDecayCron() {
4174
- const home = resolveHomeDir();
4175
- const jobsPath = path2.join(home, ".openclaw", "cron", "jobs.json");
4176
- try {
4177
- if (!existsSync(jobsPath)) {
4178
- log.debug("graph edge decay cron: jobs.json not found, skipping auto-register");
4179
- return;
4180
- }
4181
- const scheduleExpr = graphEdgeDecayCadenceToCronExpr(this.config.graphEdgeDecayCadenceMs);
4182
- const created = await ensureGraphEdgeDecayCron(jobsPath, {
4183
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
4184
- scheduleExpr
4185
- });
4186
- if (created.created) {
4187
- log.info(`graph edge decay cron auto-registered (${created.jobId}, ${scheduleExpr})`);
4188
- } else {
4189
- log.debug("graph edge decay cron already exists, skipping auto-register");
4190
- }
4191
- } catch (err) {
4192
- log.debug(`graph edge decay cron auto-register error: ${err}`);
4193
- }
4194
- }
4195
3968
  async runLiveConnectors(options = {}) {
4196
3969
  return runLiveConnectorsOnce({
4197
3970
  memoryDir: this.config.memoryDir,
@@ -4571,7 +4344,7 @@ ${doc.content}` : doc.content,
4571
4344
  }
4572
4345
  async waitForConsolidationIdle(timeoutMs = 6e4) {
4573
4346
  const started = Date.now();
4574
- while (this.consolidationInFlight) {
4347
+ while (this.maintenanceScheduler.isConsolidationInFlight()) {
4575
4348
  if (Date.now() - started > timeoutMs) {
4576
4349
  log.warn(`waitForConsolidationIdle timed out after ${timeoutMs}ms`);
4577
4350
  return false;
@@ -11149,7 +10922,6 @@ ${normalized}`).digest("hex");
11149
10922
  }
11150
10923
  const nonZeroExtraction = durableOutputCount > 0;
11151
10924
  try {
11152
- if (nonZeroExtraction) this.nonZeroExtractionsSinceConsolidation += 1;
11153
10925
  this.maybeScheduleConsolidation(nonZeroExtraction);
11154
10926
  } catch (err) {
11155
10927
  log.warn(
@@ -11367,121 +11139,20 @@ ${normalized}`).digest("hex");
11367
11139
  });
11368
11140
  }
11369
11141
  maybeScheduleConsolidation(nonZeroExtraction) {
11370
- if (this.config.consolidationRequireNonZeroExtraction && !nonZeroExtraction)
11371
- return;
11372
- if (this.nonZeroExtractionsSinceConsolidation < this.config.consolidateEveryN)
11373
- return;
11374
- const now = Date.now();
11375
- if (now - this.lastConsolidationRunAtMs < this.config.consolidationMinIntervalMs)
11376
- return;
11377
- if (this.consolidationInFlight) return;
11378
- this.consolidationInFlight = true;
11379
- this.lastConsolidationRunAtMs = now;
11380
- this.nonZeroExtractionsSinceConsolidation = 0;
11381
- this.runConsolidation().catch((err) => log.error("background consolidation failed", err)).finally(() => {
11382
- this.consolidationInFlight = false;
11383
- });
11142
+ this.maintenanceScheduler.maybeScheduleConsolidation(
11143
+ nonZeroExtraction,
11144
+ () => this.runConsolidation()
11145
+ );
11384
11146
  }
11385
11147
  requestQmdMaintenance() {
11386
- if (!this.qmd.isAvailable()) return;
11387
- if (!this.config.qmdMaintenanceEnabled) return;
11388
- this.qmdMaintenancePending = true;
11389
- if (this.qmdMaintenanceTimer) return;
11390
- this.qmdMaintenanceTimer = setTimeout(() => {
11391
- this.qmdMaintenanceTimer = null;
11392
- this.runQmdMaintenance().catch(
11393
- (err) => log.debug(`background qmd maintenance failed: ${err}`)
11394
- );
11395
- }, this.config.qmdMaintenanceDebounceMs);
11148
+ this.maintenanceScheduler.requestQmdMaintenanceForTool("__internal__");
11396
11149
  }
11397
11150
  /**
11398
11151
  * Public entrypoint for tool-driven QMD maintenance requests.
11399
- * Routes through existing debounced/singleflight maintenance controls.
11152
+ * Delegates to the maintenance scheduler (issue #1526 PR1).
11400
11153
  */
11401
11154
  requestQmdMaintenanceForTool(reason) {
11402
- try {
11403
- this.requestQmdMaintenance();
11404
- } catch (err) {
11405
- const msg = err instanceof Error ? err.message : String(err);
11406
- log.warn(`qmd maintenance request failed (${reason}): ${msg}`);
11407
- }
11408
- }
11409
- async runQmdMaintenance() {
11410
- if (this.qmdMaintenanceInFlight) return;
11411
- if (!this.qmdMaintenancePending) return;
11412
- this.qmdMaintenanceInFlight = true;
11413
- this.qmdMaintenancePending = false;
11414
- try {
11415
- if (this.config.namespacesEnabled) {
11416
- const plan = await this.namespaceMaintenancePlan("qmd");
11417
- const now = Date.now();
11418
- const lastEmbedAtByNamespace = this.lastQmdEmbedAtMsByNamespace ?? (this.lastQmdEmbedAtMsByNamespace = /* @__PURE__ */ new Map());
11419
- const dueEmbedNamespaces = (namespaces) => {
11420
- if (!this.config.qmdAutoEmbedEnabled) return [];
11421
- return namespaces.filter(
11422
- (namespace) => now - (lastEmbedAtByNamespace.get(namespace) ?? 0) >= this.config.qmdEmbedMinIntervalMs
11423
- );
11424
- };
11425
- const markEmbedded = (namespaces) => {
11426
- if (namespaces.length === 0) return;
11427
- for (const namespace of namespaces) {
11428
- lastEmbedAtByNamespace.set(namespace, now);
11429
- }
11430
- this.lastQmdEmbedAtMs = now;
11431
- };
11432
- await runNamespaceMaintenanceBatchPlan(
11433
- this.config,
11434
- plan,
11435
- async (candidates) => {
11436
- const namespaces = candidates.map((candidate) => candidate.namespace);
11437
- const embedNamespaces = dueEmbedNamespaces(namespaces);
11438
- let result;
11439
- try {
11440
- result = await this.namespaceSearchRouter.updateNamespacesDetailed(
11441
- namespaces,
11442
- void 0,
11443
- { strict: true }
11444
- );
11445
- } catch (error) {
11446
- if (embedNamespaces.length > 0 && qmdMaintenanceSkipReasonForError(error) === "throttled") {
11447
- await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
11448
- markEmbedded(embedNamespaces);
11449
- }
11450
- throw error;
11451
- }
11452
- if (result.backendCount <= 0) {
11453
- throw new Error("no eligible QMD backend for selected namespaces");
11454
- }
11455
- if (result.eligibleNamespaces.length !== namespaces.length) {
11456
- const eligible = new Set(result.eligibleNamespaces);
11457
- const missing = namespaces.filter((namespace) => !eligible.has(namespace));
11458
- throw new Error(`QMD backend ineligible for selected namespaces (${missing.length})`);
11459
- }
11460
- if (embedNamespaces.length > 0) {
11461
- await this.namespaceSearchRouter.embedNamespaces(embedNamespaces, { strict: true });
11462
- markEmbedded(embedNamespaces);
11463
- }
11464
- return { itemCount: result.backendCount };
11465
- },
11466
- this.namespaceCatalog,
11467
- {
11468
- skipReasonForError: qmdMaintenanceSkipReasonForError
11469
- }
11470
- );
11471
- } else {
11472
- await this.qmd.update();
11473
- const now = Date.now();
11474
- if (this.config.qmdAutoEmbedEnabled && now - this.lastQmdEmbedAtMs >= this.config.qmdEmbedMinIntervalMs) {
11475
- await this.qmd.embed();
11476
- this.lastQmdEmbedAtMs = now;
11477
- }
11478
- }
11479
- } finally {
11480
- this.qmdMaintenanceInFlight = false;
11481
- if (this.qmdMaintenancePending) {
11482
- this.requestQmdMaintenance();
11483
- }
11484
- }
11155
+ this.maintenanceScheduler.requestQmdMaintenanceForTool(reason);
11485
11156
  }
11486
11157
  async persistExtraction(result, storage, threadIdForExtraction, sourceContext, baseNamespace, scopeProfileWritePlan, graphCaps = resolveGraphConstructionCapabilities(this.config)) {
11487
11158
  const citationEnabled = this.config.inlineSourceAttributionEnabled === true;
@@ -15577,4 +15248,4 @@ export {
15577
15248
  resolvePersistedMemoryRelativePath,
15578
15249
  Orchestrator
15579
15250
  };
15580
- //# sourceMappingURL=chunk-TJ5IIQIR.js.map
15251
+ //# sourceMappingURL=chunk-F7BVJ3IE.js.map