opencode-swarm 7.161.0 → 7.162.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 (85) hide show
  1. package/.opencode/skills/critic-gate/SKILL.md +2 -1
  2. package/.opencode/skills/execute/SKILL.md +1 -1
  3. package/dist/cli/{coder-settlement-nayk1bbf.js → coder-settlement-s8cskxk7.js} +9 -9
  4. package/dist/cli/{config-doctor-b1w7yvcs.js → config-doctor-636h188h.js} +3 -3
  5. package/dist/cli/{core-whesnhpf.js → core-h3hsczyq.js} +2 -2
  6. package/dist/cli/{curation-policy-ej9xc0cd.js → curation-policy-ayq5kmnf.js} +4 -4
  7. package/dist/cli/curator-llm-factory-g65xmh8f.js +67 -0
  8. package/dist/cli/{curator-1rzb285s.js → curator-p0dwpn2x.js} +32 -32
  9. package/dist/cli/{evidence-summary-service-ma8drpv5.js → evidence-summary-service-hvbqyb4g.js} +14 -14
  10. package/dist/cli/{gate-evidence-7eh82zs0.js → gate-evidence-dhgmnsh0.js} +5 -5
  11. package/dist/cli/guardrail-explain-s0dzn8c6.js +68 -0
  12. package/dist/cli/{guardrail-log-845tfrwb.js → guardrail-log-qc7rfhv2.js} +7 -7
  13. package/dist/cli/{guardrail-reset-091xw53a.js → guardrail-reset-cxkf5h0x.js} +32 -32
  14. package/dist/cli/{hive-promoter-kx8t5em3.js → hive-promoter-ppbrv8m1.js} +32 -32
  15. package/dist/cli/{index-wrtgyvre.js → index-0h63swrc.js} +5 -5
  16. package/dist/cli/{index-14dgnwmh.js → index-1mbwgw4p.js} +2 -2
  17. package/dist/cli/{index-3cxfqdpv.js → index-1wapt173.js} +5 -5
  18. package/dist/cli/{index-52f67bbh.js → index-25xvw7hq.js} +34 -34
  19. package/dist/cli/{index-qjge2m9r.js → index-2rhs7j4r.js} +625 -243
  20. package/dist/cli/{index-zkgrayya.js → index-2ze7yqm8.js} +2 -2
  21. package/dist/cli/{index-7qera0f6.js → index-3gwkmq53.js} +2 -2
  22. package/dist/cli/{index-d1h4sf8f.js → index-4wmpv2kn.js} +6 -6
  23. package/dist/cli/{index-trmqq4wm.js → index-5wq0dd30.js} +3 -3
  24. package/dist/cli/{index-xy0e0r5f.js → index-6w468bjy.js} +2 -2
  25. package/dist/cli/{index-mj6ndvee.js → index-77syzssw.js} +4 -4
  26. package/dist/cli/{index-c6zyqgpq.js → index-7z9gyts0.js} +1 -1
  27. package/dist/cli/{index-k55td019.js → index-80pmq6q2.js} +1 -1
  28. package/dist/cli/{index-f4dmccpd.js → index-8vwe2qjh.js} +7 -7
  29. package/dist/cli/{index-awjx0wgk.js → index-9wrmzsnk.js} +1 -1
  30. package/dist/cli/{index-c9zp4xwc.js → index-9xd073d4.js} +1 -1
  31. package/dist/cli/{index-s33ee2w3.js → index-acnwj4pc.js} +1 -1
  32. package/dist/cli/{index-y14mwbk8.js → index-bdmg6yvj.js} +2 -2
  33. package/dist/cli/{index-d8st72j7.js → index-db520vnn.js} +1 -1
  34. package/dist/cli/{index-dq41vsf9.js → index-jw7z3gem.js} +1 -1
  35. package/dist/cli/{index-7619tk9a.js → index-kk9yk7an.js} +1 -1
  36. package/dist/cli/{index-ambz0ryy.js → index-mfewnd7j.js} +4 -4
  37. package/dist/cli/{index-134d35c1.js → index-n249fbw7.js} +9 -0
  38. package/dist/cli/{index-y0ra2v4w.js → index-pde4zn7j.js} +1 -1
  39. package/dist/cli/{index-dh5q6z7y.js → index-q87ht62k.js} +2 -2
  40. package/dist/cli/{index-54jznpq7.js → index-qn4w0gar.js} +1 -1
  41. package/dist/cli/{index-gkv7s4xy.js → index-qw893zqp.js} +6 -6
  42. package/dist/cli/{index-w9g58t3j.js → index-r7rn6e5f.js} +5 -5
  43. package/dist/cli/{index-93pf824c.js → index-sjkxrf06.js} +4 -4
  44. package/dist/cli/{index-et1jpj6z.js → index-tjaawnws.js} +3 -3
  45. package/dist/cli/{index-etdtfhhv.js → index-tnj464kq.js} +1 -1
  46. package/dist/cli/{index-t81fmfjj.js → index-vcv9m2q5.js} +2 -2
  47. package/dist/cli/{index-mbktm1ah.js → index-vkaqrrsc.js} +2 -2
  48. package/dist/cli/{index-f5axf6vq.js → index-ydbd41sv.js} +1 -1
  49. package/dist/cli/{index-h6wtxzvm.js → index-z4n60b0a.js} +2 -2
  50. package/dist/cli/{index-q8hm27yj.js → index-zg9d392c.js} +4 -1
  51. package/dist/cli/index.js +32 -32
  52. package/dist/cli/{knowledge-escalator-9eqpsbw5.js → knowledge-escalator-nyeg4ndw.js} +12 -12
  53. package/dist/cli/{knowledge-events-a8r4ej12.js → knowledge-events-z7smbnff.js} +10 -10
  54. package/dist/cli/{knowledge-link-8knefv8x.js → knowledge-link-0byjmj0w.js} +3 -3
  55. package/dist/cli/{knowledge-store-ydzeppv7.js → knowledge-store-p14t72y5.js} +4 -4
  56. package/dist/cli/{knowledge-validator-mnv58he9.js → knowledge-validator-jg6zhx9s.js} +6 -6
  57. package/dist/cli/{model-preflight-yqqchzjn.js → model-preflight-c3mc8njg.js} +1 -1
  58. package/dist/cli/{pending-delegations-9mwmrwwm.js → pending-delegations-0111ywd2.js} +3 -3
  59. package/dist/cli/{pr-review-reentry-authorization-h1ssfq37.js → pr-review-reentry-authorization-b7ceja9y.js} +32 -32
  60. package/dist/cli/{pr-subscriptions-3zwthnan.js → pr-subscriptions-4e64sbwg.js} +3 -3
  61. package/dist/cli/{runner-fzgkd6m1.js → runner-rddddxmq.js} +4 -4
  62. package/dist/cli/{scan-cursor-5rmaqw2t.js → scan-cursor-wjad4yd7.js} +5 -5
  63. package/dist/cli/{schema-72vpr9xy.js → schema-9ebqj7mv.js} +2 -2
  64. package/dist/cli/{scope-persistence-39mwns79.js → scope-persistence-j5hz4mnd.js} +8 -8
  65. package/dist/cli/{skill-generator-9aay0t53.js → skill-generator-x6b05jz6.js} +14 -14
  66. package/dist/cli/{sqlite-loader-r1kgt2pq.js → sqlite-loader-c92413n7.js} +1 -1
  67. package/dist/cli/{worktree-collision-ownership-ybhktnq4.js → worktree-collision-ownership-g5n5xbqy.js} +4 -4
  68. package/dist/cli/{worktree-isolation-w8ett6bs.js → worktree-isolation-ha70bwes.js} +32 -32
  69. package/dist/config/evidence-schema.d.ts +9 -0
  70. package/dist/db/sqlite-loader.d.ts +1 -0
  71. package/dist/hooks/delegation-gate.d.ts +4 -1
  72. package/dist/index.js +63 -49
  73. package/dist/memory/curator-decision-helpers.d.ts +1 -0
  74. package/dist/memory/index.d.ts +1 -1
  75. package/dist/memory/local-jsonl-provider.d.ts +2 -0
  76. package/dist/memory/proposal-load.d.ts +15 -0
  77. package/dist/memory/relation-constants.d.ts +3 -0
  78. package/dist/memory/relations.d.ts +8 -0
  79. package/dist/memory/schema.d.ts +8 -0
  80. package/dist/memory/sqlite-provider.d.ts +3 -0
  81. package/dist/memory/types.d.ts +21 -0
  82. package/dist/tools/placeholder-scan.d.ts +5 -3
  83. package/package.json +1 -1
  84. package/dist/cli/curator-llm-factory-bqfkaq6y.js +0 -67
  85. package/dist/cli/guardrail-explain-em2mqz9a.js +0 -68
@@ -6,7 +6,7 @@ import {
6
6
  resolveExecutableFromPath,
7
7
  runEvaluation,
8
8
  runExternalTool
9
- } from "./index-s33ee2w3.js";
9
+ } from "./index-acnwj4pc.js";
10
10
  import {
11
11
  finalizeShellAuditForClose,
12
12
  isPolicyProtectedPath,
@@ -15,13 +15,13 @@ import {
15
15
  protectedRoots,
16
16
  redactDecisionLineForArchive,
17
17
  stableCanonicalStringify
18
- } from "./index-et1jpj6z.js";
18
+ } from "./index-tjaawnws.js";
19
19
  import {
20
20
  detectStraySwarmDirs,
21
21
  readDoctorArtifact,
22
22
  removeStraySwarmDir,
23
23
  runConfigDoctor
24
- } from "./index-h6wtxzvm.js";
24
+ } from "./index-z4n60b0a.js";
25
25
  import {
26
26
  MAX_TRANSIENT_RETRIES,
27
27
  archiveEvidence,
@@ -68,7 +68,7 @@ import {
68
68
  validateProjectRoot,
69
69
  validateSymlinkBoundary,
70
70
  validateTargetWithinRoot
71
- } from "./index-f4dmccpd.js";
71
+ } from "./index-8vwe2qjh.js";
72
72
  import {
73
73
  EvaluationTaskV1Schema,
74
74
  GateAuditManifestV1Schema,
@@ -85,7 +85,7 @@ import {
85
85
  saveGateAuditResult,
86
86
  savePromotionDecision,
87
87
  saveTaskSetSnapshot
88
- } from "./index-dq41vsf9.js";
88
+ } from "./index-jw7z3gem.js";
89
89
  import {
90
90
  canonicalHash,
91
91
  canonicalJson,
@@ -99,7 +99,7 @@ import {
99
99
  } from "./index-txdagbh7.js";
100
100
  import {
101
101
  loadDatabaseCtor
102
- } from "./index-134d35c1.js";
102
+ } from "./index-n249fbw7.js";
103
103
  import {
104
104
  LANGUAGE_REGISTRY,
105
105
  _internals as _internals3,
@@ -130,15 +130,15 @@ import {
130
130
  retireSkill,
131
131
  selectCandidateEntries,
132
132
  syncBundledProjectSkillsIfMissingAsync
133
- } from "./index-93pf824c.js";
133
+ } from "./index-sjkxrf06.js";
134
134
  import {
135
135
  readRecentEscalations
136
- } from "./index-wrtgyvre.js";
136
+ } from "./index-0h63swrc.js";
137
137
  import {
138
138
  alreadyCuratedThisGeneration,
139
139
  claimNextScanBatch,
140
140
  resolveCohortId
141
- } from "./index-7qera0f6.js";
141
+ } from "./index-3gwkmq53.js";
142
142
  import {
143
143
  CURATOR_INIT_PROMPT,
144
144
  CURATOR_PHASE_PROMPT,
@@ -162,7 +162,7 @@ import {
162
162
  listActive,
163
163
  subscribe,
164
164
  unsubscribe
165
- } from "./index-y14mwbk8.js";
165
+ } from "./index-bdmg6yvj.js";
166
166
  import {
167
167
  clearWorktreeMergeStatus,
168
168
  getAllWorktreeMergeFailures,
@@ -174,7 +174,7 @@ import {
174
174
  listCoderSettlementWalStates,
175
175
  recoverCoderSettlement,
176
176
  recoverStaleCoderSettlements
177
- } from "./index-w9g58t3j.js";
177
+ } from "./index-r7rn6e5f.js";
178
178
  import {
179
179
  parsePorcelainV2Snapshot,
180
180
  resolveCommitCountSince,
@@ -207,7 +207,7 @@ import {
207
207
  WORKTREE_LIFECYCLE_LOCK_FILE,
208
208
  recordWorktreeProvisioningOwner,
209
209
  removeWorktreeProvisioningOwner
210
- } from "./index-awjx0wgk.js";
210
+ } from "./index-9wrmzsnk.js";
211
211
  import {
212
212
  appendUnactionable,
213
213
  quarantineEntry,
@@ -218,11 +218,11 @@ import {
218
218
  validateActionableFields,
219
219
  validateLesson,
220
220
  validateSkillPath
221
- } from "./index-mj6ndvee.js";
221
+ } from "./index-77syzssw.js";
222
222
  import {
223
223
  authorizeCuration,
224
224
  buildConfigFingerprintInput
225
- } from "./index-f5axf6vq.js";
225
+ } from "./index-ydbd41sv.js";
226
226
  import {
227
227
  cohortConfigFingerprint
228
228
  } from "./index-rtry5xyf.js";
@@ -253,12 +253,12 @@ import {
253
253
  transitionTaskWorkflowEvidence,
254
254
  withTaskEvidenceTransaction,
255
255
  writeWorkflowWalFile
256
- } from "./index-t81fmfjj.js";
256
+ } from "./index-vcv9m2q5.js";
257
257
  import {
258
258
  makeWorktreeBranchName,
259
259
  provisionWorktree,
260
260
  removeWorktree
261
- } from "./index-xy0e0r5f.js";
261
+ } from "./index-6w468bjy.js";
262
262
  import {
263
263
  DEFAULT_STALE_DELEGATION_TIMEOUT_MS,
264
264
  DELEGATION_COMPACTION_HIGH_WATER_BYTES,
@@ -286,7 +286,7 @@ import {
286
286
  scanBackgroundCoderReservationsForAdmission,
287
287
  scanDelegationsForRecovery,
288
288
  sweepStaleDelegations
289
- } from "./index-mbktm1ah.js";
289
+ } from "./index-vkaqrrsc.js";
290
290
  import {
291
291
  compositeSessionKey,
292
292
  sessionKeySuffix
@@ -297,7 +297,7 @@ import {
297
297
  clearAllScopes,
298
298
  clearScopeBindingFromDisk,
299
299
  clearScopeBindings
300
- } from "./index-ambz0ryy.js";
300
+ } from "./index-mfewnd7j.js";
301
301
  import {
302
302
  appendLedgerEvent,
303
303
  computePlanHash,
@@ -312,7 +312,7 @@ import {
312
312
  readPlanEpochIdentity,
313
313
  replayFromLedgerWithStatus,
314
314
  takeSnapshotEvent
315
- } from "./index-y0ra2v4w.js";
315
+ } from "./index-pde4zn7j.js";
316
316
  import {
317
317
  CORE_EVENT_LOCKED,
318
318
  appendCoreEventSync,
@@ -322,7 +322,7 @@ import {
322
322
  hasSpecDriftAuditEvent,
323
323
  hasTaskRepairAuditEvent,
324
324
  readCoreEvents
325
- } from "./index-7619tk9a.js";
325
+ } from "./index-kk9yk7an.js";
326
326
  import {
327
327
  sanitizeDiagnosticText
328
328
  } from "./index-556ja8an.js";
@@ -371,7 +371,7 @@ import {
371
371
  transactFile,
372
372
  transactKnowledge,
373
373
  wordBigrams
374
- } from "./index-d1h4sf8f.js";
374
+ } from "./index-4wmpv2kn.js";
375
375
  import {
376
376
  MAX_EVENT_LOG_ENTRIES,
377
377
  _internals as _internals2,
@@ -387,13 +387,13 @@ import {
387
387
  recordKnowledgeEvent,
388
388
  recordPhaseCloseIntent,
389
389
  resolveKnowledgeEventsPath
390
- } from "./index-gkv7s4xy.js";
390
+ } from "./index-qw893zqp.js";
391
391
  import {
392
392
  resolveWorktreeIsolationConfig
393
- } from "./index-trmqq4wm.js";
393
+ } from "./index-5wq0dd30.js";
394
394
  import {
395
395
  RetrospectiveEvidenceSchema
396
- } from "./index-q8hm27yj.js";
396
+ } from "./index-zg9d392c.js";
397
397
  import {
398
398
  estimateTokens,
399
399
  readSwarmFileAsync,
@@ -413,7 +413,7 @@ import {
413
413
  init_loader,
414
414
  loadPluginConfig,
415
415
  loadPluginConfigWithMeta
416
- } from "./index-etdtfhhv.js";
416
+ } from "./index-tnj464kq.js";
417
417
  import {
418
418
  DEFAULT_HARNESS_EVOLUTION_CONFIG,
419
419
  DEFAULT_PR_REVIEW_RESILIENCE_CONFIG,
@@ -429,7 +429,7 @@ import {
429
429
  package_default,
430
430
  resolveAutoReviewConfig,
431
431
  stripKnownSwarmPrefix
432
- } from "./index-zkgrayya.js";
432
+ } from "./index-2ze7yqm8.js";
433
433
  import {
434
434
  init_git_executable,
435
435
  resolveGitExecutable,
@@ -445,7 +445,7 @@ import {
445
445
  observeCuratorCompliance,
446
446
  observeStoreHealth,
447
447
  readLearningHealth
448
- } from "./index-k55td019.js";
448
+ } from "./index-80pmq6q2.js";
449
449
  import {
450
450
  AGENT_TOOL_MAP,
451
451
  ALL_AGENT_NAMES,
@@ -459,7 +459,7 @@ import {
459
459
  init_agent_names,
460
460
  init_constants,
461
461
  init_tool_metadata
462
- } from "./index-c9zp4xwc.js";
462
+ } from "./index-9xd073d4.js";
463
463
  import {
464
464
  resolveHiveDataDir,
465
465
  resolveHiveEventsPath,
@@ -475,10 +475,10 @@ import {
475
475
  resolveLinkDir,
476
476
  sanitizeLinkId,
477
477
  writeLinkPointer
478
- } from "./index-c6zyqgpq.js";
478
+ } from "./index-7z9gyts0.js";
479
479
  import {
480
480
  atomicWriteFile
481
- } from "./index-d8st72j7.js";
481
+ } from "./index-db520vnn.js";
482
482
  import {
483
483
  KNOWLEDGE_SCHEMA_VERSION,
484
484
  OUTCOME_BLOCK_THRESHOLD,
@@ -498,7 +498,7 @@ import {
498
498
  atomicWriteSwarmFileSync,
499
499
  matchTempGrammar,
500
500
  parseTargetBasename
501
- } from "./index-dh5q6z7y.js";
501
+ } from "./index-q87ht62k.js";
502
502
  import {
503
503
  invalidateCachedArtifact,
504
504
  resetSwarmArtifactCache
@@ -1255,6 +1255,21 @@ var _test_exports = {
1255
1255
  init_zod();
1256
1256
  import * as fs53 from "fs";
1257
1257
  import * as path117 from "path";
1258
+
1259
+ // src/config/agent-model.ts
1260
+ init_agent_names();
1261
+ init_constants();
1262
+ var CANONICAL_AGENT_NAMES = new Set(ALL_AGENT_NAMES);
1263
+ var KNOWN_EMBEDDED_VARIANTS = new Set([
1264
+ "low",
1265
+ "medium",
1266
+ "high",
1267
+ "max",
1268
+ "xhigh",
1269
+ "thinking"
1270
+ ]);
1271
+
1272
+ // src/hooks/delegation-gate.ts
1258
1273
  init_agent_names();
1259
1274
  init_constants();
1260
1275
  init_schema();
@@ -14197,19 +14212,6 @@ function isoNow() {
14197
14212
  function delay(ms) {
14198
14213
  return new Promise((resolve7) => setTimeout(resolve7, ms));
14199
14214
  }
14200
- // src/config/agent-model.ts
14201
- init_agent_names();
14202
- init_constants();
14203
- var CANONICAL_AGENT_NAMES = new Set(ALL_AGENT_NAMES);
14204
- var KNOWN_EMBEDDED_VARIANTS = new Set([
14205
- "low",
14206
- "medium",
14207
- "high",
14208
- "max",
14209
- "xhigh",
14210
- "thinking"
14211
- ]);
14212
-
14213
14215
  // src/agents/index.ts
14214
14216
  init_constants();
14215
14217
  init_schema();
@@ -21324,7 +21326,7 @@ function planMerges(active, threshold, maxComparisons, maxMerges) {
21324
21326
  };
21325
21327
  }
21326
21328
  async function sweepActiveNearDuplicates(directory, options = {}) {
21327
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-3cxfqdpv.js");
21329
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-1wapt173.js");
21328
21330
  const { config } = loadPluginConfigWithMeta2(directory);
21329
21331
  const sweepConfig = config.learning?.dedup_sweep;
21330
21332
  if (sweepConfig?.enabled === false)
@@ -22461,7 +22463,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
22461
22463
  }
22462
22464
  if (config.skill_generation_enabled === true && skillCandidates.length > 0) {
22463
22465
  try {
22464
- const skillModule = await import("./skill-generator-9aay0t53.js");
22466
+ const skillModule = await import("./skill-generator-x6b05jz6.js");
22465
22467
  for (const cand of skillCandidates) {
22466
22468
  if (cand.confidence < (config.min_skill_confidence ?? DEFAULT_SKILL_MIN_CONFIDENCE)) {
22467
22469
  continue;
@@ -22933,7 +22935,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
22933
22935
  } catch {}
22934
22936
  }
22935
22937
  if (contradictedEntries.length > 0 && knowledgeConfig.contradiction_threshold_action === "quarantine") {
22936
- const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-9eqpsbw5.js");
22938
+ const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-nyeg4ndw.js");
22937
22939
  for (const { id } of contradictedEntries) {
22938
22940
  try {
22939
22941
  await maybeQuarantineOnContradiction(directory, id, knowledgeConfig.contradiction_quarantine_threshold, knowledgeConfig.contradiction_quarantine_window_days);
@@ -23752,7 +23754,7 @@ async function runCuratorPostMortem(directory, options = {}) {
23752
23754
  warnings.push("Failed to collect knowledge summary.");
23753
23755
  }
23754
23756
  try {
23755
- const { getScanStatus } = await import("./scan-cursor-5rmaqw2t.js");
23757
+ const { getScanStatus } = await import("./scan-cursor-wjad4yd7.js");
23756
23758
  const scanStatus = await getScanStatus(directory);
23757
23759
  if (scanStatus.remaining_estimate > 0) {
23758
23760
  warnings.push(`Fair scan: reviewed ${knowledgeSummary.length} entries this sweep (generation ${scanStatus.generation}); ${scanStatus.remaining_estimate} more eligible entries will be visited in future curation sweeps.`);
@@ -23924,9 +23926,9 @@ var _internals27 = {
23924
23926
  verifyPostMortemKnowledgeActions,
23925
23927
  repairPostMortemActions,
23926
23928
  loadDefaultKnowledgeConfig: async (directory) => {
23927
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-72vpr9xy.js");
23929
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-9ebqj7mv.js");
23928
23930
  try {
23929
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-3cxfqdpv.js");
23931
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-1wapt173.js");
23930
23932
  const loaded = loadPluginConfigWithMeta2(directory);
23931
23933
  return KnowledgeConfigSchema2.parse(loaded.config.knowledge ?? {});
23932
23934
  } catch {
@@ -23934,11 +23936,11 @@ var _internals27 = {
23934
23936
  }
23935
23937
  },
23936
23938
  applyCuratorKnowledgeUpdates: async (directory, recommendations, knowledgeConfig, generation) => {
23937
- const { applyCuratorKnowledgeUpdates: applyCuratorKnowledgeUpdates2 } = await import("./curator-1rzb285s.js");
23939
+ const { applyCuratorKnowledgeUpdates: applyCuratorKnowledgeUpdates2 } = await import("./curator-p0dwpn2x.js");
23938
23940
  return applyCuratorKnowledgeUpdates2(directory, recommendations, knowledgeConfig, generation);
23939
23941
  },
23940
23942
  checkHivePromotions: async (entries, knowledgeConfig, directory) => {
23941
- const { checkHivePromotions } = await import("./hive-promoter-kx8t5em3.js");
23943
+ const { checkHivePromotions } = await import("./hive-promoter-ppbrv8m1.js");
23942
23944
  return checkHivePromotions(entries, knowledgeConfig, directory);
23943
23945
  },
23944
23946
  applyProposalTriage: async (directory, triage) => {
@@ -23947,7 +23949,7 @@ var _internals27 = {
23947
23949
  activateProposal,
23948
23950
  listSkills: listSkills2,
23949
23951
  sanitizeSlug
23950
- } = await import("./skill-generator-9aay0t53.js");
23952
+ } = await import("./skill-generator-x6b05jz6.js");
23951
23953
  const result = {
23952
23954
  approved: [],
23953
23955
  rejected: [],
@@ -25277,9 +25279,9 @@ function hashContent(content) {
25277
25279
  return createHash13("sha1").update(content).digest("hex");
25278
25280
  }
25279
25281
  async function loadConfigForPolicyCurator(directory) {
25280
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-72vpr9xy.js");
25282
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-9ebqj7mv.js");
25281
25283
  try {
25282
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-3cxfqdpv.js");
25284
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-1wapt173.js");
25283
25285
  const { config: loadedConfig } = loadPluginConfigWithMeta2(directory);
25284
25286
  return KnowledgeConfigSchema2.parse(loadedConfig.knowledge ?? {});
25285
25287
  } catch {
@@ -27432,6 +27434,10 @@ class MemoryValidationError extends Error {
27432
27434
  }
27433
27435
  }
27434
27436
 
27437
+ // src/memory/relation-constants.ts
27438
+ var MAX_MERGE_PARTICIPANTS = 8;
27439
+ var MAX_RELATIONS_PER_MEMORY = 32;
27440
+ var RELATED_RECALL_FANOUT = 2;
27435
27441
  // src/memory/schema.ts
27436
27442
  init_zod();
27437
27443
  import { createHash as createHash14 } from "crypto";
@@ -27581,6 +27587,10 @@ var MemoryRecordSchema = exports_external.object({
27581
27587
  updatedAt: exports_external.string().datetime(),
27582
27588
  lastAccessedAt: exports_external.string().datetime().optional(),
27583
27589
  expiresAt: exports_external.string().datetime().optional(),
27590
+ relations: exports_external.array(exports_external.object({
27591
+ memoryId: exports_external.string().regex(/^mem_[a-f0-9]{16}$/),
27592
+ type: exports_external.literal("merged_with")
27593
+ }).strict()).max(32).optional(),
27584
27594
  qValue: exports_external.number().min(0).max(1).optional(),
27585
27595
  supersedes: exports_external.array(exports_external.string()).optional(),
27586
27596
  supersededBy: exports_external.string().optional(),
@@ -27612,7 +27622,7 @@ var MemoryProposalSchema = exports_external.object({
27612
27622
  ]),
27613
27623
  proposedRecord: MemoryRecordSchema.optional(),
27614
27624
  targetMemoryId: exports_external.string().optional(),
27615
- relatedMemoryIds: exports_external.array(exports_external.string()).optional(),
27625
+ relatedMemoryIds: exports_external.array(exports_external.string().regex(/^mem_[a-f0-9]{16}$/)).max(MAX_MERGE_PARTICIPANTS).optional(),
27616
27626
  proposedBy: exports_external.object({
27617
27627
  agentRole: exports_external.string().optional(),
27618
27628
  agentId: exports_external.string().optional(),
@@ -27632,7 +27642,18 @@ var MemoryProposalSchema = exports_external.object({
27632
27642
  rejectionReason: exports_external.string().optional(),
27633
27643
  createdAt: exports_external.string().datetime(),
27634
27644
  metadata: exports_external.record(exports_external.string(), exports_external.unknown())
27635
- }).strict();
27645
+ }).strict().superRefine((proposal, context) => {
27646
+ if (proposal.operation !== "merge")
27647
+ return;
27648
+ const ids = proposal.relatedMemoryIds ?? [];
27649
+ if (ids.length < 2 || new Set(ids).size !== ids.length) {
27650
+ context.addIssue({
27651
+ code: exports_external.ZodIssueCode.custom,
27652
+ path: ["relatedMemoryIds"],
27653
+ message: `merge proposals require 2-${MAX_MERGE_PARTICIPANTS} distinct relatedMemoryIds`
27654
+ });
27655
+ }
27656
+ });
27636
27657
  var NewMemoryRecordSchema = exports_external.object({
27637
27658
  scope: MemoryScopeRefSchema.optional(),
27638
27659
  kind: MemoryKindSchema,
@@ -27684,6 +27705,14 @@ var CuratorMemoryDecisionSchema = exports_external.discriminatedUnion("action",
27684
27705
  replacement: NewMemoryRecordSchema,
27685
27706
  reason: CuratorDecisionReasonSchema
27686
27707
  }).strict(),
27708
+ exports_external.object({
27709
+ action: exports_external.literal("merge"),
27710
+ proposalId: ProposalIdSchema,
27711
+ relatedMemoryIds: exports_external.array(MemoryIdSchema).min(2).max(MAX_MERGE_PARTICIPANTS).refine((ids) => new Set(ids).size === ids.length, {
27712
+ message: "merge decisions require distinct relatedMemoryIds"
27713
+ }),
27714
+ reason: CuratorDecisionReasonSchema
27715
+ }).strict(),
27687
27716
  exports_external.object({
27688
27717
  action: exports_external.literal("reject"),
27689
27718
  proposalId: ProposalIdSchema,
@@ -27788,102 +27817,6 @@ function validateMemoryProposal(proposal) {
27788
27817
  return MemoryProposalSchema.parse(proposal);
27789
27818
  }
27790
27819
 
27791
- // src/memory/curator-decision-helpers.ts
27792
- var CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH = 500;
27793
- function validateDecisionMatchesProposal(decision, proposal) {
27794
- if (decision.action === "add" && proposal.operation !== "add" || decision.action === "update" && proposal.operation !== "update" || decision.action === "supersede" && proposal.operation !== "supersede") {
27795
- throw new MemoryValidationError(`curator ${decision.action} decision does not match ${proposal.operation} proposal`);
27796
- }
27797
- if (decision.action === "update" && proposal.targetMemoryId && proposal.targetMemoryId !== decision.targetMemoryId) {
27798
- throw new MemoryValidationError("curator update decision target does not match proposal target");
27799
- }
27800
- if (decision.action === "supersede" && proposal.targetMemoryId && proposal.targetMemoryId !== decision.oldMemoryId) {
27801
- throw new MemoryValidationError("curator supersede decision target does not match proposal target");
27802
- }
27803
- }
27804
- function validateCuratorPromotableMemory(record) {
27805
- if (record.stability !== "durable") {
27806
- throw new MemoryValidationError("curator memory promotions must be durable facts");
27807
- }
27808
- if (!DURABLE_MEMORY_KINDS.has(record.kind)) {
27809
- throw new MemoryValidationError("curator memory promotions must use durable fact kinds; store raw docs, search results, and other bulky source material as evidence records instead");
27810
- }
27811
- if (normalizeMemoryText(record.text).length > CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH) {
27812
- throw new MemoryValidationError(`curator memory promotions must be concise durable facts under ${CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH} characters`);
27813
- }
27814
- }
27815
- function applyPatchToMemory(existing, patch, updatedAt) {
27816
- const base = {
27817
- scope: patch.scope ?? existing.scope,
27818
- kind: patch.kind ?? existing.kind,
27819
- text: patch.text === undefined ? existing.text : normalizeMemoryText(patch.text)
27820
- };
27821
- const tags = patch.tags === undefined ? existing.tags : normalizeTags(patch.tags);
27822
- return {
27823
- ...existing,
27824
- ...patch,
27825
- ...base,
27826
- id: createMemoryId(base),
27827
- tags,
27828
- updatedAt,
27829
- contentHash: computeMemoryContentHash(base),
27830
- metadata: patch.metadata === undefined ? existing.metadata : { ...existing.metadata, ...patch.metadata }
27831
- };
27832
- }
27833
- function markProposalReviewed(proposal, decision, status, reviewedAt, ids) {
27834
- const reason = curatorDecisionReason(decision);
27835
- return validateMemoryProposal({
27836
- ...proposal,
27837
- status,
27838
- reviewer: "curator_agent",
27839
- reviewedAt,
27840
- rejectionReason: decision.action === "reject" ? reason : undefined,
27841
- metadata: {
27842
- ...proposal.metadata,
27843
- curatorDecision: {
27844
- action: decision.action,
27845
- reason,
27846
- ...ids,
27847
- appliedAt: reviewedAt
27848
- }
27849
- }
27850
- });
27851
- }
27852
- function curatorDecisionReason(decision) {
27853
- switch (decision.action) {
27854
- case "add":
27855
- return;
27856
- case "update":
27857
- case "supersede":
27858
- case "reject":
27859
- case "noop":
27860
- return decision.reason;
27861
- }
27862
- }
27863
- function buildCuratorDecisionEvent(change, proposal) {
27864
- return {
27865
- ...change,
27866
- proposalOperation: proposal.operation
27867
- };
27868
- }
27869
- function normalizeTags(tags) {
27870
- return Array.from(new Set(tags.map((tag) => tag.toLowerCase().replace(/[^\w-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")).filter(Boolean))).slice(0, 32);
27871
- }
27872
-
27873
- // src/memory/local-jsonl-provider.ts
27874
- var import_proper_lockfile6 = __toESM(require_proper_lockfile(), 1);
27875
- import { randomUUID as randomUUID6 } from "crypto";
27876
- import { existsSync as existsSync17, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
27877
- import {
27878
- appendFile as appendFile3,
27879
- mkdir as mkdir9,
27880
- readFile as readFile10,
27881
- rename as rename5,
27882
- truncate,
27883
- writeFile as writeFile7
27884
- } from "fs/promises";
27885
- import * as path32 from "path";
27886
-
27887
27820
  // src/memory/q-learning.ts
27888
27821
  function clamp01(value) {
27889
27822
  if (value < 0)
@@ -28113,6 +28046,10 @@ function sameScope(a, b) {
28113
28046
  function scopeAllowed(recordScope, allowedScopes) {
28114
28047
  return allowedScopes.some((scope) => sameScope(recordScope, scope));
28115
28048
  }
28049
+ function scoreMemoryRecord(record, request, qLearningConfig = DEFAULT_QLEARNING_CONFIG) {
28050
+ const result = scoreMemoryRecordDetailed(record, request, createScoringContext(request), qLearningConfig);
28051
+ return result.item;
28052
+ }
28116
28053
  function scoreMemoryRecordDetailed(record, request, context, qLearningConfig = DEFAULT_QLEARNING_CONFIG) {
28117
28054
  if (!request.includeExpired && isExpired(record)) {
28118
28055
  return { item: null, skipReason: "filtered" };
@@ -28278,6 +28215,218 @@ function unionTokens(...sets) {
28278
28215
  return union;
28279
28216
  }
28280
28217
 
28218
+ // src/memory/relations.ts
28219
+ function canonicalMemoryIds(ids) {
28220
+ return Array.from(new Set(ids)).sort();
28221
+ }
28222
+ function buildMemoryRelationIndex(proposals) {
28223
+ const index = new Map;
28224
+ for (const proposal of proposals) {
28225
+ if (proposal.operation !== "merge" || proposal.status !== "applied")
28226
+ continue;
28227
+ const ids = canonicalMemoryIds(proposal.relatedMemoryIds ?? []);
28228
+ for (const sourceId of ids) {
28229
+ let related = index.get(sourceId);
28230
+ if (!related) {
28231
+ related = new Map;
28232
+ index.set(sourceId, related);
28233
+ }
28234
+ for (const targetId of ids) {
28235
+ if (targetId !== sourceId) {
28236
+ related.set(targetId, { memoryId: targetId, type: "merged_with" });
28237
+ }
28238
+ }
28239
+ }
28240
+ }
28241
+ return new Map(Array.from(index, ([id, relations]) => [
28242
+ id,
28243
+ Array.from(relations.values()).sort((a, b) => a.memoryId.localeCompare(b.memoryId))
28244
+ ]));
28245
+ }
28246
+ function projectMemoryRelations(records, proposals) {
28247
+ const index = buildMemoryRelationIndex(proposals);
28248
+ return records.map(({ relations: _derived, ...record }) => {
28249
+ const relations = index.get(record.id);
28250
+ return relations?.length ? { ...record, relations } : record;
28251
+ });
28252
+ }
28253
+ function stripDerivedRelations(record) {
28254
+ const { relations: _derived, ...stored } = record;
28255
+ return stored;
28256
+ }
28257
+ function validateMergeParticipants(ids, records, proposals, now2 = new Date) {
28258
+ const canonical = canonicalMemoryIds(ids);
28259
+ if (canonical.length < 2 || canonical.length > MAX_MERGE_PARTICIPANTS) {
28260
+ throw new MemoryValidationError(`merge decisions require 2-${MAX_MERGE_PARTICIPANTS} distinct relatedMemoryIds`);
28261
+ }
28262
+ const byId = new Map(Array.from(records, (record) => [record.id, record]));
28263
+ const participants = canonical.map((id) => {
28264
+ const record = byId.get(id);
28265
+ if (!record || record.metadata.deleted === true || record.supersededBy || isExpired(record, now2)) {
28266
+ throw new MemoryValidationError(`merge participant is not active: ${id}`);
28267
+ }
28268
+ return record;
28269
+ });
28270
+ const scopeKey = stableScopeKey(participants[0].scope);
28271
+ if (participants.some((record) => stableScopeKey(record.scope) !== scopeKey)) {
28272
+ throw new MemoryValidationError("merge participants must share one memory scope");
28273
+ }
28274
+ const index = buildMemoryRelationIndex(proposals);
28275
+ for (const id of canonical) {
28276
+ const degree = new Set([
28277
+ ...index.get(id)?.map((relation) => relation.memoryId) ?? [],
28278
+ ...canonical.filter((candidate) => candidate !== id)
28279
+ ]).size;
28280
+ if (degree > MAX_RELATIONS_PER_MEMORY) {
28281
+ throw new MemoryValidationError(`merge would exceed ${MAX_RELATIONS_PER_MEMORY} relations for ${id}`);
28282
+ }
28283
+ }
28284
+ return canonical;
28285
+ }
28286
+ function expandRelatedRecallItems(items, allRecords, request) {
28287
+ const normal = items.filter((item) => !item.explored).slice(0, request.maxItems);
28288
+ const explored = items.filter((item) => item.explored);
28289
+ if (normal.length < request.maxItems) {
28290
+ const byId = new Map(allRecords.map((record) => [record.id, record]));
28291
+ const selected = new Set([...normal, ...explored].map((item) => item.record.id));
28292
+ const directSources = [...normal];
28293
+ for (const source of directSources) {
28294
+ const sourceRecord = byId.get(source.record.id) ?? source.record;
28295
+ let addedForSource = 0;
28296
+ for (const relation of sourceRecord.relations ?? []) {
28297
+ if (normal.length >= request.maxItems || addedForSource >= RELATED_RECALL_FANOUT) {
28298
+ break;
28299
+ }
28300
+ if (selected.has(relation.memoryId))
28301
+ continue;
28302
+ const record = byId.get(relation.memoryId);
28303
+ if (!record)
28304
+ continue;
28305
+ const scored = scoreMemoryRecord(record, {
28306
+ ...request,
28307
+ requireQuerySignal: false
28308
+ });
28309
+ if (!scored)
28310
+ continue;
28311
+ normal.push({
28312
+ ...scored,
28313
+ reason: `${scored.reason}, relation=${relation.type}, related_from=${source.record.id}`,
28314
+ relation: { type: relation.type, sourceMemoryId: source.record.id }
28315
+ });
28316
+ selected.add(record.id);
28317
+ addedForSource++;
28318
+ }
28319
+ }
28320
+ }
28321
+ const seen = new Set;
28322
+ return [...normal, ...explored].filter((item) => {
28323
+ if (seen.has(item.record.id))
28324
+ return false;
28325
+ seen.add(item.record.id);
28326
+ return true;
28327
+ });
28328
+ }
28329
+
28330
+ // src/memory/curator-decision-helpers.ts
28331
+ var CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH = 500;
28332
+ function validateDecisionMatchesProposal(decision, proposal) {
28333
+ if (decision.action === "add" && proposal.operation !== "add" || decision.action === "update" && proposal.operation !== "update" || decision.action === "supersede" && proposal.operation !== "supersede" || decision.action === "merge" && proposal.operation !== "merge") {
28334
+ throw new MemoryValidationError(`curator ${decision.action} decision does not match ${proposal.operation} proposal`);
28335
+ }
28336
+ if (decision.action === "update" && proposal.targetMemoryId && proposal.targetMemoryId !== decision.targetMemoryId) {
28337
+ throw new MemoryValidationError("curator update decision target does not match proposal target");
28338
+ }
28339
+ if (decision.action === "supersede" && proposal.targetMemoryId && proposal.targetMemoryId !== decision.oldMemoryId) {
28340
+ throw new MemoryValidationError("curator supersede decision target does not match proposal target");
28341
+ }
28342
+ if (decision.action === "merge" && canonicalMemoryIds(proposal.relatedMemoryIds ?? []).join("\x00") !== canonicalMemoryIds(decision.relatedMemoryIds).join("\x00")) {
28343
+ throw new MemoryValidationError("curator merge decision related memories do not match proposal");
28344
+ }
28345
+ }
28346
+ function validateCuratorPromotableMemory(record) {
28347
+ if (record.stability !== "durable") {
28348
+ throw new MemoryValidationError("curator memory promotions must be durable facts");
28349
+ }
28350
+ if (!DURABLE_MEMORY_KINDS.has(record.kind)) {
28351
+ throw new MemoryValidationError("curator memory promotions must use durable fact kinds; store raw docs, search results, and other bulky source material as evidence records instead");
28352
+ }
28353
+ if (normalizeMemoryText(record.text).length > CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH) {
28354
+ throw new MemoryValidationError(`curator memory promotions must be concise durable facts under ${CURATOR_PROMOTED_MEMORY_MAX_TEXT_LENGTH} characters`);
28355
+ }
28356
+ }
28357
+ function applyPatchToMemory(existing, patch, updatedAt) {
28358
+ const base = {
28359
+ scope: patch.scope ?? existing.scope,
28360
+ kind: patch.kind ?? existing.kind,
28361
+ text: patch.text === undefined ? existing.text : normalizeMemoryText(patch.text)
28362
+ };
28363
+ const tags = patch.tags === undefined ? existing.tags : normalizeTags(patch.tags);
28364
+ return {
28365
+ ...existing,
28366
+ ...patch,
28367
+ ...base,
28368
+ id: createMemoryId(base),
28369
+ tags,
28370
+ updatedAt,
28371
+ contentHash: computeMemoryContentHash(base),
28372
+ metadata: patch.metadata === undefined ? existing.metadata : { ...existing.metadata, ...patch.metadata }
28373
+ };
28374
+ }
28375
+ function markProposalReviewed(proposal, decision, status, reviewedAt, ids) {
28376
+ const reason = curatorDecisionReason(decision);
28377
+ return validateMemoryProposal({
28378
+ ...proposal,
28379
+ status,
28380
+ reviewer: "curator_agent",
28381
+ reviewedAt,
28382
+ rejectionReason: decision.action === "reject" ? reason : undefined,
28383
+ metadata: {
28384
+ ...proposal.metadata,
28385
+ curatorDecision: {
28386
+ action: decision.action,
28387
+ reason,
28388
+ ...ids,
28389
+ appliedAt: reviewedAt
28390
+ }
28391
+ }
28392
+ });
28393
+ }
28394
+ function curatorDecisionReason(decision) {
28395
+ switch (decision.action) {
28396
+ case "add":
28397
+ return;
28398
+ case "update":
28399
+ case "supersede":
28400
+ case "merge":
28401
+ case "reject":
28402
+ case "noop":
28403
+ return decision.reason;
28404
+ }
28405
+ }
28406
+ function buildCuratorDecisionEvent(change, proposal) {
28407
+ return {
28408
+ ...change,
28409
+ proposalOperation: proposal.operation
28410
+ };
28411
+ }
28412
+ function normalizeTags(tags) {
28413
+ return Array.from(new Set(tags.map((tag) => tag.toLowerCase().replace(/[^\w-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")).filter(Boolean))).slice(0, 32);
28414
+ }
28415
+
28416
+ // src/memory/local-jsonl-provider.ts
28417
+ var import_proper_lockfile6 = __toESM(require_proper_lockfile(), 1);
28418
+ import { randomUUID as randomUUID6 } from "crypto";
28419
+ import { existsSync as existsSync17, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
28420
+ import {
28421
+ appendFile as appendFile3,
28422
+ mkdir as mkdir9,
28423
+ readFile as readFile10,
28424
+ rename as rename5,
28425
+ truncate,
28426
+ writeFile as writeFile7
28427
+ } from "fs/promises";
28428
+ import * as path32 from "path";
28429
+
28281
28430
  // src/memory/maintenance.ts
28282
28431
  var DEFAULT_IMPORTANCE_WEIGHTS = {
28283
28432
  wRecency: 0.2,
@@ -28599,6 +28748,56 @@ function compareText(a, b) {
28599
28748
  return a < b ? -1 : a > b ? 1 : 0;
28600
28749
  }
28601
28750
 
28751
+ // src/memory/proposal-load.ts
28752
+ var INVALID_PROPOSAL_LOAD_SAMPLE_LIMIT = 5;
28753
+ var UNKNOWN_PROPOSAL_ID = "<unknown>";
28754
+ var MAX_PROPOSAL_LOAD_REASON_LENGTH = 200;
28755
+ function parseLoadedProposal(value, rejectDurableSecrets) {
28756
+ const proposal = validateMemoryProposal(value);
28757
+ if (proposal.proposedRecord) {
28758
+ validateMemoryRecordRules(proposal.proposedRecord, {
28759
+ rejectDurableSecrets
28760
+ });
28761
+ }
28762
+ return proposal;
28763
+ }
28764
+ function proposalLoadIssueFromValue(value, error2) {
28765
+ return {
28766
+ proposalId: extractProposalId(value) ?? UNKNOWN_PROPOSAL_ID,
28767
+ reason: normalizeProposalLoadReason(error2)
28768
+ };
28769
+ }
28770
+ function proposalLoadIssueFromId(proposalId, error2) {
28771
+ return {
28772
+ proposalId: proposalId || UNKNOWN_PROPOSAL_ID,
28773
+ reason: normalizeProposalLoadReason(error2)
28774
+ };
28775
+ }
28776
+ function buildProposalLoadDiagnostics(issues) {
28777
+ return {
28778
+ invalidCount: issues.length,
28779
+ samples: issues.slice(0, INVALID_PROPOSAL_LOAD_SAMPLE_LIMIT)
28780
+ };
28781
+ }
28782
+ function asStoredProposalValidationError(proposalId, error2) {
28783
+ if (error2 instanceof MemoryValidationError)
28784
+ return error2;
28785
+ return new MemoryValidationError(`stored memory proposal is malformed: ${proposalId} (${normalizeProposalLoadReason(error2)})`, "stored_memory_proposal_invalid");
28786
+ }
28787
+ function extractProposalId(value) {
28788
+ if (!value || typeof value !== "object")
28789
+ return;
28790
+ const candidate = value.id;
28791
+ return typeof candidate === "string" && candidate.length > 0 ? candidate : undefined;
28792
+ }
28793
+ function normalizeProposalLoadReason(error2) {
28794
+ const raw = error2 instanceof Error ? error2.message : String(error2);
28795
+ const trimmed = raw.replace(/\s+/g, " ").trim();
28796
+ if (trimmed.length <= MAX_PROPOSAL_LOAD_REASON_LENGTH)
28797
+ return trimmed;
28798
+ return `${trimmed.slice(0, MAX_PROPOSAL_LOAD_REASON_LENGTH - 1)}\u2026`;
28799
+ }
28800
+
28602
28801
  // src/memory/local-jsonl-provider.ts
28603
28802
  var lockfile6 = import_proper_lockfile6.default;
28604
28803
 
@@ -28610,6 +28809,7 @@ class LocalJsonlMemoryProvider {
28610
28809
  initialized = false;
28611
28810
  memories = new Map;
28612
28811
  proposals = new Map;
28812
+ lastInvalidProposalLoadSignature = null;
28613
28813
  constructor(rootDirectory, config = {}, vettedCohortRoot) {
28614
28814
  this.rootDirectory = rootDirectory;
28615
28815
  this.cohortRoot = vettedCohortRoot ?? null;
@@ -28632,7 +28832,10 @@ class LocalJsonlMemoryProvider {
28632
28832
  const memoryPath = this.pathFor("memories");
28633
28833
  const proposalPath = this.pathFor("proposals");
28634
28834
  const memoryLoad = validateLoadedMemories(await readJsonl(memoryPath), this.config);
28635
- const proposalLoad = validateLoadedProposals(await readJsonl(proposalPath), this.config);
28835
+ const rawProposalLoad = await readProposalJsonl(proposalPath);
28836
+ const proposalLoad = validateLoadedProposals(rawProposalLoad.values, this.config);
28837
+ proposalLoad.invalidCount += rawProposalLoad.invalidRows.length;
28838
+ proposalLoad.invalidRows.unshift(...rawProposalLoad.invalidRows);
28636
28839
  const outcomeEvents = this.readOutcomeEventsSync();
28637
28840
  const materializedLoad = validateMaterializedMemories(memoryLoad.records, outcomeEvents, this.config);
28638
28841
  this.memories = new Map(materializedLoad.records.map((record) => [record.id, record]));
@@ -28643,7 +28846,9 @@ class LocalJsonlMemoryProvider {
28643
28846
  await this.audit("invalid_load", "memories", `${invalidMemoryCount} invalid memory JSONL row(s) skipped`);
28644
28847
  }
28645
28848
  if (proposalLoad.invalidCount > 0) {
28646
- await this.audit("invalid_load", "proposals", `${proposalLoad.invalidCount} invalid proposal JSONL row(s) skipped`);
28849
+ await this.reportInvalidProposalLoad(proposalLoad.invalidRows);
28850
+ } else {
28851
+ this.lastInvalidProposalLoadSignature = null;
28647
28852
  }
28648
28853
  }
28649
28854
  async upsert(record) {
@@ -28655,7 +28860,7 @@ class LocalJsonlMemoryProvider {
28655
28860
  throw new MemoryValidationError("memory is tombstoned and cannot be upserted");
28656
28861
  }
28657
28862
  let parsed = validateMemoryRecordRules({
28658
- ...record,
28863
+ ...stripDerivedRelations(record),
28659
28864
  createdAt: existing?.createdAt ?? record.createdAt,
28660
28865
  metadata: {
28661
28866
  ...record.metadata,
@@ -28700,7 +28905,9 @@ class LocalJsonlMemoryProvider {
28700
28905
  await this.initialize();
28701
28906
  return this.withOutcomeStoreLock(async () => {
28702
28907
  await this.refreshMemoriesUnlocked();
28703
- return this.memories.get(id) ?? null;
28908
+ await this.refreshProposalsUnlocked();
28909
+ const record = this.memories.get(id);
28910
+ return record ? projectMemoryRelations([record], this.proposals.values())[0] : null;
28704
28911
  });
28705
28912
  }
28706
28913
  async appendOutcome(memoryId, event, anchors = []) {
@@ -28788,12 +28995,13 @@ class LocalJsonlMemoryProvider {
28788
28995
  });
28789
28996
  const result = scoreMemoryRecordsWithDiagnostics(records, request, this.config.qLearning);
28790
28997
  const sliced = sliceRecallItemsWithExploration(result.items, request.maxItems);
28998
+ const expanded = expandRelatedRecallItems(sliced, projectMemoryRelations(Array.from(this.memories.values()), this.proposals.values()), request);
28791
28999
  return {
28792
- items: sliced,
29000
+ items: expanded,
28793
29001
  diagnostics: {
28794
29002
  ...result.diagnostics,
28795
- exploredCount: sliced.some((item) => item.explored) ? 1 : 0,
28796
- returnedCount: sliced.length
29003
+ exploredCount: expanded.some((item) => item.explored) ? 1 : 0,
29004
+ returnedCount: expanded.length
28797
29005
  }
28798
29006
  };
28799
29007
  }
@@ -28846,8 +29054,9 @@ class LocalJsonlMemoryProvider {
28846
29054
  await this.initialize();
28847
29055
  await this.withOutcomeStoreLock(async () => {
28848
29056
  await this.refreshMemoriesUnlocked();
29057
+ await this.refreshProposalsUnlocked();
28849
29058
  });
28850
- let records = Array.from(this.memories.values());
29059
+ let records = projectMemoryRelations(Array.from(this.memories.values()), this.proposals.values());
28851
29060
  if (filter.scopes && filter.scopes.length > 0) {
28852
29061
  records = records.filter((record) => scopeAllowed(record.scope, filter.scopes ?? []));
28853
29062
  }
@@ -28872,8 +29081,13 @@ class LocalJsonlMemoryProvider {
28872
29081
  async createProposal(proposal) {
28873
29082
  await this.initialize();
28874
29083
  const next = validateMemoryProposal(proposal);
28875
- this.proposals.set(next.id, next);
28876
- await appendJsonl(this.pathFor("proposals"), next);
29084
+ await this.withOutcomeStoreLock(async () => {
29085
+ await this.refreshProposalsUnlocked();
29086
+ const filePath = this.pathFor("proposals");
29087
+ await repairIncompleteJsonlTail(filePath);
29088
+ await appendJsonl(filePath, next);
29089
+ this.proposals.set(next.id, next);
29090
+ });
28877
29091
  await this.audit("proposal", next.id);
28878
29092
  this.bumpCohortGeneration();
28879
29093
  return next;
@@ -28966,11 +29180,24 @@ class LocalJsonlMemoryProvider {
28966
29180
  oldMemoryId = oldMemory.id;
28967
29181
  replacementMemoryId = replacement.id;
28968
29182
  memoryId = replacement.id;
29183
+ } else if (decision.action === "merge") {
29184
+ decision = {
29185
+ ...decision,
29186
+ relatedMemoryIds: validateMergeParticipants(decision.relatedMemoryIds, this.memories.values(), this.proposals.values(), new Date(appliedAt))
29187
+ };
28969
29188
  }
28970
29189
  const proposalStatus = decision.action === "reject" ? "rejected" : "applied";
28971
- const reviewedProposal = markProposalReviewed(proposal, decision, proposalStatus, appliedAt, { memoryId, targetMemoryId, oldMemoryId, replacementMemoryId });
29190
+ const reviewedProposal = markProposalReviewed(proposal, decision, proposalStatus, appliedAt, {
29191
+ memoryId,
29192
+ targetMemoryId,
29193
+ oldMemoryId,
29194
+ replacementMemoryId,
29195
+ relatedMemoryIds: decision.action === "merge" ? decision.relatedMemoryIds : undefined
29196
+ });
29197
+ const proposalsPath = this.pathFor("proposals");
29198
+ await repairIncompleteJsonlTail(proposalsPath);
29199
+ await appendJsonl(proposalsPath, reviewedProposal);
28972
29200
  this.proposals.set(reviewedProposal.id, reviewedProposal);
28973
- await appendJsonl(this.pathFor("proposals"), reviewedProposal);
28974
29201
  const change = {
28975
29202
  action: decision.action,
28976
29203
  proposalId: decision.proposalId,
@@ -28980,9 +29207,16 @@ class LocalJsonlMemoryProvider {
28980
29207
  targetMemoryId,
28981
29208
  oldMemoryId,
28982
29209
  replacementMemoryId,
29210
+ relatedMemoryIds: decision.action === "merge" ? decision.relatedMemoryIds : undefined,
28983
29211
  reason: curatorDecisionReason(decision)
28984
29212
  };
28985
- await this.audit("curator_decision", decision.proposalId, change.reason, buildCuratorDecisionEvent(change, proposal));
29213
+ try {
29214
+ await this.audit("curator_decision", decision.proposalId, change.reason, buildCuratorDecisionEvent(change, proposal));
29215
+ } catch (error2) {
29216
+ warn("[memory] failed to persist curator decision audit event", {
29217
+ reason: error2 instanceof Error ? error2.message : String(error2)
29218
+ });
29219
+ }
28986
29220
  return change;
28987
29221
  }
28988
29222
  async compact() {
@@ -29068,8 +29302,32 @@ class LocalJsonlMemoryProvider {
29068
29302
  await appendJsonl(filePath, stripMaterializedOutcomes(record));
29069
29303
  }
29070
29304
  async refreshProposalsUnlocked() {
29071
- const loaded = validateLoadedProposals(await readJsonl(this.pathFor("proposals")), this.config);
29305
+ const proposalPath = this.pathFor("proposals");
29306
+ await repairIncompleteJsonlTail(proposalPath);
29307
+ const rawProposalLoad = await readProposalJsonl(proposalPath);
29308
+ const loaded = validateLoadedProposals(rawProposalLoad.values, this.config);
29309
+ loaded.invalidCount += rawProposalLoad.invalidRows.length;
29310
+ loaded.invalidRows.unshift(...rawProposalLoad.invalidRows);
29072
29311
  this.proposals = new Map(loaded.records.map((proposal) => [proposal.id, proposal]));
29312
+ if (loaded.invalidCount > 0) {
29313
+ await this.reportInvalidProposalLoad(loaded.invalidRows);
29314
+ } else {
29315
+ this.lastInvalidProposalLoadSignature = null;
29316
+ }
29317
+ }
29318
+ async reportInvalidProposalLoad(issues) {
29319
+ const eventJson = buildProposalLoadDiagnostics(issues);
29320
+ const signature = JSON.stringify(eventJson);
29321
+ if (signature === this.lastInvalidProposalLoadSignature)
29322
+ return;
29323
+ this.lastInvalidProposalLoadSignature = signature;
29324
+ try {
29325
+ await this.audit("invalid_load", "proposals", `${issues.length} invalid proposal JSONL row(s) skipped`, eventJson);
29326
+ } catch (error2) {
29327
+ warn("[memory] failed to persist invalid proposal load audit event", {
29328
+ reason: error2 instanceof Error ? error2.message : String(error2)
29329
+ });
29330
+ }
29073
29331
  }
29074
29332
  readOutcomeEventsSync() {
29075
29333
  const filePath = this.pathFor("outcome-events");
@@ -29228,21 +29486,18 @@ function compareText2(a, b) {
29228
29486
  }
29229
29487
  function validateLoadedProposals(values, config) {
29230
29488
  const records = [];
29489
+ const invalidRows = [];
29231
29490
  let invalidCount = 0;
29232
29491
  for (const value of values) {
29233
29492
  try {
29234
- const proposal = validateMemoryProposal(value);
29235
- if (proposal.proposedRecord) {
29236
- validateMemoryRecordRules(proposal.proposedRecord, {
29237
- rejectDurableSecrets: config.redaction.rejectDurableSecrets
29238
- });
29239
- }
29493
+ const proposal = parseLoadedProposal(value, config.redaction.rejectDurableSecrets);
29240
29494
  records.push(proposal);
29241
- } catch {
29495
+ } catch (error2) {
29242
29496
  invalidCount++;
29497
+ invalidRows.push(proposalLoadIssueFromValue(value, error2));
29243
29498
  }
29244
29499
  }
29245
- return { records, invalidCount };
29500
+ return { records, invalidCount, invalidRows };
29246
29501
  }
29247
29502
  async function readJsonl(filePath) {
29248
29503
  if (!existsSync17(filePath))
@@ -29260,6 +29515,28 @@ async function readJsonl(filePath) {
29260
29515
  }
29261
29516
  return records;
29262
29517
  }
29518
+ async function readProposalJsonl(filePath) {
29519
+ if (!existsSync17(filePath))
29520
+ return { values: [], invalidRows: [] };
29521
+ const content = await readFile10(filePath, "utf-8");
29522
+ const values = [];
29523
+ const invalidRows = [];
29524
+ for (const [index, line] of content.split(`
29525
+ `).entries()) {
29526
+ const trimmed = line.trim();
29527
+ if (!trimmed)
29528
+ continue;
29529
+ try {
29530
+ values.push(JSON.parse(trimmed));
29531
+ } catch {
29532
+ invalidRows.push({
29533
+ proposalId: "<unknown>",
29534
+ reason: `invalid JSONL at line ${index + 1}`
29535
+ });
29536
+ }
29537
+ }
29538
+ return { values, invalidRows };
29539
+ }
29263
29540
  async function readAuditEvents(filePath) {
29264
29541
  const values = await readJsonl(filePath);
29265
29542
  const events = [];
@@ -29738,7 +30015,7 @@ async function readLegacyJsonl(rootDirectory, config = {}) {
29738
30015
  const resolved = resolveConfig(config);
29739
30016
  const storageDir = resolveMemoryStorageDir(rootDirectory, resolved);
29740
30017
  const memoryLoad = await readMemoryJsonl(path35.join(storageDir, "memories.jsonl"), resolved);
29741
- const proposalLoad = await readProposalJsonl(path35.join(storageDir, "proposals.jsonl"), resolved);
30018
+ const proposalLoad = await readProposalJsonl2(path35.join(storageDir, "proposals.jsonl"), resolved);
29742
30019
  const outcomeLoad = await readOutcomeJsonl(path35.join(storageDir, "outcome-events.jsonl"));
29743
30020
  return {
29744
30021
  memories: memoryLoad.records,
@@ -29937,24 +30214,20 @@ async function readMemoryJsonl(filePath, config) {
29937
30214
  totalRows: rows.totalRows
29938
30215
  };
29939
30216
  }
29940
- async function readProposalJsonl(filePath, config) {
30217
+ async function readProposalJsonl2(filePath, config) {
29941
30218
  const rows = await readJsonlRows(filePath);
29942
30219
  const records = [];
29943
30220
  const invalidRows = [];
29944
30221
  for (const row of rows.rows) {
29945
30222
  try {
29946
- const proposal = validateMemoryProposal(row.value);
29947
- if (proposal.proposedRecord) {
29948
- validateMemoryRecordRules(proposal.proposedRecord, {
29949
- rejectDurableSecrets: config.redaction.rejectDurableSecrets
29950
- });
29951
- }
30223
+ const proposal = parseLoadedProposal(row.value, config.redaction.rejectDurableSecrets);
29952
30224
  records.push(proposal);
29953
30225
  } catch (err) {
30226
+ const issue = proposalLoadIssueFromValue(row.value, err);
29954
30227
  invalidRows.push({
29955
30228
  file: "proposals.jsonl",
29956
30229
  line: row.line,
29957
- error: err instanceof Error ? err.message : String(err)
30230
+ error: issue.reason
29958
30231
  });
29959
30232
  }
29960
30233
  }
@@ -30297,6 +30570,24 @@ var MIGRATIONS2 = [
30297
30570
  sql: `
30298
30571
  ALTER TABLE memory_events ADD COLUMN prev_hash TEXT;
30299
30572
  `
30573
+ },
30574
+ {
30575
+ version: 14,
30576
+ name: "create_memory_relations",
30577
+ sql: `
30578
+ CREATE TABLE IF NOT EXISTS memory_relations (
30579
+ source_id TEXT NOT NULL,
30580
+ target_id TEXT NOT NULL,
30581
+ proposal_id TEXT NOT NULL,
30582
+ created_at TEXT NOT NULL,
30583
+ PRIMARY KEY (source_id, target_id),
30584
+ FOREIGN KEY (source_id) REFERENCES memory_items(id) ON DELETE CASCADE,
30585
+ FOREIGN KEY (target_id) REFERENCES memory_items(id) ON DELETE CASCADE,
30586
+ FOREIGN KEY (proposal_id) REFERENCES memory_proposals(id)
30587
+ );
30588
+ CREATE INDEX IF NOT EXISTS idx_memory_relations_source
30589
+ ON memory_relations(source_id, target_id);
30590
+ `
30300
30591
  }
30301
30592
  ];
30302
30593
  var EVENT_CHAIN_SCHEMA_MIGRATION_NAME = "add_memory_events_prev_hash";
@@ -30429,6 +30720,14 @@ class SQLiteMemoryProvider {
30429
30720
  await this.migrateLegacyJsonlIfNeeded();
30430
30721
  const memoryLoad = this.loadMemories();
30431
30722
  const proposalLoad = this.loadProposals();
30723
+ for (const proposal of proposalLoad.records) {
30724
+ if (proposal.operation === "merge" && proposal.status === "applied") {
30725
+ this.writeProposal(proposal, {
30726
+ records: memoryLoad.records,
30727
+ proposals: proposalLoad.records
30728
+ });
30729
+ }
30730
+ }
30432
30731
  this.memories = new Map(memoryLoad.records.map((record) => [record.id, record]));
30433
30732
  this.proposals = new Map(proposalLoad.records.map((proposal) => [proposal.id, proposal]));
30434
30733
  this.initialized = true;
@@ -30436,7 +30735,13 @@ class SQLiteMemoryProvider {
30436
30735
  await this.event("invalid_load", "memory_items", `${memoryLoad.invalidCount} invalid SQLite memory row(s) skipped`);
30437
30736
  }
30438
30737
  if (proposalLoad.invalidCount > 0) {
30439
- await this.event("invalid_load", "memory_proposals", `${proposalLoad.invalidCount} invalid SQLite proposal row(s) skipped`);
30738
+ try {
30739
+ this.insertEvent("invalid_load", "memory_proposals", `${proposalLoad.invalidCount} invalid SQLite proposal row(s) skipped`, JSON.stringify(buildProposalLoadDiagnostics(proposalLoad.invalidRows)));
30740
+ } catch (error2) {
30741
+ warn("[memory] failed to persist invalid SQLite proposal load event", {
30742
+ reason: error2 instanceof Error ? error2.message : String(error2)
30743
+ });
30744
+ }
30440
30745
  }
30441
30746
  } catch (err) {
30442
30747
  try {
@@ -30461,7 +30766,8 @@ class SQLiteMemoryProvider {
30461
30766
  if (existing?.metadata.deleted === true) {
30462
30767
  throw new MemoryValidationError("memory is tombstoned and cannot be upserted");
30463
30768
  }
30464
- const merged = existingRow ? mergeProvenanceColumns(record, existingRow) : record;
30769
+ const storedRecord = stripDerivedRelations(record);
30770
+ const merged = existingRow ? mergeProvenanceColumns(storedRecord, existingRow) : storedRecord;
30465
30771
  next = validateMemoryRecordRules({
30466
30772
  ...merged,
30467
30773
  createdAt: existing?.createdAt ?? merged.createdAt,
@@ -30510,7 +30816,7 @@ class SQLiteMemoryProvider {
30510
30816
  const record = this.readMemoryById(id);
30511
30817
  if (record)
30512
30818
  this.memories.set(id, record);
30513
- return record;
30819
+ return record ? this.projectRelationsFromStorage([record])[0] : null;
30514
30820
  }
30515
30821
  async appendOutcome(memoryId, event, anchors = []) {
30516
30822
  await this.initialize();
@@ -30627,12 +30933,13 @@ class SQLiteMemoryProvider {
30627
30933
  const result = scoreMemoryRecordsWithDiagnostics(candidates.records, request, this.config.qLearning);
30628
30934
  const reranked = candidates.ftsOrder ? rerankWithFts(result.items, candidates.ftsOrder) : result.items;
30629
30935
  const disabledPathSliced = sliceRecallItemsWithExploration(reranked, request.maxItems);
30936
+ const expanded2 = this.expandRelated(disabledPathSliced, request);
30630
30937
  return {
30631
- items: disabledPathSliced,
30938
+ items: expanded2,
30632
30939
  diagnostics: {
30633
30940
  ...result.diagnostics,
30634
- exploredCount: disabledPathSliced.some((item) => item.explored) ? 1 : 0,
30635
- returnedCount: disabledPathSliced.length
30941
+ exploredCount: expanded2.some((item) => item.explored) ? 1 : 0,
30942
+ returnedCount: expanded2.length
30636
30943
  }
30637
30944
  };
30638
30945
  }
@@ -30673,12 +30980,13 @@ class SQLiteMemoryProvider {
30673
30980
  });
30674
30981
  }
30675
30982
  const denseFailedSliced = sliceRecallItemsWithExploration(lexicalReranked, request.maxItems);
30983
+ const expanded2 = this.expandRelated(denseFailedSliced, request);
30676
30984
  return {
30677
- items: denseFailedSliced,
30985
+ items: expanded2,
30678
30986
  diagnostics: {
30679
30987
  ...lexicalResult.diagnostics,
30680
- exploredCount: denseFailedSliced.some((item) => item.explored) ? 1 : 0,
30681
- returnedCount: denseFailedSliced.length
30988
+ exploredCount: expanded2.some((item) => item.explored) ? 1 : 0,
30989
+ returnedCount: expanded2.length
30682
30990
  }
30683
30991
  };
30684
30992
  }
@@ -30749,16 +31057,33 @@ class SQLiteMemoryProvider {
30749
31057
  }
30750
31058
  }
30751
31059
  const fusionSliced = sliceRecallItemsWithExploration(rerankedItems, request.maxItems);
31060
+ const expanded = this.expandRelated(fusionSliced, request);
30752
31061
  return {
30753
- items: fusionSliced,
31062
+ items: expanded,
30754
31063
  diagnostics: {
30755
31064
  ...lexicalResult.diagnostics,
30756
- exploredCount: fusionSliced.some((item) => item.explored) ? 1 : 0,
30757
- returnedCount: fusionSliced.length,
31065
+ exploredCount: expanded.some((item) => item.explored) ? 1 : 0,
31066
+ returnedCount: expanded.length,
30758
31067
  fusionActive: true
30759
31068
  }
30760
31069
  };
30761
31070
  }
31071
+ expandRelated(items, request) {
31072
+ const sources = this.projectRelationsFromStorage(items.map((item) => item.record));
31073
+ const sourceById = new Map(sources.map((record) => [record.id, record]));
31074
+ const relatedRecords = [];
31075
+ for (const source of sources) {
31076
+ for (const relation of (source.relations ?? []).slice(0, RELATED_RECALL_FANOUT)) {
31077
+ const record = this.readMemoryById(relation.memoryId);
31078
+ if (record)
31079
+ relatedRecords.push(record);
31080
+ }
31081
+ }
31082
+ return expandRelatedRecallItems(items.map((item) => ({
31083
+ ...item,
31084
+ record: sourceById.get(item.record.id) ?? item.record
31085
+ })), [...sources, ...relatedRecords], request);
31086
+ }
30762
31087
  async recordRecallUsage(event) {
30763
31088
  await this.initialize();
30764
31089
  this.requireDb().run(`INSERT INTO memory_recall_usage (
@@ -30954,7 +31279,7 @@ class SQLiteMemoryProvider {
30954
31279
  return !Number.isFinite(expires) || expires > now2;
30955
31280
  });
30956
31281
  }
30957
- return records;
31282
+ return this.projectRelationsFromStorage(records);
30958
31283
  }
30959
31284
  async createProposal(proposal) {
30960
31285
  await this.initialize();
@@ -30971,7 +31296,7 @@ class SQLiteMemoryProvider {
30971
31296
  }
30972
31297
  async listProposals(filter = {}) {
30973
31298
  await this.initialize();
30974
- let proposals = Array.from(this.proposals.values());
31299
+ let proposals = this.refreshProposalsFromStorage();
30975
31300
  if (filter.status) {
30976
31301
  proposals = proposals.filter((proposal) => proposal.status === filter.status);
30977
31302
  }
@@ -31111,7 +31436,8 @@ class SQLiteMemoryProvider {
31111
31436
  const provenanceById = new Map(this.requireDb().query("SELECT id, source_task_id, agent_role, embedding_model_version, valid_from, supersedes_reason FROM memory_items").all().map((row) => [row.id, row]));
31112
31437
  const enriched = memories.map((memory) => {
31113
31438
  const row = provenanceById.get(memory.id);
31114
- return row ? mergeProvenanceColumns(memory, row) : memory;
31439
+ const stored = stripDerivedRelations(memory);
31440
+ return row ? mergeProvenanceColumns(stored, row) : stored;
31115
31441
  });
31116
31442
  const proposals = await this.listProposals();
31117
31443
  const outcomeEvents = this.readOutcomeEvents();
@@ -31540,21 +31866,41 @@ class SQLiteMemoryProvider {
31540
31866
  loadProposals() {
31541
31867
  const rows = this.requireDb().query("SELECT id, proposal_json FROM memory_proposals ORDER BY created_at ASC").all();
31542
31868
  const records = [];
31869
+ const invalidRows = [];
31543
31870
  let invalidCount = 0;
31544
31871
  for (const row of rows) {
31545
31872
  try {
31546
- const proposal = validateMemoryProposal(JSON.parse(row.proposal_json));
31547
- if (proposal.proposedRecord) {
31548
- validateMemoryRecordRules(proposal.proposedRecord, {
31549
- rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
31550
- });
31551
- }
31873
+ const proposal = parseLoadedProposal(JSON.parse(row.proposal_json), this.config.redaction.rejectDurableSecrets);
31552
31874
  records.push(proposal);
31553
- } catch {
31875
+ } catch (error2) {
31554
31876
  invalidCount++;
31877
+ invalidRows.push(proposalLoadIssueFromId(row.id, error2));
31555
31878
  }
31556
31879
  }
31557
- return { records, invalidCount };
31880
+ return { records, invalidCount, invalidRows };
31881
+ }
31882
+ refreshProposalsFromStorage() {
31883
+ const records = this.loadProposals().records;
31884
+ this.proposals.clear();
31885
+ for (const proposal of records)
31886
+ this.proposals.set(proposal.id, proposal);
31887
+ return records;
31888
+ }
31889
+ projectRelationsFromStorage(records) {
31890
+ if (records.length === 0)
31891
+ return [];
31892
+ const query = this.requireDb().prepare(" SELECT target_id FROM memory_relations WHERE source_id = ? ORDER BY target_id ASC LIMIT ?");
31893
+ try {
31894
+ return records.map(({ relations: _derived, ...record }) => {
31895
+ const relations = query.all(record.id, MAX_RELATIONS_PER_MEMORY).map((row) => ({
31896
+ memoryId: row.target_id,
31897
+ type: "merged_with"
31898
+ }));
31899
+ return relations.length ? { ...record, relations } : record;
31900
+ });
31901
+ } finally {
31902
+ query.finalize();
31903
+ }
31558
31904
  }
31559
31905
  writeMemory(record) {
31560
31906
  const stored = stripMaterializedOutcomes(record);
@@ -31776,7 +32122,7 @@ class SQLiteMemoryProvider {
31776
32122
  this.requireDb().run("DELETE FROM memory_items_vec WHERE id = ?", [id]);
31777
32123
  } catch {}
31778
32124
  }
31779
- writeProposal(proposal) {
32125
+ writeProposal(proposal, validationContext) {
31780
32126
  this.requireDb().run(`INSERT OR REPLACE INTO memory_proposals (
31781
32127
  id,
31782
32128
  status,
@@ -31788,6 +32134,33 @@ class SQLiteMemoryProvider {
31788
32134
  proposal.createdAt,
31789
32135
  JSON.stringify(proposal)
31790
32136
  ]);
32137
+ if (proposal.operation === "merge" && proposal.status === "applied") {
32138
+ this.requireDb().run("DELETE FROM memory_relations WHERE proposal_id = ?", [proposal.id]);
32139
+ let ids;
32140
+ try {
32141
+ ids = validateMergeParticipants(proposal.relatedMemoryIds ?? [], validationContext?.records ?? this.loadMemories().records, validationContext?.proposals ?? this.loadProposals().records, proposal.reviewedAt ? new Date(proposal.reviewedAt) : new Date);
32142
+ } catch (error2) {
32143
+ warn("Skipping invalid applied merge during relation materialization", {
32144
+ proposalId: proposal.id,
32145
+ reason: error2 instanceof Error ? error2.message : String(error2)
32146
+ });
32147
+ return;
32148
+ }
32149
+ const existingIds = new Set(ids.filter((id) => Boolean(this.requireDb().query("SELECT id FROM memory_items WHERE id = ? LIMIT 1").get(id))));
32150
+ for (const sourceId of ids) {
32151
+ for (const targetId of ids) {
32152
+ if (sourceId === targetId || !existingIds.has(sourceId) || !existingIds.has(targetId)) {
32153
+ continue;
32154
+ }
32155
+ this.requireDb().run("INSERT OR IGNORE INTO memory_relations (source_id, target_id, proposal_id, created_at) VALUES (?, ?, ?, ?)", [
32156
+ sourceId,
32157
+ targetId,
32158
+ proposal.id,
32159
+ proposal.reviewedAt ?? proposal.createdAt
32160
+ ]);
32161
+ }
32162
+ }
32163
+ }
31791
32164
  }
31792
32165
  applyDecisionToStorage(decision, proposal, appliedAt) {
31793
32166
  const memories = [];
@@ -31852,13 +32225,21 @@ class SQLiteMemoryProvider {
31852
32225
  oldMemoryId = oldMemory.id;
31853
32226
  replacementMemoryId = replacement.id;
31854
32227
  memoryId = replacement.id;
32228
+ } else if (decision.action === "merge") {
32229
+ const currentMemories = this.loadMemories().records;
32230
+ const currentProposals = this.loadProposals().records;
32231
+ decision = {
32232
+ ...decision,
32233
+ relatedMemoryIds: validateMergeParticipants(decision.relatedMemoryIds, currentMemories, currentProposals, new Date(appliedAt))
32234
+ };
31855
32235
  }
31856
32236
  const proposalStatus = decision.action === "reject" ? "rejected" : "applied";
31857
32237
  const reviewedProposal = markProposalReviewed(proposal, decision, proposalStatus, appliedAt, {
31858
32238
  memoryId,
31859
32239
  targetMemoryId,
31860
32240
  oldMemoryId,
31861
- replacementMemoryId
32241
+ replacementMemoryId,
32242
+ relatedMemoryIds: decision.action === "merge" ? decision.relatedMemoryIds : undefined
31862
32243
  });
31863
32244
  const change = {
31864
32245
  action: decision.action,
@@ -31869,6 +32250,7 @@ class SQLiteMemoryProvider {
31869
32250
  targetMemoryId,
31870
32251
  oldMemoryId,
31871
32252
  replacementMemoryId,
32253
+ relatedMemoryIds: decision.action === "merge" ? decision.relatedMemoryIds : undefined,
31872
32254
  reason: curatorDecisionReason(decision)
31873
32255
  };
31874
32256
  return {
@@ -31883,15 +32265,15 @@ class SQLiteMemoryProvider {
31883
32265
  if (!row) {
31884
32266
  throw new MemoryValidationError("memory proposal was not found");
31885
32267
  }
31886
- const proposal = validateMemoryProposal(JSON.parse(row.proposal_json));
32268
+ let proposal;
32269
+ try {
32270
+ proposal = parseLoadedProposal(JSON.parse(row.proposal_json), this.config.redaction.rejectDurableSecrets);
32271
+ } catch (error2) {
32272
+ throw asStoredProposalValidationError(row.id, error2);
32273
+ }
31887
32274
  if (proposal.status !== "pending") {
31888
32275
  throw new MemoryValidationError("memory proposal is not pending");
31889
32276
  }
31890
- if (proposal.proposedRecord) {
31891
- validateMemoryRecordRules(proposal.proposedRecord, {
31892
- rejectDurableSecrets: this.config.redaction.rejectDurableSecrets
31893
- });
31894
- }
31895
32277
  return proposal;
31896
32278
  }
31897
32279
  readActiveMemory(memoryId) {
@@ -31952,7 +32334,7 @@ class SQLiteMemoryProvider {
31952
32334
  for (const sourceRow of payload.memoryRows) {
31953
32335
  const rawRecord = sourceRow.record;
31954
32336
  const record = (rawRecord.outcomes?.length ?? 0) > 0 ? ensureOutcomeGeneration(rawRecord) : rawRecord;
31955
- this.writeMemory(stripMaterializedOutcomes(record));
32337
+ this.writeMemory(stripDerivedRelations(stripMaterializedOutcomes(record)));
31956
32338
  if (typeof record.metadata.outcomeGeneration === "string") {
31957
32339
  try {
31958
32340
  materializedRows.push({
@@ -37584,7 +37966,7 @@ async function runFinalizeStage(ctx) {
37584
37966
  }
37585
37967
  }
37586
37968
  try {
37587
- const { CuratorConfigSchema: CCS } = await import("./schema-72vpr9xy.js");
37969
+ const { CuratorConfigSchema: CCS } = await import("./schema-9ebqj7mv.js");
37588
37970
  const { config: pmLoadedConfig } = _internals41.loadPluginConfigWithMeta(ctx.directory);
37589
37971
  const curatorCfg = CCS.parse(pmLoadedConfig.curator ?? {});
37590
37972
  if (curatorCfg.enabled && curatorCfg.postmortem_enabled) {
@@ -39808,9 +40190,9 @@ var _internals45 = {
39808
40190
  loadPluginConfigWithMeta,
39809
40191
  loadCuratorDeps: async () => {
39810
40192
  const [{ CuratorConfigSchema }, curator, { createCuratorLLMDelegate: createCuratorLLMDelegate2 }] = await Promise.all([
39811
- import("./schema-72vpr9xy.js"),
39812
- import("./curator-1rzb285s.js"),
39813
- import("./curator-llm-factory-bqfkaq6y.js")
40193
+ import("./schema-9ebqj7mv.js"),
40194
+ import("./curator-p0dwpn2x.js"),
40195
+ import("./curator-llm-factory-g65xmh8f.js")
39814
40196
  ]);
39815
40197
  return { CuratorConfigSchema, curator, createCuratorLLMDelegate: createCuratorLLMDelegate2 };
39816
40198
  }
@@ -40819,7 +41201,7 @@ async function computeCurationDiagnostics(directory, entries) {
40819
41201
  let scanCompleted = false;
40820
41202
  let scanRemaining = 0;
40821
41203
  try {
40822
- const { getScanStatus } = await import("./scan-cursor-5rmaqw2t.js");
41204
+ const { getScanStatus } = await import("./scan-cursor-wjad4yd7.js");
40823
41205
  const status = await getScanStatus(directory);
40824
41206
  scanGeneration = status.generation;
40825
41207
  scanCompleted = status.completed;
@@ -40827,19 +41209,19 @@ async function computeCurationDiagnostics(directory, entries) {
40827
41209
  } catch {}
40828
41210
  let configMatch = null;
40829
41211
  try {
40830
- const { isLinked: isLinked2 } = await import("./knowledge-link-8knefv8x.js");
41212
+ const { isLinked: isLinked2 } = await import("./knowledge-link-0byjmj0w.js");
40831
41213
  if (isLinked2(directory)) {
40832
- const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-72vpr9xy.js");
41214
+ const { KnowledgeConfigSchema: KnowledgeConfigSchema2 } = await import("./schema-9ebqj7mv.js");
40833
41215
  let config;
40834
41216
  try {
40835
- const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-3cxfqdpv.js");
41217
+ const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await import("./index-1wapt173.js");
40836
41218
  const loaded = loadPluginConfigWithMeta2(directory);
40837
41219
  config = KnowledgeConfigSchema2.parse(loaded.config.knowledge ?? {});
40838
41220
  } catch {
40839
41221
  config = KnowledgeConfigSchema2.parse({});
40840
41222
  }
40841
41223
  const { cohortConfigFingerprint: cohortConfigFingerprint2 } = await import("./config-fingerprint-v22xh5a2.js");
40842
- const { buildConfigFingerprintInput: buildConfigFingerprintInput2, readCohortConfigFingerprint } = await import("./curation-policy-ej9xc0cd.js");
41224
+ const { buildConfigFingerprintInput: buildConfigFingerprintInput2, readCohortConfigFingerprint } = await import("./curation-policy-ayq5kmnf.js");
40843
41225
  const currentFp = cohortConfigFingerprint2(buildConfigFingerprintInput2(config));
40844
41226
  const cohortFp = await readCohortConfigFingerprint(directory);
40845
41227
  configMatch = cohortFp === null ? null : currentFp === cohortFp;
@@ -42180,7 +42562,7 @@ async function handleDoctorCommand(directory, args) {
42180
42562
  const result = runConfigDoctor(config, directory);
42181
42563
  let output;
42182
42564
  if (enableAutoFix && result.hasAutoFixableIssues) {
42183
- const { runConfigDoctorWithFixes } = await import("./config-doctor-b1w7yvcs.js");
42565
+ const { runConfigDoctorWithFixes } = await import("./config-doctor-636h188h.js");
42184
42566
  const fixResult = await runConfigDoctorWithFixes(directory, config, true, {
42185
42567
  applyLossy: true
42186
42568
  });
@@ -42218,7 +42600,7 @@ async function handleDoctorCommand(directory, args) {
42218
42600
  `;
42219
42601
  }
42220
42602
  try {
42221
- const { runModelPreflight } = await import("./model-preflight-yqqchzjn.js");
42603
+ const { runModelPreflight } = await import("./model-preflight-c3mc8njg.js");
42222
42604
  const preflight = await runModelPreflight(config, swarmState.opencodeClient);
42223
42605
  if (preflight.catalogAvailable) {
42224
42606
  const unresolved = preflight.resolutions.filter((resolution) => resolution.status === "unresolved");
@@ -43120,7 +43502,7 @@ async function handleEvidenceCommand(directory, args) {
43120
43502
  return formatTaskEvidenceMarkdown(evidenceData);
43121
43503
  }
43122
43504
  async function handleEvidenceSummaryCommand(directory) {
43123
- const { buildEvidenceSummary } = await import("./evidence-summary-service-ma8drpv5.js");
43505
+ const { buildEvidenceSummary } = await import("./evidence-summary-service-hvbqyb4g.js");
43124
43506
  const artifact = await buildEvidenceSummary(directory);
43125
43507
  if (!artifact) {
43126
43508
  return "No plan found. Run `/swarm plan` to check plan status.";
@@ -63031,7 +63413,7 @@ async function mergeStagedSqlite(destStoragePath, stagedPath) {
63031
63413
  return { merged: await countRowsSafe(destDbPath), skipped: 0 };
63032
63414
  }
63033
63415
  try {
63034
- const { loadDatabaseCtor: loadDatabaseCtor2 } = await import("./sqlite-loader-r1kgt2pq.js");
63416
+ const { loadDatabaseCtor: loadDatabaseCtor2 } = await import("./sqlite-loader-c92413n7.js");
63035
63417
  const Db = loadDatabaseCtor2();
63036
63418
  const db = new Db(destDbPath);
63037
63419
  let attached = false;
@@ -63128,7 +63510,7 @@ async function mergeStagedSqlite(destStoragePath, stagedPath) {
63128
63510
  }
63129
63511
  async function countRowsSafe(dbPath) {
63130
63512
  try {
63131
- const { loadDatabaseCtor: loadDatabaseCtor2 } = await import("./sqlite-loader-r1kgt2pq.js");
63513
+ const { loadDatabaseCtor: loadDatabaseCtor2 } = await import("./sqlite-loader-c92413n7.js");
63132
63514
  const Db = loadDatabaseCtor2();
63133
63515
  const db = new Db(dbPath);
63134
63516
  try {
@@ -78479,7 +78861,7 @@ async function runValidationWithTransientRetry(input, candidateContent, baseline
78479
78861
  if (!input.dispatcher) {
78480
78862
  throw new Error("no evaluation dispatcher available (cannot run validation)");
78481
78863
  }
78482
- const { createModelEvaluationExecutor: createModelEvaluationExecutor2 } = await import("./runner-fzgkd6m1.js");
78864
+ const { createModelEvaluationExecutor: createModelEvaluationExecutor2 } = await import("./runner-rddddxmq.js");
78483
78865
  const executor = createModelEvaluationExecutor2(input.dispatcher, input.sessionId);
78484
78866
  const result = await withProtectedSetIntegrity([evalInputRoot, ...protectedRoots(input.directory)], () => _internals98.evaluateCandidateV1({
78485
78867
  projectRoot: input.directory,
@@ -80604,7 +80986,7 @@ function buildDetailedHelp(commandName, entry) {
80604
80986
  async function handleHelpCommand(ctx) {
80605
80987
  const targetCommand = ctx.args.join(" ");
80606
80988
  if (!targetCommand) {
80607
- const { buildHelpText } = await import("./index-52f67bbh.js");
80989
+ const { buildHelpText } = await import("./index-25xvw7hq.js");
80608
80990
  return buildHelpText();
80609
80991
  }
80610
80992
  const tokens = targetCommand.split(/\s+/);
@@ -80613,7 +80995,7 @@ async function handleHelpCommand(ctx) {
80613
80995
  return _internals101.buildDetailedHelp(resolved.key, resolved.entry);
80614
80996
  }
80615
80997
  const similar = _internals101.findSimilarCommands(targetCommand);
80616
- const { buildHelpText: fullHelp } = await import("./index-52f67bbh.js");
80998
+ const { buildHelpText: fullHelp } = await import("./index-25xvw7hq.js");
80617
80999
  if (similar.length > 0) {
80618
81000
  return `Command '/swarm ${targetCommand}' not found.
80619
81001
 
@@ -80944,7 +81326,7 @@ var COMMAND_REGISTRY = {
80944
81326
  },
80945
81327
  "guardrail explain": {
80946
81328
  handler: async (ctx) => {
80947
- const { handleGuardrailExplain } = await import("./guardrail-explain-em2mqz9a.js");
81329
+ const { handleGuardrailExplain } = await import("./guardrail-explain-s0dzn8c6.js");
80948
81330
  return handleGuardrailExplain(ctx.directory, ctx.args);
80949
81331
  },
80950
81332
  description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
@@ -80954,7 +81336,7 @@ var COMMAND_REGISTRY = {
80954
81336
  },
80955
81337
  "guardrail reset": {
80956
81338
  handler: async (ctx) => {
80957
- const { handleGuardrailReset } = await import("./guardrail-reset-091xw53a.js");
81339
+ const { handleGuardrailReset } = await import("./guardrail-reset-cxkf5h0x.js");
80958
81340
  return handleGuardrailReset(ctx.args, ctx.sessionID);
80959
81341
  },
80960
81342
  description: "Reset one exact active invocation/action circuit after repair",
@@ -80963,7 +81345,7 @@ var COMMAND_REGISTRY = {
80963
81345
  },
80964
81346
  "guardrail-explain": {
80965
81347
  handler: async (ctx) => {
80966
- const { handleGuardrailExplain } = await import("./guardrail-explain-em2mqz9a.js");
81348
+ const { handleGuardrailExplain } = await import("./guardrail-explain-s0dzn8c6.js");
80967
81349
  return handleGuardrailExplain(ctx.directory, ctx.args);
80968
81350
  },
80969
81351
  description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
@@ -80973,7 +81355,7 @@ var COMMAND_REGISTRY = {
80973
81355
  },
80974
81356
  "guardrail-reset": {
80975
81357
  handler: async (ctx) => {
80976
- const { handleGuardrailReset } = await import("./guardrail-reset-091xw53a.js");
81358
+ const { handleGuardrailReset } = await import("./guardrail-reset-cxkf5h0x.js");
80977
81359
  return handleGuardrailReset(ctx.args, ctx.sessionID);
80978
81360
  },
80979
81361
  description: "Reset one exact active invocation/action circuit after repair",
@@ -80983,7 +81365,7 @@ var COMMAND_REGISTRY = {
80983
81365
  },
80984
81366
  "guardrail-log": {
80985
81367
  handler: async (ctx) => {
80986
- const { handleGuardrailLog } = await import("./guardrail-log-845tfrwb.js");
81368
+ const { handleGuardrailLog } = await import("./guardrail-log-qc7rfhv2.js");
80987
81369
  return handleGuardrailLog(ctx.directory, ctx.args);
80988
81370
  },
80989
81371
  description: "Read the guardrail decision log (use --blocks-only for blocks)",
@@ -82305,7 +82687,7 @@ CLASSIFICATION RULES:
82305
82687
  - Misclassification = GATE_DELEGATION_BYPASS.
82306
82688
 
82307
82689
  \u2500\u2500 STAGE A: AUTOMATED TOOL GATES \u2500\u2500
82308
- diff \u2192 syntax_check \u2192 placeholder_scan \u2192 imports \u2192 lint fix \u2192 build_check \u2192 pre_check_batch
82690
+ diff \u2192 syntax_check \u2192 placeholder_scan (diff-scoped) \u2192 imports \u2192 lint fix \u2192 build_check \u2192 pre_check_batch
82309
82691
  Stage A tools return pass/fail. Fix failures by returning to coder.
82310
82692
  Stage A passing means: code compiles, parses, no secrets, no placeholders, no lint errors.
82311
82693
  Stage A passing does NOT mean: code is correct, secure, tested, or reviewed.
@@ -86979,7 +87361,7 @@ function getDisplayFinalPromptPressure() {
86979
87361
  async function rehydratePrSubscriptions(sessionID, directory) {
86980
87362
  const map = new Map;
86981
87363
  try {
86982
- const { listActive: listActive2 } = await import("./pr-subscriptions-3zwthnan.js");
87364
+ const { listActive: listActive2 } = await import("./pr-subscriptions-4e64sbwg.js");
86983
87365
  const records = await listActive2(directory);
86984
87366
  for (const record of records) {
86985
87367
  if (record.sessionID !== sessionID)
@@ -87425,7 +87807,7 @@ function isLaneOwnedByCurrentSession(branchName, expectedSessionId) {
87425
87807
  return extracted === expectedSessionId;
87426
87808
  }
87427
87809
  async function inspectStandardWorktreeCollisionOwnership(identity) {
87428
- const collisionOwnership = await import("./worktree-collision-ownership-ybhktnq4.js");
87810
+ const collisionOwnership = await import("./worktree-collision-ownership-g5n5xbqy.js");
87429
87811
  return collisionOwnership.inspectStandardWorktreeCollisionOwnership(identity);
87430
87812
  }
87431
87813
  async function runRecoveryGit(directory, args, timeoutMs = 15000) {
@@ -87834,7 +88216,7 @@ async function precreateStandardWorktreeSession(args) {
87834
88216
  const laneProfile = computeLaneRuntimeProfile(worktreeConfig.runtime_isolation, laneIndex, handle.worktreePath);
87835
88217
  if (laneProfile) {
87836
88218
  try {
87837
- const { writeLaneProfileToDiskReal } = await import("./core-whesnhpf.js");
88219
+ const { writeLaneProfileToDiskReal } = await import("./core-h3hsczyq.js");
87838
88220
  await writeLaneProfileToDiskReal(handle.worktreePath, laneProfile.laneIndex, laneProfile.envOverrides);
87839
88221
  } catch {}
87840
88222
  }
@@ -88759,7 +89141,7 @@ async function finishStandardWorktreeDispatch(directory, dispatch, config, callI
88759
89141
  }
88760
89142
  clearWorktreeMergeStatus(statusKey);
88761
89143
  try {
88762
- const { removeLaneProfileFromDiskReal } = await import("./core-whesnhpf.js");
89144
+ const { removeLaneProfileFromDiskReal } = await import("./core-h3hsczyq.js");
88763
89145
  await removeLaneProfileFromDiskReal(dispatch.handle.worktreePath, dispatch.laneIndex);
88764
89146
  } catch {}
88765
89147
  const state = serializationStateBySessionID.get(dispatch.parentSessionID);