@hasna/computer 0.1.1 → 0.1.2
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/agent/loop.d.ts.map +1 -1
- package/dist/cli/index.js +442 -15
- package/dist/db/agents.d.ts +26 -0
- package/dist/db/agents.d.ts.map +1 -0
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.d.ts.map +1 -1
- package/dist/drivers/mac/accessibility.d.ts +33 -0
- package/dist/drivers/mac/accessibility.d.ts.map +1 -0
- package/dist/drivers/mac/index.d.ts +7 -1
- package/dist/drivers/mac/index.d.ts.map +1 -1
- package/dist/drivers/mac/screenshot.d.ts +1 -1
- package/dist/drivers/mac/screenshot.d.ts.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +371 -36
- package/dist/lib/integrations.d.ts +30 -0
- package/dist/lib/integrations.d.ts.map +1 -0
- package/dist/lib/terminal-image.d.ts +29 -0
- package/dist/lib/terminal-image.d.ts.map +1 -0
- package/dist/mcp/index.js +347 -36
- package/dist/server/index.js +156 -36
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/helpers/accessibility +0 -0
- package/helpers/accessibility.swift +161 -0
- package/package.json +3 -1
package/dist/server/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
+
var __require = import.meta.require;
|
|
3
4
|
|
|
4
5
|
// src/agent/loop.ts
|
|
5
6
|
import { randomUUID } from "crypto";
|
|
@@ -9,10 +10,15 @@ import { mkdir } from "fs/promises";
|
|
|
9
10
|
import { tmpdir } from "os";
|
|
10
11
|
import { join } from "path";
|
|
11
12
|
import { readFile, unlink } from "fs/promises";
|
|
12
|
-
async function captureScreenshot() {
|
|
13
|
+
async function captureScreenshot(displayNumber) {
|
|
13
14
|
const timestamp = Date.now();
|
|
14
15
|
const tmpPath = join(tmpdir(), `computer-screenshot-${timestamp}.png`);
|
|
15
|
-
const
|
|
16
|
+
const args = ["screencapture", "-x", "-C", "-t", "png"];
|
|
17
|
+
if (displayNumber) {
|
|
18
|
+
args.push(`-D${displayNumber}`);
|
|
19
|
+
}
|
|
20
|
+
args.push(tmpPath);
|
|
21
|
+
const proc = Bun.spawn(args, {
|
|
16
22
|
stdout: "pipe",
|
|
17
23
|
stderr: "pipe"
|
|
18
24
|
});
|
|
@@ -235,19 +241,23 @@ function getScrollHelperPath() {
|
|
|
235
241
|
|
|
236
242
|
// src/drivers/mac/index.ts
|
|
237
243
|
class MacDriver {
|
|
244
|
+
displayNumber;
|
|
245
|
+
constructor(opts) {
|
|
246
|
+
this.displayNumber = opts?.displayNumber;
|
|
247
|
+
}
|
|
238
248
|
async getScreenSize() {
|
|
239
249
|
return getScreenSize();
|
|
240
250
|
}
|
|
241
251
|
async screenshot() {
|
|
242
|
-
return captureScreenshot();
|
|
252
|
+
return captureScreenshot(this.displayNumber);
|
|
243
253
|
}
|
|
244
254
|
async execute(action) {
|
|
245
255
|
return executeAction(action);
|
|
246
256
|
}
|
|
247
257
|
async dispose() {}
|
|
248
258
|
}
|
|
249
|
-
function createMacDriver() {
|
|
250
|
-
return new MacDriver;
|
|
259
|
+
function createMacDriver(opts) {
|
|
260
|
+
return new MacDriver(opts);
|
|
251
261
|
}
|
|
252
262
|
|
|
253
263
|
// node_modules/@anthropic-ai/sdk/version.mjs
|
|
@@ -9537,7 +9547,7 @@ var __export = (target, all) => {
|
|
|
9537
9547
|
set: __exportSetter.bind(all, name)
|
|
9538
9548
|
});
|
|
9539
9549
|
};
|
|
9540
|
-
var
|
|
9550
|
+
var __require2 = /* @__PURE__ */ createRequire(import.meta.url);
|
|
9541
9551
|
var require_postgres_array = __commonJS((exports) => {
|
|
9542
9552
|
exports.parse = function(source, transform) {
|
|
9543
9553
|
return new ArrayParser(source, transform).parse();
|
|
@@ -10477,7 +10487,7 @@ var require_defaults = __commonJS((exports, module) => {
|
|
|
10477
10487
|
});
|
|
10478
10488
|
var require_utils = __commonJS((exports, module) => {
|
|
10479
10489
|
var defaults2 = require_defaults();
|
|
10480
|
-
var util =
|
|
10490
|
+
var util = __require2("util");
|
|
10481
10491
|
var { isDate } = util.types || util;
|
|
10482
10492
|
function escapeElement(elementRepresentation) {
|
|
10483
10493
|
const escaped = elementRepresentation.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
@@ -10633,7 +10643,7 @@ var require_utils = __commonJS((exports, module) => {
|
|
|
10633
10643
|
};
|
|
10634
10644
|
});
|
|
10635
10645
|
var require_utils_legacy = __commonJS((exports, module) => {
|
|
10636
|
-
var nodeCrypto =
|
|
10646
|
+
var nodeCrypto = __require2("crypto");
|
|
10637
10647
|
function md5(string) {
|
|
10638
10648
|
return nodeCrypto.createHash("md5").update(string, "utf-8").digest("hex");
|
|
10639
10649
|
}
|
|
@@ -10666,7 +10676,7 @@ var require_utils_legacy = __commonJS((exports, module) => {
|
|
|
10666
10676
|
};
|
|
10667
10677
|
});
|
|
10668
10678
|
var require_utils_webcrypto = __commonJS((exports, module) => {
|
|
10669
|
-
var nodeCrypto =
|
|
10679
|
+
var nodeCrypto = __require2("crypto");
|
|
10670
10680
|
module.exports = {
|
|
10671
10681
|
postgresMd5PasswordHash,
|
|
10672
10682
|
randomBytes,
|
|
@@ -11076,7 +11086,7 @@ var require_pg_connection_string = __commonJS((exports, module) => {
|
|
|
11076
11086
|
if (config.sslcert || config.sslkey || config.sslrootcert || config.sslmode) {
|
|
11077
11087
|
config.ssl = {};
|
|
11078
11088
|
}
|
|
11079
|
-
const fs = config.sslcert || config.sslkey || config.sslrootcert ?
|
|
11089
|
+
const fs = config.sslcert || config.sslkey || config.sslrootcert ? __require2("fs") : null;
|
|
11080
11090
|
if (config.sslcert) {
|
|
11081
11091
|
config.ssl.cert = fs.readFileSync(config.sslcert).toString();
|
|
11082
11092
|
}
|
|
@@ -11199,7 +11209,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
|
|
|
11199
11209
|
parse.parseIntoClientConfig = parseIntoClientConfig;
|
|
11200
11210
|
});
|
|
11201
11211
|
var require_connection_parameters = __commonJS((exports, module) => {
|
|
11202
|
-
var dns =
|
|
11212
|
+
var dns = __require2("dns");
|
|
11203
11213
|
var defaults2 = require_defaults();
|
|
11204
11214
|
var parse = require_pg_connection_string().parse;
|
|
11205
11215
|
var val = function(key, config, envVar) {
|
|
@@ -11422,7 +11432,7 @@ var require_result = __commonJS((exports, module) => {
|
|
|
11422
11432
|
module.exports = Result;
|
|
11423
11433
|
});
|
|
11424
11434
|
var require_query = __commonJS((exports, module) => {
|
|
11425
|
-
var { EventEmitter } =
|
|
11435
|
+
var { EventEmitter } = __require2("events");
|
|
11426
11436
|
var Result = require_result();
|
|
11427
11437
|
var utils = require_utils();
|
|
11428
11438
|
|
|
@@ -12405,11 +12415,11 @@ var require_stream = __commonJS((exports, module) => {
|
|
|
12405
12415
|
};
|
|
12406
12416
|
function getNodejsStreamFuncs() {
|
|
12407
12417
|
function getStream2(ssl) {
|
|
12408
|
-
const net =
|
|
12418
|
+
const net = __require2("net");
|
|
12409
12419
|
return new net.Socket;
|
|
12410
12420
|
}
|
|
12411
12421
|
function getSecureStream2(options) {
|
|
12412
|
-
const tls =
|
|
12422
|
+
const tls = __require2("tls");
|
|
12413
12423
|
return tls.connect(options);
|
|
12414
12424
|
}
|
|
12415
12425
|
return {
|
|
@@ -12451,7 +12461,7 @@ var require_stream = __commonJS((exports, module) => {
|
|
|
12451
12461
|
}
|
|
12452
12462
|
});
|
|
12453
12463
|
var require_connection = __commonJS((exports, module) => {
|
|
12454
|
-
var EventEmitter =
|
|
12464
|
+
var EventEmitter = __require2("events").EventEmitter;
|
|
12455
12465
|
var { parse, serialize } = require_dist();
|
|
12456
12466
|
var { getStream, getSecureStream } = require_stream();
|
|
12457
12467
|
var flushBuffer = serialize.flush();
|
|
@@ -12524,7 +12534,7 @@ var require_connection = __commonJS((exports, module) => {
|
|
|
12524
12534
|
options.key = self.ssl.key;
|
|
12525
12535
|
}
|
|
12526
12536
|
}
|
|
12527
|
-
const net =
|
|
12537
|
+
const net = __require2("net");
|
|
12528
12538
|
if (net.isIP && net.isIP(host) === 0) {
|
|
12529
12539
|
options.servername = host;
|
|
12530
12540
|
}
|
|
@@ -12627,8 +12637,8 @@ var require_connection = __commonJS((exports, module) => {
|
|
|
12627
12637
|
module.exports = Connection;
|
|
12628
12638
|
});
|
|
12629
12639
|
var require_split2 = __commonJS((exports, module) => {
|
|
12630
|
-
var { Transform } =
|
|
12631
|
-
var { StringDecoder } =
|
|
12640
|
+
var { Transform } = __require2("stream");
|
|
12641
|
+
var { StringDecoder } = __require2("string_decoder");
|
|
12632
12642
|
var kLast = Symbol("last");
|
|
12633
12643
|
var kDecoder = Symbol("decoder");
|
|
12634
12644
|
function transform(chunk, enc, cb) {
|
|
@@ -12724,10 +12734,10 @@ var require_split2 = __commonJS((exports, module) => {
|
|
|
12724
12734
|
module.exports = split;
|
|
12725
12735
|
});
|
|
12726
12736
|
var require_helper = __commonJS((exports, module) => {
|
|
12727
|
-
var path =
|
|
12728
|
-
var Stream3 =
|
|
12737
|
+
var path = __require2("path");
|
|
12738
|
+
var Stream3 = __require2("stream").Stream;
|
|
12729
12739
|
var split = require_split2();
|
|
12730
|
-
var util =
|
|
12740
|
+
var util = __require2("util");
|
|
12731
12741
|
var defaultPort = 5432;
|
|
12732
12742
|
var isWin = process.platform === "win32";
|
|
12733
12743
|
var warnStream = process.stderr;
|
|
@@ -12886,8 +12896,8 @@ var require_helper = __commonJS((exports, module) => {
|
|
|
12886
12896
|
};
|
|
12887
12897
|
});
|
|
12888
12898
|
var require_lib = __commonJS((exports, module) => {
|
|
12889
|
-
var path =
|
|
12890
|
-
var fs =
|
|
12899
|
+
var path = __require2("path");
|
|
12900
|
+
var fs = __require2("fs");
|
|
12891
12901
|
var helper = require_helper();
|
|
12892
12902
|
module.exports = function(connInfo, cb) {
|
|
12893
12903
|
var file = helper.getFileName();
|
|
@@ -12902,9 +12912,9 @@ var require_lib = __commonJS((exports, module) => {
|
|
|
12902
12912
|
module.exports.warnTo = helper.warnTo;
|
|
12903
12913
|
});
|
|
12904
12914
|
var require_client = __commonJS((exports, module) => {
|
|
12905
|
-
var EventEmitter =
|
|
12915
|
+
var EventEmitter = __require2("events").EventEmitter;
|
|
12906
12916
|
var utils = require_utils();
|
|
12907
|
-
var nodeUtils =
|
|
12917
|
+
var nodeUtils = __require2("util");
|
|
12908
12918
|
var sasl = require_sasl();
|
|
12909
12919
|
var TypeOverrides = require_type_overrides();
|
|
12910
12920
|
var ConnectionParameters = require_connection_parameters();
|
|
@@ -13481,7 +13491,7 @@ var require_client = __commonJS((exports, module) => {
|
|
|
13481
13491
|
module.exports = Client;
|
|
13482
13492
|
});
|
|
13483
13493
|
var require_pg_pool = __commonJS((exports, module) => {
|
|
13484
|
-
var EventEmitter =
|
|
13494
|
+
var EventEmitter = __require2("events").EventEmitter;
|
|
13485
13495
|
var NOOP = function() {};
|
|
13486
13496
|
var removeWhere = (list, predicate) => {
|
|
13487
13497
|
const i = list.findIndex(predicate);
|
|
@@ -13891,8 +13901,8 @@ var require_pg_pool = __commonJS((exports, module) => {
|
|
|
13891
13901
|
module.exports = Pool;
|
|
13892
13902
|
});
|
|
13893
13903
|
var require_query2 = __commonJS((exports, module) => {
|
|
13894
|
-
var EventEmitter =
|
|
13895
|
-
var util =
|
|
13904
|
+
var EventEmitter = __require2("events").EventEmitter;
|
|
13905
|
+
var util = __require2("util");
|
|
13896
13906
|
var utils = require_utils();
|
|
13897
13907
|
var NativeQuery = module.exports = function(config, values, callback) {
|
|
13898
13908
|
EventEmitter.call(this);
|
|
@@ -14025,7 +14035,7 @@ var require_query2 = __commonJS((exports, module) => {
|
|
|
14025
14035
|
};
|
|
14026
14036
|
});
|
|
14027
14037
|
var require_client2 = __commonJS((exports, module) => {
|
|
14028
|
-
var nodeUtils =
|
|
14038
|
+
var nodeUtils = __require2("util");
|
|
14029
14039
|
var Native;
|
|
14030
14040
|
try {
|
|
14031
14041
|
Native = (() => {
|
|
@@ -14035,8 +14045,8 @@ var require_client2 = __commonJS((exports, module) => {
|
|
|
14035
14045
|
throw e;
|
|
14036
14046
|
}
|
|
14037
14047
|
var TypeOverrides = require_type_overrides();
|
|
14038
|
-
var EventEmitter =
|
|
14039
|
-
var util =
|
|
14048
|
+
var EventEmitter = __require2("events").EventEmitter;
|
|
14049
|
+
var util = __require2("util");
|
|
14040
14050
|
var ConnectionParameters = require_connection_parameters();
|
|
14041
14051
|
var NativeQuery = require_query2();
|
|
14042
14052
|
var queryQueueLengthDeprecationNotice = nodeUtils.deprecate(() => {}, "Calling client.query() when the client is already executing a query is deprecated and will be removed in pg@9.0. Use async/await or an external async flow control mechanism instead.");
|
|
@@ -18530,6 +18540,7 @@ function getDb() {
|
|
|
18530
18540
|
total_tokens_in INTEGER NOT NULL DEFAULT 0,
|
|
18531
18541
|
total_tokens_out INTEGER NOT NULL DEFAULT 0,
|
|
18532
18542
|
total_duration_ms INTEGER NOT NULL DEFAULT 0,
|
|
18543
|
+
tags TEXT,
|
|
18533
18544
|
error TEXT,
|
|
18534
18545
|
created_at TEXT NOT NULL,
|
|
18535
18546
|
completed_at TEXT
|
|
@@ -18585,9 +18596,9 @@ function getDb() {
|
|
|
18585
18596
|
async function createSession(session) {
|
|
18586
18597
|
const d = getDb();
|
|
18587
18598
|
d.prepare(`
|
|
18588
|
-
INSERT INTO sessions (id, task, provider, model, status, steps, total_tokens_in, total_tokens_out, total_duration_ms, error, created_at, completed_at)
|
|
18589
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18590
|
-
`).run(session.id, session.task, session.provider, session.model, session.status, session.steps, session.total_tokens_in, session.total_tokens_out, session.total_duration_ms, session.error ?? null, session.created_at, session.completed_at ?? null);
|
|
18599
|
+
INSERT INTO sessions (id, task, provider, model, status, steps, total_tokens_in, total_tokens_out, total_duration_ms, tags, error, created_at, completed_at)
|
|
18600
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
18601
|
+
`).run(session.id, session.task, session.provider, session.model, session.status, session.steps, session.total_tokens_in, session.total_tokens_out, session.total_duration_ms, session.tags?.length ? JSON.stringify(session.tags) : null, session.error ?? null, session.created_at, session.completed_at ?? null);
|
|
18591
18602
|
}
|
|
18592
18603
|
async function updateSession(session) {
|
|
18593
18604
|
const d = getDb();
|
|
@@ -18615,10 +18626,18 @@ function listSessions(opts) {
|
|
|
18615
18626
|
const d = getDb();
|
|
18616
18627
|
let sql = "SELECT * FROM sessions";
|
|
18617
18628
|
const params = [];
|
|
18629
|
+
const conditions = [];
|
|
18618
18630
|
if (opts?.status) {
|
|
18619
|
-
|
|
18631
|
+
conditions.push("status = ?");
|
|
18620
18632
|
params.push(opts.status);
|
|
18621
18633
|
}
|
|
18634
|
+
if (opts?.tag) {
|
|
18635
|
+
conditions.push("tags LIKE ?");
|
|
18636
|
+
params.push(`%"${opts.tag}"%`);
|
|
18637
|
+
}
|
|
18638
|
+
if (conditions.length > 0) {
|
|
18639
|
+
sql += " WHERE " + conditions.join(" AND ");
|
|
18640
|
+
}
|
|
18622
18641
|
sql += " ORDER BY created_at DESC";
|
|
18623
18642
|
if (opts?.limit) {
|
|
18624
18643
|
sql += " LIMIT ?";
|
|
@@ -18684,12 +18703,104 @@ function rowToSession(row) {
|
|
|
18684
18703
|
total_tokens_in: row.total_tokens_in,
|
|
18685
18704
|
total_tokens_out: row.total_tokens_out,
|
|
18686
18705
|
total_duration_ms: row.total_duration_ms,
|
|
18706
|
+
tags: row.tags ? JSON.parse(row.tags) : undefined,
|
|
18687
18707
|
error: row.error,
|
|
18688
18708
|
created_at: row.created_at,
|
|
18689
18709
|
completed_at: row.completed_at
|
|
18690
18710
|
};
|
|
18691
18711
|
}
|
|
18692
18712
|
|
|
18713
|
+
// src/lib/integrations.ts
|
|
18714
|
+
async function saveToRecordings(session, logs) {
|
|
18715
|
+
try {
|
|
18716
|
+
const { saveRecording } = await import("@hasna/recordings");
|
|
18717
|
+
await saveRecording({
|
|
18718
|
+
title: `Computer Use: ${session.task.slice(0, 100)}`,
|
|
18719
|
+
type: "computer-use",
|
|
18720
|
+
source: "computer",
|
|
18721
|
+
duration_ms: session.total_duration_ms,
|
|
18722
|
+
metadata: {
|
|
18723
|
+
session_id: session.id,
|
|
18724
|
+
provider: session.provider,
|
|
18725
|
+
model: session.model,
|
|
18726
|
+
steps: session.steps,
|
|
18727
|
+
tokens_in: session.total_tokens_in,
|
|
18728
|
+
tokens_out: session.total_tokens_out,
|
|
18729
|
+
status: session.status,
|
|
18730
|
+
tags: session.tags
|
|
18731
|
+
},
|
|
18732
|
+
transcript: logs.map((l) => ({
|
|
18733
|
+
step: l.step,
|
|
18734
|
+
action: l.action.type,
|
|
18735
|
+
reasoning: l.reasoning?.slice(0, 200),
|
|
18736
|
+
success: l.success,
|
|
18737
|
+
timestamp: l.created_at
|
|
18738
|
+
}))
|
|
18739
|
+
});
|
|
18740
|
+
return true;
|
|
18741
|
+
} catch {
|
|
18742
|
+
return false;
|
|
18743
|
+
}
|
|
18744
|
+
}
|
|
18745
|
+
async function registerWithSessions(session) {
|
|
18746
|
+
try {
|
|
18747
|
+
const mod = await import("@hasna/sessions");
|
|
18748
|
+
const registerSession = mod.registerSession ?? mod.createSession ?? mod.saveSession;
|
|
18749
|
+
if (typeof registerSession !== "function")
|
|
18750
|
+
return false;
|
|
18751
|
+
await registerSession({
|
|
18752
|
+
id: session.id,
|
|
18753
|
+
type: "computer-use",
|
|
18754
|
+
source: "computer",
|
|
18755
|
+
status: session.status,
|
|
18756
|
+
metadata: {
|
|
18757
|
+
task: session.task,
|
|
18758
|
+
provider: session.provider,
|
|
18759
|
+
model: session.model,
|
|
18760
|
+
steps: session.steps
|
|
18761
|
+
},
|
|
18762
|
+
started_at: session.created_at,
|
|
18763
|
+
ended_at: session.completed_at
|
|
18764
|
+
});
|
|
18765
|
+
return true;
|
|
18766
|
+
} catch {
|
|
18767
|
+
return false;
|
|
18768
|
+
}
|
|
18769
|
+
}
|
|
18770
|
+
async function pushToLogs(session, logs) {
|
|
18771
|
+
try {
|
|
18772
|
+
const mod = await import("@hasna/logs");
|
|
18773
|
+
const pushBatch = mod.logPushBatch ?? mod.pushBatch;
|
|
18774
|
+
if (typeof pushBatch !== "function")
|
|
18775
|
+
return false;
|
|
18776
|
+
await pushBatch(logs.map((l) => ({
|
|
18777
|
+
level: l.success ? "info" : "error",
|
|
18778
|
+
source: "computer",
|
|
18779
|
+
message: `[${l.action.type}] ${l.reasoning?.slice(0, 100) ?? ""}`,
|
|
18780
|
+
metadata: {
|
|
18781
|
+
session_id: session.id,
|
|
18782
|
+
step: l.step,
|
|
18783
|
+
action_type: l.action.type,
|
|
18784
|
+
success: l.success,
|
|
18785
|
+
error: l.error,
|
|
18786
|
+
duration_ms: l.duration_ms
|
|
18787
|
+
},
|
|
18788
|
+
timestamp: l.created_at
|
|
18789
|
+
})));
|
|
18790
|
+
return true;
|
|
18791
|
+
} catch {
|
|
18792
|
+
return false;
|
|
18793
|
+
}
|
|
18794
|
+
}
|
|
18795
|
+
async function runPostSessionIntegrations(session, logs) {
|
|
18796
|
+
const [recordings, sessions, logsPushed] = await Promise.all([
|
|
18797
|
+
saveToRecordings(session, logs),
|
|
18798
|
+
registerWithSessions(session),
|
|
18799
|
+
pushToLogs(session, logs)
|
|
18800
|
+
]);
|
|
18801
|
+
return { recordings, sessions, logs: logsPushed };
|
|
18802
|
+
}
|
|
18803
|
+
|
|
18693
18804
|
// src/agent/loop.ts
|
|
18694
18805
|
var DEFAULT_MAX_STEPS = 50;
|
|
18695
18806
|
async function runTask(options) {
|
|
@@ -18703,10 +18814,12 @@ async function runTask(options) {
|
|
|
18703
18814
|
systemPrompt,
|
|
18704
18815
|
screenshotMaxWidth,
|
|
18705
18816
|
dryRun = false,
|
|
18817
|
+
tags,
|
|
18818
|
+
displayNumber,
|
|
18706
18819
|
onStep,
|
|
18707
18820
|
onDone
|
|
18708
18821
|
} = options;
|
|
18709
|
-
const driver = createMacDriver();
|
|
18822
|
+
const driver = createMacDriver({ displayNumber });
|
|
18710
18823
|
const provider = createProvider(providerName, { model });
|
|
18711
18824
|
const config = loadConfig();
|
|
18712
18825
|
const safetyConfig = config.safety;
|
|
@@ -18717,6 +18830,7 @@ async function runTask(options) {
|
|
|
18717
18830
|
provider: providerName,
|
|
18718
18831
|
model: model ?? (providerName === "anthropic" ? "claude-sonnet-4-5-20250514" : "computer-use-preview"),
|
|
18719
18832
|
status: "running",
|
|
18833
|
+
tags,
|
|
18720
18834
|
steps: 0,
|
|
18721
18835
|
total_tokens_in: 0,
|
|
18722
18836
|
total_tokens_out: 0,
|
|
@@ -18769,6 +18883,8 @@ async function runTask(options) {
|
|
|
18769
18883
|
});
|
|
18770
18884
|
await updateSession(session);
|
|
18771
18885
|
onStep?.(step, response, { success: true, duration_ms: 0 });
|
|
18886
|
+
const logs = getActionLogs(sessionId);
|
|
18887
|
+
await runPostSessionIntegrations(session, logs).catch(() => {});
|
|
18772
18888
|
onDone?.(session);
|
|
18773
18889
|
await driver.dispose();
|
|
18774
18890
|
return session;
|
|
@@ -18834,6 +18950,8 @@ async function runTask(options) {
|
|
|
18834
18950
|
session.completed_at = new Date().toISOString();
|
|
18835
18951
|
session.error = `Reached max steps (${maxSteps})`;
|
|
18836
18952
|
await updateSession(session);
|
|
18953
|
+
const endLogs = getActionLogs(sessionId);
|
|
18954
|
+
await runPostSessionIntegrations(session, endLogs).catch(() => {});
|
|
18837
18955
|
onDone?.(session);
|
|
18838
18956
|
await driver.dispose();
|
|
18839
18957
|
return session;
|
|
@@ -18843,6 +18961,8 @@ async function runTask(options) {
|
|
|
18843
18961
|
session.total_duration_ms = Date.now() - startTime;
|
|
18844
18962
|
session.completed_at = new Date().toISOString();
|
|
18845
18963
|
await updateSession(session);
|
|
18964
|
+
const errLogs = getActionLogs(sessionId);
|
|
18965
|
+
await runPostSessionIntegrations(session, errLogs).catch(() => {});
|
|
18846
18966
|
onDone?.(session);
|
|
18847
18967
|
await driver.dispose();
|
|
18848
18968
|
return session;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -128,6 +128,7 @@ export interface Session {
|
|
|
128
128
|
total_tokens_in: number;
|
|
129
129
|
total_tokens_out: number;
|
|
130
130
|
total_duration_ms: number;
|
|
131
|
+
tags?: string[];
|
|
131
132
|
error?: string;
|
|
132
133
|
created_at: string;
|
|
133
134
|
completed_at?: string;
|
|
@@ -152,6 +153,10 @@ export interface RunOptions {
|
|
|
152
153
|
screenshotMaxWidth?: number;
|
|
153
154
|
/** Dry-run mode — model plans actions but they are not executed */
|
|
154
155
|
dryRun?: boolean;
|
|
156
|
+
/** Tags for this session */
|
|
157
|
+
tags?: string[];
|
|
158
|
+
/** Display number to capture (1=main, 2=secondary, etc.) */
|
|
159
|
+
displayNumber?: number;
|
|
155
160
|
/** Callback for each step */
|
|
156
161
|
onStep?: (step: number, response: ModelResponse, result: ActionResult) => void;
|
|
157
162
|
/** Callback when done */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
Binary file
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env swift
|
|
2
|
+
// accessibility.swift — Query macOS Accessibility tree (AXUIElement)
|
|
3
|
+
// Usage: accessibility [--app <name>] [--focused] [--depth <n>]
|
|
4
|
+
// Output: JSON array of UI elements with role, title, position, size
|
|
5
|
+
//
|
|
6
|
+
// Requires: Accessibility permissions in System Settings
|
|
7
|
+
|
|
8
|
+
import AppKit
|
|
9
|
+
import Foundation
|
|
10
|
+
|
|
11
|
+
struct UIElement: Codable {
|
|
12
|
+
let role: String?
|
|
13
|
+
let title: String?
|
|
14
|
+
let value: String?
|
|
15
|
+
let label: String?
|
|
16
|
+
let x: Int
|
|
17
|
+
let y: Int
|
|
18
|
+
let width: Int
|
|
19
|
+
let height: Int
|
|
20
|
+
let enabled: Bool
|
|
21
|
+
let focused: Bool
|
|
22
|
+
let children: Int
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func getAXValue<T>(_ element: AXUIElement, _ attribute: String) -> T? {
|
|
26
|
+
var value: AnyObject?
|
|
27
|
+
let result = AXUIElementCopyAttributeValue(element, attribute as CFString, &value)
|
|
28
|
+
guard result == .success else { return nil }
|
|
29
|
+
return value as? T
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
func getPosition(_ element: AXUIElement) -> CGPoint? {
|
|
33
|
+
var value: AnyObject?
|
|
34
|
+
let result = AXUIElementCopyAttributeValue(element, kAXPositionAttribute as String as CFString, &value)
|
|
35
|
+
guard result == .success, let val = value else { return nil }
|
|
36
|
+
var point = CGPoint.zero
|
|
37
|
+
AXValueGetValue(val as! AXValue, .cgPoint, &point)
|
|
38
|
+
return point
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
func getSize(_ element: AXUIElement) -> CGSize? {
|
|
42
|
+
var value: AnyObject?
|
|
43
|
+
let result = AXUIElementCopyAttributeValue(element, kAXSizeAttribute as String as CFString, &value)
|
|
44
|
+
guard result == .success, let val = value else { return nil }
|
|
45
|
+
var size = CGSize.zero
|
|
46
|
+
AXValueGetValue(val as! AXValue, .cgSize, &size)
|
|
47
|
+
return size
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
func getChildren(_ element: AXUIElement) -> [AXUIElement] {
|
|
51
|
+
var value: AnyObject?
|
|
52
|
+
let result = AXUIElementCopyAttributeValue(element, kAXChildrenAttribute as String as CFString, &value)
|
|
53
|
+
guard result == .success, let children = value as? [AXUIElement] else { return [] }
|
|
54
|
+
return children
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
func elementToStruct(_ element: AXUIElement) -> UIElement {
|
|
58
|
+
let role: String? = getAXValue(element, kAXRoleAttribute as String)
|
|
59
|
+
let title: String? = getAXValue(element, kAXTitleAttribute as String)
|
|
60
|
+
let value: String? = getAXValue(element, kAXValueAttribute as String)
|
|
61
|
+
let label: String? = getAXValue(element, kAXDescriptionAttribute as String)
|
|
62
|
+
let enabled: Bool = getAXValue(element, kAXEnabledAttribute as String) ?? true
|
|
63
|
+
let focused: Bool = getAXValue(element, kAXFocusedAttribute as String) ?? false
|
|
64
|
+
|
|
65
|
+
let pos = getPosition(element) ?? CGPoint.zero
|
|
66
|
+
let sz = getSize(element) ?? CGSize.zero
|
|
67
|
+
let children = getChildren(element)
|
|
68
|
+
|
|
69
|
+
return UIElement(
|
|
70
|
+
role: role,
|
|
71
|
+
title: title,
|
|
72
|
+
value: (value?.count ?? 0) > 200 ? String(value!.prefix(200)) + "..." : value,
|
|
73
|
+
label: label,
|
|
74
|
+
x: Int(pos.x),
|
|
75
|
+
y: Int(pos.y),
|
|
76
|
+
width: Int(sz.width),
|
|
77
|
+
height: Int(sz.height),
|
|
78
|
+
enabled: enabled,
|
|
79
|
+
focused: focused,
|
|
80
|
+
children: children.count
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
func walkTree(_ element: AXUIElement, depth: Int, maxDepth: Int) -> [UIElement] {
|
|
85
|
+
var results: [UIElement] = []
|
|
86
|
+
let el = elementToStruct(element)
|
|
87
|
+
|
|
88
|
+
// Skip tiny/invisible elements
|
|
89
|
+
if el.width > 5 && el.height > 5 {
|
|
90
|
+
results.append(el)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if depth < maxDepth {
|
|
94
|
+
for child in getChildren(element) {
|
|
95
|
+
results.append(contentsOf: walkTree(child, depth: depth + 1, maxDepth: maxDepth))
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return results
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Parse arguments
|
|
103
|
+
var appName: String? = nil
|
|
104
|
+
var focusedOnly = false
|
|
105
|
+
var maxDepth = 3
|
|
106
|
+
|
|
107
|
+
var args = Array(CommandLine.arguments.dropFirst())
|
|
108
|
+
while !args.isEmpty {
|
|
109
|
+
let arg = args.removeFirst()
|
|
110
|
+
switch arg {
|
|
111
|
+
case "--app":
|
|
112
|
+
if !args.isEmpty { appName = args.removeFirst() }
|
|
113
|
+
case "--focused":
|
|
114
|
+
focusedOnly = true
|
|
115
|
+
case "--depth":
|
|
116
|
+
if !args.isEmpty { maxDepth = Int(args.removeFirst()) ?? 3 }
|
|
117
|
+
default:
|
|
118
|
+
break
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Get target application
|
|
123
|
+
var targetApp: NSRunningApplication?
|
|
124
|
+
if let name = appName {
|
|
125
|
+
targetApp = NSWorkspace.shared.runningApplications.first {
|
|
126
|
+
$0.localizedName?.lowercased() == name.lowercased()
|
|
127
|
+
}
|
|
128
|
+
if targetApp == nil {
|
|
129
|
+
fputs("Error: Application '\(name)' not found\n", stderr)
|
|
130
|
+
exit(1)
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
targetApp = NSWorkspace.shared.frontmostApplication
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
guard let app = targetApp, let pid = Optional(app.processIdentifier) else {
|
|
137
|
+
fputs("Error: No application found\n", stderr)
|
|
138
|
+
exit(1)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let appElement = AXUIElementCreateApplication(pid)
|
|
142
|
+
|
|
143
|
+
var elements: [UIElement]
|
|
144
|
+
if focusedOnly {
|
|
145
|
+
var focusedElement: AnyObject?
|
|
146
|
+
AXUIElementCopyAttributeValue(appElement, kAXFocusedUIElementAttribute as CFString, &focusedElement)
|
|
147
|
+
if let focused = focusedElement {
|
|
148
|
+
elements = walkTree(focused as! AXUIElement, depth: 0, maxDepth: maxDepth)
|
|
149
|
+
} else {
|
|
150
|
+
elements = []
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
elements = walkTree(appElement, depth: 0, maxDepth: maxDepth)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Output as JSON
|
|
157
|
+
let encoder = JSONEncoder()
|
|
158
|
+
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
|
|
159
|
+
if let data = try? encoder.encode(elements) {
|
|
160
|
+
print(String(data: data, encoding: .utf8)!)
|
|
161
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/computer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Open-source computer use for AI agents — control your Mac with Anthropic or OpenAI. CLI + MCP server + REST API + Dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
"dist",
|
|
21
21
|
"helpers/scroll",
|
|
22
22
|
"helpers/scroll.swift",
|
|
23
|
+
"helpers/accessibility",
|
|
24
|
+
"helpers/accessibility.swift",
|
|
23
25
|
"src/db/migrations",
|
|
24
26
|
"dashboard/dist",
|
|
25
27
|
"LICENSE",
|