diff --git a/config/aipods/artificer.yaml b/config/aipods/artificer.yaml index be5d554..6e40977 100644 --- a/config/aipods/artificer.yaml +++ b/config/aipods/artificer.yaml @@ -140,11 +140,17 @@ spec: ref: master subpath: git-spec targetPath: .agents/skills/git-spec + - name: post-task-skill + repoUrl: git@github.com:pikasTech/agent_skills.git + ref: master + subpath: post-task + targetPath: .agents/skills/post-task requiredSkills: - name: dad-dev - name: cli-spec - name: docs-spec - name: git-spec + - name: post-task - name: unidesk-trans - name: unidesk-gh - name: unidesk-agentrun diff --git a/src/selftest/cases/79-primary-workspace.ts b/src/selftest/cases/79-primary-workspace.ts index 2079a54..838c7c8 100644 --- a/src/selftest/cases/79-primary-workspace.ts +++ b/src/selftest/cases/79-primary-workspace.ts @@ -28,6 +28,7 @@ const selfTest: SelfTestCase = async (context) => { "capability/probe": "#!/usr/bin/env sh\necho capability\n", "dad-dev/SKILL.md": "---\ndescription: Managed dad-dev capability\n---\n", "git-spec/SKILL.md": "---\ndescription: Managed git-spec capability\n---\n", + "post-task/SKILL.md": "---\ndescription: Managed post-task capability\n---\n", "unidesk-gh/SKILL.md": "---\ndescription: Managed unidesk-gh capability\n---\n", }); const workspaceRef: WorkspaceRef = { kind: "opaque", path: "." }; @@ -41,9 +42,10 @@ const selfTest: SelfTestCase = async (context) => { { name: "addon-tools", repoUrl: addon.path, commitId: addon.commitId, subpath: "capability", targetPath: "tools" }, { name: "dad-dev-skill", repoUrl: addon.path, commitId: addon.commitId, subpath: "dad-dev", targetPath: ".agents/skills/dad-dev" }, { name: "git-spec-skill", repoUrl: addon.path, commitId: addon.commitId, subpath: "git-spec", targetPath: ".agents/skills/git-spec" }, + { name: "post-task-skill", repoUrl: addon.path, commitId: addon.commitId, subpath: "post-task", targetPath: ".agents/skills/post-task" }, { name: "unidesk-gh-skill", repoUrl: addon.path, commitId: addon.commitId, subpath: "unidesk-gh", targetPath: ".agents/skills/unidesk-gh" }, ], - requiredSkills: [{ name: "source-skill" }, { name: "dad-dev" }, { name: "git-spec" }, { name: "unidesk-gh" }], + requiredSkills: [{ name: "source-skill" }, { name: "dad-dev" }, { name: "git-spec" }, { name: "post-task" }, { name: "unidesk-gh" }], }; const workspacePath = path.join(context.tmp, "primary-workspace-materialized"); const env = { AGENTRUN_WORKSPACE_ROOT: path.join(context.tmp, "primary-workspace-assembly"), AGENTRUN_WORKSPACE_PATH: workspacePath, AGENTRUN_RUN_ID: "run_primary_workspace_selftest" }; @@ -66,11 +68,13 @@ const selfTest: SelfTestCase = async (context) => { await access(path.join(first.skillsDir, "source-skill", "SKILL.md")); await access(path.join(first.skillsDir, "dad-dev", "SKILL.md")); await access(path.join(first.skillsDir, "git-spec", "SKILL.md")); + await access(path.join(first.skillsDir, "post-task", "SKILL.md")); await access(path.join(first.skillsDir, "unidesk-gh", "SKILL.md")); assert.equal(await readFile(path.join(first.binPath, "probe"), "utf8"), "#!/usr/bin/env sh\necho capability\n"); assert.match(await readFile(path.join(first.skillsDir, "dad-dev", "SKILL.md"), "utf8"), /Managed dad-dev capability/u); assert.match(first.initialPrompt?.text ?? "", /manifest=.*\.git\/agentrun-managed-overlay\/\.agents\/skills\/dad-dev\/SKILL\.md skillsDirEnv=AGENTRUN_SKILLS_DIRS/u); assert.match(first.initialPrompt?.text ?? "", /manifest=.*\.git\/agentrun-managed-overlay\/\.agents\/skills\/git-spec\/SKILL\.md skillsDirEnv=AGENTRUN_SKILLS_DIRS/u); + assert.match(first.initialPrompt?.text ?? "", /manifest=.*\.git\/agentrun-managed-overlay\/\.agents\/skills\/post-task\/SKILL\.md skillsDirEnv=AGENTRUN_SKILLS_DIRS/u); assert.match(first.initialPrompt?.text ?? "", /manifest=.*\.git\/agentrun-managed-overlay\/\.agents\/skills\/unidesk-gh\/SKILL\.md skillsDirEnv=AGENTRUN_SKILLS_DIRS/u); assert.equal((await execFile("git", ["status", "--porcelain=v1", "--untracked-files=all"], { cwd: workspacePath })).stdout, ""); assert.equal((await execFile("git", ["rev-parse", "HEAD"], { cwd: workspacePath })).stdout.trim(), primary.commitId); @@ -88,9 +92,9 @@ const selfTest: SelfTestCase = async (context) => { assert.equal(managedOverlay.rootRelativeToWorkspace, ".git/agentrun-managed-overlay"); assert.equal(managedOverlay.sourceViewIsolated, true); const bundleItems = ((first.event.bundles as JsonRecord).items as JsonRecord[]); - assert.deepEqual(bundleItems.map((item) => item.logicalTargetPath), [".agents/skills", "tools", ".agents/skills/dad-dev", ".agents/skills/git-spec", ".agents/skills/unidesk-gh"]); + assert.deepEqual(bundleItems.map((item) => item.logicalTargetPath), [".agents/skills", "tools", ".agents/skills/dad-dev", ".agents/skills/git-spec", ".agents/skills/post-task", ".agents/skills/unidesk-gh"]); assert.equal(bundleItems.every((item) => item.storageKind === "git-metadata-overlay"), true); - assert.deepEqual(((first.event.requiredSkills as JsonRecord).names), ["source-skill", "dad-dev", "git-spec", "unidesk-gh"]); + assert.deepEqual(((first.event.requiredSkills as JsonRecord).names), ["source-skill", "dad-dev", "git-spec", "post-task", "unidesk-gh"]); const provenancePath = path.join(workspacePath, ".git", "agentrun-primary-workspace.json"); const persistedProvenance = JSON.parse(await readFile(provenancePath, "utf8")) as JsonRecord; assert.equal(persistedProvenance.resolutionAuthority, "declared-commit"); @@ -264,6 +268,7 @@ const selfTest: SelfTestCase = async (context) => { "managed-capability-overlay-keeps-primary-source-view-clean", "managed-capability-overlay-preserves-nested-targets", "managed-capability-overlay-publishes-tools-and-skills", + "managed-post-task-skill-materializes-and-indexes", "real-primary-source-modifications-remain-git-visible", "primary-workspace-continuation-preserves-dirty-tree", "primary-workspace-continuation-freezes-mutable-ref", diff --git a/src/selftest/cases/81-artificer-nonrecursive-prompt.ts b/src/selftest/cases/81-artificer-nonrecursive-prompt.ts index 8e35e28..9ec1db7 100644 --- a/src/selftest/cases/81-artificer-nonrecursive-prompt.ts +++ b/src/selftest/cases/81-artificer-nonrecursive-prompt.ts @@ -41,6 +41,12 @@ const selfTest: SelfTestCase = async (context) => { assert.match(effectivePrompt, /runner 容器本地执行冒充 Target 原入口验证/u); assert.match(effectivePrompt, /不得把 NC01、目标绝对路径或第二条执行路径硬编码/u); assert.ok(requiredSkills.some((item) => item.name === "unidesk-trans"), "Artificer must require the unidesk-trans skill"); + assert.ok(requiredSkills.some((item) => item.name === "post-task"), "Artificer must require the post-task skill"); + assert.ok(bundles.some((item) => item.name === "post-task-skill" + && item.repoUrl === "git@github.com:pikasTech/agent_skills.git" + && item.ref === "master" + && item.subpath === "post-task" + && item.targetPath === ".agents/skills/post-task"), "Artificer must source post-task from the agent_skills bundle authority"); assert.ok(bundles.some((item) => item.name === "agentrun-runner-tools" && item.targetPath === "tools"), "Artificer must materialize the bundled trans executable"); const unideskSsh = toolCredentials.find((item) => item.tool === "unidesk-ssh" && item.purpose === "ssh-passthrough"); assert.ok(unideskSsh, "Artificer must bind the unidesk-ssh route credential"); @@ -49,7 +55,7 @@ const selfTest: SelfTestCase = async (context) => { assert.equal(effectivePrompt.endsWith(userPrompt), true, "rendered prompt must preserve the complete user business prompt"); assert.equal(effectivePrompt.split(userPrompt).length - 1, 1, "rendered prompt must include the user business prompt exactly once"); - return { name: "artificer-nonrecursive-prompt", tests: ["artificer-yaml-nonrecursive-prompt-render", "artificer-target-trans-prompt-render", "artificer-trans-skill-tool-and-secretref-bound", "artificer-user-prompt-preserved"] }; + return { name: "artificer-nonrecursive-prompt", tests: ["artificer-yaml-nonrecursive-prompt-render", "artificer-target-trans-prompt-render", "artificer-trans-skill-tool-and-secretref-bound", "artificer-post-task-agent-skills-authority", "artificer-user-prompt-preserved"] }; }; export default selfTest;