tesseract-agent 0.9.6 → 0.9.7

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.
Files changed (2) hide show
  1. package/dist-bundle/cli.js +126 -35
  2. package/package.json +1 -1
@@ -22752,13 +22752,13 @@ Add it to an EDL as an audio track (duckUnderSpeech:true under speech).`);
22752
22752
  return text6(`Speech generated: ${res.file.path}
22753
22753
  Overlay it in render_edl as an audio track (mute the original speaker's segments to replace their voice).`);
22754
22754
  }),
22755
- tool7("list_avatars", "List the HeyGen avatars available on the user's account (for virtual-presenter videos), with their avatar ids. Key-gated: needs a HeyGen API key. Pair an avatar_id with a HeyGen voice for generate_avatar_video.", {}, async () => {
22755
+ tool7("list_avatars", "List the HeyGen avatars available for virtual-presenter videos, with their avatar ids. Works on the free bundled tier when signed in, or on the user's own HeyGen key if they set one. Pair an avatar_id with a HeyGen voice for generate_avatar_video.", {}, async () => {
22756
22756
  const res = await deps.listAvatars();
22757
22757
  if (!res.ok)
22758
22758
  return text6(`Could not list avatars: ${res.error ?? "unknown error"}`, true);
22759
22759
  return jsonText(res.avatars ?? []);
22760
22760
  }),
22761
- tool7("generate_avatar_video", "Generate a talking-presenter (avatar) video from a script (HeyGen \u2014 paid, needs a HeyGen key). Draft the script yourself; pick an avatar via list_avatars and a HeyGen voice_id. Takes 1\u20135 minutes; the finished video is displayed in the chat. Use for news-desk reads, explainers, spokesperson clips. ONLY use avatars/likenesses you are authorized to use.", {
22761
+ tool7("generate_avatar_video", "Generate a talking-presenter (avatar) video from a script (HeyGen). Runs on the free bundled tier when signed in, or on the user's own HeyGen key if they set one \u2014 they never need to be asked for a key up front. Draft the script yourself; pick an avatar via list_avatars and a HeyGen voice_id. Takes 1\u20135 minutes; the finished video is displayed in the chat. Use for news-desk reads, explainers, spokesperson clips. ONLY use avatars/likenesses you are authorized to use.", {
22762
22762
  script: external_exports.string().describe("What the presenter says."),
22763
22763
  avatar_id: external_exports.string().optional().describe("HeyGen avatar id (from list_avatars). Provide this OR talking_photo_id."),
22764
22764
  talking_photo_id: external_exports.string().optional().describe("HeyGen talking-photo id (alternative to avatar_id)."),
@@ -24266,6 +24266,13 @@ ${JSON.stringify(r, null, 2)}`
24266
24266
  // ── image (image-generation/edit providers) ──
24267
24267
  { id: "image.list_providers", domain: "image", title: "List image providers", description: "Image providers with configured/default/model status.", input: external_exports.object({}), mutation: "read", availability: "host", binding: { kind: "ipc", channel: "imageEdit", verb: "list" } },
24268
24268
  { id: "image.set_provider_key", domain: "image", title: "Set image provider key", description: "Set (blank clears) an image provider's API key.", input: external_exports.object({ provider_id: IMAGE_PROVIDER, api_key: external_exports.string().describe("API key (secret); blank clears.") }), mutation: "write", availability: "host", binding: { kind: "ipc", channel: "imageEdit", verb: "setKey" } },
24269
+ // Avatar videos are the one media provider whose key lives outside the image pool
24270
+ // (HeyGen, its own vendor) — but it is set in the SAME Settings panel, so it belongs
24271
+ // to the same domain rather than earning a domain of its own. `has_` returns a
24272
+ // boolean, never the key: writing a secret in is a capability, reading one out is
24273
+ // not (the same line `auth:token` sits on the wrong side of).
24274
+ { id: "image.set_avatar_key", domain: "image", title: "Set avatar-video (HeyGen) key", description: "Set (blank clears) the HeyGen API key used for avatar/presenter videos. Without one, avatar videos fall back to the free Tesseract proxy tier for signed-in users.", input: external_exports.object({ api_key: external_exports.string().describe("HeyGen API key (secret); blank clears.") }), mutation: "write", availability: "host", binding: { kind: "ipc", channel: "heygen", verb: "setKey" } },
24275
+ { id: "image.has_avatar_key", domain: "image", title: "Avatar-video key configured?", description: "Whether a personal HeyGen key is set. Never returns the key itself.", input: external_exports.object({}), mutation: "read", availability: "host", binding: { kind: "ipc", channel: "heygen", verb: "hasKey" } },
24269
24276
  { id: "image.remove_provider_key", domain: "image", title: "Remove image provider key", description: "Remove all credentials for an image provider.", input: external_exports.object({ provider_id: IMAGE_PROVIDER }), mutation: "write", availability: "host", binding: { kind: "ipc", channel: "imageEdit", verb: "removeKey" } },
24270
24277
  { id: "image.set_default_provider", domain: "image", title: "Set default image provider", description: "Set the default image provider.", input: external_exports.object({ provider_id: IMAGE_PROVIDER }), mutation: "write", availability: "host", binding: { kind: "ipc", channel: "imageEdit", verb: "setDefault" } },
24271
24278
  { id: "image.set_provider_model", domain: "image", title: "Set image provider model", description: "Set the model for an image provider.", input: external_exports.object({ provider_id: IMAGE_PROVIDER, model: external_exports.string() }), mutation: "write", availability: "host", binding: { kind: "ipc", channel: "imageEdit", verb: "setModel" } },
@@ -66328,16 +66335,17 @@ async function listVoicesElevenLabs(cfg2, opts) {
66328
66335
  }
66329
66336
 
66330
66337
  // ../../packages/video-core/dist/heygen.js
66331
- var BASE_URL2 = "https://api.heygen.com";
66338
+ var HEYGEN_DIRECT_BASE_URL = "https://api.heygen.com";
66332
66339
  var DEFAULT_DIM = { width: 1280, height: 720 };
66333
66340
  var HG_REQUEST_TIMEOUT_MS = 6e4;
66334
66341
  var HG_DOWNLOAD_TIMEOUT_MS = 18e4;
66335
- async function hgFetch(path6, apiKey, init, signal) {
66342
+ async function hgFetch(path6, cfg2, init, signal) {
66343
+ const base = (cfg2.baseUrl || HEYGEN_DIRECT_BASE_URL).replace(/\/+$/, "");
66336
66344
  let res;
66337
66345
  try {
66338
- res = await fetch(`${BASE_URL2}${path6}`, {
66346
+ res = await fetch(`${base}${path6}`, {
66339
66347
  method: init.method,
66340
- headers: { "X-Api-Key": apiKey, ...init.body != null ? { "Content-Type": "application/json" } : {} },
66348
+ headers: { "X-Api-Key": cfg2.apiKey, ...init.body != null ? { "Content-Type": "application/json" } : {} },
66341
66349
  ...init.body != null ? { body: JSON.stringify(init.body) } : {},
66342
66350
  signal: signal ?? AbortSignal.timeout(HG_REQUEST_TIMEOUT_MS)
66343
66351
  });
@@ -66354,7 +66362,7 @@ async function hgFetch(path6, apiKey, init, signal) {
66354
66362
  return json2;
66355
66363
  }
66356
66364
  async function listAvatarsHeyGen(cfg2, signal) {
66357
- const j = await hgFetch("/v2/avatars", cfg2.apiKey, { method: "GET" }, signal);
66365
+ const j = await hgFetch("/v2/avatars", cfg2, { method: "GET" }, signal);
66358
66366
  return (j.data?.avatars ?? []).map((a) => ({ avatarId: a.avatar_id, name: a.avatar_name ?? a.avatar_id }));
66359
66367
  }
66360
66368
  async function submitAvatarVideoHeyGen(spec, cfg2, signal) {
@@ -66371,14 +66379,14 @@ async function submitAvatarVideoHeyGen(spec, cfg2, signal) {
66371
66379
  ],
66372
66380
  dimension: { width: spec.width ?? DEFAULT_DIM.width, height: spec.height ?? DEFAULT_DIM.height }
66373
66381
  };
66374
- const j = await hgFetch("/v2/video/generate", cfg2.apiKey, { method: "POST", body }, signal);
66382
+ const j = await hgFetch("/v2/video/generate", cfg2, { method: "POST", body }, signal);
66375
66383
  const id = j.data?.video_id;
66376
66384
  if (!id)
66377
66385
  throw new Error("HeyGen returned no video_id.");
66378
66386
  return id;
66379
66387
  }
66380
66388
  async function pollAvatarVideoHeyGen(videoId, cfg2, signal) {
66381
- const j = await hgFetch(`/v1/video_status.get?video_id=${encodeURIComponent(videoId)}`, cfg2.apiKey, { method: "GET" }, signal);
66389
+ const j = await hgFetch(`/v1/video_status.get?video_id=${encodeURIComponent(videoId)}`, cfg2, { method: "GET" }, signal);
66382
66390
  const d = j.data ?? {};
66383
66391
  const error51 = typeof d.error === "string" ? d.error : d.error?.message;
66384
66392
  return { status: d.status ?? "processing", videoUrl: d.video_url, error: error51 };
@@ -67662,13 +67670,13 @@ ${inputs.prompt}` : "");
67662
67670
 
67663
67671
  // ../../packages/host-core/dist/video-transcribe.js
67664
67672
  var DEFAULT_MODEL5 = "gemini-3.5-flash";
67665
- var BASE_URL3 = "https://generativelanguage.googleapis.com/v1beta";
67673
+ var BASE_URL2 = "https://generativelanguage.googleapis.com/v1beta";
67666
67674
  var CHUNK_PROMPT = `Transcribe this audio VERBATIM with speaker diarization.
67667
67675
  Return ONLY a JSON array; each element: {"start": <seconds from the START OF THIS AUDIO, number>, "end": <seconds, number>, "speaker": "<S1|S2|S3\u2026, stable within this audio>", "text": "<utterance>"}.
67668
67676
  Rules: keep the original language(s); split on speaker changes and natural sentence boundaries (segments \u2264 15s); timecodes must be accurate to the second; no commentary, no markdown.`;
67669
67677
  var REQUEST_TIMEOUT_MS3 = 18e4;
67670
67678
  async function geminiJson(opts) {
67671
- const res = await fetch(`${BASE_URL3}/models/${encodeURIComponent(opts.model)}:generateContent`, {
67679
+ const res = await fetch(`${BASE_URL2}/models/${encodeURIComponent(opts.model)}:generateContent`, {
67672
67680
  method: "POST",
67673
67681
  headers: { "Content-Type": "application/json", "x-goog-api-key": opts.apiKey },
67674
67682
  body: JSON.stringify({
@@ -67774,14 +67782,14 @@ ${compact2}`;
67774
67782
 
67775
67783
  // ../../packages/host-core/dist/video-vision.js
67776
67784
  import { readFileSync as readFileSync19 } from "node:fs";
67777
- var BASE_URL4 = "https://generativelanguage.googleapis.com/v1beta";
67785
+ var BASE_URL3 = "https://generativelanguage.googleapis.com/v1beta";
67778
67786
  var MODEL = "gemini-3.5-flash";
67779
67787
  var TIMEOUT_MS = 6e4;
67780
67788
  async function reviewFrameGemini(framePath, intent, apiKey) {
67781
67789
  try {
67782
67790
  const b642 = readFileSync19(framePath).toString("base64");
67783
67791
  const prompt = `This is a frame from an AI-generated video clip meant to show: "${intent}". Judge ONLY for obvious defects: melted/warped faces or hands, garbled text, broken anatomy, severe artifacts. Reply with STRICT JSON: {"acceptable": <true|false>, "note": "<\u226412 words, only if not acceptable>"}.`;
67784
- const res = await fetch(`${BASE_URL4}/models/${MODEL}:generateContent`, {
67792
+ const res = await fetch(`${BASE_URL3}/models/${MODEL}:generateContent`, {
67785
67793
  method: "POST",
67786
67794
  headers: { "Content-Type": "application/json", "x-goog-api-key": apiKey },
67787
67795
  body: JSON.stringify({
@@ -67809,9 +67817,19 @@ function googleKey() {
67809
67817
  function elevenLabsKey() {
67810
67818
  return readDaemonAgentSettings().voiceKeys?.elevenlabs?.trim() || null;
67811
67819
  }
67812
- function heygenKey() {
67813
- return readDaemonAgentSettings().heygenApiKey?.trim() || readDaemonKeyFile("heygen.key") || process.env.HEYGEN_API_KEY?.trim() || null;
67820
+ function resolveAvatarCreds(snap, keyFile, envKey2) {
67821
+ const fromSnapshot = (snap.heygen?.baseUrl ? void 0 : snap.heygen?.apiKey?.trim()) || snap.heygenApiKey?.trim();
67822
+ const personal = fromSnapshot || keyFile?.trim() || envKey2?.trim();
67823
+ if (personal)
67824
+ return { apiKey: personal };
67825
+ if (snap.heygen?.baseUrl && snap.heygen.apiKey)
67826
+ return { apiKey: snap.heygen.apiKey, baseUrl: snap.heygen.baseUrl };
67827
+ return null;
67828
+ }
67829
+ function heygenCreds() {
67830
+ return resolveAvatarCreds(readDaemonAgentSettings(), readDaemonKeyFile("heygen.key"), process.env.HEYGEN_API_KEY ?? null);
67814
67831
  }
67832
+ var NO_AVATAR_CREDS = "Avatar videos need either a HeyGen API key (add it in Settings, or set HEYGEN_API_KEY) or a signed-in Tesseract account for the free tier.";
67815
67833
  function readDaemonKeyFile(name) {
67816
67834
  try {
67817
67835
  const home = tesseractHome();
@@ -67984,21 +68002,21 @@ function createDaemonVideoEditRunner() {
67984
68002
  }
67985
68003
  },
67986
68004
  async listAvatars() {
67987
- const apiKey = heygenKey();
67988
- if (!apiKey)
67989
- return { ok: false, error: "Avatar videos need a HeyGen API key (set HEYGEN_API_KEY or add it in settings)." };
68005
+ const creds3 = heygenCreds();
68006
+ if (!creds3)
68007
+ return { ok: false, error: NO_AVATAR_CREDS };
67990
68008
  try {
67991
- return { ok: true, avatars: await listAvatarsHeyGen({ apiKey }) };
68009
+ return { ok: true, avatars: await listAvatarsHeyGen(creds3) };
67992
68010
  } catch (e) {
67993
68011
  return { ok: false, error: err(e) };
67994
68012
  }
67995
68013
  },
67996
68014
  async generateAvatarVideo(req, outDir, onProgress) {
67997
- const apiKey = heygenKey();
67998
- if (!apiKey)
67999
- return { ok: false, error: "Avatar videos need a HeyGen API key (set HEYGEN_API_KEY or add it in settings)." };
68015
+ const creds3 = heygenCreds();
68016
+ if (!creds3)
68017
+ return { ok: false, error: NO_AVATAR_CREDS };
68000
68018
  try {
68001
- const videoId = await submitAvatarVideoHeyGen({ avatarId: req.avatarId, talkingPhotoId: req.talkingPhotoId, text: req.text, voiceId: req.voiceId, width: req.width, height: req.height, background: req.background }, { apiKey });
68019
+ const videoId = await submitAvatarVideoHeyGen({ avatarId: req.avatarId, talkingPhotoId: req.talkingPhotoId, text: req.text, voiceId: req.voiceId, width: req.width, height: req.height, background: req.background }, creds3);
68002
68020
  onProgress?.("Avatar video submitted \u2014 rendering\u2026");
68003
68021
  const started = Date.now();
68004
68022
  for (; ; ) {
@@ -68007,7 +68025,7 @@ function createDaemonVideoEditRunner() {
68007
68025
  await new Promise((r) => setTimeout(r, HEYGEN_POLL_MS));
68008
68026
  let poll;
68009
68027
  try {
68010
- poll = await pollAvatarVideoHeyGen(videoId, { apiKey });
68028
+ poll = await pollAvatarVideoHeyGen(videoId, creds3);
68011
68029
  } catch {
68012
68030
  onProgress?.(`Rendering avatar video\u2026 (${Math.round((Date.now() - started) / 1e3)}s)`);
68013
68031
  continue;
@@ -81930,25 +81948,38 @@ async function runDaemon(opts = {}) {
81930
81948
  }
81931
81949
  async function takeoverMachine() {
81932
81950
  const rivals = /* @__PURE__ */ new Set();
81951
+ let lockPid = 0, statusPid = 0;
81952
+ const otherPids = [];
81933
81953
  try {
81934
- const lp = Number(readFileSync30(pidfile(), "utf-8").trim());
81935
- if (lp > 0)
81936
- rivals.add(lp);
81954
+ lockPid = Number(readFileSync30(pidfile(), "utf-8").trim());
81955
+ if (lockPid > 0)
81956
+ rivals.add(lockPid);
81937
81957
  } catch {
81938
81958
  }
81939
81959
  try {
81940
- const sp = Number(JSON.parse(readFileSync30(statusFile(), "utf-8")).pid ?? 0);
81941
- if (sp > 0)
81942
- rivals.add(sp);
81960
+ statusPid = Number(JSON.parse(readFileSync30(statusFile(), "utf-8")).pid ?? 0);
81961
+ if (statusPid > 0)
81962
+ rivals.add(statusPid);
81943
81963
  } catch {
81944
81964
  }
81945
- for (const p of otherDaemonPids())
81965
+ for (const p of otherDaemonPids()) {
81966
+ otherPids.push(p);
81946
81967
  rivals.add(p);
81968
+ }
81969
+ try {
81970
+ log9(`takeover: me=${process.pid} lockPid=${lockPid || "-"} statusPid=${statusPid || "-"} otherDaemonPids=[${otherPids.join(",") || "-"}]`);
81971
+ } catch {
81972
+ }
81947
81973
  rivals.delete(process.pid);
81948
81974
  const live = [...rivals].filter(isAlive2);
81949
81975
  if (live.length) {
81950
81976
  for (const pid of live) {
81951
- log9(`takeover: killing rival daemon pid=${pid} (latest-wins single-instance)`);
81977
+ let cmd = "";
81978
+ try {
81979
+ cmd = execFileSync4("ps", ["-o", "command=", "-p", String(pid)], { encoding: "utf8", timeout: 2e3 }).trim().slice(0, 200);
81980
+ } catch {
81981
+ }
81982
+ log9(`takeover: killing rival daemon pid=${pid} (latest-wins single-instance) cmd=[${cmd}]`);
81952
81983
  try {
81953
81984
  process.kill(pid, "SIGTERM");
81954
81985
  } catch {
@@ -82007,9 +82038,30 @@ async function runDaemon(opts = {}) {
82007
82038
  const creds3 = readCredentials();
82008
82039
  const deviceId2 = creds3?.deviceId;
82009
82040
  const daemonStartedAt = Date.now();
82041
+ try {
82042
+ const pp = process;
82043
+ log9(`LAUNCH-CTX pid=${pp.pid} ppid=${pp.ppid} exec=${pp.execPath}`);
82044
+ log9(`LAUNCH-CTX argv=${JSON.stringify(pp.argv)}`);
82045
+ log9(`LAUNCH-CTX env: GUI=${process.env.CCB_DAEMON_GUI ?? "-"} FORCE_GUI=${process.env.CCB_FORCE_DAEMON_GUI ?? "-"} RUN_AS_NODE=${process.env.ELECTRON_RUN_AS_NODE ?? "-"} UNMANAGED=${process.env.CCB_DAEMON_UNMANAGED ?? "-"} ACTIVE_LINK=${process.env.CCB_ACTIVE_LINK ?? "-"} RDESK=${process.env.CCB_RDESK_ROLE ?? "-"}`);
82046
+ } catch {
82047
+ }
82048
+ const snapshotProcs = (tag) => {
82049
+ try {
82050
+ const raw = execFileSync4("ps", ["-axww", "-o", "pid=,ppid=,pcpu=,etime=,command="], { encoding: "utf8", timeout: 3e3 });
82051
+ const rows = raw.split("\n").filter((l) => /[Tt]esseract|host-daemon/.test(l) && !/\bgrep\b|ps -axww/.test(l));
82052
+ log9(`PROC-SNAPSHOT [${tag}] me=${process.pid} ppid=${process.ppid} \u2014 ${rows.length} tesseract proc(s):`);
82053
+ for (const r of rows.slice(0, 40))
82054
+ log9(` PROC ${r.trim().slice(0, 240)}`);
82055
+ } catch (e) {
82056
+ try {
82057
+ log9(`PROC-SNAPSHOT [${tag}] ps failed: ${e.message}`);
82058
+ } catch {
82059
+ }
82060
+ }
82061
+ };
82010
82062
  process.on("exit", (code) => {
82011
82063
  try {
82012
- log9(`PROCESS EXIT code=${code} uptimeMs=${Date.now() - daemonStartedAt}`);
82064
+ log9(`PROCESS EXIT code=${code} uptimeMs=${Date.now() - daemonStartedAt} ppid=${process.ppid}`);
82013
82065
  } catch {
82014
82066
  }
82015
82067
  });
@@ -82017,6 +82069,8 @@ async function runDaemon(opts = {}) {
82017
82069
  try {
82018
82070
  log9(`SHUTDOWN reason=${reason} code=${code} uptimeMs=${Date.now() - daemonStartedAt} ppid=${process.ppid} pid=${process.pid}`);
82019
82071
  log9(`SHUTDOWN caller: ${(new Error("shutdown").stack ?? "").split("\n").slice(2, 7).map((l) => l.trim()).join(" <- ")}`);
82072
+ if (reason.startsWith("signal"))
82073
+ snapshotProcs(reason);
82020
82074
  } catch {
82021
82075
  }
82022
82076
  if (timer) {
@@ -82047,6 +82101,16 @@ async function runDaemon(opts = {}) {
82047
82101
  }
82048
82102
  process.on("SIGTERM", () => shutdown(0, "signal:SIGTERM"));
82049
82103
  process.on("SIGINT", () => shutdown(0, "signal:SIGINT"));
82104
+ try {
82105
+ process.on("SIGHUP", () => {
82106
+ try {
82107
+ log9("SIGHUP received \u2014 IGNORED (kept alive)");
82108
+ snapshotProcs("SIGHUP");
82109
+ } catch {
82110
+ }
82111
+ });
82112
+ } catch {
82113
+ }
82050
82114
  process.on("uncaughtException", (e) => {
82051
82115
  try {
82052
82116
  log9(`UNCAUGHT (kept alive): ${e instanceof Error ? e.stack ?? e.message : String(e)}`);
@@ -82067,6 +82131,7 @@ async function runDaemon(opts = {}) {
82067
82131
  eapp.on("before-quit", (e) => {
82068
82132
  try {
82069
82133
  log9("APP before-quit \u2014 PREVENTED (daemon never self-quits via Electron)");
82134
+ snapshotProcs("before-quit");
82070
82135
  } catch {
82071
82136
  }
82072
82137
  try {
@@ -82074,15 +82139,41 @@ async function runDaemon(opts = {}) {
82074
82139
  } catch {
82075
82140
  }
82076
82141
  });
82142
+ eapp.on("will-quit", (e) => {
82143
+ try {
82144
+ log9(`APP will-quit \u2014 PREVENTED (uptime ${Date.now() - daemonStartedAt}ms)`);
82145
+ e?.preventDefault?.();
82146
+ } catch {
82147
+ }
82148
+ });
82149
+ eapp.on("quit", (_e, code) => {
82150
+ try {
82151
+ log9(`APP quit event code=${JSON.stringify(code)} (uptime ${Date.now() - daemonStartedAt}ms)`);
82152
+ } catch {
82153
+ }
82154
+ });
82155
+ eapp.on("window-all-closed", () => {
82156
+ try {
82157
+ log9("APP window-all-closed (kept alive \u2014 no auto-quit)");
82158
+ } catch {
82159
+ }
82160
+ });
82077
82161
  eapp.on("render-process-gone", (_e, d) => {
82078
82162
  try {
82079
- log9(`render-process-gone (kept alive): ${JSON.stringify(d)}`);
82163
+ log9(`render-process-gone (kept alive) uptime=${Date.now() - daemonStartedAt}ms: ${JSON.stringify(d)}`);
82164
+ snapshotProcs("render-gone");
82080
82165
  } catch {
82081
82166
  }
82082
82167
  });
82083
82168
  eapp.on("child-process-gone", (_e, d) => {
82084
82169
  try {
82085
- log9(`child-process-gone (kept alive): ${JSON.stringify(d)}`);
82170
+ log9(`child-process-gone (kept alive) uptime=${Date.now() - daemonStartedAt}ms: ${JSON.stringify(d)}`);
82171
+ } catch {
82172
+ }
82173
+ });
82174
+ eapp.on("gpu-process-crashed", (_e, killed) => {
82175
+ try {
82176
+ log9(`gpu-process-crashed killed=${JSON.stringify(killed)} uptime=${Date.now() - daemonStartedAt}ms`);
82086
82177
  } catch {
82087
82178
  }
82088
82179
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tesseract-agent",
3
- "version": "0.9.6",
3
+ "version": "0.9.7",
4
4
  "license": "UNLICENSED",
5
5
  "publishConfig": {
6
6
  "access": "public",