forge-openclaw-plugin 0.3.17 → 0.3.19

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 (163) hide show
  1. package/dist/assets/{action-bar-D3CEYlj4.js → action-bar-B3ttL3XF.js} +1 -1
  2. package/dist/assets/{activity-page-Ce1pHIu5.js → activity-page-CoNcd0PX.js} +1 -1
  3. package/dist/assets/{ai-surface-workspace-DEliwOjF.js → ai-surface-workspace-Db34puL5.js} +1 -1
  4. package/dist/assets/artifacts-page-C09tfJTW.js +2 -0
  5. package/dist/assets/{atlas-panel-VZOnJa1c.js → atlas-panel-DRMA3RbG.js} +1 -1
  6. package/dist/assets/{board-DprRipIG.js → board-Dl7As76Q.js} +1 -1
  7. package/dist/assets/{calendar-page-Zstsn4uG.js → calendar-page-CagtpmrB.js} +1 -1
  8. package/dist/assets/{calendar-rules-BGIBuEDk.js → calendar-rules-jys-Ya5M.js} +1 -1
  9. package/dist/assets/{calendar-week-toolbar-DXFkMkbq.js → calendar-week-toolbar-DWTObcj1.js} +1 -1
  10. package/dist/assets/{charts-C5S0-BL7.js → charts-YpkKrjkZ.js} +1 -1
  11. package/dist/assets/{companion-sync-lab-page-DIPPLFKt.js → companion-sync-lab-page-COYI00E2.js} +1 -1
  12. package/dist/assets/{daily-metrics-dashboard-CG-OOCJz.js → daily-metrics-dashboard-CLoHakVX.js} +1 -1
  13. package/dist/assets/{define-workbench-box-BEEdtBkQ.js → define-workbench-box-DkTWtzNA.js} +1 -1
  14. package/dist/assets/{entity-link-multiselect-BfDAROHB.js → entity-link-multiselect-HmmmJO5A.js} +1 -1
  15. package/dist/assets/{entity-note-count-link-BGOiaash.js → entity-note-count-link-BDLj5ezr.js} +1 -1
  16. package/dist/assets/{entity-notes-surface-DPsJwqQa.js → entity-notes-surface-Csbm1myW.js} +1 -1
  17. package/dist/assets/{execution-board-Dg-2GSKv.js → execution-board-C7wYWJE4.js} +1 -1
  18. package/dist/assets/{faceted-token-search-DV7MSVYb.js → faceted-token-search-B2XWEl8j.js} +1 -1
  19. package/dist/assets/{flagship-signal-deck-D3wVL3bC.js → flagship-signal-deck-DnNN_VE1.js} +1 -1
  20. package/dist/assets/{floating-action-menu-BUs382px.js → floating-action-menu-D2Lk9TOc.js} +1 -1
  21. package/dist/assets/{forms-ByKjodjN.js → forms-DznAv9hZ.js} +1 -1
  22. package/dist/assets/{generic-node-view-BY5dbPXJ.js → generic-node-view-C_WhZXoj.js} +1 -1
  23. package/dist/assets/goal-detail-page-B395rAnv.js +1 -0
  24. package/dist/assets/{goal-dialog-nkdME5Uy.js → goal-dialog-DiEV3MyU.js} +1 -1
  25. package/dist/assets/goals-page-BNwaz0yD.js +1 -0
  26. package/dist/assets/{graph-CHVj0Z7n.js → graph-BUSFLDnl.js} +1 -1
  27. package/dist/assets/{habits-page-wO461EVU.js → habits-page-BkfbiwMJ.js} +1 -1
  28. package/dist/assets/{health-boxes-BphMeSJj.js → health-boxes-BlA33CqS.js} +1 -1
  29. package/dist/assets/index-C0CztQTU.js +2 -0
  30. package/dist/assets/index-CKnJCN1y.css +1 -0
  31. package/dist/assets/{inline-note-fields-BvQwmMAv.js → inline-note-fields-CbA0QOnc.js} +1 -1
  32. package/dist/assets/{insight-flow-dialog-H_eaOmst.js → insight-flow-dialog-DdxIE6oo.js} +1 -1
  33. package/dist/assets/{insights-page-DINYe3cB.js → insights-page-C0q_J9Hz.js} +1 -1
  34. package/dist/assets/{kanban-boxes-oACOTDYG.js → kanban-boxes-BynqbGHC.js} +1 -1
  35. package/dist/assets/{kanban-page-BGLXH91f.js → kanban-page-DyiaHH0e.js} +1 -1
  36. package/dist/assets/{knowledge-graph-page-VfMvw5jL.js → knowledge-graph-page-Cn9VkUur.js} +1 -1
  37. package/dist/assets/{life-force-page-DQPb6UL-.js → life-force-page-DQPEIj23.js} +1 -1
  38. package/dist/assets/{life-force-workspace-BJ1aI3JE.js → life-force-workspace-Db7XThH2.js} +1 -1
  39. package/dist/assets/{maps-CvEHVkBk.js → maps-CpdpZmGM.js} +1 -1
  40. package/dist/assets/{metric-tile-CbEe19Gd.js → metric-tile-sDt_l_O7.js} +1 -1
  41. package/dist/assets/{motion-BibSzp57.js → motion-eRlWWQT8.js} +1 -1
  42. package/dist/assets/{movement-boxes-dtDYhw5c.js → movement-boxes-birc_cd8.js} +1 -1
  43. package/dist/assets/{movement-page-BhmwCHjs.js → movement-page-BQllmJBm.js} +1 -1
  44. package/dist/assets/{note-markdown-CG8u2d6p.js → note-markdown-Dpve4W0R.js} +1 -1
  45. package/dist/assets/{note-tags-input-D_conqDO.js → note-tags-input-Hvi_ifLe.js} +1 -1
  46. package/dist/assets/{notes-boxes-BLKucFqW.js → notes-boxes-J-MuDr8u.js} +1 -1
  47. package/dist/assets/{notes-page-CafVxWjb.js → notes-page-uR_LafDv.js} +1 -1
  48. package/dist/assets/{open-in-graph-button-DFQ4r6SN.js → open-in-graph-button-JgYTH-IQ.js} +1 -1
  49. package/dist/assets/{orbit-map-DsEl3ori.js → orbit-map-BpNCTagm.js} +1 -1
  50. package/dist/assets/overview-page-DQB4q_vg.js +1 -0
  51. package/dist/assets/{page-hero-U603l9rQ.js → page-hero-ED69y6m0.js} +1 -1
  52. package/dist/assets/pill-cluster-DbPrs1Y4.js +1 -0
  53. package/dist/assets/{preference-entity-handoff-button-cPrTpHsV.js → preference-entity-handoff-button-NkwkWqGv.js} +1 -1
  54. package/dist/assets/{preferences-page-DQjFIOmt.js → preferences-page-BFUVjsHA.js} +1 -1
  55. package/dist/assets/{project-collections-B9OGHGqm.js → project-collections-DHXN2w-P.js} +1 -1
  56. package/dist/assets/{project-detail-page-r1Sw2kcO.js → project-detail-page-nE0M0UmN.js} +1 -1
  57. package/dist/assets/{project-dialog-B2_PcXAf.js → project-dialog-CDkUuAgl.js} +1 -1
  58. package/dist/assets/{project-management-hierarchy-page-qLNG8hsh.js → project-management-hierarchy-page-CID81NpW.js} +1 -1
  59. package/dist/assets/{project-management-section-nav-DFUlmMEB.js → project-management-section-nav-BjFavt6d.js} +1 -1
  60. package/dist/assets/{projects-boxes-BA7_XaqX.js → projects-boxes-DzGqWlhE.js} +1 -1
  61. package/dist/assets/projects-page-DpFKm_CM.js +1 -0
  62. package/dist/assets/{psyche-behaviors-page-ByWpXlLq.js → psyche-behaviors-page-CEQ2EByW.js} +1 -1
  63. package/dist/assets/{psyche-flashcards-page-B9nSc0mk.js → psyche-flashcards-page-D-g1DOS7.js} +1 -1
  64. package/dist/assets/{psyche-goal-map-page-BQU7qI88.js → psyche-goal-map-page-DbWVOpVH.js} +1 -1
  65. package/dist/assets/{psyche-graph-DCeP7r2b.js → psyche-graph-1FHrdH3f.js} +1 -1
  66. package/dist/assets/{psyche-metrics-page-DD2lOP-J.js → psyche-metrics-page-B3736p8_.js} +1 -1
  67. package/dist/assets/{psyche-mode-guide-page-DbtZgnjr.js → psyche-mode-guide-page-CjsMqDsi.js} +1 -1
  68. package/dist/assets/{psyche-modes-page-3zFJWFQf.js → psyche-modes-page-B2qzppBs.js} +1 -1
  69. package/dist/assets/{psyche-page-D5vXYkfB.js → psyche-page-BEPP2B13.js} +1 -1
  70. package/dist/assets/{psyche-patterns-page-BneAAeKS.js → psyche-patterns-page-CWeNeX2P.js} +2 -2
  71. package/dist/assets/{psyche-questionnaire-builder-page-BH1la5C9.js → psyche-questionnaire-builder-page-QFg9LkM0.js} +1 -1
  72. package/dist/assets/{psyche-questionnaire-detail-page-DYav634P.js → psyche-questionnaire-detail-page-D67EJ1D5.js} +1 -1
  73. package/dist/assets/psyche-questionnaire-run-detail-page-C1KsEy8T.js +1 -0
  74. package/dist/assets/{psyche-questionnaire-run-page-e1T6k_dS.js → psyche-questionnaire-run-page-CB3rSTAX.js} +1 -1
  75. package/dist/assets/{psyche-questionnaires-page-Dyv367z9.js → psyche-questionnaires-page-wU3bZws7.js} +1 -1
  76. package/dist/assets/{psyche-report-detail-page-hqxHIXw2.js → psyche-report-detail-page-DI3jE820.js} +3 -3
  77. package/dist/assets/{psyche-reports-page-DhIfcGbt.js → psyche-reports-page-aUbgZ_12.js} +1 -1
  78. package/dist/assets/{psyche-schemas-Cg51Ztxz.js → psyche-schemas-B00gm5HO.js} +1 -1
  79. package/dist/assets/{psyche-schemas-beliefs-page-Dgb5o9vx.js → psyche-schemas-beliefs-page-C_PMXwjL.js} +2 -2
  80. package/dist/assets/{psyche-screen-time-page-D6MnJGNa.js → psyche-screen-time-page-CMIgDG-3.js} +1 -1
  81. package/dist/assets/{psyche-self-observation-page-C1Vyezbv.js → psyche-self-observation-page-DC3orZgf.js} +1 -1
  82. package/dist/assets/{psyche-values-page-B_JWVw1Q.js → psyche-values-page-CPdKfTdl.js} +2 -2
  83. package/dist/assets/{question-flow-dialog-yMYVk998.js → question-flow-dialog-B4B3BI8e.js} +2 -2
  84. package/dist/assets/{report-chain-fields-D4NM9a6I.js → report-chain-fields-D-XNut8V.js} +1 -1
  85. package/dist/assets/rewards-page-D8w07BIZ.js +1 -0
  86. package/dist/assets/{scheduling-rules-editor-De72IUax.js → scheduling-rules-editor-Cn6t-RRn.js} +1 -1
  87. package/dist/assets/{schema-badge-jX28kUa6.js → schema-badge-Dsk9AoYd.js} +1 -1
  88. package/dist/assets/{schemas-BlFy-uPR.js → schemas-3GS34K1i.js} +1 -1
  89. package/dist/assets/{select-menu-BXv1rsVc.js → select-menu-BDeaaa4m.js} +1 -1
  90. package/dist/assets/{settings-agents-page-DN_np10S.js → settings-agents-page-CkS4s4kN.js} +2 -2
  91. package/dist/assets/settings-bin-page-BHlW0n-a.js +1 -0
  92. package/dist/assets/{settings-calendar-page-Cg0gSSFs.js → settings-calendar-page-BAmKOPeT.js} +1 -1
  93. package/dist/assets/{settings-data-page-Dwmp2rLy.js → settings-data-page-C-VrzHGq.js} +1 -1
  94. package/dist/assets/{settings-logs-page-DQNM21Re.js → settings-logs-page-CnVuzJ7d.js} +1 -1
  95. package/dist/assets/{settings-mobile-page-DQdiRa-a.js → settings-mobile-page-0SWGg6CE.js} +1 -1
  96. package/dist/assets/settings-models-page-BjVixsws.js +1 -0
  97. package/dist/assets/{settings-page-Cl2KiCFg.js → settings-page-DVZ58c3R.js} +1 -1
  98. package/dist/assets/settings-rewards-page-Df0ONVFq.js +1 -0
  99. package/dist/assets/{settings-section-nav-D_N87IG0.js → settings-section-nav-Btjx5m2u.js} +1 -1
  100. package/dist/assets/settings-users-page-Cl0YuOOI.js +1 -0
  101. package/dist/assets/{settings-wiki-page-BxMQM5Vi.js → settings-wiki-page-K8KBzeYx.js} +1 -1
  102. package/dist/assets/{sleep-page-DUYmQKrg.js → sleep-page-BFj8hcTf.js} +1 -1
  103. package/dist/assets/{sports-page-Bzi5TF9T.js → sports-page-7yta1r8s.js} +1 -1
  104. package/dist/assets/{state-BFyKSULP.js → state-CkEUXgqt.js} +1 -1
  105. package/dist/assets/{strategies-page-C-T2MZx4.js → strategies-page-BQoWnPtN.js} +1 -1
  106. package/dist/assets/strategy-detail-page-D9DTQoyy.js +1 -0
  107. package/dist/assets/strategy-dialog-z9w2UB3s.js +1 -0
  108. package/dist/assets/{surface-BJObZeRw.js → surface-BL_bDiZ5.js} +1 -1
  109. package/dist/assets/{table-CTLroJKN.js → table--SK_dk4S.js} +1 -1
  110. package/dist/assets/{task-detail-page-ZZOXSpSF.js → task-detail-page-RcbvVzXn.js} +1 -1
  111. package/dist/assets/{task-dialog-2wy0xI7f.js → task-dialog-ri1qEzPp.js} +4 -4
  112. package/dist/assets/timebox-planning-dialog-DoeeGwCm.js +1 -0
  113. package/dist/assets/{today-boxes-B_TdgSDz.js → today-boxes-CTw0D5JP.js} +1 -1
  114. package/dist/assets/today-page-5-qRLbBt.js +1 -0
  115. package/dist/assets/{training-load-page-B78e1-o-.js → training-load-page-DrGnOtnH.js} +1 -1
  116. package/dist/assets/{ui-uo_bNP7c.js → ui-CDt36qNz.js} +1 -1
  117. package/dist/assets/{use-anchored-overlay-position-BSxFX6Hi.js → use-anchored-overlay-position-C2kg0Ay0.js} +1 -1
  118. package/dist/assets/{use-psyche-focus-target-1GLkhYiv.js → use-psyche-focus-target-p2l8W-Af.js} +1 -1
  119. package/dist/assets/{user-badge-C4eZu1e_.js → user-badge-BWoSrGA-.js} +1 -1
  120. package/dist/assets/{user-select-field-CmKwcbZt.js → user-select-field-DbB9v7Lf.js} +1 -1
  121. package/dist/assets/{utility-widgets-B06wQFrd.js → utility-widgets-fodvUR7I.js} +2 -2
  122. package/dist/assets/{vendor-B7FKSwHK.js → vendor-Dgw7UY7q.js} +1 -1
  123. package/dist/assets/{vitals-page-BC7QFsm2.js → vitals-page-f8QdPdpp.js} +1 -1
  124. package/dist/assets/{weekly-review-page-BjNsNoWj.js → weekly-review-page-D0wPiQgO.js} +1 -1
  125. package/dist/assets/{weight-loss-page-BOahGY9r.js → weight-loss-page-BT9dPxYi.js} +1 -1
  126. package/dist/assets/{wiki-article-markdown-DO47HnZf.js → wiki-article-markdown-Hyu5JwrY.js} +1 -1
  127. package/dist/assets/{wiki-editor-page-OWRUHl4O.js → wiki-editor-page-ujqNw8ua.js} +3 -3
  128. package/dist/assets/{wiki-ingest-history-page-CuHpg2lZ.js → wiki-ingest-history-page-BwoDT00-.js} +1 -1
  129. package/dist/assets/{wiki-ingest-modal-EZ3kX-vA.js → wiki-ingest-modal-cvnNma0M.js} +1 -1
  130. package/dist/assets/{wiki-page-BPV3HIgu.js → wiki-page-jHyJ7EgO.js} +1 -1
  131. package/dist/assets/{workbench-flow-page-C53KueEz.js → workbench-flow-page-DJD5sXMF.js} +1 -1
  132. package/dist/assets/{workbench-page-DJ7nT2JQ.js → workbench-page-Ci0xh6rG.js} +1 -1
  133. package/dist/assets/{workout-detail-page-Dhyu0q7o.js → workout-detail-page-DA30ubtE.js} +2 -2
  134. package/dist/index.html +8 -8
  135. package/dist/openclaw/tools.js +1 -1
  136. package/dist/server/apps/api/migrations/073_artifact_entity_links_repair.sql +24 -0
  137. package/dist/server/apps/api/src/app.js +26 -8
  138. package/dist/server/apps/api/src/openapi.js +103 -24
  139. package/dist/server/apps/api/src/services/artifacts.js +138 -68
  140. package/dist/server/apps/web/src/lib/api.js +3 -0
  141. package/openclaw.plugin.json +1 -1
  142. package/package.json +1 -1
  143. package/server/migrations/073_artifact_entity_links_repair.sql +24 -0
  144. package/skills/forge-openclaw/SKILL.md +7 -5
  145. package/skills/forge-openclaw/entity_conversation_playbooks.md +14 -9
  146. package/dist/assets/artifacts-page-BgyFVIVM.js +0 -2
  147. package/dist/assets/goal-detail-page-MYr6j2B4.js +0 -1
  148. package/dist/assets/goals-page-BsFeBzU1.js +0 -1
  149. package/dist/assets/index-CSd8ylsy.css +0 -1
  150. package/dist/assets/index-gmPaoLN-.js +0 -2
  151. package/dist/assets/overview-page-BffcX-pM.js +0 -1
  152. package/dist/assets/pill-cluster-BYVFNppV.js +0 -1
  153. package/dist/assets/projects-page-B6ggXWFw.js +0 -1
  154. package/dist/assets/psyche-questionnaire-run-detail-page-9VaijhJm.js +0 -1
  155. package/dist/assets/rewards-page-B5-bcL4R.js +0 -1
  156. package/dist/assets/settings-bin-page-BM5BpK_i.js +0 -1
  157. package/dist/assets/settings-models-page-CAEPpuHF.js +0 -1
  158. package/dist/assets/settings-rewards-page-DoIUumhe.js +0 -1
  159. package/dist/assets/settings-users-page-CPesR62N.js +0 -1
  160. package/dist/assets/strategy-detail-page-3tYuSZu-.js +0 -1
  161. package/dist/assets/strategy-dialog-BWm4slo4.js +0 -1
  162. package/dist/assets/timebox-planning-dialog-C6h0Hp71.js +0 -1
  163. package/dist/assets/today-page-Dipns9tl.js +0 -1
@@ -5639,7 +5639,13 @@ export function buildOpenApiDocument() {
5639
5639
  },
5640
5640
  sourceKind: {
5641
5641
  type: "string",
5642
- enum: ["upload", "agent_upload", "wiki_ingest", "external_reference", "manual"]
5642
+ enum: [
5643
+ "upload",
5644
+ "agent_upload",
5645
+ "wiki_ingest",
5646
+ "external_reference",
5647
+ "manual"
5648
+ ]
5643
5649
  },
5644
5650
  sourceLabel: { type: "string" },
5645
5651
  uploadedByUserId: nullable({ type: "string" }),
@@ -5650,7 +5656,10 @@ export function buildOpenApiDocument() {
5650
5656
  enum: ["active", "quarantined", "blocked", "archived", "metadata_only"]
5651
5657
  },
5652
5658
  dangerScore: { type: "integer", minimum: 0, maximum: 100 },
5653
- dangerLevel: { type: "string", enum: ["low", "moderate", "high", "blocked"] },
5659
+ dangerLevel: {
5660
+ type: "string",
5661
+ enum: ["low", "moderate", "high", "blocked"]
5662
+ },
5654
5663
  downloadPolicy: { type: "string", enum: ["human_only", "disabled"] },
5655
5664
  scanResults: artifactScanResult,
5656
5665
  enrichmentResults: { type: "object", additionalProperties: true },
@@ -5660,6 +5669,17 @@ export function buildOpenApiDocument() {
5660
5669
  updatedAt: { type: "string", format: "date-time" }
5661
5670
  }
5662
5671
  };
5672
+ const artifactListResponse = {
5673
+ type: "object",
5674
+ required: ["artifacts", "total", "limit", "offset", "hasMore"],
5675
+ properties: {
5676
+ artifacts: arrayOf({ $ref: "#/components/schemas/Artifact" }),
5677
+ total: { type: "integer", minimum: 0 },
5678
+ limit: { type: "integer", minimum: 1, maximum: 500 },
5679
+ offset: { type: "integer", minimum: 0 },
5680
+ hasMore: { type: "boolean" }
5681
+ }
5682
+ };
5663
5683
  const artifactUploadInput = {
5664
5684
  type: "object",
5665
5685
  required: ["originalFileName", "contentBase64"],
@@ -5675,7 +5695,13 @@ export function buildOpenApiDocument() {
5675
5695
  },
5676
5696
  sourceKind: {
5677
5697
  type: "string",
5678
- enum: ["upload", "agent_upload", "wiki_ingest", "external_reference", "manual"]
5698
+ enum: [
5699
+ "upload",
5700
+ "agent_upload",
5701
+ "wiki_ingest",
5702
+ "external_reference",
5703
+ "manual"
5704
+ ]
5679
5705
  },
5680
5706
  sourceLabel: { type: "string" },
5681
5707
  uploadedByUserId: nullable({ type: "string" }),
@@ -5758,7 +5784,15 @@ export function buildOpenApiDocument() {
5758
5784
  };
5759
5785
  const artifactAuditEvent = {
5760
5786
  type: "object",
5761
- required: ["id", "artifactId", "eventType", "actor", "source", "metadata", "createdAt"],
5787
+ required: [
5788
+ "id",
5789
+ "artifactId",
5790
+ "eventType",
5791
+ "actor",
5792
+ "source",
5793
+ "metadata",
5794
+ "createdAt"
5795
+ ],
5762
5796
  properties: {
5763
5797
  id: { type: "string" },
5764
5798
  artifactId: { type: "string" },
@@ -5880,6 +5914,7 @@ export function buildOpenApiDocument() {
5880
5914
  ArtifactScanFinding: artifactScanFinding,
5881
5915
  ArtifactScanResult: artifactScanResult,
5882
5916
  Artifact: artifact,
5917
+ ArtifactListResponse: artifactListResponse,
5883
5918
  ArtifactUploadInput: artifactUploadInput,
5884
5919
  ArtifactMetadataPatchInput: artifactMetadataPatchInput,
5885
5920
  ArtifactTrustPatchInput: artifactTrustPatchInput,
@@ -5933,13 +5968,22 @@ export function buildOpenApiDocument() {
5933
5968
  in: "query",
5934
5969
  schema: {
5935
5970
  type: "string",
5936
- enum: ["active", "quarantined", "blocked", "archived", "metadata_only"]
5971
+ enum: [
5972
+ "active",
5973
+ "quarantined",
5974
+ "blocked",
5975
+ "archived",
5976
+ "metadata_only"
5977
+ ]
5937
5978
  }
5938
5979
  },
5939
5980
  {
5940
5981
  name: "dangerLevel",
5941
5982
  in: "query",
5942
- schema: { type: "string", enum: ["low", "moderate", "high", "blocked"] }
5983
+ schema: {
5984
+ type: "string",
5985
+ enum: ["low", "moderate", "high", "blocked"]
5986
+ }
5943
5987
  },
5944
5988
  {
5945
5989
  name: "formatFamily",
@@ -5957,16 +6001,25 @@ export function buildOpenApiDocument() {
5957
6001
  ]
5958
6002
  }
5959
6003
  },
5960
- { name: "linkedEntityType", in: "query", schema: { type: "string" } },
6004
+ {
6005
+ name: "linkedEntityType",
6006
+ in: "query",
6007
+ schema: { type: "string" }
6008
+ },
5961
6009
  { name: "linkedEntityId", in: "query", schema: { type: "string" } },
5962
- { name: "limit", in: "query", schema: { type: "integer", minimum: 1, maximum: 500 } }
6010
+ {
6011
+ name: "limit",
6012
+ in: "query",
6013
+ schema: { type: "integer", minimum: 1, maximum: 500 }
6014
+ },
6015
+ {
6016
+ name: "offset",
6017
+ in: "query",
6018
+ schema: { type: "integer", minimum: 0 }
6019
+ }
5963
6020
  ],
5964
6021
  responses: {
5965
- "200": jsonResponse({
5966
- type: "object",
5967
- required: ["artifacts"],
5968
- properties: { artifacts: arrayOf({ $ref: "#/components/schemas/Artifact" }) }
5969
- }, "Artifact list"),
6022
+ "200": jsonResponse({ $ref: "#/components/schemas/ArtifactListResponse" }, "Artifact list"),
5970
6023
  default: { $ref: "#/components/responses/Error" }
5971
6024
  }
5972
6025
  },
@@ -5985,7 +6038,9 @@ export function buildOpenApiDocument() {
5985
6038
  "201": jsonResponse({
5986
6039
  type: "object",
5987
6040
  required: ["artifact"],
5988
- properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6041
+ properties: {
6042
+ artifact: { $ref: "#/components/schemas/Artifact" }
6043
+ }
5989
6044
  }, "Created artifact"),
5990
6045
  default: { $ref: "#/components/responses/Error" }
5991
6046
  }
@@ -6006,7 +6061,9 @@ export function buildOpenApiDocument() {
6006
6061
  "200": jsonResponse({
6007
6062
  type: "object",
6008
6063
  required: ["artifact"],
6009
- properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6064
+ properties: {
6065
+ artifact: { $ref: "#/components/schemas/Artifact" }
6066
+ }
6010
6067
  }, "Artifact metadata"),
6011
6068
  default: { $ref: "#/components/responses/Error" }
6012
6069
  }
@@ -6017,7 +6074,9 @@ export function buildOpenApiDocument() {
6017
6074
  required: true,
6018
6075
  content: {
6019
6076
  "application/json": {
6020
- schema: { $ref: "#/components/schemas/ArtifactMetadataPatchInput" }
6077
+ schema: {
6078
+ $ref: "#/components/schemas/ArtifactMetadataPatchInput"
6079
+ }
6021
6080
  }
6022
6081
  }
6023
6082
  },
@@ -6025,7 +6084,9 @@ export function buildOpenApiDocument() {
6025
6084
  "200": jsonResponse({
6026
6085
  type: "object",
6027
6086
  required: ["artifact"],
6028
- properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6087
+ properties: {
6088
+ artifact: { $ref: "#/components/schemas/Artifact" }
6089
+ }
6029
6090
  }, "Updated artifact"),
6030
6091
  default: { $ref: "#/components/responses/Error" }
6031
6092
  }
@@ -6071,7 +6132,9 @@ export function buildOpenApiDocument() {
6071
6132
  "200": jsonResponse({
6072
6133
  type: "object",
6073
6134
  required: ["artifact"],
6074
- properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6135
+ properties: {
6136
+ artifact: { $ref: "#/components/schemas/Artifact" }
6137
+ }
6075
6138
  }, "Rescanned artifact"),
6076
6139
  default: { $ref: "#/components/responses/Error" }
6077
6140
  }
@@ -6101,7 +6164,9 @@ export function buildOpenApiDocument() {
6101
6164
  "200": jsonResponse({
6102
6165
  type: "object",
6103
6166
  required: ["artifact"],
6104
- properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6167
+ properties: {
6168
+ artifact: { $ref: "#/components/schemas/Artifact" }
6169
+ }
6105
6170
  }, "Enriched artifact"),
6106
6171
  default: { $ref: "#/components/responses/Error" }
6107
6172
  }
@@ -6127,7 +6192,9 @@ export function buildOpenApiDocument() {
6127
6192
  type: "object",
6128
6193
  required: ["links"],
6129
6194
  properties: {
6130
- links: arrayOf({ $ref: "#/components/schemas/EntityLinkInput" })
6195
+ links: arrayOf({
6196
+ $ref: "#/components/schemas/EntityLinkInput"
6197
+ })
6131
6198
  }
6132
6199
  }
6133
6200
  }
@@ -6137,7 +6204,9 @@ export function buildOpenApiDocument() {
6137
6204
  "200": jsonResponse({
6138
6205
  type: "object",
6139
6206
  required: ["artifact"],
6140
- properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6207
+ properties: {
6208
+ artifact: { $ref: "#/components/schemas/Artifact" }
6209
+ }
6141
6210
  }, "Relinked artifact"),
6142
6211
  default: { $ref: "#/components/responses/Error" }
6143
6212
  }
@@ -6166,7 +6235,9 @@ export function buildOpenApiDocument() {
6166
6235
  "200": jsonResponse({
6167
6236
  type: "object",
6168
6237
  required: ["artifact"],
6169
- properties: { artifact: { $ref: "#/components/schemas/Artifact" } }
6238
+ properties: {
6239
+ artifact: { $ref: "#/components/schemas/Artifact" }
6240
+ }
6170
6241
  }, "Trust-updated artifact"),
6171
6242
  default: { $ref: "#/components/responses/Error" }
6172
6243
  }
@@ -6187,7 +6258,11 @@ export function buildOpenApiDocument() {
6187
6258
  "200": jsonResponse({
6188
6259
  type: "object",
6189
6260
  required: ["versions"],
6190
- properties: { versions: arrayOf({ $ref: "#/components/schemas/ArtifactVersion" }) }
6261
+ properties: {
6262
+ versions: arrayOf({
6263
+ $ref: "#/components/schemas/ArtifactVersion"
6264
+ })
6265
+ }
6191
6266
  }, "Artifact versions"),
6192
6267
  default: { $ref: "#/components/responses/Error" }
6193
6268
  }
@@ -6208,7 +6283,11 @@ export function buildOpenApiDocument() {
6208
6283
  "200": jsonResponse({
6209
6284
  type: "object",
6210
6285
  required: ["events"],
6211
- properties: { events: arrayOf({ $ref: "#/components/schemas/ArtifactAuditEvent" }) }
6286
+ properties: {
6287
+ events: arrayOf({
6288
+ $ref: "#/components/schemas/ArtifactAuditEvent"
6289
+ })
6290
+ }
6212
6291
  }, "Artifact audit events"),
6213
6292
  default: { $ref: "#/components/responses/Error" }
6214
6293
  }
@@ -5,7 +5,7 @@ import path from "node:path";
5
5
  import AdmZip from "adm-zip";
6
6
  import { z } from "zod";
7
7
  import { getDatabase, resolveDataDir, runInTransaction } from "../db.js";
8
- import { filterDeletedEntities, isEntityDeleted } from "../repositories/deleted-entities.js";
8
+ import { isEntityDeleted } from "../repositories/deleted-entities.js";
9
9
  import { listEntityLinksForSources, replaceEntityLinksForSource } from "../repositories/entity-links.js";
10
10
  import { recordEventLog } from "../repositories/event-log.js";
11
11
  import { listWikiLlmProfiles } from "../repositories/wiki-memory.js";
@@ -64,10 +64,7 @@ export const artifactDangerLevelSchema = z.enum([
64
64
  "high",
65
65
  "blocked"
66
66
  ]);
67
- export const artifactDownloadPolicySchema = z.enum([
68
- "human_only",
69
- "disabled"
70
- ]);
67
+ export const artifactDownloadPolicySchema = z.enum(["human_only", "disabled"]);
71
68
  export const artifactFormatFamilySchema = z.enum([
72
69
  "spreadsheet",
73
70
  "document",
@@ -141,7 +138,8 @@ export const artifactListQuerySchema = z.object({
141
138
  formatFamily: artifactFormatFamilySchema.optional(),
142
139
  linkedEntityType: z.string().trim().optional(),
143
140
  linkedEntityId: z.string().trim().optional(),
144
- limit: z.coerce.number().int().min(1).max(500).optional().default(100)
141
+ limit: z.coerce.number().int().min(1).max(500).optional().default(100),
142
+ offset: z.coerce.number().int().min(0).optional().default(0)
145
143
  });
146
144
  export const artifactTrustPatchSchema = z.object({
147
145
  artifactState: artifactStateSchema,
@@ -181,10 +179,16 @@ function normalizeNullableText(value) {
181
179
  return text && text.length > 0 ? text : null;
182
180
  }
183
181
  function sanitizeFileName(fileName) {
184
- return path.basename(fileName).replace(/[^\w.\- ()[\]]+/g, "_").slice(0, 180);
182
+ return path
183
+ .basename(fileName)
184
+ .replace(/[^\w.\- ()[\]]+/g, "_")
185
+ .slice(0, 180);
185
186
  }
186
187
  function extensionFromFileName(fileName) {
187
- return path.extname(sanitizeFileName(fileName)).replace(/^\./, "").toLowerCase();
188
+ return path
189
+ .extname(sanitizeFileName(fileName))
190
+ .replace(/^\./, "")
191
+ .toLowerCase();
188
192
  }
189
193
  function formatFamilyForExtension(extension) {
190
194
  return extensionToFormatFamily[extension] ?? null;
@@ -305,11 +309,21 @@ function severityScore(severity) {
305
309
  function computeDanger(findings) {
306
310
  const score = Math.min(100, findings.reduce((max, finding) => Math.max(max, severityScore(finding.severity)), 0) +
307
311
  Math.max(0, findings.length - 1) * 4);
308
- const level = score >= 90 ? "blocked" : score >= 70 ? "high" : score >= 35 ? "moderate" : "low";
312
+ const level = score >= 90
313
+ ? "blocked"
314
+ : score >= 70
315
+ ? "high"
316
+ : score >= 35
317
+ ? "moderate"
318
+ : "low";
309
319
  return { score, level };
310
320
  }
311
321
  function safeUtf8(buffer, limit = MAX_TEXT_EXTRACTION_CHARS) {
312
- return buffer.subarray(0, limit).toString("utf8").replace(/\u0000/g, "").trim();
322
+ return buffer
323
+ .subarray(0, limit)
324
+ .toString("utf8")
325
+ .replace(/\u0000/g, "")
326
+ .trim();
313
327
  }
314
328
  function stripXml(xml) {
315
329
  return xml
@@ -321,7 +335,9 @@ function stripXml(xml) {
321
335
  .trim();
322
336
  }
323
337
  function zipEntryText(zip, name) {
324
- const entry = zip.getEntries().find((candidate) => candidate.entryName === name);
338
+ const entry = zip
339
+ .getEntries()
340
+ .find((candidate) => candidate.entryName === name);
325
341
  return entry ? entry.getData().toString("utf8") : "";
326
342
  }
327
343
  function extractOfficeText(zip, extension) {
@@ -344,7 +360,10 @@ function extractOfficeText(zip, extension) {
344
360
  .slice(0, 5)
345
361
  .map((entry) => stripXml(entry.getData().toString("utf8")))
346
362
  .join("\n");
347
- return [sharedStrings, sheetText].filter(Boolean).join("\n").slice(0, MAX_TEXT_EXTRACTION_CHARS);
363
+ return [sharedStrings, sheetText]
364
+ .filter(Boolean)
365
+ .join("\n")
366
+ .slice(0, MAX_TEXT_EXTRACTION_CHARS);
348
367
  }
349
368
  return "";
350
369
  }
@@ -359,7 +378,8 @@ function scanOfficeZip(buffer, extension, findings) {
359
378
  if (entries.length > MAX_ZIP_ENTRY_COUNT) {
360
379
  addFinding(findings, "blocked", "zip_entry_limit", "The archive has too many entries for safe static inspection.");
361
380
  }
362
- if (totalUncompressed > MAX_ZIP_UNCOMPRESSED_BYTES || ratio > MAX_ZIP_RATIO) {
381
+ if (totalUncompressed > MAX_ZIP_UNCOMPRESSED_BYTES ||
382
+ ratio > MAX_ZIP_RATIO) {
363
383
  addFinding(findings, "blocked", "zip_bomb_indicator", "The archive has unsafe compressed-to-uncompressed size characteristics.");
364
384
  }
365
385
  if (entries.some((entry) => entry.entryName.endsWith("EncryptedPackage"))) {
@@ -400,7 +420,9 @@ function scanOfficeZip(buffer, extension, findings) {
400
420
  return extractedTextSample;
401
421
  }
402
422
  function scanPdf(buffer, findings) {
403
- const text = buffer.subarray(0, Math.min(buffer.byteLength, 2_000_000)).toString("latin1");
423
+ const text = buffer
424
+ .subarray(0, Math.min(buffer.byteLength, 2_000_000))
425
+ .toString("latin1");
404
426
  if (/\/JavaScript|\/JS\b/i.test(text)) {
405
427
  addFinding(findings, "high", "pdf_javascript", "The PDF contains JavaScript actions.");
406
428
  }
@@ -436,17 +458,21 @@ export function scanArtifactBytes(input) {
436
458
  const detectedMimeType = detectMimeType(input.buffer, detectedExtension);
437
459
  const formatFamily = formatFamilyForExtension(detectedExtension);
438
460
  const findings = [];
439
- if (!formatFamily || !ALLOWED_EXTENSIONS.includes(detectedExtension)) {
461
+ if (!formatFamily ||
462
+ !ALLOWED_EXTENSIONS.includes(detectedExtension)) {
440
463
  addFinding(findings, "blocked", "unsupported_extension", `Files with extension .${detectedExtension || "unknown"} are not allowed.`);
441
464
  }
442
465
  if (input.buffer.byteLength > MAX_ARTIFACT_BYTES) {
443
466
  addFinding(findings, "blocked", "size_limit_exceeded", "The file exceeds Forge's artifact size limit.");
444
467
  }
445
- if (input.declaredMimeType?.trim() && input.declaredMimeType !== detectedMimeType) {
468
+ if (input.declaredMimeType?.trim() &&
469
+ input.declaredMimeType !== detectedMimeType) {
446
470
  addFinding(findings, "low", "mime_mismatch", "The declared MIME type differs from static file detection.");
447
471
  }
448
472
  let extractedTextSample = "";
449
- if (formatFamily === "document" || formatFamily === "presentation" || formatFamily === "spreadsheet") {
473
+ if (formatFamily === "document" ||
474
+ formatFamily === "presentation" ||
475
+ formatFamily === "spreadsheet") {
450
476
  if (["docx", "pptx", "xlsx", "xlsm"].includes(detectedExtension)) {
451
477
  extractedTextSample = scanOfficeZip(input.buffer, detectedExtension, findings);
452
478
  }
@@ -467,7 +493,11 @@ export function scanArtifactBytes(input) {
467
493
  addFinding(findings, "info", "static_scan_clean", "Static inspection found no configured danger signal.");
468
494
  }
469
495
  const danger = computeDanger(findings);
470
- const artifactState = danger.level === "blocked" ? "blocked" : danger.level === "high" ? "quarantined" : "active";
496
+ const artifactState = danger.level === "blocked"
497
+ ? "blocked"
498
+ : danger.level === "high"
499
+ ? "quarantined"
500
+ : "active";
471
501
  return {
472
502
  detectedExtension,
473
503
  detectedMimeType,
@@ -532,31 +562,66 @@ function mapArtifact(row, links = []) {
532
562
  updatedAt: row.updated_at
533
563
  };
534
564
  }
535
- function getArtifactRow(id) {
536
- return getDatabase()
537
- .prepare(`SELECT id, title, short_description, description, original_file_name,
565
+ const ARTIFACT_SELECT_COLUMNS = `id, title, short_description, description, original_file_name,
538
566
  storage_key, storage_path, content_sha256, byte_size,
539
567
  detected_extension, declared_mime_type, detected_mime_type,
540
568
  format_family, source_kind, source_label, uploaded_by_user_id,
541
569
  uploaded_by_agent_id, acting_for_user_id, artifact_state,
542
570
  danger_score, danger_level, download_policy, scan_results_json,
543
- enrichment_results_json, metadata_json, created_at, updated_at
571
+ enrichment_results_json, metadata_json, created_at, updated_at`;
572
+ function getArtifactRow(id) {
573
+ return getDatabase()
574
+ .prepare(`SELECT ${ARTIFACT_SELECT_COLUMNS}
544
575
  FROM artifacts
545
576
  WHERE id = ?`)
546
577
  .get(id);
547
578
  }
548
- function listArtifactRows() {
549
- return getDatabase()
550
- .prepare(`SELECT id, title, short_description, description, original_file_name,
551
- storage_key, storage_path, content_sha256, byte_size,
552
- detected_extension, declared_mime_type, detected_mime_type,
553
- format_family, source_kind, source_label, uploaded_by_user_id,
554
- uploaded_by_agent_id, acting_for_user_id, artifact_state,
555
- danger_score, danger_level, download_policy, scan_results_json,
556
- enrichment_results_json, metadata_json, created_at, updated_at
557
- FROM artifacts
558
- ORDER BY updated_at DESC`)
559
- .all();
579
+ function buildArtifactListWhere(parsed) {
580
+ const clauses = [
581
+ `NOT EXISTS (
582
+ SELECT 1
583
+ FROM deleted_entities
584
+ WHERE deleted_entities.entity_type = 'artifact'
585
+ AND deleted_entities.entity_id = artifacts.id
586
+ )`
587
+ ];
588
+ const params = [];
589
+ if (parsed.artifactState) {
590
+ clauses.push("artifacts.artifact_state = ?");
591
+ params.push(parsed.artifactState);
592
+ }
593
+ if (parsed.dangerLevel) {
594
+ clauses.push("artifacts.danger_level = ?");
595
+ params.push(parsed.dangerLevel);
596
+ }
597
+ if (parsed.formatFamily) {
598
+ clauses.push("artifacts.format_family = ?");
599
+ params.push(parsed.formatFamily);
600
+ }
601
+ if (parsed.query) {
602
+ const needle = `%${parsed.query.toLowerCase()}%`;
603
+ clauses.push(`(
604
+ LOWER(COALESCE(artifacts.title, '')) LIKE ?
605
+ OR LOWER(COALESCE(artifacts.short_description, '')) LIKE ?
606
+ OR LOWER(COALESCE(artifacts.description, '')) LIKE ?
607
+ OR LOWER(COALESCE(artifacts.original_file_name, '')) LIKE ?
608
+ OR LOWER(COALESCE(artifacts.source_label, '')) LIKE ?
609
+ OR LOWER(COALESCE(artifacts.metadata_json, '')) LIKE ?
610
+ )`);
611
+ params.push(needle, needle, needle, needle, needle, needle);
612
+ }
613
+ if (parsed.linkedEntityType && parsed.linkedEntityId) {
614
+ clauses.push(`EXISTS (
615
+ SELECT 1
616
+ FROM entity_links artifact_link_filter
617
+ WHERE artifact_link_filter.source_entity_type = 'artifact'
618
+ AND artifact_link_filter.source_entity_id = artifacts.id
619
+ AND artifact_link_filter.target_entity_type = ?
620
+ AND artifact_link_filter.target_entity_id = ?
621
+ )`);
622
+ params.push(parsed.linkedEntityType, parsed.linkedEntityId);
623
+ }
624
+ return { sql: clauses.join(" AND "), params };
560
625
  }
561
626
  function toEventMetadata(metadata) {
562
627
  const normalized = {};
@@ -612,7 +677,10 @@ function insertArtifactVersion(input) {
612
677
  }
613
678
  function deriveFallbackTitle(originalFileName) {
614
679
  const sanitized = sanitizeFileName(originalFileName);
615
- return sanitized.replace(/\.[^.]+$/, "").replace(/[_-]+/g, " ").trim() || "Artifact";
680
+ return (sanitized
681
+ .replace(/\.[^.]+$/, "")
682
+ .replace(/[_-]+/g, " ")
683
+ .trim() || "Artifact");
616
684
  }
617
685
  export async function createArtifactFromUpload(input, context, services = {}) {
618
686
  const parsed = artifactUploadSchema.parse(input);
@@ -628,7 +696,8 @@ export async function createArtifactFromUpload(input, context, services = {}) {
628
696
  const blob = await ensureBlobStored(buffer, scan.detectedMimeType);
629
697
  const id = artifactId();
630
698
  const createdAt = nowIso();
631
- const sourceKind = parsed.sourceKind ?? (context.source === "agent" ? "agent_upload" : "upload");
699
+ const sourceKind = parsed.sourceKind ??
700
+ (context.source === "agent" ? "agent_upload" : "upload");
632
701
  const uploadedByAgentId = parsed.uploadedByAgentId ?? context.token?.agentId ?? null;
633
702
  const metadata = {
634
703
  ...parsed.metadata,
@@ -690,38 +759,37 @@ export async function createArtifactFromUpload(input, context, services = {}) {
690
759
  export function createArtifactMetadata() {
691
760
  throw new Error("Use POST /api/v1/artifacts for artifact creation. Batch CRUD may search, link, update metadata, delete, and restore artifact records, but it must not create file artifacts.");
692
761
  }
693
- export function listArtifacts(input = {}) {
762
+ export function listArtifactsPage(input = {}) {
694
763
  const parsed = artifactListQuerySchema.parse(input);
695
- const rows = filterDeletedEntities("artifact", listArtifactRows());
764
+ const where = buildArtifactListWhere(parsed);
765
+ const totalRow = getDatabase()
766
+ .prepare(`SELECT COUNT(*) AS total FROM artifacts WHERE ${where.sql}`)
767
+ .get(...where.params);
768
+ const rows = getDatabase()
769
+ .prepare(`SELECT ${ARTIFACT_SELECT_COLUMNS}
770
+ FROM artifacts
771
+ WHERE ${where.sql}
772
+ ORDER BY updated_at DESC, id ASC
773
+ LIMIT ? OFFSET ?`)
774
+ .all(...where.params, parsed.limit, parsed.offset);
696
775
  const linksByArtifactId = new Map();
697
776
  for (const linkRow of listEntityLinksForSources("artifact", rows.map((row) => row.id))) {
698
777
  const current = linksByArtifactId.get(linkRow.sourceEntityId) ?? [];
699
778
  current.push(mapLink(linkRow));
700
779
  linksByArtifactId.set(linkRow.sourceEntityId, current);
701
780
  }
702
- const query = parsed.query?.toLowerCase() ?? "";
703
- return rows
704
- .map((row) => mapArtifact(row, linksByArtifactId.get(row.id) ?? []))
705
- .filter((artifact) => parsed.artifactState ? artifact.artifactState === parsed.artifactState : true)
706
- .filter((artifact) => parsed.dangerLevel ? artifact.dangerLevel === parsed.dangerLevel : true)
707
- .filter((artifact) => parsed.formatFamily ? artifact.formatFamily === parsed.formatFamily : true)
708
- .filter((artifact) => query
709
- ? JSON.stringify({
710
- title: artifact.title,
711
- shortDescription: artifact.shortDescription,
712
- description: artifact.description,
713
- originalFileName: artifact.originalFileName,
714
- sourceLabel: artifact.sourceLabel,
715
- metadata: artifact.metadata
716
- })
717
- .toLowerCase()
718
- .includes(query)
719
- : true)
720
- .filter((artifact) => parsed.linkedEntityType && parsed.linkedEntityId
721
- ? artifact.links.some((link) => link.targetEntityType === parsed.linkedEntityType &&
722
- link.targetEntityId === parsed.linkedEntityId)
723
- : true)
724
- .slice(0, parsed.limit);
781
+ const artifacts = rows.map((row) => mapArtifact(row, linksByArtifactId.get(row.id) ?? []));
782
+ const total = totalRow?.total ?? 0;
783
+ return {
784
+ artifacts,
785
+ total,
786
+ limit: parsed.limit,
787
+ offset: parsed.offset,
788
+ hasMore: parsed.offset + artifacts.length < total
789
+ };
790
+ }
791
+ export function listArtifacts(input = {}) {
792
+ return listArtifactsPage(input).artifacts;
725
793
  }
726
794
  export function getArtifactById(id) {
727
795
  if (isEntityDeleted("artifact", id)) {
@@ -743,12 +811,13 @@ export function updateArtifactMetadata(id, input, context) {
743
811
  const nextMetadata = parsed.metadata
744
812
  ? { ...existing.metadata, ...parsed.metadata }
745
813
  : existing.metadata;
746
- const nextLinks = parsed.links ?? existing.links.map((link) => ({
747
- entityType: link.targetEntityType,
748
- entityId: link.targetEntityId,
749
- anchorKey: link.anchorKey ?? "",
750
- relationship: link.relationship
751
- }));
814
+ const nextLinks = parsed.links ??
815
+ existing.links.map((link) => ({
816
+ entityType: link.targetEntityType,
817
+ entityId: link.targetEntityId,
818
+ anchorKey: link.anchorKey ?? "",
819
+ relationship: link.relationship
820
+ }));
752
821
  runInTransaction(() => {
753
822
  getDatabase()
754
823
  .prepare(`UPDATE artifacts
@@ -799,7 +868,8 @@ export async function readArtifactDownload(id) {
799
868
  if (!artifact) {
800
869
  return null;
801
870
  }
802
- if (artifact.downloadPolicy !== "human_only" || artifact.artifactState === "blocked") {
871
+ if (artifact.downloadPolicy !== "human_only" ||
872
+ artifact.artifactState === "blocked") {
803
873
  throw new Error("This artifact is not downloadable in its current state.");
804
874
  }
805
875
  const storagePath = resolveStoragePath(artifact.storageKey);
@@ -911,6 +911,9 @@ export async function listArtifacts(options = {}) {
911
911
  if (options.limit) {
912
912
  search.set("limit", String(options.limit));
913
913
  }
914
+ if (typeof options.offset === "number") {
915
+ search.set("offset", String(options.offset));
916
+ }
914
917
  const suffix = search.size > 0 ? `?${search.toString()}` : "";
915
918
  return request(`/api/v1/artifacts${suffix}`);
916
919
  }
@@ -2,7 +2,7 @@
2
2
  "id": "forge-openclaw-plugin",
3
3
  "name": "Forge",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
- "version": "0.3.17",
5
+ "version": "0.3.19",
6
6
  "activation": {
7
7
  "onStartup": true,
8
8
  "onCapabilities": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-openclaw-plugin",
3
- "version": "0.3.17",
3
+ "version": "0.3.19",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",