@xdxer/dingtalk-agent 0.1.5-beta.4 → 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.
Files changed (36) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/bin/dingtalk-agent.js +339 -124
  3. package/dist/bin/dingtalk-agent.js.map +1 -1
  4. package/dist/src/actions.js +3 -2
  5. package/dist/src/actions.js.map +1 -1
  6. package/dist/src/doctor.js +1 -1
  7. package/dist/src/doctor.js.map +1 -1
  8. package/dist/src/dws.js +2 -1
  9. package/dist/src/dws.js.map +1 -1
  10. package/dist/src/init.js +2 -1
  11. package/dist/src/init.js.map +1 -1
  12. package/dist/src/map.js +157 -0
  13. package/dist/src/map.js.map +1 -0
  14. package/dist/src/skill-manager.js +5 -0
  15. package/dist/src/skill-manager.js.map +1 -1
  16. package/dist/src/tui.js +369 -0
  17. package/dist/src/tui.js.map +1 -0
  18. package/dist/src/upgrade.js +113 -33
  19. package/dist/src/upgrade.js.map +1 -1
  20. package/dist/src/waits.js +2 -1
  21. package/dist/src/waits.js.map +1 -1
  22. package/package.json +3 -2
  23. package/skills/core/dingtalk-agent-compose/SKILL.md +19 -1
  24. package/skills/core/dingtalk-people-group-memory/COMPLETENESS.md +36 -0
  25. package/skills/core/dingtalk-people-group-memory/SKILL.md +69 -0
  26. package/skills/core/dingtalk-people-group-memory/references/adapters.md +273 -0
  27. package/skills/core/dingtalk-people-group-memory/references/assembly-guidance.md +40 -0
  28. package/skills/core/dingtalk-people-group-memory/references/binding.md +110 -0
  29. package/skills/core/dingtalk-people-group-memory/references/cold-start.md +70 -0
  30. package/skills/core/dingtalk-people-group-memory/references/config-binding.md +89 -0
  31. package/skills/core/dingtalk-people-group-memory/references/consent-and-visibility.md +83 -0
  32. package/skills/core/dingtalk-people-group-memory/references/consolidation.md +162 -0
  33. package/skills/core/dingtalk-people-group-memory/references/event-ingest.md +103 -0
  34. package/skills/core/dingtalk-people-group-memory/references/guided-setup.md +70 -0
  35. package/skills/core/dingtalk-people-group-memory/references/model.md +148 -0
  36. package/skills/core/dingtalk-people-group-memory/references/storage-port.md +107 -0
@@ -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';
@@ -65,8 +67,7 @@ dta —— 给 Agent 安装钉钉员工的基础行为和工作环境
65
67
  dta setup 首次配置 CLI、DWS 和内置 Skill(基础行为 + Agent 装配 + 交付后评测)
66
68
  dta bootstrap --json 为当前 Agent 会话加载工作区
67
69
  dta agent enhance / audit 安全增强已有仓库,再审计定义、存储与 Skill 真加载
68
- dta info / dta workspace doctor <name> 查看 Project 并只读诊断 Workspace
69
- dta schedule show / plan --workspace <name> 查看声明的常驻节律并生成 provider 部署计划
70
+ dta info / workspace doctor / schedule show <name> 只读诊断 Project、Workspace 与声明的常驻节律
70
71
  dta agent-platform use <platform> → dta deploy / dta promote 声明平台归属并装平台技能包,再受控部署与晋级
71
72
 
72
73
  维护环境:
@@ -184,13 +185,100 @@ dingtalk-agent 已验版本晋级与反馈候选
184
185
  Promotion 只接受指定 suite 的 load/hard/surface gate 与精确 W2 evidence hash,并委托 W4 deploy。
185
186
  Observe 只写 gitignored、proposed、不可直接发布的 Eval candidate;不修改 AGENTS.md、Prompt、Skill 或 Trigger。
186
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
+ }
187
244
  function fail(msg, code = 1, hint = '') {
188
- console.error(`错误: ${msg}`);
245
+ // 整行染色,绝不做 danger('错误') + ': ' + msg 这种切分——
246
+ // 契约 eval 断言的是 stderr.includes('错误:'),切开就再也匹配不上。
247
+ const { theme } = stderrUi();
248
+ console.error(theme.danger(`错误: ${msg}`));
189
249
  if (hint)
190
- console.error(`提示: ${hint}`);
250
+ console.error(theme.dim(`提示: ${hint}`));
191
251
  process.exit(code);
192
252
  }
193
- 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)];
194
282
  const cmd = argv[0];
195
283
  const sub = argv[1];
196
284
  try {
@@ -203,38 +291,38 @@ catch (e) {
203
291
  }
204
292
  async function main() {
205
293
  if (cmd === 'help' && sub === 'runtime') {
206
- console.log(RUNTIME_HELP);
294
+ console.log(renderHelp(RUNTIME_HELP));
207
295
  return;
208
296
  }
209
297
  if (cmd === 'help' && sub === 'adapters') {
210
- console.log(ADAPTER_HELP);
298
+ console.log(renderHelp(ADAPTER_HELP));
211
299
  return;
212
300
  }
213
301
  if (cmd === 'help' && sub === 'lab') {
214
- console.log(LAB_HELP);
302
+ console.log(renderHelp(LAB_HELP));
215
303
  return;
216
304
  }
217
305
  if (cmd === 'help' && sub === 'agent') {
218
- console.log(AGENT_HELP);
306
+ console.log(renderHelp(AGENT_HELP));
219
307
  return;
220
308
  }
221
309
  if (cmd === 'help' && sub === 'workspace') {
222
- console.log(WORKSPACE_HELP);
310
+ console.log(renderHelp(WORKSPACE_HELP));
223
311
  return;
224
312
  }
225
313
  if (cmd === 'help' && sub === 'deploy') {
226
- console.log(DEPLOY_HELP);
314
+ console.log(renderHelp(DEPLOY_HELP));
227
315
  return;
228
316
  }
229
317
  if (cmd === 'help' && ['promote', 'observe'].includes(sub || '')) {
230
- console.log(PROMOTION_HELP);
318
+ console.log(renderHelp(PROMOTION_HELP));
231
319
  return;
232
320
  }
233
321
  if (cmd === 'help' && sub) {
234
322
  fail(`不认识的帮助主题: ${sub}`, 1, '运行 dta --help 回到产品入口;事件宿主可用 dta help runtime。');
235
323
  }
236
324
  if (!cmd || cmd === '--help' || cmd === '-h' || cmd === 'help') {
237
- console.log(HELP);
325
+ console.log(renderHelp(HELP));
238
326
  return;
239
327
  }
240
328
  if (cmd === '--version' || cmd === '-V' || cmd === 'version') {
@@ -438,23 +526,23 @@ async function main() {
438
526
  return;
439
527
  }
440
528
  if (out.count === 0) {
441
- console.log('本 Project 未声明任何常驻节律(schedules)。');
529
+ console.log(muted('本 Project 未声明任何常驻节律(schedules)。'));
442
530
  return;
443
531
  }
444
- console.log(`声明的常驻节律(internalized cron) · ${out.count} 条`);
532
+ console.log(`${strong('声明的常驻节律(internalized cron)')} · ${out.count} 条`);
445
533
  for (const s of out.schedules) {
446
- 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}]`)}`);
447
535
  if (s.wake)
448
- console.log(` 唤醒 ${s.wake}`);
536
+ console.log(muted(` 唤醒 ${s.wake}`));
449
537
  if (s.completion)
450
- console.log(` ②判据 ${s.completion}`);
538
+ console.log(muted(` ②判据 ${s.completion}`));
451
539
  }
452
540
  if (!out.minutesDistinct) {
453
- console.log(`\n⚠️ 分钟位冲突: ${out.collidingMinutes.join(', ')} —— 外发类同分钟并发会重复送,请错开`);
541
+ console.log(`\n${mark('warn', `⚠️ 分钟位冲突: ${out.collidingMinutes.join(', ')} —— 外发类同分钟并发会重复送,请错开`)}`);
454
542
  process.exitCode = 2;
455
543
  }
456
544
  else {
457
- console.log('\n✓ 各节律分钟位互不相同(外发防重复的静态前提满足)');
545
+ console.log(`\n${mark('pass', '✓ 各节律分钟位互不相同(外发防重复的静态前提满足)')}`);
458
546
  }
459
547
  return;
460
548
  }
@@ -468,17 +556,17 @@ async function main() {
468
556
  console.log(JSON.stringify(plan, null, 2));
469
557
  return;
470
558
  }
471
- console.log(`schedule 部署计划 · workspace=${plan.workspace} · provider=${plan.provider}`);
559
+ console.log(`${strong('schedule 部署计划')} · workspace=${noun(plan.workspace)} · provider=${plan.provider}`);
472
560
  if (!plan.supported) {
473
- console.log(`\n 不支持: ${plan.reason}`);
474
- console.log(` ${plan.reconcile}`);
561
+ console.log(`\n${mark('fail', `✗ 不支持: ${plan.reason}`)}`);
562
+ console.log(` ${noun(plan.reconcile)}`);
475
563
  process.exitCode = 2;
476
564
  return;
477
565
  }
478
566
  console.log(` ${plan.count} 条声明 → provider ops:\n`);
479
567
  for (const s of plan.schedules)
480
- console.log(` # ${s.name}\n ${s.applyCommand}\n`);
481
- console.log(`执行: ${plan.reconcile}`);
568
+ console.log(` ${muted(`# ${s.name}`)}\n ${noun(s.applyCommand)}\n`);
569
+ console.log(`执行: ${noun(plan.reconcile)}`);
482
570
  return;
483
571
  }
484
572
  fail(`可用: dta schedule show | plan --workspace <name>${suggest(sub || '', ['show', 'plan'], 'dta schedule')}`);
@@ -671,7 +759,7 @@ async function main() {
671
759
  if (o.json)
672
760
  console.log(JSON.stringify(out, null, 2));
673
761
  else
674
- console.log(`✅ current workspace: ${out.previous || '-'} → ${out.current}`);
762
+ console.log(`${mark('pass', '✅')} current workspace: ${muted(out.previous || '-')} → ${noun(out.current)}`);
675
763
  return;
676
764
  }
677
765
  if (sub === 'run') {
@@ -717,19 +805,19 @@ async function main() {
717
805
  if (o.json)
718
806
  console.log(JSON.stringify(out, null, 2));
719
807
  else if (out.$schema === 'dingtalk-agent/opencode-workspace-run-plan@1') {
720
- 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}`);
721
809
  }
722
810
  else if (out.$schema === 'dingtalk-agent/multica-workspace-run-plan@1') {
723
- 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}`);
724
812
  }
725
813
  else {
726
- console.log(`${out.passed ? '✅' : '❌'} workspace run ${out.runId}`);
814
+ console.log(`${mark(levelOf(Boolean(out.passed)), out.passed ? '✅' : '❌')} workspace run ${noun(out.runId)}`);
727
815
  if ('execution' in out && out.execution?.answer)
728
816
  console.log(out.execution.answer);
729
817
  if ('answer' in out && out.answer)
730
818
  console.log(out.answer);
731
819
  if (out.evidencePath)
732
- console.log(`evidence=${out.evidencePath}`);
820
+ console.log(`evidence=${noun(out.evidencePath)}`);
733
821
  }
734
822
  if (o.execute && !out.passed)
735
823
  process.exitCode = 2;
@@ -798,23 +886,72 @@ async function main() {
798
886
  return;
799
887
  }
800
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
+ }
801
894
  const { values: o } = parseArgs({
802
895
  args: argv.slice(1),
803
896
  options: {
804
897
  channel: { type: 'string' }, version: { type: 'string' }, prefix: { type: 'string' },
805
898
  'dry-run': { type: 'boolean' }, force: { type: 'boolean' }, json: { type: 'boolean' },
899
+ check: { type: 'boolean' }, yes: { type: 'boolean' },
806
900
  },
807
901
  });
808
- const out = upgradeAgent(PACKAGE_ROOT, {
809
- channel: o.channel,
810
- 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,
811
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,
812
949
  });
813
- if (o.json)
814
- console.log(JSON.stringify(out, null, 2));
950
+ if (json)
951
+ console.log(JSON.stringify(result, null, 2));
815
952
  else
816
- printUpgrade(out);
817
- if (!out.dryRun && !out.ready)
953
+ printUpgrade(result);
954
+ if (!result.dryRun && !result.ready)
818
955
  process.exitCode = 2;
819
956
  return;
820
957
  }
@@ -914,7 +1051,7 @@ async function main() {
914
1051
  if (o.json)
915
1052
  console.log(JSON.stringify({ ...out, endpoint, readiness, targets, doc }, null, 2));
916
1053
  else {
917
- console.log(`✅ 工作区已归属 ${out.definition?.label}(写入 ${out.written})`);
1054
+ console.log(`${mark('pass', '✅')} 工作区已归属 ${strong(out.definition?.label)}(写入 ${noun(out.written)})`);
918
1055
  for (const install of out.skillInstalls)
919
1056
  printSkillStatus(install, 'install', false);
920
1057
  if (!out.skillInstalls.length) {
@@ -954,14 +1091,14 @@ async function main() {
954
1091
  if (o.json)
955
1092
  console.log(JSON.stringify(out, null, 2));
956
1093
  else {
957
- console.log(`✅ ${out.mode === 'workspace' ? '已装载 Workspace' : '直接会话模式'}`);
1094
+ console.log(`${mark('pass', '✅')} ${strong(out.mode === 'workspace' ? '已装载 Workspace' : '直接会话模式')}`);
958
1095
  console.log(` scope=${out.scopeId} initialized=${out.initialized}`);
959
1096
  console.log(` agent=${out.definition.id} definition=${out.definition.status}`);
960
1097
  if (!out.mounts.length)
961
- console.log(' 没有发现持久上下文;这不是错误,也不需要自动 init。');
1098
+ console.log(muted(' 没有发现持久上下文;这不是错误,也不需要自动 init。'));
962
1099
  for (const mount of out.mounts)
963
- console.log(` ${mount.slot}: ${mount.path}`);
964
- console.log(` ${out.note}`);
1100
+ console.log(` ${mount.slot}: ${noun(mount.path)}`);
1101
+ console.log(` ${muted(out.note)}`);
965
1102
  }
966
1103
  return;
967
1104
  }
@@ -1347,9 +1484,9 @@ async function main() {
1347
1484
  if (o.json)
1348
1485
  console.log(JSON.stringify(out, null, 2));
1349
1486
  else if (!out.found)
1350
- console.log('当前 Session 尚无 Task checkpoint。');
1487
+ console.log(muted('当前 Session 尚无 Task checkpoint。'));
1351
1488
  else {
1352
- console.log(`✅ Task ${out.checkpoint.taskId} · ${out.checkpoint.status}`);
1489
+ console.log(`${mark('pass', '✅')} Task ${noun(out.checkpoint.taskId)} · ${out.checkpoint.status}`);
1353
1490
  console.log(` revision=${out.checkpoint.revision} hash=${out.hash}`);
1354
1491
  console.log(` next=${out.checkpoint.nextAction || '-'}`);
1355
1492
  }
@@ -1374,7 +1511,7 @@ async function main() {
1374
1511
  if (o.json || !o.live)
1375
1512
  console.log(JSON.stringify(out, null, 2));
1376
1513
  else {
1377
- console.log(`${out.verified ? '✅' : '⚠️'} Operational Memory · ${out.mode}`);
1514
+ console.log(`${mark(out.verified ? 'pass' : 'warn', out.verified ? '✅' : '⚠️')} ${strong('Operational Memory')} · ${out.mode}`);
1378
1515
  console.log(` record=${out.recordId || '-'} verification=${out.verification}`);
1379
1516
  }
1380
1517
  if (out.mode === 'uncertain')
@@ -1428,12 +1565,12 @@ async function main() {
1428
1565
  if (o.json)
1429
1566
  console.log(JSON.stringify(out, null, 2));
1430
1567
  else if (action === 'publish') {
1431
- 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)}`);
1432
1569
  console.log(` mode=${out.mode} targetHash=${out.currentTargetHash}`);
1433
1570
  }
1434
1571
  else {
1435
- console.log(`✅ Candidate ${out.candidate.id} · ${out.candidate.status}`);
1436
- 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)}`);
1437
1574
  }
1438
1575
  if (action === 'publish' && out.mode === 'uncertain')
1439
1576
  process.exitCode = 2;
@@ -1464,10 +1601,10 @@ async function main() {
1464
1601
  if (o.json || o['dry-run'])
1465
1602
  console.log(JSON.stringify(out, null, 2));
1466
1603
  else {
1467
- console.log(`${out.verified ? '✅' : '⚠️'} ${out.kind} · ${out.outcome} · ${out.toState}`);
1468
- 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)}`);
1469
1606
  if (!out.verified)
1470
- console.log(` ${out.verification}`);
1607
+ console.log(` ${muted(out.verification)}`);
1471
1608
  }
1472
1609
  if (out.outcome === 'uncertain')
1473
1610
  process.exitCode = 2;
@@ -1539,11 +1676,41 @@ function editDistance(a, b) {
1539
1676
  }
1540
1677
  return row[b.length];
1541
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
+ }
1542
1707
  function printDispatch(out, json = false) {
1543
1708
  if (json)
1544
1709
  return console.log(JSON.stringify(out, null, 2));
1545
- const mark = out.duplicate ? (out.launch ? '🔁 REDELIVER' : '↩️ DUPLICATE') : '✅ READY';
1546
- 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)}`);
1547
1714
  console.log(` Field=${out.fieldId} Session=${out.sessionId} Event=${out.eventKind}`);
1548
1715
  console.log(` cwd=${out.cwd}`);
1549
1716
  console.log(` entrypoint=${out.entrypoint} queue=${out.queue.key} (max=${out.queue.maxConcurrency})`);
@@ -1553,7 +1720,7 @@ function printDispatch(out, json = false) {
1553
1720
  }
1554
1721
  function printLab(out) {
1555
1722
  const passed = out.ready ?? out.passed ?? out.assertions?.passed;
1556
- console.log(`${passed === false ? '❌' : '✅'} ${out.$schema || 'dingtalk-agent/lab'}`);
1723
+ console.log(`${mark(levelOf(passed !== false), passed === false ? '❌' : '✅')} ${out.$schema || 'dingtalk-agent/lab'}`);
1557
1724
  if (out.mode)
1558
1725
  console.log(` mode=${out.mode}`);
1559
1726
  if (out.marker)
@@ -1562,17 +1729,17 @@ function printLab(out) {
1562
1729
  console.log(` evidence=${out.evidencePath}`);
1563
1730
  if (Array.isArray(out.checks)) {
1564
1731
  for (const check of out.checks) {
1565
- 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}`);
1566
1733
  }
1567
1734
  }
1568
1735
  }
1569
1736
  function printAgentAudit(out) {
1570
- 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')}`);
1571
1738
  console.log(` definition=${out.definition.hash} storage=${out.storageMode}`);
1572
1739
  console.log(` dingtalkSideEffect=${out.dingtalkSideEffect} sideEffect=${out.sideEffect}`);
1573
1740
  for (const check of out.checks) {
1574
- const mark = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1575
- 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}`);
1576
1743
  }
1577
1744
  if (out.repairs.length) {
1578
1745
  console.log('\n修复建议:');
@@ -1585,7 +1752,7 @@ function printAgentAudit(out) {
1585
1752
  }
1586
1753
  function printAgentEnhance(out) {
1587
1754
  if (out.$schema === 'dingtalk-agent/agent-enhancement-plan@1') {
1588
- 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')}`);
1589
1756
  console.log(` planId=${out.planId} project=${out.projectName}`);
1590
1757
  console.log(` sideEffect=${out.sideEffect} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1591
1758
  for (const operation of out.operations) {
@@ -1595,12 +1762,12 @@ function printAgentEnhance(out) {
1595
1762
  console.log(` REVIEW ${out.semanticReview.files.join(', ')}: ${out.semanticReview.why}`);
1596
1763
  }
1597
1764
  for (const blocker of out.blockers)
1598
- console.log(` BLOCK ${blocker}`);
1765
+ console.log(` ${mark('fail', 'BLOCK')} ${blocker}`);
1599
1766
  if (out.ready)
1600
1767
  console.log(`\nApply:\n ${out.apply.command}`);
1601
1768
  return;
1602
1769
  }
1603
- console.log('dingtalk-agent agent enhance · APPLIED');
1770
+ console.log(`${strong('dingtalk-agent agent enhance')} · ${mark('pass', 'APPLIED')}`);
1604
1771
  console.log(` operation=${out.operationId} planId=${out.planId}`);
1605
1772
  console.log(` changes=${out.changes.length} idempotent=${out.idempotent}`);
1606
1773
  if (out.backupRoot)
@@ -1608,8 +1775,8 @@ function printAgentEnhance(out) {
1608
1775
  console.log(` audit=${out.audit.status} missing=${out.audit.missing.join(', ') || '-'}`);
1609
1776
  }
1610
1777
  function printAgentPlatform(platform) {
1611
- console.log(`${platform.status === 'supported' ? '✅' : '⏳'} ${platform.name} · ${platform.label} · ${platformStatusLabel(platform.status)}`);
1612
- 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)}`);
1613
1780
  for (const skill of platform.skills)
1614
1781
  console.log(` 技能[${skill.role}] ${skill.name} —— ${skill.purpose}`);
1615
1782
  if (platform.commands.length)
@@ -1617,12 +1784,12 @@ function printAgentPlatform(platform) {
1617
1784
  }
1618
1785
  function printAgentPlatformResolution(out) {
1619
1786
  if (!out.platform) {
1620
- console.log('⚠️ 当前工作区未声明 managed agent platform');
1787
+ console.log(mark('warn', '⚠️ 当前工作区未声明 managed agent platform'));
1621
1788
  console.log(' 运行 `dta agent-platform use multica-dingtalk`,或设置 DTA_AGENT_PLATFORM 环境变量。');
1622
1789
  return;
1623
1790
  }
1624
1791
  const known = out.definition;
1625
- 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)}` : '(未知)'}`);
1626
1793
  console.log(` 来源: ${out.source}${out.file ? ` · ${out.file}` : ''}`);
1627
1794
  for (const skill of known?.skills || [])
1628
1795
  console.log(` 技能[${skill.role}] ${skill.name} —— ${skill.purpose}`);
@@ -1630,8 +1797,9 @@ function printAgentPlatformResolution(out) {
1630
1797
  // 披露:dta 层平台命令关联到平台内确切的 Skill(诊断信息走 stderr,不污染 --json stdout)。
1631
1798
  function disclosePlatformSkill(resolution, role) {
1632
1799
  const skillName = resolution.definition ? platformSkillForRole(resolution.definition.name, role) : null;
1633
- if (skillName)
1634
- console.error(`提示: 平台 ${resolution.definition.name} 的该命令方法学由 Skill ${skillName} 承载`);
1800
+ if (skillName) {
1801
+ console.error(stderrUi().theme.dim(`提示: 平台 ${resolution.definition.name} 的该命令方法学由 Skill ${skillName} 承载`));
1802
+ }
1635
1803
  }
1636
1804
  function printEndpoint(endpoint) {
1637
1805
  if (!endpoint)
@@ -1645,9 +1813,9 @@ function printEndpoint(endpoint) {
1645
1813
  console.log(` Endpoint: 未解析——设 ${endpoint.envVar} 或登录 multica 后生效`);
1646
1814
  return;
1647
1815
  }
1648
- const mark = endpoint.confirmed ? '✅' : '⚠️';
1816
+ const glyph = mark(endpoint.confirmed ? 'pass' : 'warn', endpoint.confirmed ? '✅' : '⚠️');
1649
1817
  const note = endpoint.confirmed ? '' : '(建议/未确认,deploy 前需显式确认是预发还是生产)';
1650
- console.log(` ${mark} Endpoint: ${endpoint.endpoint} · 来源: ${endpoint.source}${note}`);
1818
+ console.log(` ${glyph} Endpoint: ${noun(endpoint.endpoint)} · 来源: ${endpoint.source}${muted(note)}`);
1651
1819
  console.log(` (切换:设 ${endpoint.envVar}=<url>、写 dingtalk-agent.json#multicaEndpoint、或登录对应 profile;无需改代码)`);
1652
1820
  }
1653
1821
  function printPlatformDoc(platformName) {
@@ -1655,27 +1823,27 @@ function printPlatformDoc(platformName) {
1655
1823
  return;
1656
1824
  const path = platformDocPath(PACKAGE_ROOT, platformName);
1657
1825
  if (path)
1658
- console.log(` 平台说明: ${path}\n (切换到该平台后请阅读,了解各技能用途与交付链)`);
1826
+ console.log(` 平台说明: ${noun(path)}\n${muted(' (切换到该平台后请阅读,了解各技能用途与交付链)')}`);
1659
1827
  }
1660
1828
  function printMulticaTargets(targets) {
1661
1829
  if (!targets.length)
1662
1830
  return;
1663
- console.log(' 本机 Multica 登录目标(发布前必须与用户确认 endpoint 与 workspace):');
1831
+ console.log(strong(' 本机 Multica 登录目标(发布前必须与用户确认 endpoint 与 workspace):'));
1664
1832
  for (const target of targets) {
1665
1833
  console.log(` - profile=${target.profile} · ${target.serverUrl}${target.workspaceId ? ` · workspace=${target.workspaceId}` : ''}`);
1666
1834
  }
1667
1835
  }
1668
1836
  function printAgentPlatformReadiness(checks) {
1669
1837
  for (const check of checks) {
1670
- console.log(` ${check.ok ? '✅' : '⚠️'} ${check.summary}`);
1838
+ console.log(` ${mark(check.ok ? 'pass' : 'warn', check.ok ? '✅' : '⚠️')} ${check.summary}`);
1671
1839
  if (check.hint)
1672
- console.log(` ${check.hint}`);
1840
+ console.log(` ${muted(check.hint)}`);
1673
1841
  }
1674
1842
  }
1675
1843
  function printSkillStatus(out, action, dryRun) {
1676
- const prefix = dryRun ? 'DRY-RUN' : '✅';
1844
+ const prefix = dryRun ? mark('muted', 'DRY-RUN') : mark('pass', '✅');
1677
1845
  const verb = action === 'status' ? '全局 Skill 状态' : `skill ${action}`;
1678
- console.log(`${prefix} ${verb}: ${out.name}`);
1846
+ console.log(`${prefix} ${verb}: ${strong(out.name)}`);
1679
1847
  console.log(` manager=${out.manager} bundled=${out.bundled.skillVersion || '-'}`);
1680
1848
  console.log(` canonical=${out.canonical.path}`);
1681
1849
  console.log(` installed=${out.canonical.exists} ` +
@@ -1686,71 +1854,64 @@ function printSkillStatus(out, action, dryRun) {
1686
1854
  ` → ${out.operation.after.installedVersion}(${out.operation.after.state})`);
1687
1855
  }
1688
1856
  if (out.operation)
1689
- console.log(` delegated: ${out.operation.command}`);
1857
+ console.log(` delegated: ${noun(out.operation.command)}`);
1690
1858
  for (const client of out.clients) {
1691
- 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)})`);
1692
1860
  }
1693
1861
  if (action === 'install' && !dryRun) {
1694
- console.log(' 新 Agent 会话将自动发现;当前会话未发现时请重启 Claude Code/Codex。');
1862
+ console.log(muted(' 新 Agent 会话将自动发现;当前会话未发现时请重启 Claude Code/Codex。'));
1695
1863
  }
1696
1864
  }
1697
1865
  function printDoctor(out) {
1698
- 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')}`);
1699
1867
  for (const check of out.checks) {
1700
- const mark = check.level === 'pass' ? '✅' : check.level === 'warn' ? '⚠️' : '❌';
1701
- console.log(`${mark} ${check.summary}`);
1868
+ const glyph = check.level === 'pass' ? '✅' : check.level === 'warn' ? '⚠️' : '❌';
1869
+ console.log(`${mark(levelOf(check.level), glyph)} ${check.summary}`);
1702
1870
  if (check.detail)
1703
- console.log(` ${check.detail}`);
1871
+ console.log(` ${muted(check.detail)}`);
1704
1872
  if (check.fix)
1705
- console.log(` 修复: ${check.fix}`);
1873
+ console.log(` 修复: ${noun(check.fix)}`);
1706
1874
  }
1707
1875
  if (out.hosts.length) {
1708
1876
  // Host 面回答"本地能在哪跑",不改变上面的 ready 结论。
1709
- console.log('\n本机 Coding Agent:');
1877
+ console.log(`\n${strong('本机 Coding Agent:')}`);
1710
1878
  const width = Math.max(...out.hosts.map((host) => displayWidth(host.label)));
1711
1879
  for (const host of out.hosts) {
1712
1880
  const label = host.label + ' '.repeat(width - displayWidth(host.label));
1713
1881
  const where = host.cli.found
1714
1882
  ? [host.cli.path, host.cli.version].filter(Boolean).join(' ')
1715
1883
  : `未找到 ${host.cli.command}`;
1716
- console.log(` ${host.cli.found ? '✅' : '❌'} ${label} ${where}`);
1717
- 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}`));
1718
1886
  }
1719
1887
  }
1720
1888
  if (out.nextSteps.length) {
1721
- console.log('\n下一步:');
1889
+ console.log(`\n${strong('下一步:')}`);
1722
1890
  for (const step of out.nextSteps)
1723
- console.log(` ${step}`);
1891
+ console.log(` ${noun(step)}`);
1724
1892
  }
1725
1893
  }
1726
- /** 全角字符按两列计宽,避免中英混排的 Host 列表错位。 */
1727
- function displayWidth(text) {
1728
- let width = 0;
1729
- for (const char of text)
1730
- width += /[ᄀ-ᅟ⺀-꓏가-힣豈-﫿︰-﹯＀-⦆¢-₩]/.test(char) ? 2 : 1;
1731
- return width;
1732
- }
1733
1894
  function printProjectInfo(out) {
1734
- console.log(`dingtalk-agent Project · ${out.project.name}`);
1895
+ console.log(`${strong('dingtalk-agent Project')} · ${noun(out.project.name)}`);
1735
1896
  console.log(` root=${out.root}`);
1736
1897
  console.log(` source=${out.source} manifest=${out.manifest || '(synthetic legacy)'}`);
1737
1898
  console.log(` hash=${out.manifestHash} dta=${out.project.dtaVersion}`);
1738
1899
  console.log(` current=${out.currentWorkspace || '(not selected)'}`);
1739
1900
  for (const workspace of out.workspaces) {
1740
- 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}`);
1741
1902
  }
1742
1903
  }
1743
1904
  function printWorkspaceList(out) {
1744
- console.log(`dingtalk-agent workspaces · ${out.project.name}`);
1905
+ console.log(`${strong('dingtalk-agent workspaces')} · ${noun(out.project.name)}`);
1745
1906
  if (!out.workspaces.length)
1746
- console.log(' 尚未声明 Development Workspace。');
1907
+ console.log(muted(' 尚未声明 Development Workspace。'));
1747
1908
  for (const workspace of out.workspaces) {
1748
- console.log(` ${workspace.current ? '*' : '-'} ${workspace.name} provider=${workspace.provider.kind} ` +
1909
+ console.log(` ${workspace.current ? strong('*') : muted('-')} ${workspace.name} provider=${workspace.provider.kind} ` +
1749
1910
  `stage=${workspace.stage} status=${workspace.status}`);
1750
1911
  }
1751
1912
  }
1752
1913
  function printDevelopmentWorkspace(out) {
1753
- console.log(`dingtalk-agent workspace · ${out.name}`);
1914
+ console.log(`${strong('dingtalk-agent workspace')} · ${noun(out.name)}`);
1754
1915
  console.log(` provider=${out.provider.kind} stage=${out.stage} status=${out.status}`);
1755
1916
  console.log(` desired=${out.desiredHash} observed=${out.observedHash || '-'}`);
1756
1917
  console.log(` current=${out.current} legacy=${out.legacy}`);
@@ -1760,19 +1921,22 @@ function printDevelopmentWorkspace(out) {
1760
1921
  console.log(` source=${source}`);
1761
1922
  }
1762
1923
  function printDevelopmentWorkspaceDoctor(out) {
1763
- 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')}`);
1764
1925
  console.log(` provider=${out.provider} status=${out.status}`);
1765
1926
  console.log(` sideEffect=${out.sideEffect} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1766
1927
  for (const check of out.checks) {
1767
- const mark = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1768
- 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}`);
1769
1930
  if (check.fix && check.level !== 'pass')
1770
- console.log(` fix: ${check.fix}`);
1931
+ console.log(` fix: ${noun(check.fix)}`);
1771
1932
  }
1772
1933
  }
1773
1934
  function printOpenCodeWorkspaceOperation(out) {
1774
1935
  const applied = out.$schema === 'dingtalk-agent/opencode-workspace-apply@1';
1775
- 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)}`);
1776
1940
  console.log(` action=${out.action} model=${out.model}`);
1777
1941
  console.log(` desired=${out.desiredHash} observed=${out.observedHash || '-'}`);
1778
1942
  console.log(` managed=${out.managedPath}`);
@@ -1782,7 +1946,7 @@ function printOpenCodeWorkspaceOperation(out) {
1782
1946
  function printMulticaWorkspaceOperation(out) {
1783
1947
  const passed = out.passed ?? out.readyForApply ?? out.blocking?.length === 0;
1784
1948
  const mode = out.remoteRead ? 'REMOTE-READ' : 'DRY-RUN';
1785
- console.log(`${passed ? '✅' : '⚠️'} ${mode} Multica Workspace ${out.workspace}`);
1949
+ console.log(`${mark(passed ? 'pass' : 'warn', passed ? '✅' : '⚠️')} ${mode} Multica Workspace ${noun(out.workspace)}`);
1786
1950
  console.log(` schema=${out.$schema} profile=${out.profile || '-'}`);
1787
1951
  if (out.planId)
1788
1952
  console.log(` plan=${out.planId}`);
@@ -1803,7 +1967,7 @@ function printMulticaWorkspaceOperation(out) {
1803
1967
  console.log(` remoteWrite=${out.remoteWrite} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1804
1968
  }
1805
1969
  function printMulticaDeployment(out) {
1806
- console.log(`Multica deploy: ${out.workspace || '<unknown>'}`);
1970
+ console.log(`${strong('Multica deploy')}: ${noun(out.workspace || '<unknown>')}`);
1807
1971
  if (out.planId)
1808
1972
  console.log(` plan: ${out.planId}`);
1809
1973
  if (out.operationId)
@@ -1826,7 +1990,7 @@ function printMulticaDeployment(out) {
1826
1990
  console.log(' triggers: unchanged');
1827
1991
  }
1828
1992
  function printPromotion(out) {
1829
- 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>')}`);
1830
1994
  if (out.planId)
1831
1995
  console.log(` plan: ${out.planId}`);
1832
1996
  if (out.routeId)
@@ -1877,33 +2041,84 @@ function rejectWorkspaceOptions(values, allowed, command) {
1877
2041
  fail(`${command} 不接受参数: ${extras.join(', ')}`);
1878
2042
  }
1879
2043
  function printSetup(out) {
1880
- console.log(`${out.dryRun ? 'DRY-RUN' : '✅'} dingtalk-agent setup`);
1881
- console.log(` CLI: ${out.cli.executable}`);
1882
- console.log(` 短命令: ${out.cli.alias}`);
1883
- 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)}`);
1884
2048
  if (!out.shell.pathReady) {
1885
- console.log(` 当前 shell 尚未加载 PATH;本次终端执行: ${out.shell.activateCommand}`);
2049
+ console.log(` 当前 shell 尚未加载 PATH;本次终端执行: ${noun(out.shell.activateCommand)}`);
1886
2050
  if (out.shell.rcFile)
1887
- console.log(` 新终端会从 ${out.shell.rcFile} 自动加载`);
2051
+ console.log(muted(` 新终端会从 ${out.shell.rcFile} 自动加载`));
1888
2052
  }
1889
2053
  printDoctor(out.doctor);
1890
- 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
+ }
1891
2100
  }
1892
2101
  function printUpgrade(out) {
1893
- const mark = out.dryRun ? 'DRY-RUN' : out.ready ? '✅' : '⚠️';
1894
- 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}(已是当前版本)`;
1895
2107
  console.log(`${mark} dta upgrade: ${relation}`);
1896
- console.log(` target=${out.target}`);
1897
- console.log(` CLI=${out.executable}`);
2108
+ console.log(` target=${theme.noun(out.target)}`);
2109
+ console.log(` CLI=${theme.noun(out.executable)}`);
1898
2110
  if (out.dryRun) {
1899
- console.log(` 将执行: ${out.commands.install}`);
1900
- 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 以实际执行升级')}`);
1901
2114
  }
1902
2115
  else if (out.ready) {
1903
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` : ''}`)}`);
1904
2119
  }
1905
2120
  else {
1906
- console.log(` CLI 已更新;环境复核未完全 ready,请运行: ${out.commands.verify}`);
2121
+ console.log(` CLI 已更新;环境复核未完全 ready,请运行: ${theme.noun(out.commands.verify)}`);
1907
2122
  }
1908
2123
  }
1909
2124
  //# sourceMappingURL=dingtalk-agent.js.map