@tiangong-lca/cli 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,19 +4,21 @@ Package: `@tiangong-lca/cli` Executable: `tiangong` Node: `24.x`
4
4
 
5
5
  ## Run
6
6
 
7
- Use the published CLI directly:
7
+ One-off published run:
8
8
 
9
9
  ```bash
10
- npx -y @tiangong-lca/cli@latest --help
11
- npx -y @tiangong-lca/cli@latest doctor
12
- npx -y @tiangong-lca/cli@latest flow --help
10
+ npm exec --yes --package=@tiangong-lca/cli@latest -- tiangong --help
11
+ npm exec --yes --package=@tiangong-lca/cli@latest -- tiangong doctor
12
+ npm exec --yes --package=@tiangong-lca/cli@latest -- tiangong flow --help
13
13
  ```
14
14
 
15
- Optional global install:
15
+ Install the published CLI:
16
16
 
17
17
  ```bash
18
18
  npm install --global @tiangong-lca/cli
19
19
  tiangong --help
20
+ tiangong doctor
21
+ tiangong flow --help
20
22
  ```
21
23
 
22
24
  Run from this repository:
@@ -76,9 +78,9 @@ Minimal `search flow` request:
76
78
  Run:
77
79
 
78
80
  ```bash
79
- npx -y @tiangong-lca/cli@latest search flow --input ./search-flow.request.json --json
80
- npx -y @tiangong-lca/cli@latest search process --input ./search-process.request.json --json
81
- npx -y @tiangong-lca/cli@latest search lifecyclemodel --input ./search-lifecyclemodel.request.json --json
81
+ tiangong search flow --input ./search-flow.request.json --json
82
+ tiangong search process --input ./search-process.request.json --json
83
+ tiangong search lifecyclemodel --input ./search-lifecyclemodel.request.json --json
82
84
  ```
83
85
 
84
86
  Empty search results should be treated as empty whether the response is `[]` or `{"data":[]}`.
@@ -86,9 +88,10 @@ Empty search results should be treated as empty whether the response is `[]` or
86
88
  ## Read
87
89
 
88
90
  ```bash
89
- npx -y @tiangong-lca/cli@latest flow get --id <flow-id> --version <version> --json
90
- npx -y @tiangong-lca/cli@latest flow list --id <flow-id> --state-code 100 --limit 20 --json
91
- npx -y @tiangong-lca/cli@latest process get --id <process-id> --version <version> --json
91
+ tiangong flow get --id <flow-id> --version <version> --json
92
+ tiangong flow list --id <flow-id> --state-code 100 --limit 20 --json
93
+ tiangong process get --id <process-id> --version <version> --json
94
+ tiangong process list --state-code 100 --limit 20 --json
92
95
  ```
93
96
 
94
97
  ## Real DB Flow Review
@@ -135,15 +138,15 @@ npx -y @tiangong-lca/cli@latest process get --id <process-id> --version <version
135
138
  Run:
136
139
 
137
140
  ```bash
138
- npx -y @tiangong-lca/cli@latest flow fetch-rows \
141
+ tiangong flow fetch-rows \
139
142
  --refs-file ./flow-refs.json \
140
143
  --out-dir ./flow-fetch
141
144
 
142
- npx -y @tiangong-lca/cli@latest review flow \
145
+ tiangong review flow \
143
146
  --rows-file ./flow-fetch/review-input-rows.jsonl \
144
147
  --out-dir ./flow-review
145
148
 
146
- npx -y @tiangong-lca/cli@latest flow materialize-decisions \
149
+ tiangong flow materialize-decisions \
147
150
  --decision-file ./approved-decisions.json \
148
151
  --flow-rows-file ./flow-fetch/review-input-rows.jsonl \
149
152
  --out-dir ./flow-decisions
@@ -167,11 +170,16 @@ Key `flow materialize-decisions` outputs:
167
170
  ## Other Common Commands
168
171
 
169
172
  ```bash
170
- npx -y @tiangong-lca/cli@latest review process --run-root ./artifacts/process_from_flow/<run_id> --run-id <run_id> --out-dir ./review
171
- npx -y @tiangong-lca/cli@latest publish run --input ./publish-request.json --dry-run
172
- npx -y @tiangong-lca/cli@latest doctor --json
173
+ tiangong review process --rows-file ./process-list-report.json --out-dir ./review
174
+ tiangong review process --run-root ./artifacts/process_from_flow/<run_id> --run-id <run_id> --out-dir ./review
175
+ tiangong publish run --input ./publish-request.json --dry-run
176
+ tiangong doctor --json
173
177
  ```
174
178
 
179
+ For `publish run`, relative `out_dir` values from either the request body or `--out-dir` are resolved against the request file directory, not the shell `cwd`. Use an absolute path when you want a fixed destination independent of the request file location.
180
+
181
+ For `review process`, `--rows-file` accepts either raw process rows as JSON/JSONL or the full JSON report emitted by `tiangong process list --json`, as long as it contains a `rows` array.
182
+
175
183
  ## More Docs
176
184
 
177
185
  - `docs/IMPLEMENTATION_GUIDE_CN.md`: maintainer-facing command contract and implementation notes
@@ -181,10 +189,10 @@ npx -y @tiangong-lca/cli@latest doctor --json
181
189
  ## Help
182
190
 
183
191
  ```bash
184
- npx -y @tiangong-lca/cli@latest --help
185
- npx -y @tiangong-lca/cli@latest flow --help
186
- npx -y @tiangong-lca/cli@latest review --help
187
- npx -y @tiangong-lca/cli@latest process --help
188
- npx -y @tiangong-lca/cli@latest lifecyclemodel --help
189
- npx -y @tiangong-lca/cli@latest publish --help
192
+ tiangong --help
193
+ tiangong flow --help
194
+ tiangong review --help
195
+ tiangong process --help
196
+ tiangong lifecyclemodel --help
197
+ tiangong publish --help
190
198
  ```
package/bin/tiangong.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { existsSync } from 'node:fs';
3
+ import { existsSync, realpathSync } from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import process from 'node:process';
6
6
  import { fileURLToPath, pathToFileURL } from 'node:url';
@@ -8,6 +8,19 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
8
8
  const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
9
9
  const entryPath = path.join(rootDir, 'dist', 'src', 'main.js');
10
10
 
11
+ export function resolveInvokedUrl(argv1 = process.argv[1]) {
12
+ if (!argv1) {
13
+ return null;
14
+ }
15
+
16
+ const resolvedPath = path.resolve(argv1);
17
+ try {
18
+ return pathToFileURL(realpathSync(resolvedPath)).href;
19
+ } catch {
20
+ return pathToFileURL(resolvedPath).href;
21
+ }
22
+ }
23
+
11
24
  export async function runFromBin(argv = process.argv.slice(2), env = process.env) {
12
25
  if (!existsSync(entryPath)) {
13
26
  throw new Error(
@@ -20,7 +33,7 @@ export async function runFromBin(argv = process.argv.slice(2), env = process.env
20
33
  return main(argv, env);
21
34
  }
22
35
 
23
- const invokedUrl = process.argv[1] ? pathToFileURL(path.resolve(process.argv[1])).href : null;
36
+ const invokedUrl = resolveInvokedUrl(process.argv[1]);
24
37
 
25
38
  if (invokedUrl && import.meta.url === invokedUrl) {
26
39
  try {
package/dist/src/cli.js CHANGED
@@ -2,6 +2,7 @@ import { parseArgs } from 'node:util';
2
2
  import { buildDoctorReport, readRuntimeEnv } from './lib/env.js';
3
3
  import { CliError, toErrorPayload } from './lib/errors.js';
4
4
  import { stringifyJson } from './lib/io.js';
5
+ import { loadCliPackageVersion } from './lib/package-version.js';
5
6
  import { runLifecyclemodelAutoBuild, } from './lib/lifecyclemodel-auto-build.js';
6
7
  import { runLifecyclemodelBuildResultingProcess, } from './lib/lifecyclemodel-resulting-process.js';
7
8
  import { runLifecyclemodelPublishResultingProcess, } from './lib/lifecyclemodel-publish-resulting-process.js';
@@ -10,9 +11,11 @@ import { runLifecyclemodelPublishBuild, } from './lib/lifecyclemodel-publish-bui
10
11
  import { runLifecyclemodelOrchestrate, } from './lib/lifecyclemodel-orchestrate.js';
11
12
  import { runProcessAutoBuild, } from './lib/process-auto-build.js';
12
13
  import { runProcessGet, } from './lib/process-get.js';
14
+ import { runProcessList, } from './lib/process-list.js';
13
15
  import { runProcessBatchBuild, } from './lib/process-batch-build.js';
14
16
  import { runProcessResumeBuild, } from './lib/process-resume-build.js';
15
17
  import { runProcessPublishBuild, } from './lib/process-publish-build.js';
18
+ import { runProcessSaveDraft, } from './lib/process-save-draft-run.js';
16
19
  import { runPublish } from './lib/publish.js';
17
20
  import { runProcessReview, } from './lib/review-process.js';
18
21
  import { runFlowReview, } from './lib/review-flow.js';
@@ -46,7 +49,7 @@ Commands:
46
49
  Implemented Commands:
47
50
  doctor show environment diagnostics
48
51
  search flow | process | lifecyclemodel
49
- process get | auto-build | resume-build | publish-build | batch-build
52
+ process get | list | auto-build | resume-build | publish-build | save-draft | batch-build
50
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
51
54
  lifecyclemodel auto-build | validate-build | publish-build | build-resulting-process | publish-resulting-process | orchestrate
52
55
  review process | flow | lifecyclemodel
@@ -65,9 +68,11 @@ Examples:
65
68
  tiangong search flow --input ./request.json
66
69
  tiangong search process --input ./request.json --dry-run
67
70
  tiangong process get --id <process-id>
71
+ tiangong process list --state-code 100 --limit 20
68
72
  tiangong process auto-build --input ./pff-request.json
69
73
  tiangong process resume-build --run-id <id>
70
74
  tiangong process publish-build --run-id <id>
75
+ tiangong process save-draft --input ./patched-processes.jsonl --dry-run
71
76
  tiangong process batch-build --input ./batch-request.json
72
77
  tiangong lifecyclemodel auto-build --input ./lifecyclemodel-auto-build.request.json
73
78
  tiangong lifecyclemodel validate-build --run-dir ./artifacts/lifecyclemodel_auto_build/<run_id>
@@ -86,6 +91,7 @@ Examples:
86
91
  tiangong flow apply-process-flow-repairs --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-repair-apply
87
92
  tiangong flow regen-product --processes-file ./processes.jsonl --scope-flow-file ./flows.jsonl --out-dir ./flow-regeneration --apply
88
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
89
95
  tiangong review process --run-root ./artifacts/process_from_flow/<run_id> --run-id <run_id> --out-dir ./review
90
96
  tiangong review flow --rows-file ./flows.json --out-dir ./review
91
97
  tiangong review lifecyclemodel --run-dir ./artifacts/lifecyclemodel_auto_build/<run_id> --out-dir ./lifecyclemodel-review
@@ -165,6 +171,9 @@ Options:
165
171
  --dry-run Force publish.commit=false
166
172
  --json Print compact JSON
167
173
  -h, --help
174
+
175
+ Path rule:
176
+ Relative out_dir values from the request body or --out-dir resolve from the request file directory.
168
177
  `.trim();
169
178
  }
170
179
  function renderValidationHelp() {
@@ -524,7 +533,7 @@ function renderReviewHelp() {
524
533
  tiangong review <subcommand> [options]
525
534
 
526
535
  Implemented Subcommands:
527
- process Review one local process build run and emit artifact-first findings
536
+ process Review process build runs or rows-file snapshots and emit artifact-first findings
528
537
  flow Review local flow governance snapshots and emit artifact-first findings
529
538
  lifecyclemodel Review one local lifecyclemodel build run and emit artifact-first findings
530
539
 
@@ -537,11 +546,12 @@ Examples:
537
546
  }
538
547
  function renderReviewProcessHelp() {
539
548
  return `Usage:
540
- tiangong review process --run-root <dir> --run-id <id> --out-dir <dir> [options]
549
+ tiangong review process (--rows-file <file> | --run-root <dir>) --out-dir <dir> [options]
541
550
 
542
551
  Options:
552
+ --rows-file <file> Process rows JSON/JSONL file; full process list reports with rows[] are also accepted
543
553
  --run-root <dir> Process build run root containing exports/processes
544
- --run-id <id> Process build run identifier
554
+ --run-id <id> Optional review run identifier; defaults to the rows-file name or run-root basename
545
555
  --out-dir <dir> Review artifact output directory
546
556
  --start-ts <iso> Optional run start timestamp
547
557
  --end-ts <iso> Optional run end timestamp
@@ -749,6 +759,33 @@ Required env:
749
759
  TIANGONG_LCA_API_KEY
750
760
  TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
751
761
 
762
+ Runtime note:
763
+ The CLI derives a native @supabase/supabase-js client and deterministic read target from TIANGONG_LCA_API_BASE_URL,
764
+ and authenticates that client with the resolved user access token.
765
+ `.trim();
766
+ }
767
+ function renderProcessListHelp() {
768
+ return `Usage:
769
+ tiangong process list [options]
770
+
771
+ Options:
772
+ --id <process-id> Repeatable exact process UUID filter
773
+ --version <version> Optional dataset version filter
774
+ --user-id <user-id> Optional owner filter for private rows
775
+ --state-code <code> Repeatable visibility filter such as 0 or 100
776
+ --order <expr> Deterministic PostgREST order expression (default: id.asc,version.asc)
777
+ --limit <n> Page size for one request (default: 100)
778
+ --offset <n> Row offset for one request (default: 0)
779
+ --all Fetch all matching rows via offset pagination
780
+ --page-size <n> Page size when --all is used (default: 100)
781
+ --json Print compact JSON
782
+ -h, --help
783
+
784
+ Required env:
785
+ TIANGONG_LCA_API_BASE_URL
786
+ TIANGONG_LCA_API_KEY
787
+ TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
788
+
752
789
  Runtime note:
753
790
  The CLI derives a native @supabase/supabase-js client and deterministic read target from TIANGONG_LCA_API_BASE_URL,
754
791
  and authenticates that client with the resolved user access token.
@@ -776,6 +813,31 @@ Options:
776
813
  -h, --help
777
814
  `.trim();
778
815
  }
816
+ function renderProcessSaveDraftHelp() {
817
+ return `Usage:
818
+ tiangong process save-draft --input <file> [options]
819
+
820
+ Options:
821
+ --input <file> Process rows JSON/JSONL file or publish-request.json
822
+ --out-dir <dir> Run root written relative to cwd when a relative path is passed
823
+ --commit Execute remote save-draft writes
824
+ --dry-run Keep the command local-only (default)
825
+ --json Print compact JSON
826
+ -h, --help
827
+
828
+ Environment:
829
+ none for local dry-run
830
+ TIANGONG_LCA_API_BASE_URL, TIANGONG_LCA_API_KEY, and TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
831
+ when --commit executes remote writes
832
+
833
+ Outputs written under --out-dir:
834
+ - inputs/normalized-input.json
835
+ - outputs/save-draft-rpc/selected-processes.jsonl
836
+ - outputs/save-draft-rpc/progress.jsonl
837
+ - outputs/save-draft-rpc/failures.jsonl
838
+ - outputs/save-draft-rpc/summary.json
839
+ `.trim();
840
+ }
779
841
  function renderProcessBatchBuildHelp() {
780
842
  return `Usage:
781
843
  tiangong process batch-build --input <file> [options]
@@ -793,17 +855,21 @@ function renderProcessHelp() {
793
855
 
794
856
  Implemented Subcommands:
795
857
  get Load one process dataset by identifier through direct Supabase access
858
+ list List visible process rows through direct Supabase access
796
859
  auto-build Prepare a local process-from-flow run scaffold and artifact workspace
797
860
  resume-build Prepare a local resume handoff from one existing process build run
798
861
  publish-build Prepare publish handoff artifacts from one existing process build run
862
+ save-draft Save canonical process datasets through the state-aware draft-maintenance path
799
863
  batch-build Run multiple process auto-build requests through one batch-oriented CLI surface
800
864
 
801
865
  Examples:
802
866
  tiangong process --help
803
867
  tiangong process get --id <process-id>
868
+ tiangong process list --state-code 100 --limit 20 --help
804
869
  tiangong process auto-build --help
805
870
  tiangong process resume-build --run-id <id> --help
806
871
  tiangong process publish-build --run-id <id> --help
872
+ tiangong process save-draft --input ./patched-processes.jsonl --help
807
873
  tiangong process batch-build --input ./batch-request.json --help
808
874
  `.trim();
809
875
  }
@@ -1694,6 +1760,7 @@ function parseReviewProcessFlags(args) {
1694
1760
  options: {
1695
1761
  help: { type: 'boolean', short: 'h' },
1696
1762
  json: { type: 'boolean' },
1763
+ 'rows-file': { type: 'string' },
1697
1764
  'run-root': { type: 'string' },
1698
1765
  'run-id': { type: 'string' },
1699
1766
  'out-dir': { type: 'string' },
@@ -1725,8 +1792,9 @@ function parseReviewProcessFlags(args) {
1725
1792
  return {
1726
1793
  help: Boolean(values.help),
1727
1794
  json: Boolean(values.json),
1728
- runRoot: typeof values['run-root'] === 'string' ? values['run-root'] : '',
1729
- runId: typeof values['run-id'] === 'string' ? values['run-id'] : '',
1795
+ rowsFile: typeof values['rows-file'] === 'string' ? values['rows-file'] : undefined,
1796
+ runRoot: typeof values['run-root'] === 'string' ? values['run-root'] : undefined,
1797
+ runId: typeof values['run-id'] === 'string' ? values['run-id'] : undefined,
1730
1798
  outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
1731
1799
  startTs: typeof values['start-ts'] === 'string' ? values['start-ts'] : undefined,
1732
1800
  endTs: typeof values['end-ts'] === 'string' ? values['end-ts'] : undefined,
@@ -2055,6 +2123,96 @@ function parseProcessGetFlags(args) {
2055
2123
  version: typeof values.version === 'string' ? values.version : null,
2056
2124
  };
2057
2125
  }
2126
+ function parseProcessListFlags(args) {
2127
+ let values;
2128
+ try {
2129
+ ({ values } = parseArgs({
2130
+ args,
2131
+ allowPositionals: false,
2132
+ strict: true,
2133
+ options: {
2134
+ help: { type: 'boolean', short: 'h' },
2135
+ json: { type: 'boolean' },
2136
+ id: { type: 'string', multiple: true },
2137
+ version: { type: 'string' },
2138
+ 'user-id': { type: 'string' },
2139
+ 'state-code': { type: 'string', multiple: true },
2140
+ limit: { type: 'string' },
2141
+ offset: { type: 'string' },
2142
+ all: { type: 'boolean' },
2143
+ 'page-size': { type: 'string' },
2144
+ order: { type: 'string' },
2145
+ },
2146
+ }));
2147
+ }
2148
+ catch (error) {
2149
+ throw new CliError(String(error), {
2150
+ code: 'INVALID_ARGS',
2151
+ exitCode: 2,
2152
+ });
2153
+ }
2154
+ const parseOptionalPositiveIntegerFlag = (value, label, code) => {
2155
+ if (typeof value !== 'string') {
2156
+ return null;
2157
+ }
2158
+ const parsed = Number.parseInt(value, 10);
2159
+ if (!Number.isInteger(parsed) || parsed <= 0) {
2160
+ throw new CliError(`Expected ${label} to be a positive integer.`, {
2161
+ code,
2162
+ exitCode: 2,
2163
+ });
2164
+ }
2165
+ return parsed;
2166
+ };
2167
+ const parseOptionalNonNegativeIntegerFlag = (value, label, code) => {
2168
+ if (typeof value !== 'string') {
2169
+ return null;
2170
+ }
2171
+ const parsed = Number.parseInt(value, 10);
2172
+ if (!Number.isInteger(parsed) || parsed < 0) {
2173
+ throw new CliError(`Expected ${label} to be a non-negative integer.`, {
2174
+ code,
2175
+ exitCode: 2,
2176
+ });
2177
+ }
2178
+ return parsed;
2179
+ };
2180
+ const parseStateCodeValues = (value) => {
2181
+ if (!Array.isArray(value)) {
2182
+ return [];
2183
+ }
2184
+ return value.map((entry) => {
2185
+ const parsed = Number.parseInt(String(entry), 10);
2186
+ if (!Number.isInteger(parsed) || parsed < 0) {
2187
+ throw new CliError('Expected --state-code to be a non-negative integer.', {
2188
+ code: 'INVALID_PROCESS_LIST_STATE_CODE',
2189
+ exitCode: 2,
2190
+ });
2191
+ }
2192
+ return parsed;
2193
+ });
2194
+ };
2195
+ const toStringArray = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === 'string') : [];
2196
+ if (values['page-size'] !== undefined && !values.all) {
2197
+ throw new CliError('Use --page-size only with --all.', {
2198
+ code: 'PROCESS_LIST_PAGE_SIZE_REQUIRES_ALL',
2199
+ exitCode: 2,
2200
+ });
2201
+ }
2202
+ return {
2203
+ help: Boolean(values.help),
2204
+ json: Boolean(values.json),
2205
+ ids: toStringArray(values.id),
2206
+ version: typeof values.version === 'string' ? values.version : null,
2207
+ userId: typeof values['user-id'] === 'string' ? values['user-id'] : null,
2208
+ stateCodes: parseStateCodeValues(values['state-code']),
2209
+ limit: parseOptionalPositiveIntegerFlag(values.limit, '--limit', 'INVALID_PROCESS_LIST_LIMIT'),
2210
+ offset: parseOptionalNonNegativeIntegerFlag(values.offset, '--offset', 'INVALID_PROCESS_LIST_OFFSET'),
2211
+ all: Boolean(values.all),
2212
+ pageSize: parseOptionalPositiveIntegerFlag(values['page-size'], '--page-size', 'INVALID_PROCESS_LIST_PAGE_SIZE'),
2213
+ order: typeof values.order === 'string' ? values.order : null,
2214
+ };
2215
+ }
2058
2216
  function parseProcessResumeBuildFlags(args) {
2059
2217
  let values;
2060
2218
  try {
@@ -2111,6 +2269,43 @@ function parseProcessPublishBuildFlags(args) {
2111
2269
  runDir: typeof values['run-dir'] === 'string' ? values['run-dir'] : null,
2112
2270
  };
2113
2271
  }
2272
+ function parseProcessSaveDraftFlags(args) {
2273
+ let values;
2274
+ try {
2275
+ ({ values } = parseArgs({
2276
+ args,
2277
+ allowPositionals: false,
2278
+ strict: true,
2279
+ options: {
2280
+ help: { type: 'boolean', short: 'h' },
2281
+ json: { type: 'boolean' },
2282
+ input: { type: 'string' },
2283
+ 'out-dir': { type: 'string' },
2284
+ commit: { type: 'boolean' },
2285
+ 'dry-run': { type: 'boolean' },
2286
+ },
2287
+ }));
2288
+ }
2289
+ catch (error) {
2290
+ throw new CliError(String(error), {
2291
+ code: 'INVALID_ARGS',
2292
+ exitCode: 2,
2293
+ });
2294
+ }
2295
+ if (values.commit && values['dry-run']) {
2296
+ throw new CliError('Cannot pass both --commit and --dry-run.', {
2297
+ code: 'INVALID_PROCESS_SAVE_DRAFT_MODE',
2298
+ exitCode: 2,
2299
+ });
2300
+ }
2301
+ return {
2302
+ help: Boolean(values.help),
2303
+ json: Boolean(values.json),
2304
+ inputPath: typeof values.input === 'string' ? values.input : '',
2305
+ outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : null,
2306
+ commit: Boolean(values.commit),
2307
+ };
2308
+ }
2114
2309
  function parseProcessBatchBuildFlags(args) {
2115
2310
  let values;
2116
2311
  try {
@@ -2168,10 +2363,12 @@ export async function executeCli(argv, deps) {
2168
2363
  const lifecyclemodelPublishBuildImpl = deps.runLifecyclemodelPublishBuildImpl ?? runLifecyclemodelPublishBuild;
2169
2364
  const lifecyclemodelOrchestrateImpl = deps.runLifecyclemodelOrchestrateImpl ?? runLifecyclemodelOrchestrate;
2170
2365
  const processGetImpl = deps.runProcessGetImpl ?? runProcessGet;
2366
+ const processListImpl = deps.runProcessListImpl ?? runProcessList;
2171
2367
  const processAutoBuildImpl = deps.runProcessAutoBuildImpl ?? runProcessAutoBuild;
2172
2368
  const processBatchBuildImpl = deps.runProcessBatchBuildImpl ?? runProcessBatchBuild;
2173
2369
  const processResumeBuildImpl = deps.runProcessResumeBuildImpl ?? runProcessResumeBuild;
2174
2370
  const processPublishBuildImpl = deps.runProcessPublishBuildImpl ?? runProcessPublishBuild;
2371
+ const processSaveDraftImpl = deps.runProcessSaveDraftImpl ?? runProcessSaveDraft;
2175
2372
  const processReviewImpl = deps.runProcessReviewImpl ?? runProcessReview;
2176
2373
  const flowReviewImpl = deps.runFlowReviewImpl ?? runFlowReview;
2177
2374
  const lifecyclemodelReviewImpl = deps.runLifecyclemodelReviewImpl ?? runLifecyclemodelReview;
@@ -2189,7 +2386,7 @@ export async function executeCli(argv, deps) {
2189
2386
  const flowRegenProductImpl = deps.runFlowRegenProductImpl ?? runFlowRegenProduct;
2190
2387
  const flowValidateProcessesImpl = deps.runFlowValidateProcessesImpl ?? runFlowValidateProcesses;
2191
2388
  if (flags.version) {
2192
- return { exitCode: 0, stdout: '0.0.1\n', stderr: '' };
2389
+ return { exitCode: 0, stdout: `${loadCliPackageVersion(import.meta.url)}\n`, stderr: '' };
2193
2390
  }
2194
2391
  if (!command || command === 'help' || flags.help) {
2195
2392
  return { exitCode: 0, stdout: `${renderMainHelp(deps.dotEnvStatus)}\n`, stderr: '' };
@@ -2392,6 +2589,34 @@ export async function executeCli(argv, deps) {
2392
2589
  stderr: '',
2393
2590
  };
2394
2591
  }
2592
+ if (command === 'process' && subcommand === 'list') {
2593
+ const processFlags = parseProcessListFlags(commandArgs);
2594
+ if (processFlags.help) {
2595
+ return {
2596
+ exitCode: 0,
2597
+ stdout: `${renderProcessListHelp()}\n`,
2598
+ stderr: '',
2599
+ };
2600
+ }
2601
+ const report = await processListImpl({
2602
+ ids: processFlags.ids,
2603
+ version: processFlags.version,
2604
+ userId: processFlags.userId,
2605
+ stateCodes: processFlags.stateCodes,
2606
+ limit: processFlags.limit,
2607
+ offset: processFlags.offset,
2608
+ all: processFlags.all,
2609
+ pageSize: processFlags.pageSize,
2610
+ order: processFlags.order,
2611
+ env: deps.env,
2612
+ fetchImpl: deps.fetchImpl,
2613
+ });
2614
+ return {
2615
+ exitCode: 0,
2616
+ stdout: stringifyJson(report, processFlags.json),
2617
+ stderr: '',
2618
+ };
2619
+ }
2395
2620
  if (command === 'process' && subcommand === 'auto-build') {
2396
2621
  const processFlags = parseProcessAutoBuildFlags(commandArgs);
2397
2622
  if (processFlags.help) {
@@ -2449,6 +2674,28 @@ export async function executeCli(argv, deps) {
2449
2674
  stderr: '',
2450
2675
  };
2451
2676
  }
2677
+ if (command === 'process' && subcommand === 'save-draft') {
2678
+ const processFlags = parseProcessSaveDraftFlags(commandArgs);
2679
+ if (processFlags.help) {
2680
+ return {
2681
+ exitCode: 0,
2682
+ stdout: `${renderProcessSaveDraftHelp()}\n`,
2683
+ stderr: '',
2684
+ };
2685
+ }
2686
+ const report = await processSaveDraftImpl({
2687
+ inputPath: processFlags.inputPath,
2688
+ outDir: processFlags.outDir,
2689
+ commit: processFlags.commit,
2690
+ env: deps.env,
2691
+ fetchImpl: deps.fetchImpl,
2692
+ });
2693
+ return {
2694
+ exitCode: report.status === 'completed_with_failures' ? 1 : 0,
2695
+ stdout: stringifyJson(report, processFlags.json),
2696
+ stderr: '',
2697
+ };
2698
+ }
2452
2699
  if (command === 'process' && subcommand === 'batch-build') {
2453
2700
  const processFlags = parseProcessBatchBuildFlags(commandArgs);
2454
2701
  if (processFlags.help) {
@@ -2817,6 +3064,7 @@ export async function executeCli(argv, deps) {
2817
3064
  return { exitCode: 0, stdout: `${renderReviewProcessHelp()}\n`, stderr: '' };
2818
3065
  }
2819
3066
  const report = await processReviewImpl({
3067
+ rowsFile: reviewFlags.rowsFile,
2820
3068
  runRoot: reviewFlags.runRoot,
2821
3069
  runId: reviewFlags.runId,
2822
3070
  outDir: reviewFlags.outDir,