@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/admin-out/404.html +1 -1
- package/admin-out/_next/static/chunks/241-75bac3bb8e7aca1b.js +1 -0
- package/admin-out/_next/static/chunks/989-5c90f88e8111b360.js +1 -0
- package/admin-out/_next/static/chunks/app/_not-found/{page-4271518f2746cf73.js → page-484fd244e4bc7b70.js} +1 -1
- package/admin-out/_next/static/chunks/app/layout-3e437a977abd0081.js +1 -0
- package/admin-out/_next/static/chunks/app/{page-aac322e92546015f.js → page-faee6fbd17dc7b80.js} +1 -1
- package/admin-out/_next/static/chunks/{main-app-340a5b58ed229c4d.js → main-app-42f48cb3fd4811f4.js} +1 -1
- package/admin-out/_next/static/chunks/{webpack-74f577c1b094f942.js → webpack-b7907e0d16faa4ca.js} +1 -1
- package/admin-out/index.html +1 -1
- package/admin-out/index.txt +4 -4
- package/bundled-docs/design/a2a.md +1 -1
- package/bundled-docs/dev/tools.md +1 -1
- package/bundled-docs/requirements/settings.md +3 -3
- package/dist/index.js +748 -718
- package/package.json +1 -1
- package/admin-out/_next/static/chunks/0-ba3da5a638cc90d9.js +0 -1
- package/admin-out/_next/static/chunks/989-1e0950ea81450f70.js +0 -1
- package/admin-out/_next/static/chunks/app/layout-ea161287d934ba96.js +0 -1
- /package/admin-out/_next/static/{F5kkXJkkJ-4vNC_tb2Hjk → P7yMYf16Q3-XqGtzCJNnw}/_buildManifest.js +0 -0
- /package/admin-out/_next/static/{F5kkXJkkJ-4vNC_tb2Hjk → P7yMYf16Q3-XqGtzCJNnw}/_ssgManifest.js +0 -0
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 =
|
|
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/
|
|
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 } =
|
|
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 =
|
|
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 =
|
|
2695
|
-
if (!
|
|
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 =
|
|
2707
|
-
const { mtimeMs } =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
2750
|
-
if (!
|
|
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(
|
|
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
|
-
|
|
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
|
|
2851
|
-
import
|
|
2900
|
+
import fs12 from "node:fs";
|
|
2901
|
+
import path14 from "node:path";
|
|
2852
2902
|
import { homedir as homedir8 } from "node:os";
|
|
2853
|
-
import
|
|
2903
|
+
import YAML6 from "yaml";
|
|
2854
2904
|
function loadYamlFile(filePath) {
|
|
2855
2905
|
try {
|
|
2856
|
-
const raw =
|
|
2857
|
-
return
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3079
|
+
const p = path14.join(workspaceRoot, ".halo", "settings.yaml");
|
|
3030
3080
|
let mtimeMs = 0;
|
|
3031
3081
|
try {
|
|
3032
|
-
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 =
|
|
3147
|
-
HALO_GLOBAL_DIR =
|
|
3148
|
-
HALO_SECRETS_DIR =
|
|
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 =
|
|
3200
|
+
SYSTEM_CONFIG_PATH = path14.join(HALO_SECRETS_DIR, "config.yaml");
|
|
3151
3201
|
_systemConfigCache = null;
|
|
3152
|
-
SETTINGS_PATH =
|
|
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
|
|
4070
|
+
import fs13 from "node:fs/promises";
|
|
4021
4071
|
import fsSync2 from "node:fs";
|
|
4022
|
-
import
|
|
4072
|
+
import path15 from "node:path";
|
|
4023
4073
|
import { homedir as homedir9 } from "node:os";
|
|
4024
|
-
import
|
|
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 =
|
|
4080
|
+
const wsDir = path15.join(workspaceRoot, ".halo", "agents", agentId);
|
|
4031
4081
|
if (fsSync2.existsSync(wsDir))
|
|
4032
4082
|
return wsDir;
|
|
4033
4083
|
}
|
|
4034
|
-
return
|
|
4084
|
+
return path15.join(GLOBAL_AGENTS_DIR2, agentId);
|
|
4035
4085
|
}
|
|
4036
4086
|
function isAgentDisabled(agentId, workspaceRoot, disabledSet) {
|
|
4037
|
-
const scope = workspaceRoot && fsSync2.existsSync(
|
|
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 =
|
|
4091
|
+
const yamlPath = path15.join(agentSourceDir(agentId, workspaceRoot), "agent.yaml");
|
|
4042
4092
|
try {
|
|
4043
|
-
const content = await
|
|
4044
|
-
const parsed =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
4240
|
+
const raw = await fs13.readFile(meta.path, "utf-8");
|
|
4191
4241
|
const { body } = parseSkillFrontmatter(raw);
|
|
4192
|
-
const skillDir =
|
|
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
|
|
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 ?
|
|
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
|
|
4279
|
+
const globalNames = await fs13.readdir(GLOBAL_AGENTS_DIR2);
|
|
4230
4280
|
for (const name of globalNames) {
|
|
4231
|
-
const yamlPath =
|
|
4281
|
+
const yamlPath = path15.join(GLOBAL_AGENTS_DIR2, name, "agent.yaml");
|
|
4232
4282
|
try {
|
|
4233
|
-
const content = await
|
|
4234
|
-
const cfg =
|
|
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 =
|
|
4303
|
+
const wsAgentsDir = path15.join(workspaceRoot, ".halo", "agents");
|
|
4254
4304
|
try {
|
|
4255
|
-
const wsNames = await
|
|
4305
|
+
const wsNames = await fs13.readdir(wsAgentsDir);
|
|
4256
4306
|
for (const name of wsNames) {
|
|
4257
|
-
const yamlPath =
|
|
4307
|
+
const yamlPath = path15.join(wsAgentsDir, name, "agent.yaml");
|
|
4258
4308
|
try {
|
|
4259
|
-
const content = await
|
|
4260
|
-
const cfg =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 ||
|
|
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
|
|
4491
|
+
import path17 from "node:path";
|
|
4442
4492
|
function setDurableDbDir(dir) {
|
|
4443
|
-
durableDir = dir === null ? null :
|
|
4493
|
+
durableDir = dir === null ? null : path17.resolve(dir);
|
|
4444
4494
|
}
|
|
4445
4495
|
function applyCommitDurability(sqlite, dataDir) {
|
|
4446
|
-
if (durableDir !== null &&
|
|
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
|
|
4462
|
-
import
|
|
4511
|
+
import path18 from "node:path";
|
|
4512
|
+
import fs14 from "node:fs";
|
|
4463
4513
|
function createDb(dataDir) {
|
|
4464
|
-
|
|
4465
|
-
const dbPath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
4564
|
+
const resolved = fs14.realpathSync(workspacePath);
|
|
4515
4565
|
ensureWorkspaceHalo(resolved);
|
|
4516
4566
|
let db4 = dbCache.get(resolved);
|
|
4517
4567
|
if (!db4) {
|
|
4518
|
-
const haloDir =
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
5051
|
+
return path20.resolve(path20.dirname(dir)) === path20.resolve(globalInternalSessionsDir());
|
|
5002
5052
|
}
|
|
5003
5053
|
function legacySegmentPath(dir, seg, n) {
|
|
5004
|
-
return
|
|
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(
|
|
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 =
|
|
5032
|
-
return fsSync4.existsSync(
|
|
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:
|
|
5058
|
-
agentName: data.agentName ??
|
|
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(
|
|
5185
|
+
fsSync4.rmSync(path20.join(dir, name), { force: true });
|
|
5136
5186
|
}
|
|
5137
5187
|
if (keep.size > 0)
|
|
5138
|
-
console.warn(`[LegacyMigrate] ${
|
|
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
|
|
5191
|
+
return path20.join(dir, `${seg}.migrating`);
|
|
5142
5192
|
}
|
|
5143
5193
|
function conversionPending(dir, seg) {
|
|
5144
|
-
return !fsSync4.existsSync(uiLogPath(dir, seg)) && fsSync4.existsSync(
|
|
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(
|
|
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(
|
|
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(
|
|
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 ${
|
|
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(
|
|
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(
|
|
5340
|
+
const m = /^(.*)\.(?:ui|raw)\.jsonl$/.exec(path20.basename(filePath));
|
|
5291
5341
|
if (!m)
|
|
5292
5342
|
return false;
|
|
5293
|
-
const dir =
|
|
5343
|
+
const dir = path20.dirname(filePath);
|
|
5294
5344
|
const seg = m[1];
|
|
5295
|
-
if (fsSync4.existsSync(uiLogPath(dir, seg)) || !fsSync4.existsSync(
|
|
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 =
|
|
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(
|
|
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 =
|
|
5418
|
+
const sessions = path20.join(root, ".halo", "sessions");
|
|
5369
5419
|
for (const agent of agentDirs(sessions))
|
|
5370
|
-
migrateDir(
|
|
5420
|
+
migrateDir(path20.join(sessions, agent), agent, out);
|
|
5371
5421
|
const internal = globalInternalSessionsDir();
|
|
5372
5422
|
for (const agent of agentDirs(internal))
|
|
5373
|
-
migrateDir(
|
|
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
|
|
5445
|
+
import path21 from "node:path";
|
|
5396
5446
|
function uiLogPath(dir, seg) {
|
|
5397
|
-
return
|
|
5447
|
+
return path21.join(dir, `${seg}.ui.jsonl`);
|
|
5398
5448
|
}
|
|
5399
5449
|
function rawLogPath(dir, seg) {
|
|
5400
|
-
return
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
5885
|
-
import
|
|
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
|
|
5946
|
+
return path22.join(homedir10(), ".halo", "global", "internal-sessions", agentId);
|
|
5897
5947
|
}
|
|
5898
|
-
const base = projectPath ?
|
|
5899
|
-
return
|
|
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 ?
|
|
5903
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
6016
|
-
import
|
|
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
|
|
6176
|
+
return path23.join(workspaceRoot, ".halo", "goal", goalId);
|
|
6127
6177
|
}
|
|
6128
6178
|
function goalSpecPath(workspaceRoot, goalId) {
|
|
6129
|
-
return
|
|
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(
|
|
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
|
-
|
|
6366
|
-
|
|
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
|
|
6516
|
-
import
|
|
6565
|
+
import path24 from "node:path";
|
|
6566
|
+
import fs17 from "node:fs/promises";
|
|
6517
6567
|
async function resolveWorkingDir(workspaceRoot, input) {
|
|
6518
|
-
const resolved =
|
|
6519
|
-
const wsRoot =
|
|
6520
|
-
if (resolved !== wsRoot && !resolved.startsWith(wsRoot +
|
|
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
|
|
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
|
|
6542
|
-
import
|
|
6591
|
+
import fs18 from "node:fs";
|
|
6592
|
+
import path25 from "node:path";
|
|
6543
6593
|
function folderKey(root) {
|
|
6544
|
-
const dir =
|
|
6594
|
+
const dir = path25.join(root, ".halo", "skills");
|
|
6545
6595
|
let ids;
|
|
6546
6596
|
try {
|
|
6547
|
-
ids =
|
|
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 =
|
|
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 =
|
|
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
|
|
6778
|
-
import
|
|
6827
|
+
import path26 from "node:path";
|
|
6828
|
+
import fs19 from "node:fs";
|
|
6779
6829
|
function createChannelDb(secretsDir2) {
|
|
6780
|
-
const channelsDir =
|
|
6781
|
-
|
|
6782
|
-
const dbPath =
|
|
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
|
|
6835
|
-
import
|
|
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 (!
|
|
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 (!
|
|
6904
|
+
if (!path27.isAbsolute(workspacePath))
|
|
6855
6905
|
return "workspacePath must be absolute";
|
|
6856
|
-
if (!
|
|
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
|
|
7100
|
-
import
|
|
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 =
|
|
7154
|
+
const skillMdPath = path28.join(skillDir, "SKILL.md");
|
|
7105
7155
|
try {
|
|
7106
|
-
const { mtimeMs } = await
|
|
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
|
|
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
|
|
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
|
|
7243
|
-
import
|
|
7292
|
+
import path29 from "node:path";
|
|
7293
|
+
import fs22 from "node:fs";
|
|
7244
7294
|
function createEvoDb(globalDir2) {
|
|
7245
|
-
|
|
7246
|
-
const dbPath =
|
|
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
|
|
7348
|
-
import
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
7383
|
-
const globalHalo =
|
|
7384
|
-
if (
|
|
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(
|
|
7438
|
+
content: readFileOrEmpty(path30.join(wsHalo, "INSTRUCTIONS.md"))
|
|
7389
7439
|
});
|
|
7390
7440
|
}
|
|
7391
|
-
if (
|
|
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(
|
|
7445
|
+
content: readFileOrEmpty(path30.join(globalHalo, "INSTRUCTIONS.md"))
|
|
7396
7446
|
});
|
|
7397
7447
|
}
|
|
7398
|
-
if (
|
|
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(
|
|
7452
|
+
content: readFileOrEmpty(path30.join(wsHalo, "USER.md"))
|
|
7403
7453
|
});
|
|
7404
7454
|
}
|
|
7405
|
-
if (
|
|
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(
|
|
7459
|
+
content: readFileOrEmpty(path30.join(globalHalo, "USER.md"))
|
|
7410
7460
|
});
|
|
7411
7461
|
}
|
|
7412
|
-
if (
|
|
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(
|
|
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 =
|
|
7422
|
-
const agentYaml =
|
|
7423
|
-
if (
|
|
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 (
|
|
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 =
|
|
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(
|
|
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" ?
|
|
7456
|
-
if (!
|
|
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
|
|
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 =
|
|
7468
|
-
const globalHalo =
|
|
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" &&
|
|
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
|
-
|
|
7636
|
+
fs23.mkdirSync(runDir, { recursive: true });
|
|
7587
7637
|
const rawMessages = sm.getSessionRawMessages(sourceSessionId);
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
7638
|
-
import
|
|
7687
|
+
import fs24 from "node:fs";
|
|
7688
|
+
import path31 from "node:path";
|
|
7639
7689
|
import os2 from "node:os";
|
|
7640
|
-
import
|
|
7690
|
+
import YAML8 from "yaml";
|
|
7641
7691
|
function loadAliases() {
|
|
7642
7692
|
try {
|
|
7643
|
-
const stat =
|
|
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 =
|
|
7648
|
-
const parsed =
|
|
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
|
-
|
|
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" ?
|
|
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
|
-
|
|
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 =
|
|
8213
|
-
if (!
|
|
8262
|
+
const mdPath = path31.join(dir, "SKILL.md");
|
|
8263
|
+
if (!fs24.existsSync(mdPath))
|
|
8214
8264
|
continue;
|
|
8215
8265
|
try {
|
|
8216
|
-
const { name, description } = parseSkillFrontmatter(
|
|
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" ?
|
|
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
|
-
|
|
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 =
|
|
8418
|
+
target = path31.join(os2.homedir(), target.slice(2));
|
|
8369
8419
|
} else if (!target.startsWith("/")) {
|
|
8370
|
-
target =
|
|
8420
|
+
target = path31.join(os2.homedir(), target);
|
|
8371
8421
|
}
|
|
8372
|
-
if (!
|
|
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 =
|
|
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
|
|
8465
|
-
import
|
|
8514
|
+
import path32 from "node:path";
|
|
8515
|
+
import fs25 from "node:fs";
|
|
8466
8516
|
function createA2ADb(globalDir2) {
|
|
8467
|
-
|
|
8468
|
-
const sqlite = new Database4(
|
|
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
|
|
9033
|
-
import { promises as
|
|
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
|
|
9068
|
-
return
|
|
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
|
|
9452
|
-
import
|
|
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 =
|
|
9498
|
-
await
|
|
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 =
|
|
9509
|
-
await
|
|
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
|
|
9583
|
+
import path35 from "node:path";
|
|
9534
9584
|
import os3 from "node:os";
|
|
9535
9585
|
function tempDir() {
|
|
9536
|
-
return
|
|
9586
|
+
return path35.resolve(os3.tmpdir());
|
|
9537
9587
|
}
|
|
9538
9588
|
function isInTempDir(filePath) {
|
|
9539
|
-
const resolved =
|
|
9589
|
+
const resolved = path35.resolve(filePath);
|
|
9540
9590
|
const tmp = tempDir();
|
|
9541
|
-
return resolved === tmp || resolved.startsWith(tmp +
|
|
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 =
|
|
9560
|
-
const ws =
|
|
9561
|
-
return resolved === ws || resolved.startsWith(ws +
|
|
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:
|
|
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 =
|
|
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
|
|
9604
|
-
import
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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: ${
|
|
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
|
|
10104
|
-
import
|
|
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 =
|
|
10201
|
+
const root = fs29.realpathSync(workspace);
|
|
10152
10202
|
const out = [];
|
|
10153
10203
|
for (const p of new Set(extractMediaMessage(text6).mediaPaths)) {
|
|
10154
|
-
if (!
|
|
10204
|
+
if (!path37.isAbsolute(p))
|
|
10155
10205
|
continue;
|
|
10156
10206
|
try {
|
|
10157
|
-
if (!
|
|
10207
|
+
if (!fs29.realpathSync(p).startsWith(root + path37.sep))
|
|
10158
10208
|
continue;
|
|
10159
|
-
const st =
|
|
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
|
|
10224
|
-
import
|
|
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 =
|
|
10433
|
+
wsPath = fs30.realpathSync(workspace);
|
|
10384
10434
|
} catch {
|
|
10385
10435
|
return jsonErr2(`workspace not found: ${workspace}`);
|
|
10386
10436
|
}
|
|
10387
|
-
if (!
|
|
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
|
|
10567
|
-
import
|
|
10616
|
+
import path39 from "node:path";
|
|
10617
|
+
import fs31 from "node:fs";
|
|
10568
10618
|
function createRunsDb(globalDir2) {
|
|
10569
|
-
|
|
10570
|
-
const dbPath =
|
|
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
|
|
10629
|
-
import
|
|
10630
|
-
import
|
|
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 =
|
|
10635
|
-
return
|
|
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
|
|
10756
|
-
import
|
|
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 =
|
|
10816
|
+
const lockPath = path41.join(workspaceRoot, ".halo", RUNTIME_LOCK_FILE);
|
|
10767
10817
|
try {
|
|
10768
|
-
|
|
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(
|
|
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
|
-
|
|
10788
|
-
|
|
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
|
-
|
|
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 =
|
|
10851
|
+
const lockPath = path41.join(workspaceRoot, ".halo", RUNTIME_LOCK_FILE);
|
|
10802
10852
|
try {
|
|
10803
|
-
if (parseInt(
|
|
10804
|
-
|
|
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
|
|
13698
|
+
import path42 from "node:path";
|
|
13649
13699
|
function resolveProviderRuntime(providerId) {
|
|
13650
|
-
const yamlPath =
|
|
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
|
|
13832
|
-
import
|
|
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("~/") ?
|
|
13837
|
-
return
|
|
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
|
|
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 =
|
|
13903
|
+
const fullPath = path43.join(dir, name);
|
|
13854
13904
|
let stat;
|
|
13855
13905
|
try {
|
|
13856
|
-
stat = await
|
|
13906
|
+
stat = await fs34.lstat(fullPath);
|
|
13857
13907
|
} catch {
|
|
13858
13908
|
continue;
|
|
13859
13909
|
}
|
|
13860
13910
|
if (stat.isDirectory()) {
|
|
13861
|
-
if (
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
14590
|
-
import
|
|
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
|
|
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
|
|
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 =
|
|
14676
|
+
const fullPath = path44.join(dirPath, name);
|
|
14627
14677
|
try {
|
|
14628
|
-
const content = (await
|
|
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 =
|
|
14693
|
+
const wsDir = path44.join(workspaceRoot, ".halo", "prompts", scope);
|
|
14644
14694
|
if (await dirExists(wsDir))
|
|
14645
14695
|
return wsDir;
|
|
14646
14696
|
}
|
|
14647
|
-
return
|
|
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 =
|
|
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
|
|
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 =
|
|
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.
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
-
|
|
19013
|
+
fs38.mkdirSync(logDir, { recursive: true });
|
|
18984
19014
|
}
|
|
18985
19015
|
function measureSize() {
|
|
18986
19016
|
try {
|
|
18987
|
-
return
|
|
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
|
-
|
|
19025
|
+
fs38.unlinkSync(`${logFile}.${maxFiles}`);
|
|
18996
19026
|
} catch {
|
|
18997
19027
|
}
|
|
18998
19028
|
for (let i = maxFiles - 1; i >= 1; i--) {
|
|
18999
19029
|
try {
|
|
19000
|
-
|
|
19030
|
+
fs38.renameSync(`${logFile}.${i}`, `${logFile}.${i + 1}`);
|
|
19001
19031
|
} catch {
|
|
19002
19032
|
}
|
|
19003
19033
|
}
|
|
19004
19034
|
try {
|
|
19005
|
-
|
|
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
|
-
|
|
19047
|
+
fs38.appendFileSync(logFile, line);
|
|
19018
19048
|
} catch (err) {
|
|
19019
19049
|
if (err.code !== "ENOENT")
|
|
19020
19050
|
throw err;
|
|
19021
19051
|
ensureDir();
|
|
19022
|
-
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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 =
|
|
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
|
-
|
|
19506
|
-
|
|
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
|
-
|
|
19538
|
+
fs40.chmodSync(CONFIG_PATH, 384);
|
|
19509
19539
|
} catch {
|
|
19510
19540
|
}
|
|
19511
19541
|
}
|
|
19512
19542
|
function readConfigLeaf(dotPath) {
|
|
19513
|
-
if (!
|
|
19543
|
+
if (!fs40.existsSync(CONFIG_PATH))
|
|
19514
19544
|
return void 0;
|
|
19515
|
-
const raw =
|
|
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
|
|
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 (!
|
|
19576
|
+
if (!fs41.existsSync(SETTINGS_PATH2))
|
|
19547
19577
|
return new YAML11.Document({});
|
|
19548
|
-
const raw =
|
|
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
|
-
|
|
19555
|
-
|
|
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
|
-
|
|
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
|
|
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 (!
|
|
19682
|
+
if (!fs42.existsSync(filePath))
|
|
19653
19683
|
return null;
|
|
19654
19684
|
try {
|
|
19655
|
-
return YAML12.parse(
|
|
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 (!
|
|
19725
|
+
if (!fs42.existsSync(dir))
|
|
19696
19726
|
return [];
|
|
19697
19727
|
const out = [];
|
|
19698
|
-
for (const id of
|
|
19728
|
+
for (const id of fs42.readdirSync(dir)) {
|
|
19699
19729
|
const skillDir = path51.join(dir, id);
|
|
19700
|
-
if (!
|
|
19730
|
+
if (!fs42.statSync(skillDir).isDirectory())
|
|
19701
19731
|
continue;
|
|
19702
19732
|
const skillMd = path51.join(skillDir, "SKILL.md");
|
|
19703
|
-
if (!
|
|
19733
|
+
if (!fs42.existsSync(skillMd))
|
|
19704
19734
|
continue;
|
|
19705
|
-
const text6 =
|
|
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 (!
|
|
19818
|
+
if (!fs42.existsSync(yamlPath))
|
|
19789
19819
|
continue;
|
|
19790
19820
|
try {
|
|
19791
|
-
const doc = YAML12.parseDocument(
|
|
19821
|
+
const doc = YAML12.parseDocument(fs42.readFileSync(yamlPath, "utf-8"));
|
|
19792
19822
|
doc.set("model", block);
|
|
19793
|
-
|
|
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 (!
|
|
19832
|
+
if (!fs42.existsSync(dir))
|
|
19803
19833
|
return [];
|
|
19804
19834
|
const out = [];
|
|
19805
|
-
for (const id of
|
|
19835
|
+
for (const id of fs42.readdirSync(dir)) {
|
|
19806
19836
|
const skillDir = path51.join(dir, id);
|
|
19807
|
-
if (!
|
|
19837
|
+
if (!fs42.statSync(skillDir).isDirectory())
|
|
19808
19838
|
continue;
|
|
19809
19839
|
const cfgPath = path51.join(skillDir, "config.yaml");
|
|
19810
|
-
if (!
|
|
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 (
|
|
19820
|
-
const text6 =
|
|
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
|
|
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 (!
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
20361
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
20516
|
+
const fd = fs45.openSync(resolved, "r");
|
|
20487
20517
|
let n = 0;
|
|
20488
20518
|
try {
|
|
20489
|
-
n =
|
|
20519
|
+
n = fs45.readSync(fd, buf, 0, MAX_FILE_BYTES, 0);
|
|
20490
20520
|
} finally {
|
|
20491
|
-
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
-
|
|
20793
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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([
|
|
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
|
|
22874
|
-
const st = real ? await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
23431
|
+
await fs51.mkdir(destDir, { recursive: true });
|
|
23402
23432
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
23403
|
-
await
|
|
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
|
|
23429
|
-
const stat = await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
23513
|
+
await fs51.appendFile(absolutePath, bytes);
|
|
23484
23514
|
else
|
|
23485
|
-
await
|
|
23486
|
-
const stat = await
|
|
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
|
|
23535
|
+
await fs51.mkdir(path60.dirname(absolutePath), { recursive: true });
|
|
23506
23536
|
try {
|
|
23507
|
-
await
|
|
23537
|
+
await fs51.access(absolutePath);
|
|
23508
23538
|
return c.json({ error: "File already exists" }, 409);
|
|
23509
23539
|
} catch {
|
|
23510
23540
|
}
|
|
23511
|
-
await
|
|
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
|
|
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
|
|
23554
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
23846
|
+
const entries = await fs51.readdir(resolved, { withFileTypes: true });
|
|
23817
23847
|
if (c.req.query("files") === "1") {
|
|
23818
|
-
const realDir = await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
24242
|
-
lines =
|
|
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
|
-
|
|
24282
|
+
fs53.writeFileSync(GIT_CREDENTIALS_PATH, kept.join("\n") + "\n", { encoding: "utf-8", mode: 384 });
|
|
24253
24283
|
try {
|
|
24254
|
-
|
|
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 (!
|
|
24293
|
+
if (!fs53.existsSync(GIT_CREDENTIALS_PATH))
|
|
24264
24294
|
return [];
|
|
24265
|
-
const lines =
|
|
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 (!
|
|
24309
|
+
if (!fs53.existsSync(GIT_CREDENTIALS_PATH))
|
|
24280
24310
|
return;
|
|
24281
|
-
const lines =
|
|
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
|
-
|
|
24321
|
+
fs53.writeFileSync(GIT_CREDENTIALS_PATH, kept.length ? kept.join("\n") + "\n" : "", { encoding: "utf-8", mode: 384 });
|
|
24292
24322
|
try {
|
|
24293
|
-
|
|
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
|
|
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 =
|
|
24348
|
+
const fd = fs54.openSync(abs, "r");
|
|
24319
24349
|
try {
|
|
24320
24350
|
const buf = Buffer.alloc(64);
|
|
24321
|
-
const n =
|
|
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
|
-
|
|
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 =
|
|
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 (!
|
|
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 =
|
|
24401
|
+
dir = fs54.mkdtempSync(path63.join(os6.tmpdir(), "halo-askpass-"));
|
|
24372
24402
|
const askpass = path63.join(dir, "askpass.sh");
|
|
24373
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
24917
|
+
await fs55.writeFile(tmpPath, content, "utf-8");
|
|
24888
24918
|
try {
|
|
24889
|
-
await
|
|
24919
|
+
await fs55.rename(tmpPath, filePath);
|
|
24890
24920
|
} catch {
|
|
24891
|
-
await
|
|
24892
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
25006
|
-
const parsed = _yamlCache2.get(yamlPath, yamlStat.mtimeMs) ?? _yamlCache2.set(yamlPath, yamlStat.mtimeMs, parseAgentYaml(await
|
|
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
|
|
25060
|
+
await fs55.access(yamlPath);
|
|
25031
25061
|
} catch {
|
|
25032
25062
|
await ensureDir2(defaultDir);
|
|
25033
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
25112
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
25479
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
25630
|
+
await fs56.access(skillDir);
|
|
25601
25631
|
} catch {
|
|
25602
25632
|
return c.json({ error: "Skill not found" }, 404);
|
|
25603
25633
|
}
|
|
25604
|
-
await
|
|
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
|
|
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
|
|
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
|
|
25655
|
-
await
|
|
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
|
|
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
|
|
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 (!
|
|
25956
|
+
if (!fs58.existsSync(srcDir))
|
|
25927
25957
|
return false;
|
|
25928
|
-
|
|
25958
|
+
fs58.mkdirSync(path68.dirname(outZip), { recursive: true });
|
|
25929
25959
|
const zip = new JSZip();
|
|
25930
25960
|
const walk = (dir, rel) => {
|
|
25931
|
-
const entries =
|
|
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,
|
|
25972
|
+
zip.file(childRel, fs58.readFileSync(abs), { date: fs58.statSync(abs).mtime });
|
|
25943
25973
|
} else if (e.isSymbolicLink()) {
|
|
25944
25974
|
try {
|
|
25945
|
-
if (
|
|
25946
|
-
zip.file(childRel,
|
|
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" }),
|
|
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
|
-
|
|
25994
|
+
fs58.rmSync(dir, { recursive: true, force: true });
|
|
25965
25995
|
} catch {
|
|
25966
25996
|
}
|
|
25967
25997
|
}
|
|
25968
25998
|
function rmFile(p) {
|
|
25969
25999
|
try {
|
|
25970
|
-
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 }) :
|
|
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
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
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
|
|
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
|
|
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
|
-
|
|
28397
|
+
fs62.mkdirSync(path71.dirname(final), { recursive: true });
|
|
28368
28398
|
let have = 0;
|
|
28369
28399
|
try {
|
|
28370
|
-
have =
|
|
28400
|
+
have = fs62.statSync(part).size;
|
|
28371
28401
|
} catch {
|
|
28372
28402
|
}
|
|
28373
28403
|
if (have > f.size) {
|
|
28374
|
-
|
|
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
|
|
28410
|
+
for await (const chunk of fs62.createReadStream(part))
|
|
28381
28411
|
hash.update(chunk);
|
|
28382
28412
|
if (hash.digest("hex") === f.sha256) {
|
|
28383
|
-
|
|
28413
|
+
fs62.renameSync(part, final);
|
|
28384
28414
|
return;
|
|
28385
28415
|
}
|
|
28386
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
28982
|
-
return
|
|
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
|
|
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
|
|
29350
|
-
if (!cwd || !(await
|
|
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
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
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
|
|
30683
|
+
import fs66 from "node:fs";
|
|
30654
30684
|
function createCronDb(globalDir2) {
|
|
30655
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
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(
|
|
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.
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
31451
|
-
raw =
|
|
31480
|
+
mtimeMs = fs68.fstatSync(fd).mtimeMs;
|
|
31481
|
+
raw = fs68.readFileSync(fd, "utf8");
|
|
31452
31482
|
} finally {
|
|
31453
|
-
|
|
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
|
-
|
|
31468
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 (!
|
|
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 =
|
|
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 (!
|
|
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 =
|
|
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 (!
|
|
32818
|
+
if (!fs69.existsSync(dir))
|
|
32789
32819
|
return;
|
|
32790
32820
|
const cutoff = Date.now() - LOG_RETENTION_DAYS * DAY_MS2;
|
|
32791
|
-
for (const name of
|
|
32821
|
+
for (const name of fs69.readdirSync(dir)) {
|
|
32792
32822
|
const p = path79.join(dir, name);
|
|
32793
32823
|
try {
|
|
32794
|
-
const stat =
|
|
32824
|
+
const stat = fs69.statSync(p);
|
|
32795
32825
|
if (stat.mtimeMs < cutoff)
|
|
32796
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
33348
|
+
fs71.mkdirSync(abs, { recursive: true });
|
|
33319
33349
|
continue;
|
|
33320
33350
|
}
|
|
33321
|
-
|
|
33322
|
-
|
|
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 (
|
|
33356
|
+
if (fs71.existsSync(path81.join(dir, MANIFEST_FILE)))
|
|
33327
33357
|
return;
|
|
33328
|
-
const children =
|
|
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 (!
|
|
33362
|
+
if (!fs71.existsSync(path81.join(inner, MANIFEST_FILE)))
|
|
33333
33363
|
return;
|
|
33334
|
-
for (const name of
|
|
33335
|
-
|
|
33364
|
+
for (const name of fs71.readdirSync(inner)) {
|
|
33365
|
+
fs71.renameSync(path81.join(inner, name), path81.join(dir, name));
|
|
33336
33366
|
}
|
|
33337
|
-
|
|
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
|
-
|
|
33374
|
+
fs71.mkdirSync(root, { recursive: true });
|
|
33345
33375
|
const stage = path81.join(root, `.tmp-unpack-${rand()}`);
|
|
33346
|
-
|
|
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(
|
|
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 =
|
|
33400
|
+
const hadOld = fs71.existsSync(target);
|
|
33371
33401
|
if (!hadOld)
|
|
33372
33402
|
forgetState(manifestId);
|
|
33373
33403
|
if (hadOld)
|
|
33374
|
-
|
|
33404
|
+
fs71.renameSync(target, old);
|
|
33375
33405
|
try {
|
|
33376
|
-
|
|
33406
|
+
fs71.renameSync(stage, target);
|
|
33377
33407
|
} catch (err) {
|
|
33378
33408
|
if (hadOld)
|
|
33379
|
-
|
|
33409
|
+
fs71.renameSync(old, target);
|
|
33380
33410
|
throw err;
|
|
33381
33411
|
}
|
|
33382
33412
|
if (hadOld) {
|
|
33383
33413
|
try {
|
|
33384
|
-
|
|
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
|
-
|
|
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 (!
|
|
33432
|
+
if (!fs71.existsSync(dir))
|
|
33403
33433
|
return false;
|
|
33404
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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 =
|
|
34015
|
-
real =
|
|
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 (!
|
|
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 =
|
|
34144
|
-
const nodeStream =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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: !
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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: !
|
|
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
|
|
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 =
|
|
37222
|
-
realRoot =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
38437
|
+
const fs84 = await import("node:fs");
|
|
38408
38438
|
const path94 = await import("node:path");
|
|
38409
|
-
const buf =
|
|
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
|
|
38456
|
+
const fs84 = await import("node:fs");
|
|
38427
38457
|
const path94 = await import("node:path");
|
|
38428
|
-
const buf =
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
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
|
-
|
|
39945
|
-
const fd =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
39967
|
-
|
|
39968
|
-
|
|
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 =
|
|
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 (!
|
|
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 (
|
|
40054
|
+
if (fs81.existsSync(path90.join(bundled, "index.html")))
|
|
40025
40055
|
return bundled;
|
|
40026
40056
|
const sibling = path90.resolve(__dirname3, "..", "..", "admin", "out");
|
|
40027
|
-
if (
|
|
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.
|
|
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 (!
|
|
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 (!
|
|
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 =
|
|
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
|
|
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
|
-
|
|
40404
|
-
for (const rel of
|
|
40405
|
-
|
|
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 (
|
|
40442
|
+
if (fs82.existsSync(dir))
|
|
40413
40443
|
return false;
|
|
40414
40444
|
const tmp = path91.join(base, `.tmp-${crypto13.randomBytes(8).toString("hex")}`);
|
|
40415
|
-
|
|
40445
|
+
fs82.mkdirSync(tmp, { mode: 448 });
|
|
40416
40446
|
try {
|
|
40417
40447
|
const template = path91.join(base, TEMPLATE_DIR);
|
|
40418
|
-
if (
|
|
40419
|
-
|
|
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 (
|
|
40424
|
-
|
|
40425
|
-
|
|
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
|
-
|
|
40460
|
+
fs82.renameSync(tmp, dir);
|
|
40431
40461
|
return true;
|
|
40432
40462
|
} catch (err) {
|
|
40433
|
-
|
|
40463
|
+
fs82.rmSync(tmp, { recursive: true, force: true });
|
|
40434
40464
|
const code = err.code;
|
|
40435
|
-
if ((code === "EEXIST" || code === "ENOTEMPTY") &&
|
|
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 (
|
|
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 =
|
|
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 =
|
|
40533
|
+
const link = fs82.readlinkSync(`/proc/self/fd/${pfd}`);
|
|
40504
40534
|
if (!link.startsWith(`${root}/`))
|
|
40505
40535
|
return `not under ${root}/`;
|
|
40506
|
-
const st =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
40690
|
+
fs82.rmSync(dir, { recursive: true, force: true });
|
|
40661
40691
|
settle();
|
|
40662
40692
|
};
|
|
40663
40693
|
try {
|
|
40664
|
-
dir =
|
|
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 = () =>
|
|
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
|
|
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.
|
|
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 (!
|
|
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 =
|
|
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
|
-
|
|
43357
|
-
const out =
|
|
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 (!
|
|
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 (!
|
|
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
|
|
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);
|