@turmind/halo 2.0.3 → 2.0.5

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
@@ -15857,7 +15857,7 @@ async function initObservability(haloProcess = "server") {
15857
15857
  return true;
15858
15858
  }
15859
15859
  const { registerSdk: registerSdk2 } = await Promise.resolve().then(() => (init_otel_sdk(), otel_sdk_exports));
15860
- providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.0.3", haloProcess);
15860
+ providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.0.5", haloProcess);
15861
15861
  console.log(`[Observability] OTLP export \u2192 ${process.env.OTEL_EXPORTER_OTLP_ENDPOINT} (service.name=${process.env.OTEL_SERVICE_NAME}, halo.process=${haloProcess}, capture_content=${config.observability.captureContent})`);
15862
15862
  return true;
15863
15863
  }
@@ -28141,6 +28141,37 @@ function classifyTranscribeError(err) {
28141
28141
  return "bad-request";
28142
28142
  return "io";
28143
28143
  }
28144
+ function splitBySpeaker(text6, start3, end, items) {
28145
+ const counts = /* @__PURE__ */ new Map();
28146
+ for (const i of items)
28147
+ if (i.Type === "pronunciation" && i.Speaker !== void 0)
28148
+ counts.set(i.Speaker, (counts.get(i.Speaker) ?? 0) + 1);
28149
+ if (counts.size === 0)
28150
+ return [{ text: text6, start: start3, end }];
28151
+ if (counts.size === 1)
28152
+ return [{ text: text6, start: start3, end, speaker: [...counts.keys()][0] }];
28153
+ const runs = [];
28154
+ let cursor = 0;
28155
+ for (const item of items) {
28156
+ const content = item.Content ?? "";
28157
+ const at = text6.indexOf(content, cursor);
28158
+ if (at < 0) {
28159
+ let top = "";
28160
+ for (const [s, n] of counts)
28161
+ if (n > (counts.get(top) ?? 0))
28162
+ top = s;
28163
+ return [{ text: text6, start: start3, end, speaker: top }];
28164
+ }
28165
+ cursor = at + content.length;
28166
+ const run = runs.at(-1);
28167
+ if (item.Type === "pronunciation" && item.Speaker !== void 0 && item.Speaker !== run?.speaker) {
28168
+ runs.push({ at: run ? at : 0, speaker: item.Speaker, start: (run ? item : items[0]).StartTime ?? start3, end: item.EndTime ?? end });
28169
+ } else if (run) {
28170
+ run.end = item.EndTime ?? run.end;
28171
+ }
28172
+ }
28173
+ return runs.map((r, k) => ({ text: text6.slice(r.at, runs[k + 1]?.at ?? text6.length).trim(), start: r.start, end: r.end, speaker: r.speaker })).filter((s) => s.text);
28174
+ }
28144
28175
  function extParam(extId, key, fallback) {
28145
28176
  const declared = getExtension(extId)?.settings?.params?.find((f) => f.key === key)?.default;
28146
28177
  return getServerParam(`ext-${extId}`, key) || declared || fallback;
@@ -28275,20 +28306,24 @@ function createTranscribeProxy(deps = {}) {
28275
28306
  ...languageOpts,
28276
28307
  MediaEncoding: "pcm",
28277
28308
  MediaSampleRateHertz: 16e3,
28309
+ ShowSpeakerLabel: true,
28278
28310
  AudioStream: audio()
28279
28311
  }), { abortSignal: abort.signal });
28280
28312
  for await (const ev of res.TranscriptResultStream ?? []) {
28281
28313
  for (const r of ev.TranscriptEvent?.Transcript?.Results ?? []) {
28282
- const text6 = r.Alternatives?.[0]?.Transcript ?? "";
28314
+ const alt = r.Alternatives?.[0];
28315
+ const text6 = alt?.Transcript ?? "";
28283
28316
  if (!text6)
28284
28317
  continue;
28285
- send2({
28286
- type: r.IsPartial ? "partial" : "final",
28287
- start: r.StartTime ?? 0,
28288
- end: r.EndTime ?? 0,
28289
- text: text6,
28290
- lang: r.LanguageCode ?? ("code" in langSpec ? langSpec.code : "")
28291
- });
28318
+ const start3 = r.StartTime ?? 0;
28319
+ const end = r.EndTime ?? 0;
28320
+ const lang2 = r.LanguageCode ?? ("code" in langSpec ? langSpec.code : "");
28321
+ if (r.IsPartial) {
28322
+ send2({ type: "partial", start: start3, end, text: text6, lang: lang2 });
28323
+ continue;
28324
+ }
28325
+ for (const s of splitBySpeaker(text6, start3, end, alt?.Items ?? []))
28326
+ send2({ type: "final", ...s, lang: lang2 });
28292
28327
  }
28293
28328
  }
28294
28329
  if (!closed)
@@ -30966,7 +31001,7 @@ function buildCard(workspace, interfaceUrl, caps) {
30966
31001
  return {
30967
31002
  name: raw.name,
30968
31003
  description: raw.description,
30969
- version: typeof raw.version === "string" ? raw.version : "2.0.3",
31004
+ version: typeof raw.version === "string" ? raw.version : "2.0.5",
30970
31005
  supportedInterfaces: [{ url: interfaceUrl, protocolBinding: "JSONRPC", protocolVersion: A2A_VERSION }],
30971
31006
  capabilities: { streaming: caps.streaming, pushNotifications: true, extendedAgentCard: false },
30972
31007
  ...caps.tokenAuth === false ? {} : {
@@ -33725,7 +33760,7 @@ function createCoreChecker(opts) {
33725
33760
  }
33726
33761
  function getCoreStatus(force) {
33727
33762
  checker ??= createCoreChecker({
33728
- haloVersion: "2.0.3",
33763
+ haloVersion: "2.0.5",
33729
33764
  fetchLatest: fetchNpmLatest,
33730
33765
  onChange: (status) => broadcast({ type: "updates:changed", scope: "core", status })
33731
33766
  });
@@ -33893,7 +33928,7 @@ function hubBase() {
33893
33928
  }
33894
33929
  function serverChecker() {
33895
33930
  checker2 ??= createExtensionsChecker({
33896
- haloVersion: "2.0.3",
33931
+ haloVersion: "2.0.5",
33897
33932
  installed: () => {
33898
33933
  const s = getSnapshot();
33899
33934
  return [...s.extensions, ...s.disabled];
@@ -34592,29 +34627,48 @@ var init_ticker = __esm({
34592
34627
  });
34593
34628
 
34594
34629
  // ../server/dist/evolution/spawn.js
34630
+ import fs75 from "node:fs";
34595
34631
  import path83 from "node:path";
34596
34632
  import { spawn as spawn5 } from "node:child_process";
34597
34633
  import { fileURLToPath as fileURLToPath2 } from "node:url";
34634
+ function spawnEvoWrapper(wrapperPath, mode, id) {
34635
+ fs75.mkdirSync(evoLogsDir(), { recursive: true });
34636
+ const logPath = mode === "run" ? evoWrapperLogFile(id) : evoApplyLogFile(id);
34637
+ const logFd = fs75.openSync(logPath, "a");
34638
+ let child;
34639
+ try {
34640
+ child = spawn5(process.execPath, [wrapperPath, `--mode=${mode}`, `--id=${id}`], {
34641
+ detached: true,
34642
+ stdio: ["ignore", "ignore", logFd],
34643
+ env: cleanChildEnv(),
34644
+ // Without this, a detached console process on Windows gets a freshly
34645
+ // allocated console window (a black box pops up for every evo/score/apply
34646
+ // run). cron doesn't hit this — it spawns the cli inline, not via a
34647
+ // detached wrapper. No-op on macOS/Linux.
34648
+ windowsHide: true
34649
+ });
34650
+ } finally {
34651
+ fs75.closeSync(logFd);
34652
+ }
34653
+ child.once("exit", (code, signal) => {
34654
+ if (code === 0)
34655
+ return;
34656
+ console.error(`[EvoSpawn] ${mode} wrapper pid=${child.pid} id=${id} exited code=${code} signal=${signal} \u2014 see ${logPath}`);
34657
+ });
34658
+ child.unref();
34659
+ console.log(`[EvoSpawn] launched ${mode} wrapper pid=${child.pid} id=${id}`);
34660
+ return child;
34661
+ }
34598
34662
  var __dirname2, WRAPPER_PATH, realEvoSpawner;
34599
34663
  var init_spawn = __esm({
34600
34664
  "../server/dist/evolution/spawn.js"() {
34601
34665
  "use strict";
34602
34666
  init_child_env();
34667
+ init_paths();
34603
34668
  __dirname2 = path83.dirname(fileURLToPath2(import.meta.url));
34604
34669
  WRAPPER_PATH = path83.resolve(__dirname2, "evo-wrapper.js");
34605
34670
  realEvoSpawner = (mode, id) => {
34606
- const child = spawn5(process.execPath, [WRAPPER_PATH, `--mode=${mode}`, `--id=${id}`], {
34607
- detached: true,
34608
- stdio: "ignore",
34609
- env: cleanChildEnv(),
34610
- // Without this, a detached console process on Windows gets a freshly
34611
- // allocated console window (a black box pops up for every evo/score/apply
34612
- // run). cron doesn't hit this — it spawns the cli inline, not via a
34613
- // detached wrapper. No-op on macOS/Linux.
34614
- windowsHide: true
34615
- });
34616
- child.unref();
34617
- console.log(`[EvoSpawn] launched ${mode} wrapper pid=${child.pid} id=${id}`);
34671
+ spawnEvoWrapper(WRAPPER_PATH, mode, id);
34618
34672
  };
34619
34673
  }
34620
34674
  });
@@ -35432,12 +35486,12 @@ var init_handler3 = __esm({
35432
35486
  });
35433
35487
 
35434
35488
  // ../server/dist/routes/channel-accounts.js
35435
- import fs75 from "node:fs";
35489
+ import fs76 from "node:fs";
35436
35490
  function accountListFields(a) {
35437
35491
  return {
35438
35492
  accountId: a.accountId,
35439
35493
  workspacePath: a.workspacePath,
35440
- workspaceMissing: !fs75.existsSync(a.workspacePath),
35494
+ workspaceMissing: !fs76.existsSync(a.workspacePath),
35441
35495
  label: a.label,
35442
35496
  enabled: a.enabled,
35443
35497
  accessLevel: a.accessLevel,
@@ -36079,7 +36133,7 @@ var init_cdn = __esm({
36079
36133
  });
36080
36134
 
36081
36135
  // ../server/dist/channels/wechat/send-media.js
36082
- import fs76 from "node:fs/promises";
36136
+ import fs77 from "node:fs/promises";
36083
36137
  import path84 from "node:path";
36084
36138
  function inferKind(filePath) {
36085
36139
  const cls = classifyMedia(filePath);
@@ -36092,7 +36146,7 @@ function inferKind(filePath) {
36092
36146
  async function sendMediaFile(params) {
36093
36147
  const { baseUrl, token, toUserId, contextToken, contextTokenAt, filePath } = params;
36094
36148
  const kind = params.kind ?? inferKind(filePath);
36095
- const plaintext = await fs76.readFile(filePath);
36149
+ const plaintext = await fs77.readFile(filePath);
36096
36150
  const prep = prepareUpload(plaintext);
36097
36151
  console.log(`[WeChat] sendMediaFile: path=${filePath} kind=${kind} rawsize=${prep.rawsize} filesize=${prep.filesize}`);
36098
36152
  const mediaType = kind === "image" ? UploadMediaType.IMAGE : kind === "video" ? UploadMediaType.VIDEO : UploadMediaType.FILE;
@@ -36293,7 +36347,7 @@ var init_login = __esm({
36293
36347
  });
36294
36348
 
36295
36349
  // ../server/dist/channels/wechat/handler.js
36296
- import fs77 from "node:fs";
36350
+ import fs78 from "node:fs";
36297
36351
  import path85 from "node:path";
36298
36352
  import QRCode from "qrcode";
36299
36353
  function wxRoute(fromUserId, contextToken, contextTokenAt) {
@@ -36724,7 +36778,7 @@ async function handleSlashCommand(args) {
36724
36778
  contextToken,
36725
36779
  filePath: tmpPath
36726
36780
  });
36727
- await fs77.promises.unlink(tmpPath).catch(() => {
36781
+ await fs78.promises.unlink(tmpPath).catch(() => {
36728
36782
  });
36729
36783
  await reply(t("wechat.qr_sent", lang, { level, path: account.workspacePath }));
36730
36784
  waitLogin({ sessionKey: login.sessionKey }).then(async (result2) => {
@@ -36805,7 +36859,7 @@ var init_handler4 = __esm({
36805
36859
  // ../server/dist/routes/wechat.js
36806
36860
  import { Hono as Hono22 } from "hono";
36807
36861
  import path86 from "node:path";
36808
- import fs78 from "node:fs";
36862
+ import fs79 from "node:fs";
36809
36863
  function createWechatRoutes(deps) {
36810
36864
  const { db: db4, channel } = deps;
36811
36865
  const app2 = new Hono22();
@@ -36814,7 +36868,7 @@ function createWechatRoutes(deps) {
36814
36868
  return {
36815
36869
  ...stripSecrets(acc),
36816
36870
  workspacePath: acc.workspacePath,
36817
- workspaceMissing: !fs78.existsSync(acc.workspacePath)
36871
+ workspaceMissing: !fs79.existsSync(acc.workspacePath)
36818
36872
  };
36819
36873
  });
36820
36874
  return c.json({ accounts });
@@ -37043,7 +37097,7 @@ var init_descriptor2 = __esm({
37043
37097
  import { Hono as Hono23 } from "hono";
37044
37098
  import { streamSSE as streamSSE3 } from "hono/streaming";
37045
37099
  import crypto12 from "node:crypto";
37046
- import fs79 from "node:fs";
37100
+ import fs80 from "node:fs";
37047
37101
  function streamWithKeepalive(c, chunks) {
37048
37102
  return streamSSE3(c, async (stream) => {
37049
37103
  const timer2 = setInterval(() => {
@@ -37248,8 +37302,8 @@ function createWebRoutes(deps) {
37248
37302
  let real;
37249
37303
  let realRoot;
37250
37304
  try {
37251
- real = fs79.realpathSync(resolved);
37252
- realRoot = fs79.realpathSync(root);
37305
+ real = fs80.realpathSync(resolved);
37306
+ realRoot = fs80.realpathSync(root);
37253
37307
  } catch {
37254
37308
  return c.json({ error: "file not found" }, 404);
37255
37309
  }
@@ -37259,7 +37313,7 @@ function createWebRoutes(deps) {
37259
37313
  if (isHiddenWorkspacePath(real, realRoot)) {
37260
37314
  return c.json({ error: "path is not accessible" }, 403);
37261
37315
  }
37262
- const stat = fs79.statSync(real);
37316
+ const stat = fs80.statSync(real);
37263
37317
  if (stat.isDirectory())
37264
37318
  return c.json({ error: "cannot serve directory" }, 400);
37265
37319
  const ext = path94.default.extname(real).toLowerCase();
@@ -37271,7 +37325,7 @@ function createWebRoutes(deps) {
37271
37325
  };
37272
37326
  const contentType = imageMimeFromExt(ext) || nonImageMimes[ext] || "application/octet-stream";
37273
37327
  const fileName = path94.default.basename(resolved);
37274
- const data = fs79.readFileSync(real);
37328
+ const data = fs80.readFileSync(real);
37275
37329
  c.header("content-type", contentType);
37276
37330
  c.header("content-disposition", `inline; filename="${fileName}"`);
37277
37331
  return c.body(data);
@@ -37493,10 +37547,10 @@ async function authTest(botToken) {
37493
37547
  return slackPost("auth.test", botToken, {});
37494
37548
  }
37495
37549
  async function uploadFile(args) {
37496
- const fs84 = await import("node:fs");
37550
+ const fs85 = await import("node:fs");
37497
37551
  const path94 = await import("node:path");
37498
37552
  const filename = args.filename ?? path94.basename(args.filePath);
37499
- const stat = fs84.statSync(args.filePath);
37553
+ const stat = fs85.statSync(args.filePath);
37500
37554
  if (!stat.isFile())
37501
37555
  throw new Error(`[slack:uploadFile] not a regular file: ${args.filePath}`);
37502
37556
  const length = stat.size;
@@ -37514,7 +37568,7 @@ async function uploadFile(args) {
37514
37568
  if (step1Parsed.ok === false || !step1Parsed.upload_url || !step1Parsed.file_id) {
37515
37569
  throw new Error(`[slack:files.getUploadURLExternal] ${step1Parsed.error ?? "unknown"}`);
37516
37570
  }
37517
- const buf = fs84.readFileSync(args.filePath);
37571
+ const buf = fs85.readFileSync(args.filePath);
37518
37572
  const step2 = await fetch(step1Parsed.upload_url, {
37519
37573
  method: "POST",
37520
37574
  body: buf
@@ -38434,9 +38488,9 @@ async function replyMessage(args) {
38434
38488
  return { message_id: parsed.data?.message_id ?? "" };
38435
38489
  }
38436
38490
  async function uploadImage(args) {
38437
- const fs84 = await import("node:fs");
38491
+ const fs85 = await import("node:fs");
38438
38492
  const path94 = await import("node:path");
38439
- const buf = fs84.readFileSync(args.filePath);
38493
+ const buf = fs85.readFileSync(args.filePath);
38440
38494
  const filename = path94.basename(args.filePath);
38441
38495
  const send2 = async (token) => {
38442
38496
  const form = new FormData();
@@ -38453,9 +38507,9 @@ async function uploadImage(args) {
38453
38507
  return { imageKey: parsed.data.image_key };
38454
38508
  }
38455
38509
  async function uploadFile2(args) {
38456
- const fs84 = await import("node:fs");
38510
+ const fs85 = await import("node:fs");
38457
38511
  const path94 = await import("node:path");
38458
- const buf = fs84.readFileSync(args.filePath);
38512
+ const buf = fs85.readFileSync(args.filePath);
38459
38513
  const filename = args.filename ?? path94.basename(args.filePath);
38460
38514
  const send2 = async (token) => {
38461
38515
  const form = new FormData();
@@ -39289,7 +39343,7 @@ var init_event_adapter5 = __esm({
39289
39343
 
39290
39344
  // ../server/dist/channels/wecom/handler.js
39291
39345
  import path89 from "node:path";
39292
- import fs80 from "node:fs/promises";
39346
+ import fs81 from "node:fs/promises";
39293
39347
  import { WSClient as WSClient2, generateReqId } from "@wecom/aibot-node-sdk";
39294
39348
  function pickConversation(body) {
39295
39349
  const userid = body.from?.userid ?? "unknown";
@@ -39415,7 +39469,7 @@ async function sendWecomMedia(args) {
39415
39469
  const ext = path89.extname(filePath).toLowerCase();
39416
39470
  const cls = classifyMedia(filePath);
39417
39471
  const type = cls === "image" && [".png", ".jpg", ".jpeg", ".gif"].includes(ext) ? "image" : cls === "video" && ext === ".mp4" ? "video" : "file";
39418
- const buf = await fs80.readFile(filePath);
39472
+ const buf = await fs81.readFile(filePath);
39419
39473
  if (buf.length > MAX_WECOM_DOWNLOAD_BYTES)
39420
39474
  throw new Error("file exceeds 20MB");
39421
39475
  const { media_id: mediaId } = await wsClient.uploadMedia(buf, { type, filename: path89.basename(filePath) });
@@ -39952,14 +40006,14 @@ import { serve } from "@hono/node-server";
39952
40006
  import { serveStatic } from "@hono/node-server/serve-static";
39953
40007
  import { WebSocketServer as WebSocketServer4 } from "ws";
39954
40008
  import path90 from "node:path";
39955
- import fs81 from "node:fs";
40009
+ import fs82 from "node:fs";
39956
40010
  import { spawnSync as spawnSync4 } from "node:child_process";
39957
40011
  import { homedir as homedir25 } from "node:os";
39958
40012
  import { fileURLToPath as fileURLToPath3 } from "node:url";
39959
40013
  function findProjectRoot() {
39960
40014
  let dir = process.cwd();
39961
40015
  for (let i = 0; i < 32; i++) {
39962
- if (fs81.existsSync(path90.join(dir, "pnpm-workspace.yaml")))
40016
+ if (fs82.existsSync(path90.join(dir, "pnpm-workspace.yaml")))
39963
40017
  return dir;
39964
40018
  const parent = path90.dirname(dir);
39965
40019
  if (parent === dir)
@@ -39971,15 +40025,15 @@ function findProjectRoot() {
39971
40025
  return process.cwd();
39972
40026
  }
39973
40027
  function acquireSingleInstanceLock(lockFile) {
39974
- fs81.mkdirSync(path90.dirname(lockFile), { recursive: true });
39975
- const fd = fs81.openSync(lockFile, fs81.constants.O_RDWR | fs81.constants.O_CREAT, 420);
40028
+ fs82.mkdirSync(path90.dirname(lockFile), { recursive: true });
40029
+ const fd = fs82.openSync(lockFile, fs82.constants.O_RDWR | fs82.constants.O_CREAT, 420);
39976
40030
  const result = spawnSync4("flock", ["-n", "3"], {
39977
40031
  stdio: ["ignore", "ignore", "ignore", fd]
39978
40032
  });
39979
40033
  if (result.error) {
39980
40034
  const content = readLockPid(fd);
39981
40035
  if (content > 0 && isProcessAlive(content)) {
39982
- fs81.closeSync(fd);
40036
+ fs82.closeSync(fd);
39983
40037
  console.error(`[Server] another halo server is already running (pid ${content}). kill it first.`);
39984
40038
  process.exit(1);
39985
40039
  }
@@ -39988,19 +40042,19 @@ function acquireSingleInstanceLock(lockFile) {
39988
40042
  if (content > 0 && !isProcessAlive(content)) {
39989
40043
  console.warn(`[Server] removing stale server.lock (pid ${content} not running)`);
39990
40044
  } else {
39991
- fs81.closeSync(fd);
40045
+ fs82.closeSync(fd);
39992
40046
  console.error(`[Server] another halo server is already running${content > 0 ? ` (pid ${content})` : ""}. kill it first.`);
39993
40047
  process.exit(1);
39994
40048
  }
39995
40049
  }
39996
- fs81.ftruncateSync(fd);
39997
- fs81.writeSync(fd, String(process.pid));
39998
- fs81.fsyncSync(fd);
40050
+ fs82.ftruncateSync(fd);
40051
+ fs82.writeSync(fd, String(process.pid));
40052
+ fs82.fsyncSync(fd);
39999
40053
  }
40000
40054
  function readLockPid(fd) {
40001
40055
  try {
40002
40056
  const buf = Buffer.alloc(32);
40003
- const n = fs81.readSync(fd, buf, 0, 32, 0);
40057
+ const n = fs82.readSync(fd, buf, 0, 32, 0);
40004
40058
  return parseInt(buf.subarray(0, n).toString("utf-8").trim(), 10) || 0;
40005
40059
  } catch {
40006
40060
  return 0;
@@ -40028,7 +40082,7 @@ function isProcessAlive(pid) {
40028
40082
  }
40029
40083
  }
40030
40084
  function readGitSha() {
40031
- if (!fs81.existsSync(path90.join(PROJECT_ROOT, "pnpm-workspace.yaml")) || !fs81.existsSync(path90.join(PROJECT_ROOT, ".git")))
40085
+ if (!fs82.existsSync(path90.join(PROJECT_ROOT, "pnpm-workspace.yaml")) || !fs82.existsSync(path90.join(PROJECT_ROOT, ".git")))
40032
40086
  return null;
40033
40087
  try {
40034
40088
  const rev = spawnSync4("git", ["rev-parse", "--short", "HEAD"], { cwd: PROJECT_ROOT, encoding: "utf-8" });
@@ -40051,10 +40105,10 @@ function resolveFrontendDir() {
40051
40105
  if (process.env.HALO_FRONTEND_DIR)
40052
40106
  return path90.resolve(process.env.HALO_FRONTEND_DIR);
40053
40107
  const bundled = path90.resolve(__dirname3, "..", "admin-out");
40054
- if (fs81.existsSync(path90.join(bundled, "index.html")))
40108
+ if (fs82.existsSync(path90.join(bundled, "index.html")))
40055
40109
  return bundled;
40056
40110
  const sibling = path90.resolve(__dirname3, "..", "..", "admin", "out");
40057
- if (fs81.existsSync(path90.join(sibling, "index.html")))
40111
+ if (fs82.existsSync(path90.join(sibling, "index.html")))
40058
40112
  return sibling;
40059
40113
  return path90.resolve(PROJECT_ROOT, "packages", "admin", "out");
40060
40114
  }
@@ -40159,11 +40213,11 @@ var init_dist2 = __esm({
40159
40213
  init_git_ssh();
40160
40214
  __dirname3 = path90.dirname(fileURLToPath3(import.meta.url));
40161
40215
  PORT = config.server.port;
40162
- HALO_VERSION = "2.0.3";
40216
+ HALO_VERSION = "2.0.5";
40163
40217
  PROJECT_ROOT = findProjectRoot();
40164
40218
  HALO_HOME4 = path90.join(homedir25(), ".halo");
40165
40219
  GIT_SHA = readGitSha();
40166
- if (!fs81.existsSync(path90.join(HALO_HOME4, "global", ".template-version"))) {
40220
+ if (!fs82.existsSync(path90.join(HALO_HOME4, "global", ".template-version"))) {
40167
40221
  process.stderr.write("\x1B[31m[Server] ~/.halo/global/ not initialized. Run `halo setup` first.\x1B[0m\n");
40168
40222
  process.exit(1);
40169
40223
  }
@@ -40265,7 +40319,7 @@ var init_dist2 = __esm({
40265
40319
  setCronSessionRegistry(registry);
40266
40320
  if (OWNS_RUNTIMES && !AGENTCORE) {
40267
40321
  for (const ws of listRunningWorkspaces()) {
40268
- if (!fs81.existsSync(path90.join(ws, ".halo")))
40322
+ if (!fs82.existsSync(path90.join(ws, ".halo")))
40269
40323
  continue;
40270
40324
  if (!claimWorkspaceRuntime(ws))
40271
40325
  continue;
@@ -40311,7 +40365,7 @@ var init_dist2 = __esm({
40311
40365
  app.get("/*", (c) => {
40312
40366
  const indexPath = path90.join(FRONTEND_DIR, "index.html");
40313
40367
  try {
40314
- const html = fs81.readFileSync(indexPath, "utf-8");
40368
+ const html = fs82.readFileSync(indexPath, "utf-8");
40315
40369
  return c.html(html);
40316
40370
  } catch {
40317
40371
  return c.text("Frontend not built. Run: cd packages/admin && npx next build", 503);
@@ -40399,7 +40453,7 @@ __export(agentcore_front_exports, {
40399
40453
  workerEnv: () => workerEnv
40400
40454
  });
40401
40455
  import http3 from "node:http";
40402
- import fs82 from "node:fs";
40456
+ import fs83 from "node:fs";
40403
40457
  import fsp2 from "node:fs/promises";
40404
40458
  import os11 from "node:os";
40405
40459
  import path91 from "node:path";
@@ -40430,39 +40484,39 @@ function skipTemplateEntry(rel) {
40430
40484
  }
40431
40485
  function chownTree(dir, owner, sid) {
40432
40486
  try {
40433
- fs82.lchownSync(dir, owner.uid, owner.gid);
40434
- for (const rel of fs82.readdirSync(dir, { recursive: true }))
40435
- fs82.lchownSync(path91.join(dir, rel), owner.uid, owner.gid);
40487
+ fs83.lchownSync(dir, owner.uid, owner.gid);
40488
+ for (const rel of fs83.readdirSync(dir, { recursive: true }))
40489
+ fs83.lchownSync(path91.join(dir, rel), owner.uid, owner.gid);
40436
40490
  } catch (err) {
40437
40491
  console.warn(`[AgentCore] front: chown ${sid} to ${owner.uid}:${owner.gid} failed (${err.message}) \u2014 serving it as is`);
40438
40492
  }
40439
40493
  }
40440
40494
  function ensureSessionDir(base, sid, owner) {
40441
40495
  const dir = path91.join(base, sid);
40442
- if (fs82.existsSync(dir))
40496
+ if (fs83.existsSync(dir))
40443
40497
  return false;
40444
40498
  const tmp = path91.join(base, `.tmp-${crypto13.randomBytes(8).toString("hex")}`);
40445
- fs82.mkdirSync(tmp, { mode: 448 });
40499
+ fs83.mkdirSync(tmp, { mode: 448 });
40446
40500
  try {
40447
40501
  const template = path91.join(base, TEMPLATE_DIR);
40448
- if (fs82.statSync(template, { throwIfNoEntry: false })?.isDirectory()) {
40449
- fs82.cpSync(template, tmp, { recursive: true, verbatimSymlinks: true, filter: (src) => !skipTemplateEntry(path91.relative(template, src)) });
40502
+ if (fs83.statSync(template, { throwIfNoEntry: false })?.isDirectory()) {
40503
+ fs83.cpSync(template, tmp, { recursive: true, verbatimSymlinks: true, filter: (src) => !skipTemplateEntry(path91.relative(template, src)) });
40450
40504
  }
40451
40505
  if (owner)
40452
40506
  chownTree(tmp, owner, sid);
40453
- if (fs82.readdirSync(tmp).length === 0) {
40454
- fs82.rmdirSync(tmp);
40455
- fs82.mkdirSync(dir, { mode: 448 });
40507
+ if (fs83.readdirSync(tmp).length === 0) {
40508
+ fs83.rmdirSync(tmp);
40509
+ fs83.mkdirSync(dir, { mode: 448 });
40456
40510
  if (owner)
40457
40511
  chownTree(dir, owner, sid);
40458
40512
  return true;
40459
40513
  }
40460
- fs82.renameSync(tmp, dir);
40514
+ fs83.renameSync(tmp, dir);
40461
40515
  return true;
40462
40516
  } catch (err) {
40463
- fs82.rmSync(tmp, { recursive: true, force: true });
40517
+ fs83.rmSync(tmp, { recursive: true, force: true });
40464
40518
  const code = err.code;
40465
- if ((code === "EEXIST" || code === "ENOTEMPTY") && fs82.existsSync(dir))
40519
+ if ((code === "EEXIST" || code === "ENOTEMPTY") && fs83.existsSync(dir))
40466
40520
  return false;
40467
40521
  throw err;
40468
40522
  }
@@ -40506,7 +40560,7 @@ async function runViewSetup(base, sessionDir, deps = SYSTEM_SETUP) {
40506
40560
  const left = mountLayers(base, deps.mountinfo());
40507
40561
  if (left > 0)
40508
40562
  throw new Error(`view setup: ${base} still has ${left} mount(s) after ${MAX_UMOUNTS} \xD7 umount -l`);
40509
- if (fs82.existsSync(sessionDir))
40563
+ if (fs83.existsSync(sessionDir))
40510
40564
  throw new Error(`view setup: ${base} is still visible after umount -l`);
40511
40565
  }
40512
40566
  function workerEnv(src, front) {
@@ -40525,15 +40579,15 @@ async function copyMediaFile(p, root, dest, max = MAX_MEDIA_BYTES) {
40525
40579
  return "not an absolute path";
40526
40580
  let pfd;
40527
40581
  try {
40528
- pfd = fs82.openSync(p, O_PATH);
40582
+ pfd = fs83.openSync(p, O_PATH);
40529
40583
  } catch (err) {
40530
40584
  return `cannot open (${err.code})`;
40531
40585
  }
40532
40586
  try {
40533
- const link = fs82.readlinkSync(`/proc/self/fd/${pfd}`);
40587
+ const link = fs83.readlinkSync(`/proc/self/fd/${pfd}`);
40534
40588
  if (!link.startsWith(`${root}/`))
40535
40589
  return `not under ${root}/`;
40536
- const st = fs82.fstatSync(pfd);
40590
+ const st = fs83.fstatSync(pfd);
40537
40591
  if (!st.isFile())
40538
40592
  return "not a regular file";
40539
40593
  if (st.size > max)
@@ -40560,7 +40614,7 @@ async function copyMediaFile(p, root, dest, max = MAX_MEDIA_BYTES) {
40560
40614
  await src.close();
40561
40615
  }
40562
40616
  } finally {
40563
- fs82.closeSync(pfd);
40617
+ fs83.closeSync(pfd);
40564
40618
  }
40565
40619
  }
40566
40620
  async function copyMediaLines(text6, root, dir, sid) {
@@ -40573,7 +40627,7 @@ async function copyMediaLines(text6, root, dir, sid) {
40573
40627
  continue;
40574
40628
  }
40575
40629
  const sub = path91.join(dir, String(n++));
40576
- fs82.mkdirSync(sub);
40630
+ fs83.mkdirSync(sub);
40577
40631
  const name = path91.basename(m[1]).replace(/[\x00-\x1f\x7f]/g, "_").replace(/^\.+/, "") || "file";
40578
40632
  const dest = path91.join(sub, name);
40579
40633
  const why = await copyMediaFile(m[1], root, dest).catch((err) => err.message);
@@ -40581,7 +40635,7 @@ async function copyMediaLines(text6, root, dir, sid) {
40581
40635
  out.push(`MEDIA:${dest}`);
40582
40636
  continue;
40583
40637
  }
40584
- fs82.rmSync(sub, { recursive: true, force: true });
40638
+ fs83.rmSync(sub, { recursive: true, force: true });
40585
40639
  console.warn(`[AgentCore] notify ${sid}: MEDIA dropped (${why}): ${JSON.stringify(m[1].slice(0, 300))}`);
40586
40640
  }
40587
40641
  return out.join("\n");
@@ -40625,7 +40679,7 @@ function readBody(req, max) {
40625
40679
  });
40626
40680
  }
40627
40681
  async function startAgentCoreFront(o) {
40628
- const base = fs82.realpathSync(o.base);
40682
+ const base = fs83.realpathSync(o.base);
40629
40683
  const workerPort = o.workerPort ?? WORKER_PORT;
40630
40684
  const token = crypto13.randomBytes(32).toString("hex");
40631
40685
  const isMounted = o.isMounted ?? ((b) => mountLayers(b, readMountinfo()) > 0);
@@ -40687,11 +40741,11 @@ async function startAgentCoreFront(o) {
40687
40741
  preparing++;
40688
40742
  let dir = "";
40689
40743
  const cleanup = () => {
40690
- fs82.rmSync(dir, { recursive: true, force: true });
40744
+ fs83.rmSync(dir, { recursive: true, force: true });
40691
40745
  settle();
40692
40746
  };
40693
40747
  try {
40694
- dir = fs82.mkdtempSync(path91.join(os11.tmpdir(), "halo-notify-"));
40748
+ dir = fs83.mkdtempSync(path91.join(os11.tmpdir(), "halo-notify-"));
40695
40749
  const text6 = await copyMediaLines(b.text, viewRoot, dir, b.session);
40696
40750
  runNotify(cmd, text6, { HALO_SESSION_ID: b.session, HALO_RUN_STATUS: b.status, HALO_WORKSPACE: dir }, dir, cleanup);
40697
40751
  } catch (err) {
@@ -40908,7 +40962,7 @@ var init_agentcore_front = __esm({
40908
40962
  MAX_MEDIA_BYTES = 20 * 1024 * 1024;
40909
40963
  O_PATH = 2097152;
40910
40964
  execFileP = promisify3(execFile2);
40911
- readMountinfo = () => fs82.readFileSync("/proc/self/mountinfo", "utf8");
40965
+ readMountinfo = () => fs83.readFileSync("/proc/self/mountinfo", "utf8");
40912
40966
  SYSTEM_SETUP = {
40913
40967
  mountinfo: readMountinfo,
40914
40968
  exec: (argv) => execFileP(argv[0], argv.slice(1), { timeout: SETUP_TIMEOUT_MS })
@@ -42046,7 +42100,7 @@ process.emitWarning = (warning, ...args) => {
42046
42100
  // src/index.ts
42047
42101
  init_server_supervisor();
42048
42102
  import path93 from "node:path";
42049
- import fs83 from "node:fs";
42103
+ import fs84 from "node:fs";
42050
42104
  import { homedir as homedir26, userInfo } from "node:os";
42051
42105
  import { parseArgs as parseArgs2 } from "node:util";
42052
42106
 
@@ -42337,7 +42391,7 @@ function installUserUnit(opts, run = runCommand) {
42337
42391
  }
42338
42392
 
42339
42393
  // src/index.ts
42340
- var VERSION = "2.0.3";
42394
+ var VERSION = "2.0.5";
42341
42395
  var HELP_TOP = `Usage: halo <command> [options]
42342
42396
 
42343
42397
  Commands:
@@ -43131,7 +43185,7 @@ ${HELP_SESSIONS}`);
43131
43185
  }
43132
43186
  }
43133
43187
  async function cmdSessionsMigrate(workspace) {
43134
- if (!fs83.existsSync(path93.join(workspace, ".halo"))) {
43188
+ if (!fs84.existsSync(path93.join(workspace, ".halo"))) {
43135
43189
  process.stderr.write(`Not a Halo workspace (no .halo/): ${workspace}
43136
43190
  `);
43137
43191
  process.exitCode = 1;
@@ -43276,7 +43330,7 @@ var SERVER_LOCK_PATH = path93.join(homedir26(), ".halo", "global", "server.lock"
43276
43330
  var SERVER_LOG_PATH = path93.join(homedir26(), ".halo", "logs", "server.log");
43277
43331
  function readServerPid() {
43278
43332
  try {
43279
- const txt = fs83.readFileSync(SERVER_LOCK_PATH, "utf-8").trim();
43333
+ const txt = fs84.readFileSync(SERVER_LOCK_PATH, "utf-8").trim();
43280
43334
  const n = parseInt(txt, 10);
43281
43335
  return Number.isFinite(n) && n > 0 ? n : null;
43282
43336
  } catch {
@@ -43383,8 +43437,8 @@ async function cmdServerStart(argv, restart) {
43383
43437
  }
43384
43438
  if (plan.note) writeDim(plan.note);
43385
43439
  const { spawn: spawn7 } = await import("node:child_process");
43386
- fs83.mkdirSync(path93.dirname(SERVER_LOG_PATH), { recursive: true });
43387
- const out = fs83.openSync(SERVER_LOG_PATH, "a");
43440
+ fs84.mkdirSync(path93.dirname(SERVER_LOG_PATH), { recursive: true });
43441
+ const out = fs84.openSync(SERVER_LOG_PATH, "a");
43388
43442
  const child = spawn7(process.argv[0], [process.argv[1], "server", "start"], {
43389
43443
  detached: true,
43390
43444
  stdio: ["ignore", out, out],
@@ -43466,7 +43520,7 @@ ${HELP_AGENTCORE}`);
43466
43520
  return;
43467
43521
  }
43468
43522
  const workspace = path93.resolve(raw);
43469
- if (!fs83.statSync(workspace, { throwIfNoEntry: false })?.isDirectory()) {
43523
+ if (!fs84.statSync(workspace, { throwIfNoEntry: false })?.isDirectory()) {
43470
43524
  process.stderr.write(`Workspace is not a directory: ${workspace}
43471
43525
  `);
43472
43526
  process.exitCode = 1;
@@ -43577,7 +43631,7 @@ async function cmdServerLogs(argv) {
43577
43631
  lines: { type: "string", short: "n" }
43578
43632
  }
43579
43633
  });
43580
- if (!fs83.existsSync(SERVER_LOG_PATH)) {
43634
+ if (!fs84.existsSync(SERVER_LOG_PATH)) {
43581
43635
  process.stderr.write(`No log file at ${SERVER_LOG_PATH}
43582
43636
  `);
43583
43637
  return;
@@ -43595,7 +43649,7 @@ function exitMissingSetup() {
43595
43649
  process.exit(1);
43596
43650
  }
43597
43651
  function isHaloHomeReady() {
43598
- return fs83.existsSync(path93.join(homedir26(), ".halo", "global", ".template-version"));
43652
+ return fs84.existsSync(path93.join(homedir26(), ".halo", "global", ".template-version"));
43599
43653
  }
43600
43654
  async function main2() {
43601
43655
  const argv = process.argv.slice(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@turmind/halo",
3
- "version": "2.0.3",
3
+ "version": "2.0.5",
4
4
  "description": "Halo — multi-agent collaborative workspace. CLI + TUI + HTTP/WS server in one package.",
5
5
  "type": "module",
6
6
  "license": "MIT",