persona-test-cli 0.1.0 → 0.1.3
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 +9 -7
- package/dist/commands/login.js +17 -6
- package/dist/commands/register.js +14 -5
- package/dist/config.js +7 -2
- package/dist/index.js +32 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# persona-test-cli
|
|
2
2
|
|
|
3
|
-
Ops CLI for a [persona-test](https://github.com/) deployment
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Ops CLI for a [persona-test](https://github.com/) deployment. By default it points at
|
|
4
|
+
`https://persona.mixlab.top`; pass `--base-url <url>` (or set `PERSONA_TEST_CLI_URL`) to point
|
|
5
|
+
it at a different deployment instead. Admin and approved regular users can both use it — a
|
|
6
|
+
regular user only ever sees/edits campaigns and personas they created themselves; admin sees
|
|
7
|
+
and can edit everything.
|
|
6
8
|
|
|
7
9
|
## Install
|
|
8
10
|
|
|
@@ -14,10 +16,10 @@ npm install -g persona-test-cli
|
|
|
14
16
|
|
|
15
17
|
```bash
|
|
16
18
|
# New account: register, then wait for an admin to approve it at /admin/users
|
|
17
|
-
persona-test-cli register
|
|
19
|
+
persona-test-cli register
|
|
18
20
|
|
|
19
21
|
# Log in — opens a browser to approve the CLI (device-code flow), no password typed into the terminal
|
|
20
|
-
persona-test-cli login
|
|
22
|
+
persona-test-cli login
|
|
21
23
|
|
|
22
24
|
# See everything at once
|
|
23
25
|
persona-test-cli examples
|
|
@@ -31,8 +33,8 @@ authorize page loads decides the scope of the issued token.
|
|
|
31
33
|
|
|
32
34
|
| Command | Who | What |
|
|
33
35
|
|---|---|---|
|
|
34
|
-
| `register
|
|
35
|
-
| `login
|
|
36
|
+
| `register` | anyone | Self-register (pending admin approval) |
|
|
37
|
+
| `login` | anyone | Device-code browser login |
|
|
36
38
|
| `logout` | anyone | Clear the stored token |
|
|
37
39
|
| `whoami` | anyone | Show current identity + available commands |
|
|
38
40
|
| `campaigns list/create/edit/link/stats` | anyone | Share links — scoped to your own unless admin |
|
package/dist/commands/login.js
CHANGED
|
@@ -2,24 +2,35 @@ import { publicRequest, apiRequest } from "../http.js";
|
|
|
2
2
|
import { openBrowser } from "../browser.js";
|
|
3
3
|
import { fail, EXIT_CODES } from "../errors.js";
|
|
4
4
|
import { action, printJsonOrText } from "../output.js";
|
|
5
|
-
import {
|
|
6
|
-
export const LOGIN_EXAMPLES = ` persona-test-cli login
|
|
7
|
-
persona-test-cli login
|
|
8
|
-
persona-test-cli login
|
|
5
|
+
import { resolveBaseUrl, saveProfile } from "../config.js";
|
|
6
|
+
export const LOGIN_EXAMPLES = ` persona-test-cli login
|
|
7
|
+
persona-test-cli login --no-open
|
|
8
|
+
persona-test-cli login --token <已有的 token,跳过整个设备码流程>
|
|
9
|
+
|
|
10
|
+
不传地址默认连 https://persona.mixlab.top。要连别的部署,传 <baseUrl>/--base-url,
|
|
11
|
+
或者设 PERSONA_TEST_CLI_URL 环境变量长期生效:
|
|
12
|
+
export PERSONA_TEST_CLI_URL=https://your-app.example.com # 写进 ~/.zshrc 或 ~/.bashrc`;
|
|
9
13
|
const POLL_INTERVAL_MS = 2000;
|
|
10
14
|
function sleep(ms) {
|
|
11
15
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12
16
|
}
|
|
13
17
|
export function loginCommand(program) {
|
|
14
18
|
program
|
|
15
|
-
.command("login
|
|
19
|
+
.command("login [baseUrl]")
|
|
16
20
|
.description("设备码登录:自动打开浏览器授权,或用 --token 直接注入一个已有 token")
|
|
21
|
+
.option("--base-url <url>", "同下面的位置参数,两种写法都行")
|
|
17
22
|
.option("--no-open", "不自动打开浏览器,只打印授权链接(无 GUI/沙盒环境用)")
|
|
18
23
|
.option("--wait <seconds>", "轮询超时秒数", "300")
|
|
19
24
|
.option("--token <token>", "跳过设备码流程,直接用这个 token(会先校验有效性)")
|
|
20
25
|
.addHelpText("after", `\n示例:\n${LOGIN_EXAMPLES}`)
|
|
21
26
|
.action(action(async (baseUrlArg, opts) => {
|
|
22
|
-
const baseUrl =
|
|
27
|
+
const baseUrl = resolveBaseUrl(baseUrlArg ?? opts.baseUrl);
|
|
28
|
+
if (!baseUrl) {
|
|
29
|
+
fail("没有指定地址,加 <baseUrl> 或 --base-url,或设置 PERSONA_TEST_CLI_URL 环境变量", {
|
|
30
|
+
usage: LOGIN_EXAMPLES,
|
|
31
|
+
exitCode: EXIT_CODES.validation,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
23
34
|
if (opts.token) {
|
|
24
35
|
const who = await apiRequest(baseUrl, opts.token, "GET", "/api/cli/whoami");
|
|
25
36
|
const scope = who.scope;
|
|
@@ -2,18 +2,27 @@ import { publicRequest } from "../http.js";
|
|
|
2
2
|
import { isInteractive, promptText, promptHidden } from "../prompt.js";
|
|
3
3
|
import { fail, EXIT_CODES } from "../errors.js";
|
|
4
4
|
import { action, printJsonOrText } from "../output.js";
|
|
5
|
-
import {
|
|
6
|
-
export const REGISTER_EXAMPLES = ` persona-test-cli register
|
|
7
|
-
persona-test-cli register https://your-app.example.com --email me@example.com --password ********
|
|
5
|
+
import { resolveBaseUrl } from "../config.js";
|
|
6
|
+
export const REGISTER_EXAMPLES = ` persona-test-cli register --email me@example.com --password ******** --json
|
|
7
|
+
persona-test-cli register --base-url https://your-app.example.com --email me@example.com --password ********
|
|
8
|
+
|
|
9
|
+
不传地址默认注册到 https://persona.mixlab.top,见 \`login --help\` 了解怎么连别的部署。`;
|
|
8
10
|
export function registerCommand(program) {
|
|
9
11
|
program
|
|
10
|
-
.command("register
|
|
12
|
+
.command("register [baseUrl]")
|
|
11
13
|
.description("自助注册一个普通用户账号(注册后需要 admin 在 /admin/users 审核通过才能登录)")
|
|
14
|
+
.option("--base-url <url>", "同位置参数,两种写法都行")
|
|
12
15
|
.option("--email <email>", "邮箱(作为用户名)")
|
|
13
16
|
.option("--password <password>", "密码(至少 8 位)")
|
|
14
17
|
.addHelpText("after", `\n示例:\n${REGISTER_EXAMPLES}`)
|
|
15
18
|
.action(action(async (baseUrlArg, opts) => {
|
|
16
|
-
const baseUrl =
|
|
19
|
+
const baseUrl = resolveBaseUrl(baseUrlArg ?? opts.baseUrl);
|
|
20
|
+
if (!baseUrl) {
|
|
21
|
+
fail("没有指定地址,加 <baseUrl> 或 --base-url,或设置 PERSONA_TEST_CLI_URL 环境变量", {
|
|
22
|
+
usage: REGISTER_EXAMPLES,
|
|
23
|
+
exitCode: EXIT_CODES.validation,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
17
26
|
let email = opts.email;
|
|
18
27
|
let password = opts.password;
|
|
19
28
|
if (!email || !password) {
|
package/dist/config.js
CHANGED
|
@@ -37,13 +37,18 @@ export function clearProfile(baseUrl) {
|
|
|
37
37
|
export function getProfile(baseUrl) {
|
|
38
38
|
return readConfig().profiles[normalizeBaseUrl(baseUrl)];
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
// This CLI ships pointed at one specific deployment by default — anyone
|
|
41
|
+
// installing it without overriding this is assumed to be a persona-test
|
|
42
|
+
// admin/user for that instance. Override with --base-url, PERSONA_TEST_CLI_URL,
|
|
43
|
+
// or just log into a different one (that becomes the new last-used default).
|
|
44
|
+
const DEFAULT_BASE_URL = "https://persona.mixlab.top";
|
|
45
|
+
/** Explicit --base-url wins; then PERSONA_TEST_CLI_URL; then whichever base URL was last logged into; then the built-in default. */
|
|
41
46
|
export function resolveBaseUrl(explicit) {
|
|
42
47
|
if (explicit)
|
|
43
48
|
return normalizeBaseUrl(explicit);
|
|
44
49
|
if (process.env.PERSONA_TEST_CLI_URL)
|
|
45
50
|
return normalizeBaseUrl(process.env.PERSONA_TEST_CLI_URL);
|
|
46
|
-
return readConfig().lastBaseUrl;
|
|
51
|
+
return readConfig().lastBaseUrl ?? DEFAULT_BASE_URL;
|
|
47
52
|
}
|
|
48
53
|
/** PERSONA_TEST_CLI_TOKEN always wins (agent-friendly: skip login entirely) — falls back to the stored profile. */
|
|
49
54
|
export function resolveToken(baseUrl) {
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
2
5
|
import { Command } from "commander";
|
|
3
6
|
import { registerCommand } from "./commands/register.js";
|
|
4
7
|
import { loginCommand } from "./commands/login.js";
|
|
@@ -9,13 +12,42 @@ import { personasCommand } from "./commands/personas.js";
|
|
|
9
12
|
import { eventsCommand } from "./commands/events.js";
|
|
10
13
|
import { usersCommand } from "./commands/users.js";
|
|
11
14
|
import { examplesCommand } from "./commands/examples.js";
|
|
15
|
+
import { jsonMode } from "./output.js";
|
|
16
|
+
// Reads package.json's version whether running from source (cli/index.ts,
|
|
17
|
+
// package.json next to it) or from the built dist/index.js (package.json one
|
|
18
|
+
// directory up) — avoids a hardcoded version string drifting from package.json.
|
|
19
|
+
function readVersion() {
|
|
20
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
for (const candidate of [join(here, "..", "package.json"), join(here, "package.json")]) {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(readFileSync(candidate, "utf8")).version;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return "0.0.0";
|
|
30
|
+
}
|
|
31
|
+
const version = readVersion();
|
|
12
32
|
const program = new Command();
|
|
13
33
|
program
|
|
14
34
|
.name("persona-test-cli")
|
|
15
35
|
.description("persona-test 运维 CLI —— admin 和已审核通过的普通用户都能用,普通用户只能看到/编辑自己创建的 campaigns/personas。\n" +
|
|
16
36
|
"先跑一次 `persona-test-cli examples` 看全部子命令的可复制示例。")
|
|
37
|
+
.version(version, "-v, --version", "打印版本号")
|
|
17
38
|
.option("--json", "所有命令输出纯 JSON(成功到 stdout,失败到 stderr),适合脚本/agent 调用")
|
|
18
39
|
.configureHelp({ sortSubcommands: true });
|
|
40
|
+
program
|
|
41
|
+
.command("version")
|
|
42
|
+
.description("打印版本号(等价于 -v/--version)")
|
|
43
|
+
.action(() => {
|
|
44
|
+
if (jsonMode) {
|
|
45
|
+
console.log(JSON.stringify({ version }));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.log(version);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
19
51
|
registerCommand(program);
|
|
20
52
|
loginCommand(program);
|
|
21
53
|
logoutCommand(program);
|