@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
@@ -12,6 +12,7 @@ import { resolvePackageRoot } from './package-root.js';
12
12
  import { bundledSkillPath } from './skill-manager.js';
13
13
  import { createIsolatedOpenCodeHost } from './opencode-isolation.js';
14
14
  const COMPOSE_TEMPLATE_MARKER = /<(?:Agent 名称|岗位\/角色|人群、团队或工作场域|长期目标|主动负责的事项|可观察的交付物|明确不做或必须升级确认的事项|岗位稳定的输入、判断、交付与验收范式|何时自行推进、何时交给谁|本体级常见错误 [12]|纠偏动作 [12]|Role Skill names|role-skill-name|Role Skill 名称|岗位职责或工作流|领域判断、输入与交付物|相邻职责或明确交接边界|岗位特有的禁区或必须升级条件|领域输入|领域方法\/SOP|领域常见错误|领域纠偏动作|可观察结果 [12]|route)>/u;
15
+ const BASIC = 'dingtalk-basic-behavior';
15
16
  const BASIC_INSTRUCTION = '.agents/skills/dingtalk-basic-behavior/SKILL.md';
16
17
  const DEFINITION_PROBE_PROMPT = '这是 Agent Definition 继承探针。只依据已强制加载的角色宪法末尾注释回答;' +
17
18
  '严格输出纯文本 dta-definition-probe=<值>,若看不到则输出纯文本 ' +
@@ -77,28 +78,33 @@ export function auditAgent(root, options = {}) {
77
78
  }
78
79
  }
79
80
  const basic = readCanonicalBasicSkill();
80
- const basicExposurePath = join(rootReal, '.agents', 'skills', 'dingtalk-basic-behavior', 'SKILL.md');
81
+ const packagedBasic = definition.skills.find((item) => item.name === BASIC);
82
+ const basicExposurePath = packagedBasic?.path || join(rootReal, '.agents', 'skills', BASIC, 'SKILL.md');
81
83
  const basicExposure = inspectSkill(basicExposurePath);
82
84
  const basicExposureTree = inspectSkillTree(basicExposurePath);
83
85
  add('host.basic-exposure', 'host', basicExposure.exists && basicExposure.name === basic.name &&
84
86
  basicExposure.version === basic.version && basicExposure.hash === basic.hash &&
85
87
  basicExposureTree.hash === basic.treeHash ? 'pass' : 'fail', true, basicExposure.exists && basicExposure.hash === basic.hash &&
86
88
  basicExposureTree.hash === basic.treeHash
87
- ? 'OpenCode Basic Skill 全树 exposure 与 canonical source 一致'
88
- : 'OpenCode Basic Skill 入口、references 或 assets 缺失或发生漂移', { expected: basic, actual: { ...basicExposure, treeHash: basicExposureTree.hash,
89
+ ? 'Agent package 的 Basic Skill 全树与 canonical source 一致'
90
+ : 'Agent package 的 Basic Skill 入口、references 或 assets 缺失或发生漂移', { expected: basic, actual: { ...basicExposure, treeHash: basicExposureTree.hash,
89
91
  files: basicExposureTree.files, error: basicExposureTree.error } });
90
92
  const config = inspectOpenCodeConfig(rootReal);
91
93
  const definitionInstruction = definition.body?.path
92
94
  ? relative(rootReal, definition.body.path).split('\\').join('/') : '';
93
95
  const definitionInstructionCount = countInstructionsForPath(rootReal, config.instructions, definitionInstruction);
94
- const definitionRuleReady = !config.error && definitionInstruction === 'AGENTS.md' &&
95
- definitionInstructionCount === 0;
96
+ const definitionInstructionExpected = definitionInstruction === 'AGENTS.md' ? 0 : 1;
97
+ const definitionRuleReady = !config.error && Boolean(definitionInstruction) &&
98
+ definitionInstructionCount === definitionInstructionExpected;
96
99
  add('host.definition-rule', 'host', definitionRuleReady
97
100
  ? 'pass' : 'fail', true, definitionRuleReady
98
- ? 'OpenCode 使用项目根 AGENTS.md 原生 rule,且未重复声明 custom instruction'
99
- : 'Agent Definition 必须是项目根 AGENTS.md,且不能重复加入 opencode instructions', { path: config.path, error: config.error, instruction: definitionInstruction,
101
+ ? definitionInstruction === 'AGENTS.md'
102
+ ? 'OpenCode 使用项目根开发兼容模式的原生 Agent Definition'
103
+ : 'OpenCode 以唯一 custom instruction 加载独立 Agent Definition'
104
+ : 'Agent Definition 未形成唯一加载路径', { path: config.path, error: config.error, instruction: definitionInstruction,
100
105
  instructionCount: definitionInstructionCount });
101
- const instructionCount = countInstructionsForPath(rootReal, config.instructions, '.agents/skills/dingtalk-basic-behavior/SKILL.md');
106
+ const basicInstruction = relative(rootReal, basicExposurePath).split('\\').join('/');
107
+ const instructionCount = countInstructionsForPath(rootReal, config.instructions, basicInstruction);
102
108
  add('host.basic-instruction', 'host', !config.error && instructionCount === 1 &&
103
109
  config.permissions['dingtalk-basic-behavior'] === 'allow' ? 'pass' : 'fail', true, !config.error && instructionCount === 1 &&
104
110
  config.permissions['dingtalk-basic-behavior'] === 'allow'
@@ -107,12 +113,10 @@ export function auditAgent(root, options = {}) {
107
113
  permission: config.permissions['dingtalk-basic-behavior'] || '' });
108
114
  for (const name of requiredSkills) {
109
115
  const source = roleSkills.get(name);
110
- const exposure = inspectSkill(join(rootReal, '.agents', 'skills', name, 'SKILL.md'));
111
116
  const permission = config.permissions[name] || '';
112
- const matched = Boolean(source?.hash && exposure.exists && exposure.name === name &&
113
- exposure.hash === source.hash && permission === 'allow');
114
- add(`host.role-exposure.${name}`, 'host', matched ? 'pass' : 'fail', true, matched ? `Role Skill ${name} exposure 与 Definition 一致`
115
- : `Role Skill ${name} exposure、hash 或 permission 不一致`, { sourceHash: source?.hash || '', exposure, permission });
117
+ const matched = Boolean(source?.hash && source.path && permission === 'allow');
118
+ add(`host.role-exposure.${name}`, 'host', matched ? 'pass' : 'fail', true, matched ? `Role Skill ${name} 单一发布源与 Host permission 一致`
119
+ : `Role Skill ${name} 发布源或 permission 不一致`, { sourceHash: source?.hash || '', sourcePath: source?.path || '', permission });
116
120
  }
117
121
  const staticPrerequisitesReady = checks
118
122
  .filter((item) => item.blocking)
@@ -129,7 +133,7 @@ export function auditAgent(root, options = {}) {
129
133
  if (!options.yes)
130
134
  throw new Error('agent audit --verify-load 会调用 OpenCode;必须同时传 --yes');
131
135
  if (staticPrerequisitesReady) {
132
- const execution = executeLoadAudit(rootReal, options, loadTargetHash, definitionInstruction, effectiveModel, () => currentLoadTargetHash(rootReal, options, requiredSkills, effectiveModel));
136
+ const execution = executeLoadAudit(rootReal, options, loadTargetHash, definitionInstruction, basicInstruction, effectiveModel, () => currentLoadTargetHash(rootReal, options, requiredSkills, effectiveModel));
133
137
  loadReport = execution.report;
134
138
  loadReportPath = execution.evidencePath;
135
139
  verifiedReportPath = execution.reportPath;
@@ -374,17 +378,14 @@ function currentLoadTargetHash(root, options, requiredSkills, model) {
374
378
  const hydrated = bootstrap(root, { ...(options.bootstrap || {}), deferRemote: true });
375
379
  const definition = hydrated.definition;
376
380
  const basic = readCanonicalBasicSkill();
377
- const exposedPath = join(root, '.agents', 'skills', 'dingtalk-basic-behavior', 'SKILL.md');
381
+ const packagedBasic = definition.skills.find((item) => item.name === BASIC);
382
+ const exposedPath = packagedBasic?.path || join(root, '.agents', 'skills', BASIC, 'SKILL.md');
378
383
  const exposed = inspectSkill(exposedPath);
379
384
  const exposedTree = inspectSkillTree(exposedPath);
380
385
  const config = inspectOpenCodeConfig(root);
381
386
  const roleSkills = new Map(definition.skills
382
387
  .filter((item) => item.name !== 'dingtalk-basic-behavior')
383
388
  .map((item) => [item.name, item]));
384
- const roleExposureHashes = Object.fromEntries(requiredSkills.map((name) => [
385
- name,
386
- inspectSkill(join(root, '.agents', 'skills', name, 'SKILL.md')).hash || '',
387
- ]));
388
389
  const roleSourceHashes = Object.fromEntries(requiredSkills.map((name) => [
389
390
  name, roleSkills.get(name)?.hash || '',
390
391
  ]));
@@ -402,11 +403,10 @@ function currentLoadTargetHash(root, options, requiredSkills, model) {
402
403
  opencodeConfigHash: config.hash,
403
404
  requiredSkills,
404
405
  roleSourceHashes,
405
- roleExposureHashes,
406
406
  model,
407
407
  }));
408
408
  }
409
- function executeLoadAudit(root, options, targetHash, definitionInstruction, model, revalidate) {
409
+ function executeLoadAudit(root, options, targetHash, definitionInstruction, basicInstruction, model, revalidate) {
410
410
  const runId = `agent_audit_${Date.now()}_${randomUUID().slice(0, 8)}`;
411
411
  const outputInspection = inspectContainedPath(root, options.out || join('.dingtalk-agent', 'agent-audit', 'results', runId));
412
412
  const outputRoot = outputInspection.path;
@@ -424,8 +424,8 @@ function executeLoadAudit(root, options, targetHash, definitionInstruction, mode
424
424
  const host = createIsolatedOpenCodeHost(model.split('/')[0]);
425
425
  try {
426
426
  const command = process.env.DTA_OPENCODE_BIN || 'opencode';
427
- const sourcePreflight = inspectSourceOpenCodeRuntime(command, root, host.environment, definitionInstruction);
428
- materializeAuditProbeWorkspace(root, auditWorkspace, definitionInstruction);
427
+ const sourcePreflight = inspectSourceOpenCodeRuntime(command, root, host.environment, definitionInstruction, basicInstruction);
428
+ materializeAuditProbeWorkspace(root, auditWorkspace, definitionInstruction, basicInstruction);
429
429
  const suitePath = join(auditWorkspace, 'suite.json');
430
430
  writeAtomic(suitePath, JSON.stringify({
431
431
  $schema: 'dingtalk-agent/robot-eval-suite@1',
@@ -494,19 +494,19 @@ function executeLoadAudit(root, options, targetHash, definitionInstruction, mode
494
494
  rmSync(auditWorkspace, { recursive: true, force: true });
495
495
  }
496
496
  }
497
- function materializeAuditProbeWorkspace(sourceRoot, targetRoot, definitionInstruction) {
498
- if (definitionInstruction !== 'AGENTS.md') {
499
- throw new Error('OpenCode 原生 Definition 探针只接受项目根 AGENTS.md');
500
- }
497
+ function materializeAuditProbeWorkspace(sourceRoot, targetRoot, definitionInstruction, basicInstruction) {
501
498
  mkdirSync(targetRoot, { recursive: true });
502
- writeAtomic(join(targetRoot, 'AGENTS.md'), readFileSync(join(sourceRoot, 'AGENTS.md'), 'utf8'));
503
- const sourceBasic = join(sourceRoot, '.agents', 'skills', 'dingtalk-basic-behavior');
499
+ writeAtomic(join(targetRoot, definitionInstruction), readFileSync(join(sourceRoot, definitionInstruction), 'utf8'));
500
+ const sourceBasic = dirname(join(sourceRoot, basicInstruction));
504
501
  const targetBasic = join(targetRoot, '.agents', 'skills', 'dingtalk-basic-behavior');
505
502
  mkdirSync(dirname(targetBasic), { recursive: true });
506
503
  cpSync(sourceBasic, targetBasic, { recursive: true });
507
504
  const config = {
508
505
  $schema: 'https://opencode.ai/config.json',
509
- instructions: [BASIC_INSTRUCTION],
506
+ instructions: [
507
+ ...(definitionInstruction === 'AGENTS.md' ? [] : [definitionInstruction]),
508
+ BASIC_INSTRUCTION,
509
+ ],
510
510
  permission: { skill: { 'dingtalk-basic-behavior': 'allow' } },
511
511
  plugin: [],
512
512
  mcp: {},
@@ -515,19 +515,21 @@ function materializeAuditProbeWorkspace(sourceRoot, targetRoot, definitionInstru
515
515
  };
516
516
  writeAtomic(join(targetRoot, 'opencode.json'), JSON.stringify(config, null, 2) + '\n');
517
517
  }
518
- function inspectSourceOpenCodeRuntime(command, root, environment, definitionInstruction) {
518
+ function inspectSourceOpenCodeRuntime(command, root, environment, definitionInstruction, basicInstruction) {
519
519
  const parent = mkdtempSync(join(tmpdir(), 'dta-source-config-preflight-'));
520
520
  const workspace = join(parent, 'workspace');
521
521
  let stdout = '';
522
522
  try {
523
523
  mkdirSync(workspace, { recursive: true });
524
524
  cpSync(join(root, 'opencode.json'), join(workspace, 'opencode.json'));
525
- if (existsSync(join(root, 'AGENTS.md'))) {
526
- cpSync(join(root, 'AGENTS.md'), join(workspace, 'AGENTS.md'));
525
+ if (existsSync(join(root, definitionInstruction))) {
526
+ const target = join(workspace, definitionInstruction);
527
+ mkdirSync(dirname(target), { recursive: true });
528
+ cpSync(join(root, definitionInstruction), target);
527
529
  }
528
- const basic = join(root, '.agents', 'skills', 'dingtalk-basic-behavior');
530
+ const basic = dirname(join(root, basicInstruction));
529
531
  if (existsSync(basic)) {
530
- const target = join(workspace, '.agents', 'skills', 'dingtalk-basic-behavior');
532
+ const target = dirname(join(workspace, basicInstruction));
531
533
  mkdirSync(dirname(target), { recursive: true });
532
534
  cpSync(basic, target, {
533
535
  recursive: true,
@@ -564,9 +566,10 @@ function inspectSourceOpenCodeRuntime(command, root, environment, definitionInst
564
566
  throw new Error('OpenCode 原项目 resolved instructions 不是 string array');
565
567
  }
566
568
  const definitionCount = countInstructionsForPath(root, instructions, definitionInstruction);
567
- const basicCount = countInstructionsForPath(root, instructions, BASIC_INSTRUCTION);
568
- if (definitionInstruction !== 'AGENTS.md' || definitionCount !== 0 || basicCount !== 1) {
569
- throw new Error(`OpenCode 原项目 resolved config 未形成原生 AGENTS.md + 唯一 Basic: ` +
569
+ const basicCount = countInstructionsForPath(root, instructions, basicInstruction);
570
+ const expectedDefinitionCount = definitionInstruction === 'AGENTS.md' ? 0 : 1;
571
+ if (definitionCount !== expectedDefinitionCount || basicCount !== 1) {
572
+ throw new Error(`OpenCode 原项目 resolved config 未形成唯一 Agent Definition + Basic: ` +
570
573
  `definition=${definitionCount} basic=${basicCount}`);
571
574
  }
572
575
  if (value.agent?.['dta-eval'] !== undefined) {
@@ -625,7 +628,10 @@ function executeInheritanceProbe(sourceRoot, model, command, timeoutMs, reportEv
625
628
  !Array.isArray(sourceConfig.permission) ? sourceConfig.permission : {};
626
629
  const skill = permission.skill && typeof permission.skill === 'object' &&
627
630
  !Array.isArray(permission.skill) ? permission.skill : {};
628
- sourceConfig.instructions = [BASIC_INSTRUCTION];
631
+ sourceConfig.instructions = [
632
+ ...(definitionInstruction === 'AGENTS.md' ? [] : [definitionInstruction]),
633
+ BASIC_INSTRUCTION,
634
+ ];
629
635
  delete sourceConfig.provider;
630
636
  sourceConfig.plugin = [];
631
637
  sourceConfig.mcp = {};
@@ -665,7 +671,7 @@ function executeInheritanceProbe(sourceRoot, model, command, timeoutMs, reportEv
665
671
  const definitionRaw = persistProbeExecution(reportEvidenceRoot, 'definition', definitionExecution);
666
672
  const referenceRaw = persistProbeExecution(reportEvidenceRoot, 'reference', referenceExecution);
667
673
  const result = {
668
- passed: definitionInstruction === 'AGENTS.md' && basicResolvedCount === 1 &&
674
+ passed: Boolean(definitionInstruction) && basicResolvedCount === 1 &&
669
675
  definitionPermissionPassed && referencePermissionPassed &&
670
676
  definitionExecution.exitCode === 0 && definitionExecution.directoryMatched &&
671
677
  definitionExecution.toolCalls === 0 &&
@@ -830,7 +836,7 @@ function validRandomProbe(value, name) {
830
836
  const count = name === 'dta-reference-probe' ? 2 : 1;
831
837
  return new RegExp(`^${name}=${uuid}${count === 2 ? `:${uuid}` : ''}$`).test(value);
832
838
  }
833
- function verifyLoadProbeSet(root, reportPath, report, primaryName, comparisonName, basic, expectedRuns) {
839
+ function verifyLoadProbeSet(root, reportPath, report, primaryName, comparisonName, basic, definitionInstruction, expectedRuns) {
834
840
  const all = Array.isArray(report.loadProbes) ? report.loadProbes : [];
835
841
  const declaredRuns = Number(report.summary?.runsPerConfiguration);
836
842
  const primary = all.filter((item) => item.configuration === primaryName);
@@ -841,7 +847,12 @@ function verifyLoadProbeSet(root, reportPath, report, primaryName, comparisonNam
841
847
  items.every((item) => Number.isInteger(item.runNumber) &&
842
848
  item.runNumber >= 1 && item.runNumber <= expectedRuns);
843
849
  const common = (item) => {
844
- const expectedInstructions = item.expectsLoad === true ? [BASIC_INSTRUCTION] : [];
850
+ const expectedInstructions = item.expectsLoad === true
851
+ ? [
852
+ BASIC_INSTRUCTION,
853
+ ...(definitionInstruction === 'AGENTS.md' ? [] : [definitionInstruction]),
854
+ ].sort()
855
+ : [];
845
856
  return loadProbeCorePassed(item, version) &&
846
857
  stableStringify(item.resolvedInstructions) === stableStringify(expectedInstructions) &&
847
858
  verifyLoadProbeRaw(root, reportPath, item, String(report.engine?.model || ''));
@@ -954,7 +965,7 @@ function readLoadEvidence(root, input, expectedTargetHash) {
954
965
  function verifyLoadReport(root, reportPath, report, basic, definitionInstruction, model, currentHostVersion) {
955
966
  const configuration = 'with_skill';
956
967
  const comparison = 'without_skill';
957
- const probeSet = verifyLoadProbeSet(root, reportPath, report, configuration, comparison, basic, 1);
968
+ const probeSet = verifyLoadProbeSet(root, reportPath, report, configuration, comparison, basic, definitionInstruction, 1);
958
969
  const probes = probeSet.primary;
959
970
  const source = report.skills?.[configuration];
960
971
  const gate = report.summary?.configurationLoadGates?.[configuration];
@@ -966,7 +977,7 @@ function verifyLoadReport(root, reportPath, report, basic, definitionInstruction
966
977
  Array.isArray(definition.toolNames) && definition.toolNames.length === 0 &&
967
978
  Array.isArray(definition.toolPaths) && definition.toolPaths.length === 0 &&
968
979
  Array.isArray(definition.toolTrace) && definition.toolTrace.length === 0 &&
969
- definition.nativeRule === 'AGENTS.md' && definitionInstruction === 'AGENTS.md' &&
980
+ definition.nativeRule === definitionInstruction && Boolean(definitionInstruction) &&
970
981
  definition.permissionPassed === true &&
971
982
  zeroToolPermission(definition.evalAgent || {});
972
983
  const referenceTrace = Array.isArray(reference.toolTrace) ? reference.toolTrace : [];
@@ -1017,7 +1028,7 @@ function verifyLoadReport(root, reportPath, report, basic, definitionInstruction
1017
1028
  baselineAntiGuessProbes: probeSet.passedComparison,
1018
1029
  expectedRunsPerConfiguration: probeSet.expectedRuns,
1019
1030
  definitionInstruction,
1020
- definitionNativeRule: definition.nativeRule === 'AGENTS.md',
1031
+ definitionNativeRule: definition.nativeRule === definitionInstruction,
1021
1032
  totalProbes: probes.length,
1022
1033
  definitionProbePassed: definitionPassed,
1023
1034
  referenceProbePassed: referencePassed,
@@ -1037,8 +1048,11 @@ function verifySourceConfigEvidence(root, reportPath, summary, evidence) {
1037
1048
  return false;
1038
1049
  const value = summary;
1039
1050
  const manifest = evidence;
1040
- if (value.passed !== true || value.definitionInstruction !== 'AGENTS.md' ||
1041
- value.definitionInstructionCount !== 0 || value.basicInstructionCount !== 1 ||
1051
+ const expectedDefinitionCount = value.definitionInstruction === 'AGENTS.md' ? 0 : 1;
1052
+ if (value.passed !== true || typeof value.definitionInstruction !== 'string' ||
1053
+ !value.definitionInstruction ||
1054
+ value.definitionInstructionCount !== expectedDefinitionCount ||
1055
+ value.basicInstructionCount !== 1 ||
1042
1056
  typeof value.rawHash !== 'string' || !value.rawHash ||
1043
1057
  manifest.rawHash !== value.rawHash)
1044
1058
  return false;
@@ -1227,12 +1241,12 @@ function repairFor(id) {
1227
1241
  if (id === 'definition.semantic-contract')
1228
1242
  return {
1229
1243
  id, why: '结构化模板不能替代真实的本体定义、岗位底线、做事范式和常犯错误。',
1230
- actions: ['评审并替换 AGENTS.md 中所有 <...> 占位符,再复跑 audit。'],
1244
+ actions: ['评审并替换 manifest 中 agent.definition 指向文件的所有 <...> 占位符,再复跑 audit。'],
1231
1245
  };
1232
1246
  if (id === 'definition.body')
1233
1247
  return {
1234
1248
  id, why: 'Agent 必须有长期定义、岗位底线、做事范式和常犯错误。',
1235
- actions: ['从 compose Skill 的 AGENTS.template.md 创建 AGENTS.md,再复跑 audit。'],
1249
+ actions: ['从 compose Skill 的 AGENTS.template.md 创建 agent/AGENTS.md,并由 manifest 的 agent.definition 指向它,再复跑 audit。'],
1236
1250
  };
1237
1251
  if (id === 'storage.memory')
1238
1252
  return {
@@ -1257,22 +1271,22 @@ function repairFor(id) {
1257
1271
  if (id.startsWith('skill.role.') && id.endsWith('.semantic'))
1258
1272
  return {
1259
1273
  id, why: 'Role Skill 必须包含真实的领域输入、方法、产物和验收,而不是模板提示。',
1260
- actions: [`评审并替换 skills/${id.slice('skill.role.'.length, -'.semantic'.length)}/SKILL.md 中所有 <...> 占位符。`],
1274
+ actions: [`评审并替换 agent.skillsRoot 下 ${id.slice('skill.role.'.length, -'.semantic'.length)}/SKILL.md 中所有 <...> 占位符。`],
1261
1275
  };
1262
1276
  if (id.startsWith('skill.role.'))
1263
1277
  return {
1264
1278
  id, why: '领域职责需要独立 Role Skill,不能写回 Basic Behavior。',
1265
- actions: [`创建 skills/${id.slice('skill.role.'.length)}/SKILL.md,并确保目录名等于 frontmatter name。`],
1279
+ actions: [`在 manifest 声明的 agent.skillsRoot 下创建 ${id.slice('skill.role.'.length)}/SKILL.md,并确保目录名等于 frontmatter name。`],
1266
1280
  };
1267
1281
  if (id === 'host.basic-exposure')
1268
1282
  return {
1269
1283
  id, why: 'OpenCode 只能从项目 exposure 完整继承本次装配的 Basic Skill 入口、references 与 assets。',
1270
- actions: ['把 canonical dingtalk-basic-behavior 全树物化到 .agents/skills/dingtalk-basic-behavior。'],
1284
+ actions: ['把 canonical dingtalk-basic-behavior 全树放入 agent.skillsRoot;由 dta 在隔离 Host 工作区临时物化 exposure。'],
1271
1285
  };
1272
1286
  if (id === 'host.definition-rule')
1273
1287
  return {
1274
- id, why: 'OpenCode 只会把项目根 AGENTS.md 作为本地原生 rule;重复 custom instruction 会形成冗余通道。',
1275
- actions: ['把项目本体统一为根目录 AGENTS.md,并从 opencode.json#instructions 删除其等价路径。'],
1288
+ id, why: 'Agent Definition 与仓库开发约束必须分离,重复 custom instruction 会形成冗余通道。',
1289
+ actions: [' managed Host 只加载一次 manifest 的 agent.definition;仓库根 AGENTS.md 仅保留 Coding Agent 开发约束。'],
1276
1290
  };
1277
1291
  if (id === 'host.basic-instruction')
1278
1292
  return {
@@ -1282,7 +1296,7 @@ function repairFor(id) {
1282
1296
  if (id.startsWith('host.role-exposure.'))
1283
1297
  return {
1284
1298
  id, why: 'Role Skill 的发布源、Host exposure 与权限必须指向同一版本。',
1285
- actions: [`物化 .agents/skills/${id.slice('host.role-exposure.'.length)},校验 hash 并设置 permission=allow。`],
1299
+ actions: [`修复 agent.skillsRoot 下 ${id.slice('host.role-exposure.'.length)} 的唯一发布源;由 dta 临时物化 Host exposure、校验 hash 并设置 permission=allow。`],
1286
1300
  };
1287
1301
  if (id === 'host.load-probe')
1288
1302
  return {