@turmind/halo 2.2.4 → 2.2.6
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/README.md +2 -1
- package/admin-out/404.html +1 -1
- package/admin-out/_next/static/chunks/1989-3ab059aa2c368f46.js +1 -0
- package/admin-out/_next/static/chunks/4320-0fb65ed376b666a8.js +1 -0
- package/admin-out/_next/static/chunks/app/page-99eba94ecd0f8e81.js +1 -0
- package/admin-out/_next/static/css/7eb37d975d4027da.css +1 -0
- package/admin-out/index.html +1 -1
- package/admin-out/index.txt +5 -5
- package/bundled-docs/design/agent.md +0 -1
- package/bundled-docs/design/architecture.md +1 -1
- package/bundled-docs/design/canvas-extensions.md +2 -0
- package/bundled-docs/design/cron.md +2 -2
- package/bundled-docs/design/feishu.md +10 -0
- package/bundled-docs/design/storage.md +4 -2
- package/bundled-docs/design/stt-local.md +1 -1
- package/bundled-docs/design/ws.md +1 -1
- package/bundled-docs/dev/add-model-provider.md +18 -0
- package/bundled-docs/dev/api.md +7 -1
- package/bundled-docs/dev/deploy.md +26 -1
- package/bundled-docs/dev/desktop-packaging.md +3 -2
- package/bundled-docs/dev/env.md +1 -2
- package/bundled-docs/guide/agents.md +2 -2
- package/bundled-docs/guide/cli.md +2 -2
- package/bundled-docs/guide/skills.md +1 -1
- package/bundled-docs/requirements/explorer.md +10 -3
- package/bundled-docs/requirements/settings.md +24 -1
- package/dist/feishu-sdk.cjs +23128 -0
- package/dist/feishu-sdk.licenses.txt +1465 -0
- package/dist/index.js +418 -220
- package/package.json +1 -2
- package/templates/models/aws-bedrock-claude-invoke.yaml +62 -1
- package/admin-out/_next/static/chunks/1607-bf227fc5e4db45b7.js +0 -1
- package/admin-out/_next/static/chunks/1989-9d30cdb1a86e4beb.js +0 -1
- package/admin-out/_next/static/chunks/app/page-c9d174a5432b0007.js +0 -1
- package/admin-out/_next/static/css/87d4fc049f865389.css +0 -1
- /package/admin-out/_next/static/{vf5W8US5y8B2f1E6zJJw3 → 6I6qmeIcucaJczGu5oP3C}/_buildManifest.js +0 -0
- /package/admin-out/_next/static/{vf5W8US5y8B2f1E6zJJw3 → 6I6qmeIcucaJczGu5oP3C}/_ssgManifest.js +0 -0
package/dist/index.js
CHANGED
|
@@ -2121,7 +2121,7 @@ var init_init = __esm({
|
|
|
2121
2121
|
path9.resolve(__dirname, "..", "bundled-docs"),
|
|
2122
2122
|
path9.resolve(__dirname, "..", "..", "..", ".halo", "docs")
|
|
2123
2123
|
];
|
|
2124
|
-
TEMPLATE_VERSION =
|
|
2124
|
+
TEMPLATE_VERSION = 124;
|
|
2125
2125
|
VERSION_FILE = ".template-version";
|
|
2126
2126
|
SKIP_NAMES = /* @__PURE__ */ new Set([".DS_Store", "schema.sql", "__pycache__", ".pytest_cache"]);
|
|
2127
2127
|
BUILTIN_AGENT_IDS = /* @__PURE__ */ new Set([
|
|
@@ -9350,27 +9350,27 @@ var init_workspace = __esm({
|
|
|
9350
9350
|
constructor(projectRoot) {
|
|
9351
9351
|
this.projectRoot = projectRoot;
|
|
9352
9352
|
}
|
|
9353
|
-
async readFile(
|
|
9354
|
-
const fullPath = this.validatePath(
|
|
9353
|
+
async readFile(path99) {
|
|
9354
|
+
const fullPath = this.validatePath(path99);
|
|
9355
9355
|
return readFile(fullPath, "utf-8");
|
|
9356
9356
|
}
|
|
9357
|
-
async writeFile(
|
|
9358
|
-
const fullPath = this.validatePath(
|
|
9357
|
+
async writeFile(path99, content) {
|
|
9358
|
+
const fullPath = this.validatePath(path99);
|
|
9359
9359
|
const dir = resolve2(fullPath, "..");
|
|
9360
9360
|
await mkdir(dir, { recursive: true });
|
|
9361
9361
|
await writeFile(fullPath, content, "utf-8");
|
|
9362
9362
|
}
|
|
9363
|
-
validatePath(
|
|
9364
|
-
const fullPath = isAbsolute(
|
|
9363
|
+
validatePath(path99) {
|
|
9364
|
+
const fullPath = isAbsolute(path99) ? resolve2(path99) : resolve2(this.projectRoot, path99);
|
|
9365
9365
|
const root = resolve2(this.projectRoot);
|
|
9366
9366
|
if (fullPath !== root && !fullPath.startsWith(root + sep)) {
|
|
9367
|
-
throw new WorkspaceError(`Path "${
|
|
9367
|
+
throw new WorkspaceError(`Path "${path99}" is outside the workspace directory "${this.projectRoot}"`);
|
|
9368
9368
|
}
|
|
9369
9369
|
try {
|
|
9370
9370
|
const real = realpathSync2(fullPath);
|
|
9371
9371
|
const realRoot = realpathSync2(root);
|
|
9372
9372
|
if (real !== realRoot && !real.startsWith(realRoot + sep)) {
|
|
9373
|
-
throw new WorkspaceError(`Path "${
|
|
9373
|
+
throw new WorkspaceError(`Path "${path99}" is outside the workspace directory "${this.projectRoot}"`);
|
|
9374
9374
|
}
|
|
9375
9375
|
} catch (err) {
|
|
9376
9376
|
if (err instanceof WorkspaceError)
|
|
@@ -9557,12 +9557,12 @@ var init_git_manager = __esm({
|
|
|
9557
9557
|
const code = parts[0];
|
|
9558
9558
|
const status = code[0];
|
|
9559
9559
|
const isRenameOrCopy = status === "R" || status === "C";
|
|
9560
|
-
const
|
|
9561
|
-
if (!
|
|
9560
|
+
const path99 = isRenameOrCopy ? parts[2] : parts[1];
|
|
9561
|
+
if (!path99 || seen.has(path99))
|
|
9562
9562
|
continue;
|
|
9563
|
-
seen.add(
|
|
9563
|
+
seen.add(path99);
|
|
9564
9564
|
files.push({
|
|
9565
|
-
path:
|
|
9565
|
+
path: path99,
|
|
9566
9566
|
status,
|
|
9567
9567
|
from: isRenameOrCopy ? parts[1] : void 0
|
|
9568
9568
|
});
|
|
@@ -9710,9 +9710,9 @@ var init_git_manager = __esm({
|
|
|
9710
9710
|
* empty for an added file or the root commit) and `modified` is the version
|
|
9711
9711
|
* at `commit` (empty for a deletion). The working-tree/staged path above is
|
|
9712
9712
|
* left entirely untouched (commit === undefined preserves existing behavior). */
|
|
9713
|
-
async getFileDiff(
|
|
9713
|
+
async getFileDiff(path99, staged, from, commit) {
|
|
9714
9714
|
if (commit) {
|
|
9715
|
-
const parentPath = from ||
|
|
9715
|
+
const parentPath = from || path99;
|
|
9716
9716
|
let original2 = "";
|
|
9717
9717
|
try {
|
|
9718
9718
|
original2 = await this.git.show([`${commit}^:${parentPath}`]);
|
|
@@ -9721,13 +9721,13 @@ var init_git_manager = __esm({
|
|
|
9721
9721
|
}
|
|
9722
9722
|
let modified2 = "";
|
|
9723
9723
|
try {
|
|
9724
|
-
modified2 = await this.git.show([`${commit}:${
|
|
9724
|
+
modified2 = await this.git.show([`${commit}:${path99}`]);
|
|
9725
9725
|
} catch {
|
|
9726
9726
|
modified2 = "";
|
|
9727
9727
|
}
|
|
9728
9728
|
return { original: original2, modified: modified2 };
|
|
9729
9729
|
}
|
|
9730
|
-
const headPath = from ||
|
|
9730
|
+
const headPath = from || path99;
|
|
9731
9731
|
let original = "";
|
|
9732
9732
|
try {
|
|
9733
9733
|
original = await this.git.show([`HEAD:${headPath}`]);
|
|
@@ -9737,13 +9737,13 @@ var init_git_manager = __esm({
|
|
|
9737
9737
|
let modified = "";
|
|
9738
9738
|
if (staged) {
|
|
9739
9739
|
try {
|
|
9740
|
-
modified = await this.git.show([`:${
|
|
9740
|
+
modified = await this.git.show([`:${path99}`]);
|
|
9741
9741
|
} catch {
|
|
9742
9742
|
modified = "";
|
|
9743
9743
|
}
|
|
9744
9744
|
} else {
|
|
9745
9745
|
try {
|
|
9746
|
-
modified = await this.workspace.readFile(
|
|
9746
|
+
modified = await this.workspace.readFile(path99);
|
|
9747
9747
|
} catch {
|
|
9748
9748
|
modified = "";
|
|
9749
9749
|
}
|
|
@@ -15847,7 +15847,7 @@ function createNodeHub(deps) {
|
|
|
15847
15847
|
since: c.since
|
|
15848
15848
|
}));
|
|
15849
15849
|
const announce = () => {
|
|
15850
|
-
broadcast({ type: "nodes:changed", online: online().map(({ accountId, root, shell, os:
|
|
15850
|
+
broadcast({ type: "nodes:changed", online: online().map(({ accountId, root, shell, os: os13, since }) => ({ accountId, root, shell, os: os13, since })) });
|
|
15851
15851
|
};
|
|
15852
15852
|
const settle = (conn, id, fn) => {
|
|
15853
15853
|
const p = conn.pending.get(id);
|
|
@@ -16830,7 +16830,7 @@ async function initObservability(haloProcess = "server") {
|
|
|
16830
16830
|
return true;
|
|
16831
16831
|
}
|
|
16832
16832
|
const { registerSdk: registerSdk2 } = await Promise.resolve().then(() => (init_otel_sdk(), otel_sdk_exports));
|
|
16833
|
-
providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.2.
|
|
16833
|
+
providers = await registerSdk2(process.env.OTEL_SERVICE_NAME, "2.2.6", haloProcess);
|
|
16834
16834
|
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})`);
|
|
16835
16835
|
return true;
|
|
16836
16836
|
}
|
|
@@ -22018,8 +22018,8 @@ function applyPathPick(value, ref, pick) {
|
|
|
22018
22018
|
const before = value.slice(0, markerStart);
|
|
22019
22019
|
const kind = ref.kind === "scope" ? "scope" : ref.kind === "image" ? "image" : pick.isImage ? "image" : "file";
|
|
22020
22020
|
const needsQuote = pick.insertPath.includes(" ");
|
|
22021
|
-
const
|
|
22022
|
-
return `${before}@${kind} ${
|
|
22021
|
+
const path99 = pick.isDir ? needsQuote ? `"${pick.insertPath}/` : `${pick.insertPath}/` : needsQuote ? `"${pick.insertPath}" ` : `${pick.insertPath} `;
|
|
22022
|
+
return `${before}@${kind} ${path99}`;
|
|
22023
22023
|
}
|
|
22024
22024
|
var init_path_suggest_engine = __esm({
|
|
22025
22025
|
"src/tui/path-suggest-engine.ts"() {
|
|
@@ -23920,6 +23920,31 @@ async function planFolderZip(root, projectPath, opts) {
|
|
|
23920
23920
|
const [rootReal, wsReal] = await Promise.all([fs53.realpath(root), fs53.realpath(projectPath)]);
|
|
23921
23921
|
if (isBlockedPath(rootReal, wsReal))
|
|
23922
23922
|
throw new FolderZipError(403, "Path is not accessible");
|
|
23923
|
+
const planner = createPlanner(wsReal, opts);
|
|
23924
|
+
await planner.walk(rootReal, "");
|
|
23925
|
+
return planner.plan;
|
|
23926
|
+
}
|
|
23927
|
+
async function planSelectionZip(rels, projectPath, opts) {
|
|
23928
|
+
const selected = new Set(rels);
|
|
23929
|
+
const kept = [...selected].filter((rel) => rel === "" || !rel.split("/").some((_, i, segs) => selected.has(segs.slice(0, i).join("/")))).sort();
|
|
23930
|
+
let common = kept[0].split("/").slice(0, -1);
|
|
23931
|
+
for (const rel of kept) {
|
|
23932
|
+
const segs = rel.split("/").slice(0, -1);
|
|
23933
|
+
let i = 0;
|
|
23934
|
+
while (i < common.length && common[i] === segs[i])
|
|
23935
|
+
i++;
|
|
23936
|
+
common = common.slice(0, i);
|
|
23937
|
+
}
|
|
23938
|
+
const parent = common.join("/");
|
|
23939
|
+
const wsReal = await fs53.realpath(projectPath);
|
|
23940
|
+
const planner = createPlanner(wsReal, opts);
|
|
23941
|
+
for (const rel of kept) {
|
|
23942
|
+
const real = rel ? path60.join(await fs53.realpath(path60.join(wsReal, path60.dirname(rel))), path60.basename(rel)) : wsReal;
|
|
23943
|
+
await planner.addSelected(real, parent ? rel.slice(parent.length + 1) : rel);
|
|
23944
|
+
}
|
|
23945
|
+
return { plan: planner.plan, parent };
|
|
23946
|
+
}
|
|
23947
|
+
function createPlanner(wsReal, opts) {
|
|
23923
23948
|
const { includeIgnored, limits, signal } = opts;
|
|
23924
23949
|
const deadline = Date.now() + limits.maxWalkMs;
|
|
23925
23950
|
const plan = { items: [], files: 0, bytes: 0, excluded: new ExcludedLog() };
|
|
@@ -24012,8 +24037,31 @@ async function planFolderZip(root, projectPath, opts) {
|
|
|
24012
24037
|
}
|
|
24013
24038
|
return nonEmpty2;
|
|
24014
24039
|
}
|
|
24015
|
-
|
|
24016
|
-
|
|
24040
|
+
async function addSelected(real, rel) {
|
|
24041
|
+
signal?.throwIfAborted();
|
|
24042
|
+
if (Date.now() > deadline)
|
|
24043
|
+
throw walkTimeout();
|
|
24044
|
+
const name = path60.basename(real);
|
|
24045
|
+
const st = await fs53.lstat(real);
|
|
24046
|
+
if (rel.split("/").some((seg, i) => isZipUnsafeName(seg, i === 0))) {
|
|
24047
|
+
excluded.add("unreadable", `${rel}${st.isDirectory() ? "/" : ""} (name not valid in a zip)`);
|
|
24048
|
+
} else if (st.isSymbolicLink()) {
|
|
24049
|
+
await addSymlink(real, rel, name);
|
|
24050
|
+
} else if (st.isDirectory()) {
|
|
24051
|
+
if (isBlockedPath(real, wsReal))
|
|
24052
|
+
excluded.add("blocked", `${rel}/`);
|
|
24053
|
+
else if (!await walk(real, rel) && rel)
|
|
24054
|
+
plan.items.push({ rel, mtimeMs: st.mtimeMs });
|
|
24055
|
+
} else if (st.isFile()) {
|
|
24056
|
+
if (isEnvName(name) || isBlockedPath(real, wsReal))
|
|
24057
|
+
excluded.add("blocked", rel);
|
|
24058
|
+
else
|
|
24059
|
+
addFile(rel, real, st);
|
|
24060
|
+
} else {
|
|
24061
|
+
excluded.add("unreadable", `${rel} (not a regular file)`);
|
|
24062
|
+
}
|
|
24063
|
+
}
|
|
24064
|
+
return { plan, walk, addSelected };
|
|
24017
24065
|
}
|
|
24018
24066
|
function planSummary(plan) {
|
|
24019
24067
|
return { files: plan.files, bytes: plan.bytes, excluded: { ...plan.excluded.counts }, ignoredNames: { ...plan.excluded.ignoredNames } };
|
|
@@ -24747,26 +24795,44 @@ function createFileRoutes(opts = {}) {
|
|
|
24747
24795
|
}
|
|
24748
24796
|
});
|
|
24749
24797
|
app2.get("/files/download-folder", async (c) => {
|
|
24750
|
-
const
|
|
24798
|
+
const relPaths = c.req.queries("path") ?? [];
|
|
24799
|
+
const relPath = relPaths[0] ?? "";
|
|
24751
24800
|
const projectId = c.req.query("projectId");
|
|
24752
24801
|
if (!projectId)
|
|
24753
24802
|
return c.json({ error: "projectId is required" }, 400);
|
|
24754
24803
|
const signal = c.req.raw.signal;
|
|
24804
|
+
const planOpts = { includeIgnored: c.req.query("include") === "excluded", limits: folderZipLimits, signal };
|
|
24755
24805
|
try {
|
|
24756
|
-
|
|
24757
|
-
|
|
24758
|
-
|
|
24759
|
-
|
|
24760
|
-
|
|
24761
|
-
|
|
24762
|
-
|
|
24763
|
-
|
|
24764
|
-
|
|
24765
|
-
|
|
24766
|
-
|
|
24806
|
+
let plan;
|
|
24807
|
+
let folderName;
|
|
24808
|
+
if (relPaths.length > 1) {
|
|
24809
|
+
let projectPath = "";
|
|
24810
|
+
const rels = [];
|
|
24811
|
+
for (const p of relPaths) {
|
|
24812
|
+
const resolved = await resolveProjectFile(projectId, p);
|
|
24813
|
+
if ("error" in resolved)
|
|
24814
|
+
return c.json({ error: resolved.error }, resolved.status);
|
|
24815
|
+
projectPath = resolved.projectPath;
|
|
24816
|
+
const rel = path61.relative(projectPath, resolved.absolutePath);
|
|
24817
|
+
if (rel === ".." || rel.startsWith(`..${path61.sep}`) || path61.isAbsolute(rel))
|
|
24818
|
+
return c.json({ error: "Path traversal not allowed" }, 403);
|
|
24819
|
+
rels.push(rel.split(path61.sep).join("/"));
|
|
24820
|
+
}
|
|
24821
|
+
const selection = await planSelectionZip(rels, projectPath, planOpts);
|
|
24822
|
+
plan = selection.plan;
|
|
24823
|
+
folderName = `${path61.basename(path61.resolve(projectPath, selection.parent)) || "workspace"}-selection`;
|
|
24824
|
+
} else {
|
|
24825
|
+
const resolved = await resolveProjectFile(projectId, relPath);
|
|
24826
|
+
if ("error" in resolved)
|
|
24827
|
+
return c.json({ error: resolved.error }, resolved.status);
|
|
24828
|
+
const { projectPath, absolutePath } = resolved;
|
|
24829
|
+
if (!(await fs54.stat(absolutePath)).isDirectory())
|
|
24830
|
+
return c.json({ error: "Not a directory" }, 400);
|
|
24831
|
+
plan = await planFolderZip(absolutePath, projectPath, planOpts);
|
|
24832
|
+
folderName = path61.basename(absolutePath) || "workspace";
|
|
24833
|
+
}
|
|
24767
24834
|
if (c.req.query("estimate") === "1")
|
|
24768
24835
|
return c.json(planSummary(plan));
|
|
24769
|
-
const folderName = path61.basename(absolutePath) || "workspace";
|
|
24770
24836
|
const fileName = `${folderName}.zip`;
|
|
24771
24837
|
const asciiName = fileName.replace(/[^\x20-\x7e]|["\\]/g, "_");
|
|
24772
24838
|
const encodedName = encodeURIComponent(fileName).replace(/['()*]/g, (ch) => `%${ch.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
@@ -26855,8 +26921,8 @@ function detectOrphans(tree, declared, kept) {
|
|
|
26855
26921
|
if (!block || typeof block !== "object")
|
|
26856
26922
|
continue;
|
|
26857
26923
|
for (const k of Object.keys(block)) {
|
|
26858
|
-
const
|
|
26859
|
-
if (!declaredMap.has(
|
|
26924
|
+
const path99 = `${namespaceId}.${kindWord}.${k}`;
|
|
26925
|
+
if (!declaredMap.has(path99)) {
|
|
26860
26926
|
out.push({ namespaceId, kind: kindWord === "params" ? "param" : "secret", key: k });
|
|
26861
26927
|
}
|
|
26862
26928
|
}
|
|
@@ -28460,17 +28526,17 @@ function passwordStrengthError(pw) {
|
|
|
28460
28526
|
}
|
|
28461
28527
|
function authMiddleware() {
|
|
28462
28528
|
return async (c, next) => {
|
|
28463
|
-
const
|
|
28464
|
-
if (PUBLIC_PATHS.some((p) =>
|
|
28529
|
+
const path99 = c.req.path;
|
|
28530
|
+
if (PUBLIC_PATHS.some((p) => path99 === p || path99.startsWith(p + "?"))) {
|
|
28465
28531
|
return next();
|
|
28466
28532
|
}
|
|
28467
|
-
if (EXTENSION_ASSET_PATH.test(
|
|
28533
|
+
if (EXTENSION_ASSET_PATH.test(path99)) {
|
|
28468
28534
|
return next();
|
|
28469
28535
|
}
|
|
28470
28536
|
const token = getCookie(c, COOKIE_NAME);
|
|
28471
28537
|
const payload = validateToken(token);
|
|
28472
28538
|
if (!payload) {
|
|
28473
|
-
if (!
|
|
28539
|
+
if (!path99.startsWith("/api/")) {
|
|
28474
28540
|
return next();
|
|
28475
28541
|
}
|
|
28476
28542
|
return c.json({ error: "Unauthorized" }, 401);
|
|
@@ -28524,14 +28590,14 @@ function createWebChannel(deps) {
|
|
|
28524
28590
|
return findActiveSessionId(sm, accountId, prefix, activeOverrides, "full") ?? void 0;
|
|
28525
28591
|
}
|
|
28526
28592
|
function resolveWorkspace(account, override, scaffold = true) {
|
|
28527
|
-
let
|
|
28593
|
+
let path99 = account.workspacePath;
|
|
28528
28594
|
if (override && override !== account.workspacePath) {
|
|
28529
28595
|
if (account.accessLevel !== "full") {
|
|
28530
28596
|
return { ok: false, error: "workspace override requires a full-access token" };
|
|
28531
28597
|
}
|
|
28532
|
-
|
|
28598
|
+
path99 = override;
|
|
28533
28599
|
}
|
|
28534
|
-
const resolved = scaffold ? resolveAccountWorkspace({ ...account, workspacePath:
|
|
28600
|
+
const resolved = scaffold ? resolveAccountWorkspace({ ...account, workspacePath: path99 }) : fs64.existsSync(path99) ? path99 : null;
|
|
28535
28601
|
if (!resolved)
|
|
28536
28602
|
return { ok: false, error: "workspace not found" };
|
|
28537
28603
|
return { ok: true, path: resolved };
|
|
@@ -32756,7 +32822,7 @@ function buildCard(workspace, interfaceUrl, caps) {
|
|
|
32756
32822
|
return {
|
|
32757
32823
|
name: raw.name,
|
|
32758
32824
|
description: raw.description,
|
|
32759
|
-
version: typeof raw.version === "string" ? raw.version : "2.2.
|
|
32825
|
+
version: typeof raw.version === "string" ? raw.version : "2.2.6",
|
|
32760
32826
|
supportedInterfaces: [{ url: interfaceUrl, protocolBinding: "JSONRPC", protocolVersion: A2A_VERSION }],
|
|
32761
32827
|
capabilities: { streaming: caps.streaming, pushNotifications: true, extendedAgentCard: false },
|
|
32762
32828
|
...caps.tokenAuth === false ? {} : {
|
|
@@ -34238,7 +34304,7 @@ async function finishRun(runId, db4, session) {
|
|
|
34238
34304
|
if (session.turnError) {
|
|
34239
34305
|
status = "failed";
|
|
34240
34306
|
failureReason = session.turnError.slice(0, 500);
|
|
34241
|
-
} else if (!
|
|
34307
|
+
} else if (!answer) {
|
|
34242
34308
|
status = "failed";
|
|
34243
34309
|
failureReason = "run produced no output (nothing to dispatch)";
|
|
34244
34310
|
}
|
|
@@ -34250,7 +34316,7 @@ async function finishRun(runId, db4, session) {
|
|
|
34250
34316
|
const targets = job ? parseTargets(job.targets) : [];
|
|
34251
34317
|
let dispatchResults = [];
|
|
34252
34318
|
if (job && status === "succeeded" && targets.length > 0) {
|
|
34253
|
-
dispatchResults = await dispatchToTargets(
|
|
34319
|
+
dispatchResults = await dispatchToTargets(answer, targets, row.workspacePath ?? job.workspacePath);
|
|
34254
34320
|
if (dispatchResults.length > 0 && dispatchResults.every((r) => !r.ok)) {
|
|
34255
34321
|
status = "failed";
|
|
34256
34322
|
failureReason = `all ${dispatchResults.length} target(s) failed: ${dispatchResults.map((r) => `${r.channelType}:${r.error ?? "?"}`).join("; ")}`;
|
|
@@ -35780,11 +35846,15 @@ function haloBaseVersion(haloVersion) {
|
|
|
35780
35846
|
return semver.valid(stripped) === stripped ? stripped : null;
|
|
35781
35847
|
}
|
|
35782
35848
|
function defaultHubBase(hubRepo) {
|
|
35849
|
+
const gh = githubHubRepo(hubRepo);
|
|
35850
|
+
return gh ? `https://raw.githubusercontent.com/${gh.owner}/${gh.repo}/main/extensions` : null;
|
|
35851
|
+
}
|
|
35852
|
+
function githubHubRepo(hubRepo) {
|
|
35783
35853
|
let h = hubRepo.trim();
|
|
35784
35854
|
if (h === "" || h.startsWith("{{"))
|
|
35785
35855
|
h = DEFAULT_HUB_REPO;
|
|
35786
35856
|
const m = /^(?:https:\/\/github\.com\/)?([A-Za-z0-9][A-Za-z0-9_.-]*)\/([A-Za-z0-9_.-]+?)(?:\.git)?\/?$/.exec(h);
|
|
35787
|
-
return m ?
|
|
35857
|
+
return m ? { owner: m[1], repo: m[2] } : null;
|
|
35788
35858
|
}
|
|
35789
35859
|
function updateJsonUrl(id, source, hubBase2) {
|
|
35790
35860
|
if (source)
|
|
@@ -35924,7 +35994,7 @@ function createCoreChecker(opts) {
|
|
|
35924
35994
|
}
|
|
35925
35995
|
function getCoreStatus(force) {
|
|
35926
35996
|
checker ??= createCoreChecker({
|
|
35927
|
-
haloVersion: "2.2.
|
|
35997
|
+
haloVersion: "2.2.6",
|
|
35928
35998
|
fetchLatest: fetchNpmLatest,
|
|
35929
35999
|
onChange: (status) => broadcast({ type: "updates:changed", scope: "core", status })
|
|
35930
36000
|
});
|
|
@@ -36092,7 +36162,7 @@ function hubBase() {
|
|
|
36092
36162
|
}
|
|
36093
36163
|
function serverChecker() {
|
|
36094
36164
|
checker2 ??= createExtensionsChecker({
|
|
36095
|
-
haloVersion: "2.2.
|
|
36165
|
+
haloVersion: "2.2.6",
|
|
36096
36166
|
installed: () => {
|
|
36097
36167
|
const s = getSnapshot();
|
|
36098
36168
|
return [...s.extensions, ...s.disabled];
|
|
@@ -36427,6 +36497,97 @@ var init_extensions = __esm({
|
|
|
36427
36497
|
}
|
|
36428
36498
|
});
|
|
36429
36499
|
|
|
36500
|
+
// ../server/dist/models/hub-update.js
|
|
36501
|
+
import fs80 from "node:fs";
|
|
36502
|
+
import os11 from "node:os";
|
|
36503
|
+
import path86 from "node:path";
|
|
36504
|
+
import JSZip3 from "jszip";
|
|
36505
|
+
function pickModelsRelease(releases) {
|
|
36506
|
+
if (!Array.isArray(releases))
|
|
36507
|
+
return null;
|
|
36508
|
+
for (const r of releases) {
|
|
36509
|
+
if (typeof r?.tag_name !== "string" || !/^models-v\d/.test(r.tag_name) || r.draft || r.prerelease)
|
|
36510
|
+
continue;
|
|
36511
|
+
const assets = Array.isArray(r.assets) ? r.assets : [];
|
|
36512
|
+
const zip = assets.find((a) => typeof a?.name === "string" && a.name.endsWith(".zip") && typeof a.browser_download_url === "string");
|
|
36513
|
+
if (zip)
|
|
36514
|
+
return { tag: r.tag_name, url: zip.browser_download_url };
|
|
36515
|
+
}
|
|
36516
|
+
return null;
|
|
36517
|
+
}
|
|
36518
|
+
async function unpackYamls(zipBuf, dest) {
|
|
36519
|
+
let zip;
|
|
36520
|
+
try {
|
|
36521
|
+
zip = await JSZip3.loadAsync(zipBuf);
|
|
36522
|
+
} catch (err) {
|
|
36523
|
+
throw new ModelsHubError(`release asset is not a zip: ${err instanceof Error ? err.message : String(err)}`);
|
|
36524
|
+
}
|
|
36525
|
+
const seen = /* @__PURE__ */ new Set();
|
|
36526
|
+
for (const entry of Object.values(zip.files)) {
|
|
36527
|
+
if (entry.dir)
|
|
36528
|
+
continue;
|
|
36529
|
+
const name = path86.posix.basename(entry.name.replace(/\\/g, "/"));
|
|
36530
|
+
if (!name.endsWith(".yaml") || name.startsWith("."))
|
|
36531
|
+
continue;
|
|
36532
|
+
if (seen.has(name))
|
|
36533
|
+
throw new ModelsHubError(`zip holds ${name} twice`);
|
|
36534
|
+
seen.add(name);
|
|
36535
|
+
fs80.writeFileSync(path86.join(dest, name), await entry.async("nodebuffer"));
|
|
36536
|
+
}
|
|
36537
|
+
}
|
|
36538
|
+
async function updateModelsFromHub(hubRepo, opts = {}) {
|
|
36539
|
+
const gh = githubHubRepo(hubRepo);
|
|
36540
|
+
if (!gh)
|
|
36541
|
+
throw new ModelsHubError(`not a GitHub hub: ${hubRepo}`);
|
|
36542
|
+
const hub = `${gh.owner}/${gh.repo}`;
|
|
36543
|
+
const api = `https://api.github.com/repos/${hub}/releases?per_page=100`;
|
|
36544
|
+
const res = await httpsGet(api, { maxBytes: RELEASES_MAX_BYTES, timeoutMs: RELEASES_TIMEOUT_MS, headers: { accept: "application/vnd.github+json" } });
|
|
36545
|
+
if (res.status !== 200)
|
|
36546
|
+
throw new ModelsHubError(`GitHub release API answered HTTP ${res.status} for ${hub} \u2014 rate-limited, private or wrong repo?`);
|
|
36547
|
+
let releases;
|
|
36548
|
+
try {
|
|
36549
|
+
releases = JSON.parse(res.body.toString("utf-8"));
|
|
36550
|
+
} catch {
|
|
36551
|
+
throw new ModelsHubError(`GitHub release API sent invalid JSON for ${hub}`);
|
|
36552
|
+
}
|
|
36553
|
+
const picked = pickModelsRelease(releases);
|
|
36554
|
+
if (!picked)
|
|
36555
|
+
throw new ModelsHubError(`no models-v* release with a .zip asset in ${hub}`);
|
|
36556
|
+
const zip = await httpsGet(picked.url, { maxBytes: ZIP_MAX_BYTES, timeoutMs: ZIP_TIMEOUT_MS, idleTimeoutMs: ZIP_IDLE_TIMEOUT_MS });
|
|
36557
|
+
if (zip.status !== 200)
|
|
36558
|
+
throw new ModelsHubError(`download of ${picked.tag} failed: HTTP ${zip.status}`);
|
|
36559
|
+
const tmp = fs80.mkdtempSync(path86.join(os11.tmpdir(), "halo-models-"));
|
|
36560
|
+
try {
|
|
36561
|
+
await unpackYamls(zip.body, tmp);
|
|
36562
|
+
let plan;
|
|
36563
|
+
try {
|
|
36564
|
+
plan = planModelsInstall(tmp, opts.dirs);
|
|
36565
|
+
} catch (err) {
|
|
36566
|
+
throw new ModelsHubError(`${picked.tag}: ${err instanceof Error ? err.message.replace(tmp, "the release zip") : String(err)}`);
|
|
36567
|
+
}
|
|
36568
|
+
const written = plan.needsConfirm && !opts.confirm ? null : applyModelsInstall(plan);
|
|
36569
|
+
return { hub, release: picked.tag, plan, written, summary: written ? summaryLine(plan, written) : null };
|
|
36570
|
+
} finally {
|
|
36571
|
+
fs80.rmSync(tmp, { recursive: true, force: true });
|
|
36572
|
+
}
|
|
36573
|
+
}
|
|
36574
|
+
var ModelsHubError, RELEASES_MAX_BYTES, ZIP_MAX_BYTES, RELEASES_TIMEOUT_MS, ZIP_TIMEOUT_MS, ZIP_IDLE_TIMEOUT_MS;
|
|
36575
|
+
var init_hub_update = __esm({
|
|
36576
|
+
"../server/dist/models/hub-update.js"() {
|
|
36577
|
+
"use strict";
|
|
36578
|
+
init_https_get();
|
|
36579
|
+
init_update_json();
|
|
36580
|
+
init_install();
|
|
36581
|
+
ModelsHubError = class extends Error {
|
|
36582
|
+
};
|
|
36583
|
+
RELEASES_MAX_BYTES = 2 * 1024 * 1024;
|
|
36584
|
+
ZIP_MAX_BYTES = 10 * 1024 * 1024;
|
|
36585
|
+
RELEASES_TIMEOUT_MS = 15e3;
|
|
36586
|
+
ZIP_TIMEOUT_MS = 6e4;
|
|
36587
|
+
ZIP_IDLE_TIMEOUT_MS = 2e4;
|
|
36588
|
+
}
|
|
36589
|
+
});
|
|
36590
|
+
|
|
36430
36591
|
// ../server/dist/routes/updates.js
|
|
36431
36592
|
import { Hono as Hono22 } from "hono";
|
|
36432
36593
|
function statusOf(scope, force) {
|
|
@@ -36447,20 +36608,55 @@ function createUpdateRoutes() {
|
|
|
36447
36608
|
const status = statusOf(body?.scope, true);
|
|
36448
36609
|
return status ? c.json(status) : c.json({ error: SCOPE_ERROR }, 400);
|
|
36449
36610
|
});
|
|
36611
|
+
app2.post("/models/update", async (c) => {
|
|
36612
|
+
const body = await c.req.json().catch(() => null);
|
|
36613
|
+
const hubRepo = getServerParam("extension", "hub_repo");
|
|
36614
|
+
if (!githubHubRepo(hubRepo)) {
|
|
36615
|
+
return c.json({ error: `Sync latest models supports GitHub hubs only (extension hub_repo is ${hubRepo}) \u2014 use /extension models in a chat, which also handles Gitea / Forgejo / GitLab` }, 400);
|
|
36616
|
+
}
|
|
36617
|
+
if (syncingModels)
|
|
36618
|
+
return c.json({ error: "A model sync is already running" }, 409);
|
|
36619
|
+
syncingModels = true;
|
|
36620
|
+
try {
|
|
36621
|
+
const r = await updateModelsFromHub(hubRepo, { confirm: body?.confirm === true });
|
|
36622
|
+
if (r.written)
|
|
36623
|
+
console.log(`[Models] synced ${r.hub} ${r.release}: ${r.summary}`);
|
|
36624
|
+
return c.json({
|
|
36625
|
+
hub: r.hub,
|
|
36626
|
+
release: r.release,
|
|
36627
|
+
needsConfirm: r.written === null,
|
|
36628
|
+
written: r.written ?? [],
|
|
36629
|
+
summary: r.summary,
|
|
36630
|
+
// `raw` (the yaml text) stays server-side.
|
|
36631
|
+
entries: r.plan.entries.map(({ raw: _raw, ...e }) => e)
|
|
36632
|
+
});
|
|
36633
|
+
} catch (err) {
|
|
36634
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
36635
|
+
console.log(`[Models] sync from ${hubRepo || "the default hub"} failed: ${msg}`);
|
|
36636
|
+
return c.json({ error: msg }, err instanceof ModelsHubError || err instanceof HttpsGetError ? 502 : 500);
|
|
36637
|
+
} finally {
|
|
36638
|
+
syncingModels = false;
|
|
36639
|
+
}
|
|
36640
|
+
});
|
|
36450
36641
|
return app2;
|
|
36451
36642
|
}
|
|
36452
|
-
var SCOPE_ERROR;
|
|
36643
|
+
var SCOPE_ERROR, syncingModels;
|
|
36453
36644
|
var init_updates = __esm({
|
|
36454
36645
|
"../server/dist/routes/updates.js"() {
|
|
36455
36646
|
"use strict";
|
|
36647
|
+
init_config();
|
|
36456
36648
|
init_core_check();
|
|
36457
36649
|
init_extension_check();
|
|
36650
|
+
init_update_json();
|
|
36651
|
+
init_https_get();
|
|
36652
|
+
init_hub_update();
|
|
36458
36653
|
SCOPE_ERROR = 'scope must be "core" or "extensions"';
|
|
36654
|
+
syncingModels = false;
|
|
36459
36655
|
}
|
|
36460
36656
|
});
|
|
36461
36657
|
|
|
36462
36658
|
// ../server/dist/models/watcher.js
|
|
36463
|
-
import
|
|
36659
|
+
import fs81 from "node:fs";
|
|
36464
36660
|
function snapshot2() {
|
|
36465
36661
|
const { effective } = loadProviders();
|
|
36466
36662
|
return {
|
|
@@ -36488,7 +36684,7 @@ function reloadAndBroadcast() {
|
|
|
36488
36684
|
}
|
|
36489
36685
|
function openWatcher2(root) {
|
|
36490
36686
|
try {
|
|
36491
|
-
watcher2 =
|
|
36687
|
+
watcher2 = fs81.watch(root, { persistent: false, recursive: false }, () => scheduleFlush2());
|
|
36492
36688
|
watcher2.on("error", (err) => {
|
|
36493
36689
|
console.warn(`[Models] watch error on ${root}: ${err.message} \u2014 retrying in 1s`);
|
|
36494
36690
|
closeWatcher2();
|
|
@@ -36514,7 +36710,7 @@ function start2() {
|
|
|
36514
36710
|
return;
|
|
36515
36711
|
const root = globalHubModelsDir();
|
|
36516
36712
|
try {
|
|
36517
|
-
|
|
36713
|
+
fs81.mkdirSync(root, { recursive: true });
|
|
36518
36714
|
} catch (err) {
|
|
36519
36715
|
console.warn(`[Models] cannot create ${root}: ${err instanceof Error ? err.message : String(err)}`);
|
|
36520
36716
|
}
|
|
@@ -36549,8 +36745,8 @@ var init_watcher2 = __esm({
|
|
|
36549
36745
|
});
|
|
36550
36746
|
|
|
36551
36747
|
// ../server/dist/evolution/notify.js
|
|
36552
|
-
import
|
|
36553
|
-
import
|
|
36748
|
+
import fs82 from "node:fs";
|
|
36749
|
+
import path87 from "node:path";
|
|
36554
36750
|
import { and as and18, eq as eq22, isNull as isNull7 } from "drizzle-orm";
|
|
36555
36751
|
function setEvoSessionRegistry(r) {
|
|
36556
36752
|
_registry4 = r;
|
|
@@ -36569,7 +36765,7 @@ function formatAutoAppliedNotice(input) {
|
|
|
36569
36765
|
}
|
|
36570
36766
|
function readJson(file) {
|
|
36571
36767
|
try {
|
|
36572
|
-
return JSON.parse(
|
|
36768
|
+
return JSON.parse(fs82.readFileSync(file, "utf-8"));
|
|
36573
36769
|
} catch {
|
|
36574
36770
|
return null;
|
|
36575
36771
|
}
|
|
@@ -36583,10 +36779,10 @@ function notifyAutoApplied(db4) {
|
|
|
36583
36779
|
try {
|
|
36584
36780
|
const runId = JSON.parse(a.sourceRunIds)[0];
|
|
36585
36781
|
const run = runId ? db4.select().from(evolutionRuns).where(eq22(evolutionRuns.id, runId)).get() : void 0;
|
|
36586
|
-
if (run &&
|
|
36782
|
+
if (run && fs82.existsSync(path87.join(a.workspacePath, ".halo"))) {
|
|
36587
36783
|
const sm = registry2.getOrCreate(a.workspacePath);
|
|
36588
36784
|
if (sm.getSessionById(run.sourceSession)) {
|
|
36589
|
-
const verdict2 = readJson(
|
|
36785
|
+
const verdict2 = readJson(path87.join(wsEvoRunDir(a.workspacePath, run.id), AUTO_APPLY_FILE));
|
|
36590
36786
|
sm.notifySystem(run.sourceSession, formatAutoAppliedNotice({
|
|
36591
36787
|
files: readPublishedFiles(a.workspacePath, a.id) ?? [],
|
|
36592
36788
|
avg: verdict2?.score?.avg ?? null,
|
|
@@ -36872,14 +37068,14 @@ var init_ticker = __esm({
|
|
|
36872
37068
|
});
|
|
36873
37069
|
|
|
36874
37070
|
// ../server/dist/evolution/spawn.js
|
|
36875
|
-
import
|
|
36876
|
-
import
|
|
37071
|
+
import fs83 from "node:fs";
|
|
37072
|
+
import path88 from "node:path";
|
|
36877
37073
|
import { spawn as spawn5 } from "node:child_process";
|
|
36878
37074
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
36879
37075
|
function spawnEvoWrapper(wrapperPath, mode, id) {
|
|
36880
|
-
|
|
37076
|
+
fs83.mkdirSync(evoLogsDir(), { recursive: true });
|
|
36881
37077
|
const logPath = mode === "run" ? evoWrapperLogFile(id) : evoApplyLogFile(id);
|
|
36882
|
-
const logFd =
|
|
37078
|
+
const logFd = fs83.openSync(logPath, "a");
|
|
36883
37079
|
let child;
|
|
36884
37080
|
try {
|
|
36885
37081
|
child = spawn5(process.execPath, [wrapperPath, `--mode=${mode}`, `--id=${id}`], {
|
|
@@ -36892,7 +37088,7 @@ function spawnEvoWrapper(wrapperPath, mode, id) {
|
|
|
36892
37088
|
windowsHide: true
|
|
36893
37089
|
});
|
|
36894
37090
|
} finally {
|
|
36895
|
-
|
|
37091
|
+
fs83.closeSync(logFd);
|
|
36896
37092
|
}
|
|
36897
37093
|
child.once("exit", (code, signal) => {
|
|
36898
37094
|
if (code === 0)
|
|
@@ -36909,8 +37105,8 @@ var init_spawn = __esm({
|
|
|
36909
37105
|
"use strict";
|
|
36910
37106
|
init_child_env();
|
|
36911
37107
|
init_paths();
|
|
36912
|
-
__dirname2 =
|
|
36913
|
-
WRAPPER_PATH =
|
|
37108
|
+
__dirname2 = path88.dirname(fileURLToPath2(import.meta.url));
|
|
37109
|
+
WRAPPER_PATH = path88.resolve(__dirname2, "evo-wrapper.js");
|
|
36914
37110
|
realEvoSpawner = (mode, id) => {
|
|
36915
37111
|
spawnEvoWrapper(WRAPPER_PATH, mode, id);
|
|
36916
37112
|
};
|
|
@@ -37730,12 +37926,12 @@ var init_handler3 = __esm({
|
|
|
37730
37926
|
});
|
|
37731
37927
|
|
|
37732
37928
|
// ../server/dist/routes/channel-accounts.js
|
|
37733
|
-
import
|
|
37929
|
+
import fs84 from "node:fs";
|
|
37734
37930
|
function accountListFields(a) {
|
|
37735
37931
|
return {
|
|
37736
37932
|
accountId: a.accountId,
|
|
37737
37933
|
workspacePath: a.workspacePath,
|
|
37738
|
-
workspaceMissing: !
|
|
37934
|
+
workspaceMissing: !fs84.existsSync(a.workspacePath),
|
|
37739
37935
|
label: a.label,
|
|
37740
37936
|
enabled: a.enabled,
|
|
37741
37937
|
accessLevel: a.accessLevel,
|
|
@@ -38377,8 +38573,8 @@ var init_cdn = __esm({
|
|
|
38377
38573
|
});
|
|
38378
38574
|
|
|
38379
38575
|
// ../server/dist/channels/wechat/send-media.js
|
|
38380
|
-
import
|
|
38381
|
-
import
|
|
38576
|
+
import fs85 from "node:fs/promises";
|
|
38577
|
+
import path89 from "node:path";
|
|
38382
38578
|
function inferKind(filePath) {
|
|
38383
38579
|
const cls = classifyMedia(filePath);
|
|
38384
38580
|
if (cls === "image")
|
|
@@ -38390,7 +38586,7 @@ function inferKind(filePath) {
|
|
|
38390
38586
|
async function sendMediaFile(params) {
|
|
38391
38587
|
const { baseUrl, token, toUserId, contextToken, contextTokenAt, filePath } = params;
|
|
38392
38588
|
const kind = params.kind ?? inferKind(filePath);
|
|
38393
|
-
const plaintext = await
|
|
38589
|
+
const plaintext = await fs85.readFile(filePath);
|
|
38394
38590
|
const prep = prepareUpload(plaintext);
|
|
38395
38591
|
console.log(`[WeChat] sendMediaFile: path=${filePath} kind=${kind} rawsize=${prep.rawsize} filesize=${prep.filesize}`);
|
|
38396
38592
|
const mediaType = kind === "image" ? UploadMediaType.IMAGE : kind === "video" ? UploadMediaType.VIDEO : UploadMediaType.FILE;
|
|
@@ -38428,7 +38624,7 @@ async function sendMediaFile(params) {
|
|
|
38428
38624
|
aesKeyBase64,
|
|
38429
38625
|
fileSizeCiphertext: prep.filesize,
|
|
38430
38626
|
fileSize: prep.rawsize,
|
|
38431
|
-
fileName:
|
|
38627
|
+
fileName: path89.basename(filePath)
|
|
38432
38628
|
});
|
|
38433
38629
|
const clientId = `halo-media-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
38434
38630
|
const body = {
|
|
@@ -38591,8 +38787,8 @@ var init_login = __esm({
|
|
|
38591
38787
|
});
|
|
38592
38788
|
|
|
38593
38789
|
// ../server/dist/channels/wechat/handler.js
|
|
38594
|
-
import
|
|
38595
|
-
import
|
|
38790
|
+
import fs86 from "node:fs";
|
|
38791
|
+
import path90 from "node:path";
|
|
38596
38792
|
import QRCode from "qrcode";
|
|
38597
38793
|
function wxRoute(fromUserId, contextToken, contextTokenAt) {
|
|
38598
38794
|
return (prev) => {
|
|
@@ -39013,7 +39209,7 @@ async function handleSlashCommand(args) {
|
|
|
39013
39209
|
await reply(login.message);
|
|
39014
39210
|
return true;
|
|
39015
39211
|
}
|
|
39016
|
-
const tmpPath =
|
|
39212
|
+
const tmpPath = path90.join(tempDir(), `halo-qr-${login.sessionKey}.png`);
|
|
39017
39213
|
await QRCode.toFile(tmpPath, login.qrcodeUrl, { width: 256, margin: 2 });
|
|
39018
39214
|
await sendMediaFile({
|
|
39019
39215
|
baseUrl: account.baseUrl,
|
|
@@ -39022,7 +39218,7 @@ async function handleSlashCommand(args) {
|
|
|
39022
39218
|
contextToken,
|
|
39023
39219
|
filePath: tmpPath
|
|
39024
39220
|
});
|
|
39025
|
-
await
|
|
39221
|
+
await fs86.promises.unlink(tmpPath).catch(() => {
|
|
39026
39222
|
});
|
|
39027
39223
|
await reply(t("wechat.qr_sent", lang, { level, path: account.workspacePath }));
|
|
39028
39224
|
waitLogin({ sessionKey: login.sessionKey }).then(async (result2) => {
|
|
@@ -39102,8 +39298,8 @@ var init_handler4 = __esm({
|
|
|
39102
39298
|
|
|
39103
39299
|
// ../server/dist/routes/wechat.js
|
|
39104
39300
|
import { Hono as Hono24 } from "hono";
|
|
39105
|
-
import
|
|
39106
|
-
import
|
|
39301
|
+
import path91 from "node:path";
|
|
39302
|
+
import fs87 from "node:fs";
|
|
39107
39303
|
function createWechatRoutes(deps) {
|
|
39108
39304
|
const { db: db4, channel } = deps;
|
|
39109
39305
|
const app2 = new Hono24();
|
|
@@ -39112,7 +39308,7 @@ function createWechatRoutes(deps) {
|
|
|
39112
39308
|
return {
|
|
39113
39309
|
...stripSecrets(acc),
|
|
39114
39310
|
workspacePath: acc.workspacePath,
|
|
39115
|
-
workspaceMissing: !
|
|
39311
|
+
workspaceMissing: !fs87.existsSync(acc.workspacePath)
|
|
39116
39312
|
};
|
|
39117
39313
|
});
|
|
39118
39314
|
return c.json({ accounts });
|
|
@@ -39128,7 +39324,7 @@ function createWechatRoutes(deps) {
|
|
|
39128
39324
|
return c.json({ error: "sessionKey required" }, 400);
|
|
39129
39325
|
if (!body.workspacePath)
|
|
39130
39326
|
return c.json({ error: "workspacePath required" }, 400);
|
|
39131
|
-
if (!
|
|
39327
|
+
if (!path91.isAbsolute(body.workspacePath))
|
|
39132
39328
|
return c.json({ error: "workspacePath must be absolute" }, 400);
|
|
39133
39329
|
const levelError = accessLevelError(body.accessLevel, CHAT_ACCESS_LEVELS);
|
|
39134
39330
|
if (levelError)
|
|
@@ -39341,7 +39537,7 @@ var init_descriptor2 = __esm({
|
|
|
39341
39537
|
import { Hono as Hono25 } from "hono";
|
|
39342
39538
|
import { streamSSE as streamSSE3 } from "hono/streaming";
|
|
39343
39539
|
import crypto15 from "node:crypto";
|
|
39344
|
-
import
|
|
39540
|
+
import fs88 from "node:fs";
|
|
39345
39541
|
function streamWithKeepalive(c, chunks) {
|
|
39346
39542
|
return streamSSE3(c, async (stream) => {
|
|
39347
39543
|
const timer2 = setInterval(() => {
|
|
@@ -39537,30 +39733,30 @@ function createWebRoutes(deps) {
|
|
|
39537
39733
|
const filePath = c.req.query("path");
|
|
39538
39734
|
if (!filePath)
|
|
39539
39735
|
return c.json({ error: "path required" }, 400);
|
|
39540
|
-
const
|
|
39541
|
-
const resolved =
|
|
39542
|
-
const root =
|
|
39543
|
-
if (resolved !== root && !resolved.startsWith(root +
|
|
39736
|
+
const path99 = await import("node:path");
|
|
39737
|
+
const resolved = path99.default.resolve(account.workspacePath, filePath);
|
|
39738
|
+
const root = path99.default.resolve(account.workspacePath);
|
|
39739
|
+
if (resolved !== root && !resolved.startsWith(root + path99.default.sep)) {
|
|
39544
39740
|
return c.json({ error: "path traversal not allowed" }, 403);
|
|
39545
39741
|
}
|
|
39546
39742
|
let real;
|
|
39547
39743
|
let realRoot;
|
|
39548
39744
|
try {
|
|
39549
|
-
real =
|
|
39550
|
-
realRoot =
|
|
39745
|
+
real = fs88.realpathSync(resolved);
|
|
39746
|
+
realRoot = fs88.realpathSync(root);
|
|
39551
39747
|
} catch {
|
|
39552
39748
|
return c.json({ error: "file not found" }, 404);
|
|
39553
39749
|
}
|
|
39554
|
-
if (real !== realRoot && !real.startsWith(realRoot +
|
|
39750
|
+
if (real !== realRoot && !real.startsWith(realRoot + path99.default.sep)) {
|
|
39555
39751
|
return c.json({ error: "path traversal not allowed" }, 403);
|
|
39556
39752
|
}
|
|
39557
39753
|
if (isHiddenWorkspacePath(real, realRoot)) {
|
|
39558
39754
|
return c.json({ error: "path is not accessible" }, 403);
|
|
39559
39755
|
}
|
|
39560
|
-
const stat =
|
|
39756
|
+
const stat = fs88.statSync(real);
|
|
39561
39757
|
if (stat.isDirectory())
|
|
39562
39758
|
return c.json({ error: "cannot serve directory" }, 400);
|
|
39563
|
-
const ext =
|
|
39759
|
+
const ext = path99.default.extname(real).toLowerCase();
|
|
39564
39760
|
const nonImageMimes = {
|
|
39565
39761
|
".mp4": "video/mp4",
|
|
39566
39762
|
".webm": "video/webm",
|
|
@@ -39568,8 +39764,8 @@ function createWebRoutes(deps) {
|
|
|
39568
39764
|
".txt": "text/plain"
|
|
39569
39765
|
};
|
|
39570
39766
|
const contentType = imageMimeFromExt(ext) || nonImageMimes[ext] || "application/octet-stream";
|
|
39571
|
-
const fileName =
|
|
39572
|
-
const data =
|
|
39767
|
+
const fileName = path99.default.basename(resolved);
|
|
39768
|
+
const data = fs88.readFileSync(real);
|
|
39573
39769
|
c.header("content-type", contentType);
|
|
39574
39770
|
c.header("content-disposition", `inline; filename="${fileName}"`);
|
|
39575
39771
|
return c.body(data);
|
|
@@ -39791,10 +39987,10 @@ async function authTest(botToken) {
|
|
|
39791
39987
|
return slackPost("auth.test", botToken, {});
|
|
39792
39988
|
}
|
|
39793
39989
|
async function uploadFile(args) {
|
|
39794
|
-
const
|
|
39795
|
-
const
|
|
39796
|
-
const filename = args.filename ??
|
|
39797
|
-
const stat =
|
|
39990
|
+
const fs93 = await import("node:fs");
|
|
39991
|
+
const path99 = await import("node:path");
|
|
39992
|
+
const filename = args.filename ?? path99.basename(args.filePath);
|
|
39993
|
+
const stat = fs93.statSync(args.filePath);
|
|
39798
39994
|
if (!stat.isFile())
|
|
39799
39995
|
throw new Error(`[slack:uploadFile] not a regular file: ${args.filePath}`);
|
|
39800
39996
|
const length = stat.size;
|
|
@@ -39812,7 +40008,7 @@ async function uploadFile(args) {
|
|
|
39812
40008
|
if (step1Parsed.ok === false || !step1Parsed.upload_url || !step1Parsed.file_id) {
|
|
39813
40009
|
throw new Error(`[slack:files.getUploadURLExternal] ${step1Parsed.error ?? "unknown"}`);
|
|
39814
40010
|
}
|
|
39815
|
-
const buf =
|
|
40011
|
+
const buf = fs93.readFileSync(args.filePath);
|
|
39816
40012
|
const step2 = await fetch(step1Parsed.upload_url, {
|
|
39817
40013
|
method: "POST",
|
|
39818
40014
|
body: buf
|
|
@@ -39957,7 +40153,7 @@ var init_api2 = __esm({
|
|
|
39957
40153
|
});
|
|
39958
40154
|
|
|
39959
40155
|
// ../server/dist/channels/slack/handler.js
|
|
39960
|
-
import
|
|
40156
|
+
import path92 from "node:path";
|
|
39961
40157
|
import { WebSocket as WebSocket3 } from "ws";
|
|
39962
40158
|
function slashToBang(text6, commandNames) {
|
|
39963
40159
|
if (commandNames.length === 0)
|
|
@@ -40088,7 +40284,7 @@ function startSlackChannel(deps) {
|
|
|
40088
40284
|
const route = bridge.getRoute(sessionId);
|
|
40089
40285
|
if (!account || !route)
|
|
40090
40286
|
return;
|
|
40091
|
-
const resolved =
|
|
40287
|
+
const resolved = path92.resolve(filePath);
|
|
40092
40288
|
await sendMediaOrReport({
|
|
40093
40289
|
filePath,
|
|
40094
40290
|
account,
|
|
@@ -40732,10 +40928,10 @@ async function replyMessage(args) {
|
|
|
40732
40928
|
return { message_id: parsed.data?.message_id ?? "" };
|
|
40733
40929
|
}
|
|
40734
40930
|
async function uploadImage(args) {
|
|
40735
|
-
const
|
|
40736
|
-
const
|
|
40737
|
-
const buf =
|
|
40738
|
-
const filename =
|
|
40931
|
+
const fs93 = await import("node:fs");
|
|
40932
|
+
const path99 = await import("node:path");
|
|
40933
|
+
const buf = fs93.readFileSync(args.filePath);
|
|
40934
|
+
const filename = path99.basename(args.filePath);
|
|
40739
40935
|
const send2 = async (token) => {
|
|
40740
40936
|
const form = new FormData();
|
|
40741
40937
|
form.append("image_type", "message");
|
|
@@ -40751,10 +40947,10 @@ async function uploadImage(args) {
|
|
|
40751
40947
|
return { imageKey: parsed.data.image_key };
|
|
40752
40948
|
}
|
|
40753
40949
|
async function uploadFile2(args) {
|
|
40754
|
-
const
|
|
40755
|
-
const
|
|
40756
|
-
const buf =
|
|
40757
|
-
const filename = args.filename ??
|
|
40950
|
+
const fs93 = await import("node:fs");
|
|
40951
|
+
const path99 = await import("node:path");
|
|
40952
|
+
const buf = fs93.readFileSync(args.filePath);
|
|
40953
|
+
const filename = args.filename ?? path99.basename(args.filePath);
|
|
40758
40954
|
const send2 = async (token) => {
|
|
40759
40955
|
const form = new FormData();
|
|
40760
40956
|
form.append("file_type", args.fileType);
|
|
@@ -40821,8 +41017,7 @@ var init_api3 = __esm({
|
|
|
40821
41017
|
});
|
|
40822
41018
|
|
|
40823
41019
|
// ../server/dist/channels/feishu/handler.js
|
|
40824
|
-
import
|
|
40825
|
-
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
41020
|
+
import path93 from "node:path";
|
|
40826
41021
|
function buildSessionPrefixForThread2(chatId, rootId) {
|
|
40827
41022
|
return sessionPrefix("feishu", `${chatId}:${rootId}`);
|
|
40828
41023
|
}
|
|
@@ -41024,7 +41219,7 @@ function startFeishuChannel(deps) {
|
|
|
41024
41219
|
const route = bridge.getRoute(sessionId);
|
|
41025
41220
|
if (!account || !route)
|
|
41026
41221
|
return;
|
|
41027
|
-
const resolved =
|
|
41222
|
+
const resolved = path93.resolve(filePath);
|
|
41028
41223
|
await sendMediaOrReport({
|
|
41029
41224
|
filePath,
|
|
41030
41225
|
account,
|
|
@@ -41069,13 +41264,16 @@ function startFeishuChannel(deps) {
|
|
|
41069
41264
|
const state = ensureState(accountId);
|
|
41070
41265
|
if (state.stopped || state.wsClient)
|
|
41071
41266
|
return;
|
|
41072
|
-
const
|
|
41267
|
+
const { WSClient: WSClient2, EventDispatcher, LoggerLevel } = await import("./feishu-sdk.cjs");
|
|
41268
|
+
if (state.stopped || state.wsClient)
|
|
41269
|
+
return;
|
|
41270
|
+
const wsClient = new WSClient2({
|
|
41073
41271
|
appId: account.appId,
|
|
41074
41272
|
appSecret: account.appSecret,
|
|
41075
|
-
loggerLevel:
|
|
41273
|
+
loggerLevel: LoggerLevel.warn
|
|
41076
41274
|
});
|
|
41077
41275
|
state.wsClient = wsClient;
|
|
41078
|
-
const dispatcher = new
|
|
41276
|
+
const dispatcher = new EventDispatcher({});
|
|
41079
41277
|
dispatcher.register({
|
|
41080
41278
|
"im.message.receive_v1": async (data) => {
|
|
41081
41279
|
dispatchEvent(accountId, data);
|
|
@@ -41191,7 +41389,7 @@ async function replyToInbound(args) {
|
|
|
41191
41389
|
async function sendFeishuMedia(args) {
|
|
41192
41390
|
const { account, inboundMessageId, isP2P, chatId, filePath } = args;
|
|
41193
41391
|
const cls = classifyMedia(filePath);
|
|
41194
|
-
const ext =
|
|
41392
|
+
const ext = path93.extname(filePath).toLowerCase();
|
|
41195
41393
|
if (cls === "image") {
|
|
41196
41394
|
const { imageKey } = await uploadImage({ appId: account.appId, appSecret: account.appSecret, filePath });
|
|
41197
41395
|
await replyToInboundRaw({
|
|
@@ -41586,9 +41784,9 @@ var init_event_adapter5 = __esm({
|
|
|
41586
41784
|
});
|
|
41587
41785
|
|
|
41588
41786
|
// ../server/dist/channels/wecom/handler.js
|
|
41589
|
-
import
|
|
41590
|
-
import
|
|
41591
|
-
import { WSClient
|
|
41787
|
+
import path94 from "node:path";
|
|
41788
|
+
import fs89 from "node:fs/promises";
|
|
41789
|
+
import { WSClient, generateReqId } from "@wecom/aibot-node-sdk";
|
|
41592
41790
|
function pickConversation(body) {
|
|
41593
41791
|
const userid = body.from?.userid ?? "unknown";
|
|
41594
41792
|
if (body.chattype === "group" && body.chatid) {
|
|
@@ -41710,13 +41908,13 @@ async function replyText(wsClient, route, text6) {
|
|
|
41710
41908
|
}
|
|
41711
41909
|
async function sendWecomMedia(args) {
|
|
41712
41910
|
const { wsClient, route, filePath } = args;
|
|
41713
|
-
const ext =
|
|
41911
|
+
const ext = path94.extname(filePath).toLowerCase();
|
|
41714
41912
|
const cls = classifyMedia(filePath);
|
|
41715
41913
|
const type = cls === "image" && [".png", ".jpg", ".jpeg", ".gif"].includes(ext) ? "image" : cls === "video" && ext === ".mp4" ? "video" : "file";
|
|
41716
|
-
const buf = await
|
|
41914
|
+
const buf = await fs89.readFile(filePath);
|
|
41717
41915
|
if (buf.length > MAX_WECOM_DOWNLOAD_BYTES)
|
|
41718
41916
|
throw new Error("file exceeds 20MB");
|
|
41719
|
-
const { media_id: mediaId } = await wsClient.uploadMedia(buf, { type, filename:
|
|
41917
|
+
const { media_id: mediaId } = await wsClient.uploadMedia(buf, { type, filename: path94.basename(filePath) });
|
|
41720
41918
|
if (route.reqId)
|
|
41721
41919
|
await wsClient.replyMedia({ headers: { req_id: route.reqId } }, type, mediaId);
|
|
41722
41920
|
else
|
|
@@ -41761,7 +41959,7 @@ function startWecomChannel(deps) {
|
|
|
41761
41959
|
const wsClient = states.get(accountId)?.wsClient;
|
|
41762
41960
|
if (!account || !route || !wsClient)
|
|
41763
41961
|
return;
|
|
41764
|
-
const resolved =
|
|
41962
|
+
const resolved = path94.resolve(filePath);
|
|
41765
41963
|
await sendMediaOrReport({
|
|
41766
41964
|
filePath,
|
|
41767
41965
|
account,
|
|
@@ -41820,7 +42018,7 @@ function startWecomChannel(deps) {
|
|
|
41820
42018
|
const state = ensureState(accountId);
|
|
41821
42019
|
if (state.stopped || state.wsClient)
|
|
41822
42020
|
return;
|
|
41823
|
-
const wsClient = new
|
|
42021
|
+
const wsClient = new WSClient({
|
|
41824
42022
|
botId: account.botId,
|
|
41825
42023
|
secret: account.secret,
|
|
41826
42024
|
maxReconnectAttempts: -1,
|
|
@@ -42249,17 +42447,17 @@ import { cors } from "hono/cors";
|
|
|
42249
42447
|
import { serve } from "@hono/node-server";
|
|
42250
42448
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
42251
42449
|
import { WebSocketServer as WebSocketServer5 } from "ws";
|
|
42252
|
-
import
|
|
42253
|
-
import
|
|
42450
|
+
import path95 from "node:path";
|
|
42451
|
+
import fs90 from "node:fs";
|
|
42254
42452
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
42255
42453
|
import { homedir as homedir26 } from "node:os";
|
|
42256
42454
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
42257
42455
|
function findProjectRoot() {
|
|
42258
42456
|
let dir = process.cwd();
|
|
42259
42457
|
for (let i = 0; i < 32; i++) {
|
|
42260
|
-
if (
|
|
42458
|
+
if (fs90.existsSync(path95.join(dir, "pnpm-workspace.yaml")))
|
|
42261
42459
|
return dir;
|
|
42262
|
-
const parent =
|
|
42460
|
+
const parent = path95.dirname(dir);
|
|
42263
42461
|
if (parent === dir)
|
|
42264
42462
|
break;
|
|
42265
42463
|
dir = parent;
|
|
@@ -42269,15 +42467,15 @@ function findProjectRoot() {
|
|
|
42269
42467
|
return process.cwd();
|
|
42270
42468
|
}
|
|
42271
42469
|
function acquireSingleInstanceLock(lockFile) {
|
|
42272
|
-
|
|
42273
|
-
const fd =
|
|
42470
|
+
fs90.mkdirSync(path95.dirname(lockFile), { recursive: true });
|
|
42471
|
+
const fd = fs90.openSync(lockFile, fs90.constants.O_RDWR | fs90.constants.O_CREAT, 420);
|
|
42274
42472
|
const result = spawnSync4("flock", ["-n", "3"], {
|
|
42275
42473
|
stdio: ["ignore", "ignore", "ignore", fd]
|
|
42276
42474
|
});
|
|
42277
42475
|
if (result.error) {
|
|
42278
42476
|
const content = readLockPid(fd);
|
|
42279
42477
|
if (content > 0 && isProcessAlive(content)) {
|
|
42280
|
-
|
|
42478
|
+
fs90.closeSync(fd);
|
|
42281
42479
|
console.error(`[Server] another halo server is already running (pid ${content}). kill it first.`);
|
|
42282
42480
|
process.exit(1);
|
|
42283
42481
|
}
|
|
@@ -42286,19 +42484,19 @@ function acquireSingleInstanceLock(lockFile) {
|
|
|
42286
42484
|
if (content > 0 && !isProcessAlive(content)) {
|
|
42287
42485
|
console.warn(`[Server] removing stale server.lock (pid ${content} not running)`);
|
|
42288
42486
|
} else {
|
|
42289
|
-
|
|
42487
|
+
fs90.closeSync(fd);
|
|
42290
42488
|
console.error(`[Server] another halo server is already running${content > 0 ? ` (pid ${content})` : ""}. kill it first.`);
|
|
42291
42489
|
process.exit(1);
|
|
42292
42490
|
}
|
|
42293
42491
|
}
|
|
42294
|
-
|
|
42295
|
-
|
|
42296
|
-
|
|
42492
|
+
fs90.ftruncateSync(fd);
|
|
42493
|
+
fs90.writeSync(fd, String(process.pid));
|
|
42494
|
+
fs90.fsyncSync(fd);
|
|
42297
42495
|
}
|
|
42298
42496
|
function readLockPid(fd) {
|
|
42299
42497
|
try {
|
|
42300
42498
|
const buf = Buffer.alloc(32);
|
|
42301
|
-
const n =
|
|
42499
|
+
const n = fs90.readSync(fd, buf, 0, 32, 0);
|
|
42302
42500
|
return parseInt(buf.subarray(0, n).toString("utf-8").trim(), 10) || 0;
|
|
42303
42501
|
} catch {
|
|
42304
42502
|
return 0;
|
|
@@ -42326,7 +42524,7 @@ function isProcessAlive(pid) {
|
|
|
42326
42524
|
}
|
|
42327
42525
|
}
|
|
42328
42526
|
function readGitSha() {
|
|
42329
|
-
if (!
|
|
42527
|
+
if (!fs90.existsSync(path95.join(PROJECT_ROOT, "pnpm-workspace.yaml")) || !fs90.existsSync(path95.join(PROJECT_ROOT, ".git")))
|
|
42330
42528
|
return null;
|
|
42331
42529
|
try {
|
|
42332
42530
|
const rev = spawnSync4("git", ["rev-parse", "--short", "HEAD"], { cwd: PROJECT_ROOT, encoding: "utf-8" });
|
|
@@ -42347,14 +42545,14 @@ function applySandboxPaths() {
|
|
|
42347
42545
|
}
|
|
42348
42546
|
function resolveFrontendDir() {
|
|
42349
42547
|
if (process.env.HALO_FRONTEND_DIR)
|
|
42350
|
-
return
|
|
42351
|
-
const bundled =
|
|
42352
|
-
if (
|
|
42548
|
+
return path95.resolve(process.env.HALO_FRONTEND_DIR);
|
|
42549
|
+
const bundled = path95.resolve(__dirname3, "..", "admin-out");
|
|
42550
|
+
if (fs90.existsSync(path95.join(bundled, "index.html")))
|
|
42353
42551
|
return bundled;
|
|
42354
|
-
const sibling =
|
|
42355
|
-
if (
|
|
42552
|
+
const sibling = path95.resolve(__dirname3, "..", "..", "admin", "out");
|
|
42553
|
+
if (fs90.existsSync(path95.join(sibling, "index.html")))
|
|
42356
42554
|
return sibling;
|
|
42357
|
-
return
|
|
42555
|
+
return path95.resolve(PROJECT_ROOT, "packages", "admin", "out");
|
|
42358
42556
|
}
|
|
42359
42557
|
async function gracefulShutdown(signal) {
|
|
42360
42558
|
beginShutdown();
|
|
@@ -42461,13 +42659,13 @@ var init_dist2 = __esm({
|
|
|
42461
42659
|
init_sandbox();
|
|
42462
42660
|
init_init();
|
|
42463
42661
|
init_git_ssh();
|
|
42464
|
-
__dirname3 =
|
|
42662
|
+
__dirname3 = path95.dirname(fileURLToPath3(import.meta.url));
|
|
42465
42663
|
PORT = config.server.port;
|
|
42466
|
-
HALO_VERSION = "2.2.
|
|
42664
|
+
HALO_VERSION = "2.2.6";
|
|
42467
42665
|
PROJECT_ROOT = findProjectRoot();
|
|
42468
|
-
HALO_HOME4 =
|
|
42666
|
+
HALO_HOME4 = path95.join(homedir26(), ".halo");
|
|
42469
42667
|
GIT_SHA = readGitSha();
|
|
42470
|
-
if (!
|
|
42668
|
+
if (!fs90.existsSync(path95.join(HALO_HOME4, "global", ".template-version"))) {
|
|
42471
42669
|
process.stderr.write("\x1B[31m[Server] ~/.halo/global/ not initialized. Run `halo setup` first.\x1B[0m\n");
|
|
42472
42670
|
process.exit(1);
|
|
42473
42671
|
}
|
|
@@ -42478,7 +42676,7 @@ var init_dist2 = __esm({
|
|
|
42478
42676
|
process.exit(1);
|
|
42479
42677
|
}
|
|
42480
42678
|
if (!AGENTCORE)
|
|
42481
|
-
acquireSingleInstanceLock(
|
|
42679
|
+
acquireSingleInstanceLock(path95.join(HALO_HOME4, "global", "server.lock"));
|
|
42482
42680
|
commandRegistry.assertDispatchCommands(DISPATCH_COMMANDS);
|
|
42483
42681
|
await initObservability();
|
|
42484
42682
|
initLogger();
|
|
@@ -42549,14 +42747,14 @@ var init_dist2 = __esm({
|
|
|
42549
42747
|
app.route("/api", createJupyterRoutes(jupyter));
|
|
42550
42748
|
}
|
|
42551
42749
|
start2();
|
|
42552
|
-
channelDb = createChannelDb(
|
|
42750
|
+
channelDb = createChannelDb(path95.join(HALO_HOME4, "secrets"));
|
|
42553
42751
|
setChannelDb(channelDb);
|
|
42554
42752
|
nodeHub = AGENTCORE ? null : createNodeHub({ db: channelDb });
|
|
42555
42753
|
setNodeHub(nodeHub);
|
|
42556
|
-
setEvoDb(createEvoDb(
|
|
42557
|
-
setCronDb(createCronDb(
|
|
42754
|
+
setEvoDb(createEvoDb(path95.join(HALO_HOME4, "global")));
|
|
42755
|
+
setCronDb(createCronDb(path95.join(HALO_HOME4, "global")));
|
|
42558
42756
|
if (!AGENTCORE)
|
|
42559
|
-
setRunsDb(createRunsDb(
|
|
42757
|
+
setRunsDb(createRunsDb(path95.join(HALO_HOME4, "global")));
|
|
42560
42758
|
setEvoSpawner(realEvoSpawner);
|
|
42561
42759
|
if (!AGENTCORE) {
|
|
42562
42760
|
startEvoTicker();
|
|
@@ -42572,7 +42770,7 @@ var init_dist2 = __esm({
|
|
|
42572
42770
|
setEvoSessionRegistry(registry);
|
|
42573
42771
|
if (OWNS_RUNTIMES && !AGENTCORE) {
|
|
42574
42772
|
for (const ws of listRunningWorkspaces()) {
|
|
42575
|
-
if (!
|
|
42773
|
+
if (!fs90.existsSync(path95.join(ws, ".halo")))
|
|
42576
42774
|
continue;
|
|
42577
42775
|
if (!claimWorkspaceRuntime(ws))
|
|
42578
42776
|
continue;
|
|
@@ -42600,7 +42798,7 @@ var init_dist2 = __esm({
|
|
|
42600
42798
|
startCronDaemon();
|
|
42601
42799
|
}
|
|
42602
42800
|
if (!AGENTCORE) {
|
|
42603
|
-
setA2ADb(createA2ADb(
|
|
42801
|
+
setA2ADb(createA2ADb(path95.join(HALO_HOME4, "global")));
|
|
42604
42802
|
setA2AOutboundRegistry(registry);
|
|
42605
42803
|
app.route("/a2a", createA2ARoutes({ registry, ownsRuntimes: OWNS_RUNTIMES }));
|
|
42606
42804
|
app.route("/", createA2APushRoutes());
|
|
@@ -42617,7 +42815,7 @@ var init_dist2 = __esm({
|
|
|
42617
42815
|
FRONTEND_DIR = resolveFrontendDir();
|
|
42618
42816
|
if (!AGENTCORE) {
|
|
42619
42817
|
app.use("/*", serveStatic({
|
|
42620
|
-
root:
|
|
42818
|
+
root: path95.relative(process.cwd(), FRONTEND_DIR),
|
|
42621
42819
|
// Next's `/_next/static/` files are content-hashed (under a buildId dir),
|
|
42622
42820
|
// so they can be cached forever. Only on a found file — the SPA fallback
|
|
42623
42821
|
// below must stay uncached, or a missing chunk caches index.html as js.
|
|
@@ -42631,9 +42829,9 @@ var init_dist2 = __esm({
|
|
|
42631
42829
|
app.get("/*", (c) => {
|
|
42632
42830
|
if (c.req.path.startsWith("/_next/static/"))
|
|
42633
42831
|
return c.notFound();
|
|
42634
|
-
const indexPath =
|
|
42832
|
+
const indexPath = path95.join(FRONTEND_DIR, "index.html");
|
|
42635
42833
|
try {
|
|
42636
|
-
const html =
|
|
42834
|
+
const html = fs90.readFileSync(indexPath, "utf-8");
|
|
42637
42835
|
return c.html(html);
|
|
42638
42836
|
} catch {
|
|
42639
42837
|
return c.text("Frontend not built. Run: cd packages/admin && npx next build", 503);
|
|
@@ -42724,10 +42922,10 @@ __export(agentcore_front_exports, {
|
|
|
42724
42922
|
workerEnv: () => workerEnv
|
|
42725
42923
|
});
|
|
42726
42924
|
import http3 from "node:http";
|
|
42727
|
-
import
|
|
42925
|
+
import fs91 from "node:fs";
|
|
42728
42926
|
import fsp2 from "node:fs/promises";
|
|
42729
|
-
import
|
|
42730
|
-
import
|
|
42927
|
+
import os12 from "node:os";
|
|
42928
|
+
import path96 from "node:path";
|
|
42731
42929
|
import crypto16 from "node:crypto";
|
|
42732
42930
|
import { pipeline as pipeline2 } from "node:stream";
|
|
42733
42931
|
import { execFile as execFile2, spawn as spawn6 } from "node:child_process";
|
|
@@ -42750,44 +42948,44 @@ function mountLayers(dir, mountinfo) {
|
|
|
42750
42948
|
}).length;
|
|
42751
42949
|
}
|
|
42752
42950
|
function skipTemplateEntry(rel) {
|
|
42753
|
-
const name =
|
|
42754
|
-
return rel ===
|
|
42951
|
+
const name = path96.basename(rel);
|
|
42952
|
+
return rel === path96.join(".halo", "sessions") || /\.db(-wal|-shm|-journal)?$/.test(name) || name === "runtime.lock" || name.startsWith("agentcore.lease");
|
|
42755
42953
|
}
|
|
42756
42954
|
function chownTree(dir, owner, sid) {
|
|
42757
42955
|
try {
|
|
42758
|
-
|
|
42759
|
-
for (const rel of
|
|
42760
|
-
|
|
42956
|
+
fs91.lchownSync(dir, owner.uid, owner.gid);
|
|
42957
|
+
for (const rel of fs91.readdirSync(dir, { recursive: true }))
|
|
42958
|
+
fs91.lchownSync(path96.join(dir, rel), owner.uid, owner.gid);
|
|
42761
42959
|
} catch (err) {
|
|
42762
42960
|
console.warn(`[AgentCore] front: chown ${sid} to ${owner.uid}:${owner.gid} failed (${err.message}) \u2014 serving it as is`);
|
|
42763
42961
|
}
|
|
42764
42962
|
}
|
|
42765
42963
|
function ensureSessionDir(base, sid, owner) {
|
|
42766
|
-
const dir =
|
|
42767
|
-
if (
|
|
42964
|
+
const dir = path96.join(base, sid);
|
|
42965
|
+
if (fs91.existsSync(dir))
|
|
42768
42966
|
return false;
|
|
42769
|
-
const tmp =
|
|
42770
|
-
|
|
42967
|
+
const tmp = path96.join(base, `.tmp-${crypto16.randomBytes(8).toString("hex")}`);
|
|
42968
|
+
fs91.mkdirSync(tmp, { mode: 448 });
|
|
42771
42969
|
try {
|
|
42772
|
-
const template =
|
|
42773
|
-
if (
|
|
42774
|
-
|
|
42970
|
+
const template = path96.join(base, TEMPLATE_DIR);
|
|
42971
|
+
if (fs91.statSync(template, { throwIfNoEntry: false })?.isDirectory()) {
|
|
42972
|
+
fs91.cpSync(template, tmp, { recursive: true, verbatimSymlinks: true, filter: (src) => !skipTemplateEntry(path96.relative(template, src)) });
|
|
42775
42973
|
}
|
|
42776
42974
|
if (owner)
|
|
42777
42975
|
chownTree(tmp, owner, sid);
|
|
42778
|
-
if (
|
|
42779
|
-
|
|
42780
|
-
|
|
42976
|
+
if (fs91.readdirSync(tmp).length === 0) {
|
|
42977
|
+
fs91.rmdirSync(tmp);
|
|
42978
|
+
fs91.mkdirSync(dir, { mode: 448 });
|
|
42781
42979
|
if (owner)
|
|
42782
42980
|
chownTree(dir, owner, sid);
|
|
42783
42981
|
return true;
|
|
42784
42982
|
}
|
|
42785
|
-
|
|
42983
|
+
fs91.renameSync(tmp, dir);
|
|
42786
42984
|
return true;
|
|
42787
42985
|
} catch (err) {
|
|
42788
|
-
|
|
42986
|
+
fs91.rmSync(tmp, { recursive: true, force: true });
|
|
42789
42987
|
const code = err.code;
|
|
42790
|
-
if ((code === "EEXIST" || code === "ENOTEMPTY") &&
|
|
42988
|
+
if ((code === "EEXIST" || code === "ENOTEMPTY") && fs91.existsSync(dir))
|
|
42791
42989
|
return false;
|
|
42792
42990
|
throw err;
|
|
42793
42991
|
}
|
|
@@ -42831,7 +43029,7 @@ async function runViewSetup(base, sessionDir, deps = SYSTEM_SETUP) {
|
|
|
42831
43029
|
const left = mountLayers(base, deps.mountinfo());
|
|
42832
43030
|
if (left > 0)
|
|
42833
43031
|
throw new Error(`view setup: ${base} still has ${left} mount(s) after ${MAX_UMOUNTS} \xD7 umount -l`);
|
|
42834
|
-
if (
|
|
43032
|
+
if (fs91.existsSync(sessionDir))
|
|
42835
43033
|
throw new Error(`view setup: ${base} is still visible after umount -l`);
|
|
42836
43034
|
}
|
|
42837
43035
|
function workerEnv(src, front) {
|
|
@@ -42846,19 +43044,19 @@ function workerEnv(src, front) {
|
|
|
42846
43044
|
return env;
|
|
42847
43045
|
}
|
|
42848
43046
|
async function copyMediaFile(p, root, dest, max = MAX_MEDIA_BYTES) {
|
|
42849
|
-
if (!
|
|
43047
|
+
if (!path96.isAbsolute(p))
|
|
42850
43048
|
return "not an absolute path";
|
|
42851
43049
|
let pfd;
|
|
42852
43050
|
try {
|
|
42853
|
-
pfd =
|
|
43051
|
+
pfd = fs91.openSync(p, O_PATH);
|
|
42854
43052
|
} catch (err) {
|
|
42855
43053
|
return `cannot open (${err.code})`;
|
|
42856
43054
|
}
|
|
42857
43055
|
try {
|
|
42858
|
-
const link =
|
|
43056
|
+
const link = fs91.readlinkSync(`/proc/self/fd/${pfd}`);
|
|
42859
43057
|
if (!link.startsWith(`${root}/`))
|
|
42860
43058
|
return `not under ${root}/`;
|
|
42861
|
-
const st =
|
|
43059
|
+
const st = fs91.fstatSync(pfd);
|
|
42862
43060
|
if (!st.isFile())
|
|
42863
43061
|
return "not a regular file";
|
|
42864
43062
|
if (st.size > max)
|
|
@@ -42885,7 +43083,7 @@ async function copyMediaFile(p, root, dest, max = MAX_MEDIA_BYTES) {
|
|
|
42885
43083
|
await src.close();
|
|
42886
43084
|
}
|
|
42887
43085
|
} finally {
|
|
42888
|
-
|
|
43086
|
+
fs91.closeSync(pfd);
|
|
42889
43087
|
}
|
|
42890
43088
|
}
|
|
42891
43089
|
async function copyMediaLines(text6, root, dir, sid) {
|
|
@@ -42897,16 +43095,16 @@ async function copyMediaLines(text6, root, dir, sid) {
|
|
|
42897
43095
|
out.push(line);
|
|
42898
43096
|
continue;
|
|
42899
43097
|
}
|
|
42900
|
-
const sub =
|
|
42901
|
-
|
|
42902
|
-
const name =
|
|
42903
|
-
const dest =
|
|
43098
|
+
const sub = path96.join(dir, String(n++));
|
|
43099
|
+
fs91.mkdirSync(sub);
|
|
43100
|
+
const name = path96.basename(m[1]).replace(/[\x00-\x1f\x7f]/g, "_").replace(/^\.+/, "") || "file";
|
|
43101
|
+
const dest = path96.join(sub, name);
|
|
42904
43102
|
const why = await copyMediaFile(m[1], root, dest).catch((err) => err.message);
|
|
42905
43103
|
if (why === null) {
|
|
42906
43104
|
out.push(`MEDIA:${dest}`);
|
|
42907
43105
|
continue;
|
|
42908
43106
|
}
|
|
42909
|
-
|
|
43107
|
+
fs91.rmSync(sub, { recursive: true, force: true });
|
|
42910
43108
|
console.warn(`[AgentCore] notify ${sid}: MEDIA dropped (${why}): ${JSON.stringify(m[1].slice(0, 300))}`);
|
|
42911
43109
|
}
|
|
42912
43110
|
return out.join("\n");
|
|
@@ -42950,7 +43148,7 @@ function readBody(req, max) {
|
|
|
42950
43148
|
});
|
|
42951
43149
|
}
|
|
42952
43150
|
async function startAgentCoreFront(o) {
|
|
42953
|
-
const base =
|
|
43151
|
+
const base = fs91.realpathSync(o.base);
|
|
42954
43152
|
const workerPort = o.workerPort ?? WORKER_PORT;
|
|
42955
43153
|
const token = crypto16.randomBytes(32).toString("hex");
|
|
42956
43154
|
const isMounted = o.isMounted ?? ((b) => mountLayers(b, readMountinfo()) > 0);
|
|
@@ -43012,11 +43210,11 @@ async function startAgentCoreFront(o) {
|
|
|
43012
43210
|
preparing++;
|
|
43013
43211
|
let dir = "";
|
|
43014
43212
|
const cleanup = () => {
|
|
43015
|
-
|
|
43213
|
+
fs91.rmSync(dir, { recursive: true, force: true });
|
|
43016
43214
|
settle();
|
|
43017
43215
|
};
|
|
43018
43216
|
try {
|
|
43019
|
-
dir =
|
|
43217
|
+
dir = fs91.mkdtempSync(path96.join(os12.tmpdir(), "halo-notify-"));
|
|
43020
43218
|
const text6 = await copyMediaLines(b.text, viewRoot, dir, b.session);
|
|
43021
43219
|
runNotify(cmd, text6, { HALO_SESSION_ID: b.session, HALO_RUN_STATUS: b.status, HALO_WORKSPACE: dir }, dir, cleanup);
|
|
43022
43220
|
} catch (err) {
|
|
@@ -43031,7 +43229,7 @@ async function startAgentCoreFront(o) {
|
|
|
43031
43229
|
const activate = async (sid) => {
|
|
43032
43230
|
if (!isMounted(base))
|
|
43033
43231
|
throw Object.assign(new Error(`${base} is not a mount point (the EFS not mounted yet, or HALO_WORKSPACE is not its mount path) \u2014 refusing to serve the image's empty dir`), { status: 503 });
|
|
43034
|
-
const sessionDir =
|
|
43232
|
+
const sessionDir = path96.join(base, sid);
|
|
43035
43233
|
if (ensureSessionDir(base, sid, { uid: WORKER_UID, gid: WORKER_GID }))
|
|
43036
43234
|
console.log(`[AgentCore] front: created ${sessionDir}`);
|
|
43037
43235
|
try {
|
|
@@ -43186,7 +43384,7 @@ async function runAgentCoreFront(o) {
|
|
|
43186
43384
|
throw new Error("HALO_AGENTCORE_SESSION_DIRS=1 needs root (bind mount, umount); the worker drops to an unprivileged uid itself");
|
|
43187
43385
|
if (o.port === WORKER_PORT)
|
|
43188
43386
|
throw new Error(`port ${WORKER_PORT} is the worker's loopback port \u2014 pick another HALO_PORT`);
|
|
43189
|
-
const base =
|
|
43387
|
+
const base = path96.resolve(o.base);
|
|
43190
43388
|
const overlaps = (a, b) => a === b || a.startsWith(b === "/" ? "/" : `${b}/`);
|
|
43191
43389
|
if (overlaps(WORKER_ROOT, base) || overlaps(base, WORKER_ROOT))
|
|
43192
43390
|
throw new Error(`HALO_WORKSPACE (${base}) must not overlap ${WORKER_ROOT}`);
|
|
@@ -43233,7 +43431,7 @@ var init_agentcore_front = __esm({
|
|
|
43233
43431
|
MAX_MEDIA_BYTES = 20 * 1024 * 1024;
|
|
43234
43432
|
O_PATH = 2097152;
|
|
43235
43433
|
execFileP = promisify3(execFile2);
|
|
43236
|
-
readMountinfo = () =>
|
|
43434
|
+
readMountinfo = () => fs91.readFileSync("/proc/self/mountinfo", "utf8");
|
|
43237
43435
|
SYSTEM_SETUP = {
|
|
43238
43436
|
mountinfo: readMountinfo,
|
|
43239
43437
|
exec: (argv) => execFileP(argv[0], argv.slice(1), { timeout: SETUP_TIMEOUT_MS })
|
|
@@ -43413,8 +43611,8 @@ var init_halo_client = __esm({
|
|
|
43413
43611
|
}
|
|
43414
43612
|
return await res.json();
|
|
43415
43613
|
}
|
|
43416
|
-
sessionUrl(
|
|
43417
|
-
const url = new URL(`${this.opts.baseUrl}${
|
|
43614
|
+
sessionUrl(path99, workspace, sessionId) {
|
|
43615
|
+
const url = new URL(`${this.opts.baseUrl}${path99}`);
|
|
43418
43616
|
url.searchParams.set("workspace", workspace);
|
|
43419
43617
|
url.searchParams.set("sessionId", sessionId);
|
|
43420
43618
|
return url;
|
|
@@ -43562,7 +43760,7 @@ var init_version = __esm({
|
|
|
43562
43760
|
});
|
|
43563
43761
|
|
|
43564
43762
|
// ../acp-adapter/dist/adapter.js
|
|
43565
|
-
import
|
|
43763
|
+
import path97 from "node:path";
|
|
43566
43764
|
function composePrompt(blocks) {
|
|
43567
43765
|
const segments = [];
|
|
43568
43766
|
let run = "";
|
|
@@ -43755,7 +43953,7 @@ var init_adapter = __esm({
|
|
|
43755
43953
|
if (cursor !== void 0 && !/^\d+$/.test(cursor))
|
|
43756
43954
|
throw newError(`invalid cursor: ${cursor}`, -32602);
|
|
43757
43955
|
const page = await this.client.listSessions(this.config.workspace, cursor === void 0 ? void 0 : Number(cursor));
|
|
43758
|
-
if (p.cwd !== void 0 &&
|
|
43956
|
+
if (p.cwd !== void 0 && path97.resolve(p.cwd) !== path97.resolve(page.workspace))
|
|
43759
43957
|
return { sessions: [] };
|
|
43760
43958
|
return {
|
|
43761
43959
|
sessions: page.sessions.map((s) => ({
|
|
@@ -44369,8 +44567,8 @@ process.emitWarning = (warning, ...args) => {
|
|
|
44369
44567
|
|
|
44370
44568
|
// src/index.ts
|
|
44371
44569
|
init_server_supervisor();
|
|
44372
|
-
import
|
|
44373
|
-
import
|
|
44570
|
+
import path98 from "node:path";
|
|
44571
|
+
import fs92 from "node:fs";
|
|
44374
44572
|
import { homedir as homedir27, userInfo } from "node:os";
|
|
44375
44573
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
44376
44574
|
|
|
@@ -44661,7 +44859,7 @@ function installUserUnit(opts, run = runCommand) {
|
|
|
44661
44859
|
}
|
|
44662
44860
|
|
|
44663
44861
|
// src/index.ts
|
|
44664
|
-
var VERSION = "2.2.
|
|
44862
|
+
var VERSION = "2.2.6";
|
|
44665
44863
|
var HELP_TOP = `Usage: halo <command> [options]
|
|
44666
44864
|
|
|
44667
44865
|
Commands:
|
|
@@ -45028,8 +45226,8 @@ async function cmdSetup(argv = []) {
|
|
|
45028
45226
|
const { buildBindProviderPlan: buildBindProviderPlan2, envKeyPlaceholders: envKeyPlaceholders2, KEEP_CURRENT: KEEP_CURRENT2, AWS_CHAIN_PROVIDER: AWS_CHAIN_PROVIDER2 } = await Promise.resolve().then(() => (init_setup_bind_provider(), setup_bind_provider_exports));
|
|
45029
45227
|
const { promptText: promptText2, promptPassword: promptPassword2, promptSelect: promptSelect2, promptMultiSelect: promptMultiSelect2 } = await Promise.resolve().then(() => (init_setup_prompts(), setup_prompts_exports));
|
|
45030
45228
|
const nonInteractive = argv.includes("--non-interactive") || argv.includes("-y");
|
|
45031
|
-
const haloHome2 =
|
|
45032
|
-
const globalDir2 =
|
|
45229
|
+
const haloHome2 = path98.join(homedir27(), ".halo");
|
|
45230
|
+
const globalDir2 = path98.join(haloHome2, "global");
|
|
45033
45231
|
ensureHaloHome2(haloHome2);
|
|
45034
45232
|
process.stderr.write(`[setup] ${haloHome2}/ ready
|
|
45035
45233
|
`);
|
|
@@ -45382,7 +45580,7 @@ async function cmdUpgrade() {
|
|
|
45382
45580
|
`);
|
|
45383
45581
|
process.exit(1);
|
|
45384
45582
|
}
|
|
45385
|
-
const broken = verifyNativeModules2(
|
|
45583
|
+
const broken = verifyNativeModules2(path98.join(rootDir, PKG));
|
|
45386
45584
|
if (broken.length > 0) {
|
|
45387
45585
|
process.stderr.write(
|
|
45388
45586
|
`
|
|
@@ -45413,7 +45611,7 @@ halo: upgrade failed (npm exited ${install.status}). ${hint}
|
|
|
45413
45611
|
async function cmdAgents(flags) {
|
|
45414
45612
|
const { initRuntime: initRuntime2, listAgents: listAgents2 } = await Promise.resolve().then(() => (init_harness(), harness_exports));
|
|
45415
45613
|
await initRuntime2();
|
|
45416
|
-
const workspace =
|
|
45614
|
+
const workspace = path98.resolve(flags.workspace ?? process.cwd());
|
|
45417
45615
|
const agents = await listAgents2(workspace);
|
|
45418
45616
|
if (agents.length === 0) {
|
|
45419
45617
|
process.stderr.write("No agents found.\n");
|
|
@@ -45436,12 +45634,12 @@ ${HELP_SESSIONS}`);
|
|
|
45436
45634
|
process.exitCode = 1;
|
|
45437
45635
|
return;
|
|
45438
45636
|
}
|
|
45439
|
-
await cmdSessionsMigrate(
|
|
45637
|
+
await cmdSessionsMigrate(path98.resolve(flags.workspace ?? process.cwd()));
|
|
45440
45638
|
return;
|
|
45441
45639
|
}
|
|
45442
45640
|
const { initRuntime: initRuntime2, listSessions: listSessions2 } = await Promise.resolve().then(() => (init_harness(), harness_exports));
|
|
45443
45641
|
await initRuntime2();
|
|
45444
|
-
const workspace =
|
|
45642
|
+
const workspace = path98.resolve(flags.workspace ?? process.cwd());
|
|
45445
45643
|
const sessions = listSessions2(workspace);
|
|
45446
45644
|
if (sessions.length === 0) {
|
|
45447
45645
|
process.stderr.write("No sessions found.\n");
|
|
@@ -45455,7 +45653,7 @@ ${HELP_SESSIONS}`);
|
|
|
45455
45653
|
}
|
|
45456
45654
|
}
|
|
45457
45655
|
async function cmdSessionsMigrate(workspace) {
|
|
45458
|
-
if (!
|
|
45656
|
+
if (!fs92.existsSync(path98.join(workspace, ".halo"))) {
|
|
45459
45657
|
process.stderr.write(`Not a Halo workspace (no .halo/): ${workspace}
|
|
45460
45658
|
`);
|
|
45461
45659
|
process.exitCode = 1;
|
|
@@ -45487,7 +45685,7 @@ async function cmdModels(argv) {
|
|
|
45487
45685
|
process.exitCode = 1;
|
|
45488
45686
|
return;
|
|
45489
45687
|
}
|
|
45490
|
-
const plan = mod.planModelsInstall(
|
|
45688
|
+
const plan = mod.planModelsInstall(path98.resolve(dir));
|
|
45491
45689
|
for (const line of mod.formatPlan(plan)) process.stdout.write(`${line}
|
|
45492
45690
|
`);
|
|
45493
45691
|
if (plan.needsConfirm && !values.yes) {
|
|
@@ -45596,11 +45794,11 @@ ${stdinContent}` : stdinContent;
|
|
|
45596
45794
|
harness.destroy();
|
|
45597
45795
|
}
|
|
45598
45796
|
}
|
|
45599
|
-
var SERVER_LOCK_PATH =
|
|
45600
|
-
var SERVER_LOG_PATH =
|
|
45797
|
+
var SERVER_LOCK_PATH = path98.join(homedir27(), ".halo", "global", "server.lock");
|
|
45798
|
+
var SERVER_LOG_PATH = path98.join(homedir27(), ".halo", "logs", "server.log");
|
|
45601
45799
|
function readServerPid() {
|
|
45602
45800
|
try {
|
|
45603
|
-
const txt =
|
|
45801
|
+
const txt = fs92.readFileSync(SERVER_LOCK_PATH, "utf-8").trim();
|
|
45604
45802
|
const n = parseInt(txt, 10);
|
|
45605
45803
|
return Number.isFinite(n) && n > 0 ? n : null;
|
|
45606
45804
|
} catch {
|
|
@@ -45707,8 +45905,8 @@ async function cmdServerStart(argv, restart) {
|
|
|
45707
45905
|
}
|
|
45708
45906
|
if (plan.note) writeDim(plan.note);
|
|
45709
45907
|
const { spawn: spawn7 } = await import("node:child_process");
|
|
45710
|
-
|
|
45711
|
-
const out =
|
|
45908
|
+
fs92.mkdirSync(path98.dirname(SERVER_LOG_PATH), { recursive: true });
|
|
45909
|
+
const out = fs92.openSync(SERVER_LOG_PATH, "a");
|
|
45712
45910
|
const child = spawn7(process.argv[0], [process.argv[1], "server", "start"], {
|
|
45713
45911
|
detached: true,
|
|
45714
45912
|
stdio: ["ignore", out, out],
|
|
@@ -45789,8 +45987,8 @@ ${HELP_AGENTCORE}`);
|
|
|
45789
45987
|
process.exitCode = 1;
|
|
45790
45988
|
return;
|
|
45791
45989
|
}
|
|
45792
|
-
const workspace =
|
|
45793
|
-
if (!
|
|
45990
|
+
const workspace = path98.resolve(raw);
|
|
45991
|
+
if (!fs92.statSync(workspace, { throwIfNoEntry: false })?.isDirectory()) {
|
|
45794
45992
|
process.stderr.write(`Workspace is not a directory: ${workspace}
|
|
45795
45993
|
`);
|
|
45796
45994
|
process.exitCode = 1;
|
|
@@ -45901,7 +46099,7 @@ async function cmdServerLogs(argv) {
|
|
|
45901
46099
|
lines: { type: "string", short: "n" }
|
|
45902
46100
|
}
|
|
45903
46101
|
});
|
|
45904
|
-
if (!
|
|
46102
|
+
if (!fs92.existsSync(SERVER_LOG_PATH)) {
|
|
45905
46103
|
process.stderr.write(`No log file at ${SERVER_LOG_PATH}
|
|
45906
46104
|
`);
|
|
45907
46105
|
return;
|
|
@@ -45919,7 +46117,7 @@ function exitMissingSetup() {
|
|
|
45919
46117
|
process.exit(1);
|
|
45920
46118
|
}
|
|
45921
46119
|
function isHaloHomeReady() {
|
|
45922
|
-
return
|
|
46120
|
+
return fs92.existsSync(path98.join(homedir27(), ".halo", "global", ".template-version"));
|
|
45923
46121
|
}
|
|
45924
46122
|
async function main2() {
|
|
45925
46123
|
const argv = process.argv.slice(2);
|