forge-openclaw-plugin 0.3.16 → 0.3.17

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 (186) hide show
  1. package/dist/assets/{action-bar-DgrmzFrI.js → action-bar-D3CEYlj4.js} +1 -1
  2. package/dist/assets/{activity-page-CF451ueg.js → activity-page-Ce1pHIu5.js} +1 -1
  3. package/dist/assets/{ai-surface-workspace-DtwybxJB.js → ai-surface-workspace-DEliwOjF.js} +1 -1
  4. package/dist/assets/artifacts-page-BgyFVIVM.js +2 -0
  5. package/dist/assets/{atlas-panel-CB3uYk_K.js → atlas-panel-VZOnJa1c.js} +1 -1
  6. package/dist/assets/{board-CuxQRKPJ.js → board-DprRipIG.js} +1 -1
  7. package/dist/assets/{calendar-page-BYsDuLnh.js → calendar-page-Zstsn4uG.js} +1 -1
  8. package/dist/assets/{calendar-rules-DXuOv2J-.js → calendar-rules-BGIBuEDk.js} +1 -1
  9. package/dist/assets/{calendar-week-toolbar-8PJmiUE_.js → calendar-week-toolbar-DXFkMkbq.js} +1 -1
  10. package/dist/assets/{charts-BzT4pUPg.js → charts-C5S0-BL7.js} +1 -1
  11. package/dist/assets/{companion-sync-lab-page-DzWNOaBh.js → companion-sync-lab-page-DIPPLFKt.js} +1 -1
  12. package/dist/assets/{daily-metrics-dashboard-CHcYxDhs.js → daily-metrics-dashboard-CG-OOCJz.js} +1 -1
  13. package/dist/assets/{define-workbench-box-DcI0_QKW.js → define-workbench-box-BEEdtBkQ.js} +1 -1
  14. package/dist/assets/{entity-link-multiselect-C--AiCMb.js → entity-link-multiselect-BfDAROHB.js} +1 -1
  15. package/dist/assets/{entity-note-count-link-xne6mshj.js → entity-note-count-link-BGOiaash.js} +1 -1
  16. package/dist/assets/{entity-notes-surface-jy6Psist.js → entity-notes-surface-DPsJwqQa.js} +1 -1
  17. package/dist/assets/execution-board-Dg-2GSKv.js +1 -0
  18. package/dist/assets/{faceted-token-search-BMQ1Wwzt.js → faceted-token-search-DV7MSVYb.js} +1 -1
  19. package/dist/assets/{flagship-signal-deck-DjcskRwF.js → flagship-signal-deck-D3wVL3bC.js} +1 -1
  20. package/dist/assets/{floating-action-menu-cGhbJ2tc.js → floating-action-menu-BUs382px.js} +1 -1
  21. package/dist/assets/{forms-D1qJ3oOP.js → forms-ByKjodjN.js} +1 -1
  22. package/dist/assets/{generic-node-view-DNVwfqqq.js → generic-node-view-BY5dbPXJ.js} +1 -1
  23. package/dist/assets/{goal-detail-page-dAbyCilO.js → goal-detail-page-MYr6j2B4.js} +1 -1
  24. package/dist/assets/{goal-dialog-DH50D0tP.js → goal-dialog-nkdME5Uy.js} +1 -1
  25. package/dist/assets/goals-page-BsFeBzU1.js +1 -0
  26. package/dist/assets/{graph-BF4IsheG.js → graph-CHVj0Z7n.js} +1 -1
  27. package/dist/assets/habits-page-wO461EVU.js +1 -0
  28. package/dist/assets/{health-boxes-BPTgGM6G.js → health-boxes-BphMeSJj.js} +1 -1
  29. package/dist/assets/index-CSd8ylsy.css +1 -0
  30. package/dist/assets/index-gmPaoLN-.js +2 -0
  31. package/dist/assets/{inline-note-fields-D4mCM1gO.js → inline-note-fields-BvQwmMAv.js} +1 -1
  32. package/dist/assets/{insight-flow-dialog-Btp6bkbV.js → insight-flow-dialog-H_eaOmst.js} +1 -1
  33. package/dist/assets/{insights-page-1qM4mxjS.js → insights-page-DINYe3cB.js} +3 -3
  34. package/dist/assets/{kanban-boxes-u_A-UJG-.js → kanban-boxes-oACOTDYG.js} +1 -1
  35. package/dist/assets/{kanban-page-CKCa_3Qb.js → kanban-page-BGLXH91f.js} +1 -1
  36. package/dist/assets/knowledge-graph-page-VfMvw5jL.js +1 -0
  37. package/dist/assets/{life-force-page-BZlyA144.js → life-force-page-DQPb6UL-.js} +1 -1
  38. package/dist/assets/{life-force-workspace-CtAWZXNw.js → life-force-workspace-BJ1aI3JE.js} +1 -1
  39. package/dist/assets/{maps-BTVHALP8.js → maps-CvEHVkBk.js} +1 -1
  40. package/dist/assets/{metric-tile-Bkx2btO2.js → metric-tile-CbEe19Gd.js} +1 -1
  41. package/dist/assets/{motion-DcgUnXhY.js → motion-BibSzp57.js} +1 -1
  42. package/dist/assets/{movement-boxes-QZ2EIS9q.js → movement-boxes-dtDYhw5c.js} +1 -1
  43. package/dist/assets/{movement-page-B-3ihggI.js → movement-page-BhmwCHjs.js} +1 -1
  44. package/dist/assets/{note-markdown-BWedRE3c.js → note-markdown-CG8u2d6p.js} +1 -1
  45. package/dist/assets/{note-tags-input-DZkCqI1w.js → note-tags-input-D_conqDO.js} +1 -1
  46. package/dist/assets/{notes-boxes-DGFmt7Dp.js → notes-boxes-BLKucFqW.js} +1 -1
  47. package/dist/assets/notes-page-CafVxWjb.js +1 -0
  48. package/dist/assets/{open-in-graph-button-CjvkEj1P.js → open-in-graph-button-DFQ4r6SN.js} +1 -1
  49. package/dist/assets/{orbit-map-CRHSPenk.js → orbit-map-DsEl3ori.js} +1 -1
  50. package/dist/assets/overview-page-BffcX-pM.js +1 -0
  51. package/dist/assets/page-hero-U603l9rQ.js +1 -0
  52. package/dist/assets/pill-cluster-BYVFNppV.js +1 -0
  53. package/dist/assets/{preference-entity-handoff-button-CfCQl3cW.js → preference-entity-handoff-button-cPrTpHsV.js} +1 -1
  54. package/dist/assets/{preferences-page-OltGdsQ2.js → preferences-page-DQjFIOmt.js} +1 -1
  55. package/dist/assets/{project-collections-FfBIVwXu.js → project-collections-B9OGHGqm.js} +1 -1
  56. package/dist/assets/project-detail-page-r1Sw2kcO.js +1 -0
  57. package/dist/assets/{project-dialog-B_J1ESMk.js → project-dialog-B2_PcXAf.js} +1 -1
  58. package/dist/assets/project-management-hierarchy-page-qLNG8hsh.js +1 -0
  59. package/dist/assets/{project-management-section-nav-DBNHt9p5.js → project-management-section-nav-DFUlmMEB.js} +1 -1
  60. package/dist/assets/{projects-boxes-BvlVsO5q.js → projects-boxes-BA7_XaqX.js} +1 -1
  61. package/dist/assets/projects-page-B6ggXWFw.js +1 -0
  62. package/dist/assets/psyche-behaviors-page-ByWpXlLq.js +5 -0
  63. package/dist/assets/{psyche-flashcards-page-05606-97.js → psyche-flashcards-page-B9nSc0mk.js} +1 -1
  64. package/dist/assets/{psyche-goal-map-page-Cw-aqS3Y.js → psyche-goal-map-page-BQU7qI88.js} +1 -1
  65. package/dist/assets/{psyche-graph-0E22QHPe.js → psyche-graph-DCeP7r2b.js} +1 -1
  66. package/dist/assets/{psyche-metrics-page-DBFVPeMa.js → psyche-metrics-page-DD2lOP-J.js} +1 -1
  67. package/dist/assets/psyche-mode-guide-page-DbtZgnjr.js +1 -0
  68. package/dist/assets/psyche-modes-page-3zFJWFQf.js +1 -0
  69. package/dist/assets/psyche-page-D5vXYkfB.js +1 -0
  70. package/dist/assets/psyche-patterns-page-BneAAeKS.js +5 -0
  71. package/dist/assets/{psyche-questionnaire-builder-page-DEt0UDsz.js → psyche-questionnaire-builder-page-BH1la5C9.js} +1 -1
  72. package/dist/assets/{psyche-questionnaire-detail-page-BXQbOE6A.js → psyche-questionnaire-detail-page-DYav634P.js} +1 -1
  73. package/dist/assets/psyche-questionnaire-run-detail-page-9VaijhJm.js +1 -0
  74. package/dist/assets/{psyche-questionnaire-run-page-D_EokOQm.js → psyche-questionnaire-run-page-e1T6k_dS.js} +1 -1
  75. package/dist/assets/{psyche-questionnaires-page-D1Ov2L4n.js → psyche-questionnaires-page-Dyv367z9.js} +1 -1
  76. package/dist/assets/{psyche-report-detail-page-9HyPr8BJ.js → psyche-report-detail-page-hqxHIXw2.js} +3 -3
  77. package/dist/assets/psyche-reports-page-DhIfcGbt.js +1 -0
  78. package/dist/assets/{psyche-schemas-DDol0j-g.js → psyche-schemas-Cg51Ztxz.js} +1 -1
  79. package/dist/assets/psyche-schemas-beliefs-page-Dgb5o9vx.js +9 -0
  80. package/dist/assets/{psyche-screen-time-page-DJMDR5oo.js → psyche-screen-time-page-D6MnJGNa.js} +1 -1
  81. package/dist/assets/{psyche-self-observation-page-DFKXG1Yv.js → psyche-self-observation-page-C1Vyezbv.js} +1 -1
  82. package/dist/assets/{psyche-values-page-TWKth89J.js → psyche-values-page-B_JWVw1Q.js} +2 -2
  83. package/dist/assets/{question-flow-dialog-D-_EvoAt.js → question-flow-dialog-yMYVk998.js} +2 -2
  84. package/dist/assets/{report-chain-fields-Dy-jBQDn.js → report-chain-fields-D4NM9a6I.js} +1 -1
  85. package/dist/assets/rewards-page-B5-bcL4R.js +1 -0
  86. package/dist/assets/{scheduling-rules-editor-CAd290IE.js → scheduling-rules-editor-De72IUax.js} +1 -1
  87. package/dist/assets/{schema-badge-BLaVI1D7.js → schema-badge-jX28kUa6.js} +1 -1
  88. package/dist/assets/{schemas-B0Pa-V-A.js → schemas-BlFy-uPR.js} +1 -1
  89. package/dist/assets/{select-menu-DcS4Ukjf.js → select-menu-BXv1rsVc.js} +1 -1
  90. package/dist/assets/{settings-agents-page-Bt38HhEJ.js → settings-agents-page-DN_np10S.js} +1 -1
  91. package/dist/assets/settings-bin-page-BM5BpK_i.js +1 -0
  92. package/dist/assets/{settings-calendar-page-DPSSZV3s.js → settings-calendar-page-Cg0gSSFs.js} +3 -3
  93. package/dist/assets/{settings-data-page-BdHsD1C_.js → settings-data-page-Dwmp2rLy.js} +1 -1
  94. package/dist/assets/{settings-logs-page-D9OnWoFq.js → settings-logs-page-DQNM21Re.js} +1 -1
  95. package/dist/assets/{settings-mobile-page-DFpsXA4M.js → settings-mobile-page-DQdiRa-a.js} +1 -1
  96. package/dist/assets/settings-models-page-CAEPpuHF.js +1 -0
  97. package/dist/assets/{settings-page-m_3iYPwU.js → settings-page-Cl2KiCFg.js} +1 -1
  98. package/dist/assets/{settings-rewards-page-B2aBm-dA.js → settings-rewards-page-DoIUumhe.js} +1 -1
  99. package/dist/assets/{settings-section-nav-CMeU19Rx.js → settings-section-nav-D_N87IG0.js} +1 -1
  100. package/dist/assets/{settings-users-page-D8jyewJl.js → settings-users-page-CPesR62N.js} +1 -1
  101. package/dist/assets/{settings-wiki-page-DjOgQJAh.js → settings-wiki-page-BxMQM5Vi.js} +1 -1
  102. package/dist/assets/{sleep-page-D8-dA4bE.js → sleep-page-DUYmQKrg.js} +1 -1
  103. package/dist/assets/{sports-page-CK3PgPKB.js → sports-page-Bzi5TF9T.js} +1 -1
  104. package/dist/assets/{state-Bpe5dF3T.js → state-BFyKSULP.js} +1 -1
  105. package/dist/assets/{strategies-page-aFpJath-.js → strategies-page-C-T2MZx4.js} +1 -1
  106. package/dist/assets/{strategy-detail-page-CobF5qLv.js → strategy-detail-page-3tYuSZu-.js} +1 -1
  107. package/dist/assets/{strategy-dialog-Fgoaoob5.js → strategy-dialog-BWm4slo4.js} +1 -1
  108. package/dist/assets/{surface-D0dqgX-k.js → surface-BJObZeRw.js} +1 -1
  109. package/dist/assets/{table-U7otr5go.js → table-CTLroJKN.js} +1 -1
  110. package/dist/assets/task-detail-page-ZZOXSpSF.js +1 -0
  111. package/dist/assets/{task-dialog-eCDTF8xe.js → task-dialog-2wy0xI7f.js} +5 -5
  112. package/dist/assets/timebox-planning-dialog-C6h0Hp71.js +1 -0
  113. package/dist/assets/{today-boxes-CYfskVrM.js → today-boxes-B_TdgSDz.js} +1 -1
  114. package/dist/assets/today-page-Dipns9tl.js +1 -0
  115. package/dist/assets/training-load-page-B78e1-o-.js +1 -0
  116. package/dist/assets/{ui-B9TWEtCx.js → ui-uo_bNP7c.js} +1 -1
  117. package/dist/assets/{use-anchored-overlay-position-BY4kNzPj.js → use-anchored-overlay-position-BSxFX6Hi.js} +1 -1
  118. package/dist/assets/{use-psyche-focus-target-BhNedCZB.js → use-psyche-focus-target-1GLkhYiv.js} +1 -1
  119. package/dist/assets/{user-badge-MEZuJiir.js → user-badge-C4eZu1e_.js} +1 -1
  120. package/dist/assets/{user-select-field-fx129Uh6.js → user-select-field-CmKwcbZt.js} +1 -1
  121. package/dist/assets/{utility-widgets-h5eG2jvc.js → utility-widgets-B06wQFrd.js} +2 -2
  122. package/dist/assets/{vendor-BwL6m4SE.js → vendor-B7FKSwHK.js} +222 -212
  123. package/dist/assets/{vitals-page-eoFnQ3XL.js → vitals-page-BC7QFsm2.js} +1 -1
  124. package/dist/assets/{weekly-review-page-C7BU1gkK.js → weekly-review-page-BjNsNoWj.js} +1 -1
  125. package/dist/assets/{weight-loss-page-Cc7Do3XY.js → weight-loss-page-BOahGY9r.js} +1 -1
  126. package/dist/assets/{wiki-article-markdown-CCKoSptz.js → wiki-article-markdown-DO47HnZf.js} +2 -2
  127. package/dist/assets/{wiki-editor-page-BpbxZrgz.js → wiki-editor-page-OWRUHl4O.js} +5 -5
  128. package/dist/assets/{wiki-ingest-history-page-D5Wfr8pc.js → wiki-ingest-history-page-CuHpg2lZ.js} +1 -1
  129. package/dist/assets/{wiki-ingest-modal-DhRVsEwC.js → wiki-ingest-modal-EZ3kX-vA.js} +1 -1
  130. package/dist/assets/wiki-page-BPV3HIgu.js +1 -0
  131. package/dist/assets/{workbench-flow-page-y9FxDbKO.js → workbench-flow-page-C53KueEz.js} +3 -3
  132. package/dist/assets/{workbench-page-Da16AZvN.js → workbench-page-DJ7nT2JQ.js} +1 -1
  133. package/dist/assets/workout-detail-page-Dhyu0q7o.js +2 -0
  134. package/dist/index.html +8 -8
  135. package/dist/openclaw/parity.d.ts +1 -1
  136. package/dist/openclaw/parity.js +10 -0
  137. package/dist/openclaw/routes.js +78 -0
  138. package/dist/openclaw/tools.js +42 -0
  139. package/dist/server/apps/api/migrations/072_artifact_store.sql +106 -0
  140. package/dist/server/apps/api/src/app.js +364 -3
  141. package/dist/server/apps/api/src/openapi.js +570 -1
  142. package/dist/server/apps/api/src/repositories/entity-links.js +66 -0
  143. package/dist/server/apps/api/src/services/artifacts.js +1059 -0
  144. package/dist/server/apps/api/src/services/entity-crud.js +22 -0
  145. package/dist/server/apps/api/src/services/knowledge-graph.js +45 -0
  146. package/dist/server/apps/api/src/services/psyche-observation-calendar.js +1 -0
  147. package/dist/server/apps/api/src/types.js +2 -0
  148. package/dist/server/apps/web/src/lib/api.js +69 -0
  149. package/dist/server/apps/web/src/lib/entity-visuals.js +10 -1
  150. package/dist/server/apps/web/src/lib/knowledge-graph-types.js +9 -0
  151. package/openclaw.plugin.json +2 -1
  152. package/package.json +1 -1
  153. package/server/migrations/072_artifact_store.sql +106 -0
  154. package/skills/forge-openclaw/SKILL.md +57 -4
  155. package/skills/forge-openclaw/entity_conversation_playbooks.md +212 -14
  156. package/skills/forge-openclaw/psyche_entity_playbooks.md +20 -0
  157. package/dist/assets/execution-board-BSUZCIIx.js +0 -1
  158. package/dist/assets/goals-page-DkMy9mPD.js +0 -1
  159. package/dist/assets/habits-page-CCQR8rg6.js +0 -1
  160. package/dist/assets/index-VzCGTBS_.css +0 -1
  161. package/dist/assets/index-izRKx6JK.js +0 -2
  162. package/dist/assets/knowledge-graph-page-BZOxRv19.js +0 -1
  163. package/dist/assets/notes-page-DYkn04tz.js +0 -1
  164. package/dist/assets/overview-page-D6LsjPWe.js +0 -1
  165. package/dist/assets/page-hero-BLhM8FF3.js +0 -1
  166. package/dist/assets/pill-cluster-B5bYs_e2.js +0 -1
  167. package/dist/assets/project-detail-page-CCm3iZPQ.js +0 -1
  168. package/dist/assets/project-management-hierarchy-page-BNzvtNZj.js +0 -1
  169. package/dist/assets/projects-page-BUf7KV-_.js +0 -1
  170. package/dist/assets/psyche-behaviors-page-jtyhdpJ1.js +0 -5
  171. package/dist/assets/psyche-mode-guide-page-DI-LNEDT.js +0 -1
  172. package/dist/assets/psyche-modes-page-CaMupyfi.js +0 -1
  173. package/dist/assets/psyche-page-CFBq0YKf.js +0 -1
  174. package/dist/assets/psyche-patterns-page-sp4ikoef.js +0 -5
  175. package/dist/assets/psyche-questionnaire-run-detail-page-Cd3ClsSK.js +0 -1
  176. package/dist/assets/psyche-reports-page-BeyJg5fb.js +0 -1
  177. package/dist/assets/psyche-schemas-beliefs-page-DNmf-Vma.js +0 -9
  178. package/dist/assets/rewards-page-D3ymEd2X.js +0 -1
  179. package/dist/assets/settings-bin-page-DqyVI1i1.js +0 -1
  180. package/dist/assets/settings-models-page-DaFXLp-O.js +0 -1
  181. package/dist/assets/task-detail-page-CDK79bzk.js +0 -1
  182. package/dist/assets/timebox-planning-dialog-CNZIGSpd.js +0 -1
  183. package/dist/assets/today-page-Bnh8wopq.js +0 -1
  184. package/dist/assets/training-load-page-C7lq-jqy.js +0 -1
  185. package/dist/assets/wiki-page-1vf-HErs.js +0 -1
  186. package/dist/assets/workout-detail-page-Cq0YamXF.js +0 -2
@@ -165,6 +165,10 @@ const API_TAGS = [
165
165
  name: "Wiki",
166
166
  description: "SQLite-backed wiki settings, pages, ingest, sync, health, and search."
167
167
  },
168
+ {
169
+ name: "Artifacts",
170
+ description: "Trusted file artifact storage, metadata, static safety scans, human-only downloads, links, versions, and audit events."
171
+ },
168
172
  {
169
173
  name: "Preferences",
170
174
  description: "Preference profiles, comparisons, concepts, contexts, and learned scores."
@@ -232,7 +236,7 @@ const API_TAG_GROUPS = [
232
236
  },
233
237
  {
234
238
  name: "Knowledge And Reflection",
235
- tags: ["Wiki", "Preferences", "Psyche", "Questionnaires"]
239
+ tags: ["Wiki", "Artifacts", "Preferences", "Psyche", "Questionnaires"]
236
240
  },
237
241
  {
238
242
  name: "Platform And Agents",
@@ -289,6 +293,9 @@ function resolveTagsForPath(path) {
289
293
  if (path.startsWith("/api/v1/wiki")) {
290
294
  return ["Wiki"];
291
295
  }
296
+ if (path.startsWith("/api/v1/artifacts")) {
297
+ return ["Artifacts"];
298
+ }
292
299
  if (path.startsWith("/api/v1/preferences")) {
293
300
  return ["Preferences"];
294
301
  }
@@ -5503,6 +5510,265 @@ export function buildOpenApiDocument() {
5503
5510
  dataQuality: { type: "object", additionalProperties: true }
5504
5511
  }
5505
5512
  };
5513
+ const entityLink = {
5514
+ type: "object",
5515
+ required: [
5516
+ "sourceEntityType",
5517
+ "sourceEntityId",
5518
+ "targetEntityType",
5519
+ "targetEntityId",
5520
+ "anchorKey",
5521
+ "relationship",
5522
+ "createdByActor",
5523
+ "createdAt"
5524
+ ],
5525
+ properties: {
5526
+ sourceEntityType: { type: "string" },
5527
+ sourceEntityId: { type: "string" },
5528
+ targetEntityType: { type: "string" },
5529
+ targetEntityId: { type: "string" },
5530
+ anchorKey: nullable({ type: "string" }),
5531
+ relationship: { type: "string" },
5532
+ createdByActor: nullable({ type: "string" }),
5533
+ createdAt: { type: "string", format: "date-time" }
5534
+ }
5535
+ };
5536
+ const entityLinkInput = {
5537
+ type: "object",
5538
+ required: ["entityType", "entityId"],
5539
+ properties: {
5540
+ entityType: { type: "string" },
5541
+ entityId: { type: "string" },
5542
+ anchorKey: { type: "string" },
5543
+ relationship: { type: "string", default: "related" }
5544
+ }
5545
+ };
5546
+ const artifactScanFinding = {
5547
+ type: "object",
5548
+ required: ["code", "severity", "message"],
5549
+ properties: {
5550
+ code: { type: "string" },
5551
+ severity: {
5552
+ type: "string",
5553
+ enum: ["info", "low", "moderate", "high", "blocked"]
5554
+ },
5555
+ message: { type: "string" }
5556
+ }
5557
+ };
5558
+ const artifactScanResult = {
5559
+ type: "object",
5560
+ required: [
5561
+ "scannedAt",
5562
+ "scannerVersion",
5563
+ "declaredExtension",
5564
+ "detectedMimeType",
5565
+ "extensionAllowed",
5566
+ "byteSize",
5567
+ "findings",
5568
+ "extractedTextSample",
5569
+ "extractedTextTruncated"
5570
+ ],
5571
+ properties: {
5572
+ scannedAt: { type: "string", format: "date-time" },
5573
+ scannerVersion: { type: "string" },
5574
+ declaredExtension: { type: "string" },
5575
+ detectedMimeType: { type: "string" },
5576
+ extensionAllowed: { type: "boolean" },
5577
+ byteSize: { type: "integer" },
5578
+ findings: arrayOf(artifactScanFinding),
5579
+ extractedTextSample: { type: "string" },
5580
+ extractedTextTruncated: { type: "boolean" }
5581
+ }
5582
+ };
5583
+ const artifact = {
5584
+ type: "object",
5585
+ required: [
5586
+ "id",
5587
+ "title",
5588
+ "shortDescription",
5589
+ "description",
5590
+ "originalFileName",
5591
+ "storageKey",
5592
+ "storagePath",
5593
+ "contentSha256",
5594
+ "byteSize",
5595
+ "detectedExtension",
5596
+ "declaredMimeType",
5597
+ "detectedMimeType",
5598
+ "formatFamily",
5599
+ "sourceKind",
5600
+ "sourceLabel",
5601
+ "uploadedByUserId",
5602
+ "uploadedByAgentId",
5603
+ "actingForUserId",
5604
+ "artifactState",
5605
+ "dangerScore",
5606
+ "dangerLevel",
5607
+ "downloadPolicy",
5608
+ "scanResults",
5609
+ "enrichmentResults",
5610
+ "metadata",
5611
+ "links",
5612
+ "createdAt",
5613
+ "updatedAt"
5614
+ ],
5615
+ properties: {
5616
+ id: { type: "string" },
5617
+ title: { type: "string" },
5618
+ shortDescription: { type: "string" },
5619
+ description: { type: "string" },
5620
+ originalFileName: { type: "string" },
5621
+ storageKey: { type: "string" },
5622
+ storagePath: { type: "string" },
5623
+ contentSha256: { type: "string" },
5624
+ byteSize: { type: "integer" },
5625
+ detectedExtension: { type: "string" },
5626
+ declaredMimeType: { type: "string" },
5627
+ detectedMimeType: { type: "string" },
5628
+ formatFamily: {
5629
+ type: "string",
5630
+ enum: [
5631
+ "spreadsheet",
5632
+ "document",
5633
+ "presentation",
5634
+ "pdf",
5635
+ "text",
5636
+ "structured_text",
5637
+ "image"
5638
+ ]
5639
+ },
5640
+ sourceKind: {
5641
+ type: "string",
5642
+ enum: ["upload", "agent_upload", "wiki_ingest", "external_reference", "manual"]
5643
+ },
5644
+ sourceLabel: { type: "string" },
5645
+ uploadedByUserId: nullable({ type: "string" }),
5646
+ uploadedByAgentId: nullable({ type: "string" }),
5647
+ actingForUserId: nullable({ type: "string" }),
5648
+ artifactState: {
5649
+ type: "string",
5650
+ enum: ["active", "quarantined", "blocked", "archived", "metadata_only"]
5651
+ },
5652
+ dangerScore: { type: "integer", minimum: 0, maximum: 100 },
5653
+ dangerLevel: { type: "string", enum: ["low", "moderate", "high", "blocked"] },
5654
+ downloadPolicy: { type: "string", enum: ["human_only", "disabled"] },
5655
+ scanResults: artifactScanResult,
5656
+ enrichmentResults: { type: "object", additionalProperties: true },
5657
+ metadata: { type: "object", additionalProperties: true },
5658
+ links: arrayOf(entityLink),
5659
+ createdAt: { type: "string", format: "date-time" },
5660
+ updatedAt: { type: "string", format: "date-time" }
5661
+ }
5662
+ };
5663
+ const artifactUploadInput = {
5664
+ type: "object",
5665
+ required: ["originalFileName", "contentBase64"],
5666
+ properties: {
5667
+ title: { type: "string" },
5668
+ shortDescription: { type: "string" },
5669
+ description: { type: "string" },
5670
+ originalFileName: { type: "string" },
5671
+ declaredMimeType: { type: "string" },
5672
+ contentBase64: {
5673
+ type: "string",
5674
+ description: "Base64 file bytes. Forge stores and statically scans bytes; agents must not execute or open file contents."
5675
+ },
5676
+ sourceKind: {
5677
+ type: "string",
5678
+ enum: ["upload", "agent_upload", "wiki_ingest", "external_reference", "manual"]
5679
+ },
5680
+ sourceLabel: { type: "string" },
5681
+ uploadedByUserId: nullable({ type: "string" }),
5682
+ uploadedByAgentId: nullable({ type: "string" }),
5683
+ actingForUserId: nullable({ type: "string" }),
5684
+ downloadPolicy: { type: "string", enum: ["human_only", "disabled"] },
5685
+ links: arrayOf(entityLinkInput),
5686
+ metadata: { type: "object", additionalProperties: true },
5687
+ useLlmEnrichment: { type: "boolean" },
5688
+ llmProfileId: { type: "string" }
5689
+ }
5690
+ };
5691
+ const artifactMetadataPatchInput = {
5692
+ type: "object",
5693
+ properties: {
5694
+ title: { type: "string" },
5695
+ shortDescription: { type: "string" },
5696
+ description: { type: "string" },
5697
+ sourceLabel: { type: "string" },
5698
+ artifactState: {
5699
+ type: "string",
5700
+ enum: ["active", "quarantined", "blocked", "archived", "metadata_only"]
5701
+ },
5702
+ downloadPolicy: { type: "string", enum: ["human_only", "disabled"] },
5703
+ links: arrayOf(entityLinkInput),
5704
+ metadata: { type: "object", additionalProperties: true }
5705
+ }
5706
+ };
5707
+ const artifactTrustPatchInput = {
5708
+ type: "object",
5709
+ required: ["artifactState", "reason"],
5710
+ properties: {
5711
+ artifactState: {
5712
+ type: "string",
5713
+ enum: ["active", "quarantined", "blocked", "archived", "metadata_only"]
5714
+ },
5715
+ reason: { type: "string" },
5716
+ downloadPolicy: { type: "string", enum: ["human_only", "disabled"] }
5717
+ }
5718
+ };
5719
+ const artifactEnrichmentInput = {
5720
+ type: "object",
5721
+ properties: {
5722
+ llmProfileId: { type: "string" },
5723
+ fillMissingOnly: { type: "boolean", default: true },
5724
+ explicitApiKey: {
5725
+ type: "string",
5726
+ description: "Optional transient key for the selected LLM provider. It is not persisted by Forge."
5727
+ }
5728
+ }
5729
+ };
5730
+ const artifactVersion = {
5731
+ type: "object",
5732
+ required: [
5733
+ "id",
5734
+ "artifactId",
5735
+ "versionNumber",
5736
+ "contentSha256",
5737
+ "storageKey",
5738
+ "byteSize",
5739
+ "originalFileName",
5740
+ "scanResults",
5741
+ "enrichmentResults",
5742
+ "createdByActor",
5743
+ "createdAt"
5744
+ ],
5745
+ properties: {
5746
+ id: { type: "string" },
5747
+ artifactId: { type: "string" },
5748
+ versionNumber: { type: "integer" },
5749
+ contentSha256: { type: "string" },
5750
+ storageKey: { type: "string" },
5751
+ byteSize: { type: "integer" },
5752
+ originalFileName: { type: "string" },
5753
+ scanResults: { type: "object", additionalProperties: true },
5754
+ enrichmentResults: { type: "object", additionalProperties: true },
5755
+ createdByActor: nullable({ type: "string" }),
5756
+ createdAt: { type: "string", format: "date-time" }
5757
+ }
5758
+ };
5759
+ const artifactAuditEvent = {
5760
+ type: "object",
5761
+ required: ["id", "artifactId", "eventType", "actor", "source", "metadata", "createdAt"],
5762
+ properties: {
5763
+ id: { type: "string" },
5764
+ artifactId: { type: "string" },
5765
+ eventType: { type: "string" },
5766
+ actor: nullable({ type: "string" }),
5767
+ source: { type: "string", enum: ["ui", "openclaw", "agent", "system"] },
5768
+ metadata: { type: "object", additionalProperties: true },
5769
+ createdAt: { type: "string", format: "date-time" }
5770
+ }
5771
+ };
5506
5772
  const document = {
5507
5773
  openapi: "3.1.0",
5508
5774
  info: {
@@ -5609,6 +5875,17 @@ export function buildOpenApiDocument() {
5609
5875
  Note: note,
5610
5876
  NoteSummary: noteSummary,
5611
5877
  NotesSummaryByEntity: notesSummaryByEntity,
5878
+ EntityLink: entityLink,
5879
+ EntityLinkInput: entityLinkInput,
5880
+ ArtifactScanFinding: artifactScanFinding,
5881
+ ArtifactScanResult: artifactScanResult,
5882
+ Artifact: artifact,
5883
+ ArtifactUploadInput: artifactUploadInput,
5884
+ ArtifactMetadataPatchInput: artifactMetadataPatchInput,
5885
+ ArtifactTrustPatchInput: artifactTrustPatchInput,
5886
+ ArtifactEnrichmentInput: artifactEnrichmentInput,
5887
+ ArtifactVersion: artifactVersion,
5888
+ ArtifactAuditEvent: artifactAuditEvent,
5612
5889
  HealthLink: healthLink,
5613
5890
  SleepSession: sleepSession,
5614
5891
  WorkoutSession: workoutSession,
@@ -5645,6 +5922,298 @@ export function buildOpenApiDocument() {
5645
5922
  }
5646
5923
  },
5647
5924
  paths: {
5925
+ "/api/v1/artifacts": {
5926
+ get: {
5927
+ summary: "List artifact metadata",
5928
+ description: "Lists stored file artifacts and their metadata, scan state, danger score, and generic entity links. This route does not return file bytes.",
5929
+ parameters: [
5930
+ { name: "query", in: "query", schema: { type: "string" } },
5931
+ {
5932
+ name: "artifactState",
5933
+ in: "query",
5934
+ schema: {
5935
+ type: "string",
5936
+ enum: ["active", "quarantined", "blocked", "archived", "metadata_only"]
5937
+ }
5938
+ },
5939
+ {
5940
+ name: "dangerLevel",
5941
+ in: "query",
5942
+ schema: { type: "string", enum: ["low", "moderate", "high", "blocked"] }
5943
+ },
5944
+ {
5945
+ name: "formatFamily",
5946
+ in: "query",
5947
+ schema: {
5948
+ type: "string",
5949
+ enum: [
5950
+ "spreadsheet",
5951
+ "document",
5952
+ "presentation",
5953
+ "pdf",
5954
+ "text",
5955
+ "structured_text",
5956
+ "image"
5957
+ ]
5958
+ }
5959
+ },
5960
+ { name: "linkedEntityType", in: "query", schema: { type: "string" } },
5961
+ { name: "linkedEntityId", in: "query", schema: { type: "string" } },
5962
+ { name: "limit", in: "query", schema: { type: "integer", minimum: 1, maximum: 500 } }
5963
+ ],
5964
+ responses: {
5965
+ "200": jsonResponse({
5966
+ type: "object",
5967
+ required: ["artifacts"],
5968
+ properties: { artifacts: arrayOf({ $ref: "#/components/schemas/Artifact" }) }
5969
+ }, "Artifact list"),
5970
+ default: { $ref: "#/components/responses/Error" }
5971
+ }
5972
+ },
5973
+ post: {
5974
+ summary: "Upload a trusted file artifact",
5975
+ description: "Stores base64 file bytes only for trusted human sessions or trusted/autonomous agent tokens with artifact upload scopes. Forge statically scans and stores the file for human download; it does not execute or autonomously open the file.",
5976
+ requestBody: {
5977
+ required: true,
5978
+ content: {
5979
+ "application/json": {
5980
+ schema: { $ref: "#/components/schemas/ArtifactUploadInput" }
5981
+ }
5982
+ }
5983
+ },
5984
+ responses: {
5985
+ "201": jsonResponse({
5986
+ type: "object",
5987
+ required: ["artifact"],
5988
+ properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
5989
+ }, "Created artifact"),
5990
+ default: { $ref: "#/components/responses/Error" }
5991
+ }
5992
+ }
5993
+ },
5994
+ "/api/v1/artifacts/{id}": {
5995
+ parameters: [
5996
+ {
5997
+ name: "id",
5998
+ in: "path",
5999
+ required: true,
6000
+ schema: { type: "string" }
6001
+ }
6002
+ ],
6003
+ get: {
6004
+ summary: "Get artifact metadata",
6005
+ responses: {
6006
+ "200": jsonResponse({
6007
+ type: "object",
6008
+ required: ["artifact"],
6009
+ properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6010
+ }, "Artifact metadata"),
6011
+ default: { $ref: "#/components/responses/Error" }
6012
+ }
6013
+ },
6014
+ patch: {
6015
+ summary: "Patch artifact metadata",
6016
+ requestBody: {
6017
+ required: true,
6018
+ content: {
6019
+ "application/json": {
6020
+ schema: { $ref: "#/components/schemas/ArtifactMetadataPatchInput" }
6021
+ }
6022
+ }
6023
+ },
6024
+ responses: {
6025
+ "200": jsonResponse({
6026
+ type: "object",
6027
+ required: ["artifact"],
6028
+ properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6029
+ }, "Updated artifact"),
6030
+ default: { $ref: "#/components/responses/Error" }
6031
+ }
6032
+ }
6033
+ },
6034
+ "/api/v1/artifacts/{id}/download": {
6035
+ parameters: [
6036
+ {
6037
+ name: "id",
6038
+ in: "path",
6039
+ required: true,
6040
+ schema: { type: "string" }
6041
+ }
6042
+ ],
6043
+ get: {
6044
+ summary: "Download artifact bytes for a human operator",
6045
+ description: "Returns the stored file bytes only to an authenticated human/operator session. Agent tokens are not allowed to download artifacts.",
6046
+ responses: {
6047
+ "200": {
6048
+ description: "Artifact file bytes",
6049
+ content: {
6050
+ "application/octet-stream": {
6051
+ schema: { type: "string", format: "binary" }
6052
+ }
6053
+ }
6054
+ },
6055
+ default: { $ref: "#/components/responses/Error" }
6056
+ }
6057
+ }
6058
+ },
6059
+ "/api/v1/artifacts/{id}/scan": {
6060
+ parameters: [
6061
+ {
6062
+ name: "id",
6063
+ in: "path",
6064
+ required: true,
6065
+ schema: { type: "string" }
6066
+ }
6067
+ ],
6068
+ post: {
6069
+ summary: "Rescan an artifact with the static safety scanner",
6070
+ responses: {
6071
+ "200": jsonResponse({
6072
+ type: "object",
6073
+ required: ["artifact"],
6074
+ properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6075
+ }, "Rescanned artifact"),
6076
+ default: { $ref: "#/components/responses/Error" }
6077
+ }
6078
+ }
6079
+ },
6080
+ "/api/v1/artifacts/{id}/enrich": {
6081
+ parameters: [
6082
+ {
6083
+ name: "id",
6084
+ in: "path",
6085
+ required: true,
6086
+ schema: { type: "string" }
6087
+ }
6088
+ ],
6089
+ post: {
6090
+ summary: "Use a configured LLM to fill missing artifact metadata",
6091
+ description: "LLM enrichment receives only safe metadata, scan findings, and static text samples. It may propose title, short description, description, tags, and a danger score, but Forge never lowers the deterministic scanner danger score.",
6092
+ requestBody: {
6093
+ required: false,
6094
+ content: {
6095
+ "application/json": {
6096
+ schema: { $ref: "#/components/schemas/ArtifactEnrichmentInput" }
6097
+ }
6098
+ }
6099
+ },
6100
+ responses: {
6101
+ "200": jsonResponse({
6102
+ type: "object",
6103
+ required: ["artifact"],
6104
+ properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6105
+ }, "Enriched artifact"),
6106
+ default: { $ref: "#/components/responses/Error" }
6107
+ }
6108
+ }
6109
+ },
6110
+ "/api/v1/artifacts/{id}/links": {
6111
+ parameters: [
6112
+ {
6113
+ name: "id",
6114
+ in: "path",
6115
+ required: true,
6116
+ schema: { type: "string" }
6117
+ }
6118
+ ],
6119
+ post: {
6120
+ summary: "Replace generic entity links for an artifact",
6121
+ description: "Stores artifact relationships through Forge's reusable entity_links model. Use this to connect artifacts to goals, projects, tasks, wiki-backed notes, Psyche records, calendar entities, and other supported Forge entities.",
6122
+ requestBody: {
6123
+ required: true,
6124
+ content: {
6125
+ "application/json": {
6126
+ schema: {
6127
+ type: "object",
6128
+ required: ["links"],
6129
+ properties: {
6130
+ links: arrayOf({ $ref: "#/components/schemas/EntityLinkInput" })
6131
+ }
6132
+ }
6133
+ }
6134
+ }
6135
+ },
6136
+ responses: {
6137
+ "200": jsonResponse({
6138
+ type: "object",
6139
+ required: ["artifact"],
6140
+ properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6141
+ }, "Relinked artifact"),
6142
+ default: { $ref: "#/components/responses/Error" }
6143
+ }
6144
+ }
6145
+ },
6146
+ "/api/v1/artifacts/{id}/trust": {
6147
+ parameters: [
6148
+ {
6149
+ name: "id",
6150
+ in: "path",
6151
+ required: true,
6152
+ schema: { type: "string" }
6153
+ }
6154
+ ],
6155
+ post: {
6156
+ summary: "Apply a trusted artifact state override",
6157
+ requestBody: {
6158
+ required: true,
6159
+ content: {
6160
+ "application/json": {
6161
+ schema: { $ref: "#/components/schemas/ArtifactTrustPatchInput" }
6162
+ }
6163
+ }
6164
+ },
6165
+ responses: {
6166
+ "200": jsonResponse({
6167
+ type: "object",
6168
+ required: ["artifact"],
6169
+ properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6170
+ }, "Trust-updated artifact"),
6171
+ default: { $ref: "#/components/responses/Error" }
6172
+ }
6173
+ }
6174
+ },
6175
+ "/api/v1/artifacts/{id}/versions": {
6176
+ parameters: [
6177
+ {
6178
+ name: "id",
6179
+ in: "path",
6180
+ required: true,
6181
+ schema: { type: "string" }
6182
+ }
6183
+ ],
6184
+ get: {
6185
+ summary: "List artifact versions",
6186
+ responses: {
6187
+ "200": jsonResponse({
6188
+ type: "object",
6189
+ required: ["versions"],
6190
+ properties: { versions: arrayOf({ $ref: "#/components/schemas/ArtifactVersion" }) }
6191
+ }, "Artifact versions"),
6192
+ default: { $ref: "#/components/responses/Error" }
6193
+ }
6194
+ }
6195
+ },
6196
+ "/api/v1/artifacts/{id}/audit": {
6197
+ parameters: [
6198
+ {
6199
+ name: "id",
6200
+ in: "path",
6201
+ required: true,
6202
+ schema: { type: "string" }
6203
+ }
6204
+ ],
6205
+ get: {
6206
+ summary: "List artifact audit events",
6207
+ responses: {
6208
+ "200": jsonResponse({
6209
+ type: "object",
6210
+ required: ["events"],
6211
+ properties: { events: arrayOf({ $ref: "#/components/schemas/ArtifactAuditEvent" }) }
6212
+ }, "Artifact audit events"),
6213
+ default: { $ref: "#/components/responses/Error" }
6214
+ }
6215
+ }
6216
+ },
5648
6217
  "/api/v1/health": {
5649
6218
  get: {
5650
6219
  summary: "Get Forge API health and watchdog status",
@@ -0,0 +1,66 @@
1
+ import { getDatabase } from "../db.js";
2
+ function mapRow(row) {
3
+ return {
4
+ sourceEntityType: row.source_entity_type,
5
+ sourceEntityId: row.source_entity_id,
6
+ targetEntityType: row.target_entity_type,
7
+ targetEntityId: row.target_entity_id,
8
+ anchorKey: row.anchor_key.trim() || null,
9
+ relationship: row.relationship,
10
+ createdByActor: row.created_by_actor,
11
+ createdAt: row.created_at
12
+ };
13
+ }
14
+ function normalizeLink(link) {
15
+ return {
16
+ entityType: link.entityType.trim(),
17
+ entityId: link.entityId.trim(),
18
+ anchorKey: link.anchorKey?.trim() ?? "",
19
+ relationship: link.relationship?.trim() || "related"
20
+ };
21
+ }
22
+ export function normalizeEntityLinks(links) {
23
+ const seen = new Set();
24
+ return links
25
+ .map(normalizeLink)
26
+ .filter((link) => link.entityType.length > 0 && link.entityId.length > 0)
27
+ .filter((link) => {
28
+ const key = `${link.entityType}:${link.entityId}:${link.anchorKey}:${link.relationship}`;
29
+ if (seen.has(key)) {
30
+ return false;
31
+ }
32
+ seen.add(key);
33
+ return true;
34
+ });
35
+ }
36
+ export function listEntityLinksForSources(sourceEntityType, sourceEntityIds) {
37
+ if (sourceEntityIds.length === 0) {
38
+ return [];
39
+ }
40
+ const placeholders = sourceEntityIds.map(() => "?").join(", ");
41
+ const rows = getDatabase()
42
+ .prepare(`SELECT source_entity_type, source_entity_id, target_entity_type, target_entity_id,
43
+ anchor_key, relationship, created_by_actor, created_at
44
+ FROM entity_links
45
+ WHERE source_entity_type = ?
46
+ AND source_entity_id IN (${placeholders})
47
+ ORDER BY created_at ASC`)
48
+ .all(sourceEntityType, ...sourceEntityIds);
49
+ return rows.map(mapRow);
50
+ }
51
+ export function replaceEntityLinksForSource(input) {
52
+ const createdAt = (input.now ?? new Date()).toISOString();
53
+ const normalized = normalizeEntityLinks(input.links);
54
+ getDatabase()
55
+ .prepare(`DELETE FROM entity_links
56
+ WHERE source_entity_type = ?
57
+ AND source_entity_id = ?`)
58
+ .run(input.sourceEntityType, input.sourceEntityId);
59
+ const statement = getDatabase().prepare(`INSERT OR IGNORE INTO entity_links (
60
+ source_entity_type, source_entity_id, target_entity_type, target_entity_id,
61
+ anchor_key, relationship, created_by_actor, created_at
62
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);
63
+ for (const link of normalized) {
64
+ statement.run(input.sourceEntityType, input.sourceEntityId, link.entityType, link.entityId, link.anchorKey, link.relationship, input.actor ?? null, createdAt);
65
+ }
66
+ }