forge-openclaw-plugin 0.2.7 → 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 (53) hide show
  1. package/README.md +73 -1
  2. package/dist/assets/{board-CzgvdLO8.js → board-C_m78kvK.js} +2 -2
  3. package/dist/assets/{board-CzgvdLO8.js.map → board-C_m78kvK.js.map} +1 -1
  4. package/dist/assets/index-BWtLtXwb.js +36 -0
  5. package/dist/assets/index-BWtLtXwb.js.map +1 -0
  6. package/dist/assets/index-Dp5GXY_z.css +1 -0
  7. package/dist/assets/{motion-STUd1O46.js → motion-CpZvZumD.js} +2 -2
  8. package/dist/assets/{motion-STUd1O46.js.map → motion-CpZvZumD.js.map} +1 -1
  9. package/dist/assets/{table-CtNlETLc.js → table-DtyXTw03.js} +2 -2
  10. package/dist/assets/{table-CtNlETLc.js.map → table-DtyXTw03.js.map} +1 -1
  11. package/dist/assets/{ui-ThzkR_oW.js → ui-BXbpiKyS.js} +2 -2
  12. package/dist/assets/{ui-ThzkR_oW.js.map → ui-BXbpiKyS.js.map} +1 -1
  13. package/dist/assets/{vendor-DyHAI6nk.js → vendor-QBH6qVEe.js} +84 -74
  14. package/dist/assets/vendor-QBH6qVEe.js.map +1 -0
  15. package/dist/assets/{viz-BJuBCz_G.js → viz-w-IMeueL.js} +2 -2
  16. package/dist/assets/{viz-BJuBCz_G.js.map → viz-w-IMeueL.js.map} +1 -1
  17. package/dist/index.html +8 -8
  18. package/dist/openclaw/api-client.d.ts +1 -0
  19. package/dist/openclaw/local-runtime.js +2 -1
  20. package/dist/openclaw/plugin-entry-shared.js +12 -0
  21. package/dist/server/app.js +104 -67
  22. package/dist/server/demo-data.js +49 -0
  23. package/dist/server/openapi.js +84 -43
  24. package/dist/server/psyche-types.js +1 -30
  25. package/dist/server/repositories/deleted-entities.js +60 -26
  26. package/dist/server/repositories/goals.js +2 -5
  27. package/dist/server/repositories/notes.js +359 -0
  28. package/dist/server/repositories/projects.js +2 -5
  29. package/dist/server/repositories/psyche.js +11 -14
  30. package/dist/server/repositories/task-runs.js +2 -0
  31. package/dist/server/repositories/tasks.js +21 -10
  32. package/dist/server/seed-demo.js +11 -0
  33. package/dist/server/services/dashboard.js +4 -1
  34. package/dist/server/services/entity-crud.js +27 -30
  35. package/dist/server/services/insights.js +5 -5
  36. package/dist/server/services/projects.js +3 -1
  37. package/dist/server/services/psyche.js +4 -4
  38. package/dist/server/types.js +70 -11
  39. package/openclaw.plugin.json +12 -1
  40. package/package.json +1 -1
  41. package/server/migrations/001_core.sql +78 -0
  42. package/server/migrations/002_psyche.sql +164 -13
  43. package/skills/forge-openclaw/SKILL.md +17 -5
  44. package/dist/assets/index-8d_oM8fL.js +0 -27
  45. package/dist/assets/index-8d_oM8fL.js.map +0 -1
  46. package/dist/assets/index-D4A_bq8m.css +0 -1
  47. package/dist/assets/vendor-DyHAI6nk.js.map +0 -1
  48. package/dist/server/repositories/comments.js +0 -176
  49. package/server/migrations/003_timer_execution.sql +0 -18
  50. package/server/migrations/004_psyche_linked_entities.sql +0 -5
  51. package/server/migrations/005_adaptive_schemas.sql +0 -157
  52. package/server/migrations/006_psyche_auth_setting.sql +0 -4
  53. package/server/migrations/007_deleted_entities.sql +0 -16
@@ -260,8 +260,9 @@ export function buildOpenApiDocument() {
260
260
  "behavior",
261
261
  "belief_entry",
262
262
  "mode_profile",
263
+ "mode_guide_session",
263
264
  "trigger_report",
264
- "comment",
265
+ "note",
265
266
  "tag",
266
267
  "task_run",
267
268
  "system",
@@ -306,6 +307,45 @@ export function buildOpenApiDocument() {
306
307
  topGoalTitle: nullable({ type: "string" })
307
308
  }
308
309
  };
310
+ const noteLink = {
311
+ type: "object",
312
+ additionalProperties: false,
313
+ required: ["entityType", "entityId", "anchorKey"],
314
+ properties: {
315
+ entityType: { type: "string" },
316
+ entityId: { type: "string" },
317
+ anchorKey: nullable({ type: "string" })
318
+ }
319
+ };
320
+ const note = {
321
+ type: "object",
322
+ additionalProperties: false,
323
+ required: ["id", "contentMarkdown", "contentPlain", "author", "source", "createdAt", "updatedAt", "links"],
324
+ properties: {
325
+ id: { type: "string" },
326
+ contentMarkdown: { type: "string" },
327
+ contentPlain: { type: "string" },
328
+ author: nullable({ type: "string" }),
329
+ source: { type: "string", enum: ["ui", "openclaw", "agent", "system"] },
330
+ createdAt: { type: "string", format: "date-time" },
331
+ updatedAt: { type: "string", format: "date-time" },
332
+ links: arrayOf({ $ref: "#/components/schemas/NoteLink" })
333
+ }
334
+ };
335
+ const noteSummary = {
336
+ type: "object",
337
+ additionalProperties: false,
338
+ required: ["count", "latestNoteId", "latestCreatedAt"],
339
+ properties: {
340
+ count: { type: "integer" },
341
+ latestNoteId: nullable({ type: "string" }),
342
+ latestCreatedAt: nullable({ type: "string", format: "date-time" })
343
+ }
344
+ };
345
+ const notesSummaryByEntity = {
346
+ type: "object",
347
+ additionalProperties: { $ref: "#/components/schemas/NoteSummary" }
348
+ };
309
349
  const achievementSignal = {
310
350
  type: "object",
311
351
  additionalProperties: false,
@@ -338,7 +378,7 @@ export function buildOpenApiDocument() {
338
378
  const dashboardPayload = {
339
379
  type: "object",
340
380
  additionalProperties: false,
341
- required: ["stats", "goals", "projects", "tasks", "tags", "suggestedTags", "owners", "executionBuckets", "gamification", "achievements", "milestoneRewards", "recentActivity"],
381
+ required: ["stats", "goals", "projects", "tasks", "tags", "suggestedTags", "owners", "executionBuckets", "gamification", "achievements", "milestoneRewards", "recentActivity", "notesSummaryByEntity"],
342
382
  properties: {
343
383
  stats: {
344
384
  type: "object",
@@ -375,7 +415,8 @@ export function buildOpenApiDocument() {
375
415
  gamification: { $ref: "#/components/schemas/GamificationProfile" },
376
416
  achievements: arrayOf({ $ref: "#/components/schemas/AchievementSignal" }),
377
417
  milestoneRewards: arrayOf({ $ref: "#/components/schemas/MilestoneReward" }),
378
- recentActivity: arrayOf({ $ref: "#/components/schemas/ActivityEvent" })
418
+ recentActivity: arrayOf({ $ref: "#/components/schemas/ActivityEvent" }),
419
+ notesSummaryByEntity: { $ref: "#/components/schemas/NotesSummaryByEntity" }
379
420
  }
380
421
  };
381
422
  const overviewContext = {
@@ -539,25 +580,27 @@ export function buildOpenApiDocument() {
539
580
  const taskContextPayload = {
540
581
  type: "object",
541
582
  additionalProperties: false,
542
- required: ["task", "goal", "project", "activeTaskRun", "taskRuns", "activity"],
583
+ required: ["task", "goal", "project", "activeTaskRun", "taskRuns", "activity", "notesSummaryByEntity"],
543
584
  properties: {
544
585
  task: { $ref: "#/components/schemas/Task" },
545
586
  goal: nullable({ $ref: "#/components/schemas/Goal" }),
546
587
  project: nullable({ $ref: "#/components/schemas/ProjectSummary" }),
547
588
  activeTaskRun: nullable({ $ref: "#/components/schemas/TaskRun" }),
548
589
  taskRuns: arrayOf({ $ref: "#/components/schemas/TaskRun" }),
549
- activity: arrayOf({ $ref: "#/components/schemas/ActivityEvent" })
590
+ activity: arrayOf({ $ref: "#/components/schemas/ActivityEvent" }),
591
+ notesSummaryByEntity: { $ref: "#/components/schemas/NotesSummaryByEntity" }
550
592
  }
551
593
  };
552
594
  const projectBoardPayload = {
553
595
  type: "object",
554
596
  additionalProperties: false,
555
- required: ["project", "goal", "tasks", "activity"],
597
+ required: ["project", "goal", "tasks", "activity", "notesSummaryByEntity"],
556
598
  properties: {
557
599
  project: { $ref: "#/components/schemas/ProjectSummary" },
558
600
  goal: { $ref: "#/components/schemas/Goal" },
559
601
  tasks: arrayOf({ $ref: "#/components/schemas/Task" }),
560
- activity: arrayOf({ $ref: "#/components/schemas/ActivityEvent" })
602
+ activity: arrayOf({ $ref: "#/components/schemas/ActivityEvent" }),
603
+ notesSummaryByEntity: { $ref: "#/components/schemas/NotesSummaryByEntity" }
561
604
  }
562
605
  };
563
606
  const insightsPayload = {
@@ -745,7 +788,17 @@ export function buildOpenApiDocument() {
745
788
  additionalProperties: false,
746
789
  properties: {
747
790
  actor: { type: "string" },
748
- note: { type: "string", default: "" }
791
+ note: { type: "string", default: "" },
792
+ closeoutNote: {
793
+ type: "object",
794
+ additionalProperties: false,
795
+ required: ["contentMarkdown"],
796
+ properties: {
797
+ contentMarkdown: { type: "string" },
798
+ author: nullable({ type: "string" }),
799
+ links: arrayOf({ $ref: "#/components/schemas/NoteLink" })
800
+ }
801
+ }
749
802
  }
750
803
  };
751
804
  const taskRunFocusInput = {
@@ -1217,12 +1270,13 @@ export function buildOpenApiDocument() {
1217
1270
  conceptModel: {
1218
1271
  type: "object",
1219
1272
  additionalProperties: false,
1220
- required: ["goal", "project", "task", "taskRun", "insight", "psyche"],
1273
+ required: ["goal", "project", "task", "taskRun", "note", "insight", "psyche"],
1221
1274
  properties: {
1222
1275
  goal: { type: "string" },
1223
1276
  project: { type: "string" },
1224
1277
  task: { type: "string" },
1225
1278
  taskRun: { type: "string" },
1279
+ note: { type: "string" },
1226
1280
  insight: { type: "string" },
1227
1281
  psyche: { type: "string" }
1228
1282
  }
@@ -1760,22 +1814,6 @@ export function buildOpenApiDocument() {
1760
1814
  updatedAt: { type: "string", format: "date-time" }
1761
1815
  }
1762
1816
  };
1763
- const comment = {
1764
- type: "object",
1765
- additionalProperties: false,
1766
- required: ["id", "entityType", "entityId", "anchorKey", "body", "author", "source", "createdAt", "updatedAt"],
1767
- properties: {
1768
- id: { type: "string" },
1769
- entityType: { type: "string" },
1770
- entityId: { type: "string" },
1771
- anchorKey: nullable({ type: "string" }),
1772
- body: { type: "string" },
1773
- author: nullable({ type: "string" }),
1774
- source: { type: "string", enum: ["ui", "openclaw", "agent", "system"] },
1775
- createdAt: { type: "string", format: "date-time" },
1776
- updatedAt: { type: "string", format: "date-time" }
1777
- }
1778
- };
1779
1817
  const triggerReport = {
1780
1818
  type: "object",
1781
1819
  additionalProperties: false,
@@ -1903,7 +1941,7 @@ export function buildOpenApiDocument() {
1903
1941
  "schemaPressure",
1904
1942
  "reports",
1905
1943
  "openInsights",
1906
- "unresolvedComments",
1944
+ "openNotes",
1907
1945
  "committedActions"
1908
1946
  ],
1909
1947
  properties: {
@@ -1926,7 +1964,7 @@ export function buildOpenApiDocument() {
1926
1964
  }),
1927
1965
  reports: arrayOf({ $ref: "#/components/schemas/TriggerReport" }),
1928
1966
  openInsights: { type: "integer" },
1929
- unresolvedComments: { type: "integer" },
1967
+ openNotes: { type: "integer" },
1930
1968
  committedActions: arrayOf({ type: "string" })
1931
1969
  }
1932
1970
  };
@@ -1994,7 +2032,10 @@ export function buildOpenApiDocument() {
1994
2032
  ModeProfile: modeProfile,
1995
2033
  ModeGuideSession: modeGuideSession,
1996
2034
  TriggerReport: triggerReport,
1997
- Comment: comment,
2035
+ NoteLink: noteLink,
2036
+ Note: note,
2037
+ NoteSummary: noteSummary,
2038
+ NotesSummaryByEntity: notesSummaryByEntity,
1998
2039
  PsycheOverviewPayload: psycheOverviewPayload,
1999
2040
  Insight: insight,
2000
2041
  InsightFeedback: insightFeedback,
@@ -2445,14 +2486,14 @@ export function buildOpenApiDocument() {
2445
2486
  },
2446
2487
  "/api/v1/psyche/reports/{id}": {
2447
2488
  get: {
2448
- summary: "Get a trigger report with comments and linked insights",
2489
+ summary: "Get a trigger report with linked notes and insights",
2449
2490
  responses: {
2450
2491
  "200": jsonResponse({
2451
2492
  type: "object",
2452
- required: ["report", "comments", "insights"],
2493
+ required: ["report", "notes", "insights"],
2453
2494
  properties: {
2454
2495
  report: { $ref: "#/components/schemas/TriggerReport" },
2455
- comments: arrayOf({ $ref: "#/components/schemas/Comment" }),
2496
+ notes: arrayOf({ $ref: "#/components/schemas/Note" }),
2456
2497
  insights: arrayOf({ $ref: "#/components/schemas/Insight" })
2457
2498
  }
2458
2499
  }, "Trigger report detail"),
@@ -2474,41 +2515,41 @@ export function buildOpenApiDocument() {
2474
2515
  }
2475
2516
  }
2476
2517
  },
2477
- "/api/v1/comments": {
2518
+ "/api/v1/notes": {
2478
2519
  get: {
2479
- summary: "List comments on Forge entities",
2520
+ summary: "List notes linked to Forge entities",
2480
2521
  responses: {
2481
- "200": jsonResponse({ type: "object", required: ["comments"], properties: { comments: arrayOf({ $ref: "#/components/schemas/Comment" }) } }, "Comment collection"),
2522
+ "200": jsonResponse({ type: "object", required: ["notes"], properties: { notes: arrayOf({ $ref: "#/components/schemas/Note" }) } }, "Note collection"),
2482
2523
  default: { $ref: "#/components/responses/Error" }
2483
2524
  }
2484
2525
  },
2485
2526
  post: {
2486
- summary: "Create a comment on a Forge entity",
2527
+ summary: "Create a note linked to one or more Forge entities",
2487
2528
  responses: {
2488
- "201": jsonResponse({ type: "object", required: ["comment"], properties: { comment: { $ref: "#/components/schemas/Comment" } } }, "Created comment"),
2529
+ "201": jsonResponse({ type: "object", required: ["note"], properties: { note: { $ref: "#/components/schemas/Note" } } }, "Created note"),
2489
2530
  default: { $ref: "#/components/responses/Error" }
2490
2531
  }
2491
2532
  }
2492
2533
  },
2493
- "/api/v1/comments/{id}": {
2534
+ "/api/v1/notes/{id}": {
2494
2535
  get: {
2495
- summary: "Get a comment",
2536
+ summary: "Get a note",
2496
2537
  responses: {
2497
- "200": jsonResponse({ type: "object", required: ["comment"], properties: { comment: { $ref: "#/components/schemas/Comment" } } }, "Comment"),
2538
+ "200": jsonResponse({ type: "object", required: ["note"], properties: { note: { $ref: "#/components/schemas/Note" } } }, "Note"),
2498
2539
  default: { $ref: "#/components/responses/Error" }
2499
2540
  }
2500
2541
  },
2501
2542
  patch: {
2502
- summary: "Update a comment",
2543
+ summary: "Update a note",
2503
2544
  responses: {
2504
- "200": jsonResponse({ type: "object", required: ["comment"], properties: { comment: { $ref: "#/components/schemas/Comment" } } }, "Updated comment"),
2545
+ "200": jsonResponse({ type: "object", required: ["note"], properties: { note: { $ref: "#/components/schemas/Note" } } }, "Updated note"),
2505
2546
  default: { $ref: "#/components/responses/Error" }
2506
2547
  }
2507
2548
  },
2508
2549
  delete: {
2509
- summary: "Delete a comment",
2550
+ summary: "Delete a note",
2510
2551
  responses: {
2511
- "200": jsonResponse({ type: "object", required: ["comment"], properties: { comment: { $ref: "#/components/schemas/Comment" } } }, "Deleted comment"),
2552
+ "200": jsonResponse({ type: "object", required: ["note"], properties: { note: { $ref: "#/components/schemas/Note" } } }, "Deleted note"),
2512
2553
  default: { $ref: "#/components/responses/Error" }
2513
2554
  }
2514
2555
  }
@@ -3,7 +3,6 @@ const trimmedString = z.string().trim();
3
3
  const nonEmptyTrimmedString = trimmedString.min(1);
4
4
  const uniqueStringArraySchema = z.array(nonEmptyTrimmedString);
5
5
  export const triggerReportStatusSchema = z.enum(["draft", "reviewed", "integrated"]);
6
- export const commentSourceSchema = z.enum(["ui", "openclaw", "agent", "system"]);
7
6
  export const behaviorKindSchema = z.enum(["away", "committed", "recovery"]);
8
7
  export const beliefTypeSchema = z.enum(["absolute", "conditional"]);
9
8
  export const modeFamilySchema = z.enum(["coping", "child", "critic_parent", "healthy_adult", "happy_child"]);
@@ -225,17 +224,6 @@ export const triggerReportSchema = z.object({
225
224
  createdAt: z.string(),
226
225
  updatedAt: z.string()
227
226
  });
228
- export const commentSchema = z.object({
229
- id: z.string(),
230
- entityType: nonEmptyTrimmedString,
231
- entityId: nonEmptyTrimmedString,
232
- anchorKey: trimmedString.nullable(),
233
- body: nonEmptyTrimmedString,
234
- author: trimmedString.nullable(),
235
- source: commentSourceSchema,
236
- createdAt: z.string(),
237
- updatedAt: z.string()
238
- });
239
227
  export const schemaPressureEntrySchema = z.object({
240
228
  schemaId: z.string(),
241
229
  title: nonEmptyTrimmedString,
@@ -252,7 +240,7 @@ export const psycheOverviewPayloadSchema = z.object({
252
240
  reports: z.array(triggerReportSchema),
253
241
  schemaPressure: z.array(schemaPressureEntrySchema),
254
242
  openInsights: z.number().int().nonnegative(),
255
- unresolvedComments: z.number().int().nonnegative(),
243
+ openNotes: z.number().int().nonnegative(),
256
244
  committedActions: z.array(trimmedString)
257
245
  });
258
246
  export const createPsycheValueSchema = z.object({
@@ -376,20 +364,3 @@ export const createTriggerReportSchema = z.object({
376
364
  nextMoves: z.array(trimmedString).default([])
377
365
  });
378
366
  export const updateTriggerReportSchema = createTriggerReportSchema.partial();
379
- export const createCommentSchema = z.object({
380
- entityType: nonEmptyTrimmedString,
381
- entityId: nonEmptyTrimmedString,
382
- anchorKey: trimmedString.nullable().default(null),
383
- body: nonEmptyTrimmedString,
384
- author: trimmedString.nullable().default(null)
385
- });
386
- export const updateCommentSchema = z.object({
387
- body: nonEmptyTrimmedString,
388
- author: trimmedString.nullable().default(null)
389
- });
390
- export const commentsListQuerySchema = z.object({
391
- entityType: nonEmptyTrimmedString.optional(),
392
- entityId: nonEmptyTrimmedString.optional(),
393
- limit: z.coerce.number().int().positive().max(200).optional()
394
- });
395
- export const commentListQuerySchema = commentsListQuerySchema;
@@ -107,30 +107,64 @@ export function clearDeletedEntityRecord(entityType, entityId) {
107
107
  .run(entityType, entityId);
108
108
  }
109
109
  export function cascadeSoftDeleteAnchoredCollaboration(parentEntityType, parentEntityId, context, deleteReason = "") {
110
- const commentRows = getDatabase()
111
- .prepare(`SELECT id, body, author, source, created_at, updated_at
112
- FROM entity_comments
113
- WHERE entity_type = ? AND entity_id = ?`)
110
+ const noteRows = getDatabase()
111
+ .prepare(`SELECT DISTINCT
112
+ notes.id AS id,
113
+ notes.content_markdown AS content_markdown,
114
+ notes.content_plain AS content_plain,
115
+ notes.author AS author,
116
+ notes.source AS source,
117
+ notes.created_at AS created_at,
118
+ notes.updated_at AS updated_at
119
+ FROM notes
120
+ INNER JOIN note_links
121
+ ON note_links.note_id = notes.id
122
+ LEFT JOIN deleted_entities
123
+ ON deleted_entities.entity_type = 'note'
124
+ AND deleted_entities.entity_id = notes.id
125
+ WHERE note_links.entity_type = ?
126
+ AND note_links.entity_id = ?
127
+ AND deleted_entities.entity_id IS NULL`)
114
128
  .all(parentEntityType, parentEntityId);
115
- for (const row of commentRows) {
116
- upsertDeletedEntityRecord({
117
- entityType: "comment",
118
- entityId: row.id,
119
- title: row.body.slice(0, 72) || "Comment",
120
- subtitle: `Comment on ${parentEntityType.replaceAll("_", " ")}`,
121
- snapshot: {
122
- id: row.id,
123
- entityType: parentEntityType,
124
- entityId: parentEntityId,
125
- body: row.body,
126
- author: row.author,
127
- source: row.source,
128
- createdAt: row.created_at,
129
- updatedAt: row.updated_at
130
- },
131
- deleteReason,
132
- context
133
- });
129
+ if (noteRows.length > 0) {
130
+ const placeholders = noteRows.map(() => "?").join(", ");
131
+ const linkRows = getDatabase()
132
+ .prepare(`SELECT note_id, entity_type, entity_id, anchor_key
133
+ FROM note_links
134
+ WHERE note_id IN (${placeholders})
135
+ ORDER BY created_at ASC`)
136
+ .all(...noteRows.map((row) => row.id));
137
+ const linksByNoteId = new Map();
138
+ for (const link of linkRows) {
139
+ const current = linksByNoteId.get(link.note_id) ?? [];
140
+ current.push({
141
+ entityType: link.entity_type,
142
+ entityId: link.entity_id,
143
+ anchorKey: link.anchor_key.trim().length > 0 ? link.anchor_key : null
144
+ });
145
+ linksByNoteId.set(link.note_id, current);
146
+ }
147
+ for (const row of noteRows) {
148
+ const compact = (row.content_plain || row.content_markdown).replace(/\s+/g, " ").trim();
149
+ upsertDeletedEntityRecord({
150
+ entityType: "note",
151
+ entityId: row.id,
152
+ title: compact.slice(0, 72) || "Note",
153
+ subtitle: compact.length > 72 ? compact.slice(72, 168).trim() : `Linked to ${parentEntityType.replaceAll("_", " ")}`,
154
+ snapshot: {
155
+ id: row.id,
156
+ contentMarkdown: row.content_markdown,
157
+ contentPlain: row.content_plain,
158
+ author: row.author,
159
+ source: row.source,
160
+ createdAt: row.created_at,
161
+ updatedAt: row.updated_at,
162
+ links: linksByNoteId.get(row.id) ?? []
163
+ },
164
+ deleteReason,
165
+ context
166
+ });
167
+ }
134
168
  }
135
169
  const insightRows = getDatabase()
136
170
  .prepare(`SELECT id, title, summary, created_at, updated_at
@@ -160,10 +194,10 @@ export function cascadeSoftDeleteAnchoredCollaboration(parentEntityType, parentE
160
194
  export function restoreAnchoredCollaboration(parentEntityType, parentEntityId) {
161
195
  getDatabase()
162
196
  .prepare(`DELETE FROM deleted_entities
163
- WHERE entity_type = 'comment'
197
+ WHERE entity_type = 'note'
164
198
  AND entity_id IN (
165
- SELECT id
166
- FROM entity_comments
199
+ SELECT DISTINCT note_id
200
+ FROM note_links
167
201
  WHERE entity_type = ? AND entity_id = ?
168
202
  )`)
169
203
  .run(parentEntityType, parentEntityId);
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { getDatabase, runInTransaction } from "../db.js";
3
3
  import { recordActivityEvent } from "./activity-events.js";
4
4
  import { filterDeletedEntities, filterDeletedIds, isEntityDeleted } from "./deleted-entities.js";
5
+ import { createLinkedNotes } from "./notes.js";
5
6
  import { assertGoalRelations } from "../services/relations.js";
6
7
  import { pruneLinkedEntityReferences } from "./psyche.js";
7
8
  import { goalSchema } from "../types.js";
@@ -52,6 +53,7 @@ export function createGoal(input, activity) {
52
53
  .run(id, input.title, input.description, input.horizon, input.status, input.targetPoints, input.themeColor, now, now);
53
54
  replaceGoalTags(id, input.tagIds);
54
55
  const goal = getGoalById(id);
56
+ createLinkedNotes(input.notes, { entityType: "goal", entityId: goal.id, anchorKey: null }, activity ?? { source: "ui", actor: null });
55
57
  if (activity) {
56
58
  recordActivityEvent({
57
59
  entityType: "goal",
@@ -130,11 +132,6 @@ export function deleteGoal(goalId, activity) {
130
132
  }
131
133
  return runInTransaction(() => {
132
134
  pruneLinkedEntityReferences("goal", goalId);
133
- getDatabase()
134
- .prepare(`DELETE FROM entity_comments
135
- WHERE entity_type = 'goal'
136
- AND entity_id = ?`)
137
- .run(goalId);
138
135
  getDatabase()
139
136
  .prepare(`DELETE FROM goals WHERE id = ?`)
140
137
  .run(goalId);