@tiangong-lca/cli 0.0.33 → 0.1.1

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 (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -13
  3. package/assets/import-smoke/simapro.csv +20 -0
  4. package/bin/tiangong-lca.js +1 -1
  5. package/dist/src/cli.js +213 -64
  6. package/dist/src/cli.js.map +1 -1
  7. package/dist/src/lib/auth-identity-receipt.js +634 -0
  8. package/dist/src/lib/auth-identity-receipt.js.map +1 -0
  9. package/dist/src/lib/dataset-bilingual.js.map +1 -1
  10. package/dist/src/lib/dataset-classification.js.map +1 -1
  11. package/dist/src/lib/dataset-contract.js.map +1 -1
  12. package/dist/src/lib/dataset-evidence-search.js.map +1 -1
  13. package/dist/src/lib/dataset-import-lca.js +302 -131
  14. package/dist/src/lib/dataset-import-lca.js.map +1 -1
  15. package/dist/src/lib/dataset-maintenance-apply.js +213 -46
  16. package/dist/src/lib/dataset-maintenance-apply.js.map +1 -1
  17. package/dist/src/lib/dataset-maintenance-clear-account.js +10 -4
  18. package/dist/src/lib/dataset-maintenance-clear-account.js.map +1 -1
  19. package/dist/src/lib/dataset-maintenance-contract.js +1 -6
  20. package/dist/src/lib/dataset-maintenance-contract.js.map +1 -1
  21. package/dist/src/lib/dataset-maintenance-derivatives.js +0 -1
  22. package/dist/src/lib/dataset-maintenance-derivatives.js.map +1 -1
  23. package/dist/src/lib/dataset-maintenance-flow-identity-capture.js +1 -0
  24. package/dist/src/lib/dataset-maintenance-flow-identity-capture.js.map +1 -1
  25. package/dist/src/lib/dataset-maintenance-pagination.js.map +1 -1
  26. package/dist/src/lib/dataset-maintenance-protected-before.js.map +1 -1
  27. package/dist/src/lib/dataset-maintenance-protected-contract.js +0 -1
  28. package/dist/src/lib/dataset-maintenance-protected-contract.js.map +1 -1
  29. package/dist/src/lib/dataset-maintenance-protected-freeze.js.map +1 -1
  30. package/dist/src/lib/dataset-maintenance-protected-preparation.js +0 -2
  31. package/dist/src/lib/dataset-maintenance-protected-preparation.js.map +1 -1
  32. package/dist/src/lib/dataset-maintenance-protected-seal.js.map +1 -1
  33. package/dist/src/lib/dataset-maintenance-protected-verify.js +0 -3
  34. package/dist/src/lib/dataset-maintenance-protected-verify.js.map +1 -1
  35. package/dist/src/lib/dataset-maintenance-remote.js +36 -14
  36. package/dist/src/lib/dataset-maintenance-remote.js.map +1 -1
  37. package/dist/src/lib/dataset-maintenance-verify.js +1 -2
  38. package/dist/src/lib/dataset-maintenance-verify.js.map +1 -1
  39. package/dist/src/lib/dataset-remote-refresh.js.map +1 -1
  40. package/dist/src/lib/dataset-remote-verify.js +2 -0
  41. package/dist/src/lib/dataset-remote-verify.js.map +1 -1
  42. package/dist/src/lib/dataset-save-draft-run.js +2 -0
  43. package/dist/src/lib/dataset-save-draft-run.js.map +1 -1
  44. package/dist/src/lib/flow-build-alias-map.js.map +1 -1
  45. package/dist/src/lib/flow-fetch-rows.js.map +1 -1
  46. package/dist/src/lib/flow-get.js.map +1 -1
  47. package/dist/src/lib/flow-governance.js.map +1 -1
  48. package/dist/src/lib/flow-list.js +1 -0
  49. package/dist/src/lib/flow-list.js.map +1 -1
  50. package/dist/src/lib/flow-payload-validation.js.map +1 -1
  51. package/dist/src/lib/flow-publish-version.js +1 -0
  52. package/dist/src/lib/flow-publish-version.js.map +1 -1
  53. package/dist/src/lib/flow-read.js +1 -0
  54. package/dist/src/lib/flow-read.js.map +1 -1
  55. package/dist/src/lib/flow-regen-product.js.map +1 -1
  56. package/dist/src/lib/flow-remediate.js.map +1 -1
  57. package/dist/src/lib/http.js.map +1 -1
  58. package/dist/src/lib/identity-preflight.js +4 -10
  59. package/dist/src/lib/identity-preflight.js.map +1 -1
  60. package/dist/src/lib/lifecyclemodel-bundle-save.js +1 -0
  61. package/dist/src/lib/lifecyclemodel-bundle-save.js.map +1 -1
  62. package/dist/src/lib/lifecyclemodel-orchestrate.js.map +1 -1
  63. package/dist/src/lib/lifecyclemodel-publish-resulting-process.js.map +1 -1
  64. package/dist/src/lib/lifecyclemodel-resulting-process.js.map +1 -1
  65. package/dist/src/lib/lifecyclemodel-save-draft-run.js.map +1 -1
  66. package/dist/src/lib/lifecyclemodel-validate-build.js.map +1 -1
  67. package/dist/src/lib/package-version.js.map +1 -1
  68. package/dist/src/lib/process-auto-build.js.map +1 -1
  69. package/dist/src/lib/process-dedup-review.js +14 -7
  70. package/dist/src/lib/process-dedup-review.js.map +1 -1
  71. package/dist/src/lib/process-flow-build-plan.js +111 -30
  72. package/dist/src/lib/process-flow-build-plan.js.map +1 -1
  73. package/dist/src/lib/process-get.js +1 -0
  74. package/dist/src/lib/process-get.js.map +1 -1
  75. package/dist/src/lib/process-list.js +1 -0
  76. package/dist/src/lib/process-list.js.map +1 -1
  77. package/dist/src/lib/process-payload-validation.js.map +1 -1
  78. package/dist/src/lib/process-qa.js.map +1 -1
  79. package/dist/src/lib/process-refresh-references.js +15 -10
  80. package/dist/src/lib/process-refresh-references.js.map +1 -1
  81. package/dist/src/lib/process-save-draft.js +9 -3
  82. package/dist/src/lib/process-save-draft.js.map +1 -1
  83. package/dist/src/lib/process-scope-statistics.js +11 -4
  84. package/dist/src/lib/process-scope-statistics.js.map +1 -1
  85. package/dist/src/lib/process-verify-rows.js.map +1 -1
  86. package/dist/src/lib/publish.js.map +1 -1
  87. package/dist/src/lib/run.js.map +1 -1
  88. package/dist/src/lib/supabase-client.js +13 -1
  89. package/dist/src/lib/supabase-client.js.map +1 -1
  90. package/dist/src/lib/supabase-data-api-contract.js +328 -0
  91. package/dist/src/lib/supabase-data-api-contract.js.map +1 -0
  92. package/dist/src/lib/supabase-data-api-replay.js +69 -0
  93. package/dist/src/lib/supabase-data-api-replay.js.map +1 -0
  94. package/dist/src/lib/supabase-json-ordered-write.js +2 -0
  95. package/dist/src/lib/supabase-json-ordered-write.js.map +1 -1
  96. package/dist/src/lib/supabase-rest.js +1 -0
  97. package/dist/src/lib/supabase-rest.js.map +1 -1
  98. package/dist/src/lib/tidas-sdk-package-validator.js +5 -5
  99. package/dist/src/lib/tidas-sdk-package-validator.js.map +1 -1
  100. package/dist/src/lib/validation.js.map +1 -1
  101. package/dist/src/main.js.map +1 -1
  102. package/package.json +43 -40
  103. package/dist/scripts/assert-full-coverage.js +0 -77
  104. 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,34 @@ 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
22
+ - src/lib/auth-identity-receipt.ts
20
23
  - src/lib/lca-release.ts
24
+ - scripts/run-auth-identity-production-case.ts
25
+ - test/auth-identity*.test.ts
21
26
  - test/lca-release*.test.ts
22
- lastReviewedAt: 2026-07-23
23
- lastReviewedCommit: 5c90ddd60328748ab6d8d89717e59dcaeca8cde7
27
+ lastReviewedAt: 2026-08-25
28
+ lastReviewedCommit: 47b44c65cf4bf27070fa1057e672c6ef2b2e54f3
29
+ lastReviewedNote: 'Reviewed for Issue #230: identifies 0.1.1 as the public auth-receipt release on exact Node 24.19.0 with cryptographic Sigstore and isolated pnpm verification.'
24
30
  ---
25
31
 
26
32
  # TianGong LCA CLI
27
33
 
28
- Package: `@tiangong-lca/cli` Executable: `tiangong-lca` Node: `24.x`
34
+ Package: `@tiangong-lca/cli` Executable: `tiangong-lca` Current package version: `0.1.1` Node: `24.19.0`
35
+
36
+ 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.
37
+
38
+ 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.
39
+
40
+ 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.
41
+
42
+ Review note, 2026-08-25: Issue #228 implements `auth identity-receipt` as a bounded read-only current-user proof. It checks expected project intent before session work, verifies the live user through `/auth/v1/user`, allows one auth-refresh replay after 401/403, and emits an exact-key canonical receipt without API keys, tokens, full email addresses, session paths, or credential-derived fingerprints. Production callers must pass both expected assertions and accept only `assertions.mode="intent-bound"`.
43
+
44
+ Review note, 2026-08-25: Issue #230 publishes the merged identity receipt as `@tiangong-lca/cli@0.1.1`. Runtime logic and published dependencies remain unchanged; the sole pnpm lock changes only for exact dev-only `sigstore@5.0.0`. Local metadata, engines, and every workflow converge on Node 24.19.0. Release automation asserts actual platform/architecture across the reusable four-platform pre-tag matrix and provides `pnpm release:verify-published` for cryptographic Fulcio/CT/Rekor provenance, registry signatures, actual tarball integrity, isolated user/global package-manager configuration, exact pnpm 11.23.0, and credential-free bin/ESM/CJS consumer proof.
29
45
 
30
46
  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
47
 
@@ -47,20 +63,24 @@ Review note, 2026-07-24: CLI 0.0.32 adds bounded execution-contract concurrency
47
63
 
48
64
  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
65
 
66
+ 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.
67
+
68
+ 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.
69
+
50
70
  ## Run
51
71
 
52
72
  One-off published run:
53
73
 
54
74
  ```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
75
+ pnpm dlx @tiangong-lca/cli@latest --help
76
+ pnpm dlx @tiangong-lca/cli@latest doctor
77
+ pnpm dlx @tiangong-lca/cli@latest flow --help
58
78
  ```
59
79
 
60
80
  Install the published CLI:
61
81
 
62
82
  ```bash
63
- npm install --global @tiangong-lca/cli
83
+ pnpm add --global @tiangong-lca/cli
64
84
  tiangong-lca --help
65
85
  tiangong-lca doctor
66
86
  tiangong-lca flow --help
@@ -69,8 +89,8 @@ tiangong-lca flow --help
69
89
  Run from this repository:
70
90
 
71
91
  ```bash
72
- npm ci
73
- npm run build
92
+ pnpm install --frozen-lockfile
93
+ pnpm build
74
94
  node ./bin/tiangong-lca.js --help
75
95
  ```
76
96
 
@@ -99,6 +119,31 @@ TIANGONG_LCA_DISABLE_SESSION_CACHE=false
99
119
  TIANGONG_LCA_FORCE_REAUTH=false
100
120
  ```
101
121
 
122
+ ## Auth Identity Receipt
123
+
124
+ Use the identity receipt before a production-backed case or any later owner-draft write gate:
125
+
126
+ ```text
127
+ tiangong-lca auth identity-receipt --expected-project-ref <project-ref> --expected-user-id <user-id> --json
128
+ ```
129
+
130
+ The command performs no dataset write. It exchanges the normal user API key for a session, checks the canonical Supabase project, and makes a bounded live `GET /auth/v1/user`. A cached token that receives `401` or `403` may be refreshed and retried exactly once; all other transport or response failures are terminal. A valid production guard requires:
131
+
132
+ - `schema` exactly `tiangong-lca.auth-identity-receipt.v1`;
133
+ - `status: "passed"`, `operation: "current-user-read"`, and `remote_write_mode: "read-only"`;
134
+ - exact expected project/user values with `assertions.mode: "intent-bound"` and `requested_count: 2`;
135
+ - a fresh capture time and a valid recomputed `receipt_scope_sha256`.
136
+
137
+ Calling without expectations is allowed for discovery but produces `assertions.mode: "observed"`; it is not an authorization guard. The safe display email is masked and must not be used as the account key. The receipt deliberately excludes credentials, full email, session-file details, raw response metadata, and all credential/token/path-derived fingerprints.
138
+
139
+ For the explicitly authorized local production read case from a validated repository checkout, invoke the narrow TypeScript runner with a new private output directory:
140
+
141
+ ```text
142
+ pnpm case:auth-identity:production -- --env-file <data-foundry-ignored-.env> --expected-project-ref <project-ref> --expected-user-id <user-id> --out-dir <new-private-case-directory>
143
+ ```
144
+
145
+ The runner reads only `TIANGONG_LCA_API_BASE_URL`, `TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY`, and `TIANGONG_LCA_TEST_API_KEY`; the last is mapped to the child process's standard API-key variable. It does not accept an alternate CLI path. The pnpm command first performs a clean TS7 build without the production env. Its plain-Node runner then single-reads source/config/lock and the freshly generated `dist/src/**/*.js`, hashes the source tree, runner, runtime, exact entrypoint, and pnpm lock, and copies those exact built buffers into a private snapshot before exposing the key. It forces reauthentication with session cache disabled, runs only the built snapshot from an exclusively created clean directory with an argv array and `shell:false`, cleans the snapshot before publishing success artifacts, and persists only the parsed receipt and case manifest. POSIX creates the case directory as `0700` and files as `0600`; Windows inherits ACLs from the caller-selected parent, so use a user-restricted parent because mode bits are not an ACL guarantee. The runner never stores raw child stdout/stderr and is intentionally not wired to CI secrets. This receipt is locally hash-verifiable, not server-signed attestation.
146
+
102
147
  ## LCI/LCIA Data Release
103
148
 
104
149
  The `release` command family is the authenticated transport used by the standalone release control plane. It does not introduce a TIDAS schema variant: result packages reuse the existing Process exchange structure for LCI and the existing Process LCIA result fields, with a LifecycleModel referencing the resulting Process.
@@ -255,7 +300,7 @@ Key outputs under `--out-dir`:
255
300
 
256
301
  `--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
302
 
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.
303
+ 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
304
 
260
305
  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
306
 
@@ -270,7 +315,7 @@ tiangong-lca flow build-plan validate --input ./flow-build-plan.json --out-dir .
270
315
  tiangong-lca flow build-plan materialize --input ./flow-build-plan.json --out-dir ./flow-build-plan --json
271
316
  ```
272
317
 
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.
318
+ 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
319
 
275
320
  Key outputs under `--out-dir`:
276
321
 
@@ -369,6 +414,7 @@ tiangong-lca dataset classification apply --type location --input ./rows/process
369
414
  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
415
  tiangong-lca dataset curation-queue next --queue-dir /abs/path/to/curation-queue --type support --json
371
416
  tiangong-lca dataset curation-queue verify --queue-dir /abs/path/to/curation-queue --type process --json
417
+ 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
418
  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
419
  tiangong-lca dataset evidence-search plan --query "中国2026年电力结构数据" --out-dir /abs/path/to/evidence-search --json
374
420
  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 +447,13 @@ For `qa process`, `--rows-file` accepts either raw process rows as JSON/JSONL or
401
447
 
402
448
  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
449
 
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`.
450
+ 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
451
 
406
452
  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
453
 
408
454
  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
455
 
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.
456
+ 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
457
 
412
458
  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
459
 
@@ -423,6 +469,8 @@ For `dataset validate`, `--type auto` supports mixed support scopes containing c
423
469
 
424
470
  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
471
 
472
+ 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.
473
+
426
474
  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
475
 
428
476
  ## 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
@@ -3,6 +3,7 @@ import { buildDoctorReport, readRuntimeEnv } from './lib/env.js';
3
3
  import { CliError, toErrorPayload } from './lib/errors.js';
4
4
  import { stringifyJson } from './lib/io.js';
5
5
  import { loadCliPackageVersion } from './lib/package-version.js';
6
+ import { AUTH_IDENTITY_MAX_TIMEOUT_MS, AUTH_IDENTITY_RECEIPT_SCHEMA, runAuthIdentityReceipt, } from './lib/auth-identity-receipt.js';
6
7
  import { runLifecyclemodelAutoBuild, } from './lib/lifecyclemodel-auto-build.js';
7
8
  import { runLifecyclemodelBuildResultingProcess, } from './lib/lifecyclemodel-resulting-process.js';
8
9
  import { runLifecyclemodelPublishResultingProcess, } from './lib/lifecyclemodel-publish-resulting-process.js';
@@ -86,6 +87,7 @@ Usage:
86
87
  Commands:
87
88
  Implemented Commands:
88
89
  doctor show environment diagnostics
90
+ auth identity-receipt
89
91
  search flow | process | lifecyclemodel
90
92
  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
91
93
  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/flow-identity
@@ -105,6 +107,7 @@ Planned commands currently print an explicit "not implemented yet" message and e
105
107
 
106
108
  Examples:
107
109
  tiangong-lca doctor
110
+ tiangong-lca auth identity-receipt --expected-project-ref <project-ref> --expected-user-id <user-id> --json
108
111
  tiangong-lca search flow --input ./request.json
109
112
  tiangong-lca search process --input ./request.json --dry-run
110
113
  tiangong-lca process get --id <process-id>
@@ -180,6 +183,50 @@ Environment:
180
183
  .env loaded: ${dotEnvStatus.loaded ? `yes (${dotEnvStatus.path}, ${dotEnvStatus.count} keys)` : 'no'}
181
184
  `.trim();
182
185
  }
186
+ function renderAuthHelp() {
187
+ return `Usage:
188
+ tiangong-lca auth identity-receipt [options]
189
+
190
+ Implemented Subcommands:
191
+ identity-receipt Live, read-only proof of the authenticated account and Supabase project
192
+
193
+ Planned Subcommands:
194
+ whoami | doctor-auth
195
+
196
+ Use "tiangong-lca auth identity-receipt --help" for the machine-receipt contract.
197
+ `.trim();
198
+ }
199
+ function renderAuthIdentityReceiptHelp() {
200
+ return `Usage:
201
+ tiangong-lca auth identity-receipt [options]
202
+
203
+ Options:
204
+ --expected-project-ref <ref> Assert the exact Supabase project before session/network access
205
+ --expected-user-id <id> Assert the exact server-verified authenticated user
206
+ --timeout-ms <n> Request timeout 1..${AUTH_IDENTITY_MAX_TIMEOUT_MS} ms (default: 10000)
207
+ --json Print compact JSON; default output is pretty JSON
208
+ -h, --help
209
+
210
+ Receipt schema:
211
+ ${AUTH_IDENTITY_RECEIPT_SCHEMA}
212
+
213
+ Safety:
214
+ This is a read-only command that performs one live read of /auth/v1/user, with at most one
215
+ force-refresh retry after a 401 or 403. It never emits API keys, bearer/session
216
+ tokens, full email addresses, session paths, or credential-derived fingerprints. Production guards
217
+ must pass both expected assertions and require assertions.mode="intent-bound".
218
+
219
+ Required env:
220
+ TIANGONG_LCA_API_BASE_URL
221
+ TIANGONG_LCA_API_KEY
222
+ TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
223
+
224
+ Optional session env:
225
+ TIANGONG_LCA_SESSION_FILE
226
+ TIANGONG_LCA_DISABLE_SESSION_CACHE
227
+ TIANGONG_LCA_FORCE_REAUTH
228
+ `.trim();
229
+ }
183
230
  function renderDoctorHelp() {
184
231
  return `Usage:
185
232
  tiangong-lca doctor [--json]
@@ -335,7 +382,7 @@ Implemented Subcommands:
335
382
  curation-queue build Build entity-level AI curation queue artifacts for Foundry imports
336
383
  curation-queue next Return the next runnable support/flow/process queue task
337
384
  curation-queue verify Verify queue task checkpoints for a scope
338
- import-lca convert Convert supported external LCA packages through tidas-tools
385
+ import-lca convert Import supported external LCA packages through the unified Rust tidas binary
339
386
  author Extract source evidence and prepare TIDAS context packs for AI authoring
340
387
  patch apply Apply AI-authored structured dataset patches deterministically
341
388
  save-draft Save contact/source/support or other canonical dataset rows through the platform dataset command path
@@ -537,6 +584,8 @@ Options:
537
584
  --confirm <email> Current authenticated account email
538
585
  --timeout-ms <n> Request timeout in milliseconds
539
586
  --max-parallel <1-8> Opt into bounded flow delete-only execution with durable dispatch ledger
587
+ --global-inbound-proof <file> Absolute path to a fresh all-process SELECT-only zero-inbound proof
588
+ --approve-global-inbound-proof <sha256> Exact SHA-256 of --global-inbound-proof; requires --max-parallel
540
589
  --json Print compact JSON
541
590
  -h, --help
542
591
 
@@ -833,30 +882,33 @@ function renderDatasetImportLcaHelp() {
833
882
 
834
883
  Options:
835
884
  --input <path> Source file, directory, or package to import
836
- --output-dir <dir> Output directory for generated package and reports
885
+ --output-dir <dir> Output directory atomically published by tidas
837
886
  --from-format <format> auto, ecospold1, ecospold2, openlca-jsonld, openlca-process-xlsx, simapro-csv, ilcd
838
887
  --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)
888
+ --report <file> Persist the native operation report atomically instead of using tidas stdout
889
+ --write-mapping Write deterministic mapping.csv.gz
846
890
  --no-process-bundles Disable per-process dependency bundle generation
847
- --detect-only Only detect the input format and write the report
848
891
  --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
892
+ --max-entry-mib <n> Maximum source-entry size in MiB (tidas default: 128)
893
+ --memory-budget-mib <n> Maximum accounted in-flight memory in MiB (tidas default: 512)
894
+ --queue-capacity <n> Maximum items in each bounded queue (tidas default: 256)
895
+ --tidas-bin <path> Rust tidas executable (default: TIDAS_BIN, then tidas on PATH)
896
+ --tidas-config <path> Explicit tidas config file (otherwise TIDAS_CONFIG is honored)
851
897
  --json Print compact JSON
852
898
  -h, --help
853
899
 
854
900
  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
901
+ - import-report.json and issues.jsonl
902
+ - tidas/ when target includes TIDAS
903
+ - ilcd/ when target includes ILCD
904
+ - process-bundles/ by default
905
+ - mapping.csv.gz when --write-mapping is used
906
+
907
+ Runtime contract:
908
+ - Linux x86_64/ARM64, macOS Intel/Apple Silicon, and Windows x86_64 are supported.
909
+ - Windows ARM64 is unsupported.
910
+ - The binary must report tidas.operation-report.v1 and a stable 0.2.x version.
911
+ - Import publication, cancellation cleanup, and domain validation remain owned by Rust tidas.
860
912
  `.trim();
861
913
  }
862
914
  function renderDatasetAuthorHelp() {
@@ -2264,6 +2316,59 @@ function parseDoctorFlags(args) {
2264
2316
  json: Boolean(values.json),
2265
2317
  };
2266
2318
  }
2319
+ function parseAuthIdentityReceiptFlags(args) {
2320
+ let parsed;
2321
+ try {
2322
+ parsed = parseArgs({
2323
+ args,
2324
+ allowPositionals: false,
2325
+ strict: true,
2326
+ tokens: true,
2327
+ options: {
2328
+ help: { type: 'boolean', short: 'h' },
2329
+ json: { type: 'boolean' },
2330
+ 'expected-project-ref': { type: 'string' },
2331
+ 'expected-user-id': { type: 'string' },
2332
+ 'timeout-ms': { type: 'string' },
2333
+ },
2334
+ });
2335
+ }
2336
+ catch (error) {
2337
+ throw new CliError(String(error), {
2338
+ code: 'INVALID_ARGS',
2339
+ exitCode: 2,
2340
+ });
2341
+ }
2342
+ const tokens = parsed.tokens;
2343
+ for (const optionName of ['expected-project-ref', 'expected-user-id', 'timeout-ms']) {
2344
+ const occurrences = tokens.filter((entry) => entry.kind === 'option' && entry.name === optionName).length;
2345
+ if (occurrences > 1) {
2346
+ throw new CliError(`Option --${optionName} may be provided only once.`, {
2347
+ code: 'INVALID_ARGS',
2348
+ exitCode: 2,
2349
+ });
2350
+ }
2351
+ }
2352
+ const timeoutText = typeof parsed.values['timeout-ms'] === 'string' ? parsed.values['timeout-ms'] : undefined;
2353
+ const timeoutMs = timeoutText === undefined ? 10_000 : Number(timeoutText);
2354
+ if (!Number.isInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > AUTH_IDENTITY_MAX_TIMEOUT_MS) {
2355
+ throw new CliError(`Expected --timeout-ms to be an integer between 1 and ${AUTH_IDENTITY_MAX_TIMEOUT_MS}.`, {
2356
+ code: 'INVALID_TIMEOUT',
2357
+ exitCode: 2,
2358
+ });
2359
+ }
2360
+ return {
2361
+ help: Boolean(parsed.values.help),
2362
+ json: Boolean(parsed.values.json),
2363
+ expectedProjectRef: typeof parsed.values['expected-project-ref'] === 'string'
2364
+ ? parsed.values['expected-project-ref']
2365
+ : null,
2366
+ expectedUserId: typeof parsed.values['expected-user-id'] === 'string'
2367
+ ? parsed.values['expected-user-id']
2368
+ : null,
2369
+ timeoutMs,
2370
+ };
2371
+ }
2267
2372
  function parseRemoteFlags(args) {
2268
2373
  let values;
2269
2374
  try {
@@ -2854,16 +2959,14 @@ function parseDatasetImportLcaConvertFlags(args) {
2854
2959
  'from-format': { type: 'string' },
2855
2960
  target: { type: 'string' },
2856
2961
  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' },
2962
+ 'write-mapping': { type: 'boolean' },
2862
2963
  'no-process-bundles': { type: 'boolean' },
2863
- 'detect-only': { type: 'boolean' },
2864
2964
  'fail-on-warning': { type: 'boolean' },
2865
- python: { type: 'string' },
2866
- 'tidas-tools-dir': { type: 'string' },
2965
+ 'max-entry-mib': { type: 'string' },
2966
+ 'memory-budget-mib': { type: 'string' },
2967
+ 'queue-capacity': { type: 'string' },
2968
+ 'tidas-bin': { type: 'string' },
2969
+ 'tidas-config': { type: 'string' },
2867
2970
  },
2868
2971
  }));
2869
2972
  }
@@ -2873,25 +2976,9 @@ function parseDatasetImportLcaConvertFlags(args) {
2873
2976
  exitCode: 2,
2874
2977
  });
2875
2978
  }
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
- }
2979
+ const maxEntryMib = parsePositiveIntegerFlag(values['max-entry-mib'], '--max-entry-mib');
2980
+ const memoryBudgetMib = parsePositiveIntegerFlag(values['memory-budget-mib'], '--memory-budget-mib');
2981
+ const queueCapacity = parsePositiveIntegerFlag(values['queue-capacity'], '--queue-capacity');
2895
2982
  return {
2896
2983
  help: Boolean(values.help),
2897
2984
  json: Boolean(values.json),
@@ -2900,21 +2987,29 @@ function parseDatasetImportLcaConvertFlags(args) {
2900
2987
  fromFormat: typeof values['from-format'] === 'string' ? values['from-format'] : undefined,
2901
2988
  target: typeof values.target === 'string' ? values.target : undefined,
2902
2989
  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']),
2990
+ writeMapping: Boolean(values['write-mapping']),
2991
+ processBundles: values['no-process-bundles'] ? false : undefined,
2913
2992
  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,
2993
+ maxEntryMib,
2994
+ memoryBudgetMib,
2995
+ queueCapacity,
2996
+ tidasBin: typeof values['tidas-bin'] === 'string' ? values['tidas-bin'] : undefined,
2997
+ tidasConfig: typeof values['tidas-config'] === 'string' ? values['tidas-config'] : undefined,
2916
2998
  };
2917
2999
  }
3000
+ function parsePositiveIntegerFlag(value, flag) {
3001
+ if (typeof value !== 'string') {
3002
+ return undefined;
3003
+ }
3004
+ const parsed = Number(value);
3005
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
3006
+ throw new CliError(`${flag} must be a positive integer.`, {
3007
+ code: 'DATASET_IMPORT_LCA_RUNTIME_BOUND_INVALID',
3008
+ exitCode: 2,
3009
+ });
3010
+ }
3011
+ return parsed;
3012
+ }
2918
3013
  function parseDatasetAuthorFlags(args) {
2919
3014
  let values;
2920
3015
  try {
@@ -3461,6 +3556,8 @@ function parseDatasetMaintenanceApplyFlags(args) {
3461
3556
  'timeout-ms': { type: 'string' },
3462
3557
  'dry-run': { type: 'boolean' },
3463
3558
  'max-parallel': { type: 'string' },
3559
+ 'global-inbound-proof': { type: 'string' },
3560
+ 'approve-global-inbound-proof': { type: 'string' },
3464
3561
  },
3465
3562
  }));
3466
3563
  }
@@ -3483,6 +3580,25 @@ function parseDatasetMaintenanceApplyFlags(args) {
3483
3580
  exitCode: 2,
3484
3581
  });
3485
3582
  }
3583
+ const globalInboundProofPath = typeof values['global-inbound-proof'] === 'string' ? values['global-inbound-proof'] : '';
3584
+ const approveGlobalInboundProof = typeof values['approve-global-inbound-proof'] === 'string'
3585
+ ? values['approve-global-inbound-proof']
3586
+ : '';
3587
+ if (Boolean(globalInboundProofPath) !== Boolean(approveGlobalInboundProof)) {
3588
+ throw new CliError('--global-inbound-proof and --approve-global-inbound-proof must be provided together.', { code: 'INVALID_ARGS', exitCode: 2 });
3589
+ }
3590
+ if (globalInboundProofPath && maxParallel === undefined) {
3591
+ throw new CliError('Global inbound proof flags require --max-parallel.', {
3592
+ code: 'INVALID_ARGS',
3593
+ exitCode: 2,
3594
+ });
3595
+ }
3596
+ if (approveGlobalInboundProof && !/^[0-9a-f]{64}$/u.test(approveGlobalInboundProof)) {
3597
+ throw new CliError('--approve-global-inbound-proof must be a lowercase SHA-256.', {
3598
+ code: 'INVALID_ARGS',
3599
+ exitCode: 2,
3600
+ });
3601
+ }
3486
3602
  return {
3487
3603
  help: Boolean(values.help),
3488
3604
  json: Boolean(values.json),
@@ -3493,6 +3609,8 @@ function parseDatasetMaintenanceApplyFlags(args) {
3493
3609
  timeoutMs: parseDatasetMaintenancePositiveInteger(values['timeout-ms'], '--timeout-ms'),
3494
3610
  dryRun: Boolean(values['dry-run']),
3495
3611
  maxParallel,
3612
+ globalInboundProofPath,
3613
+ approveGlobalInboundProof,
3496
3614
  };
3497
3615
  }
3498
3616
  function parseDatasetMaintenanceFreezeProtectedFlags(args) {
@@ -5424,6 +5542,7 @@ function applyRemoteOverrides(env, overrides) {
5424
5542
  export async function executeCli(argv, deps) {
5425
5543
  try {
5426
5544
  const { flags, command, subcommand, commandArgs } = parseCommandLine(argv);
5545
+ const authIdentityReceiptImpl = deps.runAuthIdentityReceiptImpl ?? runAuthIdentityReceipt;
5427
5546
  const publishImpl = deps.runPublishImpl ?? runPublish;
5428
5547
  const validationImpl = deps.runValidationImpl ?? runValidation;
5429
5548
  const lcaReleaseImpl = deps.runLcaReleaseImpl ?? runLcaRelease;
@@ -5523,6 +5642,35 @@ export async function executeCli(argv, deps) {
5523
5642
  stderr: '',
5524
5643
  };
5525
5644
  }
5645
+ if (command === 'auth' && !subcommand) {
5646
+ if (commandArgs.length === 0 ||
5647
+ (commandArgs.length === 1 && ['--help', '-h'].includes(commandArgs[0]))) {
5648
+ return { exitCode: 0, stdout: `${renderAuthHelp()}\n`, stderr: '' };
5649
+ }
5650
+ throw new CliError('The auth namespace accepts only -h or --help.', {
5651
+ code: 'INVALID_ARGS',
5652
+ exitCode: 2,
5653
+ });
5654
+ }
5655
+ if (command === 'auth' && subcommand === 'identity-receipt') {
5656
+ const authFlags = parseAuthIdentityReceiptFlags(commandArgs);
5657
+ if (authFlags.help) {
5658
+ return { exitCode: 0, stdout: `${renderAuthIdentityReceiptHelp()}\n`, stderr: '' };
5659
+ }
5660
+ const receipt = await authIdentityReceiptImpl({
5661
+ env: deps.env,
5662
+ fetchImpl: deps.fetchImpl,
5663
+ cliVersion: loadCliPackageVersion(import.meta.url),
5664
+ expectedProjectRef: authFlags.expectedProjectRef,
5665
+ expectedUserId: authFlags.expectedUserId,
5666
+ timeoutMs: authFlags.timeoutMs,
5667
+ });
5668
+ return {
5669
+ exitCode: 0,
5670
+ stdout: stringifyJson(receipt, authFlags.json),
5671
+ stderr: '',
5672
+ };
5673
+ }
5526
5674
  if (command === 'search' && !subcommand && commandArgs.includes('--help')) {
5527
5675
  return { exitCode: 0, stdout: `${renderSearchHelp()}\n`, stderr: '' };
5528
5676
  }
@@ -5757,19 +5905,18 @@ export async function executeCli(argv, deps) {
5757
5905
  fromFormat: datasetFlags.fromFormat,
5758
5906
  target: datasetFlags.target,
5759
5907
  reportPath: datasetFlags.reportPath,
5760
- mappingDir: datasetFlags.mappingDir,
5761
- language: datasetFlags.language,
5762
- validationJobs: datasetFlags.validationJobs,
5908
+ writeMapping: datasetFlags.writeMapping,
5763
5909
  processBundles: datasetFlags.processBundles,
5764
- processBundlesDir: datasetFlags.processBundlesDir,
5765
- detectOnly: datasetFlags.detectOnly,
5766
5910
  failOnWarning: datasetFlags.failOnWarning,
5767
- pythonBin: datasetFlags.pythonBin,
5768
- tidasToolsDir: datasetFlags.tidasToolsDir,
5911
+ maxEntryMib: datasetFlags.maxEntryMib,
5912
+ memoryBudgetMib: datasetFlags.memoryBudgetMib,
5913
+ queueCapacity: datasetFlags.queueCapacity,
5914
+ tidasBin: datasetFlags.tidasBin,
5915
+ tidasConfig: datasetFlags.tidasConfig,
5769
5916
  env: deps.env,
5770
5917
  });
5771
5918
  return {
5772
- exitCode: report.status === 'completed' ? 0 : 1,
5919
+ exitCode: report.exit_code,
5773
5920
  stdout: stringifyJson(report, datasetFlags.json),
5774
5921
  stderr: '',
5775
5922
  };
@@ -6418,6 +6565,8 @@ export async function executeCli(argv, deps) {
6418
6565
  confirm: datasetFlags.confirm,
6419
6566
  timeoutMs: datasetFlags.timeoutMs,
6420
6567
  maxParallel: datasetFlags.maxParallel,
6568
+ globalInboundProofPath: datasetFlags.globalInboundProofPath || undefined,
6569
+ approveGlobalInboundProof: datasetFlags.approveGlobalInboundProof || undefined,
6421
6570
  env: deps.env,
6422
6571
  fetchImpl: deps.fetchImpl,
6423
6572
  });