@mean-weasel/lineage 0.1.23 → 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 (53) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +37 -0
  3. package/dist/cli/lineage-dev.js +605 -36
  4. package/dist/cli/lineage-dev.js.map +4 -4
  5. package/dist/cli/lineage-preview.js +605 -36
  6. package/dist/cli/lineage-preview.js.map +4 -4
  7. package/dist/cli/lineage.js +605 -36
  8. package/dist/cli/lineage.js.map +4 -4
  9. package/dist/docs-site/operations/channels/index.html +11 -2
  10. package/dist/docs-site/operations/profiles-database-identity/index.html +16 -2
  11. package/dist/docs-site/pagefind/fragment/en_761fab1.pf_fragment +0 -0
  12. package/dist/docs-site/pagefind/fragment/en_bd3e194.pf_fragment +0 -0
  13. package/dist/docs-site/pagefind/fragment/en_ee82be6.pf_fragment +0 -0
  14. package/dist/docs-site/pagefind/fragment/en_f4db9e2.pf_fragment +0 -0
  15. package/dist/docs-site/pagefind/index/en_7b1363c.pf_index +0 -0
  16. package/dist/docs-site/pagefind/pagefind-entry.json +1 -1
  17. package/dist/docs-site/pagefind/pagefind.en_4e77743529.pf_meta +0 -0
  18. package/dist/docs-site/reference/cli/index.html +11 -2
  19. package/dist/docs-site/start-here/installation-first-run/index.html +7 -1
  20. package/dist/pages/assets/{app-B-fAyNsU.css → app-CuBsKrS-.css} +1 -1
  21. package/dist/pages/assets/app-TEMX-pOn.js +50 -0
  22. package/dist/pages/docs/operations/channels/index.html +11 -2
  23. package/dist/pages/docs/operations/profiles-database-identity/index.html +16 -2
  24. package/dist/pages/docs/pagefind/fragment/en_761fab1.pf_fragment +0 -0
  25. package/dist/pages/docs/pagefind/fragment/en_bd3e194.pf_fragment +0 -0
  26. package/dist/pages/docs/pagefind/fragment/en_ee82be6.pf_fragment +0 -0
  27. package/dist/pages/docs/pagefind/fragment/en_f4db9e2.pf_fragment +0 -0
  28. package/dist/pages/docs/pagefind/index/en_7b1363c.pf_index +0 -0
  29. package/dist/pages/docs/pagefind/pagefind-entry.json +1 -1
  30. package/dist/pages/docs/pagefind/pagefind.en_4e77743529.pf_meta +0 -0
  31. package/dist/pages/docs/reference/cli/index.html +11 -2
  32. package/dist/pages/docs/start-here/installation-first-run/index.html +7 -1
  33. package/dist/runtime-build.json +4 -4
  34. package/dist/server.js +375 -39
  35. package/dist/server.js.map +4 -4
  36. package/dist/web/assets/{app-B-fAyNsU.css → app-CuBsKrS-.css} +1 -1
  37. package/dist/web/assets/app-TEMX-pOn.js +50 -0
  38. package/dist/web/index.html +2 -2
  39. package/package.json +3 -2
  40. package/dist/docs-site/pagefind/fragment/en_4db923b.pf_fragment +0 -0
  41. package/dist/docs-site/pagefind/fragment/en_581a7cb.pf_fragment +0 -0
  42. package/dist/docs-site/pagefind/fragment/en_8c1c735.pf_fragment +0 -0
  43. package/dist/docs-site/pagefind/fragment/en_bcc29c5.pf_fragment +0 -0
  44. package/dist/docs-site/pagefind/index/en_f279b04.pf_index +0 -0
  45. package/dist/docs-site/pagefind/pagefind.en_74951c3ca7.pf_meta +0 -0
  46. package/dist/pages/assets/app-DdU93vp2.js +0 -50
  47. package/dist/pages/docs/pagefind/fragment/en_4db923b.pf_fragment +0 -0
  48. package/dist/pages/docs/pagefind/fragment/en_581a7cb.pf_fragment +0 -0
  49. package/dist/pages/docs/pagefind/fragment/en_8c1c735.pf_fragment +0 -0
  50. package/dist/pages/docs/pagefind/fragment/en_bcc29c5.pf_fragment +0 -0
  51. package/dist/pages/docs/pagefind/index/en_f279b04.pf_index +0 -0
  52. package/dist/pages/docs/pagefind/pagefind.en_74951c3ca7.pf_meta +0 -0
  53. package/dist/web/assets/app-DdU93vp2.js +0 -50
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')),
@@ -3977,6 +3992,19 @@ function getLineageSnapshot(project, assetId) {
3977
3992
  const request = rerollRequestFrom(row);
3978
3993
  return [request.node_asset_id, withRerollTask(request, lineageTasksByNode.get(request.node_asset_id)?.reroll)];
3979
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
+ }]));
3980
4008
  const childIds = new Set(edges.map((edge) => edge.parent_asset_id));
3981
4009
  const selectedIds = new Set(selected.map((row) => row.asset_id));
3982
4010
  const selections = selected.map((row) => ({
@@ -4005,6 +4033,7 @@ function getLineageSnapshot(project, assetId) {
4005
4033
  preview_url: canPreviewLocally(row.media_type, previewPath) ? localPreviewUrl(project, previewPath) : void 0,
4006
4034
  reroll_request: rerollsByNode.get(row.asset_id),
4007
4035
  selection_note: nodeSelection?.notes,
4036
+ social_mark: socialMarksByNode.get(row.asset_id),
4008
4037
  user_selected: selectedIds.has(row.asset_id)
4009
4038
  };
4010
4039
  });
@@ -4769,6 +4798,11 @@ function removeLineageNode(project, fields) {
4769
4798
  `);
4770
4799
  for (const edge of reparentedEdges) insertEdge.run(edge.id, project, edge.parent_asset_id, edge.child_asset_id, edge.created_at);
4771
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);
4772
4806
  compactSelectionsAfterRemove(database, project, root, fields.assetId, timestamp);
4773
4807
  database.exec("commit");
4774
4808
  } catch (error) {
@@ -4789,6 +4823,277 @@ function removeLineageNode(project, fields) {
4789
4823
  };
4790
4824
  }
4791
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
+
4792
5097
  // src/server/assetLedger.ts
4793
5098
  function allAssets(project, source) {
4794
5099
  const first = listAssets(project, { page: 1, pageSize: 100, source });
@@ -6867,7 +7172,7 @@ function registerAdapterRoutes(app2, projectFrom2, asyncRoute2) {
6867
7172
  import { Router } from "express";
6868
7173
 
6869
7174
  // src/server/contentBatchImport.ts
6870
- 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";
6871
7176
  import { basename as basename3, join as join10, relative as relative3 } from "node:path";
6872
7177
  function walk(dir) {
6873
7178
  return readdirSync3(dir, { withFileTypes: true }).flatMap((entry) => {
@@ -6922,7 +7227,7 @@ function itemFromFile(file) {
6922
7227
  }
6923
7228
  function demoMarkdownItems(kind) {
6924
7229
  const root = process.env.LINEAGE_CONTENT_SOURCE_ROOT || join10(repoRoot, "demo-project", "channels");
6925
- if (!existsSync8(root)) return [];
7230
+ if (!existsSync9(root)) return [];
6926
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));
6927
7232
  }
6928
7233
  function importDemoContentBatch(project, options) {
@@ -7261,8 +7566,8 @@ function contentBatchRouter(projectFrom2) {
7261
7566
  }
7262
7567
 
7263
7568
  // src/server/generationReceipts.ts
7264
- import { existsSync as existsSync9, realpathSync as realpathSync2, statSync as statSync4 } from "node:fs";
7265
- import { relative as relative4, resolve as resolve6 } 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";
7266
7571
  import { randomUUID as randomUUID3 } from "node:crypto";
7267
7572
 
7268
7573
  // src/shared/generationOutputManifest.ts
@@ -7800,8 +8105,8 @@ function isPathInside2(child, parent) {
7800
8105
  return Boolean(rel) && !rel.startsWith("..") && !rel.startsWith("/");
7801
8106
  }
7802
8107
  function scratchCandidate(file) {
7803
- const scratchRoot = resolve6(repoRoot, ".asset-scratch");
7804
- const candidate = file.startsWith(".asset-scratch/") || resolve6(file).startsWith(scratchRoot) ? resolve6(repoRoot, file) : resolve6(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);
7805
8110
  if (!isPathInside2(candidate, scratchRoot)) throw new GenerationReceiptError(`Import file must be under .asset-scratch: ${file}`);
7806
8111
  return { candidate, scratchRoot };
7807
8112
  }
@@ -7811,7 +8116,7 @@ function resolveScratchManifestPath(file) {
7811
8116
  }
7812
8117
  function resolveScratchFile(file) {
7813
8118
  const { candidate, scratchRoot } = scratchCandidate(file);
7814
- if (!existsSync9(candidate)) throw new GenerationReceiptError(`Missing import file: ${file}`, 404);
8119
+ if (!existsSync10(candidate)) throw new GenerationReceiptError(`Missing import file: ${file}`, 404);
7815
8120
  const realScratchRoot = realpathSync2(scratchRoot);
7816
8121
  const realCandidate = realpathSync2(candidate);
7817
8122
  if (!isPathInside2(realCandidate, realScratchRoot)) throw new GenerationReceiptError(`Import file must be under .asset-scratch: ${file}`);
@@ -8143,7 +8448,7 @@ function registerLineageTaskRoutes(app2, projectFrom2, asyncRoute2) {
8143
8448
 
8144
8449
  // src/server/assetLineageDemo.ts
8145
8450
  import { createHash as createHash5 } from "node:crypto";
8146
- 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";
8147
8452
  import { tmpdir } from "node:os";
8148
8453
  import { dirname as dirname5, join as join11, posix } from "node:path";
8149
8454
  import { gunzipSync } from "node:zlib";
@@ -8215,9 +8520,9 @@ function swissifierRerollFixturePath(attempt) {
8215
8520
  }
8216
8521
  function swissifierSourcePath(manifest, asset, sourceDir) {
8217
8522
  const direct = join11(sourceDir, asset.file);
8218
- if (existsSync10(direct)) return direct;
8523
+ if (existsSync11(direct)) return direct;
8219
8524
  const nested = join11(sourceDir, manifest.media.target_dir, asset.file);
8220
- return existsSync10(nested) ? nested : null;
8525
+ return existsSync11(nested) ? nested : null;
8221
8526
  }
8222
8527
  function swissifierMediaState(manifest) {
8223
8528
  const missing = [];
@@ -8225,7 +8530,7 @@ function swissifierMediaState(manifest) {
8225
8530
  for (const asset of manifest.assets) {
8226
8531
  const relativePath = swissifierRelativePath(manifest, asset);
8227
8532
  const path = swissifierFilePath(manifest, asset);
8228
- if (!existsSync10(path)) {
8533
+ if (!existsSync11(path)) {
8229
8534
  missing.push(relativePath);
8230
8535
  continue;
8231
8536
  }
@@ -8317,7 +8622,7 @@ async function downloadBuffer(url, maxBytes) {
8317
8622
  return buffer;
8318
8623
  }
8319
8624
  function missingDemoMedia(project) {
8320
- 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));
8321
8626
  }
8322
8627
  function demoSeedMediaStatus(project = defaultProject) {
8323
8628
  const missing = missingDemoMedia(project);
@@ -8512,7 +8817,7 @@ function writeDemoFiles(project) {
8512
8817
  }
8513
8818
  function swissifierRerollAsset(attempt) {
8514
8819
  const source = swissifierRerollFixturePath(attempt);
8515
- 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}`);
8516
8821
  const body = readFileSync6(source);
8517
8822
  if (body.length !== attempt.size_bytes) throw new Error(`Unexpected Swissifier re-roll fixture size for ${attempt.file}`);
8518
8823
  const checksumSha256 = sha256Hex(body);
@@ -8935,8 +9240,8 @@ function registerLineageWorkspaceRoutes(app2, projectFrom2, asyncRoute2) {
8935
9240
  // src/server/runtimeInfo.ts
8936
9241
  import { createHash as createHash6 } from "node:crypto";
8937
9242
  import { spawnSync as spawnSync2 } from "node:child_process";
8938
- import { existsSync as existsSync11, lstatSync as lstatSync3, readFileSync as readFileSync7, readdirSync as readdirSync4, readlinkSync, realpathSync as realpathSync3, statSync as statSync5 } from "node:fs";
8939
- import { dirname as dirname6, isAbsolute as isAbsolute3, join as join12, resolve as resolve7 } 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";
8940
9245
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8941
9246
 
8942
9247
  // src/shared/runtimeInfoTypes.ts
@@ -8955,7 +9260,7 @@ function isLineagePackageRoot(root) {
8955
9260
  }
8956
9261
  function executingCodeRoot() {
8957
9262
  const moduleDirectory = dirname6(fileURLToPath2(import.meta.url));
8958
- const candidates = [resolve7(moduleDirectory, "../.."), resolve7(moduleDirectory, "..")];
9263
+ const candidates = [resolve8(moduleDirectory, "../.."), resolve8(moduleDirectory, "..")];
8959
9264
  const root = candidates.find(isLineagePackageRoot);
8960
9265
  if (!root) throw new Error(`Unable to derive Lineage code root from executing module ${fileURLToPath2(import.meta.url)}`);
8961
9266
  return canonicalRoot(root);
@@ -8968,7 +9273,7 @@ function canonicalRoot(root) {
8968
9273
  try {
8969
9274
  return realpathSync3(root);
8970
9275
  } catch {
8971
- return resolve7(root);
9276
+ return resolve8(root);
8972
9277
  }
8973
9278
  }
8974
9279
  function packageInfo(root = codeRoot) {
@@ -9068,7 +9373,7 @@ function readInstallReceipt(path, errors) {
9068
9373
  return void 0;
9069
9374
  }
9070
9375
  let receipt;
9071
- const receiptPath = resolve7(path);
9376
+ const receiptPath = resolve8(path);
9072
9377
  try {
9073
9378
  receipt = JSON.parse(readFileSync7(receiptPath, "utf8"));
9074
9379
  } catch (error) {
@@ -9076,7 +9381,7 @@ function readInstallReceipt(path, errors) {
9076
9381
  return void 0;
9077
9382
  }
9078
9383
  if (receipt.schema_version !== lineageRuntimeInstallSchemaVersion) errors.push(`Unsupported runtime install receipt schema: ${String(receipt.schema_version)}`);
9079
- if (!isAbsolute3(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");
9080
9385
  if (!receipt.package_integrity?.startsWith("sha512-")) errors.push("Runtime install receipt package integrity is invalid");
9081
9386
  if (receipt.package_source !== "registry" && receipt.package_source !== "local") errors.push("Runtime install receipt package source is invalid");
9082
9387
  if (typeof receipt.package_spec !== "string" || !receipt.package_spec) errors.push("Runtime install receipt package spec is invalid");
@@ -9157,8 +9462,8 @@ function packageCodeIdentity(root, channel, info, receiptPath) {
9157
9462
  function getLineageCodeIdentity(channel, options = {}) {
9158
9463
  const root = canonicalRoot(options.root || codeRoot);
9159
9464
  const info = packageInfo(root);
9160
- if (existsSync11(join12(root, ".git"))) return checkoutCodeIdentity(root, channel, info.version);
9161
- 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"))) {
9162
9467
  return packageCodeIdentity(root, channel, info, options.receiptPath ?? process.env.LINEAGE_RUNTIME_RECEIPT);
9163
9468
  }
9164
9469
  const errors = [`Code root has neither checkout metadata nor package.json: ${root}`];
@@ -9197,7 +9502,7 @@ function getLineageRuntimeInfo(options = {}) {
9197
9502
  const dbPath = options.dbPath || lineageDbPath();
9198
9503
  const channel = normalizeRuntimeChannel(options.channel || process.env.LINEAGE_CHANNEL || process.env.LINEAGE_RELEASE_CHANNEL);
9199
9504
  const code = options.code || getLineageCodeIdentity(channel);
9200
- const databaseInfo = { exists: existsSync11(dbPath), path: dbPath };
9505
+ const databaseInfo = { exists: existsSync12(dbPath), path: dbPath };
9201
9506
  const schema = { migration_keys: [] };
9202
9507
  const serviceInstanceId = process.env.LINEAGE_SERVICE_INSTANCE_ID;
9203
9508
  const launcherPid = process.env.LINEAGE_LAUNCHER_PID ? Number(process.env.LINEAGE_LAUNCHER_PID) : void 0;
@@ -9337,14 +9642,14 @@ function registerManagedWriterRoute(app2, fields) {
9337
9642
  }
9338
9643
 
9339
9644
  // src/cli/lineageCli.ts
9340
- import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "node:fs";
9341
- import { dirname as dirname7, join as join13, resolve as resolve9 } 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";
9342
9647
  import { fileURLToPath as fileURLToPath3 } from "node:url";
9343
9648
 
9344
9649
  // src/server/lineageSelectionPacket.ts
9345
9650
  import { createHash as createHash7 } from "node:crypto";
9346
- import { existsSync as existsSync12, statSync as statSync6 } from "node:fs";
9347
- import { isAbsolute as isAbsolute4, resolve as resolve8 } 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";
9348
9653
  var LineageSelectionPacketError = class extends Error {
9349
9654
  constructor(message, warnings = [], errors = [], diagnostics = []) {
9350
9655
  super(message);
@@ -9390,13 +9695,13 @@ function resolveWorkspace(project, options) {
9390
9695
  }
9391
9696
  function resolveLocalReference(reference) {
9392
9697
  if (!reference) return void 0;
9393
- if (isAbsolute4(reference)) return reference;
9394
- const repoRelative = resolve8(repoRoot, reference);
9395
- if (existsSync12(repoRelative)) return repoRelative;
9396
- return resolve8(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);
9397
9702
  }
9398
9703
  function fileSize(path) {
9399
- if (!path || !existsSync12(path)) return void 0;
9704
+ if (!path || !existsSync13(path)) return void 0;
9400
9705
  try {
9401
9706
  return statSync6(path).size;
9402
9707
  } catch {
@@ -9424,7 +9729,7 @@ function currentAttemptFor(node) {
9424
9729
  function assetForNode(node, catalogAsset, warnings) {
9425
9730
  const localReference = catalogAsset?.local?.absolute_path || node.current_attempt?.file_path || node.local_path || catalogAsset?.local?.relative_path;
9426
9731
  const absolutePath = catalogAsset?.local?.absolute_path || resolveLocalReference(localReference);
9427
- const localExists = absolutePath ? existsSync12(absolutePath) : false;
9732
+ const localExists = absolutePath ? existsSync13(absolutePath) : false;
9428
9733
  const hasLocalClaim = Boolean(absolutePath || node.local_path || catalogAsset?.local?.relative_path);
9429
9734
  const s3Key = catalogAsset?.s3?.key || node.s3_key;
9430
9735
  const hasS3 = Boolean(s3Key);
@@ -9581,7 +9886,7 @@ function assetForNodeV2(node, visibleCatalogAsset, catalogById, warnings, errors
9581
9886
  const mediaCatalogAsset = currentAttemptCatalogAsset || (isVisibleNodeAttempt ? visibleCatalogAsset : void 0);
9582
9887
  const localReference = currentAttempt.file_path || mediaCatalogAsset?.local?.absolute_path || mediaCatalogAsset?.local?.relative_path || (isVisibleNodeAttempt ? node.local_path : void 0);
9583
9888
  const absolutePath = resolveLocalReference(localReference);
9584
- const localExists = absolutePath ? existsSync12(absolutePath) : false;
9889
+ const localExists = absolutePath ? existsSync13(absolutePath) : false;
9585
9890
  const hasLocalClaim = Boolean(localReference);
9586
9891
  const s3Key = mediaCatalogAsset?.s3?.key || (isVisibleNodeAttempt ? node.s3_key : void 0);
9587
9892
  const hasS3 = Boolean(s3Key);
@@ -9846,7 +10151,7 @@ function getLineageSelectionPacket(project, options = {}) {
9846
10151
 
9847
10152
  // src/cli/lineageCli.ts
9848
10153
  function packageRoot2() {
9849
- return resolve9(dirname7(fileURLToPath3(import.meta.url)), "..", "..");
10154
+ return resolve10(dirname7(fileURLToPath3(import.meta.url)), "..", "..");
9850
10155
  }
9851
10156
  function packageVersion() {
9852
10157
  try {
@@ -9879,7 +10184,7 @@ function readOptions(args, name) {
9879
10184
  }
9880
10185
  function readJsonFile(path, label) {
9881
10186
  try {
9882
- return JSON.parse(readFileSync8(resolve9(path), "utf8"));
10187
+ return JSON.parse(readFileSync8(resolve10(path), "utf8"));
9883
10188
  } catch (error) {
9884
10189
  throw new Error(`${label} must be a readable JSON file: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
9885
10190
  }
@@ -9898,7 +10203,7 @@ function parentFilesOption(value) {
9898
10203
  return mappings;
9899
10204
  }
9900
10205
  function resolveCliAssetRoot(args) {
9901
- return resolve9(readOption(args, "--asset-root") || process.env.LINEAGE_ASSET_ROOT || packageRoot);
10206
+ return resolve10(readOption(args, "--asset-root") || process.env.LINEAGE_ASSET_ROOT || packageRoot);
9902
10207
  }
9903
10208
  function configureCliAssetRoot(args) {
9904
10209
  const assetRoot = resolveCliAssetRoot(args);
@@ -9963,7 +10268,7 @@ function runLineageDataCommand(command, args) {
9963
10268
  });
9964
10269
  const out = readOption(args, "--out");
9965
10270
  if (out) {
9966
- const outPath = resolve9(out);
10271
+ const outPath = resolve10(out);
9967
10272
  mkdirSync8(dirname7(outPath), { recursive: true });
9968
10273
  writeFileSync6(outPath, `${JSON.stringify(packet, null, 2)}
9969
10274
  `);
@@ -10074,6 +10379,35 @@ function runLineageDataCommand(command, args) {
10074
10379
  }
10075
10380
  throw new Error(`Unknown reroll command: ${subcommand}`);
10076
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
+ }
10077
10411
  if (command === "tasks") {
10078
10412
  const subcommand = positionalArgs(args)[0] || "";
10079
10413
  const taskId = readOption(args, "--task");
@@ -10146,6 +10480,7 @@ function lineageCliCanDelegateMutation(command, args) {
10146
10480
  if (command === "link-child") return true;
10147
10481
  if (command === "generate") return positions[0] === "image" && ["plan", "import"].includes(positions[1] || "");
10148
10482
  if (command === "reroll") return ["mark", "cancel", "plan", "import"].includes(subcommand);
10483
+ if (command === "social") return ["mark", "unmark"].includes(subcommand);
10149
10484
  if (command === "tasks") return ["claim", "start", "comment", "cancel", "override", "instructions"].includes(subcommand);
10150
10485
  if (command === "agent") return ["claim", "heartbeat", "release", "revoke", "transfer"].includes(subcommand);
10151
10486
  return false;
@@ -10379,6 +10714,7 @@ app.get(
10379
10714
  );
10380
10715
  registerLineageWorkspaceRoutes(app, projectFrom, asyncRoute);
10381
10716
  registerLineageTaskRoutes(app, projectFrom, asyncRoute);
10717
+ registerAssetSocialMarkRoutes(app, projectFrom, asyncRoute);
10382
10718
  app.get("/api/lineage/:rootAssetId/rerolls", asyncRoute((req, res) => {
10383
10719
  res.json(listLineageRerollRequests(projectFrom(req), req.params.rootAssetId));
10384
10720
  }));
@@ -10630,7 +10966,7 @@ app.post(
10630
10966
  );
10631
10967
  if (isProduction) {
10632
10968
  const dist = join14(packageRoot, "dist", "web");
10633
- if (existsSync14(dist)) {
10969
+ if (existsSync15(dist)) {
10634
10970
  app.use(express2.static(dist));
10635
10971
  app.get("*", (_req, res) => res.sendFile(join14(dist, "index.html")));
10636
10972
  }