@tiangong-lca/cli 0.0.33 → 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 +29 -13
  3. package/assets/import-smoke/simapro.csv +20 -0
  4. package/bin/tiangong-lca.js +1 -1
  5. package/dist/src/cli.js +83 -64
  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 +213 -46
  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 +36 -14
  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
 
@@ -47,20 +56,24 @@ Review note, 2026-07-24: CLI 0.0.32 adds bounded execution-contract concurrency
47
56
 
48
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.
49
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
+
50
63
  ## Run
51
64
 
52
65
  One-off published run:
53
66
 
54
67
  ```bash
55
- npm exec --yes --package=@tiangong-lca/cli@latest -- tiangong-lca --help
56
- npm exec --yes --package=@tiangong-lca/cli@latest -- tiangong-lca doctor
57
- 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
58
71
  ```
59
72
 
60
73
  Install the published CLI:
61
74
 
62
75
  ```bash
63
- npm install --global @tiangong-lca/cli
76
+ pnpm add --global @tiangong-lca/cli
64
77
  tiangong-lca --help
65
78
  tiangong-lca doctor
66
79
  tiangong-lca flow --help
@@ -69,8 +82,8 @@ tiangong-lca flow --help
69
82
  Run from this repository:
70
83
 
71
84
  ```bash
72
- npm ci
73
- npm run build
85
+ pnpm install --frozen-lockfile
86
+ pnpm build
74
87
  node ./bin/tiangong-lca.js --help
75
88
  ```
76
89
 
@@ -255,7 +268,7 @@ Key outputs under `--out-dir`:
255
268
 
256
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`.
257
270
 
258
- 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.
259
272
 
260
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.
261
274
 
@@ -270,7 +283,7 @@ tiangong-lca flow build-plan validate --input ./flow-build-plan.json --out-dir .
270
283
  tiangong-lca flow build-plan materialize --input ./flow-build-plan.json --out-dir ./flow-build-plan --json
271
284
  ```
272
285
 
273
- 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.
274
287
 
275
288
  Key outputs under `--out-dir`:
276
289
 
@@ -369,6 +382,7 @@ tiangong-lca dataset classification apply --type location --input ./rows/process
369
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
370
383
  tiangong-lca dataset curation-queue next --queue-dir /abs/path/to/curation-queue --type support --json
371
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
372
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
373
387
  tiangong-lca dataset evidence-search plan --query "中国2026年电力结构数据" --out-dir /abs/path/to/evidence-search --json
374
388
  tiangong-lca dataset evidence-search run --input ./evidence-search.request.json --results ./search-results.json --out-dir /abs/path/to/evidence-search --json
@@ -401,13 +415,13 @@ For `qa process`, `--rows-file` accepts either raw process rows as JSON/JSONL or
401
415
 
402
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.
403
417
 
404
- 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.
405
419
 
406
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.
407
421
 
408
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.
409
423
 
410
- 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 also completes a fresh SELECT-only scan of every process visible to the owner session and rejects any inbound edge. 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 the flag to retain ordinary maintenance apply behavior.
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.
411
425
 
412
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.
413
427
 
@@ -423,6 +437,8 @@ For `dataset validate`, `--type auto` supports mixed support scopes containing c
423
437
 
424
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.
425
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
+
426
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.
427
443
 
428
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
@@ -537,6 +537,8 @@ Options:
537
537
  --confirm <email> Current authenticated account email
538
538
  --timeout-ms <n> Request timeout in milliseconds
539
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
540
542
  --json Print compact JSON
541
543
  -h, --help
542
544
 
@@ -833,30 +835,33 @@ function renderDatasetImportLcaHelp() {
833
835
 
834
836
  Options:
835
837
  --input <path> Source file, directory, or package to import
836
- --output-dir <dir> Output directory for generated package and reports
838
+ --output-dir <dir> Output directory atomically published by tidas
837
839
  --from-format <format> auto, ecospold1, ecospold2, openlca-jsonld, openlca-process-xlsx, simapro-csv, ilcd
838
840
  --target <target> tidas | ilcd | both (default: tidas)
839
- --report <file> Conversion report path (default: <output-dir>/conversion-report.json)
840
- --mapping-dir <dir> Optional custom mapping/reference data directory
841
- --language <lang> Default language for generated text (default: en)
842
- --validation-jobs <n> Parallel validation jobs passed to tidas-tools (default: 1)
843
- --process-bundles Write per-process dependency bundles (default: enabled by tidas-tools)
844
- --process-bundles-dir <dir>
845
- 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
846
843
  --no-process-bundles Disable per-process dependency bundle generation
847
- --detect-only Only detect the input format and write the report
848
844
  --fail-on-warning Return non-zero when converter warnings are present
849
- --python <bin> Python executable (default: python3)
850
- --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)
851
850
  --json Print compact JSON
852
851
  -h, --help
853
852
 
854
853
  Outputs written under --output-dir:
855
- - conversion-report.json
856
- - tidas/ when target includes TIDAS and not detect-only
857
- - ilcd/ when target includes ILCD and not detect-only
858
- - process-bundles/ when not detect-only and process bundles are enabled
859
- - 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.
860
865
  `.trim();
861
866
  }
862
867
  function renderDatasetAuthorHelp() {
@@ -2854,16 +2859,14 @@ function parseDatasetImportLcaConvertFlags(args) {
2854
2859
  'from-format': { type: 'string' },
2855
2860
  target: { type: 'string' },
2856
2861
  report: { type: 'string' },
2857
- 'mapping-dir': { type: 'string' },
2858
- language: { type: 'string' },
2859
- 'validation-jobs': { type: 'string' },
2860
- 'process-bundles': { type: 'boolean' },
2861
- 'process-bundles-dir': { type: 'string' },
2862
+ 'write-mapping': { type: 'boolean' },
2862
2863
  'no-process-bundles': { type: 'boolean' },
2863
- 'detect-only': { type: 'boolean' },
2864
2864
  'fail-on-warning': { type: 'boolean' },
2865
- python: { type: 'string' },
2866
- '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' },
2867
2870
  },
2868
2871
  }));
2869
2872
  }
@@ -2873,25 +2876,9 @@ function parseDatasetImportLcaConvertFlags(args) {
2873
2876
  exitCode: 2,
2874
2877
  });
2875
2878
  }
2876
- const validationJobs = typeof values['validation-jobs'] === 'string' ? Number(values['validation-jobs']) : undefined;
2877
- if (validationJobs !== undefined && (!Number.isInteger(validationJobs) || validationJobs < 0)) {
2878
- throw new CliError('--validation-jobs must be a non-negative integer.', {
2879
- code: 'DATASET_IMPORT_LCA_VALIDATION_JOBS_INVALID',
2880
- exitCode: 2,
2881
- });
2882
- }
2883
- if (values['process-bundles'] && values['no-process-bundles']) {
2884
- throw new CliError('--process-bundles and --no-process-bundles cannot both be set.', {
2885
- code: 'DATASET_IMPORT_LCA_PROCESS_BUNDLES_INVALID',
2886
- exitCode: 2,
2887
- });
2888
- }
2889
- if (values['no-process-bundles'] && typeof values['process-bundles-dir'] === 'string') {
2890
- throw new CliError('--process-bundles-dir cannot be used with --no-process-bundles.', {
2891
- code: 'DATASET_IMPORT_LCA_PROCESS_BUNDLES_INVALID',
2892
- exitCode: 2,
2893
- });
2894
- }
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');
2895
2882
  return {
2896
2883
  help: Boolean(values.help),
2897
2884
  json: Boolean(values.json),
@@ -2900,21 +2887,29 @@ function parseDatasetImportLcaConvertFlags(args) {
2900
2887
  fromFormat: typeof values['from-format'] === 'string' ? values['from-format'] : undefined,
2901
2888
  target: typeof values.target === 'string' ? values.target : undefined,
2902
2889
  reportPath: typeof values.report === 'string' ? values.report : undefined,
2903
- mappingDir: typeof values['mapping-dir'] === 'string' ? values['mapping-dir'] : undefined,
2904
- language: typeof values.language === 'string' ? values.language : undefined,
2905
- validationJobs,
2906
- processBundles: values['no-process-bundles']
2907
- ? false
2908
- : values['process-bundles']
2909
- ? true
2910
- : undefined,
2911
- processBundlesDir: typeof values['process-bundles-dir'] === 'string' ? values['process-bundles-dir'] : undefined,
2912
- detectOnly: Boolean(values['detect-only']),
2890
+ writeMapping: Boolean(values['write-mapping']),
2891
+ processBundles: values['no-process-bundles'] ? false : undefined,
2913
2892
  failOnWarning: Boolean(values['fail-on-warning']),
2914
- pythonBin: typeof values.python === 'string' ? values.python : undefined,
2915
- 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,
2916
2898
  };
2917
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
+ }
2918
2913
  function parseDatasetAuthorFlags(args) {
2919
2914
  let values;
2920
2915
  try {
@@ -3461,6 +3456,8 @@ function parseDatasetMaintenanceApplyFlags(args) {
3461
3456
  'timeout-ms': { type: 'string' },
3462
3457
  'dry-run': { type: 'boolean' },
3463
3458
  'max-parallel': { type: 'string' },
3459
+ 'global-inbound-proof': { type: 'string' },
3460
+ 'approve-global-inbound-proof': { type: 'string' },
3464
3461
  },
3465
3462
  }));
3466
3463
  }
@@ -3483,6 +3480,25 @@ function parseDatasetMaintenanceApplyFlags(args) {
3483
3480
  exitCode: 2,
3484
3481
  });
3485
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
+ }
3486
3502
  return {
3487
3503
  help: Boolean(values.help),
3488
3504
  json: Boolean(values.json),
@@ -3493,6 +3509,8 @@ function parseDatasetMaintenanceApplyFlags(args) {
3493
3509
  timeoutMs: parseDatasetMaintenancePositiveInteger(values['timeout-ms'], '--timeout-ms'),
3494
3510
  dryRun: Boolean(values['dry-run']),
3495
3511
  maxParallel,
3512
+ globalInboundProofPath,
3513
+ approveGlobalInboundProof,
3496
3514
  };
3497
3515
  }
3498
3516
  function parseDatasetMaintenanceFreezeProtectedFlags(args) {
@@ -5757,19 +5775,18 @@ export async function executeCli(argv, deps) {
5757
5775
  fromFormat: datasetFlags.fromFormat,
5758
5776
  target: datasetFlags.target,
5759
5777
  reportPath: datasetFlags.reportPath,
5760
- mappingDir: datasetFlags.mappingDir,
5761
- language: datasetFlags.language,
5762
- validationJobs: datasetFlags.validationJobs,
5778
+ writeMapping: datasetFlags.writeMapping,
5763
5779
  processBundles: datasetFlags.processBundles,
5764
- processBundlesDir: datasetFlags.processBundlesDir,
5765
- detectOnly: datasetFlags.detectOnly,
5766
5780
  failOnWarning: datasetFlags.failOnWarning,
5767
- pythonBin: datasetFlags.pythonBin,
5768
- tidasToolsDir: datasetFlags.tidasToolsDir,
5781
+ maxEntryMib: datasetFlags.maxEntryMib,
5782
+ memoryBudgetMib: datasetFlags.memoryBudgetMib,
5783
+ queueCapacity: datasetFlags.queueCapacity,
5784
+ tidasBin: datasetFlags.tidasBin,
5785
+ tidasConfig: datasetFlags.tidasConfig,
5769
5786
  env: deps.env,
5770
5787
  });
5771
5788
  return {
5772
- exitCode: report.status === 'completed' ? 0 : 1,
5789
+ exitCode: report.exit_code,
5773
5790
  stdout: stringifyJson(report, datasetFlags.json),
5774
5791
  stderr: '',
5775
5792
  };
@@ -6418,6 +6435,8 @@ export async function executeCli(argv, deps) {
6418
6435
  confirm: datasetFlags.confirm,
6419
6436
  timeoutMs: datasetFlags.timeoutMs,
6420
6437
  maxParallel: datasetFlags.maxParallel,
6438
+ globalInboundProofPath: datasetFlags.globalInboundProofPath || undefined,
6439
+ approveGlobalInboundProof: datasetFlags.approveGlobalInboundProof || undefined,
6421
6440
  env: deps.env,
6422
6441
  fetchImpl: deps.fetchImpl,
6423
6442
  });