@hraness/message-like-me 0.8.7 → 0.8.8
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/CHANGELOG.md +7 -0
- package/README.md +41 -33
- package/SECURITY.md +6 -6
- package/dist/agentic-messaging-v1.d.ts +44 -25
- package/dist/agentic-messaging-v1.js +81 -67
- package/dist/cli.js +91 -83
- package/docs/local-message-bundle-v1.md +11 -10
- package/docs/local-message-bundle-v2.md +10 -9
- package/docs/methodology.md +1 -1
- package/package.json +1 -1
- package/skills/message-like-me/SKILL.md +6 -6
- package/skills/message-like-me/references/privacy.md +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.8 (2026-09-09)
|
|
4
|
+
|
|
5
|
+
- Route installation to the exact public `@hraness/message-like-me@0.8.8` npm package after release admission, with the same reviewed bytes in the immutable GitHub Release.
|
|
6
|
+
- Use Ghostget in current CLI options, SDK names, source guidance, and the public site. Keep the original Wrench options and exports as compatibility aliases.
|
|
7
|
+
- Accept `ghostgetContext` when preparing a handoff while preserving the existing serialized handoff, receipt, contract hashes, and local history. Reject simultaneous context aliases.
|
|
8
|
+
- Point Ghostget setup to its exact canonical GitHub Release archive.
|
|
9
|
+
|
|
3
10
|
## 0.8.7 (2026-09-09)
|
|
4
11
|
|
|
5
12
|
- Make the exact public `@hraness/message-like-me@0.8.7` npm package the
|
package/README.md
CHANGED
|
@@ -12,9 +12,9 @@ Like Me and Ensoul Agent Skills teach Codex, Claude, and other coding agents how
|
|
|
12
12
|
to interpret those artifacts through the agent environment you already use.
|
|
13
13
|
|
|
14
14
|
Beeper users can bring a bounded observation from supported connected accounts
|
|
15
|
-
into the same private evidence layer as Apple Messages.
|
|
15
|
+
into the same private evidence layer as Apple Messages. Ghostget writes a finished
|
|
16
16
|
local bundle; Message Like Me verifies and ingests that directory. It receives
|
|
17
|
-
no provider credentials, never calls
|
|
17
|
+
no provider credentials, never calls Ghostget or a Beeper operation, and never
|
|
18
18
|
sends. Every ingest path is read-only with respect to its source.
|
|
19
19
|
|
|
20
20
|
The result is an inspectable evidence layer for relationship-aware drafting,
|
|
@@ -43,7 +43,7 @@ Message Like Me requires Bun 1.3.14 or newer. Install the exact public npm
|
|
|
43
43
|
package, then install both bundled Agent Skills:
|
|
44
44
|
|
|
45
45
|
```sh
|
|
46
|
-
bun add --global @hraness/message-like-me@0.8.
|
|
46
|
+
bun add --global @hraness/message-like-me@0.8.8
|
|
47
47
|
messagelikeme skill install
|
|
48
48
|
```
|
|
49
49
|
|
|
@@ -107,8 +107,8 @@ visibly instead of being treated as current.
|
|
|
107
107
|
| --- | --- | --- |
|
|
108
108
|
| Apple Messages | The current macOS user's native `chat.db` history | Read-only ingestion from an ownership-checked stable local copy; Messages is never operated or changed. |
|
|
109
109
|
| X data archive | Direct-message history in a caller-owned archive ZIP | X Chat is not included; the importer does not contact X, extract the archive, or download media. |
|
|
110
|
-
| Beeper via
|
|
111
|
-
| WhatsApp via
|
|
110
|
+
| Beeper via Ghostget | A finished local bundle from Ghostget v0.17.1 and adapter 2.4.0; its reviewed surface has 32 operations: 26 through one pinned Beeper CLI 0.6.2 executable, including supported actions and writes, plus six fixed Desktop loopback reads | Message Like Me receives no provider credentials, never calls Ghostget or a Beeper operation, and never sends; it reads only the finished bundle and does not claim complete history. |
|
|
111
|
+
| WhatsApp via Ghostget | A one-account native bundle produced by Ghostget v0.17.1 with official Wacli 0.15.0 | Reaction-shaped rows are omitted with `reaction-state-unproven` when current state cannot be proved. Message Like Me verifies the finished bundle and never operates WhatsApp. |
|
|
112
112
|
| macOS Contacts | Optional names and exact email or phone handles from AddressBook | Label enrichment only; Contacts is not a messaging-history source and is never changed. |
|
|
113
113
|
|
|
114
114
|
## Add private local history
|
|
@@ -187,13 +187,14 @@ same or a later archive preserves proven deduplication; archive absence does not
|
|
|
187
187
|
delete retained history.
|
|
188
188
|
|
|
189
189
|
To study accounts connected through Beeper, install the currently verified
|
|
190
|
-
[`@hraness/
|
|
191
|
-
|
|
190
|
+
[`@hraness/ghostget@0.17.1`](https://github.com/hraness/ghostget/releases/download/v0.17.1/hraness-ghostget-0.17.1.tgz)
|
|
191
|
+
canonical GitHub Release archive, then use Ghostget to create a new private Message Like Me
|
|
192
192
|
bundle:
|
|
193
193
|
|
|
194
194
|
```sh
|
|
195
|
-
bun add --global
|
|
196
|
-
|
|
195
|
+
bun add --global https://github.com/hraness/ghostget/releases/download/v0.17.1/hraness-ghostget-0.17.1.tgz
|
|
196
|
+
ghostget adapter sync-bundled --json
|
|
197
|
+
ghostget beeper export-message-like-me \
|
|
197
198
|
--auth <beeper-auth-id> \
|
|
198
199
|
--output /absolute/private/path/beeper-bundle \
|
|
199
200
|
--json
|
|
@@ -201,21 +202,21 @@ wrench beeper export-message-like-me \
|
|
|
201
202
|
|
|
202
203
|
The optional `--limit-chats`, `--limit-messages`, and `--max-participants`
|
|
203
204
|
flags lower the export bounds. The output path must be a normalized absolute
|
|
204
|
-
path to a directory that does not already exist.
|
|
205
|
+
path to a directory that does not already exist. Ghostget v0.17.1 adapter
|
|
205
206
|
`beeper-local@2.4.0` exposes 32 reviewed Beeper operations: 26 through one
|
|
206
207
|
pinned Beeper CLI 0.6.2 executable, including supported actions and writes, plus
|
|
207
|
-
six fixed Desktop loopback reads. Message Like Me never calls
|
|
208
|
-
those Beeper operations. The bundle command enters
|
|
208
|
+
six fixed Desktop loopback reads. Message Like Me never calls Ghostget or any of
|
|
209
|
+
those Beeper operations. The bundle command enters Ghostget's separate internal
|
|
209
210
|
bounded export, which fixes the raw export arguments, excludes attachments, and
|
|
210
211
|
preserves explicit incomplete-coverage evidence instead of claiming full
|
|
211
212
|
history.
|
|
212
213
|
|
|
213
|
-
|
|
214
|
+
Ghostget calls the pinned
|
|
214
215
|
[official Beeper CLI 0.6.2 release](https://github.com/beeper/cli/releases/tag/v0%2E6%2E2)
|
|
215
216
|
directly. The executable reports version `0.6.2`, which is the runtime
|
|
216
217
|
authority. At the upstream tag, `packages/cli/package.json` declares `0.6.1`;
|
|
217
218
|
that source-package value is provenance only and never overrides the executable
|
|
218
|
-
runtime identity.
|
|
219
|
+
runtime identity. Ghostget enumerates
|
|
219
220
|
the connected account realm, invokes `export --no-attachments` once per
|
|
220
221
|
account in deterministic order, and reports the account ordinal, elapsed-time
|
|
221
222
|
heartbeats, and cumulative validated chat and message counts on stderr. It
|
|
@@ -228,7 +229,7 @@ export path does not use it. The pinned CLI path supplies the bounded account
|
|
|
228
229
|
snapshots and local files needed for hash validation, deterministic conversion,
|
|
229
230
|
crash recovery, and atomic publication. Provider URLs and credentials are
|
|
230
231
|
excluded. Message Like Me does not receive the Beeper credential or live
|
|
231
|
-
session, start
|
|
232
|
+
session, start Ghostget, invoke a Beeper operation, or send a message.
|
|
232
233
|
|
|
233
234
|
Ingest the finished directory, then inspect its redacted source health:
|
|
234
235
|
|
|
@@ -247,9 +248,9 @@ iMessage and prior bundle sources remain alongside it.
|
|
|
247
248
|
The interchange, integrity, identity, and reimport laws are in the
|
|
248
249
|
[version-one local message bundle contract](docs/local-message-bundle-v1.md).
|
|
249
250
|
Message Like Me accepts bundle schema `1` with source ID `beeper-local` and
|
|
250
|
-
source-transform version `1.1.0`.
|
|
251
|
+
source-transform version `1.1.0`. Ghostget v0.17.1 is the currently verified
|
|
251
252
|
producer. Compatibility is determined by those exact manifest coordinates,
|
|
252
|
-
not by an open-ended
|
|
253
|
+
not by an open-ended Ghostget package range.
|
|
253
254
|
|
|
254
255
|
Beeper exports describe bounded local observations. A later bounded export
|
|
255
256
|
that omits an older record does not delete retained history. Explicit deletion,
|
|
@@ -258,12 +259,13 @@ reappearance restores it. Older snapshots cannot overwrite newer state. Use
|
|
|
258
259
|
`sources show <source-id> --private --json` only when you deliberately need the
|
|
259
260
|
private provider account and source metadata.
|
|
260
261
|
|
|
261
|
-
For native WhatsApp evidence, install
|
|
262
|
+
For native WhatsApp evidence, install Ghostget v0.17.1 and let its official
|
|
262
263
|
Wacli 0.15.0 adapter create the one-account v2 bundle:
|
|
263
264
|
|
|
264
265
|
```sh
|
|
265
|
-
bun add --global
|
|
266
|
-
|
|
266
|
+
bun add --global https://github.com/hraness/ghostget/releases/download/v0.17.1/hraness-ghostget-0.17.1.tgz
|
|
267
|
+
ghostget adapter sync-bundled --json
|
|
268
|
+
ghostget whatsapp export-message-like-me \
|
|
267
269
|
--auth <whatsapp-auth-id> \
|
|
268
270
|
--output /absolute/private/path/whatsapp-bundle \
|
|
269
271
|
--json
|
|
@@ -282,7 +284,7 @@ surfaces are excluded. The complete contract is in
|
|
|
282
284
|
[local message bundle v2](docs/local-message-bundle-v2.md).
|
|
283
285
|
|
|
284
286
|
Wacli v0.15.0 may retain an earlier emoji after a reaction is removed, so its
|
|
285
|
-
local rows cannot prove current active reaction state.
|
|
287
|
+
local rows cannot prove current active reaction state. Ghostget v0.17.1 omits
|
|
286
288
|
every reaction-shaped row and adds `reaction-state-unproven` when it observes
|
|
287
289
|
one. An empty `reactions.ndjson` from this producer means reaction behavior was
|
|
288
290
|
unobservable, not that the account had no reactions. The v2 wire contract keeps
|
|
@@ -386,8 +388,8 @@ person scopes and labels, never handles or message bodies.
|
|
|
386
388
|
## Prepare an exact private agent handoff
|
|
387
389
|
|
|
388
390
|
Message Like Me can bind an ordered unsent draft to one exact local
|
|
389
|
-
source-conversation candidate and one current opaque
|
|
390
|
-
does not invoke
|
|
391
|
+
source-conversation candidate and one current opaque Ghostget context. It still
|
|
392
|
+
does not invoke Ghostget, authenticate, launch a provider command, access a
|
|
391
393
|
network, or send a message.
|
|
392
394
|
|
|
393
395
|
Start with the redacted candidate inventory:
|
|
@@ -404,24 +406,24 @@ Ordinary stdout reports only its digest, counts, and selection state.
|
|
|
404
406
|
the exact account, source, and tagged conversation coordinate already observed
|
|
405
407
|
in that imported source: `beeperConversation` for a Beeper bundle,
|
|
406
408
|
`whatsappJid` for a native Wacli bundle, or `imessageChat` for Messages. It never
|
|
407
|
-
emits names, handles, participants, or a locator derived from them.
|
|
409
|
+
emits names, handles, participants, or a locator derived from them. Ghostget
|
|
408
410
|
rejects a coordinate whose tag does not match the selected provider adapter.
|
|
409
411
|
|
|
410
412
|
An X archive candidate is always `evidence-only` with reason
|
|
411
413
|
`archive-source`. Handoff v1 also keeps group candidates evidence-only as an
|
|
412
|
-
explicit direct-conversation product limit. This does not claim that
|
|
414
|
+
explicit direct-conversation product limit. This does not claim that Ghostget or
|
|
413
415
|
a provider cannot address an exact group. It prevents Message Like Me from
|
|
414
416
|
authorizing one through this first handoff contract. Several eligible direct
|
|
415
417
|
candidates produce an `ambiguous` selection state; no route is chosen from a
|
|
416
418
|
name, title, participant list, or merged person scope.
|
|
417
419
|
|
|
418
|
-
After
|
|
420
|
+
After Ghostget has written its exact current context and the agent has written an
|
|
419
421
|
ordered one-to-eight-bubble draft, prepare one private handoff:
|
|
420
422
|
|
|
421
423
|
```sh
|
|
422
424
|
messagelikeme handoff prepare <contact-id> \
|
|
423
425
|
--request /absolute/private/handoff-request.json \
|
|
424
|
-
--
|
|
426
|
+
--ghostget-context /absolute/private/ghostget-context.json \
|
|
425
427
|
--draft /absolute/private/draft.json \
|
|
426
428
|
--output /absolute/private/handoff.json \
|
|
427
429
|
--json
|
|
@@ -434,21 +436,21 @@ singly linked physical files. The context must carry the pinned
|
|
|
434
436
|
an unexpired opaque route and context reference, and exact SHA-256 data and
|
|
435
437
|
latest-message revisions. The output is a mode-`0600` file whose canonical
|
|
436
438
|
digest binds those values, the selected source revision, corpus and profile
|
|
437
|
-
evidence, bubble order, text, and optional reply references. Raw opaque
|
|
439
|
+
evidence, bubble order, text, and optional reply references. Raw opaque Ghostget
|
|
438
440
|
references and draft bodies appear only in the explicit private inputs and
|
|
439
441
|
handoff file.
|
|
440
442
|
|
|
441
443
|
Verification and audit commands emit hashes, counts, timestamps, and
|
|
442
|
-
pseudonymous IDs without bodies or raw
|
|
444
|
+
pseudonymous IDs without bodies or raw Ghostget references:
|
|
443
445
|
|
|
444
446
|
```sh
|
|
445
447
|
messagelikeme handoff verify /absolute/private/handoff.json --json
|
|
446
448
|
messagelikeme handoff record <handoff-id> \
|
|
447
|
-
--
|
|
449
|
+
--ghostget-receipt /absolute/private/ghostget-receipt.json --json
|
|
448
450
|
messagelikeme handoffs show <handoff-id> --json
|
|
449
451
|
```
|
|
450
452
|
|
|
451
|
-
Recording requires
|
|
453
|
+
Recording requires Ghostget's pinned body-free receipt binding. It carries the
|
|
452
454
|
provider-neutral client-intent digest, set to this exact Message Like Me
|
|
453
455
|
handoff digest, along with route-reference, context-reference, exact-turn, and
|
|
454
456
|
private-preview digests. It also carries the proven prefix and a canonical
|
|
@@ -664,9 +666,9 @@ messagelikeme profile show CONTACT_ID [--json]
|
|
|
664
666
|
messagelikeme profile export CONTACT_ID --output FILE [--json]
|
|
665
667
|
messagelikeme context CONTACT_ID [--json]
|
|
666
668
|
messagelikeme handoff prepare CONTACT_ID --request FILE
|
|
667
|
-
--
|
|
669
|
+
--ghostget-context FILE --draft FILE --output FILE [--json]
|
|
668
670
|
messagelikeme handoff verify FILE [--json]
|
|
669
|
-
messagelikeme handoff record HANDOFF_ID --
|
|
671
|
+
messagelikeme handoff record HANDOFF_ID --ghostget-receipt FILE [--json]
|
|
670
672
|
messagelikeme handoffs show HANDOFF_ID [--json]
|
|
671
673
|
messagelikeme skill path [--json]
|
|
672
674
|
messagelikeme skill install [--target codex|claude|agents]
|
|
@@ -789,3 +791,9 @@ the site, and the site never receives message or contact data.
|
|
|
789
791
|
## License
|
|
790
792
|
|
|
791
793
|
MIT.
|
|
794
|
+
|
|
795
|
+
Ghostget is the current name of Wrench. The original `--wrench-context` and
|
|
796
|
+
`--wrench-receipt` options remain aliases for the documented Ghostget options. The SDK accepts
|
|
797
|
+
`ghostgetContext` and retains the original `wrenchContext` input alias.
|
|
798
|
+
Existing bundle, handoff, receipt, and database formats retain their versioned
|
|
799
|
+
`wrench` identifiers so saved evidence remains verifiable.
|
package/SECURITY.md
CHANGED
|
@@ -24,8 +24,8 @@ following values are sensitive even when they do not contain an obvious name:
|
|
|
24
24
|
- the per-install HMAC key and all normalized corpus records;
|
|
25
25
|
- aggregate metrics, study packets, style profiles, drafting context, and
|
|
26
26
|
unsent drafts;
|
|
27
|
-
- opaque
|
|
28
|
-
|
|
27
|
+
- opaque Ghostget route and context references, private handoff files, and full
|
|
28
|
+
Ghostget receipts before their body-free audit projection.
|
|
29
29
|
|
|
30
30
|
The default data root is
|
|
31
31
|
`~/Library/Application Support/Message Like Me/` on macOS. The CLI creates
|
|
@@ -49,19 +49,19 @@ participant set. X archives are evidence-only. Handoff v1 also rejects group
|
|
|
49
49
|
candidates, and an ambiguous direct-candidate inventory does not choose a
|
|
50
50
|
route automatically.
|
|
51
51
|
|
|
52
|
-
`handoff prepare` reads a mode-`0600`, singly linked route request,
|
|
52
|
+
`handoff prepare` reads a mode-`0600`, singly linked route request, Ghostget
|
|
53
53
|
context file, and draft file through stable file descriptors. A route candidate
|
|
54
54
|
never appears in argv or stdout. It rejects symlinks,
|
|
55
55
|
foreign ownership, broader permissions, file replacement, invalid UTF-8,
|
|
56
56
|
unknown contract fields, unsupported contract hashes, stale context, controls,
|
|
57
57
|
duplicate bubble IDs, and byte or count overages. The output is another
|
|
58
|
-
explicit mode-`0600` file. Message text and raw
|
|
58
|
+
explicit mode-`0600` file. Message text and raw Ghostget route or context
|
|
59
59
|
references never enter argv, ordinary stdout, diagnostics, or the SQLite audit
|
|
60
60
|
table.
|
|
61
61
|
|
|
62
|
-
The body-free
|
|
62
|
+
The body-free Ghostget receipt binding contains no raw route or context
|
|
63
63
|
reference. Its pinned contract binds hashes of those references, the client
|
|
64
|
-
intent, the exact ordered turn, and the private preview. The generic
|
|
64
|
+
intent, the exact ordered turn, and the private preview. The generic Ghostget
|
|
65
65
|
field is `clientIntentSha256`; Message Like Me sets it to the exact private
|
|
66
66
|
handoff digest. The binding also carries its proven-prefix state and canonical
|
|
67
67
|
receipt digest. The local handoff audit stores those hashes, counts,
|
|
@@ -3,19 +3,19 @@ export declare const AGENT_MESSAGE_DRAFT_V1_FORMAT: "message-like-me.agent-messa
|
|
|
3
3
|
export declare const AGENT_MESSAGE_HANDOFF_REQUEST_V1_FORMAT: "message-like-me.agent-message-handoff-request";
|
|
4
4
|
export declare const AGENT_MESSAGE_HANDOFF_V1_FORMAT: "message-like-me.agent-message-handoff";
|
|
5
5
|
export declare const AGENT_MESSAGE_AUDIT_V1_FORMAT: "message-like-me.agent-message-handoff-audit";
|
|
6
|
-
export declare const
|
|
7
|
-
export declare const
|
|
8
|
-
export declare const
|
|
9
|
-
export declare const
|
|
10
|
-
export declare const
|
|
6
|
+
export declare const GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT: "wrench.messaging-context-binding";
|
|
7
|
+
export declare const GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT: "wrench.messaging-receipt-binding";
|
|
8
|
+
export declare const GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID: "wrench.messaging-context-binding.v1";
|
|
9
|
+
export declare const GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH: "5e64da6a3d826e7f6fa3db7dca0a4ba92c10cfb784981e71a25aed9513a5c687";
|
|
10
|
+
export declare const GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR: Readonly<{
|
|
11
11
|
contractId: "wrench.messaging-context-binding.v1";
|
|
12
12
|
fields: readonly string[];
|
|
13
13
|
format: "wrench.messaging-contract-descriptor";
|
|
14
14
|
schemaVersion: 1;
|
|
15
15
|
}>;
|
|
16
|
-
export declare const
|
|
17
|
-
export declare const
|
|
18
|
-
export declare const
|
|
16
|
+
export declare const GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID: "wrench.messaging-receipt-binding.v1";
|
|
17
|
+
export declare const GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH: "7f6cf724f0200b2399e4f4641c637b20b48914fc5c9b13755127a8ec69fe66f4";
|
|
18
|
+
export declare const GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_DESCRIPTOR: Readonly<{
|
|
19
19
|
contractId: "wrench.messaging-receipt-binding.v1";
|
|
20
20
|
fields: readonly string[];
|
|
21
21
|
format: "wrench.messaging-contract-descriptor";
|
|
@@ -30,11 +30,11 @@ export declare const AGENTIC_MESSAGING_V1_LIMITS: Readonly<{
|
|
|
30
30
|
readonly handoffLifetimeMilliseconds: number;
|
|
31
31
|
readonly maximumContextLifetimeMilliseconds: number;
|
|
32
32
|
}>;
|
|
33
|
-
export type
|
|
33
|
+
export type GhostgetMessagingContextBindingV1 = Readonly<{
|
|
34
34
|
schemaVersion: typeof AGENTIC_MESSAGING_V1_SCHEMA_VERSION;
|
|
35
|
-
format: typeof
|
|
36
|
-
contractId: typeof
|
|
37
|
-
contractHash: typeof
|
|
35
|
+
format: typeof GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT;
|
|
36
|
+
contractId: typeof GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID;
|
|
37
|
+
contractHash: typeof GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH;
|
|
38
38
|
routeRef: string;
|
|
39
39
|
contextRef: string;
|
|
40
40
|
exactDataRevision: string;
|
|
@@ -77,8 +77,8 @@ export type AgentMessageHandoffV1 = Readonly<{
|
|
|
77
77
|
profileEvidenceRevision: string | null;
|
|
78
78
|
}>;
|
|
79
79
|
wrench: Readonly<{
|
|
80
|
-
contractId: typeof
|
|
81
|
-
contractHash: typeof
|
|
80
|
+
contractId: typeof GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID;
|
|
81
|
+
contractHash: typeof GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH;
|
|
82
82
|
routeRef: string;
|
|
83
83
|
routeRefSha256: string;
|
|
84
84
|
contextRef: string;
|
|
@@ -140,19 +140,19 @@ export type AgentMessageRouteCandidateV1 = Readonly<{
|
|
|
140
140
|
}>;
|
|
141
141
|
}> | null;
|
|
142
142
|
}>;
|
|
143
|
-
export type
|
|
144
|
-
export type
|
|
143
|
+
export type GhostgetMessagingReceiptStateV1 = "failed" | "indeterminate" | "partial" | "submitted";
|
|
144
|
+
export type GhostgetMessagingReceiptBindingV1 = Readonly<{
|
|
145
145
|
schemaVersion: typeof AGENTIC_MESSAGING_V1_SCHEMA_VERSION;
|
|
146
|
-
format: typeof
|
|
147
|
-
contractId: typeof
|
|
148
|
-
contractHash: typeof
|
|
146
|
+
format: typeof GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT;
|
|
147
|
+
contractId: typeof GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID;
|
|
148
|
+
contractHash: typeof GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH;
|
|
149
149
|
clientIntentSha256: string;
|
|
150
150
|
routeRefSha256: string;
|
|
151
151
|
contextRefSha256: string;
|
|
152
152
|
turnDigest: string;
|
|
153
153
|
previewDigest: string;
|
|
154
154
|
runId: string;
|
|
155
|
-
state:
|
|
155
|
+
state: GhostgetMessagingReceiptStateV1;
|
|
156
156
|
partCount: number;
|
|
157
157
|
provenPartCount: number;
|
|
158
158
|
receiptSha256: string;
|
|
@@ -162,7 +162,7 @@ export declare class AgenticMessagingV1ContractError extends TypeError {
|
|
|
162
162
|
readonly code: "agentic-messaging-v1-contract";
|
|
163
163
|
constructor(message: string, options?: ErrorOptions);
|
|
164
164
|
}
|
|
165
|
-
export declare function
|
|
165
|
+
export declare function parseGhostgetMessagingContextBindingV1(value: unknown): GhostgetMessagingContextBindingV1;
|
|
166
166
|
export declare function parseAgentMessageDraftV1(value: unknown): AgentMessageDraftV1;
|
|
167
167
|
export declare function parseAgentMessageHandoffRequestV1(value: unknown): AgentMessageHandoffRequestV1;
|
|
168
168
|
export declare function createAgentMessageHandoffV1(input: Readonly<{
|
|
@@ -170,10 +170,29 @@ export declare function createAgentMessageHandoffV1(input: Readonly<{
|
|
|
170
170
|
expiresAt: string;
|
|
171
171
|
contact: AgentMessageHandoffV1["contact"];
|
|
172
172
|
evidence: AgentMessageHandoffV1["evidence"];
|
|
173
|
-
wrenchContext: WrenchMessagingContextBindingV1;
|
|
174
173
|
draft: AgentMessageDraftV1;
|
|
175
|
-
}
|
|
174
|
+
} & ({
|
|
175
|
+
ghostgetContext: GhostgetMessagingContextBindingV1;
|
|
176
|
+
wrenchContext?: never;
|
|
177
|
+
} | {
|
|
178
|
+
ghostgetContext?: never;
|
|
179
|
+
wrenchContext: GhostgetMessagingContextBindingV1;
|
|
180
|
+
})>): AgentMessageHandoffV1;
|
|
176
181
|
export declare function parseAgentMessageHandoffV1(value: unknown): AgentMessageHandoffV1;
|
|
177
|
-
export declare function
|
|
178
|
-
export declare function
|
|
182
|
+
export declare function ghostgetMessagingTurnDigestV1(value: unknown): string;
|
|
183
|
+
export declare function parseGhostgetMessagingReceiptBindingV1(value: unknown): GhostgetMessagingReceiptBindingV1;
|
|
179
184
|
export declare function agentMessageRouteCandidateId(sourceId: string, conversationId: string): string;
|
|
185
|
+
export { GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT as WRENCH_MESSAGING_CONTEXT_BINDING_V1_FORMAT };
|
|
186
|
+
export { GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT as WRENCH_MESSAGING_RECEIPT_BINDING_V1_FORMAT };
|
|
187
|
+
export { GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID as WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID };
|
|
188
|
+
export { GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH as WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH };
|
|
189
|
+
export { GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR as WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR };
|
|
190
|
+
export { GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID as WRENCH_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID };
|
|
191
|
+
export { GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH as WRENCH_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH };
|
|
192
|
+
export { GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_DESCRIPTOR as WRENCH_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_DESCRIPTOR };
|
|
193
|
+
export { type GhostgetMessagingContextBindingV1 as WrenchMessagingContextBindingV1 };
|
|
194
|
+
export { type GhostgetMessagingReceiptStateV1 as WrenchMessagingReceiptStateV1 };
|
|
195
|
+
export { type GhostgetMessagingReceiptBindingV1 as WrenchMessagingReceiptBindingV1 };
|
|
196
|
+
export { parseGhostgetMessagingContextBindingV1 as parseWrenchMessagingContextBindingV1 };
|
|
197
|
+
export { ghostgetMessagingTurnDigestV1 as wrenchMessagingTurnDigestV1 };
|
|
198
|
+
export { parseGhostgetMessagingReceiptBindingV1 as parseWrenchMessagingReceiptBindingV1 };
|
|
@@ -11,12 +11,12 @@ var AGENT_MESSAGE_DRAFT_V1_FORMAT = "message-like-me.agent-message-draft";
|
|
|
11
11
|
var AGENT_MESSAGE_HANDOFF_REQUEST_V1_FORMAT = "message-like-me.agent-message-handoff-request";
|
|
12
12
|
var AGENT_MESSAGE_HANDOFF_V1_FORMAT = "message-like-me.agent-message-handoff";
|
|
13
13
|
var AGENT_MESSAGE_AUDIT_V1_FORMAT = "message-like-me.agent-message-handoff-audit";
|
|
14
|
-
var
|
|
15
|
-
var
|
|
16
|
-
var
|
|
17
|
-
var
|
|
18
|
-
var
|
|
19
|
-
contractId:
|
|
14
|
+
var GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT = "wrench.messaging-context-binding";
|
|
15
|
+
var GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT = "wrench.messaging-receipt-binding";
|
|
16
|
+
var GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID = "wrench.messaging-context-binding.v1";
|
|
17
|
+
var GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH = "5e64da6a3d826e7f6fa3db7dca0a4ba92c10cfb784981e71a25aed9513a5c687";
|
|
18
|
+
var GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR = Object.freeze({
|
|
19
|
+
contractId: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID,
|
|
20
20
|
fields: Object.freeze([
|
|
21
21
|
"schemaVersion:1",
|
|
22
22
|
"format:wrench.messaging-context-binding",
|
|
@@ -32,10 +32,10 @@ var WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR = Object.freeze({
|
|
|
32
32
|
format: "wrench.messaging-contract-descriptor",
|
|
33
33
|
schemaVersion: 1
|
|
34
34
|
});
|
|
35
|
-
var
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
contractId:
|
|
35
|
+
var GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID = "wrench.messaging-receipt-binding.v1";
|
|
36
|
+
var GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH = "7f6cf724f0200b2399e4f4641c637b20b48914fc5c9b13755127a8ec69fe66f4";
|
|
37
|
+
var GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_DESCRIPTOR = Object.freeze({
|
|
38
|
+
contractId: GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID,
|
|
39
39
|
fields: Object.freeze([
|
|
40
40
|
"schemaVersion:1",
|
|
41
41
|
"format:wrench.messaging-receipt-binding",
|
|
@@ -191,8 +191,8 @@ function handoffCore(value) {
|
|
|
191
191
|
function handoffDigest(value) {
|
|
192
192
|
return sha256(canonicalJson(handoffCore(value)));
|
|
193
193
|
}
|
|
194
|
-
function
|
|
195
|
-
const record = object(value, "
|
|
194
|
+
function parseGhostgetMessagingContextBindingV1(value) {
|
|
195
|
+
const record = object(value, "Ghostget messaging context binding");
|
|
196
196
|
exactKeys(record, [
|
|
197
197
|
"schemaVersion",
|
|
198
198
|
"format",
|
|
@@ -204,26 +204,26 @@ function parseWrenchMessagingContextBindingV1(value) {
|
|
|
204
204
|
"latestMessageRevision",
|
|
205
205
|
"validatedAt",
|
|
206
206
|
"expiresAt"
|
|
207
|
-
], "
|
|
208
|
-
if (record.schemaVersion !== AGENTIC_MESSAGING_V1_SCHEMA_VERSION || record.format !==
|
|
209
|
-
return fail("
|
|
210
|
-
if (record.contractId !==
|
|
211
|
-
return fail("
|
|
212
|
-
const validatedAt = timestamp(record.validatedAt, "
|
|
213
|
-
const expiresAt = timestamp(record.expiresAt, "
|
|
207
|
+
], "Ghostget messaging context binding");
|
|
208
|
+
if (record.schemaVersion !== AGENTIC_MESSAGING_V1_SCHEMA_VERSION || record.format !== GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT)
|
|
209
|
+
return fail("Ghostget messaging context binding has the wrong schemaVersion or format");
|
|
210
|
+
if (record.contractId !== GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID || record.contractHash !== GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH)
|
|
211
|
+
return fail("Ghostget messaging context binding has an unsupported contract identity");
|
|
212
|
+
const validatedAt = timestamp(record.validatedAt, "Ghostget messaging context binding.validatedAt");
|
|
213
|
+
const expiresAt = timestamp(record.expiresAt, "Ghostget messaging context binding.expiresAt");
|
|
214
214
|
const lifetime = Date.parse(expiresAt) - Date.parse(validatedAt);
|
|
215
215
|
if (lifetime <= 0 || lifetime > AGENTIC_MESSAGING_V1_LIMITS.maximumContextLifetimeMilliseconds) {
|
|
216
|
-
return fail("
|
|
216
|
+
return fail("Ghostget messaging context binding has an invalid lifetime");
|
|
217
217
|
}
|
|
218
218
|
return Object.freeze({
|
|
219
219
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
220
|
-
format:
|
|
221
|
-
contractId:
|
|
222
|
-
contractHash:
|
|
223
|
-
routeRef: identifier(record.routeRef, "
|
|
224
|
-
contextRef: identifier(record.contextRef, "
|
|
225
|
-
exactDataRevision: digest(record.exactDataRevision, "
|
|
226
|
-
latestMessageRevision: digest(record.latestMessageRevision, "
|
|
220
|
+
format: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT,
|
|
221
|
+
contractId: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID,
|
|
222
|
+
contractHash: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH,
|
|
223
|
+
routeRef: identifier(record.routeRef, "Ghostget messaging context binding.routeRef"),
|
|
224
|
+
contextRef: identifier(record.contextRef, "Ghostget messaging context binding.contextRef"),
|
|
225
|
+
exactDataRevision: digest(record.exactDataRevision, "Ghostget messaging context binding.exactDataRevision"),
|
|
226
|
+
latestMessageRevision: digest(record.latestMessageRevision, "Ghostget messaging context binding.latestMessageRevision"),
|
|
227
227
|
validatedAt,
|
|
228
228
|
expiresAt
|
|
229
229
|
});
|
|
@@ -251,7 +251,10 @@ function parseAgentMessageHandoffRequestV1(value) {
|
|
|
251
251
|
});
|
|
252
252
|
}
|
|
253
253
|
function createAgentMessageHandoffV1(input) {
|
|
254
|
-
|
|
254
|
+
if (input.ghostgetContext !== undefined && input.wrenchContext !== undefined) {
|
|
255
|
+
return fail("Choose ghostgetContext or its legacy wrenchContext alias, not both");
|
|
256
|
+
}
|
|
257
|
+
const context = parseGhostgetMessagingContextBindingV1(input.ghostgetContext ?? input.wrenchContext);
|
|
255
258
|
const draft = parseAgentMessageDraftV1(input.draft);
|
|
256
259
|
const core = Object.freeze({
|
|
257
260
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
@@ -298,7 +301,7 @@ function createAgentMessageHandoffV1(input) {
|
|
|
298
301
|
return fail("Agent message handoff timestamps are inconsistent");
|
|
299
302
|
}
|
|
300
303
|
if (core.expiresAt > core.wrench.contextExpiresAt) {
|
|
301
|
-
return fail("Agent message handoff outlives its
|
|
304
|
+
return fail("Agent message handoff outlives its Ghostget context binding");
|
|
302
305
|
}
|
|
303
306
|
const canonicalSha256 = handoffDigest(core);
|
|
304
307
|
return Object.freeze({
|
|
@@ -362,9 +365,9 @@ function parseAgentMessageHandoffV1(value) {
|
|
|
362
365
|
exactKeys(integrityRecord, ["algorithm", "canonicalSha256"], "Agent message handoff.integrity");
|
|
363
366
|
if (integrityRecord.algorithm !== "sha256")
|
|
364
367
|
return fail("Agent message handoff integrity algorithm must be sha256");
|
|
365
|
-
const context =
|
|
368
|
+
const context = parseGhostgetMessagingContextBindingV1({
|
|
366
369
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
367
|
-
format:
|
|
370
|
+
format: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT,
|
|
368
371
|
contractId: wrenchRecord.contractId,
|
|
369
372
|
contractHash: wrenchRecord.contractHash,
|
|
370
373
|
routeRef: wrenchRecord.routeRef,
|
|
@@ -389,7 +392,7 @@ function parseAgentMessageHandoffV1(value) {
|
|
|
389
392
|
profileState: profileState(evidenceRecord.profileState, "Agent message handoff.evidence.profileState"),
|
|
390
393
|
profileEvidenceRevision: evidenceRecord.profileEvidenceRevision === null ? null : digest(evidenceRecord.profileEvidenceRevision, "Agent message handoff.evidence.profileEvidenceRevision")
|
|
391
394
|
},
|
|
392
|
-
|
|
395
|
+
ghostgetContext: context,
|
|
393
396
|
draft: {
|
|
394
397
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
395
398
|
format: AGENT_MESSAGE_DRAFT_V1_FORMAT,
|
|
@@ -403,7 +406,7 @@ function parseAgentMessageHandoffV1(value) {
|
|
|
403
406
|
return fail("Agent message handoff integrity does not match its canonical content");
|
|
404
407
|
return handoff;
|
|
405
408
|
}
|
|
406
|
-
function
|
|
409
|
+
function ghostgetMessagingTurnDigestV1(value) {
|
|
407
410
|
const handoff = parseAgentMessageHandoffV1(value);
|
|
408
411
|
return sha256(canonicalJson({
|
|
409
412
|
schemaVersion: 1,
|
|
@@ -418,8 +421,8 @@ function wrenchMessagingTurnDigestV1(value) {
|
|
|
418
421
|
}))
|
|
419
422
|
}));
|
|
420
423
|
}
|
|
421
|
-
function
|
|
422
|
-
const record = object(value, "
|
|
424
|
+
function parseGhostgetMessagingReceiptBindingV1(value) {
|
|
425
|
+
const record = object(value, "Ghostget messaging receipt binding");
|
|
423
426
|
exactKeys(record, [
|
|
424
427
|
"schemaVersion",
|
|
425
428
|
"format",
|
|
@@ -436,42 +439,42 @@ function parseWrenchMessagingReceiptBindingV1(value) {
|
|
|
436
439
|
"provenPartCount",
|
|
437
440
|
"receiptSha256",
|
|
438
441
|
"recordedAt"
|
|
439
|
-
], "
|
|
440
|
-
if (record.schemaVersion !== AGENTIC_MESSAGING_V1_SCHEMA_VERSION || record.format !==
|
|
441
|
-
return fail("
|
|
442
|
-
if (record.contractId !==
|
|
443
|
-
return fail("
|
|
442
|
+
], "Ghostget messaging receipt binding");
|
|
443
|
+
if (record.schemaVersion !== AGENTIC_MESSAGING_V1_SCHEMA_VERSION || record.format !== GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT)
|
|
444
|
+
return fail("Ghostget messaging receipt binding has the wrong schemaVersion or format");
|
|
445
|
+
if (record.contractId !== GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID || record.contractHash !== GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH)
|
|
446
|
+
return fail("Ghostget messaging receipt binding has an unsupported contract identity");
|
|
444
447
|
if (record.state !== "submitted" && record.state !== "failed" && record.state !== "partial" && record.state !== "indeterminate")
|
|
445
|
-
return fail("
|
|
448
|
+
return fail("Ghostget messaging receipt binding has an invalid state");
|
|
446
449
|
if (!Number.isSafeInteger(record.partCount) || record.partCount < 1 || record.partCount > 8) {
|
|
447
|
-
return fail("
|
|
450
|
+
return fail("Ghostget messaging receipt binding.partCount must be from 1 through 8");
|
|
448
451
|
}
|
|
449
452
|
if (!Number.isSafeInteger(record.provenPartCount) || record.provenPartCount < 0 || record.provenPartCount > record.partCount)
|
|
450
|
-
return fail("
|
|
453
|
+
return fail("Ghostget messaging receipt binding.provenPartCount is out of range");
|
|
451
454
|
const partCount = record.partCount;
|
|
452
455
|
const provenPartCount = record.provenPartCount;
|
|
453
456
|
if (record.state === "submitted" && provenPartCount !== partCount || record.state === "failed" && provenPartCount !== 0 || record.state === "partial" && (provenPartCount < 1 || provenPartCount >= partCount) || record.state === "indeterminate" && provenPartCount >= partCount)
|
|
454
|
-
return fail("
|
|
457
|
+
return fail("Ghostget messaging receipt binding state does not match its proven prefix");
|
|
455
458
|
const parsed = Object.freeze({
|
|
456
459
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
457
|
-
format:
|
|
458
|
-
contractId:
|
|
459
|
-
contractHash:
|
|
460
|
-
clientIntentSha256: digest(record.clientIntentSha256, "
|
|
461
|
-
routeRefSha256: digest(record.routeRefSha256, "
|
|
462
|
-
contextRefSha256: digest(record.contextRefSha256, "
|
|
463
|
-
turnDigest: digest(record.turnDigest, "
|
|
464
|
-
previewDigest: digest(record.previewDigest, "
|
|
465
|
-
runId: identifier(record.runId, "
|
|
460
|
+
format: GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT,
|
|
461
|
+
contractId: GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID,
|
|
462
|
+
contractHash: GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH,
|
|
463
|
+
clientIntentSha256: digest(record.clientIntentSha256, "Ghostget messaging receipt binding.clientIntentSha256"),
|
|
464
|
+
routeRefSha256: digest(record.routeRefSha256, "Ghostget messaging receipt binding.routeRefSha256"),
|
|
465
|
+
contextRefSha256: digest(record.contextRefSha256, "Ghostget messaging receipt binding.contextRefSha256"),
|
|
466
|
+
turnDigest: digest(record.turnDigest, "Ghostget messaging receipt binding.turnDigest"),
|
|
467
|
+
previewDigest: digest(record.previewDigest, "Ghostget messaging receipt binding.previewDigest"),
|
|
468
|
+
runId: identifier(record.runId, "Ghostget messaging receipt binding.runId", 256),
|
|
466
469
|
state: record.state,
|
|
467
470
|
partCount,
|
|
468
471
|
provenPartCount,
|
|
469
|
-
receiptSha256: digest(record.receiptSha256, "
|
|
470
|
-
recordedAt: timestamp(record.recordedAt, "
|
|
472
|
+
receiptSha256: digest(record.receiptSha256, "Ghostget messaging receipt binding.receiptSha256"),
|
|
473
|
+
recordedAt: timestamp(record.recordedAt, "Ghostget messaging receipt binding.recordedAt")
|
|
471
474
|
});
|
|
472
475
|
const { receiptSha256, ...receiptCore } = parsed;
|
|
473
476
|
if (sha256(canonicalJson(receiptCore)) !== receiptSha256) {
|
|
474
|
-
return fail("
|
|
477
|
+
return fail("Ghostget messaging receipt binding receiptSha256 does not match its canonical content");
|
|
475
478
|
}
|
|
476
479
|
return parsed;
|
|
477
480
|
}
|
|
@@ -482,22 +485,33 @@ function agentMessageRouteCandidateId(sourceId, conversationId) {
|
|
|
482
485
|
}))}`;
|
|
483
486
|
}
|
|
484
487
|
export {
|
|
485
|
-
wrenchMessagingTurnDigestV1,
|
|
486
|
-
parseWrenchMessagingReceiptBindingV1,
|
|
487
|
-
parseWrenchMessagingContextBindingV1,
|
|
488
|
+
ghostgetMessagingTurnDigestV1 as wrenchMessagingTurnDigestV1,
|
|
489
|
+
parseGhostgetMessagingReceiptBindingV1 as parseWrenchMessagingReceiptBindingV1,
|
|
490
|
+
parseGhostgetMessagingContextBindingV1 as parseWrenchMessagingContextBindingV1,
|
|
491
|
+
parseGhostgetMessagingReceiptBindingV1,
|
|
492
|
+
parseGhostgetMessagingContextBindingV1,
|
|
488
493
|
parseAgentMessageHandoffV1,
|
|
489
494
|
parseAgentMessageHandoffRequestV1,
|
|
490
495
|
parseAgentMessageDraftV1,
|
|
496
|
+
ghostgetMessagingTurnDigestV1,
|
|
491
497
|
createAgentMessageHandoffV1,
|
|
492
498
|
agentMessageRouteCandidateId,
|
|
493
|
-
WRENCH_MESSAGING_RECEIPT_BINDING_V1_FORMAT,
|
|
494
|
-
WRENCH_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID,
|
|
495
|
-
WRENCH_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH,
|
|
496
|
-
WRENCH_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_DESCRIPTOR,
|
|
497
|
-
WRENCH_MESSAGING_CONTEXT_BINDING_V1_FORMAT,
|
|
498
|
-
WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID,
|
|
499
|
-
WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH,
|
|
500
|
-
WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR,
|
|
499
|
+
GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT as WRENCH_MESSAGING_RECEIPT_BINDING_V1_FORMAT,
|
|
500
|
+
GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID as WRENCH_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID,
|
|
501
|
+
GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH as WRENCH_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH,
|
|
502
|
+
GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_DESCRIPTOR as WRENCH_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_DESCRIPTOR,
|
|
503
|
+
GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT as WRENCH_MESSAGING_CONTEXT_BINDING_V1_FORMAT,
|
|
504
|
+
GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID as WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID,
|
|
505
|
+
GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH as WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH,
|
|
506
|
+
GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR as WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR,
|
|
507
|
+
GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT,
|
|
508
|
+
GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID,
|
|
509
|
+
GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH,
|
|
510
|
+
GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_DESCRIPTOR,
|
|
511
|
+
GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT,
|
|
512
|
+
GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID,
|
|
513
|
+
GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH,
|
|
514
|
+
GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR,
|
|
501
515
|
AgenticMessagingV1ContractError,
|
|
502
516
|
AGENT_MESSAGE_HANDOFF_V1_FORMAT,
|
|
503
517
|
AGENT_MESSAGE_HANDOFF_REQUEST_V1_FORMAT,
|
package/dist/cli.js
CHANGED
|
@@ -14816,12 +14816,12 @@ var AGENTIC_MESSAGING_V1_SCHEMA_VERSION = 1;
|
|
|
14816
14816
|
var AGENT_MESSAGE_DRAFT_V1_FORMAT = "message-like-me.agent-message-draft";
|
|
14817
14817
|
var AGENT_MESSAGE_HANDOFF_REQUEST_V1_FORMAT = "message-like-me.agent-message-handoff-request";
|
|
14818
14818
|
var AGENT_MESSAGE_HANDOFF_V1_FORMAT = "message-like-me.agent-message-handoff";
|
|
14819
|
-
var
|
|
14820
|
-
var
|
|
14821
|
-
var
|
|
14822
|
-
var
|
|
14823
|
-
var
|
|
14824
|
-
contractId:
|
|
14819
|
+
var GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT = "wrench.messaging-context-binding";
|
|
14820
|
+
var GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT = "wrench.messaging-receipt-binding";
|
|
14821
|
+
var GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID = "wrench.messaging-context-binding.v1";
|
|
14822
|
+
var GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH = "5e64da6a3d826e7f6fa3db7dca0a4ba92c10cfb784981e71a25aed9513a5c687";
|
|
14823
|
+
var GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR = Object.freeze({
|
|
14824
|
+
contractId: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID,
|
|
14825
14825
|
fields: Object.freeze([
|
|
14826
14826
|
"schemaVersion:1",
|
|
14827
14827
|
"format:wrench.messaging-context-binding",
|
|
@@ -14837,10 +14837,10 @@ var WRENCH_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_DESCRIPTOR = Object.freeze({
|
|
|
14837
14837
|
format: "wrench.messaging-contract-descriptor",
|
|
14838
14838
|
schemaVersion: 1
|
|
14839
14839
|
});
|
|
14840
|
-
var
|
|
14841
|
-
var
|
|
14842
|
-
var
|
|
14843
|
-
contractId:
|
|
14840
|
+
var GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID = "wrench.messaging-receipt-binding.v1";
|
|
14841
|
+
var GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH = "7f6cf724f0200b2399e4f4641c637b20b48914fc5c9b13755127a8ec69fe66f4";
|
|
14842
|
+
var GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_DESCRIPTOR = Object.freeze({
|
|
14843
|
+
contractId: GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID,
|
|
14844
14844
|
fields: Object.freeze([
|
|
14845
14845
|
"schemaVersion:1",
|
|
14846
14846
|
"format:wrench.messaging-receipt-binding",
|
|
@@ -14996,8 +14996,8 @@ function handoffCore(value) {
|
|
|
14996
14996
|
function handoffDigest(value) {
|
|
14997
14997
|
return sha256(canonicalJson(handoffCore(value)));
|
|
14998
14998
|
}
|
|
14999
|
-
function
|
|
15000
|
-
const record = object(value, "
|
|
14999
|
+
function parseGhostgetMessagingContextBindingV1(value) {
|
|
15000
|
+
const record = object(value, "Ghostget messaging context binding");
|
|
15001
15001
|
exactKeys(record, [
|
|
15002
15002
|
"schemaVersion",
|
|
15003
15003
|
"format",
|
|
@@ -15009,26 +15009,26 @@ function parseWrenchMessagingContextBindingV1(value) {
|
|
|
15009
15009
|
"latestMessageRevision",
|
|
15010
15010
|
"validatedAt",
|
|
15011
15011
|
"expiresAt"
|
|
15012
|
-
], "
|
|
15013
|
-
if (record.schemaVersion !== AGENTIC_MESSAGING_V1_SCHEMA_VERSION || record.format !==
|
|
15014
|
-
return fail9("
|
|
15015
|
-
if (record.contractId !==
|
|
15016
|
-
return fail9("
|
|
15017
|
-
const validatedAt = timestamp(record.validatedAt, "
|
|
15018
|
-
const expiresAt = timestamp(record.expiresAt, "
|
|
15012
|
+
], "Ghostget messaging context binding");
|
|
15013
|
+
if (record.schemaVersion !== AGENTIC_MESSAGING_V1_SCHEMA_VERSION || record.format !== GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT)
|
|
15014
|
+
return fail9("Ghostget messaging context binding has the wrong schemaVersion or format");
|
|
15015
|
+
if (record.contractId !== GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID || record.contractHash !== GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH)
|
|
15016
|
+
return fail9("Ghostget messaging context binding has an unsupported contract identity");
|
|
15017
|
+
const validatedAt = timestamp(record.validatedAt, "Ghostget messaging context binding.validatedAt");
|
|
15018
|
+
const expiresAt = timestamp(record.expiresAt, "Ghostget messaging context binding.expiresAt");
|
|
15019
15019
|
const lifetime = Date.parse(expiresAt) - Date.parse(validatedAt);
|
|
15020
15020
|
if (lifetime <= 0 || lifetime > AGENTIC_MESSAGING_V1_LIMITS.maximumContextLifetimeMilliseconds) {
|
|
15021
|
-
return fail9("
|
|
15021
|
+
return fail9("Ghostget messaging context binding has an invalid lifetime");
|
|
15022
15022
|
}
|
|
15023
15023
|
return Object.freeze({
|
|
15024
15024
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
15025
|
-
format:
|
|
15026
|
-
contractId:
|
|
15027
|
-
contractHash:
|
|
15028
|
-
routeRef: identifier2(record.routeRef, "
|
|
15029
|
-
contextRef: identifier2(record.contextRef, "
|
|
15030
|
-
exactDataRevision: digest(record.exactDataRevision, "
|
|
15031
|
-
latestMessageRevision: digest(record.latestMessageRevision, "
|
|
15025
|
+
format: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT,
|
|
15026
|
+
contractId: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_ID,
|
|
15027
|
+
contractHash: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_CONTRACT_HASH,
|
|
15028
|
+
routeRef: identifier2(record.routeRef, "Ghostget messaging context binding.routeRef"),
|
|
15029
|
+
contextRef: identifier2(record.contextRef, "Ghostget messaging context binding.contextRef"),
|
|
15030
|
+
exactDataRevision: digest(record.exactDataRevision, "Ghostget messaging context binding.exactDataRevision"),
|
|
15031
|
+
latestMessageRevision: digest(record.latestMessageRevision, "Ghostget messaging context binding.latestMessageRevision"),
|
|
15032
15032
|
validatedAt,
|
|
15033
15033
|
expiresAt
|
|
15034
15034
|
});
|
|
@@ -15056,7 +15056,10 @@ function parseAgentMessageHandoffRequestV1(value) {
|
|
|
15056
15056
|
});
|
|
15057
15057
|
}
|
|
15058
15058
|
function createAgentMessageHandoffV1(input) {
|
|
15059
|
-
|
|
15059
|
+
if (input.ghostgetContext !== undefined && input.wrenchContext !== undefined) {
|
|
15060
|
+
return fail9("Choose ghostgetContext or its legacy wrenchContext alias, not both");
|
|
15061
|
+
}
|
|
15062
|
+
const context5 = parseGhostgetMessagingContextBindingV1(input.ghostgetContext ?? input.wrenchContext);
|
|
15060
15063
|
const draft = parseAgentMessageDraftV1(input.draft);
|
|
15061
15064
|
const core = Object.freeze({
|
|
15062
15065
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
@@ -15103,7 +15106,7 @@ function createAgentMessageHandoffV1(input) {
|
|
|
15103
15106
|
return fail9("Agent message handoff timestamps are inconsistent");
|
|
15104
15107
|
}
|
|
15105
15108
|
if (core.expiresAt > core.wrench.contextExpiresAt) {
|
|
15106
|
-
return fail9("Agent message handoff outlives its
|
|
15109
|
+
return fail9("Agent message handoff outlives its Ghostget context binding");
|
|
15107
15110
|
}
|
|
15108
15111
|
const canonicalSha256 = handoffDigest(core);
|
|
15109
15112
|
return Object.freeze({
|
|
@@ -15167,9 +15170,9 @@ function parseAgentMessageHandoffV1(value) {
|
|
|
15167
15170
|
exactKeys(integrityRecord, ["algorithm", "canonicalSha256"], "Agent message handoff.integrity");
|
|
15168
15171
|
if (integrityRecord.algorithm !== "sha256")
|
|
15169
15172
|
return fail9("Agent message handoff integrity algorithm must be sha256");
|
|
15170
|
-
const context5 =
|
|
15173
|
+
const context5 = parseGhostgetMessagingContextBindingV1({
|
|
15171
15174
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
15172
|
-
format:
|
|
15175
|
+
format: GHOSTGET_MESSAGING_CONTEXT_BINDING_V1_FORMAT,
|
|
15173
15176
|
contractId: wrenchRecord.contractId,
|
|
15174
15177
|
contractHash: wrenchRecord.contractHash,
|
|
15175
15178
|
routeRef: wrenchRecord.routeRef,
|
|
@@ -15194,7 +15197,7 @@ function parseAgentMessageHandoffV1(value) {
|
|
|
15194
15197
|
profileState: profileState(evidenceRecord.profileState, "Agent message handoff.evidence.profileState"),
|
|
15195
15198
|
profileEvidenceRevision: evidenceRecord.profileEvidenceRevision === null ? null : digest(evidenceRecord.profileEvidenceRevision, "Agent message handoff.evidence.profileEvidenceRevision")
|
|
15196
15199
|
},
|
|
15197
|
-
|
|
15200
|
+
ghostgetContext: context5,
|
|
15198
15201
|
draft: {
|
|
15199
15202
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
15200
15203
|
format: AGENT_MESSAGE_DRAFT_V1_FORMAT,
|
|
@@ -15208,7 +15211,7 @@ function parseAgentMessageHandoffV1(value) {
|
|
|
15208
15211
|
return fail9("Agent message handoff integrity does not match its canonical content");
|
|
15209
15212
|
return handoff;
|
|
15210
15213
|
}
|
|
15211
|
-
function
|
|
15214
|
+
function ghostgetMessagingTurnDigestV1(value) {
|
|
15212
15215
|
const handoff = parseAgentMessageHandoffV1(value);
|
|
15213
15216
|
return sha256(canonicalJson({
|
|
15214
15217
|
schemaVersion: 1,
|
|
@@ -15223,8 +15226,8 @@ function wrenchMessagingTurnDigestV1(value) {
|
|
|
15223
15226
|
}))
|
|
15224
15227
|
}));
|
|
15225
15228
|
}
|
|
15226
|
-
function
|
|
15227
|
-
const record = object(value, "
|
|
15229
|
+
function parseGhostgetMessagingReceiptBindingV1(value) {
|
|
15230
|
+
const record = object(value, "Ghostget messaging receipt binding");
|
|
15228
15231
|
exactKeys(record, [
|
|
15229
15232
|
"schemaVersion",
|
|
15230
15233
|
"format",
|
|
@@ -15241,42 +15244,42 @@ function parseWrenchMessagingReceiptBindingV1(value) {
|
|
|
15241
15244
|
"provenPartCount",
|
|
15242
15245
|
"receiptSha256",
|
|
15243
15246
|
"recordedAt"
|
|
15244
|
-
], "
|
|
15245
|
-
if (record.schemaVersion !== AGENTIC_MESSAGING_V1_SCHEMA_VERSION || record.format !==
|
|
15246
|
-
return fail9("
|
|
15247
|
-
if (record.contractId !==
|
|
15248
|
-
return fail9("
|
|
15247
|
+
], "Ghostget messaging receipt binding");
|
|
15248
|
+
if (record.schemaVersion !== AGENTIC_MESSAGING_V1_SCHEMA_VERSION || record.format !== GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT)
|
|
15249
|
+
return fail9("Ghostget messaging receipt binding has the wrong schemaVersion or format");
|
|
15250
|
+
if (record.contractId !== GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID || record.contractHash !== GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH)
|
|
15251
|
+
return fail9("Ghostget messaging receipt binding has an unsupported contract identity");
|
|
15249
15252
|
if (record.state !== "submitted" && record.state !== "failed" && record.state !== "partial" && record.state !== "indeterminate")
|
|
15250
|
-
return fail9("
|
|
15253
|
+
return fail9("Ghostget messaging receipt binding has an invalid state");
|
|
15251
15254
|
if (!Number.isSafeInteger(record.partCount) || record.partCount < 1 || record.partCount > 8) {
|
|
15252
|
-
return fail9("
|
|
15255
|
+
return fail9("Ghostget messaging receipt binding.partCount must be from 1 through 8");
|
|
15253
15256
|
}
|
|
15254
15257
|
if (!Number.isSafeInteger(record.provenPartCount) || record.provenPartCount < 0 || record.provenPartCount > record.partCount)
|
|
15255
|
-
return fail9("
|
|
15258
|
+
return fail9("Ghostget messaging receipt binding.provenPartCount is out of range");
|
|
15256
15259
|
const partCount = record.partCount;
|
|
15257
15260
|
const provenPartCount = record.provenPartCount;
|
|
15258
15261
|
if (record.state === "submitted" && provenPartCount !== partCount || record.state === "failed" && provenPartCount !== 0 || record.state === "partial" && (provenPartCount < 1 || provenPartCount >= partCount) || record.state === "indeterminate" && provenPartCount >= partCount)
|
|
15259
|
-
return fail9("
|
|
15262
|
+
return fail9("Ghostget messaging receipt binding state does not match its proven prefix");
|
|
15260
15263
|
const parsed = Object.freeze({
|
|
15261
15264
|
schemaVersion: AGENTIC_MESSAGING_V1_SCHEMA_VERSION,
|
|
15262
|
-
format:
|
|
15263
|
-
contractId:
|
|
15264
|
-
contractHash:
|
|
15265
|
-
clientIntentSha256: digest(record.clientIntentSha256, "
|
|
15266
|
-
routeRefSha256: digest(record.routeRefSha256, "
|
|
15267
|
-
contextRefSha256: digest(record.contextRefSha256, "
|
|
15268
|
-
turnDigest: digest(record.turnDigest, "
|
|
15269
|
-
previewDigest: digest(record.previewDigest, "
|
|
15270
|
-
runId: identifier2(record.runId, "
|
|
15265
|
+
format: GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_FORMAT,
|
|
15266
|
+
contractId: GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_ID,
|
|
15267
|
+
contractHash: GHOSTGET_MESSAGING_RECEIPT_BINDING_V1_CONTRACT_HASH,
|
|
15268
|
+
clientIntentSha256: digest(record.clientIntentSha256, "Ghostget messaging receipt binding.clientIntentSha256"),
|
|
15269
|
+
routeRefSha256: digest(record.routeRefSha256, "Ghostget messaging receipt binding.routeRefSha256"),
|
|
15270
|
+
contextRefSha256: digest(record.contextRefSha256, "Ghostget messaging receipt binding.contextRefSha256"),
|
|
15271
|
+
turnDigest: digest(record.turnDigest, "Ghostget messaging receipt binding.turnDigest"),
|
|
15272
|
+
previewDigest: digest(record.previewDigest, "Ghostget messaging receipt binding.previewDigest"),
|
|
15273
|
+
runId: identifier2(record.runId, "Ghostget messaging receipt binding.runId", 256),
|
|
15271
15274
|
state: record.state,
|
|
15272
15275
|
partCount,
|
|
15273
15276
|
provenPartCount,
|
|
15274
|
-
receiptSha256: digest(record.receiptSha256, "
|
|
15275
|
-
recordedAt: timestamp(record.recordedAt, "
|
|
15277
|
+
receiptSha256: digest(record.receiptSha256, "Ghostget messaging receipt binding.receiptSha256"),
|
|
15278
|
+
recordedAt: timestamp(record.recordedAt, "Ghostget messaging receipt binding.recordedAt")
|
|
15276
15279
|
});
|
|
15277
15280
|
const { receiptSha256, ...receiptCore } = parsed;
|
|
15278
15281
|
if (sha256(canonicalJson(receiptCore)) !== receiptSha256) {
|
|
15279
|
-
return fail9("
|
|
15282
|
+
return fail9("Ghostget messaging receipt binding receiptSha256 does not match its canonical content");
|
|
15280
15283
|
}
|
|
15281
15284
|
return parsed;
|
|
15282
15285
|
}
|
|
@@ -22948,7 +22951,7 @@ class LocalStore {
|
|
|
22948
22951
|
turn_digest_sha256,part_count,created_at,expires_at,state
|
|
22949
22952
|
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, 'prepared')
|
|
22950
22953
|
ON CONFLICT(handoff_id) DO NOTHING
|
|
22951
|
-
`).run(handoff.handoffId, handoff.integrity.canonicalSha256, sha256(handoff.contact.contactId), sha256(handoff.contact.routeCandidateId), sha256(handoff.contact.sourceId), sha256(handoff.contact.conversationId), handoff.evidence.corpusRevision, handoff.evidence.sourceRevision, handoff.evidence.profileState, handoff.evidence.profileEvidenceRevision, handoff.wrench.contractHash, handoff.wrench.routeRefSha256, handoff.wrench.contextRefSha256, handoff.wrench.exactDataRevision, handoff.wrench.latestMessageRevision,
|
|
22954
|
+
`).run(handoff.handoffId, handoff.integrity.canonicalSha256, sha256(handoff.contact.contactId), sha256(handoff.contact.routeCandidateId), sha256(handoff.contact.sourceId), sha256(handoff.contact.conversationId), handoff.evidence.corpusRevision, handoff.evidence.sourceRevision, handoff.evidence.profileState, handoff.evidence.profileEvidenceRevision, handoff.wrench.contractHash, handoff.wrench.routeRefSha256, handoff.wrench.contextRefSha256, handoff.wrench.exactDataRevision, handoff.wrench.latestMessageRevision, ghostgetMessagingTurnDigestV1(handoff), handoff.turn.bubbles.length, handoff.createdAt, handoff.expiresAt);
|
|
22952
22955
|
const stored = get13(this.#database, `
|
|
22953
22956
|
SELECT handoff_sha256 FROM agent_message_handoffs WHERE handoff_id=?
|
|
22954
22957
|
`, handoff.handoffId);
|
|
@@ -22962,7 +22965,7 @@ class LocalStore {
|
|
|
22962
22965
|
if (!/^handoff_[a-f0-9]{64}$/u.test(handoffId)) {
|
|
22963
22966
|
throw new CliError("usage", "Invalid handoff ID");
|
|
22964
22967
|
}
|
|
22965
|
-
const receipt =
|
|
22968
|
+
const receipt = parseGhostgetMessagingReceiptBindingV1(value);
|
|
22966
22969
|
transaction(this.#database, () => {
|
|
22967
22970
|
const stored = get13(this.#database, `
|
|
22968
22971
|
SELECT handoff_sha256,route_ref_sha256,context_ref_sha256,turn_digest_sha256,
|
|
@@ -22972,11 +22975,11 @@ class LocalStore {
|
|
|
22972
22975
|
if (stored === null)
|
|
22973
22976
|
throw new CliError("not-found", `Unknown handoff ${handoffId}`);
|
|
22974
22977
|
if (receipt.clientIntentSha256 !== stored.handoff_sha256 || receipt.routeRefSha256 !== stored.route_ref_sha256 || receipt.contextRefSha256 !== stored.context_ref_sha256 || receipt.turnDigest !== stored.turn_digest_sha256 || receipt.partCount !== stored.part_count || receipt.recordedAt < stored.created_at)
|
|
22975
|
-
throw new CliError("conflict", "
|
|
22978
|
+
throw new CliError("conflict", "Ghostget receipt does not bind the recorded handoff");
|
|
22976
22979
|
if (stored.state === "recorded") {
|
|
22977
22980
|
if (stored.receipt_sha256 === receipt.receiptSha256)
|
|
22978
22981
|
return;
|
|
22979
|
-
throw new CliError("conflict", "Handoff already has a different
|
|
22982
|
+
throw new CliError("conflict", "Handoff already has a different Ghostget receipt");
|
|
22980
22983
|
}
|
|
22981
22984
|
this.#database.query(`
|
|
22982
22985
|
UPDATE agent_message_handoffs SET
|
|
@@ -23091,7 +23094,7 @@ class LocalStore {
|
|
|
23091
23094
|
if (exists5 === null)
|
|
23092
23095
|
return "absent";
|
|
23093
23096
|
const audit = this.handoffAudit(handoff.handoffId);
|
|
23094
|
-
return audit.handoffSha256 === handoff.integrity.canonicalSha256 && audit.contactIdSha256 === sha256(handoff.contact.contactId) && audit.routeCandidateIdSha256 === sha256(handoff.contact.routeCandidateId) && audit.sourceIdSha256 === sha256(handoff.contact.sourceId) && audit.conversationIdSha256 === sha256(handoff.contact.conversationId) && audit.corpusRevision === handoff.evidence.corpusRevision && audit.sourceRevision === handoff.evidence.sourceRevision && audit.profileState === handoff.evidence.profileState && audit.profileEvidenceRevision === handoff.evidence.profileEvidenceRevision && audit.wrenchContractHash === handoff.wrench.contractHash && audit.routeRefSha256 === sha256(handoff.wrench.routeRef) && audit.contextRefSha256 === sha256(handoff.wrench.contextRef) && audit.exactDataRevisionSha256 === handoff.wrench.exactDataRevision && audit.latestMessageRevisionSha256 === handoff.wrench.latestMessageRevision && audit.turnDigest ===
|
|
23097
|
+
return audit.handoffSha256 === handoff.integrity.canonicalSha256 && audit.contactIdSha256 === sha256(handoff.contact.contactId) && audit.routeCandidateIdSha256 === sha256(handoff.contact.routeCandidateId) && audit.sourceIdSha256 === sha256(handoff.contact.sourceId) && audit.conversationIdSha256 === sha256(handoff.contact.conversationId) && audit.corpusRevision === handoff.evidence.corpusRevision && audit.sourceRevision === handoff.evidence.sourceRevision && audit.profileState === handoff.evidence.profileState && audit.profileEvidenceRevision === handoff.evidence.profileEvidenceRevision && audit.wrenchContractHash === handoff.wrench.contractHash && audit.routeRefSha256 === sha256(handoff.wrench.routeRef) && audit.contextRefSha256 === sha256(handoff.wrench.contextRef) && audit.exactDataRevisionSha256 === handoff.wrench.exactDataRevision && audit.latestMessageRevisionSha256 === handoff.wrench.latestMessageRevision && audit.turnDigest === ghostgetMessagingTurnDigestV1(handoff) && audit.partCount === handoff.turn.bubbles.length && audit.createdAt === handoff.createdAt && audit.expiresAt === handoff.expiresAt ? "committed" : "different";
|
|
23095
23098
|
}
|
|
23096
23099
|
applyProfile(profile, appliedAt) {
|
|
23097
23100
|
const parsedProfile = parseStyleProfile(profile);
|
|
@@ -24590,7 +24593,7 @@ function commandPlatformLive(io, cleanupFailure) {
|
|
|
24590
24593
|
applyProfile: (...args2) => attempt(() => store.applyProfile(...args2)),
|
|
24591
24594
|
handoffPreparation: (...args2) => attempt(() => store.handoffPreparation(...args2)),
|
|
24592
24595
|
recordPreparedHandoff: (...args2) => attempt(() => store.recordPreparedHandoff(...args2)).pipe(exports_Effect.mapError((failure) => failure.cause instanceof AgenticMessagingV1ContractError ? translatedFailure((error) => translateAgenticContractError(error, "Private handoff"), failure.cause) : failure)),
|
|
24593
|
-
recordHandoffReceipt: (...args2) => attempt(() => store.recordHandoffReceipt(...args2)).pipe(exports_Effect.mapError((failure) => failure.cause instanceof AgenticMessagingV1ContractError ? translatedFailure((error) => translateAgenticContractError(error, "Private
|
|
24596
|
+
recordHandoffReceipt: (...args2) => attempt(() => store.recordHandoffReceipt(...args2)).pipe(exports_Effect.mapError((failure) => failure.cause instanceof AgenticMessagingV1ContractError ? translatedFailure((error) => translateAgenticContractError(error, "Private Ghostget receipt file"), failure.cause) : failure)),
|
|
24594
24597
|
studyPacketReceiptStatus: (...args2) => attempt(() => store.studyPacketReceiptStatus(...args2)),
|
|
24595
24598
|
preparedHandoffReceiptStatus: (...args2) => attempt(() => store.preparedHandoffReceiptStatus(...args2)),
|
|
24596
24599
|
handoffAudit: (...args2) => attempt(() => store.handoffAudit(...args2)),
|
|
@@ -24664,10 +24667,14 @@ var VALUE_OPTIONS = new Set([
|
|
|
24664
24667
|
"subject",
|
|
24665
24668
|
"target",
|
|
24666
24669
|
"draft",
|
|
24667
|
-
"
|
|
24668
|
-
"
|
|
24670
|
+
"ghostget-context",
|
|
24671
|
+
"ghostget-receipt"
|
|
24669
24672
|
]);
|
|
24670
24673
|
var FLAG_OPTIONS = new Set(["force", "help", "json", "private", "version"]);
|
|
24674
|
+
var LEGACY_OPTION_ALIASES = new Map([
|
|
24675
|
+
["wrench-context", "ghostget-context"],
|
|
24676
|
+
["wrench-receipt", "ghostget-receipt"]
|
|
24677
|
+
]);
|
|
24671
24678
|
function parseArguments(argv) {
|
|
24672
24679
|
const positionals = [];
|
|
24673
24680
|
const options = new Map;
|
|
@@ -24686,7 +24693,8 @@ function parseArguments(argv) {
|
|
|
24686
24693
|
continue;
|
|
24687
24694
|
}
|
|
24688
24695
|
const separator = argument.indexOf("=");
|
|
24689
|
-
const
|
|
24696
|
+
const suppliedKey = argument.slice(2, separator < 0 ? undefined : separator);
|
|
24697
|
+
const key = LEGACY_OPTION_ALIASES.get(suppliedKey) ?? suppliedKey;
|
|
24690
24698
|
if (key.length === 0)
|
|
24691
24699
|
throw new CliError("usage", "Empty option name");
|
|
24692
24700
|
if (VALUE_OPTIONS.has(key)) {
|
|
@@ -24742,7 +24750,7 @@ function rejectUnused(parsed, allowedOptions, allowedFlags) {
|
|
|
24742
24750
|
import { isAbsolute as isAbsolute6, resolve as resolve8 } from "path";
|
|
24743
24751
|
|
|
24744
24752
|
// src/version.ts
|
|
24745
|
-
var MESSAGE_LIKE_ME_VERSION = "0.8.
|
|
24753
|
+
var MESSAGE_LIKE_ME_VERSION = "0.8.8";
|
|
24746
24754
|
|
|
24747
24755
|
// src/command-input.ts
|
|
24748
24756
|
var HELP = `Message Like Me ${MESSAGE_LIKE_ME_VERSION}
|
|
@@ -24778,9 +24786,9 @@ Usage:
|
|
|
24778
24786
|
messagelikeme [--data-dir PATH] profile export CONTACT_ID --output FILE [--json]
|
|
24779
24787
|
messagelikeme [--data-dir PATH] context CONTACT_ID [--json]
|
|
24780
24788
|
messagelikeme [--data-dir PATH] handoff prepare CONTACT_ID --request FILE
|
|
24781
|
-
--
|
|
24789
|
+
--ghostget-context FILE --draft FILE --output FILE [--json]
|
|
24782
24790
|
messagelikeme [--data-dir PATH] handoff verify FILE [--json]
|
|
24783
|
-
messagelikeme [--data-dir PATH] handoff record HANDOFF_ID --
|
|
24791
|
+
messagelikeme [--data-dir PATH] handoff record HANDOFF_ID --ghostget-receipt FILE [--json]
|
|
24784
24792
|
messagelikeme [--data-dir PATH] handoffs show HANDOFF_ID [--json]
|
|
24785
24793
|
messagelikeme skill path [--json]
|
|
24786
24794
|
messagelikeme skill install [--target codex|claude|agents] [--scope user|project]
|
|
@@ -27309,28 +27317,28 @@ function commandProgram(argv) {
|
|
|
27309
27317
|
rejectUnused(parsed, [
|
|
27310
27318
|
"data-dir",
|
|
27311
27319
|
"request",
|
|
27312
|
-
"
|
|
27320
|
+
"ghostget-context",
|
|
27313
27321
|
"draft",
|
|
27314
27322
|
"output"
|
|
27315
27323
|
], ["json"]);
|
|
27316
27324
|
const requestPath = absolutePrivatePath(parsed.options.get("request"), "--request");
|
|
27317
|
-
const
|
|
27325
|
+
const ghostgetContextPath = absolutePrivatePath(parsed.options.get("ghostget-context"), "--ghostget-context");
|
|
27318
27326
|
const draftPath = absolutePrivatePath(parsed.options.get("draft"), "--draft");
|
|
27319
27327
|
const output = absolutePrivatePath(parsed.options.get("output"), "--output");
|
|
27320
|
-
if (new Set([requestPath,
|
|
27321
|
-
return yield* exports_Effect.fail(commandFailure(new CliError("usage", "Handoff request,
|
|
27328
|
+
if (new Set([requestPath, ghostgetContextPath, draftPath, output]).size !== 4) {
|
|
27329
|
+
return yield* exports_Effect.fail(commandFailure(new CliError("usage", "Handoff request, Ghostget context, draft, and output paths must be different")));
|
|
27322
27330
|
}
|
|
27323
27331
|
const request2 = yield* platform2.readPrivateJson(requestPath, "Private handoff request file", AGENTIC_MESSAGING_V1_LIMITS.privateJsonBytes).pipe(exports_Effect.flatMap((value) => exports_Effect.try({ try: () => parseAgentMessageHandoffRequestV1(value), catch: commandFailure })), exports_Effect.mapError((failure) => agenticContractFailure(failure.cause, "Private handoff input")));
|
|
27324
|
-
const
|
|
27332
|
+
const ghostgetContext = yield* platform2.readPrivateJson(ghostgetContextPath, "Private Ghostget context file", AGENTIC_MESSAGING_V1_LIMITS.privateJsonBytes).pipe(exports_Effect.flatMap((value) => exports_Effect.try({ try: () => parseGhostgetMessagingContextBindingV1(value), catch: commandFailure })), exports_Effect.mapError((failure) => agenticContractFailure(failure.cause, "Private handoff input")));
|
|
27325
27333
|
const draft = yield* platform2.readPrivateJson(draftPath, "Private draft file", AGENTIC_MESSAGING_V1_LIMITS.privateJsonBytes).pipe(exports_Effect.flatMap((value) => exports_Effect.try({ try: () => parseAgentMessageDraftV1(value), catch: commandFailure })), exports_Effect.mapError((failure) => agenticContractFailure(failure.cause, "Private handoff input")));
|
|
27326
27334
|
const createdAt = yield* platform2.now;
|
|
27327
|
-
if (
|
|
27328
|
-
return yield* exports_Effect.fail(commandFailure(new CliError("conflict", "The private
|
|
27335
|
+
if (ghostgetContext.validatedAt > createdAt || ghostgetContext.expiresAt <= createdAt) {
|
|
27336
|
+
return yield* exports_Effect.fail(commandFailure(new CliError("conflict", "The private Ghostget context is not current; collect a fresh exact context")));
|
|
27329
27337
|
}
|
|
27330
27338
|
const context5 = yield* platform2.existingSession(parsed.options.get("data-dir"));
|
|
27331
27339
|
yield* exports_Effect.gen(function* () {
|
|
27332
27340
|
const preparation = yield* context5.store.handoffPreparation(identifier5, request2.routeCandidateId);
|
|
27333
|
-
const expiresAt = handoffExpiry(createdAt,
|
|
27341
|
+
const expiresAt = handoffExpiry(createdAt, ghostgetContext.expiresAt, AGENTIC_MESSAGING_V1_LIMITS.handoffLifetimeMilliseconds);
|
|
27334
27342
|
const handoff = yield* exports_Effect.try({ try: () => createAgentMessageHandoffV1({
|
|
27335
27343
|
createdAt,
|
|
27336
27344
|
expiresAt,
|
|
@@ -27346,7 +27354,7 @@ function commandProgram(argv) {
|
|
|
27346
27354
|
profileState: preparation.profileState,
|
|
27347
27355
|
profileEvidenceRevision: preparation.profileEvidenceRevision
|
|
27348
27356
|
},
|
|
27349
|
-
|
|
27357
|
+
ghostgetContext,
|
|
27350
27358
|
draft
|
|
27351
27359
|
}), catch: commandFailure });
|
|
27352
27360
|
const audit = yield* artifacts.publishWithReceipt(output, prettyJson(handoff), context5.store.recordPreparedHandoff(handoff), context5.store.preparedHandoffReceiptStatus(handoff));
|
|
@@ -27375,7 +27383,7 @@ function commandProgram(argv) {
|
|
|
27375
27383
|
contextRefSha256: handoff.wrench.contextRefSha256,
|
|
27376
27384
|
exactDataRevisionSha256: handoff.wrench.exactDataRevision,
|
|
27377
27385
|
latestMessageRevisionSha256: handoff.wrench.latestMessageRevision,
|
|
27378
|
-
turnDigest:
|
|
27386
|
+
turnDigest: ghostgetMessagingTurnDigestV1(handoff),
|
|
27379
27387
|
partCount: handoff.turn.bubbles.length,
|
|
27380
27388
|
createdAt: handoff.createdAt,
|
|
27381
27389
|
expiresAt: handoff.expiresAt,
|
|
@@ -27385,12 +27393,12 @@ function commandProgram(argv) {
|
|
|
27385
27393
|
return;
|
|
27386
27394
|
}
|
|
27387
27395
|
if (command === "handoff" && subcommand === "record" && identifier5 !== undefined) {
|
|
27388
|
-
rejectUnused(parsed, ["data-dir", "
|
|
27389
|
-
const receiptPath = absolutePrivatePath(parsed.options.get("
|
|
27390
|
-
const receipt = yield* platform2.readPrivateJson(receiptPath, "Private
|
|
27396
|
+
rejectUnused(parsed, ["data-dir", "ghostget-receipt"], ["json"]);
|
|
27397
|
+
const receiptPath = absolutePrivatePath(parsed.options.get("ghostget-receipt"), "--ghostget-receipt");
|
|
27398
|
+
const receipt = yield* platform2.readPrivateJson(receiptPath, "Private Ghostget receipt file", AGENTIC_MESSAGING_V1_LIMITS.privateJsonBytes).pipe(exports_Effect.mapError((failure) => agenticContractFailure(failure.cause, "Private Ghostget receipt file")));
|
|
27391
27399
|
const context5 = yield* platform2.existingSession(parsed.options.get("data-dir"));
|
|
27392
|
-
const audit = yield* context5.store.recordHandoffReceipt(identifier5, receipt).pipe(exports_Effect.mapError((failure) => failure.cause instanceof AgenticMessagingV1ContractError ? agenticContractFailure(failure.cause, "Private
|
|
27393
|
-
yield* platform2.emit(json, audit, `Recorded body-free
|
|
27400
|
+
const audit = yield* context5.store.recordHandoffReceipt(identifier5, receipt).pipe(exports_Effect.mapError((failure) => failure.cause instanceof AgenticMessagingV1ContractError ? agenticContractFailure(failure.cause, "Private Ghostget receipt file") : failure));
|
|
27401
|
+
yield* platform2.emit(json, audit, `Recorded body-free Ghostget audit for ${audit.handoffId}`);
|
|
27394
27402
|
return;
|
|
27395
27403
|
}
|
|
27396
27404
|
if (command === "handoffs" && subcommand === "show" && identifier5 !== undefined) {
|
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Beeper users can bring a bounded provider observation into Message Like Me's
|
|
4
4
|
private local evidence layer without giving Message Like Me a provider
|
|
5
|
-
credential or send access.
|
|
5
|
+
credential or send access. Ghostget writes a finished
|
|
6
6
|
`message-like-me.local-message-bundle`; `messagelikeme ingest bundle` verifies
|
|
7
|
-
and normalizes that directory. The importer never starts or calls
|
|
7
|
+
and normalizes that directory. The importer never starts or calls Ghostget, never
|
|
8
8
|
invokes a Beeper operation, and never sends. Like every Message Like Me ingest
|
|
9
9
|
path, it is read-only with respect to its source.
|
|
10
10
|
|
|
11
11
|
The currently verified producer is the local Beeper export in the
|
|
12
|
-
[`@hraness/
|
|
13
|
-
|
|
12
|
+
[`@hraness/ghostget@0.17.1`](https://github.com/hraness/ghostget/releases/download/v0.17.1/hraness-ghostget-0.17.1.tgz)
|
|
13
|
+
canonical GitHub Release archive:
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
|
-
bun add --global
|
|
17
|
-
|
|
16
|
+
bun add --global https://github.com/hraness/ghostget/releases/download/v0.17.1/hraness-ghostget-0.17.1.tgz
|
|
17
|
+
ghostget adapter sync-bundled --json
|
|
18
|
+
ghostget beeper export-message-like-me \
|
|
18
19
|
--auth <beeper-auth-id> \
|
|
19
20
|
--output <normalized-absolute-new-directory> \
|
|
20
21
|
[--limit-chats <n>] \
|
|
@@ -32,11 +33,11 @@ express.
|
|
|
32
33
|
## Compatibility coordinates
|
|
33
34
|
|
|
34
35
|
Message Like Me accepts schema version `1` with source ID `beeper-local` and
|
|
35
|
-
source-transform version `1.1.0`.
|
|
36
|
+
source-transform version `1.1.0`. Ghostget v0.17.1 emits those coordinates through
|
|
36
37
|
adapter `beeper-local@2.4.0`. That adapter has 32 reviewed Beeper operations:
|
|
37
38
|
26 through one pinned Beeper CLI 0.6.2 executable, including supported actions
|
|
38
39
|
and writes, plus six fixed Desktop loopback reads. The Message Like Me bundle is
|
|
39
|
-
made by
|
|
40
|
+
made by Ghostget's separate internal bounded export, not by a Message Like Me
|
|
40
41
|
provider operation. It fixes the raw export arguments, excludes attachments,
|
|
41
42
|
and preserves incomplete-coverage evidence. It does not claim a complete
|
|
42
43
|
Beeper history.
|
|
@@ -44,7 +45,7 @@ Beeper history.
|
|
|
44
45
|
The pinned Beeper CLI executable reports version `0.6.2`; that executable is
|
|
45
46
|
the runtime authority. At the upstream source tag,
|
|
46
47
|
`packages/cli/package.json` declares `0.6.1`; that source-package value is
|
|
47
|
-
provenance only and never overrides executable runtime identity. A later
|
|
48
|
+
provenance only and never overrides executable runtime identity. A later Ghostget
|
|
48
49
|
package release remains compatible only while its manifest still declares the
|
|
49
50
|
same bundle schema, source ID, and `source.version: "1.1.0"`. Package age,
|
|
50
51
|
adapter version, or a permissive package range never overrides those manifest
|
|
@@ -52,7 +53,7 @@ coordinates. The provider version records the pinned Beeper CLI used for
|
|
|
52
53
|
capture and may change without changing the bundle contract.
|
|
53
54
|
|
|
54
55
|
Message Like Me owns zero Beeper operations, credentials, or live sessions. It
|
|
55
|
-
does not start or call
|
|
56
|
+
does not start or call Ghostget, call the provider, or support sending. Its
|
|
56
57
|
authority begins at strict verification of the already finished private
|
|
57
58
|
directory.
|
|
58
59
|
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
# Local message bundle v2
|
|
2
2
|
|
|
3
3
|
Local message bundle v2 is the native WhatsApp evidence boundary between a
|
|
4
|
-
|
|
4
|
+
Ghostget-owned Wacli adapter and Message Like Me. Ghostget owns Wacli discovery,
|
|
5
5
|
authentication, local synchronization, provider interpretation, and export.
|
|
6
6
|
Message Like Me reads only the finished caller-owned directory. It never starts
|
|
7
|
-
|
|
7
|
+
Ghostget or Wacli, receives a WhatsApp credential or session database, accesses a
|
|
8
8
|
network, or sends a message.
|
|
9
9
|
|
|
10
10
|
The intended producer flow is:
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
|
-
bun add --global
|
|
14
|
-
|
|
13
|
+
bun add --global https://github.com/hraness/ghostget/releases/download/v0.17.1/hraness-ghostget-0.17.1.tgz
|
|
14
|
+
ghostget adapter sync-bundled --json
|
|
15
|
+
ghostget whatsapp export-message-like-me \
|
|
15
16
|
--auth <whatsapp-auth-id> \
|
|
16
17
|
--output /absolute/private/path/whatsapp-bundle
|
|
17
18
|
|
|
@@ -20,8 +21,8 @@ messagelikeme ingest bundle \
|
|
|
20
21
|
--json
|
|
21
22
|
```
|
|
22
23
|
|
|
23
|
-
The checked compatibility coordinates are
|
|
24
|
-
v0.15.0.
|
|
24
|
+
The checked compatibility coordinates are Ghostget v0.17.1 and official Wacli
|
|
25
|
+
v0.15.0. Ghostget owns that executable dependency and its authentication state;
|
|
25
26
|
neither enters Message Like Me.
|
|
26
27
|
|
|
27
28
|
That exact producer excludes every reaction-shaped Wacli row. Wacli v0.15.0
|
|
@@ -89,7 +90,7 @@ byte disagreement, and SHA-256 disagreement. The same public bounds as v1
|
|
|
89
90
|
apply, except v2 admits exactly one account.
|
|
90
91
|
|
|
91
92
|
The v2 wire contract retains the fixed `reactions.ndjson` artifact and strict
|
|
92
|
-
reaction parser for proven records. The checked
|
|
93
|
+
reaction parser for proven records. The checked Ghostget v0.17.1/Wacli v0.15.0
|
|
93
94
|
producer leaves that artifact empty because it cannot prove current reaction
|
|
94
95
|
state.
|
|
95
96
|
|
|
@@ -162,7 +163,7 @@ duplicates cannot prove equivalence.
|
|
|
162
163
|
|
|
163
164
|
Both source provenances and all source-unique history remain stored. Proven
|
|
164
165
|
message duplicates contribute once. A reaction can deduplicate only when a
|
|
165
|
-
conforming producer supplies a proven reaction record;
|
|
166
|
+
conforming producer supplies a proven reaction record; Ghostget v0.17.1 supplies
|
|
166
167
|
none, so this overlap path does not reconcile reaction state. The native Wacli
|
|
167
168
|
conversation is the preferred action route and carries the exact private
|
|
168
169
|
`whatsappJid` coordinate. Its proven Beeper duplicate remains evidence with
|
|
@@ -177,6 +178,6 @@ handles, account coordinates, message bodies, and source metadata stay in the
|
|
|
177
178
|
private store or explicit owner-only artifacts.
|
|
178
179
|
|
|
179
180
|
Message Like Me may write an exact `whatsappJid` route into an explicit
|
|
180
|
-
mode-`0600` route inventory. That coordinate is evidence for a separate
|
|
181
|
+
mode-`0600` route inventory. That coordinate is evidence for a separate Ghostget
|
|
181
182
|
binding and preview. Message Like Me does not authenticate, synchronize,
|
|
182
183
|
preview, submit, or send through WhatsApp.
|
package/docs/methodology.md
CHANGED
|
@@ -17,7 +17,7 @@ A caller-owned local message bundle is a separate versioned source
|
|
|
17
17
|
observation. The CLI verifies its complete fixed inventory and digests before
|
|
18
18
|
ingest, never obtains its provider credential, and does not call its producer.
|
|
19
19
|
Frozen v1 carries bounded Beeper observations. V2 carries one native WhatsApp
|
|
20
|
-
account exported through
|
|
20
|
+
account exported through Ghostget's official Wacli adapter. It requires exact
|
|
21
21
|
WhatsApp JIDs and projects a phone handle only from an E.164-backed user JID.
|
|
22
22
|
|
|
23
23
|
A caller-owned X data archive is another offline source observation. The CLI
|
package/package.json
CHANGED
|
@@ -91,7 +91,7 @@ and message overlap or fail closed. Group DMs remain separate. Keep both
|
|
|
91
91
|
provenances and treat the resulting exact-message dedupe as a source fact, not
|
|
92
92
|
an identity inference.
|
|
93
93
|
|
|
94
|
-
When the user supplies a finished
|
|
94
|
+
When the user supplies a finished Ghostget/Beeper Message Like Me bundle, ingest
|
|
95
95
|
only its normalized absolute directory path:
|
|
96
96
|
|
|
97
97
|
```sh
|
|
@@ -100,13 +100,13 @@ messagelikeme sources list --json
|
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
Do not request or handle the Beeper credential, call Beeper directly, improvise
|
|
103
|
-
a provider parser, or open the bundle's NDJSON files.
|
|
103
|
+
a provider parser, or open the bundle's NDJSON files. Ghostget owns provider
|
|
104
104
|
capture; Message Like Me owns strict verification, normalization, and local
|
|
105
105
|
analysis. Use `sources show <source-id> --json` for redacted completeness and
|
|
106
106
|
health. Add `--private` only when the user's task requires provider account
|
|
107
107
|
metadata.
|
|
108
108
|
|
|
109
|
-
When the user supplies a finished
|
|
109
|
+
When the user supplies a finished Ghostget/Wacli native WhatsApp v2 bundle, use
|
|
110
110
|
the same strict importer:
|
|
111
111
|
|
|
112
112
|
```sh
|
|
@@ -115,8 +115,8 @@ messagelikeme ingest bundle --input <absolute-private-whatsapp-bundle> --json
|
|
|
115
115
|
|
|
116
116
|
Do not request or handle Wacli session state or WhatsApp linked-device
|
|
117
117
|
authentication, call Wacli, inspect its database, synchronize the account, or
|
|
118
|
-
open bundle records in agent context.
|
|
119
|
-
The
|
|
118
|
+
open bundle records in agent context. Ghostget owns those provider operations.
|
|
119
|
+
The Ghostget v0.17.1/Wacli v0.15.0 producer omits every reaction-shaped row and
|
|
120
120
|
reports `reaction-state-unproven` when it encounters one because current active
|
|
121
121
|
or removed state is not durable. Treat that warning, and an empty reaction
|
|
122
122
|
artifact from this producer, as unobservable reaction behavior. Do not infer
|
|
@@ -185,7 +185,7 @@ parameters changes the operational meaning of turns, sessions, and latency.
|
|
|
185
185
|
|
|
186
186
|
Study packets, Ensoul source packets, evaluation packets, and explicit private
|
|
187
187
|
handoffs are the only CLI exports that contain message bodies. A handoff is for
|
|
188
|
-
bounded coordination with
|
|
188
|
+
bounded coordination with Ghostget and is not evidence that anything was sent.
|
|
189
189
|
Retain the study
|
|
190
190
|
command's JSON receipt and copy its `packetSha256`
|
|
191
191
|
into the finished profile; the packet does not contain its own digest. Analyze
|
|
@@ -19,9 +19,9 @@ sensitive local data.
|
|
|
19
19
|
- A native WhatsApp bundle is still only a finished offline input. Do not
|
|
20
20
|
request Wacli session files or WhatsApp authentication, invoke Wacli,
|
|
21
21
|
synchronize a linked device, inspect its database, or expose exact JIDs.
|
|
22
|
-
|
|
22
|
+
Ghostget owns that provider boundary. `--overlap-source` requires explicit
|
|
23
23
|
intent and exact CLI proof; it never authorizes fuzzy account or contact
|
|
24
|
-
matching. The
|
|
24
|
+
matching. The Ghostget v0.17.1 producer omits reaction-shaped Wacli rows with
|
|
25
25
|
`reaction-state-unproven`; never turn that missing evidence into a claim that
|
|
26
26
|
no reactions occurred.
|
|
27
27
|
- Treat a caller-owned X data archive ZIP as private source evidence. Pass only
|