@appclaw/agent 2.0.0
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/README.md +19 -0
- package/bin/appclaw-agent.js +4 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +55 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +95 -0
- package/dist/client.js.map +1 -0
- package/dist/daemon-entry.d.ts +1 -0
- package/dist/daemon-entry.js +4 -0
- package/dist/daemon-entry.js.map +1 -0
- package/dist/daemon.d.ts +11 -0
- package/dist/daemon.js +85 -0
- package/dist/daemon.js.map +1 -0
- package/dist/help.d.ts +3 -0
- package/dist/help.js +62 -0
- package/dist/help.js.map +1 -0
- package/dist/parser.d.ts +3 -0
- package/dist/parser.js +202 -0
- package/dist/parser.js.map +1 -0
- package/dist/paths.d.ts +9 -0
- package/dist/paths.js +7 -0
- package/dist/paths.js.map +1 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +168 -0
- package/dist/server.js.map +1 -0
- package/dist/snapshot.d.ts +7 -0
- package/dist/snapshot.js +26 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/types.d.ts +87 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# appclaw-agent
|
|
2
|
+
|
|
3
|
+
Agent-native command line interface for AppClaw. It exposes deterministic
|
|
4
|
+
terminal commands so Claude Code, Gemini CLI, Codex CLI, and other agents can
|
|
5
|
+
inspect and operate an Appium-backed mobile session.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g appclaw-agent
|
|
9
|
+
appclaw-agent help workflow
|
|
10
|
+
|
|
11
|
+
appclaw-agent --session demo open com.example.app --platform android
|
|
12
|
+
appclaw-agent --session demo snapshot -i --json
|
|
13
|
+
appclaw-agent --session demo press @e1 --json
|
|
14
|
+
appclaw-agent --session demo close
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The first device command starts a user-local daemon. The daemon owns named
|
|
18
|
+
device sessions so separate agent terminal invocations can continue operating
|
|
19
|
+
on the same screen.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function run(argv: string[]): Promise<number>;
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { sendCommand } from './client.js';
|
|
2
|
+
import { helpText, VERSION, workflowText } from './help.js';
|
|
3
|
+
import { parseInvocation } from './parser.js';
|
|
4
|
+
const c = {
|
|
5
|
+
reset: '\x1b[0m',
|
|
6
|
+
bold: '\x1b[1m',
|
|
7
|
+
dim: '\x1b[2m',
|
|
8
|
+
green: '\x1b[32m',
|
|
9
|
+
red: '\x1b[31m',
|
|
10
|
+
cyan: '\x1b[36m',
|
|
11
|
+
yellow: '\x1b[33m',
|
|
12
|
+
magenta: '\x1b[35m',
|
|
13
|
+
};
|
|
14
|
+
function colorOutput(session, ok, message, output) {
|
|
15
|
+
const icon = ok ? `${c.green}✔${c.reset}` : `${c.red}✘${c.reset}`;
|
|
16
|
+
const tag = session ? ` ${c.cyan}[${session}]${c.reset}` : '';
|
|
17
|
+
if (output)
|
|
18
|
+
process.stdout.write(`${c.dim}${output}${c.reset}\n`);
|
|
19
|
+
process.stdout.write(`${icon}${tag} ${message}\n`);
|
|
20
|
+
}
|
|
21
|
+
export async function run(argv) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = parseInvocation(argv);
|
|
24
|
+
if (parsed.local === 'version') {
|
|
25
|
+
console.log(VERSION);
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
if (parsed.local === 'help') {
|
|
29
|
+
console.log(argv.includes('workflow') ? workflowText() : helpText());
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
const response = await sendCommand(parsed.session, parsed.command);
|
|
33
|
+
if (parsed.json) {
|
|
34
|
+
process.stdout.write(`${JSON.stringify(response)}\n`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
colorOutput(response.session, response.ok, response.message, response.output);
|
|
38
|
+
}
|
|
39
|
+
return response.ok ? 0 : 1;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
43
|
+
if (argv.includes('--json')) {
|
|
44
|
+
process.stdout.write(`${JSON.stringify({ ok: false, message })}\n`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
process.stderr.write(`${c.red}✘${c.reset} ${c.bold}Error:${c.reset} ${message}\n`);
|
|
48
|
+
}
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (process.argv[1]?.endsWith('cli.js')) {
|
|
53
|
+
process.exitCode = await run(process.argv.slice(2));
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
package/dist/client.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { connect } from 'node:net';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { LOCK_PATH, METADATA_PATH, SOCKET_PATH, STATE_DIR } from './paths.js';
|
|
6
|
+
export async function sendCommand(session, command) {
|
|
7
|
+
const metadata = await ensureDaemon();
|
|
8
|
+
return request(metadata, { token: metadata.token, session, command });
|
|
9
|
+
}
|
|
10
|
+
async function ensureDaemon(retryStaleLock = true) {
|
|
11
|
+
const current = await readDaemonMetadata();
|
|
12
|
+
if (current && (await canConnect(current)))
|
|
13
|
+
return current;
|
|
14
|
+
await mkdir(STATE_DIR, { recursive: true, mode: 0o700 });
|
|
15
|
+
const ownsStartup = await acquireStartupLock();
|
|
16
|
+
if (ownsStartup) {
|
|
17
|
+
await Promise.allSettled([
|
|
18
|
+
rm(METADATA_PATH, { force: true }),
|
|
19
|
+
rm(SOCKET_PATH, { force: true }),
|
|
20
|
+
]);
|
|
21
|
+
const entry = fileURLToPath(new URL('./daemon-entry.js', import.meta.url));
|
|
22
|
+
const child = spawn(process.execPath, [entry], {
|
|
23
|
+
detached: true,
|
|
24
|
+
stdio: 'ignore',
|
|
25
|
+
env: process.env,
|
|
26
|
+
});
|
|
27
|
+
child.unref();
|
|
28
|
+
}
|
|
29
|
+
const deadline = Date.now() + 5000;
|
|
30
|
+
while (Date.now() < deadline) {
|
|
31
|
+
const started = await readDaemonMetadata();
|
|
32
|
+
if (started && (await canConnect(started))) {
|
|
33
|
+
if (ownsStartup)
|
|
34
|
+
await rm(LOCK_PATH, { force: true });
|
|
35
|
+
return started;
|
|
36
|
+
}
|
|
37
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
38
|
+
}
|
|
39
|
+
await rm(LOCK_PATH, { force: true });
|
|
40
|
+
if (!ownsStartup && retryStaleLock) {
|
|
41
|
+
return ensureDaemon(false);
|
|
42
|
+
}
|
|
43
|
+
throw new Error('Timed out starting the appclaw-agent daemon');
|
|
44
|
+
}
|
|
45
|
+
async function acquireStartupLock() {
|
|
46
|
+
try {
|
|
47
|
+
await writeFile(LOCK_PATH, `${process.pid}\n`, { flag: 'wx', mode: 0o600 });
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function readDaemonMetadata() {
|
|
55
|
+
try {
|
|
56
|
+
return JSON.parse(await readFile(METADATA_PATH, 'utf8'));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function canConnect(metadata) {
|
|
63
|
+
try {
|
|
64
|
+
const response = await request(metadata, {
|
|
65
|
+
token: metadata.token,
|
|
66
|
+
session: 'default',
|
|
67
|
+
command: { kind: 'list' },
|
|
68
|
+
});
|
|
69
|
+
return response.ok;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function request(metadata, message) {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
const socket = connect(metadata.socketPath);
|
|
78
|
+
let body = '';
|
|
79
|
+
socket.setEncoding('utf8');
|
|
80
|
+
socket.once('error', reject);
|
|
81
|
+
socket.on('data', (chunk) => {
|
|
82
|
+
body += chunk;
|
|
83
|
+
});
|
|
84
|
+
socket.once('connect', () => socket.write(`${JSON.stringify(message)}\n`));
|
|
85
|
+
socket.once('end', () => {
|
|
86
|
+
try {
|
|
87
|
+
resolve(JSON.parse(body.trim()));
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
reject(error);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAuB,MAAM,YAAY,CAAC;AAGnG,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAe,EAAE,OAAgB;IACjE,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;IACtC,OAAO,OAAO,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,cAAc,GAAG,IAAI;IAC/C,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC3C,IAAI,OAAO,IAAI,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,OAAO,CAAC;IAE3D,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,MAAM,WAAW,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAC/C,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,OAAO,CAAC,UAAU,CAAC;YACvB,EAAE,CAAC,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YAClC,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;SACjC,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3E,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE;YAC7C,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,QAAQ;YACf,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACnC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAC3C,IAAI,OAAO,IAAI,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YAC3C,IAAI,WAAW;gBAAE,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,WAAW,IAAI,cAAc,EAAE,CAAC;QACnC,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;AACjE,CAAC;AAED,KAAK,UAAU,kBAAkB;IAC/B,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,kBAAkB;IAC/B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,CAAmB,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,QAAwB;IAChD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE;YACvC,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,OAAO,EAAE,SAAS;YAClB,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;SAC1B,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,EAAE,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,QAAwB,EAAE,OAAsB;IAC/D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC3B,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1B,IAAI,IAAI,KAAK,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE;YACtB,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAoB,CAAC,CAAC;YACtD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-entry.js","sourceRoot":"","sources":["../src/daemon-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;AACjC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC"}
|
package/dist/daemon.d.ts
ADDED
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { chmod, mkdir, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { createServer } from 'node:net';
|
|
4
|
+
import { AgentDaemonState } from './server.js';
|
|
5
|
+
import { LOCK_PATH, METADATA_PATH, SOCKET_PATH, STATE_DIR } from './paths.js';
|
|
6
|
+
const IDLE_TIMEOUT_MS = Number(process.env.APPCLAW_AGENT_IDLE_TIMEOUT_MS ?? 30000);
|
|
7
|
+
export class AgentDaemon {
|
|
8
|
+
token = randomBytes(32).toString('hex');
|
|
9
|
+
state = new AgentDaemonState();
|
|
10
|
+
server = null;
|
|
11
|
+
idleTimer = null;
|
|
12
|
+
async start() {
|
|
13
|
+
await mkdir(STATE_DIR, { recursive: true, mode: 0o700 });
|
|
14
|
+
await rm(SOCKET_PATH, { force: true });
|
|
15
|
+
const server = createServer((socket) => this.accept(socket));
|
|
16
|
+
this.server = server;
|
|
17
|
+
await new Promise((resolve, reject) => {
|
|
18
|
+
server.once('error', reject);
|
|
19
|
+
server.listen(SOCKET_PATH, resolve);
|
|
20
|
+
});
|
|
21
|
+
await chmod(SOCKET_PATH, 0o600);
|
|
22
|
+
const metadata = {
|
|
23
|
+
pid: process.pid,
|
|
24
|
+
socketPath: SOCKET_PATH,
|
|
25
|
+
token: this.token,
|
|
26
|
+
};
|
|
27
|
+
await writeFile(METADATA_PATH, JSON.stringify(metadata), { mode: 0o600 });
|
|
28
|
+
process.once('SIGTERM', () => void this.stop());
|
|
29
|
+
process.once('SIGINT', () => void this.stop());
|
|
30
|
+
this.refreshIdleTimer();
|
|
31
|
+
}
|
|
32
|
+
async stop() {
|
|
33
|
+
if (this.idleTimer)
|
|
34
|
+
clearTimeout(this.idleTimer);
|
|
35
|
+
await this.state.closeAll();
|
|
36
|
+
if (this.server) {
|
|
37
|
+
await new Promise((resolve) => this.server.close(() => resolve()));
|
|
38
|
+
}
|
|
39
|
+
await Promise.allSettled([
|
|
40
|
+
rm(SOCKET_PATH, { force: true }),
|
|
41
|
+
rm(METADATA_PATH, { force: true }),
|
|
42
|
+
rm(LOCK_PATH, { force: true }),
|
|
43
|
+
]);
|
|
44
|
+
process.exitCode = 0;
|
|
45
|
+
}
|
|
46
|
+
accept(socket) {
|
|
47
|
+
let input = '';
|
|
48
|
+
socket.setEncoding('utf8');
|
|
49
|
+
socket.on('data', (chunk) => {
|
|
50
|
+
input += chunk;
|
|
51
|
+
const newline = input.indexOf('\n');
|
|
52
|
+
if (newline < 0)
|
|
53
|
+
return;
|
|
54
|
+
const raw = input.slice(0, newline);
|
|
55
|
+
void this.respond(socket, raw);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async respond(socket, raw) {
|
|
59
|
+
try {
|
|
60
|
+
const request = JSON.parse(raw);
|
|
61
|
+
if (request.token !== this.token) {
|
|
62
|
+
socket.end(`${JSON.stringify({ ok: false, message: 'Unauthorized daemon request' })}\n`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const response = await this.state.execute(request.session, request.command);
|
|
66
|
+
socket.end(`${JSON.stringify(response)}\n`);
|
|
67
|
+
this.refreshIdleTimer();
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
socket.end(`${JSON.stringify({
|
|
71
|
+
ok: false,
|
|
72
|
+
message: error instanceof Error ? error.message : String(error),
|
|
73
|
+
})}\n`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
refreshIdleTimer() {
|
|
77
|
+
if (this.idleTimer)
|
|
78
|
+
clearTimeout(this.idleTimer);
|
|
79
|
+
if (this.state.sessionCount > 0)
|
|
80
|
+
return;
|
|
81
|
+
this.idleTimer = setTimeout(() => void this.stop(), IDLE_TIMEOUT_MS);
|
|
82
|
+
this.idleTimer.unref();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
package/dist/help.d.ts
ADDED
package/dist/help.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export const VERSION = '0.1.0';
|
|
2
|
+
export function helpText() {
|
|
3
|
+
return `appclaw-agent - terminal mobile automation for coding agents
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
appclaw-agent --session <name> <command> [options]
|
|
7
|
+
|
|
8
|
+
Run \`appclaw-agent help workflow\` for the recommended agent workflow.`;
|
|
9
|
+
}
|
|
10
|
+
export function workflowText() {
|
|
11
|
+
return `Recommended AppClaw agent workflow:
|
|
12
|
+
|
|
13
|
+
1. Open a named session:
|
|
14
|
+
appclaw-agent --session <name> open <app-id> --platform android|ios
|
|
15
|
+
|
|
16
|
+
2. Inspect actionable UI:
|
|
17
|
+
appclaw-agent --session <name> snapshot -i --json
|
|
18
|
+
|
|
19
|
+
3. Use returned refs or stable selectors:
|
|
20
|
+
appclaw-agent --session <name> press @e1 --json
|
|
21
|
+
appclaw-agent --session <name> fill @e2 "text" --json
|
|
22
|
+
appclaw-agent --session <name> press 'id="login_button"' --json
|
|
23
|
+
|
|
24
|
+
4. Scroll the screen or a specific container:
|
|
25
|
+
appclaw-agent --session <name> scroll down --json (scroll down — see content below)
|
|
26
|
+
appclaw-agent --session <name> scroll up --json (scroll up — see content above)
|
|
27
|
+
appclaw-agent --session <name> scroll @e24 down --json (scroll within a specific element)
|
|
28
|
+
|
|
29
|
+
Always use "scroll", not "swipe" — they are aliases but "scroll down/up" is unambiguous.
|
|
30
|
+
Never use "swipe @eN direction" — element-scoped swipe is not implemented.
|
|
31
|
+
|
|
32
|
+
Re-run snapshot after every state-changing action; refs are invalidated.
|
|
33
|
+
|
|
34
|
+
NOTE: snapshot reports DOM elements — it does not confirm visual on-screen
|
|
35
|
+
presence. To verify what is actually rendered, take a screenshot instead:
|
|
36
|
+
appclaw-agent --session <name> screenshot /tmp/screen.png
|
|
37
|
+
|
|
38
|
+
5. Press hardware keys:
|
|
39
|
+
appclaw-agent --session <name> enter --json
|
|
40
|
+
appclaw-agent --session <name> back --json
|
|
41
|
+
appclaw-agent --session <name> home --json
|
|
42
|
+
|
|
43
|
+
6. Verify visual state:
|
|
44
|
+
IMPORTANT: Always verify assertions visually via screenshot. DOM checks only confirm
|
|
45
|
+
an element exists in the hierarchy — not that it is visible on screen. An element can
|
|
46
|
+
be in the DOM but scrolled off-screen or clipped. Screenshot is the only reliable check.
|
|
47
|
+
|
|
48
|
+
- Visual/rendered check (PREFERRED — actually on screen):
|
|
49
|
+
appclaw-agent --session <name> screenshot /tmp/screen.png
|
|
50
|
+
(then read the image file to analyze visually — base pass/fail on what you see)
|
|
51
|
+
- DOM check (element exists in hierarchy, NOT a visibility guarantee):
|
|
52
|
+
appclaw-agent --session <name> is visible 'text="Sign in"' --json
|
|
53
|
+
- Vision check (requires AppClaw vision API key configured):
|
|
54
|
+
appclaw-agent --session <name> is visible --vision "search icon" --json
|
|
55
|
+
appclaw-agent --session <name> get info --vision "displayed total" --json
|
|
56
|
+
When vision is NOT configured, these commands automatically capture a screenshot
|
|
57
|
+
and return its path in screenshotPath — read that file to answer visually.
|
|
58
|
+
|
|
59
|
+
7. Close the session:
|
|
60
|
+
appclaw-agent --session <name> close`;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=help.js.map
|
package/dist/help.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,MAAM,UAAU,QAAQ;IACtB,OAAO;;;;;wEAK+D,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wCAiD+B,CAAC;AACzC,CAAC"}
|
package/dist/parser.d.ts
ADDED
package/dist/parser.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
export function parseInvocation(argv) {
|
|
3
|
+
const args = [...argv];
|
|
4
|
+
let session = 'default';
|
|
5
|
+
let json = false;
|
|
6
|
+
for (let i = 0; i < args.length;) {
|
|
7
|
+
if (args[i] === '--session') {
|
|
8
|
+
session = required(args[i + 1], '--session requires a name');
|
|
9
|
+
args.splice(i, 2);
|
|
10
|
+
}
|
|
11
|
+
else if (args[i] === '--json') {
|
|
12
|
+
json = true;
|
|
13
|
+
args.splice(i, 1);
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
i++;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (args.length === 0 || args[0] === '--help' || args[0] === 'help') {
|
|
20
|
+
return { session, json, local: 'help' };
|
|
21
|
+
}
|
|
22
|
+
if (args[0] === '--version' || args[0] === 'version') {
|
|
23
|
+
return { session, json, local: 'version' };
|
|
24
|
+
}
|
|
25
|
+
const name = args.shift();
|
|
26
|
+
if (name === 'session' && args[0] === 'list')
|
|
27
|
+
return { session, json, command: { kind: 'list' } };
|
|
28
|
+
if (name === 'open') {
|
|
29
|
+
const app = required(args.shift(), 'open requires an app id');
|
|
30
|
+
const platform = option(args, '--platform');
|
|
31
|
+
if (platform !== 'android' && platform !== 'ios') {
|
|
32
|
+
throw new Error('open requires --platform android|ios');
|
|
33
|
+
}
|
|
34
|
+
const rawDeviceType = option(args, '--device-type');
|
|
35
|
+
if (rawDeviceType && rawDeviceType !== 'simulator' && rawDeviceType !== 'real') {
|
|
36
|
+
throw new Error('--device-type must be simulator or real');
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
session,
|
|
40
|
+
json,
|
|
41
|
+
command: {
|
|
42
|
+
kind: 'open',
|
|
43
|
+
options: {
|
|
44
|
+
app,
|
|
45
|
+
platform,
|
|
46
|
+
...(rawDeviceType && { deviceType: rawDeviceType }),
|
|
47
|
+
...(option(args, '--device') && { device: option(args, '--device') }),
|
|
48
|
+
...(option(args, '--udid') && { udid: option(args, '--udid') }),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (name === 'snapshot') {
|
|
54
|
+
if (args.includes('--vision')) {
|
|
55
|
+
throw new Error('--vision is not supported on snapshot. Use "is visible --vision" or "get info --vision" for visual checks, or "screenshot <path>" to capture and analyze the screen.');
|
|
56
|
+
}
|
|
57
|
+
return { session, json, command: { kind: 'snapshot', interactiveOnly: args.includes('-i') } };
|
|
58
|
+
}
|
|
59
|
+
if (name === 'press') {
|
|
60
|
+
const vision = option(args, '--vision');
|
|
61
|
+
return {
|
|
62
|
+
session,
|
|
63
|
+
json,
|
|
64
|
+
command: vision
|
|
65
|
+
? { kind: 'press', target: { text: vision }, vision }
|
|
66
|
+
: { kind: 'press', target: parseTarget(required(args[0], 'press requires a target')) },
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (name === 'fill') {
|
|
70
|
+
return {
|
|
71
|
+
session,
|
|
72
|
+
json,
|
|
73
|
+
command: {
|
|
74
|
+
kind: 'fill',
|
|
75
|
+
target: parseTarget(required(args[0], 'fill requires a target')),
|
|
76
|
+
text: required(args[1], 'fill requires text'),
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (name === 'longpress') {
|
|
81
|
+
const duration = args[1] ? Number(args[1]) : undefined;
|
|
82
|
+
if (duration !== undefined && !Number.isFinite(duration))
|
|
83
|
+
throw new Error('duration must be numeric');
|
|
84
|
+
return {
|
|
85
|
+
session,
|
|
86
|
+
json,
|
|
87
|
+
command: {
|
|
88
|
+
kind: 'longpress',
|
|
89
|
+
target: parseTarget(required(args[0], 'longpress requires a target')),
|
|
90
|
+
...(duration !== undefined && { duration }),
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (name === 'swipe' || name === 'scroll') {
|
|
95
|
+
const DIRECTIONS = ['up', 'down', 'left', 'right'];
|
|
96
|
+
// swipe <target> <direction> — element-scoped scroll
|
|
97
|
+
if (args.length >= 2 && DIRECTIONS.includes(args[1])) {
|
|
98
|
+
return {
|
|
99
|
+
session,
|
|
100
|
+
json,
|
|
101
|
+
command: {
|
|
102
|
+
kind: 'swipe',
|
|
103
|
+
target: parseTarget(args[0]),
|
|
104
|
+
direction: args[1],
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
// swipe <direction> — full-screen swipe
|
|
109
|
+
const direction = args[0];
|
|
110
|
+
if (!DIRECTIONS.includes(direction)) {
|
|
111
|
+
throw new Error(`${name} requires up|down|left|right, or <target> up|down|left|right`);
|
|
112
|
+
}
|
|
113
|
+
return { session, json, command: { kind: 'swipe', direction: direction } };
|
|
114
|
+
}
|
|
115
|
+
if (name === 'back' || name === 'home' || name === 'enter') {
|
|
116
|
+
return { session, json, command: { kind: 'key', key: name.toUpperCase() } };
|
|
117
|
+
}
|
|
118
|
+
if (name === 'get' && args[0] === 'info') {
|
|
119
|
+
const vision = option(args, '--vision');
|
|
120
|
+
if (!vision)
|
|
121
|
+
throw new Error('get info requires --vision "<description>"');
|
|
122
|
+
return { session, json, command: { kind: 'getInfo', vision } };
|
|
123
|
+
}
|
|
124
|
+
if (name === 'get' && (args[0] === 'text' || args[0] === 'attrs')) {
|
|
125
|
+
const target = parseTarget(required(args[1], `get ${args[0]} requires a target`));
|
|
126
|
+
return {
|
|
127
|
+
session,
|
|
128
|
+
json,
|
|
129
|
+
command: args[0] === 'text' ? { kind: 'getText', target } : { kind: 'getAttrs', target },
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (name === 'is' && args[0] === 'visible') {
|
|
133
|
+
const vision = option(args, '--vision');
|
|
134
|
+
if (vision)
|
|
135
|
+
return { session, json, command: { kind: 'isVisible', vision } };
|
|
136
|
+
const target = required(args[1], 'is visible requires a target or --vision');
|
|
137
|
+
return { session, json, command: visibleCommand(target) };
|
|
138
|
+
}
|
|
139
|
+
if (name === 'wait' && (args[0] === 'visible' || args[0] === 'gone')) {
|
|
140
|
+
const target = required(args[1], `wait ${args[0]} requires a target`);
|
|
141
|
+
const parsed = parseTargetOrText(target);
|
|
142
|
+
return {
|
|
143
|
+
session,
|
|
144
|
+
json,
|
|
145
|
+
command: { kind: 'wait', condition: args[0], ...parsed },
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (name === 'screenshot') {
|
|
149
|
+
return {
|
|
150
|
+
session,
|
|
151
|
+
json,
|
|
152
|
+
command: {
|
|
153
|
+
kind: 'screenshot',
|
|
154
|
+
path: resolve(required(args[0], 'screenshot requires a path')),
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (name === 'close')
|
|
159
|
+
return { session, json, command: { kind: 'close' } };
|
|
160
|
+
throw new Error(`Unknown command: ${name}. Run appclaw-agent help workflow.`);
|
|
161
|
+
}
|
|
162
|
+
export function parseTarget(value) {
|
|
163
|
+
if (/^@e\d+$/.test(value))
|
|
164
|
+
return { ref: value };
|
|
165
|
+
const selector = parseSelector(value);
|
|
166
|
+
if (selector)
|
|
167
|
+
return { selector };
|
|
168
|
+
const coords = /^(\d+),(\d+)$/.exec(value);
|
|
169
|
+
if (coords)
|
|
170
|
+
return { coordinates: [Number(coords[1]), Number(coords[2])] };
|
|
171
|
+
throw new Error(`Invalid target "${value}". Use @e1, id="...", accessibility="...", text="...", or x,y.`);
|
|
172
|
+
}
|
|
173
|
+
function parseTargetOrText(value) {
|
|
174
|
+
try {
|
|
175
|
+
return { target: parseTarget(value) };
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return { text: value };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function visibleCommand(value) {
|
|
182
|
+
const parsed = parseTargetOrText(value);
|
|
183
|
+
return { kind: 'isVisible', ...parsed };
|
|
184
|
+
}
|
|
185
|
+
function parseSelector(value) {
|
|
186
|
+
const match = /^(id|accessibility|text)="([\s\S]*)"$/.exec(value);
|
|
187
|
+
if (!match)
|
|
188
|
+
return undefined;
|
|
189
|
+
return { kind: match[1], value: match[2] };
|
|
190
|
+
}
|
|
191
|
+
function option(args, name) {
|
|
192
|
+
const index = args.indexOf(name);
|
|
193
|
+
if (index < 0)
|
|
194
|
+
return undefined;
|
|
195
|
+
return required(args[index + 1], `${name} requires a value`);
|
|
196
|
+
}
|
|
197
|
+
function required(value, message) {
|
|
198
|
+
if (!value)
|
|
199
|
+
throw new Error(message);
|
|
200
|
+
return value;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const STATE_DIR: string;
|
|
2
|
+
export declare const SOCKET_PATH: string;
|
|
3
|
+
export declare const METADATA_PATH: string;
|
|
4
|
+
export declare const LOCK_PATH: string;
|
|
5
|
+
export interface DaemonMetadata {
|
|
6
|
+
pid: number;
|
|
7
|
+
socketPath: string;
|
|
8
|
+
token: string;
|
|
9
|
+
}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
export const STATE_DIR = join(homedir(), '.appclaw', 'agent-cli');
|
|
4
|
+
export const SOCKET_PATH = join(STATE_DIR, 'daemon.sock');
|
|
5
|
+
export const METADATA_PATH = join(STATE_DIR, 'daemon.json');
|
|
6
|
+
export const LOCK_PATH = join(STATE_DIR, 'daemon.lock');
|
|
7
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;AAC5D,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Command, CommandResponse } from './types.js';
|
|
2
|
+
export declare class AgentDaemonState {
|
|
3
|
+
private readonly sessions;
|
|
4
|
+
get sessionCount(): number;
|
|
5
|
+
execute(sessionName: string, command: Command): Promise<CommandResponse>;
|
|
6
|
+
closeAll(): Promise<void>;
|
|
7
|
+
private requireSession;
|
|
8
|
+
}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { tmpdir } from 'node:os';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { AgentRuntimeSession } from '@appclaw/core/agent-runtime';
|
|
4
|
+
import { snapshotWithRefs } from './snapshot.js';
|
|
5
|
+
export class AgentDaemonState {
|
|
6
|
+
sessions = new Map();
|
|
7
|
+
get sessionCount() {
|
|
8
|
+
return this.sessions.size;
|
|
9
|
+
}
|
|
10
|
+
async execute(sessionName, command) {
|
|
11
|
+
try {
|
|
12
|
+
if (command.kind === 'list') {
|
|
13
|
+
const sessions = [...this.sessions.keys()];
|
|
14
|
+
return {
|
|
15
|
+
ok: true,
|
|
16
|
+
message: sessions.length ? sessions.join('\n') : 'No active sessions',
|
|
17
|
+
data: { sessions },
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (command.kind === 'open') {
|
|
21
|
+
const previous = this.sessions.get(sessionName);
|
|
22
|
+
if (previous) {
|
|
23
|
+
await previous.runtime.close();
|
|
24
|
+
this.sessions.delete(sessionName);
|
|
25
|
+
}
|
|
26
|
+
const runtime = await AgentRuntimeSession.open(command.options);
|
|
27
|
+
this.sessions.set(sessionName, { runtime, refs: null });
|
|
28
|
+
return {
|
|
29
|
+
ok: true,
|
|
30
|
+
session: sessionName,
|
|
31
|
+
message: `Opened ${command.options.app} on ${command.options.platform}`,
|
|
32
|
+
data: { sessionId: runtime.sessionId },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (command.kind === 'close') {
|
|
36
|
+
const current = this.requireSession(sessionName);
|
|
37
|
+
await current.runtime.close();
|
|
38
|
+
this.sessions.delete(sessionName);
|
|
39
|
+
return { ok: true, session: sessionName, message: `Closed session ${sessionName}` };
|
|
40
|
+
}
|
|
41
|
+
const current = this.requireSession(sessionName);
|
|
42
|
+
if (command.kind === 'snapshot') {
|
|
43
|
+
const snapshot = await current.runtime.snapshot(command.interactiveOnly);
|
|
44
|
+
const formatted = snapshotWithRefs(snapshot);
|
|
45
|
+
current.refs = formatted.refs;
|
|
46
|
+
return {
|
|
47
|
+
ok: true,
|
|
48
|
+
session: sessionName,
|
|
49
|
+
message: `Snapshot contains ${snapshot.elements.length} element(s)`,
|
|
50
|
+
output: formatted.output,
|
|
51
|
+
data: {
|
|
52
|
+
platform: snapshot.platform,
|
|
53
|
+
elements: snapshot.elements,
|
|
54
|
+
refs: formatted.entries,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
let response;
|
|
59
|
+
switch (command.kind) {
|
|
60
|
+
case 'press':
|
|
61
|
+
if (command.vision && !current.runtime.isVisionConfigured()) {
|
|
62
|
+
return screenshotFallback(sessionName, current.runtime, command.vision, true);
|
|
63
|
+
}
|
|
64
|
+
response = result(sessionName, command.vision
|
|
65
|
+
? await current.runtime.visionPress(command.vision)
|
|
66
|
+
: await current.runtime.press(resolveTarget(current, command.target)));
|
|
67
|
+
break;
|
|
68
|
+
case 'fill':
|
|
69
|
+
response = result(sessionName, await current.runtime.fill(resolveTarget(current, command.target), command.text));
|
|
70
|
+
break;
|
|
71
|
+
case 'longpress':
|
|
72
|
+
response = result(sessionName, await current.runtime.longpress(resolveTarget(current, command.target), command.duration));
|
|
73
|
+
break;
|
|
74
|
+
case 'swipe':
|
|
75
|
+
response = result(sessionName, command.target
|
|
76
|
+
? await current.runtime.swipeElement(resolveTarget(current, command.target), command.direction)
|
|
77
|
+
: await current.runtime.swipe(command.direction));
|
|
78
|
+
break;
|
|
79
|
+
case 'key':
|
|
80
|
+
response = result(sessionName, await current.runtime.pressKey(command.key));
|
|
81
|
+
break;
|
|
82
|
+
case 'getText':
|
|
83
|
+
return result(sessionName, await current.runtime.getText(resolveTarget(current, command.target)));
|
|
84
|
+
case 'getAttrs':
|
|
85
|
+
return result(sessionName, await current.runtime.getAttrs(resolveTarget(current, command.target)));
|
|
86
|
+
case 'getInfo':
|
|
87
|
+
if (!current.runtime.isVisionConfigured()) {
|
|
88
|
+
return screenshotFallback(sessionName, current.runtime, command.vision, false);
|
|
89
|
+
}
|
|
90
|
+
return result(sessionName, await current.runtime.visionInfo(command.vision));
|
|
91
|
+
case 'isVisible':
|
|
92
|
+
if (command.vision && !current.runtime.isVisionConfigured()) {
|
|
93
|
+
return screenshotFallback(sessionName, current.runtime, command.vision, false);
|
|
94
|
+
}
|
|
95
|
+
return result(sessionName, command.vision
|
|
96
|
+
? await current.runtime.visionVisible(command.vision)
|
|
97
|
+
: await current.runtime.isVisible(command.target ? resolveTarget(current, command.target) : (command.text ?? '')));
|
|
98
|
+
case 'wait':
|
|
99
|
+
return result(sessionName, await current.runtime.waitFor(command.condition, command.target ? resolveTarget(current, command.target) : (command.text ?? '')));
|
|
100
|
+
case 'screenshot':
|
|
101
|
+
return result(sessionName, await current.runtime.saveScreenshot(command.path));
|
|
102
|
+
default:
|
|
103
|
+
return { ok: false, session: sessionName, message: 'Unsupported command' };
|
|
104
|
+
}
|
|
105
|
+
if (response.ok)
|
|
106
|
+
current.refs = null;
|
|
107
|
+
return response;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
session: sessionName,
|
|
113
|
+
message: error instanceof Error ? error.message : String(error),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async closeAll() {
|
|
118
|
+
const current = [...this.sessions.values()];
|
|
119
|
+
this.sessions.clear();
|
|
120
|
+
await Promise.allSettled(current.map(({ runtime }) => runtime.close()));
|
|
121
|
+
}
|
|
122
|
+
requireSession(name) {
|
|
123
|
+
const session = this.sessions.get(name);
|
|
124
|
+
if (!session) {
|
|
125
|
+
throw new Error(`No active session "${name}". Run appclaw-agent --session ${name} open first.`);
|
|
126
|
+
}
|
|
127
|
+
return session;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function resolveTarget(state, target) {
|
|
131
|
+
if ('ref' in target) {
|
|
132
|
+
if (!state.refs) {
|
|
133
|
+
throw new Error(`Reference ${target.ref} is stale. Run snapshot -i again before interacting.`);
|
|
134
|
+
}
|
|
135
|
+
const value = state.refs.get(target.ref);
|
|
136
|
+
if (!value)
|
|
137
|
+
throw new Error(`Unknown reference ${target.ref}. Run snapshot -i again.`);
|
|
138
|
+
return value;
|
|
139
|
+
}
|
|
140
|
+
if ('selector' in target)
|
|
141
|
+
return { selector: target.selector };
|
|
142
|
+
if ('coordinates' in target)
|
|
143
|
+
return { coordinates: target.coordinates };
|
|
144
|
+
throw new Error('Text targets are supported only by visibility and wait commands');
|
|
145
|
+
}
|
|
146
|
+
async function screenshotFallback(session, runtime, visualQuery, pressIntent) {
|
|
147
|
+
const screenshotPath = join(tmpdir(), `appclaw-visual-${Date.now()}.png`);
|
|
148
|
+
await runtime.saveScreenshot(screenshotPath);
|
|
149
|
+
const action = pressIntent
|
|
150
|
+
? `Determine the coordinates of "${visualQuery}" from the screenshot, then use press <x,y> to tap it.`
|
|
151
|
+
: `Read this image file and visually determine if "${visualQuery}" is present on screen.`;
|
|
152
|
+
return {
|
|
153
|
+
ok: true,
|
|
154
|
+
session,
|
|
155
|
+
message: `Vision not configured — screenshot captured for visual analysis. ${action}`,
|
|
156
|
+
screenshotPath,
|
|
157
|
+
visualQuery,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function result(session, operation) {
|
|
161
|
+
return {
|
|
162
|
+
ok: operation.success,
|
|
163
|
+
session,
|
|
164
|
+
message: operation.message,
|
|
165
|
+
...(operation.value !== undefined && { data: operation.value }),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AgentSnapshot, AgentTarget } from '@appclaw/core/agent-runtime';
|
|
2
|
+
import type { SnapshotRef } from './types.js';
|
|
3
|
+
export declare function snapshotWithRefs(snapshot: AgentSnapshot): {
|
|
4
|
+
refs: Map<string, AgentTarget>;
|
|
5
|
+
entries: SnapshotRef[];
|
|
6
|
+
output: string;
|
|
7
|
+
};
|
package/dist/snapshot.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function snapshotWithRefs(snapshot) {
|
|
2
|
+
const refs = new Map();
|
|
3
|
+
const entries = [];
|
|
4
|
+
const lines = snapshot.elements.map((element, index) => {
|
|
5
|
+
const ref = `@e${index + 1}`;
|
|
6
|
+
const target = element.selector
|
|
7
|
+
? { selector: element.selector }
|
|
8
|
+
: { coordinates: element.center };
|
|
9
|
+
refs.set(ref, target);
|
|
10
|
+
entries.push({ ref, target });
|
|
11
|
+
const label = element.text ? ` "${element.text}"` : '';
|
|
12
|
+
const id = element.id
|
|
13
|
+
? ` id="${element.id}"`
|
|
14
|
+
: element.accessibilityId
|
|
15
|
+
? ` accessibility="${element.accessibilityId}"`
|
|
16
|
+
: '';
|
|
17
|
+
const state = element.enabled ? '' : ' disabled';
|
|
18
|
+
return `${ref} [${element.type || element.action}]${label}${id}${state}`;
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
refs,
|
|
22
|
+
entries,
|
|
23
|
+
output: lines.length ? lines.join('\n') : '(no matching elements on screen)',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,gBAAgB,CAAC,QAAuB;IAKtD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC5C,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;QACrD,MAAM,GAAG,GAAG,KAAK,KAAK,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAgB,OAAO,CAAC,QAAQ;YAC1C,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE;YAChC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;QACpC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE;YACnB,CAAC,CAAC,QAAQ,OAAO,CAAC,EAAE,GAAG;YACvB,CAAC,CAAC,OAAO,CAAC,eAAe;gBACvB,CAAC,CAAC,mBAAmB,OAAO,CAAC,eAAe,GAAG;gBAC/C,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;QACjD,OAAO,GAAG,GAAG,KAAK,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,IAAI,KAAK,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,OAAO;QACL,IAAI;QACJ,OAAO;QACP,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,kCAAkC;KAC7E,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { AgentOpenOptions, AgentSelector, AgentTarget } from '@appclaw/core/agent-runtime';
|
|
2
|
+
export type Command = {
|
|
3
|
+
kind: 'open';
|
|
4
|
+
options: AgentOpenOptions;
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'snapshot';
|
|
7
|
+
interactiveOnly: boolean;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'press';
|
|
10
|
+
target: TargetInput;
|
|
11
|
+
vision?: string;
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'fill';
|
|
14
|
+
target: TargetInput;
|
|
15
|
+
text: string;
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'longpress';
|
|
18
|
+
target: TargetInput;
|
|
19
|
+
duration?: number;
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'swipe';
|
|
22
|
+
direction: 'up' | 'down' | 'left' | 'right';
|
|
23
|
+
target?: TargetInput;
|
|
24
|
+
} | {
|
|
25
|
+
kind: 'key';
|
|
26
|
+
key: 'BACK' | 'HOME' | 'ENTER';
|
|
27
|
+
} | {
|
|
28
|
+
kind: 'getText';
|
|
29
|
+
target: TargetInput;
|
|
30
|
+
} | {
|
|
31
|
+
kind: 'getAttrs';
|
|
32
|
+
target: TargetInput;
|
|
33
|
+
} | {
|
|
34
|
+
kind: 'getInfo';
|
|
35
|
+
vision: string;
|
|
36
|
+
} | {
|
|
37
|
+
kind: 'isVisible';
|
|
38
|
+
target?: TargetInput;
|
|
39
|
+
text?: string;
|
|
40
|
+
vision?: string;
|
|
41
|
+
} | {
|
|
42
|
+
kind: 'wait';
|
|
43
|
+
condition: 'visible' | 'gone';
|
|
44
|
+
target?: TargetInput;
|
|
45
|
+
text?: string;
|
|
46
|
+
} | {
|
|
47
|
+
kind: 'screenshot';
|
|
48
|
+
path: string;
|
|
49
|
+
} | {
|
|
50
|
+
kind: 'list';
|
|
51
|
+
} | {
|
|
52
|
+
kind: 'close';
|
|
53
|
+
};
|
|
54
|
+
export type TargetInput = {
|
|
55
|
+
ref: string;
|
|
56
|
+
} | {
|
|
57
|
+
selector: AgentSelector;
|
|
58
|
+
} | {
|
|
59
|
+
text: string;
|
|
60
|
+
} | {
|
|
61
|
+
coordinates: [number, number];
|
|
62
|
+
};
|
|
63
|
+
export interface ParsedInvocation {
|
|
64
|
+
session: string;
|
|
65
|
+
json: boolean;
|
|
66
|
+
local?: 'help' | 'version';
|
|
67
|
+
command?: Command;
|
|
68
|
+
}
|
|
69
|
+
export interface DaemonRequest {
|
|
70
|
+
token: string;
|
|
71
|
+
session: string;
|
|
72
|
+
command: Command;
|
|
73
|
+
}
|
|
74
|
+
export interface CommandResponse {
|
|
75
|
+
ok: boolean;
|
|
76
|
+
session?: string;
|
|
77
|
+
message: string;
|
|
78
|
+
data?: unknown;
|
|
79
|
+
output?: string;
|
|
80
|
+
/** Set when vision was requested but not configured. Read this image file to answer the visualQuery visually. */
|
|
81
|
+
screenshotPath?: string;
|
|
82
|
+
visualQuery?: string;
|
|
83
|
+
}
|
|
84
|
+
export interface SnapshotRef {
|
|
85
|
+
ref: string;
|
|
86
|
+
target: AgentTarget;
|
|
87
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@appclaw/agent",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Agent-native terminal CLI for AppClaw mobile automation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"appclaw-agent": "bin/appclaw-agent.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/cli.js",
|
|
10
|
+
"types": "dist/cli.d.ts",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"bin",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"test": "vitest run"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@appclaw/core": "2.0.0"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
29
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
30
|
+
"@semantic-release/git": "^10.0.1",
|
|
31
|
+
"@semantic-release/github": "^11.0.6",
|
|
32
|
+
"@semantic-release/npm": "^12.0.2",
|
|
33
|
+
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
34
|
+
"@types/node": "^22.0.0",
|
|
35
|
+
"conventional-changelog-conventionalcommits": "^9.3.1",
|
|
36
|
+
"semantic-release": "^24.2.9",
|
|
37
|
+
"typescript": "^5.6.0",
|
|
38
|
+
"vitest": "^4.1.2"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18"
|
|
42
|
+
}
|
|
43
|
+
}
|