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
@@ -1,4 +1,6 @@
1
+ import { z, ZodError } from "zod";
1
2
  import { getDatabase, runInTransaction } from "../db.js";
3
+ import { createSleepSession, createSleepSessionSchema, createWorkoutSession, createWorkoutSessionSchema, deleteSleepSession, deleteWorkoutSession, getSleepSessionById, getWorkoutSessionById, listSleepSessions, listWorkoutSessions, updateSleepSession, updateSleepSessionSchema, updateWorkoutSession, updateWorkoutSessionSchema } from "../health.js";
2
4
  import { createInsight, deleteInsight, getInsightById, listInsights, updateInsight } from "../repositories/collaboration.js";
3
5
  import { createCalendarEvent, createTaskTimebox, createWorkBlockTemplate, deleteCalendarEvent, deleteTaskTimebox, deleteWorkBlockTemplate, getCalendarEventById, getTaskTimeboxById, getWorkBlockTemplateById, listCalendarEvents, listTaskTimeboxes, listWorkBlockTemplates, updateCalendarEvent, updateTaskTimebox, updateWorkBlockTemplate } from "../repositories/calendar.js";
4
6
  import { createNote, deleteNote, getNoteById, listNotes, unlinkNotesForEntity, updateNote } from "../repositories/notes.js";
@@ -155,6 +157,28 @@ const CRUD_ENTITY_CAPABILITIES = {
155
157
  update: (id, patch) => updateTaskTimebox(id, patch),
156
158
  hardDelete: (id) => deleteTaskTimebox(id)
157
159
  },
160
+ sleep_session: {
161
+ entityType: "sleep_session",
162
+ routeBase: "/api/v1/health/sleep",
163
+ deleteMode: "immediate",
164
+ inBin: false,
165
+ list: () => listSleepSessions(),
166
+ get: (id) => getSleepSessionById(id),
167
+ create: (data, context) => createSleepSession(data, context),
168
+ update: (id, patch, context) => updateSleepSession(id, patch, context),
169
+ hardDelete: (id, context) => deleteSleepSession(id, context)
170
+ },
171
+ workout_session: {
172
+ entityType: "workout_session",
173
+ routeBase: "/api/v1/health/workouts",
174
+ deleteMode: "immediate",
175
+ inBin: false,
176
+ list: () => listWorkoutSessions(),
177
+ get: (id) => getWorkoutSessionById(id),
178
+ create: (data, context) => createWorkoutSession(data, context),
179
+ update: (id, patch, context) => updateWorkoutSession(id, patch, context),
180
+ hardDelete: (id, context) => deleteWorkoutSession(id, context)
181
+ },
158
182
  psyche_value: {
159
183
  entityType: "psyche_value",
160
184
  routeBase: "/api/v1/psyche/values",
@@ -335,6 +359,8 @@ const CREATE_ENTITY_SCHEMAS = {
335
359
  calendar_event: createCalendarEventSchema,
336
360
  work_block_template: createWorkBlockTemplateSchema,
337
361
  task_timebox: createTaskTimeboxSchema,
362
+ sleep_session: createSleepSessionSchema,
363
+ workout_session: createWorkoutSessionSchema,
338
364
  psyche_value: createPsycheValueSchema,
339
365
  behavior_pattern: createBehaviorPatternSchema,
340
366
  behavior: createBehaviorSchema,
@@ -362,6 +388,8 @@ const UPDATE_ENTITY_SCHEMAS = {
362
388
  calendar_event: updateCalendarEventSchema,
363
389
  work_block_template: updateWorkBlockTemplateSchema,
364
390
  task_timebox: updateTaskTimeboxSchema,
391
+ sleep_session: updateSleepSessionSchema,
392
+ workout_session: updateWorkoutSessionSchema,
365
393
  psyche_value: updatePsycheValueSchema,
366
394
  behavior_pattern: updateBehaviorPatternSchema,
367
395
  behavior: updateBehaviorSchema,
@@ -377,11 +405,151 @@ const UPDATE_ENTITY_SCHEMAS = {
377
405
  preference_item: updatePreferenceItemSchema,
378
406
  questionnaire_instrument: updateQuestionnaireInstrumentSchema
379
407
  };
408
+ function getCreateSchema(entityType) {
409
+ return CREATE_ENTITY_SCHEMAS[entityType];
410
+ }
411
+ function getUpdateSchema(entityType) {
412
+ return UPDATE_ENTITY_SCHEMAS[entityType];
413
+ }
414
+ function unwrapSchema(schema) {
415
+ if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable) {
416
+ return unwrapSchema(schema.unwrap());
417
+ }
418
+ if (schema instanceof z.ZodDefault) {
419
+ return unwrapSchema(schema.removeDefault());
420
+ }
421
+ if (schema instanceof z.ZodEffects) {
422
+ return unwrapSchema(schema.innerType());
423
+ }
424
+ return schema;
425
+ }
426
+ function isRequiredField(schema) {
427
+ if (schema instanceof z.ZodOptional) {
428
+ return false;
429
+ }
430
+ if (schema instanceof z.ZodDefault) {
431
+ return false;
432
+ }
433
+ return true;
434
+ }
435
+ function collectRequiredTopLevelFields(schema) {
436
+ const unwrapped = unwrapSchema(schema);
437
+ if (!(unwrapped instanceof z.ZodObject)) {
438
+ return [];
439
+ }
440
+ return Object.entries(unwrapped.shape)
441
+ .filter(([, fieldSchema]) => isRequiredField(fieldSchema))
442
+ .map(([key]) => key)
443
+ .sort();
444
+ }
445
+ function extractAllowedTopLevelFields(schema) {
446
+ const unwrapped = unwrapSchema(schema);
447
+ if (!(unwrapped instanceof z.ZodObject)) {
448
+ return [];
449
+ }
450
+ return Object.keys(unwrapped.shape).sort();
451
+ }
452
+ function buildExampleValue(schema) {
453
+ const unwrapped = unwrapSchema(schema);
454
+ if (unwrapped instanceof z.ZodString) {
455
+ return "string";
456
+ }
457
+ if (unwrapped instanceof z.ZodNumber) {
458
+ return 0;
459
+ }
460
+ if (unwrapped instanceof z.ZodBoolean) {
461
+ return false;
462
+ }
463
+ if (unwrapped instanceof z.ZodArray) {
464
+ return [];
465
+ }
466
+ if (unwrapped instanceof z.ZodRecord) {
467
+ return {};
468
+ }
469
+ if (unwrapped instanceof z.ZodEnum) {
470
+ return unwrapped.options[0];
471
+ }
472
+ if (unwrapped instanceof z.ZodLiteral) {
473
+ return unwrapped.value;
474
+ }
475
+ if (unwrapped instanceof z.ZodUnion) {
476
+ return buildExampleValue(unwrapped.options[0] ?? z.string());
477
+ }
478
+ if (unwrapped instanceof z.ZodObject) {
479
+ const objectValue = {};
480
+ for (const [key, fieldSchema] of Object.entries(unwrapped.shape)) {
481
+ if (!isRequiredField(fieldSchema)) {
482
+ continue;
483
+ }
484
+ objectValue[key] = buildExampleValue(fieldSchema);
485
+ }
486
+ return objectValue;
487
+ }
488
+ return "value";
489
+ }
490
+ function buildMinimalExamplePayload(schema) {
491
+ const unwrapped = unwrapSchema(schema);
492
+ if (!(unwrapped instanceof z.ZodObject)) {
493
+ return {};
494
+ }
495
+ const requiredFields = collectRequiredTopLevelFields(schema);
496
+ const example = {};
497
+ for (const field of requiredFields) {
498
+ example[field] = buildExampleValue(unwrapped.shape[field]);
499
+ }
500
+ return example;
501
+ }
502
+ function formatIssuePath(path) {
503
+ return path.length > 0 ? path.map(String).join(".") : "body";
504
+ }
505
+ function buildValidationOperationError(input) {
506
+ const issues = input.error.issues.map((issue) => {
507
+ const allowedValues = "options" in issue && Array.isArray(issue.options)
508
+ ? [...issue.options]
509
+ : undefined;
510
+ return {
511
+ path: formatIssuePath(issue.path),
512
+ message: issue.message,
513
+ code: issue.code,
514
+ ...(allowedValues ? { allowedValues } : {})
515
+ };
516
+ });
517
+ const missingRequiredFields = Array.from(new Set(input.error.issues
518
+ .filter((issue) => issue.code === "invalid_type" &&
519
+ "received" in issue &&
520
+ issue.received === "undefined" &&
521
+ issue.path.length > 0)
522
+ .map((issue) => formatIssuePath(issue.path)))).sort();
523
+ const invalidValueGuidance = input.error.issues
524
+ .filter((issue) => "options" in issue && Array.isArray(issue.options))
525
+ .map((issue) => ({
526
+ path: formatIssuePath(issue.path),
527
+ allowedValues: [...(issue.options ?? [])],
528
+ message: issue.message
529
+ }));
530
+ return {
531
+ code: input.code,
532
+ message: input.message,
533
+ operationType: input.operationType,
534
+ entityType: input.entityType,
535
+ clientRef: input.clientRef,
536
+ routeHint: `/api/v1/entities/${input.operationType}`,
537
+ toolHint: input.operationType === "search"
538
+ ? "forge_search_entities"
539
+ : `forge_${input.operationType}_entities`,
540
+ summary: `${input.entityType} ${input.operationType} payload failed validation.`,
541
+ issues,
542
+ missingRequiredFields,
543
+ invalidValueGuidance,
544
+ allowedTopLevelFields: extractAllowedTopLevelFields(input.schema),
545
+ minimalExamplePayload: buildMinimalExamplePayload(input.schema)
546
+ };
547
+ }
380
548
  function parseCreateInput(entityType, data) {
381
- return CREATE_ENTITY_SCHEMAS[entityType].parse(data);
549
+ return getCreateSchema(entityType).parse(data);
382
550
  }
383
551
  function parseUpdatePatch(entityType, patch) {
384
- return UPDATE_ENTITY_SCHEMAS[entityType].parse(patch);
552
+ return getUpdateSchema(entityType).parse(patch);
385
553
  }
386
554
  function toOperationError(code, message) {
387
555
  return {
@@ -506,6 +674,8 @@ function matchesLinkedTo(entityType, entity, linkedTo) {
506
674
  case "insight":
507
675
  return entity.entityType === linkedTo.entityType && entity.entityId === linkedTo.id;
508
676
  case "calendar_event":
677
+ case "sleep_session":
678
+ case "workout_session":
509
679
  return (Array.isArray(entity.links) &&
510
680
  entity.links.some((link) => typeof link === "object" &&
511
681
  link !== null &&
@@ -654,6 +824,22 @@ export function createEntities(input, context) {
654
824
  return { ok: true, entityType: entry.entityType, clientRef: entry.clientRef, id: String(entity.id ?? ""), entity };
655
825
  }
656
826
  catch (error) {
827
+ if (error instanceof ZodError) {
828
+ return {
829
+ ok: false,
830
+ entityType: entry.entityType,
831
+ clientRef: entry.clientRef,
832
+ error: buildValidationOperationError({
833
+ code: "validation_failed",
834
+ message: "Entity create payload validation failed.",
835
+ operationType: "create",
836
+ entityType: entry.entityType,
837
+ clientRef: entry.clientRef,
838
+ schema: getCreateSchema(entry.entityType),
839
+ error
840
+ })
841
+ };
842
+ }
657
843
  return {
658
844
  ok: false,
659
845
  entityType: entry.entityType,
@@ -679,6 +865,23 @@ export function updateEntities(input, context) {
679
865
  return { ok: true, entityType: entry.entityType, id: entry.id, clientRef: entry.clientRef, entity };
680
866
  }
681
867
  catch (error) {
868
+ if (error instanceof ZodError) {
869
+ return {
870
+ ok: false,
871
+ entityType: entry.entityType,
872
+ id: entry.id,
873
+ clientRef: entry.clientRef,
874
+ error: buildValidationOperationError({
875
+ code: "validation_failed",
876
+ message: "Entity update payload validation failed.",
877
+ operationType: "update",
878
+ entityType: entry.entityType,
879
+ clientRef: entry.clientRef,
880
+ schema: getUpdateSchema(entry.entityType),
881
+ error
882
+ })
883
+ };
884
+ }
682
885
  return {
683
886
  ok: false,
684
887
  entityType: entry.entityType,
@@ -0,0 +1,176 @@
1
+ import { createDecipheriv, createHash } from "node:crypto";
2
+ const GOOGLE_CALLBACK_PATH = "/api/v1/calendar/oauth/google/callback";
3
+ const DEFAULT_APP_PORT = "4317";
4
+ const DEFAULT_APP_BASE_URL = `http://127.0.0.1:${DEFAULT_APP_PORT}`;
5
+ const PACKAGED_DEFAULT_GOOGLE_CREDENTIAL_KEY_MATERIAL = [
6
+ "forge",
7
+ "desktop",
8
+ "oauth",
9
+ "default",
10
+ "google",
11
+ "bundle",
12
+ "2026",
13
+ "local"
14
+ ];
15
+ const PACKAGED_DEFAULT_GOOGLE_CLIENT_ID_ENCRYPTED = {
16
+ iv: "2fc1a6723312a10b7d176f13",
17
+ data: "9fbdf9dfcd1cc8674fa46150dd0f4678df8ce1ba52cdf0ceb4d4a76c9c5df01b3d8a21f194201c827524a6e06b0d4a55c7002edb3fa20b76b67f540e46ba28f506a73edaf6559a1d",
18
+ tag: "1965dfe1213ecd888e46ea59241d03a9"
19
+ };
20
+ const PACKAGED_DEFAULT_GOOGLE_CLIENT_SECRET_ENCRYPTED = {
21
+ iv: "5a6ca66625e0ff5559b34f99",
22
+ data: "b80dec231f029d92a13426ad3f0b851e20a5b35ec6691e517744fd65349144e75005f1",
23
+ tag: "9d2cfd8a153d91f60d8c628bbe1c2f25"
24
+ };
25
+ const DEFAULT_DEV_WEB_ORIGINS = [
26
+ "http://127.0.0.1:3027",
27
+ "http://localhost:3027"
28
+ ];
29
+ function decryptPackagedGoogleOauthValue(payload) {
30
+ const key = createHash("sha256")
31
+ .update(PACKAGED_DEFAULT_GOOGLE_CREDENTIAL_KEY_MATERIAL.join(":"))
32
+ .digest();
33
+ const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(payload.iv, "hex"));
34
+ decipher.setAuthTag(Buffer.from(payload.tag, "hex"));
35
+ const decrypted = Buffer.concat([
36
+ decipher.update(Buffer.from(payload.data, "hex")),
37
+ decipher.final()
38
+ ]);
39
+ return decrypted.toString("utf8");
40
+ }
41
+ const PACKAGED_DEFAULT_GOOGLE_CLIENT_ID = decryptPackagedGoogleOauthValue(PACKAGED_DEFAULT_GOOGLE_CLIENT_ID_ENCRYPTED);
42
+ const PACKAGED_DEFAULT_GOOGLE_CLIENT_SECRET = decryptPackagedGoogleOauthValue(PACKAGED_DEFAULT_GOOGLE_CLIENT_SECRET_ENCRYPTED);
43
+ function runtimeOriginFromEnv(env) {
44
+ const port = env.PORT?.trim() || DEFAULT_APP_PORT;
45
+ return `http://127.0.0.1:${port}`;
46
+ }
47
+ function normalizeOrigin(value, fieldLabel) {
48
+ let url;
49
+ try {
50
+ url = new URL(value);
51
+ }
52
+ catch {
53
+ throw new Error(`${fieldLabel} must be a full URL.`);
54
+ }
55
+ if (url.protocol !== "http:") {
56
+ throw new Error(`${fieldLabel} must use http in local Forge mode.`);
57
+ }
58
+ if (url.pathname !== "/" && url.pathname !== "") {
59
+ throw new Error(`${fieldLabel} must not include a path.`);
60
+ }
61
+ return url.origin;
62
+ }
63
+ function isLoopbackHostname(hostname) {
64
+ return hostname === "127.0.0.1" || hostname === "localhost";
65
+ }
66
+ function normalizeLoopbackOrigin(value, fieldLabel) {
67
+ const origin = normalizeOrigin(value, fieldLabel);
68
+ const url = new URL(origin);
69
+ if (!isLoopbackHostname(url.hostname)) {
70
+ throw new Error(`${fieldLabel} must use localhost or 127.0.0.1 in local Forge mode.`);
71
+ }
72
+ return origin;
73
+ }
74
+ function normalizeRedirectUri(value, appBaseUrl) {
75
+ let url;
76
+ try {
77
+ url = new URL(value);
78
+ }
79
+ catch {
80
+ throw new Error("GOOGLE_REDIRECT_URI must be a full URL.");
81
+ }
82
+ if (url.protocol !== "http:") {
83
+ throw new Error("GOOGLE_REDIRECT_URI must use http in local Forge mode.");
84
+ }
85
+ if (!isLoopbackHostname(url.hostname)) {
86
+ throw new Error("GOOGLE_REDIRECT_URI must use localhost or 127.0.0.1 in local Forge mode.");
87
+ }
88
+ if (url.pathname !== GOOGLE_CALLBACK_PATH) {
89
+ throw new Error(`GOOGLE_REDIRECT_URI must end with ${GOOGLE_CALLBACK_PATH}.`);
90
+ }
91
+ if (url.origin !== appBaseUrl) {
92
+ throw new Error(`GOOGLE_REDIRECT_URI must use the same origin as APP_BASE_URL (${appBaseUrl}).`);
93
+ }
94
+ return url.toString();
95
+ }
96
+ function normalizeAllowedOrigins(value, appBaseUrl) {
97
+ const rawValues = value && value.trim().length > 0
98
+ ? value
99
+ .split(",")
100
+ .map((entry) => entry.trim())
101
+ .filter((entry) => entry.length > 0)
102
+ : [appBaseUrl, ...DEFAULT_DEV_WEB_ORIGINS];
103
+ const normalized = rawValues.map((entry) => normalizeLoopbackOrigin(entry, "GOOGLE_ALLOWED_ORIGINS"));
104
+ return Array.from(new Set(normalized));
105
+ }
106
+ export function getGoogleCalendarOauthCallbackPath() {
107
+ return GOOGLE_CALLBACK_PATH;
108
+ }
109
+ export function resolveGoogleCalendarOauthPublicConfig(env = process.env, overrides) {
110
+ const runtimeOrigin = runtimeOriginFromEnv(env);
111
+ const appBaseUrl = normalizeLoopbackOrigin(env.APP_BASE_URL?.trim() ||
112
+ env.APP_URL?.trim() ||
113
+ DEFAULT_APP_BASE_URL, env.APP_BASE_URL?.trim() ? "APP_BASE_URL" : "APP_URL");
114
+ const redirectUri = normalizeRedirectUri(env.GOOGLE_REDIRECT_URI?.trim() || `${appBaseUrl}${GOOGLE_CALLBACK_PATH}`, appBaseUrl);
115
+ const allowedOrigins = normalizeAllowedOrigins(env.GOOGLE_ALLOWED_ORIGINS, appBaseUrl);
116
+ const storedClientId = overrides?.clientId?.trim() || "";
117
+ const storedClientSecret = overrides?.clientSecret?.trim() || "";
118
+ const envClientId = env.GOOGLE_CLIENT_ID?.trim() || "";
119
+ const envClientSecret = env.GOOGLE_CLIENT_SECRET?.trim() || "";
120
+ const hasStoredOverride = storedClientId.length > 0 || storedClientSecret.length > 0;
121
+ const hasEnvOverride = envClientId.length > 0 || envClientSecret.length > 0;
122
+ const clientId = hasStoredOverride
123
+ ? storedClientId
124
+ : hasEnvOverride
125
+ ? envClientId
126
+ : PACKAGED_DEFAULT_GOOGLE_CLIENT_ID.trim();
127
+ const clientSecret = hasStoredOverride
128
+ ? storedClientSecret
129
+ : hasEnvOverride
130
+ ? envClientSecret
131
+ : PACKAGED_DEFAULT_GOOGLE_CLIENT_SECRET.trim();
132
+ const isConfigured = clientId.length > 0;
133
+ const hasIncompleteStoredOverride = storedClientId.length > 0 !== storedClientSecret.length > 0;
134
+ const setupMessage = hasIncompleteStoredOverride
135
+ ? "Google OAuth override is incomplete for this Forge install. Save both the client ID and client secret together, or clear both fields to use the packaged default."
136
+ : isConfigured
137
+ ? "Google Calendar sign-in is configured for local Forge. Open Forge on localhost or 127.0.0.1 on the same machine that is running Forge, because Google will redirect back to the local callback on that machine."
138
+ : "Google client ID is not set for this Forge install.";
139
+ return {
140
+ clientId,
141
+ clientSecret,
142
+ storedClientId,
143
+ storedClientSecret,
144
+ appBaseUrl,
145
+ redirectUri,
146
+ allowedOrigins,
147
+ usesPkce: true,
148
+ requiresServerClientSecret: false,
149
+ oauthClientType: "desktop_app",
150
+ authMode: "localhost_pkce",
151
+ isConfigured,
152
+ isReadyForPairing: isConfigured && !hasIncompleteStoredOverride,
153
+ isLocalOnly: true,
154
+ runtimeOrigin,
155
+ setupMessage
156
+ };
157
+ }
158
+ export function resolveGoogleCalendarOauthPrivateConfig(env = process.env, overrides) {
159
+ return resolveGoogleCalendarOauthPublicConfig(env, overrides);
160
+ }
161
+ export function isGoogleCalendarOriginAllowed(origin, allowedOrigins) {
162
+ try {
163
+ return allowedOrigins.includes(new URL(origin).origin);
164
+ }
165
+ catch {
166
+ return false;
167
+ }
168
+ }
169
+ export function isGoogleCalendarLoopbackOrigin(origin) {
170
+ try {
171
+ return isLoopbackHostname(new URL(origin).hostname);
172
+ }
173
+ catch {
174
+ return false;
175
+ }
176
+ }