forge-openclaw-plugin 0.2.102 → 0.2.103

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 (174) hide show
  1. package/dist/assets/activity-page-Dv6X5ZCV.js +1 -0
  2. package/dist/assets/{ai-surface-workspace-xtB5RFQu.js → ai-surface-workspace-CutiG6uS.js} +1 -1
  3. package/dist/assets/{atlas-panel-B3dPHCmZ.js → atlas-panel-jgMRyaHn.js} +1 -1
  4. package/dist/assets/{board-DqHzdCPQ.js → board-dIX6etHh.js} +1 -1
  5. package/dist/assets/calendar-page-q7Nm5E2U.js +1 -0
  6. package/dist/assets/calendar-rules-DPFsfiRl.js +1 -0
  7. package/dist/assets/{calendar-week-toolbar-BZ_-X3Wb.js → calendar-week-toolbar-nVhgB-0s.js} +1 -1
  8. package/dist/assets/{charts-FcU0F3XV.js → charts-DFnEuIMB.js} +1 -1
  9. package/dist/assets/companion-sync-lab-page-CJ8UTij8.js +1 -0
  10. package/dist/assets/{daily-metrics-dashboard-BMyL0Qr4.js → daily-metrics-dashboard-CiJkkkd1.js} +1 -1
  11. package/dist/assets/entity-note-count-link-RzBB6ujx.js +1 -0
  12. package/dist/assets/{entity-notes-surface-CBylYDwy.js → entity-notes-surface-Djz50HvD.js} +1 -1
  13. package/dist/assets/execution-board-CtPhI-58.js +1 -0
  14. package/dist/assets/{faceted-token-search-D7xPWfOl.js → faceted-token-search-DEC6ANa9.js} +1 -1
  15. package/dist/assets/{flagship-signal-deck-BEFKOhvx.js → flagship-signal-deck-CtHC3mql.js} +1 -1
  16. package/dist/assets/floating-action-menu-CKQRhff9.js +1 -0
  17. package/dist/assets/{forms-CmLAyGqz.js → forms-hB0SqEh-.js} +1 -1
  18. package/dist/assets/goal-detail-page-CF5fNQeR.js +1 -0
  19. package/dist/assets/goals-page-fsY8NzGB.js +1 -0
  20. package/dist/assets/{graph-BTa79qum.js → graph-DDUZNRsO.js} +1 -1
  21. package/dist/assets/habits-page-COoGz4kj.js +1 -0
  22. package/dist/assets/index-BAXYM89v.css +1 -0
  23. package/dist/assets/index-EqQsXoat.js +19 -0
  24. package/dist/assets/{insight-flow-dialog-BtIQXXsS.js → insight-flow-dialog-DtX_5W7g.js} +1 -1
  25. package/dist/assets/insights-page-cBd74ObU.js +8 -0
  26. package/dist/assets/kanban-page-CYav9THw.js +1 -0
  27. package/dist/assets/knowledge-graph-page-D2A-W1jE.js +1 -0
  28. package/dist/assets/{life-force-page-BGDkKfbJ.js → life-force-page-CACGlNhq.js} +1 -1
  29. package/dist/assets/life-force-workspace-BJ4N1I78.js +1 -0
  30. package/dist/assets/{maps-CF1RagUX.js → maps-C-yOWiDN.js} +1 -1
  31. package/dist/assets/{metric-tile-4iMd_WnJ.js → metric-tile-CMadwnGz.js} +1 -1
  32. package/dist/assets/{motion-CfdU2F35.js → motion-Lt5B1XuE.js} +1 -1
  33. package/dist/assets/movement-page-D5VqFd2q.js +1 -0
  34. package/dist/assets/{note-markdown-CsGQhQXF.js → note-markdown-BzK2Qlgr.js} +1 -1
  35. package/dist/assets/{note-tags-input-DdZi93tj.js → note-tags-input-CZzqJMLc.js} +1 -1
  36. package/dist/assets/notes-page-D3Hsh90C.js +1 -0
  37. package/dist/assets/{open-in-graph-button-C0TGev7c.js → open-in-graph-button-BFPKfyK3.js} +1 -1
  38. package/dist/assets/{orbit-map-DVXkfQdd.js → orbit-map-CnyfSmOG.js} +1 -1
  39. package/dist/assets/{overview-page-BwMlFQKX.js → overview-page-CXdWrOV1.js} +1 -1
  40. package/dist/assets/{page-hero-oFHaAjtL.js → page-hero-ffKzgyW3.js} +1 -1
  41. package/dist/assets/pill-cluster-C2D0h3lx.js +1 -0
  42. package/dist/assets/{preference-entity-handoff-button-DOKV9bZc.js → preference-entity-handoff-button-Dj3V6VxL.js} +1 -1
  43. package/dist/assets/preferences-page-Jo8Gw386.js +1 -0
  44. package/dist/assets/project-collections-qSqp90HN.js +1 -0
  45. package/dist/assets/{project-detail-page-DogvVNEn.js → project-detail-page-BifhiLQX.js} +1 -1
  46. package/dist/assets/project-management-hierarchy-page-DZ_9klIc.js +1 -0
  47. package/dist/assets/project-management-section-nav-BImLCVvf.js +1 -0
  48. package/dist/assets/projects-page-ptcx6H38.js +1 -0
  49. package/dist/assets/{psyche-behaviors-page-BeVlXvbj.js → psyche-behaviors-page-BDwXyDta.js} +1 -1
  50. package/dist/assets/{psyche-flashcards-page-CqAWCO4E.js → psyche-flashcards-page-DL1BP1jX.js} +1 -1
  51. package/dist/assets/{psyche-goal-map-page-IyNnbk_W.js → psyche-goal-map-page-ovcpisx1.js} +1 -1
  52. package/dist/assets/{psyche-graph-IkUQRaDK.js → psyche-graph-EP5GL612.js} +1 -1
  53. package/dist/assets/{psyche-metrics-page-uai0a7Lx.js → psyche-metrics-page-Bcu813Rg.js} +1 -1
  54. package/dist/assets/{psyche-mode-guide-page-C7p-ABiF.js → psyche-mode-guide-page-C0g27Xpt.js} +1 -1
  55. package/dist/assets/{psyche-modes-page-CLQ5V3w0.js → psyche-modes-page-BjKjX5MR.js} +1 -1
  56. package/dist/assets/{psyche-page-NQBHkkpU.js → psyche-page-F4tF2W70.js} +1 -1
  57. package/dist/assets/{psyche-patterns-page-BkRiNpI_.js → psyche-patterns-page-B-14hukK.js} +1 -1
  58. package/dist/assets/{psyche-questionnaire-builder-page-Du-7HwPC.js → psyche-questionnaire-builder-page-BdXmoHvK.js} +1 -1
  59. package/dist/assets/{psyche-questionnaire-detail-page-C5-yf8MF.js → psyche-questionnaire-detail-page-Cu5uwlJu.js} +1 -1
  60. package/dist/assets/{psyche-questionnaire-run-detail-page-CoSH5O6R.js → psyche-questionnaire-run-detail-page-C3R4PClg.js} +1 -1
  61. package/dist/assets/{psyche-questionnaire-run-page-ChI7c1wy.js → psyche-questionnaire-run-page-Div3iDdt.js} +1 -1
  62. package/dist/assets/{psyche-questionnaires-page-xUcJJzbI.js → psyche-questionnaires-page-DpqAPQCp.js} +1 -1
  63. package/dist/assets/{psyche-report-detail-page-BPrZCFZS.js → psyche-report-detail-page-BvWVDKP3.js} +1 -1
  64. package/dist/assets/{psyche-reports-page-D2EXJmm6.js → psyche-reports-page-BrbWUlAq.js} +1 -1
  65. package/dist/assets/{psyche-schemas-RcZYaokx.js → psyche-schemas-Dxj554nU.js} +1 -1
  66. package/dist/assets/{psyche-schemas-beliefs-page-h0ooZ1lp.js → psyche-schemas-beliefs-page-DYKvAtSD.js} +1 -1
  67. package/dist/assets/{psyche-screen-time-page-_3-4LikV.js → psyche-screen-time-page-CAOKCyQw.js} +1 -1
  68. package/dist/assets/{psyche-self-observation-page-BdbCsgR5.js → psyche-self-observation-page-F0MVA0UH.js} +1 -1
  69. package/dist/assets/{psyche-values-page-DuUVki5e.js → psyche-values-page-DyvX-d0o.js} +1 -1
  70. package/dist/assets/{report-chain-fields-BBMz0sGI.js → report-chain-fields-CeC1cJFS.js} +1 -1
  71. package/dist/assets/rewards-page-C2loyODo.js +1 -0
  72. package/dist/assets/scheduling-rules-editor-D40AC2jR.js +1 -0
  73. package/dist/assets/{schema-badge-D93RcG36.js → schema-badge-FY7818qB.js} +1 -1
  74. package/dist/assets/{select-menu-Cdq7foRu.js → select-menu-DJsCG6rM.js} +1 -1
  75. package/dist/assets/settings-agents-page-BFkJ5AAD.js +6 -0
  76. package/dist/assets/settings-bin-page-D3-Ab-iA.js +1 -0
  77. package/dist/assets/settings-calendar-page-ly_mSTAD.js +5 -0
  78. package/dist/assets/settings-data-page-D7QOqNf-.js +1 -0
  79. package/dist/assets/settings-logs-page-Ca87HEUx.js +1 -0
  80. package/dist/assets/settings-mobile-page-D0jejZot.js +1 -0
  81. package/dist/assets/settings-models-page-DPDsZjSc.js +1 -0
  82. package/dist/assets/settings-page-1cArlSPM.js +1 -0
  83. package/dist/assets/settings-rewards-page-Db4BV1DC.js +1 -0
  84. package/dist/assets/{settings-section-nav-Dc4IeVBt.js → settings-section-nav-DP9o4peU.js} +1 -1
  85. package/dist/assets/settings-users-page-BHFyDSsd.js +1 -0
  86. package/dist/assets/settings-wiki-page-BNaiupBm.js +1 -0
  87. package/dist/assets/sleep-page-BmOPF0yD.js +1 -0
  88. package/dist/assets/sports-page-BldIiclr.js +1 -0
  89. package/dist/assets/{state-VYvD1QVP.js → state-vCcAT5Hq.js} +1 -1
  90. package/dist/assets/strategies-page-CaTN99qj.js +1 -0
  91. package/dist/assets/strategy-detail-page-DsgFTd-U.js +1 -0
  92. package/dist/assets/{strategy-dialog-DMyRKrWf.js → strategy-dialog-7X7peRzu.js} +1 -1
  93. package/dist/assets/{surface-Bfz_sLX6.js → surface-CJI17F3n.js} +1 -1
  94. package/dist/assets/{table-C0VTeqw0.js → table-BNqMG3_S.js} +1 -1
  95. package/dist/assets/task-detail-page-M1sIIPA8.js +1 -0
  96. package/dist/assets/timebox-planning-dialog-ByojN0AN.js +1 -0
  97. package/dist/assets/today-page-BjDijtn8.js +1 -0
  98. package/dist/assets/training-load-page-BPRmaWmF.js +1 -0
  99. package/dist/assets/{ui-CsEkP2V8.js → ui-C1iwpj2-.js} +1 -1
  100. package/dist/assets/{use-psyche-focus-target-qxT5Oy_z.js → use-psyche-focus-target-Ct-acS9G.js} +1 -1
  101. package/dist/assets/{vendor-kIz9EZnX.js → vendor-Dnkkx2co.js} +3 -3
  102. package/dist/assets/{vitals-page-Dz1Jt5H8.js → vitals-page-CE9zdGLF.js} +1 -1
  103. package/dist/assets/weekly-review-page-CzhTv90n.js +1 -0
  104. package/dist/assets/weight-loss-page-Bp_cIk78.js +5 -0
  105. package/dist/assets/wiki-article-markdown-Dok2uy2p.js +4 -0
  106. package/dist/assets/wiki-editor-page-BuW32Y3f.js +26 -0
  107. package/dist/assets/wiki-ingest-history-page-DZKSBNHV.js +1 -0
  108. package/dist/assets/wiki-ingest-modal-DyqBEZcC.js +1 -0
  109. package/dist/assets/wiki-page-DqxlbLKG.js +1 -0
  110. package/dist/assets/workbench-flow-page-C4nc9jUg.js +5 -0
  111. package/dist/assets/workbench-page-BnyR7SL0.js +1 -0
  112. package/dist/assets/{workout-detail-page-DD9IGN6l.js → workout-detail-page-DT-c5cHL.js} +2 -2
  113. package/dist/index.html +9 -9
  114. package/dist/server/server/src/app.js +22 -3
  115. package/dist/server/server/src/health-weight-loss.js +114 -39
  116. package/dist/server/server/src/repositories/model-settings.js +9 -3
  117. package/dist/server/src/components/workbench-boxes/shared/generic-node-view.js +13 -5
  118. package/dist/server/src/lib/api.js +10 -1
  119. package/openclaw.plugin.json +1 -1
  120. package/package.json +1 -1
  121. package/dist/assets/activity-page-CgF7K2ww.js +0 -1
  122. package/dist/assets/calendar-page-C1Wfd2Fy.js +0 -1
  123. package/dist/assets/calendar-rules-CaZXtlxt.js +0 -1
  124. package/dist/assets/companion-sync-lab-page-NgeK-O-P.js +0 -1
  125. package/dist/assets/entity-note-count-link-BrS1-O0o.js +0 -1
  126. package/dist/assets/execution-board-CpO2ch6v.js +0 -1
  127. package/dist/assets/floating-action-menu-zzC2r0Ob.js +0 -1
  128. package/dist/assets/goal-detail-page-JK_Nva8e.js +0 -1
  129. package/dist/assets/goals-page-yeoJ06Vw.js +0 -1
  130. package/dist/assets/habits-page-Dx5EhkJi.js +0 -1
  131. package/dist/assets/index-BHIKoiZ6.js +0 -19
  132. package/dist/assets/index-H8R-ABM3.css +0 -1
  133. package/dist/assets/insights-page-CujrosD_.js +0 -8
  134. package/dist/assets/kanban-page-Q9NuIz5w.js +0 -1
  135. package/dist/assets/knowledge-graph-page-DaJmlvvM.js +0 -1
  136. package/dist/assets/life-force-workspace-CLVexVnb.js +0 -1
  137. package/dist/assets/movement-page-ClaoTNuX.js +0 -1
  138. package/dist/assets/notes-page-DYI8s3NN.js +0 -1
  139. package/dist/assets/pill-cluster-7UZd_lHp.js +0 -1
  140. package/dist/assets/preferences-page-BrKEkmfD.js +0 -1
  141. package/dist/assets/project-collections-CZagCmeH.js +0 -1
  142. package/dist/assets/project-management-hierarchy-page-Dr7hW9PW.js +0 -1
  143. package/dist/assets/project-management-section-nav-BLdAgTge.js +0 -1
  144. package/dist/assets/projects-page-UKrby_5-.js +0 -1
  145. package/dist/assets/rewards-page-PZFPa6rR.js +0 -1
  146. package/dist/assets/scheduling-rules-editor-B9KNKsQz.js +0 -1
  147. package/dist/assets/settings-agents-page-DPx2F6wf.js +0 -6
  148. package/dist/assets/settings-bin-page-COwP3gjo.js +0 -1
  149. package/dist/assets/settings-calendar-page-C-ghE0YT.js +0 -5
  150. package/dist/assets/settings-data-page-CBubzKBw.js +0 -1
  151. package/dist/assets/settings-logs-page-uOuXMeBm.js +0 -1
  152. package/dist/assets/settings-mobile-page-C5rfj8_r.js +0 -1
  153. package/dist/assets/settings-models-page-DijmUWdU.js +0 -1
  154. package/dist/assets/settings-page-B4u5TR5g.js +0 -1
  155. package/dist/assets/settings-rewards-page-COiTwkMH.js +0 -1
  156. package/dist/assets/settings-users-page-DEGa5DNn.js +0 -1
  157. package/dist/assets/settings-wiki-page-Cvsiz5_e.js +0 -1
  158. package/dist/assets/sleep-page-BnSOwkEU.js +0 -1
  159. package/dist/assets/sports-page-l1RqXzA_.js +0 -1
  160. package/dist/assets/strategies-page-DEnPlpAs.js +0 -1
  161. package/dist/assets/strategy-detail-page-Ls8bxKeH.js +0 -1
  162. package/dist/assets/task-detail-page-CgrYgQLD.js +0 -1
  163. package/dist/assets/timebox-planning-dialog-Ww0NGLLo.js +0 -1
  164. package/dist/assets/today-page-CIuFHMi1.js +0 -1
  165. package/dist/assets/training-load-page-BIwc648i.js +0 -1
  166. package/dist/assets/weekly-review-page-BFpBe1kI.js +0 -1
  167. package/dist/assets/weight-loss-page-BgMoBpBt.js +0 -5
  168. package/dist/assets/wiki-article-markdown-gsPTXTg1.js +0 -4
  169. package/dist/assets/wiki-editor-page-BpAZHooY.js +0 -26
  170. package/dist/assets/wiki-ingest-history-page-C-ig8O22.js +0 -1
  171. package/dist/assets/wiki-ingest-modal-BK4eQgqs.js +0 -1
  172. package/dist/assets/wiki-page-CMTZ60Zt.js +0 -1
  173. package/dist/assets/workbench-flow-page-BIpWUcLJ.js +0 -5
  174. package/dist/assets/workbench-page-CtCjYSRe.js +0 -1
@@ -3,6 +3,7 @@ import { z } from "zod";
3
3
  import { getDatabase, runInTransaction } from "./db.js";
4
4
  import { getSettings } from "./repositories/settings.js";
5
5
  import { getDefaultUser, resolveUserForMutation } from "./repositories/users.js";
6
+ import { readEncryptedSecret } from "./repositories/calendar.js";
6
7
  const optionalNumberSchema = z
7
8
  .union([z.coerce.number().finite(), z.null()])
8
9
  .optional();
@@ -88,6 +89,11 @@ export const nutritionDailyActiveCaloriesUpdateSchema = z.object({
88
89
  export const nutritionFoodLogCreateSchema = z.object({
89
90
  userId: z.string().trim().min(1).optional(),
90
91
  loggedAt: z.string().datetime().optional(),
92
+ dayKey: z
93
+ .string()
94
+ .regex(/^\d{4}-\d{2}-\d{2}$/)
95
+ .nullable()
96
+ .optional(),
91
97
  mealLabel: z.string().trim().default(""),
92
98
  source: z
93
99
  .enum(["manual", "search", "barcode", "chatgpt", "photo", "saved_meal"])
@@ -210,6 +216,9 @@ function newId(prefix) {
210
216
  function dayKey(value) {
211
217
  return value.slice(0, 10);
212
218
  }
219
+ function normalizeDayKey(value, fallbackIso) {
220
+ return value ?? dayKey(fallbackIso);
221
+ }
213
222
  function jsonString(value) {
214
223
  return JSON.stringify(value ?? null);
215
224
  }
@@ -293,10 +302,9 @@ function getDailyEnergyOverride(userId, dateKey) {
293
302
  return mapDailyEnergyOverride(row);
294
303
  }
295
304
  function buildStoredEnergyModel(input) {
296
- const today = new Date();
297
- const start = new Date(today);
298
- start.setUTCDate(today.getUTCDate() - 6);
299
- const todayKey = today.toISOString().slice(0, 10);
305
+ const todayKey = input.dateKey;
306
+ const start = new Date(`${todayKey}T00:00:00.000Z`);
307
+ start.setUTCDate(start.getUTCDate() - 6);
300
308
  const startKey = start.toISOString().slice(0, 10);
301
309
  const dailySummaryRows = getDatabase()
302
310
  .prepare(`SELECT date_key, metrics_json
@@ -344,6 +352,25 @@ function buildStoredEnergyModel(input) {
344
352
  row.date_key,
345
353
  n(row.movement_calories_kcal) || null
346
354
  ]));
355
+ const todayWorkoutEnergyFromRange = input.dayStartAt && input.dayEndAt
356
+ ? getDatabase()
357
+ .prepare(`SELECT SUM(active_energy_kcal) AS active_energy_kcal,
358
+ SUM(total_energy_kcal) AS total_energy_kcal
359
+ FROM health_workout_sessions
360
+ WHERE user_id = ?
361
+ AND started_at >= ?
362
+ AND started_at < ?`)
363
+ .get(input.userId, input.dayStartAt, input.dayEndAt)
364
+ : null;
365
+ const todayMovementCaloriesFromRange = input.dayStartAt && input.dayEndAt
366
+ ? getDatabase()
367
+ .prepare(`SELECT SUM(calories_kcal) AS movement_calories_kcal
368
+ FROM movement_trips
369
+ WHERE user_id = ?
370
+ AND started_at >= ?
371
+ AND started_at < ?`)
372
+ .get(input.userId, input.dayStartAt, input.dayEndAt)
373
+ : null;
347
374
  const activeEnergyAverage = average(dailyHealthKit.map((day) => day.activeEnergyKcal));
348
375
  const restingEnergyAverage = average(dailyHealthKit.map((day) => day.restingEnergyKcal));
349
376
  const workoutEnergyAverage = average([...workoutByDay.values()]);
@@ -356,8 +383,14 @@ function buildStoredEnergyModel(input) {
356
383
  const todayHealthKitActive = dailyHealthKit.find((day) => day.dateKey === todayKey)?.activeEnergyKcal ??
357
384
  null;
358
385
  const todayStepCount = dailyHealthKit.find((day) => day.dateKey === todayKey)?.stepCount ?? null;
359
- const todayWorkoutEnergy = workoutByDay.get(todayKey) ?? null;
360
- const todayMovementCalories = movementByDay.get(todayKey) ?? null;
386
+ const todayWorkoutEnergy = todayWorkoutEnergyFromRange != null
387
+ ? n(todayWorkoutEnergyFromRange.active_energy_kcal) ||
388
+ n(todayWorkoutEnergyFromRange.total_energy_kcal) ||
389
+ null
390
+ : (workoutByDay.get(todayKey) ?? null);
391
+ const todayMovementCalories = todayMovementCaloriesFromRange != null
392
+ ? n(todayMovementCaloriesFromRange.movement_calories_kcal) || null
393
+ : (movementByDay.get(todayKey) ?? null);
361
394
  const todayWorkoutMovementCalories = todayWorkoutEnergy != null || todayMovementCalories != null
362
395
  ? n(todayWorkoutEnergy) + n(todayMovementCalories)
363
396
  : null;
@@ -365,27 +398,35 @@ function buildStoredEnergyModel(input) {
365
398
  stepCount: todayStepCount,
366
399
  weightKg: input.latestWeightKg
367
400
  });
401
+ const todayStepCaloriesForActiveBudget = todayStepEstimatedCalories != null &&
402
+ (todayWorkoutEnergy != null ||
403
+ todayMovementCalories != null ||
404
+ todayStepEstimatedCalories > baselineActiveCalories)
405
+ ? todayStepEstimatedCalories
406
+ : null;
368
407
  const todayFallbackPartCount = [
369
408
  todayWorkoutEnergy,
370
409
  todayMovementCalories,
371
- todayStepEstimatedCalories
410
+ todayStepCaloriesForActiveBudget
372
411
  ].filter((value) => value != null).length;
373
412
  const todayFallbackActiveCalories = todayFallbackPartCount > 0
374
413
  ? n(todayWorkoutEnergy) +
375
414
  n(todayMovementCalories) +
376
- n(todayStepEstimatedCalories)
415
+ n(todayStepCaloriesForActiveBudget)
377
416
  : null;
378
417
  const todayObservedActiveCalories = todayHealthKitActive ?? todayFallbackActiveCalories;
379
418
  const todayFallbackSource = (() => {
380
419
  if (todayWorkoutEnergy != null &&
381
420
  todayMovementCalories != null &&
382
- todayStepEstimatedCalories != null) {
421
+ todayStepCaloriesForActiveBudget != null) {
383
422
  return "today_workout_movement_step_energy";
384
423
  }
385
- if (todayWorkoutEnergy != null && todayStepEstimatedCalories != null) {
424
+ if (todayWorkoutEnergy != null &&
425
+ todayStepCaloriesForActiveBudget != null) {
386
426
  return "today_workout_step_energy";
387
427
  }
388
- if (todayMovementCalories != null && todayStepEstimatedCalories != null) {
428
+ if (todayMovementCalories != null &&
429
+ todayStepCaloriesForActiveBudget != null) {
389
430
  return "today_movement_step_energy";
390
431
  }
391
432
  if (todayWorkoutEnergy != null && todayMovementCalories != null) {
@@ -397,7 +438,7 @@ function buildStoredEnergyModel(input) {
397
438
  if (todayMovementCalories != null) {
398
439
  return "today_movement_trip_calories";
399
440
  }
400
- if (todayStepEstimatedCalories != null) {
441
+ if (todayStepCaloriesForActiveBudget != null) {
401
442
  return "today_step_estimate";
402
443
  }
403
444
  return "default_active_calories";
@@ -416,7 +457,8 @@ function buildStoredEnergyModel(input) {
416
457
  const estimatedTdeeKcal = activeBurnKcal != null && restingEnergyAverage != null
417
458
  ? round(activeBurnKcal + restingEnergyAverage, 0)
418
459
  : input.inferredTdee;
419
- const hasHealthKitEnergy = activeEnergyAverage != null ||
460
+ const hasHealthKitDailyActiveEnergy = activeEnergyAverage != null;
461
+ const hasHealthKitEnergy = hasHealthKitDailyActiveEnergy ||
420
462
  restingEnergyAverage != null ||
421
463
  workoutEnergyAverage != null;
422
464
  const hasMovementEnergy = movementCaloriesAverage != null;
@@ -454,6 +496,8 @@ function buildStoredEnergyModel(input) {
454
496
  : null,
455
497
  workoutEnergyKcal: workoutEnergyAverage != null ? round(workoutEnergyAverage, 0) : null,
456
498
  averageCalorieIntake: input.averageCalories,
499
+ recentFoodLogCount: input.recentFoodLogCount,
500
+ recentFoodLogDayCount: input.recentFoodLogDayCount,
457
501
  currentDeficitEstimate: estimatedTdeeKcal != null
458
502
  ? round(input.averageCalories - estimatedTdeeKcal, 0)
459
503
  : null,
@@ -469,7 +513,7 @@ function buildStoredEnergyModel(input) {
469
513
  exerciseMinutesAverage: average(dailyHealthKit.map((day) => day.exerciseMinutes)),
470
514
  stepCountAverage: average(dailyHealthKit.map((day) => day.stepCount)),
471
515
  sourceAvailability: {
472
- healthKitDailyEnergy: hasHealthKitEnergy,
516
+ healthKitDailyEnergy: hasHealthKitDailyActiveEnergy,
473
517
  movementTripCalories: hasMovementEnergy,
474
518
  workoutEnergy: workoutEnergyAverage != null
475
519
  }
@@ -657,6 +701,7 @@ export function createNutritionFoodLog(input) {
657
701
  const parsed = nutritionFoodLogCreateSchema.parse(input);
658
702
  const userId = resolveWriteUser(parsed.userId);
659
703
  const loggedAt = parsed.loggedAt ?? nowIso();
704
+ const logDayKey = normalizeDayKey(parsed.dayKey, loggedAt);
660
705
  const id = newId("meal");
661
706
  const now = nowIso();
662
707
  runInTransaction(() => {
@@ -666,7 +711,7 @@ export function createNutritionFoodLog(input) {
666
711
  place_id, stay_id, workout_id, sleep_id, day_key, image_refs_json,
667
712
  parser_provenance_json, links_json, created_at, updated_at
668
713
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
669
- .run(id, userId, loggedAt, parsed.mealLabel, parsed.source, parsed.confirmationState, parsed.notes, parsed.placeId ?? null, parsed.stayId ?? null, parsed.workoutId ?? null, parsed.sleepId ?? null, dayKey(loggedAt), jsonString(parsed.imageRefs), jsonString(parsed.parserProvenance), jsonString(parsed.links), now, now);
714
+ .run(id, userId, loggedAt, parsed.mealLabel, parsed.source, parsed.confirmationState, parsed.notes, parsed.placeId ?? null, parsed.stayId ?? null, parsed.workoutId ?? null, parsed.sleepId ?? null, logDayKey, jsonString(parsed.imageRefs), jsonString(parsed.parserProvenance), jsonString(parsed.links), now, now);
670
715
  for (const item of parsed.items) {
671
716
  insertMealItem(id, item);
672
717
  }
@@ -680,6 +725,7 @@ export function patchNutritionFoodLog(logId, input) {
680
725
  return null;
681
726
  }
682
727
  const nextLoggedAt = parsed.loggedAt ?? existing.loggedAt;
728
+ const nextDayKey = normalizeDayKey(parsed.dayKey, nextLoggedAt);
683
729
  const now = nowIso();
684
730
  runInTransaction(() => {
685
731
  getDatabase()
@@ -689,7 +735,7 @@ export function patchNutritionFoodLog(logId, input) {
689
735
  day_key = ?, image_refs_json = ?, parser_provenance_json = ?,
690
736
  links_json = ?, updated_at = ?
691
737
  WHERE id = ?`)
692
- .run(nextLoggedAt, parsed.mealLabel ?? existing.mealLabel, parsed.source ?? existing.source, parsed.confirmationState ?? existing.confirmationState, parsed.notes ?? existing.notes, parsed.placeId !== undefined ? parsed.placeId : existing.placeId, parsed.stayId !== undefined ? parsed.stayId : existing.stayId, parsed.workoutId !== undefined ? parsed.workoutId : existing.workoutId, parsed.sleepId !== undefined ? parsed.sleepId : existing.sleepId, dayKey(nextLoggedAt), jsonString(parsed.imageRefs ?? existing.imageRefs), jsonString(parsed.parserProvenance ?? existing.parserProvenance), jsonString(parsed.links ?? existing.links), now, logId);
738
+ .run(nextLoggedAt, parsed.mealLabel ?? existing.mealLabel, parsed.source ?? existing.source, parsed.confirmationState ?? existing.confirmationState, parsed.notes ?? existing.notes, parsed.placeId !== undefined ? parsed.placeId : existing.placeId, parsed.stayId !== undefined ? parsed.stayId : existing.stayId, parsed.workoutId !== undefined ? parsed.workoutId : existing.workoutId, parsed.sleepId !== undefined ? parsed.sleepId : existing.sleepId, nextDayKey, jsonString(parsed.imageRefs ?? existing.imageRefs), jsonString(parsed.parserProvenance ?? existing.parserProvenance), jsonString(parsed.links ?? existing.links), now, logId);
693
739
  if (parsed.items) {
694
740
  getDatabase()
695
741
  .prepare(`DELETE FROM nutrition_meal_items WHERE log_id = ?`)
@@ -1035,9 +1081,8 @@ function listExperiments(userId, limit = 20) {
1035
1081
  updatedAt: row.updated_at
1036
1082
  }));
1037
1083
  }
1038
- function buildTodayLedger(logs, target, dynamicTargetCalories, activeAdjustmentCalories, activeCaloriesSource) {
1039
- const today = new Date().toISOString().slice(0, 10);
1040
- const todayLogs = logs.filter((log) => log.dayKey === today);
1084
+ function buildTodayLedger(logs, target, dateKey, dynamicTargetCalories, activeAdjustmentCalories, activeCaloriesSource) {
1085
+ const todayLogs = logs.filter((log) => log.dayKey === dateKey);
1041
1086
  const totals = todayLogs.reduce((acc, log) => ({
1042
1087
  calories: acc.calories + log.totals.calories,
1043
1088
  proteinGrams: acc.proteinGrams + log.totals.proteinGrams,
@@ -1058,7 +1103,7 @@ function buildTodayLedger(logs, target, dynamicTargetCalories, activeAdjustmentC
1058
1103
  alcoholGrams: 0
1059
1104
  });
1060
1105
  return {
1061
- dateKey: today,
1106
+ dateKey,
1062
1107
  meals: todayLogs,
1063
1108
  totals,
1064
1109
  plannedTargetCalories: target.calorieTarget,
@@ -1267,10 +1312,10 @@ function buildGeneratedHypotheses(logs, subjective, gut, appearance) {
1267
1312
  }
1268
1313
  return cards;
1269
1314
  }
1270
- export function getWeightLossViewData(userIds) {
1315
+ export function getWeightLossViewData(userIds, options = {}) {
1271
1316
  const generatedAt = new Date().toISOString();
1272
1317
  const userId = resolveReadUser(userIds);
1273
- const todayKey = generatedAt.slice(0, 10);
1318
+ const todayKey = options.dateKey ?? generatedAt.slice(0, 10);
1274
1319
  const targetRow = getDatabase()
1275
1320
  .prepare(`SELECT * FROM nutrition_targets WHERE user_id = ?`)
1276
1321
  .get(userId);
@@ -1287,7 +1332,10 @@ export function getWeightLossViewData(userIds) {
1287
1332
  const recentLogs = logs.slice(0, 14);
1288
1333
  const recentTotals = sumItems(recentLogs.flatMap((log) => log.items));
1289
1334
  const trackedDays = new Set(logs.map((log) => log.dayKey)).size;
1290
- const averageCalories = trackedDays > 0 ? round(recentTotals.calories / trackedDays, 0) : 0;
1335
+ const recentTrackedDays = new Set(recentLogs.map((log) => log.dayKey)).size;
1336
+ const averageCalories = recentTrackedDays > 0
1337
+ ? round(recentTotals.calories / recentTrackedDays, 0)
1338
+ : 0;
1291
1339
  const inferredTdee = target.calorieTarget != null
1292
1340
  ? round(target.calorieTarget + Math.abs(n(target.weeklyRateGoalKg)) * 1100, 0)
1293
1341
  : null;
@@ -1295,14 +1343,19 @@ export function getWeightLossViewData(userIds) {
1295
1343
  const dailyActiveOverride = getDailyEnergyOverride(userId, todayKey);
1296
1344
  const energyModel = buildStoredEnergyModel({
1297
1345
  userId,
1346
+ dateKey: todayKey,
1347
+ dayStartAt: options.dayStartAt,
1348
+ dayEndAt: options.dayEndAt,
1298
1349
  inferredTdee,
1299
1350
  averageCalories,
1351
+ recentFoodLogCount: recentLogs.length,
1352
+ recentFoodLogDayCount: recentTrackedDays,
1300
1353
  defaultActiveCalories,
1301
1354
  latestWeightKg: weightTrend.latestWeightKg,
1302
1355
  dailyActiveOverride
1303
1356
  });
1304
1357
  const todayTargetCalories = Math.max(0, round(target.calorieTarget + energyModel.todayTargetAdjustmentKcal, 0));
1305
- const todayLedger = buildTodayLedger(logs, target, todayTargetCalories, energyModel.todayTargetAdjustmentKcal, energyModel.todayActiveCaloriesSource);
1358
+ const todayLedger = buildTodayLedger(logs, target, todayKey, todayTargetCalories, energyModel.todayTargetAdjustmentKcal, energyModel.todayActiveCaloriesSource);
1306
1359
  return {
1307
1360
  generatedAt,
1308
1361
  userId,
@@ -1641,25 +1694,13 @@ function extractJsonObject(text) {
1641
1694
  }
1642
1695
  return trimmed;
1643
1696
  }
1644
- function getNutritionCodexProfile(connectionId) {
1645
- const settings = getSettings();
1646
- const selectedConnectionId = connectionId?.trim() ||
1647
- settings.modelSettings.forgeAgent.basicChat.connectionId ||
1648
- settings.modelSettings.forgeAgent.wiki.connectionId ||
1649
- "";
1650
- if (!selectedConnectionId) {
1651
- return null;
1652
- }
1653
- const row = getDatabase()
1654
- .prepare(`SELECT provider, auth_mode, base_url, model, secret_id, enabled
1655
- FROM ai_model_connections
1656
- WHERE id = ?`)
1657
- .get(selectedConnectionId);
1697
+ function mapNutritionCodexProfileRow(row) {
1658
1698
  if (!row ||
1659
1699
  row.enabled !== 1 ||
1660
1700
  row.provider !== "openai-codex" ||
1661
1701
  row.auth_mode !== "oauth" ||
1662
- !row.secret_id) {
1702
+ !row.secret_id ||
1703
+ !readEncryptedSecret(row.secret_id)) {
1663
1704
  return null;
1664
1705
  }
1665
1706
  return {
@@ -1671,6 +1712,40 @@ function getNutritionCodexProfile(connectionId) {
1671
1712
  metadata: {}
1672
1713
  };
1673
1714
  }
1715
+ function getNutritionCodexProfile(connectionId) {
1716
+ const settings = getSettings();
1717
+ const selectedConnectionIds = [
1718
+ connectionId?.trim(),
1719
+ settings.modelSettings.forgeAgent.basicChat.connectionId,
1720
+ settings.modelSettings.forgeAgent.wiki.connectionId
1721
+ ].filter((id) => Boolean(id));
1722
+ for (const selectedConnectionId of new Set(selectedConnectionIds)) {
1723
+ const row = getDatabase()
1724
+ .prepare(`SELECT provider, auth_mode, base_url, model, secret_id, enabled
1725
+ FROM ai_model_connections
1726
+ WHERE id = ?`)
1727
+ .get(selectedConnectionId);
1728
+ const profile = mapNutritionCodexProfileRow(row);
1729
+ if (profile) {
1730
+ return profile;
1731
+ }
1732
+ }
1733
+ const fallbackRows = getDatabase()
1734
+ .prepare(`SELECT provider, auth_mode, base_url, model, secret_id, enabled
1735
+ FROM ai_model_connections
1736
+ WHERE provider = 'openai-codex'
1737
+ AND auth_mode = 'oauth'
1738
+ AND enabled = 1
1739
+ ORDER BY updated_at DESC`)
1740
+ .all();
1741
+ for (const row of fallbackRows) {
1742
+ const profile = mapNutritionCodexProfileRow(row);
1743
+ if (profile) {
1744
+ return profile;
1745
+ }
1746
+ }
1747
+ return null;
1748
+ }
1674
1749
  const parsedMealItemSchema = z.object({
1675
1750
  name: z.string().trim().min(1),
1676
1751
  quantity: z.coerce.number().positive().default(1),
@@ -124,15 +124,16 @@ export function upsertAiModelConnection(input, secrets, options = {}) {
124
124
  WHERE id = ?`)
125
125
  .get(parsed.id.trim())
126
126
  : undefined;
127
- const id = existing?.id ??
128
- `mdl_${randomUUID().replaceAll("-", "").slice(0, 10)}`;
127
+ const id = existing?.id ?? `mdl_${randomUUID().replaceAll("-", "").slice(0, 10)}`;
129
128
  const now = new Date().toISOString();
130
129
  const provider = parsed.provider;
131
130
  const authMode = parsed.authMode ?? defaultAuthMode(provider);
132
131
  const baseUrl = parsed.baseUrl?.trim() ||
133
132
  existing?.base_url ||
134
133
  defaultBaseUrlForProvider(provider);
135
- let secretId = existing?.secret_id ?? null;
134
+ let secretId = existing?.secret_id && readEncryptedSecret(existing.secret_id)
135
+ ? existing.secret_id
136
+ : null;
136
137
  let accountLabel = existing?.account_label ?? null;
137
138
  if (parsed.provider === "mock") {
138
139
  secretId = null;
@@ -152,6 +153,11 @@ export function upsertAiModelConnection(input, secrets, options = {}) {
152
153
  accountLabel = options.oauthCredential.accountId;
153
154
  storeEncryptedSecret(secretId, secrets.sealJson(options.oauthCredential), `${parsed.label} AI OAuth connection`);
154
155
  }
156
+ if (parsed.provider !== "mock" && !secretId) {
157
+ throw new Error(authMode === "oauth"
158
+ ? "Reconnect OAuth before saving this model connection. The existing credential is missing from Forge's encrypted secret store."
159
+ : "Enter the API key before saving this model connection. The existing credential is missing from Forge's encrypted secret store.");
160
+ }
155
161
  getDatabase()
156
162
  .prepare(`INSERT INTO ai_model_connections (
157
163
  id, label, provider, auth_mode, base_url, model, account_label, secret_id, enabled, metadata_json, created_at, updated_at
@@ -3,22 +3,30 @@ import { Handle, Position } from "@xyflow/react";
3
3
  import { useState } from "react";
4
4
  import { InfoTooltip } from "../../../components/ui/info-tooltip.js";
5
5
  import { cn } from "../../../lib/utils.js";
6
+ const nodeEyebrowClass = "flex items-center gap-1 text-[10px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]";
7
+ const nodePillClass = "rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-2.5 py-1 text-[10px] uppercase tracking-[0.16em] text-[var(--ui-ink-soft)]";
8
+ const nodeSoftPanelClass = "rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-3 py-2 text-[11px] text-[var(--ui-ink-soft)]";
9
+ const nodeCodePanelClass = "rounded-[18px] border border-[var(--ui-border-subtle)] bg-[var(--ui-code-bg)] p-3 text-[var(--ui-code-text)]";
6
10
  function describePort(port) {
7
- return [port.kind, port.modelName, port.itemKind ? `item:${port.itemKind}` : null]
11
+ return [
12
+ port.kind,
13
+ port.modelName,
14
+ port.itemKind ? `item:${port.itemKind}` : null
15
+ ]
8
16
  .filter(Boolean)
9
17
  .join(" · ");
10
18
  }
11
19
  function PortList({ title, ports, align }) {
12
- return (_jsxs("div", { className: "grid gap-1.5", children: [_jsxs("div", { className: cn("flex items-center gap-1 text-[10px] uppercase tracking-[0.18em] text-white/34", align === "left" ? "text-left" : "text-right"), children: [_jsx("span", { children: title }), _jsx(InfoTooltip, { content: align === "left"
20
+ return (_jsxs("div", { className: "grid gap-1.5", children: [_jsxs("div", { className: cn(nodeEyebrowClass, align === "left" ? "text-left" : "text-right"), children: [_jsx("span", { children: title }), _jsx(InfoTooltip, { content: align === "left"
13
21
  ? "Inputs are values this box expects from upstream nodes."
14
- : "Outputs are values this box publishes for downstream nodes.", label: align === "left" ? "Explain box inputs" : "Explain box outputs" })] }), ports.length === 0 ? (_jsx("div", { className: "rounded-full border border-dashed border-white/10 px-3 py-1.5 text-[11px] text-white/28", children: "None" })) : null, ports.map((port) => (_jsxs("div", { className: cn("relative rounded-[16px] bg-white/[0.05] px-3 py-2 text-[11px] text-white/62", align === "left" ? "pl-5 text-left" : "pr-5 text-right"), children: [_jsx(Handle, { type: align === "left" ? "target" : "source", position: align === "left" ? Position.Left : Position.Right, id: port.key, className: "!size-2.5 !border !border-white/80 !bg-[#b8c5ff]", style: {
22
+ : "Outputs are values this box publishes for downstream nodes.", label: align === "left" ? "Explain box inputs" : "Explain box outputs" })] }), ports.length === 0 ? (_jsx("div", { className: "rounded-full border border-dashed border-[var(--ui-border-subtle)] px-3 py-1.5 text-[11px] text-[var(--ui-ink-faint)]", children: "None" })) : null, ports.map((port) => (_jsxs("div", { className: cn("relative rounded-[16px] border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-3 py-2 text-[11px] text-[var(--ui-ink-soft)]", align === "left" ? "pl-5 text-left" : "pr-5 text-right"), children: [_jsx(Handle, { type: align === "left" ? "target" : "source", position: align === "left" ? Position.Left : Position.Right, id: port.key, className: "!size-2.5 !border !border-[var(--ui-surface-1)] !bg-[var(--primary)]", style: {
15
23
  [align]: 6
16
- } }), _jsx("div", { children: port.label }), _jsx("div", { className: "mt-1 text-[10px] text-white/38", children: describePort(port) })] }, port.key)))] }));
24
+ } }), _jsx("div", { children: port.label }), _jsx("div", { className: "mt-1 text-[10px] text-[var(--ui-ink-faint)]", children: describePort(port) })] }, port.key)))] }));
17
25
  }
18
26
  export function createGenericWorkbenchNodeView(definition) {
19
27
  return function GenericWorkbenchNodeView(_props) {
20
28
  const [schemaOpen, setSchemaOpen] = useState(false);
21
- return (_jsxs("div", { className: "min-w-[280px] rounded-[24px] border border-white/10 bg-[linear-gradient(180deg,rgba(20,28,45,0.98),rgba(11,16,29,0.98))] p-3 shadow-[0_26px_80px_rgba(0,0,0,0.4)]", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-sm font-semibold text-white", children: definition.title }), _jsx("div", { className: "mt-1 line-clamp-2 text-[12px] leading-5 text-white/48", children: definition.description })] }), _jsx("div", { className: "rounded-full bg-white/[0.06] px-2.5 py-1 text-[10px] uppercase tracking-[0.16em] text-white/56", children: "box" })] }), definition.params.length > 0 ? (_jsxs("div", { className: "mt-3 rounded-[18px] bg-white/[0.04] px-3 py-2 text-[11px] text-white/52", children: [definition.params.length, " param", definition.params.length === 1 ? "" : "s", " configurable in the flow editor"] })) : null, definition.tools.length > 0 ? (_jsxs("div", { className: "mt-2 rounded-[18px] bg-white/[0.04] px-3 py-2 text-[11px] text-white/52", children: [definition.tools.length, " tool", definition.tools.length === 1 ? "" : "s", " available"] })) : null, _jsx("div", { className: "mt-2", children: _jsx("button", { type: "button", className: "rounded-full bg-white/[0.05] px-3 py-1.5 text-[11px] text-white/56 transition hover:bg-white/[0.08] hover:text-white", onClick: () => setSchemaOpen((current) => !current), children: schemaOpen ? "Hide schema" : "Preview schema" }) }), _jsxs("div", { className: "mt-3 grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] gap-3", children: [_jsx(PortList, { title: "Inputs", ports: definition.inputs, align: "left" }), _jsx(PortList, { title: "Outputs", ports: definition.output, align: "right" })] }), schemaOpen ? (_jsxs("div", { className: "mt-3 rounded-[18px] border border-white/8 bg-black/20 p-3", children: [_jsxs("div", { className: "flex items-center gap-2 text-[10px] uppercase tracking-[0.18em] text-white/38", children: [_jsx("span", { children: "Box contract" }), _jsx(InfoTooltip, { content: "This preview summarizes what the box consumes, publishes, and what tools it can expose to AI nodes.", label: "Explain box contract preview" })] }), _jsx("pre", { className: "mt-2 overflow-auto whitespace-pre-wrap text-[11px] leading-5 text-white/64", children: JSON.stringify({
29
+ return (_jsxs("div", { className: "min-w-[280px] rounded-[24px] border border-[var(--ui-border-subtle)] bg-[image:var(--ui-surface-modal)] p-3 shadow-[var(--ui-shadow-floating)]", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-sm font-semibold text-[var(--ui-ink-strong)]", children: definition.title }), _jsx("div", { className: "mt-1 line-clamp-2 text-[12px] leading-5 text-[var(--ui-ink-soft)]", children: definition.description })] }), _jsx("div", { className: nodePillClass, children: "box" })] }), definition.params.length > 0 ? (_jsxs("div", { className: `mt-3 ${nodeSoftPanelClass}`, children: [definition.params.length, " param", definition.params.length === 1 ? "" : "s", " configurable in the flow editor"] })) : null, definition.tools.length > 0 ? (_jsxs("div", { className: `mt-2 ${nodeSoftPanelClass}`, children: [definition.tools.length, " tool", definition.tools.length === 1 ? "" : "s", " available"] })) : null, _jsx("div", { className: "mt-2", children: _jsx("button", { type: "button", className: "rounded-full border border-[var(--ui-border-subtle)] bg-[var(--ui-surface-2)] px-3 py-1.5 text-[11px] text-[var(--ui-ink-soft)] transition hover:bg-[var(--ui-surface-hover)] hover:text-[var(--ui-ink-strong)]", onClick: () => setSchemaOpen((current) => !current), children: schemaOpen ? "Hide schema" : "Preview schema" }) }), _jsxs("div", { className: "mt-3 grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] gap-3", children: [_jsx(PortList, { title: "Inputs", ports: definition.inputs, align: "left" }), _jsx(PortList, { title: "Outputs", ports: definition.output, align: "right" })] }), schemaOpen ? (_jsxs("div", { className: `mt-3 ${nodeCodePanelClass}`, children: [_jsxs("div", { className: "flex items-center gap-2 text-[10px] uppercase tracking-[0.18em] text-[var(--ui-ink-faint)]", children: [_jsx("span", { children: "Box contract" }), _jsx(InfoTooltip, { content: "This preview summarizes what the box consumes, publishes, and what tools it can expose to AI nodes.", label: "Explain box contract preview" })] }), _jsx("pre", { className: "mt-2 overflow-auto whitespace-pre-wrap text-[11px] leading-5", children: JSON.stringify({
22
30
  inputs: definition.inputs.map(({ key, kind, required, description, modelName, itemKind, shape, exampleValue }) => ({
23
31
  key,
24
32
  kind,
@@ -1756,9 +1756,18 @@ export function getVitalsView(userIds) {
1756
1756
  const suffix = search.size > 0 ? `?${search.toString()}` : "";
1757
1757
  return request(`/api/v1/health/vitals${suffix}`);
1758
1758
  }
1759
- export function getWeightLossView(userIds) {
1759
+ export function getWeightLossView(userIds, options) {
1760
1760
  const search = new URLSearchParams();
1761
1761
  appendUserIds(search, coerceUserIds(userIds));
1762
+ if (options?.dateKey) {
1763
+ search.set("dateKey", options.dateKey);
1764
+ }
1765
+ if (options?.dayStartAt) {
1766
+ search.set("dayStartAt", options.dayStartAt);
1767
+ }
1768
+ if (options?.dayEndAt) {
1769
+ search.set("dayEndAt", options.dayEndAt);
1770
+ }
1762
1771
  const suffix = search.size > 0 ? `?${search.toString()}` : "";
1763
1772
  return request(`/api/v1/health/weight-loss${suffix}`);
1764
1773
  }
@@ -2,7 +2,7 @@
2
2
  "id": "forge-openclaw-plugin",
3
3
  "name": "Forge",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
- "version": "0.2.102",
5
+ "version": "0.2.103",
6
6
  "activation": {
7
7
  "onStartup": true,
8
8
  "onCapabilities": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-openclaw-plugin",
3
- "version": "0.2.102",
3
+ "version": "0.2.103",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -1 +0,0 @@
1
- import{j as e,aC as x,c2 as k}from"./vendor-kIz9EZnX.js";import{j as A,i as C,k as E}from"./state-VYvD1QVP.js";import{C as w,B as I,U as P,f,u as R,i as S,r as L,L as T,E as U,a as q,l as Q}from"./index-BHIKoiZ6.js";import{P as _}from"./page-hero-oFHaAjtL.js";import{u as F,f as g,g as H,c as M}from"./table-C0VTeqw0.js";import{g as p,a as v}from"./entity-links-DwpxhW2H.js";import"./motion-CfdU2F35.js";import"./ui-CsEkP2V8.js";import"./forms-CmLAyGqz.js";import"./board-DqHzdCPQ.js";import"./graph-BTa79qum.js";const n=M(),y=[n.accessor("title",{header:"Event",cell:t=>{const s=p(t.row.original);return s?e.jsx(x,{to:s,className:"font-medium text-white transition hover:text-[var(--primary)]",children:t.getValue()}):e.jsx("div",{className:"font-medium text-white",children:t.getValue()})}}),n.accessor("source",{header:"Source",cell:t=>e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.16em] text-white/50",children:t.getValue()})}),n.display({id:"owner",header:"Owner",cell:t=>t.row.original.user?e.jsx(P,{user:t.row.original.user,compact:!0}):e.jsx("div",{className:"text-[11px] uppercase tracking-[0.16em] text-white/32",children:"Unowned"})}),n.accessor("createdAt",{header:"When",cell:t=>e.jsx("div",{className:"text-sm text-white/55",children:f(t.getValue())})}),n.display({id:"actions",header:"Open",cell:t=>{const s=p(t.row.original);return s?e.jsx(x,{to:s,className:"inline-flex text-[11px] uppercase tracking-[0.16em] text-[var(--primary)] transition hover:text-white",children:"Open"}):e.jsx("div",{className:"text-[11px] uppercase tracking-[0.16em] text-white/32",children:"Archive only"})}})];function V({rows:t,onRemove:s}){const l=s?[...y,n.display({id:"remove",header:"Correct",cell:i=>e.jsx(I,{variant:"ghost",className:"h-auto px-0 py-0 text-[11px] uppercase tracking-[0.16em] text-white/55",onClick:()=>{s(i.row.original.id)},children:"Remove log"})})]:y,o=F({columns:l,data:t,getCoreRowModel:H()});return e.jsx(w,{className:"overflow-hidden p-0",children:e.jsxs("table",{className:"w-full border-collapse",children:[e.jsx("thead",{children:o.getHeaderGroups().map(i=>e.jsx("tr",{className:"bg-white/[0.03]",children:i.headers.map(a=>e.jsx("th",{className:"px-5 py-4 text-left font-label text-[11px] uppercase tracking-[0.18em] text-white/40",children:a.isPlaceholder?null:g(a.column.columnDef.header,a.getContext())},a.id))},i.id))}),e.jsx("tbody",{children:o.getRowModel().rows.map(i=>e.jsx("tr",{className:"bg-white/[0.015] transition hover:bg-white/[0.035]",children:i.getVisibleCells().map(a=>e.jsx("td",{className:"px-5 py-4 align-top",children:g(a.column.columnDef.cell,a.getContext())},a.id))},i.id))})]})})}function Z(){var u;const t=R(),s=Array.isArray(t.selectedUserIds)?t.selectedUserIds:[],[l]=k(),o=A(),i=l.get("entityId")??void 0,a=l.get("entityType")??void 0,j=l.get("eventId"),d=C({queryKey:["activity-archive",a,i,...s],queryFn:()=>Q({limit:100,entityType:a,entityId:i,userIds:s})}),b=E({mutationFn:c=>L(c),onSuccess:async()=>{await Promise.all([o.invalidateQueries({queryKey:["activity-archive"]}),S(o),o.invalidateQueries({queryKey:["task-context"]}),o.invalidateQueries({queryKey:["project-board"]})])}}),m=((u=d.data)==null?void 0:u.activity)??[];if(d.isLoading)return e.jsx(T,{eyebrow:"Evidence archive",title:"Loading activity",description:"Pulling the visible audit trail, grouped evidence, and correction history."});if(d.isError)return e.jsx(U,{eyebrow:"Evidence archive",error:d.error,onRetry:()=>void d.refetch()});if(m.length===0)return e.jsx(q,{eyebrow:"Evidence archive",title:i?"No evidence matched this filter":"No activity recorded yet",description:i?"Forge could not find visible events for this specific entity yet. Try a broader archive view or create some work first.":"As you complete work, log runs, or make corrections, the audit trail will appear here."});const N=m.reduce((c,h)=>{const r=h.createdAt.slice(0,10);return c[r]=[...c[r]??[],h],c},{});return e.jsxs("div",{className:"grid gap-5",children:[e.jsx(_,{title:"Activity",description:i?"This filtered archive shows the evidence connected to the item you opened, so you can confirm what changed and when.":"Activity is your visible audit trail. Use it to inspect progress, confirm corrections, and trace work back to the goal, project, or task it came from.",badge:`${m.length} recent events`}),e.jsxs("section",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]",children:[e.jsx(V,{rows:m,onRemove:async c=>{await b.mutateAsync(c)}}),e.jsx("div",{className:"grid gap-4",children:Object.entries(N).slice(0,6).map(([c,h])=>e.jsxs(w,{children:[e.jsx("div",{className:"font-label text-[11px] uppercase tracking-[0.18em] text-white/45",children:c}),e.jsx("div",{className:"mt-4 grid gap-3",children:h.slice(0,3).map(r=>e.jsxs("div",{className:`rounded-[18px] p-4 ${j===r.id?"bg-[rgba(192,193,255,0.12)] shadow-[inset_0_0_0_1px_rgba(192,193,255,0.2)]":"bg-white/[0.04]"}`,children:[e.jsx("div",{className:"font-medium text-white",children:r.title}),e.jsx("div",{className:"mt-2 text-sm text-white/58",children:r.description}),e.jsx("div",{className:"mt-3 text-[11px] uppercase tracking-[0.16em] text-white/35",children:f(r.createdAt)}),p(r)&&v(r)?e.jsx(x,{to:p(r),className:"mt-3 inline-flex text-[11px] uppercase tracking-[0.16em] text-[var(--primary)]",children:v(r)}):null]},r.id))})]},c))})]})]})}export{Z as ActivityPage};
@@ -1 +0,0 @@
1
- import{r as p,j as e,aV as tt,aG as He,c3 as Lt,b5 as Rt,c2 as Kt,c4 as oe,c5 as Me,c6 as Ht,c7 as ze,c8 as Bt,c9 as Ut,bK as at,ca as $e,bc as Wt,cb as it,bg as Qt}from"./vendor-kIz9EZnX.js";import{w as qt,j as Zt,i as rt,k as $}from"./state-VYvD1QVP.js";import{g as bt,b as Be,F as j,I as P,T as Gt,e as be,c as S,d as ee,h as ce,j as we,k as We,m as Yt,n as wt,Q as Qe,o as vt,p as ft,q as Xt,u as Jt,s as Vt,t as ea,v as ta,w as aa,x as ia,y as nt,z as ra,A as na,D as sa,G as la,H as ye,S as oa,E as da,C as Z,J as ca,K as ma,B as G,M as ua,i as ha,N as pa,O as ga}from"./index-BHIKoiZ6.js";import{C as xa}from"./calendar-week-toolbar-BZ_-X3Wb.js";import{T as ya,a as ba}from"./timebox-planning-dialog-Ww0NGLLo.js";import{W as Ue,m as st,a as wa,s as _e,b as Le,c as va,f as Re}from"./calendar-ui-Cy1XRwzV.js";import{P as fa}from"./page-hero-oFHaAjtL.js";import{F as ka}from"./floating-action-menu-zzC2r0Ob.js";import{r as ja,b as Aa,g as lt}from"./calendar-display-preferences-Cid-2RnL.js";import"./motion-CfdU2F35.js";import"./ui-CsEkP2V8.js";import"./forms-CmLAyGqz.js";import"./board-DqHzdCPQ.js";import"./graph-BTa79qum.js";import"./scheduling-rules-editor-B9KNKsQz.js";function ot(a,n){const d=new Date(a);return Number.isNaN(d.getTime())?n:d.toISOString()}function de(a){const n=new Date(a);return new Date(n.getTime()-n.getTimezoneOffset()*6e4).toISOString().slice(0,16)}function dt(a,n){var y,b,v,m,N;const d=new Date,w=new Date(d.getTime()+30*6e4),x=new Date(w.getTime()+60*6e4);return{title:(n==null?void 0:n.title)??(a==null?void 0:a.title)??"",description:(n==null?void 0:n.description)??(a==null?void 0:a.description)??"",location:(n==null?void 0:n.location)??(a==null?void 0:a.location)??"",placeAddress:((y=n==null?void 0:n.place)==null?void 0:y.address)??((b=a==null?void 0:a.place)==null?void 0:b.address)??"",placeTimezone:((v=n==null?void 0:n.place)==null?void 0:v.timezone)??((m=a==null?void 0:a.place)==null?void 0:m.timezone)??"",startAtLocal:a?de(a.startAt):n!=null&&n.startAt?de(n.startAt):de(w.toISOString()),endAtLocal:a?de(a.endAt):n!=null&&n.endAt?de(n.endAt):de(x.toISOString()),timezone:(n==null?void 0:n.timezone)??(a==null?void 0:a.timezone)??Intl.DateTimeFormat().resolvedOptions().timeZone??"UTC",availability:(n==null?void 0:n.availability)??(a==null?void 0:a.availability)??"busy",activityPresetKey:ft(a==null?void 0:a.actionProfile),customSustainRateApPerHour:vt(a==null?void 0:a.actionProfile),preferredCalendarId:n&&"preferredCalendarId"in n?n.preferredCalendarId:(a==null?void 0:a.calendarId)??void 0,categoriesText:((N=n==null?void 0:n.categories)==null?void 0:N.join(", "))??(a==null?void 0:a.categories.join(", "))??"",linkQuery:"",links:(n==null?void 0:n.links)??(a==null?void 0:a.links.map(F=>({entityType:F.entityType,entityId:F.entityId,relationshipType:F.relationshipType,label:`${F.entityType.replaceAll("_"," ")} · ${F.entityId}`})))??[]}}function Sa({open:a,onOpenChange:n,writableCalendars:d,linkOptions:w,event:x,seed:y,onSubmit:b,pending:v=!1}){const[m,N]=p.useState(()=>dt(x,y)),[F,c]=p.useState(null);p.useEffect(()=>{a&&(N(dt(x,y)),c(null))},[x,a,y]);const A=p.useMemo(()=>w.map(s=>{const g=bt(s.entityType);return{value:`${s.entityType}:${s.entityId}`,label:s.label,description:s.subtitle,searchText:`${s.label} ${s.subtitle} ${s.entityType}`,kind:g??void 0,menuBadge:g?e.jsx(Be,{kind:g,label:s.label,compact:!0,gradient:!1}):void 0,badge:g?e.jsx(Be,{kind:g,label:s.label,compact:!0}):void 0}}),[w]),u=p.useMemo(()=>[{id:"identity",eyebrow:"Event",title:x?"Refine the Forge event":"Create a Forge calendar event",description:"This event belongs to Forge first. If you choose a writable calendar, Forge will also project it to the connected provider.",render:(s,g)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(j,{label:"Title",children:e.jsx(P,{value:s.title,onChange:o=>g({title:o.target.value}),placeholder:"Weekly research supervision"})}),e.jsx(j,{label:"Description",children:e.jsx(Gt,{value:s.description,onChange:o=>g({description:o.target.value}),placeholder:"Agenda, context, or outcomes you want this event to carry."})}),e.jsx(j,{label:"Location",children:e.jsx(P,{value:s.location,onChange:o=>g({location:o.target.value}),placeholder:"Clinic room 2 or Zoom"})}),e.jsx(j,{label:"Place address",children:e.jsx(P,{value:s.placeAddress,onChange:o=>g({placeAddress:o.target.value}),placeholder:"Bahnhofstrasse 10, Zurich"})}),e.jsx(j,{label:"Place timezone",children:e.jsx(P,{value:s.placeTimezone,onChange:o=>g({placeTimezone:o.target.value}),placeholder:"Europe/Zurich"})})]})},{id:"timing",eyebrow:"Timing",title:"Set the time and visibility",description:"Forge stores the real event window, timezone, and whether it should behave like a busy or free slot for scheduling rules.",render:(s,g)=>e.jsxs("div",{className:"grid gap-4",children:[(()=>{const o=new Date().toISOString(),_=new Date(Date.now()+3600*1e3).toISOString(),M=be({title:s.title,availability:s.availability,activityPresetKey:s.activityPresetKey,customSustainRateApPerHour:s.customSustainRateApPerHour,startAt:ot(s.startAtLocal,o),endAt:ot(s.endAtLocal,_)});return e.jsxs("div",{className:"rounded-[22px] border border-white/8 bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(S,{className:"bg-white/[0.08] text-white/74",children:ee(M.rateApPerHour)}),e.jsx(S,{className:"bg-white/[0.08] text-white/74",children:ce(M.totalAp)})]}),e.jsx("div",{className:"mt-3 text-sm leading-6 text-white/58",children:"Availability controls whether the event blocks planning. The activity profile controls AP drain, and you can override it with a custom AP per hour."})]})})(),e.jsx(j,{label:"Activity profile",children:e.jsx(we,{value:s.activityPresetKey??(s.availability==="busy"?"meeting":"light_context"),columns:3,onChange:o=>g({activityPresetKey:o}),options:We().filter(o=>o.key!=="task_inherited").map(o=>({value:o.key,label:o.label,description:`${ee(o.defaultRateApPerHour)} · ${o.description}`}))})}),e.jsx(j,{label:"Custom AP per hour",children:e.jsx(P,{type:"number",min:0,step:.5,value:s.customSustainRateApPerHour??"",onChange:o=>g({customSustainRateApPerHour:o.target.value.trim()===""?null:Number(o.target.value)}),placeholder:"Leave empty to use the activity default"})}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsx(j,{label:"Starts",children:e.jsx(P,{type:"datetime-local",value:s.startAtLocal,onChange:o=>g({startAtLocal:o.target.value})})}),e.jsx(j,{label:"Ends",children:e.jsx(P,{type:"datetime-local",value:s.endAtLocal,onChange:o=>g({endAtLocal:o.target.value})})})]}),e.jsx(j,{label:"Timezone",children:e.jsx(P,{value:s.timezone,onChange:o=>g({timezone:o.target.value}),placeholder:"Europe/Zurich"})}),e.jsx(j,{label:"Availability",children:e.jsx(we,{value:s.availability,onChange:o=>g({availability:o}),options:[{value:"busy",label:"Busy",description:"This event should block timebox recommendations and rule checks."},{value:"free",label:"Free",description:"This event stays visible in the calendar without blocking work."}]})})]})},{id:"links",eyebrow:"Meaning",title:"Connect the event to Forge entities",description:"Attach this event to strategies, goals, projects, tasks, or habits so the calendar carries multi-user operating context instead of staying isolated.",render:(s,g)=>e.jsx("div",{className:"grid gap-4",children:e.jsx(j,{label:"Search Forge entities",description:"Search across human and bot-owned entities; the linked records use the same icon, color, and owner system as the rest of Forge.",children:e.jsx(Yt,{options:A,selectedValues:s.links.map(o=>`${o.entityType}:${o.entityId}`),onChange:o=>{g({links:o.map(_=>{const[M,...L]=_.split(":"),R=L.join(":"),te=w.find(me=>me.entityType===M&&me.entityId===R);return te?{entityType:te.entityType,entityId:te.entityId,relationshipType:"context",label:te.label}:null}).filter(_=>_!==null)})},placeholder:"Search strategies, goals, projects, tasks, habits, human, or bot owners",emptyMessage:"No matching Forge entities found."})})})},{id:"projection",eyebrow:"Projection",title:"Choose where this event should live remotely",description:"You can keep the event local to Forge, or choose a writable connected calendar so Forge also keeps a synced remote copy.",render:(s,g)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsxs("div",{className:"grid gap-3",children:[d.length>0?e.jsxs("button",{type:"button",onClick:()=>g({preferredCalendarId:void 0}),className:`rounded-[22px] border px-4 py-4 text-left transition ${s.preferredCalendarId===void 0?"border-[rgba(125,211,252,0.28)] bg-[rgba(125,211,252,0.14)] text-white":"border-white/8 bg-white/[0.04] text-white/72 hover:bg-white/[0.07]"}`,children:[e.jsxs("div",{className:"flex items-center gap-2 font-medium",children:[e.jsx(tt,{className:"size-4"}),"Default synced calendar"]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-white/55",children:"Let Forge use the default writable connected calendar automatically."})]}):null,e.jsxs("button",{type:"button",onClick:()=>g({preferredCalendarId:null}),className:`rounded-[22px] border px-4 py-4 text-left transition ${s.preferredCalendarId===null?"border-[rgba(192,193,255,0.28)] bg-[rgba(192,193,255,0.14)] text-white":"border-white/8 bg-white/[0.04] text-white/72 hover:bg-white/[0.07]"}`,children:[e.jsxs("div",{className:"flex items-center gap-2 font-medium",children:[e.jsx(He,{className:"size-4"}),"Forge only"]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-white/55",children:"Keep the event in Forge without creating a remote provider copy yet."})]}),d.map(o=>e.jsxs("button",{type:"button",onClick:()=>g({preferredCalendarId:o.id}),className:`rounded-[22px] border px-4 py-4 text-left transition ${s.preferredCalendarId===o.id?"border-[rgba(125,211,252,0.28)] bg-[rgba(125,211,252,0.14)] text-white":"border-white/8 bg-white/[0.04] text-white/72 hover:bg-white/[0.07]"}`,children:[e.jsxs("div",{className:"flex items-center gap-2 font-medium",children:[e.jsx(tt,{className:"size-4"}),wt(o)]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-white/55",children:o.description||`${o.timezone} · writable`})]},o.id))]}),e.jsxs("div",{className:"grid gap-2 rounded-[22px] border border-white/8 bg-white/[0.04] p-4 text-sm text-white/66",children:[e.jsxs("div",{className:"flex items-center gap-2 font-medium text-white",children:[e.jsx(Lt,{className:"size-4 text-[var(--primary)]"}),"Categories and filtering"]}),e.jsx(P,{value:s.categoriesText,onChange:o=>g({categoriesText:o.target.value}),placeholder:"meeting, clinic, research"})]})]})}],[x,w,A,d]);return e.jsx(Qe,{open:a,onOpenChange:n,eyebrow:x?"Edit event":"New event",title:x?"Edit calendar event":"Create calendar event",description:"Forge-owned events can stay local or publish to a connected provider calendar.",value:m,onChange:N,draftPersistenceKey:x?`calendar.event.${x.id}`:"calendar.event.new",steps:u,onSubmit:async()=>{if(!m.title.trim()){c("Add an event title before saving.");return}if(!m.startAtLocal||!m.endAtLocal){c("Set both the start and end time before saving.");return}if(new Date(m.endAtLocal).getTime()<=new Date(m.startAtLocal).getTime()){c("The event end time must be after the start time.");return}c(null),await b({title:m.title.trim(),description:m.description.trim(),location:m.location.trim(),place:{label:m.location.trim(),address:m.placeAddress.trim(),timezone:m.placeTimezone.trim(),latitude:null,longitude:null,source:m.placeAddress.trim()?"manual":"",externalPlaceId:""},startAt:new Date(m.startAtLocal).toISOString(),endAt:new Date(m.endAtLocal).toISOString(),timezone:m.timezone.trim()||"UTC",availability:m.availability,activityPresetKey:m.activityPresetKey,customSustainRateApPerHour:m.customSustainRateApPerHour,categories:m.categoriesText.split(",").map(s=>s.trim()).filter(Boolean),links:m.links.map(s=>({entityType:s.entityType,entityId:s.entityId,relationshipType:s.relationshipType})),...m.preferredCalendarId!==void 0?{preferredCalendarId:m.preferredCalendarId}:{}})},submitLabel:x?"Save event":"Create event",pending:v,pendingLabel:x?"Saving":"Creating",error:F})}function Na({open:a,onOpenChange:n,initialTitle:d,pending:w=!1,onSubmit:x}){const[y,b]=p.useState(d),[v,m]=p.useState(null);return p.useEffect(()=>{a&&(b(d),m(null))},[d,a]),e.jsx(Qe,{open:a,onOpenChange:n,eyebrow:"Calendar",title:"Quick rename",description:"Rename the event without reopening the full event guide.",value:{title:y},onChange:N=>b(N.title),draftPersistenceKey:`calendar.quick-rename.${d}`,steps:[{id:"rename",eyebrow:"Rename",title:"Update the event title",description:"Keep the rename fast and direct. Everything else on the event stays unchanged.",render:(N,F)=>e.jsx(j,{label:"Event title",children:e.jsx(P,{value:N.title,onChange:c=>F({title:c.target.value}),placeholder:"Weekly research supervision"})})}],submitLabel:"Save title",pending:w,pendingLabel:"Saving",error:v,onSubmit:async()=>{const N=y.trim();if(!N){m("Add a title before saving.");return}m(null),await x(N),n(!1)}})}function ct(a){if(a)return{title:a.title,kind:a.kind,color:a.color,timezone:a.timezone,weekDays:a.weekDays,startMinute:a.startMinute,endMinute:a.endMinute,startsOn:a.startsOn,endsOn:a.endsOn,blockingState:a.blockingState,activityPresetKey:ft(a.actionProfile),customSustainRateApPerHour:vt(a.actionProfile)};const n=Ue[0];return{title:n.title,kind:n.kind,color:n.color,timezone:typeof Intl<"u"&&Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC",weekDays:[1,2,3,4,5],startMinute:n.startMinute,endMinute:n.endMinute,startsOn:null,endsOn:null,blockingState:n.blockingState,activityPresetKey:n.kind==="main_activity"?"deep_work":n.kind==="secondary_activity"?"admin":n.kind==="holiday"?"holiday_leisure":n.kind==="rest"?"recovery_break":"maintenance",customSustainRateApPerHour:null}}function mt(a){return a??""}function Ke({draft:a}){const n=Xt({kind:a.kind,startMinute:a.startMinute,endMinute:a.endMinute,activityPresetKey:a.activityPresetKey,customSustainRateApPerHour:a.customSustainRateApPerHour}),d=a.endMinute>a.startMinute?a.endMinute-a.startMinute:1440-a.startMinute+a.endMinute;return e.jsxs("div",{className:"rounded-[22px] border border-white/8 bg-white/[0.04] p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(S,{className:"bg-white/[0.08] text-white/74",children:ee(n.rateApPerHour)}),e.jsxs(S,{className:"bg-white/[0.08] text-white/74",children:[ce(n.totalAp)," / block"]}),e.jsxs(S,{className:"bg-white/[0.08] text-white/74",children:[Math.round(d/60),"h ",d%60,"m"]})]}),e.jsx("div",{className:"mt-3 text-sm leading-6 text-white/58",children:"This is the default Life Force container drain for each occurrence of the block when no richer task run or timebox already covers that window."})]})}function Ta({open:a,onOpenChange:n,onSubmit:d,pending:w=!1,template:x=null}){const[y,b]=p.useState(()=>ct(x)),[v,m]=p.useState(null),N=x!==null;p.useEffect(()=>{a&&(m(null),b(ct(x)))},[a,x]);const F=p.useMemo(()=>[{id:"preset",eyebrow:"Preset",title:"Start from a recurring block that already matches the rhythm",description:"Use a preset to seed the schedule, then tune the dates and recurrence in the next step.",render:(c,A)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(Ke,{draft:c}),e.jsx(j,{label:"Activity profile",children:e.jsx(we,{value:c.activityPresetKey??"maintenance",columns:3,onChange:u=>A({activityPresetKey:u,customSustainRateApPerHour:c.customSustainRateApPerHour}),options:We().filter(u=>u.key!=="task_inherited").map(u=>({value:u.key,label:u.label,description:`${ee(u.defaultRateApPerHour)} · ${u.description}`}))})}),e.jsx(j,{label:"Custom AP per hour",children:e.jsx(P,{type:"number",min:0,step:.5,value:c.customSustainRateApPerHour??"",onChange:u=>A({customSustainRateApPerHour:u.target.value.trim()===""?null:Number(u.target.value)}),placeholder:"Leave empty to use the activity default"})}),e.jsx(j,{label:"Block type",children:e.jsx(we,{value:c.kind,columns:3,onChange:u=>{const s=Ue.find(g=>g.kind===u);if(s){const g=s.kind==="holiday"?[0,1,2,3,4,5,6]:[1,2,3,4,5];A({kind:s.kind,title:s.title,color:s.color,weekDays:g,startMinute:s.startMinute,endMinute:s.endMinute,blockingState:s.blockingState,activityPresetKey:s.kind==="main_activity"?"deep_work":s.kind==="secondary_activity"?"admin":s.kind==="holiday"?"holiday_leisure":s.kind==="rest"?"recovery_break":"maintenance",customSustainRateApPerHour:null});return}A({kind:"custom",title:"Custom block",color:"#7dd3fc",activityPresetKey:"maintenance",customSustainRateApPerHour:null})},options:[...Ue.map(u=>({value:u.kind,label:u.title,description:`${st(u.startMinute)}-${st(u.endMinute)}`})),{value:"custom",label:"Custom",description:"Build a different recurring window."}]})})]})},{id:"shape",eyebrow:"Schedule",title:"Define when this recurring block should exist",description:"Weekdays and times describe the recurring pattern. Optional start and end dates bound when the template is active.",render:(c,A)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(Ke,{draft:c}),e.jsx(j,{label:"Block title",children:e.jsx(P,{value:c.title,onChange:u=>A({title:u.target.value}),placeholder:"Main Activity"})}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsx(j,{label:"Start minute",children:e.jsx(P,{type:"number",min:0,max:1440,step:15,value:c.startMinute,onChange:u=>A({startMinute:Number(u.target.value)||0})})}),e.jsx(j,{label:"End minute",children:e.jsx(P,{type:"number",min:0,max:1440,step:15,value:c.endMinute,onChange:u=>A({endMinute:Number(u.target.value)||0})})})]}),e.jsxs("div",{className:"grid gap-4 md:grid-cols-2",children:[e.jsx(j,{label:"Start date",children:e.jsx(P,{type:"date",value:mt(c.startsOn),onChange:u=>A({startsOn:u.target.value.trim()||null})})}),e.jsx(j,{label:"End date",children:e.jsx(P,{type:"date",value:mt(c.endsOn),onChange:u=>A({endsOn:u.target.value.trim()||null})})})]}),e.jsx("div",{className:"text-sm leading-6 text-white/54",children:"Leave the end date empty to keep repeating indefinitely. Holiday blocks work well with all seven weekdays and `0-1440`, and they still carry AP load because leisure and holiday time are real activities."}),e.jsx(j,{label:"Weekdays",children:e.jsx("div",{className:"flex flex-wrap gap-2",children:wa.map((u,s)=>{const g=c.weekDays.includes(s);return e.jsx("button",{type:"button",onClick:()=>A({weekDays:g?c.weekDays.filter(o=>o!==s):[...c.weekDays,s].sort((o,_)=>o-_)}),className:`rounded-full px-3 py-2 text-sm transition ${g?"bg-[var(--primary)]/18 text-[var(--primary)] shadow-[inset_0_0_0_1px_rgba(192,193,255,0.24)]":"bg-white/[0.05] text-white/62 hover:bg-white/[0.08]"}`,children:u},u)})})})]})},{id:"policy",eyebrow:"Policy",title:"Tell Forge whether this block allows or blocks work",description:"Use blocked mode for time that should normally stop optional work. Use allowed mode for protected focus windows.",render:(c,A)=>e.jsxs("div",{className:"grid gap-4",children:[e.jsx(Ke,{draft:c}),e.jsx(j,{label:"Work effect",children:e.jsx(we,{value:c.blockingState,onChange:u=>A({blockingState:u}),options:[{value:"blocked",label:"Blocks work",description:"Starting blocked tasks should require an explicit override."},{value:"allowed",label:"Allows work",description:"Use this for protected windows where the right tasks should fit."}]})}),e.jsx(j,{label:"Color",children:e.jsxs("div",{className:"flex items-center gap-3 rounded-[22px] border border-white/8 bg-white/6 px-4 py-3",children:[e.jsx("input",{className:"h-10 w-12 rounded-lg border border-white/10 bg-transparent",type:"color",value:c.color,onChange:u=>A({color:u.target.value})}),e.jsx(P,{className:"border-none bg-transparent px-0 py-0",value:c.color,onChange:u=>A({color:u.target.value})})]})})]})}],[]);return e.jsx(Qe,{open:a,onOpenChange:n,eyebrow:"Calendar",title:N?"Edit work block":"Create a work block",description:N?"Adjust the recurring pattern, date bounds, or work policy for this block.":"Build recurring half-day, holiday, or custom blocks so Forge can understand when work should be protected or blocked.",value:y,onChange:b,draftPersistenceKey:x?`calendar.work-block.${x.id}`:"calendar.work-block.new",steps:F,submitLabel:N?"Save changes":"Save work block",pending:w,pendingLabel:N?"Saving changes":"Saving",error:v,onSubmit:async()=>{if(!y.title.trim()){m("Give the block a title so it stays readable in the calendar.");return}if(y.weekDays.length===0){m("Select at least one weekday for the recurring block.");return}if(y.endMinute<=y.startMinute){m("The end minute needs to be later than the start minute.");return}if(y.startsOn&&y.endsOn&&y.endsOn<y.startsOn){m("The end date needs to be on or after the start date.");return}try{m(null),await d({...y,title:y.title.trim()}),n(!1)}catch(c){m(c instanceof Error?c.message:"Forge could not save this work block.")}}})}const Ne=qt(a=>({entry:null,setEntry:n=>a({entry:n}),clear:()=>a({entry:null}),completePaste:()=>a(n=>{var d;return{entry:((d=n.entry)==null?void 0:d.mode)==="cut"?null:n.entry}})}));function Ca(a){const n=new Date(a);n.setUTCHours(9,0,0,0);const d=new Date(n.getTime()+3600*1e3);return{startAt:n.toISOString(),endAt:d.toISOString(),timezone:Intl.DateTimeFormat().resolvedOptions().timeZone??"UTC",availability:"busy"}}function ut(a){var b;const n=Math.max(60,Math.floor((Date.parse(a.endsAt)-Date.parse(a.startsAt))/1e3)),d=((b=We().find(v=>v.key===a.activityPresetKey))==null?void 0:b.defaultRateApPerHour)??100/24,w=a.customSustainRateApPerHour??d,x=Number((n/3600*w).toFixed(2)),y=new Date().toISOString();return{id:`preview_${a.entityType}_${a.entityId}`,profileKey:`${String(a.entityType)}_${a.entityId}`,title:a.title,entityType:a.entityType,mode:"container",startupAp:0,totalCostAp:x,expectedDurationSeconds:n,sustainRateApPerHour:w,demandWeights:{activation:.1,focus:.35,vigor:.1,composure:.15,flow:.3},doubleCountPolicy:"container_only",sourceMethod:a.customSustainRateApPerHour!==null&&a.customSustainRateApPerHour!==void 0?"manual":a.activityPresetKey?"seeded":"inferred",costBand:w>=10?"standard":"light",recoveryEffect:0,metadata:{activityPresetKey:a.activityPresetKey??null,customSustainRateApPerHour:a.customSustainRateApPerHour??null},createdAt:y,updatedAt:y}}function ht(a){const n=typeof a.location=="string"?a.location:"",d=a.place??{label:n,address:"",timezone:"",latitude:null,longitude:null,source:"",externalPlaceId:""};return{...a,place:{label:d.label||n,address:d.address??"",timezone:d.timezone??"",latitude:d.latitude??null,longitude:d.longitude??null,source:d.source??"",externalPlaceId:d.externalPlaceId??""}}}function pt(a,n){const d=new Date(a.startAt),x=new Date(a.endAt).getTime()-d.getTime(),y=new Date(n);y.setUTCHours(d.getUTCHours(),d.getUTCMinutes(),0,0);const b=new Date(y.getTime()+x);return{startAt:y.toISOString(),endAt:b.toISOString()}}function gt(a){return{type:"calendar_event",eventId:a.id,title:a.title,description:a.description,location:a.location,startAt:a.startAt,endAt:a.endAt,timezone:a.timezone,availability:a.availability,preferredCalendarId:a.calendarId,categories:a.categories,links:a.links.map(n=>({entityType:n.entityType,entityId:n.entityId,relationshipType:n.relationshipType}))}}function Ia(a){switch(a){case"apple":return"Apple";case"google":return"Google";case"caldav":return"CalDAV";case"native":return"Forge";default:return"Derived"}}function Pa(a,n){var d;if(a.calendarId){const w=(d=n.get(a.calendarId))==null?void 0:d.trim();if(w)return w}return a.originType==="native"?"Forge only":Ia(a.originType)}function xt(a){switch(a){case"main_activity":return"Main activity";case"secondary_activity":return"Secondary activity";case"third_activity":return"Third activity";case"rest":return"Rest";case"holiday":return"Holiday";default:return"Custom"}}function yt(a){return a.startsOn&&a.endsOn?`${a.startsOn} to ${a.endsOn}`:a.startsOn?`From ${a.startsOn}`:a.endsOn?`Until ${a.endsOn}`:"Repeats with no end date"}function Qa(){var Ye,Xe,Je,Ve,et;const a=Rt(),[n,d]=Kt(),w=Jt(),x=Array.isArray(w.selectedUserIds)?w.selectedUserIds:[],y=Vt(x),b=Zt(),v=Ne(t=>t.entry),m=Ne(t=>t.setEntry),N=Ne(t=>t.clear),F=Ne(t=>t.completePaste),[c,A]=p.useState(()=>_e()),[u,s]=p.useState(null),[g,o]=p.useState(null),[_,M]=p.useState(!1),[L,R]=p.useState(null),[te,me]=p.useState(!1),[Te,ae]=p.useState(!1),[Y,ue]=p.useState(null),[kt,ie]=p.useState(!1),[Ce,re]=p.useState(null),[ne,Ie]=p.useState(null),he=p.useMemo(()=>ja(),[]),[jt,se]=p.useState(null),[k,pe]=p.useState(null),[Pe,K]=p.useState(null),ve=n.get("timeboxId"),H=p.useMemo(()=>{const t=c.toISOString(),r=Le(c,7).toISOString();return{from:t,to:r}},[c]),X=rt({queryKey:["forge-calendar-overview",H.from,H.to,...x],queryFn:()=>pa({...H,userIds:x})}),B=rt({queryKey:["forge-life-force",...x],queryFn:()=>ga(x)}),z=["forge-calendar-overview",H.from,H.to,...x],fe=t=>{if(t.deletedAt)return!1;const r=new Date(t.startAt).getTime();return r>=new Date(H.from).getTime()&&r<new Date(H.to).getTime()},ge=t=>{b.setQueryData(z,r=>r&&t(r))},E=async()=>{await Promise.all([b.invalidateQueries({queryKey:["forge-calendar-overview"]}),ha(b),b.invalidateQueries({queryKey:["task-context"]}),b.invalidateQueries({queryKey:["project-board"]})])},qe=$({mutationFn:t=>ea({...t,userId:t.userId??y}),onSuccess:E}),Ze=$({mutationFn:({templateId:t,patch:r})=>ta(t,r),onSuccess:E}),De=$({mutationFn:aa,onSuccess:E}),At=$({mutationFn:t=>ia({...t,userId:y}),onSuccess:E}),St=$({mutationFn:({timeboxId:t,startsAt:r,endsAt:l})=>nt(t,{startsAt:r,endsAt:l}),onSuccess:E}),Nt=$({mutationFn:({timeboxId:t,patch:r})=>nt(t,r),onSuccess:E}),Tt=$({mutationFn:ra,onSuccess:async()=>{ue(null),ae(!1),await E()}}),ke=$({mutationFn:t=>na({...t,userId:t.userId??y}),onMutate:async t=>{var h,C,U,W,le,V,D;K({tone:"saving",message:"Saving event changes in the background…"}),await b.cancelQueries({queryKey:z});const r=b.getQueryData(z),l=(r==null?void 0:r.calendar.calendars.find(I=>I.canWrite&&I.selectedForSync))??(r==null?void 0:r.calendar.calendars.find(I=>I.canWrite))??null,T=new Date().toISOString(),O=`calendar_event_optimistic_${Date.now()}`,i={id:O,connectionId:(l==null?void 0:l.connectionId)??null,calendarId:t.preferredCalendarId===void 0?(l==null?void 0:l.id)??null:t.preferredCalendarId,remoteId:null,ownership:"forge",originType:"native",status:"confirmed",title:t.title,description:t.description??"",location:t.location??"",place:{label:((h=t.place)==null?void 0:h.label)??t.location??"",address:((C=t.place)==null?void 0:C.address)??"",timezone:((U=t.place)==null?void 0:U.timezone)??t.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone??"UTC",latitude:((W=t.place)==null?void 0:W.latitude)??null,longitude:((le=t.place)==null?void 0:le.longitude)??null,source:((V=t.place)==null?void 0:V.source)??"forge",externalPlaceId:((D=t.place)==null?void 0:D.externalPlaceId)??""},startAt:t.startAt,endAt:t.endAt,timezone:t.timezone??Intl.DateTimeFormat().resolvedOptions().timeZone??"UTC",isAllDay:t.isAllDay??!1,availability:t.availability??"busy",eventType:t.eventType??"general",categories:t.categories??[],sourceMappings:[],links:(t.links??[]).map((I,Q)=>({id:`calendar_event_link_optimistic_${Date.now()}_${Q}`,entityType:I.entityType,entityId:I.entityId,relationshipType:I.relationshipType??"context",createdAt:T,updatedAt:T})),actionProfile:ut({entityType:"calendar_event",entityId:O,title:t.title,startsAt:t.startAt,endsAt:t.endAt,activityPresetKey:t.activityPresetKey??null,customSustainRateApPerHour:t.customSustainRateApPerHour??null}),remoteUpdatedAt:null,deletedAt:null,createdAt:T,updatedAt:T};return r&&fe(i)&&ge(I=>({...I,calendar:{...I.calendar,events:[i,...I.calendar.events]}})),{previous:r,optimisticEventId:i.id}},onError:(t,r,l)=>{l!=null&&l.previous&&b.setQueryData(z,l.previous),K({tone:"error",message:t instanceof Error?t.message:"Forge could not sync that event change."})},onSuccess:({event:t},r,l)=>{K(null),ge(T=>({...T,calendar:{...T.calendar,events:(fe(t)?[t,...T.calendar.events.filter(O=>O.id!==(l==null?void 0:l.optimisticEventId))]:T.calendar.events.filter(O=>O.id!==(l==null?void 0:l.optimisticEventId))).filter((O,i,h)=>h.findIndex(C=>C.id===O.id)===i)}}))},onSettled:E}),J=$({mutationFn:({eventId:t,patch:r})=>sa(t,r),onMutate:async({eventId:t,patch:r})=>{K({tone:"saving",message:"Saving event changes in the background…"}),await b.cancelQueries({queryKey:z});const l=b.getQueryData(z);return l&&ge(T=>{var C,U,W,le,V;const O=T.calendar.events.find(D=>D.id===t);if(!O)return T;const i=ht(O),h={...i,...r,place:r.place?{...i.place,...r.place}:i.place,calendarId:r.preferredCalendarId===void 0?i.calendarId:r.preferredCalendarId,links:((C=r.links)==null?void 0:C.map((D,I)=>{var Q,Se;return{id:((Q=i.links[I])==null?void 0:Q.id)??`calendar_event_link_optimistic_${Date.now()}_${I}`,entityType:D.entityType,entityId:D.entityId,relationshipType:D.relationshipType??"context",createdAt:((Se=i.links[I])==null?void 0:Se.createdAt)??i.createdAt,updatedAt:new Date().toISOString()}}))??i.links,actionProfile:ut({entityType:"calendar_event",entityId:t,title:r.title??i.title,startsAt:r.startAt??i.startAt,endsAt:r.endAt??i.endAt,activityPresetKey:r.activityPresetKey===void 0?(W=(U=i.actionProfile)==null?void 0:U.metadata)==null?void 0:W.activityPresetKey:r.activityPresetKey,customSustainRateApPerHour:r.customSustainRateApPerHour===void 0?typeof((V=(le=i.actionProfile)==null?void 0:le.metadata)==null?void 0:V.customSustainRateApPerHour)=="number"?i.actionProfile.metadata.customSustainRateApPerHour:null:r.customSustainRateApPerHour}),updatedAt:new Date().toISOString()};return{...T,calendar:{...T.calendar,events:T.calendar.events.map(D=>D.id===t?h:D).filter(fe)}}}),{previous:l}},onError:(t,r,l)=>{l!=null&&l.previous&&b.setQueryData(z,l.previous),K({tone:"error",message:t instanceof Error?t.message:"Forge could not sync that event change."})},onSuccess:({event:t})=>{K(null),ge(r=>({...r,calendar:{...r.calendar,events:r.calendar.events.map(l=>l.id===t.id?t:l).filter(fe)}}))},onSettled:E}),Oe=$({mutationFn:la,onMutate:async t=>{K({tone:"saving",message:"Removing the event in the background…"}),await b.cancelQueries({queryKey:z});const r=b.getQueryData(z);return r&&ge(l=>({...l,calendar:{...l.calendar,events:l.calendar.events.filter(T=>T.id!==t)}})),{previous:r}},onError:(t,r,l)=>{l!=null&&l.previous&&b.setQueryData(z,l.previous),K({tone:"error",message:t instanceof Error?t.message:"Forge could not delete that event."})},onSuccess:()=>{K(null)},onSettled:E}),je=(Ye=X.data)==null?void 0:Ye.calendar,Ae=p.useMemo(()=>va(c),[c]),f=p.useMemo(()=>je?{...je,events:je.events.map(ht)}:{generatedAt:"",providers:[],connections:[],calendars:[],events:[],workBlockTemplates:[],workBlockInstances:[],timeboxes:[]},[je]),Ct=p.useMemo(()=>new Map(f.calendars.map(t=>[t.id,wt(t)])),[f.calendars]),Fe=p.useMemo(()=>Aa(f.calendars,he.calendarColors),[he.calendarColors,f.calendars]),It=ke.isPending||J.isPending||Oe.isPending,Pt=f.timeboxes.filter(t=>t.status==="planned"),Dt=f.calendars.filter(t=>t.canWrite),xe=(t,r)=>r?`${t} · ${r}`:t,Ee=[...w.snapshot.goals.map(t=>({entityType:"goal",entityId:t.id,label:t.title,subtitle:xe("Goal",ye(t.user))})),...w.snapshot.projects.map(t=>({entityType:"project",entityId:t.id,label:t.title,subtitle:xe("Project",ye(t.user))})),...w.snapshot.tasks.map(t=>({entityType:"task",entityId:t.id,label:t.title,subtitle:xe("Task",ye(t.user))})),...w.snapshot.strategies.map(t=>({entityType:"strategy",entityId:t.id,label:t.title,subtitle:xe("Strategy",ye(t.user))})),...w.snapshot.habits.map(t=>({entityType:"habit",entityId:t.id,label:t.title,subtitle:xe("Habit",ye(t.user))}))],Ot=p.useMemo(()=>new Map(Ee.map(t=>[`${t.entityType}:${t.entityId}`,t.label])),[Ee]),Ft=f.connections.length===0?"No providers connected":`${f.connections.filter(t=>t.status==="connected").length}/${f.connections.length} healthy`,q=(v==null?void 0:v.items.filter(t=>t.type==="calendar_event"))??[];p.useEffect(()=>{if(!ve)return;const t=f.timeboxes.find(l=>l.id===ve);if(!t)return;const r=_e(new Date(t.startsAt));if(r.getTime()!==c.getTime()){A(r);return}((Y==null?void 0:Y.id)!==t.id||!Te)&&(ue(t),ae(!0))},[ve,f.timeboxes,Y==null?void 0:Y.id,Te,c]);const Ge=()=>{if(!ve)return;const t=new URLSearchParams(n);t.delete("timeboxId"),d(t,{replace:!0})},Et=t=>{ae(t),t||(ue(null),Ge())},Mt=t=>{re(null),se(Ca(t)),ie(!0)},zt=async(t,r)=>{const l=pt({startAt:t.startAt,endAt:t.endAt},r);await J.mutateAsync({eventId:t.id,patch:l})},$t=async t=>{if(q.length!==0){for(const r of q){const l=pt(r,t);(v==null?void 0:v.mode)==="cut"?await J.mutateAsync({eventId:r.eventId,patch:l}):await ke.mutateAsync({title:r.title,description:r.description,location:r.location,startAt:l.startAt,endAt:l.endAt,timezone:r.timezone,availability:r.availability,preferredCalendarId:r.preferredCalendarId,categories:r.categories,links:r.links})}F()}},_t=p.useMemo(()=>{if(!k)return[];if(k.kind==="day"){const r=Ae.find(l=>l.toISOString().slice(0,10)===k.dayKey);return r?[{id:"create-event",label:"Create event",description:"Open the event guide with this day already selected.",icon:oe,onSelect:()=>Mt(r)},{id:"create-work-block",label:"Create work block",description:"Open the guided work-block flow while you are looking at this day.",icon:Me,onSelect:()=>{R(null),M(!0)}},{id:"paste",label:(v==null?void 0:v.mode)==="cut"?"Paste moved event":"Paste copied event",description:q.length>0?`${q.length} calendar item${q.length===1?"":"s"} ready to paste here.`:v?"The current clipboard entry does not contain calendar events.":"Copy or cut an event first, then paste it into this day.",icon:Ht,disabled:q.length===0,onSelect:()=>void $t(r)}]:[]}if(k.kind==="work-block"){const r=f.workBlockTemplates.find(l=>l.id===k.templateId);return r?[{id:"edit-work-block",label:"Edit",description:"Adjust the recurring pattern, date bounds, or work policy.",icon:oe,onSelect:()=>{R(r),M(!0)}},{id:"delete-work-block",label:"Delete",description:"Remove this recurring work block from Forge.",icon:ze,tone:"danger",onSelect:()=>{(L==null?void 0:L.id)===r.id&&R(null),De.mutateAsync(r.id)}}]:[]}const t=f.events.find(r=>r.id===k.eventId);return t?[{id:"rename",label:"Quick rename",description:"Change the event title without opening the full event flow.",icon:oe,onSelect:()=>Ie(t)},{id:"copy",label:"Copy",description:"Put this event on the Forge clipboard so you can paste it into another day.",icon:Bt,onSelect:()=>m({id:`clipboard_${t.id}_${Date.now()}`,mode:"copy",source:"calendar",label:t.title,createdAt:new Date().toISOString(),items:[gt(t)]})},{id:"cut",label:"Cut",description:"Move this event by pasting it into another day.",icon:Ut,onSelect:()=>m({id:`clipboard_cut_${t.id}_${Date.now()}`,mode:"cut",source:"calendar",label:t.title,createdAt:new Date().toISOString(),items:[gt(t)]})},{id:"delete",label:"Delete",description:"Remove the event from Forge and delete any connected remote projection.",icon:ze,tone:"danger",onSelect:()=>{(v==null?void 0:v.mode)==="cut"&&q.some(r=>r.eventId===t.id)&&N(),Oe.mutateAsync(t.id)}}]:[]},[N,q,v,Ae,Oe,De,k,f.events,f.workBlockTemplates,L,m]);return X.isLoading?e.jsx(oa,{}):X.isError||!X.data?e.jsx(da,{eyebrow:"Calendar",error:X.error??new Error("Calendar data is unavailable"),onRetry:()=>void X.refetch()}):e.jsxs("div",{className:"grid gap-5",children:[e.jsx(fa,{entityKind:"project",titleText:"Calendar",title:"Calendar",description:"See the real week first, then open guided flows for work blocks, task rules, timeboxing, and provider setup.",badge:`${f.connections.length} connection${f.connections.length===1?"":"s"}`}),(Xe=B.data)!=null&&Xe.lifeForce?e.jsxs(Z,{className:"grid gap-3 rounded-[28px] border border-white/8 bg-[linear-gradient(180deg,rgba(15,25,36,0.98),rgba(9,15,26,0.96))] p-4 md:grid-cols-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/40",children:"Life Force today"}),e.jsxs("div",{className:"mt-2 text-3xl font-semibold text-white",children:[Math.round(B.data.lifeForce.spentTodayAp),e.jsxs("span",{className:"ml-2 text-lg text-white/44",children:["/ ",Math.round(B.data.lifeForce.dailyBudgetAp)," AP"]})]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/40",children:"Instant headroom"}),e.jsxs("div",{className:"mt-2 text-2xl font-semibold text-[var(--primary)]",children:[B.data.lifeForce.instantFreeApPerHour.toFixed(1)," AP/h"]}),e.jsx("div",{className:"mt-2 text-sm text-white/58",children:"Calendar containers now speak the same AP language as live work."})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/40",children:"Forecast"}),e.jsxs("div",{className:"mt-2 text-2xl font-semibold text-white",children:[Math.round(B.data.lifeForce.forecastAp)," AP"]}),e.jsxs("div",{className:"mt-2 text-sm text-white/58",children:["Planned remaining ",ce(B.data.lifeForce.plannedRemainingAp)]})]})]}):null,e.jsxs(Z,{className:"grid gap-4 rounded-[32px] border border-white/8 bg-[linear-gradient(180deg,rgba(17,28,39,0.985),rgba(10,17,29,0.985))]",children:[e.jsx(xa,{description:"The calendar is the priority surface here. Connected provider events, recurring work blocks, and owned task timeboxes all stay visible together.",weekStart:c,status:Pe?e.jsx("div",{className:`inline-flex max-w-full items-center gap-2 rounded-full px-3 py-1.5 text-xs ${Pe.tone==="error"?"border border-rose-400/20 bg-rose-400/10 text-rose-200":"border border-[var(--primary)]/18 bg-[var(--primary)]/12 text-[var(--primary)]"}`,children:Pe.message}):null,badges:e.jsxs(e.Fragment,{children:[(Je=B.data)!=null&&Je.lifeForce?e.jsxs(S,{className:"bg-white/[0.08] text-white/74",children:[Math.round(B.data.lifeForce.spentTodayAp),"/",Math.round(B.data.lifeForce.dailyBudgetAp)," AP"]}):null,It?e.jsxs(S,{className:"bg-white/[0.08] text-white/78",children:[e.jsx(at,{className:"mr-1 size-3.5 animate-spin"}),"Syncing changes"]}):null,v?e.jsxs(S,{className:"bg-white/[0.08] text-white/74",children:[v.mode==="cut"?"Cut":"Copied"," · ",v.label]}):null]}),onPrevious:()=>A(Le(c,-7)),onCurrent:()=>A(_e()),onNext:()=>A(Le(c,7))}),e.jsx("div",{className:"grid gap-3 [grid-template-columns:repeat(auto-fit,minmax(min(100%,17rem),1fr))] 2xl:[grid-template-columns:repeat(7,minmax(0,1fr))]",children:Ae.map(t=>{const r=t.toISOString().slice(0,10),l=f.events.filter(i=>i.startAt.slice(0,10)===r&&!i.deletedAt),T=f.workBlockInstances.filter(i=>i.dateKey===r),O=f.timeboxes.filter(i=>i.startsAt.slice(0,10)===r);return e.jsxs("div",{"data-calendar-day":r,onClick:i=>{i.target.closest("[data-calendar-item='true']")||pe({kind:"day",dayKey:r,position:{x:i.clientX,y:i.clientY}})},onDragOver:i=>{i.preventDefault()},onDrop:i=>{i.preventDefault();const h=i.dataTransfer.getData("text/forge-event-id")||g;if(h){const Q=f.events.find(Se=>Se.id===h);Q&&zt(Q,t),o(null);return}const C=i.dataTransfer.getData("text/forge-timebox-id")||u;if(!C)return;const U=f.timeboxes.find(Q=>Q.id===C);if(!U)return;const W=new Date(U.startsAt),V=new Date(U.endsAt).getTime()-W.getTime(),D=new Date(t);D.setUTCHours(W.getUTCHours(),W.getUTCMinutes(),0,0);const I=new Date(D.getTime()+V);St.mutateAsync({timeboxId:C,startsAt:D.toISOString(),endsAt:I.toISOString()}),s(null)},className:"min-w-0 overflow-hidden rounded-[24px] border border-white/6 bg-white/[0.03] p-3 transition hover:border-white/12 hover:bg-white/[0.045]",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3 rounded-[18px] bg-[rgba(10,16,30,0.96)] px-3 py-2 text-sm font-medium text-white",children:[e.jsx("span",{className:"min-w-0 truncate",children:Re(t)}),e.jsx("button",{type:"button","aria-label":`Open actions for ${Re(t)}`,className:"rounded-full bg-white/[0.06] p-2 text-white/58 transition hover:bg-white/[0.1] hover:text-white",onClick:i=>{i.stopPropagation(),pe({kind:"day",dayKey:r,position:{x:i.clientX,y:i.clientY}})},children:e.jsx($e,{className:"size-4"})})]}),e.jsxs("div",{className:"mt-3 grid min-w-0 gap-2",children:[T.map(i=>e.jsxs("div",{"data-calendar-item":"true",className:"min-w-0 overflow-hidden rounded-[18px] px-3 py-2 text-sm text-white",style:{backgroundColor:`${i.color}22`,border:`1px solid ${i.color}55`},children:[(()=>{const h=ca(i);return e.jsxs("div",{className:"flex min-w-0 items-start justify-between gap-2",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"min-w-0 [overflow-wrap:anywhere] font-medium",children:i.title}),e.jsxs("div",{className:"mt-1 flex min-w-0 flex-wrap items-center gap-1.5",children:[e.jsx(S,{size:"sm",className:"shrink-0 bg-white/[0.08] text-white/78",children:i.blockingState}),e.jsx(S,{size:"sm",className:"shrink-0 bg-white/[0.08] text-white/78",children:xt(i.kind)}),h.rateApPerHour>0?e.jsxs(e.Fragment,{children:[e.jsx(S,{size:"sm",className:"shrink-0 bg-[var(--primary)]/14 text-[var(--primary)]",children:ee(h.rateApPerHour)}),e.jsx(S,{size:"sm",className:"shrink-0 bg-white/[0.08] text-white/72",children:ce(h.totalAp)})]}):e.jsx(S,{size:"sm",className:"shrink-0 bg-emerald-400/12 text-emerald-100",children:"Recovery"})]})]}),e.jsx("button",{type:"button","aria-label":`Open actions for ${i.title}`,className:"rounded-full bg-white/[0.05] p-1.5 text-white/56 transition hover:bg-white/[0.1] hover:text-white",onClick:C=>{C.stopPropagation(),pe({kind:"work-block",templateId:i.templateId,position:{x:C.clientX,y:C.clientY}})},children:e.jsx($e,{className:"size-4"})})]})})(),e.jsxs("div",{className:"mt-1 text-white/60",children:[new Date(i.startAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})," ","-"," ",new Date(i.endAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})]}),e.jsx("div",{className:"mt-2 text-xs text-white/48",children:yt(f.workBlockTemplates.find(h=>h.id===i.templateId)??{id:i.templateId,title:i.title,kind:i.kind,color:i.color,startsOn:null,endsOn:null,blockingState:i.blockingState,createdAt:i.createdAt,updatedAt:i.updatedAt})})]},i.id)),l.map(i=>e.jsxs("div",{"data-calendar-item":"true",draggable:!0,onDragStart:h=>{o(i.id),h.dataTransfer.setData("text/forge-event-id",i.id)},onClick:h=>{h.stopPropagation(),re(i),se(null),ie(!0)},className:`min-w-0 cursor-move overflow-hidden rounded-[18px] px-3 py-2 text-left text-sm text-white/82 transition ${he.useCalendarColors?"hover:brightness-110":"border border-white/10 bg-white/[0.05] hover:border-white/18 hover:bg-white/[0.08] hover:shadow-[0_12px_32px_rgba(4,9,20,0.22)]"}`,style:he.useCalendarColors?{backgroundColor:`${(i.calendarId?Fe[i.calendarId]:null)??lt(`origin:${i.originType}`)}1f`,border:`1px solid ${(i.calendarId?Fe[i.calendarId]:null)??lt(`origin:${i.originType}`)}55`}:void 0,children:[(be(i),e.jsxs("div",{className:"flex min-w-0 items-start justify-between gap-2",children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"line-clamp-2 [overflow-wrap:anywhere] font-medium",children:i.title}),e.jsxs("div",{className:"mt-1 text-white/55",children:[new Date(i.startAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})," ","-"," ",new Date(i.endAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})]})]}),e.jsx("div",{className:"flex shrink-0 items-center gap-1.5",children:e.jsx("button",{type:"button","aria-label":`Open quick actions for ${i.title}`,className:"rounded-full bg-white/[0.05] p-1.5 text-white/56 transition hover:bg-white/[0.1] hover:text-white",onClick:h=>{h.stopPropagation(),pe({kind:"event",eventId:i.id,position:{x:h.clientX,y:h.clientY}})},children:e.jsx($e,{className:"size-4"})})})]})),e.jsxs("div",{className:"mt-2 flex min-w-0 flex-wrap items-center gap-1.5",children:[e.jsx(S,{size:"sm",className:"max-w-full bg-white/[0.08] px-2 py-0.5 text-[10px] uppercase tracking-[0.14em] text-white/70",children:Pa(i,Ct)}),be(i).rateApPerHour>0?e.jsxs(e.Fragment,{children:[e.jsx(S,{size:"sm",className:"bg-[var(--primary)]/14 px-2 py-0.5 text-[10px] uppercase tracking-[0.14em] text-[var(--primary)]",children:ee(be(i).rateApPerHour)}),e.jsx(S,{size:"sm",className:"bg-white/[0.08] px-2 py-0.5 text-[10px] uppercase tracking-[0.14em] text-white/70",children:ce(be(i).totalAp)})]}):null,i.calendarId&&he.useCalendarColors?e.jsx("span",{"aria-hidden":"true",className:"size-2.5 shrink-0 rounded-full",style:{backgroundColor:Fe[i.calendarId]}}):null]}),i.place.address||i.place.timezone?e.jsxs("div",{className:"mt-2 text-xs leading-5 text-white/50",children:[i.place.address||i.location,i.place.address&&i.place.timezone?" · ":"",i.place.timezone]}):null,i.links.length>0?e.jsx("div",{className:"mt-2 flex min-w-0 flex-wrap gap-1.5",children:i.links.slice(0,3).map(h=>{const C=bt(h.entityType);return C?e.jsx(Be,{kind:C,label:Ot.get(`${h.entityType}:${h.entityId}`)??h.entityType,compact:!0,gradient:!1},h.id):e.jsx(S,{className:"bg-white/[0.08] text-white/72",children:h.entityType},h.id)})}):null]},i.id)),O.map(i=>e.jsxs("div",{"data-calendar-item":"true",draggable:!0,onDragStart:h=>{s(i.id),h.dataTransfer.setData("text/forge-timebox-id",i.id)},onClick:()=>{ue(i),ae(!0)},className:"min-w-0 cursor-move overflow-hidden rounded-[18px] border border-[rgba(192,193,255,0.18)] bg-[linear-gradient(180deg,rgba(67,72,112,0.34),rgba(43,47,80,0.32))] px-3 py-2 text-left text-sm text-white/82 shadow-[inset_0_0_0_1px_rgba(192,193,255,0.08)] transition hover:border-[rgba(192,193,255,0.32)] hover:bg-[linear-gradient(180deg,rgba(74,79,122,0.4),rgba(48,53,92,0.36))]",children:[(()=>{const h=ma(i);return e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"flex min-w-0 items-start justify-between gap-2",children:e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"line-clamp-2 font-medium leading-5 text-white",children:i.title}),e.jsxs("div",{className:"mt-1 flex items-center gap-2 text-white/58",children:[e.jsx(Wt,{className:"size-3.5 shrink-0"}),new Date(i.startsAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})," ","-"," ",new Date(i.endsAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})]})]})}),e.jsxs("div",{className:"mt-2 flex min-w-0 flex-wrap items-center gap-1.5",children:[e.jsx(S,{size:"sm",className:"bg-white/[0.08] px-2 py-0.5 text-[10px] uppercase tracking-[0.14em] text-white/72",children:i.status}),e.jsx(S,{size:"sm",className:"bg-[var(--primary)]/14 px-2 py-0.5 text-[10px] uppercase tracking-[0.14em] text-[var(--primary)]",children:ee(h.rateApPerHour)}),e.jsx(S,{size:"sm",className:"bg-white/[0.08] px-2 py-0.5 text-[10px] uppercase tracking-[0.14em] text-white/72",children:ce(h.totalAp)})]})]})})(),e.jsxs("div",{className:"mt-2 flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:h=>{h.stopPropagation(),ue(i),ae(!0)},className:"rounded-[999px] bg-white/[0.08] px-2.5 py-1 text-[10px] uppercase tracking-[0.14em] text-white/78 transition hover:bg-white/[0.14]",children:"Edit"}),e.jsx("button",{type:"button",onClick:h=>{h.stopPropagation(),a(`/tasks/${i.taskId}`)},className:"rounded-[999px] bg-white/[0.08] px-2.5 py-1 text-[10px] uppercase tracking-[0.14em] text-white/78 transition hover:bg-white/[0.14]",children:"Open task"})]})]},i.id)),T.length===0&&l.length===0&&O.length===0?e.jsx("div",{className:"min-h-[10rem] rounded-[18px] border border-dashed border-white/8 px-3 py-4 text-sm leading-8 text-white/42",children:"Nothing scheduled here yet. Click inside this day to create, block, or paste."}):null]})]},r)})})]}),e.jsxs("section",{className:"grid gap-5 xl:grid-cols-[minmax(0,1.2fr)_minmax(0,0.8fr)]",children:[e.jsxs("div",{className:"grid gap-4 md:grid-cols-3",children:[e.jsxs(Z,{className:"rounded-[28px] border border-white/8 bg-[linear-gradient(180deg,rgba(18,28,38,0.98),rgba(11,17,28,0.98))]",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"rounded-[18px] bg-[var(--primary)]/14 p-3 text-[var(--primary)]",children:e.jsx(oe,{className:"size-4"})}),e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:"Create event"}),e.jsx("div",{className:"mt-1 text-sm text-white/56",children:"Add a native Forge event with linked context."})]})]}),e.jsx("p",{className:"mt-4 text-sm leading-6 text-white/62",children:"Create a real calendar event even with no provider connected, then project it remotely whenever you choose."}),e.jsx("div",{className:"mt-4",children:e.jsxs(G,{onClick:()=>{R(null),re(null),se(null),ie(!0)},children:[e.jsx(oe,{className:"size-4"}),"Open event guide"]})})]}),e.jsxs(Z,{className:"rounded-[28px] border border-white/8 bg-[linear-gradient(180deg,rgba(18,28,38,0.98),rgba(11,17,28,0.98))]",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"rounded-[18px] bg-[var(--primary)]/14 p-3 text-[var(--primary)]",children:e.jsx(Me,{className:"size-4"})}),e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:"Create work block"}),e.jsx("div",{className:"mt-1 text-sm text-white/56",children:"Block main activity or protect creative windows."})]})]}),e.jsx("p",{className:"mt-4 text-sm leading-6 text-white/62",children:"Open the guided flow to create half-day presets, holidays, or custom recurring work blocks."}),e.jsx("div",{className:"mt-4",children:e.jsxs(G,{onClick:()=>{R(null),M(!0)},children:[e.jsx(Me,{className:"size-4"}),"Open work-block guide"]})})]}),e.jsxs(Z,{className:"rounded-[28px] border border-white/8 bg-[linear-gradient(180deg,rgba(18,28,38,0.98),rgba(11,17,28,0.98))]",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"rounded-[18px] bg-[var(--primary)]/14 p-3 text-[var(--primary)]",children:e.jsx(He,{className:"size-4"})}),e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:"Plan timebox"}),e.jsx("div",{className:"mt-1 text-sm text-white/56",children:"Let Forge recommend valid upcoming slots."})]})]}),e.jsx("p",{className:"mt-4 text-sm leading-6 text-white/62",children:"Choose a task, review the suggested windows, and schedule directly into the calendar."}),e.jsx("div",{className:"mt-4",children:e.jsxs(G,{onClick:()=>ae(!0),children:[e.jsx(He,{className:"size-4"}),"Open planning guide"]})})]}),e.jsxs(Z,{className:"rounded-[28px] border border-white/8 bg-[linear-gradient(180deg,rgba(18,28,38,0.98),rgba(11,17,28,0.98))]",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"rounded-[18px] bg-[var(--primary)]/14 p-3 text-[var(--primary)]",children:e.jsx(it,{className:"size-4"})}),e.jsxs("div",{children:[e.jsx("div",{className:"font-medium text-white",children:"Manage provider settings"}),e.jsx("div",{className:"mt-1 text-sm text-white/56",children:Ft})]})]}),e.jsx("p",{className:"mt-4 text-sm leading-6 text-white/62",children:"Provider connections and setup instructions now live in Settings so the calendar view can stay focused on the week."}),e.jsxs("div",{className:"mt-4 flex flex-wrap gap-2",children:[e.jsxs(G,{variant:"secondary",onClick:()=>a("/settings/calendar"),children:[e.jsx(Qt,{className:"size-4"}),"Open calendar settings"]}),e.jsxs(G,{variant:"secondary",onClick:()=>a("/settings/calendar?intent=connect"),children:[e.jsx(it,{className:"size-4"}),"Connect provider"]})]})]})]}),e.jsxs("div",{className:"grid gap-4",children:[e.jsxs(Z,{className:"rounded-[28px] border border-white/8 bg-[linear-gradient(180deg,rgba(18,28,38,0.98),rgba(11,17,28,0.98))]",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/45",children:"This week"}),e.jsx("p",{className:"mt-2 text-sm leading-6 text-white/60",children:"Quick status for the currently visible week."})]}),e.jsxs(G,{variant:"secondary",onClick:()=>void X.refetch(),children:[e.jsx(at,{className:"size-4"}),"Refresh view"]})]}),e.jsxs("div",{className:"mt-4 grid gap-3 sm:grid-cols-3",children:[e.jsxs("div",{className:"rounded-[22px] bg-white/[0.04] px-4 py-4",children:[e.jsx("div",{className:"text-sm text-white/54",children:"Provider events"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:f.events.length})]}),e.jsxs("div",{className:"rounded-[22px] bg-white/[0.04] px-4 py-4",children:[e.jsx("div",{className:"text-sm text-white/54",children:"Work blocks"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:f.workBlockInstances.length})]}),e.jsxs("div",{className:"rounded-[22px] bg-white/[0.04] px-4 py-4",children:[e.jsx("div",{className:"text-sm text-white/54",children:"Planned timeboxes"}),e.jsx("div",{className:"mt-2 font-display text-3xl text-white",children:Pt.length})]})]})]}),e.jsxs(Z,{className:"rounded-[28px] border border-white/8 bg-[linear-gradient(180deg,rgba(18,28,38,0.98),rgba(11,17,28,0.98))]",children:[e.jsx("div",{className:"text-[11px] uppercase tracking-[0.18em] text-white/45",children:"Guided actions"}),e.jsxs("div",{className:"mt-3 grid gap-3",children:[e.jsxs("button",{type:"button",onClick:()=>me(!0),className:"rounded-[22px] border border-white/8 bg-white/[0.04] px-4 py-4 text-left transition hover:bg-white/[0.06]",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("div",{className:"font-medium text-white",children:"Adjust task blocking rules"}),e.jsx(S,{className:"bg-white/[0.08] text-white/74",children:"Guided"})]}),e.jsx("div",{className:"mt-2 text-sm leading-6 text-white/58",children:"Decide which work blocks, calendar conditions, and event keywords should block or allow a task."})]}),e.jsxs("div",{className:"rounded-[22px] border border-white/8 bg-white/[0.04] px-4 py-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("div",{className:"font-medium text-white",children:"Active templates"}),e.jsx(S,{className:"bg-white/[0.08] text-white/74",children:f.workBlockTemplates.length})]}),e.jsxs("div",{className:"mt-3 grid gap-2",children:[f.workBlockTemplates.slice(0,4).map(t=>e.jsxs("div",{className:"rounded-[18px] bg-white/[0.04] px-3 py-3 text-sm text-white/74",children:[e.jsx("div",{className:"font-medium text-white",children:t.title}),e.jsxs("div",{className:"mt-1 text-white/56",children:[xt(t.kind)," · ",t.weekDays.length," day",t.weekDays.length===1?"":"s"," · ",t.blockingState]}),e.jsx("div",{className:"mt-1 text-white/46",children:yt(t)}),e.jsxs("div",{className:"mt-3 flex flex-wrap gap-2",children:[e.jsxs(G,{variant:"secondary",size:"sm",onClick:()=>{R(t),M(!0)},children:[e.jsx(oe,{className:"size-3.5"}),"Edit"]}),e.jsxs(G,{variant:"secondary",size:"sm",onClick:()=>void De.mutateAsync(t.id),children:[e.jsx(ze,{className:"size-3.5"}),"Delete"]})]})]},t.id)),f.workBlockTemplates.length===0?e.jsx("div",{className:"text-sm text-white/52",children:"No recurring templates yet. Open the work-block guide to create the first one."}):null]})]})]})]})]})]}),e.jsx(Ta,{open:_,onOpenChange:t=>{M(t),t||R(null)},pending:qe.isPending||Ze.isPending,template:L,onSubmit:async t=>{if(L){await Ze.mutateAsync({templateId:L.id,patch:t});return}await qe.mutateAsync(t)}}),e.jsx(ya,{open:te,onOpenChange:me,tasks:w.snapshot.tasks,onSave:async({taskId:t,schedulingRules:r,plannedDurationSeconds:l})=>{await ua(t,{schedulingRules:r,plannedDurationSeconds:l}),await w.refresh(),await E(),await b.invalidateQueries({queryKey:["task-context",t]})}}),e.jsx(ba,{open:Te,onOpenChange:Et,tasks:w.snapshot.tasks,editingTimebox:Y,from:H.from,to:H.to,onCreateTimebox:async t=>{await At.mutateAsync(t)},onUpdateTimebox:async(t,r)=>{await Nt.mutateAsync({timeboxId:t,patch:r})},onDeleteTimebox:async t=>{await Tt.mutateAsync(t),Ge()}}),e.jsx(Sa,{open:kt,onOpenChange:t=>{ie(t),t||(re(null),se(null))},writableCalendars:Dt,linkOptions:Ee,event:Ce,seed:jt??void 0,onSubmit:async t=>{if(Ce){const r=Ce.id;ie(!1),re(null),se(null),J.mutateAsync({eventId:r,patch:t}).catch(()=>{});return}else{ie(!1),re(null),se(null),ke.mutateAsync(t).catch(()=>{});return}},pending:ke.isPending||J.isPending}),e.jsx(Na,{open:ne!==null,onOpenChange:t=>{t||Ie(null)},initialTitle:(ne==null?void 0:ne.title)??"",pending:J.isPending,onSubmit:async t=>{if(!ne)return;const r=ne.id;Ie(null),J.mutateAsync({eventId:r,patch:{title:t}}).catch(()=>{})}}),e.jsx(ka,{open:k!==null,title:(k==null?void 0:k.kind)==="event"?((Ve=f.events.find(t=>t.id===k.eventId))==null?void 0:Ve.title)??"Event actions":(k==null?void 0:k.kind)==="work-block"?((et=f.workBlockTemplates.find(t=>t.id===k.templateId))==null?void 0:et.title)??"Work block actions":(k==null?void 0:k.kind)==="day"?Re(Ae.find(t=>t.toISOString().slice(0,10)===k.dayKey)??c):"Calendar actions",subtitle:(k==null?void 0:k.kind)==="day"?"Choose what to create or paste into this day.":(k==null?void 0:k.kind)==="work-block"?"Edit or remove this recurring work block.":v?`Clipboard ready: ${v.label}`:"Quick calendar event actions.",items:_t,position:(k==null?void 0:k.position)??null,onClose:()=>pe(null)})]})}export{Qa as CalendarPage};