@tiangong-lca/cli 0.0.21 → 0.0.22
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 +53 -4
- package/dist/src/cli.js +331 -21
- package/dist/src/cli.js.map +1 -1
- package/dist/src/lib/dataset-maintenance-alias-rewrite.js +541 -0
- package/dist/src/lib/dataset-maintenance-alias-rewrite.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-apply.js +1537 -0
- package/dist/src/lib/dataset-maintenance-apply.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-contract.js +836 -0
- package/dist/src/lib/dataset-maintenance-contract.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-plan.js +485 -0
- package/dist/src/lib/dataset-maintenance-plan.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-remote.js +272 -0
- package/dist/src/lib/dataset-maintenance-remote.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-support-validation.js +18 -0
- package/dist/src/lib/dataset-maintenance-support-validation.js.map +1 -0
- package/dist/src/lib/dataset-maintenance-verify.js +690 -0
- package/dist/src/lib/dataset-maintenance-verify.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,14 +17,16 @@ checkPaths:
|
|
|
17
17
|
- bin/**
|
|
18
18
|
- src/cli.ts
|
|
19
19
|
- src/main.ts
|
|
20
|
-
lastReviewedAt: 2026-
|
|
21
|
-
lastReviewedCommit:
|
|
20
|
+
lastReviewedAt: 2026-07-12
|
|
21
|
+
lastReviewedCommit: 192ce9cb233af85b8bcf50136d37fd08d4ae8292
|
|
22
22
|
---
|
|
23
23
|
|
|
24
24
|
# TianGong LCA CLI
|
|
25
25
|
|
|
26
26
|
Package: `@tiangong-lca/cli` Executable: `tiangong-lca` Node: `24.x`
|
|
27
27
|
|
|
28
|
+
Review note, 2026-07-12: `dataset maintenance plan/apply/verify` provides current-user RLS-scoped exact-row maintenance with immutable plans, explicit approval, per-action logs, platform audit correlation, and independent readback. `merge-support-aliases` now runs only in `target_mode=owner_draft`: source/target support and all changed rows stay private `state_code=0`; publication is a separate future workflow.
|
|
29
|
+
|
|
28
30
|
## Run
|
|
29
31
|
|
|
30
32
|
One-off published run:
|
|
@@ -273,7 +275,9 @@ tiangong-lca dataset curation-queue verify --queue-dir /abs/path/to/curation-que
|
|
|
273
275
|
tiangong-lca dataset evidence-search plan --query "中国2026年电力结构数据" --out-dir /abs/path/to/evidence-search --json
|
|
274
276
|
tiangong-lca dataset evidence-search run --input ./evidence-search.request.json --results ./search-results.json --out-dir /abs/path/to/evidence-search --json
|
|
275
277
|
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 --json
|
|
276
|
-
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation redo-import --out-dir /abs/path/to/dataset-maintenance
|
|
278
|
+
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation redo-import --out-dir /abs/path/to/dataset-maintenance --page-size 1000 --timeout-ms 10000 --json
|
|
279
|
+
tiangong-lca dataset maintenance apply --plan /abs/path/to/dataset-maintenance/maintenance-plan.json --commit --approve-plan <sha256> --confirm <current-account-email> --timeout-ms 10000 --json
|
|
280
|
+
tiangong-lca dataset maintenance verify --plan /abs/path/to/dataset-maintenance/maintenance-plan.json --out-dir /abs/path/to/dataset-maintenance/verify --page-size 1000 --timeout-ms 10000 --json
|
|
277
281
|
tiangong-lca lifecyclemodel auto-build --input ./examples/lifecyclemodel-auto-build.request.json --out-dir /abs/path/to/lifecyclemodel-run --json
|
|
278
282
|
tiangong-lca lifecyclemodel validate-build --run-dir /abs/path/to/lifecyclemodel-run --json
|
|
279
283
|
tiangong-lca lifecyclemodel publish-build --run-dir /abs/path/to/lifecyclemodel-run --json
|
|
@@ -316,7 +320,52 @@ For `dataset curation-queue build/next/verify`, the CLI owns entity-level Foundr
|
|
|
316
320
|
|
|
317
321
|
For `dataset references rewrite`, `--commit` executes the state-aware save-draft path for patched process and lifecyclemodel rows; without `--commit`, the command only writes local rewrite artifacts.
|
|
318
322
|
|
|
319
|
-
|
|
323
|
+
## Dataset Maintenance
|
|
324
|
+
|
|
325
|
+
`dataset maintenance plan/apply/verify` is the row-level cleanup surface for bad imports and the fixed BAFU private alias rewrite. It runs as the currently authenticated user and relies on RLS for visibility and ownership enforcement.
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
tiangong-lca dataset maintenance plan \
|
|
329
|
+
--scope ./maintenance-scope.json \
|
|
330
|
+
--operation merge-support-aliases \
|
|
331
|
+
--out-dir ./dataset-maintenance \
|
|
332
|
+
--page-size 1000 \
|
|
333
|
+
--timeout-ms 10000 \
|
|
334
|
+
--json
|
|
335
|
+
|
|
336
|
+
tiangong-lca dataset maintenance apply \
|
|
337
|
+
--plan ./dataset-maintenance/maintenance-plan.json \
|
|
338
|
+
--commit \
|
|
339
|
+
--approve-plan <sha256> \
|
|
340
|
+
--confirm <current-account-email> \
|
|
341
|
+
--timeout-ms 10000 \
|
|
342
|
+
--json
|
|
343
|
+
|
|
344
|
+
tiangong-lca dataset maintenance verify \
|
|
345
|
+
--plan ./dataset-maintenance/maintenance-plan.json \
|
|
346
|
+
--out-dir ./dataset-maintenance/verify \
|
|
347
|
+
--page-size 1000 \
|
|
348
|
+
--timeout-ms 10000 \
|
|
349
|
+
--json
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
The scope is intentionally narrow:
|
|
353
|
+
|
|
354
|
+
- Each requested row must name its table, exact `id`, exact `version`, expected current owner, and draft `state_code=0` state.
|
|
355
|
+
- `--operation` accepts `delete`, `retire`, `redo-import`, `repair-references`, or `merge-support-aliases`; it records the operator's maintenance intent and does not broaden the eligible row actions.
|
|
356
|
+
- Only current-user `contacts`, `sources`, `flows`, and `processes` can become `save_draft` or `delete` actions.
|
|
357
|
+
- `merge-support-aliases` requires top-level `target_mode: "owner_draft"` and accepts only two named batches, `time` and `length_time`. The scope must bind reviewed current-owner draft source and target FP/UG exact ids/versions to 52 `update_json_ordered` actions: 25 time rows (1 FP, 10 flows, 14 processes) and 27 length-time rows (1 FP, 13 flows, 13 processes). Process actions freeze every selected exchange index, internal id, flow id/version, direction, before hash, and both amount strings.
|
|
358
|
+
- The alias factors are exact decimal strings: `0.00011415525114155251` for time and `1000` for length-time. Planning requires exactly 20 and 39 selected exchanges, preserves exactly 309 other exchanges in the affected processes, and proves the fixed source-zero/target-reference postconditions. The transformation changes references and the selected `meanAmount`/`resultingAmount`; it does not delete the source FP/UG rows.
|
|
359
|
+
- Source alias support, target FP/UG, and every changed flow/process must all belong to the authenticated account at `state_code=0`. Public/shared, foreign-owner, mixed-visibility, non-draft, lifecyclemodel, and unsupported action/table rows remain protected.
|
|
360
|
+
- The CLI classifies and executes an operator-authored scope; it does not decide whether rows are semantically duplicates, canonical replacements, or safe business-level cleanup targets.
|
|
361
|
+
|
|
362
|
+
`plan` writes the frozen `maintenance-scope.json`, `rls-visible-snapshot.json`, `protected-rows.jsonl`, `reference-impact-report.json`, `maintenance-plan.json`, and `dry-run-report.json`. Alias plans additionally write `exchange-rewrite-plan.jsonl`, freeze current-owner state-0 target FP, target UG, and source UG snapshots for each batch, derive schema-valid desired payloads with matching embedded UUID/version, and include the exact closure, `modified_at`, hashes, conversion evidence, and postconditions in the approved plan. The plan SHA-256 is the approval identity; do not edit or recompute the plan after review.
|
|
363
|
+
|
|
364
|
+
`apply` is write-disabled unless all three commit guards are present: `--commit`, `--approve-plan <sha256>`, and `--confirm <current-account-email>`. Before the first write it re-checks the whole plan for drift and persists `approval-record.json`. Ordinary draft updates/deletes use their platform paths. The ordered `time` plus `length_time` alias request is sent once to `cmd_dataset_alias_plan_guarded` with `target_visibility=owner_draft`; the CLI has neither a per-dimension fallback nor a 52-write sequential fallback. The RPC locks and validates the complete 52-row/59-exchange closure before both dimensions commit, so a second-dimension failure rolls back the first. It checks actor ownership, state 0, exact payload/timestamp locks and embedded UUID/version, rejects missing or phantom flow/exchange references, and returns one plan summary audit id plus both batch and per-row audit proofs. The CLI writes `alias-plan-progress.jsonl` together with plan-bound per-batch, per-row, and per-exchange ledgers. A lost response or incomplete derived ledger is repaired only by replaying the same whole plan and matching every returned plan and batch proof.
|
|
365
|
+
|
|
366
|
+
`verify` performs a fresh remote readback rather than trusting the apply report and writes `readback-verify-report.json` in its own output directory. For alias plans it also requires both successful batch records, all 52 correlated row records, all 59 unique exchange records, unchanged support snapshots, and exact desired row payloads. It validates the RPC-returned audit ids against the local proof chain; it does not independently query `public.command_audit_log`.
|
|
367
|
+
|
|
368
|
+
Foundry and skills may prepare the scope, invoke these commands, and retain their artifacts. They must not replace the CLI with direct SQL, service-role access, raw REST mutation, or private Supabase delete/update code.
|
|
320
369
|
|
|
321
370
|
## More Docs
|
|
322
371
|
|
package/dist/src/cli.js
CHANGED
|
@@ -54,6 +54,9 @@ import { runDatasetPatchApply, } from './lib/dataset-patch.js';
|
|
|
54
54
|
import { runDatasetSaveDraft, } from './lib/dataset-save-draft-run.js';
|
|
55
55
|
import { runDatasetClassificationApply, runDatasetClassificationAudit, runDatasetClassificationChildren, runDatasetClassificationPath, } from './lib/dataset-classification.js';
|
|
56
56
|
import { runDatasetMaintenanceClearAccount, } from './lib/dataset-maintenance-clear-account.js';
|
|
57
|
+
import { runDatasetMaintenancePlan } from './lib/dataset-maintenance-plan.js';
|
|
58
|
+
import { runDatasetMaintenanceApply } from './lib/dataset-maintenance-apply.js';
|
|
59
|
+
import { runDatasetMaintenanceVerify } from './lib/dataset-maintenance-verify.js';
|
|
57
60
|
import { runDatasetSourceUploadAttachments, } from './lib/dataset-source-upload-attachments.js';
|
|
58
61
|
function renderMainHelp(dotEnvStatus) {
|
|
59
62
|
return `TianGong LCA CLI
|
|
@@ -74,7 +77,7 @@ Implemented Commands:
|
|
|
74
77
|
doctor show environment diagnostics
|
|
75
78
|
search flow | process | lifecyclemodel
|
|
76
79
|
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
|
|
77
|
-
dataset contract get | context-pack | classification children/path/audit/apply | curation-queue build/next/verify | import-lca convert | author | patch apply | save-draft | source upload-attachments | validate | verify-remote | bilingual extract/apply/validate | evidence-search plan/run | references rewrite/refresh-remote | maintenance clear-account
|
|
80
|
+
dataset contract get | context-pack | classification children/path/audit/apply | curation-queue build/next/verify | import-lca convert | author | patch apply | save-draft | source upload-attachments | validate | verify-remote | bilingual extract/apply/validate | evidence-search plan/run | references rewrite/refresh-remote | maintenance clear-account/plan/apply/verify
|
|
78
81
|
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
|
|
79
82
|
lifecyclemodel auto-build | validate-build | publish-build | save-draft | graph | build-resulting-process | publish-resulting-process | orchestrate
|
|
80
83
|
qa process | flow | lifecyclemodel
|
|
@@ -85,7 +88,6 @@ Implemented Commands:
|
|
|
85
88
|
Planned Surface (not implemented yet):
|
|
86
89
|
auth whoami | doctor-auth
|
|
87
90
|
job get | wait | logs
|
|
88
|
-
dataset maintenance plan | apply | verify
|
|
89
91
|
|
|
90
92
|
Planned commands currently print an explicit "not implemented yet" message and exit with code 2.
|
|
91
93
|
|
|
@@ -128,7 +130,7 @@ Examples:
|
|
|
128
130
|
tiangong-lca dataset evidence-search run --input ./evidence-search.request.json --results ./search-results.json --out-dir ./evidence-search
|
|
129
131
|
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
|
|
130
132
|
tiangong-lca dataset maintenance clear-account --out-dir /abs/path/to/account-clear --json
|
|
131
|
-
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation
|
|
133
|
+
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation merge-support-aliases --out-dir /abs/path/to/dataset-maintenance
|
|
132
134
|
tiangong-lca lifecyclemodel auto-build --input ./lifecyclemodel-auto-build.request.json --out-dir /abs/path/to/lifecyclemodel-run
|
|
133
135
|
tiangong-lca lifecyclemodel validate-build --run-dir /abs/path/to/lifecyclemodel-run
|
|
134
136
|
tiangong-lca lifecyclemodel publish-build --run-dir /abs/path/to/lifecyclemodel-run
|
|
@@ -279,9 +281,9 @@ Implemented Subcommands:
|
|
|
279
281
|
references rewrite Rewrite flow references in local process and lifecyclemodel rows
|
|
280
282
|
references refresh-remote Refresh local TIDAS reference versions to latest reachable remote rows
|
|
281
283
|
maintenance clear-account Dry-run or clear current authenticated account-owned dataset rows through RLS
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
maintenance
|
|
284
|
+
maintenance plan Build an immutable, RLS-visible row-level maintenance plan
|
|
285
|
+
maintenance apply Execute an explicitly approved maintenance plan through current-user RLS
|
|
286
|
+
maintenance verify Read back affected rows and references against the immutable plan
|
|
285
287
|
|
|
286
288
|
Examples:
|
|
287
289
|
tiangong-lca dataset contract get --type process --include schema,methodology,ruleset --out-dir ./contract --help
|
|
@@ -307,25 +309,23 @@ Examples:
|
|
|
307
309
|
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
|
|
308
310
|
tiangong-lca dataset references refresh-remote --input ./rows.jsonl --out ./rows.refreshed.jsonl --out-dir ./dataset-reference-refresh --help
|
|
309
311
|
tiangong-lca dataset maintenance clear-account --out-dir ./account-clear --json --help
|
|
310
|
-
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation
|
|
312
|
+
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation merge-support-aliases --out-dir ./dataset-maintenance --help
|
|
311
313
|
`.trim();
|
|
312
314
|
}
|
|
313
315
|
function renderDatasetMaintenanceHelp() {
|
|
314
316
|
return `Usage:
|
|
315
317
|
tiangong-lca dataset maintenance <clear-account|plan|apply|verify> [options]
|
|
316
318
|
|
|
317
|
-
|
|
318
|
-
clear-account is implemented for current authenticated account cleanup.
|
|
319
|
-
plan/apply/verify remain reserved for row-level RLS-scoped cleanup and redo workflows and currently exit with code 2 for executable actions.
|
|
320
|
-
|
|
321
|
-
Implemented Actions:
|
|
319
|
+
Actions:
|
|
322
320
|
clear-account Dry-run or delete current authenticated account-owned lifecyclemodels, processes, flows, sources, and contacts.
|
|
323
|
-
|
|
324
|
-
Planned Actions:
|
|
325
321
|
plan Build an immutable maintenance plan from a scope manifest, visible remote snapshot, dependency impact report, and intended operation.
|
|
326
322
|
apply Execute an approved plan through current-user RLS and platform dataset command paths; never bypass RLS or delete rows outside the visible scope.
|
|
327
323
|
verify Re-fetch affected rows and references, then prove that deleted, updated, skipped, protected, and redone rows match the plan.
|
|
328
324
|
|
|
325
|
+
Safety:
|
|
326
|
+
plan and verify are read-only.
|
|
327
|
+
apply is commit-only and requires --commit, the exact plan SHA-256 via --approve-plan, and the current account email via --confirm.
|
|
328
|
+
|
|
329
329
|
Required Artifact Contract:
|
|
330
330
|
- maintenance-plan.json
|
|
331
331
|
- rls-visible-snapshot.json
|
|
@@ -338,11 +338,66 @@ Required Artifact Contract:
|
|
|
338
338
|
Examples:
|
|
339
339
|
tiangong-lca dataset maintenance clear-account --out-dir ./account-clear --json
|
|
340
340
|
tiangong-lca dataset maintenance clear-account --commit --confirm user@example.com --out-dir ./account-clear
|
|
341
|
-
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation
|
|
342
|
-
tiangong-lca dataset maintenance apply --plan ./dataset-maintenance/maintenance-plan.json --commit
|
|
341
|
+
tiangong-lca dataset maintenance plan --scope ./maintenance-scope.json --operation merge-support-aliases --out-dir ./dataset-maintenance
|
|
342
|
+
tiangong-lca dataset maintenance apply --plan ./dataset-maintenance/maintenance-plan.json --commit --approve-plan <sha256> --confirm user@example.com
|
|
343
343
|
tiangong-lca dataset maintenance verify --plan ./dataset-maintenance/maintenance-plan.json --out-dir ./dataset-maintenance/verify
|
|
344
344
|
`.trim();
|
|
345
345
|
}
|
|
346
|
+
function renderDatasetMaintenancePlanHelp() {
|
|
347
|
+
return `Usage:
|
|
348
|
+
tiangong-lca dataset maintenance plan --scope <file> --operation <operation> --out-dir <dir> [options]
|
|
349
|
+
|
|
350
|
+
Operations:
|
|
351
|
+
delete | retire | redo-import | repair-references | merge-support-aliases
|
|
352
|
+
|
|
353
|
+
Options:
|
|
354
|
+
--scope <file> Maintenance scope manifest
|
|
355
|
+
--operation <value> Intended row-level maintenance operation
|
|
356
|
+
--out-dir <dir> Artifact directory
|
|
357
|
+
--page-size <n> Snapshot page size
|
|
358
|
+
--timeout-ms <n> Request timeout in milliseconds
|
|
359
|
+
--json Print compact JSON
|
|
360
|
+
-h, --help
|
|
361
|
+
|
|
362
|
+
Outputs written under --out-dir include the immutable maintenance-plan.json, visible snapshot,
|
|
363
|
+
protected-row ledger, reference-impact report, and dry-run report.
|
|
364
|
+
`.trim();
|
|
365
|
+
}
|
|
366
|
+
function renderDatasetMaintenanceApplyHelp() {
|
|
367
|
+
return `Usage:
|
|
368
|
+
tiangong-lca dataset maintenance apply --plan <file> --commit --approve-plan <sha256> --confirm <email> [options]
|
|
369
|
+
|
|
370
|
+
Behavior:
|
|
371
|
+
Commit-only. The command rejects dry-run mode, a missing --commit flag, a plan hash mismatch,
|
|
372
|
+
or a confirmation email that does not match the current authenticated account.
|
|
373
|
+
|
|
374
|
+
Options:
|
|
375
|
+
--plan <file> Immutable maintenance-plan.json
|
|
376
|
+
--commit Execute the approved plan
|
|
377
|
+
--approve-plan <sha256> Exact SHA-256 recorded for the plan
|
|
378
|
+
--confirm <email> Current authenticated account email
|
|
379
|
+
--timeout-ms <n> Request timeout in milliseconds
|
|
380
|
+
--json Print compact JSON
|
|
381
|
+
-h, --help
|
|
382
|
+
|
|
383
|
+
Outputs include approval-record.json and commit-report.json alongside an append-only action ledger.
|
|
384
|
+
`.trim();
|
|
385
|
+
}
|
|
386
|
+
function renderDatasetMaintenanceVerifyHelp() {
|
|
387
|
+
return `Usage:
|
|
388
|
+
tiangong-lca dataset maintenance verify --plan <file> [options]
|
|
389
|
+
|
|
390
|
+
Options:
|
|
391
|
+
--plan <file> Immutable maintenance-plan.json
|
|
392
|
+
--out-dir <dir> Optional verification artifact directory
|
|
393
|
+
--page-size <n> Readback page size
|
|
394
|
+
--timeout-ms <n> Request timeout in milliseconds
|
|
395
|
+
--json Print compact JSON
|
|
396
|
+
-h, --help
|
|
397
|
+
|
|
398
|
+
Outputs include readback-verify-report.json with affected-row and reference checks.
|
|
399
|
+
`.trim();
|
|
400
|
+
}
|
|
346
401
|
function renderDatasetMaintenanceClearAccountHelp() {
|
|
347
402
|
return `Usage:
|
|
348
403
|
tiangong-lca dataset maintenance clear-account [options]
|
|
@@ -2966,6 +3021,130 @@ function parseDatasetMaintenanceClearAccountFlags(args) {
|
|
|
2966
3021
|
confirm: typeof values.confirm === 'string' ? values.confirm : null,
|
|
2967
3022
|
};
|
|
2968
3023
|
}
|
|
3024
|
+
function parseDatasetMaintenancePositiveInteger(value, flagName) {
|
|
3025
|
+
if (typeof value !== 'string') {
|
|
3026
|
+
return undefined;
|
|
3027
|
+
}
|
|
3028
|
+
if (!/^\d+$/u.test(value.trim()) || Number.parseInt(value.trim(), 10) <= 0) {
|
|
3029
|
+
throw new CliError(`${flagName} must be a positive integer.`, {
|
|
3030
|
+
code: 'DATASET_MAINTENANCE_INTEGER_INVALID',
|
|
3031
|
+
exitCode: 2,
|
|
3032
|
+
details: { flag: flagName, value },
|
|
3033
|
+
});
|
|
3034
|
+
}
|
|
3035
|
+
return Number.parseInt(value.trim(), 10);
|
|
3036
|
+
}
|
|
3037
|
+
function parseDatasetMaintenancePlanFlags(args) {
|
|
3038
|
+
let values;
|
|
3039
|
+
try {
|
|
3040
|
+
({ values } = parseArgs({
|
|
3041
|
+
args,
|
|
3042
|
+
allowPositionals: false,
|
|
3043
|
+
strict: true,
|
|
3044
|
+
options: {
|
|
3045
|
+
help: { type: 'boolean', short: 'h' },
|
|
3046
|
+
json: { type: 'boolean' },
|
|
3047
|
+
scope: { type: 'string' },
|
|
3048
|
+
operation: { type: 'string' },
|
|
3049
|
+
'out-dir': { type: 'string' },
|
|
3050
|
+
'page-size': { type: 'string' },
|
|
3051
|
+
'timeout-ms': { type: 'string' },
|
|
3052
|
+
},
|
|
3053
|
+
}));
|
|
3054
|
+
}
|
|
3055
|
+
catch (error) {
|
|
3056
|
+
throw new CliError(String(error), {
|
|
3057
|
+
code: 'INVALID_ARGS',
|
|
3058
|
+
exitCode: 2,
|
|
3059
|
+
});
|
|
3060
|
+
}
|
|
3061
|
+
const rawOperation = typeof values.operation === 'string' ? values.operation : null;
|
|
3062
|
+
if (rawOperation !== null &&
|
|
3063
|
+
!['delete', 'retire', 'redo-import', 'repair-references', 'merge-support-aliases'].includes(rawOperation)) {
|
|
3064
|
+
throw new CliError("--operation must be 'delete', 'retire', 'redo-import', 'repair-references', or 'merge-support-aliases'.", {
|
|
3065
|
+
code: 'DATASET_MAINTENANCE_OPERATION_INVALID',
|
|
3066
|
+
exitCode: 2,
|
|
3067
|
+
details: rawOperation,
|
|
3068
|
+
});
|
|
3069
|
+
}
|
|
3070
|
+
return {
|
|
3071
|
+
help: Boolean(values.help),
|
|
3072
|
+
json: Boolean(values.json),
|
|
3073
|
+
scopePath: typeof values.scope === 'string' ? values.scope : '',
|
|
3074
|
+
operation: rawOperation,
|
|
3075
|
+
outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : '',
|
|
3076
|
+
pageSize: parseDatasetMaintenancePositiveInteger(values['page-size'], '--page-size'),
|
|
3077
|
+
timeoutMs: parseDatasetMaintenancePositiveInteger(values['timeout-ms'], '--timeout-ms'),
|
|
3078
|
+
};
|
|
3079
|
+
}
|
|
3080
|
+
function parseDatasetMaintenanceApplyFlags(args) {
|
|
3081
|
+
let values;
|
|
3082
|
+
try {
|
|
3083
|
+
({ values } = parseArgs({
|
|
3084
|
+
args,
|
|
3085
|
+
allowPositionals: false,
|
|
3086
|
+
strict: true,
|
|
3087
|
+
options: {
|
|
3088
|
+
help: { type: 'boolean', short: 'h' },
|
|
3089
|
+
json: { type: 'boolean' },
|
|
3090
|
+
plan: { type: 'string' },
|
|
3091
|
+
commit: { type: 'boolean' },
|
|
3092
|
+
'approve-plan': { type: 'string' },
|
|
3093
|
+
confirm: { type: 'string' },
|
|
3094
|
+
'timeout-ms': { type: 'string' },
|
|
3095
|
+
'dry-run': { type: 'boolean' },
|
|
3096
|
+
},
|
|
3097
|
+
}));
|
|
3098
|
+
}
|
|
3099
|
+
catch (error) {
|
|
3100
|
+
throw new CliError(String(error), {
|
|
3101
|
+
code: 'INVALID_ARGS',
|
|
3102
|
+
exitCode: 2,
|
|
3103
|
+
});
|
|
3104
|
+
}
|
|
3105
|
+
return {
|
|
3106
|
+
help: Boolean(values.help),
|
|
3107
|
+
json: Boolean(values.json),
|
|
3108
|
+
planPath: typeof values.plan === 'string' ? values.plan : '',
|
|
3109
|
+
commit: Boolean(values.commit),
|
|
3110
|
+
approvePlan: typeof values['approve-plan'] === 'string' ? values['approve-plan'] : '',
|
|
3111
|
+
confirm: typeof values.confirm === 'string' ? values.confirm : '',
|
|
3112
|
+
timeoutMs: parseDatasetMaintenancePositiveInteger(values['timeout-ms'], '--timeout-ms'),
|
|
3113
|
+
dryRun: Boolean(values['dry-run']),
|
|
3114
|
+
};
|
|
3115
|
+
}
|
|
3116
|
+
function parseDatasetMaintenanceVerifyFlags(args) {
|
|
3117
|
+
let values;
|
|
3118
|
+
try {
|
|
3119
|
+
({ values } = parseArgs({
|
|
3120
|
+
args,
|
|
3121
|
+
allowPositionals: false,
|
|
3122
|
+
strict: true,
|
|
3123
|
+
options: {
|
|
3124
|
+
help: { type: 'boolean', short: 'h' },
|
|
3125
|
+
json: { type: 'boolean' },
|
|
3126
|
+
plan: { type: 'string' },
|
|
3127
|
+
'out-dir': { type: 'string' },
|
|
3128
|
+
'page-size': { type: 'string' },
|
|
3129
|
+
'timeout-ms': { type: 'string' },
|
|
3130
|
+
},
|
|
3131
|
+
}));
|
|
3132
|
+
}
|
|
3133
|
+
catch (error) {
|
|
3134
|
+
throw new CliError(String(error), {
|
|
3135
|
+
code: 'INVALID_ARGS',
|
|
3136
|
+
exitCode: 2,
|
|
3137
|
+
});
|
|
3138
|
+
}
|
|
3139
|
+
return {
|
|
3140
|
+
help: Boolean(values.help),
|
|
3141
|
+
json: Boolean(values.json),
|
|
3142
|
+
planPath: typeof values.plan === 'string' ? values.plan : '',
|
|
3143
|
+
outDir: typeof values['out-dir'] === 'string' ? values['out-dir'] : undefined,
|
|
3144
|
+
pageSize: parseDatasetMaintenancePositiveInteger(values['page-size'], '--page-size'),
|
|
3145
|
+
timeoutMs: parseDatasetMaintenancePositiveInteger(values['timeout-ms'], '--timeout-ms'),
|
|
3146
|
+
};
|
|
3147
|
+
}
|
|
2969
3148
|
function parseIdentityPreflightFlags(args) {
|
|
2970
3149
|
let values;
|
|
2971
3150
|
try {
|
|
@@ -4711,6 +4890,9 @@ export async function executeCli(argv, deps) {
|
|
|
4711
4890
|
const datasetClassificationAuditImpl = deps.runDatasetClassificationAuditImpl ?? runDatasetClassificationAudit;
|
|
4712
4891
|
const datasetClassificationApplyImpl = deps.runDatasetClassificationApplyImpl ?? runDatasetClassificationApply;
|
|
4713
4892
|
const datasetMaintenanceClearAccountImpl = deps.runDatasetMaintenanceClearAccountImpl ?? runDatasetMaintenanceClearAccount;
|
|
4893
|
+
const datasetMaintenancePlanImpl = deps.runDatasetMaintenancePlanImpl ?? runDatasetMaintenancePlan;
|
|
4894
|
+
const datasetMaintenanceApplyImpl = deps.runDatasetMaintenanceApplyImpl ?? runDatasetMaintenanceApply;
|
|
4895
|
+
const datasetMaintenanceVerifyImpl = deps.runDatasetMaintenanceVerifyImpl ?? runDatasetMaintenanceVerify;
|
|
4714
4896
|
const datasetSourceUploadAttachmentsImpl = deps.runDatasetSourceUploadAttachmentsImpl ?? runDatasetSourceUploadAttachments;
|
|
4715
4897
|
if (flags.version) {
|
|
4716
4898
|
return { exitCode: 0, stdout: `${loadCliPackageVersion(import.meta.url)}\n`, stderr: '' };
|
|
@@ -5320,13 +5502,141 @@ export async function executeCli(argv, deps) {
|
|
|
5320
5502
|
stderr: '',
|
|
5321
5503
|
};
|
|
5322
5504
|
}
|
|
5323
|
-
if (
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5505
|
+
if (action === 'plan') {
|
|
5506
|
+
const datasetFlags = parseDatasetMaintenancePlanFlags(commandArgs.slice(1));
|
|
5507
|
+
if (datasetFlags.help) {
|
|
5508
|
+
return {
|
|
5509
|
+
exitCode: 0,
|
|
5510
|
+
stdout: `${renderDatasetMaintenancePlanHelp()}\n`,
|
|
5511
|
+
stderr: '',
|
|
5512
|
+
};
|
|
5513
|
+
}
|
|
5514
|
+
if (!datasetFlags.scopePath) {
|
|
5515
|
+
throw new CliError('dataset maintenance plan requires --scope.', {
|
|
5516
|
+
code: 'DATASET_MAINTENANCE_SCOPE_REQUIRED',
|
|
5517
|
+
exitCode: 2,
|
|
5518
|
+
});
|
|
5519
|
+
}
|
|
5520
|
+
if (!datasetFlags.operation) {
|
|
5521
|
+
throw new CliError('dataset maintenance plan requires --operation.', {
|
|
5522
|
+
code: 'DATASET_MAINTENANCE_OPERATION_REQUIRED',
|
|
5523
|
+
exitCode: 2,
|
|
5524
|
+
});
|
|
5525
|
+
}
|
|
5526
|
+
if (!datasetFlags.outDir) {
|
|
5527
|
+
throw new CliError('dataset maintenance plan requires --out-dir.', {
|
|
5528
|
+
code: 'DATASET_MAINTENANCE_OUT_DIR_REQUIRED',
|
|
5529
|
+
exitCode: 2,
|
|
5530
|
+
});
|
|
5531
|
+
}
|
|
5532
|
+
const report = await datasetMaintenancePlanImpl({
|
|
5533
|
+
scopePath: datasetFlags.scopePath,
|
|
5534
|
+
operation: datasetFlags.operation,
|
|
5535
|
+
outDir: datasetFlags.outDir,
|
|
5536
|
+
pageSize: datasetFlags.pageSize,
|
|
5537
|
+
timeoutMs: datasetFlags.timeoutMs,
|
|
5538
|
+
env: deps.env,
|
|
5539
|
+
fetchImpl: deps.fetchImpl,
|
|
5540
|
+
});
|
|
5541
|
+
return {
|
|
5542
|
+
exitCode: report.status === 'blocked' ? 1 : 0,
|
|
5543
|
+
stdout: stringifyJson(report, datasetFlags.json),
|
|
5544
|
+
stderr: '',
|
|
5545
|
+
};
|
|
5546
|
+
}
|
|
5547
|
+
if (action === 'apply') {
|
|
5548
|
+
const datasetFlags = parseDatasetMaintenanceApplyFlags(commandArgs.slice(1));
|
|
5549
|
+
if (datasetFlags.help) {
|
|
5550
|
+
return {
|
|
5551
|
+
exitCode: 0,
|
|
5552
|
+
stdout: `${renderDatasetMaintenanceApplyHelp()}\n`,
|
|
5553
|
+
stderr: '',
|
|
5554
|
+
};
|
|
5555
|
+
}
|
|
5556
|
+
if (!datasetFlags.planPath) {
|
|
5557
|
+
throw new CliError('dataset maintenance apply requires --plan.', {
|
|
5558
|
+
code: 'DATASET_MAINTENANCE_PLAN_REQUIRED',
|
|
5559
|
+
exitCode: 2,
|
|
5560
|
+
});
|
|
5561
|
+
}
|
|
5562
|
+
if (datasetFlags.commit && datasetFlags.dryRun) {
|
|
5563
|
+
throw new CliError('Cannot pass both --commit and --dry-run.', {
|
|
5564
|
+
code: 'DATASET_MAINTENANCE_APPLY_MODE_CONFLICT',
|
|
5565
|
+
exitCode: 2,
|
|
5566
|
+
});
|
|
5567
|
+
}
|
|
5568
|
+
if (datasetFlags.dryRun) {
|
|
5569
|
+
throw new CliError('dataset maintenance apply is commit-only; use dataset maintenance plan for a dry run.', {
|
|
5570
|
+
code: 'DATASET_MAINTENANCE_APPLY_COMMIT_ONLY',
|
|
5571
|
+
exitCode: 2,
|
|
5572
|
+
});
|
|
5573
|
+
}
|
|
5574
|
+
if (!datasetFlags.commit) {
|
|
5575
|
+
throw new CliError('dataset maintenance apply requires --commit.', {
|
|
5576
|
+
code: 'DATASET_MAINTENANCE_APPLY_COMMIT_REQUIRED',
|
|
5577
|
+
exitCode: 2,
|
|
5578
|
+
});
|
|
5579
|
+
}
|
|
5580
|
+
if (!datasetFlags.approvePlan) {
|
|
5581
|
+
throw new CliError('dataset maintenance apply requires --approve-plan <sha256>.', {
|
|
5582
|
+
code: 'DATASET_MAINTENANCE_APPROVAL_REQUIRED',
|
|
5583
|
+
exitCode: 2,
|
|
5584
|
+
});
|
|
5585
|
+
}
|
|
5586
|
+
if (!datasetFlags.confirm) {
|
|
5587
|
+
throw new CliError('dataset maintenance apply requires --confirm <email>.', {
|
|
5588
|
+
code: 'DATASET_MAINTENANCE_CONFIRM_REQUIRED',
|
|
5589
|
+
exitCode: 2,
|
|
5590
|
+
});
|
|
5591
|
+
}
|
|
5592
|
+
const report = await datasetMaintenanceApplyImpl({
|
|
5593
|
+
planPath: datasetFlags.planPath,
|
|
5594
|
+
commit: datasetFlags.commit,
|
|
5595
|
+
approvePlan: datasetFlags.approvePlan,
|
|
5596
|
+
confirm: datasetFlags.confirm,
|
|
5597
|
+
timeoutMs: datasetFlags.timeoutMs,
|
|
5598
|
+
env: deps.env,
|
|
5599
|
+
fetchImpl: deps.fetchImpl,
|
|
5327
5600
|
});
|
|
5601
|
+
return {
|
|
5602
|
+
exitCode: report.status === 'completed_with_failures' ? 1 : 0,
|
|
5603
|
+
stdout: stringifyJson(report, datasetFlags.json),
|
|
5604
|
+
stderr: '',
|
|
5605
|
+
};
|
|
5328
5606
|
}
|
|
5329
|
-
|
|
5607
|
+
if (action === 'verify') {
|
|
5608
|
+
const datasetFlags = parseDatasetMaintenanceVerifyFlags(commandArgs.slice(1));
|
|
5609
|
+
if (datasetFlags.help) {
|
|
5610
|
+
return {
|
|
5611
|
+
exitCode: 0,
|
|
5612
|
+
stdout: `${renderDatasetMaintenanceVerifyHelp()}\n`,
|
|
5613
|
+
stderr: '',
|
|
5614
|
+
};
|
|
5615
|
+
}
|
|
5616
|
+
if (!datasetFlags.planPath) {
|
|
5617
|
+
throw new CliError('dataset maintenance verify requires --plan.', {
|
|
5618
|
+
code: 'DATASET_MAINTENANCE_PLAN_REQUIRED',
|
|
5619
|
+
exitCode: 2,
|
|
5620
|
+
});
|
|
5621
|
+
}
|
|
5622
|
+
const report = await datasetMaintenanceVerifyImpl({
|
|
5623
|
+
planPath: datasetFlags.planPath,
|
|
5624
|
+
outDir: datasetFlags.outDir,
|
|
5625
|
+
pageSize: datasetFlags.pageSize,
|
|
5626
|
+
timeoutMs: datasetFlags.timeoutMs,
|
|
5627
|
+
env: deps.env,
|
|
5628
|
+
fetchImpl: deps.fetchImpl,
|
|
5629
|
+
});
|
|
5630
|
+
return {
|
|
5631
|
+
exitCode: report.status === 'failed' ? 1 : 0,
|
|
5632
|
+
stdout: stringifyJson(report, datasetFlags.json),
|
|
5633
|
+
stderr: '',
|
|
5634
|
+
};
|
|
5635
|
+
}
|
|
5636
|
+
throw new CliError("dataset maintenance action must be 'clear-account', 'plan', 'apply', or 'verify'.", {
|
|
5637
|
+
code: 'DATASET_MAINTENANCE_ACTION_INVALID',
|
|
5638
|
+
exitCode: 2,
|
|
5639
|
+
});
|
|
5330
5640
|
}
|
|
5331
5641
|
if (command === 'lifecyclemodel' && !subcommand) {
|
|
5332
5642
|
return { exitCode: 0, stdout: `${renderLifecyclemodelHelp()}\n`, stderr: '' };
|