forge-openclaw-plugin 0.2.60 → 0.2.61
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/README.md +93 -46
- package/dist/assets/{board-B1V3M__K.js → board-DThHV1D8.js} +1 -1
- package/dist/assets/index-7gvVCqnV.css +1 -0
- package/dist/assets/index-_Cn6Prym.js +90 -0
- package/dist/assets/{motion-CltSTItx.js → motion-BtTJtHCw.js} +1 -1
- package/dist/assets/{table-B-VrSFx8.js → table-Bnw6pcwN.js} +1 -1
- package/dist/assets/{ui-DUqM4jkt.js → ui-CnVxFkj0.js} +1 -1
- package/dist/assets/{vendor-C0otBhgu.js → vendor-BgZ3YrRd.js} +212 -207
- package/dist/gamification-previews/dark-fantasy-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/dark-fantasy-mascot.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/dramatic-smithie-mascot.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-trophy-tasks-anvil-marathon.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-trophy-xp-levels-the-first-heat.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-item-unlock-streaks-molten-crown-fire.webp +0 -0
- package/dist/gamification-previews/mind-locksmith-mascot.webp +0 -0
- package/dist/index.html +7 -7
- package/dist/openclaw/parity.js +27 -0
- package/dist/openclaw/plugin-entry-shared.js +2 -2
- package/dist/openclaw/plugin-sdk-types.d.ts +2 -1
- package/dist/openclaw/routes.d.ts +4 -0
- package/dist/openclaw/routes.js +112 -3
- package/dist/openclaw/tools.js +32 -4
- package/dist/server/server/migrations/059_data_backup_retention.sql +2 -0
- package/dist/server/server/src/app.js +125 -43
- package/dist/server/server/src/data-management-types.js +2 -0
- package/dist/server/server/src/health.js +40 -0
- package/dist/server/server/src/openapi.js +398 -7
- package/dist/server/server/src/repositories/rewards.js +60 -0
- package/dist/server/server/src/services/data-management.js +32 -2
- package/dist/server/server/src/services/doctor.js +762 -0
- package/dist/server/server/src/services/gamification.js +75 -3
- package/dist/server/src/lib/api.js +9 -0
- package/dist/server/src/lib/gamification-catalog.js +1 -1
- package/openclaw.plugin.json +85 -3
- package/package.json +8 -4
- package/server/migrations/059_data_backup_retention.sql +2 -0
- package/skills/forge-openclaw/SKILL.md +38 -19
- package/skills/forge-openclaw/entity_conversation_playbooks.md +66 -8
- package/skills/forge-openclaw/psyche_entity_playbooks.md +23 -0
- package/dist/assets/index-BwKAPo98.css +0 -1
- package/dist/assets/index-Dy7c-dRY.js +0 -90
package/README.md
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# Forge OpenClaw Plugin
|
|
2
2
|
|
|
3
|
-
`forge-openclaw-plugin` is the
|
|
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
|
|
5
|
+
It gives OpenClaw a clear way to:
|
|
7
6
|
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
7
|
+
- start or reach the local Forge runtime
|
|
8
|
+
- open the Forge web app
|
|
9
|
+
- read the current operator overview
|
|
10
|
+
- create and update goals, projects, issues, tasks, notes, wiki pages, health records, preferences, and Psyche records
|
|
11
|
+
- run Forge Doctor when the local setup looks wrong
|
|
12
|
+
|
|
13
|
+
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
14
|
|
|
13
15
|
## Open the UI
|
|
14
16
|
|
|
@@ -35,10 +37,13 @@ If you want Forge to use a specific local data folder, set `dataRoot` in the plu
|
|
|
35
37
|
|
|
36
38
|
Default data path:
|
|
37
39
|
|
|
38
|
-
- local installs
|
|
39
|
-
- set `dataRoot`
|
|
40
|
+
- local installs default to `~/.forge/forge.sqlite`
|
|
41
|
+
- the user can set `dataRoot` to use another folder
|
|
42
|
+
- when `dataRoot` is set, Forge stores `forge.sqlite` directly inside that folder
|
|
43
|
+
|
|
44
|
+
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
45
|
|
|
41
|
-
|
|
46
|
+
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
47
|
|
|
43
48
|
## What Forge looks like
|
|
44
49
|
|
|
@@ -116,8 +121,8 @@ Recommended shared setup:
|
|
|
116
121
|
|
|
117
122
|
1. Run one shared Forge runtime.
|
|
118
123
|
2. Point OpenClaw, Hermes, and the browser UI at that same runtime.
|
|
119
|
-
3.
|
|
120
|
-
|
|
124
|
+
3. Use one explicit shared `dataRoot` when several adapters must share the same
|
|
125
|
+
database.
|
|
121
126
|
4. Create the human and bot users in `Settings -> Users`.
|
|
122
127
|
5. Use `userId` on writes and `userIds` on reads.
|
|
123
128
|
|
|
@@ -130,9 +135,9 @@ Current sharing behavior is intentionally clear:
|
|
|
130
135
|
tasks, notes, or strategy nodes
|
|
131
136
|
|
|
132
137
|
If OpenClaw and Hermes are supposed to collaborate inside one Forge system, the
|
|
133
|
-
important thing is not only matching `origin` and `port`.
|
|
134
|
-
|
|
135
|
-
|
|
138
|
+
important thing is not only matching `origin` and `port`. Either leave every
|
|
139
|
+
adapter on the default `~/.forge` root or set one explicit `dataRoot`, then
|
|
140
|
+
verify that each live runtime has opened that database.
|
|
136
141
|
|
|
137
142
|
## Strategies And Alignment Metrics
|
|
138
143
|
|
|
@@ -215,45 +220,91 @@ The sports UI route is `/forge/sports`, while the backend overview route remains
|
|
|
215
220
|
|
|
216
221
|
## Install
|
|
217
222
|
|
|
218
|
-
|
|
223
|
+
### Published Package
|
|
224
|
+
|
|
225
|
+
Use this path when you want the released Forge plugin from npm:
|
|
219
226
|
|
|
220
227
|
```bash
|
|
221
|
-
openclaw plugins install forge-openclaw-plugin
|
|
228
|
+
openclaw plugins install --dangerously-force-unsafe-install forge-openclaw-plugin
|
|
222
229
|
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
230
|
openclaw gateway restart
|
|
225
231
|
openclaw forge health
|
|
232
|
+
openclaw forge ui
|
|
226
233
|
```
|
|
227
234
|
|
|
228
|
-
|
|
235
|
+
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.
|
|
236
|
+
|
|
237
|
+
Check what OpenClaw loaded:
|
|
229
238
|
|
|
230
239
|
```bash
|
|
231
|
-
|
|
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
|
|
240
|
+
openclaw plugins inspect forge-openclaw-plugin --runtime
|
|
235
241
|
openclaw forge health
|
|
236
242
|
```
|
|
237
243
|
|
|
238
|
-
|
|
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.
|
|
244
|
+
### Local Development From This Repo
|
|
241
245
|
|
|
242
|
-
|
|
246
|
+
Use this path when you are editing Forge and want OpenClaw to load this checkout directly:
|
|
243
247
|
|
|
244
248
|
```bash
|
|
245
|
-
openclaw plugins install ./
|
|
249
|
+
openclaw plugins install --link --dangerously-force-unsafe-install ./openclaw-plugin
|
|
246
250
|
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
251
|
openclaw gateway restart
|
|
252
|
+
openclaw plugins inspect forge-openclaw-plugin --runtime
|
|
249
253
|
openclaw forge health
|
|
250
254
|
```
|
|
251
255
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
256
|
+
Use `--link` for active local development. Omit `--link` when you want to test the copied package layout that a normal install receives.
|
|
257
|
+
|
|
258
|
+
If you are running the command from the monorepo root instead of the Forge repo root, use:
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
openclaw plugins install --link --dangerously-force-unsafe-install ./projects/forge/openclaw-plugin
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Manual Fallback For Older OpenClaw Builds
|
|
265
|
+
|
|
266
|
+
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`.
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
npm install -g forge-openclaw-plugin
|
|
270
|
+
node <<'NODE'
|
|
271
|
+
const cp = require("node:child_process");
|
|
272
|
+
const fs = require("node:fs");
|
|
273
|
+
const path = require("node:path");
|
|
274
|
+
|
|
275
|
+
const configPath = path.join(process.env.HOME, ".openclaw", "openclaw.json");
|
|
276
|
+
const pluginPath = path.join(
|
|
277
|
+
cp.execSync("npm root -g", { encoding: "utf8" }).trim(),
|
|
278
|
+
"forge-openclaw-plugin"
|
|
279
|
+
);
|
|
280
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
281
|
+
|
|
282
|
+
config.plugins ??= {};
|
|
283
|
+
config.plugins.allow = Array.from(
|
|
284
|
+
new Set([...(config.plugins.allow ?? []), "forge-openclaw-plugin"])
|
|
285
|
+
);
|
|
286
|
+
config.plugins.load ??= {};
|
|
287
|
+
config.plugins.load.paths = Array.from(
|
|
288
|
+
new Set([...(config.plugins.load.paths ?? []), pluginPath])
|
|
289
|
+
);
|
|
290
|
+
config.plugins.entries ??= {};
|
|
291
|
+
config.plugins.entries["forge-openclaw-plugin"] = {
|
|
292
|
+
enabled: true,
|
|
293
|
+
config: {
|
|
294
|
+
origin: "http://127.0.0.1",
|
|
295
|
+
port: 4317,
|
|
296
|
+
actorLabel: "",
|
|
297
|
+
timeoutMs: 15000
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
302
|
+
console.log(`Configured ${pluginPath}`);
|
|
303
|
+
NODE
|
|
304
|
+
openclaw gateway restart
|
|
305
|
+
openclaw plugins inspect forge-openclaw-plugin --runtime
|
|
306
|
+
openclaw forge health
|
|
307
|
+
```
|
|
257
308
|
|
|
258
309
|
Equivalent config:
|
|
259
310
|
|
|
@@ -265,7 +316,7 @@ Equivalent config:
|
|
|
265
316
|
"forge-openclaw-plugin": {
|
|
266
317
|
enabled: true,
|
|
267
318
|
config: {
|
|
268
|
-
dataRoot: "
|
|
319
|
+
dataRoot: "/absolute/path/to/forge-data",
|
|
269
320
|
actorLabel: "",
|
|
270
321
|
apiToken: ""
|
|
271
322
|
}
|
|
@@ -295,7 +346,8 @@ Recommended local behavior:
|
|
|
295
346
|
|
|
296
347
|
- leave `actorLabel` blank so Forge can inherit the trusted local operator label automatically
|
|
297
348
|
- leave `apiToken` blank for localhost and trusted Tailscale setups
|
|
298
|
-
-
|
|
349
|
+
- keep `dataRoot` aligned across OpenClaw, Hermes, Codex, and the browser runtime when they should share data
|
|
350
|
+
- before changing or merging data roots, back up every candidate Forge database and verify which database the live runtime is using
|
|
299
351
|
|
|
300
352
|
## Doctor And Runtime Config
|
|
301
353
|
|
|
@@ -318,10 +370,12 @@ Diagnostic entrypoints:
|
|
|
318
370
|
|
|
319
371
|
```bash
|
|
320
372
|
openclaw forge doctor
|
|
373
|
+
openclaw forge doctor --json
|
|
374
|
+
openclaw forge doctor --fix
|
|
321
375
|
npm run doctor --prefix ./projects/forge
|
|
322
376
|
```
|
|
323
377
|
|
|
324
|
-
The doctor output
|
|
378
|
+
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
379
|
|
|
326
380
|
Then restart the gateway:
|
|
327
381
|
|
|
@@ -329,14 +383,7 @@ Then restart the gateway:
|
|
|
329
383
|
openclaw gateway restart
|
|
330
384
|
```
|
|
331
385
|
|
|
332
|
-
|
|
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`.
|
|
386
|
+
The OpenClaw plugin id is `forge-openclaw-plugin`, the product name is `Forge`, and the CLI namespace is `forge`.
|
|
340
387
|
|
|
341
388
|
## Recommended usage
|
|
342
389
|
|
|
@@ -465,7 +512,7 @@ The startup error now points at that log file when the child process exits befor
|
|
|
465
512
|
The reliable publication path for the Forge plugin is:
|
|
466
513
|
|
|
467
514
|
1. publish `forge-openclaw-plugin` to npm
|
|
468
|
-
2. verify `openclaw plugins install forge-openclaw-plugin`
|
|
515
|
+
2. verify `openclaw plugins install --dangerously-force-unsafe-install forge-openclaw-plugin`
|
|
469
516
|
3. add Forge to the OpenClaw community plugin listing with the npm package and GitHub repo
|
|
470
517
|
|
|
471
518
|
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-
|
|
1
|
+
import{r as c,R as I,a as Ne}from"./vendor-BgZ3YrRd.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.
|