forge-openclaw-plugin 0.2.60 → 0.2.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +121 -51
  2. package/dist/assets/{board-B1V3M__K.js → board-DUwMfZvN.js} +1 -1
  3. package/dist/assets/index-B9VOpR7r.css +1 -0
  4. package/dist/assets/index-DoHjjze2.js +90 -0
  5. package/dist/assets/{motion-CltSTItx.js → motion-Crg3QyXD.js} +1 -1
  6. package/dist/assets/{table-B-VrSFx8.js → table-CTlDeYRs.js} +1 -1
  7. package/dist/assets/{ui-DUqM4jkt.js → ui-CJPaElbj.js} +1 -1
  8. package/dist/assets/{vendor-C0otBhgu.js → vendor-BdrT2htV.js} +217 -207
  9. package/dist/companion-iroh/darwin-arm64/forge-companion-iroh +0 -0
  10. package/dist/companion-iroh/darwin-x64/forge-companion-iroh +0 -0
  11. package/dist/companion-iroh/linux-x64/forge-companion-iroh +0 -0
  12. package/dist/companion-iroh-src/Cargo.lock +4559 -0
  13. package/dist/companion-iroh-src/Cargo.toml +37 -0
  14. package/dist/companion-iroh-src/src/lib.rs +279 -0
  15. package/dist/companion-iroh-src/src/main.rs +478 -0
  16. package/dist/companion-iroh-src/src/protocol.rs +129 -0
  17. package/dist/gamification-previews/dark-fantasy-item-trophy-tasks-anvil-marathon.webp +0 -0
  18. package/dist/gamification-previews/dark-fantasy-item-trophy-xp-levels-the-first-heat.webp +0 -0
  19. package/dist/gamification-previews/dark-fantasy-item-unlock-streaks-molten-crown-fire.webp +0 -0
  20. package/dist/gamification-previews/dark-fantasy-mascot.webp +0 -0
  21. package/dist/gamification-previews/dramatic-smithie-item-trophy-tasks-anvil-marathon.webp +0 -0
  22. package/dist/gamification-previews/dramatic-smithie-item-trophy-xp-levels-the-first-heat.webp +0 -0
  23. package/dist/gamification-previews/dramatic-smithie-item-unlock-streaks-molten-crown-fire.webp +0 -0
  24. package/dist/gamification-previews/dramatic-smithie-mascot.webp +0 -0
  25. package/dist/gamification-previews/mind-locksmith-item-trophy-tasks-anvil-marathon.webp +0 -0
  26. package/dist/gamification-previews/mind-locksmith-item-trophy-xp-levels-the-first-heat.webp +0 -0
  27. package/dist/gamification-previews/mind-locksmith-item-unlock-streaks-molten-crown-fire.webp +0 -0
  28. package/dist/gamification-previews/mind-locksmith-mascot.webp +0 -0
  29. package/dist/index.html +7 -7
  30. package/dist/openclaw/parity.js +27 -0
  31. package/dist/openclaw/plugin-entry-shared.js +2 -2
  32. package/dist/openclaw/plugin-sdk-types.d.ts +2 -1
  33. package/dist/openclaw/routes.d.ts +4 -0
  34. package/dist/openclaw/routes.js +112 -3
  35. package/dist/openclaw/tools.js +32 -4
  36. package/dist/server/server/migrations/059_data_backup_retention.sql +2 -0
  37. package/dist/server/server/src/app.js +288 -61
  38. package/dist/server/server/src/data-management-types.js +2 -0
  39. package/dist/server/server/src/discovery-advertiser.js +13 -0
  40. package/dist/server/server/src/health.js +58 -3
  41. package/dist/server/server/src/movement.js +16 -1
  42. package/dist/server/server/src/openapi.js +410 -9
  43. package/dist/server/server/src/repositories/rewards.js +60 -0
  44. package/dist/server/server/src/services/companion-iroh.js +425 -0
  45. package/dist/server/server/src/services/data-management.js +32 -2
  46. package/dist/server/server/src/services/doctor.js +762 -0
  47. package/dist/server/server/src/services/gamification.js +75 -3
  48. package/dist/server/server/src/services/life-force.js +166 -25
  49. package/dist/server/server/src/web.js +88 -12
  50. package/dist/server/src/lib/api.js +9 -0
  51. package/dist/server/src/lib/gamification-catalog.js +1 -1
  52. package/openclaw.plugin.json +85 -3
  53. package/package.json +10 -6
  54. package/server/migrations/059_data_backup_retention.sql +2 -0
  55. package/skills/forge-openclaw/SKILL.md +80 -19
  56. package/skills/forge-openclaw/entity_conversation_playbooks.md +283 -25
  57. package/skills/forge-openclaw/psyche_entity_playbooks.md +82 -0
  58. package/dist/assets/index-BwKAPo98.css +0 -1
  59. package/dist/assets/index-Dy7c-dRY.js +0 -90
package/README.md CHANGED
@@ -1,14 +1,28 @@
1
1
  # Forge OpenClaw Plugin
2
2
 
3
- `forge-openclaw-plugin` is the publishable OpenClaw package for Forge.
4
- When the plugin targets `localhost` or `127.0.0.1`, it auto-starts the bundled Forge runtime so the local install path stays one-step.
3
+ `forge-openclaw-plugin` is the OpenClaw bridge for Forge.
5
4
 
6
- OpenClaw install note:
5
+ For normal installs, start with the single-command Forge installer:
7
6
 
8
- - `openclaw plugins enable forge-openclaw-plugin` is not always enough by itself.
9
- - If `forge-openclaw-plugin` is missing from `plugins.allow`, OpenClaw can still refuse to load it.
10
- - The install section below includes the `node -e ...` step that repairs `plugins.allow` safely.
11
- - I re-verified on April 21, 2026 that OpenClaw `2026.4.15` still blocks both the published package install and the repo-local install because Forge launches a local runtime and gets flagged by the installer scanner. The bypass sections below are still current.
7
+ ```bash
8
+ npx forge-memory
9
+ ```
10
+
11
+ It installs the Forge UI/runtime first, discovers OpenClaw, Hermes, and Codex in
12
+ the background, lets you choose adapters from a guided checkbox flow, and keeps
13
+ every selected surface pointed at the same real Forge data folder. Use the direct
14
+ OpenClaw commands below only for plugin-specific debugging, source-linking, or
15
+ manual recovery.
16
+
17
+ It gives OpenClaw a clear way to:
18
+
19
+ - start or reach the local Forge runtime
20
+ - open the Forge web app
21
+ - read the current operator overview
22
+ - create and update goals, projects, issues, tasks, notes, wiki pages, health records, preferences, and Psyche records
23
+ - run Forge Doctor when the local setup looks wrong
24
+
25
+ When the plugin targets `localhost` or `127.0.0.1`, it can auto-start the bundled Forge runtime. That is why current OpenClaw installers may ask for explicit approval during install.
12
26
 
13
27
  ## Open the UI
14
28
 
@@ -24,10 +38,18 @@ For a normal local install, the Forge UI address is usually:
24
38
  http://127.0.0.1:4317/forge/
25
39
  ```
26
40
 
27
- That `4317` backend URL is the stable entrypoint. If Forge is running in a local
28
- development checkout, the backend can proxy and supervise the hot-reloading Vite
29
- frontend behind that same `/forge/` URL. Shared routes such as Tailscale should
30
- still target `http://127.0.0.1:4317/forge/`, not `3027` directly.
41
+ That `4317` backend URL is the stable entrypoint for normal local plugin installs.
42
+
43
+ Albert's MacBook also has a repo-local development mode used for plugin/dashboard work.
44
+ The restored 6-hour Tailscale automation exposes `/forge` through the `4317` backend as
45
+ `http://127.0.0.1:4317/forge/`, while that backend is started locally with
46
+ `FORGE_OPENCLAW_DEV=1` and proxies the Vite dev server at `127.0.0.1:3027`. A correct
47
+ dev-mode response contains `/forge/@vite/client` and `/forge/src/main.tsx`.
48
+
49
+ That environment flag is only for the repo-local development machine. Normal plugin
50
+ installs on other machines use the packaged runtime by default and should not be forced
51
+ into source-backed dev mode. The restored automation also must not expose `/forge-dev` or
52
+ point `/forge` at bare `http://127.0.0.1:3027`.
31
53
 
32
54
  You can also ask the agent to call the UI entry tool and return the exact current address.
33
55
 
@@ -35,10 +57,13 @@ If you want Forge to use a specific local data folder, set `dataRoot` in the plu
35
57
 
36
58
  Default data path:
37
59
 
38
- - local installs now default to the shared Forge home at `~/.forge/forge.sqlite`
39
- - set `dataRoot` only when you intentionally want a different shared database
60
+ - local installs default to `~/.forge/forge.sqlite`
61
+ - the user can set `dataRoot` to use another folder
62
+ - when `dataRoot` is set, Forge stores `forge.sqlite` directly inside that folder
63
+
64
+ If you want the data to live somewhere specific for persistence or backup reasons, set `dataRoot` explicitly in the plugin config and restart the gateway. When debugging storage, check the config and the live runtime path before moving or merging database files.
40
65
 
41
- If you want the data to live somewhere else for persistence or backup reasons, set `dataRoot` explicitly in the plugin config and restart the gateway.
66
+ The Forge web app also exposes these controls in `Settings -> Data`. Use it to see the live data folder, move current data, adopt an existing Forge data folder, create a manual backup, enable automatic backups, and choose how many days of automatic backups Forge should keep. Automatic retention only cleans automatic backups; manual and safety backups stay in place.
42
67
 
43
68
  ## What Forge looks like
44
69
 
@@ -116,8 +141,8 @@ Recommended shared setup:
116
141
 
117
142
  1. Run one shared Forge runtime.
118
143
  2. Point OpenClaw, Hermes, and the browser UI at that same runtime.
119
- 3. Let the default shared Forge home `~/.forge` stand unless you intentionally
120
- want a different shared database.
144
+ 3. Use one explicit shared `dataRoot` when several adapters must share the same
145
+ database.
121
146
  4. Create the human and bot users in `Settings -> Users`.
122
147
  5. Use `userId` on writes and `userIds` on reads.
123
148
 
@@ -130,9 +155,9 @@ Current sharing behavior is intentionally clear:
130
155
  tasks, notes, or strategy nodes
131
156
 
132
157
  If OpenClaw and Hermes are supposed to collaborate inside one Forge system, the
133
- important thing is not only matching `origin` and `port`. Local installs now
134
- converge on the same `~/.forge` data root automatically. Only override
135
- `dataRoot` when you deliberately want a different shared database.
158
+ important thing is not only matching `origin` and `port`. Either leave every
159
+ adapter on the default `~/.forge` root or set one explicit `dataRoot`, then
160
+ verify that each live runtime has opened that database.
136
161
 
137
162
  ## Strategies And Alignment Metrics
138
163
 
@@ -213,47 +238,96 @@ OpenClaw tool coverage for those areas is explicit:
213
238
  The sports UI route is `/forge/sports`, while the backend overview route remains
214
239
  `/api/v1/health/fitness`. Sleep lives at `/forge/sleep` and `/api/v1/health/sleep`.
215
240
 
216
- ## Install
241
+ ## Advanced Install
217
242
 
218
- Current OpenClaw builds should use package discovery:
243
+ Prefer `npx forge-memory` for normal installs. The direct commands in this
244
+ section are for OpenClaw-specific debugging, source-linking, and recovery.
245
+
246
+ ### Published Package
247
+
248
+ Use this path when you want the released Forge plugin from npm:
219
249
 
220
250
  ```bash
221
- openclaw plugins install forge-openclaw-plugin
251
+ openclaw plugins install --dangerously-force-unsafe-install forge-openclaw-plugin
222
252
  openclaw plugins enable forge-openclaw-plugin
223
- node -e 'const fs=require("fs"); const p=process.env.HOME+"/.openclaw/openclaw.json"; const j=JSON.parse(fs.readFileSync(p,"utf8")); j.plugins ??= {}; j.plugins.allow = Array.from(new Set([...(j.plugins.allow || []), "forge-openclaw-plugin"])); fs.writeFileSync(p, JSON.stringify(j, null, 2)+"\n");'
224
253
  openclaw gateway restart
225
254
  openclaw forge health
255
+ openclaw forge ui
226
256
  ```
227
257
 
228
- If the install path is blocked on your OpenClaw build, use this temporary npm bypass instead. This is still required on OpenClaw `2026.4.15` as of April 21, 2026:
258
+ Tested on OpenClaw `2026.5.4`: plain `openclaw plugins install forge-openclaw-plugin` is blocked by the plugin scanner because Forge contains local runtime startup helpers. The documented command uses OpenClaw's explicit approval flag and installs without the old config-edit workaround.
259
+
260
+ Check what OpenClaw loaded:
229
261
 
230
262
  ```bash
231
- npm install -g forge-openclaw-plugin
232
- node -e 'const cp=require("child_process"); const fs=require("fs"); const path=require("path"); const p=process.env.HOME+"/.openclaw/openclaw.json"; const j=JSON.parse(fs.readFileSync(p,"utf8")); const pluginPath=path.join(cp.execSync("npm root -g",{encoding:"utf8"}).trim(),"forge-openclaw-plugin"); j.plugins ??= {}; j.plugins.allow = Array.from(new Set([...(j.plugins.allow || []), "forge-openclaw-plugin"])); j.plugins.load ??= {}; j.plugins.load.paths = Array.from(new Set([...(j.plugins.load.paths || []), pluginPath])); j.plugins.entries ??= {}; j.plugins.entries["forge-openclaw-plugin"] = { enabled: true, config: { origin: "http://127.0.0.1", port: 4317, actorLabel: "", timeoutMs: 15000 } }; fs.writeFileSync(p, JSON.stringify(j, null, 2)+"\n"); console.log("Configured", pluginPath);'
233
- openclaw gateway restart
234
- openclaw plugins info forge-openclaw-plugin
263
+ openclaw plugins inspect forge-openclaw-plugin --runtime
235
264
  openclaw forge health
236
265
  ```
237
266
 
238
- That bypass still uses the published npm package. It just tells OpenClaw to load the npm-installed folder directly from `plugins.load.paths`, which avoids the installer block that still happens on OpenClaw `2026.4.15`.
239
-
240
- `openclaw plugins enable forge-openclaw-plugin` marks the plugin enabled, but it does not guarantee that `plugins.allow` was repaired. The `node -e ...` command above preserves the current allow list and appends `"forge-openclaw-plugin"` if it is missing.
267
+ ### Local Development From This Repo
241
268
 
242
- For release-parity local development from this repo:
269
+ Use this path when you are editing Forge and want OpenClaw to load this checkout directly:
243
270
 
244
271
  ```bash
245
- openclaw plugins install ./projects/forge/openclaw-plugin
272
+ openclaw plugins install --link --dangerously-force-unsafe-install ./openclaw-plugin
246
273
  openclaw plugins enable forge-openclaw-plugin
247
- node -e 'const fs=require("fs"); const p=process.env.HOME+"/.openclaw/openclaw.json"; const j=JSON.parse(fs.readFileSync(p,"utf8")); j.plugins ??= {}; j.plugins.allow = Array.from(new Set([...(j.plugins.allow || []), "forge-openclaw-plugin"])); fs.writeFileSync(p, JSON.stringify(j, null, 2)+"\n");'
248
274
  openclaw gateway restart
275
+ openclaw plugins inspect forge-openclaw-plugin --runtime
249
276
  openclaw forge health
250
277
  ```
251
278
 
252
- OpenClaw `2026.4.15` still blocks that repo-local install on this machine, so keep
253
- the repo folder on `plugins.load.paths`, make sure
254
- `openclaw plugins info forge-openclaw-plugin` still points at the local Forge source
255
- path, then restart the gateway and verify health. That fallback still keeps OpenClaw
256
- on the local code folder instead of switching to the published package.
279
+ Use `--link` for active local development. Omit `--link` when you want to test the copied package layout that a normal install receives.
280
+
281
+ If you are running the command from the monorepo root instead of the Forge repo root, use:
282
+
283
+ ```bash
284
+ openclaw plugins install --link --dangerously-force-unsafe-install ./projects/forge/openclaw-plugin
285
+ ```
286
+
287
+ ### Manual Fallback For Older OpenClaw Builds
288
+
289
+ Use this only if your OpenClaw installer does not support `--dangerously-force-unsafe-install` or still refuses to install Forge. It installs the npm package, adds the package folder to `plugins.load.paths`, enables the plugin, and keeps the default local Forge runtime on `127.0.0.1:4317`.
290
+
291
+ ```bash
292
+ npm install -g forge-openclaw-plugin
293
+ node <<'NODE'
294
+ const cp = require("node:child_process");
295
+ const fs = require("node:fs");
296
+ const path = require("node:path");
297
+
298
+ const configPath = path.join(process.env.HOME, ".openclaw", "openclaw.json");
299
+ const pluginPath = path.join(
300
+ cp.execSync("npm root -g", { encoding: "utf8" }).trim(),
301
+ "forge-openclaw-plugin"
302
+ );
303
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
304
+
305
+ config.plugins ??= {};
306
+ config.plugins.allow = Array.from(
307
+ new Set([...(config.plugins.allow ?? []), "forge-openclaw-plugin"])
308
+ );
309
+ config.plugins.load ??= {};
310
+ config.plugins.load.paths = Array.from(
311
+ new Set([...(config.plugins.load.paths ?? []), pluginPath])
312
+ );
313
+ config.plugins.entries ??= {};
314
+ config.plugins.entries["forge-openclaw-plugin"] = {
315
+ enabled: true,
316
+ config: {
317
+ origin: "http://127.0.0.1",
318
+ port: 4317,
319
+ actorLabel: "",
320
+ timeoutMs: 15000
321
+ }
322
+ };
323
+
324
+ fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
325
+ console.log(`Configured ${pluginPath}`);
326
+ NODE
327
+ openclaw gateway restart
328
+ openclaw plugins inspect forge-openclaw-plugin --runtime
329
+ openclaw forge health
330
+ ```
257
331
 
258
332
  Equivalent config:
259
333
 
@@ -265,7 +339,7 @@ Equivalent config:
265
339
  "forge-openclaw-plugin": {
266
340
  enabled: true,
267
341
  config: {
268
- dataRoot: "~/.forge",
342
+ dataRoot: "/absolute/path/to/forge-data",
269
343
  actorLabel: "",
270
344
  apiToken: ""
271
345
  }
@@ -295,7 +369,8 @@ Recommended local behavior:
295
369
 
296
370
  - leave `actorLabel` blank so Forge can inherit the trusted local operator label automatically
297
371
  - leave `apiToken` blank for localhost and trusted Tailscale setups
298
- - leave `dataRoot` alone unless you intentionally want a different shared local Forge home
372
+ - keep `dataRoot` aligned across OpenClaw, Hermes, Codex, and the browser runtime when they should share data
373
+ - before changing or merging data roots, back up every candidate Forge database and verify which database the live runtime is using
299
374
 
300
375
  ## Doctor And Runtime Config
301
376
 
@@ -318,10 +393,12 @@ Diagnostic entrypoints:
318
393
 
319
394
  ```bash
320
395
  openclaw forge doctor
396
+ openclaw forge doctor --json
397
+ openclaw forge doctor --fix
321
398
  npm run doctor --prefix ./projects/forge
322
399
  ```
323
400
 
324
- The doctor output now includes `settingsFile` details such as the resolved path, validity, sync state, parse errors, and which override keys were applied from `forge.json`.
401
+ The doctor output includes explicit runtime, settings, SQLite storage, entity-link, hierarchy, reward, and gamification checks. It also returns concrete issues and proposed fixes. Fixes are never applied by a normal read; `openclaw forge doctor --fix` applies only Doctor-marked safe fixes.
325
402
 
326
403
  Then restart the gateway:
327
404
 
@@ -329,14 +406,7 @@ Then restart the gateway:
329
406
  openclaw gateway restart
330
407
  ```
331
408
 
332
- Older OpenClaw builds can keep using the repo-root fallback entry during the transition:
333
-
334
- ```bash
335
- openclaw plugins install ./projects/forge
336
- openclaw gateway restart
337
- ```
338
-
339
- That repo-local path is the fallback only. The published package stays on the SDK `definePluginEntry` entrypoint. The OpenClaw plugin id is `forge-openclaw-plugin`, while the product name stays `Forge` and the CLI namespace stays `forge`.
409
+ The OpenClaw plugin id is `forge-openclaw-plugin`, the product name is `Forge`, and the CLI namespace is `forge`.
340
410
 
341
411
  ## Recommended usage
342
412
 
@@ -465,7 +535,7 @@ The startup error now points at that log file when the child process exits befor
465
535
  The reliable publication path for the Forge plugin is:
466
536
 
467
537
  1. publish `forge-openclaw-plugin` to npm
468
- 2. verify `openclaw plugins install forge-openclaw-plugin`
538
+ 2. verify `openclaw plugins install --dangerously-force-unsafe-install forge-openclaw-plugin`
469
539
  3. add Forge to the OpenClaw community plugin listing with the npm package and GitHub repo
470
540
 
471
541
  The repo now supports a tag-driven GitHub Actions release path for step 1. The normal
@@ -1,4 +1,4 @@
1
- import{r as c,R as I,a as Ne}from"./vendor-C0otBhgu.js";function Mn(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return c.useMemo(()=>r=>{t.forEach(o=>o(r))},t)}const nt=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function we(e){const t=Object.prototype.toString.call(e);return t==="[object Window]"||t==="[object global]"}function mt(e){return"nodeType"in e}function z(e){var t,n;return e?we(e)?e:mt(e)&&(t=(n=e.ownerDocument)==null?void 0:n.defaultView)!=null?t:window:window}function yt(e){const{Document:t}=z(e);return e instanceof t}function Be(e){return we(e)?!1:e instanceof z(e).HTMLElement}function Vt(e){return e instanceof z(e).SVGElement}function xe(e){return e?we(e)?e.document:mt(e)?yt(e)?e:Be(e)||Vt(e)?e.ownerDocument:document:document:document}const V=nt?c.useLayoutEffect:c.useEffect;function rt(e){const t=c.useRef(e);return V(()=>{t.current=e}),c.useCallback(function(){for(var n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return t.current==null?void 0:t.current(...r)},[])}function On(){const e=c.useRef(null),t=c.useCallback((r,o)=>{e.current=setInterval(r,o)},[]),n=c.useCallback(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[]);return[t,n]}function Pe(e,t){t===void 0&&(t=[e]);const n=c.useRef(e);return V(()=>{n.current!==e&&(n.current=e)},t),n}function Fe(e,t){const n=c.useRef();return c.useMemo(()=>{const r=e(n.current);return n.current=r,r},[...t])}function Je(e){const t=rt(e),n=c.useRef(null),r=c.useCallback(o=>{o!==n.current&&(t==null||t(o,n.current)),n.current=o},[]);return[n,r]}function _e(e){const t=c.useRef();return c.useEffect(()=>{t.current=e},[e]),t.current}let ut={};function $e(e,t){return c.useMemo(()=>{if(t)return t;const n=ut[e]==null?0:ut[e]+1;return ut[e]=n,e+"-"+n},[e,t])}function qt(e){return function(t){for(var n=arguments.length,r=new Array(n>1?n-1:0),o=1;o<n;o++)r[o-1]=arguments[o];return r.reduce((i,s)=>{const a=Object.entries(s);for(const[l,u]of a){const d=i[l];d!=null&&(i[l]=d+e*u)}return i},{...t})}}const ye=qt(1),Qe=qt(-1);function In(e){return"clientX"in e&&"clientY"in e}function ot(e){if(!e)return!1;const{KeyboardEvent:t}=z(e.target);return t&&e instanceof t}function Nn(e){if(!e)return!1;const{TouchEvent:t}=z(e.target);return t&&e instanceof t}function Ze(e){if(Nn(e)){if(e.touches&&e.touches.length){const{clientX:t,clientY:n}=e.touches[0];return{x:t,y:n}}else if(e.changedTouches&&e.changedTouches.length){const{clientX:t,clientY:n}=e.changedTouches[0];return{x:t,y:n}}}return In(e)?{x:e.clientX,y:e.clientY}:null}const fe=Object.freeze({Translate:{toString(e){if(!e)return;const{x:t,y:n}=e;return"translate3d("+(t?Math.round(t):0)+"px, "+(n?Math.round(n):0)+"px, 0)"}},Scale:{toString(e){if(!e)return;const{scaleX:t,scaleY:n}=e;return"scaleX("+t+") scaleY("+n+")"}},Transform:{toString(e){if(e)return[fe.Translate.toString(e),fe.Scale.toString(e)].join(" ")}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+" "+n+"ms "+r}}}),kt="a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]";function Tn(e){return e.matches(kt)?e:e.querySelector(kt)}const Ln={display:"none"};function kn(e){let{id:t,value:n}=e;return I.createElement("div",{id:t,style:Ln},n)}function Pn(e){let{id:t,announcement:n,ariaLiveType:r="assertive"}=e;const o={position:"fixed",top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0 0 0 0)",clipPath:"inset(100%)",whiteSpace:"nowrap"};return I.createElement("div",{id:t,style:o,role:"status","aria-live":r,"aria-atomic":!0},n)}function zn(){const[e,t]=c.useState("");return{announce:c.useCallback(r=>{r!=null&&t(r)},[]),announcement:e}}const Gt=c.createContext(null);function Bn(e){const t=c.useContext(Gt);c.useEffect(()=>{if(!t)throw new Error("useDndMonitor must be used within a children of <DndContext>");return t(e)},[e,t])}function Fn(){const[e]=c.useState(()=>new Set),t=c.useCallback(r=>(e.add(r),()=>e.delete(r)),[e]);return[c.useCallback(r=>{let{type:o,event:i}=r;e.forEach(s=>{var a;return(a=s[o])==null?void 0:a.call(s,i)})},[e]),t]}const $n={draggable:`
1
+ import{r as c,R as I,a as Ne}from"./vendor-BdrT2htV.js";function Mn(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return c.useMemo(()=>r=>{t.forEach(o=>o(r))},t)}const nt=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function we(e){const t=Object.prototype.toString.call(e);return t==="[object Window]"||t==="[object global]"}function mt(e){return"nodeType"in e}function z(e){var t,n;return e?we(e)?e:mt(e)&&(t=(n=e.ownerDocument)==null?void 0:n.defaultView)!=null?t:window:window}function yt(e){const{Document:t}=z(e);return e instanceof t}function Be(e){return we(e)?!1:e instanceof z(e).HTMLElement}function Vt(e){return e instanceof z(e).SVGElement}function xe(e){return e?we(e)?e.document:mt(e)?yt(e)?e:Be(e)||Vt(e)?e.ownerDocument:document:document:document}const V=nt?c.useLayoutEffect:c.useEffect;function rt(e){const t=c.useRef(e);return V(()=>{t.current=e}),c.useCallback(function(){for(var n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return t.current==null?void 0:t.current(...r)},[])}function On(){const e=c.useRef(null),t=c.useCallback((r,o)=>{e.current=setInterval(r,o)},[]),n=c.useCallback(()=>{e.current!==null&&(clearInterval(e.current),e.current=null)},[]);return[t,n]}function Pe(e,t){t===void 0&&(t=[e]);const n=c.useRef(e);return V(()=>{n.current!==e&&(n.current=e)},t),n}function Fe(e,t){const n=c.useRef();return c.useMemo(()=>{const r=e(n.current);return n.current=r,r},[...t])}function Je(e){const t=rt(e),n=c.useRef(null),r=c.useCallback(o=>{o!==n.current&&(t==null||t(o,n.current)),n.current=o},[]);return[n,r]}function _e(e){const t=c.useRef();return c.useEffect(()=>{t.current=e},[e]),t.current}let ut={};function $e(e,t){return c.useMemo(()=>{if(t)return t;const n=ut[e]==null?0:ut[e]+1;return ut[e]=n,e+"-"+n},[e,t])}function qt(e){return function(t){for(var n=arguments.length,r=new Array(n>1?n-1:0),o=1;o<n;o++)r[o-1]=arguments[o];return r.reduce((i,s)=>{const a=Object.entries(s);for(const[l,u]of a){const d=i[l];d!=null&&(i[l]=d+e*u)}return i},{...t})}}const ye=qt(1),Qe=qt(-1);function In(e){return"clientX"in e&&"clientY"in e}function ot(e){if(!e)return!1;const{KeyboardEvent:t}=z(e.target);return t&&e instanceof t}function Nn(e){if(!e)return!1;const{TouchEvent:t}=z(e.target);return t&&e instanceof t}function Ze(e){if(Nn(e)){if(e.touches&&e.touches.length){const{clientX:t,clientY:n}=e.touches[0];return{x:t,y:n}}else if(e.changedTouches&&e.changedTouches.length){const{clientX:t,clientY:n}=e.changedTouches[0];return{x:t,y:n}}}return In(e)?{x:e.clientX,y:e.clientY}:null}const fe=Object.freeze({Translate:{toString(e){if(!e)return;const{x:t,y:n}=e;return"translate3d("+(t?Math.round(t):0)+"px, "+(n?Math.round(n):0)+"px, 0)"}},Scale:{toString(e){if(!e)return;const{scaleX:t,scaleY:n}=e;return"scaleX("+t+") scaleY("+n+")"}},Transform:{toString(e){if(e)return[fe.Translate.toString(e),fe.Scale.toString(e)].join(" ")}},Transition:{toString(e){let{property:t,duration:n,easing:r}=e;return t+" "+n+"ms "+r}}}),kt="a,frame,iframe,input:not([type=hidden]):not(:disabled),select:not(:disabled),textarea:not(:disabled),button:not(:disabled),*[tabindex]";function Tn(e){return e.matches(kt)?e:e.querySelector(kt)}const Ln={display:"none"};function kn(e){let{id:t,value:n}=e;return I.createElement("div",{id:t,style:Ln},n)}function Pn(e){let{id:t,announcement:n,ariaLiveType:r="assertive"}=e;const o={position:"fixed",top:0,left:0,width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0 0 0 0)",clipPath:"inset(100%)",whiteSpace:"nowrap"};return I.createElement("div",{id:t,style:o,role:"status","aria-live":r,"aria-atomic":!0},n)}function zn(){const[e,t]=c.useState("");return{announce:c.useCallback(r=>{r!=null&&t(r)},[]),announcement:e}}const Gt=c.createContext(null);function Bn(e){const t=c.useContext(Gt);c.useEffect(()=>{if(!t)throw new Error("useDndMonitor must be used within a children of <DndContext>");return t(e)},[e,t])}function Fn(){const[e]=c.useState(()=>new Set),t=c.useCallback(r=>(e.add(r),()=>e.delete(r)),[e]);return[c.useCallback(r=>{let{type:o,event:i}=r;e.forEach(s=>{var a;return(a=s[o])==null?void 0:a.call(s,i)})},[e]),t]}const $n={draggable:`
2
2
  To pick up a draggable item, press the space bar.
3
3
  While dragging, use the arrow keys to move the item.
4
4
  Press space again to drop the item in its new position, or press escape to cancel.