@mcptoolshop/style-dataset-lab 3.3.0 → 3.5.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.
Files changed (119) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.es.md +117 -55
  3. package/README.fr.md +125 -65
  4. package/README.hi.md +117 -68
  5. package/README.it.md +119 -58
  6. package/README.ja.md +124 -74
  7. package/README.md +73 -7
  8. package/README.pt-BR.md +128 -63
  9. package/README.zh.md +116 -65
  10. package/bin/sdlab.js +100 -4
  11. package/lib/adapters/ai-toolkit.js +224 -35
  12. package/lib/adapters/comfyui-runner.js +79 -26
  13. package/lib/adapters/comfyui-workflows.js +94 -11
  14. package/lib/adapters/diffusers-lora.js +37 -5
  15. package/lib/adapters/generic-image-caption.js +43 -5
  16. package/lib/args.js +16 -1
  17. package/lib/asset-ingest.js +575 -0
  18. package/lib/asset-masks.js +323 -0
  19. package/lib/asset-source.js +1176 -0
  20. package/lib/batch-modes.js +29 -8
  21. package/lib/batch-runs.js +29 -1
  22. package/lib/batch-sheet-render.js +13 -3
  23. package/lib/brief-compiler.js +19 -0
  24. package/lib/candidate-sheet.js +327 -0
  25. package/lib/canon-author.js +350 -0
  26. package/lib/canon-build/build.js +146 -93
  27. package/lib/canon-review-gate.js +205 -0
  28. package/lib/captions.js +57 -0
  29. package/lib/card.js +74 -2
  30. package/lib/colab-launcher-guards.js +285 -0
  31. package/lib/comfyui.js +116 -18
  32. package/lib/config.js +116 -12
  33. package/lib/critique-engine.js +36 -2
  34. package/lib/eligibility.js +121 -9
  35. package/lib/eval-pack.js +14 -14
  36. package/lib/eval-runs.js +33 -0
  37. package/lib/export.js +122 -34
  38. package/lib/freeze-gate.js +16 -3
  39. package/lib/freeze-stamp.js +28 -3
  40. package/lib/generated-provenance.js +194 -6
  41. package/lib/implementation-packs.js +95 -17
  42. package/lib/ingest.js +396 -0
  43. package/lib/judgment-provenance.js +220 -0
  44. package/lib/lane1-render.js +668 -0
  45. package/lib/measure.js +422 -0
  46. package/lib/memory-store.js +663 -0
  47. package/lib/model-licences.js +305 -0
  48. package/lib/npy-meta.js +130 -0
  49. package/lib/paths.js +196 -7
  50. package/lib/png-meta.js +512 -0
  51. package/lib/records.js +54 -8
  52. package/lib/reingest-selected.js +113 -17
  53. package/lib/reingest.js +27 -3
  54. package/lib/run-manifest.js +159 -25
  55. package/lib/run-summary.js +12 -6
  56. package/lib/runtime-runs.js +45 -4
  57. package/lib/snapshot.js +114 -15
  58. package/lib/split.js +364 -48
  59. package/lib/train-runs.js +214 -0
  60. package/lib/training-manifests.js +114 -21
  61. package/lib/training-packages.js +147 -15
  62. package/lib/verifier.js +3 -0
  63. package/lib/verify-chain.js +367 -0
  64. package/lib/workflow-profiles.js +24 -3
  65. package/package.json +4 -3
  66. package/runtime/comfyui/txt2img-qwen.json +38 -0
  67. package/runtime/comfyui/txt2img-standard.json +21 -0
  68. package/scripts/_resume.js +62 -0
  69. package/scripts/_shared-args.js +44 -0
  70. package/scripts/asset-ingest.js +160 -0
  71. package/scripts/brief-compile.js +2 -1
  72. package/scripts/brief-show.js +2 -1
  73. package/scripts/canon-bind.js +2 -2
  74. package/scripts/canon-build.js +27 -20
  75. package/scripts/canon-draft.js +82 -0
  76. package/scripts/canon-drift.js +16 -7
  77. package/scripts/canon-freeze-status.js +14 -6
  78. package/scripts/canon-freeze.js +31 -11
  79. package/scripts/canon-unfreeze.js +17 -9
  80. package/scripts/card.js +2 -2
  81. package/scripts/colab/REAL_SERVICE_ASSUMPTIONS.md +14 -0
  82. package/scripts/colab/ai-toolkit-override-py315.txt +45 -0
  83. package/scripts/colab/colab_window.sh +587 -0
  84. package/scripts/colab/lane1_render.py +970 -0
  85. package/scripts/colab/launch_guards.py +564 -0
  86. package/scripts/colab/launch_lane1_stub.sh +309 -0
  87. package/scripts/colab/launch_lane3_stub.sh +366 -0
  88. package/scripts/colab/remote_runner.py +59 -0
  89. package/scripts/compare.js +2 -2
  90. package/scripts/critique.js +16 -1
  91. package/scripts/curate.js +2 -2
  92. package/scripts/doctor.js +182 -55
  93. package/scripts/eligibility.js +42 -2
  94. package/scripts/eval-pack.js +2 -2
  95. package/scripts/eval-run.js +2 -2
  96. package/scripts/export.js +2 -2
  97. package/scripts/generate-controlnet.js +45 -25
  98. package/scripts/generate-identity.js +53 -23
  99. package/scripts/generate-ipadapter.js +44 -23
  100. package/scripts/generate.js +86 -17
  101. package/scripts/implementation-pack.js +2 -2
  102. package/scripts/ingest.js +145 -0
  103. package/scripts/init.js +73 -13
  104. package/scripts/measure.js +170 -0
  105. package/scripts/measure_image.py +458 -0
  106. package/scripts/migrate-records.js +142 -0
  107. package/scripts/painterly-test.js +4 -3
  108. package/scripts/painterly.js +7 -3
  109. package/scripts/qwen_generate.py +138 -20
  110. package/scripts/reingest.js +2 -2
  111. package/scripts/sheet.js +142 -0
  112. package/scripts/snapshot.js +2 -2
  113. package/scripts/split.js +2 -2
  114. package/scripts/training-manifest.js +2 -2
  115. package/scripts/training-package.js +2 -2
  116. package/scripts/training-profile.js +2 -2
  117. package/scripts/verify.js +67 -0
  118. package/scripts/workflow-list.js +2 -1
  119. package/scripts/workflow-show.js +2 -1
@@ -16,6 +16,8 @@ import { writeFile, mkdir, symlink, copyFile } from 'node:fs/promises';
16
16
  import { join, relative } from 'node:path';
17
17
  import { existsSync } from 'node:fs';
18
18
  import { groupRowsByPartition } from '../rows.js';
19
+ import { assertSafeAssetPath, assertSafeId } from '../export.js';
20
+ import { warn } from '../log.js';
19
21
 
20
22
  /**
21
23
  * Build training package in diffusers LoRA format from canonical rows.
@@ -33,6 +35,11 @@ export async function buildPackage({ packageDir, rows, profile, manifest, config
33
35
  const partitioned = groupRowsByPartition(rows || []);
34
36
 
35
37
  let imageCount = 0;
38
+ // SDL-C5: per-row failure accounting (export.js DB-002 shape) — see
39
+ // generic-image-caption.js for the full rationale. A caught copy/symlink
40
+ // error must not silently drop the image, caption sidecar, AND metadata
41
+ // row together with zero logging.
42
+ const imagesFailed = [];
36
43
 
37
44
  for (const [partition, partitionRows] of Object.entries(partitioned)) {
38
45
  const datasetDir = join(packageDir, 'dataset', partition);
@@ -43,10 +50,21 @@ export async function buildPackage({ packageDir, rows, profile, manifest, config
43
50
  const metadataRows = [];
44
51
 
45
52
  for (const row of partitionRows) {
46
- if (!row.asset_path) continue;
53
+ if (!row.asset_path) {
54
+ imagesFailed.push({ record_id: row.entity_id, partition, reason: 'missing_asset_path' });
55
+ continue;
56
+ }
47
57
 
48
- const sourcePath = join(projectRoot, row.asset_path);
49
- if (!existsSync(sourcePath)) continue;
58
+ // SDL-H5 / SDL-H6: defense-in-depth — see generic-image-caption.js
59
+ // for the full rationale. Throws (hard fail) on traversal/unsafe id;
60
+ // that is a security boundary, not an operational hiccup.
61
+ assertSafeId(row.entity_id, `row.entity_id in diffusers-lora adapter (partition "${partition}")`);
62
+ const sourcePath = assertSafeAssetPath(row.asset_path, projectRoot, row.entity_id);
63
+
64
+ if (!existsSync(sourcePath)) {
65
+ imagesFailed.push({ record_id: row.entity_id, partition, reason: 'source_missing' });
66
+ continue;
67
+ }
50
68
 
51
69
  const sourceBasename = row.asset_path.split(/[\\/]/).pop();
52
70
  const extMatch = sourceBasename.match(/\.[^.]+$/);
@@ -62,7 +80,13 @@ export async function buildPackage({ packageDir, rows, profile, manifest, config
62
80
  await symlink(relative(datasetDir, sourcePath), destPath);
63
81
  }
64
82
  imageCount++;
65
- } catch {
83
+ } catch (err) {
84
+ imagesFailed.push({
85
+ record_id: row.entity_id,
86
+ partition,
87
+ reason: copy ? 'copy_failed' : 'link_failed',
88
+ detail: err.message,
89
+ });
66
90
  continue;
67
91
  }
68
92
 
@@ -77,7 +101,15 @@ export async function buildPackage({ packageDir, rows, profile, manifest, config
77
101
  );
78
102
  }
79
103
 
80
- return { imageCount };
104
+ if (imagesFailed.length > 0) {
105
+ const sample = imagesFailed.slice(0, 10).map(f => `${f.record_id} (${f.reason})`);
106
+ warn(
107
+ `diffusers-lora adapter: ${imagesFailed.length} of ${imageCount + imagesFailed.length} rows failed to place` +
108
+ (imagesFailed.length > 10 ? ` — first 10: ${sample.join(', ')}, ...` : ` — ${sample.join(', ')}`),
109
+ );
110
+ }
111
+
112
+ return { imageCount, imagesFailed };
81
113
  }
82
114
 
83
115
  function buildMetadataRow(row, partition, filename, stem) {
@@ -14,11 +14,20 @@ import { writeFile, mkdir, symlink, copyFile } from 'node:fs/promises';
14
14
  import { join, relative } from 'node:path';
15
15
  import { existsSync } from 'node:fs';
16
16
  import { groupRowsByPartition } from '../rows.js';
17
+ import { assertSafeAssetPath, assertSafeId } from '../export.js';
18
+ import { warn } from '../log.js';
17
19
 
18
20
  export async function buildPackage({ packageDir, rows, profile, manifest, config, projectRoot, copy }) {
19
21
  const partitioned = groupRowsByPartition(rows || []);
20
22
 
21
23
  let imageCount = 0;
24
+ // SDL-C5: per-row failure accounting (export.js DB-002 shape). The old
25
+ // bare `catch { continue; }` silently dropped the image, the caption
26
+ // sidecar, AND the metadata row together with no logging — on Windows
27
+ // without Developer Mode this fired on every row, so imageCount stayed
28
+ // 0 and the build still reported success. Every drop is now accounted
29
+ // for and returned to the caller.
30
+ const imagesFailed = [];
22
31
 
23
32
  for (const [partition, partitionRows] of Object.entries(partitioned)) {
24
33
  const datasetDir = join(packageDir, 'dataset', partition);
@@ -29,10 +38,25 @@ export async function buildPackage({ packageDir, rows, profile, manifest, config
29
38
  const metadataRows = [];
30
39
 
31
40
  for (const row of partitionRows) {
32
- if (!row.asset_path) continue;
41
+ if (!row.asset_path) {
42
+ imagesFailed.push({ record_id: row.entity_id, partition, reason: 'missing_asset_path' });
43
+ continue;
44
+ }
33
45
 
34
- const sourcePath = join(projectRoot, row.asset_path);
35
- if (!existsSync(sourcePath)) continue;
46
+ // SDL-H5 / SDL-H6: defense-in-depth. buildTrainingPackage validates
47
+ // every row before dispatching here, but this adapter is also
48
+ // unit-tested (and documented in lib/rows.js as a future direct
49
+ // canon-build target) independent of that caller, so the guard
50
+ // lives here too. A traversal / unsafe id is a security boundary,
51
+ // not an operational hiccup — it throws (hard fail) rather than
52
+ // joining the soft imagesFailed accounting below.
53
+ assertSafeId(row.entity_id, `row.entity_id in generic-image-caption adapter (partition "${partition}")`);
54
+ const sourcePath = assertSafeAssetPath(row.asset_path, projectRoot, row.entity_id);
55
+
56
+ if (!existsSync(sourcePath)) {
57
+ imagesFailed.push({ record_id: row.entity_id, partition, reason: 'source_missing' });
58
+ continue;
59
+ }
36
60
 
37
61
  const sourceBasename = row.asset_path.split(/[\\/]/).pop();
38
62
  const extMatch = sourceBasename.match(/\.[^.]+$/);
@@ -47,7 +71,13 @@ export async function buildPackage({ packageDir, rows, profile, manifest, config
47
71
  await symlink(relative(datasetDir, sourcePath), destPath);
48
72
  }
49
73
  imageCount++;
50
- } catch {
74
+ } catch (err) {
75
+ imagesFailed.push({
76
+ record_id: row.entity_id,
77
+ partition,
78
+ reason: copy ? 'copy_failed' : 'link_failed',
79
+ detail: err.message,
80
+ });
51
81
  continue;
52
82
  }
53
83
 
@@ -67,5 +97,13 @@ export async function buildPackage({ packageDir, rows, profile, manifest, config
67
97
  );
68
98
  }
69
99
 
70
- return { imageCount };
100
+ if (imagesFailed.length > 0) {
101
+ const sample = imagesFailed.slice(0, 10).map(f => `${f.record_id} (${f.reason})`);
102
+ warn(
103
+ `generic-image-caption adapter: ${imagesFailed.length} of ${imageCount + imagesFailed.length} rows failed to place` +
104
+ (imagesFailed.length > 10 ? ` — first 10: ${sample.join(', ')}, ...` : ` — ${sample.join(', ')}`),
105
+ );
106
+ }
107
+
108
+ return { imageCount, imagesFailed };
71
109
  }
package/lib/args.js CHANGED
@@ -149,8 +149,23 @@ export function getProjectName(argv) {
149
149
  for (let i = 0; i < argv.length; i++) {
150
150
  const a = argv[i];
151
151
  if (a === '--project' || a === '--game') {
152
+ const flagName = a === '--game' ? 'game' : 'project';
152
153
  if (a === '--game') warnDeprecated('game', 'project');
153
- explicit = argv[i + 1];
154
+ const next = argv[i + 1];
155
+ // SDL-L1: mirror takeFlagValue's guard below — without it, a missing
156
+ // value silently swallowed the NEXT flag as the project name (e.g.
157
+ // `--project --dry-run` yielded the project name "--dry-run").
158
+ if (next === undefined) {
159
+ throw inputError('INPUT_MISSING_VALUE', `Flag --${flagName} requires a value.`);
160
+ }
161
+ if (next.startsWith('--')) {
162
+ throw inputError(
163
+ 'INPUT_MISSING_VALUE',
164
+ `Flag --${flagName} is missing its value (got another flag: ${next}).`,
165
+ `Pass a value after --${flagName}.`
166
+ );
167
+ }
168
+ explicit = next;
154
169
  break;
155
170
  }
156
171
  if (a.startsWith('--project=')) { explicit = a.slice('--project='.length); break; }