@tiangong-lca/cli 0.1.2 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -12
- package/dist/src/auth-identity-receipt.d.ts +2 -0
- package/dist/src/auth-identity-receipt.js +2 -0
- package/dist/src/auth-identity-receipt.js.map +1 -0
- package/dist/src/cli.d.ts +4 -0
- package/dist/src/cli.js +264 -7
- package/dist/src/cli.js.map +1 -1
- package/dist/src/lib/auth-identity-receipt.d.ts +2 -2
- package/dist/src/lib/auth-identity-receipt.js +20 -12
- package/dist/src/lib/auth-identity-receipt.js.map +1 -1
- package/dist/src/lib/env.d.ts +8 -0
- package/dist/src/lib/env.js +36 -3
- package/dist/src/lib/env.js.map +1 -1
- package/dist/src/lib/lca-release.d.ts +1 -1
- package/dist/src/lib/lca-release.js +3 -4
- package/dist/src/lib/lca-release.js.map +1 -1
- package/dist/src/lib/lifecyclemodel-resulting-process.js +6 -2
- package/dist/src/lib/lifecyclemodel-resulting-process.js.map +1 -1
- package/dist/src/lib/oauth-loopback.d.ts +52 -0
- package/dist/src/lib/oauth-loopback.js +229 -0
- package/dist/src/lib/oauth-loopback.js.map +1 -0
- package/dist/src/lib/oauth-pkce.d.ts +63 -0
- package/dist/src/lib/oauth-pkce.js +268 -0
- package/dist/src/lib/oauth-pkce.js.map +1 -0
- package/dist/src/lib/process-refresh-references.js +2 -2
- package/dist/src/lib/process-refresh-references.js.map +1 -1
- package/dist/src/lib/process-scope-statistics.js +8 -3
- package/dist/src/lib/process-scope-statistics.js.map +1 -1
- package/dist/src/lib/state-lock.js +10 -4
- package/dist/src/lib/state-lock.js.map +1 -1
- package/dist/src/lib/supabase-client.d.ts +13 -1
- package/dist/src/lib/supabase-client.js +64 -3
- package/dist/src/lib/supabase-client.js.map +1 -1
- package/dist/src/lib/supabase-json-ordered-write.js +7 -3
- package/dist/src/lib/supabase-json-ordered-write.js.map +1 -1
- package/dist/src/lib/supabase-session.d.ts +63 -8
- package/dist/src/lib/supabase-session.js +315 -21
- package/dist/src/lib/supabase-session.js.map +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -13,27 +13,33 @@ whenToUpdate:
|
|
|
13
13
|
- when user-facing command examples change
|
|
14
14
|
checkPaths:
|
|
15
15
|
- README.md
|
|
16
|
+
- .env.example
|
|
16
17
|
- package.json
|
|
17
18
|
- pnpm-workspace.yaml
|
|
18
19
|
- pnpm-lock.yaml
|
|
19
20
|
- bin/**
|
|
20
21
|
- src/cli.ts
|
|
21
22
|
- src/main.ts
|
|
23
|
+
- src/auth-identity-receipt.ts
|
|
22
24
|
- src/batch.ts
|
|
23
25
|
- src/command-spec.ts
|
|
24
26
|
- src/lib/auth-identity-receipt.ts
|
|
27
|
+
- src/lib/oauth-loopback.ts
|
|
28
|
+
- src/lib/oauth-pkce.ts
|
|
29
|
+
- src/lib/supabase-session.ts
|
|
25
30
|
- src/lib/lca-release.ts
|
|
26
31
|
- scripts/run-auth-identity-production-case.ts
|
|
27
32
|
- test/auth-identity*.test.ts
|
|
33
|
+
- test/public-auth-identity-receipt.test.ts
|
|
28
34
|
- test/lca-release*.test.ts
|
|
29
|
-
lastReviewedAt: 2026-08-
|
|
30
|
-
lastReviewedCommit:
|
|
31
|
-
lastReviewedNote: 'Reviewed for Issue #
|
|
35
|
+
lastReviewedAt: 2026-08-31
|
|
36
|
+
lastReviewedCommit: 352c11c5ffafaea1bf94133be92f3337b847866a
|
|
37
|
+
lastReviewedNote: 'Reviewed for Issue #252: identifies 0.1.5 as the replacement OAuth release after unpublished 0.1.4, preserving exports, dependencies, and release behavior.'
|
|
32
38
|
---
|
|
33
39
|
|
|
34
40
|
# TianGong LCA CLI
|
|
35
41
|
|
|
36
|
-
Package: `@tiangong-lca/cli` Executable: `tiangong-lca` Current package version: `0.1.
|
|
42
|
+
Package: `@tiangong-lca/cli` Executable: `tiangong-lca` Current package version: `0.1.5` Node: `24.19.0`
|
|
37
43
|
|
|
38
44
|
Repository development is single-track on pnpm `11.24.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.
|
|
39
45
|
|
|
@@ -53,6 +59,18 @@ Review note, 2026-08-26: Issue #236 changes only the repository and clean-consum
|
|
|
53
59
|
|
|
54
60
|
Review note, 2026-08-26: Issue #237 releases the already reviewed bounded CommandSpec/batch runtime and pnpm 11.24 toolchain as `@tiangong-lca/cli@0.1.2`. The release changes only package metadata and four live CLI-version fixtures; runtime files, public subpaths and object identities, dependencies, the sole lock, Node 24.19.0, TypeScript 7.0.2, package-manager-neutral consumers, and automated provenance path remain unchanged.
|
|
55
61
|
|
|
62
|
+
Review note, 2026-08-29: Issue #240 adds the typed `@tiangong-lca/cli/auth-identity-receipt` public parser entry without changing package version 0.1.2 or auth behavior. It directly re-exports the existing strict parser, schema/timeout constants, and receipt types; the remote runner and test internals stay private, and the previous `dist/src/lib/**` deep path remains blocked.
|
|
63
|
+
|
|
64
|
+
Review note, 2026-08-29: Issue #242 releases that public parser as `@tiangong-lca/cli@0.1.3`. Only package identity and four existing exact-version fixtures change; `./batch`, `./command-spec`, `./auth-identity-receipt`, the executable, dependencies, pnpm lock, Node 24.19.0 / TypeScript 7.0.2 toolchain, and package-manager-neutral consumer contract are otherwise unchanged.
|
|
65
|
+
|
|
66
|
+
Review note, 2026-08-31: Issue #244 adds Supabase OAuth 2.1 Authorization Code + S256 PKCE without adding a dependency or changing package version/exports. `auth login` uses a registered public client, exact literal-`127.0.0.1` callback, state validation, and shell-free system browser; it atomically stores rotating access/refresh tokens in a private session file. `auth status` performs no network request and reveals no credential or session path; `auth whoami` and `auth doctor-auth` use the live redacted identity receipt. `auth logout` deletes only that matching local session; Connected applications owns grant revocation. `TIANGONG_LCA_ACCESS_TOKEN` is a short-lived, online-verified, memory-only headless option. The reversible API key remains only as a transition fallback and is never used by OAuth mode.
|
|
67
|
+
|
|
68
|
+
Review note, 2026-08-31: Issue #247 prevents a second CLI process from failing when the first process removes `session.json.lock` between contention and metadata read. Only an absent lock is treated as released; permission, I/O, malformed-owner, timeout, and stale-owner safety behavior is unchanged.
|
|
69
|
+
|
|
70
|
+
Review note, 2026-08-31: Issue #246 releases that OAuth runtime as `@tiangong-lca/cli@0.1.4`. Only package identity and four existing exact-version fixtures change; the executable and public subpaths, dependencies, pnpm lock, Node 24.19.0 / TypeScript 7.0.2 toolchain, auth behavior, and package-manager-neutral consumer contract are otherwise unchanged.
|
|
71
|
+
|
|
72
|
+
Review note, 2026-08-31: Issue #252 replaces the stopped-unpublished 0.1.4 attempt with `@tiangong-lca/cli@0.1.5` after platform-complete session coverage merged. Only package identity, four version fixtures, and release evidence change; executable/public subpaths, OAuth behavior, dependencies, pnpm lock, Node/TypeScript toolchain, and consumer contract stay unchanged.
|
|
73
|
+
|
|
56
74
|
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.
|
|
57
75
|
|
|
58
76
|
Review note, 2026-07-13: maintenance scans now prove exact-count pagination even when PostgREST returns fewer rows than the requested `--page-size`. An incomplete or inconsistent scan fails before artifacts, approval, or mutation; under stable filtered membership/order the proof represents a complete ordered multi-request traversal, not one transaction-level/MVCC snapshot.
|
|
@@ -108,11 +126,12 @@ node ./bin/tiangong-lca.js --help
|
|
|
108
126
|
|
|
109
127
|
The package exposes only these supported module APIs in addition to the executable launcher subpath:
|
|
110
128
|
|
|
129
|
+
- `@tiangong-lca/cli/auth-identity-receipt` parses the exact safe receipt projection offline and exports its schema, Node-safe timeout ceiling, and receipt types. It does not expose session resolution, network execution, or test internals; callers that need a fresh receipt still invoke the CLI command.
|
|
111
130
|
- `@tiangong-lca/cli/command-spec` parses, creates, artifact-binds, and executes exact `tiangong-foundry.command-spec.v1` objects. `display` is diagnostic only; executable plus argv and binding bytes/SHA-256 form the canonical authority. Sync and async execution always use `shell:false`; async callers may inject resolver, clock, sleep, spawn, timeout, and abort adapters. `timeoutMs` must fit Node's maximum timer delay.
|
|
112
131
|
- `@tiangong-lca/cli/batch` runs bounded generic work with an overall run contract and a required per-item `{ item_id, content_sha256, policy_sha256 }` contract. Every identity/content/policy/resource projection is validated before work starts and rechecked before resumed acceptance or a fresh claim. Identity changes or getter failures emit `item_identity_drift` with `BatchItemIdentityDriftError`, execute zero attempts, and do not let the batch return before other in-flight items drain. An escaping scheduler/event/stop callback records the first infrastructure error, closes further claims, awaits all worker settlements, then rejects. Input order, truthful resource-aware claim order, completion order, pause/stop behavior, awaited monotonic events, and exception isolation are explicit. Optional exclusive keys serialize only matching resources; a blocked key remains unclaimed and consumes no worker while later free keys may use the public ceiling of 64 workers. Per-resource FIFO queues expose only their head through an ordered binary min-heap, giving near `O(n log k)` ready scheduling for `k` resources.
|
|
113
132
|
- Mutation batches reject automatic retry. A consumed or ambiguous mutation can continue only through an explicitly supplied readback-recovery callback; resume requires exact run and item contracts, and each resumed or rejected result participates in stop decisions before fresh claims. Retry/backoff values must be non-negative safe integers within Node's timer limit. Exclusive keys must be runtime strings. `withBatchRunLock` gives one canonical run directory one cross-process lock domain, permits reentrancy only from a still-live scope owned by the current holder, keeps the top-level promise pending until detached nested scopes drain, rejects completed-context reentry into a later owner, preserves live or foreign-host locks, and stale-recovers only a same-host dead PID. Public lock callers cannot set PID, host, or ownership time; timeout/poll values are non-negative safe integers within Node's timer limit.
|
|
114
133
|
|
|
115
|
-
The packed ESM, CJS dynamic-import, and TypeScript consumers exercise
|
|
134
|
+
The packed ESM, CJS dynamic-import, and TypeScript consumers exercise every public subpath and generated declaration. Deep imports and `import '@tiangong-lca/cli'` remain unsupported.
|
|
116
135
|
|
|
117
136
|
## Env
|
|
118
137
|
|
|
@@ -120,25 +139,45 @@ Remote commands require:
|
|
|
120
139
|
|
|
121
140
|
```bash
|
|
122
141
|
TIANGONG_LCA_API_BASE_URL=
|
|
123
|
-
TIANGONG_LCA_API_KEY=
|
|
124
142
|
TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY=
|
|
143
|
+
TIANGONG_LCA_OAUTH_CLIENT_ID=
|
|
125
144
|
TIANGONG_LCA_REGION=us-east-1
|
|
126
145
|
```
|
|
127
146
|
|
|
128
147
|
Notes:
|
|
129
148
|
|
|
130
149
|
- `TIANGONG_LCA_API_BASE_URL` accepts the project root, `/functions/v1`, or `/rest/v1`.
|
|
131
|
-
- `
|
|
132
|
-
-
|
|
150
|
+
- `TIANGONG_LCA_OAUTH_CLIENT_ID` is the environment-specific registered public CLI client; it is not a secret.
|
|
151
|
+
- Run `tiangong-lca auth login` once in a trusted terminal. All Edge Function and direct Supabase commands then reuse the OAuth access token and rotate the refresh token on demand.
|
|
152
|
+
- For approved headless execution, set `TIANGONG_LCA_AUTH_MODE=access-token` and inject one short-lived `TIANGONG_LCA_ACCESS_TOKEN`. It is verified online, kept only in process memory, and never refreshed.
|
|
153
|
+
- Transition-only compatibility uses `TIANGONG_LCA_AUTH_MODE=legacy-user-api-key` plus `TIANGONG_LCA_API_KEY`. OAuth failures never fall back to this password-equivalent credential.
|
|
133
154
|
|
|
134
155
|
Optional session control:
|
|
135
156
|
|
|
136
157
|
```bash
|
|
158
|
+
TIANGONG_LCA_AUTH_MODE=oauth
|
|
159
|
+
TIANGONG_LCA_OAUTH_REDIRECT_URI=http://127.0.0.1:49191/oauth/callback
|
|
137
160
|
TIANGONG_LCA_SESSION_FILE=
|
|
138
161
|
TIANGONG_LCA_DISABLE_SESSION_CACHE=false
|
|
139
162
|
TIANGONG_LCA_FORCE_REAUTH=false
|
|
140
163
|
```
|
|
141
164
|
|
|
165
|
+
## OAuth Session Commands
|
|
166
|
+
|
|
167
|
+
```text
|
|
168
|
+
tiangong-lca auth login
|
|
169
|
+
tiangong-lca auth status --json
|
|
170
|
+
tiangong-lca auth whoami --json
|
|
171
|
+
tiangong-lca auth doctor-auth --json
|
|
172
|
+
tiangong-lca auth logout
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The callback URI must exactly match the URI registered with the selected Supabase OAuth client. The default is `http://127.0.0.1:49191/oauth/callback`; OAuth client redirect URIs do not support wildcards. Login never accepts a username, password, authorization code, access token, refresh token, or PKCE verifier through argv. On POSIX, the app directory is `0700` and `session.json` is `0600`; writes and refresh-token rotation use a temporary file, atomic rename, and the existing cross-process state lock. Windows callers must keep the selected parent ACL current-user-only because chmod bits are not an ACL.
|
|
176
|
+
|
|
177
|
+
`auth status` is intentionally local-only and non-mutating. It reports whether a matching session can be used or refreshed, but sets `onlineVerified: false`; it never prints email, tokens, a session path, or a credential fingerprint. `auth whoami` performs the live redacted identity receipt. `auth doctor-auth` first checks local readiness, then performs that live check; a missing OAuth session returns `login-required` so a human can run `auth login`. An AI agent must never ask for or handle the user's password, authorization code, access token, or refresh token.
|
|
178
|
+
|
|
179
|
+
Local logout does not revoke the server grant. To invalidate every refresh token for the CLI client, open Account → Connected applications and disconnect TianGong CLI.
|
|
180
|
+
|
|
142
181
|
## Auth Identity Receipt
|
|
143
182
|
|
|
144
183
|
Use the identity receipt before a production-backed case or any later owner-draft write gate:
|
|
@@ -147,7 +186,7 @@ Use the identity receipt before a production-backed case or any later owner-draf
|
|
|
147
186
|
tiangong-lca auth identity-receipt --expected-project-ref <project-ref> --expected-user-id <user-id> --json
|
|
148
187
|
```
|
|
149
188
|
|
|
150
|
-
The command performs no dataset write. It
|
|
189
|
+
The command performs no dataset write. It resolves the selected OAuth, explicit headless, or transition-only legacy session, checks the canonical Supabase project, and makes a bounded live `GET /auth/v1/user`. A refreshable cached token that receives `401` or `403` may be refreshed and retried exactly once; an explicit headless access token is never refreshed. All other transport or response failures are terminal. A valid production guard requires:
|
|
151
190
|
|
|
152
191
|
- `schema` exactly `tiangong-lca.auth-identity-receipt.v1`;
|
|
153
192
|
- `status: "passed"`, `operation: "current-user-read"`, and `remote_write_mode: "read-only"`;
|
|
@@ -162,7 +201,7 @@ For the explicitly authorized local production read case from a validated reposi
|
|
|
162
201
|
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>
|
|
163
202
|
```
|
|
164
203
|
|
|
165
|
-
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
|
|
204
|
+
The historical production-case runner remains a transition-only legacy fixture: it 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 explicit legacy 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. New automation should use OAuth/headless mode instead. This receipt is locally hash-verifiable, not server-signed attestation.
|
|
166
205
|
|
|
167
206
|
## LCI/LCIA Data Release
|
|
168
207
|
|
|
@@ -228,7 +267,7 @@ tiangong-lca release status --release-run-id <release-run-id> --json
|
|
|
228
267
|
}
|
|
229
268
|
```
|
|
230
269
|
|
|
231
|
-
The CLI verifies every local upload against its declared byte size, SHA-256, media type, and required pair before requesting signed URLs. Upload receipts and downloads are written atomically with private file permissions. Existing outputs are preserved unless `--force` is explicit.
|
|
270
|
+
The CLI verifies every local upload against its declared byte size, SHA-256, media type, and required pair before requesting signed URLs. Upload receipts and downloads are written atomically with private file permissions. Existing outputs are preserved unless `--force` is explicit. Release requests use the resolved actor access token and `client_id`-aware database policy; no credential-derived fingerprint is accepted from local state or the request file.
|
|
232
271
|
|
|
233
272
|
Calculation results and published artifacts remain file-first:
|
|
234
273
|
|
|
@@ -318,7 +357,7 @@ Key outputs under `--out-dir`:
|
|
|
318
357
|
- `outputs/identity-candidates.jsonl`
|
|
319
358
|
- `outputs/identity-candidate-sources.json`
|
|
320
359
|
|
|
321
|
-
`--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
|
|
360
|
+
`--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 OAuth session env above and optional `TIANGONG_LCA_REGION`.
|
|
322
361
|
|
|
323
362
|
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.
|
|
324
363
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-identity-receipt.js","sourceRoot":"","sources":["../../src/auth-identity-receipt.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,4BAA4B,EAC5B,wBAAwB,GACzB,MAAM,gCAAgC,CAAC","sourcesContent":["export {\n AUTH_IDENTITY_MAX_TIMEOUT_MS,\n AUTH_IDENTITY_RECEIPT_SCHEMA,\n parseAuthIdentityReceipt,\n} from './lib/auth-identity-receipt.js';\nexport type { AuthIdentityReceipt, AuthIdentityReceiptScope } from './lib/auth-identity-receipt.js';\n"]}
|
package/dist/src/cli.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DotEnvLoadResult } from './lib/dotenv.js';
|
|
2
2
|
import type { FetchLike } from './lib/http.js';
|
|
3
|
+
import { inspectSupabaseAuthStatus, loginWithSupabaseOAuth, logoutSupabaseUserSession } from './lib/supabase-session.js';
|
|
3
4
|
import { type AuthIdentityReceipt, type RunAuthIdentityReceiptOptions } from './lib/auth-identity-receipt.js';
|
|
4
5
|
import { type LifecyclemodelAutoBuildReport, type RunLifecyclemodelAutoBuildOptions } from './lib/lifecyclemodel-auto-build.js';
|
|
5
6
|
import { type LifecyclemodelResultingProcessReport, type RunLifecyclemodelResultingProcessOptions } from './lib/lifecyclemodel-resulting-process.js';
|
|
@@ -71,6 +72,9 @@ export type CliDeps = {
|
|
|
71
72
|
dotEnvStatus: DotEnvLoadResult;
|
|
72
73
|
fetchImpl: FetchLike;
|
|
73
74
|
runAuthIdentityReceiptImpl?: (options: RunAuthIdentityReceiptOptions) => Promise<AuthIdentityReceipt>;
|
|
75
|
+
loginWithSupabaseOAuthImpl?: typeof loginWithSupabaseOAuth;
|
|
76
|
+
logoutSupabaseUserSessionImpl?: typeof logoutSupabaseUserSession;
|
|
77
|
+
inspectSupabaseAuthStatusImpl?: typeof inspectSupabaseAuthStatus;
|
|
74
78
|
runPublishImpl?: (options: RunPublishOptions) => Promise<PublishReport>;
|
|
75
79
|
runValidationImpl?: (options: RunValidationOptions) => Promise<ValidationRunReport>;
|
|
76
80
|
runLcaReleaseImpl?: (options: RunLcaReleaseOptions) => Promise<LcaReleaseReport>;
|
package/dist/src/cli.js
CHANGED
|
@@ -3,6 +3,9 @@ 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 { requireSupabaseRestRuntime } from './lib/supabase-client.js';
|
|
7
|
+
import { inspectSupabaseAuthStatus, loginWithSupabaseOAuth, logoutSupabaseUserSession, } from './lib/supabase-session.js';
|
|
8
|
+
import { OAUTH_LOGIN_TIMEOUT_MAX_MS } from './lib/oauth-loopback.js';
|
|
6
9
|
import { AUTH_IDENTITY_MAX_TIMEOUT_MS, AUTH_IDENTITY_RECEIPT_SCHEMA, runAuthIdentityReceipt, } from './lib/auth-identity-receipt.js';
|
|
7
10
|
import { runLifecyclemodelAutoBuild, } from './lib/lifecyclemodel-auto-build.js';
|
|
8
11
|
import { runLifecyclemodelBuildResultingProcess, } from './lib/lifecyclemodel-resulting-process.js';
|
|
@@ -87,7 +90,7 @@ Usage:
|
|
|
87
90
|
Commands:
|
|
88
91
|
Implemented Commands:
|
|
89
92
|
doctor show environment diagnostics
|
|
90
|
-
auth identity-receipt
|
|
93
|
+
auth login | status | whoami | doctor-auth | logout | identity-receipt
|
|
91
94
|
search flow | process | lifecyclemodel
|
|
92
95
|
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
|
|
93
96
|
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
|
|
@@ -100,13 +103,17 @@ Implemented Commands:
|
|
|
100
103
|
admin embedding-run
|
|
101
104
|
|
|
102
105
|
Planned Surface (not implemented yet):
|
|
103
|
-
auth whoami | doctor-auth
|
|
104
106
|
job get | wait | logs
|
|
105
107
|
|
|
106
108
|
Planned commands currently print an explicit "not implemented yet" message and exit with code 2.
|
|
107
109
|
|
|
108
110
|
Examples:
|
|
109
111
|
tiangong-lca doctor
|
|
112
|
+
tiangong-lca auth login
|
|
113
|
+
tiangong-lca auth status --json
|
|
114
|
+
tiangong-lca auth whoami --json
|
|
115
|
+
tiangong-lca auth doctor-auth --json
|
|
116
|
+
tiangong-lca auth logout
|
|
110
117
|
tiangong-lca auth identity-receipt --expected-project-ref <project-ref> --expected-user-id <user-id> --json
|
|
111
118
|
tiangong-lca search flow --input ./request.json
|
|
112
119
|
tiangong-lca search process --input ./request.json --dry-run
|
|
@@ -185,15 +192,79 @@ Environment:
|
|
|
185
192
|
}
|
|
186
193
|
function renderAuthHelp() {
|
|
187
194
|
return `Usage:
|
|
188
|
-
tiangong-lca auth identity-receipt [options]
|
|
195
|
+
tiangong-lca auth <login|status|whoami|doctor-auth|logout|identity-receipt> [options]
|
|
189
196
|
|
|
190
197
|
Implemented Subcommands:
|
|
198
|
+
login Authorize the registered public CLI through browser PKCE and store a private rotating session
|
|
199
|
+
status Inspect only local auth readiness without reading or printing credentials
|
|
200
|
+
whoami Run the live, redacted identity receipt for the current user
|
|
201
|
+
doctor-auth Combine local readiness with a live, redacted identity check
|
|
202
|
+
logout Remove only this local CLI session; revoke the connected-app grant from the account page
|
|
191
203
|
identity-receipt Live, read-only proof of the authenticated account and Supabase project
|
|
192
204
|
|
|
193
|
-
|
|
194
|
-
|
|
205
|
+
Use "tiangong-lca auth <subcommand> --help" for details.
|
|
206
|
+
`.trim();
|
|
207
|
+
}
|
|
208
|
+
function renderAuthStatusHelp() {
|
|
209
|
+
return `Usage:
|
|
210
|
+
tiangong-lca auth status [--json]
|
|
211
|
+
|
|
212
|
+
Inspects only the matching local session metadata. It performs no network request, never refreshes
|
|
213
|
+
a token, and never emits email, token, session path, or credential fingerprint. A ready result can
|
|
214
|
+
still be remotely revoked; use "auth doctor-auth" when live verification is required. If OAuth login
|
|
215
|
+
is required, hand the terminal to the human user and run "tiangong-lca auth login". Never ask an AI
|
|
216
|
+
agent to collect a username, password, authorization code, access token, or refresh token.
|
|
217
|
+
`.trim();
|
|
218
|
+
}
|
|
219
|
+
function renderAuthWhoamiHelp() {
|
|
220
|
+
return `Usage:
|
|
221
|
+
tiangong-lca auth whoami [--timeout-ms <n>] [--json]
|
|
222
|
+
|
|
223
|
+
Runs the same live, read-only and redacted proof as "auth identity-receipt" without requiring an
|
|
224
|
+
expected identity assertion. It may refresh an OAuth session under the private session lock. Output
|
|
225
|
+
contains no token, full email address, session path, or credential fingerprint.
|
|
226
|
+
`.trim();
|
|
227
|
+
}
|
|
228
|
+
function renderAuthDoctorHelp() {
|
|
229
|
+
return `Usage:
|
|
230
|
+
tiangong-lca auth doctor-auth [--timeout-ms <n>] [--json]
|
|
231
|
+
|
|
232
|
+
First checks local readiness without network access. If ready, it performs the live redacted identity
|
|
233
|
+
receipt. Missing OAuth authorization returns login-required without attempting password bootstrap.
|
|
234
|
+
Run "tiangong-lca auth login" only in a trusted human-controlled terminal.
|
|
235
|
+
`.trim();
|
|
236
|
+
}
|
|
237
|
+
function renderAuthLoginHelp() {
|
|
238
|
+
return `Usage:
|
|
239
|
+
tiangong-lca auth login [options]
|
|
240
|
+
|
|
241
|
+
Options:
|
|
242
|
+
--timeout-ms <n> Browser callback timeout 1..${OAUTH_LOGIN_TIMEOUT_MAX_MS} ms (default: 180000)
|
|
243
|
+
--json Print compact JSON; default output is pretty JSON
|
|
244
|
+
-h, --help
|
|
245
|
+
|
|
246
|
+
Required env:
|
|
247
|
+
TIANGONG_LCA_API_BASE_URL
|
|
248
|
+
TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
|
|
249
|
+
TIANGONG_LCA_OAUTH_CLIENT_ID
|
|
250
|
+
|
|
251
|
+
Optional env:
|
|
252
|
+
TIANGONG_LCA_AUTH_MODE=oauth
|
|
253
|
+
TIANGONG_LCA_OAUTH_REDIRECT_URI (default: exact registered 127.0.0.1 callback)
|
|
254
|
+
TIANGONG_LCA_SESSION_FILE
|
|
255
|
+
|
|
256
|
+
The CLI binds only 127.0.0.1, opens the system browser without a shell, verifies state and S256
|
|
257
|
+
PKCE, and atomically writes access/rotating refresh tokens to a private session file. It never
|
|
258
|
+
accepts a username, password, authorization code, access token, or refresh token as an argv value.
|
|
259
|
+
`.trim();
|
|
260
|
+
}
|
|
261
|
+
function renderAuthLogoutHelp() {
|
|
262
|
+
return `Usage:
|
|
263
|
+
tiangong-lca auth logout [--json]
|
|
195
264
|
|
|
196
|
-
|
|
265
|
+
Removes only the locally cached session bound to the current project/client. To revoke the OAuth
|
|
266
|
+
grant and every refresh token, disconnect TianGong CLI from Connected applications in the account
|
|
267
|
+
page. An explicit TIANGONG_LCA_ACCESS_TOKEN is never persisted and therefore has nothing to delete.
|
|
197
268
|
`.trim();
|
|
198
269
|
}
|
|
199
270
|
function renderAuthIdentityReceiptHelp() {
|
|
@@ -218,8 +289,14 @@ Safety:
|
|
|
218
289
|
|
|
219
290
|
Required env:
|
|
220
291
|
TIANGONG_LCA_API_BASE_URL
|
|
221
|
-
TIANGONG_LCA_API_KEY
|
|
222
292
|
TIANGONG_LCA_SUPABASE_PUBLISHABLE_KEY
|
|
293
|
+
TIANGONG_LCA_OAUTH_CLIENT_ID and a prior "tiangong-lca auth login"
|
|
294
|
+
|
|
295
|
+
Headless alternative:
|
|
296
|
+
TIANGONG_LCA_ACCESS_TOKEN (short-lived actor token; never cached or refreshed)
|
|
297
|
+
|
|
298
|
+
Legacy compatibility:
|
|
299
|
+
TIANGONG_LCA_AUTH_MODE=legacy-user-api-key plus TIANGONG_LCA_API_KEY
|
|
223
300
|
|
|
224
301
|
Optional session env:
|
|
225
302
|
TIANGONG_LCA_SESSION_FILE
|
|
@@ -2369,6 +2446,99 @@ function parseAuthIdentityReceiptFlags(args) {
|
|
|
2369
2446
|
timeoutMs,
|
|
2370
2447
|
};
|
|
2371
2448
|
}
|
|
2449
|
+
function parseAuthLoginFlags(args) {
|
|
2450
|
+
let parsed;
|
|
2451
|
+
try {
|
|
2452
|
+
parsed = parseArgs({
|
|
2453
|
+
args,
|
|
2454
|
+
allowPositionals: false,
|
|
2455
|
+
strict: true,
|
|
2456
|
+
tokens: true,
|
|
2457
|
+
options: {
|
|
2458
|
+
help: { type: 'boolean', short: 'h' },
|
|
2459
|
+
json: { type: 'boolean' },
|
|
2460
|
+
'timeout-ms': { type: 'string' },
|
|
2461
|
+
},
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
catch (error) {
|
|
2465
|
+
throw new CliError(String(error), { code: 'INVALID_ARGS', exitCode: 2 });
|
|
2466
|
+
}
|
|
2467
|
+
const timeoutOccurrences = parsed.tokens.filter((entry) => entry.kind === 'option' && entry.name === 'timeout-ms').length;
|
|
2468
|
+
if (timeoutOccurrences > 1) {
|
|
2469
|
+
throw new CliError('Option --timeout-ms may be provided only once.', {
|
|
2470
|
+
code: 'INVALID_ARGS',
|
|
2471
|
+
exitCode: 2,
|
|
2472
|
+
});
|
|
2473
|
+
}
|
|
2474
|
+
const timeoutText = parsed.values['timeout-ms'];
|
|
2475
|
+
const timeoutMs = typeof timeoutText === 'string' ? Number(timeoutText) : 180_000;
|
|
2476
|
+
if (!Number.isSafeInteger(timeoutMs) ||
|
|
2477
|
+
timeoutMs <= 0 ||
|
|
2478
|
+
timeoutMs > OAUTH_LOGIN_TIMEOUT_MAX_MS) {
|
|
2479
|
+
throw new CliError(`Expected --timeout-ms to be an integer between 1 and ${OAUTH_LOGIN_TIMEOUT_MAX_MS}.`, { code: 'INVALID_TIMEOUT', exitCode: 2 });
|
|
2480
|
+
}
|
|
2481
|
+
return {
|
|
2482
|
+
help: Boolean(parsed.values.help),
|
|
2483
|
+
json: Boolean(parsed.values.json),
|
|
2484
|
+
timeoutMs,
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2487
|
+
function parseAuthLogoutFlags(args) {
|
|
2488
|
+
try {
|
|
2489
|
+
const { values } = parseArgs({
|
|
2490
|
+
args,
|
|
2491
|
+
allowPositionals: false,
|
|
2492
|
+
strict: true,
|
|
2493
|
+
options: {
|
|
2494
|
+
help: { type: 'boolean', short: 'h' },
|
|
2495
|
+
json: { type: 'boolean' },
|
|
2496
|
+
},
|
|
2497
|
+
});
|
|
2498
|
+
return { help: Boolean(values.help), json: Boolean(values.json) };
|
|
2499
|
+
}
|
|
2500
|
+
catch (error) {
|
|
2501
|
+
throw new CliError(String(error), { code: 'INVALID_ARGS', exitCode: 2 });
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
function parseAuthLiveFlags(args) {
|
|
2505
|
+
let parsed;
|
|
2506
|
+
try {
|
|
2507
|
+
parsed = parseArgs({
|
|
2508
|
+
args,
|
|
2509
|
+
allowPositionals: false,
|
|
2510
|
+
strict: true,
|
|
2511
|
+
tokens: true,
|
|
2512
|
+
options: {
|
|
2513
|
+
help: { type: 'boolean', short: 'h' },
|
|
2514
|
+
json: { type: 'boolean' },
|
|
2515
|
+
'timeout-ms': { type: 'string' },
|
|
2516
|
+
},
|
|
2517
|
+
});
|
|
2518
|
+
}
|
|
2519
|
+
catch (error) {
|
|
2520
|
+
throw new CliError(String(error), { code: 'INVALID_ARGS', exitCode: 2 });
|
|
2521
|
+
}
|
|
2522
|
+
const timeoutOccurrences = parsed.tokens.filter((entry) => entry.kind === 'option' && entry.name === 'timeout-ms').length;
|
|
2523
|
+
if (timeoutOccurrences > 1) {
|
|
2524
|
+
throw new CliError('Option --timeout-ms may be provided only once.', {
|
|
2525
|
+
code: 'INVALID_ARGS',
|
|
2526
|
+
exitCode: 2,
|
|
2527
|
+
});
|
|
2528
|
+
}
|
|
2529
|
+
const timeoutText = parsed.values['timeout-ms'];
|
|
2530
|
+
const timeoutMs = typeof timeoutText === 'string' ? Number(timeoutText) : 10_000;
|
|
2531
|
+
if (!Number.isSafeInteger(timeoutMs) ||
|
|
2532
|
+
timeoutMs <= 0 ||
|
|
2533
|
+
timeoutMs > AUTH_IDENTITY_MAX_TIMEOUT_MS) {
|
|
2534
|
+
throw new CliError(`Expected --timeout-ms to be an integer between 1 and ${AUTH_IDENTITY_MAX_TIMEOUT_MS}.`, { code: 'INVALID_TIMEOUT', exitCode: 2 });
|
|
2535
|
+
}
|
|
2536
|
+
return {
|
|
2537
|
+
help: Boolean(parsed.values.help),
|
|
2538
|
+
json: Boolean(parsed.values.json),
|
|
2539
|
+
timeoutMs,
|
|
2540
|
+
};
|
|
2541
|
+
}
|
|
2372
2542
|
function parseRemoteFlags(args) {
|
|
2373
2543
|
let values;
|
|
2374
2544
|
try {
|
|
@@ -5543,6 +5713,9 @@ export async function executeCli(argv, deps) {
|
|
|
5543
5713
|
try {
|
|
5544
5714
|
const { flags, command, subcommand, commandArgs } = parseCommandLine(argv);
|
|
5545
5715
|
const authIdentityReceiptImpl = deps.runAuthIdentityReceiptImpl ?? runAuthIdentityReceipt;
|
|
5716
|
+
const oauthLoginImpl = deps.loginWithSupabaseOAuthImpl ?? loginWithSupabaseOAuth;
|
|
5717
|
+
const oauthLogoutImpl = deps.logoutSupabaseUserSessionImpl ?? logoutSupabaseUserSession;
|
|
5718
|
+
const authStatusImpl = deps.inspectSupabaseAuthStatusImpl ?? inspectSupabaseAuthStatus;
|
|
5546
5719
|
const publishImpl = deps.runPublishImpl ?? runPublish;
|
|
5547
5720
|
const validationImpl = deps.runValidationImpl ?? runValidation;
|
|
5548
5721
|
const lcaReleaseImpl = deps.runLcaReleaseImpl ?? runLcaRelease;
|
|
@@ -5671,6 +5844,90 @@ export async function executeCli(argv, deps) {
|
|
|
5671
5844
|
stderr: '',
|
|
5672
5845
|
};
|
|
5673
5846
|
}
|
|
5847
|
+
if (command === 'auth' && subcommand === 'status') {
|
|
5848
|
+
const authFlags = parseAuthLogoutFlags(commandArgs);
|
|
5849
|
+
if (authFlags.help) {
|
|
5850
|
+
return { exitCode: 0, stdout: `${renderAuthStatusHelp()}\n`, stderr: '' };
|
|
5851
|
+
}
|
|
5852
|
+
const receipt = authStatusImpl({ runtime: requireSupabaseRestRuntime(deps.env) });
|
|
5853
|
+
return {
|
|
5854
|
+
exitCode: receipt.status === 'ready' ? 0 : 1,
|
|
5855
|
+
stdout: stringifyJson(receipt, authFlags.json),
|
|
5856
|
+
stderr: '',
|
|
5857
|
+
};
|
|
5858
|
+
}
|
|
5859
|
+
if (command === 'auth' && subcommand === 'whoami') {
|
|
5860
|
+
const authFlags = parseAuthLiveFlags(commandArgs);
|
|
5861
|
+
if (authFlags.help) {
|
|
5862
|
+
return { exitCode: 0, stdout: `${renderAuthWhoamiHelp()}\n`, stderr: '' };
|
|
5863
|
+
}
|
|
5864
|
+
const receipt = await authIdentityReceiptImpl({
|
|
5865
|
+
env: deps.env,
|
|
5866
|
+
fetchImpl: deps.fetchImpl,
|
|
5867
|
+
cliVersion: loadCliPackageVersion(import.meta.url),
|
|
5868
|
+
expectedProjectRef: null,
|
|
5869
|
+
expectedUserId: null,
|
|
5870
|
+
timeoutMs: authFlags.timeoutMs,
|
|
5871
|
+
});
|
|
5872
|
+
return { exitCode: 0, stdout: stringifyJson(receipt, authFlags.json), stderr: '' };
|
|
5873
|
+
}
|
|
5874
|
+
if (command === 'auth' && subcommand === 'doctor-auth') {
|
|
5875
|
+
const authFlags = parseAuthLiveFlags(commandArgs);
|
|
5876
|
+
if (authFlags.help) {
|
|
5877
|
+
return { exitCode: 0, stdout: `${renderAuthDoctorHelp()}\n`, stderr: '' };
|
|
5878
|
+
}
|
|
5879
|
+
const local = authStatusImpl({ runtime: requireSupabaseRestRuntime(deps.env) });
|
|
5880
|
+
if (local.status !== 'ready') {
|
|
5881
|
+
return {
|
|
5882
|
+
exitCode: 1,
|
|
5883
|
+
stdout: stringifyJson({
|
|
5884
|
+
schemaVersion: 'tiangong.cli-auth-doctor.v1',
|
|
5885
|
+
status: 'login-required',
|
|
5886
|
+
local,
|
|
5887
|
+
live: null,
|
|
5888
|
+
}, authFlags.json),
|
|
5889
|
+
stderr: '',
|
|
5890
|
+
};
|
|
5891
|
+
}
|
|
5892
|
+
const live = await authIdentityReceiptImpl({
|
|
5893
|
+
env: deps.env,
|
|
5894
|
+
fetchImpl: deps.fetchImpl,
|
|
5895
|
+
cliVersion: loadCliPackageVersion(import.meta.url),
|
|
5896
|
+
expectedProjectRef: null,
|
|
5897
|
+
expectedUserId: null,
|
|
5898
|
+
timeoutMs: authFlags.timeoutMs,
|
|
5899
|
+
});
|
|
5900
|
+
return {
|
|
5901
|
+
exitCode: 0,
|
|
5902
|
+
stdout: stringifyJson({
|
|
5903
|
+
schemaVersion: 'tiangong.cli-auth-doctor.v1',
|
|
5904
|
+
status: 'passed',
|
|
5905
|
+
local,
|
|
5906
|
+
live,
|
|
5907
|
+
}, authFlags.json),
|
|
5908
|
+
stderr: '',
|
|
5909
|
+
};
|
|
5910
|
+
}
|
|
5911
|
+
if (command === 'auth' && subcommand === 'login') {
|
|
5912
|
+
const authFlags = parseAuthLoginFlags(commandArgs);
|
|
5913
|
+
if (authFlags.help) {
|
|
5914
|
+
return { exitCode: 0, stdout: `${renderAuthLoginHelp()}\n`, stderr: '' };
|
|
5915
|
+
}
|
|
5916
|
+
const receipt = await oauthLoginImpl({
|
|
5917
|
+
runtime: requireSupabaseRestRuntime(deps.env),
|
|
5918
|
+
fetchImpl: deps.fetchImpl,
|
|
5919
|
+
loginTimeoutMs: authFlags.timeoutMs,
|
|
5920
|
+
});
|
|
5921
|
+
return { exitCode: 0, stdout: stringifyJson(receipt, authFlags.json), stderr: '' };
|
|
5922
|
+
}
|
|
5923
|
+
if (command === 'auth' && subcommand === 'logout') {
|
|
5924
|
+
const authFlags = parseAuthLogoutFlags(commandArgs);
|
|
5925
|
+
if (authFlags.help) {
|
|
5926
|
+
return { exitCode: 0, stdout: `${renderAuthLogoutHelp()}\n`, stderr: '' };
|
|
5927
|
+
}
|
|
5928
|
+
const receipt = await oauthLogoutImpl({ runtime: requireSupabaseRestRuntime(deps.env) });
|
|
5929
|
+
return { exitCode: 0, stdout: stringifyJson(receipt, authFlags.json), stderr: '' };
|
|
5930
|
+
}
|
|
5674
5931
|
if (command === 'search' && !subcommand && commandArgs.includes('--help')) {
|
|
5675
5932
|
return { exitCode: 0, stdout: `${renderSearchHelp()}\n`, stderr: '' };
|
|
5676
5933
|
}
|