@turmind/halo 2.0.2 → 2.0.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
@@ -1921,7 +1921,7 @@ var init_init = __esm({
1921
1921
  path8.resolve(__dirname, "..", "bundled-docs"),
1922
1922
  path8.resolve(__dirname, "..", "..", "..", ".halo", "docs")
1923
1923
  ];
1924
- TEMPLATE_VERSION = 108;
1924
+ TEMPLATE_VERSION = 109;
1925
1925
  VERSION_FILE = ".template-version";
1926
1926
  SKIP_NAMES = /* @__PURE__ */ new Set([".DS_Store", "schema.sql", "__pycache__", ".pytest_cache"]);
1927
1927
  BUILTIN_AGENT_IDS = /* @__PURE__ */ new Set([
@@ -2542,11 +2542,40 @@ var init_skill_sources = __esm({
2542
2542
  }
2543
2543
  });
2544
2544
 
2545
- // ../server/dist/settings-schema.js
2545
+ // ../server/dist/a2a/remotes.js
2546
2546
  import fs10 from "node:fs";
2547
2547
  import path12 from "node:path";
2548
- import { homedir as homedir7 } from "node:os";
2549
2548
  import YAML4 from "yaml";
2549
+ function remotesFile() {
2550
+ return path12.join(secretsDir(), "a2a-remotes.yaml");
2551
+ }
2552
+ function loadRemotes() {
2553
+ let doc;
2554
+ try {
2555
+ doc = YAML4.parse(fs10.readFileSync(remotesFile(), "utf8")) ?? {};
2556
+ } catch {
2557
+ return {};
2558
+ }
2559
+ const out = {};
2560
+ for (const [name, r] of Object.entries(doc.remotes ?? {})) {
2561
+ if (!r?.card)
2562
+ continue;
2563
+ out[name] = { name, card: r.card, auth: r.auth === "sigv4" ? "sigv4" : "bearer", pushBase: r.push_base?.replace(/\/+$/, "") };
2564
+ }
2565
+ return out;
2566
+ }
2567
+ var init_remotes = __esm({
2568
+ "../server/dist/a2a/remotes.js"() {
2569
+ "use strict";
2570
+ init_paths();
2571
+ }
2572
+ });
2573
+
2574
+ // ../server/dist/settings-schema.js
2575
+ import fs11 from "node:fs";
2576
+ import path13 from "node:path";
2577
+ import { homedir as homedir7 } from "node:os";
2578
+ import YAML5 from "yaml";
2550
2579
  function generalSection() {
2551
2580
  return {
2552
2581
  namespaceId: "general",
@@ -2633,11 +2662,11 @@ function generalSection() {
2633
2662
  }
2634
2663
  function readYamlFile(p) {
2635
2664
  try {
2636
- const { mtimeMs } = fs10.statSync(p);
2665
+ const { mtimeMs } = fs11.statSync(p);
2637
2666
  const hit = _yamlCache.get(p, mtimeMs);
2638
2667
  if (hit !== void 0)
2639
2668
  return hit;
2640
- const parsed = YAML4.parse(fs10.readFileSync(p, "utf-8"));
2669
+ const parsed = YAML5.parse(fs11.readFileSync(p, "utf-8"));
2641
2670
  return _yamlCache.set(p, mtimeMs, parsed && typeof parsed === "object" ? parsed : null);
2642
2671
  } catch {
2643
2672
  return null;
@@ -2691,8 +2720,8 @@ function providerSections() {
2691
2720
  return sections;
2692
2721
  }
2693
2722
  function buildSkillSection(skillsDir, skillId) {
2694
- const configPath = path12.join(skillsDir, skillId, "config.yaml");
2695
- if (!fs10.existsSync(configPath))
2723
+ const configPath = path13.join(skillsDir, skillId, "config.yaml");
2724
+ if (!fs11.existsSync(configPath))
2696
2725
  return null;
2697
2726
  const parsed = readYamlFile(configPath);
2698
2727
  if (!parsed)
@@ -2703,11 +2732,11 @@ function buildSkillSection(skillsDir, skillId) {
2703
2732
  return null;
2704
2733
  let displayName = skillId;
2705
2734
  try {
2706
- const mdPath = path12.join(skillsDir, skillId, "SKILL.md");
2707
- const { mtimeMs } = fs10.statSync(mdPath);
2735
+ const mdPath = path13.join(skillsDir, skillId, "SKILL.md");
2736
+ const { mtimeMs } = fs11.statSync(mdPath);
2708
2737
  let name = _skillNameCache.get(mdPath, mtimeMs);
2709
2738
  if (name === void 0) {
2710
- const m = fs10.readFileSync(mdPath, "utf-8").match(/^---\s*\n([\s\S]*?)\n---/);
2739
+ const m = fs11.readFileSync(mdPath, "utf-8").match(/^---\s*\n([\s\S]*?)\n---/);
2711
2740
  const nameMatch = m?.[1].match(/^name:\s*(.+)$/m);
2712
2741
  name = _skillNameCache.set(mdPath, mtimeMs, nameMatch ? nameMatch[1].trim() : null);
2713
2742
  }
@@ -2728,7 +2757,7 @@ function buildSkillSection(skillsDir, skillId) {
2728
2757
  function skillSections(workspaceRoot) {
2729
2758
  const byId = /* @__PURE__ */ new Map();
2730
2759
  for (const { id, dir } of listSkillDirs(workspaceRoot).reverse()) {
2731
- const section = buildSkillSection(path12.dirname(dir), id);
2760
+ const section = buildSkillSection(path13.dirname(dir), id);
2732
2761
  if (section)
2733
2762
  byId.set(section.namespaceId, section);
2734
2763
  }
@@ -2738,7 +2767,7 @@ function agentSections() {
2738
2767
  const sections = [];
2739
2768
  let entries = [];
2740
2769
  try {
2741
- entries = fs10.readdirSync(GLOBAL_AGENTS_DIR, { withFileTypes: true });
2770
+ entries = fs11.readdirSync(GLOBAL_AGENTS_DIR, { withFileTypes: true });
2742
2771
  } catch {
2743
2772
  return sections;
2744
2773
  }
@@ -2746,8 +2775,8 @@ function agentSections() {
2746
2775
  if (!entry.isDirectory())
2747
2776
  continue;
2748
2777
  const agentId = entry.name;
2749
- const configPath = path12.join(GLOBAL_AGENTS_DIR, agentId, "agent-config.yaml");
2750
- if (!fs10.existsSync(configPath))
2778
+ const configPath = path13.join(GLOBAL_AGENTS_DIR, agentId, "agent-config.yaml");
2779
+ if (!fs11.existsSync(configPath))
2751
2780
  continue;
2752
2781
  const parsed = readYamlFile(configPath);
2753
2782
  if (!parsed)
@@ -2758,7 +2787,7 @@ function agentSections() {
2758
2787
  continue;
2759
2788
  let displayName = agentId;
2760
2789
  try {
2761
- const ay = readYamlFile(path12.join(GLOBAL_AGENTS_DIR, agentId, "agent.yaml"));
2790
+ const ay = readYamlFile(path13.join(GLOBAL_AGENTS_DIR, agentId, "agent.yaml"));
2762
2791
  if (ay && typeof ay.name === "string")
2763
2792
  displayName = ay.name;
2764
2793
  } catch {
@@ -2776,7 +2805,27 @@ function agentSections() {
2776
2805
  return sections;
2777
2806
  }
2778
2807
  function loadSettingsSchema(workspaceRoot) {
2779
- return [generalSection(), ...providerSections(), ...skillSections(workspaceRoot), ...agentSections(), ...extensionSections()];
2808
+ return [generalSection(), ...a2aSections(), ...providerSections(), ...skillSections(workspaceRoot), ...agentSections(), ...extensionSections()];
2809
+ }
2810
+ function a2aSections() {
2811
+ const fields = Object.values(loadRemotes()).filter((r) => r.auth === "bearer").map((r) => ({
2812
+ key: r.name,
2813
+ kind: "secret",
2814
+ secret: true,
2815
+ description: `Bearer token for the A2A remote "${r.name}" (card: ${r.card}).`,
2816
+ description_zh: `A2A \u8FDC\u7A0B "${r.name}" \u7684 bearer token\uFF08card\uFF1A${r.card}\uFF09\u3002`
2817
+ }));
2818
+ if (fields.length === 0)
2819
+ return [];
2820
+ return [{
2821
+ namespaceId: "a2a",
2822
+ source: "general",
2823
+ displayName: "A2A remotes",
2824
+ displayName_zh: "A2A \u8FDC\u7A0B",
2825
+ description: "Tokens for the bearer remotes in ~/.halo/secrets/a2a-remotes.yaml. Prefer global: non-full sessions can read the workspace settings.yaml.",
2826
+ description_zh: "~/.halo/secrets/a2a-remotes.yaml \u4E2D bearer \u8FDC\u7A0B\u7684 token\u3002\u5EFA\u8BAE\u8BBE\u5728\u5168\u5C40\uFF1A\u975E full \u4F1A\u8BDD\u53EF\u4EE5\u8BFB\u53D6\u5DE5\u4F5C\u533A\u7684 settings.yaml\u3002",
2827
+ fields
2828
+ }];
2780
2829
  }
2781
2830
  function extensionSections() {
2782
2831
  const sections = [];
@@ -2812,7 +2861,8 @@ var init_settings_schema = __esm({
2812
2861
  init_registry2();
2813
2862
  init_skill_sources();
2814
2863
  init_mtime_cache();
2815
- GLOBAL_AGENTS_DIR = path12.join(homedir7(), ".halo", "global", "agents");
2864
+ init_remotes();
2865
+ GLOBAL_AGENTS_DIR = path13.join(homedir7(), ".halo", "global", "agents");
2816
2866
  DEFAULT_A2A_URL_ALLOWLIST = "100.64.0.0/10,*.ts.net";
2817
2867
  DEFAULT_FILES_SUMMARY = DEFAULT_HIDDEN_FILES.filter((f) => !/-(wal|shm)$/.test(f)).join(", ");
2818
2868
  _yamlCache = createMtimeCache();
@@ -2847,14 +2897,14 @@ __export(config_exports, {
2847
2897
  resolveThinkingMode: () => resolveThinkingMode,
2848
2898
  resolveVerbosity: () => resolveVerbosity
2849
2899
  });
2850
- import fs11 from "node:fs";
2851
- import path13 from "node:path";
2900
+ import fs12 from "node:fs";
2901
+ import path14 from "node:path";
2852
2902
  import { homedir as homedir8 } from "node:os";
2853
- import YAML5 from "yaml";
2903
+ import YAML6 from "yaml";
2854
2904
  function loadYamlFile(filePath) {
2855
2905
  try {
2856
- const raw = fs11.readFileSync(filePath, "utf-8");
2857
- return YAML5.parse(raw) ?? {};
2906
+ const raw = fs12.readFileSync(filePath, "utf-8");
2907
+ return YAML6.parse(raw) ?? {};
2858
2908
  } catch {
2859
2909
  return {};
2860
2910
  }
@@ -2873,7 +2923,7 @@ function invalidateModelsRegistry() {
2873
2923
  function getSystemConfig() {
2874
2924
  let mtimeMs = 0;
2875
2925
  try {
2876
- mtimeMs = fs11.statSync(SYSTEM_CONFIG_PATH).mtimeMs;
2926
+ mtimeMs = fs12.statSync(SYSTEM_CONFIG_PATH).mtimeMs;
2877
2927
  } catch {
2878
2928
  }
2879
2929
  if (!_systemConfigCache || _systemConfigCache.mtimeMs !== mtimeMs) {
@@ -2884,7 +2934,7 @@ function getSystemConfig() {
2884
2934
  function getSettings() {
2885
2935
  let mtimeMs = 0;
2886
2936
  try {
2887
- mtimeMs = fs11.statSync(SETTINGS_PATH).mtimeMs;
2937
+ mtimeMs = fs12.statSync(SETTINGS_PATH).mtimeMs;
2888
2938
  } catch {
2889
2939
  }
2890
2940
  if (!_settingsCache || _settingsCache.mtimeMs !== mtimeMs) {
@@ -3026,10 +3076,10 @@ function missingEnvRefs(raw) {
3026
3076
  return [...new Set([...raw.matchAll(ENV_PATTERN2)].map((m) => m[1]))].filter((name) => process.env[name] === void 0);
3027
3077
  }
3028
3078
  function getWorkspaceSettings(workspaceRoot) {
3029
- const p = path13.join(workspaceRoot, ".halo", "settings.yaml");
3079
+ const p = path14.join(workspaceRoot, ".halo", "settings.yaml");
3030
3080
  let mtimeMs = 0;
3031
3081
  try {
3032
- mtimeMs = fs11.statSync(p).mtimeMs;
3082
+ mtimeMs = fs12.statSync(p).mtimeMs;
3033
3083
  } catch {
3034
3084
  }
3035
3085
  const hit = _wsSettingsCache.get(workspaceRoot);
@@ -3143,13 +3193,13 @@ var init_config = __esm({
3143
3193
  init_settings_schema();
3144
3194
  init_sandbox();
3145
3195
  init_registry();
3146
- HALO_HOME3 = path13.join(homedir8(), ".halo");
3147
- HALO_GLOBAL_DIR = path13.join(HALO_HOME3, "global");
3148
- HALO_SECRETS_DIR = path13.join(HALO_HOME3, "secrets");
3196
+ HALO_HOME3 = path14.join(homedir8(), ".halo");
3197
+ HALO_GLOBAL_DIR = path14.join(HALO_HOME3, "global");
3198
+ HALO_SECRETS_DIR = path14.join(HALO_HOME3, "secrets");
3149
3199
  _modelsRegistryCache = null;
3150
- SYSTEM_CONFIG_PATH = path13.join(HALO_SECRETS_DIR, "config.yaml");
3200
+ SYSTEM_CONFIG_PATH = path14.join(HALO_SECRETS_DIR, "config.yaml");
3151
3201
  _systemConfigCache = null;
3152
- SETTINGS_PATH = path13.join(HALO_SECRETS_DIR, "settings.yaml");
3202
+ SETTINGS_PATH = path14.join(HALO_SECRETS_DIR, "settings.yaml");
3153
3203
  _settingsCache = null;
3154
3204
  _schemaDefaultsCache = null;
3155
3205
  ENV_PATTERN2 = /<<([A-Z_][A-Z0-9_]*)>>/g;
@@ -4017,31 +4067,31 @@ Error: tool "${tu.name}" was not run \u2014 the turn was interrupted before this
4017
4067
  });
4018
4068
 
4019
4069
  // ../server/dist/agents/agent-loader.js
4020
- import fs12 from "node:fs/promises";
4070
+ import fs13 from "node:fs/promises";
4021
4071
  import fsSync2 from "node:fs";
4022
- import path14 from "node:path";
4072
+ import path15 from "node:path";
4023
4073
  import { homedir as homedir9 } from "node:os";
4024
- import YAML6 from "yaml";
4074
+ import YAML7 from "yaml";
4025
4075
  function canDelegate(yaml) {
4026
4076
  return !yaml?.internal && (yaml?.team?.length ?? 0) > 0;
4027
4077
  }
4028
4078
  function agentSourceDir(agentId, workspaceRoot) {
4029
4079
  if (workspaceRoot) {
4030
- const wsDir = path14.join(workspaceRoot, ".halo", "agents", agentId);
4080
+ const wsDir = path15.join(workspaceRoot, ".halo", "agents", agentId);
4031
4081
  if (fsSync2.existsSync(wsDir))
4032
4082
  return wsDir;
4033
4083
  }
4034
- return path14.join(GLOBAL_AGENTS_DIR2, agentId);
4084
+ return path15.join(GLOBAL_AGENTS_DIR2, agentId);
4035
4085
  }
4036
4086
  function isAgentDisabled(agentId, workspaceRoot, disabledSet) {
4037
- const scope = workspaceRoot && fsSync2.existsSync(path14.join(workspaceRoot, ".halo", "agents", agentId)) ? "workspace" : "global";
4087
+ const scope = workspaceRoot && fsSync2.existsSync(path15.join(workspaceRoot, ".halo", "agents", agentId)) ? "workspace" : "global";
4038
4088
  return disabledSet.has(`${scope}:${agentId}`);
4039
4089
  }
4040
4090
  async function loadAgentYaml(agentId, workspaceRoot) {
4041
- const yamlPath = path14.join(agentSourceDir(agentId, workspaceRoot), "agent.yaml");
4091
+ const yamlPath = path15.join(agentSourceDir(agentId, workspaceRoot), "agent.yaml");
4042
4092
  try {
4043
- const content = await fs12.readFile(yamlPath, "utf-8");
4044
- const parsed = YAML6.parse(content);
4093
+ const content = await fs13.readFile(yamlPath, "utf-8");
4094
+ const parsed = YAML7.parse(content);
4045
4095
  if (parsed === null || typeof parsed !== "object") {
4046
4096
  console.warn(`[AgentLoader] Failed to parse ${yamlPath}: empty or non-object YAML`);
4047
4097
  return null;
@@ -4070,7 +4120,7 @@ function parseSkillFrontmatter(raw) {
4070
4120
  let doc = {};
4071
4121
  const parseYaml = (block) => {
4072
4122
  try {
4073
- const parsed = YAML6.parse(block);
4123
+ const parsed = YAML7.parse(block);
4074
4124
  if (parsed && typeof parsed === "object")
4075
4125
  doc = parsed;
4076
4126
  return true;
@@ -4110,7 +4160,7 @@ function resolveSkillPath(skillId, workspaceRoot) {
4110
4160
  const dir = skillSourceDir(skillId, workspaceRoot);
4111
4161
  if (!dir)
4112
4162
  return null;
4113
- const p = path14.join(dir, "SKILL.md");
4163
+ const p = path15.join(dir, "SKILL.md");
4114
4164
  try {
4115
4165
  fsSync2.accessSync(p);
4116
4166
  return p;
@@ -4128,7 +4178,7 @@ async function loadSkillMetadata(skillIds, workspaceRoot, disabledSet, accessLev
4128
4178
  if (!mdPath)
4129
4179
  continue;
4130
4180
  try {
4131
- const raw = await fs12.readFile(mdPath, "utf-8");
4181
+ const raw = await fs13.readFile(mdPath, "utf-8");
4132
4182
  const { name, description, command, requiresAccess, disableModelInvocation } = parseSkillFrontmatter(raw);
4133
4183
  if (requiresAccess && ACCESS_RANK[requiresAccess] > sessionRank)
4134
4184
  continue;
@@ -4187,9 +4237,9 @@ function createSkillTool(skills, ctx = {}) {
4187
4237
  return `${TOOL_WARN_MARKER}
4188
4238
  Error: skill "${skill_id}" not found. Available: ${skills.map((s) => s.id).join(", ")}`;
4189
4239
  try {
4190
- const raw = await fs12.readFile(meta.path, "utf-8");
4240
+ const raw = await fs13.readFile(meta.path, "utf-8");
4191
4241
  const { body } = parseSkillFrontmatter(raw);
4192
- const skillDir = path14.dirname(meta.path);
4242
+ const skillDir = path15.dirname(meta.path);
4193
4243
  const qualifiedBody = body.replace(/\{\{\s*params\.([\w-][\w.-]*)\s*\}\}/g, (_m, key) => `{{${skill_id}.params.${key}}}`);
4194
4244
  const { buildRenderContext: buildRenderContext2, renderMdBody: renderMdBody2 } = await Promise.resolve().then(() => (init_md_vars(), md_vars_exports));
4195
4245
  const renderCtx = await buildRenderContext2({
@@ -4202,9 +4252,9 @@ Error: skill "${skill_id}" not found. Available: ${skills.map((s) => s.id).join(
4202
4252
  const renderedBody = renderMdBody2(qualifiedBody, renderCtx);
4203
4253
  let resources = "";
4204
4254
  try {
4205
- const entries = await fs12.readdir(skillDir, { recursive: true, withFileTypes: true });
4255
+ const entries = await fs13.readdir(skillDir, { recursive: true, withFileTypes: true });
4206
4256
  const files = entries.filter((e) => e.isFile() && e.name !== "SKILL.md").map((e) => {
4207
- const rel = e.parentPath ? path14.relative(skillDir, path14.join(e.parentPath, e.name)) : e.name;
4257
+ const rel = e.parentPath ? path15.relative(skillDir, path15.join(e.parentPath, e.name)) : e.name;
4208
4258
  return rel;
4209
4259
  });
4210
4260
  if (files.length > 0)
@@ -4226,12 +4276,12 @@ ${renderedBody}${resources}`;
4226
4276
  async function scanAvailableAgents(workspaceRoot, disabledSet) {
4227
4277
  const agents = [];
4228
4278
  try {
4229
- const globalNames = await fs12.readdir(GLOBAL_AGENTS_DIR2);
4279
+ const globalNames = await fs13.readdir(GLOBAL_AGENTS_DIR2);
4230
4280
  for (const name of globalNames) {
4231
- const yamlPath = path14.join(GLOBAL_AGENTS_DIR2, name, "agent.yaml");
4281
+ const yamlPath = path15.join(GLOBAL_AGENTS_DIR2, name, "agent.yaml");
4232
4282
  try {
4233
- const content = await fs12.readFile(yamlPath, "utf-8");
4234
- const cfg = YAML6.parse(content);
4283
+ const content = await fs13.readFile(yamlPath, "utf-8");
4284
+ const cfg = YAML7.parse(content);
4235
4285
  agents.push({
4236
4286
  id: name,
4237
4287
  name: cfg.name ?? name,
@@ -4250,14 +4300,14 @@ async function scanAvailableAgents(workspaceRoot, disabledSet) {
4250
4300
  } catch {
4251
4301
  }
4252
4302
  if (workspaceRoot) {
4253
- const wsAgentsDir = path14.join(workspaceRoot, ".halo", "agents");
4303
+ const wsAgentsDir = path15.join(workspaceRoot, ".halo", "agents");
4254
4304
  try {
4255
- const wsNames = await fs12.readdir(wsAgentsDir);
4305
+ const wsNames = await fs13.readdir(wsAgentsDir);
4256
4306
  for (const name of wsNames) {
4257
- const yamlPath = path14.join(wsAgentsDir, name, "agent.yaml");
4307
+ const yamlPath = path15.join(wsAgentsDir, name, "agent.yaml");
4258
4308
  try {
4259
- const content = await fs12.readFile(yamlPath, "utf-8");
4260
- const cfg = YAML6.parse(content);
4309
+ const content = await fs13.readFile(yamlPath, "utf-8");
4310
+ const cfg = YAML7.parse(content);
4261
4311
  agents.push({
4262
4312
  id: name,
4263
4313
  name: cfg.name ?? name,
@@ -4294,7 +4344,7 @@ var init_agent_loader = __esm({
4294
4344
  init_agent_loop();
4295
4345
  init_skill_sources();
4296
4346
  init_skill_sources();
4297
- GLOBAL_AGENTS_DIR2 = path14.join(homedir9(), ".halo", "global", "agents");
4347
+ GLOBAL_AGENTS_DIR2 = path15.join(homedir9(), ".halo", "global", "agents");
4298
4348
  ACCESS_RANK = {
4299
4349
  readonly: 0,
4300
4350
  observer: 0,
@@ -4305,7 +4355,7 @@ var init_agent_loader = __esm({
4305
4355
  });
4306
4356
 
4307
4357
  // ../server/dist/ws/broadcast.js
4308
- import path15 from "node:path";
4358
+ import path16 from "node:path";
4309
4359
  function setBroadcastWss(wss2) {
4310
4360
  _wss = wss2;
4311
4361
  }
@@ -4332,14 +4382,14 @@ function broadcastToWorkspace(workspacePath, event) {
4332
4382
  return;
4333
4383
  if (!_workspaceOfClient)
4334
4384
  return broadcast(event);
4335
- const target = path15.resolve(workspacePath);
4385
+ const target = path16.resolve(workspacePath);
4336
4386
  const payload = JSON.stringify(event);
4337
4387
  for (const client of _wss.clients) {
4338
4388
  const ws = client;
4339
4389
  if (ws.readyState !== ws.OPEN)
4340
4390
  continue;
4341
4391
  const bound = _workspaceOfClient(ws);
4342
- if (!bound || path15.resolve(bound) !== target)
4392
+ if (!bound || path16.resolve(bound) !== target)
4343
4393
  continue;
4344
4394
  try {
4345
4395
  ws.send(payload);
@@ -4438,12 +4488,12 @@ var init_migrate = __esm({
4438
4488
  });
4439
4489
 
4440
4490
  // ../server/dist/db/durability.js
4441
- import path16 from "node:path";
4491
+ import path17 from "node:path";
4442
4492
  function setDurableDbDir(dir) {
4443
- durableDir = dir === null ? null : path16.resolve(dir);
4493
+ durableDir = dir === null ? null : path17.resolve(dir);
4444
4494
  }
4445
4495
  function applyCommitDurability(sqlite, dataDir) {
4446
- if (durableDir !== null && path16.resolve(dataDir) === durableDir)
4496
+ if (durableDir !== null && path17.resolve(dataDir) === durableDir)
4447
4497
  sqlite.pragma("synchronous = FULL");
4448
4498
  }
4449
4499
  var durableDir;
@@ -4458,17 +4508,17 @@ var init_durability = __esm({
4458
4508
  import Database from "better-sqlite3";
4459
4509
  import { drizzle } from "drizzle-orm/better-sqlite3";
4460
4510
  import { eq, and, sql } from "drizzle-orm";
4461
- import path17 from "node:path";
4462
- import fs13 from "node:fs";
4511
+ import path18 from "node:path";
4512
+ import fs14 from "node:fs";
4463
4513
  function createDb(dataDir) {
4464
- fs13.mkdirSync(dataDir, { recursive: true });
4465
- const dbPath = path17.join(dataDir, "halo.db");
4514
+ fs14.mkdirSync(dataDir, { recursive: true });
4515
+ const dbPath = path18.join(dataDir, "halo.db");
4466
4516
  const sqlite = new Database(dbPath);
4467
4517
  sqlite.pragma("journal_mode = WAL");
4468
4518
  applyCommitDurability(sqlite, dataDir);
4469
4519
  sqlite.pragma("foreign_keys = ON");
4470
4520
  const db4 = drizzle(sqlite, { schema: schema_exports });
4471
- const schemaSql = fs13.readFileSync(SCHEMA_SQL_PATH, "utf-8");
4521
+ const schemaSql = fs14.readFileSync(SCHEMA_SQL_PATH, "utf-8");
4472
4522
  sqlite.exec(schemaSql);
4473
4523
  runMigrations(sqlite, HALO_MIGRATIONS);
4474
4524
  return db4;
@@ -4499,7 +4549,7 @@ function updateSessionOutput(db4, sessionId, output, lastActivityAt) {
4499
4549
  db4.update(agentSessions).set({ output, lastActivityAt }).where(and(eq(agentSessions.id, sessionId), sql`(${agentSessions.output} IS NOT ${output} OR ${agentSessions.lastActivityAt} IS NOT ${lastActivityAt})`)).run();
4500
4550
  }
4501
4551
  function openHaloDb(dataDir) {
4502
- const key = path17.resolve(dataDir);
4552
+ const key = path18.resolve(dataDir);
4503
4553
  let db4 = haloDbCache.get(key);
4504
4554
  if (!db4) {
4505
4555
  db4 = createDb(key);
@@ -4511,11 +4561,11 @@ function internalSessionsDb() {
4511
4561
  return openHaloDb(globalInternalSessionsDir());
4512
4562
  }
4513
4563
  function getWorkspaceDb(workspacePath) {
4514
- const resolved = fs13.realpathSync(workspacePath);
4564
+ const resolved = fs14.realpathSync(workspacePath);
4515
4565
  ensureWorkspaceHalo(resolved);
4516
4566
  let db4 = dbCache.get(resolved);
4517
4567
  if (!db4) {
4518
- const haloDir = path17.join(resolved, ".halo");
4568
+ const haloDir = path18.join(resolved, ".halo");
4519
4569
  db4 = createDb(haloDir);
4520
4570
  dbCache.set(resolved, db4);
4521
4571
  }
@@ -4544,7 +4594,7 @@ var init_db = __esm({
4544
4594
  init_paths();
4545
4595
  init_migrate();
4546
4596
  init_durability();
4547
- SCHEMA_SQL_PATH = path17.join(TEMPLATES_DIR, "schema.sql");
4597
+ SCHEMA_SQL_PATH = path18.join(TEMPLATES_DIR, "schema.sql");
4548
4598
  HALO_MIGRATIONS = [
4549
4599
  // v1: everything that used to be an ad-hoc boot-time ALTER / CREATE INDEX.
4550
4600
  (s) => {
@@ -4895,7 +4945,7 @@ var init_session_tools = __esm({
4895
4945
 
4896
4946
  // ../server/dist/sessions/session-archive.js
4897
4947
  import fsSync3 from "node:fs";
4898
- import path18 from "node:path";
4948
+ import path19 from "node:path";
4899
4949
  import { createHash } from "node:crypto";
4900
4950
  import { gzipSync, gunzipSync } from "node:zlib";
4901
4951
  function firstIdHash(id) {
@@ -4937,7 +4987,7 @@ function countArchiveSegments(dir, seg) {
4937
4987
  }
4938
4988
  function readSegmentFile(dir, s) {
4939
4989
  try {
4940
- const text6 = gunzipSync(fsSync3.readFileSync(path18.join(dir, s.name))).toString("utf-8");
4990
+ const text6 = gunzipSync(fsSync3.readFileSync(path19.join(dir, s.name))).toString("utf-8");
4941
4991
  const out = [];
4942
4992
  for (const line of text6.split("\n"))
4943
4993
  if (line)
@@ -4956,13 +5006,13 @@ function writeArchiveSegment(dir, seg, n, messages2) {
4956
5006
  for (const s of listSegmentFiles(dir, seg)) {
4957
5007
  if (s.n >= n) {
4958
5008
  try {
4959
- fsSync3.unlinkSync(path18.join(dir, s.name));
5009
+ fsSync3.unlinkSync(path19.join(dir, s.name));
4960
5010
  } catch {
4961
5011
  }
4962
5012
  }
4963
5013
  }
4964
5014
  const body = messages2.map((m) => JSON.stringify(m)).join("\n") + "\n";
4965
- atomicWriteFileSync(path18.join(dir, `${seg}.ui.arch.${n}.${firstIdHash(messages2[0].id)}.jsonl.gz`), gzipSync(body));
5015
+ atomicWriteFileSync(path19.join(dir, `${seg}.ui.arch.${n}.${firstIdHash(messages2[0].id)}.jsonl.gz`), gzipSync(body));
4966
5016
  }
4967
5017
  function isCompactSummary(m) {
4968
5018
  return m.compactSummary === true || m.content.startsWith("[Conversation Summary \u2014 ");
@@ -4994,17 +5044,17 @@ __export(legacy_migrate_exports, {
4994
5044
  migrateWorkspaceSessions: () => migrateWorkspaceSessions
4995
5045
  });
4996
5046
  import fsSync4 from "node:fs";
4997
- import path19 from "node:path";
5047
+ import path20 from "node:path";
4998
5048
  import { gunzipSync as gunzipSync2 } from "node:zlib";
4999
5049
  import { eq as eq2 } from "drizzle-orm";
5000
5050
  function isInternalDir(dir) {
5001
- return path19.resolve(path19.dirname(dir)) === path19.resolve(globalInternalSessionsDir());
5051
+ return path20.resolve(path20.dirname(dir)) === path20.resolve(globalInternalSessionsDir());
5002
5052
  }
5003
5053
  function legacySegmentPath(dir, seg, n) {
5004
- return path19.join(dir, `${seg}.arch.${n}.json.gz`);
5054
+ return path20.join(dir, `${seg}.arch.${n}.json.gz`);
5005
5055
  }
5006
5056
  function readLegacy(dir, seg) {
5007
- const data = JSON.parse(fsSync4.readFileSync(path19.join(dir, `${seg}.json`), "utf-8"));
5057
+ const data = JSON.parse(fsSync4.readFileSync(path20.join(dir, `${seg}.json`), "utf-8"));
5008
5058
  const committed = typeof data.archiveCount === "number" ? data.archiveCount : 0;
5009
5059
  const segs = [];
5010
5060
  const unreadable = [];
@@ -5028,8 +5078,8 @@ function readLegacy(dir, seg) {
5028
5078
  function dbForSessionDir(dir) {
5029
5079
  if (isInternalDir(dir))
5030
5080
  return internalSessionsDb();
5031
- const haloDir = path19.dirname(path19.dirname(dir));
5032
- return fsSync4.existsSync(path19.join(haloDir, "halo.db")) ? openHaloDb(haloDir) : null;
5081
+ const haloDir = path20.dirname(path20.dirname(dir));
5082
+ return fsSync4.existsSync(path20.join(haloDir, "halo.db")) ? openHaloDb(haloDir) : null;
5033
5083
  }
5034
5084
  function mainUsers(messages2) {
5035
5085
  let n = 0;
@@ -5054,8 +5104,8 @@ function backfillRow(dir, seg, legacy) {
5054
5104
  db4.insert(agentSessions).values({
5055
5105
  id,
5056
5106
  parentId: data.parentSessionId ?? null,
5057
- agentId: path19.basename(dir),
5058
- agentName: data.agentName ?? path19.basename(dir),
5107
+ agentId: path20.basename(dir),
5108
+ agentName: data.agentName ?? path20.basename(dir),
5059
5109
  description: data.description ?? data.title ?? "",
5060
5110
  createdAt: created,
5061
5111
  updatedAt: toMs(data.updatedAt, created)
@@ -5132,16 +5182,16 @@ function deleteLegacyFiles(dir, seg, legacy) {
5132
5182
  for (const name of fsSync4.readdirSync(dir)) {
5133
5183
  const hit = name === `${seg}.json` || name.startsWith(`${seg}.json.tmp.`) || /^\d+\.json\.gz$/.test(name.startsWith(`${seg}.arch.`) ? name.slice(seg.length + 6) : "");
5134
5184
  if (hit && !keep.has(name))
5135
- fsSync4.rmSync(path19.join(dir, name), { force: true });
5185
+ fsSync4.rmSync(path20.join(dir, name), { force: true });
5136
5186
  }
5137
5187
  if (keep.size > 0)
5138
- console.warn(`[LegacyMigrate] ${path19.join(dir, seg)}: kept unreadable 1.x segment(s) ${legacy.unreadable.join(", ")}`);
5188
+ console.warn(`[LegacyMigrate] ${path20.join(dir, seg)}: kept unreadable 1.x segment(s) ${legacy.unreadable.join(", ")}`);
5139
5189
  }
5140
5190
  function migrationLockPath(dir, seg) {
5141
- return path19.join(dir, `${seg}.migrating`);
5191
+ return path20.join(dir, `${seg}.migrating`);
5142
5192
  }
5143
5193
  function conversionPending(dir, seg) {
5144
- return !fsSync4.existsSync(uiLogPath(dir, seg)) && fsSync4.existsSync(path19.join(dir, `${seg}.json`));
5194
+ return !fsSync4.existsSync(uiLogPath(dir, seg)) && fsSync4.existsSync(path20.join(dir, `${seg}.json`));
5145
5195
  }
5146
5196
  function sleepSync(ms) {
5147
5197
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
@@ -5201,7 +5251,7 @@ function takeOverLock(lock, deadPid) {
5201
5251
  console.warn(`[LegacyMigrate] ${lock}: took over from dead pid ${deadPid || "(none)"}`);
5202
5252
  }
5203
5253
  function conversionLanded(dir, seg) {
5204
- return fsSync4.existsSync(uiLogPath(dir, seg)) && !fsSync4.existsSync(path19.join(dir, `${seg}.json`));
5254
+ return fsSync4.existsSync(uiLogPath(dir, seg)) && !fsSync4.existsSync(path20.join(dir, `${seg}.json`));
5205
5255
  }
5206
5256
  function acquireMigrationLock(dir, seg) {
5207
5257
  const lock = migrationLockPath(dir, seg);
@@ -5261,7 +5311,7 @@ function convertLocked(dir, seg) {
5261
5311
  }
5262
5312
  replaceUILog(uiLogPath(dir, seg), legacy.messages);
5263
5313
  const mismatch = verifyConverted(dir, seg, legacy);
5264
- if (mismatch && (!holdsMigrationLock(dir, seg) || !fsSync4.existsSync(path19.join(dir, `${seg}.json`)))) {
5314
+ if (mismatch && (!holdsMigrationLock(dir, seg) || !fsSync4.existsSync(path20.join(dir, `${seg}.json`)))) {
5265
5315
  throw new Error(`check after conversion failed: ${mismatch}; lost the conversion lock \u2014 nothing undone`);
5266
5316
  }
5267
5317
  if (mismatch) {
@@ -5269,15 +5319,15 @@ function convertLocked(dir, seg) {
5269
5319
  fsSync4.rmSync(rawLogPath(dir, seg), { force: true });
5270
5320
  for (const name of fsSync4.readdirSync(dir)) {
5271
5321
  if (name.startsWith(`${seg}.ui.arch.`))
5272
- fsSync4.rmSync(path19.join(dir, name), { force: true });
5322
+ fsSync4.rmSync(path20.join(dir, name), { force: true });
5273
5323
  }
5274
5324
  throw new Error(`check after conversion failed: ${mismatch}; 1.x files kept`);
5275
5325
  }
5276
5326
  deleteLegacyFiles(dir, seg, legacy);
5277
- console.log(`[LegacyMigrate] migrated ${path19.join(dir, seg)} (${legacy.messages.length} UI, ${legacy.raw.length} raw, ${legacy.segs.length} segment(s))`);
5327
+ console.log(`[LegacyMigrate] migrated ${path20.join(dir, seg)} (${legacy.messages.length} UI, ${legacy.raw.length} raw, ${legacy.segs.length} segment(s))`);
5278
5328
  }
5279
5329
  function cleanUpLegacy(dir, seg) {
5280
- const pending = () => fsSync4.existsSync(uiLogPath(dir, seg)) && fsSync4.existsSync(path19.join(dir, `${seg}.json`));
5330
+ const pending = () => fsSync4.existsSync(uiLogPath(dir, seg)) && fsSync4.existsSync(path20.join(dir, `${seg}.json`));
5281
5331
  return underMigrationLock(dir, seg, pending, () => {
5282
5332
  const legacy = readLegacy(dir, seg);
5283
5333
  const mismatch = verifyPreserved(dir, seg, legacy);
@@ -5287,18 +5337,18 @@ function cleanUpLegacy(dir, seg) {
5287
5337
  });
5288
5338
  }
5289
5339
  function migrateOnMissingLog(filePath) {
5290
- const m = /^(.*)\.(?:ui|raw)\.jsonl$/.exec(path19.basename(filePath));
5340
+ const m = /^(.*)\.(?:ui|raw)\.jsonl$/.exec(path20.basename(filePath));
5291
5341
  if (!m)
5292
5342
  return false;
5293
- const dir = path19.dirname(filePath);
5343
+ const dir = path20.dirname(filePath);
5294
5344
  const seg = m[1];
5295
- if (fsSync4.existsSync(uiLogPath(dir, seg)) || !fsSync4.existsSync(path19.join(dir, `${seg}.json`)))
5345
+ if (fsSync4.existsSync(uiLogPath(dir, seg)) || !fsSync4.existsSync(path20.join(dir, `${seg}.json`)))
5296
5346
  return false;
5297
5347
  try {
5298
5348
  migrateLegacySession(dir, seg);
5299
5349
  } catch (err) {
5300
5350
  const reason = err instanceof Error ? err.message : String(err);
5301
- const key = path19.join(dir, seg);
5351
+ const key = path20.join(dir, seg);
5302
5352
  if (!loggedFailures.has(key)) {
5303
5353
  loggedFailures.add(key);
5304
5354
  console.error(`[LegacyMigrate] ${key}: ${reason}`);
@@ -5318,7 +5368,7 @@ function isPidAlive(pid) {
5318
5368
  function liveRuntimeHolder(root) {
5319
5369
  let pid = 0;
5320
5370
  try {
5321
- pid = parseInt(fsSync4.readFileSync(path19.join(root, ".halo", "runtime.lock"), "utf-8").trim(), 10) || 0;
5371
+ pid = parseInt(fsSync4.readFileSync(path20.join(root, ".halo", "runtime.lock"), "utf-8").trim(), 10) || 0;
5322
5372
  } catch {
5323
5373
  return null;
5324
5374
  }
@@ -5365,12 +5415,12 @@ function migrateWorkspaceSessions(root) {
5365
5415
  throw new Error(`A server (pid ${holder}) is running on this workspace. Stop it first (\`halo server stop\`, or \`systemctl --user stop halo\` under systemd), migrate, then start it again. Also stop any other server that has this workspace open (e.g. a HALO_BADGE=DEV instance) \u2014 it doesn't hold runtime.lock.`);
5366
5416
  }
5367
5417
  const out = { migrated: 0, cleaned: 0, skipped: 0, failed: [] };
5368
- const sessions = path19.join(root, ".halo", "sessions");
5418
+ const sessions = path20.join(root, ".halo", "sessions");
5369
5419
  for (const agent of agentDirs(sessions))
5370
- migrateDir(path19.join(sessions, agent), agent, out);
5420
+ migrateDir(path20.join(sessions, agent), agent, out);
5371
5421
  const internal = globalInternalSessionsDir();
5372
5422
  for (const agent of agentDirs(internal))
5373
- migrateDir(path19.join(internal, agent), agent, out);
5423
+ migrateDir(path20.join(internal, agent), agent, out);
5374
5424
  return out;
5375
5425
  }
5376
5426
  var MIGRATION_LOCK_WAIT_MS, MIGRATION_LOCK_STEP_MS, LegacyConversionError, loggedFailures;
@@ -5392,12 +5442,12 @@ var init_legacy_migrate = __esm({
5392
5442
 
5393
5443
  // ../server/dist/sessions/session-log.js
5394
5444
  import fsSync5 from "node:fs";
5395
- import path20 from "node:path";
5445
+ import path21 from "node:path";
5396
5446
  function uiLogPath(dir, seg) {
5397
- return path20.join(dir, `${seg}.ui.jsonl`);
5447
+ return path21.join(dir, `${seg}.ui.jsonl`);
5398
5448
  }
5399
5449
  function rawLogPath(dir, seg) {
5400
- return path20.join(dir, `${seg}.raw.jsonl`);
5450
+ return path21.join(dir, `${seg}.raw.jsonl`);
5401
5451
  }
5402
5452
  function openOrNull(filePath) {
5403
5453
  try {
@@ -5671,7 +5721,7 @@ function writeUILog(filePath, rows, inflight, opts) {
5671
5721
  out2 += inflightLine(inflight, 0, shell);
5672
5722
  inflightCache2 = inflightCacheOf(inflight, JSON.stringify(shell));
5673
5723
  }
5674
- fsSync5.mkdirSync(path20.dirname(filePath), { recursive: true });
5724
+ fsSync5.mkdirSync(path21.dirname(filePath), { recursive: true });
5675
5725
  const stamp = rewriteAndStamp(filePath, out2);
5676
5726
  uiCaches.set(filePath, uiCacheOf(stamp, rows, usersAfter, inflightCache2));
5677
5727
  return { userDelta: usersAfter - usersBefore, size: stamp.size, foreign };
@@ -5727,7 +5777,7 @@ function writeUILog(filePath, rows, inflight, opts) {
5727
5777
  return { userDelta: usersAfter - usersBefore, size: c.stamp.size, foreign: false };
5728
5778
  }
5729
5779
  function replaceUILog(filePath, rows) {
5730
- fsSync5.mkdirSync(path20.dirname(filePath), { recursive: true });
5780
+ fsSync5.mkdirSync(path21.dirname(filePath), { recursive: true });
5731
5781
  atomicWriteFileSync(filePath, rows.map(addLine).join(""));
5732
5782
  uiCaches.delete(filePath);
5733
5783
  }
@@ -5810,7 +5860,7 @@ function writeRawLog(filePath, messages2) {
5810
5860
  }
5811
5861
  if (full) {
5812
5862
  const { out: out2, lastStart: lastStart2 } = rawLines(messages2);
5813
- fsSync5.mkdirSync(path20.dirname(filePath), { recursive: true });
5863
+ fsSync5.mkdirSync(path21.dirname(filePath), { recursive: true });
5814
5864
  rawCaches.set(filePath, rawCacheOf(rewriteAndStamp(filePath, out2), messages2, lastStart2));
5815
5865
  return foreign;
5816
5866
  }
@@ -5849,7 +5899,7 @@ function writeRawLog(filePath, messages2) {
5849
5899
  return false;
5850
5900
  }
5851
5901
  function replaceRawLog(filePath, messages2) {
5852
- fsSync5.mkdirSync(path20.dirname(filePath), { recursive: true });
5902
+ fsSync5.mkdirSync(path21.dirname(filePath), { recursive: true });
5853
5903
  atomicWriteFileSync(filePath, messages2.map((m) => JSON.stringify(m) + "\n").join(""));
5854
5904
  rawCaches.delete(filePath);
5855
5905
  }
@@ -5881,8 +5931,8 @@ var init_session_log = __esm({
5881
5931
  });
5882
5932
 
5883
5933
  // ../server/dist/sessions/session-store.js
5884
- import fs14 from "node:fs/promises";
5885
- import path21 from "node:path";
5934
+ import fs15 from "node:fs/promises";
5935
+ import path22 from "node:path";
5886
5936
  import { homedir as homedir10 } from "node:os";
5887
5937
  import { and as and2, eq as eq3, gte, inArray, lt, or } from "drizzle-orm";
5888
5938
  function isInternalAgent(agentId) {
@@ -5893,14 +5943,14 @@ function sessionMetaDb(workspaceDb, agentId) {
5893
5943
  }
5894
5944
  function getSessionDir(agentId, projectPath) {
5895
5945
  if (isInternalAgent(agentId)) {
5896
- return path21.join(homedir10(), ".halo", "global", "internal-sessions", agentId);
5946
+ return path22.join(homedir10(), ".halo", "global", "internal-sessions", agentId);
5897
5947
  }
5898
- const base = projectPath ? path21.join(projectPath, ".halo") : path21.join(homedir10(), ".halo");
5899
- return path21.join(base, "sessions", agentId);
5948
+ const base = projectPath ? path22.join(projectPath, ".halo") : path22.join(homedir10(), ".halo");
5949
+ return path22.join(base, "sessions", agentId);
5900
5950
  }
5901
5951
  function getSessionsBaseDir(projectPath) {
5902
- const base = projectPath ? path21.join(projectPath, ".halo") : path21.join(homedir10(), ".halo");
5903
- return path21.join(base, "sessions");
5952
+ const base = projectPath ? path22.join(projectPath, ".halo") : path22.join(homedir10(), ".halo");
5953
+ return path22.join(base, "sessions");
5904
5954
  }
5905
5955
  function fileSegment(sessionId) {
5906
5956
  const parts = sessionId.split(">");
@@ -5956,7 +6006,7 @@ function isSessionFile(name, seg) {
5956
6006
  async function deleteSessionFilesIn(dir, seg) {
5957
6007
  let names;
5958
6008
  try {
5959
- names = await fs14.readdir(dir);
6009
+ names = await fs15.readdir(dir);
5960
6010
  } catch {
5961
6011
  return false;
5962
6012
  }
@@ -5965,7 +6015,7 @@ async function deleteSessionFilesIn(dir, seg) {
5965
6015
  if (!isSessionFile(name, seg))
5966
6016
  continue;
5967
6017
  try {
5968
- await fs14.rm(path21.join(dir, name));
6018
+ await fs15.rm(path22.join(dir, name));
5969
6019
  hit = true;
5970
6020
  } catch {
5971
6021
  }
@@ -5975,7 +6025,7 @@ async function deleteSessionFilesIn(dir, seg) {
5975
6025
  }
5976
6026
  async function subdirs(base) {
5977
6027
  try {
5978
- return (await fs14.readdir(base, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => path21.join(base, d.name));
6028
+ return (await fs15.readdir(base, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => path22.join(base, d.name));
5979
6029
  } catch {
5980
6030
  return [];
5981
6031
  }
@@ -5989,7 +6039,7 @@ async function findAndDeleteSessionFile(sessionId, projectPath) {
5989
6039
  const db4 = internalSessionsDb();
5990
6040
  const tree = db4.select({ id: agentSessions.id, agentId: agentSessions.agentId }).from(agentSessions).where(or(eq3(agentSessions.id, sessionId), and2(gte(agentSessions.id, sessionId + ">"), lt(agentSessions.id, sessionId + ">\uFFFF")))).all();
5991
6041
  for (const r of tree)
5992
- await deleteSessionFilesIn(path21.join(globalInternalSessionsDir(), r.agentId), fileSegment(r.id));
6042
+ await deleteSessionFilesIn(path22.join(globalInternalSessionsDir(), r.agentId), fileSegment(r.id));
5993
6043
  if (tree.length > 0) {
5994
6044
  db4.delete(agentSessions).where(inArray(agentSessions.id, tree.map((r) => r.id))).run();
5995
6045
  return;
@@ -6012,8 +6062,8 @@ var init_session_store = __esm({
6012
6062
  });
6013
6063
 
6014
6064
  // ../server/dist/agents/goal-mode.js
6015
- import fs15 from "node:fs";
6016
- import path22 from "node:path";
6065
+ import fs16 from "node:fs";
6066
+ import path23 from "node:path";
6017
6067
  import { createHash as createHash2 } from "node:crypto";
6018
6068
  import { and as and3, eq as eq4, isNull, isNotNull } from "drizzle-orm";
6019
6069
  function initialGoalState(goalId, workerSessionId) {
@@ -6123,14 +6173,14 @@ function dissolveGoalBindingsFor(db4, ids) {
6123
6173
  }
6124
6174
  }
6125
6175
  function goalDir(workspaceRoot, goalId) {
6126
- return path22.join(workspaceRoot, ".halo", "goal", goalId);
6176
+ return path23.join(workspaceRoot, ".halo", "goal", goalId);
6127
6177
  }
6128
6178
  function goalSpecPath(workspaceRoot, goalId) {
6129
- return path22.join(goalDir(workspaceRoot, goalId), "GOAL_SPEC.md");
6179
+ return path23.join(goalDir(workspaceRoot, goalId), "GOAL_SPEC.md");
6130
6180
  }
6131
6181
  function hashFileOrNull(filePath) {
6132
6182
  try {
6133
- return createHash2("sha256").update(fs15.readFileSync(filePath)).digest("hex");
6183
+ return createHash2("sha256").update(fs16.readFileSync(filePath)).digest("hex");
6134
6184
  } catch {
6135
6185
  return null;
6136
6186
  }
@@ -6362,8 +6412,8 @@ ${params.kickoff}`);
6362
6412
  }
6363
6413
  const n = s.delegatedCount + 1;
6364
6414
  const dir = goalDir(host.workspaceRoot, s.goalId);
6365
- fs15.mkdirSync(dir, { recursive: true });
6366
- fs15.writeFileSync(path22.join(dir, `decision-${n}.md`), [
6415
+ fs16.mkdirSync(dir, { recursive: true });
6416
+ fs16.writeFileSync(path23.join(dir, `decision-${n}.md`), [
6367
6417
  `# Delegated decision ${n}/${DELEGATED_DECISION_CAP}`,
6368
6418
  `- at: ${(/* @__PURE__ */ new Date()).toISOString()}`,
6369
6419
  `- round: ${s.round}`,
@@ -6512,16 +6562,16 @@ var init_goal_mode = __esm({
6512
6562
  });
6513
6563
 
6514
6564
  // ../server/dist/agents/working-dir.js
6515
- import path23 from "node:path";
6516
- import fs16 from "node:fs/promises";
6565
+ import path24 from "node:path";
6566
+ import fs17 from "node:fs/promises";
6517
6567
  async function resolveWorkingDir(workspaceRoot, input) {
6518
- const resolved = path23.isAbsolute(input) ? path23.resolve(input) : path23.resolve(workspaceRoot, input);
6519
- const wsRoot = path23.resolve(workspaceRoot);
6520
- if (resolved !== wsRoot && !resolved.startsWith(wsRoot + path23.sep)) {
6568
+ const resolved = path24.isAbsolute(input) ? path24.resolve(input) : path24.resolve(workspaceRoot, input);
6569
+ const wsRoot = path24.resolve(workspaceRoot);
6570
+ if (resolved !== wsRoot && !resolved.startsWith(wsRoot + path24.sep)) {
6521
6571
  throw new Error(`working_dir "${input}" is outside the workspace`);
6522
6572
  }
6523
6573
  try {
6524
- const stat = await fs16.stat(resolved);
6574
+ const stat = await fs17.stat(resolved);
6525
6575
  if (!stat.isDirectory())
6526
6576
  throw new Error(`working_dir "${input}" is not a directory`);
6527
6577
  } catch (err) {
@@ -6538,27 +6588,27 @@ var init_working_dir = __esm({
6538
6588
  });
6539
6589
 
6540
6590
  // ../server/dist/ws/skills-changed.js
6541
- import fs17 from "node:fs";
6542
- import path24 from "node:path";
6591
+ import fs18 from "node:fs";
6592
+ import path25 from "node:path";
6543
6593
  function folderKey(root) {
6544
- const dir = path24.join(root, ".halo", "skills");
6594
+ const dir = path25.join(root, ".halo", "skills");
6545
6595
  let ids;
6546
6596
  try {
6547
- ids = fs17.readdirSync(dir).sort();
6597
+ ids = fs18.readdirSync(dir).sort();
6548
6598
  } catch {
6549
6599
  return "";
6550
6600
  }
6551
6601
  return ids.map((id) => {
6552
6602
  let fm = "";
6553
6603
  try {
6554
- fm = fs17.readFileSync(path24.join(dir, id, "SKILL.md"), "utf-8").match(/^---\s*\n([\s\S]*?)\n---/)?.[1] ?? "";
6604
+ fm = fs18.readFileSync(path25.join(dir, id, "SKILL.md"), "utf-8").match(/^---\s*\n([\s\S]*?)\n---/)?.[1] ?? "";
6555
6605
  } catch {
6556
6606
  }
6557
6607
  return `${id}\0${fm}`;
6558
6608
  }).join("\n");
6559
6609
  }
6560
6610
  function skillFoldersChanged(root) {
6561
- const resolved = path24.resolve(root);
6611
+ const resolved = path25.resolve(root);
6562
6612
  const key = folderKey(resolved);
6563
6613
  if (folderKeys.get(resolved) === key)
6564
6614
  return false;
@@ -6774,12 +6824,12 @@ var init_i18n = __esm({
6774
6824
  import Database2 from "better-sqlite3";
6775
6825
  import { drizzle as drizzle2 } from "drizzle-orm/better-sqlite3";
6776
6826
  import { sqliteTable as sqliteTable2, text as text2, integer as integer2 } from "drizzle-orm/sqlite-core";
6777
- import path25 from "node:path";
6778
- import fs18 from "node:fs";
6827
+ import path26 from "node:path";
6828
+ import fs19 from "node:fs";
6779
6829
  function createChannelDb(secretsDir2) {
6780
- const channelsDir = path25.join(secretsDir2, "channels");
6781
- fs18.mkdirSync(channelsDir, { recursive: true });
6782
- const dbPath = path25.join(channelsDir, "channels.db");
6830
+ const channelsDir = path26.join(secretsDir2, "channels");
6831
+ fs19.mkdirSync(channelsDir, { recursive: true });
6832
+ const dbPath = path26.join(channelsDir, "channels.db");
6783
6833
  const sqlite = new Database2(dbPath);
6784
6834
  sqlite.pragma("journal_mode = WAL");
6785
6835
  sqlite.exec(CREATE_SQL);
@@ -6831,11 +6881,11 @@ CREATE INDEX IF NOT EXISTS idx_channel_accounts_type ON channel_accounts(channel
6831
6881
  });
6832
6882
 
6833
6883
  // ../server/dist/channels/shared/accounts.js
6834
- import fs19 from "node:fs";
6835
- import path26 from "node:path";
6884
+ import fs20 from "node:fs";
6885
+ import path27 from "node:path";
6836
6886
  import { eq as eq5, and as and4 } from "drizzle-orm";
6837
6887
  function resolveAccountWorkspace(account) {
6838
- if (!fs19.existsSync(account.workspacePath))
6888
+ if (!fs20.existsSync(account.workspacePath))
6839
6889
  return null;
6840
6890
  ensureWorkspaceHalo(account.workspacePath);
6841
6891
  return account.workspacePath;
@@ -6851,9 +6901,9 @@ function accessLevelError(value, allowed) {
6851
6901
  return `accessLevel must be one of: ${allowed.join(", ")}`;
6852
6902
  }
6853
6903
  function validateWorkspaceBody(workspacePath) {
6854
- if (!path26.isAbsolute(workspacePath))
6904
+ if (!path27.isAbsolute(workspacePath))
6855
6905
  return "workspacePath must be absolute";
6856
- if (!fs19.existsSync(workspacePath))
6906
+ if (!fs20.existsSync(workspacePath))
6857
6907
  return "workspace path not found";
6858
6908
  ensureWorkspaceHalo(workspacePath);
6859
6909
  return null;
@@ -7096,17 +7146,17 @@ var init_commands = __esm({
7096
7146
  });
7097
7147
 
7098
7148
  // ../server/dist/commands/skill-command.js
7099
- import fs20 from "node:fs/promises";
7100
- import path27 from "node:path";
7149
+ import fs21 from "node:fs/promises";
7150
+ import path28 from "node:path";
7101
7151
  async function readEntries(dirs) {
7102
7152
  const entries = [];
7103
7153
  for (const { id: entryName, dir: skillDir } of dirs) {
7104
- const skillMdPath = path27.join(skillDir, "SKILL.md");
7154
+ const skillMdPath = path28.join(skillDir, "SKILL.md");
7105
7155
  try {
7106
- const { mtimeMs } = await fs20.stat(skillMdPath);
7156
+ const { mtimeMs } = await fs21.stat(skillMdPath);
7107
7157
  let fm = _frontmatterCache.get(skillMdPath, mtimeMs);
7108
7158
  if (!fm) {
7109
- const { name: name2, description: description2, command: command2, requiresAccess: requiresAccess2, verbs: verbs2, userInvocable: userInvocable2 } = parseSkillFrontmatter(await fs20.readFile(skillMdPath, "utf-8"));
7159
+ const { name: name2, description: description2, command: command2, requiresAccess: requiresAccess2, verbs: verbs2, userInvocable: userInvocable2 } = parseSkillFrontmatter(await fs21.readFile(skillMdPath, "utf-8"));
7110
7160
  fm = _frontmatterCache.set(skillMdPath, mtimeMs, { name: name2, description: description2, command: command2, requiresAccess: requiresAccess2, verbs: verbs2, userInvocable: userInvocable2 });
7111
7161
  }
7112
7162
  const { name, description, command, requiresAccess, verbs, userInvocable } = fm;
@@ -7193,7 +7243,7 @@ async function execSkillCommand(slashCommand, args, sm, sessionId, workspaceRoot
7193
7243
  let body = "";
7194
7244
  let freshRequiresAccess;
7195
7245
  try {
7196
- const raw = await fs20.readFile(entry.skillPath, "utf-8");
7246
+ const raw = await fs21.readFile(entry.skillPath, "utf-8");
7197
7247
  const parsed = parseSkillFrontmatter(raw);
7198
7248
  body = parsed.body;
7199
7249
  freshRequiresAccess = parsed.requiresAccess;
@@ -7239,11 +7289,11 @@ var init_skill_command = __esm({
7239
7289
  import Database3 from "better-sqlite3";
7240
7290
  import { drizzle as drizzle3 } from "drizzle-orm/better-sqlite3";
7241
7291
  import { sqliteTable as sqliteTable3, text as text3, integer as integer3 } from "drizzle-orm/sqlite-core";
7242
- import path28 from "node:path";
7243
- import fs21 from "node:fs";
7292
+ import path29 from "node:path";
7293
+ import fs22 from "node:fs";
7244
7294
  function createEvoDb(globalDir2) {
7245
- fs21.mkdirSync(globalDir2, { recursive: true });
7246
- const dbPath = path28.join(globalDir2, "evo.db");
7295
+ fs22.mkdirSync(globalDir2, { recursive: true });
7296
+ const dbPath = path29.join(globalDir2, "evo.db");
7247
7297
  const sqlite = new Database3(dbPath);
7248
7298
  sqlite.pragma("journal_mode = WAL");
7249
7299
  sqlite.exec(CREATE_SQL2);
@@ -7344,23 +7394,23 @@ CREATE INDEX IF NOT EXISTS idx_evo_applies_archived ON evolution_applies(archive
7344
7394
  });
7345
7395
 
7346
7396
  // ../server/dist/evolution/enqueue.js
7347
- import fs22 from "node:fs";
7348
- import path29 from "node:path";
7397
+ import fs23 from "node:fs";
7398
+ import path30 from "node:path";
7349
7399
  import { homedir as homedir11 } from "node:os";
7350
7400
  function listMdFiles(rootDir) {
7351
- if (!fs22.existsSync(rootDir))
7401
+ if (!fs23.existsSync(rootDir))
7352
7402
  return [];
7353
7403
  const out = [];
7354
7404
  function walk(dir, prefix) {
7355
7405
  let entries;
7356
7406
  try {
7357
- entries = fs22.readdirSync(dir, { withFileTypes: true });
7407
+ entries = fs23.readdirSync(dir, { withFileTypes: true });
7358
7408
  } catch {
7359
7409
  return;
7360
7410
  }
7361
7411
  for (const e of entries) {
7362
7412
  const rel = prefix ? `${prefix}/${e.name}` : e.name;
7363
- const abs = path29.join(dir, e.name);
7413
+ const abs = path30.join(dir, e.name);
7364
7414
  if (e.isDirectory())
7365
7415
  walk(abs, rel);
7366
7416
  else if (e.isFile() && e.name.endsWith(".md"))
@@ -7372,62 +7422,62 @@ function listMdFiles(rootDir) {
7372
7422
  }
7373
7423
  function readFileOrEmpty(p) {
7374
7424
  try {
7375
- return fs22.readFileSync(p, "utf-8");
7425
+ return fs23.readFileSync(p, "utf-8");
7376
7426
  } catch {
7377
7427
  return "";
7378
7428
  }
7379
7429
  }
7380
7430
  function snapshotPromptSurface(workspacePath, agentId) {
7381
7431
  const out = [];
7382
- const wsHalo = path29.join(workspacePath, ".halo");
7383
- const globalHalo = path29.join(homedir11(), ".halo", "global");
7384
- if (fs22.existsSync(path29.join(wsHalo, "INSTRUCTIONS.md"))) {
7432
+ const wsHalo = path30.join(workspacePath, ".halo");
7433
+ const globalHalo = path30.join(homedir11(), ".halo", "global");
7434
+ if (fs23.existsSync(path30.join(wsHalo, "INSTRUCTIONS.md"))) {
7385
7435
  out.push({
7386
7436
  scope: "workspace",
7387
7437
  path: "INSTRUCTIONS.md",
7388
- content: readFileOrEmpty(path29.join(wsHalo, "INSTRUCTIONS.md"))
7438
+ content: readFileOrEmpty(path30.join(wsHalo, "INSTRUCTIONS.md"))
7389
7439
  });
7390
7440
  }
7391
- if (fs22.existsSync(path29.join(globalHalo, "INSTRUCTIONS.md"))) {
7441
+ if (fs23.existsSync(path30.join(globalHalo, "INSTRUCTIONS.md"))) {
7392
7442
  out.push({
7393
7443
  scope: "global",
7394
7444
  path: "INSTRUCTIONS.md",
7395
- content: readFileOrEmpty(path29.join(globalHalo, "INSTRUCTIONS.md"))
7445
+ content: readFileOrEmpty(path30.join(globalHalo, "INSTRUCTIONS.md"))
7396
7446
  });
7397
7447
  }
7398
- if (fs22.existsSync(path29.join(wsHalo, "USER.md"))) {
7448
+ if (fs23.existsSync(path30.join(wsHalo, "USER.md"))) {
7399
7449
  out.push({
7400
7450
  scope: "workspace",
7401
7451
  path: "USER.md",
7402
- content: readFileOrEmpty(path29.join(wsHalo, "USER.md"))
7452
+ content: readFileOrEmpty(path30.join(wsHalo, "USER.md"))
7403
7453
  });
7404
7454
  }
7405
- if (fs22.existsSync(path29.join(globalHalo, "USER.md"))) {
7455
+ if (fs23.existsSync(path30.join(globalHalo, "USER.md"))) {
7406
7456
  out.push({
7407
7457
  scope: "global",
7408
7458
  path: "USER.md",
7409
- content: readFileOrEmpty(path29.join(globalHalo, "USER.md"))
7459
+ content: readFileOrEmpty(path30.join(globalHalo, "USER.md"))
7410
7460
  });
7411
7461
  }
7412
- if (fs22.existsSync(path29.join(wsHalo, "INDEX.md"))) {
7462
+ if (fs23.existsSync(path30.join(wsHalo, "INDEX.md"))) {
7413
7463
  out.push({
7414
7464
  scope: "workspace",
7415
7465
  path: "INDEX.md",
7416
- content: readFileOrEmpty(path29.join(wsHalo, "INDEX.md"))
7466
+ content: readFileOrEmpty(path30.join(wsHalo, "INDEX.md"))
7417
7467
  });
7418
7468
  }
7419
7469
  for (const scope of ["workspace", "global"]) {
7420
7470
  const base = scope === "workspace" ? wsHalo : globalHalo;
7421
- const agentMd = path29.join(base, "agents", agentId, "AGENT.md");
7422
- const agentYaml = path29.join(base, "agents", agentId, "agent.yaml");
7423
- if (fs22.existsSync(agentMd)) {
7471
+ const agentMd = path30.join(base, "agents", agentId, "AGENT.md");
7472
+ const agentYaml = path30.join(base, "agents", agentId, "agent.yaml");
7473
+ if (fs23.existsSync(agentMd)) {
7424
7474
  out.push({
7425
7475
  scope,
7426
7476
  path: `agents/${agentId}/AGENT.md`,
7427
7477
  content: readFileOrEmpty(agentMd)
7428
7478
  });
7429
7479
  }
7430
- if (fs22.existsSync(agentYaml)) {
7480
+ if (fs23.existsSync(agentYaml)) {
7431
7481
  out.push({
7432
7482
  scope,
7433
7483
  path: `agents/${agentId}/agent.yaml`,
@@ -7438,12 +7488,12 @@ function snapshotPromptSurface(workspacePath, agentId) {
7438
7488
  for (const promptScope of ["all", "root"]) {
7439
7489
  for (const fsScope of ["workspace", "global"]) {
7440
7490
  const base = fsScope === "workspace" ? wsHalo : globalHalo;
7441
- const dir = path29.join(base, "prompts", promptScope);
7491
+ const dir = path30.join(base, "prompts", promptScope);
7442
7492
  for (const rel of listMdFiles(dir)) {
7443
7493
  out.push({
7444
7494
  scope: fsScope,
7445
7495
  path: `prompts/${promptScope}/${rel}`,
7446
- content: readFileOrEmpty(path29.join(dir, rel))
7496
+ content: readFileOrEmpty(path30.join(dir, rel))
7447
7497
  });
7448
7498
  }
7449
7499
  }
@@ -7452,11 +7502,11 @@ function snapshotPromptSurface(workspacePath, agentId) {
7452
7502
  }
7453
7503
  function listAgentsAndSkills(workspacePath) {
7454
7504
  function listDir(base, kind, scope) {
7455
- const dir = kind === "agent" ? path29.join(base, "agents") : path29.join(base, "skills");
7456
- if (!fs22.existsSync(dir))
7505
+ const dir = kind === "agent" ? path30.join(base, "agents") : path30.join(base, "skills");
7506
+ if (!fs23.existsSync(dir))
7457
7507
  return [];
7458
7508
  const yamlName = kind === "agent" ? "agent.yaml" : "SKILL.md";
7459
- return fs22.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && fs22.existsSync(path29.join(dir, e.name, yamlName))).map((e) => ({
7509
+ return fs23.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && fs23.existsSync(path30.join(dir, e.name, yamlName))).map((e) => ({
7460
7510
  id: e.name,
7461
7511
  // Agents whose id is `__xxx__` are platform-internal; surface that
7462
7512
  // distinction so evo knows it can't legitimately propose a patch
@@ -7464,13 +7514,13 @@ function listAgentsAndSkills(workspacePath) {
7464
7514
  scope: e.name.startsWith("__") && e.name.endsWith("__") ? "builtin" : scope
7465
7515
  }));
7466
7516
  }
7467
- const wsHalo = path29.join(workspacePath, ".halo");
7468
- const globalHalo = path29.join(homedir11(), ".halo", "global");
7517
+ const wsHalo = path30.join(workspacePath, ".halo");
7518
+ const globalHalo = path30.join(homedir11(), ".halo", "global");
7469
7519
  const agents = [
7470
7520
  ...listDir(wsHalo, "agent", "workspace"),
7471
7521
  ...listDir(globalHalo, "agent", "global")
7472
7522
  ];
7473
- const skills = listSkillDirs(workspacePath).filter((s) => !s.overridden && s.scope !== "extension" && fs22.existsSync(path29.join(s.dir, "SKILL.md"))).map((s) => ({ id: s.id, scope: s.id.startsWith("__") && s.id.endsWith("__") ? "builtin" : s.scope }));
7523
+ const skills = listSkillDirs(workspacePath).filter((s) => !s.overridden && s.scope !== "extension" && fs23.existsSync(path30.join(s.dir, "SKILL.md"))).map((s) => ({ id: s.id, scope: s.id.startsWith("__") && s.id.endsWith("__") ? "builtin" : s.scope }));
7474
7524
  function dedup(arr) {
7475
7525
  const seen = /* @__PURE__ */ new Set();
7476
7526
  const out = [];
@@ -7583,11 +7633,11 @@ function enqueueEvoRun(input) {
7583
7633
  return { ok: false, reason: "session_missing", error: `session ${sourceSessionId} not found` };
7584
7634
  }
7585
7635
  try {
7586
- fs22.mkdirSync(runDir, { recursive: true });
7636
+ fs23.mkdirSync(runDir, { recursive: true });
7587
7637
  const rawMessages = sm.getSessionRawMessages(sourceSessionId);
7588
- fs22.writeFileSync(path29.join(runDir, "source-snapshot.json"), JSON.stringify({ sessionId: sourceSessionId, agentId: info.agentId, capturedAt: ts, rawMessages }, null, 2), "utf-8");
7589
- fs22.writeFileSync(path29.join(runDir, "tool-flow.md"), renderToolFlow(rawMessages), "utf-8");
7590
- fs22.writeFileSync(path29.join(runDir, "meta.json"), JSON.stringify({
7638
+ fs23.writeFileSync(path30.join(runDir, "source-snapshot.json"), JSON.stringify({ sessionId: sourceSessionId, agentId: info.agentId, capturedAt: ts, rawMessages }, null, 2), "utf-8");
7639
+ fs23.writeFileSync(path30.join(runDir, "tool-flow.md"), renderToolFlow(rawMessages), "utf-8");
7640
+ fs23.writeFileSync(path30.join(runDir, "meta.json"), JSON.stringify({
7591
7641
  id: runId,
7592
7642
  triggerKind: trigger,
7593
7643
  sourceSession: sourceSessionId,
@@ -7601,7 +7651,7 @@ function enqueueEvoRun(input) {
7601
7651
  promptFiles: snapshotPromptSurface(workspacePath, info.agentId),
7602
7652
  ...listAgentsAndSkills(workspacePath)
7603
7653
  };
7604
- fs22.writeFileSync(path29.join(runDir, "evo-context.json"), JSON.stringify(evoContext, null, 2), "utf-8");
7654
+ fs23.writeFileSync(path30.join(runDir, "evo-context.json"), JSON.stringify(evoContext, null, 2), "utf-8");
7605
7655
  } catch (err) {
7606
7656
  return { ok: false, reason: "snapshot_failed", error: err instanceof Error ? err.message : String(err) };
7607
7657
  }
@@ -7617,7 +7667,7 @@ function enqueueEvoRun(input) {
7617
7667
  }).run();
7618
7668
  } catch (err) {
7619
7669
  try {
7620
- fs22.rmSync(runDir, { recursive: true, force: true });
7670
+ fs23.rmSync(runDir, { recursive: true, force: true });
7621
7671
  } catch {
7622
7672
  }
7623
7673
  return { ok: false, reason: "queue_failed", error: err instanceof Error ? err.message : String(err) };
@@ -7634,18 +7684,18 @@ var init_enqueue = __esm({
7634
7684
  });
7635
7685
 
7636
7686
  // ../server/dist/channels/shared/commands.js
7637
- import fs23 from "node:fs";
7638
- import path30 from "node:path";
7687
+ import fs24 from "node:fs";
7688
+ import path31 from "node:path";
7639
7689
  import os2 from "node:os";
7640
- import YAML7 from "yaml";
7690
+ import YAML8 from "yaml";
7641
7691
  function loadAliases() {
7642
7692
  try {
7643
- const stat = fs23.statSync(ALIASES_FILE);
7693
+ const stat = fs24.statSync(ALIASES_FILE);
7644
7694
  const mtime = stat.mtimeMs;
7645
7695
  if (aliasCache && aliasCache.mtime === mtime)
7646
7696
  return aliasCache;
7647
- const raw = fs23.readFileSync(ALIASES_FILE, "utf-8");
7648
- const parsed = YAML7.parse(raw) ?? {};
7697
+ const raw = fs24.readFileSync(ALIASES_FILE, "utf-8");
7698
+ const parsed = YAML8.parse(raw) ?? {};
7649
7699
  aliasCache = { mtime, top: parsed.top ?? {}, verb: parsed.verb ?? {} };
7650
7700
  return aliasCache;
7651
7701
  } catch {
@@ -7986,7 +8036,7 @@ ${formatGoalStatus(active.goalSessionId, active.state, ctx.lang)}` };
7986
8036
  } catch (err) {
7987
8037
  return { text: t("goal.create_failed", ctx.lang, { error: err instanceof Error ? err.message : String(err) }) };
7988
8038
  }
7989
- fs23.mkdirSync(goalDir(ctx.workspacePath, gId), { recursive: true });
8039
+ fs24.mkdirSync(goalDir(ctx.workspacePath, gId), { recursive: true });
7990
8040
  writeGoalState(ctx.sm.getDb(), gId, initialGoalState(gId, workerId));
7991
8041
  setWorkerBackptr(ctx.sm.getDb(), workerId, gId);
7992
8042
  const hint = arg.trim();
@@ -8197,9 +8247,9 @@ async function execAgentDelete(ctx, arg) {
8197
8247
  const agent = resolveAgent(agents, arg);
8198
8248
  if (!agent)
8199
8249
  return { text: t("agent.not_found", ctx.lang, { name: arg }) };
8200
- const dir = agent.scope === "workspace" ? path30.join(ctx.workspacePath, ".halo", "agents", agent.id) : path30.join(GLOBAL_AGENTS_DIR2, agent.id);
8250
+ const dir = agent.scope === "workspace" ? path31.join(ctx.workspacePath, ".halo", "agents", agent.id) : path31.join(GLOBAL_AGENTS_DIR2, agent.id);
8201
8251
  try {
8202
- fs23.rmSync(dir, { recursive: true, force: true });
8252
+ fs24.rmSync(dir, { recursive: true, force: true });
8203
8253
  return { text: t("agent.delete_done", ctx.lang, { name: agent.name, scope: agent.scope }) };
8204
8254
  } catch (err) {
8205
8255
  return { text: t("agent.failed", ctx.lang, { error: err instanceof Error ? err.message : String(err) }) };
@@ -8209,11 +8259,11 @@ function scanSkills(ctx) {
8209
8259
  const disabledSet = getDisabledSet(ctx.sm.getDb(), "skill");
8210
8260
  const out = [];
8211
8261
  for (const { id, dir, scope, extId, overridden } of listSkillDirs(ctx.workspacePath)) {
8212
- const mdPath = path30.join(dir, "SKILL.md");
8213
- if (!fs23.existsSync(mdPath))
8262
+ const mdPath = path31.join(dir, "SKILL.md");
8263
+ if (!fs24.existsSync(mdPath))
8214
8264
  continue;
8215
8265
  try {
8216
- const { name, description } = parseSkillFrontmatter(fs23.readFileSync(mdPath, "utf-8"));
8266
+ const { name, description } = parseSkillFrontmatter(fs24.readFileSync(mdPath, "utf-8"));
8217
8267
  out.push({
8218
8268
  id,
8219
8269
  name: name || id,
@@ -8300,9 +8350,9 @@ function execSkillDelete(ctx, arg) {
8300
8350
  return { text: t("skill.not_found", ctx.lang, { name: arg }) };
8301
8351
  if (skill.scope === "extension")
8302
8352
  return { text: t("skill.delete_extension", ctx.lang, { name: skill.id, ext: skill.extId ?? "" }) };
8303
- const dir = skill.scope === "workspace" ? path30.join(ctx.workspacePath, ".halo", "skills", skill.id) : path30.join(GLOBAL_SKILLS_DIR, skill.id);
8353
+ const dir = skill.scope === "workspace" ? path31.join(ctx.workspacePath, ".halo", "skills", skill.id) : path31.join(GLOBAL_SKILLS_DIR, skill.id);
8304
8354
  try {
8305
- fs23.rmSync(dir, { recursive: true, force: true });
8355
+ fs24.rmSync(dir, { recursive: true, force: true });
8306
8356
  notifySkillsChanged(skill.scope === "workspace" ? ctx.workspacePath : null);
8307
8357
  return { text: t("skill.delete_done", ctx.lang, { name: skill.id, scope: skill.scope }) };
8308
8358
  } catch (err) {
@@ -8365,11 +8415,11 @@ function execWsSwitch(ctx, arg) {
8365
8415
  return { text: t("workspace.switch_usage", ctx.lang) };
8366
8416
  let target = arg.trim();
8367
8417
  if (target.startsWith("~/")) {
8368
- target = path30.join(os2.homedir(), target.slice(2));
8418
+ target = path31.join(os2.homedir(), target.slice(2));
8369
8419
  } else if (!target.startsWith("/")) {
8370
- target = path30.join(os2.homedir(), target);
8420
+ target = path31.join(os2.homedir(), target);
8371
8421
  }
8372
- if (!fs23.existsSync(target))
8422
+ if (!fs24.existsSync(target))
8373
8423
  return { text: t("workspace.not_found", ctx.lang, { path: target }) };
8374
8424
  if (target === ctx.workspacePath)
8375
8425
  return { text: t("workspace.same", ctx.lang) };
@@ -8393,7 +8443,7 @@ var init_commands2 = __esm({
8393
8443
  init_config();
8394
8444
  init_enqueue();
8395
8445
  init_goal_mode();
8396
- ALIASES_FILE = path30.join(os2.homedir(), ".halo", "global", "aliases.yaml");
8446
+ ALIASES_FILE = path31.join(os2.homedir(), ".halo", "global", "aliases.yaml");
8397
8447
  aliasCache = null;
8398
8448
  CHANNEL_LIST_LIMIT = 50;
8399
8449
  DISPATCH_COMMANDS = [
@@ -8461,11 +8511,11 @@ var init_commands2 = __esm({
8461
8511
 
8462
8512
  // ../server/dist/db/a2a-db.js
8463
8513
  import Database4 from "better-sqlite3";
8464
- import path31 from "node:path";
8465
- import fs24 from "node:fs";
8514
+ import path32 from "node:path";
8515
+ import fs25 from "node:fs";
8466
8516
  function createA2ADb(globalDir2) {
8467
- fs24.mkdirSync(globalDir2, { recursive: true });
8468
- const sqlite = new Database4(path31.join(globalDir2, "a2a.db"));
8517
+ fs25.mkdirSync(globalDir2, { recursive: true });
8518
+ const sqlite = new Database4(path32.join(globalDir2, "a2a.db"));
8469
8519
  sqlite.pragma("journal_mode = WAL");
8470
8520
  applyCommitDurability(sqlite, globalDir2);
8471
8521
  sqlite.exec(CREATE_SQL3);
@@ -9029,8 +9079,8 @@ var init_workspace = __esm({
9029
9079
  });
9030
9080
 
9031
9081
  // ../core/dist/workspace/git-manager.js
9032
- import path32 from "node:path";
9033
- import { promises as fs25 } from "node:fs";
9082
+ import path33 from "node:path";
9083
+ import { promises as fs26 } from "node:fs";
9034
9084
  import simpleGit from "simple-git";
9035
9085
  var GitManagerError, GitManager;
9036
9086
  var init_git_manager = __esm({
@@ -9064,8 +9114,8 @@ var init_git_manager = __esm({
9064
9114
  const top = (await this.git.revparse(["--show-toplevel"])).trim();
9065
9115
  if (!top)
9066
9116
  return false;
9067
- const here = await fs25.realpath(this.workspace.projectRoot);
9068
- return path32.resolve(top) === path32.resolve(here);
9117
+ const here = await fs26.realpath(this.workspace.projectRoot);
9118
+ return path33.resolve(top) === path33.resolve(here);
9069
9119
  } catch {
9070
9120
  return false;
9071
9121
  }
@@ -9448,8 +9498,8 @@ var init_dist = __esm({
9448
9498
  });
9449
9499
 
9450
9500
  // ../server/dist/channels/shared/media-store.js
9451
- import fs26 from "node:fs/promises";
9452
- import path33 from "node:path";
9501
+ import fs27 from "node:fs/promises";
9502
+ import path34 from "node:path";
9453
9503
  import { randomBytes } from "node:crypto";
9454
9504
  function sniffImageMime(buf) {
9455
9505
  if (buf.length >= 4 && buf[0] === 255 && buf[1] === 216)
@@ -9494,8 +9544,8 @@ async function saveInboundMedia(params) {
9494
9544
  const mm = String(date.getMonth() + 1).padStart(2, "0");
9495
9545
  const dd = String(date.getDate()).padStart(2, "0");
9496
9546
  const channel = params.channel ?? "weixin";
9497
- const dir = path33.join(params.workspacePath, ".halo", "assets", channel, "inbound", params.accountId, `${yyyy}-${mm}-${dd}`);
9498
- await fs26.mkdir(dir, { recursive: true });
9547
+ const dir = path34.join(params.workspacePath, ".halo", "assets", channel, "inbound", params.accountId, `${yyyy}-${mm}-${dd}`);
9548
+ await fs27.mkdir(dir, { recursive: true });
9499
9549
  const ts = `${date.getHours().toString().padStart(2, "0")}${date.getMinutes().toString().padStart(2, "0")}${date.getSeconds().toString().padStart(2, "0")}`;
9500
9550
  const suffix = randomBytes(3).toString("hex");
9501
9551
  let filename;
@@ -9505,8 +9555,8 @@ async function saveInboundMedia(params) {
9505
9555
  const ext = params.mimeType ? extForMime(params.mimeType) ?? inferExtFromBytes(params.buffer) : inferExtFromBytes(params.buffer);
9506
9556
  filename = `${params.kind}_${ts}_${suffix}${ext}`;
9507
9557
  }
9508
- const fullPath = path33.join(dir, filename);
9509
- await fs26.writeFile(fullPath, params.buffer);
9558
+ const fullPath = path34.join(dir, filename);
9559
+ await fs27.writeFile(fullPath, params.buffer);
9510
9560
  return fullPath;
9511
9561
  }
9512
9562
  var VISION_IMAGE_MIME_TYPES, EXT_BY_AV_MIME;
@@ -9530,15 +9580,15 @@ var init_media_store = __esm({
9530
9580
  });
9531
9581
 
9532
9582
  // ../server/dist/channels/shared/media.js
9533
- import path34 from "node:path";
9583
+ import path35 from "node:path";
9534
9584
  import os3 from "node:os";
9535
9585
  function tempDir() {
9536
- return path34.resolve(os3.tmpdir());
9586
+ return path35.resolve(os3.tmpdir());
9537
9587
  }
9538
9588
  function isInTempDir(filePath) {
9539
- const resolved = path34.resolve(filePath);
9589
+ const resolved = path35.resolve(filePath);
9540
9590
  const tmp = tempDir();
9541
- return resolved === tmp || resolved.startsWith(tmp + path34.sep);
9591
+ return resolved === tmp || resolved.startsWith(tmp + path35.sep);
9542
9592
  }
9543
9593
  function extractMediaPaths(text6) {
9544
9594
  const mediaPaths = [];
@@ -9556,9 +9606,9 @@ function extractMediaMessage(text6) {
9556
9606
  function isMediaPathAllowed(filePath, workspacePath, accessLevel) {
9557
9607
  if (accessLevel === "full")
9558
9608
  return true;
9559
- const resolved = path34.resolve(filePath);
9560
- const ws = path34.resolve(workspacePath);
9561
- return resolved === ws || resolved.startsWith(ws + path34.sep) || isInTempDir(resolved);
9609
+ const resolved = path35.resolve(filePath);
9610
+ const ws = path35.resolve(workspacePath);
9611
+ return resolved === ws || resolved.startsWith(ws + path35.sep) || isInTempDir(resolved);
9562
9612
  }
9563
9613
  function assertMediaPathAllowed(filePath, account) {
9564
9614
  if (!isMediaPathAllowed(filePath, account.workspacePath, account.accessLevel)) {
@@ -9573,12 +9623,12 @@ async function sendMediaOrReport(opts) {
9573
9623
  } catch (err) {
9574
9624
  const error = err instanceof Error ? err.message : String(err);
9575
9625
  console.log(`[${opts.logTag}] sendMedia ${filePath} failed: ${error}`);
9576
- await opts.reply(t("handler.upload_failed", getLang(account), { name: path34.basename(filePath), error })).catch(() => {
9626
+ await opts.reply(t("handler.upload_failed", getLang(account), { name: path35.basename(filePath), error })).catch(() => {
9577
9627
  });
9578
9628
  }
9579
9629
  }
9580
9630
  function classifyMedia(filePath) {
9581
- const ext = path34.extname(filePath).toLowerCase();
9631
+ const ext = path35.extname(filePath).toLowerCase();
9582
9632
  if (IMAGE_EXTS.has(ext))
9583
9633
  return "image";
9584
9634
  if (VIDEO_EXTS.has(ext))
@@ -9600,8 +9650,8 @@ var init_media = __esm({
9600
9650
  });
9601
9651
 
9602
9652
  // ../server/dist/a2a/files.js
9603
- import fs27 from "node:fs";
9604
- import path35 from "node:path";
9653
+ import fs28 from "node:fs";
9654
+ import path36 from "node:path";
9605
9655
  function normalizeMime(v) {
9606
9656
  return typeof v === "string" ? v.split(";", 1)[0].trim().toLowerCase() : "";
9607
9657
  }
@@ -9683,7 +9733,7 @@ async function fetchImageUrls(images) {
9683
9733
  return out;
9684
9734
  }
9685
9735
  function saveImage(workspace, accountId, img) {
9686
- const keepName = img.filename && imageMimeFromExt(path35.extname(img.filename)) === img.mediaType;
9736
+ const keepName = img.filename && imageMimeFromExt(path36.extname(img.filename)) === img.mediaType;
9687
9737
  return saveInboundMedia({
9688
9738
  workspacePath: workspace,
9689
9739
  accountId,
@@ -9695,12 +9745,12 @@ function saveImage(workspace, accountId, img) {
9695
9745
  });
9696
9746
  }
9697
9747
  function readImageFile(filePath, budget) {
9698
- const mediaType = imageMimeFromExt(path35.extname(filePath)) ?? "";
9748
+ const mediaType = imageMimeFromExt(path36.extname(filePath)) ?? "";
9699
9749
  if (!isImageMime(mediaType))
9700
9750
  return { reason: `not a supported image (${SUPPORTED})` };
9701
9751
  let st;
9702
9752
  try {
9703
- st = fs27.statSync(filePath);
9753
+ st = fs28.statSync(filePath);
9704
9754
  } catch {
9705
9755
  return { reason: "file not found" };
9706
9756
  }
@@ -9710,14 +9760,14 @@ function readImageFile(filePath, budget) {
9710
9760
  return { reason: `larger than ${mb(MAX_IMAGE_BYTES)}` };
9711
9761
  if (st.size > budget)
9712
9762
  return { reason: `would exceed the ${mb(MAX_IMAGES_TOTAL_BYTES)} total` };
9713
- const buf = fs27.readFileSync(filePath);
9763
+ const buf = fs28.readFileSync(filePath);
9714
9764
  const actual = sniffImageMime(buf);
9715
9765
  if (!actual)
9716
9766
  return { reason: `content is not a ${SUPPORTED} image` };
9717
- return { file: { filename: path35.basename(filePath), mediaType: actual, raw: buf.toString("base64") }, size: buf.length };
9767
+ return { file: { filename: path36.basename(filePath), mediaType: actual, raw: buf.toString("base64") }, size: buf.length };
9718
9768
  }
9719
9769
  function refusedPath(p, workspace, level) {
9720
- if (!path35.isAbsolute(p))
9770
+ if (!path36.isAbsolute(p))
9721
9771
  return "path is not absolute";
9722
9772
  if (level === "full")
9723
9773
  return null;
@@ -9725,13 +9775,13 @@ function refusedPath(p, workspace, level) {
9725
9775
  return "outside the workspace and the temp dir";
9726
9776
  let real;
9727
9777
  try {
9728
- real = fs27.realpathSync(p);
9778
+ real = fs28.realpathSync(p);
9729
9779
  } catch {
9730
9780
  return "file not found";
9731
9781
  }
9732
9782
  let realWs = workspace;
9733
9783
  try {
9734
- realWs = fs27.realpathSync(workspace);
9784
+ realWs = fs28.realpathSync(workspace);
9735
9785
  } catch {
9736
9786
  }
9737
9787
  return isMediaPathAllowed(real, realWs, level) ? null : "links outside the workspace and the temp dir";
@@ -9747,7 +9797,7 @@ function attachResultFiles(text6, workspace, level) {
9747
9797
  const why = refusedPath(p, workspace, level);
9748
9798
  const r = why ? { reason: why } : readImageFile(p, budget);
9749
9799
  if ("reason" in r) {
9750
- notes.push(`[file not attached: ${path35.basename(p)} \u2014 ${r.reason}]`);
9800
+ notes.push(`[file not attached: ${path36.basename(p)} \u2014 ${r.reason}]`);
9751
9801
  continue;
9752
9802
  }
9753
9803
  files.push(r.file);
@@ -10100,8 +10150,8 @@ var init_agentcore_notify = __esm({
10100
10150
 
10101
10151
  // ../server/dist/a2a/invocations.js
10102
10152
  import crypto2 from "node:crypto";
10103
- import fs28 from "node:fs";
10104
- import path36 from "node:path";
10153
+ import fs29 from "node:fs";
10154
+ import path37 from "node:path";
10105
10155
  function onInvocationDone(id, fn) {
10106
10156
  let set = listeners2.get(id);
10107
10157
  if (!set) {
@@ -10148,15 +10198,15 @@ function lookupInvocation(key) {
10148
10198
  return getInvocation(key) ?? findInvocation(key);
10149
10199
  }
10150
10200
  function mediaManifest(text6, workspace) {
10151
- const root = fs28.realpathSync(workspace);
10201
+ const root = fs29.realpathSync(workspace);
10152
10202
  const out = [];
10153
10203
  for (const p of new Set(extractMediaMessage(text6).mediaPaths)) {
10154
- if (!path36.isAbsolute(p))
10204
+ if (!path37.isAbsolute(p))
10155
10205
  continue;
10156
10206
  try {
10157
- if (!fs28.realpathSync(p).startsWith(root + path36.sep))
10207
+ if (!fs29.realpathSync(p).startsWith(root + path37.sep))
10158
10208
  continue;
10159
- const st = fs28.statSync(p);
10209
+ const st = fs29.statSync(p);
10160
10210
  if (st.isFile())
10161
10211
  out.push({ path: p, size: st.size });
10162
10212
  } catch {
@@ -10220,8 +10270,8 @@ var init_invocations = __esm({
10220
10270
  });
10221
10271
 
10222
10272
  // ../server/dist/agents/relay.js
10223
- import fs29 from "node:fs";
10224
- import path37 from "node:path";
10273
+ import fs30 from "node:fs";
10274
+ import path38 from "node:path";
10225
10275
  import { and as and5, eq as eq6, isNull as isNull2 } from "drizzle-orm";
10226
10276
  function setRelayRegistry(r) {
10227
10277
  _registry = r;
@@ -10380,11 +10430,11 @@ function resolveTarget(workspace) {
10380
10430
  return jsonErr2(RELAY_UNAVAILABLE);
10381
10431
  let wsPath;
10382
10432
  try {
10383
- wsPath = fs29.realpathSync(workspace);
10433
+ wsPath = fs30.realpathSync(workspace);
10384
10434
  } catch {
10385
10435
  return jsonErr2(`workspace not found: ${workspace}`);
10386
10436
  }
10387
- if (!fs29.existsSync(path37.join(wsPath, ".halo")))
10437
+ if (!fs30.existsSync(path38.join(wsPath, ".halo")))
10388
10438
  return jsonErr2(`not a halo workspace (no .halo/): ${workspace}`);
10389
10439
  return { wsPath, target: registry2.getOrCreate(wsPath) };
10390
10440
  }
@@ -10563,11 +10613,11 @@ import Database5 from "better-sqlite3";
10563
10613
  import { drizzle as drizzle4 } from "drizzle-orm/better-sqlite3";
10564
10614
  import { sqliteTable as sqliteTable4, text as text4, integer as integer4, primaryKey } from "drizzle-orm/sqlite-core";
10565
10615
  import { and as and6, eq as eq7 } from "drizzle-orm";
10566
- import path38 from "node:path";
10567
- import fs30 from "node:fs";
10616
+ import path39 from "node:path";
10617
+ import fs31 from "node:fs";
10568
10618
  function createRunsDb(globalDir2) {
10569
- fs30.mkdirSync(globalDir2, { recursive: true });
10570
- const dbPath = path38.join(globalDir2, "runs.db");
10619
+ fs31.mkdirSync(globalDir2, { recursive: true });
10620
+ const dbPath = path39.join(globalDir2, "runs.db");
10571
10621
  const sqlite = new Database5(dbPath);
10572
10622
  sqlite.pragma("journal_mode = WAL");
10573
10623
  applyCommitDurability(sqlite, globalDir2);
@@ -10625,14 +10675,14 @@ CREATE TABLE IF NOT EXISTS running_sessions (
10625
10675
  });
10626
10676
 
10627
10677
  // ../server/dist/agents/run-ledger.js
10628
- import fs31 from "node:fs";
10629
- import path39 from "node:path";
10630
- import YAML8 from "yaml";
10678
+ import fs32 from "node:fs";
10679
+ import path40 from "node:path";
10680
+ import YAML9 from "yaml";
10631
10681
  import { eq as eq8 } from "drizzle-orm";
10632
10682
  function isInternalAgent2(agentId, workspaceRoot) {
10633
10683
  try {
10634
- const raw = fs31.readFileSync(path39.join(agentSourceDir(agentId, workspaceRoot), "agent.yaml"), "utf-8");
10635
- return YAML8.parse(raw)?.internal === true;
10684
+ const raw = fs32.readFileSync(path40.join(agentSourceDir(agentId, workspaceRoot), "agent.yaml"), "utf-8");
10685
+ return YAML9.parse(raw)?.internal === true;
10636
10686
  } catch {
10637
10687
  return false;
10638
10688
  }
@@ -10752,8 +10802,8 @@ var init_shutdown = __esm({
10752
10802
  });
10753
10803
 
10754
10804
  // ../server/dist/agents/workspace-runtime-lock.js
10755
- import fs32 from "node:fs";
10756
- import path40 from "node:path";
10805
+ import fs33 from "node:fs";
10806
+ import path41 from "node:path";
10757
10807
  function isPidAlive2(pid) {
10758
10808
  try {
10759
10809
  process.kill(pid, 0);
@@ -10763,9 +10813,9 @@ function isPidAlive2(pid) {
10763
10813
  }
10764
10814
  }
10765
10815
  function claimWorkspaceRuntime(workspaceRoot) {
10766
- const lockPath = path40.join(workspaceRoot, ".halo", RUNTIME_LOCK_FILE);
10816
+ const lockPath = path41.join(workspaceRoot, ".halo", RUNTIME_LOCK_FILE);
10767
10817
  try {
10768
- fs32.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
10818
+ fs33.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
10769
10819
  return true;
10770
10820
  } catch (err) {
10771
10821
  if (err.code !== "EEXIST") {
@@ -10775,7 +10825,7 @@ function claimWorkspaceRuntime(workspaceRoot) {
10775
10825
  }
10776
10826
  let holder = 0;
10777
10827
  try {
10778
- holder = parseInt(fs32.readFileSync(lockPath, "utf-8").trim(), 10) || 0;
10828
+ holder = parseInt(fs33.readFileSync(lockPath, "utf-8").trim(), 10) || 0;
10779
10829
  } catch {
10780
10830
  }
10781
10831
  if (holder === process.pid)
@@ -10784,13 +10834,13 @@ function claimWorkspaceRuntime(workspaceRoot) {
10784
10834
  return false;
10785
10835
  const tmpPath = `${lockPath}.${process.pid}.tmp`;
10786
10836
  try {
10787
- fs32.writeFileSync(tmpPath, String(process.pid));
10788
- fs32.renameSync(tmpPath, lockPath);
10837
+ fs33.writeFileSync(tmpPath, String(process.pid));
10838
+ fs33.renameSync(tmpPath, lockPath);
10789
10839
  console.debug(`[WorkspaceRuntimeLock] took over stale runtime.lock in ${workspaceRoot} (previous holder pid ${holder || "unreadable"})`);
10790
10840
  return true;
10791
10841
  } catch (renameErr) {
10792
10842
  try {
10793
- fs32.unlinkSync(tmpPath);
10843
+ fs33.unlinkSync(tmpPath);
10794
10844
  } catch {
10795
10845
  }
10796
10846
  console.warn(`[WorkspaceRuntimeLock] stale takeover failed for ${lockPath}: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}`);
@@ -10798,10 +10848,10 @@ function claimWorkspaceRuntime(workspaceRoot) {
10798
10848
  }
10799
10849
  }
10800
10850
  function releaseWorkspaceRuntime(workspaceRoot) {
10801
- const lockPath = path40.join(workspaceRoot, ".halo", RUNTIME_LOCK_FILE);
10851
+ const lockPath = path41.join(workspaceRoot, ".halo", RUNTIME_LOCK_FILE);
10802
10852
  try {
10803
- if (parseInt(fs32.readFileSync(lockPath, "utf-8").trim(), 10) === process.pid)
10804
- fs32.unlinkSync(lockPath);
10853
+ if (parseInt(fs33.readFileSync(lockPath, "utf-8").trim(), 10) === process.pid)
10854
+ fs33.unlinkSync(lockPath);
10805
10855
  } catch {
10806
10856
  }
10807
10857
  }
@@ -13645,9 +13695,9 @@ var init_anthropic_agent = __esm({
13645
13695
  });
13646
13696
 
13647
13697
  // ../server/dist/agents/model-runtime.js
13648
- import path41 from "node:path";
13698
+ import path42 from "node:path";
13649
13699
  function resolveProviderRuntime(providerId) {
13650
- const yamlPath = path41.join(HALO_GLOBAL_DIR, "models", `${providerId}.yaml`);
13700
+ const yamlPath = path42.join(HALO_GLOBAL_DIR, "models", `${providerId}.yaml`);
13651
13701
  const providers2 = getModelsRegistry().providers;
13652
13702
  const entry = providers2.find((p) => p.id === providerId);
13653
13703
  if (!entry) {
@@ -13828,20 +13878,20 @@ var init_model_runtime = __esm({
13828
13878
  });
13829
13879
 
13830
13880
  // ../server/dist/tools/workspace-tools.js
13831
- import fs33 from "node:fs/promises";
13832
- import path42 from "node:path";
13881
+ import fs34 from "node:fs/promises";
13882
+ import path43 from "node:path";
13833
13883
  import crypto3 from "node:crypto";
13834
13884
  import { homedir as homedir12 } from "node:os";
13835
13885
  function resolvePath2(filePath, workspaceRoot) {
13836
- const expanded = filePath.startsWith("~/") ? path42.join(HOME2, filePath.slice(2)) : filePath;
13837
- return path42.isAbsolute(expanded) ? path42.resolve(expanded) : path42.resolve(workspaceRoot, expanded);
13886
+ const expanded = filePath.startsWith("~/") ? path43.join(HOME2, filePath.slice(2)) : filePath;
13887
+ return path43.isAbsolute(expanded) ? path43.resolve(expanded) : path43.resolve(workspaceRoot, expanded);
13838
13888
  }
13839
13889
  async function* walkDir(dir, signal) {
13840
13890
  if (signal?.aborted)
13841
13891
  return;
13842
13892
  let names;
13843
13893
  try {
13844
- names = await fs33.readdir(dir);
13894
+ names = await fs34.readdir(dir);
13845
13895
  } catch {
13846
13896
  return;
13847
13897
  }
@@ -13850,15 +13900,15 @@ async function* walkDir(dir, signal) {
13850
13900
  return;
13851
13901
  if (SKIP_DIRS.has(name))
13852
13902
  continue;
13853
- const fullPath = path42.join(dir, name);
13903
+ const fullPath = path43.join(dir, name);
13854
13904
  let stat;
13855
13905
  try {
13856
- stat = await fs33.lstat(fullPath);
13906
+ stat = await fs34.lstat(fullPath);
13857
13907
  } catch {
13858
13908
  continue;
13859
13909
  }
13860
13910
  if (stat.isDirectory()) {
13861
- if (path42.basename(dir) === ".halo" && SKIP_HALO_SUBDIRS.has(name))
13911
+ if (path43.basename(dir) === ".halo" && SKIP_HALO_SUBDIRS.has(name))
13862
13912
  continue;
13863
13913
  if (process.platform === "win32" && await isReparsePoint(fullPath))
13864
13914
  continue;
@@ -13870,7 +13920,7 @@ async function* walkDir(dir, signal) {
13870
13920
  }
13871
13921
  async function isReparsePoint(dir) {
13872
13922
  try {
13873
- await fs33.readlink(dir);
13923
+ await fs34.readlink(dir);
13874
13924
  return true;
13875
13925
  } catch {
13876
13926
  return false;
@@ -13879,7 +13929,7 @@ async function isReparsePoint(dir) {
13879
13929
  async function isBinaryFile(filePath) {
13880
13930
  let handle = null;
13881
13931
  try {
13882
- handle = await fs33.open(filePath, "r");
13932
+ handle = await fs34.open(filePath, "r");
13883
13933
  const buf = Buffer.alloc(512);
13884
13934
  const { bytesRead } = await handle.read(buf, 0, 512, 0);
13885
13935
  for (let i = 0; i < bytesRead; i++) {
@@ -14086,7 +14136,7 @@ function createWorkspaceTools(workspaceRoot, accessLevelOrOpts = "full") {
14086
14136
  callback: async (_input) => {
14087
14137
  const input = _input;
14088
14138
  const fullPath = resolvePath2(input.path, workspaceRoot);
14089
- const ext = path42.extname(fullPath).toLowerCase();
14139
+ const ext = path43.extname(fullPath).toLowerCase();
14090
14140
  const supportedExts = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp"]);
14091
14141
  if (!supportedExts.has(ext)) {
14092
14142
  return `${TOOL_WARN_MARKER}
@@ -14283,7 +14333,7 @@ Error: old_string appears more than once in ${input.path}. Either expand it with
14283
14333
  const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
14284
14334
  if (entry.isDirectory) {
14285
14335
  results.push(`\u{1F4C1} ${relPath}/`);
14286
- await walk(path42.join(dir, entry.name), relPath);
14336
+ await walk(path43.join(dir, entry.name), relPath);
14287
14337
  } else {
14288
14338
  results.push(`\u{1F4C4} ${relPath}`);
14289
14339
  }
@@ -14397,14 +14447,14 @@ Error: Invalid regex pattern: ${err.message}`;
14397
14447
  const results = [];
14398
14448
  let fileTarget = false;
14399
14449
  try {
14400
- fileTarget = (await fs33.stat(searchDir)).isFile();
14450
+ fileTarget = (await fs34.stat(searchDir)).isFile();
14401
14451
  } catch {
14402
14452
  }
14403
14453
  const files = fileTarget ? [searchDir] : walkDir(searchDir, signal);
14404
14454
  for await (const filePath of files) {
14405
14455
  if (results.length >= maxResults)
14406
14456
  break;
14407
- if (input.include && !matchInclude(path42.basename(filePath), input.include)) {
14457
+ if (input.include && !matchInclude(path43.basename(filePath), input.include)) {
14408
14458
  continue;
14409
14459
  }
14410
14460
  if (await isBinaryFile(filePath))
@@ -14415,7 +14465,7 @@ Error: Invalid regex pattern: ${err.message}`;
14415
14465
  } catch {
14416
14466
  continue;
14417
14467
  }
14418
- const relativePath = path42.relative(workspaceRoot, filePath);
14468
+ const relativePath = path43.relative(workspaceRoot, filePath);
14419
14469
  const lines = content.split("\n");
14420
14470
  for (let i = 0; i < lines.length; i++) {
14421
14471
  if (results.length >= maxResults)
@@ -14460,7 +14510,7 @@ Error: Invalid regex pattern: ${err.message}`;
14460
14510
  for await (const filePath of walkDir(searchDir, signal)) {
14461
14511
  if (results.length >= GLOB_MAX_RESULTS)
14462
14512
  break;
14463
- const relativePath = path42.relative(workspaceRoot, filePath);
14513
+ const relativePath = path43.relative(workspaceRoot, filePath);
14464
14514
  if (matchGlob(relativePath, input.pattern)) {
14465
14515
  results.push(relativePath);
14466
14516
  }
@@ -14586,12 +14636,12 @@ var init_workspace_tools = __esm({
14586
14636
  });
14587
14637
 
14588
14638
  // ../server/dist/prompts/system-prompts.js
14589
- import fs34 from "node:fs/promises";
14590
- import path43 from "node:path";
14639
+ import fs35 from "node:fs/promises";
14640
+ import path44 from "node:path";
14591
14641
  import { homedir as homedir13 } from "node:os";
14592
14642
  async function dirExists(dirPath) {
14593
14643
  try {
14594
- const stat = await fs34.stat(dirPath);
14644
+ const stat = await fs35.stat(dirPath);
14595
14645
  return stat.isDirectory();
14596
14646
  } catch {
14597
14647
  return false;
@@ -14610,7 +14660,7 @@ function selectForPlatform(mdFiles) {
14610
14660
  async function loadDir(dirPath, fallback) {
14611
14661
  let entries;
14612
14662
  try {
14613
- entries = await fs34.readdir(dirPath);
14663
+ entries = await fs35.readdir(dirPath);
14614
14664
  } catch {
14615
14665
  console.log(`[SystemPrompts] Directory missing: ${dirPath} \u2014 using built-in fallback`);
14616
14666
  return { content: fallback, files: [] };
@@ -14623,9 +14673,9 @@ async function loadDir(dirPath, fallback) {
14623
14673
  const chunks = [];
14624
14674
  const loaded = [];
14625
14675
  for (const name of mdFiles) {
14626
- const fullPath = path43.join(dirPath, name);
14676
+ const fullPath = path44.join(dirPath, name);
14627
14677
  try {
14628
- const content = (await fs34.readFile(fullPath, "utf-8")).trim();
14678
+ const content = (await fs35.readFile(fullPath, "utf-8")).trim();
14629
14679
  if (content) {
14630
14680
  chunks.push(content);
14631
14681
  loaded.push(fullPath);
@@ -14640,11 +14690,11 @@ async function loadDir(dirPath, fallback) {
14640
14690
  }
14641
14691
  async function resolvePromptsDir(scope, workspaceRoot) {
14642
14692
  if (workspaceRoot) {
14643
- const wsDir = path43.join(workspaceRoot, ".halo", "prompts", scope);
14693
+ const wsDir = path44.join(workspaceRoot, ".halo", "prompts", scope);
14644
14694
  if (await dirExists(wsDir))
14645
14695
  return wsDir;
14646
14696
  }
14647
- return path43.join(GLOBAL_PROMPTS_DIR, scope);
14697
+ return path44.join(GLOBAL_PROMPTS_DIR, scope);
14648
14698
  }
14649
14699
  async function loadSystemPrompts(workspaceRoot) {
14650
14700
  const [bootstrapDir, allDir, rootDir] = await Promise.all([
@@ -14673,15 +14723,13 @@ var GLOBAL_PROMPTS_DIR;
14673
14723
  var init_system_prompts = __esm({
14674
14724
  "../server/dist/prompts/system-prompts.js"() {
14675
14725
  "use strict";
14676
- GLOBAL_PROMPTS_DIR = path43.join(homedir13(), ".halo", "global", "prompts");
14726
+ GLOBAL_PROMPTS_DIR = path44.join(homedir13(), ".halo", "global", "prompts");
14677
14727
  }
14678
14728
  });
14679
14729
 
14680
14730
  // ../server/dist/a2a/outbound.js
14681
- import fs35 from "node:fs";
14682
- import path44 from "node:path";
14731
+ import fs36 from "node:fs";
14683
14732
  import crypto4 from "node:crypto";
14684
- import YAML9 from "yaml";
14685
14733
  import { Hono } from "hono";
14686
14734
  import { SignatureV4 as SignatureV42 } from "@smithy/signature-v4";
14687
14735
  import { Sha256 as Sha2562 } from "@aws-crypto/sha256-js";
@@ -14695,28 +14743,10 @@ function jsonErr3(error) {
14695
14743
  function errMsg(err) {
14696
14744
  return err instanceof Error ? err.message : String(err);
14697
14745
  }
14698
- function remotesFile() {
14699
- return path44.join(secretsDir(), "a2a-remotes.yaml");
14700
- }
14701
- function loadRemotes() {
14702
- let doc;
14703
- try {
14704
- doc = YAML9.parse(fs35.readFileSync(remotesFile(), "utf8")) ?? {};
14705
- } catch {
14706
- return {};
14707
- }
14708
- const out = {};
14709
- for (const [name, r] of Object.entries(doc.remotes ?? {})) {
14710
- if (!r?.card)
14711
- continue;
14712
- out[name] = { name, card: r.card, auth: r.auth === "sigv4" ? "sigv4" : "bearer", pushBase: r.push_base?.replace(/\/+$/, "") };
14713
- }
14714
- return out;
14715
- }
14716
14746
  function runtimeSessionId(workspace, remoteName) {
14717
14747
  let real = workspace;
14718
14748
  try {
14719
- real = fs35.realpathSync(workspace);
14749
+ real = fs36.realpathSync(workspace);
14720
14750
  } catch {
14721
14751
  }
14722
14752
  return `halo-${crypto4.createHash("sha256").update(`${real}\0${remoteName}`).digest("hex")}`;
@@ -15124,11 +15154,11 @@ var init_outbound = __esm({
15124
15154
  "../server/dist/a2a/outbound.js"() {
15125
15155
  "use strict";
15126
15156
  init_config();
15127
- init_paths();
15128
15157
  init_a2a_db();
15129
15158
  init_relay();
15130
15159
  init_http();
15131
15160
  init_wire();
15161
+ init_remotes();
15132
15162
  init_files();
15133
15163
  TIMEOUT_MS2 = 3e4;
15134
15164
  _registry2 = null;
@@ -15827,7 +15857,7 @@ async function initObservability(haloProcess = "server") {
15827
15857
  return true;
15828
15858
  }
15829
15859
  const { registerSdk: registerSdk2 } = await Promise.resolve().then(() => (init_otel_sdk(), otel_sdk_exports));
15830
- providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.0.2", haloProcess);
15860
+ providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.0.3", haloProcess);
15831
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})`);
15832
15862
  return true;
15833
15863
  }
@@ -18907,7 +18937,7 @@ ${result.summary}`, agentName: "user", report: true, compactSummary: true, taskI
18907
18937
  });
18908
18938
 
18909
18939
  // ../server/dist/agents/session-manager-registry.js
18910
- import fs36 from "node:fs";
18940
+ import fs37 from "node:fs";
18911
18941
  var SessionManagerRegistry;
18912
18942
  var init_session_manager_registry = __esm({
18913
18943
  "../server/dist/agents/session-manager-registry.js"() {
@@ -18936,7 +18966,7 @@ var init_session_manager_registry = __esm({
18936
18966
  return this.opts.reconcileOrphansOnBoot === true;
18937
18967
  }
18938
18968
  getOrCreate(workspacePath) {
18939
- const resolved = fs36.realpathSync(workspacePath);
18969
+ const resolved = fs37.realpathSync(workspacePath);
18940
18970
  const cached2 = this.cache.get(resolved);
18941
18971
  if (cached2)
18942
18972
  return cached2;
@@ -18956,7 +18986,7 @@ var init_session_manager_registry = __esm({
18956
18986
  peek(workspacePath) {
18957
18987
  let resolved;
18958
18988
  try {
18959
- resolved = fs36.realpathSync(workspacePath);
18989
+ resolved = fs37.realpathSync(workspacePath);
18960
18990
  } catch {
18961
18991
  return void 0;
18962
18992
  }
@@ -18975,16 +19005,16 @@ var init_session_manager_registry = __esm({
18975
19005
  });
18976
19006
 
18977
19007
  // ../server/dist/logger.js
18978
- import fs37 from "node:fs";
19008
+ import fs38 from "node:fs";
18979
19009
  import path47 from "node:path";
18980
19010
  import { homedir as homedir14 } from "node:os";
18981
19011
  import { SeverityNumber } from "@opentelemetry/api-logs";
18982
19012
  function ensureDir() {
18983
- fs37.mkdirSync(logDir, { recursive: true });
19013
+ fs38.mkdirSync(logDir, { recursive: true });
18984
19014
  }
18985
19015
  function measureSize() {
18986
19016
  try {
18987
- return fs37.statSync(logFile).size;
19017
+ return fs38.statSync(logFile).size;
18988
19018
  } catch {
18989
19019
  return 0;
18990
19020
  }
@@ -18992,17 +19022,17 @@ function measureSize() {
18992
19022
  function rotate() {
18993
19023
  const maxFiles = config.logging.maxFiles;
18994
19024
  try {
18995
- fs37.unlinkSync(`${logFile}.${maxFiles}`);
19025
+ fs38.unlinkSync(`${logFile}.${maxFiles}`);
18996
19026
  } catch {
18997
19027
  }
18998
19028
  for (let i = maxFiles - 1; i >= 1; i--) {
18999
19029
  try {
19000
- fs37.renameSync(`${logFile}.${i}`, `${logFile}.${i + 1}`);
19030
+ fs38.renameSync(`${logFile}.${i}`, `${logFile}.${i + 1}`);
19001
19031
  } catch {
19002
19032
  }
19003
19033
  }
19004
19034
  try {
19005
- fs37.renameSync(logFile, `${logFile}.1`);
19035
+ fs38.renameSync(logFile, `${logFile}.1`);
19006
19036
  } catch {
19007
19037
  }
19008
19038
  currentSize = 0;
@@ -19014,12 +19044,12 @@ function writeToFile(line) {
19014
19044
  if (currentSize >= config.logging.maxFileSize)
19015
19045
  rotate();
19016
19046
  try {
19017
- fs37.appendFileSync(logFile, line);
19047
+ fs38.appendFileSync(logFile, line);
19018
19048
  } catch (err) {
19019
19049
  if (err.code !== "ENOENT")
19020
19050
  throw err;
19021
19051
  ensureDir();
19022
- fs37.appendFileSync(logFile, line);
19052
+ fs38.appendFileSync(logFile, line);
19023
19053
  }
19024
19054
  currentSize += Buffer.byteLength(line);
19025
19055
  } catch {
@@ -19136,7 +19166,7 @@ __export(harness_exports, {
19136
19166
  listSessions: () => listSessions
19137
19167
  });
19138
19168
  import path48 from "node:path";
19139
- import fs38 from "node:fs";
19169
+ import fs39 from "node:fs";
19140
19170
  async function initRuntime(observe) {
19141
19171
  console.log = (...args) => process.stderr.write(args.map(String).join(" ") + "\n");
19142
19172
  refreshTemplatesIfOutdated(HALO_HOME3, "CLI");
@@ -19178,7 +19208,7 @@ async function agentSupportsImage(sm, workspace, agentId) {
19178
19208
  }
19179
19209
  async function createHarness(opts) {
19180
19210
  const initialPath = path48.resolve(opts.workspace);
19181
- if (!fs38.existsSync(initialPath)) {
19211
+ if (!fs39.existsSync(initialPath)) {
19182
19212
  throw new Error(`Workspace does not exist: ${initialPath}`);
19183
19213
  }
19184
19214
  const registry2 = new SessionManagerRegistry();
@@ -19367,7 +19397,7 @@ async function createHarness(opts) {
19367
19397
  async function switchWorkspace(newPath) {
19368
19398
  const resolved = path48.resolve(newPath);
19369
19399
  if (resolved === state.workspace) return;
19370
- if (!fs38.existsSync(resolved)) {
19400
+ if (!fs39.existsSync(resolved)) {
19371
19401
  throw new Error(`Workspace does not exist: ${resolved}`);
19372
19402
  }
19373
19403
  state.unsubPersistent();
@@ -19490,29 +19520,29 @@ __export(setup_config_exports, {
19490
19520
  readConfigLeaf: () => readConfigLeaf,
19491
19521
  updateConfigLeaves: () => updateConfigLeaves
19492
19522
  });
19493
- import fs39 from "node:fs";
19523
+ import fs40 from "node:fs";
19494
19524
  import path49 from "node:path";
19495
19525
  import { homedir as homedir15 } from "node:os";
19496
19526
  import YAML10 from "yaml";
19497
19527
  function updateConfigLeaves(updates) {
19498
- const raw = fs39.existsSync(CONFIG_PATH) ? fs39.readFileSync(CONFIG_PATH, "utf-8") : "";
19528
+ const raw = fs40.existsSync(CONFIG_PATH) ? fs40.readFileSync(CONFIG_PATH, "utf-8") : "";
19499
19529
  const doc = raw ? YAML10.parseDocument(raw) : new YAML10.Document({});
19500
19530
  for (const [dotPath, val] of Object.entries(updates)) {
19501
19531
  const parts = dotPath.split(".");
19502
19532
  parts.push("value");
19503
19533
  doc.setIn(parts, val);
19504
19534
  }
19505
- fs39.mkdirSync(path49.dirname(CONFIG_PATH), { recursive: true });
19506
- fs39.writeFileSync(CONFIG_PATH, doc.toString(), { encoding: "utf-8", mode: 384 });
19535
+ fs40.mkdirSync(path49.dirname(CONFIG_PATH), { recursive: true });
19536
+ fs40.writeFileSync(CONFIG_PATH, doc.toString(), { encoding: "utf-8", mode: 384 });
19507
19537
  try {
19508
- fs39.chmodSync(CONFIG_PATH, 384);
19538
+ fs40.chmodSync(CONFIG_PATH, 384);
19509
19539
  } catch {
19510
19540
  }
19511
19541
  }
19512
19542
  function readConfigLeaf(dotPath) {
19513
- if (!fs39.existsSync(CONFIG_PATH))
19543
+ if (!fs40.existsSync(CONFIG_PATH))
19514
19544
  return void 0;
19515
- const raw = fs39.readFileSync(CONFIG_PATH, "utf-8");
19545
+ const raw = fs40.readFileSync(CONFIG_PATH, "utf-8");
19516
19546
  const doc = YAML10.parseDocument(raw);
19517
19547
  const parts = dotPath.split(".");
19518
19548
  parts.push("value");
@@ -19538,23 +19568,23 @@ __export(setup_settings_exports, {
19538
19568
  writeSetting: () => writeSetting,
19539
19569
  writeSettings: () => writeSettings
19540
19570
  });
19541
- import fs40 from "node:fs";
19571
+ import fs41 from "node:fs";
19542
19572
  import path50 from "node:path";
19543
19573
  import { homedir as homedir16 } from "node:os";
19544
19574
  import YAML11 from "yaml";
19545
19575
  function loadDoc() {
19546
- if (!fs40.existsSync(SETTINGS_PATH2))
19576
+ if (!fs41.existsSync(SETTINGS_PATH2))
19547
19577
  return new YAML11.Document({});
19548
- const raw = fs40.readFileSync(SETTINGS_PATH2, "utf-8");
19578
+ const raw = fs41.readFileSync(SETTINGS_PATH2, "utf-8");
19549
19579
  if (raw.trim().length === 0)
19550
19580
  return new YAML11.Document({});
19551
19581
  return YAML11.parseDocument(raw);
19552
19582
  }
19553
19583
  function saveDoc(doc) {
19554
- fs40.mkdirSync(path50.dirname(SETTINGS_PATH2), { recursive: true });
19555
- fs40.writeFileSync(SETTINGS_PATH2, doc.toString({ lineWidth: 120 }), { encoding: "utf-8", mode: 384 });
19584
+ fs41.mkdirSync(path50.dirname(SETTINGS_PATH2), { recursive: true });
19585
+ fs41.writeFileSync(SETTINGS_PATH2, doc.toString({ lineWidth: 120 }), { encoding: "utf-8", mode: 384 });
19556
19586
  try {
19557
- fs40.chmodSync(SETTINGS_PATH2, 384);
19587
+ fs41.chmodSync(SETTINGS_PATH2, 384);
19558
19588
  } catch {
19559
19589
  }
19560
19590
  }
@@ -19644,15 +19674,15 @@ __export(setup_providers_exports, {
19644
19674
  modelBlockFromProvider: () => modelBlockFromProvider,
19645
19675
  readDefaultAgentProvider: () => readDefaultAgentProvider
19646
19676
  });
19647
- import fs41 from "node:fs";
19677
+ import fs42 from "node:fs";
19648
19678
  import path51 from "node:path";
19649
19679
  import { homedir as homedir17 } from "node:os";
19650
19680
  import YAML12 from "yaml";
19651
19681
  function readYamlFile2(filePath) {
19652
- if (!fs41.existsSync(filePath))
19682
+ if (!fs42.existsSync(filePath))
19653
19683
  return null;
19654
19684
  try {
19655
- return YAML12.parse(fs41.readFileSync(filePath, "utf-8"));
19685
+ return YAML12.parse(fs42.readFileSync(filePath, "utf-8"));
19656
19686
  } catch {
19657
19687
  return null;
19658
19688
  }
@@ -19692,17 +19722,17 @@ function listModelProviders() {
19692
19722
  }
19693
19723
  function listOptionalSkills() {
19694
19724
  const dir = path51.join(TEMPLATES_DIR, "optional-skills");
19695
- if (!fs41.existsSync(dir))
19725
+ if (!fs42.existsSync(dir))
19696
19726
  return [];
19697
19727
  const out = [];
19698
- for (const id of fs41.readdirSync(dir)) {
19728
+ for (const id of fs42.readdirSync(dir)) {
19699
19729
  const skillDir = path51.join(dir, id);
19700
- if (!fs41.statSync(skillDir).isDirectory())
19730
+ if (!fs42.statSync(skillDir).isDirectory())
19701
19731
  continue;
19702
19732
  const skillMd = path51.join(skillDir, "SKILL.md");
19703
- if (!fs41.existsSync(skillMd))
19733
+ if (!fs42.existsSync(skillMd))
19704
19734
  continue;
19705
- const text6 = fs41.readFileSync(skillMd, "utf-8");
19735
+ const text6 = fs42.readFileSync(skillMd, "utf-8");
19706
19736
  const fmMatch = /^---\n([\s\S]*?)\n---/.exec(text6);
19707
19737
  let name = id;
19708
19738
  let description = "";
@@ -19785,12 +19815,12 @@ function bindBuiltinAgentsToProvider(providerId) {
19785
19815
  const agents = [];
19786
19816
  for (const id of REBIND_BUILTIN_AGENT_IDS) {
19787
19817
  const yamlPath = path51.join(GLOBAL_AGENTS_DIR3, id, "agent.yaml");
19788
- if (!fs41.existsSync(yamlPath))
19818
+ if (!fs42.existsSync(yamlPath))
19789
19819
  continue;
19790
19820
  try {
19791
- const doc = YAML12.parseDocument(fs41.readFileSync(yamlPath, "utf-8"));
19821
+ const doc = YAML12.parseDocument(fs42.readFileSync(yamlPath, "utf-8"));
19792
19822
  doc.set("model", block);
19793
- fs41.writeFileSync(yamlPath, doc.toString(), "utf-8");
19823
+ fs42.writeFileSync(yamlPath, doc.toString(), "utf-8");
19794
19824
  agents.push(id);
19795
19825
  } catch {
19796
19826
  }
@@ -19799,15 +19829,15 @@ function bindBuiltinAgentsToProvider(providerId) {
19799
19829
  }
19800
19830
  function listRequiredSkillsWithSecrets() {
19801
19831
  const dir = path51.join(TEMPLATES_DIR, "skills");
19802
- if (!fs41.existsSync(dir))
19832
+ if (!fs42.existsSync(dir))
19803
19833
  return [];
19804
19834
  const out = [];
19805
- for (const id of fs41.readdirSync(dir)) {
19835
+ for (const id of fs42.readdirSync(dir)) {
19806
19836
  const skillDir = path51.join(dir, id);
19807
- if (!fs41.statSync(skillDir).isDirectory())
19837
+ if (!fs42.statSync(skillDir).isDirectory())
19808
19838
  continue;
19809
19839
  const cfgPath = path51.join(skillDir, "config.yaml");
19810
- if (!fs41.existsSync(cfgPath))
19840
+ if (!fs42.existsSync(cfgPath))
19811
19841
  continue;
19812
19842
  const cfg = readYamlFile2(cfgPath);
19813
19843
  const fields = parseFields(cfg?.params).filter((f) => f.secret);
@@ -19816,8 +19846,8 @@ function listRequiredSkillsWithSecrets() {
19816
19846
  const skillMd = path51.join(skillDir, "SKILL.md");
19817
19847
  let name = id;
19818
19848
  let description = "";
19819
- if (fs41.existsSync(skillMd)) {
19820
- const text6 = fs41.readFileSync(skillMd, "utf-8");
19849
+ if (fs42.existsSync(skillMd)) {
19850
+ const text6 = fs42.readFileSync(skillMd, "utf-8");
19821
19851
  const fmMatch = /^---\n([\s\S]*?)\n---/.exec(text6);
19822
19852
  if (fmMatch) {
19823
19853
  try {
@@ -20186,13 +20216,13 @@ __export(upgrade_verify_exports, {
20186
20216
  verifyNativeModules: () => verifyNativeModules
20187
20217
  });
20188
20218
  import path52 from "node:path";
20189
- import fs42 from "node:fs";
20219
+ import fs43 from "node:fs";
20190
20220
  import { spawnSync as spawnSync2 } from "node:child_process";
20191
20221
  function verifyNativeModules(pkgRoot) {
20192
20222
  const broken = [];
20193
20223
  for (const { name, smoke } of NATIVE_MODULE_SMOKES) {
20194
20224
  const modDir = path52.join(pkgRoot, "node_modules", name);
20195
- if (!fs42.existsSync(modDir)) {
20225
+ if (!fs43.existsSync(modDir)) {
20196
20226
  broken.push(name);
20197
20227
  continue;
20198
20228
  }
@@ -20223,7 +20253,7 @@ __export(install_exports, {
20223
20253
  planModelsInstall: () => planModelsInstall,
20224
20254
  summaryLine: () => summaryLine
20225
20255
  });
20226
- import fs43 from "node:fs";
20256
+ import fs44 from "node:fs";
20227
20257
  import path53 from "node:path";
20228
20258
  import { isDeepStrictEqual } from "node:util";
20229
20259
  import YAML13 from "yaml";
@@ -20311,7 +20341,7 @@ function planModelsInstall(srcDir, dirs = {}) {
20311
20341
  const effective = loadProviders(dirs.bundledDir ?? globalModelsDir(), hubDir).effective;
20312
20342
  let files;
20313
20343
  try {
20314
- files = fs43.readdirSync(srcDir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".yaml")).map((e) => e.name).sort();
20344
+ files = fs44.readdirSync(srcDir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".yaml")).map((e) => e.name).sort();
20315
20345
  } catch (err) {
20316
20346
  throw new Error(`cannot read ${srcDir}: ${err instanceof Error ? err.message : String(err)}`);
20317
20347
  }
@@ -20319,7 +20349,7 @@ function planModelsInstall(srcDir, dirs = {}) {
20319
20349
  throw new Error(`no provider yaml in ${srcDir}`);
20320
20350
  const seen = /* @__PURE__ */ new Set();
20321
20351
  const entries = files.map((file) => {
20322
- const raw = fs43.readFileSync(path53.join(srcDir, file), "utf-8");
20352
+ const raw = fs44.readFileSync(path53.join(srcDir, file), "utf-8");
20323
20353
  let data;
20324
20354
  try {
20325
20355
  data = YAML13.parse(raw);
@@ -20352,13 +20382,13 @@ function planModelsInstall(srcDir, dirs = {}) {
20352
20382
  }
20353
20383
  function applyModelsInstall(plan) {
20354
20384
  const written = [];
20355
- fs43.mkdirSync(plan.hubDir, { recursive: true });
20385
+ fs44.mkdirSync(plan.hubDir, { recursive: true });
20356
20386
  for (const e of plan.entries) {
20357
20387
  if (e.action !== "install" || !e.id || e.raw == null)
20358
20388
  continue;
20359
20389
  const tmp = path53.join(plan.hubDir, `.tmp-${e.id}-${process.pid}-${Date.now()}`);
20360
- fs43.writeFileSync(tmp, e.raw, "utf-8");
20361
- fs43.renameSync(tmp, path53.join(plan.hubDir, `${e.id}.yaml`));
20390
+ fs44.writeFileSync(tmp, e.raw, "utf-8");
20391
+ fs44.renameSync(tmp, path53.join(plan.hubDir, `${e.id}.yaml`));
20362
20392
  written.push(e.id);
20363
20393
  }
20364
20394
  return written;
@@ -20441,7 +20471,7 @@ var init_render_md = __esm({
20441
20471
  });
20442
20472
 
20443
20473
  // src/resolve-refs.ts
20444
- import fs44 from "node:fs";
20474
+ import fs45 from "node:fs";
20445
20475
  import path54 from "node:path";
20446
20476
  function resolveRefs(input, workspace) {
20447
20477
  const images = [];
@@ -20459,7 +20489,7 @@ function resolveRefs(input, workspace) {
20459
20489
  const ext = path54.extname(resolved).toLowerCase();
20460
20490
  let stat = null;
20461
20491
  try {
20462
- stat = fs44.statSync(resolved);
20492
+ stat = fs45.statSync(resolved);
20463
20493
  } catch {
20464
20494
  }
20465
20495
  if (!stat) {
@@ -20477,18 +20507,18 @@ function resolveRefs(input, workspace) {
20477
20507
  warnings.push(`${rawPath}: image too large (${(stat.size / 1024 / 1024).toFixed(1)}MB, max ${MAX_IMAGE_BYTES2 / 1024 / 1024}MB), skipped`);
20478
20508
  continue;
20479
20509
  }
20480
- const data = fs44.readFileSync(resolved).toString("base64");
20510
+ const data = fs45.readFileSync(resolved).toString("base64");
20481
20511
  images.push({ data, mimeType: imageMimeFromExt(ext) ?? "application/octet-stream" });
20482
20512
  } else {
20483
20513
  const relPath = path54.relative(workspace, resolved);
20484
20514
  if (stat.size > MAX_FILE_BYTES) {
20485
20515
  const buf = Buffer.alloc(MAX_FILE_BYTES);
20486
- const fd = fs44.openSync(resolved, "r");
20516
+ const fd = fs45.openSync(resolved, "r");
20487
20517
  let n = 0;
20488
20518
  try {
20489
- n = fs44.readSync(fd, buf, 0, MAX_FILE_BYTES, 0);
20519
+ n = fs45.readSync(fd, buf, 0, MAX_FILE_BYTES, 0);
20490
20520
  } finally {
20491
- fs44.closeSync(fd);
20521
+ fs45.closeSync(fd);
20492
20522
  }
20493
20523
  const content = buf.subarray(0, n).toString("utf-8").replace(/\uFFFD+$/, "");
20494
20524
  parts.push(`
@@ -20499,7 +20529,7 @@ ${content}
20499
20529
  `);
20500
20530
  warnings.push(`${rawPath}: truncated (${(stat.size / 1024).toFixed(0)}KB, max ${MAX_FILE_BYTES / 1024}KB)`);
20501
20531
  } else {
20502
- const content = fs44.readFileSync(resolved, "utf-8");
20532
+ const content = fs45.readFileSync(resolved, "utf-8");
20503
20533
  parts.push(`
20504
20534
  <file path="${relPath}">
20505
20535
  ${content}
@@ -20771,12 +20801,12 @@ var init_streaming = __esm({
20771
20801
  });
20772
20802
 
20773
20803
  // src/tui/history.ts
20774
- import fs45 from "node:fs";
20804
+ import fs46 from "node:fs";
20775
20805
  import path55 from "node:path";
20776
20806
  import os4 from "node:os";
20777
20807
  function loadHistory() {
20778
20808
  try {
20779
- const arr = JSON.parse(fs45.readFileSync(HISTORY_FILE, "utf8"));
20809
+ const arr = JSON.parse(fs46.readFileSync(HISTORY_FILE, "utf8"));
20780
20810
  if (Array.isArray(arr)) {
20781
20811
  return arr.filter((x) => typeof x === "string").slice(-MAX_ENTRIES);
20782
20812
  }
@@ -20789,8 +20819,8 @@ function appendHistory(entry) {
20789
20819
  const arr = loadHistory();
20790
20820
  if (arr[arr.length - 1] === entry) return;
20791
20821
  arr.push(entry);
20792
- fs45.mkdirSync(path55.dirname(HISTORY_FILE), { recursive: true });
20793
- fs45.writeFileSync(HISTORY_FILE, JSON.stringify(arr.slice(-MAX_ENTRIES)));
20822
+ fs46.mkdirSync(path55.dirname(HISTORY_FILE), { recursive: true });
20823
+ fs46.writeFileSync(HISTORY_FILE, JSON.stringify(arr.slice(-MAX_ENTRIES)));
20794
20824
  } catch {
20795
20825
  }
20796
20826
  }
@@ -20902,7 +20932,7 @@ var init_path_suggest = __esm({
20902
20932
  });
20903
20933
 
20904
20934
  // src/tui/path-suggest-engine.ts
20905
- import fs46 from "node:fs";
20935
+ import fs47 from "node:fs";
20906
20936
  import path56 from "node:path";
20907
20937
  function detectActiveRef(value) {
20908
20938
  const reExplicit = /@(file|image|scope)\s+(?:"([^"]*)|(\S*))$/;
@@ -20945,7 +20975,7 @@ function scanCandidates(partial, workspace, kind) {
20945
20975
  const { absDir, displayDir, prefix } = resolveDirAndPrefix(partial, workspace);
20946
20976
  let entries;
20947
20977
  try {
20948
- entries = fs46.readdirSync(absDir, { withFileTypes: true });
20978
+ entries = fs47.readdirSync(absDir, { withFileTypes: true });
20949
20979
  } catch {
20950
20980
  return { items: [], cwdLabel: displayDir };
20951
20981
  }
@@ -22515,13 +22545,13 @@ var init_read_stdin_prompt = __esm({
22515
22545
  });
22516
22546
 
22517
22547
  // ../server/dist/routes/workspace-path.js
22518
- import fs47 from "node:fs/promises";
22548
+ import fs48 from "node:fs/promises";
22519
22549
  import { existsSync as existsSync2, realpathSync as realpathSync3 } from "node:fs";
22520
22550
  import path57 from "node:path";
22521
22551
  async function resolveProjectPath(projectId) {
22522
22552
  if (path57.isAbsolute(projectId)) {
22523
22553
  try {
22524
- await fs47.access(projectId);
22554
+ await fs48.access(projectId);
22525
22555
  return projectId;
22526
22556
  } catch {
22527
22557
  return null;
@@ -22564,7 +22594,7 @@ var init_workspace_path = __esm({
22564
22594
  });
22565
22595
 
22566
22596
  // ../server/dist/ws/file-watcher.js
22567
- import fs48 from "node:fs";
22597
+ import fs49 from "node:fs";
22568
22598
  import path58 from "node:path";
22569
22599
  function enqueueNativeOp(op) {
22570
22600
  const result = nativeOpChain.then(op);
@@ -22674,7 +22704,7 @@ var init_file_watcher = __esm({
22674
22704
  }
22675
22705
  let root = workspaceRoot;
22676
22706
  try {
22677
- root = fs48.realpathSync(workspaceRoot);
22707
+ root = fs49.realpathSync(workspaceRoot);
22678
22708
  } catch {
22679
22709
  }
22680
22710
  if (this.subscription && this.workspaceRoot === root)
@@ -22732,7 +22762,7 @@ var init_file_watcher = __esm({
22732
22762
  } else {
22733
22763
  let isDir = false;
22734
22764
  try {
22735
- isDir = fs48.statSync(absPath).isDirectory();
22765
+ isDir = fs49.statSync(absPath).isDirectory();
22736
22766
  } catch {
22737
22767
  }
22738
22768
  action = isDir ? "addDir" : "add";
@@ -22808,7 +22838,7 @@ var init_file_watcher = __esm({
22808
22838
  });
22809
22839
 
22810
22840
  // ../server/dist/routes/folder-zip.js
22811
- import fs49 from "node:fs/promises";
22841
+ import fs50 from "node:fs/promises";
22812
22842
  import { realpathSync as realpathSync4 } from "node:fs";
22813
22843
  import os5 from "node:os";
22814
22844
  import path59 from "node:path";
@@ -22850,7 +22880,7 @@ function isBlockedPath(real, wsReal) {
22850
22880
  return isHiddenWorkspacePath(real, base) || real === path59.join(base, ".halo", "settings.yaml");
22851
22881
  }
22852
22882
  async function planFolderZip(root, projectPath, opts) {
22853
- const [rootReal, wsReal] = await Promise.all([fs49.realpath(root), fs49.realpath(projectPath)]);
22883
+ const [rootReal, wsReal] = await Promise.all([fs50.realpath(root), fs50.realpath(projectPath)]);
22854
22884
  if (isBlockedPath(rootReal, wsReal))
22855
22885
  throw new FolderZipError(403, "Path is not accessible");
22856
22886
  const { includeIgnored, limits, signal } = opts;
@@ -22870,8 +22900,8 @@ async function planFolderZip(root, projectPath, opts) {
22870
22900
  excluded.add("blocked", rel);
22871
22901
  return false;
22872
22902
  }
22873
- const real = await fs49.realpath(linkPath).catch(() => null);
22874
- const st = real ? await fs49.stat(real).catch(() => null) : null;
22903
+ const real = await fs50.realpath(linkPath).catch(() => null);
22904
+ const st = real ? await fs50.stat(real).catch(() => null) : null;
22875
22905
  if (!real || !st?.isFile() || !isUnder2(real, wsReal) || isBlockedPath(real, wsReal) || isEnvName(path59.basename(real))) {
22876
22906
  excluded.add("symlink", st?.isDirectory() ? `${rel}/` : rel);
22877
22907
  return false;
@@ -22882,7 +22912,7 @@ async function planFolderZip(root, projectPath, opts) {
22882
22912
  async function walk(dirReal, rel) {
22883
22913
  let entries;
22884
22914
  try {
22885
- entries = await fs49.readdir(dirReal, { withFileTypes: true });
22915
+ entries = await fs50.readdir(dirReal, { withFileTypes: true });
22886
22916
  } catch (err) {
22887
22917
  if (!rel)
22888
22918
  throw err;
@@ -22897,7 +22927,7 @@ async function planFolderZip(root, projectPath, opts) {
22897
22927
  if (Date.now() > deadline)
22898
22928
  throw walkTimeout();
22899
22929
  await Promise.all(toStat.slice(i, i + 64).map(async (e) => {
22900
- fileStats.set(e.name, await fs49.stat(path59.join(dirReal, e.name)).catch((err) => err));
22930
+ fileStats.set(e.name, await fs50.stat(path59.join(dirReal, e.name)).catch((err) => err));
22901
22931
  }));
22902
22932
  }
22903
22933
  let nonEmpty2 = false;
@@ -22922,7 +22952,7 @@ async function planFolderZip(root, projectPath, opts) {
22922
22952
  excluded.ignoredNames[e.name] = (excluded.ignoredNames[e.name] ?? 0) + 1;
22923
22953
  } else {
22924
22954
  if (!await walk(childReal, childRel)) {
22925
- const st = await fs49.stat(childReal).catch(() => null);
22955
+ const st = await fs50.stat(childReal).catch(() => null);
22926
22956
  plan.items.push({ rel: childRel, mtimeMs: st?.mtimeMs ?? Date.now() });
22927
22957
  }
22928
22958
  nonEmpty2 = true;
@@ -23014,7 +23044,7 @@ function streamFolderZip(plan, folderName, signal) {
23014
23044
  const mtime = new Date(item.mtimeMs);
23015
23045
  let handle;
23016
23046
  try {
23017
- handle = await fs49.open(item.abs, "r");
23047
+ handle = await fs50.open(item.abs, "r");
23018
23048
  } catch (err) {
23019
23049
  plan.excluded.add("unreadable", `${item.rel} (${err.code ?? "error"})`);
23020
23050
  continue;
@@ -23191,7 +23221,7 @@ var init_folder_zip = __esm({
23191
23221
 
23192
23222
  // ../server/dist/routes/files.js
23193
23223
  import { Hono as Hono2 } from "hono";
23194
- import fs50 from "node:fs/promises";
23224
+ import fs51 from "node:fs/promises";
23195
23225
  import { createReadStream } from "node:fs";
23196
23226
  import { Readable } from "node:stream";
23197
23227
  import path60 from "node:path";
@@ -23220,7 +23250,7 @@ function createFileRoutes(opts = {}) {
23220
23250
  }
23221
23251
  async function dirHasChildren(dirPath) {
23222
23252
  try {
23223
- const entries = await fs50.readdir(dirPath, { withFileTypes: true });
23253
+ const entries = await fs51.readdir(dirPath, { withFileTypes: true });
23224
23254
  for (const entry of entries) {
23225
23255
  if (!isSkippedName(entry.name))
23226
23256
  return true;
@@ -23233,7 +23263,7 @@ function createFileRoutes(opts = {}) {
23233
23263
  async function listDir(dirPath, basePath) {
23234
23264
  let entries;
23235
23265
  try {
23236
- entries = await fs50.readdir(dirPath, { withFileTypes: true });
23266
+ entries = await fs51.readdir(dirPath, { withFileTypes: true });
23237
23267
  } catch {
23238
23268
  return [];
23239
23269
  }
@@ -23283,7 +23313,7 @@ function createFileRoutes(opts = {}) {
23283
23313
  }
23284
23314
  const targetPath = relPath ? path60.resolve(projectPath, relPath) : projectPath;
23285
23315
  try {
23286
- const stat = await fs50.stat(targetPath);
23316
+ const stat = await fs51.stat(targetPath);
23287
23317
  if (!stat.isDirectory()) {
23288
23318
  return c.json({ error: "Path is not a directory" }, 400);
23289
23319
  }
@@ -23326,7 +23356,7 @@ function createFileRoutes(opts = {}) {
23326
23356
  return;
23327
23357
  let entries;
23328
23358
  try {
23329
- entries = await fs50.readdir(dirPath, { withFileTypes: true });
23359
+ entries = await fs51.readdir(dirPath, { withFileTypes: true });
23330
23360
  } catch {
23331
23361
  return;
23332
23362
  }
@@ -23398,9 +23428,9 @@ function createFileRoutes(opts = {}) {
23398
23428
  }
23399
23429
  const destPath = path60.resolve(projectPath, relPath);
23400
23430
  const destDir = path60.dirname(destPath);
23401
- await fs50.mkdir(destDir, { recursive: true });
23431
+ await fs51.mkdir(destDir, { recursive: true });
23402
23432
  const buffer = Buffer.from(await file.arrayBuffer());
23403
- await fs50.writeFile(destPath, buffer);
23433
+ await fs51.writeFile(destPath, buffer);
23404
23434
  uploaded.push({
23405
23435
  name: file.name,
23406
23436
  path: relPath,
@@ -23425,8 +23455,8 @@ function createFileRoutes(opts = {}) {
23425
23455
  if ("error" in resolved)
23426
23456
  return c.json({ error: resolved.error }, resolved.status);
23427
23457
  const { absolutePath } = resolved;
23428
- await fs50.writeFile(absolutePath, content, "utf-8");
23429
- const stat = await fs50.stat(absolutePath);
23458
+ await fs51.writeFile(absolutePath, content, "utf-8");
23459
+ const stat = await fs51.stat(absolutePath);
23430
23460
  return c.json({ ok: true, path: filePath, modifiedAt: stat.mtimeMs });
23431
23461
  } catch (err) {
23432
23462
  const errorMessage = err instanceof Error ? err.message : String(err);
@@ -23459,19 +23489,19 @@ function createFileRoutes(opts = {}) {
23459
23489
  return c.json({ error: rootResolved.error }, rootResolved.status);
23460
23490
  const rel = path60.relative(rootResolved.absolutePath, absolutePath);
23461
23491
  const inside = rel !== "" && !rel.startsWith("..") && !path60.isAbsolute(rel);
23462
- const rootIsDir = await fs50.stat(rootResolved.absolutePath).then((s) => s.isDirectory(), () => false);
23492
+ const rootIsDir = await fs51.stat(rootResolved.absolutePath).then((s) => s.isDirectory(), () => false);
23463
23493
  if (!inside || !rootIsDir)
23464
23494
  return c.json({ error: "Bundle root not found" }, 404);
23465
23495
  }
23466
23496
  let before;
23467
23497
  try {
23468
- before = await fs50.stat(absolutePath);
23498
+ before = await fs51.stat(absolutePath);
23469
23499
  } catch (err) {
23470
23500
  if (err.code !== "ENOENT")
23471
23501
  throw err;
23472
23502
  if (!create)
23473
23503
  return c.json({ error: "File not found" }, 404);
23474
- await fs50.mkdir(path60.dirname(absolutePath), { recursive: true });
23504
+ await fs51.mkdir(path60.dirname(absolutePath), { recursive: true });
23475
23505
  }
23476
23506
  if (before?.isDirectory())
23477
23507
  return c.json({ error: "Cannot write a directory" }, 400);
@@ -23480,10 +23510,10 @@ function createFileRoutes(opts = {}) {
23480
23510
  }
23481
23511
  const bytes = Buffer.from(await c.req.arrayBuffer());
23482
23512
  if (append)
23483
- await fs50.appendFile(absolutePath, bytes);
23513
+ await fs51.appendFile(absolutePath, bytes);
23484
23514
  else
23485
- await fs50.writeFile(absolutePath, bytes);
23486
- const stat = await fs50.stat(absolutePath);
23515
+ await fs51.writeFile(absolutePath, bytes);
23516
+ const stat = await fs51.stat(absolutePath);
23487
23517
  return c.json({ ok: true, path: filePath, mtime: stat.mtimeMs, size: stat.size });
23488
23518
  } catch (err) {
23489
23519
  const errorMessage = err instanceof Error ? err.message : String(err);
@@ -23502,13 +23532,13 @@ function createFileRoutes(opts = {}) {
23502
23532
  if ("error" in resolved)
23503
23533
  return c.json({ error: resolved.error }, resolved.status);
23504
23534
  const { absolutePath } = resolved;
23505
- await fs50.mkdir(path60.dirname(absolutePath), { recursive: true });
23535
+ await fs51.mkdir(path60.dirname(absolutePath), { recursive: true });
23506
23536
  try {
23507
- await fs50.access(absolutePath);
23537
+ await fs51.access(absolutePath);
23508
23538
  return c.json({ error: "File already exists" }, 409);
23509
23539
  } catch {
23510
23540
  }
23511
- await fs50.writeFile(absolutePath, "", "utf-8");
23541
+ await fs51.writeFile(absolutePath, "", "utf-8");
23512
23542
  return c.json({ ok: true, path: filePath });
23513
23543
  } catch (err) {
23514
23544
  const errorMessage = err instanceof Error ? err.message : String(err);
@@ -23526,7 +23556,7 @@ function createFileRoutes(opts = {}) {
23526
23556
  const resolved = await resolveProjectFile(projectId, dirPath);
23527
23557
  if ("error" in resolved)
23528
23558
  return c.json({ error: resolved.error }, resolved.status);
23529
- await fs50.mkdir(resolved.absolutePath, { recursive: true });
23559
+ await fs51.mkdir(resolved.absolutePath, { recursive: true });
23530
23560
  return c.json({ ok: true, path: dirPath });
23531
23561
  } catch (err) {
23532
23562
  const errorMessage = err instanceof Error ? err.message : String(err);
@@ -23550,8 +23580,8 @@ function createFileRoutes(opts = {}) {
23550
23580
  }
23551
23581
  const absOld = path60.resolve(projectPath, oldPath);
23552
23582
  const absNew = path60.resolve(projectPath, newPath);
23553
- await fs50.mkdir(path60.dirname(absNew), { recursive: true });
23554
- await fs50.rename(absOld, absNew);
23583
+ await fs51.mkdir(path60.dirname(absNew), { recursive: true });
23584
+ await fs51.rename(absOld, absNew);
23555
23585
  return c.json({ ok: true, oldPath, newPath });
23556
23586
  } catch (err) {
23557
23587
  const errorMessage = err instanceof Error ? err.message : String(err);
@@ -23573,7 +23603,7 @@ function createFileRoutes(opts = {}) {
23573
23603
  if (absolutePath === path60.resolve(projectPath)) {
23574
23604
  return c.json({ error: "Cannot delete project root" }, 403);
23575
23605
  }
23576
- await fs50.rm(absolutePath, { recursive: true, force: true });
23606
+ await fs51.rm(absolutePath, { recursive: true, force: true });
23577
23607
  return c.json({ ok: true, path: filePath });
23578
23608
  } catch (err) {
23579
23609
  const errorMessage = err instanceof Error ? err.message : String(err);
@@ -23613,7 +23643,7 @@ function createFileRoutes(opts = {}) {
23613
23643
  return c.json({ error: "Path traversal not allowed" }, 403);
23614
23644
  }
23615
23645
  const absolutePath = isTmp ? path60.resolve(filePath) : path60.resolve(projectPath, filePath);
23616
- const stat = await fs50.stat(absolutePath);
23646
+ const stat = await fs51.stat(absolutePath);
23617
23647
  if (stat.isDirectory()) {
23618
23648
  return c.json({ error: "Cannot download a directory" }, 400);
23619
23649
  }
@@ -23678,7 +23708,7 @@ function createFileRoutes(opts = {}) {
23678
23708
  if ("error" in resolved)
23679
23709
  return c.json({ error: resolved.error }, resolved.status);
23680
23710
  const { projectPath, absolutePath } = resolved;
23681
- if (!(await fs50.stat(absolutePath)).isDirectory())
23711
+ if (!(await fs51.stat(absolutePath)).isDirectory())
23682
23712
  return c.json({ error: "Not a directory" }, 400);
23683
23713
  const plan = await planFolderZip(absolutePath, projectPath, {
23684
23714
  includeIgnored: c.req.query("include") === "excluded",
@@ -23725,7 +23755,7 @@ function createFileRoutes(opts = {}) {
23725
23755
  const resolved = await resolveProjectFile(projectId, filePath);
23726
23756
  if ("error" in resolved)
23727
23757
  return c.json({ error: resolved.error }, resolved.status);
23728
- const stat = await fs50.stat(resolved.absolutePath);
23758
+ const stat = await fs51.stat(resolved.absolutePath);
23729
23759
  return c.json({ path: filePath, modifiedAt: stat.mtimeMs, createdAt: stat.birthtimeMs, size: stat.size });
23730
23760
  } catch (err) {
23731
23761
  if (err.code === "ENOENT")
@@ -23745,7 +23775,7 @@ function createFileRoutes(opts = {}) {
23745
23775
  return c.json({ error: resolved.error }, resolved.status);
23746
23776
  const { absolutePath } = resolved;
23747
23777
  try {
23748
- const stat = await fs50.stat(absolutePath);
23778
+ const stat = await fs51.stat(absolutePath);
23749
23779
  if (stat.isDirectory()) {
23750
23780
  return c.json({ error: "Path is a directory, use /files/tree instead" }, 400);
23751
23781
  }
@@ -23753,7 +23783,7 @@ function createFileRoutes(opts = {}) {
23753
23783
  if (stat.size > maxSize) {
23754
23784
  return c.json({ error: "File too large (max 10MB)" }, 413);
23755
23785
  }
23756
- const content = await fs50.readFile(absolutePath, "utf-8");
23786
+ const content = await fs51.readFile(absolutePath, "utf-8");
23757
23787
  return c.json({
23758
23788
  path: filePath,
23759
23789
  content,
@@ -23783,7 +23813,7 @@ function createFileRoutes(opts = {}) {
23783
23813
  const resolved = path60.resolve(body.path);
23784
23814
  let stat;
23785
23815
  try {
23786
- stat = await fs50.stat(resolved);
23816
+ stat = await fs51.stat(resolved);
23787
23817
  } catch {
23788
23818
  return c.json({ error: "path not found" }, 404);
23789
23819
  }
@@ -23801,7 +23831,7 @@ function createFileRoutes(opts = {}) {
23801
23831
  if (!target || !path60.isAbsolute(target))
23802
23832
  return c.json({ exists: false, reason: "absolute path required" });
23803
23833
  try {
23804
- const stat = await fs50.stat(target);
23834
+ const stat = await fs51.stat(target);
23805
23835
  return c.json({ exists: true, isDirectory: stat.isDirectory() });
23806
23836
  } catch {
23807
23837
  return c.json({ exists: false });
@@ -23813,9 +23843,9 @@ function createFileRoutes(opts = {}) {
23813
23843
  return c.json({ error: "absolute path required" }, 400);
23814
23844
  try {
23815
23845
  const resolved = path60.resolve(target);
23816
- const entries = await fs50.readdir(resolved, { withFileTypes: true });
23846
+ const entries = await fs51.readdir(resolved, { withFileTypes: true });
23817
23847
  if (c.req.query("files") === "1") {
23818
- const realDir = await fs50.realpath(resolved);
23848
+ const realDir = await fs51.realpath(resolved);
23819
23849
  if (isHiddenHostPath(realDir))
23820
23850
  throw hiddenAsMissing("scandir", resolved);
23821
23851
  const withSizes = c.req.query("sizes") === "1";
@@ -23824,15 +23854,15 @@ function createFileRoutes(opts = {}) {
23824
23854
  if (isSkippedName(e.name))
23825
23855
  continue;
23826
23856
  const full = path60.join(resolved, e.name);
23827
- const st = e.isSymbolicLink() ? await fs50.stat(full).catch(() => null) : null;
23857
+ const st = e.isSymbolicLink() ? await fs51.stat(full).catch(() => null) : null;
23828
23858
  const isDir = st ? st.isDirectory() : e.isDirectory();
23829
23859
  const isFile2 = st ? st.isFile() : e.isFile();
23830
23860
  if (!isDir && !isFile2)
23831
23861
  continue;
23832
- const real = st ? await fs50.realpath(full).catch(() => full) : path60.join(realDir, e.name);
23862
+ const real = st ? await fs51.realpath(full).catch(() => full) : path60.join(realDir, e.name);
23833
23863
  if (isHiddenHostPath(real))
23834
23864
  continue;
23835
- const size = isFile2 && withSizes ? (st ?? await fs50.stat(full).catch(() => null))?.size : void 0;
23865
+ const size = isFile2 && withSizes ? (st ?? await fs51.stat(full).catch(() => null))?.size : void 0;
23836
23866
  list.push({ name: e.name, path: full, type: isDir ? "directory" : "file", ...size !== void 0 ? { size } : {} });
23837
23867
  }
23838
23868
  list.sort((a, b) => a.type === b.type ? a.name.localeCompare(b.name) : a.type === "directory" ? -1 : 1);
@@ -23857,7 +23887,7 @@ function createFileRoutes(opts = {}) {
23857
23887
  return Object.assign(new Error(`ENOENT: no such file or directory, ${syscall} '${target}'`), { code: "ENOENT" });
23858
23888
  }
23859
23889
  async function readableRealPath(target) {
23860
- const real = await fs50.realpath(target);
23890
+ const real = await fs51.realpath(target);
23861
23891
  if (isHiddenHostPath(real))
23862
23892
  throw hiddenAsMissing("realpath", target);
23863
23893
  return real;
@@ -23868,7 +23898,7 @@ function createFileRoutes(opts = {}) {
23868
23898
  return c.json({ error: "absolute path without .. required" }, 400);
23869
23899
  try {
23870
23900
  const realPath = await readableRealPath(target);
23871
- const stat = await fs50.stat(realPath);
23901
+ const stat = await fs51.stat(realPath);
23872
23902
  return c.json({ path: target, realPath, size: stat.size, modifiedAt: stat.mtimeMs, isDirectory: stat.isDirectory() });
23873
23903
  } catch (err) {
23874
23904
  return c.json({ error: err.message }, fsErrorStatus(err));
@@ -23880,7 +23910,7 @@ function createFileRoutes(opts = {}) {
23880
23910
  return c.json({ error: "absolute path without .. required" }, 400);
23881
23911
  try {
23882
23912
  const real = await readableRealPath(target);
23883
- const stat = await fs50.stat(real);
23913
+ const stat = await fs51.stat(real);
23884
23914
  if (!stat.isFile())
23885
23915
  return c.json({ error: "not a file" }, 400);
23886
23916
  const nodeStream = stat.size === 0 ? Readable.from([]) : createReadStream(real);
@@ -23907,7 +23937,7 @@ var init_files2 = __esm({
23907
23937
 
23908
23938
  // ../server/dist/routes/data-preview.js
23909
23939
  import { Hono as Hono3 } from "hono";
23910
- import fs51 from "node:fs/promises";
23940
+ import fs52 from "node:fs/promises";
23911
23941
  import { createReadStream as createReadStream2 } from "node:fs";
23912
23942
  import path61 from "node:path";
23913
23943
  import Database6 from "better-sqlite3";
@@ -23940,7 +23970,7 @@ function quoteIdent(name) {
23940
23970
  return `"${name.replaceAll('"', '""')}"`;
23941
23971
  }
23942
23972
  async function sniffDelimiter(absolutePath) {
23943
- const fh = await fs51.open(absolutePath, "r");
23973
+ const fh = await fs52.open(absolutePath, "r");
23944
23974
  let head;
23945
23975
  try {
23946
23976
  const buf = Buffer.alloc(65536);
@@ -24026,7 +24056,7 @@ function createDataPreviewRoutes() {
24026
24056
  return { error: "Path traversal not allowed", status: 403 };
24027
24057
  const absolutePath = path61.resolve(projectPath, filePath);
24028
24058
  try {
24029
- const stat = await fs51.stat(absolutePath);
24059
+ const stat = await fs52.stat(absolutePath);
24030
24060
  if (stat.isDirectory())
24031
24061
  return { error: "Path is a directory", status: 400 };
24032
24062
  } catch {
@@ -24232,14 +24262,14 @@ var init_data_preview = __esm({
24232
24262
  });
24233
24263
 
24234
24264
  // ../server/dist/git-credentials.js
24235
- import fs52 from "node:fs";
24265
+ import fs53 from "node:fs";
24236
24266
  import path62 from "node:path";
24237
24267
  import { homedir as homedir19 } from "node:os";
24238
24268
  function writeGitCredentialsFile(host, username, token) {
24239
24269
  const line = `https://${encodeURIComponent(username)}:${encodeURIComponent(token)}@${host}`;
24240
24270
  let lines = [];
24241
- if (fs52.existsSync(GIT_CREDENTIALS_PATH)) {
24242
- lines = fs52.readFileSync(GIT_CREDENTIALS_PATH, "utf-8").split("\n").filter((l) => l.trim() !== "");
24271
+ if (fs53.existsSync(GIT_CREDENTIALS_PATH)) {
24272
+ lines = fs53.readFileSync(GIT_CREDENTIALS_PATH, "utf-8").split("\n").filter((l) => l.trim() !== "");
24243
24273
  }
24244
24274
  const kept = lines.filter((l) => {
24245
24275
  try {
@@ -24249,9 +24279,9 @@ function writeGitCredentialsFile(host, username, token) {
24249
24279
  }
24250
24280
  });
24251
24281
  kept.push(line);
24252
- fs52.writeFileSync(GIT_CREDENTIALS_PATH, kept.join("\n") + "\n", { encoding: "utf-8", mode: 384 });
24282
+ fs53.writeFileSync(GIT_CREDENTIALS_PATH, kept.join("\n") + "\n", { encoding: "utf-8", mode: 384 });
24253
24283
  try {
24254
- fs52.chmodSync(GIT_CREDENTIALS_PATH, 384);
24284
+ fs53.chmodSync(GIT_CREDENTIALS_PATH, 384);
24255
24285
  } catch {
24256
24286
  }
24257
24287
  }
@@ -24260,9 +24290,9 @@ function saveGitCredentials({ host, username, token }) {
24260
24290
  console.log(`[GitCredentials] saved for host ${host}`);
24261
24291
  }
24262
24292
  function listGitCredentials() {
24263
- if (!fs52.existsSync(GIT_CREDENTIALS_PATH))
24293
+ if (!fs53.existsSync(GIT_CREDENTIALS_PATH))
24264
24294
  return [];
24265
- const lines = fs52.readFileSync(GIT_CREDENTIALS_PATH, "utf-8").split("\n").filter((l) => l.trim() !== "");
24295
+ const lines = fs53.readFileSync(GIT_CREDENTIALS_PATH, "utf-8").split("\n").filter((l) => l.trim() !== "");
24266
24296
  const byHost = /* @__PURE__ */ new Map();
24267
24297
  for (const line of lines) {
24268
24298
  try {
@@ -24276,9 +24306,9 @@ function listGitCredentials() {
24276
24306
  return [...byHost.values()];
24277
24307
  }
24278
24308
  function deleteGitCredential(host) {
24279
- if (!fs52.existsSync(GIT_CREDENTIALS_PATH))
24309
+ if (!fs53.existsSync(GIT_CREDENTIALS_PATH))
24280
24310
  return;
24281
- const lines = fs52.readFileSync(GIT_CREDENTIALS_PATH, "utf-8").split("\n").filter((l) => l.trim() !== "");
24311
+ const lines = fs53.readFileSync(GIT_CREDENTIALS_PATH, "utf-8").split("\n").filter((l) => l.trim() !== "");
24282
24312
  const kept = lines.filter((l) => {
24283
24313
  try {
24284
24314
  return new URL(l).host !== host;
@@ -24288,9 +24318,9 @@ function deleteGitCredential(host) {
24288
24318
  });
24289
24319
  if (kept.length === lines.length)
24290
24320
  return;
24291
- fs52.writeFileSync(GIT_CREDENTIALS_PATH, kept.length ? kept.join("\n") + "\n" : "", { encoding: "utf-8", mode: 384 });
24321
+ fs53.writeFileSync(GIT_CREDENTIALS_PATH, kept.length ? kept.join("\n") + "\n" : "", { encoding: "utf-8", mode: 384 });
24292
24322
  try {
24293
- fs52.chmodSync(GIT_CREDENTIALS_PATH, 384);
24323
+ fs53.chmodSync(GIT_CREDENTIALS_PATH, 384);
24294
24324
  } catch {
24295
24325
  }
24296
24326
  console.log(`[GitCredentials] removed for host ${host}`);
@@ -24304,7 +24334,7 @@ var init_git_credentials = __esm({
24304
24334
  });
24305
24335
 
24306
24336
  // ../server/dist/git-ssh.js
24307
- import fs53 from "node:fs";
24337
+ import fs54 from "node:fs";
24308
24338
  import os6 from "node:os";
24309
24339
  import path63 from "node:path";
24310
24340
  import { spawnSync as spawnSync3 } from "node:child_process";
@@ -24315,13 +24345,13 @@ function looksLikePrivateKey(name, abs) {
24315
24345
  return false;
24316
24346
  let firstLine = "";
24317
24347
  try {
24318
- const fd = fs53.openSync(abs, "r");
24348
+ const fd = fs54.openSync(abs, "r");
24319
24349
  try {
24320
24350
  const buf = Buffer.alloc(64);
24321
- const n = fs53.readSync(fd, buf, 0, 64, 0);
24351
+ const n = fs54.readSync(fd, buf, 0, 64, 0);
24322
24352
  firstLine = buf.toString("utf-8", 0, n).split("\n")[0];
24323
24353
  } finally {
24324
- fs53.closeSync(fd);
24354
+ fs54.closeSync(fd);
24325
24355
  }
24326
24356
  } catch {
24327
24357
  return false;
@@ -24335,7 +24365,7 @@ function isKeyEncrypted(abs) {
24335
24365
  function listSshKeys() {
24336
24366
  let entries = [];
24337
24367
  try {
24338
- entries = fs53.readdirSync(SSH_DIR);
24368
+ entries = fs54.readdirSync(SSH_DIR);
24339
24369
  } catch {
24340
24370
  return [];
24341
24371
  }
@@ -24343,7 +24373,7 @@ function listSshKeys() {
24343
24373
  for (const name of entries) {
24344
24374
  const abs = path63.join(SSH_DIR, name);
24345
24375
  try {
24346
- if (!fs53.statSync(abs).isFile())
24376
+ if (!fs54.statSync(abs).isFile())
24347
24377
  continue;
24348
24378
  } catch {
24349
24379
  continue;
@@ -24368,9 +24398,9 @@ function unlockSshKey(keyPath, passphrase) {
24368
24398
  return { ok: false, error: "ssh-agent is not running" };
24369
24399
  let dir = "";
24370
24400
  try {
24371
- dir = fs53.mkdtempSync(path63.join(os6.tmpdir(), "halo-askpass-"));
24401
+ dir = fs54.mkdtempSync(path63.join(os6.tmpdir(), "halo-askpass-"));
24372
24402
  const askpass = path63.join(dir, "askpass.sh");
24373
- fs53.writeFileSync(askpass, ASKPASS_SCRIPT, { mode: 448 });
24403
+ fs54.writeFileSync(askpass, ASKPASS_SCRIPT, { mode: 448 });
24374
24404
  const r = spawnSync3("ssh-add", [keyPath], {
24375
24405
  encoding: "utf-8",
24376
24406
  // stdin from /dev/null so ssh-add can never fall back to a tty prompt and block.
@@ -24399,7 +24429,7 @@ function unlockSshKey(keyPath, passphrase) {
24399
24429
  return { ok: false, error: "Failed to unlock key" };
24400
24430
  } finally {
24401
24431
  if (dir)
24402
- fs53.rmSync(dir, { recursive: true, force: true });
24432
+ fs54.rmSync(dir, { recursive: true, force: true });
24403
24433
  }
24404
24434
  }
24405
24435
  function ensureSshAgent() {
@@ -24857,7 +24887,7 @@ var init_git = __esm({
24857
24887
 
24858
24888
  // ../server/dist/routes/agent-configs.js
24859
24889
  import { Hono as Hono5 } from "hono";
24860
- import fs54 from "node:fs/promises";
24890
+ import fs55 from "node:fs/promises";
24861
24891
  import path65 from "node:path";
24862
24892
  import { homedir as homedir20 } from "node:os";
24863
24893
  import YAML14 from "yaml";
@@ -24884,12 +24914,12 @@ ${a2a[0].description}`
24884
24914
  }
24885
24915
  async function writeFileAtomic2(filePath, content) {
24886
24916
  const tmpPath = `${filePath}.tmp`;
24887
- await fs54.writeFile(tmpPath, content, "utf-8");
24917
+ await fs55.writeFile(tmpPath, content, "utf-8");
24888
24918
  try {
24889
- await fs54.rename(tmpPath, filePath);
24919
+ await fs55.rename(tmpPath, filePath);
24890
24920
  } catch {
24891
- await fs54.writeFile(filePath, content, "utf-8");
24892
- await fs54.rm(tmpPath, { force: true }).catch(() => {
24921
+ await fs55.writeFile(filePath, content, "utf-8");
24922
+ await fs55.rm(tmpPath, { force: true }).catch(() => {
24893
24923
  });
24894
24924
  }
24895
24925
  }
@@ -24927,7 +24957,7 @@ async function scaffoldModelBlock(scope, projectId) {
24927
24957
  for (const yamlPath of candidates) {
24928
24958
  let content;
24929
24959
  try {
24930
- content = await fs54.readFile(yamlPath, "utf-8");
24960
+ content = await fs55.readFile(yamlPath, "utf-8");
24931
24961
  } catch {
24932
24962
  continue;
24933
24963
  }
@@ -24974,7 +25004,7 @@ function defaultAgentYamlTemplate() {
24974
25004
  }, { lineWidth: 120 });
24975
25005
  }
24976
25006
  async function ensureDir2(dir) {
24977
- await fs54.mkdir(dir, { recursive: true });
25007
+ await fs55.mkdir(dir, { recursive: true });
24978
25008
  }
24979
25009
  function resolveAgentDir(id, scope, projectId) {
24980
25010
  if (scope === "global")
@@ -24987,14 +25017,14 @@ async function scanAgentsDir(dir, scope) {
24987
25017
  const agents = [];
24988
25018
  let names;
24989
25019
  try {
24990
- names = await fs54.readdir(dir);
25020
+ names = await fs55.readdir(dir);
24991
25021
  } catch {
24992
25022
  return agents;
24993
25023
  }
24994
25024
  for (const entryName of names) {
24995
25025
  const agentDir = path65.join(dir, entryName);
24996
25026
  try {
24997
- const stat = await fs54.stat(agentDir);
25027
+ const stat = await fs55.stat(agentDir);
24998
25028
  if (!stat.isDirectory())
24999
25029
  continue;
25000
25030
  } catch {
@@ -25002,8 +25032,8 @@ async function scanAgentsDir(dir, scope) {
25002
25032
  }
25003
25033
  const yamlPath = path65.join(agentDir, "agent.yaml");
25004
25034
  try {
25005
- const yamlStat = await fs54.stat(yamlPath);
25006
- const parsed = _yamlCache2.get(yamlPath, yamlStat.mtimeMs) ?? _yamlCache2.set(yamlPath, yamlStat.mtimeMs, parseAgentYaml(await fs54.readFile(yamlPath, "utf-8")));
25035
+ const yamlStat = await fs55.stat(yamlPath);
25036
+ const parsed = _yamlCache2.get(yamlPath, yamlStat.mtimeMs) ?? _yamlCache2.set(yamlPath, yamlStat.mtimeMs, parseAgentYaml(await fs55.readFile(yamlPath, "utf-8")));
25007
25037
  const { name, description, model, priority, tools, skills, internal } = parsed;
25008
25038
  agents.push({
25009
25039
  id: entryName,
@@ -25027,10 +25057,10 @@ async function ensureDefaultAgent(dir) {
25027
25057
  const defaultDir = path65.join(dir, "default");
25028
25058
  const yamlPath = path65.join(defaultDir, "agent.yaml");
25029
25059
  try {
25030
- await fs54.access(yamlPath);
25060
+ await fs55.access(yamlPath);
25031
25061
  } catch {
25032
25062
  await ensureDir2(defaultDir);
25033
- await fs54.writeFile(yamlPath, defaultAgentYamlTemplate(), "utf-8");
25063
+ await fs55.writeFile(yamlPath, defaultAgentYamlTemplate(), "utf-8");
25034
25064
  }
25035
25065
  }
25036
25066
  function createAgentConfigRoutes() {
@@ -25088,28 +25118,28 @@ function createAgentConfigRoutes() {
25088
25118
  }
25089
25119
  const agentDir = path65.join(baseDir, id);
25090
25120
  try {
25091
- await fs54.access(agentDir);
25121
+ await fs55.access(agentDir);
25092
25122
  return c.json({ error: "Agent already exists" }, 409);
25093
25123
  } catch {
25094
25124
  }
25095
25125
  let conflictScope = null;
25096
25126
  if (scope === "workspace") {
25097
25127
  try {
25098
- await fs54.access(path65.join(GLOBAL_AGENTS_DIR4, id));
25128
+ await fs55.access(path65.join(GLOBAL_AGENTS_DIR4, id));
25099
25129
  conflictScope = "global";
25100
25130
  } catch {
25101
25131
  }
25102
25132
  } else if (body.projectId) {
25103
25133
  try {
25104
- await fs54.access(path65.join(body.projectId, ".halo", "agents", id));
25134
+ await fs55.access(path65.join(body.projectId, ".halo", "agents", id));
25105
25135
  conflictScope = "workspace";
25106
25136
  } catch {
25107
25137
  }
25108
25138
  }
25109
25139
  const scaffoldModel = await scaffoldModelBlock(scope, body.projectId);
25110
25140
  await ensureDir2(agentDir);
25111
- await fs54.writeFile(path65.join(agentDir, "agent.yaml"), defaultAgentYaml(body.name, body.description ?? "", scaffoldModel), "utf-8");
25112
- await fs54.writeFile(path65.join(agentDir, "AGENT.md"), `# ${body.name}
25141
+ await fs55.writeFile(path65.join(agentDir, "agent.yaml"), defaultAgentYaml(body.name, body.description ?? "", scaffoldModel), "utf-8");
25142
+ await fs55.writeFile(path65.join(agentDir, "AGENT.md"), `# ${body.name}
25113
25143
 
25114
25144
  ${body.description ?? ""}
25115
25145
  `, "utf-8");
@@ -25128,7 +25158,7 @@ ${body.description ?? ""}
25128
25158
  const { agentDir } = resolved;
25129
25159
  const yamlPath = path65.join(agentDir, "agent.yaml");
25130
25160
  try {
25131
- const content = await fs54.readFile(yamlPath, "utf-8");
25161
+ const content = await fs55.readFile(yamlPath, "utf-8");
25132
25162
  return c.json({ yaml: content });
25133
25163
  } catch {
25134
25164
  return c.json({ error: "Agent not found" }, 404);
@@ -25152,7 +25182,7 @@ ${body.description ?? ""}
25152
25182
  const { agentDir } = resolved;
25153
25183
  const yamlPath = path65.join(agentDir, "agent.yaml");
25154
25184
  try {
25155
- await fs54.access(agentDir);
25185
+ await fs55.access(agentDir);
25156
25186
  } catch {
25157
25187
  return c.json({ error: "Agent not found" }, 404);
25158
25188
  }
@@ -25165,7 +25195,7 @@ ${body.description ?? ""}
25165
25195
  if (typeof next.maxTokens === "number" && modelMax !== void 0 && next.maxTokens > modelMax) {
25166
25196
  let prev;
25167
25197
  try {
25168
- prev = ctxKey(YAML14.parse(await fs54.readFile(yamlPath, "utf-8")));
25198
+ prev = ctxKey(YAML14.parse(await fs55.readFile(yamlPath, "utf-8")));
25169
25199
  } catch {
25170
25200
  prev = void 0;
25171
25201
  }
@@ -25188,7 +25218,7 @@ ${body.description ?? ""}
25188
25218
  return c.json({ error: resolved.error }, 400);
25189
25219
  const { agentDir } = resolved;
25190
25220
  try {
25191
- await fs54.access(agentDir);
25221
+ await fs55.access(agentDir);
25192
25222
  } catch {
25193
25223
  return c.json({ error: "Agent not found" }, 404);
25194
25224
  }
@@ -25198,7 +25228,7 @@ ${body.description ?? ""}
25198
25228
  return c.json({ error: "Cannot delete the last global agent. At least one global agent must remain." }, 400);
25199
25229
  }
25200
25230
  }
25201
- await fs54.rm(agentDir, { recursive: true, force: true });
25231
+ await fs55.rm(agentDir, { recursive: true, force: true });
25202
25232
  return c.json({ ok: true });
25203
25233
  });
25204
25234
  app2.patch("/agent-configs/:id/toggle", async (c) => {
@@ -25234,7 +25264,7 @@ ${body.description ?? ""}
25234
25264
  if (!filePath)
25235
25265
  return c.json({ content: "", exists: false, readOnly: !isMdWritable(fileType) });
25236
25266
  try {
25237
- const content = await fs54.readFile(filePath, "utf-8");
25267
+ const content = await fs55.readFile(filePath, "utf-8");
25238
25268
  return c.json({ content, exists: true, path: filePath, readOnly: !isMdWritable(fileType) });
25239
25269
  } catch {
25240
25270
  return c.json({ content: "", exists: false, path: filePath, readOnly: !isMdWritable(fileType) });
@@ -25275,7 +25305,7 @@ ${body.description ?? ""}
25275
25305
  continue;
25276
25306
  }
25277
25307
  try {
25278
- const content = await fs54.readFile(filePath, "utf-8");
25308
+ const content = await fs55.readFile(filePath, "utf-8");
25279
25309
  result[ft] = { content, exists: true, path: filePath, readOnly: !isMdWritable(ft) };
25280
25310
  } catch {
25281
25311
  result[ft] = { content: "", exists: false, path: filePath, readOnly: !isMdWritable(ft) };
@@ -25299,7 +25329,7 @@ ${body.description ?? ""}
25299
25329
  const dir = getSessionsDir(agentId, source, projectId || void 0);
25300
25330
  let files;
25301
25331
  try {
25302
- files = await fs54.readdir(dir);
25332
+ files = await fs55.readdir(dir);
25303
25333
  } catch {
25304
25334
  return c.json({ sessions: [] });
25305
25335
  }
@@ -25308,7 +25338,7 @@ ${body.description ?? ""}
25308
25338
  if (!f.endsWith(".json"))
25309
25339
  continue;
25310
25340
  try {
25311
- const raw = await fs54.readFile(path65.join(dir, f), "utf-8");
25341
+ const raw = await fs55.readFile(path65.join(dir, f), "utf-8");
25312
25342
  const session = JSON.parse(raw);
25313
25343
  sessions.push({
25314
25344
  id: session.id,
@@ -25342,7 +25372,7 @@ ${body.description ?? ""}
25342
25372
  if (!filePath)
25343
25373
  return c.json({ error: "Invalid id" }, 400);
25344
25374
  try {
25345
- const raw = await fs54.readFile(filePath, "utf-8");
25375
+ const raw = await fs55.readFile(filePath, "utf-8");
25346
25376
  return c.json({ session: JSON.parse(raw) });
25347
25377
  } catch {
25348
25378
  return c.json({ error: "Session not found" }, 404);
@@ -25361,7 +25391,7 @@ ${body.description ?? ""}
25361
25391
  const dir = getSessionsDir(agentId, source, projectId || void 0);
25362
25392
  if (agentId === GOAL_AGENT_ID && !config.goalModeEnabled) {
25363
25393
  try {
25364
- await fs54.access(path65.join(dir, `${sessionId}.json`));
25394
+ await fs55.access(path65.join(dir, `${sessionId}.json`));
25365
25395
  } catch {
25366
25396
  return c.json({ error: "Goal mode is disabled." }, 403);
25367
25397
  }
@@ -25383,7 +25413,7 @@ ${body.description ?? ""}
25383
25413
  agentSnapshot: body.agentSnapshot ?? {},
25384
25414
  messages: messages2
25385
25415
  };
25386
- await fs54.writeFile(path65.join(dir, `${sessionId}.json`), JSON.stringify(session, null, 2), "utf-8");
25416
+ await fs55.writeFile(path65.join(dir, `${sessionId}.json`), JSON.stringify(session, null, 2), "utf-8");
25387
25417
  return c.json({ id: sessionId, session: { ...session, messages: void 0 } });
25388
25418
  });
25389
25419
  app2.delete("/agent-configs/:id/sessions", async (c) => {
@@ -25395,11 +25425,11 @@ ${body.description ?? ""}
25395
25425
  const dir = getSessionsDir(agentId, source, projectId || void 0);
25396
25426
  let deleted = 0;
25397
25427
  try {
25398
- const files = await fs54.readdir(dir);
25428
+ const files = await fs55.readdir(dir);
25399
25429
  for (const f of files) {
25400
25430
  if (!f.endsWith(".json"))
25401
25431
  continue;
25402
- await fs54.rm(path65.join(dir, f));
25432
+ await fs55.rm(path65.join(dir, f));
25403
25433
  deleted++;
25404
25434
  }
25405
25435
  } catch {
@@ -25411,7 +25441,7 @@ ${body.description ?? ""}
25411
25441
  if (!filePath)
25412
25442
  return c.json({ error: "Invalid id" }, 400);
25413
25443
  try {
25414
- await fs54.rm(filePath);
25444
+ await fs55.rm(filePath);
25415
25445
  return c.json({ ok: true });
25416
25446
  } catch {
25417
25447
  return c.json({ error: "Session not found" }, 404);
@@ -25443,7 +25473,7 @@ var init_agent_configs = __esm({
25443
25473
 
25444
25474
  // ../server/dist/routes/skills.js
25445
25475
  import { Hono as Hono6 } from "hono";
25446
- import fs55 from "node:fs/promises";
25476
+ import fs56 from "node:fs/promises";
25447
25477
  import path66 from "node:path";
25448
25478
  import { homedir as homedir21 } from "node:os";
25449
25479
  import YAML15 from "yaml";
@@ -25463,20 +25493,20 @@ function defaultSkillSettings() {
25463
25493
  }
25464
25494
  async function readYamlFile3(filePath) {
25465
25495
  try {
25466
- const content = await fs55.readFile(filePath, "utf-8");
25496
+ const content = await fs56.readFile(filePath, "utf-8");
25467
25497
  return YAML15.parse(content) ?? {};
25468
25498
  } catch {
25469
25499
  try {
25470
25500
  const jsonPath = filePath.replace(/\.yaml$/, ".json");
25471
- return JSON.parse(await fs55.readFile(jsonPath, "utf-8"));
25501
+ return JSON.parse(await fs56.readFile(jsonPath, "utf-8"));
25472
25502
  } catch {
25473
25503
  return {};
25474
25504
  }
25475
25505
  }
25476
25506
  }
25477
25507
  async function writeYamlFile(filePath, data) {
25478
- await fs55.mkdir(path66.dirname(filePath), { recursive: true });
25479
- await fs55.writeFile(filePath, YAML15.stringify(data, { lineWidth: 120 }), "utf-8");
25508
+ await fs56.mkdir(path66.dirname(filePath), { recursive: true });
25509
+ await fs56.writeFile(filePath, YAML15.stringify(data, { lineWidth: 120 }), "utf-8");
25480
25510
  }
25481
25511
  async function addSkillSettings(settingsPath, skillId) {
25482
25512
  const settings = await readYamlFile3(settingsPath);
@@ -25499,7 +25529,7 @@ async function removeSkillSettings(settingsPath, skillId) {
25499
25529
  }
25500
25530
  }
25501
25531
  async function ensureDir3(dir) {
25502
- await fs55.mkdir(dir, { recursive: true });
25532
+ await fs56.mkdir(dir, { recursive: true });
25503
25533
  }
25504
25534
  function toSkillMd(name, description) {
25505
25535
  return `---
@@ -25518,17 +25548,17 @@ async function readSkillMetas(dirs) {
25518
25548
  const base = { path: skillDir, scope, ...extId ? { extId } : {}, ...overridden ? { overridden } : {} };
25519
25549
  const skillMdPath = path66.join(skillDir, "SKILL.md");
25520
25550
  try {
25521
- const mdStat = await fs55.stat(skillMdPath);
25551
+ const mdStat = await fs56.stat(skillMdPath);
25522
25552
  let meta = _skillMdCache.get(skillMdPath, mdStat.mtimeMs);
25523
25553
  if (!meta) {
25524
- const { name, description, command } = parseSkillFrontmatter(await fs55.readFile(skillMdPath, "utf-8"));
25554
+ const { name, description, command } = parseSkillFrontmatter(await fs56.readFile(skillMdPath, "utf-8"));
25525
25555
  meta = _skillMdCache.set(skillMdPath, mdStat.mtimeMs, { name: name || entryName, description: description ?? "", command });
25526
25556
  }
25527
25557
  skills.push({ id: entryName, name: meta.name, description: meta.description, ...base, command: meta.command });
25528
25558
  } catch {
25529
25559
  const yamlPath = path66.join(skillDir, "skill.yaml");
25530
25560
  try {
25531
- const yamlContent = await fs55.readFile(yamlPath, "utf-8");
25561
+ const yamlContent = await fs56.readFile(yamlPath, "utf-8");
25532
25562
  const m = yamlContent.match(/^name:\s*(.+)$/m);
25533
25563
  const d = yamlContent.match(/^description:\s*(.+)$/m);
25534
25564
  skills.push({ id: entryName, name: m?.[1]?.trim() || entryName, description: d?.[1]?.trim() || "", ...base });
@@ -25570,12 +25600,12 @@ function createSkillRoutes() {
25570
25600
  }
25571
25601
  const skillDir = path66.join(baseDir, id);
25572
25602
  try {
25573
- await fs55.access(skillDir);
25603
+ await fs56.access(skillDir);
25574
25604
  return c.json({ error: "Skill already exists" }, 409);
25575
25605
  } catch {
25576
25606
  }
25577
25607
  await ensureDir3(skillDir);
25578
- await fs55.writeFile(path66.join(skillDir, "SKILL.md"), toSkillMd(body.name, body.description ?? ""), "utf-8");
25608
+ await fs56.writeFile(path66.join(skillDir, "SKILL.md"), toSkillMd(body.name, body.description ?? ""), "utf-8");
25579
25609
  const settingsPath = scope === "workspace" && body.projectId ? path66.join(body.projectId, ".halo", "settings.yaml") : GLOBAL_SETTINGS_PATH;
25580
25610
  await addSkillSettings(settingsPath, id);
25581
25611
  notifySkillsChanged(scope === "workspace" ? body.projectId : null);
@@ -25597,11 +25627,11 @@ function createSkillRoutes() {
25597
25627
  skillDir = path66.join(GLOBAL_SKILLS_DIR, id);
25598
25628
  }
25599
25629
  try {
25600
- await fs55.access(skillDir);
25630
+ await fs56.access(skillDir);
25601
25631
  } catch {
25602
25632
  return c.json({ error: "Skill not found" }, 404);
25603
25633
  }
25604
- await fs55.rm(skillDir, { recursive: true, force: true });
25634
+ await fs56.rm(skillDir, { recursive: true, force: true });
25605
25635
  const settingsPath = scope === "workspace" && projectId ? path66.join(projectId, ".halo", "settings.yaml") : GLOBAL_SETTINGS_PATH;
25606
25636
  await removeSkillSettings(settingsPath, id);
25607
25637
  notifySkillsChanged(scope === "workspace" && projectId ? projectId : null);
@@ -25638,23 +25668,23 @@ var init_skills = __esm({
25638
25668
 
25639
25669
  // ../server/dist/routes/settings.js
25640
25670
  import { Hono as Hono7 } from "hono";
25641
- import fs56 from "node:fs/promises";
25671
+ import fs57 from "node:fs/promises";
25642
25672
  import path67 from "node:path";
25643
25673
  import { homedir as homedir22 } from "node:os";
25644
25674
  import YAML16 from "yaml";
25645
25675
  async function readSettingsFile(filePath) {
25646
25676
  try {
25647
- const content = await fs56.readFile(filePath, "utf-8");
25677
+ const content = await fs57.readFile(filePath, "utf-8");
25648
25678
  return YAML16.parse(content) ?? {};
25649
25679
  } catch {
25650
25680
  return {};
25651
25681
  }
25652
25682
  }
25653
25683
  async function writeSettingsFile(filePath, data) {
25654
- await fs56.mkdir(path67.dirname(filePath), { recursive: true });
25655
- await fs56.writeFile(filePath, YAML16.stringify(data, { lineWidth: 120 }), { encoding: "utf-8", mode: 384 });
25684
+ await fs57.mkdir(path67.dirname(filePath), { recursive: true });
25685
+ await fs57.writeFile(filePath, YAML16.stringify(data, { lineWidth: 120 }), { encoding: "utf-8", mode: 384 });
25656
25686
  try {
25657
- await fs56.chmod(filePath, 384);
25687
+ await fs57.chmod(filePath, 384);
25658
25688
  } catch {
25659
25689
  }
25660
25690
  }
@@ -25917,18 +25947,18 @@ var init_settings = __esm({
25917
25947
  });
25918
25948
 
25919
25949
  // ../server/dist/evolution/archive.js
25920
- import fs57 from "node:fs";
25950
+ import fs58 from "node:fs";
25921
25951
  import path68 from "node:path";
25922
25952
  import { pipeline } from "node:stream/promises";
25923
25953
  import JSZip from "jszip";
25924
25954
  import { eq as eq13, and as and9, isNull as isNull5, lte, isNotNull as isNotNull3, lt as lt3 } from "drizzle-orm";
25925
25955
  async function zipDir(srcDir, outZip) {
25926
- if (!fs57.existsSync(srcDir))
25956
+ if (!fs58.existsSync(srcDir))
25927
25957
  return false;
25928
- fs57.mkdirSync(path68.dirname(outZip), { recursive: true });
25958
+ fs58.mkdirSync(path68.dirname(outZip), { recursive: true });
25929
25959
  const zip = new JSZip();
25930
25960
  const walk = (dir, rel) => {
25931
- const entries = fs57.readdirSync(dir, { withFileTypes: true });
25961
+ const entries = fs58.readdirSync(dir, { withFileTypes: true });
25932
25962
  if (entries.length === 0 && rel) {
25933
25963
  zip.folder(rel);
25934
25964
  return;
@@ -25939,11 +25969,11 @@ async function zipDir(srcDir, outZip) {
25939
25969
  if (e.isDirectory()) {
25940
25970
  walk(abs, childRel);
25941
25971
  } else if (e.isFile()) {
25942
- zip.file(childRel, fs57.readFileSync(abs), { date: fs57.statSync(abs).mtime });
25972
+ zip.file(childRel, fs58.readFileSync(abs), { date: fs58.statSync(abs).mtime });
25943
25973
  } else if (e.isSymbolicLink()) {
25944
25974
  try {
25945
- if (fs57.statSync(abs).isFile())
25946
- zip.file(childRel, fs57.readFileSync(abs));
25975
+ if (fs58.statSync(abs).isFile())
25976
+ zip.file(childRel, fs58.readFileSync(abs));
25947
25977
  } catch {
25948
25978
  }
25949
25979
  }
@@ -25951,7 +25981,7 @@ async function zipDir(srcDir, outZip) {
25951
25981
  };
25952
25982
  try {
25953
25983
  walk(srcDir, "");
25954
- await pipeline(zip.generateNodeStream({ type: "nodebuffer", streamFiles: true, compression: "DEFLATE" }), fs57.createWriteStream(outZip));
25984
+ await pipeline(zip.generateNodeStream({ type: "nodebuffer", streamFiles: true, compression: "DEFLATE" }), fs58.createWriteStream(outZip));
25955
25985
  return true;
25956
25986
  } catch (err) {
25957
25987
  rmFile(outZip);
@@ -25961,20 +25991,20 @@ async function zipDir(srcDir, outZip) {
25961
25991
  }
25962
25992
  function rmDir(dir) {
25963
25993
  try {
25964
- fs57.rmSync(dir, { recursive: true, force: true });
25994
+ fs58.rmSync(dir, { recursive: true, force: true });
25965
25995
  } catch {
25966
25996
  }
25967
25997
  }
25968
25998
  function rmFile(p) {
25969
25999
  try {
25970
- fs57.rmSync(p, { force: true });
26000
+ fs58.rmSync(p, { force: true });
25971
26001
  } catch {
25972
26002
  }
25973
26003
  }
25974
26004
  async function archiveRun(workspacePath, runId, errors) {
25975
26005
  const runDir = wsEvoRunDir(workspacePath, runId);
25976
26006
  const outZip = wsEvoArchivedRunZip(workspacePath, runId);
25977
- if (!fs57.existsSync(runDir)) {
26007
+ if (!fs58.existsSync(runDir)) {
25978
26008
  return true;
25979
26009
  }
25980
26010
  if (!await zipDir(runDir, outZip)) {
@@ -25987,7 +26017,7 @@ async function archiveRun(workspacePath, runId, errors) {
25987
26017
  async function archiveApply(workspacePath, applyId, errors) {
25988
26018
  const applyDir = wsEvoApplyDir(workspacePath, applyId);
25989
26019
  const outZip = wsEvoArchivedApplyZip(workspacePath, applyId);
25990
- if (!fs57.existsSync(applyDir))
26020
+ if (!fs58.existsSync(applyDir))
25991
26021
  return true;
25992
26022
  if (!await zipDir(applyDir, outZip)) {
25993
26023
  errors.push(`zip failed for apply ${applyId}`);
@@ -26114,7 +26144,7 @@ var init_raw_sqlite = __esm({
26114
26144
  // ../server/dist/routes/evolution.js
26115
26145
  import { Hono as Hono8 } from "hono";
26116
26146
  import { eq as eq14, desc as desc2, lt as lt4, and as and10, or as or2, sql as sql2 } from "drizzle-orm";
26117
- import fs58 from "node:fs/promises";
26147
+ import fs59 from "node:fs/promises";
26118
26148
  import path69 from "node:path";
26119
26149
  function createEvolutionRoutes() {
26120
26150
  const router = new Hono8();
@@ -26180,33 +26210,33 @@ function createEvolutionRoutes() {
26180
26210
  const dir = wsEvoRunDir(row.workspacePath, id);
26181
26211
  let patchMd = null;
26182
26212
  try {
26183
- patchMd = await fs58.readFile(path69.join(dir, "patch.md"), "utf-8");
26213
+ patchMd = await fs59.readFile(path69.join(dir, "patch.md"), "utf-8");
26184
26214
  } catch {
26185
26215
  }
26186
26216
  let scoreJson = null;
26187
26217
  try {
26188
- const raw = await fs58.readFile(path69.join(dir, "score.json"), "utf-8");
26218
+ const raw = await fs59.readFile(path69.join(dir, "score.json"), "utf-8");
26189
26219
  scoreJson = JSON.parse(raw);
26190
26220
  } catch {
26191
26221
  }
26192
26222
  let wrapperLog = null;
26193
26223
  try {
26194
- wrapperLog = await fs58.readFile(evoWrapperLogFile(id), "utf-8");
26224
+ wrapperLog = await fs59.readFile(evoWrapperLogFile(id), "utf-8");
26195
26225
  } catch {
26196
26226
  }
26197
26227
  let subCliLog = null;
26198
26228
  try {
26199
- subCliLog = await fs58.readFile(path69.join(dir, "sub-cli.log"), "utf-8");
26229
+ subCliLog = await fs59.readFile(path69.join(dir, "sub-cli.log"), "utf-8");
26200
26230
  } catch {
26201
26231
  }
26202
26232
  let skipReasonMd = null;
26203
26233
  try {
26204
- skipReasonMd = await fs58.readFile(path69.join(dir, ".skip.md"), "utf-8");
26234
+ skipReasonMd = await fs59.readFile(path69.join(dir, ".skip.md"), "utf-8");
26205
26235
  } catch {
26206
26236
  }
26207
26237
  let snapshotSummary = null;
26208
26238
  try {
26209
- const raw = await fs58.readFile(path69.join(dir, "source-snapshot.json"), "utf-8");
26239
+ const raw = await fs59.readFile(path69.join(dir, "source-snapshot.json"), "utf-8");
26210
26240
  const parsed = JSON.parse(raw);
26211
26241
  const msgs = parsed.rawMessages ?? [];
26212
26242
  const firstUser = msgs.find((m) => m.role === "user");
@@ -27099,7 +27129,7 @@ var init_auth = __esm({
27099
27129
  });
27100
27130
 
27101
27131
  // ../server/dist/channels/web/handler.js
27102
- import fs59 from "node:fs";
27132
+ import fs60 from "node:fs";
27103
27133
  function buildWebSessionPrefix(accountId) {
27104
27134
  return sessionPrefix("web", accountId);
27105
27135
  }
@@ -27127,7 +27157,7 @@ function createWebChannel(deps) {
27127
27157
  }
27128
27158
  path94 = override;
27129
27159
  }
27130
- const resolved = scaffold ? resolveAccountWorkspace({ ...account, workspacePath: path94 }) : fs59.existsSync(path94) ? path94 : null;
27160
+ const resolved = scaffold ? resolveAccountWorkspace({ ...account, workspacePath: path94 }) : fs60.existsSync(path94) ? path94 : null;
27131
27161
  if (!resolved)
27132
27162
  return { ok: false, error: "workspace not found" };
27133
27163
  return { ok: true, path: resolved };
@@ -27554,14 +27584,14 @@ var init_etag = __esm({
27554
27584
 
27555
27585
  // ../server/dist/routes/halo-city.js
27556
27586
  import { Hono as Hono12 } from "hono";
27557
- import fs60 from "node:fs";
27587
+ import fs61 from "node:fs";
27558
27588
  import path70 from "node:path";
27559
27589
  import crypto7 from "node:crypto";
27560
27590
  import Database7 from "better-sqlite3";
27561
27591
  function scanSkills2(dir) {
27562
27592
  let names;
27563
27593
  try {
27564
- names = fs60.readdirSync(dir);
27594
+ names = fs61.readdirSync(dir);
27565
27595
  } catch {
27566
27596
  return [];
27567
27597
  }
@@ -27570,7 +27600,7 @@ function scanSkills2(dir) {
27570
27600
  const skillMd = path70.join(dir, entry, "SKILL.md");
27571
27601
  let stat;
27572
27602
  try {
27573
- stat = fs60.statSync(skillMd);
27603
+ stat = fs61.statSync(skillMd);
27574
27604
  if (!stat.isFile())
27575
27605
  continue;
27576
27606
  } catch {
@@ -27579,7 +27609,7 @@ function scanSkills2(dir) {
27579
27609
  let meta = _skillCache.get(skillMd, stat.mtimeMs);
27580
27610
  if (!meta) {
27581
27611
  try {
27582
- const { name, description, command } = parseSkillFrontmatter(fs60.readFileSync(skillMd, "utf-8"));
27612
+ const { name, description, command } = parseSkillFrontmatter(fs61.readFileSync(skillMd, "utf-8"));
27583
27613
  meta = _skillCache.set(skillMd, stat.mtimeMs, { id: entry, name: name || entry, description: description ?? "", command });
27584
27614
  } catch {
27585
27615
  continue;
@@ -27664,7 +27694,7 @@ function snapshotWorkspace(sm, wsPath, label) {
27664
27694
  function roReader(rawPath) {
27665
27695
  let wsPath;
27666
27696
  try {
27667
- wsPath = fs60.realpathSync(rawPath);
27697
+ wsPath = fs61.realpathSync(rawPath);
27668
27698
  } catch {
27669
27699
  return null;
27670
27700
  }
@@ -27672,7 +27702,7 @@ function roReader(rawPath) {
27672
27702
  if (cached2)
27673
27703
  return cached2;
27674
27704
  const dbPath = path70.join(wsPath, ".halo", "halo.db");
27675
- if (!fs60.existsSync(dbPath))
27705
+ if (!fs61.existsSync(dbPath))
27676
27706
  return null;
27677
27707
  try {
27678
27708
  const db4 = new Database7(dbPath, { readonly: true, fileMustExist: true });
@@ -27701,7 +27731,7 @@ function dropRoReader(rawPath) {
27701
27731
  return;
27702
27732
  let wsPath = rawPath;
27703
27733
  try {
27704
- wsPath = fs60.realpathSync(rawPath);
27734
+ wsPath = fs61.realpathSync(rawPath);
27705
27735
  } catch {
27706
27736
  }
27707
27737
  const r = _roReaders.get(wsPath);
@@ -27797,7 +27827,7 @@ function workspaceBirth(wsPath) {
27797
27827
  let b = _birthCache.get(wsPath);
27798
27828
  if (b === void 0) {
27799
27829
  try {
27800
- b = fs60.statSync(wsPath).birthtimeMs || fs60.statSync(wsPath).ctimeMs;
27830
+ b = fs61.statSync(wsPath).birthtimeMs || fs61.statSync(wsPath).ctimeMs;
27801
27831
  } catch {
27802
27832
  b = 0;
27803
27833
  }
@@ -27809,7 +27839,7 @@ function discoverWorkspaces(registry2) {
27809
27839
  const out = /* @__PURE__ */ new Map();
27810
27840
  const add = (p, label) => {
27811
27841
  try {
27812
- const resolved = fs60.realpathSync(p);
27842
+ const resolved = fs61.realpathSync(p);
27813
27843
  if (!out.has(resolved))
27814
27844
  out.set(resolved, label);
27815
27845
  } catch {
@@ -27888,7 +27918,7 @@ function createShowRoutes(registry2) {
27888
27918
  if (scoped) {
27889
27919
  let allowed = false;
27890
27920
  try {
27891
- allowed = fs60.realpathSync(wsPath) === fs60.realpathSync(scoped.workspacePath);
27921
+ allowed = fs61.realpathSync(wsPath) === fs61.realpathSync(scoped.workspacePath);
27892
27922
  } catch {
27893
27923
  }
27894
27924
  if (!allowed || !canAddressSession(scoped, id))
@@ -27916,7 +27946,7 @@ function createShowRoutes(registry2) {
27916
27946
  const row = reader.getById.get(id);
27917
27947
  if (!row)
27918
27948
  return c.json({ error: "session not found" }, 404);
27919
- if (!fs60.existsSync(uiLogPath(getSessionDir(row.agent_id, wsPath), fileSegment(id))))
27949
+ if (!fs61.existsSync(uiLogPath(getSessionDir(row.agent_id, wsPath), fileSegment(id))))
27920
27950
  return c.json({ error: "session not found" }, 404);
27921
27951
  const data = loadSessionView(id, row.agent_id, wsPath);
27922
27952
  if (!data)
@@ -28300,7 +28330,7 @@ var init_transcribe_ws = __esm({
28300
28330
 
28301
28331
  // ../server/dist/stt/models.js
28302
28332
  import { createHash as createHash3 } from "node:crypto";
28303
- import fs61 from "node:fs";
28333
+ import fs62 from "node:fs";
28304
28334
  import fsp from "node:fs/promises";
28305
28335
  import http2 from "node:http";
28306
28336
  import https2 from "node:https";
@@ -28341,7 +28371,7 @@ function createSttModelManager(opts = {}) {
28341
28371
  let closed = false;
28342
28372
  const fileReady = (f) => {
28343
28373
  try {
28344
- return fs61.statSync(filePath(f.path)).size === f.size;
28374
+ return fs62.statSync(filePath(f.path)).size === f.size;
28345
28375
  } catch {
28346
28376
  return false;
28347
28377
  }
@@ -28364,26 +28394,26 @@ function createSttModelManager(opts = {}) {
28364
28394
  async function fetchFile(f, url, base) {
28365
28395
  const final = filePath(f.path);
28366
28396
  const part = `${final}.part`;
28367
- fs61.mkdirSync(path71.dirname(final), { recursive: true });
28397
+ fs62.mkdirSync(path71.dirname(final), { recursive: true });
28368
28398
  let have = 0;
28369
28399
  try {
28370
- have = fs61.statSync(part).size;
28400
+ have = fs62.statSync(part).size;
28371
28401
  } catch {
28372
28402
  }
28373
28403
  if (have > f.size) {
28374
- fs61.rmSync(part, { force: true });
28404
+ fs62.rmSync(part, { force: true });
28375
28405
  have = 0;
28376
28406
  }
28377
28407
  received = base + have;
28378
28408
  if (have === f.size) {
28379
28409
  const hash = createHash3("sha256");
28380
- for await (const chunk of fs61.createReadStream(part))
28410
+ for await (const chunk of fs62.createReadStream(part))
28381
28411
  hash.update(chunk);
28382
28412
  if (hash.digest("hex") === f.sha256) {
28383
- fs61.renameSync(part, final);
28413
+ fs62.renameSync(part, final);
28384
28414
  return;
28385
28415
  }
28386
- fs61.rmSync(part, { force: true });
28416
+ fs62.rmSync(part, { force: true });
28387
28417
  have = 0;
28388
28418
  }
28389
28419
  const ac = new AbortController();
@@ -28402,7 +28432,7 @@ function createSttModelManager(opts = {}) {
28402
28432
  try {
28403
28433
  const res = await httpGet(url, have > 0 ? { Range: `bytes=${have}-` } : {}, ac.signal);
28404
28434
  if (res.statusCode === 416) {
28405
- fs61.rmSync(part, { force: true });
28435
+ fs62.rmSync(part, { force: true });
28406
28436
  throw new Error("HTTP 416");
28407
28437
  }
28408
28438
  if (res.statusCode !== 200 && res.statusCode !== 206)
@@ -28416,7 +28446,7 @@ function createSttModelManager(opts = {}) {
28416
28446
  const hash = createHash3("sha256");
28417
28447
  let got = 0;
28418
28448
  if (resume) {
28419
- for await (const chunk of fs61.createReadStream(part))
28449
+ for await (const chunk of fs62.createReadStream(part))
28420
28450
  hash.update(chunk);
28421
28451
  got = have;
28422
28452
  }
@@ -28439,10 +28469,10 @@ function createSttModelManager(opts = {}) {
28439
28469
  if (got < f.size)
28440
28470
  throw new Error(`truncated (${got} of ${f.size} bytes)`);
28441
28471
  if (got > f.size || hash.digest("hex") !== f.sha256) {
28442
- fs61.rmSync(part, { force: true });
28472
+ fs62.rmSync(part, { force: true });
28443
28473
  throw new Error(got > f.size ? `size mismatch (more than ${f.size} bytes)` : "sha256 mismatch");
28444
28474
  }
28445
- fs61.renameSync(part, final);
28475
+ fs62.renameSync(part, final);
28446
28476
  } catch (err) {
28447
28477
  if (reason)
28448
28478
  throw new Error(reason);
@@ -28970,7 +29000,7 @@ var init_stt_ws = __esm({
28970
29000
  // ../server/dist/jupyter/manager.js
28971
29001
  import { spawn as nodeSpawn } from "node:child_process";
28972
29002
  import { randomBytes as randomBytes2 } from "node:crypto";
28973
- import fs62 from "node:fs";
29003
+ import fs63 from "node:fs";
28974
29004
  import net from "node:net";
28975
29005
  import os9 from "node:os";
28976
29006
  import path72 from "node:path";
@@ -28978,8 +29008,8 @@ import { WebSocket } from "ws";
28978
29008
  function resolveExecutable(configured) {
28979
29009
  const isExe = (p) => {
28980
29010
  try {
28981
- fs62.accessSync(p, fs62.constants.X_OK);
28982
- return fs62.statSync(p).isFile();
29011
+ fs63.accessSync(p, fs63.constants.X_OK);
29012
+ return fs63.statSync(p).isFile();
28983
29013
  } catch {
28984
29014
  return false;
28985
29015
  }
@@ -29314,7 +29344,7 @@ var init_manager = __esm({
29314
29344
  });
29315
29345
 
29316
29346
  // ../server/dist/routes/jupyter.js
29317
- import fs63 from "node:fs/promises";
29347
+ import fs64 from "node:fs/promises";
29318
29348
  import path73 from "node:path";
29319
29349
  import { Hono as Hono15 } from "hono";
29320
29350
  import { WebSocketServer as WebSocketServer3 } from "ws";
@@ -29346,8 +29376,8 @@ function createJupyterRoutes(jm) {
29346
29376
  return c.json({ error: "Project not found" }, 400);
29347
29377
  if (!validatePath(nbPath, projectPath))
29348
29378
  return c.json({ error: "Path outside the workspace" }, 400);
29349
- const cwd = await fs63.realpath(path73.dirname(path73.resolve(projectPath, nbPath))).catch(() => null);
29350
- if (!cwd || !(await fs63.stat(cwd)).isDirectory())
29379
+ const cwd = await fs64.realpath(path73.dirname(path73.resolve(projectPath, nbPath))).catch(() => null);
29380
+ if (!cwd || !(await fs64.stat(cwd)).isDirectory())
29351
29381
  return c.json({ error: "Notebook directory not found" }, 400);
29352
29382
  try {
29353
29383
  return c.json(await jm.startKernel(name, cwd));
@@ -29518,7 +29548,7 @@ var init_upgrade_router = __esm({
29518
29548
  });
29519
29549
 
29520
29550
  // ../server/dist/ws/git-dir-watcher.js
29521
- import fs64 from "node:fs";
29551
+ import fs65 from "node:fs";
29522
29552
  import path74 from "node:path";
29523
29553
  var GitDirWatcher;
29524
29554
  var init_git_dir_watcher = __esm({
@@ -29544,7 +29574,7 @@ var init_git_dir_watcher = __esm({
29544
29574
  this.stop();
29545
29575
  this.workspaceRoot = workspaceRoot;
29546
29576
  const gitDir = path74.join(workspaceRoot, ".git");
29547
- if (fs64.existsSync(gitDir)) {
29577
+ if (fs65.existsSync(gitDir)) {
29548
29578
  this.watchGitDir(gitDir);
29549
29579
  } else {
29550
29580
  this.watchParentForGit(workspaceRoot);
@@ -29553,7 +29583,7 @@ var init_git_dir_watcher = __esm({
29553
29583
  /** Watch the `.git` dir for index/HEAD changes (steady state). */
29554
29584
  watchGitDir(gitDir) {
29555
29585
  try {
29556
- this.watcher = fs64.watch(gitDir, { persistent: true, recursive: false }, (_eventType, filename) => {
29586
+ this.watcher = fs65.watch(gitDir, { persistent: true, recursive: false }, (_eventType, filename) => {
29557
29587
  this.handleGitEvent(filename);
29558
29588
  });
29559
29589
  this.watcher.on("error", (err) => {
@@ -29572,7 +29602,7 @@ var init_git_dir_watcher = __esm({
29572
29602
  * Exists solely during the non-repo window; upgraded away on first `.git`. */
29573
29603
  watchParentForGit(workspaceRoot) {
29574
29604
  try {
29575
- this.watcher = fs64.watch(workspaceRoot, { persistent: true, recursive: false }, (_eventType, filename) => {
29605
+ this.watcher = fs65.watch(workspaceRoot, { persistent: true, recursive: false }, (_eventType, filename) => {
29576
29606
  this.handleParentEvent(filename);
29577
29607
  });
29578
29608
  this.watcher.on("error", (err) => {
@@ -29609,7 +29639,7 @@ var init_git_dir_watcher = __esm({
29609
29639
  if (!root)
29610
29640
  return;
29611
29641
  const gitDir = path74.join(root, ".git");
29612
- if (!fs64.existsSync(gitDir))
29642
+ if (!fs65.existsSync(gitDir))
29613
29643
  return;
29614
29644
  this.closeWatcher();
29615
29645
  this.watchGitDir(gitDir);
@@ -30650,9 +30680,9 @@ import Database8 from "better-sqlite3";
30650
30680
  import { drizzle as drizzle5 } from "drizzle-orm/better-sqlite3";
30651
30681
  import { sqliteTable as sqliteTable5, text as text5, integer as integer5 } from "drizzle-orm/sqlite-core";
30652
30682
  import path76 from "node:path";
30653
- import fs65 from "node:fs";
30683
+ import fs66 from "node:fs";
30654
30684
  function createCronDb(globalDir2) {
30655
- fs65.mkdirSync(globalDir2, { recursive: true });
30685
+ fs66.mkdirSync(globalDir2, { recursive: true });
30656
30686
  const dbPath = path76.join(globalDir2, "cron.db");
30657
30687
  const sqlite = new Database8(dbPath);
30658
30688
  sqlite.pragma("journal_mode = WAL");
@@ -30868,7 +30898,7 @@ CREATE INDEX IF NOT EXISTS idx_cron_runs_status ON cron_runs(status);
30868
30898
  });
30869
30899
 
30870
30900
  // ../server/dist/a2a/exposure.js
30871
- import fs66 from "node:fs";
30901
+ import fs67 from "node:fs";
30872
30902
  import path77 from "node:path";
30873
30903
  import crypto8 from "node:crypto";
30874
30904
  function samePath(a, b, platform = process.platform) {
@@ -30882,7 +30912,7 @@ function realBase() {
30882
30912
  if (baseCache?.raw !== raw) {
30883
30913
  let real = null;
30884
30914
  try {
30885
- real = fs66.realpathSync(raw);
30915
+ real = fs67.realpathSync(raw);
30886
30916
  } catch {
30887
30917
  console.warn(`[A2A] base dir ${raw} not found \u2014 nothing is exposed`);
30888
30918
  }
@@ -30907,14 +30937,14 @@ function resolveExposedWorkspace(base, rel) {
30907
30937
  }
30908
30938
  let real;
30909
30939
  try {
30910
- real = fs66.realpathSync(path77.join(base, ...segs));
30940
+ real = fs67.realpathSync(path77.join(base, ...segs));
30911
30941
  } catch {
30912
30942
  return null;
30913
30943
  }
30914
30944
  if (!real.startsWith(base.endsWith(path77.sep) ? base : base + path77.sep))
30915
30945
  return null;
30916
30946
  try {
30917
- if (!fs66.statSync(path77.join(real, CARD_FILE)).isFile())
30947
+ if (!fs67.statSync(path77.join(real, CARD_FILE)).isFile())
30918
30948
  return null;
30919
30949
  } catch {
30920
30950
  return null;
@@ -30929,14 +30959,14 @@ function publicOrigin(c) {
30929
30959
  return `${proto}://${c.req.header("host") ?? url.host}`;
30930
30960
  }
30931
30961
  function buildCard(workspace, interfaceUrl, caps) {
30932
- const raw = JSON.parse(fs66.readFileSync(path77.join(workspace, CARD_FILE), "utf8"));
30962
+ const raw = JSON.parse(fs67.readFileSync(path77.join(workspace, CARD_FILE), "utf8"));
30933
30963
  if (typeof raw.name !== "string" || typeof raw.description !== "string" || !Array.isArray(raw.skills)) {
30934
30964
  throw new Error('agent-card.json needs string "name", string "description" and array "skills"');
30935
30965
  }
30936
30966
  return {
30937
30967
  name: raw.name,
30938
30968
  description: raw.description,
30939
- version: typeof raw.version === "string" ? raw.version : "2.0.2",
30969
+ version: typeof raw.version === "string" ? raw.version : "2.0.3",
30940
30970
  supportedInterfaces: [{ url: interfaceUrl, protocolBinding: "JSONRPC", protocolVersion: A2A_VERSION }],
30941
30971
  capabilities: { streaming: caps.streaming, pushNotifications: true, extendedAgentCard: false },
30942
30972
  ...caps.tokenAuth === false ? {} : {
@@ -30977,7 +31007,7 @@ var init_exposure = __esm({
30977
31007
  return { ok: false, status: 404 };
30978
31008
  let bound;
30979
31009
  try {
30980
- bound = fs66.realpathSync(auth.account.workspacePath);
31010
+ bound = fs67.realpathSync(auth.account.workspacePath);
30981
31011
  } catch {
30982
31012
  return { ok: false, status: 404 };
30983
31013
  }
@@ -31429,7 +31459,7 @@ var init_session_id = __esm({
31429
31459
  });
31430
31460
 
31431
31461
  // ../server/dist/a2a/agentcore.js
31432
- import fs67 from "node:fs";
31462
+ import fs68 from "node:fs";
31433
31463
  import os10 from "node:os";
31434
31464
  import path78 from "node:path";
31435
31465
  import crypto10 from "node:crypto";
@@ -31440,17 +31470,17 @@ function readLease(file) {
31440
31470
  let mtimeMs;
31441
31471
  let fd;
31442
31472
  try {
31443
- fd = fs67.openSync(file, "r");
31473
+ fd = fs68.openSync(file, "r");
31444
31474
  } catch (err) {
31445
31475
  if (err.code === "ENOENT")
31446
31476
  return null;
31447
31477
  throw err;
31448
31478
  }
31449
31479
  try {
31450
- mtimeMs = fs67.fstatSync(fd).mtimeMs;
31451
- raw = fs67.readFileSync(fd, "utf8");
31480
+ mtimeMs = fs68.fstatSync(fd).mtimeMs;
31481
+ raw = fs68.readFileSync(fd, "utf8");
31452
31482
  } finally {
31453
- fs67.closeSync(fd);
31483
+ fs68.closeSync(fd);
31454
31484
  }
31455
31485
  try {
31456
31486
  const b = JSON.parse(raw);
@@ -31464,12 +31494,12 @@ function leaseJson(owner, now) {
31464
31494
  }
31465
31495
  function writeLease(file, owner, now) {
31466
31496
  const tmp = `${file}.${owner}.tmp`;
31467
- fs67.writeFileSync(tmp, leaseJson(owner, now));
31468
- fs67.renameSync(tmp, file);
31497
+ fs68.writeFileSync(tmp, leaseJson(owner, now));
31498
+ fs68.renameSync(tmp, file);
31469
31499
  }
31470
31500
  function tryAcquireLease(file, owner, now = Date.now()) {
31471
31501
  try {
31472
- fs67.writeFileSync(file, leaseJson(owner, now), { flag: "wx" });
31502
+ fs68.writeFileSync(file, leaseJson(owner, now), { flag: "wx" });
31473
31503
  return "held";
31474
31504
  } catch (err) {
31475
31505
  if (err.code !== "EEXIST")
@@ -31497,7 +31527,7 @@ function heartbeatLease(file, owner, now = Date.now()) {
31497
31527
  function releaseLease(file, owner) {
31498
31528
  try {
31499
31529
  if (readLease(file)?.body?.owner === owner)
31500
- fs67.unlinkSync(file);
31530
+ fs68.unlinkSync(file);
31501
31531
  } catch {
31502
31532
  }
31503
31533
  }
@@ -31519,7 +31549,7 @@ function upstreamStrategies(workspace, accessLevel) {
31519
31549
  function seedAgentCard(workspace) {
31520
31550
  const card = { name: "Halo", description: "Halo multi-agent workspace on Amazon Bedrock AgentCore. Send a task as plain text.", skills: [] };
31521
31551
  try {
31522
- fs67.writeFileSync(path78.join(workspace, CARD_FILE), `${JSON.stringify(card, null, 2)}
31552
+ fs68.writeFileSync(path78.join(workspace, CARD_FILE), `${JSON.stringify(card, null, 2)}
31523
31553
  `, { flag: "wx" });
31524
31554
  return true;
31525
31555
  } catch (err) {
@@ -31581,18 +31611,18 @@ function parseInvocation(raw) {
31581
31611
  function readPromptFile(workspace, rel) {
31582
31612
  let real;
31583
31613
  try {
31584
- real = fs67.realpathSync(path78.resolve(workspace, rel));
31614
+ real = fs68.realpathSync(path78.resolve(workspace, rel));
31585
31615
  } catch {
31586
31616
  return { error: `promptFile not found: ${rel}` };
31587
31617
  }
31588
31618
  if (!real.startsWith(workspace + path78.sep) || isHiddenWorkspacePath(real, workspace))
31589
31619
  return { error: `promptFile must be a file inside the workspace: ${rel}` };
31590
- const st = fs67.statSync(real);
31620
+ const st = fs68.statSync(real);
31591
31621
  if (!st.isFile())
31592
31622
  return { error: `promptFile is not a regular file: ${rel}` };
31593
31623
  if (st.size > MAX_PROMPT_FILE)
31594
31624
  return { error: `promptFile is larger than ${MAX_PROMPT_FILE} bytes: ${rel}` };
31595
- const text6 = fs67.readFileSync(real, "utf8");
31625
+ const text6 = fs68.readFileSync(real, "utf8");
31596
31626
  return text6.trim() ? text6 : { error: `promptFile is empty: ${rel}` };
31597
31627
  }
31598
31628
  async function startInvocation(sm, workspace, accessLevel, req) {
@@ -31792,7 +31822,7 @@ function createAgentCoreA2ARoutes(deps) {
31792
31822
  return app2;
31793
31823
  }
31794
31824
  function createAgentCoreA2A(registry2, rawWorkspace, onLost) {
31795
- const workspace = fs67.realpathSync(rawWorkspace);
31825
+ const workspace = fs68.realpathSync(rawWorkspace);
31796
31826
  const haloDir = path78.join(workspace, ".halo");
31797
31827
  setDurableDbDir(haloDir);
31798
31828
  if (!config.a2a.publicUrl)
@@ -31807,7 +31837,7 @@ function createAgentCoreA2A(registry2, rawWorkspace, onLost) {
31807
31837
  setA2ADb(a2a);
31808
31838
  runs = createRunsDb(haloDir);
31809
31839
  setRunsDb(runs);
31810
- fs67.rmSync(path78.join(haloDir, RUNTIME_LOCK_FILE), { force: true });
31840
+ fs68.rmSync(path78.join(haloDir, RUNTIME_LOCK_FILE), { force: true });
31811
31841
  registry2.getOrCreate(workspace);
31812
31842
  } catch (err) {
31813
31843
  setA2ADb(null);
@@ -31835,7 +31865,7 @@ function createAgentCoreA2A(registry2, rawWorkspace, onLost) {
31835
31865
  const activate = () => {
31836
31866
  if (active)
31837
31867
  return;
31838
- fs67.mkdirSync(haloDir, { recursive: true });
31868
+ fs68.mkdirSync(haloDir, { recursive: true });
31839
31869
  if (seedAgentCard(workspace))
31840
31870
  console.log(`[AgentCoreA2A] seeded ${path78.join(workspace, CARD_FILE)}`);
31841
31871
  active = true;
@@ -32022,7 +32052,7 @@ var init_dispatcher = __esm({
32022
32052
 
32023
32053
  // ../server/dist/cron/runner.js
32024
32054
  import { spawn as spawn4, execFileSync } from "node:child_process";
32025
- import fs68 from "node:fs";
32055
+ import fs69 from "node:fs";
32026
32056
  import path79 from "node:path";
32027
32057
  import { homedir as homedir24 } from "node:os";
32028
32058
  import { Cron } from "croner";
@@ -32128,7 +32158,7 @@ function jobChangedFields(job) {
32128
32158
  function sessionKeyFor(workspacePath, sessionId) {
32129
32159
  let ws;
32130
32160
  try {
32131
- ws = fs68.realpathSync(workspacePath);
32161
+ ws = fs69.realpathSync(workspacePath);
32132
32162
  } catch {
32133
32163
  ws = path79.resolve(workspacePath);
32134
32164
  }
@@ -32207,7 +32237,7 @@ function sweepOrphanRuns(opts) {
32207
32237
  }
32208
32238
  }
32209
32239
  function startCronDaemon() {
32210
- fs68.mkdirSync(logsDir(), { recursive: true });
32240
+ fs69.mkdirSync(logsDir(), { recursive: true });
32211
32241
  sweepOrphanRuns();
32212
32242
  reloadAll();
32213
32243
  _daemonTimers.push(setInterval(() => {
@@ -32410,7 +32440,7 @@ async function runJob(jobId, triggerKind) {
32410
32440
  const runId = newRunId();
32411
32441
  const startedAt = Date.now();
32412
32442
  const logPath = logPathFor(runId);
32413
- fs68.mkdirSync(logsDir(), { recursive: true });
32443
+ fs69.mkdirSync(logsDir(), { recursive: true });
32414
32444
  const sessionId = job.stateless ? perRunSessionId(job, startedAt) : effectiveSessionId(job);
32415
32445
  const sessionKey = sessionKeyFor(job.workspacePath, sessionId);
32416
32446
  const host = _sessionRegistry?.peek(job.workspacePath);
@@ -32453,7 +32483,7 @@ async function runJob(jobId, triggerKind) {
32453
32483
  }).run();
32454
32484
  broadcast({ type: "cron:run_changed", jobId, runId, status: "running" });
32455
32485
  const targets = parseTargets(job.targets);
32456
- if (!fs68.existsSync(job.workspacePath)) {
32486
+ if (!fs69.existsSync(job.workspacePath)) {
32457
32487
  finalize(runId, jobId, {
32458
32488
  status: "failed",
32459
32489
  output: null,
@@ -32496,7 +32526,7 @@ async function runJob(jobId, triggerKind) {
32496
32526
  args.push("--access", accessLevel);
32497
32527
  const [spawnBin, spawnArgs] = process.platform === "win32" && cli.endsWith(".cmd") ? ["cmd.exe", ["/c", cli, ...args]] : [cli, args];
32498
32528
  const timeoutSec = job.timeoutSec ?? CLI_TIMEOUT_SEC;
32499
- const teeStream = fs68.createWriteStream(logPath, { flags: "a" });
32529
+ const teeStream = fs69.createWriteStream(logPath, { flags: "a" });
32500
32530
  teeStream.write(`=== ${(/* @__PURE__ */ new Date()).toISOString()} cron run ${runId} job=${jobId} trigger=${triggerKind} ===
32501
32531
  `);
32502
32532
  teeStream.write(`agent=${job.agentId} session=${sessionId}${job.stateless ? " (stateless)" : ""}${accessLevel ? ` access=${accessLevel}` : ""} workspace=${job.workspacePath} dir=${job.workingDir ?? "."} schedule=${job.schedule}
@@ -32623,7 +32653,7 @@ function readSessionRow(workspacePath, sessionId) {
32623
32653
  let entry = _sessionRows.get(workspacePath);
32624
32654
  if (!entry) {
32625
32655
  const file = path79.join(workspacePath, ".halo", "halo.db");
32626
- if (!fs68.existsSync(file))
32656
+ if (!fs69.existsSync(file))
32627
32657
  return null;
32628
32658
  entry = { db: new Database9(file, { readonly: true, fileMustExist: true }), version: -1, rows: /* @__PURE__ */ new Map() };
32629
32659
  _sessionRows.set(workspacePath, entry);
@@ -32728,7 +32758,7 @@ async function deleteRuns(runs) {
32728
32758
  const openWorkspace = (workspacePath) => {
32729
32759
  let ws = workspaceOf.get(workspacePath);
32730
32760
  if (ws === void 0) {
32731
- ws = fs68.existsSync(path79.join(workspacePath, ".halo", "halo.db")) ? { workspacePath, db: getWorkspaceDb(workspacePath).db } : null;
32761
+ ws = fs69.existsSync(path79.join(workspacePath, ".halo", "halo.db")) ? { workspacePath, db: getWorkspaceDb(workspacePath).db } : null;
32732
32762
  workspaceOf.set(workspacePath, ws);
32733
32763
  }
32734
32764
  return ws;
@@ -32785,15 +32815,15 @@ async function deleteRunSession({ workspacePath, db: db4 }, run) {
32785
32815
  }
32786
32816
  async function pruneOldLogs() {
32787
32817
  const dir = logsDir();
32788
- if (!fs68.existsSync(dir))
32818
+ if (!fs69.existsSync(dir))
32789
32819
  return;
32790
32820
  const cutoff = Date.now() - LOG_RETENTION_DAYS * DAY_MS2;
32791
- for (const name of fs68.readdirSync(dir)) {
32821
+ for (const name of fs69.readdirSync(dir)) {
32792
32822
  const p = path79.join(dir, name);
32793
32823
  try {
32794
- const stat = fs68.statSync(p);
32824
+ const stat = fs69.statSync(p);
32795
32825
  if (stat.mtimeMs < cutoff)
32796
- fs68.rmSync(p, { force: true });
32826
+ fs69.rmSync(p, { force: true });
32797
32827
  } catch {
32798
32828
  }
32799
32829
  }
@@ -32846,7 +32876,7 @@ var init_runner = __esm({
32846
32876
  // ../server/dist/routes/cron.js
32847
32877
  import { Hono as Hono18 } from "hono";
32848
32878
  import { eq as eq17, desc as desc3, lt as lt7, and as and13 } from "drizzle-orm";
32849
- import fs69 from "node:fs/promises";
32879
+ import fs70 from "node:fs/promises";
32850
32880
  import path80 from "node:path";
32851
32881
  import { Cron as Cron2 } from "croner";
32852
32882
  function newJobId() {
@@ -33215,7 +33245,7 @@ function createCronRoutes() {
33215
33245
  return c.json({ log: null });
33216
33246
  let log2 = null;
33217
33247
  try {
33218
- log2 = await fs69.readFile(row.logPath, "utf-8");
33248
+ log2 = await fs70.readFile(row.logPath, "utf-8");
33219
33249
  } catch {
33220
33250
  }
33221
33251
  return c.json({ log: log2 });
@@ -33281,7 +33311,7 @@ var init_cron = __esm({
33281
33311
  });
33282
33312
 
33283
33313
  // ../server/dist/extensions/install.js
33284
- import fs70 from "node:fs";
33314
+ import fs71 from "node:fs";
33285
33315
  import path81 from "node:path";
33286
33316
  import { randomBytes as randomBytes3 } from "node:crypto";
33287
33317
  import JSZip2 from "jszip";
@@ -33315,42 +33345,42 @@ async function unpackZip(zipBuf, dest) {
33315
33345
  throw new ExtensionInstallError(`zip entry is a symlink: ${entry.name}`);
33316
33346
  const abs = path81.join(dest, rel);
33317
33347
  if (entry.dir) {
33318
- fs70.mkdirSync(abs, { recursive: true });
33348
+ fs71.mkdirSync(abs, { recursive: true });
33319
33349
  continue;
33320
33350
  }
33321
- fs70.mkdirSync(path81.dirname(abs), { recursive: true });
33322
- fs70.writeFileSync(abs, await entry.async("nodebuffer"));
33351
+ fs71.mkdirSync(path81.dirname(abs), { recursive: true });
33352
+ fs71.writeFileSync(abs, await entry.async("nodebuffer"));
33323
33353
  }
33324
33354
  }
33325
33355
  function stripWrapperDir(dir) {
33326
- if (fs70.existsSync(path81.join(dir, MANIFEST_FILE)))
33356
+ if (fs71.existsSync(path81.join(dir, MANIFEST_FILE)))
33327
33357
  return;
33328
- const children = fs70.readdirSync(dir, { withFileTypes: true });
33358
+ const children = fs71.readdirSync(dir, { withFileTypes: true });
33329
33359
  if (children.length !== 1 || !children[0].isDirectory())
33330
33360
  return;
33331
33361
  const inner = path81.join(dir, children[0].name);
33332
- if (!fs70.existsSync(path81.join(inner, MANIFEST_FILE)))
33362
+ if (!fs71.existsSync(path81.join(inner, MANIFEST_FILE)))
33333
33363
  return;
33334
- for (const name of fs70.readdirSync(inner)) {
33335
- fs70.renameSync(path81.join(inner, name), path81.join(dir, name));
33364
+ for (const name of fs71.readdirSync(inner)) {
33365
+ fs71.renameSync(path81.join(inner, name), path81.join(dir, name));
33336
33366
  }
33337
- fs70.rmdirSync(inner);
33367
+ fs71.rmdirSync(inner);
33338
33368
  }
33339
33369
  function rand() {
33340
33370
  return randomBytes3(3).toString("hex");
33341
33371
  }
33342
33372
  async function installExtensionZip(zipBuf, expectId, expectVersion) {
33343
33373
  const root = extensionsRoot();
33344
- fs70.mkdirSync(root, { recursive: true });
33374
+ fs71.mkdirSync(root, { recursive: true });
33345
33375
  const stage = path81.join(root, `.tmp-unpack-${rand()}`);
33346
- fs70.mkdirSync(stage);
33376
+ fs71.mkdirSync(stage);
33347
33377
  try {
33348
33378
  await unpackZip(zipBuf, stage);
33349
33379
  stripWrapperDir(stage);
33350
33380
  let manifestId;
33351
33381
  let manifestVersion;
33352
33382
  try {
33353
- const raw = JSON.parse(fs70.readFileSync(path81.join(stage, MANIFEST_FILE), "utf-8"));
33383
+ const raw = JSON.parse(fs71.readFileSync(path81.join(stage, MANIFEST_FILE), "utf-8"));
33354
33384
  manifestId = typeof raw.id === "string" ? raw.id : "";
33355
33385
  manifestVersion = raw.version;
33356
33386
  } catch (err) {
@@ -33367,21 +33397,21 @@ async function installExtensionZip(zipBuf, expectId, expectVersion) {
33367
33397
  throw new ExtensionInstallError(`invalid extension: ${verdict2.error}`);
33368
33398
  const target = path81.join(root, manifestId);
33369
33399
  const old = path81.join(root, `.old-${manifestId}-${rand()}`);
33370
- const hadOld = fs70.existsSync(target);
33400
+ const hadOld = fs71.existsSync(target);
33371
33401
  if (!hadOld)
33372
33402
  forgetState(manifestId);
33373
33403
  if (hadOld)
33374
- fs70.renameSync(target, old);
33404
+ fs71.renameSync(target, old);
33375
33405
  try {
33376
- fs70.renameSync(stage, target);
33406
+ fs71.renameSync(stage, target);
33377
33407
  } catch (err) {
33378
33408
  if (hadOld)
33379
- fs70.renameSync(old, target);
33409
+ fs71.renameSync(old, target);
33380
33410
  throw err;
33381
33411
  }
33382
33412
  if (hadOld) {
33383
33413
  try {
33384
- fs70.rmSync(old, { recursive: true, force: true, maxRetries: 3 });
33414
+ fs71.rmSync(old, { recursive: true, force: true, maxRetries: 3 });
33385
33415
  } catch (err) {
33386
33416
  console.log(`[Extensions] could not remove the previous copy ${old}: ${err instanceof Error ? err.message : String(err)}`);
33387
33417
  }
@@ -33392,16 +33422,16 @@ async function installExtensionZip(zipBuf, expectId, expectVersion) {
33392
33422
  console.log(`[Extensions] installed ${info.id}@${info.version}${hadOld ? " (replaced previous)" : ""}`);
33393
33423
  return info;
33394
33424
  } finally {
33395
- fs70.rmSync(stage, { recursive: true, force: true });
33425
+ fs71.rmSync(stage, { recursive: true, force: true });
33396
33426
  }
33397
33427
  }
33398
33428
  function uninstallExtension(id) {
33399
33429
  if (!isExtensionId(id))
33400
33430
  throw new ExtensionInstallError(`"${id}" is not a valid extension id`);
33401
33431
  const dir = path81.join(extensionsRoot(), id);
33402
- if (!fs70.existsSync(dir))
33432
+ if (!fs71.existsSync(dir))
33403
33433
  return false;
33404
- fs70.rmSync(dir, { recursive: true, force: true });
33434
+ fs71.rmSync(dir, { recursive: true, force: true });
33405
33435
  forgetState(id);
33406
33436
  console.log(`[Extensions] removed ${id}`);
33407
33437
  return true;
@@ -33695,7 +33725,7 @@ function createCoreChecker(opts) {
33695
33725
  }
33696
33726
  function getCoreStatus(force) {
33697
33727
  checker ??= createCoreChecker({
33698
- haloVersion: "2.0.2",
33728
+ haloVersion: "2.0.3",
33699
33729
  fetchLatest: fetchNpmLatest,
33700
33730
  onChange: (status) => broadcast({ type: "updates:changed", scope: "core", status })
33701
33731
  });
@@ -33863,7 +33893,7 @@ function hubBase() {
33863
33893
  }
33864
33894
  function serverChecker() {
33865
33895
  checker2 ??= createExtensionsChecker({
33866
- haloVersion: "2.0.2",
33896
+ haloVersion: "2.0.3",
33867
33897
  installed: () => {
33868
33898
  const s = getSnapshot();
33869
33899
  return [...s.extensions, ...s.disabled];
@@ -33899,7 +33929,7 @@ var init_extension_check = __esm({
33899
33929
  });
33900
33930
 
33901
33931
  // ../server/dist/extensions/watcher.js
33902
- import fs71 from "node:fs";
33932
+ import fs72 from "node:fs";
33903
33933
  function scheduleFlush() {
33904
33934
  if (flushTimer)
33905
33935
  return;
@@ -33927,7 +33957,7 @@ function reconcileSttModels(snap) {
33927
33957
  }
33928
33958
  function openWatcher(root) {
33929
33959
  try {
33930
- watcher = fs71.watch(root, { persistent: false, recursive: false }, () => scheduleFlush());
33960
+ watcher = fs72.watch(root, { persistent: false, recursive: false }, () => scheduleFlush());
33931
33961
  watcher.on("error", (err) => {
33932
33962
  console.warn(`[Extensions] watch error on ${root}: ${err.message} \u2014 retrying in 1s`);
33933
33963
  closeWatcher();
@@ -33953,7 +33983,7 @@ function start() {
33953
33983
  return;
33954
33984
  const root = extensionsRoot();
33955
33985
  try {
33956
- fs71.mkdirSync(root, { recursive: true });
33986
+ fs72.mkdirSync(root, { recursive: true });
33957
33987
  } catch (err) {
33958
33988
  console.warn(`[Extensions] cannot create ${root}: ${err instanceof Error ? err.message : String(err)}`);
33959
33989
  }
@@ -33992,7 +34022,7 @@ var init_watcher = __esm({
33992
34022
 
33993
34023
  // ../server/dist/routes/extensions.js
33994
34024
  import { Hono as Hono19 } from "hono";
33995
- import fs72 from "node:fs";
34025
+ import fs73 from "node:fs";
33996
34026
  import path82 from "node:path";
33997
34027
  import { Readable as Readable2 } from "node:stream";
33998
34028
  function assetMime(fileName) {
@@ -34011,15 +34041,15 @@ function resolveAsset(id, version, rest) {
34011
34041
  let dir;
34012
34042
  let real;
34013
34043
  try {
34014
- dir = fs72.realpathSync(path82.join(extensionsRoot(), id));
34015
- real = fs72.realpathSync(path82.join(dir, ...segments));
34044
+ dir = fs73.realpathSync(path82.join(extensionsRoot(), id));
34045
+ real = fs73.realpathSync(path82.join(dir, ...segments));
34016
34046
  } catch {
34017
34047
  return null;
34018
34048
  }
34019
34049
  if (real !== dir && !real.startsWith(dir + path82.sep))
34020
34050
  return null;
34021
34051
  try {
34022
- if (!fs72.statSync(real).isFile())
34052
+ if (!fs73.statSync(real).isFile())
34023
34053
  return null;
34024
34054
  } catch {
34025
34055
  return null;
@@ -34140,8 +34170,8 @@ function createExtensionRoutes() {
34140
34170
  const abs = resolveAsset(c.req.param("id"), c.req.param("version"), c.req.param("rest"));
34141
34171
  if (!abs)
34142
34172
  return c.json({ error: "Not found" }, 404);
34143
- const stat = fs72.statSync(abs);
34144
- const nodeStream = fs72.createReadStream(abs);
34173
+ const stat = fs73.statSync(abs);
34174
+ const nodeStream = fs73.createReadStream(abs);
34145
34175
  c.req.raw.signal?.addEventListener("abort", () => nodeStream.destroy(), { once: true });
34146
34176
  return new Response(Readable2.toWeb(nodeStream), {
34147
34177
  headers: {
@@ -34231,7 +34261,7 @@ var init_updates = __esm({
34231
34261
  });
34232
34262
 
34233
34263
  // ../server/dist/models/watcher.js
34234
- import fs73 from "node:fs";
34264
+ import fs74 from "node:fs";
34235
34265
  function snapshot2() {
34236
34266
  const { effective } = loadProviders();
34237
34267
  return {
@@ -34259,7 +34289,7 @@ function reloadAndBroadcast() {
34259
34289
  }
34260
34290
  function openWatcher2(root) {
34261
34291
  try {
34262
- watcher2 = fs73.watch(root, { persistent: false, recursive: false }, () => scheduleFlush2());
34292
+ watcher2 = fs74.watch(root, { persistent: false, recursive: false }, () => scheduleFlush2());
34263
34293
  watcher2.on("error", (err) => {
34264
34294
  console.warn(`[Models] watch error on ${root}: ${err.message} \u2014 retrying in 1s`);
34265
34295
  closeWatcher2();
@@ -34285,7 +34315,7 @@ function start2() {
34285
34315
  return;
34286
34316
  const root = globalHubModelsDir();
34287
34317
  try {
34288
- fs73.mkdirSync(root, { recursive: true });
34318
+ fs74.mkdirSync(root, { recursive: true });
34289
34319
  } catch (err) {
34290
34320
  console.warn(`[Models] cannot create ${root}: ${err instanceof Error ? err.message : String(err)}`);
34291
34321
  }
@@ -35402,12 +35432,12 @@ var init_handler3 = __esm({
35402
35432
  });
35403
35433
 
35404
35434
  // ../server/dist/routes/channel-accounts.js
35405
- import fs74 from "node:fs";
35435
+ import fs75 from "node:fs";
35406
35436
  function accountListFields(a) {
35407
35437
  return {
35408
35438
  accountId: a.accountId,
35409
35439
  workspacePath: a.workspacePath,
35410
- workspaceMissing: !fs74.existsSync(a.workspacePath),
35440
+ workspaceMissing: !fs75.existsSync(a.workspacePath),
35411
35441
  label: a.label,
35412
35442
  enabled: a.enabled,
35413
35443
  accessLevel: a.accessLevel,
@@ -36049,7 +36079,7 @@ var init_cdn = __esm({
36049
36079
  });
36050
36080
 
36051
36081
  // ../server/dist/channels/wechat/send-media.js
36052
- import fs75 from "node:fs/promises";
36082
+ import fs76 from "node:fs/promises";
36053
36083
  import path84 from "node:path";
36054
36084
  function inferKind(filePath) {
36055
36085
  const cls = classifyMedia(filePath);
@@ -36062,7 +36092,7 @@ function inferKind(filePath) {
36062
36092
  async function sendMediaFile(params) {
36063
36093
  const { baseUrl, token, toUserId, contextToken, contextTokenAt, filePath } = params;
36064
36094
  const kind = params.kind ?? inferKind(filePath);
36065
- const plaintext = await fs75.readFile(filePath);
36095
+ const plaintext = await fs76.readFile(filePath);
36066
36096
  const prep = prepareUpload(plaintext);
36067
36097
  console.log(`[WeChat] sendMediaFile: path=${filePath} kind=${kind} rawsize=${prep.rawsize} filesize=${prep.filesize}`);
36068
36098
  const mediaType = kind === "image" ? UploadMediaType.IMAGE : kind === "video" ? UploadMediaType.VIDEO : UploadMediaType.FILE;
@@ -36263,7 +36293,7 @@ var init_login = __esm({
36263
36293
  });
36264
36294
 
36265
36295
  // ../server/dist/channels/wechat/handler.js
36266
- import fs76 from "node:fs";
36296
+ import fs77 from "node:fs";
36267
36297
  import path85 from "node:path";
36268
36298
  import QRCode from "qrcode";
36269
36299
  function wxRoute(fromUserId, contextToken, contextTokenAt) {
@@ -36694,7 +36724,7 @@ async function handleSlashCommand(args) {
36694
36724
  contextToken,
36695
36725
  filePath: tmpPath
36696
36726
  });
36697
- await fs76.promises.unlink(tmpPath).catch(() => {
36727
+ await fs77.promises.unlink(tmpPath).catch(() => {
36698
36728
  });
36699
36729
  await reply(t("wechat.qr_sent", lang, { level, path: account.workspacePath }));
36700
36730
  waitLogin({ sessionKey: login.sessionKey }).then(async (result2) => {
@@ -36775,7 +36805,7 @@ var init_handler4 = __esm({
36775
36805
  // ../server/dist/routes/wechat.js
36776
36806
  import { Hono as Hono22 } from "hono";
36777
36807
  import path86 from "node:path";
36778
- import fs77 from "node:fs";
36808
+ import fs78 from "node:fs";
36779
36809
  function createWechatRoutes(deps) {
36780
36810
  const { db: db4, channel } = deps;
36781
36811
  const app2 = new Hono22();
@@ -36784,7 +36814,7 @@ function createWechatRoutes(deps) {
36784
36814
  return {
36785
36815
  ...stripSecrets(acc),
36786
36816
  workspacePath: acc.workspacePath,
36787
- workspaceMissing: !fs77.existsSync(acc.workspacePath)
36817
+ workspaceMissing: !fs78.existsSync(acc.workspacePath)
36788
36818
  };
36789
36819
  });
36790
36820
  return c.json({ accounts });
@@ -37013,7 +37043,7 @@ var init_descriptor2 = __esm({
37013
37043
  import { Hono as Hono23 } from "hono";
37014
37044
  import { streamSSE as streamSSE3 } from "hono/streaming";
37015
37045
  import crypto12 from "node:crypto";
37016
- import fs78 from "node:fs";
37046
+ import fs79 from "node:fs";
37017
37047
  function streamWithKeepalive(c, chunks) {
37018
37048
  return streamSSE3(c, async (stream) => {
37019
37049
  const timer2 = setInterval(() => {
@@ -37218,8 +37248,8 @@ function createWebRoutes(deps) {
37218
37248
  let real;
37219
37249
  let realRoot;
37220
37250
  try {
37221
- real = fs78.realpathSync(resolved);
37222
- realRoot = fs78.realpathSync(root);
37251
+ real = fs79.realpathSync(resolved);
37252
+ realRoot = fs79.realpathSync(root);
37223
37253
  } catch {
37224
37254
  return c.json({ error: "file not found" }, 404);
37225
37255
  }
@@ -37229,7 +37259,7 @@ function createWebRoutes(deps) {
37229
37259
  if (isHiddenWorkspacePath(real, realRoot)) {
37230
37260
  return c.json({ error: "path is not accessible" }, 403);
37231
37261
  }
37232
- const stat = fs78.statSync(real);
37262
+ const stat = fs79.statSync(real);
37233
37263
  if (stat.isDirectory())
37234
37264
  return c.json({ error: "cannot serve directory" }, 400);
37235
37265
  const ext = path94.default.extname(real).toLowerCase();
@@ -37241,7 +37271,7 @@ function createWebRoutes(deps) {
37241
37271
  };
37242
37272
  const contentType = imageMimeFromExt(ext) || nonImageMimes[ext] || "application/octet-stream";
37243
37273
  const fileName = path94.default.basename(resolved);
37244
- const data = fs78.readFileSync(real);
37274
+ const data = fs79.readFileSync(real);
37245
37275
  c.header("content-type", contentType);
37246
37276
  c.header("content-disposition", `inline; filename="${fileName}"`);
37247
37277
  return c.body(data);
@@ -37463,10 +37493,10 @@ async function authTest(botToken) {
37463
37493
  return slackPost("auth.test", botToken, {});
37464
37494
  }
37465
37495
  async function uploadFile(args) {
37466
- const fs83 = await import("node:fs");
37496
+ const fs84 = await import("node:fs");
37467
37497
  const path94 = await import("node:path");
37468
37498
  const filename = args.filename ?? path94.basename(args.filePath);
37469
- const stat = fs83.statSync(args.filePath);
37499
+ const stat = fs84.statSync(args.filePath);
37470
37500
  if (!stat.isFile())
37471
37501
  throw new Error(`[slack:uploadFile] not a regular file: ${args.filePath}`);
37472
37502
  const length = stat.size;
@@ -37484,7 +37514,7 @@ async function uploadFile(args) {
37484
37514
  if (step1Parsed.ok === false || !step1Parsed.upload_url || !step1Parsed.file_id) {
37485
37515
  throw new Error(`[slack:files.getUploadURLExternal] ${step1Parsed.error ?? "unknown"}`);
37486
37516
  }
37487
- const buf = fs83.readFileSync(args.filePath);
37517
+ const buf = fs84.readFileSync(args.filePath);
37488
37518
  const step2 = await fetch(step1Parsed.upload_url, {
37489
37519
  method: "POST",
37490
37520
  body: buf
@@ -38404,9 +38434,9 @@ async function replyMessage(args) {
38404
38434
  return { message_id: parsed.data?.message_id ?? "" };
38405
38435
  }
38406
38436
  async function uploadImage(args) {
38407
- const fs83 = await import("node:fs");
38437
+ const fs84 = await import("node:fs");
38408
38438
  const path94 = await import("node:path");
38409
- const buf = fs83.readFileSync(args.filePath);
38439
+ const buf = fs84.readFileSync(args.filePath);
38410
38440
  const filename = path94.basename(args.filePath);
38411
38441
  const send2 = async (token) => {
38412
38442
  const form = new FormData();
@@ -38423,9 +38453,9 @@ async function uploadImage(args) {
38423
38453
  return { imageKey: parsed.data.image_key };
38424
38454
  }
38425
38455
  async function uploadFile2(args) {
38426
- const fs83 = await import("node:fs");
38456
+ const fs84 = await import("node:fs");
38427
38457
  const path94 = await import("node:path");
38428
- const buf = fs83.readFileSync(args.filePath);
38458
+ const buf = fs84.readFileSync(args.filePath);
38429
38459
  const filename = args.filename ?? path94.basename(args.filePath);
38430
38460
  const send2 = async (token) => {
38431
38461
  const form = new FormData();
@@ -39259,7 +39289,7 @@ var init_event_adapter5 = __esm({
39259
39289
 
39260
39290
  // ../server/dist/channels/wecom/handler.js
39261
39291
  import path89 from "node:path";
39262
- import fs79 from "node:fs/promises";
39292
+ import fs80 from "node:fs/promises";
39263
39293
  import { WSClient as WSClient2, generateReqId } from "@wecom/aibot-node-sdk";
39264
39294
  function pickConversation(body) {
39265
39295
  const userid = body.from?.userid ?? "unknown";
@@ -39385,7 +39415,7 @@ async function sendWecomMedia(args) {
39385
39415
  const ext = path89.extname(filePath).toLowerCase();
39386
39416
  const cls = classifyMedia(filePath);
39387
39417
  const type = cls === "image" && [".png", ".jpg", ".jpeg", ".gif"].includes(ext) ? "image" : cls === "video" && ext === ".mp4" ? "video" : "file";
39388
- const buf = await fs79.readFile(filePath);
39418
+ const buf = await fs80.readFile(filePath);
39389
39419
  if (buf.length > MAX_WECOM_DOWNLOAD_BYTES)
39390
39420
  throw new Error("file exceeds 20MB");
39391
39421
  const { media_id: mediaId } = await wsClient.uploadMedia(buf, { type, filename: path89.basename(filePath) });
@@ -39922,14 +39952,14 @@ import { serve } from "@hono/node-server";
39922
39952
  import { serveStatic } from "@hono/node-server/serve-static";
39923
39953
  import { WebSocketServer as WebSocketServer4 } from "ws";
39924
39954
  import path90 from "node:path";
39925
- import fs80 from "node:fs";
39955
+ import fs81 from "node:fs";
39926
39956
  import { spawnSync as spawnSync4 } from "node:child_process";
39927
39957
  import { homedir as homedir25 } from "node:os";
39928
39958
  import { fileURLToPath as fileURLToPath3 } from "node:url";
39929
39959
  function findProjectRoot() {
39930
39960
  let dir = process.cwd();
39931
39961
  for (let i = 0; i < 32; i++) {
39932
- if (fs80.existsSync(path90.join(dir, "pnpm-workspace.yaml")))
39962
+ if (fs81.existsSync(path90.join(dir, "pnpm-workspace.yaml")))
39933
39963
  return dir;
39934
39964
  const parent = path90.dirname(dir);
39935
39965
  if (parent === dir)
@@ -39941,15 +39971,15 @@ function findProjectRoot() {
39941
39971
  return process.cwd();
39942
39972
  }
39943
39973
  function acquireSingleInstanceLock(lockFile) {
39944
- fs80.mkdirSync(path90.dirname(lockFile), { recursive: true });
39945
- const fd = fs80.openSync(lockFile, fs80.constants.O_RDWR | fs80.constants.O_CREAT, 420);
39974
+ fs81.mkdirSync(path90.dirname(lockFile), { recursive: true });
39975
+ const fd = fs81.openSync(lockFile, fs81.constants.O_RDWR | fs81.constants.O_CREAT, 420);
39946
39976
  const result = spawnSync4("flock", ["-n", "3"], {
39947
39977
  stdio: ["ignore", "ignore", "ignore", fd]
39948
39978
  });
39949
39979
  if (result.error) {
39950
39980
  const content = readLockPid(fd);
39951
39981
  if (content > 0 && isProcessAlive(content)) {
39952
- fs80.closeSync(fd);
39982
+ fs81.closeSync(fd);
39953
39983
  console.error(`[Server] another halo server is already running (pid ${content}). kill it first.`);
39954
39984
  process.exit(1);
39955
39985
  }
@@ -39958,19 +39988,19 @@ function acquireSingleInstanceLock(lockFile) {
39958
39988
  if (content > 0 && !isProcessAlive(content)) {
39959
39989
  console.warn(`[Server] removing stale server.lock (pid ${content} not running)`);
39960
39990
  } else {
39961
- fs80.closeSync(fd);
39991
+ fs81.closeSync(fd);
39962
39992
  console.error(`[Server] another halo server is already running${content > 0 ? ` (pid ${content})` : ""}. kill it first.`);
39963
39993
  process.exit(1);
39964
39994
  }
39965
39995
  }
39966
- fs80.ftruncateSync(fd);
39967
- fs80.writeSync(fd, String(process.pid));
39968
- fs80.fsyncSync(fd);
39996
+ fs81.ftruncateSync(fd);
39997
+ fs81.writeSync(fd, String(process.pid));
39998
+ fs81.fsyncSync(fd);
39969
39999
  }
39970
40000
  function readLockPid(fd) {
39971
40001
  try {
39972
40002
  const buf = Buffer.alloc(32);
39973
- const n = fs80.readSync(fd, buf, 0, 32, 0);
40003
+ const n = fs81.readSync(fd, buf, 0, 32, 0);
39974
40004
  return parseInt(buf.subarray(0, n).toString("utf-8").trim(), 10) || 0;
39975
40005
  } catch {
39976
40006
  return 0;
@@ -39998,7 +40028,7 @@ function isProcessAlive(pid) {
39998
40028
  }
39999
40029
  }
40000
40030
  function readGitSha() {
40001
- if (!fs80.existsSync(path90.join(PROJECT_ROOT, "pnpm-workspace.yaml")) || !fs80.existsSync(path90.join(PROJECT_ROOT, ".git")))
40031
+ if (!fs81.existsSync(path90.join(PROJECT_ROOT, "pnpm-workspace.yaml")) || !fs81.existsSync(path90.join(PROJECT_ROOT, ".git")))
40002
40032
  return null;
40003
40033
  try {
40004
40034
  const rev = spawnSync4("git", ["rev-parse", "--short", "HEAD"], { cwd: PROJECT_ROOT, encoding: "utf-8" });
@@ -40021,10 +40051,10 @@ function resolveFrontendDir() {
40021
40051
  if (process.env.HALO_FRONTEND_DIR)
40022
40052
  return path90.resolve(process.env.HALO_FRONTEND_DIR);
40023
40053
  const bundled = path90.resolve(__dirname3, "..", "admin-out");
40024
- if (fs80.existsSync(path90.join(bundled, "index.html")))
40054
+ if (fs81.existsSync(path90.join(bundled, "index.html")))
40025
40055
  return bundled;
40026
40056
  const sibling = path90.resolve(__dirname3, "..", "..", "admin", "out");
40027
- if (fs80.existsSync(path90.join(sibling, "index.html")))
40057
+ if (fs81.existsSync(path90.join(sibling, "index.html")))
40028
40058
  return sibling;
40029
40059
  return path90.resolve(PROJECT_ROOT, "packages", "admin", "out");
40030
40060
  }
@@ -40129,11 +40159,11 @@ var init_dist2 = __esm({
40129
40159
  init_git_ssh();
40130
40160
  __dirname3 = path90.dirname(fileURLToPath3(import.meta.url));
40131
40161
  PORT = config.server.port;
40132
- HALO_VERSION = "2.0.2";
40162
+ HALO_VERSION = "2.0.3";
40133
40163
  PROJECT_ROOT = findProjectRoot();
40134
40164
  HALO_HOME4 = path90.join(homedir25(), ".halo");
40135
40165
  GIT_SHA = readGitSha();
40136
- if (!fs80.existsSync(path90.join(HALO_HOME4, "global", ".template-version"))) {
40166
+ if (!fs81.existsSync(path90.join(HALO_HOME4, "global", ".template-version"))) {
40137
40167
  process.stderr.write("\x1B[31m[Server] ~/.halo/global/ not initialized. Run `halo setup` first.\x1B[0m\n");
40138
40168
  process.exit(1);
40139
40169
  }
@@ -40235,7 +40265,7 @@ var init_dist2 = __esm({
40235
40265
  setCronSessionRegistry(registry);
40236
40266
  if (OWNS_RUNTIMES && !AGENTCORE) {
40237
40267
  for (const ws of listRunningWorkspaces()) {
40238
- if (!fs80.existsSync(path90.join(ws, ".halo")))
40268
+ if (!fs81.existsSync(path90.join(ws, ".halo")))
40239
40269
  continue;
40240
40270
  if (!claimWorkspaceRuntime(ws))
40241
40271
  continue;
@@ -40281,7 +40311,7 @@ var init_dist2 = __esm({
40281
40311
  app.get("/*", (c) => {
40282
40312
  const indexPath = path90.join(FRONTEND_DIR, "index.html");
40283
40313
  try {
40284
- const html = fs80.readFileSync(indexPath, "utf-8");
40314
+ const html = fs81.readFileSync(indexPath, "utf-8");
40285
40315
  return c.html(html);
40286
40316
  } catch {
40287
40317
  return c.text("Frontend not built. Run: cd packages/admin && npx next build", 503);
@@ -40369,7 +40399,7 @@ __export(agentcore_front_exports, {
40369
40399
  workerEnv: () => workerEnv
40370
40400
  });
40371
40401
  import http3 from "node:http";
40372
- import fs81 from "node:fs";
40402
+ import fs82 from "node:fs";
40373
40403
  import fsp2 from "node:fs/promises";
40374
40404
  import os11 from "node:os";
40375
40405
  import path91 from "node:path";
@@ -40400,39 +40430,39 @@ function skipTemplateEntry(rel) {
40400
40430
  }
40401
40431
  function chownTree(dir, owner, sid) {
40402
40432
  try {
40403
- fs81.lchownSync(dir, owner.uid, owner.gid);
40404
- for (const rel of fs81.readdirSync(dir, { recursive: true }))
40405
- fs81.lchownSync(path91.join(dir, rel), owner.uid, owner.gid);
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);
40406
40436
  } catch (err) {
40407
40437
  console.warn(`[AgentCore] front: chown ${sid} to ${owner.uid}:${owner.gid} failed (${err.message}) \u2014 serving it as is`);
40408
40438
  }
40409
40439
  }
40410
40440
  function ensureSessionDir(base, sid, owner) {
40411
40441
  const dir = path91.join(base, sid);
40412
- if (fs81.existsSync(dir))
40442
+ if (fs82.existsSync(dir))
40413
40443
  return false;
40414
40444
  const tmp = path91.join(base, `.tmp-${crypto13.randomBytes(8).toString("hex")}`);
40415
- fs81.mkdirSync(tmp, { mode: 448 });
40445
+ fs82.mkdirSync(tmp, { mode: 448 });
40416
40446
  try {
40417
40447
  const template = path91.join(base, TEMPLATE_DIR);
40418
- if (fs81.statSync(template, { throwIfNoEntry: false })?.isDirectory()) {
40419
- fs81.cpSync(template, tmp, { recursive: true, verbatimSymlinks: true, filter: (src) => !skipTemplateEntry(path91.relative(template, src)) });
40448
+ if (fs82.statSync(template, { throwIfNoEntry: false })?.isDirectory()) {
40449
+ fs82.cpSync(template, tmp, { recursive: true, verbatimSymlinks: true, filter: (src) => !skipTemplateEntry(path91.relative(template, src)) });
40420
40450
  }
40421
40451
  if (owner)
40422
40452
  chownTree(tmp, owner, sid);
40423
- if (fs81.readdirSync(tmp).length === 0) {
40424
- fs81.rmdirSync(tmp);
40425
- fs81.mkdirSync(dir, { mode: 448 });
40453
+ if (fs82.readdirSync(tmp).length === 0) {
40454
+ fs82.rmdirSync(tmp);
40455
+ fs82.mkdirSync(dir, { mode: 448 });
40426
40456
  if (owner)
40427
40457
  chownTree(dir, owner, sid);
40428
40458
  return true;
40429
40459
  }
40430
- fs81.renameSync(tmp, dir);
40460
+ fs82.renameSync(tmp, dir);
40431
40461
  return true;
40432
40462
  } catch (err) {
40433
- fs81.rmSync(tmp, { recursive: true, force: true });
40463
+ fs82.rmSync(tmp, { recursive: true, force: true });
40434
40464
  const code = err.code;
40435
- if ((code === "EEXIST" || code === "ENOTEMPTY") && fs81.existsSync(dir))
40465
+ if ((code === "EEXIST" || code === "ENOTEMPTY") && fs82.existsSync(dir))
40436
40466
  return false;
40437
40467
  throw err;
40438
40468
  }
@@ -40476,7 +40506,7 @@ async function runViewSetup(base, sessionDir, deps = SYSTEM_SETUP) {
40476
40506
  const left = mountLayers(base, deps.mountinfo());
40477
40507
  if (left > 0)
40478
40508
  throw new Error(`view setup: ${base} still has ${left} mount(s) after ${MAX_UMOUNTS} \xD7 umount -l`);
40479
- if (fs81.existsSync(sessionDir))
40509
+ if (fs82.existsSync(sessionDir))
40480
40510
  throw new Error(`view setup: ${base} is still visible after umount -l`);
40481
40511
  }
40482
40512
  function workerEnv(src, front) {
@@ -40495,15 +40525,15 @@ async function copyMediaFile(p, root, dest, max = MAX_MEDIA_BYTES) {
40495
40525
  return "not an absolute path";
40496
40526
  let pfd;
40497
40527
  try {
40498
- pfd = fs81.openSync(p, O_PATH);
40528
+ pfd = fs82.openSync(p, O_PATH);
40499
40529
  } catch (err) {
40500
40530
  return `cannot open (${err.code})`;
40501
40531
  }
40502
40532
  try {
40503
- const link = fs81.readlinkSync(`/proc/self/fd/${pfd}`);
40533
+ const link = fs82.readlinkSync(`/proc/self/fd/${pfd}`);
40504
40534
  if (!link.startsWith(`${root}/`))
40505
40535
  return `not under ${root}/`;
40506
- const st = fs81.fstatSync(pfd);
40536
+ const st = fs82.fstatSync(pfd);
40507
40537
  if (!st.isFile())
40508
40538
  return "not a regular file";
40509
40539
  if (st.size > max)
@@ -40530,7 +40560,7 @@ async function copyMediaFile(p, root, dest, max = MAX_MEDIA_BYTES) {
40530
40560
  await src.close();
40531
40561
  }
40532
40562
  } finally {
40533
- fs81.closeSync(pfd);
40563
+ fs82.closeSync(pfd);
40534
40564
  }
40535
40565
  }
40536
40566
  async function copyMediaLines(text6, root, dir, sid) {
@@ -40543,7 +40573,7 @@ async function copyMediaLines(text6, root, dir, sid) {
40543
40573
  continue;
40544
40574
  }
40545
40575
  const sub = path91.join(dir, String(n++));
40546
- fs81.mkdirSync(sub);
40576
+ fs82.mkdirSync(sub);
40547
40577
  const name = path91.basename(m[1]).replace(/[\x00-\x1f\x7f]/g, "_").replace(/^\.+/, "") || "file";
40548
40578
  const dest = path91.join(sub, name);
40549
40579
  const why = await copyMediaFile(m[1], root, dest).catch((err) => err.message);
@@ -40551,7 +40581,7 @@ async function copyMediaLines(text6, root, dir, sid) {
40551
40581
  out.push(`MEDIA:${dest}`);
40552
40582
  continue;
40553
40583
  }
40554
- fs81.rmSync(sub, { recursive: true, force: true });
40584
+ fs82.rmSync(sub, { recursive: true, force: true });
40555
40585
  console.warn(`[AgentCore] notify ${sid}: MEDIA dropped (${why}): ${JSON.stringify(m[1].slice(0, 300))}`);
40556
40586
  }
40557
40587
  return out.join("\n");
@@ -40595,7 +40625,7 @@ function readBody(req, max) {
40595
40625
  });
40596
40626
  }
40597
40627
  async function startAgentCoreFront(o) {
40598
- const base = fs81.realpathSync(o.base);
40628
+ const base = fs82.realpathSync(o.base);
40599
40629
  const workerPort = o.workerPort ?? WORKER_PORT;
40600
40630
  const token = crypto13.randomBytes(32).toString("hex");
40601
40631
  const isMounted = o.isMounted ?? ((b) => mountLayers(b, readMountinfo()) > 0);
@@ -40657,11 +40687,11 @@ async function startAgentCoreFront(o) {
40657
40687
  preparing++;
40658
40688
  let dir = "";
40659
40689
  const cleanup = () => {
40660
- fs81.rmSync(dir, { recursive: true, force: true });
40690
+ fs82.rmSync(dir, { recursive: true, force: true });
40661
40691
  settle();
40662
40692
  };
40663
40693
  try {
40664
- dir = fs81.mkdtempSync(path91.join(os11.tmpdir(), "halo-notify-"));
40694
+ dir = fs82.mkdtempSync(path91.join(os11.tmpdir(), "halo-notify-"));
40665
40695
  const text6 = await copyMediaLines(b.text, viewRoot, dir, b.session);
40666
40696
  runNotify(cmd, text6, { HALO_SESSION_ID: b.session, HALO_RUN_STATUS: b.status, HALO_WORKSPACE: dir }, dir, cleanup);
40667
40697
  } catch (err) {
@@ -40878,7 +40908,7 @@ var init_agentcore_front = __esm({
40878
40908
  MAX_MEDIA_BYTES = 20 * 1024 * 1024;
40879
40909
  O_PATH = 2097152;
40880
40910
  execFileP = promisify3(execFile2);
40881
- readMountinfo = () => fs81.readFileSync("/proc/self/mountinfo", "utf8");
40911
+ readMountinfo = () => fs82.readFileSync("/proc/self/mountinfo", "utf8");
40882
40912
  SYSTEM_SETUP = {
40883
40913
  mountinfo: readMountinfo,
40884
40914
  exec: (argv) => execFileP(argv[0], argv.slice(1), { timeout: SETUP_TIMEOUT_MS })
@@ -42016,7 +42046,7 @@ process.emitWarning = (warning, ...args) => {
42016
42046
  // src/index.ts
42017
42047
  init_server_supervisor();
42018
42048
  import path93 from "node:path";
42019
- import fs82 from "node:fs";
42049
+ import fs83 from "node:fs";
42020
42050
  import { homedir as homedir26, userInfo } from "node:os";
42021
42051
  import { parseArgs as parseArgs2 } from "node:util";
42022
42052
 
@@ -42307,7 +42337,7 @@ function installUserUnit(opts, run = runCommand) {
42307
42337
  }
42308
42338
 
42309
42339
  // src/index.ts
42310
- var VERSION = "2.0.2";
42340
+ var VERSION = "2.0.3";
42311
42341
  var HELP_TOP = `Usage: halo <command> [options]
42312
42342
 
42313
42343
  Commands:
@@ -43101,7 +43131,7 @@ ${HELP_SESSIONS}`);
43101
43131
  }
43102
43132
  }
43103
43133
  async function cmdSessionsMigrate(workspace) {
43104
- if (!fs82.existsSync(path93.join(workspace, ".halo"))) {
43134
+ if (!fs83.existsSync(path93.join(workspace, ".halo"))) {
43105
43135
  process.stderr.write(`Not a Halo workspace (no .halo/): ${workspace}
43106
43136
  `);
43107
43137
  process.exitCode = 1;
@@ -43246,7 +43276,7 @@ var SERVER_LOCK_PATH = path93.join(homedir26(), ".halo", "global", "server.lock"
43246
43276
  var SERVER_LOG_PATH = path93.join(homedir26(), ".halo", "logs", "server.log");
43247
43277
  function readServerPid() {
43248
43278
  try {
43249
- const txt = fs82.readFileSync(SERVER_LOCK_PATH, "utf-8").trim();
43279
+ const txt = fs83.readFileSync(SERVER_LOCK_PATH, "utf-8").trim();
43250
43280
  const n = parseInt(txt, 10);
43251
43281
  return Number.isFinite(n) && n > 0 ? n : null;
43252
43282
  } catch {
@@ -43353,8 +43383,8 @@ async function cmdServerStart(argv, restart) {
43353
43383
  }
43354
43384
  if (plan.note) writeDim(plan.note);
43355
43385
  const { spawn: spawn7 } = await import("node:child_process");
43356
- fs82.mkdirSync(path93.dirname(SERVER_LOG_PATH), { recursive: true });
43357
- const out = fs82.openSync(SERVER_LOG_PATH, "a");
43386
+ fs83.mkdirSync(path93.dirname(SERVER_LOG_PATH), { recursive: true });
43387
+ const out = fs83.openSync(SERVER_LOG_PATH, "a");
43358
43388
  const child = spawn7(process.argv[0], [process.argv[1], "server", "start"], {
43359
43389
  detached: true,
43360
43390
  stdio: ["ignore", out, out],
@@ -43436,7 +43466,7 @@ ${HELP_AGENTCORE}`);
43436
43466
  return;
43437
43467
  }
43438
43468
  const workspace = path93.resolve(raw);
43439
- if (!fs82.statSync(workspace, { throwIfNoEntry: false })?.isDirectory()) {
43469
+ if (!fs83.statSync(workspace, { throwIfNoEntry: false })?.isDirectory()) {
43440
43470
  process.stderr.write(`Workspace is not a directory: ${workspace}
43441
43471
  `);
43442
43472
  process.exitCode = 1;
@@ -43547,7 +43577,7 @@ async function cmdServerLogs(argv) {
43547
43577
  lines: { type: "string", short: "n" }
43548
43578
  }
43549
43579
  });
43550
- if (!fs82.existsSync(SERVER_LOG_PATH)) {
43580
+ if (!fs83.existsSync(SERVER_LOG_PATH)) {
43551
43581
  process.stderr.write(`No log file at ${SERVER_LOG_PATH}
43552
43582
  `);
43553
43583
  return;
@@ -43565,7 +43595,7 @@ function exitMissingSetup() {
43565
43595
  process.exit(1);
43566
43596
  }
43567
43597
  function isHaloHomeReady() {
43568
- return fs82.existsSync(path93.join(homedir26(), ".halo", "global", ".template-version"));
43598
+ return fs83.existsSync(path93.join(homedir26(), ".halo", "global", ".template-version"));
43569
43599
  }
43570
43600
  async function main2() {
43571
43601
  const argv = process.argv.slice(2);