forge-openclaw-plugin 0.2.24 → 0.2.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +13 -0
  2. package/dist/assets/{board-_C6oMy5w.js → board-ta0rUHOf.js} +3 -3
  3. package/dist/assets/{board-_C6oMy5w.js.map → board-ta0rUHOf.js.map} +1 -1
  4. package/dist/assets/index-Ro0ZF_az.css +1 -0
  5. package/dist/assets/index-ytlpSj23.js +79 -0
  6. package/dist/assets/index-ytlpSj23.js.map +1 -0
  7. package/dist/assets/{motion-D4sZgCHd.js → motion-fBKPB6yw.js} +3 -3
  8. package/dist/assets/motion-fBKPB6yw.js.map +1 -0
  9. package/dist/assets/{table-BWzTaky1.js → table-C-IGTQni.js} +2 -2
  10. package/dist/assets/{table-BWzTaky1.js.map → table-C-IGTQni.js.map} +1 -1
  11. package/dist/assets/{ui-BzK4azQb.js → ui-DInOpaYF.js} +2 -2
  12. package/dist/assets/{ui-BzK4azQb.js.map → ui-DInOpaYF.js.map} +1 -1
  13. package/dist/assets/vendor-lE3tZJcC.js +876 -0
  14. package/dist/assets/vendor-lE3tZJcC.js.map +1 -0
  15. package/dist/index.html +7 -8
  16. package/dist/openclaw/local-runtime.d.ts +3 -1
  17. package/dist/openclaw/local-runtime.js +51 -15
  18. package/dist/openclaw/parity.d.ts +1 -1
  19. package/dist/openclaw/parity.js +29 -0
  20. package/dist/openclaw/plugin-entry-shared.d.ts +1 -0
  21. package/dist/openclaw/plugin-entry-shared.js +31 -6
  22. package/dist/openclaw/plugin-sdk-types.d.ts +29 -0
  23. package/dist/openclaw/routes.js +236 -0
  24. package/dist/openclaw/session-bootstrap.d.ts +78 -0
  25. package/dist/openclaw/session-bootstrap.js +240 -0
  26. package/dist/openclaw/tools.js +279 -6
  27. package/dist/server/server/migrations/001_core.sql +411 -0
  28. package/dist/server/server/migrations/002_psyche.sql +392 -0
  29. package/dist/server/server/migrations/003_habits.sql +30 -0
  30. package/dist/server/server/migrations/004_habit_links.sql +8 -0
  31. package/dist/server/server/migrations/005_habit_psyche_links.sql +24 -0
  32. package/dist/server/server/migrations/006_work_adjustments.sql +14 -0
  33. package/dist/server/server/migrations/007_weekly_review_closures.sql +17 -0
  34. package/dist/server/server/migrations/008_calendar_execution.sql +147 -0
  35. package/dist/server/server/migrations/009_true_calendar_events.sql +195 -0
  36. package/dist/server/server/migrations/010_calendar_selection_state.sql +6 -0
  37. package/dist/server/server/migrations/011_calendar_timezone_backfill.sql +11 -0
  38. package/dist/server/server/migrations/012_work_block_ranges.sql +7 -0
  39. package/dist/server/server/migrations/013_microsoft_local_auth_settings.sql +8 -0
  40. package/dist/server/server/migrations/014_note_tags_and_ephemeral.sql +8 -0
  41. package/dist/server/server/migrations/015_multi_user_and_strategies.sql +244 -0
  42. package/dist/server/server/migrations/016_health_companion.sql +158 -0
  43. package/dist/server/server/migrations/016_strategy_contracts_and_user_graph.sql +22 -0
  44. package/dist/server/server/migrations/017_preferences.sql +131 -0
  45. package/dist/server/server/migrations/018_preference_catalogs.sql +31 -0
  46. package/dist/server/server/migrations/019_wiki_memory.sql +255 -0
  47. package/dist/server/server/migrations/020_wiki_page_hierarchy.sql +11 -0
  48. package/dist/server/server/migrations/021_hide_evidence_from_wiki_index.sql +3 -0
  49. package/dist/server/server/migrations/022_wiki_ingest_background.sql +85 -0
  50. package/dist/server/server/migrations/023_diagnostic_logs.sql +28 -0
  51. package/dist/server/server/migrations/024_questionnaires.sql +96 -0
  52. package/dist/server/server/migrations/025_ai_model_connections.sql +26 -0
  53. package/dist/server/server/migrations/026_custom_theme_settings.sql +2 -0
  54. package/dist/server/server/migrations/027_ai_processors.sql +31 -0
  55. package/dist/server/server/migrations/028_movement_domain.sql +136 -0
  56. package/dist/server/server/migrations/029_watch_micro_capture.sql +23 -0
  57. package/dist/server/server/migrations/030_surface_layouts.sql +5 -0
  58. package/dist/server/server/migrations/031_ai_processor_runtime_upgrades.sql +10 -0
  59. package/dist/server/server/migrations/032_ai_connectors.sql +44 -0
  60. package/dist/server/server/migrations/033_movement_trip_point_sync.sql +36 -0
  61. package/dist/server/server/migrations/034_movement_segment_sync.sql +49 -0
  62. package/dist/server/server/migrations/035_google_local_auth_settings.sql +2 -0
  63. package/dist/server/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  64. package/dist/server/{app.js → server/src/app.js} +992 -25
  65. package/dist/server/server/src/connectors/box-registry.js +188 -0
  66. package/dist/server/{db.js → server/src/db.js} +6 -0
  67. package/dist/server/server/src/debug.js +19 -0
  68. package/dist/server/server/src/discovery-advertiser.js +114 -0
  69. package/dist/server/{health.js → server/src/health.js} +39 -11
  70. package/dist/server/{index.js → server/src/index.js} +4 -0
  71. package/dist/server/{managers → server/src/managers}/platform/llm-manager.js +40 -4
  72. package/dist/server/{managers → server/src/managers}/platform/openai-responses-provider.js +129 -19
  73. package/dist/server/server/src/movement.js +2935 -0
  74. package/dist/server/{openapi.js → server/src/openapi.js} +628 -5
  75. package/dist/server/{psyche-types.js → server/src/psyche-types.js} +15 -1
  76. package/dist/server/server/src/questionnaire-flow.js +552 -0
  77. package/dist/server/server/src/questionnaire-seeds.js +853 -0
  78. package/dist/server/server/src/questionnaire-types.js +340 -0
  79. package/dist/server/server/src/repositories/ai-connectors.js +1207 -0
  80. package/dist/server/server/src/repositories/ai-processors.js +547 -0
  81. package/dist/server/{repositories → server/src/repositories}/calendar.js +1 -1
  82. package/dist/server/{repositories → server/src/repositories}/entity-ownership.js +9 -1
  83. package/dist/server/{repositories → server/src/repositories}/habits.js +69 -5
  84. package/dist/server/server/src/repositories/model-settings.js +216 -0
  85. package/dist/server/{repositories → server/src/repositories}/notes.js +57 -15
  86. package/dist/server/{repositories → server/src/repositories}/preferences.js +124 -0
  87. package/dist/server/server/src/repositories/questionnaires.js +1338 -0
  88. package/dist/server/{repositories → server/src/repositories}/settings.js +156 -12
  89. package/dist/server/server/src/repositories/surface-layouts.js +76 -0
  90. package/dist/server/{repositories → server/src/repositories}/wiki-memory.js +5 -1
  91. package/dist/server/{services → server/src/services}/calendar-runtime.js +775 -58
  92. package/dist/server/{services → server/src/services}/entity-crud.js +81 -2
  93. package/dist/server/server/src/services/google-calendar-oauth-config.js +176 -0
  94. package/dist/server/server/src/services/openai-codex-oauth.js +153 -0
  95. package/dist/server/server/src/services/psyche-observation-calendar.js +46 -0
  96. package/dist/server/{types.js → server/src/types.js} +621 -14
  97. package/dist/server/server/src/watch-mobile.js +562 -0
  98. package/dist/server/{web.js → server/src/web.js} +30 -4
  99. package/dist/server/src/components/customization/utility-widgets.js +330 -0
  100. package/dist/server/src/components/workbench-boxes/health/health-boxes.js +92 -0
  101. package/dist/server/src/components/workbench-boxes/kanban/kanban-boxes.js +128 -0
  102. package/dist/server/src/components/workbench-boxes/movement/movement-boxes.js +37 -0
  103. package/dist/server/src/components/workbench-boxes/notes/notes-boxes.js +114 -0
  104. package/dist/server/src/components/workbench-boxes/projects/projects-boxes.js +57 -0
  105. package/dist/server/src/components/workbench-boxes/shared/define-workbench-box.js +4 -0
  106. package/dist/server/src/components/workbench-boxes/shared/generic-node-view.js +13 -0
  107. package/dist/server/src/components/workbench-boxes/today/today-boxes.js +63 -0
  108. package/dist/server/src/lib/api-error.js +37 -0
  109. package/dist/server/src/lib/api.js +1859 -0
  110. package/dist/server/src/lib/calendar-name-deduper.js +144 -0
  111. package/dist/server/src/lib/diagnostics.js +67 -0
  112. package/dist/server/src/lib/psyche-types.js +1 -0
  113. package/dist/server/src/lib/questionnaire-types.js +1 -0
  114. package/dist/server/src/lib/runtime-paths.js +24 -0
  115. package/dist/server/src/lib/schemas.js +234 -0
  116. package/dist/server/src/lib/snapshot-normalizer.js +374 -0
  117. package/dist/server/src/lib/theme-system.js +319 -0
  118. package/dist/server/src/lib/types.js +1 -0
  119. package/dist/server/src/lib/utils.js +22 -0
  120. package/dist/server/src/lib/workbench/boxes.js +16 -0
  121. package/dist/server/src/lib/workbench/nodes.js +15 -0
  122. package/dist/server/src/lib/workbench/registry.js +73 -0
  123. package/dist/server/src/lib/workbench/runtime.js +181 -0
  124. package/openclaw.plugin.json +1 -1
  125. package/package.json +6 -1
  126. package/server/index.js +68 -0
  127. package/server/migrations/024_questionnaires.sql +96 -0
  128. package/server/migrations/025_ai_model_connections.sql +26 -0
  129. package/server/migrations/026_custom_theme_settings.sql +2 -0
  130. package/server/migrations/027_ai_processors.sql +31 -0
  131. package/server/migrations/028_movement_domain.sql +136 -0
  132. package/server/migrations/029_watch_micro_capture.sql +23 -0
  133. package/server/migrations/030_surface_layouts.sql +5 -0
  134. package/server/migrations/031_ai_processor_runtime_upgrades.sql +10 -0
  135. package/server/migrations/032_ai_connectors.sql +44 -0
  136. package/server/migrations/033_movement_trip_point_sync.sql +36 -0
  137. package/server/migrations/034_movement_segment_sync.sql +49 -0
  138. package/server/migrations/035_google_local_auth_settings.sql +2 -0
  139. package/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  140. package/skills/forge-openclaw/SKILL.md +15 -1
  141. package/skills/forge-openclaw/entity_conversation_playbooks.md +523 -87
  142. package/skills/forge-openclaw/psyche_entity_playbooks.md +331 -221
  143. package/dist/assets/index-DTCwBWAs.js +0 -65
  144. package/dist/assets/index-DTCwBWAs.js.map +0 -1
  145. package/dist/assets/index-DttXlAgi.css +0 -1
  146. package/dist/assets/motion-D4sZgCHd.js.map +0 -1
  147. package/dist/assets/vendor-De38P6YR.js +0 -729
  148. package/dist/assets/vendor-De38P6YR.js.map +0 -1
  149. package/dist/assets/viz-C6hfyqzu.js +0 -34
  150. package/dist/assets/viz-C6hfyqzu.js.map +0 -1
  151. package/skills/forge-openclaw/cron_jobs.md +0 -395
  152. /package/dist/server/{demo-data.js → server/src/demo-data.js} +0 -0
  153. /package/dist/server/{e2e-server.js → server/src/e2e-server.js} +0 -0
  154. /package/dist/server/{errors.js → server/src/errors.js} +0 -0
  155. /package/dist/server/{managers → server/src/managers}/base.js +0 -0
  156. /package/dist/server/{managers → server/src/managers}/contracts.js +0 -0
  157. /package/dist/server/{managers → server/src/managers}/platform/api-gateway-manager.js +0 -0
  158. /package/dist/server/{managers → server/src/managers}/platform/audit-manager.js +0 -0
  159. /package/dist/server/{managers → server/src/managers}/platform/authentication-manager.js +0 -0
  160. /package/dist/server/{managers → server/src/managers}/platform/authorization-manager.js +0 -0
  161. /package/dist/server/{managers → server/src/managers}/platform/background-job-manager.js +0 -0
  162. /package/dist/server/{managers → server/src/managers}/platform/configuration-manager.js +0 -0
  163. /package/dist/server/{managers → server/src/managers}/platform/database-manager.js +0 -0
  164. /package/dist/server/{managers → server/src/managers}/platform/event-bus-manager.js +0 -0
  165. /package/dist/server/{managers → server/src/managers}/platform/external-service-manager.js +0 -0
  166. /package/dist/server/{managers → server/src/managers}/platform/health-manager.js +0 -0
  167. /package/dist/server/{managers → server/src/managers}/platform/migration-manager.js +0 -0
  168. /package/dist/server/{managers → server/src/managers}/platform/search-index-manager.js +0 -0
  169. /package/dist/server/{managers → server/src/managers}/platform/secrets-manager.js +0 -0
  170. /package/dist/server/{managers → server/src/managers}/platform/session-manager.js +0 -0
  171. /package/dist/server/{managers → server/src/managers}/platform/storage-manager.js +0 -0
  172. /package/dist/server/{managers → server/src/managers}/platform/token-manager.js +0 -0
  173. /package/dist/server/{managers → server/src/managers}/platform/transaction-manager.js +0 -0
  174. /package/dist/server/{managers → server/src/managers}/platform/trusted-network.js +0 -0
  175. /package/dist/server/{managers → server/src/managers}/runtime.js +0 -0
  176. /package/dist/server/{managers → server/src/managers}/type-guards.js +0 -0
  177. /package/dist/server/{preferences-seeds.js → server/src/preferences-seeds.js} +0 -0
  178. /package/dist/server/{preferences-types.js → server/src/preferences-types.js} +0 -0
  179. /package/dist/server/{repositories → server/src/repositories}/activity-events.js +0 -0
  180. /package/dist/server/{repositories → server/src/repositories}/collaboration.js +0 -0
  181. /package/dist/server/{repositories → server/src/repositories}/deleted-entities.js +0 -0
  182. /package/dist/server/{repositories → server/src/repositories}/diagnostic-logs.js +0 -0
  183. /package/dist/server/{repositories → server/src/repositories}/domains.js +0 -0
  184. /package/dist/server/{repositories → server/src/repositories}/event-log.js +0 -0
  185. /package/dist/server/{repositories → server/src/repositories}/goals.js +0 -0
  186. /package/dist/server/{repositories → server/src/repositories}/projects.js +0 -0
  187. /package/dist/server/{repositories → server/src/repositories}/psyche.js +0 -0
  188. /package/dist/server/{repositories → server/src/repositories}/rewards.js +0 -0
  189. /package/dist/server/{repositories → server/src/repositories}/strategies.js +0 -0
  190. /package/dist/server/{repositories → server/src/repositories}/tags.js +0 -0
  191. /package/dist/server/{repositories → server/src/repositories}/task-runs.js +0 -0
  192. /package/dist/server/{repositories → server/src/repositories}/tasks.js +0 -0
  193. /package/dist/server/{repositories → server/src/repositories}/users.js +0 -0
  194. /package/dist/server/{repositories → server/src/repositories}/weekly-reviews.js +0 -0
  195. /package/dist/server/{repositories → server/src/repositories}/work-adjustments.js +0 -0
  196. /package/dist/server/{seed-demo.js → server/src/seed-demo.js} +0 -0
  197. /package/dist/server/{services → server/src/services}/context.js +0 -0
  198. /package/dist/server/{services → server/src/services}/dashboard.js +0 -0
  199. /package/dist/server/{services → server/src/services}/gamification.js +0 -0
  200. /package/dist/server/{services → server/src/services}/insights.js +0 -0
  201. /package/dist/server/{services → server/src/services}/projects.js +0 -0
  202. /package/dist/server/{services → server/src/services}/psyche.js +0 -0
  203. /package/dist/server/{services → server/src/services}/relations.js +0 -0
  204. /package/dist/server/{services → server/src/services}/reviews.js +0 -0
  205. /package/dist/server/{services → server/src/services}/run-recovery.js +0 -0
  206. /package/dist/server/{services → server/src/services}/tagging.js +0 -0
  207. /package/dist/server/{services → server/src/services}/task-run-watchdog.js +0 -0
  208. /package/dist/server/{services → server/src/services}/work-time.js +0 -0
@@ -0,0 +1,330 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+ import { useMutation, useQueryClient } from "@tanstack/react-query";
4
+ import { CalendarDays, CloudSun, ExternalLink, Music4, NotebookPen, Save, TimerReset } from "lucide-react";
5
+ import { createNote, createWikiPage } from "../../lib/api.js";
6
+ import { buildStaticWorkbenchExecution } from "../../lib/workbench/runtime.js";
7
+ import { cn } from "../../lib/utils.js";
8
+ import { createGenericWorkbenchNodeView } from "../workbench-boxes/shared/generic-node-view.js";
9
+ function formatMonthGrid(baseDate) {
10
+ const start = new Date(baseDate.getFullYear(), baseDate.getMonth(), 1);
11
+ const startOffset = (start.getDay() + 6) % 7;
12
+ const cursor = new Date(start);
13
+ cursor.setDate(cursor.getDate() - startOffset);
14
+ return Array.from({ length: 35 }, (_, index) => {
15
+ const current = new Date(cursor);
16
+ current.setDate(cursor.getDate() + index);
17
+ return current;
18
+ });
19
+ }
20
+ function readStoredValue(key, fallback) {
21
+ if (typeof window === "undefined") {
22
+ return fallback;
23
+ }
24
+ return window.localStorage.getItem(key) ?? fallback;
25
+ }
26
+ function writeStoredValue(key, value) {
27
+ if (typeof window === "undefined") {
28
+ return;
29
+ }
30
+ window.localStorage.setItem(key, value);
31
+ }
32
+ export function TimeWidget({ compact }) {
33
+ const [now, setNow] = useState(() => new Date());
34
+ useEffect(() => {
35
+ const timer = window.setInterval(() => setNow(new Date()), 30_000);
36
+ return () => window.clearInterval(timer);
37
+ }, []);
38
+ return (_jsxs("div", { className: "flex h-full flex-col justify-between gap-4 rounded-[20px] bg-white/[0.03] p-4", children: [_jsxs("div", { className: "flex items-center gap-2 text-white/45", children: [_jsx(TimerReset, { className: "size-4" }), _jsx("span", { className: "text-[12px] uppercase tracking-[0.16em]", children: "Local time" })] }), _jsx("div", { className: cn("font-display text-white", compact ? "text-3xl" : "text-5xl"), children: new Intl.DateTimeFormat(undefined, {
39
+ hour: "2-digit",
40
+ minute: "2-digit"
41
+ }).format(now) }), _jsx("div", { className: "text-sm text-white/58", children: new Intl.DateTimeFormat(undefined, {
42
+ weekday: "long",
43
+ month: "long",
44
+ day: "numeric"
45
+ }).format(now) })] }));
46
+ }
47
+ export function MiniCalendarWidget({ compact }) {
48
+ const today = new Date();
49
+ const days = useMemo(() => formatMonthGrid(today), [today]);
50
+ const weekdayLabels = compact
51
+ ? ["M", "T", "W", "T", "F", "S", "S"]
52
+ : ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
53
+ return (_jsxs("div", { className: "grid gap-3 rounded-[20px] bg-white/[0.03] p-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm text-white", children: [_jsx(CalendarDays, { className: "size-4 text-[var(--primary)]" }), new Intl.DateTimeFormat(undefined, {
54
+ month: "long",
55
+ year: "numeric"
56
+ }).format(today)] }), _jsx("div", { className: "text-[12px] text-white/45", children: compact ? "Mini" : "Month view" })] }), _jsxs("div", { className: "grid grid-cols-7 gap-1.5", children: [weekdayLabels.map((label) => (_jsx("div", { className: "text-center text-[11px] uppercase tracking-[0.14em] text-white/35", children: label }, label))), days.map((day) => {
57
+ const isCurrentMonth = day.getMonth() === today.getMonth();
58
+ const isToday = day.toDateString() === today.toDateString();
59
+ return (_jsx("div", { className: cn("flex min-h-9 items-center justify-center rounded-xl text-sm", isToday
60
+ ? "bg-[var(--primary)] text-slate-950"
61
+ : isCurrentMonth
62
+ ? "bg-white/[0.04] text-white/78"
63
+ : "bg-transparent text-white/24"), children: day.getDate() }, day.toISOString()));
64
+ })] })] }));
65
+ }
66
+ export function SpotifyWidget({ surfaceId }) {
67
+ const storageKey = `forge.utility.spotify.${surfaceId}`;
68
+ const [url, setUrl] = useState(() => readStoredValue(storageKey, "https://open.spotify.com/"));
69
+ useEffect(() => {
70
+ writeStoredValue(storageKey, url);
71
+ }, [storageKey, url]);
72
+ return (_jsxs("div", { className: "grid h-full gap-3 rounded-[20px] bg-white/[0.03] p-4", children: [_jsxs("div", { className: "flex items-center gap-2 text-white", children: [_jsx(Music4, { className: "size-4 text-[var(--secondary)]" }), _jsx("span", { className: "text-sm font-semibold", children: "Spotify link" })] }), _jsx("input", { value: url, onChange: (event) => setUrl(event.target.value), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2.5 text-sm text-white outline-none transition focus:border-[rgba(192,193,255,0.35)]", placeholder: "Paste a playlist, album, or artist URL" }), _jsxs("a", { href: url, target: "_blank", rel: "noreferrer", className: "inline-flex min-h-10 items-center justify-center gap-2 rounded-2xl bg-[rgba(78,222,163,0.14)] px-3 py-2 text-sm font-medium text-[var(--secondary)] transition hover:bg-[rgba(78,222,163,0.22)]", children: ["Open Spotify", _jsx(ExternalLink, { className: "size-4" })] })] }));
73
+ }
74
+ export function WeatherWidget({ compact }) {
75
+ const [weather, setWeather] = useState(null);
76
+ const [status, setStatus] = useState("Locating…");
77
+ useEffect(() => {
78
+ if (typeof navigator === "undefined" || !navigator.geolocation) {
79
+ setStatus("Location unavailable");
80
+ return;
81
+ }
82
+ let cancelled = false;
83
+ navigator.geolocation.getCurrentPosition(async (position) => {
84
+ try {
85
+ const response = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${position.coords.latitude}&longitude=${position.coords.longitude}&current=temperature_2m,weather_code`);
86
+ const payload = (await response.json());
87
+ if (cancelled || !payload.current) {
88
+ return;
89
+ }
90
+ setWeather({
91
+ temperature: Number(payload.current.temperature_2m ?? 0),
92
+ weatherCode: Number(payload.current.weather_code ?? 0)
93
+ });
94
+ setStatus("Live");
95
+ }
96
+ catch {
97
+ if (!cancelled) {
98
+ setStatus("Weather unavailable");
99
+ }
100
+ }
101
+ }, () => {
102
+ if (!cancelled) {
103
+ setStatus("Permission denied");
104
+ }
105
+ }, { maximumAge: 300000, timeout: 6000 });
106
+ return () => {
107
+ cancelled = true;
108
+ };
109
+ }, []);
110
+ return (_jsxs("div", { className: "flex h-full flex-col justify-between gap-4 rounded-[20px] bg-white/[0.03] p-4", children: [_jsxs("div", { className: "flex items-center gap-2 text-white", children: [_jsx(CloudSun, { className: "size-4 text-[var(--tertiary)]" }), _jsx("span", { className: "text-sm font-semibold", children: "Weather" })] }), weather ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: cn("font-display text-white", compact ? "text-3xl" : "text-5xl"), children: [Math.round(weather.temperature), "\u00B0"] }), _jsxs("div", { className: "text-sm text-white/58", children: ["Code ", weather.weatherCode, " \u00B7 ", status] })] })) : (_jsx("div", { className: "text-sm text-white/58", children: status }))] }));
111
+ }
112
+ export function QuickCaptureWidget({ compact, defaultUserId }) {
113
+ const queryClient = useQueryClient();
114
+ const titleRef = useRef(null);
115
+ const contentRef = useRef(null);
116
+ const [title, setTitle] = useState("");
117
+ const [content, setContent] = useState("");
118
+ const noteMutation = useMutation({
119
+ mutationFn: async () => createNote({
120
+ contentMarkdown: `# ${title.trim() || "Quick note"}\n\n${content.trim()}`,
121
+ author: "Forge quick capture",
122
+ userId: defaultUserId ?? null,
123
+ links: []
124
+ }),
125
+ onSuccess: async () => {
126
+ setTitle("");
127
+ setContent("");
128
+ await queryClient.invalidateQueries({ queryKey: ["notes-index"] });
129
+ }
130
+ });
131
+ const wikiMutation = useMutation({
132
+ mutationFn: async () => createWikiPage({
133
+ title: title.trim() || "Quick capture",
134
+ contentMarkdown: content.trim(),
135
+ summary: content.trim().slice(0, 180),
136
+ author: "Forge quick capture"
137
+ }),
138
+ onSuccess: async () => {
139
+ setTitle("");
140
+ setContent("");
141
+ await queryClient.invalidateQueries({ queryKey: ["wiki-pages"] });
142
+ }
143
+ });
144
+ function wrapSelection(prefix, suffix = prefix) {
145
+ const node = contentRef.current;
146
+ if (!node) {
147
+ return;
148
+ }
149
+ const start = node.selectionStart ?? 0;
150
+ const end = node.selectionEnd ?? 0;
151
+ const selected = content.slice(start, end);
152
+ const next = `${content.slice(0, start)}${prefix}${selected}${suffix}${content.slice(end)}`;
153
+ setContent(next);
154
+ requestAnimationFrame(() => {
155
+ node.focus();
156
+ node.selectionStart = start + prefix.length;
157
+ node.selectionEnd = end + prefix.length;
158
+ });
159
+ }
160
+ return (_jsxs("div", { className: "grid h-full min-h-0 gap-3 rounded-[20px] bg-white/[0.03] p-4", children: [_jsxs("div", { className: "flex items-center gap-2 text-white", children: [_jsx(NotebookPen, { className: "size-4 text-[var(--primary)]" }), _jsx("span", { className: "text-sm font-semibold", children: "Quick capture" })] }), _jsx("input", { ref: titleRef, value: title, onChange: (event) => setTitle(event.target.value), className: "w-full rounded-2xl border border-white/10 bg-white/[0.04] px-3 py-2.5 text-sm text-white outline-none transition focus:border-[rgba(192,193,255,0.35)]", placeholder: "Title" }), _jsx("div", { className: "flex flex-wrap gap-2", children: [
161
+ { label: "B", action: () => wrapSelection("**") },
162
+ { label: "I", action: () => wrapSelection("_") },
163
+ { label: "H1", action: () => wrapSelection("# ", "") },
164
+ { label: "[]", action: () => wrapSelection("- [ ] ", "") }
165
+ ].map((tool) => (_jsx("button", { type: "button", className: "inline-flex min-h-8 items-center justify-center rounded-xl bg-white/[0.05] px-2.5 text-[12px] font-semibold text-white/72 transition hover:bg-white/[0.08] hover:text-white", onClick: tool.action, children: tool.label }, tool.label))) }), _jsx("textarea", { ref: contentRef, value: content, onChange: (event) => setContent(event.target.value), className: cn("min-h-0 w-full rounded-[20px] border border-white/10 bg-white/[0.04] px-3 py-3 text-sm text-white outline-none transition focus:border-[rgba(192,193,255,0.35)]", compact ? "h-28" : "h-40"), placeholder: "Write a quick note or rough wiki draft" }), _jsxs("div", { className: "grid gap-2 sm:grid-cols-2", children: [_jsxs("button", { type: "button", className: "inline-flex min-h-10 items-center justify-center gap-2 rounded-2xl bg-[rgba(192,193,255,0.16)] px-3 py-2 text-sm font-medium text-[var(--primary)] transition hover:bg-[rgba(192,193,255,0.24)] disabled:opacity-50", disabled: !content.trim() || noteMutation.isPending, onClick: () => noteMutation.mutate(), children: [_jsx(Save, { className: "size-4" }), "Save as note"] }), _jsxs("button", { type: "button", className: "inline-flex min-h-10 items-center justify-center gap-2 rounded-2xl bg-[rgba(255,185,95,0.16)] px-3 py-2 text-sm font-medium text-[var(--tertiary)] transition hover:bg-[rgba(255,185,95,0.24)] disabled:opacity-50", disabled: !content.trim() || wikiMutation.isPending, onClick: () => wikiMutation.mutate(), children: [_jsx(NotebookPen, { className: "size-4" }), "Save as wiki"] })] })] }));
166
+ }
167
+ const timeWidgetDefinition = {
168
+ id: "surface:utility:time",
169
+ surfaceId: "utility",
170
+ routePath: null,
171
+ title: "Clock",
172
+ icon: "timer",
173
+ description: "Live local time widget.",
174
+ category: "Utilities",
175
+ tags: ["utility", "clock"],
176
+ inputs: [],
177
+ params: [],
178
+ output: [{ key: "primary", label: "Current time", kind: "text" }],
179
+ tools: [],
180
+ NodeView: createGenericWorkbenchNodeView({
181
+ title: "Clock",
182
+ description: "Live local time widget.",
183
+ inputs: [],
184
+ params: [],
185
+ output: [{ key: "primary", label: "Current time", kind: "text" }],
186
+ tools: []
187
+ }),
188
+ WebView: TimeWidget,
189
+ execute: (input) => buildStaticWorkbenchExecution(input, {
190
+ now: input.context.now
191
+ }, new Intl.DateTimeFormat(undefined, {
192
+ hour: "2-digit",
193
+ minute: "2-digit"
194
+ }).format(new Date(input.context.now)))
195
+ };
196
+ TimeWidget.workbench = timeWidgetDefinition;
197
+ const calendarWidgetDefinition = {
198
+ id: "surface:utility:mini-calendar",
199
+ surfaceId: "utility",
200
+ routePath: null,
201
+ title: "Mini calendar",
202
+ icon: "calendar",
203
+ description: "Compact month calendar widget.",
204
+ category: "Utilities",
205
+ tags: ["utility", "calendar"],
206
+ inputs: [],
207
+ params: [],
208
+ output: [{ key: "primary", label: "Month view", kind: "object" }],
209
+ tools: [],
210
+ NodeView: createGenericWorkbenchNodeView({
211
+ title: "Mini calendar",
212
+ description: "Compact month calendar widget.",
213
+ inputs: [],
214
+ params: [],
215
+ output: [{ key: "primary", label: "Month view", kind: "object" }],
216
+ tools: []
217
+ }),
218
+ WebView: MiniCalendarWidget,
219
+ execute: (input) => buildStaticWorkbenchExecution(input, {
220
+ now: input.context.now
221
+ }, "Compact month calendar")
222
+ };
223
+ MiniCalendarWidget.workbench = calendarWidgetDefinition;
224
+ const spotifyWidgetDefinition = {
225
+ id: "surface:utility:spotify",
226
+ surfaceId: "utility",
227
+ routePath: null,
228
+ title: "Spotify",
229
+ icon: "music",
230
+ description: "Pinned music link widget.",
231
+ category: "Utilities",
232
+ tags: ["utility", "spotify"],
233
+ inputs: [
234
+ {
235
+ key: "surfaceId",
236
+ label: "Surface id",
237
+ kind: "text",
238
+ required: false
239
+ }
240
+ ],
241
+ params: [],
242
+ output: [{ key: "primary", label: "Spotify link", kind: "text" }],
243
+ tools: [],
244
+ NodeView: createGenericWorkbenchNodeView({
245
+ title: "Spotify",
246
+ description: "Pinned music link widget.",
247
+ inputs: [{ key: "surfaceId", label: "Surface id", kind: "text" }],
248
+ params: [],
249
+ output: [{ key: "primary", label: "Spotify link", kind: "text" }],
250
+ tools: []
251
+ }),
252
+ WebView: SpotifyWidget,
253
+ execute: (input) => buildStaticWorkbenchExecution(input, {
254
+ surfaceId: input.inputs.surfaceId ?? null
255
+ }, "Pinned Spotify link")
256
+ };
257
+ SpotifyWidget.workbench = spotifyWidgetDefinition;
258
+ const weatherWidgetDefinition = {
259
+ id: "surface:utility:weather",
260
+ surfaceId: "utility",
261
+ routePath: null,
262
+ title: "Weather",
263
+ icon: "weather",
264
+ description: "Location-aware weather widget.",
265
+ category: "Utilities",
266
+ tags: ["utility", "weather"],
267
+ inputs: [],
268
+ params: [],
269
+ output: [{ key: "primary", label: "Weather", kind: "object" }],
270
+ tools: [],
271
+ NodeView: createGenericWorkbenchNodeView({
272
+ title: "Weather",
273
+ description: "Location-aware weather widget.",
274
+ inputs: [],
275
+ params: [],
276
+ output: [{ key: "primary", label: "Weather", kind: "object" }],
277
+ tools: []
278
+ }),
279
+ WebView: WeatherWidget,
280
+ execute: (input) => buildStaticWorkbenchExecution(input, null, "Weather widget")
281
+ };
282
+ WeatherWidget.workbench = weatherWidgetDefinition;
283
+ const quickCaptureWidgetDefinition = {
284
+ id: "surface:utility:quick-capture",
285
+ surfaceId: "utility",
286
+ routePath: null,
287
+ title: "Quick capture",
288
+ icon: "capture",
289
+ description: "Draft a quick note or wiki page.",
290
+ category: "Capture",
291
+ tags: ["capture", "notes"],
292
+ inputs: [
293
+ {
294
+ key: "defaultUserId",
295
+ label: "Default user id",
296
+ kind: "text",
297
+ required: false
298
+ }
299
+ ],
300
+ params: [],
301
+ output: [{ key: "primary", label: "Draft", kind: "content" }],
302
+ tools: [
303
+ {
304
+ key: "forge.create_note",
305
+ label: "Create note",
306
+ description: "Create a Forge evidence note from captured markdown.",
307
+ accessMode: "write"
308
+ }
309
+ ],
310
+ NodeView: createGenericWorkbenchNodeView({
311
+ title: "Quick capture",
312
+ description: "Draft a quick note or wiki page.",
313
+ inputs: [{ key: "defaultUserId", label: "Default user id", kind: "text" }],
314
+ params: [],
315
+ output: [{ key: "primary", label: "Draft", kind: "content" }],
316
+ tools: [
317
+ {
318
+ key: "forge.create_note",
319
+ label: "Create note",
320
+ description: "Create a Forge evidence note from captured markdown.",
321
+ accessMode: "write"
322
+ }
323
+ ]
324
+ }),
325
+ WebView: QuickCaptureWidget,
326
+ execute: (input) => buildStaticWorkbenchExecution(input, {
327
+ defaultUserId: input.inputs.defaultUserId ?? null
328
+ }, "Quick capture can draft notes and wiki pages.")
329
+ };
330
+ QuickCaptureWidget.workbench = quickCaptureWidgetDefinition;
@@ -0,0 +1,92 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { buildSleepWorkbenchExecution, buildSportsWorkbenchExecution } from "../../../lib/workbench/runtime.js";
3
+ import { createGenericWorkbenchNodeView } from "../shared/generic-node-view.js";
4
+ import { defineWorkbenchBox } from "../shared/define-workbench-box.js";
5
+ function Slot({ children }) {
6
+ return _jsx(_Fragment, { children: children });
7
+ }
8
+ function defineHealthBox(input) {
9
+ return defineWorkbenchBox(Slot, {
10
+ id: input.id,
11
+ surfaceId: input.surfaceId,
12
+ routePath: input.routePath,
13
+ title: input.title,
14
+ icon: input.surfaceId,
15
+ description: input.description,
16
+ category: input.category,
17
+ tags: input.tags,
18
+ inputs: [],
19
+ params: [],
20
+ output: [{ key: "primary", label: input.title, kind: "content" }],
21
+ tools: [],
22
+ NodeView: createGenericWorkbenchNodeView({
23
+ title: input.title,
24
+ description: input.description,
25
+ inputs: [],
26
+ params: [],
27
+ output: [{ key: "primary", label: input.title, kind: "content" }],
28
+ tools: []
29
+ }),
30
+ execute: input.execute
31
+ });
32
+ }
33
+ export const SleepSummaryBox = defineHealthBox({
34
+ id: "surface:sleep-index:summary",
35
+ surfaceId: "sleep-index",
36
+ routePath: "/sleep",
37
+ title: "Sleep summary",
38
+ description: "Recent nightly sleep metrics and recovery posture.",
39
+ category: "Sleep",
40
+ tags: ["sleep", "summary"],
41
+ execute: (input) => buildSleepWorkbenchExecution(input)
42
+ });
43
+ export const SleepPatternsBox = defineHealthBox({
44
+ id: "surface:sleep-index:patterns",
45
+ surfaceId: "sleep-index",
46
+ routePath: "/sleep",
47
+ title: "Sleep patterns",
48
+ description: "Trend, stage averages, recovery state, and timing patterns.",
49
+ category: "Sleep",
50
+ tags: ["sleep", "patterns"],
51
+ execute: (input) => buildSleepWorkbenchExecution(input)
52
+ });
53
+ export const SleepBrowserBox = defineHealthBox({
54
+ id: "surface:sleep-index:browser",
55
+ surfaceId: "sleep-index",
56
+ routePath: "/sleep",
57
+ title: "Night browser",
58
+ description: "Searchable and virtualized sleep history browser.",
59
+ category: "Sleep",
60
+ tags: ["sleep", "browser", "history"],
61
+ execute: (input) => buildSleepWorkbenchExecution(input)
62
+ });
63
+ export const SportsSummaryBox = defineHealthBox({
64
+ id: "surface:sports-index:summary",
65
+ surfaceId: "sports-index",
66
+ routePath: "/sports",
67
+ title: "Sports summary",
68
+ description: "Recent workout metrics, streaks, and linked-session totals.",
69
+ category: "Sports",
70
+ tags: ["sports", "summary"],
71
+ execute: (input) => buildSportsWorkbenchExecution(input)
72
+ });
73
+ export const SportsCompositionBox = defineHealthBox({
74
+ id: "surface:sports-index:composition",
75
+ surfaceId: "sports-index",
76
+ routePath: "/sports",
77
+ title: "Training composition",
78
+ description: "Workout mix, trend, and session composition context.",
79
+ category: "Sports",
80
+ tags: ["sports", "composition", "trend"],
81
+ execute: (input) => buildSportsWorkbenchExecution(input)
82
+ });
83
+ export const SportsBrowserBox = defineHealthBox({
84
+ id: "surface:sports-index:browser",
85
+ surfaceId: "sports-index",
86
+ routePath: "/sports",
87
+ title: "Session browser",
88
+ description: "Searchable and virtualized workout history browser.",
89
+ category: "Sports",
90
+ tags: ["sports", "browser", "history"],
91
+ execute: (input) => buildSportsWorkbenchExecution(input)
92
+ });
@@ -0,0 +1,128 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { buildSearchWorkbenchExecution } from "../../../lib/workbench/runtime.js";
3
+ import { createGenericWorkbenchNodeView } from "../shared/generic-node-view.js";
4
+ import { defineWorkbenchBox } from "../shared/define-workbench-box.js";
5
+ function Slot({ children }) {
6
+ return _jsx(_Fragment, { children: children });
7
+ }
8
+ export const KanbanSummaryBox = defineWorkbenchBox(Slot, {
9
+ id: "surface:kanban-index:summary",
10
+ surfaceId: "kanban-index",
11
+ routePath: "/kanban",
12
+ title: "Kanban summary",
13
+ icon: "kanban",
14
+ description: "Board summary and execution posture.",
15
+ category: "Execution",
16
+ tags: ["kanban", "summary"],
17
+ inputs: [],
18
+ params: [],
19
+ output: [{ key: "primary", label: "Kanban summary", kind: "content" }],
20
+ tools: [],
21
+ NodeView: createGenericWorkbenchNodeView({
22
+ title: "Kanban summary",
23
+ description: "Board summary and execution posture.",
24
+ inputs: [],
25
+ params: [],
26
+ output: [{ key: "primary", label: "Kanban summary", kind: "content" }],
27
+ tools: []
28
+ }),
29
+ execute: (input) => buildSearchWorkbenchExecution(input, {
30
+ query: "",
31
+ entityTypes: ["task"],
32
+ limit: 24
33
+ })
34
+ });
35
+ export const KanbanFiltersBox = defineWorkbenchBox(Slot, {
36
+ id: "surface:kanban-index:filters",
37
+ surfaceId: "kanban-index",
38
+ routePath: "/kanban",
39
+ title: "Kanban filters",
40
+ icon: "filter",
41
+ description: "Goal, owner, and tag filters for board scope.",
42
+ category: "Execution",
43
+ tags: ["kanban", "filters"],
44
+ inputs: [],
45
+ params: [],
46
+ output: [{ key: "primary", label: "Kanban filters", kind: "content" }],
47
+ tools: [
48
+ {
49
+ key: "forge.search_entities",
50
+ label: "Search Forge entities",
51
+ description: "Search Forge entities by query and entity types.",
52
+ accessMode: "read"
53
+ }
54
+ ],
55
+ NodeView: createGenericWorkbenchNodeView({
56
+ title: "Kanban filters",
57
+ description: "Goal, owner, and tag filters for board scope.",
58
+ inputs: [],
59
+ params: [],
60
+ output: [{ key: "primary", label: "Kanban filters", kind: "content" }],
61
+ tools: [
62
+ {
63
+ key: "forge.search_entities",
64
+ label: "Search Forge entities",
65
+ description: "Search Forge entities by query and entity types.",
66
+ accessMode: "read"
67
+ }
68
+ ]
69
+ }),
70
+ execute: (input) => buildSearchWorkbenchExecution(input, {
71
+ query: "",
72
+ entityTypes: ["task"],
73
+ limit: 24
74
+ })
75
+ });
76
+ export const KanbanBoardBox = defineWorkbenchBox(Slot, {
77
+ id: "surface:kanban-index:board",
78
+ surfaceId: "kanban-index",
79
+ routePath: "/kanban",
80
+ title: "Kanban board",
81
+ icon: "board",
82
+ description: "Task board with move and execution actions.",
83
+ category: "Execution",
84
+ tags: ["kanban", "board", "tasks"],
85
+ inputs: [],
86
+ params: [],
87
+ output: [{ key: "primary", label: "Kanban board", kind: "content" }],
88
+ tools: [
89
+ {
90
+ key: "forge.search_entities",
91
+ label: "Search Forge entities",
92
+ description: "Search Forge entities by query and entity types.",
93
+ accessMode: "read"
94
+ },
95
+ {
96
+ key: "forge.update_task_status",
97
+ label: "Move task",
98
+ description: "Update a task status.",
99
+ accessMode: "write"
100
+ }
101
+ ],
102
+ NodeView: createGenericWorkbenchNodeView({
103
+ title: "Kanban board",
104
+ description: "Task board with move and execution actions.",
105
+ inputs: [],
106
+ params: [],
107
+ output: [{ key: "primary", label: "Kanban board", kind: "content" }],
108
+ tools: [
109
+ {
110
+ key: "forge.search_entities",
111
+ label: "Search Forge entities",
112
+ description: "Search Forge entities by query and entity types.",
113
+ accessMode: "read"
114
+ },
115
+ {
116
+ key: "forge.update_task_status",
117
+ label: "Move task",
118
+ description: "Update a task status.",
119
+ accessMode: "write"
120
+ }
121
+ ]
122
+ }),
123
+ execute: (input) => buildSearchWorkbenchExecution(input, {
124
+ query: "",
125
+ entityTypes: ["task"],
126
+ limit: 24
127
+ })
128
+ });
@@ -0,0 +1,37 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { buildMovementPlacesExecution, buildStaticWorkbenchExecution } from "../../../lib/workbench/runtime.js";
3
+ import { createGenericWorkbenchNodeView } from "../shared/generic-node-view.js";
4
+ import { defineWorkbenchBox } from "../shared/define-workbench-box.js";
5
+ function Slot({ children }) {
6
+ return _jsx(_Fragment, { children: children });
7
+ }
8
+ function defineMovementBox(id, title, description, tags, execute) {
9
+ return defineWorkbenchBox(Slot, {
10
+ id,
11
+ surfaceId: "movement-index",
12
+ routePath: "/movement",
13
+ title,
14
+ icon: "movement",
15
+ description,
16
+ category: "Movement",
17
+ tags,
18
+ inputs: [],
19
+ params: [],
20
+ output: [{ key: "primary", label: title, kind: "content" }],
21
+ tools: [],
22
+ NodeView: createGenericWorkbenchNodeView({
23
+ title,
24
+ description,
25
+ inputs: [],
26
+ params: [],
27
+ output: [{ key: "primary", label: title, kind: "content" }],
28
+ tools: []
29
+ }),
30
+ execute
31
+ });
32
+ }
33
+ export const MovementSummaryBox = defineMovementBox("surface:movement-index:summary", "Movement summary", "Tracking mode, daily totals, and passive capture posture.", ["movement", "summary"], (input) => buildStaticWorkbenchExecution(input, null, "Movement summary is available."));
34
+ export const MovementSelectionBox = defineMovementBox("surface:movement-index:selection", "Movement selection aggregate", "Selected-stay and selected-trip aggregate totals.", ["movement", "selection", "aggregate"], (input) => buildStaticWorkbenchExecution(input, null, "Selected stay and trip aggregate totals."));
35
+ export const MovementTimelineBox = defineMovementBox("surface:movement-index:timeline", "Movement life timeline", "Life-scale stay and trip timeline with edit access.", ["movement", "timeline", "life"], (input) => buildStaticWorkbenchExecution(input, null, "Movement life timeline with stay and trip history."));
36
+ export const MovementPlacesBox = defineMovementBox("surface:movement-index:places", "Known places", "Known places, aliases, and category tags.", ["movement", "places"], (input) => buildMovementPlacesExecution(input));
37
+ export const MovementDataBrowserBox = defineMovementBox("surface:movement-index:data-browser", "Movement data browser", "Datapoint browsing, invalid records, and movement data cleanup.", ["movement", "data", "browser"], (input) => buildStaticWorkbenchExecution(input, null, "Movement datapoint browser with cleanup actions."));