forge-openclaw-plugin 0.2.25 → 0.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/README.md +59 -3
  2. package/dist/assets/{board-VmF4FAfr.js → board-C6jCchjI.js} +3 -3
  3. package/dist/assets/{board-VmF4FAfr.js.map → board-C6jCchjI.js.map} +1 -1
  4. package/dist/assets/index-DVvS8iiU.css +1 -0
  5. package/dist/assets/index-zYB-9Dfo.js +85 -0
  6. package/dist/assets/index-zYB-9Dfo.js.map +1 -0
  7. package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js +2 -0
  8. package/dist/assets/knowledge-graph-layout.worker-DRvzPxhP.js.map +1 -0
  9. package/dist/assets/{motion-DvkU14p-.js → motion-DFHrH2rd.js} +2 -2
  10. package/dist/assets/{motion-DvkU14p-.js.map → motion-DFHrH2rd.js.map} +1 -1
  11. package/dist/assets/{table-DgiPof9E.js → table-ZL7Di_u3.js} +2 -2
  12. package/dist/assets/{table-DgiPof9E.js.map → table-ZL7Di_u3.js.map} +1 -1
  13. package/dist/assets/{ui-nYfoC0Gq.js → ui-CKNPpz7q.js} +2 -2
  14. package/dist/assets/{ui-nYfoC0Gq.js.map → ui-CKNPpz7q.js.map} +1 -1
  15. package/dist/assets/vendor-DoNZuFhn.js +1247 -0
  16. package/dist/assets/vendor-DoNZuFhn.js.map +1 -0
  17. package/dist/index.html +7 -8
  18. package/dist/openclaw/local-runtime.d.ts +3 -1
  19. package/dist/openclaw/local-runtime.js +67 -15
  20. package/dist/openclaw/plugin-entry-shared.js +24 -2
  21. package/dist/openclaw/plugin-sdk-types.d.ts +17 -0
  22. package/dist/openclaw/routes.d.ts +27 -0
  23. package/dist/openclaw/routes.js +16 -12
  24. package/dist/openclaw/tools.js +0 -3
  25. package/dist/server/server/migrations/001_core.sql +411 -0
  26. package/dist/server/server/migrations/002_psyche.sql +392 -0
  27. package/dist/server/server/migrations/003_habits.sql +30 -0
  28. package/dist/server/server/migrations/004_habit_links.sql +8 -0
  29. package/dist/server/server/migrations/005_habit_psyche_links.sql +24 -0
  30. package/dist/server/server/migrations/006_work_adjustments.sql +14 -0
  31. package/dist/server/server/migrations/007_weekly_review_closures.sql +17 -0
  32. package/dist/server/server/migrations/008_calendar_execution.sql +147 -0
  33. package/dist/server/server/migrations/009_true_calendar_events.sql +195 -0
  34. package/dist/server/server/migrations/010_calendar_selection_state.sql +6 -0
  35. package/dist/server/server/migrations/011_calendar_timezone_backfill.sql +11 -0
  36. package/dist/server/server/migrations/012_work_block_ranges.sql +7 -0
  37. package/dist/server/server/migrations/013_microsoft_local_auth_settings.sql +8 -0
  38. package/dist/server/server/migrations/014_note_tags_and_ephemeral.sql +8 -0
  39. package/dist/server/server/migrations/015_multi_user_and_strategies.sql +244 -0
  40. package/dist/server/server/migrations/016_health_companion.sql +158 -0
  41. package/dist/server/server/migrations/016_strategy_contracts_and_user_graph.sql +22 -0
  42. package/dist/server/server/migrations/017_preferences.sql +131 -0
  43. package/dist/server/server/migrations/018_preference_catalogs.sql +31 -0
  44. package/dist/server/server/migrations/019_wiki_memory.sql +255 -0
  45. package/dist/server/server/migrations/020_wiki_page_hierarchy.sql +11 -0
  46. package/dist/server/server/migrations/021_hide_evidence_from_wiki_index.sql +3 -0
  47. package/dist/server/server/migrations/022_wiki_ingest_background.sql +85 -0
  48. package/dist/server/server/migrations/023_diagnostic_logs.sql +28 -0
  49. package/dist/server/server/migrations/024_questionnaires.sql +96 -0
  50. package/dist/server/server/migrations/025_ai_model_connections.sql +26 -0
  51. package/dist/server/server/migrations/026_custom_theme_settings.sql +2 -0
  52. package/dist/server/server/migrations/027_ai_processors.sql +31 -0
  53. package/dist/server/server/migrations/028_movement_domain.sql +136 -0
  54. package/dist/server/server/migrations/029_watch_micro_capture.sql +23 -0
  55. package/dist/server/server/migrations/030_surface_layouts.sql +5 -0
  56. package/dist/server/server/migrations/031_ai_processor_runtime_upgrades.sql +10 -0
  57. package/dist/server/server/migrations/032_ai_connectors.sql +44 -0
  58. package/dist/server/server/migrations/033_movement_trip_point_sync.sql +36 -0
  59. package/dist/server/server/migrations/034_movement_segment_sync.sql +49 -0
  60. package/dist/server/server/migrations/035_google_local_auth_settings.sql +2 -0
  61. package/dist/server/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  62. package/dist/server/server/migrations/037_workbench_public_inputs_and_run_inputs.sql +5 -0
  63. package/dist/server/server/migrations/038_data_management_settings.sql +11 -0
  64. package/dist/server/server/migrations/039_life_force_and_action_points.sql +114 -0
  65. package/dist/server/server/migrations/040_screen_time_domain.sql +89 -0
  66. package/dist/server/server/migrations/041_companion_source_states.sql +21 -0
  67. package/dist/server/server/migrations/042_movement_boxes.sql +47 -0
  68. package/dist/server/server/migrations/043_movement_box_overlap_overrides.sql +26 -0
  69. package/dist/server/{app.js → server/src/app.js} +2112 -414
  70. package/dist/server/server/src/connectors/box-registry.js +223 -0
  71. package/dist/server/server/src/data-management-types.js +107 -0
  72. package/dist/server/{db.js → server/src/db.js} +72 -4
  73. package/dist/server/server/src/debug.js +19 -0
  74. package/dist/server/{demo-data.js → server/src/demo-data.js} +2 -2
  75. package/dist/server/{health.js → server/src/health.js} +702 -18
  76. package/dist/server/{managers → server/src/managers}/platform/llm-manager.js +7 -4
  77. package/dist/server/server/src/managers/platform/mock-workbench-provider.js +149 -0
  78. package/dist/server/{managers → server/src/managers}/platform/secrets-manager.js +18 -1
  79. package/dist/server/{managers → server/src/managers}/runtime.js +9 -0
  80. package/dist/server/{movement.js → server/src/movement.js} +1971 -112
  81. package/dist/server/{openapi.js → server/src/openapi.js} +491 -3
  82. package/dist/server/{psyche-types.js → server/src/psyche-types.js} +9 -1
  83. package/dist/server/{repositories → server/src/repositories}/activity-events.js +8 -0
  84. package/dist/server/{repositories → server/src/repositories}/ai-connectors.js +758 -47
  85. package/dist/server/{repositories → server/src/repositories}/calendar.js +1 -1
  86. package/dist/server/{repositories → server/src/repositories}/habits.js +37 -1
  87. package/dist/server/{repositories → server/src/repositories}/model-settings.js +13 -3
  88. package/dist/server/{repositories → server/src/repositories}/notes.js +3 -0
  89. package/dist/server/{repositories → server/src/repositories}/settings.js +431 -21
  90. package/dist/server/{repositories → server/src/repositories}/tasks.js +170 -10
  91. package/dist/server/server/src/runtime-data-root.js +82 -0
  92. package/dist/server/server/src/screen-time.js +802 -0
  93. package/dist/server/{services → server/src/services}/calendar-runtime.js +775 -58
  94. package/dist/server/server/src/services/data-management.js +788 -0
  95. package/dist/server/{services → server/src/services}/entity-crud.js +205 -2
  96. package/dist/server/server/src/services/google-calendar-oauth-config.js +176 -0
  97. package/dist/server/server/src/services/knowledge-graph.js +1455 -0
  98. package/dist/server/server/src/services/life-force-model.js +197 -0
  99. package/dist/server/server/src/services/life-force.js +1270 -0
  100. package/dist/server/server/src/services/psyche-observation-calendar.js +413 -0
  101. package/dist/server/{types.js → server/src/types.js} +420 -29
  102. package/dist/server/server/src/web.js +332 -0
  103. package/dist/server/src/components/customization/utility-widgets.js +439 -0
  104. package/dist/server/src/components/ui/info-tooltip.js +25 -0
  105. package/dist/server/src/components/workbench-boxes/calendar/calendar-boxes.js +78 -0
  106. package/dist/server/src/components/workbench-boxes/goals/goals-boxes.js +62 -0
  107. package/dist/server/src/components/workbench-boxes/habits/habits-boxes.js +62 -0
  108. package/dist/server/src/components/workbench-boxes/health/health-boxes.js +147 -0
  109. package/dist/server/src/components/workbench-boxes/insights/insights-boxes.js +50 -0
  110. package/dist/server/src/components/workbench-boxes/kanban/kanban-boxes.js +136 -0
  111. package/dist/server/src/components/workbench-boxes/movement/movement-boxes.js +47 -0
  112. package/dist/server/src/components/workbench-boxes/notes/notes-boxes.js +132 -0
  113. package/dist/server/src/components/workbench-boxes/overview/overview-boxes.js +65 -0
  114. package/dist/server/src/components/workbench-boxes/preferences/preferences-boxes.js +78 -0
  115. package/dist/server/src/components/workbench-boxes/projects/projects-boxes.js +62 -0
  116. package/dist/server/src/components/workbench-boxes/psyche/psyche-boxes.js +88 -0
  117. package/dist/server/src/components/workbench-boxes/questionnaires/questionnaires-boxes.js +61 -0
  118. package/dist/server/src/components/workbench-boxes/review/review-boxes.js +53 -0
  119. package/dist/server/src/components/workbench-boxes/shared/define-workbench-box.js +6 -0
  120. package/dist/server/src/components/workbench-boxes/shared/generic-node-view.js +49 -0
  121. package/dist/server/src/components/workbench-boxes/strategies/strategies-boxes.js +62 -0
  122. package/dist/server/src/components/workbench-boxes/tasks/tasks-boxes.js +76 -0
  123. package/dist/server/src/components/workbench-boxes/today/today-boxes.js +78 -0
  124. package/dist/server/src/components/workbench-boxes/wiki/wiki-boxes.js +60 -0
  125. package/dist/server/src/lib/api-error.js +37 -0
  126. package/dist/server/src/lib/api.js +2118 -0
  127. package/dist/server/src/lib/calendar-name-deduper.js +144 -0
  128. package/dist/server/src/lib/data-management-types.js +1 -0
  129. package/dist/server/src/lib/diagnostics.js +67 -0
  130. package/dist/server/src/lib/entity-visuals.js +279 -0
  131. package/dist/server/src/lib/knowledge-graph-types.js +276 -0
  132. package/dist/server/src/lib/knowledge-graph.js +470 -0
  133. package/dist/server/src/lib/psyche-types.js +1 -0
  134. package/dist/server/src/lib/questionnaire-types.js +1 -0
  135. package/dist/server/src/lib/runtime-paths.js +24 -0
  136. package/dist/server/src/lib/schemas.js +238 -0
  137. package/dist/server/src/lib/snapshot-normalizer.js +416 -0
  138. package/dist/server/src/lib/theme-system.js +319 -0
  139. package/dist/server/src/lib/types.js +1 -0
  140. package/dist/server/src/lib/utils.js +22 -0
  141. package/dist/server/src/lib/workbench/boxes.js +16 -0
  142. package/dist/server/src/lib/workbench/contracts.js +229 -0
  143. package/dist/server/src/lib/workbench/nodes.js +215 -0
  144. package/dist/server/src/lib/workbench/registry.js +120 -0
  145. package/dist/server/src/lib/workbench/runtime.js +397 -0
  146. package/dist/server/src/lib/workbench/tool-catalog.js +68 -0
  147. package/openclaw.plugin.json +1 -1
  148. package/package.json +1 -1
  149. package/server/index.js +68 -0
  150. package/server/migrations/035_google_local_auth_settings.sql +2 -0
  151. package/server/migrations/036_google_local_auth_client_secret.sql +2 -0
  152. package/server/migrations/037_workbench_public_inputs_and_run_inputs.sql +5 -0
  153. package/server/migrations/038_data_management_settings.sql +11 -0
  154. package/server/migrations/039_life_force_and_action_points.sql +114 -0
  155. package/server/migrations/040_screen_time_domain.sql +89 -0
  156. package/server/migrations/041_companion_source_states.sql +21 -0
  157. package/server/migrations/042_movement_boxes.sql +47 -0
  158. package/server/migrations/043_movement_box_overlap_overrides.sql +26 -0
  159. package/skills/forge-openclaw/SKILL.md +27 -11
  160. package/skills/forge-openclaw/entity_conversation_playbooks.md +411 -46
  161. package/skills/forge-openclaw/psyche_entity_playbooks.md +195 -20
  162. package/dist/assets/index-CFCKDIMH.js +0 -67
  163. package/dist/assets/index-CFCKDIMH.js.map +0 -1
  164. package/dist/assets/index-ZPY6U1TU.css +0 -1
  165. package/dist/assets/vendor-D9PTEPSB.js +0 -824
  166. package/dist/assets/vendor-D9PTEPSB.js.map +0 -1
  167. package/dist/assets/viz-Cqb6s--o.js +0 -34
  168. package/dist/assets/viz-Cqb6s--o.js.map +0 -1
  169. package/dist/server/connectors/box-registry.js +0 -257
  170. package/dist/server/services/psyche-observation-calendar.js +0 -46
  171. package/dist/server/web.js +0 -98
  172. /package/dist/server/{discovery-advertiser.js → server/src/discovery-advertiser.js} +0 -0
  173. /package/dist/server/{e2e-server.js → server/src/e2e-server.js} +0 -0
  174. /package/dist/server/{errors.js → server/src/errors.js} +0 -0
  175. /package/dist/server/{index.js → server/src/index.js} +0 -0
  176. /package/dist/server/{managers → server/src/managers}/base.js +0 -0
  177. /package/dist/server/{managers → server/src/managers}/contracts.js +0 -0
  178. /package/dist/server/{managers → server/src/managers}/platform/api-gateway-manager.js +0 -0
  179. /package/dist/server/{managers → server/src/managers}/platform/audit-manager.js +0 -0
  180. /package/dist/server/{managers → server/src/managers}/platform/authentication-manager.js +0 -0
  181. /package/dist/server/{managers → server/src/managers}/platform/authorization-manager.js +0 -0
  182. /package/dist/server/{managers → server/src/managers}/platform/background-job-manager.js +0 -0
  183. /package/dist/server/{managers → server/src/managers}/platform/configuration-manager.js +0 -0
  184. /package/dist/server/{managers → server/src/managers}/platform/database-manager.js +0 -0
  185. /package/dist/server/{managers → server/src/managers}/platform/event-bus-manager.js +0 -0
  186. /package/dist/server/{managers → server/src/managers}/platform/external-service-manager.js +0 -0
  187. /package/dist/server/{managers → server/src/managers}/platform/health-manager.js +0 -0
  188. /package/dist/server/{managers → server/src/managers}/platform/migration-manager.js +0 -0
  189. /package/dist/server/{managers → server/src/managers}/platform/openai-responses-provider.js +0 -0
  190. /package/dist/server/{managers → server/src/managers}/platform/search-index-manager.js +0 -0
  191. /package/dist/server/{managers → server/src/managers}/platform/session-manager.js +0 -0
  192. /package/dist/server/{managers → server/src/managers}/platform/storage-manager.js +0 -0
  193. /package/dist/server/{managers → server/src/managers}/platform/token-manager.js +0 -0
  194. /package/dist/server/{managers → server/src/managers}/platform/transaction-manager.js +0 -0
  195. /package/dist/server/{managers → server/src/managers}/platform/trusted-network.js +0 -0
  196. /package/dist/server/{managers → server/src/managers}/type-guards.js +0 -0
  197. /package/dist/server/{preferences-seeds.js → server/src/preferences-seeds.js} +0 -0
  198. /package/dist/server/{preferences-types.js → server/src/preferences-types.js} +0 -0
  199. /package/dist/server/{questionnaire-flow.js → server/src/questionnaire-flow.js} +0 -0
  200. /package/dist/server/{questionnaire-seeds.js → server/src/questionnaire-seeds.js} +0 -0
  201. /package/dist/server/{questionnaire-types.js → server/src/questionnaire-types.js} +0 -0
  202. /package/dist/server/{repositories → server/src/repositories}/ai-processors.js +0 -0
  203. /package/dist/server/{repositories → server/src/repositories}/collaboration.js +0 -0
  204. /package/dist/server/{repositories → server/src/repositories}/deleted-entities.js +0 -0
  205. /package/dist/server/{repositories → server/src/repositories}/diagnostic-logs.js +0 -0
  206. /package/dist/server/{repositories → server/src/repositories}/domains.js +0 -0
  207. /package/dist/server/{repositories → server/src/repositories}/entity-ownership.js +0 -0
  208. /package/dist/server/{repositories → server/src/repositories}/event-log.js +0 -0
  209. /package/dist/server/{repositories → server/src/repositories}/goals.js +0 -0
  210. /package/dist/server/{repositories → server/src/repositories}/preferences.js +0 -0
  211. /package/dist/server/{repositories → server/src/repositories}/projects.js +0 -0
  212. /package/dist/server/{repositories → server/src/repositories}/psyche.js +0 -0
  213. /package/dist/server/{repositories → server/src/repositories}/questionnaires.js +0 -0
  214. /package/dist/server/{repositories → server/src/repositories}/rewards.js +0 -0
  215. /package/dist/server/{repositories → server/src/repositories}/strategies.js +0 -0
  216. /package/dist/server/{repositories → server/src/repositories}/surface-layouts.js +0 -0
  217. /package/dist/server/{repositories → server/src/repositories}/tags.js +0 -0
  218. /package/dist/server/{repositories → server/src/repositories}/task-runs.js +0 -0
  219. /package/dist/server/{repositories → server/src/repositories}/users.js +0 -0
  220. /package/dist/server/{repositories → server/src/repositories}/weekly-reviews.js +0 -0
  221. /package/dist/server/{repositories → server/src/repositories}/wiki-memory.js +0 -0
  222. /package/dist/server/{repositories → server/src/repositories}/work-adjustments.js +0 -0
  223. /package/dist/server/{seed-demo.js → server/src/seed-demo.js} +0 -0
  224. /package/dist/server/{services → server/src/services}/context.js +0 -0
  225. /package/dist/server/{services → server/src/services}/dashboard.js +0 -0
  226. /package/dist/server/{services → server/src/services}/gamification.js +0 -0
  227. /package/dist/server/{services → server/src/services}/insights.js +0 -0
  228. /package/dist/server/{services → server/src/services}/openai-codex-oauth.js +0 -0
  229. /package/dist/server/{services → server/src/services}/projects.js +0 -0
  230. /package/dist/server/{services → server/src/services}/psyche.js +0 -0
  231. /package/dist/server/{services → server/src/services}/relations.js +0 -0
  232. /package/dist/server/{services → server/src/services}/reviews.js +0 -0
  233. /package/dist/server/{services → server/src/services}/run-recovery.js +0 -0
  234. /package/dist/server/{services → server/src/services}/tagging.js +0 -0
  235. /package/dist/server/{services → server/src/services}/task-run-watchdog.js +0 -0
  236. /package/dist/server/{services → server/src/services}/work-time.js +0 -0
  237. /package/dist/server/{watch-mobile.js → server/src/watch-mobile.js} +0 -0
@@ -0,0 +1,1455 @@
1
+ import { getDatabase } from "../db.js";
2
+ import { listInsights } from "../repositories/collaboration.js";
3
+ import { listCalendarEvents, listTaskTimeboxes, listWorkBlockTemplates } from "../repositories/calendar.js";
4
+ import { filterOwnedEntities } from "../repositories/entity-ownership.js";
5
+ import { listGoals } from "../repositories/goals.js";
6
+ import { listHabits } from "../repositories/habits.js";
7
+ import { listNotes } from "../repositories/notes.js";
8
+ import { listBehaviors, listBehaviorPatterns, listBeliefEntries, listEmotionDefinitions, listEventTypes, listModeGuideSessions, listModeProfiles, listPsycheValues, listTriggerReports } from "../repositories/psyche.js";
9
+ import { listStrategies } from "../repositories/strategies.js";
10
+ import { listTags } from "../repositories/tags.js";
11
+ import { listTasks } from "../repositories/tasks.js";
12
+ import { listWikiSpaces } from "../repositories/wiki-memory.js";
13
+ import { listProjectSummaries } from "./projects.js";
14
+ import { listAiConnectors } from "../repositories/ai-connectors.js";
15
+ import { buildKnowledgeGraphFacets, buildKnowledgeGraphFocusPayload, filterKnowledgeGraphData, selectKnowledgeGraphVisibleNodeIds } from "../../../src/lib/knowledge-graph.js";
16
+ import { getEntityVisual } from "../../../src/lib/entity-visuals.js";
17
+ import { KNOWLEDGE_GRAPH_RELATION_FAMILY_MAP, buildKnowledgeGraphFocusHref, buildKnowledgeGraphNodeId, getKnowledgeGraphEntityHref } from "../../../src/lib/knowledge-graph-types.js";
18
+ const GRAPH_RANGE = {
19
+ from: "2000-01-01T00:00:00.000Z",
20
+ to: "2100-01-01T00:00:00.000Z"
21
+ };
22
+ const BASE_NODE_SIZE = {
23
+ goal: 56,
24
+ strategy: 52,
25
+ project: 48,
26
+ task: 42,
27
+ tag: 30,
28
+ wiki_space: 40,
29
+ wiki_page: 38,
30
+ note: 34,
31
+ habit: 36,
32
+ insight: 34,
33
+ calendar_event: 34,
34
+ work_block: 32,
35
+ timebox: 33,
36
+ value: 38,
37
+ pattern: 38,
38
+ behavior: 38,
39
+ belief: 38,
40
+ mode: 38,
41
+ mode_session: 34,
42
+ report: 40,
43
+ event_type: 32,
44
+ emotion: 30,
45
+ workbench: 42,
46
+ functor: 36,
47
+ chat: 36
48
+ };
49
+ const WORKBENCH_SURFACE_ROUTES = {
50
+ workbench: {
51
+ title: "Workbench",
52
+ subtitle: "Global graph flows",
53
+ href: "/workbench"
54
+ },
55
+ overview: {
56
+ title: "Overview Surface",
57
+ subtitle: "Operator overview workspace",
58
+ href: "/overview"
59
+ },
60
+ today: {
61
+ title: "Today Surface",
62
+ subtitle: "Execution workspace",
63
+ href: "/today"
64
+ },
65
+ goals: {
66
+ title: "Goals Surface",
67
+ subtitle: "Goal planning workspace",
68
+ href: "/goals"
69
+ },
70
+ projects: {
71
+ title: "Projects Surface",
72
+ subtitle: "Project execution workspace",
73
+ href: "/projects"
74
+ },
75
+ kanban: {
76
+ title: "Kanban Surface",
77
+ subtitle: "Task board workspace",
78
+ href: "/kanban"
79
+ },
80
+ notes: {
81
+ title: "Notes Surface",
82
+ subtitle: "Notes and evidence workspace",
83
+ href: "/notes"
84
+ },
85
+ calendar: {
86
+ title: "Calendar Surface",
87
+ subtitle: "Calendar planning workspace",
88
+ href: "/calendar"
89
+ },
90
+ psyche: {
91
+ title: "Psyche Surface",
92
+ subtitle: "Psyche workspace",
93
+ href: "/psyche"
94
+ },
95
+ wiki: {
96
+ title: "KarpaWiki Surface",
97
+ subtitle: "KarpaWiki memory workspace",
98
+ href: "/wiki"
99
+ },
100
+ strategies: {
101
+ title: "Strategies Surface",
102
+ subtitle: "Strategy design workspace",
103
+ href: "/strategies"
104
+ },
105
+ preferences: {
106
+ title: "Preferences Surface",
107
+ subtitle: "Preference workspace",
108
+ href: "/preferences"
109
+ },
110
+ questionnaires: {
111
+ title: "Questionnaires Surface",
112
+ subtitle: "Questionnaire workspace",
113
+ href: "/questionnaires"
114
+ },
115
+ review: {
116
+ title: "Review Surface",
117
+ subtitle: "Weekly review workspace",
118
+ href: "/weekly-review"
119
+ },
120
+ movement: {
121
+ title: "Movement Surface",
122
+ subtitle: "Movement workspace",
123
+ href: "/movement"
124
+ },
125
+ sleep: {
126
+ title: "Sleep Surface",
127
+ subtitle: "Sleep workspace",
128
+ href: "/sleep"
129
+ },
130
+ sports: {
131
+ title: "Sports Surface",
132
+ subtitle: "Sports workspace",
133
+ href: "/sports"
134
+ }
135
+ };
136
+ function truncate(value, max = 160) {
137
+ const normalized = (value ?? "").replace(/\s+/g, " ").trim();
138
+ if (normalized.length <= max) {
139
+ return normalized;
140
+ }
141
+ return `${normalized.slice(0, max - 1).trimEnd()}...`;
142
+ }
143
+ function buildOwner(owner) {
144
+ if (!owner?.user) {
145
+ return null;
146
+ }
147
+ return {
148
+ userId: owner.userId ?? null,
149
+ displayName: owner.user.displayName,
150
+ accentColor: owner.user.accentColor,
151
+ kind: owner.user.kind
152
+ };
153
+ }
154
+ function makeNode(input) {
155
+ const previewStats = (input.previewStats ?? [])
156
+ .filter((stat) => stat.value !== null && stat.value !== undefined && `${stat.value}`.trim().length > 0)
157
+ .slice(0, 3)
158
+ .map((stat) => ({
159
+ label: stat.label,
160
+ value: String(stat.value)
161
+ }));
162
+ return {
163
+ id: buildKnowledgeGraphNodeId(input.entityType, input.entityId),
164
+ entityType: input.entityType,
165
+ entityId: input.entityId,
166
+ entityKind: input.entityKind,
167
+ title: truncate(input.title, 90) || input.entityId,
168
+ subtitle: truncate(input.subtitle, 120),
169
+ description: truncate(input.description, 220),
170
+ href: input.href ?? null,
171
+ graphHref: buildKnowledgeGraphFocusHref(input.entityType, input.entityId),
172
+ iconName: null,
173
+ accentToken: null,
174
+ size: BASE_NODE_SIZE[input.entityKind],
175
+ importance: BASE_NODE_SIZE[input.entityKind],
176
+ previewStats,
177
+ owner: buildOwner(input.owner),
178
+ tags: input.tags ?? [],
179
+ updatedAt: input.updatedAt ?? null,
180
+ graphStats: {
181
+ degree: 0,
182
+ structuralDegree: 0,
183
+ contextualDegree: 0,
184
+ taxonomyDegree: 0,
185
+ workspaceDegree: 0
186
+ }
187
+ };
188
+ }
189
+ function addEdge(edgeIndex, input) {
190
+ if (input.source === input.target) {
191
+ return;
192
+ }
193
+ const edgeId = [
194
+ input.relationKind,
195
+ input.source,
196
+ input.target,
197
+ input.label
198
+ ].join("|");
199
+ if (edgeIndex.has(edgeId)) {
200
+ return;
201
+ }
202
+ edgeIndex.set(edgeId, {
203
+ id: edgeId,
204
+ family: KNOWLEDGE_GRAPH_RELATION_FAMILY_MAP[input.relationKind],
205
+ ...input
206
+ });
207
+ }
208
+ function listWikiLinkRows(noteIds) {
209
+ if (noteIds.length === 0) {
210
+ return [];
211
+ }
212
+ const placeholders = noteIds.map(() => "?").join(", ");
213
+ return getDatabase()
214
+ .prepare(`SELECT source_note_id, target_type, target_note_id, target_entity_type, target_entity_id
215
+ FROM wiki_link_edges
216
+ WHERE source_note_id IN (${placeholders})`)
217
+ .all(...noteIds);
218
+ }
219
+ function buildFocusPayload(graph, focusNodeId) {
220
+ return buildKnowledgeGraphFocusPayload(graph.nodes, graph.edges, focusNodeId);
221
+ }
222
+ export function buildKnowledgeGraph(userIds, query = {}) {
223
+ const goals = filterOwnedEntities("goal", listGoals(), userIds);
224
+ const projects = listProjectSummaries({ userIds });
225
+ const tasks = filterOwnedEntities("task", listTasks(), userIds);
226
+ const tags = filterOwnedEntities("tag", listTags(), userIds);
227
+ const strategies = listStrategies({ userIds });
228
+ const habits = listHabits({ userIds });
229
+ const notes = listNotes({ userIds });
230
+ const insights = listInsights({ userIds });
231
+ const calendarEvents = listCalendarEvents({ ...GRAPH_RANGE, userIds });
232
+ const workBlocks = listWorkBlockTemplates({ userIds });
233
+ const timeboxes = listTaskTimeboxes({ ...GRAPH_RANGE, userIds });
234
+ const eventTypes = filterOwnedEntities("event_type", listEventTypes(), userIds);
235
+ const emotions = filterOwnedEntities("emotion_definition", listEmotionDefinitions(), userIds);
236
+ const values = filterOwnedEntities("psyche_value", listPsycheValues(), userIds);
237
+ const patterns = filterOwnedEntities("behavior_pattern", listBehaviorPatterns(), userIds);
238
+ const behaviors = filterOwnedEntities("behavior", listBehaviors(), userIds);
239
+ const beliefs = filterOwnedEntities("belief_entry", listBeliefEntries(), userIds);
240
+ const modes = filterOwnedEntities("mode_profile", listModeProfiles(), userIds);
241
+ const modeSessions = filterOwnedEntities("mode_guide_session", listModeGuideSessions(), userIds);
242
+ const reports = filterOwnedEntities("trigger_report", listTriggerReports(), userIds);
243
+ const wikiSpaces = listWikiSpaces();
244
+ const flows = listAiConnectors();
245
+ const nodes = new Map();
246
+ const edges = new Map();
247
+ const noteIds = notes.map((note) => note.id);
248
+ const wikiLinkRows = listWikiLinkRows(noteIds);
249
+ const noteById = new Map(notes.map((note) => [note.id, note]));
250
+ const tagById = new Map(tags.map((tag) => [tag.id, tag]));
251
+ for (const goal of goals) {
252
+ nodes.set(buildKnowledgeGraphNodeId("goal", goal.id), makeNode({
253
+ entityType: "goal",
254
+ entityId: goal.id,
255
+ entityKind: "goal",
256
+ title: goal.title,
257
+ subtitle: goal.horizon,
258
+ description: goal.description,
259
+ previewStats: [
260
+ { label: "Horizon", value: goal.horizon },
261
+ { label: "Status", value: goal.status },
262
+ { label: "Target XP", value: goal.targetPoints }
263
+ ],
264
+ owner: goal,
265
+ tags: goal.tagIds
266
+ .map((tagId) => tagById.get(tagId))
267
+ .filter(Boolean)
268
+ .map((tag) => ({ id: tag.id, label: tag.name })),
269
+ href: getKnowledgeGraphEntityHref("goal", goal.id),
270
+ updatedAt: goal.updatedAt
271
+ }));
272
+ for (const tagId of goal.tagIds) {
273
+ addEdge(edges, {
274
+ source: buildKnowledgeGraphNodeId("tag", tagId),
275
+ target: buildKnowledgeGraphNodeId("goal", goal.id),
276
+ relationKind: "tag_goal",
277
+ label: "Tags goal",
278
+ strength: 0.7,
279
+ directional: true,
280
+ structural: false
281
+ });
282
+ }
283
+ }
284
+ for (const tag of tags) {
285
+ nodes.set(buildKnowledgeGraphNodeId("tag", tag.id), makeNode({
286
+ entityType: "tag",
287
+ entityId: tag.id,
288
+ entityKind: "tag",
289
+ title: tag.name,
290
+ subtitle: tag.kind,
291
+ description: tag.description,
292
+ previewStats: [
293
+ { label: "Kind", value: tag.kind },
294
+ { label: "Color", value: tag.color }
295
+ ],
296
+ owner: tag,
297
+ href: "/tags"
298
+ }));
299
+ }
300
+ for (const project of projects) {
301
+ nodes.set(buildKnowledgeGraphNodeId("project", project.id), makeNode({
302
+ entityType: "project",
303
+ entityId: project.id,
304
+ entityKind: "project",
305
+ title: project.title,
306
+ subtitle: project.goalTitle,
307
+ description: project.description,
308
+ previewStats: [
309
+ { label: "Progress", value: `${project.progress}%` },
310
+ { label: "Tasks", value: project.totalTasks },
311
+ { label: "Status", value: project.status }
312
+ ],
313
+ owner: project,
314
+ href: getKnowledgeGraphEntityHref("project", project.id),
315
+ updatedAt: "updatedAt" in project ? project.updatedAt : null
316
+ }));
317
+ addEdge(edges, {
318
+ source: buildKnowledgeGraphNodeId("goal", project.goalId),
319
+ target: buildKnowledgeGraphNodeId("project", project.id),
320
+ relationKind: "goal_project",
321
+ label: "Supports goal",
322
+ strength: 0.96,
323
+ directional: true,
324
+ structural: true
325
+ });
326
+ }
327
+ for (const task of tasks) {
328
+ nodes.set(buildKnowledgeGraphNodeId("task", task.id), makeNode({
329
+ entityType: "task",
330
+ entityId: task.id,
331
+ entityKind: "task",
332
+ title: task.title,
333
+ subtitle: task.status.replaceAll("_", " "),
334
+ description: task.description,
335
+ previewStats: [
336
+ { label: "Status", value: task.status.replaceAll("_", " ") },
337
+ { label: "Priority", value: task.priority },
338
+ { label: "XP", value: task.points }
339
+ ],
340
+ owner: task,
341
+ tags: task.tagIds
342
+ .map((tagId) => tagById.get(tagId))
343
+ .filter(Boolean)
344
+ .map((tag) => ({ id: tag.id, label: tag.name })),
345
+ href: getKnowledgeGraphEntityHref("task", task.id),
346
+ updatedAt: task.updatedAt
347
+ }));
348
+ if (task.projectId) {
349
+ addEdge(edges, {
350
+ source: buildKnowledgeGraphNodeId("project", task.projectId),
351
+ target: buildKnowledgeGraphNodeId("task", task.id),
352
+ relationKind: "project_task",
353
+ label: "Contains task",
354
+ strength: 0.98,
355
+ directional: true,
356
+ structural: true
357
+ });
358
+ }
359
+ if (task.goalId && !task.projectId) {
360
+ addEdge(edges, {
361
+ source: buildKnowledgeGraphNodeId("goal", task.goalId),
362
+ target: buildKnowledgeGraphNodeId("task", task.id),
363
+ relationKind: "goal_task",
364
+ label: "Direct goal task",
365
+ strength: 0.8,
366
+ directional: true,
367
+ structural: false
368
+ });
369
+ }
370
+ for (const tagId of task.tagIds) {
371
+ addEdge(edges, {
372
+ source: buildKnowledgeGraphNodeId("tag", tagId),
373
+ target: buildKnowledgeGraphNodeId("task", task.id),
374
+ relationKind: "tag_task",
375
+ label: "Tags task",
376
+ strength: 0.68,
377
+ directional: true,
378
+ structural: false
379
+ });
380
+ }
381
+ }
382
+ for (const strategy of strategies) {
383
+ nodes.set(buildKnowledgeGraphNodeId("strategy", strategy.id), makeNode({
384
+ entityType: "strategy",
385
+ entityId: strategy.id,
386
+ entityKind: "strategy",
387
+ title: strategy.title,
388
+ subtitle: `${strategy.metrics.alignmentScore}% aligned`,
389
+ description: strategy.overview || strategy.endStateDescription,
390
+ previewStats: [
391
+ { label: "Aligned", value: `${strategy.metrics.alignmentScore}%` },
392
+ { label: "Nodes", value: strategy.metrics.totalNodeCount },
393
+ { label: "Status", value: strategy.status }
394
+ ],
395
+ owner: strategy,
396
+ tags: strategy.linkedEntities
397
+ .filter((link) => link.entityType === "tag")
398
+ .map((link) => tagById.get(link.entityId))
399
+ .filter(Boolean)
400
+ .map((tag) => ({ id: tag.id, label: tag.name })),
401
+ href: getKnowledgeGraphEntityHref("strategy", strategy.id),
402
+ updatedAt: strategy.updatedAt
403
+ }));
404
+ for (const goalId of strategy.targetGoalIds) {
405
+ addEdge(edges, {
406
+ source: buildKnowledgeGraphNodeId("strategy", strategy.id),
407
+ target: buildKnowledgeGraphNodeId("goal", goalId),
408
+ relationKind: "strategy_target",
409
+ label: "Targets goal",
410
+ strength: 0.92,
411
+ directional: true,
412
+ structural: true
413
+ });
414
+ }
415
+ for (const projectId of strategy.targetProjectIds) {
416
+ addEdge(edges, {
417
+ source: buildKnowledgeGraphNodeId("strategy", strategy.id),
418
+ target: buildKnowledgeGraphNodeId("project", projectId),
419
+ relationKind: "strategy_target",
420
+ label: "Targets project",
421
+ strength: 0.92,
422
+ directional: true,
423
+ structural: true
424
+ });
425
+ }
426
+ for (const link of strategy.linkedEntities) {
427
+ if (link.entityType === "tag") {
428
+ addEdge(edges, {
429
+ source: buildKnowledgeGraphNodeId("tag", link.entityId),
430
+ target: buildKnowledgeGraphNodeId("strategy", strategy.id),
431
+ relationKind: "tag_strategy",
432
+ label: "Tags strategy",
433
+ strength: 0.68,
434
+ directional: true,
435
+ structural: false
436
+ });
437
+ continue;
438
+ }
439
+ addEdge(edges, {
440
+ source: buildKnowledgeGraphNodeId("strategy", strategy.id),
441
+ target: buildKnowledgeGraphNodeId(link.entityType, link.entityId),
442
+ relationKind: "strategy_link",
443
+ label: "References entity",
444
+ strength: 0.66,
445
+ directional: true,
446
+ structural: false
447
+ });
448
+ }
449
+ for (const node of strategy.graph.nodes) {
450
+ addEdge(edges, {
451
+ source: buildKnowledgeGraphNodeId("strategy", strategy.id),
452
+ target: buildKnowledgeGraphNodeId(node.entityType, node.entityId),
453
+ relationKind: "strategy_step",
454
+ label: "Uses plan step",
455
+ strength: 0.82,
456
+ directional: true,
457
+ structural: true
458
+ });
459
+ }
460
+ }
461
+ for (const habit of habits) {
462
+ nodes.set(buildKnowledgeGraphNodeId("habit", habit.id), makeNode({
463
+ entityType: "habit",
464
+ entityId: habit.id,
465
+ entityKind: "habit",
466
+ title: habit.title,
467
+ subtitle: habit.frequency,
468
+ description: habit.description,
469
+ previewStats: [
470
+ { label: "Frequency", value: habit.frequency },
471
+ { label: "Streak", value: habit.streakCount },
472
+ { label: "Completion", value: `${Math.round(habit.completionRate)}%` }
473
+ ],
474
+ owner: habit,
475
+ href: getKnowledgeGraphEntityHref("habit", habit.id),
476
+ updatedAt: habit.updatedAt
477
+ }));
478
+ for (const linkedId of habit.linkedGoalIds) {
479
+ addEdge(edges, {
480
+ source: buildKnowledgeGraphNodeId("habit", habit.id),
481
+ target: buildKnowledgeGraphNodeId("goal", linkedId),
482
+ relationKind: "habit_link",
483
+ label: "Habit supports goal",
484
+ strength: 0.76,
485
+ directional: true,
486
+ structural: false
487
+ });
488
+ }
489
+ for (const linkedId of habit.linkedProjectIds) {
490
+ addEdge(edges, {
491
+ source: buildKnowledgeGraphNodeId("habit", habit.id),
492
+ target: buildKnowledgeGraphNodeId("project", linkedId),
493
+ relationKind: "habit_link",
494
+ label: "Habit supports project",
495
+ strength: 0.76,
496
+ directional: true,
497
+ structural: false
498
+ });
499
+ }
500
+ for (const linkedId of habit.linkedTaskIds) {
501
+ addEdge(edges, {
502
+ source: buildKnowledgeGraphNodeId("habit", habit.id),
503
+ target: buildKnowledgeGraphNodeId("task", linkedId),
504
+ relationKind: "habit_link",
505
+ label: "Habit supports task",
506
+ strength: 0.76,
507
+ directional: true,
508
+ structural: false
509
+ });
510
+ }
511
+ for (const linkedId of habit.linkedValueIds) {
512
+ addEdge(edges, {
513
+ source: buildKnowledgeGraphNodeId("habit", habit.id),
514
+ target: buildKnowledgeGraphNodeId("psyche_value", linkedId),
515
+ relationKind: "habit_link",
516
+ label: "Habit supports value",
517
+ strength: 0.74,
518
+ directional: true,
519
+ structural: false
520
+ });
521
+ }
522
+ for (const linkedId of habit.linkedPatternIds) {
523
+ addEdge(edges, {
524
+ source: buildKnowledgeGraphNodeId("habit", habit.id),
525
+ target: buildKnowledgeGraphNodeId("behavior_pattern", linkedId),
526
+ relationKind: "habit_link",
527
+ label: "Habit relates to pattern",
528
+ strength: 0.74,
529
+ directional: true,
530
+ structural: false
531
+ });
532
+ }
533
+ for (const linkedId of habit.linkedBehaviorIds) {
534
+ addEdge(edges, {
535
+ source: buildKnowledgeGraphNodeId("habit", habit.id),
536
+ target: buildKnowledgeGraphNodeId("behavior", linkedId),
537
+ relationKind: "habit_link",
538
+ label: "Habit relates to behavior",
539
+ strength: 0.74,
540
+ directional: true,
541
+ structural: false
542
+ });
543
+ }
544
+ for (const linkedId of habit.linkedBeliefIds) {
545
+ addEdge(edges, {
546
+ source: buildKnowledgeGraphNodeId("habit", habit.id),
547
+ target: buildKnowledgeGraphNodeId("belief_entry", linkedId),
548
+ relationKind: "habit_link",
549
+ label: "Habit relates to belief",
550
+ strength: 0.72,
551
+ directional: true,
552
+ structural: false
553
+ });
554
+ }
555
+ for (const linkedId of habit.linkedModeIds) {
556
+ addEdge(edges, {
557
+ source: buildKnowledgeGraphNodeId("habit", habit.id),
558
+ target: buildKnowledgeGraphNodeId("mode_profile", linkedId),
559
+ relationKind: "habit_link",
560
+ label: "Habit relates to mode",
561
+ strength: 0.72,
562
+ directional: true,
563
+ structural: false
564
+ });
565
+ }
566
+ for (const linkedId of habit.linkedReportIds) {
567
+ addEdge(edges, {
568
+ source: buildKnowledgeGraphNodeId("habit", habit.id),
569
+ target: buildKnowledgeGraphNodeId("trigger_report", linkedId),
570
+ relationKind: "habit_link",
571
+ label: "Habit relates to report",
572
+ strength: 0.72,
573
+ directional: true,
574
+ structural: false
575
+ });
576
+ }
577
+ }
578
+ for (const note of notes) {
579
+ const isWiki = note.kind === "wiki";
580
+ const noteNodeId = buildKnowledgeGraphNodeId("note", note.id);
581
+ nodes.set(noteNodeId, makeNode({
582
+ entityType: "note",
583
+ entityId: note.id,
584
+ entityKind: isWiki ? "wiki_page" : "note",
585
+ title: note.title,
586
+ subtitle: isWiki ? note.slug : note.summary,
587
+ description: note.summary || note.contentPlain,
588
+ previewStats: [
589
+ { label: "Kind", value: note.kind },
590
+ { label: "Links", value: note.links.length },
591
+ { label: "Tags", value: note.tags?.length ?? 0 }
592
+ ],
593
+ owner: note,
594
+ tags: (note.tags ?? []).map((tag) => ({
595
+ id: tag,
596
+ label: tag
597
+ })),
598
+ href: getKnowledgeGraphEntityHref("note", note.id, {
599
+ noteKind: note.kind,
600
+ noteSlug: note.slug,
601
+ noteSpaceId: note.spaceId
602
+ }),
603
+ updatedAt: note.updatedAt
604
+ }));
605
+ if (isWiki && note.spaceId) {
606
+ addEdge(edges, {
607
+ source: buildKnowledgeGraphNodeId("wiki_space", note.spaceId),
608
+ target: noteNodeId,
609
+ relationKind: "wiki_parent",
610
+ label: "Contains page",
611
+ strength: 0.72,
612
+ directional: true,
613
+ structural: true
614
+ });
615
+ }
616
+ for (const link of note.links) {
617
+ addEdge(edges, {
618
+ source: noteNodeId,
619
+ target: buildKnowledgeGraphNodeId(link.entityType, link.entityId),
620
+ relationKind: "note_link",
621
+ label: "Attached note",
622
+ strength: isWiki ? 0.74 : 0.68,
623
+ directional: true,
624
+ structural: false
625
+ });
626
+ }
627
+ }
628
+ for (const space of wikiSpaces) {
629
+ nodes.set(buildKnowledgeGraphNodeId("wiki_space", space.id), makeNode({
630
+ entityType: "wiki_space",
631
+ entityId: space.id,
632
+ entityKind: "wiki_space",
633
+ title: space.label,
634
+ subtitle: space.visibility,
635
+ description: space.description,
636
+ previewStats: [
637
+ { label: "Visibility", value: space.visibility },
638
+ { label: "Slug", value: space.slug }
639
+ ],
640
+ href: getKnowledgeGraphEntityHref("wiki_space", space.id),
641
+ updatedAt: space.updatedAt
642
+ }));
643
+ }
644
+ for (const row of wikiLinkRows) {
645
+ const sourceNote = noteById.get(row.source_note_id);
646
+ if (!sourceNote) {
647
+ continue;
648
+ }
649
+ if (row.target_type === "page" && row.target_note_id) {
650
+ addEdge(edges, {
651
+ source: buildKnowledgeGraphNodeId("note", row.source_note_id),
652
+ target: buildKnowledgeGraphNodeId("note", row.target_note_id),
653
+ relationKind: "wiki_link",
654
+ label: "Wiki link",
655
+ strength: 0.64,
656
+ directional: true,
657
+ structural: false
658
+ });
659
+ }
660
+ if (row.target_type === "entity" && row.target_entity_type && row.target_entity_id) {
661
+ addEdge(edges, {
662
+ source: buildKnowledgeGraphNodeId("note", row.source_note_id),
663
+ target: buildKnowledgeGraphNodeId(row.target_entity_type, row.target_entity_id),
664
+ relationKind: "wiki_link",
665
+ label: "Wiki entity link",
666
+ strength: 0.64,
667
+ directional: true,
668
+ structural: false
669
+ });
670
+ }
671
+ }
672
+ for (const insight of insights) {
673
+ nodes.set(buildKnowledgeGraphNodeId("insight", insight.id), makeNode({
674
+ entityType: "insight",
675
+ entityId: insight.id,
676
+ entityKind: "insight",
677
+ title: insight.title,
678
+ subtitle: insight.status,
679
+ description: insight.summary || insight.recommendation,
680
+ previewStats: [
681
+ { label: "Status", value: insight.status },
682
+ { label: "Confidence", value: `${Math.round(insight.confidence * 100)}%` },
683
+ { label: "Evidence", value: insight.evidence.length }
684
+ ],
685
+ owner: insight,
686
+ href: getKnowledgeGraphEntityHref("insight", insight.id),
687
+ updatedAt: insight.updatedAt
688
+ }));
689
+ if (insight.entityType && insight.entityId) {
690
+ addEdge(edges, {
691
+ source: buildKnowledgeGraphNodeId("insight", insight.id),
692
+ target: buildKnowledgeGraphNodeId(insight.entityType, insight.entityId),
693
+ relationKind: "note_link",
694
+ label: "Primary entity",
695
+ strength: 0.7,
696
+ directional: true,
697
+ structural: false
698
+ });
699
+ }
700
+ for (const evidence of insight.evidence) {
701
+ addEdge(edges, {
702
+ source: buildKnowledgeGraphNodeId("insight", insight.id),
703
+ target: buildKnowledgeGraphNodeId(evidence.entityType, evidence.entityId),
704
+ relationKind: "note_link",
705
+ label: "Evidence",
706
+ strength: 0.66,
707
+ directional: true,
708
+ structural: false
709
+ });
710
+ }
711
+ }
712
+ for (const event of calendarEvents) {
713
+ nodes.set(buildKnowledgeGraphNodeId("calendar_event", event.id), makeNode({
714
+ entityType: "calendar_event",
715
+ entityId: event.id,
716
+ entityKind: "calendar_event",
717
+ title: event.title,
718
+ subtitle: event.eventType || event.originType,
719
+ description: event.description || event.location,
720
+ previewStats: [
721
+ { label: "Origin", value: event.originType },
722
+ { label: "Start", value: new Date(event.startAt).toLocaleDateString() },
723
+ { label: "Links", value: event.links.length }
724
+ ],
725
+ owner: event,
726
+ href: getKnowledgeGraphEntityHref("calendar_event", event.id),
727
+ updatedAt: event.updatedAt
728
+ }));
729
+ for (const link of event.links) {
730
+ addEdge(edges, {
731
+ source: buildKnowledgeGraphNodeId("calendar_event", event.id),
732
+ target: buildKnowledgeGraphNodeId(link.entityType, link.entityId),
733
+ relationKind: "calendar_link",
734
+ label: link.relationshipType || "Calendar link",
735
+ strength: 0.7,
736
+ directional: true,
737
+ structural: false
738
+ });
739
+ }
740
+ }
741
+ for (const workBlock of workBlocks) {
742
+ nodes.set(buildKnowledgeGraphNodeId("work_block_template", workBlock.id), makeNode({
743
+ entityType: "work_block_template",
744
+ entityId: workBlock.id,
745
+ entityKind: "work_block",
746
+ title: workBlock.title,
747
+ subtitle: workBlock.kind.replaceAll("_", " "),
748
+ description: `${workBlock.blockingState} block`,
749
+ previewStats: [
750
+ { label: "Kind", value: workBlock.kind.replaceAll("_", " ") },
751
+ { label: "State", value: workBlock.blockingState },
752
+ { label: "Days", value: workBlock.weekDays.length }
753
+ ],
754
+ owner: workBlock,
755
+ href: getKnowledgeGraphEntityHref("work_block_template", workBlock.id),
756
+ updatedAt: workBlock.updatedAt
757
+ }));
758
+ }
759
+ for (const timebox of timeboxes) {
760
+ nodes.set(buildKnowledgeGraphNodeId("task_timebox", timebox.id), makeNode({
761
+ entityType: "task_timebox",
762
+ entityId: timebox.id,
763
+ entityKind: "timebox",
764
+ title: timebox.title,
765
+ subtitle: timebox.status,
766
+ description: `${timebox.source} timebox`,
767
+ previewStats: [
768
+ { label: "Status", value: timebox.status },
769
+ { label: "Source", value: timebox.source },
770
+ { label: "Starts", value: new Date(timebox.startsAt).toLocaleDateString() }
771
+ ],
772
+ owner: timebox,
773
+ href: getKnowledgeGraphEntityHref("task_timebox", timebox.id),
774
+ updatedAt: timebox.updatedAt
775
+ }));
776
+ addEdge(edges, {
777
+ source: buildKnowledgeGraphNodeId("task_timebox", timebox.id),
778
+ target: buildKnowledgeGraphNodeId("task", timebox.taskId),
779
+ relationKind: "timebox_task",
780
+ label: "Timeboxes task",
781
+ strength: 0.9,
782
+ directional: true,
783
+ structural: true
784
+ });
785
+ if (timebox.projectId) {
786
+ addEdge(edges, {
787
+ source: buildKnowledgeGraphNodeId("task_timebox", timebox.id),
788
+ target: buildKnowledgeGraphNodeId("project", timebox.projectId),
789
+ relationKind: "timebox_project",
790
+ label: "Timeboxes project",
791
+ strength: 0.78,
792
+ directional: true,
793
+ structural: false
794
+ });
795
+ }
796
+ }
797
+ for (const eventType of eventTypes) {
798
+ nodes.set(buildKnowledgeGraphNodeId("event_type", eventType.id), makeNode({
799
+ entityType: "event_type",
800
+ entityId: eventType.id,
801
+ entityKind: "event_type",
802
+ title: eventType.label,
803
+ subtitle: eventType.system ? "System type" : "Custom type",
804
+ description: eventType.description,
805
+ previewStats: [
806
+ { label: "System", value: eventType.system ? "Yes" : "No" }
807
+ ],
808
+ owner: eventType,
809
+ href: "/psyche/reports",
810
+ updatedAt: eventType.updatedAt
811
+ }));
812
+ }
813
+ for (const emotion of emotions) {
814
+ nodes.set(buildKnowledgeGraphNodeId("emotion_definition", emotion.id), makeNode({
815
+ entityType: "emotion_definition",
816
+ entityId: emotion.id,
817
+ entityKind: "emotion",
818
+ title: emotion.label,
819
+ subtitle: emotion.category,
820
+ description: emotion.description,
821
+ previewStats: [
822
+ { label: "Category", value: emotion.category },
823
+ { label: "System", value: emotion.system ? "Yes" : "No" }
824
+ ],
825
+ owner: emotion,
826
+ href: "/psyche/reports",
827
+ updatedAt: emotion.updatedAt
828
+ }));
829
+ }
830
+ for (const value of values) {
831
+ nodes.set(buildKnowledgeGraphNodeId("psyche_value", value.id), makeNode({
832
+ entityType: "psyche_value",
833
+ entityId: value.id,
834
+ entityKind: "value",
835
+ title: value.title,
836
+ subtitle: value.valuedDirection,
837
+ description: value.description || value.whyItMatters,
838
+ previewStats: [
839
+ { label: "Goals", value: value.linkedGoalIds.length },
840
+ { label: "Projects", value: value.linkedProjectIds.length },
841
+ { label: "Tasks", value: value.linkedTaskIds.length }
842
+ ],
843
+ owner: value,
844
+ href: getKnowledgeGraphEntityHref("psyche_value", value.id),
845
+ updatedAt: value.updatedAt
846
+ }));
847
+ for (const goalId of value.linkedGoalIds) {
848
+ addEdge(edges, {
849
+ source: buildKnowledgeGraphNodeId("psyche_value", value.id),
850
+ target: buildKnowledgeGraphNodeId("goal", goalId),
851
+ relationKind: "value_goal",
852
+ label: "Anchors goal",
853
+ strength: 0.72,
854
+ directional: true,
855
+ structural: false
856
+ });
857
+ }
858
+ for (const projectId of value.linkedProjectIds) {
859
+ addEdge(edges, {
860
+ source: buildKnowledgeGraphNodeId("psyche_value", value.id),
861
+ target: buildKnowledgeGraphNodeId("project", projectId),
862
+ relationKind: "value_project",
863
+ label: "Anchors project",
864
+ strength: 0.72,
865
+ directional: true,
866
+ structural: false
867
+ });
868
+ }
869
+ for (const taskId of value.linkedTaskIds) {
870
+ addEdge(edges, {
871
+ source: buildKnowledgeGraphNodeId("psyche_value", value.id),
872
+ target: buildKnowledgeGraphNodeId("task", taskId),
873
+ relationKind: "value_task",
874
+ label: "Anchors task",
875
+ strength: 0.72,
876
+ directional: true,
877
+ structural: false
878
+ });
879
+ }
880
+ }
881
+ for (const pattern of patterns) {
882
+ nodes.set(buildKnowledgeGraphNodeId("behavior_pattern", pattern.id), makeNode({
883
+ entityType: "behavior_pattern",
884
+ entityId: pattern.id,
885
+ entityKind: "pattern",
886
+ title: pattern.title,
887
+ subtitle: pattern.targetBehavior,
888
+ description: pattern.description,
889
+ previewStats: [
890
+ { label: "Values", value: pattern.linkedValueIds.length },
891
+ { label: "Beliefs", value: pattern.linkedBeliefIds.length },
892
+ { label: "Modes", value: pattern.linkedModeIds.length }
893
+ ],
894
+ owner: pattern,
895
+ href: getKnowledgeGraphEntityHref("behavior_pattern", pattern.id),
896
+ updatedAt: pattern.updatedAt
897
+ }));
898
+ for (const linkedId of pattern.linkedValueIds) {
899
+ addEdge(edges, {
900
+ source: buildKnowledgeGraphNodeId("behavior_pattern", pattern.id),
901
+ target: buildKnowledgeGraphNodeId("psyche_value", linkedId),
902
+ relationKind: "pattern_value",
903
+ label: "Pattern to value",
904
+ strength: 0.78,
905
+ directional: true,
906
+ structural: false
907
+ });
908
+ }
909
+ for (const linkedId of pattern.linkedBeliefIds) {
910
+ addEdge(edges, {
911
+ source: buildKnowledgeGraphNodeId("behavior_pattern", pattern.id),
912
+ target: buildKnowledgeGraphNodeId("belief_entry", linkedId),
913
+ relationKind: "pattern_belief",
914
+ label: "Pattern to belief",
915
+ strength: 0.76,
916
+ directional: true,
917
+ structural: false
918
+ });
919
+ }
920
+ for (const linkedId of pattern.linkedModeIds) {
921
+ addEdge(edges, {
922
+ source: buildKnowledgeGraphNodeId("behavior_pattern", pattern.id),
923
+ target: buildKnowledgeGraphNodeId("mode_profile", linkedId),
924
+ relationKind: "pattern_mode",
925
+ label: "Pattern to mode",
926
+ strength: 0.76,
927
+ directional: true,
928
+ structural: false
929
+ });
930
+ }
931
+ }
932
+ for (const behavior of behaviors) {
933
+ nodes.set(buildKnowledgeGraphNodeId("behavior", behavior.id), makeNode({
934
+ entityType: "behavior",
935
+ entityId: behavior.id,
936
+ entityKind: "behavior",
937
+ title: behavior.title,
938
+ subtitle: behavior.kind,
939
+ description: behavior.description,
940
+ previewStats: [
941
+ { label: "Patterns", value: behavior.linkedPatternIds.length },
942
+ { label: "Values", value: behavior.linkedValueIds.length },
943
+ { label: "Modes", value: behavior.linkedModeIds.length }
944
+ ],
945
+ owner: behavior,
946
+ href: getKnowledgeGraphEntityHref("behavior", behavior.id),
947
+ updatedAt: behavior.updatedAt
948
+ }));
949
+ for (const linkedId of behavior.linkedPatternIds) {
950
+ addEdge(edges, {
951
+ source: buildKnowledgeGraphNodeId("behavior", behavior.id),
952
+ target: buildKnowledgeGraphNodeId("behavior_pattern", linkedId),
953
+ relationKind: "behavior_pattern",
954
+ label: "Behavior to pattern",
955
+ strength: 0.8,
956
+ directional: true,
957
+ structural: false
958
+ });
959
+ }
960
+ for (const linkedId of behavior.linkedValueIds) {
961
+ addEdge(edges, {
962
+ source: buildKnowledgeGraphNodeId("behavior", behavior.id),
963
+ target: buildKnowledgeGraphNodeId("psyche_value", linkedId),
964
+ relationKind: "behavior_value",
965
+ label: "Behavior to value",
966
+ strength: 0.76,
967
+ directional: true,
968
+ structural: false
969
+ });
970
+ }
971
+ for (const linkedId of behavior.linkedSchemaIds) {
972
+ addEdge(edges, {
973
+ source: buildKnowledgeGraphNodeId("behavior", behavior.id),
974
+ target: buildKnowledgeGraphNodeId("belief_entry", linkedId),
975
+ relationKind: "behavior_belief",
976
+ label: "Behavior to belief",
977
+ strength: 0.74,
978
+ directional: true,
979
+ structural: false
980
+ });
981
+ }
982
+ for (const linkedId of behavior.linkedModeIds) {
983
+ addEdge(edges, {
984
+ source: buildKnowledgeGraphNodeId("behavior", behavior.id),
985
+ target: buildKnowledgeGraphNodeId("mode_profile", linkedId),
986
+ relationKind: "behavior_mode",
987
+ label: "Behavior to mode",
988
+ strength: 0.74,
989
+ directional: true,
990
+ structural: false
991
+ });
992
+ }
993
+ }
994
+ for (const belief of beliefs) {
995
+ nodes.set(buildKnowledgeGraphNodeId("belief_entry", belief.id), makeNode({
996
+ entityType: "belief_entry",
997
+ entityId: belief.id,
998
+ entityKind: "belief",
999
+ title: truncate(belief.statement, 82),
1000
+ subtitle: belief.beliefType,
1001
+ description: belief.flexibleAlternative || belief.originNote,
1002
+ previewStats: [
1003
+ { label: "Confidence", value: `${belief.confidence}%` },
1004
+ { label: "Values", value: belief.linkedValueIds.length },
1005
+ { label: "Reports", value: belief.linkedReportIds.length }
1006
+ ],
1007
+ owner: belief,
1008
+ href: getKnowledgeGraphEntityHref("belief_entry", belief.id),
1009
+ updatedAt: belief.updatedAt
1010
+ }));
1011
+ for (const linkedId of belief.linkedValueIds) {
1012
+ addEdge(edges, {
1013
+ source: buildKnowledgeGraphNodeId("belief_entry", belief.id),
1014
+ target: buildKnowledgeGraphNodeId("psyche_value", linkedId),
1015
+ relationKind: "belief_value",
1016
+ label: "Belief to value",
1017
+ strength: 0.76,
1018
+ directional: true,
1019
+ structural: false
1020
+ });
1021
+ }
1022
+ for (const linkedId of belief.linkedBehaviorIds) {
1023
+ addEdge(edges, {
1024
+ source: buildKnowledgeGraphNodeId("belief_entry", belief.id),
1025
+ target: buildKnowledgeGraphNodeId("behavior", linkedId),
1026
+ relationKind: "belief_behavior",
1027
+ label: "Belief to behavior",
1028
+ strength: 0.74,
1029
+ directional: true,
1030
+ structural: false
1031
+ });
1032
+ }
1033
+ for (const linkedId of belief.linkedModeIds) {
1034
+ addEdge(edges, {
1035
+ source: buildKnowledgeGraphNodeId("belief_entry", belief.id),
1036
+ target: buildKnowledgeGraphNodeId("mode_profile", linkedId),
1037
+ relationKind: "belief_mode",
1038
+ label: "Belief to mode",
1039
+ strength: 0.74,
1040
+ directional: true,
1041
+ structural: false
1042
+ });
1043
+ }
1044
+ for (const linkedId of belief.linkedReportIds) {
1045
+ addEdge(edges, {
1046
+ source: buildKnowledgeGraphNodeId("belief_entry", belief.id),
1047
+ target: buildKnowledgeGraphNodeId("trigger_report", linkedId),
1048
+ relationKind: "belief_report",
1049
+ label: "Belief to report",
1050
+ strength: 0.72,
1051
+ directional: true,
1052
+ structural: false
1053
+ });
1054
+ }
1055
+ }
1056
+ for (const mode of modes) {
1057
+ nodes.set(buildKnowledgeGraphNodeId("mode_profile", mode.id), makeNode({
1058
+ entityType: "mode_profile",
1059
+ entityId: mode.id,
1060
+ entityKind: "mode",
1061
+ title: mode.title,
1062
+ subtitle: mode.family.replaceAll("_", " "),
1063
+ description: mode.persona || mode.protectiveJob,
1064
+ previewStats: [
1065
+ { label: "Family", value: mode.family.replaceAll("_", " ") },
1066
+ { label: "Patterns", value: mode.linkedPatternIds.length },
1067
+ { label: "Behaviors", value: mode.linkedBehaviorIds.length }
1068
+ ],
1069
+ owner: mode,
1070
+ href: getKnowledgeGraphEntityHref("mode_profile", mode.id),
1071
+ updatedAt: mode.updatedAt
1072
+ }));
1073
+ for (const linkedId of mode.linkedPatternIds) {
1074
+ addEdge(edges, {
1075
+ source: buildKnowledgeGraphNodeId("mode_profile", mode.id),
1076
+ target: buildKnowledgeGraphNodeId("behavior_pattern", linkedId),
1077
+ relationKind: "mode_pattern",
1078
+ label: "Mode to pattern",
1079
+ strength: 0.76,
1080
+ directional: true,
1081
+ structural: false
1082
+ });
1083
+ }
1084
+ for (const linkedId of mode.linkedBehaviorIds) {
1085
+ addEdge(edges, {
1086
+ source: buildKnowledgeGraphNodeId("mode_profile", mode.id),
1087
+ target: buildKnowledgeGraphNodeId("behavior", linkedId),
1088
+ relationKind: "mode_behavior",
1089
+ label: "Mode to behavior",
1090
+ strength: 0.74,
1091
+ directional: true,
1092
+ structural: false
1093
+ });
1094
+ }
1095
+ for (const linkedId of mode.linkedValueIds) {
1096
+ addEdge(edges, {
1097
+ source: buildKnowledgeGraphNodeId("mode_profile", mode.id),
1098
+ target: buildKnowledgeGraphNodeId("psyche_value", linkedId),
1099
+ relationKind: "mode_value",
1100
+ label: "Mode to value",
1101
+ strength: 0.74,
1102
+ directional: true,
1103
+ structural: false
1104
+ });
1105
+ }
1106
+ }
1107
+ const modeByGuideKey = new Map(modes.map((mode) => [
1108
+ `${mode.family}::${mode.archetype}`.toLowerCase(),
1109
+ mode
1110
+ ]));
1111
+ for (const session of modeSessions) {
1112
+ nodes.set(buildKnowledgeGraphNodeId("mode_guide_session", session.id), makeNode({
1113
+ entityType: "mode_guide_session",
1114
+ entityId: session.id,
1115
+ entityKind: "mode_session",
1116
+ title: truncate(session.summary, 84),
1117
+ subtitle: `${session.results.length} results`,
1118
+ description: session.summary,
1119
+ previewStats: [
1120
+ { label: "Results", value: session.results.length },
1121
+ { label: "Answers", value: session.answers.length }
1122
+ ],
1123
+ owner: session,
1124
+ href: getKnowledgeGraphEntityHref("mode_guide_session", session.id),
1125
+ updatedAt: session.updatedAt
1126
+ }));
1127
+ for (const result of session.results) {
1128
+ const matchedMode = modeByGuideKey.get(`${result.family}::${result.archetype}`.toLowerCase()) ??
1129
+ modes.find((mode) => mode.family === result.family &&
1130
+ (mode.title.toLowerCase() === result.label.toLowerCase() ||
1131
+ mode.archetype.toLowerCase() === result.label.toLowerCase()));
1132
+ if (!matchedMode) {
1133
+ continue;
1134
+ }
1135
+ addEdge(edges, {
1136
+ source: buildKnowledgeGraphNodeId("mode_guide_session", session.id),
1137
+ target: buildKnowledgeGraphNodeId("mode_profile", matchedMode.id),
1138
+ relationKind: "mode_session_mode",
1139
+ label: "Session suggests mode",
1140
+ strength: Math.max(0.6, Math.min(1, result.confidence)),
1141
+ directional: true,
1142
+ structural: false
1143
+ });
1144
+ }
1145
+ }
1146
+ for (const report of reports) {
1147
+ nodes.set(buildKnowledgeGraphNodeId("trigger_report", report.id), makeNode({
1148
+ entityType: "trigger_report",
1149
+ entityId: report.id,
1150
+ entityKind: "report",
1151
+ title: report.title,
1152
+ subtitle: report.status,
1153
+ description: report.eventSituation,
1154
+ previewStats: [
1155
+ { label: "Status", value: report.status },
1156
+ { label: "Occurred", value: report.occurredAt ? new Date(report.occurredAt).toLocaleDateString() : "Draft" },
1157
+ { label: "Next moves", value: report.nextMoves.length }
1158
+ ],
1159
+ owner: report,
1160
+ href: getKnowledgeGraphEntityHref("trigger_report", report.id),
1161
+ updatedAt: report.updatedAt
1162
+ }));
1163
+ if (report.eventTypeId) {
1164
+ addEdge(edges, {
1165
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1166
+ target: buildKnowledgeGraphNodeId("event_type", report.eventTypeId),
1167
+ relationKind: "report_event_type",
1168
+ label: "Categorized as event type",
1169
+ strength: 0.84,
1170
+ directional: true,
1171
+ structural: false
1172
+ });
1173
+ }
1174
+ for (const emotion of report.emotions) {
1175
+ if (!emotion.emotionDefinitionId) {
1176
+ continue;
1177
+ }
1178
+ addEdge(edges, {
1179
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1180
+ target: buildKnowledgeGraphNodeId("emotion_definition", emotion.emotionDefinitionId),
1181
+ relationKind: "report_emotion",
1182
+ label: "Records emotion",
1183
+ strength: Math.max(0.64, Math.min(0.92, emotion.intensity / 10)),
1184
+ directional: true,
1185
+ structural: false
1186
+ });
1187
+ }
1188
+ for (const linkedId of report.linkedValueIds) {
1189
+ addEdge(edges, {
1190
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1191
+ target: buildKnowledgeGraphNodeId("psyche_value", linkedId),
1192
+ relationKind: "report_value",
1193
+ label: "Report to value",
1194
+ strength: 0.8,
1195
+ directional: true,
1196
+ structural: false
1197
+ });
1198
+ }
1199
+ for (const linkedId of report.linkedPatternIds) {
1200
+ addEdge(edges, {
1201
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1202
+ target: buildKnowledgeGraphNodeId("behavior_pattern", linkedId),
1203
+ relationKind: "report_pattern",
1204
+ label: "Report to pattern",
1205
+ strength: 0.78,
1206
+ directional: true,
1207
+ structural: false
1208
+ });
1209
+ }
1210
+ for (const linkedId of report.linkedGoalIds) {
1211
+ addEdge(edges, {
1212
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1213
+ target: buildKnowledgeGraphNodeId("goal", linkedId),
1214
+ relationKind: "report_goal",
1215
+ label: "Report to goal",
1216
+ strength: 0.78,
1217
+ directional: true,
1218
+ structural: false
1219
+ });
1220
+ }
1221
+ for (const linkedId of report.linkedProjectIds) {
1222
+ addEdge(edges, {
1223
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1224
+ target: buildKnowledgeGraphNodeId("project", linkedId),
1225
+ relationKind: "report_project",
1226
+ label: "Report to project",
1227
+ strength: 0.78,
1228
+ directional: true,
1229
+ structural: false
1230
+ });
1231
+ }
1232
+ for (const linkedId of report.linkedTaskIds) {
1233
+ addEdge(edges, {
1234
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1235
+ target: buildKnowledgeGraphNodeId("task", linkedId),
1236
+ relationKind: "report_task",
1237
+ label: "Report to task",
1238
+ strength: 0.78,
1239
+ directional: true,
1240
+ structural: false
1241
+ });
1242
+ }
1243
+ for (const linkedId of report.linkedBehaviorIds) {
1244
+ addEdge(edges, {
1245
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1246
+ target: buildKnowledgeGraphNodeId("behavior", linkedId),
1247
+ relationKind: "report_behavior",
1248
+ label: "Report to behavior",
1249
+ strength: 0.76,
1250
+ directional: true,
1251
+ structural: false
1252
+ });
1253
+ }
1254
+ for (const linkedId of report.linkedBeliefIds) {
1255
+ addEdge(edges, {
1256
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1257
+ target: buildKnowledgeGraphNodeId("belief_entry", linkedId),
1258
+ relationKind: "report_belief",
1259
+ label: "Report to belief",
1260
+ strength: 0.76,
1261
+ directional: true,
1262
+ structural: false
1263
+ });
1264
+ }
1265
+ for (const linkedId of report.linkedModeIds) {
1266
+ addEdge(edges, {
1267
+ source: buildKnowledgeGraphNodeId("trigger_report", report.id),
1268
+ target: buildKnowledgeGraphNodeId("mode_profile", linkedId),
1269
+ relationKind: "report_mode",
1270
+ label: "Report to mode",
1271
+ strength: 0.76,
1272
+ directional: true,
1273
+ structural: false
1274
+ });
1275
+ }
1276
+ }
1277
+ const discoveredWorkbenchSurfaceIds = new Set(["workbench"]);
1278
+ for (const flow of flows) {
1279
+ if (flow.homeSurfaceId) {
1280
+ discoveredWorkbenchSurfaceIds.add(flow.homeSurfaceId);
1281
+ }
1282
+ }
1283
+ for (const surfaceId of discoveredWorkbenchSurfaceIds) {
1284
+ const surfaceMeta = WORKBENCH_SURFACE_ROUTES[surfaceId] ?? {
1285
+ title: surfaceId.replace(/[-_]+/g, " ").replace(/\b\w/g, (value) => value.toUpperCase()),
1286
+ subtitle: "Workbench route surface",
1287
+ href: `/workbench?surface=${encodeURIComponent(surfaceId)}`
1288
+ };
1289
+ nodes.set(buildKnowledgeGraphNodeId("workbench_surface", surfaceId), makeNode({
1290
+ entityType: "workbench_surface",
1291
+ entityId: surfaceId,
1292
+ entityKind: "workbench",
1293
+ title: surfaceMeta.title,
1294
+ subtitle: surfaceMeta.subtitle,
1295
+ description: surfaceId === "workbench"
1296
+ ? "Forge's top-level graph-flow workspace for functors, chats, and published outputs."
1297
+ : `Workbench surface routed into ${surfaceMeta.href}.`,
1298
+ previewStats: surfaceId === "workbench" ? [{ label: "Flows", value: flows.length }] : [],
1299
+ href: surfaceMeta.href
1300
+ }));
1301
+ if (surfaceId !== "workbench") {
1302
+ addEdge(edges, {
1303
+ source: buildKnowledgeGraphNodeId("workbench_surface", "workbench"),
1304
+ target: buildKnowledgeGraphNodeId("workbench_surface", surfaceId),
1305
+ relationKind: "workbench_route",
1306
+ label: "Route surface",
1307
+ strength: 0.82,
1308
+ directional: true,
1309
+ structural: true
1310
+ });
1311
+ }
1312
+ }
1313
+ for (const flow of flows) {
1314
+ const entityKind = flow.kind === "chat" ? "chat" : "functor";
1315
+ nodes.set(buildKnowledgeGraphNodeId("workbench_flow", flow.id), makeNode({
1316
+ entityType: "workbench_flow",
1317
+ entityId: flow.id,
1318
+ entityKind,
1319
+ title: flow.title,
1320
+ subtitle: flow.kind,
1321
+ description: flow.description,
1322
+ previewStats: [
1323
+ { label: "Kind", value: flow.kind },
1324
+ { label: "Nodes", value: flow.graph.nodes.length },
1325
+ { label: "Public inputs", value: flow.publicInputs.length }
1326
+ ],
1327
+ href: getKnowledgeGraphEntityHref("workbench_flow", flow.id, {
1328
+ workbenchKind: flow.kind
1329
+ }),
1330
+ updatedAt: flow.updatedAt
1331
+ }));
1332
+ addEdge(edges, {
1333
+ source: buildKnowledgeGraphNodeId("workbench_surface", flow.homeSurfaceId ?? "workbench"),
1334
+ target: buildKnowledgeGraphNodeId("workbench_flow", flow.id),
1335
+ relationKind: "workbench_flow",
1336
+ label: flow.homeSurfaceId ? "Home surface flow" : "Contains flow",
1337
+ strength: 0.88,
1338
+ directional: true,
1339
+ structural: true
1340
+ });
1341
+ }
1342
+ const graphNodes = [...nodes.values()];
1343
+ const validNodeIds = new Set(graphNodes.map((node) => node.id));
1344
+ const graphEdges = [...edges.values()].filter((edge) => validNodeIds.has(edge.source) && validNodeIds.has(edge.target));
1345
+ const degreeById = new Map();
1346
+ for (const edge of graphEdges) {
1347
+ for (const nodeId of [edge.source, edge.target]) {
1348
+ const current = degreeById.get(nodeId) ?? {
1349
+ degree: 0,
1350
+ structuralDegree: 0,
1351
+ contextualDegree: 0,
1352
+ taxonomyDegree: 0,
1353
+ workspaceDegree: 0
1354
+ };
1355
+ current.degree += 1;
1356
+ if (edge.family === "structural") {
1357
+ current.structuralDegree += 1;
1358
+ }
1359
+ else if (edge.family === "contextual") {
1360
+ current.contextualDegree += 1;
1361
+ }
1362
+ else if (edge.family === "taxonomy") {
1363
+ current.taxonomyDegree += 1;
1364
+ }
1365
+ else if (edge.family === "workspace") {
1366
+ current.workspaceDegree += 1;
1367
+ }
1368
+ degreeById.set(nodeId, current);
1369
+ }
1370
+ }
1371
+ const sizedNodes = graphNodes.map((node) => {
1372
+ const degreeStats = degreeById.get(node.id) ?? {
1373
+ degree: 0,
1374
+ structuralDegree: 0,
1375
+ contextualDegree: 0,
1376
+ taxonomyDegree: 0,
1377
+ workspaceDegree: 0
1378
+ };
1379
+ const visual = getEntityVisual(node.entityKind);
1380
+ const importance = node.importance + degreeStats.degree * 1.6;
1381
+ const size = Math.min(88, node.size + degreeStats.degree * 1.35);
1382
+ return {
1383
+ ...node,
1384
+ graphHref: buildKnowledgeGraphFocusHref(node.entityType, node.entityId),
1385
+ iconName: visual.iconName,
1386
+ accentToken: visual.colorToken.cssVariable,
1387
+ graphStats: degreeStats,
1388
+ importance,
1389
+ size
1390
+ };
1391
+ });
1392
+ const kinds = sizedNodes.reduce((counts, node) => {
1393
+ counts[node.entityKind] = (counts[node.entityKind] ?? 0) + 1;
1394
+ return counts;
1395
+ }, {});
1396
+ const relationKinds = graphEdges.reduce((counts, edge) => {
1397
+ counts[edge.relationKind] = (counts[edge.relationKind] ?? 0) + 1;
1398
+ return counts;
1399
+ }, {});
1400
+ const baseGraph = {
1401
+ generatedAt: new Date().toISOString(),
1402
+ nodes: sizedNodes,
1403
+ edges: graphEdges,
1404
+ facets: buildKnowledgeGraphFacets(sizedNodes, graphEdges),
1405
+ counts: {
1406
+ nodeCount: sizedNodes.length,
1407
+ edgeCount: graphEdges.length,
1408
+ totalNodeCount: sizedNodes.length,
1409
+ totalEdgeCount: graphEdges.length,
1410
+ filteredNodeCount: sizedNodes.length,
1411
+ filteredEdgeCount: graphEdges.length,
1412
+ kinds,
1413
+ relationKinds,
1414
+ limited: false
1415
+ }
1416
+ };
1417
+ const filteredGraph = filterKnowledgeGraphData(baseGraph, query);
1418
+ const visibleNodeIds = selectKnowledgeGraphVisibleNodeIds({
1419
+ nodes: filteredGraph.nodes,
1420
+ edges: filteredGraph.edges,
1421
+ limit: query.limit,
1422
+ focusNodeId: query.focusNodeId
1423
+ });
1424
+ const visibleNodes = filteredGraph.nodes.filter((node) => visibleNodeIds.has(node.id));
1425
+ const visibleEdges = filteredGraph.edges.filter((edge) => visibleNodeIds.has(edge.source) && visibleNodeIds.has(edge.target));
1426
+ const visibleKinds = visibleNodes.reduce((counts, node) => {
1427
+ counts[node.entityKind] = (counts[node.entityKind] ?? 0) + 1;
1428
+ return counts;
1429
+ }, {});
1430
+ const visibleRelationKinds = visibleEdges.reduce((counts, edge) => {
1431
+ counts[edge.relationKind] = (counts[edge.relationKind] ?? 0) + 1;
1432
+ return counts;
1433
+ }, {});
1434
+ return {
1435
+ generatedAt: new Date().toISOString(),
1436
+ nodes: visibleNodes,
1437
+ edges: visibleEdges,
1438
+ facets: buildKnowledgeGraphFacets(filteredGraph.nodes, filteredGraph.edges),
1439
+ counts: {
1440
+ nodeCount: visibleNodes.length,
1441
+ edgeCount: visibleEdges.length,
1442
+ totalNodeCount: baseGraph.counts.totalNodeCount,
1443
+ totalEdgeCount: baseGraph.counts.totalEdgeCount,
1444
+ filteredNodeCount: filteredGraph.nodes.length,
1445
+ filteredEdgeCount: filteredGraph.edges.length,
1446
+ kinds: visibleKinds,
1447
+ relationKinds: visibleRelationKinds,
1448
+ limited: visibleNodes.length < filteredGraph.nodes.length
1449
+ }
1450
+ };
1451
+ }
1452
+ export function buildKnowledgeGraphFocus(entityType, entityId, userIds) {
1453
+ const graph = buildKnowledgeGraph(userIds);
1454
+ return buildFocusPayload(graph, buildKnowledgeGraphNodeId(entityType, entityId));
1455
+ }