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
|
@@ -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
|
|
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
|
|
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("
|
|
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/
|
|
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 ?? "
|
|
4327
|
-
|
|
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
|
-
?
|
|
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: "
|
|
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-
|
|
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`
|