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.
- package/dist/assets/activity-page-Dv6X5ZCV.js +1 -0
- package/dist/assets/{ai-surface-workspace-xtB5RFQu.js → ai-surface-workspace-CutiG6uS.js} +1 -1
- package/dist/assets/{atlas-panel-B3dPHCmZ.js → atlas-panel-jgMRyaHn.js} +1 -1
- package/dist/assets/{board-DqHzdCPQ.js → board-dIX6etHh.js} +1 -1
- package/dist/assets/calendar-page-q7Nm5E2U.js +1 -0
- package/dist/assets/calendar-rules-DPFsfiRl.js +1 -0
- package/dist/assets/{calendar-week-toolbar-BZ_-X3Wb.js → calendar-week-toolbar-nVhgB-0s.js} +1 -1
- package/dist/assets/{charts-FcU0F3XV.js → charts-DFnEuIMB.js} +1 -1
- package/dist/assets/companion-sync-lab-page-CJ8UTij8.js +1 -0
- package/dist/assets/{daily-metrics-dashboard-BMyL0Qr4.js → daily-metrics-dashboard-CiJkkkd1.js} +1 -1
- package/dist/assets/entity-note-count-link-RzBB6ujx.js +1 -0
- package/dist/assets/{entity-notes-surface-CBylYDwy.js → entity-notes-surface-Djz50HvD.js} +1 -1
- package/dist/assets/execution-board-CtPhI-58.js +1 -0
- package/dist/assets/{faceted-token-search-D7xPWfOl.js → faceted-token-search-DEC6ANa9.js} +1 -1
- package/dist/assets/{flagship-signal-deck-BEFKOhvx.js → flagship-signal-deck-CtHC3mql.js} +1 -1
- package/dist/assets/floating-action-menu-CKQRhff9.js +1 -0
- package/dist/assets/{forms-CmLAyGqz.js → forms-hB0SqEh-.js} +1 -1
- package/dist/assets/goal-detail-page-CF5fNQeR.js +1 -0
- package/dist/assets/goals-page-fsY8NzGB.js +1 -0
- package/dist/assets/{graph-BTa79qum.js → graph-DDUZNRsO.js} +1 -1
- package/dist/assets/habits-page-COoGz4kj.js +1 -0
- package/dist/assets/index-BAXYM89v.css +1 -0
- package/dist/assets/index-EqQsXoat.js +19 -0
- package/dist/assets/{insight-flow-dialog-BtIQXXsS.js → insight-flow-dialog-DtX_5W7g.js} +1 -1
- package/dist/assets/insights-page-cBd74ObU.js +8 -0
- package/dist/assets/kanban-page-CYav9THw.js +1 -0
- package/dist/assets/knowledge-graph-page-D2A-W1jE.js +1 -0
- package/dist/assets/{life-force-page-BGDkKfbJ.js → life-force-page-CACGlNhq.js} +1 -1
- package/dist/assets/life-force-workspace-BJ4N1I78.js +1 -0
- package/dist/assets/{maps-CF1RagUX.js → maps-C-yOWiDN.js} +1 -1
- package/dist/assets/{metric-tile-4iMd_WnJ.js → metric-tile-CMadwnGz.js} +1 -1
- package/dist/assets/{motion-CfdU2F35.js → motion-Lt5B1XuE.js} +1 -1
- package/dist/assets/movement-page-D5VqFd2q.js +1 -0
- package/dist/assets/{note-markdown-CsGQhQXF.js → note-markdown-BzK2Qlgr.js} +1 -1
- package/dist/assets/{note-tags-input-DdZi93tj.js → note-tags-input-CZzqJMLc.js} +1 -1
- package/dist/assets/notes-page-D3Hsh90C.js +1 -0
- package/dist/assets/{open-in-graph-button-C0TGev7c.js → open-in-graph-button-BFPKfyK3.js} +1 -1
- package/dist/assets/{orbit-map-DVXkfQdd.js → orbit-map-CnyfSmOG.js} +1 -1
- package/dist/assets/{overview-page-BwMlFQKX.js → overview-page-CXdWrOV1.js} +1 -1
- package/dist/assets/{page-hero-oFHaAjtL.js → page-hero-ffKzgyW3.js} +1 -1
- package/dist/assets/pill-cluster-C2D0h3lx.js +1 -0
- package/dist/assets/{preference-entity-handoff-button-DOKV9bZc.js → preference-entity-handoff-button-Dj3V6VxL.js} +1 -1
- package/dist/assets/preferences-page-Jo8Gw386.js +1 -0
- package/dist/assets/project-collections-qSqp90HN.js +1 -0
- package/dist/assets/{project-detail-page-DogvVNEn.js → project-detail-page-BifhiLQX.js} +1 -1
- package/dist/assets/project-management-hierarchy-page-DZ_9klIc.js +1 -0
- package/dist/assets/project-management-section-nav-BImLCVvf.js +1 -0
- package/dist/assets/projects-page-ptcx6H38.js +1 -0
- package/dist/assets/{psyche-behaviors-page-BeVlXvbj.js → psyche-behaviors-page-BDwXyDta.js} +1 -1
- package/dist/assets/{psyche-flashcards-page-CqAWCO4E.js → psyche-flashcards-page-DL1BP1jX.js} +1 -1
- package/dist/assets/{psyche-goal-map-page-IyNnbk_W.js → psyche-goal-map-page-ovcpisx1.js} +1 -1
- package/dist/assets/{psyche-graph-IkUQRaDK.js → psyche-graph-EP5GL612.js} +1 -1
- package/dist/assets/{psyche-metrics-page-uai0a7Lx.js → psyche-metrics-page-Bcu813Rg.js} +1 -1
- package/dist/assets/{psyche-mode-guide-page-C7p-ABiF.js → psyche-mode-guide-page-C0g27Xpt.js} +1 -1
- package/dist/assets/{psyche-modes-page-CLQ5V3w0.js → psyche-modes-page-BjKjX5MR.js} +1 -1
- package/dist/assets/{psyche-page-NQBHkkpU.js → psyche-page-F4tF2W70.js} +1 -1
- package/dist/assets/{psyche-patterns-page-BkRiNpI_.js → psyche-patterns-page-B-14hukK.js} +1 -1
- package/dist/assets/{psyche-questionnaire-builder-page-Du-7HwPC.js → psyche-questionnaire-builder-page-BdXmoHvK.js} +1 -1
- package/dist/assets/{psyche-questionnaire-detail-page-C5-yf8MF.js → psyche-questionnaire-detail-page-Cu5uwlJu.js} +1 -1
- package/dist/assets/{psyche-questionnaire-run-detail-page-CoSH5O6R.js → psyche-questionnaire-run-detail-page-C3R4PClg.js} +1 -1
- package/dist/assets/{psyche-questionnaire-run-page-ChI7c1wy.js → psyche-questionnaire-run-page-Div3iDdt.js} +1 -1
- package/dist/assets/{psyche-questionnaires-page-xUcJJzbI.js → psyche-questionnaires-page-DpqAPQCp.js} +1 -1
- package/dist/assets/{psyche-report-detail-page-BPrZCFZS.js → psyche-report-detail-page-BvWVDKP3.js} +1 -1
- package/dist/assets/{psyche-reports-page-D2EXJmm6.js → psyche-reports-page-BrbWUlAq.js} +1 -1
- package/dist/assets/{psyche-schemas-RcZYaokx.js → psyche-schemas-Dxj554nU.js} +1 -1
- package/dist/assets/{psyche-schemas-beliefs-page-h0ooZ1lp.js → psyche-schemas-beliefs-page-DYKvAtSD.js} +1 -1
- package/dist/assets/{psyche-screen-time-page-_3-4LikV.js → psyche-screen-time-page-CAOKCyQw.js} +1 -1
- package/dist/assets/{psyche-self-observation-page-BdbCsgR5.js → psyche-self-observation-page-F0MVA0UH.js} +1 -1
- package/dist/assets/{psyche-values-page-DuUVki5e.js → psyche-values-page-DyvX-d0o.js} +1 -1
- package/dist/assets/{report-chain-fields-BBMz0sGI.js → report-chain-fields-CeC1cJFS.js} +1 -1
- package/dist/assets/rewards-page-C2loyODo.js +1 -0
- package/dist/assets/scheduling-rules-editor-D40AC2jR.js +1 -0
- package/dist/assets/{schema-badge-D93RcG36.js → schema-badge-FY7818qB.js} +1 -1
- package/dist/assets/{select-menu-Cdq7foRu.js → select-menu-DJsCG6rM.js} +1 -1
- package/dist/assets/settings-agents-page-BFkJ5AAD.js +6 -0
- package/dist/assets/settings-bin-page-D3-Ab-iA.js +1 -0
- package/dist/assets/settings-calendar-page-ly_mSTAD.js +5 -0
- package/dist/assets/settings-data-page-D7QOqNf-.js +1 -0
- package/dist/assets/settings-logs-page-Ca87HEUx.js +1 -0
- package/dist/assets/settings-mobile-page-D0jejZot.js +1 -0
- package/dist/assets/settings-models-page-DPDsZjSc.js +1 -0
- package/dist/assets/settings-page-1cArlSPM.js +1 -0
- package/dist/assets/settings-rewards-page-Db4BV1DC.js +1 -0
- package/dist/assets/{settings-section-nav-Dc4IeVBt.js → settings-section-nav-DP9o4peU.js} +1 -1
- package/dist/assets/settings-users-page-BHFyDSsd.js +1 -0
- package/dist/assets/settings-wiki-page-BNaiupBm.js +1 -0
- package/dist/assets/sleep-page-BmOPF0yD.js +1 -0
- package/dist/assets/sports-page-BldIiclr.js +1 -0
- package/dist/assets/{state-VYvD1QVP.js → state-vCcAT5Hq.js} +1 -1
- package/dist/assets/strategies-page-CaTN99qj.js +1 -0
- package/dist/assets/strategy-detail-page-DsgFTd-U.js +1 -0
- package/dist/assets/{strategy-dialog-DMyRKrWf.js → strategy-dialog-7X7peRzu.js} +1 -1
- package/dist/assets/{surface-Bfz_sLX6.js → surface-CJI17F3n.js} +1 -1
- package/dist/assets/{table-C0VTeqw0.js → table-BNqMG3_S.js} +1 -1
- package/dist/assets/task-detail-page-M1sIIPA8.js +1 -0
- package/dist/assets/timebox-planning-dialog-ByojN0AN.js +1 -0
- package/dist/assets/today-page-BjDijtn8.js +1 -0
- package/dist/assets/training-load-page-BPRmaWmF.js +1 -0
- package/dist/assets/{ui-CsEkP2V8.js → ui-C1iwpj2-.js} +1 -1
- package/dist/assets/{use-psyche-focus-target-qxT5Oy_z.js → use-psyche-focus-target-Ct-acS9G.js} +1 -1
- package/dist/assets/{vendor-kIz9EZnX.js → vendor-Dnkkx2co.js} +3 -3
- package/dist/assets/{vitals-page-Dz1Jt5H8.js → vitals-page-CE9zdGLF.js} +1 -1
- package/dist/assets/weekly-review-page-CzhTv90n.js +1 -0
- package/dist/assets/weight-loss-page-Bp_cIk78.js +5 -0
- package/dist/assets/wiki-article-markdown-Dok2uy2p.js +4 -0
- package/dist/assets/wiki-editor-page-BuW32Y3f.js +26 -0
- package/dist/assets/wiki-ingest-history-page-DZKSBNHV.js +1 -0
- package/dist/assets/wiki-ingest-modal-DyqBEZcC.js +1 -0
- package/dist/assets/wiki-page-DqxlbLKG.js +1 -0
- package/dist/assets/workbench-flow-page-C4nc9jUg.js +5 -0
- package/dist/assets/workbench-page-BnyR7SL0.js +1 -0
- package/dist/assets/{workout-detail-page-DD9IGN6l.js → workout-detail-page-DT-c5cHL.js} +2 -2
- package/dist/index.html +9 -9
- package/dist/server/server/src/app.js +22 -3
- package/dist/server/server/src/health-weight-loss.js +114 -39
- package/dist/server/server/src/repositories/model-settings.js +9 -3
- package/dist/server/src/components/workbench-boxes/shared/generic-node-view.js +13 -5
- package/dist/server/src/lib/api.js +10 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/assets/activity-page-CgF7K2ww.js +0 -1
- package/dist/assets/calendar-page-C1Wfd2Fy.js +0 -1
- package/dist/assets/calendar-rules-CaZXtlxt.js +0 -1
- package/dist/assets/companion-sync-lab-page-NgeK-O-P.js +0 -1
- package/dist/assets/entity-note-count-link-BrS1-O0o.js +0 -1
- package/dist/assets/execution-board-CpO2ch6v.js +0 -1
- package/dist/assets/floating-action-menu-zzC2r0Ob.js +0 -1
- package/dist/assets/goal-detail-page-JK_Nva8e.js +0 -1
- package/dist/assets/goals-page-yeoJ06Vw.js +0 -1
- package/dist/assets/habits-page-Dx5EhkJi.js +0 -1
- package/dist/assets/index-BHIKoiZ6.js +0 -19
- package/dist/assets/index-H8R-ABM3.css +0 -1
- package/dist/assets/insights-page-CujrosD_.js +0 -8
- package/dist/assets/kanban-page-Q9NuIz5w.js +0 -1
- package/dist/assets/knowledge-graph-page-DaJmlvvM.js +0 -1
- package/dist/assets/life-force-workspace-CLVexVnb.js +0 -1
- package/dist/assets/movement-page-ClaoTNuX.js +0 -1
- package/dist/assets/notes-page-DYI8s3NN.js +0 -1
- package/dist/assets/pill-cluster-7UZd_lHp.js +0 -1
- package/dist/assets/preferences-page-BrKEkmfD.js +0 -1
- package/dist/assets/project-collections-CZagCmeH.js +0 -1
- package/dist/assets/project-management-hierarchy-page-Dr7hW9PW.js +0 -1
- package/dist/assets/project-management-section-nav-BLdAgTge.js +0 -1
- package/dist/assets/projects-page-UKrby_5-.js +0 -1
- package/dist/assets/rewards-page-PZFPa6rR.js +0 -1
- package/dist/assets/scheduling-rules-editor-B9KNKsQz.js +0 -1
- package/dist/assets/settings-agents-page-DPx2F6wf.js +0 -6
- package/dist/assets/settings-bin-page-COwP3gjo.js +0 -1
- package/dist/assets/settings-calendar-page-C-ghE0YT.js +0 -5
- package/dist/assets/settings-data-page-CBubzKBw.js +0 -1
- package/dist/assets/settings-logs-page-uOuXMeBm.js +0 -1
- package/dist/assets/settings-mobile-page-C5rfj8_r.js +0 -1
- package/dist/assets/settings-models-page-DijmUWdU.js +0 -1
- package/dist/assets/settings-page-B4u5TR5g.js +0 -1
- package/dist/assets/settings-rewards-page-COiTwkMH.js +0 -1
- package/dist/assets/settings-users-page-DEGa5DNn.js +0 -1
- package/dist/assets/settings-wiki-page-Cvsiz5_e.js +0 -1
- package/dist/assets/sleep-page-BnSOwkEU.js +0 -1
- package/dist/assets/sports-page-l1RqXzA_.js +0 -1
- package/dist/assets/strategies-page-DEnPlpAs.js +0 -1
- package/dist/assets/strategy-detail-page-Ls8bxKeH.js +0 -1
- package/dist/assets/task-detail-page-CgrYgQLD.js +0 -1
- package/dist/assets/timebox-planning-dialog-Ww0NGLLo.js +0 -1
- package/dist/assets/today-page-CIuFHMi1.js +0 -1
- package/dist/assets/training-load-page-BIwc648i.js +0 -1
- package/dist/assets/weekly-review-page-BFpBe1kI.js +0 -1
- package/dist/assets/weight-loss-page-BgMoBpBt.js +0 -5
- package/dist/assets/wiki-article-markdown-gsPTXTg1.js +0 -4
- package/dist/assets/wiki-editor-page-BpAZHooY.js +0 -26
- package/dist/assets/wiki-ingest-history-page-C-ig8O22.js +0 -1
- package/dist/assets/wiki-ingest-modal-BK4eQgqs.js +0 -1
- package/dist/assets/wiki-page-CMTZ60Zt.js +0 -1
- package/dist/assets/workbench-flow-page-BIpWUcLJ.js +0 -5
- 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
|
|
297
|
-
const start = new Date(
|
|
298
|
-
start.setUTCDate(
|
|
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 =
|
|
360
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
421
|
+
todayStepCaloriesForActiveBudget != null) {
|
|
383
422
|
return "today_workout_movement_step_energy";
|
|
384
423
|
}
|
|
385
|
-
if (todayWorkoutEnergy != null &&
|
|
424
|
+
if (todayWorkoutEnergy != null &&
|
|
425
|
+
todayStepCaloriesForActiveBudget != null) {
|
|
386
426
|
return "today_workout_step_energy";
|
|
387
427
|
}
|
|
388
|
-
if (todayMovementCalories != 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 (
|
|
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
|
|
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:
|
|
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,
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 [
|
|
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(
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
}
|
package/openclaw.plugin.json
CHANGED
|
@@ -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.
|
|
5
|
+
"version": "0.2.103",
|
|
6
6
|
"activation": {
|
|
7
7
|
"onStartup": true,
|
|
8
8
|
"onCapabilities": [
|
package/package.json
CHANGED
|
@@ -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};
|