@ghostpaw/affinity 0.1.5 → 0.1.6

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 (3) hide show
  1. package/dist/index.cjs +262 -38
  2. package/dist/index.js +262 -38
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -6443,12 +6443,43 @@ var manageAttributeTool = defineAffinityTool({
6443
6443
  });
6444
6444
 
6445
6445
  // src/tools/manage_commitment_tool.ts
6446
+ function normalizeParticipant(p) {
6447
+ let contactId = p.contactId;
6448
+ if (contactId === void 0 && p.contact != null) {
6449
+ const loc = p.contact;
6450
+ contactId = loc.contactId;
6451
+ }
6452
+ const result = {
6453
+ contactId,
6454
+ role: p.role
6455
+ };
6456
+ if (p.directionality !== void 0) {
6457
+ result.directionality = p.directionality;
6458
+ }
6459
+ return result;
6460
+ }
6461
+ function ensureOwnerParticipates(db, participants) {
6462
+ const ownerId = findOwnerContactId(db);
6463
+ if (ownerId === null) return participants;
6464
+ if (participants.some((p) => p.contactId === ownerId)) return participants;
6465
+ return [{ contactId: ownerId, role: "actor" }, ...participants];
6466
+ }
6467
+ function prepareParticipants(db, raw) {
6468
+ return ensureOwnerParticipates(db, raw.map(normalizeParticipant));
6469
+ }
6446
6470
  function manageCommitmentToolHandler(db, input) {
6447
6471
  return withToolHandling(() => {
6448
6472
  if (input.action === "record") {
6473
+ const patched = {
6474
+ ...input.input,
6475
+ participants: prepareParticipants(
6476
+ db,
6477
+ input.input.participants
6478
+ )
6479
+ };
6449
6480
  return mutationToolResult(
6450
6481
  "record",
6451
- recordCommitment(db, input.input),
6482
+ recordCommitment(db, patched),
6452
6483
  "commitment"
6453
6484
  );
6454
6485
  }
@@ -6466,7 +6497,7 @@ function manageCommitmentToolHandler(db, input) {
6466
6497
  }
6467
6498
  var manageCommitmentTool = defineAffinityTool({
6468
6499
  name: manageCommitmentToolName,
6469
- description: "Record or resolve one commitment such as a promise or agreement.",
6500
+ description: "Record or resolve one commitment such as a promise or agreement. The owner contact is auto-injected into participants if missing.",
6470
6501
  whenToUse: "Use this when the work is specifically about a commitment lifecycle rather than a general event.",
6471
6502
  whenNotToUse: "Do not use this for ordinary interactions or direct relationship state changes.",
6472
6503
  sideEffects: "writes_state",
@@ -6484,10 +6515,42 @@ var manageCommitmentTool = defineAffinityTool({
6484
6515
  inputSchema: objectSchema(
6485
6516
  {
6486
6517
  action: enumSchema("Operation to perform.", ["record", "resolve"]),
6487
- input: {
6488
- type: "object",
6489
- description: "Commitment payload. Required when action=record."
6490
- },
6518
+ input: objectSchema(
6519
+ {
6520
+ commitmentType: enumSchema("Promise or agreement.", [
6521
+ "promise",
6522
+ "agreement"
6523
+ ]),
6524
+ occurredAt: integerSchema(
6525
+ "When the commitment was made, Unix timestamp in milliseconds."
6526
+ ),
6527
+ summary: stringSchema("Commitment summary. Must be non-empty."),
6528
+ significance: integerSchema("Commitment significance from 1 to 10."),
6529
+ dueAt: integerSchema("Optional due timestamp."),
6530
+ participants: arraySchema(
6531
+ objectSchema(
6532
+ {
6533
+ contactId: integerSchema(
6534
+ "Participant contact id. The owner contact MUST be included."
6535
+ ),
6536
+ role: stringSchema("Participant role."),
6537
+ directionality: stringSchema("Optional directionality.")
6538
+ },
6539
+ ["contactId", "role"]
6540
+ ),
6541
+ "Participant list. Must be non-empty and include the owner contact."
6542
+ ),
6543
+ now: integerSchema("Optional timestamp override.")
6544
+ },
6545
+ [
6546
+ "commitmentType",
6547
+ "occurredAt",
6548
+ "summary",
6549
+ "significance",
6550
+ "participants"
6551
+ ],
6552
+ "Commitment payload. Required when action=record."
6553
+ ),
6491
6554
  commitmentEventId: integerSchema(
6492
6555
  "Commitment event id. Required when action=resolve."
6493
6556
  ),
@@ -6644,6 +6707,43 @@ var manageContactTool = defineAffinityTool({
6644
6707
  });
6645
6708
 
6646
6709
  // src/tools/manage_date_anchor_tool.ts
6710
+ function contactLocatorSchema4(description) {
6711
+ return {
6712
+ type: "object",
6713
+ properties: {
6714
+ contactId: integerSchema("Exact contact id."),
6715
+ identity: objectSchema(
6716
+ {
6717
+ type: stringSchema("Identity type."),
6718
+ value: stringSchema("Identity value.")
6719
+ },
6720
+ ["type", "value"],
6721
+ "Contact identity locator."
6722
+ )
6723
+ },
6724
+ description
6725
+ };
6726
+ }
6727
+ function linkLocatorSchema3(description) {
6728
+ return {
6729
+ type: "object",
6730
+ properties: {
6731
+ linkId: integerSchema("Exact link id."),
6732
+ endpoints: objectSchema(
6733
+ {
6734
+ fromContactId: integerSchema("From contact id."),
6735
+ toContactId: integerSchema("To contact id."),
6736
+ kind: stringSchema("Optional link kind."),
6737
+ role: stringSchema("Optional link role."),
6738
+ isStructural: booleanSchema("Optional structural discriminator.")
6739
+ },
6740
+ ["fromContactId", "toContactId"],
6741
+ "Endpoint-based link locator."
6742
+ )
6743
+ },
6744
+ description
6745
+ };
6746
+ }
6647
6747
  function resolveDateAnchorTarget(db, target) {
6648
6748
  if (target.kind === "contact") {
6649
6749
  const contact = resolveContactLocator(db, target.contact, "target.contact");
@@ -6709,17 +6809,65 @@ var manageDateAnchorTool = defineAffinityTool({
6709
6809
  inputSchema: objectSchema(
6710
6810
  {
6711
6811
  action: enumSchema("Operation to perform.", ["add", "revise", "remove"]),
6712
- input: {
6713
- type: "object",
6714
- description: "Date anchor payload. Required when action=add."
6715
- },
6812
+ input: objectSchema(
6813
+ {
6814
+ target: objectSchema(
6815
+ {
6816
+ kind: enumSchema("Target kind.", ["contact", "link"]),
6817
+ contact: contactLocatorSchema4(
6818
+ "Contact locator. Required when kind=contact. Provide contactId or identity."
6819
+ ),
6820
+ link: linkLocatorSchema3(
6821
+ "Link locator. Required when kind=link. Provide linkId or endpoints."
6822
+ )
6823
+ },
6824
+ ["kind"],
6825
+ "Date-anchor target."
6826
+ ),
6827
+ recurrenceKind: enumSchema("Recurrence kind.", [
6828
+ "birthday",
6829
+ "anniversary",
6830
+ "renewal",
6831
+ "memorial",
6832
+ "custom_yearly"
6833
+ ]),
6834
+ anchorMonth: integerSchema("Anchor month, 1\u201312."),
6835
+ anchorDay: integerSchema("Anchor day, 1\u201331 (validated per month)."),
6836
+ summary: stringSchema("Summary. Must be non-empty."),
6837
+ significance: integerSchema("Significance from 1 to 10."),
6838
+ now: integerSchema("Optional timestamp override."),
6839
+ force: booleanSchema("Whether to bypass duplicate checks.")
6840
+ },
6841
+ [
6842
+ "target",
6843
+ "recurrenceKind",
6844
+ "anchorMonth",
6845
+ "anchorDay",
6846
+ "summary",
6847
+ "significance"
6848
+ ],
6849
+ "Date anchor payload. Required when action=add."
6850
+ ),
6716
6851
  anchorEventId: integerSchema(
6717
6852
  "Anchor event id. Required when action=revise or remove."
6718
6853
  ),
6719
- patch: {
6720
- type: "object",
6721
- description: "Anchor patch. Required when action=revise."
6722
- },
6854
+ patch: objectSchema(
6855
+ {
6856
+ recurrenceKind: enumSchema("Optional recurrence kind.", [
6857
+ "birthday",
6858
+ "anniversary",
6859
+ "renewal",
6860
+ "memorial",
6861
+ "custom_yearly"
6862
+ ]),
6863
+ anchorMonth: integerSchema("Optional month, 1\u201312."),
6864
+ anchorDay: integerSchema("Optional day, 1\u201331."),
6865
+ summary: stringSchema("Optional summary."),
6866
+ significance: integerSchema("Optional significance, 1\u201310.")
6867
+ },
6868
+ [],
6869
+ "Anchor patch. Required when action=revise."
6870
+ ),
6723
6871
  options: objectSchema(
6724
6872
  {
6725
6873
  now: integerSchema("Optional timestamp."),
@@ -6921,7 +7069,7 @@ function verifyIdentity(db, identityId, verifiedAt) {
6921
7069
  }
6922
7070
 
6923
7071
  // src/tools/manage_identity_tool.ts
6924
- function contactLocatorSchema4(description) {
7072
+ function contactLocatorSchema5(description) {
6925
7073
  return {
6926
7074
  type: "object",
6927
7075
  properties: {
@@ -7000,7 +7148,7 @@ var manageIdentityTool = defineAffinityTool({
7000
7148
  "verify",
7001
7149
  "remove"
7002
7150
  ]),
7003
- contact: contactLocatorSchema4(
7151
+ contact: contactLocatorSchema5(
7004
7152
  "Target contact. Required when action=add. Provide contactId or identity."
7005
7153
  ),
7006
7154
  input: objectSchema(
@@ -7040,7 +7188,7 @@ var manageIdentityTool = defineAffinityTool({
7040
7188
  });
7041
7189
 
7042
7190
  // src/tools/manage_relationship_tool.ts
7043
- function contactLocatorSchema5(description) {
7191
+ function contactLocatorSchema6(description) {
7044
7192
  return {
7045
7193
  type: "object",
7046
7194
  properties: {
@@ -7057,7 +7205,7 @@ function contactLocatorSchema5(description) {
7057
7205
  description
7058
7206
  };
7059
7207
  }
7060
- function linkLocatorSchema3(description) {
7208
+ function linkLocatorSchema4(description) {
7061
7209
  return {
7062
7210
  type: "object",
7063
7211
  properties: {
@@ -7196,14 +7344,14 @@ var manageRelationshipTool = defineAffinityTool({
7196
7344
  "set_structural_tie",
7197
7345
  "remove_structural_tie"
7198
7346
  ]),
7199
- from: contactLocatorSchema5(
7347
+ from: contactLocatorSchema6(
7200
7348
  "Source contact. Required when action=seed_social_link or set_structural_tie. Provide contactId or identity."
7201
7349
  ),
7202
- to: contactLocatorSchema5(
7350
+ to: contactLocatorSchema6(
7203
7351
  "Target contact. Required when action=seed_social_link or set_structural_tie. Provide contactId or identity."
7204
7352
  ),
7205
7353
  kind: stringSchema(
7206
- "Link kind. Required for seed_social_link and set_structural_tie. Can be passed here or inside input."
7354
+ "Link kind. Required for seed_social_link and set_structural_tie. Can be passed here or inside input. For seed_social_link: personal, family, professional, romantic, care, service, observed, other_relational. For set_structural_tie: works_at, manages, member_of, married_to, partner_of, parent_of, child_of, sibling_of, friend_of, client_of, vendor_of, reports_to, belongs_to, other_structural."
7207
7355
  ),
7208
7356
  role: stringSchema(
7209
7357
  "Optional role for seed_social_link or set_structural_tie. Can be passed here or inside input."
@@ -7212,7 +7360,7 @@ var manageRelationshipTool = defineAffinityTool({
7212
7360
  type: "object",
7213
7361
  description: "Full payload for seed_social_link or set_structural_tie. Alternative to top-level kind/role."
7214
7362
  },
7215
- link: linkLocatorSchema3(
7363
+ link: linkLocatorSchema4(
7216
7364
  "Target link. Required when action=revise_bond, override_state, or remove_structural_tie. Provide linkId or endpoints."
7217
7365
  ),
7218
7366
  bond: nullableStringSchema(
@@ -7241,7 +7389,7 @@ var manageRelationshipTool = defineAffinityTool({
7241
7389
  });
7242
7390
 
7243
7391
  // src/tools/merge_contacts_tool.ts
7244
- function contactLocatorSchema6(description) {
7392
+ function contactLocatorSchema7(description) {
7245
7393
  return {
7246
7394
  type: "object",
7247
7395
  properties: {
@@ -7298,10 +7446,10 @@ var mergeContactsTool = defineAffinityTool({
7298
7446
  outputDescription: "Returns the merge receipt with rewired entities and affected-link information.",
7299
7447
  inputSchema: objectSchema(
7300
7448
  {
7301
- winner: contactLocatorSchema6(
7449
+ winner: contactLocatorSchema7(
7302
7450
  "Winner contact. Provide contactId or identity."
7303
7451
  ),
7304
- loser: contactLocatorSchema6(
7452
+ loser: contactLocatorSchema7(
7305
7453
  "Loser contact. Provide contactId or identity."
7306
7454
  ),
7307
7455
  reasonSummary: stringSchema("Optional merge reason."),
@@ -7314,31 +7462,64 @@ var mergeContactsTool = defineAffinityTool({
7314
7462
  });
7315
7463
 
7316
7464
  // src/tools/record_event_tool.ts
7465
+ function normalizeParticipant2(p) {
7466
+ let contactId = p.contactId;
7467
+ if (contactId === void 0 && p.contact != null) {
7468
+ const loc = p.contact;
7469
+ contactId = loc.contactId;
7470
+ }
7471
+ const result = {
7472
+ contactId,
7473
+ role: p.role
7474
+ };
7475
+ if (p.directionality !== void 0) {
7476
+ result.directionality = p.directionality;
7477
+ }
7478
+ return result;
7479
+ }
7480
+ function ensureOwnerParticipates2(db, participants) {
7481
+ const ownerId = findOwnerContactId(db);
7482
+ if (ownerId === null) return participants;
7483
+ if (participants.some((p) => p.contactId === ownerId)) return participants;
7484
+ return [{ contactId: ownerId, role: "actor" }, ...participants];
7485
+ }
7486
+ function prepareParticipants2(db, raw, injectOwner) {
7487
+ const normalized = raw.map(normalizeParticipant2);
7488
+ return injectOwner ? ensureOwnerParticipates2(db, normalized) : normalized;
7489
+ }
7317
7490
  function recordEventToolHandler(db, input) {
7318
7491
  return withToolHandling(() => {
7492
+ const patched = {
7493
+ ...input.input,
7494
+ participants: prepareParticipants2(
7495
+ db,
7496
+ input.input.participants,
7497
+ input.kind !== "observation"
7498
+ )
7499
+ };
7319
7500
  switch (input.kind) {
7320
7501
  case "interaction":
7321
7502
  return mutationToolResult(
7322
7503
  "interaction",
7323
- recordInteraction(db, input.input),
7504
+ recordInteraction(db, patched),
7324
7505
  "event"
7325
7506
  );
7326
7507
  case "observation":
7327
7508
  return mutationToolResult(
7328
7509
  "observation",
7329
- recordObservation(db, input.input),
7510
+ recordObservation(db, patched),
7330
7511
  "event"
7331
7512
  );
7332
7513
  case "milestone":
7333
7514
  return mutationToolResult(
7334
7515
  "milestone",
7335
- recordMilestone(db, input.input),
7516
+ recordMilestone(db, patched),
7336
7517
  "event"
7337
7518
  );
7338
7519
  case "transaction":
7339
7520
  return mutationToolResult(
7340
7521
  "transaction",
7341
- recordTransaction(db, input.input),
7522
+ recordTransaction(db, patched),
7342
7523
  "event"
7343
7524
  );
7344
7525
  }
@@ -7346,7 +7527,7 @@ function recordEventToolHandler(db, input) {
7346
7527
  }
7347
7528
  var recordEventTool = defineAffinityTool({
7348
7529
  name: recordEventToolName,
7349
- description: "Record one social event such as an interaction, observation, milestone, or transaction.",
7530
+ description: "Record one social event such as an interaction, observation, milestone, or transaction. For interactions, milestones, and transactions the owner contact is auto-injected into participants if missing. Observations may omit the owner when recording third-party evidence.",
7350
7531
  whenToUse: "Use this when you are capturing something that happened in the relationship graph.",
7351
7532
  whenNotToUse: "Do not use this for commitments, date anchors, or direct relationship state overrides.",
7352
7533
  sideEffects: "writes_state",
@@ -7366,10 +7547,53 @@ var recordEventTool = defineAffinityTool({
7366
7547
  "milestone",
7367
7548
  "transaction"
7368
7549
  ]),
7369
- input: {
7370
- type: "object",
7371
- description: "Event payload. Shape depends on kind. Interaction events require a `type` subtype; others do not. Always required."
7372
- }
7550
+ input: objectSchema(
7551
+ {
7552
+ type: enumSchema(
7553
+ "Interaction subtype. Required when kind=interaction, omit otherwise.",
7554
+ [
7555
+ "conversation",
7556
+ "activity",
7557
+ "gift",
7558
+ "support",
7559
+ "conflict",
7560
+ "correction"
7561
+ ]
7562
+ ),
7563
+ occurredAt: integerSchema(
7564
+ "When the event occurred, Unix timestamp in milliseconds."
7565
+ ),
7566
+ summary: stringSchema("Event summary. Must be non-empty."),
7567
+ significance: integerSchema("Event significance from 1 to 10."),
7568
+ participants: arraySchema(
7569
+ objectSchema(
7570
+ {
7571
+ contactId: integerSchema(
7572
+ "Participant contact id. The owner contact MUST be included."
7573
+ ),
7574
+ role: enumSchema("Participant role.", [
7575
+ "actor",
7576
+ "recipient",
7577
+ "subject",
7578
+ "observer",
7579
+ "mentioned"
7580
+ ]),
7581
+ directionality: enumSchema("Optional directionality.", [
7582
+ "owner_initiated",
7583
+ "other_initiated",
7584
+ "mutual",
7585
+ "observed"
7586
+ ])
7587
+ },
7588
+ ["contactId", "role"]
7589
+ ),
7590
+ "Participant list. Must be non-empty and include the owner contact."
7591
+ ),
7592
+ now: integerSchema("Optional timestamp override.")
7593
+ },
7594
+ ["occurredAt", "summary", "significance", "participants"],
7595
+ "Event payload. Always required. Interaction events also require `type`."
7596
+ )
7373
7597
  },
7374
7598
  ["kind", "input"],
7375
7599
  "Record one social event."
@@ -7396,7 +7620,7 @@ function buildChartOptions(input) {
7396
7620
  ...input.contactIds === void 0 ? {} : { contactIds: input.contactIds }
7397
7621
  };
7398
7622
  }
7399
- function contactLocatorSchema7(description) {
7623
+ function contactLocatorSchema8(description) {
7400
7624
  return {
7401
7625
  type: "object",
7402
7626
  properties: {
@@ -7413,7 +7637,7 @@ function contactLocatorSchema7(description) {
7413
7637
  description
7414
7638
  };
7415
7639
  }
7416
- function linkLocatorSchema4(description) {
7640
+ function linkLocatorSchema5(description) {
7417
7641
  return {
7418
7642
  type: "object",
7419
7643
  properties: {
@@ -7832,8 +8056,8 @@ var reviewAffinityTool = defineAffinityTool({
7832
8056
  "graph.chart",
7833
8057
  "merges.history"
7834
8058
  ]),
7835
- contact: contactLocatorSchema7("Optional target contact locator."),
7836
- link: linkLocatorSchema4("Optional target link locator."),
8059
+ contact: contactLocatorSchema8("Optional target contact locator."),
8060
+ link: linkLocatorSchema5("Optional target link locator."),
7837
8061
  contactIds: arraySchema(
7838
8062
  integerSchema("Contact id."),
7839
8063
  "Optional contact-id subset."
package/dist/index.js CHANGED
@@ -6441,12 +6441,43 @@ var manageAttributeTool = defineAffinityTool({
6441
6441
  });
6442
6442
 
6443
6443
  // src/tools/manage_commitment_tool.ts
6444
+ function normalizeParticipant(p) {
6445
+ let contactId = p.contactId;
6446
+ if (contactId === void 0 && p.contact != null) {
6447
+ const loc = p.contact;
6448
+ contactId = loc.contactId;
6449
+ }
6450
+ const result = {
6451
+ contactId,
6452
+ role: p.role
6453
+ };
6454
+ if (p.directionality !== void 0) {
6455
+ result.directionality = p.directionality;
6456
+ }
6457
+ return result;
6458
+ }
6459
+ function ensureOwnerParticipates(db, participants) {
6460
+ const ownerId = findOwnerContactId(db);
6461
+ if (ownerId === null) return participants;
6462
+ if (participants.some((p) => p.contactId === ownerId)) return participants;
6463
+ return [{ contactId: ownerId, role: "actor" }, ...participants];
6464
+ }
6465
+ function prepareParticipants(db, raw) {
6466
+ return ensureOwnerParticipates(db, raw.map(normalizeParticipant));
6467
+ }
6444
6468
  function manageCommitmentToolHandler(db, input) {
6445
6469
  return withToolHandling(() => {
6446
6470
  if (input.action === "record") {
6471
+ const patched = {
6472
+ ...input.input,
6473
+ participants: prepareParticipants(
6474
+ db,
6475
+ input.input.participants
6476
+ )
6477
+ };
6447
6478
  return mutationToolResult(
6448
6479
  "record",
6449
- recordCommitment(db, input.input),
6480
+ recordCommitment(db, patched),
6450
6481
  "commitment"
6451
6482
  );
6452
6483
  }
@@ -6464,7 +6495,7 @@ function manageCommitmentToolHandler(db, input) {
6464
6495
  }
6465
6496
  var manageCommitmentTool = defineAffinityTool({
6466
6497
  name: manageCommitmentToolName,
6467
- description: "Record or resolve one commitment such as a promise or agreement.",
6498
+ description: "Record or resolve one commitment such as a promise or agreement. The owner contact is auto-injected into participants if missing.",
6468
6499
  whenToUse: "Use this when the work is specifically about a commitment lifecycle rather than a general event.",
6469
6500
  whenNotToUse: "Do not use this for ordinary interactions or direct relationship state changes.",
6470
6501
  sideEffects: "writes_state",
@@ -6482,10 +6513,42 @@ var manageCommitmentTool = defineAffinityTool({
6482
6513
  inputSchema: objectSchema(
6483
6514
  {
6484
6515
  action: enumSchema("Operation to perform.", ["record", "resolve"]),
6485
- input: {
6486
- type: "object",
6487
- description: "Commitment payload. Required when action=record."
6488
- },
6516
+ input: objectSchema(
6517
+ {
6518
+ commitmentType: enumSchema("Promise or agreement.", [
6519
+ "promise",
6520
+ "agreement"
6521
+ ]),
6522
+ occurredAt: integerSchema(
6523
+ "When the commitment was made, Unix timestamp in milliseconds."
6524
+ ),
6525
+ summary: stringSchema("Commitment summary. Must be non-empty."),
6526
+ significance: integerSchema("Commitment significance from 1 to 10."),
6527
+ dueAt: integerSchema("Optional due timestamp."),
6528
+ participants: arraySchema(
6529
+ objectSchema(
6530
+ {
6531
+ contactId: integerSchema(
6532
+ "Participant contact id. The owner contact MUST be included."
6533
+ ),
6534
+ role: stringSchema("Participant role."),
6535
+ directionality: stringSchema("Optional directionality.")
6536
+ },
6537
+ ["contactId", "role"]
6538
+ ),
6539
+ "Participant list. Must be non-empty and include the owner contact."
6540
+ ),
6541
+ now: integerSchema("Optional timestamp override.")
6542
+ },
6543
+ [
6544
+ "commitmentType",
6545
+ "occurredAt",
6546
+ "summary",
6547
+ "significance",
6548
+ "participants"
6549
+ ],
6550
+ "Commitment payload. Required when action=record."
6551
+ ),
6489
6552
  commitmentEventId: integerSchema(
6490
6553
  "Commitment event id. Required when action=resolve."
6491
6554
  ),
@@ -6642,6 +6705,43 @@ var manageContactTool = defineAffinityTool({
6642
6705
  });
6643
6706
 
6644
6707
  // src/tools/manage_date_anchor_tool.ts
6708
+ function contactLocatorSchema4(description) {
6709
+ return {
6710
+ type: "object",
6711
+ properties: {
6712
+ contactId: integerSchema("Exact contact id."),
6713
+ identity: objectSchema(
6714
+ {
6715
+ type: stringSchema("Identity type."),
6716
+ value: stringSchema("Identity value.")
6717
+ },
6718
+ ["type", "value"],
6719
+ "Contact identity locator."
6720
+ )
6721
+ },
6722
+ description
6723
+ };
6724
+ }
6725
+ function linkLocatorSchema3(description) {
6726
+ return {
6727
+ type: "object",
6728
+ properties: {
6729
+ linkId: integerSchema("Exact link id."),
6730
+ endpoints: objectSchema(
6731
+ {
6732
+ fromContactId: integerSchema("From contact id."),
6733
+ toContactId: integerSchema("To contact id."),
6734
+ kind: stringSchema("Optional link kind."),
6735
+ role: stringSchema("Optional link role."),
6736
+ isStructural: booleanSchema("Optional structural discriminator.")
6737
+ },
6738
+ ["fromContactId", "toContactId"],
6739
+ "Endpoint-based link locator."
6740
+ )
6741
+ },
6742
+ description
6743
+ };
6744
+ }
6645
6745
  function resolveDateAnchorTarget(db, target) {
6646
6746
  if (target.kind === "contact") {
6647
6747
  const contact = resolveContactLocator(db, target.contact, "target.contact");
@@ -6707,17 +6807,65 @@ var manageDateAnchorTool = defineAffinityTool({
6707
6807
  inputSchema: objectSchema(
6708
6808
  {
6709
6809
  action: enumSchema("Operation to perform.", ["add", "revise", "remove"]),
6710
- input: {
6711
- type: "object",
6712
- description: "Date anchor payload. Required when action=add."
6713
- },
6810
+ input: objectSchema(
6811
+ {
6812
+ target: objectSchema(
6813
+ {
6814
+ kind: enumSchema("Target kind.", ["contact", "link"]),
6815
+ contact: contactLocatorSchema4(
6816
+ "Contact locator. Required when kind=contact. Provide contactId or identity."
6817
+ ),
6818
+ link: linkLocatorSchema3(
6819
+ "Link locator. Required when kind=link. Provide linkId or endpoints."
6820
+ )
6821
+ },
6822
+ ["kind"],
6823
+ "Date-anchor target."
6824
+ ),
6825
+ recurrenceKind: enumSchema("Recurrence kind.", [
6826
+ "birthday",
6827
+ "anniversary",
6828
+ "renewal",
6829
+ "memorial",
6830
+ "custom_yearly"
6831
+ ]),
6832
+ anchorMonth: integerSchema("Anchor month, 1\u201312."),
6833
+ anchorDay: integerSchema("Anchor day, 1\u201331 (validated per month)."),
6834
+ summary: stringSchema("Summary. Must be non-empty."),
6835
+ significance: integerSchema("Significance from 1 to 10."),
6836
+ now: integerSchema("Optional timestamp override."),
6837
+ force: booleanSchema("Whether to bypass duplicate checks.")
6838
+ },
6839
+ [
6840
+ "target",
6841
+ "recurrenceKind",
6842
+ "anchorMonth",
6843
+ "anchorDay",
6844
+ "summary",
6845
+ "significance"
6846
+ ],
6847
+ "Date anchor payload. Required when action=add."
6848
+ ),
6714
6849
  anchorEventId: integerSchema(
6715
6850
  "Anchor event id. Required when action=revise or remove."
6716
6851
  ),
6717
- patch: {
6718
- type: "object",
6719
- description: "Anchor patch. Required when action=revise."
6720
- },
6852
+ patch: objectSchema(
6853
+ {
6854
+ recurrenceKind: enumSchema("Optional recurrence kind.", [
6855
+ "birthday",
6856
+ "anniversary",
6857
+ "renewal",
6858
+ "memorial",
6859
+ "custom_yearly"
6860
+ ]),
6861
+ anchorMonth: integerSchema("Optional month, 1\u201312."),
6862
+ anchorDay: integerSchema("Optional day, 1\u201331."),
6863
+ summary: stringSchema("Optional summary."),
6864
+ significance: integerSchema("Optional significance, 1\u201310.")
6865
+ },
6866
+ [],
6867
+ "Anchor patch. Required when action=revise."
6868
+ ),
6721
6869
  options: objectSchema(
6722
6870
  {
6723
6871
  now: integerSchema("Optional timestamp."),
@@ -6919,7 +7067,7 @@ function verifyIdentity(db, identityId, verifiedAt) {
6919
7067
  }
6920
7068
 
6921
7069
  // src/tools/manage_identity_tool.ts
6922
- function contactLocatorSchema4(description) {
7070
+ function contactLocatorSchema5(description) {
6923
7071
  return {
6924
7072
  type: "object",
6925
7073
  properties: {
@@ -6998,7 +7146,7 @@ var manageIdentityTool = defineAffinityTool({
6998
7146
  "verify",
6999
7147
  "remove"
7000
7148
  ]),
7001
- contact: contactLocatorSchema4(
7149
+ contact: contactLocatorSchema5(
7002
7150
  "Target contact. Required when action=add. Provide contactId or identity."
7003
7151
  ),
7004
7152
  input: objectSchema(
@@ -7038,7 +7186,7 @@ var manageIdentityTool = defineAffinityTool({
7038
7186
  });
7039
7187
 
7040
7188
  // src/tools/manage_relationship_tool.ts
7041
- function contactLocatorSchema5(description) {
7189
+ function contactLocatorSchema6(description) {
7042
7190
  return {
7043
7191
  type: "object",
7044
7192
  properties: {
@@ -7055,7 +7203,7 @@ function contactLocatorSchema5(description) {
7055
7203
  description
7056
7204
  };
7057
7205
  }
7058
- function linkLocatorSchema3(description) {
7206
+ function linkLocatorSchema4(description) {
7059
7207
  return {
7060
7208
  type: "object",
7061
7209
  properties: {
@@ -7194,14 +7342,14 @@ var manageRelationshipTool = defineAffinityTool({
7194
7342
  "set_structural_tie",
7195
7343
  "remove_structural_tie"
7196
7344
  ]),
7197
- from: contactLocatorSchema5(
7345
+ from: contactLocatorSchema6(
7198
7346
  "Source contact. Required when action=seed_social_link or set_structural_tie. Provide contactId or identity."
7199
7347
  ),
7200
- to: contactLocatorSchema5(
7348
+ to: contactLocatorSchema6(
7201
7349
  "Target contact. Required when action=seed_social_link or set_structural_tie. Provide contactId or identity."
7202
7350
  ),
7203
7351
  kind: stringSchema(
7204
- "Link kind. Required for seed_social_link and set_structural_tie. Can be passed here or inside input."
7352
+ "Link kind. Required for seed_social_link and set_structural_tie. Can be passed here or inside input. For seed_social_link: personal, family, professional, romantic, care, service, observed, other_relational. For set_structural_tie: works_at, manages, member_of, married_to, partner_of, parent_of, child_of, sibling_of, friend_of, client_of, vendor_of, reports_to, belongs_to, other_structural."
7205
7353
  ),
7206
7354
  role: stringSchema(
7207
7355
  "Optional role for seed_social_link or set_structural_tie. Can be passed here or inside input."
@@ -7210,7 +7358,7 @@ var manageRelationshipTool = defineAffinityTool({
7210
7358
  type: "object",
7211
7359
  description: "Full payload for seed_social_link or set_structural_tie. Alternative to top-level kind/role."
7212
7360
  },
7213
- link: linkLocatorSchema3(
7361
+ link: linkLocatorSchema4(
7214
7362
  "Target link. Required when action=revise_bond, override_state, or remove_structural_tie. Provide linkId or endpoints."
7215
7363
  ),
7216
7364
  bond: nullableStringSchema(
@@ -7239,7 +7387,7 @@ var manageRelationshipTool = defineAffinityTool({
7239
7387
  });
7240
7388
 
7241
7389
  // src/tools/merge_contacts_tool.ts
7242
- function contactLocatorSchema6(description) {
7390
+ function contactLocatorSchema7(description) {
7243
7391
  return {
7244
7392
  type: "object",
7245
7393
  properties: {
@@ -7296,10 +7444,10 @@ var mergeContactsTool = defineAffinityTool({
7296
7444
  outputDescription: "Returns the merge receipt with rewired entities and affected-link information.",
7297
7445
  inputSchema: objectSchema(
7298
7446
  {
7299
- winner: contactLocatorSchema6(
7447
+ winner: contactLocatorSchema7(
7300
7448
  "Winner contact. Provide contactId or identity."
7301
7449
  ),
7302
- loser: contactLocatorSchema6(
7450
+ loser: contactLocatorSchema7(
7303
7451
  "Loser contact. Provide contactId or identity."
7304
7452
  ),
7305
7453
  reasonSummary: stringSchema("Optional merge reason."),
@@ -7312,31 +7460,64 @@ var mergeContactsTool = defineAffinityTool({
7312
7460
  });
7313
7461
 
7314
7462
  // src/tools/record_event_tool.ts
7463
+ function normalizeParticipant2(p) {
7464
+ let contactId = p.contactId;
7465
+ if (contactId === void 0 && p.contact != null) {
7466
+ const loc = p.contact;
7467
+ contactId = loc.contactId;
7468
+ }
7469
+ const result = {
7470
+ contactId,
7471
+ role: p.role
7472
+ };
7473
+ if (p.directionality !== void 0) {
7474
+ result.directionality = p.directionality;
7475
+ }
7476
+ return result;
7477
+ }
7478
+ function ensureOwnerParticipates2(db, participants) {
7479
+ const ownerId = findOwnerContactId(db);
7480
+ if (ownerId === null) return participants;
7481
+ if (participants.some((p) => p.contactId === ownerId)) return participants;
7482
+ return [{ contactId: ownerId, role: "actor" }, ...participants];
7483
+ }
7484
+ function prepareParticipants2(db, raw, injectOwner) {
7485
+ const normalized = raw.map(normalizeParticipant2);
7486
+ return injectOwner ? ensureOwnerParticipates2(db, normalized) : normalized;
7487
+ }
7315
7488
  function recordEventToolHandler(db, input) {
7316
7489
  return withToolHandling(() => {
7490
+ const patched = {
7491
+ ...input.input,
7492
+ participants: prepareParticipants2(
7493
+ db,
7494
+ input.input.participants,
7495
+ input.kind !== "observation"
7496
+ )
7497
+ };
7317
7498
  switch (input.kind) {
7318
7499
  case "interaction":
7319
7500
  return mutationToolResult(
7320
7501
  "interaction",
7321
- recordInteraction(db, input.input),
7502
+ recordInteraction(db, patched),
7322
7503
  "event"
7323
7504
  );
7324
7505
  case "observation":
7325
7506
  return mutationToolResult(
7326
7507
  "observation",
7327
- recordObservation(db, input.input),
7508
+ recordObservation(db, patched),
7328
7509
  "event"
7329
7510
  );
7330
7511
  case "milestone":
7331
7512
  return mutationToolResult(
7332
7513
  "milestone",
7333
- recordMilestone(db, input.input),
7514
+ recordMilestone(db, patched),
7334
7515
  "event"
7335
7516
  );
7336
7517
  case "transaction":
7337
7518
  return mutationToolResult(
7338
7519
  "transaction",
7339
- recordTransaction(db, input.input),
7520
+ recordTransaction(db, patched),
7340
7521
  "event"
7341
7522
  );
7342
7523
  }
@@ -7344,7 +7525,7 @@ function recordEventToolHandler(db, input) {
7344
7525
  }
7345
7526
  var recordEventTool = defineAffinityTool({
7346
7527
  name: recordEventToolName,
7347
- description: "Record one social event such as an interaction, observation, milestone, or transaction.",
7528
+ description: "Record one social event such as an interaction, observation, milestone, or transaction. For interactions, milestones, and transactions the owner contact is auto-injected into participants if missing. Observations may omit the owner when recording third-party evidence.",
7348
7529
  whenToUse: "Use this when you are capturing something that happened in the relationship graph.",
7349
7530
  whenNotToUse: "Do not use this for commitments, date anchors, or direct relationship state overrides.",
7350
7531
  sideEffects: "writes_state",
@@ -7364,10 +7545,53 @@ var recordEventTool = defineAffinityTool({
7364
7545
  "milestone",
7365
7546
  "transaction"
7366
7547
  ]),
7367
- input: {
7368
- type: "object",
7369
- description: "Event payload. Shape depends on kind. Interaction events require a `type` subtype; others do not. Always required."
7370
- }
7548
+ input: objectSchema(
7549
+ {
7550
+ type: enumSchema(
7551
+ "Interaction subtype. Required when kind=interaction, omit otherwise.",
7552
+ [
7553
+ "conversation",
7554
+ "activity",
7555
+ "gift",
7556
+ "support",
7557
+ "conflict",
7558
+ "correction"
7559
+ ]
7560
+ ),
7561
+ occurredAt: integerSchema(
7562
+ "When the event occurred, Unix timestamp in milliseconds."
7563
+ ),
7564
+ summary: stringSchema("Event summary. Must be non-empty."),
7565
+ significance: integerSchema("Event significance from 1 to 10."),
7566
+ participants: arraySchema(
7567
+ objectSchema(
7568
+ {
7569
+ contactId: integerSchema(
7570
+ "Participant contact id. The owner contact MUST be included."
7571
+ ),
7572
+ role: enumSchema("Participant role.", [
7573
+ "actor",
7574
+ "recipient",
7575
+ "subject",
7576
+ "observer",
7577
+ "mentioned"
7578
+ ]),
7579
+ directionality: enumSchema("Optional directionality.", [
7580
+ "owner_initiated",
7581
+ "other_initiated",
7582
+ "mutual",
7583
+ "observed"
7584
+ ])
7585
+ },
7586
+ ["contactId", "role"]
7587
+ ),
7588
+ "Participant list. Must be non-empty and include the owner contact."
7589
+ ),
7590
+ now: integerSchema("Optional timestamp override.")
7591
+ },
7592
+ ["occurredAt", "summary", "significance", "participants"],
7593
+ "Event payload. Always required. Interaction events also require `type`."
7594
+ )
7371
7595
  },
7372
7596
  ["kind", "input"],
7373
7597
  "Record one social event."
@@ -7394,7 +7618,7 @@ function buildChartOptions(input) {
7394
7618
  ...input.contactIds === void 0 ? {} : { contactIds: input.contactIds }
7395
7619
  };
7396
7620
  }
7397
- function contactLocatorSchema7(description) {
7621
+ function contactLocatorSchema8(description) {
7398
7622
  return {
7399
7623
  type: "object",
7400
7624
  properties: {
@@ -7411,7 +7635,7 @@ function contactLocatorSchema7(description) {
7411
7635
  description
7412
7636
  };
7413
7637
  }
7414
- function linkLocatorSchema4(description) {
7638
+ function linkLocatorSchema5(description) {
7415
7639
  return {
7416
7640
  type: "object",
7417
7641
  properties: {
@@ -7830,8 +8054,8 @@ var reviewAffinityTool = defineAffinityTool({
7830
8054
  "graph.chart",
7831
8055
  "merges.history"
7832
8056
  ]),
7833
- contact: contactLocatorSchema7("Optional target contact locator."),
7834
- link: linkLocatorSchema4("Optional target link locator."),
8057
+ contact: contactLocatorSchema8("Optional target contact locator."),
8058
+ link: linkLocatorSchema5("Optional target link locator."),
7835
8059
  contactIds: arraySchema(
7836
8060
  integerSchema("Contact id."),
7837
8061
  "Optional contact-id subset."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostpaw/affinity",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Relationship intelligence and social CRM model for Node.js — SQLite, zero dependencies, with a built-in LLM tool facade",
5
5
  "license": "MIT",
6
6
  "author": {