@xdxer/dingtalk-agent 0.1.4-beta.10 → 0.1.4-beta.12

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.
@@ -0,0 +1,157 @@
1
+ // Managed Agents Platform(MAP)注册表与工作区归属解析。
2
+ //
3
+ // 一个 Agent 工作区归属于至多一个托管平台;归属解析顺序固定:
4
+ // DTA_MAP 环境变量 > dingtalk-agent.json#map > .dingtalk-agent/map.json > 按 Provider 声明推断。
5
+ // 平台相关的方法学不写进 CLI——它们随对应平台的 Skill 包分发,只在用户选择该平台时安装。
6
+ // 平台命令(如 deploy/promote/observe)必须先通过归属门禁;coming-soon 平台一律 fail-closed。
7
+ import { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
8
+ import { dirname, join, parse, resolve } from 'node:path';
9
+ import { findAgentProjectRoot } from './development-workspace.js';
10
+ import { installGlobalSkill } from './skill-manager.js';
11
+ export const MANAGED_AGENT_PLATFORMS = [
12
+ {
13
+ name: 'multica-dingtalk',
14
+ label: 'Multica (DingTalk)',
15
+ status: 'supported',
16
+ description: '钉钉 Multica 托管平台:受控部署、晋级与观测回流。',
17
+ skills: ['dingtalk-agent-deploy', 'dingtalk-agent-boot-multica'],
18
+ commands: ['deploy', 'promote', 'observe'],
19
+ },
20
+ {
21
+ name: 'deap',
22
+ label: 'DEAP',
23
+ status: 'coming-soon',
24
+ description: '敬请期待。',
25
+ skills: [],
26
+ commands: [],
27
+ },
28
+ ];
29
+ export const MAP_FILE = '.dingtalk-agent/map.json';
30
+ const PROJECT_FILE = 'dingtalk-agent.json';
31
+ export function mapDefinition(name) {
32
+ return MANAGED_AGENT_PLATFORMS.find((item) => item.name === name) || null;
33
+ }
34
+ export function resolveMap(start = process.cwd(), env = process.env) {
35
+ const fromEnv = String(env.DTA_MAP || '').trim();
36
+ if (fromEnv)
37
+ return resolution(fromEnv, 'env', '');
38
+ const projectRoot = findAgentProjectRoot(start);
39
+ if (projectRoot) {
40
+ const manifestPath = join(projectRoot, PROJECT_FILE);
41
+ if (existsSync(manifestPath) && !lstatSync(manifestPath).isSymbolicLink()) {
42
+ const manifest = readJsonOrNull(manifestPath);
43
+ const declared = typeof manifest?.map === 'string' ? manifest.map.trim() : '';
44
+ if (declared)
45
+ return resolution(declared, 'project-manifest', manifestPath);
46
+ }
47
+ }
48
+ const mapPath = findUp(start, MAP_FILE);
49
+ if (mapPath) {
50
+ const stored = readJsonOrNull(mapPath);
51
+ const declared = typeof stored?.map === 'string' ? stored.map.trim() : '';
52
+ if (declared)
53
+ return resolution(declared, 'map-file', mapPath);
54
+ }
55
+ if (projectRoot) {
56
+ const manifest = readJsonOrNull(join(projectRoot, PROJECT_FILE));
57
+ const providers = Object.values(manifest?.workspaces || {})
58
+ .map((workspace) => workspace?.provider?.kind);
59
+ if (providers.includes('multica')) {
60
+ return resolution('multica-dingtalk', 'inferred', join(projectRoot, PROJECT_FILE));
61
+ }
62
+ }
63
+ return resolution(null, 'none', '');
64
+ }
65
+ export function useMap(start, name, options) {
66
+ const definition = mapDefinition(name);
67
+ if (!definition) {
68
+ throw new Error(`未知 managed agents platform: ${name}\n` +
69
+ `可用: ${MANAGED_AGENT_PLATFORMS.map((item) => `${item.name}(${statusLabel(item.status)})`).join('、')}`);
70
+ }
71
+ if (definition.status !== 'supported') {
72
+ throw new Error(`${definition.label} 敬请期待——当前版本尚未开放该平台。`);
73
+ }
74
+ const projectRoot = findAgentProjectRoot(start);
75
+ let written;
76
+ if (projectRoot && existsSync(join(projectRoot, PROJECT_FILE))) {
77
+ const manifestPath = join(projectRoot, PROJECT_FILE);
78
+ if (lstatSync(manifestPath).isSymbolicLink()) {
79
+ throw new Error(`${PROJECT_FILE} 不能是符号链接`);
80
+ }
81
+ const manifest = readJsonOrNull(manifestPath);
82
+ if (!manifest || typeof manifest !== 'object') {
83
+ throw new Error(`${PROJECT_FILE} 不是合法 JSON,无法写入 map 归属`);
84
+ }
85
+ manifest.map = definition.name;
86
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
87
+ written = manifestPath;
88
+ }
89
+ else {
90
+ const target = join(resolve(start), MAP_FILE);
91
+ mkdirSync(dirname(target), { recursive: true });
92
+ writeFileSync(target, JSON.stringify({ $schema: 'dingtalk-agent/map@1', map: definition.name }, null, 2) + '\n');
93
+ written = target;
94
+ }
95
+ const skillInstalls = [];
96
+ if (options.installSkills !== false) {
97
+ for (const skill of definition.skills) {
98
+ skillInstalls.push(installGlobalSkill(options.packageRoot, {
99
+ name: skill, home: options.home, env: options.env,
100
+ }));
101
+ }
102
+ }
103
+ return { ...resolveMap(start, options.env || process.env), written, skillInstalls };
104
+ }
105
+ /** deploy/promote/observe 等平台命令的归属门禁:未归属、未知或 coming-soon 一律 fail-closed。 */
106
+ export function requireSupportedMap(command, start = process.cwd(), env = process.env) {
107
+ const resolved = resolveMap(start, env);
108
+ if (!resolved.map) {
109
+ throw new Error(`当前工作区未声明 managed agents platform,无法执行 \`${command}\`。\n` +
110
+ '先运行 `dta map use multica-dingtalk`,或设置 DTA_MAP 环境变量。');
111
+ }
112
+ if (!resolved.definition) {
113
+ throw new Error(`工作区声明了未知 platform: ${resolved.map}(来源 ${resolved.source})。\n` +
114
+ `可用: ${MANAGED_AGENT_PLATFORMS.map((item) => item.name).join('、')}`);
115
+ }
116
+ if (resolved.definition.status !== 'supported') {
117
+ throw new Error(`${resolved.definition.label} 敬请期待——\`${command}\` 尚未在该平台开放。`);
118
+ }
119
+ if (!resolved.definition.commands.includes(command)) {
120
+ throw new Error(`${resolved.definition.label} 不承接命令 \`${command}\`。`);
121
+ }
122
+ return resolved;
123
+ }
124
+ export function statusLabel(status) {
125
+ return status === 'supported' ? '已支持' : '敬请期待';
126
+ }
127
+ function resolution(name, source, file) {
128
+ return {
129
+ $schema: 'dingtalk-agent/map-resolution@1',
130
+ map: name,
131
+ source,
132
+ file,
133
+ definition: name ? mapDefinition(name) : null,
134
+ platforms: MANAGED_AGENT_PLATFORMS,
135
+ };
136
+ }
137
+ function readJsonOrNull(path) {
138
+ try {
139
+ return JSON.parse(readFileSync(path, 'utf8'));
140
+ }
141
+ catch {
142
+ return null;
143
+ }
144
+ }
145
+ function findUp(start, relativePath) {
146
+ let dir = resolve(start);
147
+ while (true) {
148
+ const candidate = join(dir, relativePath);
149
+ if (existsSync(candidate) && !lstatSync(candidate).isSymbolicLink())
150
+ return candidate;
151
+ const parent = dirname(dir);
152
+ if (parent === dir || dir === parse(dir).root)
153
+ return null;
154
+ dir = parent;
155
+ }
156
+ }
157
+ //# sourceMappingURL=map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map.js","sourceRoot":"","sources":["../../src/map.ts"],"names":[],"mappings":"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","sourcesContent":["// Managed Agents Platform(MAP)注册表与工作区归属解析。\n//\n// 一个 Agent 工作区归属于至多一个托管平台;归属解析顺序固定:\n// DTA_MAP 环境变量 > dingtalk-agent.json#map > .dingtalk-agent/map.json > 按 Provider 声明推断。\n// 平台相关的方法学不写进 CLI——它们随对应平台的 Skill 包分发,只在用户选择该平台时安装。\n// 平台命令(如 deploy/promote/observe)必须先通过归属门禁;coming-soon 平台一律 fail-closed。\n\nimport { existsSync, lstatSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { dirname, join, parse, resolve } from 'node:path'\n\nimport { findAgentProjectRoot } from './development-workspace.js'\nimport { installGlobalSkill, type GlobalSkillStatus } from './skill-manager.js'\n\nexport type MapStatus = 'supported' | 'coming-soon'\n\nexport interface MapDefinition {\n name: string\n label: string\n status: MapStatus\n description: string\n skills: string[]\n commands: string[]\n}\n\nexport const MANAGED_AGENT_PLATFORMS: MapDefinition[] = [\n {\n name: 'multica-dingtalk',\n label: 'Multica (DingTalk)',\n status: 'supported',\n description: '钉钉 Multica 托管平台:受控部署、晋级与观测回流。',\n skills: ['dingtalk-agent-deploy', 'dingtalk-agent-boot-multica'],\n commands: ['deploy', 'promote', 'observe'],\n },\n {\n name: 'deap',\n label: 'DEAP',\n status: 'coming-soon',\n description: '敬请期待。',\n skills: [],\n commands: [],\n },\n]\n\nexport const MAP_FILE = '.dingtalk-agent/map.json'\nconst PROJECT_FILE = 'dingtalk-agent.json'\n\nexport type MapSource = 'env' | 'project-manifest' | 'map-file' | 'inferred' | 'none'\n\nexport interface MapResolution {\n $schema: 'dingtalk-agent/map-resolution@1'\n map: string | null\n source: MapSource\n file: string\n definition: MapDefinition | null\n platforms: MapDefinition[]\n}\n\nexport interface MapUseResult extends MapResolution {\n written: string\n skillInstalls: GlobalSkillStatus[]\n}\n\nexport function mapDefinition(name: string): MapDefinition | null {\n return MANAGED_AGENT_PLATFORMS.find((item) => item.name === name) || null\n}\n\nexport function resolveMap(start = process.cwd(), env: NodeJS.ProcessEnv = process.env): MapResolution {\n const fromEnv = String(env.DTA_MAP || '').trim()\n if (fromEnv) return resolution(fromEnv, 'env', '')\n\n const projectRoot = findAgentProjectRoot(start)\n if (projectRoot) {\n const manifestPath = join(projectRoot, PROJECT_FILE)\n if (existsSync(manifestPath) && !lstatSync(manifestPath).isSymbolicLink()) {\n const manifest = readJsonOrNull(manifestPath)\n const declared = typeof manifest?.map === 'string' ? manifest.map.trim() : ''\n if (declared) return resolution(declared, 'project-manifest', manifestPath)\n }\n }\n\n const mapPath = findUp(start, MAP_FILE)\n if (mapPath) {\n const stored = readJsonOrNull(mapPath)\n const declared = typeof stored?.map === 'string' ? stored.map.trim() : ''\n if (declared) return resolution(declared, 'map-file', mapPath)\n }\n\n if (projectRoot) {\n const manifest = readJsonOrNull(join(projectRoot, PROJECT_FILE))\n const providers = Object.values(manifest?.workspaces || {})\n .map((workspace: any) => workspace?.provider?.kind)\n if (providers.includes('multica')) {\n return resolution('multica-dingtalk', 'inferred', join(projectRoot, PROJECT_FILE))\n }\n }\n\n return resolution(null, 'none', '')\n}\n\nexport interface MapUseOptions {\n packageRoot: string\n home?: string\n env?: NodeJS.ProcessEnv\n installSkills?: boolean\n}\n\nexport function useMap(start: string, name: string, options: MapUseOptions): MapUseResult {\n const definition = mapDefinition(name)\n if (!definition) {\n throw new Error(\n `未知 managed agents platform: ${name}\\n` +\n `可用: ${MANAGED_AGENT_PLATFORMS.map((item) => `${item.name}(${statusLabel(item.status)})`).join('、')}`,\n )\n }\n if (definition.status !== 'supported') {\n throw new Error(`${definition.label} 敬请期待——当前版本尚未开放该平台。`)\n }\n\n const projectRoot = findAgentProjectRoot(start)\n let written: string\n if (projectRoot && existsSync(join(projectRoot, PROJECT_FILE))) {\n const manifestPath = join(projectRoot, PROJECT_FILE)\n if (lstatSync(manifestPath).isSymbolicLink()) {\n throw new Error(`${PROJECT_FILE} 不能是符号链接`)\n }\n const manifest = readJsonOrNull(manifestPath)\n if (!manifest || typeof manifest !== 'object') {\n throw new Error(`${PROJECT_FILE} 不是合法 JSON,无法写入 map 归属`)\n }\n manifest.map = definition.name\n writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\\n')\n written = manifestPath\n } else {\n const target = join(resolve(start), MAP_FILE)\n mkdirSync(dirname(target), { recursive: true })\n writeFileSync(target, JSON.stringify(\n { $schema: 'dingtalk-agent/map@1', map: definition.name }, null, 2,\n ) + '\\n')\n written = target\n }\n\n const skillInstalls: GlobalSkillStatus[] = []\n if (options.installSkills !== false) {\n for (const skill of definition.skills) {\n skillInstalls.push(installGlobalSkill(options.packageRoot, {\n name: skill, home: options.home, env: options.env,\n }))\n }\n }\n\n return { ...resolveMap(start, options.env || process.env), written, skillInstalls }\n}\n\n/** deploy/promote/observe 等平台命令的归属门禁:未归属、未知或 coming-soon 一律 fail-closed。 */\nexport function requireSupportedMap(\n command: string, start = process.cwd(), env: NodeJS.ProcessEnv = process.env,\n): MapResolution {\n const resolved = resolveMap(start, env)\n if (!resolved.map) {\n throw new Error(\n `当前工作区未声明 managed agents platform,无法执行 \\`${command}\\`。\\n` +\n '先运行 `dta map use multica-dingtalk`,或设置 DTA_MAP 环境变量。',\n )\n }\n if (!resolved.definition) {\n throw new Error(\n `工作区声明了未知 platform: ${resolved.map}(来源 ${resolved.source})。\\n` +\n `可用: ${MANAGED_AGENT_PLATFORMS.map((item) => item.name).join('、')}`,\n )\n }\n if (resolved.definition.status !== 'supported') {\n throw new Error(`${resolved.definition.label} 敬请期待——\\`${command}\\` 尚未在该平台开放。`)\n }\n if (!resolved.definition.commands.includes(command)) {\n throw new Error(`${resolved.definition.label} 不承接命令 \\`${command}\\`。`)\n }\n return resolved\n}\n\nexport function statusLabel(status: MapStatus): string {\n return status === 'supported' ? '已支持' : '敬请期待'\n}\n\nfunction resolution(name: string | null, source: MapSource, file: string): MapResolution {\n return {\n $schema: 'dingtalk-agent/map-resolution@1',\n map: name,\n source,\n file,\n definition: name ? mapDefinition(name) : null,\n platforms: MANAGED_AGENT_PLATFORMS,\n }\n}\n\nfunction readJsonOrNull(path: string): any {\n try { return JSON.parse(readFileSync(path, 'utf8')) } catch { return null }\n}\n\nfunction findUp(start: string, relativePath: string): string | null {\n let dir = resolve(start)\n while (true) {\n const candidate = join(dir, relativePath)\n if (existsSync(candidate) && !lstatSync(candidate).isSymbolicLink()) return candidate\n const parent = dirname(dir)\n if (parent === dir || dir === parse(dir).root) return null\n dir = parent\n }\n}\n"]}
package/dist/src/setup.js CHANGED
@@ -3,7 +3,7 @@ import { delimiter, join } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  import { spawnSync } from 'node:child_process';
5
5
  import { doctor, findExecutable } from './doctor.js';
6
- import { installGlobalSkill, skillStatus, } from './skill-manager.js';
6
+ import { GLOBAL_SKILL_NAME, installBundledSkills, skillSuiteStatus, } from './skill-manager.js';
7
7
  const PATH_MARKER_START = '# >>> dingtalk-agent PATH >>>';
8
8
  const PATH_MARKER_END = '# <<< dingtalk-agent PATH <<<';
9
9
  export function setup(packageRoot, options = {}) {
@@ -41,10 +41,10 @@ export function setup(packageRoot, options = {}) {
41
41
  ...env,
42
42
  PATH: [binDir, env.PATH || ''].filter(Boolean).join(delimiter),
43
43
  };
44
- const beforeSkill = skillStatus(packageRoot, { home });
45
- const skill = options.dryRun
46
- ? beforeSkill
47
- : installGlobalSkill(packageRoot, { home, env: effectiveEnv });
44
+ const suite = options.dryRun
45
+ ? skillSuiteStatus(packageRoot, { home })
46
+ : installBundledSkills(packageRoot, { home, env: effectiveEnv });
47
+ const skill = suite.skills.find((item) => item.name === GLOBAL_SKILL_NAME) || suite.skills[0];
48
48
  const report = doctor(packageRoot, { home, env: effectiveEnv });
49
49
  return {
50
50
  $schema: 'dingtalk-agent/setup@1',
@@ -60,6 +60,7 @@ export function setup(packageRoot, options = {}) {
60
60
  },
61
61
  shell,
62
62
  skill,
63
+ skills: suite.skills,
63
64
  doctor: report,
64
65
  nextCommand: report.ready ? 'dta bootstrap --json' : 'dta doctor',
65
66
  };
@@ -1 +1 @@
1
- {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/setup.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs'\nimport { delimiter, join } from 'node:path'\nimport { homedir } from 'node:os'\nimport { spawnSync } from 'node:child_process'\n\nimport { doctor, findExecutable, type DoctorReport } from './doctor.js'\nimport {\n installGlobalSkill, skillStatus, type GlobalSkillStatus,\n} from './skill-manager.js'\n\nconst PATH_MARKER_START = '# >>> dingtalk-agent PATH >>>'\nconst PATH_MARKER_END = '# <<< dingtalk-agent PATH <<<'\n\nexport interface SetupOptions {\n home?: string\n env?: NodeJS.ProcessEnv\n prefix?: string\n dryRun?: boolean\n writeShell?: boolean\n skipCliInstall?: boolean\n}\n\nexport interface SetupResult {\n $schema: 'dingtalk-agent/setup@1'\n dryRun: boolean\n cli: {\n installed: boolean\n skipped: boolean\n prefix: string\n binDir: string\n executable: string\n alias: string\n packageSpec: string\n }\n shell: {\n pathReady: boolean\n rcFile: string\n updated: boolean\n activateCommand: string\n }\n skill: GlobalSkillStatus\n doctor: DoctorReport\n nextCommand: string\n}\n\nexport function setup(packageRoot: string, options: SetupOptions = {}): SetupResult {\n const home = options.home || homedir()\n const env = { ...(options.env || process.env) }\n const prefix = options.prefix || join(home, '.local')\n const binDir = process.platform === 'win32' ? prefix : join(prefix, 'bin')\n const executable = join(binDir, process.platform === 'win32' ? 'dingtalk-agent.cmd' : 'dingtalk-agent')\n const alias = join(binDir, process.platform === 'win32' ? 'dta.cmd' : 'dta')\n const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'))\n const packageSpec = env.DTA_SETUP_PACKAGE_SOURCE || `${pkg.name}@${pkg.version}`\n const npm = findExecutable(process.platform === 'win32' ? 'npm.cmd' : 'npm', env) || 'npm'\n const installedVersion = existsSync(executable)\n ? readInstalledVersion(executable, env)\n : ''\n const aliasVersion = existsSync(alias) ? readInstalledVersion(alias, env) : ''\n const alreadyCurrent = installedVersion === String(pkg.version || '') && aliasVersion === installedVersion\n\n if (!options.dryRun && !options.skipCliInstall && !alreadyCurrent) {\n mkdirSync(prefix, { recursive: true })\n const run = spawnSync(npm, [\n 'install', '--global', '--prefix', prefix, '--registry', 'https://registry.npmjs.org', packageSpec,\n ], { encoding: 'utf8', env, timeout: 120_000 })\n if (run.status !== 0 || run.error) {\n throw new Error(\n `CLI 用户级安装失败: ${run.error?.message || String(run.stderr || run.stdout).trim() || `退出码 ${run.status}`}`,\n )\n }\n if (!existsSync(executable) || !existsSync(alias)) {\n throw new Error(`npm 安装完成但 CLI 入口不完整: ${executable} / ${alias}`)\n }\n }\n\n const shell = ensureShellPath(home, binDir, env, {\n dryRun: Boolean(options.dryRun),\n writeShell: options.writeShell !== false,\n })\n const effectiveEnv = {\n ...env,\n PATH: [binDir, env.PATH || ''].filter(Boolean).join(delimiter),\n }\n const beforeSkill = skillStatus(packageRoot, { home })\n const skill = options.dryRun\n ? beforeSkill\n : installGlobalSkill(packageRoot, { home, env: effectiveEnv })\n const report = doctor(packageRoot, { home, env: effectiveEnv })\n return {\n $schema: 'dingtalk-agent/setup@1',\n dryRun: Boolean(options.dryRun),\n cli: {\n installed: !options.dryRun && !options.skipCliInstall && existsSync(executable),\n skipped: Boolean(options.skipCliInstall || alreadyCurrent),\n prefix,\n binDir,\n executable,\n alias,\n packageSpec,\n },\n shell,\n skill,\n doctor: report,\n nextCommand: report.ready ? 'dta bootstrap --json' : 'dta doctor',\n }\n}\n\nfunction ensureShellPath(\n home: string,\n binDir: string,\n env: NodeJS.ProcessEnv,\n options: { dryRun: boolean; writeShell: boolean },\n) {\n const current = (env.PATH || '').split(delimiter).filter(Boolean)\n const pathReady = current.includes(binDir)\n const shell = env.SHELL || ''\n const rcFile = shell.endsWith('/zsh')\n ? join(home, '.zshrc')\n : shell.endsWith('/bash')\n ? join(home, '.bashrc')\n : ''\n const isDefaultBin = binDir === join(home, '.local', 'bin')\n const activateCommand = isDefaultBin\n ? 'export PATH=\"$HOME/.local/bin:$PATH\"'\n : `export PATH=${shellQuote(binDir)}:\"$PATH\"`\n let updated = false\n if (!pathReady && options.writeShell && rcFile) {\n const before = existsSync(rcFile) ? readFileSync(rcFile, 'utf8') : ''\n if (!before.includes(PATH_MARKER_START) && !options.dryRun) {\n const pathLine = isDefaultBin\n ? 'export PATH=\"$HOME/.local/bin:$PATH\"'\n : `export PATH=${shellQuote(binDir)}:\"$PATH\"`\n const block = `${before && !before.endsWith('\\n') ? '\\n' : ''}${PATH_MARKER_START}\\n` +\n `${pathLine}\\n${PATH_MARKER_END}\\n`\n appendFileSync(rcFile, block)\n updated = true\n }\n }\n return { pathReady, rcFile, updated, activateCommand }\n}\n\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\"'\"'`)}'`\n}\n\nfunction readInstalledVersion(executable: string, env: NodeJS.ProcessEnv): string {\n const run = spawnSync(executable, ['--version'], { encoding: 'utf8', env, timeout: 8_000 })\n return run.status === 0 ? String(run.stdout || '').trim() : ''\n}\n"]}
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/setup.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs'\nimport { delimiter, join } from 'node:path'\nimport { homedir } from 'node:os'\nimport { spawnSync } from 'node:child_process'\n\nimport { doctor, findExecutable, type DoctorReport } from './doctor.js'\nimport {\n GLOBAL_SKILL_NAME, installBundledSkills, skillSuiteStatus, type GlobalSkillStatus,\n} from './skill-manager.js'\n\nconst PATH_MARKER_START = '# >>> dingtalk-agent PATH >>>'\nconst PATH_MARKER_END = '# <<< dingtalk-agent PATH <<<'\n\nexport interface SetupOptions {\n home?: string\n env?: NodeJS.ProcessEnv\n prefix?: string\n dryRun?: boolean\n writeShell?: boolean\n skipCliInstall?: boolean\n}\n\nexport interface SetupResult {\n $schema: 'dingtalk-agent/setup@1'\n dryRun: boolean\n cli: {\n installed: boolean\n skipped: boolean\n prefix: string\n binDir: string\n executable: string\n alias: string\n packageSpec: string\n }\n shell: {\n pathReady: boolean\n rcFile: string\n updated: boolean\n activateCommand: string\n }\n skill: GlobalSkillStatus\n skills: GlobalSkillStatus[]\n doctor: DoctorReport\n nextCommand: string\n}\n\nexport function setup(packageRoot: string, options: SetupOptions = {}): SetupResult {\n const home = options.home || homedir()\n const env = { ...(options.env || process.env) }\n const prefix = options.prefix || join(home, '.local')\n const binDir = process.platform === 'win32' ? prefix : join(prefix, 'bin')\n const executable = join(binDir, process.platform === 'win32' ? 'dingtalk-agent.cmd' : 'dingtalk-agent')\n const alias = join(binDir, process.platform === 'win32' ? 'dta.cmd' : 'dta')\n const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'))\n const packageSpec = env.DTA_SETUP_PACKAGE_SOURCE || `${pkg.name}@${pkg.version}`\n const npm = findExecutable(process.platform === 'win32' ? 'npm.cmd' : 'npm', env) || 'npm'\n const installedVersion = existsSync(executable)\n ? readInstalledVersion(executable, env)\n : ''\n const aliasVersion = existsSync(alias) ? readInstalledVersion(alias, env) : ''\n const alreadyCurrent = installedVersion === String(pkg.version || '') && aliasVersion === installedVersion\n\n if (!options.dryRun && !options.skipCliInstall && !alreadyCurrent) {\n mkdirSync(prefix, { recursive: true })\n const run = spawnSync(npm, [\n 'install', '--global', '--prefix', prefix, '--registry', 'https://registry.npmjs.org', packageSpec,\n ], { encoding: 'utf8', env, timeout: 120_000 })\n if (run.status !== 0 || run.error) {\n throw new Error(\n `CLI 用户级安装失败: ${run.error?.message || String(run.stderr || run.stdout).trim() || `退出码 ${run.status}`}`,\n )\n }\n if (!existsSync(executable) || !existsSync(alias)) {\n throw new Error(`npm 安装完成但 CLI 入口不完整: ${executable} / ${alias}`)\n }\n }\n\n const shell = ensureShellPath(home, binDir, env, {\n dryRun: Boolean(options.dryRun),\n writeShell: options.writeShell !== false,\n })\n const effectiveEnv = {\n ...env,\n PATH: [binDir, env.PATH || ''].filter(Boolean).join(delimiter),\n }\n const suite = options.dryRun\n ? skillSuiteStatus(packageRoot, { home })\n : installBundledSkills(packageRoot, { home, env: effectiveEnv })\n const skill = suite.skills.find((item) => item.name === GLOBAL_SKILL_NAME) || suite.skills[0]\n const report = doctor(packageRoot, { home, env: effectiveEnv })\n return {\n $schema: 'dingtalk-agent/setup@1',\n dryRun: Boolean(options.dryRun),\n cli: {\n installed: !options.dryRun && !options.skipCliInstall && existsSync(executable),\n skipped: Boolean(options.skipCliInstall || alreadyCurrent),\n prefix,\n binDir,\n executable,\n alias,\n packageSpec,\n },\n shell,\n skill,\n skills: suite.skills,\n doctor: report,\n nextCommand: report.ready ? 'dta bootstrap --json' : 'dta doctor',\n }\n}\n\nfunction ensureShellPath(\n home: string,\n binDir: string,\n env: NodeJS.ProcessEnv,\n options: { dryRun: boolean; writeShell: boolean },\n) {\n const current = (env.PATH || '').split(delimiter).filter(Boolean)\n const pathReady = current.includes(binDir)\n const shell = env.SHELL || ''\n const rcFile = shell.endsWith('/zsh')\n ? join(home, '.zshrc')\n : shell.endsWith('/bash')\n ? join(home, '.bashrc')\n : ''\n const isDefaultBin = binDir === join(home, '.local', 'bin')\n const activateCommand = isDefaultBin\n ? 'export PATH=\"$HOME/.local/bin:$PATH\"'\n : `export PATH=${shellQuote(binDir)}:\"$PATH\"`\n let updated = false\n if (!pathReady && options.writeShell && rcFile) {\n const before = existsSync(rcFile) ? readFileSync(rcFile, 'utf8') : ''\n if (!before.includes(PATH_MARKER_START) && !options.dryRun) {\n const pathLine = isDefaultBin\n ? 'export PATH=\"$HOME/.local/bin:$PATH\"'\n : `export PATH=${shellQuote(binDir)}:\"$PATH\"`\n const block = `${before && !before.endsWith('\\n') ? '\\n' : ''}${PATH_MARKER_START}\\n` +\n `${pathLine}\\n${PATH_MARKER_END}\\n`\n appendFileSync(rcFile, block)\n updated = true\n }\n }\n return { pathReady, rcFile, updated, activateCommand }\n}\n\nfunction shellQuote(value: string): string {\n return `'${value.replace(/'/g, `'\"'\"'`)}'`\n}\n\nfunction readInstalledVersion(executable: string, env: NodeJS.ProcessEnv): string {\n const run = spawnSync(executable, ['--version'], { encoding: 'utf8', env, timeout: 8_000 })\n return run.status === 0 ? String(run.stdout || '').trim() : ''\n}\n"]}
@@ -1,14 +1,41 @@
1
1
  // Skill 安装生命周期由开放生态的 `npx skills` 负责。
2
2
  // dingtalk-agent 只做两件事:把内置 Skill 目录交给上游 CLI;只读验证客户端能否发现。
3
+ // 默认(不指定 name)对全部内置 Skill 生效:基础行为 + Agent 装配;指定 name 时只操作该 Skill。
3
4
  import { existsSync, lstatSync, readFileSync, readlinkSync } from 'node:fs';
4
5
  import { homedir } from 'node:os';
5
6
  import { dirname, join, resolve } from 'node:path';
6
7
  import { spawnSync } from 'node:child_process';
7
8
  export const GLOBAL_SKILL_NAME = 'dingtalk-basic-behavior';
9
+ // 默认套装:所有机器都装的通用 Skill。平台 Skill(deploy/boot-multica 等)不在默认套装内,
10
+ // 只有工作区通过 `dta map use` 选择对应 managed agents platform 时才按名安装。
8
11
  export const BUNDLED_SKILL_NAMES = [GLOBAL_SKILL_NAME, 'dingtalk-agent-compose'];
12
+ export const INSTALLABLE_SKILL_NAMES = [
13
+ ...BUNDLED_SKILL_NAMES,
14
+ 'dingtalk-agent-deploy', 'dingtalk-agent-boot-multica', 'multica-fde-external',
15
+ ];
9
16
  const SKILLS_PACKAGE = 'skills@latest';
10
17
  const REGISTRY = 'https://registry.npmjs.org';
11
18
  const AGENTS = ['claude-code', 'codex', 'opencode'];
19
+ export function skillSuiteStatus(packageRoot, options = {}) {
20
+ return suiteOf(BUNDLED_SKILL_NAMES.map((name) => skillStatus(packageRoot, { ...options, name })));
21
+ }
22
+ export function installBundledSkills(packageRoot, options = {}) {
23
+ return suiteOf(BUNDLED_SKILL_NAMES.map((name) => installGlobalSkill(packageRoot, { ...options, name })));
24
+ }
25
+ export function upgradeBundledSkills(packageRoot, options = {}) {
26
+ return suiteOf(BUNDLED_SKILL_NAMES.map((name) => upgradeGlobalSkill(packageRoot, { ...options, name })));
27
+ }
28
+ export function uninstallBundledSkills(packageRoot, options = {}) {
29
+ return suiteOf(BUNDLED_SKILL_NAMES.map((name) => uninstallGlobalSkill(packageRoot, { ...options, name })));
30
+ }
31
+ function suiteOf(skills) {
32
+ return {
33
+ $schema: 'dingtalk-agent/skill-status-suite@1',
34
+ manager: 'skills-cli',
35
+ names: skills.map((skill) => skill.name),
36
+ skills,
37
+ };
38
+ }
12
39
  export function skillStatus(packageRoot, options = {}) {
13
40
  const name = bundledSkillName(options.name);
14
41
  const paths = globalPaths(packageRoot, options.home, name);
@@ -143,8 +170,8 @@ function validateSkill(root, name) {
143
170
  }
144
171
  function bundledSkillName(value = '') {
145
172
  const name = value.trim() || GLOBAL_SKILL_NAME;
146
- if (!BUNDLED_SKILL_NAMES.includes(name)) {
147
- throw new Error(`不支持的内置 Skill: ${name};可用: ${BUNDLED_SKILL_NAMES.join(', ')}`);
173
+ if (!INSTALLABLE_SKILL_NAMES.includes(name)) {
174
+ throw new Error(`不支持的内置 Skill: ${name};可用: ${INSTALLABLE_SKILL_NAMES.join(', ')}`);
148
175
  }
149
176
  return name;
150
177
  }
@@ -1 +1 @@
1
- {"version":3,"file":"skill-manager.js","sourceRoot":"","sources":["../../src/skill-manager.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,yDAAyD;AAEzD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9C,MAAM,CAAC,MAAM,iBAAiB,GAAG,yBAAyB,CAAA;AAC1D,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,iBAAiB,EAAE,wBAAwB,CAAU,CAAA;AACzF,MAAM,cAAc,GAAG,eAAe,CAAA;AACtC,MAAM,QAAQ,GAAG,4BAA4B,CAAA;AAC7C,MAAM,MAAM,GAAG,CAAC,aAAa,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;AAqCnD,MAAM,UAAU,WAAW,CAAC,WAAmB,EAAE,UAA+B,EAAE;IAChF,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC1D,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;IAC9C,MAAM,eAAe,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACpD,MAAM,gBAAgB,GAAG,eAAe;QACtC,CAAC,CAAC,qBAAqB,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO;QACxF,CAAC,CAAC,EAAE,CAAA;IACN,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAA;IAC7D,MAAM,WAAW,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;IACtD,OAAO;QACL,OAAO,EAAE,+BAA+B;QACxC,IAAI;QACJ,OAAO,EAAE,YAAY;QACrB,OAAO;QACP,SAAS,EAAE;YACT,IAAI,EAAE,KAAK,CAAC,SAAS;YACrB,MAAM,EAAE,eAAe;YACvB,gBAAgB;YAChB,OAAO,EAAE,OAAO,CAAC,eAAe,IAAI,gBAAgB,KAAK,OAAO,CAAC,YAAY,CAAC;SAC/E;QACD,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE;QACzC,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS;gBAC/D,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK;aACxC;YACD;gBACE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,qBAAqB;gBAC/D,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,WAAW;aAC1C;YACD;gBACE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,qBAAqB;gBACrE,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,WAAW;aAC1C;SACF;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,WAAmB,EACnB,UAA+B,EAAE;IAEjC,OAAO,SAAS,CAAC,WAAW,EAAE,SAAS,EAAE;QACvC,KAAK,EAAE,WAAW,CAAC,WAAW,EAAE,SAAS,EAAE,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;QACjF,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM;KAC1C,EAAE,OAAO,CAAC,CAAA;AACb,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,WAAmB,EACnB,UAA+B,EAAE;IAEjC,2DAA2D;IAC3D,OAAO,SAAS,CAAC,WAAW,EAAE,SAAS,EAAE;QACvC,KAAK,EAAE,WAAW,CAAC,WAAW,EAAE,SAAS,EAAE,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM;QACjF,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM;KAC1C,EAAE,OAAO,CAAC,CAAA;AACb,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,WAAmB,EACnB,UAA+B,EAAE;IAEjC,OAAO,SAAS,CAAC,WAAW,EAAE,WAAW,EAAE;QACzC,QAAQ,EAAE,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC;QACxC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM;KAC1C,EAAE,OAAO,CAAC,CAAA;AACb,CAAC;AAED,SAAS,SAAS,CAChB,WAAmB,EACnB,MAA2C,EAC3C,IAAc,EACd,OAA4B;IAE5B,MAAM,WAAW,GAAG;QAClB,OAAO,EAAE,cAAc,QAAQ,EAAE,EAAE,aAAa,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI;KAC1F,CAAA;IACD,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,GAAG,WAAW,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjE,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAChD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO;YACL,GAAG,MAAM;YACT,SAAS,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;SAC5E,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAG;QACV,GAAG,OAAO,CAAC,GAAG;QACd,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC;QACtB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,OAAO,EAAE;KACzE,CAAA;IACD,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE;QACxC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO;KACxC,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;IACzE,IAAI,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,MAAM,GAAI,GAAG,CAAC,KAA2C,EAAE,IAAI,KAAK,QAAQ;YAChF,CAAC,CAAC,2CAA2C;YAC7C,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,MAAM,IAAI,OAAO,GAAG,CAAC,MAAM,EAAE,CAAA;QACvD,MAAM,IAAI,KAAK,CACb,cAAc,MAAM,QAAQ,MAAM,IAAI;YACtC,UAAU,OAAO,EAAE,CACpB,CAAA;IACH,CAAC;IACD,OAAO;QACL,GAAG,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC;QACpC,SAAS,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE;KAC7E,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,WAAmB,EAAE,IAAI,GAAG,OAAO,EAAE,EAAE,IAAI,GAAG,iBAAiB;IAClF,OAAO;QACL,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,IAAI,CAAC;QACzC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC;QAChD,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC;KAC9C,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,WAAmB,EAAE,IAAY;IACpD,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,MAAM,CAAA;IAC/D,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;IAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;IAC/E,MAAM,WAAW,GAAG,qBAAqB,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;IACzF,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC;QACzC,YAAY,EAAE,WAAW,CAAC,OAAO;KAClC,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB,EAAE,SAAiB;IAI1D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;IAClE,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAA;IAChC,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;QAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE,CAAA;IACpE,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;IAClC,OAAO,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,KAAK,OAAO,CAAC,SAAS,CAAC;QAC3D,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;QAC9B,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAA;AACxC,CAAC;AAED,SAAS,aAAa,CAAC,IAAY,EAAE,IAAY;IAC/C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAA;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAA;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAA;IACpE,MAAM,QAAQ,GAAG,qBAAqB,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;IAClE,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,cAAc,QAAQ,CAAC,IAAI,SAAS,IAAI,MAAM,CAAC,CAAA;IACjE,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;AAChF,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAK,GAAG,EAAE;IAClC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,iBAAiB,CAAA;IAC9C,IAAI,CAAE,mBAAyC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,QAAQ,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChF,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAClE,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;IAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;IACtB,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,EAAE;QACjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,YAAY,EAAE,GAAG,CAAC,CAAC,CAAA;QAC/D,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACrE,CAAC,CAAA;IACD,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,mFAAmF,CAAC,CAAA;IACtH,OAAO;QACL,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC;QACxB,WAAW,EAAE,UAAU,CAAC,aAAa,CAAC;QACtC,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,UAAU,CAAC,SAAS,CAAC;KAC7D,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC;QAAC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAA;IAAC,CAAC;AACrE,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,CAAC;QAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAAC,OAAO,IAAI,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAA;IAAC,CAAC;AAC7D,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAA;AAC1F,CAAC","sourcesContent":["// Skill 安装生命周期由开放生态的 `npx skills` 负责。\n// dingtalk-agent 只做两件事:把内置 Skill 目录交给上游 CLI;只读验证客户端能否发现。\n\nimport { existsSync, lstatSync, readFileSync, readlinkSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport { spawnSync } from 'node:child_process'\n\nexport const GLOBAL_SKILL_NAME = 'dingtalk-basic-behavior'\nexport const BUNDLED_SKILL_NAMES = [GLOBAL_SKILL_NAME, 'dingtalk-agent-compose'] as const\nconst SKILLS_PACKAGE = 'skills@latest'\nconst REGISTRY = 'https://registry.npmjs.org'\nconst AGENTS = ['claude-code', 'codex', 'opencode']\n\nexport interface SkillManagerOptions {\n home?: string\n dryRun?: boolean\n env?: NodeJS.ProcessEnv\n name?: string\n}\n\nexport interface GlobalSkillStatus {\n $schema: 'dingtalk-agent/skill-status@2'\n name: string\n manager: 'skills-cli'\n bundled: { path: string; packageVersion: string; skillVersion: string }\n canonical: {\n path: string\n exists: boolean\n installedVersion: string\n current: boolean\n }\n claude: { path: string; state: 'ok' | 'missing' | 'conflict'; target: string }\n clients: Array<{\n name: 'claude-code' | 'codex' | 'opencode'\n label: string\n discovery: 'symlink' | 'shared-agent-skills'\n path: string\n state: 'ok' | 'missing' | 'conflict'\n }>\n operation?: {\n action: 'install' | 'upgrade' | 'uninstall'\n command: string\n executed: boolean\n exitCode: number | null\n output: string\n }\n}\n\nexport function skillStatus(packageRoot: string, options: SkillManagerOptions = {}): GlobalSkillStatus {\n const name = bundledSkillName(options.name)\n const paths = globalPaths(packageRoot, options.home, name)\n const bundled = bundledInfo(packageRoot, name)\n const canonicalExists = isDirectory(paths.canonical)\n const installedVersion = canonicalExists\n ? parseSkillFrontmatter(readFileSync(join(paths.canonical, 'SKILL.md'), 'utf8')).version\n : ''\n const claude = inspectExposure(paths.claude, paths.canonical)\n const sharedState = canonicalExists ? 'ok' : 'missing'\n return {\n $schema: 'dingtalk-agent/skill-status@2',\n name,\n manager: 'skills-cli',\n bundled,\n canonical: {\n path: paths.canonical,\n exists: canonicalExists,\n installedVersion,\n current: Boolean(canonicalExists && installedVersion === bundled.skillVersion),\n },\n claude: { path: paths.claude, ...claude },\n clients: [\n {\n name: 'claude-code', label: 'Claude Code', discovery: 'symlink',\n path: paths.claude, state: claude.state,\n },\n {\n name: 'codex', label: 'Codex', discovery: 'shared-agent-skills',\n path: paths.canonical, state: sharedState,\n },\n {\n name: 'opencode', label: 'OpenCode', discovery: 'shared-agent-skills',\n path: paths.canonical, state: sharedState,\n },\n ],\n }\n}\n\nexport function installGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n return runSkills(packageRoot, 'install', [\n 'add', globalPaths(packageRoot, undefined, bundledSkillName(options.name)).source,\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nexport function upgradeGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n // Skill 随 npm 包发布;重新 add 当前包内目录,让 skills CLI 执行自己的覆盖/链接语义。\n return runSkills(packageRoot, 'upgrade', [\n 'add', globalPaths(packageRoot, undefined, bundledSkillName(options.name)).source,\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nexport function uninstallGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n return runSkills(packageRoot, 'uninstall', [\n 'remove', bundledSkillName(options.name),\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nfunction runSkills(\n packageRoot: string,\n action: 'install' | 'upgrade' | 'uninstall',\n args: string[],\n options: SkillManagerOptions,\n): GlobalSkillStatus {\n const commandArgs = [\n '--yes', `--registry=${REGISTRY}`, `--package=${SKILLS_PACKAGE}`, '--', 'skills', ...args,\n ]\n const command = ['npx', ...commandArgs].map(shellQuote).join(' ')\n const before = skillStatus(packageRoot, options)\n if (options.dryRun) {\n return {\n ...before,\n operation: { action, command, executed: false, exitCode: null, output: '' },\n }\n }\n\n const env = {\n ...process.env,\n ...(options.env || {}),\n HOME: options.home || options.env?.HOME || process.env.HOME || homedir(),\n }\n const run = spawnSync('npx', commandArgs, {\n encoding: 'utf8', env, timeout: 120_000,\n })\n const output = [run.stdout, run.stderr].filter(Boolean).join('\\n').trim()\n if (run.error || run.status !== 0) {\n const reason = (run.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT'\n ? 'PATH 找不到 npx;请安装带 npm/npx 的 Node.js 18.3+'\n : run.error?.message || output || `退出码 ${run.status}`\n throw new Error(\n `skills CLI ${action} 失败: ${reason}\\n` +\n `可手动执行: ${command}`,\n )\n }\n return {\n ...skillStatus(packageRoot, options),\n operation: { action, command, executed: true, exitCode: run.status, output },\n }\n}\n\nfunction globalPaths(packageRoot: string, home = homedir(), name = GLOBAL_SKILL_NAME) {\n return {\n source: join(packageRoot, 'skills', name),\n canonical: join(home, '.agents', 'skills', name),\n claude: join(home, '.claude', 'skills', name),\n }\n}\n\nfunction bundledInfo(packageRoot: string, name: string) {\n const source = globalPaths(packageRoot, undefined, name).source\n validateSkill(source, name)\n const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'))\n const frontmatter = parseSkillFrontmatter(readFileSync(join(source, 'SKILL.md'), 'utf8'))\n return {\n path: source,\n packageVersion: String(pkg.version || ''),\n skillVersion: frontmatter.version,\n }\n}\n\nfunction inspectExposure(exposure: string, canonical: string): {\n state: 'ok' | 'missing' | 'conflict'\n target: string\n} {\n if (!pathExists(exposure)) return { state: 'missing', target: '' }\n const stat = lstatSync(exposure)\n if (!stat.isSymbolicLink()) return { state: 'conflict', target: '' }\n const raw = readlinkSync(exposure)\n return resolve(dirname(exposure), raw) === resolve(canonical)\n ? { state: 'ok', target: raw }\n : { state: 'conflict', target: raw }\n}\n\nfunction validateSkill(root: string, name: string): void {\n if (!isDirectory(root)) throw new Error(`内置 Skill 不存在: ${root}`)\n const file = join(root, 'SKILL.md')\n if (!existsSync(file)) throw new Error(`Skill 缺少 SKILL.md: ${root}`)\n const metadata = parseSkillFrontmatter(readFileSync(file, 'utf8'))\n if (metadata.name !== name) {\n throw new Error(`Skill name=${metadata.name} 与目录名 ${name} 不一致`)\n }\n if (!metadata.description) throw new Error('Skill frontmatter 缺少 description')\n}\n\nfunction bundledSkillName(value = ''): string {\n const name = value.trim() || GLOBAL_SKILL_NAME\n if (!(BUNDLED_SKILL_NAMES as readonly string[]).includes(name)) {\n throw new Error(`不支持的内置 Skill: ${name};可用: ${BUNDLED_SKILL_NAMES.join(', ')}`)\n }\n return name\n}\n\nfunction parseSkillFrontmatter(text: string): { name: string; description: string; version: string } {\n const match = text.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---(?:\\r?\\n|$)/)\n if (!match) throw new Error('SKILL.md 缺少 YAML frontmatter')\n const block = match[1]\n const readScalar = (key: string) => {\n const found = block.match(new RegExp(`^${key}:\\\\s*(.+)$`, 'm'))\n return found ? found[1].trim().replace(/^(['\"])(.*)\\1$/, '$2') : ''\n }\n const nestedVersion = block.match(/^metadata:\\s*\\r?\\n(?:[ \\t]+.*\\r?\\n)*?[ \\t]+version:\\s*['\"]?([^'\"\\r\\n]+)['\"]?\\s*$/m)\n return {\n name: readScalar('name'),\n description: readScalar('description'),\n version: nestedVersion?.[1]?.trim() || readScalar('version'),\n }\n}\n\nfunction isDirectory(path: string): boolean {\n try { return lstatSync(path).isDirectory() } catch { return false }\n}\n\nfunction pathExists(path: string): boolean {\n try { lstatSync(path); return true } catch { return false }\n}\n\nfunction shellQuote(value: string): string {\n return /^[A-Za-z0-9_./:=@-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\"'\"'`)}'`\n}\n"]}
1
+ {"version":3,"file":"skill-manager.js","sourceRoot":"","sources":["../../src/skill-manager.ts"],"names":[],"mappings":"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","sourcesContent":["// Skill 安装生命周期由开放生态的 `npx skills` 负责。\n// dingtalk-agent 只做两件事:把内置 Skill 目录交给上游 CLI;只读验证客户端能否发现。\n// 默认(不指定 name)对全部内置 Skill 生效:基础行为 + Agent 装配;指定 name 时只操作该 Skill。\n\nimport { existsSync, lstatSync, readFileSync, readlinkSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join, resolve } from 'node:path'\nimport { spawnSync } from 'node:child_process'\n\nexport const GLOBAL_SKILL_NAME = 'dingtalk-basic-behavior'\n// 默认套装:所有机器都装的通用 Skill。平台 Skill(deploy/boot-multica 等)不在默认套装内,\n// 只有工作区通过 `dta map use` 选择对应 managed agents platform 时才按名安装。\nexport const BUNDLED_SKILL_NAMES = [GLOBAL_SKILL_NAME, 'dingtalk-agent-compose'] as const\nexport const INSTALLABLE_SKILL_NAMES = [\n ...BUNDLED_SKILL_NAMES,\n 'dingtalk-agent-deploy', 'dingtalk-agent-boot-multica', 'multica-fde-external',\n] as const\nconst SKILLS_PACKAGE = 'skills@latest'\nconst REGISTRY = 'https://registry.npmjs.org'\nconst AGENTS = ['claude-code', 'codex', 'opencode']\n\nexport interface SkillManagerOptions {\n home?: string\n dryRun?: boolean\n env?: NodeJS.ProcessEnv\n name?: string\n}\n\nexport interface GlobalSkillStatus {\n $schema: 'dingtalk-agent/skill-status@2'\n name: string\n manager: 'skills-cli'\n bundled: { path: string; packageVersion: string; skillVersion: string }\n canonical: {\n path: string\n exists: boolean\n installedVersion: string\n current: boolean\n }\n claude: { path: string; state: 'ok' | 'missing' | 'conflict'; target: string }\n clients: Array<{\n name: 'claude-code' | 'codex' | 'opencode'\n label: string\n discovery: 'symlink' | 'shared-agent-skills'\n path: string\n state: 'ok' | 'missing' | 'conflict'\n }>\n operation?: {\n action: 'install' | 'upgrade' | 'uninstall'\n command: string\n executed: boolean\n exitCode: number | null\n output: string\n }\n}\n\nexport interface GlobalSkillSuiteStatus {\n $schema: 'dingtalk-agent/skill-status-suite@1'\n manager: 'skills-cli'\n names: string[]\n skills: GlobalSkillStatus[]\n}\n\nexport function skillSuiteStatus(\n packageRoot: string,\n options: Omit<SkillManagerOptions, 'name'> = {},\n): GlobalSkillSuiteStatus {\n return suiteOf(BUNDLED_SKILL_NAMES.map((name) => skillStatus(packageRoot, { ...options, name })))\n}\n\nexport function installBundledSkills(\n packageRoot: string,\n options: Omit<SkillManagerOptions, 'name'> = {},\n): GlobalSkillSuiteStatus {\n return suiteOf(BUNDLED_SKILL_NAMES.map((name) => installGlobalSkill(packageRoot, { ...options, name })))\n}\n\nexport function upgradeBundledSkills(\n packageRoot: string,\n options: Omit<SkillManagerOptions, 'name'> = {},\n): GlobalSkillSuiteStatus {\n return suiteOf(BUNDLED_SKILL_NAMES.map((name) => upgradeGlobalSkill(packageRoot, { ...options, name })))\n}\n\nexport function uninstallBundledSkills(\n packageRoot: string,\n options: Omit<SkillManagerOptions, 'name'> = {},\n): GlobalSkillSuiteStatus {\n return suiteOf(BUNDLED_SKILL_NAMES.map((name) => uninstallGlobalSkill(packageRoot, { ...options, name })))\n}\n\nfunction suiteOf(skills: GlobalSkillStatus[]): GlobalSkillSuiteStatus {\n return {\n $schema: 'dingtalk-agent/skill-status-suite@1',\n manager: 'skills-cli',\n names: skills.map((skill) => skill.name),\n skills,\n }\n}\n\nexport function skillStatus(packageRoot: string, options: SkillManagerOptions = {}): GlobalSkillStatus {\n const name = bundledSkillName(options.name)\n const paths = globalPaths(packageRoot, options.home, name)\n const bundled = bundledInfo(packageRoot, name)\n const canonicalExists = isDirectory(paths.canonical)\n const installedVersion = canonicalExists\n ? parseSkillFrontmatter(readFileSync(join(paths.canonical, 'SKILL.md'), 'utf8')).version\n : ''\n const claude = inspectExposure(paths.claude, paths.canonical)\n const sharedState = canonicalExists ? 'ok' : 'missing'\n return {\n $schema: 'dingtalk-agent/skill-status@2',\n name,\n manager: 'skills-cli',\n bundled,\n canonical: {\n path: paths.canonical,\n exists: canonicalExists,\n installedVersion,\n current: Boolean(canonicalExists && installedVersion === bundled.skillVersion),\n },\n claude: { path: paths.claude, ...claude },\n clients: [\n {\n name: 'claude-code', label: 'Claude Code', discovery: 'symlink',\n path: paths.claude, state: claude.state,\n },\n {\n name: 'codex', label: 'Codex', discovery: 'shared-agent-skills',\n path: paths.canonical, state: sharedState,\n },\n {\n name: 'opencode', label: 'OpenCode', discovery: 'shared-agent-skills',\n path: paths.canonical, state: sharedState,\n },\n ],\n }\n}\n\nexport function installGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n return runSkills(packageRoot, 'install', [\n 'add', globalPaths(packageRoot, undefined, bundledSkillName(options.name)).source,\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nexport function upgradeGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n // Skill 随 npm 包发布;重新 add 当前包内目录,让 skills CLI 执行自己的覆盖/链接语义。\n return runSkills(packageRoot, 'upgrade', [\n 'add', globalPaths(packageRoot, undefined, bundledSkillName(options.name)).source,\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nexport function uninstallGlobalSkill(\n packageRoot: string,\n options: SkillManagerOptions = {},\n): GlobalSkillStatus {\n return runSkills(packageRoot, 'uninstall', [\n 'remove', bundledSkillName(options.name),\n '--global', '--yes', '--agent', ...AGENTS,\n ], options)\n}\n\nfunction runSkills(\n packageRoot: string,\n action: 'install' | 'upgrade' | 'uninstall',\n args: string[],\n options: SkillManagerOptions,\n): GlobalSkillStatus {\n const commandArgs = [\n '--yes', `--registry=${REGISTRY}`, `--package=${SKILLS_PACKAGE}`, '--', 'skills', ...args,\n ]\n const command = ['npx', ...commandArgs].map(shellQuote).join(' ')\n const before = skillStatus(packageRoot, options)\n if (options.dryRun) {\n return {\n ...before,\n operation: { action, command, executed: false, exitCode: null, output: '' },\n }\n }\n\n const env = {\n ...process.env,\n ...(options.env || {}),\n HOME: options.home || options.env?.HOME || process.env.HOME || homedir(),\n }\n const run = spawnSync('npx', commandArgs, {\n encoding: 'utf8', env, timeout: 120_000,\n })\n const output = [run.stdout, run.stderr].filter(Boolean).join('\\n').trim()\n if (run.error || run.status !== 0) {\n const reason = (run.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT'\n ? 'PATH 找不到 npx;请安装带 npm/npx 的 Node.js 18.3+'\n : run.error?.message || output || `退出码 ${run.status}`\n throw new Error(\n `skills CLI ${action} 失败: ${reason}\\n` +\n `可手动执行: ${command}`,\n )\n }\n return {\n ...skillStatus(packageRoot, options),\n operation: { action, command, executed: true, exitCode: run.status, output },\n }\n}\n\nfunction globalPaths(packageRoot: string, home = homedir(), name = GLOBAL_SKILL_NAME) {\n return {\n source: join(packageRoot, 'skills', name),\n canonical: join(home, '.agents', 'skills', name),\n claude: join(home, '.claude', 'skills', name),\n }\n}\n\nfunction bundledInfo(packageRoot: string, name: string) {\n const source = globalPaths(packageRoot, undefined, name).source\n validateSkill(source, name)\n const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'))\n const frontmatter = parseSkillFrontmatter(readFileSync(join(source, 'SKILL.md'), 'utf8'))\n return {\n path: source,\n packageVersion: String(pkg.version || ''),\n skillVersion: frontmatter.version,\n }\n}\n\nfunction inspectExposure(exposure: string, canonical: string): {\n state: 'ok' | 'missing' | 'conflict'\n target: string\n} {\n if (!pathExists(exposure)) return { state: 'missing', target: '' }\n const stat = lstatSync(exposure)\n if (!stat.isSymbolicLink()) return { state: 'conflict', target: '' }\n const raw = readlinkSync(exposure)\n return resolve(dirname(exposure), raw) === resolve(canonical)\n ? { state: 'ok', target: raw }\n : { state: 'conflict', target: raw }\n}\n\nfunction validateSkill(root: string, name: string): void {\n if (!isDirectory(root)) throw new Error(`内置 Skill 不存在: ${root}`)\n const file = join(root, 'SKILL.md')\n if (!existsSync(file)) throw new Error(`Skill 缺少 SKILL.md: ${root}`)\n const metadata = parseSkillFrontmatter(readFileSync(file, 'utf8'))\n if (metadata.name !== name) {\n throw new Error(`Skill name=${metadata.name} 与目录名 ${name} 不一致`)\n }\n if (!metadata.description) throw new Error('Skill frontmatter 缺少 description')\n}\n\nfunction bundledSkillName(value = ''): string {\n const name = value.trim() || GLOBAL_SKILL_NAME\n if (!(INSTALLABLE_SKILL_NAMES as readonly string[]).includes(name)) {\n throw new Error(`不支持的内置 Skill: ${name};可用: ${INSTALLABLE_SKILL_NAMES.join(', ')}`)\n }\n return name\n}\n\nfunction parseSkillFrontmatter(text: string): { name: string; description: string; version: string } {\n const match = text.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---(?:\\r?\\n|$)/)\n if (!match) throw new Error('SKILL.md 缺少 YAML frontmatter')\n const block = match[1]\n const readScalar = (key: string) => {\n const found = block.match(new RegExp(`^${key}:\\\\s*(.+)$`, 'm'))\n return found ? found[1].trim().replace(/^(['\"])(.*)\\1$/, '$2') : ''\n }\n const nestedVersion = block.match(/^metadata:\\s*\\r?\\n(?:[ \\t]+.*\\r?\\n)*?[ \\t]+version:\\s*['\"]?([^'\"\\r\\n]+)['\"]?\\s*$/m)\n return {\n name: readScalar('name'),\n description: readScalar('description'),\n version: nestedVersion?.[1]?.trim() || readScalar('version'),\n }\n}\n\nfunction isDirectory(path: string): boolean {\n try { return lstatSync(path).isDirectory() } catch { return false }\n}\n\nfunction pathExists(path: string): boolean {\n try { lstatSync(path); return true } catch { return false }\n}\n\nfunction shellQuote(value: string): string {\n return /^[A-Za-z0-9_./:=@-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\"'\"'`)}'`\n}\n"]}
@@ -69,7 +69,7 @@ npm 全局命令会被链接到 `{prefix}/bin`,但不同 Node 版本管理器
69
69
  npm install → dta setup
70
70
  → 安装当前版本到 ~/.local/bin
71
71
  → 检查并幂等补充 ~/.zshrc / ~/.bashrc PATH
72
- → 安装 canonical Basic Behavior Skill
72
+ → 安装 canonical 内置 Skill(Basic Behavior + Compose)
73
73
  → 暴露给 Claude Code,验证 Codex/OpenCode 共享发现
74
74
  → 检查 DWS 版本和认证
75
75
  → 给出唯一下一条命令
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://github.com/D1-2004/dingtalk-agent/docs/schemas/agent-platform.schema.json",
4
+ "title": "dingtalk-agent Managed Agent Platform declaration",
5
+ "description": "工作区归属的 managed agent platform。解析顺序:DTA_AGENT_PLATFORM 环境变量 > dingtalk-agent.json#agentPlatform > .dingtalk-agent/agent-platform.json > 按 Provider 声明推断。",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["$schema", "agentPlatform"],
9
+ "properties": {
10
+ "$schema": { "const": "dingtalk-agent/agent-platform@1" },
11
+ "agentPlatform": { "enum": ["multica-dingtalk", "deap"] }
12
+ }
13
+ }
@@ -9,6 +9,7 @@
9
9
  "$schema": { "const": "dingtalk-agent/project@1" },
10
10
  "name": { "$ref": "#/$defs/name" },
11
11
  "dtaVersion": { "type": "string", "minLength": 1 },
12
+ "agentPlatform": { "enum": ["multica-dingtalk", "deap"] },
12
13
  "agent": {
13
14
  "type": "object",
14
15
  "additionalProperties": false,
@@ -24,12 +24,13 @@
24
24
  },
25
25
  "install": {
26
26
  "type": "object", "additionalProperties": false,
27
- "required": ["offlineTarball", "cliEntries", "versionMatched", "canonicalSkillCopies", "clientsReady"],
27
+ "required": ["offlineTarball", "cliEntries", "versionMatched", "canonicalSkillCopies", "composeSkillCopies", "clientsReady"],
28
28
  "properties": {
29
29
  "offlineTarball": { "const": true },
30
30
  "cliEntries": { "const": 2 },
31
31
  "versionMatched": { "const": true },
32
32
  "canonicalSkillCopies": { "const": 1 },
33
+ "composeSkillCopies": { "const": 1 },
33
34
  "clientsReady": { "const": 3 }
34
35
  }
35
36
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xdxer/dingtalk-agent",
3
- "version": "0.1.4-beta.10",
3
+ "version": "0.1.4-beta.12",
4
4
  "description": "钉钉数字员工的 Skill-first 行为范式:全局 Skill 决策,CLI 固定事务边界,Workspace 按需。",
5
5
  "keywords": [
6
6
  "dingtalk",
@@ -22,6 +22,7 @@
22
22
  "skills/dingtalk-agent-compose",
23
23
  "skills/dingtalk-agent-deploy",
24
24
  "skills/dingtalk-agent-eval",
25
+ "skills/multica-fde-external",
25
26
  "examples/agents",
26
27
  "templates/behaviors",
27
28
  "templates/fields",
@@ -1,24 +1,25 @@
1
1
  ---
2
2
  name: dingtalk-agent-compose
3
- description: 当用户要把 GitHub 仓库、本地文件夹或钉钉文档定义成一个 XXX Agent,或要审计、补齐、优化 Agent 的 AGENTS.md、本体职责、岗位 Skills、记忆/知识/产物存储与 DWS 权限绑定时使用。即使尚未 init Workspace,也按 dingtalk-agent 的 AgentDefinition 范式给出可运行的最小装配方案;不负责事件触发器。
3
+ description: 当用户要创建、新建、装配一个 Agent 或钉钉数字员工——包括把 GitHub 仓库、本地文件夹或钉钉文档定义成 Agent,或要审计、补齐、优化 Agent 的 AGENTS.md、本体职责、岗位 Skills、记忆/知识/产物存储与 DWS 权限绑定时使用。即使尚未 init Workspace,也按 dingtalk-agent 的 AgentDefinition 范式给出可运行的最小装配方案;不负责事件触发器。
4
4
  compatibility: Requires dingtalk-agent on PATH; remote DingTalk documents require authenticated dws.
5
5
  metadata:
6
- version: "0.5.0"
6
+ version: "0.6.0"
7
7
  ---
8
8
 
9
- # 装配一个可工作的 XXX Agent
9
+ # 装配一个可工作的钉钉数字员工 Agent
10
10
 
11
11
  把用户已有的仓库、目录或钉钉文档整理成两部分:**本体(body + role skills)**和**存储路由(memory + knowledge + artifacts + private state)**。复用 dta 的 Basic Behavior、Invocation、Session/Run/Wait 与 Action Gate,不复制一套新运行时。
12
12
 
13
13
  ## 工作顺序
14
14
 
15
15
  1. 识别来源和运行方式:GitHub 先由宿主 clone/checkout,本 Skill 不接管凭证;本地目录直接读取;钉钉文档只承担 memory/knowledge 等远端语义状态。本体 `AGENTS.md` 与 Role Skills 保持在本地、可版本化。
16
- 2. 对已有仓库优先运行 `dta agent enhance --project-name <name> --role-skill <role> --dry-run --json`。它只生成 `agent-enhancement-plan@1`,不会写文件、访问 DWS 或创建 Trigger。审阅 operations、blockers semanticReview 后,才复制计划给出的命令,用同一组参数、当前 `planId` `--yes` 落盘。
17
- 3. apply 只允许本地文件副作用:先把被更新的旧文件备份到 `.dingtalk-agent/backups/agent-enhance/<operationId>/`,再写入并按 hash 回读;自定义 private state 目录必须同步进入 `.gitignore`。输入漂移、planId 过期、非法 Role 路径、未知 OpenCode instruction、路径越界或 symlink 都必须 fail closed。不要跳过 plan,也不要把 `--yes` 写进无人审阅的默认脚本。
18
- 4. 审核本体:优先使用 `AGENTS.md` 表达长期身份、职责、交付物、拒绝边界和协作方式。CLI 只补骨架,绝不虚构这些语义;只要 `AGENTS.md` Role Skill 仍含模板 `<...>`,`agent audit` 必须保持 `partial`。
19
- 5. 审核能力:Basic Behavior 是所有钉钉员工共享且**每个 Session 必须加载**的协议;岗位知识和流程拆到独立 Role/Workflow Skill。目录可发现不等于正文已加载,必须为目标 Agent Host 生成可验证的加载合同。不要把 FDE、招聘、事故处理等岗位方法写回 Basic Skill。
20
- 6. 审核存储:明确工作记忆、业务事实、长期知识、产物和宿主私有控制状态分别去哪。介质可以换,语义层与控制状态不能混。远端 memory/knowledge plan 必须显式绑定 profile expected user,但 enhance 本身仍不读写远端。
21
- 7. 运行 `dta bootstrap --bindings agent.bindings.json --json` `dta agent audit --bindings agent.bindings.json --require-skill <role> --json`。静态配置和真实语义通过后再加 `--verify-load --yes`;不能把“写出了文件”或“目录存在”当成装配完成。
16
+ 2. **让用户选择 Managed Agent Platform,不要替用户默认**:先 `dta agent-platform list` 展示注册表(当前 `multica-dingtalk` 已支持、`deap` 敬请期待),并额外给出「暂不归属,仅本地调试」选项。用户选定托管平台后运行 `dta agent-platform use <platform>`——它写入归属声明并按需安装平台技能包(`multica-dingtalk` 对应 `dingtalk-agent-deploy`、`dingtalk-agent-boot-multica` `multica-fde-external`)。命令会同时输出 readiness 检查:multica CLI 未安装时按提示安装(`curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash`),未登录时引导 `multica login --server-url <endpoint>`(预发环境为 `https://pre-fde-workbench.dingtalk.com`),检测到代理环境变量时提醒连接失败可用 `env -u` 剥离。readiness 未过先引导用户补齐,再继续装配;选「暂不归属」则跳过,后续仍可随时归属。
17
+ 3. 对已有仓库优先运行 `dta agent enhance --project-name <name> --role-skill <role> --dry-run --json`。它只生成 `agent-enhancement-plan@1`,不会写文件、访问 DWS 或创建 Trigger。审阅 operations、blockers semanticReview 后,才复制计划给出的命令,用同一组参数、当前 `planId` `--yes` 落盘。
18
+ 4. apply 只允许本地文件副作用:先把被更新的旧文件备份到 `.dingtalk-agent/backups/agent-enhance/<operationId>/`,再写入并按 hash 回读;自定义 private state 目录必须同步进入 `.gitignore`。输入漂移、planId 过期、非法 Role 路径、未知 OpenCode instruction、路径越界或 symlink 都必须 fail closed。不要跳过 plan,也不要把 `--yes` 写进无人审阅的默认脚本。
19
+ 5. 审核本体:优先使用 `AGENTS.md` 表达长期身份、职责、交付物、拒绝边界和协作方式。CLI 只补骨架,绝不虚构这些语义;只要 `AGENTS.md` Role Skill 仍含模板 `<...>`,`agent audit` 必须保持 `partial`。
20
+ 6. 审核能力:Basic Behavior 是所有钉钉员工共享且**每个 Session 必须加载**的协议;岗位知识和流程拆到独立 Role/Workflow Skill。目录可发现不等于正文已加载,必须为目标 Agent Host 生成可验证的加载合同。不要把 FDE、招聘、事故处理等岗位方法写回 Basic Skill。
21
+ 7. 审核存储:明确工作记忆、业务事实、长期知识、产物和宿主私有控制状态分别去哪。介质可以换,语义层与控制状态不能混。远端 memory/knowledge plan 必须显式绑定 profile expected user,但 enhance 本身仍不读写远端。
22
+ 8. 运行 `dta bootstrap --bindings agent.bindings.json --json` 和 `dta agent audit --bindings agent.bindings.json --require-skill <role> --json`。静态配置和真实语义通过后再加 `--verify-load --yes`;不能把“写出了文件”或“目录存在”当成装配完成。
22
23
 
23
24
  ## Agent Host 加载合同
24
25
 
@@ -36,6 +37,15 @@ Why:OpenCode 会发现 `.agents/skills/<name>/SKILL.md`,但 Skill 正文默
36
37
 
37
38
  任何 `ready` 结论都必须保留以下证据:Basic Skill 的 name/version/hash、Host resolved config、项目内发现路径和一次随机 load probe。`agent-audit@1` 会把 Definition、Storage、Host exposure 与 load gate 分开报告;load gate 失败时,后续回答再像员工也只能算本体 Prompt 命中,不能算 Skill 生效。
38
39
 
40
+ ## 连接钉钉机器人的两条路径
41
+
42
+ 装配通过 audit `ready` 后,把 Agent 接到钉钉聊天有两条路径,必须呈现给用户选择:
43
+
44
+ - **本地调试(不需要托管平台)**:直接在宿主(OpenCode 等)里基于 `AGENTS.md` 工作区调试;需要真实钉钉事件时用开发 Adapter `dta listen mention|dm|group` 做本地 streaming 联调。适合开发期验证行为,不适合常驻服务。
45
+ - **发布到 Multica 托管平台(推荐正式使用)**:归属 `multica-dingtalk` 后,用平台技能包 `multica-fde-external`(`python3 scripts/multica_ext.py <命令>`)完成完整交付链——`workspace-create/workspace-init` 供给工作区 → `runtime-templates`/`agent-create` 供给运行时与 Agent → `agent-source-sync`/`skill-push` 同步本体与 Skill → `dingtalk-begin`/`dingtalk-bind` 绑定钉钉机器人(真实绑定需要真实 AppKey/AppSecret 或扫码,把返回的绑定链接交给用户完成)→ `chat-send --wait` 免钉钉直聊测试通道验收 → `task-trace --follow` 观测执行轨迹 → `agent-check` 综合体检。绑定完成后用户在钉钉向机器人发消息即可到达该 Agent。
46
+
47
+ 不要在未询问用户的情况下用 `dws dev app robot submit` 直接创建新的钉钉机器人应用——那是脱离托管平台的裸应用,消息事件不会到达任何 Agent 运行时;只有用户明确要自管事件链路时才走该路径。
48
+
39
49
  ## 可复制装配命令
40
50
 
41
51
  ```bash
@@ -14,7 +14,7 @@
14
14
  },
15
15
  {
16
16
  "id": 2,
17
- "prompt": "这个本地目录已经有 AGENTS.md 和 skills/,帮我判断能不能作为 XXX Agent,并给出验证命令。",
17
+ "prompt": "这个本地目录已经有 AGENTS.md 和 skills/,帮我判断能不能作为钉钉数字员工 Agent,并给出验证命令。",
18
18
  "expected_output": "运行 bootstrap 和 agent audit;依据稳定 check/missing/repairs 判断;说明 Basic 与 Role Skills 可叠加及 Session 冻结边界。",
19
19
  "files": [],
20
20
  "expectations": [