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,238 @@
1
+ import { z } from "zod";
2
+ import { forgeCustomThemeSchema, forgeThemePreferenceSchema } from "@/lib/theme-system";
3
+ export const appLocaleSchema = z.enum(["en", "fr"]);
4
+ export const inlineCreateNoteSchema = z.object({
5
+ contentMarkdown: z.string().trim().min(1, "Note content is required"),
6
+ author: z.string().trim()
7
+ });
8
+ export const goalMutationSchema = z.object({
9
+ title: z.string().trim().min(1, "Title is required"),
10
+ description: z.string().trim(),
11
+ horizon: z.enum(["quarter", "year", "lifetime"]),
12
+ status: z.enum(["active", "paused", "completed"]),
13
+ userId: z.string().trim().nullable().optional(),
14
+ targetPoints: z.coerce.number().int().min(25).max(10000),
15
+ themeColor: z
16
+ .string()
17
+ .trim()
18
+ .regex(/^#[0-9a-fA-F]{6}$/, "Theme color must be a valid hex value"),
19
+ tagIds: z.array(z.string()),
20
+ notes: z.array(inlineCreateNoteSchema)
21
+ });
22
+ export const projectMutationSchema = z.object({
23
+ goalId: z.string().trim().min(1, "Life goal is required"),
24
+ title: z.string().trim().min(1, "Title is required"),
25
+ description: z.string().trim(),
26
+ status: z.enum(["active", "paused", "completed"]),
27
+ userId: z.string().trim().nullable().optional(),
28
+ targetPoints: z.coerce.number().int().min(25).max(10000),
29
+ themeColor: z
30
+ .string()
31
+ .trim()
32
+ .regex(/^#[0-9a-fA-F]{6}$/, "Theme color must be a valid hex value"),
33
+ notes: z.array(inlineCreateNoteSchema)
34
+ });
35
+ export const settingsMutationSchema = z.object({
36
+ profile: z.object({
37
+ operatorName: z.string().trim().min(1, "Name is required"),
38
+ operatorEmail: z.string().trim().min(1, "Email is required"),
39
+ operatorTitle: z.string().trim().min(1, "Title is required")
40
+ }),
41
+ notifications: z.object({
42
+ goalDriftAlerts: z.boolean(),
43
+ dailyQuestReminders: z.boolean(),
44
+ achievementCelebrations: z.boolean()
45
+ }),
46
+ execution: z.object({
47
+ maxActiveTasks: z.coerce.number().int().min(1).max(8),
48
+ timeAccountingMode: z.enum(["split", "parallel", "primary_only"])
49
+ }),
50
+ themePreference: forgeThemePreferenceSchema,
51
+ customTheme: forgeCustomThemeSchema.nullable().optional(),
52
+ localePreference: appLocaleSchema,
53
+ calendarProviders: z
54
+ .object({
55
+ google: z
56
+ .object({
57
+ clientId: z.string().trim().optional(),
58
+ clientSecret: z.string().trim().optional(),
59
+ storedClientId: z.string().optional(),
60
+ storedClientSecret: z.string().optional(),
61
+ appBaseUrl: z.string().optional(),
62
+ redirectUri: z.string().optional(),
63
+ allowedOrigins: z.array(z.string()).optional(),
64
+ usesPkce: z.literal(true).optional(),
65
+ requiresServerClientSecret: z.literal(false).optional(),
66
+ oauthClientType: z.literal("desktop_app").optional(),
67
+ authMode: z.literal("localhost_pkce").optional(),
68
+ isConfigured: z.boolean().optional(),
69
+ isReadyForPairing: z.boolean().optional(),
70
+ isLocalOnly: z.literal(true).optional(),
71
+ runtimeOrigin: z.string().optional(),
72
+ setupMessage: z.string().optional()
73
+ })
74
+ .optional(),
75
+ microsoft: z
76
+ .object({
77
+ clientId: z.string().trim(),
78
+ tenantId: z.string().trim(),
79
+ redirectUri: z.string().trim()
80
+ })
81
+ .optional()
82
+ })
83
+ .optional()
84
+ .superRefine((value, context) => {
85
+ const google = value?.google;
86
+ if (!google) {
87
+ return;
88
+ }
89
+ const hasClientIdField = google.clientId !== undefined;
90
+ const hasClientSecretField = google.clientSecret !== undefined;
91
+ const hasClientIdValue = (google.clientId?.length ?? 0) > 0;
92
+ const hasClientSecretValue = (google.clientSecret?.length ?? 0) > 0;
93
+ if (hasClientIdField !== hasClientSecretField) {
94
+ context.addIssue({
95
+ code: z.ZodIssueCode.custom,
96
+ path: ["google", hasClientIdField ? "clientSecret" : "clientId"],
97
+ message: "Provide both the Google client ID and client secret together, or clear both together."
98
+ });
99
+ return;
100
+ }
101
+ if (hasClientIdValue !== hasClientSecretValue) {
102
+ context.addIssue({
103
+ code: z.ZodIssueCode.custom,
104
+ path: ["google", hasClientIdValue ? "clientSecret" : "clientId"],
105
+ message: "Provide both the Google client ID and client secret together, or clear both together."
106
+ });
107
+ }
108
+ }),
109
+ modelSettings: z
110
+ .object({
111
+ forgeAgent: z
112
+ .object({
113
+ basicChat: z
114
+ .object({
115
+ connectionId: z.string().trim().nullable().optional(),
116
+ model: z.string().trim().optional()
117
+ })
118
+ .optional(),
119
+ wiki: z
120
+ .object({
121
+ connectionId: z.string().trim().nullable().optional(),
122
+ model: z.string().trim().optional()
123
+ })
124
+ .optional()
125
+ })
126
+ .optional()
127
+ })
128
+ .optional()
129
+ });
130
+ export const createAgentTokenSchema = z.object({
131
+ label: z.string().trim().min(1, "Label is required"),
132
+ agentLabel: z.string().trim().min(1, "Agent name is required"),
133
+ agentType: z.string().trim().min(1, "Agent type is required"),
134
+ description: z.string().trim(),
135
+ trustLevel: z.enum(["standard", "trusted", "autonomous"]),
136
+ autonomyMode: z.enum(["approval_required", "scoped_write", "autonomous"]),
137
+ approvalMode: z.enum(["approval_by_default", "high_impact_only", "none"]),
138
+ scopes: z.array(z.string().trim().min(1)).min(1)
139
+ });
140
+ export const createInsightSchema = z.object({
141
+ originType: z.enum(["system", "user", "agent"]),
142
+ originAgentId: z.string().trim(),
143
+ originLabel: z.string().trim(),
144
+ entityType: z.string().trim(),
145
+ entityId: z.string().trim(),
146
+ timeframeLabel: z.string().trim(),
147
+ title: z.string().trim().min(1, "Title is required"),
148
+ summary: z.string().trim().min(1, "Summary is required"),
149
+ recommendation: z.string().trim().min(1, "Recommendation is required"),
150
+ rationale: z.string().trim(),
151
+ confidence: z.coerce.number().min(0).max(1),
152
+ ctaLabel: z.string().trim().min(1, "CTA label is required")
153
+ });
154
+ export const quickTaskSchema = z.object({
155
+ title: z.string().trim().min(1, "Title is required"),
156
+ description: z.string().trim(),
157
+ owner: z.string().trim().min(1, "Owner is required"),
158
+ userId: z.string().trim().nullable().optional(),
159
+ goalId: z.string().trim(),
160
+ projectId: z.string().trim().min(1, "Project is required"),
161
+ priority: z.enum(["low", "medium", "high", "critical"]),
162
+ status: z.enum(["backlog", "focus", "in_progress", "blocked", "done"]),
163
+ effort: z.enum(["light", "deep", "marathon"]),
164
+ energy: z.enum(["low", "steady", "high"]),
165
+ dueDate: z.string().trim(),
166
+ points: z.coerce.number().int().min(5).max(500),
167
+ plannedDurationSeconds: z.coerce.number().int().min(60).max(7 * 86_400).nullable().optional(),
168
+ actionCostBand: z
169
+ .enum(["tiny", "light", "standard", "heavy", "brutal"])
170
+ .optional(),
171
+ tagIds: z.array(z.string()),
172
+ notes: z.array(inlineCreateNoteSchema)
173
+ });
174
+ export const habitMutationSchema = z
175
+ .object({
176
+ title: z.string().trim().min(1, "Title is required"),
177
+ description: z.string().trim(),
178
+ status: z.enum(["active", "paused", "archived"]),
179
+ userId: z.string().trim().nullable().optional(),
180
+ polarity: z.enum(["positive", "negative"]),
181
+ frequency: z.enum(["daily", "weekly"]),
182
+ targetCount: z.coerce.number().int().min(1).max(14),
183
+ weekDays: z.array(z.number().int().min(0).max(6)).max(7),
184
+ linkedGoalIds: z.array(z.string().trim().min(1)),
185
+ linkedProjectIds: z.array(z.string().trim().min(1)),
186
+ linkedTaskIds: z.array(z.string().trim().min(1)),
187
+ linkedValueIds: z.array(z.string().trim().min(1)),
188
+ linkedPatternIds: z.array(z.string().trim().min(1)),
189
+ linkedBehaviorIds: z.array(z.string().trim().min(1)),
190
+ linkedBeliefIds: z.array(z.string().trim().min(1)),
191
+ linkedModeIds: z.array(z.string().trim().min(1)),
192
+ linkedReportIds: z.array(z.string().trim().min(1)),
193
+ linkedBehaviorId: z.string().trim(),
194
+ rewardXp: z.coerce.number().int().min(1).max(100),
195
+ penaltyXp: z.coerce.number().int().min(1).max(100),
196
+ generatedHealthEventTemplate: z.object({
197
+ enabled: z.boolean(),
198
+ workoutType: z.string().trim(),
199
+ title: z.string().trim(),
200
+ durationMinutes: z.coerce.number().int().min(1).max(24 * 60),
201
+ xpReward: z.coerce.number().int().min(0).max(500),
202
+ tags: z.array(z.string().trim()),
203
+ links: z.array(z.object({
204
+ entityType: z.string().trim().min(1),
205
+ entityId: z.string().trim().min(1),
206
+ relationshipType: z.string().trim().default("context")
207
+ })),
208
+ notesTemplate: z.string().trim()
209
+ })
210
+ })
211
+ .superRefine((value, context) => {
212
+ if (value.frequency === "weekly" && value.weekDays.length === 0) {
213
+ context.addIssue({
214
+ code: z.ZodIssueCode.custom,
215
+ path: ["weekDays"],
216
+ message: "Pick at least one weekday"
217
+ });
218
+ }
219
+ });
220
+ export const workAdjustmentMutationSchema = z.object({
221
+ entityType: z.enum(["task", "project"]),
222
+ entityId: z.string().trim().min(1, "A target is required"),
223
+ deltaMinutes: z.coerce
224
+ .number()
225
+ .int()
226
+ .refine((value) => value !== 0, "Minutes must not be zero"),
227
+ note: z.string().trim()
228
+ });
229
+ export const tagMutationSchema = z.object({
230
+ name: z.string().trim().min(1, "Name is required"),
231
+ kind: z.enum(["value", "category", "execution"]),
232
+ userId: z.string().trim().nullable().optional(),
233
+ color: z
234
+ .string()
235
+ .trim()
236
+ .regex(/^#[0-9a-fA-F]{6}$/, "Color must be a valid hex value"),
237
+ description: z.string().trim()
238
+ });
@@ -0,0 +1,416 @@
1
+ const EMPTY_CALENDAR_RULES = {
2
+ allowWorkBlockKinds: [],
3
+ blockWorkBlockKinds: [],
4
+ allowCalendarIds: [],
5
+ blockCalendarIds: [],
6
+ allowEventTypes: [],
7
+ blockEventTypes: [],
8
+ allowEventKeywords: [],
9
+ blockEventKeywords: [],
10
+ allowAvailability: [],
11
+ blockAvailability: []
12
+ };
13
+ function normalizeTask(task) {
14
+ return {
15
+ id: task?.id ?? "",
16
+ title: task?.title ?? "",
17
+ description: task?.description ?? "",
18
+ status: task?.status ?? "backlog",
19
+ priority: task?.priority ?? "medium",
20
+ owner: task?.owner ?? "Albert",
21
+ goalId: task?.goalId ?? null,
22
+ projectId: task?.projectId ?? null,
23
+ dueDate: task?.dueDate ?? null,
24
+ effort: task?.effort ?? "deep",
25
+ energy: task?.energy ?? "steady",
26
+ points: task?.points ?? 0,
27
+ plannedDurationSeconds: task?.plannedDurationSeconds ?? null,
28
+ schedulingRules: task?.schedulingRules ?? null,
29
+ sortOrder: task?.sortOrder ?? 0,
30
+ resolutionKind: task?.resolutionKind ?? null,
31
+ splitParentTaskId: task?.splitParentTaskId ?? null,
32
+ completedAt: task?.completedAt ?? null,
33
+ createdAt: task?.createdAt ?? new Date(0).toISOString(),
34
+ updatedAt: task?.updatedAt ?? new Date(0).toISOString(),
35
+ tagIds: task?.tagIds ?? [],
36
+ userId: task?.userId ?? null,
37
+ user: task?.user ?? null,
38
+ time: task?.time ?? {
39
+ totalTrackedSeconds: 0,
40
+ totalCreditedSeconds: 0,
41
+ liveTrackedSeconds: 0,
42
+ liveCreditedSeconds: 0,
43
+ manualAdjustedSeconds: 0,
44
+ activeRunCount: 0,
45
+ hasCurrentRun: false,
46
+ currentRunId: null
47
+ },
48
+ actionPointSummary: task?.actionPointSummary ?? {
49
+ costBand: "standard",
50
+ totalCostAp: 100,
51
+ expectedDurationSeconds: 86_400,
52
+ sustainRateApPerHour: 100 / 24,
53
+ spentTodayAp: 0,
54
+ spentTotalAp: 0,
55
+ remainingAp: 100
56
+ },
57
+ splitSuggestion: task?.splitSuggestion ?? {
58
+ shouldSplit: false,
59
+ reason: null,
60
+ thresholdSeconds: 2 * 86_400
61
+ }
62
+ };
63
+ }
64
+ function normalizeGoal(goal) {
65
+ return {
66
+ id: goal?.id ?? "",
67
+ title: goal?.title ?? "",
68
+ description: goal?.description ?? "",
69
+ horizon: goal?.horizon === "quarter" || goal?.horizon === "lifetime"
70
+ ? goal.horizon
71
+ : "year",
72
+ status: goal?.status === "paused" || goal?.status === "completed"
73
+ ? goal.status
74
+ : "active",
75
+ targetPoints: goal?.targetPoints ?? 0,
76
+ themeColor: goal?.themeColor ?? "#c8a46b",
77
+ createdAt: goal?.createdAt ?? new Date(0).toISOString(),
78
+ updatedAt: goal?.updatedAt ?? new Date(0).toISOString(),
79
+ tagIds: goal?.tagIds ?? [],
80
+ userId: goal?.userId ?? null,
81
+ user: goal?.user ?? null
82
+ };
83
+ }
84
+ function normalizeTag(tag) {
85
+ return {
86
+ id: tag?.id ?? "",
87
+ name: tag?.name ?? "",
88
+ kind: tag?.kind === "value" || tag?.kind === "execution"
89
+ ? tag.kind
90
+ : "category",
91
+ color: tag?.color ?? "#71717a",
92
+ description: tag?.description ?? "",
93
+ userId: tag?.userId ?? null,
94
+ user: tag?.user ?? null
95
+ };
96
+ }
97
+ function normalizeProject(project) {
98
+ return {
99
+ id: project?.id ?? "",
100
+ goalId: project?.goalId ?? "",
101
+ title: project?.title ?? "",
102
+ description: project?.description ?? project?.summary ?? "",
103
+ status: project?.status === "paused" || project?.status === "completed"
104
+ ? project.status
105
+ : "active",
106
+ targetPoints: project?.targetPoints ?? project?.totalPoints ?? 0,
107
+ themeColor: project?.themeColor ?? "#c0c1ff",
108
+ schedulingRules: project?.schedulingRules ?? EMPTY_CALENDAR_RULES,
109
+ createdAt: project?.createdAt ?? new Date(0).toISOString(),
110
+ updatedAt: project?.updatedAt ?? new Date(0).toISOString(),
111
+ goalTitle: project?.goalTitle ?? "",
112
+ activeTaskCount: project?.activeTaskCount ?? 0,
113
+ completedTaskCount: project?.completedTaskCount ?? 0,
114
+ totalTasks: project?.totalTasks ?? 0,
115
+ earnedPoints: project?.earnedPoints ?? project?.totalPoints ?? 0,
116
+ progress: project?.progress ?? 0,
117
+ nextTaskId: project?.nextTaskId ?? null,
118
+ nextTaskTitle: project?.nextTaskTitle ?? null,
119
+ momentumLabel: project?.momentumLabel ?? "No momentum yet",
120
+ userId: project?.userId ?? null,
121
+ user: project?.user ?? null,
122
+ time: project?.time ?? {
123
+ totalTrackedSeconds: 0,
124
+ totalCreditedSeconds: 0,
125
+ liveTrackedSeconds: 0,
126
+ liveCreditedSeconds: 0,
127
+ manualAdjustedSeconds: 0,
128
+ activeRunCount: 0,
129
+ hasCurrentRun: false,
130
+ currentRunId: null
131
+ }
132
+ };
133
+ }
134
+ function normalizeHabit(habit) {
135
+ return {
136
+ id: habit?.id ?? "",
137
+ title: habit?.title ?? "",
138
+ description: habit?.description ?? "",
139
+ status: habit?.status ?? "active",
140
+ polarity: habit?.polarity ?? "positive",
141
+ frequency: habit?.frequency ?? "daily",
142
+ targetCount: habit?.targetCount ?? 1,
143
+ weekDays: habit?.weekDays ?? [],
144
+ linkedGoalIds: habit?.linkedGoalIds ?? [],
145
+ linkedProjectIds: habit?.linkedProjectIds ?? [],
146
+ linkedTaskIds: habit?.linkedTaskIds ?? [],
147
+ linkedValueIds: habit?.linkedValueIds ?? [],
148
+ linkedPatternIds: habit?.linkedPatternIds ?? [],
149
+ linkedBehaviorIds: habit?.linkedBehaviorIds ?? [],
150
+ linkedBeliefIds: habit?.linkedBeliefIds ?? [],
151
+ linkedModeIds: habit?.linkedModeIds ?? [],
152
+ linkedReportIds: habit?.linkedReportIds ?? [],
153
+ linkedBehaviorId: habit?.linkedBehaviorId ?? null,
154
+ linkedBehaviorTitle: habit?.linkedBehaviorTitle ?? null,
155
+ linkedBehaviorTitles: habit?.linkedBehaviorTitles ?? [],
156
+ rewardXp: habit?.rewardXp ?? 12,
157
+ penaltyXp: habit?.penaltyXp ?? 8,
158
+ generatedHealthEventTemplate: habit?.generatedHealthEventTemplate ?? {
159
+ enabled: false,
160
+ workoutType: "",
161
+ title: "",
162
+ durationMinutes: 60,
163
+ xpReward: 0,
164
+ tags: [],
165
+ links: [],
166
+ notesTemplate: ""
167
+ },
168
+ createdAt: habit?.createdAt ?? new Date(0).toISOString(),
169
+ updatedAt: habit?.updatedAt ?? new Date(0).toISOString(),
170
+ lastCheckInAt: habit?.lastCheckInAt ?? null,
171
+ lastCheckInStatus: habit?.lastCheckInStatus ?? null,
172
+ streakCount: habit?.streakCount ?? 0,
173
+ completionRate: habit?.completionRate ?? 0,
174
+ dueToday: habit?.dueToday ?? false,
175
+ userId: habit?.userId ?? null,
176
+ user: habit?.user ?? null,
177
+ checkIns: habit?.checkIns ?? []
178
+ };
179
+ }
180
+ function normalizeUser(user) {
181
+ return {
182
+ id: user?.id ?? "",
183
+ kind: user?.kind ?? "human",
184
+ handle: user?.handle ?? "",
185
+ displayName: user?.displayName ?? "",
186
+ description: user?.description ?? "",
187
+ accentColor: user?.accentColor ?? "#c0c1ff",
188
+ createdAt: user?.createdAt ?? new Date(0).toISOString(),
189
+ updatedAt: user?.updatedAt ?? new Date(0).toISOString()
190
+ };
191
+ }
192
+ function normalizeStrategy(strategy) {
193
+ return {
194
+ id: strategy?.id ?? "",
195
+ title: strategy?.title ?? "",
196
+ overview: strategy?.overview ?? "",
197
+ endStateDescription: strategy?.endStateDescription ?? "",
198
+ status: strategy?.status === "paused" || strategy?.status === "completed"
199
+ ? strategy.status
200
+ : "active",
201
+ targetGoalIds: strategy?.targetGoalIds ?? [],
202
+ targetProjectIds: strategy?.targetProjectIds ?? [],
203
+ linkedEntities: strategy?.linkedEntities ?? [],
204
+ graph: strategy?.graph ?? { nodes: [], edges: [] },
205
+ metrics: strategy?.metrics ?? {
206
+ alignmentScore: 0,
207
+ planCoverageScore: 0,
208
+ sequencingScore: 100,
209
+ scopeDisciplineScore: 100,
210
+ qualityScore: 0,
211
+ targetProgressScore: 0,
212
+ completedNodeCount: 0,
213
+ startedNodeCount: 0,
214
+ readyNodeCount: 0,
215
+ totalNodeCount: 1,
216
+ completedTargetCount: 0,
217
+ totalTargetCount: 0,
218
+ offPlanEntityCount: 0,
219
+ offPlanActiveEntityCount: 0,
220
+ offPlanCompletedEntityCount: 0,
221
+ activeNodeIds: [],
222
+ nextNodeIds: [],
223
+ blockedNodeIds: [],
224
+ outOfOrderNodeIds: []
225
+ },
226
+ isLocked: strategy?.isLocked ?? false,
227
+ lockedAt: strategy?.lockedAt ?? null,
228
+ lockedByUserId: strategy?.lockedByUserId ?? null,
229
+ lockedByUser: strategy?.lockedByUser ?? null,
230
+ createdAt: strategy?.createdAt ?? new Date(0).toISOString(),
231
+ updatedAt: strategy?.updatedAt ?? new Date(0).toISOString(),
232
+ userId: strategy?.userId ?? null,
233
+ user: strategy?.user ?? null
234
+ };
235
+ }
236
+ export function normalizeForgeSnapshot(raw) {
237
+ const legacy = raw;
238
+ const rootProjects = (legacy.projects ?? legacy.campaigns ?? []).map(normalizeProject);
239
+ const dashboardProjects = (legacy.dashboard?.projects ??
240
+ legacy.dashboard?.campaigns ??
241
+ rootProjects).map(normalizeProject);
242
+ const overviewProjects = (legacy.overview?.projects ??
243
+ legacy.overview?.campaigns ??
244
+ dashboardProjects).map(normalizeProject);
245
+ return {
246
+ ...raw,
247
+ meta: {
248
+ apiVersion: "v1",
249
+ transport: "rest+sse",
250
+ generatedAt: raw.meta?.generatedAt ?? new Date().toISOString(),
251
+ backend: raw.meta?.backend ?? "forge-node-runtime",
252
+ mode: raw.meta?.mode ?? "transitional-node"
253
+ },
254
+ metrics: {
255
+ totalXp: raw.metrics?.totalXp ?? 0,
256
+ level: raw.metrics?.level ?? 1,
257
+ currentLevelXp: raw.metrics?.currentLevelXp ?? 0,
258
+ nextLevelXp: raw.metrics?.nextLevelXp ?? 120,
259
+ weeklyXp: raw.metrics?.weeklyXp ?? 0,
260
+ streakDays: raw.metrics?.streakDays ?? 0,
261
+ comboMultiplier: raw.metrics?.comboMultiplier ?? 1,
262
+ momentumScore: raw.metrics?.momentumScore ?? 0,
263
+ topGoalId: raw.metrics?.topGoalId ?? null,
264
+ topGoalTitle: raw.metrics?.topGoalTitle ?? null
265
+ },
266
+ users: (raw.users ?? []).map(normalizeUser),
267
+ strategies: (raw.strategies ?? []).map(normalizeStrategy),
268
+ userScope: {
269
+ selectedUserIds: raw.userScope?.selectedUserIds ?? [],
270
+ selectedUsers: (raw.userScope?.selectedUsers ?? []).map(normalizeUser)
271
+ },
272
+ dashboard: {
273
+ stats: {
274
+ totalPoints: raw.dashboard?.stats?.totalPoints ?? 0,
275
+ completedThisWeek: raw.dashboard?.stats?.completedThisWeek ?? 0,
276
+ activeGoals: raw.dashboard?.stats?.activeGoals ?? 0,
277
+ alignmentScore: raw.dashboard?.stats?.alignmentScore ?? 0,
278
+ focusTasks: raw.dashboard?.stats?.focusTasks ?? 0,
279
+ overdueTasks: raw.dashboard?.stats?.overdueTasks ?? 0,
280
+ dueThisWeek: raw.dashboard?.stats?.dueThisWeek ?? 0
281
+ },
282
+ goals: (raw.dashboard?.goals ?? []).map((goal) => ({
283
+ ...goal,
284
+ ...normalizeGoal(goal)
285
+ })),
286
+ projects: dashboardProjects,
287
+ tasks: (raw.dashboard?.tasks ?? []).map(normalizeTask),
288
+ habits: (raw.dashboard?.habits ?? raw.habits ?? []).map(normalizeHabit),
289
+ tags: (raw.dashboard?.tags ?? []).map(normalizeTag),
290
+ suggestedTags: (raw.dashboard?.suggestedTags ?? []).map(normalizeTag),
291
+ owners: raw.dashboard?.owners ?? [],
292
+ executionBuckets: (raw.dashboard?.executionBuckets ?? []).map((bucket) => ({
293
+ ...bucket,
294
+ tasks: (bucket.tasks ?? []).map(normalizeTask)
295
+ })),
296
+ gamification: raw.dashboard?.gamification ?? {
297
+ totalXp: raw.metrics?.totalXp ?? 0,
298
+ level: raw.metrics?.level ?? 1,
299
+ currentLevelXp: raw.metrics?.currentLevelXp ?? 0,
300
+ nextLevelXp: raw.metrics?.nextLevelXp ?? 120,
301
+ weeklyXp: raw.metrics?.weeklyXp ?? 0,
302
+ streakDays: raw.metrics?.streakDays ?? 0,
303
+ comboMultiplier: raw.metrics?.comboMultiplier ?? 1,
304
+ momentumScore: raw.metrics?.momentumScore ?? 0,
305
+ topGoalId: raw.metrics?.topGoalId ?? null,
306
+ topGoalTitle: raw.metrics?.topGoalTitle ?? null
307
+ },
308
+ achievements: raw.dashboard?.achievements ?? [],
309
+ milestoneRewards: raw.dashboard?.milestoneRewards ?? [],
310
+ recentActivity: raw.dashboard?.recentActivity ?? [],
311
+ notesSummaryByEntity: raw.dashboard?.notesSummaryByEntity ?? {}
312
+ },
313
+ overview: {
314
+ generatedAt: raw.overview?.generatedAt ?? new Date().toISOString(),
315
+ strategicHeader: {
316
+ streakDays: raw.overview?.strategicHeader?.streakDays ??
317
+ raw.metrics?.streakDays ??
318
+ 0,
319
+ level: raw.overview?.strategicHeader?.level ?? raw.metrics?.level ?? 1,
320
+ totalXp: raw.overview?.strategicHeader?.totalXp ?? raw.metrics?.totalXp ?? 0,
321
+ currentLevelXp: raw.overview?.strategicHeader?.currentLevelXp ??
322
+ raw.metrics?.currentLevelXp ??
323
+ 0,
324
+ nextLevelXp: raw.overview?.strategicHeader?.nextLevelXp ??
325
+ raw.metrics?.nextLevelXp ??
326
+ 120,
327
+ momentumScore: raw.overview?.strategicHeader?.momentumScore ??
328
+ raw.metrics?.momentumScore ??
329
+ 0,
330
+ focusTasks: raw.overview?.strategicHeader?.focusTasks ?? 0,
331
+ overdueTasks: raw.overview?.strategicHeader?.overdueTasks ?? 0
332
+ },
333
+ projects: overviewProjects,
334
+ activeGoals: (raw.overview?.activeGoals ?? []).map((goal) => ({
335
+ ...goal,
336
+ ...normalizeGoal(goal)
337
+ })),
338
+ topTasks: (raw.overview?.topTasks ?? []).map(normalizeTask),
339
+ dueHabits: (raw.overview?.dueHabits ??
340
+ raw.today?.dueHabits ??
341
+ raw.dashboard?.habits ??
342
+ []).map(normalizeHabit),
343
+ recentEvidence: raw.overview?.recentEvidence ?? [],
344
+ achievements: raw.overview?.achievements ?? [],
345
+ domainBalance: raw.overview?.domainBalance ?? [],
346
+ neglectedGoals: raw.overview?.neglectedGoals ?? []
347
+ },
348
+ today: {
349
+ generatedAt: raw.today?.generatedAt ?? new Date().toISOString(),
350
+ directive: {
351
+ task: raw.today?.directive?.task
352
+ ? normalizeTask(raw.today.directive.task)
353
+ : null,
354
+ goalTitle: raw.today?.directive?.goalTitle ?? null,
355
+ rewardXp: raw.today?.directive?.rewardXp ?? 0,
356
+ sessionLabel: raw.today?.directive?.sessionLabel ?? "No active session"
357
+ },
358
+ timeline: (raw.today?.timeline ?? []).map((bucket) => ({
359
+ ...bucket,
360
+ tasks: (bucket.tasks ?? []).map(normalizeTask)
361
+ })),
362
+ dueHabits: (raw.today?.dueHabits ??
363
+ raw.overview?.dueHabits ??
364
+ raw.dashboard?.habits ??
365
+ []).map(normalizeHabit),
366
+ dailyQuests: raw.today?.dailyQuests ?? [],
367
+ milestoneRewards: raw.today?.milestoneRewards ?? [],
368
+ recentHabitRewards: raw.today?.recentHabitRewards ?? [],
369
+ momentum: {
370
+ streakDays: raw.today?.momentum?.streakDays ?? 0,
371
+ momentumScore: raw.today?.momentum?.momentumScore ?? 0,
372
+ recoveryHint: raw.today?.momentum?.recoveryHint ?? ""
373
+ }
374
+ },
375
+ risk: {
376
+ generatedAt: raw.risk?.generatedAt ?? new Date().toISOString(),
377
+ overdueTasks: (raw.risk?.overdueTasks ?? []).map(normalizeTask),
378
+ blockedTasks: (raw.risk?.blockedTasks ?? []).map(normalizeTask),
379
+ neglectedGoals: raw.risk?.neglectedGoals ?? [],
380
+ summary: raw.risk?.summary ?? ""
381
+ },
382
+ goals: (raw.goals ?? []).map(normalizeGoal),
383
+ projects: rootProjects,
384
+ tags: (raw.tags ?? []).map(normalizeTag),
385
+ tasks: (raw.tasks ?? []).map(normalizeTask),
386
+ habits: (raw.habits ?? raw.dashboard?.habits ?? []).map(normalizeHabit),
387
+ activity: raw.activity ?? [],
388
+ activeTaskRuns: raw.activeTaskRuns ?? [],
389
+ lifeForce: raw.lifeForce ?? {
390
+ userId: "",
391
+ dateKey: new Date().toISOString().slice(0, 10),
392
+ baselineDailyAp: 200,
393
+ dailyBudgetAp: 200,
394
+ spentTodayAp: 0,
395
+ remainingAp: 200,
396
+ forecastAp: 0,
397
+ targetBandMinAp: 170,
398
+ targetBandMaxAp: 200,
399
+ instantCapacityApPerHour: 0,
400
+ instantFreeApPerHour: 0,
401
+ overloadApPerHour: 0,
402
+ currentDrainApPerHour: 0,
403
+ fatigueBufferApPerHour: 0,
404
+ sleepRecoveryMultiplier: 1,
405
+ readinessMultiplier: 1,
406
+ fatigueDebtCarry: 0,
407
+ stats: [],
408
+ currentCurve: [],
409
+ activeDrains: [],
410
+ warnings: [],
411
+ recommendations: [],
412
+ topTaskIdsNeedingSplit: [],
413
+ updatedAt: new Date(0).toISOString()
414
+ }
415
+ };
416
+ }