@engramx/client 0.1.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/dist/EngramClient.d.ts +223 -0
  4. package/dist/EngramClient.js +1232 -0
  5. package/dist/EngramClient.js.map +1 -0
  6. package/dist/ProfileManager.d.ts +61 -0
  7. package/dist/ProfileManager.js +116 -0
  8. package/dist/ProfileManager.js.map +1 -0
  9. package/dist/SessionManager.d.ts +46 -0
  10. package/dist/SessionManager.js +114 -0
  11. package/dist/SessionManager.js.map +1 -0
  12. package/dist/agent-skill.d.ts +150 -0
  13. package/dist/agent-skill.js +152 -0
  14. package/dist/agent-skill.js.map +1 -0
  15. package/dist/auth.d.ts +17 -0
  16. package/dist/auth.js +65 -0
  17. package/dist/auth.js.map +1 -0
  18. package/dist/bootstrap.d.ts +21 -0
  19. package/dist/bootstrap.js +71 -0
  20. package/dist/bootstrap.js.map +1 -0
  21. package/dist/cache.d.ts +11 -0
  22. package/dist/cache.js +41 -0
  23. package/dist/cache.js.map +1 -0
  24. package/dist/claude-setup.d.ts +29 -0
  25. package/dist/claude-setup.js +57 -0
  26. package/dist/claude-setup.js.map +1 -0
  27. package/dist/cli.d.ts +2 -0
  28. package/dist/cli.js +1078 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/encryption.d.ts +44 -0
  31. package/dist/encryption.js +108 -0
  32. package/dist/encryption.js.map +1 -0
  33. package/dist/index.d.ts +36 -0
  34. package/dist/index.js +23 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/migrate.d.ts +106 -0
  37. package/dist/migrate.js +882 -0
  38. package/dist/migrate.js.map +1 -0
  39. package/dist/offline.d.ts +21 -0
  40. package/dist/offline.js +90 -0
  41. package/dist/offline.js.map +1 -0
  42. package/dist/openclaw-setup.d.ts +24 -0
  43. package/dist/openclaw-setup.js +249 -0
  44. package/dist/openclaw-setup.js.map +1 -0
  45. package/dist/pair.d.ts +20 -0
  46. package/dist/pair.js +68 -0
  47. package/dist/pair.js.map +1 -0
  48. package/dist/path-utils.d.ts +16 -0
  49. package/dist/path-utils.js +29 -0
  50. package/dist/path-utils.js.map +1 -0
  51. package/dist/schema.d.ts +54 -0
  52. package/dist/schema.js +101 -0
  53. package/dist/schema.js.map +1 -0
  54. package/dist/types.d.ts +452 -0
  55. package/dist/types.js +2 -0
  56. package/dist/types.js.map +1 -0
  57. package/package.json +67 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 EngramX contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # @engramx/client
2
+
3
+ TypeScript SDK for EngramX — persistent, decentralized memory for AI agents on the Internet Computer.
4
+
5
+ ## What is this
6
+
7
+ EngramX (Engram Externalized) stores your AI agent's memory, identity, session history, and wallet in an ICP canister. If the host machine dies, gets hacked, or moves — the agent resumes on a new machine with full state intact.
8
+
9
+ This package is the client SDK that agents use to read and write their engram.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pnpm add @engramx/client
15
+ ```
16
+
17
+ ## Quickstart
18
+
19
+ ```typescript
20
+ import { EngramClient } from '@engramx/client';
21
+
22
+ const engram = new EngramClient({
23
+ canisterId: 'xxxxx-xxxxx-xxxxx-xxxxx-xxx',
24
+ sessionKeyPath: '~/.engramx/session.key',
25
+ });
26
+
27
+ // Read memory
28
+ const file = await engram.readMemory('MEMORY.md');
29
+ console.log(file.content);
30
+
31
+ // Append to memory
32
+ const version = await engram.appendMemory('memory/daily.md', '## Notes\nSomething happened.');
33
+
34
+ // Read several files at once
35
+ const files = await engram.readMemoryBatch(['MEMORY.md', 'memory/daily.md']);
36
+
37
+ // Check balance
38
+ const balance = await engram.walletBalance();
39
+ ```
40
+
41
+ ## Pairing
42
+
43
+ Register your machine as an operator:
44
+
45
+ ```bash
46
+ # Pair this host — register as operator and install the OpenClaw plugin
47
+ pnpm dlx @engramx/client pair <invite-code> --engram <canister-id> --target openclaw
48
+
49
+ # Replacement host — after pairing, restore memory from the engram
50
+ pnpm dlx @engramx/client migrate --engram <canister-id> --recover
51
+ ```
52
+
53
+ `pair` generates `~/.engramx/session.key`, registers the operator, and installs the OpenClaw plugin. `migrate` then moves memory, saving a local checkpoint first — run `npx @engramx/client rollback` to undo. Its default direction pushes local memory files to the engram; `--recover` instead restores database backups, and memory files sync automatically on next OpenClaw startup.
54
+
55
+ ## Guardian API
56
+
57
+ Guardians are trusted principals who can take emergency actions. Adding/removing
58
+ guardians is an owner-only operation done from the engramx.ai dashboard with
59
+ Internet Identity authentication. The SDK exposes the read-only side:
60
+
61
+ ```typescript
62
+ // List guardians
63
+ const guardians = await engram.listGuardians();
64
+ ```
65
+
66
+ The SDK runs on operator-credentialed agent hosts and intentionally does NOT
67
+ expose owner-only methods (writeMemory, addGuardian, setProtectedPaths,
68
+ setPaymentPolicy, signTypedData, etc.). Owner workflows belong in the
69
+ dashboard at engramx.ai.
70
+
71
+ ## Backup API
72
+
73
+ Store and retrieve external database snapshots:
74
+
75
+ ```typescript
76
+ // Init a backup upload
77
+ const backupId = await engram.initBackup('sqlite', { FullSnapshot: null }, null, sha256, 'daily-backup');
78
+
79
+ // Upload in chunks
80
+ await engram.pushBackupChunk(backupId, 0, chunkData);
81
+
82
+ // Finalize
83
+ await engram.finalizeBackup(backupId);
84
+
85
+ // List backups
86
+ const backups = await engram.listBackups('sqlite');
87
+
88
+ // Download a chunk
89
+ const data = await engram.pullBackupChunk(backupId, 0);
90
+ ```
91
+
92
+ ## OpenClaw Integration
93
+
94
+ The `--target openclaw` option on `pair` handles plugin installation and `openclaw.json` configuration automatically. For manual setup or customization, see [integrations/openclaw/README.md](../../integrations/openclaw/README.md).
95
+
96
+ ## Roadmap
97
+
98
+ These features are stubbed and available in the canister interface but not yet fully implemented:
99
+
100
+ - **ERC-8004 Agent Identity** — threshold ECDSA-derived Ethereum address
101
+ - **x402 Payment Protocol** — autonomous HTTP-based payments
102
+ - **World ID** — proof-of-personhood for engram owners
103
+
104
+ ## License
105
+
106
+ MIT
@@ -0,0 +1,223 @@
1
+ import { Principal } from '@icp-sdk/core/principal';
2
+ import { Ic402Client, type SessionHandle } from '@ic402/client';
3
+ import type { RawMemoryFile, MemoryFile, MemoryFileInfo, MemoryVersion, OperatorRecord, AuditEntry, EngramStatus, GuardianRecord, WorldIdProof, BackupMetadata, BackupType, StorageStats, PaymentRequirement, PaymentSignature, PaymentResult, SessionIntent, SessionConfig, SessionState, Voucher, SpendingPolicy, ContentEntry, ContentDelivery, AgentCard, ApprovalRequest, EndpointType, EndpointStatus, X402Endpoint, PurchaseRecord, RevenueSummary } from './types';
4
+ export interface EngramClientConfig {
5
+ /** The engram canister ID */
6
+ canisterId: string;
7
+ /** Path to the Ed25519 session key file */
8
+ sessionKeyPath?: string;
9
+ /** Or provide the key directly as a Uint8Array (32 bytes seed) */
10
+ sessionKeySeed?: Uint8Array;
11
+ /** ICP host. Default: 'https://ic0.app' for mainnet */
12
+ host?: string;
13
+ /** Cache duration in milliseconds for memory reads. Default: 60000 (1 minute) */
14
+ cacheMaxAge?: number;
15
+ /** Max cache entries. Default: 100 */
16
+ cacheMaxSize?: number;
17
+ /** Path for offline queue. Default: null (disabled) */
18
+ offlineQueuePath?: string;
19
+ /** Encrypt memory content client-side via vetKeys. Default: false (plaintext).
20
+ * Enable for new/migrated engrams; the canister must support vetKD. Reads of
21
+ * legacy plaintext keep working regardless. */
22
+ encryptMemory?: boolean;
23
+ }
24
+ export declare class EngramClient {
25
+ private agent;
26
+ private actor;
27
+ private cache;
28
+ private offlineQueue?;
29
+ private identity;
30
+ private canisterId;
31
+ private encryption;
32
+ private encryptionModeSynced;
33
+ private unwrap;
34
+ constructor(config: EngramClientConfig);
35
+ readMemory(path: string): Promise<MemoryFile>;
36
+ appendMemory(path: string, content: string): Promise<bigint>;
37
+ listMemoryFiles(): Promise<MemoryFileInfo[]>;
38
+ readMemoryBatch(paths: string[]): Promise<[string, MemoryFile | Error][]>;
39
+ getMemoryHistory(path: string): Promise<MemoryVersion[]>;
40
+ walletBalance(): Promise<bigint>;
41
+ readAuditLog(fromIndex?: number, limit?: number): Promise<AuditEntry[]>;
42
+ auditLogSize(): Promise<bigint>;
43
+ status(): Promise<EngramStatus>;
44
+ listGuardians(): Promise<GuardianRecord[]>;
45
+ rotateOperatorKey(newPublicKeyHash: string): Promise<void>;
46
+ getWorldIdProof(): Promise<WorldIdProof | null>;
47
+ getPaymentRequirements(amount: bigint): Promise<PaymentRequirement[]>;
48
+ requestSession(): Promise<SessionIntent>;
49
+ openSession(config: SessionConfig, sig: PaymentSignature, rationale?: string, approvalId?: string): Promise<SessionState | {
50
+ approvalPending: ApprovalRequest;
51
+ }>;
52
+ sessionReadMemory(voucher: Voucher, path: string): Promise<RawMemoryFile>;
53
+ sessionAppendMemory(voucher: Voucher, path: string, content: Uint8Array): Promise<bigint>;
54
+ endSession(sessionId: string): Promise<PaymentResult>;
55
+ forceCloseSession(sessionId: string): Promise<PaymentResult>;
56
+ uploadContent(id: string, mimeType: string, data: Uint8Array): Promise<void>;
57
+ /**
58
+ * E8: upload content larger than the ~2 MB single-shot ingress limit by streaming it through the
59
+ * canister's chunked path (uploadContentInit + uploadContentChunk). Chunk size is 1.5 MB — the
60
+ * ContentStore MAX_CHUNK_SIZE, enforced as a hard cap and safely under ICP's 2 MB ingress limit once
61
+ * Candid framing is added.
62
+ *
63
+ * There is NO finalize step: content is complete and readable once every chunk is written (the store
64
+ * reassembles on read). Chunks are write-once server-side (CTR keystream-reuse guard), so a mid-upload
65
+ * failure leaves a stuck, un-overwritable entry; on any error this helper best-effort deletes the
66
+ * partial entry so the caller can retry from scratch (set cleanupOnError=false to keep it for a manual
67
+ * resume). Payloads at or under one chunk delegate to single-shot uploadContent.
68
+ */
69
+ uploadContentChunked(id: string, mimeType: string, data: Uint8Array, cleanupOnError?: boolean): Promise<void>;
70
+ listContent(): Promise<ContentEntry[]>;
71
+ getContent(contentId: string, paymentSig?: PaymentSignature, rationale?: string, approvalId?: string): Promise<{
72
+ paymentRequired?: PaymentRequirement[];
73
+ delivery?: ContentDelivery;
74
+ error?: string;
75
+ approvalPending?: ApprovalRequest;
76
+ }>;
77
+ deleteContent(id: string): Promise<void>;
78
+ createEndpoint(name: string, description: string, endpointType: EndpointType, contentId: string | null, suggestedPrice: bigint): Promise<X402Endpoint>;
79
+ listEndpoints(statusFilter?: EndpointStatus): Promise<X402Endpoint[]>;
80
+ getEndpointPurchases(endpointId: string, fromIndex: bigint, limit: bigint): Promise<PurchaseRecord[]>;
81
+ getRevenueSummary(): Promise<RevenueSummary>;
82
+ getPaymentPolicy(): Promise<SpendingPolicy>;
83
+ getAgentCard(): Promise<AgentCard>;
84
+ getEvmAddress(): Promise<string>;
85
+ getOwnerEvmAddress(): Promise<string | null>;
86
+ initBackup(dbType: string, backupType: BackupType, parentBackupId: string | null, sha256: string, backupLabel: string | null): Promise<string>;
87
+ pushBackupChunk(backupId: string, chunkIndex: number, data: Uint8Array): Promise<void>;
88
+ finalizeBackup(backupId: string): Promise<void>;
89
+ abortBackup(backupId: string): Promise<void>;
90
+ listBackups(dbTypeFilter?: string): Promise<BackupMetadata[]>;
91
+ pullBackupChunk(backupId: string, chunkIndex: number): Promise<Uint8Array>;
92
+ getBackupMetadata(backupId: string): Promise<BackupMetadata>;
93
+ deleteBackup(backupId: string): Promise<void>;
94
+ latestBackupMatchesHash(dbType: string, sha256: string): Promise<BackupMetadata | null>;
95
+ storageStats(): Promise<StorageStats>;
96
+ /** Warm the vetKeys memory-encryption key cache (one vetKD derivation). Optional —
97
+ * read/append derive lazily on first use. */
98
+ initEncryption(): Promise<void>;
99
+ clearEncryptionCache(): void;
100
+ /** Sync the write-time encryption mode from the canister flag (once, cached),
101
+ * unless an explicit `encryptMemory` was given at construction. */
102
+ private ensureEncryptionMode;
103
+ /** Whether this engram has memory encryption enabled (reads the canister flag). */
104
+ isMemoryEncryptionEnabled(): Promise<boolean>;
105
+ /** Owner-only: turn memory encryption on/off on the canister. Updates the local
106
+ * write mode immediately. Turning ON does not re-encrypt existing files — call
107
+ * migrateMemoryToEncrypted() for that. */
108
+ setMemoryEncryption(enabled: boolean): Promise<void>;
109
+ /** Owner-only: re-encrypt all existing memory files under the current key. Reads
110
+ * each file (decrypting any that are already encrypted), then rewrites it via
111
+ * writeMemory so it is stored as ciphertext. Idempotent and resumable — files
112
+ * already encrypted are simply re-written identically. Requires encryption to be
113
+ * enabled (canister flag) and an owner identity (writeMemory is owner-only). */
114
+ migrateMemoryToEncrypted(): Promise<{
115
+ migrated: number;
116
+ total: number;
117
+ failed: string[];
118
+ }>;
119
+ syncOfflineQueue(): Promise<{
120
+ synced: number;
121
+ failed: number;
122
+ }>;
123
+ registerOperator(inviteCode: string): Promise<OperatorRecord>;
124
+ getProtectedPaths(): Promise<string[]>;
125
+ /**
126
+ * Create a pre-configured Ic402Client for auto-payment operations.
127
+ * The client handles 402 → ICRC-2 approve → retry automatically.
128
+ */
129
+ createPaymentClient(options?: {
130
+ autoPayment?: boolean;
131
+ ledger?: string;
132
+ }): Ic402Client;
133
+ /**
134
+ * Auto-pay bridge for the engramx x402 methods. The stock ic402 client injects the
135
+ * payment signature into the LAST argument, but the engramx canister appends
136
+ * `rationale` + `approvalId` AFTER `paymentSig` (for the owner approval workflow), so the
137
+ * signature must land at a FIXED index, not last. Flow: call with no sig → on
138
+ * #paymentRequired, icrc2_approve the amount (+ fee buffer) → build the ICP payment
139
+ * signature (a nonce-carrier; the real authorization is the ICRC-2 allowance the canister
140
+ * spends via transfer_from) → retry with the sig at `sigIndex`. Returns the raw canister
141
+ * result; the caller unwraps ok/error/approvalPending.
142
+ */
143
+ private payAndCall;
144
+ /**
145
+ * Get paid content with auto-payment. Handles #paymentRequired → approve → retry.
146
+ * @param contentId Content identifier
147
+ * @param options Optional ledger override
148
+ */
149
+ getContentWithPayment(contentId: string, options?: {
150
+ ledger?: string;
151
+ }): Promise<ContentDelivery>;
152
+ /**
153
+ * Open a streaming payment session with auto-escrow and voucher signing.
154
+ * Returns a SessionHandle that auto-signs vouchers on each call.
155
+ *
156
+ * Usage:
157
+ * const session = await engram.openPaymentSession({ maxDeposit: 50_000n });
158
+ * const file = await session.call('sessionReadMemory', ['SOUL.md']);
159
+ * const receipt = await session.close();
160
+ */
161
+ openPaymentSession(options?: {
162
+ maxDeposit?: bigint;
163
+ autoClose?: boolean;
164
+ ledger?: string;
165
+ }): Promise<SessionHandle>;
166
+ registerService(name: string, description: string, serviceType: {
167
+ Sync: null;
168
+ } | {
169
+ Async: null;
170
+ }, pricing: {
171
+ Exact: bigint;
172
+ } | {
173
+ Upto: bigint;
174
+ } | {
175
+ Session: null;
176
+ }, verificationMethod: string, delivery: {
177
+ Poll: null;
178
+ } | {
179
+ Callback: null;
180
+ } | {
181
+ Both: null;
182
+ }, timeout: bigint, verifierCanisterId?: string, verificationKey?: Uint8Array, bindResult?: boolean): Promise<string>;
183
+ listServices(): Promise<unknown[]>;
184
+ /** Owner/operator view — includes disabled service drafts (others get enabled-only). */
185
+ listAllServices(): Promise<unknown[]>;
186
+ submitServiceRequest(serviceId: string, params: Uint8Array, paymentSig?: unknown, rationale?: string, approvalId?: string): Promise<{
187
+ jobId: string;
188
+ } | {
189
+ approvalPending: unknown;
190
+ }>;
191
+ /**
192
+ * Submit a paid service request with auto-payment (the marketplace counterpart of
193
+ * getContentWithPayment). Handles #paymentRequired → approve → retry, injecting the
194
+ * signature at the correct index for the engramx submitServiceRequest signature
195
+ * (serviceId, params, paymentSig, rationale, approvalId). Returns the jobId, or an
196
+ * approval-pending handle when the charge exceeds policy and the owner must approve.
197
+ */
198
+ submitServiceRequestWithPayment(serviceId: string, params: Uint8Array, options?: {
199
+ ledger?: string;
200
+ rationale?: string;
201
+ }): Promise<{
202
+ jobId: string;
203
+ } | {
204
+ approvalPending: unknown;
205
+ }>;
206
+ claimJob(jobId: string): Promise<void>;
207
+ submitJobResult(jobId: string, result: Uint8Array, proof?: Uint8Array, actualCost?: bigint): Promise<void>;
208
+ confirmJob(jobId: string): Promise<void>;
209
+ disputeJob(jobId: string, reason: string): Promise<void>;
210
+ getJobStatus(jobId: string): Promise<unknown | null>;
211
+ getJob(jobId: string): Promise<unknown | null>;
212
+ /**
213
+ * E1: enumerate a service's job summaries. Owner OR the service's own operator only — any other
214
+ * caller gets []. Summaries omit params/result/proof blobs (use getJob(jobId) for a full payload).
215
+ * Pass a statusFilter like `{ Pending: null }` to filter, or omit for all statuses.
216
+ */
217
+ listJobs(serviceId: string, statusFilter?: unknown): Promise<unknown[]>;
218
+ getJobResult(jobId: string): Promise<Uint8Array | null>;
219
+ pollJobResult(jobId: string, maxAttempts?: number, intervalMs?: number): Promise<unknown>;
220
+ keccak256(data: number[]): Promise<number[]>;
221
+ clearCache(): void;
222
+ getPrincipal(): Principal;
223
+ }