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

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 (131) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.en.md +6 -6
  3. package/README.md +6 -6
  4. package/dist/bin/dingtalk-agent.js +406 -139
  5. package/dist/bin/dingtalk-agent.js.map +1 -1
  6. package/dist/src/actions.js +3 -2
  7. package/dist/src/actions.js.map +1 -1
  8. package/dist/src/agent-audit.js +29 -25
  9. package/dist/src/agent-audit.js.map +1 -1
  10. package/dist/src/agent-definition.js +7 -3
  11. package/dist/src/agent-definition.js.map +1 -1
  12. package/dist/src/agent-enhance.js +2 -2
  13. package/dist/src/agent-enhance.js.map +1 -1
  14. package/dist/src/agent-platform.js +2 -2
  15. package/dist/src/agent-platform.js.map +1 -1
  16. package/dist/src/development-workspace.js +14 -9
  17. package/dist/src/development-workspace.js.map +1 -1
  18. package/dist/src/doctor.js +58 -7
  19. package/dist/src/doctor.js.map +1 -1
  20. package/dist/src/dws.js +2 -1
  21. package/dist/src/dws.js.map +1 -1
  22. package/dist/src/init.js +2 -1
  23. package/dist/src/init.js.map +1 -1
  24. package/dist/src/map.js +157 -0
  25. package/dist/src/map.js.map +1 -0
  26. package/dist/src/opencode-evals.js +6 -6
  27. package/dist/src/opencode-evals.js.map +1 -1
  28. package/dist/src/opencode-provider.js +2 -2
  29. package/dist/src/opencode-provider.js.map +1 -1
  30. package/dist/src/opencode-workspace.js +3 -3
  31. package/dist/src/opencode-workspace.js.map +1 -1
  32. package/dist/src/personal-event-evals.js +4 -2
  33. package/dist/src/personal-event-evals.js.map +1 -1
  34. package/dist/src/remote-semantic-state-live-evals.js +5 -4
  35. package/dist/src/remote-semantic-state-live-evals.js.map +1 -1
  36. package/dist/src/remote-state-evals.js +2 -2
  37. package/dist/src/remote-state-evals.js.map +1 -1
  38. package/dist/src/robot-evals.js +3 -3
  39. package/dist/src/robot-evals.js.map +1 -1
  40. package/dist/src/schedule-plan.js +1 -1
  41. package/dist/src/schedule-plan.js.map +1 -1
  42. package/dist/src/sessions.js +1 -1
  43. package/dist/src/sessions.js.map +1 -1
  44. package/dist/src/skill-manager.js +74 -13
  45. package/dist/src/skill-manager.js.map +1 -1
  46. package/dist/src/tui.js +369 -0
  47. package/dist/src/tui.js.map +1 -0
  48. package/dist/src/upgrade.js +113 -33
  49. package/dist/src/upgrade.js.map +1 -1
  50. package/dist/src/waits.js +2 -1
  51. package/dist/src/waits.js.map +1 -1
  52. package/dist/src/workspace.js +2 -2
  53. package/dist/src/workspace.js.map +1 -1
  54. package/docs/ARCHITECTURE.md +9 -9
  55. package/docs/INSTALLATION.md +6 -6
  56. package/docs/SELF-TEST.md +3 -3
  57. package/docs/schemas/project.schema.json +2 -2
  58. package/examples/agents/README.md +1 -1
  59. package/examples/agents/fde-coach/agent/AGENTS.md +1 -1
  60. package/examples/agents/release-manager/agent/AGENTS.md +1 -1
  61. package/lab/agent-eval/catalog.json +5 -5
  62. package/lab/agent-eval/classic-failures.json +4 -4
  63. package/lab/agent-eval/completion-gate-regression.json +9 -9
  64. package/lab/agent-eval/personal-event-live.example.json +3 -3
  65. package/lab/agent-eval/remote-semantic-state-live.example.json +1 -1
  66. package/lab/agent-eval/workspace/opencode.json +2 -2
  67. package/lab/project-workspace/multica-readonly.fixture.json +2 -2
  68. package/lab/project-workspace/opencode-provider-suite.json +2 -2
  69. package/lab/project-workspace/project.fixture.json +1 -1
  70. package/lab/robot-eval/suite.json +1 -1
  71. package/lab/robot-eval/workspace/AGENTS.md +1 -1
  72. package/lab/robot-eval/workspace/opencode.json +2 -2
  73. package/lab/schemas/personal-event-eval.schema.json +1 -1
  74. package/package.json +8 -8
  75. package/skills/README.md +10 -7
  76. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/SKILL.md +8 -8
  77. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/AGENTS.template.md +1 -1
  78. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/hosts/opencode/opencode.template.json +2 -2
  79. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/evals/evals.json +3 -3
  80. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/host-loading-contract.md +1 -1
  81. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/hosts/claude-code.md +1 -1
  82. package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/hosts/opencode.md +2 -2
  83. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/SKILL.md +2 -2
  84. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/assets/eval-catalog.template.json +1 -1
  85. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/evals/evals.json +1 -1
  86. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/eval-topology.md +3 -3
  87. package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/interactive-debug-channels.md +1 -1
  88. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/SKILL.md +2 -2
  89. package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/event-to-behavior.md +1 -1
  90. package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/COMPLETENESS.md +1 -1
  91. package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/SKILL.md +2 -2
  92. package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/config-binding.md +1 -1
  93. package/skills/platforms/deap/PLATFORM.md +1 -1
  94. package/skills/platforms/multica-dingtalk/PLATFORM.md +4 -4
  95. package/skills/platforms/multica-dingtalk/{dingtalk-agent-deploy-multica → dta-deploy-multica}/SKILL.md +3 -3
  96. package/skills/platforms/multica-dingtalk/{multica-external → dta-ops-multica}/SKILL.md +5 -5
  97. package/skills/platforms/multica-dingtalk/{multica-external → dta-ops-multica}/scripts/bootstrap.sh +2 -2
  98. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/REPOSITORY.template.md +0 -0
  99. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/agent.bindings.dingtalk-doc.template.json +0 -0
  100. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/agent.bindings.local.template.json +0 -0
  101. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/assets/role-skill.template.md +0 -0
  102. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/agent-definition-contract.md +0 -0
  103. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/drive-and-schedules.md +0 -0
  104. /package/skills/core/{dingtalk-agent-compose → dta-agent-compose}/references/storage-routing.md +0 -0
  105. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/evidence-contract.md +0 -0
  106. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/failure-to-case.md +0 -0
  107. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/local-connector-smoke.md +0 -0
  108. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/scenario-taxonomy.md +0 -0
  109. /package/skills/core/{dingtalk-agent-eval → dta-agent-eval}/references/storage-modes.md +0 -0
  110. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/assets/memory-candidate-proposal.json +0 -0
  111. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/assets/task-checkpoint.json +0 -0
  112. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/action-contract.md +0 -0
  113. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/memory-and-evolution.md +0 -0
  114. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/perception-and-gates.md +0 -0
  115. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/risk-authority-and-privacy.md +0 -0
  116. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/runtime-modes.md +0 -0
  117. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/task-lifecycle.md +0 -0
  118. /package/skills/core/{dingtalk-basic-behavior → dta-basic-behavior}/references/truth-and-recovery.md +0 -0
  119. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/adapters.md +0 -0
  120. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/assembly-guidance.md +0 -0
  121. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/binding.md +0 -0
  122. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/cold-start.md +0 -0
  123. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/consent-and-visibility.md +0 -0
  124. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/consolidation.md +0 -0
  125. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/event-ingest.md +0 -0
  126. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/guided-setup.md +0 -0
  127. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/model.md +0 -0
  128. /package/skills/core/{dingtalk-people-group-memory → dta-people-group-memory}/references/storage-port.md +0 -0
  129. /package/skills/platforms/multica-dingtalk/{dingtalk-agent-deploy-multica → dta-deploy-multica}/references/multica-deployment-contract.md +0 -0
  130. /package/skills/platforms/multica-dingtalk/{dingtalk-agent-deploy-multica → dta-deploy-multica}/references/promotion-observation-contract.md +0 -0
  131. /package/skills/platforms/multica-dingtalk/{multica-external → dta-ops-multica}/scripts/multica_ext.py +0 -0
@@ -31,7 +31,7 @@ import { runRobotEvaluation } from '../src/robot-evals.js';
31
31
  import { runOpenCodeEvaluation } from '../src/opencode-evals.js';
32
32
  import { runStorageEvaluation } from '../src/storage-evals.js';
33
33
  import { runPersonalEventEvaluation } from '../src/personal-event-evals.js';
34
- import { doctor } from '../src/doctor.js';
34
+ import { CHECK_LABELS, doctor } from '../src/doctor.js';
35
35
  import { doctorDevelopmentWorkspace, inspectAgentProject, showDevelopmentWorkspace, } from '../src/development-workspace.js';
36
36
  import { buildScheduleShow, buildSchedulePlan } from '../src/schedule-plan.js';
37
37
  import { applyOpenCodeWorkspace, evalOpenCodeWorkspace, planOpenCodeWorkspace, runOpenCodeWorkspace, useOpenCodeWorkspace, } from '../src/opencode-provider.js';
@@ -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
  }
@@ -856,9 +994,14 @@ async function main() {
856
994
  }
857
995
  if (o.json)
858
996
  console.log(JSON.stringify(out, null, 2));
859
- else if ('skills' in out)
997
+ else if ('skills' in out) {
860
998
  for (const item of out.skills)
861
999
  printSkillStatus(item, sub, dryRun);
1000
+ // 静默删目录会让人以为什么都没发生;说清楚删了哪几个旧名。
1001
+ for (const item of out.prunedLegacy || []) {
1002
+ console.log(` 已清理改名前的旧副本 ${item.name} → 现用 ${item.replacedBy}`);
1003
+ }
1004
+ }
862
1005
  else
863
1006
  printSkillStatus(out, sub, dryRun);
864
1007
  return;
@@ -913,7 +1056,7 @@ async function main() {
913
1056
  if (o.json)
914
1057
  console.log(JSON.stringify({ ...out, endpoint, readiness, targets, doc }, null, 2));
915
1058
  else {
916
- console.log(`✅ 工作区已归属 ${out.definition?.label}(写入 ${out.written})`);
1059
+ console.log(`${mark('pass', '✅')} 工作区已归属 ${strong(out.definition?.label)}(写入 ${noun(out.written)})`);
917
1060
  for (const install of out.skillInstalls)
918
1061
  printSkillStatus(install, 'install', false);
919
1062
  if (!out.skillInstalls.length) {
@@ -953,14 +1096,14 @@ async function main() {
953
1096
  if (o.json)
954
1097
  console.log(JSON.stringify(out, null, 2));
955
1098
  else {
956
- console.log(`✅ ${out.mode === 'workspace' ? '已装载 Workspace' : '直接会话模式'}`);
1099
+ console.log(`${mark('pass', '✅')} ${strong(out.mode === 'workspace' ? '已装载 Workspace' : '直接会话模式')}`);
957
1100
  console.log(` scope=${out.scopeId} initialized=${out.initialized}`);
958
1101
  console.log(` agent=${out.definition.id} definition=${out.definition.status}`);
959
1102
  if (!out.mounts.length)
960
- console.log(' 没有发现持久上下文;这不是错误,也不需要自动 init。');
1103
+ console.log(muted(' 没有发现持久上下文;这不是错误,也不需要自动 init。'));
961
1104
  for (const mount of out.mounts)
962
- console.log(` ${mount.slot}: ${mount.path}`);
963
- console.log(` ${out.note}`);
1105
+ console.log(` ${mount.slot}: ${noun(mount.path)}`);
1106
+ console.log(` ${muted(out.note)}`);
964
1107
  }
965
1108
  return;
966
1109
  }
@@ -1346,9 +1489,9 @@ async function main() {
1346
1489
  if (o.json)
1347
1490
  console.log(JSON.stringify(out, null, 2));
1348
1491
  else if (!out.found)
1349
- console.log('当前 Session 尚无 Task checkpoint。');
1492
+ console.log(muted('当前 Session 尚无 Task checkpoint。'));
1350
1493
  else {
1351
- console.log(`✅ Task ${out.checkpoint.taskId} · ${out.checkpoint.status}`);
1494
+ console.log(`${mark('pass', '✅')} Task ${noun(out.checkpoint.taskId)} · ${out.checkpoint.status}`);
1352
1495
  console.log(` revision=${out.checkpoint.revision} hash=${out.hash}`);
1353
1496
  console.log(` next=${out.checkpoint.nextAction || '-'}`);
1354
1497
  }
@@ -1373,7 +1516,7 @@ async function main() {
1373
1516
  if (o.json || !o.live)
1374
1517
  console.log(JSON.stringify(out, null, 2));
1375
1518
  else {
1376
- console.log(`${out.verified ? '✅' : '⚠️'} Operational Memory · ${out.mode}`);
1519
+ console.log(`${mark(out.verified ? 'pass' : 'warn', out.verified ? '✅' : '⚠️')} ${strong('Operational Memory')} · ${out.mode}`);
1377
1520
  console.log(` record=${out.recordId || '-'} verification=${out.verification}`);
1378
1521
  }
1379
1522
  if (out.mode === 'uncertain')
@@ -1427,12 +1570,12 @@ async function main() {
1427
1570
  if (o.json)
1428
1571
  console.log(JSON.stringify(out, null, 2));
1429
1572
  else if (action === 'publish') {
1430
- console.log(`${out.verified ? '✅' : out.mode === 'dry-run' ? '🔎' : '⚠️'} Candidate ${o.id}`);
1573
+ console.log(`${mark(out.verified ? 'pass' : out.mode === 'dry-run' ? 'muted' : 'warn', out.verified ? '✅' : out.mode === 'dry-run' ? '🔎' : '⚠️')} Candidate ${noun(o.id)}`);
1431
1574
  console.log(` mode=${out.mode} targetHash=${out.currentTargetHash}`);
1432
1575
  }
1433
1576
  else {
1434
- console.log(`✅ Candidate ${out.candidate.id} · ${out.candidate.status}`);
1435
- console.log(` revision=${out.candidate.revision} path=${out.path}`);
1577
+ console.log(`${mark('pass', '✅')} Candidate ${noun(out.candidate.id)} · ${out.candidate.status}`);
1578
+ console.log(` revision=${out.candidate.revision} path=${noun(out.path)}`);
1436
1579
  }
1437
1580
  if (action === 'publish' && out.mode === 'uncertain')
1438
1581
  process.exitCode = 2;
@@ -1463,10 +1606,10 @@ async function main() {
1463
1606
  if (o.json || o['dry-run'])
1464
1607
  console.log(JSON.stringify(out, null, 2));
1465
1608
  else {
1466
- console.log(`${out.verified ? '✅' : '⚠️'} ${out.kind} · ${out.outcome} · ${out.toState}`);
1467
- console.log(` action=${out.actionId} run=${out.runId}`);
1609
+ console.log(`${mark(out.verified ? 'pass' : 'warn', out.verified ? '✅' : '⚠️')} ${strong(out.kind)} · ${out.outcome} · ${out.toState}`);
1610
+ console.log(` action=${noun(out.actionId)} run=${noun(out.runId)}`);
1468
1611
  if (!out.verified)
1469
- console.log(` ${out.verification}`);
1612
+ console.log(` ${muted(out.verification)}`);
1470
1613
  }
1471
1614
  if (out.outcome === 'uncertain')
1472
1615
  process.exitCode = 2;
@@ -1538,11 +1681,41 @@ function editDistance(a, b) {
1538
1681
  }
1539
1682
  return row[b.length];
1540
1683
  }
1684
+ /** 按语义给状态标记上色;字形原样返回,不做任何替换。 */
1685
+ function mark(level, text) {
1686
+ const { theme } = stdoutUi();
1687
+ return level === 'pass' ? theme.success(text)
1688
+ : level === 'warn' ? theme.warn(text)
1689
+ : level === 'fail' ? theme.danger(text)
1690
+ : theme.dim(text);
1691
+ }
1692
+ /** 可复制的名词:路径、版本号、ID、命令。 */
1693
+ function noun(text) {
1694
+ return stdoutUi().theme.noun(text);
1695
+ }
1696
+ /** 次要信息:补充说明、括注、下一步提示。 */
1697
+ function muted(text) {
1698
+ return stdoutUi().theme.dim(text);
1699
+ }
1700
+ /** 标题行 / key=value 的结构性强调。 */
1701
+ function strong(text) {
1702
+ return stdoutUi().theme.bold(text);
1703
+ }
1704
+ /** ready 布尔 → 语义级别,printX 里到处都是这个三态。 */
1705
+ function levelOf(state) {
1706
+ if (state === true)
1707
+ return 'pass';
1708
+ if (state === false)
1709
+ return 'fail';
1710
+ return state;
1711
+ }
1541
1712
  function printDispatch(out, json = false) {
1542
1713
  if (json)
1543
1714
  return console.log(JSON.stringify(out, null, 2));
1544
- const mark = out.duplicate ? (out.launch ? '🔁 REDELIVER' : '↩️ DUPLICATE') : '✅ READY';
1545
- console.log(`${mark} ${out.runId}`);
1715
+ const state = out.duplicate
1716
+ ? mark(out.launch ? 'warn' : 'muted', out.launch ? '🔁 REDELIVER' : '↩️ DUPLICATE')
1717
+ : mark('pass', '✅ READY');
1718
+ console.log(`${state} ${noun(out.runId)}`);
1546
1719
  console.log(` Field=${out.fieldId} Session=${out.sessionId} Event=${out.eventKind}`);
1547
1720
  console.log(` cwd=${out.cwd}`);
1548
1721
  console.log(` entrypoint=${out.entrypoint} queue=${out.queue.key} (max=${out.queue.maxConcurrency})`);
@@ -1552,7 +1725,7 @@ function printDispatch(out, json = false) {
1552
1725
  }
1553
1726
  function printLab(out) {
1554
1727
  const passed = out.ready ?? out.passed ?? out.assertions?.passed;
1555
- console.log(`${passed === false ? '❌' : '✅'} ${out.$schema || 'dingtalk-agent/lab'}`);
1728
+ console.log(`${mark(levelOf(passed !== false), passed === false ? '❌' : '✅')} ${out.$schema || 'dingtalk-agent/lab'}`);
1556
1729
  if (out.mode)
1557
1730
  console.log(` mode=${out.mode}`);
1558
1731
  if (out.marker)
@@ -1561,17 +1734,17 @@ function printLab(out) {
1561
1734
  console.log(` evidence=${out.evidencePath}`);
1562
1735
  if (Array.isArray(out.checks)) {
1563
1736
  for (const check of out.checks) {
1564
- console.log(` ${check.passed ? 'PASS' : 'FAIL'} ${check.id}: ${check.detail}`);
1737
+ console.log(` ${mark(levelOf(Boolean(check.passed)), check.passed ? 'PASS' : 'FAIL')} ${check.id}: ${check.detail}`);
1565
1738
  }
1566
1739
  }
1567
1740
  }
1568
1741
  function printAgentAudit(out) {
1569
- console.log(`dingtalk-agent agent audit · ${out.ready ? 'READY' : 'PARTIAL'}`);
1742
+ console.log(`${strong('dingtalk-agent agent audit')} · ${mark(out.ready ? 'pass' : 'warn', out.ready ? 'READY' : 'PARTIAL')}`);
1570
1743
  console.log(` definition=${out.definition.hash} storage=${out.storageMode}`);
1571
1744
  console.log(` dingtalkSideEffect=${out.dingtalkSideEffect} sideEffect=${out.sideEffect}`);
1572
1745
  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}`);
1746
+ const word = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1747
+ console.log(` ${mark(levelOf(check.level), word)} ${check.id}: ${check.summary}`);
1575
1748
  }
1576
1749
  if (out.repairs.length) {
1577
1750
  console.log('\n修复建议:');
@@ -1584,7 +1757,7 @@ function printAgentAudit(out) {
1584
1757
  }
1585
1758
  function printAgentEnhance(out) {
1586
1759
  if (out.$schema === 'dingtalk-agent/agent-enhancement-plan@1') {
1587
- console.log(`dingtalk-agent agent enhance · ${out.ready ? 'READY PLAN' : 'BLOCKED'}`);
1760
+ console.log(`${strong('dingtalk-agent agent enhance')} · ${mark(out.ready ? 'pass' : 'fail', out.ready ? 'READY PLAN' : 'BLOCKED')}`);
1588
1761
  console.log(` planId=${out.planId} project=${out.projectName}`);
1589
1762
  console.log(` sideEffect=${out.sideEffect} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1590
1763
  for (const operation of out.operations) {
@@ -1594,12 +1767,12 @@ function printAgentEnhance(out) {
1594
1767
  console.log(` REVIEW ${out.semanticReview.files.join(', ')}: ${out.semanticReview.why}`);
1595
1768
  }
1596
1769
  for (const blocker of out.blockers)
1597
- console.log(` BLOCK ${blocker}`);
1770
+ console.log(` ${mark('fail', 'BLOCK')} ${blocker}`);
1598
1771
  if (out.ready)
1599
1772
  console.log(`\nApply:\n ${out.apply.command}`);
1600
1773
  return;
1601
1774
  }
1602
- console.log('dingtalk-agent agent enhance · APPLIED');
1775
+ console.log(`${strong('dingtalk-agent agent enhance')} · ${mark('pass', 'APPLIED')}`);
1603
1776
  console.log(` operation=${out.operationId} planId=${out.planId}`);
1604
1777
  console.log(` changes=${out.changes.length} idempotent=${out.idempotent}`);
1605
1778
  if (out.backupRoot)
@@ -1607,8 +1780,8 @@ function printAgentEnhance(out) {
1607
1780
  console.log(` audit=${out.audit.status} missing=${out.audit.missing.join(', ') || '-'}`);
1608
1781
  }
1609
1782
  function printAgentPlatform(platform) {
1610
- console.log(`${platform.status === 'supported' ? '✅' : '⏳'} ${platform.name} · ${platform.label} · ${platformStatusLabel(platform.status)}`);
1611
- console.log(` ${platform.description}`);
1783
+ console.log(`${mark(platform.status === 'supported' ? 'pass' : 'muted', platform.status === 'supported' ? '✅' : '⏳')} ${strong(platform.name)} · ${platform.label} · ${platformStatusLabel(platform.status)}`);
1784
+ console.log(` ${muted(platform.description)}`);
1612
1785
  for (const skill of platform.skills)
1613
1786
  console.log(` 技能[${skill.role}] ${skill.name} —— ${skill.purpose}`);
1614
1787
  if (platform.commands.length)
@@ -1616,12 +1789,12 @@ function printAgentPlatform(platform) {
1616
1789
  }
1617
1790
  function printAgentPlatformResolution(out) {
1618
1791
  if (!out.platform) {
1619
- console.log('⚠️ 当前工作区未声明 managed agent platform');
1792
+ console.log(mark('warn', '⚠️ 当前工作区未声明 managed agent platform'));
1620
1793
  console.log(' 运行 `dta agent-platform use multica-dingtalk`,或设置 DTA_AGENT_PLATFORM 环境变量。');
1621
1794
  return;
1622
1795
  }
1623
1796
  const known = out.definition;
1624
- console.log(`${known ? '✅' : '❌'} 当前 platform: ${out.platform}${known ? ` · ${known.label} · ${platformStatusLabel(known.status)}` : '(未知)'}`);
1797
+ console.log(`${mark(levelOf(Boolean(known)), known ? '✅' : '❌')} 当前 platform: ${strong(out.platform)}${known ? ` · ${known.label} · ${platformStatusLabel(known.status)}` : '(未知)'}`);
1625
1798
  console.log(` 来源: ${out.source}${out.file ? ` · ${out.file}` : ''}`);
1626
1799
  for (const skill of known?.skills || [])
1627
1800
  console.log(` 技能[${skill.role}] ${skill.name} —— ${skill.purpose}`);
@@ -1629,8 +1802,9 @@ function printAgentPlatformResolution(out) {
1629
1802
  // 披露:dta 层平台命令关联到平台内确切的 Skill(诊断信息走 stderr,不污染 --json stdout)。
1630
1803
  function disclosePlatformSkill(resolution, role) {
1631
1804
  const skillName = resolution.definition ? platformSkillForRole(resolution.definition.name, role) : null;
1632
- if (skillName)
1633
- console.error(`提示: 平台 ${resolution.definition.name} 的该命令方法学由 Skill ${skillName} 承载`);
1805
+ if (skillName) {
1806
+ console.error(stderrUi().theme.dim(`提示: 平台 ${resolution.definition.name} 的该命令方法学由 Skill ${skillName} 承载`));
1807
+ }
1634
1808
  }
1635
1809
  function printEndpoint(endpoint) {
1636
1810
  if (!endpoint)
@@ -1644,9 +1818,9 @@ function printEndpoint(endpoint) {
1644
1818
  console.log(` Endpoint: 未解析——设 ${endpoint.envVar} 或登录 multica 后生效`);
1645
1819
  return;
1646
1820
  }
1647
- const mark = endpoint.confirmed ? '✅' : '⚠️';
1821
+ const glyph = mark(endpoint.confirmed ? 'pass' : 'warn', endpoint.confirmed ? '✅' : '⚠️');
1648
1822
  const note = endpoint.confirmed ? '' : '(建议/未确认,deploy 前需显式确认是预发还是生产)';
1649
- console.log(` ${mark} Endpoint: ${endpoint.endpoint} · 来源: ${endpoint.source}${note}`);
1823
+ console.log(` ${glyph} Endpoint: ${noun(endpoint.endpoint)} · 来源: ${endpoint.source}${muted(note)}`);
1650
1824
  console.log(` (切换:设 ${endpoint.envVar}=<url>、写 dingtalk-agent.json#multicaEndpoint、或登录对应 profile;无需改代码)`);
1651
1825
  }
1652
1826
  function printPlatformDoc(platformName) {
@@ -1654,27 +1828,27 @@ function printPlatformDoc(platformName) {
1654
1828
  return;
1655
1829
  const path = platformDocPath(PACKAGE_ROOT, platformName);
1656
1830
  if (path)
1657
- console.log(` 平台说明: ${path}\n (切换到该平台后请阅读,了解各技能用途与交付链)`);
1831
+ console.log(` 平台说明: ${noun(path)}\n${muted(' (切换到该平台后请阅读,了解各技能用途与交付链)')}`);
1658
1832
  }
1659
1833
  function printMulticaTargets(targets) {
1660
1834
  if (!targets.length)
1661
1835
  return;
1662
- console.log(' 本机 Multica 登录目标(发布前必须与用户确认 endpoint 与 workspace):');
1836
+ console.log(strong(' 本机 Multica 登录目标(发布前必须与用户确认 endpoint 与 workspace):'));
1663
1837
  for (const target of targets) {
1664
1838
  console.log(` - profile=${target.profile} · ${target.serverUrl}${target.workspaceId ? ` · workspace=${target.workspaceId}` : ''}`);
1665
1839
  }
1666
1840
  }
1667
1841
  function printAgentPlatformReadiness(checks) {
1668
1842
  for (const check of checks) {
1669
- console.log(` ${check.ok ? '✅' : '⚠️'} ${check.summary}`);
1843
+ console.log(` ${mark(check.ok ? 'pass' : 'warn', check.ok ? '✅' : '⚠️')} ${check.summary}`);
1670
1844
  if (check.hint)
1671
- console.log(` ${check.hint}`);
1845
+ console.log(` ${muted(check.hint)}`);
1672
1846
  }
1673
1847
  }
1674
1848
  function printSkillStatus(out, action, dryRun) {
1675
- const prefix = dryRun ? 'DRY-RUN' : '✅';
1849
+ const prefix = dryRun ? mark('muted', 'DRY-RUN') : mark('pass', '✅');
1676
1850
  const verb = action === 'status' ? '全局 Skill 状态' : `skill ${action}`;
1677
- console.log(`${prefix} ${verb}: ${out.name}`);
1851
+ console.log(`${prefix} ${verb}: ${strong(out.name)}`);
1678
1852
  console.log(` manager=${out.manager} bundled=${out.bundled.skillVersion || '-'}`);
1679
1853
  console.log(` canonical=${out.canonical.path}`);
1680
1854
  console.log(` installed=${out.canonical.exists} ` +
@@ -1685,71 +1859,110 @@ function printSkillStatus(out, action, dryRun) {
1685
1859
  ` → ${out.operation.after.installedVersion}(${out.operation.after.state})`);
1686
1860
  }
1687
1861
  if (out.operation)
1688
- console.log(` delegated: ${out.operation.command}`);
1862
+ console.log(` delegated: ${noun(out.operation.command)}`);
1689
1863
  for (const client of out.clients) {
1690
- console.log(` ${client.label}=${client.state} (${client.discovery}: ${client.path})`);
1864
+ console.log(` ${client.label}=${mark(client.state === 'ok' ? 'pass' : 'warn', client.state)} (${client.discovery}: ${noun(client.path)})`);
1691
1865
  }
1692
1866
  if (action === 'install' && !dryRun) {
1693
- console.log(' 新 Agent 会话将自动发现;当前会话未发现时请重启 Claude Code/Codex。');
1867
+ console.log(muted(' 新 Agent 会话将自动发现;当前会话未发现时请重启 Claude Code/Codex。'));
1694
1868
  }
1695
1869
  }
1870
+ /**
1871
+ * doctor 的版面。改造前的问题不是"不够花哨",是三条实打实的:
1872
+ * 1. 同一事实说两遍——⚠️ 摘要和它的 detail 重复平台 Skill 漂移;三个客户端
1873
+ * 的 Skill 可见性在 check 区和「本机 Coding Agent」区各说一次。
1874
+ * 2. 一行塞太多——detail 用 ` | ` 把四条 canonical 路径和平台 Skill 状态拼在
1875
+ * 一起,200+ 字符,终端里必然折行。
1876
+ * 3. 分隔符混用 `·` `;` `|` 三种,没有一列是对齐的。
1877
+ * 所以这里按「一行一件事、明细缩进、列对齐」重排,并把客户端合并成一节。
1878
+ */
1696
1879
  function printDoctor(out) {
1697
- console.log(`dingtalk-agent doctor · ${out.ready ? 'READY' : 'NOT READY'}`);
1698
- for (const check of out.checks) {
1699
- const mark = check.level === 'pass' ? '✅' : check.level === 'warn' ? '⚠️' : '❌';
1700
- console.log(`${mark} ${check.summary}`);
1701
- if (check.detail)
1702
- console.log(` ${check.detail}`);
1703
- if (check.fix)
1704
- console.log(` 修复: ${check.fix}`);
1705
- }
1706
- if (out.hosts.length) {
1707
- // Host 面回答"本地能在哪跑",不改变上面的 ready 结论。
1708
- console.log('\n本机 Coding Agent:');
1709
- const width = Math.max(...out.hosts.map((host) => displayWidth(host.label)));
1710
- for (const host of out.hosts) {
1711
- const label = host.label + ' '.repeat(width - displayWidth(host.label));
1712
- const where = host.cli.found
1713
- ? [host.cli.path, host.cli.version].filter(Boolean).join(' ')
1714
- : `未找到 ${host.cli.command}`;
1715
- console.log(` ${host.cli.found ? '' : '❌'} ${label} ${where}`);
1716
- console.log(` Skill 可见性: ${host.skillExposure.exists ? '已暴露' : '未暴露'} · ${host.skillExposureRoot}`);
1717
- }
1718
- }
1719
- if (out.nextSteps.length) {
1720
- console.log('\n下一步:');
1721
- for (const step of out.nextSteps)
1722
- console.log(` ${step}`);
1880
+ const { theme } = stdoutUi();
1881
+ // 字形沿用全 CLI 既定的 ✅/⚠️/❌(bin 里各出现 24/11/5 次)。上一版换成
1882
+ // ✔/!/✗ doctor 成了唯一的异类,也违反 AGENTS.md「stdout 是稳定的人/
1883
+ // 机器接口」——颜色可以加,承载语义的字形不能动。三者都是 2 列宽,对齐不受影响。
1884
+ const glyph = (level) => level === 'pass' ? mark('pass', '✅')
1885
+ : level === 'warn' ? mark('warn', '⚠️') : mark('fail', '❌');
1886
+ const clientIds = new Set(['claude-code', 'codex', 'opencode']);
1887
+ const envChecks = out.checks.filter((check) => !clientIds.has(check.id));
1888
+ const clientChecks = out.checks.filter((check) => clientIds.has(check.id));
1889
+ console.log(`${strong('dingtalk-agent doctor')} · ${out.ready ? mark('pass', 'READY') : mark('fail', 'NOT READY')}`);
1890
+ console.log('');
1891
+ // 左列按显示宽度对齐——中文标签用 String.length 补齐必然错位
1892
+ const labelWidth = Math.max(...envChecks.map((check) => displayWidth(CHECK_LABELS[check.id])));
1893
+ for (const check of envChecks) {
1894
+ const label = padRight(CHECK_LABELS[check.id], labelWidth);
1895
+ console.log(` ${glyph(check.level)} ${strong(label)} ${check.value || check.summary}`);
1896
+ const items = check.items || [];
1897
+ const itemWidth = items.length ? Math.max(...items.map((i) => displayWidth(i.label))) : 0;
1898
+ const valueWidth = items.length ? Math.max(...items.map((i) => displayWidth(i.value || ''))) : 0;
1899
+ for (const item of items) {
1900
+ console.log(` ${noun(padRight(item.label, itemWidth))} ${padRight(item.value || '', valueWidth)}${item.note ? ` ${muted(item.note)}` : ''}`);
1901
+ }
1902
+ if (check.level !== 'pass' && check.fix) {
1903
+ // 一条命令一行。挤在同一行里用「与」串起来的命令没法直接复制。
1904
+ const commands = plain(check.fix).replace(/^运行\s*/, '').split(/\s*与\s*/);
1905
+ commands.forEach((command, index) => {
1906
+ console.log(` ${muted(index === 0 ? '修复' : ' ')} ${noun(command)}`);
1907
+ });
1908
+ }
1909
+ }
1910
+ if (clientChecks.length) {
1911
+ console.log('');
1912
+ console.log(` ${strong('Coding Agent')}`);
1913
+ const nameWidth = Math.max(...clientChecks.map((c) => displayWidth(CHECK_LABELS[c.id])));
1914
+ const hostOf = (id) => out.hosts.find((host) => host.name === id);
1915
+ // 版本列去掉冗余括注与前缀:claude 报 "2.1.218 (Claude Code)"、codex 报 "codex-cli 0.144.6"
1916
+ const versions = clientChecks.map((c) => (hostOf(c.id)?.cli.version || '')
1917
+ .replace(/\s*\(.*\)\s*$/, '').replace(/^\S+-cli\s+/, ''));
1918
+ const versionWidth = Math.max(...versions.map(displayWidth));
1919
+ clientChecks.forEach((check, index) => {
1920
+ const host = hostOf(check.id);
1921
+ const name = padRight(CHECK_LABELS[check.id], nameWidth);
1922
+ const version = padRight(versions[index], versionWidth);
1923
+ const where = host?.cli.found ? tilde(host.skillExposureRoot) : `未安装 ${host?.cli.command || ''}`;
1924
+ console.log(` ${glyph(check.level)} ${strong(name)} ${muted(version)} ${check.value || check.summary} ${noun(where)}`);
1925
+ });
1926
+ }
1927
+ // 「下一步」此前逐字重复上面已经打过的修复命令。只留没展示过的。
1928
+ const shown = new Set(out.checks.filter((c) => c.level !== 'pass' && c.fix).map((c) => c.fix));
1929
+ const remaining = out.nextSteps.filter((step) => !shown.has(step));
1930
+ if (remaining.length) {
1931
+ console.log('');
1932
+ for (const step of remaining)
1933
+ console.log(` ${strong('下一步')} ${noun(plain(step))}`);
1723
1934
  }
1724
1935
  }
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;
1936
+ /** 反引号在终端里不是强调,是噪声;着色已经承担了同一职责。 */
1937
+ function plain(text) {
1938
+ return text.replace(/`/g, '');
1939
+ }
1940
+ /** 家目录缩成 ~/,省掉对读者零信息量的前缀。 */
1941
+ function tilde(path) {
1942
+ const home = process.env.HOME || '';
1943
+ return home && path.startsWith(home) ? `~${path.slice(home.length)}` : path;
1731
1944
  }
1732
1945
  function printProjectInfo(out) {
1733
- console.log(`dingtalk-agent Project · ${out.project.name}`);
1946
+ console.log(`${strong('dingtalk-agent Project')} · ${noun(out.project.name)}`);
1734
1947
  console.log(` root=${out.root}`);
1735
1948
  console.log(` source=${out.source} manifest=${out.manifest || '(synthetic legacy)'}`);
1736
1949
  console.log(` hash=${out.manifestHash} dta=${out.project.dtaVersion}`);
1737
1950
  console.log(` current=${out.currentWorkspace || '(not selected)'}`);
1738
1951
  for (const workspace of out.workspaces) {
1739
- console.log(` ${workspace.current ? '*' : '-'} ${workspace.name} · ${workspace.provider.kind} · ${workspace.status}`);
1952
+ console.log(` ${workspace.current ? strong('*') : muted('-')} ${workspace.name} · ${workspace.provider.kind} · ${workspace.status}`);
1740
1953
  }
1741
1954
  }
1742
1955
  function printWorkspaceList(out) {
1743
- console.log(`dingtalk-agent workspaces · ${out.project.name}`);
1956
+ console.log(`${strong('dingtalk-agent workspaces')} · ${noun(out.project.name)}`);
1744
1957
  if (!out.workspaces.length)
1745
- console.log(' 尚未声明 Development Workspace。');
1958
+ console.log(muted(' 尚未声明 Development Workspace。'));
1746
1959
  for (const workspace of out.workspaces) {
1747
- console.log(` ${workspace.current ? '*' : '-'} ${workspace.name} provider=${workspace.provider.kind} ` +
1960
+ console.log(` ${workspace.current ? strong('*') : muted('-')} ${workspace.name} provider=${workspace.provider.kind} ` +
1748
1961
  `stage=${workspace.stage} status=${workspace.status}`);
1749
1962
  }
1750
1963
  }
1751
1964
  function printDevelopmentWorkspace(out) {
1752
- console.log(`dingtalk-agent workspace · ${out.name}`);
1965
+ console.log(`${strong('dingtalk-agent workspace')} · ${noun(out.name)}`);
1753
1966
  console.log(` provider=${out.provider.kind} stage=${out.stage} status=${out.status}`);
1754
1967
  console.log(` desired=${out.desiredHash} observed=${out.observedHash || '-'}`);
1755
1968
  console.log(` current=${out.current} legacy=${out.legacy}`);
@@ -1759,19 +1972,22 @@ function printDevelopmentWorkspace(out) {
1759
1972
  console.log(` source=${source}`);
1760
1973
  }
1761
1974
  function printDevelopmentWorkspaceDoctor(out) {
1762
- console.log(`dingtalk-agent workspace doctor · ${out.workspace} · ${out.ready ? 'READY' : 'PARTIAL'}`);
1975
+ console.log(`${strong('dingtalk-agent workspace doctor')} · ${noun(out.workspace)} · ${mark(out.ready ? 'pass' : 'warn', out.ready ? 'READY' : 'PARTIAL')}`);
1763
1976
  console.log(` provider=${out.provider} status=${out.status}`);
1764
1977
  console.log(` sideEffect=${out.sideEffect} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1765
1978
  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}`);
1979
+ const word = check.level === 'pass' ? 'PASS' : check.level === 'warn' ? 'WARN' : 'FAIL';
1980
+ console.log(` ${mark(levelOf(check.level), word)} ${check.id}: ${check.summary}`);
1768
1981
  if (check.fix && check.level !== 'pass')
1769
- console.log(` fix: ${check.fix}`);
1982
+ console.log(` fix: ${noun(check.fix)}`);
1770
1983
  }
1771
1984
  }
1772
1985
  function printOpenCodeWorkspaceOperation(out) {
1773
1986
  const applied = out.$schema === 'dingtalk-agent/opencode-workspace-apply@1';
1774
- console.log(`${applied ? out.applied ? '✅' : '↩️' : 'DRY-RUN'} OpenCode Workspace ${out.workspace}`);
1987
+ const glyph = applied
1988
+ ? mark(out.applied ? 'pass' : 'muted', out.applied ? '✅' : '↩️')
1989
+ : mark('muted', 'DRY-RUN');
1990
+ console.log(`${glyph} OpenCode Workspace ${noun(out.workspace)}`);
1775
1991
  console.log(` action=${out.action} model=${out.model}`);
1776
1992
  console.log(` desired=${out.desiredHash} observed=${out.observedHash || '-'}`);
1777
1993
  console.log(` managed=${out.managedPath}`);
@@ -1781,7 +1997,7 @@ function printOpenCodeWorkspaceOperation(out) {
1781
1997
  function printMulticaWorkspaceOperation(out) {
1782
1998
  const passed = out.passed ?? out.readyForApply ?? out.blocking?.length === 0;
1783
1999
  const mode = out.remoteRead ? 'REMOTE-READ' : 'DRY-RUN';
1784
- console.log(`${passed ? '✅' : '⚠️'} ${mode} Multica Workspace ${out.workspace}`);
2000
+ console.log(`${mark(passed ? 'pass' : 'warn', passed ? '✅' : '⚠️')} ${mode} Multica Workspace ${noun(out.workspace)}`);
1785
2001
  console.log(` schema=${out.$schema} profile=${out.profile || '-'}`);
1786
2002
  if (out.planId)
1787
2003
  console.log(` plan=${out.planId}`);
@@ -1802,7 +2018,7 @@ function printMulticaWorkspaceOperation(out) {
1802
2018
  console.log(` remoteWrite=${out.remoteWrite} dingtalkSideEffect=${out.dingtalkSideEffect}`);
1803
2019
  }
1804
2020
  function printMulticaDeployment(out) {
1805
- console.log(`Multica deploy: ${out.workspace || '<unknown>'}`);
2021
+ console.log(`${strong('Multica deploy')}: ${noun(out.workspace || '<unknown>')}`);
1806
2022
  if (out.planId)
1807
2023
  console.log(` plan: ${out.planId}`);
1808
2024
  if (out.operationId)
@@ -1825,7 +2041,7 @@ function printMulticaDeployment(out) {
1825
2041
  console.log(' triggers: unchanged');
1826
2042
  }
1827
2043
  function printPromotion(out) {
1828
- console.log(`Promotion: ${out.promotionId || out.candidateId || out.candidate?.candidateId || '<none>'}`);
2044
+ console.log(`${strong('Promotion')}: ${noun(out.promotionId || out.candidateId || out.candidate?.candidateId || '<none>')}`);
1829
2045
  if (out.planId)
1830
2046
  console.log(` plan: ${out.planId}`);
1831
2047
  if (out.routeId)
@@ -1876,33 +2092,84 @@ function rejectWorkspaceOptions(values, allowed, command) {
1876
2092
  fail(`${command} 不接受参数: ${extras.join(', ')}`);
1877
2093
  }
1878
2094
  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}`);
2095
+ console.log(`${out.dryRun ? mark('muted', 'DRY-RUN') : mark('pass', '✅')} ${strong('dingtalk-agent setup')}`);
2096
+ console.log(` CLI: ${noun(out.cli.executable)}`);
2097
+ console.log(` 短命令: ${noun(out.cli.alias)}`);
2098
+ console.log(` Skill: ${noun(out.skill.canonical.path)}`);
1883
2099
  if (!out.shell.pathReady) {
1884
- console.log(` 当前 shell 尚未加载 PATH;本次终端执行: ${out.shell.activateCommand}`);
2100
+ console.log(` 当前 shell 尚未加载 PATH;本次终端执行: ${noun(out.shell.activateCommand)}`);
1885
2101
  if (out.shell.rcFile)
1886
- console.log(` 新终端会从 ${out.shell.rcFile} 自动加载`);
2102
+ console.log(muted(` 新终端会从 ${out.shell.rcFile} 自动加载`));
1887
2103
  }
1888
2104
  printDoctor(out.doctor);
1889
- console.log(`\n开始使用: ${out.nextCommand}`);
2105
+ console.log(`\n开始使用: ${noun(out.nextCommand)}`);
2106
+ }
2107
+ /**
2108
+ * 确认之前的抬头:告诉人「将要去哪」,好让 [y/N] 是个有信息的决定。
2109
+ *
2110
+ * 三态必须分开说。只判 outdated 会让 `--version <旧版> --force` 显示成
2111
+ * "已是最新版本",用户确认之后却真的降级——在唯一的不可逆动作前给了反的信息。
2112
+ */
2113
+ function printUpgradePreamble(checked, options) {
2114
+ const { theme } = stderrUi();
2115
+ const arrow = (from, to, paint) => `${theme.dim(from)} ${theme.bold('→')} ${paint(to)}`;
2116
+ if (checked.relation === 'same' && !options.force && !options.dryRun) {
2117
+ console.error(` ${theme.success('✔')} 已是最新版本 ${theme.bold(checked.currentVersion)}`);
2118
+ console.error(theme.dim(' 仍会重新校验环境;只想查版本可用 dta upgrade --check'));
2119
+ return;
2120
+ }
2121
+ const label = checked.relation === 'upgrade' ? '新版本可用'
2122
+ : checked.relation === 'downgrade' ? '降级' : '重装';
2123
+ const value = checked.relation === 'upgrade'
2124
+ ? arrow(checked.currentVersion, checked.targetVersion, theme.success)
2125
+ : checked.relation === 'downgrade'
2126
+ ? `${arrow(checked.currentVersion, checked.targetVersion, theme.warn)}${theme.warn('(降级)')}`
2127
+ : `${theme.bold(checked.targetVersion)}${theme.dim('(与当前版本相同,将强制重装)')}`;
2128
+ for (const line of renderPairs([
2129
+ [label, value],
2130
+ ['通道', `${checked.channel} ${theme.dim(checked.pinnedSource)}`],
2131
+ ]))
2132
+ console.error(line);
2133
+ console.error('');
2134
+ }
2135
+ function printUpgradeCheck(checked) {
2136
+ const { theme } = stdoutUi();
2137
+ const glyph = checked.relation === 'upgrade' ? theme.warn('⬆️')
2138
+ : checked.relation === 'downgrade' ? theme.warn('⬇️') : theme.success('✅');
2139
+ const summary = checked.relation === 'upgrade'
2140
+ ? `${theme.dim(checked.currentVersion)} → ${theme.success(checked.targetVersion)}`
2141
+ : checked.relation === 'downgrade'
2142
+ ? `${theme.dim(checked.currentVersion)} → ${theme.warn(checked.targetVersion)}(目标更旧)`
2143
+ : `${theme.bold(checked.currentVersion)}(已是最新)`;
2144
+ console.log(`${glyph} dta upgrade --check: ${summary}`);
2145
+ console.log(` target=${theme.noun(checked.pinnedSource)} channel=${checked.channel}`);
2146
+ if (checked.relation === 'upgrade')
2147
+ console.log(` ${theme.dim('运行 dta upgrade 执行升级')}`);
2148
+ if (checked.relation === 'downgrade') {
2149
+ console.log(` ${theme.dim(`降级需显式确认: dta upgrade --version ${checked.targetVersion} --force`)}`);
2150
+ }
1890
2151
  }
1891
2152
  function printUpgrade(out) {
1892
- const mark = out.dryRun ? 'DRY-RUN' : out.ready ? '✅' : '⚠️';
1893
- const relation = out.changed ? `${out.currentVersion} ${out.targetVersion}` : `${out.targetVersion}(已是当前版本)`;
2153
+ const { theme } = stdoutUi();
2154
+ const mark = out.dryRun ? theme.dim('DRY-RUN') : out.ready ? theme.success('✅') : theme.warn('⚠️');
2155
+ const relation = out.changed
2156
+ ? `${theme.dim(out.currentVersion)} → ${theme.success(out.targetVersion)}`
2157
+ : `${out.targetVersion}(已是当前版本)`;
1894
2158
  console.log(`${mark} dta upgrade: ${relation}`);
1895
- console.log(` target=${out.target}`);
1896
- console.log(` CLI=${out.executable}`);
2159
+ console.log(` target=${theme.noun(out.target)}`);
2160
+ console.log(` CLI=${theme.noun(out.executable)}`);
1897
2161
  if (out.dryRun) {
1898
- console.log(` 将执行: ${out.commands.install}`);
1899
- console.log(` 将复核: ${out.commands.verify}`);
2162
+ console.log(` 将执行: ${theme.noun(out.commands.install)}`);
2163
+ console.log(` 将复核: ${theme.noun(out.commands.verify)}`);
2164
+ console.log(` ${theme.dim('移除 --dry-run 以实际执行升级')}`);
1900
2165
  }
1901
2166
  else if (out.ready) {
1902
2167
  console.log(' setup / DWS / Skill / Claude Code / Codex / OpenCode 全部 ready');
2168
+ // 出口指引:验证命令 + 后悔药,都是可以直接复制的
2169
+ console.log(` ${theme.dim(`验证: dta --version${out.changed ? ` 回退: dta upgrade --version ${out.currentVersion} --force` : ''}`)}`);
1903
2170
  }
1904
2171
  else {
1905
- console.log(` CLI 已更新;环境复核未完全 ready,请运行: ${out.commands.verify}`);
2172
+ console.log(` CLI 已更新;环境复核未完全 ready,请运行: ${theme.noun(out.commands.verify)}`);
1906
2173
  }
1907
2174
  }
1908
2175
  //# sourceMappingURL=dingtalk-agent.js.map