@ghostpaw/affinity 0.4.0 → 0.4.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 -1
- package/dist/cli.js +45 -21
- package/dist/index.cjs +38 -14
- package/dist/index.js +38 -14
- package/dist/mcp-server.js +44 -20
- package/dist/mcp.cjs +39 -15
- package/dist/mcp.js +39 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,6 +110,12 @@ curl -fsSL https://raw.githubusercontent.com/GhostPawJS/affinity/main/install.sh
|
|
|
110
110
|
irm https://raw.githubusercontent.com/GhostPawJS/affinity/main/install.ps1 | iex
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
A session with the 0.4.0 linux-x64 binary against a fresh database (output piped through `jq` to keep it short):
|
|
114
|
+
|
|
115
|
+

|
|
116
|
+
|
|
117
|
+
The same session as an [animated GIF](https://raw.githubusercontent.com/GhostPawJS/affinity/main/docs/assets/cli.gif).
|
|
118
|
+
|
|
113
119
|
Other release installers:
|
|
114
120
|
|
|
115
121
|
```sh
|
|
@@ -163,7 +169,19 @@ download on macOS, remove quarantine with
|
|
|
163
169
|
Linux binaries require glibc 2.28+; use npx on Alpine.
|
|
164
170
|
See the [binary build workflow](.github/workflows/release-binaries.yml).
|
|
165
171
|
|
|
166
|
-
|
|
172
|
+
Sizes for 0.4.0 (Node 26.12.1 inside each binary):
|
|
173
|
+
|
|
174
|
+
| Target | Archive | Binary |
|
|
175
|
+
|---|---|---|
|
|
176
|
+
| linux-x64 | 41.7 MB tar.gz | 117.6 MB |
|
|
177
|
+
| linux-arm64 | 41.2 MB tar.gz | 115.3 MB |
|
|
178
|
+
| darwin-arm64 | 44.9 MB tar.gz | 146.8 MB |
|
|
179
|
+
| darwin-x64 | 46.4 MB tar.gz | 149.7 MB |
|
|
180
|
+
| windows-x64 | 38.4 MB zip | 105.7 MB |
|
|
181
|
+
|
|
182
|
+
The npm package is 2003 KB unpacked and needs Node 24+. Every release is
|
|
183
|
+
installed and run on ubuntu-24.04, macos-15 and windows-2025 by the
|
|
184
|
+
[install check](.github/workflows/install-check.yml).
|
|
167
185
|
|
|
168
186
|
The install check runs on ubuntu-24.04, macos-15 and windows-2025.
|
|
169
187
|
|
package/dist/cli.js
CHANGED
|
@@ -23,7 +23,7 @@ var __export = (target, all) => {
|
|
|
23
23
|
var affinityVersion;
|
|
24
24
|
var init_version = __esm({
|
|
25
25
|
"src/version.ts"() {
|
|
26
|
-
affinityVersion = "0.4.
|
|
26
|
+
affinityVersion = "0.4.1";
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
|
|
@@ -2492,21 +2492,6 @@ var init_unset_attribute = __esm({
|
|
|
2492
2492
|
}
|
|
2493
2493
|
});
|
|
2494
2494
|
|
|
2495
|
-
// src/tools/tool_summary.ts
|
|
2496
|
-
function summarizeCount(count, singular) {
|
|
2497
|
-
if (count === 0) {
|
|
2498
|
-
return `No ${singular}s found.`;
|
|
2499
|
-
}
|
|
2500
|
-
if (count === 1) {
|
|
2501
|
-
return `Found 1 ${singular}.`;
|
|
2502
|
-
}
|
|
2503
|
-
return `Found ${count} ${singular}s.`;
|
|
2504
|
-
}
|
|
2505
|
-
var init_tool_summary = __esm({
|
|
2506
|
-
"src/tools/tool_summary.ts"() {
|
|
2507
|
-
}
|
|
2508
|
-
});
|
|
2509
|
-
|
|
2510
2495
|
// src/tools/tool_mutation.ts
|
|
2511
2496
|
function mutationToolResult(action, receipt, entitySummary) {
|
|
2512
2497
|
const changedCount = receipt.created.length + receipt.updated.length + receipt.archived.length + receipt.removed.length;
|
|
@@ -2520,7 +2505,7 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
2520
2505
|
affectedLinks: receipt.affectedLinks,
|
|
2521
2506
|
derivedEffects: receipt.derivedEffects
|
|
2522
2507
|
};
|
|
2523
|
-
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` :
|
|
2508
|
+
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` : describeChanges(receipt);
|
|
2524
2509
|
if (changedCount === 0) {
|
|
2525
2510
|
return toolNoOp(summary, data, {
|
|
2526
2511
|
entities: toReceiptEntityRefs(receipt)
|
|
@@ -2530,11 +2515,28 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
2530
2515
|
entities: toReceiptEntityRefs(receipt)
|
|
2531
2516
|
});
|
|
2532
2517
|
}
|
|
2518
|
+
function describeChanges(receipt) {
|
|
2519
|
+
const parts = [];
|
|
2520
|
+
for (const verb of ["created", "updated", "archived", "removed"]) {
|
|
2521
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2522
|
+
for (const ref of receipt[verb]) {
|
|
2523
|
+
counts.set(ref.kind, (counts.get(ref.kind) ?? 0) + 1);
|
|
2524
|
+
}
|
|
2525
|
+
if (counts.size === 0) continue;
|
|
2526
|
+
const items = [...counts].map(
|
|
2527
|
+
([kind, n]) => `${n} ${n === 1 ? kind : PLURALS[kind] ?? `${kind}s`}`
|
|
2528
|
+
);
|
|
2529
|
+
parts.push(`${verb} ${items.join(", ")}`);
|
|
2530
|
+
}
|
|
2531
|
+
const text = parts.join("; ");
|
|
2532
|
+
return `${text.charAt(0).toUpperCase()}${text.slice(1)}.`;
|
|
2533
|
+
}
|
|
2534
|
+
var PLURALS;
|
|
2533
2535
|
var init_tool_mutation = __esm({
|
|
2534
2536
|
"src/tools/tool_mutation.ts"() {
|
|
2535
2537
|
init_tool_ref();
|
|
2536
|
-
init_tool_summary();
|
|
2537
2538
|
init_tool_types();
|
|
2539
|
+
PLURALS = { identity: "identities" };
|
|
2538
2540
|
}
|
|
2539
2541
|
});
|
|
2540
2542
|
|
|
@@ -4296,13 +4298,20 @@ function createContact(db, input) {
|
|
|
4296
4298
|
if (!KINDS.has(input.kind)) {
|
|
4297
4299
|
throw new AffinityValidationError("invalid contact kind");
|
|
4298
4300
|
}
|
|
4301
|
+
if (input.isOwner !== void 0) {
|
|
4302
|
+
throw new AffinityValidationError(
|
|
4303
|
+
"isOwner is read-only; pass bootstrapOwner: true to create the owner contact"
|
|
4304
|
+
);
|
|
4305
|
+
}
|
|
4299
4306
|
const now = resolveNow(input.now);
|
|
4300
4307
|
if (input.bootstrapOwner) {
|
|
4301
4308
|
const existing = db.prepare(
|
|
4302
|
-
"SELECT id FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
4309
|
+
"SELECT id, name FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
4303
4310
|
).get();
|
|
4304
4311
|
if (existing !== void 0) {
|
|
4305
|
-
throw new AffinityConflictError(
|
|
4312
|
+
throw new AffinityConflictError(
|
|
4313
|
+
`owner already exists: contact ${existing.id} (${existing.name}); bootstrapOwner can only be used once`
|
|
4314
|
+
);
|
|
4306
4315
|
}
|
|
4307
4316
|
}
|
|
4308
4317
|
const isOwner = input.bootstrapOwner ? 1 : 0;
|
|
@@ -7405,6 +7414,21 @@ var init_list_dismissed_duplicates = __esm({
|
|
|
7405
7414
|
}
|
|
7406
7415
|
});
|
|
7407
7416
|
|
|
7417
|
+
// src/tools/tool_summary.ts
|
|
7418
|
+
function summarizeCount(count, singular) {
|
|
7419
|
+
if (count === 0) {
|
|
7420
|
+
return `No ${singular}s found.`;
|
|
7421
|
+
}
|
|
7422
|
+
if (count === 1) {
|
|
7423
|
+
return `Found 1 ${singular}.`;
|
|
7424
|
+
}
|
|
7425
|
+
return `Found ${count} ${singular}s.`;
|
|
7426
|
+
}
|
|
7427
|
+
var init_tool_summary = __esm({
|
|
7428
|
+
"src/tools/tool_summary.ts"() {
|
|
7429
|
+
}
|
|
7430
|
+
});
|
|
7431
|
+
|
|
7408
7432
|
// src/tools/review_affinity_tool.ts
|
|
7409
7433
|
function buildReadOptions(input) {
|
|
7410
7434
|
return {
|
|
@@ -10107,7 +10131,7 @@ function parseCliArgs(argv, spec) {
|
|
|
10107
10131
|
raw = negative ? "false" : "true";
|
|
10108
10132
|
if (raw === void 0) {
|
|
10109
10133
|
const next = argv[i + 1];
|
|
10110
|
-
if (next === void 0 ||
|
|
10134
|
+
if (next === void 0 || /^--[a-z]/i.test(next))
|
|
10111
10135
|
throw new CliUsageError(`Missing value: --${arg.name}`);
|
|
10112
10136
|
raw = next;
|
|
10113
10137
|
i++;
|
package/dist/index.cjs
CHANGED
|
@@ -788,13 +788,20 @@ function createContact(db, input) {
|
|
|
788
788
|
if (!KINDS.has(input.kind)) {
|
|
789
789
|
throw new AffinityValidationError("invalid contact kind");
|
|
790
790
|
}
|
|
791
|
+
if (input.isOwner !== void 0) {
|
|
792
|
+
throw new AffinityValidationError(
|
|
793
|
+
"isOwner is read-only; pass bootstrapOwner: true to create the owner contact"
|
|
794
|
+
);
|
|
795
|
+
}
|
|
791
796
|
const now = resolveNow(input.now);
|
|
792
797
|
if (input.bootstrapOwner) {
|
|
793
798
|
const existing = db.prepare(
|
|
794
|
-
"SELECT id FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
799
|
+
"SELECT id, name FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
795
800
|
).get();
|
|
796
801
|
if (existing !== void 0) {
|
|
797
|
-
throw new AffinityConflictError(
|
|
802
|
+
throw new AffinityConflictError(
|
|
803
|
+
`owner already exists: contact ${existing.id} (${existing.name}); bootstrapOwner can only be used once`
|
|
804
|
+
);
|
|
798
805
|
}
|
|
799
806
|
}
|
|
800
807
|
const isOwner = input.bootstrapOwner ? 1 : 0;
|
|
@@ -6453,17 +6460,6 @@ function unsetAttribute(db, target, name, removedAt) {
|
|
|
6453
6460
|
});
|
|
6454
6461
|
}
|
|
6455
6462
|
|
|
6456
|
-
// src/tools/tool_summary.ts
|
|
6457
|
-
function summarizeCount(count, singular) {
|
|
6458
|
-
if (count === 0) {
|
|
6459
|
-
return `No ${singular}s found.`;
|
|
6460
|
-
}
|
|
6461
|
-
if (count === 1) {
|
|
6462
|
-
return `Found 1 ${singular}.`;
|
|
6463
|
-
}
|
|
6464
|
-
return `Found ${count} ${singular}s.`;
|
|
6465
|
-
}
|
|
6466
|
-
|
|
6467
6463
|
// src/tools/tool_mutation.ts
|
|
6468
6464
|
function mutationToolResult(action, receipt, entitySummary) {
|
|
6469
6465
|
const changedCount = receipt.created.length + receipt.updated.length + receipt.archived.length + receipt.removed.length;
|
|
@@ -6477,7 +6473,7 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
6477
6473
|
affectedLinks: receipt.affectedLinks,
|
|
6478
6474
|
derivedEffects: receipt.derivedEffects
|
|
6479
6475
|
};
|
|
6480
|
-
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` :
|
|
6476
|
+
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` : describeChanges(receipt);
|
|
6481
6477
|
if (changedCount === 0) {
|
|
6482
6478
|
return toolNoOp(summary, data, {
|
|
6483
6479
|
entities: toReceiptEntityRefs(receipt)
|
|
@@ -6487,6 +6483,23 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
6487
6483
|
entities: toReceiptEntityRefs(receipt)
|
|
6488
6484
|
});
|
|
6489
6485
|
}
|
|
6486
|
+
var PLURALS = { identity: "identities" };
|
|
6487
|
+
function describeChanges(receipt) {
|
|
6488
|
+
const parts = [];
|
|
6489
|
+
for (const verb of ["created", "updated", "archived", "removed"]) {
|
|
6490
|
+
const counts = /* @__PURE__ */ new Map();
|
|
6491
|
+
for (const ref of receipt[verb]) {
|
|
6492
|
+
counts.set(ref.kind, (counts.get(ref.kind) ?? 0) + 1);
|
|
6493
|
+
}
|
|
6494
|
+
if (counts.size === 0) continue;
|
|
6495
|
+
const items = [...counts].map(
|
|
6496
|
+
([kind, n]) => `${n} ${n === 1 ? kind : PLURALS[kind] ?? `${kind}s`}`
|
|
6497
|
+
);
|
|
6498
|
+
parts.push(`${verb} ${items.join(", ")}`);
|
|
6499
|
+
}
|
|
6500
|
+
const text = parts.join("; ");
|
|
6501
|
+
return `${text.charAt(0).toUpperCase()}${text.slice(1)}.`;
|
|
6502
|
+
}
|
|
6490
6503
|
|
|
6491
6504
|
// src/tools/manage_attribute_tool.ts
|
|
6492
6505
|
function contactLocatorSchema2(description) {
|
|
@@ -7868,6 +7881,17 @@ var recordEventTool = defineAffinityTool({
|
|
|
7868
7881
|
handler: recordEventToolHandler
|
|
7869
7882
|
});
|
|
7870
7883
|
|
|
7884
|
+
// src/tools/tool_summary.ts
|
|
7885
|
+
function summarizeCount(count, singular) {
|
|
7886
|
+
if (count === 0) {
|
|
7887
|
+
return `No ${singular}s found.`;
|
|
7888
|
+
}
|
|
7889
|
+
if (count === 1) {
|
|
7890
|
+
return `Found 1 ${singular}.`;
|
|
7891
|
+
}
|
|
7892
|
+
return `Found ${count} ${singular}s.`;
|
|
7893
|
+
}
|
|
7894
|
+
|
|
7871
7895
|
// src/tools/review_affinity_tool.ts
|
|
7872
7896
|
function buildReadOptions(input) {
|
|
7873
7897
|
return {
|
package/dist/index.js
CHANGED
|
@@ -786,13 +786,20 @@ function createContact(db, input) {
|
|
|
786
786
|
if (!KINDS.has(input.kind)) {
|
|
787
787
|
throw new AffinityValidationError("invalid contact kind");
|
|
788
788
|
}
|
|
789
|
+
if (input.isOwner !== void 0) {
|
|
790
|
+
throw new AffinityValidationError(
|
|
791
|
+
"isOwner is read-only; pass bootstrapOwner: true to create the owner contact"
|
|
792
|
+
);
|
|
793
|
+
}
|
|
789
794
|
const now = resolveNow(input.now);
|
|
790
795
|
if (input.bootstrapOwner) {
|
|
791
796
|
const existing = db.prepare(
|
|
792
|
-
"SELECT id FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
797
|
+
"SELECT id, name FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
793
798
|
).get();
|
|
794
799
|
if (existing !== void 0) {
|
|
795
|
-
throw new AffinityConflictError(
|
|
800
|
+
throw new AffinityConflictError(
|
|
801
|
+
`owner already exists: contact ${existing.id} (${existing.name}); bootstrapOwner can only be used once`
|
|
802
|
+
);
|
|
796
803
|
}
|
|
797
804
|
}
|
|
798
805
|
const isOwner = input.bootstrapOwner ? 1 : 0;
|
|
@@ -6451,17 +6458,6 @@ function unsetAttribute(db, target, name, removedAt) {
|
|
|
6451
6458
|
});
|
|
6452
6459
|
}
|
|
6453
6460
|
|
|
6454
|
-
// src/tools/tool_summary.ts
|
|
6455
|
-
function summarizeCount(count, singular) {
|
|
6456
|
-
if (count === 0) {
|
|
6457
|
-
return `No ${singular}s found.`;
|
|
6458
|
-
}
|
|
6459
|
-
if (count === 1) {
|
|
6460
|
-
return `Found 1 ${singular}.`;
|
|
6461
|
-
}
|
|
6462
|
-
return `Found ${count} ${singular}s.`;
|
|
6463
|
-
}
|
|
6464
|
-
|
|
6465
6461
|
// src/tools/tool_mutation.ts
|
|
6466
6462
|
function mutationToolResult(action, receipt, entitySummary) {
|
|
6467
6463
|
const changedCount = receipt.created.length + receipt.updated.length + receipt.archived.length + receipt.removed.length;
|
|
@@ -6475,7 +6471,7 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
6475
6471
|
affectedLinks: receipt.affectedLinks,
|
|
6476
6472
|
derivedEffects: receipt.derivedEffects
|
|
6477
6473
|
};
|
|
6478
|
-
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` :
|
|
6474
|
+
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` : describeChanges(receipt);
|
|
6479
6475
|
if (changedCount === 0) {
|
|
6480
6476
|
return toolNoOp(summary, data, {
|
|
6481
6477
|
entities: toReceiptEntityRefs(receipt)
|
|
@@ -6485,6 +6481,23 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
6485
6481
|
entities: toReceiptEntityRefs(receipt)
|
|
6486
6482
|
});
|
|
6487
6483
|
}
|
|
6484
|
+
var PLURALS = { identity: "identities" };
|
|
6485
|
+
function describeChanges(receipt) {
|
|
6486
|
+
const parts = [];
|
|
6487
|
+
for (const verb of ["created", "updated", "archived", "removed"]) {
|
|
6488
|
+
const counts = /* @__PURE__ */ new Map();
|
|
6489
|
+
for (const ref of receipt[verb]) {
|
|
6490
|
+
counts.set(ref.kind, (counts.get(ref.kind) ?? 0) + 1);
|
|
6491
|
+
}
|
|
6492
|
+
if (counts.size === 0) continue;
|
|
6493
|
+
const items = [...counts].map(
|
|
6494
|
+
([kind, n]) => `${n} ${n === 1 ? kind : PLURALS[kind] ?? `${kind}s`}`
|
|
6495
|
+
);
|
|
6496
|
+
parts.push(`${verb} ${items.join(", ")}`);
|
|
6497
|
+
}
|
|
6498
|
+
const text = parts.join("; ");
|
|
6499
|
+
return `${text.charAt(0).toUpperCase()}${text.slice(1)}.`;
|
|
6500
|
+
}
|
|
6488
6501
|
|
|
6489
6502
|
// src/tools/manage_attribute_tool.ts
|
|
6490
6503
|
function contactLocatorSchema2(description) {
|
|
@@ -7866,6 +7879,17 @@ var recordEventTool = defineAffinityTool({
|
|
|
7866
7879
|
handler: recordEventToolHandler
|
|
7867
7880
|
});
|
|
7868
7881
|
|
|
7882
|
+
// src/tools/tool_summary.ts
|
|
7883
|
+
function summarizeCount(count, singular) {
|
|
7884
|
+
if (count === 0) {
|
|
7885
|
+
return `No ${singular}s found.`;
|
|
7886
|
+
}
|
|
7887
|
+
if (count === 1) {
|
|
7888
|
+
return `Found 1 ${singular}.`;
|
|
7889
|
+
}
|
|
7890
|
+
return `Found ${count} ${singular}s.`;
|
|
7891
|
+
}
|
|
7892
|
+
|
|
7869
7893
|
// src/tools/review_affinity_tool.ts
|
|
7870
7894
|
function buildReadOptions(input) {
|
|
7871
7895
|
return {
|
package/dist/mcp-server.js
CHANGED
|
@@ -285,7 +285,7 @@ var init_mcp_stdio = __esm({
|
|
|
285
285
|
var affinityVersion;
|
|
286
286
|
var init_version = __esm({
|
|
287
287
|
"src/version.ts"() {
|
|
288
|
-
affinityVersion = "0.4.
|
|
288
|
+
affinityVersion = "0.4.1";
|
|
289
289
|
}
|
|
290
290
|
});
|
|
291
291
|
|
|
@@ -2762,21 +2762,6 @@ var init_unset_attribute = __esm({
|
|
|
2762
2762
|
}
|
|
2763
2763
|
});
|
|
2764
2764
|
|
|
2765
|
-
// src/tools/tool_summary.ts
|
|
2766
|
-
function summarizeCount(count, singular) {
|
|
2767
|
-
if (count === 0) {
|
|
2768
|
-
return `No ${singular}s found.`;
|
|
2769
|
-
}
|
|
2770
|
-
if (count === 1) {
|
|
2771
|
-
return `Found 1 ${singular}.`;
|
|
2772
|
-
}
|
|
2773
|
-
return `Found ${count} ${singular}s.`;
|
|
2774
|
-
}
|
|
2775
|
-
var init_tool_summary = __esm({
|
|
2776
|
-
"src/tools/tool_summary.ts"() {
|
|
2777
|
-
}
|
|
2778
|
-
});
|
|
2779
|
-
|
|
2780
2765
|
// src/tools/tool_mutation.ts
|
|
2781
2766
|
function mutationToolResult(action, receipt, entitySummary) {
|
|
2782
2767
|
const changedCount = receipt.created.length + receipt.updated.length + receipt.archived.length + receipt.removed.length;
|
|
@@ -2790,7 +2775,7 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
2790
2775
|
affectedLinks: receipt.affectedLinks,
|
|
2791
2776
|
derivedEffects: receipt.derivedEffects
|
|
2792
2777
|
};
|
|
2793
|
-
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` :
|
|
2778
|
+
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` : describeChanges(receipt);
|
|
2794
2779
|
if (changedCount === 0) {
|
|
2795
2780
|
return toolNoOp(summary, data, {
|
|
2796
2781
|
entities: toReceiptEntityRefs(receipt)
|
|
@@ -2800,11 +2785,28 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
2800
2785
|
entities: toReceiptEntityRefs(receipt)
|
|
2801
2786
|
});
|
|
2802
2787
|
}
|
|
2788
|
+
function describeChanges(receipt) {
|
|
2789
|
+
const parts = [];
|
|
2790
|
+
for (const verb of ["created", "updated", "archived", "removed"]) {
|
|
2791
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2792
|
+
for (const ref of receipt[verb]) {
|
|
2793
|
+
counts.set(ref.kind, (counts.get(ref.kind) ?? 0) + 1);
|
|
2794
|
+
}
|
|
2795
|
+
if (counts.size === 0) continue;
|
|
2796
|
+
const items = [...counts].map(
|
|
2797
|
+
([kind, n]) => `${n} ${n === 1 ? kind : PLURALS[kind] ?? `${kind}s`}`
|
|
2798
|
+
);
|
|
2799
|
+
parts.push(`${verb} ${items.join(", ")}`);
|
|
2800
|
+
}
|
|
2801
|
+
const text = parts.join("; ");
|
|
2802
|
+
return `${text.charAt(0).toUpperCase()}${text.slice(1)}.`;
|
|
2803
|
+
}
|
|
2804
|
+
var PLURALS;
|
|
2803
2805
|
var init_tool_mutation = __esm({
|
|
2804
2806
|
"src/tools/tool_mutation.ts"() {
|
|
2805
2807
|
init_tool_ref();
|
|
2806
|
-
init_tool_summary();
|
|
2807
2808
|
init_tool_types();
|
|
2809
|
+
PLURALS = { identity: "identities" };
|
|
2808
2810
|
}
|
|
2809
2811
|
});
|
|
2810
2812
|
|
|
@@ -4566,13 +4568,20 @@ function createContact(db, input) {
|
|
|
4566
4568
|
if (!KINDS.has(input.kind)) {
|
|
4567
4569
|
throw new AffinityValidationError("invalid contact kind");
|
|
4568
4570
|
}
|
|
4571
|
+
if (input.isOwner !== void 0) {
|
|
4572
|
+
throw new AffinityValidationError(
|
|
4573
|
+
"isOwner is read-only; pass bootstrapOwner: true to create the owner contact"
|
|
4574
|
+
);
|
|
4575
|
+
}
|
|
4569
4576
|
const now = resolveNow(input.now);
|
|
4570
4577
|
if (input.bootstrapOwner) {
|
|
4571
4578
|
const existing = db.prepare(
|
|
4572
|
-
"SELECT id FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
4579
|
+
"SELECT id, name FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
4573
4580
|
).get();
|
|
4574
4581
|
if (existing !== void 0) {
|
|
4575
|
-
throw new AffinityConflictError(
|
|
4582
|
+
throw new AffinityConflictError(
|
|
4583
|
+
`owner already exists: contact ${existing.id} (${existing.name}); bootstrapOwner can only be used once`
|
|
4584
|
+
);
|
|
4576
4585
|
}
|
|
4577
4586
|
}
|
|
4578
4587
|
const isOwner = input.bootstrapOwner ? 1 : 0;
|
|
@@ -7675,6 +7684,21 @@ var init_list_dismissed_duplicates = __esm({
|
|
|
7675
7684
|
}
|
|
7676
7685
|
});
|
|
7677
7686
|
|
|
7687
|
+
// src/tools/tool_summary.ts
|
|
7688
|
+
function summarizeCount(count, singular) {
|
|
7689
|
+
if (count === 0) {
|
|
7690
|
+
return `No ${singular}s found.`;
|
|
7691
|
+
}
|
|
7692
|
+
if (count === 1) {
|
|
7693
|
+
return `Found 1 ${singular}.`;
|
|
7694
|
+
}
|
|
7695
|
+
return `Found ${count} ${singular}s.`;
|
|
7696
|
+
}
|
|
7697
|
+
var init_tool_summary = __esm({
|
|
7698
|
+
"src/tools/tool_summary.ts"() {
|
|
7699
|
+
}
|
|
7700
|
+
});
|
|
7701
|
+
|
|
7678
7702
|
// src/tools/review_affinity_tool.ts
|
|
7679
7703
|
function buildReadOptions(input) {
|
|
7680
7704
|
return {
|
package/dist/mcp.cjs
CHANGED
|
@@ -5,7 +5,7 @@ var node_path = require('node:path');
|
|
|
5
5
|
var node_os = require('node:os');
|
|
6
6
|
|
|
7
7
|
// src/version.ts
|
|
8
|
-
var affinityVersion = "0.4.
|
|
8
|
+
var affinityVersion = "0.4.1";
|
|
9
9
|
|
|
10
10
|
// src/surface/affinity_mcp_instructions.ts
|
|
11
11
|
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.";
|
|
@@ -2160,17 +2160,6 @@ function unsetAttribute(db, target, name, removedAt) {
|
|
|
2160
2160
|
});
|
|
2161
2161
|
}
|
|
2162
2162
|
|
|
2163
|
-
// src/tools/tool_summary.ts
|
|
2164
|
-
function summarizeCount(count, singular) {
|
|
2165
|
-
if (count === 0) {
|
|
2166
|
-
return `No ${singular}s found.`;
|
|
2167
|
-
}
|
|
2168
|
-
if (count === 1) {
|
|
2169
|
-
return `Found 1 ${singular}.`;
|
|
2170
|
-
}
|
|
2171
|
-
return `Found ${count} ${singular}s.`;
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
2163
|
// src/tools/tool_mutation.ts
|
|
2175
2164
|
function mutationToolResult(action, receipt, entitySummary) {
|
|
2176
2165
|
const changedCount = receipt.created.length + receipt.updated.length + receipt.archived.length + receipt.removed.length;
|
|
@@ -2184,7 +2173,7 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
2184
2173
|
affectedLinks: receipt.affectedLinks,
|
|
2185
2174
|
derivedEffects: receipt.derivedEffects
|
|
2186
2175
|
};
|
|
2187
|
-
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` :
|
|
2176
|
+
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` : describeChanges(receipt);
|
|
2188
2177
|
if (changedCount === 0) {
|
|
2189
2178
|
return toolNoOp(summary, data, {
|
|
2190
2179
|
entities: toReceiptEntityRefs(receipt)
|
|
@@ -2194,6 +2183,23 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
2194
2183
|
entities: toReceiptEntityRefs(receipt)
|
|
2195
2184
|
});
|
|
2196
2185
|
}
|
|
2186
|
+
var PLURALS = { identity: "identities" };
|
|
2187
|
+
function describeChanges(receipt) {
|
|
2188
|
+
const parts = [];
|
|
2189
|
+
for (const verb of ["created", "updated", "archived", "removed"]) {
|
|
2190
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2191
|
+
for (const ref of receipt[verb]) {
|
|
2192
|
+
counts.set(ref.kind, (counts.get(ref.kind) ?? 0) + 1);
|
|
2193
|
+
}
|
|
2194
|
+
if (counts.size === 0) continue;
|
|
2195
|
+
const items = [...counts].map(
|
|
2196
|
+
([kind, n]) => `${n} ${n === 1 ? kind : PLURALS[kind] ?? `${kind}s`}`
|
|
2197
|
+
);
|
|
2198
|
+
parts.push(`${verb} ${items.join(", ")}`);
|
|
2199
|
+
}
|
|
2200
|
+
const text = parts.join("; ");
|
|
2201
|
+
return `${text.charAt(0).toUpperCase()}${text.slice(1)}.`;
|
|
2202
|
+
}
|
|
2197
2203
|
|
|
2198
2204
|
// src/tools/manage_attribute_tool.ts
|
|
2199
2205
|
function contactLocatorSchema2(description) {
|
|
@@ -3825,13 +3831,20 @@ function createContact(db, input) {
|
|
|
3825
3831
|
if (!KINDS.has(input.kind)) {
|
|
3826
3832
|
throw new AffinityValidationError("invalid contact kind");
|
|
3827
3833
|
}
|
|
3834
|
+
if (input.isOwner !== void 0) {
|
|
3835
|
+
throw new AffinityValidationError(
|
|
3836
|
+
"isOwner is read-only; pass bootstrapOwner: true to create the owner contact"
|
|
3837
|
+
);
|
|
3838
|
+
}
|
|
3828
3839
|
const now = resolveNow(input.now);
|
|
3829
3840
|
if (input.bootstrapOwner) {
|
|
3830
3841
|
const existing = db.prepare(
|
|
3831
|
-
"SELECT id FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
3842
|
+
"SELECT id, name FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
3832
3843
|
).get();
|
|
3833
3844
|
if (existing !== void 0) {
|
|
3834
|
-
throw new AffinityConflictError(
|
|
3845
|
+
throw new AffinityConflictError(
|
|
3846
|
+
`owner already exists: contact ${existing.id} (${existing.name}); bootstrapOwner can only be used once`
|
|
3847
|
+
);
|
|
3835
3848
|
}
|
|
3836
3849
|
}
|
|
3837
3850
|
const isOwner = input.bootstrapOwner ? 1 : 0;
|
|
@@ -6451,6 +6464,17 @@ function listDismissedDuplicates(db, options) {
|
|
|
6451
6464
|
}));
|
|
6452
6465
|
}
|
|
6453
6466
|
|
|
6467
|
+
// src/tools/tool_summary.ts
|
|
6468
|
+
function summarizeCount(count, singular) {
|
|
6469
|
+
if (count === 0) {
|
|
6470
|
+
return `No ${singular}s found.`;
|
|
6471
|
+
}
|
|
6472
|
+
if (count === 1) {
|
|
6473
|
+
return `Found 1 ${singular}.`;
|
|
6474
|
+
}
|
|
6475
|
+
return `Found ${count} ${singular}s.`;
|
|
6476
|
+
}
|
|
6477
|
+
|
|
6454
6478
|
// src/tools/review_affinity_tool.ts
|
|
6455
6479
|
function buildReadOptions(input) {
|
|
6456
6480
|
return {
|
package/dist/mcp.js
CHANGED
|
@@ -3,7 +3,7 @@ import { dirname, join } from 'node:path';
|
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
|
|
5
5
|
// src/version.ts
|
|
6
|
-
var affinityVersion = "0.4.
|
|
6
|
+
var affinityVersion = "0.4.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.";
|
|
@@ -2158,17 +2158,6 @@ function unsetAttribute(db, target, name, removedAt) {
|
|
|
2158
2158
|
});
|
|
2159
2159
|
}
|
|
2160
2160
|
|
|
2161
|
-
// src/tools/tool_summary.ts
|
|
2162
|
-
function summarizeCount(count, singular) {
|
|
2163
|
-
if (count === 0) {
|
|
2164
|
-
return `No ${singular}s found.`;
|
|
2165
|
-
}
|
|
2166
|
-
if (count === 1) {
|
|
2167
|
-
return `Found 1 ${singular}.`;
|
|
2168
|
-
}
|
|
2169
|
-
return `Found ${count} ${singular}s.`;
|
|
2170
|
-
}
|
|
2171
|
-
|
|
2172
2161
|
// src/tools/tool_mutation.ts
|
|
2173
2162
|
function mutationToolResult(action, receipt, entitySummary) {
|
|
2174
2163
|
const changedCount = receipt.created.length + receipt.updated.length + receipt.archived.length + receipt.removed.length;
|
|
@@ -2182,7 +2171,7 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
2182
2171
|
affectedLinks: receipt.affectedLinks,
|
|
2183
2172
|
derivedEffects: receipt.derivedEffects
|
|
2184
2173
|
};
|
|
2185
|
-
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` :
|
|
2174
|
+
const summary = changedCount === 0 ? `No ${entitySummary} changes were needed.` : describeChanges(receipt);
|
|
2186
2175
|
if (changedCount === 0) {
|
|
2187
2176
|
return toolNoOp(summary, data, {
|
|
2188
2177
|
entities: toReceiptEntityRefs(receipt)
|
|
@@ -2192,6 +2181,23 @@ function mutationToolResult(action, receipt, entitySummary) {
|
|
|
2192
2181
|
entities: toReceiptEntityRefs(receipt)
|
|
2193
2182
|
});
|
|
2194
2183
|
}
|
|
2184
|
+
var PLURALS = { identity: "identities" };
|
|
2185
|
+
function describeChanges(receipt) {
|
|
2186
|
+
const parts = [];
|
|
2187
|
+
for (const verb of ["created", "updated", "archived", "removed"]) {
|
|
2188
|
+
const counts = /* @__PURE__ */ new Map();
|
|
2189
|
+
for (const ref of receipt[verb]) {
|
|
2190
|
+
counts.set(ref.kind, (counts.get(ref.kind) ?? 0) + 1);
|
|
2191
|
+
}
|
|
2192
|
+
if (counts.size === 0) continue;
|
|
2193
|
+
const items = [...counts].map(
|
|
2194
|
+
([kind, n]) => `${n} ${n === 1 ? kind : PLURALS[kind] ?? `${kind}s`}`
|
|
2195
|
+
);
|
|
2196
|
+
parts.push(`${verb} ${items.join(", ")}`);
|
|
2197
|
+
}
|
|
2198
|
+
const text = parts.join("; ");
|
|
2199
|
+
return `${text.charAt(0).toUpperCase()}${text.slice(1)}.`;
|
|
2200
|
+
}
|
|
2195
2201
|
|
|
2196
2202
|
// src/tools/manage_attribute_tool.ts
|
|
2197
2203
|
function contactLocatorSchema2(description) {
|
|
@@ -3823,13 +3829,20 @@ function createContact(db, input) {
|
|
|
3823
3829
|
if (!KINDS.has(input.kind)) {
|
|
3824
3830
|
throw new AffinityValidationError("invalid contact kind");
|
|
3825
3831
|
}
|
|
3832
|
+
if (input.isOwner !== void 0) {
|
|
3833
|
+
throw new AffinityValidationError(
|
|
3834
|
+
"isOwner is read-only; pass bootstrapOwner: true to create the owner contact"
|
|
3835
|
+
);
|
|
3836
|
+
}
|
|
3826
3837
|
const now = resolveNow(input.now);
|
|
3827
3838
|
if (input.bootstrapOwner) {
|
|
3828
3839
|
const existing = db.prepare(
|
|
3829
|
-
"SELECT id FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
3840
|
+
"SELECT id, name FROM contacts WHERE is_owner = 1 AND deleted_at IS NULL"
|
|
3830
3841
|
).get();
|
|
3831
3842
|
if (existing !== void 0) {
|
|
3832
|
-
throw new AffinityConflictError(
|
|
3843
|
+
throw new AffinityConflictError(
|
|
3844
|
+
`owner already exists: contact ${existing.id} (${existing.name}); bootstrapOwner can only be used once`
|
|
3845
|
+
);
|
|
3833
3846
|
}
|
|
3834
3847
|
}
|
|
3835
3848
|
const isOwner = input.bootstrapOwner ? 1 : 0;
|
|
@@ -6449,6 +6462,17 @@ function listDismissedDuplicates(db, options) {
|
|
|
6449
6462
|
}));
|
|
6450
6463
|
}
|
|
6451
6464
|
|
|
6465
|
+
// src/tools/tool_summary.ts
|
|
6466
|
+
function summarizeCount(count, singular) {
|
|
6467
|
+
if (count === 0) {
|
|
6468
|
+
return `No ${singular}s found.`;
|
|
6469
|
+
}
|
|
6470
|
+
if (count === 1) {
|
|
6471
|
+
return `Found 1 ${singular}.`;
|
|
6472
|
+
}
|
|
6473
|
+
return `Found ${count} ${singular}s.`;
|
|
6474
|
+
}
|
|
6475
|
+
|
|
6452
6476
|
// src/tools/review_affinity_tool.ts
|
|
6453
6477
|
function buildReadOptions(input) {
|
|
6454
6478
|
return {
|
package/package.json
CHANGED