forge-openclaw-plugin 0.2.19 → 0.2.21

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 (82) hide show
  1. package/README.md +133 -2
  2. package/dist/assets/board-_C6oMy5w.js +6 -0
  3. package/dist/assets/{board-8L3uX7_O.js.map → board-_C6oMy5w.js.map} +1 -1
  4. package/dist/assets/index-B4A6TooJ.js +63 -0
  5. package/dist/assets/index-B4A6TooJ.js.map +1 -0
  6. package/dist/assets/index-D6Xs_2mo.css +1 -0
  7. package/dist/assets/{motion-1GAqqi8M.js → motion-D4sZgCHd.js} +2 -2
  8. package/dist/assets/{motion-1GAqqi8M.js.map → motion-D4sZgCHd.js.map} +1 -1
  9. package/dist/assets/{table-DBGlgRjk.js → table-BWzTaky1.js} +2 -2
  10. package/dist/assets/{table-DBGlgRjk.js.map → table-BWzTaky1.js.map} +1 -1
  11. package/dist/assets/{ui-iTluWjC4.js → ui-BzK4azQb.js} +7 -7
  12. package/dist/assets/{ui-iTluWjC4.js.map → ui-BzK4azQb.js.map} +1 -1
  13. package/dist/assets/vendor-DT3pnAKJ.css +1 -0
  14. package/dist/assets/vendor-De38P6YR.js +729 -0
  15. package/dist/assets/vendor-De38P6YR.js.map +1 -0
  16. package/dist/assets/viz-C6hfyqzu.js +34 -0
  17. package/dist/assets/viz-C6hfyqzu.js.map +1 -0
  18. package/dist/index.html +9 -9
  19. package/dist/openclaw/parity.d.ts +1 -1
  20. package/dist/openclaw/parity.js +29 -2
  21. package/dist/openclaw/routes.js +207 -24
  22. package/dist/openclaw/tools.js +324 -35
  23. package/dist/server/app.js +2080 -92
  24. package/dist/server/db.js +3 -0
  25. package/dist/server/health.js +1284 -0
  26. package/dist/server/managers/platform/background-job-manager.js +138 -2
  27. package/dist/server/managers/platform/llm-manager.js +126 -0
  28. package/dist/server/managers/platform/openai-responses-provider.js +773 -0
  29. package/dist/server/managers/runtime.js +6 -1
  30. package/dist/server/openapi.js +718 -0
  31. package/dist/server/preferences-seeds.js +409 -0
  32. package/dist/server/preferences-types.js +368 -0
  33. package/dist/server/psyche-types.js +42 -18
  34. package/dist/server/repositories/activity-events.js +53 -4
  35. package/dist/server/repositories/calendar.js +89 -15
  36. package/dist/server/repositories/collaboration.js +8 -3
  37. package/dist/server/repositories/diagnostic-logs.js +243 -0
  38. package/dist/server/repositories/entity-ownership.js +92 -0
  39. package/dist/server/repositories/goals.js +7 -2
  40. package/dist/server/repositories/habits.js +122 -16
  41. package/dist/server/repositories/notes.js +119 -41
  42. package/dist/server/repositories/preferences.js +1765 -0
  43. package/dist/server/repositories/projects.js +18 -7
  44. package/dist/server/repositories/psyche.js +84 -27
  45. package/dist/server/repositories/rewards.js +112 -4
  46. package/dist/server/repositories/strategies.js +450 -0
  47. package/dist/server/repositories/tags.js +11 -6
  48. package/dist/server/repositories/task-runs.js +10 -2
  49. package/dist/server/repositories/tasks.js +99 -17
  50. package/dist/server/repositories/users.js +417 -0
  51. package/dist/server/repositories/wiki-memory.js +3366 -0
  52. package/dist/server/services/context.js +20 -18
  53. package/dist/server/services/dashboard.js +29 -6
  54. package/dist/server/services/entity-crud.js +21 -3
  55. package/dist/server/services/insights.js +9 -7
  56. package/dist/server/services/projects.js +2 -1
  57. package/dist/server/services/psyche.js +10 -9
  58. package/dist/server/types.js +594 -30
  59. package/openclaw.plugin.json +1 -1
  60. package/package.json +1 -1
  61. package/server/migrations/015_multi_user_and_strategies.sql +244 -0
  62. package/server/migrations/016_health_companion.sql +158 -0
  63. package/server/migrations/016_strategy_contracts_and_user_graph.sql +22 -0
  64. package/server/migrations/017_preferences.sql +131 -0
  65. package/server/migrations/018_preference_catalogs.sql +31 -0
  66. package/server/migrations/019_wiki_memory.sql +255 -0
  67. package/server/migrations/020_wiki_page_hierarchy.sql +11 -0
  68. package/server/migrations/021_hide_evidence_from_wiki_index.sql +3 -0
  69. package/server/migrations/022_wiki_ingest_background.sql +85 -0
  70. package/server/migrations/023_diagnostic_logs.sql +28 -0
  71. package/skills/forge-openclaw/SKILL.md +126 -34
  72. package/skills/forge-openclaw/entity_conversation_playbooks.md +337 -0
  73. package/skills/forge-openclaw/psyche_entity_playbooks.md +404 -0
  74. package/dist/assets/board-8L3uX7_O.js +0 -6
  75. package/dist/assets/index-Cj1IBH_w.js +0 -36
  76. package/dist/assets/index-Cj1IBH_w.js.map +0 -1
  77. package/dist/assets/index-DQT6EbuS.css +0 -1
  78. package/dist/assets/vendor-BvM2F9Dp.js +0 -503
  79. package/dist/assets/vendor-BvM2F9Dp.js.map +0 -1
  80. package/dist/assets/vendor-CRS-psbw.css +0 -1
  81. package/dist/assets/viz-CNeunkfu.js +0 -34
  82. package/dist/assets/viz-CNeunkfu.js.map +0 -1
package/dist/index.html CHANGED
@@ -13,15 +13,15 @@
13
13
  />
14
14
  <link rel="icon" type="image/png" href="/forge/assets/favicon-BCHm9dUV.ico" />
15
15
  <link rel="alternate icon" href="/forge/assets/favicon-BCHm9dUV.ico" />
16
- <script type="module" crossorigin src="/forge/assets/index-Cj1IBH_w.js"></script>
17
- <link rel="modulepreload" crossorigin href="/forge/assets/vendor-BvM2F9Dp.js">
18
- <link rel="modulepreload" crossorigin href="/forge/assets/motion-1GAqqi8M.js">
19
- <link rel="modulepreload" crossorigin href="/forge/assets/ui-iTluWjC4.js">
20
- <link rel="modulepreload" crossorigin href="/forge/assets/table-DBGlgRjk.js">
21
- <link rel="modulepreload" crossorigin href="/forge/assets/viz-CNeunkfu.js">
22
- <link rel="modulepreload" crossorigin href="/forge/assets/board-8L3uX7_O.js">
23
- <link rel="stylesheet" crossorigin href="/forge/assets/vendor-CRS-psbw.css">
24
- <link rel="stylesheet" crossorigin href="/forge/assets/index-DQT6EbuS.css">
16
+ <script type="module" crossorigin src="/forge/assets/index-B4A6TooJ.js"></script>
17
+ <link rel="modulepreload" crossorigin href="/forge/assets/viz-C6hfyqzu.js">
18
+ <link rel="modulepreload" crossorigin href="/forge/assets/vendor-De38P6YR.js">
19
+ <link rel="modulepreload" crossorigin href="/forge/assets/ui-BzK4azQb.js">
20
+ <link rel="modulepreload" crossorigin href="/forge/assets/motion-D4sZgCHd.js">
21
+ <link rel="modulepreload" crossorigin href="/forge/assets/table-BWzTaky1.js">
22
+ <link rel="modulepreload" crossorigin href="/forge/assets/board-_C6oMy5w.js">
23
+ <link rel="stylesheet" crossorigin href="/forge/assets/vendor-DT3pnAKJ.css">
24
+ <link rel="stylesheet" crossorigin href="/forge/assets/index-D6Xs_2mo.css">
25
25
  </head>
26
26
  <body class="bg-canvas text-ink antialiased">
27
27
  <div id="root"></div>
@@ -2,7 +2,7 @@ export type ApiRouteKey = `${Uppercase<string>} ${string}`;
2
2
  export type ForgeSupportedPluginApiRoute = {
3
3
  method: Uppercase<string>;
4
4
  path: string;
5
- purpose: "diagnostics" | "overview" | "operator_context" | "onboarding" | "psyche" | "xp" | "weekly_review" | "entities" | "work" | "insights";
5
+ purpose: "diagnostics" | "overview" | "operator_context" | "onboarding" | "psyche" | "xp" | "weekly_review" | "entities" | "work" | "insights" | "wiki" | "health";
6
6
  };
7
7
  export declare const FORGE_SUPPORTED_PLUGIN_API_ROUTES: ForgeSupportedPluginApiRoute[];
8
8
  export declare function makeApiRouteKey(method: string, path: string): ApiRouteKey;
@@ -1,11 +1,34 @@
1
1
  export const FORGE_SUPPORTED_PLUGIN_API_ROUTES = [
2
2
  { method: "GET", path: "/api/v1/health", purpose: "diagnostics" },
3
+ {
4
+ method: "GET",
5
+ path: "/api/v1/users/directory",
6
+ purpose: "operator_context"
7
+ },
3
8
  { method: "GET", path: "/api/v1/operator/overview", purpose: "overview" },
4
- { method: "GET", path: "/api/v1/operator/context", purpose: "operator_context" },
9
+ {
10
+ method: "GET",
11
+ path: "/api/v1/operator/context",
12
+ purpose: "operator_context"
13
+ },
5
14
  { method: "GET", path: "/api/v1/agents/onboarding", purpose: "onboarding" },
6
15
  { method: "GET", path: "/api/v1/psyche/overview", purpose: "psyche" },
7
16
  { method: "GET", path: "/api/v1/metrics/xp", purpose: "xp" },
8
17
  { method: "GET", path: "/api/v1/reviews/weekly", purpose: "weekly_review" },
18
+ { method: "GET", path: "/api/v1/wiki/settings", purpose: "wiki" },
19
+ { method: "GET", path: "/api/v1/wiki/pages", purpose: "wiki" },
20
+ { method: "GET", path: "/api/v1/wiki/pages/:id", purpose: "wiki" },
21
+ { method: "GET", path: "/api/v1/wiki/health", purpose: "wiki" },
22
+ { method: "POST", path: "/api/v1/wiki/search", purpose: "wiki" },
23
+ { method: "POST", path: "/api/v1/wiki/pages", purpose: "wiki" },
24
+ { method: "PATCH", path: "/api/v1/wiki/pages/:id", purpose: "wiki" },
25
+ { method: "POST", path: "/api/v1/wiki/sync", purpose: "wiki" },
26
+ { method: "POST", path: "/api/v1/wiki/reindex", purpose: "wiki" },
27
+ { method: "POST", path: "/api/v1/wiki/ingest-jobs", purpose: "wiki" },
28
+ { method: "GET", path: "/api/v1/health/sleep", purpose: "health" },
29
+ { method: "PATCH", path: "/api/v1/health/sleep/:id", purpose: "health" },
30
+ { method: "GET", path: "/api/v1/health/fitness", purpose: "health" },
31
+ { method: "PATCH", path: "/api/v1/health/workouts/:id", purpose: "health" },
9
32
  { method: "POST", path: "/api/v1/entities/search", purpose: "entities" },
10
33
  { method: "POST", path: "/api/v1/entities/create", purpose: "entities" },
11
34
  { method: "POST", path: "/api/v1/entities/update", purpose: "entities" },
@@ -15,7 +38,11 @@ export const FORGE_SUPPORTED_PLUGIN_API_ROUTES = [
15
38
  { method: "POST", path: "/api/v1/work-adjustments", purpose: "work" },
16
39
  { method: "POST", path: "/api/v1/tasks/:id/runs", purpose: "work" },
17
40
  { method: "GET", path: "/api/v1/task-runs", purpose: "work" },
18
- { method: "POST", path: "/api/v1/task-runs/:id/heartbeat", purpose: "work" },
41
+ {
42
+ method: "POST",
43
+ path: "/api/v1/task-runs/:id/heartbeat",
44
+ purpose: "work"
45
+ },
19
46
  { method: "POST", path: "/api/v1/task-runs/:id/focus", purpose: "work" },
20
47
  { method: "POST", path: "/api/v1/task-runs/:id/complete", purpose: "work" },
21
48
  { method: "POST", path: "/api/v1/task-runs/:id/release", purpose: "work" },
@@ -54,7 +54,9 @@ async function forwardOperation(request, response, config, operation, match, url
54
54
  if (operation.requiresToken) {
55
55
  requireApiToken(config);
56
56
  }
57
- const body = operation.requestBody === "json" ? await readJsonRequestBody(request, { emptyObject: true }) : undefined;
57
+ const body = operation.requestBody === "json"
58
+ ? await readJsonRequestBody(request, { emptyObject: true })
59
+ : undefined;
58
60
  const result = await callConfiguredForgeApi(config, {
59
61
  method: operation.method,
60
62
  path: operation.target(match, url),
@@ -83,7 +85,9 @@ async function handleGroup(request, response, config, group) {
83
85
  }
84
86
  const matchedOperation = matchingOperations.find((entry) => entry.operation.method === method);
85
87
  if (!matchedOperation) {
86
- methodNotAllowed(response, [...new Set(matchingOperations.map((entry) => entry.operation.method))]);
88
+ methodNotAllowed(response, [
89
+ ...new Set(matchingOperations.map((entry) => entry.operation.method))
90
+ ]);
87
91
  return;
88
92
  }
89
93
  await forwardOperation(request, response, config, matchedOperation.operation, matchedOperation.match, url);
@@ -95,7 +99,9 @@ async function handleGroup(request, response, config, group) {
95
99
  const exact = (path, operation) => ({
96
100
  path,
97
101
  match: "exact",
98
- operations: [{ ...operation, pattern: new RegExp(`^${path.replaceAll("/", "\\/")}$`) }]
102
+ operations: [
103
+ { ...operation, pattern: new RegExp(`^${path.replaceAll("/", "\\/")}$`) }
104
+ ]
99
105
  });
100
106
  export const FORGE_PLUGIN_ROUTE_GROUPS = [
101
107
  exact("/forge/v1/health", {
@@ -118,6 +124,11 @@ export const FORGE_PLUGIN_ROUTE_GROUPS = [
118
124
  upstreamPath: "/api/v1/agents/onboarding",
119
125
  target: (_match, url) => passthroughSearch("/api/v1/agents/onboarding", url)
120
126
  }),
127
+ exact("/forge/v1/users/directory", {
128
+ method: "GET",
129
+ upstreamPath: "/api/v1/users/directory",
130
+ target: (_match, url) => passthroughSearch("/api/v1/users/directory", url)
131
+ }),
121
132
  exact("/forge/v1/psyche/overview", {
122
133
  method: "GET",
123
134
  upstreamPath: "/api/v1/psyche/overview",
@@ -133,6 +144,26 @@ export const FORGE_PLUGIN_ROUTE_GROUPS = [
133
144
  upstreamPath: "/api/v1/reviews/weekly",
134
145
  target: (_match, url) => passthroughSearch("/api/v1/reviews/weekly", url)
135
146
  }),
147
+ exact("/forge/v1/wiki/settings", {
148
+ method: "GET",
149
+ upstreamPath: "/api/v1/wiki/settings",
150
+ target: (_match, url) => passthroughSearch("/api/v1/wiki/settings", url)
151
+ }),
152
+ exact("/forge/v1/wiki/health", {
153
+ method: "GET",
154
+ upstreamPath: "/api/v1/wiki/health",
155
+ target: (_match, url) => passthroughSearch("/api/v1/wiki/health", url)
156
+ }),
157
+ exact("/forge/v1/health/sleep", {
158
+ method: "GET",
159
+ upstreamPath: "/api/v1/health/sleep",
160
+ target: (_match, url) => passthroughSearch("/api/v1/health/sleep", url)
161
+ }),
162
+ exact("/forge/v1/health/fitness", {
163
+ method: "GET",
164
+ upstreamPath: "/api/v1/health/fitness",
165
+ target: (_match, url) => passthroughSearch("/api/v1/health/fitness", url)
166
+ }),
136
167
  exact("/forge/v1/operator/log-work", {
137
168
  method: "POST",
138
169
  upstreamPath: "/api/v1/operator/log-work",
@@ -154,6 +185,100 @@ export const FORGE_PLUGIN_ROUTE_GROUPS = [
154
185
  requiresToken: true,
155
186
  target: (_match, url) => passthroughSearch("/api/v1/insights", url)
156
187
  }),
188
+ {
189
+ path: "/forge/v1/wiki/pages",
190
+ match: "prefix",
191
+ operations: [
192
+ {
193
+ method: "GET",
194
+ pattern: /^\/forge\/v1\/wiki\/pages$/,
195
+ upstreamPath: "/api/v1/wiki/pages",
196
+ target: (_match, url) => passthroughSearch("/api/v1/wiki/pages", url)
197
+ },
198
+ {
199
+ method: "POST",
200
+ pattern: /^\/forge\/v1\/wiki\/pages$/,
201
+ upstreamPath: "/api/v1/wiki/pages",
202
+ requestBody: "json",
203
+ requiresToken: true,
204
+ target: (_match, url) => passthroughSearch("/api/v1/wiki/pages", url)
205
+ },
206
+ {
207
+ method: "GET",
208
+ pattern: /^\/forge\/v1\/wiki\/pages\/([^/]+)$/,
209
+ upstreamPath: "/api/v1/wiki/pages/:id",
210
+ target: (match, url) => passthroughSearch(`/api/v1/wiki/pages/${match[1]}`, url)
211
+ },
212
+ {
213
+ method: "PATCH",
214
+ pattern: /^\/forge\/v1\/wiki\/pages\/([^/]+)$/,
215
+ upstreamPath: "/api/v1/wiki/pages/:id",
216
+ requestBody: "json",
217
+ requiresToken: true,
218
+ target: (match, url) => passthroughSearch(`/api/v1/wiki/pages/${match[1]}`, url)
219
+ }
220
+ ]
221
+ },
222
+ {
223
+ path: "/forge/v1/wiki",
224
+ match: "prefix",
225
+ operations: [
226
+ {
227
+ method: "POST",
228
+ pattern: /^\/forge\/v1\/wiki\/search$/,
229
+ upstreamPath: "/api/v1/wiki/search",
230
+ requestBody: "json",
231
+ requiresToken: true,
232
+ target: (_match, url) => passthroughSearch("/api/v1/wiki/search", url)
233
+ },
234
+ {
235
+ method: "POST",
236
+ pattern: /^\/forge\/v1\/wiki\/sync$/,
237
+ upstreamPath: "/api/v1/wiki/sync",
238
+ requestBody: "json",
239
+ requiresToken: true,
240
+ target: (_match, url) => passthroughSearch("/api/v1/wiki/sync", url)
241
+ },
242
+ {
243
+ method: "POST",
244
+ pattern: /^\/forge\/v1\/wiki\/reindex$/,
245
+ upstreamPath: "/api/v1/wiki/reindex",
246
+ requestBody: "json",
247
+ requiresToken: true,
248
+ target: (_match, url) => passthroughSearch("/api/v1/wiki/reindex", url)
249
+ },
250
+ {
251
+ method: "POST",
252
+ pattern: /^\/forge\/v1\/wiki\/ingest-jobs$/,
253
+ upstreamPath: "/api/v1/wiki/ingest-jobs",
254
+ requestBody: "json",
255
+ requiresToken: true,
256
+ target: (_match, url) => passthroughSearch("/api/v1/wiki/ingest-jobs", url)
257
+ }
258
+ ]
259
+ },
260
+ {
261
+ path: "/forge/v1/health",
262
+ match: "prefix",
263
+ operations: [
264
+ {
265
+ method: "PATCH",
266
+ pattern: /^\/forge\/v1\/health\/sleep\/([^/]+)$/,
267
+ upstreamPath: "/api/v1/health/sleep/:id",
268
+ requestBody: "json",
269
+ requiresToken: true,
270
+ target: (match, url) => passthroughSearch(`/api/v1/health/sleep/${match[1]}`, url)
271
+ },
272
+ {
273
+ method: "PATCH",
274
+ pattern: /^\/forge\/v1\/health\/workouts\/([^/]+)$/,
275
+ upstreamPath: "/api/v1/health/workouts/:id",
276
+ requestBody: "json",
277
+ requiresToken: true,
278
+ target: (match, url) => passthroughSearch(`/api/v1/health/workouts/${match[1]}`, url)
279
+ }
280
+ ]
281
+ },
157
282
  {
158
283
  path: "/forge/v1/entities",
159
284
  match: "prefix",
@@ -264,17 +389,28 @@ export const FORGE_PLUGIN_ROUTE_GROUPS = [
264
389
  })
265
390
  ];
266
391
  export function collectMirroredApiRouteKeys() {
267
- return new Set(FORGE_PLUGIN_ROUTE_GROUPS.flatMap((group) => group.operations.flatMap((operation) => ("upstreamPath" in operation ? [makeApiRouteKey(operation.method, operation.upstreamPath)] : []))));
392
+ return new Set(FORGE_PLUGIN_ROUTE_GROUPS.flatMap((group) => group.operations.flatMap((operation) => "upstreamPath" in operation
393
+ ? [makeApiRouteKey(operation.method, operation.upstreamPath)]
394
+ : [])));
268
395
  }
269
396
  export function buildRouteParityReport(pathMap) {
270
397
  const mirrored = collectMirroredApiRouteKeys();
271
398
  const supported = collectSupportedPluginApiRouteKeys();
272
399
  const openApiRoutes = new Set(Object.entries(pathMap)
273
400
  .flatMap(([path, methods]) => Object.keys(methods).map((method) => makeApiRouteKey(method, path)))
274
- .filter((key) => key.startsWith("GET /api/v1") || key.startsWith("POST /api/v1") || key.startsWith("PATCH /api/v1") || key.startsWith("DELETE /api/v1")));
275
- const missingFromPlugin = [...supported].filter((key) => !mirrored.has(key)).sort();
276
- const missingFromOpenApi = [...supported].filter((key) => !openApiRoutes.has(key)).sort();
277
- const unexpectedMirrors = [...mirrored].filter((key) => !supported.has(key)).sort();
401
+ .filter((key) => key.startsWith("GET /api/v1") ||
402
+ key.startsWith("POST /api/v1") ||
403
+ key.startsWith("PATCH /api/v1") ||
404
+ key.startsWith("DELETE /api/v1")));
405
+ const missingFromPlugin = [...supported]
406
+ .filter((key) => !mirrored.has(key))
407
+ .sort();
408
+ const missingFromOpenApi = [...supported]
409
+ .filter((key) => !openApiRoutes.has(key))
410
+ .sort();
411
+ const unexpectedMirrors = [...mirrored]
412
+ .filter((key) => !supported.has(key))
413
+ .sort();
278
414
  return {
279
415
  supported: [...supported].sort(),
280
416
  mirrored: [...mirrored].sort(),
@@ -311,7 +447,11 @@ async function runReadOnly(config, path) {
311
447
  }
312
448
  async function runRouteCheck(config) {
313
449
  const openapi = await runReadOnly(config, "/api/v1/openapi.json");
314
- const pathMap = typeof openapi === "object" && openapi !== null && "paths" in openapi && typeof openapi.paths === "object" && openapi.paths !== null
450
+ const pathMap = typeof openapi === "object" &&
451
+ openapi !== null &&
452
+ "paths" in openapi &&
453
+ typeof openapi.paths === "object" &&
454
+ openapi.paths !== null
315
455
  ? openapi.paths
316
456
  : {};
317
457
  return buildRouteParityReport(pathMap);
@@ -324,13 +464,21 @@ async function runDoctor(config) {
324
464
  runRouteCheck(config),
325
465
  resolveForgeUiUrl(config)
326
466
  ]);
327
- const overviewBody = typeof overview === "object" && overview !== null && "overview" in overview && typeof overview.overview === "object" && overview.overview !== null
467
+ const overviewBody = typeof overview === "object" &&
468
+ overview !== null &&
469
+ "overview" in overview &&
470
+ typeof overview.overview === "object" &&
471
+ overview.overview !== null
328
472
  ? overview.overview
329
473
  : null;
330
- const capabilities = overviewBody && typeof overviewBody.capabilities === "object" && overviewBody.capabilities !== null
474
+ const capabilities = overviewBody &&
475
+ typeof overviewBody.capabilities === "object" &&
476
+ overviewBody.capabilities !== null
331
477
  ? overviewBody.capabilities
332
478
  : null;
333
- const overviewWarnings = Array.isArray(overviewBody?.warnings) ? overviewBody.warnings.filter((entry) => typeof entry === "string") : [];
479
+ const overviewWarnings = Array.isArray(overviewBody?.warnings)
480
+ ? overviewBody.warnings.filter((entry) => typeof entry === "string")
481
+ : [];
334
482
  const warnings = [];
335
483
  const canBootstrap = canBootstrapOperatorSession(config.baseUrl);
336
484
  if (config.apiToken.trim().length === 0 && canBootstrap) {
@@ -375,29 +523,64 @@ async function runDoctor(config) {
375
523
  }
376
524
  export function registerForgePluginCli(api, config) {
377
525
  api.registerCli?.(({ program }) => {
378
- const command = program.command("forge").description("Inspect and operate Forge through the OpenClaw plugin");
379
- command.command("health").description("Check Forge health").action(createCliAction(config, "/api/v1/health"));
380
- command.command("overview").description("Fetch the one-shot Forge operator overview").action(createCliAction(config, "/api/v1/operator/overview"));
381
- command.command("onboarding").description("Print the Forge agent onboarding contract").action(createCliAction(config, "/api/v1/agents/onboarding"));
382
- command.command("ui").description("Print the Forge UI entrypoint").action(async () => {
383
- console.log(JSON.stringify({ webAppUrl: await resolveForgeUiUrl(config), pluginUiRoute: "/forge/v1/ui" }, null, 2));
526
+ const command = program
527
+ .command("forge")
528
+ .description("Inspect and operate Forge through the OpenClaw plugin");
529
+ command
530
+ .command("health")
531
+ .description("Check Forge health")
532
+ .action(createCliAction(config, "/api/v1/health"));
533
+ command
534
+ .command("overview")
535
+ .description("Fetch the one-shot Forge operator overview")
536
+ .action(createCliAction(config, "/api/v1/operator/overview"));
537
+ command
538
+ .command("onboarding")
539
+ .description("Print the Forge agent onboarding contract")
540
+ .action(createCliAction(config, "/api/v1/agents/onboarding"));
541
+ command
542
+ .command("ui")
543
+ .description("Print the Forge UI entrypoint")
544
+ .action(async () => {
545
+ console.log(JSON.stringify({
546
+ webAppUrl: await resolveForgeUiUrl(config),
547
+ pluginUiRoute: "/forge/v1/ui"
548
+ }, null, 2));
384
549
  });
385
- command.command("start").description("Start the local Forge runtime when it is managed by the OpenClaw plugin").action(async () => {
550
+ command
551
+ .command("start")
552
+ .description("Start the local Forge runtime when it is managed by the OpenClaw plugin")
553
+ .action(async () => {
386
554
  console.log(JSON.stringify(await startForgeRuntime(config), null, 2));
387
555
  });
388
- command.command("stop").description("Stop the local Forge runtime when it was auto-started by the OpenClaw plugin").action(async () => {
556
+ command
557
+ .command("stop")
558
+ .description("Stop the local Forge runtime when it was auto-started by the OpenClaw plugin")
559
+ .action(async () => {
389
560
  console.log(JSON.stringify(await stopForgeRuntime(config), null, 2));
390
561
  });
391
- command.command("restart").description("Restart the local Forge runtime when it is managed by the OpenClaw plugin").action(async () => {
562
+ command
563
+ .command("restart")
564
+ .description("Restart the local Forge runtime when it is managed by the OpenClaw plugin")
565
+ .action(async () => {
392
566
  console.log(JSON.stringify(await restartForgeRuntime(config), null, 2));
393
567
  });
394
- command.command("status").description("Report whether the local Forge runtime is running and whether it is plugin-managed").action(async () => {
568
+ command
569
+ .command("status")
570
+ .description("Report whether the local Forge runtime is running and whether it is plugin-managed")
571
+ .action(async () => {
395
572
  console.log(JSON.stringify(await getForgeRuntimeStatus(config), null, 2));
396
573
  });
397
- command.command("doctor").description("Run plugin connectivity and curated route diagnostics").action(async () => {
574
+ command
575
+ .command("doctor")
576
+ .description("Run plugin connectivity and curated route diagnostics")
577
+ .action(async () => {
398
578
  console.log(JSON.stringify(await runDoctor(config), null, 2));
399
579
  });
400
- command.command("route-check").description("Compare curated plugin route coverage against the live Forge OpenAPI paths").action(async () => {
580
+ command
581
+ .command("route-check")
582
+ .description("Compare curated plugin route coverage against the live Forge OpenAPI paths")
583
+ .action(async () => {
401
584
  console.log(JSON.stringify(await runRouteCheck(config), null, 2));
402
585
  });
403
586
  }, { commands: ["forge"] });