@equationalapplications/core-llm-wiki 7.3.0 → 7.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-ht1qOvcD.mjs';
2
- export { C as ChunkFailure, D as DegradedRecord, E as EmbedFactResult, d as EmbedFailureKind, e as EmbeddingMarkerKind, f as EntityStatus, g as ExtractedFact, h as ExtractedFactEdge, i as ExtractedFactWithOntology, j as ExtractedTask, k as GraphTraversalOptions, H as HEAL_BATCH_SIZE, l as HEAL_RECHECK_MS, m as HOOK_TIMEOUT_MARKER, n as HealResult, I as IngestDocumentResult, L as LLMProvider, O as ONTOLOGY_BACKFILL_BATCH_SIZE, o as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, p as ONTOLOGY_BACKFILL_RECHECK_MS, q as OntologyBackfillResult, r as OntologyConfig, s as OntologyEdgeType, t as OntologyManifest, u as OntologyMode, v as OntologyNodeType, w as OntologyPromptContext, x as OntologyUpdates, P as PromptOverrides, y as PromptService, z as PrunePartialFailureError, A as ReembedResult, V as VectorRanker, B as VectorRankerFallback, J as VectorRankerRankArgs, K as VectorRankerSemanticResult, N as WikiBusyError, Q as WikiBusyOperation, T as WikiCheckpoint, U as WikiConfig, X as WikiDiagnostic, Y as WikiDiagnosticCode, Z as WikiDiagnosticDetail, _ as WikiDiagnosticOperation, $ as WikiDiagnosticSeverity, a0 as WikiDiagnosticTrigger, a1 as WikiDuplicateHashError, a2 as WikiEdge, a3 as WikiEvent, a4 as WikiFact, a5 as WikiGraphNodeOwnershipConflict, a6 as WikiIngestEmptyError, a7 as WikiInvalidReadOptions, a8 as WikiMemoryTestAccess, a9 as WikiOutboxEvent, aa as WikiParseError, ab as WikiSourceRefHashCollision, ac as WikiStrictOntologyViolation, ad as WikiTask, ae as WikiTransactionError, af as validateManifest } from './testing-ht1qOvcD.mjs';
1
+ import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-Dmh1kfkd.mjs';
2
+ export { C as ChunkFailure, D as DegradedRecord, d as DraftPage, E as EmbedFactResult, e as EmbedFailureKind, f as EmbeddingMarkerKind, g as EntityStatus, h as ExtractedFact, i as ExtractedFactEdge, j as ExtractedFactWithOntology, k as ExtractedTask, l as GraphTraversalOptions, H as HEAL_BATCH_SIZE, m as HEAL_RECHECK_MS, n as HOOK_TIMEOUT_MARKER, o as HealResult, I as IngestDocumentResult, L as LLMProvider, O as ONTOLOGY_BACKFILL_BATCH_SIZE, p as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, q as ONTOLOGY_BACKFILL_RECHECK_MS, r as OntologyBackfillResult, s as OntologyConfig, t as OntologyEdgeType, u as OntologyManifest, v as OntologyMode, w as OntologyNodeType, x as OntologyPromptContext, y as OntologyUpdates, P as PromptOverrides, z as PromptService, A as PrunePartialFailureError, B as ReembedResult, V as VectorRanker, J as VectorRankerFallback, K as VectorRankerRankArgs, N as VectorRankerSemanticResult, Q as WikiBusyError, T as WikiBusyOperation, U as WikiCheckpoint, X as WikiConfig, Y as WikiDiagnostic, Z as WikiDiagnosticCode, _ as WikiDiagnosticDetail, $ as WikiDiagnosticOperation, a0 as WikiDiagnosticSeverity, a1 as WikiDiagnosticTrigger, a2 as WikiDraftNotFound, a3 as WikiDuplicateHashError, a4 as WikiEdge, a5 as WikiEvent, a6 as WikiFact, a7 as WikiGraphNodeOwnershipConflict, a8 as WikiIngestEmptyError, a9 as WikiInvalidReadOptions, aa as WikiMemoryTestAccess, ab as WikiOutboxEvent, ac as WikiParseError, ad as WikiSourceRefHashCollision, ae as WikiStrictOntologyViolation, af as WikiTask, ag as WikiTransactionError, ah as validateManifest } from './testing-Dmh1kfkd.mjs';
3
3
  import { OkfFile } from '@equationalapplications/core-okf';
4
4
  import 'minisearch';
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-ht1qOvcD.js';
2
- export { C as ChunkFailure, D as DegradedRecord, E as EmbedFactResult, d as EmbedFailureKind, e as EmbeddingMarkerKind, f as EntityStatus, g as ExtractedFact, h as ExtractedFactEdge, i as ExtractedFactWithOntology, j as ExtractedTask, k as GraphTraversalOptions, H as HEAL_BATCH_SIZE, l as HEAL_RECHECK_MS, m as HOOK_TIMEOUT_MARKER, n as HealResult, I as IngestDocumentResult, L as LLMProvider, O as ONTOLOGY_BACKFILL_BATCH_SIZE, o as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, p as ONTOLOGY_BACKFILL_RECHECK_MS, q as OntologyBackfillResult, r as OntologyConfig, s as OntologyEdgeType, t as OntologyManifest, u as OntologyMode, v as OntologyNodeType, w as OntologyPromptContext, x as OntologyUpdates, P as PromptOverrides, y as PromptService, z as PrunePartialFailureError, A as ReembedResult, V as VectorRanker, B as VectorRankerFallback, J as VectorRankerRankArgs, K as VectorRankerSemanticResult, N as WikiBusyError, Q as WikiBusyOperation, T as WikiCheckpoint, U as WikiConfig, X as WikiDiagnostic, Y as WikiDiagnosticCode, Z as WikiDiagnosticDetail, _ as WikiDiagnosticOperation, $ as WikiDiagnosticSeverity, a0 as WikiDiagnosticTrigger, a1 as WikiDuplicateHashError, a2 as WikiEdge, a3 as WikiEvent, a4 as WikiFact, a5 as WikiGraphNodeOwnershipConflict, a6 as WikiIngestEmptyError, a7 as WikiInvalidReadOptions, a8 as WikiMemoryTestAccess, a9 as WikiOutboxEvent, aa as WikiParseError, ab as WikiSourceRefHashCollision, ac as WikiStrictOntologyViolation, ad as WikiTask, ae as WikiTransactionError, af as validateManifest } from './testing-ht1qOvcD.js';
1
+ import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-Dmh1kfkd.js';
2
+ export { C as ChunkFailure, D as DegradedRecord, d as DraftPage, E as EmbedFactResult, e as EmbedFailureKind, f as EmbeddingMarkerKind, g as EntityStatus, h as ExtractedFact, i as ExtractedFactEdge, j as ExtractedFactWithOntology, k as ExtractedTask, l as GraphTraversalOptions, H as HEAL_BATCH_SIZE, m as HEAL_RECHECK_MS, n as HOOK_TIMEOUT_MARKER, o as HealResult, I as IngestDocumentResult, L as LLMProvider, O as ONTOLOGY_BACKFILL_BATCH_SIZE, p as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, q as ONTOLOGY_BACKFILL_RECHECK_MS, r as OntologyBackfillResult, s as OntologyConfig, t as OntologyEdgeType, u as OntologyManifest, v as OntologyMode, w as OntologyNodeType, x as OntologyPromptContext, y as OntologyUpdates, P as PromptOverrides, z as PromptService, A as PrunePartialFailureError, B as ReembedResult, V as VectorRanker, J as VectorRankerFallback, K as VectorRankerRankArgs, N as VectorRankerSemanticResult, Q as WikiBusyError, T as WikiBusyOperation, U as WikiCheckpoint, X as WikiConfig, Y as WikiDiagnostic, Z as WikiDiagnosticCode, _ as WikiDiagnosticDetail, $ as WikiDiagnosticOperation, a0 as WikiDiagnosticSeverity, a1 as WikiDiagnosticTrigger, a2 as WikiDraftNotFound, a3 as WikiDuplicateHashError, a4 as WikiEdge, a5 as WikiEvent, a6 as WikiFact, a7 as WikiGraphNodeOwnershipConflict, a8 as WikiIngestEmptyError, a9 as WikiInvalidReadOptions, aa as WikiMemoryTestAccess, ab as WikiOutboxEvent, ac as WikiParseError, ad as WikiSourceRefHashCollision, ae as WikiStrictOntologyViolation, af as WikiTask, ag as WikiTransactionError, ah as validateManifest } from './testing-Dmh1kfkd.js';
3
3
  import { OkfFile } from '@equationalapplications/core-okf';
4
4
  import 'minisearch';
5
5
 
package/dist/index.js CHANGED
@@ -333,6 +333,14 @@ var WikiInvalidReadOptions = class _WikiInvalidReadOptions extends Error {
333
333
  Object.setPrototypeOf(this, _WikiInvalidReadOptions.prototype);
334
334
  }
335
335
  };
336
+ var WikiDraftNotFound = class _WikiDraftNotFound extends Error {
337
+ constructor() {
338
+ super("No draft fact with that id exists for this entity.");
339
+ this.code = "WIKI_DRAFT_NOT_FOUND";
340
+ this.name = "WikiDraftNotFound";
341
+ Object.setPrototypeOf(this, _WikiDraftNotFound.prototype);
342
+ }
343
+ };
336
344
 
337
345
  // src/db/serializedAdapter.ts
338
346
  function isDriverError(err) {
@@ -1757,16 +1765,52 @@ var EntryRepository = class extends BaseRepository {
1757
1765
  `UPDATE ${this.prefix}entries SET source_type = 'librarian_inferred' WHERE source_type = 'agent_inferred';`
1758
1766
  ].join("\n");
1759
1767
  }
1760
- async findRecentByEntityIds(entityIds, limit, tx) {
1768
+ async findRecentByEntityIds(entityIds, limit, tx, opts) {
1761
1769
  if (entityIds.length === 0) return [];
1762
1770
  const executor = this.getExecutor(tx);
1763
1771
  const placeholders = entityIds.map(() => "?").join(",");
1772
+ const draftClause = opts?.excludeDrafts === true ? ` AND lifecycle_status != 'draft'` : "";
1764
1773
  const rows = await executor.getAllAsync(
1765
- `SELECT * FROM ${this.prefix}entries WHERE entity_id IN (${placeholders}) AND deleted_at IS NULL ORDER BY updated_at DESC LIMIT ?`,
1774
+ `SELECT * FROM ${this.prefix}entries WHERE entity_id IN (${placeholders}) AND deleted_at IS NULL${draftClause} ORDER BY updated_at DESC LIMIT ?`,
1766
1775
  [...entityIds, limit]
1767
1776
  );
1768
1777
  return rows.map(mapRowToFact);
1769
1778
  }
1779
+ /** IDs of live draft facts for the given entities (spec §5.1). Callers pass ≤ 100 entity ids. */
1780
+ async findDraftIdsByEntityIds(entityIds, tx) {
1781
+ if (entityIds.length === 0) return /* @__PURE__ */ new Set();
1782
+ const executor = this.getExecutor(tx);
1783
+ const placeholders = entityIds.map(() => "?").join(",");
1784
+ const rows = await executor.getAllAsync(
1785
+ `SELECT id FROM ${this.prefix}entries
1786
+ WHERE entity_id IN (${placeholders}) AND deleted_at IS NULL AND lifecycle_status = 'draft'`,
1787
+ [...entityIds]
1788
+ );
1789
+ return new Set(rows.map((r) => r.id));
1790
+ }
1791
+ /** Live drafts for one entity, newest first, keyset-paged by (created_at, id). */
1792
+ async listDraftsByEntityId(entityId, limit, after, tx) {
1793
+ const executor = this.getExecutor(tx);
1794
+ const afterClause = after ? ` AND (created_at < ? OR (created_at = ? AND id < ?))` : "";
1795
+ const args = after ? [entityId, after.createdAt, after.createdAt, after.id, limit] : [entityId, limit];
1796
+ const rows = await executor.getAllAsync(
1797
+ `SELECT * FROM ${this.prefix}entries
1798
+ WHERE entity_id = ? AND deleted_at IS NULL AND lifecycle_status = 'draft'${afterClause}
1799
+ ORDER BY created_at DESC, id DESC LIMIT ?`,
1800
+ args
1801
+ );
1802
+ return rows.map(mapRowToFact);
1803
+ }
1804
+ /** True iff `entryId` is a live draft owned by `entityId`. */
1805
+ async isLiveDraft(entryId, entityId, tx) {
1806
+ const executor = this.getExecutor(tx);
1807
+ const row = await executor.getFirstAsync(
1808
+ `SELECT id FROM ${this.prefix}entries
1809
+ WHERE id = ? AND entity_id = ? AND deleted_at IS NULL AND lifecycle_status = 'draft'`,
1810
+ [entryId, entityId]
1811
+ );
1812
+ return row != null;
1813
+ }
1770
1814
  /**
1771
1815
  * Live untyped facts eligible for ontology backfill, oldest first.
1772
1816
  * Skips facts checked within the recheck cooldown (ontology_checked_at > recheckCutoff).
@@ -2577,6 +2621,7 @@ var EdgeRepository = class extends BaseRepository {
2577
2621
  END
2578
2622
  ) >= ?
2579
2623
  AND n.source_type NOT IN (${excludeSourceTypesPlaceholders})
2624
+ AND (? = 0 OR n.lifecycle_status != 'draft')
2580
2625
  WHERE w.depth < ?
2581
2626
  AND instr(w.visited, ',' || (CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END) || ',') = 0
2582
2627
  )
@@ -2596,6 +2641,7 @@ var EdgeRepository = class extends BaseRepository {
2596
2641
  entityId,
2597
2642
  minConfidenceRank,
2598
2643
  ...opts.excludeSourceTypes,
2644
+ opts.excludeDrafts === true ? 1 : 0,
2599
2645
  opts.maxDepth,
2600
2646
  opts.maxNodes
2601
2647
  ];
@@ -6969,6 +7015,7 @@ function selectWithFloors(sortedRows, floors, maxResults) {
6969
7015
  }
6970
7016
 
6971
7017
  // src/services/RetrievalService.ts
7018
+ var EMPTY_ID_SET = /* @__PURE__ */ new Set();
6972
7019
  var RetrievalService = class {
6973
7020
  constructor(options, entryRepo, taskRepo, eventRepo, metadataRepo, searchService) {
6974
7021
  this.options = options;
@@ -7001,6 +7048,7 @@ var RetrievalService = class {
7001
7048
  }
7002
7049
  const rawMaxResults = options?.maxResults ?? config?.maxResults ?? config?.maxFtsResults ?? 10;
7003
7050
  const maxResults = Number.isFinite(rawMaxResults) ? Math.max(0, Math.trunc(rawMaxResults)) : 10;
7051
+ const excludeDrafts = (options?.excludeDrafts ?? config?.excludeDrafts ?? false) === true;
7004
7052
  const trimmedQuery = query.trim();
7005
7053
  const sanitizedTierFloors = trimmedQuery && exposeMetadata ? validateTierFloors(
7006
7054
  entityIds,
@@ -7020,6 +7068,9 @@ var RetrievalService = class {
7020
7068
  if (maxResults === 0) ; else if (trimmedQuery) {
7021
7069
  let usedEmbed = false;
7022
7070
  const scoredEntityIds = this._filterScoredEntities(entityIds, sanitizedTierWeights, options?.includeZeroWeightEntities);
7071
+ const draftIds = excludeDrafts && scoredEntityIds.length > 0 ? await this.entryRepo.findDraftIdsByEntityIds(scoredEntityIds) : EMPTY_ID_SET;
7072
+ const draftPad = draftIds.size;
7073
+ const padLimit = (n) => n >= Number.MAX_SAFE_INTEGER ? n : n + draftPad;
7023
7074
  if (scoredEntityIds.length === 0) {
7024
7075
  usedEmbed = true;
7025
7076
  } else if (!skipEmbed && embedFn) {
@@ -7053,7 +7104,7 @@ var RetrievalService = class {
7053
7104
  let miniSearchScores;
7054
7105
  if (effectivePreFilterLimit !== void 0) {
7055
7106
  populateCache = false;
7056
- const preResults = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, Number.MAX_SAFE_INTEGER);
7107
+ const preResults = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, Number.MAX_SAFE_INTEGER).filter((r) => !draftIds.has(r.id));
7057
7108
  if (preResults.length === 0) {
7058
7109
  candidateRows = null;
7059
7110
  } else {
@@ -7075,9 +7126,9 @@ var RetrievalService = class {
7075
7126
  }
7076
7127
  } else {
7077
7128
  if (useRanker) {
7078
- candidateRows = await this.entryRepo.findMetadataByEntityIds(scoredEntityIds);
7129
+ candidateRows = this._withoutDrafts(await this.entryRepo.findMetadataByEntityIds(scoredEntityIds), draftIds);
7079
7130
  } else {
7080
- candidateRows = await this.entryRepo.findWithEmbeddingsByEntityIds(scoredEntityIds);
7131
+ candidateRows = this._withoutDrafts(await this.entryRepo.findWithEmbeddingsByEntityIds(scoredEntityIds), draftIds);
7081
7132
  }
7082
7133
  if (weight !== void 0 && weight < 1) {
7083
7134
  miniSearchScores = this.searchService.getMiniSearchScores(trimmedQuery, scoredEntityIds);
@@ -7107,7 +7158,7 @@ var RetrievalService = class {
7107
7158
  candidateRows: rowsForEntity,
7108
7159
  weight,
7109
7160
  miniSearchScores,
7110
- limit: Math.max(maxResults * 2, maxResults + 50)
7161
+ limit: padLimit(Math.max(maxResults * 2, maxResults + 50))
7111
7162
  });
7112
7163
  return ranked.map((row) => ({ ...row, entity_id: scopedEntityId }));
7113
7164
  })
@@ -7321,7 +7372,7 @@ var RetrievalService = class {
7321
7372
  });
7322
7373
  } else if (policy === "keyword") {
7323
7374
  const hasActiveFloorsKeywordFallback = sanitizedTierFloors !== void 0 && Object.values(sanitizedTierFloors).some((f) => f > 0);
7324
- const keywordOversampledLimit = hasActiveFloorsKeywordFallback ? Number.MAX_SAFE_INTEGER : Math.max(maxResults * 2, maxResults + 50);
7375
+ const keywordOversampledLimit = hasActiveFloorsKeywordFallback ? Number.MAX_SAFE_INTEGER : padLimit(Math.max(maxResults * 2, maxResults + 50));
7325
7376
  const preFilteredIds = effectivePreFilterLimit !== void 0 ? new Set(candidateRows.map((r) => r.id)) : void 0;
7326
7377
  const keywordResults = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, keywordOversampledLimit);
7327
7378
  const topResults = preFilteredIds === void 0 ? keywordResults : keywordResults.filter((r) => preFilteredIds.has(r.id));
@@ -7362,6 +7413,7 @@ var RetrievalService = class {
7362
7413
  // read() re-sorts after applying tier weights
7363
7414
  });
7364
7415
  }
7416
+ if (draftPad > 0) scored = scored.filter((s) => !draftIds.has(s.id));
7365
7417
  if (scored.length > 0) {
7366
7418
  scored = scored.map((row) => ({
7367
7419
  ...row,
@@ -7424,8 +7476,8 @@ var RetrievalService = class {
7424
7476
  }
7425
7477
  if (!usedEmbed && scoredEntityIds.length > 0) {
7426
7478
  const hasActiveFloors = sanitizedTierFloors !== void 0 && Object.values(sanitizedTierFloors).some((f) => f > 0);
7427
- const fallbackOversampledLimit = hasActiveFloors ? Number.MAX_SAFE_INTEGER : Math.max(maxResults * 2, maxResults + 50);
7428
- const results = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, fallbackOversampledLimit);
7479
+ const fallbackOversampledLimit = hasActiveFloors ? Number.MAX_SAFE_INTEGER : padLimit(Math.max(maxResults * 2, maxResults + 50));
7480
+ const results = this.searchService.searchKeyword(trimmedQuery, scoredEntityIds, fallbackOversampledLimit).filter((r) => !draftIds.has(r.id));
7429
7481
  const candidates = results.map((r) => ({
7430
7482
  id: r.id,
7431
7483
  entity_id: r.entity_id,
@@ -7449,7 +7501,7 @@ var RetrievalService = class {
7449
7501
  await this.entryRepo.trackAccess(ids, now);
7450
7502
  }
7451
7503
  } else {
7452
- facts = await this.entryRepo.findRecentByEntityIds(entityIds, maxResults);
7504
+ facts = excludeDrafts ? await this.entryRepo.findRecentByEntityIds(entityIds, maxResults, void 0, { excludeDrafts: true }) : await this.entryRepo.findRecentByEntityIds(entityIds, maxResults);
7453
7505
  }
7454
7506
  const eventsLimit = Math.min(10 * entityIds.length, 100);
7455
7507
  const [tasks, events] = await Promise.all([
@@ -7485,6 +7537,9 @@ var RetrievalService = class {
7485
7537
  _tieBreakSort(items) {
7486
7538
  items.sort((a, b) => this._compareScoredRows(a, b));
7487
7539
  }
7540
+ _withoutDrafts(rows, draftIds) {
7541
+ return draftIds.size === 0 ? rows : rows.filter((row) => !draftIds.has(row.id));
7542
+ }
7488
7543
  /**
7489
7544
  * Comparator for score + deterministic tie-break fields.
7490
7545
  * Negative return means "a ranks ahead of b" for descending score order.
@@ -7881,6 +7936,7 @@ var GraphTraversalService = class {
7881
7936
  edgeTypes: options.edgeTypes,
7882
7937
  minConfidence: options.minTraversalConfidence ?? this.config.minTraversalConfidence ?? "tentative",
7883
7938
  excludeSourceTypes: options.excludeSourceTypes ?? this.config.excludeSourceTypes ?? [],
7939
+ excludeDrafts: options.excludeDrafts ?? this.config.excludeDrafts ?? false,
7884
7940
  maxNodes
7885
7941
  };
7886
7942
  const { nodeIds, edges } = await this.edgeRepo.getNeighborhood(entityId, options.sourceId, opts);
@@ -8054,6 +8110,15 @@ var OkfTrustWritesRepository = class {
8054
8110
 
8055
8111
  // src/WikiMemory.ts
8056
8112
  var TABLE_PREFIX_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,30}_$/;
8113
+ function decodeDraftCursor(cursor) {
8114
+ const sep = typeof cursor === "string" ? cursor.indexOf(":") : -1;
8115
+ const createdAt = sep > 0 ? Number(cursor.slice(0, sep)) : Number.NaN;
8116
+ const id = sep > 0 ? cursor.slice(sep + 1) : "";
8117
+ if (!Number.isSafeInteger(createdAt) || id.length === 0) {
8118
+ throw new TypeError("Invalid listDrafts cursor.");
8119
+ }
8120
+ return { createdAt, id };
8121
+ }
8057
8122
  var _testAccessNonTestEnvWarned;
8058
8123
  var WikiMemory = class {
8059
8124
  constructor(db, options) {
@@ -8598,6 +8663,43 @@ var WikiMemory = class {
8598
8663
  async setLifecycleStatus(entryId, entityId, status) {
8599
8664
  return this.okfTrustWrites.setLifecycleStatus(entryId, entityId, status);
8600
8665
  }
8666
+ /**
8667
+ * Live draft facts for one entity, newest first (spec §5.2). Default page
8668
+ * size 50, clamped to [1, 500]. Pass `nextCursor` back unchanged for the next page.
8669
+ */
8670
+ async listDrafts(entityId, options) {
8671
+ const rawLimit = options?.limit;
8672
+ const limit = typeof rawLimit === "number" && Number.isFinite(rawLimit) ? Math.min(500, Math.max(1, Math.floor(rawLimit))) : 50;
8673
+ const after = options?.cursor === void 0 ? null : decodeDraftCursor(options.cursor);
8674
+ const rows = await this.entryRepo.listDraftsByEntityId(entityId, limit + 1, after);
8675
+ const facts = rows.slice(0, limit);
8676
+ const last = facts[facts.length - 1];
8677
+ return {
8678
+ facts,
8679
+ nextCursor: rows.length > limit && last ? `${last.created_at}:${last.id}` : null
8680
+ };
8681
+ }
8682
+ /**
8683
+ * Promote a draft to `stable` and record who reviewed it, atomically
8684
+ * (spec §5.2). Metadata writes only: `updated_at` is not bumped and no
8685
+ * outbox event is pushed. Pass `by: 'human:<id>'` so `trustTier` becomes
8686
+ * `'human-reviewed'`.
8687
+ *
8688
+ * @throws WikiDraftNotFound when no live draft with that id exists for the entity.
8689
+ */
8690
+ async promoteDraft(entryId, entityId, reviewer) {
8691
+ const by = reviewer?.by;
8692
+ if (typeof by !== "string" || by.trim().length === 0) {
8693
+ throw new TypeError("promoteDraft requires reviewer.by to be a non-empty string.");
8694
+ }
8695
+ await this.db.withTransactionAsync(async (tx) => {
8696
+ if (!await this.entryRepo.isLiveDraft(entryId, entityId, tx)) {
8697
+ throw new WikiDraftNotFound();
8698
+ }
8699
+ await this.okfTrustWrites.setLifecycleStatus(entryId, entityId, "stable", tx);
8700
+ await this.okfTrustWrites.writeOkfTrust(entryId, entityId, [{ by, at: (/* @__PURE__ */ new Date()).toISOString() }], tx);
8701
+ });
8702
+ }
8601
8703
  /** Set a fact's stale_after (epoch ms) or clear it. Does NOT touch `updated_at`. */
8602
8704
  async setStaleAfter(entryId, entityId, date) {
8603
8705
  return this.okfTrustWrites.setStaleAfter(entryId, entityId, date);
@@ -9549,6 +9651,7 @@ exports.ONTOLOGY_BACKFILL_SYSTEM_PROMPT = ONTOLOGY_BACKFILL_SYSTEM_PROMPT;
9549
9651
  exports.PromptService = PromptService;
9550
9652
  exports.PrunePartialFailureError = PrunePartialFailureError;
9551
9653
  exports.WikiBusyError = WikiBusyError;
9654
+ exports.WikiDraftNotFound = WikiDraftNotFound;
9552
9655
  exports.WikiDuplicateHashError = WikiDuplicateHashError;
9553
9656
  exports.WikiGraphNodeOwnershipConflict = WikiGraphNodeOwnershipConflict;
9554
9657
  exports.WikiIngestEmptyError = WikiIngestEmptyError;