Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/autohand-code-skills.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

Include Autohand Code CLI in Cloudflare skills installation and updates

Update the Rosie agent registry so Wrangler detects Autohand Code CLI and installs Cloudflare skills into `~/.autohand/skills`. Existing Wrangler-managed installations can use the same skills update flow as other supported agents.
Comment thread
igorcosta marked this conversation as resolved.
2 changes: 1 addition & 1 deletion packages/wrangler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
"qr": "^0.6.0",
"recast": "0.23.11",
"resolve": "^1.22.8",
"rosie-skills": "^0.8.1",
"rosie-skills": "^0.8.5",
"semiver": "^1.1.0",
"shell-quote": "^1.9.0",
"signal-exit": "catalog:default",
Expand Down
84 changes: 84 additions & 0 deletions packages/wrangler/src/__tests__/agents-skills-install.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,90 @@ const DEFAULT_INSTALL_RESULT = {
installedInstruction: null,
};

describe("Autohand Code skills installation", () => {
runInTempDir();
const std = mockConsoleMethods();
const { setIsTTY } = useMockIsTTY();

afterEach(() => {
clearDialogs();
});

test("detects Autohand with the real Rosie registry and installs and updates its skills", async ({
expect,
}) => {
const rosie =
await vi.importActual<typeof import("rosie-skills")>("rosie-skills");
createAgentDir(".autohand");
const skillsPath = path.join(os.homedir(), ".autohand", "skills");
mockRosieAgents.mockImplementation(rosie.agents);
mockRosieInstall.mockResolvedValue({
...DEFAULT_INSTALL_RESULT,
skills: [
{
...DEFAULT_INSTALL_RESULT.skills[0],
installedAgents: ["autohand-code"],
},
],
installedAgents: ["autohand-code"],
});
mockGitHubSkillsApi(["cloudflare"], "old-sha");
setIsTTY(true);

const runSkillsInstallFlow = await freshImport();
await runSkillsInstallFlow({ force: true });

expect(mockRosieInstall).toHaveBeenCalledWith(
"cloudflare/skills",
expect.objectContaining({ agent: ["autohand-code"], global: true })
);
expect(std.out).toContain(
"Successfully installed Cloudflare skills for: Autohand Code CLI"
);
expect(readMetadataFile()).toMatchObject({
accepted: true,
installFailed: false,
detectedAgents: [
{
name: "Autohand Code CLI",
rosie: { id: "autohand-code", globalPath: skillsPath },
},
],
});

mkdirSync(path.join(skillsPath, "cloudflare"), { recursive: true });
// An update is only offered after the installation cooldown and cache expire.
writeMetadataFile({
...readMetadataFile(),
date: "2025-01-01T00:00:00Z",
});
writeFileSync(
path.join(getGlobalConfigPath(), "cloudflare-skills-repo-cache.json"),
JSON.stringify({ lastUpdate: 0, skillNames: ["cloudflare"] })
);
mockGitHubSkillsApi(["cloudflare"], "new-sha");
mockConfirm({
text: "It looks like your Cloudflare skills might be out of date. Would you like Wrangler to update them for you?",
result: true,
});
const runSkillsUpdateFlow = await freshUpdateImport();
await runSkillsUpdateFlow({ command: "deploy" });

expect(mockRosieInstall).toHaveBeenCalledTimes(2);
expect(mockRosieInstall).toHaveBeenLastCalledWith(
"cloudflare/skills",
expect.objectContaining({ agent: ["autohand-code"], global: true })
);
expect(std.out).toContain(
"Successfully updated Cloudflare skills for: Autohand Code CLI"
);
expect(readMetadataFile()).toMatchObject({
installedTreeSha: "new-sha",
installFailed: false,
});
});
});

/** Writes the skills-install metadata file to the global wrangler config path. */
function writeMetadataFile(content: Record<string, unknown>): void {
const configDir = getGlobalConfigPath();
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading