UDD Kit 的设计目标是:宿主项目接入一次,后续通过升级 udd-kit 版本持续获得新能力,而不是每次都重写接入逻辑。
宿主项目只需要负责两件事:
- 提供一个稳定的
adapter - 提供一份稳定的
udd.config.json
adapter 负责把宿主环境翻译成 UDD Runtime 能理解的上下文。
runtime 负责更新检查、issue 草稿、贡献草稿、GitHub 提交等会持续演进的能力。
在宿主项目根目录新增:
udd.config.json
可以从 udd.config.example.json 复制。
兼容旧名字:
agent-upgrade.json
安装:
npm install udd-kit最小接入:
import { defineAdapter } from "udd-kit/adapter";
import { createRuntime } from "udd-kit/runtime";
const adapter = defineAdapter({
name: "my-skill",
async getContext() {
return {
cwd: process.cwd(),
appName: "my-skill",
logs: ["./logs/latest.log"],
confirm: async (prompt) => {
console.log(prompt.title);
return true;
}
};
}
});
const runtime = await createRuntime({
cwd: process.cwd()
});
const result = await runtime.check(adapter);
if (result.shouldNotify) {
console.log(result.message);
}错误上报:
const issueDraft = await runtime.prepareIssue(adapter, {
error: {
message: err.message,
stack: err.stack
}
});本地修复回流:
const draft = await runtime.prepareContribution(adapter, {
summary: "fix retry loop"
});可以直接用 CLI,不需要写 JS SDK:
udd check --manifest ./udd.config.json
udd issue-draft --manifest ./udd.config.json --error "Request failed" --log ./logs/latest.log
udd contribute-draft --manifest ./udd.config.json --summary "Fix retry loop"
udd ignore --manifest ./udd.config.json --version 1.2.3为了确保“接一次、持续升级”成立,宿主应遵守这几个规则:
- 只依赖
adapter和runtime的公开接口 - 不直接调用内部文件
- 把宿主特有逻辑放在 adapter 中,不写进 runtime
- manifest 字段尽量补全,新增字段允许缺省
- 启动时:
runtime.check(adapter) - 捕获错误时:
runtime.prepareIssue(adapter, ...) - 用户修好问题后:
runtime.prepareContribution(adapter, ...) - 需要统一调度时:
runtime.run(adapter, hooks)
宿主项目未来升级 udd-kit 时,优先只做依赖版本升级:
npm update udd-kit如果没有新增宿主必填能力,就不需要改宿主接入代码。
下面这个例子展示了宿主如何把三类能力一起接进来:
invokeRepairAgent让宿主自己的 Agent 在本地隔离工作区里改代码- 可选的
UpdateKit provider如果宿主集成了UpdateKit,优先让它执行上游更新 - fallback provider
如果没有
UpdateKit,退回宿主原生更新器或手动更新提示
import { execFile } from "node:child_process";
import { promisify } from "node:util";
import { defineAdapter } from "udd-kit/adapter";
import { createRuntime } from "udd-kit/runtime";
import type { HookDefinition, RepairAgentRequest, UpdateProvider } from "udd-kit";
const execFileAsync = promisify(execFile);
type HostServices = {
runInternalRepairAgent: (request: RepairAgentRequest) => Promise<{
ok: boolean;
summary: string;
changedFiles: string[];
patchPreview?: string;
}>;
maybeCreateUpdateKitProvider: () => UpdateProvider | undefined;
runHostUpdate: (targetVersion?: string) => Promise<void>;
};
export async function runSelfHealing(host: HostServices) {
const runtime = await createRuntime({
cwd: process.cwd()
});
const hostNativeProvider: UpdateProvider = {
kind: "host-native",
async isAvailable() {
return true;
},
async plan(request) {
return {
summary: `Use host-native updater for ${request.targetVersion ?? "latest"}`,
targetVersion: request.targetVersion
};
},
async apply(request) {
await host.runHostUpdate(request.targetVersion);
return {
ok: true,
version: request.targetVersion,
details: "Updated using host-native updater."
};
}
};
const manualProvider: UpdateProvider = {
kind: "manual",
async describeManualSteps(request) {
return [
`Fetch upstream updates for ${request.repo}.`,
"Install or merge the updated version into the host environment.",
"Re-run the host verification suite."
];
}
};
const adapter = defineAdapter({
name: "my-host",
async getContext() {
return {
cwd: process.cwd(),
appName: "my-host",
appVersion: "1.2.3",
logs: ["./logs/latest.log"],
error: {
message: "dependency mismatch during runtime startup"
},
confirm: async () => true
};
},
async decide(prompt) {
if (prompt.kind === "update") {
return "update_once";
}
return "repair_once";
},
async invokeRepairAgent(request) {
return host.runInternalRepairAgent(request);
},
async getUpdateProviders() {
const providers = [
host.maybeCreateUpdateKitProvider(),
hostNativeProvider,
manualProvider
].filter((value): value is UpdateProvider => Boolean(value));
return providers;
},
async runHook(hook: HookDefinition, cwd: string) {
const command = hook.command ?? "true";
const { stdout } = await execFileAsync("sh", ["-lc", command], { cwd });
return {
ok: true,
output: stdout.trim()
};
}
});
const result = await runtime.heal(adapter, {
auth: process.env.GITHUB_TOKEN ? { token: process.env.GITHUB_TOKEN } : undefined,
submitIssueOnEscalation: true,
createPr: true
});
return result;
}接入约定建议如下:
- 如果宿主接了
UpdateKit,就把它包装成kind: "update-kit"的 provider 放在最前面 - 如果宿主没接
UpdateKit,仍然可以只提供host-native或manualprovider UDDKit会按 manifest 里的updateStrategyOrder选择 providerinvokeRepairAgent只负责改代码,验证、PR、issue、状态和审计都仍由UDDKit统一编排