agent-device 0.14.6 → 0.14.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/io.js CHANGED
@@ -1 +1 @@
1
- import{promises as t}from"node:fs";import e from"node:os";import i from"node:path";import{AppError as a}from"./9152.js";function r(n={}){let l=n.cwd??process.cwd(),c=n.tempDir??e.tmpdir(),p=n.rootDir?o(n.rootDir,l):void 0;return{resolveInput:async t=>{if("uploadedArtifact"===t.kind)throw new a("UNSUPPORTED_OPERATION","Uploaded artifact inputs require a custom artifact adapter");return{path:o(t.path,l,p)}},reserveOutput:async(e,a)=>{let r,n=a.visibility??"client-visible",d=e?.kind==="path"?o(e.path,l,p):i.join(r=await t.mkdtemp(i.join(c,`agent-device-${a.field}-`)),`${a.field}${a.ext}`);return await t.mkdir(i.dirname(d),{recursive:!0}),{path:d,visibility:n,...r?{cleanup:async()=>{await t.rm(r,{recursive:!0,force:!0})}}:{},publish:async()=>e?.kind==="downloadableArtifact"?{kind:"localPath",field:a.field,path:d,fileName:e.fileName??i.basename(e.clientPath??d)}:void 0}},createTempFile:async e=>{let a=await t.mkdtemp(i.join(c,`${e.prefix}-`));return{path:i.join(a,`file${e.ext}`),visibility:"internal",cleanup:async()=>{await t.rm(a,{recursive:!0,force:!0})}}}}}function o(t,e,r){var o,n;let l,c=i.isAbsolute(t)?t:i.resolve(e,t);if(r&&(o=c,n=r,""!==(l=i.relative(n,o))&&(l.startsWith("..")||i.isAbsolute(l))))throw new a("INVALID_ARGS","Local path is outside the artifact adapter root",{path:c,rootDir:r});return c}export{r as createLocalArtifactAdapter};
1
+ export{createLocalArtifactAdapter}from"./7719.js";
@@ -1 +1 @@
1
- import e from"node:fs";import t from"node:path";import{AppError as n}from"./9152.js";import{resolveUserPath as r}from"./3267.js";let o=new Set(["1","true","yes","on"]),i=new Set(["0","false","no","off"]);function a(e){return`AGENT_DEVICE_${e.replace(/([A-Z])/g,"_$1").replace(/[^A-Za-z0-9_]/g,"_").toUpperCase()}`}function s(e,t,r,o){if(e.multiple)return(Array.isArray(t)?t:[t]).map(t=>s({...e,multiple:!1},t,r,o));if("boolean"===e.type){var i=t,a=r,u=o;if("boolean"==typeof i)return i;if("string"==typeof i){let e=l(i);if(void 0!==e)return e}throw new n("INVALID_ARGS",`Invalid value for "${u}" in ${a}. Expected boolean.`)}if("booleanOrString"===e.type){if("boolean"==typeof t)return t;if("string"==typeof t&&void 0!==l(t))return l(t);if("string"==typeof t&&t.trim().length>0)return t;throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected boolean or non-empty string.`)}if("string"===e.type){if("string"==typeof t&&t.trim().length>0)return t;throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected non-empty string.`)}if("enum"===e.type){if(void 0!==e.setValue){var y=e,f=t,m=r,p=o;let i=y.setValue;if(f===i)return i;if("string"==typeof f){let e=f.trim();if(""===e||"true"===e||"1"===e)return i;if("false"===e||"0"===e)return}if(!0===f)return i;if(!1!==f)throw new n("INVALID_ARGS",`Invalid value for "${p}" in ${m}. Expected boolean-like value for enum flag.`);return}if("string"!=typeof t||!e.enumValues?.includes(t))throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected one of: ${e.enumValues?.join(", ")}.`);return t}let c="number"==typeof t?t:"string"==typeof t?Number(t):NaN;if(!Number.isFinite(c)||!Number.isInteger(c))throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Expected integer.`);if("number"==typeof e.min&&c<e.min)throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Must be >= ${e.min}.`);if("number"==typeof e.max&&c>e.max)throw new n("INVALID_ARGS",`Invalid value for "${o}" in ${r}. Must be <= ${e.max}.`);return c}function l(e){let t=e.trim().toLowerCase();return!!o.has(t)||!i.has(t)&&void 0}let u=[{key:"stateDir",type:"string",path:!0},{key:"daemonBaseUrl",type:"string"},{key:"daemonAuthToken",type:"string"},{key:"daemonTransport",type:"enum",enumValues:["auto","socket","http"]},{key:"daemonServerMode",type:"enum",enumValues:["socket","http","dual"]},{key:"tenant",type:"string"},{key:"sessionIsolation",type:"enum",enumValues:["none","tenant"]},{key:"runId",type:"string"},{key:"leaseId",type:"string"},{key:"leaseBackend",type:"enum",enumValues:["ios-simulator","ios-instance","android-instance"]},{key:"platform",type:"enum",enumValues:["ios","macos","android","linux","apple"]},{key:"target",type:"enum",enumValues:["mobile","tv","desktop"]},{key:"device",type:"string"},{key:"udid",type:"string"},{key:"serial",type:"string"},{key:"iosSimulatorDeviceSet",type:"string",path:!0,legacyEnvNames:["IOS_SIMULATOR_DEVICE_SET"]},{key:"androidDeviceAllowlist",type:"string",legacyEnvNames:["ANDROID_DEVICE_ALLOWLIST"]},{key:"session",type:"string"},{key:"metroProjectRoot",type:"string",path:!0},{key:"metroKind",type:"enum",enumValues:["auto","react-native","expo"]},{key:"metroPublicBaseUrl",type:"string"},{key:"metroProxyBaseUrl",type:"string"},{key:"metroBearerToken",type:"string",legacyEnvNames:["AGENT_DEVICE_PROXY_TOKEN"]},{key:"metroPreparePort",type:"int",min:1,max:65535},{key:"metroListenHost",type:"string"},{key:"metroStatusHost",type:"string"},{key:"metroStartupTimeoutMs",type:"int",min:1},{key:"metroProbeTimeoutMs",type:"int",min:1},{key:"metroRuntimeFile",type:"string",path:!0},{key:"metroNoReuseExisting",type:"boolean"},{key:"metroNoInstallDeps",type:"boolean"}],y=new Map(u.map(e=>[e.key,e]));function f(e){let t=e.env??process.env;return r(e.configPath,{cwd:e.cwd,env:t})}function m(o){let i=function(o){let i,a,l=o.env??process.env,u=f(o);if(!e.existsSync(u))throw new n("INVALID_ARGS",`Remote config file not found: ${u}`);try{i=e.readFileSync(u,"utf8")}catch(e){throw new n("INVALID_ARGS",`Failed to read remote config file: ${u}`,{cause:e instanceof Error?e.message:String(e)})}try{a=JSON.parse(i)}catch(e){throw new n("INVALID_ARGS",`Invalid JSON in remote config file: ${u}`,{cause:e instanceof Error?e.message:String(e)})}if(!a||"object"!=typeof a||Array.isArray(a))throw new n("INVALID_ARGS",`Remote config file must contain a JSON object: ${u}`);let m={},p=a,c=t.dirname(u);for(let[e,t]of Object.entries(p)){let o=y.get(e);if(!o)throw new n("INVALID_ARGS",`Unsupported remote config key "${e}" in remote config file ${u}.`);let i=s(o,t,`remote config file ${u}`,e);m[o.key]="string"==typeof i&&"path"in o&&o.path?r(i,{cwd:c,env:l}):i}return{resolvedPath:u,profile:m}}(o);return{resolvedPath:i.resolvedPath,profile:function(...e){let t={};for(let n of e)if(n)for(let e of u){let r=n[e.key];void 0!==r&&(t[e.key]=r)}return t}(function(e=process.env){let t={};for(let n of u){let r=(function(e){let t=y.get(e);return[a(e),...t?.legacyEnvNames??[]]})(n.key).map(t=>({name:t,value:e[t]})).find(e=>"string"==typeof e.value&&e.value.trim().length>0);r&&(t[n.key]=s(n,r.value,`environment variable ${r.name}`,r.name))}return t}(o.env),i.profile)}}export{u as REMOTE_CONFIG_FIELD_SPECS,a as buildPrimaryEnvVarName,s as parseSourceValue,f as resolveRemoteConfigPath,m as resolveRemoteConfigProfile};
1
+ export{resolveRemoteConfigPath,resolveRemoteConfigProfile}from"./208.js";
@@ -0,0 +1,20 @@
1
+ import{buildCommandUsageText as e,buildUsageText as t}from"./command-schema.js";import{readVersion as r}from"./9671.js";let n="agent-device",o=["workflow","debugging","react-devtools","remote","macos","dogfood"];function i(e={}){let t=!1===e.global?"npx -y agent-device mcp":"agent-device mcp",r=!1===e.global?"No global install required.":"npm install -g agent-device",n=e.client?`
2
+ Client hint: ${e.client}`:"";return`${r}
3
+
4
+ MCP server command:
5
+ ${t}
6
+
7
+ Generic MCP JSON:
8
+ {
9
+ "mcpServers": {
10
+ "agent-device": {
11
+ "command": "${!1===e.global?"npx":"agent-device"}",
12
+ "args": ${JSON.stringify(!1===e.global?["-y","agent-device","mcp"]:["mcp"])}
13
+ }
14
+ }
15
+ }
16
+
17
+ Use this server for discovery and routing only. For device actions, call the CLI commands returned by the help tool, starting with:
18
+ agent-device help workflow${n}
19
+ `}function a(r={}){if(r.topic&&r.command)throw Error("Provide either topic or command, not both.");let n=r.topic??r.command;if(!n)return t();if(r.topic&&!d(r.topic))throw Error(`Unknown help topic: ${r.topic}. Expected one of: ${o.join(", ")}`);let i=e(n);if(!i)throw Error(`Unknown command or help topic: ${n}`);return i}function s(){return[{uri:"agent-device://install",name:"agent-device MCP install",description:"Install and client configuration snippets.",mimeType:"text/markdown"},{uri:"agent-device://help",name:"agent-device command list",description:"Version-matched command list and global flags.",mimeType:"text/plain"},...o.map(e=>({uri:`agent-device://help/${e}`,name:`agent-device help ${e}`,description:`Version-matched ${e} workflow guidance.`,mimeType:"text/plain"}))]}function c(){return[l("agent-device-workflow","Plan a normal app automation loop."),l("agent-device-debugging","Collect focused debugging evidence."),l("agent-device-dogfood","Run exploratory QA with reproducible evidence."),l("agent-device-react-native-performance","Inspect React Native renders."),l("agent-device-macos","Inspect a macOS app or surface.")]}function l(e,t){return{name:e,description:t,arguments:[{name:"target",description:"Optional app, device, or task target.",required:!1}]}}function d(e){return o.includes(e)}function p(e){if("2.0"!==e.jsonrpc||"string"!=typeof e.method)return g(e.id??null,-32600,"Invalid JSON-RPC request.");if(void 0===e.id)return null;try{var l,p;return l=e.id,p=function(e,l){switch(e){case"initialize":return{protocolVersion:"2025-11-25",capabilities:{tools:{},resources:{},prompts:{}},serverInfo:{name:n,version:r()}};case"ping":return{};case"tools/list":return{tools:[{name:"status",description:"Report the installed agent-device MCP router and CLI metadata.",inputSchema:{type:"object",properties:{},additionalProperties:!1}},{name:"install",description:"Return install and MCP client configuration snippets for agent-device.",inputSchema:{type:"object",properties:{client:{type:"string",description:"Optional client name for labeling the returned guidance."},global:{type:"boolean",description:"Use a global agent-device binary when true; use npx when false."}},additionalProperties:!1}},{name:"help",description:"Return version-matched CLI help for a workflow topic or command.",inputSchema:{type:"object",properties:{topic:{type:"string",enum:o,description:"Agent workflow topic."},command:{type:"string",description:"CLI command name such as snapshot, open, logs, or react-devtools."}},additionalProperties:!1}}]};case"tools/call":var p,g,w,y=l;let b=m(y),$=h(b,"name"),k=f(b.arguments);try{if("status"===$)return u(JSON.stringify({name:n,registryName:"io.github.callstackincubator/agent-device",version:r(),transport:"stdio",command:"agent-device mcp",node:process.version,capabilities:{tools:["status","install","help"],resources:s().map(e=>e.uri),prompts:c().map(e=>e.name)},note:"This MCP server routes agents to the agent-device CLI. It does not expose device automation or shell execution tools."},null,2));if("install"===$)return u(i(k));if("help"===$)return u(a(k));throw Error(`Unknown tool: ${$}`)}catch(e){return u(e instanceof Error?e.message:String(e),!0)}return;case"resources/list":return{resources:s()};case"resources/read":let x;return p=l,{contents:[{uri:x=h(m(p),"uri"),mimeType:"agent-device://install"===x?"text/markdown":"text/plain",text:function(e){if("agent-device://install"===e)return i();if("agent-device://help"===e)return t();let r=e.startsWith("agent-device://help/")?e.slice(20):"";if(d(r))return a({topic:r});throw Error(`Unknown resource: ${e}`)}(x)}]};case"prompts/list":return{prompts:c()};case"prompts/get":let C;return g=l,C=m(g),function(e,t={}){let r={"agent-device-workflow":"workflow","agent-device-debugging":"debugging","agent-device-dogfood":"dogfood","agent-device-react-native-performance":"react-devtools","agent-device-macos":"macos"}[e];if(!r)throw Error(`Unknown prompt: ${e}`);let n=t.target?` Target: ${t.target}.`:"";return{description:`Use agent-device help ${r} before planning commands.${n}`,messages:[{role:"user",content:{type:"text",text:`Read the agent-device ${r} guidance through the MCP help tool, then produce a concise command plan using agent-device CLI commands only.${n}`}}]}}(h(C,"name"),(w=C.arguments,Object.fromEntries(Object.entries(f(w)).filter(e=>"string"==typeof e[1]))));default:throw new v(`Unsupported MCP method: ${e}`)}}(e.method,e.params),{jsonrpc:"2.0",id:l,result:p}}catch(t){if(t instanceof v)return g(e.id,-32601,t.message);return g(e.id,-32602,t instanceof Error?t.message:String(t))}}function u(e,t=!1){return{isError:t,content:[{type:"text",text:e}]}}function g(e,t,r){return{jsonrpc:"2.0",id:e,error:{code:t,message:r}}}function m(e){if(!e||"object"!=typeof e||Array.isArray(e))throw Error("Expected object parameters.");return e}function f(e){return void 0===e?{}:m(e)}function h(e,t){let r=e[t];if("string"!=typeof r||0===r.length)throw Error(`Expected ${t} to be a non-empty string.`);return r}class v extends Error{}async function w(){let e=new y(e=>{let t=function(e){if(Array.isArray(e)){let t=e.flatMap(e=>{var t;return(t=p(e))?[t]:[]});return t.length>0?t:null}return p(e)}(e);t&&b(t)});process.stdin.setEncoding("utf8"),process.stdin.on("data",t=>{try{e.push(t)}catch(e){b({jsonrpc:"2.0",id:null,error:{code:-32700,message:e instanceof Error?e.message:String(e)}})}}),await new Promise(e=>{process.stdin.on("end",e),process.stdin.on("close",e),process.stdin.resume()})}class y{buffer="";sink;constructor(e){this.sink=e}push(e){for(this.buffer+=e;;){let e=this.tryReadLineMessage();if(void 0!==e){this.emit(e);continue}break}}tryReadLineMessage(){let e=this.buffer.indexOf("\n");if(-1===e)return;let t=this.buffer.slice(0,e).trim();return this.buffer=this.buffer.slice(e+1),t.length>0?t:void 0}emit(e){let t=JSON.parse(e);Array.isArray(t),this.sink(t)}}function b(e){process.stdout.write(`${JSON.stringify(e)}
20
+ `)}export{w as runAgentDeviceMcpServer};
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "agent-device",
3
- "version": "0.14.6",
4
- "description": "Agent-driven CLI for mobile UI automation, network inspection, and performance diagnostics across iOS, Android, tvOS, and macOS.",
3
+ "version": "0.14.8",
4
+ "description": "Agent-native CLI for AI mobile testing and app automation across iOS, Android, tvOS, Android TV, macOS, and Linux.",
5
+ "mcpName": "io.github.callstackincubator/agent-device",
5
6
  "license": "MIT",
6
7
  "author": "Callstack",
7
8
  "homepage": "https://agent-device.dev/",
@@ -92,10 +93,12 @@
92
93
  "fallow:baseline": "(fallow dead-code --save-baseline fallow-baselines/dead-code.json --summary || true) && (fallow dupes --save-baseline fallow-baselines/dupes.json --summary || true) && (fallow health --save-baseline fallow-baselines/health.json --summary || true)",
93
94
  "check:fallow": "fallow audit",
94
95
  "check:quick": "pnpm lint && pnpm typecheck",
95
- "check:tooling": "pnpm lint && pnpm typecheck && pnpm build",
96
+ "sync:mcp-metadata": "node scripts/sync-mcp-metadata.mjs",
97
+ "check:mcp-metadata": "node scripts/sync-mcp-metadata.mjs --check",
98
+ "check:tooling": "pnpm lint && pnpm typecheck && pnpm check:mcp-metadata && pnpm build",
96
99
  "check:unit": "pnpm test:unit && pnpm test:smoke",
97
100
  "check": "pnpm check:tooling && pnpm check:fallow && pnpm check:unit",
98
- "prepack": "pnpm build:all && pnpm package:android-snapshot-helper:npm",
101
+ "prepack": "pnpm check:mcp-metadata && pnpm build:all && pnpm package:android-snapshot-helper:npm",
99
102
  "typecheck": "tsc -p tsconfig.json",
100
103
  "test-app:install": "pnpm install --dir examples/test-app --ignore-workspace",
101
104
  "test-app:start": "pnpm --dir examples/test-app start",
@@ -127,6 +130,8 @@
127
130
  "!android-snapshot-helper/dist/*.idsig",
128
131
  "src/platforms/linux/atspi-dump.py",
129
132
  "skills",
133
+ "server.json",
134
+ "smithery.yaml",
130
135
  "README.md",
131
136
  "LICENSE"
132
137
  ],
@@ -152,7 +157,29 @@
152
157
  "diagnostics",
153
158
  "network",
154
159
  "profiling",
155
- "performance"
160
+ "performance",
161
+ "mcp",
162
+ "model-context-protocol",
163
+ "mcp-server",
164
+ "ai-agent",
165
+ "mobile-automation",
166
+ "ios-simulator",
167
+ "android-emulator",
168
+ "xcuitest",
169
+ "e2e-testing",
170
+ "cursor",
171
+ "claude-code",
172
+ "expo",
173
+ "mobile-testing",
174
+ "qa-automation",
175
+ "ai-testing",
176
+ "ios-automation",
177
+ "android-automation",
178
+ "simulator",
179
+ "emulator",
180
+ "appium",
181
+ "maestro",
182
+ "detox"
156
183
  ],
157
184
  "dependencies": {
158
185
  "fast-xml-parser": "^5.7.2",
@@ -166,7 +193,7 @@
166
193
  "fallow": "^2.52.0",
167
194
  "oxfmt": "^0.42.0",
168
195
  "oxlint": "^1.57.0",
169
- "skillgym": "^0.6.0",
196
+ "skillgym": "^0.8.0",
170
197
  "typescript": "^6.0.2",
171
198
  "vite": "^8.0.10"
172
199
  }
package/server.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.callstackincubator/agent-device",
4
+ "title": "agent-device",
5
+ "description": "Official MCP discovery router for the agent-device CLI. It exposes status, install guidance, version-matched CLI help, prompts, and resources without exposing device automation over MCP.",
6
+ "repository": {
7
+ "url": "https://github.com/callstackincubator/agent-device",
8
+ "source": "github"
9
+ },
10
+ "version": "0.14.8",
11
+ "packages": [
12
+ {
13
+ "registryType": "npm",
14
+ "identifier": "agent-device",
15
+ "version": "0.14.8",
16
+ "transport": {
17
+ "type": "stdio"
18
+ }
19
+ }
20
+ ]
21
+ }
@@ -34,6 +34,15 @@ agent-device react-devtools profile slow --limit 5
34
34
  agent-device react-devtools profile rerenders --limit 5
35
35
  ```
36
36
 
37
+ Remote iOS bridge order:
38
+
39
+ ```bash
40
+ agent-device open <bundle-id> --platform ios --relaunch
41
+ agent-device react-devtools start
42
+ agent-device open <bundle-id> --platform ios --relaunch
43
+ agent-device react-devtools wait --connected
44
+ ```
45
+
37
46
  Rules:
38
47
 
39
- Keep reads bounded with `--depth`/`find`, treat `@c` refs as reload-local, profile only the investigated interaction, and run the same command in remote Android sessions; the CLI manages the needed local service tunnel.
48
+ Keep reads bounded with `--depth`/`find`, treat `@c` refs as reload-local, profile only the investigated interaction, and run the same command in remote Android sessions; the CLI manages the needed local service tunnel. For remote iOS, relaunch after `react-devtools start` because React Native opens the legacy DevTools websocket during JavaScript startup.
package/smithery.yaml ADDED
@@ -0,0 +1 @@
1
+ runtime: "typescript"
@@ -1 +0,0 @@
1
- e9a4afcfa6fee4515b0dadacb7a92530d68ec4bb999aa0808651df5d41be78e0 agent-device-android-snapshot-helper-0.14.6.apk