@tiangong-lca/cli 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +154 -30
  2. package/dist/src/cli.js +2235 -149
  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-local.js +231 -0
  15. package/dist/src/lib/dataset-local.js.map +1 -0
  16. package/dist/src/lib/dataset-references-rewrite.js +214 -0
  17. package/dist/src/lib/dataset-references-rewrite.js.map +1 -0
  18. package/dist/src/lib/dataset-remote-refresh.js +166 -0
  19. package/dist/src/lib/dataset-remote-refresh.js.map +1 -0
  20. package/dist/src/lib/dataset-remote-verify.js +543 -0
  21. package/dist/src/lib/dataset-remote-verify.js.map +1 -0
  22. package/dist/src/lib/dataset-validate.js +247 -0
  23. package/dist/src/lib/dataset-validate.js.map +1 -0
  24. package/dist/src/lib/flow-payload-validation.js +51 -0
  25. package/dist/src/lib/flow-payload-validation.js.map +1 -0
  26. package/dist/src/lib/flow-publish-reviewed-data.js +16 -0
  27. package/dist/src/lib/flow-publish-reviewed-data.js.map +1 -1
  28. package/dist/src/lib/flow-publish-version.js +182 -12
  29. package/dist/src/lib/flow-publish-version.js.map +1 -1
  30. package/dist/src/lib/flow-regen-product.js +2 -10
  31. package/dist/src/lib/flow-regen-product.js.map +1 -1
  32. package/dist/src/lib/flow-remediate.js +4 -8
  33. package/dist/src/lib/flow-remediate.js.map +1 -1
  34. package/dist/src/lib/identity-preflight.js +1021 -0
  35. package/dist/src/lib/identity-preflight.js.map +1 -0
  36. package/dist/src/lib/lifecyclemodel-auto-build.js +11 -8
  37. package/dist/src/lib/lifecyclemodel-auto-build.js.map +1 -1
  38. package/dist/src/lib/lifecyclemodel-graph.js +248 -0
  39. package/dist/src/lib/lifecyclemodel-graph.js.map +1 -0
  40. package/dist/src/lib/lifecyclemodel-publish-build.js +1 -1
  41. package/dist/src/lib/lifecyclemodel-publish-build.js.map +1 -1
  42. package/dist/src/lib/lifecyclemodel-save-draft-run.js +245 -0
  43. package/dist/src/lib/lifecyclemodel-save-draft-run.js.map +1 -0
  44. package/dist/src/lib/lifecyclemodel-validate-build.js +1 -1
  45. package/dist/src/lib/lifecyclemodel-validate-build.js.map +1 -1
  46. package/dist/src/lib/process-auto-build.js +158 -8
  47. package/dist/src/lib/process-auto-build.js.map +1 -1
  48. package/dist/src/lib/process-batch-build.js +6 -3
  49. package/dist/src/lib/process-batch-build.js.map +1 -1
  50. package/dist/src/lib/process-dedup-review.js +921 -0
  51. package/dist/src/lib/process-dedup-review.js.map +1 -0
  52. package/dist/src/lib/process-flow-build-plan.js +1071 -0
  53. package/dist/src/lib/process-flow-build-plan.js.map +1 -0
  54. package/dist/src/lib/process-payload-validation.js +57 -0
  55. package/dist/src/lib/process-payload-validation.js.map +1 -0
  56. package/dist/src/lib/process-publish-build.js +126 -10
  57. package/dist/src/lib/process-publish-build.js.map +1 -1
  58. package/dist/src/lib/process-refresh-references.js +1037 -0
  59. package/dist/src/lib/process-refresh-references.js.map +1 -0
  60. package/dist/src/lib/process-required-fields.js +810 -0
  61. package/dist/src/lib/process-required-fields.js.map +1 -0
  62. package/dist/src/lib/process-resume-build.js +4 -6
  63. package/dist/src/lib/process-resume-build.js.map +1 -1
  64. package/dist/src/lib/process-save-draft-run.js +35 -13
  65. package/dist/src/lib/process-save-draft-run.js.map +1 -1
  66. package/dist/src/lib/process-scope-statistics.js +859 -0
  67. package/dist/src/lib/process-scope-statistics.js.map +1 -0
  68. package/dist/src/lib/process-verify-rows.js +250 -0
  69. package/dist/src/lib/process-verify-rows.js.map +1 -0
  70. package/dist/src/lib/publish.js +101 -1
  71. package/dist/src/lib/publish.js.map +1 -1
  72. package/dist/src/lib/remote.js +4 -4
  73. package/dist/src/lib/remote.js.map +1 -1
  74. package/dist/src/lib/review-flow.js +58 -0
  75. package/dist/src/lib/review-flow.js.map +1 -1
  76. package/dist/src/lib/review-lifecyclemodel.js +2 -2
  77. package/dist/src/lib/review-lifecyclemodel.js.map +1 -1
  78. package/dist/src/lib/review-process.js +150 -2
  79. package/dist/src/lib/review-process.js.map +1 -1
  80. package/dist/src/lib/runtime-rulesets.js +283 -0
  81. package/dist/src/lib/runtime-rulesets.js.map +1 -0
  82. package/dist/src/lib/tidas-sdk-package-validator.js +28 -9
  83. package/dist/src/lib/tidas-sdk-package-validator.js.map +1 -1
  84. package/dist/src/lib/tidas-sdk-validation.js +96 -0
  85. package/dist/src/lib/tidas-sdk-validation.js.map +1 -0
  86. package/dist/src/lib/user-api-key.js +1 -1
  87. package/dist/src/lib/user-api-key.js.map +1 -1
  88. package/package.json +5 -5
  89. /package/bin/{tiangong.d.ts → tiangong-lca.d.ts} +0 -0
  90. /package/bin/{tiangong.js → tiangong-lca.js} +0 -0
package/dist/src/cli.js CHANGED
@@ -8,14 +8,23 @@ import { runLifecyclemodelBuildResultingProcess, } from './lib/lifecyclemodel-re
8
8
  import { runLifecyclemodelPublishResultingProcess, } from './lib/lifecyclemodel-publish-resulting-process.js';
9
9
  import { runLifecyclemodelValidateBuild, } from './lib/lifecyclemodel-validate-build.js';
10
10
  import { runLifecyclemodelPublishBuild, } from './lib/lifecyclemodel-publish-build.js';
11
+ import { runLifecyclemodelSaveDraft, } from './lib/lifecyclemodel-save-draft-run.js';
12
+ import { runLifecyclemodelGraph, } from './lib/lifecyclemodel-graph.js';
11
13
  import { runLifecyclemodelOrchestrate, } from './lib/lifecyclemodel-orchestrate.js';
12
14
  import { runProcessAutoBuild, } from './lib/process-auto-build.js';
13
15
  import { runProcessGet, } from './lib/process-get.js';
14
16
  import { runProcessList, } from './lib/process-list.js';
15
17
  import { runProcessBatchBuild, } from './lib/process-batch-build.js';
18
+ import { runProcessScopeStatistics, } from './lib/process-scope-statistics.js';
19
+ import { runProcessRefreshReferences, } from './lib/process-refresh-references.js';
20
+ import { runProcessDedupReview, } from './lib/process-dedup-review.js';
16
21
  import { runProcessResumeBuild, } from './lib/process-resume-build.js';
17
22
  import { runProcessPublishBuild, } from './lib/process-publish-build.js';
18
23
  import { runProcessSaveDraft, } from './lib/process-save-draft-run.js';
24
+ import { runProcessRequiredFieldsComplete, } from './lib/process-required-fields.js';
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';
19
28
  import { runPublish } from './lib/publish.js';
20
29
  import { runProcessReview, } from './lib/review-process.js';
21
30
  import { runFlowReview, } from './lib/review-flow.js';
@@ -31,6 +40,15 @@ import { runFlowBuildAliasMap, } from './lib/flow-build-alias-map.js';
31
40
  import { runFlowApplyProcessFlowRepairs, runFlowPlanProcessFlowRepairs, runFlowRegenProduct, runFlowScanProcessFlowRefs, runFlowValidateProcesses, } from './lib/flow-regen-product.js';
32
41
  import { executeRemoteCommand, getRemoteCommandHelp } from './lib/remote.js';
33
42
  import { runValidation, } from './lib/validation.js';
43
+ import { runDatasetValidate, } from './lib/dataset-validate.js';
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';
34
52
  function renderMainHelp(dotEnvStatus) {
35
53
  return `TianGong LCA CLI
36
54
 
@@ -43,15 +61,16 @@ Design principles:
43
61
  - file-first input and JSON-first output
44
62
 
45
63
  Usage:
46
- tiangong <command> [subcommand] [options]
64
+ tiangong-lca <command> [subcommand] [options]
47
65
 
48
66
  Commands:
49
67
  Implemented Commands:
50
68
  doctor show environment diagnostics
51
69
  search flow | process | lifecyclemodel
52
- process get | list | auto-build | resume-build | publish-build | save-draft | batch-build
53
- 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
54
- lifecyclemodel auto-build | validate-build | publish-build | build-resulting-process | publish-resulting-process | orchestrate
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
73
+ lifecyclemodel auto-build | validate-build | publish-build | save-draft | graph | build-resulting-process | publish-resulting-process | orchestrate
55
74
  review process | flow | lifecyclemodel
56
75
  publish run
57
76
  validation run
@@ -64,40 +83,63 @@ Planned Surface (not implemented yet):
64
83
  Planned commands currently print an explicit "not implemented yet" message and exit with code 2.
65
84
 
66
85
  Examples:
67
- tiangong doctor
68
- tiangong search flow --input ./request.json
69
- tiangong search process --input ./request.json --dry-run
70
- tiangong process get --id <process-id>
71
- tiangong process list --state-code 100 --limit 20
72
- tiangong process auto-build --input ./pff-request.json
73
- tiangong process resume-build --run-id <id>
74
- tiangong process publish-build --run-id <id>
75
- tiangong process save-draft --input ./patched-processes.jsonl --dry-run
76
- tiangong process batch-build --input ./batch-request.json
77
- tiangong lifecyclemodel auto-build --input ./lifecyclemodel-auto-build.request.json
78
- tiangong lifecyclemodel validate-build --run-dir ./artifacts/lifecyclemodel_auto_build/<run_id>
79
- tiangong lifecyclemodel publish-build --run-dir ./artifacts/lifecyclemodel_auto_build/<run_id>
80
- tiangong lifecyclemodel orchestrate plan --input ./lifecyclemodel-orchestrate.request.json --out-dir ./artifacts/lifecyclemodel_recursive/run-001
81
- tiangong flow get --id <flow-id> --version <version>
82
- tiangong flow list --id <flow-id> --state-code 100 --limit 20
83
- tiangong flow fetch-rows --refs-file ./flow-refs.json --out-dir ./flow-fetch
84
- tiangong flow materialize-decisions --decision-file ./approved-decisions.json --flow-rows-file ./review-input-rows.jsonl --out-dir ./flow-decisions
85
- tiangong flow remediate --input-file ./invalid-flows.jsonl --out-dir ./flow-remediation
86
- tiangong flow publish-version --input-file ./ready-flows.jsonl --out-dir ./flow-publish --commit
87
- tiangong flow publish-reviewed-data --flow-rows-file ./reviewed-flows.jsonl --original-flow-rows-file ./original-flows.jsonl --out-dir ./flow-publish-review
88
- tiangong flow build-alias-map --old-flow-file ./old-flows.jsonl --new-flow-file ./new-flows.jsonl --out-dir ./flow-alias-map
89
- tiangong flow scan-process-flow-refs --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-scan
90
- tiangong flow plan-process-flow-repairs --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-repair-plan
91
- tiangong flow apply-process-flow-repairs --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-repair-apply
92
- tiangong flow regen-product --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-regeneration --apply
93
- tiangong flow validate-processes --original-processes-file ./before.jsonl --patched-processes-file ./after.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-validation
94
- tiangong review process --rows-file ./processes.jsonl --out-dir ./review
95
- tiangong review process --run-root ./artifacts/process_from_flow/<run_id> --run-id <run_id> --out-dir ./review
96
- tiangong review flow --rows-file ./flows.json --out-dir ./review
97
- tiangong review lifecyclemodel --run-dir ./artifacts/lifecyclemodel_auto_build/<run_id> --out-dir ./lifecyclemodel-review
98
- tiangong publish run --input ./publish-request.json --dry-run
99
- tiangong validation run --input-dir ./package --engine auto
100
- tiangong admin embedding-run --input ./jobs.json
86
+ tiangong-lca doctor
87
+ tiangong-lca search flow --input ./request.json
88
+ tiangong-lca search process --input ./request.json --dry-run
89
+ tiangong-lca process get --id <process-id>
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
93
+ tiangong-lca process scope-statistics --out-dir /abs/path/to/process-scope --state-code 0 --state-code 100
94
+ tiangong-lca process dedup-review --input ./duplicate-groups.json --out-dir /abs/path/to/process-dedup
95
+ tiangong-lca process auto-build --input ./pff-request.json --out-dir /abs/path/to/process-run
96
+ tiangong-lca process resume-build --run-dir /abs/path/to/process-run
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
99
+ tiangong-lca process save-draft --input ./patched-processes.jsonl --out-dir /abs/path/to/process-save-draft --dry-run
100
+ tiangong-lca process batch-build --input ./batch-request.json --out-dir /abs/path/to/process-batch
101
+ tiangong-lca process refresh-references --out-dir /abs/path/to/process-refresh --dry-run
102
+ tiangong-lca process verify-rows --rows-file ./process-list-report.json --out-dir /abs/path/to/process-verify
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
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
115
+ tiangong-lca lifecyclemodel auto-build --input ./lifecyclemodel-auto-build.request.json --out-dir /abs/path/to/lifecyclemodel-run
116
+ tiangong-lca lifecyclemodel validate-build --run-dir /abs/path/to/lifecyclemodel-run
117
+ tiangong-lca lifecyclemodel publish-build --run-dir /abs/path/to/lifecyclemodel-run
118
+ tiangong-lca lifecyclemodel save-draft --input ./lifecyclemodels.jsonl --out-dir /abs/path/to/lifecyclemodel-save-draft --dry-run
119
+ tiangong-lca lifecyclemodel graph --input ./lifecyclemodels.jsonl --out-dir /abs/path/to/lifecyclemodel-graph --format all
120
+ tiangong-lca lifecyclemodel orchestrate plan --input ./lifecyclemodel-orchestrate.request.json --out-dir /abs/path/to/lifecyclemodel-recursive-run
121
+ tiangong-lca flow get --id <flow-id> --version <version>
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
125
+ tiangong-lca flow fetch-rows --refs-file ./flow-refs.json --out-dir ./flow-fetch
126
+ tiangong-lca flow materialize-decisions --decision-file ./approved-decisions.json --flow-rows-file ./review-input-rows.jsonl --out-dir ./flow-decisions
127
+ tiangong-lca flow remediate --input-file ./invalid-flows.jsonl --out-dir ./flow-remediation
128
+ tiangong-lca flow publish-version --input-file ./ready-flows.jsonl --out-dir ./flow-publish --commit
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
130
+ tiangong-lca flow build-alias-map --old-flow-file ./old-flows.jsonl --new-flow-file ./new-flows.jsonl --out-dir ./flow-alias-map
131
+ tiangong-lca flow scan-process-flow-refs --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-scan
132
+ tiangong-lca flow plan-process-flow-repairs --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-repair-plan
133
+ tiangong-lca flow apply-process-flow-repairs --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-repair-apply
134
+ tiangong-lca flow regen-product --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-regeneration --apply
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
136
+ tiangong-lca review process --rows-file ./processes.jsonl --out-dir ./review
137
+ tiangong-lca review process --run-root /abs/path/to/process-run --run-id <run_id> --out-dir ./review
138
+ tiangong-lca review flow --rows-file ./flows.json --out-dir ./review
139
+ tiangong-lca review lifecyclemodel --run-dir /abs/path/to/lifecyclemodel-run --out-dir ./lifecyclemodel-review
140
+ tiangong-lca publish run --input ./publish-request.json --dry-run
141
+ tiangong-lca validation run --input-dir ./package --engine auto
142
+ tiangong-lca admin embedding-run --input ./jobs.json
101
143
 
102
144
  Environment:
103
145
  .env loaded: ${dotEnvStatus.loaded ? `yes (${dotEnvStatus.path}, ${dotEnvStatus.count} keys)` : 'no'}
@@ -105,7 +147,7 @@ Environment:
105
147
  }
106
148
  function renderDoctorHelp() {
107
149
  return `Usage:
108
- tiangong doctor [--json]
150
+ tiangong-lca doctor [--json]
109
151
 
110
152
  Options:
111
153
  --json Print structured environment diagnostics
@@ -114,7 +156,7 @@ Options:
114
156
  }
115
157
  function renderSearchHelp() {
116
158
  return `Usage:
117
- tiangong search <flow|process|lifecyclemodel> --input <file> [options]
159
+ tiangong-lca search <flow|process|lifecyclemodel> --input <file> [options]
118
160
 
119
161
  Options:
120
162
  --input <file> JSON request file
@@ -139,7 +181,7 @@ Runtime note:
139
181
  }
140
182
  function renderAdminHelp() {
141
183
  return `Usage:
142
- tiangong admin embedding-run --input <file> [options]
184
+ tiangong-lca admin embedding-run --input <file> [options]
143
185
 
144
186
  Options:
145
187
  --input <file> JSON request file
@@ -162,7 +204,7 @@ Runtime note:
162
204
  }
163
205
  function renderPublishHelp() {
164
206
  return `Usage:
165
- tiangong publish run --input <file> [options]
207
+ tiangong-lca publish run --input <file> [options]
166
208
 
167
209
  Options:
168
210
  --input <file> JSON publish request file
@@ -174,11 +216,18 @@ Options:
174
216
 
175
217
  Path rule:
176
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
177
226
  `.trim();
178
227
  }
179
228
  function renderValidationHelp() {
180
229
  return `Usage:
181
- tiangong validation run --input-dir <dir> [options]
230
+ tiangong-lca validation run --input-dir <dir> [options]
182
231
 
183
232
  Options:
184
233
  --input-dir <dir> TIDAS package directory
@@ -188,13 +237,327 @@ Options:
188
237
  -h, --help
189
238
  `.trim();
190
239
  }
240
+ function renderDatasetHelp() {
241
+ return `Usage:
242
+ tiangong-lca dataset <subcommand> [options]
243
+
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
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/review gates
254
+ evidence-search Plan or record field-level public evidence retrieval
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
257
+
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
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
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
387
+ `.trim();
388
+ }
389
+ function renderDatasetValidateHelp() {
390
+ return `Usage:
391
+ tiangong-lca dataset validate --input <file> [options]
392
+
393
+ Options:
394
+ --input <file> Local rows as JSON or JSONL; objects with rows[] are also accepted
395
+ --type <type> auto | flow | process | lifecyclemodel (default: auto)
396
+ --out-dir <dir> Optional artifact directory for validation report and row splits
397
+ --json Print compact JSON
398
+ -h, --help
399
+
400
+ Outputs written under --out-dir:
401
+ - outputs/validation-report.json
402
+ - outputs/valid-rows.jsonl
403
+ - outputs/invalid-rows.jsonl
404
+ `.trim();
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 review 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
+ - review/process/... and/or review/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
+ }
512
+ function renderDatasetReferencesHelp() {
513
+ return `Usage:
514
+ tiangong-lca dataset references <rewrite|refresh-remote> [options]
515
+
516
+ Rewrite:
517
+ tiangong-lca dataset references rewrite --input <file> --from flow:<id>[@<version>] --to flow:<id>[@<version>] [options]
518
+
519
+ Refresh remote versions:
520
+ tiangong-lca dataset references refresh-remote --input <file> --out <file> --out-dir <dir> [options]
521
+
522
+ Options:
523
+ --input <file> Local rows as JSON or JSONL; process and lifecyclemodel rows are supported
524
+ --from <ref> Source flow reference, for example flow:<old-id>@01.00.000
525
+ --to <ref> Target flow reference, for example flow:<new-id>@01.01.000
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
535
+ -h, --help
536
+
537
+ Environment:
538
+ none for local dry-run
539
+ TIANGONG_LCA_API_BASE_URL, TIANGONG_LCA_API_KEY, and TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
540
+ when --commit executes remote writes
541
+
542
+ Outputs written under --out-dir:
543
+ - outputs/patched-rows.jsonl
544
+ - outputs/rewrite-plan.json
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
550
+ `.trim();
551
+ }
191
552
  function renderFlowHelp() {
192
553
  return `Usage:
193
- tiangong flow <subcommand> [options]
554
+ tiangong-lca flow <subcommand> [options]
194
555
 
195
556
  Implemented Subcommands:
196
557
  get Load one flow dataset by identifier through direct Supabase access
197
558
  list Enumerate flow datasets through direct Supabase access with deterministic filters
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
198
561
  fetch-rows Materialize real DB flow refs into local review-input rows and fetch artifacts
199
562
  materialize-decisions Materialize approved merge decisions into canonical-map, rewrite-plan, and seed artifacts
200
563
  remediate Deterministically repair invalid local flow rows and emit artifact-first outputs
@@ -208,25 +571,73 @@ Implemented Subcommands:
208
571
  validate-processes Validate locally patched process rows against allowed flow-reference-only changes
209
572
 
210
573
  Examples:
211
- tiangong flow --help
212
- tiangong flow get --help
213
- tiangong flow list --help
214
- tiangong flow fetch-rows --help
215
- tiangong flow materialize-decisions --help
216
- tiangong flow remediate --help
217
- tiangong flow publish-version --help
218
- tiangong flow publish-reviewed-data --help
219
- tiangong flow build-alias-map --help
220
- tiangong flow scan-process-flow-refs --help
221
- tiangong flow plan-process-flow-repairs --help
222
- tiangong flow apply-process-flow-repairs --help
223
- tiangong flow regen-product --help
224
- tiangong flow validate-processes --help
574
+ tiangong-lca flow --help
575
+ tiangong-lca flow get --help
576
+ tiangong-lca flow list --help
577
+ tiangong-lca flow identity-preflight --help
578
+ tiangong-lca flow build-plan validate --help
579
+ tiangong-lca flow fetch-rows --help
580
+ tiangong-lca flow materialize-decisions --help
581
+ tiangong-lca flow remediate --help
582
+ tiangong-lca flow publish-version --help
583
+ tiangong-lca flow publish-reviewed-data --help
584
+ tiangong-lca flow build-alias-map --help
585
+ tiangong-lca flow scan-process-flow-refs --help
586
+ tiangong-lca flow plan-process-flow-repairs --help
587
+ tiangong-lca flow apply-process-flow-repairs --help
588
+ tiangong-lca flow regen-product --help
589
+ tiangong-lca flow validate-processes --help
590
+ `.trim();
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
225
636
  `.trim();
226
637
  }
227
638
  function renderFlowGetHelp() {
228
639
  return `Usage:
229
- tiangong flow get --id <flow-id> [options]
640
+ tiangong-lca flow get --id <flow-id> [options]
230
641
 
231
642
  Options:
232
643
  --id <flow-id> Flow UUID
@@ -248,7 +659,7 @@ Runtime note:
248
659
  }
249
660
  function renderFlowListHelp() {
250
661
  return `Usage:
251
- tiangong flow list [options]
662
+ tiangong-lca flow list [options]
252
663
 
253
664
  Options:
254
665
  --id <flow-id> Repeatable exact flow UUID filter
@@ -276,7 +687,7 @@ Runtime note:
276
687
  }
277
688
  function renderFlowRemediateHelp() {
278
689
  return `Usage:
279
- tiangong flow remediate --input-file <file> --out-dir <dir> [options]
690
+ tiangong-lca flow remediate --input-file <file> --out-dir <dir> [options]
280
691
 
281
692
  Options:
282
693
  --input-file <file> Invalid flow rows as JSON or JSONL
@@ -295,7 +706,7 @@ Outputs written under --out-dir:
295
706
  }
296
707
  function renderFlowFetchRowsHelp() {
297
708
  return `Usage:
298
- tiangong flow fetch-rows --refs-file <file> --out-dir <dir> [options]
709
+ tiangong-lca flow fetch-rows --refs-file <file> --out-dir <dir> [options]
299
710
 
300
711
  Options:
301
712
  --refs-file <file> Flow refs as JSON or JSONL
@@ -320,7 +731,7 @@ Outputs written under --out-dir:
320
731
  }
321
732
  function renderFlowMaterializeDecisionsHelp() {
322
733
  return `Usage:
323
- tiangong flow materialize-decisions --decision-file <file> --flow-rows-file <file> --out-dir <dir> [options]
734
+ tiangong-lca flow materialize-decisions --decision-file <file> --flow-rows-file <file> --out-dir <dir> [options]
324
735
 
325
736
  Options:
326
737
  --decision-file <file> Approved cluster decisions as JSON or JSONL
@@ -339,7 +750,7 @@ Outputs written under --out-dir:
339
750
  }
340
751
  function renderFlowPublishVersionHelp() {
341
752
  return `Usage:
342
- tiangong flow publish-version --input-file <file> --out-dir <dir> [options]
753
+ tiangong-lca flow publish-version --input-file <file> --out-dir <dir> [options]
343
754
 
344
755
  Options:
345
756
  --input-file <file> Ready-for-publish flow rows as JSON or JSONL
@@ -360,12 +771,13 @@ Environment:
360
771
  Outputs written under --out-dir:
361
772
  - flows_tidas_sdk_plus_classification_mcp_success_list.json
362
773
  - flows_tidas_sdk_plus_classification_remote_validation_failed.jsonl
774
+ - flow-publish-version-gate-report.json
363
775
  - flows_tidas_sdk_plus_classification_mcp_sync_report.json
364
776
  `.trim();
365
777
  }
366
778
  function renderFlowPublishReviewedDataHelp() {
367
779
  return `Usage:
368
- tiangong flow publish-reviewed-data --out-dir <dir> [--flow-rows-file <file>] [--process-rows-file <file>] [options]
780
+ tiangong-lca flow publish-reviewed-data --out-dir <dir> [--flow-rows-file <file>] [--process-rows-file <file>] [options]
369
781
 
370
782
  Options:
371
783
  --flow-rows-file <file> Reviewed flow rows as JSON or JSONL
@@ -395,12 +807,13 @@ Outputs written under --out-dir:
395
807
  - publish-report.json
396
808
  - flows_tidas_sdk_plus_classification_mcp_success_list.json
397
809
  - flows_tidas_sdk_plus_classification_remote_validation_failed.jsonl
810
+ - flow-publish-version-gate-report.json
398
811
  - flows_tidas_sdk_plus_classification_mcp_sync_report.json
399
812
  `.trim();
400
813
  }
401
814
  function renderFlowBuildAliasMapHelp() {
402
815
  return `Usage:
403
- tiangong flow build-alias-map --old-flow-file <file> --new-flow-file <file> --out-dir <dir> [options]
816
+ tiangong-lca flow build-alias-map --old-flow-file <file> --new-flow-file <file> --out-dir <dir> [options]
404
817
 
405
818
  Options:
406
819
  --old-flow-file <file> Repeatable pre-governance flow snapshot as JSON or JSONL
@@ -420,7 +833,7 @@ Outputs written under --out-dir:
420
833
  }
421
834
  function renderFlowScanProcessFlowRefsHelp() {
422
835
  return `Usage:
423
- tiangong flow scan-process-flow-refs --processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
836
+ tiangong-lca flow scan-process-flow-refs --processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
424
837
 
425
838
  Options:
426
839
  --processes-file <file> Process rows as JSON or JSONL
@@ -441,7 +854,7 @@ Outputs written under --out-dir:
441
854
  }
442
855
  function renderFlowPlanProcessFlowRepairsHelp() {
443
856
  return `Usage:
444
- tiangong flow plan-process-flow-repairs --processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
857
+ tiangong-lca flow plan-process-flow-repairs --processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
445
858
 
446
859
  Options:
447
860
  --processes-file <file> Process rows as JSON or JSONL
@@ -462,7 +875,7 @@ Outputs written under --out-dir:
462
875
  }
463
876
  function renderFlowApplyProcessFlowRepairsHelp() {
464
877
  return `Usage:
465
- tiangong flow apply-process-flow-repairs --processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
878
+ tiangong-lca flow apply-process-flow-repairs --processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
466
879
 
467
880
  Options:
468
881
  --processes-file <file> Process rows as JSON or JSONL
@@ -486,7 +899,7 @@ Outputs written under --out-dir:
486
899
  }
487
900
  function renderFlowRegenProductHelp() {
488
901
  return `Usage:
489
- tiangong flow regen-product --processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
902
+ tiangong-lca flow regen-product --processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
490
903
 
491
904
  Options:
492
905
  --processes-file <file> Process rows as JSON or JSONL
@@ -512,7 +925,7 @@ Outputs written under --out-dir:
512
925
  }
513
926
  function renderFlowValidateProcessesHelp() {
514
927
  return `Usage:
515
- tiangong flow validate-processes --original-processes-file <file> --patched-processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
928
+ tiangong-lca flow validate-processes --original-processes-file <file> --patched-processes-file <file> --scope-flow-file <file> --out-dir <dir> [options]
516
929
 
517
930
  Options:
518
931
  --original-processes-file <file> Original process rows before repair as JSON or JSONL
@@ -530,7 +943,7 @@ Outputs written under --out-dir:
530
943
  }
531
944
  function renderReviewHelp() {
532
945
  return `Usage:
533
- tiangong review <subcommand> [options]
946
+ tiangong-lca review <subcommand> [options]
534
947
 
535
948
  Implemented Subcommands:
536
949
  process Review process build runs or rows-file snapshots and emit artifact-first findings
@@ -538,15 +951,15 @@ Implemented Subcommands:
538
951
  lifecyclemodel Review one local lifecyclemodel build run and emit artifact-first findings
539
952
 
540
953
  Examples:
541
- tiangong review --help
542
- tiangong review process --help
543
- tiangong review flow --help
544
- tiangong review lifecyclemodel --help
954
+ tiangong-lca review --help
955
+ tiangong-lca review process --help
956
+ tiangong-lca review flow --help
957
+ tiangong-lca review lifecyclemodel --help
545
958
  `.trim();
546
959
  }
547
960
  function renderReviewProcessHelp() {
548
961
  return `Usage:
549
- tiangong review process (--rows-file <file> | --run-root <dir>) --out-dir <dir> [options]
962
+ tiangong-lca review process (--rows-file <file> | --run-root <dir>) --out-dir <dir> [options]
550
963
 
551
964
  Options:
552
965
  --rows-file <file> Process rows JSON/JSONL file; full process list reports with rows[] are also accepted
@@ -565,7 +978,7 @@ Options:
565
978
  }
566
979
  function renderReviewFlowHelp() {
567
980
  return `Usage:
568
- tiangong review flow (--rows-file <file> | --flows-dir <dir> | --run-root <dir>) --out-dir <dir> [options]
981
+ tiangong-lca review flow (--rows-file <file> | --flows-dir <dir> | --run-root <dir>) --out-dir <dir> [options]
569
982
 
570
983
  Options:
571
984
  --rows-file <file> Flow rows JSON / JSONL file; the CLI materializes review-input/flows automatically
@@ -588,7 +1001,7 @@ Options:
588
1001
  }
589
1002
  function renderReviewLifecyclemodelHelp() {
590
1003
  return `Usage:
591
- tiangong review lifecyclemodel --run-dir <dir> --out-dir <dir> [options]
1004
+ tiangong-lca review lifecyclemodel --run-dir <dir> --out-dir <dir> [options]
592
1005
 
593
1006
  Options:
594
1007
  --run-dir <dir> Existing lifecyclemodel auto-build run directory
@@ -607,7 +1020,7 @@ This command:
607
1020
  }
608
1021
  function renderLifecyclemodelBuildResultingProcessHelp() {
609
1022
  return `Usage:
610
- tiangong lifecyclemodel build-resulting-process --input <file> [options]
1023
+ tiangong-lca lifecyclemodel build-resulting-process --input <file> [options]
611
1024
 
612
1025
  Options:
613
1026
  --input <file> JSON request file
@@ -623,7 +1036,7 @@ Remote lookup env (only when process_sources.allow_remote_lookup=true):
623
1036
  }
624
1037
  function renderLifecyclemodelPublishResultingProcessHelp() {
625
1038
  return `Usage:
626
- tiangong lifecyclemodel publish-resulting-process --run-dir <dir> [options]
1039
+ tiangong-lca lifecyclemodel publish-resulting-process --run-dir <dir> [options]
627
1040
 
628
1041
  Options:
629
1042
  --run-dir <dir> Existing lifecyclemodel resulting-process run directory
@@ -633,30 +1046,83 @@ Options:
633
1046
  -h, --help
634
1047
  `.trim();
635
1048
  }
1049
+ function renderLifecyclemodelSaveDraftHelp() {
1050
+ return `Usage:
1051
+ tiangong-lca lifecyclemodel save-draft --input <file> [options]
1052
+
1053
+ Options:
1054
+ --input <file> Lifecyclemodel rows JSON/JSONL file or publish-request.json
1055
+ --out-dir <dir> Run root written relative to cwd when a relative path is passed
1056
+ --commit Execute remote save-draft writes
1057
+ --dry-run Keep the command local-only (default)
1058
+ --json Print compact JSON
1059
+ -h, --help
1060
+
1061
+ Environment:
1062
+ none for local dry-run
1063
+ TIANGONG_LCA_API_BASE_URL, TIANGONG_LCA_API_KEY, and TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
1064
+ when --commit executes remote writes
1065
+
1066
+ Local gate:
1067
+ canonical lifecyclemodel payloads are validated against LifeCycleModelSchema before any remote write;
1068
+ schema-invalid rows stay in failures.jsonl instead of being committed
1069
+
1070
+ Outputs written under --out-dir:
1071
+ - inputs/normalized-input.json
1072
+ - outputs/save-draft-bundle/selected-lifecyclemodels.jsonl
1073
+ - outputs/save-draft-bundle/progress.jsonl
1074
+ - outputs/save-draft-bundle/failures.jsonl
1075
+ - outputs/save-draft-bundle/summary.json
1076
+ `.trim();
1077
+ }
1078
+ function renderLifecyclemodelGraphHelp() {
1079
+ return `Usage:
1080
+ tiangong-lca lifecyclemodel graph --input <file> [options]
1081
+
1082
+ Options:
1083
+ --input <file> Lifecyclemodel rows JSON/JSONL file
1084
+ --out-dir <dir> Artifact directory for graph files and findings
1085
+ --format <format> json | dot | svg | all (default: all)
1086
+ --check-connections Fail when process-instance links are missing or unresolved
1087
+ --json Print compact JSON
1088
+ -h, --help
1089
+
1090
+ Outputs written under --out-dir:
1091
+ - outputs/graph-report.json
1092
+ - outputs/findings.jsonl
1093
+ - graphs/*.json
1094
+ - graphs/*.dot
1095
+ - graphs/*.svg
1096
+ `.trim();
1097
+ }
636
1098
  function renderLifecyclemodelHelp() {
637
1099
  return `Usage:
638
- tiangong lifecyclemodel <subcommand> [options]
1100
+ tiangong-lca lifecyclemodel <subcommand> [options]
639
1101
 
640
1102
  Implemented Subcommands:
641
1103
  auto-build Build native lifecyclemodel json_ordered artifacts from local process run exports
642
1104
  validate-build Re-run local validation on one lifecyclemodel build run
643
1105
  publish-build Prepare lifecyclemodel publish handoff artifacts from one local build run
1106
+ save-draft Save canonical lifecyclemodel datasets through the bundle save path
1107
+ graph Derive lifecyclemodel graph artifacts and connection findings
644
1108
  build-resulting-process Deterministically aggregate a lifecycle model into a resulting process bundle
645
1109
  publish-resulting-process Prepare publish-bundle.json and publish-intent.json from a prior resulting-process run
646
1110
  orchestrate Plan, execute, or publish a recursive lifecyclemodel assembly run
647
1111
 
648
1112
  Examples:
649
- tiangong lifecyclemodel --help
650
- tiangong lifecyclemodel auto-build --help
651
- tiangong lifecyclemodel validate-build --help
652
- tiangong lifecyclemodel publish-build --help
653
- tiangong lifecyclemodel build-resulting-process --help
654
- tiangong lifecyclemodel orchestrate --help
1113
+ tiangong-lca lifecyclemodel --help
1114
+ tiangong-lca lifecyclemodel auto-build --help
1115
+ tiangong-lca lifecyclemodel validate-build --help
1116
+ tiangong-lca lifecyclemodel publish-build --help
1117
+ tiangong-lca lifecyclemodel save-draft --help
1118
+ tiangong-lca lifecyclemodel graph --help
1119
+ tiangong-lca lifecyclemodel build-resulting-process --help
1120
+ tiangong-lca lifecyclemodel orchestrate --help
655
1121
  `.trim();
656
1122
  }
657
1123
  function renderLifecyclemodelOrchestrateHelp() {
658
1124
  return `Usage:
659
- tiangong lifecyclemodel orchestrate <plan|execute|publish> [options]
1125
+ tiangong-lca lifecyclemodel orchestrate <plan|execute|publish> [options]
660
1126
 
661
1127
  Plan / execute options:
662
1128
  --input <file> JSON request file
@@ -682,11 +1148,11 @@ This command:
682
1148
  }
683
1149
  function renderLifecyclemodelAutoBuildHelp() {
684
1150
  return `Usage:
685
- tiangong lifecyclemodel auto-build --input <file> [options]
1151
+ tiangong-lca lifecyclemodel auto-build --input <file> [options]
686
1152
 
687
1153
  Options:
688
1154
  --input <file> JSON request file
689
- --out-dir <dir> Override the default lifecyclemodel build run root
1155
+ --out-dir <dir> Explicit run root; otherwise request.out_dir is required
690
1156
  --json Print compact JSON
691
1157
  -h, --help
692
1158
 
@@ -696,6 +1162,7 @@ Minimal request contract:
696
1162
  }
697
1163
 
698
1164
  This first CLI slice is local-only and read-only:
1165
+ - applies no implicit repo-local ./artifacts fallback; callers must provide a run root
699
1166
  - loads local process build run directories
700
1167
  - infers the process graph from shared flow UUIDs
701
1168
  - emits native lifecyclemodel json_ordered artifacts
@@ -704,7 +1171,7 @@ This first CLI slice is local-only and read-only:
704
1171
  }
705
1172
  function renderLifecyclemodelValidateBuildHelp() {
706
1173
  return `Usage:
707
- tiangong lifecyclemodel validate-build --run-dir <dir> [options]
1174
+ tiangong-lca lifecyclemodel validate-build --run-dir <dir> [options]
708
1175
 
709
1176
  Options:
710
1177
  --run-dir <dir> Existing lifecyclemodel auto-build run directory
@@ -720,7 +1187,7 @@ This command:
720
1187
  }
721
1188
  function renderLifecyclemodelPublishBuildHelp() {
722
1189
  return `Usage:
723
- tiangong lifecyclemodel publish-build --run-dir <dir> [options]
1190
+ tiangong-lca lifecyclemodel publish-build --run-dir <dir> [options]
724
1191
 
725
1192
  Options:
726
1193
  --run-dir <dir> Existing lifecyclemodel auto-build run directory
@@ -730,24 +1197,26 @@ Options:
730
1197
  This command:
731
1198
  - collects native lifecyclemodel json_ordered payloads from one local build run
732
1199
  - writes publish-bundle.json, publish-request.json, and publish-intent.json
733
- - keeps actual dry-run / commit execution in tiangong publish run
1200
+ - keeps actual dry-run / commit execution in tiangong-lca publish run
734
1201
  - routes lifecyclemodel commit through save_lifecycle_model_bundle internally
735
1202
  `.trim();
736
1203
  }
737
1204
  function renderProcessAutoBuildHelp() {
738
1205
  return `Usage:
739
- tiangong process auto-build --input <file> [options]
1206
+ tiangong-lca process auto-build --input <file> [options]
740
1207
 
741
1208
  Options:
742
1209
  --input <file> JSON request file
743
- --out-dir <dir> Override the default run root directory
1210
+ --out-dir <dir> Explicit run root; otherwise request.workspace_run_root is required
744
1211
  --json Print compact JSON
745
1212
  -h, --help
1213
+
1214
+ This command applies no implicit repo-local ./artifacts fallback.
746
1215
  `.trim();
747
1216
  }
748
1217
  function renderProcessGetHelp() {
749
1218
  return `Usage:
750
- tiangong process get --id <process-id> [options]
1219
+ tiangong-lca process get --id <process-id> [options]
751
1220
 
752
1221
  Options:
753
1222
  --id <process-id> Process UUID
@@ -767,7 +1236,7 @@ Runtime note:
767
1236
  }
768
1237
  function renderProcessListHelp() {
769
1238
  return `Usage:
770
- tiangong process list [options]
1239
+ tiangong-lca process list [options]
771
1240
 
772
1241
  Options:
773
1242
  --id <process-id> Repeatable exact process UUID filter
@@ -792,31 +1261,132 @@ Runtime note:
792
1261
  and authenticates that client with the resolved user access token.
793
1262
  `.trim();
794
1263
  }
1264
+ function renderProcessScopeStatisticsHelp() {
1265
+ return `Usage:
1266
+ tiangong-lca process scope-statistics --out-dir <dir> [options]
1267
+
1268
+ Options:
1269
+ --out-dir <dir> Artifact root to write inputs/outputs/reports
1270
+ --scope <name> visible | current-user (default: visible)
1271
+ --state-code <code> Repeatable non-negative integer state code filter
1272
+ --state-codes <csv> Comma-separated alias for one or more state codes
1273
+ --page-size <n> Remote page size (default: 200)
1274
+ --reuse-snapshot Reuse inputs/processes.snapshot.rows.jsonl instead of refetching
1275
+ --json Print compact JSON
1276
+ -h, --help
1277
+
1278
+ Outputs written under --out-dir:
1279
+ - inputs/processes.snapshot.manifest.json
1280
+ - inputs/processes.snapshot.rows.jsonl
1281
+ - outputs/process-scope-summary.json
1282
+ - outputs/domain-summary.json
1283
+ - outputs/craft-summary.json
1284
+ - outputs/product-summary.json
1285
+ - outputs/type-of-dataset-summary.json
1286
+ - reports/process-scope-statistics.md
1287
+ - reports/process-scope-statistics.zh-CN.md
1288
+ `.trim();
1289
+ }
1290
+ function renderProcessIdentityPreflightHelp() {
1291
+ return `Usage:
1292
+ tiangong-lca process identity-preflight --input <file> [options]
1293
+
1294
+ Options:
1295
+ --input <file> JSON preflight request with target process and optional candidates
1296
+ --candidate-input <path>
1297
+ Optional JSON/JSONL file or directory of candidate process rows; repeatable
1298
+ --remote-candidates
1299
+ Also fetch candidate rows from process_hybrid_search
1300
+ --remote-query <text>
1301
+ Override the remote search query; defaults to target identity text
1302
+ --remote-limit <n>
1303
+ Limit remote candidate rows after fetch
1304
+ --out-dir <dir> Optional artifact directory for identity decision outputs
1305
+ --json Print compact JSON
1306
+ -h, --help
1307
+
1308
+ Input contract:
1309
+ {
1310
+ "target": { "...": "process target or canonical processDataSet" },
1311
+ "candidates": [{ "...": "existing process row or canonical processDataSet" }]
1312
+ }
1313
+
1314
+ Outputs written under --out-dir:
1315
+ - outputs/identity-decision.json
1316
+ - outputs/identity-candidates.jsonl
1317
+ - outputs/identity-candidate-sources.json
1318
+ `.trim();
1319
+ }
1320
+ function renderProcessDedupReviewHelp() {
1321
+ return `Usage:
1322
+ tiangong-lca process dedup-review --input <file> --out-dir <dir> [options]
1323
+
1324
+ Options:
1325
+ --input <file> Grouped duplicate-candidate JSON input
1326
+ --out-dir <dir> Artifact root to write inputs/outputs
1327
+ --skip-remote Skip optional TianGong remote enrichment and reference scans
1328
+ --json Print compact JSON
1329
+ -h, --help
1330
+
1331
+ Input contract:
1332
+ {
1333
+ "source_label": "duplicate-processes-export",
1334
+ "groups": [
1335
+ {
1336
+ "group_id": 1,
1337
+ "processes": [
1338
+ {
1339
+ "process_id": "proc-1",
1340
+ "version": "01.00.000",
1341
+ "name_en": "Example",
1342
+ "name_zh": "示例",
1343
+ "sheet_exchange_rows": [
1344
+ {
1345
+ "flow_id": "flow-1",
1346
+ "direction": "Input",
1347
+ "mean_amount": "1",
1348
+ "resulting_amount": "1"
1349
+ }
1350
+ ]
1351
+ }
1352
+ ]
1353
+ }
1354
+ ]
1355
+ }
1356
+
1357
+ Outputs written under --out-dir:
1358
+ - inputs/dedup-input.manifest.json
1359
+ - inputs/processes.remote-metadata.json (when remote enrichment succeeds)
1360
+ - outputs/duplicate-groups.json
1361
+ - outputs/delete-plan.json
1362
+ - outputs/current-user-reference-scan.json (when reference scan succeeds)
1363
+ `.trim();
1364
+ }
795
1365
  function renderProcessResumeBuildHelp() {
796
1366
  return `Usage:
797
- tiangong process resume-build [--run-id <id>] [--run-dir <dir>] [options]
1367
+ tiangong-lca process resume-build --run-dir <dir> [options]
798
1368
 
799
1369
  Options:
800
- --run-id <id> Existing process build run id
801
1370
  --run-dir <dir> Existing process build run directory
1371
+ --run-id <id> Optional run id consistency check
802
1372
  --json Print compact JSON
803
1373
  -h, --help
804
1374
  `.trim();
805
1375
  }
806
1376
  function renderProcessPublishBuildHelp() {
807
1377
  return `Usage:
808
- tiangong process publish-build [--run-id <id>] [--run-dir <dir>] [options]
1378
+ tiangong-lca process publish-build --run-dir <dir> [options]
809
1379
 
810
1380
  Options:
811
- --run-id <id> Existing process build run id
812
1381
  --run-dir <dir> Existing process build run directory
1382
+ --run-id <id> Optional run id consistency check
813
1383
  --json Print compact JSON
814
1384
  -h, --help
815
1385
  `.trim();
816
1386
  }
817
1387
  function renderProcessSaveDraftHelp() {
818
1388
  return `Usage:
819
- tiangong process save-draft --input <file> [options]
1389
+ tiangong-lca process save-draft --input <file> [options]
820
1390
 
821
1391
  Options:
822
1392
  --input <file> Process rows JSON/JSONL file or publish-request.json
@@ -831,6 +1401,10 @@ Environment:
831
1401
  TIANGONG_LCA_API_BASE_URL, TIANGONG_LCA_API_KEY, and TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
832
1402
  when --commit executes remote writes
833
1403
 
1404
+ Local gate:
1405
+ canonical process payloads are validated against ProcessSchema before any remote write;
1406
+ schema-invalid rows stay in failures.jsonl instead of being committed
1407
+
834
1408
  Outputs written under --out-dir:
835
1409
  - inputs/normalized-input.json
836
1410
  - outputs/save-draft-rpc/selected-processes.jsonl
@@ -839,39 +1413,145 @@ Outputs written under --out-dir:
839
1413
  - outputs/save-draft-rpc/summary.json
840
1414
  `.trim();
841
1415
  }
1416
+ function renderProcessRequiredFieldsHelp() {
1417
+ return `Usage:
1418
+ tiangong-lca process complete-required-fields --input <file> --out <file> [options]
1419
+
1420
+ Options:
1421
+ --input <file> Process rows JSON/JSONL file
1422
+ --out <file> Output JSONL with required fields completed
1423
+ --out-dir <dir> Optional artifact directory for report and evidence
1424
+ --flows <file> Optional flow rows JSON/JSONL used to infer reference-flow units
1425
+ --default-unit <unit> Unit suffix to use when it cannot be inferred (default: unit)
1426
+ --json Print compact JSON
1427
+ -h, --help
1428
+
1429
+ Annual supply / production volume policy:
1430
+ 1. keep an existing valid annualized annualSupplyOrProductionVolume, for example "3.6 MJ/year";
1431
+ 2. use an explicit value from row-level authoring evidence or evidenceManifest field bindings;
1432
+ 3. otherwise complete from the quantitative reference flow meanAmount/resultingAmount and unit.
1433
+
1434
+ Outputs:
1435
+ - completed rows at --out
1436
+ - outputs/process-required-fields-report.json
1437
+ - outputs/process-required-fields-evidence.jsonl
1438
+ `.trim();
1439
+ }
1440
+ function renderProcessRefreshReferencesHelp() {
1441
+ return `Usage:
1442
+ tiangong-lca process refresh-references --out-dir <dir> [options]
1443
+
1444
+ Options:
1445
+ --out-dir <dir> Artifact root for manifest, progress, blockers, and reports
1446
+ --apply Commit state-aware draft writes after local validation passes
1447
+ --dry-run Refresh references locally only (default)
1448
+ --reuse-manifest Reuse inputs/processes.manifest.json instead of refetching the owner snapshot
1449
+ --limit <n> Process at most n manifest rows
1450
+ --page-size <n> Snapshot page size (default: 500)
1451
+ --concurrency <n> Parallel row workers (default: 1, max: 8)
1452
+ --json Print compact JSON
1453
+ -h, --help
1454
+
1455
+ Required env:
1456
+ TIANGONG_LCA_API_BASE_URL
1457
+ TIANGONG_LCA_API_KEY
1458
+ TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
1459
+
1460
+ Guardrails:
1461
+ - refresh only the current authenticated user's process snapshot
1462
+ - skip rows with state_code >= 20 instead of forcing an unsupported write path
1463
+ - block remote writes when ProcessSchema validation fails or references stay unresolved
1464
+ - never requires raw SUPABASE_EMAIL / SUPABASE_PASSWORD in the skill layer
1465
+
1466
+ Outputs written under --out-dir:
1467
+ - inputs/processes.manifest.json
1468
+ - outputs/progress.jsonl
1469
+ - outputs/errors.jsonl
1470
+ - outputs/validation-blockers.jsonl
1471
+ - outputs/summary.json
1472
+ - reports/process-refresh-references.md
1473
+ `.trim();
1474
+ }
1475
+ function renderProcessVerifyRowsHelp() {
1476
+ return `Usage:
1477
+ tiangong-lca process verify-rows --rows-file <file> --out-dir <dir> [options]
1478
+
1479
+ Options:
1480
+ --rows-file <file> Raw process rows JSON/JSONL file; full process list reports with rows[] are also accepted
1481
+ --out-dir <dir> Output directory for summary and verification JSONL artifacts
1482
+ --json Print compact JSON
1483
+ -h, --help
1484
+
1485
+ Outputs written under --out-dir:
1486
+ - outputs/summary.json
1487
+ - outputs/verification.jsonl
1488
+ `.trim();
1489
+ }
842
1490
  function renderProcessBatchBuildHelp() {
843
1491
  return `Usage:
844
- tiangong process batch-build --input <file> [options]
1492
+ tiangong-lca process batch-build --input <file> [options]
845
1493
 
846
1494
  Options:
847
1495
  --input <file> JSON batch manifest file
848
- --out-dir <dir> Override the batch artifact output directory
1496
+ --out-dir <dir> Explicit batch root; otherwise request.out_dir is required
849
1497
  --json Print compact JSON
850
1498
  -h, --help
1499
+
1500
+ This command applies no implicit repo-local ./artifacts fallback.
851
1501
  `.trim();
852
1502
  }
853
1503
  function renderProcessHelp() {
854
1504
  return `Usage:
855
- tiangong process <subcommand> [options]
1505
+ tiangong-lca process <subcommand> [options]
856
1506
 
857
1507
  Implemented Subcommands:
858
1508
  get Load one process dataset by identifier through direct Supabase access
859
1509
  list List visible process rows through direct Supabase access
1510
+ identity-preflight Compare one target process against local candidates before generation
1511
+ build-plan Validate or materialize a process build plan into gate artifacts
1512
+ scope-statistics Count repeatable coverage statistics from visible or owner-filtered process snapshots
1513
+ dedup-review Review grouped duplicate process candidates and emit keep/delete evidence
860
1514
  auto-build Prepare a local process-from-flow run scaffold and artifact workspace
861
1515
  resume-build Prepare a local resume handoff from one existing process build run
862
1516
  publish-build Prepare publish handoff artifacts from one existing process build run
1517
+ complete-required-fields Complete deterministic required authoring fields in process rows
863
1518
  save-draft Save canonical process datasets through the state-aware draft-maintenance path
864
1519
  batch-build Run multiple process auto-build requests through one batch-oriented CLI surface
1520
+ refresh-references Refresh current-user process references to the latest reachable dataset versions
1521
+ verify-rows Re-validate fetched process rows and required naming fields locally
865
1522
 
866
1523
  Examples:
867
- tiangong process --help
868
- tiangong process get --id <process-id>
869
- tiangong process list --state-code 100 --limit 20 --help
870
- tiangong process auto-build --help
871
- tiangong process resume-build --run-id <id> --help
872
- tiangong process publish-build --run-id <id> --help
873
- tiangong process save-draft --input ./patched-processes.jsonl --help
874
- tiangong process batch-build --input ./batch-request.json --help
1524
+ tiangong-lca process --help
1525
+ tiangong-lca process get --id <process-id>
1526
+ tiangong-lca process list --state-code 100 --limit 20 --help
1527
+ tiangong-lca process identity-preflight --input ./process-preflight.json --help
1528
+ tiangong-lca process build-plan validate --input ./process-build-plan.json --help
1529
+ tiangong-lca process scope-statistics --out-dir ./process-scope --state-code 0 --state-code 100 --help
1530
+ tiangong-lca process dedup-review --input ./duplicate-groups.json --out-dir ./process-dedup --help
1531
+ tiangong-lca process auto-build --help
1532
+ tiangong-lca process resume-build --run-dir /abs/path/to/process-run --help
1533
+ tiangong-lca process publish-build --run-dir /abs/path/to/process-run --help
1534
+ tiangong-lca process complete-required-fields --input ./processes.jsonl --out ./processes.completed.jsonl --help
1535
+ tiangong-lca process save-draft --input ./patched-processes.jsonl --help
1536
+ tiangong-lca process batch-build --input ./batch-request.json --help
1537
+ tiangong-lca process refresh-references --out-dir ./process-refresh --help
1538
+ tiangong-lca process verify-rows --rows-file ./process-list-report.json --out-dir ./process-verify --help
1539
+ `.trim();
1540
+ }
1541
+ function renderProcessBuildPlanHelp() {
1542
+ return `Usage:
1543
+ tiangong-lca process build-plan <validate|materialize> --input <file> [options]
1544
+
1545
+ Options:
1546
+ --input <file> JSON process build plan; materialize writes a canonical processDataSet
1547
+ --out-dir <dir> Optional artifact directory for gate outputs
1548
+ --report-only Print blocker reports with exit code 0
1549
+ --json Print compact JSON
1550
+ -h, --help
1551
+
1552
+ Outputs written under --out-dir:
1553
+ - outputs/build-plan-gate-report.json
1554
+ - outputs/materialized-process.json
875
1555
  `.trim();
876
1556
  }
877
1557
  function renderDoctorText(report) {
@@ -1079,7 +1759,7 @@ function parseValidationFlags(args) {
1079
1759
  reportFile: typeof values['report-file'] === 'string' ? values['report-file'] : null,
1080
1760
  };
1081
1761
  }
1082
- function parseFlowRemediateFlags(args) {
1762
+ function parseDatasetValidateFlags(args) {
1083
1763
  let values;
1084
1764
  try {
1085
1765
  ({ values } = parseArgs({
@@ -1089,7 +1769,8 @@ function parseFlowRemediateFlags(args) {
1089
1769
  options: {
1090
1770
  help: { type: 'boolean', short: 'h' },
1091
1771
  json: { type: 'boolean' },
1092
- 'input-file': { type: 'string' },
1772
+ input: { type: 'string' },
1773
+ type: { type: 'string' },
1093
1774
  'out-dir': { type: 'string' },
1094
1775
  },
1095
1776
  }));
@@ -1103,8 +1784,535 @@ function parseFlowRemediateFlags(args) {
1103
1784
  return {
1104
1785
  help: Boolean(values.help),
1105
1786
  json: Boolean(values.json),
1106
- inputFile: typeof values['input-file'] === 'string' ? values['input-file'] : '',
1107
- outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
1787
+ inputPath: typeof values.input === 'string' ? values.input : '',
1788
+ type: typeof values.type === 'string' ? values.type : undefined,
1789
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1790
+ };
1791
+ }
1792
+ function parseDatasetContractFlags(args) {
1793
+ let values;
1794
+ try {
1795
+ ({ values } = parseArgs({
1796
+ args,
1797
+ allowPositionals: false,
1798
+ strict: true,
1799
+ options: {
1800
+ help: { type: 'boolean', short: 'h' },
1801
+ json: { type: 'boolean' },
1802
+ type: { type: 'string' },
1803
+ include: { type: 'string', multiple: true },
1804
+ profile: { type: 'string' },
1805
+ 'out-dir': { type: 'string' },
1806
+ },
1807
+ }));
1808
+ }
1809
+ catch (error) {
1810
+ throw new CliError(String(error), {
1811
+ code: 'INVALID_ARGS',
1812
+ exitCode: 2,
1813
+ });
1814
+ }
1815
+ return {
1816
+ help: Boolean(values.help),
1817
+ json: Boolean(values.json),
1818
+ type: typeof values.type === 'string' ? values.type : undefined,
1819
+ include: Array.isArray(values.include)
1820
+ ? values.include.filter((value) => typeof value === 'string')
1821
+ : [],
1822
+ profile: typeof values.profile === 'string' ? values.profile : undefined,
1823
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1824
+ };
1825
+ }
1826
+ function parseDatasetImportLcaConvertFlags(args) {
1827
+ let values;
1828
+ try {
1829
+ ({ values } = parseArgs({
1830
+ args,
1831
+ allowPositionals: false,
1832
+ strict: true,
1833
+ options: {
1834
+ help: { type: 'boolean', short: 'h' },
1835
+ json: { type: 'boolean' },
1836
+ input: { type: 'string' },
1837
+ 'output-dir': { type: 'string' },
1838
+ 'from-format': { type: 'string' },
1839
+ target: { type: 'string' },
1840
+ report: { type: 'string' },
1841
+ 'mapping-dir': { type: 'string' },
1842
+ language: { type: 'string' },
1843
+ 'validation-jobs': { type: 'string' },
1844
+ 'detect-only': { type: 'boolean' },
1845
+ 'fail-on-warning': { type: 'boolean' },
1846
+ python: { type: 'string' },
1847
+ 'tidas-tools-dir': { type: 'string' },
1848
+ },
1849
+ }));
1850
+ }
1851
+ catch (error) {
1852
+ throw new CliError(String(error), {
1853
+ code: 'INVALID_ARGS',
1854
+ exitCode: 2,
1855
+ });
1856
+ }
1857
+ const validationJobs = typeof values['validation-jobs'] === 'string' ? Number(values['validation-jobs']) : undefined;
1858
+ if (validationJobs !== undefined && (!Number.isInteger(validationJobs) || validationJobs < 0)) {
1859
+ throw new CliError('--validation-jobs must be a non-negative integer.', {
1860
+ code: 'DATASET_IMPORT_LCA_VALIDATION_JOBS_INVALID',
1861
+ exitCode: 2,
1862
+ });
1863
+ }
1864
+ return {
1865
+ help: Boolean(values.help),
1866
+ json: Boolean(values.json),
1867
+ inputPath: typeof values.input === 'string' ? values.input : '',
1868
+ outputDir: typeof values['output-dir'] === 'string' ? values['output-dir'] : '',
1869
+ fromFormat: typeof values['from-format'] === 'string' ? values['from-format'] : undefined,
1870
+ target: typeof values.target === 'string' ? values.target : undefined,
1871
+ reportPath: typeof values.report === 'string' ? values.report : undefined,
1872
+ mappingDir: typeof values['mapping-dir'] === 'string' ? values['mapping-dir'] : undefined,
1873
+ language: typeof values.language === 'string' ? values.language : undefined,
1874
+ validationJobs,
1875
+ detectOnly: Boolean(values['detect-only']),
1876
+ failOnWarning: Boolean(values['fail-on-warning']),
1877
+ pythonBin: typeof values.python === 'string' ? values.python : undefined,
1878
+ tidasToolsDir: typeof values['tidas-tools-dir'] === 'string' ? values['tidas-tools-dir'] : undefined,
1879
+ };
1880
+ }
1881
+ function parseDatasetAuthorFlags(args) {
1882
+ let values;
1883
+ try {
1884
+ ({ values } = parseArgs({
1885
+ args,
1886
+ allowPositionals: false,
1887
+ strict: true,
1888
+ options: {
1889
+ help: { type: 'boolean', short: 'h' },
1890
+ json: { type: 'boolean' },
1891
+ input: { type: 'string' },
1892
+ 'target-types': { type: 'string', multiple: true },
1893
+ 'out-dir': { type: 'string' },
1894
+ prompt: { type: 'string' },
1895
+ provider: { type: 'string' },
1896
+ model: { type: 'string' },
1897
+ 'timeout-ms': { type: 'string' },
1898
+ },
1899
+ }));
1900
+ }
1901
+ catch (error) {
1902
+ throw new CliError(String(error), {
1903
+ code: 'INVALID_ARGS',
1904
+ exitCode: 2,
1905
+ });
1906
+ }
1907
+ const timeoutMs = typeof values['timeout-ms'] === 'string' ? Number(values['timeout-ms']) : undefined;
1908
+ if (timeoutMs !== undefined && (!Number.isInteger(timeoutMs) || timeoutMs <= 0)) {
1909
+ throw new CliError('--timeout-ms must be a positive integer.', {
1910
+ code: 'DATASET_AUTHOR_TIMEOUT_INVALID',
1911
+ exitCode: 2,
1912
+ });
1913
+ }
1914
+ return {
1915
+ help: Boolean(values.help),
1916
+ json: Boolean(values.json),
1917
+ inputPath: typeof values.input === 'string' ? values.input : '',
1918
+ targetTypes: Array.isArray(values['target-types'])
1919
+ ? values['target-types'].filter((value) => typeof value === 'string')
1920
+ : [],
1921
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1922
+ prompt: typeof values.prompt === 'string' ? values.prompt : undefined,
1923
+ provider: typeof values.provider === 'string' ? values.provider : undefined,
1924
+ model: typeof values.model === 'string' ? values.model : undefined,
1925
+ timeoutMs,
1926
+ };
1927
+ }
1928
+ function parseDatasetRemoteVerifyFlags(args) {
1929
+ let values;
1930
+ try {
1931
+ ({ values } = parseArgs({
1932
+ args,
1933
+ allowPositionals: false,
1934
+ strict: true,
1935
+ options: {
1936
+ help: { type: 'boolean', short: 'h' },
1937
+ json: { type: 'boolean' },
1938
+ input: { type: 'string' },
1939
+ 'out-dir': { type: 'string' },
1940
+ 'root-policy': { type: 'string' },
1941
+ },
1942
+ }));
1943
+ }
1944
+ catch (error) {
1945
+ throw new CliError(String(error), {
1946
+ code: 'INVALID_ARGS',
1947
+ exitCode: 2,
1948
+ });
1949
+ }
1950
+ const rawRootPolicy = typeof values['root-policy'] === 'string' ? values['root-policy'] : 'existing';
1951
+ if (!['existing', 'candidate'].includes(rawRootPolicy)) {
1952
+ throw new CliError("--root-policy must be 'existing' or 'candidate'.", {
1953
+ code: 'DATASET_REMOTE_VERIFY_ROOT_POLICY_INVALID',
1954
+ exitCode: 2,
1955
+ });
1956
+ }
1957
+ const rootPolicy = rawRootPolicy;
1958
+ return {
1959
+ help: Boolean(values.help),
1960
+ json: Boolean(values.json),
1961
+ inputPath: typeof values.input === 'string' ? values.input : '',
1962
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
1963
+ rootPolicy,
1964
+ };
1965
+ }
1966
+ function parseDatasetBilingualExtractFlags(args) {
1967
+ let values;
1968
+ try {
1969
+ ({ values } = parseArgs({
1970
+ args,
1971
+ allowPositionals: false,
1972
+ strict: true,
1973
+ options: {
1974
+ help: { type: 'boolean', short: 'h' },
1975
+ json: { type: 'boolean' },
1976
+ input: { type: 'string' },
1977
+ type: { type: 'string' },
1978
+ 'source-lang': { type: 'string' },
1979
+ 'target-lang': { type: 'string' },
1980
+ 'out-dir': { type: 'string' },
1981
+ },
1982
+ }));
1983
+ }
1984
+ catch (error) {
1985
+ throw new CliError(String(error), {
1986
+ code: 'INVALID_ARGS',
1987
+ exitCode: 2,
1988
+ });
1989
+ }
1990
+ return {
1991
+ help: Boolean(values.help),
1992
+ json: Boolean(values.json),
1993
+ inputPath: typeof values.input === 'string' ? values.input : '',
1994
+ type: typeof values.type === 'string' ? values.type : undefined,
1995
+ sourceLang: typeof values['source-lang'] === 'string' ? values['source-lang'] : null,
1996
+ targetLang: typeof values['target-lang'] === 'string' ? values['target-lang'] : null,
1997
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
1998
+ };
1999
+ }
2000
+ function parseDatasetBilingualApplyFlags(args) {
2001
+ let values;
2002
+ try {
2003
+ ({ values } = parseArgs({
2004
+ args,
2005
+ allowPositionals: false,
2006
+ strict: true,
2007
+ options: {
2008
+ help: { type: 'boolean', short: 'h' },
2009
+ json: { type: 'boolean' },
2010
+ input: { type: 'string' },
2011
+ translations: { type: 'string' },
2012
+ out: { type: 'string' },
2013
+ 'target-lang': { type: 'string' },
2014
+ 'out-dir': { type: 'string' },
2015
+ },
2016
+ }));
2017
+ }
2018
+ catch (error) {
2019
+ throw new CliError(String(error), {
2020
+ code: 'INVALID_ARGS',
2021
+ exitCode: 2,
2022
+ });
2023
+ }
2024
+ return {
2025
+ help: Boolean(values.help),
2026
+ json: Boolean(values.json),
2027
+ inputPath: typeof values.input === 'string' ? values.input : '',
2028
+ translationsPath: typeof values.translations === 'string' ? values.translations : '',
2029
+ outPath: typeof values.out === 'string' ? values.out : '',
2030
+ targetLang: typeof values['target-lang'] === 'string' ? values['target-lang'] : null,
2031
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2032
+ };
2033
+ }
2034
+ function parseDatasetBilingualValidateFlags(args) {
2035
+ let values;
2036
+ try {
2037
+ ({ values } = parseArgs({
2038
+ args,
2039
+ allowPositionals: false,
2040
+ strict: true,
2041
+ options: {
2042
+ help: { type: 'boolean', short: 'h' },
2043
+ json: { type: 'boolean' },
2044
+ input: { type: 'string' },
2045
+ type: { type: 'string' },
2046
+ 'out-dir': { type: 'string' },
2047
+ },
2048
+ }));
2049
+ }
2050
+ catch (error) {
2051
+ throw new CliError(String(error), {
2052
+ code: 'INVALID_ARGS',
2053
+ exitCode: 2,
2054
+ });
2055
+ }
2056
+ return {
2057
+ help: Boolean(values.help),
2058
+ json: Boolean(values.json),
2059
+ inputPath: typeof values.input === 'string' ? values.input : '',
2060
+ type: typeof values.type === 'string' ? values.type : undefined,
2061
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2062
+ };
2063
+ }
2064
+ function parseDatasetEvidenceSearchFlags(args) {
2065
+ let values;
2066
+ try {
2067
+ ({ values } = parseArgs({
2068
+ args,
2069
+ allowPositionals: false,
2070
+ strict: true,
2071
+ options: {
2072
+ help: { type: 'boolean', short: 'h' },
2073
+ json: { type: 'boolean' },
2074
+ query: { type: 'string' },
2075
+ input: { type: 'string' },
2076
+ results: { type: 'string' },
2077
+ 'provider-url': { type: 'string' },
2078
+ 'provider-key': { type: 'string' },
2079
+ profile: { type: 'string' },
2080
+ 'out-dir': { type: 'string' },
2081
+ 'max-queries': { type: 'string' },
2082
+ 'max-results-per-query': { type: 'string' },
2083
+ 'timeout-ms': { type: 'string' },
2084
+ },
2085
+ }));
2086
+ }
2087
+ catch (error) {
2088
+ throw new CliError(String(error), {
2089
+ code: 'INVALID_ARGS',
2090
+ exitCode: 2,
2091
+ });
2092
+ }
2093
+ const readNumber = (value) => {
2094
+ if (typeof value !== 'string') {
2095
+ return null;
2096
+ }
2097
+ const parsed = Number(value);
2098
+ return Number.isFinite(parsed) ? parsed : Number.NaN;
2099
+ };
2100
+ return {
2101
+ help: Boolean(values.help),
2102
+ json: Boolean(values.json),
2103
+ query: typeof values.query === 'string' ? values.query : null,
2104
+ inputPath: typeof values.input === 'string' ? values.input : null,
2105
+ resultsPath: typeof values.results === 'string' ? values.results : null,
2106
+ providerUrl: typeof values['provider-url'] === 'string' ? values['provider-url'] : null,
2107
+ providerKey: typeof values['provider-key'] === 'string' ? values['provider-key'] : null,
2108
+ profile: typeof values.profile === 'string' ? values.profile : null,
2109
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2110
+ maxQueries: readNumber(values['max-queries']),
2111
+ maxResultsPerQuery: readNumber(values['max-results-per-query']),
2112
+ timeoutMs: readNumber(values['timeout-ms']),
2113
+ };
2114
+ }
2115
+ function parseDatasetReferencesRewriteFlags(args) {
2116
+ let values;
2117
+ try {
2118
+ ({ values } = parseArgs({
2119
+ args,
2120
+ allowPositionals: false,
2121
+ strict: true,
2122
+ options: {
2123
+ help: { type: 'boolean', short: 'h' },
2124
+ json: { type: 'boolean' },
2125
+ input: { type: 'string' },
2126
+ from: { type: 'string' },
2127
+ to: { type: 'string' },
2128
+ type: { type: 'string', multiple: true },
2129
+ types: { type: 'string', multiple: true },
2130
+ scope: { type: 'string' },
2131
+ 'out-dir': { type: 'string' },
2132
+ commit: { type: 'boolean' },
2133
+ 'dry-run': { type: 'boolean' },
2134
+ },
2135
+ }));
2136
+ }
2137
+ catch (error) {
2138
+ throw new CliError(String(error), {
2139
+ code: 'INVALID_ARGS',
2140
+ exitCode: 2,
2141
+ });
2142
+ }
2143
+ if (values.commit && values['dry-run']) {
2144
+ throw new CliError('Cannot pass both --commit and --dry-run.', {
2145
+ code: 'DATASET_REFERENCES_REWRITE_MODE_CONFLICT',
2146
+ exitCode: 2,
2147
+ });
2148
+ }
2149
+ return {
2150
+ help: Boolean(values.help),
2151
+ json: Boolean(values.json),
2152
+ inputPath: typeof values.input === 'string' ? values.input : '',
2153
+ from: typeof values.from === 'string' ? values.from : '',
2154
+ to: typeof values.to === 'string' ? values.to : '',
2155
+ types: [
2156
+ ...(Array.isArray(values.type)
2157
+ ? values.type.filter((value) => typeof value === 'string')
2158
+ : []),
2159
+ ...(Array.isArray(values.types)
2160
+ ? values.types.filter((value) => typeof value === 'string')
2161
+ : []),
2162
+ ],
2163
+ scope: typeof values.scope === 'string' ? values.scope : null,
2164
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
2165
+ commit: Boolean(values.commit),
2166
+ };
2167
+ }
2168
+ function parseDatasetReferencesRefreshRemoteFlags(args) {
2169
+ let values;
2170
+ try {
2171
+ ({ values } = parseArgs({
2172
+ args,
2173
+ allowPositionals: false,
2174
+ strict: true,
2175
+ options: {
2176
+ help: { type: 'boolean', short: 'h' },
2177
+ json: { type: 'boolean' },
2178
+ input: { type: 'string' },
2179
+ out: { type: 'string' },
2180
+ 'out-dir': { type: 'string' },
2181
+ 'root-policy': { type: 'string' },
2182
+ },
2183
+ }));
2184
+ }
2185
+ catch (error) {
2186
+ throw new CliError(String(error), {
2187
+ code: 'INVALID_ARGS',
2188
+ exitCode: 2,
2189
+ });
2190
+ }
2191
+ const rawRootPolicy = typeof values['root-policy'] === 'string' ? values['root-policy'] : 'existing';
2192
+ if (!['existing', 'candidate'].includes(rawRootPolicy)) {
2193
+ throw new CliError("--root-policy must be 'existing' or 'candidate'.", {
2194
+ code: 'DATASET_REMOTE_REFRESH_ROOT_POLICY_INVALID',
2195
+ exitCode: 2,
2196
+ });
2197
+ }
2198
+ const rootPolicy = rawRootPolicy;
2199
+ return {
2200
+ help: Boolean(values.help),
2201
+ json: Boolean(values.json),
2202
+ inputPath: typeof values.input === 'string' ? values.input : '',
2203
+ outPath: typeof values.out === 'string' ? values.out : '',
2204
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
2205
+ rootPolicy,
2206
+ };
2207
+ }
2208
+ function parseIdentityPreflightFlags(args) {
2209
+ let values;
2210
+ try {
2211
+ ({ values } = parseArgs({
2212
+ args,
2213
+ allowPositionals: false,
2214
+ strict: true,
2215
+ options: {
2216
+ help: { type: 'boolean', short: 'h' },
2217
+ json: { type: 'boolean' },
2218
+ input: { type: 'string' },
2219
+ 'candidate-input': { type: 'string', multiple: true },
2220
+ 'remote-candidates': { type: 'boolean' },
2221
+ 'remote-query': { type: 'string' },
2222
+ 'remote-limit': { type: 'string' },
2223
+ 'out-dir': { type: 'string' },
2224
+ },
2225
+ }));
2226
+ }
2227
+ catch (error) {
2228
+ throw new CliError(String(error), {
2229
+ code: 'INVALID_ARGS',
2230
+ exitCode: 2,
2231
+ });
2232
+ }
2233
+ const candidateInputValue = values['candidate-input'];
2234
+ const parseRemoteLimit = (value) => {
2235
+ if (typeof value !== 'string') {
2236
+ return null;
2237
+ }
2238
+ const parsed = Number.parseInt(value, 10);
2239
+ if (!Number.isInteger(parsed) || parsed <= 0) {
2240
+ throw new CliError('Expected --remote-limit to be a positive integer.', {
2241
+ code: 'INVALID_IDENTITY_PREFLIGHT_REMOTE_LIMIT',
2242
+ exitCode: 2,
2243
+ });
2244
+ }
2245
+ return parsed;
2246
+ };
2247
+ return {
2248
+ help: Boolean(values.help),
2249
+ json: Boolean(values.json),
2250
+ inputPath: typeof values.input === 'string' ? values.input : '',
2251
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2252
+ candidateInputPaths: Array.isArray(candidateInputValue)
2253
+ ? candidateInputValue.filter((entry) => typeof entry === 'string')
2254
+ : [],
2255
+ remoteCandidateSearch: Boolean(values['remote-candidates']),
2256
+ remoteQuery: typeof values['remote-query'] === 'string' ? values['remote-query'] : null,
2257
+ remoteLimit: parseRemoteLimit(values['remote-limit']),
2258
+ };
2259
+ }
2260
+ function parseBuildPlanFlags(args) {
2261
+ let values;
2262
+ try {
2263
+ ({ values } = parseArgs({
2264
+ args,
2265
+ allowPositionals: false,
2266
+ strict: true,
2267
+ options: {
2268
+ help: { type: 'boolean', short: 'h' },
2269
+ json: { type: 'boolean' },
2270
+ input: { type: 'string' },
2271
+ 'out-dir': { type: 'string' },
2272
+ 'report-only': { type: 'boolean' },
2273
+ },
2274
+ }));
2275
+ }
2276
+ catch (error) {
2277
+ throw new CliError(String(error), {
2278
+ code: 'INVALID_ARGS',
2279
+ exitCode: 2,
2280
+ });
2281
+ }
2282
+ return {
2283
+ help: Boolean(values.help),
2284
+ json: Boolean(values.json),
2285
+ inputPath: typeof values.input === 'string' ? values.input : '',
2286
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2287
+ reportOnly: Boolean(values['report-only']),
2288
+ };
2289
+ }
2290
+ function parseFlowRemediateFlags(args) {
2291
+ let values;
2292
+ try {
2293
+ ({ values } = parseArgs({
2294
+ args,
2295
+ allowPositionals: false,
2296
+ strict: true,
2297
+ options: {
2298
+ help: { type: 'boolean', short: 'h' },
2299
+ json: { type: 'boolean' },
2300
+ 'input-file': { type: 'string' },
2301
+ 'out-dir': { type: 'string' },
2302
+ },
2303
+ }));
2304
+ }
2305
+ catch (error) {
2306
+ throw new CliError(String(error), {
2307
+ code: 'INVALID_ARGS',
2308
+ exitCode: 2,
2309
+ });
2310
+ }
2311
+ return {
2312
+ help: Boolean(values.help),
2313
+ json: Boolean(values.json),
2314
+ inputFile: typeof values['input-file'] === 'string' ? values['input-file'] : '',
2315
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
1108
2316
  };
1109
2317
  }
1110
2318
  function parseFlowPublishVersionFlags(args) {
@@ -1968,11 +3176,74 @@ function parseLifecyclemodelValidateBuildFlags(args) {
1968
3176
  return {
1969
3177
  help: Boolean(values.help),
1970
3178
  json: Boolean(values.json),
1971
- runDir: typeof values['run-dir'] === 'string' ? values['run-dir'] : '',
1972
- engine: typeof values.engine === 'string' ? values.engine : undefined,
3179
+ runDir: typeof values['run-dir'] === 'string' ? values['run-dir'] : '',
3180
+ engine: typeof values.engine === 'string' ? values.engine : undefined,
3181
+ };
3182
+ }
3183
+ function parseLifecyclemodelPublishBuildFlags(args) {
3184
+ let values;
3185
+ try {
3186
+ ({ values } = parseArgs({
3187
+ args,
3188
+ allowPositionals: false,
3189
+ strict: true,
3190
+ options: {
3191
+ help: { type: 'boolean', short: 'h' },
3192
+ json: { type: 'boolean' },
3193
+ 'run-dir': { type: 'string' },
3194
+ },
3195
+ }));
3196
+ }
3197
+ catch (error) {
3198
+ throw new CliError(String(error), {
3199
+ code: 'INVALID_ARGS',
3200
+ exitCode: 2,
3201
+ });
3202
+ }
3203
+ return {
3204
+ help: Boolean(values.help),
3205
+ json: Boolean(values.json),
3206
+ runDir: typeof values['run-dir'] === 'string' ? values['run-dir'] : '',
3207
+ };
3208
+ }
3209
+ function parseLifecyclemodelSaveDraftFlags(args) {
3210
+ let values;
3211
+ try {
3212
+ ({ values } = parseArgs({
3213
+ args,
3214
+ allowPositionals: false,
3215
+ strict: true,
3216
+ options: {
3217
+ help: { type: 'boolean', short: 'h' },
3218
+ json: { type: 'boolean' },
3219
+ input: { type: 'string' },
3220
+ 'out-dir': { type: 'string' },
3221
+ commit: { type: 'boolean' },
3222
+ 'dry-run': { type: 'boolean' },
3223
+ },
3224
+ }));
3225
+ }
3226
+ catch (error) {
3227
+ throw new CliError(String(error), {
3228
+ code: 'INVALID_ARGS',
3229
+ exitCode: 2,
3230
+ });
3231
+ }
3232
+ if (values.commit && values['dry-run']) {
3233
+ throw new CliError('Cannot pass both --commit and --dry-run.', {
3234
+ code: 'INVALID_LIFECYCLEMODEL_SAVE_DRAFT_MODE',
3235
+ exitCode: 2,
3236
+ });
3237
+ }
3238
+ return {
3239
+ help: Boolean(values.help),
3240
+ json: Boolean(values.json),
3241
+ inputPath: typeof values.input === 'string' ? values.input : '',
3242
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
3243
+ commit: Boolean(values.commit),
1973
3244
  };
1974
3245
  }
1975
- function parseLifecyclemodelPublishBuildFlags(args) {
3246
+ function parseLifecyclemodelGraphFlags(args) {
1976
3247
  let values;
1977
3248
  try {
1978
3249
  ({ values } = parseArgs({
@@ -1982,7 +3253,10 @@ function parseLifecyclemodelPublishBuildFlags(args) {
1982
3253
  options: {
1983
3254
  help: { type: 'boolean', short: 'h' },
1984
3255
  json: { type: 'boolean' },
1985
- 'run-dir': { type: 'string' },
3256
+ input: { type: 'string' },
3257
+ 'out-dir': { type: 'string' },
3258
+ format: { type: 'string' },
3259
+ 'check-connections': { type: 'boolean' },
1986
3260
  },
1987
3261
  }));
1988
3262
  }
@@ -1995,7 +3269,10 @@ function parseLifecyclemodelPublishBuildFlags(args) {
1995
3269
  return {
1996
3270
  help: Boolean(values.help),
1997
3271
  json: Boolean(values.json),
1998
- runDir: typeof values['run-dir'] === 'string' ? values['run-dir'] : '',
3272
+ inputPath: typeof values.input === 'string' ? values.input : '',
3273
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
3274
+ format: typeof values.format === 'string' ? values.format : undefined,
3275
+ checkConnections: Boolean(values['check-connections']),
1999
3276
  };
2000
3277
  }
2001
3278
  function parseLifecyclemodelBuildFlags(args) {
@@ -2214,6 +3491,111 @@ function parseProcessListFlags(args) {
2214
3491
  order: typeof values.order === 'string' ? values.order : null,
2215
3492
  };
2216
3493
  }
3494
+ function parseProcessScopeStatisticsFlags(args) {
3495
+ let values;
3496
+ try {
3497
+ ({ values } = parseArgs({
3498
+ args,
3499
+ allowPositionals: false,
3500
+ strict: true,
3501
+ options: {
3502
+ help: { type: 'boolean', short: 'h' },
3503
+ json: { type: 'boolean' },
3504
+ 'out-dir': { type: 'string' },
3505
+ scope: { type: 'string' },
3506
+ 'state-code': { type: 'string', multiple: true },
3507
+ 'state-codes': { type: 'string' },
3508
+ 'page-size': { type: 'string' },
3509
+ 'reuse-snapshot': { type: 'boolean' },
3510
+ },
3511
+ }));
3512
+ }
3513
+ catch (error) {
3514
+ throw new CliError(String(error), {
3515
+ code: 'INVALID_ARGS',
3516
+ exitCode: 2,
3517
+ });
3518
+ }
3519
+ const parseStateCode = (value) => {
3520
+ const parsed = Number.parseInt(value, 10);
3521
+ if (!Number.isInteger(parsed) || parsed < 0) {
3522
+ throw new CliError('Expected --state-code to be a non-negative integer.', {
3523
+ code: 'INVALID_PROCESS_SCOPE_STATE_CODE',
3524
+ exitCode: 2,
3525
+ });
3526
+ }
3527
+ return parsed;
3528
+ };
3529
+ const stateCodes = [
3530
+ ...(Array.isArray(values['state-code'])
3531
+ ? values['state-code'].map((value) => parseStateCode(String(value)))
3532
+ : []),
3533
+ ...(typeof values['state-codes'] === 'string' ? values['state-codes'].split(',') : [])
3534
+ .map((value) => value.trim())
3535
+ .filter(Boolean)
3536
+ .map((value) => parseStateCode(value)),
3537
+ ];
3538
+ let pageSize = null;
3539
+ if (typeof values['page-size'] === 'string') {
3540
+ const parsed = Number.parseInt(values['page-size'], 10);
3541
+ if (!Number.isInteger(parsed) || parsed <= 0) {
3542
+ throw new CliError('Expected --page-size to be a positive integer.', {
3543
+ code: 'INVALID_PROCESS_SCOPE_PAGE_SIZE',
3544
+ exitCode: 2,
3545
+ });
3546
+ }
3547
+ pageSize = parsed;
3548
+ }
3549
+ let scope;
3550
+ if (typeof values.scope === 'string') {
3551
+ if (values.scope !== 'visible' && values.scope !== 'current-user') {
3552
+ throw new CliError("Expected --scope to be either 'visible' or 'current-user'.", {
3553
+ code: 'INVALID_PROCESS_SCOPE_SCOPE',
3554
+ exitCode: 2,
3555
+ });
3556
+ }
3557
+ scope = values.scope;
3558
+ }
3559
+ return {
3560
+ help: Boolean(values.help),
3561
+ json: Boolean(values.json),
3562
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
3563
+ scope,
3564
+ stateCodes,
3565
+ pageSize,
3566
+ reuseSnapshot: Boolean(values['reuse-snapshot']),
3567
+ };
3568
+ }
3569
+ function parseProcessDedupReviewFlags(args) {
3570
+ let values;
3571
+ try {
3572
+ ({ values } = parseArgs({
3573
+ args,
3574
+ allowPositionals: false,
3575
+ strict: true,
3576
+ options: {
3577
+ help: { type: 'boolean', short: 'h' },
3578
+ json: { type: 'boolean' },
3579
+ input: { type: 'string' },
3580
+ 'out-dir': { type: 'string' },
3581
+ 'skip-remote': { type: 'boolean' },
3582
+ },
3583
+ }));
3584
+ }
3585
+ catch (error) {
3586
+ throw new CliError(String(error), {
3587
+ code: 'INVALID_ARGS',
3588
+ exitCode: 2,
3589
+ });
3590
+ }
3591
+ return {
3592
+ help: Boolean(values.help),
3593
+ json: Boolean(values.json),
3594
+ inputPath: typeof values.input === 'string' ? values.input : '',
3595
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
3596
+ skipRemote: Boolean(values['skip-remote']),
3597
+ };
3598
+ }
2217
3599
  function parseProcessResumeBuildFlags(args) {
2218
3600
  let values;
2219
3601
  try {
@@ -2307,6 +3689,124 @@ function parseProcessSaveDraftFlags(args) {
2307
3689
  commit: Boolean(values.commit),
2308
3690
  };
2309
3691
  }
3692
+ function parseProcessRequiredFieldsFlags(args) {
3693
+ let values;
3694
+ try {
3695
+ ({ values } = parseArgs({
3696
+ args,
3697
+ allowPositionals: false,
3698
+ strict: true,
3699
+ options: {
3700
+ help: { type: 'boolean', short: 'h' },
3701
+ json: { type: 'boolean' },
3702
+ input: { type: 'string' },
3703
+ out: { type: 'string' },
3704
+ 'out-dir': { type: 'string' },
3705
+ flows: { type: 'string' },
3706
+ 'default-unit': { type: 'string' },
3707
+ },
3708
+ }));
3709
+ }
3710
+ catch (error) {
3711
+ throw new CliError(String(error), {
3712
+ code: 'INVALID_ARGS',
3713
+ exitCode: 2,
3714
+ });
3715
+ }
3716
+ return {
3717
+ help: Boolean(values.help),
3718
+ json: Boolean(values.json),
3719
+ inputPath: typeof values.input === 'string' ? values.input : '',
3720
+ outPath: typeof values.out === 'string' ? values.out : '',
3721
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
3722
+ flowInputPath: typeof values.flows === 'string' ? values.flows : null,
3723
+ defaultUnit: typeof values['default-unit'] === 'string' ? values['default-unit'] : null,
3724
+ };
3725
+ }
3726
+ function parseProcessRefreshReferencesFlags(args) {
3727
+ let values;
3728
+ try {
3729
+ ({ values } = parseArgs({
3730
+ args,
3731
+ allowPositionals: false,
3732
+ strict: true,
3733
+ options: {
3734
+ help: { type: 'boolean', short: 'h' },
3735
+ json: { type: 'boolean' },
3736
+ 'out-dir': { type: 'string' },
3737
+ apply: { type: 'boolean' },
3738
+ 'dry-run': { type: 'boolean' },
3739
+ 'reuse-manifest': { type: 'boolean' },
3740
+ limit: { type: 'string' },
3741
+ 'page-size': { type: 'string' },
3742
+ concurrency: { type: 'string' },
3743
+ },
3744
+ }));
3745
+ }
3746
+ catch (error) {
3747
+ throw new CliError(String(error), {
3748
+ code: 'INVALID_ARGS',
3749
+ exitCode: 2,
3750
+ });
3751
+ }
3752
+ if (values.apply && values['dry-run']) {
3753
+ throw new CliError('Cannot pass both --apply and --dry-run.', {
3754
+ code: 'PROCESS_REFRESH_MODE_CONFLICT',
3755
+ exitCode: 2,
3756
+ });
3757
+ }
3758
+ const parseOptionalPositiveIntegerFlag = (value, label, code) => {
3759
+ if (typeof value !== 'string') {
3760
+ return null;
3761
+ }
3762
+ const parsed = Number.parseInt(value, 10);
3763
+ if (!Number.isInteger(parsed) || parsed <= 0) {
3764
+ throw new CliError(`Expected ${label} to be a positive integer.`, {
3765
+ code,
3766
+ exitCode: 2,
3767
+ });
3768
+ }
3769
+ return parsed;
3770
+ };
3771
+ return {
3772
+ help: Boolean(values.help),
3773
+ json: Boolean(values.json),
3774
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
3775
+ apply: Boolean(values.apply),
3776
+ reuseManifest: Boolean(values['reuse-manifest']),
3777
+ limit: parseOptionalPositiveIntegerFlag(values.limit, '--limit', 'INVALID_PROCESS_REFRESH_LIMIT'),
3778
+ pageSize: parseOptionalPositiveIntegerFlag(values['page-size'], '--page-size', 'INVALID_PROCESS_REFRESH_PAGE_SIZE'),
3779
+ concurrency: parseOptionalPositiveIntegerFlag(values.concurrency, '--concurrency', 'INVALID_PROCESS_REFRESH_CONCURRENCY'),
3780
+ };
3781
+ }
3782
+ function parseProcessVerifyRowsFlags(args) {
3783
+ let values;
3784
+ try {
3785
+ ({ values } = parseArgs({
3786
+ args,
3787
+ allowPositionals: false,
3788
+ strict: true,
3789
+ options: {
3790
+ help: { type: 'boolean', short: 'h' },
3791
+ json: { type: 'boolean' },
3792
+ 'rows-file': { type: 'string' },
3793
+ 'out-dir': { type: 'string' },
3794
+ },
3795
+ }));
3796
+ }
3797
+ catch (error) {
3798
+ throw new CliError(String(error), {
3799
+ code: 'INVALID_ARGS',
3800
+ exitCode: 2,
3801
+ });
3802
+ }
3803
+ return {
3804
+ help: Boolean(values.help),
3805
+ json: Boolean(values.json),
3806
+ rowsFile: typeof values['rows-file'] === 'string' ? values['rows-file'] : '',
3807
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
3808
+ };
3809
+ }
2310
3810
  function parseProcessBatchBuildFlags(args) {
2311
3811
  let values;
2312
3812
  try {
@@ -2362,14 +3862,24 @@ export async function executeCli(argv, deps) {
2362
3862
  const lifecyclemodelPublishImpl = deps.runLifecyclemodelPublishResultingProcessImpl ?? runLifecyclemodelPublishResultingProcess;
2363
3863
  const lifecyclemodelValidateImpl = deps.runLifecyclemodelValidateBuildImpl ?? runLifecyclemodelValidateBuild;
2364
3864
  const lifecyclemodelPublishBuildImpl = deps.runLifecyclemodelPublishBuildImpl ?? runLifecyclemodelPublishBuild;
3865
+ const lifecyclemodelSaveDraftImpl = deps.runLifecyclemodelSaveDraftImpl ?? runLifecyclemodelSaveDraft;
3866
+ const lifecyclemodelGraphImpl = deps.runLifecyclemodelGraphImpl ?? runLifecyclemodelGraph;
2365
3867
  const lifecyclemodelOrchestrateImpl = deps.runLifecyclemodelOrchestrateImpl ?? runLifecyclemodelOrchestrate;
2366
3868
  const processGetImpl = deps.runProcessGetImpl ?? runProcessGet;
2367
3869
  const processListImpl = deps.runProcessListImpl ?? runProcessList;
2368
3870
  const processAutoBuildImpl = deps.runProcessAutoBuildImpl ?? runProcessAutoBuild;
2369
3871
  const processBatchBuildImpl = deps.runProcessBatchBuildImpl ?? runProcessBatchBuild;
3872
+ const processScopeStatisticsImpl = deps.runProcessScopeStatisticsImpl ?? runProcessScopeStatistics;
3873
+ const processRefreshReferencesImpl = deps.runProcessRefreshReferencesImpl ?? runProcessRefreshReferences;
3874
+ const processDedupReviewImpl = deps.runProcessDedupReviewImpl ?? runProcessDedupReview;
2370
3875
  const processResumeBuildImpl = deps.runProcessResumeBuildImpl ?? runProcessResumeBuild;
2371
3876
  const processPublishBuildImpl = deps.runProcessPublishBuildImpl ?? runProcessPublishBuild;
2372
3877
  const processSaveDraftImpl = deps.runProcessSaveDraftImpl ?? runProcessSaveDraft;
3878
+ const processRequiredFieldsCompleteImpl = deps.runProcessRequiredFieldsCompleteImpl ?? runProcessRequiredFieldsComplete;
3879
+ const processVerifyRowsImpl = deps.runProcessVerifyRowsImpl ?? runProcessVerifyRows;
3880
+ const processIdentityPreflightImpl = deps.runProcessIdentityPreflightImpl ?? runProcessIdentityPreflight;
3881
+ const processBuildPlanValidateImpl = deps.runProcessBuildPlanValidateImpl ?? runProcessBuildPlanValidate;
3882
+ const processBuildPlanMaterializeImpl = deps.runProcessBuildPlanMaterializeImpl ?? runProcessBuildPlanMaterialize;
2373
3883
  const processReviewImpl = deps.runProcessReviewImpl ?? runProcessReview;
2374
3884
  const flowReviewImpl = deps.runFlowReviewImpl ?? runFlowReview;
2375
3885
  const lifecyclemodelReviewImpl = deps.runLifecyclemodelReviewImpl ?? runLifecyclemodelReview;
@@ -2386,45 +3896,348 @@ export async function executeCli(argv, deps) {
2386
3896
  const flowApplyProcessFlowRepairsImpl = deps.runFlowApplyProcessFlowRepairsImpl ?? runFlowApplyProcessFlowRepairs;
2387
3897
  const flowRegenProductImpl = deps.runFlowRegenProductImpl ?? runFlowRegenProduct;
2388
3898
  const flowValidateProcessesImpl = deps.runFlowValidateProcessesImpl ?? runFlowValidateProcesses;
3899
+ const flowIdentityPreflightImpl = deps.runFlowIdentityPreflightImpl ?? runFlowIdentityPreflight;
3900
+ const flowBuildPlanValidateImpl = deps.runFlowBuildPlanValidateImpl ?? runFlowBuildPlanValidate;
3901
+ const flowBuildPlanMaterializeImpl = deps.runFlowBuildPlanMaterializeImpl ?? runFlowBuildPlanMaterialize;
3902
+ const datasetValidateImpl = deps.runDatasetValidateImpl ?? runDatasetValidate;
3903
+ const datasetReferencesRewriteImpl = deps.runDatasetReferencesRewriteImpl ?? runDatasetReferencesRewrite;
3904
+ const datasetRemoteRefreshImpl = deps.runDatasetRemoteRefreshImpl ?? runDatasetRemoteRefresh;
3905
+ const datasetRemoteVerifyImpl = deps.runDatasetRemoteVerifyImpl ?? runDatasetRemoteVerify;
3906
+ const datasetBilingualExtractImpl = deps.runDatasetBilingualExtractImpl ?? runDatasetBilingualExtract;
3907
+ const datasetBilingualApplyImpl = deps.runDatasetBilingualApplyImpl ?? runDatasetBilingualApply;
3908
+ const datasetBilingualValidateImpl = deps.runDatasetBilingualValidateImpl ?? runDatasetBilingualValidate;
3909
+ const datasetEvidenceSearchImpl = deps.runDatasetEvidenceSearchImpl ?? runDatasetEvidenceSearch;
3910
+ const datasetContractImpl = deps.runDatasetContractImpl ?? runDatasetContract;
3911
+ const datasetImportLcaConvertImpl = deps.runDatasetImportLcaConvertImpl ?? runDatasetImportLcaConvert;
3912
+ const datasetAuthorImpl = deps.runDatasetAuthorImpl ?? runDatasetAuthor;
2389
3913
  if (flags.version) {
2390
3914
  return { exitCode: 0, stdout: `${loadCliPackageVersion(import.meta.url)}\n`, stderr: '' };
2391
3915
  }
2392
- if (!command || command === 'help' || flags.help) {
2393
- return { exitCode: 0, stdout: `${renderMainHelp(deps.dotEnvStatus)}\n`, stderr: '' };
3916
+ if (!command || command === 'help' || flags.help) {
3917
+ return { exitCode: 0, stdout: `${renderMainHelp(deps.dotEnvStatus)}\n`, stderr: '' };
3918
+ }
3919
+ if (command === 'doctor') {
3920
+ const doctorFlags = parseDoctorFlags(commandArgs);
3921
+ if (doctorFlags.help) {
3922
+ return { exitCode: 0, stdout: `${renderDoctorHelp()}\n`, stderr: '' };
3923
+ }
3924
+ const report = buildDoctorReport(deps.env, deps.dotEnvStatus);
3925
+ return {
3926
+ exitCode: report.ok ? 0 : 1,
3927
+ stdout: doctorFlags.json ? `${JSON.stringify(report)}\n` : renderDoctorText(report),
3928
+ stderr: '',
3929
+ };
3930
+ }
3931
+ if (command === 'search' && !subcommand && commandArgs.includes('--help')) {
3932
+ return { exitCode: 0, stdout: `${renderSearchHelp()}\n`, stderr: '' };
3933
+ }
3934
+ if (command === 'search' && subcommand) {
3935
+ const remoteFlags = parseRemoteFlags(commandArgs);
3936
+ const commandKey = `search:${subcommand}`;
3937
+ if (remoteFlags.help) {
3938
+ return { exitCode: 0, stdout: `${getRemoteCommandHelp(commandKey)}\n`, stderr: '' };
3939
+ }
3940
+ const env = applyRemoteOverrides(deps.env, remoteFlags);
3941
+ return {
3942
+ exitCode: 0,
3943
+ stdout: await executeRemoteCommand({
3944
+ commandKey,
3945
+ inputPath: remoteFlags.inputPath,
3946
+ env,
3947
+ timeoutMs: remoteFlags.timeoutMs,
3948
+ dryRun: remoteFlags.dryRun,
3949
+ compactJson: remoteFlags.json,
3950
+ fetchImpl: deps.fetchImpl,
3951
+ }),
3952
+ stderr: '',
3953
+ };
3954
+ }
3955
+ if (command === 'dataset' && !subcommand) {
3956
+ return { exitCode: 0, stdout: `${renderDatasetHelp()}\n`, stderr: '' };
3957
+ }
3958
+ if (command === 'dataset' && subcommand === 'contract') {
3959
+ const action = commandArgs[0] ?? '';
3960
+ if (!action || action === '--help' || action === '-h') {
3961
+ return { exitCode: 0, stdout: `${renderDatasetContractHelp()}\n`, stderr: '' };
3962
+ }
3963
+ if (action !== 'get') {
3964
+ throw new CliError("dataset contract action must be 'get'.", {
3965
+ code: 'DATASET_CONTRACT_ACTION_INVALID',
3966
+ exitCode: 2,
3967
+ });
3968
+ }
3969
+ const datasetFlags = parseDatasetContractFlags(commandArgs.slice(1));
3970
+ if (datasetFlags.help) {
3971
+ return { exitCode: 0, stdout: `${renderDatasetContractHelp()}\n`, stderr: '' };
3972
+ }
3973
+ const report = await datasetContractImpl({
3974
+ type: datasetFlags.type,
3975
+ include: datasetFlags.include,
3976
+ profile: datasetFlags.profile,
3977
+ outDir: datasetFlags.outDir,
3978
+ mode: 'contract',
3979
+ });
3980
+ return {
3981
+ exitCode: 0,
3982
+ stdout: stringifyJson(report, datasetFlags.json),
3983
+ stderr: '',
3984
+ };
3985
+ }
3986
+ if (command === 'dataset' && subcommand === 'context-pack') {
3987
+ const datasetFlags = parseDatasetContractFlags(commandArgs);
3988
+ if (datasetFlags.help) {
3989
+ return { exitCode: 0, stdout: `${renderDatasetContextPackHelp()}\n`, stderr: '' };
3990
+ }
3991
+ const report = await datasetContractImpl({
3992
+ type: datasetFlags.type,
3993
+ include: datasetFlags.include,
3994
+ profile: datasetFlags.profile,
3995
+ outDir: datasetFlags.outDir,
3996
+ mode: 'context-pack',
3997
+ });
3998
+ return {
3999
+ exitCode: 0,
4000
+ stdout: stringifyJson(report, datasetFlags.json),
4001
+ stderr: '',
4002
+ };
4003
+ }
4004
+ if (command === 'dataset' && subcommand === 'import-lca') {
4005
+ const action = commandArgs[0] ?? '';
4006
+ if (!action || action === '--help' || action === '-h') {
4007
+ return { exitCode: 0, stdout: `${renderDatasetImportLcaHelp()}\n`, stderr: '' };
4008
+ }
4009
+ if (action !== 'convert') {
4010
+ throw new CliError("dataset import-lca action must be 'convert'.", {
4011
+ code: 'DATASET_IMPORT_LCA_ACTION_INVALID',
4012
+ exitCode: 2,
4013
+ });
4014
+ }
4015
+ const datasetFlags = parseDatasetImportLcaConvertFlags(commandArgs.slice(1));
4016
+ if (datasetFlags.help) {
4017
+ return { exitCode: 0, stdout: `${renderDatasetImportLcaHelp()}\n`, stderr: '' };
4018
+ }
4019
+ const report = await datasetImportLcaConvertImpl({
4020
+ inputPath: datasetFlags.inputPath,
4021
+ outputDir: datasetFlags.outputDir,
4022
+ fromFormat: datasetFlags.fromFormat,
4023
+ target: datasetFlags.target,
4024
+ reportPath: datasetFlags.reportPath,
4025
+ mappingDir: datasetFlags.mappingDir,
4026
+ language: datasetFlags.language,
4027
+ validationJobs: datasetFlags.validationJobs,
4028
+ detectOnly: datasetFlags.detectOnly,
4029
+ failOnWarning: datasetFlags.failOnWarning,
4030
+ pythonBin: datasetFlags.pythonBin,
4031
+ tidasToolsDir: datasetFlags.tidasToolsDir,
4032
+ env: deps.env,
4033
+ });
4034
+ return {
4035
+ exitCode: report.status === 'completed' ? 0 : 1,
4036
+ stdout: stringifyJson(report, datasetFlags.json),
4037
+ stderr: '',
4038
+ };
4039
+ }
4040
+ if (command === 'dataset' && subcommand === 'author') {
4041
+ const datasetFlags = parseDatasetAuthorFlags(commandArgs);
4042
+ if (datasetFlags.help) {
4043
+ return { exitCode: 0, stdout: `${renderDatasetAuthorHelp()}\n`, stderr: '' };
4044
+ }
4045
+ const report = await datasetAuthorImpl({
4046
+ inputPath: datasetFlags.inputPath,
4047
+ targetTypes: datasetFlags.targetTypes,
4048
+ outDir: datasetFlags.outDir,
4049
+ prompt: datasetFlags.prompt,
4050
+ provider: datasetFlags.provider,
4051
+ model: datasetFlags.model,
4052
+ timeoutMs: datasetFlags.timeoutMs,
4053
+ env: deps.env,
4054
+ fetchImpl: deps.fetchImpl,
4055
+ });
4056
+ return {
4057
+ exitCode: 0,
4058
+ stdout: stringifyJson(report, datasetFlags.json),
4059
+ stderr: '',
4060
+ };
4061
+ }
4062
+ if (command === 'dataset' && subcommand === 'validate') {
4063
+ const datasetFlags = parseDatasetValidateFlags(commandArgs);
4064
+ if (datasetFlags.help) {
4065
+ return { exitCode: 0, stdout: `${renderDatasetValidateHelp()}\n`, stderr: '' };
4066
+ }
4067
+ const report = await datasetValidateImpl({
4068
+ inputPath: datasetFlags.inputPath,
4069
+ type: datasetFlags.type,
4070
+ outDir: datasetFlags.outDir,
4071
+ });
4072
+ return {
4073
+ exitCode: report.counts.invalid > 0 ? 1 : 0,
4074
+ stdout: stringifyJson(report, datasetFlags.json),
4075
+ stderr: '',
4076
+ };
2394
4077
  }
2395
- if (command === 'doctor') {
2396
- const doctorFlags = parseDoctorFlags(commandArgs);
2397
- if (doctorFlags.help) {
2398
- return { exitCode: 0, stdout: `${renderDoctorHelp()}\n`, stderr: '' };
4078
+ if (command === 'dataset' && subcommand === 'verify-remote') {
4079
+ const datasetFlags = parseDatasetRemoteVerifyFlags(commandArgs);
4080
+ if (datasetFlags.help) {
4081
+ return { exitCode: 0, stdout: `${renderDatasetRemoteVerifyHelp()}\n`, stderr: '' };
2399
4082
  }
2400
- const report = buildDoctorReport(deps.env, deps.dotEnvStatus);
4083
+ const report = await datasetRemoteVerifyImpl({
4084
+ inputPath: datasetFlags.inputPath,
4085
+ outDir: datasetFlags.outDir,
4086
+ rootPolicy: datasetFlags.rootPolicy,
4087
+ env: deps.env,
4088
+ fetchImpl: deps.fetchImpl,
4089
+ });
2401
4090
  return {
2402
- exitCode: report.ok ? 0 : 1,
2403
- stdout: doctorFlags.json ? `${JSON.stringify(report)}\n` : renderDoctorText(report),
4091
+ exitCode: report.status === 'blocked_remote_verification' ? 1 : 0,
4092
+ stdout: stringifyJson(report, datasetFlags.json),
2404
4093
  stderr: '',
2405
4094
  };
2406
4095
  }
2407
- if (command === 'search' && !subcommand && commandArgs.includes('--help')) {
2408
- return { exitCode: 0, stdout: `${renderSearchHelp()}\n`, stderr: '' };
4096
+ if (command === 'dataset' && subcommand === 'bilingual') {
4097
+ const action = commandArgs[0] ?? '';
4098
+ if (!action || action === '--help' || action === '-h') {
4099
+ return { exitCode: 0, stdout: `${renderDatasetBilingualHelp()}\n`, stderr: '' };
4100
+ }
4101
+ if (action === 'extract') {
4102
+ const datasetFlags = parseDatasetBilingualExtractFlags(commandArgs.slice(1));
4103
+ if (datasetFlags.help) {
4104
+ return { exitCode: 0, stdout: `${renderDatasetBilingualExtractHelp()}\n`, stderr: '' };
4105
+ }
4106
+ const report = await datasetBilingualExtractImpl({
4107
+ inputPath: datasetFlags.inputPath,
4108
+ type: datasetFlags.type,
4109
+ sourceLang: datasetFlags.sourceLang,
4110
+ targetLang: datasetFlags.targetLang,
4111
+ outDir: datasetFlags.outDir,
4112
+ });
4113
+ return {
4114
+ exitCode: 0,
4115
+ stdout: stringifyJson(report, datasetFlags.json),
4116
+ stderr: '',
4117
+ };
4118
+ }
4119
+ if (action === 'apply') {
4120
+ const datasetFlags = parseDatasetBilingualApplyFlags(commandArgs.slice(1));
4121
+ if (datasetFlags.help) {
4122
+ return { exitCode: 0, stdout: `${renderDatasetBilingualApplyHelp()}\n`, stderr: '' };
4123
+ }
4124
+ const report = await datasetBilingualApplyImpl({
4125
+ inputPath: datasetFlags.inputPath,
4126
+ translationsPath: datasetFlags.translationsPath,
4127
+ outPath: datasetFlags.outPath,
4128
+ targetLang: datasetFlags.targetLang,
4129
+ outDir: datasetFlags.outDir,
4130
+ });
4131
+ return {
4132
+ exitCode: report.status === 'blocked' ? 1 : 0,
4133
+ stdout: stringifyJson(report, datasetFlags.json),
4134
+ stderr: '',
4135
+ };
4136
+ }
4137
+ if (action === 'validate') {
4138
+ const datasetFlags = parseDatasetBilingualValidateFlags(commandArgs.slice(1));
4139
+ if (datasetFlags.help) {
4140
+ return { exitCode: 0, stdout: `${renderDatasetBilingualValidateHelp()}\n`, stderr: '' };
4141
+ }
4142
+ const report = await datasetBilingualValidateImpl({
4143
+ inputPath: datasetFlags.inputPath,
4144
+ type: datasetFlags.type,
4145
+ outDir: datasetFlags.outDir,
4146
+ });
4147
+ return {
4148
+ exitCode: report.status === 'blocked' ? 1 : 0,
4149
+ stdout: stringifyJson(report, datasetFlags.json),
4150
+ stderr: '',
4151
+ };
4152
+ }
4153
+ throw new CliError("dataset bilingual action must be 'extract', 'apply', or 'validate'.", {
4154
+ code: 'INVALID_ARGS',
4155
+ exitCode: 2,
4156
+ });
2409
4157
  }
2410
- if (command === 'search' && subcommand) {
2411
- const remoteFlags = parseRemoteFlags(commandArgs);
2412
- const commandKey = `search:${subcommand}`;
2413
- if (remoteFlags.help) {
2414
- return { exitCode: 0, stdout: `${getRemoteCommandHelp(commandKey)}\n`, stderr: '' };
4158
+ if (command === 'dataset' && subcommand === 'evidence-search') {
4159
+ const action = commandArgs[0] ?? '';
4160
+ if (!action || action === '--help' || action === '-h') {
4161
+ return { exitCode: 0, stdout: `${renderDatasetEvidenceSearchHelp()}\n`, stderr: '' };
2415
4162
  }
2416
- const env = applyRemoteOverrides(deps.env, remoteFlags);
4163
+ if (action !== 'plan' && action !== 'run') {
4164
+ throw new CliError("dataset evidence-search action must be 'plan' or 'run'.", {
4165
+ code: 'INVALID_ARGS',
4166
+ exitCode: 2,
4167
+ });
4168
+ }
4169
+ const datasetFlags = parseDatasetEvidenceSearchFlags(commandArgs.slice(1));
4170
+ if (datasetFlags.help) {
4171
+ return { exitCode: 0, stdout: `${renderDatasetEvidenceSearchHelp()}\n`, stderr: '' };
4172
+ }
4173
+ const report = await datasetEvidenceSearchImpl({
4174
+ mode: action,
4175
+ query: datasetFlags.query,
4176
+ inputPath: datasetFlags.inputPath,
4177
+ resultsPath: datasetFlags.resultsPath,
4178
+ providerUrl: datasetFlags.providerUrl,
4179
+ providerKey: datasetFlags.providerKey,
4180
+ profile: datasetFlags.profile,
4181
+ outDir: datasetFlags.outDir,
4182
+ maxQueries: datasetFlags.maxQueries,
4183
+ maxResultsPerQuery: datasetFlags.maxResultsPerQuery,
4184
+ timeoutMs: datasetFlags.timeoutMs,
4185
+ fetchImpl: deps.fetchImpl,
4186
+ });
2417
4187
  return {
2418
- exitCode: 0,
2419
- stdout: await executeRemoteCommand({
2420
- commandKey,
2421
- inputPath: remoteFlags.inputPath,
2422
- env,
2423
- timeoutMs: remoteFlags.timeoutMs,
2424
- dryRun: remoteFlags.dryRun,
2425
- compactJson: remoteFlags.json,
4188
+ exitCode: report.status === 'completed_no_sufficient_evidence' ? 1 : 0,
4189
+ stdout: stringifyJson(report, datasetFlags.json),
4190
+ stderr: '',
4191
+ };
4192
+ }
4193
+ if (command === 'dataset' && subcommand === 'references') {
4194
+ const action = commandArgs[0] ?? '';
4195
+ if (!action || action === '--help' || action === '-h') {
4196
+ return { exitCode: 0, stdout: `${renderDatasetReferencesHelp()}\n`, stderr: '' };
4197
+ }
4198
+ if (!['rewrite', 'refresh-remote'].includes(action)) {
4199
+ throw new CliError("dataset references action must be 'rewrite' or 'refresh-remote'.", {
4200
+ code: 'INVALID_ARGS',
4201
+ exitCode: 2,
4202
+ });
4203
+ }
4204
+ if (action === 'refresh-remote') {
4205
+ const datasetFlags = parseDatasetReferencesRefreshRemoteFlags(commandArgs.slice(1));
4206
+ if (datasetFlags.help) {
4207
+ return { exitCode: 0, stdout: `${renderDatasetReferencesHelp()}\n`, stderr: '' };
4208
+ }
4209
+ const report = await datasetRemoteRefreshImpl({
4210
+ inputPath: datasetFlags.inputPath,
4211
+ outPath: datasetFlags.outPath,
4212
+ outDir: datasetFlags.outDir,
4213
+ rootPolicy: datasetFlags.rootPolicy,
4214
+ env: deps.env,
2426
4215
  fetchImpl: deps.fetchImpl,
2427
- }),
4216
+ });
4217
+ return {
4218
+ exitCode: report.status === 'completed_with_blockers' ? 1 : 0,
4219
+ stdout: stringifyJson(report, datasetFlags.json),
4220
+ stderr: '',
4221
+ };
4222
+ }
4223
+ const datasetFlags = parseDatasetReferencesRewriteFlags(commandArgs.slice(1));
4224
+ if (datasetFlags.help) {
4225
+ return { exitCode: 0, stdout: `${renderDatasetReferencesHelp()}\n`, stderr: '' };
4226
+ }
4227
+ const report = await datasetReferencesRewriteImpl({
4228
+ inputPath: datasetFlags.inputPath,
4229
+ from: datasetFlags.from,
4230
+ to: datasetFlags.to,
4231
+ types: datasetFlags.types,
4232
+ scope: datasetFlags.scope,
4233
+ outDir: datasetFlags.outDir,
4234
+ commit: datasetFlags.commit,
4235
+ env: deps.env,
4236
+ fetchImpl: deps.fetchImpl,
4237
+ });
4238
+ return {
4239
+ exitCode: report.status === 'completed_with_failures' ? 1 : 0,
4240
+ stdout: stringifyJson(report, datasetFlags.json),
2428
4241
  stderr: '',
2429
4242
  };
2430
4243
  }
@@ -2531,6 +4344,49 @@ export async function executeCli(argv, deps) {
2531
4344
  stderr: '',
2532
4345
  };
2533
4346
  }
4347
+ if (command === 'lifecyclemodel' && subcommand === 'save-draft') {
4348
+ const lifecyclemodelFlags = parseLifecyclemodelSaveDraftFlags(commandArgs);
4349
+ if (lifecyclemodelFlags.help) {
4350
+ return {
4351
+ exitCode: 0,
4352
+ stdout: `${renderLifecyclemodelSaveDraftHelp()}\n`,
4353
+ stderr: '',
4354
+ };
4355
+ }
4356
+ const report = await lifecyclemodelSaveDraftImpl({
4357
+ inputPath: lifecyclemodelFlags.inputPath,
4358
+ outDir: lifecyclemodelFlags.outDir,
4359
+ commit: lifecyclemodelFlags.commit,
4360
+ env: deps.env,
4361
+ fetchImpl: deps.fetchImpl,
4362
+ });
4363
+ return {
4364
+ exitCode: report.status === 'completed_with_failures' ? 1 : 0,
4365
+ stdout: stringifyJson(report, lifecyclemodelFlags.json),
4366
+ stderr: '',
4367
+ };
4368
+ }
4369
+ if (command === 'lifecyclemodel' && subcommand === 'graph') {
4370
+ const lifecyclemodelFlags = parseLifecyclemodelGraphFlags(commandArgs);
4371
+ if (lifecyclemodelFlags.help) {
4372
+ return {
4373
+ exitCode: 0,
4374
+ stdout: `${renderLifecyclemodelGraphHelp()}\n`,
4375
+ stderr: '',
4376
+ };
4377
+ }
4378
+ const report = await lifecyclemodelGraphImpl({
4379
+ inputPath: lifecyclemodelFlags.inputPath,
4380
+ outDir: lifecyclemodelFlags.outDir,
4381
+ format: lifecyclemodelFlags.format,
4382
+ checkConnections: lifecyclemodelFlags.checkConnections,
4383
+ });
4384
+ return {
4385
+ exitCode: report.status === 'completed_with_findings' ? 1 : 0,
4386
+ stdout: stringifyJson(report, lifecyclemodelFlags.json),
4387
+ stderr: '',
4388
+ };
4389
+ }
2534
4390
  if (command === 'lifecyclemodel' && subcommand === 'orchestrate') {
2535
4391
  const lifecyclemodelFlags = parseLifecyclemodelOrchestrateFlags(commandArgs);
2536
4392
  if (lifecyclemodelFlags.help || !lifecyclemodelFlags.action) {
@@ -2618,6 +4474,117 @@ export async function executeCli(argv, deps) {
2618
4474
  stderr: '',
2619
4475
  };
2620
4476
  }
4477
+ if (command === 'process' && subcommand === 'identity-preflight') {
4478
+ const processFlags = parseIdentityPreflightFlags(commandArgs);
4479
+ if (processFlags.help) {
4480
+ return {
4481
+ exitCode: 0,
4482
+ stdout: `${renderProcessIdentityPreflightHelp()}\n`,
4483
+ stderr: '',
4484
+ };
4485
+ }
4486
+ const report = await processIdentityPreflightImpl({
4487
+ inputPath: processFlags.inputPath,
4488
+ outDir: processFlags.outDir,
4489
+ candidateInputPaths: processFlags.candidateInputPaths,
4490
+ remoteCandidateSearch: processFlags.remoteCandidateSearch,
4491
+ remoteQuery: processFlags.remoteQuery,
4492
+ remoteLimit: processFlags.remoteLimit,
4493
+ env: deps.env,
4494
+ fetchImpl: deps.fetchImpl,
4495
+ });
4496
+ return {
4497
+ exitCode: report.status === 'passed' ? 0 : 1,
4498
+ stdout: stringifyJson(report, processFlags.json),
4499
+ stderr: '',
4500
+ };
4501
+ }
4502
+ if (command === 'process' && subcommand === 'build-plan') {
4503
+ const action = commandArgs[0] ?? '';
4504
+ if (!action || action === '--help' || action === '-h') {
4505
+ return {
4506
+ exitCode: 0,
4507
+ stdout: `${renderProcessBuildPlanHelp()}\n`,
4508
+ stderr: '',
4509
+ };
4510
+ }
4511
+ if (action !== 'validate' && action !== 'materialize') {
4512
+ throw new CliError("process build-plan action must be 'validate' or 'materialize'.", {
4513
+ code: 'INVALID_ARGS',
4514
+ exitCode: 2,
4515
+ });
4516
+ }
4517
+ const processFlags = parseBuildPlanFlags(commandArgs.slice(1));
4518
+ if (processFlags.help) {
4519
+ return {
4520
+ exitCode: 0,
4521
+ stdout: `${renderProcessBuildPlanHelp()}\n`,
4522
+ stderr: '',
4523
+ };
4524
+ }
4525
+ const report = action === 'validate'
4526
+ ? await processBuildPlanValidateImpl({
4527
+ inputPath: processFlags.inputPath,
4528
+ outDir: processFlags.outDir,
4529
+ reportOnly: processFlags.reportOnly,
4530
+ })
4531
+ : await processBuildPlanMaterializeImpl({
4532
+ inputPath: processFlags.inputPath,
4533
+ outDir: processFlags.outDir,
4534
+ reportOnly: processFlags.reportOnly,
4535
+ });
4536
+ return {
4537
+ exitCode: report.status === 'blocked' && !processFlags.reportOnly ? 1 : 0,
4538
+ stdout: stringifyJson(report, processFlags.json),
4539
+ stderr: '',
4540
+ };
4541
+ }
4542
+ if (command === 'process' && subcommand === 'scope-statistics') {
4543
+ const processFlags = parseProcessScopeStatisticsFlags(commandArgs);
4544
+ if (processFlags.help) {
4545
+ return {
4546
+ exitCode: 0,
4547
+ stdout: `${renderProcessScopeStatisticsHelp()}\n`,
4548
+ stderr: '',
4549
+ };
4550
+ }
4551
+ const report = await processScopeStatisticsImpl({
4552
+ outDir: processFlags.outDir,
4553
+ scope: processFlags.scope,
4554
+ stateCodes: processFlags.stateCodes,
4555
+ pageSize: processFlags.pageSize,
4556
+ reuseSnapshot: processFlags.reuseSnapshot,
4557
+ env: deps.env,
4558
+ fetchImpl: deps.fetchImpl,
4559
+ });
4560
+ return {
4561
+ exitCode: 0,
4562
+ stdout: stringifyJson(report, processFlags.json),
4563
+ stderr: '',
4564
+ };
4565
+ }
4566
+ if (command === 'process' && subcommand === 'dedup-review') {
4567
+ const processFlags = parseProcessDedupReviewFlags(commandArgs);
4568
+ if (processFlags.help) {
4569
+ return {
4570
+ exitCode: 0,
4571
+ stdout: `${renderProcessDedupReviewHelp()}\n`,
4572
+ stderr: '',
4573
+ };
4574
+ }
4575
+ const report = await processDedupReviewImpl({
4576
+ inputPath: processFlags.inputPath,
4577
+ outDir: processFlags.outDir,
4578
+ skipRemote: processFlags.skipRemote,
4579
+ env: deps.env,
4580
+ fetchImpl: deps.fetchImpl,
4581
+ });
4582
+ return {
4583
+ exitCode: 0,
4584
+ stdout: stringifyJson(report, processFlags.json),
4585
+ stderr: '',
4586
+ };
4587
+ }
2621
4588
  if (command === 'process' && subcommand === 'auto-build') {
2622
4589
  const processFlags = parseProcessAutoBuildFlags(commandArgs);
2623
4590
  if (processFlags.help) {
@@ -2675,6 +4642,28 @@ export async function executeCli(argv, deps) {
2675
4642
  stderr: '',
2676
4643
  };
2677
4644
  }
4645
+ if (command === 'process' && subcommand === 'complete-required-fields') {
4646
+ const processFlags = parseProcessRequiredFieldsFlags(commandArgs);
4647
+ if (processFlags.help) {
4648
+ return {
4649
+ exitCode: 0,
4650
+ stdout: `${renderProcessRequiredFieldsHelp()}\n`,
4651
+ stderr: '',
4652
+ };
4653
+ }
4654
+ const report = await processRequiredFieldsCompleteImpl({
4655
+ inputPath: processFlags.inputPath,
4656
+ outPath: processFlags.outPath,
4657
+ outDir: processFlags.outDir,
4658
+ flowInputPath: processFlags.flowInputPath,
4659
+ defaultUnit: processFlags.defaultUnit,
4660
+ });
4661
+ return {
4662
+ exitCode: report.status === 'completed_with_blockers' ? 1 : 0,
4663
+ stdout: stringifyJson(report, processFlags.json),
4664
+ stderr: '',
4665
+ };
4666
+ }
2678
4667
  if (command === 'process' && subcommand === 'save-draft') {
2679
4668
  const processFlags = parseProcessSaveDraftFlags(commandArgs);
2680
4669
  if (processFlags.help) {
@@ -2697,6 +4686,50 @@ export async function executeCli(argv, deps) {
2697
4686
  stderr: '',
2698
4687
  };
2699
4688
  }
4689
+ if (command === 'process' && subcommand === 'refresh-references') {
4690
+ const processFlags = parseProcessRefreshReferencesFlags(commandArgs);
4691
+ if (processFlags.help) {
4692
+ return {
4693
+ exitCode: 0,
4694
+ stdout: `${renderProcessRefreshReferencesHelp()}\n`,
4695
+ stderr: '',
4696
+ };
4697
+ }
4698
+ const report = await processRefreshReferencesImpl({
4699
+ outDir: processFlags.outDir,
4700
+ apply: processFlags.apply,
4701
+ reuseManifest: processFlags.reuseManifest,
4702
+ limit: processFlags.limit,
4703
+ pageSize: processFlags.pageSize,
4704
+ concurrency: processFlags.concurrency,
4705
+ env: deps.env,
4706
+ fetchImpl: deps.fetchImpl,
4707
+ });
4708
+ return {
4709
+ exitCode: report.status === 'completed_process_reference_refresh_with_errors' ? 1 : 0,
4710
+ stdout: stringifyJson(report, processFlags.json),
4711
+ stderr: '',
4712
+ };
4713
+ }
4714
+ if (command === 'process' && subcommand === 'verify-rows') {
4715
+ const processFlags = parseProcessVerifyRowsFlags(commandArgs);
4716
+ if (processFlags.help) {
4717
+ return {
4718
+ exitCode: 0,
4719
+ stdout: `${renderProcessVerifyRowsHelp()}\n`,
4720
+ stderr: '',
4721
+ };
4722
+ }
4723
+ const report = await processVerifyRowsImpl({
4724
+ rowsFile: processFlags.rowsFile,
4725
+ outDir: processFlags.outDir,
4726
+ });
4727
+ return {
4728
+ exitCode: report.invalid_count > 0 ? 1 : 0,
4729
+ stdout: stringifyJson(report, processFlags.json),
4730
+ stderr: '',
4731
+ };
4732
+ }
2700
4733
  if (command === 'process' && subcommand === 'batch-build') {
2701
4734
  const processFlags = parseProcessBatchBuildFlags(commandArgs);
2702
4735
  if (processFlags.help) {
@@ -2763,6 +4796,59 @@ export async function executeCli(argv, deps) {
2763
4796
  stderr: '',
2764
4797
  };
2765
4798
  }
4799
+ if (command === 'flow' && subcommand === 'identity-preflight') {
4800
+ const flowFlags = parseIdentityPreflightFlags(commandArgs);
4801
+ if (flowFlags.help) {
4802
+ return { exitCode: 0, stdout: `${renderFlowIdentityPreflightHelp()}\n`, stderr: '' };
4803
+ }
4804
+ const report = await flowIdentityPreflightImpl({
4805
+ inputPath: flowFlags.inputPath,
4806
+ outDir: flowFlags.outDir,
4807
+ candidateInputPaths: flowFlags.candidateInputPaths,
4808
+ remoteCandidateSearch: flowFlags.remoteCandidateSearch,
4809
+ remoteQuery: flowFlags.remoteQuery,
4810
+ remoteLimit: flowFlags.remoteLimit,
4811
+ env: deps.env,
4812
+ fetchImpl: deps.fetchImpl,
4813
+ });
4814
+ return {
4815
+ exitCode: report.status === 'passed' ? 0 : 1,
4816
+ stdout: stringifyJson(report, flowFlags.json),
4817
+ stderr: '',
4818
+ };
4819
+ }
4820
+ if (command === 'flow' && subcommand === 'build-plan') {
4821
+ const action = commandArgs[0] ?? '';
4822
+ if (!action || action === '--help' || action === '-h') {
4823
+ return { exitCode: 0, stdout: `${renderFlowBuildPlanHelp()}\n`, stderr: '' };
4824
+ }
4825
+ if (action !== 'validate' && action !== 'materialize') {
4826
+ throw new CliError("flow build-plan action must be 'validate' or 'materialize'.", {
4827
+ code: 'INVALID_ARGS',
4828
+ exitCode: 2,
4829
+ });
4830
+ }
4831
+ const flowFlags = parseBuildPlanFlags(commandArgs.slice(1));
4832
+ if (flowFlags.help) {
4833
+ return { exitCode: 0, stdout: `${renderFlowBuildPlanHelp()}\n`, stderr: '' };
4834
+ }
4835
+ const report = action === 'validate'
4836
+ ? await flowBuildPlanValidateImpl({
4837
+ inputPath: flowFlags.inputPath,
4838
+ outDir: flowFlags.outDir,
4839
+ reportOnly: flowFlags.reportOnly,
4840
+ })
4841
+ : await flowBuildPlanMaterializeImpl({
4842
+ inputPath: flowFlags.inputPath,
4843
+ outDir: flowFlags.outDir,
4844
+ reportOnly: flowFlags.reportOnly,
4845
+ });
4846
+ return {
4847
+ exitCode: report.status === 'blocked' && !flowFlags.reportOnly ? 1 : 0,
4848
+ stdout: stringifyJson(report, flowFlags.json),
4849
+ stderr: '',
4850
+ };
4851
+ }
2766
4852
  if (command === 'flow' && subcommand === 'remediate') {
2767
4853
  const flowFlags = parseFlowRemediateFlags(commandArgs);
2768
4854
  if (flowFlags.help) {