@sonzai-labs/openclaw-context 1.0.3
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 +220 -0
- package/dist/cli.cjs +169 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +145 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +670 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +282 -0
- package/dist/index.d.ts +282 -0
- package/dist/index.js +638 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
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
|
package/dist/cli.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/setup.ts","../src/cli.ts"],"names":["Sonzai","path","readline","resolve","fs"],"mappings":"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","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
|
package/dist/cli.js.map
ADDED
|
@@ -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"]}
|