@kweaver-ai/kweaver-sdk 0.6.5 → 0.6.7

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 CHANGED
@@ -153,8 +153,11 @@ const skillMd = await client.skills.fetchContent("skill-id");
153
153
  ## CLI Reference
154
154
 
155
155
  ```
156
- kweaver auth login <url> [--alias name] [--no-auth] [--no-browser] [-u user] [-p pass] [--http-signin] [--playwright] [--insecure|-k]
157
- # -u/-p: tries HTTP /oauth2/signin first (refresh_token). If studioweb is missing: falls back to Playwright when installed, else prints install hint. --http-signin: HTTP only. --playwright: force browser automation.
156
+ kweaver auth login <url> [--alias name] [--no-auth] [--no-browser] [-u user] [-p pass] [--new-password <pwd>] [--http-signin] [--insecure|-k]
157
+ # -u/-p (with or without --http-signin): HTTP POST /oauth2/signin (yields refresh_token). Missing -u/-p are prompted from stdin (password hidden when TTY).
158
+ # If the server returns error 401001017 (initial password), TTY users get a prompt to set a new password; non-interactive scripts must pass --new-password <pwd>.
159
+ kweaver auth change-password [<url>] [-u <account>] [-o <old>] [-n <new>] [--insecure|-k]
160
+ # EACP POST /api/eacp/v1/auth1/modifypassword — no OAuth token required. Omit -o/-n on a TTY to be prompted.
158
161
  kweaver auth login <url> --client-id ID --client-secret S --refresh-token T (headless login)
159
162
  kweaver auth export [url|alias] [--json] (export command to run on a headless host)
160
163
  kweaver auth status / whoami [url|alias] [--json] # whoami: --json; with KWEAVER_BASE_URL+KWEAVER_TOKEN when no ~/.kweaver/ platform
package/README.zh.md CHANGED
@@ -146,8 +146,10 @@ const skillMd = await client.skills.fetchContent("skill-id");
146
146
  ## 命令速查
147
147
 
148
148
  ```
149
- kweaver auth login <url> [--alias name] [--no-auth] [--no-browser] [-u user] [-p pass] [--http-signin] [--playwright] [--insecure|-k]
150
- # -u/-p:默认先试 HTTP /oauth2/signin(可拿 refresh_token);无 studioweb 时:已装 Playwright 则回退无头浏览器,否则提示安装 Playwright;--http-signin 仅 HTTP;--playwright 强制浏览器
149
+ kweaver auth login <url> [--alias name] [--no-auth] [--no-browser] [-u user] [-p pass] [--new-password <pwd>] [--http-signin] [--insecure|-k]
150
+ # -u/-p(无论是否带 --http-signin):HTTP POST /oauth2/signin(可拿 refresh_token);缺失的用户名/密码会从 stdin 提示输入(TTY 下密码隐藏)
151
+ # 若服务端返回 401001017(初始密码),交互终端会引导修改;非交互请使用 --new-password <pwd>。
152
+ kweaver auth change-password [<url>] [-u <account>] [-o <old>] [-n <new>] [--insecure|-k]
151
153
  kweaver auth login <url> --client-id ID --client-secret S --refresh-token T (无浏览器登录)
152
154
  kweaver auth export [url|alias] [--json] (导出在无浏览器机器上运行的命令)
153
155
  kweaver auth status / whoami [url|alias] [--json] # whoami 支持 --json;无 ~/.kweaver/ 当前平台时可配 KWEAVER_BASE_URL+KWEAVER_TOKEN
@@ -12,8 +12,8 @@ import { buildHeaders } from "./headers.js";
12
12
  // POST /tool-box/{id}/tools/status enable/disable (batch)
13
13
  //
14
14
  // Verified during Task 8 e2e against the live backend (2026-04-18):
15
- // GET /tool-box?keyword=&limit=&offset= list toolboxes
16
- // GET /tool-box/{id}/tool list tools
15
+ // GET /tool-box/list?keyword=&limit=&offset= list toolboxes
16
+ // GET /tool-box/{id}/tools/list list tools
17
17
  const PATH = "/api/agent-operator-integration/v1/tool-box";
18
18
  function url(base, suffix = "") {
19
19
  return `${base.replace(/\/+$/, "")}${PATH}${suffix}`;
@@ -74,7 +74,7 @@ export async function listToolboxes(opts) {
74
74
  qp.set("limit", String(opts.limit));
75
75
  if (opts.offset !== undefined)
76
76
  qp.set("offset", String(opts.offset));
77
- const suffix = qp.toString() ? `?${qp}` : "";
77
+ const suffix = `/list${qp.toString() ? `?${qp}` : ""}`;
78
78
  const { body } = await fetchTextOrThrow(url(opts.baseUrl, suffix), {
79
79
  method: "GET",
80
80
  headers: buildHeaders(opts.accessToken, opts.businessDomain ?? "bd_public"),
@@ -82,7 +82,7 @@ export async function listToolboxes(opts) {
82
82
  return body;
83
83
  }
84
84
  export async function listTools(opts) {
85
- const { body } = await fetchTextOrThrow(url(opts.baseUrl, `/${encodeURIComponent(opts.boxId)}/tool`), {
85
+ const { body } = await fetchTextOrThrow(url(opts.baseUrl, `/${encodeURIComponent(opts.boxId)}/tools/list`), {
86
86
  method: "GET",
87
87
  headers: buildHeaders(opts.accessToken, opts.businessDomain ?? "bd_public"),
88
88
  });
@@ -0,0 +1,25 @@
1
+ /** Encrypt a password with EACP modifypassword's RSA public key, base64-encoded. */
2
+ export declare function encryptModifyPwd(plain: string, publicKeyPem?: string): string;
3
+ /** @internal For unit tests: decrypt ciphertext produced by encryptModifyPwd with the embedded key. */
4
+ export declare function decryptModifyPwdForTest(cipherB64: string): string;
5
+ export interface EacpModifyPasswordOptions {
6
+ account: string;
7
+ oldPassword: string;
8
+ newPassword: string;
9
+ /** Override the embedded RSA public key (PEM). */
10
+ publicKeyPem?: string;
11
+ tlsInsecure?: boolean;
12
+ }
13
+ export interface EacpModifyPasswordResult {
14
+ status: number;
15
+ ok: boolean;
16
+ body: string;
17
+ json?: unknown;
18
+ }
19
+ /**
20
+ * Call EACP `POST /api/eacp/v1/auth1/modifypassword` to change a user's password
21
+ * when the old password is known (`isforgetpwd: false`).
22
+ *
23
+ * No bearer token / cookie is required — the endpoint authenticates by old password.
24
+ */
25
+ export declare function eacpModifyPassword(baseUrl: string, options: EacpModifyPasswordOptions): Promise<EacpModifyPasswordResult>;
@@ -0,0 +1,84 @@
1
+ import { constants as cryptoConstants, createPrivateKey, createPublicKey, privateDecrypt, publicEncrypt, } from "node:crypto";
2
+ import { normalizeBaseUrl, runWithTlsInsecure } from "./oauth.js";
3
+ /**
4
+ * 1024-bit RSA private key embedded in ShareServer
5
+ * (`isf/ShareServer/src/eachttpserver/ncEACHttpServerUtil.cpp`, function
6
+ * `ncEACHttpServerUtil::RSADecrypt`). It is the keypair used by the EACP
7
+ * `auth1/modifypassword` endpoint to decrypt `oldpwd` / `newpwd`.
8
+ *
9
+ * Note: this key is intentionally hard-coded in the C++ binary and shipped to
10
+ * every customer; it is not a secret. We embed it here so the CLI can perform
11
+ * the matching `RSA_PKCS1` encryption without contacting the server.
12
+ */
13
+ const EACP_MODIFYPWD_PRIVATE_KEY_PEM = `-----BEGIN RSA PRIVATE KEY-----
14
+ MIICXgIBAAKBgQDB2fhLla9rMx+6LWTXajnK11Kdp520s1Q+TfPfIXI/7G9+L2YC
15
+ 4RA3M5rgRi32s5+UFQ/CVqUFqMqVuzaZ4lw/uEdk1qHcP0g6LB3E9wkl2FclFR0M
16
+ +/HrWmxPoON+0y/tFQxxfNgsUodFzbdh0XY1rIVUIbPLvufUBbLKXHDPpwIDAQAB
17
+ AoGBALCM/H6ajXFs1nCR903aCVicUzoS9qckzI0SIhIOPCfMBp8+PAJTSJl9/ohU
18
+ YnhVj/kmVXwBvboxyJAmOcxdRPWL7iTk5nA1oiVXMer3Wby+tRg/ls91xQbJLVv3
19
+ oGSt7q0CXxJpRH2oYkVVlMMlZUwKz3ovHiLKAnhw+jEsdL2BAkEA9hA97yyeA2eq
20
+ f9dMu/ici99R3WJRRtk4NEI4WShtWPyziDg48d3SOzYmhEJjPuOo3g1ze01os70P
21
+ ApE7d0qcyQJBAMmt+FR8h5MwxPQPAzjh/fTuTttvUfBeMiUDrIycK1I/L96lH+fU
22
+ i4Nu+7TPOzExnPeGO5UJbZxrpIEUB7Zs8O8CQQCLzTCTGiNwxc5eMgH77kVrRudp
23
+ Q7nv6ex/7Hu9VDXEUFbkdyULbj9KuvppPJrMmWZROw04qgNp02mayM8jeLXZAkEA
24
+ o+PM/pMn9TPXiWE9xBbaMhUKXgXLd2KEq1GeAbHS/oY8l1hmYhV1vjwNLbSNrH9d
25
+ yEP73TQJL+jFiONHFTbYXwJAU03Xgum5mLIkX/02LpOrz2QCdfX1IMJk2iKi9osV
26
+ KqfbvHsF0+GvFGg18/FXStG9Kr4TjqLsygQJT76/MnMluw==
27
+ -----END RSA PRIVATE KEY-----`;
28
+ let cachedPubKey;
29
+ function getModifyPwdPublicKey() {
30
+ if (!cachedPubKey) {
31
+ cachedPubKey = createPublicKey(createPrivateKey(EACP_MODIFYPWD_PRIVATE_KEY_PEM));
32
+ }
33
+ return cachedPubKey;
34
+ }
35
+ /** Encrypt a password with EACP modifypassword's RSA public key, base64-encoded. */
36
+ export function encryptModifyPwd(plain, publicKeyPem) {
37
+ const key = publicKeyPem ? createPublicKey(publicKeyPem) : getModifyPwdPublicKey();
38
+ const buf = publicEncrypt({ key, padding: cryptoConstants.RSA_PKCS1_PADDING }, Buffer.from(plain, "utf8"));
39
+ return buf.toString("base64");
40
+ }
41
+ /** @internal For unit tests: decrypt ciphertext produced by encryptModifyPwd with the embedded key. */
42
+ export function decryptModifyPwdForTest(cipherB64) {
43
+ const key = createPrivateKey(EACP_MODIFYPWD_PRIVATE_KEY_PEM);
44
+ const buf = privateDecrypt({ key, padding: cryptoConstants.RSA_PKCS1_PADDING }, Buffer.from(cipherB64, "base64"));
45
+ return buf.toString("utf8");
46
+ }
47
+ /**
48
+ * Call EACP `POST /api/eacp/v1/auth1/modifypassword` to change a user's password
49
+ * when the old password is known (`isforgetpwd: false`).
50
+ *
51
+ * No bearer token / cookie is required — the endpoint authenticates by old password.
52
+ */
53
+ export async function eacpModifyPassword(baseUrl, options) {
54
+ return runWithTlsInsecure(options.tlsInsecure, async () => {
55
+ const body = {
56
+ account: options.account,
57
+ oldpwd: encryptModifyPwd(options.oldPassword, options.publicKeyPem),
58
+ newpwd: encryptModifyPwd(options.newPassword, options.publicKeyPem),
59
+ vcodeinfo: {
60
+ uuid: "",
61
+ vcode: "",
62
+ },
63
+ isforgetpwd: false,
64
+ };
65
+ const url = `${normalizeBaseUrl(baseUrl)}/api/eacp/v1/auth1/modifypassword`;
66
+ const resp = await fetch(url, {
67
+ method: "POST",
68
+ headers: {
69
+ "Content-Type": "application/json",
70
+ Accept: "application/json, text/plain, */*",
71
+ },
72
+ body: JSON.stringify(body),
73
+ });
74
+ const text = await resp.text();
75
+ let json;
76
+ try {
77
+ json = text ? JSON.parse(text) : undefined;
78
+ }
79
+ catch {
80
+ /* not JSON */
81
+ }
82
+ return { status: resp.status, ok: resp.ok, body: text, json };
83
+ });
84
+ }
@@ -1,4 +1,17 @@
1
1
  import { type TokenConfig } from "../config/store.js";
2
+ /** Thrown when `POST /oauth2/signin` returns HTTP 401 with EACP code `401001017` (initial password must be changed). */
3
+ export declare class InitialPasswordChangeRequiredError extends Error {
4
+ readonly code = 401001017;
5
+ readonly account: string;
6
+ readonly baseUrl: string;
7
+ readonly httpStatus = 401;
8
+ readonly serverMessage: string;
9
+ constructor(opts: {
10
+ account: string;
11
+ baseUrl: string;
12
+ serverMessage: string;
13
+ });
14
+ }
2
15
  /**
3
16
  * Studioweb hardcoded LOGIN public key (PEM) — the single key used for HTTP `/oauth2/signin`.
4
17
  * Source: kweaver-ai/kweaver `deploy/auto_cofig/auto_config.sh` `LOGIN_PUBLIC_KEY`.
@@ -32,6 +45,40 @@ export declare function normalizeBaseUrl(value: string): string;
32
45
  */
33
46
  /** @internal Exported for CLI env-only identity resolution (`env-snapshot.ts`). */
34
47
  export declare function runWithTlsInsecure<T>(tlsInsecure: boolean | undefined, fn: () => Promise<T>): Promise<T>;
48
+ /**
49
+ * Headless login: read authorization code from stdin (full callback URL or raw code).
50
+ * Used with `--no-browser` or when automatic browser launch fails.
51
+ *
52
+ * `io` is injectable for tests; defaults to `process.stdin` / `process.stderr`.
53
+ */
54
+ export declare function promptForCode(authUrl: string, state: string, port: number, pasteMode?: "explicit" | "fallback", io?: {
55
+ input?: NodeJS.ReadableStream;
56
+ output?: NodeJS.WritableStream;
57
+ }): Promise<string>;
58
+ /**
59
+ * Prompt the user for a username on stderr (input echoed).
60
+ *
61
+ * `io` is injectable for tests; defaults to `process.stdin` / `process.stderr`.
62
+ */
63
+ export declare function promptForUsername(promptLabel?: string, io?: {
64
+ input?: NodeJS.ReadableStream;
65
+ output?: NodeJS.WritableStream;
66
+ }): Promise<string>;
67
+ /**
68
+ * Prompt the user for a password on stderr without echoing keystrokes (TTY only).
69
+ *
70
+ * Falls back to a regular readline prompt when stdin is not a TTY (e.g. piped input
71
+ * during scripted use); callers needing strict no-echo should detect this case themselves.
72
+ *
73
+ * `io` is injectable for tests.
74
+ */
75
+ export declare function promptForPassword(promptLabel?: string, io?: {
76
+ input?: NodeJS.ReadableStream & {
77
+ isTTY?: boolean;
78
+ setRawMode?: (mode: boolean) => unknown;
79
+ };
80
+ output?: NodeJS.WritableStream;
81
+ }): Promise<string>;
35
82
  /**
36
83
  * OAuth2 Authorization Code login flow.
37
84
  * 1. Register client (if not already registered), OR use a provided client ID
@@ -53,24 +100,6 @@ export declare function oauth2Login(baseUrl: string, options?: {
53
100
  */
54
101
  noBrowser?: boolean;
55
102
  }): Promise<TokenConfig>;
56
- /**
57
- * Playwright-automated OAuth2 login.
58
- *
59
- * Uses the full OAuth2 authorization code flow (same as `oauth2Login`) but
60
- * automates the browser interaction with Playwright. This produces a
61
- * refresh_token so the CLI can auto-refresh without re-login.
62
- *
63
- * When `username` and `password` are provided the browser runs headless and
64
- * fills the login form automatically. Otherwise it opens a visible browser
65
- * window for manual login (same UX as the old cookie-based flow).
66
- */
67
- export declare function playwrightLogin(baseUrl: string, options?: {
68
- username?: string;
69
- password?: string;
70
- port?: number;
71
- scope?: string;
72
- tlsInsecure?: boolean;
73
- }): Promise<TokenConfig>;
74
103
  /**
75
104
  * Parse Next.js `__NEXT_DATA__` from the OAuth2 sign-in HTML shell (CSRF + optional challenge/remember for POST /oauth2/signin).
76
105
  * Hydra `login_challenge` may appear only in the sign-in URL; use that when `pageProps.challenge` is absent.
@@ -83,10 +112,25 @@ export declare function parseSigninPageHtmlProps(html: string): {
83
112
  rsaPublicKeyMaterial?: string;
84
113
  };
85
114
  /**
86
- * True when {@link oauth2PasswordSigninLogin} failed because the Studio web sign-in shell
87
- * (`/interface/studioweb/login`) is missing or unreachable — callers may fall back to Playwright.
115
+ * Build the JSON body for `POST /oauth2/signin` (matches the browser `oauth2-ui` form).
116
+ *
117
+ * `device.client_type` MUST be a value present in the EACP whitelist defined by
118
+ * `kweaver/deploy/auto_cofig/auto_config.sh`. `console_web` is the canonical CLI value
119
+ * (also used by `kweaver-admin`); other values such as `unknown` are rejected by strict
120
+ * deployments with `管理员已禁止此类客户端登录` — surfaced upstream as a `request_forbidden`
121
+ * `No CSRF value available in the session cookie` error after Hydra discards the rejected
122
+ * login challenge.
123
+ *
124
+ * `vcode` and `dualfactorauthinfo` must be present even when empty; otherwise eachttpserver
125
+ * returns HTTP 400 (invalid parameter).
88
126
  */
89
- export declare function isStudiowebShellUnavailableError(err: unknown): boolean;
127
+ export declare function buildOauth2SigninPostBody(opts: {
128
+ csrftoken: string;
129
+ challenge: string;
130
+ account: string;
131
+ passwordCipher: string;
132
+ remember: boolean;
133
+ }): Record<string, unknown>;
90
134
  /**
91
135
  * OAuth2 Authorization Code login using HTTP **only**: `GET /oauth2/signin` (Next.js shell) and
92
136
  * `POST /oauth2/signin` with an RSA PKCS#1 v1.5–encrypted password (same as the browser `rsa.min` / Studio