@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.
- package/LICENSE +21 -0
- package/README.md +116 -0
- package/dist/EngramClient.d.ts +204 -0
- package/dist/EngramClient.js +1168 -0
- package/dist/EngramClient.js.map +1 -0
- package/dist/ProfileManager.d.ts +61 -0
- package/dist/ProfileManager.js +116 -0
- package/dist/ProfileManager.js.map +1 -0
- package/dist/SessionManager.d.ts +46 -0
- package/dist/SessionManager.js +114 -0
- package/dist/SessionManager.js.map +1 -0
- package/dist/agent-skill.d.ts +150 -0
- package/dist/agent-skill.js +152 -0
- package/dist/agent-skill.js.map +1 -0
- package/dist/auth.d.ts +17 -0
- package/dist/auth.js +65 -0
- package/dist/auth.js.map +1 -0
- package/dist/bootstrap.d.ts +21 -0
- package/dist/bootstrap.js +71 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/cache.d.ts +11 -0
- package/dist/cache.js +41 -0
- package/dist/cache.js.map +1 -0
- package/dist/claude-setup.d.ts +29 -0
- package/dist/claude-setup.js +57 -0
- package/dist/claude-setup.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1078 -0
- package/dist/cli.js.map +1 -0
- package/dist/encryption.d.ts +44 -0
- package/dist/encryption.js +108 -0
- package/dist/encryption.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/migrate.d.ts +106 -0
- package/dist/migrate.js +882 -0
- package/dist/migrate.js.map +1 -0
- package/dist/offline.d.ts +21 -0
- package/dist/offline.js +90 -0
- package/dist/offline.js.map +1 -0
- package/dist/openclaw-setup.d.ts +24 -0
- package/dist/openclaw-setup.js +249 -0
- package/dist/openclaw-setup.js.map +1 -0
- package/dist/pair.d.ts +20 -0
- package/dist/pair.js +68 -0
- package/dist/pair.js.map +1 -0
- package/dist/path-utils.d.ts +16 -0
- package/dist/path-utils.js +29 -0
- package/dist/path-utils.js.map +1 -0
- package/dist/schema.d.ts +54 -0
- package/dist/schema.js +101 -0
- package/dist/schema.js.map +1 -0
- package/dist/types.d.ts +452 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Skill: engramx
|
|
3
|
+
*
|
|
4
|
+
* Provides AI agents with tools to read/write persistent memory from an ICP
|
|
5
|
+
* engram canister. Works with any agent framework that supports tool/skill
|
|
6
|
+
* registration (OpenClaw, LangChain, etc.).
|
|
7
|
+
*
|
|
8
|
+
* Setup:
|
|
9
|
+
* 1. Install: pnpm add @engramx/client
|
|
10
|
+
* 2. Set environment variables:
|
|
11
|
+
* ENGRAM_CANISTER_ID=xxxxx-xxxxx-xxxxx-xxxxx-xxx (also checks VAULT_CANISTER_ID for migration)
|
|
12
|
+
* ENGRAM_SESSION_KEY_PATH=~/.engramx/session.key
|
|
13
|
+
* (also checks ENGRAMX_SESSION_KEY_PATH, VAULT_SESSION_KEY_PATH, and ~/.openclaw/vault-session.key for migration)
|
|
14
|
+
* 3. Add this skill to your agent's skill list
|
|
15
|
+
*/
|
|
16
|
+
import { EngramClient } from './EngramClient';
|
|
17
|
+
import { ProfileManager } from './ProfileManager';
|
|
18
|
+
import { SessionManager } from './SessionManager';
|
|
19
|
+
const canisterId = process.env['ENGRAM_CANISTER_ID'] || process.env['VAULT_CANISTER_ID'];
|
|
20
|
+
if (!canisterId) {
|
|
21
|
+
throw new Error('ENGRAM_CANISTER_ID environment variable is required');
|
|
22
|
+
}
|
|
23
|
+
const sessionKeyPath = process.env['ENGRAM_SESSION_KEY_PATH'] ||
|
|
24
|
+
process.env['ENGRAMX_SESSION_KEY_PATH'] ||
|
|
25
|
+
process.env['VAULT_SESSION_KEY_PATH'];
|
|
26
|
+
if (!sessionKeyPath) {
|
|
27
|
+
throw new Error('ENGRAM_SESSION_KEY_PATH environment variable is required');
|
|
28
|
+
}
|
|
29
|
+
const engram = new EngramClient({
|
|
30
|
+
canisterId,
|
|
31
|
+
sessionKeyPath,
|
|
32
|
+
cacheMaxAge: 60000,
|
|
33
|
+
offlineQueuePath: process.env['ENGRAM_OFFLINE_QUEUE_PATH'] ||
|
|
34
|
+
process.env['VAULT_OFFLINE_QUEUE_PATH'] ||
|
|
35
|
+
undefined,
|
|
36
|
+
});
|
|
37
|
+
const profile = new ProfileManager(engram);
|
|
38
|
+
const sessions = new SessionManager(engram);
|
|
39
|
+
export const name = 'engramx';
|
|
40
|
+
export const description = 'Persistent, decentralized memory storage for your agent';
|
|
41
|
+
export const tools = {
|
|
42
|
+
engram_read_memory: {
|
|
43
|
+
description: 'Read a memory file from the engram (e.g., "MEMORY.md", "memory/2026-02-11.md")',
|
|
44
|
+
parameters: { path: { type: 'string', description: 'File path' } },
|
|
45
|
+
execute: async ({ path }) => {
|
|
46
|
+
const file = await engram.readMemory(path);
|
|
47
|
+
return file.content;
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
engram_append_memory: {
|
|
51
|
+
description: 'Append content to a memory file in the engram. Creates the file if it does not exist. Cannot modify owner-protected paths.',
|
|
52
|
+
parameters: {
|
|
53
|
+
path: { type: 'string', description: 'File path' },
|
|
54
|
+
content: { type: 'string', description: 'Content to append' },
|
|
55
|
+
},
|
|
56
|
+
execute: async ({ path, content }) => {
|
|
57
|
+
const version = await engram.appendMemory(path, content);
|
|
58
|
+
return `Appended to ${path} (version ${version})`;
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
engram_list_memory: {
|
|
62
|
+
description: 'List all memory files stored in the engram',
|
|
63
|
+
parameters: {},
|
|
64
|
+
execute: async () => {
|
|
65
|
+
const files = await engram.listMemoryFiles();
|
|
66
|
+
return files
|
|
67
|
+
.map((f) => `${f.path} (v${f.version}, modified ${new Date(Number(f.lastModifiedAt) / 1000000).toISOString()})`)
|
|
68
|
+
.join('\n');
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
engram_wallet_balance: {
|
|
72
|
+
description: 'Check the engram wallet balance',
|
|
73
|
+
parameters: {},
|
|
74
|
+
execute: async () => {
|
|
75
|
+
const balance = await engram.walletBalance();
|
|
76
|
+
return `Balance: ${Number(balance) / 100000000} ICP`;
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
engram_payment_info: {
|
|
80
|
+
description: 'Get x402 payment requirements for accessing engram memory. Returns pricing and accepted payment methods.',
|
|
81
|
+
parameters: {
|
|
82
|
+
amount: { type: 'number', description: 'Amount in USDC e6s (1000 = $0.001)' },
|
|
83
|
+
},
|
|
84
|
+
execute: async ({ amount }) => {
|
|
85
|
+
const requirements = await engram.getPaymentRequirements(BigInt(amount));
|
|
86
|
+
return `Payment requirements (${requirements.length} options):\n${JSON.stringify(requirements, (_, v) => (typeof v === 'bigint' ? v.toString() : v), 2)}`;
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
// ── Schema-aware tools (ProfileManager / SessionManager) ────
|
|
90
|
+
engram_get_profile: {
|
|
91
|
+
description: 'Load user identity (soul, user, preferences) and accumulated lessons in one call. Use at session start.',
|
|
92
|
+
parameters: {},
|
|
93
|
+
execute: async () => {
|
|
94
|
+
const p = await profile.getProfile();
|
|
95
|
+
return JSON.stringify(p, null, 2);
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
engram_save_preference: {
|
|
99
|
+
description: 'Save a user preference (e.g. "prefers terse responses"). Persists across platforms.',
|
|
100
|
+
parameters: {
|
|
101
|
+
preference: { type: 'string', description: 'The preference to save' },
|
|
102
|
+
},
|
|
103
|
+
execute: async ({ preference }) => {
|
|
104
|
+
const version = await profile.savePreference(preference);
|
|
105
|
+
return `Preference saved (version ${version})`;
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
engram_save_insight: {
|
|
109
|
+
description: 'Save a lesson or insight. Optionally provide a topic for domain-specific knowledge.',
|
|
110
|
+
parameters: {
|
|
111
|
+
content: { type: 'string', description: 'The insight to save' },
|
|
112
|
+
topic: { type: 'string', description: 'Optional domain topic (lowercase, alphanumeric)' },
|
|
113
|
+
},
|
|
114
|
+
execute: async ({ content, topic }) => {
|
|
115
|
+
const version = await profile.saveInsight({ content, topic });
|
|
116
|
+
return `Insight saved${topic ? ` (topic: ${topic})` : ''} (version ${version})`;
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
engram_save_decision: {
|
|
120
|
+
description: 'Record a decision and its rationale for future cross-platform reference.',
|
|
121
|
+
parameters: {
|
|
122
|
+
decision: { type: 'string', description: 'What was decided' },
|
|
123
|
+
rationale: { type: 'string', description: 'Why this decision was made' },
|
|
124
|
+
},
|
|
125
|
+
execute: async ({ decision, rationale }) => {
|
|
126
|
+
const version = await profile.saveDecision(decision, rationale);
|
|
127
|
+
return `Decision recorded (version ${version})`;
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
engram_session_summary: {
|
|
131
|
+
description: 'Write a session summary for today. Other platforms can read this for continuity.',
|
|
132
|
+
parameters: {
|
|
133
|
+
platform: { type: 'string', description: 'Platform name (e.g. "openclaw")' },
|
|
134
|
+
summary: { type: 'string', description: 'Summary of what was accomplished' },
|
|
135
|
+
},
|
|
136
|
+
execute: async ({ platform, summary }) => {
|
|
137
|
+
const version = await sessions.writeSummary(platform, summary);
|
|
138
|
+
return `Session summary saved for ${platform} (version ${version})`;
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
engram_read_sessions: {
|
|
142
|
+
description: 'Read recent session summaries across platforms for continuity.',
|
|
143
|
+
parameters: {
|
|
144
|
+
limit: { type: 'number', description: 'Max sessions to return (default: 5)' },
|
|
145
|
+
},
|
|
146
|
+
execute: async ({ limit }) => {
|
|
147
|
+
const result = await sessions.readRecent(limit ?? 5);
|
|
148
|
+
return JSON.stringify(result, null, 2);
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
//# sourceMappingURL=agent-skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-skill.js","sourceRoot":"","sources":["../src/agent-skill.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Ed25519KeyIdentity } from '@icp-sdk/core/identity';
|
|
2
|
+
/**
|
|
3
|
+
* Load or create an Ed25519 session key identity.
|
|
4
|
+
*
|
|
5
|
+
* The key file stores a 32-byte seed. If the file doesn't exist,
|
|
6
|
+
* a new random key is generated and saved.
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadSessionKey(keyPath: string): Ed25519KeyIdentity;
|
|
9
|
+
/**
|
|
10
|
+
* Create an Ed25519 identity from a raw 32-byte seed.
|
|
11
|
+
*/
|
|
12
|
+
export declare function identityFromSeed(seed: Uint8Array): Ed25519KeyIdentity;
|
|
13
|
+
/**
|
|
14
|
+
* Generate a new session key and save it to disk.
|
|
15
|
+
* Returns the identity.
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateSessionKey(keyPath: string): Ed25519KeyIdentity;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Ed25519KeyIdentity } from '@icp-sdk/core/identity';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as crypto from 'crypto';
|
|
5
|
+
/**
|
|
6
|
+
* Load or create an Ed25519 session key identity.
|
|
7
|
+
*
|
|
8
|
+
* The key file stores a 32-byte seed. If the file doesn't exist,
|
|
9
|
+
* a new random key is generated and saved.
|
|
10
|
+
*/
|
|
11
|
+
export function loadSessionKey(keyPath) {
|
|
12
|
+
const home = process.env['HOME'];
|
|
13
|
+
if (keyPath.startsWith('~') && !home)
|
|
14
|
+
throw new Error('HOME environment variable is not set');
|
|
15
|
+
const resolvedPath = keyPath.startsWith('~') ? path.join(home, keyPath.slice(1)) : keyPath;
|
|
16
|
+
if (fs.existsSync(resolvedPath)) {
|
|
17
|
+
// Refuse to load symlinked key files
|
|
18
|
+
const lstat = fs.lstatSync(resolvedPath);
|
|
19
|
+
if (lstat.isSymbolicLink()) {
|
|
20
|
+
throw new Error(`Session key cannot be a symlink: ${resolvedPath}`);
|
|
21
|
+
}
|
|
22
|
+
// Refuse to load key files with overly permissive permissions
|
|
23
|
+
const stats = fs.statSync(resolvedPath);
|
|
24
|
+
const mode = stats.mode & 0o777;
|
|
25
|
+
if (mode & 0o077) {
|
|
26
|
+
throw new Error(`Session key ${resolvedPath} has insecure permissions (${mode.toString(8)}). ` +
|
|
27
|
+
`Expected 0600. Fix with: chmod 600 ${resolvedPath}`);
|
|
28
|
+
}
|
|
29
|
+
const seed = fs.readFileSync(resolvedPath);
|
|
30
|
+
if (seed.length !== 32) {
|
|
31
|
+
throw new Error(`Invalid session key: expected 32 bytes, got ${seed.length}`);
|
|
32
|
+
}
|
|
33
|
+
return Ed25519KeyIdentity.generate(seed);
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`Session key not found. ` +
|
|
36
|
+
`Run 'pnpm dlx @engramx/client pair <invite-code> --engram <canister-id>' to create one.`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Create an Ed25519 identity from a raw 32-byte seed.
|
|
40
|
+
*/
|
|
41
|
+
export function identityFromSeed(seed) {
|
|
42
|
+
if (seed.length !== 32) {
|
|
43
|
+
throw new Error(`Invalid seed: expected 32 bytes, got ${seed.length}`);
|
|
44
|
+
}
|
|
45
|
+
return Ed25519KeyIdentity.generate(seed);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate a new session key and save it to disk.
|
|
49
|
+
* Returns the identity.
|
|
50
|
+
*/
|
|
51
|
+
export function generateSessionKey(keyPath) {
|
|
52
|
+
const home = process.env['HOME'];
|
|
53
|
+
if (keyPath.startsWith('~') && !home)
|
|
54
|
+
throw new Error('HOME environment variable is not set');
|
|
55
|
+
const resolvedPath = keyPath.startsWith('~') ? path.join(home, keyPath.slice(1)) : keyPath;
|
|
56
|
+
const seed = crypto.randomBytes(32);
|
|
57
|
+
// Ensure parent directory exists
|
|
58
|
+
const dir = path.dirname(resolvedPath);
|
|
59
|
+
if (!fs.existsSync(dir)) {
|
|
60
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
61
|
+
}
|
|
62
|
+
fs.writeFileSync(resolvedPath, seed, { mode: 0o600 });
|
|
63
|
+
return Ed25519KeyIdentity.generate(seed);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC9F,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE5F,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,qCAAqC;QACrC,MAAM,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACzC,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,oCAAoC,YAAY,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,8DAA8D;QAC9D,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;QAChC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,eAAe,YAAY,8BAA8B,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK;gBAC5E,sCAAsC,YAAY,EAAE,CACvD,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,+CAA+C,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAChF,CAAC;QACD,OAAO,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,IAAI,KAAK,CACb,yBAAyB;QACvB,yFAAyF,CAC5F,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAgB;IAC/C,IAAI,IAAI,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC9F,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE5F,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAEpC,iCAAiC;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,OAAO,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { EngramClient } from './EngramClient';
|
|
2
|
+
export interface BootstrapConfig {
|
|
3
|
+
engram: {
|
|
4
|
+
canisterId: string;
|
|
5
|
+
sessionKeyPath: string;
|
|
6
|
+
host?: string;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Load config with remote overlay: reads local bootstrap config, then fetches
|
|
11
|
+
* the remote config from the engram (if available) and deep-merges them.
|
|
12
|
+
* Local values override remote values.
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadBootstrapConfig(localConfigPath: string): Promise<Record<string, any>>;
|
|
15
|
+
/**
|
|
16
|
+
* Save config to the engram's config/openclaw.json path. Owner-only operation —
|
|
17
|
+
* only succeeds when the caller's principal is the engram owner. Uses raw
|
|
18
|
+
* actor access since `writeMemory` is intentionally NOT exposed on the
|
|
19
|
+
* EngramClient SDK (operator hosts can't satisfy this).
|
|
20
|
+
*/
|
|
21
|
+
export declare function saveBootstrapConfig(client: EngramClient, config: object): Promise<void>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import { EngramClient } from './EngramClient';
|
|
3
|
+
/**
|
|
4
|
+
* Load config with remote overlay: reads local bootstrap config, then fetches
|
|
5
|
+
* the remote config from the engram (if available) and deep-merges them.
|
|
6
|
+
* Local values override remote values.
|
|
7
|
+
*/
|
|
8
|
+
export async function loadBootstrapConfig(localConfigPath) {
|
|
9
|
+
if (localConfigPath.startsWith('~') && !process.env['HOME']) {
|
|
10
|
+
throw new Error('HOME environment variable is not set');
|
|
11
|
+
}
|
|
12
|
+
const resolvedPath = localConfigPath.replace(/^~/, process.env['HOME'] || '');
|
|
13
|
+
let local;
|
|
14
|
+
try {
|
|
15
|
+
local = JSON.parse(fs.readFileSync(resolvedPath, 'utf-8'));
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
throw new Error(`Failed to load config from ${resolvedPath}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
19
|
+
}
|
|
20
|
+
const engram = local['engram'];
|
|
21
|
+
if (!engram?.['canisterId'] || !engram?.['sessionKeyPath']) {
|
|
22
|
+
return local;
|
|
23
|
+
}
|
|
24
|
+
const client = new EngramClient({
|
|
25
|
+
canisterId: engram['canisterId'],
|
|
26
|
+
sessionKeyPath: engram['sessionKeyPath'],
|
|
27
|
+
host: engram['host'],
|
|
28
|
+
});
|
|
29
|
+
try {
|
|
30
|
+
const remoteFile = await client.readMemory('config/openclaw.json');
|
|
31
|
+
const remote = JSON.parse(remoteFile.content);
|
|
32
|
+
return deepMerge(remote, local); // local overrides remote
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return local;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Save config to the engram's config/openclaw.json path. Owner-only operation —
|
|
40
|
+
* only succeeds when the caller's principal is the engram owner. Uses raw
|
|
41
|
+
* actor access since `writeMemory` is intentionally NOT exposed on the
|
|
42
|
+
* EngramClient SDK (operator hosts can't satisfy this).
|
|
43
|
+
*/
|
|
44
|
+
export async function saveBootstrapConfig(client, config) {
|
|
45
|
+
const ciphertext = new TextEncoder().encode(JSON.stringify(config, null, 2));
|
|
46
|
+
const actor = client.actor;
|
|
47
|
+
const result = await actor.writeMemory('config/openclaw.json', ciphertext);
|
|
48
|
+
if ('Err' in result)
|
|
49
|
+
throw new Error(result.Err);
|
|
50
|
+
}
|
|
51
|
+
const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
52
|
+
function deepMerge(base, override) {
|
|
53
|
+
const result = { ...base };
|
|
54
|
+
for (const key of Object.keys(override)) {
|
|
55
|
+
if (UNSAFE_KEYS.has(key))
|
|
56
|
+
continue;
|
|
57
|
+
if (override[key] !== null &&
|
|
58
|
+
typeof override[key] === 'object' &&
|
|
59
|
+
!Array.isArray(override[key]) &&
|
|
60
|
+
result[key] !== null &&
|
|
61
|
+
typeof result[key] === 'object' &&
|
|
62
|
+
!Array.isArray(result[key])) {
|
|
63
|
+
result[key] = deepMerge(result[key], override[key]);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
result[key] = override[key];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=bootstrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../src/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAU9C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,eAAuB;IAC/D,IAAI,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9E,IAAI,KAA0B,CAAC;IAC/B,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,8BAA8B,YAAY,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACjG,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAuC,CAAC;IACrE,IAAI,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAC3D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC;QAC9B,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC;QAChC,cAAc,EAAE,MAAM,CAAC,gBAAgB,CAAC;QACxC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC;KACrB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;QACnE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC9C,OAAO,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,yBAAyB;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAoB,EAAE,MAAc;IAC5E,MAAM,UAAU,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7E,MAAM,KAAK,GACT,MAKD,CAAC,KAAK,CAAC;IACR,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,sBAAsB,EAAE,UAAU,CAAC,CAAC;IAC3E,IAAI,KAAK,IAAI,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC;AAEvE,SAAS,SAAS,CAAC,IAAyB,EAAE,QAA6B;IACzE,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxC,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACnC,IACE,QAAQ,CAAC,GAAG,CAAC,KAAK,IAAI;YACtB,OAAO,QAAQ,CAAC,GAAG,CAAC,KAAK,QAAQ;YACjC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC7B,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI;YACpB,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ;YAC/B,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAC3B,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class LRUCache {
|
|
2
|
+
private cache;
|
|
3
|
+
private maxSize;
|
|
4
|
+
private defaultTTL;
|
|
5
|
+
constructor(maxSize?: number, defaultTTLMs?: number);
|
|
6
|
+
get<T>(key: string): T | undefined;
|
|
7
|
+
set(key: string, value: unknown, ttlMs?: number): void;
|
|
8
|
+
invalidate(key: string): void;
|
|
9
|
+
clear(): void;
|
|
10
|
+
get size(): number;
|
|
11
|
+
}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export class LRUCache {
|
|
2
|
+
constructor(maxSize = 100, defaultTTLMs = 60000) {
|
|
3
|
+
this.cache = new Map();
|
|
4
|
+
this.maxSize = maxSize;
|
|
5
|
+
this.defaultTTL = defaultTTLMs;
|
|
6
|
+
}
|
|
7
|
+
get(key) {
|
|
8
|
+
const entry = this.cache.get(key);
|
|
9
|
+
if (!entry)
|
|
10
|
+
return undefined;
|
|
11
|
+
if (Date.now() > entry.expiresAt) {
|
|
12
|
+
this.cache.delete(key);
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
this.cache.delete(key);
|
|
16
|
+
this.cache.set(key, entry);
|
|
17
|
+
return entry.value;
|
|
18
|
+
}
|
|
19
|
+
set(key, value, ttlMs) {
|
|
20
|
+
if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
|
|
21
|
+
const firstKey = this.cache.keys().next().value;
|
|
22
|
+
if (firstKey !== undefined) {
|
|
23
|
+
this.cache.delete(firstKey);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
this.cache.set(key, {
|
|
27
|
+
value,
|
|
28
|
+
expiresAt: Date.now() + (ttlMs ?? this.defaultTTL),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
invalidate(key) {
|
|
32
|
+
this.cache.delete(key);
|
|
33
|
+
}
|
|
34
|
+
clear() {
|
|
35
|
+
this.cache.clear();
|
|
36
|
+
}
|
|
37
|
+
get size() {
|
|
38
|
+
return this.cache.size;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAQ;IAKnB,YAAY,UAAkB,GAAG,EAAE,eAAuB,KAAM;QAJxD,UAAK,GAAG,IAAI,GAAG,EAAiD,CAAC;QAKvE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,YAAY,CAAC;IACjC,CAAC;IAED,GAAG,CAAI,GAAW;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAE7B,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,OAAO,KAAK,CAAC,KAAU,CAAC;IAC1B,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAc,EAAE,KAAc;QAC7C,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAChD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE;YAClB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,UAAU,CAAC;SACnD,CAAC,CAAC;IACL,CAAC;IAED,UAAU,CAAC,GAAW;QACpB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude setup — generates MCP config for Claude Code and Claude Cowork.
|
|
3
|
+
*/
|
|
4
|
+
export interface ClaudeSetupOptions {
|
|
5
|
+
canisterId: string;
|
|
6
|
+
sessionKeyPath: string;
|
|
7
|
+
host?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface McpConfig {
|
|
10
|
+
mcpServers: {
|
|
11
|
+
engramx: {
|
|
12
|
+
command: string;
|
|
13
|
+
args: string[];
|
|
14
|
+
env: Record<string, string>;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** Generate the MCP server config block for Claude. */
|
|
19
|
+
export declare function generateMcpConfig(options: ClaudeSetupOptions): McpConfig;
|
|
20
|
+
/** Return the config paths for each Claude product. */
|
|
21
|
+
export declare function claudeConfigPaths(): {
|
|
22
|
+
claudeCode: string;
|
|
23
|
+
claudeDesktop: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Install the MCP config into a Claude config file.
|
|
27
|
+
* Merges the engramx entry into the existing mcpServers, preserving other servers.
|
|
28
|
+
*/
|
|
29
|
+
export declare function installMcpConfig(configPath: string, options: ClaudeSetupOptions): void;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude setup — generates MCP config for Claude Code and Claude Cowork.
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
/** Generate the MCP server config block for Claude. */
|
|
7
|
+
export function generateMcpConfig(options) {
|
|
8
|
+
const env = {
|
|
9
|
+
ENGRAM_CANISTER_ID: options.canisterId,
|
|
10
|
+
ENGRAM_SESSION_KEY_PATH: options.sessionKeyPath,
|
|
11
|
+
};
|
|
12
|
+
if (options.host && options.host !== 'https://ic0.app') {
|
|
13
|
+
env['ENGRAM_HOST'] = options.host;
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
mcpServers: {
|
|
17
|
+
engramx: {
|
|
18
|
+
command: 'npx',
|
|
19
|
+
args: ['-y', '@engramx/mcp'],
|
|
20
|
+
env,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/** Return the config paths for each Claude product. */
|
|
26
|
+
export function claudeConfigPaths() {
|
|
27
|
+
const home = process.env['HOME'] || '';
|
|
28
|
+
return {
|
|
29
|
+
claudeCode: path.join(home, '.claude', 'settings.json'),
|
|
30
|
+
claudeDesktop: path.join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Install the MCP config into a Claude config file.
|
|
35
|
+
* Merges the engramx entry into the existing mcpServers, preserving other servers.
|
|
36
|
+
*/
|
|
37
|
+
export function installMcpConfig(configPath, options) {
|
|
38
|
+
const mcpBlock = generateMcpConfig(options);
|
|
39
|
+
const resolvedPath = configPath.startsWith('~')
|
|
40
|
+
? path.join(process.env['HOME'] || '', configPath.slice(1))
|
|
41
|
+
: configPath;
|
|
42
|
+
let existing = {};
|
|
43
|
+
if (fs.existsSync(resolvedPath)) {
|
|
44
|
+
existing = JSON.parse(fs.readFileSync(resolvedPath, 'utf-8'));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const dir = path.dirname(resolvedPath);
|
|
48
|
+
if (!fs.existsSync(dir)) {
|
|
49
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const servers = existing['mcpServers'] || {};
|
|
53
|
+
servers['engramx'] = mcpBlock.mcpServers.engramx;
|
|
54
|
+
existing['mcpServers'] = servers;
|
|
55
|
+
fs.writeFileSync(resolvedPath, JSON.stringify(existing, null, 2) + '\n');
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=claude-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-setup.js","sourceRoot":"","sources":["../src/claude-setup.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAkB7B,uDAAuD;AACvD,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,MAAM,GAAG,GAA2B;QAClC,kBAAkB,EAAE,OAAO,CAAC,UAAU;QACtC,uBAAuB,EAAE,OAAO,CAAC,cAAc;KAChD,CAAC;IACF,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QACvD,GAAG,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IACpC,CAAC;IAED,OAAO;QACL,UAAU,EAAE;YACV,OAAO,EAAE;gBACP,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,CAAC,IAAI,EAAE,cAAc,CAAC;gBAC5B,GAAG;aACJ;SACF;KACF,CAAC;AACJ,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvC,OAAO;QACL,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,CAAC;QACvD,aAAa,EAAE,IAAI,CAAC,IAAI,CACtB,IAAI,EACJ,SAAS,EACT,qBAAqB,EACrB,QAAQ,EACR,4BAA4B,CAC7B;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,OAA2B;IAC9E,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC;QAC7C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC,UAAU,CAAC;IAEf,IAAI,QAAQ,GAA4B,EAAE,CAAC;IAC3C,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAI,QAAQ,CAAC,YAAY,CAA6B,IAAI,EAAE,CAAC;IAC1E,OAAO,CAAC,SAAS,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC;IACjD,QAAQ,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC;IAEjC,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3E,CAAC"}
|
package/dist/cli.d.ts
ADDED