@sonzai-labs/openclaw-context 1.0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sonzai Labs
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,220 @@
1
+ # @sonzai-labs/openclaw-context
2
+
3
+ OpenClaw ContextEngine plugin for the [Sonzai Mind Layer](https://sonz.ai). Gives OpenClaw agents hierarchical memory, personality evolution, mood tracking, relationship modeling, and automatic fact extraction — powered by the Sonzai API.
4
+
5
+ ## Quick Start
6
+
7
+ ### Interactive Setup (Recommended)
8
+
9
+ ```bash
10
+ # Install the plugin
11
+ openclaw plugins install @sonzai-labs/openclaw-context
12
+
13
+ # Run guided setup — validates your key, provisions agent, writes openclaw.json
14
+ npx @sonzai-labs/openclaw-context setup
15
+ ```
16
+
17
+ The setup wizard will:
18
+ 1. Ask for your Sonzai API key (or detect `SONZAI_API_KEY` from env)
19
+ 2. Ask if you have an existing agent ID, or create one for you
20
+ 3. Write the plugin config to your `openclaw.json`
21
+ 4. Show you the env var to add to your shell profile
22
+
23
+ That's it — restart OpenClaw and your agent has persistent memory.
24
+
25
+ ### Manual Setup
26
+
27
+ ```bash
28
+ # 1. Install
29
+ openclaw plugins install @sonzai-labs/openclaw-context
30
+
31
+ # 2. Set your API key
32
+ export SONZAI_API_KEY="sk-your-api-key"
33
+
34
+ # 3. Optionally set a specific agent (otherwise auto-provisioned)
35
+ export SONZAI_AGENT_ID="your-agent-uuid"
36
+ ```
37
+
38
+ Add to your `openclaw.json`:
39
+
40
+ ```json5
41
+ {
42
+ "plugins": {
43
+ "slots": {
44
+ "contextEngine": "sonzai"
45
+ },
46
+ "entries": {
47
+ "sonzai": {
48
+ "enabled": true,
49
+ "agentId": "your-agent-uuid" // optional
50
+ }
51
+ }
52
+ }
53
+ }
54
+ ```
55
+
56
+ ## B2B Integration (Programmatic Setup)
57
+
58
+ For platforms deploying OpenClaw at scale, use the programmatic setup API
59
+ in your provisioning scripts:
60
+
61
+ ```typescript
62
+ import { setup } from "@sonzai-labs/openclaw-context";
63
+
64
+ // One-liner: validates key, provisions agent, writes openclaw.json
65
+ const result = await setup({
66
+ apiKey: "sk-project-scoped-key",
67
+ agentName: "customer-support-bot", // stable name → deterministic agent ID
68
+ configPath: "/path/to/openclaw.json",
69
+ });
70
+
71
+ console.log(result.agentId); // "a1b2c3d4-..."
72
+ console.log(result.written); // true — config file updated
73
+ ```
74
+
75
+ ### B2B Provisioning Script Example
76
+
77
+ ```typescript
78
+ import { setup } from "@sonzai-labs/openclaw-context";
79
+
80
+ // Called once per tenant during onboarding
81
+ async function provisionOpenClawForTenant(tenantName: string) {
82
+ const result = await setup({
83
+ apiKey: process.env.SONZAI_PROJECT_KEY!,
84
+ agentName: `${tenantName}-assistant`, // unique per tenant
85
+ configPath: `/etc/openclaw/${tenantName}/openclaw.json`,
86
+ });
87
+
88
+ // Store the agent ID in your DB for reference
89
+ await db.tenants.update(tenantName, { sonzaiAgentId: result.agentId });
90
+ }
91
+ ```
92
+
93
+ ### Kubernetes / Docker Deployments
94
+
95
+ The agent ID is deterministic: `SHA1(tenantID + agentName)`. As long as your
96
+ config has the same API key + agent name (or explicit agent ID), pods can
97
+ restart, scale, or be replaced without creating duplicate agents.
98
+
99
+ ```yaml
100
+ # Example: K8s deployment env vars
101
+ env:
102
+ - name: SONZAI_API_KEY
103
+ valueFrom:
104
+ secretKeyRef:
105
+ name: sonzai-secrets
106
+ key: api-key
107
+ - name: SONZAI_AGENT_ID
108
+ value: "a1b2c3d4-e5f6-..." # from provisioning step
109
+ ```
110
+
111
+ ### Config-Only (No Env Vars)
112
+
113
+ If you prefer not to use env vars, pass everything through `openclaw.json`:
114
+
115
+ ```typescript
116
+ const result = await setup({
117
+ apiKey: "sk-...",
118
+ agentName: "my-bot",
119
+ writeConfig: true,
120
+ configPath: "./openclaw.json",
121
+ });
122
+ // API key is NOT written to the file (security) — only agentId is persisted.
123
+ // The key must be set via SONZAI_API_KEY at runtime.
124
+ ```
125
+
126
+ ## How It Works
127
+
128
+ The plugin replaces OpenClaw's default Markdown-file memory with Sonzai's Mind Layer:
129
+
130
+ | OpenClaw Hook | What Happens |
131
+ |---------------|-------------|
132
+ | **bootstrap** | Starts a Sonzai session; provisions agent if needed |
133
+ | **ingest** | No-op (processing deferred to afterTurn) |
134
+ | **assemble** | Fetches memory, mood, personality, relationships, goals, interests, and habits in parallel; injects as `systemPromptAddition` |
135
+ | **compact** | Triggers Sonzai's consolidation pipeline (replaces OpenClaw's summarization) |
136
+ | **afterTurn** | Sends conversation to Sonzai for fact extraction |
137
+ | **dispose** | Ends all active sessions cleanly |
138
+
139
+ ### Context Injection
140
+
141
+ Before each LLM call, the plugin injects a `<sonzai-context>` block into the system prompt containing:
142
+
143
+ - Agent personality profile and Big5 traits
144
+ - Current mood state
145
+ - Relationship data with the current user
146
+ - Semantically relevant memories (searched by last user message)
147
+ - Active goals
148
+ - User interests
149
+ - Behavioral habits
150
+
151
+ If any API call fails, it's silently skipped — the plugin never blocks OpenClaw.
152
+
153
+ ### User Identity
154
+
155
+ The plugin automatically extracts user identity from OpenClaw session keys:
156
+
157
+ | Session Type | Example Key | Resolved userId |
158
+ |-------------|------------|-----------------|
159
+ | CLI (1:1) | `agent:abc:mainKey` | `"owner"` (default) |
160
+ | Telegram DM | `agent:abc:telegram:direct:123` | `"123"` |
161
+ | WhatsApp DM | `agent:abc:whatsapp:direct:+1555...` | `"+1555..."` |
162
+ | Discord group | `agent:abc:discord:group:guild789` | `"guild789"` |
163
+
164
+ ### Agent ID Stability
165
+
166
+ The Sonzai backend derives agent IDs deterministically:
167
+
168
+ ```
169
+ agentId = SHA1(namespace, tenantID + "/" + lowercase(agentName))
170
+ ```
171
+
172
+ Same API key + same name = same agent UUID, always. Safe across:
173
+ - Pod restarts and replacements
174
+ - Container recreation
175
+ - Multiple replicas (they all resolve to the same agent)
176
+ - `openclaw plugins install` re-runs
177
+
178
+ To get **separate** agents under one API key, use different `agentName` values.
179
+
180
+ ## Full Configuration Reference
181
+
182
+ | Setting | Env Var | Default | Description |
183
+ |---------|---------|---------|-------------|
184
+ | `apiKey` | `SONZAI_API_KEY` | *required* | Sonzai API key |
185
+ | `agentId` | `SONZAI_AGENT_ID` | auto-provision | Pre-provisioned agent UUID |
186
+ | `baseUrl` | `SONZAI_BASE_URL` | `https://api.sonz.ai` | API base URL |
187
+ | `agentName` | `SONZAI_AGENT_NAME` | `openclaw-agent` | Name for auto-provisioned agents |
188
+ | `defaultUserId` | — | `owner` | Default userId for CLI (1:1) sessions |
189
+ | `contextTokenBudget` | — | `2000` | Max tokens for context injection |
190
+ | `disable.mood` | — | `false` | Skip mood context |
191
+ | `disable.personality` | — | `false` | Skip personality context |
192
+ | `disable.relationships` | — | `false` | Skip relationship context |
193
+ | `disable.memory` | — | `false` | Skip memory search |
194
+ | `disable.goals` | — | `false` | Skip goals context |
195
+ | `disable.interests` | — | `false` | Skip interests context |
196
+ | `disable.habits` | — | `false` | Skip habits context |
197
+
198
+ ## Programmatic Engine Usage
199
+
200
+ The engine can also be used directly outside OpenClaw:
201
+
202
+ ```typescript
203
+ import { Sonzai } from "@sonzai-labs/agents";
204
+ import { SonzaiContextEngine, resolveConfig } from "@sonzai-labs/openclaw-context";
205
+
206
+ const client = new Sonzai({ apiKey: "sk-..." });
207
+ const config = resolveConfig({ apiKey: "sk-...", agentId: "agent-123" });
208
+ const engine = new SonzaiContextEngine(client, config);
209
+
210
+ await engine.bootstrap({ sessionId: "my-session" });
211
+ const { systemPromptAddition } = await engine.assemble({
212
+ sessionId: "my-session",
213
+ messages: [{ role: "user", content: "Hello!" }],
214
+ tokenBudget: 4000,
215
+ });
216
+ ```
217
+
218
+ ## License
219
+
220
+ MIT
package/dist/cli.cjs ADDED
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var agents = require('@sonzai-labs/agents');
5
+ var readline = require('readline');
6
+ var fs = require('fs');
7
+ var path = require('path');
8
+
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
28
+ var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
29
+ var path__namespace = /*#__PURE__*/_interopNamespace(path);
30
+
31
+ async function setup(options) {
32
+ const baseUrl = options.baseUrl || "https://api.sonz.ai";
33
+ const agentName = options.agentName || "openclaw-agent";
34
+ const configPath = options.configPath || "./openclaw.json";
35
+ const client = new agents.Sonzai({ apiKey: options.apiKey, baseUrl });
36
+ let agentId;
37
+ if (options.agentId) {
38
+ const agent = await client.agents.get(options.agentId);
39
+ agentId = agent.agent_id;
40
+ } else {
41
+ const agent = await client.agents.create({ name: agentName });
42
+ agentId = agent.agent_id;
43
+ }
44
+ const pluginConfig = buildOpenClawConfig(options.apiKey, agentId);
45
+ let written = false;
46
+ return {
47
+ agentId,
48
+ agentName,
49
+ config: pluginConfig,
50
+ configPath: written ? path__namespace.resolve(configPath) : void 0,
51
+ written
52
+ };
53
+ }
54
+ async function interactiveSetup() {
55
+ const rl = readline__namespace.createInterface({
56
+ input: process.stdin,
57
+ output: process.stdout
58
+ });
59
+ const ask = (question) => new Promise((resolve2) => rl.question(question, resolve2));
60
+ console.log("\n\u{1F99E} Sonzai Mind Layer \u2014 OpenClaw Plugin Setup\n");
61
+ try {
62
+ const envKey = process.env.SONZAI_API_KEY;
63
+ let apiKey;
64
+ if (envKey) {
65
+ const useEnv = await ask(
66
+ `Found SONZAI_API_KEY in environment (${envKey.slice(0, 8)}...). Use it? [Y/n] `
67
+ );
68
+ apiKey = useEnv.toLowerCase() === "n" ? await ask("Enter your Sonzai API key: ") : envKey;
69
+ } else {
70
+ apiKey = await ask("Enter your Sonzai API key (from https://sonz.ai/settings/api): ");
71
+ }
72
+ if (!apiKey.trim()) {
73
+ console.log("No API key provided. Aborting.");
74
+ return;
75
+ }
76
+ const hasAgent = await ask("Do you have an existing Sonzai agent ID? [y/N] ");
77
+ let agentId;
78
+ let agentName = "openclaw-agent";
79
+ if (hasAgent.toLowerCase() === "y") {
80
+ agentId = await ask("Enter agent ID: ");
81
+ } else {
82
+ const customName = await ask(
83
+ `Agent name for auto-provisioning [openclaw-agent]: `
84
+ );
85
+ if (customName.trim()) agentName = customName.trim();
86
+ }
87
+ console.log("\nValidating API key and provisioning agent...");
88
+ const result = await setup({
89
+ apiKey: apiKey.trim(),
90
+ agentId: agentId?.trim() || void 0,
91
+ agentName,
92
+ writeConfig: false
93
+ });
94
+ console.log(`Agent ready: ${result.agentId}`);
95
+ const configPath = await ask("Path to openclaw.json [./openclaw.json]: ");
96
+ const resolvedPath = configPath.trim() || "./openclaw.json";
97
+ mergeOpenClawConfig(resolvedPath, result.config);
98
+ console.log(`
99
+ Config written to ${path__namespace.resolve(resolvedPath)}`);
100
+ console.log("\n--- Setup Complete ---\n");
101
+ console.log("Set your API key as an environment variable (recommended):\n");
102
+ console.log(` export SONZAI_API_KEY="${apiKey.trim()}"
103
+ `);
104
+ console.log("Or add it to your shell profile (~/.bashrc, ~/.zshrc).\n");
105
+ console.log(
106
+ "The agent ID is saved in openclaw.json \u2014 no need to set SONZAI_AGENT_ID.\n"
107
+ );
108
+ } finally {
109
+ rl.close();
110
+ }
111
+ }
112
+ function buildOpenClawConfig(_apiKey, agentId) {
113
+ return {
114
+ plugins: {
115
+ slots: {
116
+ contextEngine: "sonzai"
117
+ },
118
+ entries: {
119
+ sonzai: {
120
+ enabled: true,
121
+ agentId
122
+ // apiKey is intentionally NOT written to the config file —
123
+ // it should be set via SONZAI_API_KEY env var for security.
124
+ }
125
+ }
126
+ }
127
+ };
128
+ }
129
+ function mergeOpenClawConfig(configPath, pluginConfig) {
130
+ let existing = {};
131
+ const resolvedPath = path__namespace.resolve(configPath);
132
+ if (fs__namespace.existsSync(resolvedPath)) {
133
+ try {
134
+ const raw = fs__namespace.readFileSync(resolvedPath, "utf-8");
135
+ existing = JSON.parse(raw);
136
+ } catch {
137
+ }
138
+ }
139
+ const merged = { ...existing };
140
+ const existingPlugins = merged.plugins || {};
141
+ const newPlugins = pluginConfig.plugins;
142
+ const existingSlots = existingPlugins.slots || {};
143
+ const newSlots = newPlugins.slots || {};
144
+ const existingEntries = existingPlugins.entries || {};
145
+ const newEntries = newPlugins.entries || {};
146
+ merged.plugins = {
147
+ ...existingPlugins,
148
+ slots: { ...existingSlots, ...newSlots },
149
+ entries: { ...existingEntries, ...newEntries }
150
+ };
151
+ fs__namespace.writeFileSync(resolvedPath, JSON.stringify(merged, null, 2) + "\n");
152
+ }
153
+ async function main() {
154
+ const command = process.argv[2];
155
+ if (command === "setup") {
156
+ await interactiveSetup();
157
+ } else {
158
+ console.log("Usage: npx @sonzai-labs/openclaw-context setup");
159
+ console.log("\nRun interactive setup to configure the Sonzai OpenClaw plugin.");
160
+ }
161
+ }
162
+
163
+ // src/cli.ts
164
+ main().catch((err) => {
165
+ console.error(err);
166
+ process.exit(1);
167
+ });
168
+ //# sourceMappingURL=cli.cjs.map
169
+ //# sourceMappingURL=cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/setup.ts","../src/cli.ts"],"names":["Sonzai","path","readline","resolve","fs"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,eAAsB,MAAM,OAAA,EAA6C;AACvE,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,qBAAA;AACnC,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,gBAAA;AAEvC,EAAA,MAAM,UAAA,GAAa,QAAQ,UAAA,IAAc,iBAAA;AAGzC,EAAA,MAAM,MAAA,GAAS,IAAIA,aAAA,CAAO,EAAE,QAAQ,OAAA,CAAQ,MAAA,EAAQ,SAAS,CAAA;AAE7D,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,QAAQ,OAAA,EAAS;AAEnB,IAAA,MAAM,QAAQ,MAAM,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,QAAQ,OAAO,CAAA;AACrD,IAAA,OAAA,GAAU,KAAA,CAAM,QAAA;AAAA,EAClB,CAAA,MAAO;AAEL,IAAA,MAAM,KAAA,GAAQ,MAAM,MAAA,CAAO,MAAA,CAAO,OAAO,EAAE,IAAA,EAAM,WAAW,CAAA;AAC5D,IAAA,OAAA,GAAU,KAAA,CAAM,QAAA;AAAA,EAClB;AAGA,EAAA,MAAM,YAAA,GAAe,mBAAA,CAAoB,OAAA,CAAQ,MAAA,EAAQ,OAAO,CAAA;AAGhE,EAAA,IAAI,OAAA,GAAU,KAAA;AAMd,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,SAAA;AAAA,IACA,MAAA,EAAQ,YAAA;AAAA,IACR,UAAA,EAAY,OAAA,GAAeC,eAAA,CAAA,OAAA,CAAQ,UAAU,CAAA,GAAI,MAAA;AAAA,IACjD;AAAA,GACF;AACF;AAMA,eAAsB,gBAAA,GAAkC;AACtD,EAAA,MAAM,KAAcC,mBAAA,CAAA,eAAA,CAAgB;AAAA,IAClC,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,QAAQ,OAAA,CAAQ;AAAA,GACjB,CAAA;AAED,EAAA,MAAM,GAAA,GAAM,CAAC,QAAA,KACX,IAAI,OAAA,CAAQ,CAACC,QAAAA,KAAY,EAAA,CAAG,QAAA,CAAS,QAAA,EAAUA,QAAO,CAAC,CAAA;AAEzD,EAAA,OAAA,CAAQ,IAAI,8DAAkD,CAAA;AAE9D,EAAA,IAAI;AAEF,IAAA,MAAM,MAAA,GAAS,QAAQ,GAAA,CAAI,cAAA;AAC3B,IAAA,IAAI,MAAA;AACJ,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAM,SAAS,MAAM,GAAA;AAAA,QACnB,CAAA,qCAAA,EAAwC,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,CAAC,CAAC,CAAA,oBAAA;AAAA,OAC5D;AACA,MAAA,MAAA,GAAS,OAAO,WAAA,EAAY,KAAM,MAAM,MAAM,GAAA,CAAI,6BAA6B,CAAA,GAAI,MAAA;AAAA,IACrF,CAAA,MAAO;AACL,MAAA,MAAA,GAAS,MAAM,IAAI,iEAAiE,CAAA;AAAA,IACtF;AAEA,IAAA,IAAI,CAAC,MAAA,CAAO,IAAA,EAAK,EAAG;AAClB,MAAA,OAAA,CAAQ,IAAI,gCAAgC,CAAA;AAC5C,MAAA;AAAA,IACF;AAGA,IAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,iDAAiD,CAAA;AAC5E,IAAA,IAAI,OAAA;AACJ,IAAA,IAAI,SAAA,GAAY,gBAAA;AAEhB,IAAA,IAAI,QAAA,CAAS,WAAA,EAAY,KAAM,GAAA,EAAK;AAClC,MAAA,OAAA,GAAU,MAAM,IAAI,kBAAkB,CAAA;AAAA,IACxC,CAAA,MAAO;AACL,MAAA,MAAM,aAAa,MAAM,GAAA;AAAA,QACvB,CAAA,mDAAA;AAAA,OACF;AACA,MAAA,IAAI,UAAA,CAAW,IAAA,EAAK,EAAG,SAAA,GAAY,WAAW,IAAA,EAAK;AAAA,IACrD;AAGA,IAAA,OAAA,CAAQ,IAAI,gDAAgD,CAAA;AAC5D,IAAA,MAAM,MAAA,GAAS,MAAM,KAAA,CAAM;AAAA,MACzB,MAAA,EAAQ,OAAO,IAAA,EAAK;AAAA,MACpB,OAAA,EAAS,OAAA,EAAS,IAAA,EAAK,IAAK,KAAA,CAAA;AAAA,MAC5B,SAAA;AAAA,MACA,WAAA,EAAa;AAAA,KACd,CAAA;AACD,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,aAAA,EAAgB,MAAA,CAAO,OAAO,CAAA,CAAE,CAAA;AAG5C,IAAA,MAAM,UAAA,GAAa,MAAM,GAAA,CAAI,2CAA2C,CAAA;AACxE,IAAA,MAAM,YAAA,GAAe,UAAA,CAAW,IAAA,EAAK,IAAK,iBAAA;AAE1C,IAAA,mBAAA,CAAoB,YAAA,EAAc,OAAO,MAAM,CAAA;AAC/C,IAAA,OAAA,CAAQ,GAAA,CAAI;AAAA,kBAAA,EAA4BF,eAAA,CAAA,OAAA,CAAQ,YAAY,CAAC,CAAA,CAAE,CAAA;AAG/D,IAAA,OAAA,CAAQ,IAAI,4BAA4B,CAAA;AACxC,IAAA,OAAA,CAAQ,IAAI,8DAA8D,CAAA;AAC1E,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,yBAAA,EAA4B,MAAA,CAAO,IAAA,EAAM,CAAA;AAAA,CAAK,CAAA;AAC1D,IAAA,OAAA,CAAQ,IAAI,0DAA0D,CAAA;AACtE,IAAA,OAAA,CAAQ,GAAA;AAAA,MACN;AAAA,KACF;AAAA,EACF,CAAA,SAAE;AACA,IAAA,EAAA,CAAG,KAAA,EAAM;AAAA,EACX;AACF;AAMA,SAAS,mBAAA,CACP,SACA,OAAA,EACyB;AACzB,EAAA,OAAO;AAAA,IACL,OAAA,EAAS;AAAA,MACP,KAAA,EAAO;AAAA,QACL,aAAA,EAAe;AAAA,OACjB;AAAA,MACA,OAAA,EAAS;AAAA,QACP,MAAA,EAAQ;AAAA,UACN,OAAA,EAAS,IAAA;AAAA,UACT;AAAA;AAAA;AAAA;AAGF;AACF;AACF,GACF;AACF;AAEA,SAAS,mBAAA,CACP,YACA,YAAA,EACM;AACN,EAAA,IAAI,WAAoC,EAAC;AAEzC,EAAA,MAAM,YAAA,GAAoBA,wBAAQ,UAAU,CAAA;AAC5C,EAAA,IAAOG,aAAA,CAAA,UAAA,CAAW,YAAY,CAAA,EAAG;AAC/B,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAASA,aAAA,CAAA,YAAA,CAAa,YAAA,EAAc,OAAO,CAAA;AACjD,MAAA,QAAA,GAAW,IAAA,CAAK,MAAM,GAAG,CAAA;AAAA,IAC3B,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAGA,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,QAAA,EAAS;AAC7B,EAAA,MAAM,eAAA,GAAmB,MAAA,CAAO,OAAA,IAAW,EAAC;AAC5C,EAAA,MAAM,aAAa,YAAA,CAAa,OAAA;AAEhC,EAAA,MAAM,aAAA,GAAiB,eAAA,CAAgB,KAAA,IAAS,EAAC;AACjD,EAAA,MAAM,QAAA,GAAY,UAAA,CAAW,KAAA,IAAS,EAAC;AAEvC,EAAA,MAAM,eAAA,GAAmB,eAAA,CAAgB,OAAA,IAAW,EAAC;AACrD,EAAA,MAAM,UAAA,GAAc,UAAA,CAAW,OAAA,IAAW,EAAC;AAE3C,EAAA,MAAA,CAAO,OAAA,GAAU;AAAA,IACf,GAAG,eAAA;AAAA,IACH,KAAA,EAAO,EAAE,GAAG,aAAA,EAAe,GAAG,QAAA,EAAS;AAAA,IACvC,OAAA,EAAS,EAAE,GAAG,eAAA,EAAiB,GAAG,UAAA;AAAW,GAC/C;AAEA,EAAGA,aAAA,CAAA,aAAA,CAAc,cAAc,IAAA,CAAK,SAAA,CAAU,QAAQ,IAAA,EAAM,CAAC,IAAI,IAAI,CAAA;AACvE;AAOA,eAAsB,IAAA,GAAsB;AAC1C,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA;AAE9B,EAAA,IAAI,YAAY,OAAA,EAAS;AACvB,IAAA,MAAM,gBAAA,EAAiB;AAAA,EACzB,CAAA,MAAO;AACL,IAAA,OAAA,CAAQ,IAAI,gDAAgD,CAAA;AAC5D,IAAA,OAAA,CAAQ,IAAI,kEAAkE,CAAA;AAAA,EAChF;AACF;;;ACxOA,IAAA,EAAK,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AACpB,EAAA,OAAA,CAAQ,MAAM,GAAG,CAAA;AACjB,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAChB,CAAC,CAAA","file":"cli.cjs","sourcesContent":["/**\n * Interactive and programmatic setup for the Sonzai OpenClaw plugin.\n *\n * Interactive: `npx @sonzai-labs/openclaw-context setup`\n * Programmatic: `import { setup } from \"@sonzai-labs/openclaw-context\"`\n */\n\nimport { Sonzai } from \"@sonzai-labs/agents\";\nimport * as readline from \"node:readline\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n// ---------------------------------------------------------------------------\n// Programmatic setup — for B2B integrations\n// ---------------------------------------------------------------------------\n\nexport interface SetupOptions {\n /** Sonzai API key. */\n apiKey: string;\n /** Agent name (deterministic ID derived from tenant + name). */\n agentName?: string;\n /** Pre-existing agent ID (skips agent provisioning). */\n agentId?: string;\n /** Base URL override. */\n baseUrl?: string;\n /** Path to openclaw.json. Defaults to ./openclaw.json */\n configPath?: string;\n /** If true, writes to openclaw.json. If false, returns config object only. */\n writeConfig?: boolean;\n}\n\nexport interface SetupResult {\n agentId: string;\n agentName: string;\n config: Record<string, unknown>;\n configPath?: string;\n written: boolean;\n}\n\n/**\n * Programmatic setup — validates API key, provisions agent, optionally\n * writes openclaw.json. Designed for B2B automation scripts.\n */\nexport async function setup(options: SetupOptions): Promise<SetupResult> {\n const baseUrl = options.baseUrl || \"https://api.sonz.ai\";\n const agentName = options.agentName || \"openclaw-agent\";\n const writeConfig = options.writeConfig ?? true;\n const configPath = options.configPath || \"./openclaw.json\";\n\n // 1. Validate API key by provisioning / finding the agent\n const client = new Sonzai({ apiKey: options.apiKey, baseUrl });\n\n let agentId: string;\n if (options.agentId) {\n // Verify agent exists\n const agent = await client.agents.get(options.agentId);\n agentId = agent.agent_id;\n } else {\n // Idempotent create — backend derives deterministic UUID from tenant+name\n const agent = await client.agents.create({ name: agentName });\n agentId = agent.agent_id;\n }\n\n // 2. Build the openclaw.json plugin config\n const pluginConfig = buildOpenClawConfig(options.apiKey, agentId);\n\n // 3. Optionally write to openclaw.json\n let written = false;\n if (writeConfig) {\n mergeOpenClawConfig(configPath, pluginConfig);\n written = true;\n }\n\n return {\n agentId,\n agentName,\n config: pluginConfig,\n configPath: written ? path.resolve(configPath) : undefined,\n written,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Interactive CLI setup — `npx @sonzai-labs/openclaw-context setup`\n// ---------------------------------------------------------------------------\n\nexport async function interactiveSetup(): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const ask = (question: string): Promise<string> =>\n new Promise((resolve) => rl.question(question, resolve));\n\n console.log(\"\\n🦞 Sonzai Mind Layer — OpenClaw Plugin Setup\\n\");\n\n try {\n // Step 1: API Key\n const envKey = process.env.SONZAI_API_KEY;\n let apiKey: string;\n if (envKey) {\n const useEnv = await ask(\n `Found SONZAI_API_KEY in environment (${envKey.slice(0, 8)}...). Use it? [Y/n] `,\n );\n apiKey = useEnv.toLowerCase() === \"n\" ? await ask(\"Enter your Sonzai API key: \") : envKey;\n } else {\n apiKey = await ask(\"Enter your Sonzai API key (from https://sonz.ai/settings/api): \");\n }\n\n if (!apiKey.trim()) {\n console.log(\"No API key provided. Aborting.\");\n return;\n }\n\n // Step 2: Agent\n const hasAgent = await ask(\"Do you have an existing Sonzai agent ID? [y/N] \");\n let agentId: string | undefined;\n let agentName = \"openclaw-agent\";\n\n if (hasAgent.toLowerCase() === \"y\") {\n agentId = await ask(\"Enter agent ID: \");\n } else {\n const customName = await ask(\n `Agent name for auto-provisioning [openclaw-agent]: `,\n );\n if (customName.trim()) agentName = customName.trim();\n }\n\n // Step 3: Validate\n console.log(\"\\nValidating API key and provisioning agent...\");\n const result = await setup({\n apiKey: apiKey.trim(),\n agentId: agentId?.trim() || undefined,\n agentName,\n writeConfig: false,\n });\n console.log(`Agent ready: ${result.agentId}`);\n\n // Step 4: Write config\n const configPath = await ask(\"Path to openclaw.json [./openclaw.json]: \");\n const resolvedPath = configPath.trim() || \"./openclaw.json\";\n\n mergeOpenClawConfig(resolvedPath, result.config);\n console.log(`\\nConfig written to ${path.resolve(resolvedPath)}`);\n\n // Step 5: Env var hint\n console.log(\"\\n--- Setup Complete ---\\n\");\n console.log(\"Set your API key as an environment variable (recommended):\\n\");\n console.log(` export SONZAI_API_KEY=\"${apiKey.trim()}\"\\n`);\n console.log(\"Or add it to your shell profile (~/.bashrc, ~/.zshrc).\\n\");\n console.log(\n \"The agent ID is saved in openclaw.json — no need to set SONZAI_AGENT_ID.\\n\",\n );\n } finally {\n rl.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction buildOpenClawConfig(\n _apiKey: string,\n agentId: string,\n): Record<string, unknown> {\n return {\n plugins: {\n slots: {\n contextEngine: \"sonzai\",\n },\n entries: {\n sonzai: {\n enabled: true,\n agentId,\n // apiKey is intentionally NOT written to the config file —\n // it should be set via SONZAI_API_KEY env var for security.\n },\n },\n },\n };\n}\n\nfunction mergeOpenClawConfig(\n configPath: string,\n pluginConfig: Record<string, unknown>,\n): void {\n let existing: Record<string, unknown> = {};\n\n const resolvedPath = path.resolve(configPath);\n if (fs.existsSync(resolvedPath)) {\n try {\n const raw = fs.readFileSync(resolvedPath, \"utf-8\");\n existing = JSON.parse(raw);\n } catch {\n // If parse fails, start fresh\n }\n }\n\n // Deep merge plugins section\n const merged = { ...existing };\n const existingPlugins = (merged.plugins || {}) as Record<string, unknown>;\n const newPlugins = pluginConfig.plugins as Record<string, unknown>;\n\n const existingSlots = (existingPlugins.slots || {}) as Record<string, unknown>;\n const newSlots = (newPlugins.slots || {}) as Record<string, unknown>;\n\n const existingEntries = (existingPlugins.entries || {}) as Record<string, unknown>;\n const newEntries = (newPlugins.entries || {}) as Record<string, unknown>;\n\n merged.plugins = {\n ...existingPlugins,\n slots: { ...existingSlots, ...newSlots },\n entries: { ...existingEntries, ...newEntries },\n };\n\n fs.writeFileSync(resolvedPath, JSON.stringify(merged, null, 2) + \"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// CLI entry point\n// ---------------------------------------------------------------------------\n\n/** Run when invoked as `npx @sonzai-labs/openclaw-context setup` */\nexport async function main(): Promise<void> {\n const command = process.argv[2];\n\n if (command === \"setup\") {\n await interactiveSetup();\n } else {\n console.log(\"Usage: npx @sonzai-labs/openclaw-context setup\");\n console.log(\"\\nRun interactive setup to configure the Sonzai OpenClaw plugin.\");\n }\n}\n","#!/usr/bin/env node\nimport { main } from \"./setup.js\";\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"]}
package/dist/cli.d.cts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ import { Sonzai } from '@sonzai-labs/agents';
3
+ import * as readline from 'readline';
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+
7
+ async function setup(options) {
8
+ const baseUrl = options.baseUrl || "https://api.sonz.ai";
9
+ const agentName = options.agentName || "openclaw-agent";
10
+ const configPath = options.configPath || "./openclaw.json";
11
+ const client = new Sonzai({ apiKey: options.apiKey, baseUrl });
12
+ let agentId;
13
+ if (options.agentId) {
14
+ const agent = await client.agents.get(options.agentId);
15
+ agentId = agent.agent_id;
16
+ } else {
17
+ const agent = await client.agents.create({ name: agentName });
18
+ agentId = agent.agent_id;
19
+ }
20
+ const pluginConfig = buildOpenClawConfig(options.apiKey, agentId);
21
+ let written = false;
22
+ return {
23
+ agentId,
24
+ agentName,
25
+ config: pluginConfig,
26
+ configPath: written ? path.resolve(configPath) : void 0,
27
+ written
28
+ };
29
+ }
30
+ async function interactiveSetup() {
31
+ const rl = readline.createInterface({
32
+ input: process.stdin,
33
+ output: process.stdout
34
+ });
35
+ const ask = (question) => new Promise((resolve2) => rl.question(question, resolve2));
36
+ console.log("\n\u{1F99E} Sonzai Mind Layer \u2014 OpenClaw Plugin Setup\n");
37
+ try {
38
+ const envKey = process.env.SONZAI_API_KEY;
39
+ let apiKey;
40
+ if (envKey) {
41
+ const useEnv = await ask(
42
+ `Found SONZAI_API_KEY in environment (${envKey.slice(0, 8)}...). Use it? [Y/n] `
43
+ );
44
+ apiKey = useEnv.toLowerCase() === "n" ? await ask("Enter your Sonzai API key: ") : envKey;
45
+ } else {
46
+ apiKey = await ask("Enter your Sonzai API key (from https://sonz.ai/settings/api): ");
47
+ }
48
+ if (!apiKey.trim()) {
49
+ console.log("No API key provided. Aborting.");
50
+ return;
51
+ }
52
+ const hasAgent = await ask("Do you have an existing Sonzai agent ID? [y/N] ");
53
+ let agentId;
54
+ let agentName = "openclaw-agent";
55
+ if (hasAgent.toLowerCase() === "y") {
56
+ agentId = await ask("Enter agent ID: ");
57
+ } else {
58
+ const customName = await ask(
59
+ `Agent name for auto-provisioning [openclaw-agent]: `
60
+ );
61
+ if (customName.trim()) agentName = customName.trim();
62
+ }
63
+ console.log("\nValidating API key and provisioning agent...");
64
+ const result = await setup({
65
+ apiKey: apiKey.trim(),
66
+ agentId: agentId?.trim() || void 0,
67
+ agentName,
68
+ writeConfig: false
69
+ });
70
+ console.log(`Agent ready: ${result.agentId}`);
71
+ const configPath = await ask("Path to openclaw.json [./openclaw.json]: ");
72
+ const resolvedPath = configPath.trim() || "./openclaw.json";
73
+ mergeOpenClawConfig(resolvedPath, result.config);
74
+ console.log(`
75
+ Config written to ${path.resolve(resolvedPath)}`);
76
+ console.log("\n--- Setup Complete ---\n");
77
+ console.log("Set your API key as an environment variable (recommended):\n");
78
+ console.log(` export SONZAI_API_KEY="${apiKey.trim()}"
79
+ `);
80
+ console.log("Or add it to your shell profile (~/.bashrc, ~/.zshrc).\n");
81
+ console.log(
82
+ "The agent ID is saved in openclaw.json \u2014 no need to set SONZAI_AGENT_ID.\n"
83
+ );
84
+ } finally {
85
+ rl.close();
86
+ }
87
+ }
88
+ function buildOpenClawConfig(_apiKey, agentId) {
89
+ return {
90
+ plugins: {
91
+ slots: {
92
+ contextEngine: "sonzai"
93
+ },
94
+ entries: {
95
+ sonzai: {
96
+ enabled: true,
97
+ agentId
98
+ // apiKey is intentionally NOT written to the config file —
99
+ // it should be set via SONZAI_API_KEY env var for security.
100
+ }
101
+ }
102
+ }
103
+ };
104
+ }
105
+ function mergeOpenClawConfig(configPath, pluginConfig) {
106
+ let existing = {};
107
+ const resolvedPath = path.resolve(configPath);
108
+ if (fs.existsSync(resolvedPath)) {
109
+ try {
110
+ const raw = fs.readFileSync(resolvedPath, "utf-8");
111
+ existing = JSON.parse(raw);
112
+ } catch {
113
+ }
114
+ }
115
+ const merged = { ...existing };
116
+ const existingPlugins = merged.plugins || {};
117
+ const newPlugins = pluginConfig.plugins;
118
+ const existingSlots = existingPlugins.slots || {};
119
+ const newSlots = newPlugins.slots || {};
120
+ const existingEntries = existingPlugins.entries || {};
121
+ const newEntries = newPlugins.entries || {};
122
+ merged.plugins = {
123
+ ...existingPlugins,
124
+ slots: { ...existingSlots, ...newSlots },
125
+ entries: { ...existingEntries, ...newEntries }
126
+ };
127
+ fs.writeFileSync(resolvedPath, JSON.stringify(merged, null, 2) + "\n");
128
+ }
129
+ async function main() {
130
+ const command = process.argv[2];
131
+ if (command === "setup") {
132
+ await interactiveSetup();
133
+ } else {
134
+ console.log("Usage: npx @sonzai-labs/openclaw-context setup");
135
+ console.log("\nRun interactive setup to configure the Sonzai OpenClaw plugin.");
136
+ }
137
+ }
138
+
139
+ // src/cli.ts
140
+ main().catch((err) => {
141
+ console.error(err);
142
+ process.exit(1);
143
+ });
144
+ //# sourceMappingURL=cli.js.map
145
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/setup.ts","../src/cli.ts"],"names":["resolve"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * Interactive and programmatic setup for the Sonzai OpenClaw plugin.\n *\n * Interactive: `npx @sonzai-labs/openclaw-context setup`\n * Programmatic: `import { setup } from \"@sonzai-labs/openclaw-context\"`\n */\n\nimport { Sonzai } from \"@sonzai-labs/agents\";\nimport * as readline from \"node:readline\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n// ---------------------------------------------------------------------------\n// Programmatic setup — for B2B integrations\n// ---------------------------------------------------------------------------\n\nexport interface SetupOptions {\n /** Sonzai API key. */\n apiKey: string;\n /** Agent name (deterministic ID derived from tenant + name). */\n agentName?: string;\n /** Pre-existing agent ID (skips agent provisioning). */\n agentId?: string;\n /** Base URL override. */\n baseUrl?: string;\n /** Path to openclaw.json. Defaults to ./openclaw.json */\n configPath?: string;\n /** If true, writes to openclaw.json. If false, returns config object only. */\n writeConfig?: boolean;\n}\n\nexport interface SetupResult {\n agentId: string;\n agentName: string;\n config: Record<string, unknown>;\n configPath?: string;\n written: boolean;\n}\n\n/**\n * Programmatic setup — validates API key, provisions agent, optionally\n * writes openclaw.json. Designed for B2B automation scripts.\n */\nexport async function setup(options: SetupOptions): Promise<SetupResult> {\n const baseUrl = options.baseUrl || \"https://api.sonz.ai\";\n const agentName = options.agentName || \"openclaw-agent\";\n const writeConfig = options.writeConfig ?? true;\n const configPath = options.configPath || \"./openclaw.json\";\n\n // 1. Validate API key by provisioning / finding the agent\n const client = new Sonzai({ apiKey: options.apiKey, baseUrl });\n\n let agentId: string;\n if (options.agentId) {\n // Verify agent exists\n const agent = await client.agents.get(options.agentId);\n agentId = agent.agent_id;\n } else {\n // Idempotent create — backend derives deterministic UUID from tenant+name\n const agent = await client.agents.create({ name: agentName });\n agentId = agent.agent_id;\n }\n\n // 2. Build the openclaw.json plugin config\n const pluginConfig = buildOpenClawConfig(options.apiKey, agentId);\n\n // 3. Optionally write to openclaw.json\n let written = false;\n if (writeConfig) {\n mergeOpenClawConfig(configPath, pluginConfig);\n written = true;\n }\n\n return {\n agentId,\n agentName,\n config: pluginConfig,\n configPath: written ? path.resolve(configPath) : undefined,\n written,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Interactive CLI setup — `npx @sonzai-labs/openclaw-context setup`\n// ---------------------------------------------------------------------------\n\nexport async function interactiveSetup(): Promise<void> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n const ask = (question: string): Promise<string> =>\n new Promise((resolve) => rl.question(question, resolve));\n\n console.log(\"\\n🦞 Sonzai Mind Layer — OpenClaw Plugin Setup\\n\");\n\n try {\n // Step 1: API Key\n const envKey = process.env.SONZAI_API_KEY;\n let apiKey: string;\n if (envKey) {\n const useEnv = await ask(\n `Found SONZAI_API_KEY in environment (${envKey.slice(0, 8)}...). Use it? [Y/n] `,\n );\n apiKey = useEnv.toLowerCase() === \"n\" ? await ask(\"Enter your Sonzai API key: \") : envKey;\n } else {\n apiKey = await ask(\"Enter your Sonzai API key (from https://sonz.ai/settings/api): \");\n }\n\n if (!apiKey.trim()) {\n console.log(\"No API key provided. Aborting.\");\n return;\n }\n\n // Step 2: Agent\n const hasAgent = await ask(\"Do you have an existing Sonzai agent ID? [y/N] \");\n let agentId: string | undefined;\n let agentName = \"openclaw-agent\";\n\n if (hasAgent.toLowerCase() === \"y\") {\n agentId = await ask(\"Enter agent ID: \");\n } else {\n const customName = await ask(\n `Agent name for auto-provisioning [openclaw-agent]: `,\n );\n if (customName.trim()) agentName = customName.trim();\n }\n\n // Step 3: Validate\n console.log(\"\\nValidating API key and provisioning agent...\");\n const result = await setup({\n apiKey: apiKey.trim(),\n agentId: agentId?.trim() || undefined,\n agentName,\n writeConfig: false,\n });\n console.log(`Agent ready: ${result.agentId}`);\n\n // Step 4: Write config\n const configPath = await ask(\"Path to openclaw.json [./openclaw.json]: \");\n const resolvedPath = configPath.trim() || \"./openclaw.json\";\n\n mergeOpenClawConfig(resolvedPath, result.config);\n console.log(`\\nConfig written to ${path.resolve(resolvedPath)}`);\n\n // Step 5: Env var hint\n console.log(\"\\n--- Setup Complete ---\\n\");\n console.log(\"Set your API key as an environment variable (recommended):\\n\");\n console.log(` export SONZAI_API_KEY=\"${apiKey.trim()}\"\\n`);\n console.log(\"Or add it to your shell profile (~/.bashrc, ~/.zshrc).\\n\");\n console.log(\n \"The agent ID is saved in openclaw.json — no need to set SONZAI_AGENT_ID.\\n\",\n );\n } finally {\n rl.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction buildOpenClawConfig(\n _apiKey: string,\n agentId: string,\n): Record<string, unknown> {\n return {\n plugins: {\n slots: {\n contextEngine: \"sonzai\",\n },\n entries: {\n sonzai: {\n enabled: true,\n agentId,\n // apiKey is intentionally NOT written to the config file —\n // it should be set via SONZAI_API_KEY env var for security.\n },\n },\n },\n };\n}\n\nfunction mergeOpenClawConfig(\n configPath: string,\n pluginConfig: Record<string, unknown>,\n): void {\n let existing: Record<string, unknown> = {};\n\n const resolvedPath = path.resolve(configPath);\n if (fs.existsSync(resolvedPath)) {\n try {\n const raw = fs.readFileSync(resolvedPath, \"utf-8\");\n existing = JSON.parse(raw);\n } catch {\n // If parse fails, start fresh\n }\n }\n\n // Deep merge plugins section\n const merged = { ...existing };\n const existingPlugins = (merged.plugins || {}) as Record<string, unknown>;\n const newPlugins = pluginConfig.plugins as Record<string, unknown>;\n\n const existingSlots = (existingPlugins.slots || {}) as Record<string, unknown>;\n const newSlots = (newPlugins.slots || {}) as Record<string, unknown>;\n\n const existingEntries = (existingPlugins.entries || {}) as Record<string, unknown>;\n const newEntries = (newPlugins.entries || {}) as Record<string, unknown>;\n\n merged.plugins = {\n ...existingPlugins,\n slots: { ...existingSlots, ...newSlots },\n entries: { ...existingEntries, ...newEntries },\n };\n\n fs.writeFileSync(resolvedPath, JSON.stringify(merged, null, 2) + \"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// CLI entry point\n// ---------------------------------------------------------------------------\n\n/** Run when invoked as `npx @sonzai-labs/openclaw-context setup` */\nexport async function main(): Promise<void> {\n const command = process.argv[2];\n\n if (command === \"setup\") {\n await interactiveSetup();\n } else {\n console.log(\"Usage: npx @sonzai-labs/openclaw-context setup\");\n console.log(\"\\nRun interactive setup to configure the Sonzai OpenClaw plugin.\");\n }\n}\n","#!/usr/bin/env node\nimport { main } from \"./setup.js\";\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"]}