openclaw-weiyuan-init 1.0.115 → 1.0.116

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/identity.js CHANGED
@@ -50,7 +50,7 @@ function normalizeBusinessServerUrl(serverUrl) {
50
50
  try {
51
51
  const url = new URL(String(serverUrl).trim());
52
52
  const rawPath = String(url.pathname || '/');
53
- if (/^\/(?:api\/)?agent-register(?:\/|$)/.test(rawPath)) {
53
+ if (/^\/(?:api\/)?agent-(?:register|bind)(?:\/|$)/.test(rawPath)) {
54
54
  url.pathname = '/api';
55
55
  } else if (!rawPath || rawPath === '/') {
56
56
  url.pathname = '/api';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-weiyuan-init",
3
- "version": "1.0.115",
3
+ "version": "1.0.116",
4
4
  "description": "OpenClaw Weiyuan Skill 一键初始化工具",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -4,7 +4,7 @@ import { createInterface } from "node:readline/promises"
4
4
  import { stdin as input, stdout as output } from "node:process"
5
5
  import { spawnSync } from "node:child_process"
6
6
  import type { WeiyuanIdentityFileV1 } from "./types"
7
- import { DEFAULT_IDENTITY_PATH, normalizeServerBaseUrl, readIdentity, writeIdentity } from "./weiyuanFile"
7
+ import { DEFAULT_IDENTITY_PATH, healIdentityServerBaseUrl, normalizeServerBaseUrl, readIdentity, writeIdentity } from "./weiyuanFile"
8
8
  import { sha256Hex } from "./crypto"
9
9
  import { signedFetch, signedRequest } from "./http"
10
10
  import { bodyHashBase64, canonicalRequest, newKeyPair, signEd25519Base64 } from "./signing"
@@ -1203,6 +1203,41 @@ async function fetchOptionalJson(url: string): Promise<Record<string, unknown> |
1203
1203
  }
1204
1204
  }
1205
1205
 
1206
+ async function reportAgentRuntimeVersion(options: {
1207
+ apiBaseUrl: string
1208
+ identity: WeiyuanIdentityFileV1
1209
+ skillVersion?: string
1210
+ targetAccountId?: string
1211
+ }): Promise<Record<string, unknown> | null> {
1212
+ const apiBaseUrl = normalizeServerBaseUrl(String(options.apiBaseUrl || "").trim())
1213
+ const skillVersion = String(options.skillVersion || "").trim().replace(/^v/i, "")
1214
+ const lobsterId = String(options.identity?.lobsterId || "").trim()
1215
+ const identityHash = String(options.identity?.identityHash || "").trim()
1216
+ const targetAccountId = String(options.targetAccountId || lobsterId).trim()
1217
+ if (!apiBaseUrl || !lobsterId || !identityHash) return null
1218
+ try {
1219
+ const res = await fetch(`${apiBaseUrl}/agent/version/report`, {
1220
+ method: "POST",
1221
+ headers: { "content-type": "application/json" },
1222
+ body: JSON.stringify({
1223
+ lobsterId,
1224
+ identityHash,
1225
+ skillVersion,
1226
+ targetAccountId,
1227
+ }),
1228
+ })
1229
+ const text = await res.text()
1230
+ const parsed = text.trim() ? (JSON.parse(text) as any) : {}
1231
+ if (!res.ok) throw new Error(String(parsed?.msg || parsed?.message || `http_${res.status}`))
1232
+ return parsed?.data && typeof parsed.data === "object" ? parsed.data : parsed
1233
+ } catch (error) {
1234
+ return {
1235
+ ok: false,
1236
+ reportError: String((error as Error)?.message ?? error ?? "version_report_failed"),
1237
+ }
1238
+ }
1239
+ }
1240
+
1206
1241
  async function downloadBinaryFile(url: string, outPath: string, errorPrefix: string): Promise<void> {
1207
1242
  let res: Response
1208
1243
  try {
@@ -2909,14 +2944,14 @@ function printCommandHelp(command: string): boolean {
2909
2944
  command: "member",
2910
2945
  usage: [
2911
2946
  "member list --project <projectId>",
2912
- "member add-web --project <projectId> --name <显示名称>",
2947
+ "member add --project <projectId> --name <显示名称>",
2913
2948
  "member remove --project <projectId> --target <lobsterId> --reason <原因> [--confirm1 同意 --confirm2 同意]",
2914
2949
  "member leave --project <projectId> --reason <原因> [--confirm1 同意 --confirm2 同意]",
2915
2950
  "member profile-edit --project <projectId> [--nickname <项目昵称>] [--roleTitle <角色>] [--specialties <A,B>] [--taskPreferenceTags <X,Y>] [--syncAll]",
2916
2951
  "member profile-global-edit --project <projectId> [--nickname <全局昵称>] [--roleTitle <角色>] [--specialties <A,B>] [--taskPreferenceTags <X,Y>]",
2917
2952
  ],
2918
2953
  examples: [
2919
- "npm run weiyuan -- member add-web --project <projectId> --name 设计同学A",
2954
+ "npm run weiyuan -- member add --project <projectId> --name 设计同学A",
2920
2955
  "npm run weiyuan -- member profile-edit --project <projectId> --nickname 小李 --roleTitle 研发",
2921
2956
  "npm run weiyuan -- member-profile-edit --project <projectId> --specialties 前端,交互 --taskPreferenceTags 重构,性能 --syncAll",
2922
2957
  "npm run weiyuan -- member profile-global-edit --project <projectId> --nickname 全局小李 --roleTitle 项目经理",
@@ -3573,6 +3608,7 @@ async function cmdRuntimeUpgrade(args: Argv): Promise<void> {
3573
3608
  const upgradeBaseUrl = inferUpgradeBaseUrl(apiBaseUrl, optString(args.flags, "upgrade"))
3574
3609
  const upgradeRules = buildUpgradeRules(upgradeBaseUrl)
3575
3610
  const currentVersion = await readLocalRuntimeVersion(weiyuanPath)
3611
+ const targetAccountId = optString(args.flags, "target-account-id") ?? optString(args.flags, "target") ?? identity.lobsterId
3576
3612
  const latestVersion = await fetchRequiredText(upgradeRules.latestVersionUrl, "upgrade_latest_version_unavailable")
3577
3613
  const releaseNotes = await fetchOptionalJson(upgradeRules.releaseNotesUrl)
3578
3614
  const currentReady = await fs
@@ -3581,6 +3617,12 @@ async function cmdRuntimeUpgrade(args: Argv): Promise<void> {
3581
3617
  .catch(() => false)
3582
3618
  if (currentReady && currentVersion === latestVersion && !asBoolFlag(args.flags, "force", false)) {
3583
3619
  const persisted = await persistLocalUpgradeArtifacts(weiyuanPath, latestVersion, releaseNotes)
3620
+ const reportResult = await reportAgentRuntimeVersion({
3621
+ apiBaseUrl,
3622
+ identity,
3623
+ skillVersion: latestVersion,
3624
+ targetAccountId,
3625
+ })
3584
3626
  print({
3585
3627
  ok: true,
3586
3628
  action: "runtime_upgrade",
@@ -3590,6 +3632,8 @@ async function cmdRuntimeUpgrade(args: Argv): Promise<void> {
3590
3632
  currentVersion,
3591
3633
  latestVersion,
3592
3634
  apiBaseUrl,
3635
+ targetAccountId,
3636
+ versionReport: reportResult,
3593
3637
  ...upgradeRules,
3594
3638
  ...persisted,
3595
3639
  })
@@ -3609,6 +3653,13 @@ async function cmdRuntimeUpgrade(args: Argv): Promise<void> {
3609
3653
  }
3610
3654
  runProcessOrThrow(process.platform === "win32" ? "npm.cmd" : "npm", ["--prefix", weiyuanPath, "install"], workspacePath, "runtime_upgrade_install_failed")
3611
3655
  const persisted = await persistLocalUpgradeArtifacts(weiyuanPath, latestVersion, releaseNotes)
3656
+ const refreshedIdentity = await readIdentity(filePath)
3657
+ const reportResult = await reportAgentRuntimeVersion({
3658
+ apiBaseUrl,
3659
+ identity: refreshedIdentity,
3660
+ skillVersion: latestVersion,
3661
+ targetAccountId,
3662
+ })
3612
3663
  print({
3613
3664
  ok: true,
3614
3665
  action: "runtime_upgrade",
@@ -3617,6 +3668,8 @@ async function cmdRuntimeUpgrade(args: Argv): Promise<void> {
3617
3668
  currentVersionBefore: currentVersion ?? null,
3618
3669
  latestVersion,
3619
3670
  apiBaseUrl,
3671
+ targetAccountId,
3672
+ versionReport: reportResult,
3620
3673
  ...upgradeRules,
3621
3674
  ...persisted,
3622
3675
  })
@@ -4297,15 +4350,15 @@ async function cmdMemberAddWeb(args: Argv): Promise<void> {
4297
4350
  const projectId = resolveProjectId(args.flags, identity)
4298
4351
  let name = optString(args.flags, "name") ?? optString(args.flags, "displayName") ?? optString(args.flags, "nickname")
4299
4352
  if (!name && canAskInteractively()) {
4300
- name = await askRequired("请填写网页成员显示名称:")
4353
+ name = await askRequired("请填写普通成员显示名称:")
4301
4354
  }
4302
4355
  const displayName = String(name ?? "").trim()
4303
- if (!displayName) throw new Error("web_member_name_required")
4356
+ if (!displayName) throw new Error("member_name_required")
4304
4357
  const capabilityToken = await issueCapabilityToken(identity, CAPABILITY_ACTION.MEMBER_ADD, { projectId }, { ttlSec: 120, maxRequests: 2, windowSec: 60 })
4305
4358
  const { status, json } = await signedRequest({
4306
4359
  serverBaseUrl: identity.serverBaseUrl,
4307
4360
  method: "POST",
4308
- pathWithQuery: `/v1/projects/${projectId}/members/web`,
4361
+ pathWithQuery: `/v1/projects/${projectId}/members/manual`,
4309
4362
  lobsterId: identity.lobsterId,
4310
4363
  secretKeyBase64: identity.secretKeyBase64,
4311
4364
  capabilityToken,
@@ -4323,15 +4376,15 @@ async function cmdMemberAddWeb(args: Argv): Promise<void> {
4323
4376
  lobsterId: member.lobsterId,
4324
4377
  displayName: member.displayName ?? displayName,
4325
4378
  role: member.role ?? "member",
4326
- memberType: member.memberType ?? "web",
4327
- isWeb: true,
4379
+ memberType: member.memberType ?? "member",
4380
+ isManualMember: true,
4328
4381
  },
4329
4382
  panelUrl,
4330
4383
  projectPanelLink: panelUrl,
4331
4384
  linkSummary: formatLinkSummary(panelUrl, undefined),
4332
4385
  message: panelUrl
4333
- ? `网页成员已添加。请直接转发以下看板链接给该成员:\n${panelUrl}`
4334
- : "网页成员已添加,项目看板将自动同步显示。",
4386
+ ? `普通成员已添加。请直接转发以下看板链接给该成员:\n${panelUrl}`
4387
+ : "普通成员已添加,项目看板将自动同步显示。",
4335
4388
  })
4336
4389
  }
4337
4390
 
@@ -5438,7 +5491,7 @@ function getPanelCliModules(): Array<{ name: string; actions: Array<{ action: st
5438
5491
  name: "成员",
5439
5492
  actions: [
5440
5493
  { action: "查看成员列表", command: "member list --project <projectId>" },
5441
- { action: "添加网页成员", command: "member add-web --project <projectId> --name <显示名称>" },
5494
+ { action: "添加成员", command: "member add --project <projectId> --name <显示名称>" },
5442
5495
  { action: "移除成员", command: "member remove --project <projectId> --target <lobsterId> --reason <原因>" },
5443
5496
  ],
5444
5497
  },
@@ -6597,6 +6650,10 @@ export async function runCli(argv: string[]): Promise<void> {
6597
6650
  const wantsHelp = Boolean(args.flags.help || args.flags.h || cmd === "help")
6598
6651
  const helpTarget = cmd === "help" ? sub : cmd
6599
6652
  if (wantsHelp && helpTarget && printCommandHelp(helpTarget)) return
6653
+ if (cmd && cmd !== "init" && cmd !== "help") {
6654
+ const identityPath = optString(args.flags, "identity") ?? DEFAULT_IDENTITY_PATH
6655
+ await healIdentityServerBaseUrl(identityPath)
6656
+ }
6600
6657
  if (!wantsHelp && cmd && optString(args.flags, "project")) {
6601
6658
  args = await normalizeProjectFlagForExecution(args)
6602
6659
  }
@@ -6689,7 +6746,7 @@ export async function runCli(argv: string[]): Promise<void> {
6689
6746
  if (cmd === "sync-reopen") return await cmdSyncReopen(args)
6690
6747
  if (cmd === "member") {
6691
6748
  if (sub === "list") return await cmdMemberList(args)
6692
- if (sub === "add-web" || sub === "add_web" || sub === "add") return await cmdMemberAddWeb(args)
6749
+ if (sub === "add" || sub === "add-member" || sub === "add_member" || sub === "add-web" || sub === "add_web") return await cmdMemberAddWeb(args)
6693
6750
  if (sub === "profile-edit") return await cmdMemberProfileEdit(args)
6694
6751
  if (sub === "profile-global-set") return await cmdMemberProfileGlobalSet(args)
6695
6752
  if (sub === "profile-global-edit") return await cmdMemberProfileGlobalEdit(args)
@@ -20,7 +20,7 @@ export function normalizeServerBaseUrl(raw: string): string {
20
20
  if (host === "api.magon.com.cn") {
21
21
  url.protocol = "https:"
22
22
  const rawPath = String(url.pathname || "/")
23
- if (/^\/(?:api\/)?agent-register(?:\/|$)/.test(rawPath)) {
23
+ if (/^\/(?:api\/)?agent-(?:register|bind)(?:\/|$)/.test(rawPath)) {
24
24
  url.pathname = "/api"
25
25
  } else {
26
26
  if (!url.pathname || url.pathname === "/") url.pathname = "/api"
@@ -29,7 +29,7 @@ export function normalizeServerBaseUrl(raw: string): string {
29
29
  url.hash = ""
30
30
  return url.toString().replace(/\/$/, "")
31
31
  }
32
- if (/^\/(?:api\/)?agent-register(?:\/|$)/.test(String(url.pathname || "/"))) {
32
+ if (/^\/(?:api\/)?agent-(?:register|bind)(?:\/|$)/.test(String(url.pathname || "/"))) {
33
33
  url.pathname = "/api"
34
34
  }
35
35
  url.hash = ""
@@ -55,6 +55,22 @@ export async function readIdentity(filePath: string): Promise<WeiyuanIdentityFil
55
55
  return parsed
56
56
  }
57
57
 
58
+ export async function healIdentityServerBaseUrl(filePath: string): Promise<boolean> {
59
+ try {
60
+ const raw = await fs.readFile(filePath, "utf8")
61
+ const parsed = JSON.parse(raw) as WeiyuanIdentityFileV1
62
+ if (!parsed || parsed.version !== 1) return false
63
+ const before = String(parsed.serverBaseUrl || "")
64
+ const normalized = normalizeServerBaseUrl(before)
65
+ if (!normalized || normalized === before) return false
66
+ parsed.serverBaseUrl = normalized
67
+ await writeIdentity(filePath, parsed)
68
+ return true
69
+ } catch {
70
+ return false
71
+ }
72
+ }
73
+
58
74
  export async function writeIdentity(filePath: string, data: WeiyuanIdentityFileV1): Promise<void> {
59
75
  await fs.mkdir(path.dirname(path.resolve(filePath)), { recursive: true })
60
76
  const tmp = `${filePath}.tmp`