forge-openclaw-plugin 0.2.4 → 0.2.10

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 (114) hide show
  1. package/README.md +186 -6
  2. package/dist/assets/board-C_m78kvK.js +6 -0
  3. package/dist/assets/board-C_m78kvK.js.map +1 -0
  4. package/dist/assets/favicon-BCHm9dUV.ico +0 -0
  5. package/dist/assets/index-BWtLtXwb.js +36 -0
  6. package/dist/assets/index-BWtLtXwb.js.map +1 -0
  7. package/dist/assets/index-Dp5GXY_z.css +1 -0
  8. package/dist/assets/motion-CpZvZumD.js +10 -0
  9. package/dist/assets/motion-CpZvZumD.js.map +1 -0
  10. package/dist/assets/plus-jakarta-sans-latin-ext-wght-normal-DmpS2jIq.woff2 +0 -0
  11. package/dist/assets/plus-jakarta-sans-latin-wght-normal-eXO_dkmS.woff2 +0 -0
  12. package/dist/assets/plus-jakarta-sans-vietnamese-wght-normal-qRpaaN48.woff2 +0 -0
  13. package/dist/assets/sora-latin-ext-wght-normal-CawQDOvP.woff2 +0 -0
  14. package/dist/assets/sora-latin-wght-normal-DdqRvwsR.woff2 +0 -0
  15. package/dist/assets/space-grotesk-latin-500-normal-CNSSEhBt.woff +0 -0
  16. package/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
  17. package/dist/assets/space-grotesk-latin-700-normal-CwsQ-cCU.woff +0 -0
  18. package/dist/assets/space-grotesk-latin-700-normal-RjhwGPKo.woff2 +0 -0
  19. package/dist/assets/space-grotesk-latin-ext-500-normal-3dgZTiw9.woff +0 -0
  20. package/dist/assets/space-grotesk-latin-ext-500-normal-DUe3BAxM.woff2 +0 -0
  21. package/dist/assets/space-grotesk-latin-ext-700-normal-BQnZhY3m.woff2 +0 -0
  22. package/dist/assets/space-grotesk-latin-ext-700-normal-HVCqSBdx.woff +0 -0
  23. package/dist/assets/space-grotesk-vietnamese-500-normal-BTqKIpxg.woff +0 -0
  24. package/dist/assets/space-grotesk-vietnamese-500-normal-BmEvtly_.woff2 +0 -0
  25. package/dist/assets/space-grotesk-vietnamese-700-normal-DMty7AZE.woff2 +0 -0
  26. package/dist/assets/space-grotesk-vietnamese-700-normal-Duxec5Rn.woff +0 -0
  27. package/dist/assets/table-DtyXTw03.js +23 -0
  28. package/dist/assets/table-DtyXTw03.js.map +1 -0
  29. package/dist/assets/ui-BXbpiKyS.js +46 -0
  30. package/dist/assets/ui-BXbpiKyS.js.map +1 -0
  31. package/dist/assets/vendor-CRS-psbw.css +1 -0
  32. package/dist/assets/vendor-QBH6qVEe.js +433 -0
  33. package/dist/assets/vendor-QBH6qVEe.js.map +1 -0
  34. package/dist/assets/viz-w-IMeueL.js +34 -0
  35. package/dist/assets/viz-w-IMeueL.js.map +1 -0
  36. package/dist/favicon.ico +0 -0
  37. package/dist/favicon.png +0 -0
  38. package/dist/index.html +29 -0
  39. package/dist/openclaw/api-client.d.ts +9 -0
  40. package/dist/openclaw/api-client.js +31 -4
  41. package/dist/openclaw/local-runtime.d.ts +3 -0
  42. package/dist/openclaw/local-runtime.js +136 -0
  43. package/dist/openclaw/parity.d.ts +4 -4
  44. package/dist/openclaw/parity.js +23 -33
  45. package/dist/openclaw/plugin-entry-shared.d.ts +4 -2
  46. package/dist/openclaw/plugin-entry-shared.js +63 -9
  47. package/dist/openclaw/routes.d.ts +12 -3
  48. package/dist/openclaw/routes.js +156 -924
  49. package/dist/openclaw/tools.js +242 -1100
  50. package/dist/server/app.js +2487 -0
  51. package/dist/server/db.js +313 -0
  52. package/dist/server/demo-data.js +49 -0
  53. package/dist/server/e2e-server.js +20 -0
  54. package/dist/server/errors.js +15 -0
  55. package/dist/server/index.js +16 -0
  56. package/dist/server/managers/base.js +17 -0
  57. package/dist/server/managers/contracts.js +47 -0
  58. package/dist/server/managers/platform/api-gateway-manager.js +11 -0
  59. package/dist/server/managers/platform/audit-manager.js +15 -0
  60. package/dist/server/managers/platform/authentication-manager.js +56 -0
  61. package/dist/server/managers/platform/authorization-manager.js +56 -0
  62. package/dist/server/managers/platform/background-job-manager.js +10 -0
  63. package/dist/server/managers/platform/configuration-manager.js +33 -0
  64. package/dist/server/managers/platform/database-manager.js +14 -0
  65. package/dist/server/managers/platform/event-bus-manager.js +7 -0
  66. package/dist/server/managers/platform/external-service-manager.js +11 -0
  67. package/dist/server/managers/platform/health-manager.js +7 -0
  68. package/dist/server/managers/platform/migration-manager.js +8 -0
  69. package/dist/server/managers/platform/search-index-manager.js +4 -0
  70. package/dist/server/managers/platform/secrets-manager.js +19 -0
  71. package/dist/server/managers/platform/session-manager.js +121 -0
  72. package/dist/server/managers/platform/storage-manager.js +16 -0
  73. package/dist/server/managers/platform/token-manager.js +37 -0
  74. package/dist/server/managers/platform/transaction-manager.js +8 -0
  75. package/dist/server/managers/platform/trusted-network.js +39 -0
  76. package/dist/server/managers/runtime.js +56 -0
  77. package/dist/server/managers/type-guards.js +4 -0
  78. package/dist/server/openapi.js +3553 -0
  79. package/dist/server/psyche-types.js +366 -0
  80. package/dist/server/repositories/activity-events.js +157 -0
  81. package/dist/server/repositories/collaboration.js +497 -0
  82. package/dist/server/repositories/deleted-entities.js +226 -0
  83. package/dist/server/repositories/domains.js +30 -0
  84. package/dist/server/repositories/event-log.js +64 -0
  85. package/dist/server/repositories/goals.js +156 -0
  86. package/dist/server/repositories/notes.js +359 -0
  87. package/dist/server/repositories/projects.js +211 -0
  88. package/dist/server/repositories/psyche.js +1353 -0
  89. package/dist/server/repositories/rewards.js +675 -0
  90. package/dist/server/repositories/settings.js +399 -0
  91. package/dist/server/repositories/tags.js +160 -0
  92. package/dist/server/repositories/task-runs.js +490 -0
  93. package/dist/server/repositories/tasks.js +424 -0
  94. package/dist/server/seed-demo.js +11 -0
  95. package/dist/server/services/context.js +214 -0
  96. package/dist/server/services/dashboard.js +173 -0
  97. package/dist/server/services/entity-crud.js +573 -0
  98. package/dist/server/services/gamification.js +215 -0
  99. package/dist/server/services/insights.js +91 -0
  100. package/dist/server/services/projects.js +77 -0
  101. package/dist/server/services/psyche.js +63 -0
  102. package/dist/server/services/relations.js +28 -0
  103. package/dist/server/services/reviews.js +88 -0
  104. package/dist/server/services/run-recovery.js +13 -0
  105. package/dist/server/services/tagging.js +49 -0
  106. package/dist/server/services/task-run-watchdog.js +92 -0
  107. package/dist/server/services/work-time.js +176 -0
  108. package/dist/server/types.js +1058 -0
  109. package/dist/server/web.js +91 -0
  110. package/openclaw.plugin.json +32 -9
  111. package/package.json +17 -4
  112. package/server/migrations/001_core.sql +411 -0
  113. package/server/migrations/002_psyche.sql +392 -0
  114. package/skills/forge-openclaw/SKILL.md +197 -271
@@ -0,0 +1,573 @@
1
+ import { getDatabase, runInTransaction } from "../db.js";
2
+ import { createInsight, deleteInsight, getInsightById, listInsights, updateInsight } from "../repositories/collaboration.js";
3
+ import { createNote, deleteNote, getNoteById, listNotes, unlinkNotesForEntity, updateNote } from "../repositories/notes.js";
4
+ import { createBehaviorPatternSchema, createBehaviorSchema, createBeliefEntrySchema, createEmotionDefinitionSchema, createEventTypeSchema, createModeGuideSessionSchema, createModeProfileSchema, createPsycheValueSchema, createTriggerReportSchema, updateBehaviorPatternSchema, updateBehaviorSchema, updateBeliefEntrySchema, updateEmotionDefinitionSchema, updateEventTypeSchema, updateModeGuideSessionSchema, updateModeProfileSchema, updatePsycheValueSchema, updateTriggerReportSchema } from "../psyche-types.js";
5
+ import { buildSettingsBinPayload, cascadeSoftDeleteAnchoredCollaboration, clearDeletedEntityRecord, getDeletedEntityRecord, listDeletedEntities, restoreAnchoredCollaboration, restoreDeletedEntityRecord, upsertDeletedEntityRecord } from "../repositories/deleted-entities.js";
6
+ import { createGoal, deleteGoal, getGoalById, listGoals, updateGoal } from "../repositories/goals.js";
7
+ import { createBehavior, createBehaviorPattern, createBeliefEntry, createEmotionDefinition, createEventType, createModeGuideSession, createModeProfile, createPsycheValue, createTriggerReport, deleteBehavior, deleteBehaviorPattern, deleteBeliefEntry, deleteEmotionDefinition, deleteEventType, deleteModeGuideSession, deleteModeProfile, deletePsycheValue, deleteTriggerReport, getBehaviorById, getBehaviorPatternById, getBeliefEntryById, getEmotionDefinitionById, getEventTypeById, getModeGuideSessionById, getModeProfileById, getPsycheValueById, getTriggerReportById, listBehaviors, listBehaviorPatterns, listBeliefEntries, listEmotionDefinitions, listEventTypes, listModeGuideSessions, listModeProfiles, listPsycheValues, listTriggerReports, updateBehavior, updateBehaviorPattern, updateBeliefEntry, updateEmotionDefinition, updateEventType, updateModeGuideSession, updateModeProfile, updatePsycheValue, updateTriggerReport } from "../repositories/psyche.js";
8
+ import { createProject, deleteProject, getProjectById, listProjects, updateProject } from "../repositories/projects.js";
9
+ import { createTag, deleteTag, getTagById, listTags, updateTag } from "../repositories/tags.js";
10
+ import { createTask, deleteTask, getTaskById, listTasks, updateTask } from "../repositories/tasks.js";
11
+ import { createGoalSchema, createInsightSchema, createNoteSchema, createProjectSchema, createTagSchema, createTaskSchema, updateGoalSchema, updateInsightSchema, updateNoteSchema, updateProjectSchema, updateTagSchema, updateTaskSchema } from "../types.js";
12
+ class AtomicBatchRollback extends Error {
13
+ index;
14
+ code;
15
+ messageText;
16
+ constructor(index, code, messageText) {
17
+ super(messageText);
18
+ this.index = index;
19
+ this.code = code;
20
+ this.messageText = messageText;
21
+ this.name = "AtomicBatchRollback";
22
+ }
23
+ }
24
+ const CRUD_ENTITY_CAPABILITIES = {
25
+ goal: {
26
+ entityType: "goal",
27
+ routeBase: "/api/v1/goals",
28
+ list: () => listGoals(),
29
+ get: (id) => getGoalById(id),
30
+ create: (data, context) => createGoal(data, context),
31
+ update: (id, patch, context) => updateGoal(id, patch, context),
32
+ hardDelete: (id, context) => deleteGoal(id, context)
33
+ },
34
+ project: {
35
+ entityType: "project",
36
+ routeBase: "/api/v1/projects",
37
+ list: () => listProjects(),
38
+ get: (id) => getProjectById(id),
39
+ create: (data, context) => createProject(data, context),
40
+ update: (id, patch, context) => updateProject(id, patch, context),
41
+ hardDelete: (id, context) => deleteProject(id, context)
42
+ },
43
+ task: {
44
+ entityType: "task",
45
+ routeBase: "/api/v1/tasks",
46
+ list: () => listTasks(),
47
+ get: (id) => getTaskById(id),
48
+ create: (data, context) => createTask(data, context),
49
+ update: (id, patch, context) => updateTask(id, patch, context),
50
+ hardDelete: (id, context) => deleteTask(id, context)
51
+ },
52
+ tag: {
53
+ entityType: "tag",
54
+ routeBase: "/api/v1/tags",
55
+ list: () => listTags(),
56
+ get: (id) => getTagById(id),
57
+ create: (data, context) => createTag(data, context),
58
+ update: (id, patch, context) => updateTag(id, patch, context),
59
+ hardDelete: (id, context) => deleteTag(id, context)
60
+ },
61
+ note: {
62
+ entityType: "note",
63
+ routeBase: "/api/v1/notes",
64
+ list: () => listNotes(),
65
+ get: (id) => getNoteById(id),
66
+ create: (data, context) => createNote(data, context),
67
+ update: (id, patch, context) => updateNote(id, patch, context),
68
+ hardDelete: (id, context) => deleteNote(id, context)
69
+ },
70
+ insight: {
71
+ entityType: "insight",
72
+ routeBase: "/api/v1/insights",
73
+ list: () => listInsights(),
74
+ get: (id) => getInsightById(id),
75
+ create: (data, context) => createInsight(data, context),
76
+ update: (id, patch, context) => updateInsight(id, patch, context),
77
+ hardDelete: (id, context) => deleteInsight(id, context)
78
+ },
79
+ psyche_value: {
80
+ entityType: "psyche_value",
81
+ routeBase: "/api/v1/psyche/values",
82
+ list: () => listPsycheValues(),
83
+ get: (id) => getPsycheValueById(id),
84
+ create: (data, context) => createPsycheValue(data, context),
85
+ update: (id, patch, context) => updatePsycheValue(id, patch, context),
86
+ hardDelete: (id, context) => deletePsycheValue(id, context)
87
+ },
88
+ behavior_pattern: {
89
+ entityType: "behavior_pattern",
90
+ routeBase: "/api/v1/psyche/patterns",
91
+ list: () => listBehaviorPatterns(),
92
+ get: (id) => getBehaviorPatternById(id),
93
+ create: (data, context) => createBehaviorPattern(data, context),
94
+ update: (id, patch, context) => updateBehaviorPattern(id, patch, context),
95
+ hardDelete: (id, context) => deleteBehaviorPattern(id, context)
96
+ },
97
+ behavior: {
98
+ entityType: "behavior",
99
+ routeBase: "/api/v1/psyche/behaviors",
100
+ list: () => listBehaviors(),
101
+ get: (id) => getBehaviorById(id),
102
+ create: (data, context) => createBehavior(data, context),
103
+ update: (id, patch, context) => updateBehavior(id, patch, context),
104
+ hardDelete: (id, context) => deleteBehavior(id, context)
105
+ },
106
+ belief_entry: {
107
+ entityType: "belief_entry",
108
+ routeBase: "/api/v1/psyche/beliefs",
109
+ list: () => listBeliefEntries(),
110
+ get: (id) => getBeliefEntryById(id),
111
+ create: (data, context) => createBeliefEntry(data, context),
112
+ update: (id, patch, context) => updateBeliefEntry(id, patch, context),
113
+ hardDelete: (id, context) => deleteBeliefEntry(id, context)
114
+ },
115
+ mode_profile: {
116
+ entityType: "mode_profile",
117
+ routeBase: "/api/v1/psyche/modes",
118
+ list: () => listModeProfiles(),
119
+ get: (id) => getModeProfileById(id),
120
+ create: (data, context) => createModeProfile(data, context),
121
+ update: (id, patch, context) => updateModeProfile(id, patch, context),
122
+ hardDelete: (id, context) => deleteModeProfile(id, context)
123
+ },
124
+ mode_guide_session: {
125
+ entityType: "mode_guide_session",
126
+ routeBase: "/api/v1/psyche/mode-guides",
127
+ list: () => listModeGuideSessions(200),
128
+ get: (id) => getModeGuideSessionById(id),
129
+ create: (data, context) => createModeGuideSession(data, context),
130
+ update: (id, patch, context) => updateModeGuideSession(id, patch, context),
131
+ hardDelete: (id, context) => deleteModeGuideSession(id, context)
132
+ },
133
+ event_type: {
134
+ entityType: "event_type",
135
+ routeBase: "/api/v1/psyche/event-types",
136
+ list: () => listEventTypes(),
137
+ get: (id) => getEventTypeById(id),
138
+ create: (data, context) => createEventType(data, context),
139
+ update: (id, patch, context) => updateEventType(id, patch, context),
140
+ hardDelete: (id, context) => deleteEventType(id, context)
141
+ },
142
+ emotion_definition: {
143
+ entityType: "emotion_definition",
144
+ routeBase: "/api/v1/psyche/emotions",
145
+ list: () => listEmotionDefinitions(),
146
+ get: (id) => getEmotionDefinitionById(id),
147
+ create: (data, context) => createEmotionDefinition(data, context),
148
+ update: (id, patch, context) => updateEmotionDefinition(id, patch, context),
149
+ hardDelete: (id, context) => deleteEmotionDefinition(id, context)
150
+ },
151
+ trigger_report: {
152
+ entityType: "trigger_report",
153
+ routeBase: "/api/v1/psyche/reports",
154
+ list: () => listTriggerReports(200),
155
+ get: (id) => getTriggerReportById(id),
156
+ create: (data, context) => createTriggerReport(data, context),
157
+ update: (id, patch, context) => updateTriggerReport(id, patch, context),
158
+ hardDelete: (id, context) => deleteTriggerReport(id, context)
159
+ }
160
+ };
161
+ export function getCrudEntityCapabilityMatrix() {
162
+ return Object.values(CRUD_ENTITY_CAPABILITIES).map((capability) => ({
163
+ entityType: capability.entityType,
164
+ routeBase: capability.routeBase,
165
+ pluginExposed: true,
166
+ deleteMode: "soft_default",
167
+ inBin: true
168
+ }));
169
+ }
170
+ function getCapability(entityType) {
171
+ return CRUD_ENTITY_CAPABILITIES[entityType];
172
+ }
173
+ const CREATE_ENTITY_SCHEMAS = {
174
+ goal: createGoalSchema,
175
+ project: createProjectSchema,
176
+ task: createTaskSchema,
177
+ tag: createTagSchema,
178
+ note: createNoteSchema,
179
+ insight: createInsightSchema,
180
+ psyche_value: createPsycheValueSchema,
181
+ behavior_pattern: createBehaviorPatternSchema,
182
+ behavior: createBehaviorSchema,
183
+ belief_entry: createBeliefEntrySchema,
184
+ mode_profile: createModeProfileSchema,
185
+ mode_guide_session: createModeGuideSessionSchema,
186
+ event_type: createEventTypeSchema,
187
+ emotion_definition: createEmotionDefinitionSchema,
188
+ trigger_report: createTriggerReportSchema
189
+ };
190
+ const UPDATE_ENTITY_SCHEMAS = {
191
+ goal: updateGoalSchema,
192
+ project: updateProjectSchema,
193
+ task: updateTaskSchema,
194
+ tag: updateTagSchema,
195
+ note: updateNoteSchema,
196
+ insight: updateInsightSchema,
197
+ psyche_value: updatePsycheValueSchema,
198
+ behavior_pattern: updateBehaviorPatternSchema,
199
+ behavior: updateBehaviorSchema,
200
+ belief_entry: updateBeliefEntrySchema,
201
+ mode_profile: updateModeProfileSchema,
202
+ mode_guide_session: updateModeGuideSessionSchema,
203
+ event_type: updateEventTypeSchema,
204
+ emotion_definition: updateEmotionDefinitionSchema,
205
+ trigger_report: updateTriggerReportSchema
206
+ };
207
+ function parseCreateInput(entityType, data) {
208
+ return CREATE_ENTITY_SCHEMAS[entityType].parse(data);
209
+ }
210
+ function parseUpdatePatch(entityType, patch) {
211
+ return UPDATE_ENTITY_SCHEMAS[entityType].parse(patch);
212
+ }
213
+ function toOperationError(code, message) {
214
+ return {
215
+ code,
216
+ message
217
+ };
218
+ }
219
+ function markRolledBack(result) {
220
+ if (!result.ok) {
221
+ return result;
222
+ }
223
+ return {
224
+ ok: false,
225
+ entityType: result.entityType,
226
+ id: result.id,
227
+ clientRef: result.clientRef,
228
+ error: toOperationError("rolled_back", "Rolled back because an earlier atomic batch operation failed.")
229
+ };
230
+ }
231
+ function markNotExecuted(entry) {
232
+ return {
233
+ ok: false,
234
+ entityType: entry.entityType,
235
+ id: entry.id,
236
+ clientRef: entry.clientRef,
237
+ error: toOperationError("not_executed", "Skipped because an earlier atomic batch operation failed.")
238
+ };
239
+ }
240
+ function finalizeAtomicRollbackResults(entries, partialResults, rollback) {
241
+ return entries.map((entry, index) => {
242
+ if (index < rollback.index) {
243
+ return markRolledBack(partialResults[index] ?? markNotExecuted(entry));
244
+ }
245
+ if (index === rollback.index) {
246
+ const failedResult = partialResults[index];
247
+ if (failedResult) {
248
+ return failedResult.ok ? markRolledBack(failedResult) : failedResult;
249
+ }
250
+ return {
251
+ ok: false,
252
+ entityType: entry.entityType,
253
+ id: entry.id,
254
+ clientRef: entry.clientRef,
255
+ error: toOperationError(rollback.code, rollback.messageText)
256
+ };
257
+ }
258
+ return markNotExecuted(entry);
259
+ });
260
+ }
261
+ function executeBatchOperation(entries, atomic, execute) {
262
+ if (!atomic) {
263
+ return { results: entries.map((entry) => execute(entry)) };
264
+ }
265
+ const partialResults = [];
266
+ try {
267
+ runInTransaction(() => {
268
+ entries.forEach((entry, index) => {
269
+ const result = execute(entry);
270
+ partialResults[index] = result;
271
+ if (!result.ok) {
272
+ throw new AtomicBatchRollback(index, result.error?.code ?? "batch_failed", result.error?.message ?? "Atomic batch failed.");
273
+ }
274
+ });
275
+ return partialResults;
276
+ });
277
+ return { results: partialResults };
278
+ }
279
+ catch (error) {
280
+ if (error instanceof AtomicBatchRollback) {
281
+ return {
282
+ results: finalizeAtomicRollbackResults(entries, partialResults, error)
283
+ };
284
+ }
285
+ throw error;
286
+ }
287
+ }
288
+ function describeEntity(entityType, entity) {
289
+ const title = typeof entity.title === "string" && entity.title.trim().length > 0
290
+ ? entity.title
291
+ : typeof entity.name === "string" && entity.name.trim().length > 0
292
+ ? entity.name
293
+ : typeof entity.label === "string" && entity.label.trim().length > 0
294
+ ? entity.label
295
+ : typeof entity.summary === "string" && entity.summary.trim().length > 0
296
+ ? entity.summary
297
+ : typeof entity.body === "string" && entity.body.trim().length > 0
298
+ ? entity.body.slice(0, 72)
299
+ : entityType.replaceAll("_", " ");
300
+ const subtitle = typeof entity.description === "string" && entity.description.trim().length > 0
301
+ ? entity.description
302
+ : typeof entity.summary === "string" && entity.summary.trim().length > 0
303
+ ? entity.summary
304
+ : typeof entity.body === "string" && entity.body.trim().length > 0
305
+ ? entity.body
306
+ : "";
307
+ return { title, subtitle };
308
+ }
309
+ function matchesLinkedTo(entityType, entity, linkedTo) {
310
+ switch (entityType) {
311
+ case "project":
312
+ return linkedTo.entityType === "goal" && entity.goalId === linkedTo.id;
313
+ case "task":
314
+ return (linkedTo.entityType === "goal" && entity.goalId === linkedTo.id) || (linkedTo.entityType === "project" && entity.projectId === linkedTo.id);
315
+ case "note":
316
+ return (Array.isArray(entity.links) &&
317
+ entity.links.some((link) => typeof link === "object" &&
318
+ link !== null &&
319
+ "entityType" in link &&
320
+ "entityId" in link &&
321
+ link.entityType === linkedTo.entityType &&
322
+ link.entityId === linkedTo.id));
323
+ case "insight":
324
+ return entity.entityType === linkedTo.entityType && entity.entityId === linkedTo.id;
325
+ case "psyche_value":
326
+ return ((linkedTo.entityType === "goal" && Array.isArray(entity.linkedGoalIds) && entity.linkedGoalIds.includes(linkedTo.id)) ||
327
+ (linkedTo.entityType === "project" && Array.isArray(entity.linkedProjectIds) && entity.linkedProjectIds.includes(linkedTo.id)) ||
328
+ (linkedTo.entityType === "task" && Array.isArray(entity.linkedTaskIds) && entity.linkedTaskIds.includes(linkedTo.id)));
329
+ case "behavior_pattern":
330
+ return ((linkedTo.entityType === "psyche_value" && Array.isArray(entity.linkedValueIds) && entity.linkedValueIds.includes(linkedTo.id)) ||
331
+ (linkedTo.entityType === "mode_profile" && Array.isArray(entity.linkedModeIds) && entity.linkedModeIds.includes(linkedTo.id)) ||
332
+ (linkedTo.entityType === "belief_entry" && Array.isArray(entity.linkedBeliefIds) && entity.linkedBeliefIds.includes(linkedTo.id)));
333
+ case "behavior":
334
+ return ((linkedTo.entityType === "behavior_pattern" && Array.isArray(entity.linkedPatternIds) && entity.linkedPatternIds.includes(linkedTo.id)) ||
335
+ (linkedTo.entityType === "psyche_value" && Array.isArray(entity.linkedValueIds) && entity.linkedValueIds.includes(linkedTo.id)) ||
336
+ (linkedTo.entityType === "mode_profile" && Array.isArray(entity.linkedModeIds) && entity.linkedModeIds.includes(linkedTo.id)));
337
+ case "belief_entry":
338
+ return ((linkedTo.entityType === "psyche_value" && Array.isArray(entity.linkedValueIds) && entity.linkedValueIds.includes(linkedTo.id)) ||
339
+ (linkedTo.entityType === "behavior" && Array.isArray(entity.linkedBehaviorIds) && entity.linkedBehaviorIds.includes(linkedTo.id)) ||
340
+ (linkedTo.entityType === "mode_profile" && Array.isArray(entity.linkedModeIds) && entity.linkedModeIds.includes(linkedTo.id)) ||
341
+ (linkedTo.entityType === "trigger_report" && Array.isArray(entity.linkedReportIds) && entity.linkedReportIds.includes(linkedTo.id)));
342
+ case "mode_profile":
343
+ return ((linkedTo.entityType === "behavior_pattern" && Array.isArray(entity.linkedPatternIds) && entity.linkedPatternIds.includes(linkedTo.id)) ||
344
+ (linkedTo.entityType === "behavior" && Array.isArray(entity.linkedBehaviorIds) && entity.linkedBehaviorIds.includes(linkedTo.id)) ||
345
+ (linkedTo.entityType === "psyche_value" && Array.isArray(entity.linkedValueIds) && entity.linkedValueIds.includes(linkedTo.id)));
346
+ case "trigger_report":
347
+ return ((linkedTo.entityType === "behavior_pattern" && Array.isArray(entity.linkedPatternIds) && entity.linkedPatternIds.includes(linkedTo.id)) ||
348
+ (linkedTo.entityType === "psyche_value" && Array.isArray(entity.linkedValueIds) && entity.linkedValueIds.includes(linkedTo.id)) ||
349
+ (linkedTo.entityType === "goal" && Array.isArray(entity.linkedGoalIds) && entity.linkedGoalIds.includes(linkedTo.id)) ||
350
+ (linkedTo.entityType === "project" && Array.isArray(entity.linkedProjectIds) && entity.linkedProjectIds.includes(linkedTo.id)) ||
351
+ (linkedTo.entityType === "task" && Array.isArray(entity.linkedTaskIds) && entity.linkedTaskIds.includes(linkedTo.id)) ||
352
+ (linkedTo.entityType === "behavior" && Array.isArray(entity.linkedBehaviorIds) && entity.linkedBehaviorIds.includes(linkedTo.id)) ||
353
+ (linkedTo.entityType === "belief_entry" && Array.isArray(entity.linkedBeliefIds) && entity.linkedBeliefIds.includes(linkedTo.id)) ||
354
+ (linkedTo.entityType === "mode_profile" && Array.isArray(entity.linkedModeIds) && entity.linkedModeIds.includes(linkedTo.id)));
355
+ default:
356
+ return false;
357
+ }
358
+ }
359
+ function matchesQuery(entity, query) {
360
+ if (!query || query.trim().length === 0) {
361
+ return true;
362
+ }
363
+ const haystack = JSON.stringify(entity).toLowerCase();
364
+ return haystack.includes(query.trim().toLowerCase());
365
+ }
366
+ function matchesStatus(entity, statuses) {
367
+ if (!statuses || statuses.length === 0) {
368
+ return true;
369
+ }
370
+ return typeof entity.status === "string" ? statuses.includes(entity.status) : false;
371
+ }
372
+ function purgeAnchoredCollaboration(entityType, entityId) {
373
+ const insightIds = getDatabase()
374
+ .prepare(`SELECT id FROM insights WHERE entity_type = ? AND entity_id = ?`)
375
+ .all(entityType, entityId);
376
+ if (insightIds.length > 0) {
377
+ const placeholders = insightIds.map(() => "?").join(", ");
378
+ getDatabase()
379
+ .prepare(`DELETE FROM insight_feedback WHERE insight_id IN (${placeholders})`)
380
+ .run(...insightIds.map((row) => row.id));
381
+ getDatabase()
382
+ .prepare(`DELETE FROM insights WHERE id IN (${placeholders})`)
383
+ .run(...insightIds.map((row) => row.id));
384
+ getDatabase()
385
+ .prepare(`DELETE FROM deleted_entities WHERE entity_type = 'insight' AND entity_id IN (${placeholders})`)
386
+ .run(...insightIds.map((row) => row.id));
387
+ }
388
+ unlinkNotesForEntity(entityType, entityId, { source: "system", actor: null });
389
+ }
390
+ export function deleteEntity(entityType, id, options, context) {
391
+ const capability = getCapability(entityType);
392
+ const mode = options.mode ?? "soft";
393
+ const existing = capability.get(id);
394
+ if (!existing) {
395
+ const deleted = getDeletedEntityRecord(entityType, id);
396
+ if (!deleted || mode !== "hard") {
397
+ return undefined;
398
+ }
399
+ }
400
+ return runInTransaction(() => {
401
+ if (mode === "soft") {
402
+ const entity = capability.get(id);
403
+ if (!entity) {
404
+ return undefined;
405
+ }
406
+ const details = describeEntity(entityType, entity);
407
+ upsertDeletedEntityRecord({
408
+ entityType,
409
+ entityId: id,
410
+ title: details.title,
411
+ subtitle: details.subtitle,
412
+ snapshot: entity,
413
+ deleteReason: options.reason ?? "",
414
+ context
415
+ });
416
+ if (entityType !== "note" && entityType !== "insight") {
417
+ cascadeSoftDeleteAnchoredCollaboration(entityType, id, context, options.reason ?? "");
418
+ }
419
+ return entity;
420
+ }
421
+ clearDeletedEntityRecord(entityType, id);
422
+ if (entityType !== "note" && entityType !== "insight") {
423
+ purgeAnchoredCollaboration(entityType, id);
424
+ }
425
+ const deleted = capability.hardDelete(id, context);
426
+ clearDeletedEntityRecord(entityType, id);
427
+ return deleted;
428
+ });
429
+ }
430
+ export function restoreEntity(entityType, id) {
431
+ return runInTransaction(() => {
432
+ const deleted = restoreDeletedEntityRecord(entityType, id);
433
+ if (!deleted) {
434
+ return undefined;
435
+ }
436
+ if (entityType !== "note" && entityType !== "insight") {
437
+ restoreAnchoredCollaboration(entityType, id);
438
+ }
439
+ return getCapability(entityType).get(id) ?? deleted.snapshot;
440
+ });
441
+ }
442
+ export function createEntities(input, context) {
443
+ return executeBatchOperation(input.operations, input.atomic, (entry) => {
444
+ try {
445
+ const entity = getCapability(entry.entityType).create(parseCreateInput(entry.entityType, entry.data), context);
446
+ return { ok: true, entityType: entry.entityType, clientRef: entry.clientRef, id: String(entity.id ?? ""), entity };
447
+ }
448
+ catch (error) {
449
+ return {
450
+ ok: false,
451
+ entityType: entry.entityType,
452
+ clientRef: entry.clientRef,
453
+ error: toOperationError("create_failed", error instanceof Error ? error.message : String(error))
454
+ };
455
+ }
456
+ });
457
+ }
458
+ export function updateEntities(input, context) {
459
+ return executeBatchOperation(input.operations, input.atomic, (entry) => {
460
+ try {
461
+ const entity = getCapability(entry.entityType).update(entry.id, parseUpdatePatch(entry.entityType, entry.patch), context);
462
+ if (!entity) {
463
+ return {
464
+ ok: false,
465
+ entityType: entry.entityType,
466
+ id: entry.id,
467
+ clientRef: entry.clientRef,
468
+ error: toOperationError("not_found", `${entry.entityType} ${entry.id} was not found.`)
469
+ };
470
+ }
471
+ return { ok: true, entityType: entry.entityType, id: entry.id, clientRef: entry.clientRef, entity };
472
+ }
473
+ catch (error) {
474
+ return {
475
+ ok: false,
476
+ entityType: entry.entityType,
477
+ id: entry.id,
478
+ clientRef: entry.clientRef,
479
+ error: toOperationError("update_failed", error instanceof Error ? error.message : String(error))
480
+ };
481
+ }
482
+ });
483
+ }
484
+ export function deleteEntities(input, context) {
485
+ return executeBatchOperation(input.operations, input.atomic, (entry) => {
486
+ try {
487
+ const entity = deleteEntity(entry.entityType, entry.id, { mode: entry.mode, reason: entry.reason }, context);
488
+ if (!entity) {
489
+ return {
490
+ ok: false,
491
+ entityType: entry.entityType,
492
+ id: entry.id,
493
+ clientRef: entry.clientRef,
494
+ error: toOperationError("not_found", `${entry.entityType} ${entry.id} was not found.`)
495
+ };
496
+ }
497
+ return { ok: true, entityType: entry.entityType, id: entry.id, clientRef: entry.clientRef, entity };
498
+ }
499
+ catch (error) {
500
+ return {
501
+ ok: false,
502
+ entityType: entry.entityType,
503
+ id: entry.id,
504
+ clientRef: entry.clientRef,
505
+ error: toOperationError("delete_failed", error instanceof Error ? error.message : String(error))
506
+ };
507
+ }
508
+ });
509
+ }
510
+ export function restoreEntities(input) {
511
+ return executeBatchOperation(input.operations, input.atomic, (entry) => {
512
+ try {
513
+ const entity = restoreEntity(entry.entityType, entry.id);
514
+ if (!entity) {
515
+ return {
516
+ ok: false,
517
+ entityType: entry.entityType,
518
+ id: entry.id,
519
+ clientRef: entry.clientRef,
520
+ error: toOperationError("not_found", `${entry.entityType} ${entry.id} was not found in the bin.`)
521
+ };
522
+ }
523
+ return { ok: true, entityType: entry.entityType, id: entry.id, clientRef: entry.clientRef, entity };
524
+ }
525
+ catch (error) {
526
+ return {
527
+ ok: false,
528
+ entityType: entry.entityType,
529
+ id: entry.id,
530
+ clientRef: entry.clientRef,
531
+ error: toOperationError("restore_failed", error instanceof Error ? error.message : String(error))
532
+ };
533
+ }
534
+ });
535
+ }
536
+ export function searchEntities(input) {
537
+ const deleted = listDeletedEntities();
538
+ const defaultEntityTypes = Object.keys(CRUD_ENTITY_CAPABILITIES);
539
+ return {
540
+ results: input.searches.map((search) => {
541
+ const entityTypes = search.entityTypes && search.entityTypes.length > 0 ? search.entityTypes : defaultEntityTypes;
542
+ const liveMatches = entityTypes.flatMap((entityType) => getCapability(entityType)
543
+ .list()
544
+ .filter((entity) => (search.ids && search.ids.length > 0 ? search.ids.includes(String(entity.id ?? "")) : true))
545
+ .filter((entity) => matchesQuery(entity, search.query))
546
+ .filter((entity) => matchesStatus(entity, search.status))
547
+ .filter((entity) => (search.linkedTo ? matchesLinkedTo(entityType, entity, search.linkedTo) : true))
548
+ .slice(0, search.limit)
549
+ .map((entity) => ({ deleted: false, entityType, id: String(entity.id ?? ""), entity })));
550
+ const deletedMatches = search.includeDeleted
551
+ ? deleted
552
+ .filter((item) => entityTypes.includes(item.entityType))
553
+ .filter((item) => (search.ids && search.ids.length > 0 ? search.ids.includes(item.entityId) : true))
554
+ .filter((item) => matchesQuery(item.snapshot, search.query) || matchesQuery(item, search.query))
555
+ .filter((item) => matchesStatus(item.snapshot, search.status))
556
+ .filter((item) => (search.linkedTo ? matchesLinkedTo(item.entityType, item.snapshot, search.linkedTo) : true))
557
+ .slice(0, search.limit)
558
+ .map((item) => ({ deleted: true, entityType: item.entityType, id: item.entityId, entity: item.snapshot, deletedRecord: item }))
559
+ : [];
560
+ return {
561
+ ok: true,
562
+ clientRef: search.clientRef,
563
+ matches: [...liveMatches, ...deletedMatches].slice(0, search.limit)
564
+ };
565
+ })
566
+ };
567
+ }
568
+ export function getSettingsBinPayload() {
569
+ return buildSettingsBinPayload();
570
+ }
571
+ export function getDeletedEntityRecords() {
572
+ return listDeletedEntities();
573
+ }