@ghostpaw/affinity 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +184 -9
- package/SKILL.md +43 -386
- package/dist/cli.js +2797 -894
- package/dist/index.cjs +1922 -613
- package/dist/index.d.cts +333 -55
- package/dist/index.d.ts +333 -55
- package/dist/index.js +1922 -613
- package/dist/mcp-server.js +2131 -819
- package/dist/mcp.cjs +1912 -707
- package/dist/mcp.d.cts +3 -0
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.js +1913 -708
- package/package.json +1 -1
- package/skills/affinity/SKILL.md +43 -386
- package/skills/affinity/references/identify-and-locate-contacts.md +9 -0
- package/skills/affinity/references/import-history-without-faking-evidence.md +25 -0
- package/skills/affinity/references/manage-promises-and-agreements.md +8 -0
- package/skills/affinity/references/manage-recurring-dates-and-reminders.md +8 -0
- package/skills/affinity/references/record-direct-evidence-well.md +18 -0
- package/skills/affinity/references/record-observations-and-referrals.md +10 -0
- package/skills/affinity/references/review-radar-progression-and-graph.md +13 -0
- package/skills/affinity/references/tools.md +489 -0
package/README.md
CHANGED
|
@@ -45,9 +45,19 @@ cd "$(mktemp -d)" && T=darwin-x64 && V=$(curl -fsSLI -o /dev/null -w '%{url_effe
|
|
|
45
45
|
$r='GhostPawJS/affinity'; $v=(irm "https://api.github.com/repos/$r/releases/latest").tag_name; $f="ghostpaw-affinity-$($v.TrimStart('v'))-windows-x64.zip"; $u="https://github.com/$r/releases/download/$v"; $t=(New-Item -ItemType Directory (Join-Path $env:TEMP ([guid]::NewGuid()))).FullName; iwr "$u/$f" -OutFile "$t\$f" -UseBasicParsing; iwr "$u/SHA256SUMS" -OutFile "$t\SHA256SUMS" -UseBasicParsing; $want=((Get-Content "$t\SHA256SUMS" | Where-Object { $_ -like "* $f" }) -split '\s+')[0]; if (-not $want -or (Get-FileHash "$t\$f" -Algorithm SHA256).Hash -ne $want) { throw "checksum mismatch for $f" }; $d=Join-Path $env:LOCALAPPDATA 'Programs\ghostpaw\bin'; Expand-Archive "$t\$f" $t -Force; New-Item -ItemType Directory -Force $d | Out-Null; Copy-Item "$t\ghostpaw-affinity.exe" $d -Force; $p=[Environment]::GetEnvironmentVariable('Path','User'); if (";$p;" -notlike "*;$d;*") { [Environment]::SetEnvironmentVariable('Path',"$p;$d",'User') }; $env:Path="$d;$env:Path"; ghostpaw-affinity --version
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
These commands install the latest release in `~/.local/bin` on Linux, `/usr/local/bin` on macOS (asks for sudo), or `%LOCALAPPDATA%\Programs\ghostpaw\bin` on Windows; Linux adds it to PATH via `~/.profile` only if missing, and Windows adds it to the user PATH (open a new terminal afterwards). To pin a version, set `V=0.6.0` instead of resolving latest (`$v='v0.6.0'` in PowerShell).
|
|
49
|
+
|
|
50
|
+
For a pinned Linux/macOS download to the current directory with no profile or PATH edits, choose the matching `T` (`linux-x64`, `linux-arm64`, `darwin-arm64`, or `darwin-x64`):
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
V=0.6.0
|
|
54
|
+
T=linux-x64
|
|
55
|
+
F=ghostpaw-affinity-$V-$T.tar.gz
|
|
56
|
+
U=https://github.com/GhostPawJS/affinity/releases/download/v$V
|
|
57
|
+
curl -fsSL -O "$U/$F" -O "$U/SHA256SUMS" &&
|
|
58
|
+
{ case "$T" in darwin-*) grep " $F\$" SHA256SUMS | shasum -a 256 -c - ;; *) grep " $F\$" SHA256SUMS | sha256sum -c - ;; esac; } &&
|
|
59
|
+
tar -xzf "$F" ghostpaw-affinity && ./ghostpaw-affinity --version
|
|
60
|
+
```
|
|
51
61
|
|
|
52
62
|
Then:
|
|
53
63
|
|
|
@@ -63,7 +73,7 @@ resolve against the current directory.
|
|
|
63
73
|
|
|
64
74
|
A session with the linux-x64 binary against a fresh database:
|
|
65
75
|
|
|
66
|
-

|
|
67
77
|
|
|
68
78
|
The same session as an [animated GIF](https://raw.githubusercontent.com/GhostPawJS/affinity/main/docs/assets/cli.gif).
|
|
69
79
|
|
|
@@ -218,6 +228,43 @@ ghostpaw-affinity skill --list # workflow guides
|
|
|
218
228
|
ghostpaw-affinity skill bootstrap-and-cold-start
|
|
219
229
|
```
|
|
220
230
|
|
|
231
|
+
## Events
|
|
232
|
+
|
|
233
|
+
Record events and commitments with an optional `externalRef: {source, id}`.
|
|
234
|
+
Both values are trimmed and non-empty; source is lowercased. The pair is unique
|
|
235
|
+
across the database. Repeated intake returns the original event and `no_op`,
|
|
236
|
+
without creating rows or relationship effects.
|
|
237
|
+
|
|
238
|
+
`content` preserves text exactly, including whitespace, empty strings and NUL,
|
|
239
|
+
up to 1 MB (1,048,576 UTF-8 bytes). Supply a short `summary`, or omit it to derive
|
|
240
|
+
one from the first non-empty content line (at most 140 characters; empty text
|
|
241
|
+
becomes `(no text)`). Unknown event fields and moment kinds are validation errors.
|
|
242
|
+
Journal/timeline rows omit content by default; use `{includeContent: true}` in
|
|
243
|
+
library/tool options or CLI `--with-content`. Content appears once in review JSON.
|
|
244
|
+
|
|
245
|
+
Events support a free-text `channel` (trimmed, lowercased, at most 40 characters),
|
|
246
|
+
`parentRef`, `parentEventId`, and a root `threadRef`. Journal, timeline, moments,
|
|
247
|
+
and open commitment reviews accept a channel filter. Set event attributes with
|
|
248
|
+
`write.setAttribute(db, {kind: "event", eventId}, name, value)`; unset and replace
|
|
249
|
+
use the same target and validation as contact/link attributes.
|
|
250
|
+
|
|
251
|
+
Read exact events with `read.getEventById(db, eventId)` or
|
|
252
|
+
`read.getEventByExternalRef(db, source, id)`. `read.searchEvents` searches folded
|
|
253
|
+
summary, content, reference and channel text. The search tool's `scope` is
|
|
254
|
+
`contacts` by default, with additive `events` and `all` modes.
|
|
255
|
+
`read.getEventThread(db, source, id)` returns a root and its descendants in time
|
|
256
|
+
order, including parents imported after their children.
|
|
257
|
+
|
|
258
|
+
`write.reviseEvent(db, eventIdOrTarget, patch)` accepts summary, content,
|
|
259
|
+
occurredAt, significance, channel, type within the same event family, and an
|
|
260
|
+
externalRef only when absent. `write.deleteEvent(db, eventIdOrTarget,
|
|
261
|
+
{confirm: true})` removes evidence, participants, attributes and link effects,
|
|
262
|
+
then replays surviving effects and refreshes rollups. Targets can also be
|
|
263
|
+
`{ref: {source, id}}`. Existing 0.5.x databases migrate through
|
|
264
|
+
`initAffinityTables`. Historical affinity/trust/rank baselines are recovered
|
|
265
|
+
from saved deltas; historical cadence and state before evidence were not stored
|
|
266
|
+
and use the default cadence and active state during replay.
|
|
267
|
+
|
|
221
268
|
## CLI
|
|
222
269
|
|
|
223
270
|
```sh
|
|
@@ -252,6 +299,13 @@ ghostpaw-affinity commitment record|resolve [flags]
|
|
|
252
299
|
ghostpaw-affinity attribute set|unset|replace [flags]
|
|
253
300
|
ghostpaw-affinity date add|revise|remove [flags]
|
|
254
301
|
ghostpaw-affinity event record [flags]
|
|
302
|
+
ghostpaw-affinity show event --event-id 12
|
|
303
|
+
ghostpaw-affinity show event --ref-source bluesky --ref-id at://record
|
|
304
|
+
ghostpaw-affinity search --scope events "text or record id"
|
|
305
|
+
ghostpaw-affinity review events.contact_journal --contact '{"contactId":2}' --with-content --channel bluesky
|
|
306
|
+
ghostpaw-affinity review events.thread --ref-source bluesky --ref-id at://root
|
|
307
|
+
ghostpaw-affinity event revise --event-id 12 --patch '{"summary":"Corrected"}'
|
|
308
|
+
ghostpaw-affinity event delete --event-id 12 --confirm
|
|
255
309
|
ghostpaw-affinity duplicate dismiss|undismiss [flags]
|
|
256
310
|
ghostpaw-affinity mcp|skill|tools|describe|call|completions|version|help
|
|
257
311
|
```
|
|
@@ -265,15 +319,30 @@ to read a file; repeated array flags accept JSON objects
|
|
|
265
319
|
(`--entries '{"name":"a","value":"x"}'`) or one JSON array.
|
|
266
320
|
|
|
267
321
|
Every time field accepts epoch milliseconds, ISO 8601 with `Z` or an offset,
|
|
268
|
-
`YYYY-MM-DD`, `DD.MM.YYYY
|
|
269
|
-
such as `+3d` or `-2d
|
|
270
|
-
|
|
322
|
+
`YYYY-MM-DD`, `DD.MM.YYYY`, `today`, `tomorrow`, `yesterday` and signed day offsets
|
|
323
|
+
such as `+3d` or `-2d`, with the same grammar in CLI, MCP and direct tool calls.
|
|
324
|
+
Date-only values preserve their calendar day: timestamps use UTC midnight, or
|
|
325
|
+
23:59:59.999Z for `dueAt`. Keywords first resolve against the process local
|
|
326
|
+
calendar date; this is the only time-zone-dependent parsing step. `occurredOn`
|
|
327
|
+
and `dueOn` retain the input day (the written offset day for ISO inputs; UTC day
|
|
328
|
+
for epoch inputs). Existing rows derive these fields from their UTC timestamps.
|
|
329
|
+
Review rows for dates include `occursOn`, the anchor occurrence day; the library
|
|
330
|
+
keeps its numeric `occursOn` sorting key and adds `occursOnDate`.
|
|
331
|
+
The existing `*Iso` fields remain UTC. Overdue commitments compare the local
|
|
332
|
+
date to `dueOn`. Future events carry a `future_event` warning and do not count
|
|
333
|
+
as contact until their timestamp and day arrive. Commitments and their
|
|
334
|
+
resolutions do not reset recency or cadence. Radar marks `drift` after a gap
|
|
335
|
+
exceeds 1.5 times the expected cadence and explains its reasons in the snippet.
|
|
271
336
|
|
|
272
337
|
Global flags: `--db <path>`, `--json`, `--quiet`, `--compact`,
|
|
273
338
|
`--help`/`-h`, `--version`/`-V`/`-v`, `--no-color`.
|
|
274
339
|
`NO_COLOR` is accepted. In a terminal, commands print a readable summary with
|
|
275
340
|
names and dates. With `--json` or piped stdout they print the tool result as
|
|
276
|
-
JSON with ISO date siblings and floats rounded to three decimals
|
|
341
|
+
JSON with ISO date siblings and floats rounded to three decimals. Journal review rows
|
|
342
|
+
keep one summary and compact `{id,name,role}` participants. Radar rows keep one link
|
|
343
|
+
id, counterparty name, reasons and rounded scores; upcoming link dates omit radar
|
|
344
|
+
scores. Default piped writes and `--compact` keep primary and changed ids plus
|
|
345
|
+
warnings; explicit `--json` retains full mutation detail. `--compact`
|
|
277
346
|
removes indentation and empty receipt arrays. `--quiet` suppresses stdout.
|
|
278
347
|
Writes list what changed in `data.changes`, and creates warn about likely
|
|
279
348
|
duplicates. Kebab-case flags map to schema properties. `--` ends flags.
|
|
@@ -296,7 +365,24 @@ stderr. These commands work offline.
|
|
|
296
365
|
|
|
297
366
|
Errors go to stderr. With `--json`, errors also print to stdout.
|
|
298
367
|
`--version` names the variant: `affinity 0.5.0 (binary, linux-x64)`,
|
|
299
|
-
`(npm)` or `(library)`.
|
|
368
|
+
`(npm)` or `(library)`. Use `--version --short` in scripts for exact semver
|
|
369
|
+
matching. `--version --json` returns `name`, `version`, `variant` and `target`
|
|
370
|
+
(the target is null outside a binary). `version --short` and `version --json`
|
|
371
|
+
are equivalent.
|
|
372
|
+
|
|
373
|
+
Read commands (search, show, review and contact export, including direct tool
|
|
374
|
+
calls) exit 3 on a missing database without creating files:
|
|
375
|
+
`Database not found: <path> (it is created by the first write)`.
|
|
376
|
+
The first write creates the database and reports `created <path>` on stderr.
|
|
377
|
+
The MCP server continues to create its database on startup.
|
|
378
|
+
|
|
379
|
+
String-valued flags such as `--value Hamburg`, `--bond 'Warm lead'` and
|
|
380
|
+
`--reason 'Different people'` accept plain strings or JSON strings/null.
|
|
381
|
+
Object and array flags still require JSON. Tag filters accept both
|
|
382
|
+
`--tag gastro-radar` and `--tag tag:gastro-radar`.
|
|
383
|
+
Per-command `--help` lists the fields used by that action.
|
|
384
|
+
|
|
385
|
+
Legacy `tools [--json]`, `describe <tool>`,
|
|
300
386
|
`call <tool> [JSON|-]` and `<tool_name> --parameter value` remain available.
|
|
301
387
|
`completions bash|zsh|fish` prints shell scripts.
|
|
302
388
|
|
|
@@ -536,3 +622,92 @@ If this package helps your project, consider sponsoring its maintenance:
|
|
|
536
622
|
---
|
|
537
623
|
|
|
538
624
|
**[Anonyfox](https://anonyfox.com) • [MIT License](LICENSE)**
|
|
625
|
+
|
|
626
|
+
### Social imports and batch writes
|
|
627
|
+
|
|
628
|
+
Contact creation accepts `identities` and `ifExists: "error" | "return"` in the
|
|
629
|
+
library and tools. Identity ownership conflicts fail atomically (CLI exit 4),
|
|
630
|
+
including `data.existingContactId` and `error.details.existingContactId` in tool
|
|
631
|
+
results. `contact create '<JSON>' --if-exists return` returns the existing contact
|
|
632
|
+
with `outcome: "no_op"` and `matchedIdentities`; it attaches nothing, including
|
|
633
|
+
other free identities. Name-only duplicates still receive a possible-duplicate
|
|
634
|
+
warning. Links can opt into `input.ifExists: "return"` when seeding repeatedly. Identity
|
|
635
|
+
addition supports the same opt-in policy for an identity already on that contact;
|
|
636
|
+
another contact still conflicts. Importers add changed handles separately after
|
|
637
|
+
contact creation.
|
|
638
|
+
|
|
639
|
+
Handle identities strip a leading `@` and lowercase on add, revise and lookup.
|
|
640
|
+
Bluesky handles must be domain-like, X/Twitter handles have 1–15 letters, digits
|
|
641
|
+
or underscores, and Mastodon handles use `user@host.tld`. Use native `did` (alias
|
|
642
|
+
`atproto_did`) for stable AT Protocol identities. Locators also find legacy
|
|
643
|
+
`custom:atproto-did` rows. Keep former handles as additional identities.
|
|
644
|
+
`search @handle` works because CLI values are literal.
|
|
645
|
+
|
|
646
|
+
Only the JSON payload arguments (`--input`, the positional `<input>`, `--patch`
|
|
647
|
+
and the `call` argument) read files. Their help line ends with
|
|
648
|
+
`(@file, @- stdin, @@ literal @)`: `@path` reads the file as UTF-8 relative to
|
|
649
|
+
the current directory, `@-` reads stdin, and `@@text` passes the literal
|
|
650
|
+
`@text`. An empty path (`@`) or an unreadable file exits 2. Every other value,
|
|
651
|
+
including names, notes, attribute values and search queries, is taken byte for
|
|
652
|
+
byte, even with a leading `@` or `@@`.
|
|
653
|
+
|
|
654
|
+
For large payloads use stdin or `@file` to avoid the operating system's argv
|
|
655
|
+
size limit (`E2BIG`). JSON flag values support `-` too:
|
|
656
|
+
|
|
657
|
+
```sh
|
|
658
|
+
ghostpaw-affinity event record --kind interaction --input - < event.json
|
|
659
|
+
ghostpaw-affinity event record --kind interaction --input @event.json
|
|
660
|
+
ghostpaw-affinity review events.contact_journal --contact '{"contactId":2}' --event-types '["conversation","observation"]'
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
Array flags accept JSON arrays, comma lists, or repeated flags. Unknown event
|
|
664
|
+
types fail with exit 2 and allowed values. SQLite timestamps such as
|
|
665
|
+
`2026-10-27 17:51:33` use UTC; explicit offsets are honored. Sub-millisecond
|
|
666
|
+
fractions are rounded silently to milliseconds, including carry into the next
|
|
667
|
+
second. Keep the original timestamp in the source archive if finer precision
|
|
668
|
+
matters. Null `occurredAt` is invalid.
|
|
669
|
+
|
|
670
|
+
Record likes, reposts and follows as observations with `affectsBond: false`.
|
|
671
|
+
Observations with significance <= 2 default to false; other events default to
|
|
672
|
+
true. These ambient records stay in the journal without changing affinity or
|
|
673
|
+
recency. `provenance.ambient: true` also suppresses bond effects. Explicitly
|
|
674
|
+
outbound-only evidence contributes much less and does not reset radar recency;
|
|
675
|
+
without reciprocal contact it generates no routine check-in or drift prompt.
|
|
676
|
+
Include the owner explicitly with the correct actor/recipient role and use
|
|
677
|
+
`owner_initiated`, `other_initiated`, or `mutual` directionality. Observations and
|
|
678
|
+
follow-like milestones never derive breakthroughs; low-significance milestones
|
|
679
|
+
do not derive moments. An explicit `momentKind` is honored.
|
|
680
|
+
|
|
681
|
+
List reviews default to 50 rows, accept `--limit` (up to 250) and `--offset`,
|
|
682
|
+
and include `total` and `hasMore`. Follow `hasMore` rather than assuming the
|
|
683
|
+
first page is complete.
|
|
684
|
+
|
|
685
|
+
`batch` reads one tool invocation per JSONL line, with one transaction for the
|
|
686
|
+
whole input by default, or one per `--chunk N` lines. Each line has its own
|
|
687
|
+
savepoint: failed lines roll back and later lines continue. `--stop-on-error`
|
|
688
|
+
stops at the first failure. Results are JSONL `{line, ok, outcome, id, error?}`
|
|
689
|
+
plus `{done, created, noOp, failed}`; created counts successful non-no-op lines.
|
|
690
|
+
Exit status is 0 for success, 1 for failures, or 2 if a line is invalid JSON.
|
|
691
|
+
Committed chunks remain committed if a later chunk fails.
|
|
692
|
+
|
|
693
|
+
```jsonl
|
|
694
|
+
{"tool":"manage_contact","args":{"action":"create","input":{"name":"Owner","kind":"human","bootstrapOwner":true,"ifExists":"return","identities":[{"type":"did","value":"did:plc:owner"}]}}}
|
|
695
|
+
{"op":"event","kind":"observation","input":{"occurredAt":"2026-10-27","content":"","significance":1,"affectsBond":false,"externalRef":{"source":"bluesky","id":"at://example/like/1"},"participants":[{"contactId":1,"role":"actor"}]}}
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
```sh
|
|
699
|
+
ghostpaw-affinity batch --chunk 500 < import.jsonl
|
|
700
|
+
node scripts/examples/import_social_jsonl.mjs scripts/examples/fixtures/social_sample.json | ghostpaw-affinity --db /tmp/social-demo.db batch
|
|
701
|
+
node scripts/examples/import_dry_run.mjs
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
The dependency-free example consumes a JSON export shaped as accounts, posts,
|
|
705
|
+
interactions and follows; it never opens the source database. It resolves handle
|
|
706
|
+
aliases to DIDs, deduplicates record URIs, keeps content verbatim, sets channel,
|
|
707
|
+
parent references and directionality, and uses first_seen for undated follows
|
|
708
|
+
or counts a skipped timestamp. The dry run checks two imports, DID uniqueness
|
|
709
|
+
and byte-identical content, and reports journal JSON bytes versus raw text bytes.
|
|
710
|
+
Examples and synthetic fixtures are development files, outside the npm package.
|
|
711
|
+
|
|
712
|
+
`ghostpaw-affinity skill --short` prints the compact command reference without
|
|
713
|
+
frontmatter or an appendix. `skill --list` lists guides; `skill <guide>` reads one.
|