lecodes-cli 0.20.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -57
- package/dist/index.js +11052 -7592
- package/package.json +14 -8
- package/runtime/materials/decal-relief.mat +12 -1
- package/runtime/materials/decal.mat +17 -3
- package/runtime/materials/lightmap.mat +117 -138
- package/runtime/materials/particles-quad.mat +6 -2
- package/runtime/materials/terrain-lightmap.mat +123 -0
- package/runtime/materials/terrain.mat +36 -55
- package/runtime/sdk-types.json +1 -1
- package/runtime/web/VERSION.json +5 -0
- package/runtime/web/assets/camera-5XOM8eHl.js +1 -0
- package/runtime/web/assets/creator-2d-D9WKYM6h.js +1 -0
- package/runtime/web/assets/creator-2d-ukvEmNEp.wasm +0 -0
- package/runtime/web/assets/creator-full-BBXzQlhq.js +1 -0
- package/runtime/web/assets/creator-full-D2dSDdDj.wasm +0 -0
- package/runtime/web/assets/creator-full.js-BYswGsqR.symbols +8124 -0
- package/runtime/web/assets/creator-ui-DIc92ion.wasm +0 -0
- package/runtime/web/assets/creator-ui-_1Z_AX2M.js +1 -0
- package/runtime/web/assets/geolocation-BjTKN9_P.js +1 -0
- package/runtime/web/assets/inspect-C7x78PNs.js +2 -0
- package/runtime/web/assets/map-CyBxOSV0.js +1 -0
- package/runtime/web/assets/map-XzoOFt0E.js +2 -0
- package/runtime/web/assets/mapImpl-bxvQ2h1Z.js +823 -0
- package/runtime/web/assets/maplibre-gl-worker-B7LXXUkR.js +8 -0
- package/runtime/web/assets/materials-uri4FvPE.bin +0 -0
- package/runtime/web/assets/materials-world-CQWt8TAm.bin +0 -0
- package/runtime/web/assets/qr-scanner-CK_cYoJR.js +1 -0
- package/runtime/web/assets/uberarchive-DLH-kBhM.bin +0 -0
- package/runtime/web/index.html +36 -0
- package/runtime/web/player.js +21 -0
- package/runtime/web-page/index.html +41 -0
- package/runtime/web-page/page.css +1 -0
- package/runtime/web-page/page.js +31 -0
- package/src/api.ts +1 -302
- package/src/cli/args.ts +37 -0
- package/src/cli/command.ts +113 -0
- package/src/cli/errors.ts +13 -0
- package/src/cli/help.ts +158 -0
- package/src/cli/index.ts +7 -0
- package/src/cli/output.ts +102 -0
- package/src/cli/run.ts +106 -0
- package/src/commands/{appAndroid.ts → app/android.ts} +454 -43
- package/src/commands/{appDesktop.ts → app/desktop.ts} +64 -33
- package/src/commands/{appDesktopMac.ts → app/desktopMac.ts} +34 -27
- package/src/commands/{appIcon.ts → app/icon.ts} +11 -8
- package/src/commands/{app.ts → app/index.ts} +400 -290
- package/src/commands/{appShared.ts → app/shared.ts} +43 -44
- package/src/commands/{appTemplatesAndroid.ts → app/templates/android.ts} +72 -39
- package/src/commands/{appTemplatesGradlew.ts → app/templates/gradlew.ts} +1 -1
- package/src/commands/{appTemplates.ts → app/templates/ios.ts} +2 -2
- package/src/commands/assets.ts +23 -21
- package/src/commands/clone.ts +48 -51
- package/src/commands/compile.ts +76 -89
- package/src/commands/create.ts +46 -47
- package/src/commands/design/comments.ts +361 -0
- package/src/commands/design/context.ts +101 -0
- package/src/commands/design/index.ts +391 -0
- package/src/commands/design/snapshot.ts +134 -0
- package/src/commands/{designTemplates.ts → design/templates.ts} +4 -3
- package/src/commands/desktop.ts +94 -82
- package/src/commands/dev.ts +260 -182
- package/src/commands/diff.ts +39 -51
- package/src/commands/index.ts +64 -0
- package/src/commands/{init.ts → init/index.ts} +195 -191
- package/src/commands/{projectTemplates.ts → init/templates.ts} +64 -21
- package/src/commands/install.ts +80 -67
- package/src/commands/lightmap.ts +543 -252
- package/src/commands/link.ts +87 -94
- package/src/commands/login.ts +25 -23
- package/src/commands/navmesh.ts +169 -139
- package/src/commands/plugin.ts +46 -0
- package/src/commands/pn.ts +201 -244
- package/src/commands/pull.ts +49 -56
- package/src/commands/push.ts +48 -54
- package/src/commands/render.ts +176 -111
- package/src/commands/scene.ts +63 -55
- package/src/commands/serve.ts +58 -0
- package/src/commands/{shaders.ts → shaders/index.ts} +61 -42
- package/src/commands/{shadersNew.ts → shaders/new.ts} +3 -3
- package/src/commands/shared.ts +79 -0
- package/src/commands/status.ts +22 -26
- package/src/commands/test.ts +94 -63
- package/src/commands/thumbs.ts +185 -175
- package/src/commands/update/index.ts +226 -0
- package/src/commands/{types.ts → update/types.ts} +31 -22
- package/src/compile/collect.ts +5 -5
- package/src/compile/collectLocal.ts +3 -3
- package/src/compile/designCompile.ts +4 -4
- package/src/compile/headlessBundle.ts +16 -12
- package/src/compile/nativeStack.ts +1 -1
- package/src/compile/projectCompile.ts +12 -4
- package/src/compile/sceneCompile.ts +14 -26
- package/src/compile/screenEntry.ts +123 -127
- package/src/compile/shaders.ts +3 -3
- package/src/{lecodes-3d-editor.d.ts → declarations/lecodes-3d-editor.d.ts} +4 -0
- package/src/{lecodes-assets.d.ts → declarations/lecodes-assets.d.ts} +1 -1
- package/src/{lecodes-renderer.d.ts → declarations/lecodes-headless.d.ts} +3 -3
- package/src/dev/androidDev.ts +1 -1
- package/src/dev/clientTemplates.ts +18 -14
- package/src/dev/devServer.ts +78 -41
- package/src/dev/iosDev.ts +180 -0
- package/src/dev/webRunner.ts +83 -15
- package/src/{cmgenTool.ts → hosts/cmgenTool.ts} +2 -2
- package/src/{desktopRenderer.ts → hosts/desktopRenderer.ts} +104 -32
- package/src/{desktopScript.ts → hosts/desktopScript.ts} +151 -36
- package/src/{distRoot.ts → hosts/distRoot.ts} +9 -5
- package/src/{matcTool.ts → hosts/matcTool.ts} +2 -2
- package/src/{peerInstall.ts → hosts/peerInstall.ts} +7 -7
- package/src/{peers.ts → hosts/peers.ts} +2 -2
- package/src/{releases.ts → hosts/releases.ts} +1 -1
- package/src/index.ts +35 -480
- package/src/platform/api.ts +302 -0
- package/src/{browserAuth.ts → platform/browserAuth.ts} +1 -1
- package/src/{config.ts → platform/config.ts} +1 -1
- package/src/{serverDiff.ts → platform/serverDiff.ts} +3 -3
- package/src/plugin/contract.ts +438 -0
- package/src/plugin/emitKotlin.ts +357 -0
- package/src/plugin/emitSdk.ts +259 -0
- package/src/plugin/emitSwift.ts +336 -0
- package/src/plugin/emitWeb.ts +383 -0
- package/src/plugin/generate.ts +157 -0
- package/src/plugin/lines.ts +28 -0
- package/src/plugin/lower.ts +231 -0
- package/src/plugin/manifest.ts +192 -0
- package/src/{projectEnv.ts → project/env.ts} +33 -2
- package/src/{ignore.ts → project/ignore.ts} +164 -163
- package/src/{localFiles.ts → project/localFiles.ts} +1 -1
- package/src/{manifest.ts → project/manifest.ts} +1 -1
- package/src/{project.ts → project/materialize.ts} +2 -2
- package/src/project/paths.ts +20 -0
- package/src/{textDiff.ts → project/textDiff.ts} +1 -1
- package/src/{types.ts → project/types.ts} +0 -0
- package/runtime/materials/lightmap-baked-lite.mat +0 -175
- package/runtime/materials/lightmap-baked.mat +0 -176
- package/runtime/scene-harness.json +0 -1
- package/runtime/web/assets/__vite-browser-external-BIHI7g3E.js +0 -1
- package/runtime/web/assets/basis-C64VHDVD.js +0 -1
- package/runtime/web/assets/basis_transcoder-VXdx5NbI.wasm +0 -0
- package/runtime/web/assets/createViewerLite-Ct_PZdof.js +0 -852
- package/runtime/web/assets/draco-BiISTFcR.js +0 -118
- package/runtime/web/assets/draco_decoder-DsQ12WqX.wasm +0 -0
- package/runtime/web/assets/index-BMt7AnC5.js +0 -2
- package/runtime/web/assets/mapViewImpl-B2JcES8l.js +0 -810
- package/runtime/web/assets/maplibre-gl-worker-CJfwIrte.js +0 -8
- package/runtime/web/assets/worker-Caf-yYEI.js +0 -2
- package/runtime/web/embed.html +0 -32
- package/runtime/web/embed.js +0 -171
- package/src/commands/design.ts +0 -846
- package/src/commands/update.ts +0 -211
- package/src/util.ts +0 -146
- /package/src/{lecodes-design.d.ts → declarations/lecodes-design.d.ts} +0 -0
- /package/src/{qrcode-terminal.d.ts → declarations/qrcode-terminal.d.ts} +0 -0
- /package/src/{designMeta.ts → project/designMeta.ts} +0 -0
package/src/commands/link.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { existsSync } from "node:fs"
|
|
2
2
|
import { basename, join, resolve } from "node:path"
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
3
|
+
import { CliError, bool, c, confirm, defineCommand, info, log, note, str, success, warn } from "../cli"
|
|
4
|
+
import { createProject, getCommits, getProject, type Project, type ProjectAsset } from "../platform/api"
|
|
5
|
+
import { computeServerDiff } from "../platform/serverDiff"
|
|
6
|
+
import { ensureGitignore, writeDefaultIgnore } from "../project/ignore"
|
|
7
|
+
import { scanProject } from "../project/localFiles"
|
|
8
|
+
import { findProjectRoot, LECODES_DIR, writeManifest, type FileKind, type Manifest, type ManifestFile } from "../project/manifest"
|
|
9
|
+
import { buildPaths } from "../project/materialize"
|
|
10
|
+
import { sha256 } from "../project/paths"
|
|
11
|
+
import { materializeTypes, writeTsconfig } from "../project/types"
|
|
12
12
|
import { parseUuid } from "./clone"
|
|
13
|
-
import {
|
|
13
|
+
import { pushFlags, runPush } from "./push"
|
|
14
|
+
import { session } from "./shared"
|
|
14
15
|
|
|
15
16
|
/*
|
|
16
17
|
* `lecodes link [dir]` — connect an existing local folder (typically one made by `lecodes init`) to
|
|
@@ -38,110 +39,102 @@ const manifestFromServer = (project: Project): Record<string, ManifestFile> => {
|
|
|
38
39
|
const files: Record<string, ManifestFile> = {}
|
|
39
40
|
for (const asset of project.assets) {
|
|
40
41
|
if (asset.type === "folder") continue
|
|
41
|
-
files[pathById.get(asset.id)!] = {
|
|
42
|
-
id: asset.id,
|
|
43
|
-
type: kindOf(asset.type),
|
|
44
|
-
sha: asset.type === "file" ? "" : sha256(asset.text ?? ""),
|
|
45
|
-
}
|
|
42
|
+
files[pathById.get(asset.id)!] = { id: asset.id, type: kindOf(asset.type), sha: asset.type === "file" ? "" : sha256(asset.text ?? "") }
|
|
46
43
|
}
|
|
47
44
|
return files
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
/** Show what a push from this folder would do to the project's server tree, and get a yes. */
|
|
51
|
-
const confirmAdoption = async (root: string, project: Project, files: Record<string, ManifestFile>,
|
|
48
|
+
const confirmAdoption = async (root: string, project: Project, files: Record<string, ManifestFile>, skipAsk: boolean): Promise<boolean> => {
|
|
52
49
|
const count = Object.keys(files).length
|
|
53
|
-
if (count === 0) {
|
|
54
|
-
info(c.dim(`Project ${c.bold(project.name)} is empty on the server — nothing to overwrite.`))
|
|
55
|
-
return true
|
|
56
|
-
}
|
|
50
|
+
if (count === 0) { info(c.dim(`Project ${c.bold(project.name)} is empty on the server — nothing to overwrite.`)); return true }
|
|
57
51
|
|
|
58
52
|
const scan = scanProject(root, { files } as Manifest)
|
|
59
53
|
const diff = computeServerDiff(project, scan)
|
|
60
|
-
if (diff.length === 0) {
|
|
61
|
-
info(c.dim(`Project ${c.bold(project.name)} (${count} file(s)) already matches this folder.`))
|
|
62
|
-
return true
|
|
63
|
-
}
|
|
54
|
+
if (diff.length === 0) { info(c.dim(`Project ${c.bold(project.name)} (${count} file(s)) already matches this folder.`)); return true }
|
|
64
55
|
|
|
65
56
|
warn(`${c.bold(project.name)} already has ${count} file(s). Your next push would change the server:`)
|
|
66
57
|
const label: Record<string, string> = { added: c.green(" create "), removed: c.red(" delete "), modified: c.yellow(" update ") }
|
|
67
58
|
for (const e of diff) log(label[e.status] + e.path + (e.binary ? c.dim(" (binary)") : ""))
|
|
68
59
|
log("")
|
|
69
60
|
note("`lecodes pull` after linking takes the server's version instead.")
|
|
70
|
-
|
|
71
|
-
if (flagBool(args, "y", "yes") || flagBool(args, "force") || !process.stdin.isTTY) return true
|
|
61
|
+
if (skipAsk || !process.stdin.isTTY) return true
|
|
72
62
|
return confirm("Link this folder to that project?", false)
|
|
73
63
|
}
|
|
74
64
|
|
|
75
|
-
export
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
65
|
+
export default defineCommand({
|
|
66
|
+
name: "link",
|
|
67
|
+
summary: "Connect an existing local folder to the platform (the reverse of clone)",
|
|
68
|
+
usage: "[dir]",
|
|
69
|
+
description: "Creates a project on the server, writes .lecodes/manifest.json and refreshes the types; nothing is uploaded until you push, so `status` shows what would go up first. `--project` adopts an EXISTING project instead: the manifest is built from its server tree and the command prints exactly what your next push would create / update / delete there before linking.",
|
|
70
|
+
flags: {
|
|
71
|
+
name: str("project name (default: the folder name)", { value: "<s>" }),
|
|
72
|
+
team: str("create it inside a team", { value: "<uuid>" }),
|
|
73
|
+
project: str("adopt an existing project instead of creating one", { value: "<uuid|url>" }),
|
|
74
|
+
push: bool("push right after linking (--publish to deploy it live in the same step)"),
|
|
75
|
+
"no-types": bool("skip the .d.ts / tsconfig refresh"),
|
|
76
|
+
...pushFlags,
|
|
77
|
+
},
|
|
78
|
+
examples: ["lecodes link", "lecodes link --project <uuid> && lecodes status", 'lecodes link --push -m "initial"'],
|
|
79
|
+
run: async ({ args, flags }) => {
|
|
80
|
+
const { apiUrl, token } = session()
|
|
81
|
+
const dirArg = args[0]
|
|
82
|
+
const root = dirArg ? resolve(dirArg) : process.cwd()
|
|
83
|
+
if (!existsSync(root)) throw new CliError(`No such directory: ${root}`)
|
|
84
|
+
|
|
85
|
+
// Already linked? Re-linking silently would orphan the old project's history.
|
|
86
|
+
if (existsSync(join(root, LECODES_DIR, "manifest.json")) && !flags.force) {
|
|
87
|
+
throw new CliError("This folder is already linked (.lecodes/manifest.json exists) — use `lecodes push`, or `lecodes link --force` to re-link it to another project.")
|
|
88
|
+
}
|
|
89
|
+
// …or sitting inside a linked project, where a nested manifest would shadow the real root.
|
|
90
|
+
let enclosing: string | null = null
|
|
91
|
+
try { enclosing = findProjectRoot(root) } catch { /* not inside a project — the normal case */ }
|
|
92
|
+
if (enclosing && enclosing !== root) throw new CliError(`This folder is inside the linked project at ${enclosing} — push from there instead.`)
|
|
93
|
+
|
|
94
|
+
let uuid: string
|
|
95
|
+
let name: string
|
|
96
|
+
let files: Record<string, ManifestFile>
|
|
97
|
+
if (flags.project) {
|
|
98
|
+
uuid = parseUuid(flags.project)
|
|
99
|
+
const project = await getProject(apiUrl, token, uuid)
|
|
100
|
+
if (project.role === "viewer") throw new CliError(`You have view-only access to ${project.name} — linking would give you a checkout you can't push.`)
|
|
101
|
+
files = manifestFromServer(project)
|
|
102
|
+
if (!(await confirmAdoption(root, project, files, flags.yes || flags.force))) { info(c.dim("Aborted — nothing was linked.")); return }
|
|
103
|
+
name = project.name
|
|
104
|
+
} else {
|
|
105
|
+
name = flags.name ?? basename(root)
|
|
106
|
+
info(c.dim(`Creating project ${c.bold(name)}…`))
|
|
107
|
+
uuid = (await createProject(apiUrl, token, name, flags.team)).uuid
|
|
108
|
+
files = {} // fresh project: the whole folder is a pending add
|
|
105
109
|
}
|
|
106
|
-
files = manifestFromServer(project)
|
|
107
|
-
if (!(await confirmAdoption(root, project, files, args))) { info(c.dim("Aborted — nothing was linked.")); return }
|
|
108
|
-
name = project.name
|
|
109
|
-
} else {
|
|
110
|
-
name = flagStr(args, "name") ?? basename(root)
|
|
111
|
-
info(c.dim(`Creating project ${c.bold(name)}…`))
|
|
112
|
-
uuid = (await createProject(apiUrl, token, name, flagStr(args, "team"))).uuid
|
|
113
|
-
files = {} // fresh project: the whole folder is a pending add
|
|
114
|
-
}
|
|
115
110
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
const commits = await getCommits(apiUrl, token, uuid)
|
|
112
|
+
writeManifest(root, { uuid, apiUrl, name, baseHeadId: commits.headId, files })
|
|
113
|
+
log(`${c.green("linked")} ${c.bold(name)} ${c.dim(uuid)}`)
|
|
119
114
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
115
|
+
// Now that there IS a server, take its type surface — it matches the runtime the project will
|
|
116
|
+
// actually run on, unlike the CLI-bundled copy `lecodes init` wrote.
|
|
117
|
+
if (!flags["no-types"]) {
|
|
118
|
+
await materializeTypes(root, apiUrl)
|
|
119
|
+
writeTsconfig(root)
|
|
120
|
+
log(`${c.green("written")} ${LECODES_DIR}/types/ + tsconfig.json ${c.dim("(from the server)")}`)
|
|
121
|
+
}
|
|
122
|
+
writeDefaultIgnore(root)
|
|
123
|
+
if (ensureGitignore(root)) log(`${c.green("written")} .gitignore ${c.dim("(.lecodes/ is per-checkout state)")}`)
|
|
124
|
+
|
|
125
|
+
if (flags.push) {
|
|
126
|
+
log("")
|
|
127
|
+
if (root !== process.cwd()) process.chdir(root) // push works from the current project root
|
|
128
|
+
await runPush(flags)
|
|
129
|
+
return
|
|
130
|
+
}
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
const pending = scanProject(root, { files } as Manifest).files.filter((f) => { const known = files[f.path]; return !known || known.sha !== f.sha }).length
|
|
131
133
|
log("")
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return !known || known.sha !== f.sha
|
|
140
|
-
}).length
|
|
141
|
-
log("")
|
|
142
|
-
success(`Connected to ${c.bold(name)}.`)
|
|
143
|
-
const cd = dirArg ? `cd ${dirArg} && ` : ""
|
|
144
|
-
log(` ${c.bold(cd + "lecodes status")} ${pending} file(s) would go up`)
|
|
145
|
-
log(` ${c.bold(cd + 'lecodes push -m "initial"')} push them as the first checkpoint`)
|
|
146
|
-
log(` ${c.dim("(add --publish to deploy it live in the same step)")}`)
|
|
147
|
-
}
|
|
134
|
+
success(`Connected to ${c.bold(name)}.`)
|
|
135
|
+
const cd = dirArg ? `cd ${dirArg} && ` : ""
|
|
136
|
+
log(` ${c.bold(cd + "lecodes status")} ${pending} file(s) would go up`)
|
|
137
|
+
log(` ${c.bold(cd + 'lecodes push -m "initial"')} push them as the first checkpoint`)
|
|
138
|
+
log(` ${c.dim("(add --publish to deploy it live in the same step)")}`)
|
|
139
|
+
},
|
|
140
|
+
})
|
package/src/commands/login.ts
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { browserLogin } from "../browserAuth"
|
|
4
|
-
import {
|
|
1
|
+
import { c, defineCommand, str, success } from "../cli"
|
|
2
|
+
import { getAccount } from "../platform/api"
|
|
3
|
+
import { browserLogin } from "../platform/browserAuth"
|
|
4
|
+
import { DEFAULT_API, loadConfig, normalizeApiUrl, saveConfig } from "../platform/config"
|
|
5
5
|
|
|
6
|
-
/*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
6
|
+
/* `lecodes login` — authorize this machine; the token lands in ~/.lecodes/config.json. */
|
|
7
|
+
export default defineCommand({
|
|
8
|
+
name: "login",
|
|
9
|
+
summary: "Authorize in the browser and store an access token",
|
|
10
|
+
description: "Opens the browser to sign in / authorize on le.codes and captures the token. `--token` stores a token created in the web UI instead (headless / CI). LECODES_API / LECODES_TOKEN in the environment override the stored values.",
|
|
11
|
+
flags: {
|
|
12
|
+
token: str("store a personal access token from the web UI instead of the browser flow", { value: "<pat>" }),
|
|
13
|
+
api: str(`API origin (default: the stored one, else ${DEFAULT_API})`, { value: "<url>" }),
|
|
14
|
+
web: str("app origin for the browser flow (default: the API origin)", { value: "<url>" }),
|
|
15
|
+
},
|
|
16
|
+
run: async ({ flags }) => {
|
|
17
|
+
const config = loadConfig()
|
|
18
|
+
const apiUrl = normalizeApiUrl(flags.api ?? config.apiUrl ?? DEFAULT_API)
|
|
19
|
+
const webBase = normalizeApiUrl(flags.web ?? apiUrl)
|
|
20
|
+
const token = flags.token ?? await browserLogin(webBase)
|
|
21
|
+
// Verify the token works against the API before persisting it.
|
|
22
|
+
const account = await getAccount(apiUrl, token)
|
|
23
|
+
saveConfig({ apiUrl, token })
|
|
24
|
+
success(`Logged in as ${c.bold(account.email)} on ${apiUrl}`)
|
|
25
|
+
},
|
|
26
|
+
})
|