@revturbine/cli 0.18.0 → 0.18.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.
- package/README.md +1 -1
- package/dist/cli.js +44 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -66,7 +66,7 @@ Commands that read a config name the version explicitly — there is no default:
|
|
|
66
66
|
| `init` (alias `create`) | Set up RevTurbine while preserving existing integrations: install missing packages, pin the CLI exactly, create a starter for a fresh integration, and install skills for one agent. Use `--scaffold` to create a missing root starter explicitly; existing files are never overwritten. `--agent claude-code\|cursor\|codex` overrides environment detection; an unknown agent skips skills and prints the selection command. Also supports `--dir`, `--dry-run`, `--no-skills`, `--json`. With no `package.json`, offers a new project (`--yes` for noninteractive creation). Runs the invoked CLI even inside a repo that pins a different one. |
|
|
67
67
|
| `signup` | Create an account headlessly: email + password, then an emailed one-time code to verify, then a token is stored. |
|
|
68
68
|
| `login` / `logout` | Device-flow auth; tokens stored at `~/.revturbine/credentials.json` (mode 0600). |
|
|
69
|
-
| `whoami` |
|
|
69
|
+
| `whoami` | Authentication state first: not logged in, credentials accepted, credentials rejected for the selected instance/tenant, or verification unavailable. Then shows instance, tenant, and credentials source; configured tenant information alone does not prove login. Verification and subsequent telemetry each time out after 3 seconds. Status reports exit 0. `--json` retains its seven fields: `instance`, `tenant`, `tenant_source`, `credentials_dir`, `credentials_source`, `token_present` (boolean), and `token_valid` (`true` for 2xx, `false` for 401/403, `null` when absent or unverified, including redirects, other HTTP errors, timeouts and network failures). |
|
|
70
70
|
| `schema` | Emit the bundled `RevTurbineConfig` JSON schema (for agents to author against). |
|
|
71
71
|
| `docs` | Print the canonical documentation URL. |
|
|
72
72
|
| `download` | Fetch a config version (`--live` / `--draft` / `--release <id>`); `--save`. |
|
package/dist/cli.js
CHANGED
|
@@ -10705,7 +10705,7 @@ var CLI_UNTRACKED_COMMANDS = /* @__PURE__ */ new Set(["login", "signup", "logout
|
|
|
10705
10705
|
function shouldTrackCommandExecution(name, hasUrl) {
|
|
10706
10706
|
return hasUrl && !CLI_UNTRACKED_COMMANDS.has(name);
|
|
10707
10707
|
}
|
|
10708
|
-
async function trackEvent(rawUrl, explicitTenantId, eventType, payload) {
|
|
10708
|
+
async function trackEvent(rawUrl, explicitTenantId, eventType, payload, signal) {
|
|
10709
10709
|
try {
|
|
10710
10710
|
const url = normalizeBaseUrl(rawUrl);
|
|
10711
10711
|
const cred = getCredential(url);
|
|
@@ -10717,7 +10717,8 @@ async function trackEvent(rawUrl, explicitTenantId, eventType, payload) {
|
|
|
10717
10717
|
"x-tenant-id": explicitTenantId ?? cred.tenant_id ?? "dev-tenant-001",
|
|
10718
10718
|
Authorization: `Bearer ${cred.token}`
|
|
10719
10719
|
},
|
|
10720
|
-
body: JSON.stringify({ event_type: eventType, payload })
|
|
10720
|
+
body: JSON.stringify({ event_type: eventType, payload }),
|
|
10721
|
+
...signal ? { signal } : {}
|
|
10721
10722
|
});
|
|
10722
10723
|
} catch {
|
|
10723
10724
|
}
|
|
@@ -10886,6 +10887,20 @@ async function resolveActiveDraft(baseUrl, headers, fetchImpl = fetch) {
|
|
|
10886
10887
|
return { ok: res.ok, status: res.status, draft: res.ok ? json.active ?? null : null };
|
|
10887
10888
|
}
|
|
10888
10889
|
|
|
10890
|
+
// src/lib/whoami.ts
|
|
10891
|
+
function classifyToken(hasToken, status) {
|
|
10892
|
+
if (!hasToken || status === null) return null;
|
|
10893
|
+
if (status >= 200 && status < 300) return true;
|
|
10894
|
+
if (status === 401 || status === 403) return false;
|
|
10895
|
+
return null;
|
|
10896
|
+
}
|
|
10897
|
+
function formatAuthentication(hasToken, tokenValid) {
|
|
10898
|
+
if (!hasToken) return "authentication: not logged in \u2014 run `revturbine login`";
|
|
10899
|
+
if (tokenValid === true) return "authentication: credentials accepted for this instance and tenant";
|
|
10900
|
+
if (tokenValid === false) return "authentication: credentials rejected for this instance or tenant \u2014 check access or run `revturbine login`";
|
|
10901
|
+
return "authentication: verification unavailable \u2014 credentials present; retry when the instance is reachable";
|
|
10902
|
+
}
|
|
10903
|
+
|
|
10889
10904
|
// src/lib/evaluate-local.ts
|
|
10890
10905
|
import { initRevTurbine } from "@revturbine/sdk/headless";
|
|
10891
10906
|
function resolvePlacementComponentType(input) {
|
|
@@ -11781,6 +11796,7 @@ function queryAnalyticsView(baseUrl, headers, body, fetchImpl) {
|
|
|
11781
11796
|
// src/cli.ts
|
|
11782
11797
|
var DOCS_URL = "https://github.com/revt-eng/revturbine-cli#readme";
|
|
11783
11798
|
var DEFAULT_URL = "https://revturbine.com/app";
|
|
11799
|
+
var WHOAMI_REQUEST_TIMEOUT_MS = 3e3;
|
|
11784
11800
|
function loadConfig(file) {
|
|
11785
11801
|
const resolved = path2.resolve(file);
|
|
11786
11802
|
if (!existsSync2(resolved)) fail(EXIT.USAGE, `Config not found: ${resolved}`);
|
|
@@ -11816,15 +11832,15 @@ function verifyConfig(file) {
|
|
|
11816
11832
|
if (check.advisories.length > 0) diagRaw(formatFindings(check.advisories));
|
|
11817
11833
|
return check.body;
|
|
11818
11834
|
}
|
|
11819
|
-
function connect(rawUrl, explicitTenantId) {
|
|
11835
|
+
function connect(rawUrl, explicitTenantId, diagnostic = diag) {
|
|
11820
11836
|
const url = normalizeBaseUrl(rawUrl);
|
|
11821
11837
|
const { dir, source } = resolveConfigDir();
|
|
11822
11838
|
const cred = getCredential(url);
|
|
11823
11839
|
const tenantId = explicitTenantId ?? cred?.tenant_id ?? "dev-tenant-001";
|
|
11824
11840
|
const tenantSource = explicitTenantId ? "--tenant-id" : cred?.tenant_id ? "stored token" : "default";
|
|
11825
|
-
|
|
11841
|
+
diagnostic(`Tenant ${tenantId} (${tenantSource}); credentials: ${dir} [${source}].`);
|
|
11826
11842
|
if (source === "global") {
|
|
11827
|
-
|
|
11843
|
+
diagnostic(
|
|
11828
11844
|
`WARNING: using the global ${dir} - NOT worktree-scoped. If this session is for a specific customer, run from that customer's worktree (with its own .revturbine/) so a stale login can't target the wrong tenant.`
|
|
11829
11845
|
);
|
|
11830
11846
|
}
|
|
@@ -12092,6 +12108,10 @@ Auth:
|
|
|
12092
12108
|
~/.revturbine/credentials.json (0600); the token's tenant is used by default,
|
|
12093
12109
|
override with -t/--tenant-id. Mutating commands (discard, restore) prompt
|
|
12094
12110
|
for confirmation unless --yes.
|
|
12111
|
+
\`whoami\` leads with absent, accepted, rejected, or unverifiable credentials;
|
|
12112
|
+
a configured tenant alone does not prove login. Verification and subsequent
|
|
12113
|
+
telemetry each time out after 3 seconds. Status reports exit 0; --json keeps
|
|
12114
|
+
token_present boolean and token_valid true/false/null (null = unverified).
|
|
12095
12115
|
|
|
12096
12116
|
Full reference: ${DOCS_URL}
|
|
12097
12117
|
`;
|
|
@@ -12102,7 +12122,7 @@ program.hook("postAction", async (_thisCommand, actionCommand) => {
|
|
|
12102
12122
|
if (!shouldTrackCommandExecution(actionCommand.name(), Boolean(opts.url))) return;
|
|
12103
12123
|
await trackEvent(opts.url, opts.tenantId, "cli_command_executed", {
|
|
12104
12124
|
command: actionCommand.name()
|
|
12105
|
-
});
|
|
12125
|
+
}, actionCommand.name() === "whoami" ? globalThis.AbortSignal.timeout(WHOAMI_REQUEST_TIMEOUT_MS) : void 0);
|
|
12106
12126
|
});
|
|
12107
12127
|
program.name("revturbine").description("Validate RevTurbine Playbooks and ship them through the playbook-version lifecycle (draft \u2192 Release).").version(`${pkgVersion} (schema ${SCHEMA_VERSION})`, "-V, --version", "Print the revturbine and bundled schema versions").option(NO_LOCAL_FLAG, "Ignore the repo-pinned CLI and run this installation").showHelpAfterError().addHelpText("after", HELP_AFTER);
|
|
12108
12128
|
function runInstall(manager, args, cwd) {
|
|
@@ -12350,13 +12370,22 @@ program.command("logout").description("Remove the stored token for <url>.").argu
|
|
|
12350
12370
|
const removed = removeCredential(normalized);
|
|
12351
12371
|
diag(removed ? `Logged out of ${normalized}.` : `No stored credential for ${normalized}.`);
|
|
12352
12372
|
});
|
|
12353
|
-
program.command("whoami").description("Show
|
|
12354
|
-
const
|
|
12355
|
-
|
|
12373
|
+
program.command("whoami").description("Show authentication state first (absent, accepted, rejected, or unverifiable), then instance, tenant, and credentials source.").option("-u, --url <url>", "RevTurbine instance URL", DEFAULT_URL).option("-t, --tenant-id <id>", "x-tenant-id (defaults to the stored token tenant)").option("--json", "Machine-readable output").action(async (opts) => {
|
|
12374
|
+
const diagnostics = [];
|
|
12375
|
+
const conn = connect(opts.url, opts.tenantId, (message) => diagnostics.push(message));
|
|
12376
|
+
let probeStatus = null;
|
|
12356
12377
|
if (conn.hasToken) {
|
|
12357
|
-
|
|
12358
|
-
|
|
12359
|
-
|
|
12378
|
+
probeStatus = await fetch(`${conn.url}/api/optimization/drafts`, {
|
|
12379
|
+
headers: conn.headers,
|
|
12380
|
+
signal: globalThis.AbortSignal.timeout(WHOAMI_REQUEST_TIMEOUT_MS),
|
|
12381
|
+
// A redirected login page returning 200 is not proof of authentication.
|
|
12382
|
+
redirect: "manual"
|
|
12383
|
+
}).then(async (response) => {
|
|
12384
|
+
await response.body?.cancel();
|
|
12385
|
+
return response.status;
|
|
12386
|
+
}).catch(() => null);
|
|
12387
|
+
}
|
|
12388
|
+
const tokenValid = classifyToken(conn.hasToken, probeStatus);
|
|
12360
12389
|
const data = {
|
|
12361
12390
|
instance: conn.url,
|
|
12362
12391
|
tenant: conn.tenantId,
|
|
@@ -12370,12 +12399,13 @@ program.command("whoami").description("Show the resolved instance, tenant, crede
|
|
|
12370
12399
|
data,
|
|
12371
12400
|
Boolean(opts.json),
|
|
12372
12401
|
[
|
|
12402
|
+
formatAuthentication(conn.hasToken, tokenValid),
|
|
12373
12403
|
`instance: ${data.instance}`,
|
|
12374
12404
|
`tenant: ${data.tenant} (${data.tenant_source})`,
|
|
12375
|
-
`credentials: ${data.credentials_dir} [${data.credentials_source}]
|
|
12376
|
-
`token: ${data.token_present ? tokenValid ? "present, valid" : "present, NOT accepted" : "absent \u2014 run `revturbine login`"}`
|
|
12405
|
+
`credentials: ${data.credentials_dir} [${data.credentials_source}]`
|
|
12377
12406
|
].join("\n")
|
|
12378
12407
|
);
|
|
12408
|
+
for (const message of diagnostics) diag(message);
|
|
12379
12409
|
});
|
|
12380
12410
|
program.command("schema").description("Emit the bundled RevTurbineConfig JSON schema for an agent to author against.").option("--json", "Accepted for symmetry; output is always JSON").action(() => {
|
|
12381
12411
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revturbine/cli",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "revturbine — validate RevTurbine Playbooks and ship them to a RevTurbine instance through the playbook-version lifecycle (draft → Release).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|