@xdxer/dingtalk-agent 0.1.5-beta.5 → 0.1.5-beta.6

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.
@@ -39,7 +39,9 @@ import { inspectMulticaWorkspace, listMulticaWorkspaceResources, planMulticaWork
39
39
  import { applyMulticaDeployment, listMulticaDeployments, planMulticaDeployment, runMulticaWorkspaceIssue, statusMulticaDeployment, statusMulticaWorkspaceRun, } from '../src/multica-deploy.js';
40
40
  import { applyObservation, applyPromotion, listPromotions, planObservation, planPromotion, statusPromotion, } from '../src/promotion.js';
41
41
  import { setup } from '../src/setup.js';
42
- import { upgradeAgent } from '../src/upgrade.js';
42
+ import { checkUpgrade, upgradeAgent } from '../src/upgrade.js';
43
+ // out/err 在本文件里改名导入:printX 的形参普遍叫 out,直接同名会被遮蔽。
44
+ import { configureTui, confirm, displayWidth, padRight, renderPairs, StepReporter, err as stderrUi, out as stdoutUi, } from '../src/tui.js';
43
45
  import { checkpointTask, showTaskCheckpoint } from '../src/memory/task-checkpoints.js';
44
46
  import { upsertOperationalMemory } from '../src/memory/operational.js';
45
47
  import { proposeMemoryCandidate, publishMemoryCandidate, reviewMemoryCandidate, showMemoryCandidate, } from '../src/memory/candidates.js';
@@ -183,13 +185,100 @@ dingtalk-agent 已验版本晋级与反馈候选
183
185
  Promotion 只接受指定 suite 的 load/hard/surface gate 与精确 W2 evidence hash,并委托 W4 deploy。
184
186
  Observe 只写 gitignored、proposed、不可直接发布的 Eval candidate;不修改 AGENTS.md、Prompt、Skill 或 Trigger。
185
187
  `;
188
+ const UPGRADE_HELP = `
189
+ dta upgrade —— 自升级 CLI,再重新检查完整环境
190
+
191
+ 用法:
192
+ dta upgrade 升级到当前通道的最新版本
193
+ dta upgrade --check 只查有没有新版本,不安装
194
+ dta upgrade --dry-run 只预览将执行的命令,不安装
195
+ dta upgrade --channel beta 指定通道(beta | latest)
196
+ dta upgrade --version <x.y.z> 升级到指定版本
197
+ dta upgrade --version <x.y.z> --force 允许降级(两者必须同时给)
198
+ dta upgrade --yes 跳过确认提示(AI Agent 模式)
199
+ dta upgrade --json 机器通道;输出 upgrade@1,不打任何进度
200
+
201
+ 参数:
202
+ --check 只解析升级目标并对比当前版本
203
+ --channel <name> beta 或 latest;不给时按当前版本是否带 - 推断
204
+ --version <ver> 精确版本;与 --channel 互斥
205
+ --prefix <dir> 安装前缀,默认 ~/.local
206
+ --dry-run 不安装,只回报将执行的 install/verify 命令
207
+ --force 强制重装当前版本;配合 --version 才允许降级
208
+ --yes 跳过确认;非交互环境本来就不提示
209
+ --json 输出 JSON,不混入任何日志
210
+ --no-color 关闭颜色(也支持 NO_COLOR 环境变量)
211
+
212
+ 升级过程分 7 步:冻结 Skill 版本 → 解析目标 → 检查版本关系 → 安装
213
+ → 定位新 CLI → 校验版本 → 复核环境。前 3 步失败不会改动机器;从第 4 步
214
+ (安装)起失败可能留下已更新但未复核的 CLI,此时按提示重跑 setup 或
215
+ 用 --version <旧版本> --force 回退。
216
+
217
+ 非交互环境(管道 / CI / Agent 调用)不提示确认,直接执行。
218
+ 颜色只在终端里出现;管道里想要颜色需显式 --color。
219
+ `;
220
+ /**
221
+ * 帮助文本的打印时装饰。**不把 ANSI 写进常量**——常量一旦带色就没法降级,
222
+ * 而这里 color=false 时原样返回,NO_COLOR / 管道下与改造前逐字节相同。
223
+ *
224
+ * 只染整段连续短语:命令名从行首吃到两个以上空格为止,所以
225
+ * `dta setup`、`dta skill status` 这类断言目标始终完整。行数不变。
226
+ */
227
+ function renderHelp(text) {
228
+ const { ctx, theme } = stdoutUi();
229
+ if (!ctx.color)
230
+ return text;
231
+ return text.split('\n').map((line, index) => {
232
+ if (index === 1 && line.trim())
233
+ return theme.bold(line);
234
+ if (/^\S.*[::]$/.test(line))
235
+ return theme.bold(line);
236
+ if (/^\s+·\s/.test(line))
237
+ return theme.dim(line);
238
+ const command = line.match(/^(\s+)((?:dta|dingtalk-agent)\s\S.*?)(\s{2,})(.*)$/);
239
+ if (command)
240
+ return `${command[1]}${theme.noun(command[2])}${command[3]}${theme.dim(command[4])}`;
241
+ return line;
242
+ }).join('\n');
243
+ }
186
244
  function fail(msg, code = 1, hint = '') {
187
- console.error(`错误: ${msg}`);
245
+ // 整行染色,绝不做 danger('错误') + ': ' + msg 这种切分——
246
+ // 契约 eval 断言的是 stderr.includes('错误:'),切开就再也匹配不上。
247
+ const { theme } = stderrUi();
248
+ console.error(theme.danger(`错误: ${msg}`));
188
249
  if (hint)
189
- console.error(`提示: ${hint}`);
250
+ console.error(theme.dim(`提示: ${hint}`));
190
251
  process.exit(code);
191
252
  }
192
- const argv = process.argv.slice(2);
253
+ // --color / --no-color 在 dispatch 前预剥:parseArgs 是 strict 模式,
254
+ // 想让它成为全局参数就得改 23 个 options 块,预剥只需要这一处。
255
+ //
256
+ // 三条边界:`--` 之后的 token 是 positional,一律不碰;非法取值报错而不是
257
+ // 静默吞掉;同一参数出现多次以最后一次为准(与 parseArgs 的口径一致)。
258
+ const rawArgv = process.argv.slice(2);
259
+ const COLOR_VALUES = new Set(['auto', 'always', 'never']);
260
+ const terminator = rawArgv.indexOf('--');
261
+ const scannable = terminator === -1 ? rawArgv : rawArgv.slice(0, terminator);
262
+ let colorFlag = 'auto';
263
+ for (const item of scannable) {
264
+ if (item === '--no-color')
265
+ colorFlag = 'never';
266
+ else if (item === '--color')
267
+ colorFlag = 'always';
268
+ else if (item.startsWith('--color=')) {
269
+ const value = item.slice('--color='.length);
270
+ if (!COLOR_VALUES.has(value)) {
271
+ console.error(`错误: --color 只接受 auto | always | never,收到 ${JSON.stringify(value)}`);
272
+ process.exit(1);
273
+ }
274
+ colorFlag = value;
275
+ }
276
+ }
277
+ configureTui(colorFlag);
278
+ const isColorToken = (item) => item === '--color' || item === '--no-color' || item.startsWith('--color=');
279
+ const argv = terminator === -1
280
+ ? rawArgv.filter((item) => !isColorToken(item))
281
+ : [...rawArgv.slice(0, terminator).filter((item) => !isColorToken(item)), ...rawArgv.slice(terminator)];
193
282
  const cmd = argv[0];
194
283
  const sub = argv[1];
195
284
  try {
@@ -202,38 +291,38 @@ catch (e) {
202
291
  }
203
292
  async function main() {
204
293
  if (cmd === 'help' && sub === 'runtime') {
205
- console.log(RUNTIME_HELP);
294
+ console.log(renderHelp(RUNTIME_HELP));
206
295
  return;
207
296
  }
208
297
  if (cmd === 'help' && sub === 'adapters') {
209
- console.log(ADAPTER_HELP);
298
+ console.log(renderHelp(ADAPTER_HELP));
210
299
  return;
211
300
  }
212
301
  if (cmd === 'help' && sub === 'lab') {
213
- console.log(LAB_HELP);
302
+ console.log(renderHelp(LAB_HELP));
214
303
  return;
215
304
  }
216
305
  if (cmd === 'help' && sub === 'agent') {
217
- console.log(AGENT_HELP);
306
+ console.log(renderHelp(AGENT_HELP));
218
307
  return;
219
308
  }
220
309
  if (cmd === 'help' && sub === 'workspace') {
221
- console.log(WORKSPACE_HELP);
310
+ console.log(renderHelp(WORKSPACE_HELP));
222
311
  return;
223
312
  }
224
313
  if (cmd === 'help' && sub === 'deploy') {
225
- console.log(DEPLOY_HELP);
314
+ console.log(renderHelp(DEPLOY_HELP));
226
315
  return;
227
316
  }
228
317
  if (cmd === 'help' && ['promote', 'observe'].includes(sub || '')) {
229
- console.log(PROMOTION_HELP);
318
+ console.log(renderHelp(PROMOTION_HELP));
230
319
  return;
231
320
  }
232
321
  if (cmd === 'help' && sub) {
233
322
  fail(`不认识的帮助主题: ${sub}`, 1, '运行 dta --help 回到产品入口;事件宿主可用 dta help runtime。');
234
323
  }
235
324
  if (!cmd || cmd === '--help' || cmd === '-h' || cmd === 'help') {
236
- console.log(HELP);
325
+ console.log(renderHelp(HELP));
237
326
  return;
238
327
  }
239
328
  if (cmd === '--version' || cmd === '-V' || cmd === 'version') {
@@ -437,23 +526,23 @@ async function main() {
437
526
  return;
438
527
  }
439
528
  if (out.count === 0) {
440
- console.log('本 Project 未声明任何常驻节律(schedules)。');
529
+ console.log(muted('本 Project 未声明任何常驻节律(schedules)。'));
441
530
  return;
442
531
  }
443
- console.log(`声明的常驻节律(internalized cron) · ${out.count} 条`);
532
+ console.log(`${strong('声明的常驻节律(internalized cron)')} · ${out.count} 条`);
444
533
  for (const s of out.schedules) {
445
- console.log(`\n ${s.name} ${s.cron} ${s.timezone} [${s.mode}]`);
534
+ console.log(`\n ${noun(s.name)} ${s.cron} ${s.timezone} ${muted(`[${s.mode}]`)}`);
446
535
  if (s.wake)
447
- console.log(` 唤醒 ${s.wake}`);
536
+ console.log(muted(` 唤醒 ${s.wake}`));
448
537
  if (s.completion)
449
- console.log(` ②判据 ${s.completion}`);
538
+ console.log(muted(` ②判据 ${s.completion}`));
450
539
  }
451
540
  if (!out.minutesDistinct) {
452
- console.log(`\n⚠️ 分钟位冲突: ${out.collidingMinutes.join(', ')} —— 外发类同分钟并发会重复送,请错开`);
541
+ console.log(`\n${mark('warn', `⚠️ 分钟位冲突: ${out.collidingMinutes.join(', ')} —— 外发类同分钟并发会重复送,请错开`)}`);
453
542
  process.exitCode = 2;
454
543
  }
455
544
  else {
456
- console.log('\n✓ 各节律分钟位互不相同(外发防重复的静态前提满足)');
545
+ console.log(`\n${mark('pass', '✓ 各节律分钟位互不相同(外发防重复的静态前提满足)')}`);
457
546
  }
458
547
  return;
459
548
  }
@@ -467,17 +556,17 @@ async function main() {
467
556
  console.log(JSON.stringify(plan, null, 2));
468
557
  return;
469
558
  }
470
- console.log(`schedule 部署计划 · workspace=${plan.workspace} · provider=${plan.provider}`);
559
+ console.log(`${strong('schedule 部署计划')} · workspace=${noun(plan.workspace)} · provider=${plan.provider}`);
471
560
  if (!plan.supported) {
472
- console.log(`\n 不支持: ${plan.reason}`);
473
- console.log(` ${plan.reconcile}`);
561
+ console.log(`\n${mark('fail', `✗ 不支持: ${plan.reason}`)}`);
562
+ console.log(` ${noun(plan.reconcile)}`);
474
563
  process.exitCode = 2;
475
564
  return;
476
565
  }
477
566
  console.log(` ${plan.count} 条声明 → provider ops:\n`);
478
567
  for (const s of plan.schedules)
479
- console.log(` # ${s.name}\n ${s.applyCommand}\n`);
480
- console.log(`执行: ${plan.reconcile}`);
568
+ console.log(` ${muted(`# ${s.name}`)}\n ${noun(s.applyCommand)}\n`);
569
+ console.log(`执行: ${noun(plan.reconcile)}`);
481
570
  return;
482
571
  }
483
572
  fail(`可用: dta schedule show | plan --workspace <name>${suggest(sub || '', ['show', 'plan'], 'dta schedule')}`);
@@ -670,7 +759,7 @@ async function main() {
670
759
  if (o.json)
671
760
  console.log(JSON.stringify(out, null, 2));
672
761
  else
673
- console.log(`✅ current workspace: ${out.previous || '-'} → ${out.current}`);
762
+ console.log(`${mark('pass', '✅')} current workspace: ${muted(out.previous || '-')} → ${noun(out.current)}`);
674
763
  return;
675
764
  }
676
765
  if (sub === 'run') {
@@ -716,19 +805,19 @@ async function main() {
716
805
  if (o.json)
717
806
  console.log(JSON.stringify(out, null, 2));
718
807
  else if (out.$schema === 'dingtalk-agent/opencode-workspace-run-plan@1') {
719
- console.log(`DRY-RUN workspace=${out.workspace} model=${out.model} prompt=${out.promptHash}`);
808
+ console.log(`${mark('muted', 'DRY-RUN')} workspace=${noun(out.workspace)} model=${out.model} prompt=${out.promptHash}`);
720
809
  }
721
810
  else if (out.$schema === 'dingtalk-agent/multica-workspace-run-plan@1') {
722
- console.log(`DRY-RUN workspace=${out.workspace} agent=${out.agentId || '-'} prompt=${out.promptHash}`);
811
+ console.log(`${mark('muted', 'DRY-RUN')} workspace=${noun(out.workspace)} agent=${out.agentId || '-'} prompt=${out.promptHash}`);
723
812
  }
724
813
  else {
725
- console.log(`${out.passed ? '✅' : '❌'} workspace run ${out.runId}`);
814
+ console.log(`${mark(levelOf(Boolean(out.passed)), out.passed ? '✅' : '❌')} workspace run ${noun(out.runId)}`);
726
815
  if ('execution' in out && out.execution?.answer)
727
816
  console.log(out.execution.answer);
728
817
  if ('answer' in out && out.answer)
729
818
  console.log(out.answer);
730
819
  if (out.evidencePath)
731
- console.log(`evidence=${out.evidencePath}`);
820
+ console.log(`evidence=${noun(out.evidencePath)}`);
732
821
  }
733
822
  if (o.execute && !out.passed)
734
823
  process.exitCode = 2;
@@ -797,23 +886,72 @@ async function main() {
797
886
  return;
798
887
  }
799
888
  if (cmd === 'upgrade') {
889
+ // parseArgs strict 模式会把 --help 当成未知参数抛掉,必须先拦。
890
+ if (argv.includes('--help') || argv.includes('-h')) {
891
+ console.log(renderHelp(UPGRADE_HELP));
892
+ return;
893
+ }
800
894
  const { values: o } = parseArgs({
801
895
  args: argv.slice(1),
802
896
  options: {
803
897
  channel: { type: 'string' }, version: { type: 'string' }, prefix: { type: 'string' },
804
898
  'dry-run': { type: 'boolean' }, force: { type: 'boolean' }, json: { type: 'boolean' },
899
+ check: { type: 'boolean' }, yes: { type: 'boolean' },
805
900
  },
806
901
  });
807
- const out = upgradeAgent(PACKAGE_ROOT, {
808
- channel: o.channel,
809
- version: o.version, prefix: o.prefix,
902
+ const channel = o.channel;
903
+ const json = Boolean(o.json);
904
+ if (o.check) {
905
+ if (o['dry-run'] || o.force || o.prefix || o.yes) {
906
+ fail('upgrade --check 只接受 --channel / --version / --json');
907
+ }
908
+ const checked = checkUpgrade(PACKAGE_ROOT, { channel, version: o.version });
909
+ if (json)
910
+ console.log(JSON.stringify(checked, null, 2));
911
+ else
912
+ printUpgradeCheck(checked);
913
+ return;
914
+ }
915
+ // --json 是机器通道:结构性绕开 tui,连回调都不构造。
916
+ // 非交互(管道/CI/Agent)也不提示,保持"敲下去就装"的既有行为。
917
+ const interactive = !json && Boolean(process.stdin.isTTY);
918
+ let known = null;
919
+ if (interactive) {
920
+ known = checkUpgrade(PACKAGE_ROOT, { channel, version: o.version });
921
+ printUpgradePreamble(known, { dryRun: Boolean(o['dry-run']), force: Boolean(o.force) });
922
+ const proceed = await confirm(o['dry-run'] ? '是否预览升级?' : '是否升级?', { yes: Boolean(o.yes), fallback: true });
923
+ if (!proceed) {
924
+ console.error(stderrUi().theme.dim(' 已取消'));
925
+ return;
926
+ }
927
+ }
928
+ const reporter = json ? null : new StepReporter({ total: o['dry-run'] ? 3 : 7 });
929
+ const result = upgradeAgent(PACKAGE_ROOT, {
930
+ channel, version: o.version, prefix: o.prefix,
810
931
  dryRun: o['dry-run'], force: o.force,
932
+ // 已经解析过就别再问一次 registry;**同时把安装源钉死到精确版本**——
933
+ // 只冻结期望版本而仍按 `pkg@latest` 安装,会在用户思考的这几秒里
934
+ // 被移动的 tag 装进另一个版本,然后按旧期望校验失败,而机器已经改了。
935
+ env: known
936
+ ? {
937
+ DTA_UPGRADE_TARGET_VERSION: known.targetVersion,
938
+ DTA_UPGRADE_PACKAGE_SOURCE: known.pinnedSource,
939
+ }
940
+ : undefined,
941
+ onEvent: reporter
942
+ ? (event) => {
943
+ if (event.phase === 'begin')
944
+ reporter.begin(event.label);
945
+ else
946
+ reporter.end(event.ok !== false, event.meta || '');
947
+ }
948
+ : undefined,
811
949
  });
812
- if (o.json)
813
- console.log(JSON.stringify(out, null, 2));
950
+ if (json)
951
+ console.log(JSON.stringify(result, null, 2));
814
952
  else
815
- printUpgrade(out);
816
- if (!out.dryRun && !out.ready)
953
+ printUpgrade(result);
954
+ if (!result.dryRun && !result.ready)
817
955
  process.exitCode = 2;
818
956
  return;
819
957
  }
@@ -913,7 +1051,7 @@ async function main() {
913
1051
  if (o.json)
914
1052
  console.log(JSON.stringify({ ...out, endpoint, readiness, targets, doc }, null, 2));
915
1053
  else {
916
- console.log(`✅ 工作区已归属 ${out.definition?.label}(写入 ${out.written})`);
1054
+ console.log(`${mark('pass', '✅')} 工作区已归属 ${strong(out.definition?.label)}(写入 ${noun(out.written)})`);
917
1055
  for (const install of out.skillInstalls)
918
1056
  printSkillStatus(install, 'install', false);
919
1057
  if (!out.skillInstalls.length) {
@@ -953,14 +1091,14 @@ async function main() {
953
1091
  if (o.json)
954
1092
  console.log(JSON.stringify(out, null, 2));
955
1093
  else {
956
- console.log(`✅ ${out.mode === 'workspace' ? '已装载 Workspace' : '直接会话模式'}`);
1094
+ console.log(`${mark('pass', '✅')} ${strong(out.mode === 'workspace' ? '已装载 Workspace' : '直接会话模式')}`);
957
1095
  console.log(` scope=${out.scopeId} initialized=${out.initialized}`);
958
1096
  console.log(` agent=${out.definition.id} definition=${out.definition.status}`);
959
1097
  if (!out.mounts.length)
960
- console.log(' 没有发现持久上下文;这不是错误,也不需要自动 init。');
1098
+ console.log(muted(' 没有发现持久上下文;这不是错误,也不需要自动 init。'));
961
1099
  for (const mount of out.mounts)
962
- console.log(` ${mount.slot}: ${mount.path}`);
963
- console.log(` ${out.note}`);
1100
+ console.log(` ${mount.slot}: ${noun(mount.path)}`);
1101
+ console.log(` ${muted(out.note)}`);
964
1102
  }
965
1103
  return;
966
1104
  }
@@ -1346,9 +1484,9 @@ async function main() {
1346
1484
  if (o.json)
1347
1485
  console.log(JSON.stringify(out, null, 2));
1348
1486
  else if (!out.found)
1349
- console.log('当前 Session 尚无 Task checkpoint。');
1487
+ console.log(muted('当前 Session 尚无 Task checkpoint。'));
1350
1488
  else {
1351
- console.log(`✅ Task ${out.checkpoint.taskId} · ${out.checkpoint.status}`);
1489
+ console.log(`${mark('pass', '✅')} Task ${noun(out.checkpoint.taskId)} · ${out.checkpoint.status}`);
1352
1490
  console.log(` revision=${out.checkpoint.revision} hash=${out.hash}`);
1353
1491
  console.log(` next=${out.checkpoint.nextAction || '-'}`);
1354
1492
  }
@@ -1373,7 +1511,7 @@ async function main() {
1373
1511
  if (o.json || !o.live)
1374
1512
  console.log(JSON.stringify(out, null, 2));
1375
1513
  else {
1376
- console.log(`${out.verified ? '✅' : '⚠️'} Operational Memory · ${out.mode}`);
1514
+ console.log(`${mark(out.verified ? 'pass' : 'warn', out.verified ? '✅' : '⚠️')} ${strong('Operational Memory')} · ${out.mode}`);
1377
1515
  console.log(` record=${out.recordId || '-'} verification=${out.verification}`);
1378
1516
  }
1379
1517
  if (out.mode === 'uncertain')
@@ -1427,12 +1565,12 @@ async function main() {
1427
1565
  if (o.json)
1428
1566
  console.log(JSON.stringify(out, null, 2));
1429
1567
  else if (action === 'publish') {
1430
- console.log(`${out.verified ? '✅' : out.mode === 'dry-run' ? '🔎' : '⚠️'} Candidate ${o.id}`);
1568
+ console.log(`${mark(out.verified ? 'pass' : out.mode === 'dry-run' ? 'muted' : 'warn', out.verified ? '✅' : out.mode === 'dry-run' ? '🔎' : '⚠️')} Candidate ${noun(o.id)}`);
1431
1569
  console.log(` mode=${out.mode} targetHash=${out.currentTargetHash}`);
1432
1570
  }
1433
1571
  else {
1434
- console.log(`✅ Candidate ${out.candidate.id} · ${out.candidate.status}`);
1435
- console.log(` revision=${out.candidate.revision} path=${out.path}`);
1572
+ console.log(`${mark('pass', '✅')} Candidate ${noun(out.candidate.id)} · ${out.candidate.status}`);
1573
+ console.log(` revision=${out.candidate.revision} path=${noun(out.path)}`);
1436
1574
  }
1437
1575
  if (action === 'publish' && out.mode === 'uncertain')
1438
1576
  process.exitCode = 2;
@@ -1463,10 +1601,10 @@ async function main() {
1463
1601
  if (o.json || o['dry-run'])
1464
1602
  console.log(JSON.stringify(out, null, 2));
1465
1603
  else {
1466
- console.log(`${out.verified ? '✅' : '⚠️'} ${out.kind} · ${out.outcome} · ${out.toState}`);
1467
- console.log(` action=${out.actionId} run=${out.runId}`);
1604
+ console.log(`${mark(out.verified ? 'pass' : 'warn', out.verified ? '✅' : '⚠️')} ${strong(out.kind)} · ${out.outcome} · ${out.toState}`);
1605
+ console.log(` action=${noun(out.actionId)} run=${noun(out.runId)}`);
1468
1606
  if (!out.verified)
1469
- console.log(` ${out.verification}`);
1607
+ console.log(` ${muted(out.verification)}`);
1470
1608
  }
1471
1609
  if (out.outcome === 'uncertain')
1472
1610
  process.exitCode = 2;
@@ -1538,11 +1676,41 @@ function editDistance(a, b) {
1538
1676
  }
1539
1677
  return row[b.length];
1540
1678
  }
1679
+ /** 按语义给状态标记上色;字形原样返回,不做任何替换。 */
1680
+ function mark(level, text) {
1681
+ const { theme } = stdoutUi();
1682
+ return level === 'pass' ? theme.success(text)
1683
+ : level === 'warn' ? theme.warn(text)
1684
+ : level === 'fail' ? theme.danger(text)
1685
+ : theme.dim(text);
1686
+ }
1687
+ /** 可复制的名词:路径、版本号、ID、命令。 */
1688
+ function noun(text) {
1689
+ return stdoutUi().theme.noun(text);
1690
+ }
1691
+ /** 次要信息:补充说明、括注、下一步提示。 */
1692
+ function muted(text) {
1693
+ return stdoutUi().theme.dim(text);
1694
+ }
1695
+ /** 标题行 / key=value 的结构性强调。 */
1696
+ function strong(text) {
1697
+ return stdoutUi().theme.bold(text);
1698
+ }
1699
+ /** ready 布尔 → 语义级别,printX 里到处都是这个三态。 */
1700
+ function levelOf(state) {
1701
+ if (state === true)
1702
+ return 'pass';
1703
+ if (state === false)
1704
+ return 'fail';
1705
+ return state;
1706
+ }
1541
1707
  function printDispatch(out, json = false) {
1542
1708
  if (json)
1543
1709
  return console.log(JSON.stringify(out, null, 2));
1544
- const mark = out.duplicate ? (out.launch ? '🔁 REDELIVER' : '↩️ DUPLICATE') : '✅ READY';
1545
- console.log(`${mark} ${out.runId}`);
1710
+ const state = out.duplicate
1711
+ ? mark(out.launch ? 'warn' : 'muted', out.launch ? '🔁 REDELIVER' : '↩️ DUPLICATE')
1712
+ : mark('pass', '✅ READY');
1713
+ console.log(`${state} ${noun(out.runId)}`);
1546
1714
  console.log(` Field=${out.fieldId} Session=${out.sessionId} Event=${out.eventKind}`);
1547
1715
  console.log(` cwd=${out.cwd}`);
1548
1716
  console.log(` entrypoint=${out.entrypoint} queue=${out.queue.key} (max=${out.queue.maxConcurrency})`);
@@ -1552,7 +1720,7 @@ function printDispatch(out, json = false) {
1552
1720
  }
1553
1721
  function printLab(out) {
1554
1722
  const passed = out.ready ?? out.passed ?? out.assertions?.passed;
1555
- console.log(`${passed === false ? '❌' : '✅'} ${out.$schema || 'dingtalk-agent/lab'}`);
1723
+ console.log(`${mark(levelOf(passed !== false), passed === false ? '❌' : '✅')} ${out.$schema || 'dingtalk-agent/lab'}`);
1556
1724
  if (out.mode)
1557
1725
  console.log(` mode=${out.mode}`);
1558
1726
  if (out.marker)
@@ -1561,17 +1729,17 @@ function printLab(out) {
1561
1729
  console.log(` evidence=${out.evidencePath}`);
1562
1730
  if (Array.isArray(out.checks)) {
1563
1731
  for (const check of out.checks) {
1564
- console.log(` ${check.passed ? 'PASS' : 'FAIL'} ${check.id}: ${check.detail}`);
1732
+ console.log(` ${mark(levelOf(Boolean(check.passed)), check.passed ? 'PASS' : 'FAIL')} ${check.id}: ${check.detail}`);
1565
1733
  }
1566
1734
  }
1567
1735
  }
1568
1736
  function printAgentAudit(out) {
1569
- console.log(`dingtalk-agent agent audit · ${out.ready ? 'READY' : 'PARTIAL'}`);
1737
+ console.log(`${strong('dingtalk-agent agent audit')} · ${mark(out.ready ? 'pass' : 'warn', out.ready ? 'READY' : 'PARTIAL')}`);
1570
1738
  console.log(` definition=${out.definition.hash} storage=${out.storageMode}`);
1571
1739
  console.log(` dingtalkSideEffect=${out.dingtalkSideEffect} sideEffect=${out.sideEffect}`);
1572
1740
  for (const check of out.checks) {
1573
- const mark = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1574
- console.log(` ${mark} ${check.id}: ${check.summary}`);
1741
+ const word = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1742
+ console.log(` ${mark(levelOf(check.level), word)} ${check.id}: ${check.summary}`);
1575
1743
  }
1576
1744
  if (out.repairs.length) {
1577
1745
  console.log('\n修复建议:');
@@ -1584,7 +1752,7 @@ function printAgentAudit(out) {
1584
1752
  }
1585
1753
  function printAgentEnhance(out) {
1586
1754
  if (out.$schema === 'dingtalk-agent/agent-enhancement-plan@1') {
1587
- console.log(`dingtalk-agent agent enhance · ${out.ready ? 'READY PLAN' : 'BLOCKED'}`);
1755
+ console.log(`${strong('dingtalk-agent agent enhance')} · ${mark(out.ready ? 'pass' : 'fail', out.ready ? 'READY PLAN' : 'BLOCKED')}`);
1588
1756
  console.log(` planId=${out.planId} project=${out.projectName}`);
1589
1757
  console.log(` sideEffect=${out.sideEffect} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1590
1758
  for (const operation of out.operations) {
@@ -1594,12 +1762,12 @@ function printAgentEnhance(out) {
1594
1762
  console.log(` REVIEW ${out.semanticReview.files.join(', ')}: ${out.semanticReview.why}`);
1595
1763
  }
1596
1764
  for (const blocker of out.blockers)
1597
- console.log(` BLOCK ${blocker}`);
1765
+ console.log(` ${mark('fail', 'BLOCK')} ${blocker}`);
1598
1766
  if (out.ready)
1599
1767
  console.log(`\nApply:\n ${out.apply.command}`);
1600
1768
  return;
1601
1769
  }
1602
- console.log('dingtalk-agent agent enhance · APPLIED');
1770
+ console.log(`${strong('dingtalk-agent agent enhance')} · ${mark('pass', 'APPLIED')}`);
1603
1771
  console.log(` operation=${out.operationId} planId=${out.planId}`);
1604
1772
  console.log(` changes=${out.changes.length} idempotent=${out.idempotent}`);
1605
1773
  if (out.backupRoot)
@@ -1607,8 +1775,8 @@ function printAgentEnhance(out) {
1607
1775
  console.log(` audit=${out.audit.status} missing=${out.audit.missing.join(', ') || '-'}`);
1608
1776
  }
1609
1777
  function printAgentPlatform(platform) {
1610
- console.log(`${platform.status === 'supported' ? '✅' : '⏳'} ${platform.name} · ${platform.label} · ${platformStatusLabel(platform.status)}`);
1611
- console.log(` ${platform.description}`);
1778
+ console.log(`${mark(platform.status === 'supported' ? 'pass' : 'muted', platform.status === 'supported' ? '✅' : '⏳')} ${strong(platform.name)} · ${platform.label} · ${platformStatusLabel(platform.status)}`);
1779
+ console.log(` ${muted(platform.description)}`);
1612
1780
  for (const skill of platform.skills)
1613
1781
  console.log(` 技能[${skill.role}] ${skill.name} —— ${skill.purpose}`);
1614
1782
  if (platform.commands.length)
@@ -1616,12 +1784,12 @@ function printAgentPlatform(platform) {
1616
1784
  }
1617
1785
  function printAgentPlatformResolution(out) {
1618
1786
  if (!out.platform) {
1619
- console.log('⚠️ 当前工作区未声明 managed agent platform');
1787
+ console.log(mark('warn', '⚠️ 当前工作区未声明 managed agent platform'));
1620
1788
  console.log(' 运行 `dta agent-platform use multica-dingtalk`,或设置 DTA_AGENT_PLATFORM 环境变量。');
1621
1789
  return;
1622
1790
  }
1623
1791
  const known = out.definition;
1624
- console.log(`${known ? '✅' : '❌'} 当前 platform: ${out.platform}${known ? ` · ${known.label} · ${platformStatusLabel(known.status)}` : '(未知)'}`);
1792
+ console.log(`${mark(levelOf(Boolean(known)), known ? '✅' : '❌')} 当前 platform: ${strong(out.platform)}${known ? ` · ${known.label} · ${platformStatusLabel(known.status)}` : '(未知)'}`);
1625
1793
  console.log(` 来源: ${out.source}${out.file ? ` · ${out.file}` : ''}`);
1626
1794
  for (const skill of known?.skills || [])
1627
1795
  console.log(` 技能[${skill.role}] ${skill.name} —— ${skill.purpose}`);
@@ -1629,8 +1797,9 @@ function printAgentPlatformResolution(out) {
1629
1797
  // 披露:dta 层平台命令关联到平台内确切的 Skill(诊断信息走 stderr,不污染 --json stdout)。
1630
1798
  function disclosePlatformSkill(resolution, role) {
1631
1799
  const skillName = resolution.definition ? platformSkillForRole(resolution.definition.name, role) : null;
1632
- if (skillName)
1633
- console.error(`提示: 平台 ${resolution.definition.name} 的该命令方法学由 Skill ${skillName} 承载`);
1800
+ if (skillName) {
1801
+ console.error(stderrUi().theme.dim(`提示: 平台 ${resolution.definition.name} 的该命令方法学由 Skill ${skillName} 承载`));
1802
+ }
1634
1803
  }
1635
1804
  function printEndpoint(endpoint) {
1636
1805
  if (!endpoint)
@@ -1644,9 +1813,9 @@ function printEndpoint(endpoint) {
1644
1813
  console.log(` Endpoint: 未解析——设 ${endpoint.envVar} 或登录 multica 后生效`);
1645
1814
  return;
1646
1815
  }
1647
- const mark = endpoint.confirmed ? '✅' : '⚠️';
1816
+ const glyph = mark(endpoint.confirmed ? 'pass' : 'warn', endpoint.confirmed ? '✅' : '⚠️');
1648
1817
  const note = endpoint.confirmed ? '' : '(建议/未确认,deploy 前需显式确认是预发还是生产)';
1649
- console.log(` ${mark} Endpoint: ${endpoint.endpoint} · 来源: ${endpoint.source}${note}`);
1818
+ console.log(` ${glyph} Endpoint: ${noun(endpoint.endpoint)} · 来源: ${endpoint.source}${muted(note)}`);
1650
1819
  console.log(` (切换:设 ${endpoint.envVar}=<url>、写 dingtalk-agent.json#multicaEndpoint、或登录对应 profile;无需改代码)`);
1651
1820
  }
1652
1821
  function printPlatformDoc(platformName) {
@@ -1654,27 +1823,27 @@ function printPlatformDoc(platformName) {
1654
1823
  return;
1655
1824
  const path = platformDocPath(PACKAGE_ROOT, platformName);
1656
1825
  if (path)
1657
- console.log(` 平台说明: ${path}\n (切换到该平台后请阅读,了解各技能用途与交付链)`);
1826
+ console.log(` 平台说明: ${noun(path)}\n${muted(' (切换到该平台后请阅读,了解各技能用途与交付链)')}`);
1658
1827
  }
1659
1828
  function printMulticaTargets(targets) {
1660
1829
  if (!targets.length)
1661
1830
  return;
1662
- console.log(' 本机 Multica 登录目标(发布前必须与用户确认 endpoint 与 workspace):');
1831
+ console.log(strong(' 本机 Multica 登录目标(发布前必须与用户确认 endpoint 与 workspace):'));
1663
1832
  for (const target of targets) {
1664
1833
  console.log(` - profile=${target.profile} · ${target.serverUrl}${target.workspaceId ? ` · workspace=${target.workspaceId}` : ''}`);
1665
1834
  }
1666
1835
  }
1667
1836
  function printAgentPlatformReadiness(checks) {
1668
1837
  for (const check of checks) {
1669
- console.log(` ${check.ok ? '✅' : '⚠️'} ${check.summary}`);
1838
+ console.log(` ${mark(check.ok ? 'pass' : 'warn', check.ok ? '✅' : '⚠️')} ${check.summary}`);
1670
1839
  if (check.hint)
1671
- console.log(` ${check.hint}`);
1840
+ console.log(` ${muted(check.hint)}`);
1672
1841
  }
1673
1842
  }
1674
1843
  function printSkillStatus(out, action, dryRun) {
1675
- const prefix = dryRun ? 'DRY-RUN' : '✅';
1844
+ const prefix = dryRun ? mark('muted', 'DRY-RUN') : mark('pass', '✅');
1676
1845
  const verb = action === 'status' ? '全局 Skill 状态' : `skill ${action}`;
1677
- console.log(`${prefix} ${verb}: ${out.name}`);
1846
+ console.log(`${prefix} ${verb}: ${strong(out.name)}`);
1678
1847
  console.log(` manager=${out.manager} bundled=${out.bundled.skillVersion || '-'}`);
1679
1848
  console.log(` canonical=${out.canonical.path}`);
1680
1849
  console.log(` installed=${out.canonical.exists} ` +
@@ -1685,71 +1854,64 @@ function printSkillStatus(out, action, dryRun) {
1685
1854
  ` → ${out.operation.after.installedVersion}(${out.operation.after.state})`);
1686
1855
  }
1687
1856
  if (out.operation)
1688
- console.log(` delegated: ${out.operation.command}`);
1857
+ console.log(` delegated: ${noun(out.operation.command)}`);
1689
1858
  for (const client of out.clients) {
1690
- console.log(` ${client.label}=${client.state} (${client.discovery}: ${client.path})`);
1859
+ console.log(` ${client.label}=${mark(client.state === 'ok' ? 'pass' : 'warn', client.state)} (${client.discovery}: ${noun(client.path)})`);
1691
1860
  }
1692
1861
  if (action === 'install' && !dryRun) {
1693
- console.log(' 新 Agent 会话将自动发现;当前会话未发现时请重启 Claude Code/Codex。');
1862
+ console.log(muted(' 新 Agent 会话将自动发现;当前会话未发现时请重启 Claude Code/Codex。'));
1694
1863
  }
1695
1864
  }
1696
1865
  function printDoctor(out) {
1697
- console.log(`dingtalk-agent doctor · ${out.ready ? 'READY' : 'NOT READY'}`);
1866
+ console.log(`${strong('dingtalk-agent doctor')} · ${mark(out.ready ? 'pass' : 'fail', out.ready ? 'READY' : 'NOT READY')}`);
1698
1867
  for (const check of out.checks) {
1699
- const mark = check.level === 'pass' ? '✅' : check.level === 'warn' ? '⚠️' : '❌';
1700
- console.log(`${mark} ${check.summary}`);
1868
+ const glyph = check.level === 'pass' ? '✅' : check.level === 'warn' ? '⚠️' : '❌';
1869
+ console.log(`${mark(levelOf(check.level), glyph)} ${check.summary}`);
1701
1870
  if (check.detail)
1702
- console.log(` ${check.detail}`);
1871
+ console.log(` ${muted(check.detail)}`);
1703
1872
  if (check.fix)
1704
- console.log(` 修复: ${check.fix}`);
1873
+ console.log(` 修复: ${noun(check.fix)}`);
1705
1874
  }
1706
1875
  if (out.hosts.length) {
1707
1876
  // Host 面回答"本地能在哪跑",不改变上面的 ready 结论。
1708
- console.log('\n本机 Coding Agent:');
1877
+ console.log(`\n${strong('本机 Coding Agent:')}`);
1709
1878
  const width = Math.max(...out.hosts.map((host) => displayWidth(host.label)));
1710
1879
  for (const host of out.hosts) {
1711
1880
  const label = host.label + ' '.repeat(width - displayWidth(host.label));
1712
1881
  const where = host.cli.found
1713
1882
  ? [host.cli.path, host.cli.version].filter(Boolean).join(' ')
1714
1883
  : `未找到 ${host.cli.command}`;
1715
- console.log(` ${host.cli.found ? '✅' : '❌'} ${label} ${where}`);
1716
- console.log(` Skill 可见性: ${host.skillExposure.exists ? '已暴露' : '未暴露'} · ${host.skillExposureRoot}`);
1884
+ console.log(` ${mark(levelOf(host.cli.found), host.cli.found ? '✅' : '❌')} ${label} ${noun(where)}`);
1885
+ console.log(muted(` Skill 可见性: ${host.skillExposure.exists ? '已暴露' : '未暴露'} · ${host.skillExposureRoot}`));
1717
1886
  }
1718
1887
  }
1719
1888
  if (out.nextSteps.length) {
1720
- console.log('\n下一步:');
1889
+ console.log(`\n${strong('下一步:')}`);
1721
1890
  for (const step of out.nextSteps)
1722
- console.log(` ${step}`);
1891
+ console.log(` ${noun(step)}`);
1723
1892
  }
1724
1893
  }
1725
- /** 全角字符按两列计宽,避免中英混排的 Host 列表错位。 */
1726
- function displayWidth(text) {
1727
- let width = 0;
1728
- for (const char of text)
1729
- width += /[ᄀ-ᅟ⺀-꓏가-힣豈-﫿︰-﹯＀-⦆¢-₩]/.test(char) ? 2 : 1;
1730
- return width;
1731
- }
1732
1894
  function printProjectInfo(out) {
1733
- console.log(`dingtalk-agent Project · ${out.project.name}`);
1895
+ console.log(`${strong('dingtalk-agent Project')} · ${noun(out.project.name)}`);
1734
1896
  console.log(` root=${out.root}`);
1735
1897
  console.log(` source=${out.source} manifest=${out.manifest || '(synthetic legacy)'}`);
1736
1898
  console.log(` hash=${out.manifestHash} dta=${out.project.dtaVersion}`);
1737
1899
  console.log(` current=${out.currentWorkspace || '(not selected)'}`);
1738
1900
  for (const workspace of out.workspaces) {
1739
- console.log(` ${workspace.current ? '*' : '-'} ${workspace.name} · ${workspace.provider.kind} · ${workspace.status}`);
1901
+ console.log(` ${workspace.current ? strong('*') : muted('-')} ${workspace.name} · ${workspace.provider.kind} · ${workspace.status}`);
1740
1902
  }
1741
1903
  }
1742
1904
  function printWorkspaceList(out) {
1743
- console.log(`dingtalk-agent workspaces · ${out.project.name}`);
1905
+ console.log(`${strong('dingtalk-agent workspaces')} · ${noun(out.project.name)}`);
1744
1906
  if (!out.workspaces.length)
1745
- console.log(' 尚未声明 Development Workspace。');
1907
+ console.log(muted(' 尚未声明 Development Workspace。'));
1746
1908
  for (const workspace of out.workspaces) {
1747
- console.log(` ${workspace.current ? '*' : '-'} ${workspace.name} provider=${workspace.provider.kind} ` +
1909
+ console.log(` ${workspace.current ? strong('*') : muted('-')} ${workspace.name} provider=${workspace.provider.kind} ` +
1748
1910
  `stage=${workspace.stage} status=${workspace.status}`);
1749
1911
  }
1750
1912
  }
1751
1913
  function printDevelopmentWorkspace(out) {
1752
- console.log(`dingtalk-agent workspace · ${out.name}`);
1914
+ console.log(`${strong('dingtalk-agent workspace')} · ${noun(out.name)}`);
1753
1915
  console.log(` provider=${out.provider.kind} stage=${out.stage} status=${out.status}`);
1754
1916
  console.log(` desired=${out.desiredHash} observed=${out.observedHash || '-'}`);
1755
1917
  console.log(` current=${out.current} legacy=${out.legacy}`);
@@ -1759,19 +1921,22 @@ function printDevelopmentWorkspace(out) {
1759
1921
  console.log(` source=${source}`);
1760
1922
  }
1761
1923
  function printDevelopmentWorkspaceDoctor(out) {
1762
- console.log(`dingtalk-agent workspace doctor · ${out.workspace} · ${out.ready ? 'READY' : 'PARTIAL'}`);
1924
+ console.log(`${strong('dingtalk-agent workspace doctor')} · ${noun(out.workspace)} · ${mark(out.ready ? 'pass' : 'warn', out.ready ? 'READY' : 'PARTIAL')}`);
1763
1925
  console.log(` provider=${out.provider} status=${out.status}`);
1764
1926
  console.log(` sideEffect=${out.sideEffect} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1765
1927
  for (const check of out.checks) {
1766
- const mark = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1767
- console.log(` ${mark} ${check.id}: ${check.summary}`);
1928
+ const word = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1929
+ console.log(` ${mark(levelOf(check.level), word)} ${check.id}: ${check.summary}`);
1768
1930
  if (check.fix && check.level !== 'pass')
1769
- console.log(` fix: ${check.fix}`);
1931
+ console.log(` fix: ${noun(check.fix)}`);
1770
1932
  }
1771
1933
  }
1772
1934
  function printOpenCodeWorkspaceOperation(out) {
1773
1935
  const applied = out.$schema === 'dingtalk-agent/opencode-workspace-apply@1';
1774
- console.log(`${applied ? out.applied ? '✅' : '↩️' : 'DRY-RUN'} OpenCode Workspace ${out.workspace}`);
1936
+ const glyph = applied
1937
+ ? mark(out.applied ? 'pass' : 'muted', out.applied ? '✅' : '↩️')
1938
+ : mark('muted', 'DRY-RUN');
1939
+ console.log(`${glyph} OpenCode Workspace ${noun(out.workspace)}`);
1775
1940
  console.log(` action=${out.action} model=${out.model}`);
1776
1941
  console.log(` desired=${out.desiredHash} observed=${out.observedHash || '-'}`);
1777
1942
  console.log(` managed=${out.managedPath}`);
@@ -1781,7 +1946,7 @@ function printOpenCodeWorkspaceOperation(out) {
1781
1946
  function printMulticaWorkspaceOperation(out) {
1782
1947
  const passed = out.passed ?? out.readyForApply ?? out.blocking?.length === 0;
1783
1948
  const mode = out.remoteRead ? 'REMOTE-READ' : 'DRY-RUN';
1784
- console.log(`${passed ? '✅' : '⚠️'} ${mode} Multica Workspace ${out.workspace}`);
1949
+ console.log(`${mark(passed ? 'pass' : 'warn', passed ? '✅' : '⚠️')} ${mode} Multica Workspace ${noun(out.workspace)}`);
1785
1950
  console.log(` schema=${out.$schema} profile=${out.profile || '-'}`);
1786
1951
  if (out.planId)
1787
1952
  console.log(` plan=${out.planId}`);
@@ -1802,7 +1967,7 @@ function printMulticaWorkspaceOperation(out) {
1802
1967
  console.log(` remoteWrite=${out.remoteWrite} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1803
1968
  }
1804
1969
  function printMulticaDeployment(out) {
1805
- console.log(`Multica deploy: ${out.workspace || '<unknown>'}`);
1970
+ console.log(`${strong('Multica deploy')}: ${noun(out.workspace || '<unknown>')}`);
1806
1971
  if (out.planId)
1807
1972
  console.log(` plan: ${out.planId}`);
1808
1973
  if (out.operationId)
@@ -1825,7 +1990,7 @@ function printMulticaDeployment(out) {
1825
1990
  console.log(' triggers: unchanged');
1826
1991
  }
1827
1992
  function printPromotion(out) {
1828
- console.log(`Promotion: ${out.promotionId || out.candidateId || out.candidate?.candidateId || '<none>'}`);
1993
+ console.log(`${strong('Promotion')}: ${noun(out.promotionId || out.candidateId || out.candidate?.candidateId || '<none>')}`);
1829
1994
  if (out.planId)
1830
1995
  console.log(` plan: ${out.planId}`);
1831
1996
  if (out.routeId)
@@ -1876,33 +2041,84 @@ function rejectWorkspaceOptions(values, allowed, command) {
1876
2041
  fail(`${command} 不接受参数: ${extras.join(', ')}`);
1877
2042
  }
1878
2043
  function printSetup(out) {
1879
- console.log(`${out.dryRun ? 'DRY-RUN' : '✅'} dingtalk-agent setup`);
1880
- console.log(` CLI: ${out.cli.executable}`);
1881
- console.log(` 短命令: ${out.cli.alias}`);
1882
- console.log(` Skill: ${out.skill.canonical.path}`);
2044
+ console.log(`${out.dryRun ? mark('muted', 'DRY-RUN') : mark('pass', '✅')} ${strong('dingtalk-agent setup')}`);
2045
+ console.log(` CLI: ${noun(out.cli.executable)}`);
2046
+ console.log(` 短命令: ${noun(out.cli.alias)}`);
2047
+ console.log(` Skill: ${noun(out.skill.canonical.path)}`);
1883
2048
  if (!out.shell.pathReady) {
1884
- console.log(` 当前 shell 尚未加载 PATH;本次终端执行: ${out.shell.activateCommand}`);
2049
+ console.log(` 当前 shell 尚未加载 PATH;本次终端执行: ${noun(out.shell.activateCommand)}`);
1885
2050
  if (out.shell.rcFile)
1886
- console.log(` 新终端会从 ${out.shell.rcFile} 自动加载`);
2051
+ console.log(muted(` 新终端会从 ${out.shell.rcFile} 自动加载`));
1887
2052
  }
1888
2053
  printDoctor(out.doctor);
1889
- console.log(`\n开始使用: ${out.nextCommand}`);
2054
+ console.log(`\n开始使用: ${noun(out.nextCommand)}`);
2055
+ }
2056
+ /**
2057
+ * 确认之前的抬头:告诉人「将要去哪」,好让 [y/N] 是个有信息的决定。
2058
+ *
2059
+ * 三态必须分开说。只判 outdated 会让 `--version <旧版> --force` 显示成
2060
+ * "已是最新版本",用户确认之后却真的降级——在唯一的不可逆动作前给了反的信息。
2061
+ */
2062
+ function printUpgradePreamble(checked, options) {
2063
+ const { theme } = stderrUi();
2064
+ const arrow = (from, to, paint) => `${theme.dim(from)} ${theme.bold('→')} ${paint(to)}`;
2065
+ if (checked.relation === 'same' && !options.force && !options.dryRun) {
2066
+ console.error(` ${theme.success('✔')} 已是最新版本 ${theme.bold(checked.currentVersion)}`);
2067
+ console.error(theme.dim(' 仍会重新校验环境;只想查版本可用 dta upgrade --check'));
2068
+ return;
2069
+ }
2070
+ const label = checked.relation === 'upgrade' ? '新版本可用'
2071
+ : checked.relation === 'downgrade' ? '降级' : '重装';
2072
+ const value = checked.relation === 'upgrade'
2073
+ ? arrow(checked.currentVersion, checked.targetVersion, theme.success)
2074
+ : checked.relation === 'downgrade'
2075
+ ? `${arrow(checked.currentVersion, checked.targetVersion, theme.warn)}${theme.warn('(降级)')}`
2076
+ : `${theme.bold(checked.targetVersion)}${theme.dim('(与当前版本相同,将强制重装)')}`;
2077
+ for (const line of renderPairs([
2078
+ [label, value],
2079
+ ['通道', `${checked.channel} ${theme.dim(checked.pinnedSource)}`],
2080
+ ]))
2081
+ console.error(line);
2082
+ console.error('');
2083
+ }
2084
+ function printUpgradeCheck(checked) {
2085
+ const { theme } = stdoutUi();
2086
+ const glyph = checked.relation === 'upgrade' ? theme.warn('⬆️')
2087
+ : checked.relation === 'downgrade' ? theme.warn('⬇️') : theme.success('✅');
2088
+ const summary = checked.relation === 'upgrade'
2089
+ ? `${theme.dim(checked.currentVersion)} → ${theme.success(checked.targetVersion)}`
2090
+ : checked.relation === 'downgrade'
2091
+ ? `${theme.dim(checked.currentVersion)} → ${theme.warn(checked.targetVersion)}(目标更旧)`
2092
+ : `${theme.bold(checked.currentVersion)}(已是最新)`;
2093
+ console.log(`${glyph} dta upgrade --check: ${summary}`);
2094
+ console.log(` target=${theme.noun(checked.pinnedSource)} channel=${checked.channel}`);
2095
+ if (checked.relation === 'upgrade')
2096
+ console.log(` ${theme.dim('运行 dta upgrade 执行升级')}`);
2097
+ if (checked.relation === 'downgrade') {
2098
+ console.log(` ${theme.dim(`降级需显式确认: dta upgrade --version ${checked.targetVersion} --force`)}`);
2099
+ }
1890
2100
  }
1891
2101
  function printUpgrade(out) {
1892
- const mark = out.dryRun ? 'DRY-RUN' : out.ready ? '✅' : '⚠️';
1893
- const relation = out.changed ? `${out.currentVersion} ${out.targetVersion}` : `${out.targetVersion}(已是当前版本)`;
2102
+ const { theme } = stdoutUi();
2103
+ const mark = out.dryRun ? theme.dim('DRY-RUN') : out.ready ? theme.success('✅') : theme.warn('⚠️');
2104
+ const relation = out.changed
2105
+ ? `${theme.dim(out.currentVersion)} → ${theme.success(out.targetVersion)}`
2106
+ : `${out.targetVersion}(已是当前版本)`;
1894
2107
  console.log(`${mark} dta upgrade: ${relation}`);
1895
- console.log(` target=${out.target}`);
1896
- console.log(` CLI=${out.executable}`);
2108
+ console.log(` target=${theme.noun(out.target)}`);
2109
+ console.log(` CLI=${theme.noun(out.executable)}`);
1897
2110
  if (out.dryRun) {
1898
- console.log(` 将执行: ${out.commands.install}`);
1899
- console.log(` 将复核: ${out.commands.verify}`);
2111
+ console.log(` 将执行: ${theme.noun(out.commands.install)}`);
2112
+ console.log(` 将复核: ${theme.noun(out.commands.verify)}`);
2113
+ console.log(` ${theme.dim('移除 --dry-run 以实际执行升级')}`);
1900
2114
  }
1901
2115
  else if (out.ready) {
1902
2116
  console.log(' setup / DWS / Skill / Claude Code / Codex / OpenCode 全部 ready');
2117
+ // 出口指引:验证命令 + 后悔药,都是可以直接复制的
2118
+ console.log(` ${theme.dim(`验证: dta --version${out.changed ? ` 回退: dta upgrade --version ${out.currentVersion} --force` : ''}`)}`);
1903
2119
  }
1904
2120
  else {
1905
- console.log(` CLI 已更新;环境复核未完全 ready,请运行: ${out.commands.verify}`);
2121
+ console.log(` CLI 已更新;环境复核未完全 ready,请运行: ${theme.noun(out.commands.verify)}`);
1906
2122
  }
1907
2123
  }
1908
2124
  //# sourceMappingURL=dingtalk-agent.js.map