@engramx/client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +116 -0
  3. package/dist/EngramClient.d.ts +204 -0
  4. package/dist/EngramClient.js +1168 -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,116 @@
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
+ // Search memory
35
+ const results = await engram.searchKeyword('authentication', 5);
36
+
37
+ // Read session transcript
38
+ const messages = await engram.readSession('session-key', 0, 50);
39
+
40
+ // Append to session
41
+ await engram.appendSession('session-key', [
42
+ { role: { User: null }, content: 'Hello', timestamp: BigInt(Date.now() * 1_000_000) },
43
+ ]);
44
+
45
+ // Check balance
46
+ const balance = await engram.walletBalance();
47
+ ```
48
+
49
+ ## Pairing
50
+
51
+ Register your machine as an operator:
52
+
53
+ ```bash
54
+ # First host — push local memory files to the engram
55
+ pnpm dlx @engramx/client pair <invite-code> --engram <canister-id> --openclaw
56
+
57
+ # Replacement host — restore database backups from the engram
58
+ pnpm dlx @engramx/client pair <invite-code> --engram <canister-id> --openclaw --recover
59
+ ```
60
+
61
+ Both modes generate `~/.engramx/session.key`, register the operator, and install the OpenClaw plugin. They save a local checkpoint first — run `engramx rollback` to undo.
62
+
63
+ Migration (default) pushes local memory files to the engram. Recovery (`--recover`) restores database backups; memory files sync automatically on next OpenClaw startup.
64
+
65
+ ## Guardian API
66
+
67
+ Guardians are trusted principals who can take emergency actions. Adding/removing
68
+ guardians is an owner-only operation done from the engramx.ai dashboard with
69
+ Internet Identity authentication. The SDK exposes the read-only side:
70
+
71
+ ```typescript
72
+ // List guardians
73
+ const guardians = await engram.listGuardians();
74
+ ```
75
+
76
+ The SDK runs on operator-credentialed agent hosts and intentionally does NOT
77
+ expose owner-only methods (writeMemory, addGuardian, setProtectedPaths,
78
+ setPaymentPolicy, signTypedData, etc.). Owner workflows belong in the
79
+ dashboard at engramx.ai.
80
+
81
+ ## Backup API
82
+
83
+ Store and retrieve external database snapshots:
84
+
85
+ ```typescript
86
+ // Init a backup upload
87
+ const backupId = await engram.initBackup('sqlite', { FullSnapshot: null }, null, sha256, 'daily-backup');
88
+
89
+ // Upload in chunks
90
+ await engram.pushBackupChunk(backupId, 0, chunkData);
91
+
92
+ // Finalize
93
+ await engram.finalizeBackup(backupId);
94
+
95
+ // List backups
96
+ const backups = await engram.listBackups('sqlite');
97
+
98
+ // Download a chunk
99
+ const data = await engram.pullBackupChunk(backupId, 0);
100
+ ```
101
+
102
+ ## OpenClaw Integration
103
+
104
+ The `--openclaw` flag on `pair` handles plugin installation and `openclaw.json` configuration automatically. For manual setup or customization, see [integrations/openclaw/README.md](../../integrations/openclaw/README.md).
105
+
106
+ ## Roadmap
107
+
108
+ These features are stubbed and available in the canister interface but not yet fully implemented:
109
+
110
+ - **ERC-8004 Agent Identity** — threshold ECDSA-derived Ethereum address
111
+ - **x402 Payment Protocol** — autonomous HTTP-based payments
112
+ - **World ID** — proof-of-personhood for engram owners
113
+
114
+ ## License
115
+
116
+ MIT
@@ -0,0 +1,204 @@
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
+ listContent(): Promise<ContentEntry[]>;
58
+ getContent(contentId: string, paymentSig?: PaymentSignature, rationale?: string, approvalId?: string): Promise<{
59
+ paymentRequired?: PaymentRequirement[];
60
+ delivery?: ContentDelivery;
61
+ error?: string;
62
+ approvalPending?: ApprovalRequest;
63
+ }>;
64
+ deleteContent(id: string): Promise<void>;
65
+ createEndpoint(name: string, description: string, endpointType: EndpointType, contentId: string | null, suggestedPrice: bigint): Promise<X402Endpoint>;
66
+ listEndpoints(statusFilter?: EndpointStatus): Promise<X402Endpoint[]>;
67
+ getEndpointPurchases(endpointId: string, fromIndex: bigint, limit: bigint): Promise<PurchaseRecord[]>;
68
+ getRevenueSummary(): Promise<RevenueSummary>;
69
+ getPaymentPolicy(): Promise<SpendingPolicy>;
70
+ getAgentCard(): Promise<AgentCard>;
71
+ getEvmAddress(): Promise<string>;
72
+ getOwnerEvmAddress(): Promise<string | null>;
73
+ initBackup(dbType: string, backupType: BackupType, parentBackupId: string | null, sha256: string, backupLabel: string | null): Promise<string>;
74
+ pushBackupChunk(backupId: string, chunkIndex: number, data: Uint8Array): Promise<void>;
75
+ finalizeBackup(backupId: string): Promise<void>;
76
+ abortBackup(backupId: string): Promise<void>;
77
+ listBackups(dbTypeFilter?: string): Promise<BackupMetadata[]>;
78
+ pullBackupChunk(backupId: string, chunkIndex: number): Promise<Uint8Array>;
79
+ getBackupMetadata(backupId: string): Promise<BackupMetadata>;
80
+ deleteBackup(backupId: string): Promise<void>;
81
+ latestBackupMatchesHash(dbType: string, sha256: string): Promise<BackupMetadata | null>;
82
+ storageStats(): Promise<StorageStats>;
83
+ /** Warm the vetKeys memory-encryption key cache (one vetKD derivation). Optional —
84
+ * read/append derive lazily on first use. */
85
+ initEncryption(): Promise<void>;
86
+ clearEncryptionCache(): void;
87
+ /** Sync the write-time encryption mode from the canister flag (once, cached),
88
+ * unless an explicit `encryptMemory` was given at construction. */
89
+ private ensureEncryptionMode;
90
+ /** Whether this engram has memory encryption enabled (reads the canister flag). */
91
+ isMemoryEncryptionEnabled(): Promise<boolean>;
92
+ /** Owner-only: turn memory encryption on/off on the canister. Updates the local
93
+ * write mode immediately. Turning ON does not re-encrypt existing files — call
94
+ * migrateMemoryToEncrypted() for that. */
95
+ setMemoryEncryption(enabled: boolean): Promise<void>;
96
+ /** Owner-only: re-encrypt all existing memory files under the current key. Reads
97
+ * each file (decrypting any that are already encrypted), then rewrites it via
98
+ * writeMemory so it is stored as ciphertext. Idempotent and resumable — files
99
+ * already encrypted are simply re-written identically. Requires encryption to be
100
+ * enabled (canister flag) and an owner identity (writeMemory is owner-only). */
101
+ migrateMemoryToEncrypted(): Promise<{
102
+ migrated: number;
103
+ total: number;
104
+ failed: string[];
105
+ }>;
106
+ syncOfflineQueue(): Promise<{
107
+ synced: number;
108
+ failed: number;
109
+ }>;
110
+ registerOperator(inviteCode: string): Promise<OperatorRecord>;
111
+ getProtectedPaths(): Promise<string[]>;
112
+ /**
113
+ * Create a pre-configured Ic402Client for auto-payment operations.
114
+ * The client handles 402 → ICRC-2 approve → retry automatically.
115
+ */
116
+ createPaymentClient(options?: {
117
+ autoPayment?: boolean;
118
+ ledger?: string;
119
+ }): Ic402Client;
120
+ /**
121
+ * Auto-pay bridge for the engramx x402 methods. The stock ic402 client injects the
122
+ * payment signature into the LAST argument, but the engramx canister appends
123
+ * `rationale` + `approvalId` AFTER `paymentSig` (for the owner approval workflow), so the
124
+ * signature must land at a FIXED index, not last. Flow: call with no sig → on
125
+ * #paymentRequired, icrc2_approve the amount (+ fee buffer) → build the ICP payment
126
+ * signature (a nonce-carrier; the real authorization is the ICRC-2 allowance the canister
127
+ * spends via transfer_from) → retry with the sig at `sigIndex`. Returns the raw canister
128
+ * result; the caller unwraps ok/error/approvalPending.
129
+ */
130
+ private payAndCall;
131
+ /**
132
+ * Get paid content with auto-payment. Handles #paymentRequired → approve → retry.
133
+ * @param contentId Content identifier
134
+ * @param options Optional ledger override
135
+ */
136
+ getContentWithPayment(contentId: string, options?: {
137
+ ledger?: string;
138
+ }): Promise<ContentDelivery>;
139
+ /**
140
+ * Open a streaming payment session with auto-escrow and voucher signing.
141
+ * Returns a SessionHandle that auto-signs vouchers on each call.
142
+ *
143
+ * Usage:
144
+ * const session = await engram.openPaymentSession({ maxDeposit: 50_000n });
145
+ * const file = await session.call('sessionReadMemory', ['SOUL.md']);
146
+ * const receipt = await session.close();
147
+ */
148
+ openPaymentSession(options?: {
149
+ maxDeposit?: bigint;
150
+ autoClose?: boolean;
151
+ ledger?: string;
152
+ }): Promise<SessionHandle>;
153
+ registerService(name: string, description: string, serviceType: {
154
+ Sync: null;
155
+ } | {
156
+ Async: null;
157
+ }, pricing: {
158
+ Exact: bigint;
159
+ } | {
160
+ Upto: bigint;
161
+ } | {
162
+ Session: null;
163
+ }, verificationMethod: string, delivery: {
164
+ Poll: null;
165
+ } | {
166
+ Callback: null;
167
+ } | {
168
+ Both: null;
169
+ }, timeout: bigint, verifierCanisterId?: string, verificationKey?: Uint8Array): Promise<string>;
170
+ listServices(): Promise<unknown[]>;
171
+ /** Owner/operator view — includes disabled service drafts (others get enabled-only). */
172
+ listAllServices(): Promise<unknown[]>;
173
+ submitServiceRequest(serviceId: string, params: Uint8Array, paymentSig?: unknown, rationale?: string, approvalId?: string): Promise<{
174
+ jobId: string;
175
+ } | {
176
+ approvalPending: unknown;
177
+ }>;
178
+ /**
179
+ * Submit a paid service request with auto-payment (the marketplace counterpart of
180
+ * getContentWithPayment). Handles #paymentRequired → approve → retry, injecting the
181
+ * signature at the correct index for the engramx submitServiceRequest signature
182
+ * (serviceId, params, paymentSig, rationale, approvalId). Returns the jobId, or an
183
+ * approval-pending handle when the charge exceeds policy and the owner must approve.
184
+ */
185
+ submitServiceRequestWithPayment(serviceId: string, params: Uint8Array, options?: {
186
+ ledger?: string;
187
+ rationale?: string;
188
+ }): Promise<{
189
+ jobId: string;
190
+ } | {
191
+ approvalPending: unknown;
192
+ }>;
193
+ claimJob(jobId: string): Promise<void>;
194
+ submitJobResult(jobId: string, result: Uint8Array, proof?: Uint8Array, actualCost?: bigint): Promise<void>;
195
+ confirmJob(jobId: string): Promise<void>;
196
+ disputeJob(jobId: string, reason: string): Promise<void>;
197
+ getJobStatus(jobId: string): Promise<unknown | null>;
198
+ getJob(jobId: string): Promise<unknown | null>;
199
+ getJobResult(jobId: string): Promise<Uint8Array | null>;
200
+ pollJobResult(jobId: string, maxAttempts?: number, intervalMs?: number): Promise<unknown>;
201
+ keccak256(data: number[]): Promise<number[]>;
202
+ clearCache(): void;
203
+ getPrincipal(): Principal;
204
+ }