fix: resolve 25 pre-publish blockers
- postinstall.mjs: fix alias package detection - migrate-legacy-plugin-entry: dedupe + regression tests - task_system: default consistency across runtime paths - task() contract: consistent tool behavior - runtime model selection, tool cap, stale-task cancellation - recovery sanitization, context-limit gating - Ralph semantic DONE hardening, Atlas fallback persistence - native-skill description/content, skill path traversal guard - publish workflow: platform awaited via reusable workflow job - release: version edits reapplied before commit/tag - JSONC plugin migration: top-level plugin key safety - cold-cache: user fallback models skip disconnected providers - docs/version/release framing updates Verified: bun test (4599 pass), tsc --noEmit clean, bun run build clean
This commit is contained in:
@@ -616,6 +616,33 @@ describe("skill tool - browserProvider forwarding", () => {
|
||||
})
|
||||
|
||||
describe("skill tool - nativeSkills integration", () => {
|
||||
it("includes native skills in the description even when skills are pre-seeded", async () => {
|
||||
//#given
|
||||
const tool = createSkillTool({
|
||||
skills: [createMockSkill("seeded-skill")],
|
||||
nativeSkills: {
|
||||
async all() {
|
||||
return [{
|
||||
name: "native-visible-skill",
|
||||
description: "Native skill exposed from config",
|
||||
location: "/external/skills/native-visible-skill/SKILL.md",
|
||||
content: "Native visible skill body",
|
||||
}]
|
||||
},
|
||||
async get() { return undefined },
|
||||
async dirs() { return [] },
|
||||
},
|
||||
})
|
||||
|
||||
//#when
|
||||
expect(tool.description).toContain("seeded-skill")
|
||||
await tool.execute({ name: "native-visible-skill" }, mockContext)
|
||||
|
||||
//#then
|
||||
expect(tool.description).toContain("seeded-skill")
|
||||
expect(tool.description).toContain("native-visible-skill")
|
||||
})
|
||||
|
||||
it("merges native skills exposed by PluginInput.skills.all()", async () => {
|
||||
//#given
|
||||
const tool = createSkillTool({
|
||||
@@ -639,6 +666,6 @@ describe("skill tool - nativeSkills integration", () => {
|
||||
|
||||
//#then
|
||||
expect(result).toContain("external-plugin-skill")
|
||||
expect(result).toContain("Test skill body content")
|
||||
expect(result).toContain("External plugin skill body")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -105,6 +105,11 @@ async function extractSkillBody(skill: LoadedSkill): Promise<string> {
|
||||
return templateMatch ? templateMatch[1].trim() : fullTemplate
|
||||
}
|
||||
|
||||
if (skill.scope === "config" && skill.definition.template) {
|
||||
const templateMatch = skill.definition.template.match(/<skill-instruction>([\s\S]*?)<\/skill-instruction>/)
|
||||
return templateMatch ? templateMatch[1].trim() : skill.definition.template
|
||||
}
|
||||
|
||||
if (skill.path) {
|
||||
return extractSkillTemplate(skill)
|
||||
}
|
||||
@@ -235,11 +240,13 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition
|
||||
return cachedDescription
|
||||
}
|
||||
|
||||
// Eagerly build description when callers pre-provide skills/commands.
|
||||
if (options.skills !== undefined) {
|
||||
const skillInfos = options.skills.map(loadedSkillToInfo)
|
||||
const commandsForDescription = options.commands ?? []
|
||||
cachedDescription = formatCombinedDescription(skillInfos, commandsForDescription)
|
||||
if (options.nativeSkills) {
|
||||
void buildDescription()
|
||||
}
|
||||
} else if (options.commands !== undefined) {
|
||||
cachedDescription = formatCombinedDescription([], options.commands)
|
||||
} else {
|
||||
@@ -248,6 +255,9 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition
|
||||
|
||||
return tool({
|
||||
get description() {
|
||||
if (cachedDescription === null) {
|
||||
void buildDescription()
|
||||
}
|
||||
return cachedDescription ?? TOOL_DESCRIPTION_PREFIX
|
||||
},
|
||||
args: {
|
||||
@@ -259,8 +269,8 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition
|
||||
},
|
||||
async execute(args: SkillArgs, ctx?: { agent?: string }) {
|
||||
const skills = await getSkills()
|
||||
cachedDescription = null
|
||||
const commands = getCommands()
|
||||
cachedDescription = formatCombinedDescription(skills.map(loadedSkillToInfo), commands)
|
||||
|
||||
const requestedName = args.name.replace(/^\//, "")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user