@tiangong-lca/cli 0.0.32 → 0.1.0

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 (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -12
  3. package/assets/import-smoke/simapro.csv +20 -0
  4. package/bin/tiangong-lca.js +1 -1
  5. package/dist/src/cli.js +103 -65
  6. package/dist/src/cli.js.map +1 -1
  7. package/dist/src/lib/dataset-bilingual.js.map +1 -1
  8. package/dist/src/lib/dataset-classification.js.map +1 -1
  9. package/dist/src/lib/dataset-contract.js.map +1 -1
  10. package/dist/src/lib/dataset-evidence-search.js.map +1 -1
  11. package/dist/src/lib/dataset-import-lca.js +302 -131
  12. package/dist/src/lib/dataset-import-lca.js.map +1 -1
  13. package/dist/src/lib/dataset-maintenance-apply.js +916 -43
  14. package/dist/src/lib/dataset-maintenance-apply.js.map +1 -1
  15. package/dist/src/lib/dataset-maintenance-clear-account.js +10 -4
  16. package/dist/src/lib/dataset-maintenance-clear-account.js.map +1 -1
  17. package/dist/src/lib/dataset-maintenance-contract.js +1 -6
  18. package/dist/src/lib/dataset-maintenance-contract.js.map +1 -1
  19. package/dist/src/lib/dataset-maintenance-derivatives.js +0 -1
  20. package/dist/src/lib/dataset-maintenance-derivatives.js.map +1 -1
  21. package/dist/src/lib/dataset-maintenance-flow-identity-capture.js +1 -0
  22. package/dist/src/lib/dataset-maintenance-flow-identity-capture.js.map +1 -1
  23. package/dist/src/lib/dataset-maintenance-pagination.js.map +1 -1
  24. package/dist/src/lib/dataset-maintenance-protected-before.js.map +1 -1
  25. package/dist/src/lib/dataset-maintenance-protected-contract.js +0 -1
  26. package/dist/src/lib/dataset-maintenance-protected-contract.js.map +1 -1
  27. package/dist/src/lib/dataset-maintenance-protected-freeze.js.map +1 -1
  28. package/dist/src/lib/dataset-maintenance-protected-preparation.js +0 -2
  29. package/dist/src/lib/dataset-maintenance-protected-preparation.js.map +1 -1
  30. package/dist/src/lib/dataset-maintenance-protected-seal.js.map +1 -1
  31. package/dist/src/lib/dataset-maintenance-protected-verify.js +0 -3
  32. package/dist/src/lib/dataset-maintenance-protected-verify.js.map +1 -1
  33. package/dist/src/lib/dataset-maintenance-remote.js +68 -12
  34. package/dist/src/lib/dataset-maintenance-remote.js.map +1 -1
  35. package/dist/src/lib/dataset-maintenance-verify.js +1 -2
  36. package/dist/src/lib/dataset-maintenance-verify.js.map +1 -1
  37. package/dist/src/lib/dataset-remote-refresh.js.map +1 -1
  38. package/dist/src/lib/dataset-remote-verify.js +2 -0
  39. package/dist/src/lib/dataset-remote-verify.js.map +1 -1
  40. package/dist/src/lib/dataset-save-draft-run.js +2 -0
  41. package/dist/src/lib/dataset-save-draft-run.js.map +1 -1
  42. package/dist/src/lib/flow-build-alias-map.js.map +1 -1
  43. package/dist/src/lib/flow-fetch-rows.js.map +1 -1
  44. package/dist/src/lib/flow-get.js.map +1 -1
  45. package/dist/src/lib/flow-governance.js.map +1 -1
  46. package/dist/src/lib/flow-list.js +1 -0
  47. package/dist/src/lib/flow-list.js.map +1 -1
  48. package/dist/src/lib/flow-payload-validation.js.map +1 -1
  49. package/dist/src/lib/flow-publish-version.js +1 -0
  50. package/dist/src/lib/flow-publish-version.js.map +1 -1
  51. package/dist/src/lib/flow-read.js +1 -0
  52. package/dist/src/lib/flow-read.js.map +1 -1
  53. package/dist/src/lib/flow-regen-product.js.map +1 -1
  54. package/dist/src/lib/flow-remediate.js.map +1 -1
  55. package/dist/src/lib/identity-preflight.js +4 -10
  56. package/dist/src/lib/identity-preflight.js.map +1 -1
  57. package/dist/src/lib/lifecyclemodel-bundle-save.js +1 -0
  58. package/dist/src/lib/lifecyclemodel-bundle-save.js.map +1 -1
  59. package/dist/src/lib/lifecyclemodel-orchestrate.js.map +1 -1
  60. package/dist/src/lib/lifecyclemodel-publish-resulting-process.js.map +1 -1
  61. package/dist/src/lib/lifecyclemodel-resulting-process.js.map +1 -1
  62. package/dist/src/lib/lifecyclemodel-save-draft-run.js.map +1 -1
  63. package/dist/src/lib/lifecyclemodel-validate-build.js.map +1 -1
  64. package/dist/src/lib/package-version.js.map +1 -1
  65. package/dist/src/lib/process-auto-build.js.map +1 -1
  66. package/dist/src/lib/process-dedup-review.js +14 -7
  67. package/dist/src/lib/process-dedup-review.js.map +1 -1
  68. package/dist/src/lib/process-flow-build-plan.js +111 -30
  69. package/dist/src/lib/process-flow-build-plan.js.map +1 -1
  70. package/dist/src/lib/process-get.js +1 -0
  71. package/dist/src/lib/process-get.js.map +1 -1
  72. package/dist/src/lib/process-list.js +1 -0
  73. package/dist/src/lib/process-list.js.map +1 -1
  74. package/dist/src/lib/process-payload-validation.js.map +1 -1
  75. package/dist/src/lib/process-qa.js.map +1 -1
  76. package/dist/src/lib/process-refresh-references.js +15 -10
  77. package/dist/src/lib/process-refresh-references.js.map +1 -1
  78. package/dist/src/lib/process-save-draft.js +9 -3
  79. package/dist/src/lib/process-save-draft.js.map +1 -1
  80. package/dist/src/lib/process-scope-statistics.js +11 -4
  81. package/dist/src/lib/process-scope-statistics.js.map +1 -1
  82. package/dist/src/lib/process-verify-rows.js.map +1 -1
  83. package/dist/src/lib/publish.js.map +1 -1
  84. package/dist/src/lib/run.js.map +1 -1
  85. package/dist/src/lib/supabase-client.js +13 -1
  86. package/dist/src/lib/supabase-client.js.map +1 -1
  87. package/dist/src/lib/supabase-data-api-contract.js +328 -0
  88. package/dist/src/lib/supabase-data-api-contract.js.map +1 -0
  89. package/dist/src/lib/supabase-data-api-replay.js +69 -0
  90. package/dist/src/lib/supabase-data-api-replay.js.map +1 -0
  91. package/dist/src/lib/supabase-json-ordered-write.js +2 -0
  92. package/dist/src/lib/supabase-json-ordered-write.js.map +1 -1
  93. package/dist/src/lib/supabase-rest.js +1 -0
  94. package/dist/src/lib/supabase-rest.js.map +1 -1
  95. package/dist/src/lib/tidas-sdk-package-validator.js +5 -5
  96. package/dist/src/lib/tidas-sdk-package-validator.js.map +1 -1
  97. package/dist/src/lib/validation.js.map +1 -1
  98. package/dist/src/main.js.map +1 -1
  99. package/package.json +40 -40
  100. package/dist/scripts/assert-full-coverage.js +0 -77
  101. package/dist/scripts/assert-full-coverage.js.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) TianGong LCA contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -14,18 +14,27 @@ whenToUpdate:
14
14
  checkPaths:
15
15
  - README.md
16
16
  - package.json
17
+ - pnpm-workspace.yaml
18
+ - pnpm-lock.yaml
17
19
  - bin/**
18
20
  - src/cli.ts
19
21
  - src/main.ts
20
22
  - src/lib/lca-release.ts
21
23
  - test/lca-release*.test.ts
22
- lastReviewedAt: 2026-07-23
23
- lastReviewedCommit: 5c90ddd60328748ab6d8d89717e59dcaeca8cde7
24
+ lastReviewedAt: 2026-08-25
25
+ lastReviewedCommit: 9078fe123e5909b680f27af1af1d2018bcd02826
26
+ lastReviewedNote: 'Reviewed for Issue #226: the public package guide identifies the 0.1.0 pnpm/TypeScript 7 compatibility release while the tarball remains package-manager neutral.'
24
27
  ---
25
28
 
26
29
  # TianGong LCA CLI
27
30
 
28
- Package: `@tiangong-lca/cli` Executable: `tiangong-lca` Node: `24.x`
31
+ Package: `@tiangong-lca/cli` Executable: `tiangong-lca` Current package version: `0.1.0` Node: `24.x`
32
+
33
+ Repository development is single-track on pnpm `11.23.0` and TypeScript `7.0.2`. The published package remains a clean, package-manager-neutral consumer artifact: it contains runtime files only, not pnpm, TypeScript, Oxlint, tests, source-only tooling, or repository lockfiles.
34
+
35
+ Review note, 2026-08-25: Issue #224 migrates repository development and release automation to the sole root `pnpm-workspace.yaml` / `pnpm-lock.yaml`, TypeScript 7.0.2, and type-aware Oxlint on Node 24. The feature change deliberately keeps version 0.0.33. A separate release-only PR should prepare 0.1.0 after the toolchain change merges and its full package/coverage/release gates pass.
36
+
37
+ Review note, 2026-08-25: Issue #226 publishes that 0.1.0 compatibility boundary after merged PR #225. Version metadata and public release evidence advance to 0.1.0; the runtime JavaScript/assets surface, command behavior, Node 24 runtime, pnpm/TypeScript 7 development baseline, native pnpm Trusted Publishing/provenance, and exact released-commit workspace handoff remain unchanged from the reviewed feature delivery.
29
38
 
30
39
  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.
31
40
 
@@ -45,20 +54,26 @@ Review note, 2026-07-23: `dataset save-draft --execution-contract` adds an opt-i
45
54
 
46
55
  Review note, 2026-07-24: CLI 0.0.32 adds bounded execution-contract concurrency without changing the sealed payload or replay model. `--max-parallel 1..8` keeps the complete dependency prefix serial and exact-read-back, then overlaps only the unique-target suffix. The current owner token is renewed and revalidated before each DML dispatch so long batches do not turn token expiry into an avoidable UNKNOWN.
47
56
 
57
+ Review note, 2026-07-24: CLI 0.0.33 adds an explicit `dataset maintenance apply --max-parallel 1..8` profile for large owner-draft flow convergence. It accepts only unique flow delete-only plans with zero frozen and fresh visible-process inbound references, persists `PREPARED` and `DISPATCHED` before each protected RPC, requires exact absent readback for `COMMITTED`, never automatically replays success or UNKNOWN, and continues independent rows.
58
+
59
+ Review note, 2026-07-25: The complete RLS-visible process fence now paginates in the strict `(id, version)` primary-key order. It still has no `user_id` filter and retains exact-count completeness, while avoiding a redundant owner/state sort before any deletion can dispatch.
60
+
61
+ Review note, 2026-07-25: Bounded flow deletion can instead accept an explicitly SHA-approved, at-most-30-minute-old SELECT-only proof covering all process rows. The proof binds the exact project, actor, plan, ordered delete targets, and contiguous target chunks and must report zero inbound edges and zero P0/P1 findings. The CLI validates it before approval or dispatch and never executes the proof SQL itself; omitting the flags preserves the live RLS-visible scan.
62
+
48
63
  ## Run
49
64
 
50
65
  One-off published run:
51
66
 
52
67
  ```bash
53
- npm exec --yes --package=@tiangong-lca/cli@latest -- tiangong-lca --help
54
- npm exec --yes --package=@tiangong-lca/cli@latest -- tiangong-lca doctor
55
- npm exec --yes --package=@tiangong-lca/cli@latest -- tiangong-lca flow --help
68
+ pnpm dlx @tiangong-lca/cli@latest --help
69
+ pnpm dlx @tiangong-lca/cli@latest doctor
70
+ pnpm dlx @tiangong-lca/cli@latest flow --help
56
71
  ```
57
72
 
58
73
  Install the published CLI:
59
74
 
60
75
  ```bash
61
- npm install --global @tiangong-lca/cli
76
+ pnpm add --global @tiangong-lca/cli
62
77
  tiangong-lca --help
63
78
  tiangong-lca doctor
64
79
  tiangong-lca flow --help
@@ -67,8 +82,8 @@ tiangong-lca flow --help
67
82
  Run from this repository:
68
83
 
69
84
  ```bash
70
- npm ci
71
- npm run build
85
+ pnpm install --frozen-lockfile
86
+ pnpm build
72
87
  node ./bin/tiangong-lca.js --help
73
88
  ```
74
89
 
@@ -253,7 +268,7 @@ Key outputs under `--out-dir`:
253
268
 
254
269
  `--candidate-input` is repeatable and accepts JSON, JSONL, or a directory scanned recursively for JSON/JSONL candidate rows. Embedded `candidates` from the request and local-scan candidates are evaluated together. Add `--remote-candidates` when the preflight should also call `process_hybrid_search` or `flow_hybrid_search`; `--remote-query` overrides the target-derived search text and `--remote-limit` caps returned candidate rows. Remote candidate search uses the normal Supabase session env: `TIANGONG_LCA_API_BASE_URL`, `TIANGONG_LCA_API_KEY`, `TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY`, and optional `TIANGONG_LCA_REGION`.
255
270
 
256
- When remote search is enabled, the CLI sends a compact fielded `query` string plus supported edge-search options to `process_hybrid_search` or `flow_hybrid_search`: `filter`, `match_count`, `page_size`, `data_source`, `match_threshold`, `full_text_weight`, `extracted_text_weight`, `semantic_weight`, and `rrf_k`. Request-level `remote_candidate_search.profile_hints` are not sent to the Edge Function. They are applied locally before scoring candidates so Foundry can provide source-derived facts such as flow type, flow property, reference unit, elementary categories, geography, reference-flow names, technology route, and system boundary without polluting the full-text/semantic query.
271
+ When remote search is enabled, the CLI sends a compact fielded `query` string plus supported edge-search options to `process_hybrid_search` or `flow_hybrid_search`: `filter`, `match_count`, `page_size`, `data_source`, `match_threshold`, `lexical_weight`, `semantic_weight`, and `rrf_k`. `lexical_weight` controls the single database-owned `extracted_md` lexical branch. Request-level `remote_candidate_search.profile_hints` are not sent to the Edge Function. They are applied locally before scoring candidates so Foundry can provide source-derived facts such as flow type, flow property, reference unit, elementary categories, geography, reference-flow names, technology route, and system boundary without polluting the full-text/semantic query.
257
272
 
258
273
  Exact process exchange fingerprints with matching identity context block duplicate creation, while weaker inventory-only matches still route to manual review. Flow preflight also blocks alias-equivalent flows when type, reference property, unit, and category/CAS evidence match.
259
274
 
@@ -268,7 +283,7 @@ tiangong-lca flow build-plan validate --input ./flow-build-plan.json --out-dir .
268
283
  tiangong-lca flow build-plan materialize --input ./flow-build-plan.json --out-dir ./flow-build-plan --json
269
284
  ```
270
285
 
271
- The minimum plan contract requires an automatic identity decision, EvidenceManifest sources and field bindings, name plan, and the relevant process reference-flow or flow-property fields. Process materialization carries name, quantitative reference, exchange, source evidence, modelling, administrative, and annual supply/production fields from the plan into `processDataSet`; when annual volume source evidence is not explicit, Foundry-facing required-field completion uses the deterministic `9999 missing-data-sentinel/year` value so the schema-required field stays searchable for later database-side curation. Flow materialization carries name, flow type, reference property, source evidence, administrative, and classification fields into `flowDataSet`. `--report-only` keeps exit code `0` while still reporting blockers.
286
+ The minimum plan contract requires an automatic identity decision, EvidenceManifest sources and field bindings, name plan, and the relevant process reference-flow or flow-property fields. Plan-only materialization additionally requires an explicit canonical `classification_path`: continuous level `0..n` objects with exact locked `@classId`/`#text` for process and product/waste flow taxonomies, or `@catId`/`#text` for elementary flows. Label-only, missing, malformed, or taxonomy-spoofed classifications fail before artifact publication. Process materialization carries name, quantitative reference, exchange, source evidence, modelling, administrative, and annual supply/production fields from the plan into `processDataSet`; when annual volume source evidence is not explicit, Foundry-facing required-field completion uses the deterministic `9999 missing-data-sentinel/year` value so the schema-required field stays searchable for later database-side curation. Flow materialization carries name, flow type, reference property, source evidence, administrative, and classification fields into `flowDataSet`. `--report-only` keeps exit code `0` while still reporting blockers.
272
287
 
273
288
  Key outputs under `--out-dir`:
274
289
 
@@ -367,6 +382,7 @@ tiangong-lca dataset classification apply --type location --input ./rows/process
367
382
  tiangong-lca dataset curation-queue build --processes ./rows/processes.jsonl --flows ./rows/flows.jsonl --support ./rows/sources.jsonl --out-dir /abs/path/to/curation-queue --json
368
383
  tiangong-lca dataset curation-queue next --queue-dir /abs/path/to/curation-queue --type support --json
369
384
  tiangong-lca dataset curation-queue verify --queue-dir /abs/path/to/curation-queue --type process --json
385
+ tiangong-lca dataset import-lca convert --input ./external/simapro.csv --output-dir /abs/path/to/imported --from-format simapro-csv --target both --write-mapping --json
370
386
  tiangong-lca dataset save-draft --input ./rows.jsonl --type auto --execution-contract ./execution-contract.json --max-parallel 8 --out-dir /abs/path/to/dataset-save-draft --commit --json
371
387
  tiangong-lca dataset evidence-search plan --query "中国2026年电力结构数据" --out-dir /abs/path/to/evidence-search --json
372
388
  tiangong-lca dataset evidence-search run --input ./evidence-search.request.json --results ./search-results.json --out-dir /abs/path/to/evidence-search --json
@@ -374,6 +390,7 @@ tiangong-lca dataset references rewrite --input ./rows.jsonl --from flow:<old-id
374
390
  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
375
391
  tiangong-lca dataset maintenance plan --scope ./derivative-rebuild-scope.json --operation rebuild-derivatives --out-dir /abs/path/to/derivative-rebuild --json
376
392
  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
393
+ tiangong-lca dataset maintenance apply --plan /abs/path/to/flow-delete-maintenance/maintenance-plan.json --commit --approve-plan <sha256> --confirm <current-account-email> --max-parallel 8 --timeout-ms 10000 --json
377
394
  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
378
395
  tiangong-lca dataset maintenance run-protected --plan /abs/path/to/maintenance-plan.json --freeze /abs/path/to/protected-execution-freeze.json --approval /abs/path/to/protected-approval.json --out-dir /abs/path/to/protected-run --status-only --json
379
396
  tiangong-lca lifecyclemodel auto-build --input ./examples/lifecyclemodel-auto-build.request.json --out-dir /abs/path/to/lifecyclemodel-run --json
@@ -398,12 +415,14 @@ For `qa process`, `--rows-file` accepts either raw process rows as JSON/JSONL or
398
415
 
399
416
  For `process identity-preflight` and `flow identity-preflight`, canonical TIDAS wrappers are schema-checked when present. Loose target objects are accepted for early planning and produce `schema_validation.status: "not_applicable"` until materialization. Candidate rows can be embedded in the request, loaded from repeatable `--candidate-input` local files/directories, or fetched through explicit `--remote-candidates` hybrid search; `identity-candidate-sources.json` records scanned files, remote endpoints, queries, filters, edge-search options, and row counts. The remote Edge Function receives only search-safe query/options fields; local-only `profile_hints` stay in the preflight target profile and candidate scoring evidence.
400
417
 
401
- For `process build-plan` and `flow build-plan`, canonical payloads embedded in the plan are schema-checked during `materialize`. Plan-only materialization now creates deterministic canonical `processDataSet` / `flowDataSet` wrappers from the build plan and validates them with the TIDAS SDK before reporting `passed`.
418
+ For `process build-plan` and `flow build-plan`, canonical payloads embedded in the plan are schema-checked during `materialize`. Plan-only materialization creates deterministic canonical `processDataSet` / `flowDataSet` wrappers, requires an explicit canonical locked-taxonomy `classification_path`, and validates the result with the TIDAS SDK before reporting `passed`; it never invents taxonomy ids from free-form labels.
402
419
 
403
420
  For `process save-draft`, canonical process payloads are validated locally with `ProcessSchema` before any `--commit` write. Schema-invalid rows remain in `outputs/save-draft-rpc/failures.jsonl` instead of being persisted. Batch import callers should pass `--target-user-id`; the CLI then verifies the current auth session and any visible draft owner before writing, while downstream readback verification still proves the final owner and payload.
404
421
 
405
422
  For `dataset save-draft --execution-contract`, the JSON contract uses schema `dataset-save-draft-execution-contract.v1` and supplies `execution_id`, `project_ref`, an exact owner (`user_id`, lowercase `email`, `state_code: 0`), and ordered actions. Each action binds `action_id`, `desired_sha256`, `expected_operation` (`insert` or `save_draft`), table/id/version, `before_sha256`, and earlier `dependency_action_ids`. Contract mode requires `--commit`; account-local Unit Group or Flow Property support rows additionally require `--allow-account-local-support`. `--max-parallel` defaults to 1 and is capped at 8. When it is greater than 1, every action through the highest referenced dependency remains serial; only the later table/id/version-unique suffix may overlap. The exact owner token is renewed and checked before each DML dispatch. Attempts and outcomes are stored under the platform user-state directory (`$XDG_STATE_HOME/tiangong-lca-cli` when configured), not beside the contract or report. Any prior terminal or unresolved attempt is read back or retained without re-dispatch; exit status is nonzero unless every action has exact terminal success.
406
423
 
424
+ For `dataset maintenance apply`, explicitly passing `--max-parallel 1..8` opts into the destructive flow-convergence profile. It accepts only a non-empty, unique-target, flow delete-only plan whose current and projected reference impacts are both zero. Before dispatch it completes a fresh SELECT-only scan of every process visible to the owner session and rejects any inbound edge. For a separately governed all-process check, pair `--global-inbound-proof /absolute/proof.json` with `--approve-global-inbound-proof <sha256>`; the proof must be fresh, SELECT-only, complete, zero-inbound, and bound to the exact project, actor, plan, and ordered target set, and it is validated before the live scan is skipped. The CLI never runs raw SQL. Each action writes append-only `PREPARED` and `DISPATCHED` evidence before its protected owner-session RPC, then records `COMMITTED` only after exact absent readback. An ambiguous action is read back, marked `UNKNOWN`, and never replayed automatically; independent actions continue. Omit `--max-parallel` to retain ordinary maintenance apply behavior.
425
+
407
426
  For `flow publish-version`, canonical flow payloads are validated locally with `FlowSchema` before remote visibility planning or writes. The command always writes `flow-publish-version-gate-report.json`; blocked rows are written to the remote-failure JSONL without calling the remote service.
408
427
 
409
428
  For `process publish-build`, canonical process payloads are validated locally with `ProcessSchema` before publish handoff artifacts are written. The gate report is `reports/process-publish-schema-gate.json`.
@@ -418,6 +437,8 @@ For `dataset validate`, `--type auto` supports mixed support scopes containing c
418
437
 
419
438
  For `dataset curation-queue build/next/verify`, the CLI owns entity-level Foundry import queue state. `build` writes `outputs/curation-queue-manifest.json`, `outputs/curation-queue-tasks.jsonl`, `outputs/curation-queue-locks.json`, `outputs/curation-queue-blockers.jsonl`, and per-entity `input.jsonl`, `closure.json`, and `entity-run-plan.json`. `next` returns one runnable support/flow/process task based on checkpoint state. `verify` passes only when scoped checkpoints are complete and build blockers are absent. AI authoring must return structured patches or build plans, and remote writes remain gated by deterministic apply, schema/QA, prewrite verify, and readback.
420
439
 
440
+ For `dataset import-lca convert`, the CLI delegates all format detection, conversion, validation, bounded spooling, cancellation, and atomic publication to unified Rust `tidas import`; it does not reproduce import logic in TypeScript. Binary selection is `--tidas-bin`, then `TIDAS_BIN`, then `tidas` on PATH. Optional `--tidas-config` maps to native `--config`. Every run first requires a successful `tidas version --format json --progress never` handshake with `tidas.operation-report.v1` and a stable `0.2.x` binary version, then validates the native `tidas.import-execution-report.v1` summary and exact exit-class/code mapping. Native controls include explicit or automatic source format, target, mapping output, process-bundle disablement, warning failure, maximum entry size, memory budget, and queue capacity. The supported release matrix is Linux x86_64/ARM64, macOS Intel/Apple Silicon, and Windows x86_64; Windows ARM64 is unsupported. The npm package includes `assets/import-smoke/simapro.csv` for clean-machine proof but does not bundle a platform binary or require Python.
441
+
421
442
  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.
422
443
 
423
444
  ## Dataset Maintenance
@@ -0,0 +1,20 @@
1
+ {SimaPro 8.0}
2
+ {processes}
3
+ {CSV separator: Semicolon}
4
+ {Decimal separator: ,}
5
+
6
+ Process
7
+
8
+ Process name
9
+ Test process
10
+
11
+ Products
12
+ my product;kg;0,5;100;not defined;Agricultural;
13
+
14
+ Materials/fuels
15
+ Soy oil, refined, at plant/kg/RNA;kg;0,2;Undefined;0;0;0;
16
+
17
+ Emissions to air
18
+ carbon dioxide;low. pop.;kg;1,5;Undefined;0;0;0;
19
+
20
+ End
@@ -24,7 +24,7 @@ export function resolveInvokedUrl(argv1 = process.argv[1]) {
24
24
  export async function runFromBin(argv = process.argv.slice(2), env = process.env) {
25
25
  if (!existsSync(entryPath)) {
26
26
  throw new Error(
27
- "Missing built CLI artifacts at 'dist/src/main.js'. Run 'npm run build' or reinstall dependencies to regenerate dist.",
27
+ "Missing built CLI artifacts at 'dist/src/main.js'. Run 'pnpm build' or reinstall dependencies to regenerate dist.",
28
28
  );
29
29
  }
30
30
 
package/dist/src/cli.js CHANGED
@@ -335,7 +335,7 @@ Implemented Subcommands:
335
335
  curation-queue build Build entity-level AI curation queue artifacts for Foundry imports
336
336
  curation-queue next Return the next runnable support/flow/process queue task
337
337
  curation-queue verify Verify queue task checkpoints for a scope
338
- import-lca convert Convert supported external LCA packages through tidas-tools
338
+ import-lca convert Import supported external LCA packages through the unified Rust tidas binary
339
339
  author Extract source evidence and prepare TIDAS context packs for AI authoring
340
340
  patch apply Apply AI-authored structured dataset patches deterministically
341
341
  save-draft Save contact/source/support or other canonical dataset rows through the platform dataset command path
@@ -536,6 +536,9 @@ Options:
536
536
  --approve-plan <sha256> Exact SHA-256 recorded for the plan
537
537
  --confirm <email> Current authenticated account email
538
538
  --timeout-ms <n> Request timeout in milliseconds
539
+ --max-parallel <1-8> Opt into bounded flow delete-only execution with durable dispatch ledger
540
+ --global-inbound-proof <file> Absolute path to a fresh all-process SELECT-only zero-inbound proof
541
+ --approve-global-inbound-proof <sha256> Exact SHA-256 of --global-inbound-proof; requires --max-parallel
539
542
  --json Print compact JSON
540
543
  -h, --help
541
544
 
@@ -832,30 +835,33 @@ function renderDatasetImportLcaHelp() {
832
835
 
833
836
  Options:
834
837
  --input <path> Source file, directory, or package to import
835
- --output-dir <dir> Output directory for generated package and reports
838
+ --output-dir <dir> Output directory atomically published by tidas
836
839
  --from-format <format> auto, ecospold1, ecospold2, openlca-jsonld, openlca-process-xlsx, simapro-csv, ilcd
837
840
  --target <target> tidas | ilcd | both (default: tidas)
838
- --report <file> Conversion report path (default: <output-dir>/conversion-report.json)
839
- --mapping-dir <dir> Optional custom mapping/reference data directory
840
- --language <lang> Default language for generated text (default: en)
841
- --validation-jobs <n> Parallel validation jobs passed to tidas-tools (default: 1)
842
- --process-bundles Write per-process dependency bundles (default: enabled by tidas-tools)
843
- --process-bundles-dir <dir>
844
- Custom per-process bundle directory (default: <output-dir>/process-bundles)
841
+ --report <file> Persist the native operation report atomically instead of using tidas stdout
842
+ --write-mapping Write deterministic mapping.csv.gz
845
843
  --no-process-bundles Disable per-process dependency bundle generation
846
- --detect-only Only detect the input format and write the report
847
844
  --fail-on-warning Return non-zero when converter warnings are present
848
- --python <bin> Python executable (default: python3)
849
- --tidas-tools-dir <dir> Explicit tidas-tools checkout path
845
+ --max-entry-mib <n> Maximum source-entry size in MiB (tidas default: 128)
846
+ --memory-budget-mib <n> Maximum accounted in-flight memory in MiB (tidas default: 512)
847
+ --queue-capacity <n> Maximum items in each bounded queue (tidas default: 256)
848
+ --tidas-bin <path> Rust tidas executable (default: TIDAS_BIN, then tidas on PATH)
849
+ --tidas-config <path> Explicit tidas config file (otherwise TIDAS_CONFIG is honored)
850
850
  --json Print compact JSON
851
851
  -h, --help
852
852
 
853
853
  Outputs written under --output-dir:
854
- - conversion-report.json
855
- - tidas/ when target includes TIDAS and not detect-only
856
- - ilcd/ when target includes ILCD and not detect-only
857
- - process-bundles/ when not detect-only and process bundles are enabled
858
- - outputs/import-lca-report.json
854
+ - import-report.json and issues.jsonl
855
+ - tidas/ when target includes TIDAS
856
+ - ilcd/ when target includes ILCD
857
+ - process-bundles/ by default
858
+ - mapping.csv.gz when --write-mapping is used
859
+
860
+ Runtime contract:
861
+ - Linux x86_64/ARM64, macOS Intel/Apple Silicon, and Windows x86_64 are supported.
862
+ - Windows ARM64 is unsupported.
863
+ - The binary must report tidas.operation-report.v1 and a stable 0.2.x version.
864
+ - Import publication, cancellation cleanup, and domain validation remain owned by Rust tidas.
859
865
  `.trim();
860
866
  }
861
867
  function renderDatasetAuthorHelp() {
@@ -2853,16 +2859,14 @@ function parseDatasetImportLcaConvertFlags(args) {
2853
2859
  'from-format': { type: 'string' },
2854
2860
  target: { type: 'string' },
2855
2861
  report: { type: 'string' },
2856
- 'mapping-dir': { type: 'string' },
2857
- language: { type: 'string' },
2858
- 'validation-jobs': { type: 'string' },
2859
- 'process-bundles': { type: 'boolean' },
2860
- 'process-bundles-dir': { type: 'string' },
2862
+ 'write-mapping': { type: 'boolean' },
2861
2863
  'no-process-bundles': { type: 'boolean' },
2862
- 'detect-only': { type: 'boolean' },
2863
2864
  'fail-on-warning': { type: 'boolean' },
2864
- python: { type: 'string' },
2865
- 'tidas-tools-dir': { type: 'string' },
2865
+ 'max-entry-mib': { type: 'string' },
2866
+ 'memory-budget-mib': { type: 'string' },
2867
+ 'queue-capacity': { type: 'string' },
2868
+ 'tidas-bin': { type: 'string' },
2869
+ 'tidas-config': { type: 'string' },
2866
2870
  },
2867
2871
  }));
2868
2872
  }
@@ -2872,25 +2876,9 @@ function parseDatasetImportLcaConvertFlags(args) {
2872
2876
  exitCode: 2,
2873
2877
  });
2874
2878
  }
2875
- const validationJobs = typeof values['validation-jobs'] === 'string' ? Number(values['validation-jobs']) : undefined;
2876
- if (validationJobs !== undefined && (!Number.isInteger(validationJobs) || validationJobs < 0)) {
2877
- throw new CliError('--validation-jobs must be a non-negative integer.', {
2878
- code: 'DATASET_IMPORT_LCA_VALIDATION_JOBS_INVALID',
2879
- exitCode: 2,
2880
- });
2881
- }
2882
- if (values['process-bundles'] && values['no-process-bundles']) {
2883
- throw new CliError('--process-bundles and --no-process-bundles cannot both be set.', {
2884
- code: 'DATASET_IMPORT_LCA_PROCESS_BUNDLES_INVALID',
2885
- exitCode: 2,
2886
- });
2887
- }
2888
- if (values['no-process-bundles'] && typeof values['process-bundles-dir'] === 'string') {
2889
- throw new CliError('--process-bundles-dir cannot be used with --no-process-bundles.', {
2890
- code: 'DATASET_IMPORT_LCA_PROCESS_BUNDLES_INVALID',
2891
- exitCode: 2,
2892
- });
2893
- }
2879
+ const maxEntryMib = parsePositiveIntegerFlag(values['max-entry-mib'], '--max-entry-mib');
2880
+ const memoryBudgetMib = parsePositiveIntegerFlag(values['memory-budget-mib'], '--memory-budget-mib');
2881
+ const queueCapacity = parsePositiveIntegerFlag(values['queue-capacity'], '--queue-capacity');
2894
2882
  return {
2895
2883
  help: Boolean(values.help),
2896
2884
  json: Boolean(values.json),
@@ -2899,21 +2887,29 @@ function parseDatasetImportLcaConvertFlags(args) {
2899
2887
  fromFormat: typeof values['from-format'] === 'string' ? values['from-format'] : undefined,
2900
2888
  target: typeof values.target === 'string' ? values.target : undefined,
2901
2889
  reportPath: typeof values.report === 'string' ? values.report : undefined,
2902
- mappingDir: typeof values['mapping-dir'] === 'string' ? values['mapping-dir'] : undefined,
2903
- language: typeof values.language === 'string' ? values.language : undefined,
2904
- validationJobs,
2905
- processBundles: values['no-process-bundles']
2906
- ? false
2907
- : values['process-bundles']
2908
- ? true
2909
- : undefined,
2910
- processBundlesDir: typeof values['process-bundles-dir'] === 'string' ? values['process-bundles-dir'] : undefined,
2911
- detectOnly: Boolean(values['detect-only']),
2890
+ writeMapping: Boolean(values['write-mapping']),
2891
+ processBundles: values['no-process-bundles'] ? false : undefined,
2912
2892
  failOnWarning: Boolean(values['fail-on-warning']),
2913
- pythonBin: typeof values.python === 'string' ? values.python : undefined,
2914
- tidasToolsDir: typeof values['tidas-tools-dir'] === 'string' ? values['tidas-tools-dir'] : undefined,
2893
+ maxEntryMib,
2894
+ memoryBudgetMib,
2895
+ queueCapacity,
2896
+ tidasBin: typeof values['tidas-bin'] === 'string' ? values['tidas-bin'] : undefined,
2897
+ tidasConfig: typeof values['tidas-config'] === 'string' ? values['tidas-config'] : undefined,
2915
2898
  };
2916
2899
  }
2900
+ function parsePositiveIntegerFlag(value, flag) {
2901
+ if (typeof value !== 'string') {
2902
+ return undefined;
2903
+ }
2904
+ const parsed = Number(value);
2905
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
2906
+ throw new CliError(`${flag} must be a positive integer.`, {
2907
+ code: 'DATASET_IMPORT_LCA_RUNTIME_BOUND_INVALID',
2908
+ exitCode: 2,
2909
+ });
2910
+ }
2911
+ return parsed;
2912
+ }
2917
2913
  function parseDatasetAuthorFlags(args) {
2918
2914
  let values;
2919
2915
  try {
@@ -3459,6 +3455,9 @@ function parseDatasetMaintenanceApplyFlags(args) {
3459
3455
  confirm: { type: 'string' },
3460
3456
  'timeout-ms': { type: 'string' },
3461
3457
  'dry-run': { type: 'boolean' },
3458
+ 'max-parallel': { type: 'string' },
3459
+ 'global-inbound-proof': { type: 'string' },
3460
+ 'approve-global-inbound-proof': { type: 'string' },
3462
3461
  },
3463
3462
  }));
3464
3463
  }
@@ -3468,6 +3467,38 @@ function parseDatasetMaintenanceApplyFlags(args) {
3468
3467
  exitCode: 2,
3469
3468
  });
3470
3469
  }
3470
+ const maxParallelValue = values['max-parallel'];
3471
+ const maxParallel = typeof maxParallelValue === 'string' && /^\d+$/u.test(maxParallelValue)
3472
+ ? Number.parseInt(maxParallelValue, 10)
3473
+ : maxParallelValue === undefined
3474
+ ? undefined
3475
+ : Number.NaN;
3476
+ if (maxParallel !== undefined &&
3477
+ (!Number.isInteger(maxParallel) || maxParallel < 1 || maxParallel > 8)) {
3478
+ throw new CliError('--max-parallel must be an integer from 1 to 8.', {
3479
+ code: 'INVALID_ARGS',
3480
+ exitCode: 2,
3481
+ });
3482
+ }
3483
+ const globalInboundProofPath = typeof values['global-inbound-proof'] === 'string' ? values['global-inbound-proof'] : '';
3484
+ const approveGlobalInboundProof = typeof values['approve-global-inbound-proof'] === 'string'
3485
+ ? values['approve-global-inbound-proof']
3486
+ : '';
3487
+ if (Boolean(globalInboundProofPath) !== Boolean(approveGlobalInboundProof)) {
3488
+ throw new CliError('--global-inbound-proof and --approve-global-inbound-proof must be provided together.', { code: 'INVALID_ARGS', exitCode: 2 });
3489
+ }
3490
+ if (globalInboundProofPath && maxParallel === undefined) {
3491
+ throw new CliError('Global inbound proof flags require --max-parallel.', {
3492
+ code: 'INVALID_ARGS',
3493
+ exitCode: 2,
3494
+ });
3495
+ }
3496
+ if (approveGlobalInboundProof && !/^[0-9a-f]{64}$/u.test(approveGlobalInboundProof)) {
3497
+ throw new CliError('--approve-global-inbound-proof must be a lowercase SHA-256.', {
3498
+ code: 'INVALID_ARGS',
3499
+ exitCode: 2,
3500
+ });
3501
+ }
3471
3502
  return {
3472
3503
  help: Boolean(values.help),
3473
3504
  json: Boolean(values.json),
@@ -3477,6 +3508,9 @@ function parseDatasetMaintenanceApplyFlags(args) {
3477
3508
  confirm: typeof values.confirm === 'string' ? values.confirm : '',
3478
3509
  timeoutMs: parseDatasetMaintenancePositiveInteger(values['timeout-ms'], '--timeout-ms'),
3479
3510
  dryRun: Boolean(values['dry-run']),
3511
+ maxParallel,
3512
+ globalInboundProofPath,
3513
+ approveGlobalInboundProof,
3480
3514
  };
3481
3515
  }
3482
3516
  function parseDatasetMaintenanceFreezeProtectedFlags(args) {
@@ -5741,19 +5775,18 @@ export async function executeCli(argv, deps) {
5741
5775
  fromFormat: datasetFlags.fromFormat,
5742
5776
  target: datasetFlags.target,
5743
5777
  reportPath: datasetFlags.reportPath,
5744
- mappingDir: datasetFlags.mappingDir,
5745
- language: datasetFlags.language,
5746
- validationJobs: datasetFlags.validationJobs,
5778
+ writeMapping: datasetFlags.writeMapping,
5747
5779
  processBundles: datasetFlags.processBundles,
5748
- processBundlesDir: datasetFlags.processBundlesDir,
5749
- detectOnly: datasetFlags.detectOnly,
5750
5780
  failOnWarning: datasetFlags.failOnWarning,
5751
- pythonBin: datasetFlags.pythonBin,
5752
- tidasToolsDir: datasetFlags.tidasToolsDir,
5781
+ maxEntryMib: datasetFlags.maxEntryMib,
5782
+ memoryBudgetMib: datasetFlags.memoryBudgetMib,
5783
+ queueCapacity: datasetFlags.queueCapacity,
5784
+ tidasBin: datasetFlags.tidasBin,
5785
+ tidasConfig: datasetFlags.tidasConfig,
5753
5786
  env: deps.env,
5754
5787
  });
5755
5788
  return {
5756
- exitCode: report.status === 'completed' ? 0 : 1,
5789
+ exitCode: report.exit_code,
5757
5790
  stdout: stringifyJson(report, datasetFlags.json),
5758
5791
  stderr: '',
5759
5792
  };
@@ -6401,11 +6434,16 @@ export async function executeCli(argv, deps) {
6401
6434
  approvePlan: datasetFlags.approvePlan,
6402
6435
  confirm: datasetFlags.confirm,
6403
6436
  timeoutMs: datasetFlags.timeoutMs,
6437
+ maxParallel: datasetFlags.maxParallel,
6438
+ globalInboundProofPath: datasetFlags.globalInboundProofPath || undefined,
6439
+ approveGlobalInboundProof: datasetFlags.approveGlobalInboundProof || undefined,
6404
6440
  env: deps.env,
6405
6441
  fetchImpl: deps.fetchImpl,
6406
6442
  });
6407
6443
  return {
6408
- exitCode: report.status === 'completed_with_failures' ? 1 : 0,
6444
+ exitCode: ['completed_with_failures', 'completed_with_unknowns'].includes(report.status)
6445
+ ? 1
6446
+ : 0,
6409
6447
  stdout: stringifyJson(report, datasetFlags.json),
6410
6448
  stderr: '',
6411
6449
  };