@qingchencloud/openclaw-zh 2026.1.29-zh.20260130 → 2026.1.30-zh.1

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.
@@ -70,7 +70,11 @@ function buildProfileHealth(params) {
70
70
  label,
71
71
  };
72
72
  }
73
- const { status, remainingMs } = resolveOAuthStatus(credential.expires, now, warnAfterMs);
73
+ const hasRefreshToken = typeof credential.refresh === "string" && credential.refresh.length > 0;
74
+ const { status: rawStatus, remainingMs } = resolveOAuthStatus(credential.expires, now, warnAfterMs);
75
+ // OAuth credentials with a valid refresh token auto-renew on first API call,
76
+ // so don't warn about access token expiration.
77
+ const status = hasRefreshToken && (rawStatus === "expired" || rawStatus === "expiring") ? "ok" : rawStatus;
74
78
  return {
75
79
  profileId,
76
80
  provider: credential.provider,
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2026.1.29-zh.20260130",
3
- "commit": "da71eaebd2f613f8afaddccdff12cb28c1d7e0f4",
4
- "builtAt": "2026-01-30T13:55:46.616Z"
2
+ "version": "2026.1.30-zh.1",
3
+ "commit": "6522de6ce045e0166d3136880b26004a04e44f91",
4
+ "builtAt": "2026-01-30T18:27:27.253Z"
5
5
  }
@@ -1 +1 @@
1
- 0759910ce289e6f12d0e8c31222f3316d28de774656d770b25b840f52064b597
1
+ 6bca341722b482e79a5e38480c148b710a49dc6632213f89ca397a239fc3d770
@@ -6,23 +6,23 @@ const CLI_NAME = resolveCliName();
6
6
  const EXAMPLES = [
7
7
  [
8
8
  "openclaw channels login --verbose",
9
- "Link personal WhatsApp Web and show QR + connection logs.",
9
+ "关联个人 WhatsApp Web 并显示二维码和连接日志。",
10
10
  ],
11
11
  [
12
12
  'openclaw message send --target +15555550123 --message "Hi" --json',
13
- "Send via your web session and print JSON result.",
13
+ "通过你的 Web 会话发送并打印 JSON 结果。",
14
14
  ],
15
- ["openclaw gateway --port 18789", "Run the WebSocket Gateway locally."],
16
- ["openclaw --dev gateway", "Run a dev Gateway (isolated state/config) on ws://127.0.0.1:19001."],
17
- ["openclaw gateway --force", "Kill anything bound to the default gateway port, then start it."],
18
- ["openclaw gateway ...", "Gateway control via WebSocket."],
15
+ ["openclaw gateway --port 18789", "在本地运行 WebSocket 网关。"],
16
+ ["openclaw --dev gateway", " ws://127.0.0.1:19001 上运行开发网关(隔离状态/配置)。"],
17
+ ["openclaw gateway --force", "终止占用默认网关端口的进程,然后启动网关。"],
18
+ ["openclaw gateway ...", "通过 WebSocket 控制网关。"],
19
19
  [
20
20
  'openclaw agent --to +15555550123 --message "Run summary" --deliver',
21
- "Talk directly to the agent using the Gateway; optionally send the WhatsApp reply.",
21
+ "通过网关直接与 AI 助手对话;可选发送 WhatsApp 回复。",
22
22
  ],
23
23
  [
24
24
  'openclaw message send --channel telegram --target @mychat --message "Hi"',
25
- "Send via your Telegram bot.",
25
+ "通过你的 Telegram 机器人发送。",
26
26
  ],
27
27
  ];
28
28
  export function configureProgramHelp(program, ctx) {
@@ -30,9 +30,9 @@ export function configureProgramHelp(program, ctx) {
30
30
  .name(CLI_NAME)
31
31
  .description("")
32
32
  .version(ctx.programVersion)
33
- .option("--dev", "Dev profile: isolate state under ~/.openclaw-dev, default gateway port 19001, and shift derived ports (browser/canvas)")
34
- .option("--profile <name>", "Use a named profile (isolates OPENCLAW_STATE_DIR/OPENCLAW_CONFIG_PATH under ~/.openclaw-<name>)");
35
- program.option("--no-color", "Disable ANSI colors", false);
33
+ .option("--dev", "开发配置:在 ~/.openclaw-dev 下隔离状态,默认网关端口 19001,并移动派生端口(浏览器/画布)")
34
+ .option("--profile <name>", "使用命名配置文件(在 ~/.openclaw-<name> 下隔离状态和配置)");
35
+ program.option("--no-color", "禁用 ANSI 颜色", false);
36
36
  program.configureHelp({
37
37
  optionTerm: (option) => theme.option(option.flags),
38
38
  subcommandTerm: (cmd) => theme.command(cmd.name()),
@@ -66,6 +66,6 @@ export function configureProgramHelp(program, ctx) {
66
66
  if (command !== program)
67
67
  return "";
68
68
  const docs = formatDocsLink("/cli", "docs.openclaw.ai/cli");
69
- return `\n${theme.heading("Examples:")}\n${fmtExamples}\n\n${theme.muted("Docs:")} ${docs}\n`;
69
+ return `\n${theme.heading("示例:")}\n${fmtExamples}\n\n${theme.muted("文档:")} ${docs}\n${theme.muted("汉化版:")} ${theme.info("https://openclaw.qt.cool/")}\n`;
70
70
  });
71
71
  }
@@ -96,7 +96,7 @@ export function formatSkillsList(report, opts) {
96
96
  columns.push({ key: "Missing", header: "Missing", minWidth: 18, flex: true });
97
97
  }
98
98
  const lines = [];
99
- lines.push(`${theme.heading("Skills")} ${theme.muted(`(${eligible.length}/${skills.length} ready)`)}`);
99
+ lines.push(`${theme.heading("技能")} ${theme.muted(`(${eligible.length}/${skills.length} ready)`)}`);
100
100
  lines.push(renderTable({
101
101
  width: tableWidth,
102
102
  columns,
@@ -132,7 +132,7 @@ export function formatSkillInfo(report, skillName, opts) {
132
132
  lines.push(skill.description);
133
133
  lines.push("");
134
134
  // Details
135
- lines.push(theme.heading("Details:"));
135
+ lines.push(theme.heading("详情:"));
136
136
  lines.push(`${theme.muted(" Source:")} ${skill.source}`);
137
137
  lines.push(`${theme.muted(" Path:")} ${shortenHomePath(skill.filePath)}`);
138
138
  if (skill.homepage) {
@@ -149,7 +149,7 @@ export function formatSkillInfo(report, skillName, opts) {
149
149
  skill.requirements.os.length > 0;
150
150
  if (hasRequirements) {
151
151
  lines.push("");
152
- lines.push(theme.heading("Requirements:"));
152
+ lines.push(theme.heading("依赖条件:"));
153
153
  if (skill.requirements.bins.length > 0) {
154
154
  const binsStatus = skill.requirements.bins.map((bin) => {
155
155
  const missing = skill.missing.bins.includes(bin);
@@ -190,7 +190,7 @@ export function formatSkillInfo(report, skillName, opts) {
190
190
  // Install options
191
191
  if (skill.install.length > 0 && !skill.eligible) {
192
192
  lines.push("");
193
- lines.push(theme.heading("Install options:"));
193
+ lines.push(theme.heading("安装选项:"));
194
194
  for (const inst of skill.install) {
195
195
  lines.push(` ${theme.warn("→")} ${inst.label}`);
196
196
  }
@@ -225,7 +225,7 @@ export function formatSkillsCheck(report, opts) {
225
225
  }, null, 2);
226
226
  }
227
227
  const lines = [];
228
- lines.push(theme.heading("Skills Status Check"));
228
+ lines.push(theme.heading("技能状态检查"));
229
229
  lines.push("");
230
230
  lines.push(`${theme.muted("Total:")} ${report.skills.length}`);
231
231
  lines.push(`${theme.success("✓")} ${theme.muted("Eligible:")} ${eligible.length}`);
@@ -320,7 +320,7 @@ export async function updateStatusCommand(opts) {
320
320
  Value: updateAvailability.available ? theme.warn(`available · ${updateLine}`) : updateLine,
321
321
  },
322
322
  ];
323
- defaultRuntime.log(theme.heading("OpenClaw update status"));
323
+ defaultRuntime.log(theme.heading("OpenClaw 更新状态"));
324
324
  defaultRuntime.log("");
325
325
  defaultRuntime.log(renderTable({
326
326
  width: tableWidth,
@@ -405,7 +405,7 @@ function printResult(result, opts) {
405
405
  }
406
406
  const statusColor = result.status === "ok" ? theme.success : result.status === "skipped" ? theme.warn : theme.error;
407
407
  defaultRuntime.log("");
408
- defaultRuntime.log(`${theme.heading("Update Result:")} ${statusColor(result.status.toUpperCase())}`);
408
+ defaultRuntime.log(`${theme.heading("更新结果:")} ${statusColor(result.status.toUpperCase())}`);
409
409
  if (result.root) {
410
410
  defaultRuntime.log(` Root: ${theme.muted(result.root)}`);
411
411
  }
@@ -422,7 +422,7 @@ function printResult(result, opts) {
422
422
  }
423
423
  if (!opts.hideSteps && result.steps.length > 0) {
424
424
  defaultRuntime.log("");
425
- defaultRuntime.log(theme.heading("Steps:"));
425
+ defaultRuntime.log(theme.heading("步骤:"));
426
426
  for (const step of result.steps) {
427
427
  const status = formatStepStatus(step.exitCode);
428
428
  const duration = theme.muted(`(${formatDuration(step.durationMs)})`);
@@ -543,7 +543,7 @@ export async function updateCommand(opts) {
543
543
  }
544
544
  const showProgress = !opts.json && process.stdout.isTTY;
545
545
  if (!opts.json) {
546
- defaultRuntime.log(theme.heading("Updating OpenClaw..."));
546
+ defaultRuntime.log(theme.heading("正在更新 OpenClaw..."));
547
547
  defaultRuntime.log("");
548
548
  }
549
549
  const { progress, stop } = createUpdateProgress(showProgress);
@@ -685,7 +685,7 @@ export async function updateCommand(opts) {
685
685
  };
686
686
  if (!opts.json) {
687
687
  defaultRuntime.log("");
688
- defaultRuntime.log(theme.heading("Updating plugins..."));
688
+ defaultRuntime.log(theme.heading("正在更新插件..."));
689
689
  }
690
690
  const syncResult = await syncPluginsForUpdateChannel({
691
691
  config: activeConfig,
@@ -750,7 +750,7 @@ export async function updateCommand(opts) {
750
750
  if (shouldRestart) {
751
751
  if (!opts.json) {
752
752
  defaultRuntime.log("");
753
- defaultRuntime.log(theme.heading("Restarting service..."));
753
+ defaultRuntime.log(theme.heading("正在重启服务..."));
754
754
  }
755
755
  try {
756
756
  const { runDaemonRestart } = await import("./daemon-cli.js");
@@ -937,23 +937,23 @@ export function registerUpdateCli(program) {
937
937
  .map(([cmd, desc]) => ` ${theme.command(cmd)} ${theme.muted(`# ${desc}`)}`)
938
938
  .join("\n");
939
939
  return `
940
- ${theme.heading("What this does:")}
940
+ ${theme.heading("此命令功能:")}
941
941
  - Git checkouts: fetches, rebases, installs deps, builds, and runs doctor
942
942
  - npm installs: updates via detected package manager
943
943
 
944
- ${theme.heading("Switch channels:")}
944
+ ${theme.heading("切换更新通道:")}
945
945
  - Use --channel stable|beta|dev to persist the update channel in config
946
946
  - Run openclaw update status to see the active channel and source
947
947
  - Use --tag <dist-tag|version> for a one-off npm update without persisting
948
948
 
949
- ${theme.heading("Non-interactive:")}
949
+ ${theme.heading("非交互模式:")}
950
950
  - Use --yes to accept downgrade prompts
951
951
  - Combine with --channel/--tag/--restart/--json/--timeout as needed
952
952
 
953
- ${theme.heading("Examples:")}
953
+ ${theme.heading("示例:")}
954
954
  ${fmtExamples}
955
955
 
956
- ${theme.heading("Notes:")}
956
+ ${theme.heading("注意事项:")}
957
957
  - Switch channels with --channel stable|beta|dev
958
958
  - For global installs: auto-updates via detected package manager when possible (see docs/install/updating.md)
959
959
  - Downgrades require confirmation (can break configuration)
@@ -996,11 +996,11 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.openclaw.ai/cli/up
996
996
  .description("Show update channel and version status")
997
997
  .option("--json", "Output result as JSON", false)
998
998
  .option("--timeout <seconds>", "Timeout for update checks in seconds (default: 3)")
999
- .addHelpText("after", () => `\n${theme.heading("Examples:")}\n${formatHelpExamples([
999
+ .addHelpText("after", () => `\n${theme.heading("示例:")}\n${formatHelpExamples([
1000
1000
  ["openclaw update status", "Show channel + version status."],
1001
1001
  ["openclaw update status --json", "JSON output."],
1002
1002
  ["openclaw update status --timeout 10", "Custom timeout."],
1003
- ])}\n\n${theme.heading("Notes:")}\n${theme.muted("- Shows current update channel (stable/beta/dev) and source")}\n${theme.muted("- Includes git tag/branch/SHA for source checkouts")}\n\n${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.openclaw.ai/cli/update")}`)
1003
+ ])}\n\n${theme.heading("注意事项:")}\n${theme.muted("- Shows current update channel (stable/beta/dev) and source")}\n${theme.muted("- Includes git tag/branch/SHA for source checkouts")}\n\n${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.openclaw.ai/cli/update")}`)
1004
1004
  .action(async (opts) => {
1005
1005
  try {
1006
1006
  await updateStatusCommand({
@@ -100,7 +100,7 @@ export async function channelsListCommand(opts, runtime = defaultRuntime) {
100
100
  return;
101
101
  }
102
102
  const lines = [];
103
- lines.push(theme.heading("Chat channels:"));
103
+ lines.push(theme.heading("聊天通道:"));
104
104
  for (const plugin of plugins) {
105
105
  const accounts = plugin.config.listAccountIds(cfg);
106
106
  if (!accounts || accounts.length === 0)
@@ -118,7 +118,7 @@ export async function channelsListCommand(opts, runtime = defaultRuntime) {
118
118
  }
119
119
  }
120
120
  lines.push("");
121
- lines.push(theme.heading("Auth providers (OAuth + API keys):"));
121
+ lines.push(theme.heading("认证提供商(OAuth + API 密钥):"));
122
122
  if (authProfiles.length === 0) {
123
123
  lines.push(theme.muted("- none"));
124
124
  }
@@ -46,11 +46,11 @@ export async function noteSecurityWarnings(cfg) {
46
46
  ` Fix: ${formatCliCommand("openclaw doctor --fix")} to generate a token`,
47
47
  ` Or set token directly: ${formatCliCommand("openclaw config set gateway.auth.mode token")}`,
48
48
  ];
49
- warnings.push(`- CRITICAL: Gateway bound to ${bindDescriptor} without authentication.`, ` Anyone on your network (or internet if port-forwarded) can fully control your agent.`, ` Fix: ${formatCliCommand("openclaw config set gateway.bind loopback")}`, ...authFixLines);
49
+ warnings.push(`- 严重警告: 网关绑定到 ${bindDescriptor} 但未设置认证。`, ` 你网络上的任何人(如果做了端口转发则是互联网上的任何人)都可以完全控制你的 AI 助手。`, ` Fix: ${formatCliCommand("openclaw config set gateway.bind loopback")}`, ...authFixLines);
50
50
  }
51
51
  else {
52
52
  // Auth is configured, but still warn about network exposure
53
- warnings.push(`- WARNING: Gateway bound to ${bindDescriptor} (network-accessible).`, ` Ensure your auth credentials are strong and not exposed.`);
53
+ warnings.push(`- WARNING: Gateway bound to ${bindDescriptor} (可被网络访问)。`, ` 请确保你的认证凭据足够强且未被泄露。`);
54
54
  }
55
55
  }
56
56
  const warnDmPolicy = async (params) => {
@@ -73,7 +73,7 @@ export async function noteSecurityWarnings(cfg) {
73
73
  const isMultiUserDm = hasWildcard || allowCount > 1;
74
74
  if (dmPolicy === "open") {
75
75
  const allowFromPath = `${params.allowFromPath}allowFrom`;
76
- warnings.push(`- ${params.label} DMs: OPEN (${policyPath}="open"). Anyone can DM it.`);
76
+ warnings.push(`- ${params.label} DMs: OPEN (${policyPath}="open"). 任何人都可以向它发私信。`);
77
77
  if (!hasWildcard) {
78
78
  warnings.push(`- ${params.label} DMs: config invalid — "open" requires ${allowFromPath} to include "*".`);
79
79
  }
@@ -83,7 +83,7 @@ export async function noteSecurityWarnings(cfg) {
83
83
  return;
84
84
  }
85
85
  if (dmPolicy !== "open" && allowCount === 0) {
86
- warnings.push(`- ${params.label} DMs: locked (${policyPath}="${dmPolicy}") with no allowlist; unknown senders will be blocked / get a pairing code.`);
86
+ warnings.push(`- ${params.label} DMs: locked (${policyPath}="${dmPolicy}") with no allowlist; 未知发送者将被阻止 / get a pairing code.`);
87
87
  warnings.push(` ${params.approveHint}`);
88
88
  }
89
89
  if (dmScope === "main" && isMultiUserDm) {
@@ -135,7 +135,7 @@ export async function noteSecurityWarnings(cfg) {
135
135
  warnings.push(...extra);
136
136
  }
137
137
  }
138
- const lines = warnings.length > 0 ? warnings : ["- No channel security warnings detected."];
138
+ const lines = warnings.length > 0 ? warnings : ["- 未检测到频道安全警告。"];
139
139
  lines.push(auditHint);
140
- note(lines.join("\n"), "Security");
140
+ note(lines.join("\n"), "安全");
141
141
  }
@@ -41,7 +41,7 @@ function resolveMode(cfg) {
41
41
  export async function doctorCommand(runtime = defaultRuntime, options = {}) {
42
42
  const prompter = createDoctorPrompter({ runtime, options });
43
43
  printWizardHeader(runtime);
44
- intro("OpenClaw doctor");
44
+ intro("OpenClaw 诊断");
45
45
  const root = await resolveOpenClawPackageRoot({
46
46
  moduleUrl: import.meta.url,
47
47
  argv1: process.argv[1],
@@ -96,7 +96,7 @@ export async function statusCommand(opts, runtime) {
96
96
  const warn = (value) => (rich ? theme.warn(value) : value);
97
97
  if (opts.verbose) {
98
98
  const details = buildGatewayConnectionDetails();
99
- runtime.log(info("Gateway connection:"));
99
+ runtime.log(info("网关连接:"));
100
100
  for (const line of details.message.split("\n"))
101
101
  runtime.log(` ${line}`);
102
102
  runtime.log("");
@@ -271,9 +271,9 @@ export async function statusCommand(opts, runtime) {
271
271
  Value: `${summary.sessions.count} active · default ${defaults.model ?? "unknown"}${defaultCtx} · ${storeLabel}`,
272
272
  },
273
273
  ];
274
- runtime.log(theme.heading("OpenClaw status"));
274
+ runtime.log(theme.heading("OpenClaw 状态"));
275
275
  runtime.log("");
276
- runtime.log(theme.heading("Overview"));
276
+ runtime.log(theme.heading("概览"));
277
277
  runtime.log(renderTable({
278
278
  width: tableWidth,
279
279
  columns: [
@@ -283,7 +283,7 @@ export async function statusCommand(opts, runtime) {
283
283
  rows: overviewRows,
284
284
  }).trimEnd());
285
285
  runtime.log("");
286
- runtime.log(theme.heading("Security audit"));
286
+ runtime.log(theme.heading("安全审计"));
287
287
  const fmtSummary = (value) => {
288
288
  const parts = [
289
289
  theme.error(`${value.critical} critical`),
@@ -295,7 +295,7 @@ export async function statusCommand(opts, runtime) {
295
295
  runtime.log(theme.muted(`Summary: ${fmtSummary(securityAudit.summary)}`));
296
296
  const importantFindings = securityAudit.findings.filter((f) => f.severity === "critical" || f.severity === "warn");
297
297
  if (importantFindings.length === 0) {
298
- runtime.log(theme.muted("No critical or warn findings detected."));
298
+ runtime.log(theme.muted("未检测到严重或警告级别问题。"));
299
299
  }
300
300
  else {
301
301
  const severityLabel = (sev) => {
@@ -321,7 +321,7 @@ export async function statusCommand(opts, runtime) {
321
321
  runtime.log(theme.muted(`Full report: ${formatCliCommand("openclaw security audit")}`));
322
322
  runtime.log(theme.muted(`Deep probe: ${formatCliCommand("openclaw security audit --deep")}`));
323
323
  runtime.log("");
324
- runtime.log(theme.heading("Channels"));
324
+ runtime.log(theme.heading("通道"));
325
325
  const channelIssuesByChannel = (() => {
326
326
  const map = new Map();
327
327
  for (const issue of channelIssues) {
@@ -363,7 +363,7 @@ export async function statusCommand(opts, runtime) {
363
363
  }),
364
364
  }).trimEnd());
365
365
  runtime.log("");
366
- runtime.log(theme.heading("Sessions"));
366
+ runtime.log(theme.heading("会话"));
367
367
  runtime.log(renderTable({
368
368
  width: tableWidth,
369
369
  columns: [
@@ -393,7 +393,7 @@ export async function statusCommand(opts, runtime) {
393
393
  }).trimEnd());
394
394
  if (summary.queuedSystemEvents.length > 0) {
395
395
  runtime.log("");
396
- runtime.log(theme.heading("System events"));
396
+ runtime.log(theme.heading("系统事件"));
397
397
  runtime.log(renderTable({
398
398
  width: tableWidth,
399
399
  columns: [{ key: "Event", header: "Event", flex: true, minWidth: 24 }],
@@ -407,7 +407,7 @@ export async function statusCommand(opts, runtime) {
407
407
  }
408
408
  if (health) {
409
409
  runtime.log("");
410
- runtime.log(theme.heading("Health"));
410
+ runtime.log(theme.heading("健康状态"));
411
411
  const rows = [];
412
412
  rows.push({
413
413
  Item: "Gateway",
@@ -450,7 +450,7 @@ export async function statusCommand(opts, runtime) {
450
450
  }
451
451
  if (usage) {
452
452
  runtime.log("");
453
- runtime.log(theme.heading("Usage"));
453
+ runtime.log(theme.heading("用量统计"));
454
454
  for (const line of formatUsageReportLines(usage)) {
455
455
  runtime.log(line);
456
456
  }
@@ -25,7 +25,7 @@ function buildScopeSelection(opts) {
25
25
  }
26
26
  async function stopAndUninstallService(runtime) {
27
27
  if (isNixMode) {
28
- runtime.error("Nix mode detected; service uninstall is disabled.");
28
+ runtime.error("检测到 Nix 模式;服务卸载已禁用。");
29
29
  return false;
30
30
  }
31
31
  const service = resolveGatewayService();
@@ -68,13 +68,13 @@ export async function uninstallCommand(runtime, opts) {
68
68
  const { scopes, hadExplicit } = buildScopeSelection(opts);
69
69
  const interactive = !opts.nonInteractive;
70
70
  if (!interactive && !opts.yes) {
71
- runtime.error("Non-interactive mode requires --yes.");
71
+ runtime.error("非交互模式需要 --yes 参数。");
72
72
  runtime.exit(1);
73
73
  return;
74
74
  }
75
75
  if (!hadExplicit) {
76
76
  if (!interactive) {
77
- runtime.error("Non-interactive mode requires explicit scopes (use --all).");
77
+ runtime.error("非交互模式需要明确指定范围(使用 --all)。");
78
78
  runtime.exit(1);
79
79
  return;
80
80
  }
@@ -105,7 +105,7 @@ export async function uninstallCommand(runtime, opts) {
105
105
  scopes.add(value);
106
106
  }
107
107
  if (scopes.size === 0) {
108
- runtime.log("Nothing selected.");
108
+ runtime.log("未选择任何内容。");
109
109
  return;
110
110
  }
111
111
  if (interactive && !opts.yes) {
@@ -151,11 +151,11 @@ export async function uninstallCommand(runtime, opts) {
151
151
  if (scopes.has("app")) {
152
152
  await removeMacApp(runtime, dryRun);
153
153
  }
154
- runtime.log("CLI still installed. Remove via npm/pnpm if desired.");
154
+ runtime.log("CLI 仍已安装。如需删除请使用 npm/pnpm");
155
155
  if (scopes.has("state") && !scopes.has("workspace")) {
156
156
  const home = resolveHomeDir();
157
157
  if (home && workspaceDirs.some((dir) => dir.startsWith(path.resolve(home)))) {
158
- runtime.log("Tip: workspaces were preserved. Re-run with --workspace to remove them.");
158
+ runtime.log("提示:工作区已保留。如需删除请加 --workspace 重新运行。");
159
159
  }
160
160
  }
161
161
  }