@hasna/computer 0.1.1 → 0.1.3

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/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  // @bun
2
+ var __require = import.meta.require;
3
+
2
4
  // src/agent/loop.ts
3
5
  import { randomUUID } from "crypto";
4
6
  import { mkdir } from "fs/promises";
@@ -7,10 +9,15 @@ import { mkdir } from "fs/promises";
7
9
  import { tmpdir } from "os";
8
10
  import { join } from "path";
9
11
  import { readFile, unlink } from "fs/promises";
10
- async function captureScreenshot() {
12
+ async function captureScreenshot(displayNumber) {
11
13
  const timestamp = Date.now();
12
14
  const tmpPath = join(tmpdir(), `computer-screenshot-${timestamp}.png`);
13
- const proc = Bun.spawn(["screencapture", "-x", "-C", "-t", "png", tmpPath], {
15
+ const args = ["screencapture", "-x", "-C", "-t", "png"];
16
+ if (displayNumber) {
17
+ args.push(`-D${displayNumber}`);
18
+ }
19
+ args.push(tmpPath);
20
+ const proc = Bun.spawn(args, {
14
21
  stdout: "pipe",
15
22
  stderr: "pipe"
16
23
  });
@@ -233,19 +240,23 @@ function getScrollHelperPath() {
233
240
 
234
241
  // src/drivers/mac/index.ts
235
242
  class MacDriver {
243
+ displayNumber;
244
+ constructor(opts) {
245
+ this.displayNumber = opts?.displayNumber;
246
+ }
236
247
  async getScreenSize() {
237
248
  return getScreenSize();
238
249
  }
239
250
  async screenshot() {
240
- return captureScreenshot();
251
+ return captureScreenshot(this.displayNumber);
241
252
  }
242
253
  async execute(action) {
243
254
  return executeAction(action);
244
255
  }
245
256
  async dispose() {}
246
257
  }
247
- function createMacDriver() {
248
- return new MacDriver;
258
+ function createMacDriver(opts) {
259
+ return new MacDriver(opts);
249
260
  }
250
261
 
251
262
  // node_modules/@anthropic-ai/sdk/version.mjs
@@ -9586,7 +9597,7 @@ var __export = (target, all) => {
9586
9597
  set: __exportSetter.bind(all, name)
9587
9598
  });
9588
9599
  };
9589
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
9600
+ var __require2 = /* @__PURE__ */ createRequire(import.meta.url);
9590
9601
  var require_postgres_array = __commonJS((exports) => {
9591
9602
  exports.parse = function(source, transform) {
9592
9603
  return new ArrayParser(source, transform).parse();
@@ -10526,7 +10537,7 @@ var require_defaults = __commonJS((exports, module) => {
10526
10537
  });
10527
10538
  var require_utils = __commonJS((exports, module) => {
10528
10539
  var defaults2 = require_defaults();
10529
- var util = __require("util");
10540
+ var util = __require2("util");
10530
10541
  var { isDate } = util.types || util;
10531
10542
  function escapeElement(elementRepresentation) {
10532
10543
  const escaped = elementRepresentation.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
@@ -10682,7 +10693,7 @@ var require_utils = __commonJS((exports, module) => {
10682
10693
  };
10683
10694
  });
10684
10695
  var require_utils_legacy = __commonJS((exports, module) => {
10685
- var nodeCrypto = __require("crypto");
10696
+ var nodeCrypto = __require2("crypto");
10686
10697
  function md5(string) {
10687
10698
  return nodeCrypto.createHash("md5").update(string, "utf-8").digest("hex");
10688
10699
  }
@@ -10715,7 +10726,7 @@ var require_utils_legacy = __commonJS((exports, module) => {
10715
10726
  };
10716
10727
  });
10717
10728
  var require_utils_webcrypto = __commonJS((exports, module) => {
10718
- var nodeCrypto = __require("crypto");
10729
+ var nodeCrypto = __require2("crypto");
10719
10730
  module.exports = {
10720
10731
  postgresMd5PasswordHash,
10721
10732
  randomBytes,
@@ -11125,7 +11136,7 @@ var require_pg_connection_string = __commonJS((exports, module) => {
11125
11136
  if (config.sslcert || config.sslkey || config.sslrootcert || config.sslmode) {
11126
11137
  config.ssl = {};
11127
11138
  }
11128
- const fs = config.sslcert || config.sslkey || config.sslrootcert ? __require("fs") : null;
11139
+ const fs = config.sslcert || config.sslkey || config.sslrootcert ? __require2("fs") : null;
11129
11140
  if (config.sslcert) {
11130
11141
  config.ssl.cert = fs.readFileSync(config.sslcert).toString();
11131
11142
  }
@@ -11248,7 +11259,7 @@ See https://www.postgresql.org/docs/current/libpq-ssl.html for libpq SSL mode de
11248
11259
  parse.parseIntoClientConfig = parseIntoClientConfig;
11249
11260
  });
11250
11261
  var require_connection_parameters = __commonJS((exports, module) => {
11251
- var dns = __require("dns");
11262
+ var dns = __require2("dns");
11252
11263
  var defaults2 = require_defaults();
11253
11264
  var parse = require_pg_connection_string().parse;
11254
11265
  var val = function(key, config, envVar) {
@@ -11471,7 +11482,7 @@ var require_result = __commonJS((exports, module) => {
11471
11482
  module.exports = Result;
11472
11483
  });
11473
11484
  var require_query = __commonJS((exports, module) => {
11474
- var { EventEmitter } = __require("events");
11485
+ var { EventEmitter } = __require2("events");
11475
11486
  var Result = require_result();
11476
11487
  var utils = require_utils();
11477
11488
 
@@ -12454,11 +12465,11 @@ var require_stream = __commonJS((exports, module) => {
12454
12465
  };
12455
12466
  function getNodejsStreamFuncs() {
12456
12467
  function getStream2(ssl) {
12457
- const net = __require("net");
12468
+ const net = __require2("net");
12458
12469
  return new net.Socket;
12459
12470
  }
12460
12471
  function getSecureStream2(options) {
12461
- const tls = __require("tls");
12472
+ const tls = __require2("tls");
12462
12473
  return tls.connect(options);
12463
12474
  }
12464
12475
  return {
@@ -12500,7 +12511,7 @@ var require_stream = __commonJS((exports, module) => {
12500
12511
  }
12501
12512
  });
12502
12513
  var require_connection = __commonJS((exports, module) => {
12503
- var EventEmitter = __require("events").EventEmitter;
12514
+ var EventEmitter = __require2("events").EventEmitter;
12504
12515
  var { parse, serialize } = require_dist();
12505
12516
  var { getStream, getSecureStream } = require_stream();
12506
12517
  var flushBuffer = serialize.flush();
@@ -12573,7 +12584,7 @@ var require_connection = __commonJS((exports, module) => {
12573
12584
  options.key = self.ssl.key;
12574
12585
  }
12575
12586
  }
12576
- const net = __require("net");
12587
+ const net = __require2("net");
12577
12588
  if (net.isIP && net.isIP(host) === 0) {
12578
12589
  options.servername = host;
12579
12590
  }
@@ -12676,8 +12687,8 @@ var require_connection = __commonJS((exports, module) => {
12676
12687
  module.exports = Connection;
12677
12688
  });
12678
12689
  var require_split2 = __commonJS((exports, module) => {
12679
- var { Transform } = __require("stream");
12680
- var { StringDecoder } = __require("string_decoder");
12690
+ var { Transform } = __require2("stream");
12691
+ var { StringDecoder } = __require2("string_decoder");
12681
12692
  var kLast = Symbol("last");
12682
12693
  var kDecoder = Symbol("decoder");
12683
12694
  function transform(chunk, enc, cb) {
@@ -12773,10 +12784,10 @@ var require_split2 = __commonJS((exports, module) => {
12773
12784
  module.exports = split;
12774
12785
  });
12775
12786
  var require_helper = __commonJS((exports, module) => {
12776
- var path = __require("path");
12777
- var Stream3 = __require("stream").Stream;
12787
+ var path = __require2("path");
12788
+ var Stream3 = __require2("stream").Stream;
12778
12789
  var split = require_split2();
12779
- var util = __require("util");
12790
+ var util = __require2("util");
12780
12791
  var defaultPort = 5432;
12781
12792
  var isWin = process.platform === "win32";
12782
12793
  var warnStream = process.stderr;
@@ -12935,8 +12946,8 @@ var require_helper = __commonJS((exports, module) => {
12935
12946
  };
12936
12947
  });
12937
12948
  var require_lib = __commonJS((exports, module) => {
12938
- var path = __require("path");
12939
- var fs = __require("fs");
12949
+ var path = __require2("path");
12950
+ var fs = __require2("fs");
12940
12951
  var helper = require_helper();
12941
12952
  module.exports = function(connInfo, cb) {
12942
12953
  var file = helper.getFileName();
@@ -12951,9 +12962,9 @@ var require_lib = __commonJS((exports, module) => {
12951
12962
  module.exports.warnTo = helper.warnTo;
12952
12963
  });
12953
12964
  var require_client = __commonJS((exports, module) => {
12954
- var EventEmitter = __require("events").EventEmitter;
12965
+ var EventEmitter = __require2("events").EventEmitter;
12955
12966
  var utils = require_utils();
12956
- var nodeUtils = __require("util");
12967
+ var nodeUtils = __require2("util");
12957
12968
  var sasl = require_sasl();
12958
12969
  var TypeOverrides = require_type_overrides();
12959
12970
  var ConnectionParameters = require_connection_parameters();
@@ -13530,7 +13541,7 @@ var require_client = __commonJS((exports, module) => {
13530
13541
  module.exports = Client;
13531
13542
  });
13532
13543
  var require_pg_pool = __commonJS((exports, module) => {
13533
- var EventEmitter = __require("events").EventEmitter;
13544
+ var EventEmitter = __require2("events").EventEmitter;
13534
13545
  var NOOP = function() {};
13535
13546
  var removeWhere = (list, predicate) => {
13536
13547
  const i = list.findIndex(predicate);
@@ -13940,8 +13951,8 @@ var require_pg_pool = __commonJS((exports, module) => {
13940
13951
  module.exports = Pool;
13941
13952
  });
13942
13953
  var require_query2 = __commonJS((exports, module) => {
13943
- var EventEmitter = __require("events").EventEmitter;
13944
- var util = __require("util");
13954
+ var EventEmitter = __require2("events").EventEmitter;
13955
+ var util = __require2("util");
13945
13956
  var utils = require_utils();
13946
13957
  var NativeQuery = module.exports = function(config, values, callback) {
13947
13958
  EventEmitter.call(this);
@@ -14074,7 +14085,7 @@ var require_query2 = __commonJS((exports, module) => {
14074
14085
  };
14075
14086
  });
14076
14087
  var require_client2 = __commonJS((exports, module) => {
14077
- var nodeUtils = __require("util");
14088
+ var nodeUtils = __require2("util");
14078
14089
  var Native;
14079
14090
  try {
14080
14091
  Native = (() => {
@@ -14084,8 +14095,8 @@ var require_client2 = __commonJS((exports, module) => {
14084
14095
  throw e;
14085
14096
  }
14086
14097
  var TypeOverrides = require_type_overrides();
14087
- var EventEmitter = __require("events").EventEmitter;
14088
- var util = __require("util");
14098
+ var EventEmitter = __require2("events").EventEmitter;
14099
+ var util = __require2("util");
14089
14100
  var ConnectionParameters = require_connection_parameters();
14090
14101
  var NativeQuery = require_query2();
14091
14102
  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.");
@@ -18579,6 +18590,7 @@ function getDb() {
18579
18590
  total_tokens_in INTEGER NOT NULL DEFAULT 0,
18580
18591
  total_tokens_out INTEGER NOT NULL DEFAULT 0,
18581
18592
  total_duration_ms INTEGER NOT NULL DEFAULT 0,
18593
+ tags TEXT,
18582
18594
  error TEXT,
18583
18595
  created_at TEXT NOT NULL,
18584
18596
  completed_at TEXT
@@ -18634,9 +18646,9 @@ function getDb() {
18634
18646
  async function createSession(session) {
18635
18647
  const d = getDb();
18636
18648
  d.prepare(`
18637
- INSERT INTO sessions (id, task, provider, model, status, steps, total_tokens_in, total_tokens_out, total_duration_ms, error, created_at, completed_at)
18638
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
18639
- `).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);
18649
+ INSERT INTO sessions (id, task, provider, model, status, steps, total_tokens_in, total_tokens_out, total_duration_ms, tags, error, created_at, completed_at)
18650
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
18651
+ `).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);
18640
18652
  }
18641
18653
  async function updateSession(session) {
18642
18654
  const d = getDb();
@@ -18664,10 +18676,18 @@ function listSessions(opts) {
18664
18676
  const d = getDb();
18665
18677
  let sql = "SELECT * FROM sessions";
18666
18678
  const params = [];
18679
+ const conditions = [];
18667
18680
  if (opts?.status) {
18668
- sql += " WHERE status = ?";
18681
+ conditions.push("status = ?");
18669
18682
  params.push(opts.status);
18670
18683
  }
18684
+ if (opts?.tag) {
18685
+ conditions.push("tags LIKE ?");
18686
+ params.push(`%"${opts.tag}"%`);
18687
+ }
18688
+ if (conditions.length > 0) {
18689
+ sql += " WHERE " + conditions.join(" AND ");
18690
+ }
18671
18691
  sql += " ORDER BY created_at DESC";
18672
18692
  if (opts?.limit) {
18673
18693
  sql += " LIMIT ?";
@@ -18768,12 +18788,104 @@ function rowToSession(row) {
18768
18788
  total_tokens_in: row.total_tokens_in,
18769
18789
  total_tokens_out: row.total_tokens_out,
18770
18790
  total_duration_ms: row.total_duration_ms,
18791
+ tags: row.tags ? JSON.parse(row.tags) : undefined,
18771
18792
  error: row.error,
18772
18793
  created_at: row.created_at,
18773
18794
  completed_at: row.completed_at
18774
18795
  };
18775
18796
  }
18776
18797
 
18798
+ // src/lib/integrations.ts
18799
+ async function saveToRecordings(session, logs) {
18800
+ try {
18801
+ const { saveRecording } = await import("@hasna/recordings");
18802
+ await saveRecording({
18803
+ title: `Computer Use: ${session.task.slice(0, 100)}`,
18804
+ type: "computer-use",
18805
+ source: "computer",
18806
+ duration_ms: session.total_duration_ms,
18807
+ metadata: {
18808
+ session_id: session.id,
18809
+ provider: session.provider,
18810
+ model: session.model,
18811
+ steps: session.steps,
18812
+ tokens_in: session.total_tokens_in,
18813
+ tokens_out: session.total_tokens_out,
18814
+ status: session.status,
18815
+ tags: session.tags
18816
+ },
18817
+ transcript: logs.map((l) => ({
18818
+ step: l.step,
18819
+ action: l.action.type,
18820
+ reasoning: l.reasoning?.slice(0, 200),
18821
+ success: l.success,
18822
+ timestamp: l.created_at
18823
+ }))
18824
+ });
18825
+ return true;
18826
+ } catch {
18827
+ return false;
18828
+ }
18829
+ }
18830
+ async function registerWithSessions(session) {
18831
+ try {
18832
+ const mod = await import("@hasna/sessions");
18833
+ const registerSession = mod.registerSession ?? mod.createSession ?? mod.saveSession;
18834
+ if (typeof registerSession !== "function")
18835
+ return false;
18836
+ await registerSession({
18837
+ id: session.id,
18838
+ type: "computer-use",
18839
+ source: "computer",
18840
+ status: session.status,
18841
+ metadata: {
18842
+ task: session.task,
18843
+ provider: session.provider,
18844
+ model: session.model,
18845
+ steps: session.steps
18846
+ },
18847
+ started_at: session.created_at,
18848
+ ended_at: session.completed_at
18849
+ });
18850
+ return true;
18851
+ } catch {
18852
+ return false;
18853
+ }
18854
+ }
18855
+ async function pushToLogs(session, logs) {
18856
+ try {
18857
+ const mod = await import("@hasna/logs");
18858
+ const pushBatch = mod.logPushBatch ?? mod.pushBatch;
18859
+ if (typeof pushBatch !== "function")
18860
+ return false;
18861
+ await pushBatch(logs.map((l) => ({
18862
+ level: l.success ? "info" : "error",
18863
+ source: "computer",
18864
+ message: `[${l.action.type}] ${l.reasoning?.slice(0, 100) ?? ""}`,
18865
+ metadata: {
18866
+ session_id: session.id,
18867
+ step: l.step,
18868
+ action_type: l.action.type,
18869
+ success: l.success,
18870
+ error: l.error,
18871
+ duration_ms: l.duration_ms
18872
+ },
18873
+ timestamp: l.created_at
18874
+ })));
18875
+ return true;
18876
+ } catch {
18877
+ return false;
18878
+ }
18879
+ }
18880
+ async function runPostSessionIntegrations(session, logs) {
18881
+ const [recordings, sessions, logsPushed] = await Promise.all([
18882
+ saveToRecordings(session, logs),
18883
+ registerWithSessions(session),
18884
+ pushToLogs(session, logs)
18885
+ ]);
18886
+ return { recordings, sessions, logs: logsPushed };
18887
+ }
18888
+
18777
18889
  // src/agent/loop.ts
18778
18890
  var DEFAULT_MAX_STEPS = 50;
18779
18891
  async function runTask(options) {
@@ -18787,10 +18899,12 @@ async function runTask(options) {
18787
18899
  systemPrompt,
18788
18900
  screenshotMaxWidth,
18789
18901
  dryRun = false,
18902
+ tags,
18903
+ displayNumber,
18790
18904
  onStep,
18791
18905
  onDone
18792
18906
  } = options;
18793
- const driver = createMacDriver();
18907
+ const driver = createMacDriver({ displayNumber });
18794
18908
  const provider = createProvider(providerName, { model });
18795
18909
  const config = loadConfig();
18796
18910
  const safetyConfig = config.safety;
@@ -18801,6 +18915,7 @@ async function runTask(options) {
18801
18915
  provider: providerName,
18802
18916
  model: model ?? (providerName === "anthropic" ? "claude-sonnet-4-5-20250514" : "computer-use-preview"),
18803
18917
  status: "running",
18918
+ tags,
18804
18919
  steps: 0,
18805
18920
  total_tokens_in: 0,
18806
18921
  total_tokens_out: 0,
@@ -18853,6 +18968,8 @@ async function runTask(options) {
18853
18968
  });
18854
18969
  await updateSession(session);
18855
18970
  onStep?.(step, response, { success: true, duration_ms: 0 });
18971
+ const logs = getActionLogs(sessionId);
18972
+ await runPostSessionIntegrations(session, logs).catch(() => {});
18856
18973
  onDone?.(session);
18857
18974
  await driver.dispose();
18858
18975
  return session;
@@ -18918,6 +19035,8 @@ async function runTask(options) {
18918
19035
  session.completed_at = new Date().toISOString();
18919
19036
  session.error = `Reached max steps (${maxSteps})`;
18920
19037
  await updateSession(session);
19038
+ const endLogs = getActionLogs(sessionId);
19039
+ await runPostSessionIntegrations(session, endLogs).catch(() => {});
18921
19040
  onDone?.(session);
18922
19041
  await driver.dispose();
18923
19042
  return session;
@@ -18927,6 +19046,8 @@ async function runTask(options) {
18927
19046
  session.total_duration_ms = Date.now() - startTime;
18928
19047
  session.completed_at = new Date().toISOString();
18929
19048
  await updateSession(session);
19049
+ const errLogs = getActionLogs(sessionId);
19050
+ await runPostSessionIntegrations(session, errLogs).catch(() => {});
18930
19051
  onDone?.(session);
18931
19052
  await driver.dispose();
18932
19053
  return session;
@@ -18953,6 +19074,152 @@ function remapCoordinates(action, from, to) {
18953
19074
  break;
18954
19075
  }
18955
19076
  }
19077
+ // src/drivers/mac/accessibility.ts
19078
+ import { join as join6, dirname as dirname2 } from "path";
19079
+ import { existsSync as existsSync4 } from "fs";
19080
+ import { fileURLToPath as fileURLToPath2 } from "url";
19081
+ async function queryAccessibilityTree(opts) {
19082
+ const helperPath = getAccessibilityHelperPath();
19083
+ const args = [helperPath];
19084
+ if (opts?.app) {
19085
+ args.push("--app", opts.app);
19086
+ }
19087
+ if (opts?.focusedOnly) {
19088
+ args.push("--focused");
19089
+ }
19090
+ if (opts?.depth !== undefined) {
19091
+ args.push("--depth", String(opts.depth));
19092
+ }
19093
+ const proc = Bun.spawn(args, {
19094
+ stdout: "pipe",
19095
+ stderr: "pipe"
19096
+ });
19097
+ await proc.exited;
19098
+ if (proc.exitCode !== 0) {
19099
+ const stderr = await new Response(proc.stderr).text();
19100
+ throw new Error(`accessibility query failed: ${stderr}`);
19101
+ }
19102
+ const stdout = await new Response(proc.stdout).text();
19103
+ try {
19104
+ return JSON.parse(stdout);
19105
+ } catch {
19106
+ return [];
19107
+ }
19108
+ }
19109
+ function summarizeAccessibilityTree(elements) {
19110
+ if (elements.length === 0)
19111
+ return "No accessibility information available.";
19112
+ const lines = ["UI Elements:"];
19113
+ for (const el of elements) {
19114
+ const parts = [];
19115
+ if (el.role)
19116
+ parts.push(el.role);
19117
+ if (el.title)
19118
+ parts.push(`"${el.title}"`);
19119
+ if (el.label)
19120
+ parts.push(`(${el.label})`);
19121
+ if (el.value)
19122
+ parts.push(`value="${el.value}"`);
19123
+ const pos = `at (${el.x + Math.round(el.width / 2)}, ${el.y + Math.round(el.height / 2)})`;
19124
+ const size = `${el.width}x${el.height}`;
19125
+ const flags = [];
19126
+ if (!el.enabled)
19127
+ flags.push("disabled");
19128
+ if (el.focused)
19129
+ flags.push("focused");
19130
+ lines.push(` - ${parts.join(" ")} ${pos} [${size}]${flags.length ? ` (${flags.join(", ")})` : ""}`);
19131
+ }
19132
+ return lines.join(`
19133
+ `);
19134
+ }
19135
+ var _helperPath = null;
19136
+ function getAccessibilityHelperPath() {
19137
+ if (_helperPath)
19138
+ return _helperPath;
19139
+ const candidates = [
19140
+ join6(dirname2(fileURLToPath2(import.meta.url)), "..", "..", "..", "helpers", "accessibility"),
19141
+ join6(dirname2(fileURLToPath2(import.meta.url)), "..", "helpers", "accessibility"),
19142
+ join6(process.env.HOME ?? "~", ".hasna", "computer", "helpers", "accessibility")
19143
+ ];
19144
+ for (const candidate of candidates) {
19145
+ if (existsSync4(candidate)) {
19146
+ _helperPath = candidate;
19147
+ return candidate;
19148
+ }
19149
+ }
19150
+ throw new Error("Accessibility helper not found. Run `swiftc helpers/accessibility.swift -o helpers/accessibility -framework AppKit` from the project root.");
19151
+ }
19152
+ // src/db/agents.ts
19153
+ function ensureAgentsTable() {
19154
+ const d = getDb();
19155
+ d.exec(`
19156
+ CREATE TABLE IF NOT EXISTS agents (
19157
+ id TEXT PRIMARY KEY,
19158
+ name TEXT NOT NULL UNIQUE,
19159
+ description TEXT,
19160
+ capabilities TEXT,
19161
+ focus TEXT,
19162
+ last_heartbeat TEXT NOT NULL,
19163
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
19164
+ );
19165
+ `);
19166
+ }
19167
+ function registerAgent(agent) {
19168
+ ensureAgentsTable();
19169
+ const d = getDb();
19170
+ const now = new Date().toISOString();
19171
+ const id = agent.name;
19172
+ const existing = d.prepare("SELECT * FROM agents WHERE name = ?").get(agent.name);
19173
+ if (existing) {
19174
+ d.prepare(`
19175
+ UPDATE agents SET description = ?, capabilities = ?, last_heartbeat = ?
19176
+ WHERE name = ?
19177
+ `).run(agent.description ?? existing.description, agent.capabilities ? JSON.stringify(agent.capabilities) : existing.capabilities, now, agent.name);
19178
+ } else {
19179
+ d.prepare(`
19180
+ INSERT INTO agents (id, name, description, capabilities, last_heartbeat, created_at)
19181
+ VALUES (?, ?, ?, ?, ?, ?)
19182
+ `).run(id, agent.name, agent.description ?? null, agent.capabilities ? JSON.stringify(agent.capabilities) : null, now, now);
19183
+ }
19184
+ return getAgent(id);
19185
+ }
19186
+ function heartbeat(agentId) {
19187
+ ensureAgentsTable();
19188
+ const d = getDb();
19189
+ const result = d.prepare("UPDATE agents SET last_heartbeat = ? WHERE id = ?").run(new Date().toISOString(), agentId);
19190
+ return result.changes > 0;
19191
+ }
19192
+ function setFocus(agentId, focus) {
19193
+ ensureAgentsTable();
19194
+ const d = getDb();
19195
+ const result = d.prepare("UPDATE agents SET focus = ? WHERE id = ?").run(focus, agentId);
19196
+ return result.changes > 0;
19197
+ }
19198
+ function getAgent(id) {
19199
+ ensureAgentsTable();
19200
+ const d = getDb();
19201
+ const row = d.prepare("SELECT * FROM agents WHERE id = ?").get(id);
19202
+ if (!row)
19203
+ return null;
19204
+ return rowToAgent(row);
19205
+ }
19206
+ function listAgents() {
19207
+ ensureAgentsTable();
19208
+ const d = getDb();
19209
+ const rows = d.prepare("SELECT * FROM agents ORDER BY last_heartbeat DESC").all();
19210
+ return rows.map(rowToAgent);
19211
+ }
19212
+ function rowToAgent(row) {
19213
+ return {
19214
+ id: row.id,
19215
+ name: row.name,
19216
+ description: row.description,
19217
+ capabilities: row.capabilities ? JSON.parse(row.capabilities) : undefined,
19218
+ focus: row.focus,
19219
+ last_heartbeat: row.last_heartbeat,
19220
+ created_at: row.created_at
19221
+ };
19222
+ }
18956
19223
  // src/lib/pricing.ts
18957
19224
  var MODEL_PRICING = {
18958
19225
  "claude-sonnet-4-5-20250514": { input: 3, output: 15 },
@@ -18997,22 +19264,88 @@ function findPricing(model) {
18997
19264
  function listPricing() {
18998
19265
  return { ...MODEL_PRICING };
18999
19266
  }
19267
+ // src/lib/terminal-image.ts
19268
+ function detectProtocol() {
19269
+ const term = process.env.TERM_PROGRAM ?? "";
19270
+ const termInfo = process.env.TERM ?? "";
19271
+ if (term === "iTerm.app" || term === "WezTerm") {
19272
+ return "iterm2";
19273
+ }
19274
+ if (termInfo.includes("kitty") || process.env.KITTY_PID) {
19275
+ return "kitty";
19276
+ }
19277
+ return "none";
19278
+ }
19279
+ function renderInlineImage(base64, opts) {
19280
+ const protocol = detectProtocol();
19281
+ const width = opts?.width ?? 40;
19282
+ const height = opts?.height ?? 15;
19283
+ switch (protocol) {
19284
+ case "iterm2":
19285
+ return renderIterm2(base64, width, height, opts?.preserveAspectRatio ?? true);
19286
+ case "kitty":
19287
+ return renderKitty(base64, width, height);
19288
+ case "none":
19289
+ return "";
19290
+ }
19291
+ }
19292
+ function supportsInlineImages() {
19293
+ return detectProtocol() !== "none";
19294
+ }
19295
+ function renderIterm2(base64, width, height, preserveAspectRatio) {
19296
+ const params = [
19297
+ `width=${width}`,
19298
+ `height=${height}`,
19299
+ `preserveAspectRatio=${preserveAspectRatio ? 1 : 0}`,
19300
+ "inline=1"
19301
+ ].join(";");
19302
+ return `\x1B]1337;File=${params}:${base64}\x07
19303
+ `;
19304
+ }
19305
+ function renderKitty(base64, width, height) {
19306
+ const chunkSize = 4096;
19307
+ const chunks = [];
19308
+ for (let i = 0;i < base64.length; i += chunkSize) {
19309
+ const chunk = base64.slice(i, i + chunkSize);
19310
+ const isLast = i + chunkSize >= base64.length;
19311
+ const more = isLast ? 0 : 1;
19312
+ if (i === 0) {
19313
+ chunks.push(`\x1B_Gf=100,a=T,m=${more},c=${width},r=${height};${chunk}\x1B\\`);
19314
+ } else {
19315
+ chunks.push(`\x1B_Gm=${more};${chunk}\x1B\\`);
19316
+ }
19317
+ }
19318
+ return chunks.join("") + `
19319
+ `;
19320
+ }
19000
19321
  export {
19001
19322
  updateSession,
19323
+ supportsInlineImages,
19324
+ summarizeAccessibilityTree,
19002
19325
  stepCost,
19326
+ setFocus,
19003
19327
  setConfigValue,
19004
19328
  searchSessions,
19005
19329
  searchActionLogs,
19006
19330
  screenshotsMatch,
19007
19331
  scaleScreenshot,
19332
+ saveToRecordings,
19008
19333
  saveScreenshotToFile,
19009
19334
  saveConfig,
19010
19335
  runTask,
19336
+ runPostSessionIntegrations,
19011
19337
  resetRateLimiter,
19338
+ renderInlineImage,
19339
+ registerWithSessions,
19340
+ registerAgent,
19341
+ queryAccessibilityTree,
19342
+ pushToLogs,
19012
19343
  logAction,
19013
19344
  loadConfig,
19014
19345
  listSessions,
19015
19346
  listPricing,
19347
+ listAgents,
19348
+ heartbeat,
19016
19349
  getStats,
19017
19350
  getSession,
19018
19351
  getScreenSize,
@@ -19020,9 +19353,11 @@ export {
19020
19353
  getDb,
19021
19354
  getConfigValue,
19022
19355
  getConfigPath,
19356
+ getAgent,
19023
19357
  getActionLogs,
19024
19358
  formatCost,
19025
19359
  executeAction,
19360
+ detectProtocol,
19026
19361
  deleteSession,
19027
19362
  createSession,
19028
19363
  createProvider,