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,195 @@
1
+ CREATE TABLE IF NOT EXISTS forge_events (
2
+ id TEXT PRIMARY KEY,
3
+ preferred_connection_id TEXT,
4
+ preferred_calendar_id TEXT,
5
+ ownership TEXT NOT NULL DEFAULT 'forge',
6
+ origin_type TEXT NOT NULL DEFAULT 'native',
7
+ status TEXT NOT NULL DEFAULT 'confirmed',
8
+ title TEXT NOT NULL,
9
+ description TEXT NOT NULL DEFAULT '',
10
+ location TEXT NOT NULL DEFAULT '',
11
+ start_at TEXT NOT NULL,
12
+ end_at TEXT NOT NULL,
13
+ timezone TEXT NOT NULL DEFAULT 'UTC',
14
+ is_all_day INTEGER NOT NULL DEFAULT 0,
15
+ availability TEXT NOT NULL DEFAULT 'busy',
16
+ event_type TEXT NOT NULL DEFAULT '',
17
+ categories_json TEXT NOT NULL DEFAULT '[]',
18
+ deleted_at TEXT,
19
+ created_at TEXT NOT NULL,
20
+ updated_at TEXT NOT NULL,
21
+ FOREIGN KEY (preferred_connection_id) REFERENCES calendar_connections(id) ON DELETE SET NULL,
22
+ FOREIGN KEY (preferred_calendar_id) REFERENCES calendar_calendars(id) ON DELETE SET NULL
23
+ );
24
+
25
+ CREATE INDEX IF NOT EXISTS idx_forge_events_time
26
+ ON forge_events(start_at, end_at);
27
+
28
+ CREATE INDEX IF NOT EXISTS idx_forge_events_calendar
29
+ ON forge_events(preferred_calendar_id, start_at, end_at);
30
+
31
+ CREATE TABLE IF NOT EXISTS forge_event_sources (
32
+ id TEXT PRIMARY KEY,
33
+ forge_event_id TEXT NOT NULL,
34
+ provider TEXT NOT NULL,
35
+ connection_id TEXT,
36
+ calendar_id TEXT,
37
+ remote_calendar_id TEXT,
38
+ remote_event_id TEXT NOT NULL,
39
+ remote_uid TEXT,
40
+ recurrence_instance_id TEXT,
41
+ is_master_recurring INTEGER NOT NULL DEFAULT 0,
42
+ remote_href TEXT,
43
+ remote_etag TEXT,
44
+ sync_state TEXT NOT NULL DEFAULT 'synced',
45
+ raw_payload_json TEXT NOT NULL DEFAULT '{}',
46
+ last_synced_at TEXT,
47
+ created_at TEXT NOT NULL,
48
+ updated_at TEXT NOT NULL,
49
+ FOREIGN KEY (forge_event_id) REFERENCES forge_events(id) ON DELETE CASCADE,
50
+ FOREIGN KEY (connection_id) REFERENCES calendar_connections(id) ON DELETE SET NULL,
51
+ FOREIGN KEY (calendar_id) REFERENCES calendar_calendars(id) ON DELETE SET NULL,
52
+ UNIQUE(provider, connection_id, calendar_id, remote_event_id)
53
+ );
54
+
55
+ CREATE INDEX IF NOT EXISTS idx_forge_event_sources_event
56
+ ON forge_event_sources(forge_event_id);
57
+
58
+ CREATE INDEX IF NOT EXISTS idx_forge_event_sources_remote
59
+ ON forge_event_sources(connection_id, calendar_id, remote_event_id);
60
+
61
+ CREATE TABLE IF NOT EXISTS forge_event_links (
62
+ id TEXT PRIMARY KEY,
63
+ forge_event_id TEXT NOT NULL,
64
+ entity_type TEXT NOT NULL,
65
+ entity_id TEXT NOT NULL,
66
+ relationship_type TEXT NOT NULL DEFAULT 'context',
67
+ created_at TEXT NOT NULL,
68
+ updated_at TEXT NOT NULL,
69
+ FOREIGN KEY (forge_event_id) REFERENCES forge_events(id) ON DELETE CASCADE,
70
+ UNIQUE(forge_event_id, entity_type, entity_id, relationship_type)
71
+ );
72
+
73
+ CREATE INDEX IF NOT EXISTS idx_forge_event_links_entity
74
+ ON forge_event_links(entity_type, entity_id);
75
+
76
+ CREATE TABLE IF NOT EXISTS forge_event_metadata (
77
+ id TEXT PRIMARY KEY,
78
+ forge_event_id TEXT NOT NULL,
79
+ namespace TEXT NOT NULL,
80
+ key TEXT NOT NULL,
81
+ value_json TEXT NOT NULL DEFAULT 'null',
82
+ created_at TEXT NOT NULL,
83
+ updated_at TEXT NOT NULL,
84
+ FOREIGN KEY (forge_event_id) REFERENCES forge_events(id) ON DELETE CASCADE,
85
+ UNIQUE(forge_event_id, namespace, key)
86
+ );
87
+
88
+ ALTER TABLE task_timeboxes ADD COLUMN forge_event_id TEXT REFERENCES forge_events(id) ON DELETE SET NULL;
89
+
90
+ INSERT INTO forge_events (
91
+ id,
92
+ preferred_connection_id,
93
+ preferred_calendar_id,
94
+ ownership,
95
+ origin_type,
96
+ status,
97
+ title,
98
+ description,
99
+ location,
100
+ start_at,
101
+ end_at,
102
+ timezone,
103
+ is_all_day,
104
+ availability,
105
+ event_type,
106
+ categories_json,
107
+ deleted_at,
108
+ created_at,
109
+ updated_at
110
+ )
111
+ SELECT
112
+ calendar_events.id,
113
+ calendar_events.connection_id,
114
+ calendar_events.calendar_id,
115
+ calendar_events.ownership,
116
+ calendar_connections.provider,
117
+ calendar_events.status,
118
+ calendar_events.title,
119
+ calendar_events.description,
120
+ calendar_events.location,
121
+ calendar_events.start_at,
122
+ calendar_events.end_at,
123
+ COALESCE(calendar_calendars.timezone, 'UTC'),
124
+ calendar_events.is_all_day,
125
+ calendar_events.availability,
126
+ calendar_events.event_type,
127
+ calendar_events.categories_json,
128
+ calendar_events.deleted_at,
129
+ calendar_events.created_at,
130
+ calendar_events.updated_at
131
+ FROM calendar_events
132
+ LEFT JOIN calendar_connections
133
+ ON calendar_connections.id = calendar_events.connection_id
134
+ LEFT JOIN calendar_calendars
135
+ ON calendar_calendars.id = calendar_events.calendar_id
136
+ WHERE NOT EXISTS (
137
+ SELECT 1 FROM forge_events WHERE forge_events.id = calendar_events.id
138
+ );
139
+
140
+ INSERT INTO forge_event_sources (
141
+ id,
142
+ forge_event_id,
143
+ provider,
144
+ connection_id,
145
+ calendar_id,
146
+ remote_calendar_id,
147
+ remote_event_id,
148
+ remote_uid,
149
+ recurrence_instance_id,
150
+ is_master_recurring,
151
+ remote_href,
152
+ remote_etag,
153
+ sync_state,
154
+ raw_payload_json,
155
+ last_synced_at,
156
+ created_at,
157
+ updated_at
158
+ )
159
+ SELECT
160
+ 'evsrc_' || lower(hex(randomblob(5))),
161
+ calendar_events.id,
162
+ calendar_connections.provider,
163
+ calendar_events.connection_id,
164
+ calendar_events.calendar_id,
165
+ calendar_calendars.remote_id,
166
+ calendar_events.remote_id,
167
+ json_extract(calendar_events.raw_payload_json, '$.uid'),
168
+ json_extract(calendar_events.raw_payload_json, '$.recurrenceid'),
169
+ CASE
170
+ WHEN json_extract(calendar_events.raw_payload_json, '$.rrule') IS NOT NULL THEN 1
171
+ ELSE 0
172
+ END,
173
+ calendar_events.remote_href,
174
+ calendar_events.remote_etag,
175
+ CASE
176
+ WHEN calendar_events.deleted_at IS NOT NULL THEN 'deleted'
177
+ ELSE 'synced'
178
+ END,
179
+ calendar_events.raw_payload_json,
180
+ COALESCE(calendar_events.remote_updated_at, calendar_events.updated_at),
181
+ calendar_events.created_at,
182
+ calendar_events.updated_at
183
+ FROM calendar_events
184
+ LEFT JOIN calendar_connections
185
+ ON calendar_connections.id = calendar_events.connection_id
186
+ LEFT JOIN calendar_calendars
187
+ ON calendar_calendars.id = calendar_events.calendar_id
188
+ WHERE NOT EXISTS (
189
+ SELECT 1
190
+ FROM forge_event_sources
191
+ WHERE forge_event_sources.forge_event_id = calendar_events.id
192
+ AND forge_event_sources.connection_id = calendar_events.connection_id
193
+ AND forge_event_sources.calendar_id = calendar_events.calendar_id
194
+ AND forge_event_sources.remote_event_id = calendar_events.remote_id
195
+ );
@@ -0,0 +1,6 @@
1
+ ALTER TABLE calendar_calendars
2
+ ADD COLUMN selected_for_sync INTEGER NOT NULL DEFAULT 1;
3
+
4
+ UPDATE calendar_calendars
5
+ SET selected_for_sync = 1
6
+ WHERE selected_for_sync IS NULL;
@@ -0,0 +1,11 @@
1
+ UPDATE calendar_calendars
2
+ SET timezone = 'UTC'
3
+ WHERE TRIM(COALESCE(timezone, '')) = '';
4
+
5
+ UPDATE forge_events
6
+ SET timezone = 'UTC'
7
+ WHERE TRIM(COALESCE(timezone, '')) = '';
8
+
9
+ UPDATE work_block_templates
10
+ SET timezone = 'UTC'
11
+ WHERE TRIM(COALESCE(timezone, '')) = '';
@@ -0,0 +1,7 @@
1
+ ALTER TABLE work_block_templates ADD COLUMN starts_on TEXT;
2
+ ALTER TABLE work_block_templates ADD COLUMN ends_on TEXT;
3
+
4
+ CREATE INDEX IF NOT EXISTS idx_work_block_templates_active_window
5
+ ON work_block_templates(starts_on, ends_on, start_minute);
6
+
7
+ DROP TABLE IF EXISTS work_block_instances;
@@ -0,0 +1,8 @@
1
+ ALTER TABLE app_settings
2
+ ADD COLUMN microsoft_client_id TEXT NOT NULL DEFAULT '';
3
+
4
+ ALTER TABLE app_settings
5
+ ADD COLUMN microsoft_tenant_id TEXT NOT NULL DEFAULT 'common';
6
+
7
+ ALTER TABLE app_settings
8
+ ADD COLUMN microsoft_redirect_uri TEXT NOT NULL DEFAULT '';
@@ -0,0 +1,8 @@
1
+ ALTER TABLE notes
2
+ ADD COLUMN tags_json TEXT NOT NULL DEFAULT '[]';
3
+
4
+ ALTER TABLE notes
5
+ ADD COLUMN destroy_at TEXT;
6
+
7
+ CREATE INDEX IF NOT EXISTS idx_notes_destroy_at
8
+ ON notes(destroy_at);
@@ -0,0 +1,244 @@
1
+ CREATE TABLE IF NOT EXISTS users (
2
+ id TEXT PRIMARY KEY,
3
+ kind TEXT NOT NULL CHECK (kind IN ('human', 'bot')),
4
+ handle TEXT NOT NULL UNIQUE,
5
+ display_name TEXT NOT NULL,
6
+ description TEXT NOT NULL DEFAULT '',
7
+ accent_color TEXT NOT NULL DEFAULT '#c0c1ff',
8
+ created_at TEXT NOT NULL,
9
+ updated_at TEXT NOT NULL
10
+ );
11
+
12
+ CREATE TABLE IF NOT EXISTS user_access_grants (
13
+ id TEXT PRIMARY KEY,
14
+ subject_user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
15
+ target_user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
16
+ access_level TEXT NOT NULL DEFAULT 'view',
17
+ config_json TEXT NOT NULL DEFAULT '{}',
18
+ created_at TEXT NOT NULL,
19
+ updated_at TEXT NOT NULL,
20
+ UNIQUE (subject_user_id, target_user_id, access_level)
21
+ );
22
+
23
+ CREATE TABLE IF NOT EXISTS entity_owners (
24
+ entity_type TEXT NOT NULL,
25
+ entity_id TEXT NOT NULL,
26
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
27
+ role TEXT NOT NULL DEFAULT 'owner',
28
+ created_at TEXT NOT NULL,
29
+ updated_at TEXT NOT NULL,
30
+ PRIMARY KEY (entity_type, entity_id)
31
+ );
32
+
33
+ CREATE TABLE IF NOT EXISTS strategies (
34
+ id TEXT PRIMARY KEY,
35
+ title TEXT NOT NULL,
36
+ overview TEXT NOT NULL DEFAULT '',
37
+ end_state_description TEXT NOT NULL DEFAULT '',
38
+ status TEXT NOT NULL DEFAULT 'active',
39
+ target_goal_ids_json TEXT NOT NULL DEFAULT '[]',
40
+ target_project_ids_json TEXT NOT NULL DEFAULT '[]',
41
+ linked_entities_json TEXT NOT NULL DEFAULT '[]',
42
+ graph_json TEXT NOT NULL DEFAULT '{"nodes":[],"edges":[]}',
43
+ created_at TEXT NOT NULL,
44
+ updated_at TEXT NOT NULL
45
+ );
46
+
47
+ CREATE INDEX IF NOT EXISTS idx_users_kind ON users(kind, display_name);
48
+ CREATE INDEX IF NOT EXISTS idx_entity_owners_user ON entity_owners(user_id, entity_type, entity_id);
49
+ CREATE INDEX IF NOT EXISTS idx_strategies_status ON strategies(status, updated_at DESC);
50
+
51
+ INSERT OR IGNORE INTO users (
52
+ id,
53
+ kind,
54
+ handle,
55
+ display_name,
56
+ description,
57
+ accent_color,
58
+ created_at,
59
+ updated_at
60
+ )
61
+ VALUES (
62
+ 'user_operator',
63
+ 'human',
64
+ 'operator',
65
+ 'Operator',
66
+ 'Primary human Forge operator.',
67
+ '#f4b97a',
68
+ CURRENT_TIMESTAMP,
69
+ CURRENT_TIMESTAMP
70
+ );
71
+
72
+ UPDATE users
73
+ SET handle = COALESCE(
74
+ (
75
+ SELECT CASE
76
+ WHEN trim(lower(replace(replace(replace(operator_name, ' ', '_'), '-', '_'), '.', ''))) = '' THEN 'operator'
77
+ ELSE trim(lower(replace(replace(replace(operator_name, ' ', '_'), '-', '_'), '.', '')))
78
+ END
79
+ FROM app_settings
80
+ WHERE id = 1
81
+ ),
82
+ handle
83
+ ),
84
+ display_name = COALESCE(
85
+ (
86
+ SELECT CASE
87
+ WHEN trim(operator_name) = '' THEN 'Operator'
88
+ ELSE trim(operator_name)
89
+ END
90
+ FROM app_settings
91
+ WHERE id = 1
92
+ ),
93
+ display_name
94
+ ),
95
+ updated_at = CURRENT_TIMESTAMP
96
+ WHERE id = 'user_operator';
97
+
98
+ INSERT OR IGNORE INTO users (
99
+ id,
100
+ kind,
101
+ handle,
102
+ display_name,
103
+ description,
104
+ accent_color,
105
+ created_at,
106
+ updated_at
107
+ )
108
+ VALUES (
109
+ 'user_forge_bot',
110
+ 'bot',
111
+ 'forge_bot',
112
+ 'Forge Bot',
113
+ 'Autonomous or semi-autonomous execution partner inside Forge.',
114
+ '#7dd3fc',
115
+ CURRENT_TIMESTAMP,
116
+ CURRENT_TIMESTAMP
117
+ );
118
+
119
+ INSERT OR IGNORE INTO users (
120
+ id,
121
+ kind,
122
+ handle,
123
+ display_name,
124
+ description,
125
+ accent_color,
126
+ created_at,
127
+ updated_at
128
+ )
129
+ SELECT
130
+ 'user_human_' || lower(hex(substr(owner, 1, 16))),
131
+ 'human',
132
+ trim(lower(replace(replace(replace(owner, ' ', '_'), '-', '_'), '.', ''))),
133
+ trim(owner),
134
+ 'Backfilled from existing task ownership labels.',
135
+ '#f4b97a',
136
+ CURRENT_TIMESTAMP,
137
+ CURRENT_TIMESTAMP
138
+ FROM tasks
139
+ WHERE trim(owner) != ''
140
+ AND lower(trim(owner)) NOT IN (SELECT lower(display_name) FROM users)
141
+ GROUP BY trim(owner);
142
+
143
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
144
+ SELECT 'goal', id, 'user_operator', 'owner', created_at, updated_at FROM goals;
145
+
146
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
147
+ SELECT 'project', id, 'user_operator', 'owner', created_at, updated_at FROM projects;
148
+
149
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
150
+ SELECT
151
+ 'task',
152
+ tasks.id,
153
+ COALESCE(
154
+ (
155
+ SELECT users.id
156
+ FROM users
157
+ WHERE lower(users.display_name) = lower(trim(tasks.owner))
158
+ OR lower(users.handle) = lower(trim(replace(replace(replace(tasks.owner, ' ', '_'), '-', '_'), '.', '')))
159
+ ORDER BY CASE WHEN users.kind = 'human' THEN 0 ELSE 1 END, users.created_at
160
+ LIMIT 1
161
+ ),
162
+ 'user_operator'
163
+ ),
164
+ 'owner',
165
+ tasks.created_at,
166
+ tasks.updated_at
167
+ FROM tasks;
168
+
169
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
170
+ SELECT 'habit', id, 'user_operator', 'owner', created_at, updated_at FROM habits;
171
+
172
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
173
+ SELECT 'tag', id, 'user_operator', 'owner', created_at, created_at FROM tags;
174
+
175
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
176
+ SELECT 'note', id, 'user_operator', 'owner', created_at, updated_at FROM notes;
177
+
178
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
179
+ SELECT 'insight', id, 'user_operator', 'owner', created_at, updated_at FROM insights;
180
+
181
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
182
+ SELECT 'calendar_event', id, 'user_operator', 'owner', created_at, updated_at FROM calendar_events;
183
+
184
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
185
+ SELECT 'work_block_template', id, 'user_operator', 'owner', created_at, updated_at FROM work_block_templates;
186
+
187
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
188
+ SELECT 'task_timebox', id, 'user_operator', 'owner', created_at, updated_at FROM task_timeboxes;
189
+
190
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
191
+ SELECT 'psyche_value', id, 'user_operator', 'owner', created_at, updated_at FROM psyche_values;
192
+
193
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
194
+ SELECT 'behavior_pattern', id, 'user_operator', 'owner', created_at, updated_at FROM behavior_patterns;
195
+
196
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
197
+ SELECT 'behavior', id, 'user_operator', 'owner', created_at, updated_at FROM psyche_behaviors;
198
+
199
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
200
+ SELECT 'belief_entry', id, 'user_operator', 'owner', created_at, updated_at FROM belief_entries;
201
+
202
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
203
+ SELECT 'mode_profile', id, 'user_operator', 'owner', created_at, updated_at FROM mode_profiles;
204
+
205
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
206
+ SELECT 'mode_guide_session', id, 'user_operator', 'owner', created_at, updated_at FROM mode_guide_sessions;
207
+
208
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
209
+ SELECT 'event_type', id, 'user_operator', 'owner', created_at, updated_at FROM event_types;
210
+
211
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
212
+ SELECT 'emotion_definition', id, 'user_operator', 'owner', created_at, updated_at FROM emotion_definitions;
213
+
214
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
215
+ SELECT 'trigger_report', id, 'user_operator', 'owner', created_at, updated_at FROM trigger_reports;
216
+
217
+ INSERT OR IGNORE INTO entity_owners (entity_type, entity_id, user_id, role, created_at, updated_at)
218
+ SELECT 'strategy', id, 'user_operator', 'owner', created_at, updated_at FROM strategies;
219
+
220
+ INSERT OR IGNORE INTO user_access_grants (
221
+ id,
222
+ subject_user_id,
223
+ target_user_id,
224
+ access_level,
225
+ config_json,
226
+ created_at,
227
+ updated_at
228
+ )
229
+ SELECT
230
+ 'grant_' || lower(hex(randomblob(8))),
231
+ subject_users.id,
232
+ target_users.id,
233
+ CASE
234
+ WHEN subject_users.id = target_users.id THEN 'manage'
235
+ ELSE 'view'
236
+ END,
237
+ CASE
238
+ WHEN subject_users.id = target_users.id THEN '{"self":true,"mutable":true}'
239
+ ELSE '{"discoverable":true,"linkedEntities":true}'
240
+ END,
241
+ CURRENT_TIMESTAMP,
242
+ CURRENT_TIMESTAMP
243
+ FROM users AS subject_users
244
+ CROSS JOIN users AS target_users;
@@ -0,0 +1,158 @@
1
+ CREATE TABLE IF NOT EXISTS companion_pairing_sessions (
2
+ id TEXT PRIMARY KEY,
3
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
4
+ label TEXT NOT NULL DEFAULT '',
5
+ pairing_token TEXT NOT NULL,
6
+ status TEXT NOT NULL DEFAULT 'pending',
7
+ capability_flags_json TEXT NOT NULL DEFAULT '[]',
8
+ device_name TEXT,
9
+ platform TEXT,
10
+ app_version TEXT,
11
+ api_base_url TEXT NOT NULL DEFAULT '',
12
+ last_seen_at TEXT,
13
+ last_sync_at TEXT,
14
+ last_sync_error TEXT,
15
+ paired_at TEXT,
16
+ expires_at TEXT NOT NULL,
17
+ created_at TEXT NOT NULL,
18
+ updated_at TEXT NOT NULL
19
+ );
20
+
21
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_companion_pairing_token
22
+ ON companion_pairing_sessions(pairing_token);
23
+
24
+ CREATE INDEX IF NOT EXISTS idx_companion_pairing_user
25
+ ON companion_pairing_sessions(user_id, status, updated_at DESC);
26
+
27
+ CREATE TABLE IF NOT EXISTS health_import_runs (
28
+ id TEXT PRIMARY KEY,
29
+ pairing_session_id TEXT REFERENCES companion_pairing_sessions(id) ON DELETE SET NULL,
30
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
31
+ source TEXT NOT NULL,
32
+ source_device TEXT NOT NULL DEFAULT '',
33
+ status TEXT NOT NULL DEFAULT 'completed',
34
+ payload_summary_json TEXT NOT NULL DEFAULT '{}',
35
+ imported_count INTEGER NOT NULL DEFAULT 0,
36
+ created_count INTEGER NOT NULL DEFAULT 0,
37
+ updated_count INTEGER NOT NULL DEFAULT 0,
38
+ merged_count INTEGER NOT NULL DEFAULT 0,
39
+ error_message TEXT,
40
+ imported_at TEXT NOT NULL,
41
+ created_at TEXT NOT NULL,
42
+ updated_at TEXT NOT NULL
43
+ );
44
+
45
+ CREATE INDEX IF NOT EXISTS idx_health_import_runs_user
46
+ ON health_import_runs(user_id, imported_at DESC);
47
+
48
+ CREATE TABLE IF NOT EXISTS health_sleep_sessions (
49
+ id TEXT PRIMARY KEY,
50
+ external_uid TEXT NOT NULL,
51
+ pairing_session_id TEXT REFERENCES companion_pairing_sessions(id) ON DELETE SET NULL,
52
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
53
+ source TEXT NOT NULL,
54
+ source_type TEXT NOT NULL DEFAULT 'healthkit',
55
+ source_device TEXT NOT NULL DEFAULT '',
56
+ started_at TEXT NOT NULL,
57
+ ended_at TEXT NOT NULL,
58
+ time_in_bed_seconds INTEGER NOT NULL DEFAULT 0,
59
+ asleep_seconds INTEGER NOT NULL DEFAULT 0,
60
+ awake_seconds INTEGER NOT NULL DEFAULT 0,
61
+ sleep_score REAL,
62
+ regularity_score REAL,
63
+ bedtime_consistency_minutes INTEGER,
64
+ wake_consistency_minutes INTEGER,
65
+ stage_breakdown_json TEXT NOT NULL DEFAULT '[]',
66
+ recovery_metrics_json TEXT NOT NULL DEFAULT '{}',
67
+ links_json TEXT NOT NULL DEFAULT '[]',
68
+ annotations_json TEXT NOT NULL DEFAULT '{}',
69
+ provenance_json TEXT NOT NULL DEFAULT '{}',
70
+ derived_json TEXT NOT NULL DEFAULT '{}',
71
+ created_at TEXT NOT NULL,
72
+ updated_at TEXT NOT NULL,
73
+ UNIQUE (user_id, source, external_uid)
74
+ );
75
+
76
+ CREATE INDEX IF NOT EXISTS idx_health_sleep_user
77
+ ON health_sleep_sessions(user_id, started_at DESC);
78
+
79
+ CREATE TABLE IF NOT EXISTS health_workout_sessions (
80
+ id TEXT PRIMARY KEY,
81
+ external_uid TEXT NOT NULL,
82
+ pairing_session_id TEXT REFERENCES companion_pairing_sessions(id) ON DELETE SET NULL,
83
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
84
+ source TEXT NOT NULL,
85
+ source_type TEXT NOT NULL DEFAULT 'healthkit',
86
+ workout_type TEXT NOT NULL,
87
+ source_device TEXT NOT NULL DEFAULT '',
88
+ started_at TEXT NOT NULL,
89
+ ended_at TEXT NOT NULL,
90
+ duration_seconds INTEGER NOT NULL DEFAULT 0,
91
+ active_energy_kcal REAL,
92
+ total_energy_kcal REAL,
93
+ distance_meters REAL,
94
+ step_count INTEGER,
95
+ exercise_minutes REAL,
96
+ average_heart_rate REAL,
97
+ max_heart_rate REAL,
98
+ subjective_effort INTEGER,
99
+ mood_before TEXT NOT NULL DEFAULT '',
100
+ mood_after TEXT NOT NULL DEFAULT '',
101
+ meaning_text TEXT NOT NULL DEFAULT '',
102
+ planned_context TEXT NOT NULL DEFAULT '',
103
+ social_context TEXT NOT NULL DEFAULT '',
104
+ links_json TEXT NOT NULL DEFAULT '[]',
105
+ tags_json TEXT NOT NULL DEFAULT '[]',
106
+ annotations_json TEXT NOT NULL DEFAULT '{}',
107
+ provenance_json TEXT NOT NULL DEFAULT '{}',
108
+ derived_json TEXT NOT NULL DEFAULT '{}',
109
+ generated_from_habit_id TEXT REFERENCES habits(id) ON DELETE SET NULL,
110
+ generated_from_check_in_id TEXT REFERENCES habit_check_ins(id) ON DELETE SET NULL,
111
+ reconciliation_status TEXT NOT NULL DEFAULT 'standalone',
112
+ created_at TEXT NOT NULL,
113
+ updated_at TEXT NOT NULL,
114
+ UNIQUE (user_id, source, external_uid)
115
+ );
116
+
117
+ CREATE INDEX IF NOT EXISTS idx_health_workouts_user
118
+ ON health_workout_sessions(user_id, started_at DESC);
119
+
120
+ CREATE TABLE IF NOT EXISTS health_daily_summaries (
121
+ id TEXT PRIMARY KEY,
122
+ user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
123
+ date_key TEXT NOT NULL,
124
+ summary_type TEXT NOT NULL,
125
+ metrics_json TEXT NOT NULL DEFAULT '{}',
126
+ derived_json TEXT NOT NULL DEFAULT '{}',
127
+ source TEXT NOT NULL DEFAULT 'derived',
128
+ created_at TEXT NOT NULL,
129
+ updated_at TEXT NOT NULL,
130
+ UNIQUE (user_id, date_key, summary_type)
131
+ );
132
+
133
+ CREATE INDEX IF NOT EXISTS idx_health_daily_summaries_user
134
+ ON health_daily_summaries(user_id, date_key DESC, summary_type);
135
+
136
+ ALTER TABLE habits
137
+ ADD COLUMN generated_health_event_template_json TEXT NOT NULL DEFAULT '{}';
138
+
139
+ ALTER TABLE forge_events
140
+ ADD COLUMN place_label TEXT NOT NULL DEFAULT '';
141
+
142
+ ALTER TABLE forge_events
143
+ ADD COLUMN place_address TEXT NOT NULL DEFAULT '';
144
+
145
+ ALTER TABLE forge_events
146
+ ADD COLUMN place_timezone TEXT NOT NULL DEFAULT '';
147
+
148
+ ALTER TABLE forge_events
149
+ ADD COLUMN place_latitude REAL;
150
+
151
+ ALTER TABLE forge_events
152
+ ADD COLUMN place_longitude REAL;
153
+
154
+ ALTER TABLE forge_events
155
+ ADD COLUMN place_source TEXT NOT NULL DEFAULT '';
156
+
157
+ ALTER TABLE forge_events
158
+ ADD COLUMN place_external_id TEXT NOT NULL DEFAULT '';
@@ -0,0 +1,22 @@
1
+ ALTER TABLE strategies ADD COLUMN is_locked INTEGER NOT NULL DEFAULT 0;
2
+ ALTER TABLE strategies ADD COLUMN locked_at TEXT;
3
+ ALTER TABLE strategies ADD COLUMN locked_by_user_id TEXT REFERENCES users(id) ON DELETE SET NULL;
4
+
5
+ CREATE INDEX IF NOT EXISTS idx_strategies_locked_by_user ON strategies(locked_by_user_id, updated_at DESC);
6
+
7
+ DELETE FROM user_access_grants
8
+ WHERE rowid NOT IN (
9
+ SELECT MIN(rowid)
10
+ FROM user_access_grants
11
+ GROUP BY subject_user_id, target_user_id
12
+ );
13
+
14
+ UPDATE user_access_grants
15
+ SET access_level = 'manage',
16
+ config_json = CASE
17
+ WHEN subject_user_id = target_user_id THEN
18
+ '{"self":true,"mutable":true,"linkedEntities":true,"rights":{"discoverable":true,"canListUsers":true,"canReadProfile":true,"canReadEntities":true,"canSearchEntities":true,"canLinkEntities":true,"canAffectEntities":true,"canManageStrategies":true,"canCreateOnBehalf":true,"canViewMetrics":true,"canViewActivity":true}}'
19
+ ELSE
20
+ '{"self":false,"mutable":false,"linkedEntities":true,"rights":{"discoverable":true,"canListUsers":true,"canReadProfile":true,"canReadEntities":true,"canSearchEntities":true,"canLinkEntities":true,"canAffectEntities":true,"canManageStrategies":true,"canCreateOnBehalf":true,"canViewMetrics":true,"canViewActivity":true}}'
21
+ END,
22
+ updated_at = CURRENT_TIMESTAMP;