forge-openclaw-plugin 0.2.25 → 0.2.27

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 (237) hide show
  1. package/README.md +59 -3
  2. package/dist/assets/{board-VmF4FAfr.js → board-C6jCchjI.js} +3 -3
  3. package/dist/assets/{board-VmF4FAfr.js.map → board-C6jCchjI.js.map} +1 -1
  4. package/dist/assets/index-DVvS8iiU.css +1 -0
  5. package/dist/assets/index-zYB-9Dfo.js +85 -0
  6. package/dist/assets/index-zYB-9Dfo.js.map +1 -0
  7. package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js +2 -0
  8. package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js.map +1 -0
  9. package/dist/assets/{motion-DvkU14p-.js → motion-DFHrH2rd.js} +2 -2
  10. package/dist/assets/{motion-DvkU14p-.js.map → motion-DFHrH2rd.js.map} +1 -1
  11. package/dist/assets/{table-DgiPof9E.js → table-ZL7Di_u3.js} +2 -2
  12. package/dist/assets/{table-DgiPof9E.js.map → table-ZL7Di_u3.js.map} +1 -1
  13. package/dist/assets/{ui-nYfoC0Gq.js → ui-CKNPpz7q.js} +2 -2
  14. package/dist/assets/{ui-nYfoC0Gq.js.map → ui-CKNPpz7q.js.map} +1 -1
  15. package/dist/assets/vendor-DoNZuFhn.js +1247 -0
  16. package/dist/assets/vendor-DoNZuFhn.js.map +1 -0
  17. package/dist/index.html +7 -8
  18. package/dist/openclaw/local-runtime.d.ts +3 -1
  19. package/dist/openclaw/local-runtime.js +67 -15
  20. package/dist/openclaw/plugin-entry-shared.js +24 -2
  21. package/dist/openclaw/plugin-sdk-types.d.ts +17 -0
  22. package/dist/openclaw/routes.d.ts +27 -0
  23. package/dist/openclaw/routes.js +16 -12
  24. package/dist/openclaw/tools.js +0 -3
  25. package/dist/server/server/migrations/001_core.sql +411 -0
  26. package/dist/server/server/migrations/002_psyche.sql +392 -0
  27. package/dist/server/server/migrations/003_habits.sql +30 -0
  28. package/dist/server/server/migrations/004_habit_links.sql +8 -0
  29. package/dist/server/server/migrations/005_habit_psyche_links.sql +24 -0
  30. package/dist/server/server/migrations/006_work_adjustments.sql +14 -0
  31. package/dist/server/server/migrations/007_weekly_review_closures.sql +17 -0
  32. package/dist/server/server/migrations/008_calendar_execution.sql +147 -0
  33. package/dist/server/server/migrations/009_true_calendar_events.sql +195 -0
  34. package/dist/server/server/migrations/010_calendar_selection_state.sql +6 -0
  35. package/dist/server/server/migrations/011_calendar_timezone_backfill.sql +11 -0
  36. package/dist/server/server/migrations/012_work_block_ranges.sql +7 -0
  37. package/dist/server/server/migrations/013_microsoft_local_auth_settings.sql +8 -0
  38. package/dist/server/server/migrations/014_note_tags_and_ephemeral.sql +8 -0
  39. package/dist/server/server/migrations/015_multi_user_and_strategies.sql +244 -0
  40. package/dist/server/server/migrations/016_health_companion.sql +158 -0
  41. package/dist/server/server/migrations/016_strategy_contracts_and_user_graph.sql +22 -0
  42. package/dist/server/server/migrations/017_preferences.sql +131 -0
  43. package/dist/server/server/migrations/018_preference_catalogs.sql +31 -0
  44. package/dist/server/server/migrations/019_wiki_memory.sql +255 -0
  45. package/dist/server/server/migrations/020_wiki_page_hierarchy.sql +11 -0
  46. package/dist/server/server/migrations/021_hide_evidence_from_wiki_index.sql +3 -0
  47. package/dist/server/server/migrations/022_wiki_ingest_background.sql +85 -0
  48. package/dist/server/server/migrations/023_diagnostic_logs.sql +28 -0
  49. package/dist/server/server/migrations/024_questionnaires.sql +96 -0
  50. package/dist/server/server/migrations/025_ai_model_connections.sql +26 -0
  51. package/dist/server/server/migrations/026_custom_theme_settings.sql +2 -0
  52. package/dist/server/server/migrations/027_ai_processors.sql +31 -0
  53. package/dist/server/server/migrations/028_movement_domain.sql +136 -0
  54. package/dist/server/server/migrations/029_watch_micro_capture.sql +23 -0
  55. package/dist/server/server/migrations/030_surface_layouts.sql +5 -0
  56. package/dist/server/server/migrations/031_ai_processor_runtime_upgrades.sql +10 -0
  57. package/dist/server/server/migrations/032_ai_connectors.sql +44 -0
  58. package/dist/server/server/migrations/033_movement_trip_point_sync.sql +36 -0
  59. package/dist/server/server/migrations/034_movement_segment_sync.sql +49 -0
  60. package/dist/server/server/migrations/035_google_local_auth_settings.sql +2 -0
  61. package/dist/server/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  62. package/dist/server/server/migrations/037_workbench_public_inputs_and_run_inputs.sql +5 -0
  63. package/dist/server/server/migrations/038_data_management_settings.sql +11 -0
  64. package/dist/server/server/migrations/039_life_force_and_action_points.sql +114 -0
  65. package/dist/server/server/migrations/040_screen_time_domain.sql +89 -0
  66. package/dist/server/server/migrations/041_companion_source_states.sql +21 -0
  67. package/dist/server/server/migrations/042_movement_boxes.sql +47 -0
  68. package/dist/server/server/migrations/043_movement_box_overlap_overrides.sql +26 -0
  69. package/dist/server/{app.js → server/src/app.js} +2112 -414
  70. package/dist/server/server/src/connectors/box-registry.js +223 -0
  71. package/dist/server/server/src/data-management-types.js +107 -0
  72. package/dist/server/{db.js → server/src/db.js} +72 -4
  73. package/dist/server/server/src/debug.js +19 -0
  74. package/dist/server/{demo-data.js → server/src/demo-data.js} +2 -2
  75. package/dist/server/{health.js → server/src/health.js} +702 -18
  76. package/dist/server/{managers → server/src/managers}/platform/llm-manager.js +7 -4
  77. package/dist/server/server/src/managers/platform/mock-workbench-provider.js +149 -0
  78. package/dist/server/{managers → server/src/managers}/platform/secrets-manager.js +18 -1
  79. package/dist/server/{managers → server/src/managers}/runtime.js +9 -0
  80. package/dist/server/{movement.js → server/src/movement.js} +1971 -112
  81. package/dist/server/{openapi.js → server/src/openapi.js} +491 -3
  82. package/dist/server/{psyche-types.js → server/src/psyche-types.js} +9 -1
  83. package/dist/server/{repositories → server/src/repositories}/activity-events.js +8 -0
  84. package/dist/server/{repositories → server/src/repositories}/ai-connectors.js +758 -47
  85. package/dist/server/{repositories → server/src/repositories}/calendar.js +1 -1
  86. package/dist/server/{repositories → server/src/repositories}/habits.js +37 -1
  87. package/dist/server/{repositories → server/src/repositories}/model-settings.js +13 -3
  88. package/dist/server/{repositories → server/src/repositories}/notes.js +3 -0
  89. package/dist/server/{repositories → server/src/repositories}/settings.js +431 -21
  90. package/dist/server/{repositories → server/src/repositories}/tasks.js +170 -10
  91. package/dist/server/server/src/runtime-data-root.js +82 -0
  92. package/dist/server/server/src/screen-time.js +802 -0
  93. package/dist/server/{services → server/src/services}/calendar-runtime.js +775 -58
  94. package/dist/server/server/src/services/data-management.js +788 -0
  95. package/dist/server/{services → server/src/services}/entity-crud.js +205 -2
  96. package/dist/server/server/src/services/google-calendar-oauth-config.js +176 -0
  97. package/dist/server/server/src/services/knowledge-graph.js +1455 -0
  98. package/dist/server/server/src/services/life-force-model.js +197 -0
  99. package/dist/server/server/src/services/life-force.js +1270 -0
  100. package/dist/server/server/src/services/psyche-observation-calendar.js +413 -0
  101. package/dist/server/{types.js → server/src/types.js} +420 -29
  102. package/dist/server/server/src/web.js +332 -0
  103. package/dist/server/src/components/customization/utility-widgets.js +439 -0
  104. package/dist/server/src/components/ui/info-tooltip.js +25 -0
  105. package/dist/server/src/components/workbench-boxes/calendar/calendar-boxes.js +78 -0
  106. package/dist/server/src/components/workbench-boxes/goals/goals-boxes.js +62 -0
  107. package/dist/server/src/components/workbench-boxes/habits/habits-boxes.js +62 -0
  108. package/dist/server/src/components/workbench-boxes/health/health-boxes.js +147 -0
  109. package/dist/server/src/components/workbench-boxes/insights/insights-boxes.js +50 -0
  110. package/dist/server/src/components/workbench-boxes/kanban/kanban-boxes.js +136 -0
  111. package/dist/server/src/components/workbench-boxes/movement/movement-boxes.js +47 -0
  112. package/dist/server/src/components/workbench-boxes/notes/notes-boxes.js +132 -0
  113. package/dist/server/src/components/workbench-boxes/overview/overview-boxes.js +65 -0
  114. package/dist/server/src/components/workbench-boxes/preferences/preferences-boxes.js +78 -0
  115. package/dist/server/src/components/workbench-boxes/projects/projects-boxes.js +62 -0
  116. package/dist/server/src/components/workbench-boxes/psyche/psyche-boxes.js +88 -0
  117. package/dist/server/src/components/workbench-boxes/questionnaires/questionnaires-boxes.js +61 -0
  118. package/dist/server/src/components/workbench-boxes/review/review-boxes.js +53 -0
  119. package/dist/server/src/components/workbench-boxes/shared/define-workbench-box.js +6 -0
  120. package/dist/server/src/components/workbench-boxes/shared/generic-node-view.js +49 -0
  121. package/dist/server/src/components/workbench-boxes/strategies/strategies-boxes.js +62 -0
  122. package/dist/server/src/components/workbench-boxes/tasks/tasks-boxes.js +76 -0
  123. package/dist/server/src/components/workbench-boxes/today/today-boxes.js +78 -0
  124. package/dist/server/src/components/workbench-boxes/wiki/wiki-boxes.js +60 -0
  125. package/dist/server/src/lib/api-error.js +37 -0
  126. package/dist/server/src/lib/api.js +2118 -0
  127. package/dist/server/src/lib/calendar-name-deduper.js +144 -0
  128. package/dist/server/src/lib/data-management-types.js +1 -0
  129. package/dist/server/src/lib/diagnostics.js +67 -0
  130. package/dist/server/src/lib/entity-visuals.js +279 -0
  131. package/dist/server/src/lib/knowledge-graph-types.js +276 -0
  132. package/dist/server/src/lib/knowledge-graph.js +470 -0
  133. package/dist/server/src/lib/psyche-types.js +1 -0
  134. package/dist/server/src/lib/questionnaire-types.js +1 -0
  135. package/dist/server/src/lib/runtime-paths.js +24 -0
  136. package/dist/server/src/lib/schemas.js +238 -0
  137. package/dist/server/src/lib/snapshot-normalizer.js +416 -0
  138. package/dist/server/src/lib/theme-system.js +319 -0
  139. package/dist/server/src/lib/types.js +1 -0
  140. package/dist/server/src/lib/utils.js +22 -0
  141. package/dist/server/src/lib/workbench/boxes.js +16 -0
  142. package/dist/server/src/lib/workbench/contracts.js +229 -0
  143. package/dist/server/src/lib/workbench/nodes.js +215 -0
  144. package/dist/server/src/lib/workbench/registry.js +120 -0
  145. package/dist/server/src/lib/workbench/runtime.js +397 -0
  146. package/dist/server/src/lib/workbench/tool-catalog.js +68 -0
  147. package/openclaw.plugin.json +1 -1
  148. package/package.json +1 -1
  149. package/server/index.js +68 -0
  150. package/server/migrations/035_google_local_auth_settings.sql +2 -0
  151. package/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  152. package/server/migrations/037_workbench_public_inputs_and_run_inputs.sql +5 -0
  153. package/server/migrations/038_data_management_settings.sql +11 -0
  154. package/server/migrations/039_life_force_and_action_points.sql +114 -0
  155. package/server/migrations/040_screen_time_domain.sql +89 -0
  156. package/server/migrations/041_companion_source_states.sql +21 -0
  157. package/server/migrations/042_movement_boxes.sql +47 -0
  158. package/server/migrations/043_movement_box_overlap_overrides.sql +26 -0
  159. package/skills/forge-openclaw/SKILL.md +27 -11
  160. package/skills/forge-openclaw/entity_conversation_playbooks.md +411 -46
  161. package/skills/forge-openclaw/psyche_entity_playbooks.md +195 -20
  162. package/dist/assets/index-CFCKDIMH.js +0 -67
  163. package/dist/assets/index-CFCKDIMH.js.map +0 -1
  164. package/dist/assets/index-ZPY6U1TU.css +0 -1
  165. package/dist/assets/vendor-D9PTEPSB.js +0 -824
  166. package/dist/assets/vendor-D9PTEPSB.js.map +0 -1
  167. package/dist/assets/viz-Cqb6s--o.js +0 -34
  168. package/dist/assets/viz-Cqb6s--o.js.map +0 -1
  169. package/dist/server/connectors/box-registry.js +0 -257
  170. package/dist/server/services/psyche-observation-calendar.js +0 -46
  171. package/dist/server/web.js +0 -98
  172. /package/dist/server/{discovery-advertiser.js → server/src/discovery-advertiser.js} +0 -0
  173. /package/dist/server/{e2e-server.js → server/src/e2e-server.js} +0 -0
  174. /package/dist/server/{errors.js → server/src/errors.js} +0 -0
  175. /package/dist/server/{index.js → server/src/index.js} +0 -0
  176. /package/dist/server/{managers → server/src/managers}/base.js +0 -0
  177. /package/dist/server/{managers → server/src/managers}/contracts.js +0 -0
  178. /package/dist/server/{managers → server/src/managers}/platform/api-gateway-manager.js +0 -0
  179. /package/dist/server/{managers → server/src/managers}/platform/audit-manager.js +0 -0
  180. /package/dist/server/{managers → server/src/managers}/platform/authentication-manager.js +0 -0
  181. /package/dist/server/{managers → server/src/managers}/platform/authorization-manager.js +0 -0
  182. /package/dist/server/{managers → server/src/managers}/platform/background-job-manager.js +0 -0
  183. /package/dist/server/{managers → server/src/managers}/platform/configuration-manager.js +0 -0
  184. /package/dist/server/{managers → server/src/managers}/platform/database-manager.js +0 -0
  185. /package/dist/server/{managers → server/src/managers}/platform/event-bus-manager.js +0 -0
  186. /package/dist/server/{managers → server/src/managers}/platform/external-service-manager.js +0 -0
  187. /package/dist/server/{managers → server/src/managers}/platform/health-manager.js +0 -0
  188. /package/dist/server/{managers → server/src/managers}/platform/migration-manager.js +0 -0
  189. /package/dist/server/{managers → server/src/managers}/platform/openai-responses-provider.js +0 -0
  190. /package/dist/server/{managers → server/src/managers}/platform/search-index-manager.js +0 -0
  191. /package/dist/server/{managers → server/src/managers}/platform/session-manager.js +0 -0
  192. /package/dist/server/{managers → server/src/managers}/platform/storage-manager.js +0 -0
  193. /package/dist/server/{managers → server/src/managers}/platform/token-manager.js +0 -0
  194. /package/dist/server/{managers → server/src/managers}/platform/transaction-manager.js +0 -0
  195. /package/dist/server/{managers → server/src/managers}/platform/trusted-network.js +0 -0
  196. /package/dist/server/{managers → server/src/managers}/type-guards.js +0 -0
  197. /package/dist/server/{preferences-seeds.js → server/src/preferences-seeds.js} +0 -0
  198. /package/dist/server/{preferences-types.js → server/src/preferences-types.js} +0 -0
  199. /package/dist/server/{questionnaire-flow.js → server/src/questionnaire-flow.js} +0 -0
  200. /package/dist/server/{questionnaire-seeds.js → server/src/questionnaire-seeds.js} +0 -0
  201. /package/dist/server/{questionnaire-types.js → server/src/questionnaire-types.js} +0 -0
  202. /package/dist/server/{repositories → server/src/repositories}/ai-processors.js +0 -0
  203. /package/dist/server/{repositories → server/src/repositories}/collaboration.js +0 -0
  204. /package/dist/server/{repositories → server/src/repositories}/deleted-entities.js +0 -0
  205. /package/dist/server/{repositories → server/src/repositories}/diagnostic-logs.js +0 -0
  206. /package/dist/server/{repositories → server/src/repositories}/domains.js +0 -0
  207. /package/dist/server/{repositories → server/src/repositories}/entity-ownership.js +0 -0
  208. /package/dist/server/{repositories → server/src/repositories}/event-log.js +0 -0
  209. /package/dist/server/{repositories → server/src/repositories}/goals.js +0 -0
  210. /package/dist/server/{repositories → server/src/repositories}/preferences.js +0 -0
  211. /package/dist/server/{repositories → server/src/repositories}/projects.js +0 -0
  212. /package/dist/server/{repositories → server/src/repositories}/psyche.js +0 -0
  213. /package/dist/server/{repositories → server/src/repositories}/questionnaires.js +0 -0
  214. /package/dist/server/{repositories → server/src/repositories}/rewards.js +0 -0
  215. /package/dist/server/{repositories → server/src/repositories}/strategies.js +0 -0
  216. /package/dist/server/{repositories → server/src/repositories}/surface-layouts.js +0 -0
  217. /package/dist/server/{repositories → server/src/repositories}/tags.js +0 -0
  218. /package/dist/server/{repositories → server/src/repositories}/task-runs.js +0 -0
  219. /package/dist/server/{repositories → server/src/repositories}/users.js +0 -0
  220. /package/dist/server/{repositories → server/src/repositories}/weekly-reviews.js +0 -0
  221. /package/dist/server/{repositories → server/src/repositories}/wiki-memory.js +0 -0
  222. /package/dist/server/{repositories → server/src/repositories}/work-adjustments.js +0 -0
  223. /package/dist/server/{seed-demo.js → server/src/seed-demo.js} +0 -0
  224. /package/dist/server/{services → server/src/services}/context.js +0 -0
  225. /package/dist/server/{services → server/src/services}/dashboard.js +0 -0
  226. /package/dist/server/{services → server/src/services}/gamification.js +0 -0
  227. /package/dist/server/{services → server/src/services}/insights.js +0 -0
  228. /package/dist/server/{services → server/src/services}/openai-codex-oauth.js +0 -0
  229. /package/dist/server/{services → server/src/services}/projects.js +0 -0
  230. /package/dist/server/{services → server/src/services}/psyche.js +0 -0
  231. /package/dist/server/{services → server/src/services}/relations.js +0 -0
  232. /package/dist/server/{services → server/src/services}/reviews.js +0 -0
  233. /package/dist/server/{services → server/src/services}/run-recovery.js +0 -0
  234. /package/dist/server/{services → server/src/services}/tagging.js +0 -0
  235. /package/dist/server/{services → server/src/services}/task-run-watchdog.js +0 -0
  236. /package/dist/server/{services → server/src/services}/work-time.js +0 -0
  237. /package/dist/server/{watch-mobile.js → server/src/watch-mobile.js} +0 -0
@@ -0,0 +1,332 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { access, readFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { setTimeout as delay } from "node:timers/promises";
6
+ const distDir = path.join(process.cwd(), "dist");
7
+ const packagedRuntimeDistDir = path.join(process.cwd(), "plugins", "forge-codex", "runtime", "dist");
8
+ const contentTypes = {
9
+ ".css": "text/css; charset=utf-8",
10
+ ".html": "text/html; charset=utf-8",
11
+ ".js": "application/javascript; charset=utf-8",
12
+ ".json": "application/json; charset=utf-8",
13
+ ".map": "application/json; charset=utf-8",
14
+ ".svg": "image/svg+xml",
15
+ ".woff": "font/woff",
16
+ ".woff2": "font/woff2"
17
+ };
18
+ function normalizeBasePath(value) {
19
+ if (!value || value === "/") {
20
+ return "/";
21
+ }
22
+ const withLeadingSlash = value.startsWith("/") ? value : `/${value}`;
23
+ return withLeadingSlash.endsWith("/")
24
+ ? withLeadingSlash
25
+ : `${withLeadingSlash}/`;
26
+ }
27
+ function normalizeAbsoluteUrl(value) {
28
+ const url = new URL(value);
29
+ url.pathname = normalizeBasePath(url.pathname);
30
+ return url;
31
+ }
32
+ function getDefaultBasePath() {
33
+ return process.env.FORGE_BASE_PATH ?? "/forge/";
34
+ }
35
+ function getDevWebOrigin() {
36
+ const value = process.env.FORGE_DEV_WEB_ORIGIN?.trim();
37
+ return value && value.length > 0 ? value : null;
38
+ }
39
+ function shouldAutostartDevWeb(env) {
40
+ const value = env.FORGE_DEV_WEB_AUTOSTART?.trim().toLowerCase();
41
+ return value !== "0" && value !== "false" && value !== "no";
42
+ }
43
+ function getDevWebCommand(env) {
44
+ const value = env.FORGE_DEV_WEB_COMMAND?.trim();
45
+ return value && value.length > 0 ? value : "npm run dev:web";
46
+ }
47
+ function getDefaultDevWebOriginPort(origin) {
48
+ if (origin?.port && origin.port.trim().length > 0) {
49
+ return origin.port;
50
+ }
51
+ if (origin?.protocol === "https:") {
52
+ return "443";
53
+ }
54
+ return "3027";
55
+ }
56
+ function getDefaultViteCliPath(cwd) {
57
+ const candidate = path.join(cwd, "node_modules", "vite", "bin", "vite.js");
58
+ return existsSync(candidate) ? candidate : null;
59
+ }
60
+ function buildManagedDevWebLaunch(input) {
61
+ const explicitCommand = input.env.FORGE_DEV_WEB_COMMAND?.trim();
62
+ if (explicitCommand && explicitCommand.length > 0) {
63
+ return {
64
+ command: explicitCommand,
65
+ env: input.env,
66
+ shell: true
67
+ };
68
+ }
69
+ const viteCliPath = getDefaultViteCliPath(input.cwd);
70
+ if (!viteCliPath) {
71
+ return {
72
+ command: getDevWebCommand(input.env),
73
+ env: input.env,
74
+ shell: true
75
+ };
76
+ }
77
+ const host = input.env.FORGE_DEV_WEB_HOST?.trim() || "127.0.0.1";
78
+ const port = input.env.FORGE_DEV_WEB_PORT?.trim() || getDefaultDevWebOriginPort(input.origin);
79
+ return {
80
+ command: process.execPath,
81
+ args: [viteCliPath, "--host", host, "--port", port],
82
+ env: {
83
+ ...input.env,
84
+ FORGE_BASE_PATH: getDefaultBasePath()
85
+ },
86
+ shell: false
87
+ };
88
+ }
89
+ function stripBasePath(requestPath, basePath) {
90
+ const normalizedBasePath = normalizeBasePath(basePath);
91
+ if (normalizedBasePath === "/") {
92
+ return requestPath;
93
+ }
94
+ const normalizedRoot = normalizedBasePath.slice(0, -1);
95
+ if (requestPath === normalizedRoot) {
96
+ return "/";
97
+ }
98
+ if (requestPath.startsWith(normalizedBasePath)) {
99
+ const stripped = requestPath.slice(normalizedRoot.length);
100
+ return stripped.startsWith("/") ? stripped : `/${stripped}`;
101
+ }
102
+ return requestPath;
103
+ }
104
+ function resolveAsset(clientDir, requestPath) {
105
+ if (requestPath === "/") {
106
+ return path.join(clientDir, "index.html");
107
+ }
108
+ const safePath = requestPath.replace(/^\/+/, "");
109
+ return path.join(clientDir, safePath);
110
+ }
111
+ async function getClientDir() {
112
+ try {
113
+ await access(path.join(distDir, "index.html"));
114
+ return distDir;
115
+ }
116
+ catch {
117
+ await access(path.join(packagedRuntimeDistDir, "index.html"));
118
+ return packagedRuntimeDistDir;
119
+ }
120
+ }
121
+ function parseRequestTarget(requestPath) {
122
+ return new URL(requestPath, "http://forge.local");
123
+ }
124
+ function copyProxyHeaders(response, reply) {
125
+ for (const [name, value] of response.headers) {
126
+ const lowerName = name.toLowerCase();
127
+ if (lowerName === "connection" ||
128
+ lowerName === "content-length" ||
129
+ lowerName === "keep-alive" ||
130
+ lowerName === "transfer-encoding") {
131
+ continue;
132
+ }
133
+ reply.header(name, value);
134
+ }
135
+ }
136
+ async function proxyDevAsset(input) {
137
+ const target = new URL(input.pathname.startsWith("/") ? input.pathname.slice(1) : input.pathname, input.origin);
138
+ target.search = input.search;
139
+ const response = await input.fetchImpl(target, { redirect: "manual" });
140
+ input.reply.code(response.status);
141
+ copyProxyHeaders(response, input.reply);
142
+ if (!response.headers.has("cache-control")) {
143
+ input.reply.header("Cache-Control", "no-store, max-age=0, must-revalidate");
144
+ }
145
+ if (!response.body) {
146
+ return "";
147
+ }
148
+ return Buffer.from(await response.arrayBuffer());
149
+ }
150
+ async function waitForProcessExit(child, timeoutMs = 5_000) {
151
+ if (child.exitCode !== null) {
152
+ return;
153
+ }
154
+ await Promise.race([
155
+ new Promise((resolve) => {
156
+ child.once("exit", () => resolve());
157
+ child.once("close", () => resolve());
158
+ }),
159
+ delay(timeoutMs).then(() => { })
160
+ ]);
161
+ }
162
+ export function createManagedDevWebRuntime(options = {}) {
163
+ const env = options.env ?? process.env;
164
+ const originValue = env.FORGE_DEV_WEB_ORIGIN?.trim();
165
+ const origin = originValue ? normalizeAbsoluteUrl(originValue) : null;
166
+ const cwd = options.cwd ?? process.cwd();
167
+ const fetchImpl = options.fetchImpl ?? fetch;
168
+ const spawnImpl = options.spawnImpl ?? spawn;
169
+ const autostart = shouldAutostartDevWeb(env);
170
+ const waitTimeoutMs = Number(env.FORGE_DEV_WEB_START_TIMEOUT_MS ?? 30_000);
171
+ const pollIntervalMs = 500;
172
+ let child = null;
173
+ let startupPromise = null;
174
+ async function probe() {
175
+ if (!origin) {
176
+ return null;
177
+ }
178
+ const controller = new AbortController();
179
+ const timeout = setTimeout(() => controller.abort(), 1_500);
180
+ try {
181
+ const response = await fetchImpl(origin, {
182
+ method: "GET",
183
+ redirect: "manual",
184
+ signal: controller.signal
185
+ });
186
+ return response.status < 500 ? origin : null;
187
+ }
188
+ catch {
189
+ return null;
190
+ }
191
+ finally {
192
+ clearTimeout(timeout);
193
+ }
194
+ }
195
+ async function waitUntilReady(processRef) {
196
+ const startedAt = Date.now();
197
+ while (Date.now() - startedAt < waitTimeoutMs) {
198
+ const readyOrigin = await probe();
199
+ if (readyOrigin) {
200
+ return readyOrigin;
201
+ }
202
+ if (processRef.exitCode !== null) {
203
+ break;
204
+ }
205
+ await delay(pollIntervalMs);
206
+ }
207
+ return null;
208
+ }
209
+ async function ensureReady() {
210
+ if (!origin) {
211
+ return null;
212
+ }
213
+ const readyOrigin = await probe();
214
+ if (readyOrigin || !autostart) {
215
+ return readyOrigin;
216
+ }
217
+ if (!startupPromise) {
218
+ startupPromise = (async () => {
219
+ if (!child || child.exitCode !== null) {
220
+ const launch = buildManagedDevWebLaunch({ cwd, env, origin });
221
+ const nextChild = launch.shell
222
+ ? spawnImpl(launch.command, {
223
+ cwd,
224
+ env: launch.env,
225
+ shell: true,
226
+ stdio: "inherit"
227
+ })
228
+ : spawnImpl(launch.command, launch.args ?? [], {
229
+ cwd,
230
+ env: launch.env,
231
+ stdio: "inherit"
232
+ });
233
+ child = nextChild;
234
+ nextChild.once("exit", () => {
235
+ if (child === nextChild) {
236
+ child = null;
237
+ }
238
+ });
239
+ }
240
+ const startedOrigin = await waitUntilReady(child);
241
+ startupPromise = null;
242
+ return startedOrigin;
243
+ })().catch((error) => {
244
+ startupPromise = null;
245
+ throw error;
246
+ });
247
+ }
248
+ return startupPromise;
249
+ }
250
+ async function stop() {
251
+ if (!child || child.exitCode !== null) {
252
+ return;
253
+ }
254
+ const childRef = child;
255
+ childRef.kill("SIGTERM");
256
+ await waitForProcessExit(childRef);
257
+ if (childRef.exitCode === null) {
258
+ childRef.kill("SIGKILL");
259
+ await waitForProcessExit(childRef, 1_000);
260
+ }
261
+ child = null;
262
+ }
263
+ return {
264
+ ensureReady,
265
+ stop
266
+ };
267
+ }
268
+ async function serveAsset(requestPath, reply, options) {
269
+ const requestTarget = parseRequestTarget(requestPath);
270
+ if (requestTarget.pathname.startsWith("/api")) {
271
+ reply.code(404);
272
+ return { error: "Not found" };
273
+ }
274
+ const normalizedRequestPath = stripBasePath(requestTarget.pathname, getDefaultBasePath());
275
+ const devWebOrigin = await options.devWebRuntime.ensureReady();
276
+ if (devWebOrigin) {
277
+ try {
278
+ return await proxyDevAsset({
279
+ origin: devWebOrigin,
280
+ pathname: normalizedRequestPath,
281
+ search: requestTarget.search,
282
+ reply,
283
+ fetchImpl: options.fetchImpl
284
+ });
285
+ }
286
+ catch {
287
+ reply.header("X-Forge-Web-Fallback", "built");
288
+ }
289
+ }
290
+ const clientDir = await getClientDir();
291
+ const assetPath = resolveAsset(clientDir, normalizedRequestPath);
292
+ const ext = path.extname(assetPath);
293
+ try {
294
+ const payload = await readFile(assetPath);
295
+ reply.type(contentTypes[ext] ?? "application/octet-stream");
296
+ reply.header("Cache-Control", "no-store, max-age=0, must-revalidate");
297
+ if (ext === ".html") {
298
+ reply.header("Pragma", "no-cache");
299
+ }
300
+ return payload;
301
+ }
302
+ catch {
303
+ if (!path.extname(normalizedRequestPath)) {
304
+ try {
305
+ const payload = await readFile(path.join(clientDir, "index.html"));
306
+ reply.type(contentTypes[".html"]);
307
+ reply.header("Cache-Control", "no-store, max-age=0, must-revalidate");
308
+ reply.header("Pragma", "no-cache");
309
+ return payload;
310
+ }
311
+ catch {
312
+ reply.code(503);
313
+ return {
314
+ code: "frontend_not_built",
315
+ error: "Forge frontend build output is missing. Run the Vite build before serving the modern web client.",
316
+ statusCode: 503
317
+ };
318
+ }
319
+ }
320
+ reply.code(404);
321
+ return { error: "Asset not found" };
322
+ }
323
+ }
324
+ export async function registerWebRoutes(app, options = {}) {
325
+ const devWebRuntime = options.devWebRuntime ?? createManagedDevWebRuntime();
326
+ const fetchImpl = options.fetchImpl ?? fetch;
327
+ app.addHook("onClose", async () => {
328
+ await devWebRuntime.stop();
329
+ });
330
+ app.get("/", async (_request, reply) => serveAsset("/", reply, { devWebRuntime, fetchImpl }));
331
+ app.get("/*", async (request, reply) => serveAsset(request.url, reply, { devWebRuntime, fetchImpl }));
332
+ }