openclaw-weiyuan-init 1.0.127 → 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/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 '服务器未找到本次绑定/解绑对应的目标账号,通常是命令域名错误、令牌对应账号已失效,或服务端数据尚未同步';
@@ -507,7 +518,7 @@ function normalizeServerUrl(raw) {
507
518
  try {
508
519
  const url = new URL(cleaned);
509
520
  const p = (url.pathname || '/').replace(/\/+$/, '');
510
- if (!p || p === '/') url.pathname = '/api';
521
+ if (!p || p === '/' || p === '/api' || /^\/(?:api\/)?v1(?:\/|$)/.test(p)) url.pathname = '';
511
522
  url.hash = '';
512
523
  return url.toString().replace(/\/$/, '');
513
524
  } catch (_) {
@@ -662,6 +673,7 @@ function buildAgentConversationGuide(projectId) {
662
673
  '请至少再给用户补充 2 个场景示例:',
663
674
  '1. 项目场景:用户说“帮我创建一个项目”,你继续追问项目名称、目标、负责人等关键信息,再完成创建。',
664
675
  '2. 协作场景:用户说“帮我在当前项目里建一个测试任务,明天下午提醒我跟进”,你要继续补全信息并直接帮他处理。',
676
+ '如果系统已经返回个人驾驶舱链接,你必须把该链接原样输出给用户,并提醒用户保存这个入口,后续可直接打开使用。',
665
677
  joinedProjectLine,
666
678
  '',
667
679
  '你还必须明确告诉用户:',
package/lib/identity.js CHANGED
@@ -46,17 +46,15 @@ function buildRecoveryHint(workspacePath) {
46
46
  }
47
47
 
48
48
  function normalizeBusinessServerUrl(serverUrl) {
49
- const fallback = 'https://api.magon.com.cn/api';
49
+ const fallback = 'https://api.magon.com.cn';
50
50
  if (!serverUrl || typeof serverUrl !== 'string') return fallback;
51
51
  try {
52
52
  const url = new URL(String(serverUrl).trim());
53
53
  const rawPath = String(url.pathname || '/');
54
54
  if (/^\/(?:api\/)?agent-(?:register|bind)(?:\/|$)/.test(rawPath)) {
55
- url.pathname = '/api';
56
- } else if (!rawPath || rawPath === '/') {
57
- url.pathname = '/api';
58
- } else if (!rawPath.startsWith('/api')) {
59
- url.pathname = `/api${rawPath.startsWith('/') ? '' : '/'}${rawPath}`;
55
+ url.pathname = '';
56
+ } else if (!rawPath || rawPath === '/' || rawPath === '/api' || /^\/(?:api\/)?v1(?:\/|$)/.test(rawPath)) {
57
+ url.pathname = '';
60
58
  }
61
59
  url.hash = '';
62
60
  return url.toString().replace(/\/$/, '');
@@ -190,22 +188,21 @@ async function createIdentityFile(identityPath, serverUrl, workspacePath) {
190
188
  }
191
189
  if (initInfo && Array.isArray(initInfo.joinedProjectIds)) {
192
190
  identity.joinedProjectIds = initInfo.joinedProjectIds.map((x) => String(x || '').trim()).filter(Boolean);
193
- } else {
194
- delete identity.joinedProjectIds;
195
191
  }
196
192
  if (initInfo && typeof initInfo.currentProjectId === 'string' && initInfo.currentProjectId.trim()) {
197
193
  identity.currentProjectId = String(initInfo.currentProjectId).trim();
198
- } else {
199
- 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 = {};
200
205
  }
201
- identity.projectCursors =
202
- initInfo && initInfo.projectCursors && typeof initInfo.projectCursors === 'object' && !Array.isArray(initInfo.projectCursors)
203
- ? Object.fromEntries(
204
- Object.entries(initInfo.projectCursors)
205
- .map(([k, v]) => [String(k || '').trim(), Number(v || 0)])
206
- .filter(([k, v]) => k && Number.isFinite(v))
207
- )
208
- : {};
209
206
  const nextIdentity = applyIdentityProxyMetadata(identity, initInfo);
210
207
  await fs.writeJson(identityPath, nextIdentity, { spaces: 2 });
211
208
  return { created: true, initInfo: initInfo || null };
@@ -240,22 +237,21 @@ async function createIdentityFile(identityPath, serverUrl, workspacePath) {
240
237
  }
241
238
  if (initInfo && Array.isArray(initInfo.joinedProjectIds)) {
242
239
  identity.joinedProjectIds = initInfo.joinedProjectIds.map((x) => String(x || '').trim()).filter(Boolean);
243
- } else {
244
- delete identity.joinedProjectIds;
245
240
  }
246
241
  if (initInfo && typeof initInfo.currentProjectId === 'string' && initInfo.currentProjectId.trim()) {
247
242
  identity.currentProjectId = String(initInfo.currentProjectId).trim();
248
- } else {
249
- 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;
245
+ }
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 = {};
250
254
  }
251
- identity.projectCursors =
252
- initInfo && initInfo.projectCursors && typeof initInfo.projectCursors === 'object' && !Array.isArray(initInfo.projectCursors)
253
- ? Object.fromEntries(
254
- Object.entries(initInfo.projectCursors)
255
- .map(([k, v]) => [String(k || '').trim(), Number(v || 0)])
256
- .filter(([k, v]) => k && Number.isFinite(v))
257
- )
258
- : {};
259
255
  const nextIdentity = applyIdentityProxyMetadata(identity, initInfo);
260
256
  await fs.writeJson(identityPath, nextIdentity, { spaces: 2 });
261
257
  return { created: true, initInfo: initInfo || null };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-weiyuan-init",
3
- "version": "1.0.127",
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(/\/$/, "")