@mean-weasel/lineage 0.1.22 → 0.1.24

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 (221) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/MANUAL_INSTALL_DOGFOOD.md +1 -0
  3. package/README.md +45 -5
  4. package/dist/cli/lineage-dev.js +612 -37
  5. package/dist/cli/lineage-dev.js.map +4 -4
  6. package/dist/cli/lineage-preview.js +612 -37
  7. package/dist/cli/lineage-preview.js.map +4 -4
  8. package/dist/cli/lineage.js +612 -37
  9. package/dist/cli/lineage.js.map +4 -4
  10. package/dist/docs-site/404.html +41 -0
  11. package/dist/docs-site/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.BcSo_yiZ.js +1 -0
  12. package/dist/docs-site/_astro/Search.astro_astro_type_script_index_0_lang.x2pVooPA.js +1 -0
  13. package/dist/docs-site/_astro/TableOfContents.astro_astro_type_script_index_0_lang.Csloo1VZ.js +1 -0
  14. package/dist/docs-site/_astro/common.DarLW4Vf.css +3 -0
  15. package/dist/docs-site/_astro/ec.0vx5m.js +3 -0
  16. package/dist/docs-site/_astro/ec.w36nc.css +1 -0
  17. package/dist/docs-site/_astro/page.LAbJoB63.js +1 -0
  18. package/dist/docs-site/_astro/print.ehPL0gv-.css +1 -0
  19. package/dist/docs-site/_astro/starlight-toc.CTCQXEge.js +1 -0
  20. package/dist/docs-site/_astro/ui-core.DWIqd25E.js +2 -0
  21. package/dist/docs-site/concepts/agent-claims-handoffs/index.html +99 -0
  22. package/dist/docs-site/concepts/attempts-current-version/index.html +86 -0
  23. package/dist/docs-site/concepts/branches-vs-rerolls/index.html +114 -0
  24. package/dist/docs-site/concepts/projects-workspaces-assets/index.html +89 -0
  25. package/dist/docs-site/concepts/selections-next-variations/index.html +86 -0
  26. package/dist/docs-site/index.html +92 -0
  27. package/dist/docs-site/integrations/cloud-storage/index.html +92 -0
  28. package/dist/docs-site/integrations/image-generation/index.html +93 -0
  29. package/dist/docs-site/integrations/index.html +112 -0
  30. package/dist/docs-site/integrations/social-scheduling/index.html +89 -0
  31. package/dist/docs-site/operations/backup-recovery/index.html +87 -0
  32. package/dist/docs-site/operations/channels/index.html +97 -0
  33. package/dist/docs-site/operations/local-first-data/index.html +90 -0
  34. package/dist/docs-site/operations/profiles-database-identity/index.html +104 -0
  35. package/dist/docs-site/operations/troubleshooting/index.html +89 -0
  36. package/dist/docs-site/pagefind/fragment/en_1126abb.pf_fragment +0 -0
  37. package/dist/docs-site/pagefind/fragment/en_19b3f6c.pf_fragment +0 -0
  38. package/dist/docs-site/pagefind/fragment/en_31aa611.pf_fragment +0 -0
  39. package/dist/docs-site/pagefind/fragment/en_38817cc.pf_fragment +0 -0
  40. package/dist/docs-site/pagefind/fragment/en_4184ad1.pf_fragment +0 -0
  41. package/dist/docs-site/pagefind/fragment/en_41db543.pf_fragment +0 -0
  42. package/dist/docs-site/pagefind/fragment/en_469f895.pf_fragment +0 -0
  43. package/dist/docs-site/pagefind/fragment/en_56e45b6.pf_fragment +0 -0
  44. package/dist/docs-site/pagefind/fragment/en_56fe7ca.pf_fragment +0 -0
  45. package/dist/docs-site/pagefind/fragment/en_5be5e44.pf_fragment +0 -0
  46. package/dist/docs-site/pagefind/fragment/en_603c2be.pf_fragment +0 -0
  47. package/dist/docs-site/pagefind/fragment/en_66b3118.pf_fragment +0 -0
  48. package/dist/docs-site/pagefind/fragment/en_6a19c31.pf_fragment +0 -0
  49. package/dist/docs-site/pagefind/fragment/en_74e9307.pf_fragment +0 -0
  50. package/dist/docs-site/pagefind/fragment/en_761fab1.pf_fragment +0 -0
  51. package/dist/docs-site/pagefind/fragment/en_7c9d5a2.pf_fragment +0 -0
  52. package/dist/docs-site/pagefind/fragment/en_818744b.pf_fragment +0 -0
  53. package/dist/docs-site/pagefind/fragment/en_8269752.pf_fragment +0 -0
  54. package/dist/docs-site/pagefind/fragment/en_88b38c1.pf_fragment +0 -0
  55. package/dist/docs-site/pagefind/fragment/en_98d9b16.pf_fragment +0 -0
  56. package/dist/docs-site/pagefind/fragment/en_a3d636e.pf_fragment +0 -0
  57. package/dist/docs-site/pagefind/fragment/en_b15ecf0.pf_fragment +0 -0
  58. package/dist/docs-site/pagefind/fragment/en_bd3e194.pf_fragment +0 -0
  59. package/dist/docs-site/pagefind/fragment/en_bfb13e9.pf_fragment +0 -0
  60. package/dist/docs-site/pagefind/fragment/en_d0fca9e.pf_fragment +0 -0
  61. package/dist/docs-site/pagefind/fragment/en_d49ed00.pf_fragment +0 -0
  62. package/dist/docs-site/pagefind/fragment/en_e0786b9.pf_fragment +0 -0
  63. package/dist/docs-site/pagefind/fragment/en_e298dee.pf_fragment +0 -0
  64. package/dist/docs-site/pagefind/fragment/en_ee82be6.pf_fragment +0 -0
  65. package/dist/docs-site/pagefind/fragment/en_f4db9e2.pf_fragment +0 -0
  66. package/dist/docs-site/pagefind/fragment/en_f6179a8.pf_fragment +0 -0
  67. package/dist/docs-site/pagefind/index/en_7b1363c.pf_index +0 -0
  68. package/dist/docs-site/pagefind/pagefind-component-ui.css +1509 -0
  69. package/dist/docs-site/pagefind/pagefind-component-ui.js +56 -0
  70. package/dist/docs-site/pagefind/pagefind-entry.json +1 -0
  71. package/dist/docs-site/pagefind/pagefind-highlight.js +1070 -0
  72. package/dist/docs-site/pagefind/pagefind-modular-ui.css +214 -0
  73. package/dist/docs-site/pagefind/pagefind-modular-ui.js +8 -0
  74. package/dist/docs-site/pagefind/pagefind-ui.css +1 -0
  75. package/dist/docs-site/pagefind/pagefind-ui.js +2 -0
  76. package/dist/docs-site/pagefind/pagefind-worker.js +6 -0
  77. package/dist/docs-site/pagefind/pagefind.en_4e77743529.pf_meta +0 -0
  78. package/dist/docs-site/pagefind/pagefind.js +6 -0
  79. package/dist/docs-site/pagefind/wasm.en.pagefind +0 -0
  80. package/dist/docs-site/pagefind/wasm.unknown.pagefind +0 -0
  81. package/dist/docs-site/reference/cli/index.html +95 -0
  82. package/dist/docs-site/reference/interface-guide/index.html +86 -0
  83. package/dist/docs-site/reference/release-notes/index.html +80 -0
  84. package/dist/docs-site/reference/settings/index.html +86 -0
  85. package/dist/docs-site/reference/terminology/index.html +94 -0
  86. package/dist/docs-site/sitemap-0.xml +1 -0
  87. package/dist/docs-site/sitemap-index.xml +1 -0
  88. package/dist/docs-site/start-here/example-projects/index.html +88 -0
  89. package/dist/docs-site/start-here/first-workspace/index.html +91 -0
  90. package/dist/docs-site/start-here/installation-first-run/index.html +92 -0
  91. package/dist/docs-site/start-here/what-is-lineage/index.html +96 -0
  92. package/dist/docs-site/workflows/back-up-approved-assets/index.html +88 -0
  93. package/dist/docs-site/workflows/content-batches/index.html +88 -0
  94. package/dist/docs-site/workflows/continue-new-agent-session/index.html +89 -0
  95. package/dist/docs-site/workflows/create-grow-lineage/index.html +89 -0
  96. package/dist/docs-site/workflows/generate-import-variations/index.html +92 -0
  97. package/dist/docs-site/workflows/restore-earlier-attempt/index.html +87 -0
  98. package/dist/docs-site/workflows/review-approve-assets/index.html +87 -0
  99. package/dist/pages/.nojekyll +0 -0
  100. package/dist/pages/assets/agent-shared-state-DOfpTLiw.webp +0 -0
  101. package/dist/pages/assets/agent-to-canvas-DtIu_cPq.mp4 +0 -0
  102. package/dist/{web/assets/app-B-fAyNsU.css → pages/assets/app-CuBsKrS-.css} +1 -1
  103. package/dist/pages/assets/app-TEMX-pOn.js +50 -0
  104. package/dist/pages/assets/attempt-history-D6wdic6n.webp +0 -0
  105. package/dist/pages/assets/branching-tree-B8I5_S6D.png +0 -0
  106. package/dist/pages/assets/canvas-cli-DHBacq7r.png +0 -0
  107. package/dist/pages/assets/hero-agent-sync-D8ibW83E.mp4 +0 -0
  108. package/dist/pages/assets/hero-agent-sync-poster-zBB3KpbO.png +0 -0
  109. package/dist/pages/assets/hero-board-DG3ED4AW.webp +0 -0
  110. package/dist/pages/assets/hero-lineage-growth-Bsl9tiq-.mp4 +0 -0
  111. package/dist/pages/assets/hero-trace-connections-Bb52ABBc.mp4 +0 -0
  112. package/dist/pages/assets/human-selection-BdDBDE-I.webp +0 -0
  113. package/dist/pages/assets/human-to-agent-D1z92ZO9.mp4 +0 -0
  114. package/dist/pages/assets/jsx-runtime-DAFSxiwi.js +8 -0
  115. package/dist/pages/assets/landing-MwOFmHoi.js +2 -0
  116. package/dist/pages/assets/landing-wy4L-yBm.css +1 -0
  117. package/dist/pages/assets/reroll-history-DQcEH42R.mp4 +0 -0
  118. package/dist/pages/docs/404.html +41 -0
  119. package/dist/pages/docs/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.BcSo_yiZ.js +1 -0
  120. package/dist/pages/docs/_astro/Search.astro_astro_type_script_index_0_lang.x2pVooPA.js +1 -0
  121. package/dist/pages/docs/_astro/TableOfContents.astro_astro_type_script_index_0_lang.Csloo1VZ.js +1 -0
  122. package/dist/pages/docs/_astro/common.DarLW4Vf.css +3 -0
  123. package/dist/pages/docs/_astro/ec.0vx5m.js +3 -0
  124. package/dist/pages/docs/_astro/ec.w36nc.css +1 -0
  125. package/dist/pages/docs/_astro/page.LAbJoB63.js +1 -0
  126. package/dist/pages/docs/_astro/print.ehPL0gv-.css +1 -0
  127. package/dist/pages/docs/_astro/starlight-toc.CTCQXEge.js +1 -0
  128. package/dist/pages/docs/_astro/ui-core.DWIqd25E.js +2 -0
  129. package/dist/pages/docs/concepts/agent-claims-handoffs/index.html +99 -0
  130. package/dist/pages/docs/concepts/attempts-current-version/index.html +86 -0
  131. package/dist/pages/docs/concepts/branches-vs-rerolls/index.html +114 -0
  132. package/dist/pages/docs/concepts/projects-workspaces-assets/index.html +89 -0
  133. package/dist/pages/docs/concepts/selections-next-variations/index.html +86 -0
  134. package/dist/pages/docs/index.html +92 -0
  135. package/dist/pages/docs/integrations/cloud-storage/index.html +92 -0
  136. package/dist/pages/docs/integrations/image-generation/index.html +93 -0
  137. package/dist/pages/docs/integrations/index.html +112 -0
  138. package/dist/pages/docs/integrations/social-scheduling/index.html +89 -0
  139. package/dist/pages/docs/operations/backup-recovery/index.html +87 -0
  140. package/dist/pages/docs/operations/channels/index.html +97 -0
  141. package/dist/pages/docs/operations/local-first-data/index.html +90 -0
  142. package/dist/pages/docs/operations/profiles-database-identity/index.html +104 -0
  143. package/dist/pages/docs/operations/troubleshooting/index.html +89 -0
  144. package/dist/pages/docs/pagefind/fragment/en_1126abb.pf_fragment +0 -0
  145. package/dist/pages/docs/pagefind/fragment/en_19b3f6c.pf_fragment +0 -0
  146. package/dist/pages/docs/pagefind/fragment/en_31aa611.pf_fragment +0 -0
  147. package/dist/pages/docs/pagefind/fragment/en_38817cc.pf_fragment +0 -0
  148. package/dist/pages/docs/pagefind/fragment/en_4184ad1.pf_fragment +0 -0
  149. package/dist/pages/docs/pagefind/fragment/en_41db543.pf_fragment +0 -0
  150. package/dist/pages/docs/pagefind/fragment/en_469f895.pf_fragment +0 -0
  151. package/dist/pages/docs/pagefind/fragment/en_56e45b6.pf_fragment +0 -0
  152. package/dist/pages/docs/pagefind/fragment/en_56fe7ca.pf_fragment +0 -0
  153. package/dist/pages/docs/pagefind/fragment/en_5be5e44.pf_fragment +0 -0
  154. package/dist/pages/docs/pagefind/fragment/en_603c2be.pf_fragment +0 -0
  155. package/dist/pages/docs/pagefind/fragment/en_66b3118.pf_fragment +0 -0
  156. package/dist/pages/docs/pagefind/fragment/en_6a19c31.pf_fragment +0 -0
  157. package/dist/pages/docs/pagefind/fragment/en_74e9307.pf_fragment +0 -0
  158. package/dist/pages/docs/pagefind/fragment/en_761fab1.pf_fragment +0 -0
  159. package/dist/pages/docs/pagefind/fragment/en_7c9d5a2.pf_fragment +0 -0
  160. package/dist/pages/docs/pagefind/fragment/en_818744b.pf_fragment +0 -0
  161. package/dist/pages/docs/pagefind/fragment/en_8269752.pf_fragment +0 -0
  162. package/dist/pages/docs/pagefind/fragment/en_88b38c1.pf_fragment +0 -0
  163. package/dist/pages/docs/pagefind/fragment/en_98d9b16.pf_fragment +0 -0
  164. package/dist/pages/docs/pagefind/fragment/en_a3d636e.pf_fragment +0 -0
  165. package/dist/pages/docs/pagefind/fragment/en_b15ecf0.pf_fragment +0 -0
  166. package/dist/pages/docs/pagefind/fragment/en_bd3e194.pf_fragment +0 -0
  167. package/dist/pages/docs/pagefind/fragment/en_bfb13e9.pf_fragment +0 -0
  168. package/dist/pages/docs/pagefind/fragment/en_d0fca9e.pf_fragment +0 -0
  169. package/dist/pages/docs/pagefind/fragment/en_d49ed00.pf_fragment +0 -0
  170. package/dist/pages/docs/pagefind/fragment/en_e0786b9.pf_fragment +0 -0
  171. package/dist/pages/docs/pagefind/fragment/en_e298dee.pf_fragment +0 -0
  172. package/dist/pages/docs/pagefind/fragment/en_ee82be6.pf_fragment +0 -0
  173. package/dist/pages/docs/pagefind/fragment/en_f4db9e2.pf_fragment +0 -0
  174. package/dist/pages/docs/pagefind/fragment/en_f6179a8.pf_fragment +0 -0
  175. package/dist/pages/docs/pagefind/index/en_7b1363c.pf_index +0 -0
  176. package/dist/pages/docs/pagefind/pagefind-component-ui.css +1509 -0
  177. package/dist/pages/docs/pagefind/pagefind-component-ui.js +56 -0
  178. package/dist/pages/docs/pagefind/pagefind-entry.json +1 -0
  179. package/dist/pages/docs/pagefind/pagefind-highlight.js +1070 -0
  180. package/dist/pages/docs/pagefind/pagefind-modular-ui.css +214 -0
  181. package/dist/pages/docs/pagefind/pagefind-modular-ui.js +8 -0
  182. package/dist/pages/docs/pagefind/pagefind-ui.css +1 -0
  183. package/dist/pages/docs/pagefind/pagefind-ui.js +2 -0
  184. package/dist/pages/docs/pagefind/pagefind-worker.js +6 -0
  185. package/dist/pages/docs/pagefind/pagefind.en_4e77743529.pf_meta +0 -0
  186. package/dist/pages/docs/pagefind/pagefind.js +6 -0
  187. package/dist/pages/docs/pagefind/wasm.en.pagefind +0 -0
  188. package/dist/pages/docs/pagefind/wasm.unknown.pagefind +0 -0
  189. package/dist/pages/docs/reference/cli/index.html +95 -0
  190. package/dist/pages/docs/reference/interface-guide/index.html +86 -0
  191. package/dist/pages/docs/reference/release-notes/index.html +80 -0
  192. package/dist/pages/docs/reference/settings/index.html +86 -0
  193. package/dist/pages/docs/reference/terminology/index.html +94 -0
  194. package/dist/pages/docs/sitemap-0.xml +1 -0
  195. package/dist/pages/docs/sitemap-index.xml +1 -0
  196. package/dist/pages/docs/start-here/example-projects/index.html +88 -0
  197. package/dist/pages/docs/start-here/first-workspace/index.html +91 -0
  198. package/dist/pages/docs/start-here/installation-first-run/index.html +92 -0
  199. package/dist/pages/docs/start-here/what-is-lineage/index.html +96 -0
  200. package/dist/pages/docs/workflows/back-up-approved-assets/index.html +88 -0
  201. package/dist/pages/docs/workflows/content-batches/index.html +88 -0
  202. package/dist/pages/docs/workflows/continue-new-agent-session/index.html +89 -0
  203. package/dist/pages/docs/workflows/create-grow-lineage/index.html +89 -0
  204. package/dist/pages/docs/workflows/generate-import-variations/index.html +92 -0
  205. package/dist/pages/docs/workflows/restore-earlier-attempt/index.html +87 -0
  206. package/dist/pages/docs/workflows/review-approve-assets/index.html +87 -0
  207. package/dist/pages/index.html +42 -0
  208. package/dist/pages/landing/index.html +42 -0
  209. package/dist/pages/lineage-showcase-cover-16x9.png +0 -0
  210. package/dist/runtime-build.json +5 -5
  211. package/dist/server.js +431 -46
  212. package/dist/server.js.map +4 -4
  213. package/dist/web/assets/app-CuBsKrS-.css +1 -0
  214. package/dist/web/assets/app-TEMX-pOn.js +50 -0
  215. package/dist/web/assets/landing-MwOFmHoi.js +2 -0
  216. package/dist/web/index.html +3 -3
  217. package/dist/web/landing/index.html +26 -3
  218. package/dist/web/lineage-showcase-cover-16x9.png +0 -0
  219. package/package.json +11 -2
  220. package/dist/web/assets/app-D-7R33Mc.js +0 -16
  221. package/dist/web/assets/landing-DIjBBL33.js +0 -2
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/server.ts
2
2
  import express2 from "express";
3
3
  import multer from "multer";
4
- import { existsSync as existsSync14 } from "node:fs";
4
+ import { existsSync as existsSync15 } from "node:fs";
5
5
  import { join as join14 } from "node:path";
6
6
 
7
7
  // src/server/assetCore.ts
@@ -980,6 +980,21 @@ function lineageDb() {
980
980
  where status = 'pending';
981
981
  create index if not exists asset_reroll_requests_root_status
982
982
  on asset_reroll_requests(project_id, root_asset_id, status, created_at);
983
+ create table if not exists asset_social_marks (
984
+ id text primary key,
985
+ project_id text not null references projects(id),
986
+ root_asset_id text not null references assets(id),
987
+ asset_id text not null references assets(id),
988
+ notes text,
989
+ marked_by text not null,
990
+ marked_at text not null,
991
+ unmarked_by text,
992
+ unmarked_at text,
993
+ updated_at text not null,
994
+ unique(project_id, root_asset_id, asset_id)
995
+ );
996
+ create index if not exists asset_social_marks_root_active
997
+ on asset_social_marks(project_id, root_asset_id, unmarked_at, marked_at);
983
998
  create table if not exists asset_reviews (
984
999
  asset_id text primary key references assets(id),
985
1000
  review_state text not null check (review_state in ('unreviewed', 'approved', 'needs_revision', 'rejected', 'ignored')),
@@ -2177,7 +2192,7 @@ function lookupAssets(project, assetIds) {
2177
2192
  }
2178
2193
 
2179
2194
  // src/server/assetLineage.ts
2180
- import { join as join7 } from "node:path";
2195
+ import { isAbsolute as isAbsolute2, join as join7, resolve as resolve5 } from "node:path";
2181
2196
 
2182
2197
  // src/shared/edgeSummary.ts
2183
2198
  var edgeSummaryWordLimit = 2;
@@ -3493,6 +3508,11 @@ function collectAssets(project, source) {
3493
3508
  }
3494
3509
  return assets;
3495
3510
  }
3511
+ function absoluteLocalPath(localPath) {
3512
+ if (!localPath) return void 0;
3513
+ if (isAbsolute2(localPath)) return localPath;
3514
+ return resolve5(repoRoot, ".asset-scratch", localPath);
3515
+ }
3496
3516
  function upsertProject(database, project) {
3497
3517
  const timestamp = nowIso();
3498
3518
  database.prepare(`
@@ -3972,6 +3992,19 @@ function getLineageSnapshot(project, assetId) {
3972
3992
  const request = rerollRequestFrom(row);
3973
3993
  return [request.node_asset_id, withRerollTask(request, lineageTasksByNode.get(request.node_asset_id)?.reroll)];
3974
3994
  }));
3995
+ const hasSocialMarks = database.prepare("select 1 from sqlite_master where type = 'table' and name = 'asset_social_marks'").get() !== void 0;
3996
+ const socialMarkRows = ids.length > 0 && hasSocialMarks ? database.prepare(`select * from asset_social_marks where project_id = ? and root_asset_id = ? and unmarked_at is null and asset_id in (${placeholders2})`).all(project, root, ...ids) : [];
3997
+ const socialMarksByNode = new Map(socialMarkRows.map((row) => [String(row.asset_id), {
3998
+ active: true,
3999
+ asset_id: String(row.asset_id),
4000
+ id: String(row.id),
4001
+ marked_at: String(row.marked_at),
4002
+ marked_by: String(row.marked_by),
4003
+ notes: rowString(row.notes),
4004
+ project_id: String(row.project_id),
4005
+ root_asset_id: String(row.root_asset_id),
4006
+ updated_at: String(row.updated_at)
4007
+ }]));
3975
4008
  const childIds = new Set(edges.map((edge) => edge.parent_asset_id));
3976
4009
  const selectedIds = new Set(selected.map((row) => row.asset_id));
3977
4010
  const selections = selected.map((row) => ({
@@ -3991,6 +4024,7 @@ function getLineageSnapshot(project, assetId) {
3991
4024
  const lineageTasks = lineageTasksByNode.get(row.asset_id);
3992
4025
  return {
3993
4026
  ...node,
4027
+ absolute_path: absoluteLocalPath(row.local_path),
3994
4028
  attempt_count: attempts.length,
3995
4029
  current_attempt: currentAttempt,
3996
4030
  is_latest: !childIds.has(row.asset_id),
@@ -3999,6 +4033,7 @@ function getLineageSnapshot(project, assetId) {
3999
4033
  preview_url: canPreviewLocally(row.media_type, previewPath) ? localPreviewUrl(project, previewPath) : void 0,
4000
4034
  reroll_request: rerollsByNode.get(row.asset_id),
4001
4035
  selection_note: nodeSelection?.notes,
4036
+ social_mark: socialMarksByNode.get(row.asset_id),
4002
4037
  user_selected: selectedIds.has(row.asset_id)
4003
4038
  };
4004
4039
  });
@@ -4763,6 +4798,11 @@ function removeLineageNode(project, fields) {
4763
4798
  `);
4764
4799
  for (const edge of reparentedEdges) insertEdge.run(edge.id, project, edge.parent_asset_id, edge.child_asset_id, edge.created_at);
4765
4800
  database.prepare("delete from asset_layouts where project_id = ? and root_asset_id = ? and asset_id = ?").run(project, root, fields.assetId);
4801
+ database.prepare(`
4802
+ update asset_social_marks
4803
+ set unmarked_by = 'lineage:remove-node', unmarked_at = ?, updated_at = ?
4804
+ where project_id = ? and root_asset_id = ? and asset_id = ? and unmarked_at is null
4805
+ `).run(timestamp, timestamp, project, root, fields.assetId);
4766
4806
  compactSelectionsAfterRemove(database, project, root, fields.assetId, timestamp);
4767
4807
  database.exec("commit");
4768
4808
  } catch (error) {
@@ -4783,6 +4823,277 @@ function removeLineageNode(project, fields) {
4783
4823
  };
4784
4824
  }
4785
4825
 
4826
+ // src/server/assetSocialMarks.ts
4827
+ import { accessSync, constants, existsSync as existsSync8 } from "node:fs";
4828
+ import { isAbsolute as isAbsolute3, resolve as resolve6 } from "node:path";
4829
+ function markFromRow(row) {
4830
+ return {
4831
+ active: row.unmarked_at === null,
4832
+ asset_id: row.asset_id,
4833
+ id: row.id,
4834
+ marked_at: row.marked_at,
4835
+ marked_by: row.marked_by,
4836
+ notes: row.notes || void 0,
4837
+ project_id: row.project_id,
4838
+ root_asset_id: row.root_asset_id,
4839
+ unmarked_at: row.unmarked_at || void 0,
4840
+ unmarked_by: row.unmarked_by || void 0,
4841
+ updated_at: row.updated_at
4842
+ };
4843
+ }
4844
+ function requireCanonicalSnapshot(project, rootAssetId) {
4845
+ const snapshot = getLineageSnapshot(project, rootAssetId);
4846
+ if (snapshot.root_asset_id !== rootAssetId) {
4847
+ throw new LineageError(`Asset ${rootAssetId} is not a canonical lineage canvas root`, 400);
4848
+ }
4849
+ return snapshot;
4850
+ }
4851
+ function resolveVisibleNode(snapshot, asset) {
4852
+ const exactId = snapshot.nodes.find((node) => node.asset_id === asset);
4853
+ if (exactId) return exactId;
4854
+ const title = asset.trim().toLocaleLowerCase();
4855
+ const matches = snapshot.nodes.filter((node) => node.title.trim().toLocaleLowerCase() === title);
4856
+ if (matches.length > 1) throw new LineageError(`Asset title "${asset}" matches multiple visible nodes; use an exact asset ID.`, 409);
4857
+ if (matches.length === 1) return matches[0];
4858
+ throw new LineageError(`Asset ${asset} is not visible in lineage canvas ${snapshot.root_asset_id}`, 404);
4859
+ }
4860
+ function rootChannel(snapshot) {
4861
+ return snapshot.nodes.find((node) => node.asset_id === snapshot.root_asset_id)?.channel;
4862
+ }
4863
+ function requireActor(actor, field) {
4864
+ const normalized = actor.trim();
4865
+ if (!normalized) throw new LineageError(`Social mark ${field} is required`);
4866
+ return normalized;
4867
+ }
4868
+ function socialMarkId(project, rootAssetId, assetId) {
4869
+ return `${project}:${rootAssetId}:social:${assetId}`;
4870
+ }
4871
+ function activeRow(project, rootAssetId, assetId) {
4872
+ const database = lineageDb();
4873
+ try {
4874
+ return database.prepare(`
4875
+ select * from asset_social_marks
4876
+ where project_id = ? and root_asset_id = ? and asset_id = ? and unmarked_at is null
4877
+ `).get(project, rootAssetId, assetId);
4878
+ } finally {
4879
+ database.close();
4880
+ }
4881
+ }
4882
+ function mutationResponse(project, rootAssetId, active, mark, dryRun) {
4883
+ return {
4884
+ active,
4885
+ ...dryRun ? { dryRun } : {},
4886
+ ...mark ? { mark } : {},
4887
+ ok: true,
4888
+ snapshot: getLineageSnapshot(project, rootAssetId)
4889
+ };
4890
+ }
4891
+ function markAssetSocial(project, fields) {
4892
+ const snapshot = requireCanonicalSnapshot(project, fields.rootAssetId);
4893
+ const node = resolveVisibleNode(snapshot, fields.asset);
4894
+ const markedBy = requireActor(fields.markedBy, "markedBy");
4895
+ requireLineageWorkspaceClaimForWrite({
4896
+ channel: rootChannel(snapshot),
4897
+ claimToken: fields.claimToken,
4898
+ confirmWrite: fields.confirmWrite,
4899
+ project,
4900
+ rootAssetId: fields.rootAssetId,
4901
+ writeKind: "social_mark"
4902
+ });
4903
+ const existing = activeRow(project, fields.rootAssetId, node.asset_id);
4904
+ if (existing) return mutationResponse(project, fields.rootAssetId, true, markFromRow(existing), fields.confirmWrite ? void 0 : true);
4905
+ const timestamp = nowIso();
4906
+ const preview = {
4907
+ active: true,
4908
+ asset_id: node.asset_id,
4909
+ id: socialMarkId(project, fields.rootAssetId, node.asset_id),
4910
+ marked_at: timestamp,
4911
+ marked_by: markedBy,
4912
+ notes: fields.notes?.trim() || void 0,
4913
+ project_id: project,
4914
+ root_asset_id: fields.rootAssetId,
4915
+ updated_at: timestamp
4916
+ };
4917
+ if (!fields.confirmWrite) return mutationResponse(project, fields.rootAssetId, true, preview, true);
4918
+ const database = lineageDb();
4919
+ try {
4920
+ database.prepare(`
4921
+ insert into asset_social_marks (
4922
+ id, project_id, root_asset_id, asset_id, notes, marked_by, marked_at,
4923
+ unmarked_by, unmarked_at, updated_at
4924
+ ) values (?, ?, ?, ?, ?, ?, ?, null, null, ?)
4925
+ on conflict(project_id, root_asset_id, asset_id) do update set
4926
+ notes = excluded.notes,
4927
+ marked_by = excluded.marked_by,
4928
+ marked_at = excluded.marked_at,
4929
+ unmarked_by = null,
4930
+ unmarked_at = null,
4931
+ updated_at = excluded.updated_at
4932
+ `).run(
4933
+ preview.id,
4934
+ project,
4935
+ fields.rootAssetId,
4936
+ node.asset_id,
4937
+ preview.notes || null,
4938
+ markedBy,
4939
+ timestamp,
4940
+ timestamp
4941
+ );
4942
+ } finally {
4943
+ database.close();
4944
+ }
4945
+ return mutationResponse(project, fields.rootAssetId, true, markFromRow(activeRow(project, fields.rootAssetId, node.asset_id)));
4946
+ }
4947
+ function unmarkAssetSocial(project, fields) {
4948
+ const snapshot = requireCanonicalSnapshot(project, fields.rootAssetId);
4949
+ const node = resolveVisibleNode(snapshot, fields.asset);
4950
+ const unmarkedBy = requireActor(fields.unmarkedBy, "unmarkedBy");
4951
+ requireLineageWorkspaceClaimForWrite({
4952
+ channel: rootChannel(snapshot),
4953
+ claimToken: fields.claimToken,
4954
+ confirmWrite: fields.confirmWrite,
4955
+ project,
4956
+ rootAssetId: fields.rootAssetId,
4957
+ writeKind: "social_unmark"
4958
+ });
4959
+ const existing = activeRow(project, fields.rootAssetId, node.asset_id);
4960
+ if (!existing) return mutationResponse(project, fields.rootAssetId, false, void 0, fields.confirmWrite ? void 0 : true);
4961
+ const timestamp = nowIso();
4962
+ const preview = markFromRow({
4963
+ ...existing,
4964
+ unmarked_at: timestamp,
4965
+ unmarked_by: unmarkedBy,
4966
+ updated_at: timestamp
4967
+ });
4968
+ if (!fields.confirmWrite) return mutationResponse(project, fields.rootAssetId, false, preview, true);
4969
+ const database = lineageDb();
4970
+ try {
4971
+ database.prepare(`
4972
+ update asset_social_marks
4973
+ set unmarked_by = ?, unmarked_at = ?, updated_at = ?
4974
+ where project_id = ? and root_asset_id = ? and asset_id = ? and unmarked_at is null
4975
+ `).run(unmarkedBy, timestamp, timestamp, project, fields.rootAssetId, node.asset_id);
4976
+ } finally {
4977
+ database.close();
4978
+ }
4979
+ return mutationResponse(project, fields.rootAssetId, false, preview);
4980
+ }
4981
+ function absoluteLocalPath2(reference) {
4982
+ if (!reference) return void 0;
4983
+ if (isAbsolute3(reference)) return reference;
4984
+ const repoRelative = resolve6(repoRoot, reference);
4985
+ return existsSync8(repoRelative) || reference === ".asset-scratch" || reference.startsWith(".asset-scratch/") ? repoRelative : resolve6(repoRoot, ".asset-scratch", reference);
4986
+ }
4987
+ function isReadable(path) {
4988
+ try {
4989
+ accessSync(path, constants.R_OK);
4990
+ return true;
4991
+ } catch {
4992
+ return false;
4993
+ }
4994
+ }
4995
+ function listItem(project, rootAssetId, node, row) {
4996
+ const relativePath = node.current_attempt?.file_path || node.local_path;
4997
+ const absolutePath = absoluteLocalPath2(relativePath);
4998
+ const exists = absolutePath ? existsSync8(absolutePath) : false;
4999
+ const warnings = [];
5000
+ if (absolutePath && !exists) warnings.push(`Asset ${node.asset_id} local file is missing: ${absolutePath}`);
5001
+ if (absolutePath && exists && !isReadable(absolutePath)) {
5002
+ warnings.push(`Asset ${node.asset_id} local file is unreadable: ${absolutePath}. Check file permissions before handoff.`);
5003
+ }
5004
+ if (!absolutePath && node.s3_key) {
5005
+ warnings.push(`Asset ${node.asset_id} is only available in non-local storage; create a readable local copy before handoff.`);
5006
+ }
5007
+ if (!absolutePath && !node.s3_key) warnings.push(`Asset ${node.asset_id} has no local file or storage key.`);
5008
+ const base = `--project ${shellQuote(project)} --root ${shellQuote(rootAssetId)} --asset ${shellQuote(node.asset_id)}`;
5009
+ return {
5010
+ ...markFromRow(row),
5011
+ checksum_sha256: node.current_attempt?.checksum_sha256 || node.checksum_sha256,
5012
+ commands: {
5013
+ mark: lineageCliCommand(`social mark ${base} --confirm-write`),
5014
+ unmark: lineageCliCommand(`social unmark ${base} --confirm-write`)
5015
+ },
5016
+ current_attempt: node.current_attempt,
5017
+ local: {
5018
+ absolute_path: absolutePath,
5019
+ exists,
5020
+ relative_path: relativePath
5021
+ },
5022
+ media_type: node.media_type,
5023
+ s3: node.s3_key ? { key: node.s3_key } : void 0,
5024
+ source: node.source,
5025
+ title: node.title,
5026
+ warnings
5027
+ };
5028
+ }
5029
+ function listAssetSocialMarks(project, rootAssetId) {
5030
+ const snapshot = requireCanonicalSnapshot(project, rootAssetId);
5031
+ const database = lineageDb();
5032
+ let rows;
5033
+ try {
5034
+ const hasSocialMarks = database.prepare("select 1 from sqlite_master where type = 'table' and name = 'asset_social_marks'").get() !== void 0;
5035
+ rows = hasSocialMarks ? database.prepare(`
5036
+ select * from asset_social_marks
5037
+ where project_id = ? and root_asset_id = ? and unmarked_at is null
5038
+ order by marked_at, asset_id
5039
+ `).all(project, rootAssetId) : [];
5040
+ } finally {
5041
+ database.close();
5042
+ }
5043
+ const nodesById = new Map(snapshot.nodes.map((node) => [node.asset_id, node]));
5044
+ return {
5045
+ commands: {
5046
+ mark: lineageCliCommand(`social mark --project ${shellQuote(project)} --root ${shellQuote(rootAssetId)} --asset <asset-id> --confirm-write`)
5047
+ },
5048
+ fetchedAt: nowIso(),
5049
+ marks: rows.flatMap((row) => {
5050
+ const node = nodesById.get(row.asset_id);
5051
+ return node ? [listItem(project, rootAssetId, node, row)] : [];
5052
+ }),
5053
+ project,
5054
+ root_asset_id: rootAssetId,
5055
+ schema_version: "lineage.social_marks.v1",
5056
+ workspace: {
5057
+ id: lineageWorkspaceId(project, rootAssetId),
5058
+ root_asset_id: rootAssetId
5059
+ }
5060
+ };
5061
+ }
5062
+ function bodyString(req, key) {
5063
+ const value = req.body?.[key];
5064
+ return typeof value === "string" ? value : void 0;
5065
+ }
5066
+ function requestClaimToken(req) {
5067
+ return req.header("X-Lineage-Claim-Token") || bodyString(req, "claimToken");
5068
+ }
5069
+ function registerAssetSocialMarkRoutes(app2, projectFrom2, asyncRoute2) {
5070
+ app2.get("/api/lineage/:rootAssetId/social-marks", asyncRoute2((req, res) => {
5071
+ res.json(listAssetSocialMarks(
5072
+ projectFrom2({ query: req.query }),
5073
+ req.params.rootAssetId
5074
+ ));
5075
+ }));
5076
+ app2.post("/api/lineage/:rootAssetId/social-marks/:assetId", asyncRoute2((req, res) => {
5077
+ res.json(markAssetSocial(projectFrom2({ body: req.body, query: req.query }), {
5078
+ asset: req.params.assetId,
5079
+ claimToken: requestClaimToken(req),
5080
+ confirmWrite: req.body?.confirmWrite === true,
5081
+ markedBy: bodyString(req, "markedBy") || bodyString(req, "actor") || "human",
5082
+ notes: bodyString(req, "notes"),
5083
+ rootAssetId: req.params.rootAssetId
5084
+ }));
5085
+ }));
5086
+ app2.post("/api/lineage/:rootAssetId/social-marks/:assetId/unmark", asyncRoute2((req, res) => {
5087
+ res.json(unmarkAssetSocial(projectFrom2({ body: req.body, query: req.query }), {
5088
+ asset: req.params.assetId,
5089
+ claimToken: requestClaimToken(req),
5090
+ confirmWrite: req.body?.confirmWrite === true,
5091
+ rootAssetId: req.params.rootAssetId,
5092
+ unmarkedBy: bodyString(req, "unmarkedBy") || bodyString(req, "actor") || "human"
5093
+ }));
5094
+ }));
5095
+ }
5096
+
4786
5097
  // src/server/assetLedger.ts
4787
5098
  function allAssets(project, source) {
4788
5099
  const first = listAssets(project, { page: 1, pageSize: 100, source });
@@ -5929,6 +6240,49 @@ function registerAgentClaimRoutes(app2, projectFrom2, asyncRoute2) {
5929
6240
  }));
5930
6241
  }
5931
6242
 
6243
+ // src/shared/adapterCatalog.ts
6244
+ var adapterCatalogJson = `[
6245
+ {
6246
+ "adapterType": "cloud",
6247
+ "capabilityId": "cloud-storage",
6248
+ "capabilityLabel": "Cloud storage",
6249
+ "description": "Inspect and back up approved assets with an explicitly configured cloud storage provider.",
6250
+ "docsSlug": "integrations/cloud-storage",
6251
+ "liveBehavior": "available",
6252
+ "maturity": "Available",
6253
+ "providerId": "s3",
6254
+ "providerLabel": "Amazon S3"
6255
+ },
6256
+ {
6257
+ "adapterType": "scheduler",
6258
+ "capabilityId": "social-scheduling",
6259
+ "capabilityLabel": "Social scheduling",
6260
+ "description": "Prepare and validate reviewed social posts for an external scheduler without publishing them live.",
6261
+ "docsSlug": "integrations/social-scheduling",
6262
+ "liveBehavior": "disabled",
6263
+ "maturity": "Preview",
6264
+ "providerId": "buffer",
6265
+ "providerLabel": "Buffer"
6266
+ },
6267
+ {
6268
+ "adapterType": "image_generator",
6269
+ "capabilityId": "image-generation",
6270
+ "capabilityLabel": "Image generation",
6271
+ "description": "Create Codex generation handoffs and durable import receipts without embedding a model service.",
6272
+ "docsSlug": "integrations/image-generation",
6273
+ "liveBehavior": "handoff",
6274
+ "maturity": "Available",
6275
+ "providerId": "codex-handoff",
6276
+ "providerLabel": "Codex handoff"
6277
+ }
6278
+ ]`;
6279
+ var adapterCatalog = JSON.parse(adapterCatalogJson);
6280
+ function findAdapterCatalogEntry(adapterType, providerId) {
6281
+ const entry = adapterCatalog.find((item) => item.adapterType === adapterType && item.providerId === providerId);
6282
+ if (!entry) throw new Error(`Missing public adapter catalog entry: ${adapterType}/${providerId}`);
6283
+ return entry;
6284
+ }
6285
+
5932
6286
  // src/server/adapters/adapterSettings.ts
5933
6287
  var AdapterSettingsError = class extends Error {
5934
6288
  constructor(message, status = 400) {
@@ -5944,8 +6298,8 @@ var definitions = [
5944
6298
  {
5945
6299
  adapter_type: "cloud",
5946
6300
  default_enabled: false,
5947
- description: "Optional cloud storage inspection for projects that configure it explicitly.",
5948
- label: "Cloud storage",
6301
+ description: findAdapterCatalogEntry("cloud", "s3").description,
6302
+ label: findAdapterCatalogEntry("cloud", "s3").providerLabel,
5949
6303
  provider: "s3",
5950
6304
  safeConfig: (project) => {
5951
6305
  if (project === defaultProject) return { bucket: "", mode: "local-public-fallback", region: "" };
@@ -5957,8 +6311,8 @@ var definitions = [
5957
6311
  {
5958
6312
  adapter_type: "scheduler",
5959
6313
  default_enabled: false,
5960
- description: "Prepare reviewed social posts for external scheduling.",
5961
- label: "Buffer",
6314
+ description: findAdapterCatalogEntry("scheduler", "buffer").description,
6315
+ label: findAdapterCatalogEntry("scheduler", "buffer").providerLabel,
5962
6316
  provider: "buffer",
5963
6317
  safeConfig: () => ({ defaultMode: "dry-run" }),
5964
6318
  secret_ref: "env:LINEAGE_SCHEDULER_TOKEN"
@@ -5966,8 +6320,8 @@ var definitions = [
5966
6320
  {
5967
6321
  adapter_type: "image_generator",
5968
6322
  default_enabled: true,
5969
- description: "Create generation handoff packets and store proof receipts.",
5970
- label: "Codex handoff",
6323
+ description: findAdapterCatalogEntry("image_generator", "codex-handoff").description,
6324
+ label: findAdapterCatalogEntry("image_generator", "codex-handoff").providerLabel,
5971
6325
  provider: "codex-handoff",
5972
6326
  safeConfig: () => ({ clearSelectionAfterImport: true, defaultVariationCount: 3, receipts: "sqlite" }),
5973
6327
  secret_ref: null
@@ -6818,7 +7172,7 @@ function registerAdapterRoutes(app2, projectFrom2, asyncRoute2) {
6818
7172
  import { Router } from "express";
6819
7173
 
6820
7174
  // src/server/contentBatchImport.ts
6821
- import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync5 } from "node:fs";
7175
+ import { existsSync as existsSync9, readdirSync as readdirSync3, readFileSync as readFileSync5 } from "node:fs";
6822
7176
  import { basename as basename3, join as join10, relative as relative3 } from "node:path";
6823
7177
  function walk(dir) {
6824
7178
  return readdirSync3(dir, { withFileTypes: true }).flatMap((entry) => {
@@ -6873,7 +7227,7 @@ function itemFromFile(file) {
6873
7227
  }
6874
7228
  function demoMarkdownItems(kind) {
6875
7229
  const root = process.env.LINEAGE_CONTENT_SOURCE_ROOT || join10(repoRoot, "demo-project", "channels");
6876
- if (!existsSync8(root)) return [];
7230
+ if (!existsSync9(root)) return [];
6877
7231
  return walk(root).map(itemFromFile).filter((item) => Boolean(item)).filter((item) => kind === "all" || `${item.kind}s` === kind).sort((a, b) => a.sourcePath.localeCompare(b.sourcePath));
6878
7232
  }
6879
7233
  function importDemoContentBatch(project, options) {
@@ -7212,8 +7566,8 @@ function contentBatchRouter(projectFrom2) {
7212
7566
  }
7213
7567
 
7214
7568
  // src/server/generationReceipts.ts
7215
- import { existsSync as existsSync9, realpathSync as realpathSync2, statSync as statSync4 } from "node:fs";
7216
- import { relative as relative4, resolve as resolve5 } from "node:path";
7569
+ import { existsSync as existsSync10, realpathSync as realpathSync2, statSync as statSync4 } from "node:fs";
7570
+ import { relative as relative4, resolve as resolve7 } from "node:path";
7217
7571
  import { randomUUID as randomUUID3 } from "node:crypto";
7218
7572
 
7219
7573
  // src/shared/generationOutputManifest.ts
@@ -7751,8 +8105,8 @@ function isPathInside2(child, parent) {
7751
8105
  return Boolean(rel) && !rel.startsWith("..") && !rel.startsWith("/");
7752
8106
  }
7753
8107
  function scratchCandidate(file) {
7754
- const scratchRoot = resolve5(repoRoot, ".asset-scratch");
7755
- const candidate = file.startsWith(".asset-scratch/") || resolve5(file).startsWith(scratchRoot) ? resolve5(repoRoot, file) : resolve5(scratchRoot, file);
8108
+ const scratchRoot = resolve7(repoRoot, ".asset-scratch");
8109
+ const candidate = file.startsWith(".asset-scratch/") || resolve7(file).startsWith(scratchRoot) ? resolve7(repoRoot, file) : resolve7(scratchRoot, file);
7756
8110
  if (!isPathInside2(candidate, scratchRoot)) throw new GenerationReceiptError(`Import file must be under .asset-scratch: ${file}`);
7757
8111
  return { candidate, scratchRoot };
7758
8112
  }
@@ -7762,7 +8116,7 @@ function resolveScratchManifestPath(file) {
7762
8116
  }
7763
8117
  function resolveScratchFile(file) {
7764
8118
  const { candidate, scratchRoot } = scratchCandidate(file);
7765
- if (!existsSync9(candidate)) throw new GenerationReceiptError(`Missing import file: ${file}`, 404);
8119
+ if (!existsSync10(candidate)) throw new GenerationReceiptError(`Missing import file: ${file}`, 404);
7766
8120
  const realScratchRoot = realpathSync2(scratchRoot);
7767
8121
  const realCandidate = realpathSync2(candidate);
7768
8122
  if (!isPathInside2(realCandidate, realScratchRoot)) throw new GenerationReceiptError(`Import file must be under .asset-scratch: ${file}`);
@@ -8094,7 +8448,7 @@ function registerLineageTaskRoutes(app2, projectFrom2, asyncRoute2) {
8094
8448
 
8095
8449
  // src/server/assetLineageDemo.ts
8096
8450
  import { createHash as createHash5 } from "node:crypto";
8097
- import { copyFileSync as copyFileSync3, existsSync as existsSync10, mkdirSync as mkdirSync7, mkdtempSync, readFileSync as readFileSync6, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
8451
+ import { copyFileSync as copyFileSync3, existsSync as existsSync11, mkdirSync as mkdirSync7, mkdtempSync, readFileSync as readFileSync6, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
8098
8452
  import { tmpdir } from "node:os";
8099
8453
  import { dirname as dirname5, join as join11, posix } from "node:path";
8100
8454
  import { gunzipSync } from "node:zlib";
@@ -8166,9 +8520,9 @@ function swissifierRerollFixturePath(attempt) {
8166
8520
  }
8167
8521
  function swissifierSourcePath(manifest, asset, sourceDir) {
8168
8522
  const direct = join11(sourceDir, asset.file);
8169
- if (existsSync10(direct)) return direct;
8523
+ if (existsSync11(direct)) return direct;
8170
8524
  const nested = join11(sourceDir, manifest.media.target_dir, asset.file);
8171
- return existsSync10(nested) ? nested : null;
8525
+ return existsSync11(nested) ? nested : null;
8172
8526
  }
8173
8527
  function swissifierMediaState(manifest) {
8174
8528
  const missing = [];
@@ -8176,7 +8530,7 @@ function swissifierMediaState(manifest) {
8176
8530
  for (const asset of manifest.assets) {
8177
8531
  const relativePath = swissifierRelativePath(manifest, asset);
8178
8532
  const path = swissifierFilePath(manifest, asset);
8179
- if (!existsSync10(path)) {
8533
+ if (!existsSync11(path)) {
8180
8534
  missing.push(relativePath);
8181
8535
  continue;
8182
8536
  }
@@ -8268,7 +8622,7 @@ async function downloadBuffer(url, maxBytes) {
8268
8622
  return buffer;
8269
8623
  }
8270
8624
  function missingDemoMedia(project) {
8271
- return demoAssets.filter((asset) => !existsSync10(demoFilePath(project, asset))).map((asset) => demoRelativePath(project, asset));
8625
+ return demoAssets.filter((asset) => !existsSync11(demoFilePath(project, asset))).map((asset) => demoRelativePath(project, asset));
8272
8626
  }
8273
8627
  function demoSeedMediaStatus(project = defaultProject) {
8274
8628
  const missing = missingDemoMedia(project);
@@ -8463,7 +8817,7 @@ function writeDemoFiles(project) {
8463
8817
  }
8464
8818
  function swissifierRerollAsset(attempt) {
8465
8819
  const source = swissifierRerollFixturePath(attempt);
8466
- if (!existsSync10(source)) throw new Error(`Missing Swissifier re-roll fixture media: ${attempt.file}`);
8820
+ if (!existsSync11(source)) throw new Error(`Missing Swissifier re-roll fixture media: ${attempt.file}`);
8467
8821
  const body = readFileSync6(source);
8468
8822
  if (body.length !== attempt.size_bytes) throw new Error(`Unexpected Swissifier re-roll fixture size for ${attempt.file}`);
8469
8823
  const checksumSha256 = sha256Hex(body);
@@ -8886,8 +9240,8 @@ function registerLineageWorkspaceRoutes(app2, projectFrom2, asyncRoute2) {
8886
9240
  // src/server/runtimeInfo.ts
8887
9241
  import { createHash as createHash6 } from "node:crypto";
8888
9242
  import { spawnSync as spawnSync2 } from "node:child_process";
8889
- import { existsSync as existsSync11, lstatSync as lstatSync3, readFileSync as readFileSync7, readdirSync as readdirSync4, readlinkSync, realpathSync as realpathSync3, statSync as statSync5 } from "node:fs";
8890
- import { dirname as dirname6, isAbsolute as isAbsolute2, join as join12, resolve as resolve6 } from "node:path";
9243
+ import { existsSync as existsSync12, lstatSync as lstatSync3, readFileSync as readFileSync7, readdirSync as readdirSync4, readlinkSync, realpathSync as realpathSync3, statSync as statSync5 } from "node:fs";
9244
+ import { dirname as dirname6, isAbsolute as isAbsolute4, join as join12, resolve as resolve8 } from "node:path";
8891
9245
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8892
9246
 
8893
9247
  // src/shared/runtimeInfoTypes.ts
@@ -8906,7 +9260,7 @@ function isLineagePackageRoot(root) {
8906
9260
  }
8907
9261
  function executingCodeRoot() {
8908
9262
  const moduleDirectory = dirname6(fileURLToPath2(import.meta.url));
8909
- const candidates = [resolve6(moduleDirectory, "../.."), resolve6(moduleDirectory, "..")];
9263
+ const candidates = [resolve8(moduleDirectory, "../.."), resolve8(moduleDirectory, "..")];
8910
9264
  const root = candidates.find(isLineagePackageRoot);
8911
9265
  if (!root) throw new Error(`Unable to derive Lineage code root from executing module ${fileURLToPath2(import.meta.url)}`);
8912
9266
  return canonicalRoot(root);
@@ -8919,7 +9273,7 @@ function canonicalRoot(root) {
8919
9273
  try {
8920
9274
  return realpathSync3(root);
8921
9275
  } catch {
8922
- return resolve6(root);
9276
+ return resolve8(root);
8923
9277
  }
8924
9278
  }
8925
9279
  function packageInfo(root = codeRoot) {
@@ -9019,7 +9373,7 @@ function readInstallReceipt(path, errors) {
9019
9373
  return void 0;
9020
9374
  }
9021
9375
  let receipt;
9022
- const receiptPath = resolve6(path);
9376
+ const receiptPath = resolve8(path);
9023
9377
  try {
9024
9378
  receipt = JSON.parse(readFileSync7(receiptPath, "utf8"));
9025
9379
  } catch (error) {
@@ -9027,7 +9381,7 @@ function readInstallReceipt(path, errors) {
9027
9381
  return void 0;
9028
9382
  }
9029
9383
  if (receipt.schema_version !== lineageRuntimeInstallSchemaVersion) errors.push(`Unsupported runtime install receipt schema: ${String(receipt.schema_version)}`);
9030
- if (!isAbsolute2(receipt.package_root || "")) errors.push("Runtime install receipt package_root must be absolute");
9384
+ if (!isAbsolute4(receipt.package_root || "")) errors.push("Runtime install receipt package_root must be absolute");
9031
9385
  if (!receipt.package_integrity?.startsWith("sha512-")) errors.push("Runtime install receipt package integrity is invalid");
9032
9386
  if (receipt.package_source !== "registry" && receipt.package_source !== "local") errors.push("Runtime install receipt package source is invalid");
9033
9387
  if (typeof receipt.package_spec !== "string" || !receipt.package_spec) errors.push("Runtime install receipt package spec is invalid");
@@ -9108,8 +9462,8 @@ function packageCodeIdentity(root, channel, info, receiptPath) {
9108
9462
  function getLineageCodeIdentity(channel, options = {}) {
9109
9463
  const root = canonicalRoot(options.root || codeRoot);
9110
9464
  const info = packageInfo(root);
9111
- if (existsSync11(join12(root, ".git"))) return checkoutCodeIdentity(root, channel, info.version);
9112
- if (existsSync11(join12(root, "package.json"))) {
9465
+ if (existsSync12(join12(root, ".git"))) return checkoutCodeIdentity(root, channel, info.version);
9466
+ if (existsSync12(join12(root, "package.json"))) {
9113
9467
  return packageCodeIdentity(root, channel, info, options.receiptPath ?? process.env.LINEAGE_RUNTIME_RECEIPT);
9114
9468
  }
9115
9469
  const errors = [`Code root has neither checkout metadata nor package.json: ${root}`];
@@ -9148,7 +9502,7 @@ function getLineageRuntimeInfo(options = {}) {
9148
9502
  const dbPath = options.dbPath || lineageDbPath();
9149
9503
  const channel = normalizeRuntimeChannel(options.channel || process.env.LINEAGE_CHANNEL || process.env.LINEAGE_RELEASE_CHANNEL);
9150
9504
  const code = options.code || getLineageCodeIdentity(channel);
9151
- const databaseInfo = { exists: existsSync11(dbPath), path: dbPath };
9505
+ const databaseInfo = { exists: existsSync12(dbPath), path: dbPath };
9152
9506
  const schema = { migration_keys: [] };
9153
9507
  const serviceInstanceId = process.env.LINEAGE_SERVICE_INSTANCE_ID;
9154
9508
  const launcherPid = process.env.LINEAGE_LAUNCHER_PID ? Number(process.env.LINEAGE_LAUNCHER_PID) : void 0;
@@ -9288,14 +9642,14 @@ function registerManagedWriterRoute(app2, fields) {
9288
9642
  }
9289
9643
 
9290
9644
  // src/cli/lineageCli.ts
9291
- import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
9292
- import { dirname as dirname7, join as join13, resolve as resolve8 } from "node:path";
9645
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
9646
+ import { dirname as dirname7, join as join13, resolve as resolve10 } from "node:path";
9293
9647
  import { fileURLToPath as fileURLToPath3 } from "node:url";
9294
9648
 
9295
9649
  // src/server/lineageSelectionPacket.ts
9296
9650
  import { createHash as createHash7 } from "node:crypto";
9297
- import { existsSync as existsSync12, statSync as statSync6 } from "node:fs";
9298
- import { isAbsolute as isAbsolute3, resolve as resolve7 } from "node:path";
9651
+ import { existsSync as existsSync13, statSync as statSync6 } from "node:fs";
9652
+ import { isAbsolute as isAbsolute5, resolve as resolve9 } from "node:path";
9299
9653
  var LineageSelectionPacketError = class extends Error {
9300
9654
  constructor(message, warnings = [], errors = [], diagnostics = []) {
9301
9655
  super(message);
@@ -9341,13 +9695,13 @@ function resolveWorkspace(project, options) {
9341
9695
  }
9342
9696
  function resolveLocalReference(reference) {
9343
9697
  if (!reference) return void 0;
9344
- if (isAbsolute3(reference)) return reference;
9345
- const repoRelative = resolve7(repoRoot, reference);
9346
- if (existsSync12(repoRelative)) return repoRelative;
9347
- return resolve7(repoRoot, ".asset-scratch", reference);
9698
+ if (isAbsolute5(reference)) return reference;
9699
+ const repoRelative = resolve9(repoRoot, reference);
9700
+ if (existsSync13(repoRelative)) return repoRelative;
9701
+ return resolve9(repoRoot, ".asset-scratch", reference);
9348
9702
  }
9349
9703
  function fileSize(path) {
9350
- if (!path || !existsSync12(path)) return void 0;
9704
+ if (!path || !existsSync13(path)) return void 0;
9351
9705
  try {
9352
9706
  return statSync6(path).size;
9353
9707
  } catch {
@@ -9375,7 +9729,7 @@ function currentAttemptFor(node) {
9375
9729
  function assetForNode(node, catalogAsset, warnings) {
9376
9730
  const localReference = catalogAsset?.local?.absolute_path || node.current_attempt?.file_path || node.local_path || catalogAsset?.local?.relative_path;
9377
9731
  const absolutePath = catalogAsset?.local?.absolute_path || resolveLocalReference(localReference);
9378
- const localExists = absolutePath ? existsSync12(absolutePath) : false;
9732
+ const localExists = absolutePath ? existsSync13(absolutePath) : false;
9379
9733
  const hasLocalClaim = Boolean(absolutePath || node.local_path || catalogAsset?.local?.relative_path);
9380
9734
  const s3Key = catalogAsset?.s3?.key || node.s3_key;
9381
9735
  const hasS3 = Boolean(s3Key);
@@ -9532,7 +9886,7 @@ function assetForNodeV2(node, visibleCatalogAsset, catalogById, warnings, errors
9532
9886
  const mediaCatalogAsset = currentAttemptCatalogAsset || (isVisibleNodeAttempt ? visibleCatalogAsset : void 0);
9533
9887
  const localReference = currentAttempt.file_path || mediaCatalogAsset?.local?.absolute_path || mediaCatalogAsset?.local?.relative_path || (isVisibleNodeAttempt ? node.local_path : void 0);
9534
9888
  const absolutePath = resolveLocalReference(localReference);
9535
- const localExists = absolutePath ? existsSync12(absolutePath) : false;
9889
+ const localExists = absolutePath ? existsSync13(absolutePath) : false;
9536
9890
  const hasLocalClaim = Boolean(localReference);
9537
9891
  const s3Key = mediaCatalogAsset?.s3?.key || (isVisibleNodeAttempt ? node.s3_key : void 0);
9538
9892
  const hasS3 = Boolean(s3Key);
@@ -9797,7 +10151,7 @@ function getLineageSelectionPacket(project, options = {}) {
9797
10151
 
9798
10152
  // src/cli/lineageCli.ts
9799
10153
  function packageRoot2() {
9800
- return resolve8(dirname7(fileURLToPath3(import.meta.url)), "..", "..");
10154
+ return resolve10(dirname7(fileURLToPath3(import.meta.url)), "..", "..");
9801
10155
  }
9802
10156
  function packageVersion() {
9803
10157
  try {
@@ -9830,7 +10184,7 @@ function readOptions(args, name) {
9830
10184
  }
9831
10185
  function readJsonFile(path, label) {
9832
10186
  try {
9833
- return JSON.parse(readFileSync8(resolve8(path), "utf8"));
10187
+ return JSON.parse(readFileSync8(resolve10(path), "utf8"));
9834
10188
  } catch (error) {
9835
10189
  throw new Error(`${label} must be a readable JSON file: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
9836
10190
  }
@@ -9849,7 +10203,7 @@ function parentFilesOption(value) {
9849
10203
  return mappings;
9850
10204
  }
9851
10205
  function resolveCliAssetRoot(args) {
9852
- return resolve8(readOption(args, "--asset-root") || process.env.LINEAGE_ASSET_ROOT || packageRoot);
10206
+ return resolve10(readOption(args, "--asset-root") || process.env.LINEAGE_ASSET_ROOT || packageRoot);
9853
10207
  }
9854
10208
  function configureCliAssetRoot(args) {
9855
10209
  const assetRoot = resolveCliAssetRoot(args);
@@ -9914,7 +10268,7 @@ function runLineageDataCommand(command, args) {
9914
10268
  });
9915
10269
  const out = readOption(args, "--out");
9916
10270
  if (out) {
9917
- const outPath = resolve8(out);
10271
+ const outPath = resolve10(out);
9918
10272
  mkdirSync8(dirname7(outPath), { recursive: true });
9919
10273
  writeFileSync6(outPath, `${JSON.stringify(packet, null, 2)}
9920
10274
  `);
@@ -10025,6 +10379,35 @@ function runLineageDataCommand(command, args) {
10025
10379
  }
10026
10380
  throw new Error(`Unknown reroll command: ${subcommand}`);
10027
10381
  }
10382
+ if (command === "social") {
10383
+ const subcommand = positionalArgs(args)[0] || "";
10384
+ const explicitProject = readOption(args, "--project");
10385
+ const asset = readOption(args, "--asset");
10386
+ if (!explicitProject) throw new Error(`lineage social ${subcommand || "command"} requires --project`);
10387
+ if (!options.rootAssetId) throw new Error(`lineage social ${subcommand || "command"} requires --root`);
10388
+ if (subcommand === "list") return listAssetSocialMarks(explicitProject, options.rootAssetId);
10389
+ if (!asset) throw new Error(`lineage social ${subcommand || "command"} requires --asset`);
10390
+ if (subcommand === "mark") {
10391
+ return markAssetSocial(explicitProject, {
10392
+ asset,
10393
+ claimToken: options.claimToken,
10394
+ confirmWrite: options.confirmWrite,
10395
+ markedBy: readOption(args, "--actor") || "agent",
10396
+ notes: readOption(args, "--notes"),
10397
+ rootAssetId: options.rootAssetId
10398
+ });
10399
+ }
10400
+ if (subcommand === "unmark") {
10401
+ return unmarkAssetSocial(explicitProject, {
10402
+ asset,
10403
+ claimToken: options.claimToken,
10404
+ confirmWrite: options.confirmWrite,
10405
+ rootAssetId: options.rootAssetId,
10406
+ unmarkedBy: readOption(args, "--actor") || "agent"
10407
+ });
10408
+ }
10409
+ throw new Error(`Unknown social command: ${subcommand}`);
10410
+ }
10028
10411
  if (command === "tasks") {
10029
10412
  const subcommand = positionalArgs(args)[0] || "";
10030
10413
  const taskId = readOption(args, "--task");
@@ -10097,6 +10480,7 @@ function lineageCliCanDelegateMutation(command, args) {
10097
10480
  if (command === "link-child") return true;
10098
10481
  if (command === "generate") return positions[0] === "image" && ["plan", "import"].includes(positions[1] || "");
10099
10482
  if (command === "reroll") return ["mark", "cancel", "plan", "import"].includes(subcommand);
10483
+ if (command === "social") return ["mark", "unmark"].includes(subcommand);
10100
10484
  if (command === "tasks") return ["claim", "start", "comment", "cancel", "override", "instructions"].includes(subcommand);
10101
10485
  if (command === "agent") return ["claim", "heartbeat", "release", "revoke", "transfer"].includes(subcommand);
10102
10486
  return false;
@@ -10330,6 +10714,7 @@ app.get(
10330
10714
  );
10331
10715
  registerLineageWorkspaceRoutes(app, projectFrom, asyncRoute);
10332
10716
  registerLineageTaskRoutes(app, projectFrom, asyncRoute);
10717
+ registerAssetSocialMarkRoutes(app, projectFrom, asyncRoute);
10333
10718
  app.get("/api/lineage/:rootAssetId/rerolls", asyncRoute((req, res) => {
10334
10719
  res.json(listLineageRerollRequests(projectFrom(req), req.params.rootAssetId));
10335
10720
  }));
@@ -10581,7 +10966,7 @@ app.post(
10581
10966
  );
10582
10967
  if (isProduction) {
10583
10968
  const dist = join14(packageRoot, "dist", "web");
10584
- if (existsSync14(dist)) {
10969
+ if (existsSync15(dist)) {
10585
10970
  app.use(express2.static(dist));
10586
10971
  app.get("*", (_req, res) => res.sendFile(join14(dist, "index.html")));
10587
10972
  }