@tiangong-lca/cli 0.0.10 → 0.0.12

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 (56) hide show
  1. package/README.md +18 -4
  2. package/assets/tidas-schemas/tidas_contacts.json +312 -0
  3. package/assets/tidas-schemas/tidas_contacts_category.json +126 -0
  4. package/assets/tidas-schemas/tidas_data_types.json +359 -0
  5. package/assets/tidas-schemas/tidas_flowproperties.json +303 -0
  6. package/assets/tidas-schemas/tidas_flowproperties_category.json +61 -0
  7. package/assets/tidas-schemas/tidas_flows.json +809 -0
  8. package/assets/tidas-schemas/tidas_flows_elementary_category.json +720 -0
  9. package/assets/tidas-schemas/tidas_flows_product_category.json +59623 -0
  10. package/assets/tidas-schemas/tidas_lciamethods.json +1326 -0
  11. package/assets/tidas-schemas/tidas_lciamethods_category.json +685 -0
  12. package/assets/tidas-schemas/tidas_lifecyclemodels.json +1374 -0
  13. package/assets/tidas-schemas/tidas_locations_category.json +2593 -0
  14. package/assets/tidas-schemas/tidas_processes.json +1646 -0
  15. package/assets/tidas-schemas/tidas_processes_category.json +10795 -0
  16. package/assets/tidas-schemas/tidas_sources.json +228 -0
  17. package/assets/tidas-schemas/tidas_sources_category.json +100 -0
  18. package/assets/tidas-schemas/tidas_unitgroups.json +338 -0
  19. package/assets/tidas-schemas/tidas_unitgroups_category.json +61 -0
  20. package/dist/src/cli.js +948 -8
  21. package/dist/src/cli.js.map +1 -1
  22. package/dist/src/lib/dataset-classification.js +947 -0
  23. package/dist/src/lib/dataset-classification.js.map +1 -0
  24. package/dist/src/lib/dataset-command.js +11 -0
  25. package/dist/src/lib/dataset-command.js.map +1 -1
  26. package/dist/src/lib/dataset-contract.js +2 -0
  27. package/dist/src/lib/dataset-contract.js.map +1 -1
  28. package/dist/src/lib/dataset-curation-queue.js +768 -0
  29. package/dist/src/lib/dataset-curation-queue.js.map +1 -0
  30. package/dist/src/lib/dataset-import-lca.js +18 -0
  31. package/dist/src/lib/dataset-import-lca.js.map +1 -1
  32. package/dist/src/lib/dataset-local.js +94 -1
  33. package/dist/src/lib/dataset-local.js.map +1 -1
  34. package/dist/src/lib/dataset-maintenance-clear-account.js +506 -0
  35. package/dist/src/lib/dataset-maintenance-clear-account.js.map +1 -0
  36. package/dist/src/lib/dataset-patch.js +797 -0
  37. package/dist/src/lib/dataset-patch.js.map +1 -0
  38. package/dist/src/lib/dataset-remote-verify.js +188 -3
  39. package/dist/src/lib/dataset-remote-verify.js.map +1 -1
  40. package/dist/src/lib/dataset-save-draft-run.js +725 -0
  41. package/dist/src/lib/dataset-save-draft-run.js.map +1 -0
  42. package/dist/src/lib/dataset-validate.js +32 -2
  43. package/dist/src/lib/dataset-validate.js.map +1 -1
  44. package/dist/src/lib/flow-publish-version.js +7 -2
  45. package/dist/src/lib/flow-publish-version.js.map +1 -1
  46. package/dist/src/lib/flow-qa.js +8 -0
  47. package/dist/src/lib/flow-qa.js.map +1 -1
  48. package/dist/src/lib/identity-preflight.js +895 -117
  49. package/dist/src/lib/identity-preflight.js.map +1 -1
  50. package/dist/src/lib/lifecyclemodel-qa.js +159 -34
  51. package/dist/src/lib/lifecyclemodel-qa.js.map +1 -1
  52. package/dist/src/lib/process-required-fields.js +62 -12
  53. package/dist/src/lib/process-required-fields.js.map +1 -1
  54. package/dist/src/lib/supabase-client.js +19 -8
  55. package/dist/src/lib/supabase-client.js.map +1 -1
  56. package/package.json +2 -1
package/dist/src/cli.js CHANGED
@@ -41,6 +41,7 @@ import { runFlowApplyProcessFlowRepairs, runFlowPlanProcessFlowRepairs, runFlowR
41
41
  import { executeRemoteCommand, getRemoteCommandHelp } from './lib/remote.js';
42
42
  import { runValidation, } from './lib/validation.js';
43
43
  import { runDatasetValidate, } from './lib/dataset-validate.js';
44
+ import { runDatasetCurationQueueBuild, runDatasetCurationQueueNext, runDatasetCurationQueueVerify, } from './lib/dataset-curation-queue.js';
44
45
  import { runDatasetReferencesRewrite, } from './lib/dataset-references-rewrite.js';
45
46
  import { runDatasetRemoteRefresh, } from './lib/dataset-remote-refresh.js';
46
47
  import { runDatasetRemoteVerify, } from './lib/dataset-remote-verify.js';
@@ -49,6 +50,10 @@ import { runDatasetEvidenceSearch, } from './lib/dataset-evidence-search.js';
49
50
  import { runDatasetContract, } from './lib/dataset-contract.js';
50
51
  import { runDatasetImportLcaConvert, } from './lib/dataset-import-lca.js';
51
52
  import { runDatasetAuthor, } from './lib/dataset-author.js';
53
+ import { runDatasetPatchApply, } from './lib/dataset-patch.js';
54
+ import { runDatasetSaveDraft, } from './lib/dataset-save-draft-run.js';
55
+ import { runDatasetClassificationApply, runDatasetClassificationAudit, runDatasetClassificationChildren, runDatasetClassificationPath, } from './lib/dataset-classification.js';
56
+ import { runDatasetMaintenanceClearAccount, } from './lib/dataset-maintenance-clear-account.js';
52
57
  function renderMainHelp(dotEnvStatus) {
53
58
  return `TianGong LCA CLI
54
59
 
@@ -68,7 +73,7 @@ Implemented Commands:
68
73
  doctor show environment diagnostics
69
74
  search flow | process | lifecyclemodel
70
75
  process get | list | identity-preflight | build-plan | scope-statistics | dedup-review | auto-build | resume-build | publish-build | complete-required-fields | save-draft | batch-build | refresh-references | verify-rows
71
- dataset contract get | context-pack | import-lca convert | author | validate | verify-remote | bilingual extract/apply/validate | evidence-search plan/run | references rewrite/refresh-remote
76
+ dataset contract get | context-pack | classification children/path/audit/apply | curation-queue build/next/verify | import-lca convert | author | patch apply | save-draft | validate | verify-remote | bilingual extract/apply/validate | evidence-search plan/run | references rewrite/refresh-remote | maintenance clear-account
72
77
  flow get | list | identity-preflight | build-plan | fetch-rows | materialize-decisions | remediate | publish-version | publish-reviewed-data | build-alias-map | scan-process-flow-refs | plan-process-flow-repairs | apply-process-flow-repairs | regen-product | validate-processes
73
78
  lifecyclemodel auto-build | validate-build | publish-build | save-draft | graph | build-resulting-process | publish-resulting-process | orchestrate
74
79
  qa process | flow | lifecyclemodel
@@ -79,6 +84,7 @@ Implemented Commands:
79
84
  Planned Surface (not implemented yet):
80
85
  auth whoami | doctor-auth
81
86
  job get | wait | logs
87
+ dataset maintenance plan | apply | verify
82
88
 
83
89
  Planned commands currently print an explicit "not implemented yet" message and exit with code 2.
84
90
 
@@ -103,8 +109,16 @@ Examples:
103
109
  tiangong-lca dataset validate --input ./rows.jsonl --type auto --out-dir /abs/path/to/dataset-validate
104
110
  tiangong-lca dataset contract get --type process --include schema,methodology,ruleset --out-dir ./contract
105
111
  tiangong-lca dataset context-pack --type process --profile ai-import --out-dir ./context-pack
112
+ tiangong-lca dataset classification children --type process --parent A --out-dir ./classification --json
113
+ tiangong-lca dataset classification path --type process --code 1080 --out-dir ./classification --json
114
+ tiangong-lca dataset classification audit --type location --input ./rows/processes.jsonl --out-dir ./classification --json
115
+ tiangong-lca dataset classification apply --input ./rows/processes.jsonl --decisions ./classification-decisions.jsonl --out ./rows/processes.classified.jsonl --type process --out-dir ./classification --json
116
+ tiangong-lca dataset curation-queue build --processes ./processes.jsonl --flows ./flows.jsonl --out-dir ./curation-queue
117
+ tiangong-lca dataset curation-queue next --queue-dir ./curation-queue --type support
118
+ tiangong-lca dataset curation-queue verify --queue-dir ./curation-queue --type process
106
119
  tiangong-lca dataset import-lca convert --input ./external-package --output-dir ./converted --from-format auto --target tidas
107
120
  tiangong-lca dataset author --input ./source.pdf --target-types process,flow --out-dir ./authoring
121
+ tiangong-lca dataset save-draft --input ./contacts.jsonl --type contact --out-dir /abs/path/to/contact-save-draft --commit
108
122
  tiangong-lca dataset verify-remote --input ./rows.jsonl --out-dir /abs/path/to/dataset-remote-verify
109
123
  tiangong-lca dataset bilingual extract --input ./rows/processes.jsonl --type process --out-dir ./translation
110
124
  tiangong-lca dataset bilingual apply --input ./rows/processes.jsonl --translations ./translation/trans-reviewed.jsonl --out ./rows/processes.translated.jsonl
@@ -112,6 +126,8 @@ Examples:
112
126
  tiangong-lca dataset evidence-search plan --query "中国2026年电力结构数据" --out-dir ./evidence-search
113
127
  tiangong-lca dataset evidence-search run --input ./evidence-search.request.json --results ./search-results.json --out-dir ./evidence-search
114
128
  tiangong-lca dataset references rewrite --input ./rows.jsonl --from flow:<old-id>@<old-version> --to flow:<new-id>@<new-version> --out-dir /abs/path/to/dataset-rewrite
129
+ tiangong-lca dataset maintenance clear-account --out-dir /abs/path/to/account-clear --json
130
+ tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation redo-import --out-dir /abs/path/to/dataset-maintenance
115
131
  tiangong-lca lifecyclemodel auto-build --input ./lifecyclemodel-auto-build.request.json --out-dir /abs/path/to/lifecyclemodel-run
116
132
  tiangong-lca lifecyclemodel validate-build --run-dir /abs/path/to/lifecyclemodel-run
117
133
  tiangong-lca lifecyclemodel publish-build --run-dir /abs/path/to/lifecyclemodel-run
@@ -136,7 +152,7 @@ Examples:
136
152
  tiangong-lca qa process --rows-file ./processes.jsonl --out-dir ./qa
137
153
  tiangong-lca qa process --run-root /abs/path/to/process-run --run-id <run_id> --out-dir ./qa
138
154
  tiangong-lca qa flow --rows-file ./flows.json --out-dir ./qa
139
- tiangong-lca qa lifecyclemodel --run-dir /abs/path/to/lifecyclemodel-run --out-dir ./lifecyclemodel-qa
155
+ tiangong-lca qa lifecyclemodel --rows-file ./lifecyclemodels.jsonl --out-dir ./lifecyclemodel-qa
140
156
  tiangong-lca publish run --input ./publish-request.json --dry-run
141
157
  tiangong-lca validation run --input-dir ./package --engine auto
142
158
  tiangong-lca admin embedding-run --input ./jobs.json
@@ -244,8 +260,14 @@ function renderDatasetHelp() {
244
260
  Implemented Subcommands:
245
261
  contract get Write TIDAS schema / methodology / ruleset contract artifacts
246
262
  context-pack Write an AI-ready TIDAS contract context pack
263
+ classification Navigate bundled TIDAS classification schemas or apply selected classifications
264
+ curation-queue build Build entity-level AI curation queue artifacts for Foundry imports
265
+ curation-queue next Return the next runnable support/flow/process queue task
266
+ curation-queue verify Verify queue task checkpoints for a scope
247
267
  import-lca convert Convert supported external LCA packages through tidas-tools
248
268
  author Extract source evidence and prepare TIDAS context packs for AI authoring
269
+ patch apply Apply AI-authored structured dataset patches deterministically
270
+ save-draft Save contact/source/support or other canonical dataset rows through the platform dataset command path
249
271
  validate Validate local flow / process / lifecyclemodel rows with the TIDAS SDK
250
272
  verify-remote Verify dataset roots and TIDAS references against remote published versions
251
273
  bilingual extract Extract bilingual translation units from local rows
@@ -254,12 +276,25 @@ Implemented Subcommands:
254
276
  evidence-search Plan or record field-level public evidence retrieval
255
277
  references rewrite Rewrite flow references in local process and lifecyclemodel rows
256
278
  references refresh-remote Refresh local TIDAS reference versions to latest reachable remote rows
279
+ maintenance clear-account Dry-run or clear current authenticated account-owned dataset rows through RLS
280
+
281
+ Planned Subcommands:
282
+ maintenance plan/apply/verify Plan, execute, and verify RLS-scoped dataset delete/redo maintenance
257
283
 
258
284
  Examples:
259
285
  tiangong-lca dataset contract get --type process --include schema,methodology,ruleset --out-dir ./contract --help
260
286
  tiangong-lca dataset context-pack --type process --profile ai-import --out-dir ./context-pack --help
287
+ tiangong-lca dataset classification children --type process --parent A --out-dir ./classification --help
288
+ tiangong-lca dataset classification path --type process --code 1080 --out-dir ./classification --help
289
+ tiangong-lca dataset classification audit --type location --input ./rows/processes.jsonl --out-dir ./classification --help
290
+ tiangong-lca dataset classification apply --input ./rows/processes.jsonl --decisions ./classification-decisions.jsonl --out ./rows/processes.classified.jsonl --type process --out-dir ./classification --help
291
+ tiangong-lca dataset curation-queue build --processes ./rows/processes.jsonl --flows ./rows/flows.jsonl --support ./rows/sources.jsonl --out-dir ./curation-queue --help
292
+ tiangong-lca dataset curation-queue next --queue-dir ./curation-queue --type flow --json
293
+ tiangong-lca dataset curation-queue verify --queue-dir ./curation-queue --task-id process:abc@00.00.001 --json
261
294
  tiangong-lca dataset import-lca convert --input ./external-package --output-dir ./converted --from-format auto --target tidas --help
262
295
  tiangong-lca dataset author --input ./source.pdf --target-types process,flow --out-dir ./authoring --help
296
+ tiangong-lca dataset patch apply --input ./rows.jsonl --patch ./ai-patches.json --out ./rows.patched.jsonl --out-dir ./patch-apply --help
297
+ tiangong-lca dataset save-draft --input ./contacts.jsonl --type contact --out-dir ./contact-save-draft --commit --help
263
298
  tiangong-lca dataset validate --input ./rows.jsonl --type auto --out-dir ./dataset-validate --help
264
299
  tiangong-lca dataset verify-remote --input ./rows.jsonl --out-dir ./dataset-remote-verify --help
265
300
  tiangong-lca dataset bilingual extract --input ./rows.jsonl --type process --out-dir ./translation --help
@@ -269,6 +304,69 @@ Examples:
269
304
  tiangong-lca dataset evidence-search run --input ./request.json --results ./search-results.json --out-dir ./evidence-search --help
270
305
  tiangong-lca dataset references rewrite --input ./rows.jsonl --from flow:<old-id>@<old-version> --to flow:<new-id>@<new-version> --out-dir ./dataset-rewrite --help
271
306
  tiangong-lca dataset references refresh-remote --input ./rows.jsonl --out ./rows.refreshed.jsonl --out-dir ./dataset-reference-refresh --help
307
+ tiangong-lca dataset maintenance clear-account --out-dir ./account-clear --json --help
308
+ tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation redo-import --out-dir ./dataset-maintenance --help
309
+ `.trim();
310
+ }
311
+ function renderDatasetMaintenanceHelp() {
312
+ return `Usage:
313
+ tiangong-lca dataset maintenance <clear-account|plan|apply|verify> [options]
314
+
315
+ Status:
316
+ clear-account is implemented for current authenticated account cleanup.
317
+ plan/apply/verify remain reserved for row-level RLS-scoped cleanup and redo workflows and currently exit with code 2 for executable actions.
318
+
319
+ Implemented Actions:
320
+ clear-account Dry-run or delete current authenticated account-owned lifecyclemodels, processes, flows, sources, and contacts.
321
+
322
+ Planned Actions:
323
+ plan Build an immutable maintenance plan from a scope manifest, visible remote snapshot, dependency impact report, and intended operation.
324
+ apply Execute an approved plan through current-user RLS and platform dataset command paths; never bypass RLS or delete rows outside the visible scope.
325
+ verify Re-fetch affected rows and references, then prove that deleted, updated, skipped, protected, and redone rows match the plan.
326
+
327
+ Required Artifact Contract:
328
+ - maintenance-plan.json
329
+ - rls-visible-snapshot.json
330
+ - protected-rows.jsonl
331
+ - reference-impact-report.json
332
+ - dry-run-report.json
333
+ - commit-report.json
334
+ - readback-verify-report.json
335
+
336
+ Examples:
337
+ tiangong-lca dataset maintenance clear-account --out-dir ./account-clear --json
338
+ tiangong-lca dataset maintenance clear-account --commit --confirm user@example.com --out-dir ./account-clear
339
+ tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation redo-import --out-dir ./dataset-maintenance
340
+ tiangong-lca dataset maintenance apply --plan ./dataset-maintenance/maintenance-plan.json --commit
341
+ tiangong-lca dataset maintenance verify --plan ./dataset-maintenance/maintenance-plan.json --out-dir ./dataset-maintenance/verify
342
+ `.trim();
343
+ }
344
+ function renderDatasetMaintenanceClearAccountHelp() {
345
+ return `Usage:
346
+ tiangong-lca dataset maintenance clear-account [options]
347
+
348
+ Behavior:
349
+ Dry-run by default. With --commit, deletes only rows visible to the current authenticated user and filtered by user_id through RLS.
350
+ Tables are deleted in reference-safe order: lifecyclemodels, processes, flows, sources, contacts.
351
+ Unit groups and flow properties are not deleted by this command because they are treated as protected support data.
352
+
353
+ Options:
354
+ --state-code <n> Optional repeatable state_code filter. Omit to clear all state codes for the current account.
355
+ --out-dir <dir> Artifact directory (default: ./dataset-maintenance/clear-account)
356
+ --page-size <n> Snapshot page size, 1-5000 (default: 1000)
357
+ --timeout-ms <n> Request timeout in milliseconds (default: 10000)
358
+ --commit Execute deletion. Without this flag the command only writes a dry-run report.
359
+ --dry-run Explicit dry-run mode
360
+ --confirm <email> Required with --commit; must match the current authenticated account email
361
+ --json Print compact JSON
362
+ -h, --help
363
+
364
+ Outputs written under --out-dir:
365
+ - rls-visible-snapshot.json
366
+ - dry-run-report.json
367
+ - approval-record.json (commit only)
368
+ - commit-report.json (commit only)
369
+ - readback-verify-report.json (commit only)
272
370
  `.trim();
273
371
  }
274
372
  function renderDatasetContractHelp() {
@@ -313,6 +411,106 @@ Outputs written under --out-dir:
313
411
  - outputs/contract-report.json
314
412
  `.trim();
315
413
  }
414
+ function renderDatasetClassificationHelp() {
415
+ return `Usage:
416
+ tiangong-lca dataset classification children --type <type> [options]
417
+ tiangong-lca dataset classification path --type <type> --code <code> [options]
418
+ tiangong-lca dataset classification audit --type location --input <file> [options]
419
+ tiangong-lca dataset classification apply --input <file> --decisions <file> --out <file> [options]
420
+
421
+ Classification types:
422
+ process, flow-product, flow-elementary, source, contact, unitgroup, flowproperty, lciamethod, location
423
+
424
+ Actions:
425
+ children List the next selectable children for a parent code. Omit --parent for top level.
426
+ path Resolve one schema code into the full root-to-leaf classification path.
427
+ audit Scan local rows for schema-derived location fields that are not valid TIDAS location codes.
428
+ apply Apply AI/human classification decisions to local TIDAS rows deterministically.
429
+
430
+ Options for children:
431
+ --type <type> Classification schema type
432
+ --parent <code> Parent code to inspect
433
+ --query <text> Filter direct children by code or label
434
+ --limit <n> Limit returned children
435
+ --out-dir <dir> Optional artifact directory
436
+ --json Print compact JSON
437
+
438
+ Options for path:
439
+ --type <type> Classification schema type
440
+ --code <code> Leaf or intermediate classification code
441
+ --out-dir <dir> Optional artifact directory
442
+ --json Print compact JSON
443
+
444
+ Options for audit:
445
+ --type location Audit schema-derived location values against tidas_locations_category.json
446
+ --input <file> Local rows as JSON or JSONL
447
+ --out-dir <dir> Optional artifact directory
448
+ --json Print compact JSON
449
+
450
+ Options for apply:
451
+ --input <file> Local rows as JSON or JSONL
452
+ --decisions <file> JSON/JSONL decisions with row_index or dataset_id plus code/classes
453
+ --out <file> Output JSONL path for classified rows
454
+ --type <type> Default classification type when decisions omit category_type
455
+ --out-dir <dir> Artifact directory; defaults to the output file directory
456
+ --json Print compact JSON
457
+ -h, --help
458
+
459
+ Decision contract:
460
+ Decisions may target row_index or dataset_id. They may provide code, leaf_code, class_id, cat_id,
461
+ or a classes/common:class/common:category path. The CLI normalizes the path against the bundled
462
+ TIDAS schema copied from tidas-tools before writing it back. Location decisions use location
463
+ target fields derived from the bundled TIDAS schemas, plus TIDAS LCIA geography fields; use
464
+ --type location and target_path when a row contains more than one location field.
465
+
466
+ Outputs:
467
+ - children/path report under outputs/ when --out-dir is provided
468
+ - outputs/location-audit-findings.jsonl for audit
469
+ - outputs/location-audit-report.json for audit
470
+ - classified rows at --out for apply
471
+ - outputs/classification-apply-evidence.jsonl
472
+ - outputs/classification-apply-report.json
473
+ `.trim();
474
+ }
475
+ function renderDatasetCurationQueueHelp() {
476
+ return `Usage:
477
+ tiangong-lca dataset curation-queue build --processes <file> --out-dir <dir> [options]
478
+ tiangong-lca dataset curation-queue next --queue-dir <dir> [--type <type>|--task-id <id>]
479
+ tiangong-lca dataset curation-queue verify --queue-dir <dir> [--type <type>|--task-id <id>]
480
+
481
+ Options for build:
482
+ --processes <file> Process rows JSON/JSONL
483
+ --flows <file> Local flow rows JSON/JSONL used by process references
484
+ --support <file> Repeatable support rows JSON/JSONL, for source/contact/unitgroup/flowproperty rows
485
+ --external-flow-ref <file> Repeatable external flow ref rows JSON/JSONL treated as already resolvable
486
+ --exclude-process-id <id> Repeatable process id to skip
487
+ --process-limit <n> Limit process tasks for focused validation or retries
488
+ --out-dir <dir> Queue artifact directory
489
+ --json Print compact JSON
490
+ -h, --help
491
+
492
+ Options for next/verify:
493
+ --queue-dir <dir> Queue artifact directory produced by build
494
+ --type <type> support | flow | process
495
+ --task-id <id> Exact task id such as process:<uuid>@00.00.001
496
+ --json Print compact JSON
497
+ -h, --help
498
+
499
+ Outputs written under --out-dir:
500
+ - outputs/curation-queue-manifest.json
501
+ - outputs/curation-queue-tasks.jsonl
502
+ - outputs/curation-queue-locks.json
503
+ - outputs/curation-queue-blockers.jsonl
504
+ - entities/<supports|flows|processes>/<id>__<version>/input.jsonl
505
+ - entities/<supports|flows|processes>/<id>__<version>/closure.json
506
+ - entities/<supports|flows|processes>/<id>__<version>/entity-run-plan.json
507
+
508
+ Contract:
509
+ build creates queue artifacts. next/verify consume those artifacts and entity checkpoint.json files.
510
+ They do not run AI or write the database. AI authoring must write structured patches or build plans,
511
+ and remote writes remain blocked until deterministic apply, schema/QA, prewrite verify, and readback gates pass.
512
+ `.trim();
513
+ }
316
514
  function renderDatasetImportLcaHelp() {
317
515
  return `Usage:
318
516
  tiangong-lca dataset import-lca convert --input <path> --output-dir <dir> [options]
@@ -326,6 +524,10 @@ Options:
326
524
  --mapping-dir <dir> Optional custom mapping/reference data directory
327
525
  --language <lang> Default language for generated text (default: en)
328
526
  --validation-jobs <n> Parallel validation jobs passed to tidas-tools (default: 1)
527
+ --process-bundles Write per-process dependency bundles (default: enabled)
528
+ --process-bundles-dir <dir>
529
+ Custom per-process bundle directory (default: <output-dir>/process-bundles)
530
+ --no-process-bundles Disable per-process dependency bundle generation
329
531
  --detect-only Only detect the input format and write the report
330
532
  --fail-on-warning Return non-zero when converter warnings are present
331
533
  --python <bin> Python executable (default: python3)
@@ -338,6 +540,7 @@ Outputs written under --output-dir:
338
540
  - tidas/ when target includes TIDAS and not detect-only
339
541
  - ilcd/ when target includes ILCD and not detect-only
340
542
  - mapping.csv when not detect-only
543
+ - process-bundles/ when not detect-only and process bundles are enabled
341
544
  - outputs/import-lca-report.json
342
545
  `.trim();
343
546
  }
@@ -366,6 +569,35 @@ Environment:
366
569
  TIANGONG_LCA_UNSTRUCTURED_API_BASE_URL and TIANGONG_LCA_UNSTRUCTURED_API_KEY
367
570
  `.trim();
368
571
  }
572
+ function renderDatasetPatchHelp() {
573
+ return `Usage:
574
+ tiangong-lca dataset patch apply --input <file> --patch <file> --out <file> [options]
575
+
576
+ Options:
577
+ --input <file> Local rows as JSON or JSONL
578
+ --patch <file> AI-authored JSON patch set with row_index or dataset_id selectors
579
+ --out <file> Output JSONL path for patched rows
580
+ --out-dir <dir> Artifact directory; defaults to the output file directory
581
+ --authoring-package-dir <dir> Resolve relative authoring_package paths from this directory
582
+ --require-authoring-package Require each patch set to point at a matching authoring package
583
+ --require-action-item-closure Require patch operations to close package action_items
584
+ --json Print compact JSON
585
+ -h, --help
586
+
587
+ Patch contract:
588
+ Patch payloads must declare patch_status=completed before deterministic apply.
589
+ Patch sets must target a row by row_index or dataset_id and use operations[].
590
+ Supported operations are test, add, replace, and remove. Non-test operations require basis or evidence.
591
+ Foundry AI patches should include resolution.mode and resolution.used_context_kinds; these are copied to patch evidence.
592
+ Strict Foundry mode also requires authoring package lineage and explicit action item closure.
593
+ If any operation is invalid, the command reports blocked and writes the original rows unchanged.
594
+
595
+ Outputs:
596
+ - patched rows at --out
597
+ - outputs/patch-evidence.jsonl
598
+ - outputs/dataset-patch-apply-report.json
599
+ `.trim();
600
+ }
369
601
  function renderDatasetRemoteVerifyHelp() {
370
602
  return `Usage:
371
603
  tiangong-lca dataset verify-remote --input <file> --out-dir <dir> [options]
@@ -374,6 +606,9 @@ Options:
374
606
  --input <file> Local rows as JSON or JSONL; objects with rows[] are also accepted
375
607
  --out-dir <dir> Artifact directory for the remote verification report
376
608
  --root-policy <mode> existing | candidate (default: existing)
609
+ --compare-root-payload Compare each root row payload hash against the remote row
610
+ --target-user-id <id> Require root readback rows to belong to this user
611
+ --state-code <code> Require root readback rows to have this state_code
377
612
  --json Print compact JSON
378
613
  -h, --help
379
614
 
@@ -386,13 +621,37 @@ Outputs written under --out-dir:
386
621
  - outputs/blockers.jsonl
387
622
  `.trim();
388
623
  }
624
+ function renderDatasetSaveDraftHelp() {
625
+ return `Usage:
626
+ tiangong-lca dataset save-draft --input <file> --type <type> [options]
627
+
628
+ Options:
629
+ --input <file> Canonical TIDAS rows JSON/JSONL
630
+ --type <type> auto, contact, source, flow, process
631
+ --out-dir <dir> Artifact directory
632
+ --commit Execute remote save-draft writes
633
+ --dry-run Validate and plan without remote writes (default)
634
+ --json Print compact JSON
635
+ -h, --help
636
+
637
+ Outputs written under --out-dir:
638
+ - outputs/dataset-save-draft/selected-rows.jsonl
639
+ - outputs/dataset-save-draft/progress.jsonl
640
+ - outputs/dataset-save-draft/failures.jsonl
641
+ - outputs/dataset-save-draft/summary.json
642
+
643
+ Contract:
644
+ This generic dataset path writes only mutable rows such as contact/source/flow/process. Unit group and flow property rows are reference-only; select existing database rows and rewrite references instead of creating My Data support rows.
645
+ Process and lifecyclemodel imports may still use their dedicated save-draft commands when the workflow needs their specialized reports.
646
+ `.trim();
647
+ }
389
648
  function renderDatasetValidateHelp() {
390
649
  return `Usage:
391
650
  tiangong-lca dataset validate --input <file> [options]
392
651
 
393
652
  Options:
394
653
  --input <file> Local rows as JSON or JSONL; objects with rows[] are also accepted
395
- --type <type> auto | flow | process | lifecyclemodel (default: auto)
654
+ --type <type> auto | contact | source | unitgroup | flowproperty | flow | process | lifecyclemodel (default: auto)
396
655
  --out-dir <dir> Optional artifact directory for validation report and row splits
397
656
  --json Print compact JSON
398
657
  -h, --help
@@ -619,6 +878,9 @@ Options:
619
878
  Override the remote search query; defaults to target identity text
620
879
  --remote-limit <n>
621
880
  Limit remote candidate rows after fetch
881
+ --remote-data-source <tg|co|my|te>
882
+ Search TianGong public, community, my data, or team data (default: tg)
883
+ --timeout-ms <n> Remote search/auth timeout in milliseconds
622
884
  --out-dir <dir> Optional artifact directory for identity decision outputs
623
885
  --json Print compact JSON
624
886
  -h, --help
@@ -948,7 +1210,7 @@ function renderQaHelp() {
948
1210
  Implemented Subcommands:
949
1211
  process Run deterministic process QA for build runs or rows-file snapshots
950
1212
  flow Run deterministic flow QA for local governance snapshots
951
- lifecyclemodel Run deterministic lifecyclemodel QA for one local build run
1213
+ lifecyclemodel Run deterministic lifecyclemodel QA for build runs or rows-file snapshots
952
1214
 
953
1215
  Examples:
954
1216
  tiangong-lca qa process --help
@@ -1000,9 +1262,10 @@ Options:
1000
1262
  }
1001
1263
  function renderQaLifecyclemodelHelp() {
1002
1264
  return `Usage:
1003
- tiangong-lca qa lifecyclemodel --run-dir <dir> --out-dir <dir> [options]
1265
+ tiangong-lca qa lifecyclemodel (--rows-file <file> | --run-dir <dir>) --out-dir <dir> [options]
1004
1266
 
1005
1267
  Options:
1268
+ --rows-file <file> Lifecyclemodel rows JSON/JSONL file; payload-level QA for import snapshots
1006
1269
  --run-dir <dir> Existing lifecyclemodel auto-build run directory
1007
1270
  --out-dir <dir> QA artifact output directory
1008
1271
  --start-ts <iso> Optional run start timestamp
@@ -1012,7 +1275,7 @@ Options:
1012
1275
  -h, --help
1013
1276
 
1014
1277
  This command:
1015
- - reads one existing lifecyclemodel build run under models/*/tidas_bundle/lifecyclemodels
1278
+ - reads one lifecyclemodel rows snapshot or existing build run under models/*/tidas_bundle/lifecyclemodels
1016
1279
  - aggregates validate-build findings when reports/lifecyclemodel-validate-build-report.json is present
1017
1280
  - emits artifact-first model summaries, findings, markdown QA notes, and a structured report
1018
1281
  `.trim();
@@ -1300,6 +1563,9 @@ Options:
1300
1563
  Override the remote search query; defaults to target identity text
1301
1564
  --remote-limit <n>
1302
1565
  Limit remote candidate rows after fetch
1566
+ --remote-data-source <tg|co|my|te>
1567
+ Search TianGong public, community, my data, or team data (default: tg)
1568
+ --timeout-ms <n> Remote search/auth timeout in milliseconds
1303
1569
  --out-dir <dir> Optional artifact directory for identity decision outputs
1304
1570
  --json Print compact JSON
1305
1571
  -h, --help
@@ -1428,7 +1694,7 @@ Options:
1428
1694
  Annual supply / production volume policy:
1429
1695
  1. keep an existing valid annualized annualSupplyOrProductionVolume, for example "3.6 MJ/year";
1430
1696
  2. use an explicit value from row-level authoring evidence or evidenceManifest field bindings;
1431
- 3. otherwise complete from the quantitative reference flow meanAmount/resultingAmount and unit.
1697
+ 3. otherwise write "9999 missing-data-sentinel/year", an intentionally non-physical searchable sentinel for later database-side curation.
1432
1698
 
1433
1699
  Outputs:
1434
1700
  - completed rows at --out
@@ -1788,6 +2054,45 @@ function parseDatasetValidateFlags(args) {
1788
2054
  outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1789
2055
  };
1790
2056
  }
2057
+ function parseDatasetSaveDraftFlags(args) {
2058
+ let values;
2059
+ try {
2060
+ ({ values } = parseArgs({
2061
+ args,
2062
+ allowPositionals: false,
2063
+ strict: true,
2064
+ options: {
2065
+ help: { type: 'boolean', short: 'h' },
2066
+ json: { type: 'boolean' },
2067
+ input: { type: 'string' },
2068
+ type: { type: 'string' },
2069
+ 'out-dir': { type: 'string' },
2070
+ commit: { type: 'boolean' },
2071
+ 'dry-run': { type: 'boolean' },
2072
+ },
2073
+ }));
2074
+ }
2075
+ catch (error) {
2076
+ throw new CliError(String(error), {
2077
+ code: 'INVALID_ARGS',
2078
+ exitCode: 2,
2079
+ });
2080
+ }
2081
+ if (values.commit && values['dry-run']) {
2082
+ throw new CliError('Cannot pass both --commit and --dry-run.', {
2083
+ code: 'INVALID_DATASET_SAVE_DRAFT_MODE',
2084
+ exitCode: 2,
2085
+ });
2086
+ }
2087
+ return {
2088
+ help: Boolean(values.help),
2089
+ json: Boolean(values.json),
2090
+ inputPath: typeof values.input === 'string' ? values.input : '',
2091
+ type: typeof values.type === 'string' ? values.type : undefined,
2092
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2093
+ commit: Boolean(values.commit),
2094
+ };
2095
+ }
1791
2096
  function parseDatasetContractFlags(args) {
1792
2097
  let values;
1793
2098
  try {
@@ -1822,6 +2127,228 @@ function parseDatasetContractFlags(args) {
1822
2127
  outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1823
2128
  };
1824
2129
  }
2130
+ function parseDatasetClassificationChildrenFlags(args) {
2131
+ let values;
2132
+ try {
2133
+ ({ values } = parseArgs({
2134
+ args,
2135
+ allowPositionals: false,
2136
+ strict: true,
2137
+ options: {
2138
+ help: { type: 'boolean', short: 'h' },
2139
+ json: { type: 'boolean' },
2140
+ type: { type: 'string' },
2141
+ parent: { type: 'string' },
2142
+ query: { type: 'string' },
2143
+ limit: { type: 'string' },
2144
+ 'out-dir': { type: 'string' },
2145
+ },
2146
+ }));
2147
+ }
2148
+ catch (error) {
2149
+ throw new CliError(String(error), {
2150
+ code: 'INVALID_ARGS',
2151
+ exitCode: 2,
2152
+ });
2153
+ }
2154
+ const limit = typeof values.limit === 'string' ? Number.parseInt(values.limit, 10) : null;
2155
+ if (limit !== null && (!Number.isInteger(limit) || limit <= 0)) {
2156
+ throw new CliError('--limit must be a positive integer.', {
2157
+ code: 'DATASET_CLASSIFICATION_LIMIT_INVALID',
2158
+ exitCode: 2,
2159
+ });
2160
+ }
2161
+ return {
2162
+ help: Boolean(values.help),
2163
+ json: Boolean(values.json),
2164
+ type: typeof values.type === 'string' ? values.type : '',
2165
+ parent: typeof values.parent === 'string' ? values.parent : null,
2166
+ query: typeof values.query === 'string' ? values.query : null,
2167
+ limit,
2168
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2169
+ };
2170
+ }
2171
+ function parseDatasetClassificationPathFlags(args) {
2172
+ let values;
2173
+ try {
2174
+ ({ values } = parseArgs({
2175
+ args,
2176
+ allowPositionals: false,
2177
+ strict: true,
2178
+ options: {
2179
+ help: { type: 'boolean', short: 'h' },
2180
+ json: { type: 'boolean' },
2181
+ type: { type: 'string' },
2182
+ code: { type: 'string' },
2183
+ 'out-dir': { type: 'string' },
2184
+ },
2185
+ }));
2186
+ }
2187
+ catch (error) {
2188
+ throw new CliError(String(error), {
2189
+ code: 'INVALID_ARGS',
2190
+ exitCode: 2,
2191
+ });
2192
+ }
2193
+ return {
2194
+ help: Boolean(values.help),
2195
+ json: Boolean(values.json),
2196
+ type: typeof values.type === 'string' ? values.type : '',
2197
+ code: typeof values.code === 'string' ? values.code : '',
2198
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2199
+ };
2200
+ }
2201
+ function parseDatasetClassificationAuditFlags(args) {
2202
+ let values;
2203
+ try {
2204
+ ({ values } = parseArgs({
2205
+ args,
2206
+ allowPositionals: false,
2207
+ strict: true,
2208
+ options: {
2209
+ help: { type: 'boolean', short: 'h' },
2210
+ json: { type: 'boolean' },
2211
+ input: { type: 'string' },
2212
+ type: { type: 'string' },
2213
+ 'out-dir': { type: 'string' },
2214
+ },
2215
+ }));
2216
+ }
2217
+ catch (error) {
2218
+ throw new CliError(String(error), {
2219
+ code: 'INVALID_ARGS',
2220
+ exitCode: 2,
2221
+ });
2222
+ }
2223
+ return {
2224
+ help: Boolean(values.help),
2225
+ json: Boolean(values.json),
2226
+ inputPath: typeof values.input === 'string' ? values.input : '',
2227
+ type: typeof values.type === 'string' ? values.type : 'location',
2228
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2229
+ };
2230
+ }
2231
+ function parseDatasetClassificationApplyFlags(args) {
2232
+ let values;
2233
+ try {
2234
+ ({ values } = parseArgs({
2235
+ args,
2236
+ allowPositionals: false,
2237
+ strict: true,
2238
+ options: {
2239
+ help: { type: 'boolean', short: 'h' },
2240
+ json: { type: 'boolean' },
2241
+ input: { type: 'string' },
2242
+ decisions: { type: 'string' },
2243
+ out: { type: 'string' },
2244
+ type: { type: 'string' },
2245
+ 'out-dir': { type: 'string' },
2246
+ },
2247
+ }));
2248
+ }
2249
+ catch (error) {
2250
+ throw new CliError(String(error), {
2251
+ code: 'INVALID_ARGS',
2252
+ exitCode: 2,
2253
+ });
2254
+ }
2255
+ return {
2256
+ help: Boolean(values.help),
2257
+ json: Boolean(values.json),
2258
+ inputPath: typeof values.input === 'string' ? values.input : '',
2259
+ decisionsPath: typeof values.decisions === 'string' ? values.decisions : '',
2260
+ outPath: typeof values.out === 'string' ? values.out : '',
2261
+ type: typeof values.type === 'string' ? values.type : null,
2262
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2263
+ };
2264
+ }
2265
+ function parseDatasetCurationQueueBuildFlags(args) {
2266
+ let values;
2267
+ try {
2268
+ ({ values } = parseArgs({
2269
+ args,
2270
+ allowPositionals: false,
2271
+ strict: true,
2272
+ options: {
2273
+ help: { type: 'boolean', short: 'h' },
2274
+ json: { type: 'boolean' },
2275
+ processes: { type: 'string' },
2276
+ flows: { type: 'string' },
2277
+ support: { type: 'string', multiple: true },
2278
+ 'external-flow-ref': { type: 'string', multiple: true },
2279
+ 'exclude-process-id': { type: 'string', multiple: true },
2280
+ 'process-limit': { type: 'string' },
2281
+ 'out-dir': { type: 'string' },
2282
+ },
2283
+ }));
2284
+ }
2285
+ catch (error) {
2286
+ throw new CliError(String(error), {
2287
+ code: 'INVALID_ARGS',
2288
+ exitCode: 2,
2289
+ });
2290
+ }
2291
+ const processLimit = typeof values['process-limit'] === 'string'
2292
+ ? Number.parseInt(values['process-limit'], 10)
2293
+ : undefined;
2294
+ return {
2295
+ help: Boolean(values.help),
2296
+ json: Boolean(values.json),
2297
+ processesPath: typeof values.processes === 'string' ? values.processes : '',
2298
+ flowsPath: typeof values.flows === 'string' ? values.flows : undefined,
2299
+ supportPaths: Array.isArray(values.support)
2300
+ ? values.support.filter((value) => typeof value === 'string')
2301
+ : [],
2302
+ externalFlowRefPaths: Array.isArray(values['external-flow-ref'])
2303
+ ? values['external-flow-ref'].filter((value) => typeof value === 'string')
2304
+ : [],
2305
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
2306
+ excludeProcessIds: Array.isArray(values['exclude-process-id'])
2307
+ ? values['exclude-process-id'].filter((value) => typeof value === 'string')
2308
+ : [],
2309
+ processLimit,
2310
+ };
2311
+ }
2312
+ function parseDatasetCurationQueueRuntimeFlags(args) {
2313
+ let values;
2314
+ try {
2315
+ ({ values } = parseArgs({
2316
+ args,
2317
+ allowPositionals: false,
2318
+ strict: true,
2319
+ options: {
2320
+ help: { type: 'boolean', short: 'h' },
2321
+ json: { type: 'boolean' },
2322
+ 'queue-dir': { type: 'string' },
2323
+ type: { type: 'string' },
2324
+ 'task-id': { type: 'string' },
2325
+ },
2326
+ }));
2327
+ }
2328
+ catch (error) {
2329
+ throw new CliError(String(error), {
2330
+ code: 'INVALID_ARGS',
2331
+ exitCode: 2,
2332
+ });
2333
+ }
2334
+ const entityType = typeof values.type === 'string' ? values.type : undefined;
2335
+ if (entityType !== undefined &&
2336
+ entityType !== 'support' &&
2337
+ entityType !== 'flow' &&
2338
+ entityType !== 'process') {
2339
+ throw new CliError('--type must be support, flow, or process.', {
2340
+ code: 'DATASET_CURATION_QUEUE_TYPE_INVALID',
2341
+ exitCode: 2,
2342
+ });
2343
+ }
2344
+ return {
2345
+ help: Boolean(values.help),
2346
+ json: Boolean(values.json),
2347
+ queueDir: typeof values['queue-dir'] === 'string' ? values['queue-dir'] : '',
2348
+ entityType,
2349
+ taskId: typeof values['task-id'] === 'string' ? values['task-id'] : undefined,
2350
+ };
2351
+ }
1825
2352
  function parseDatasetImportLcaConvertFlags(args) {
1826
2353
  let values;
1827
2354
  try {
@@ -1840,6 +2367,9 @@ function parseDatasetImportLcaConvertFlags(args) {
1840
2367
  'mapping-dir': { type: 'string' },
1841
2368
  language: { type: 'string' },
1842
2369
  'validation-jobs': { type: 'string' },
2370
+ 'process-bundles': { type: 'boolean' },
2371
+ 'process-bundles-dir': { type: 'string' },
2372
+ 'no-process-bundles': { type: 'boolean' },
1843
2373
  'detect-only': { type: 'boolean' },
1844
2374
  'fail-on-warning': { type: 'boolean' },
1845
2375
  python: { type: 'string' },
@@ -1860,6 +2390,18 @@ function parseDatasetImportLcaConvertFlags(args) {
1860
2390
  exitCode: 2,
1861
2391
  });
1862
2392
  }
2393
+ if (values['process-bundles'] && values['no-process-bundles']) {
2394
+ throw new CliError('--process-bundles and --no-process-bundles cannot both be set.', {
2395
+ code: 'DATASET_IMPORT_LCA_PROCESS_BUNDLES_INVALID',
2396
+ exitCode: 2,
2397
+ });
2398
+ }
2399
+ if (values['no-process-bundles'] && typeof values['process-bundles-dir'] === 'string') {
2400
+ throw new CliError('--process-bundles-dir cannot be used with --no-process-bundles.', {
2401
+ code: 'DATASET_IMPORT_LCA_PROCESS_BUNDLES_INVALID',
2402
+ exitCode: 2,
2403
+ });
2404
+ }
1863
2405
  return {
1864
2406
  help: Boolean(values.help),
1865
2407
  json: Boolean(values.json),
@@ -1871,6 +2413,12 @@ function parseDatasetImportLcaConvertFlags(args) {
1871
2413
  mappingDir: typeof values['mapping-dir'] === 'string' ? values['mapping-dir'] : undefined,
1872
2414
  language: typeof values.language === 'string' ? values.language : undefined,
1873
2415
  validationJobs,
2416
+ processBundles: values['no-process-bundles']
2417
+ ? false
2418
+ : values['process-bundles']
2419
+ ? true
2420
+ : undefined,
2421
+ processBundlesDir: typeof values['process-bundles-dir'] === 'string' ? values['process-bundles-dir'] : undefined,
1874
2422
  detectOnly: Boolean(values['detect-only']),
1875
2423
  failOnWarning: Boolean(values['fail-on-warning']),
1876
2424
  pythonBin: typeof values.python === 'string' ? values.python : undefined,
@@ -1924,6 +2472,44 @@ function parseDatasetAuthorFlags(args) {
1924
2472
  timeoutMs,
1925
2473
  };
1926
2474
  }
2475
+ function parseDatasetPatchApplyFlags(args) {
2476
+ let values;
2477
+ try {
2478
+ ({ values } = parseArgs({
2479
+ args,
2480
+ allowPositionals: false,
2481
+ strict: true,
2482
+ options: {
2483
+ help: { type: 'boolean', short: 'h' },
2484
+ json: { type: 'boolean' },
2485
+ input: { type: 'string' },
2486
+ patch: { type: 'string' },
2487
+ out: { type: 'string' },
2488
+ 'out-dir': { type: 'string' },
2489
+ 'authoring-package-dir': { type: 'string' },
2490
+ 'require-authoring-package': { type: 'boolean' },
2491
+ 'require-action-item-closure': { type: 'boolean' },
2492
+ },
2493
+ }));
2494
+ }
2495
+ catch (error) {
2496
+ throw new CliError(String(error), {
2497
+ code: 'INVALID_ARGS',
2498
+ exitCode: 2,
2499
+ });
2500
+ }
2501
+ return {
2502
+ help: Boolean(values.help),
2503
+ json: Boolean(values.json),
2504
+ inputPath: typeof values.input === 'string' ? values.input : '',
2505
+ patchPath: typeof values.patch === 'string' ? values.patch : '',
2506
+ outPath: typeof values.out === 'string' ? values.out : '',
2507
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2508
+ authoringPackageDir: typeof values['authoring-package-dir'] === 'string' ? values['authoring-package-dir'] : null,
2509
+ requireAuthoringPackage: Boolean(values['require-authoring-package']),
2510
+ requireActionItemClosure: Boolean(values['require-action-item-closure']),
2511
+ };
2512
+ }
1927
2513
  function parseDatasetRemoteVerifyFlags(args) {
1928
2514
  let values;
1929
2515
  try {
@@ -1937,6 +2523,9 @@ function parseDatasetRemoteVerifyFlags(args) {
1937
2523
  input: { type: 'string' },
1938
2524
  'out-dir': { type: 'string' },
1939
2525
  'root-policy': { type: 'string' },
2526
+ 'compare-root-payload': { type: 'boolean' },
2527
+ 'target-user-id': { type: 'string' },
2528
+ 'state-code': { type: 'string' },
1940
2529
  },
1941
2530
  }));
1942
2531
  }
@@ -1954,12 +2543,25 @@ function parseDatasetRemoteVerifyFlags(args) {
1954
2543
  });
1955
2544
  }
1956
2545
  const rootPolicy = rawRootPolicy;
2546
+ let stateCode = null;
2547
+ if (typeof values['state-code'] === 'string') {
2548
+ stateCode = Number.parseInt(values['state-code'], 10);
2549
+ if (!Number.isInteger(stateCode) || stateCode < 0) {
2550
+ throw new CliError('--state-code must be a non-negative integer.', {
2551
+ code: 'DATASET_REMOTE_VERIFY_STATE_CODE_INVALID',
2552
+ exitCode: 2,
2553
+ });
2554
+ }
2555
+ }
1957
2556
  return {
1958
2557
  help: Boolean(values.help),
1959
2558
  json: Boolean(values.json),
1960
2559
  inputPath: typeof values.input === 'string' ? values.input : '',
1961
2560
  outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
1962
2561
  rootPolicy,
2562
+ compareRootPayload: Boolean(values['compare-root-payload']),
2563
+ targetUserId: typeof values['target-user-id'] === 'string' ? values['target-user-id'] : null,
2564
+ stateCode,
1963
2565
  };
1964
2566
  }
1965
2567
  function parseDatasetBilingualExtractFlags(args) {
@@ -2204,6 +2806,78 @@ function parseDatasetReferencesRefreshRemoteFlags(args) {
2204
2806
  rootPolicy,
2205
2807
  };
2206
2808
  }
2809
+ function parseDatasetMaintenanceClearAccountFlags(args) {
2810
+ let values;
2811
+ try {
2812
+ ({ values } = parseArgs({
2813
+ args,
2814
+ allowPositionals: false,
2815
+ strict: true,
2816
+ options: {
2817
+ help: { type: 'boolean', short: 'h' },
2818
+ json: { type: 'boolean' },
2819
+ 'out-dir': { type: 'string' },
2820
+ 'state-code': { type: 'string', multiple: true },
2821
+ 'page-size': { type: 'string' },
2822
+ 'timeout-ms': { type: 'string' },
2823
+ commit: { type: 'boolean' },
2824
+ 'dry-run': { type: 'boolean' },
2825
+ confirm: { type: 'string' },
2826
+ },
2827
+ }));
2828
+ }
2829
+ catch (error) {
2830
+ throw new CliError(String(error), {
2831
+ code: 'INVALID_ARGS',
2832
+ exitCode: 2,
2833
+ });
2834
+ }
2835
+ if (values.commit && values['dry-run']) {
2836
+ throw new CliError('Cannot pass both --commit and --dry-run.', {
2837
+ code: 'DATASET_MAINTENANCE_CLEAR_ACCOUNT_MODE_CONFLICT',
2838
+ exitCode: 2,
2839
+ });
2840
+ }
2841
+ const rawStateCodes = Array.isArray(values['state-code'])
2842
+ ? values['state-code'].filter((value) => typeof value === 'string')
2843
+ : [];
2844
+ const stateCodes = rawStateCodes.map((value) => {
2845
+ if (!/^-?\d+$/u.test(value.trim())) {
2846
+ throw new CliError('--state-code must be an integer.', {
2847
+ code: 'DATASET_MAINTENANCE_STATE_CODE_INVALID',
2848
+ exitCode: 2,
2849
+ details: value,
2850
+ });
2851
+ }
2852
+ return Number.parseInt(value.trim(), 10);
2853
+ });
2854
+ const parseOptionalInteger = (value, flagName) => {
2855
+ if (typeof value !== 'string') {
2856
+ return undefined;
2857
+ }
2858
+ if (!/^\d+$/u.test(value.trim())) {
2859
+ throw new CliError(`${flagName} must be a positive integer.`, {
2860
+ code: 'DATASET_MAINTENANCE_INTEGER_INVALID',
2861
+ exitCode: 2,
2862
+ details: {
2863
+ flag: flagName,
2864
+ value,
2865
+ },
2866
+ });
2867
+ }
2868
+ return Number.parseInt(value.trim(), 10);
2869
+ };
2870
+ return {
2871
+ help: Boolean(values.help),
2872
+ json: Boolean(values.json),
2873
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2874
+ stateCodes: stateCodes.length > 0 ? stateCodes : null,
2875
+ pageSize: parseOptionalInteger(values['page-size'], '--page-size'),
2876
+ timeoutMs: parseOptionalInteger(values['timeout-ms'], '--timeout-ms'),
2877
+ commit: Boolean(values.commit),
2878
+ confirm: typeof values.confirm === 'string' ? values.confirm : null,
2879
+ };
2880
+ }
2207
2881
  function parseIdentityPreflightFlags(args) {
2208
2882
  let values;
2209
2883
  try {
@@ -2219,6 +2893,8 @@ function parseIdentityPreflightFlags(args) {
2219
2893
  'remote-candidates': { type: 'boolean' },
2220
2894
  'remote-query': { type: 'string' },
2221
2895
  'remote-limit': { type: 'string' },
2896
+ 'remote-data-source': { type: 'string' },
2897
+ 'timeout-ms': { type: 'string' },
2222
2898
  'out-dir': { type: 'string' },
2223
2899
  },
2224
2900
  }));
@@ -2243,6 +2919,19 @@ function parseIdentityPreflightFlags(args) {
2243
2919
  }
2244
2920
  return parsed;
2245
2921
  };
2922
+ const parseTimeoutMs = (value) => {
2923
+ if (typeof value !== 'string') {
2924
+ return undefined;
2925
+ }
2926
+ const parsed = Number.parseInt(value, 10);
2927
+ if (!Number.isInteger(parsed) || parsed <= 0) {
2928
+ throw new CliError('Expected --timeout-ms to be a positive integer.', {
2929
+ code: 'INVALID_IDENTITY_PREFLIGHT_TIMEOUT',
2930
+ exitCode: 2,
2931
+ });
2932
+ }
2933
+ return parsed;
2934
+ };
2246
2935
  return {
2247
2936
  help: Boolean(values.help),
2248
2937
  json: Boolean(values.json),
@@ -2251,9 +2940,11 @@ function parseIdentityPreflightFlags(args) {
2251
2940
  candidateInputPaths: Array.isArray(candidateInputValue)
2252
2941
  ? candidateInputValue.filter((entry) => typeof entry === 'string')
2253
2942
  : [],
2254
- remoteCandidateSearch: Boolean(values['remote-candidates']),
2943
+ remoteCandidateSearch: values['remote-candidates'] === true ? true : undefined,
2255
2944
  remoteQuery: typeof values['remote-query'] === 'string' ? values['remote-query'] : null,
2256
2945
  remoteLimit: parseRemoteLimit(values['remote-limit']),
2946
+ remoteDataSource: typeof values['remote-data-source'] === 'string' ? values['remote-data-source'] : null,
2947
+ timeoutMs: parseTimeoutMs(values['timeout-ms']),
2257
2948
  };
2258
2949
  }
2259
2950
  function parseBuildPlanFlags(args) {
@@ -3097,6 +3788,7 @@ function parseQaLifecyclemodelFlags(args) {
3097
3788
  options: {
3098
3789
  help: { type: 'boolean', short: 'h' },
3099
3790
  json: { type: 'boolean' },
3791
+ 'rows-file': { type: 'string' },
3100
3792
  'run-dir': { type: 'string' },
3101
3793
  'out-dir': { type: 'string' },
3102
3794
  'start-ts': { type: 'string' },
@@ -3114,6 +3806,7 @@ function parseQaLifecyclemodelFlags(args) {
3114
3806
  return {
3115
3807
  help: Boolean(values.help),
3116
3808
  json: Boolean(values.json),
3809
+ rowsFile: typeof values['rows-file'] === 'string' ? values['rows-file'] : undefined,
3117
3810
  runDir: typeof values['run-dir'] === 'string' ? values['run-dir'] : '',
3118
3811
  outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
3119
3812
  startTs: typeof values['start-ts'] === 'string' ? values['start-ts'] : undefined,
@@ -3908,6 +4601,9 @@ export async function executeCli(argv, deps) {
3908
4601
  const flowBuildPlanValidateImpl = deps.runFlowBuildPlanValidateImpl ?? runFlowBuildPlanValidate;
3909
4602
  const flowBuildPlanMaterializeImpl = deps.runFlowBuildPlanMaterializeImpl ?? runFlowBuildPlanMaterialize;
3910
4603
  const datasetValidateImpl = deps.runDatasetValidateImpl ?? runDatasetValidate;
4604
+ const datasetCurationQueueBuildImpl = deps.runDatasetCurationQueueBuildImpl ?? runDatasetCurationQueueBuild;
4605
+ const datasetCurationQueueNextImpl = deps.runDatasetCurationQueueNextImpl ?? runDatasetCurationQueueNext;
4606
+ const datasetCurationQueueVerifyImpl = deps.runDatasetCurationQueueVerifyImpl ?? runDatasetCurationQueueVerify;
3911
4607
  const datasetReferencesRewriteImpl = deps.runDatasetReferencesRewriteImpl ?? runDatasetReferencesRewrite;
3912
4608
  const datasetRemoteRefreshImpl = deps.runDatasetRemoteRefreshImpl ?? runDatasetRemoteRefresh;
3913
4609
  const datasetRemoteVerifyImpl = deps.runDatasetRemoteVerifyImpl ?? runDatasetRemoteVerify;
@@ -3918,6 +4614,13 @@ export async function executeCli(argv, deps) {
3918
4614
  const datasetContractImpl = deps.runDatasetContractImpl ?? runDatasetContract;
3919
4615
  const datasetImportLcaConvertImpl = deps.runDatasetImportLcaConvertImpl ?? runDatasetImportLcaConvert;
3920
4616
  const datasetAuthorImpl = deps.runDatasetAuthorImpl ?? runDatasetAuthor;
4617
+ const datasetPatchApplyImpl = deps.runDatasetPatchApplyImpl ?? runDatasetPatchApply;
4618
+ const datasetSaveDraftImpl = deps.runDatasetSaveDraftImpl ?? runDatasetSaveDraft;
4619
+ const datasetClassificationChildrenImpl = deps.runDatasetClassificationChildrenImpl ?? runDatasetClassificationChildren;
4620
+ const datasetClassificationPathImpl = deps.runDatasetClassificationPathImpl ?? runDatasetClassificationPath;
4621
+ const datasetClassificationAuditImpl = deps.runDatasetClassificationAuditImpl ?? runDatasetClassificationAudit;
4622
+ const datasetClassificationApplyImpl = deps.runDatasetClassificationApplyImpl ?? runDatasetClassificationApply;
4623
+ const datasetMaintenanceClearAccountImpl = deps.runDatasetMaintenanceClearAccountImpl ?? runDatasetMaintenanceClearAccount;
3921
4624
  if (flags.version) {
3922
4625
  return { exitCode: 0, stdout: `${loadCliPackageVersion(import.meta.url)}\n`, stderr: '' };
3923
4626
  }
@@ -4009,6 +4712,146 @@ export async function executeCli(argv, deps) {
4009
4712
  stderr: '',
4010
4713
  };
4011
4714
  }
4715
+ if (command === 'dataset' && subcommand === 'classification') {
4716
+ const action = commandArgs[0] ?? '';
4717
+ if (!action || action === '--help' || action === '-h') {
4718
+ return { exitCode: 0, stdout: `${renderDatasetClassificationHelp()}\n`, stderr: '' };
4719
+ }
4720
+ if (action === 'children') {
4721
+ const datasetFlags = parseDatasetClassificationChildrenFlags(commandArgs.slice(1));
4722
+ if (datasetFlags.help) {
4723
+ return { exitCode: 0, stdout: `${renderDatasetClassificationHelp()}\n`, stderr: '' };
4724
+ }
4725
+ const report = await datasetClassificationChildrenImpl({
4726
+ type: datasetFlags.type,
4727
+ parent: datasetFlags.parent,
4728
+ query: datasetFlags.query,
4729
+ limit: datasetFlags.limit,
4730
+ outDir: datasetFlags.outDir,
4731
+ });
4732
+ return {
4733
+ exitCode: report.status === 'blocked' ? 1 : 0,
4734
+ stdout: stringifyJson(report, datasetFlags.json),
4735
+ stderr: '',
4736
+ };
4737
+ }
4738
+ if (action === 'path') {
4739
+ const datasetFlags = parseDatasetClassificationPathFlags(commandArgs.slice(1));
4740
+ if (datasetFlags.help) {
4741
+ return { exitCode: 0, stdout: `${renderDatasetClassificationHelp()}\n`, stderr: '' };
4742
+ }
4743
+ const report = await datasetClassificationPathImpl({
4744
+ type: datasetFlags.type,
4745
+ code: datasetFlags.code,
4746
+ outDir: datasetFlags.outDir,
4747
+ });
4748
+ return {
4749
+ exitCode: report.status === 'blocked' ? 1 : 0,
4750
+ stdout: stringifyJson(report, datasetFlags.json),
4751
+ stderr: '',
4752
+ };
4753
+ }
4754
+ if (action === 'audit') {
4755
+ const datasetFlags = parseDatasetClassificationAuditFlags(commandArgs.slice(1));
4756
+ if (datasetFlags.help) {
4757
+ return { exitCode: 0, stdout: `${renderDatasetClassificationHelp()}\n`, stderr: '' };
4758
+ }
4759
+ const report = await datasetClassificationAuditImpl({
4760
+ inputPath: datasetFlags.inputPath,
4761
+ type: datasetFlags.type,
4762
+ outDir: datasetFlags.outDir,
4763
+ });
4764
+ return {
4765
+ exitCode: report.status === 'blocked' ? 1 : 0,
4766
+ stdout: stringifyJson(report, datasetFlags.json),
4767
+ stderr: '',
4768
+ };
4769
+ }
4770
+ if (action === 'apply') {
4771
+ const datasetFlags = parseDatasetClassificationApplyFlags(commandArgs.slice(1));
4772
+ if (datasetFlags.help) {
4773
+ return { exitCode: 0, stdout: `${renderDatasetClassificationHelp()}\n`, stderr: '' };
4774
+ }
4775
+ const report = await datasetClassificationApplyImpl({
4776
+ inputPath: datasetFlags.inputPath,
4777
+ decisionsPath: datasetFlags.decisionsPath,
4778
+ outPath: datasetFlags.outPath,
4779
+ type: datasetFlags.type,
4780
+ outDir: datasetFlags.outDir,
4781
+ });
4782
+ return {
4783
+ exitCode: report.status === 'blocked' ? 1 : 0,
4784
+ stdout: stringifyJson(report, datasetFlags.json),
4785
+ stderr: '',
4786
+ };
4787
+ }
4788
+ throw new CliError("dataset classification action must be 'children', 'path', 'audit', or 'apply'.", {
4789
+ code: 'DATASET_CLASSIFICATION_ACTION_INVALID',
4790
+ exitCode: 2,
4791
+ });
4792
+ }
4793
+ if (command === 'dataset' && subcommand === 'curation-queue') {
4794
+ const action = commandArgs[0] ?? '';
4795
+ if (!action || action === '--help' || action === '-h') {
4796
+ return { exitCode: 0, stdout: `${renderDatasetCurationQueueHelp()}\n`, stderr: '' };
4797
+ }
4798
+ if (action !== 'build' && action !== 'next' && action !== 'verify') {
4799
+ throw new CliError("dataset curation-queue action must be 'build', 'next', or 'verify'.", {
4800
+ code: 'DATASET_CURATION_QUEUE_ACTION_INVALID',
4801
+ exitCode: 2,
4802
+ });
4803
+ }
4804
+ if (action === 'next') {
4805
+ const datasetFlags = parseDatasetCurationQueueRuntimeFlags(commandArgs.slice(1));
4806
+ if (datasetFlags.help) {
4807
+ return { exitCode: 0, stdout: `${renderDatasetCurationQueueHelp()}\n`, stderr: '' };
4808
+ }
4809
+ const report = await datasetCurationQueueNextImpl({
4810
+ queueDir: datasetFlags.queueDir,
4811
+ entityType: datasetFlags.entityType,
4812
+ taskId: datasetFlags.taskId,
4813
+ });
4814
+ return {
4815
+ exitCode: report.status === 'blocked' ? 1 : 0,
4816
+ stdout: stringifyJson(report, datasetFlags.json),
4817
+ stderr: '',
4818
+ };
4819
+ }
4820
+ if (action === 'verify') {
4821
+ const datasetFlags = parseDatasetCurationQueueRuntimeFlags(commandArgs.slice(1));
4822
+ if (datasetFlags.help) {
4823
+ return { exitCode: 0, stdout: `${renderDatasetCurationQueueHelp()}\n`, stderr: '' };
4824
+ }
4825
+ const report = await datasetCurationQueueVerifyImpl({
4826
+ queueDir: datasetFlags.queueDir,
4827
+ entityType: datasetFlags.entityType,
4828
+ taskId: datasetFlags.taskId,
4829
+ });
4830
+ return {
4831
+ exitCode: report.status === 'blocked' ? 1 : 0,
4832
+ stdout: stringifyJson(report, datasetFlags.json),
4833
+ stderr: '',
4834
+ };
4835
+ }
4836
+ const datasetFlags = parseDatasetCurationQueueBuildFlags(commandArgs.slice(1));
4837
+ if (datasetFlags.help) {
4838
+ return { exitCode: 0, stdout: `${renderDatasetCurationQueueHelp()}\n`, stderr: '' };
4839
+ }
4840
+ const report = await datasetCurationQueueBuildImpl({
4841
+ processesPath: datasetFlags.processesPath,
4842
+ flowsPath: datasetFlags.flowsPath,
4843
+ supportPaths: datasetFlags.supportPaths,
4844
+ externalFlowRefPaths: datasetFlags.externalFlowRefPaths,
4845
+ outDir: datasetFlags.outDir,
4846
+ excludeProcessIds: datasetFlags.excludeProcessIds,
4847
+ processLimit: datasetFlags.processLimit,
4848
+ });
4849
+ return {
4850
+ exitCode: report.status === 'blocked' ? 1 : 0,
4851
+ stdout: stringifyJson(report, datasetFlags.json),
4852
+ stderr: '',
4853
+ };
4854
+ }
4012
4855
  if (command === 'dataset' && subcommand === 'import-lca') {
4013
4856
  const action = commandArgs[0] ?? '';
4014
4857
  if (!action || action === '--help' || action === '-h') {
@@ -4033,6 +4876,8 @@ export async function executeCli(argv, deps) {
4033
4876
  mappingDir: datasetFlags.mappingDir,
4034
4877
  language: datasetFlags.language,
4035
4878
  validationJobs: datasetFlags.validationJobs,
4879
+ processBundles: datasetFlags.processBundles,
4880
+ processBundlesDir: datasetFlags.processBundlesDir,
4036
4881
  detectOnly: datasetFlags.detectOnly,
4037
4882
  failOnWarning: datasetFlags.failOnWarning,
4038
4883
  pythonBin: datasetFlags.pythonBin,
@@ -4067,6 +4912,55 @@ export async function executeCli(argv, deps) {
4067
4912
  stderr: '',
4068
4913
  };
4069
4914
  }
4915
+ if (command === 'dataset' && subcommand === 'patch') {
4916
+ const action = commandArgs[0] ?? '';
4917
+ if (!action || action === '--help' || action === '-h') {
4918
+ return { exitCode: 0, stdout: `${renderDatasetPatchHelp()}\n`, stderr: '' };
4919
+ }
4920
+ if (action !== 'apply') {
4921
+ throw new CliError("dataset patch action must be 'apply'.", {
4922
+ code: 'DATASET_PATCH_ACTION_INVALID',
4923
+ exitCode: 2,
4924
+ });
4925
+ }
4926
+ const datasetFlags = parseDatasetPatchApplyFlags(commandArgs.slice(1));
4927
+ if (datasetFlags.help) {
4928
+ return { exitCode: 0, stdout: `${renderDatasetPatchHelp()}\n`, stderr: '' };
4929
+ }
4930
+ const report = await datasetPatchApplyImpl({
4931
+ inputPath: datasetFlags.inputPath,
4932
+ patchPath: datasetFlags.patchPath,
4933
+ outPath: datasetFlags.outPath,
4934
+ outDir: datasetFlags.outDir,
4935
+ authoringPackageDir: datasetFlags.authoringPackageDir,
4936
+ requireAuthoringPackage: datasetFlags.requireAuthoringPackage,
4937
+ requireActionItemClosure: datasetFlags.requireActionItemClosure,
4938
+ });
4939
+ return {
4940
+ exitCode: report.status === 'blocked' ? 1 : 0,
4941
+ stdout: stringifyJson(report, datasetFlags.json),
4942
+ stderr: '',
4943
+ };
4944
+ }
4945
+ if (command === 'dataset' && subcommand === 'save-draft') {
4946
+ const datasetFlags = parseDatasetSaveDraftFlags(commandArgs);
4947
+ if (datasetFlags.help) {
4948
+ return { exitCode: 0, stdout: `${renderDatasetSaveDraftHelp()}\n`, stderr: '' };
4949
+ }
4950
+ const report = await datasetSaveDraftImpl({
4951
+ inputPath: datasetFlags.inputPath,
4952
+ type: datasetFlags.type,
4953
+ outDir: datasetFlags.outDir,
4954
+ commit: datasetFlags.commit,
4955
+ env: deps.env,
4956
+ fetchImpl: deps.fetchImpl,
4957
+ });
4958
+ return {
4959
+ exitCode: report.status === 'completed_with_failures' ? 1 : 0,
4960
+ stdout: stringifyJson(report, datasetFlags.json),
4961
+ stderr: '',
4962
+ };
4963
+ }
4070
4964
  if (command === 'dataset' && subcommand === 'validate') {
4071
4965
  const datasetFlags = parseDatasetValidateFlags(commandArgs);
4072
4966
  if (datasetFlags.help) {
@@ -4092,6 +4986,9 @@ export async function executeCli(argv, deps) {
4092
4986
  inputPath: datasetFlags.inputPath,
4093
4987
  outDir: datasetFlags.outDir,
4094
4988
  rootPolicy: datasetFlags.rootPolicy,
4989
+ compareRootPayload: datasetFlags.compareRootPayload,
4990
+ targetUserId: datasetFlags.targetUserId,
4991
+ stateCode: datasetFlags.stateCode,
4095
4992
  env: deps.env,
4096
4993
  fetchImpl: deps.fetchImpl,
4097
4994
  });
@@ -4249,6 +5146,44 @@ export async function executeCli(argv, deps) {
4249
5146
  stderr: '',
4250
5147
  };
4251
5148
  }
5149
+ if (command === 'dataset' && subcommand === 'maintenance') {
5150
+ const action = commandArgs[0] ?? '';
5151
+ if (!action || action === '--help' || action === '-h') {
5152
+ return { exitCode: 0, stdout: `${renderDatasetMaintenanceHelp()}\n`, stderr: '' };
5153
+ }
5154
+ if (action === 'clear-account') {
5155
+ const datasetFlags = parseDatasetMaintenanceClearAccountFlags(commandArgs.slice(1));
5156
+ if (datasetFlags.help) {
5157
+ return {
5158
+ exitCode: 0,
5159
+ stdout: `${renderDatasetMaintenanceClearAccountHelp()}\n`,
5160
+ stderr: '',
5161
+ };
5162
+ }
5163
+ const report = await datasetMaintenanceClearAccountImpl({
5164
+ outDir: datasetFlags.outDir,
5165
+ stateCodes: datasetFlags.stateCodes,
5166
+ pageSize: datasetFlags.pageSize,
5167
+ timeoutMs: datasetFlags.timeoutMs,
5168
+ commit: datasetFlags.commit,
5169
+ confirm: datasetFlags.confirm,
5170
+ env: deps.env,
5171
+ fetchImpl: deps.fetchImpl,
5172
+ });
5173
+ return {
5174
+ exitCode: report.status === 'completed_with_failures' ? 1 : 0,
5175
+ stdout: stringifyJson(report, datasetFlags.json),
5176
+ stderr: '',
5177
+ };
5178
+ }
5179
+ if (!['plan', 'apply', 'verify'].includes(action)) {
5180
+ throw new CliError("dataset maintenance action must be 'clear-account', 'plan', 'apply', or 'verify'.", {
5181
+ code: 'DATASET_MAINTENANCE_ACTION_INVALID',
5182
+ exitCode: 2,
5183
+ });
5184
+ }
5185
+ return plannedCommand('dataset', `maintenance ${action}`);
5186
+ }
4252
5187
  if (command === 'lifecyclemodel' && !subcommand) {
4253
5188
  return { exitCode: 0, stdout: `${renderLifecyclemodelHelp()}\n`, stderr: '' };
4254
5189
  }
@@ -4498,6 +5433,8 @@ export async function executeCli(argv, deps) {
4498
5433
  remoteCandidateSearch: processFlags.remoteCandidateSearch,
4499
5434
  remoteQuery: processFlags.remoteQuery,
4500
5435
  remoteLimit: processFlags.remoteLimit,
5436
+ remoteDataSource: processFlags.remoteDataSource,
5437
+ timeoutMs: processFlags.timeoutMs,
4501
5438
  env: deps.env,
4502
5439
  fetchImpl: deps.fetchImpl,
4503
5440
  });
@@ -4816,6 +5753,8 @@ export async function executeCli(argv, deps) {
4816
5753
  remoteCandidateSearch: flowFlags.remoteCandidateSearch,
4817
5754
  remoteQuery: flowFlags.remoteQuery,
4818
5755
  remoteLimit: flowFlags.remoteLimit,
5756
+ remoteDataSource: flowFlags.remoteDataSource,
5757
+ timeoutMs: flowFlags.timeoutMs,
4819
5758
  env: deps.env,
4820
5759
  fetchImpl: deps.fetchImpl,
4821
5760
  });
@@ -5213,6 +6152,7 @@ export async function executeCli(argv, deps) {
5213
6152
  return { exitCode: 0, stdout: `${renderQaLifecyclemodelHelp()}\n`, stderr: '' };
5214
6153
  }
5215
6154
  const report = await lifecyclemodelQaImpl({
6155
+ ...(qaFlags.rowsFile ? { rowsFile: qaFlags.rowsFile } : {}),
5216
6156
  runDir: qaFlags.runDir,
5217
6157
  outDir: qaFlags.outDir,
5218
6158
  startTs: qaFlags.startTs,