forge-openclaw-plugin 0.2.19 → 0.2.21

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 (82) hide show
  1. package/README.md +133 -2
  2. package/dist/assets/board-_C6oMy5w.js +6 -0
  3. package/dist/assets/{board-8L3uX7_O.js.map → board-_C6oMy5w.js.map} +1 -1
  4. package/dist/assets/index-B4A6TooJ.js +63 -0
  5. package/dist/assets/index-B4A6TooJ.js.map +1 -0
  6. package/dist/assets/index-D6Xs_2mo.css +1 -0
  7. package/dist/assets/{motion-1GAqqi8M.js → motion-D4sZgCHd.js} +2 -2
  8. package/dist/assets/{motion-1GAqqi8M.js.map → motion-D4sZgCHd.js.map} +1 -1
  9. package/dist/assets/{table-DBGlgRjk.js → table-BWzTaky1.js} +2 -2
  10. package/dist/assets/{table-DBGlgRjk.js.map → table-BWzTaky1.js.map} +1 -1
  11. package/dist/assets/{ui-iTluWjC4.js → ui-BzK4azQb.js} +7 -7
  12. package/dist/assets/{ui-iTluWjC4.js.map → ui-BzK4azQb.js.map} +1 -1
  13. package/dist/assets/vendor-DT3pnAKJ.css +1 -0
  14. package/dist/assets/vendor-De38P6YR.js +729 -0
  15. package/dist/assets/vendor-De38P6YR.js.map +1 -0
  16. package/dist/assets/viz-C6hfyqzu.js +34 -0
  17. package/dist/assets/viz-C6hfyqzu.js.map +1 -0
  18. package/dist/index.html +9 -9
  19. package/dist/openclaw/parity.d.ts +1 -1
  20. package/dist/openclaw/parity.js +29 -2
  21. package/dist/openclaw/routes.js +207 -24
  22. package/dist/openclaw/tools.js +324 -35
  23. package/dist/server/app.js +2080 -92
  24. package/dist/server/db.js +3 -0
  25. package/dist/server/health.js +1284 -0
  26. package/dist/server/managers/platform/background-job-manager.js +138 -2
  27. package/dist/server/managers/platform/llm-manager.js +126 -0
  28. package/dist/server/managers/platform/openai-responses-provider.js +773 -0
  29. package/dist/server/managers/runtime.js +6 -1
  30. package/dist/server/openapi.js +718 -0
  31. package/dist/server/preferences-seeds.js +409 -0
  32. package/dist/server/preferences-types.js +368 -0
  33. package/dist/server/psyche-types.js +42 -18
  34. package/dist/server/repositories/activity-events.js +53 -4
  35. package/dist/server/repositories/calendar.js +89 -15
  36. package/dist/server/repositories/collaboration.js +8 -3
  37. package/dist/server/repositories/diagnostic-logs.js +243 -0
  38. package/dist/server/repositories/entity-ownership.js +92 -0
  39. package/dist/server/repositories/goals.js +7 -2
  40. package/dist/server/repositories/habits.js +122 -16
  41. package/dist/server/repositories/notes.js +119 -41
  42. package/dist/server/repositories/preferences.js +1765 -0
  43. package/dist/server/repositories/projects.js +18 -7
  44. package/dist/server/repositories/psyche.js +84 -27
  45. package/dist/server/repositories/rewards.js +112 -4
  46. package/dist/server/repositories/strategies.js +450 -0
  47. package/dist/server/repositories/tags.js +11 -6
  48. package/dist/server/repositories/task-runs.js +10 -2
  49. package/dist/server/repositories/tasks.js +99 -17
  50. package/dist/server/repositories/users.js +417 -0
  51. package/dist/server/repositories/wiki-memory.js +3366 -0
  52. package/dist/server/services/context.js +20 -18
  53. package/dist/server/services/dashboard.js +29 -6
  54. package/dist/server/services/entity-crud.js +21 -3
  55. package/dist/server/services/insights.js +9 -7
  56. package/dist/server/services/projects.js +2 -1
  57. package/dist/server/services/psyche.js +10 -9
  58. package/dist/server/types.js +594 -30
  59. package/openclaw.plugin.json +1 -1
  60. package/package.json +1 -1
  61. package/server/migrations/015_multi_user_and_strategies.sql +244 -0
  62. package/server/migrations/016_health_companion.sql +158 -0
  63. package/server/migrations/016_strategy_contracts_and_user_graph.sql +22 -0
  64. package/server/migrations/017_preferences.sql +131 -0
  65. package/server/migrations/018_preference_catalogs.sql +31 -0
  66. package/server/migrations/019_wiki_memory.sql +255 -0
  67. package/server/migrations/020_wiki_page_hierarchy.sql +11 -0
  68. package/server/migrations/021_hide_evidence_from_wiki_index.sql +3 -0
  69. package/server/migrations/022_wiki_ingest_background.sql +85 -0
  70. package/server/migrations/023_diagnostic_logs.sql +28 -0
  71. package/skills/forge-openclaw/SKILL.md +126 -34
  72. package/skills/forge-openclaw/entity_conversation_playbooks.md +337 -0
  73. package/skills/forge-openclaw/psyche_entity_playbooks.md +404 -0
  74. package/dist/assets/board-8L3uX7_O.js +0 -6
  75. package/dist/assets/index-Cj1IBH_w.js +0 -36
  76. package/dist/assets/index-Cj1IBH_w.js.map +0 -1
  77. package/dist/assets/index-DQT6EbuS.css +0 -1
  78. package/dist/assets/vendor-BvM2F9Dp.js +0 -503
  79. package/dist/assets/vendor-BvM2F9Dp.js.map +0 -1
  80. package/dist/assets/vendor-CRS-psbw.css +0 -1
  81. package/dist/assets/viz-CNeunkfu.js +0 -34
  82. package/dist/assets/viz-CNeunkfu.js.map +0 -1
@@ -0,0 +1,255 @@
1
+ ALTER TABLE notes
2
+ ADD COLUMN kind TEXT NOT NULL DEFAULT 'evidence';
3
+
4
+ ALTER TABLE notes
5
+ ADD COLUMN title TEXT NOT NULL DEFAULT '';
6
+
7
+ ALTER TABLE notes
8
+ ADD COLUMN slug TEXT NOT NULL DEFAULT '';
9
+
10
+ ALTER TABLE notes
11
+ ADD COLUMN space_id TEXT NOT NULL DEFAULT '';
12
+
13
+ ALTER TABLE notes
14
+ ADD COLUMN aliases_json TEXT NOT NULL DEFAULT '[]';
15
+
16
+ ALTER TABLE notes
17
+ ADD COLUMN summary TEXT NOT NULL DEFAULT '';
18
+
19
+ ALTER TABLE notes
20
+ ADD COLUMN source_path TEXT NOT NULL DEFAULT '';
21
+
22
+ ALTER TABLE notes
23
+ ADD COLUMN frontmatter_json TEXT NOT NULL DEFAULT '{}';
24
+
25
+ ALTER TABLE notes
26
+ ADD COLUMN revision_hash TEXT NOT NULL DEFAULT '';
27
+
28
+ ALTER TABLE notes
29
+ ADD COLUMN last_synced_at TEXT;
30
+
31
+ CREATE INDEX IF NOT EXISTS idx_notes_kind_updated
32
+ ON notes (kind, updated_at DESC);
33
+
34
+ CREATE INDEX IF NOT EXISTS idx_notes_space_updated
35
+ ON notes (space_id, updated_at DESC);
36
+
37
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_notes_space_slug_unique
38
+ ON notes (space_id, slug)
39
+ WHERE slug != '';
40
+
41
+ CREATE TABLE IF NOT EXISTS wiki_spaces (
42
+ id TEXT PRIMARY KEY,
43
+ slug TEXT NOT NULL UNIQUE,
44
+ label TEXT NOT NULL,
45
+ description TEXT NOT NULL DEFAULT '',
46
+ owner_user_id TEXT,
47
+ visibility TEXT NOT NULL DEFAULT 'personal',
48
+ created_at TEXT NOT NULL,
49
+ updated_at TEXT NOT NULL
50
+ );
51
+
52
+ CREATE INDEX IF NOT EXISTS idx_wiki_spaces_owner
53
+ ON wiki_spaces (owner_user_id, updated_at DESC);
54
+
55
+ INSERT INTO wiki_spaces (id, slug, label, description, owner_user_id, visibility, created_at, updated_at)
56
+ VALUES (
57
+ 'wiki_space_shared',
58
+ 'shared',
59
+ 'Shared Forge Memory',
60
+ 'Shared wiki space for file-backed Forge knowledge.',
61
+ NULL,
62
+ 'shared',
63
+ CURRENT_TIMESTAMP,
64
+ CURRENT_TIMESTAMP
65
+ )
66
+ ON CONFLICT(id) DO NOTHING;
67
+
68
+ UPDATE notes
69
+ SET space_id = 'wiki_space_shared'
70
+ WHERE trim(space_id) = '';
71
+
72
+ UPDATE notes
73
+ SET title = CASE
74
+ WHEN trim(title) != '' THEN title
75
+ WHEN trim(content_plain) != '' THEN substr(trim(content_plain), 1, 120)
76
+ ELSE 'Untitled note'
77
+ END
78
+ WHERE trim(title) = '';
79
+
80
+ UPDATE notes
81
+ SET slug = replace(replace(lower(id), '_', '-'), ' ', '-')
82
+ WHERE trim(slug) = '';
83
+
84
+ CREATE TABLE IF NOT EXISTS wiki_link_edges (
85
+ source_note_id TEXT NOT NULL,
86
+ target_type TEXT NOT NULL,
87
+ target_note_id TEXT,
88
+ target_entity_type TEXT,
89
+ target_entity_id TEXT,
90
+ label TEXT NOT NULL DEFAULT '',
91
+ raw_target TEXT NOT NULL DEFAULT '',
92
+ is_embed INTEGER NOT NULL DEFAULT 0,
93
+ created_at TEXT NOT NULL,
94
+ updated_at TEXT NOT NULL,
95
+ PRIMARY KEY (
96
+ source_note_id,
97
+ target_type,
98
+ target_note_id,
99
+ target_entity_type,
100
+ target_entity_id,
101
+ raw_target,
102
+ is_embed
103
+ ),
104
+ FOREIGN KEY (source_note_id) REFERENCES notes(id) ON DELETE CASCADE,
105
+ FOREIGN KEY (target_note_id) REFERENCES notes(id) ON DELETE CASCADE
106
+ );
107
+
108
+ CREATE INDEX IF NOT EXISTS idx_wiki_link_edges_source
109
+ ON wiki_link_edges (source_note_id, updated_at DESC);
110
+
111
+ CREATE INDEX IF NOT EXISTS idx_wiki_link_edges_target_note
112
+ ON wiki_link_edges (target_note_id, updated_at DESC);
113
+
114
+ CREATE INDEX IF NOT EXISTS idx_wiki_link_edges_target_entity
115
+ ON wiki_link_edges (target_entity_type, target_entity_id, updated_at DESC);
116
+
117
+ CREATE VIRTUAL TABLE IF NOT EXISTS wiki_pages_fts
118
+ USING fts5(
119
+ note_id UNINDEXED,
120
+ title,
121
+ slug,
122
+ aliases,
123
+ summary,
124
+ content_plain,
125
+ linked_entities
126
+ );
127
+
128
+ INSERT INTO wiki_pages_fts (note_id, title, slug, aliases, summary, content_plain, linked_entities)
129
+ SELECT
130
+ notes.id,
131
+ notes.title,
132
+ notes.slug,
133
+ COALESCE(notes.aliases_json, '[]'),
134
+ COALESCE(notes.summary, ''),
135
+ notes.content_plain,
136
+ ''
137
+ FROM notes
138
+ WHERE NOT EXISTS (
139
+ SELECT 1
140
+ FROM wiki_pages_fts
141
+ WHERE wiki_pages_fts.note_id = notes.id
142
+ );
143
+
144
+ CREATE TABLE IF NOT EXISTS wiki_media_assets (
145
+ id TEXT PRIMARY KEY,
146
+ space_id TEXT NOT NULL,
147
+ note_id TEXT,
148
+ label TEXT NOT NULL,
149
+ mime_type TEXT NOT NULL,
150
+ file_name TEXT NOT NULL,
151
+ file_path TEXT NOT NULL,
152
+ size_bytes INTEGER NOT NULL DEFAULT 0,
153
+ checksum TEXT NOT NULL DEFAULT '',
154
+ transcript_note_id TEXT,
155
+ metadata_json TEXT NOT NULL DEFAULT '{}',
156
+ created_at TEXT NOT NULL,
157
+ updated_at TEXT NOT NULL,
158
+ FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE SET NULL,
159
+ FOREIGN KEY (transcript_note_id) REFERENCES notes(id) ON DELETE SET NULL
160
+ );
161
+
162
+ CREATE INDEX IF NOT EXISTS idx_wiki_media_assets_space
163
+ ON wiki_media_assets (space_id, updated_at DESC);
164
+
165
+ CREATE TABLE IF NOT EXISTS wiki_llm_profiles (
166
+ id TEXT PRIMARY KEY,
167
+ label TEXT NOT NULL,
168
+ provider TEXT NOT NULL,
169
+ base_url TEXT NOT NULL DEFAULT '',
170
+ model TEXT NOT NULL,
171
+ secret_id TEXT,
172
+ system_prompt TEXT NOT NULL DEFAULT '',
173
+ enabled INTEGER NOT NULL DEFAULT 1,
174
+ metadata_json TEXT NOT NULL DEFAULT '{}',
175
+ created_at TEXT NOT NULL,
176
+ updated_at TEXT NOT NULL
177
+ );
178
+
179
+ CREATE TABLE IF NOT EXISTS wiki_embedding_profiles (
180
+ id TEXT PRIMARY KEY,
181
+ label TEXT NOT NULL,
182
+ provider TEXT NOT NULL,
183
+ base_url TEXT NOT NULL DEFAULT '',
184
+ model TEXT NOT NULL,
185
+ secret_id TEXT,
186
+ dimensions INTEGER,
187
+ chunk_size INTEGER NOT NULL DEFAULT 1200,
188
+ chunk_overlap INTEGER NOT NULL DEFAULT 200,
189
+ enabled INTEGER NOT NULL DEFAULT 1,
190
+ metadata_json TEXT NOT NULL DEFAULT '{}',
191
+ created_at TEXT NOT NULL,
192
+ updated_at TEXT NOT NULL
193
+ );
194
+
195
+ CREATE TABLE IF NOT EXISTS wiki_embedding_chunks (
196
+ id TEXT PRIMARY KEY,
197
+ note_id TEXT NOT NULL,
198
+ space_id TEXT NOT NULL,
199
+ profile_id TEXT NOT NULL,
200
+ chunk_key TEXT NOT NULL,
201
+ heading_path TEXT NOT NULL DEFAULT '',
202
+ content_text TEXT NOT NULL,
203
+ vector_json TEXT NOT NULL,
204
+ created_at TEXT NOT NULL,
205
+ updated_at TEXT NOT NULL,
206
+ FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE,
207
+ FOREIGN KEY (profile_id) REFERENCES wiki_embedding_profiles(id) ON DELETE CASCADE
208
+ );
209
+
210
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_wiki_embedding_chunks_unique
211
+ ON wiki_embedding_chunks (note_id, profile_id, chunk_key);
212
+
213
+ CREATE INDEX IF NOT EXISTS idx_wiki_embedding_chunks_profile_space
214
+ ON wiki_embedding_chunks (profile_id, space_id, updated_at DESC);
215
+
216
+ CREATE TABLE IF NOT EXISTS wiki_ingest_jobs (
217
+ id TEXT PRIMARY KEY,
218
+ space_id TEXT NOT NULL,
219
+ llm_profile_id TEXT,
220
+ status TEXT NOT NULL,
221
+ source_kind TEXT NOT NULL,
222
+ source_locator TEXT NOT NULL DEFAULT '',
223
+ mime_type TEXT NOT NULL DEFAULT '',
224
+ title_hint TEXT NOT NULL DEFAULT '',
225
+ summary TEXT NOT NULL DEFAULT '',
226
+ page_note_id TEXT,
227
+ created_by_actor TEXT,
228
+ error_message TEXT NOT NULL DEFAULT '',
229
+ created_at TEXT NOT NULL,
230
+ updated_at TEXT NOT NULL,
231
+ completed_at TEXT,
232
+ FOREIGN KEY (llm_profile_id) REFERENCES wiki_llm_profiles(id) ON DELETE SET NULL,
233
+ FOREIGN KEY (page_note_id) REFERENCES notes(id) ON DELETE SET NULL
234
+ );
235
+
236
+ CREATE INDEX IF NOT EXISTS idx_wiki_ingest_jobs_space
237
+ ON wiki_ingest_jobs (space_id, created_at DESC);
238
+
239
+ CREATE TABLE IF NOT EXISTS wiki_ingest_job_items (
240
+ id TEXT PRIMARY KEY,
241
+ job_id TEXT NOT NULL,
242
+ item_type TEXT NOT NULL,
243
+ status TEXT NOT NULL,
244
+ note_id TEXT,
245
+ media_asset_id TEXT,
246
+ payload_json TEXT NOT NULL DEFAULT '{}',
247
+ created_at TEXT NOT NULL,
248
+ updated_at TEXT NOT NULL,
249
+ FOREIGN KEY (job_id) REFERENCES wiki_ingest_jobs(id) ON DELETE CASCADE,
250
+ FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE SET NULL,
251
+ FOREIGN KEY (media_asset_id) REFERENCES wiki_media_assets(id) ON DELETE SET NULL
252
+ );
253
+
254
+ CREATE INDEX IF NOT EXISTS idx_wiki_ingest_job_items_job
255
+ ON wiki_ingest_job_items (job_id, created_at DESC);
@@ -0,0 +1,11 @@
1
+ ALTER TABLE notes
2
+ ADD COLUMN parent_slug TEXT;
3
+
4
+ ALTER TABLE notes
5
+ ADD COLUMN index_order INTEGER NOT NULL DEFAULT 0;
6
+
7
+ ALTER TABLE notes
8
+ ADD COLUMN show_in_index INTEGER NOT NULL DEFAULT 1;
9
+
10
+ CREATE INDEX IF NOT EXISTS idx_notes_space_parent_order
11
+ ON notes (space_id, parent_slug, index_order, updated_at DESC);
@@ -0,0 +1,3 @@
1
+ UPDATE notes
2
+ SET show_in_index = 0
3
+ WHERE kind = 'evidence';
@@ -0,0 +1,85 @@
1
+ ALTER TABLE wiki_ingest_jobs
2
+ ADD COLUMN phase TEXT NOT NULL DEFAULT 'queued';
3
+
4
+ ALTER TABLE wiki_ingest_jobs
5
+ ADD COLUMN progress_percent INTEGER NOT NULL DEFAULT 0;
6
+
7
+ ALTER TABLE wiki_ingest_jobs
8
+ ADD COLUMN total_files INTEGER NOT NULL DEFAULT 0;
9
+
10
+ ALTER TABLE wiki_ingest_jobs
11
+ ADD COLUMN processed_files INTEGER NOT NULL DEFAULT 0;
12
+
13
+ ALTER TABLE wiki_ingest_jobs
14
+ ADD COLUMN created_page_count INTEGER NOT NULL DEFAULT 0;
15
+
16
+ ALTER TABLE wiki_ingest_jobs
17
+ ADD COLUMN created_entity_count INTEGER NOT NULL DEFAULT 0;
18
+
19
+ ALTER TABLE wiki_ingest_jobs
20
+ ADD COLUMN accepted_count INTEGER NOT NULL DEFAULT 0;
21
+
22
+ ALTER TABLE wiki_ingest_jobs
23
+ ADD COLUMN rejected_count INTEGER NOT NULL DEFAULT 0;
24
+
25
+ ALTER TABLE wiki_ingest_jobs
26
+ ADD COLUMN latest_message TEXT NOT NULL DEFAULT '';
27
+
28
+ ALTER TABLE wiki_ingest_jobs
29
+ ADD COLUMN input_json TEXT NOT NULL DEFAULT '{}';
30
+
31
+ CREATE TABLE IF NOT EXISTS wiki_ingest_job_logs (
32
+ id TEXT PRIMARY KEY,
33
+ job_id TEXT NOT NULL,
34
+ level TEXT NOT NULL DEFAULT 'info',
35
+ message TEXT NOT NULL,
36
+ metadata_json TEXT NOT NULL DEFAULT '{}',
37
+ created_at TEXT NOT NULL,
38
+ FOREIGN KEY (job_id) REFERENCES wiki_ingest_jobs(id) ON DELETE CASCADE
39
+ );
40
+
41
+ CREATE INDEX IF NOT EXISTS idx_wiki_ingest_job_logs_job
42
+ ON wiki_ingest_job_logs (job_id, created_at ASC);
43
+
44
+ CREATE TABLE IF NOT EXISTS wiki_ingest_job_assets (
45
+ id TEXT PRIMARY KEY,
46
+ job_id TEXT NOT NULL,
47
+ status TEXT NOT NULL DEFAULT 'queued',
48
+ source_kind TEXT NOT NULL,
49
+ source_locator TEXT NOT NULL DEFAULT '',
50
+ file_name TEXT NOT NULL DEFAULT '',
51
+ mime_type TEXT NOT NULL DEFAULT '',
52
+ file_path TEXT NOT NULL DEFAULT '',
53
+ size_bytes INTEGER NOT NULL DEFAULT 0,
54
+ checksum TEXT NOT NULL DEFAULT '',
55
+ metadata_json TEXT NOT NULL DEFAULT '{}',
56
+ created_at TEXT NOT NULL,
57
+ updated_at TEXT NOT NULL,
58
+ FOREIGN KEY (job_id) REFERENCES wiki_ingest_jobs(id) ON DELETE CASCADE
59
+ );
60
+
61
+ CREATE INDEX IF NOT EXISTS idx_wiki_ingest_job_assets_job
62
+ ON wiki_ingest_job_assets (job_id, created_at ASC);
63
+
64
+ CREATE TABLE IF NOT EXISTS wiki_ingest_job_candidates (
65
+ id TEXT PRIMARY KEY,
66
+ job_id TEXT NOT NULL,
67
+ source_asset_id TEXT,
68
+ candidate_type TEXT NOT NULL,
69
+ status TEXT NOT NULL DEFAULT 'suggested',
70
+ title TEXT NOT NULL DEFAULT '',
71
+ summary TEXT NOT NULL DEFAULT '',
72
+ target_key TEXT NOT NULL DEFAULT '',
73
+ payload_json TEXT NOT NULL DEFAULT '{}',
74
+ published_note_id TEXT,
75
+ published_entity_type TEXT,
76
+ published_entity_id TEXT,
77
+ created_at TEXT NOT NULL,
78
+ updated_at TEXT NOT NULL,
79
+ FOREIGN KEY (job_id) REFERENCES wiki_ingest_jobs(id) ON DELETE CASCADE,
80
+ FOREIGN KEY (source_asset_id) REFERENCES wiki_ingest_job_assets(id) ON DELETE SET NULL,
81
+ FOREIGN KEY (published_note_id) REFERENCES notes(id) ON DELETE SET NULL
82
+ );
83
+
84
+ CREATE INDEX IF NOT EXISTS idx_wiki_ingest_job_candidates_job
85
+ ON wiki_ingest_job_candidates (job_id, created_at ASC);
@@ -0,0 +1,28 @@
1
+ CREATE TABLE IF NOT EXISTS diagnostic_logs (
2
+ id TEXT PRIMARY KEY,
3
+ level TEXT NOT NULL DEFAULT 'info',
4
+ source TEXT NOT NULL DEFAULT 'server',
5
+ scope TEXT NOT NULL,
6
+ event_key TEXT NOT NULL DEFAULT '',
7
+ message TEXT NOT NULL,
8
+ route TEXT,
9
+ function_name TEXT,
10
+ request_id TEXT,
11
+ entity_type TEXT,
12
+ entity_id TEXT,
13
+ job_id TEXT,
14
+ details_json TEXT NOT NULL DEFAULT '{}',
15
+ created_at TEXT NOT NULL
16
+ );
17
+
18
+ CREATE INDEX IF NOT EXISTS idx_diagnostic_logs_created
19
+ ON diagnostic_logs (created_at DESC);
20
+
21
+ CREATE INDEX IF NOT EXISTS idx_diagnostic_logs_scope
22
+ ON diagnostic_logs (scope, created_at DESC);
23
+
24
+ CREATE INDEX IF NOT EXISTS idx_diagnostic_logs_job
25
+ ON diagnostic_logs (job_id, created_at DESC);
26
+
27
+ CREATE INDEX IF NOT EXISTS idx_diagnostic_logs_entity
28
+ ON diagnostic_logs (entity_type, entity_id, created_at DESC);