Skip to content

Commit 8cda924

Browse files
k4cper-gclaude
andcommitted
Fix CI: update tests for renamed API methods and add press to Action type
- Align test method names with current API (execute→action, pressKeys→press, launchApp→openApp, press_keys→press) - Add missing "press" to Action type union - Add MCP server instructions for agent guidance Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5da6e7b commit 8cda924

3 files changed

Lines changed: 42 additions & 14 deletions

File tree

src/mcp/server.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,37 @@ import { z } from "zod";
1212
import { Session } from "../index.js";
1313
import { formatLine } from "../format.js";
1414

15-
export const server = new McpServer({
16-
name: "cup",
17-
version: "0.1.0",
18-
});
15+
export const server = new McpServer(
16+
{ name: "cup", version: "0.1.0" },
17+
{
18+
instructions:
19+
"CUP (Computer Use Protocol) gives you access to the UI accessibility " +
20+
"tree of the user's computer.\n\n" +
21+
"WORKFLOW — follow this pattern:\n" +
22+
"1. snapshot to capture the active window's UI\n" +
23+
"2. find to locate specific elements (PREFERRED over re-capturing)\n" +
24+
"3. action to interact (click, type, press, etc.)\n" +
25+
"4. Re-capture ONLY after actions change the UI\n\n" +
26+
"TOOLS:\n" +
27+
"- snapshot() — active window tree + window list (most common)\n" +
28+
"- snapshot_app(app) — specific app by title (when not in foreground)\n" +
29+
"- overview() — just the window list, near-instant\n" +
30+
"- snapshot_desktop() — desktop icons and widgets\n" +
31+
"- find(role/name/state) — search last tree without re-capturing\n" +
32+
"- action(action, ...) — interact with elements or press keys\n" +
33+
"- open_app(name) — open an app by name with fuzzy matching\n" +
34+
"- screenshot(region) — visual context when tree isn't enough\n\n" +
35+
"IMPORTANT — minimize token usage:\n" +
36+
"- Use find(name=...) to locate elements — NOT repeated tree captures\n" +
37+
"- Use overview() to discover what apps are open\n" +
38+
"- Use snapshot_app(app='...') to target a specific app\n" +
39+
"- snapshot() is your default starting point\n\n" +
40+
"Element IDs (e.g., 'e14') are ephemeral — only valid for the most " +
41+
"recent tree snapshot. After any action, re-capture before using IDs.\n\n" +
42+
"Use action(action='press', keys='ctrl+s') for keyboard shortcuts.\n\n" +
43+
"Use screenshot when you need visual context (colors, images, layout).",
44+
},
45+
);
1946

2047
// ---------------------------------------------------------------------------
2148
// Session state

src/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export interface AppInfo {
4545
}
4646

4747
// ---------------------------------------------------------------------------
48-
// Roles (54 canonical ARIA-derived roles)
48+
// Roles (59 canonical ARIA-derived roles)
4949
// ---------------------------------------------------------------------------
5050

5151
export type Role =
@@ -133,7 +133,7 @@ export type State =
133133
| "selected";
134134

135135
// ---------------------------------------------------------------------------
136-
// Actions (15 element-level canonical actions)
136+
// Actions (15 element-level canonical actions + press for global keys)
137137
// ---------------------------------------------------------------------------
138138

139139
export type Action =
@@ -146,6 +146,7 @@ export type Action =
146146
| "focus"
147147
| "increment"
148148
| "longpress"
149+
| "press"
149150
| "rightclick"
150151
| "scroll"
151152
| "select"

tests/actions.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ describe("VALID_ACTIONS", () => {
7878
it("contains all canonical actions", () => {
7979
const expected = [
8080
"click", "collapse", "decrement", "dismiss", "doubleclick",
81-
"expand", "focus", "increment", "longpress", "press_keys",
81+
"expand", "focus", "increment", "longpress", "press",
8282
"rightclick", "scroll", "select", "setvalue", "toggle", "type",
8383
];
8484
for (const action of expected) {
@@ -95,35 +95,35 @@ describe("MacosActionHandler", () => {
9595
it("returns error for unknown action", async () => {
9696
const { MacosActionHandler } = await import("../src/actions/macos.js");
9797
const handler = new MacosActionHandler();
98-
const result = await handler.execute(null, "fly", {});
98+
const result = await handler.action(null, "fly", {});
9999
expect(result.success).toBe(false);
100100
expect(result.error?.toLowerCase()).toContain("not implemented");
101101
});
102102

103-
it("pressKeys works on macOS", async () => {
103+
it("press works on macOS", async () => {
104104
if (process.platform !== "darwin") return; // skip on non-macOS
105105

106106
const { MacosActionHandler } = await import("../src/actions/macos.js");
107107
const handler = new MacosActionHandler();
108-
const result = await handler.pressKeys("escape");
108+
const result = await handler.press("escape");
109109
expect(result.success).toBe(true);
110110
expect(result.message).toContain("Pressed");
111111
}, 60000); // First run compiles the Swift helper (~30s)
112112

113-
it("launchApp rejects empty name", async () => {
113+
it("openApp rejects empty name", async () => {
114114
const { MacosActionHandler } = await import("../src/actions/macos.js");
115115
const handler = new MacosActionHandler();
116-
const result = await handler.launchApp("");
116+
const result = await handler.openApp("");
117117
expect(result.success).toBe(false);
118118
expect(result.error?.toLowerCase()).toContain("empty");
119119
});
120120

121-
it("launchApp rejects nonexistent app", async () => {
121+
it("openApp rejects nonexistent app", async () => {
122122
if (process.platform !== "darwin") return; // skip on non-macOS
123123

124124
const { MacosActionHandler } = await import("../src/actions/macos.js");
125125
const handler = new MacosActionHandler();
126-
const result = await handler.launchApp("zzzznonexistentapp99999");
126+
const result = await handler.openApp("zzzznonexistentapp99999");
127127
expect(result.success).toBe(false);
128128
expect(result.error?.toLowerCase()).toContain("no installed app");
129129
});

0 commit comments

Comments
 (0)