@xdxer/dingtalk-agent 0.1.5-beta.2 → 0.1.5-beta.4

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 (72) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.en.md +92 -63
  3. package/README.md +92 -63
  4. package/dist/bin/dingtalk-agent.js +142 -15
  5. package/dist/bin/dingtalk-agent.js.map +1 -1
  6. package/dist/src/agent-audit.js +69 -55
  7. package/dist/src/agent-audit.js.map +1 -1
  8. package/dist/src/agent-enhance.js +49 -30
  9. package/dist/src/agent-enhance.js.map +1 -1
  10. package/dist/src/agent-platform.js +1 -0
  11. package/dist/src/agent-platform.js.map +1 -1
  12. package/dist/src/bootstrap.js +6 -2
  13. package/dist/src/bootstrap.js.map +1 -1
  14. package/dist/src/development-workspace.js +108 -18
  15. package/dist/src/development-workspace.js.map +1 -1
  16. package/dist/src/multica-deploy.js +128 -18
  17. package/dist/src/multica-deploy.js.map +1 -1
  18. package/dist/src/multica-provider.js +157 -2
  19. package/dist/src/multica-provider.js.map +1 -1
  20. package/dist/src/opencode-provider.js +17 -5
  21. package/dist/src/opencode-provider.js.map +1 -1
  22. package/dist/src/schedule-plan.js +105 -0
  23. package/dist/src/schedule-plan.js.map +1 -0
  24. package/dist/src/skills.js +2 -0
  25. package/dist/src/skills.js.map +1 -1
  26. package/dist/src/workspace.js +11 -6
  27. package/dist/src/workspace.js.map +1 -1
  28. package/docs/ARCHITECTURE.md +142 -24
  29. package/docs/INSTALLATION.md +1 -1
  30. package/docs/PRIOR-ART.md +4 -0
  31. package/docs/SELF-TEST.md +1 -1
  32. package/docs/architecture/agent-platform-connection-layer.svg +120 -0
  33. package/docs/architecture/digital-employee-composition.svg +92 -0
  34. package/docs/architecture/dingtalk-agent-architecture.svg +125 -0
  35. package/docs/assets/digital-employee-at-work.svg +77 -0
  36. package/docs/schemas/multica-workspace-run.schema.json +150 -33
  37. package/docs/schemas/project.schema.json +27 -0
  38. package/docs/schemas/workspace-scaffold.schema.json +37 -0
  39. package/examples/agents/README.md +9 -7
  40. package/examples/agents/fde-coach/AGENTS.md +2 -34
  41. package/examples/agents/fde-coach/agent/AGENTS.md +35 -0
  42. package/examples/agents/fde-coach/agent.bindings.json +10 -0
  43. package/examples/agents/release-manager/AGENTS.md +2 -34
  44. package/examples/agents/release-manager/agent/AGENTS.md +35 -0
  45. package/examples/agents/release-manager/agent.bindings.json +10 -0
  46. package/lab/project-workspace/fake-multica-provider.mjs +43 -8
  47. package/lab/project-workspace/opencode-provider-suite.json +1 -1
  48. package/lab/robot-eval/suite.json +1 -1
  49. package/package.json +2 -2
  50. package/skills/core/dingtalk-agent-compose/SKILL.md +25 -18
  51. package/skills/core/dingtalk-agent-compose/assets/AGENTS.template.md +1 -1
  52. package/skills/core/dingtalk-agent-compose/assets/REPOSITORY.template.md +10 -0
  53. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.dingtalk-doc.template.json +2 -2
  54. package/skills/core/dingtalk-agent-compose/assets/agent.bindings.local.template.json +2 -2
  55. package/skills/core/dingtalk-agent-compose/assets/hosts/opencode/opencode.template.json +2 -1
  56. package/skills/core/dingtalk-agent-compose/evals/evals.json +1 -1
  57. package/skills/core/dingtalk-agent-compose/references/agent-definition-contract.md +6 -6
  58. package/skills/core/dingtalk-agent-compose/references/drive-and-schedules.md +124 -0
  59. package/skills/core/dingtalk-agent-compose/references/host-loading-contract.md +10 -12
  60. package/skills/core/dingtalk-agent-compose/references/hosts/claude-code.md +13 -12
  61. package/skills/core/dingtalk-agent-compose/references/hosts/opencode.md +13 -12
  62. package/skills/core/dingtalk-basic-behavior/SKILL.md +11 -7
  63. package/skills/core/dingtalk-basic-behavior/references/event-to-behavior.md +15 -1
  64. package/skills/core/dingtalk-basic-behavior/references/perception-and-gates.md +5 -0
  65. package/skills/core/dingtalk-basic-behavior/references/risk-authority-and-privacy.md +12 -0
  66. package/skills/platforms/deap/PLATFORM.md +30 -1
  67. package/skills/platforms/multica-dingtalk/PLATFORM.md +25 -0
  68. package/skills/platforms/multica-dingtalk/dingtalk-agent-deploy-multica/SKILL.md +3 -2
  69. package/skills/platforms/multica-dingtalk/multica-external/SKILL.md +15 -0
  70. package/docs/assets/agent-delivery-lifecycle.svg +0 -103
  71. /package/examples/agents/fde-coach/{skills → agent/skills}/fde-coach/SKILL.md +0 -0
  72. /package/examples/agents/release-manager/{skills → agent/skills}/release-manager/SKILL.md +0 -0
@@ -33,9 +33,10 @@ import { runStorageEvaluation } from '../src/storage-evals.js';
33
33
  import { runPersonalEventEvaluation } from '../src/personal-event-evals.js';
34
34
  import { doctor } from '../src/doctor.js';
35
35
  import { doctorDevelopmentWorkspace, inspectAgentProject, showDevelopmentWorkspace, } from '../src/development-workspace.js';
36
+ import { buildScheduleShow, buildSchedulePlan } from '../src/schedule-plan.js';
36
37
  import { applyOpenCodeWorkspace, evalOpenCodeWorkspace, planOpenCodeWorkspace, runOpenCodeWorkspace, useOpenCodeWorkspace, } from '../src/opencode-provider.js';
37
- import { inspectMulticaWorkspace, listMulticaWorkspaceResources, planMulticaWorkspace, statusMulticaWorkspace, } from '../src/multica-provider.js';
38
- import { applyMulticaDeployment, listMulticaDeployments, planMulticaDeployment, runMulticaWorkspaceIssue, statusMulticaDeployment, } from '../src/multica-deploy.js';
38
+ import { inspectMulticaWorkspace, listMulticaWorkspaceResources, planMulticaWorkspace, scaffoldMulticaWorkspace, statusMulticaWorkspace, } from '../src/multica-provider.js';
39
+ import { applyMulticaDeployment, listMulticaDeployments, planMulticaDeployment, runMulticaWorkspaceIssue, statusMulticaDeployment, statusMulticaWorkspaceRun, } from '../src/multica-deploy.js';
39
40
  import { applyObservation, applyPromotion, listPromotions, planObservation, planPromotion, statusPromotion, } from '../src/promotion.js';
40
41
  import { setup } from '../src/setup.js';
41
42
  import { upgradeAgent } from '../src/upgrade.js';
@@ -65,6 +66,7 @@ dta —— 给 Agent 安装钉钉员工的基础行为和工作环境
65
66
  dta bootstrap --json 为当前 Agent 会话加载工作区
66
67
  dta agent enhance / audit 安全增强已有仓库,再审计定义、存储与 Skill 真加载
67
68
  dta info / dta workspace doctor <name> 查看 Project 并只读诊断 Workspace
69
+ dta schedule show / plan --workspace <name> 查看声明的常驻节律并生成 provider 部署计划
68
70
  dta agent-platform use <platform> → dta deploy / dta promote 声明平台归属并装平台技能包,再受控部署与晋级
69
71
 
70
72
  维护环境:
@@ -155,7 +157,7 @@ const DEPLOY_HELP = `
155
157
  dingtalk-agent Multica 受控部署
156
158
 
157
159
  deploy --workspace <name> --dry-run [--json]
158
- deploy --workspace <name> --plan-id <id> --yes [--no-wait] [--json]
160
+ deploy --workspace <name> --plan-id <id> --yes [--wait | --no-wait] [--json]
159
161
  deploy --workspace <name> --status [--operation-id <id>] [--json]
160
162
  deploy --workspace <name> --status --operation-id <id> --execute --yes [--json]
161
163
  deploy --workspace <name> --list [--json]
@@ -163,6 +165,9 @@ dingtalk-agent Multica 受控部署
163
165
  deploy --workspace <name> --retire --plan-id <id> --yes [--json]
164
166
 
165
167
  dry-run 不启动 Multica。apply/retire 必须携带当前 planId;scope 或源码漂移会在写入前拒绝。
168
+ apply 默认在同一条命令内等 load smoke 到 ~30 秒;云端 runtime 冷启常超 30 秒会返回 verifying,
169
+ 再用 --status --operation-id 独立 reconcile。加 --wait 把等待预算放宽到 4 分钟,一条命令直接到 ready;
170
+ --no-wait 立即返回 verifying(异步/CI)。--smoke-timeout <ms> 精确覆盖等待预算(上限 5 分钟)。
166
171
  status 默认只验本地脱敏 operation/Receipt;--execute --yes 才做远端独立回读。
167
172
  deploy 只管理 Agent、完整 Skill tree、assignment 和 load smoke,不创建机器人、Webhook、Autopilot 或定时 Trigger。
168
173
  `;
@@ -245,6 +250,7 @@ async function main() {
245
250
  workspace: { type: 'string' }, json: { type: 'boolean' },
246
251
  'dry-run': { type: 'boolean' }, yes: { type: 'boolean' },
247
252
  'plan-id': { type: 'string' }, 'no-wait': { type: 'boolean' },
253
+ wait: { type: 'boolean' },
248
254
  status: { type: 'boolean' }, list: { type: 'boolean' },
249
255
  execute: { type: 'boolean' }, 'operation-id': { type: 'string' },
250
256
  timeout: { type: 'string' }, 'smoke-timeout': { type: 'string' },
@@ -265,16 +271,18 @@ async function main() {
265
271
  const timeoutMs = parseOptionalTimeout(o.timeout, '--timeout');
266
272
  const smokeTimeoutMs = parseOptionalTimeout(o['smoke-timeout'], '--smoke-timeout');
267
273
  let out;
274
+ if (o.wait && o['no-wait'])
275
+ fail('deploy --wait 与 --no-wait 互斥');
268
276
  if (o.list) {
269
- if (o.execute || o['operation-id'] || o.retire || o['plan-id'] || o['no-wait'] ||
277
+ if (o.execute || o['operation-id'] || o.retire || o['plan-id'] || o['no-wait'] || o.wait ||
270
278
  o.timeout || o['smoke-timeout']) {
271
279
  fail('deploy --list 只接受 --workspace 和 --json');
272
280
  }
273
281
  out = listMulticaDeployments(PROJECT_START, o.workspace, PACKAGE_JSON.version);
274
282
  }
275
283
  else if (o.status) {
276
- if (o.retire || o['plan-id'] || o['no-wait'] || o['dry-run'] || o['smoke-timeout']) {
277
- fail('deploy --status 不接受 retire/plan-id/no-wait/dry-run/smoke-timeout');
284
+ if (o.retire || o['plan-id'] || o['no-wait'] || o.wait || o['dry-run'] || o['smoke-timeout']) {
285
+ fail('deploy --status 不接受 retire/plan-id/no-wait/wait/dry-run/smoke-timeout');
278
286
  }
279
287
  if (Boolean(o.execute) !== Boolean(o.yes)) {
280
288
  fail('deploy --status 远端 reconcile 必须同时传 --execute --yes');
@@ -285,9 +293,9 @@ async function main() {
285
293
  });
286
294
  }
287
295
  else if (o['dry-run']) {
288
- if (o.execute || o['operation-id'] || o['plan-id'] || o['no-wait'] ||
296
+ if (o.execute || o['operation-id'] || o['plan-id'] || o['no-wait'] || o.wait ||
289
297
  o.timeout || o['smoke-timeout']) {
290
- fail('deploy --dry-run 不接受 execute/operation-id/plan-id/no-wait/timeout/smoke-timeout');
298
+ fail('deploy --dry-run 不接受 execute/operation-id/plan-id/no-wait/wait/timeout/smoke-timeout');
291
299
  }
292
300
  out = planMulticaDeployment(PROJECT_START, o.workspace, {
293
301
  action: o.retire ? 'retire' : 'apply', cliVersion: PACKAGE_JSON.version,
@@ -297,12 +305,16 @@ async function main() {
297
305
  if (o.execute || o['operation-id'] || o.status || o.list || o['dry-run']) {
298
306
  fail('deploy apply 不接受 execute/operation-id/status/list/dry-run');
299
307
  }
300
- if (o.retire && (o['no-wait'] || o['smoke-timeout'])) {
301
- fail('deploy --retire 不接受 no-wait/smoke-timeout');
308
+ if (o.retire && (o['no-wait'] || o.wait || o['smoke-timeout'])) {
309
+ fail('deploy --retire 不接受 no-wait/wait/smoke-timeout');
302
310
  }
311
+ // --wait widens the in-band smoke-wait budget so one command reaches ready across a
312
+ // cold-start runtime; an explicit --smoke-timeout still wins. Default stays ~30s.
313
+ const effectiveSmokeTimeoutMs = smokeTimeoutMs !== undefined
314
+ ? smokeTimeoutMs : o.wait ? 240_000 : undefined;
303
315
  out = applyMulticaDeployment(PROJECT_START, o.workspace, {
304
316
  yes: o.yes, planId: o['plan-id'], noWait: o['no-wait'],
305
- timeoutMs, smokeTimeoutMs, cliVersion: PACKAGE_JSON.version,
317
+ timeoutMs, smokeTimeoutMs: effectiveSmokeTimeoutMs, cliVersion: PACKAGE_JSON.version,
306
318
  }, o.retire ? 'retire' : 'apply');
307
319
  }
308
320
  if (o.json)
@@ -413,6 +425,65 @@ async function main() {
413
425
  printProjectInfo(out);
414
426
  return;
415
427
  }
428
+ if (cmd === 'schedule') {
429
+ const sub = argv[1];
430
+ const { values: o, positionals } = parseArgs({
431
+ args: argv.slice(2), allowPositionals: true,
432
+ options: { json: { type: 'boolean' }, workspace: { type: 'string' } },
433
+ });
434
+ if (sub === 'show') {
435
+ const out = buildScheduleShow(PROJECT_START, PACKAGE_JSON.version);
436
+ if (o.json) {
437
+ console.log(JSON.stringify(out, null, 2));
438
+ return;
439
+ }
440
+ if (out.count === 0) {
441
+ console.log('本 Project 未声明任何常驻节律(schedules)。');
442
+ return;
443
+ }
444
+ console.log(`声明的常驻节律(internalized cron) · ${out.count} 条`);
445
+ for (const s of out.schedules) {
446
+ console.log(`\n ${s.name} ${s.cron} ${s.timezone} [${s.mode}]`);
447
+ if (s.wake)
448
+ console.log(` 唤醒 ${s.wake}`);
449
+ if (s.completion)
450
+ console.log(` ②判据 ${s.completion}`);
451
+ }
452
+ if (!out.minutesDistinct) {
453
+ console.log(`\n⚠️ 分钟位冲突: ${out.collidingMinutes.join(', ')} —— 外发类同分钟并发会重复送,请错开`);
454
+ process.exitCode = 2;
455
+ }
456
+ else {
457
+ console.log('\n✓ 各节律分钟位互不相同(外发防重复的静态前提满足)');
458
+ }
459
+ return;
460
+ }
461
+ if (sub === 'plan') {
462
+ const workspaceName = o.workspace || positionals[0];
463
+ if (!workspaceName)
464
+ fail('schedule plan 需要 --workspace <name>');
465
+ const info = inspectAgentProject(PROJECT_START, PACKAGE_JSON.version);
466
+ const plan = buildSchedulePlan(info, workspaceName);
467
+ if (o.json) {
468
+ console.log(JSON.stringify(plan, null, 2));
469
+ return;
470
+ }
471
+ console.log(`schedule 部署计划 · workspace=${plan.workspace} · provider=${plan.provider}`);
472
+ if (!plan.supported) {
473
+ console.log(`\n✗ 不支持: ${plan.reason}`);
474
+ console.log(` ${plan.reconcile}`);
475
+ process.exitCode = 2;
476
+ return;
477
+ }
478
+ console.log(` ${plan.count} 条声明 → provider ops:\n`);
479
+ for (const s of plan.schedules)
480
+ console.log(` # ${s.name}\n ${s.applyCommand}\n`);
481
+ console.log(`执行: ${plan.reconcile}`);
482
+ return;
483
+ }
484
+ fail(`可用: dta schedule show | plan --workspace <name>${suggest(sub || '', ['show', 'plan'], 'dta schedule')}`);
485
+ return;
486
+ }
416
487
  if (cmd === 'workspace') {
417
488
  const { values: o, positionals } = parseArgs({
418
489
  args: argv.slice(2), allowPositionals: true,
@@ -423,6 +494,8 @@ async function main() {
423
494
  cases: { type: 'string' }, lanes: { type: 'string' }, runs: { type: 'string' },
424
495
  out: { type: 'string' }, timeout: { type: 'string' },
425
496
  'previous-skill': { type: 'string' },
497
+ status: { type: 'boolean' }, 'run-id': { type: 'string' },
498
+ provider: { type: 'string' }, stage: { type: 'string' }, profile: { type: 'string' },
426
499
  },
427
500
  });
428
501
  if (sub === 'list') {
@@ -544,16 +617,46 @@ async function main() {
544
617
  return;
545
618
  }
546
619
  if (sub === 'create') {
547
- rejectWorkspaceOptions(o, ['json', 'yes', 'dry-run'], 'workspace create');
548
620
  if (positionals.length !== 1)
549
621
  fail('workspace create 需要且只接受一个 Workspace name');
550
622
  if (o.yes && o['dry-run'])
551
623
  fail('workspace create 的 --dry-run 与 --yes 不能同时使用');
624
+ const wsName = positionals[0];
625
+ // Resolve the provider kind to scaffold/build: explicit --provider wins, else an already
626
+ // declared Workspace keeps its kind, else the attributed platform's provider (registry-
627
+ // driven so deap inherits it), else opencode. multica has no local host — create authors
628
+ // its config entry; opencode keeps building the managed host.
629
+ if (o.provider && !['opencode', 'multica'].includes(String(o.provider))) {
630
+ fail('workspace create --provider 只支持 opencode 或 multica');
631
+ }
632
+ const declaredWs = inspectAgentProject(PROJECT_START, PACKAGE_JSON.version)
633
+ .workspaces.find((item) => item.name === wsName);
634
+ const platformProvider = resolveAgentPlatform(PROJECT_START).definition?.provider;
635
+ const kind = String(o.provider || declaredWs?.provider.kind || platformProvider || 'opencode');
636
+ if (declaredWs && o.provider && declaredWs.provider.kind !== kind) {
637
+ fail(`Workspace ${wsName} 已声明为 ${declaredWs.provider.kind},与 --provider ${kind} 冲突`);
638
+ }
639
+ if (kind === 'multica') {
640
+ rejectWorkspaceOptions(o, ['json', 'yes', 'dry-run', 'provider', 'stage', 'profile'], 'workspace create');
641
+ const out = scaffoldMulticaWorkspace(PROJECT_START, wsName, {
642
+ stage: o.stage, profile: o.profile, apply: o.yes, cliVersion: PACKAGE_JSON.version,
643
+ });
644
+ if (o.json)
645
+ console.log(JSON.stringify(out, null, 2));
646
+ else {
647
+ const tag = out.alreadyDeclared ? '已存在' : out.applied ? '已写入' : 'DRY-RUN';
648
+ console.log(`${tag} workspace ${out.workspace} · provider=multica · profile=${out.profile}`);
649
+ for (const step of out.nextSteps)
650
+ console.log(` ${step}`);
651
+ }
652
+ return;
653
+ }
654
+ rejectWorkspaceOptions(o, ['json', 'yes', 'dry-run', 'provider'], 'workspace create');
552
655
  const out = o.yes
553
- ? applyOpenCodeWorkspace(PROJECT_START, positionals[0], {
656
+ ? applyOpenCodeWorkspace(PROJECT_START, wsName, {
554
657
  yes: true, cliVersion: PACKAGE_JSON.version,
555
658
  })
556
- : planOpenCodeWorkspace(PROJECT_START, positionals[0], PACKAGE_JSON.version);
659
+ : planOpenCodeWorkspace(PROJECT_START, wsName, PACKAGE_JSON.version);
557
660
  if (o.json)
558
661
  console.log(JSON.stringify(out, null, 2));
559
662
  else
@@ -572,11 +675,35 @@ async function main() {
572
675
  return;
573
676
  }
574
677
  if (sub === 'run') {
678
+ const timeoutMs = o.timeout === undefined ? undefined : Number(o.timeout);
679
+ if (o.status) {
680
+ // Resume a timed-out multica run by re-reading the SAME Issue; no new Issue is created.
681
+ rejectWorkspaceOptions(o, ['json', 'yes', 'execute', 'out', 'timeout', 'status', 'run-id'], 'workspace run --status');
682
+ if (positionals.length !== 1)
683
+ fail('workspace run --status 需要一个 Workspace name');
684
+ if (o['prompt-file'])
685
+ fail('workspace run --status 不接受 --prompt-file;用 --run-id 续读');
686
+ if (!o['run-id'])
687
+ fail('workspace run --status 需要 --run-id <上次 run 的 runId>');
688
+ const out = statusMulticaWorkspaceRun(PROJECT_START, positionals[0], {
689
+ runId: o['run-id'], execute: o.execute, yes: o.yes, timeoutMs, out: o.out,
690
+ cliVersion: PACKAGE_JSON.version,
691
+ });
692
+ if (o.json)
693
+ console.log(JSON.stringify(out, null, 2));
694
+ else {
695
+ console.log(`${out.passed ? '✅' : '❌'} workspace run ${out.runId} (resumed)`);
696
+ if (out.answer)
697
+ console.log(out.answer);
698
+ }
699
+ if (!out.passed)
700
+ process.exitCode = 2;
701
+ return;
702
+ }
575
703
  rejectWorkspaceOptions(o, ['json', 'yes', 'execute', 'prompt-file', 'out', 'timeout'], 'workspace run');
576
704
  if (positionals.length !== 1 || !o['prompt-file']) {
577
705
  fail('workspace run 需要一个 Workspace name 和 --prompt-file <file>');
578
706
  }
579
- const timeoutMs = o.timeout === undefined ? undefined : Number(o.timeout);
580
707
  const prompt = readProjectText(PROJECT_START, o['prompt-file'], 'workspace run prompt');
581
708
  const workspace = showDevelopmentWorkspace(PROJECT_START, positionals[0], PACKAGE_JSON.version);
582
709
  const out = workspace.provider.kind === 'multica'