@mean-weasel/lineage 0.1.7 → 0.1.8
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 +7 -0
- package/README.md +14 -0
- package/dist/cli/lineage-dev.js +308 -5
- package/dist/cli/lineage-dev.js.map +4 -4
- package/dist/cli/lineage.js +308 -5
- package/dist/cli/lineage.js.map +4 -4
- package/dist/web/assets/index-BplMjJB9.css +1 -0
- package/dist/web/assets/index-ClSbabxx.js +23 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-38XlcMya.css +0 -1
- package/dist/web/assets/index-CtsYIUyG.js +0 -23
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.8
|
|
4
|
+
|
|
5
|
+
- Add durable selection packet export so agents can hand selected Lineage assets to GrowthOps without scraping UI state or copying local paths.
|
|
6
|
+
- Add Agent OS adoption guidance for Lineage agents and operators.
|
|
7
|
+
- Improve popover media previews, node actions, and image expansion controls for faster asset inspection.
|
|
8
|
+
- Clean up the Lineage shell navigation, toolbar, and side-panel layout for a more focused workspace.
|
|
9
|
+
|
|
3
10
|
## 0.1.7
|
|
4
11
|
|
|
5
12
|
- Add a claim-aware lineage task queue for per-image iteration and re-roll work, including task instructions, comments, cancellation, and human override controls.
|
package/README.md
CHANGED
|
@@ -60,6 +60,20 @@ Agents can inspect the current lineage graph without a claim:
|
|
|
60
60
|
lineage agent graph --project demo-project --root <root-asset-id> --json
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
Agents can also export the current active workspace selection as a durable JSON
|
|
64
|
+
packet for downstream tools such as GrowthOps:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
lineage selection packet --project demo-project --channel linkedin --campaign 2026-07-launch --out ./lineage-selection-packet.json --json
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The packet is schema-versioned as `lineage.selection_packet.v1` and includes the
|
|
71
|
+
workspace/root binding, selected asset IDs, local media paths when known, S3 key
|
|
72
|
+
metadata when known, context labels/notes, warnings, and a stable `packet_id`.
|
|
73
|
+
Lineage only exports the packet. GrowthOps or another downstream tool remains
|
|
74
|
+
responsible for importing it, creating posts, checking media readiness, preparing
|
|
75
|
+
public URLs, scheduling, and recording placement receipts.
|
|
76
|
+
|
|
63
77
|
Keep the claim fresh and pass it to mutating commands:
|
|
64
78
|
|
|
65
79
|
```bash
|
package/dist/cli/lineage-dev.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/lineageCli.ts
|
|
4
|
-
import { existsSync as
|
|
4
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
5
5
|
import { homedir, platform } from "node:os";
|
|
6
|
-
import { dirname as dirname3, join as join6, resolve as
|
|
6
|
+
import { dirname as dirname3, join as join6, resolve as resolve5 } from "node:path";
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
8
8
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
9
9
|
|
|
@@ -328,6 +328,13 @@ function catalogPath(project = defaultProject) {
|
|
|
328
328
|
function fixtureCatalogPath(project = defaultProject) {
|
|
329
329
|
return join3(repoRoot, "fixtures", cleanProject(project), "assets", "catalog.json");
|
|
330
330
|
}
|
|
331
|
+
function resolvedCatalogPath(project = defaultProject) {
|
|
332
|
+
const path = catalogPath(project);
|
|
333
|
+
if (existsSync3(path)) return path;
|
|
334
|
+
const clean = cleanProject(project);
|
|
335
|
+
if (clean === defaultProject && existsSync3(fixtureCatalogPath(clean))) return fixtureCatalogPath(clean);
|
|
336
|
+
return path;
|
|
337
|
+
}
|
|
331
338
|
function normalizeCatalog(catalog, fallbackProject = defaultProject) {
|
|
332
339
|
const project = cleanProject(catalog.project || catalog.product || fallbackProject);
|
|
333
340
|
const product = catalog.product || project;
|
|
@@ -570,6 +577,10 @@ function listAssets(project = defaultProject, options = {}) {
|
|
|
570
577
|
error
|
|
571
578
|
};
|
|
572
579
|
}
|
|
580
|
+
function validateProject(project = defaultProject) {
|
|
581
|
+
const catalog = loadCatalog(project);
|
|
582
|
+
return { project: catalog.project, product: catalog.product, catalogPath: resolvedCatalogPath(project), default_bucket: catalog.default_bucket, default_region: catalog.default_region, asset_count: catalog.assets.length };
|
|
583
|
+
}
|
|
573
584
|
|
|
574
585
|
// src/server/assetLineageDb.ts
|
|
575
586
|
var require2 = createRequire(import.meta.url);
|
|
@@ -2223,6 +2234,17 @@ function seedLegacyWorkspaces(database, project) {
|
|
|
2223
2234
|
);
|
|
2224
2235
|
}
|
|
2225
2236
|
}
|
|
2237
|
+
function listRows(database, project) {
|
|
2238
|
+
return database.prepare(`
|
|
2239
|
+
select * from lineage_workspaces
|
|
2240
|
+
where project_id = ?
|
|
2241
|
+
order by
|
|
2242
|
+
case status when 'active' then 0 when 'paused' then 1 else 2 end,
|
|
2243
|
+
active_at desc nulls last,
|
|
2244
|
+
updated_at desc,
|
|
2245
|
+
title
|
|
2246
|
+
`).all(project).map(rowToWorkspace);
|
|
2247
|
+
}
|
|
2226
2248
|
function activeWorkspace(database, project) {
|
|
2227
2249
|
const row = database.prepare(`
|
|
2228
2250
|
select * from lineage_workspaces
|
|
@@ -2232,6 +2254,20 @@ function activeWorkspace(database, project) {
|
|
|
2232
2254
|
`).get(project);
|
|
2233
2255
|
return row ? rowToWorkspace(row) : null;
|
|
2234
2256
|
}
|
|
2257
|
+
function listLineageWorkspaces(project) {
|
|
2258
|
+
const database = lineageDb();
|
|
2259
|
+
try {
|
|
2260
|
+
seedLegacyWorkspaces(database, project);
|
|
2261
|
+
return {
|
|
2262
|
+
project,
|
|
2263
|
+
active_workspace: activeWorkspace(database, project),
|
|
2264
|
+
workspaces: listRows(database, project),
|
|
2265
|
+
fetchedAt: nowIso()
|
|
2266
|
+
};
|
|
2267
|
+
} finally {
|
|
2268
|
+
database.close();
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2235
2271
|
function activeLineageWorkspaceRoot(project) {
|
|
2236
2272
|
const database = lineageDb();
|
|
2237
2273
|
try {
|
|
@@ -3336,13 +3372,234 @@ function importImageRerollOutput(project = defaultProject, fields) {
|
|
|
3336
3372
|
}
|
|
3337
3373
|
}
|
|
3338
3374
|
|
|
3375
|
+
// src/server/lineageSelectionPacket.ts
|
|
3376
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
3377
|
+
import { existsSync as existsSync5, statSync as statSync4 } from "node:fs";
|
|
3378
|
+
import { isAbsolute, resolve as resolve4 } from "node:path";
|
|
3379
|
+
var LineageSelectionPacketError = class extends Error {
|
|
3380
|
+
constructor(message, warnings = [], errors = []) {
|
|
3381
|
+
super(message);
|
|
3382
|
+
this.warnings = warnings;
|
|
3383
|
+
this.errors = errors;
|
|
3384
|
+
}
|
|
3385
|
+
warnings;
|
|
3386
|
+
errors;
|
|
3387
|
+
};
|
|
3388
|
+
function listAllAssets(project) {
|
|
3389
|
+
const pageSize = 100;
|
|
3390
|
+
const first = listAssets(project, { page: 1, pageSize, source: "all" });
|
|
3391
|
+
const assets = [...first.assets];
|
|
3392
|
+
for (let page = 2; page <= first.pagination.totalPages; page += 1) {
|
|
3393
|
+
assets.push(...listAssets(project, { page, pageSize, source: "all" }).assets);
|
|
3394
|
+
}
|
|
3395
|
+
return assets;
|
|
3396
|
+
}
|
|
3397
|
+
function resolveWorkspace(project, options) {
|
|
3398
|
+
if (options.rootAssetId && options.workspaceId) {
|
|
3399
|
+
throw new LineageSelectionPacketError("Use either --root or --workspace, not both.", [], ["ambiguous_workspace"]);
|
|
3400
|
+
}
|
|
3401
|
+
const snapshot = listLineageWorkspaces(project);
|
|
3402
|
+
const target = options.workspaceId || options.rootAssetId;
|
|
3403
|
+
const workspace = target ? snapshot.workspaces.find((item) => item.id === target || item.root_asset_id === target) : snapshot.active_workspace;
|
|
3404
|
+
if (workspace) return workspace;
|
|
3405
|
+
if (options.rootAssetId) {
|
|
3406
|
+
return {
|
|
3407
|
+
id: lineageWorkspaceId(project, options.rootAssetId),
|
|
3408
|
+
project,
|
|
3409
|
+
root_asset_id: options.rootAssetId,
|
|
3410
|
+
title: `${options.rootAssetId} lineage`,
|
|
3411
|
+
status: "active",
|
|
3412
|
+
created_by: "system",
|
|
3413
|
+
created_at: "",
|
|
3414
|
+
updated_at: ""
|
|
3415
|
+
};
|
|
3416
|
+
}
|
|
3417
|
+
const message = options.workspaceId ? `Unknown lineage workspace: ${options.workspaceId}` : "No active lineage workspace. Pass --root or activate a workspace first.";
|
|
3418
|
+
throw new LineageSelectionPacketError(message, [], [options.workspaceId ? "unknown_workspace" : "missing_active_workspace"]);
|
|
3419
|
+
}
|
|
3420
|
+
function resolveLocalReference(reference) {
|
|
3421
|
+
if (!reference) return void 0;
|
|
3422
|
+
if (isAbsolute(reference)) return reference;
|
|
3423
|
+
const repoRelative = resolve4(repoRoot, reference);
|
|
3424
|
+
if (existsSync5(repoRelative)) return repoRelative;
|
|
3425
|
+
return resolve4(repoRoot, ".asset-scratch", reference);
|
|
3426
|
+
}
|
|
3427
|
+
function fileSize(path) {
|
|
3428
|
+
if (!path || !existsSync5(path)) return void 0;
|
|
3429
|
+
try {
|
|
3430
|
+
return statSync4(path).size;
|
|
3431
|
+
} catch {
|
|
3432
|
+
return void 0;
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
function storageState(hasLocal, hasS3) {
|
|
3436
|
+
if (hasLocal && hasS3) return "local_and_s3";
|
|
3437
|
+
if (hasLocal) return "local_only";
|
|
3438
|
+
if (hasS3) return "s3_backed";
|
|
3439
|
+
return "unresolved";
|
|
3440
|
+
}
|
|
3441
|
+
function currentAttemptFor(node) {
|
|
3442
|
+
if (!node.current_attempt) return void 0;
|
|
3443
|
+
return {
|
|
3444
|
+
asset_id: node.current_attempt.asset_id,
|
|
3445
|
+
checksum_sha256: node.current_attempt.checksum_sha256,
|
|
3446
|
+
file_path: node.current_attempt.file_path,
|
|
3447
|
+
generation_job_id: node.current_attempt.generation_job_id,
|
|
3448
|
+
id: node.current_attempt.id,
|
|
3449
|
+
is_current: node.current_attempt.is_current,
|
|
3450
|
+
source: node.current_attempt.source
|
|
3451
|
+
};
|
|
3452
|
+
}
|
|
3453
|
+
function assetForNode(node, catalogAsset, warnings) {
|
|
3454
|
+
const localReference = catalogAsset?.local?.absolute_path || node.current_attempt?.file_path || node.local_path || catalogAsset?.local?.relative_path;
|
|
3455
|
+
const absolutePath = catalogAsset?.local?.absolute_path || resolveLocalReference(localReference);
|
|
3456
|
+
const localExists = absolutePath ? existsSync5(absolutePath) : false;
|
|
3457
|
+
const hasLocalClaim = Boolean(absolutePath || node.local_path || catalogAsset?.local?.relative_path);
|
|
3458
|
+
const s3Key = catalogAsset?.s3?.key || node.s3_key;
|
|
3459
|
+
const hasS3 = Boolean(s3Key);
|
|
3460
|
+
const checksum = catalogAsset?.local?.checksum_sha256 || node.current_attempt?.checksum_sha256 || node.checksum_sha256 || catalogAsset?.s3?.checksum_sha256;
|
|
3461
|
+
const mimeType = catalogAsset?.local?.content_type || catalogAsset?.s3?.content_type;
|
|
3462
|
+
const mediaType = catalogAsset?.content_type || node.media_type;
|
|
3463
|
+
if (hasLocalClaim && !localExists) warnings.push(`Selected asset ${node.asset_id} has a local path but the file is missing: ${absolutePath || node.local_path}`);
|
|
3464
|
+
if (!hasLocalClaim && !hasS3) warnings.push(`Selected asset ${node.asset_id} has neither a local file nor S3 key.`);
|
|
3465
|
+
if (mediaType && mediaType !== "image" && mediaType !== "gif") warnings.push(`Selected asset ${node.asset_id} is ${mediaType}, not an image/gif asset.`);
|
|
3466
|
+
return {
|
|
3467
|
+
asset_id: node.asset_id,
|
|
3468
|
+
campaign: catalogAsset?.campaign || node.campaign,
|
|
3469
|
+
channel: catalogAsset?.channel || node.channel,
|
|
3470
|
+
checksum_sha256: checksum,
|
|
3471
|
+
current_attempt: currentAttemptFor(node),
|
|
3472
|
+
local: {
|
|
3473
|
+
absolute_path: absolutePath,
|
|
3474
|
+
content_type: catalogAsset?.local?.content_type,
|
|
3475
|
+
exists: localExists,
|
|
3476
|
+
relative_path: catalogAsset?.local?.relative_path || node.local_path || node.current_attempt?.file_path,
|
|
3477
|
+
size_bytes: catalogAsset?.local?.size_bytes || fileSize(absolutePath)
|
|
3478
|
+
},
|
|
3479
|
+
media_type: mediaType,
|
|
3480
|
+
mime_type: mimeType,
|
|
3481
|
+
review_notes: node.review_notes,
|
|
3482
|
+
review_state: node.review_state,
|
|
3483
|
+
s3: {
|
|
3484
|
+
bucket: catalogAsset?.s3?.bucket,
|
|
3485
|
+
checksum_sha256: catalogAsset?.s3?.checksum_sha256,
|
|
3486
|
+
content_type: catalogAsset?.s3?.content_type,
|
|
3487
|
+
etag: catalogAsset?.s3?.etag,
|
|
3488
|
+
key: s3Key,
|
|
3489
|
+
region: catalogAsset?.s3?.region,
|
|
3490
|
+
size_bytes: catalogAsset?.s3?.size_bytes,
|
|
3491
|
+
version_id: catalogAsset?.s3?.version_id
|
|
3492
|
+
},
|
|
3493
|
+
selection_note: node.selection_note,
|
|
3494
|
+
source: catalogAsset?.source || node.source,
|
|
3495
|
+
status: catalogAsset?.status || node.status,
|
|
3496
|
+
storage_state: storageState(hasLocalClaim, hasS3),
|
|
3497
|
+
title: catalogAsset?.title || node.title || node.asset_id
|
|
3498
|
+
};
|
|
3499
|
+
}
|
|
3500
|
+
function packetId(packetIdentity) {
|
|
3501
|
+
const digest = createHash3("sha256").update(JSON.stringify(packetIdentity)).digest("hex").slice(0, 24);
|
|
3502
|
+
return `lineage_packet_${digest}`;
|
|
3503
|
+
}
|
|
3504
|
+
function getLineageSelectionPacket(project, options = {}) {
|
|
3505
|
+
const workspace = resolveWorkspace(project, options);
|
|
3506
|
+
const snapshot = getLineageSnapshot(project, workspace.root_asset_id);
|
|
3507
|
+
const catalogSummary = validateProject(project);
|
|
3508
|
+
const catalogAssets = listAllAssets(project);
|
|
3509
|
+
const catalogById = new Map(catalogAssets.map((asset) => [asset.asset_id, asset]));
|
|
3510
|
+
const warnings = [];
|
|
3511
|
+
const errors = [];
|
|
3512
|
+
const nodeById = new Map(snapshot.nodes.map((node) => [node.asset_id, node]));
|
|
3513
|
+
const selectedItems = snapshot.selections.map((selection) => ({
|
|
3514
|
+
asset_id: selection.asset_id,
|
|
3515
|
+
position: selection.position,
|
|
3516
|
+
selected_at: selection.selected_at,
|
|
3517
|
+
selection_note: selection.notes
|
|
3518
|
+
}));
|
|
3519
|
+
if (selectedItems.length === 0) warnings.push(`Lineage workspace ${workspace.id} has no selected assets.`);
|
|
3520
|
+
const assets = selectedItems.flatMap((item) => {
|
|
3521
|
+
const node = nodeById.get(item.asset_id);
|
|
3522
|
+
if (!node) {
|
|
3523
|
+
const message = `Selected asset ${item.asset_id} is not present in the resolved workspace snapshot.`;
|
|
3524
|
+
warnings.push(message);
|
|
3525
|
+
errors.push("selected_asset_outside_workspace");
|
|
3526
|
+
return [];
|
|
3527
|
+
}
|
|
3528
|
+
return [assetForNode(node, catalogById.get(item.asset_id), warnings)];
|
|
3529
|
+
});
|
|
3530
|
+
if (assets.some((asset) => !asset.dimensions)) warnings.push("Image dimensions are unavailable for one or more selected assets.");
|
|
3531
|
+
if (options.strict) {
|
|
3532
|
+
const strictErrors = [
|
|
3533
|
+
...selectedItems.length === 0 ? ["empty_selection"] : [],
|
|
3534
|
+
...assets.filter((asset) => asset.local.absolute_path && !asset.local.exists).map((asset) => `missing_local_file:${asset.asset_id}`),
|
|
3535
|
+
...errors
|
|
3536
|
+
];
|
|
3537
|
+
if (strictErrors.length > 0) {
|
|
3538
|
+
throw new LineageSelectionPacketError(`Lineage selection packet strict mode failed: ${strictErrors.join(", ")}`, warnings, strictErrors);
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
const context = {
|
|
3542
|
+
campaign: options.campaign,
|
|
3543
|
+
channel: options.channel,
|
|
3544
|
+
labels: options.labels || [],
|
|
3545
|
+
notes: options.contextNotes
|
|
3546
|
+
};
|
|
3547
|
+
const identity = {
|
|
3548
|
+
assets: assets.map((asset) => ({
|
|
3549
|
+
asset_id: asset.asset_id,
|
|
3550
|
+
checksum_sha256: asset.checksum_sha256,
|
|
3551
|
+
local_path: asset.local.absolute_path,
|
|
3552
|
+
s3_key: asset.s3.key,
|
|
3553
|
+
storage_state: asset.storage_state
|
|
3554
|
+
})),
|
|
3555
|
+
context,
|
|
3556
|
+
project,
|
|
3557
|
+
root_asset_id: workspace.root_asset_id,
|
|
3558
|
+
schema_version: "lineage.selection_packet.v1",
|
|
3559
|
+
selection: selectedItems,
|
|
3560
|
+
workspace_id: workspace.id
|
|
3561
|
+
};
|
|
3562
|
+
return {
|
|
3563
|
+
assets,
|
|
3564
|
+
context,
|
|
3565
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3566
|
+
errors,
|
|
3567
|
+
kind: "lineage.selection_packet",
|
|
3568
|
+
packet_id: packetId(identity),
|
|
3569
|
+
product: catalogSummary.product,
|
|
3570
|
+
project,
|
|
3571
|
+
schema_version: "lineage.selection_packet.v1",
|
|
3572
|
+
selection: {
|
|
3573
|
+
asset_ids: selectedItems.map((item) => item.asset_id),
|
|
3574
|
+
count: selectedItems.length,
|
|
3575
|
+
items: selectedItems,
|
|
3576
|
+
root_asset_id: workspace.root_asset_id
|
|
3577
|
+
},
|
|
3578
|
+
source: {
|
|
3579
|
+
app: "lineage",
|
|
3580
|
+
command: options.command,
|
|
3581
|
+
db_path: options.dbPath || process.env.LINEAGE_DB || lineageDbPath(),
|
|
3582
|
+
package: options.packageVersion
|
|
3583
|
+
},
|
|
3584
|
+
warnings: [...new Set(warnings)],
|
|
3585
|
+
workspace: {
|
|
3586
|
+
active_at: workspace.active_at,
|
|
3587
|
+
id: workspace.id,
|
|
3588
|
+
notes: workspace.notes,
|
|
3589
|
+
root_asset_id: workspace.root_asset_id,
|
|
3590
|
+
status: workspace.status,
|
|
3591
|
+
title: workspace.title
|
|
3592
|
+
}
|
|
3593
|
+
};
|
|
3594
|
+
}
|
|
3595
|
+
|
|
3339
3596
|
// src/cli/lineageCli.ts
|
|
3340
3597
|
var signalExitCodes = {
|
|
3341
3598
|
SIGINT: 130,
|
|
3342
3599
|
SIGTERM: 143
|
|
3343
3600
|
};
|
|
3344
3601
|
function packageRoot() {
|
|
3345
|
-
return
|
|
3602
|
+
return resolve5(dirname3(fileURLToPath2(import.meta.url)), "..", "..");
|
|
3346
3603
|
}
|
|
3347
3604
|
function packageVersion() {
|
|
3348
3605
|
try {
|
|
@@ -3366,6 +3623,19 @@ function readOption(args, name) {
|
|
|
3366
3623
|
if (index >= 0) return args[index + 1];
|
|
3367
3624
|
return void 0;
|
|
3368
3625
|
}
|
|
3626
|
+
function readOptions(args, name) {
|
|
3627
|
+
const values = [];
|
|
3628
|
+
const prefix = `${name}=`;
|
|
3629
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
3630
|
+
const arg = args[index];
|
|
3631
|
+
if (arg.startsWith(prefix)) values.push(arg.slice(prefix.length));
|
|
3632
|
+
else if (arg === name && args[index + 1] && !args[index + 1].startsWith("--")) {
|
|
3633
|
+
values.push(args[index + 1]);
|
|
3634
|
+
index += 1;
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
return values;
|
|
3638
|
+
}
|
|
3369
3639
|
function resolveStartOptions(config, args) {
|
|
3370
3640
|
const runtimeDir = dataRoot(config.displayName);
|
|
3371
3641
|
const rawPort = readOption(args, "--port") || process.env.PORT || String(config.defaultPort);
|
|
@@ -3389,6 +3659,7 @@ Usage:
|
|
|
3389
3659
|
${config.binName} next [--project <project>] [--root <asset-id>] [--db <path>] [--json]
|
|
3390
3660
|
${config.binName} brief [--project <project>] [--root <asset-id>] [--db <path>] [--json]
|
|
3391
3661
|
${config.binName} inspect --asset-id <asset-id> [--project <project>] [--db <path>] [--json]
|
|
3662
|
+
${config.binName} selection packet [--project <project>] [--workspace <id-or-root>|--root <asset-id>] [--channel <channel>] [--campaign <campaign>] [--context-notes <text>] [--label <label>] [--out <path>] [--strict] [--db <path>] [--json]
|
|
3392
3663
|
${config.binName} link-child --root <asset-id> --child <asset-id> [--project <project>] [--claim-token <claim-id.secret>] [--confirm-write] [--db <path>] [--json]
|
|
3393
3664
|
${config.binName} reroll list --root <asset-id> [--project <project>] [--db <path>] [--json]
|
|
3394
3665
|
${config.binName} reroll mark --root <asset-id> --target <asset-id> [--notes <text>] [--requested-by agent|human|system] [--project <project>] [--confirm-write] [--db <path>] [--json]
|
|
@@ -3464,6 +3735,31 @@ function runLineageDataCommand(command, args) {
|
|
|
3464
3735
|
if (!options.assetId) throw new Error("lineage inspect requires --asset-id");
|
|
3465
3736
|
return getLineageSnapshot(options.project, options.assetId);
|
|
3466
3737
|
}
|
|
3738
|
+
if (command === "selection") {
|
|
3739
|
+
const subcommand = positionalArgs(args)[0] || "";
|
|
3740
|
+
if (subcommand !== "packet") throw new Error(`Unknown selection command: ${subcommand}`);
|
|
3741
|
+
const labels = readOptions(args, "--label").flatMap((label) => label.split(",")).map((label) => label.trim()).filter(Boolean);
|
|
3742
|
+
const packet = getLineageSelectionPacket(options.project, {
|
|
3743
|
+
campaign: readOption(args, "--campaign"),
|
|
3744
|
+
channel: readOption(args, "--channel"),
|
|
3745
|
+
command: "lineage selection packet",
|
|
3746
|
+
contextNotes: readOption(args, "--context-notes") || readOption(args, "--notes"),
|
|
3747
|
+
dbPath: options.dbPath,
|
|
3748
|
+
labels,
|
|
3749
|
+
packageVersion: packageVersion(),
|
|
3750
|
+
rootAssetId: options.rootAssetId,
|
|
3751
|
+
strict: args.includes("--strict"),
|
|
3752
|
+
workspaceId: readOption(args, "--workspace") || readOption(args, "--workspace-id")
|
|
3753
|
+
});
|
|
3754
|
+
const out = readOption(args, "--out");
|
|
3755
|
+
if (out) {
|
|
3756
|
+
const outPath = resolve5(out);
|
|
3757
|
+
mkdirSync4(dirname3(outPath), { recursive: true });
|
|
3758
|
+
writeFileSync2(outPath, `${JSON.stringify(packet, null, 2)}
|
|
3759
|
+
`);
|
|
3760
|
+
}
|
|
3761
|
+
return packet;
|
|
3762
|
+
}
|
|
3467
3763
|
if (command === "link-child") {
|
|
3468
3764
|
if (!options.childAssetId) throw new Error("lineage link-child requires --child");
|
|
3469
3765
|
return linkSelectedLineageChild(options.project, {
|
|
@@ -3613,6 +3909,13 @@ function printDataResult(command, result, json) {
|
|
|
3613
3909
|
console.log(`Active: ${snapshot.active_asset_id}`);
|
|
3614
3910
|
return;
|
|
3615
3911
|
}
|
|
3912
|
+
if (command === "selection" && result && typeof result === "object" && "packet_id" in result) {
|
|
3913
|
+
const packet = result;
|
|
3914
|
+
console.log(`${packet.packet_id}: ${packet.selection?.count || packet.assets?.length || 0} selected asset(s)`);
|
|
3915
|
+
if (packet.workspace?.root_asset_id) console.log(`Root: ${packet.workspace.root_asset_id}`);
|
|
3916
|
+
for (const warning of packet.warnings || []) console.log(`Warning: ${warning}`);
|
|
3917
|
+
return;
|
|
3918
|
+
}
|
|
3616
3919
|
if (command === "link-child" && result && typeof result === "object") {
|
|
3617
3920
|
const link = result;
|
|
3618
3921
|
console.log(link.message || `${link.dryRun ? "Dry run: " : ""}Link ${link.edge?.child_asset_id || "child"} from ${link.edge?.parent_asset_id || "parent"}`);
|
|
@@ -3782,7 +4085,7 @@ function start(config, args) {
|
|
|
3782
4085
|
process.exit(1);
|
|
3783
4086
|
}
|
|
3784
4087
|
const serverPath = join6(packageRoot(), "dist", "server.js");
|
|
3785
|
-
if (!
|
|
4088
|
+
if (!existsSync6(serverPath)) {
|
|
3786
4089
|
const message = `Missing bundled server at ${serverPath}. Run npm run build before using ${config.binName} start from a source checkout.`;
|
|
3787
4090
|
if (options.json) console.error(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
3788
4091
|
else console.error(`${config.binName}: ${message}`);
|
|
@@ -3836,7 +4139,7 @@ function runLineageCli(config, args = process.argv.slice(2)) {
|
|
|
3836
4139
|
start(config, normalizedArgs.slice(1));
|
|
3837
4140
|
return;
|
|
3838
4141
|
}
|
|
3839
|
-
if (command === "next" || command === "brief" || command === "inspect" || command === "link-child" || command === "reroll" || command === "tasks") {
|
|
4142
|
+
if (command === "next" || command === "brief" || command === "inspect" || command === "selection" || command === "link-child" || command === "reroll" || command === "tasks") {
|
|
3840
4143
|
const commandArgs = normalizedArgs.slice(1);
|
|
3841
4144
|
const json2 = commandArgs.includes("--json");
|
|
3842
4145
|
try {
|