signetai 0.165.0 → 0.167.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/mcp-stdio.js CHANGED
@@ -36494,6 +36494,7 @@ function classifyEntityQuality(name, type) {
36494
36494
  }
36495
36495
 
36496
36496
  // ../../platform/daemon/src/episodic-sources.ts
36497
+ var EPISODIC_CAPTURED_AT_FLOOR = "2000-01-01T00:00:00.000Z";
36497
36498
  function readNonEmptyTrimmed(value) {
36498
36499
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
36499
36500
  }
@@ -36699,11 +36700,8 @@ function searchEpisodicSources(db, params) {
36699
36700
  const query = params.query.trim();
36700
36701
  const limit = Math.max(1, Math.min(Math.floor(params.limit ?? 20), 50));
36701
36702
  const like = `%${query}%`;
36702
- const timeArgs = [];
36703
- if (params.since !== undefined)
36704
- timeArgs.push(params.since);
36705
- if (params.before !== undefined)
36706
- timeArgs.push(params.before);
36703
+ const sinceArgs = params.since !== undefined ? [params.since, EPISODIC_CAPTURED_AT_FLOOR] : [];
36704
+ const beforeArgs = params.before !== undefined ? [params.before] : [];
36707
36705
  const branches = [];
36708
36706
  if (params.kind === undefined || params.kind === "memory") {
36709
36707
  branches.push({
@@ -36712,8 +36710,9 @@ function searchEpisodicSources(db, params) {
36712
36710
  WHERE agent_id = ? AND memory_kind = 'episodic'
36713
36711
  AND COALESCE(is_deleted, 0) = 0 AND visibility != 'archived' AND scope IS NULL
36714
36712
  AND COALESCE(type, '') != 'session_summary' AND content LIKE ?
36715
- ${params.since ? "AND created_at >= ?" : ""} ${params.before ? "AND created_at <= ?" : ""}`,
36716
- args: [params.agentId, like, ...timeArgs]
36713
+ ${params.since ? "AND (julianday(created_at) >= julianday(?) OR julianday(created_at) < julianday(?))" : ""}
36714
+ ${params.before ? "AND julianday(created_at) <= julianday(?)" : ""}`,
36715
+ args: [params.agentId, like, ...sinceArgs, ...beforeArgs]
36717
36716
  });
36718
36717
  }
36719
36718
  if (params.kind === undefined || params.kind === "artifact") {
@@ -36722,7 +36721,8 @@ function searchEpisodicSources(db, params) {
36722
36721
  FROM memory_artifacts ma
36723
36722
  WHERE ma.agent_id = ? AND COALESCE(ma.is_deleted, 0) = 0
36724
36723
  AND length(ma.content) > 0 AND ma.content LIKE ?
36725
- ${params.since ? "AND ma.captured_at >= ?" : ""} ${params.before ? "AND ma.captured_at <= ?" : ""}
36724
+ ${params.since ? "AND (julianday(ma.captured_at) >= julianday(?) OR julianday(ma.captured_at) < julianday(?))" : ""}
36725
+ ${params.before ? "AND julianday(ma.captured_at) <= julianday(?)" : ""}
36726
36726
  AND (ma.source_sha256 IS NULL OR ma.source_sha256 = ''
36727
36727
  OR (ma.agent_id, ma.source_path) = (
36728
36728
  SELECT ma2.agent_id, ma2.source_path FROM memory_artifacts ma2
@@ -36731,7 +36731,7 @@ function searchEpisodicSources(db, params) {
36731
36731
  ORDER BY ma2.captured_at DESC, ma2.source_path ASC
36732
36732
  LIMIT 1
36733
36733
  ))`,
36734
- args: [params.agentId, like, ...timeArgs]
36734
+ args: [params.agentId, like, ...sinceArgs, ...beforeArgs]
36735
36735
  });
36736
36736
  }
36737
36737
  if (params.kind === undefined || params.kind === "transcript") {
@@ -36739,9 +36739,9 @@ function searchEpisodicSources(db, params) {
36739
36739
  sql: `SELECT 'transcript' AS kind, session_key AS id, COALESCE(updated_at, created_at) AS captured_at
36740
36740
  FROM session_transcripts
36741
36741
  WHERE agent_id = ? AND content LIKE ?
36742
- ${params.since ? "AND COALESCE(updated_at, created_at) >= ?" : ""}
36743
- ${params.before ? "AND COALESCE(updated_at, created_at) <= ?" : ""}`,
36744
- args: [params.agentId, like, ...timeArgs]
36742
+ ${params.since ? "AND (julianday(COALESCE(updated_at, created_at)) >= julianday(?) OR julianday(COALESCE(updated_at, created_at)) < julianday(?))" : ""}
36743
+ ${params.before ? "AND julianday(COALESCE(updated_at, created_at)) <= julianday(?)" : ""}`,
36744
+ args: [params.agentId, like, ...sinceArgs, ...beforeArgs]
36745
36745
  });
36746
36746
  }
36747
36747
  if (params.kind === undefined || params.kind === "summary") {
@@ -36751,8 +36751,9 @@ function searchEpisodicSources(db, params) {
36751
36751
  WHERE agent_id = ? AND depth = 0
36752
36752
  AND COALESCE(source_type, 'summary') IN ('summary', 'compaction', 'checkpoint')
36753
36753
  AND content LIKE ?
36754
- ${params.since ? "AND latest_at >= ?" : ""} ${params.before ? "AND latest_at <= ?" : ""}`,
36755
- args: [params.agentId, like, ...timeArgs]
36754
+ ${params.since ? "AND (julianday(latest_at) >= julianday(?) OR julianday(latest_at) < julianday(?))" : ""}
36755
+ ${params.before ? "AND julianday(latest_at) <= julianday(?)" : ""}`,
36756
+ args: [params.agentId, like, ...sinceArgs, ...beforeArgs]
36756
36757
  });
36757
36758
  }
36758
36759
  const union3 = branches.map((branch) => branch.sql).join(`
@@ -43926,6 +43927,7 @@ function buildRememberRequestBody(content, options = {}) {
43926
43927
  validUntil: options.validUntil,
43927
43928
  sourceCreatedAt: options.sourceCreatedAt,
43928
43929
  reviewAfter: options.reviewAfter,
43930
+ supersedes: options.supersedes,
43929
43931
  hints: options.hints,
43930
43932
  transcript: options.transcript,
43931
43933
  structured: normalizeStructuredMemoryPayload(options.structured),
@@ -48289,6 +48291,7 @@ var ONTOLOGY_PROPOSAL_OPERATIONS = [
48289
48291
  "update_link",
48290
48292
  "archive_link",
48291
48293
  "merge_entities",
48294
+ "merge_aspects",
48292
48295
  "supersede_claim_value",
48293
48296
  "create_policy",
48294
48297
  "create_action_type",
@@ -49357,6 +49360,7 @@ function truncateToTokens(text, limit) {
49357
49360
  }
49358
49361
 
49359
49362
  // ../../platform/daemon/src/pipeline/dreaming.ts
49363
+ var EVIDENCE_WATERMARK_FLOOR_MS = Date.parse(EPISODIC_CAPTURED_AT_FLOOR);
49360
49364
  var FAILURE_BACKOFF_BASE_MS = 5 * 60 * 1000;
49361
49365
  var DREAMING_HALT_COOLDOWN_MS = 24 * 60 * 60 * 1000;
49362
49366
 
@@ -50051,8 +50055,10 @@ var DEFAULT_PIPELINE_V2 = {
50051
50055
  traversal: {
50052
50056
  enabled: true,
50053
50057
  primary: true,
50054
- maxAspectsPerEntity: 10,
50055
- maxAttributesPerAspect: 20,
50058
+ maxAspectsPerEntity: 20,
50059
+ maxAttributesPerAspect: 50,
50060
+ maxWriteAspectsPerEntity: 20,
50061
+ maxWriteAttributesPerAspect: 50,
50056
50062
  maxDependencyHops: 10,
50057
50063
  minDependencyStrength: 0.3,
50058
50064
  maxBranching: 4,
@@ -50821,6 +50827,15 @@ function txSupersedeMemory(db, input) {
50821
50827
  currentSupersededBy: existing.superseded_by
50822
50828
  };
50823
50829
  }
50830
+ if (existing.superseded_by !== null && existing.superseded_by !== input.supersededBy) {
50831
+ return {
50832
+ status: "already_superseded_by_other",
50833
+ memoryId: input.memoryId,
50834
+ supersededBy: existing.superseded_by,
50835
+ currentVersion: existing.version,
50836
+ currentSupersededBy: existing.superseded_by
50837
+ };
50838
+ }
50824
50839
  const target2 = db.prepare(`SELECT id, is_deleted, agent_id, project, scope, visibility
50825
50840
  FROM memories
50826
50841
  WHERE id = ?`).get(input.supersededBy);
@@ -50893,7 +50908,7 @@ function applyOntologyOperationBatchInTx(db, params) {
50893
50908
  const row = getProposalInTx(db, inserted.id, params.agentId);
50894
50909
  if (row === null)
50895
50910
  throw new OntologyProposalError("Proposal not found", 404);
50896
- const result = applyOperation(db, row, params.actor);
50911
+ const result = applyOperation(db, row, params.actor, params.writeCaps);
50897
50912
  items.push({
50898
50913
  proposal: markAppliedInTx(db, row, params.actor, result),
50899
50914
  result,
@@ -51355,7 +51370,7 @@ function restoreAttributeMemoryInTx(db, memoryId, proposal) {
51355
51370
  createdAt: changedAt
51356
51371
  });
51357
51372
  }
51358
- function applyAddClaimValue(db, agentId, proposal, payload) {
51373
+ function applyAddClaimValue(db, agentId, proposal, payload, writeCaps) {
51359
51374
  const entity = readString2(payload, "entity");
51360
51375
  const aspect = readString2(payload, "aspect");
51361
51376
  const claimKey = readString2(payload, "claim_key");
@@ -51369,6 +51384,9 @@ function applyAddClaimValue(db, agentId, proposal, payload) {
51369
51384
  if (value === null)
51370
51385
  throw new OntologyProposalError("payload.value is required", 400);
51371
51386
  const entityId = resolveOrCreateEntity(db, agentId, entity, normalizeEntityType2(readString2(payload, "entity_type")));
51387
+ const addEntityRow = db.prepare("SELECT id, name FROM entities WHERE id = ?").get(entityId);
51388
+ if (addEntityRow !== undefined)
51389
+ enforceAspectCapForNewAspect(db, addEntityRow, agentId, aspect, writeCaps);
51372
51390
  const aspectId = resolveOrCreateAspect(db, entityId, agentId, aspect);
51373
51391
  const groupKey = readString2(payload, "group_key") ?? "general";
51374
51392
  const kind = normalizeAttributeKind(readString2(payload, "kind"));
@@ -51385,6 +51403,14 @@ function applyAddClaimValue(db, agentId, proposal, payload) {
51385
51403
  if (existing) {
51386
51404
  return { entityId, aspectId, attributeId: existing.id, deduped: true };
51387
51405
  }
51406
+ if (writeCaps !== undefined) {
51407
+ const attrCount = db.prepare(`SELECT COUNT(*) AS c FROM entity_attributes
51408
+ WHERE aspect_id = ? AND agent_id = ? AND status = 'active'`).get(aspectId, agentId);
51409
+ if (attrCount.c >= writeCaps.maxAttributesPerAspect) {
51410
+ const aspectName = db.prepare("SELECT name FROM entity_aspects WHERE id = ?").get(aspectId);
51411
+ throw new OntologyProposalError(`aspect '${aspectName?.name ?? aspectId}' is at attribute cap (${attrCount.c}/${writeCaps.maxAttributesPerAspect}) — supersede or expire an existing claim, or consolidate duplicates, before adding`, 409);
51412
+ }
51413
+ }
51388
51414
  const id = crypto.randomUUID();
51389
51415
  const confidence = clamp01(readNumber(payload, "confidence") ?? proposal.confidence);
51390
51416
  const importance = clamp01(readNumber(payload, "importance") ?? confidence);
@@ -51411,7 +51437,7 @@ function applyAddClaimValue(db, agentId, proposal, payload) {
51411
51437
  });
51412
51438
  return { entityId, aspectId, attributeId: id, memoryId, deduped: false };
51413
51439
  }
51414
- function applySetClaimValue(db, agentId, proposal, payload) {
51440
+ function applySetClaimValue(db, agentId, proposal, payload, writeCaps) {
51415
51441
  const entity = readString2(payload, "entity");
51416
51442
  const aspect = readString2(payload, "aspect");
51417
51443
  const claimKey = canonicalKey(readString2(payload, "claim_key") ?? readString2(payload, "claim"));
@@ -51453,6 +51479,14 @@ function applySetClaimValue(db, agentId, proposal, payload) {
51453
51479
  throw new OntologyProposalError("Refusing to replace active constraint claim without force", 409);
51454
51480
  }
51455
51481
  const previous = active[0] ?? slot[0] ?? null;
51482
+ if (previous === null && writeCaps !== undefined) {
51483
+ const attrCount = db.prepare(`SELECT COUNT(*) AS c FROM entity_attributes
51484
+ WHERE aspect_id = ? AND agent_id = ? AND status = 'active'`).get(aspectId, agentId);
51485
+ if (attrCount.c >= writeCaps.maxAttributesPerAspect) {
51486
+ const aspectName = db.prepare("SELECT name FROM entity_aspects WHERE id = ?").get(aspectId);
51487
+ throw new OntologyProposalError(`aspect '${aspectName?.name ?? aspectId}' is at attribute cap (${attrCount.c}/${writeCaps.maxAttributesPerAspect}) — supersede or expire an existing claim, or consolidate duplicates, before adding`, 409);
51488
+ }
51489
+ }
51456
51490
  const version2 = previous === null ? 1 : Math.max(...slot.map((row) => row.version ?? 1)) + 1;
51457
51491
  const rootId = previous?.version_root_id ?? previous?.id ?? crypto.randomUUID();
51458
51492
  const id = version2 === 1 ? rootId : crypto.randomUUID();
@@ -51624,7 +51658,21 @@ function applyArchiveEntity(db, agentId, proposal, payload, actor) {
51624
51658
  WHERE id = ? AND agent_id = ?`).run(actor, readString2(payload, "reason") ?? proposal.rationale, proposal.id, JSON.stringify(proposalAuditEvidence(proposal)), entity.id, agentId);
51625
51659
  return { entityId: entity.id, archived: true };
51626
51660
  }
51627
- function applyCreateAspect(db, agentId, proposal, payload) {
51661
+ function enforceAspectCapForNewAspect(db, entity, agentId, name, writeCaps) {
51662
+ if (writeCaps === undefined)
51663
+ return;
51664
+ const key = canonical(name);
51665
+ const activeAspect = db.prepare(`SELECT id FROM entity_aspects
51666
+ WHERE entity_id = ? AND agent_id = ? AND canonical_name = ? AND COALESCE(status, 'active') = 'active'`).get(entity.id, agentId, key);
51667
+ if (activeAspect != null)
51668
+ return;
51669
+ const aspectCount = db.prepare(`SELECT COUNT(*) AS c FROM entity_aspects
51670
+ WHERE entity_id = ? AND agent_id = ? AND COALESCE(status, 'active') = 'active'`).get(entity.id, agentId);
51671
+ if (aspectCount.c >= writeCaps.maxAspectsPerEntity) {
51672
+ throw new OntologyProposalError(`entity '${entity.name}' is at aspect cap (${aspectCount.c}/${writeCaps.maxAspectsPerEntity}) — consolidate or archive an existing aspect before creating a new one`, 409);
51673
+ }
51674
+ }
51675
+ function applyCreateAspect(db, agentId, proposal, payload, writeCaps) {
51628
51676
  const entitySelector = readPayloadSelector(payload, "entity", "entity_id");
51629
51677
  const name = readString2(payload, "name") ?? readString2(payload, "aspect");
51630
51678
  if (entitySelector === null)
@@ -51632,6 +51680,7 @@ function applyCreateAspect(db, agentId, proposal, payload) {
51632
51680
  if (name === null)
51633
51681
  throw new OntologyProposalError("payload.name is required", 400);
51634
51682
  const entity = resolveEntityStrict(db, agentId, entitySelector);
51683
+ enforceAspectCapForNewAspect(db, entity, agentId, name, writeCaps);
51635
51684
  const aspectId = resolveOrCreateAspect(db, entity.id, agentId, name);
51636
51685
  db.prepare(`UPDATE entity_aspects
51637
51686
  SET proposal_id = ?, proposal_evidence = ?, updated_at = datetime('now')
@@ -51795,6 +51844,68 @@ function applyMergeEntities(db, agentId, payload) {
51795
51844
  warnings: plan.warnings
51796
51845
  };
51797
51846
  }
51847
+ function applyMergeAspects(db, agentId, proposal, payload) {
51848
+ const entitySelector = readPayloadSelector(payload, "entity", "entity_id");
51849
+ const targetSelector = readPayloadSelector(payload, "target", "target_aspect", "target_aspect_id", "aspect");
51850
+ const rawSources = readStringArray(payload, "sources") ?? readStringArray(payload, "source_aspects");
51851
+ if (entitySelector === null)
51852
+ throw new OntologyProposalError("payload.entity is required", 400);
51853
+ if (targetSelector === null)
51854
+ throw new OntologyProposalError("payload.target is required", 400);
51855
+ if (rawSources.length === 0)
51856
+ throw new OntologyProposalError("payload.sources is required", 400);
51857
+ const entity = resolveEntityStrict(db, agentId, entitySelector);
51858
+ const target2 = resolveAspectStrict(db, agentId, entity.id, targetSelector);
51859
+ const newName = readString2(payload, "new_name");
51860
+ if (newName !== null) {
51861
+ const key = canonical(newName);
51862
+ const collision = db.prepare(`SELECT id FROM entity_aspects
51863
+ WHERE entity_id = ? AND agent_id = ? AND id != ?
51864
+ AND COALESCE(status, 'active') = 'active'
51865
+ AND (canonical_name = ? OR LOWER(name) = ?)
51866
+ LIMIT 1`).get(entity.id, agentId, target2.id, key, key);
51867
+ if (collision)
51868
+ throw new OntologyProposalError(`Aspect collides with "${newName}"`, 409);
51869
+ }
51870
+ const evidence = JSON.stringify(proposalAuditEvidence(proposal));
51871
+ const moved = [];
51872
+ let totalMoved = 0;
51873
+ const seen = new Set([target2.id]);
51874
+ for (const raw of rawSources) {
51875
+ if (typeof raw !== "string")
51876
+ throw new OntologyProposalError("payload.sources must be aspect selectors", 400);
51877
+ const source = resolveAspectStrict(db, agentId, entity.id, raw);
51878
+ if (seen.has(source.id))
51879
+ continue;
51880
+ seen.add(source.id);
51881
+ const attributes = db.prepare("SELECT id FROM entity_attributes WHERE aspect_id = ? AND agent_id = ?").all(source.id, agentId);
51882
+ for (const attribute of attributes) {
51883
+ db.prepare(`UPDATE entity_attributes
51884
+ SET aspect_id = ?, updated_at = datetime('now')
51885
+ WHERE id = ? AND agent_id = ?`).run(target2.id, attribute.id, agentId);
51886
+ }
51887
+ db.prepare(`UPDATE entity_aspects
51888
+ SET status = 'archived', archived_at = datetime('now'), archived_by = ?,
51889
+ archive_reason = ?, proposal_id = ?, proposal_evidence = ?, updated_at = datetime('now')
51890
+ WHERE id = ? AND agent_id = ? AND COALESCE(status, 'active') = 'active'`).run(proposal.created_by || "ontology-merge", `Merged into aspect '${target2.name}'`, proposal.id, evidence, source.id, agentId);
51891
+ moved.push({ aspect: source.name, attributes: attributes.length });
51892
+ totalMoved += attributes.length;
51893
+ }
51894
+ if (moved.length === 0)
51895
+ throw new OntologyProposalError("No distinct source aspects to merge", 400);
51896
+ if (newName !== null) {
51897
+ db.prepare(`UPDATE entity_aspects
51898
+ SET name = ?, canonical_name = ?, proposal_id = ?, proposal_evidence = ?, updated_at = datetime('now')
51899
+ WHERE id = ? AND agent_id = ?`).run(newName, canonical(newName), proposal.id, evidence, target2.id, agentId);
51900
+ }
51901
+ return {
51902
+ entityId: entity.id,
51903
+ targetAspectId: target2.id,
51904
+ targetAspect: newName ?? target2.name,
51905
+ mergedAspects: moved,
51906
+ totalAttributesMoved: totalMoved
51907
+ };
51908
+ }
51798
51909
  function applyCreateLink(db, agentId, proposal, payload) {
51799
51910
  const sourceIdSelector = readString2(payload, "source_entity_id");
51800
51911
  const targetIdSelector = readString2(payload, "target_entity_id");
@@ -51927,7 +52038,7 @@ function applyArchiveEntityAlias(db, agentId, proposal, payload) {
51927
52038
  throw new OntologyProposalError("Alias not found", 404);
51928
52039
  return { aliasId, entityId: entity.id, archived: true };
51929
52040
  }
51930
- function applyOperation(db, proposal, actor) {
52041
+ function applyOperation(db, proposal, actor, writeCaps) {
51931
52042
  const payload = parseJsonRecord(proposal.payload);
51932
52043
  if (proposal.operation === "create_entity")
51933
52044
  return applyCreateEntity(db, proposal.agent_id, proposal, payload);
@@ -51936,17 +52047,19 @@ function applyOperation(db, proposal, actor) {
51936
52047
  if (proposal.operation === "archive_entity")
51937
52048
  return applyArchiveEntity(db, proposal.agent_id, proposal, payload, actor);
51938
52049
  if (proposal.operation === "create_aspect")
51939
- return applyCreateAspect(db, proposal.agent_id, proposal, payload);
52050
+ return applyCreateAspect(db, proposal.agent_id, proposal, payload, writeCaps);
51940
52051
  if (proposal.operation === "rename_aspect")
51941
52052
  return applyRenameAspect(db, proposal.agent_id, proposal, payload);
51942
52053
  if (proposal.operation === "archive_aspect")
51943
52054
  return applyArchiveAspect(db, proposal.agent_id, proposal, payload, actor);
51944
52055
  if (proposal.operation === "add_claim_value")
51945
- return applyAddClaimValue(db, proposal.agent_id, proposal, payload);
52056
+ return applyAddClaimValue(db, proposal.agent_id, proposal, payload, writeCaps);
51946
52057
  if (proposal.operation === "set_claim_value")
51947
- return applySetClaimValue(db, proposal.agent_id, proposal, payload);
52058
+ return applySetClaimValue(db, proposal.agent_id, proposal, payload, writeCaps);
51948
52059
  if (proposal.operation === "merge_entities")
51949
52060
  return applyMergeEntities(db, proposal.agent_id, payload);
52061
+ if (proposal.operation === "merge_aspects")
52062
+ return applyMergeAspects(db, proposal.agent_id, proposal, payload);
51950
52063
  if (proposal.operation === "supersede_claim_value") {
51951
52064
  return applySupersedeClaimValue(db, proposal.agent_id, proposal, payload);
51952
52065
  }
@@ -52385,6 +52498,13 @@ var DREAMING_ONTOLOGY_PAYLOAD_SCHEMAS = {
52385
52498
  survivor: entityId.describe("The entity that survives the merge."),
52386
52499
  ...reasonField
52387
52500
  }),
52501
+ merge_aspects: payload({
52502
+ entityId,
52503
+ target: aspectId.describe("The aspect that absorbs the sources. Use aspect_id."),
52504
+ sources: exports_external.array(aspectId).min(1).describe("Aspect ids to fold into the target. Attributes are moved, sources are archived."),
52505
+ newName: aspectName.describe("Optional new name for the merged aspect.").optional(),
52506
+ ...reasonField
52507
+ }),
52388
52508
  create_entity: payload({ name: entityName, type: entityType }),
52389
52509
  add_claim_value: payload({ entityId, aspectId, claimKey, value: claimValue, reviewAfter }),
52390
52510
  set_claim_value: payload({ entityId, aspectId, claimKey, value: claimValue, reviewAfter }),
@@ -52440,6 +52560,7 @@ var DREAMING_ONTOLOGY_OPERATION_SCHEMA = exports_external.discriminatedUnion("op
52440
52560
  operation("update_link"),
52441
52561
  operation("archive_link"),
52442
52562
  operation("merge_entities"),
52563
+ operation("merge_aspects"),
52443
52564
  operation("supersede_claim_value"),
52444
52565
  operation("create_policy"),
52445
52566
  operation("create_action_type"),
@@ -52454,7 +52575,8 @@ var HYGIENE_ARCHIVE_OPS = new Set([
52454
52575
  "archive_aspect",
52455
52576
  "archive_claim_value",
52456
52577
  "archive_link",
52457
- "merge_entities"
52578
+ "merge_entities",
52579
+ "merge_aspects"
52458
52580
  ]);
52459
52581
  function citationRecord(value) {
52460
52582
  if (typeof value !== "object" || value === null || Array.isArray(value))
@@ -52569,6 +52691,10 @@ function attentionProvenance(accessor, agentId, operation2, mintedById) {
52569
52691
  const survivor = typeof payload2.survivor === "string" ? payload2.survivor : "";
52570
52692
  const groupIds = semanticDuplicateIds(accessor, agentId, attention.details.canonicalName ?? "");
52571
52693
  expectedTarget = attention.subjectRef === `duplicate:${attention.details.canonicalName}` && groupIds.size > 1 && groupIds.has(survivor) && targets.length >= 2 && targets.every((id) => groupIds.has(id)) && targets.includes(survivor) && targets.some((id) => id !== survivor);
52694
+ } else if (operation2.operation === "merge_aspects") {
52695
+ const sources = Array.isArray(payload2.sources) ? payload2.sources.filter((value) => typeof value === "string") : [];
52696
+ const flaggedAspect = attention.details.aspectId ?? attention.subjectRef.replace(/^aspect:/, "");
52697
+ expectedTarget = attention.subjectRef.startsWith("aspect:") && typeof payload2.target === "string" && sources.length >= 1 && sources.includes(flaggedAspect);
52572
52698
  }
52573
52699
  if (!expectedTarget)
52574
52700
  return null;
@@ -52675,6 +52801,15 @@ function toApplicatorPayload(accessor, agentId, operation2, payload2) {
52675
52801
  const sourceIds = targets.filter((id) => id !== survivor);
52676
52802
  return { target_entity_id: survivor, source_entity_ids: sourceIds };
52677
52803
  }
52804
+ case "merge_aspects": {
52805
+ const entityId2 = stringField(payload2, "entityId");
52806
+ const target3 = stringField(payload2, "target");
52807
+ const sources = stringArrayField(payload2, "sources");
52808
+ if (entityId2 === null || target3 === null || sources === null || sources.length === 0)
52809
+ return null;
52810
+ const name = lookupEntityName(accessor, agentId, entityId2);
52811
+ return name === null ? null : { entity: name, target: target3, sources, new_name: stringField(payload2, "newName") ?? undefined };
52812
+ }
52678
52813
  case "create_entity": {
52679
52814
  const name = stringField(payload2, "name");
52680
52815
  const type = stringField(payload2, "type");
@@ -52836,7 +52971,8 @@ function applyDreamingOperations(params) {
52836
52971
  const batch = applyOntologyOperationBatchInTx(db, {
52837
52972
  agentId: params.agentId,
52838
52973
  actor: params.actor,
52839
- operations: [entry.input]
52974
+ operations: [entry.input],
52975
+ writeCaps: params.writeCaps
52840
52976
  });
52841
52977
  db.exec(`RELEASE SAVEPOINT ${savepoint}`);
52842
52978
  if (entry.attentionId !== null) {
@@ -53059,6 +53195,14 @@ function boundedText(value, maxChars) {
53059
53195
  return value;
53060
53196
  return value.slice(0, maxChars);
53061
53197
  }
53198
+ function readEvidenceWatermark(db, agentId) {
53199
+ try {
53200
+ const row = db.prepare("SELECT last_pass_at AS lastPassAt FROM dreaming_state WHERE agent_id = ?").get(agentId);
53201
+ return row?.lastPassAt ?? null;
53202
+ } catch {
53203
+ return null;
53204
+ }
53205
+ }
53062
53206
  function evidenceExcerptStart(content, query, maxChars) {
53063
53207
  const terms = query.toLowerCase().split(/\W+/).filter((term) => term.length >= 3).slice(0, 8);
53064
53208
  const lower = content.toLowerCase();
@@ -53291,7 +53435,7 @@ function createDreamingCapabilities(params) {
53291
53435
  }
53292
53436
  return { ok: true, result: getOntologyLinkEvidence(accessor, { agentId: scopeId, id: ref3.id }) };
53293
53437
  }),
53294
- capability("search_evidence", "Search episodic evidence", "Full-text search immutable episodic memories, artifacts, transcripts, and summaries in one agent scope. Results contain exact bounded excerpts of the rendered evidence with contentOffset/contentLength; use sourceRef for citations, which are validated against the complete canonical source. Each record carries completed: memory, artifact, and summary records are settled captures (true); a transcript is true once a session-end summary job has been triggered for its session (the session ended), whether or not the summary itself landed, and false while the session is still running — do not file claims from a still-growing transcript, since its states may be contradicted by the session's end. If contentTruncated is true, page exact fragments with the same sourceRef and chunkSize: start at offset=0 when contentHasPrevious is true, then use offset=contentOffset+content.length from the fragment just returned until contentHasNext is false. Omit the query to list the most recent sources (e.g. with since as a cutoff). Artifacts are deduped by content hash: content-identical files across vault paths collapse to one canonical entry.", true, exports_external.object({
53438
+ capability("search_evidence", "Search episodic evidence", "Full-text search immutable episodic memories, artifacts, transcripts, and summaries in one agent scope. Results contain exact bounded excerpts of the rendered evidence with contentOffset/contentLength; use sourceRef for citations, which are validated against the complete canonical source. Each record carries completed: memory, artifact, and summary records are settled captures (true); a transcript is true once a session-end summary job has been triggered for its session (the session ended), whether or not the summary itself landed, and false while the session is still running — do not file claims from a still-growing transcript, since its states may be contradicted by the session's end. If contentTruncated is true, page exact fragments with the same sourceRef and chunkSize: start at offset=0 when contentHasPrevious is true, then use offset=contentOffset+content.length from the fragment just returned until contentHasNext is false. Omit the query AND since to list the unprocessed window: the listing starts at the scope's evidence watermark (the last pass's surfaced frontier), so the newest unseen sources come first. Narrow with a query if the list is large; pass an explicit earlier since only when you need older history. Artifacts are deduped by content hash: content-identical files across vault paths collapse to one canonical entry.", true, exports_external.object({
53295
53439
  agentId: exports_external.string().min(1),
53296
53440
  query: exports_external.string().optional(),
53297
53441
  since: exports_external.string().optional(),
@@ -53309,10 +53453,11 @@ function createDreamingCapabilities(params) {
53309
53453
  const fragment = projectEvidenceFragment(source, Math.max(0, Math.floor(offset ?? 0)), Math.min(Math.max(Math.floor(chunkSize ?? MAX_EVIDENCE_EXCERPT_CHARS), 1), MAX_EVIDENCE_EXCERPT_CHARS));
53310
53454
  return fragment === null ? { ok: false, error: "Evidence fragment offset is outside the source" } : { ok: true, items: [fragment] };
53311
53455
  }
53456
+ const effectiveSince = since ?? readEvidenceWatermark(db, scopeId);
53312
53457
  const sources = searchEpisodicSources(db, {
53313
53458
  agentId: scopeId,
53314
53459
  query: query ?? "",
53315
- since,
53460
+ since: effectiveSince ?? undefined,
53316
53461
  before,
53317
53462
  kind,
53318
53463
  limit
@@ -53420,7 +53565,8 @@ function createDreamingCapabilities(params) {
53420
53565
  agentId: scopeId,
53421
53566
  actor,
53422
53567
  operations,
53423
- passId: params.passId
53568
+ passId: params.passId,
53569
+ writeCaps: params.writeCaps
53424
53570
  });
53425
53571
  params.onOperationsApplied?.(result, operations);
53426
53572
  return { ok: result.ok, ...result.error ? { error: result.error } : {}, items: result.items };
@@ -55463,6 +55609,7 @@ async function createMcpServer(opts) {
55463
55609
  validFrom: exports_external.string().optional().describe("Start of validity window for this memory"),
55464
55610
  validUntil: exports_external.string().optional().describe("End of validity window for this memory"),
55465
55611
  reviewAfter: exports_external.string().optional().describe("ISO timestamp when this temporal claim becomes due for review (issue #945)"),
55612
+ supersedes: exports_external.string().optional().describe("Id of an existing memory this write supersedes. The old row is marked superseded in the same transaction, wiring vN -> vN+1 lineage for drill-down history."),
55466
55613
  transcript: exports_external.string().optional().describe("Raw source text (conversation transcript) to preserve alongside extracted memory"),
55467
55614
  structured: exports_external.object({
55468
55615
  entities: exports_external.array(exports_external.object({
@@ -55515,7 +55662,8 @@ async function createMcpServer(opts) {
55515
55662
  sourceCreatedAt,
55516
55663
  validFrom,
55517
55664
  validUntil,
55518
- reviewAfter: reviewAfter2
55665
+ reviewAfter: reviewAfter2,
55666
+ supersedes
55519
55667
  }) => {
55520
55668
  const result = await fetchDaemon(baseUrl, "/api/memory/remember", {
55521
55669
  method: "POST",
@@ -55533,7 +55681,8 @@ async function createMcpServer(opts) {
55533
55681
  sourceCreatedAt,
55534
55682
  validFrom,
55535
55683
  validUntil,
55536
- reviewAfter: reviewAfter2
55684
+ reviewAfter: reviewAfter2,
55685
+ supersedes
55537
55686
  })
55538
55687
  });
55539
55688
  if (!result.ok) {
@@ -1,43 +1,43 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.165.0",
3
+ "version": "0.167.0",
4
4
  "assets": [
5
5
  {
6
6
  "name": "signet-darwin-arm64",
7
7
  "platform": "darwin-arm64",
8
- "sha256": "cfa00e0e08296e60030ec256596115e23360e3d113456dd1b4117a17f2a09f26",
9
- "size": 116929312
8
+ "sha256": "9873f32416ca55b9759d8470cfe5a074f4d91084bdd927f71be47f6c442611ba",
9
+ "size": 116962336
10
10
  },
11
11
  {
12
12
  "name": "signet-darwin-x64",
13
13
  "platform": "darwin-x64",
14
- "sha256": "bfa798eefc6a1e502186b32678ee9d0a6c4edef5d14f57aa70fafb1c69f8f5c7",
15
- "size": 121555520
14
+ "sha256": "1d48388b93a7c87d042176c0671240b7e0782e54e98c9c0eed1301e55c0e94c8",
15
+ "size": 121588288
16
16
  },
17
17
  {
18
18
  "name": "signet-linux-arm64",
19
19
  "platform": "linux-arm64",
20
- "sha256": "9e5dfbd7c4664cde0ccb882b642fb413e7ee1a1c61821514d7d451c8685a4d9b",
21
- "size": 154173882
20
+ "sha256": "5b226210a175550fa16f929e1cd488563460092e1799e90d8a2cfec19478dfc1",
21
+ "size": 154208710
22
22
  },
23
23
  {
24
24
  "name": "signet-linux-x64",
25
25
  "platform": "linux-x64",
26
- "sha256": "c0740baf74799c1b229e41a0231360700e0b536adfd538d70ead1fa55d4bc841",
27
- "size": 154732867
26
+ "sha256": "fde3e639c5c5e2a8c4b059d1792641ab9853a4d76340a24f9b391a1bf194abf4",
27
+ "size": 154767695
28
28
  },
29
29
  {
30
30
  "name": "signet-win32-x64.exe",
31
31
  "platform": "win32-x64",
32
- "sha256": "2e3291f8f52a1aec46c9e207c3d58f079046f12e9890b148a3b47197c3c116ee",
33
- "size": 170866176
32
+ "sha256": "1b29614c6ab3f35cb0c5d8b582a68d7da15ce9371b93a0c1b796d41e48d6f616",
33
+ "size": 170900992
34
34
  }
35
35
  ],
36
36
  "components": {
37
37
  "connectors": {
38
- "url": "signet-connectors-0.165.0.tar.gz",
39
- "sha256": "59cfe5b98223652be028e51f99d927681c6cdd6da1b4e6237582e94cae40b071",
40
- "size": 16248
38
+ "url": "signet-connectors-0.167.0.tar.gz",
39
+ "sha256": "ad0d2bba53e73dde4705fb5150ccc87a8b75bcdf8f71ab19bad2db45f373cdf9",
40
+ "size": 16250
41
41
  }
42
42
  }
43
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signetai",
3
- "version": "0.165.0",
3
+ "version": "0.167.0",
4
4
  "description": "Signet native CLI installer wrapper",
5
5
  "type": "module",
6
6
  "bin": {
@@ -65,10 +65,10 @@
65
65
  "access": "public"
66
66
  },
67
67
  "optionalDependencies": {
68
- "signetai-darwin-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.165.0/signetai-darwin-arm64-0.165.0.tgz",
69
- "signetai-darwin-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.165.0/signetai-darwin-x64-0.165.0.tgz",
70
- "signetai-linux-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.165.0/signetai-linux-arm64-0.165.0.tgz",
71
- "signetai-linux-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.165.0/signetai-linux-x64-0.165.0.tgz",
72
- "signetai-win32-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.165.0/signetai-win32-x64-0.165.0.tgz"
68
+ "signetai-darwin-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.167.0/signetai-darwin-arm64-0.167.0.tgz",
69
+ "signetai-darwin-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.167.0/signetai-darwin-x64-0.167.0.tgz",
70
+ "signetai-linux-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.167.0/signetai-linux-arm64-0.167.0.tgz",
71
+ "signetai-linux-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.167.0/signetai-linux-x64-0.167.0.tgz",
72
+ "signetai-win32-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.167.0/signetai-win32-x64-0.167.0.tgz"
73
73
  }
74
74
  }