@equationalapplications/core-llm-wiki 7.3.0 → 7.5.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.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { __privateAdd, MetadataRepository, EmbeddingService, SearchService, JobManager, PromptService, IngestionService, MaintenanceService, ImportExportService, RetrievalService, WriteService, __privateGet, __privateSet, normalizeSourceRef, normalizeSourceHash, entitySummaryMetaKey, WikiSourceRefHashCollision, DiagnosticBuffer, validateManifest, generateId, BaseRepository, WikiGraphNodeOwnershipConflict, emptyManifest, resolveNodeType, WikiStrictOntologyViolation, validateInlineEdges, resolveEdgeDefinitions, typeSatisfies, normalizeTitleKey, WikiTransactionError, extractSqliteCode } from './chunk-IAYO63DQ.mjs';
2
- export { DEFAULT_CHUNK_OVERLAP, DEFAULT_MAX_CHUNK_LENGTH, DEFAULT_MAX_EMBED_CHARS, EMBED_CHARS_CEILING, HEAL_ANCHORS_PER_CANDIDATE, HEAL_BATCH_SIZE, HEAL_MAX_FACT_BODY_CHARS_L3, HEAL_MAX_TASKS, HEAL_RECHECK_MS, HOOK_TIMEOUT_MARKER, ONTOLOGY_BACKFILL_BATCH_SIZE, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, ONTOLOGY_BACKFILL_RECHECK_MS, ONTOLOGY_BACKFILL_SYSTEM_PROMPT, PromptService, PrunePartialFailureError, WikiBusyError, WikiDuplicateHashError, WikiGraphNodeOwnershipConflict, WikiIngestEmptyError, WikiInvalidReadOptions, WikiParseError, WikiSourceRefHashCollision, WikiStrictOntologyViolation, WikiTransactionError, chunkText, configureRandomSource, parseEmbedding, safeSlice, validateManifest } from './chunk-IAYO63DQ.mjs';
1
+ import { __privateAdd, MetadataRepository, EmbeddingService, SearchService, JobManager, PromptService, IngestionService, MaintenanceService, ImportExportService, RetrievalService, WriteService, __privateGet, __privateSet, normalizeSourceRef, normalizeSourceHash, entitySummaryMetaKey, WikiSourceRefHashCollision, DiagnosticBuffer, validateManifest, WikiDraftNotFound, generateId, BaseRepository, WikiGraphNodeOwnershipConflict, emptyManifest, resolveNodeType, WikiStrictOntologyViolation, validateInlineEdges, resolveEdgeDefinitions, typeSatisfies, normalizeTitleKey, WikiTransactionError, extractSqliteCode } from './chunk-3P7FAKJA.mjs';
2
+ export { DEFAULT_CHUNK_OVERLAP, DEFAULT_MAX_CHUNK_LENGTH, DEFAULT_MAX_EMBED_CHARS, EMBED_CHARS_CEILING, HEAL_ANCHORS_PER_CANDIDATE, HEAL_BATCH_SIZE, HEAL_MAX_FACT_BODY_CHARS_L3, HEAL_MAX_TASKS, HEAL_RECHECK_MS, HOOK_TIMEOUT_MARKER, ONTOLOGY_BACKFILL_BATCH_SIZE, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, ONTOLOGY_BACKFILL_RECHECK_MS, ONTOLOGY_BACKFILL_SYSTEM_PROMPT, PromptService, PrunePartialFailureError, WikiBusyError, WikiDraftNotFound, WikiDuplicateHashError, WikiGraphNodeOwnershipConflict, WikiIngestEmptyError, WikiInvalidReadOptions, WikiParseError, WikiSourceRefHashCollision, WikiStrictOntologyViolation, WikiTransactionError, chunkText, configureRandomSource, parseEmbedding, safeSlice, validateManifest } from './chunk-3P7FAKJA.mjs';
3
3
  import { appendRelatedSection, buildConceptDocument, buildLogMd, buildEntityIndexMd, buildRootIndexMd, isAllowedOkfPath, parseRootIndexMd, parseEntityIndexMd, parseConcept, splitRelatedSection, extractMarkdownLinks, parseLogMd, parseEventIdComment, latestVerified, formatSourcesJson, appendEventIdComment, parseVerifiedFlexible, parseCitationsList, deriveTrustTier, isStaleAfter } from '@equationalapplications/core-okf';
4
4
 
5
5
  // src/db/schema.ts
@@ -1569,16 +1569,52 @@ var EntryRepository = class extends BaseRepository {
1569
1569
  `UPDATE ${this.prefix}entries SET source_type = 'librarian_inferred' WHERE source_type = 'agent_inferred';`
1570
1570
  ].join("\n");
1571
1571
  }
1572
- async findRecentByEntityIds(entityIds, limit, tx) {
1572
+ async findRecentByEntityIds(entityIds, limit, tx, opts) {
1573
1573
  if (entityIds.length === 0) return [];
1574
1574
  const executor = this.getExecutor(tx);
1575
1575
  const placeholders = entityIds.map(() => "?").join(",");
1576
+ const draftClause = opts?.excludeDrafts === true ? ` AND lifecycle_status != 'draft'` : "";
1576
1577
  const rows = await executor.getAllAsync(
1577
- `SELECT * FROM ${this.prefix}entries WHERE entity_id IN (${placeholders}) AND deleted_at IS NULL ORDER BY updated_at DESC LIMIT ?`,
1578
+ `SELECT * FROM ${this.prefix}entries WHERE entity_id IN (${placeholders}) AND deleted_at IS NULL${draftClause} ORDER BY updated_at DESC LIMIT ?`,
1578
1579
  [...entityIds, limit]
1579
1580
  );
1580
1581
  return rows.map(mapRowToFact);
1581
1582
  }
1583
+ /** IDs of live draft facts for the given entities (spec §5.1). Callers pass ≤ 100 entity ids. */
1584
+ async findDraftIdsByEntityIds(entityIds, tx) {
1585
+ if (entityIds.length === 0) return /* @__PURE__ */ new Set();
1586
+ const executor = this.getExecutor(tx);
1587
+ const placeholders = entityIds.map(() => "?").join(",");
1588
+ const rows = await executor.getAllAsync(
1589
+ `SELECT id FROM ${this.prefix}entries
1590
+ WHERE entity_id IN (${placeholders}) AND deleted_at IS NULL AND lifecycle_status = 'draft'`,
1591
+ [...entityIds]
1592
+ );
1593
+ return new Set(rows.map((r) => r.id));
1594
+ }
1595
+ /** Live drafts for one entity, newest first, keyset-paged by (created_at, id). */
1596
+ async listDraftsByEntityId(entityId, limit, after, tx) {
1597
+ const executor = this.getExecutor(tx);
1598
+ const afterClause = after ? ` AND (created_at < ? OR (created_at = ? AND id < ?))` : "";
1599
+ const args = after ? [entityId, after.createdAt, after.createdAt, after.id, limit] : [entityId, limit];
1600
+ const rows = await executor.getAllAsync(
1601
+ `SELECT * FROM ${this.prefix}entries
1602
+ WHERE entity_id = ? AND deleted_at IS NULL AND lifecycle_status = 'draft'${afterClause}
1603
+ ORDER BY created_at DESC, id DESC LIMIT ?`,
1604
+ args
1605
+ );
1606
+ return rows.map(mapRowToFact);
1607
+ }
1608
+ /** True iff `entryId` is a live draft owned by `entityId`. */
1609
+ async isLiveDraft(entryId, entityId, tx) {
1610
+ const executor = this.getExecutor(tx);
1611
+ const row = await executor.getFirstAsync(
1612
+ `SELECT id FROM ${this.prefix}entries
1613
+ WHERE id = ? AND entity_id = ? AND deleted_at IS NULL AND lifecycle_status = 'draft'`,
1614
+ [entryId, entityId]
1615
+ );
1616
+ return row != null;
1617
+ }
1582
1618
  /**
1583
1619
  * Live untyped facts eligible for ontology backfill, oldest first.
1584
1620
  * Skips facts checked within the recheck cooldown (ontology_checked_at > recheckCutoff).
@@ -2365,6 +2401,7 @@ var EdgeRepository = class extends BaseRepository {
2365
2401
  END
2366
2402
  ) >= ?
2367
2403
  AND n.source_type NOT IN (${excludeSourceTypesPlaceholders})
2404
+ AND (? = 0 OR n.lifecycle_status != 'draft')
2368
2405
  WHERE w.depth < ?
2369
2406
  AND instr(w.visited, ',' || (CASE WHEN e.source_id = w.node_id THEN e.target_id ELSE e.source_id END) || ',') = 0
2370
2407
  )
@@ -2384,6 +2421,7 @@ var EdgeRepository = class extends BaseRepository {
2384
2421
  entityId,
2385
2422
  minConfidenceRank,
2386
2423
  ...opts.excludeSourceTypes,
2424
+ opts.excludeDrafts === true ? 1 : 0,
2387
2425
  opts.maxDepth,
2388
2426
  opts.maxNodes
2389
2427
  ];
@@ -2603,6 +2641,7 @@ var GraphTraversalService = class {
2603
2641
  edgeTypes: options.edgeTypes,
2604
2642
  minConfidence: options.minTraversalConfidence ?? this.config.minTraversalConfidence ?? "tentative",
2605
2643
  excludeSourceTypes: options.excludeSourceTypes ?? this.config.excludeSourceTypes ?? [],
2644
+ excludeDrafts: options.excludeDrafts ?? this.config.excludeDrafts ?? false,
2606
2645
  maxNodes
2607
2646
  };
2608
2647
  const { nodeIds, edges } = await this.edgeRepo.getNeighborhood(entityId, options.sourceId, opts);
@@ -2776,6 +2815,15 @@ var OkfTrustWritesRepository = class {
2776
2815
 
2777
2816
  // src/WikiMemory.ts
2778
2817
  var TABLE_PREFIX_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,30}_$/;
2818
+ function decodeDraftCursor(cursor) {
2819
+ const sep = typeof cursor === "string" ? cursor.indexOf(":") : -1;
2820
+ const createdAt = sep > 0 ? Number(cursor.slice(0, sep)) : Number.NaN;
2821
+ const id = sep > 0 ? cursor.slice(sep + 1) : "";
2822
+ if (!Number.isSafeInteger(createdAt) || id.length === 0) {
2823
+ throw new TypeError("Invalid listDrafts cursor.");
2824
+ }
2825
+ return { createdAt, id };
2826
+ }
2779
2827
  var _testAccessNonTestEnvWarned;
2780
2828
  var WikiMemory = class {
2781
2829
  constructor(db, options) {
@@ -3320,6 +3368,43 @@ var WikiMemory = class {
3320
3368
  async setLifecycleStatus(entryId, entityId, status) {
3321
3369
  return this.okfTrustWrites.setLifecycleStatus(entryId, entityId, status);
3322
3370
  }
3371
+ /**
3372
+ * Live draft facts for one entity, newest first (spec §5.2). Default page
3373
+ * size 50, clamped to [1, 500]. Pass `nextCursor` back unchanged for the next page.
3374
+ */
3375
+ async listDrafts(entityId, options) {
3376
+ const rawLimit = options?.limit;
3377
+ const limit = typeof rawLimit === "number" && Number.isFinite(rawLimit) ? Math.min(500, Math.max(1, Math.floor(rawLimit))) : 50;
3378
+ const after = options?.cursor === void 0 ? null : decodeDraftCursor(options.cursor);
3379
+ const rows = await this.entryRepo.listDraftsByEntityId(entityId, limit + 1, after);
3380
+ const facts = rows.slice(0, limit);
3381
+ const last = facts[facts.length - 1];
3382
+ return {
3383
+ facts,
3384
+ nextCursor: rows.length > limit && last ? `${last.created_at}:${last.id}` : null
3385
+ };
3386
+ }
3387
+ /**
3388
+ * Promote a draft to `stable` and record who reviewed it, atomically
3389
+ * (spec §5.2). Metadata writes only: `updated_at` is not bumped and no
3390
+ * outbox event is pushed. Pass `by: 'human:<id>'` so `trustTier` becomes
3391
+ * `'human-reviewed'`.
3392
+ *
3393
+ * @throws WikiDraftNotFound when no live draft with that id exists for the entity.
3394
+ */
3395
+ async promoteDraft(entryId, entityId, reviewer) {
3396
+ const by = reviewer?.by;
3397
+ if (typeof by !== "string" || by.trim().length === 0) {
3398
+ throw new TypeError("promoteDraft requires reviewer.by to be a non-empty string.");
3399
+ }
3400
+ await this.db.withTransactionAsync(async (tx) => {
3401
+ if (!await this.entryRepo.isLiveDraft(entryId, entityId, tx)) {
3402
+ throw new WikiDraftNotFound();
3403
+ }
3404
+ await this.okfTrustWrites.setLifecycleStatus(entryId, entityId, "stable", tx);
3405
+ await this.okfTrustWrites.writeOkfTrust(entryId, entityId, [{ by, at: (/* @__PURE__ */ new Date()).toISOString() }], tx);
3406
+ });
3407
+ }
3323
3408
  /** Set a fact's stale_after (epoch ms) or clear it. Does NOT touch `updated_at`. */
3324
3409
  async setStaleAfter(entryId, entityId, date) {
3325
3410
  return this.okfTrustWrites.setStaleAfter(entryId, entityId, date);