openclaw-weiyuan-init 1.0.119 → 1.0.128

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/cli.js CHANGED
@@ -3,11 +3,12 @@
3
3
  const { program } = require('commander');
4
4
  const chalk = require('chalk');
5
5
  const { runInit, runClean, runStatus } = require('../lib/commands');
6
+ const { version } = require('../package.json');
6
7
 
7
8
  program
8
9
  .name('openclaw-weiyuan-init')
9
10
  .description('OpenClaw Weiyuan Skill 一键初始化工具')
10
- .version('1.0.0');
11
+ .version(version);
11
12
 
12
13
  program
13
14
  .command('init')
package/lib/commands.js CHANGED
@@ -21,7 +21,7 @@ const DEFAULT_CONFIG = {
21
21
  workspaceName: 'workspace-weiyuan',
22
22
  upgradeBaseUrl: 'https://api.magon.com.cn/upgrade',
23
23
  downloadUrl: '',
24
- serverUrl: 'https://api.magon.com.cn/api',
24
+ serverUrl: 'https://api.magon.com.cn',
25
25
  identityFile: '.weiyuan',
26
26
  serverFallbacks: []
27
27
  };
@@ -168,6 +168,11 @@ function printInitAccountWelcome(initInfo) {
168
168
  const ruleInjectionMessage = String(initInfo.ruleInjectionMessage || '').trim();
169
169
  const targetAccountId = String(initInfo.targetAccountId || '').trim();
170
170
  const ownerAccountId = String(initInfo.ownerAccountId || '').trim();
171
+ const dashboardUrl = String(initInfo.dashboardUrl || '').trim();
172
+ const officialSiteUrl = String(initInfo.officialSiteUrl || 'https://www.magon.com.cn/').trim();
173
+ const loginUrl = String(initInfo.loginUrl || 'https://api.magon.com.cn/api/login').trim();
174
+ const bindPhoneUrl = String(initInfo.bindPhoneUrl || 'https://api.magon.com.cn/api/account/bind-phone').trim();
175
+ const skillDownloadUrl = String(initInfo.skillDownloadUrl || 'https://api.magon.com.cn/api/downloads/weiyuan-agent-cli-skill.md').trim();
171
176
  if (bindInit) {
172
177
  console.log(chalk.cyan(`\n【${modeLabel}绑定成功】`));
173
178
  if (welcome) console.log(chalk.white(welcome));
@@ -191,9 +196,15 @@ function printInitAccountWelcome(initInfo) {
191
196
  : '请牢记该账号信息;当前账号中心已切换为验证码登录体系。'
192
197
  )
193
198
  );
194
- console.log(chalk.white('微元系统官方网站为:https://api.magon.com.cn/'));
195
- console.log(chalk.white('微元系统登录页面为:https://api.magon.com.cn/api/login'));
196
- console.log(chalk.white('微元系统绑定手机号页面为:https://api.magon.com.cn/api/account/bind-phone'));
199
+ console.log(chalk.white(`微元系统官方网站为:${officialSiteUrl}`));
200
+ console.log(chalk.white(`微元系统登录页面为:${loginUrl}`));
201
+ console.log(chalk.white(`微元系统绑定手机号页面为:${bindPhoneUrl}`));
202
+ console.log(chalk.white(`微元系统智能体 skill 下载地址为:${skillDownloadUrl}`));
203
+ if (dashboardUrl) {
204
+ console.log(chalk.white(`个人驾驶舱地址为:${dashboardUrl}`));
205
+ console.log(chalk.white('请把这个驾驶舱链接保存好;后续优先直接打开该链接即可,不必每次都先回登录页查找入口。'));
206
+ }
207
+ console.log(chalk.white('如果你想把微元系统能力导入到 workbuddy、豆包等智能体,可以直接下载上面的 skill 文件并导入。'));
197
208
  console.log(chalk.white('建议立即前往“绑定手机号”页面完成手机号绑定,后续即可通过登录页获取验证码登录,并可在登录后修改用户名和密码。'));
198
209
  } else if (recovered) {
199
210
  console.log(chalk.cyan('\n【微元身份已同步】'));
@@ -217,7 +228,7 @@ function describeInitErrorMessage(error) {
217
228
  return '绑定命令已被使用,不能重复执行。请回到微元系统驾驶舱重新生成最新绑定命令';
218
229
  }
219
230
  if (msg.includes('bind_token_expired')) {
220
- return '绑定命令已过期,请回到微元系统驾驶舱重新生成最新绑定命令';
231
+ return '绑定命令已过期。注意:这通常只代表旧命令失效,不代表当前绑定状态已失效;如果驾驶舱已显示“已绑定”,请直接继续使用,或回到驾驶舱重新生成最新绑定命令';
221
232
  }
222
233
  if (msg.includes('unbind_token_not_found')) {
223
234
  return '解绑命令无效:未找到对应解绑令牌。请回到微元系统驾驶舱重新生成最新解绑命令后再执行';
@@ -226,7 +237,7 @@ function describeInitErrorMessage(error) {
226
237
  return '解绑命令已被使用,不能重复执行。请回到微元系统驾驶舱重新生成最新解绑命令';
227
238
  }
228
239
  if (msg.includes('unbind_token_expired')) {
229
- return '解绑命令已过期,请回到微元系统驾驶舱重新生成最新解绑命令';
240
+ return '解绑命令已过期。注意:这通常只代表旧命令失效,不代表当前绑定状态异常;请回到微元系统驾驶舱重新生成最新解绑命令';
230
241
  }
231
242
  if (msg.includes('target_not_found')) {
232
243
  return '服务器未找到本次绑定/解绑对应的目标账号,通常是命令域名错误、令牌对应账号已失效,或服务端数据尚未同步';
@@ -456,7 +467,19 @@ async function persistReleaseNotes(weiyuanPath, notes) {
456
467
 
457
468
  function resolveWorkspacePath(workspaceOption) {
458
469
  const raw = (workspaceOption || DEFAULT_CONFIG.workspaceName).trim();
459
- const target = path.isAbsolute(raw) ? raw : path.join(process.cwd(), raw);
470
+ const cwd = process.cwd();
471
+ const workspaceName = DEFAULT_CONFIG.workspaceName.toLowerCase();
472
+ const cwdBase = path.basename(cwd).toLowerCase();
473
+ const rawParts = raw.replace(/\\/g, '/').split('/').map((x) => String(x || '').trim()).filter(Boolean);
474
+ if (cwdBase === workspaceName) {
475
+ if (!raw || raw === '.' || raw === './' || raw === '.\\') {
476
+ return cwd;
477
+ }
478
+ if (rawParts.length > 0 && rawParts.every((part) => part.toLowerCase() === workspaceName)) {
479
+ return cwd;
480
+ }
481
+ }
482
+ const target = path.isAbsolute(raw) ? raw : path.join(cwd, raw);
460
483
  if (path.basename(target).toLowerCase() === DEFAULT_CONFIG.workspaceName.toLowerCase()) {
461
484
  return target;
462
485
  }
@@ -495,7 +518,7 @@ function normalizeServerUrl(raw) {
495
518
  try {
496
519
  const url = new URL(cleaned);
497
520
  const p = (url.pathname || '/').replace(/\/+$/, '');
498
- if (!p || p === '/') url.pathname = '/api';
521
+ if (!p || p === '/' || p === '/api' || /^\/(?:api\/)?v1(?:\/|$)/.test(p)) url.pathname = '';
499
522
  url.hash = '';
500
523
  return url.toString().replace(/\/$/, '');
501
524
  } catch (_) {
@@ -650,6 +673,7 @@ function buildAgentConversationGuide(projectId) {
650
673
  '请至少再给用户补充 2 个场景示例:',
651
674
  '1. 项目场景:用户说“帮我创建一个项目”,你继续追问项目名称、目标、负责人等关键信息,再完成创建。',
652
675
  '2. 协作场景:用户说“帮我在当前项目里建一个测试任务,明天下午提醒我跟进”,你要继续补全信息并直接帮他处理。',
676
+ '如果系统已经返回个人驾驶舱链接,你必须把该链接原样输出给用户,并提醒用户保存这个入口,后续可直接打开使用。',
653
677
  joinedProjectLine,
654
678
  '',
655
679
  '你还必须明确告诉用户:',
package/lib/identity.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs-extra');
2
2
  const os = require('os');
3
+ const path = require('path');
3
4
  const crypto = require('crypto');
4
5
  const axios = require('axios');
5
6
  const naclImport = require('tweetnacl');
@@ -45,17 +46,15 @@ function buildRecoveryHint(workspacePath) {
45
46
  }
46
47
 
47
48
  function normalizeBusinessServerUrl(serverUrl) {
48
- const fallback = 'https://api.magon.com.cn/api';
49
+ const fallback = 'https://api.magon.com.cn';
49
50
  if (!serverUrl || typeof serverUrl !== 'string') return fallback;
50
51
  try {
51
52
  const url = new URL(String(serverUrl).trim());
52
53
  const rawPath = String(url.pathname || '/');
53
54
  if (/^\/(?:api\/)?agent-(?:register|bind)(?:\/|$)/.test(rawPath)) {
54
- url.pathname = '/api';
55
- } else if (!rawPath || rawPath === '/') {
56
- url.pathname = '/api';
57
- } else if (!rawPath.startsWith('/api')) {
58
- url.pathname = `/api${rawPath.startsWith('/') ? '' : '/'}${rawPath}`;
55
+ url.pathname = '';
56
+ } else if (!rawPath || rawPath === '/' || rawPath === '/api' || /^\/(?:api\/)?v1(?:\/|$)/.test(rawPath)) {
57
+ url.pathname = '';
59
58
  }
60
59
  url.hash = '';
61
60
  return url.toString().replace(/\/$/, '');
@@ -64,12 +63,66 @@ function normalizeBusinessServerUrl(serverUrl) {
64
63
  }
65
64
  }
66
65
 
67
- async function registerIdentity(serverUrl, identity) {
66
+ function applyIdentityProxyMetadata(identity, initInfo) {
67
+ const next = identity && typeof identity === 'object' ? { ...identity } : {};
68
+ const lobsterId = String(next.lobsterId || '').trim();
69
+ const effectiveLobsterId = String(initInfo && initInfo.effectiveLobsterId || '').trim();
70
+ const ownerLobsterId = String(initInfo && initInfo.ownerLobsterId || '').trim();
71
+ const accountModeRaw = String(initInfo && initInfo.accountMode || initInfo && initInfo.mode || '').trim();
72
+ const accountMode = accountModeRaw === 'agent' || accountModeRaw === 'owner' ? accountModeRaw : '';
73
+ const accountTypeRaw = String(initInfo && initInfo.accountType || '').trim().toLowerCase();
74
+ const accountType = accountTypeRaw === 'auto' || accountTypeRaw === 'weiyuan' || accountTypeRaw === 'lob' ? accountTypeRaw : '';
75
+ const displayAccountId = String((initInfo && (initInfo.displayAccountId || initInfo.account)) || '').trim();
76
+ if (effectiveLobsterId && effectiveLobsterId !== lobsterId) next.effectiveLobsterId = effectiveLobsterId;
77
+ else delete next.effectiveLobsterId;
78
+ if (ownerLobsterId && ownerLobsterId !== lobsterId) next.ownerLobsterId = ownerLobsterId;
79
+ else delete next.ownerLobsterId;
80
+ if (accountMode) next.accountMode = accountMode;
81
+ else delete next.accountMode;
82
+ if (accountType) next.accountType = accountType;
83
+ else delete next.accountType;
84
+ if (displayAccountId) next.displayAccountId = displayAccountId;
85
+ else delete next.displayAccountId;
86
+ return next;
87
+ }
88
+
89
+ function normalizeSkillVersionText(raw) {
90
+ const text = String(raw || '').trim().replace(/^v/i, '');
91
+ return text && text !== '0.0.0' ? text : '';
92
+ }
93
+
94
+ async function readLocalSkillVersion(workspacePath) {
95
+ const weiyuanPath = path.join(String(workspacePath || ''), 'weiyuan');
96
+ const candidates = [
97
+ path.join(weiyuanPath, 'package.json'),
98
+ path.join(weiyuanPath, 'release-notes', 'latest.json'),
99
+ path.join(weiyuanPath, 'manifest.json'),
100
+ ];
101
+ for (const file of candidates) {
102
+ try {
103
+ const parsed = await fs.readJson(file);
104
+ const version = normalizeSkillVersionText(parsed && parsed.version);
105
+ if (version) return version;
106
+ } catch (_) {
107
+ }
108
+ }
109
+ try {
110
+ const plain = await fs.readFile(path.join(weiyuanPath, '.version'), 'utf8');
111
+ const version = normalizeSkillVersionText(plain);
112
+ if (version) return version;
113
+ } catch (_) {
114
+ }
115
+ return '';
116
+ }
117
+
118
+ async function registerIdentity(serverUrl, identity, workspacePath) {
119
+ const skillVersion = await readLocalSkillVersion(workspacePath);
68
120
  const body = {
69
121
  lobsterId: identity.lobsterId,
70
122
  publicKeyBase64: identity.publicKeyBase64,
71
123
  identityHash: identity.identityHash,
72
- recoveryHint: identity && identity.meta ? identity.meta.recoveryHint : undefined
124
+ recoveryHint: identity && identity.meta ? identity.meta.recoveryHint : undefined,
125
+ skillVersion: skillVersion || undefined
73
126
  };
74
127
  const timestampMs = String(Date.now());
75
128
  const nonce = `nonce_${Math.random().toString(16).slice(2)}`;
@@ -127,7 +180,7 @@ async function createIdentityFile(identityPath, serverUrl, workspacePath) {
127
180
  recoveryHint: (existing.meta && existing.meta.recoveryHint) || buildRecoveryHint(workspacePath)
128
181
  }
129
182
  };
130
- const initInfo = await registerIdentity(serverUrl, identity);
183
+ const initInfo = await registerIdentity(serverUrl, identity, workspacePath);
131
184
  const serverLobsterId = String(initInfo && initInfo.lobsterId || '').trim();
132
185
  if (serverLobsterId) {
133
186
  identity.lobsterId = serverLobsterId;
@@ -135,23 +188,23 @@ async function createIdentityFile(identityPath, serverUrl, workspacePath) {
135
188
  }
136
189
  if (initInfo && Array.isArray(initInfo.joinedProjectIds)) {
137
190
  identity.joinedProjectIds = initInfo.joinedProjectIds.map((x) => String(x || '').trim()).filter(Boolean);
138
- } else {
139
- delete identity.joinedProjectIds;
140
191
  }
141
192
  if (initInfo && typeof initInfo.currentProjectId === 'string' && initInfo.currentProjectId.trim()) {
142
193
  identity.currentProjectId = String(initInfo.currentProjectId).trim();
143
- } else {
144
- delete identity.currentProjectId;
194
+ } else if (!identity.currentProjectId && Array.isArray(identity.joinedProjectIds) && identity.joinedProjectIds.length) {
195
+ identity.currentProjectId = String(identity.joinedProjectIds[0] || '').trim() || identity.currentProjectId;
196
+ }
197
+ if (initInfo && initInfo.projectCursors && typeof initInfo.projectCursors === 'object' && !Array.isArray(initInfo.projectCursors)) {
198
+ identity.projectCursors = Object.fromEntries(
199
+ Object.entries(initInfo.projectCursors)
200
+ .map(([k, v]) => [String(k || '').trim(), Number(v || 0)])
201
+ .filter(([k, v]) => k && Number.isFinite(v))
202
+ );
203
+ } else if (!identity.projectCursors || typeof identity.projectCursors !== 'object' || Array.isArray(identity.projectCursors)) {
204
+ identity.projectCursors = {};
145
205
  }
146
- identity.projectCursors =
147
- initInfo && initInfo.projectCursors && typeof initInfo.projectCursors === 'object' && !Array.isArray(initInfo.projectCursors)
148
- ? Object.fromEntries(
149
- Object.entries(initInfo.projectCursors)
150
- .map(([k, v]) => [String(k || '').trim(), Number(v || 0)])
151
- .filter(([k, v]) => k && Number.isFinite(v))
152
- )
153
- : {};
154
- await fs.writeJson(identityPath, identity, { spaces: 2 });
206
+ const nextIdentity = applyIdentityProxyMetadata(identity, initInfo);
207
+ await fs.writeJson(identityPath, nextIdentity, { spaces: 2 });
155
208
  return { created: true, initInfo: initInfo || null };
156
209
  }
157
210
  }
@@ -176,7 +229,7 @@ async function createIdentityFile(identityPath, serverUrl, workspacePath) {
176
229
  }
177
230
  };
178
231
 
179
- const initInfo = await registerIdentity(serverUrl, identity);
232
+ const initInfo = await registerIdentity(serverUrl, identity, workspacePath);
180
233
  const serverLobsterId = String(initInfo && initInfo.lobsterId || '').trim();
181
234
  if (serverLobsterId) {
182
235
  identity.lobsterId = serverLobsterId;
@@ -184,23 +237,23 @@ async function createIdentityFile(identityPath, serverUrl, workspacePath) {
184
237
  }
185
238
  if (initInfo && Array.isArray(initInfo.joinedProjectIds)) {
186
239
  identity.joinedProjectIds = initInfo.joinedProjectIds.map((x) => String(x || '').trim()).filter(Boolean);
187
- } else {
188
- delete identity.joinedProjectIds;
189
240
  }
190
241
  if (initInfo && typeof initInfo.currentProjectId === 'string' && initInfo.currentProjectId.trim()) {
191
242
  identity.currentProjectId = String(initInfo.currentProjectId).trim();
192
- } else {
193
- delete identity.currentProjectId;
243
+ } else if (!identity.currentProjectId && Array.isArray(identity.joinedProjectIds) && identity.joinedProjectIds.length) {
244
+ identity.currentProjectId = String(identity.joinedProjectIds[0] || '').trim() || identity.currentProjectId;
194
245
  }
195
- identity.projectCursors =
196
- initInfo && initInfo.projectCursors && typeof initInfo.projectCursors === 'object' && !Array.isArray(initInfo.projectCursors)
197
- ? Object.fromEntries(
198
- Object.entries(initInfo.projectCursors)
199
- .map(([k, v]) => [String(k || '').trim(), Number(v || 0)])
200
- .filter(([k, v]) => k && Number.isFinite(v))
201
- )
202
- : {};
203
- await fs.writeJson(identityPath, identity, { spaces: 2 });
246
+ if (initInfo && initInfo.projectCursors && typeof initInfo.projectCursors === 'object' && !Array.isArray(initInfo.projectCursors)) {
247
+ identity.projectCursors = Object.fromEntries(
248
+ Object.entries(initInfo.projectCursors)
249
+ .map(([k, v]) => [String(k || '').trim(), Number(v || 0)])
250
+ .filter(([k, v]) => k && Number.isFinite(v))
251
+ );
252
+ } else if (!identity.projectCursors || typeof identity.projectCursors !== 'object' || Array.isArray(identity.projectCursors)) {
253
+ identity.projectCursors = {};
254
+ }
255
+ const nextIdentity = applyIdentityProxyMetadata(identity, initInfo);
256
+ await fs.writeJson(identityPath, nextIdentity, { spaces: 2 });
204
257
  return { created: true, initInfo: initInfo || null };
205
258
  } catch (error) {
206
259
  return { created: false, initInfo: null, error: error && error.message ? String(error.message) : 'identity_create_failed' };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-weiyuan-init",
3
- "version": "1.0.119",
3
+ "version": "1.0.128",
4
4
  "description": "OpenClaw Weiyuan Skill 一键初始化工具",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -1052,7 +1052,7 @@ const DEFAULT_REPLY_TEMPLATES: ReplyTemplateMap = {
1052
1052
  "runtime.upgrade": { text: "更新成功。" },
1053
1053
  }
1054
1054
 
1055
- const WEIYUAN_OFFICIAL_WEBSITE = "https://api.magon.com.cn/"
1055
+ const WEIYUAN_OFFICIAL_WEBSITE = "https://www.magon.com.cn/"
1056
1056
 
1057
1057
  function withOfficialWebsiteIfLinkPresent(obj: Record<string, unknown>, message: string): { message: string; officialWebsite: string } | null {
1058
1058
  const hasDashboard = typeof obj.dashboardLink === "string" && obj.dashboardLink.trim().length > 0
@@ -1124,9 +1124,31 @@ function formatWatermark(): { time: string; traceId: string } {
1124
1124
  }
1125
1125
 
1126
1126
  function buildMandatoryDisplay(actionKey: string | undefined, core: unknown): string | undefined {
1127
- if (!actionKey) return undefined
1128
1127
  const c = asRecord(core)
1129
1128
  const { time, traceId } = formatWatermark()
1129
+ const account = typeof c.account === "string" ? c.account.trim() : ""
1130
+ const dashboardLink = typeof c.dashboardLink === "string" ? c.dashboardLink.trim() : (typeof c.dashboardUrl === "string" ? c.dashboardUrl.trim() : "")
1131
+ const bindPhoneUrl = typeof c.bindPhoneUrl === "string" ? c.bindPhoneUrl.trim() : ""
1132
+ const loginUrl = typeof c.loginUrl === "string" ? c.loginUrl.trim() : ""
1133
+ const officialWebsite = typeof c.officialWebsite === "string"
1134
+ ? c.officialWebsite.trim()
1135
+ : (typeof c.officialSiteUrl === "string" ? c.officialSiteUrl.trim() : WEIYUAN_OFFICIAL_WEBSITE)
1136
+ if (account && (dashboardLink || bindPhoneUrl || loginUrl || officialWebsite)) {
1137
+ return [
1138
+ `### 🌀 微元系统账号入口 (不可修改)(数据时间:${time} | Trace_ID:${traceId})`,
1139
+ "| 项目 | 内容 |",
1140
+ "| --- | --- |",
1141
+ `| 微元账号 | ${account} |`,
1142
+ `| 个人驾驶舱 | ${dashboardLink || "未返回"} |`,
1143
+ `| 手机号绑定 | ${bindPhoneUrl || "未返回"} |`,
1144
+ `| 登录页面 | ${loginUrl || "未返回"} |`,
1145
+ `| 官方网站 | ${officialWebsite || WEIYUAN_OFFICIAL_WEBSITE} |`,
1146
+ "",
1147
+ `- **重点提醒**:个人驾驶舱链接是重点入口,请立即保存:${dashboardLink || "当前未返回,请重新获取一次加入成功结果"}`,
1148
+ "-----------------------------------",
1149
+ ].join("\n")
1150
+ }
1151
+ if (!actionKey) return undefined
1130
1152
  if (actionKey.startsWith("project.")) {
1131
1153
  const projectName = pickProjectName(c)
1132
1154
  const projectId = typeof c.projectId === "string" ? c.projectId : "未获取"
@@ -1507,7 +1529,7 @@ function buildDialogueData(raw: unknown, detailed: boolean, actionKey?: string,
1507
1529
  const quickActions = showOperationalInfo ? collectQuickActions(raw).slice(0, 3) : []
1508
1530
  const base = enforceOutputQuality(conciseMessageFromCore(slim, actionKey, templates), slim, actionKey)
1509
1531
  const tip = pickMicroTip(actionKey)
1510
- const mandatoryDisplay = buildMandatoryDisplay(actionKey, slim)
1532
+ const mandatoryDisplay = buildMandatoryDisplay(actionKey, raw)
1511
1533
  const friendly = withMicroPrefix(tip ? `${base}\n${tip}` : base)
1512
1534
  const messageRaw = mandatoryDisplay ? `🌐【微元项目模式】\n${mandatoryDisplay}\n${friendly}` : friendly
1513
1535
  const message = applyExpressionPolicyText(messageRaw, "已处理完成。", actionKey)
@@ -5,7 +5,7 @@ import type { WeiyuanIdentityFileV1 } from "./types"
5
5
  export const DEFAULT_IDENTITY_PATH = ".weiyuan"
6
6
 
7
7
  export function normalizeServerBaseUrl(raw: string): string {
8
- const fallback = "https://api.magon.com.cn/api"
8
+ const fallback = "https://api.magon.com.cn"
9
9
  if (!raw || typeof raw !== "string") return fallback
10
10
  const cleaned = raw.trim().replace(/^[`'"\s]+|[`'"\s]+$/g, "")
11
11
  if (!cleaned) return fallback
@@ -21,16 +21,17 @@ export function normalizeServerBaseUrl(raw: string): string {
21
21
  url.protocol = "https:"
22
22
  const rawPath = String(url.pathname || "/")
23
23
  if (/^\/(?:api\/)?agent-(?:register|bind)(?:\/|$)/.test(rawPath)) {
24
- url.pathname = "/api"
24
+ url.pathname = ""
25
25
  } else {
26
- if (!url.pathname || url.pathname === "/") url.pathname = "/api"
27
- if (!url.pathname.startsWith("/api")) url.pathname = `/api${url.pathname.startsWith("/") ? "" : "/"}${url.pathname}`
26
+ if (!url.pathname || url.pathname === "/" || url.pathname === "/api" || /^\/(?:api\/)?v1(?:\/|$)/.test(rawPath)) url.pathname = ""
28
27
  }
29
28
  url.hash = ""
30
29
  return url.toString().replace(/\/$/, "")
31
30
  }
32
31
  if (/^\/(?:api\/)?agent-(?:register|bind)(?:\/|$)/.test(String(url.pathname || "/"))) {
33
- url.pathname = "/api"
32
+ url.pathname = ""
33
+ } else if (String(url.pathname || "") === "/api" || /^\/(?:api\/)?v1(?:\/|$)/.test(String(url.pathname || "/"))) {
34
+ url.pathname = ""
34
35
  }
35
36
  url.hash = ""
36
37
  return url.toString().replace(/\/$/, "")