@ghostpaw/affinity 0.6.0 → 0.6.1
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/README.md +19 -6
- package/dist/cli.js +99 -35
- package/dist/index.cjs +69 -26
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +69 -26
- package/dist/mcp-server.js +86 -27
- package/dist/mcp.cjs +83 -27
- package/dist/mcp.js +83 -27
- package/package.json +1 -1
- package/skills/affinity/references/import-history-without-faking-evidence.md +1 -1
- package/skills/affinity/references/record-direct-evidence-well.md +1 -1
- package/skills/affinity/references/record-observations-and-referrals.md +2 -1
- package/skills/affinity/references/tools.md +7 -6
package/dist/mcp.js
CHANGED
|
@@ -3,7 +3,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
|
|
5
5
|
// src/version.ts
|
|
6
|
-
var affinityVersion = "0.6.
|
|
6
|
+
var affinityVersion = "0.6.1";
|
|
7
7
|
|
|
8
8
|
// src/surface/affinity_mcp_instructions.ts
|
|
9
9
|
var affinityMcpInstructions = "Affinity is a local relationship model and social CRM. Search before creating contacts. Inspect before revising or merging. Record direct evidence honestly, keep identities and structural ties distinct from social links, and ask for clarification when a target is ambiguous. Review commitments and recurring dates regularly. Derived scores guide attention and do not prove relationship quality.";
|
|
@@ -380,6 +380,8 @@ function mapEventRowToEventRecord(row, participants) {
|
|
|
380
380
|
momentKind: row.moment_kind,
|
|
381
381
|
participants
|
|
382
382
|
};
|
|
383
|
+
if (row.provenance_json != null)
|
|
384
|
+
base.provenance = JSON.parse(row.provenance_json);
|
|
383
385
|
if (row.content != null) base.content = decodeEventText(row.content);
|
|
384
386
|
if (row.channel != null) base.channel = row.channel;
|
|
385
387
|
if (row.external_source != null && row.external_id != null)
|
|
@@ -670,14 +672,9 @@ function parseCalendarTime(value, field = "time", now = Date.now()) {
|
|
|
670
672
|
text = text.replace(" ", "T");
|
|
671
673
|
if (!/(?:Z|[+-]\d{2}:\d{2})$/.test(text)) text += "Z";
|
|
672
674
|
}
|
|
673
|
-
let rounding = 0;
|
|
674
675
|
text = text.replace(
|
|
675
676
|
/\.(\d{4,})(?=Z|[+-]\d{2}:\d{2}$)/,
|
|
676
|
-
(_, digits) => {
|
|
677
|
-
const ms = Math.round(Number(`0.${digits}`) * 1e3);
|
|
678
|
-
rounding = ms === 1e3 ? 1 : 0;
|
|
679
|
-
return `.${String(ms === 1e3 ? 999 : ms).padStart(3, "0")}`;
|
|
680
|
-
}
|
|
677
|
+
(_, digits) => `.${digits.slice(0, 3)}`
|
|
681
678
|
);
|
|
682
679
|
if (/^(today|yesterday|tomorrow|[+-]\d+d)$/.test(text)) {
|
|
683
680
|
const offset = text === "today" ? 0 : text === "tomorrow" ? 1 : text === "yesterday" ? -1 : Number(text.slice(0, -1));
|
|
@@ -697,7 +694,7 @@ function parseCalendarTime(value, field = "time", now = Date.now()) {
|
|
|
697
694
|
const midnight = Date.parse(`${day}T00:00:00Z`);
|
|
698
695
|
if (!Number.isFinite(midnight) || new Date(midnight).toISOString().slice(0, 10) !== day)
|
|
699
696
|
return fail();
|
|
700
|
-
const timestamp = dateOnly ? midnight + (field.split(".").at(-1) === "dueAt" ? 86399999 : 0) : Date.parse(text)
|
|
697
|
+
const timestamp = dateOnly ? midnight + (field.split(".").at(-1) === "dueAt" ? 86399999 : 0) : Date.parse(text);
|
|
701
698
|
if (!Number.isFinite(timestamp)) return fail();
|
|
702
699
|
return { timestamp, day };
|
|
703
700
|
}
|
|
@@ -1737,7 +1734,7 @@ var externalRefSchema = objectSchema(
|
|
|
1737
1734
|
);
|
|
1738
1735
|
var eventMetadataSchema = {
|
|
1739
1736
|
affectsBond: booleanSchema(
|
|
1740
|
-
"Whether evidence affects the relationship; defaults false for observations with significance <=2."
|
|
1737
|
+
"Whether evidence affects the relationship; defaults false for like/follow/repost labels and observations with significance <=2; explicit true opts in."
|
|
1741
1738
|
),
|
|
1742
1739
|
content: stringSchema(
|
|
1743
1740
|
"Verbatim text, including empty text; at most 1 MB UTF-8. Summary may be omitted when content is supplied."
|
|
@@ -2287,6 +2284,13 @@ function validateToolInput(schema, value, path = "input", injectedNow = Date.now
|
|
|
2287
2284
|
`${path}.${key}`,
|
|
2288
2285
|
referenceNow
|
|
2289
2286
|
);
|
|
2287
|
+
if (!path.endsWith(".patch") && ["occurredAt", "dueAt"].includes(key) && typeof object[key] === "string" && /\.\d{4,}/.test(object[key])) {
|
|
2288
|
+
const provenance = object.provenance;
|
|
2289
|
+
object.provenance = {
|
|
2290
|
+
...provenance && typeof provenance === "object" ? provenance : {},
|
|
2291
|
+
[`raw${key[0]?.toUpperCase()}${key.slice(1)}`]: object[key]
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
2290
2294
|
object[key] = parsed.timestamp;
|
|
2291
2295
|
if (!path.endsWith(".patch") && ["occurredAt", "dueAt"].includes(key))
|
|
2292
2296
|
object[key.replace(/At$/, "On")] ??= parsed.day;
|
|
@@ -2304,7 +2308,7 @@ function validateToolInput(schema, value, path = "input", injectedNow = Date.now
|
|
|
2304
2308
|
const error = validateToolInput(
|
|
2305
2309
|
child,
|
|
2306
2310
|
object[key],
|
|
2307
|
-
`${path}.${key}`,
|
|
2311
|
+
key === "input" && path === "input" ? path : `${path}.${key}`,
|
|
2308
2312
|
referenceNow,
|
|
2309
2313
|
strict
|
|
2310
2314
|
);
|
|
@@ -2741,6 +2745,11 @@ function setAttribute(db, target, name, value) {
|
|
|
2741
2745
|
const stored = normalizeAttributeValue(value);
|
|
2742
2746
|
const now = resolveNow();
|
|
2743
2747
|
const existing = getLiveAttributeRow(db, target, key);
|
|
2748
|
+
if (existing?.value === stored)
|
|
2749
|
+
return buildAttributeMutationReceipt(
|
|
2750
|
+
mapAttributeRowToAttributeRecord(existing),
|
|
2751
|
+
{}
|
|
2752
|
+
);
|
|
2744
2753
|
if (existing) {
|
|
2745
2754
|
db.prepare(
|
|
2746
2755
|
"UPDATE attributes SET value = ?, updated_at = ? WHERE id = ?"
|
|
@@ -2880,7 +2889,30 @@ function linkLocatorSchema2(description) {
|
|
|
2880
2889
|
};
|
|
2881
2890
|
}
|
|
2882
2891
|
function resolveAttributeTarget(db, target) {
|
|
2883
|
-
if (target.kind === "event")
|
|
2892
|
+
if (target.kind === "event") {
|
|
2893
|
+
if (target.eventId === void 0 === (target.ref === void 0))
|
|
2894
|
+
return {
|
|
2895
|
+
kind: "error",
|
|
2896
|
+
result: toolFailure(
|
|
2897
|
+
"protocol",
|
|
2898
|
+
"invalid_input",
|
|
2899
|
+
"Invalid event target.",
|
|
2900
|
+
"Provide exactly one of target.eventId or target.ref."
|
|
2901
|
+
)
|
|
2902
|
+
};
|
|
2903
|
+
const eventId = target.eventId ?? (target.ref && getEventByExternalRef(db, target.ref.source, target.ref.id)?.id);
|
|
2904
|
+
if (eventId === void 0)
|
|
2905
|
+
return {
|
|
2906
|
+
kind: "error",
|
|
2907
|
+
result: toolFailure(
|
|
2908
|
+
"domain",
|
|
2909
|
+
"not_found",
|
|
2910
|
+
"Event not found.",
|
|
2911
|
+
"No event matches target.ref."
|
|
2912
|
+
)
|
|
2913
|
+
};
|
|
2914
|
+
return { kind: "ok", target: { kind: "event", eventId } };
|
|
2915
|
+
}
|
|
2884
2916
|
if (target.kind === "contact") {
|
|
2885
2917
|
const contact = resolveContactLocator(db, target.contact, "target.contact");
|
|
2886
2918
|
if (!contact.ok) {
|
|
@@ -2962,7 +2994,8 @@ var manageAttributeTool = defineAffinityTool({
|
|
|
2962
2994
|
target: objectSchema(
|
|
2963
2995
|
{
|
|
2964
2996
|
kind: enumSchema("Target kind.", ["contact", "link", "event"]),
|
|
2965
|
-
eventId: integerSchema("Target event id."),
|
|
2997
|
+
eventId: integerSchema("Target event id; provide eventId or ref."),
|
|
2998
|
+
ref: externalRefSchema,
|
|
2966
2999
|
contact: contactLocatorSchema2(
|
|
2967
3000
|
"Contact locator. Required when kind=contact. Provide contactId or identity."
|
|
2968
3001
|
),
|
|
@@ -3018,7 +3051,9 @@ function insertJournalEvent(db, params) {
|
|
|
3018
3051
|
);
|
|
3019
3052
|
const eventId = Number(result.lastInsertRowid);
|
|
3020
3053
|
db.prepare("UPDATE events SET affects_bond=? WHERE id=?").run(
|
|
3021
|
-
params.affectsBond === void 0 ? params.type === "observation" && params.significance <= 2
|
|
3054
|
+
params.affectsBond === void 0 ? params.type === "observation" && params.significance <= 2 || ["activity", "milestone", "observation"].includes(params.type) && /^(?:follow(?:ed|ing)?|like(?:d)?|repost(?:ed)?)(?:\b|[-_])/i.test(
|
|
3055
|
+
summary
|
|
3056
|
+
) && !/^follow[ -]up\b/i.test(summary) ? 0 : 1 : Number(params.affectsBond),
|
|
3022
3057
|
eventId
|
|
3023
3058
|
);
|
|
3024
3059
|
db.prepare("UPDATE events SET declared_moment_kind=? WHERE id=?").run(
|
|
@@ -4690,7 +4725,7 @@ function exportContact(db, id) {
|
|
|
4690
4725
|
const contact = query("SELECT * FROM contacts WHERE id = ?", id)[0];
|
|
4691
4726
|
if (!contact) throw new AffinityNotFoundError("contact not found");
|
|
4692
4727
|
const events = query(
|
|
4693
|
-
"SELECT DISTINCT e.*, CAST(e.content AS BLOB) AS content, CAST(e.summary AS BLOB) AS summary FROM events e JOIN event_participants p ON p.event_id = e.id WHERE p.contact_id = ? AND e.type != 'date_anchor' ORDER BY e.id",
|
|
4728
|
+
"SELECT DISTINCT e.*, COALESCE(e.parent_event_id, (SELECT parent.id FROM events parent WHERE parent.external_source=e.parent_source AND parent.external_id=e.parent_ref_id AND parent.deleted_at IS NULL)) AS parent_event_id, CAST(e.content AS BLOB) AS content, CAST(e.summary AS BLOB) AS summary FROM events e JOIN event_participants p ON p.event_id = e.id WHERE p.contact_id = ? AND e.type != 'date_anchor' ORDER BY e.id",
|
|
4694
4729
|
id
|
|
4695
4730
|
).map((event) => ({
|
|
4696
4731
|
...event,
|
|
@@ -7831,12 +7866,14 @@ function getEventThread(db, source, id, options) {
|
|
|
7831
7866
|
const rows = db.prepare(`WITH RECURSIVE thread(id) AS (
|
|
7832
7867
|
SELECT ? UNION SELECT e.id FROM events e JOIN thread t JOIN events p ON p.id=t.id
|
|
7833
7868
|
WHERE e.deleted_at IS NULL AND (e.parent_event_id=p.id OR (e.parent_source=p.external_source AND e.parent_ref_id=p.external_id) OR (e.thread_source=? AND e.thread_id=?))
|
|
7834
|
-
) SELECT e.id FROM events e JOIN thread t ON e.id=t.id WHERE e.deleted_at IS NULL AND (? IS NULL OR e.channel=?) ORDER BY e.occurred_at,e.id LIMIT ? OFFSET ?`).all(
|
|
7869
|
+
) SELECT e.id FROM events e JOIN thread t ON e.id=t.id WHERE e.deleted_at IS NULL AND (? IS NULL OR e.channel=?) AND (? IS NULL OR e.type IN (SELECT value FROM json_each(?))) ORDER BY e.occurred_at,e.id LIMIT ? OFFSET ?`).all(
|
|
7835
7870
|
root.id,
|
|
7836
7871
|
root.externalRef?.source ?? null,
|
|
7837
7872
|
root.externalRef?.id ?? null,
|
|
7838
7873
|
options?.channel ?? null,
|
|
7839
7874
|
options?.channel?.trim().toLowerCase() ?? null,
|
|
7875
|
+
options?.eventTypes === void 0 ? null : JSON.stringify(options.eventTypes),
|
|
7876
|
+
options?.eventTypes === void 0 ? null : JSON.stringify(options.eventTypes),
|
|
7840
7877
|
limit,
|
|
7841
7878
|
offset
|
|
7842
7879
|
);
|
|
@@ -8488,12 +8525,12 @@ function reviewPage(db, rawInput, pageOnly) {
|
|
|
8488
8525
|
if (!pageOnly && input.view !== "graph.chart") {
|
|
8489
8526
|
const limit = input.limit ?? 50;
|
|
8490
8527
|
const offset = input.offset ?? 0;
|
|
8491
|
-
if (!Number.isInteger(limit) || limit < 1 || limit >
|
|
8528
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 1e4 || !Number.isInteger(offset) || offset < 0)
|
|
8492
8529
|
return toolFailure(
|
|
8493
8530
|
"protocol",
|
|
8494
8531
|
"invalid_input",
|
|
8495
8532
|
"Invalid pagination.",
|
|
8496
|
-
"limit must be 1..
|
|
8533
|
+
"limit must be 1..10000; use offset to page through larger results; offset must be non-negative"
|
|
8497
8534
|
);
|
|
8498
8535
|
const all = [];
|
|
8499
8536
|
let page;
|
|
@@ -8545,7 +8582,7 @@ function reviewPage(db, rawInput, pageOnly) {
|
|
|
8545
8582
|
{
|
|
8546
8583
|
...input.contactIds === void 0 ? {} : { contactIds: input.contactIds },
|
|
8547
8584
|
...input.exactOnly === void 0 ? {} : { exactOnly: input.exactOnly },
|
|
8548
|
-
...input.minScore === void 0 ? {} : { minScore: input.minScore },
|
|
8585
|
+
...input.minScore === void 0 ? { minScore: 0.5 } : { minScore: input.minScore },
|
|
8549
8586
|
...input.includeDismissed === void 0 ? {} : { includeDismissed: input.includeDismissed }
|
|
8550
8587
|
},
|
|
8551
8588
|
options
|
|
@@ -8559,9 +8596,10 @@ function reviewPage(db, rawInput, pageOnly) {
|
|
|
8559
8596
|
"Missing thread reference.",
|
|
8560
8597
|
"ref is required for events.thread."
|
|
8561
8598
|
);
|
|
8562
|
-
items = getEventThread(db, input.ref.source, input.ref.id,
|
|
8563
|
-
|
|
8564
|
-
|
|
8599
|
+
items = getEventThread(db, input.ref.source, input.ref.id, {
|
|
8600
|
+
...options,
|
|
8601
|
+
...input.eventTypes === void 0 ? {} : { eventTypes: input.eventTypes }
|
|
8602
|
+
}).map(toEventListToolItem);
|
|
8565
8603
|
break;
|
|
8566
8604
|
}
|
|
8567
8605
|
case "events.contact_journal": {
|
|
@@ -8820,7 +8858,7 @@ var reviewAffinityTool = defineAffinityTool({
|
|
|
8820
8858
|
includeDismissed: "Whether dismissed pairs should be included in duplicate review (marked with dismissed flag).",
|
|
8821
8859
|
since: "Optional lower timestamp bound for time-based views.",
|
|
8822
8860
|
until: "Optional upper timestamp bound for time-based views.",
|
|
8823
|
-
limit: "Optional result limit.",
|
|
8861
|
+
limit: "Optional result limit, 1..10000 (default 50); use offset for paging.",
|
|
8824
8862
|
offset: "Optional result offset."
|
|
8825
8863
|
},
|
|
8826
8864
|
outputDescription: "Returns compact review items, a count, the applied filters, and the chart payload for graph review.",
|
|
@@ -8925,13 +8963,17 @@ var reviewAffinityTool = defineAffinityTool({
|
|
|
8925
8963
|
]),
|
|
8926
8964
|
horizonDays: integerSchema("Optional horizon-days filter."),
|
|
8927
8965
|
exactOnly: booleanSchema("Whether duplicate review is exact-only."),
|
|
8928
|
-
minScore: numberSchema(
|
|
8966
|
+
minScore: numberSchema(
|
|
8967
|
+
"Optional duplicate minimum score (default 0.5; use 0 for all candidates)."
|
|
8968
|
+
),
|
|
8929
8969
|
includeDismissed: booleanSchema(
|
|
8930
8970
|
"Whether dismissed pairs are included in duplicate review (marked with dismissed flag)."
|
|
8931
8971
|
),
|
|
8932
8972
|
since: integerSchema("Optional lower timestamp bound."),
|
|
8933
8973
|
until: integerSchema("Optional upper timestamp bound."),
|
|
8934
|
-
limit: integerSchema(
|
|
8974
|
+
limit: integerSchema(
|
|
8975
|
+
"Optional result limit, 1..10000 (default 50); use offset for paging."
|
|
8976
|
+
),
|
|
8935
8977
|
offset: integerSchema("Optional result offset.")
|
|
8936
8978
|
},
|
|
8937
8979
|
["view"],
|
|
@@ -9225,10 +9267,18 @@ function normalizeTimeInputs(value, now = Date.now(), inPatch = false) {
|
|
|
9225
9267
|
`Invalid timestamp "${item}". ${error.message}`
|
|
9226
9268
|
);
|
|
9227
9269
|
}
|
|
9270
|
+
if (!inPatch && ["occurredAt", "dueAt"].includes(key) && typeof item === "string" && /\.\d{4,}/.test(item)) {
|
|
9271
|
+
const provenance = result.provenance ?? value.provenance;
|
|
9272
|
+
result.provenance = {
|
|
9273
|
+
...provenance && typeof provenance === "object" ? provenance : {},
|
|
9274
|
+
[`raw${key[0]?.toUpperCase()}${key.slice(1)}`]: item
|
|
9275
|
+
};
|
|
9276
|
+
}
|
|
9228
9277
|
result[key] = parsed.timestamp;
|
|
9229
9278
|
if (!inPatch && ["occurredAt", "dueAt"].includes(key))
|
|
9230
9279
|
result[key.replace(/At$/, "On")] = parsed.day;
|
|
9231
|
-
} else
|
|
9280
|
+
} else if (key !== "provenance" || result.provenance === void 0)
|
|
9281
|
+
result[key] = key === "provenance" ? item : normalizeTimeInputs(item, now, key === "patch");
|
|
9232
9282
|
}
|
|
9233
9283
|
return result;
|
|
9234
9284
|
}
|
|
@@ -9260,6 +9310,12 @@ function timestampSchema(schema) {
|
|
|
9260
9310
|
function surfaceProperties(tool) {
|
|
9261
9311
|
return {
|
|
9262
9312
|
...tool.inputSchema.properties,
|
|
9313
|
+
...tool.name === "review_affinity" ? {
|
|
9314
|
+
includeContent: {
|
|
9315
|
+
type: "boolean",
|
|
9316
|
+
description: "Deprecated alias for --with-content; includes verbatim event content."
|
|
9317
|
+
}
|
|
9318
|
+
} : {},
|
|
9263
9319
|
...["inspect_affinity_item", "review_affinity", "manage_event"].includes(
|
|
9264
9320
|
tool.name
|
|
9265
9321
|
) ? {
|
|
@@ -9860,9 +9916,9 @@ async function openAffinityDb(path) {
|
|
|
9860
9916
|
}
|
|
9861
9917
|
const db = new sqlite.DatabaseSync(path);
|
|
9862
9918
|
try {
|
|
9863
|
-
db.exec("PRAGMA
|
|
9919
|
+
db.exec("PRAGMA busy_timeout=5000; PRAGMA journal_mode=WAL;");
|
|
9864
9920
|
const context = db;
|
|
9865
|
-
initAffinityTables(context);
|
|
9921
|
+
withTransaction(context, () => initAffinityTables(context));
|
|
9866
9922
|
return context;
|
|
9867
9923
|
} catch (error) {
|
|
9868
9924
|
db.close();
|
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@ Use ghostpaw-affinity batch [--chunk 500] with JSONL {tool,args}, or
|
|
|
12
12
|
Use externalRef {source:"bluesky",id:recordUri}, verbatim content and channel.
|
|
13
13
|
Participant contact locators may use identities, including did, instead of ids.
|
|
14
14
|
Read JSON flags from stdin with --input - or from @file for large payloads (E2BIG).
|
|
15
|
-
SQLite date-times without offsets mean UTC; microseconds
|
|
15
|
+
SQLite date-times without offsets mean UTC; microseconds truncate to milliseconds; raw timestamps remain in provenance.
|
|
16
16
|
Missing inbound-follow timestamps should use a known first_seen or be counted as skipped.
|
|
17
17
|
The synthetic scripts/examples/import_social_jsonl.mjs and import_dry_run.mjs
|
|
18
18
|
show the mapping and verify an idempotent retry and byte-identical text.
|
|
@@ -11,7 +11,7 @@ arrive. Commitments and resolutions never reset contact recency or cadence.
|
|
|
11
11
|
Imported text and event maintenance:
|
|
12
12
|
- Use externalRef: {source, id} for idempotent intake; retries return no_op and the existing id.
|
|
13
13
|
- Store verbatim text in content (up to 1,048,576 UTF-8 bytes, empty allowed). Summary is optional when content exists; its derived label is at most 140 characters.
|
|
14
|
-
- Use channel for the medium, parentRef or parentEventId for replies, and threadRef for the root. Event attributes use target {kind: "event", eventId}.
|
|
14
|
+
- Use channel for the medium, parentRef or parentEventId for replies, and threadRef for the root. Event attributes use target {kind: "event", eventId} or {kind: "event", ref: {source, id}}. Unchanged values return no_op.
|
|
15
15
|
- Inspect kind "event" by eventId or ref. Search scope "events" or "all" discovers event ids; default scope remains contacts.
|
|
16
16
|
- Review journals/timelines with includeContent: true only when needed; CLI uses --with-content. Filter with channel. Review events.thread by ref for chronological context.
|
|
17
17
|
- Use manage_event revise with patch: summary, content, occurredAt, significance, channel, type within the same kind, or externalRef only when absent. Unknown keys fail validation.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Record Observations And Referrals
|
|
2
2
|
|
|
3
3
|
Likes, reposts and follows are ambient observations, not milestones. Record them
|
|
4
|
-
with affectsBond:false
|
|
4
|
+
with affectsBond:false. Like/follow/repost labels default to false across families;
|
|
5
|
+
explicit true opts in. Observations with significance <=2 also default to false.
|
|
5
6
|
They stay in journals but do not change affinity or meaningful-contact recency.
|
|
6
7
|
provenance.ambient:true also suppresses effects. Use explicit owner and other
|
|
7
8
|
participants, actor/recipient roles, and the correct directionality.
|
|
@@ -58,7 +58,7 @@ Read-only.
|
|
|
58
58
|
| Parameter | Type | Required | Values / description |
|
|
59
59
|
| --- | --- | --- | --- |
|
|
60
60
|
| ref | object | no | |
|
|
61
|
-
| includeContent | boolean | no |
|
|
61
|
+
| includeContent | boolean | no | Deprecated alias for --with-content; includes verbatim event content. |
|
|
62
62
|
| channel | string | no | Filter events by channel. |
|
|
63
63
|
| view | string | yes | contacts.list, contacts.duplicates, events.thread, events.contact_journal, events.link_timeline, events.moments, commitments.open, links.owner, links.observed, links.progression_readiness, links.radar, dates.upcoming, graph.chart, merges.history, merges.dismissed. Which review surface to return. |
|
|
64
64
|
| now | integer / string | no | Optional current timestamp for overdue calculations. Accepts epoch milliseconds integer, ISO 8601 date-time with Z/offset, YYYY-MM-DD, DD.MM.YYYY, today, tomorrow, yesterday, +3d or -2d. UTC midnight for dates; dueAt uses UTC end of day. |
|
|
@@ -81,11 +81,11 @@ Read-only.
|
|
|
81
81
|
| recurrenceKind | string | no | birthday, anniversary, renewal, memorial, custom_yearly. Optional recurrence-kind filter. |
|
|
82
82
|
| horizonDays | integer | no | Optional horizon-days filter. |
|
|
83
83
|
| exactOnly | boolean | no | Whether duplicate review is exact-only. |
|
|
84
|
-
| minScore | number | no | Optional duplicate minimum score. |
|
|
84
|
+
| minScore | number | no | Optional duplicate minimum score (default 0.5; use 0 for all candidates). |
|
|
85
85
|
| includeDismissed | boolean | no | Whether dismissed pairs are included in duplicate review (marked with dismissed flag). |
|
|
86
86
|
| since | integer / string | no | Optional lower timestamp bound. Accepts epoch milliseconds integer, ISO 8601 date-time with Z/offset, YYYY-MM-DD, DD.MM.YYYY, today, tomorrow, yesterday, +3d or -2d. UTC midnight for dates; dueAt uses UTC end of day. |
|
|
87
87
|
| until | integer / string | no | Optional upper timestamp bound. Accepts epoch milliseconds integer, ISO 8601 date-time with Z/offset, YYYY-MM-DD, DD.MM.YYYY, today, tomorrow, yesterday, +3d or -2d. UTC midnight for dates; dueAt uses UTC end of day. |
|
|
88
|
-
| limit | integer | no | Optional result limit. |
|
|
88
|
+
| limit | integer | no | Optional result limit, 1..10000 (default 50); use offset for paging. |
|
|
89
89
|
| offset | integer | no | Optional result offset. |
|
|
90
90
|
| refSource | string | no | External reference source. |
|
|
91
91
|
| refId | string | no | External reference id. |
|
|
@@ -302,7 +302,7 @@ Writes: writes_state.
|
|
|
302
302
|
| kind | string | yes | interaction, observation, milestone, transaction. Event kind. |
|
|
303
303
|
| input | object | yes | Event payload. Always required. Interaction events also require `type`. |
|
|
304
304
|
| input.type | string | no | Interaction subtype. Required when kind=interaction, omit otherwise. |
|
|
305
|
-
| input.affectsBond | boolean | no | Whether evidence affects the relationship; defaults false for observations with significance <=2. |
|
|
305
|
+
| input.affectsBond | boolean | no | Whether evidence affects the relationship; defaults false for like/follow/repost labels and observations with significance <=2; explicit true opts in. |
|
|
306
306
|
| input.content | string | no | Verbatim text, including empty text; at most 1 MB UTF-8. Summary may be omitted when content is supplied. |
|
|
307
307
|
| input.externalRef | object | no | |
|
|
308
308
|
| input.channel | string | no | Free-text channel, trimmed and lowercased, at most 40 characters. |
|
|
@@ -340,7 +340,7 @@ Writes: writes_state.
|
|
|
340
340
|
| resolution | string | no | kept, cancelled, broken. How the commitment was resolved. Required when action=resolve. |
|
|
341
341
|
| options | object | no | Optional metadata. |
|
|
342
342
|
| input.commitmentType | string | yes | Promise or agreement. |
|
|
343
|
-
| input.affectsBond | boolean | no | Whether evidence affects the relationship; defaults false for observations with significance <=2. |
|
|
343
|
+
| input.affectsBond | boolean | no | Whether evidence affects the relationship; defaults false for like/follow/repost labels and observations with significance <=2; explicit true opts in. |
|
|
344
344
|
| input.content | string | no | Verbatim text, including empty text; at most 1 MB UTF-8. Summary may be omitted when content is supplied. |
|
|
345
345
|
| input.externalRef | object | no | |
|
|
346
346
|
| input.channel | string | no | Free-text channel, trimmed and lowercased, at most 40 characters. |
|
|
@@ -421,7 +421,8 @@ Writes: writes_state.
|
|
|
421
421
|
| entries | array | no | Key-value map to replace all attributes. Required when action=replace. |
|
|
422
422
|
| removedAt | integer / string | no | Removal timestamp. Optional for action=unset. Accepts epoch milliseconds integer, ISO 8601 date-time with Z/offset, YYYY-MM-DD, DD.MM.YYYY, today, tomorrow, yesterday, +3d or -2d. UTC midnight for dates; dueAt uses UTC end of day. |
|
|
423
423
|
| target.kind | string | yes | Target kind. |
|
|
424
|
-
| target.eventId | integer | no | Target event id. |
|
|
424
|
+
| target.eventId | integer | no | Target event id; provide eventId or ref. |
|
|
425
|
+
| target.ref | object | no | |
|
|
425
426
|
| target.contact | object | no | Contact locator. Required when kind=contact. Provide contactId or identity. |
|
|
426
427
|
| target.link | object | no | Link locator. Required when kind=link. Provide linkId or endpoints. |
|
|
427
428
|
| entries.name | string | yes | Attribute name. |
|