@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.
- package/CHANGELOG.md +15 -0
- package/MANUAL_INSTALL_DOGFOOD.md +1 -0
- package/README.md +45 -5
- package/dist/cli/lineage-dev.js +612 -37
- package/dist/cli/lineage-dev.js.map +4 -4
- package/dist/cli/lineage-preview.js +612 -37
- package/dist/cli/lineage-preview.js.map +4 -4
- package/dist/cli/lineage.js +612 -37
- package/dist/cli/lineage.js.map +4 -4
- package/dist/docs-site/404.html +41 -0
- package/dist/docs-site/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.BcSo_yiZ.js +1 -0
- package/dist/docs-site/_astro/Search.astro_astro_type_script_index_0_lang.x2pVooPA.js +1 -0
- package/dist/docs-site/_astro/TableOfContents.astro_astro_type_script_index_0_lang.Csloo1VZ.js +1 -0
- package/dist/docs-site/_astro/common.DarLW4Vf.css +3 -0
- package/dist/docs-site/_astro/ec.0vx5m.js +3 -0
- package/dist/docs-site/_astro/ec.w36nc.css +1 -0
- package/dist/docs-site/_astro/page.LAbJoB63.js +1 -0
- package/dist/docs-site/_astro/print.ehPL0gv-.css +1 -0
- package/dist/docs-site/_astro/starlight-toc.CTCQXEge.js +1 -0
- package/dist/docs-site/_astro/ui-core.DWIqd25E.js +2 -0
- package/dist/docs-site/concepts/agent-claims-handoffs/index.html +99 -0
- package/dist/docs-site/concepts/attempts-current-version/index.html +86 -0
- package/dist/docs-site/concepts/branches-vs-rerolls/index.html +114 -0
- package/dist/docs-site/concepts/projects-workspaces-assets/index.html +89 -0
- package/dist/docs-site/concepts/selections-next-variations/index.html +86 -0
- package/dist/docs-site/index.html +92 -0
- package/dist/docs-site/integrations/cloud-storage/index.html +92 -0
- package/dist/docs-site/integrations/image-generation/index.html +93 -0
- package/dist/docs-site/integrations/index.html +112 -0
- package/dist/docs-site/integrations/social-scheduling/index.html +89 -0
- package/dist/docs-site/operations/backup-recovery/index.html +87 -0
- package/dist/docs-site/operations/channels/index.html +97 -0
- package/dist/docs-site/operations/local-first-data/index.html +90 -0
- package/dist/docs-site/operations/profiles-database-identity/index.html +104 -0
- package/dist/docs-site/operations/troubleshooting/index.html +89 -0
- package/dist/docs-site/pagefind/fragment/en_1126abb.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_19b3f6c.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_31aa611.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_38817cc.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_4184ad1.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_41db543.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_469f895.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_56e45b6.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_56fe7ca.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_5be5e44.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_603c2be.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_66b3118.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_6a19c31.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_74e9307.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_761fab1.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_7c9d5a2.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_818744b.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_8269752.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_88b38c1.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_98d9b16.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_a3d636e.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_b15ecf0.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_bd3e194.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_bfb13e9.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_d0fca9e.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_d49ed00.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_e0786b9.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_e298dee.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_ee82be6.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_f4db9e2.pf_fragment +0 -0
- package/dist/docs-site/pagefind/fragment/en_f6179a8.pf_fragment +0 -0
- package/dist/docs-site/pagefind/index/en_7b1363c.pf_index +0 -0
- package/dist/docs-site/pagefind/pagefind-component-ui.css +1509 -0
- package/dist/docs-site/pagefind/pagefind-component-ui.js +56 -0
- package/dist/docs-site/pagefind/pagefind-entry.json +1 -0
- package/dist/docs-site/pagefind/pagefind-highlight.js +1070 -0
- package/dist/docs-site/pagefind/pagefind-modular-ui.css +214 -0
- package/dist/docs-site/pagefind/pagefind-modular-ui.js +8 -0
- package/dist/docs-site/pagefind/pagefind-ui.css +1 -0
- package/dist/docs-site/pagefind/pagefind-ui.js +2 -0
- package/dist/docs-site/pagefind/pagefind-worker.js +6 -0
- package/dist/docs-site/pagefind/pagefind.en_4e77743529.pf_meta +0 -0
- package/dist/docs-site/pagefind/pagefind.js +6 -0
- package/dist/docs-site/pagefind/wasm.en.pagefind +0 -0
- package/dist/docs-site/pagefind/wasm.unknown.pagefind +0 -0
- package/dist/docs-site/reference/cli/index.html +95 -0
- package/dist/docs-site/reference/interface-guide/index.html +86 -0
- package/dist/docs-site/reference/release-notes/index.html +80 -0
- package/dist/docs-site/reference/settings/index.html +86 -0
- package/dist/docs-site/reference/terminology/index.html +94 -0
- package/dist/docs-site/sitemap-0.xml +1 -0
- package/dist/docs-site/sitemap-index.xml +1 -0
- package/dist/docs-site/start-here/example-projects/index.html +88 -0
- package/dist/docs-site/start-here/first-workspace/index.html +91 -0
- package/dist/docs-site/start-here/installation-first-run/index.html +92 -0
- package/dist/docs-site/start-here/what-is-lineage/index.html +96 -0
- package/dist/docs-site/workflows/back-up-approved-assets/index.html +88 -0
- package/dist/docs-site/workflows/content-batches/index.html +88 -0
- package/dist/docs-site/workflows/continue-new-agent-session/index.html +89 -0
- package/dist/docs-site/workflows/create-grow-lineage/index.html +89 -0
- package/dist/docs-site/workflows/generate-import-variations/index.html +92 -0
- package/dist/docs-site/workflows/restore-earlier-attempt/index.html +87 -0
- package/dist/docs-site/workflows/review-approve-assets/index.html +87 -0
- package/dist/pages/.nojekyll +0 -0
- package/dist/pages/assets/agent-shared-state-DOfpTLiw.webp +0 -0
- package/dist/pages/assets/agent-to-canvas-DtIu_cPq.mp4 +0 -0
- package/dist/{web/assets/app-B-fAyNsU.css → pages/assets/app-CuBsKrS-.css} +1 -1
- package/dist/pages/assets/app-TEMX-pOn.js +50 -0
- package/dist/pages/assets/attempt-history-D6wdic6n.webp +0 -0
- package/dist/pages/assets/branching-tree-B8I5_S6D.png +0 -0
- package/dist/pages/assets/canvas-cli-DHBacq7r.png +0 -0
- package/dist/pages/assets/hero-agent-sync-D8ibW83E.mp4 +0 -0
- package/dist/pages/assets/hero-agent-sync-poster-zBB3KpbO.png +0 -0
- package/dist/pages/assets/hero-board-DG3ED4AW.webp +0 -0
- package/dist/pages/assets/hero-lineage-growth-Bsl9tiq-.mp4 +0 -0
- package/dist/pages/assets/hero-trace-connections-Bb52ABBc.mp4 +0 -0
- package/dist/pages/assets/human-selection-BdDBDE-I.webp +0 -0
- package/dist/pages/assets/human-to-agent-D1z92ZO9.mp4 +0 -0
- package/dist/pages/assets/jsx-runtime-DAFSxiwi.js +8 -0
- package/dist/pages/assets/landing-MwOFmHoi.js +2 -0
- package/dist/pages/assets/landing-wy4L-yBm.css +1 -0
- package/dist/pages/assets/reroll-history-DQcEH42R.mp4 +0 -0
- package/dist/pages/docs/404.html +41 -0
- package/dist/pages/docs/_astro/MobileTableOfContents.astro_astro_type_script_index_0_lang.BcSo_yiZ.js +1 -0
- package/dist/pages/docs/_astro/Search.astro_astro_type_script_index_0_lang.x2pVooPA.js +1 -0
- package/dist/pages/docs/_astro/TableOfContents.astro_astro_type_script_index_0_lang.Csloo1VZ.js +1 -0
- package/dist/pages/docs/_astro/common.DarLW4Vf.css +3 -0
- package/dist/pages/docs/_astro/ec.0vx5m.js +3 -0
- package/dist/pages/docs/_astro/ec.w36nc.css +1 -0
- package/dist/pages/docs/_astro/page.LAbJoB63.js +1 -0
- package/dist/pages/docs/_astro/print.ehPL0gv-.css +1 -0
- package/dist/pages/docs/_astro/starlight-toc.CTCQXEge.js +1 -0
- package/dist/pages/docs/_astro/ui-core.DWIqd25E.js +2 -0
- package/dist/pages/docs/concepts/agent-claims-handoffs/index.html +99 -0
- package/dist/pages/docs/concepts/attempts-current-version/index.html +86 -0
- package/dist/pages/docs/concepts/branches-vs-rerolls/index.html +114 -0
- package/dist/pages/docs/concepts/projects-workspaces-assets/index.html +89 -0
- package/dist/pages/docs/concepts/selections-next-variations/index.html +86 -0
- package/dist/pages/docs/index.html +92 -0
- package/dist/pages/docs/integrations/cloud-storage/index.html +92 -0
- package/dist/pages/docs/integrations/image-generation/index.html +93 -0
- package/dist/pages/docs/integrations/index.html +112 -0
- package/dist/pages/docs/integrations/social-scheduling/index.html +89 -0
- package/dist/pages/docs/operations/backup-recovery/index.html +87 -0
- package/dist/pages/docs/operations/channels/index.html +97 -0
- package/dist/pages/docs/operations/local-first-data/index.html +90 -0
- package/dist/pages/docs/operations/profiles-database-identity/index.html +104 -0
- package/dist/pages/docs/operations/troubleshooting/index.html +89 -0
- package/dist/pages/docs/pagefind/fragment/en_1126abb.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_19b3f6c.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_31aa611.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_38817cc.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_4184ad1.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_41db543.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_469f895.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_56e45b6.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_56fe7ca.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_5be5e44.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_603c2be.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_66b3118.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_6a19c31.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_74e9307.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_761fab1.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_7c9d5a2.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_818744b.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_8269752.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_88b38c1.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_98d9b16.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_a3d636e.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_b15ecf0.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_bd3e194.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_bfb13e9.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_d0fca9e.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_d49ed00.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_e0786b9.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_e298dee.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_ee82be6.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_f4db9e2.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/fragment/en_f6179a8.pf_fragment +0 -0
- package/dist/pages/docs/pagefind/index/en_7b1363c.pf_index +0 -0
- package/dist/pages/docs/pagefind/pagefind-component-ui.css +1509 -0
- package/dist/pages/docs/pagefind/pagefind-component-ui.js +56 -0
- package/dist/pages/docs/pagefind/pagefind-entry.json +1 -0
- package/dist/pages/docs/pagefind/pagefind-highlight.js +1070 -0
- package/dist/pages/docs/pagefind/pagefind-modular-ui.css +214 -0
- package/dist/pages/docs/pagefind/pagefind-modular-ui.js +8 -0
- package/dist/pages/docs/pagefind/pagefind-ui.css +1 -0
- package/dist/pages/docs/pagefind/pagefind-ui.js +2 -0
- package/dist/pages/docs/pagefind/pagefind-worker.js +6 -0
- package/dist/pages/docs/pagefind/pagefind.en_4e77743529.pf_meta +0 -0
- package/dist/pages/docs/pagefind/pagefind.js +6 -0
- package/dist/pages/docs/pagefind/wasm.en.pagefind +0 -0
- package/dist/pages/docs/pagefind/wasm.unknown.pagefind +0 -0
- package/dist/pages/docs/reference/cli/index.html +95 -0
- package/dist/pages/docs/reference/interface-guide/index.html +86 -0
- package/dist/pages/docs/reference/release-notes/index.html +80 -0
- package/dist/pages/docs/reference/settings/index.html +86 -0
- package/dist/pages/docs/reference/terminology/index.html +94 -0
- package/dist/pages/docs/sitemap-0.xml +1 -0
- package/dist/pages/docs/sitemap-index.xml +1 -0
- package/dist/pages/docs/start-here/example-projects/index.html +88 -0
- package/dist/pages/docs/start-here/first-workspace/index.html +91 -0
- package/dist/pages/docs/start-here/installation-first-run/index.html +92 -0
- package/dist/pages/docs/start-here/what-is-lineage/index.html +96 -0
- package/dist/pages/docs/workflows/back-up-approved-assets/index.html +88 -0
- package/dist/pages/docs/workflows/content-batches/index.html +88 -0
- package/dist/pages/docs/workflows/continue-new-agent-session/index.html +89 -0
- package/dist/pages/docs/workflows/create-grow-lineage/index.html +89 -0
- package/dist/pages/docs/workflows/generate-import-variations/index.html +92 -0
- package/dist/pages/docs/workflows/restore-earlier-attempt/index.html +87 -0
- package/dist/pages/docs/workflows/review-approve-assets/index.html +87 -0
- package/dist/pages/index.html +42 -0
- package/dist/pages/landing/index.html +42 -0
- package/dist/pages/lineage-showcase-cover-16x9.png +0 -0
- package/dist/runtime-build.json +5 -5
- package/dist/server.js +431 -46
- package/dist/server.js.map +4 -4
- package/dist/web/assets/app-CuBsKrS-.css +1 -0
- package/dist/web/assets/app-TEMX-pOn.js +50 -0
- package/dist/web/assets/landing-MwOFmHoi.js +2 -0
- package/dist/web/index.html +3 -3
- package/dist/web/landing/index.html +26 -3
- package/dist/web/lineage-showcase-cover-16x9.png +0 -0
- package/package.json +11 -2
- package/dist/web/assets/app-D-7R33Mc.js +0 -16
- package/dist/web/assets/landing-DIjBBL33.js +0 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/lineageCli.ts
|
|
4
|
-
import { existsSync as
|
|
4
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
5
5
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
6
6
|
import { homedir as homedir2, platform as platform2 } from "node:os";
|
|
7
|
-
import { dirname as dirname6, join as join10, resolve as
|
|
7
|
+
import { dirname as dirname6, join as join10, resolve as resolve10 } from "node:path";
|
|
8
8
|
import { spawn } from "node:child_process";
|
|
9
9
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
10
10
|
|
|
@@ -648,6 +648,7 @@ var lineageProfileDoctorSchemaVersion = "lineage.profile_doctor.v1";
|
|
|
648
648
|
var lineageProfileCloneReceiptSchemaVersion = "lineage.profile_clone_receipt.v1";
|
|
649
649
|
var lineageProfileAssetsCloneReceiptSchemaVersion = "lineage.profile_assets_clone_receipt.v1";
|
|
650
650
|
var lineageProfileRuntimeRepinReceiptSchemaVersion = "lineage.profile_runtime_repin_receipt.v1";
|
|
651
|
+
var lineageProfileRuntimeUpgradeReceiptSchemaVersion = "lineage.profile_runtime_upgrade_receipt.v1";
|
|
651
652
|
|
|
652
653
|
// src/server/nodeSqlite.ts
|
|
653
654
|
import { createRequire } from "node:module";
|
|
@@ -848,7 +849,9 @@ function initializeLineageProfile(profileId, serviceOrigin, runtime, confirmWrit
|
|
|
848
849
|
expected_runtime: {
|
|
849
850
|
channel: runtime.channel,
|
|
850
851
|
code_fingerprint: runtime.code.fingerprint.toLowerCase(),
|
|
851
|
-
code_origin: runtime.code.origin
|
|
852
|
+
code_origin: runtime.code.origin,
|
|
853
|
+
...runtime.gitSha ? { git_sha: runtime.gitSha } : {},
|
|
854
|
+
version: runtime.version
|
|
852
855
|
},
|
|
853
856
|
profile_id: profileId,
|
|
854
857
|
schema_version: lineageProfileSchemaVersion,
|
|
@@ -914,7 +917,9 @@ function initializeLineageProfile(profileId, serviceOrigin, runtime, confirmWrit
|
|
|
914
917
|
runtime: {
|
|
915
918
|
channel: runtime.channel,
|
|
916
919
|
code_fingerprint: runtime.code.fingerprint,
|
|
917
|
-
code_origin: runtime.code.origin
|
|
920
|
+
code_origin: runtime.code.origin,
|
|
921
|
+
...runtime.gitSha ? { git_sha: runtime.gitSha } : {},
|
|
922
|
+
version: runtime.version
|
|
918
923
|
},
|
|
919
924
|
schema_version: lineageProfileInitSchemaVersion,
|
|
920
925
|
service_origin: profile.service_origin
|
|
@@ -950,6 +955,229 @@ function runtimeRepinInvariant(profile) {
|
|
|
950
955
|
function sameFileIdentity(left, right) {
|
|
951
956
|
return left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs;
|
|
952
957
|
}
|
|
958
|
+
function fsyncDirectory(path) {
|
|
959
|
+
const directoryFd = openSync(path, "r");
|
|
960
|
+
try {
|
|
961
|
+
fsyncSync(directoryFd);
|
|
962
|
+
} finally {
|
|
963
|
+
closeSync(directoryFd);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
function parseStableVersion(value, label) {
|
|
967
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(value);
|
|
968
|
+
if (!match) throw new Error(`${label} must be a valid stable SemVer without a prerelease, found ${value}`);
|
|
969
|
+
return match.slice(1).map(BigInt);
|
|
970
|
+
}
|
|
971
|
+
function compareStableVersions(left, right) {
|
|
972
|
+
for (let index = 0; index < left.length; index += 1) {
|
|
973
|
+
if (left[index] !== right[index]) return left[index] < right[index] ? -1 : 1;
|
|
974
|
+
}
|
|
975
|
+
return 0;
|
|
976
|
+
}
|
|
977
|
+
function profileUpgradePreflight(profile, runtime) {
|
|
978
|
+
const doctor = doctorLineageProfile(profile.manifest_path, runtime);
|
|
979
|
+
const allowedRuntimeMismatches = /* @__PURE__ */ new Set(["runtime_code", "runtime_version", "runtime_git_sha"]);
|
|
980
|
+
const failures = doctor.checks.filter((check) => check.status === "fail" && !allowedRuntimeMismatches.has(check.id));
|
|
981
|
+
if (failures.length > 0) {
|
|
982
|
+
throw new Error(`Stable profile runtime upgrade requires a healthy production profile before changing its pin: ${failures.map((check) => `${check.id}: ${check.message}`).join("; ")}`);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
function upgradeRuntimeIdentity(fingerprint, options = {}) {
|
|
986
|
+
return {
|
|
987
|
+
channel: "stable",
|
|
988
|
+
code_fingerprint: fingerprint,
|
|
989
|
+
code_origin: "package",
|
|
990
|
+
...options.codeRoot ? { code_root: options.codeRoot } : {},
|
|
991
|
+
...options.gitSha ? { git_sha: options.gitSha } : {},
|
|
992
|
+
...options.version ? { version: options.version } : {}
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
function upgradeLineageStableProfileRuntime(selector, runtime, confirmWrite, testHooks = {}) {
|
|
996
|
+
if (!confirmWrite) throw new Error("Stable profile runtime upgrade requires --confirm-write");
|
|
997
|
+
if (runtime.channel !== "stable") throw new Error(`Stable profile runtime upgrade requires stable code, not ${runtime.channel}`);
|
|
998
|
+
if (!runtime.code?.verified) throw new Error("Stable profile runtime upgrade requires a verified package runtime");
|
|
999
|
+
if (runtime.code.channel !== "stable") throw new Error(`Stable profile runtime upgrade requires stable code identity, not ${runtime.code.channel}`);
|
|
1000
|
+
if (runtime.code.origin !== "package") throw new Error(`Stable profile runtime upgrade requires package code, not ${runtime.code.origin}`);
|
|
1001
|
+
if (!runtime.code.fingerprint || !/^[a-f0-9]{64}$/i.test(runtime.code.fingerprint)) {
|
|
1002
|
+
throw new Error("Stable profile runtime upgrade requires a valid executing code fingerprint");
|
|
1003
|
+
}
|
|
1004
|
+
if (runtime.code.package_version !== runtime.version) {
|
|
1005
|
+
throw new Error(`Stable profile runtime upgrade version ${runtime.version} does not match package version ${runtime.code.package_version || "missing"}`);
|
|
1006
|
+
}
|
|
1007
|
+
const targetVersion = parseStableVersion(runtime.version, "Stable profile runtime upgrade target version");
|
|
1008
|
+
const executingRoot = realpathSync(runtime.code.root);
|
|
1009
|
+
if (!statSync3(executingRoot).isDirectory()) {
|
|
1010
|
+
throw new Error(`Stable profile runtime upgrade code root is not a directory: ${executingRoot}`);
|
|
1011
|
+
}
|
|
1012
|
+
const profile = resolveLineageProfile(selector);
|
|
1013
|
+
if (profile.environment !== "production") {
|
|
1014
|
+
throw new Error(`Stable profile runtime upgrade requires a production profile, not ${profile.environment}`);
|
|
1015
|
+
}
|
|
1016
|
+
if (profile.expected_runtime?.channel !== "stable") {
|
|
1017
|
+
throw new Error("Stable profile runtime upgrade requires an existing stable channel pin");
|
|
1018
|
+
}
|
|
1019
|
+
if (profile.expected_runtime.code_origin !== "package") {
|
|
1020
|
+
throw new Error("Stable profile runtime upgrade requires an existing package origin pin");
|
|
1021
|
+
}
|
|
1022
|
+
const previousFingerprint = profile.expected_runtime.code_fingerprint;
|
|
1023
|
+
if (!previousFingerprint) throw new Error("Stable profile runtime upgrade requires an existing code fingerprint pin");
|
|
1024
|
+
const previousVersion = profile.expected_runtime.version;
|
|
1025
|
+
if (previousVersion) {
|
|
1026
|
+
const comparison = compareStableVersions(targetVersion, parseStableVersion(previousVersion, "Stable profile runtime upgrade source version"));
|
|
1027
|
+
if (previousFingerprint === runtime.code.fingerprint && previousVersion !== runtime.version) {
|
|
1028
|
+
throw new Error(`Stable profile runtime upgrade found one code fingerprint claiming conflicting versions ${previousVersion} and ${runtime.version}`);
|
|
1029
|
+
}
|
|
1030
|
+
if (comparison === 0 && previousFingerprint !== runtime.code.fingerprint) {
|
|
1031
|
+
throw new Error(`Stable profile runtime upgrade refuses same-version fingerprint change for ${runtime.version}`);
|
|
1032
|
+
}
|
|
1033
|
+
if (comparison < 0) {
|
|
1034
|
+
throw new Error(`Stable profile runtime upgrade refuses downgrade from ${previousVersion} to ${runtime.version}`);
|
|
1035
|
+
}
|
|
1036
|
+
if (comparison > 0 && previousFingerprint === runtime.code.fingerprint) {
|
|
1037
|
+
throw new Error(`Stable profile runtime upgrade requires a new code fingerprint for version ${runtime.version}`);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
if (previousFingerprint === runtime.code.fingerprint && profile.expected_runtime.git_sha && runtime.gitSha && profile.expected_runtime.git_sha !== runtime.gitSha) {
|
|
1041
|
+
throw new Error("Stable profile runtime upgrade found one code fingerprint claiming conflicting Git revisions");
|
|
1042
|
+
}
|
|
1043
|
+
profileUpgradePreflight(profile, runtime);
|
|
1044
|
+
const manifestPath = profile.manifest_path;
|
|
1045
|
+
const profileDirectory = dirname3(manifestPath);
|
|
1046
|
+
assertOwnerOnlyPath(profileDirectory, "profile directory");
|
|
1047
|
+
const beforeStats = assertOwnerOnlyPath(manifestPath, "manifest");
|
|
1048
|
+
const beforeText = readFileSync3(manifestPath, "utf8");
|
|
1049
|
+
const beforeHash = sha256(beforeText);
|
|
1050
|
+
let raw;
|
|
1051
|
+
try {
|
|
1052
|
+
raw = JSON.parse(beforeText);
|
|
1053
|
+
} catch (error) {
|
|
1054
|
+
throw new Error(`Could not parse profile manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
1055
|
+
}
|
|
1056
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) throw new Error("Profile manifest must be a JSON object");
|
|
1057
|
+
const nextExpectedRuntime = {
|
|
1058
|
+
channel: "stable",
|
|
1059
|
+
code_fingerprint: runtime.code.fingerprint.toLowerCase(),
|
|
1060
|
+
code_origin: "package",
|
|
1061
|
+
...runtime.gitSha ? { git_sha: runtime.gitSha } : {},
|
|
1062
|
+
version: runtime.version
|
|
1063
|
+
};
|
|
1064
|
+
const afterText = `${JSON.stringify({ ...raw, expected_runtime: nextExpectedRuntime }, null, 2)}
|
|
1065
|
+
`;
|
|
1066
|
+
const afterHash = sha256(afterText);
|
|
1067
|
+
const normalizedTargetMatches = previousFingerprint === nextExpectedRuntime.code_fingerprint && previousVersion === nextExpectedRuntime.version && profile.expected_runtime.git_sha === nextExpectedRuntime.git_sha;
|
|
1068
|
+
const newRuntime = upgradeRuntimeIdentity(runtime.code.fingerprint, {
|
|
1069
|
+
codeRoot: executingRoot,
|
|
1070
|
+
gitSha: runtime.gitSha,
|
|
1071
|
+
version: runtime.version
|
|
1072
|
+
});
|
|
1073
|
+
const result = {
|
|
1074
|
+
asset_root: profile.asset_root,
|
|
1075
|
+
changed: !normalizedTargetMatches,
|
|
1076
|
+
database_path: profile.database_path,
|
|
1077
|
+
manifest_after_sha256: normalizedTargetMatches ? beforeHash : afterHash,
|
|
1078
|
+
manifest_before_sha256: beforeHash,
|
|
1079
|
+
manifest_path: manifestPath,
|
|
1080
|
+
new_runtime: newRuntime,
|
|
1081
|
+
post_upgrade_doctor_ok: true,
|
|
1082
|
+
previous_runtime: upgradeRuntimeIdentity(previousFingerprint, {
|
|
1083
|
+
gitSha: profile.expected_runtime.git_sha,
|
|
1084
|
+
version: previousVersion
|
|
1085
|
+
}),
|
|
1086
|
+
profile_fingerprint: profile.profile_fingerprint,
|
|
1087
|
+
profile_id: profile.profile_id,
|
|
1088
|
+
schema_version: lineageProfileRuntimeUpgradeReceiptSchemaVersion,
|
|
1089
|
+
service_origin: profile.service_origin,
|
|
1090
|
+
upgrade_kind: normalizedTargetMatches ? "idempotent" : previousVersion ? "versioned" : "legacy_unversioned"
|
|
1091
|
+
};
|
|
1092
|
+
if (!result.changed) {
|
|
1093
|
+
const doctor = doctorLineageProfile(manifestPath, runtime);
|
|
1094
|
+
if (!doctor.ok) throw new Error("Stable profile runtime upgrade idempotency check did not pass profile doctor");
|
|
1095
|
+
return result;
|
|
1096
|
+
}
|
|
1097
|
+
const operationId = randomUUID();
|
|
1098
|
+
const temporaryPath = join4(profileDirectory, `.profile.runtime-upgrade-${operationId}.tmp`);
|
|
1099
|
+
const rollbackPath = join4(profileDirectory, `.profile.runtime-upgrade-${operationId}.rollback`);
|
|
1100
|
+
let temporaryExists = false;
|
|
1101
|
+
let rollbackExists = false;
|
|
1102
|
+
let published = false;
|
|
1103
|
+
let preserveRollback = false;
|
|
1104
|
+
try {
|
|
1105
|
+
writeFileSync2(temporaryPath, afterText, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
1106
|
+
temporaryExists = true;
|
|
1107
|
+
chmodSync2(temporaryPath, 384);
|
|
1108
|
+
const temporaryFd = openSync(temporaryPath, "r");
|
|
1109
|
+
try {
|
|
1110
|
+
fsyncSync(temporaryFd);
|
|
1111
|
+
} finally {
|
|
1112
|
+
closeSync(temporaryFd);
|
|
1113
|
+
}
|
|
1114
|
+
const preparedReplacement = resolveLineageProfile(temporaryPath);
|
|
1115
|
+
if (runtimeRepinInvariant(preparedReplacement) !== runtimeRepinInvariant(profile)) {
|
|
1116
|
+
throw new Error("Stable profile runtime upgrade would change immutable profile routing identity");
|
|
1117
|
+
}
|
|
1118
|
+
testHooks.beforePublish?.();
|
|
1119
|
+
const currentStats = assertOwnerOnlyPath(manifestPath, "manifest");
|
|
1120
|
+
const currentText = readFileSync3(manifestPath, "utf8");
|
|
1121
|
+
if (!sameFileIdentity(beforeStats, currentStats) || sha256(currentText) !== beforeHash) {
|
|
1122
|
+
throw new Error("Profile manifest changed while stable runtime upgrade was being prepared; refusing replacement");
|
|
1123
|
+
}
|
|
1124
|
+
linkSync(manifestPath, rollbackPath);
|
|
1125
|
+
rollbackExists = true;
|
|
1126
|
+
chmodSync2(rollbackPath, 384);
|
|
1127
|
+
const rollbackStats = assertOwnerOnlyPath(rollbackPath, "manifest");
|
|
1128
|
+
const linkedCurrentStats = assertOwnerOnlyPath(manifestPath, "manifest");
|
|
1129
|
+
if (!sameFileIdentity(rollbackStats, linkedCurrentStats) || readFileSync3(rollbackPath, "utf8") !== beforeText) {
|
|
1130
|
+
throw new Error("Stable profile runtime upgrade could not preserve an exact rollback preimage");
|
|
1131
|
+
}
|
|
1132
|
+
fsyncDirectory(profileDirectory);
|
|
1133
|
+
renameSync(temporaryPath, manifestPath);
|
|
1134
|
+
temporaryExists = false;
|
|
1135
|
+
published = true;
|
|
1136
|
+
fsyncDirectory(profileDirectory);
|
|
1137
|
+
testHooks.afterPublish?.();
|
|
1138
|
+
const replacement = resolveLineageProfile(manifestPath);
|
|
1139
|
+
if (runtimeRepinInvariant(replacement) !== runtimeRepinInvariant(profile)) {
|
|
1140
|
+
throw new Error("Stable profile runtime upgrade changed immutable profile routing identity");
|
|
1141
|
+
}
|
|
1142
|
+
if (readFileSync3(manifestPath, "utf8") !== afterText) {
|
|
1143
|
+
throw new Error("Stable profile runtime upgrade replacement bytes do not match the prepared manifest");
|
|
1144
|
+
}
|
|
1145
|
+
const doctor = doctorLineageProfile(manifestPath, runtime);
|
|
1146
|
+
if (!doctor.ok) {
|
|
1147
|
+
const failures = doctor.checks.filter((check) => check.status === "fail").map((check) => `${check.id}: ${check.message}`).join("; ");
|
|
1148
|
+
throw new Error(`Stable profile runtime upgrade failed post-upgrade profile doctor: ${failures}`);
|
|
1149
|
+
}
|
|
1150
|
+
rmSync(rollbackPath);
|
|
1151
|
+
rollbackExists = false;
|
|
1152
|
+
fsyncDirectory(profileDirectory);
|
|
1153
|
+
return result;
|
|
1154
|
+
} catch (error) {
|
|
1155
|
+
if (published && rollbackExists) {
|
|
1156
|
+
try {
|
|
1157
|
+
if (readFileSync3(manifestPath, "utf8") !== afterText) {
|
|
1158
|
+
throw new Error("published manifest no longer matches the prepared replacement", { cause: error });
|
|
1159
|
+
}
|
|
1160
|
+
renameSync(rollbackPath, manifestPath);
|
|
1161
|
+
rollbackExists = false;
|
|
1162
|
+
fsyncDirectory(profileDirectory);
|
|
1163
|
+
const restoredText = readFileSync3(manifestPath, "utf8");
|
|
1164
|
+
if (restoredText !== beforeText || sha256(restoredText) !== beforeHash) {
|
|
1165
|
+
throw new Error("restored manifest does not match the exact preimage", { cause: error });
|
|
1166
|
+
}
|
|
1167
|
+
} catch (rollbackError) {
|
|
1168
|
+
preserveRollback = true;
|
|
1169
|
+
throw new Error(
|
|
1170
|
+
`Stable profile runtime upgrade failed and automatic rollback could not be proven: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`,
|
|
1171
|
+
{ cause: rollbackError }
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
throw error;
|
|
1176
|
+
} finally {
|
|
1177
|
+
if (temporaryExists) rmSync(temporaryPath, { force: true });
|
|
1178
|
+
if (rollbackExists && !preserveRollback) rmSync(rollbackPath, { force: true });
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
953
1181
|
function repinLineageDevelopmentProfileRuntime(selector, checkoutRoot, runtime, confirmWrite) {
|
|
954
1182
|
if (!confirmWrite) throw new Error("Profile runtime repin requires --confirm-write");
|
|
955
1183
|
if (runtime.channel !== "dev") throw new Error(`Profile runtime repin requires dev code, not ${runtime.channel}`);
|
|
@@ -1824,6 +2052,21 @@ function lineageDb() {
|
|
|
1824
2052
|
where status = 'pending';
|
|
1825
2053
|
create index if not exists asset_reroll_requests_root_status
|
|
1826
2054
|
on asset_reroll_requests(project_id, root_asset_id, status, created_at);
|
|
2055
|
+
create table if not exists asset_social_marks (
|
|
2056
|
+
id text primary key,
|
|
2057
|
+
project_id text not null references projects(id),
|
|
2058
|
+
root_asset_id text not null references assets(id),
|
|
2059
|
+
asset_id text not null references assets(id),
|
|
2060
|
+
notes text,
|
|
2061
|
+
marked_by text not null,
|
|
2062
|
+
marked_at text not null,
|
|
2063
|
+
unmarked_by text,
|
|
2064
|
+
unmarked_at text,
|
|
2065
|
+
updated_at text not null,
|
|
2066
|
+
unique(project_id, root_asset_id, asset_id)
|
|
2067
|
+
);
|
|
2068
|
+
create index if not exists asset_social_marks_root_active
|
|
2069
|
+
on asset_social_marks(project_id, root_asset_id, unmarked_at, marked_at);
|
|
1827
2070
|
create table if not exists asset_reviews (
|
|
1828
2071
|
asset_id text primary key references assets(id),
|
|
1829
2072
|
review_state text not null check (review_state in ('unreviewed', 'approved', 'needs_revision', 'rejected', 'ignored')),
|
|
@@ -2810,7 +3053,7 @@ function validateAgentClaimForWrite(fields) {
|
|
|
2810
3053
|
}
|
|
2811
3054
|
|
|
2812
3055
|
// src/server/assetLineage.ts
|
|
2813
|
-
import { join as join7 } from "node:path";
|
|
3056
|
+
import { isAbsolute as isAbsolute2, join as join7, resolve as resolve5 } from "node:path";
|
|
2814
3057
|
|
|
2815
3058
|
// src/server/assetLineageSelection.ts
|
|
2816
3059
|
function selectedRows(database, project, root) {
|
|
@@ -3515,6 +3758,11 @@ function collectAssets(project, source) {
|
|
|
3515
3758
|
}
|
|
3516
3759
|
return assets;
|
|
3517
3760
|
}
|
|
3761
|
+
function absoluteLocalPath(localPath) {
|
|
3762
|
+
if (!localPath) return void 0;
|
|
3763
|
+
if (isAbsolute2(localPath)) return localPath;
|
|
3764
|
+
return resolve5(repoRoot, ".asset-scratch", localPath);
|
|
3765
|
+
}
|
|
3518
3766
|
function upsertProject(database, project) {
|
|
3519
3767
|
const timestamp = nowIso();
|
|
3520
3768
|
database.prepare(`
|
|
@@ -3910,6 +4158,19 @@ function getLineageSnapshot(project, assetId) {
|
|
|
3910
4158
|
const request = rerollRequestFrom(row);
|
|
3911
4159
|
return [request.node_asset_id, withRerollTask(request, lineageTasksByNode.get(request.node_asset_id)?.reroll)];
|
|
3912
4160
|
}));
|
|
4161
|
+
const hasSocialMarks = database.prepare("select 1 from sqlite_master where type = 'table' and name = 'asset_social_marks'").get() !== void 0;
|
|
4162
|
+
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 (${placeholders})`).all(project, root, ...ids) : [];
|
|
4163
|
+
const socialMarksByNode = new Map(socialMarkRows.map((row) => [String(row.asset_id), {
|
|
4164
|
+
active: true,
|
|
4165
|
+
asset_id: String(row.asset_id),
|
|
4166
|
+
id: String(row.id),
|
|
4167
|
+
marked_at: String(row.marked_at),
|
|
4168
|
+
marked_by: String(row.marked_by),
|
|
4169
|
+
notes: rowString(row.notes),
|
|
4170
|
+
project_id: String(row.project_id),
|
|
4171
|
+
root_asset_id: String(row.root_asset_id),
|
|
4172
|
+
updated_at: String(row.updated_at)
|
|
4173
|
+
}]));
|
|
3913
4174
|
const childIds = new Set(edges.map((edge) => edge.parent_asset_id));
|
|
3914
4175
|
const selectedIds = new Set(selected.map((row) => row.asset_id));
|
|
3915
4176
|
const selections = selected.map((row) => ({
|
|
@@ -3929,6 +4190,7 @@ function getLineageSnapshot(project, assetId) {
|
|
|
3929
4190
|
const lineageTasks = lineageTasksByNode.get(row.asset_id);
|
|
3930
4191
|
return {
|
|
3931
4192
|
...node,
|
|
4193
|
+
absolute_path: absoluteLocalPath(row.local_path),
|
|
3932
4194
|
attempt_count: attempts.length,
|
|
3933
4195
|
current_attempt: currentAttempt,
|
|
3934
4196
|
is_latest: !childIds.has(row.asset_id),
|
|
@@ -3937,6 +4199,7 @@ function getLineageSnapshot(project, assetId) {
|
|
|
3937
4199
|
preview_url: canPreviewLocally(row.media_type, previewPath) ? localPreviewUrl(project, previewPath) : void 0,
|
|
3938
4200
|
reroll_request: rerollsByNode.get(row.asset_id),
|
|
3939
4201
|
selection_note: nodeSelection?.notes,
|
|
4202
|
+
social_mark: socialMarksByNode.get(row.asset_id),
|
|
3940
4203
|
user_selected: selectedIds.has(row.asset_id)
|
|
3941
4204
|
};
|
|
3942
4205
|
});
|
|
@@ -4359,9 +4622,246 @@ function linkSelectedLineageChild(project, fields) {
|
|
|
4359
4622
|
};
|
|
4360
4623
|
}
|
|
4361
4624
|
|
|
4625
|
+
// src/server/assetSocialMarks.ts
|
|
4626
|
+
import { accessSync, constants, existsSync as existsSync8 } from "node:fs";
|
|
4627
|
+
import { isAbsolute as isAbsolute3, resolve as resolve6 } from "node:path";
|
|
4628
|
+
function markFromRow(row) {
|
|
4629
|
+
return {
|
|
4630
|
+
active: row.unmarked_at === null,
|
|
4631
|
+
asset_id: row.asset_id,
|
|
4632
|
+
id: row.id,
|
|
4633
|
+
marked_at: row.marked_at,
|
|
4634
|
+
marked_by: row.marked_by,
|
|
4635
|
+
notes: row.notes || void 0,
|
|
4636
|
+
project_id: row.project_id,
|
|
4637
|
+
root_asset_id: row.root_asset_id,
|
|
4638
|
+
unmarked_at: row.unmarked_at || void 0,
|
|
4639
|
+
unmarked_by: row.unmarked_by || void 0,
|
|
4640
|
+
updated_at: row.updated_at
|
|
4641
|
+
};
|
|
4642
|
+
}
|
|
4643
|
+
function requireCanonicalSnapshot(project, rootAssetId) {
|
|
4644
|
+
const snapshot = getLineageSnapshot(project, rootAssetId);
|
|
4645
|
+
if (snapshot.root_asset_id !== rootAssetId) {
|
|
4646
|
+
throw new LineageError(`Asset ${rootAssetId} is not a canonical lineage canvas root`, 400);
|
|
4647
|
+
}
|
|
4648
|
+
return snapshot;
|
|
4649
|
+
}
|
|
4650
|
+
function resolveVisibleNode(snapshot, asset) {
|
|
4651
|
+
const exactId = snapshot.nodes.find((node) => node.asset_id === asset);
|
|
4652
|
+
if (exactId) return exactId;
|
|
4653
|
+
const title = asset.trim().toLocaleLowerCase();
|
|
4654
|
+
const matches = snapshot.nodes.filter((node) => node.title.trim().toLocaleLowerCase() === title);
|
|
4655
|
+
if (matches.length > 1) throw new LineageError(`Asset title "${asset}" matches multiple visible nodes; use an exact asset ID.`, 409);
|
|
4656
|
+
if (matches.length === 1) return matches[0];
|
|
4657
|
+
throw new LineageError(`Asset ${asset} is not visible in lineage canvas ${snapshot.root_asset_id}`, 404);
|
|
4658
|
+
}
|
|
4659
|
+
function rootChannel(snapshot) {
|
|
4660
|
+
return snapshot.nodes.find((node) => node.asset_id === snapshot.root_asset_id)?.channel;
|
|
4661
|
+
}
|
|
4662
|
+
function requireActor(actor, field) {
|
|
4663
|
+
const normalized = actor.trim();
|
|
4664
|
+
if (!normalized) throw new LineageError(`Social mark ${field} is required`);
|
|
4665
|
+
return normalized;
|
|
4666
|
+
}
|
|
4667
|
+
function socialMarkId(project, rootAssetId, assetId) {
|
|
4668
|
+
return `${project}:${rootAssetId}:social:${assetId}`;
|
|
4669
|
+
}
|
|
4670
|
+
function activeRow(project, rootAssetId, assetId) {
|
|
4671
|
+
const database = lineageDb();
|
|
4672
|
+
try {
|
|
4673
|
+
return database.prepare(`
|
|
4674
|
+
select * from asset_social_marks
|
|
4675
|
+
where project_id = ? and root_asset_id = ? and asset_id = ? and unmarked_at is null
|
|
4676
|
+
`).get(project, rootAssetId, assetId);
|
|
4677
|
+
} finally {
|
|
4678
|
+
database.close();
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4681
|
+
function mutationResponse(project, rootAssetId, active, mark, dryRun) {
|
|
4682
|
+
return {
|
|
4683
|
+
active,
|
|
4684
|
+
...dryRun ? { dryRun } : {},
|
|
4685
|
+
...mark ? { mark } : {},
|
|
4686
|
+
ok: true,
|
|
4687
|
+
snapshot: getLineageSnapshot(project, rootAssetId)
|
|
4688
|
+
};
|
|
4689
|
+
}
|
|
4690
|
+
function markAssetSocial(project, fields) {
|
|
4691
|
+
const snapshot = requireCanonicalSnapshot(project, fields.rootAssetId);
|
|
4692
|
+
const node = resolveVisibleNode(snapshot, fields.asset);
|
|
4693
|
+
const markedBy = requireActor(fields.markedBy, "markedBy");
|
|
4694
|
+
requireLineageWorkspaceClaimForWrite({
|
|
4695
|
+
channel: rootChannel(snapshot),
|
|
4696
|
+
claimToken: fields.claimToken,
|
|
4697
|
+
confirmWrite: fields.confirmWrite,
|
|
4698
|
+
project,
|
|
4699
|
+
rootAssetId: fields.rootAssetId,
|
|
4700
|
+
writeKind: "social_mark"
|
|
4701
|
+
});
|
|
4702
|
+
const existing = activeRow(project, fields.rootAssetId, node.asset_id);
|
|
4703
|
+
if (existing) return mutationResponse(project, fields.rootAssetId, true, markFromRow(existing), fields.confirmWrite ? void 0 : true);
|
|
4704
|
+
const timestamp = nowIso();
|
|
4705
|
+
const preview = {
|
|
4706
|
+
active: true,
|
|
4707
|
+
asset_id: node.asset_id,
|
|
4708
|
+
id: socialMarkId(project, fields.rootAssetId, node.asset_id),
|
|
4709
|
+
marked_at: timestamp,
|
|
4710
|
+
marked_by: markedBy,
|
|
4711
|
+
notes: fields.notes?.trim() || void 0,
|
|
4712
|
+
project_id: project,
|
|
4713
|
+
root_asset_id: fields.rootAssetId,
|
|
4714
|
+
updated_at: timestamp
|
|
4715
|
+
};
|
|
4716
|
+
if (!fields.confirmWrite) return mutationResponse(project, fields.rootAssetId, true, preview, true);
|
|
4717
|
+
const database = lineageDb();
|
|
4718
|
+
try {
|
|
4719
|
+
database.prepare(`
|
|
4720
|
+
insert into asset_social_marks (
|
|
4721
|
+
id, project_id, root_asset_id, asset_id, notes, marked_by, marked_at,
|
|
4722
|
+
unmarked_by, unmarked_at, updated_at
|
|
4723
|
+
) values (?, ?, ?, ?, ?, ?, ?, null, null, ?)
|
|
4724
|
+
on conflict(project_id, root_asset_id, asset_id) do update set
|
|
4725
|
+
notes = excluded.notes,
|
|
4726
|
+
marked_by = excluded.marked_by,
|
|
4727
|
+
marked_at = excluded.marked_at,
|
|
4728
|
+
unmarked_by = null,
|
|
4729
|
+
unmarked_at = null,
|
|
4730
|
+
updated_at = excluded.updated_at
|
|
4731
|
+
`).run(
|
|
4732
|
+
preview.id,
|
|
4733
|
+
project,
|
|
4734
|
+
fields.rootAssetId,
|
|
4735
|
+
node.asset_id,
|
|
4736
|
+
preview.notes || null,
|
|
4737
|
+
markedBy,
|
|
4738
|
+
timestamp,
|
|
4739
|
+
timestamp
|
|
4740
|
+
);
|
|
4741
|
+
} finally {
|
|
4742
|
+
database.close();
|
|
4743
|
+
}
|
|
4744
|
+
return mutationResponse(project, fields.rootAssetId, true, markFromRow(activeRow(project, fields.rootAssetId, node.asset_id)));
|
|
4745
|
+
}
|
|
4746
|
+
function unmarkAssetSocial(project, fields) {
|
|
4747
|
+
const snapshot = requireCanonicalSnapshot(project, fields.rootAssetId);
|
|
4748
|
+
const node = resolveVisibleNode(snapshot, fields.asset);
|
|
4749
|
+
const unmarkedBy = requireActor(fields.unmarkedBy, "unmarkedBy");
|
|
4750
|
+
requireLineageWorkspaceClaimForWrite({
|
|
4751
|
+
channel: rootChannel(snapshot),
|
|
4752
|
+
claimToken: fields.claimToken,
|
|
4753
|
+
confirmWrite: fields.confirmWrite,
|
|
4754
|
+
project,
|
|
4755
|
+
rootAssetId: fields.rootAssetId,
|
|
4756
|
+
writeKind: "social_unmark"
|
|
4757
|
+
});
|
|
4758
|
+
const existing = activeRow(project, fields.rootAssetId, node.asset_id);
|
|
4759
|
+
if (!existing) return mutationResponse(project, fields.rootAssetId, false, void 0, fields.confirmWrite ? void 0 : true);
|
|
4760
|
+
const timestamp = nowIso();
|
|
4761
|
+
const preview = markFromRow({
|
|
4762
|
+
...existing,
|
|
4763
|
+
unmarked_at: timestamp,
|
|
4764
|
+
unmarked_by: unmarkedBy,
|
|
4765
|
+
updated_at: timestamp
|
|
4766
|
+
});
|
|
4767
|
+
if (!fields.confirmWrite) return mutationResponse(project, fields.rootAssetId, false, preview, true);
|
|
4768
|
+
const database = lineageDb();
|
|
4769
|
+
try {
|
|
4770
|
+
database.prepare(`
|
|
4771
|
+
update asset_social_marks
|
|
4772
|
+
set unmarked_by = ?, unmarked_at = ?, updated_at = ?
|
|
4773
|
+
where project_id = ? and root_asset_id = ? and asset_id = ? and unmarked_at is null
|
|
4774
|
+
`).run(unmarkedBy, timestamp, timestamp, project, fields.rootAssetId, node.asset_id);
|
|
4775
|
+
} finally {
|
|
4776
|
+
database.close();
|
|
4777
|
+
}
|
|
4778
|
+
return mutationResponse(project, fields.rootAssetId, false, preview);
|
|
4779
|
+
}
|
|
4780
|
+
function absoluteLocalPath2(reference) {
|
|
4781
|
+
if (!reference) return void 0;
|
|
4782
|
+
if (isAbsolute3(reference)) return reference;
|
|
4783
|
+
const repoRelative = resolve6(repoRoot, reference);
|
|
4784
|
+
return existsSync8(repoRelative) || reference === ".asset-scratch" || reference.startsWith(".asset-scratch/") ? repoRelative : resolve6(repoRoot, ".asset-scratch", reference);
|
|
4785
|
+
}
|
|
4786
|
+
function isReadable(path) {
|
|
4787
|
+
try {
|
|
4788
|
+
accessSync(path, constants.R_OK);
|
|
4789
|
+
return true;
|
|
4790
|
+
} catch {
|
|
4791
|
+
return false;
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
function listItem(project, rootAssetId, node, row) {
|
|
4795
|
+
const relativePath = node.current_attempt?.file_path || node.local_path;
|
|
4796
|
+
const absolutePath = absoluteLocalPath2(relativePath);
|
|
4797
|
+
const exists = absolutePath ? existsSync8(absolutePath) : false;
|
|
4798
|
+
const warnings = [];
|
|
4799
|
+
if (absolutePath && !exists) warnings.push(`Asset ${node.asset_id} local file is missing: ${absolutePath}`);
|
|
4800
|
+
if (absolutePath && exists && !isReadable(absolutePath)) {
|
|
4801
|
+
warnings.push(`Asset ${node.asset_id} local file is unreadable: ${absolutePath}. Check file permissions before handoff.`);
|
|
4802
|
+
}
|
|
4803
|
+
if (!absolutePath && node.s3_key) {
|
|
4804
|
+
warnings.push(`Asset ${node.asset_id} is only available in non-local storage; create a readable local copy before handoff.`);
|
|
4805
|
+
}
|
|
4806
|
+
if (!absolutePath && !node.s3_key) warnings.push(`Asset ${node.asset_id} has no local file or storage key.`);
|
|
4807
|
+
const base = `--project ${shellQuote(project)} --root ${shellQuote(rootAssetId)} --asset ${shellQuote(node.asset_id)}`;
|
|
4808
|
+
return {
|
|
4809
|
+
...markFromRow(row),
|
|
4810
|
+
checksum_sha256: node.current_attempt?.checksum_sha256 || node.checksum_sha256,
|
|
4811
|
+
commands: {
|
|
4812
|
+
mark: lineageCliCommand(`social mark ${base} --confirm-write`),
|
|
4813
|
+
unmark: lineageCliCommand(`social unmark ${base} --confirm-write`)
|
|
4814
|
+
},
|
|
4815
|
+
current_attempt: node.current_attempt,
|
|
4816
|
+
local: {
|
|
4817
|
+
absolute_path: absolutePath,
|
|
4818
|
+
exists,
|
|
4819
|
+
relative_path: relativePath
|
|
4820
|
+
},
|
|
4821
|
+
media_type: node.media_type,
|
|
4822
|
+
s3: node.s3_key ? { key: node.s3_key } : void 0,
|
|
4823
|
+
source: node.source,
|
|
4824
|
+
title: node.title,
|
|
4825
|
+
warnings
|
|
4826
|
+
};
|
|
4827
|
+
}
|
|
4828
|
+
function listAssetSocialMarks(project, rootAssetId) {
|
|
4829
|
+
const snapshot = requireCanonicalSnapshot(project, rootAssetId);
|
|
4830
|
+
const database = lineageDb();
|
|
4831
|
+
let rows;
|
|
4832
|
+
try {
|
|
4833
|
+
const hasSocialMarks = database.prepare("select 1 from sqlite_master where type = 'table' and name = 'asset_social_marks'").get() !== void 0;
|
|
4834
|
+
rows = hasSocialMarks ? database.prepare(`
|
|
4835
|
+
select * from asset_social_marks
|
|
4836
|
+
where project_id = ? and root_asset_id = ? and unmarked_at is null
|
|
4837
|
+
order by marked_at, asset_id
|
|
4838
|
+
`).all(project, rootAssetId) : [];
|
|
4839
|
+
} finally {
|
|
4840
|
+
database.close();
|
|
4841
|
+
}
|
|
4842
|
+
const nodesById = new Map(snapshot.nodes.map((node) => [node.asset_id, node]));
|
|
4843
|
+
return {
|
|
4844
|
+
commands: {
|
|
4845
|
+
mark: lineageCliCommand(`social mark --project ${shellQuote(project)} --root ${shellQuote(rootAssetId)} --asset <asset-id> --confirm-write`)
|
|
4846
|
+
},
|
|
4847
|
+
fetchedAt: nowIso(),
|
|
4848
|
+
marks: rows.flatMap((row) => {
|
|
4849
|
+
const node = nodesById.get(row.asset_id);
|
|
4850
|
+
return node ? [listItem(project, rootAssetId, node, row)] : [];
|
|
4851
|
+
}),
|
|
4852
|
+
project,
|
|
4853
|
+
root_asset_id: rootAssetId,
|
|
4854
|
+
schema_version: "lineage.social_marks.v1",
|
|
4855
|
+
workspace: {
|
|
4856
|
+
id: lineageWorkspaceId(project, rootAssetId),
|
|
4857
|
+
root_asset_id: rootAssetId
|
|
4858
|
+
}
|
|
4859
|
+
};
|
|
4860
|
+
}
|
|
4861
|
+
|
|
4362
4862
|
// src/server/generationReceipts.ts
|
|
4363
|
-
import { existsSync as
|
|
4364
|
-
import { relative as relative3, resolve as
|
|
4863
|
+
import { existsSync as existsSync9, realpathSync as realpathSync2, statSync as statSync4 } from "node:fs";
|
|
4864
|
+
import { relative as relative3, resolve as resolve7 } from "node:path";
|
|
4365
4865
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
4366
4866
|
|
|
4367
4867
|
// src/shared/generationOutputManifest.ts
|
|
@@ -4896,8 +5396,8 @@ function isPathInside(child, parent) {
|
|
|
4896
5396
|
return Boolean(rel) && !rel.startsWith("..") && !rel.startsWith("/");
|
|
4897
5397
|
}
|
|
4898
5398
|
function scratchCandidate(file) {
|
|
4899
|
-
const scratchRoot =
|
|
4900
|
-
const candidate = file.startsWith(".asset-scratch/") ||
|
|
5399
|
+
const scratchRoot = resolve7(repoRoot, ".asset-scratch");
|
|
5400
|
+
const candidate = file.startsWith(".asset-scratch/") || resolve7(file).startsWith(scratchRoot) ? resolve7(repoRoot, file) : resolve7(scratchRoot, file);
|
|
4901
5401
|
if (!isPathInside(candidate, scratchRoot)) throw new GenerationReceiptError(`Import file must be under .asset-scratch: ${file}`);
|
|
4902
5402
|
return { candidate, scratchRoot };
|
|
4903
5403
|
}
|
|
@@ -4907,7 +5407,7 @@ function resolveScratchManifestPath(file) {
|
|
|
4907
5407
|
}
|
|
4908
5408
|
function resolveScratchFile(file) {
|
|
4909
5409
|
const { candidate, scratchRoot } = scratchCandidate(file);
|
|
4910
|
-
if (!
|
|
5410
|
+
if (!existsSync9(candidate)) throw new GenerationReceiptError(`Missing import file: ${file}`, 404);
|
|
4911
5411
|
const realScratchRoot = realpathSync2(scratchRoot);
|
|
4912
5412
|
const realCandidate = realpathSync2(candidate);
|
|
4913
5413
|
if (!isPathInside(realCandidate, realScratchRoot)) throw new GenerationReceiptError(`Import file must be under .asset-scratch: ${file}`);
|
|
@@ -5151,8 +5651,8 @@ function importImageRerollOutput(project = defaultProject, fields) {
|
|
|
5151
5651
|
|
|
5152
5652
|
// src/server/lineageSelectionPacket.ts
|
|
5153
5653
|
import { createHash as createHash5 } from "node:crypto";
|
|
5154
|
-
import { existsSync as
|
|
5155
|
-
import { isAbsolute as
|
|
5654
|
+
import { existsSync as existsSync10, statSync as statSync5 } from "node:fs";
|
|
5655
|
+
import { isAbsolute as isAbsolute4, resolve as resolve8 } from "node:path";
|
|
5156
5656
|
var LineageSelectionPacketError = class extends Error {
|
|
5157
5657
|
constructor(message, warnings = [], errors = [], diagnostics = []) {
|
|
5158
5658
|
super(message);
|
|
@@ -5198,13 +5698,13 @@ function resolveWorkspace(project, options) {
|
|
|
5198
5698
|
}
|
|
5199
5699
|
function resolveLocalReference(reference) {
|
|
5200
5700
|
if (!reference) return void 0;
|
|
5201
|
-
if (
|
|
5202
|
-
const repoRelative =
|
|
5203
|
-
if (
|
|
5204
|
-
return
|
|
5701
|
+
if (isAbsolute4(reference)) return reference;
|
|
5702
|
+
const repoRelative = resolve8(repoRoot, reference);
|
|
5703
|
+
if (existsSync10(repoRelative)) return repoRelative;
|
|
5704
|
+
return resolve8(repoRoot, ".asset-scratch", reference);
|
|
5205
5705
|
}
|
|
5206
5706
|
function fileSize(path) {
|
|
5207
|
-
if (!path || !
|
|
5707
|
+
if (!path || !existsSync10(path)) return void 0;
|
|
5208
5708
|
try {
|
|
5209
5709
|
return statSync5(path).size;
|
|
5210
5710
|
} catch {
|
|
@@ -5232,7 +5732,7 @@ function currentAttemptFor(node) {
|
|
|
5232
5732
|
function assetForNode(node, catalogAsset, warnings) {
|
|
5233
5733
|
const localReference = catalogAsset?.local?.absolute_path || node.current_attempt?.file_path || node.local_path || catalogAsset?.local?.relative_path;
|
|
5234
5734
|
const absolutePath = catalogAsset?.local?.absolute_path || resolveLocalReference(localReference);
|
|
5235
|
-
const localExists = absolutePath ?
|
|
5735
|
+
const localExists = absolutePath ? existsSync10(absolutePath) : false;
|
|
5236
5736
|
const hasLocalClaim = Boolean(absolutePath || node.local_path || catalogAsset?.local?.relative_path);
|
|
5237
5737
|
const s3Key = catalogAsset?.s3?.key || node.s3_key;
|
|
5238
5738
|
const hasS3 = Boolean(s3Key);
|
|
@@ -5389,7 +5889,7 @@ function assetForNodeV2(node, visibleCatalogAsset, catalogById, warnings, errors
|
|
|
5389
5889
|
const mediaCatalogAsset = currentAttemptCatalogAsset || (isVisibleNodeAttempt ? visibleCatalogAsset : void 0);
|
|
5390
5890
|
const localReference = currentAttempt.file_path || mediaCatalogAsset?.local?.absolute_path || mediaCatalogAsset?.local?.relative_path || (isVisibleNodeAttempt ? node.local_path : void 0);
|
|
5391
5891
|
const absolutePath = resolveLocalReference(localReference);
|
|
5392
|
-
const localExists = absolutePath ?
|
|
5892
|
+
const localExists = absolutePath ? existsSync10(absolutePath) : false;
|
|
5393
5893
|
const hasLocalClaim = Boolean(localReference);
|
|
5394
5894
|
const s3Key = mediaCatalogAsset?.s3?.key || (isVisibleNodeAttempt ? node.s3_key : void 0);
|
|
5395
5895
|
const hasS3 = Boolean(s3Key);
|
|
@@ -5655,8 +6155,8 @@ function getLineageSelectionPacket(project, options = {}) {
|
|
|
5655
6155
|
// src/server/runtimeInfo.ts
|
|
5656
6156
|
import { createHash as createHash6 } from "node:crypto";
|
|
5657
6157
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
5658
|
-
import { existsSync as
|
|
5659
|
-
import { dirname as dirname5, isAbsolute as
|
|
6158
|
+
import { existsSync as existsSync11, lstatSync as lstatSync3, readFileSync as readFileSync5, readdirSync as readdirSync3, readlinkSync, realpathSync as realpathSync3, statSync as statSync6 } from "node:fs";
|
|
6159
|
+
import { dirname as dirname5, isAbsolute as isAbsolute5, join as join9, resolve as resolve9 } from "node:path";
|
|
5660
6160
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5661
6161
|
|
|
5662
6162
|
// src/shared/runtimeInfoTypes.ts
|
|
@@ -5675,7 +6175,7 @@ function isLineagePackageRoot(root) {
|
|
|
5675
6175
|
}
|
|
5676
6176
|
function executingCodeRoot() {
|
|
5677
6177
|
const moduleDirectory = dirname5(fileURLToPath2(import.meta.url));
|
|
5678
|
-
const candidates = [
|
|
6178
|
+
const candidates = [resolve9(moduleDirectory, "../.."), resolve9(moduleDirectory, "..")];
|
|
5679
6179
|
const root = candidates.find(isLineagePackageRoot);
|
|
5680
6180
|
if (!root) throw new Error(`Unable to derive Lineage code root from executing module ${fileURLToPath2(import.meta.url)}`);
|
|
5681
6181
|
return canonicalRoot(root);
|
|
@@ -5688,7 +6188,7 @@ function canonicalRoot(root) {
|
|
|
5688
6188
|
try {
|
|
5689
6189
|
return realpathSync3(root);
|
|
5690
6190
|
} catch {
|
|
5691
|
-
return
|
|
6191
|
+
return resolve9(root);
|
|
5692
6192
|
}
|
|
5693
6193
|
}
|
|
5694
6194
|
function packageInfo(root = codeRoot) {
|
|
@@ -5788,7 +6288,7 @@ function readInstallReceipt(path, errors) {
|
|
|
5788
6288
|
return void 0;
|
|
5789
6289
|
}
|
|
5790
6290
|
let receipt;
|
|
5791
|
-
const receiptPath =
|
|
6291
|
+
const receiptPath = resolve9(path);
|
|
5792
6292
|
try {
|
|
5793
6293
|
receipt = JSON.parse(readFileSync5(receiptPath, "utf8"));
|
|
5794
6294
|
} catch (error) {
|
|
@@ -5796,7 +6296,7 @@ function readInstallReceipt(path, errors) {
|
|
|
5796
6296
|
return void 0;
|
|
5797
6297
|
}
|
|
5798
6298
|
if (receipt.schema_version !== lineageRuntimeInstallSchemaVersion) errors.push(`Unsupported runtime install receipt schema: ${String(receipt.schema_version)}`);
|
|
5799
|
-
if (!
|
|
6299
|
+
if (!isAbsolute5(receipt.package_root || "")) errors.push("Runtime install receipt package_root must be absolute");
|
|
5800
6300
|
if (!receipt.package_integrity?.startsWith("sha512-")) errors.push("Runtime install receipt package integrity is invalid");
|
|
5801
6301
|
if (receipt.package_source !== "registry" && receipt.package_source !== "local") errors.push("Runtime install receipt package source is invalid");
|
|
5802
6302
|
if (typeof receipt.package_spec !== "string" || !receipt.package_spec) errors.push("Runtime install receipt package spec is invalid");
|
|
@@ -5877,8 +6377,8 @@ function packageCodeIdentity(root, channel, info, receiptPath) {
|
|
|
5877
6377
|
function getLineageCodeIdentity(channel, options = {}) {
|
|
5878
6378
|
const root = canonicalRoot(options.root || codeRoot);
|
|
5879
6379
|
const info = packageInfo(root);
|
|
5880
|
-
if (
|
|
5881
|
-
if (
|
|
6380
|
+
if (existsSync11(join9(root, ".git"))) return checkoutCodeIdentity(root, channel, info.version);
|
|
6381
|
+
if (existsSync11(join9(root, "package.json"))) {
|
|
5882
6382
|
return packageCodeIdentity(root, channel, info, options.receiptPath ?? process.env.LINEAGE_RUNTIME_RECEIPT);
|
|
5883
6383
|
}
|
|
5884
6384
|
const errors = [`Code root has neither checkout metadata nor package.json: ${root}`];
|
|
@@ -5917,7 +6417,7 @@ function getLineageRuntimeInfo(options = {}) {
|
|
|
5917
6417
|
const dbPath = options.dbPath || lineageDbPath();
|
|
5918
6418
|
const channel = normalizeRuntimeChannel(options.channel || process.env.LINEAGE_CHANNEL || process.env.LINEAGE_RELEASE_CHANNEL);
|
|
5919
6419
|
const code = options.code || getLineageCodeIdentity(channel);
|
|
5920
|
-
const databaseInfo = { exists:
|
|
6420
|
+
const databaseInfo = { exists: existsSync11(dbPath), path: dbPath };
|
|
5921
6421
|
const schema = { migration_keys: [] };
|
|
5922
6422
|
const serviceInstanceId = process.env.LINEAGE_SERVICE_INSTANCE_ID;
|
|
5923
6423
|
const launcherPid = process.env.LINEAGE_LAUNCHER_PID ? Number(process.env.LINEAGE_LAUNCHER_PID) : void 0;
|
|
@@ -6074,7 +6574,7 @@ var signalExitCodes = {
|
|
|
6074
6574
|
SIGTERM: 143
|
|
6075
6575
|
};
|
|
6076
6576
|
function packageRoot2() {
|
|
6077
|
-
return
|
|
6577
|
+
return resolve10(dirname6(fileURLToPath3(import.meta.url)), "..", "..");
|
|
6078
6578
|
}
|
|
6079
6579
|
function packageVersion() {
|
|
6080
6580
|
try {
|
|
@@ -6113,7 +6613,7 @@ function readOptions(args, name) {
|
|
|
6113
6613
|
}
|
|
6114
6614
|
function readJsonFile(path, label) {
|
|
6115
6615
|
try {
|
|
6116
|
-
return JSON.parse(readFileSync6(
|
|
6616
|
+
return JSON.parse(readFileSync6(resolve10(path), "utf8"));
|
|
6117
6617
|
} catch (error) {
|
|
6118
6618
|
throw new Error(`${label} must be a readable JSON file: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
6119
6619
|
}
|
|
@@ -6157,7 +6657,7 @@ function resolveStartOptions(config, args) {
|
|
|
6157
6657
|
};
|
|
6158
6658
|
}
|
|
6159
6659
|
function resolveCliAssetRoot(args) {
|
|
6160
|
-
return
|
|
6660
|
+
return resolve10(readOption(args, "--asset-root") || process.env.LINEAGE_ASSET_ROOT || packageRoot);
|
|
6161
6661
|
}
|
|
6162
6662
|
function configureCliAssetRoot(args) {
|
|
6163
6663
|
const assetRoot = resolveCliAssetRoot(args);
|
|
@@ -6189,10 +6689,10 @@ function prepareCliProfile(config, args) {
|
|
|
6189
6689
|
if (hasOption(args, "--db")) throw new Error("A named profile cannot be combined with --db");
|
|
6190
6690
|
if (hasOption(args, "--asset-root")) throw new Error("A named profile cannot be combined with --asset-root");
|
|
6191
6691
|
const profile = resolveLineageProfile(selector);
|
|
6192
|
-
if (process.env.LINEAGE_DB &&
|
|
6692
|
+
if (process.env.LINEAGE_DB && resolve10(process.env.LINEAGE_DB) !== profile.database_path) {
|
|
6193
6693
|
throw new Error(`Profile ${profile.profile_id} database_path conflicts with LINEAGE_DB`);
|
|
6194
6694
|
}
|
|
6195
|
-
if (process.env.LINEAGE_ASSET_ROOT &&
|
|
6695
|
+
if (process.env.LINEAGE_ASSET_ROOT && resolve10(process.env.LINEAGE_ASSET_ROOT) !== profile.asset_root) {
|
|
6196
6696
|
throw new Error(`Profile ${profile.profile_id} asset_root conflicts with LINEAGE_ASSET_ROOT`);
|
|
6197
6697
|
}
|
|
6198
6698
|
assertProfileChannel(profile, config.channel);
|
|
@@ -6221,6 +6721,7 @@ Usage:
|
|
|
6221
6721
|
${config.binName} profile clone --source-db <snapshot-source> --target-profile <id-or-manifest> --confirm-write [--json]
|
|
6222
6722
|
${config.binName} profile clone-assets --source-asset-root <path> --target-profile <id-or-manifest> --confirm-write [--json]
|
|
6223
6723
|
${config.binName} profile repin-runtime --profile <development-profile> --checkout-root <path> --confirm-write [--json]
|
|
6724
|
+
${config.binName} profile upgrade-runtime --profile <production-profile> --confirm-write [--json]
|
|
6224
6725
|
${config.binName} runtime info [--json]
|
|
6225
6726
|
${config.binName} runtime doctor [--json]
|
|
6226
6727
|
${config.binName} next [--project <project>] [--root <asset-id>] [--db <path>] [--json]
|
|
@@ -6237,6 +6738,9 @@ Usage:
|
|
|
6237
6738
|
${config.binName} reroll cancel --root <asset-id> --target <asset-id> [--project <project>] [--confirm-write] [--db <path>] [--json]
|
|
6238
6739
|
${config.binName} reroll plan --root <asset-id> --target <asset-id> --prompt <text> [--project <project>] [--db <path>] [--json]
|
|
6239
6740
|
${config.binName} reroll import --job-id <job-id> --file <scratch-file> --confirm-write [--project <project>] [--db <path>] [--json]
|
|
6741
|
+
${config.binName} social list --project <project> --root <asset-id> [--db <path>] [--json]
|
|
6742
|
+
${config.binName} social mark --project <project> --root <asset-id> --asset <asset-id-or-exact-title> --confirm-write [--actor <actor>] [--notes <text>] [--claim-token <claim-id.secret>] [--db <path>] [--json]
|
|
6743
|
+
${config.binName} social unmark --project <project> --root <asset-id> --asset <asset-id-or-exact-title> --confirm-write [--actor <actor>] [--claim-token <claim-id.secret>] [--db <path>] [--json]
|
|
6240
6744
|
${config.binName} tasks list --root <asset-id> [--project <project>] [--db <path>] [--json]
|
|
6241
6745
|
${config.binName} tasks inspect --task <task-id> [--project <project>] [--db <path>] [--json]
|
|
6242
6746
|
${config.binName} tasks claim --task <task-id> --agent-name <name> [--project <project>] [--db <path>] [--json]
|
|
@@ -6293,7 +6797,7 @@ function lineageServiceIdentityErrors(runtime, expected) {
|
|
|
6293
6797
|
if (runtime.channel !== expected.channel) errors.push(`channel ${runtime.channel} != ${expected.channel}`);
|
|
6294
6798
|
if (!runtime.code?.verified) errors.push("service code identity is not verified");
|
|
6295
6799
|
if (runtime.code?.fingerprint !== expected.code_fingerprint) errors.push(`code fingerprint ${runtime.code?.fingerprint || "missing"} != ${expected.code_fingerprint}`);
|
|
6296
|
-
if (
|
|
6800
|
+
if (resolve10(runtime.database.path) !== resolve10(expected.database_path)) errors.push(`database ${runtime.database.path} != ${expected.database_path}`);
|
|
6297
6801
|
if (runtime.service?.instance_id !== expected.instance_id) errors.push(`service instance ${runtime.service?.instance_id || "missing"} != ${expected.instance_id}`);
|
|
6298
6802
|
if (runtime.service?.launcher_pid !== expected.launcher_pid) errors.push(`launcher pid ${runtime.service?.launcher_pid || "missing"} != ${expected.launcher_pid}`);
|
|
6299
6803
|
if (expected.profile) {
|
|
@@ -6388,7 +6892,7 @@ function runLineageDataCommand(command, args) {
|
|
|
6388
6892
|
});
|
|
6389
6893
|
const out = readOption(args, "--out");
|
|
6390
6894
|
if (out) {
|
|
6391
|
-
const outPath =
|
|
6895
|
+
const outPath = resolve10(out);
|
|
6392
6896
|
mkdirSync6(dirname6(outPath), { recursive: true });
|
|
6393
6897
|
writeFileSync4(outPath, `${JSON.stringify(packet, null, 2)}
|
|
6394
6898
|
`);
|
|
@@ -6499,6 +7003,35 @@ function runLineageDataCommand(command, args) {
|
|
|
6499
7003
|
}
|
|
6500
7004
|
throw new Error(`Unknown reroll command: ${subcommand}`);
|
|
6501
7005
|
}
|
|
7006
|
+
if (command === "social") {
|
|
7007
|
+
const subcommand = positionalArgs(args)[0] || "";
|
|
7008
|
+
const explicitProject = readOption(args, "--project");
|
|
7009
|
+
const asset = readOption(args, "--asset");
|
|
7010
|
+
if (!explicitProject) throw new Error(`lineage social ${subcommand || "command"} requires --project`);
|
|
7011
|
+
if (!options.rootAssetId) throw new Error(`lineage social ${subcommand || "command"} requires --root`);
|
|
7012
|
+
if (subcommand === "list") return listAssetSocialMarks(explicitProject, options.rootAssetId);
|
|
7013
|
+
if (!asset) throw new Error(`lineage social ${subcommand || "command"} requires --asset`);
|
|
7014
|
+
if (subcommand === "mark") {
|
|
7015
|
+
return markAssetSocial(explicitProject, {
|
|
7016
|
+
asset,
|
|
7017
|
+
claimToken: options.claimToken,
|
|
7018
|
+
confirmWrite: options.confirmWrite,
|
|
7019
|
+
markedBy: readOption(args, "--actor") || "agent",
|
|
7020
|
+
notes: readOption(args, "--notes"),
|
|
7021
|
+
rootAssetId: options.rootAssetId
|
|
7022
|
+
});
|
|
7023
|
+
}
|
|
7024
|
+
if (subcommand === "unmark") {
|
|
7025
|
+
return unmarkAssetSocial(explicitProject, {
|
|
7026
|
+
asset,
|
|
7027
|
+
claimToken: options.claimToken,
|
|
7028
|
+
confirmWrite: options.confirmWrite,
|
|
7029
|
+
rootAssetId: options.rootAssetId,
|
|
7030
|
+
unmarkedBy: readOption(args, "--actor") || "agent"
|
|
7031
|
+
});
|
|
7032
|
+
}
|
|
7033
|
+
throw new Error(`Unknown social command: ${subcommand}`);
|
|
7034
|
+
}
|
|
6502
7035
|
if (command === "tasks") {
|
|
6503
7036
|
const subcommand = positionalArgs(args)[0] || "";
|
|
6504
7037
|
const taskId = readOption(args, "--task");
|
|
@@ -6628,6 +7161,20 @@ function printDataResult(command, result, json) {
|
|
|
6628
7161
|
return;
|
|
6629
7162
|
}
|
|
6630
7163
|
}
|
|
7164
|
+
if (command === "social" && result && typeof result === "object") {
|
|
7165
|
+
if ("marks" in result) {
|
|
7166
|
+
const listed = result;
|
|
7167
|
+
console.log(`${listed.marks.length} social-marked asset(s)`);
|
|
7168
|
+
for (const mark of listed.marks) {
|
|
7169
|
+
console.log(`${mark.asset_id}: ${mark.title}`);
|
|
7170
|
+
for (const warning of mark.warnings || []) console.log(`Warning: ${warning}`);
|
|
7171
|
+
}
|
|
7172
|
+
return;
|
|
7173
|
+
}
|
|
7174
|
+
const mutation = result;
|
|
7175
|
+
console.log(`${mutation.dryRun ? "Dry run: " : ""}${mutation.active ? "Marked" : "Unmarked"} ${mutation.mark?.asset_id || "asset"} for social`);
|
|
7176
|
+
return;
|
|
7177
|
+
}
|
|
6631
7178
|
if (command === "tasks" && result && typeof result === "object") {
|
|
6632
7179
|
if ("tasks" in result) {
|
|
6633
7180
|
const listed = result;
|
|
@@ -6716,6 +7263,30 @@ function runLineageProfileCommand(config, command, args) {
|
|
|
6716
7263
|
writerLease.release();
|
|
6717
7264
|
}
|
|
6718
7265
|
}
|
|
7266
|
+
if (command === "upgrade-runtime") {
|
|
7267
|
+
if (!args.includes("--confirm-write")) throw new Error("Profile runtime upgrade requires --confirm-write");
|
|
7268
|
+
for (const option of [
|
|
7269
|
+
"--checkout-root",
|
|
7270
|
+
"--code-fingerprint",
|
|
7271
|
+
"--code-root",
|
|
7272
|
+
"--from-code-fingerprint",
|
|
7273
|
+
"--git-sha",
|
|
7274
|
+
"--runtime-receipt",
|
|
7275
|
+
"--runtime-root",
|
|
7276
|
+
"--to-code-fingerprint",
|
|
7277
|
+
"--to-version",
|
|
7278
|
+
"--version"
|
|
7279
|
+
]) {
|
|
7280
|
+
if (hasOption(args, option)) throw new Error(`Profile runtime upgrade derives its target from the executing stable package and does not accept ${option}`);
|
|
7281
|
+
}
|
|
7282
|
+
const profile = resolveLineageProfile(selector);
|
|
7283
|
+
const writerLease = acquireProfileWriterLease(profile, config.channel, "cli");
|
|
7284
|
+
try {
|
|
7285
|
+
return upgradeLineageStableProfileRuntime(selector, runtimeIdentity, true);
|
|
7286
|
+
} finally {
|
|
7287
|
+
writerLease.release();
|
|
7288
|
+
}
|
|
7289
|
+
}
|
|
6719
7290
|
if (command === "bind") {
|
|
6720
7291
|
if (!args.includes("--confirm-write")) throw new Error("Profile bind requires --confirm-write");
|
|
6721
7292
|
const profile = resolveLineageProfile(selector);
|
|
@@ -6747,6 +7318,9 @@ function printProfileResult(result, json) {
|
|
|
6747
7318
|
} else if (result.schema_version === "lineage.profile_runtime_repin_receipt.v1") {
|
|
6748
7319
|
console.log(`${result.changed ? "Repinned" : "Already pinned"} ${result.profile_id} to checkout ${result.checkout_root}`);
|
|
6749
7320
|
console.log(`Code fingerprint: ${result.new_code_fingerprint}`);
|
|
7321
|
+
} else if (result.schema_version === "lineage.profile_runtime_upgrade_receipt.v1") {
|
|
7322
|
+
console.log(`${result.changed ? "Upgraded" : "Already pinned"} ${result.profile_id} to stable ${result.new_runtime.version}`);
|
|
7323
|
+
console.log(`Code fingerprint: ${result.new_runtime.code_fingerprint}`);
|
|
6750
7324
|
} else {
|
|
6751
7325
|
console.log(`Cloned ${result.files_copied} referenced asset file(s) into ${result.asset_root}`);
|
|
6752
7326
|
console.log(`Receipt: ${result.receipt_path}`);
|
|
@@ -6781,6 +7355,7 @@ function lineageCliRequiresWriterLease(command, args) {
|
|
|
6781
7355
|
const subcommand = positions[0] || "";
|
|
6782
7356
|
if (command === "generate") return positions[0] !== "image" || positions[1] !== "inspect";
|
|
6783
7357
|
if (command === "reroll") return subcommand !== "list";
|
|
7358
|
+
if (command === "social") return subcommand !== "list";
|
|
6784
7359
|
if (command === "tasks") return subcommand !== "list" && subcommand !== "inspect";
|
|
6785
7360
|
if (command === "db") return subcommand !== "info";
|
|
6786
7361
|
if (command === "agent") return subcommand !== "status" && subcommand !== "graph" && subcommand !== "inspect";
|
|
@@ -6954,7 +7529,7 @@ function start(config, args) {
|
|
|
6954
7529
|
process.exit(1);
|
|
6955
7530
|
}
|
|
6956
7531
|
const serverPath = join10(packageRoot2(), "dist", "server.js");
|
|
6957
|
-
if (!
|
|
7532
|
+
if (!existsSync12(serverPath)) {
|
|
6958
7533
|
const message = `Missing bundled server at ${serverPath}. Run npm run build before using ${config.binName} start from a source checkout.`;
|
|
6959
7534
|
if (options.json) console.error(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
6960
7535
|
else console.error(`${config.binName}: ${message}`);
|
|
@@ -7118,7 +7693,7 @@ async function runLineageCli(config, args = process.argv.slice(2)) {
|
|
|
7118
7693
|
else console.error(`${config.binName}: ${message2}`);
|
|
7119
7694
|
process.exit(1);
|
|
7120
7695
|
}
|
|
7121
|
-
if (command === "next" || command === "brief" || command === "inspect" || command === "selection" || command === "link-child" || command === "generate" || command === "reroll" || command === "tasks") {
|
|
7696
|
+
if (command === "next" || command === "brief" || command === "inspect" || command === "selection" || command === "link-child" || command === "generate" || command === "reroll" || command === "social" || command === "tasks") {
|
|
7122
7697
|
const commandArgs = normalizedArgs.slice(1);
|
|
7123
7698
|
const json2 = commandArgs.includes("--json");
|
|
7124
7699
|
try {
|