openclaw-quiubo 2.6.29 → 2.6.31

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/MULTI_AGENT.md ADDED
@@ -0,0 +1,281 @@
1
+ # Multi-Agent Setup
2
+
3
+ One gateway. Multiple agents. Each with its own chat, model, workspace, and schedule — completely isolated from each other.
4
+
5
+ ## What You Get
6
+
7
+ - **Own chat** — separate Quiubo identity and conversation thread
8
+ - **Own model** — Opus for heavy thinking, Haiku for lightweight jobs
9
+ - **Own workspace** — files, memory, history are private
10
+ - **Own schedule** — cron jobs scoped per agent
11
+ - **One key** — all agents share your SDK API key (and its quota — see [API Key Quota](#api-key-quota))
12
+
13
+ ## Example
14
+
15
+ **Bob** is your personal assistant (Opus, handles research and writing).
16
+ **Sam** is your project manager (Sonnet, runs standups and tracks tasks).
17
+
18
+ Both appear as separate chats in Quiubo — independent conversations, independent workspaces.
19
+
20
+ ## Setup
21
+
22
+ ### 1. Add a bot identity
23
+
24
+ Run the interactive wizard to add a new account:
25
+
26
+ ```bash
27
+ openclaw channels add
28
+ ```
29
+
30
+ The wizard asks for three things:
31
+ - **Account ID** — short name for this agent (e.g. `pm`, `research`). Your first agent uses `default`.
32
+ - **SDK API Key** — reuse your existing `qub_...` key.
33
+ - **Bot identity** — choose "Create new bot identity" to give this agent its own name in Quiubo.
34
+
35
+ ### 2. Register the agent
36
+
37
+ Add an entry to `agents.list` in `~/.openclaw/openclaw.json`. Give it a unique ID and its own workspace path:
38
+
39
+ ```json
40
+ {
41
+ "agents": {
42
+ "defaults": {
43
+ "workspace": "~/.openclaw/workspace"
44
+ },
45
+ "list": [
46
+ {
47
+ "id": "main",
48
+ "subagents": { "allowAgents": ["*"] }
49
+ },
50
+ {
51
+ "id": "project-manager",
52
+ "name": "Sam",
53
+ "model": "anthropic/claude-sonnet-4-5",
54
+ "workspace": "~/.openclaw/workspace-project-manager",
55
+ "agentDir": "~/.openclaw/agents/project-manager/agent",
56
+ "subagents": { "allowAgents": ["*"] }
57
+ }
58
+ ]
59
+ }
60
+ }
61
+ ```
62
+
63
+ The `main` agent inherits `workspace` from `agents.defaults`. Non-main agents override it with their own path.
64
+
65
+ - **`workspace`** — the agent's working directory (files it creates, edits, and reads during tasks).
66
+ - **`agentDir`** — the agent's identity/state directory (`IDENTITY.md`, `SOUL.md`, `AGENTS.md`, memory). Optional — defaults to a path under `~/.openclaw/agents/{id}/agent`. Set it explicitly if you want control over where identity files live.
67
+
68
+ ### 3. Bind account to agent
69
+
70
+ Tell OpenClaw which Quiubo account maps to which agent using the `bindings` array:
71
+
72
+ ```json
73
+ {
74
+ "bindings": [
75
+ {
76
+ "agentId": "main",
77
+ "match": {
78
+ "channel": "quiubo",
79
+ "accountId": "default"
80
+ }
81
+ },
82
+ {
83
+ "agentId": "project-manager",
84
+ "match": {
85
+ "channel": "quiubo",
86
+ "accountId": "pm"
87
+ }
88
+ }
89
+ ]
90
+ }
91
+ ```
92
+
93
+ *Without bindings, all messages route to the first agent in the list.*
94
+
95
+ ### 4. Create the workspace
96
+
97
+ ```bash
98
+ mkdir -p ~/.openclaw/workspace-project-manager
99
+ mkdir -p ~/.openclaw/agents/project-manager/agent/memory
100
+ ```
101
+
102
+ Seed the agent dir with identity files: `SOUL.md`, `AGENTS.md`, `USER.md`, `IDENTITY.md`, `MEMORY.md`.
103
+
104
+ To help the agent understand the multi-agent setup, add this to its `AGENTS.md`:
105
+
106
+ ```markdown
107
+ ## Multi-Agent Architecture
108
+ This agent runs as part of a multi-agent OpenClaw gateway.
109
+ Each agent has its own chat, workspace, and cron jobs.
110
+ ```
111
+
112
+ > **Note:** If you use auth profiles (e.g. GitHub tokens), each agent workspace needs its own `config.json` or shared auth config.
113
+
114
+ ### 5. Restart
115
+
116
+ ```bash
117
+ openclaw gateway restart
118
+ ```
119
+
120
+ The new agent gets its own welcome chat automatically.
121
+
122
+ ## Config Integrity Warning
123
+
124
+ Your config will have account data in **two** places:
125
+
126
+ | Location | Who writes it | Who reads it |
127
+ |----------|---------------|--------------|
128
+ | `channels.quiubo.accounts` | `openclaw channels add` wizard | **The plugin** (source of truth) |
129
+ | `plugins.entries.openclaw-quiubo.config.accounts` | OpenClaw core (mirrors plugin config) | OpenClaw core |
130
+
131
+ The plugin reads **only** from `channels.quiubo.accounts`. If that section is missing or empty, the plugin silently does nothing — no `[quiubo]` logs, no errors, just gone.
132
+
133
+ > **The #1 footgun:** an agent running `config.patch` that omits `channels` will wipe `channels.quiubo.accounts` entirely. The plugin dies on the next restart while everything else looks fine.
134
+ >
135
+ > **Rule of thumb:** never do a full config write/patch that doesn't preserve `channels`. Always merge rather than replace.
136
+
137
+ ## API Key Quota
138
+
139
+ All accounts sharing the same `qub_...` API key share its monthly request quota. If one agent is chatty enough to exhaust the limit, **all** agents using that key stop working on the next restart.
140
+
141
+ Options:
142
+ - **One key, shared quota** — simpler setup, fine for low-traffic agents.
143
+ - **Separate keys per account** — independent quotas, each agent can hit its own ceiling without affecting others.
144
+
145
+ ## How It Works
146
+
147
+ ```
148
+ ┌─────────────────────────┐
149
+ │ OpenClaw Gateway │
150
+ └────────┬────────────────┘
151
+
152
+ ┌──────────────┼──────────────┐
153
+ ▼ ▼ ▼
154
+ account:default account:pm account:research
155
+ │ │ │
156
+ ┌────┴────┐ ┌────┴────┐ ┌────┴────┐
157
+ │ gateway │ │ gateway │ │ gateway │
158
+ │ client │ │ client │ │ client │
159
+ │ logger │ │ logger │ │ logger │
160
+ │ cursor │ │ cursor │ │ cursor │
161
+ └────┬────┘ └────┬────┘ └────┬────┘
162
+ │ │ │
163
+ binding ──→ binding ──→ binding ──→
164
+ agent:main agent:pm agent:research
165
+ ```
166
+
167
+ **Isolation boundaries:**
168
+
169
+ - **Per-account Maps** — each account gets its own gateway, API client, config, and logger.
170
+ - **Per-account cursors** — `~/.openclaw/cron/quiubo-cursors-{accountId}.json` — no clobbering between agents.
171
+ - **Per-account E2EE keys** — `~/.openclaw/cron/quiubo-keys-{accountId}.json` — each account's key seed. If lost, the agent re-enrolls its keys (may break E2EE for existing conversations).
172
+ - **Session keys** — main agent uses `quiubo:{groupId}`, others use `agent:{agentId}:quiubo:{groupId}` — conversations never cross.
173
+ - **Cron jobs** — filtered by `agentId` in `getActivityData()` — each agent's chat shows only its own scheduled jobs.
174
+ - **Auto-provisioning** — each new account gets a welcome `agent_channel` group with `externalGroupId: auto-{accountId}`.
175
+ - **Auto-registration** — on first startup, each account auto-registers an agent record in the Quiubo directory if none exists for its bot identity.
176
+
177
+ **Agent resolution** (`resolveAgentId`): searches `bindings[]` for matching channel + accountId. Falls back to first agent in `agents.list`, then to `"main"`.
178
+
179
+ ## Cron Jobs
180
+
181
+ Cron jobs are scoped per agent via the `agentId` field:
182
+
183
+ ```json
184
+ {
185
+ "jobs": [
186
+ {
187
+ "id": "daily-standup",
188
+ "agentId": "project-manager",
189
+ "schedule": "0 9 * * 1-5",
190
+ "enabled": true,
191
+ "delivery": {
192
+ "channel": "quiubo",
193
+ "to": "<group-uuid>"
194
+ }
195
+ }
196
+ ]
197
+ }
198
+ ```
199
+
200
+ - **`agentId`**: Ensures only the "project-manager" agent sees/runs this job. **Required** — jobs without `agentId` are invisible to all agents.
201
+ - **`delivery.channel`**: Must be `"quiubo"`.
202
+ - **`delivery.to`**: The raw group UUID (e.g. `eec8a4ce-d08d-483a-ba5d-90a43ce8f521`). Find it in the agent's welcome chat or via the API.
203
+
204
+ > **Multi-agent caveat:** The fallback resolver (`resolveAnnounceGroupId`) reads cron jobs from disk but does not filter by accountId. If multiple agents have cron jobs, it may resolve to the wrong agent's target group. Keep one cron job per agent, or ensure each agent's delivery target is unambiguous.
205
+
206
+ ## Full Config Reference
207
+
208
+ Quiubo-relevant sections of `openclaw.json` for a 2-agent setup:
209
+
210
+ ```json
211
+ {
212
+ "agents": {
213
+ "defaults": {
214
+ "workspace": "~/.openclaw/workspace"
215
+ },
216
+ "list": [
217
+ {
218
+ "id": "main",
219
+ "subagents": { "allowAgents": ["*"] }
220
+ },
221
+ {
222
+ "id": "project-manager",
223
+ "name": "Sam",
224
+ "model": "anthropic/claude-sonnet-4-5",
225
+ "workspace": "~/.openclaw/workspace-project-manager",
226
+ "agentDir": "~/.openclaw/agents/project-manager/agent",
227
+ "subagents": { "allowAgents": ["*"] }
228
+ }
229
+ ]
230
+ },
231
+ "bindings": [
232
+ {
233
+ "agentId": "main",
234
+ "match": {
235
+ "channel": "quiubo",
236
+ "accountId": "default"
237
+ }
238
+ },
239
+ {
240
+ "agentId": "project-manager",
241
+ "match": {
242
+ "channel": "quiubo",
243
+ "accountId": "pm"
244
+ }
245
+ }
246
+ ],
247
+ "channels": {
248
+ "quiubo": {
249
+ "accounts": {
250
+ "default": {
251
+ "enabled": true,
252
+ "apiKey": "qub_your_key_here",
253
+ "botIdentityId": "<main-bot-uuid>",
254
+ "apiUrl": "https://api.quiubo.io"
255
+ },
256
+ "pm": {
257
+ "enabled": true,
258
+ "apiKey": "qub_your_key_here",
259
+ "botIdentityId": "<pm-bot-uuid>",
260
+ "apiUrl": "https://api.quiubo.io"
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }
266
+ ```
267
+
268
+ > **Note:** OpenClaw also mirrors account data into `plugins.entries.openclaw-quiubo.config.accounts`. The plugin ignores that copy — `channels.quiubo.accounts` is the only location that matters. See [Config Integrity Warning](#config-integrity-warning).
269
+
270
+ ## Troubleshooting
271
+
272
+ | Symptom | Fix |
273
+ |---------|-----|
274
+ | Plugin silently stops — no `[quiubo]` logs on startup | `channels.quiubo.accounts` is missing from config. An agent's `config.patch` likely wiped it. Restore the `channels` block and restart. |
275
+ | Second agent doesn't respond | Check `bindings[]` — accountId must match exactly. Run `openclaw gateway restart`. |
276
+ | Both agents reply to the same message | Missing or duplicate bindings. Each accountId needs exactly one binding. |
277
+ | Agent dies on restart, others work fine | Check logs for `[FATAL] STARTUP FAILED`. Common causes: invalid/expired API key (401), permission error (403), or quota exhausted. Rotate the key or check usage. |
278
+ | Cron job runs in wrong chat | Verify `agentId` on the job matches the target agent, and `delivery.to` uses the correct group UUID. |
279
+ | "welcome group already exists" on restart | Normal — auto-provisioning is safe. The existing group is reused. |
280
+ | Agent shows other agent's cron jobs | The `agentId` on the job doesn't match. Double-check spelling. |
281
+ | Cron job never runs / missing from activity | Missing `agentId` field on the job. Untagged jobs are invisible to all agents — the filter requires an exact match. |
package/README.md CHANGED
@@ -17,7 +17,7 @@ openclaw plugins update openclaw-quiubo
17
17
  ## Setup
18
18
 
19
19
  ```bash
20
- openclaw channels add --channel quiubo
20
+ openclaw channels add
21
21
  ```
22
22
 
23
23
  The interactive wizard will:
@@ -58,7 +58,7 @@ channels:
58
58
 
59
59
  ### Multiple accounts
60
60
 
61
- Run the setup wizard again and enter a different Account ID when prompted (e.g., `support-bot`, `sales-bot`). Each account gets its own gateway instance, cursor file, and bot config cache.
61
+ Run the setup wizard again and enter a different Account ID when prompted (e.g., `support-bot`, `sales-bot`). Each account gets its own gateway instance, cursor file, and bot config cache. For full multi-agent isolation (separate workspaces, models, cron jobs), see the **[Multi-Agent Setup guide](./MULTI_AGENT.md)**.
62
62
 
63
63
  ## Architecture
64
64
 
@@ -98,7 +98,7 @@ Four layers prevent old messages from being reprocessed on restart:
98
98
 
99
99
  The plugin supports Quiubo's E2EE protocol for groups that require it:
100
100
 
101
- - **Key generation**: Deterministic Ed25519 + X25519 keypairs derived from a 32-byte seed (persisted in config)
101
+ - **Key generation**: Deterministic Ed25519 + X25519 keypairs derived from a 32-byte seed (persisted to `~/.openclaw/cron/quiubo-keys-{accountId}.json`)
102
102
  - **Auto-enrollment**: On first startup, generates keypair and enrolls via challenge-response (`requestKeyChallenge` > `signChallenge` > `verifyKeyChallenge`)
103
103
  - **Inbound decryption**: GroupEnvelopeV2 messages decrypted using XChaCha20-Poly1305 with epoch keys
104
104
  - **Outbound encryption**: Plaintext encrypted before sending when E2EE is granted for the group
@@ -143,125 +143,16 @@ On first gateway startup, if the bot has no groups, the plugin automatically cre
143
143
 
144
144
  ## Multi-Agent Setup
145
145
 
146
- Run multiple AI agents on a single OpenClaw gateway — each with their own Quiubo chat, workspace, model, and cron jobs.
146
+ Run multiple agents on a single gateway — each with its own chat, model, workspace, and cron jobs.
147
147
 
148
- Each agent needs two things: a **bot identity** in Quiubo (so it has its own chat presence) and an **agent entry** in OpenClaw (so it has its own workspace and model). They can share the same SDK API key.
148
+ 1. `openclaw channels add` create a new bot identity
149
+ 2. Add the agent and binding to `~/.openclaw/openclaw.json`
150
+ 3. Create the agent's workspace
151
+ 4. `openclaw gateway restart`
149
152
 
150
- ### Step 1: Create a bot identity in Quiubo
153
+ All agents share one SDK API key (and its quota). Each gets fully isolated conversations, cursors, and session keys.
151
154
 
152
- Each agent needs its own bot identity. You create one by running the setup wizard with a new account ID:
153
-
154
- ```bash
155
- openclaw channels add --channel quiubo
156
- ```
157
-
158
- The wizard will:
159
-
160
- 1. Ask for an **Account ID** — enter a short name for this agent (e.g. `pm`, `support`, `research`). Your first/default agent uses `default`.
161
- 2. Ask for your **SDK API Key** — you can reuse the same `qub_...` key across all agents.
162
- 3. **Create or select a bot identity** — choose "Create new bot identity" to give this agent its own username and display name in Quiubo.
163
-
164
- > **Where to get an SDK API Key:** In the Quiubo app, go to **Settings > Developer > API Keys**. One key works for all agents under the same app.
165
-
166
- After the wizard completes, the new account is saved to `~/.openclaw/openclaw.json` automatically:
167
-
168
- ```json
169
- {
170
- "plugins": {
171
- "quiubo": {
172
- "accounts": {
173
- "default": {
174
- "apiKey": "qub_...",
175
- "botIdentityId": "<main-bot-uuid>"
176
- },
177
- "pm": {
178
- "apiKey": "qub_...",
179
- "botIdentityId": "<pm-bot-uuid>"
180
- }
181
- }
182
- }
183
- }
184
- }
185
- ```
186
-
187
- ### Step 2: Add the agent to OpenClaw
188
-
189
- In `~/.openclaw/openclaw.json`, add an entry to the agents list:
190
-
191
- ```json
192
- {
193
- "agents": {
194
- "list": [
195
- { "id": "main" },
196
- {
197
- "id": "project-manager",
198
- "model": "anthropic/claude-sonnet-4-5",
199
- "workspace": "~/.openclaw/workspace-project-manager"
200
- }
201
- ]
202
- }
203
- }
204
- ```
205
-
206
- Each agent can have its own model, workspace, and system prompt.
207
-
208
- ### Step 3: Bind the Quiubo account to the agent
209
-
210
- Tell OpenClaw which Quiubo account maps to which agent:
211
-
212
- ```json
213
- {
214
- "bindings": [
215
- {
216
- "match": { "channel": "quiubo", "accountId": "default" },
217
- "agentId": "main"
218
- },
219
- {
220
- "match": { "channel": "quiubo", "accountId": "pm" },
221
- "agentId": "project-manager"
222
- }
223
- ]
224
- }
225
- ```
226
-
227
- Without bindings, all messages route to the first agent.
228
-
229
- ### Step 4: Create the agent's workspace
230
-
231
- ```bash
232
- mkdir -p ~/.openclaw/workspace-project-manager/memory
233
- ```
234
-
235
- Seed it with: `SOUL.md`, `AGENTS.md`, `USER.md`, `IDENTITY.md`, `MEMORY.md`.
236
-
237
- ### Step 5: Restart
238
-
239
- ```bash
240
- openclaw gateway restart
241
- ```
242
-
243
- ### How routing works
244
-
245
- ```
246
- Quiubo Chat (You + Main Bot) → account: default → binding → agent: main
247
- Quiubo Chat (You + PM Bot) → account: pm → binding → agent: project-manager
248
- ```
249
-
250
- - **Messages**: AccountId resolves the agent via bindings
251
- - **Cron jobs**: Filtered by agentId — each agent's chat shows only its own
252
- - **Sessions**: Isolated session namespaces per agent, no cross-talk
253
- - **Workspaces**: Fully isolated — agents can't see each other's files
254
- - **Cursors**: Each account has its own cursor file — no clobbering
255
-
256
- ### Adding more agents
257
-
258
- Repeat steps 1–5 for each new agent. The key command is:
259
-
260
- ```bash
261
- openclaw channels add --channel quiubo
262
- ```
263
-
264
- Enter a unique Account ID each time (e.g. `support`, `research`). The wizard handles identity creation and config — then add the agent, binding, and workspace as shown above.
155
+ **[Full guide](./MULTI_AGENT.md)** architecture, config examples, cron setup, and troubleshooting.
265
156
 
266
157
  ## Markdown Attachments
267
158
 
@@ -269,7 +160,7 @@ Agents can send `.md` file attachments alongside messages. Attachments appear as
269
160
 
270
161
  OpenClaw's `MEDIA:` token protocol is used: when an agent writes a file and includes `MEDIA: /path/to/file.md` in its response, the plugin reads the file and sends it as a structured attachment.
271
162
 
272
- **Supported:** `.md` files only, max 1MB each. Source tracking distinguishes `agent` vs `subagent` attachments.
163
+ **Supported:** `.md` files (max 1MB) and images — `.jpg`, `.jpeg`, `.png`, `.webp` (max 5MB, uploaded via S3 presign). Source tracking distinguishes `agent` vs `subagent` attachments.
273
164
 
274
165
  Add this to your agent's `AGENTS.md`:
275
166
 
@@ -286,20 +177,19 @@ Example response:
286
177
  MEDIA: /tmp/daily-report.md
287
178
 
288
179
  The file will be delivered as a tappable attachment card in the chat.
289
- Only `.md` files are supported. Files over 1MB are skipped.
180
+ Supported: `.md` (max 1MB) and images `.jpg`/`.png`/`.webp` (max 5MB).
290
181
  ```
291
182
 
292
183
  ## Operational Notes
293
184
 
294
- ### Cursor files
185
+ ### Per-account state files
295
186
 
296
- Cursors are persisted at:
297
-
298
- ```
299
- ~/.openclaw/cron/quiubo-cursors-{accountId}.json
300
- ```
187
+ Each account persists its own state files under `~/.openclaw/cron/`:
301
188
 
302
- Each account writes to its own file to avoid clobbering in multi-account setups. Safe to delete — the gateway will `seekToLatest()` on next start (no replay).
189
+ | File | Purpose | Safe to delete? |
190
+ |------|---------|-----------------|
191
+ | `quiubo-cursors-{accountId}.json` | Message cursor positions | Yes — gateway will `seekToLatest()` on next start (no replay) |
192
+ | `quiubo-keys-{accountId}.json` | E2EE key seed (32 bytes) | **No** — deleting forces re-enrollment, may break E2EE for existing conversations |
303
193
 
304
194
  ### Heartbeat
305
195
 
@@ -313,7 +203,7 @@ A typing indicator is sent immediately when processing begins, then repeated eve
313
203
 
314
204
  ```bash
315
205
  openclaw channels disable --channel quiubo # Disable
316
- openclaw channels add --channel quiubo # Re-configure
206
+ openclaw channels add # Re-configure
317
207
  ```
318
208
 
319
209
  ## Development
package/dist/index.js CHANGED
@@ -31,9 +31,9 @@ var __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__
31
31
  mod2
32
32
  ));
33
33
 
34
- // ../../node_modules/.pnpm/pusher-js@8.4.0/node_modules/pusher-js/dist/node/pusher.js
34
+ // node_modules/pusher-js/dist/node/pusher.js
35
35
  var require_pusher = __commonJS({
36
- "../../node_modules/.pnpm/pusher-js@8.4.0/node_modules/pusher-js/dist/node/pusher.js"(exports, module) {
36
+ "node_modules/pusher-js/dist/node/pusher.js"(exports, module) {
37
37
  "use strict";
38
38
  module.exports = /******/
39
39
  (function(modules) {
@@ -9265,11 +9265,11 @@ var import_pusher_js = __toESM(require_pusher(), 1);
9265
9265
  import { readFile, writeFile, mkdir } from "fs/promises";
9266
9266
  import { join } from "path";
9267
9267
 
9268
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/cryptoNode.js
9268
+ // node_modules/@noble/hashes/esm/cryptoNode.js
9269
9269
  import * as nc from "node:crypto";
9270
9270
  var crypto = nc && typeof nc === "object" && "webcrypto" in nc ? nc.webcrypto : nc && typeof nc === "object" && "randomBytes" in nc ? nc : void 0;
9271
9271
 
9272
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/utils.js
9272
+ // node_modules/@noble/hashes/esm/utils.js
9273
9273
  function isBytes(a) {
9274
9274
  return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
9275
9275
  }
@@ -9405,7 +9405,7 @@ function randomBytes(bytesLength = 32) {
9405
9405
  throw new Error("crypto.getRandomValues must be defined");
9406
9406
  }
9407
9407
 
9408
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_md.js
9408
+ // node_modules/@noble/hashes/esm/_md.js
9409
9409
  function setBigUint64(view, byteOffset, value, isLE2) {
9410
9410
  if (typeof view.setBigUint64 === "function")
9411
9411
  return view.setBigUint64(byteOffset, value, isLE2);
@@ -9543,7 +9543,7 @@ var SHA512_IV = /* @__PURE__ */ Uint32Array.from([
9543
9543
  327033209
9544
9544
  ]);
9545
9545
 
9546
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/_u64.js
9546
+ // node_modules/@noble/hashes/esm/_u64.js
9547
9547
  var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
9548
9548
  var _32n = /* @__PURE__ */ BigInt(32);
9549
9549
  function fromBig(n, le = false) {
@@ -9578,7 +9578,7 @@ var add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0
9578
9578
  var add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);
9579
9579
  var add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0;
9580
9580
 
9581
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha2.js
9581
+ // node_modules/@noble/hashes/esm/sha2.js
9582
9582
  var SHA256_K = /* @__PURE__ */ Uint32Array.from([
9583
9583
  1116352408,
9584
9584
  1899447441,
@@ -9916,7 +9916,7 @@ var SHA512 = class extends HashMD {
9916
9916
  var sha256 = /* @__PURE__ */ createHasher(() => new SHA256());
9917
9917
  var sha512 = /* @__PURE__ */ createHasher(() => new SHA512());
9918
9918
 
9919
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/utils.js
9919
+ // node_modules/@noble/curves/esm/utils.js
9920
9920
  var _0n = /* @__PURE__ */ BigInt(0);
9921
9921
  var _1n = /* @__PURE__ */ BigInt(1);
9922
9922
  function _abool2(value, title = "") {
@@ -10029,7 +10029,7 @@ function memoized(fn) {
10029
10029
  };
10030
10030
  }
10031
10031
 
10032
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/abstract/modular.js
10032
+ // node_modules/@noble/curves/esm/abstract/modular.js
10033
10033
  var _0n2 = BigInt(0);
10034
10034
  var _1n2 = BigInt(1);
10035
10035
  var _2n = /* @__PURE__ */ BigInt(2);
@@ -10355,7 +10355,7 @@ function Field(ORDER, bitLenOrOpts, isLE2 = false, opts = {}) {
10355
10355
  return Object.freeze(f);
10356
10356
  }
10357
10357
 
10358
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/abstract/curve.js
10358
+ // node_modules/@noble/curves/esm/abstract/curve.js
10359
10359
  var _0n3 = BigInt(0);
10360
10360
  var _1n3 = BigInt(1);
10361
10361
  function negateCt(condition, item) {
@@ -10618,7 +10618,7 @@ function _createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
10618
10618
  return { CURVE, Fp: Fp2, Fn: Fn2 };
10619
10619
  }
10620
10620
 
10621
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/abstract/edwards.js
10621
+ // node_modules/@noble/curves/esm/abstract/edwards.js
10622
10622
  var _0n4 = BigInt(0);
10623
10623
  var _1n4 = BigInt(1);
10624
10624
  var _2n2 = BigInt(2);
@@ -11169,7 +11169,7 @@ function twistedEdwards(c) {
11169
11169
  return _eddsa_new_output_to_legacy(c, EDDSA);
11170
11170
  }
11171
11171
 
11172
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/abstract/montgomery.js
11172
+ // node_modules/@noble/curves/esm/abstract/montgomery.js
11173
11173
  var _0n5 = BigInt(0);
11174
11174
  var _1n5 = BigInt(1);
11175
11175
  var _2n3 = BigInt(2);
@@ -11289,7 +11289,7 @@ function montgomery(curveDef) {
11289
11289
  };
11290
11290
  }
11291
11291
 
11292
- // ../../node_modules/.pnpm/@noble+curves@1.9.7/node_modules/@noble/curves/esm/ed25519.js
11292
+ // node_modules/@noble/curves/esm/ed25519.js
11293
11293
  var _0n6 = /* @__PURE__ */ BigInt(0);
11294
11294
  var _1n6 = BigInt(1);
11295
11295
  var _2n4 = BigInt(2);
@@ -11524,7 +11524,7 @@ _RistrettoPoint.ZERO = /* @__PURE__ */ (() => new _RistrettoPoint(ed25519.Point.
11524
11524
  _RistrettoPoint.Fp = /* @__PURE__ */ (() => Fp)();
11525
11525
  _RistrettoPoint.Fn = /* @__PURE__ */ (() => Fn)();
11526
11526
 
11527
- // ../../node_modules/.pnpm/@noble+ciphers@1.3.0/node_modules/@noble/ciphers/esm/utils.js
11527
+ // node_modules/@noble/ciphers/esm/utils.js
11528
11528
  function isBytes2(a) {
11529
11529
  return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
11530
11530
  }
@@ -11680,7 +11680,7 @@ function copyBytes2(bytes) {
11680
11680
  return Uint8Array.from(bytes);
11681
11681
  }
11682
11682
 
11683
- // ../../node_modules/.pnpm/@noble+ciphers@1.3.0/node_modules/@noble/ciphers/esm/_arx.js
11683
+ // node_modules/@noble/ciphers/esm/_arx.js
11684
11684
  var _utf8ToBytes = (str) => Uint8Array.from(str.split("").map((c) => c.charCodeAt(0)));
11685
11685
  var sigma16 = _utf8ToBytes("expand 16-byte k");
11686
11686
  var sigma32 = _utf8ToBytes("expand 32-byte k");
@@ -11788,7 +11788,7 @@ function createCipher(core, opts) {
11788
11788
  };
11789
11789
  }
11790
11790
 
11791
- // ../../node_modules/.pnpm/@noble+ciphers@1.3.0/node_modules/@noble/ciphers/esm/_poly1305.js
11791
+ // node_modules/@noble/ciphers/esm/_poly1305.js
11792
11792
  var u8to16 = (a, i) => a[i++] & 255 | (a[i++] & 255) << 8;
11793
11793
  var Poly1305 = class {
11794
11794
  constructor(key) {
@@ -12043,7 +12043,7 @@ function wrapConstructorWithKey(hashCons) {
12043
12043
  }
12044
12044
  var poly1305 = wrapConstructorWithKey((key) => new Poly1305(key));
12045
12045
 
12046
- // ../../node_modules/.pnpm/@noble+ciphers@1.3.0/node_modules/@noble/ciphers/esm/chacha.js
12046
+ // node_modules/@noble/ciphers/esm/chacha.js
12047
12047
  function chachaCore(s, k, n, out, cnt, rounds = 20) {
12048
12048
  let y00 = s[0], y01 = s[1], y02 = s[2], y03 = s[3], y04 = k[0], y05 = k[1], y06 = k[2], y07 = k[3], y08 = k[4], y09 = k[5], y10 = k[6], y11 = k[7], y12 = cnt, y13 = n[0], y14 = n[1], y15 = n[2];
12049
12049
  let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15;
@@ -12274,10 +12274,10 @@ var xchacha20poly1305 = /* @__PURE__ */ wrapCipher({ blockSize: 64, nonceLength:
12274
12274
  // src/crypto.ts
12275
12275
  import { randomBytes as randomBytes2 } from "node:crypto";
12276
12276
 
12277
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/sha256.js
12277
+ // node_modules/@noble/hashes/esm/sha256.js
12278
12278
  var sha2562 = sha256;
12279
12279
 
12280
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/hmac.js
12280
+ // node_modules/@noble/hashes/esm/hmac.js
12281
12281
  var HMAC = class extends Hash {
12282
12282
  constructor(hash, _key) {
12283
12283
  super();
@@ -12345,7 +12345,7 @@ var HMAC = class extends Hash {
12345
12345
  var hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
12346
12346
  hmac.create = (hash, key) => new HMAC(hash, key);
12347
12347
 
12348
- // ../../node_modules/.pnpm/@noble+hashes@1.8.0/node_modules/@noble/hashes/esm/hkdf.js
12348
+ // node_modules/@noble/hashes/esm/hkdf.js
12349
12349
  function extract(hash, ikm, salt) {
12350
12350
  ahash(hash);
12351
12351
  if (salt === void 0)