@mcptoolshop/style-dataset-lab 3.0.0 → 3.1.0
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 +108 -15
- package/CODE_OF_CONDUCT.md +9 -0
- package/CONTRIBUTING.md +71 -0
- package/README.es.md +99 -8
- package/README.fr.md +100 -9
- package/README.hi.md +102 -9
- package/README.it.md +99 -8
- package/README.ja.md +100 -9
- package/README.md +64 -1
- package/README.pt-BR.md +99 -8
- package/README.zh.md +100 -9
- package/SECURITY.md +6 -5
- package/bin/sdlab.js +289 -62
- package/lib/adapters/comfyui-runner.js +11 -15
- package/lib/adapters/diffusers-lora.js +7 -2
- package/lib/adapters/generic-image-caption.js +6 -1
- package/lib/args.js +200 -13
- package/lib/batch-compiler.js +7 -3
- package/lib/batch-runs.js +162 -31
- package/lib/batch-sheet-render.js +5 -2
- package/lib/brief-compiler.js +38 -11
- package/lib/card.js +11 -4
- package/lib/comfyui-output.js +70 -0
- package/lib/comfyui.js +100 -6
- package/lib/config.js +68 -3
- package/lib/deprecation.js +1 -1
- package/lib/eval-pack.js +94 -4
- package/lib/eval-runs.js +42 -3
- package/lib/export.js +144 -34
- package/lib/implementation-packs.js +15 -1
- package/lib/log.js +41 -4
- package/lib/paths.js +41 -3
- package/lib/refine-briefs.js +16 -9
- package/lib/reingest-selected.js +14 -3
- package/lib/reingest.js +15 -1
- package/lib/run-summary.js +3 -2
- package/lib/runtime-runs.js +59 -9
- package/lib/selections.js +54 -2
- package/lib/snapshot.js +100 -7
- package/lib/split.js +175 -17
- package/lib/training-adapters.js +79 -0
- package/lib/training-manifests.js +17 -3
- package/lib/training-packages.js +29 -28
- package/lib/training-profiles.js +10 -0
- package/package.json +27 -3
- package/scripts/batch-generate.js +72 -20
- package/scripts/batch-sheet.js +3 -3
- package/scripts/batch-show.js +3 -3
- package/scripts/brief-compile.js +8 -8
- package/scripts/brief-show.js +4 -3
- package/scripts/canon-bind.js +7 -9
- package/scripts/card.js +22 -25
- package/scripts/compare.js +38 -33
- package/scripts/critique-show.js +3 -3
- package/scripts/critique.js +3 -3
- package/scripts/curate.js +91 -46
- package/scripts/doctor.js +3 -5
- package/scripts/eligibility.js +17 -14
- package/scripts/eval-pack.js +13 -11
- package/scripts/eval-run.js +30 -29
- package/scripts/export.js +27 -31
- package/scripts/generate-controlnet.js +31 -17
- package/scripts/generate-identity.js +37 -20
- package/scripts/generate-ipadapter.js +22 -16
- package/scripts/generate.js +96 -29
- package/scripts/implementation-pack.js +19 -14
- package/scripts/init.js +115 -17
- package/scripts/painterly.js +8 -10
- package/scripts/refine.js +3 -3
- package/scripts/reingest-selected.js +3 -3
- package/scripts/reingest.js +33 -20
- package/scripts/run-generate.js +4 -4
- package/scripts/run-list.js +3 -3
- package/scripts/run-show.js +3 -3
- package/scripts/select.js +5 -4
- package/scripts/selection-show.js +3 -3
- package/scripts/snapshot.js +22 -24
- package/scripts/split.js +26 -31
- package/scripts/training-manifest.js +29 -24
- package/scripts/training-package.js +24 -20
- package/scripts/training-profile.js +13 -8
- package/scripts/workflow-list.js +2 -2
- package/scripts/workflow-show.js +4 -3
- package/templates/domains/architecture/inputs/prompts/example-wave.json +32 -0
- package/templates/domains/architecture/terminology.json +10 -8
- package/templates/domains/character-design/inputs/prompts/example-wave.json +32 -0
- package/templates/domains/character-design/project.json +4 -2
- package/templates/domains/creature-design/inputs/prompts/example-wave.json +32 -0
- package/templates/domains/creature-design/project.json +4 -2
- package/templates/domains/creature-design/terminology.json +1 -0
- package/templates/domains/game-art/inputs/prompts/example-wave.json +37 -0
- package/templates/domains/game-art/project.json +4 -2
- package/templates/domains/vehicle-mech/inputs/prompts/example-wave.json +37 -0
- package/templates/domains/vehicle-mech/project.json +4 -2
- package/scripts/bulk-curate-wave2-5.js +0 -138
- package/scripts/bulk-curate-waves11-18.js +0 -413
- package/scripts/curate-wave25.js +0 -209
- package/scripts/migrate-records.js +0 -141
- package/templates/inputs/prompts/example-wave.json +0 -27
package/scripts/run-generate.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* sdlab run generate --brief brief_2026-04-15_001 --project star-freight --seed 42
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { parseArgs } from '../lib/args.js';
|
|
12
|
+
import { parseArgs, getProjectName, parseNumberFlag } from '../lib/args.js';
|
|
13
13
|
import { getProjectRoot, getRunsDir } from '../lib/paths.js';
|
|
14
14
|
import { loadCompiledBrief } from '../lib/brief-compiler.js';
|
|
15
15
|
import { executeRun } from '../lib/adapters/comfyui-runner.js';
|
|
@@ -20,7 +20,7 @@ import { join } from 'node:path';
|
|
|
20
20
|
export async function run(argv = process.argv.slice(2)) {
|
|
21
21
|
const { flags } = parseArgs(argv, {
|
|
22
22
|
flags: {
|
|
23
|
-
project: { type: 'string'
|
|
23
|
+
project: { type: 'string' },
|
|
24
24
|
brief: { type: 'string' },
|
|
25
25
|
seed: { type: 'string' },
|
|
26
26
|
'dry-run': { type: 'boolean' },
|
|
@@ -40,7 +40,7 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
const projectName = flags.project;
|
|
43
|
+
const projectName = flags.project || getProjectName(argv);
|
|
44
44
|
const projectRoot = getProjectRoot(projectName);
|
|
45
45
|
|
|
46
46
|
console.log(`\x1b[1mstyle-dataset-lab\x1b[0m run generate`);
|
|
@@ -57,7 +57,7 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
57
57
|
projectRoot,
|
|
58
58
|
projectName,
|
|
59
59
|
brief,
|
|
60
|
-
baseSeed: flags.seed ?
|
|
60
|
+
baseSeed: flags.seed ? parseNumberFlag('seed', flags.seed, { int: true, min: 0 }) : undefined,
|
|
61
61
|
dryRun: flags['dry-run'] || false,
|
|
62
62
|
});
|
|
63
63
|
|
package/scripts/run-list.js
CHANGED
|
@@ -8,20 +8,20 @@
|
|
|
8
8
|
* sdlab run list --project star-freight --json
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { parseArgs } from '../lib/args.js';
|
|
11
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
12
12
|
import { getProjectRoot } from '../lib/paths.js';
|
|
13
13
|
import { listRuns } from '../lib/runtime-runs.js';
|
|
14
14
|
|
|
15
15
|
export async function run(argv = process.argv.slice(2)) {
|
|
16
16
|
const { flags } = parseArgs(argv, {
|
|
17
17
|
flags: {
|
|
18
|
-
project: { type: 'string'
|
|
18
|
+
project: { type: 'string' },
|
|
19
19
|
json: { type: 'boolean' },
|
|
20
20
|
},
|
|
21
21
|
deprecated: { game: 'project' },
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
const projectName = flags.project;
|
|
24
|
+
const projectName = flags.project || getProjectName(argv);
|
|
25
25
|
const projectRoot = getProjectRoot(projectName);
|
|
26
26
|
const runs = listRuns(projectRoot);
|
|
27
27
|
|
package/scripts/run-show.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* sdlab run show run_2026-04-16_001 --project star-freight --md
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { parseArgs } from '../lib/args.js';
|
|
12
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
13
13
|
import { getProjectRoot } from '../lib/paths.js';
|
|
14
14
|
import { loadRun, listRuns } from '../lib/runtime-runs.js';
|
|
15
15
|
import { renderRunText, renderRunMarkdown } from '../lib/run-summary.js';
|
|
@@ -17,7 +17,7 @@ import { renderRunText, renderRunMarkdown } from '../lib/run-summary.js';
|
|
|
17
17
|
export async function run(argv = process.argv.slice(2)) {
|
|
18
18
|
const { positionals, flags } = parseArgs(argv, {
|
|
19
19
|
flags: {
|
|
20
|
-
project: { type: 'string'
|
|
20
|
+
project: { type: 'string' },
|
|
21
21
|
json: { type: 'boolean' },
|
|
22
22
|
md: { type: 'boolean' },
|
|
23
23
|
},
|
|
@@ -25,7 +25,7 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
const runId = positionals[0];
|
|
28
|
-
const projectName = flags.project;
|
|
28
|
+
const projectName = flags.project || getProjectName(argv);
|
|
29
29
|
const projectRoot = getProjectRoot(projectName);
|
|
30
30
|
|
|
31
31
|
// No run ID → list runs
|
package/scripts/select.js
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
* sdlab select --run run_2026-04-15_001 --approve 001.png --reason "best continuity" --tags portrait,keeper
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { parseArgs } from '../lib/args.js';
|
|
12
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
13
13
|
import { getProjectRoot } from '../lib/paths.js';
|
|
14
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
14
15
|
import {
|
|
15
16
|
createSelectionFromRun,
|
|
16
17
|
createSelectionFromBatch,
|
|
@@ -21,7 +22,7 @@ import { info } from '../lib/log.js';
|
|
|
21
22
|
export async function run(argv = process.argv.slice(2)) {
|
|
22
23
|
const { flags } = parseArgs(argv, {
|
|
23
24
|
flags: {
|
|
24
|
-
project: { type: 'string'
|
|
25
|
+
project: { type: 'string' },
|
|
25
26
|
run: { type: 'string' },
|
|
26
27
|
batch: { type: 'string' },
|
|
27
28
|
approve: { type: 'string' },
|
|
@@ -46,7 +47,7 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
46
47
|
return;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
const projectName = flags.project;
|
|
50
|
+
const projectName = flags.project || getProjectName(argv);
|
|
50
51
|
const projectRoot = getProjectRoot(projectName);
|
|
51
52
|
const reason = flags.reason || undefined;
|
|
52
53
|
const tags = flags.tags ? flags.tags.split(',').map(t => t.trim()) : undefined;
|
|
@@ -71,7 +72,7 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
71
72
|
const approvedSlots = pairs.map(pair => {
|
|
72
73
|
const colonIdx = pair.indexOf(':');
|
|
73
74
|
if (colonIdx < 0) {
|
|
74
|
-
throw
|
|
75
|
+
throw inputError('INPUT_BAD_FORMAT', `Invalid batch approve format: "${pair}". Use slot_id:filename`);
|
|
75
76
|
}
|
|
76
77
|
return {
|
|
77
78
|
slotId: pair.slice(0, colonIdx),
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* sdlab selection show selection_2026-04-16_001 --json
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { parseArgs } from '../lib/args.js';
|
|
12
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
13
13
|
import { getProjectRoot } from '../lib/paths.js';
|
|
14
14
|
import { loadSelection, listSelections, getSelectionsDir } from '../lib/selections.js';
|
|
15
15
|
import { join } from 'node:path';
|
|
@@ -18,14 +18,14 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
18
18
|
export async function run(argv = process.argv.slice(2)) {
|
|
19
19
|
const { flags, positionals } = parseArgs(argv, {
|
|
20
20
|
flags: {
|
|
21
|
-
project: { type: 'string'
|
|
21
|
+
project: { type: 'string' },
|
|
22
22
|
selection: { type: 'string' },
|
|
23
23
|
json: { type: 'boolean' },
|
|
24
24
|
},
|
|
25
25
|
deprecated: { game: 'project' },
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
const projectName = flags.project;
|
|
28
|
+
const projectName = flags.project || getProjectName(argv);
|
|
29
29
|
const projectRoot = getProjectRoot(projectName);
|
|
30
30
|
const selectionId = positionals[0] || flags.selection;
|
|
31
31
|
|
package/scripts/snapshot.js
CHANGED
|
@@ -12,30 +12,33 @@
|
|
|
12
12
|
|
|
13
13
|
import { readFile } from 'node:fs/promises';
|
|
14
14
|
import { join } from 'node:path';
|
|
15
|
-
import {
|
|
16
|
-
import { getProjectName } from '../lib/args.js';
|
|
15
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
17
16
|
import { REPO_ROOT } from '../lib/paths.js';
|
|
18
17
|
import { loadSelectionProfile } from '../lib/config.js';
|
|
18
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
19
19
|
import { createSnapshot, loadSnapshot, listSnapshots, diffSnapshots } from '../lib/snapshot.js';
|
|
20
|
-
import { evaluateEligibility } from '../lib/eligibility.js';
|
|
21
20
|
import { categorizeExclusions } from '../lib/eligibility.js';
|
|
22
21
|
|
|
23
22
|
export async function run(argv = process.argv.slice(2)) {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
const { flags, positionals } = parseArgs(argv, {
|
|
24
|
+
flags: {
|
|
25
|
+
project: { type: 'string' },
|
|
26
|
+
profile: { type: 'string' },
|
|
27
|
+
'dry-run': { type: 'boolean', default: false },
|
|
28
|
+
},
|
|
29
|
+
deprecated: { game: 'project' },
|
|
30
|
+
});
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
const
|
|
32
|
+
const projectName = flags.project || getProjectName(argv);
|
|
33
|
+
const projectRoot = join(REPO_ROOT, 'projects', projectName);
|
|
34
|
+
const subcommand = positionals[0] || 'list';
|
|
35
|
+
const dryRun = flags['dry-run'] || flags.dryRun;
|
|
30
36
|
|
|
31
37
|
if (subcommand === 'create') {
|
|
32
|
-
const
|
|
33
|
-
const profileId = profileIdx >= 0 ? args[profileIdx + 1] : null;
|
|
34
|
-
const profile = loadSelectionProfile(projectRoot, profileId);
|
|
35
|
-
const dryRun = argv.includes('--dry-run');
|
|
38
|
+
const profile = loadSelectionProfile(projectRoot, flags.profile);
|
|
36
39
|
|
|
37
40
|
console.log(`\x1b[1msdlab snapshot create\x1b[0m — ${projectName}`);
|
|
38
|
-
console.log(` Profile: ${
|
|
41
|
+
console.log(` Profile: ${flags.profile || 'training-default (built-in)'}`);
|
|
39
42
|
if (dryRun) console.log(' Mode: DRY RUN (no files written)');
|
|
40
43
|
console.log('');
|
|
41
44
|
|
|
@@ -46,7 +49,6 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
46
49
|
console.log(` Excluded: ${result.excluded}`);
|
|
47
50
|
|
|
48
51
|
if (!dryRun) {
|
|
49
|
-
// Read and display summary
|
|
50
52
|
const summary = JSON.parse(
|
|
51
53
|
await readFile(join(projectRoot, 'snapshots', result.snapshotId, 'summary.json'), 'utf-8')
|
|
52
54
|
);
|
|
@@ -59,7 +61,6 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
59
61
|
console.log(` ${f}: ${c}`);
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
// Read and categorize exclusions
|
|
63
64
|
const excludedRaw = await readFile(
|
|
64
65
|
join(projectRoot, 'snapshots', result.snapshotId, 'excluded.jsonl'), 'utf-8'
|
|
65
66
|
);
|
|
@@ -83,8 +84,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
} else if (subcommand === 'show') {
|
|
86
|
-
const snapshotId =
|
|
87
|
-
if (!snapshotId) throw
|
|
87
|
+
const snapshotId = positionals[1] || positionals.find(a => a.startsWith('snap-'));
|
|
88
|
+
if (!snapshotId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab snapshot show <snapshot-id>');
|
|
88
89
|
|
|
89
90
|
const manifest = await loadSnapshot(projectRoot, snapshotId);
|
|
90
91
|
console.log(`\x1b[1mSnapshot\x1b[0m — ${snapshotId}\n`);
|
|
@@ -102,8 +103,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
} else if (subcommand === 'diff') {
|
|
105
|
-
const snapIds =
|
|
106
|
-
if (snapIds.length < 2) throw
|
|
106
|
+
const snapIds = positionals.slice(1).filter(a => a.startsWith('snap-'));
|
|
107
|
+
if (snapIds.length < 2) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab snapshot diff <id-a> <id-b>');
|
|
107
108
|
|
|
108
109
|
const diff = await diffSnapshots(projectRoot, snapIds[0], snapIds[1]);
|
|
109
110
|
console.log(`\x1b[1mSnapshot diff\x1b[0m — ${snapIds[0]} vs ${snapIds[1]}\n`);
|
|
@@ -123,14 +124,11 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
} else {
|
|
126
|
-
throw
|
|
127
|
+
throw inputError('INPUT_BAD_SUBCOMMAND', `Unknown subcommand: ${subcommand}. Use: create, list, show, diff`);
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
// Direct execution guard
|
|
131
132
|
if (process.argv[1] && (process.argv[1].endsWith('snapshot.js') || process.argv[1].endsWith('snapshot'))) {
|
|
132
|
-
run().catch(
|
|
133
|
-
console.error(err.message || err);
|
|
134
|
-
process.exit(1);
|
|
135
|
-
});
|
|
133
|
+
run().catch(handleCliError);
|
|
136
134
|
}
|
package/scripts/split.js
CHANGED
|
@@ -10,43 +10,45 @@
|
|
|
10
10
|
* sdlab split audit <split-id> [--project <name>]
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { readFile } from 'node:fs/promises';
|
|
14
13
|
import { join } from 'node:path';
|
|
15
|
-
import { getProjectName } from '../lib/args.js';
|
|
14
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
16
15
|
import { REPO_ROOT } from '../lib/paths.js';
|
|
17
16
|
import { loadSplitProfile } from '../lib/config.js';
|
|
17
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
18
18
|
import { listSnapshots } from '../lib/snapshot.js';
|
|
19
19
|
import { createSplit, loadSplit, loadSplitAudit, listSplits } from '../lib/split.js';
|
|
20
20
|
|
|
21
21
|
export async function run(argv = process.argv.slice(2)) {
|
|
22
|
-
const
|
|
22
|
+
const { flags, positionals } = parseArgs(argv, {
|
|
23
|
+
flags: {
|
|
24
|
+
project: { type: 'string' },
|
|
25
|
+
snapshot: { type: 'string' },
|
|
26
|
+
profile: { type: 'string' },
|
|
27
|
+
'dry-run': { type: 'boolean', default: false },
|
|
28
|
+
},
|
|
29
|
+
deprecated: { game: 'project' },
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const projectName = flags.project || getProjectName(argv);
|
|
23
33
|
const projectRoot = join(REPO_ROOT, 'projects', projectName);
|
|
24
|
-
const subcommand =
|
|
25
|
-
const
|
|
34
|
+
const subcommand = positionals[0] || 'list';
|
|
35
|
+
const dryRun = flags['dry-run'] || flags.dryRun;
|
|
26
36
|
|
|
27
37
|
if (subcommand === 'build') {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const snapIdx = args.indexOf('--snapshot');
|
|
31
|
-
if (snapIdx >= 0) {
|
|
32
|
-
snapshotId = args[snapIdx + 1];
|
|
33
|
-
} else {
|
|
34
|
-
// Use latest snapshot
|
|
38
|
+
let snapshotId = flags.snapshot;
|
|
39
|
+
if (!snapshotId) {
|
|
35
40
|
const snapshots = await listSnapshots(projectRoot);
|
|
36
41
|
if (snapshots.length === 0) {
|
|
37
|
-
throw
|
|
42
|
+
throw inputError('INPUT_NO_SNAPSHOT', 'No snapshots found. Run: sdlab snapshot create');
|
|
38
43
|
}
|
|
39
44
|
snapshotId = snapshots[snapshots.length - 1].id;
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
const
|
|
43
|
-
const profileId = profileIdx >= 0 ? args[profileIdx + 1] : null;
|
|
44
|
-
const profile = loadSplitProfile(projectRoot, profileId);
|
|
45
|
-
const dryRun = argv.includes('--dry-run');
|
|
47
|
+
const profile = loadSplitProfile(projectRoot, flags.profile);
|
|
46
48
|
|
|
47
49
|
console.log(`\x1b[1msdlab split build\x1b[0m — ${projectName}`);
|
|
48
50
|
console.log(` Snapshot: ${snapshotId}`);
|
|
49
|
-
console.log(` Profile: ${
|
|
51
|
+
console.log(` Profile: ${flags.profile || 'balanced-default (built-in)'}`);
|
|
50
52
|
console.log(` Strategy: ${profile.strategy}`);
|
|
51
53
|
console.log(` Ratios: ${profile.train_ratio}/${profile.val_ratio}/${profile.test_ratio}`);
|
|
52
54
|
console.log(` Seed: ${profile.seed}`);
|
|
@@ -60,7 +62,6 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
60
62
|
console.log(` Val: ${result.val}`);
|
|
61
63
|
console.log(` Test: ${result.test}`);
|
|
62
64
|
|
|
63
|
-
// Show audit summary
|
|
64
65
|
const audit = await loadSplitAudit(projectRoot, result.splitId);
|
|
65
66
|
console.log('');
|
|
66
67
|
if (audit.leakage_check.passed) {
|
|
@@ -86,8 +87,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
} else if (subcommand === 'show') {
|
|
89
|
-
const splitId =
|
|
90
|
-
if (!splitId) throw
|
|
90
|
+
const splitId = positionals[1] || positionals.find(a => a.startsWith('split-'));
|
|
91
|
+
if (!splitId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab split show <split-id>');
|
|
91
92
|
|
|
92
93
|
const manifest = await loadSplit(projectRoot, splitId);
|
|
93
94
|
console.log(`\x1b[1mSplit\x1b[0m — ${splitId}\n`);
|
|
@@ -112,13 +113,12 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
} else if (subcommand === 'audit') {
|
|
115
|
-
const splitId =
|
|
116
|
-
if (!splitId) throw
|
|
116
|
+
const splitId = positionals[1] || positionals.find(a => a.startsWith('split-'));
|
|
117
|
+
if (!splitId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab split audit <split-id>');
|
|
117
118
|
|
|
118
119
|
const audit = await loadSplitAudit(projectRoot, splitId);
|
|
119
120
|
console.log(`\x1b[1mSplit audit\x1b[0m — ${splitId}\n`);
|
|
120
121
|
|
|
121
|
-
// Leakage check
|
|
122
122
|
if (audit.leakage_check.passed) {
|
|
123
123
|
console.log(` \x1b[32m✓\x1b[0m Leakage check: PASSED`);
|
|
124
124
|
} else {
|
|
@@ -128,13 +128,11 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
-
// Family distribution
|
|
132
131
|
console.log(`\n Families: ${audit.family_count}`);
|
|
133
132
|
console.log(` Train: ${audit.families_per_split.train}`);
|
|
134
133
|
console.log(` Val: ${audit.families_per_split.val}`);
|
|
135
134
|
console.log(` Test: ${audit.families_per_split.test}`);
|
|
136
135
|
|
|
137
|
-
// Lane balance
|
|
138
136
|
console.log('\n Lane balance:');
|
|
139
137
|
console.log(` ${'Lane'.padEnd(20)} ${'Total'.padStart(6)} ${'Train%'.padStart(8)} ${'Val%'.padStart(8)} ${'Test%'.padStart(8)}`);
|
|
140
138
|
console.log(` ${'─'.repeat(52)}`);
|
|
@@ -143,14 +141,11 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
143
141
|
}
|
|
144
142
|
|
|
145
143
|
} else {
|
|
146
|
-
throw
|
|
144
|
+
throw inputError('INPUT_BAD_SUBCOMMAND', `Unknown subcommand: ${subcommand}. Use: build, list, show, audit`);
|
|
147
145
|
}
|
|
148
146
|
}
|
|
149
147
|
|
|
150
148
|
// Direct execution guard
|
|
151
149
|
if (process.argv[1] && (process.argv[1].endsWith('split.js') || process.argv[1].endsWith('split'))) {
|
|
152
|
-
run().catch(
|
|
153
|
-
console.error(err.message || err);
|
|
154
|
-
process.exit(1);
|
|
155
|
-
});
|
|
150
|
+
run().catch(handleCliError);
|
|
156
151
|
}
|
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { join } from 'node:path';
|
|
14
|
-
import { getProjectName } from '../lib/args.js';
|
|
14
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
15
15
|
import { REPO_ROOT } from '../lib/paths.js';
|
|
16
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
16
17
|
import { listExports } from '../lib/export.js';
|
|
17
18
|
import {
|
|
18
19
|
createTrainingManifest,
|
|
@@ -22,30 +23,34 @@ import {
|
|
|
22
23
|
} from '../lib/training-manifests.js';
|
|
23
24
|
|
|
24
25
|
export async function run(argv = process.argv.slice(2)) {
|
|
25
|
-
const
|
|
26
|
+
const { flags, positionals } = parseArgs(argv, {
|
|
27
|
+
flags: {
|
|
28
|
+
project: { type: 'string' },
|
|
29
|
+
export: { type: 'string' },
|
|
30
|
+
profile: { type: 'string' },
|
|
31
|
+
adapter: { type: 'string' },
|
|
32
|
+
'base-model': { type: 'string' },
|
|
33
|
+
},
|
|
34
|
+
deprecated: { game: 'project' },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const projectName = flags.project || getProjectName(argv);
|
|
26
38
|
const projectRoot = join(REPO_ROOT, 'projects', projectName);
|
|
27
|
-
const subcommand =
|
|
28
|
-
const args = argv.filter(a => a !== subcommand);
|
|
39
|
+
const subcommand = positionals.find(a => !a.startsWith('tm-')) || 'list';
|
|
29
40
|
|
|
30
41
|
if (subcommand === 'create') {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (exportIdx < 0) {
|
|
34
|
-
// Try latest export
|
|
42
|
+
let exportId = flags.export;
|
|
43
|
+
if (!exportId) {
|
|
35
44
|
const exports = await listExports(projectRoot);
|
|
36
|
-
if (exports.length === 0) throw
|
|
45
|
+
if (exports.length === 0) throw inputError('INPUT_NO_EXPORT', 'No exports found. Run: sdlab export build');
|
|
46
|
+
exportId = exports[exports.length - 1].id;
|
|
37
47
|
}
|
|
38
|
-
const exportId = exportIdx >= 0 ? args[exportIdx + 1] : (await listExports(projectRoot)).pop().id;
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const profileId = args[profileIdx + 1];
|
|
49
|
+
if (!flags.profile) throw inputError('INPUT_MISSING_FLAG', '--profile is required. Use: sdlab training-profile list');
|
|
50
|
+
const profileId = flags.profile;
|
|
43
51
|
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
const baseModelIdx = args.indexOf('--base-model');
|
|
48
|
-
const baseModel = baseModelIdx >= 0 ? args[baseModelIdx + 1] : undefined;
|
|
52
|
+
const adapterTarget = flags.adapter;
|
|
53
|
+
const baseModel = flags['base-model'] || flags.baseModel;
|
|
49
54
|
|
|
50
55
|
console.log(`\x1b[1msdlab training-manifest create\x1b[0m — ${projectName}`);
|
|
51
56
|
console.log(` Export: ${exportId}`);
|
|
@@ -62,8 +67,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
62
67
|
console.log(` \x1b[32m✓\x1b[0m Manifest: ${result.manifestId}`);
|
|
63
68
|
|
|
64
69
|
} else if (subcommand === 'validate') {
|
|
65
|
-
const manifestId =
|
|
66
|
-
if (!manifestId) throw
|
|
70
|
+
const manifestId = positionals.find(a => a.startsWith('tm-'));
|
|
71
|
+
if (!manifestId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab training-manifest validate <manifest-id>');
|
|
67
72
|
|
|
68
73
|
console.log(`\x1b[1msdlab training-manifest validate\x1b[0m — ${manifestId}\n`);
|
|
69
74
|
const { valid, issues } = await validateTrainingManifest(projectRoot, manifestId);
|
|
@@ -78,8 +83,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
} else if (subcommand === 'show') {
|
|
81
|
-
const manifestId =
|
|
82
|
-
if (!manifestId) throw
|
|
86
|
+
const manifestId = positionals.find(a => a.startsWith('tm-'));
|
|
87
|
+
if (!manifestId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab training-manifest show <manifest-id>');
|
|
83
88
|
|
|
84
89
|
const manifest = await loadTrainingManifest(projectRoot, manifestId);
|
|
85
90
|
console.log(`\x1b[1mTraining manifest\x1b[0m — ${manifestId}\n`);
|
|
@@ -110,10 +115,10 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
} else {
|
|
113
|
-
throw
|
|
118
|
+
throw inputError('INPUT_BAD_SUBCOMMAND', `Unknown subcommand: ${subcommand}. Use: create, validate, show, list`);
|
|
114
119
|
}
|
|
115
120
|
}
|
|
116
121
|
|
|
117
122
|
if (process.argv[1] && (process.argv[1].endsWith('training-manifest.js') || process.argv[1].endsWith('training-manifest'))) {
|
|
118
|
-
run().catch(
|
|
123
|
+
run().catch(handleCliError);
|
|
119
124
|
}
|
|
@@ -10,48 +10,52 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { join } from 'node:path';
|
|
13
|
-
import { getProjectName } from '../lib/args.js';
|
|
13
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
14
14
|
import { REPO_ROOT } from '../lib/paths.js';
|
|
15
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
15
16
|
import { listTrainingManifests } from '../lib/training-manifests.js';
|
|
16
17
|
import { buildTrainingPackage, listTrainingPackages, loadTrainingPackage } from '../lib/training-packages.js';
|
|
17
18
|
|
|
18
19
|
export async function run(argv = process.argv.slice(2)) {
|
|
19
|
-
const
|
|
20
|
+
const { flags, positionals } = parseArgs(argv, {
|
|
21
|
+
flags: {
|
|
22
|
+
project: { type: 'string' },
|
|
23
|
+
manifest: { type: 'string' },
|
|
24
|
+
adapter: { type: 'string' },
|
|
25
|
+
copy: { type: 'boolean', default: false },
|
|
26
|
+
},
|
|
27
|
+
deprecated: { game: 'project' },
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const projectName = flags.project || getProjectName(argv);
|
|
20
31
|
const projectRoot = join(REPO_ROOT, 'projects', projectName);
|
|
21
|
-
const subcommand =
|
|
22
|
-
const args = argv.filter(a => a !== subcommand);
|
|
32
|
+
const subcommand = positionals.find(a => !a.startsWith('tp-') && !a.startsWith('tm-')) || 'list';
|
|
23
33
|
|
|
24
34
|
if (subcommand === 'build') {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const manifestIdx = args.indexOf('--manifest');
|
|
28
|
-
if (manifestIdx >= 0) {
|
|
29
|
-
manifestId = args[manifestIdx + 1];
|
|
30
|
-
} else {
|
|
35
|
+
let manifestId = flags.manifest;
|
|
36
|
+
if (!manifestId) {
|
|
31
37
|
const manifests = await listTrainingManifests(projectRoot);
|
|
32
|
-
if (manifests.length === 0) throw
|
|
38
|
+
if (manifests.length === 0) throw inputError('INPUT_NO_MANIFEST', 'No training manifests found. Run: sdlab training-manifest create');
|
|
33
39
|
manifestId = manifests[manifests.length - 1].id;
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
const
|
|
37
|
-
const adapterOverride = adapterIdx >= 0 ? args[adapterIdx + 1] : undefined;
|
|
38
|
-
const copy = args.includes('--copy');
|
|
42
|
+
const adapterOverride = flags.adapter;
|
|
39
43
|
|
|
40
44
|
console.log(`\x1b[1msdlab training-package build\x1b[0m — ${projectName}`);
|
|
41
45
|
console.log(` Manifest: ${manifestId}`);
|
|
42
46
|
if (adapterOverride) console.log(` Adapter: ${adapterOverride}`);
|
|
43
|
-
console.log(` Images: ${copy ? 'copy' : 'symlink'}`);
|
|
47
|
+
console.log(` Images: ${flags.copy ? 'copy' : 'symlink'}`);
|
|
44
48
|
console.log('');
|
|
45
49
|
|
|
46
|
-
const result = await buildTrainingPackage(projectRoot, manifestId, { copy, adapterOverride });
|
|
50
|
+
const result = await buildTrainingPackage(projectRoot, manifestId, { copy: flags.copy, adapterOverride });
|
|
47
51
|
|
|
48
52
|
console.log(` \x1b[32m✓\x1b[0m Package: ${result.packageId}`);
|
|
49
53
|
console.log(` Records: ${result.records}`);
|
|
50
54
|
console.log(` Images: ${result.images}`);
|
|
51
55
|
|
|
52
56
|
} else if (subcommand === 'show') {
|
|
53
|
-
const packageId =
|
|
54
|
-
if (!packageId) throw
|
|
57
|
+
const packageId = positionals.find(a => a.startsWith('tp-'));
|
|
58
|
+
if (!packageId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab training-package show <package-id>');
|
|
55
59
|
|
|
56
60
|
const pkg = await loadTrainingPackage(projectRoot, packageId);
|
|
57
61
|
console.log(`\x1b[1mTraining package\x1b[0m — ${packageId}\n`);
|
|
@@ -75,10 +79,10 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
} else {
|
|
78
|
-
throw
|
|
82
|
+
throw inputError('INPUT_BAD_SUBCOMMAND', `Unknown subcommand: ${subcommand}. Use: build, show, list`);
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
if (process.argv[1] && (process.argv[1].endsWith('training-package.js') || process.argv[1].endsWith('training-package'))) {
|
|
83
|
-
run().catch(
|
|
87
|
+
run().catch(handleCliError);
|
|
84
88
|
}
|
|
@@ -9,15 +9,20 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { join } from 'node:path';
|
|
12
|
-
import { getProjectName } from '../lib/args.js';
|
|
12
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
13
13
|
import { REPO_ROOT } from '../lib/paths.js';
|
|
14
|
+
import { inputError, handleCliError } from '../lib/errors.js';
|
|
14
15
|
import { listTrainingProfiles, loadTrainingProfile } from '../lib/training-profiles.js';
|
|
15
16
|
|
|
16
17
|
export async function run(argv = process.argv.slice(2)) {
|
|
17
|
-
const
|
|
18
|
+
const { flags, positionals } = parseArgs(argv, {
|
|
19
|
+
flags: { project: { type: 'string' } },
|
|
20
|
+
deprecated: { game: 'project' },
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const projectName = flags.project || getProjectName(argv);
|
|
18
24
|
const projectRoot = join(REPO_ROOT, 'projects', projectName);
|
|
19
|
-
const subcommand =
|
|
20
|
-
const args = argv.filter(a => a !== subcommand);
|
|
25
|
+
const subcommand = positionals[0] || 'list';
|
|
21
26
|
|
|
22
27
|
if (subcommand === 'list') {
|
|
23
28
|
const profiles = await listTrainingProfiles(projectRoot);
|
|
@@ -31,8 +36,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
31
36
|
}
|
|
32
37
|
|
|
33
38
|
} else if (subcommand === 'show') {
|
|
34
|
-
const profileId =
|
|
35
|
-
if (!profileId) throw
|
|
39
|
+
const profileId = positionals[1];
|
|
40
|
+
if (!profileId) throw inputError('INPUT_MISSING_ARGS', 'Usage: sdlab training-profile show <profile-id>');
|
|
36
41
|
|
|
37
42
|
const profile = await loadTrainingProfile(projectRoot, profileId);
|
|
38
43
|
console.log(`\x1b[1mTraining profile\x1b[0m — ${profileId}\n`);
|
|
@@ -54,10 +59,10 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
} else {
|
|
57
|
-
throw
|
|
62
|
+
throw inputError('INPUT_BAD_SUBCOMMAND', `Unknown subcommand: ${subcommand}. Use: list, show`);
|
|
58
63
|
}
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
if (process.argv[1] && (process.argv[1].endsWith('training-profile.js') || process.argv[1].endsWith('training-profile'))) {
|
|
62
|
-
run().catch(
|
|
67
|
+
run().catch(handleCliError);
|
|
63
68
|
}
|
package/scripts/workflow-list.js
CHANGED
|
@@ -15,13 +15,13 @@ import { listWorkflowProfiles } from '../lib/workflow-profiles.js';
|
|
|
15
15
|
export async function run(argv = process.argv.slice(2)) {
|
|
16
16
|
const { flags } = parseArgs(argv, {
|
|
17
17
|
flags: {
|
|
18
|
-
project: { type: 'string'
|
|
18
|
+
project: { type: 'string' },
|
|
19
19
|
json: { type: 'boolean' },
|
|
20
20
|
},
|
|
21
21
|
deprecated: { game: 'project' },
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
const projectName = flags.project;
|
|
24
|
+
const projectName = flags.project || getProjectName(argv);
|
|
25
25
|
const projectRoot = getProjectRoot(projectName);
|
|
26
26
|
const profiles = await listWorkflowProfiles(projectRoot);
|
|
27
27
|
|
package/scripts/workflow-show.js
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
* sdlab workflow show character-portrait-set --json
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { parseArgs } from '../lib/args.js';
|
|
11
|
+
import { parseArgs, getProjectName } from '../lib/args.js';
|
|
12
12
|
import { getProjectRoot } from '../lib/paths.js';
|
|
13
13
|
import { getWorkflowProfile } from '../lib/workflow-profiles.js';
|
|
14
14
|
|
|
15
15
|
export async function run(argv = process.argv.slice(2)) {
|
|
16
16
|
const { flags, positionals } = parseArgs(argv, {
|
|
17
17
|
flags: {
|
|
18
|
-
project: { type: 'string'
|
|
18
|
+
project: { type: 'string' },
|
|
19
19
|
json: { type: 'boolean' },
|
|
20
20
|
},
|
|
21
21
|
positionals: ['workflowId'],
|
|
@@ -28,7 +28,8 @@ export async function run(argv = process.argv.slice(2)) {
|
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const
|
|
31
|
+
const projectName = flags.project || getProjectName(argv);
|
|
32
|
+
const projectRoot = getProjectRoot(projectName);
|
|
32
33
|
const profile = await getWorkflowProfile(projectRoot, workflowId);
|
|
33
34
|
|
|
34
35
|
if (flags.json) {
|