@tiangong-lca/cli 0.0.7 → 0.0.9

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 (59) hide show
  1. package/README.md +97 -16
  2. package/dist/src/cli.js +1429 -131
  3. package/dist/src/cli.js.map +1 -1
  4. package/dist/src/lib/dataset-author.js +100 -0
  5. package/dist/src/lib/dataset-author.js.map +1 -0
  6. package/dist/src/lib/dataset-bilingual.js +545 -0
  7. package/dist/src/lib/dataset-bilingual.js.map +1 -0
  8. package/dist/src/lib/dataset-contract.js +350 -0
  9. package/dist/src/lib/dataset-contract.js.map +1 -0
  10. package/dist/src/lib/dataset-evidence-search.js +636 -0
  11. package/dist/src/lib/dataset-evidence-search.js.map +1 -0
  12. package/dist/src/lib/dataset-import-lca.js +171 -0
  13. package/dist/src/lib/dataset-import-lca.js.map +1 -0
  14. package/dist/src/lib/dataset-remote-refresh.js +166 -0
  15. package/dist/src/lib/dataset-remote-refresh.js.map +1 -0
  16. package/dist/src/lib/dataset-remote-verify.js +543 -0
  17. package/dist/src/lib/dataset-remote-verify.js.map +1 -0
  18. package/dist/src/lib/dataset-validate.js +63 -7
  19. package/dist/src/lib/dataset-validate.js.map +1 -1
  20. package/dist/src/lib/flow-fetch-rows.js +12 -12
  21. package/dist/src/lib/flow-fetch-rows.js.map +1 -1
  22. package/dist/src/lib/flow-payload-validation.js +51 -0
  23. package/dist/src/lib/flow-payload-validation.js.map +1 -0
  24. package/dist/src/lib/flow-publish-reviewed-data.js +16 -0
  25. package/dist/src/lib/flow-publish-reviewed-data.js.map +1 -1
  26. package/dist/src/lib/flow-publish-version.js +182 -12
  27. package/dist/src/lib/flow-publish-version.js.map +1 -1
  28. package/dist/src/lib/{review-flow.js → flow-qa.js} +86 -28
  29. package/dist/src/lib/flow-qa.js.map +1 -0
  30. package/dist/src/lib/identity-preflight.js +1021 -0
  31. package/dist/src/lib/identity-preflight.js.map +1 -0
  32. package/dist/src/lib/{review-lifecyclemodel.js → lifecyclemodel-qa.js} +54 -54
  33. package/dist/src/lib/lifecyclemodel-qa.js.map +1 -0
  34. package/dist/src/lib/process-auto-build.js +147 -0
  35. package/dist/src/lib/process-auto-build.js.map +1 -1
  36. package/dist/src/lib/process-dedup-review.js +51 -0
  37. package/dist/src/lib/process-dedup-review.js.map +1 -1
  38. package/dist/src/lib/process-flow-build-plan.js +1071 -0
  39. package/dist/src/lib/process-flow-build-plan.js.map +1 -0
  40. package/dist/src/lib/process-payload-validation.js +14 -7
  41. package/dist/src/lib/process-payload-validation.js.map +1 -1
  42. package/dist/src/lib/process-publish-build.js +122 -4
  43. package/dist/src/lib/process-publish-build.js.map +1 -1
  44. package/dist/src/lib/{review-process.js → process-qa.js} +259 -117
  45. package/dist/src/lib/process-qa.js.map +1 -0
  46. package/dist/src/lib/process-refresh-references.js +19 -10
  47. package/dist/src/lib/process-refresh-references.js.map +1 -1
  48. package/dist/src/lib/process-required-fields.js +810 -0
  49. package/dist/src/lib/process-required-fields.js.map +1 -0
  50. package/dist/src/lib/process-save-draft-run.js +4 -1
  51. package/dist/src/lib/process-save-draft-run.js.map +1 -1
  52. package/dist/src/lib/publish.js +100 -0
  53. package/dist/src/lib/publish.js.map +1 -1
  54. package/dist/src/lib/runtime-rulesets.js +283 -0
  55. package/dist/src/lib/runtime-rulesets.js.map +1 -0
  56. package/package.json +2 -2
  57. package/dist/src/lib/review-flow.js.map +0 -1
  58. package/dist/src/lib/review-lifecyclemodel.js.map +0 -1
  59. package/dist/src/lib/review-process.js.map +0 -1
package/dist/src/cli.js CHANGED
@@ -21,11 +21,14 @@ import { runProcessDedupReview, } from './lib/process-dedup-review.js';
21
21
  import { runProcessResumeBuild, } from './lib/process-resume-build.js';
22
22
  import { runProcessPublishBuild, } from './lib/process-publish-build.js';
23
23
  import { runProcessSaveDraft, } from './lib/process-save-draft-run.js';
24
+ import { runProcessRequiredFieldsComplete, } from './lib/process-required-fields.js';
24
25
  import { runProcessVerifyRows, } from './lib/process-verify-rows.js';
26
+ import { runFlowBuildPlanMaterialize, runFlowBuildPlanValidate, runProcessBuildPlanMaterialize, runProcessBuildPlanValidate, } from './lib/process-flow-build-plan.js';
27
+ import { runFlowIdentityPreflight, runProcessIdentityPreflight, } from './lib/identity-preflight.js';
25
28
  import { runPublish } from './lib/publish.js';
26
- import { runProcessReview, } from './lib/review-process.js';
27
- import { runFlowReview, } from './lib/review-flow.js';
28
- import { runLifecyclemodelReview, } from './lib/review-lifecyclemodel.js';
29
+ import { runProcessQa } from './lib/process-qa.js';
30
+ import { runFlowQa } from './lib/flow-qa.js';
31
+ import { runLifecyclemodelQa, } from './lib/lifecyclemodel-qa.js';
29
32
  import { runFlowRemediate, } from './lib/flow-remediate.js';
30
33
  import { runFlowFetchRows, } from './lib/flow-fetch-rows.js';
31
34
  import { runFlowMaterializeDecisions, } from './lib/flow-materialize-decisions.js';
@@ -39,6 +42,13 @@ import { executeRemoteCommand, getRemoteCommandHelp } from './lib/remote.js';
39
42
  import { runValidation, } from './lib/validation.js';
40
43
  import { runDatasetValidate, } from './lib/dataset-validate.js';
41
44
  import { runDatasetReferencesRewrite, } from './lib/dataset-references-rewrite.js';
45
+ import { runDatasetRemoteRefresh, } from './lib/dataset-remote-refresh.js';
46
+ import { runDatasetRemoteVerify, } from './lib/dataset-remote-verify.js';
47
+ import { runDatasetBilingualApply, runDatasetBilingualExtract, runDatasetBilingualValidate, } from './lib/dataset-bilingual.js';
48
+ import { runDatasetEvidenceSearch, } from './lib/dataset-evidence-search.js';
49
+ import { runDatasetContract, } from './lib/dataset-contract.js';
50
+ import { runDatasetImportLcaConvert, } from './lib/dataset-import-lca.js';
51
+ import { runDatasetAuthor, } from './lib/dataset-author.js';
42
52
  function renderMainHelp(dotEnvStatus) {
43
53
  return `TianGong LCA CLI
44
54
 
@@ -57,11 +67,11 @@ Commands:
57
67
  Implemented Commands:
58
68
  doctor show environment diagnostics
59
69
  search flow | process | lifecyclemodel
60
- process get | list | scope-statistics | dedup-review | auto-build | resume-build | publish-build | save-draft | batch-build | refresh-references | verify-rows
61
- dataset validate | references rewrite
62
- flow get | list | 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
70
+ 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
72
+ 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
63
73
  lifecyclemodel auto-build | validate-build | publish-build | save-draft | graph | build-resulting-process | publish-resulting-process | orchestrate
64
- review process | flow | lifecyclemodel
74
+ qa process | flow | lifecyclemodel
65
75
  publish run
66
76
  validation run
67
77
  admin embedding-run
@@ -78,16 +88,29 @@ Examples:
78
88
  tiangong-lca search process --input ./request.json --dry-run
79
89
  tiangong-lca process get --id <process-id>
80
90
  tiangong-lca process list --state-code 100 --limit 20
91
+ tiangong-lca process identity-preflight --input ./process-preflight.json --out-dir ./process-preflight
92
+ tiangong-lca process build-plan validate --input ./process-build-plan.json --out-dir ./process-build-plan
81
93
  tiangong-lca process scope-statistics --out-dir /abs/path/to/process-scope --state-code 0 --state-code 100
82
94
  tiangong-lca process dedup-review --input ./duplicate-groups.json --out-dir /abs/path/to/process-dedup
83
95
  tiangong-lca process auto-build --input ./pff-request.json --out-dir /abs/path/to/process-run
84
96
  tiangong-lca process resume-build --run-dir /abs/path/to/process-run
85
97
  tiangong-lca process publish-build --run-dir /abs/path/to/process-run
98
+ tiangong-lca process complete-required-fields --input ./processes.jsonl --out ./processes.completed.jsonl --default-unit MJ
86
99
  tiangong-lca process save-draft --input ./patched-processes.jsonl --out-dir /abs/path/to/process-save-draft --dry-run
87
100
  tiangong-lca process batch-build --input ./batch-request.json --out-dir /abs/path/to/process-batch
88
101
  tiangong-lca process refresh-references --out-dir /abs/path/to/process-refresh --dry-run
89
102
  tiangong-lca process verify-rows --rows-file ./process-list-report.json --out-dir /abs/path/to/process-verify
90
103
  tiangong-lca dataset validate --input ./rows.jsonl --type auto --out-dir /abs/path/to/dataset-validate
104
+ tiangong-lca dataset contract get --type process --include schema,methodology,ruleset --out-dir ./contract
105
+ tiangong-lca dataset context-pack --type process --profile ai-import --out-dir ./context-pack
106
+ tiangong-lca dataset import-lca convert --input ./external-package --output-dir ./converted --from-format auto --target tidas
107
+ tiangong-lca dataset author --input ./source.pdf --target-types process,flow --out-dir ./authoring
108
+ tiangong-lca dataset verify-remote --input ./rows.jsonl --out-dir /abs/path/to/dataset-remote-verify
109
+ tiangong-lca dataset bilingual extract --input ./rows/processes.jsonl --type process --out-dir ./translation
110
+ tiangong-lca dataset bilingual apply --input ./rows/processes.jsonl --translations ./translation/trans-reviewed.jsonl --out ./rows/processes.translated.jsonl
111
+ tiangong-lca dataset bilingual validate --input ./rows/processes.translated.jsonl --type process --out-dir ./translation-validate
112
+ tiangong-lca dataset evidence-search plan --query "中国2026年电力结构数据" --out-dir ./evidence-search
113
+ tiangong-lca dataset evidence-search run --input ./evidence-search.request.json --results ./search-results.json --out-dir ./evidence-search
91
114
  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
92
115
  tiangong-lca lifecyclemodel auto-build --input ./lifecyclemodel-auto-build.request.json --out-dir /abs/path/to/lifecyclemodel-run
93
116
  tiangong-lca lifecyclemodel validate-build --run-dir /abs/path/to/lifecyclemodel-run
@@ -97,8 +120,10 @@ Examples:
97
120
  tiangong-lca lifecyclemodel orchestrate plan --input ./lifecyclemodel-orchestrate.request.json --out-dir /abs/path/to/lifecyclemodel-recursive-run
98
121
  tiangong-lca flow get --id <flow-id> --version <version>
99
122
  tiangong-lca flow list --id <flow-id> --state-code 100 --limit 20
123
+ tiangong-lca flow identity-preflight --input ./flow-preflight.json --out-dir ./flow-preflight
124
+ tiangong-lca flow build-plan validate --input ./flow-build-plan.json --out-dir ./flow-build-plan
100
125
  tiangong-lca flow fetch-rows --refs-file ./flow-refs.json --out-dir ./flow-fetch
101
- tiangong-lca flow materialize-decisions --decision-file ./approved-decisions.json --flow-rows-file ./review-input-rows.jsonl --out-dir ./flow-decisions
126
+ tiangong-lca flow materialize-decisions --decision-file ./approved-decisions.json --flow-rows-file ./qa-input-rows.jsonl --out-dir ./flow-decisions
102
127
  tiangong-lca flow remediate --input-file ./invalid-flows.jsonl --out-dir ./flow-remediation
103
128
  tiangong-lca flow publish-version --input-file ./ready-flows.jsonl --out-dir ./flow-publish --commit
104
129
  tiangong-lca flow publish-reviewed-data --flow-rows-file ./reviewed-flows.jsonl --original-flow-rows-file ./original-flows.jsonl --out-dir ./flow-publish-review
@@ -108,10 +133,10 @@ Examples:
108
133
  tiangong-lca flow apply-process-flow-repairs --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-repair-apply
109
134
  tiangong-lca flow regen-product --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-regeneration --apply
110
135
  tiangong-lca flow validate-processes --original-processes-file ./before.jsonl --patched-processes-file ./after.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-validation
111
- tiangong-lca review process --rows-file ./processes.jsonl --out-dir ./review
112
- tiangong-lca review process --run-root /abs/path/to/process-run --run-id <run_id> --out-dir ./review
113
- tiangong-lca review flow --rows-file ./flows.json --out-dir ./review
114
- tiangong-lca review lifecyclemodel --run-dir /abs/path/to/lifecyclemodel-run --out-dir ./lifecyclemodel-review
136
+ tiangong-lca qa process --rows-file ./processes.jsonl --out-dir ./qa
137
+ tiangong-lca qa process --run-root /abs/path/to/process-run --run-id <run_id> --out-dir ./qa
138
+ 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
115
140
  tiangong-lca publish run --input ./publish-request.json --dry-run
116
141
  tiangong-lca validation run --input-dir ./package --engine auto
117
142
  tiangong-lca admin embedding-run --input ./jobs.json
@@ -191,6 +216,13 @@ Options:
191
216
 
192
217
  Path rule:
193
218
  Relative out_dir values from the request body or --out-dir resolve from the request file directory.
219
+
220
+ Outputs written under out_dir:
221
+ - normalized-request.json
222
+ - collected-inputs.json
223
+ - relation-manifest.json
224
+ - verification-report.json
225
+ - publish-report.json
194
226
  `.trim();
195
227
  }
196
228
  function renderValidationHelp() {
@@ -210,12 +242,148 @@ function renderDatasetHelp() {
210
242
  tiangong-lca dataset <subcommand> [options]
211
243
 
212
244
  Implemented Subcommands:
245
+ contract get Write TIDAS schema / methodology / ruleset contract artifacts
246
+ context-pack Write an AI-ready TIDAS contract context pack
247
+ import-lca convert Convert supported external LCA packages through tidas-tools
248
+ author Extract source evidence and prepare TIDAS context packs for AI authoring
213
249
  validate Validate local flow / process / lifecyclemodel rows with the TIDAS SDK
250
+ verify-remote Verify dataset roots and TIDAS references against remote published versions
251
+ bilingual extract Extract bilingual translation units from local rows
252
+ bilingual apply Apply reviewed bilingual translations back to local rows
253
+ bilingual validate Validate bilingual rows with deterministic scans and schema/QA gates
254
+ evidence-search Plan or record field-level public evidence retrieval
214
255
  references rewrite Rewrite flow references in local process and lifecyclemodel rows
256
+ references refresh-remote Refresh local TIDAS reference versions to latest reachable remote rows
215
257
 
216
258
  Examples:
259
+ tiangong-lca dataset contract get --type process --include schema,methodology,ruleset --out-dir ./contract --help
260
+ tiangong-lca dataset context-pack --type process --profile ai-import --out-dir ./context-pack --help
261
+ tiangong-lca dataset import-lca convert --input ./external-package --output-dir ./converted --from-format auto --target tidas --help
262
+ tiangong-lca dataset author --input ./source.pdf --target-types process,flow --out-dir ./authoring --help
217
263
  tiangong-lca dataset validate --input ./rows.jsonl --type auto --out-dir ./dataset-validate --help
264
+ tiangong-lca dataset verify-remote --input ./rows.jsonl --out-dir ./dataset-remote-verify --help
265
+ tiangong-lca dataset bilingual extract --input ./rows.jsonl --type process --out-dir ./translation --help
266
+ tiangong-lca dataset bilingual apply --input ./rows.jsonl --translations ./trans-reviewed.jsonl --out ./rows.translated.jsonl --help
267
+ tiangong-lca dataset bilingual validate --input ./rows.translated.jsonl --type process --out-dir ./translation-validate --help
268
+ tiangong-lca dataset evidence-search plan --query "中国2026年电力结构数据" --out-dir ./evidence-search --help
269
+ tiangong-lca dataset evidence-search run --input ./request.json --results ./search-results.json --out-dir ./evidence-search --help
218
270
  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
+ tiangong-lca dataset references refresh-remote --input ./rows.jsonl --out ./rows.refreshed.jsonl --out-dir ./dataset-reference-refresh --help
272
+ `.trim();
273
+ }
274
+ function renderDatasetContractHelp() {
275
+ return `Usage:
276
+ tiangong-lca dataset contract get --type <type> --out-dir <dir> [options]
277
+
278
+ Options:
279
+ --type <type> TIDAS target type: process, flow, source, contact, unitgroup, flowproperty, lifecyclemodel, lciamethod
280
+ --include <list> Comma-separated or repeatable list: schema, methodology, ruleset (default: all)
281
+ --profile <name> default | ai-import (default: default)
282
+ --out-dir <dir> Artifact directory
283
+ --json Print compact JSON
284
+ -h, --help
285
+
286
+ Outputs written under --out-dir:
287
+ - outputs/contract-manifest.json
288
+ - outputs/schema.json when requested and available
289
+ - outputs/methodology.yaml when requested and available
290
+ - outputs/runtime-ruleset.json when requested and available
291
+ - outputs/contract-report.json
292
+ `.trim();
293
+ }
294
+ function renderDatasetContextPackHelp() {
295
+ return `Usage:
296
+ tiangong-lca dataset context-pack --type <type> --out-dir <dir> [options]
297
+
298
+ Options:
299
+ --type <type> TIDAS target type for AI authoring or repair
300
+ --include <list> Comma-separated or repeatable list: schema, methodology, ruleset (default: all)
301
+ --profile <name> default | ai-import (default: ai-import)
302
+ --out-dir <dir> Artifact directory
303
+ --json Print compact JSON
304
+ -h, --help
305
+
306
+ Outputs written under --out-dir:
307
+ - outputs/contract-manifest.json
308
+ - outputs/schema.json
309
+ - outputs/methodology.yaml when available
310
+ - outputs/runtime-ruleset.json when available
311
+ - outputs/ai-context.json
312
+ - outputs/ai-context.md
313
+ - outputs/contract-report.json
314
+ `.trim();
315
+ }
316
+ function renderDatasetImportLcaHelp() {
317
+ return `Usage:
318
+ tiangong-lca dataset import-lca convert --input <path> --output-dir <dir> [options]
319
+
320
+ Options:
321
+ --input <path> Source file, directory, or package to import
322
+ --output-dir <dir> Output directory for generated package and reports
323
+ --from-format <format> auto, ecospold1, ecospold2, openlca-jsonld, openlca-process-xlsx, simapro-csv
324
+ --target <target> tidas | ilcd | both (default: tidas)
325
+ --report <file> Conversion report path (default: <output-dir>/conversion-report.json)
326
+ --mapping-dir <dir> Optional custom mapping/reference data directory
327
+ --language <lang> Default language for generated text (default: en)
328
+ --validation-jobs <n> Parallel validation jobs passed to tidas-tools (default: 1)
329
+ --detect-only Only detect the input format and write the report
330
+ --fail-on-warning Return non-zero when converter warnings are present
331
+ --python <bin> Python executable (default: python3)
332
+ --tidas-tools-dir <dir> Explicit tidas-tools checkout path
333
+ --json Print compact JSON
334
+ -h, --help
335
+
336
+ Outputs written under --output-dir:
337
+ - conversion-report.json
338
+ - tidas/ when target includes TIDAS and not detect-only
339
+ - ilcd/ when target includes ILCD and not detect-only
340
+ - mapping.csv when not detect-only
341
+ - outputs/import-lca-report.json
342
+ `.trim();
343
+ }
344
+ function renderDatasetAuthorHelp() {
345
+ return `Usage:
346
+ tiangong-lca dataset author --input <file> --target-types <types> --out-dir <dir> [options]
347
+
348
+ Options:
349
+ --input <file> PDF, Excel, image, markdown, or source document file
350
+ --target-types <list> Comma-separated or repeatable TIDAS types, for example process,flow,source
351
+ --out-dir <dir> Artifact directory
352
+ --prompt <text> Optional extraction prompt passed to the unstructured parser
353
+ --provider <name> Optional unstructured parser provider override
354
+ --model <name> Optional unstructured parser model override
355
+ --timeout-ms <n> Parser timeout in milliseconds (default: 120000)
356
+ --json Print compact JSON
357
+ -h, --help
358
+
359
+ Outputs written under --out-dir:
360
+ - outputs/source-extract.json
361
+ - context/<type>/outputs/contract-manifest.json
362
+ - context/<type>/outputs/ai-context.json
363
+ - outputs/authoring-report.json
364
+
365
+ Environment:
366
+ TIANGONG_LCA_UNSTRUCTURED_API_BASE_URL and TIANGONG_LCA_UNSTRUCTURED_API_KEY
367
+ `.trim();
368
+ }
369
+ function renderDatasetRemoteVerifyHelp() {
370
+ return `Usage:
371
+ tiangong-lca dataset verify-remote --input <file> --out-dir <dir> [options]
372
+
373
+ Options:
374
+ --input <file> Local rows as JSON or JSONL; objects with rows[] are also accepted
375
+ --out-dir <dir> Artifact directory for the remote verification report
376
+ --root-policy <mode> existing | candidate (default: existing)
377
+ --json Print compact JSON
378
+ -h, --help
379
+
380
+ Environment:
381
+ TIANGONG_LCA_API_BASE_URL, TIANGONG_LCA_API_KEY, and TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
382
+
383
+ Outputs written under --out-dir:
384
+ - outputs/remote-verification-report.json
385
+ - outputs/remote-verification.jsonl
386
+ - outputs/blockers.jsonl
219
387
  `.trim();
220
388
  }
221
389
  function renderDatasetValidateHelp() {
@@ -235,21 +403,135 @@ Outputs written under --out-dir:
235
403
  - outputs/invalid-rows.jsonl
236
404
  `.trim();
237
405
  }
406
+ function renderDatasetBilingualHelp() {
407
+ return `Usage:
408
+ tiangong-lca dataset bilingual <extract|apply|validate> [options]
409
+
410
+ Subcommands:
411
+ extract Extract trans-units.jsonl from process/flow/lifecyclemodel rows
412
+ apply Apply reviewed translations to rows and write translation-evidence.json
413
+ validate Run placeholder/mixed-language scans plus schema and process/flow review gates
414
+
415
+ Examples:
416
+ tiangong-lca dataset bilingual extract --input ./rows/processes.jsonl --type process --out-dir ./translation
417
+ tiangong-lca dataset bilingual apply --input ./rows/processes.jsonl --translations ./translation/trans-reviewed.jsonl --out ./rows/processes.translated.jsonl
418
+ tiangong-lca dataset bilingual validate --input ./rows/processes.translated.jsonl --type process --out-dir ./translation-validate
419
+ `.trim();
420
+ }
421
+ function renderDatasetBilingualExtractHelp() {
422
+ return `Usage:
423
+ tiangong-lca dataset bilingual extract --input <file> [options]
424
+
425
+ Options:
426
+ --input <file> Local rows as JSON or JSONL
427
+ --type <type> auto | flow | process | lifecyclemodel (default: auto)
428
+ --source-lang <lang> Source language code (default: en)
429
+ --target-lang <lang> Target language code (default: zh)
430
+ --out-dir <dir> Artifact directory for trans-units.jsonl and extract-report.json
431
+ --json Print compact JSON
432
+ -h, --help
433
+
434
+ Outputs written under --out-dir:
435
+ - outputs/trans-units.jsonl
436
+ - outputs/extract-report.json
437
+ `.trim();
438
+ }
439
+ function renderDatasetBilingualApplyHelp() {
440
+ return `Usage:
441
+ tiangong-lca dataset bilingual apply --input <file> --translations <file> --out <file> [options]
442
+
443
+ Options:
444
+ --input <file> Local rows as JSON or JSONL
445
+ --translations <file> Reviewed translation JSONL from extract units
446
+ --out <file> Output JSONL with translations applied
447
+ --target-lang <lang> Target language code (default: zh)
448
+ --out-dir <dir> Optional artifact directory; defaults to the output file directory
449
+ --json Print compact JSON
450
+ -h, --help
451
+
452
+ Translation row fields:
453
+ unit_id, row_index, field_path, source_lang, target_lang, source_text, translated_text,
454
+ basis, review_status, reviewer
455
+
456
+ Outputs:
457
+ - translated rows at --out
458
+ - outputs/translation-evidence.json
459
+ - outputs/bilingual-apply-report.json
460
+ `.trim();
461
+ }
462
+ function renderDatasetBilingualValidateHelp() {
463
+ return `Usage:
464
+ tiangong-lca dataset bilingual validate --input <file> [options]
465
+
466
+ Options:
467
+ --input <file> Local rows as JSON or JSONL
468
+ --type <type> auto | flow | process | lifecyclemodel (default: auto)
469
+ --out-dir <dir> Artifact directory for scan, schema, and QA outputs
470
+ --json Print compact JSON
471
+ -h, --help
472
+
473
+ Outputs written under --out-dir:
474
+ - outputs/bilingual-validate-report.json
475
+ - outputs/bilingual-findings.jsonl
476
+ - schema/outputs/validation-report.json
477
+ - qa/process/... and/or qa/flow/... when applicable
478
+ `.trim();
479
+ }
480
+ function renderDatasetEvidenceSearchHelp() {
481
+ return `Usage:
482
+ tiangong-lca dataset evidence-search <plan|run> [options]
483
+
484
+ Plan:
485
+ tiangong-lca dataset evidence-search plan --query <text> --out-dir <dir>
486
+
487
+ Run:
488
+ tiangong-lca dataset evidence-search run --input <request.json> --results <search-results.json> --out-dir <dir>
489
+ tiangong-lca dataset evidence-search run --query <text> --provider-url <url> --out-dir <dir>
490
+
491
+ Options:
492
+ --query <text> Evidence question when no --input is supplied
493
+ --input <file> JSON request with question, field, budget, preferred_domains, and required_evidence
494
+ --results <file> Normalized external search results JSON/JSONL captured from web/search tools
495
+ --provider-url <url> Optional generic JSON search provider endpoint
496
+ --provider-key <key> Optional bearer token for --provider-url
497
+ --profile <profile> shallow | balanced | deep (default: balanced)
498
+ --max-queries <n> Override query budget
499
+ --max-results-per-query <n> Override per-query result budget
500
+ --timeout-ms <n> Provider request timeout in milliseconds
501
+ --out-dir <dir> Artifact directory
502
+ --json Print compact JSON
503
+ -h, --help
504
+
505
+ Outputs written under --out-dir:
506
+ - outputs/evidence-search-plan.json
507
+ - outputs/evidence-search-results.jsonl
508
+ - outputs/evidence-search-report.json
509
+ - outputs/evidence-search-declaration.json when evidence is absent or only partial
510
+ `.trim();
511
+ }
238
512
  function renderDatasetReferencesHelp() {
239
513
  return `Usage:
514
+ tiangong-lca dataset references <rewrite|refresh-remote> [options]
515
+
516
+ Rewrite:
240
517
  tiangong-lca dataset references rewrite --input <file> --from flow:<id>[@<version>] --to flow:<id>[@<version>] [options]
241
518
 
519
+ Refresh remote versions:
520
+ tiangong-lca dataset references refresh-remote --input <file> --out <file> --out-dir <dir> [options]
521
+
242
522
  Options:
243
523
  --input <file> Local rows as JSON or JSONL; process and lifecyclemodel rows are supported
244
524
  --from <ref> Source flow reference, for example flow:<old-id>@01.00.000
245
525
  --to <ref> Target flow reference, for example flow:<new-id>@01.01.000
246
- --type <type> Repeatable row type filter: process | lifecyclemodel (default: both)
247
- --types <csv> Comma-separated alias for one or more row types
248
- --scope <label> Optional artifact label for the already-frozen input scope
249
- --out-dir <dir> Artifact directory for rewrite plan and patched rows
250
- --commit Execute state-aware save-draft writes for patched rows
251
- --dry-run Keep the command local-only (default)
252
- --json Print compact JSON
526
+ --out <file> Output JSONL path for refresh-remote patched rows
527
+ --root-policy <mode> existing | candidate for refresh-remote root rows (default: existing)
528
+ --type <type> Repeatable row type filter: process | lifecyclemodel (default: both)
529
+ --types <csv> Comma-separated alias for one or more row types
530
+ --scope <label> Optional artifact label for the already-frozen input scope
531
+ --out-dir <dir> Artifact directory for rewrite plan and patched rows
532
+ --commit Execute state-aware save-draft writes for patched rows
533
+ --dry-run Keep the command local-only (default)
534
+ --json Print compact JSON
253
535
  -h, --help
254
536
 
255
537
  Environment:
@@ -261,6 +543,10 @@ Outputs written under --out-dir:
261
543
  - outputs/patched-rows.jsonl
262
544
  - outputs/rewrite-plan.json
263
545
  - outputs/summary.json
546
+ - outputs/remote-refresh-report.json
547
+ - outputs/remote-refresh-patches.jsonl
548
+ - pre-refresh-verify/outputs/remote-verification-report.json
549
+ - post-refresh-verify/outputs/remote-verification-report.json
264
550
  `.trim();
265
551
  }
266
552
  function renderFlowHelp() {
@@ -270,7 +556,9 @@ function renderFlowHelp() {
270
556
  Implemented Subcommands:
271
557
  get Load one flow dataset by identifier through direct Supabase access
272
558
  list Enumerate flow datasets through direct Supabase access with deterministic filters
273
- fetch-rows Materialize real DB flow refs into local review-input rows and fetch artifacts
559
+ identity-preflight Compare one target flow against local candidates before generation
560
+ build-plan Validate or materialize a flow build plan into gate artifacts
561
+ fetch-rows Materialize real DB flow refs into local qa-input rows and fetch artifacts
274
562
  materialize-decisions Materialize approved merge decisions into canonical-map, rewrite-plan, and seed artifacts
275
563
  remediate Deterministically repair invalid local flow rows and emit artifact-first outputs
276
564
  publish-version Publish remediated flow versions through the unified CLI surface
@@ -286,6 +574,8 @@ Examples:
286
574
  tiangong-lca flow --help
287
575
  tiangong-lca flow get --help
288
576
  tiangong-lca flow list --help
577
+ tiangong-lca flow identity-preflight --help
578
+ tiangong-lca flow build-plan validate --help
289
579
  tiangong-lca flow fetch-rows --help
290
580
  tiangong-lca flow materialize-decisions --help
291
581
  tiangong-lca flow remediate --help
@@ -299,6 +589,52 @@ Examples:
299
589
  tiangong-lca flow validate-processes --help
300
590
  `.trim();
301
591
  }
592
+ function renderFlowBuildPlanHelp() {
593
+ return `Usage:
594
+ tiangong-lca flow build-plan <validate|materialize> --input <file> [options]
595
+
596
+ Options:
597
+ --input <file> JSON flow build plan; materialize writes a canonical flowDataSet
598
+ --out-dir <dir> Optional artifact directory for gate outputs
599
+ --report-only Print blocker reports with exit code 0
600
+ --json Print compact JSON
601
+ -h, --help
602
+
603
+ Outputs written under --out-dir:
604
+ - outputs/build-plan-gate-report.json
605
+ - outputs/materialized-flow.json
606
+ `.trim();
607
+ }
608
+ function renderFlowIdentityPreflightHelp() {
609
+ return `Usage:
610
+ tiangong-lca flow identity-preflight --input <file> [options]
611
+
612
+ Options:
613
+ --input <file> JSON preflight request with target flow and optional candidates
614
+ --candidate-input <path>
615
+ Optional JSON/JSONL file or directory of candidate flow rows; repeatable
616
+ --remote-candidates
617
+ Also fetch candidate rows from flow_hybrid_search
618
+ --remote-query <text>
619
+ Override the remote search query; defaults to target identity text
620
+ --remote-limit <n>
621
+ Limit remote candidate rows after fetch
622
+ --out-dir <dir> Optional artifact directory for identity decision outputs
623
+ --json Print compact JSON
624
+ -h, --help
625
+
626
+ Input contract:
627
+ {
628
+ "target": { "...": "flow target or canonical flowDataSet" },
629
+ "candidates": [{ "...": "existing flow row or canonical flowDataSet" }]
630
+ }
631
+
632
+ Outputs written under --out-dir:
633
+ - outputs/identity-decision.json
634
+ - outputs/identity-candidates.jsonl
635
+ - outputs/identity-candidate-sources.json
636
+ `.trim();
637
+ }
302
638
  function renderFlowGetHelp() {
303
639
  return `Usage:
304
640
  tiangong-lca flow get --id <flow-id> [options]
@@ -387,7 +723,7 @@ Required env:
387
723
 
388
724
  Outputs written under --out-dir:
389
725
  - resolved-flow-rows.jsonl
390
- - review-input-rows.jsonl
726
+ - qa-input-rows.jsonl
391
727
  - fetch-summary.json
392
728
  - missing-flow-refs.jsonl
393
729
  - ambiguous-flow-refs.jsonl
@@ -435,6 +771,7 @@ Environment:
435
771
  Outputs written under --out-dir:
436
772
  - flows_tidas_sdk_plus_classification_mcp_success_list.json
437
773
  - flows_tidas_sdk_plus_classification_remote_validation_failed.jsonl
774
+ - flow-publish-version-gate-report.json
438
775
  - flows_tidas_sdk_plus_classification_mcp_sync_report.json
439
776
  `.trim();
440
777
  }
@@ -470,6 +807,7 @@ Outputs written under --out-dir:
470
807
  - publish-report.json
471
808
  - flows_tidas_sdk_plus_classification_mcp_success_list.json
472
809
  - flows_tidas_sdk_plus_classification_remote_validation_failed.jsonl
810
+ - flow-publish-version-gate-report.json
473
811
  - flows_tidas_sdk_plus_classification_mcp_sync_report.json
474
812
  `.trim();
475
813
  }
@@ -603,56 +941,55 @@ Outputs written under --out-dir:
603
941
  - validation-failures.jsonl
604
942
  `.trim();
605
943
  }
606
- function renderReviewHelp() {
944
+ function renderQaHelp() {
607
945
  return `Usage:
608
- tiangong-lca review <subcommand> [options]
946
+ tiangong-lca qa <subcommand> [options]
609
947
 
610
948
  Implemented Subcommands:
611
- process Review process build runs or rows-file snapshots and emit artifact-first findings
612
- flow Review local flow governance snapshots and emit artifact-first findings
613
- lifecyclemodel Review one local lifecyclemodel build run and emit artifact-first findings
949
+ process Run deterministic process QA for build runs or rows-file snapshots
950
+ flow Run deterministic flow QA for local governance snapshots
951
+ lifecyclemodel Run deterministic lifecyclemodel QA for one local build run
614
952
 
615
953
  Examples:
616
- tiangong-lca review --help
617
- tiangong-lca review process --help
618
- tiangong-lca review flow --help
619
- tiangong-lca review lifecyclemodel --help
954
+ tiangong-lca qa process --help
955
+ tiangong-lca qa flow --help
956
+ tiangong-lca qa lifecyclemodel --help
620
957
  `.trim();
621
958
  }
622
- function renderReviewProcessHelp() {
959
+ function renderQaProcessHelp() {
623
960
  return `Usage:
624
- tiangong-lca review process (--rows-file <file> | --run-root <dir>) --out-dir <dir> [options]
961
+ tiangong-lca qa process (--rows-file <file> | --run-root <dir>) --out-dir <dir> [options]
625
962
 
626
963
  Options:
627
964
  --rows-file <file> Process rows JSON/JSONL file; full process list reports with rows[] are also accepted
628
965
  --run-root <dir> Process build run root containing exports/processes
629
- --run-id <id> Optional review run identifier; defaults to the rows-file name or run-root basename
630
- --out-dir <dir> Review artifact output directory
966
+ --run-id <id> Optional QA run identifier; defaults to the rows-file name or run-root basename
967
+ --out-dir <dir> QA artifact output directory
631
968
  --start-ts <iso> Optional run start timestamp
632
969
  --end-ts <iso> Optional run end timestamp
633
- --logic-version <name> Review logic version label (default: v2.1)
634
- --enable-llm Enable optional review-only semantic review via the CLI LLM client
635
- --llm-model <name> Override TIANGONG_LCA_REVIEW_LLM_MODEL for this review command
636
- --llm-max-processes <n> Cap how many process summaries are sent to the LLM (default: 8)
970
+ --logic-version <name> QA logic version label (default: v2.1)
971
+ --enable-llm Deprecated no-op; process semantic authoring now belongs in Foundry curation
972
+ --llm-model <name> Deprecated no-op kept for older scripts
973
+ --llm-max-processes <n> Deprecated no-op kept for older scripts
637
974
  --json Print compact JSON
638
975
  -h, --help
639
976
  `.trim();
640
977
  }
641
- function renderReviewFlowHelp() {
978
+ function renderQaFlowHelp() {
642
979
  return `Usage:
643
- tiangong-lca review flow (--rows-file <file> | --flows-dir <dir> | --run-root <dir>) --out-dir <dir> [options]
980
+ tiangong-lca qa flow (--rows-file <file> | --flows-dir <dir> | --run-root <dir>) --out-dir <dir> [options]
644
981
 
645
982
  Options:
646
- --rows-file <file> Flow rows JSON / JSONL file; the CLI materializes review-input/flows automatically
983
+ --rows-file <file> Flow rows JSON / JSONL file; the CLI materializes qa-input/flows automatically
647
984
  --flows-dir <dir> Directory containing per-flow JSON files
648
985
  --run-root <dir> Existing run root containing cache/flows or exports/flows
649
986
  --run-id <id> Optional run identifier override
650
- --out-dir <dir> Review artifact output directory
987
+ --out-dir <dir> QA artifact output directory
651
988
  --start-ts <iso> Optional run start timestamp
652
989
  --end-ts <iso> Optional run end timestamp
653
- --logic-version <name> Review logic version label (default: flow-v1.0-cli)
654
- --enable-llm Enable optional review-only semantic review via the CLI LLM client
655
- --llm-model <name> Override TIANGONG_LCA_REVIEW_LLM_MODEL for this review command
990
+ --logic-version <name> QA logic version label (default: flow-v1.0-cli)
991
+ --enable-llm Enable optional QA-only semantic checks via the CLI LLM client
992
+ --llm-model <name> Override TIANGONG_LCA_REVIEW_LLM_MODEL for this QA command
656
993
  --llm-max-flows <n> Cap how many flow summaries are sent to the LLM (default: 120)
657
994
  --llm-batch-size <n> Cap how many flow summaries each LLM batch sends (default: 20)
658
995
  --similarity-threshold <n> Similarity threshold for duplicate-candidate warnings (default: 0.92)
@@ -661,23 +998,23 @@ Options:
661
998
  -h, --help
662
999
  `.trim();
663
1000
  }
664
- function renderReviewLifecyclemodelHelp() {
1001
+ function renderQaLifecyclemodelHelp() {
665
1002
  return `Usage:
666
- tiangong-lca review lifecyclemodel --run-dir <dir> --out-dir <dir> [options]
1003
+ tiangong-lca qa lifecyclemodel --run-dir <dir> --out-dir <dir> [options]
667
1004
 
668
1005
  Options:
669
1006
  --run-dir <dir> Existing lifecyclemodel auto-build run directory
670
- --out-dir <dir> Review artifact output directory
1007
+ --out-dir <dir> QA artifact output directory
671
1008
  --start-ts <iso> Optional run start timestamp
672
1009
  --end-ts <iso> Optional run end timestamp
673
- --logic-version <name> Review logic version label (default: lifecyclemodel-review-v1.0)
1010
+ --logic-version <name> QA logic version label (default: lifecyclemodel-qa-v1.0)
674
1011
  --json Print compact JSON
675
1012
  -h, --help
676
1013
 
677
1014
  This command:
678
1015
  - reads one existing lifecyclemodel build run under models/*/tidas_bundle/lifecyclemodels
679
1016
  - aggregates validate-build findings when reports/lifecyclemodel-validate-build-report.json is present
680
- - emits artifact-first model summaries, findings, markdown review notes, and a structured report
1017
+ - emits artifact-first model summaries, findings, markdown QA notes, and a structured report
681
1018
  `.trim();
682
1019
  }
683
1020
  function renderLifecyclemodelBuildResultingProcessHelp() {
@@ -949,6 +1286,36 @@ Outputs written under --out-dir:
949
1286
  - reports/process-scope-statistics.zh-CN.md
950
1287
  `.trim();
951
1288
  }
1289
+ function renderProcessIdentityPreflightHelp() {
1290
+ return `Usage:
1291
+ tiangong-lca process identity-preflight --input <file> [options]
1292
+
1293
+ Options:
1294
+ --input <file> JSON preflight request with target process and optional candidates
1295
+ --candidate-input <path>
1296
+ Optional JSON/JSONL file or directory of candidate process rows; repeatable
1297
+ --remote-candidates
1298
+ Also fetch candidate rows from process_hybrid_search
1299
+ --remote-query <text>
1300
+ Override the remote search query; defaults to target identity text
1301
+ --remote-limit <n>
1302
+ Limit remote candidate rows after fetch
1303
+ --out-dir <dir> Optional artifact directory for identity decision outputs
1304
+ --json Print compact JSON
1305
+ -h, --help
1306
+
1307
+ Input contract:
1308
+ {
1309
+ "target": { "...": "process target or canonical processDataSet" },
1310
+ "candidates": [{ "...": "existing process row or canonical processDataSet" }]
1311
+ }
1312
+
1313
+ Outputs written under --out-dir:
1314
+ - outputs/identity-decision.json
1315
+ - outputs/identity-candidates.jsonl
1316
+ - outputs/identity-candidate-sources.json
1317
+ `.trim();
1318
+ }
952
1319
  function renderProcessDedupReviewHelp() {
953
1320
  return `Usage:
954
1321
  tiangong-lca process dedup-review --input <file> --out-dir <dir> [options]
@@ -1045,6 +1412,30 @@ Outputs written under --out-dir:
1045
1412
  - outputs/save-draft-rpc/summary.json
1046
1413
  `.trim();
1047
1414
  }
1415
+ function renderProcessRequiredFieldsHelp() {
1416
+ return `Usage:
1417
+ tiangong-lca process complete-required-fields --input <file> --out <file> [options]
1418
+
1419
+ Options:
1420
+ --input <file> Process rows JSON/JSONL file
1421
+ --out <file> Output JSONL with required fields completed
1422
+ --out-dir <dir> Optional artifact directory for report and evidence
1423
+ --flows <file> Optional flow rows JSON/JSONL used to infer reference-flow units
1424
+ --default-unit <unit> Unit suffix to use when it cannot be inferred (default: unit)
1425
+ --json Print compact JSON
1426
+ -h, --help
1427
+
1428
+ Annual supply / production volume policy:
1429
+ 1. keep an existing valid annualized annualSupplyOrProductionVolume, for example "3.6 MJ/year";
1430
+ 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.
1432
+
1433
+ Outputs:
1434
+ - completed rows at --out
1435
+ - outputs/process-required-fields-report.json
1436
+ - outputs/process-required-fields-evidence.jsonl
1437
+ `.trim();
1438
+ }
1048
1439
  function renderProcessRefreshReferencesHelp() {
1049
1440
  return `Usage:
1050
1441
  tiangong-lca process refresh-references --out-dir <dir> [options]
@@ -1115,11 +1506,14 @@ function renderProcessHelp() {
1115
1506
  Implemented Subcommands:
1116
1507
  get Load one process dataset by identifier through direct Supabase access
1117
1508
  list List visible process rows through direct Supabase access
1509
+ identity-preflight Compare one target process against local candidates before generation
1510
+ build-plan Validate or materialize a process build plan into gate artifacts
1118
1511
  scope-statistics Count repeatable coverage statistics from visible or owner-filtered process snapshots
1119
1512
  dedup-review Review grouped duplicate process candidates and emit keep/delete evidence
1120
1513
  auto-build Prepare a local process-from-flow run scaffold and artifact workspace
1121
1514
  resume-build Prepare a local resume handoff from one existing process build run
1122
1515
  publish-build Prepare publish handoff artifacts from one existing process build run
1516
+ complete-required-fields Complete deterministic required authoring fields in process rows
1123
1517
  save-draft Save canonical process datasets through the state-aware draft-maintenance path
1124
1518
  batch-build Run multiple process auto-build requests through one batch-oriented CLI surface
1125
1519
  refresh-references Refresh current-user process references to the latest reachable dataset versions
@@ -1129,17 +1523,36 @@ Examples:
1129
1523
  tiangong-lca process --help
1130
1524
  tiangong-lca process get --id <process-id>
1131
1525
  tiangong-lca process list --state-code 100 --limit 20 --help
1526
+ tiangong-lca process identity-preflight --input ./process-preflight.json --help
1527
+ tiangong-lca process build-plan validate --input ./process-build-plan.json --help
1132
1528
  tiangong-lca process scope-statistics --out-dir ./process-scope --state-code 0 --state-code 100 --help
1133
1529
  tiangong-lca process dedup-review --input ./duplicate-groups.json --out-dir ./process-dedup --help
1134
1530
  tiangong-lca process auto-build --help
1135
1531
  tiangong-lca process resume-build --run-dir /abs/path/to/process-run --help
1136
1532
  tiangong-lca process publish-build --run-dir /abs/path/to/process-run --help
1533
+ tiangong-lca process complete-required-fields --input ./processes.jsonl --out ./processes.completed.jsonl --help
1137
1534
  tiangong-lca process save-draft --input ./patched-processes.jsonl --help
1138
1535
  tiangong-lca process batch-build --input ./batch-request.json --help
1139
1536
  tiangong-lca process refresh-references --out-dir ./process-refresh --help
1140
1537
  tiangong-lca process verify-rows --rows-file ./process-list-report.json --out-dir ./process-verify --help
1141
1538
  `.trim();
1142
1539
  }
1540
+ function renderProcessBuildPlanHelp() {
1541
+ return `Usage:
1542
+ tiangong-lca process build-plan <validate|materialize> --input <file> [options]
1543
+
1544
+ Options:
1545
+ --input <file> JSON process build plan; materialize writes a canonical processDataSet
1546
+ --out-dir <dir> Optional artifact directory for gate outputs
1547
+ --report-only Print blocker reports with exit code 0
1548
+ --json Print compact JSON
1549
+ -h, --help
1550
+
1551
+ Outputs written under --out-dir:
1552
+ - outputs/build-plan-gate-report.json
1553
+ - outputs/materialized-process.json
1554
+ `.trim();
1555
+ }
1143
1556
  function renderDoctorText(report) {
1144
1557
  const lines = [
1145
1558
  'TianGong CLI doctor',
@@ -1375,6 +1788,329 @@ function parseDatasetValidateFlags(args) {
1375
1788
  outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1376
1789
  };
1377
1790
  }
1791
+ function parseDatasetContractFlags(args) {
1792
+ let values;
1793
+ try {
1794
+ ({ values } = parseArgs({
1795
+ args,
1796
+ allowPositionals: false,
1797
+ strict: true,
1798
+ options: {
1799
+ help: { type: 'boolean', short: 'h' },
1800
+ json: { type: 'boolean' },
1801
+ type: { type: 'string' },
1802
+ include: { type: 'string', multiple: true },
1803
+ profile: { type: 'string' },
1804
+ 'out-dir': { type: 'string' },
1805
+ },
1806
+ }));
1807
+ }
1808
+ catch (error) {
1809
+ throw new CliError(String(error), {
1810
+ code: 'INVALID_ARGS',
1811
+ exitCode: 2,
1812
+ });
1813
+ }
1814
+ return {
1815
+ help: Boolean(values.help),
1816
+ json: Boolean(values.json),
1817
+ type: typeof values.type === 'string' ? values.type : undefined,
1818
+ include: Array.isArray(values.include)
1819
+ ? values.include.filter((value) => typeof value === 'string')
1820
+ : [],
1821
+ profile: typeof values.profile === 'string' ? values.profile : undefined,
1822
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1823
+ };
1824
+ }
1825
+ function parseDatasetImportLcaConvertFlags(args) {
1826
+ let values;
1827
+ try {
1828
+ ({ values } = parseArgs({
1829
+ args,
1830
+ allowPositionals: false,
1831
+ strict: true,
1832
+ options: {
1833
+ help: { type: 'boolean', short: 'h' },
1834
+ json: { type: 'boolean' },
1835
+ input: { type: 'string' },
1836
+ 'output-dir': { type: 'string' },
1837
+ 'from-format': { type: 'string' },
1838
+ target: { type: 'string' },
1839
+ report: { type: 'string' },
1840
+ 'mapping-dir': { type: 'string' },
1841
+ language: { type: 'string' },
1842
+ 'validation-jobs': { type: 'string' },
1843
+ 'detect-only': { type: 'boolean' },
1844
+ 'fail-on-warning': { type: 'boolean' },
1845
+ python: { type: 'string' },
1846
+ 'tidas-tools-dir': { type: 'string' },
1847
+ },
1848
+ }));
1849
+ }
1850
+ catch (error) {
1851
+ throw new CliError(String(error), {
1852
+ code: 'INVALID_ARGS',
1853
+ exitCode: 2,
1854
+ });
1855
+ }
1856
+ const validationJobs = typeof values['validation-jobs'] === 'string' ? Number(values['validation-jobs']) : undefined;
1857
+ if (validationJobs !== undefined && (!Number.isInteger(validationJobs) || validationJobs < 0)) {
1858
+ throw new CliError('--validation-jobs must be a non-negative integer.', {
1859
+ code: 'DATASET_IMPORT_LCA_VALIDATION_JOBS_INVALID',
1860
+ exitCode: 2,
1861
+ });
1862
+ }
1863
+ return {
1864
+ help: Boolean(values.help),
1865
+ json: Boolean(values.json),
1866
+ inputPath: typeof values.input === 'string' ? values.input : '',
1867
+ outputDir: typeof values['output-dir'] === 'string' ? values['output-dir'] : '',
1868
+ fromFormat: typeof values['from-format'] === 'string' ? values['from-format'] : undefined,
1869
+ target: typeof values.target === 'string' ? values.target : undefined,
1870
+ reportPath: typeof values.report === 'string' ? values.report : undefined,
1871
+ mappingDir: typeof values['mapping-dir'] === 'string' ? values['mapping-dir'] : undefined,
1872
+ language: typeof values.language === 'string' ? values.language : undefined,
1873
+ validationJobs,
1874
+ detectOnly: Boolean(values['detect-only']),
1875
+ failOnWarning: Boolean(values['fail-on-warning']),
1876
+ pythonBin: typeof values.python === 'string' ? values.python : undefined,
1877
+ tidasToolsDir: typeof values['tidas-tools-dir'] === 'string' ? values['tidas-tools-dir'] : undefined,
1878
+ };
1879
+ }
1880
+ function parseDatasetAuthorFlags(args) {
1881
+ let values;
1882
+ try {
1883
+ ({ values } = parseArgs({
1884
+ args,
1885
+ allowPositionals: false,
1886
+ strict: true,
1887
+ options: {
1888
+ help: { type: 'boolean', short: 'h' },
1889
+ json: { type: 'boolean' },
1890
+ input: { type: 'string' },
1891
+ 'target-types': { type: 'string', multiple: true },
1892
+ 'out-dir': { type: 'string' },
1893
+ prompt: { type: 'string' },
1894
+ provider: { type: 'string' },
1895
+ model: { type: 'string' },
1896
+ 'timeout-ms': { type: 'string' },
1897
+ },
1898
+ }));
1899
+ }
1900
+ catch (error) {
1901
+ throw new CliError(String(error), {
1902
+ code: 'INVALID_ARGS',
1903
+ exitCode: 2,
1904
+ });
1905
+ }
1906
+ const timeoutMs = typeof values['timeout-ms'] === 'string' ? Number(values['timeout-ms']) : undefined;
1907
+ if (timeoutMs !== undefined && (!Number.isInteger(timeoutMs) || timeoutMs <= 0)) {
1908
+ throw new CliError('--timeout-ms must be a positive integer.', {
1909
+ code: 'DATASET_AUTHOR_TIMEOUT_INVALID',
1910
+ exitCode: 2,
1911
+ });
1912
+ }
1913
+ return {
1914
+ help: Boolean(values.help),
1915
+ json: Boolean(values.json),
1916
+ inputPath: typeof values.input === 'string' ? values.input : '',
1917
+ targetTypes: Array.isArray(values['target-types'])
1918
+ ? values['target-types'].filter((value) => typeof value === 'string')
1919
+ : [],
1920
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1921
+ prompt: typeof values.prompt === 'string' ? values.prompt : undefined,
1922
+ provider: typeof values.provider === 'string' ? values.provider : undefined,
1923
+ model: typeof values.model === 'string' ? values.model : undefined,
1924
+ timeoutMs,
1925
+ };
1926
+ }
1927
+ function parseDatasetRemoteVerifyFlags(args) {
1928
+ let values;
1929
+ try {
1930
+ ({ values } = parseArgs({
1931
+ args,
1932
+ allowPositionals: false,
1933
+ strict: true,
1934
+ options: {
1935
+ help: { type: 'boolean', short: 'h' },
1936
+ json: { type: 'boolean' },
1937
+ input: { type: 'string' },
1938
+ 'out-dir': { type: 'string' },
1939
+ 'root-policy': { type: 'string' },
1940
+ },
1941
+ }));
1942
+ }
1943
+ catch (error) {
1944
+ throw new CliError(String(error), {
1945
+ code: 'INVALID_ARGS',
1946
+ exitCode: 2,
1947
+ });
1948
+ }
1949
+ const rawRootPolicy = typeof values['root-policy'] === 'string' ? values['root-policy'] : 'existing';
1950
+ if (!['existing', 'candidate'].includes(rawRootPolicy)) {
1951
+ throw new CliError("--root-policy must be 'existing' or 'candidate'.", {
1952
+ code: 'DATASET_REMOTE_VERIFY_ROOT_POLICY_INVALID',
1953
+ exitCode: 2,
1954
+ });
1955
+ }
1956
+ const rootPolicy = rawRootPolicy;
1957
+ return {
1958
+ help: Boolean(values.help),
1959
+ json: Boolean(values.json),
1960
+ inputPath: typeof values.input === 'string' ? values.input : '',
1961
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
1962
+ rootPolicy,
1963
+ };
1964
+ }
1965
+ function parseDatasetBilingualExtractFlags(args) {
1966
+ let values;
1967
+ try {
1968
+ ({ values } = parseArgs({
1969
+ args,
1970
+ allowPositionals: false,
1971
+ strict: true,
1972
+ options: {
1973
+ help: { type: 'boolean', short: 'h' },
1974
+ json: { type: 'boolean' },
1975
+ input: { type: 'string' },
1976
+ type: { type: 'string' },
1977
+ 'source-lang': { type: 'string' },
1978
+ 'target-lang': { type: 'string' },
1979
+ 'out-dir': { type: 'string' },
1980
+ },
1981
+ }));
1982
+ }
1983
+ catch (error) {
1984
+ throw new CliError(String(error), {
1985
+ code: 'INVALID_ARGS',
1986
+ exitCode: 2,
1987
+ });
1988
+ }
1989
+ return {
1990
+ help: Boolean(values.help),
1991
+ json: Boolean(values.json),
1992
+ inputPath: typeof values.input === 'string' ? values.input : '',
1993
+ type: typeof values.type === 'string' ? values.type : undefined,
1994
+ sourceLang: typeof values['source-lang'] === 'string' ? values['source-lang'] : null,
1995
+ targetLang: typeof values['target-lang'] === 'string' ? values['target-lang'] : null,
1996
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1997
+ };
1998
+ }
1999
+ function parseDatasetBilingualApplyFlags(args) {
2000
+ let values;
2001
+ try {
2002
+ ({ values } = parseArgs({
2003
+ args,
2004
+ allowPositionals: false,
2005
+ strict: true,
2006
+ options: {
2007
+ help: { type: 'boolean', short: 'h' },
2008
+ json: { type: 'boolean' },
2009
+ input: { type: 'string' },
2010
+ translations: { type: 'string' },
2011
+ out: { type: 'string' },
2012
+ 'target-lang': { type: 'string' },
2013
+ 'out-dir': { type: 'string' },
2014
+ },
2015
+ }));
2016
+ }
2017
+ catch (error) {
2018
+ throw new CliError(String(error), {
2019
+ code: 'INVALID_ARGS',
2020
+ exitCode: 2,
2021
+ });
2022
+ }
2023
+ return {
2024
+ help: Boolean(values.help),
2025
+ json: Boolean(values.json),
2026
+ inputPath: typeof values.input === 'string' ? values.input : '',
2027
+ translationsPath: typeof values.translations === 'string' ? values.translations : '',
2028
+ outPath: typeof values.out === 'string' ? values.out : '',
2029
+ targetLang: typeof values['target-lang'] === 'string' ? values['target-lang'] : null,
2030
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2031
+ };
2032
+ }
2033
+ function parseDatasetBilingualValidateFlags(args) {
2034
+ let values;
2035
+ try {
2036
+ ({ values } = parseArgs({
2037
+ args,
2038
+ allowPositionals: false,
2039
+ strict: true,
2040
+ options: {
2041
+ help: { type: 'boolean', short: 'h' },
2042
+ json: { type: 'boolean' },
2043
+ input: { type: 'string' },
2044
+ type: { type: 'string' },
2045
+ 'out-dir': { type: 'string' },
2046
+ },
2047
+ }));
2048
+ }
2049
+ catch (error) {
2050
+ throw new CliError(String(error), {
2051
+ code: 'INVALID_ARGS',
2052
+ exitCode: 2,
2053
+ });
2054
+ }
2055
+ return {
2056
+ help: Boolean(values.help),
2057
+ json: Boolean(values.json),
2058
+ inputPath: typeof values.input === 'string' ? values.input : '',
2059
+ type: typeof values.type === 'string' ? values.type : undefined,
2060
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2061
+ };
2062
+ }
2063
+ function parseDatasetEvidenceSearchFlags(args) {
2064
+ let values;
2065
+ try {
2066
+ ({ values } = parseArgs({
2067
+ args,
2068
+ allowPositionals: false,
2069
+ strict: true,
2070
+ options: {
2071
+ help: { type: 'boolean', short: 'h' },
2072
+ json: { type: 'boolean' },
2073
+ query: { type: 'string' },
2074
+ input: { type: 'string' },
2075
+ results: { type: 'string' },
2076
+ 'provider-url': { type: 'string' },
2077
+ 'provider-key': { type: 'string' },
2078
+ profile: { type: 'string' },
2079
+ 'out-dir': { type: 'string' },
2080
+ 'max-queries': { type: 'string' },
2081
+ 'max-results-per-query': { type: 'string' },
2082
+ 'timeout-ms': { type: 'string' },
2083
+ },
2084
+ }));
2085
+ }
2086
+ catch (error) {
2087
+ throw new CliError(String(error), {
2088
+ code: 'INVALID_ARGS',
2089
+ exitCode: 2,
2090
+ });
2091
+ }
2092
+ const readNumber = (value) => {
2093
+ if (typeof value !== 'string') {
2094
+ return null;
2095
+ }
2096
+ const parsed = Number(value);
2097
+ return Number.isFinite(parsed) ? parsed : Number.NaN;
2098
+ };
2099
+ return {
2100
+ help: Boolean(values.help),
2101
+ json: Boolean(values.json),
2102
+ query: typeof values.query === 'string' ? values.query : null,
2103
+ inputPath: typeof values.input === 'string' ? values.input : null,
2104
+ resultsPath: typeof values.results === 'string' ? values.results : null,
2105
+ providerUrl: typeof values['provider-url'] === 'string' ? values['provider-url'] : null,
2106
+ providerKey: typeof values['provider-key'] === 'string' ? values['provider-key'] : null,
2107
+ profile: typeof values.profile === 'string' ? values.profile : null,
2108
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2109
+ maxQueries: readNumber(values['max-queries']),
2110
+ maxResultsPerQuery: readNumber(values['max-results-per-query']),
2111
+ timeoutMs: readNumber(values['timeout-ms']),
2112
+ };
2113
+ }
1378
2114
  function parseDatasetReferencesRewriteFlags(args) {
1379
2115
  let values;
1380
2116
  try {
@@ -1392,8 +2128,147 @@ function parseDatasetReferencesRewriteFlags(args) {
1392
2128
  types: { type: 'string', multiple: true },
1393
2129
  scope: { type: 'string' },
1394
2130
  'out-dir': { type: 'string' },
1395
- commit: { type: 'boolean' },
1396
- 'dry-run': { type: 'boolean' },
2131
+ commit: { type: 'boolean' },
2132
+ 'dry-run': { type: 'boolean' },
2133
+ },
2134
+ }));
2135
+ }
2136
+ catch (error) {
2137
+ throw new CliError(String(error), {
2138
+ code: 'INVALID_ARGS',
2139
+ exitCode: 2,
2140
+ });
2141
+ }
2142
+ if (values.commit && values['dry-run']) {
2143
+ throw new CliError('Cannot pass both --commit and --dry-run.', {
2144
+ code: 'DATASET_REFERENCES_REWRITE_MODE_CONFLICT',
2145
+ exitCode: 2,
2146
+ });
2147
+ }
2148
+ return {
2149
+ help: Boolean(values.help),
2150
+ json: Boolean(values.json),
2151
+ inputPath: typeof values.input === 'string' ? values.input : '',
2152
+ from: typeof values.from === 'string' ? values.from : '',
2153
+ to: typeof values.to === 'string' ? values.to : '',
2154
+ types: [
2155
+ ...(Array.isArray(values.type)
2156
+ ? values.type.filter((value) => typeof value === 'string')
2157
+ : []),
2158
+ ...(Array.isArray(values.types)
2159
+ ? values.types.filter((value) => typeof value === 'string')
2160
+ : []),
2161
+ ],
2162
+ scope: typeof values.scope === 'string' ? values.scope : null,
2163
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
2164
+ commit: Boolean(values.commit),
2165
+ };
2166
+ }
2167
+ function parseDatasetReferencesRefreshRemoteFlags(args) {
2168
+ let values;
2169
+ try {
2170
+ ({ values } = parseArgs({
2171
+ args,
2172
+ allowPositionals: false,
2173
+ strict: true,
2174
+ options: {
2175
+ help: { type: 'boolean', short: 'h' },
2176
+ json: { type: 'boolean' },
2177
+ input: { type: 'string' },
2178
+ out: { type: 'string' },
2179
+ 'out-dir': { type: 'string' },
2180
+ 'root-policy': { type: 'string' },
2181
+ },
2182
+ }));
2183
+ }
2184
+ catch (error) {
2185
+ throw new CliError(String(error), {
2186
+ code: 'INVALID_ARGS',
2187
+ exitCode: 2,
2188
+ });
2189
+ }
2190
+ const rawRootPolicy = typeof values['root-policy'] === 'string' ? values['root-policy'] : 'existing';
2191
+ if (!['existing', 'candidate'].includes(rawRootPolicy)) {
2192
+ throw new CliError("--root-policy must be 'existing' or 'candidate'.", {
2193
+ code: 'DATASET_REMOTE_REFRESH_ROOT_POLICY_INVALID',
2194
+ exitCode: 2,
2195
+ });
2196
+ }
2197
+ const rootPolicy = rawRootPolicy;
2198
+ return {
2199
+ help: Boolean(values.help),
2200
+ json: Boolean(values.json),
2201
+ inputPath: typeof values.input === 'string' ? values.input : '',
2202
+ outPath: typeof values.out === 'string' ? values.out : '',
2203
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
2204
+ rootPolicy,
2205
+ };
2206
+ }
2207
+ function parseIdentityPreflightFlags(args) {
2208
+ let values;
2209
+ try {
2210
+ ({ values } = parseArgs({
2211
+ args,
2212
+ allowPositionals: false,
2213
+ strict: true,
2214
+ options: {
2215
+ help: { type: 'boolean', short: 'h' },
2216
+ json: { type: 'boolean' },
2217
+ input: { type: 'string' },
2218
+ 'candidate-input': { type: 'string', multiple: true },
2219
+ 'remote-candidates': { type: 'boolean' },
2220
+ 'remote-query': { type: 'string' },
2221
+ 'remote-limit': { type: 'string' },
2222
+ 'out-dir': { type: 'string' },
2223
+ },
2224
+ }));
2225
+ }
2226
+ catch (error) {
2227
+ throw new CliError(String(error), {
2228
+ code: 'INVALID_ARGS',
2229
+ exitCode: 2,
2230
+ });
2231
+ }
2232
+ const candidateInputValue = values['candidate-input'];
2233
+ const parseRemoteLimit = (value) => {
2234
+ if (typeof value !== 'string') {
2235
+ return null;
2236
+ }
2237
+ const parsed = Number.parseInt(value, 10);
2238
+ if (!Number.isInteger(parsed) || parsed <= 0) {
2239
+ throw new CliError('Expected --remote-limit to be a positive integer.', {
2240
+ code: 'INVALID_IDENTITY_PREFLIGHT_REMOTE_LIMIT',
2241
+ exitCode: 2,
2242
+ });
2243
+ }
2244
+ return parsed;
2245
+ };
2246
+ return {
2247
+ help: Boolean(values.help),
2248
+ json: Boolean(values.json),
2249
+ inputPath: typeof values.input === 'string' ? values.input : '',
2250
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2251
+ candidateInputPaths: Array.isArray(candidateInputValue)
2252
+ ? candidateInputValue.filter((entry) => typeof entry === 'string')
2253
+ : [],
2254
+ remoteCandidateSearch: Boolean(values['remote-candidates']),
2255
+ remoteQuery: typeof values['remote-query'] === 'string' ? values['remote-query'] : null,
2256
+ remoteLimit: parseRemoteLimit(values['remote-limit']),
2257
+ };
2258
+ }
2259
+ function parseBuildPlanFlags(args) {
2260
+ let values;
2261
+ try {
2262
+ ({ values } = parseArgs({
2263
+ args,
2264
+ allowPositionals: false,
2265
+ strict: true,
2266
+ options: {
2267
+ help: { type: 'boolean', short: 'h' },
2268
+ json: { type: 'boolean' },
2269
+ input: { type: 'string' },
2270
+ 'out-dir': { type: 'string' },
2271
+ 'report-only': { type: 'boolean' },
1397
2272
  },
1398
2273
  }));
1399
2274
  }
@@ -1403,29 +2278,12 @@ function parseDatasetReferencesRewriteFlags(args) {
1403
2278
  exitCode: 2,
1404
2279
  });
1405
2280
  }
1406
- if (values.commit && values['dry-run']) {
1407
- throw new CliError('Cannot pass both --commit and --dry-run.', {
1408
- code: 'DATASET_REFERENCES_REWRITE_MODE_CONFLICT',
1409
- exitCode: 2,
1410
- });
1411
- }
1412
2281
  return {
1413
2282
  help: Boolean(values.help),
1414
2283
  json: Boolean(values.json),
1415
2284
  inputPath: typeof values.input === 'string' ? values.input : '',
1416
- from: typeof values.from === 'string' ? values.from : '',
1417
- to: typeof values.to === 'string' ? values.to : '',
1418
- types: [
1419
- ...(Array.isArray(values.type)
1420
- ? values.type.filter((value) => typeof value === 'string')
1421
- : []),
1422
- ...(Array.isArray(values.types)
1423
- ? values.types.filter((value) => typeof value === 'string')
1424
- : []),
1425
- ],
1426
- scope: typeof values.scope === 'string' ? values.scope : null,
1427
- outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
1428
- commit: Boolean(values.commit),
2285
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2286
+ reportOnly: Boolean(values['report-only']),
1429
2287
  };
1430
2288
  }
1431
2289
  function parseFlowRemediateFlags(args) {
@@ -2100,7 +2958,7 @@ function parseFlowListFlags(args) {
2100
2958
  order: typeof values.order === 'string' ? values.order : null,
2101
2959
  };
2102
2960
  }
2103
- function parseReviewProcessFlags(args) {
2961
+ function parseQaProcessFlags(args) {
2104
2962
  let values;
2105
2963
  try {
2106
2964
  ({ values } = parseArgs({
@@ -2154,7 +3012,7 @@ function parseReviewProcessFlags(args) {
2154
3012
  llmMaxProcesses: llmMaxProcessesValue,
2155
3013
  };
2156
3014
  }
2157
- function parseReviewFlowFlags(args) {
3015
+ function parseQaFlowFlags(args) {
2158
3016
  let values;
2159
3017
  try {
2160
3018
  ({ values } = parseArgs({
@@ -2229,7 +3087,7 @@ function parseReviewFlowFlags(args) {
2229
3087
  methodologyId: typeof values['methodology-id'] === 'string' ? values['methodology-id'] : undefined,
2230
3088
  };
2231
3089
  }
2232
- function parseReviewLifecyclemodelFlags(args) {
3090
+ function parseQaLifecyclemodelFlags(args) {
2233
3091
  let values;
2234
3092
  try {
2235
3093
  ({ values } = parseArgs({
@@ -2830,6 +3688,40 @@ function parseProcessSaveDraftFlags(args) {
2830
3688
  commit: Boolean(values.commit),
2831
3689
  };
2832
3690
  }
3691
+ function parseProcessRequiredFieldsFlags(args) {
3692
+ let values;
3693
+ try {
3694
+ ({ values } = parseArgs({
3695
+ args,
3696
+ allowPositionals: false,
3697
+ strict: true,
3698
+ options: {
3699
+ help: { type: 'boolean', short: 'h' },
3700
+ json: { type: 'boolean' },
3701
+ input: { type: 'string' },
3702
+ out: { type: 'string' },
3703
+ 'out-dir': { type: 'string' },
3704
+ flows: { type: 'string' },
3705
+ 'default-unit': { type: 'string' },
3706
+ },
3707
+ }));
3708
+ }
3709
+ catch (error) {
3710
+ throw new CliError(String(error), {
3711
+ code: 'INVALID_ARGS',
3712
+ exitCode: 2,
3713
+ });
3714
+ }
3715
+ return {
3716
+ help: Boolean(values.help),
3717
+ json: Boolean(values.json),
3718
+ inputPath: typeof values.input === 'string' ? values.input : '',
3719
+ outPath: typeof values.out === 'string' ? values.out : '',
3720
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
3721
+ flowInputPath: typeof values.flows === 'string' ? values.flows : null,
3722
+ defaultUnit: typeof values['default-unit'] === 'string' ? values['default-unit'] : null,
3723
+ };
3724
+ }
2833
3725
  function parseProcessRefreshReferencesFlags(args) {
2834
3726
  let values;
2835
3727
  try {
@@ -2950,6 +3842,15 @@ function plannedCommand(command, subcommand) {
2950
3842
  stderr: `Command '${command}${suffix}' is part of the planned unified surface but is not implemented yet.\n`,
2951
3843
  };
2952
3844
  }
3845
+ function removedReviewCommand(subcommand) {
3846
+ const suffix = subcommand ? ` ${subcommand}` : '';
3847
+ const replacement = subcommand ? `qa ${subcommand}` : 'qa';
3848
+ return {
3849
+ exitCode: 2,
3850
+ stdout: '',
3851
+ stderr: `Command 'review${suffix}' was removed. Use 'tiangong-lca ${replacement}' instead.\n`,
3852
+ };
3853
+ }
2953
3854
  function applyRemoteOverrides(env, overrides) {
2954
3855
  const runtimeEnv = readRuntimeEnv(env);
2955
3856
  return {
@@ -2982,10 +3883,14 @@ export async function executeCli(argv, deps) {
2982
3883
  const processResumeBuildImpl = deps.runProcessResumeBuildImpl ?? runProcessResumeBuild;
2983
3884
  const processPublishBuildImpl = deps.runProcessPublishBuildImpl ?? runProcessPublishBuild;
2984
3885
  const processSaveDraftImpl = deps.runProcessSaveDraftImpl ?? runProcessSaveDraft;
3886
+ const processRequiredFieldsCompleteImpl = deps.runProcessRequiredFieldsCompleteImpl ?? runProcessRequiredFieldsComplete;
2985
3887
  const processVerifyRowsImpl = deps.runProcessVerifyRowsImpl ?? runProcessVerifyRows;
2986
- const processReviewImpl = deps.runProcessReviewImpl ?? runProcessReview;
2987
- const flowReviewImpl = deps.runFlowReviewImpl ?? runFlowReview;
2988
- const lifecyclemodelReviewImpl = deps.runLifecyclemodelReviewImpl ?? runLifecyclemodelReview;
3888
+ const processIdentityPreflightImpl = deps.runProcessIdentityPreflightImpl ?? runProcessIdentityPreflight;
3889
+ const processBuildPlanValidateImpl = deps.runProcessBuildPlanValidateImpl ?? runProcessBuildPlanValidate;
3890
+ const processBuildPlanMaterializeImpl = deps.runProcessBuildPlanMaterializeImpl ?? runProcessBuildPlanMaterialize;
3891
+ const processQaImpl = deps.runProcessQaImpl ?? runProcessQa;
3892
+ const flowQaImpl = deps.runFlowQaImpl ?? runFlowQa;
3893
+ const lifecyclemodelQaImpl = deps.runLifecyclemodelQaImpl ?? runLifecyclemodelQa;
2989
3894
  const flowRemediateImpl = deps.runFlowRemediateImpl ?? runFlowRemediate;
2990
3895
  const flowFetchRowsImpl = deps.runFlowFetchRowsImpl ?? runFlowFetchRows;
2991
3896
  const flowMaterializeDecisionsImpl = deps.runFlowMaterializeDecisionsImpl ?? runFlowMaterializeDecisions;
@@ -2999,8 +3904,20 @@ export async function executeCli(argv, deps) {
2999
3904
  const flowApplyProcessFlowRepairsImpl = deps.runFlowApplyProcessFlowRepairsImpl ?? runFlowApplyProcessFlowRepairs;
3000
3905
  const flowRegenProductImpl = deps.runFlowRegenProductImpl ?? runFlowRegenProduct;
3001
3906
  const flowValidateProcessesImpl = deps.runFlowValidateProcessesImpl ?? runFlowValidateProcesses;
3907
+ const flowIdentityPreflightImpl = deps.runFlowIdentityPreflightImpl ?? runFlowIdentityPreflight;
3908
+ const flowBuildPlanValidateImpl = deps.runFlowBuildPlanValidateImpl ?? runFlowBuildPlanValidate;
3909
+ const flowBuildPlanMaterializeImpl = deps.runFlowBuildPlanMaterializeImpl ?? runFlowBuildPlanMaterialize;
3002
3910
  const datasetValidateImpl = deps.runDatasetValidateImpl ?? runDatasetValidate;
3003
3911
  const datasetReferencesRewriteImpl = deps.runDatasetReferencesRewriteImpl ?? runDatasetReferencesRewrite;
3912
+ const datasetRemoteRefreshImpl = deps.runDatasetRemoteRefreshImpl ?? runDatasetRemoteRefresh;
3913
+ const datasetRemoteVerifyImpl = deps.runDatasetRemoteVerifyImpl ?? runDatasetRemoteVerify;
3914
+ const datasetBilingualExtractImpl = deps.runDatasetBilingualExtractImpl ?? runDatasetBilingualExtract;
3915
+ const datasetBilingualApplyImpl = deps.runDatasetBilingualApplyImpl ?? runDatasetBilingualApply;
3916
+ const datasetBilingualValidateImpl = deps.runDatasetBilingualValidateImpl ?? runDatasetBilingualValidate;
3917
+ const datasetEvidenceSearchImpl = deps.runDatasetEvidenceSearchImpl ?? runDatasetEvidenceSearch;
3918
+ const datasetContractImpl = deps.runDatasetContractImpl ?? runDatasetContract;
3919
+ const datasetImportLcaConvertImpl = deps.runDatasetImportLcaConvertImpl ?? runDatasetImportLcaConvert;
3920
+ const datasetAuthorImpl = deps.runDatasetAuthorImpl ?? runDatasetAuthor;
3004
3921
  if (flags.version) {
3005
3922
  return { exitCode: 0, stdout: `${loadCliPackageVersion(import.meta.url)}\n`, stderr: '' };
3006
3923
  }
@@ -3046,6 +3963,110 @@ export async function executeCli(argv, deps) {
3046
3963
  if (command === 'dataset' && !subcommand) {
3047
3964
  return { exitCode: 0, stdout: `${renderDatasetHelp()}\n`, stderr: '' };
3048
3965
  }
3966
+ if (command === 'dataset' && subcommand === 'contract') {
3967
+ const action = commandArgs[0] ?? '';
3968
+ if (!action || action === '--help' || action === '-h') {
3969
+ return { exitCode: 0, stdout: `${renderDatasetContractHelp()}\n`, stderr: '' };
3970
+ }
3971
+ if (action !== 'get') {
3972
+ throw new CliError("dataset contract action must be 'get'.", {
3973
+ code: 'DATASET_CONTRACT_ACTION_INVALID',
3974
+ exitCode: 2,
3975
+ });
3976
+ }
3977
+ const datasetFlags = parseDatasetContractFlags(commandArgs.slice(1));
3978
+ if (datasetFlags.help) {
3979
+ return { exitCode: 0, stdout: `${renderDatasetContractHelp()}\n`, stderr: '' };
3980
+ }
3981
+ const report = await datasetContractImpl({
3982
+ type: datasetFlags.type,
3983
+ include: datasetFlags.include,
3984
+ profile: datasetFlags.profile,
3985
+ outDir: datasetFlags.outDir,
3986
+ mode: 'contract',
3987
+ });
3988
+ return {
3989
+ exitCode: 0,
3990
+ stdout: stringifyJson(report, datasetFlags.json),
3991
+ stderr: '',
3992
+ };
3993
+ }
3994
+ if (command === 'dataset' && subcommand === 'context-pack') {
3995
+ const datasetFlags = parseDatasetContractFlags(commandArgs);
3996
+ if (datasetFlags.help) {
3997
+ return { exitCode: 0, stdout: `${renderDatasetContextPackHelp()}\n`, stderr: '' };
3998
+ }
3999
+ const report = await datasetContractImpl({
4000
+ type: datasetFlags.type,
4001
+ include: datasetFlags.include,
4002
+ profile: datasetFlags.profile,
4003
+ outDir: datasetFlags.outDir,
4004
+ mode: 'context-pack',
4005
+ });
4006
+ return {
4007
+ exitCode: 0,
4008
+ stdout: stringifyJson(report, datasetFlags.json),
4009
+ stderr: '',
4010
+ };
4011
+ }
4012
+ if (command === 'dataset' && subcommand === 'import-lca') {
4013
+ const action = commandArgs[0] ?? '';
4014
+ if (!action || action === '--help' || action === '-h') {
4015
+ return { exitCode: 0, stdout: `${renderDatasetImportLcaHelp()}\n`, stderr: '' };
4016
+ }
4017
+ if (action !== 'convert') {
4018
+ throw new CliError("dataset import-lca action must be 'convert'.", {
4019
+ code: 'DATASET_IMPORT_LCA_ACTION_INVALID',
4020
+ exitCode: 2,
4021
+ });
4022
+ }
4023
+ const datasetFlags = parseDatasetImportLcaConvertFlags(commandArgs.slice(1));
4024
+ if (datasetFlags.help) {
4025
+ return { exitCode: 0, stdout: `${renderDatasetImportLcaHelp()}\n`, stderr: '' };
4026
+ }
4027
+ const report = await datasetImportLcaConvertImpl({
4028
+ inputPath: datasetFlags.inputPath,
4029
+ outputDir: datasetFlags.outputDir,
4030
+ fromFormat: datasetFlags.fromFormat,
4031
+ target: datasetFlags.target,
4032
+ reportPath: datasetFlags.reportPath,
4033
+ mappingDir: datasetFlags.mappingDir,
4034
+ language: datasetFlags.language,
4035
+ validationJobs: datasetFlags.validationJobs,
4036
+ detectOnly: datasetFlags.detectOnly,
4037
+ failOnWarning: datasetFlags.failOnWarning,
4038
+ pythonBin: datasetFlags.pythonBin,
4039
+ tidasToolsDir: datasetFlags.tidasToolsDir,
4040
+ env: deps.env,
4041
+ });
4042
+ return {
4043
+ exitCode: report.status === 'completed' ? 0 : 1,
4044
+ stdout: stringifyJson(report, datasetFlags.json),
4045
+ stderr: '',
4046
+ };
4047
+ }
4048
+ if (command === 'dataset' && subcommand === 'author') {
4049
+ const datasetFlags = parseDatasetAuthorFlags(commandArgs);
4050
+ if (datasetFlags.help) {
4051
+ return { exitCode: 0, stdout: `${renderDatasetAuthorHelp()}\n`, stderr: '' };
4052
+ }
4053
+ const report = await datasetAuthorImpl({
4054
+ inputPath: datasetFlags.inputPath,
4055
+ targetTypes: datasetFlags.targetTypes,
4056
+ outDir: datasetFlags.outDir,
4057
+ prompt: datasetFlags.prompt,
4058
+ provider: datasetFlags.provider,
4059
+ model: datasetFlags.model,
4060
+ timeoutMs: datasetFlags.timeoutMs,
4061
+ env: deps.env,
4062
+ fetchImpl: deps.fetchImpl,
4063
+ });
4064
+ return {
4065
+ exitCode: 0,
4066
+ stdout: stringifyJson(report, datasetFlags.json),
4067
+ stderr: '',
4068
+ };
4069
+ }
3049
4070
  if (command === 'dataset' && subcommand === 'validate') {
3050
4071
  const datasetFlags = parseDatasetValidateFlags(commandArgs);
3051
4072
  if (datasetFlags.help) {
@@ -3062,17 +4083,151 @@ export async function executeCli(argv, deps) {
3062
4083
  stderr: '',
3063
4084
  };
3064
4085
  }
4086
+ if (command === 'dataset' && subcommand === 'verify-remote') {
4087
+ const datasetFlags = parseDatasetRemoteVerifyFlags(commandArgs);
4088
+ if (datasetFlags.help) {
4089
+ return { exitCode: 0, stdout: `${renderDatasetRemoteVerifyHelp()}\n`, stderr: '' };
4090
+ }
4091
+ const report = await datasetRemoteVerifyImpl({
4092
+ inputPath: datasetFlags.inputPath,
4093
+ outDir: datasetFlags.outDir,
4094
+ rootPolicy: datasetFlags.rootPolicy,
4095
+ env: deps.env,
4096
+ fetchImpl: deps.fetchImpl,
4097
+ });
4098
+ return {
4099
+ exitCode: report.status === 'blocked_remote_verification' ? 1 : 0,
4100
+ stdout: stringifyJson(report, datasetFlags.json),
4101
+ stderr: '',
4102
+ };
4103
+ }
4104
+ if (command === 'dataset' && subcommand === 'bilingual') {
4105
+ const action = commandArgs[0] ?? '';
4106
+ if (!action || action === '--help' || action === '-h') {
4107
+ return { exitCode: 0, stdout: `${renderDatasetBilingualHelp()}\n`, stderr: '' };
4108
+ }
4109
+ if (action === 'extract') {
4110
+ const datasetFlags = parseDatasetBilingualExtractFlags(commandArgs.slice(1));
4111
+ if (datasetFlags.help) {
4112
+ return { exitCode: 0, stdout: `${renderDatasetBilingualExtractHelp()}\n`, stderr: '' };
4113
+ }
4114
+ const report = await datasetBilingualExtractImpl({
4115
+ inputPath: datasetFlags.inputPath,
4116
+ type: datasetFlags.type,
4117
+ sourceLang: datasetFlags.sourceLang,
4118
+ targetLang: datasetFlags.targetLang,
4119
+ outDir: datasetFlags.outDir,
4120
+ });
4121
+ return {
4122
+ exitCode: 0,
4123
+ stdout: stringifyJson(report, datasetFlags.json),
4124
+ stderr: '',
4125
+ };
4126
+ }
4127
+ if (action === 'apply') {
4128
+ const datasetFlags = parseDatasetBilingualApplyFlags(commandArgs.slice(1));
4129
+ if (datasetFlags.help) {
4130
+ return { exitCode: 0, stdout: `${renderDatasetBilingualApplyHelp()}\n`, stderr: '' };
4131
+ }
4132
+ const report = await datasetBilingualApplyImpl({
4133
+ inputPath: datasetFlags.inputPath,
4134
+ translationsPath: datasetFlags.translationsPath,
4135
+ outPath: datasetFlags.outPath,
4136
+ targetLang: datasetFlags.targetLang,
4137
+ outDir: datasetFlags.outDir,
4138
+ });
4139
+ return {
4140
+ exitCode: report.status === 'blocked' ? 1 : 0,
4141
+ stdout: stringifyJson(report, datasetFlags.json),
4142
+ stderr: '',
4143
+ };
4144
+ }
4145
+ if (action === 'validate') {
4146
+ const datasetFlags = parseDatasetBilingualValidateFlags(commandArgs.slice(1));
4147
+ if (datasetFlags.help) {
4148
+ return { exitCode: 0, stdout: `${renderDatasetBilingualValidateHelp()}\n`, stderr: '' };
4149
+ }
4150
+ const report = await datasetBilingualValidateImpl({
4151
+ inputPath: datasetFlags.inputPath,
4152
+ type: datasetFlags.type,
4153
+ outDir: datasetFlags.outDir,
4154
+ });
4155
+ return {
4156
+ exitCode: report.status === 'blocked' ? 1 : 0,
4157
+ stdout: stringifyJson(report, datasetFlags.json),
4158
+ stderr: '',
4159
+ };
4160
+ }
4161
+ throw new CliError("dataset bilingual action must be 'extract', 'apply', or 'validate'.", {
4162
+ code: 'INVALID_ARGS',
4163
+ exitCode: 2,
4164
+ });
4165
+ }
4166
+ if (command === 'dataset' && subcommand === 'evidence-search') {
4167
+ const action = commandArgs[0] ?? '';
4168
+ if (!action || action === '--help' || action === '-h') {
4169
+ return { exitCode: 0, stdout: `${renderDatasetEvidenceSearchHelp()}\n`, stderr: '' };
4170
+ }
4171
+ if (action !== 'plan' && action !== 'run') {
4172
+ throw new CliError("dataset evidence-search action must be 'plan' or 'run'.", {
4173
+ code: 'INVALID_ARGS',
4174
+ exitCode: 2,
4175
+ });
4176
+ }
4177
+ const datasetFlags = parseDatasetEvidenceSearchFlags(commandArgs.slice(1));
4178
+ if (datasetFlags.help) {
4179
+ return { exitCode: 0, stdout: `${renderDatasetEvidenceSearchHelp()}\n`, stderr: '' };
4180
+ }
4181
+ const report = await datasetEvidenceSearchImpl({
4182
+ mode: action,
4183
+ query: datasetFlags.query,
4184
+ inputPath: datasetFlags.inputPath,
4185
+ resultsPath: datasetFlags.resultsPath,
4186
+ providerUrl: datasetFlags.providerUrl,
4187
+ providerKey: datasetFlags.providerKey,
4188
+ profile: datasetFlags.profile,
4189
+ outDir: datasetFlags.outDir,
4190
+ maxQueries: datasetFlags.maxQueries,
4191
+ maxResultsPerQuery: datasetFlags.maxResultsPerQuery,
4192
+ timeoutMs: datasetFlags.timeoutMs,
4193
+ fetchImpl: deps.fetchImpl,
4194
+ });
4195
+ return {
4196
+ exitCode: report.status === 'completed_no_sufficient_evidence' ? 1 : 0,
4197
+ stdout: stringifyJson(report, datasetFlags.json),
4198
+ stderr: '',
4199
+ };
4200
+ }
3065
4201
  if (command === 'dataset' && subcommand === 'references') {
3066
4202
  const action = commandArgs[0] ?? '';
3067
4203
  if (!action || action === '--help' || action === '-h') {
3068
4204
  return { exitCode: 0, stdout: `${renderDatasetReferencesHelp()}\n`, stderr: '' };
3069
4205
  }
3070
- if (action !== 'rewrite') {
3071
- throw new CliError("dataset references action must be 'rewrite'.", {
4206
+ if (!['rewrite', 'refresh-remote'].includes(action)) {
4207
+ throw new CliError("dataset references action must be 'rewrite' or 'refresh-remote'.", {
3072
4208
  code: 'INVALID_ARGS',
3073
4209
  exitCode: 2,
3074
4210
  });
3075
4211
  }
4212
+ if (action === 'refresh-remote') {
4213
+ const datasetFlags = parseDatasetReferencesRefreshRemoteFlags(commandArgs.slice(1));
4214
+ if (datasetFlags.help) {
4215
+ return { exitCode: 0, stdout: `${renderDatasetReferencesHelp()}\n`, stderr: '' };
4216
+ }
4217
+ const report = await datasetRemoteRefreshImpl({
4218
+ inputPath: datasetFlags.inputPath,
4219
+ outPath: datasetFlags.outPath,
4220
+ outDir: datasetFlags.outDir,
4221
+ rootPolicy: datasetFlags.rootPolicy,
4222
+ env: deps.env,
4223
+ fetchImpl: deps.fetchImpl,
4224
+ });
4225
+ return {
4226
+ exitCode: report.status === 'completed_with_blockers' ? 1 : 0,
4227
+ stdout: stringifyJson(report, datasetFlags.json),
4228
+ stderr: '',
4229
+ };
4230
+ }
3076
4231
  const datasetFlags = parseDatasetReferencesRewriteFlags(commandArgs.slice(1));
3077
4232
  if (datasetFlags.help) {
3078
4233
  return { exitCode: 0, stdout: `${renderDatasetReferencesHelp()}\n`, stderr: '' };
@@ -3327,6 +4482,71 @@ export async function executeCli(argv, deps) {
3327
4482
  stderr: '',
3328
4483
  };
3329
4484
  }
4485
+ if (command === 'process' && subcommand === 'identity-preflight') {
4486
+ const processFlags = parseIdentityPreflightFlags(commandArgs);
4487
+ if (processFlags.help) {
4488
+ return {
4489
+ exitCode: 0,
4490
+ stdout: `${renderProcessIdentityPreflightHelp()}\n`,
4491
+ stderr: '',
4492
+ };
4493
+ }
4494
+ const report = await processIdentityPreflightImpl({
4495
+ inputPath: processFlags.inputPath,
4496
+ outDir: processFlags.outDir,
4497
+ candidateInputPaths: processFlags.candidateInputPaths,
4498
+ remoteCandidateSearch: processFlags.remoteCandidateSearch,
4499
+ remoteQuery: processFlags.remoteQuery,
4500
+ remoteLimit: processFlags.remoteLimit,
4501
+ env: deps.env,
4502
+ fetchImpl: deps.fetchImpl,
4503
+ });
4504
+ return {
4505
+ exitCode: report.status === 'passed' ? 0 : 1,
4506
+ stdout: stringifyJson(report, processFlags.json),
4507
+ stderr: '',
4508
+ };
4509
+ }
4510
+ if (command === 'process' && subcommand === 'build-plan') {
4511
+ const action = commandArgs[0] ?? '';
4512
+ if (!action || action === '--help' || action === '-h') {
4513
+ return {
4514
+ exitCode: 0,
4515
+ stdout: `${renderProcessBuildPlanHelp()}\n`,
4516
+ stderr: '',
4517
+ };
4518
+ }
4519
+ if (action !== 'validate' && action !== 'materialize') {
4520
+ throw new CliError("process build-plan action must be 'validate' or 'materialize'.", {
4521
+ code: 'INVALID_ARGS',
4522
+ exitCode: 2,
4523
+ });
4524
+ }
4525
+ const processFlags = parseBuildPlanFlags(commandArgs.slice(1));
4526
+ if (processFlags.help) {
4527
+ return {
4528
+ exitCode: 0,
4529
+ stdout: `${renderProcessBuildPlanHelp()}\n`,
4530
+ stderr: '',
4531
+ };
4532
+ }
4533
+ const report = action === 'validate'
4534
+ ? await processBuildPlanValidateImpl({
4535
+ inputPath: processFlags.inputPath,
4536
+ outDir: processFlags.outDir,
4537
+ reportOnly: processFlags.reportOnly,
4538
+ })
4539
+ : await processBuildPlanMaterializeImpl({
4540
+ inputPath: processFlags.inputPath,
4541
+ outDir: processFlags.outDir,
4542
+ reportOnly: processFlags.reportOnly,
4543
+ });
4544
+ return {
4545
+ exitCode: report.status === 'blocked' && !processFlags.reportOnly ? 1 : 0,
4546
+ stdout: stringifyJson(report, processFlags.json),
4547
+ stderr: '',
4548
+ };
4549
+ }
3330
4550
  if (command === 'process' && subcommand === 'scope-statistics') {
3331
4551
  const processFlags = parseProcessScopeStatisticsFlags(commandArgs);
3332
4552
  if (processFlags.help) {
@@ -3430,6 +4650,28 @@ export async function executeCli(argv, deps) {
3430
4650
  stderr: '',
3431
4651
  };
3432
4652
  }
4653
+ if (command === 'process' && subcommand === 'complete-required-fields') {
4654
+ const processFlags = parseProcessRequiredFieldsFlags(commandArgs);
4655
+ if (processFlags.help) {
4656
+ return {
4657
+ exitCode: 0,
4658
+ stdout: `${renderProcessRequiredFieldsHelp()}\n`,
4659
+ stderr: '',
4660
+ };
4661
+ }
4662
+ const report = await processRequiredFieldsCompleteImpl({
4663
+ inputPath: processFlags.inputPath,
4664
+ outPath: processFlags.outPath,
4665
+ outDir: processFlags.outDir,
4666
+ flowInputPath: processFlags.flowInputPath,
4667
+ defaultUnit: processFlags.defaultUnit,
4668
+ });
4669
+ return {
4670
+ exitCode: report.status === 'completed_with_blockers' ? 1 : 0,
4671
+ stdout: stringifyJson(report, processFlags.json),
4672
+ stderr: '',
4673
+ };
4674
+ }
3433
4675
  if (command === 'process' && subcommand === 'save-draft') {
3434
4676
  const processFlags = parseProcessSaveDraftFlags(commandArgs);
3435
4677
  if (processFlags.help) {
@@ -3562,6 +4804,59 @@ export async function executeCli(argv, deps) {
3562
4804
  stderr: '',
3563
4805
  };
3564
4806
  }
4807
+ if (command === 'flow' && subcommand === 'identity-preflight') {
4808
+ const flowFlags = parseIdentityPreflightFlags(commandArgs);
4809
+ if (flowFlags.help) {
4810
+ return { exitCode: 0, stdout: `${renderFlowIdentityPreflightHelp()}\n`, stderr: '' };
4811
+ }
4812
+ const report = await flowIdentityPreflightImpl({
4813
+ inputPath: flowFlags.inputPath,
4814
+ outDir: flowFlags.outDir,
4815
+ candidateInputPaths: flowFlags.candidateInputPaths,
4816
+ remoteCandidateSearch: flowFlags.remoteCandidateSearch,
4817
+ remoteQuery: flowFlags.remoteQuery,
4818
+ remoteLimit: flowFlags.remoteLimit,
4819
+ env: deps.env,
4820
+ fetchImpl: deps.fetchImpl,
4821
+ });
4822
+ return {
4823
+ exitCode: report.status === 'passed' ? 0 : 1,
4824
+ stdout: stringifyJson(report, flowFlags.json),
4825
+ stderr: '',
4826
+ };
4827
+ }
4828
+ if (command === 'flow' && subcommand === 'build-plan') {
4829
+ const action = commandArgs[0] ?? '';
4830
+ if (!action || action === '--help' || action === '-h') {
4831
+ return { exitCode: 0, stdout: `${renderFlowBuildPlanHelp()}\n`, stderr: '' };
4832
+ }
4833
+ if (action !== 'validate' && action !== 'materialize') {
4834
+ throw new CliError("flow build-plan action must be 'validate' or 'materialize'.", {
4835
+ code: 'INVALID_ARGS',
4836
+ exitCode: 2,
4837
+ });
4838
+ }
4839
+ const flowFlags = parseBuildPlanFlags(commandArgs.slice(1));
4840
+ if (flowFlags.help) {
4841
+ return { exitCode: 0, stdout: `${renderFlowBuildPlanHelp()}\n`, stderr: '' };
4842
+ }
4843
+ const report = action === 'validate'
4844
+ ? await flowBuildPlanValidateImpl({
4845
+ inputPath: flowFlags.inputPath,
4846
+ outDir: flowFlags.outDir,
4847
+ reportOnly: flowFlags.reportOnly,
4848
+ })
4849
+ : await flowBuildPlanMaterializeImpl({
4850
+ inputPath: flowFlags.inputPath,
4851
+ outDir: flowFlags.outDir,
4852
+ reportOnly: flowFlags.reportOnly,
4853
+ });
4854
+ return {
4855
+ exitCode: report.status === 'blocked' && !flowFlags.reportOnly ? 1 : 0,
4856
+ stdout: stringifyJson(report, flowFlags.json),
4857
+ stderr: '',
4858
+ };
4859
+ }
3565
4860
  if (command === 'flow' && subcommand === 'remediate') {
3566
4861
  const flowFlags = parseFlowRemediateFlags(commandArgs);
3567
4862
  if (flowFlags.help) {
@@ -3855,81 +5150,84 @@ export async function executeCli(argv, deps) {
3855
5150
  stderr: '',
3856
5151
  };
3857
5152
  }
3858
- if (command === 'review' && !subcommand) {
3859
- return { exitCode: 0, stdout: `${renderReviewHelp()}\n`, stderr: '' };
3860
- }
3861
- if (command === 'review' && subcommand === 'process') {
3862
- const reviewFlags = parseReviewProcessFlags(commandArgs);
3863
- if (reviewFlags.help) {
3864
- return { exitCode: 0, stdout: `${renderReviewProcessHelp()}\n`, stderr: '' };
3865
- }
3866
- const report = await processReviewImpl({
3867
- rowsFile: reviewFlags.rowsFile,
3868
- runRoot: reviewFlags.runRoot,
3869
- runId: reviewFlags.runId,
3870
- outDir: reviewFlags.outDir,
3871
- startTs: reviewFlags.startTs,
3872
- endTs: reviewFlags.endTs,
3873
- logicVersion: reviewFlags.logicVersion,
3874
- enableLlm: reviewFlags.enableLlm,
3875
- llmModel: reviewFlags.llmModel,
3876
- llmMaxProcesses: reviewFlags.llmMaxProcesses,
5153
+ if (command === 'qa' && !subcommand) {
5154
+ return { exitCode: 0, stdout: `${renderQaHelp()}\n`, stderr: '' };
5155
+ }
5156
+ if (command === 'qa' && subcommand === 'process') {
5157
+ const qaFlags = parseQaProcessFlags(commandArgs);
5158
+ if (qaFlags.help) {
5159
+ return { exitCode: 0, stdout: `${renderQaProcessHelp()}\n`, stderr: '' };
5160
+ }
5161
+ const report = await processQaImpl({
5162
+ rowsFile: qaFlags.rowsFile,
5163
+ runRoot: qaFlags.runRoot,
5164
+ runId: qaFlags.runId,
5165
+ outDir: qaFlags.outDir,
5166
+ startTs: qaFlags.startTs,
5167
+ endTs: qaFlags.endTs,
5168
+ logicVersion: qaFlags.logicVersion,
5169
+ enableLlm: qaFlags.enableLlm,
5170
+ llmModel: qaFlags.llmModel,
5171
+ llmMaxProcesses: qaFlags.llmMaxProcesses,
3877
5172
  env: deps.env,
3878
5173
  fetchImpl: deps.fetchImpl,
3879
5174
  });
3880
5175
  return {
3881
5176
  exitCode: 0,
3882
- stdout: stringifyJson(report, reviewFlags.json),
5177
+ stdout: stringifyJson(report, qaFlags.json),
3883
5178
  stderr: '',
3884
5179
  };
3885
5180
  }
3886
- if (command === 'review' && subcommand === 'flow') {
3887
- const reviewFlags = parseReviewFlowFlags(commandArgs);
3888
- if (reviewFlags.help) {
3889
- return { exitCode: 0, stdout: `${renderReviewFlowHelp()}\n`, stderr: '' };
3890
- }
3891
- const report = await flowReviewImpl({
3892
- rowsFile: reviewFlags.rowsFile,
3893
- flowsDir: reviewFlags.flowsDir,
3894
- runRoot: reviewFlags.runRoot,
3895
- runId: reviewFlags.runId,
3896
- outDir: reviewFlags.outDir,
3897
- startTs: reviewFlags.startTs,
3898
- endTs: reviewFlags.endTs,
3899
- logicVersion: reviewFlags.logicVersion,
3900
- enableLlm: reviewFlags.enableLlm,
3901
- llmModel: reviewFlags.llmModel,
3902
- llmMaxFlows: reviewFlags.llmMaxFlows,
3903
- llmBatchSize: reviewFlags.llmBatchSize,
3904
- similarityThreshold: reviewFlags.similarityThreshold,
3905
- methodologyId: reviewFlags.methodologyId,
5181
+ if (command === 'qa' && subcommand === 'flow') {
5182
+ const qaFlags = parseQaFlowFlags(commandArgs);
5183
+ if (qaFlags.help) {
5184
+ return { exitCode: 0, stdout: `${renderQaFlowHelp()}\n`, stderr: '' };
5185
+ }
5186
+ const report = await flowQaImpl({
5187
+ rowsFile: qaFlags.rowsFile,
5188
+ flowsDir: qaFlags.flowsDir,
5189
+ runRoot: qaFlags.runRoot,
5190
+ runId: qaFlags.runId,
5191
+ outDir: qaFlags.outDir,
5192
+ startTs: qaFlags.startTs,
5193
+ endTs: qaFlags.endTs,
5194
+ logicVersion: qaFlags.logicVersion,
5195
+ enableLlm: qaFlags.enableLlm,
5196
+ llmModel: qaFlags.llmModel,
5197
+ llmMaxFlows: qaFlags.llmMaxFlows,
5198
+ llmBatchSize: qaFlags.llmBatchSize,
5199
+ similarityThreshold: qaFlags.similarityThreshold,
5200
+ methodologyId: qaFlags.methodologyId,
3906
5201
  env: deps.env,
3907
5202
  fetchImpl: deps.fetchImpl,
3908
5203
  });
3909
5204
  return {
3910
5205
  exitCode: 0,
3911
- stdout: stringifyJson(report, reviewFlags.json),
5206
+ stdout: stringifyJson(report, qaFlags.json),
3912
5207
  stderr: '',
3913
5208
  };
3914
5209
  }
3915
- if (command === 'review' && subcommand === 'lifecyclemodel') {
3916
- const reviewFlags = parseReviewLifecyclemodelFlags(commandArgs);
3917
- if (reviewFlags.help) {
3918
- return { exitCode: 0, stdout: `${renderReviewLifecyclemodelHelp()}\n`, stderr: '' };
5210
+ if (command === 'qa' && subcommand === 'lifecyclemodel') {
5211
+ const qaFlags = parseQaLifecyclemodelFlags(commandArgs);
5212
+ if (qaFlags.help) {
5213
+ return { exitCode: 0, stdout: `${renderQaLifecyclemodelHelp()}\n`, stderr: '' };
3919
5214
  }
3920
- const report = await lifecyclemodelReviewImpl({
3921
- runDir: reviewFlags.runDir,
3922
- outDir: reviewFlags.outDir,
3923
- startTs: reviewFlags.startTs,
3924
- endTs: reviewFlags.endTs,
3925
- logicVersion: reviewFlags.logicVersion,
5215
+ const report = await lifecyclemodelQaImpl({
5216
+ runDir: qaFlags.runDir,
5217
+ outDir: qaFlags.outDir,
5218
+ startTs: qaFlags.startTs,
5219
+ endTs: qaFlags.endTs,
5220
+ logicVersion: qaFlags.logicVersion,
3926
5221
  });
3927
5222
  return {
3928
5223
  exitCode: 0,
3929
- stdout: stringifyJson(report, reviewFlags.json),
5224
+ stdout: stringifyJson(report, qaFlags.json),
3930
5225
  stderr: '',
3931
5226
  };
3932
5227
  }
5228
+ if (command === 'review') {
5229
+ return removedReviewCommand(subcommand ?? undefined);
5230
+ }
3933
5231
  return plannedCommand(command, subcommand ?? undefined);
3934
5232
  }
3935
5233
  catch (error) {