@dreamlake/dreamlake-cli 0.1.0 → 0.9.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/bin/dreamlake.js CHANGED
@@ -1,41 +1,37 @@
1
1
  #!/usr/bin/env node
2
- // `dreamlake` CLI entry. Picks the compiled JS if present (production
3
- // install), else falls back to running the TS source through tsx
4
- // (workspace dev — no `pnpm build` required).
2
+ "use strict";
3
+ const { spawnSync } = require("node:child_process");
5
4
 
6
- import { existsSync } from "node:fs";
7
- import { fileURLToPath, pathToFileURL } from "node:url";
8
- import path from "node:path";
5
+ function isMusl() {
6
+ if (process.platform !== "linux") return false;
7
+ try {
8
+ return !process.report.getReport().header.glibcVersionRuntime;
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
9
13
 
10
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
- const distEntry = path.join(__dirname, "..", "dist", "cli", "index.js");
12
- const srcEntry = path.join(__dirname, "..", "src", "cli", "index.ts");
14
+ const key = process.platform + "-" + process.arch + (isMusl() ? "-musl" : "");
15
+ const pkg = "@dreamlake/dreamlake-cli-" + key;
16
+ const bin = process.platform === "win32" ? "dreamlake.exe" : "dreamlake";
13
17
 
14
- async function run() {
15
- if (existsSync(distEntry)) {
16
- await import(pathToFileURL(distEntry).href);
17
- return;
18
- }
19
- if (existsSync(srcEntry)) {
20
- // Register tsx as a module loader, then import the TS source.
21
- let tsx;
22
- try {
23
- tsx = await import("tsx/esm/api");
24
- } catch {
25
- console.error(
26
- "dreamlake: dist/ is missing and tsx is not installed — run `pnpm install && pnpm build` first",
27
- );
28
- process.exit(2);
29
- }
30
- tsx.register();
31
- await import(pathToFileURL(srcEntry).href);
32
- return;
33
- }
34
- console.error("dreamlake: neither dist/cli/index.js nor src/cli/index.ts found");
35
- process.exit(2);
18
+ let binPath;
19
+ try {
20
+ binPath = require.resolve(pkg + "/" + bin);
21
+ } catch {
22
+ process.stderr.write(
23
+ "dreamlake: no binary for " + key + ".\n" +
24
+ "The platform package " + pkg + " is not installed. npm skips it when\n" +
25
+ "os/cpu do not match, and --no-optional skips it always. Reinstall without\n" +
26
+ "--no-optional, or use the native installer:\n" +
27
+ " curl -fsSL https://dl.dreamlake.ai/install.sh | sh\n",
28
+ );
29
+ process.exit(1);
36
30
  }
37
31
 
38
- run().catch((err) => {
39
- console.error(err?.stack ?? err);
32
+ const r = spawnSync(binPath, process.argv.slice(2), { stdio: "inherit" });
33
+ if (r.error) {
34
+ process.stderr.write("dreamlake: " + r.error.message + "\n");
40
35
  process.exit(1);
41
- });
36
+ }
37
+ process.exit(r.status === null ? 1 : r.status);
package/package.json CHANGED
@@ -1,58 +1,29 @@
1
1
  {
2
2
  "name": "@dreamlake/dreamlake-cli",
3
- "version": "0.1.0",
4
- "description": "dreamlake — data-warehouse CLI. The `dreamlake` command uploads/downloads assets and manages episodes, bindrs, and datasets against a DreamLake server + BSS.",
5
- "private": false,
6
- "license": "MIT",
7
- "type": "module",
8
- "bin": {
9
- "dreamlake": "bin/dreamlake.js"
10
- },
11
- "files": [
12
- "bin",
13
- "dist",
14
- "!dist/**/*.map"
15
- ],
16
- "engines": {
17
- "node": ">=20"
18
- },
3
+ "version": "0.9.1",
19
4
  "repository": {
20
5
  "type": "git",
21
6
  "url": "git+https://github.com/dreamlake-ai/dreamlake-cli.git"
22
7
  },
23
- "homepage": "https://github.com/dreamlake-ai/dreamlake-cli#readme",
24
- "bugs": {
25
- "url": "https://github.com/dreamlake-ai/dreamlake-cli/issues"
8
+ "homepage": "https://cli.dreamlake.ai",
9
+ "description": "dreamlake — data-warehouse CLI. The `dreamlake` command uploads/downloads assets, manages episodes, bindrs, datasets, organizations and teams, and versions artifacts, workflow specs and pipelines against a DreamLake server + BSS.",
10
+ "bin": {
11
+ "dreamlake": "bin/dreamlake.js"
26
12
  },
27
- "keywords": [
28
- "dreamlake",
29
- "cli",
30
- "data-warehouse",
31
- "dataset",
32
- "robotics"
13
+ "files": [
14
+ "bin"
33
15
  ],
34
- "author": "DreamLake AI",
35
- "publishConfig": {
36
- "access": "public"
37
- },
38
- "scripts": {
39
- "build": "tsc",
40
- "cli": "tsx src/cli/index.ts",
41
- "test": "tsc -p tsconfig.json --noEmit && node --import tsx --test src/cli/__tests__/*.test.ts",
42
- "prepublishOnly": "npm test",
43
- "prepack": "npm run build",
44
- "docs:dev": "pnpm -C docs dev",
45
- "docs:build": "pnpm -C docs build",
46
- "docs:preview": "pnpm -C docs preview"
47
- },
48
- "devDependencies": {
49
- "@types/node": "^22.10.0",
50
- "tsx": "^4.19.0",
51
- "typescript": "^5.7.0"
16
+ "engines": {
17
+ "node": ">=18"
52
18
  },
53
- "dependencies": {
54
- "@inquirer/prompts": "^8.4.3",
55
- "commander": "^12.1.0",
56
- "yaml": "^2.6.1"
19
+ "optionalDependencies": {
20
+ "@dreamlake/dreamlake-cli-darwin-arm64": "0.9.1",
21
+ "@dreamlake/dreamlake-cli-darwin-x64": "0.9.1",
22
+ "@dreamlake/dreamlake-cli-linux-x64": "0.9.1",
23
+ "@dreamlake/dreamlake-cli-linux-arm64": "0.9.1",
24
+ "@dreamlake/dreamlake-cli-linux-x64-musl": "0.9.1",
25
+ "@dreamlake/dreamlake-cli-linux-arm64-musl": "0.9.1",
26
+ "@dreamlake/dreamlake-cli-win32-x64": "0.9.1",
27
+ "@dreamlake/dreamlake-cli-win32-arm64": "0.9.1"
57
28
  }
58
29
  }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 DreamLake AI
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 DELETED
@@ -1,191 +0,0 @@
1
- # dreamlake-cli
2
-
3
- `dreamlake` — a data-warehouse CLI for DreamLake. Uploads/downloads assets and
4
- manages episodes, bindrs, and datasets against a DreamLake server + BSS
5
- (big-streaming-server).
6
-
7
- It is a TypeScript port of the CLI shipped in `dreamlake-py` (`dreamlake.cli`),
8
- built on Commander + native `fetch`, pure ESM, with the token saved to a flat
9
- YAML file instead of the system keyring.
10
-
11
- > The `dreamlake` binary shares its name with the Python `dreamlake` entry
12
- > point — this CLI is the TypeScript replacement. When both are on a machine,
13
- > `PATH` order decides which one runs.
14
-
15
- ## Install
16
-
17
- Requires Node.js >= 20.
18
-
19
- ```bash
20
- npm install -g @dreamlake/dreamlake-cli # or: pnpm add -g @dreamlake/dreamlake-cli
21
-
22
- dreamlake --version
23
- dreamlake --help
24
- ```
25
-
26
- Or run it without installing:
27
-
28
- ```bash
29
- npx @dreamlake/dreamlake-cli --help
30
- ```
31
-
32
- Then authenticate and go:
33
-
34
- ```bash
35
- dreamlake login --env prod
36
- dreamlake list project
37
- ```
38
-
39
- ## Auth & environments
40
-
41
- The CLI knows two built-in environments — **`staging`** and **`prod`** — so you
42
- never type their URLs. Each environment keeps its own token; switch between them
43
- with one command.
44
-
45
- ```bash
46
- dreamlake login --env staging # device-authorization flow (opens browser)
47
- dreamlake login --env prod # built-in URLs; no --url/--bss needed
48
- dreamlake login # re-auth the active env (or staging if none)
49
-
50
- dreamlake env list # show logged-in envs (* = active)
51
- dreamlake env use prod # switch active env — no URLs, no re-login
52
- dreamlake env remove staging # forget a saved env
53
-
54
- dreamlake profile # current user (shows [env: ...])
55
- dreamlake logout # log out of the active env only
56
- ```
57
-
58
- Custom / self-hosted environments — define once, then switch by name forever:
59
-
60
- ```bash
61
- dreamlake login --env dev --url https://dev-api.example.com --bss https://dev-bss.example.com
62
- dreamlake env use dev
63
- ```
64
-
65
- Flags / env vars (`DREAMLAKE_REMOTE`, `DREAMLAKE_BSS_URL`, `DREAMLAKE_API_KEY`)
66
- still override the active environment for one-off commands. `--token <jwt>` saves
67
- a token directly (skip the device flow). `--auth <url>` overrides the vuer-auth
68
- server (built-ins set this automatically; staging needs `staging-auth.vuer.ai`).
69
-
70
- Credentials live in `~/.config/dreamlake/auth.yml`
71
- (`$XDG_CONFIG_HOME/dreamlake/auth.yml`, `chmod 600`) as a multi-environment file:
72
-
73
- ```yaml
74
- current: prod
75
- envs:
76
- staging: { server, bss, auth, namespace, token }
77
- prod: { server, bss, auth, namespace, token }
78
- ```
79
-
80
- ## Targets
81
-
82
- Most commands take a target string:
83
-
84
- ```
85
- --episode space[@namespace][:episode] # e.g. robotics@alice:2026/q1/run-042
86
- --project space[@namespace] # e.g. robotics@alice
87
- ```
88
-
89
- When `@namespace` is omitted it is resolved from your token (`/auth/me`).
90
-
91
- ## Commands
92
-
93
- ```bash
94
- # Upload — single file, or a flat directory (resumable). Type auto-detected.
95
- dreamlake upload ./mic.wav --episode robotics@alice:run-042 --to /microphone/front
96
- dreamlake upload ./clip.mp4 --episode robotics:run-042 --to /camera/front --bindr cam-set
97
- dreamlake upload ./capture/ --episode robotics@alice:run-042 --to /sensors --yes
98
-
99
- # Download — a single file, or a whole folder/episode recursively.
100
- dreamlake download --episode robotics@alice:run-042 --from /camera/front/clip.mp4 -o ./clip.mp4
101
- dreamlake download --episode robotics@alice:run-042 --from /camera -o ./out/
102
-
103
- # Projects. Private by default — pass --public (or --visibility public) to share.
104
- dreamlake create project my-robots --description "robot captures" # private
105
- dreamlake create project shared-set --public # public
106
- dreamlake update project my-robots --public # flip visibility later
107
- dreamlake list project
108
- dreamlake delete project my-robots # HARD-deletes the whole subtree
109
-
110
- # List — assets (default), or projects / bindrs / datasets / episodes.
111
- dreamlake list --episode robotics@alice:run-042 --type video
112
- dreamlake list project
113
- dreamlake list bindr --project robotics@alice
114
- dreamlake list dataset --project robotics@alice --json
115
- dreamlake list episode --project robotics@alice
116
-
117
- # Delete uploaded data (all HARD deletes — confirm prompt unless --yes).
118
- dreamlake delete file /camera/front/clip.mp4 --episode robotics@alice:run-042
119
- dreamlake delete episode run-042 --project robotics@alice
120
-
121
- # Bindrs (members are episodes, matched by node-path glob).
122
- dreamlake create bindr front-cam --project robotics@alice --episode "camera/front/*"
123
- dreamlake update bindr front-cam --project robotics@alice --add "2026/04/*"
124
- dreamlake delete bindr front-cam --project robotics@alice
125
-
126
- # Datasets (members are bindrs, matched by name glob).
127
- dreamlake create dataset train-v1 --project robotics@alice --tags robotics,training
128
- dreamlake update dataset train-v1 --project robotics@alice --add "front-*"
129
- dreamlake delete dataset train-v1 --project robotics@alice
130
- ```
131
-
132
- > Videos are just files — upload/list/download them with `upload` / `list --type video`
133
- > / `download`, no dedicated `video` command needed.
134
-
135
- ```bash
136
- # Organizations (GraphQL-backed; same token). Members resolve by email/name.
137
- dreamlake org list
138
- dreamlake org show my-org
139
- dreamlake org create my-org --name "My Org" --description "..." # you become OWNER + a namespace is created
140
- dreamlake org update my-org --description "..."
141
- dreamlake org delete my-org # must have no remaining projects
142
- dreamlake org leave my-org
143
- dreamlake org member list my-org
144
- dreamlake org member add my-org alice@example.com --role member
145
- dreamlake org member role my-org alice@example.com --role owner
146
- dreamlake org member remove my-org alice@example.com
147
-
148
- # Teams (scoped to an org; nestable via --parent; visible|secret).
149
- dreamlake team list # all teams you belong to
150
- dreamlake team list my-org # teams in one org
151
- dreamlake team show my-org backend
152
- dreamlake team create my-org backend --name "Backend" --visibility secret
153
- dreamlake team create my-org api --parent backend # nested team
154
- dreamlake team update my-org backend --visibility visible
155
- dreamlake team delete my-org backend # must have no child teams
156
- dreamlake team leave my-org backend
157
- dreamlake team member list my-org backend
158
- dreamlake team member add my-org backend alice@example.com --role maintainer
159
- dreamlake team member role my-org backend alice@example.com --role member
160
- dreamlake team member remove my-org backend alice@example.com
161
- ```
162
-
163
- ## Configuration
164
-
165
- Resolution precedence (high → low): flag → env var → saved `auth.yml` → default.
166
-
167
- | Setting | Env var | Default |
168
- | --- | --- | --- |
169
- | DreamLake server | `DREAMLAKE_REMOTE` | `http://localhost:10334` |
170
- | BSS server | `DREAMLAKE_BSS_URL` | `http://localhost:10234` |
171
- | Token | `DREAMLAKE_API_KEY` | (from `auth.yml`) |
172
-
173
- ## Not implemented
174
-
175
- By design, the CLI excludes the parts of `dreamlake-py` that aren't
176
- command-line-shaped: `vectorize` (CLIP/LLaVA inference + Zaku + Qdrant), the
177
- SDK-only rich types (`Video`/`TextTrack`/`VectorIndex`), and the deprecated
178
- Episode-tracking stack.
179
-
180
- ## Development
181
-
182
- ```bash
183
- pnpm install
184
- pnpm cli --help # dev — runs the TS source through tsx
185
- pnpm test # tsc --noEmit + node --test (target/glob/kinds/credentials)
186
- pnpm build # tsc → dist/
187
- node bin/dreamlake.js … # runs compiled dist/ (falls back to tsx when dist/ is absent)
188
- ```
189
-
190
- Publishing: `npm version patch|minor` → `npm publish` (tests and build run
191
- automatically via `prepublishOnly`/`prepack`) → `git push --follow-tags`.
@@ -1,240 +0,0 @@
1
- // `dreamlake login | logout | profile`.
2
- //
3
- // login: runs the device-authorization flow (default) or saves a token
4
- // passed via --token (lakeshore-style escape hatch). On success the
5
- // dreamlake token + resolved server/bss/namespace are written to
6
- // ~/.config/dreamlake/auth.yml (NOT the system keyring — see credentials.ts).
7
- //
8
- // profile: hits GET /auth/me, falling back to a local JWT decode when the
9
- // server is unreachable. logout: deletes the auth file.
10
- import { spawn } from "node:child_process";
11
- import { resolveRemote, resolveToken, decodeJwtPayload } from "../config.js";
12
- import { emitJson, renderTable } from "../helpers.js";
13
- import { authFilePath, builtinEnv, BUILTIN_ENVS, currentEnvName, listEnvs, removeEnv, saveEnv, useEnv, } from "./credentials.js";
14
- import { getOrCreateDeviceSecret } from "./device-secret.js";
15
- import { AuthorizationDeniedError, DeviceCodeExpiredError, DeviceFlowClient, TokenExchangeError, } from "./device-flow.js";
16
- async function fetchAuthMe(remote, token) {
17
- try {
18
- const res = await fetch(`${remote}/auth/me`, {
19
- headers: { Authorization: `Bearer ${token}` },
20
- signal: AbortSignal.timeout(5000),
21
- });
22
- if (res.ok)
23
- return (await res.json());
24
- }
25
- catch {
26
- // unreachable
27
- }
28
- return null;
29
- }
30
- function openBrowser(url) {
31
- const cmd = process.platform === "darwin"
32
- ? "open"
33
- : process.platform === "win32"
34
- ? "start"
35
- : "xdg-open";
36
- try {
37
- const child = spawn(cmd, [url], { stdio: "ignore", detached: true });
38
- child.on("error", () => { });
39
- child.unref();
40
- }
41
- catch {
42
- // best-effort
43
- }
44
- }
45
- export async function runLogin(args) {
46
- // Resolve which environment we're logging into and its URLs.
47
- const envName = args.env ?? currentEnvName() ?? "staging";
48
- const builtin = builtinEnv(envName);
49
- const remote = (args.url ?? builtin?.server)?.replace(/\/+$/, "");
50
- const bss = (args.bss ?? builtin?.bss)?.replace(/\/+$/, "");
51
- const auth = args.auth ?? builtin?.auth;
52
- if (!remote || !bss) {
53
- process.stderr.write(`✗ unknown environment '${envName}'. Either use a built-in (${Object.keys(BUILTIN_ENVS).join(", ")}) ` +
54
- `or define one: dreamlake login --env ${envName} --url <api> --bss <bss>\n`);
55
- return 1;
56
- }
57
- process.stderr.write(`Logging into environment '${envName}' (${remote})\n`);
58
- // ── Escape hatch: direct token (lakeshore style) ──────────────────
59
- if (args.token) {
60
- const me = await fetchAuthMe(remote, args.token);
61
- if (!me) {
62
- process.stderr.write(`✗ token validation failed against ${remote}/auth/me\n`);
63
- return 1;
64
- }
65
- const namespace = me.namespace?.slug ?? "";
66
- const p = saveEnv(envName, { server: remote, bss, auth, namespace, token: args.token });
67
- process.stdout.write(`✓ Saved env '${envName}' to ${p}\n` +
68
- ` server: ${remote}\n` +
69
- ` bss: ${bss}\n` +
70
- ` namespace: ${namespace || "(none)"}\n`);
71
- return 0;
72
- }
73
- // ── Device authorization flow ─────────────────────────────────────
74
- const deviceSecret = getOrCreateDeviceSecret();
75
- const client = new DeviceFlowClient(deviceSecret, remote, auth);
76
- let flow;
77
- try {
78
- process.stderr.write("Initializing device authorization...\n\n");
79
- flow = await client.startDeviceFlow();
80
- }
81
- catch (err) {
82
- process.stderr.write(`✗ ${err.message}\n`);
83
- return 1;
84
- }
85
- process.stdout.write(`DEVICE AUTHORIZATION REQUIRED\n\n` +
86
- ` 1. Visit: ${flow.verificationUri}\n` +
87
- ` 2. Enter code: ${flow.userCode}\n\n` +
88
- ` (code expires in ${Math.floor(flow.expiresIn / 60)} minutes)\n\n`);
89
- if (!args.noBrowser) {
90
- openBrowser(flow.verificationUriComplete);
91
- }
92
- process.stderr.write("Waiting for authorization...\n");
93
- let vuerToken;
94
- try {
95
- vuerToken = await client.pollForToken(120, (elapsed) => {
96
- if (process.stderr.isTTY) {
97
- process.stderr.write(`\r waiting (${elapsed}s)`);
98
- }
99
- });
100
- if (process.stderr.isTTY)
101
- process.stderr.write("\n");
102
- }
103
- catch (err) {
104
- if (process.stderr.isTTY)
105
- process.stderr.write("\n");
106
- if (err instanceof DeviceCodeExpiredError) {
107
- process.stderr.write("✗ Device code expired. Run 'dreamlake login' again.\n");
108
- }
109
- else if (err instanceof AuthorizationDeniedError) {
110
- process.stderr.write("✗ Authorization denied.\n");
111
- }
112
- else {
113
- process.stderr.write(`✗ ${err.message}\n`);
114
- }
115
- return 1;
116
- }
117
- let token;
118
- try {
119
- process.stderr.write("Exchanging token with DreamLake server...\n");
120
- token = await client.exchangeToken(vuerToken);
121
- }
122
- catch (err) {
123
- const msg = err instanceof TokenExchangeError ? err.message : err.message;
124
- process.stderr.write(`✗ ${msg}\n`);
125
- return 1;
126
- }
127
- const me = await fetchAuthMe(remote, token);
128
- const namespace = me?.namespace?.slug ?? "";
129
- saveEnv(envName, { server: remote, bss, auth, namespace, token });
130
- process.stdout.write(`✓ Logged in to '${envName}' (now active)\n` +
131
- ` server: ${remote}\n` +
132
- ` bss: ${bss}\n` +
133
- ` namespace: ${namespace || "(none)"}\n`);
134
- return 0;
135
- }
136
- // ─── logout ──────────────────────────────────────────────────────────
137
- export async function runLogout() {
138
- const name = currentEnvName();
139
- if (!name) {
140
- process.stdout.write(`No active environment (${authFilePath()})\n`);
141
- return 0;
142
- }
143
- removeEnv(name);
144
- const next = currentEnvName();
145
- process.stdout.write(`✓ Logged out of '${name}'.` +
146
- (next ? ` Active environment is now '${next}'.\n` : " No environments left.\n"));
147
- return 0;
148
- }
149
- // ─── env (environment switching) ──────────────────────────────────────
150
- export async function runEnvList(opts) {
151
- const envs = listEnvs();
152
- if (opts.json) {
153
- emitJson(envs.map((e) => ({
154
- name: e.name,
155
- current: e.current,
156
- server: e.env.server,
157
- bss: e.env.bss,
158
- namespace: e.env.namespace,
159
- })));
160
- return 0;
161
- }
162
- process.stdout.write("Environments\n\n");
163
- if (envs.length === 0) {
164
- process.stdout.write(` (none logged in)\n hint: dreamlake login --env staging (built-in: ${Object.keys(BUILTIN_ENVS).join(", ")})\n`);
165
- return 0;
166
- }
167
- const rows = envs.map((e) => ({
168
- "": e.current ? "*" : "",
169
- name: e.name,
170
- server: e.env.server,
171
- namespace: e.env.namespace || "(none)",
172
- }));
173
- process.stdout.write(renderTable(rows, ["", "name", "server", "namespace"]));
174
- return 0;
175
- }
176
- export async function runEnvUse(name) {
177
- if (useEnv(name)) {
178
- process.stdout.write(`✓ Active environment is now '${name}'\n`);
179
- return 0;
180
- }
181
- const known = listEnvs().map((e) => e.name);
182
- process.stderr.write(`✗ environment '${name}' is not logged in.\n` +
183
- (known.length ? ` logged in: ${known.join(", ")}\n` : "") +
184
- ` log in with: dreamlake login --env ${name}\n`);
185
- return 1;
186
- }
187
- export async function runEnvRemove(name) {
188
- if (removeEnv(name)) {
189
- process.stdout.write(`✓ Removed environment '${name}'\n`);
190
- return 0;
191
- }
192
- process.stderr.write(`✗ environment '${name}' not found\n`);
193
- return 1;
194
- }
195
- export async function runProfile(args) {
196
- const token = resolveToken();
197
- if (!token) {
198
- process.stdout.write("Not logged in. Run: dreamlake login\n");
199
- return 1;
200
- }
201
- const remote = resolveRemote(args.url);
202
- const me = await fetchAuthMe(remote, token);
203
- if (me) {
204
- const envName = currentEnvName();
205
- process.stdout.write(`Current DreamLake user${envName ? ` [env: ${envName}]` : ""}\n`);
206
- for (const field of ["id", "sub", "username", "name", "email"]) {
207
- if (me[field] != null)
208
- process.stdout.write(` ${field}: ${me[field]}\n`);
209
- }
210
- if (me.namespace?.slug) {
211
- process.stdout.write(` namespace: ${me.namespace.slug} (id: ${me.namespace.id ?? "?"})\n`);
212
- }
213
- if (me.createdAt) {
214
- process.stdout.write(` member since: ${String(me.createdAt).slice(0, 10)}\n`);
215
- }
216
- return 0;
217
- }
218
- // Fallback: decode JWT locally.
219
- process.stderr.write("⚠ could not reach server, showing local token info.\n");
220
- const payload = decodeJwtPayload(token);
221
- if (Object.keys(payload).length === 0) {
222
- process.stdout.write("Failed to decode token. Please log in again.\n");
223
- return 1;
224
- }
225
- process.stdout.write("Current DreamLake user (from token)\n");
226
- for (const field of ["sub", "username", "name", "email"]) {
227
- if (payload[field] != null) {
228
- process.stdout.write(` ${field}: ${payload[field]}\n`);
229
- }
230
- }
231
- const exp = payload.exp;
232
- if (typeof exp === "number") {
233
- const expired = exp < Date.now() / 1000;
234
- process.stdout.write(` expires: ${new Date(exp * 1000).toISOString()}${expired ? " (EXPIRED)" : ""}\n`);
235
- }
236
- else {
237
- process.stdout.write(" expires: never (long-lived token)\n");
238
- }
239
- return 0;
240
- }
@@ -1,16 +0,0 @@
1
- // Authentication constants — port of dreamlake-py's auth/constants.py.
2
- /**
3
- * Vuer-auth server URL (device-flow provider). Resolved lazily so a
4
- * `--auth` flag / late env assignment can override it. NOTE: this must
5
- * match the auth server the TARGET dreamlake-server trusts — e.g.
6
- * staging-api.dreamlake.ai validates tokens from staging-auth.vuer.ai,
7
- * not the production auth.vuer.ai (mismatched keys → "No matching key
8
- * found in JWKS").
9
- */
10
- export function vuerAuthUrl(override) {
11
- return (override || process.env.VUER_AUTH_URL || "https://auth.vuer.ai").replace(/\/+$/, "");
12
- }
13
- /** OAuth client ID for dreamlake. */
14
- export const CLIENT_ID = "dreamlake-client";
15
- /** Default OAuth scopes. */
16
- export const DEFAULT_SCOPE = "openid profile email";