forge-openclaw-plugin 0.2.24 → 0.2.26

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 (208) hide show
  1. package/README.md +13 -0
  2. package/dist/assets/{board-_C6oMy5w.js → board-ta0rUHOf.js} +3 -3
  3. package/dist/assets/{board-_C6oMy5w.js.map → board-ta0rUHOf.js.map} +1 -1
  4. package/dist/assets/index-Ro0ZF_az.css +1 -0
  5. package/dist/assets/index-ytlpSj23.js +79 -0
  6. package/dist/assets/index-ytlpSj23.js.map +1 -0
  7. package/dist/assets/{motion-D4sZgCHd.js → motion-fBKPB6yw.js} +3 -3
  8. package/dist/assets/motion-fBKPB6yw.js.map +1 -0
  9. package/dist/assets/{table-BWzTaky1.js → table-C-IGTQni.js} +2 -2
  10. package/dist/assets/{table-BWzTaky1.js.map → table-C-IGTQni.js.map} +1 -1
  11. package/dist/assets/{ui-BzK4azQb.js → ui-DInOpaYF.js} +2 -2
  12. package/dist/assets/{ui-BzK4azQb.js.map → ui-DInOpaYF.js.map} +1 -1
  13. package/dist/assets/vendor-lE3tZJcC.js +876 -0
  14. package/dist/assets/vendor-lE3tZJcC.js.map +1 -0
  15. package/dist/index.html +7 -8
  16. package/dist/openclaw/local-runtime.d.ts +3 -1
  17. package/dist/openclaw/local-runtime.js +51 -15
  18. package/dist/openclaw/parity.d.ts +1 -1
  19. package/dist/openclaw/parity.js +29 -0
  20. package/dist/openclaw/plugin-entry-shared.d.ts +1 -0
  21. package/dist/openclaw/plugin-entry-shared.js +31 -6
  22. package/dist/openclaw/plugin-sdk-types.d.ts +29 -0
  23. package/dist/openclaw/routes.js +236 -0
  24. package/dist/openclaw/session-bootstrap.d.ts +78 -0
  25. package/dist/openclaw/session-bootstrap.js +240 -0
  26. package/dist/openclaw/tools.js +279 -6
  27. package/dist/server/server/migrations/001_core.sql +411 -0
  28. package/dist/server/server/migrations/002_psyche.sql +392 -0
  29. package/dist/server/server/migrations/003_habits.sql +30 -0
  30. package/dist/server/server/migrations/004_habit_links.sql +8 -0
  31. package/dist/server/server/migrations/005_habit_psyche_links.sql +24 -0
  32. package/dist/server/server/migrations/006_work_adjustments.sql +14 -0
  33. package/dist/server/server/migrations/007_weekly_review_closures.sql +17 -0
  34. package/dist/server/server/migrations/008_calendar_execution.sql +147 -0
  35. package/dist/server/server/migrations/009_true_calendar_events.sql +195 -0
  36. package/dist/server/server/migrations/010_calendar_selection_state.sql +6 -0
  37. package/dist/server/server/migrations/011_calendar_timezone_backfill.sql +11 -0
  38. package/dist/server/server/migrations/012_work_block_ranges.sql +7 -0
  39. package/dist/server/server/migrations/013_microsoft_local_auth_settings.sql +8 -0
  40. package/dist/server/server/migrations/014_note_tags_and_ephemeral.sql +8 -0
  41. package/dist/server/server/migrations/015_multi_user_and_strategies.sql +244 -0
  42. package/dist/server/server/migrations/016_health_companion.sql +158 -0
  43. package/dist/server/server/migrations/016_strategy_contracts_and_user_graph.sql +22 -0
  44. package/dist/server/server/migrations/017_preferences.sql +131 -0
  45. package/dist/server/server/migrations/018_preference_catalogs.sql +31 -0
  46. package/dist/server/server/migrations/019_wiki_memory.sql +255 -0
  47. package/dist/server/server/migrations/020_wiki_page_hierarchy.sql +11 -0
  48. package/dist/server/server/migrations/021_hide_evidence_from_wiki_index.sql +3 -0
  49. package/dist/server/server/migrations/022_wiki_ingest_background.sql +85 -0
  50. package/dist/server/server/migrations/023_diagnostic_logs.sql +28 -0
  51. package/dist/server/server/migrations/024_questionnaires.sql +96 -0
  52. package/dist/server/server/migrations/025_ai_model_connections.sql +26 -0
  53. package/dist/server/server/migrations/026_custom_theme_settings.sql +2 -0
  54. package/dist/server/server/migrations/027_ai_processors.sql +31 -0
  55. package/dist/server/server/migrations/028_movement_domain.sql +136 -0
  56. package/dist/server/server/migrations/029_watch_micro_capture.sql +23 -0
  57. package/dist/server/server/migrations/030_surface_layouts.sql +5 -0
  58. package/dist/server/server/migrations/031_ai_processor_runtime_upgrades.sql +10 -0
  59. package/dist/server/server/migrations/032_ai_connectors.sql +44 -0
  60. package/dist/server/server/migrations/033_movement_trip_point_sync.sql +36 -0
  61. package/dist/server/server/migrations/034_movement_segment_sync.sql +49 -0
  62. package/dist/server/server/migrations/035_google_local_auth_settings.sql +2 -0
  63. package/dist/server/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  64. package/dist/server/{app.js → server/src/app.js} +992 -25
  65. package/dist/server/server/src/connectors/box-registry.js +188 -0
  66. package/dist/server/{db.js → server/src/db.js} +6 -0
  67. package/dist/server/server/src/debug.js +19 -0
  68. package/dist/server/server/src/discovery-advertiser.js +114 -0
  69. package/dist/server/{health.js → server/src/health.js} +39 -11
  70. package/dist/server/{index.js → server/src/index.js} +4 -0
  71. package/dist/server/{managers → server/src/managers}/platform/llm-manager.js +40 -4
  72. package/dist/server/{managers → server/src/managers}/platform/openai-responses-provider.js +129 -19
  73. package/dist/server/server/src/movement.js +2935 -0
  74. package/dist/server/{openapi.js → server/src/openapi.js} +628 -5
  75. package/dist/server/{psyche-types.js → server/src/psyche-types.js} +15 -1
  76. package/dist/server/server/src/questionnaire-flow.js +552 -0
  77. package/dist/server/server/src/questionnaire-seeds.js +853 -0
  78. package/dist/server/server/src/questionnaire-types.js +340 -0
  79. package/dist/server/server/src/repositories/ai-connectors.js +1207 -0
  80. package/dist/server/server/src/repositories/ai-processors.js +547 -0
  81. package/dist/server/{repositories → server/src/repositories}/calendar.js +1 -1
  82. package/dist/server/{repositories → server/src/repositories}/entity-ownership.js +9 -1
  83. package/dist/server/{repositories → server/src/repositories}/habits.js +69 -5
  84. package/dist/server/server/src/repositories/model-settings.js +216 -0
  85. package/dist/server/{repositories → server/src/repositories}/notes.js +57 -15
  86. package/dist/server/{repositories → server/src/repositories}/preferences.js +124 -0
  87. package/dist/server/server/src/repositories/questionnaires.js +1338 -0
  88. package/dist/server/{repositories → server/src/repositories}/settings.js +156 -12
  89. package/dist/server/server/src/repositories/surface-layouts.js +76 -0
  90. package/dist/server/{repositories → server/src/repositories}/wiki-memory.js +5 -1
  91. package/dist/server/{services → server/src/services}/calendar-runtime.js +775 -58
  92. package/dist/server/{services → server/src/services}/entity-crud.js +81 -2
  93. package/dist/server/server/src/services/google-calendar-oauth-config.js +176 -0
  94. package/dist/server/server/src/services/openai-codex-oauth.js +153 -0
  95. package/dist/server/server/src/services/psyche-observation-calendar.js +46 -0
  96. package/dist/server/{types.js → server/src/types.js} +621 -14
  97. package/dist/server/server/src/watch-mobile.js +562 -0
  98. package/dist/server/{web.js → server/src/web.js} +30 -4
  99. package/dist/server/src/components/customization/utility-widgets.js +330 -0
  100. package/dist/server/src/components/workbench-boxes/health/health-boxes.js +92 -0
  101. package/dist/server/src/components/workbench-boxes/kanban/kanban-boxes.js +128 -0
  102. package/dist/server/src/components/workbench-boxes/movement/movement-boxes.js +37 -0
  103. package/dist/server/src/components/workbench-boxes/notes/notes-boxes.js +114 -0
  104. package/dist/server/src/components/workbench-boxes/projects/projects-boxes.js +57 -0
  105. package/dist/server/src/components/workbench-boxes/shared/define-workbench-box.js +4 -0
  106. package/dist/server/src/components/workbench-boxes/shared/generic-node-view.js +13 -0
  107. package/dist/server/src/components/workbench-boxes/today/today-boxes.js +63 -0
  108. package/dist/server/src/lib/api-error.js +37 -0
  109. package/dist/server/src/lib/api.js +1859 -0
  110. package/dist/server/src/lib/calendar-name-deduper.js +144 -0
  111. package/dist/server/src/lib/diagnostics.js +67 -0
  112. package/dist/server/src/lib/psyche-types.js +1 -0
  113. package/dist/server/src/lib/questionnaire-types.js +1 -0
  114. package/dist/server/src/lib/runtime-paths.js +24 -0
  115. package/dist/server/src/lib/schemas.js +234 -0
  116. package/dist/server/src/lib/snapshot-normalizer.js +374 -0
  117. package/dist/server/src/lib/theme-system.js +319 -0
  118. package/dist/server/src/lib/types.js +1 -0
  119. package/dist/server/src/lib/utils.js +22 -0
  120. package/dist/server/src/lib/workbench/boxes.js +16 -0
  121. package/dist/server/src/lib/workbench/nodes.js +15 -0
  122. package/dist/server/src/lib/workbench/registry.js +73 -0
  123. package/dist/server/src/lib/workbench/runtime.js +181 -0
  124. package/openclaw.plugin.json +1 -1
  125. package/package.json +6 -1
  126. package/server/index.js +68 -0
  127. package/server/migrations/024_questionnaires.sql +96 -0
  128. package/server/migrations/025_ai_model_connections.sql +26 -0
  129. package/server/migrations/026_custom_theme_settings.sql +2 -0
  130. package/server/migrations/027_ai_processors.sql +31 -0
  131. package/server/migrations/028_movement_domain.sql +136 -0
  132. package/server/migrations/029_watch_micro_capture.sql +23 -0
  133. package/server/migrations/030_surface_layouts.sql +5 -0
  134. package/server/migrations/031_ai_processor_runtime_upgrades.sql +10 -0
  135. package/server/migrations/032_ai_connectors.sql +44 -0
  136. package/server/migrations/033_movement_trip_point_sync.sql +36 -0
  137. package/server/migrations/034_movement_segment_sync.sql +49 -0
  138. package/server/migrations/035_google_local_auth_settings.sql +2 -0
  139. package/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  140. package/skills/forge-openclaw/SKILL.md +15 -1
  141. package/skills/forge-openclaw/entity_conversation_playbooks.md +523 -87
  142. package/skills/forge-openclaw/psyche_entity_playbooks.md +331 -221
  143. package/dist/assets/index-DTCwBWAs.js +0 -65
  144. package/dist/assets/index-DTCwBWAs.js.map +0 -1
  145. package/dist/assets/index-DttXlAgi.css +0 -1
  146. package/dist/assets/motion-D4sZgCHd.js.map +0 -1
  147. package/dist/assets/vendor-De38P6YR.js +0 -729
  148. package/dist/assets/vendor-De38P6YR.js.map +0 -1
  149. package/dist/assets/viz-C6hfyqzu.js +0 -34
  150. package/dist/assets/viz-C6hfyqzu.js.map +0 -1
  151. package/skills/forge-openclaw/cron_jobs.md +0 -395
  152. /package/dist/server/{demo-data.js → server/src/demo-data.js} +0 -0
  153. /package/dist/server/{e2e-server.js → server/src/e2e-server.js} +0 -0
  154. /package/dist/server/{errors.js → server/src/errors.js} +0 -0
  155. /package/dist/server/{managers → server/src/managers}/base.js +0 -0
  156. /package/dist/server/{managers → server/src/managers}/contracts.js +0 -0
  157. /package/dist/server/{managers → server/src/managers}/platform/api-gateway-manager.js +0 -0
  158. /package/dist/server/{managers → server/src/managers}/platform/audit-manager.js +0 -0
  159. /package/dist/server/{managers → server/src/managers}/platform/authentication-manager.js +0 -0
  160. /package/dist/server/{managers → server/src/managers}/platform/authorization-manager.js +0 -0
  161. /package/dist/server/{managers → server/src/managers}/platform/background-job-manager.js +0 -0
  162. /package/dist/server/{managers → server/src/managers}/platform/configuration-manager.js +0 -0
  163. /package/dist/server/{managers → server/src/managers}/platform/database-manager.js +0 -0
  164. /package/dist/server/{managers → server/src/managers}/platform/event-bus-manager.js +0 -0
  165. /package/dist/server/{managers → server/src/managers}/platform/external-service-manager.js +0 -0
  166. /package/dist/server/{managers → server/src/managers}/platform/health-manager.js +0 -0
  167. /package/dist/server/{managers → server/src/managers}/platform/migration-manager.js +0 -0
  168. /package/dist/server/{managers → server/src/managers}/platform/search-index-manager.js +0 -0
  169. /package/dist/server/{managers → server/src/managers}/platform/secrets-manager.js +0 -0
  170. /package/dist/server/{managers → server/src/managers}/platform/session-manager.js +0 -0
  171. /package/dist/server/{managers → server/src/managers}/platform/storage-manager.js +0 -0
  172. /package/dist/server/{managers → server/src/managers}/platform/token-manager.js +0 -0
  173. /package/dist/server/{managers → server/src/managers}/platform/transaction-manager.js +0 -0
  174. /package/dist/server/{managers → server/src/managers}/platform/trusted-network.js +0 -0
  175. /package/dist/server/{managers → server/src/managers}/runtime.js +0 -0
  176. /package/dist/server/{managers → server/src/managers}/type-guards.js +0 -0
  177. /package/dist/server/{preferences-seeds.js → server/src/preferences-seeds.js} +0 -0
  178. /package/dist/server/{preferences-types.js → server/src/preferences-types.js} +0 -0
  179. /package/dist/server/{repositories → server/src/repositories}/activity-events.js +0 -0
  180. /package/dist/server/{repositories → server/src/repositories}/collaboration.js +0 -0
  181. /package/dist/server/{repositories → server/src/repositories}/deleted-entities.js +0 -0
  182. /package/dist/server/{repositories → server/src/repositories}/diagnostic-logs.js +0 -0
  183. /package/dist/server/{repositories → server/src/repositories}/domains.js +0 -0
  184. /package/dist/server/{repositories → server/src/repositories}/event-log.js +0 -0
  185. /package/dist/server/{repositories → server/src/repositories}/goals.js +0 -0
  186. /package/dist/server/{repositories → server/src/repositories}/projects.js +0 -0
  187. /package/dist/server/{repositories → server/src/repositories}/psyche.js +0 -0
  188. /package/dist/server/{repositories → server/src/repositories}/rewards.js +0 -0
  189. /package/dist/server/{repositories → server/src/repositories}/strategies.js +0 -0
  190. /package/dist/server/{repositories → server/src/repositories}/tags.js +0 -0
  191. /package/dist/server/{repositories → server/src/repositories}/task-runs.js +0 -0
  192. /package/dist/server/{repositories → server/src/repositories}/tasks.js +0 -0
  193. /package/dist/server/{repositories → server/src/repositories}/users.js +0 -0
  194. /package/dist/server/{repositories → server/src/repositories}/weekly-reviews.js +0 -0
  195. /package/dist/server/{repositories → server/src/repositories}/work-adjustments.js +0 -0
  196. /package/dist/server/{seed-demo.js → server/src/seed-demo.js} +0 -0
  197. /package/dist/server/{services → server/src/services}/context.js +0 -0
  198. /package/dist/server/{services → server/src/services}/dashboard.js +0 -0
  199. /package/dist/server/{services → server/src/services}/gamification.js +0 -0
  200. /package/dist/server/{services → server/src/services}/insights.js +0 -0
  201. /package/dist/server/{services → server/src/services}/projects.js +0 -0
  202. /package/dist/server/{services → server/src/services}/psyche.js +0 -0
  203. /package/dist/server/{services → server/src/services}/relations.js +0 -0
  204. /package/dist/server/{services → server/src/services}/reviews.js +0 -0
  205. /package/dist/server/{services → server/src/services}/run-recovery.js +0 -0
  206. /package/dist/server/{services → server/src/services}/tagging.js +0 -0
  207. /package/dist/server/{services → server/src/services}/task-run-watchdog.js +0 -0
  208. /package/dist/server/{services → server/src/services}/work-time.js +0 -0
package/dist/index.html CHANGED
@@ -13,15 +13,14 @@
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-DTCwBWAs.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">
16
+ <script type="module" crossorigin src="/forge/assets/index-ytlpSj23.js"></script>
17
+ <link rel="modulepreload" crossorigin href="/forge/assets/vendor-lE3tZJcC.js">
18
+ <link rel="modulepreload" crossorigin href="/forge/assets/board-ta0rUHOf.js">
19
+ <link rel="modulepreload" crossorigin href="/forge/assets/ui-DInOpaYF.js">
20
+ <link rel="modulepreload" crossorigin href="/forge/assets/motion-fBKPB6yw.js">
21
+ <link rel="modulepreload" crossorigin href="/forge/assets/table-C-IGTQni.js">
23
22
  <link rel="stylesheet" crossorigin href="/forge/assets/vendor-DT3pnAKJ.css">
24
- <link rel="stylesheet" crossorigin href="/forge/assets/index-DttXlAgi.css">
23
+ <link rel="stylesheet" crossorigin href="/forge/assets/index-Ro0ZF_az.css">
25
24
  </head>
26
25
  <body class="bg-canvas text-ink antialiased">
27
26
  <div id="root"></div>
@@ -33,7 +33,9 @@ export type ForgeRuntimeRestartResult = {
33
33
  };
34
34
  export declare function ensureForgeRuntimeReady(config: ForgePluginConfig): Promise<void>;
35
35
  export declare function startForgeRuntime(config: ForgePluginConfig): Promise<ForgeRuntimeStartResult>;
36
- export declare function primeForgeRuntime(config: ForgePluginConfig): void;
36
+ export declare function primeForgeRuntime(config: ForgePluginConfig, logger?: {
37
+ warn?(message: string): void;
38
+ }): void;
37
39
  export declare function stopForgeRuntime(config: ForgePluginConfig): Promise<ForgeRuntimeStopResult>;
38
40
  export declare function getForgeRuntimeStatus(config: ForgePluginConfig): Promise<ForgeRuntimeStatusResult>;
39
41
  export declare function restartForgeRuntime(config: ForgePluginConfig): Promise<ForgeRuntimeRestartResult>;
@@ -168,6 +168,37 @@ function isLocalOrigin(origin) {
168
168
  function getCurrentModuleRoot() {
169
169
  return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
170
170
  }
171
+ function buildLaunchPlanSearchPaths(moduleRoot) {
172
+ const repoRoot = path.resolve(moduleRoot, "..");
173
+ return {
174
+ packagedEntries: [
175
+ path.join(moduleRoot, "server", "index.js"),
176
+ path.join(moduleRoot, "dist", "server", "index.js"),
177
+ path.join(moduleRoot, "dist", "server", "src", "index.js"),
178
+ path.join(moduleRoot, "dist", "server", "server", "src", "index.js")
179
+ ],
180
+ packagedMigrations: path.join(moduleRoot, "server", "migrations"),
181
+ sourceEntries: [
182
+ path.join(repoRoot, "server", "src", "index.ts"),
183
+ path.join(moduleRoot, "server", "src", "index.ts")
184
+ ],
185
+ tsxCliCandidates: [
186
+ path.join(repoRoot, "node_modules", "tsx", "dist", "cli.mjs"),
187
+ path.join(moduleRoot, "node_modules", "tsx", "dist", "cli.mjs")
188
+ ],
189
+ repoRoot
190
+ };
191
+ }
192
+ function formatLaunchPlanFailure(moduleRoot) {
193
+ const paths = buildLaunchPlanSearchPaths(moduleRoot);
194
+ return [
195
+ "Forge local runtime could not find a launchable server entry.",
196
+ `Packaged entry candidates: ${paths.packagedEntries.join(", ")}.`,
197
+ `Expected migrations at: ${paths.packagedMigrations}.`,
198
+ `Source entry candidates: ${paths.sourceEntries.join(", ")}.`,
199
+ `tsx candidates: ${paths.tsxCliCandidates.join(", ")}.`
200
+ ].join(" ");
201
+ }
171
202
  function getRuntimeLogPath(config) {
172
203
  const origin = new URL(config.origin).hostname.toLowerCase().replace(/[^a-z0-9._-]+/g, "-");
173
204
  return path.join(homedir(), ".openclaw", "logs", FORGE_PLUGIN_ID, `${origin}-${config.port}.log`);
@@ -177,7 +208,7 @@ function openRuntimeLogFile(logPath) {
177
208
  return openSync(logPath, "a");
178
209
  }
179
210
  function isPackagedServerPlan(plan) {
180
- return plan.entryFile.endsWith(path.join("dist", "server", "index.js"));
211
+ return plan.mode === "packaged";
181
212
  }
182
213
  function getNpmInvocation() {
183
214
  const binDir = path.dirname(process.execPath);
@@ -250,23 +281,25 @@ async function ensurePackagedRuntimeDependencies(plan, config) {
250
281
  }
251
282
  function resolveLaunchPlan() {
252
283
  const moduleRoot = getCurrentModuleRoot();
284
+ const paths = buildLaunchPlanSearchPaths(moduleRoot);
253
285
  // Published or linked plugin package runtime.
254
- const packagedEntry = path.join(moduleRoot, "dist", "server", "index.js");
255
- const packagedMigrations = path.join(moduleRoot, "server", "migrations");
256
- if (existsSync(packagedEntry) && existsSync(packagedMigrations)) {
286
+ const packagedEntry = paths.packagedEntries.find((candidate) => existsSync(candidate));
287
+ if (packagedEntry && existsSync(paths.packagedMigrations)) {
257
288
  return {
258
289
  packageRoot: moduleRoot,
259
- entryFile: packagedEntry
290
+ entryFile: packagedEntry,
291
+ mode: "packaged"
260
292
  };
261
293
  }
262
294
  // Source-tree fallback for local development before packaging.
263
- const repoRoot = moduleRoot;
264
- const sourceEntry = path.join(repoRoot, "server", "src", "index.ts");
265
- const tsxCli = path.join(repoRoot, "node_modules", "tsx", "dist", "cli.mjs");
266
- if (existsSync(sourceEntry) && existsSync(tsxCli)) {
295
+ const sourceEntry = paths.sourceEntries.find((candidate) => existsSync(candidate));
296
+ const tsxCli = paths.tsxCliCandidates.find((candidate) => existsSync(candidate));
297
+ if (sourceEntry && tsxCli) {
267
298
  return {
268
- packageRoot: repoRoot,
269
- entryFile: tsxCli
299
+ packageRoot: paths.repoRoot,
300
+ entryFile: tsxCli,
301
+ mode: "source",
302
+ sourceEntryFile: sourceEntry
270
303
  };
271
304
  }
272
305
  return null;
@@ -330,7 +363,9 @@ async function adoptManagedRuntimeState(config, probe) {
330
363
  }
331
364
  async function spawnManagedRuntime(config, plan) {
332
365
  const isPackagedServer = isPackagedServerPlan(plan);
333
- const args = isPackagedServer ? [plan.entryFile] : [plan.entryFile, path.join(plan.packageRoot, "server", "src", "index.ts")];
366
+ const args = isPackagedServer
367
+ ? [plan.entryFile]
368
+ : [plan.entryFile, plan.sourceEntryFile ?? path.join(plan.packageRoot, "server", "src", "index.ts")];
334
369
  const logPath = getRuntimeLogPath(config);
335
370
  const logFd = openRuntimeLogFile(logPath);
336
371
  const child = spawn(process.execPath, args, {
@@ -454,7 +489,7 @@ export async function ensureForgeRuntimeReady(config) {
454
489
  }
455
490
  const plan = resolveLaunchPlan();
456
491
  if (!plan) {
457
- return;
492
+ throw new Error(formatLaunchPlanFailure(getCurrentModuleRoot()));
458
493
  }
459
494
  startupPromise = (async () => {
460
495
  const probeBeforeStart = await probeForgeRuntime(config, HEALTHCHECK_TIMEOUT_MS);
@@ -556,8 +591,9 @@ export async function startForgeRuntime(config) {
556
591
  baseUrl: config.baseUrl
557
592
  };
558
593
  }
559
- export function primeForgeRuntime(config) {
560
- void ensureForgeRuntimeReady(config).catch(() => {
594
+ export function primeForgeRuntime(config, logger) {
595
+ void ensureForgeRuntimeReady(config).catch((error) => {
596
+ logger?.warn?.(`Forge local runtime bootstrap failed for ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`);
561
597
  // Keep plugin registration non-blocking. Failures surface on first real call.
562
598
  });
563
599
  }
@@ -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" | "wiki" | "health";
5
+ purpose: "diagnostics" | "overview" | "operator_context" | "onboarding" | "psyche" | "xp" | "weekly_review" | "entities" | "work" | "insights" | "wiki" | "health" | "preferences" | "questionnaires";
6
6
  };
7
7
  export declare const FORGE_SUPPORTED_PLUGIN_API_ROUTES: ForgeSupportedPluginApiRoute[];
8
8
  export declare function makeApiRouteKey(method: string, path: string): ApiRouteKey;
@@ -29,6 +29,35 @@ export const FORGE_SUPPORTED_PLUGIN_API_ROUTES = [
29
29
  { method: "PATCH", path: "/api/v1/health/sleep/:id", purpose: "health" },
30
30
  { method: "GET", path: "/api/v1/health/fitness", purpose: "health" },
31
31
  { method: "PATCH", path: "/api/v1/health/workouts/:id", purpose: "health" },
32
+ { method: "GET", path: "/api/v1/preferences/workspace", purpose: "preferences" },
33
+ { method: "POST", path: "/api/v1/preferences/game/start", purpose: "preferences" },
34
+ { method: "POST", path: "/api/v1/preferences/catalogs", purpose: "preferences" },
35
+ { method: "PATCH", path: "/api/v1/preferences/catalogs/:id", purpose: "preferences" },
36
+ { method: "DELETE", path: "/api/v1/preferences/catalogs/:id", purpose: "preferences" },
37
+ { method: "POST", path: "/api/v1/preferences/catalog-items", purpose: "preferences" },
38
+ { method: "PATCH", path: "/api/v1/preferences/catalog-items/:id", purpose: "preferences" },
39
+ { method: "DELETE", path: "/api/v1/preferences/catalog-items/:id", purpose: "preferences" },
40
+ { method: "POST", path: "/api/v1/preferences/contexts", purpose: "preferences" },
41
+ { method: "PATCH", path: "/api/v1/preferences/contexts/:id", purpose: "preferences" },
42
+ { method: "POST", path: "/api/v1/preferences/contexts/merge", purpose: "preferences" },
43
+ { method: "POST", path: "/api/v1/preferences/items", purpose: "preferences" },
44
+ { method: "PATCH", path: "/api/v1/preferences/items/:id", purpose: "preferences" },
45
+ { method: "POST", path: "/api/v1/preferences/items/from-entity", purpose: "preferences" },
46
+ { method: "POST", path: "/api/v1/preferences/judgments", purpose: "preferences" },
47
+ { method: "POST", path: "/api/v1/preferences/signals", purpose: "preferences" },
48
+ { method: "PATCH", path: "/api/v1/preferences/items/:id/score", purpose: "preferences" },
49
+ { method: "GET", path: "/api/v1/psyche/questionnaires", purpose: "questionnaires" },
50
+ { method: "POST", path: "/api/v1/psyche/questionnaires", purpose: "questionnaires" },
51
+ { method: "GET", path: "/api/v1/psyche/questionnaires/:id", purpose: "questionnaires" },
52
+ { method: "POST", path: "/api/v1/psyche/questionnaires/:id/clone", purpose: "questionnaires" },
53
+ { method: "POST", path: "/api/v1/psyche/questionnaires/:id/draft", purpose: "questionnaires" },
54
+ { method: "PATCH", path: "/api/v1/psyche/questionnaires/:id/draft", purpose: "questionnaires" },
55
+ { method: "POST", path: "/api/v1/psyche/questionnaires/:id/publish", purpose: "questionnaires" },
56
+ { method: "POST", path: "/api/v1/psyche/questionnaires/:id/runs", purpose: "questionnaires" },
57
+ { method: "GET", path: "/api/v1/psyche/questionnaire-runs/:id", purpose: "questionnaires" },
58
+ { method: "PATCH", path: "/api/v1/psyche/questionnaire-runs/:id", purpose: "questionnaires" },
59
+ { method: "POST", path: "/api/v1/psyche/questionnaire-runs/:id/complete", purpose: "questionnaires" },
60
+ { method: "GET", path: "/api/v1/psyche/self-observation/calendar", purpose: "questionnaires" },
32
61
  { method: "POST", path: "/api/v1/entities/search", purpose: "entities" },
33
62
  { method: "POST", path: "/api/v1/entities/create", purpose: "entities" },
34
63
  { method: "POST", path: "/api/v1/entities/update", purpose: "entities" },
@@ -5,6 +5,7 @@ export declare const FORGE_PLUGIN_NAME = "Forge";
5
5
  export declare const FORGE_PLUGIN_DESCRIPTION = "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.";
6
6
  export declare const DEFAULT_FORGE_ORIGIN = "http://127.0.0.1";
7
7
  export declare const DEFAULT_FORGE_PORT = 4317;
8
+ export declare const DEFAULT_OPENCLAW_ACTOR_LABEL = "aurel (claw)";
8
9
  export declare function resolveForgePluginConfig(pluginConfig: unknown): ForgePluginConfig;
9
10
  export declare const forgePluginConfigSchema: ForgePluginConfigSchema;
10
11
  export declare function registerForgePlugin(api: ForgePluginRegistrationApi): void;
@@ -2,14 +2,16 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
3
  import path from "node:path";
4
4
  import { buildForgeBaseUrl, buildForgeWebAppUrl } from "./api-client.js";
5
- import { primeForgeRuntime } from "./local-runtime.js";
5
+ import { ensureForgeRuntimeReady, getForgeRuntimeStatus, primeForgeRuntime } from "./local-runtime.js";
6
6
  import { registerForgePluginCli, registerForgePluginRoutes } from "./routes.js";
7
+ import { registerForgeSessionBootstrapHook } from "./session-bootstrap.js";
7
8
  import { registerForgePluginTools } from "./tools.js";
8
9
  export const FORGE_PLUGIN_ID = "forge-openclaw-plugin";
9
10
  export const FORGE_PLUGIN_NAME = "Forge";
10
11
  export const FORGE_PLUGIN_DESCRIPTION = "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.";
11
12
  export const DEFAULT_FORGE_ORIGIN = "http://127.0.0.1";
12
13
  export const DEFAULT_FORGE_PORT = 4317;
14
+ export const DEFAULT_OPENCLAW_ACTOR_LABEL = "aurel (claw)";
13
15
  const LOCAL_HOSTNAMES = new Set(["127.0.0.1", "localhost", "::1"]);
14
16
  function normalizeString(value, fallback) {
15
17
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback;
@@ -88,7 +90,7 @@ export function resolveForgePluginConfig(pluginConfig) {
88
90
  portSource: hasConfiguredPort ? "configured" : preferredPort !== null ? "preferred" : "default",
89
91
  dataRoot: normalizeDataRoot(raw.dataRoot),
90
92
  apiToken: typeof raw.apiToken === "string" ? raw.apiToken.trim() : "",
91
- actorLabel: normalizeString(raw.actorLabel, "aurel"),
93
+ actorLabel: normalizeString(raw.actorLabel, DEFAULT_OPENCLAW_ACTOR_LABEL),
92
94
  timeoutMs: normalizeTimeout(raw.timeoutMs, 15_000)
93
95
  };
94
96
  }
@@ -124,7 +126,7 @@ export const forgePluginConfigSchema = {
124
126
  },
125
127
  actorLabel: {
126
128
  type: "string",
127
- default: "aurel",
129
+ default: DEFAULT_OPENCLAW_ACTOR_LABEL,
128
130
  description: "Actor label recorded in Forge provenance headers."
129
131
  },
130
132
  timeoutMs: {
@@ -161,8 +163,8 @@ export const forgePluginConfigSchema = {
161
163
  },
162
164
  actorLabel: {
163
165
  label: "Actor Label",
164
- help: "Recorded in Forge provenance headers for plugin-originated writes.",
165
- placeholder: "aurel"
166
+ help: "Recorded in Forge provenance headers for plugin-originated writes. Use a distinct OpenClaw label such as <name> (claw).",
167
+ placeholder: DEFAULT_OPENCLAW_ACTOR_LABEL
166
168
  },
167
169
  timeoutMs: {
168
170
  label: "Request Timeout (ms)",
@@ -173,7 +175,30 @@ export const forgePluginConfigSchema = {
173
175
  };
174
176
  export function registerForgePlugin(api) {
175
177
  const config = resolveForgePluginConfig(api.pluginConfig);
176
- primeForgeRuntime(config);
178
+ if (api.registerService) {
179
+ api.registerService({
180
+ id: "forge-local-runtime-bootstrap",
181
+ start: async ({ logger }) => {
182
+ if (!isLocalOrigin(config.origin)) {
183
+ logger.info?.(`Forge local runtime bootstrap skipped for remote target ${config.baseUrl}.`);
184
+ return;
185
+ }
186
+ logger.info?.(`Forge local runtime bootstrap: ensuring Forge at ${config.baseUrl}.`);
187
+ try {
188
+ await ensureForgeRuntimeReady(config);
189
+ const status = await getForgeRuntimeStatus(config);
190
+ logger.info?.(`Forge local runtime bootstrap: ${status?.message ?? `Forge is ready at ${config.baseUrl}.`}`);
191
+ }
192
+ catch (error) {
193
+ logger.warn?.(`Forge local runtime bootstrap failed for ${config.baseUrl}: ${error instanceof Error ? error.message : String(error)}`);
194
+ }
195
+ }
196
+ });
197
+ }
198
+ else {
199
+ primeForgeRuntime(config, api.logger);
200
+ }
201
+ registerForgeSessionBootstrapHook(api, config);
177
202
  registerForgePluginRoutes(api, config);
178
203
  registerForgePluginCli(api, config);
179
204
  registerForgePluginTools(api, config);
@@ -1,6 +1,7 @@
1
1
  import type { IncomingMessage, ServerResponse } from "node:http";
2
2
  import type { TSchema } from "@sinclair/typebox";
3
3
  import type { AgentToolResult } from "@mariozechner/pi-agent-core";
4
+ import type { InternalHookEvent } from "openclaw/plugin-sdk/hook-runtime";
4
5
  export type ForgePluginConfigSchema = {
5
6
  parse(value: unknown): unknown;
6
7
  jsonSchema: Record<string, unknown>;
@@ -41,15 +42,43 @@ export type ForgeCliRegistrarContext = {
41
42
  debug?(message: string): void;
42
43
  };
43
44
  };
45
+ export type ForgePluginServiceContext = {
46
+ config?: unknown;
47
+ workspaceDir?: string;
48
+ stateDir: string;
49
+ logger: {
50
+ info?(message: string): void;
51
+ warn?(message: string): void;
52
+ error?(message: string): void;
53
+ debug?(message: string): void;
54
+ };
55
+ };
56
+ export type ForgeRegisteredService = {
57
+ id: string;
58
+ start: (context: ForgePluginServiceContext) => Promise<void> | void;
59
+ stop?: (context: ForgePluginServiceContext) => Promise<void> | void;
60
+ };
44
61
  export type ForgePluginRegistrationApi = {
45
62
  pluginConfig?: unknown;
63
+ logger?: {
64
+ info?(message: string): void;
65
+ warn?(message: string): void;
66
+ error?(message: string): void;
67
+ debug?(message: string): void;
68
+ };
46
69
  registerHttpRoute(route: ForgeRegisteredHttpRoute): void;
47
70
  registerTool(tool: ForgeRegisteredTool, options?: {
48
71
  optional?: boolean;
49
72
  }): void;
73
+ registerHook?(events: string | string[], handler: (event: InternalHookEvent) => Promise<void> | void, options?: {
74
+ name?: string;
75
+ description?: string;
76
+ register?: boolean;
77
+ }): void;
50
78
  registerCli?(registrar: (context: ForgeCliRegistrarContext) => void, options?: {
51
79
  commands?: string[];
52
80
  }): void;
81
+ registerService?(service: ForgeRegisteredService): void;
53
82
  };
54
83
  export type ForgePluginRouteApi = Pick<ForgePluginRegistrationApi, "registerHttpRoute">;
55
84
  export type ForgePluginToolApi = Pick<ForgePluginRegistrationApi, "registerTool">;
@@ -164,6 +164,16 @@ export const FORGE_PLUGIN_ROUTE_GROUPS = [
164
164
  upstreamPath: "/api/v1/health/fitness",
165
165
  target: (_match, url) => passthroughSearch("/api/v1/health/fitness", url)
166
166
  }),
167
+ exact("/forge/v1/preferences/workspace", {
168
+ method: "GET",
169
+ upstreamPath: "/api/v1/preferences/workspace",
170
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/workspace", url)
171
+ }),
172
+ exact("/forge/v1/psyche/self-observation/calendar", {
173
+ method: "GET",
174
+ upstreamPath: "/api/v1/psyche/self-observation/calendar",
175
+ target: (_match, url) => passthroughSearch("/api/v1/psyche/self-observation/calendar", url)
176
+ }),
167
177
  exact("/forge/v1/operator/log-work", {
168
178
  method: "POST",
169
179
  upstreamPath: "/api/v1/operator/log-work",
@@ -185,6 +195,232 @@ export const FORGE_PLUGIN_ROUTE_GROUPS = [
185
195
  requiresToken: true,
186
196
  target: (_match, url) => passthroughSearch("/api/v1/insights", url)
187
197
  }),
198
+ {
199
+ path: "/forge/v1/preferences",
200
+ match: "prefix",
201
+ operations: [
202
+ {
203
+ method: "POST",
204
+ pattern: /^\/forge\/v1\/preferences\/game\/start$/,
205
+ upstreamPath: "/api/v1/preferences/game/start",
206
+ requestBody: "json",
207
+ requiresToken: true,
208
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/game/start", url)
209
+ },
210
+ {
211
+ method: "POST",
212
+ pattern: /^\/forge\/v1\/preferences\/catalogs$/,
213
+ upstreamPath: "/api/v1/preferences/catalogs",
214
+ requestBody: "json",
215
+ requiresToken: true,
216
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/catalogs", url)
217
+ },
218
+ {
219
+ method: "PATCH",
220
+ pattern: /^\/forge\/v1\/preferences\/catalogs\/([^/]+)$/,
221
+ upstreamPath: "/api/v1/preferences/catalogs/:id",
222
+ requestBody: "json",
223
+ requiresToken: true,
224
+ target: (match, url) => passthroughSearch(`/api/v1/preferences/catalogs/${match[1]}`, url)
225
+ },
226
+ {
227
+ method: "DELETE",
228
+ pattern: /^\/forge\/v1\/preferences\/catalogs\/([^/]+)$/,
229
+ upstreamPath: "/api/v1/preferences/catalogs/:id",
230
+ requiresToken: true,
231
+ target: (match, url) => passthroughSearch(`/api/v1/preferences/catalogs/${match[1]}`, url)
232
+ },
233
+ {
234
+ method: "POST",
235
+ pattern: /^\/forge\/v1\/preferences\/catalog-items$/,
236
+ upstreamPath: "/api/v1/preferences/catalog-items",
237
+ requestBody: "json",
238
+ requiresToken: true,
239
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/catalog-items", url)
240
+ },
241
+ {
242
+ method: "PATCH",
243
+ pattern: /^\/forge\/v1\/preferences\/catalog-items\/([^/]+)$/,
244
+ upstreamPath: "/api/v1/preferences/catalog-items/:id",
245
+ requestBody: "json",
246
+ requiresToken: true,
247
+ target: (match, url) => passthroughSearch(`/api/v1/preferences/catalog-items/${match[1]}`, url)
248
+ },
249
+ {
250
+ method: "DELETE",
251
+ pattern: /^\/forge\/v1\/preferences\/catalog-items\/([^/]+)$/,
252
+ upstreamPath: "/api/v1/preferences/catalog-items/:id",
253
+ requiresToken: true,
254
+ target: (match, url) => passthroughSearch(`/api/v1/preferences/catalog-items/${match[1]}`, url)
255
+ },
256
+ {
257
+ method: "POST",
258
+ pattern: /^\/forge\/v1\/preferences\/contexts$/,
259
+ upstreamPath: "/api/v1/preferences/contexts",
260
+ requestBody: "json",
261
+ requiresToken: true,
262
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/contexts", url)
263
+ },
264
+ {
265
+ method: "PATCH",
266
+ pattern: /^\/forge\/v1\/preferences\/contexts\/([^/]+)$/,
267
+ upstreamPath: "/api/v1/preferences/contexts/:id",
268
+ requestBody: "json",
269
+ requiresToken: true,
270
+ target: (match, url) => passthroughSearch(`/api/v1/preferences/contexts/${match[1]}`, url)
271
+ },
272
+ {
273
+ method: "POST",
274
+ pattern: /^\/forge\/v1\/preferences\/contexts\/merge$/,
275
+ upstreamPath: "/api/v1/preferences/contexts/merge",
276
+ requestBody: "json",
277
+ requiresToken: true,
278
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/contexts/merge", url)
279
+ },
280
+ {
281
+ method: "POST",
282
+ pattern: /^\/forge\/v1\/preferences\/items$/,
283
+ upstreamPath: "/api/v1/preferences/items",
284
+ requestBody: "json",
285
+ requiresToken: true,
286
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/items", url)
287
+ },
288
+ {
289
+ method: "PATCH",
290
+ pattern: /^\/forge\/v1\/preferences\/items\/([^/]+)$/,
291
+ upstreamPath: "/api/v1/preferences/items/:id",
292
+ requestBody: "json",
293
+ requiresToken: true,
294
+ target: (match, url) => passthroughSearch(`/api/v1/preferences/items/${match[1]}`, url)
295
+ },
296
+ {
297
+ method: "POST",
298
+ pattern: /^\/forge\/v1\/preferences\/items\/from-entity$/,
299
+ upstreamPath: "/api/v1/preferences/items/from-entity",
300
+ requestBody: "json",
301
+ requiresToken: true,
302
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/items/from-entity", url)
303
+ },
304
+ {
305
+ method: "POST",
306
+ pattern: /^\/forge\/v1\/preferences\/judgments$/,
307
+ upstreamPath: "/api/v1/preferences/judgments",
308
+ requestBody: "json",
309
+ requiresToken: true,
310
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/judgments", url)
311
+ },
312
+ {
313
+ method: "POST",
314
+ pattern: /^\/forge\/v1\/preferences\/signals$/,
315
+ upstreamPath: "/api/v1/preferences/signals",
316
+ requestBody: "json",
317
+ requiresToken: true,
318
+ target: (_match, url) => passthroughSearch("/api/v1/preferences/signals", url)
319
+ },
320
+ {
321
+ method: "PATCH",
322
+ pattern: /^\/forge\/v1\/preferences\/items\/([^/]+)\/score$/,
323
+ upstreamPath: "/api/v1/preferences/items/:id/score",
324
+ requestBody: "json",
325
+ requiresToken: true,
326
+ target: (match, url) => passthroughSearch(`/api/v1/preferences/items/${match[1]}/score`, url)
327
+ }
328
+ ]
329
+ },
330
+ {
331
+ path: "/forge/v1/psyche/questionnaires",
332
+ match: "prefix",
333
+ operations: [
334
+ {
335
+ method: "GET",
336
+ pattern: /^\/forge\/v1\/psyche\/questionnaires$/,
337
+ upstreamPath: "/api/v1/psyche/questionnaires",
338
+ target: (_match, url) => passthroughSearch("/api/v1/psyche/questionnaires", url)
339
+ },
340
+ {
341
+ method: "POST",
342
+ pattern: /^\/forge\/v1\/psyche\/questionnaires$/,
343
+ upstreamPath: "/api/v1/psyche/questionnaires",
344
+ requestBody: "json",
345
+ requiresToken: true,
346
+ target: (_match, url) => passthroughSearch("/api/v1/psyche/questionnaires", url)
347
+ },
348
+ {
349
+ method: "GET",
350
+ pattern: /^\/forge\/v1\/psyche\/questionnaires\/([^/]+)$/,
351
+ upstreamPath: "/api/v1/psyche/questionnaires/:id",
352
+ target: (match, url) => passthroughSearch(`/api/v1/psyche/questionnaires/${match[1]}`, url)
353
+ },
354
+ {
355
+ method: "POST",
356
+ pattern: /^\/forge\/v1\/psyche\/questionnaires\/([^/]+)\/clone$/,
357
+ upstreamPath: "/api/v1/psyche/questionnaires/:id/clone",
358
+ requestBody: "json",
359
+ requiresToken: true,
360
+ target: (match, url) => passthroughSearch(`/api/v1/psyche/questionnaires/${match[1]}/clone`, url)
361
+ },
362
+ {
363
+ method: "POST",
364
+ pattern: /^\/forge\/v1\/psyche\/questionnaires\/([^/]+)\/draft$/,
365
+ upstreamPath: "/api/v1/psyche/questionnaires/:id/draft",
366
+ requestBody: "json",
367
+ requiresToken: true,
368
+ target: (match, url) => passthroughSearch(`/api/v1/psyche/questionnaires/${match[1]}/draft`, url)
369
+ },
370
+ {
371
+ method: "PATCH",
372
+ pattern: /^\/forge\/v1\/psyche\/questionnaires\/([^/]+)\/draft$/,
373
+ upstreamPath: "/api/v1/psyche/questionnaires/:id/draft",
374
+ requestBody: "json",
375
+ requiresToken: true,
376
+ target: (match, url) => passthroughSearch(`/api/v1/psyche/questionnaires/${match[1]}/draft`, url)
377
+ },
378
+ {
379
+ method: "POST",
380
+ pattern: /^\/forge\/v1\/psyche\/questionnaires\/([^/]+)\/publish$/,
381
+ upstreamPath: "/api/v1/psyche/questionnaires/:id/publish",
382
+ requestBody: "json",
383
+ requiresToken: true,
384
+ target: (match, url) => passthroughSearch(`/api/v1/psyche/questionnaires/${match[1]}/publish`, url)
385
+ },
386
+ {
387
+ method: "POST",
388
+ pattern: /^\/forge\/v1\/psyche\/questionnaires\/([^/]+)\/runs$/,
389
+ upstreamPath: "/api/v1/psyche/questionnaires/:id/runs",
390
+ requestBody: "json",
391
+ requiresToken: true,
392
+ target: (match, url) => passthroughSearch(`/api/v1/psyche/questionnaires/${match[1]}/runs`, url)
393
+ }
394
+ ]
395
+ },
396
+ {
397
+ path: "/forge/v1/psyche/questionnaire-runs",
398
+ match: "prefix",
399
+ operations: [
400
+ {
401
+ method: "GET",
402
+ pattern: /^\/forge\/v1\/psyche\/questionnaire-runs\/([^/]+)$/,
403
+ upstreamPath: "/api/v1/psyche/questionnaire-runs/:id",
404
+ target: (match, url) => passthroughSearch(`/api/v1/psyche/questionnaire-runs/${match[1]}`, url)
405
+ },
406
+ {
407
+ method: "PATCH",
408
+ pattern: /^\/forge\/v1\/psyche\/questionnaire-runs\/([^/]+)$/,
409
+ upstreamPath: "/api/v1/psyche/questionnaire-runs/:id",
410
+ requestBody: "json",
411
+ requiresToken: true,
412
+ target: (match, url) => passthroughSearch(`/api/v1/psyche/questionnaire-runs/${match[1]}`, url)
413
+ },
414
+ {
415
+ method: "POST",
416
+ pattern: /^\/forge\/v1\/psyche\/questionnaire-runs\/([^/]+)\/complete$/,
417
+ upstreamPath: "/api/v1/psyche/questionnaire-runs/:id/complete",
418
+ requestBody: "json",
419
+ requiresToken: true,
420
+ target: (match, url) => passthroughSearch(`/api/v1/psyche/questionnaire-runs/${match[1]}/complete`, url)
421
+ }
422
+ ]
423
+ },
188
424
  {
189
425
  path: "/forge/v1/wiki/pages",
190
426
  match: "prefix",