@turmind/halo 1.5.6 → 1.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin-out/404.html +1 -1
- package/admin-out/index.html +1 -1
- package/admin-out/index.txt +1 -1
- package/bundled-docs/design/agent.md +7 -7
- package/bundled-docs/design/architecture.md +12 -11
- package/bundled-docs/design/storage.md +2 -1
- package/bundled-docs/dev/add-model-provider.md +33 -24
- package/bundled-docs/dev/deploy.md +1 -1
- package/bundled-docs/dev/desktop-packaging.md +4 -3
- package/bundled-docs/dev/env.md +1 -1
- package/bundled-docs/guide/agents.md +2 -2
- package/bundled-docs/guide/cli.md +5 -4
- package/bundled-docs/guide/getting-started.md +1 -1
- package/bundled-docs/requirements/settings.md +2 -1
- package/dist/index.js +409 -388
- package/package.json +1 -1
- package/templates/models/anthropic.yaml +1 -0
- package/templates/models/aws-bedrock-claude-invoke.yaml +1 -0
- package/templates/models/aws-bedrock-mantle.yaml +1 -0
- package/templates/models/aws-bedrock-openai.yaml +1 -0
- package/templates/models/deepseek.yaml +1 -0
- package/templates/models/doubao.yaml +1 -0
- package/templates/models/hunyuan.yaml +1 -0
- package/templates/models/kimi.yaml +1 -0
- package/templates/models/mimo-token-plan-china.yaml +1 -0
- package/templates/models/minimax.yaml +1 -0
- package/templates/models/openai.yaml +1 -0
- package/templates/models/qwen.yaml +1 -0
- package/templates/models/zhipu.yaml +1 -0
- /package/admin-out/_next/static/{visjvN510yFK-Ff5zwx-0 → rTD3zkMvzwtqUwzhz6QJH}/_buildManifest.js +0 -0
- /package/admin-out/_next/static/{visjvN510yFK-Ff5zwx-0 → rTD3zkMvzwtqUwzhz6QJH}/_ssgManifest.js +0 -0
package/dist/index.js
CHANGED
|
@@ -3102,6 +3102,7 @@ __export(init_exports, {
|
|
|
3102
3102
|
mergeAgentYaml: () => mergeAgentYaml,
|
|
3103
3103
|
readInstalledOptionalSkills: () => readInstalledOptionalSkills,
|
|
3104
3104
|
readSeedVersion: () => readSeedVersion,
|
|
3105
|
+
refreshTemplatesIfOutdated: () => refreshTemplatesIfOutdated,
|
|
3105
3106
|
writeFileAtomic: () => writeFileAtomic,
|
|
3106
3107
|
writeInstalledOptionalSkills: () => writeInstalledOptionalSkills
|
|
3107
3108
|
});
|
|
@@ -3124,6 +3125,17 @@ function readSeedVersion(haloHome2) {
|
|
|
3124
3125
|
return 0;
|
|
3125
3126
|
}
|
|
3126
3127
|
}
|
|
3128
|
+
function refreshTemplatesIfOutdated(haloHome2, logTag) {
|
|
3129
|
+
const seedVersion = readSeedVersion(haloHome2);
|
|
3130
|
+
if (seedVersion <= 0 || seedVersion >= TEMPLATE_VERSION)
|
|
3131
|
+
return;
|
|
3132
|
+
console.log(`[${logTag}] Templates outdated (v${seedVersion} \u2192 v${TEMPLATE_VERSION}), refreshing ~/.halo/global/`);
|
|
3133
|
+
try {
|
|
3134
|
+
ensureHaloHome(haloHome2);
|
|
3135
|
+
} catch (err) {
|
|
3136
|
+
console.error(`[${logTag}] Template refresh failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3127
3139
|
function writeFileAtomic(filePath, content, mode) {
|
|
3128
3140
|
fs7.mkdirSync(path9.dirname(filePath), { recursive: true });
|
|
3129
3141
|
const tmpPath = `${filePath}.tmp`;
|
|
@@ -3455,7 +3467,7 @@ var init_init = __esm({
|
|
|
3455
3467
|
path9.resolve(__dirname, "..", "bundled-docs"),
|
|
3456
3468
|
path9.resolve(__dirname, "..", "..", "..", ".halo", "docs")
|
|
3457
3469
|
];
|
|
3458
|
-
TEMPLATE_VERSION =
|
|
3470
|
+
TEMPLATE_VERSION = 82;
|
|
3459
3471
|
VERSION_FILE = ".template-version";
|
|
3460
3472
|
SKIP_NAMES = /* @__PURE__ */ new Set([".DS_Store", "schema.sql", "__pycache__", ".pytest_cache"]);
|
|
3461
3473
|
BUILTIN_AGENT_IDS = /* @__PURE__ */ new Set([
|
|
@@ -7144,27 +7156,27 @@ var init_workspace = __esm({
|
|
|
7144
7156
|
constructor(projectRoot) {
|
|
7145
7157
|
this.projectRoot = projectRoot;
|
|
7146
7158
|
}
|
|
7147
|
-
async readFile(
|
|
7148
|
-
const fullPath = this.validatePath(
|
|
7159
|
+
async readFile(path74) {
|
|
7160
|
+
const fullPath = this.validatePath(path74);
|
|
7149
7161
|
return readFile(fullPath, "utf-8");
|
|
7150
7162
|
}
|
|
7151
|
-
async writeFile(
|
|
7152
|
-
const fullPath = this.validatePath(
|
|
7163
|
+
async writeFile(path74, content) {
|
|
7164
|
+
const fullPath = this.validatePath(path74);
|
|
7153
7165
|
const dir = resolve(fullPath, "..");
|
|
7154
7166
|
await mkdir(dir, { recursive: true });
|
|
7155
7167
|
await writeFile(fullPath, content, "utf-8");
|
|
7156
7168
|
}
|
|
7157
|
-
validatePath(
|
|
7158
|
-
const fullPath = isAbsolute(
|
|
7169
|
+
validatePath(path74) {
|
|
7170
|
+
const fullPath = isAbsolute(path74) ? resolve(path74) : resolve(this.projectRoot, path74);
|
|
7159
7171
|
const root = resolve(this.projectRoot);
|
|
7160
7172
|
if (fullPath !== root && !fullPath.startsWith(root + sep)) {
|
|
7161
|
-
throw new WorkspaceError(`Path "${
|
|
7173
|
+
throw new WorkspaceError(`Path "${path74}" is outside the workspace directory "${this.projectRoot}"`);
|
|
7162
7174
|
}
|
|
7163
7175
|
try {
|
|
7164
7176
|
const real = realpathSync2(fullPath);
|
|
7165
7177
|
const realRoot = realpathSync2(root);
|
|
7166
7178
|
if (real !== realRoot && !real.startsWith(realRoot + sep)) {
|
|
7167
|
-
throw new WorkspaceError(`Path "${
|
|
7179
|
+
throw new WorkspaceError(`Path "${path74}" is outside the workspace directory "${this.projectRoot}"`);
|
|
7168
7180
|
}
|
|
7169
7181
|
} catch (err) {
|
|
7170
7182
|
if (err instanceof WorkspaceError)
|
|
@@ -7351,12 +7363,12 @@ var init_git_manager = __esm({
|
|
|
7351
7363
|
const code = parts[0];
|
|
7352
7364
|
const status = code[0];
|
|
7353
7365
|
const isRenameOrCopy = status === "R" || status === "C";
|
|
7354
|
-
const
|
|
7355
|
-
if (!
|
|
7366
|
+
const path74 = isRenameOrCopy ? parts[2] : parts[1];
|
|
7367
|
+
if (!path74 || seen.has(path74))
|
|
7356
7368
|
continue;
|
|
7357
|
-
seen.add(
|
|
7369
|
+
seen.add(path74);
|
|
7358
7370
|
files.push({
|
|
7359
|
-
path:
|
|
7371
|
+
path: path74,
|
|
7360
7372
|
status,
|
|
7361
7373
|
from: isRenameOrCopy ? parts[1] : void 0
|
|
7362
7374
|
});
|
|
@@ -7504,9 +7516,9 @@ var init_git_manager = __esm({
|
|
|
7504
7516
|
* empty for an added file or the root commit) and `modified` is the version
|
|
7505
7517
|
* at `commit` (empty for a deletion). The working-tree/staged path above is
|
|
7506
7518
|
* left entirely untouched (commit === undefined preserves existing behavior). */
|
|
7507
|
-
async getFileDiff(
|
|
7519
|
+
async getFileDiff(path74, staged, from, commit) {
|
|
7508
7520
|
if (commit) {
|
|
7509
|
-
const parentPath = from ||
|
|
7521
|
+
const parentPath = from || path74;
|
|
7510
7522
|
let original2 = "";
|
|
7511
7523
|
try {
|
|
7512
7524
|
original2 = await this.git.show([`${commit}^:${parentPath}`]);
|
|
@@ -7515,13 +7527,13 @@ var init_git_manager = __esm({
|
|
|
7515
7527
|
}
|
|
7516
7528
|
let modified2 = "";
|
|
7517
7529
|
try {
|
|
7518
|
-
modified2 = await this.git.show([`${commit}:${
|
|
7530
|
+
modified2 = await this.git.show([`${commit}:${path74}`]);
|
|
7519
7531
|
} catch {
|
|
7520
7532
|
modified2 = "";
|
|
7521
7533
|
}
|
|
7522
7534
|
return { original: original2, modified: modified2 };
|
|
7523
7535
|
}
|
|
7524
|
-
const headPath = from ||
|
|
7536
|
+
const headPath = from || path74;
|
|
7525
7537
|
let original = "";
|
|
7526
7538
|
try {
|
|
7527
7539
|
original = await this.git.show([`HEAD:${headPath}`]);
|
|
@@ -7531,13 +7543,13 @@ var init_git_manager = __esm({
|
|
|
7531
7543
|
let modified = "";
|
|
7532
7544
|
if (staged) {
|
|
7533
7545
|
try {
|
|
7534
|
-
modified = await this.git.show([`:${
|
|
7546
|
+
modified = await this.git.show([`:${path74}`]);
|
|
7535
7547
|
} catch {
|
|
7536
7548
|
modified = "";
|
|
7537
7549
|
}
|
|
7538
7550
|
} else {
|
|
7539
7551
|
try {
|
|
7540
|
-
modified = await this.workspace.readFile(
|
|
7552
|
+
modified = await this.workspace.readFile(path74);
|
|
7541
7553
|
} catch {
|
|
7542
7554
|
modified = "";
|
|
7543
7555
|
}
|
|
@@ -10239,12 +10251,29 @@ var init_anthropic_agent = __esm({
|
|
|
10239
10251
|
});
|
|
10240
10252
|
|
|
10241
10253
|
// ../server/dist/agents/model-runtime.js
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10254
|
+
import path28 from "node:path";
|
|
10255
|
+
function resolveProviderRuntime(providerId) {
|
|
10256
|
+
const yamlPath = path28.join(HALO_GLOBAL_DIR, "models", `${providerId}.yaml`);
|
|
10257
|
+
const providers2 = getModelsRegistry().providers;
|
|
10258
|
+
const entry = providers2.find((p) => p.id === providerId);
|
|
10259
|
+
if (!entry) {
|
|
10260
|
+
throw new Error(`[model-runtime] Unknown provider "${providerId}": no provider yaml with that id (expected ${yamlPath}). Check agent.yaml model.provider, or run \`halo setup\` to install the bundled providers.`);
|
|
10261
|
+
}
|
|
10262
|
+
const runtime = entry.runtime;
|
|
10263
|
+
if (typeof runtime !== "string" || !runtime) {
|
|
10264
|
+
throw new Error(`[model-runtime] Provider "${providerId}" has no \`runtime:\` field in ${yamlPath}. Run \`halo setup\` or restart the Halo server to refresh templates.`);
|
|
10265
|
+
}
|
|
10266
|
+
if (!MODEL_RUNTIME_NAMES.includes(runtime)) {
|
|
10267
|
+
throw new Error(`[model-runtime] Provider "${providerId}" names unknown runtime "${runtime}" in ${yamlPath}. Valid runtimes: ${MODEL_RUNTIME_NAMES.join(", ")}.`);
|
|
10268
|
+
}
|
|
10269
|
+
return runtime;
|
|
10270
|
+
}
|
|
10271
|
+
function createModelRuntime(runtime, cfg) {
|
|
10272
|
+
switch (runtime) {
|
|
10273
|
+
case "bedrock-invoke":
|
|
10245
10274
|
return new BedrockAgent({
|
|
10246
10275
|
modelId: cfg.modelId,
|
|
10247
|
-
endpoint: cfg.endpoint
|
|
10276
|
+
endpoint: cfg.endpoint,
|
|
10248
10277
|
systemPrompt: cfg.systemPrompt,
|
|
10249
10278
|
tools: cfg.tools,
|
|
10250
10279
|
maxTokens: cfg.maxTokens,
|
|
@@ -10257,7 +10286,7 @@ function createModelRuntime(providerId, cfg) {
|
|
|
10257
10286
|
case "kimi":
|
|
10258
10287
|
return new KimiAgent({
|
|
10259
10288
|
modelId: cfg.modelId,
|
|
10260
|
-
endpoint: cfg.endpoint
|
|
10289
|
+
endpoint: cfg.endpoint,
|
|
10261
10290
|
apiKey: cfg.apiKey ?? "",
|
|
10262
10291
|
systemPrompt: cfg.systemPrompt,
|
|
10263
10292
|
tools: cfg.tools,
|
|
@@ -10268,7 +10297,7 @@ function createModelRuntime(providerId, cfg) {
|
|
|
10268
10297
|
case "deepseek":
|
|
10269
10298
|
return new DeepSeekAgent({
|
|
10270
10299
|
modelId: cfg.modelId,
|
|
10271
|
-
endpoint: cfg.endpoint
|
|
10300
|
+
endpoint: cfg.endpoint,
|
|
10272
10301
|
apiKey: cfg.apiKey ?? "",
|
|
10273
10302
|
systemPrompt: cfg.systemPrompt,
|
|
10274
10303
|
tools: cfg.tools,
|
|
@@ -10278,7 +10307,7 @@ function createModelRuntime(providerId, cfg) {
|
|
|
10278
10307
|
case "minimax":
|
|
10279
10308
|
return new MiniMaxAgent({
|
|
10280
10309
|
modelId: cfg.modelId,
|
|
10281
|
-
endpoint: cfg.endpoint
|
|
10310
|
+
endpoint: cfg.endpoint,
|
|
10282
10311
|
apiKey: cfg.apiKey ?? "",
|
|
10283
10312
|
systemPrompt: cfg.systemPrompt,
|
|
10284
10313
|
tools: cfg.tools,
|
|
@@ -10291,7 +10320,7 @@ function createModelRuntime(providerId, cfg) {
|
|
|
10291
10320
|
case "qwen":
|
|
10292
10321
|
return new QwenAgent({
|
|
10293
10322
|
modelId: cfg.modelId,
|
|
10294
|
-
endpoint: cfg.endpoint
|
|
10323
|
+
endpoint: cfg.endpoint,
|
|
10295
10324
|
apiKey: cfg.apiKey ?? "",
|
|
10296
10325
|
systemPrompt: cfg.systemPrompt,
|
|
10297
10326
|
tools: cfg.tools,
|
|
@@ -10303,7 +10332,7 @@ function createModelRuntime(providerId, cfg) {
|
|
|
10303
10332
|
case "hunyuan":
|
|
10304
10333
|
return new HunyuanAgent({
|
|
10305
10334
|
modelId: cfg.modelId,
|
|
10306
|
-
endpoint: cfg.endpoint
|
|
10335
|
+
endpoint: cfg.endpoint,
|
|
10307
10336
|
apiKey: cfg.apiKey ?? "",
|
|
10308
10337
|
systemPrompt: cfg.systemPrompt,
|
|
10309
10338
|
tools: cfg.tools,
|
|
@@ -10313,7 +10342,7 @@ function createModelRuntime(providerId, cfg) {
|
|
|
10313
10342
|
case "doubao":
|
|
10314
10343
|
return new DoubaoAgent({
|
|
10315
10344
|
modelId: cfg.modelId,
|
|
10316
|
-
endpoint: cfg.endpoint
|
|
10345
|
+
endpoint: cfg.endpoint,
|
|
10317
10346
|
apiKey: cfg.apiKey ?? "",
|
|
10318
10347
|
systemPrompt: cfg.systemPrompt,
|
|
10319
10348
|
tools: cfg.tools,
|
|
@@ -10323,32 +10352,30 @@ function createModelRuntime(providerId, cfg) {
|
|
|
10323
10352
|
case "zhipu":
|
|
10324
10353
|
return new ZhipuAgent({
|
|
10325
10354
|
modelId: cfg.modelId,
|
|
10326
|
-
endpoint: cfg.endpoint
|
|
10355
|
+
endpoint: cfg.endpoint,
|
|
10327
10356
|
apiKey: cfg.apiKey ?? "",
|
|
10328
10357
|
systemPrompt: cfg.systemPrompt,
|
|
10329
10358
|
tools: cfg.tools,
|
|
10330
10359
|
maxTokens: cfg.maxTokens,
|
|
10331
10360
|
thinking: cfg.thinking
|
|
10332
10361
|
});
|
|
10333
|
-
case "openai":
|
|
10362
|
+
case "openai-chat":
|
|
10334
10363
|
return new OpenAIAgent({
|
|
10335
10364
|
modelId: cfg.modelId,
|
|
10336
|
-
endpoint: cfg.endpoint
|
|
10365
|
+
endpoint: cfg.endpoint,
|
|
10337
10366
|
apiKey: cfg.apiKey ?? "",
|
|
10338
10367
|
systemPrompt: cfg.systemPrompt,
|
|
10339
10368
|
tools: cfg.tools,
|
|
10340
10369
|
maxTokens: cfg.maxTokens,
|
|
10341
10370
|
thinking: cfg.thinking
|
|
10342
10371
|
});
|
|
10343
|
-
//
|
|
10344
|
-
// bedrock-
|
|
10345
|
-
//
|
|
10346
|
-
|
|
10347
|
-
case "aws-bedrock-mantle":
|
|
10348
|
-
case "aws-bedrock-openai":
|
|
10372
|
+
// OpenAI Responses API on Bedrock — serves both aws-bedrock-mantle
|
|
10373
|
+
// (bedrock-mantle host) and aws-bedrock-openai (bedrock-runtime host,
|
|
10374
|
+
// /openai/v1); the endpoint alone picks the host and SigV4 region.
|
|
10375
|
+
case "bedrock-mantle":
|
|
10349
10376
|
return new MantleAgent({
|
|
10350
10377
|
modelId: cfg.modelId,
|
|
10351
|
-
endpoint: cfg.endpoint
|
|
10378
|
+
endpoint: cfg.endpoint,
|
|
10352
10379
|
// No bearer token → MantleAgent falls back to SigV4 IAM auth using
|
|
10353
10380
|
// these creds (or the SDK default chain when also empty).
|
|
10354
10381
|
apiKey: cfg.apiKey ?? "",
|
|
@@ -10359,22 +10386,10 @@ function createModelRuntime(providerId, cfg) {
|
|
|
10359
10386
|
thinking: cfg.thinking,
|
|
10360
10387
|
verbosity: cfg.verbosity
|
|
10361
10388
|
});
|
|
10362
|
-
case "anthropic":
|
|
10389
|
+
case "anthropic-messages":
|
|
10363
10390
|
return new AnthropicAgent({
|
|
10364
10391
|
modelId: cfg.modelId,
|
|
10365
|
-
endpoint: cfg.endpoint
|
|
10366
|
-
apiKey: cfg.apiKey ?? "",
|
|
10367
|
-
systemPrompt: cfg.systemPrompt,
|
|
10368
|
-
tools: cfg.tools,
|
|
10369
|
-
maxTokens: cfg.maxTokens,
|
|
10370
|
-
promptCaching: cfg.promptCaching,
|
|
10371
|
-
thinking: cfg.thinking,
|
|
10372
|
-
thinkingBudgetTokens: cfg.thinkingBudgetTokens
|
|
10373
|
-
});
|
|
10374
|
-
case "mimo-token-plan-china":
|
|
10375
|
-
return new AnthropicAgent({
|
|
10376
|
-
modelId: cfg.modelId,
|
|
10377
|
-
endpoint: cfg.endpoint ?? "https://token-plan-cn.xiaomimimo.com/anthropic",
|
|
10392
|
+
endpoint: cfg.endpoint,
|
|
10378
10393
|
apiKey: cfg.apiKey ?? "",
|
|
10379
10394
|
systemPrompt: cfg.systemPrompt,
|
|
10380
10395
|
tools: cfg.tools,
|
|
@@ -10384,9 +10399,10 @@ function createModelRuntime(providerId, cfg) {
|
|
|
10384
10399
|
thinkingBudgetTokens: cfg.thinkingBudgetTokens
|
|
10385
10400
|
});
|
|
10386
10401
|
default:
|
|
10387
|
-
throw new Error(`[model-runtime] Unknown
|
|
10402
|
+
throw new Error(`[model-runtime] Unknown runtime "${runtime}". Valid runtimes: ${MODEL_RUNTIME_NAMES.join(", ")}.`);
|
|
10388
10403
|
}
|
|
10389
10404
|
}
|
|
10405
|
+
var MODEL_RUNTIME_NAMES;
|
|
10390
10406
|
var init_model_runtime = __esm({
|
|
10391
10407
|
"../server/dist/agents/model-runtime.js"() {
|
|
10392
10408
|
"use strict";
|
|
@@ -10401,17 +10417,31 @@ var init_model_runtime = __esm({
|
|
|
10401
10417
|
init_openai_agent();
|
|
10402
10418
|
init_mantle_agent();
|
|
10403
10419
|
init_anthropic_agent();
|
|
10420
|
+
init_config();
|
|
10421
|
+
MODEL_RUNTIME_NAMES = [
|
|
10422
|
+
"anthropic-messages",
|
|
10423
|
+
"openai-chat",
|
|
10424
|
+
"bedrock-invoke",
|
|
10425
|
+
"bedrock-mantle",
|
|
10426
|
+
"kimi",
|
|
10427
|
+
"deepseek",
|
|
10428
|
+
"minimax",
|
|
10429
|
+
"qwen",
|
|
10430
|
+
"hunyuan",
|
|
10431
|
+
"doubao",
|
|
10432
|
+
"zhipu"
|
|
10433
|
+
];
|
|
10404
10434
|
}
|
|
10405
10435
|
});
|
|
10406
10436
|
|
|
10407
10437
|
// ../server/dist/tools/workspace-tools.js
|
|
10408
10438
|
import fs24 from "node:fs/promises";
|
|
10409
|
-
import
|
|
10439
|
+
import path29 from "node:path";
|
|
10410
10440
|
import crypto from "node:crypto";
|
|
10411
10441
|
import { homedir as homedir11 } from "node:os";
|
|
10412
10442
|
function resolvePath2(filePath, workspaceRoot) {
|
|
10413
|
-
const expanded = filePath.startsWith("~/") ?
|
|
10414
|
-
return
|
|
10443
|
+
const expanded = filePath.startsWith("~/") ? path29.join(HOME2, filePath.slice(2)) : filePath;
|
|
10444
|
+
return path29.isAbsolute(expanded) ? path29.resolve(expanded) : path29.resolve(workspaceRoot, expanded);
|
|
10415
10445
|
}
|
|
10416
10446
|
async function* walkDir(dir, signal) {
|
|
10417
10447
|
if (signal?.aborted)
|
|
@@ -10427,7 +10457,7 @@ async function* walkDir(dir, signal) {
|
|
|
10427
10457
|
return;
|
|
10428
10458
|
if (SKIP_DIRS.has(name))
|
|
10429
10459
|
continue;
|
|
10430
|
-
const fullPath =
|
|
10460
|
+
const fullPath = path29.join(dir, name);
|
|
10431
10461
|
let stat;
|
|
10432
10462
|
try {
|
|
10433
10463
|
stat = await fs24.lstat(fullPath);
|
|
@@ -10435,7 +10465,7 @@ async function* walkDir(dir, signal) {
|
|
|
10435
10465
|
continue;
|
|
10436
10466
|
}
|
|
10437
10467
|
if (stat.isDirectory()) {
|
|
10438
|
-
if (
|
|
10468
|
+
if (path29.basename(dir) === ".halo" && SKIP_HALO_SUBDIRS.has(name))
|
|
10439
10469
|
continue;
|
|
10440
10470
|
if (process.platform === "win32" && await isReparsePoint(fullPath))
|
|
10441
10471
|
continue;
|
|
@@ -10663,7 +10693,7 @@ function createWorkspaceTools(workspaceRoot, accessLevelOrOpts = "full") {
|
|
|
10663
10693
|
callback: async (_input) => {
|
|
10664
10694
|
const input = _input;
|
|
10665
10695
|
const fullPath = resolvePath2(input.path, workspaceRoot);
|
|
10666
|
-
const ext =
|
|
10696
|
+
const ext = path29.extname(fullPath).toLowerCase();
|
|
10667
10697
|
const supportedExts = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp"]);
|
|
10668
10698
|
if (!supportedExts.has(ext)) {
|
|
10669
10699
|
return `${TOOL_WARN_MARKER}
|
|
@@ -10860,7 +10890,7 @@ Error: old_string appears more than once in ${input.path}. Either expand it with
|
|
|
10860
10890
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
10861
10891
|
if (entry.isDirectory) {
|
|
10862
10892
|
results.push(`\u{1F4C1} ${relPath}/`);
|
|
10863
|
-
await walk(
|
|
10893
|
+
await walk(path29.join(dir, entry.name), relPath);
|
|
10864
10894
|
} else {
|
|
10865
10895
|
results.push(`\u{1F4C4} ${relPath}`);
|
|
10866
10896
|
}
|
|
@@ -10969,7 +10999,7 @@ Error: Invalid regex pattern: ${err.message}`;
|
|
|
10969
10999
|
for await (const filePath of files) {
|
|
10970
11000
|
if (results.length >= maxResults)
|
|
10971
11001
|
break;
|
|
10972
|
-
if (input.include && !matchInclude(
|
|
11002
|
+
if (input.include && !matchInclude(path29.basename(filePath), input.include)) {
|
|
10973
11003
|
continue;
|
|
10974
11004
|
}
|
|
10975
11005
|
if (await isBinaryFile(filePath))
|
|
@@ -10980,7 +11010,7 @@ Error: Invalid regex pattern: ${err.message}`;
|
|
|
10980
11010
|
} catch {
|
|
10981
11011
|
continue;
|
|
10982
11012
|
}
|
|
10983
|
-
const relativePath =
|
|
11013
|
+
const relativePath = path29.relative(workspaceRoot, filePath);
|
|
10984
11014
|
const lines = content.split("\n");
|
|
10985
11015
|
for (let i = 0; i < lines.length; i++) {
|
|
10986
11016
|
if (results.length >= maxResults)
|
|
@@ -11025,7 +11055,7 @@ Error: Invalid regex pattern: ${err.message}`;
|
|
|
11025
11055
|
for await (const filePath of walkDir(searchDir, signal)) {
|
|
11026
11056
|
if (results.length >= GLOB_MAX_RESULTS)
|
|
11027
11057
|
break;
|
|
11028
|
-
const relativePath =
|
|
11058
|
+
const relativePath = path29.relative(workspaceRoot, filePath);
|
|
11029
11059
|
if (matchGlob(relativePath, input.pattern)) {
|
|
11030
11060
|
results.push(relativePath);
|
|
11031
11061
|
}
|
|
@@ -11150,7 +11180,7 @@ var init_workspace_tools = __esm({
|
|
|
11150
11180
|
|
|
11151
11181
|
// ../server/dist/prompts/system-prompts.js
|
|
11152
11182
|
import fs25 from "node:fs/promises";
|
|
11153
|
-
import
|
|
11183
|
+
import path30 from "node:path";
|
|
11154
11184
|
import { homedir as homedir12 } from "node:os";
|
|
11155
11185
|
async function dirExists(dirPath) {
|
|
11156
11186
|
try {
|
|
@@ -11186,7 +11216,7 @@ async function loadDir(dirPath, fallback) {
|
|
|
11186
11216
|
const chunks = [];
|
|
11187
11217
|
const loaded = [];
|
|
11188
11218
|
for (const name of mdFiles) {
|
|
11189
|
-
const fullPath =
|
|
11219
|
+
const fullPath = path30.join(dirPath, name);
|
|
11190
11220
|
try {
|
|
11191
11221
|
const content = (await fs25.readFile(fullPath, "utf-8")).trim();
|
|
11192
11222
|
if (content) {
|
|
@@ -11203,11 +11233,11 @@ async function loadDir(dirPath, fallback) {
|
|
|
11203
11233
|
}
|
|
11204
11234
|
async function resolvePromptsDir(scope, workspaceRoot) {
|
|
11205
11235
|
if (workspaceRoot) {
|
|
11206
|
-
const wsDir =
|
|
11236
|
+
const wsDir = path30.join(workspaceRoot, ".halo", "prompts", scope);
|
|
11207
11237
|
if (await dirExists(wsDir))
|
|
11208
11238
|
return wsDir;
|
|
11209
11239
|
}
|
|
11210
|
-
return
|
|
11240
|
+
return path30.join(GLOBAL_PROMPTS_DIR, scope);
|
|
11211
11241
|
}
|
|
11212
11242
|
async function loadSystemPrompts(workspaceRoot) {
|
|
11213
11243
|
const [bootstrapDir, allDir, rootDir] = await Promise.all([
|
|
@@ -11236,12 +11266,12 @@ var GLOBAL_PROMPTS_DIR;
|
|
|
11236
11266
|
var init_system_prompts = __esm({
|
|
11237
11267
|
"../server/dist/prompts/system-prompts.js"() {
|
|
11238
11268
|
"use strict";
|
|
11239
|
-
GLOBAL_PROMPTS_DIR =
|
|
11269
|
+
GLOBAL_PROMPTS_DIR = path30.join(homedir12(), ".halo", "global", "prompts");
|
|
11240
11270
|
}
|
|
11241
11271
|
});
|
|
11242
11272
|
|
|
11243
11273
|
// ../server/dist/agents/session-agent-builder.js
|
|
11244
|
-
import
|
|
11274
|
+
import path31 from "node:path";
|
|
11245
11275
|
var SessionAgentBuilder;
|
|
11246
11276
|
var init_session_agent_builder = __esm({
|
|
11247
11277
|
"../server/dist/agents/session-agent-builder.js"() {
|
|
@@ -11316,7 +11346,7 @@ var init_session_agent_builder = __esm({
|
|
|
11316
11346
|
* (yamlConfig null — read/parse failed, see loadAgentYaml) from "config
|
|
11317
11347
|
* genuinely incomplete", so the error is self-diagnosing. */
|
|
11318
11348
|
validateAgentModelConfig(agentId, yamlConfig) {
|
|
11319
|
-
const yamlPath =
|
|
11349
|
+
const yamlPath = path31.join(agentSourceDir(agentId, this.host.workspaceRoot), "agent.yaml");
|
|
11320
11350
|
if (yamlConfig === null) {
|
|
11321
11351
|
throw new Error(`[SessionManager] Agent "${agentId}": agent.yaml missing or unreadable at ${yamlPath}.`);
|
|
11322
11352
|
}
|
|
@@ -11403,7 +11433,7 @@ var init_session_agent_builder = __esm({
|
|
|
11403
11433
|
|
|
11404
11434
|
The project workspace is at: ${this.host.workspaceRoot}
|
|
11405
11435
|
`;
|
|
11406
|
-
if (workingDir &&
|
|
11436
|
+
if (workingDir && path31.resolve(workingDir) !== path31.resolve(this.host.workspaceRoot)) {
|
|
11407
11437
|
systemPrompt += `Working directory: ${workingDir}
|
|
11408
11438
|
`;
|
|
11409
11439
|
}
|
|
@@ -11532,7 +11562,7 @@ ${roster}`;
|
|
|
11532
11562
|
const aws = resolveAwsCredentials(providerId, this.host.workspaceRoot);
|
|
11533
11563
|
const awsCreds = aws.accessKeyId && aws.secretAccessKey ? aws : void 0;
|
|
11534
11564
|
const apiKey = resolveApiKey(providerId, this.host.workspaceRoot);
|
|
11535
|
-
const agent = createModelRuntime(providerId, {
|
|
11565
|
+
const agent = createModelRuntime(resolveProviderRuntime(providerId), {
|
|
11536
11566
|
modelId,
|
|
11537
11567
|
endpoint,
|
|
11538
11568
|
systemPrompt,
|
|
@@ -11587,7 +11617,7 @@ ${roster}`;
|
|
|
11587
11617
|
const loaded = systemPrompts.files[scope];
|
|
11588
11618
|
if (loaded.length > 0) {
|
|
11589
11619
|
for (const file of loaded) {
|
|
11590
|
-
mdFiles.push({ label: `prompt/${scope}/${
|
|
11620
|
+
mdFiles.push({ label: `prompt/${scope}/${path31.basename(file)}`, path: file });
|
|
11591
11621
|
}
|
|
11592
11622
|
} else {
|
|
11593
11623
|
mdFiles.push({ label: `prompt/${scope} (built-in fallback)`, path: systemPrompts.dirs[scope] });
|
|
@@ -11693,7 +11723,7 @@ var init_session_skill_commands = __esm({
|
|
|
11693
11723
|
|
|
11694
11724
|
// ../server/dist/agents/session-state-store.js
|
|
11695
11725
|
import fsSync6 from "node:fs";
|
|
11696
|
-
import
|
|
11726
|
+
import path32 from "node:path";
|
|
11697
11727
|
var SessionStateStore;
|
|
11698
11728
|
var init_session_state_store = __esm({
|
|
11699
11729
|
"../server/dist/agents/session-state-store.js"() {
|
|
@@ -11720,7 +11750,7 @@ var init_session_state_store = __esm({
|
|
|
11720
11750
|
try {
|
|
11721
11751
|
const dir = this.sessionDir(session.agentId);
|
|
11722
11752
|
fsSync6.mkdirSync(dir, { recursive: true });
|
|
11723
|
-
const filePath =
|
|
11753
|
+
const filePath = path32.join(dir, `${fileSegment(session.id)}.json`);
|
|
11724
11754
|
let existing = {};
|
|
11725
11755
|
try {
|
|
11726
11756
|
existing = JSON.parse(fsSync6.readFileSync(filePath, "utf-8"));
|
|
@@ -11749,7 +11779,7 @@ var init_session_state_store = __esm({
|
|
|
11749
11779
|
/** Load agent.messages from the delegated log file's rawMessages field */
|
|
11750
11780
|
loadAgentState(sessionId, agentId) {
|
|
11751
11781
|
try {
|
|
11752
|
-
const filePath =
|
|
11782
|
+
const filePath = path32.join(this.sessionDir(agentId), `${fileSegment(sessionId)}.json`);
|
|
11753
11783
|
const data = JSON.parse(fsSync6.readFileSync(filePath, "utf-8"));
|
|
11754
11784
|
return data.rawMessages ?? [];
|
|
11755
11785
|
} catch {
|
|
@@ -11829,7 +11859,7 @@ async function initObservability() {
|
|
|
11829
11859
|
return true;
|
|
11830
11860
|
}
|
|
11831
11861
|
const { registerSdk: registerSdk2 } = await Promise.resolve().then(() => (init_otel_sdk(), otel_sdk_exports));
|
|
11832
|
-
providers = registerSdk2(process.env.OTEL_SERVICE_NAME, "1.5.
|
|
11862
|
+
providers = registerSdk2(process.env.OTEL_SERVICE_NAME, "1.5.7");
|
|
11833
11863
|
console.log(`[Observability] OTLP export \u2192 ${process.env.OTEL_EXPORTER_OTLP_ENDPOINT} (service.name=${process.env.OTEL_SERVICE_NAME}, capture_content=${config.observability.captureContent})`);
|
|
11834
11864
|
return true;
|
|
11835
11865
|
}
|
|
@@ -12115,7 +12145,7 @@ var init_genai_spans = __esm({
|
|
|
12115
12145
|
|
|
12116
12146
|
// ../server/dist/agents/session-manager.js
|
|
12117
12147
|
import fsSync7 from "node:fs";
|
|
12118
|
-
import
|
|
12148
|
+
import path33 from "node:path";
|
|
12119
12149
|
import { eq as eq10, and as and7, isNull as isNull4, isNotNull as isNotNull2 } from "drizzle-orm";
|
|
12120
12150
|
function simpleHash(str) {
|
|
12121
12151
|
let h = 0;
|
|
@@ -12313,7 +12343,7 @@ var init_session_manager = __esm({
|
|
|
12313
12343
|
}
|
|
12314
12344
|
constructor(workspaceRoot, opts) {
|
|
12315
12345
|
this.workspaceRoot = workspaceRoot;
|
|
12316
|
-
const haloDir =
|
|
12346
|
+
const haloDir = path33.join(workspaceRoot, ".halo");
|
|
12317
12347
|
this.db = createDb(haloDir);
|
|
12318
12348
|
this.uiStore = new SessionUIStore(this);
|
|
12319
12349
|
this.queryStore = new SessionQueryStore(this);
|
|
@@ -12426,9 +12456,9 @@ var init_session_manager = __esm({
|
|
|
12426
12456
|
*/
|
|
12427
12457
|
/** @internal */
|
|
12428
12458
|
async resolveWorkingDir(input) {
|
|
12429
|
-
const resolved =
|
|
12430
|
-
const wsRoot =
|
|
12431
|
-
if (resolved !== wsRoot && !resolved.startsWith(wsRoot +
|
|
12459
|
+
const resolved = path33.isAbsolute(input) ? path33.resolve(input) : path33.resolve(this.workspaceRoot, input);
|
|
12460
|
+
const wsRoot = path33.resolve(this.workspaceRoot);
|
|
12461
|
+
if (resolved !== wsRoot && !resolved.startsWith(wsRoot + path33.sep)) {
|
|
12432
12462
|
throw new Error(`working_dir "${input}" is outside the workspace`);
|
|
12433
12463
|
}
|
|
12434
12464
|
try {
|
|
@@ -12548,7 +12578,7 @@ var init_session_manager = __esm({
|
|
|
12548
12578
|
if (meta.archivedAt)
|
|
12549
12579
|
throw new Error(`Session ${sessionId} is archived and cannot be resumed`);
|
|
12550
12580
|
const restoredAccessLevel = meta.accessLevel === "readonly" ? "readonly" : meta.accessLevel === "workspace" ? "workspace" : null;
|
|
12551
|
-
const restoredWorkingDir = meta.workingDir ?
|
|
12581
|
+
const restoredWorkingDir = meta.workingDir ? path33.resolve(this.workspaceRoot, meta.workingDir) : void 0;
|
|
12552
12582
|
const { agent, yamlConfig: resumedYaml, contextConfig, modelId, systemPrompt, thinkingEffort, meta: agentMeta } = await this.buildAgentInstance(meta.agentId, sessionId, meta.parentId, restoredWorkingDir, restoredAccessLevel);
|
|
12553
12583
|
const savedMessages = this.loadAgentState(sessionId, meta.agentId);
|
|
12554
12584
|
if (savedMessages.length > 0) {
|
|
@@ -12617,7 +12647,7 @@ var init_session_manager = __esm({
|
|
|
12617
12647
|
agentId,
|
|
12618
12648
|
agentName: resolvedAgentName,
|
|
12619
12649
|
description,
|
|
12620
|
-
workingDir: workingDir ?
|
|
12650
|
+
workingDir: workingDir ? path33.relative(this.workspaceRoot, workingDir) : null,
|
|
12621
12651
|
accessLevel,
|
|
12622
12652
|
createdAt: now,
|
|
12623
12653
|
updatedAt: now
|
|
@@ -12626,7 +12656,7 @@ var init_session_manager = __esm({
|
|
|
12626
12656
|
try {
|
|
12627
12657
|
const dir = this.sessionDir(agentId);
|
|
12628
12658
|
fsSync7.mkdirSync(dir, { recursive: true });
|
|
12629
|
-
atomicWriteSessionFile(
|
|
12659
|
+
atomicWriteSessionFile(path33.join(dir, `${fileSegment(sessionId)}.json`), JSON.stringify({ id: sessionId, agentId, title, createdAt: new Date(now).toISOString() }));
|
|
12630
12660
|
} catch (err) {
|
|
12631
12661
|
console.warn(`[SessionManager] Failed to pre-seed title for ${sessionId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
12632
12662
|
}
|
|
@@ -12705,7 +12735,7 @@ var init_session_manager = __esm({
|
|
|
12705
12735
|
if (row.exchangeCount !== null)
|
|
12706
12736
|
return row.title || null;
|
|
12707
12737
|
try {
|
|
12708
|
-
const filePath =
|
|
12738
|
+
const filePath = path33.join(this.sessionDir(row.agentId), `${fileSegment(sessionId)}.json`);
|
|
12709
12739
|
const data = JSON.parse(fsSync7.readFileSync(filePath, "utf-8"));
|
|
12710
12740
|
return data.title || null;
|
|
12711
12741
|
} catch {
|
|
@@ -14195,7 +14225,7 @@ ${result.summary}`, agentName: "user", report: true, taskId });
|
|
|
14195
14225
|
live.agent.messages = repaired;
|
|
14196
14226
|
this.saveAgentState(live);
|
|
14197
14227
|
} else {
|
|
14198
|
-
const filePath =
|
|
14228
|
+
const filePath = path33.join(this.sessionDir(info.agentId), `${fileSegment(rootId)}.json`);
|
|
14199
14229
|
let data = {};
|
|
14200
14230
|
try {
|
|
14201
14231
|
data = JSON.parse(fsSync7.readFileSync(filePath, "utf-8"));
|
|
@@ -14351,7 +14381,7 @@ ${result.summary}`, agentName: "user", report: true, taskId });
|
|
|
14351
14381
|
lastActivityAt = session.lastActivityAt;
|
|
14352
14382
|
} else {
|
|
14353
14383
|
try {
|
|
14354
|
-
const filePath =
|
|
14384
|
+
const filePath = path33.join(this.sessionDir(meta.agentId), `${fileSegment(sessionId)}.json`);
|
|
14355
14385
|
const data = JSON.parse(fsSync7.readFileSync(filePath, "utf-8"));
|
|
14356
14386
|
output = typeof data.output === "string" ? data.output : "";
|
|
14357
14387
|
lastActivityAt = typeof data.lastActivityAt === "string" ? data.lastActivityAt : null;
|
|
@@ -14518,7 +14548,7 @@ var init_session_manager_registry = __esm({
|
|
|
14518
14548
|
|
|
14519
14549
|
// ../server/dist/logger.js
|
|
14520
14550
|
import fs27 from "node:fs";
|
|
14521
|
-
import
|
|
14551
|
+
import path34 from "node:path";
|
|
14522
14552
|
import { homedir as homedir13 } from "node:os";
|
|
14523
14553
|
import { SeverityNumber } from "@opentelemetry/api-logs";
|
|
14524
14554
|
function ensureDir() {
|
|
@@ -14641,8 +14671,8 @@ var init_logger = __esm({
|
|
|
14641
14671
|
init_config();
|
|
14642
14672
|
init_otel();
|
|
14643
14673
|
LOG_FILENAME = "server.log";
|
|
14644
|
-
logDir =
|
|
14645
|
-
logFile =
|
|
14674
|
+
logDir = path34.join(homedir13(), ".halo", "global", "logs");
|
|
14675
|
+
logFile = path34.join(logDir, LOG_FILENAME);
|
|
14646
14676
|
currentSize = -1;
|
|
14647
14677
|
LEVEL_ORDER = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
14648
14678
|
OTEL_SEVERITY = {
|
|
@@ -14662,17 +14692,18 @@ __export(harness_exports, {
|
|
|
14662
14692
|
listAgents: () => listAgents,
|
|
14663
14693
|
listSessions: () => listSessions
|
|
14664
14694
|
});
|
|
14665
|
-
import
|
|
14695
|
+
import path35 from "node:path";
|
|
14666
14696
|
import fs28 from "node:fs";
|
|
14667
14697
|
async function initRuntime() {
|
|
14668
14698
|
console.log = (...args) => process.stderr.write(args.map(String).join(" ") + "\n");
|
|
14699
|
+
refreshTemplatesIfOutdated(HALO_HOME3, "CLI");
|
|
14669
14700
|
initLogger();
|
|
14670
14701
|
await initBwrapCheck();
|
|
14671
14702
|
const { hiddenDirs, hiddenFiles } = resolveSandboxPaths();
|
|
14672
14703
|
setSandboxHiddenPaths(hiddenDirs, hiddenFiles);
|
|
14673
14704
|
}
|
|
14674
14705
|
async function listAgents(workspace) {
|
|
14675
|
-
const absWs =
|
|
14706
|
+
const absWs = path35.resolve(workspace);
|
|
14676
14707
|
ensureWorkspaceHalo(absWs);
|
|
14677
14708
|
const sm = new SessionManager(absWs);
|
|
14678
14709
|
const disabledSet = getDisabledSet(sm.getDb(), "agent");
|
|
@@ -14680,7 +14711,7 @@ async function listAgents(workspace) {
|
|
|
14680
14711
|
return agents.map((a) => ({ id: a.id, description: a.description, scope: a.scope }));
|
|
14681
14712
|
}
|
|
14682
14713
|
function listSessions(workspace) {
|
|
14683
|
-
const absWs =
|
|
14714
|
+
const absWs = path35.resolve(workspace);
|
|
14684
14715
|
ensureWorkspaceHalo(absWs);
|
|
14685
14716
|
const sm = new SessionManager(absWs);
|
|
14686
14717
|
const { sessions } = sm.listSessions({ limit: 200 });
|
|
@@ -14692,7 +14723,7 @@ async function agentSupportsImage(sm, workspace, agentId) {
|
|
|
14692
14723
|
return entry ? modelSupportsImage(entry.model) : false;
|
|
14693
14724
|
}
|
|
14694
14725
|
async function createHarness(opts) {
|
|
14695
|
-
const initialPath =
|
|
14726
|
+
const initialPath = path35.resolve(opts.workspace);
|
|
14696
14727
|
if (!fs28.existsSync(initialPath)) {
|
|
14697
14728
|
throw new Error(`Workspace does not exist: ${initialPath}`);
|
|
14698
14729
|
}
|
|
@@ -14864,7 +14895,7 @@ async function createHarness(opts) {
|
|
|
14864
14895
|
return Array.from(merged.values()).sort((a, b) => a.slashName.localeCompare(b.slashName));
|
|
14865
14896
|
}
|
|
14866
14897
|
async function switchWorkspace(newPath) {
|
|
14867
|
-
const resolved =
|
|
14898
|
+
const resolved = path35.resolve(newPath);
|
|
14868
14899
|
if (resolved === state.workspace) return;
|
|
14869
14900
|
if (!fs28.existsSync(resolved)) {
|
|
14870
14901
|
throw new Error(`Workspace does not exist: ${resolved}`);
|
|
@@ -14988,7 +15019,7 @@ __export(setup_config_exports, {
|
|
|
14988
15019
|
updateConfigLeaves: () => updateConfigLeaves
|
|
14989
15020
|
});
|
|
14990
15021
|
import fs29 from "node:fs";
|
|
14991
|
-
import
|
|
15022
|
+
import path36 from "node:path";
|
|
14992
15023
|
import { homedir as homedir14 } from "node:os";
|
|
14993
15024
|
import YAML8 from "yaml";
|
|
14994
15025
|
function updateConfigLeaves(updates) {
|
|
@@ -14999,7 +15030,7 @@ function updateConfigLeaves(updates) {
|
|
|
14999
15030
|
parts.push("value");
|
|
15000
15031
|
doc.setIn(parts, val);
|
|
15001
15032
|
}
|
|
15002
|
-
fs29.mkdirSync(
|
|
15033
|
+
fs29.mkdirSync(path36.dirname(CONFIG_PATH), { recursive: true });
|
|
15003
15034
|
fs29.writeFileSync(CONFIG_PATH, doc.toString(), { encoding: "utf-8", mode: 384 });
|
|
15004
15035
|
try {
|
|
15005
15036
|
fs29.chmodSync(CONFIG_PATH, 384);
|
|
@@ -15023,7 +15054,7 @@ var CONFIG_PATH;
|
|
|
15023
15054
|
var init_setup_config = __esm({
|
|
15024
15055
|
"../server/dist/setup-config.js"() {
|
|
15025
15056
|
"use strict";
|
|
15026
|
-
CONFIG_PATH =
|
|
15057
|
+
CONFIG_PATH = path36.join(homedir14(), ".halo", "secrets", "config.yaml");
|
|
15027
15058
|
}
|
|
15028
15059
|
});
|
|
15029
15060
|
|
|
@@ -15036,7 +15067,7 @@ __export(setup_settings_exports, {
|
|
|
15036
15067
|
writeSettings: () => writeSettings
|
|
15037
15068
|
});
|
|
15038
15069
|
import fs30 from "node:fs";
|
|
15039
|
-
import
|
|
15070
|
+
import path37 from "node:path";
|
|
15040
15071
|
import { homedir as homedir15 } from "node:os";
|
|
15041
15072
|
import YAML9 from "yaml";
|
|
15042
15073
|
function loadDoc() {
|
|
@@ -15048,7 +15079,7 @@ function loadDoc() {
|
|
|
15048
15079
|
return YAML9.parseDocument(raw);
|
|
15049
15080
|
}
|
|
15050
15081
|
function saveDoc(doc) {
|
|
15051
|
-
fs30.mkdirSync(
|
|
15082
|
+
fs30.mkdirSync(path37.dirname(SETTINGS_PATH2), { recursive: true });
|
|
15052
15083
|
fs30.writeFileSync(SETTINGS_PATH2, doc.toString({ lineWidth: 120 }), { encoding: "utf-8", mode: 384 });
|
|
15053
15084
|
try {
|
|
15054
15085
|
fs30.chmodSync(SETTINGS_PATH2, 384);
|
|
@@ -15108,7 +15139,7 @@ var SETTINGS_PATH2;
|
|
|
15108
15139
|
var init_setup_settings = __esm({
|
|
15109
15140
|
"../server/dist/setup-settings.js"() {
|
|
15110
15141
|
"use strict";
|
|
15111
|
-
SETTINGS_PATH2 =
|
|
15142
|
+
SETTINGS_PATH2 = path37.join(homedir15(), ".halo", "secrets", "settings.yaml");
|
|
15112
15143
|
}
|
|
15113
15144
|
});
|
|
15114
15145
|
|
|
@@ -15125,7 +15156,7 @@ __export(setup_providers_exports, {
|
|
|
15125
15156
|
readDefaultAgentProvider: () => readDefaultAgentProvider
|
|
15126
15157
|
});
|
|
15127
15158
|
import fs31 from "node:fs";
|
|
15128
|
-
import
|
|
15159
|
+
import path38 from "node:path";
|
|
15129
15160
|
import { homedir as homedir16 } from "node:os";
|
|
15130
15161
|
import YAML10 from "yaml";
|
|
15131
15162
|
function readYamlFile2(filePath) {
|
|
@@ -15155,14 +15186,14 @@ function parseFields(raw) {
|
|
|
15155
15186
|
})).filter((f) => f.key.length > 0);
|
|
15156
15187
|
}
|
|
15157
15188
|
function listModelProviders() {
|
|
15158
|
-
const dir =
|
|
15189
|
+
const dir = path38.join(TEMPLATES_DIR, "models");
|
|
15159
15190
|
if (!fs31.existsSync(dir))
|
|
15160
15191
|
return [];
|
|
15161
15192
|
const out = [];
|
|
15162
15193
|
for (const f of fs31.readdirSync(dir)) {
|
|
15163
15194
|
if (!f.endsWith(".yaml"))
|
|
15164
15195
|
continue;
|
|
15165
|
-
const data = readYamlFile2(
|
|
15196
|
+
const data = readYamlFile2(path38.join(dir, f));
|
|
15166
15197
|
if (!data || typeof data !== "object")
|
|
15167
15198
|
continue;
|
|
15168
15199
|
const id = typeof data.id === "string" ? data.id : f.replace(/\.yaml$/, "");
|
|
@@ -15177,15 +15208,15 @@ function listModelProviders() {
|
|
|
15177
15208
|
return out.sort((a, b) => a.id.localeCompare(b.id));
|
|
15178
15209
|
}
|
|
15179
15210
|
function listOptionalSkills() {
|
|
15180
|
-
const dir =
|
|
15211
|
+
const dir = path38.join(TEMPLATES_DIR, "optional-skills");
|
|
15181
15212
|
if (!fs31.existsSync(dir))
|
|
15182
15213
|
return [];
|
|
15183
15214
|
const out = [];
|
|
15184
15215
|
for (const id of fs31.readdirSync(dir)) {
|
|
15185
|
-
const skillDir =
|
|
15216
|
+
const skillDir = path38.join(dir, id);
|
|
15186
15217
|
if (!fs31.statSync(skillDir).isDirectory())
|
|
15187
15218
|
continue;
|
|
15188
|
-
const skillMd =
|
|
15219
|
+
const skillMd = path38.join(skillDir, "SKILL.md");
|
|
15189
15220
|
if (!fs31.existsSync(skillMd))
|
|
15190
15221
|
continue;
|
|
15191
15222
|
const text6 = fs31.readFileSync(skillMd, "utf-8");
|
|
@@ -15204,7 +15235,7 @@ function listOptionalSkills() {
|
|
|
15204
15235
|
} catch {
|
|
15205
15236
|
}
|
|
15206
15237
|
}
|
|
15207
|
-
const cfg = readYamlFile2(
|
|
15238
|
+
const cfg = readYamlFile2(path38.join(skillDir, "config.yaml"));
|
|
15208
15239
|
out.push({
|
|
15209
15240
|
id,
|
|
15210
15241
|
name,
|
|
@@ -15226,7 +15257,7 @@ function listConfiguredSwitchableProviders() {
|
|
|
15226
15257
|
});
|
|
15227
15258
|
}
|
|
15228
15259
|
function readDefaultAgentProvider() {
|
|
15229
|
-
const data = readYamlFile2(
|
|
15260
|
+
const data = readYamlFile2(path38.join(GLOBAL_AGENTS_DIR3, "default", "agent.yaml"));
|
|
15230
15261
|
const provider = data?.model && typeof data.model === "object" ? data.model.provider : void 0;
|
|
15231
15262
|
return typeof provider === "string" && provider.length > 0 ? provider : void 0;
|
|
15232
15263
|
}
|
|
@@ -15256,7 +15287,7 @@ function modelBlockFromProvider(providerId, data) {
|
|
|
15256
15287
|
return block;
|
|
15257
15288
|
}
|
|
15258
15289
|
function buildTemplateModelBlock(providerId) {
|
|
15259
|
-
const data = readYamlFile2(
|
|
15290
|
+
const data = readYamlFile2(path38.join(TEMPLATES_DIR, "models", `${providerId}.yaml`));
|
|
15260
15291
|
if (!data || typeof data !== "object")
|
|
15261
15292
|
return null;
|
|
15262
15293
|
return modelBlockFromProvider(providerId, data);
|
|
@@ -15267,7 +15298,7 @@ function bindBuiltinAgentsToProvider(providerId) {
|
|
|
15267
15298
|
return null;
|
|
15268
15299
|
const agents = [];
|
|
15269
15300
|
for (const id of REBIND_BUILTIN_AGENT_IDS) {
|
|
15270
|
-
const yamlPath =
|
|
15301
|
+
const yamlPath = path38.join(GLOBAL_AGENTS_DIR3, id, "agent.yaml");
|
|
15271
15302
|
if (!fs31.existsSync(yamlPath))
|
|
15272
15303
|
continue;
|
|
15273
15304
|
try {
|
|
@@ -15281,22 +15312,22 @@ function bindBuiltinAgentsToProvider(providerId) {
|
|
|
15281
15312
|
return { modelId: typeof block.id === "string" ? block.id : void 0, agents };
|
|
15282
15313
|
}
|
|
15283
15314
|
function listRequiredSkillsWithSecrets() {
|
|
15284
|
-
const dir =
|
|
15315
|
+
const dir = path38.join(TEMPLATES_DIR, "skills");
|
|
15285
15316
|
if (!fs31.existsSync(dir))
|
|
15286
15317
|
return [];
|
|
15287
15318
|
const out = [];
|
|
15288
15319
|
for (const id of fs31.readdirSync(dir)) {
|
|
15289
|
-
const skillDir =
|
|
15320
|
+
const skillDir = path38.join(dir, id);
|
|
15290
15321
|
if (!fs31.statSync(skillDir).isDirectory())
|
|
15291
15322
|
continue;
|
|
15292
|
-
const cfgPath =
|
|
15323
|
+
const cfgPath = path38.join(skillDir, "config.yaml");
|
|
15293
15324
|
if (!fs31.existsSync(cfgPath))
|
|
15294
15325
|
continue;
|
|
15295
15326
|
const cfg = readYamlFile2(cfgPath);
|
|
15296
15327
|
const fields = parseFields(cfg?.params).filter((f) => f.secret);
|
|
15297
15328
|
if (fields.length === 0)
|
|
15298
15329
|
continue;
|
|
15299
|
-
const skillMd =
|
|
15330
|
+
const skillMd = path38.join(skillDir, "SKILL.md");
|
|
15300
15331
|
let name = id;
|
|
15301
15332
|
let description = "";
|
|
15302
15333
|
if (fs31.existsSync(skillMd)) {
|
|
@@ -15327,7 +15358,7 @@ var init_setup_providers = __esm({
|
|
|
15327
15358
|
init_setup_settings();
|
|
15328
15359
|
AWS_CREDENTIAL_CHAIN_PROVIDER = "aws-bedrock-claude-invoke";
|
|
15329
15360
|
REBIND_BUILTIN_AGENT_IDS = ["default", "executor", "deep-executor"];
|
|
15330
|
-
GLOBAL_AGENTS_DIR3 =
|
|
15361
|
+
GLOBAL_AGENTS_DIR3 = path38.join(homedir16(), ".halo", "global", "agents");
|
|
15331
15362
|
}
|
|
15332
15363
|
});
|
|
15333
15364
|
|
|
@@ -15645,13 +15676,13 @@ __export(upgrade_verify_exports, {
|
|
|
15645
15676
|
NATIVE_MODULE_SMOKES: () => NATIVE_MODULE_SMOKES,
|
|
15646
15677
|
verifyNativeModules: () => verifyNativeModules
|
|
15647
15678
|
});
|
|
15648
|
-
import
|
|
15679
|
+
import path39 from "node:path";
|
|
15649
15680
|
import fs32 from "node:fs";
|
|
15650
15681
|
import { spawnSync } from "node:child_process";
|
|
15651
15682
|
function verifyNativeModules(pkgRoot) {
|
|
15652
15683
|
const broken = [];
|
|
15653
15684
|
for (const { name, smoke } of NATIVE_MODULE_SMOKES) {
|
|
15654
|
-
const modDir =
|
|
15685
|
+
const modDir = path39.join(pkgRoot, "node_modules", name);
|
|
15655
15686
|
if (!fs32.existsSync(modDir)) {
|
|
15656
15687
|
broken.push(name);
|
|
15657
15688
|
continue;
|
|
@@ -15690,7 +15721,7 @@ var init_render_md = __esm({
|
|
|
15690
15721
|
|
|
15691
15722
|
// src/resolve-refs.ts
|
|
15692
15723
|
import fs33 from "node:fs";
|
|
15693
|
-
import
|
|
15724
|
+
import path40 from "node:path";
|
|
15694
15725
|
function resolveRefs(input, workspace) {
|
|
15695
15726
|
const images = [];
|
|
15696
15727
|
const attachments = [];
|
|
@@ -15703,8 +15734,8 @@ function resolveRefs(input, workspace) {
|
|
|
15703
15734
|
lastIdx = match.index + match[0].length;
|
|
15704
15735
|
const kind = match[1];
|
|
15705
15736
|
const rawPath = match[2] ?? match[3];
|
|
15706
|
-
const resolved =
|
|
15707
|
-
const ext =
|
|
15737
|
+
const resolved = path40.isAbsolute(rawPath) ? rawPath : path40.resolve(workspace, rawPath);
|
|
15738
|
+
const ext = path40.extname(resolved).toLowerCase();
|
|
15708
15739
|
let stat = null;
|
|
15709
15740
|
try {
|
|
15710
15741
|
stat = fs33.statSync(resolved);
|
|
@@ -15728,7 +15759,7 @@ function resolveRefs(input, workspace) {
|
|
|
15728
15759
|
const data = fs33.readFileSync(resolved).toString("base64");
|
|
15729
15760
|
images.push({ data, mimeType: imageMimeFromExt(ext) ?? "application/octet-stream" });
|
|
15730
15761
|
} else {
|
|
15731
|
-
const relPath =
|
|
15762
|
+
const relPath = path40.relative(workspace, resolved);
|
|
15732
15763
|
if (stat.size > MAX_FILE_BYTES) {
|
|
15733
15764
|
const buf = Buffer.alloc(MAX_FILE_BYTES);
|
|
15734
15765
|
const fd = fs33.openSync(resolved, "r");
|
|
@@ -16020,7 +16051,7 @@ var init_streaming = __esm({
|
|
|
16020
16051
|
|
|
16021
16052
|
// src/tui/history.ts
|
|
16022
16053
|
import fs34 from "node:fs";
|
|
16023
|
-
import
|
|
16054
|
+
import path41 from "node:path";
|
|
16024
16055
|
import os2 from "node:os";
|
|
16025
16056
|
function loadHistory() {
|
|
16026
16057
|
try {
|
|
@@ -16037,7 +16068,7 @@ function appendHistory(entry) {
|
|
|
16037
16068
|
const arr = loadHistory();
|
|
16038
16069
|
if (arr[arr.length - 1] === entry) return;
|
|
16039
16070
|
arr.push(entry);
|
|
16040
|
-
fs34.mkdirSync(
|
|
16071
|
+
fs34.mkdirSync(path41.dirname(HISTORY_FILE), { recursive: true });
|
|
16041
16072
|
fs34.writeFileSync(HISTORY_FILE, JSON.stringify(arr.slice(-MAX_ENTRIES)));
|
|
16042
16073
|
} catch {
|
|
16043
16074
|
}
|
|
@@ -16046,7 +16077,7 @@ var HISTORY_FILE, MAX_ENTRIES;
|
|
|
16046
16077
|
var init_history = __esm({
|
|
16047
16078
|
"src/tui/history.ts"() {
|
|
16048
16079
|
"use strict";
|
|
16049
|
-
HISTORY_FILE =
|
|
16080
|
+
HISTORY_FILE = path41.join(os2.homedir(), ".halo", "global", "tui-history.json");
|
|
16050
16081
|
MAX_ENTRIES = 100;
|
|
16051
16082
|
}
|
|
16052
16083
|
});
|
|
@@ -16151,7 +16182,7 @@ var init_path_suggest = __esm({
|
|
|
16151
16182
|
|
|
16152
16183
|
// src/tui/path-suggest-engine.ts
|
|
16153
16184
|
import fs35 from "node:fs";
|
|
16154
|
-
import
|
|
16185
|
+
import path42 from "node:path";
|
|
16155
16186
|
function detectActiveRef(value) {
|
|
16156
16187
|
const reExplicit = /@(file|image|scope)\s+(?:"([^"]*)|(\S*))$/;
|
|
16157
16188
|
const mExplicit = value.match(reExplicit);
|
|
@@ -16180,13 +16211,13 @@ function resolveDirAndPrefix(partial, workspace) {
|
|
|
16180
16211
|
if (partial === "") {
|
|
16181
16212
|
return { absDir: workspace, displayDir: ".", prefix: "" };
|
|
16182
16213
|
}
|
|
16183
|
-
const absBase =
|
|
16214
|
+
const absBase = path42.isAbsolute(partial) ? partial : path42.join(workspace, partial);
|
|
16184
16215
|
if (partial.endsWith("/")) {
|
|
16185
16216
|
return { absDir: absBase, displayDir: partial.replace(/\/$/, "") || "/", prefix: "" };
|
|
16186
16217
|
}
|
|
16187
|
-
const dirAbs =
|
|
16188
|
-
const prefix =
|
|
16189
|
-
const dirRel =
|
|
16218
|
+
const dirAbs = path42.dirname(absBase);
|
|
16219
|
+
const prefix = path42.basename(absBase);
|
|
16220
|
+
const dirRel = path42.dirname(partial);
|
|
16190
16221
|
return { absDir: dirAbs, displayDir: dirRel === "." ? "." : dirRel, prefix };
|
|
16191
16222
|
}
|
|
16192
16223
|
function scanCandidates(partial, workspace, kind) {
|
|
@@ -16202,17 +16233,17 @@ function scanCandidates(partial, workspace, kind) {
|
|
|
16202
16233
|
if (e.name.startsWith(".")) continue;
|
|
16203
16234
|
if (prefix && !e.name.toLowerCase().startsWith(prefix.toLowerCase())) continue;
|
|
16204
16235
|
const isDir = e.isDirectory();
|
|
16205
|
-
const ext =
|
|
16236
|
+
const ext = path42.extname(e.name).toLowerCase();
|
|
16206
16237
|
const isImage = IMAGE_EXTS.has(ext);
|
|
16207
16238
|
if (kind === "image" && !isDir && !isImage) continue;
|
|
16208
16239
|
if (kind === "scope" && !isDir) continue;
|
|
16209
16240
|
let insertPath;
|
|
16210
|
-
if (
|
|
16211
|
-
insertPath =
|
|
16241
|
+
if (path42.isAbsolute(partial)) {
|
|
16242
|
+
insertPath = path42.join(absDir, e.name);
|
|
16212
16243
|
} else if (partial.endsWith("/") || partial === "") {
|
|
16213
16244
|
insertPath = partial + e.name;
|
|
16214
16245
|
} else {
|
|
16215
|
-
const dirRel =
|
|
16246
|
+
const dirRel = path42.dirname(partial);
|
|
16216
16247
|
insertPath = (dirRel === "." ? "" : dirRel + "/") + e.name;
|
|
16217
16248
|
}
|
|
16218
16249
|
items.push({ name: e.name, insertPath, isDir, isImage });
|
|
@@ -16231,8 +16262,8 @@ function applyPathPick(value, ref, pick) {
|
|
|
16231
16262
|
const before = value.slice(0, markerStart);
|
|
16232
16263
|
const kind = ref.kind === "scope" ? "scope" : ref.kind === "image" ? "image" : pick.isImage ? "image" : "file";
|
|
16233
16264
|
const needsQuote = pick.insertPath.includes(" ");
|
|
16234
|
-
const
|
|
16235
|
-
return `${before}@${kind} ${
|
|
16265
|
+
const path74 = pick.isDir ? needsQuote ? `"${pick.insertPath}/` : `${pick.insertPath}/` : needsQuote ? `"${pick.insertPath}" ` : `${pick.insertPath} `;
|
|
16266
|
+
return `${before}@${kind} ${path74}`;
|
|
16236
16267
|
}
|
|
16237
16268
|
var init_path_suggest_engine = __esm({
|
|
16238
16269
|
"src/tui/path-suggest-engine.ts"() {
|
|
@@ -17713,15 +17744,15 @@ var init_cli = __esm({
|
|
|
17713
17744
|
});
|
|
17714
17745
|
|
|
17715
17746
|
// ../server/dist/channels/shared/media.js
|
|
17716
|
-
import
|
|
17747
|
+
import path43 from "node:path";
|
|
17717
17748
|
import os3 from "node:os";
|
|
17718
17749
|
function tempDir() {
|
|
17719
|
-
return
|
|
17750
|
+
return path43.resolve(os3.tmpdir());
|
|
17720
17751
|
}
|
|
17721
17752
|
function isInTempDir(filePath) {
|
|
17722
|
-
const resolved =
|
|
17753
|
+
const resolved = path43.resolve(filePath);
|
|
17723
17754
|
const tmp = tempDir();
|
|
17724
|
-
return resolved === tmp || resolved.startsWith(tmp +
|
|
17755
|
+
return resolved === tmp || resolved.startsWith(tmp + path43.sep);
|
|
17725
17756
|
}
|
|
17726
17757
|
function extractMediaPaths(text6) {
|
|
17727
17758
|
const mediaPaths = [];
|
|
@@ -17739,9 +17770,9 @@ function extractMediaMessage(text6) {
|
|
|
17739
17770
|
function isMediaPathAllowed(filePath, workspacePath, accessLevel) {
|
|
17740
17771
|
if (accessLevel === "full")
|
|
17741
17772
|
return true;
|
|
17742
|
-
const resolved =
|
|
17743
|
-
const ws =
|
|
17744
|
-
return resolved === ws || resolved.startsWith(ws +
|
|
17773
|
+
const resolved = path43.resolve(filePath);
|
|
17774
|
+
const ws = path43.resolve(workspacePath);
|
|
17775
|
+
return resolved === ws || resolved.startsWith(ws + path43.sep) || isInTempDir(resolved);
|
|
17745
17776
|
}
|
|
17746
17777
|
function assertMediaPathAllowed(filePath, account) {
|
|
17747
17778
|
if (!isMediaPathAllowed(filePath, account.workspacePath, account.accessLevel)) {
|
|
@@ -17756,12 +17787,12 @@ async function sendMediaOrReport(opts) {
|
|
|
17756
17787
|
} catch (err) {
|
|
17757
17788
|
const error = err instanceof Error ? err.message : String(err);
|
|
17758
17789
|
console.log(`[${opts.logTag}] sendMedia ${filePath} failed: ${error}`);
|
|
17759
|
-
await opts.reply(t("handler.upload_failed", getLang(account), { name:
|
|
17790
|
+
await opts.reply(t("handler.upload_failed", getLang(account), { name: path43.basename(filePath), error })).catch(() => {
|
|
17760
17791
|
});
|
|
17761
17792
|
}
|
|
17762
17793
|
}
|
|
17763
17794
|
function classifyMedia(filePath) {
|
|
17764
|
-
const ext =
|
|
17795
|
+
const ext = path43.extname(filePath).toLowerCase();
|
|
17765
17796
|
if (IMAGE_EXTS.has(ext))
|
|
17766
17797
|
return "image";
|
|
17767
17798
|
if (VIDEO_EXTS.has(ext))
|
|
@@ -17785,9 +17816,9 @@ var init_media = __esm({
|
|
|
17785
17816
|
// ../server/dist/routes/workspace-path.js
|
|
17786
17817
|
import fs36 from "node:fs/promises";
|
|
17787
17818
|
import { existsSync as existsSync2, realpathSync as realpathSync3 } from "node:fs";
|
|
17788
|
-
import
|
|
17819
|
+
import path44 from "node:path";
|
|
17789
17820
|
async function resolveProjectPath(projectId) {
|
|
17790
|
-
if (
|
|
17821
|
+
if (path44.isAbsolute(projectId)) {
|
|
17791
17822
|
try {
|
|
17792
17823
|
await fs36.access(projectId);
|
|
17793
17824
|
return projectId;
|
|
@@ -17798,13 +17829,13 @@ async function resolveProjectPath(projectId) {
|
|
|
17798
17829
|
return null;
|
|
17799
17830
|
}
|
|
17800
17831
|
function realpathBounded2(filePath) {
|
|
17801
|
-
let prefix =
|
|
17832
|
+
let prefix = path44.resolve(filePath);
|
|
17802
17833
|
const tail = [];
|
|
17803
17834
|
while (!existsSync2(prefix)) {
|
|
17804
|
-
const parent =
|
|
17835
|
+
const parent = path44.dirname(prefix);
|
|
17805
17836
|
if (parent === prefix)
|
|
17806
17837
|
break;
|
|
17807
|
-
tail.unshift(
|
|
17838
|
+
tail.unshift(path44.basename(prefix));
|
|
17808
17839
|
prefix = parent;
|
|
17809
17840
|
}
|
|
17810
17841
|
let realPrefix;
|
|
@@ -17813,12 +17844,12 @@ function realpathBounded2(filePath) {
|
|
|
17813
17844
|
} catch {
|
|
17814
17845
|
realPrefix = prefix;
|
|
17815
17846
|
}
|
|
17816
|
-
return tail.length > 0 ?
|
|
17847
|
+
return tail.length > 0 ? path44.join(realPrefix, ...tail) : realPrefix;
|
|
17817
17848
|
}
|
|
17818
17849
|
function validatePath(filePath, projectPath) {
|
|
17819
|
-
const resolved = realpathBounded2(
|
|
17850
|
+
const resolved = realpathBounded2(path44.resolve(projectPath, filePath));
|
|
17820
17851
|
const proj = realpathBounded2(projectPath);
|
|
17821
|
-
return resolved === proj || resolved.startsWith(proj +
|
|
17852
|
+
return resolved === proj || resolved.startsWith(proj + path44.sep);
|
|
17822
17853
|
}
|
|
17823
17854
|
function isSafeIdSegment(id) {
|
|
17824
17855
|
if (id === "." || id === "..")
|
|
@@ -17836,7 +17867,7 @@ import { Hono } from "hono";
|
|
|
17836
17867
|
import fs37 from "node:fs/promises";
|
|
17837
17868
|
import { createReadStream } from "node:fs";
|
|
17838
17869
|
import { Readable } from "node:stream";
|
|
17839
|
-
import
|
|
17870
|
+
import path45 from "node:path";
|
|
17840
17871
|
import { homedir as homedir17 } from "node:os";
|
|
17841
17872
|
async function resolveProjectFile(projectId, filePath) {
|
|
17842
17873
|
const projectPath = await resolveProjectPath(projectId);
|
|
@@ -17844,7 +17875,7 @@ async function resolveProjectFile(projectId, filePath) {
|
|
|
17844
17875
|
return { error: "Project not found", status: 404 };
|
|
17845
17876
|
if (!validatePath(filePath, projectPath))
|
|
17846
17877
|
return { error: "Path traversal not allowed", status: 403 };
|
|
17847
|
-
return { projectPath, absolutePath:
|
|
17878
|
+
return { projectPath, absolutePath: path45.resolve(projectPath, filePath) };
|
|
17848
17879
|
}
|
|
17849
17880
|
function createFileRoutes() {
|
|
17850
17881
|
const app2 = new Hono();
|
|
@@ -17889,8 +17920,8 @@ function createFileRoutes() {
|
|
|
17889
17920
|
for (const entry of sorted) {
|
|
17890
17921
|
if (isSkippedName(entry.name))
|
|
17891
17922
|
continue;
|
|
17892
|
-
const fullPath =
|
|
17893
|
-
const relativePath =
|
|
17923
|
+
const fullPath = path45.join(dirPath, entry.name);
|
|
17924
|
+
const relativePath = path45.relative(basePath, fullPath).split(path45.sep).join("/");
|
|
17894
17925
|
if (entry.isDirectory()) {
|
|
17895
17926
|
nodes.push({
|
|
17896
17927
|
name: entry.name,
|
|
@@ -17922,7 +17953,7 @@ function createFileRoutes() {
|
|
|
17922
17953
|
if (relPath && !validatePath(relPath, projectPath)) {
|
|
17923
17954
|
return c.json({ error: "Path traversal not allowed" }, 403);
|
|
17924
17955
|
}
|
|
17925
|
-
const targetPath = relPath ?
|
|
17956
|
+
const targetPath = relPath ? path45.resolve(projectPath, relPath) : projectPath;
|
|
17926
17957
|
try {
|
|
17927
17958
|
const stat = await fs37.stat(targetPath);
|
|
17928
17959
|
if (!stat.isDirectory()) {
|
|
@@ -17934,7 +17965,7 @@ function createFileRoutes() {
|
|
|
17934
17965
|
const tree = await listDir(targetPath, projectPath);
|
|
17935
17966
|
return c.json({
|
|
17936
17967
|
projectId,
|
|
17937
|
-
root:
|
|
17968
|
+
root: path45.basename(projectPath),
|
|
17938
17969
|
path: relPath,
|
|
17939
17970
|
tree
|
|
17940
17971
|
});
|
|
@@ -17977,11 +18008,11 @@ function createFileRoutes() {
|
|
|
17977
18008
|
if (isSkippedName(entry.name))
|
|
17978
18009
|
continue;
|
|
17979
18010
|
scanned++;
|
|
17980
|
-
const fullPath =
|
|
18011
|
+
const fullPath = path45.join(dirPath, entry.name);
|
|
17981
18012
|
if (entry.isDirectory()) {
|
|
17982
18013
|
if (dirsOnly) {
|
|
17983
18014
|
const name = entry.name.toLowerCase();
|
|
17984
|
-
const rel =
|
|
18015
|
+
const rel = path45.relative(projectRoot, fullPath);
|
|
17985
18016
|
if (!q || name.includes(q) || rel.toLowerCase().includes(q)) {
|
|
17986
18017
|
matches.push({ name: entry.name, path: rel });
|
|
17987
18018
|
}
|
|
@@ -17989,7 +18020,7 @@ function createFileRoutes() {
|
|
|
17989
18020
|
await walk(fullPath);
|
|
17990
18021
|
} else if (entry.isFile() && !dirsOnly) {
|
|
17991
18022
|
const name = entry.name.toLowerCase();
|
|
17992
|
-
const rel =
|
|
18023
|
+
const rel = path45.relative(projectRoot, fullPath);
|
|
17993
18024
|
if (!q || name.includes(q) || rel.toLowerCase().includes(q)) {
|
|
17994
18025
|
matches.push({ name: entry.name, path: rel });
|
|
17995
18026
|
}
|
|
@@ -18033,12 +18064,12 @@ function createFileRoutes() {
|
|
|
18033
18064
|
}
|
|
18034
18065
|
const uploaded = [];
|
|
18035
18066
|
for (const file of files) {
|
|
18036
|
-
const relPath = targetDir ?
|
|
18067
|
+
const relPath = targetDir ? path45.join(targetDir, file.name) : file.name;
|
|
18037
18068
|
if (!validatePath(relPath, projectPath)) {
|
|
18038
18069
|
continue;
|
|
18039
18070
|
}
|
|
18040
|
-
const destPath =
|
|
18041
|
-
const destDir =
|
|
18071
|
+
const destPath = path45.resolve(projectPath, relPath);
|
|
18072
|
+
const destDir = path45.dirname(destPath);
|
|
18042
18073
|
await fs37.mkdir(destDir, { recursive: true });
|
|
18043
18074
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
18044
18075
|
await fs37.writeFile(destPath, buffer);
|
|
@@ -18124,7 +18155,7 @@ function createFileRoutes() {
|
|
|
18124
18155
|
if ("error" in resolved)
|
|
18125
18156
|
return c.json({ error: resolved.error }, resolved.status);
|
|
18126
18157
|
const { absolutePath } = resolved;
|
|
18127
|
-
await fs37.mkdir(
|
|
18158
|
+
await fs37.mkdir(path45.dirname(absolutePath), { recursive: true });
|
|
18128
18159
|
try {
|
|
18129
18160
|
await fs37.access(absolutePath);
|
|
18130
18161
|
return c.json({ error: "File already exists" }, 409);
|
|
@@ -18170,9 +18201,9 @@ function createFileRoutes() {
|
|
|
18170
18201
|
if (!validatePath(oldPath, projectPath) || !validatePath(newPath, projectPath)) {
|
|
18171
18202
|
return c.json({ error: "Path traversal not allowed" }, 403);
|
|
18172
18203
|
}
|
|
18173
|
-
const absOld =
|
|
18174
|
-
const absNew =
|
|
18175
|
-
await fs37.mkdir(
|
|
18204
|
+
const absOld = path45.resolve(projectPath, oldPath);
|
|
18205
|
+
const absNew = path45.resolve(projectPath, newPath);
|
|
18206
|
+
await fs37.mkdir(path45.dirname(absNew), { recursive: true });
|
|
18176
18207
|
await fs37.rename(absOld, absNew);
|
|
18177
18208
|
return c.json({ ok: true, oldPath, newPath });
|
|
18178
18209
|
} catch (err) {
|
|
@@ -18192,7 +18223,7 @@ function createFileRoutes() {
|
|
|
18192
18223
|
if ("error" in resolved)
|
|
18193
18224
|
return c.json({ error: resolved.error }, resolved.status);
|
|
18194
18225
|
const { projectPath, absolutePath } = resolved;
|
|
18195
|
-
if (absolutePath ===
|
|
18226
|
+
if (absolutePath === path45.resolve(projectPath)) {
|
|
18196
18227
|
return c.json({ error: "Cannot delete project root" }, 403);
|
|
18197
18228
|
}
|
|
18198
18229
|
await fs37.rm(absolutePath, { recursive: true, force: true });
|
|
@@ -18230,16 +18261,16 @@ function createFileRoutes() {
|
|
|
18230
18261
|
if (!projectPath) {
|
|
18231
18262
|
return c.json({ error: "Project not found" }, 404);
|
|
18232
18263
|
}
|
|
18233
|
-
const isTmp =
|
|
18264
|
+
const isTmp = path45.isAbsolute(filePath) && isInTempDir(filePath);
|
|
18234
18265
|
if (!isTmp && !validatePath(filePath, projectPath)) {
|
|
18235
18266
|
return c.json({ error: "Path traversal not allowed" }, 403);
|
|
18236
18267
|
}
|
|
18237
|
-
const absolutePath = isTmp ?
|
|
18268
|
+
const absolutePath = isTmp ? path45.resolve(filePath) : path45.resolve(projectPath, filePath);
|
|
18238
18269
|
const stat = await fs37.stat(absolutePath);
|
|
18239
18270
|
if (stat.isDirectory()) {
|
|
18240
18271
|
return c.json({ error: "Cannot download a directory" }, 400);
|
|
18241
18272
|
}
|
|
18242
|
-
const fileName =
|
|
18273
|
+
const fileName = path45.basename(filePath);
|
|
18243
18274
|
const ext = fileName.split(".").pop()?.toLowerCase() ?? "";
|
|
18244
18275
|
const mime = inline ? imageMimeFromExt(ext) ?? MIME_MAP[ext] ?? "application/octet-stream" : "application/octet-stream";
|
|
18245
18276
|
const disposition = inline ? `inline; filename="${encodeURIComponent(fileName)}"` : `attachment; filename="${encodeURIComponent(fileName)}"`;
|
|
@@ -18351,7 +18382,7 @@ function createFileRoutes() {
|
|
|
18351
18382
|
const body = await c.req.json();
|
|
18352
18383
|
if (!body.path)
|
|
18353
18384
|
return c.json({ error: "path required" }, 400);
|
|
18354
|
-
const resolved =
|
|
18385
|
+
const resolved = path45.resolve(body.path);
|
|
18355
18386
|
let stat;
|
|
18356
18387
|
try {
|
|
18357
18388
|
stat = await fs37.stat(resolved);
|
|
@@ -18360,7 +18391,7 @@ function createFileRoutes() {
|
|
|
18360
18391
|
}
|
|
18361
18392
|
if (!stat.isDirectory())
|
|
18362
18393
|
return c.json({ error: "not a directory" }, 400);
|
|
18363
|
-
if (resolved ===
|
|
18394
|
+
if (resolved === path45.parse(resolved).root) {
|
|
18364
18395
|
return c.json({ error: "filesystem root cannot be a workspace" }, 400);
|
|
18365
18396
|
}
|
|
18366
18397
|
const { ensureWorkspaceHalo: ensureWorkspaceHalo2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
@@ -18369,7 +18400,7 @@ function createFileRoutes() {
|
|
|
18369
18400
|
});
|
|
18370
18401
|
app2.get("/fs/exists", async (c) => {
|
|
18371
18402
|
const target = c.req.query("path");
|
|
18372
|
-
if (!target || !
|
|
18403
|
+
if (!target || !path45.isAbsolute(target))
|
|
18373
18404
|
return c.json({ exists: false, reason: "absolute path required" });
|
|
18374
18405
|
try {
|
|
18375
18406
|
const stat = await fs37.stat(target);
|
|
@@ -18380,13 +18411,13 @@ function createFileRoutes() {
|
|
|
18380
18411
|
});
|
|
18381
18412
|
app2.get("/fs/browse", async (c) => {
|
|
18382
18413
|
const target = c.req.query("path") ?? homedir17();
|
|
18383
|
-
if (!
|
|
18414
|
+
if (!path45.isAbsolute(target))
|
|
18384
18415
|
return c.json({ error: "absolute path required" }, 400);
|
|
18385
18416
|
try {
|
|
18386
|
-
const resolved =
|
|
18417
|
+
const resolved = path45.resolve(target);
|
|
18387
18418
|
const entries = await fs37.readdir(resolved, { withFileTypes: true });
|
|
18388
|
-
const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => ({ name: e.name, path:
|
|
18389
|
-
return c.json({ path: resolved, parent:
|
|
18419
|
+
const dirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => ({ name: e.name, path: path45.join(resolved, e.name) })).sort((a, b) => a.name.localeCompare(b.name));
|
|
18420
|
+
return c.json({ path: resolved, parent: path45.dirname(resolved), entries: dirs });
|
|
18390
18421
|
} catch (err) {
|
|
18391
18422
|
return c.json({ error: err.message }, 404);
|
|
18392
18423
|
}
|
|
@@ -18406,7 +18437,7 @@ var init_files = __esm({
|
|
|
18406
18437
|
import { Hono as Hono2 } from "hono";
|
|
18407
18438
|
import fs38 from "node:fs/promises";
|
|
18408
18439
|
import { createReadStream as createReadStream2 } from "node:fs";
|
|
18409
|
-
import
|
|
18440
|
+
import path46 from "node:path";
|
|
18410
18441
|
import Database5 from "better-sqlite3";
|
|
18411
18442
|
import { asyncBufferFromFile, parquetMetadataAsync, parquetSchema, parquetReadObjects } from "hyparquet";
|
|
18412
18443
|
import { compressors } from "hyparquet-compressors";
|
|
@@ -18521,7 +18552,7 @@ function createDataPreviewRoutes() {
|
|
|
18521
18552
|
return { error: "Project not found", status: 404 };
|
|
18522
18553
|
if (!validatePath(filePath, projectPath))
|
|
18523
18554
|
return { error: "Path traversal not allowed", status: 403 };
|
|
18524
|
-
const absolutePath =
|
|
18555
|
+
const absolutePath = path46.resolve(projectPath, filePath);
|
|
18525
18556
|
try {
|
|
18526
18557
|
const stat = await fs38.stat(absolutePath);
|
|
18527
18558
|
if (stat.isDirectory())
|
|
@@ -18730,7 +18761,7 @@ var init_data_preview = __esm({
|
|
|
18730
18761
|
|
|
18731
18762
|
// ../server/dist/git-credentials.js
|
|
18732
18763
|
import fs39 from "node:fs";
|
|
18733
|
-
import
|
|
18764
|
+
import path47 from "node:path";
|
|
18734
18765
|
import { homedir as homedir18 } from "node:os";
|
|
18735
18766
|
function writeGitCredentialsFile(host, username, token) {
|
|
18736
18767
|
const line = `https://${encodeURIComponent(username)}:${encodeURIComponent(token)}@${host}`;
|
|
@@ -18796,14 +18827,14 @@ var GIT_CREDENTIALS_PATH;
|
|
|
18796
18827
|
var init_git_credentials = __esm({
|
|
18797
18828
|
"../server/dist/git-credentials.js"() {
|
|
18798
18829
|
"use strict";
|
|
18799
|
-
GIT_CREDENTIALS_PATH =
|
|
18830
|
+
GIT_CREDENTIALS_PATH = path47.join(homedir18(), ".git-credentials");
|
|
18800
18831
|
}
|
|
18801
18832
|
});
|
|
18802
18833
|
|
|
18803
18834
|
// ../server/dist/git-ssh.js
|
|
18804
18835
|
import fs40 from "node:fs";
|
|
18805
18836
|
import os4 from "node:os";
|
|
18806
|
-
import
|
|
18837
|
+
import path48 from "node:path";
|
|
18807
18838
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
18808
18839
|
function looksLikePrivateKey(name, abs) {
|
|
18809
18840
|
if (name.endsWith(".pub"))
|
|
@@ -18838,7 +18869,7 @@ function listSshKeys() {
|
|
|
18838
18869
|
}
|
|
18839
18870
|
const keys = [];
|
|
18840
18871
|
for (const name of entries) {
|
|
18841
|
-
const abs =
|
|
18872
|
+
const abs = path48.join(SSH_DIR, name);
|
|
18842
18873
|
try {
|
|
18843
18874
|
if (!fs40.statSync(abs).isFile())
|
|
18844
18875
|
continue;
|
|
@@ -18865,8 +18896,8 @@ function unlockSshKey(keyPath, passphrase) {
|
|
|
18865
18896
|
return { ok: false, error: "ssh-agent is not running" };
|
|
18866
18897
|
let dir = "";
|
|
18867
18898
|
try {
|
|
18868
|
-
dir = fs40.mkdtempSync(
|
|
18869
|
-
const askpass =
|
|
18899
|
+
dir = fs40.mkdtempSync(path48.join(os4.tmpdir(), "halo-askpass-"));
|
|
18900
|
+
const askpass = path48.join(dir, "askpass.sh");
|
|
18870
18901
|
fs40.writeFileSync(askpass, ASKPASS_SCRIPT, { mode: 448 });
|
|
18871
18902
|
const r = spawnSync2("ssh-add", [keyPath], {
|
|
18872
18903
|
encoding: "utf-8",
|
|
@@ -18883,10 +18914,10 @@ function unlockSshKey(keyPath, passphrase) {
|
|
|
18883
18914
|
}
|
|
18884
18915
|
});
|
|
18885
18916
|
if (r.status === 0) {
|
|
18886
|
-
console.log(`[GitSsh] unlocked key ${
|
|
18917
|
+
console.log(`[GitSsh] unlocked key ${path48.basename(keyPath)}`);
|
|
18887
18918
|
return { ok: true };
|
|
18888
18919
|
}
|
|
18889
|
-
console.log(`[GitSsh] unlock failed for ${
|
|
18920
|
+
console.log(`[GitSsh] unlock failed for ${path48.basename(keyPath)} (exit ${r.status ?? "killed"})`);
|
|
18890
18921
|
if (r.status === 2)
|
|
18891
18922
|
return { ok: false, error: "ssh-agent is not reachable" };
|
|
18892
18923
|
return { ok: false, error: "Incorrect passphrase, or the key could not be unlocked" };
|
|
@@ -18979,7 +19010,7 @@ var SSH_DIR, NON_KEY_NAMES, ownedAgentPid, ASKPASS_SCRIPT;
|
|
|
18979
19010
|
var init_git_ssh = __esm({
|
|
18980
19011
|
"../server/dist/git-ssh.js"() {
|
|
18981
19012
|
"use strict";
|
|
18982
|
-
SSH_DIR =
|
|
19013
|
+
SSH_DIR = path48.join(os4.homedir(), ".ssh");
|
|
18983
19014
|
NON_KEY_NAMES = /* @__PURE__ */ new Set(["known_hosts", "known_hosts2", "authorized_keys", "config"]);
|
|
18984
19015
|
ownedAgentPid = null;
|
|
18985
19016
|
ASKPASS_SCRIPT = `#!/bin/sh
|
|
@@ -18993,7 +19024,7 @@ printf '%s\\n' "$HALO_SSH_PASSPHRASE"
|
|
|
18993
19024
|
// ../server/dist/routes/git.js
|
|
18994
19025
|
import { Hono as Hono3 } from "hono";
|
|
18995
19026
|
import os5 from "node:os";
|
|
18996
|
-
import
|
|
19027
|
+
import path49 from "node:path";
|
|
18997
19028
|
function notifyGitChanged(workspacePath) {
|
|
18998
19029
|
broadcastToWorkspace(workspacePath, { type: "file:changed", path: ".git", action: "change" });
|
|
18999
19030
|
}
|
|
@@ -19296,9 +19327,9 @@ function createGitRoutes() {
|
|
|
19296
19327
|
if (!keyPath || typeof passphrase !== "string") {
|
|
19297
19328
|
return c.json({ error: "keyPath and passphrase are required" }, 400);
|
|
19298
19329
|
}
|
|
19299
|
-
const sshDir =
|
|
19300
|
-
const resolved =
|
|
19301
|
-
if (
|
|
19330
|
+
const sshDir = path49.join(os5.homedir(), ".ssh");
|
|
19331
|
+
const resolved = path49.resolve(keyPath);
|
|
19332
|
+
if (path49.dirname(resolved) !== path49.resolve(sshDir)) {
|
|
19302
19333
|
return c.json({ error: "keyPath must be inside ~/.ssh" }, 400);
|
|
19303
19334
|
}
|
|
19304
19335
|
return c.json(unlockSshKey(resolved, passphrase));
|
|
@@ -19375,7 +19406,7 @@ var init_mtime_cache = __esm({
|
|
|
19375
19406
|
// ../server/dist/routes/agent-configs.js
|
|
19376
19407
|
import { Hono as Hono4 } from "hono";
|
|
19377
19408
|
import fs41 from "node:fs/promises";
|
|
19378
|
-
import
|
|
19409
|
+
import path50 from "node:path";
|
|
19379
19410
|
import { homedir as homedir19 } from "node:os";
|
|
19380
19411
|
import YAML11 from "yaml";
|
|
19381
19412
|
function getAvailableTools() {
|
|
@@ -19434,9 +19465,9 @@ function registryModelBlock() {
|
|
|
19434
19465
|
return modelBlockFromProvider(provider.id, provider);
|
|
19435
19466
|
}
|
|
19436
19467
|
async function scaffoldModelBlock(scope, projectId) {
|
|
19437
|
-
const candidates = [
|
|
19468
|
+
const candidates = [path50.join(GLOBAL_AGENTS_DIR4, "default", "agent.yaml")];
|
|
19438
19469
|
if (scope === "workspace" && projectId)
|
|
19439
|
-
candidates.unshift(
|
|
19470
|
+
candidates.unshift(path50.join(projectId, ".halo", "agents", "default", "agent.yaml"));
|
|
19440
19471
|
for (const yamlPath of candidates) {
|
|
19441
19472
|
let content;
|
|
19442
19473
|
try {
|
|
@@ -19490,10 +19521,10 @@ async function ensureDir2(dir) {
|
|
|
19490
19521
|
}
|
|
19491
19522
|
function resolveAgentDir(id, scope, projectId) {
|
|
19492
19523
|
if (scope === "global")
|
|
19493
|
-
return { agentDir:
|
|
19524
|
+
return { agentDir: path50.join(GLOBAL_AGENTS_DIR4, id) };
|
|
19494
19525
|
if (scope !== "workspace")
|
|
19495
19526
|
return { error: "Invalid scope" };
|
|
19496
|
-
return projectId ? { agentDir:
|
|
19527
|
+
return projectId ? { agentDir: path50.join(projectId, ".halo", "agents", id) } : { error: "projectId required for workspace agents" };
|
|
19497
19528
|
}
|
|
19498
19529
|
async function scanAgentsDir(dir, scope) {
|
|
19499
19530
|
const agents = [];
|
|
@@ -19504,7 +19535,7 @@ async function scanAgentsDir(dir, scope) {
|
|
|
19504
19535
|
return agents;
|
|
19505
19536
|
}
|
|
19506
19537
|
for (const entryName of names) {
|
|
19507
|
-
const agentDir =
|
|
19538
|
+
const agentDir = path50.join(dir, entryName);
|
|
19508
19539
|
try {
|
|
19509
19540
|
const stat = await fs41.stat(agentDir);
|
|
19510
19541
|
if (!stat.isDirectory())
|
|
@@ -19512,7 +19543,7 @@ async function scanAgentsDir(dir, scope) {
|
|
|
19512
19543
|
} catch {
|
|
19513
19544
|
continue;
|
|
19514
19545
|
}
|
|
19515
|
-
const yamlPath =
|
|
19546
|
+
const yamlPath = path50.join(agentDir, "agent.yaml");
|
|
19516
19547
|
try {
|
|
19517
19548
|
const yamlStat = await fs41.stat(yamlPath);
|
|
19518
19549
|
const parsed = _yamlCache.get(yamlPath, yamlStat.mtimeMs) ?? _yamlCache.set(yamlPath, yamlStat.mtimeMs, parseAgentYaml(await fs41.readFile(yamlPath, "utf-8")));
|
|
@@ -19536,8 +19567,8 @@ async function scanAgentsDir(dir, scope) {
|
|
|
19536
19567
|
return agents;
|
|
19537
19568
|
}
|
|
19538
19569
|
async function ensureDefaultAgent(dir) {
|
|
19539
|
-
const defaultDir =
|
|
19540
|
-
const yamlPath =
|
|
19570
|
+
const defaultDir = path50.join(dir, "default");
|
|
19571
|
+
const yamlPath = path50.join(defaultDir, "agent.yaml");
|
|
19541
19572
|
try {
|
|
19542
19573
|
await fs41.access(yamlPath);
|
|
19543
19574
|
} catch {
|
|
@@ -19560,7 +19591,7 @@ function createAgentConfigRoutes() {
|
|
|
19560
19591
|
const projectId = c.req.query("projectId");
|
|
19561
19592
|
let workspaceAgents = [];
|
|
19562
19593
|
if (projectId) {
|
|
19563
|
-
const wsAgentsDir =
|
|
19594
|
+
const wsAgentsDir = path50.join(projectId, ".halo", "agents");
|
|
19564
19595
|
workspaceAgents = await scanAgentsDir(wsAgentsDir, "workspace");
|
|
19565
19596
|
}
|
|
19566
19597
|
const wsIds = new Set(workspaceAgents.map((a) => a.id));
|
|
@@ -19594,11 +19625,11 @@ function createAgentConfigRoutes() {
|
|
|
19594
19625
|
if (scope === "workspace") {
|
|
19595
19626
|
if (!body.projectId)
|
|
19596
19627
|
return c.json({ error: "projectId required for workspace agents" }, 400);
|
|
19597
|
-
baseDir =
|
|
19628
|
+
baseDir = path50.join(body.projectId, ".halo", "agents");
|
|
19598
19629
|
} else {
|
|
19599
19630
|
baseDir = GLOBAL_AGENTS_DIR4;
|
|
19600
19631
|
}
|
|
19601
|
-
const agentDir =
|
|
19632
|
+
const agentDir = path50.join(baseDir, id);
|
|
19602
19633
|
try {
|
|
19603
19634
|
await fs41.access(agentDir);
|
|
19604
19635
|
return c.json({ error: "Agent already exists" }, 409);
|
|
@@ -19607,21 +19638,21 @@ function createAgentConfigRoutes() {
|
|
|
19607
19638
|
let conflictScope = null;
|
|
19608
19639
|
if (scope === "workspace") {
|
|
19609
19640
|
try {
|
|
19610
|
-
await fs41.access(
|
|
19641
|
+
await fs41.access(path50.join(GLOBAL_AGENTS_DIR4, id));
|
|
19611
19642
|
conflictScope = "global";
|
|
19612
19643
|
} catch {
|
|
19613
19644
|
}
|
|
19614
19645
|
} else if (body.projectId) {
|
|
19615
19646
|
try {
|
|
19616
|
-
await fs41.access(
|
|
19647
|
+
await fs41.access(path50.join(body.projectId, ".halo", "agents", id));
|
|
19617
19648
|
conflictScope = "workspace";
|
|
19618
19649
|
} catch {
|
|
19619
19650
|
}
|
|
19620
19651
|
}
|
|
19621
19652
|
const scaffoldModel = await scaffoldModelBlock(scope, body.projectId);
|
|
19622
19653
|
await ensureDir2(agentDir);
|
|
19623
|
-
await fs41.writeFile(
|
|
19624
|
-
await fs41.writeFile(
|
|
19654
|
+
await fs41.writeFile(path50.join(agentDir, "agent.yaml"), defaultAgentYaml(body.name, body.description ?? "", scaffoldModel), "utf-8");
|
|
19655
|
+
await fs41.writeFile(path50.join(agentDir, "AGENT.md"), `# ${body.name}
|
|
19625
19656
|
|
|
19626
19657
|
${body.description ?? ""}
|
|
19627
19658
|
`, "utf-8");
|
|
@@ -19638,7 +19669,7 @@ ${body.description ?? ""}
|
|
|
19638
19669
|
if ("error" in resolved)
|
|
19639
19670
|
return c.json({ error: resolved.error }, 400);
|
|
19640
19671
|
const { agentDir } = resolved;
|
|
19641
|
-
const yamlPath =
|
|
19672
|
+
const yamlPath = path50.join(agentDir, "agent.yaml");
|
|
19642
19673
|
try {
|
|
19643
19674
|
const content = await fs41.readFile(yamlPath, "utf-8");
|
|
19644
19675
|
return c.json({ yaml: content });
|
|
@@ -19661,7 +19692,7 @@ ${body.description ?? ""}
|
|
|
19661
19692
|
if ("error" in resolved)
|
|
19662
19693
|
return c.json({ error: resolved.error }, 400);
|
|
19663
19694
|
const { agentDir } = resolved;
|
|
19664
|
-
const yamlPath =
|
|
19695
|
+
const yamlPath = path50.join(agentDir, "agent.yaml");
|
|
19665
19696
|
try {
|
|
19666
19697
|
await fs41.access(agentDir);
|
|
19667
19698
|
} catch {
|
|
@@ -19779,10 +19810,10 @@ ${body.description ?? ""}
|
|
|
19779
19810
|
});
|
|
19780
19811
|
function getSessionsDir(agentId, _source, projectId) {
|
|
19781
19812
|
if (agentId.startsWith("__") && agentId.endsWith("__")) {
|
|
19782
|
-
return
|
|
19813
|
+
return path50.join(homedir19(), ".halo", "global", "internal-sessions", agentId);
|
|
19783
19814
|
}
|
|
19784
|
-
const base = projectId ?
|
|
19785
|
-
return
|
|
19815
|
+
const base = projectId ? path50.join(projectId, ".halo") : path50.join(homedir19(), ".halo");
|
|
19816
|
+
return path50.join(base, "sessions", agentId);
|
|
19786
19817
|
}
|
|
19787
19818
|
app2.get("/agent-configs/:id/sessions", async (c) => {
|
|
19788
19819
|
const agentId = c.req.param("id");
|
|
@@ -19802,7 +19833,7 @@ ${body.description ?? ""}
|
|
|
19802
19833
|
if (!f.endsWith(".json"))
|
|
19803
19834
|
continue;
|
|
19804
19835
|
try {
|
|
19805
|
-
const raw = await fs41.readFile(
|
|
19836
|
+
const raw = await fs41.readFile(path50.join(dir, f), "utf-8");
|
|
19806
19837
|
const session = JSON.parse(raw);
|
|
19807
19838
|
sessions.push({
|
|
19808
19839
|
id: session.id,
|
|
@@ -19829,7 +19860,7 @@ ${body.description ?? ""}
|
|
|
19829
19860
|
return null;
|
|
19830
19861
|
const projectId = c.req.query("projectId");
|
|
19831
19862
|
const source = c.req.query("source") || "test-chat";
|
|
19832
|
-
return
|
|
19863
|
+
return path50.join(getSessionsDir(agentId, source, projectId || void 0), `${sessionId}.json`);
|
|
19833
19864
|
}
|
|
19834
19865
|
app2.get("/agent-configs/:id/sessions/:sessionId", async (c) => {
|
|
19835
19866
|
const filePath = sessionFileFromParams(c);
|
|
@@ -19855,7 +19886,7 @@ ${body.description ?? ""}
|
|
|
19855
19886
|
const dir = getSessionsDir(agentId, source, projectId || void 0);
|
|
19856
19887
|
if (agentId === GOAL_AGENT_ID && !config.goalModeEnabled) {
|
|
19857
19888
|
try {
|
|
19858
|
-
await fs41.access(
|
|
19889
|
+
await fs41.access(path50.join(dir, `${sessionId}.json`));
|
|
19859
19890
|
} catch {
|
|
19860
19891
|
return c.json({ error: "Goal mode is disabled." }, 403);
|
|
19861
19892
|
}
|
|
@@ -19877,7 +19908,7 @@ ${body.description ?? ""}
|
|
|
19877
19908
|
agentSnapshot: body.agentSnapshot ?? {},
|
|
19878
19909
|
messages: messages2
|
|
19879
19910
|
};
|
|
19880
|
-
await fs41.writeFile(
|
|
19911
|
+
await fs41.writeFile(path50.join(dir, `${sessionId}.json`), JSON.stringify(session, null, 2), "utf-8");
|
|
19881
19912
|
return c.json({ id: sessionId, session: { ...session, messages: void 0 } });
|
|
19882
19913
|
});
|
|
19883
19914
|
app2.delete("/agent-configs/:id/sessions", async (c) => {
|
|
@@ -19893,7 +19924,7 @@ ${body.description ?? ""}
|
|
|
19893
19924
|
for (const f of files) {
|
|
19894
19925
|
if (!f.endsWith(".json"))
|
|
19895
19926
|
continue;
|
|
19896
|
-
await fs41.rm(
|
|
19927
|
+
await fs41.rm(path50.join(dir, f));
|
|
19897
19928
|
deleted++;
|
|
19898
19929
|
}
|
|
19899
19930
|
} catch {
|
|
@@ -19928,7 +19959,7 @@ var init_agent_configs = __esm({
|
|
|
19928
19959
|
init_workspace_path();
|
|
19929
19960
|
init_mtime_cache();
|
|
19930
19961
|
_cachedTools = null;
|
|
19931
|
-
GLOBAL_AGENTS_DIR4 =
|
|
19962
|
+
GLOBAL_AGENTS_DIR4 = path50.join(homedir19(), ".halo", "global", "agents");
|
|
19932
19963
|
FALLBACK_SCAFFOLD_PROVIDER = "aws-bedrock-claude-invoke";
|
|
19933
19964
|
_yamlCache = createMtimeCache();
|
|
19934
19965
|
}
|
|
@@ -19937,7 +19968,7 @@ var init_agent_configs = __esm({
|
|
|
19937
19968
|
// ../server/dist/routes/skills.js
|
|
19938
19969
|
import { Hono as Hono5 } from "hono";
|
|
19939
19970
|
import fs42 from "node:fs/promises";
|
|
19940
|
-
import
|
|
19971
|
+
import path51 from "node:path";
|
|
19941
19972
|
import { homedir as homedir20 } from "node:os";
|
|
19942
19973
|
import YAML12 from "yaml";
|
|
19943
19974
|
function defaultSkillSettings() {
|
|
@@ -19968,7 +19999,7 @@ async function readYamlFile3(filePath) {
|
|
|
19968
19999
|
}
|
|
19969
20000
|
}
|
|
19970
20001
|
async function writeYamlFile(filePath, data) {
|
|
19971
|
-
await fs42.mkdir(
|
|
20002
|
+
await fs42.mkdir(path51.dirname(filePath), { recursive: true });
|
|
19972
20003
|
await fs42.writeFile(filePath, YAML12.stringify(data, { lineWidth: 120 }), "utf-8");
|
|
19973
20004
|
}
|
|
19974
20005
|
async function addSkillSettings(settingsPath, skillId) {
|
|
@@ -20014,7 +20045,7 @@ async function scanSkillsDir(dir, scope) {
|
|
|
20014
20045
|
return skills;
|
|
20015
20046
|
}
|
|
20016
20047
|
for (const entryName of names) {
|
|
20017
|
-
const skillDir =
|
|
20048
|
+
const skillDir = path51.join(dir, entryName);
|
|
20018
20049
|
try {
|
|
20019
20050
|
const stat = await fs42.stat(skillDir);
|
|
20020
20051
|
if (!stat.isDirectory())
|
|
@@ -20022,7 +20053,7 @@ async function scanSkillsDir(dir, scope) {
|
|
|
20022
20053
|
} catch {
|
|
20023
20054
|
continue;
|
|
20024
20055
|
}
|
|
20025
|
-
const skillMdPath =
|
|
20056
|
+
const skillMdPath = path51.join(skillDir, "SKILL.md");
|
|
20026
20057
|
try {
|
|
20027
20058
|
const mdStat = await fs42.stat(skillMdPath);
|
|
20028
20059
|
let meta = _skillMdCache.get(skillMdPath, mdStat.mtimeMs);
|
|
@@ -20032,7 +20063,7 @@ async function scanSkillsDir(dir, scope) {
|
|
|
20032
20063
|
}
|
|
20033
20064
|
skills.push({ id: entryName, name: meta.name, description: meta.description, path: skillDir, scope, command: meta.command });
|
|
20034
20065
|
} catch {
|
|
20035
|
-
const yamlPath =
|
|
20066
|
+
const yamlPath = path51.join(skillDir, "skill.yaml");
|
|
20036
20067
|
try {
|
|
20037
20068
|
const yamlContent = await fs42.readFile(yamlPath, "utf-8");
|
|
20038
20069
|
const m = yamlContent.match(/^name:\s*(.+)$/m);
|
|
@@ -20053,7 +20084,7 @@ function createSkillRoutes() {
|
|
|
20053
20084
|
const projectId = c.req.query("projectId");
|
|
20054
20085
|
let workspaceSkills = [];
|
|
20055
20086
|
if (projectId) {
|
|
20056
|
-
const wsSkillsDir =
|
|
20087
|
+
const wsSkillsDir = path51.join(projectId, ".halo", "skills");
|
|
20057
20088
|
workspaceSkills = await scanSkillsDir(wsSkillsDir, "workspace");
|
|
20058
20089
|
}
|
|
20059
20090
|
const wsIds = new Set(workspaceSkills.map((s) => s.id));
|
|
@@ -20076,19 +20107,19 @@ function createSkillRoutes() {
|
|
|
20076
20107
|
if (scope === "workspace") {
|
|
20077
20108
|
if (!body.projectId)
|
|
20078
20109
|
return c.json({ error: "projectId required for workspace skills" }, 400);
|
|
20079
|
-
baseDir =
|
|
20110
|
+
baseDir = path51.join(body.projectId, ".halo", "skills");
|
|
20080
20111
|
} else {
|
|
20081
20112
|
baseDir = GLOBAL_SKILLS_DIR2;
|
|
20082
20113
|
}
|
|
20083
|
-
const skillDir =
|
|
20114
|
+
const skillDir = path51.join(baseDir, id);
|
|
20084
20115
|
try {
|
|
20085
20116
|
await fs42.access(skillDir);
|
|
20086
20117
|
return c.json({ error: "Skill already exists" }, 409);
|
|
20087
20118
|
} catch {
|
|
20088
20119
|
}
|
|
20089
20120
|
await ensureDir3(skillDir);
|
|
20090
|
-
await fs42.writeFile(
|
|
20091
|
-
const settingsPath = scope === "workspace" && body.projectId ?
|
|
20121
|
+
await fs42.writeFile(path51.join(skillDir, "SKILL.md"), toSkillMd(body.name, body.description ?? ""), "utf-8");
|
|
20122
|
+
const settingsPath = scope === "workspace" && body.projectId ? path51.join(body.projectId, ".halo", "settings.yaml") : GLOBAL_SETTINGS_PATH;
|
|
20092
20123
|
await addSkillSettings(settingsPath, id);
|
|
20093
20124
|
const skill = { id, name: body.name, description: body.description ?? "", path: skillDir, scope };
|
|
20094
20125
|
return c.json({ skill }, 201);
|
|
@@ -20101,9 +20132,9 @@ function createSkillRoutes() {
|
|
|
20101
20132
|
const projectId = c.req.query("projectId");
|
|
20102
20133
|
let skillDir;
|
|
20103
20134
|
if (scope === "workspace" && projectId) {
|
|
20104
|
-
skillDir =
|
|
20135
|
+
skillDir = path51.join(projectId, ".halo", "skills", id);
|
|
20105
20136
|
} else {
|
|
20106
|
-
skillDir =
|
|
20137
|
+
skillDir = path51.join(GLOBAL_SKILLS_DIR2, id);
|
|
20107
20138
|
}
|
|
20108
20139
|
try {
|
|
20109
20140
|
await fs42.access(skillDir);
|
|
@@ -20111,7 +20142,7 @@ function createSkillRoutes() {
|
|
|
20111
20142
|
return c.json({ error: "Skill not found" }, 404);
|
|
20112
20143
|
}
|
|
20113
20144
|
await fs42.rm(skillDir, { recursive: true, force: true });
|
|
20114
|
-
const settingsPath = scope === "workspace" && projectId ?
|
|
20145
|
+
const settingsPath = scope === "workspace" && projectId ? path51.join(projectId, ".halo", "settings.yaml") : GLOBAL_SETTINGS_PATH;
|
|
20115
20146
|
await removeSkillSettings(settingsPath, id);
|
|
20116
20147
|
return c.json({ ok: true });
|
|
20117
20148
|
});
|
|
@@ -20135,7 +20166,7 @@ var init_skills = __esm({
|
|
|
20135
20166
|
init_db();
|
|
20136
20167
|
init_workspace_path();
|
|
20137
20168
|
init_mtime_cache();
|
|
20138
|
-
GLOBAL_SETTINGS_PATH =
|
|
20169
|
+
GLOBAL_SETTINGS_PATH = path51.join(homedir20(), ".halo", "secrets", "settings.yaml");
|
|
20139
20170
|
_skillMdCache = createMtimeCache();
|
|
20140
20171
|
}
|
|
20141
20172
|
});
|
|
@@ -20143,7 +20174,7 @@ var init_skills = __esm({
|
|
|
20143
20174
|
// ../server/dist/routes/settings.js
|
|
20144
20175
|
import { Hono as Hono6 } from "hono";
|
|
20145
20176
|
import fs43 from "node:fs/promises";
|
|
20146
|
-
import
|
|
20177
|
+
import path52 from "node:path";
|
|
20147
20178
|
import { homedir as homedir21 } from "node:os";
|
|
20148
20179
|
import YAML13 from "yaml";
|
|
20149
20180
|
async function readSettingsFile(filePath) {
|
|
@@ -20155,7 +20186,7 @@ async function readSettingsFile(filePath) {
|
|
|
20155
20186
|
}
|
|
20156
20187
|
}
|
|
20157
20188
|
async function writeSettingsFile(filePath, data) {
|
|
20158
|
-
await fs43.mkdir(
|
|
20189
|
+
await fs43.mkdir(path52.dirname(filePath), { recursive: true });
|
|
20159
20190
|
await fs43.writeFile(filePath, YAML13.stringify(data, { lineWidth: 120 }), { encoding: "utf-8", mode: 384 });
|
|
20160
20191
|
try {
|
|
20161
20192
|
await fs43.chmod(filePath, 384);
|
|
@@ -20274,8 +20305,8 @@ function detectOrphans(tree, declared) {
|
|
|
20274
20305
|
if (!block || typeof block !== "object")
|
|
20275
20306
|
continue;
|
|
20276
20307
|
for (const k of Object.keys(block)) {
|
|
20277
|
-
const
|
|
20278
|
-
if (!declaredMap.has(
|
|
20308
|
+
const path74 = `${namespaceId}.${kindWord}.${k}`;
|
|
20309
|
+
if (!declaredMap.has(path74)) {
|
|
20279
20310
|
out.push({ namespaceId, kind: kindWord === "params" ? "param" : "secret", key: k });
|
|
20280
20311
|
}
|
|
20281
20312
|
}
|
|
@@ -20290,7 +20321,7 @@ function createSettingsRoutes() {
|
|
|
20290
20321
|
const globalTree = await readSettingsFile(GLOBAL_SETTINGS_PATH2);
|
|
20291
20322
|
let workspaceTree = null;
|
|
20292
20323
|
if (projectId) {
|
|
20293
|
-
workspaceTree = await readSettingsFile(
|
|
20324
|
+
workspaceTree = await readSettingsFile(path52.join(projectId, ".halo", "settings.yaml"));
|
|
20294
20325
|
}
|
|
20295
20326
|
const declared = loadSettingsSchema(projectId ?? void 0);
|
|
20296
20327
|
const sections = resolveSections(declared, globalTree, workspaceTree);
|
|
@@ -20325,7 +20356,7 @@ function createSettingsRoutes() {
|
|
|
20325
20356
|
const projectPath = await resolveProjectPath(projectId);
|
|
20326
20357
|
if (!projectPath)
|
|
20327
20358
|
return { error: "Project not found", status: 404 };
|
|
20328
|
-
return { filePath:
|
|
20359
|
+
return { filePath: path52.join(projectPath, ".halo", "settings.yaml") };
|
|
20329
20360
|
}
|
|
20330
20361
|
function flattenDotted(tree, prefix = "") {
|
|
20331
20362
|
const out = [];
|
|
@@ -20413,21 +20444,21 @@ var init_settings = __esm({
|
|
|
20413
20444
|
"use strict";
|
|
20414
20445
|
init_settings_schema();
|
|
20415
20446
|
init_workspace_path();
|
|
20416
|
-
GLOBAL_SETTINGS_PATH2 =
|
|
20447
|
+
GLOBAL_SETTINGS_PATH2 = path52.join(homedir21(), ".halo", "secrets", "settings.yaml");
|
|
20417
20448
|
_changeListeners = [];
|
|
20418
20449
|
}
|
|
20419
20450
|
});
|
|
20420
20451
|
|
|
20421
20452
|
// ../server/dist/evolution/archive.js
|
|
20422
20453
|
import fs44 from "node:fs";
|
|
20423
|
-
import
|
|
20454
|
+
import path53 from "node:path";
|
|
20424
20455
|
import { pipeline } from "node:stream/promises";
|
|
20425
20456
|
import JSZip from "jszip";
|
|
20426
20457
|
import { eq as eq11, and as and8, isNull as isNull5, lte, isNotNull as isNotNull3, lt as lt2 } from "drizzle-orm";
|
|
20427
20458
|
async function zipDir(srcDir, outZip) {
|
|
20428
20459
|
if (!fs44.existsSync(srcDir))
|
|
20429
20460
|
return false;
|
|
20430
|
-
fs44.mkdirSync(
|
|
20461
|
+
fs44.mkdirSync(path53.dirname(outZip), { recursive: true });
|
|
20431
20462
|
const zip = new JSZip();
|
|
20432
20463
|
const walk = (dir, rel) => {
|
|
20433
20464
|
const entries = fs44.readdirSync(dir, { withFileTypes: true });
|
|
@@ -20436,7 +20467,7 @@ async function zipDir(srcDir, outZip) {
|
|
|
20436
20467
|
return;
|
|
20437
20468
|
}
|
|
20438
20469
|
for (const e of entries) {
|
|
20439
|
-
const abs =
|
|
20470
|
+
const abs = path53.join(dir, e.name);
|
|
20440
20471
|
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
20441
20472
|
if (e.isDirectory()) {
|
|
20442
20473
|
walk(abs, childRel);
|
|
@@ -20617,7 +20648,7 @@ var init_raw_sqlite = __esm({
|
|
|
20617
20648
|
import { Hono as Hono7 } from "hono";
|
|
20618
20649
|
import { eq as eq12, desc as desc2, lt as lt3, and as and9, or, sql } from "drizzle-orm";
|
|
20619
20650
|
import fs45 from "node:fs/promises";
|
|
20620
|
-
import
|
|
20651
|
+
import path54 from "node:path";
|
|
20621
20652
|
function createEvolutionRoutes() {
|
|
20622
20653
|
const router = new Hono7();
|
|
20623
20654
|
router.get("/evolution/runs", async (c) => {
|
|
@@ -20682,12 +20713,12 @@ function createEvolutionRoutes() {
|
|
|
20682
20713
|
const dir = wsEvoRunDir(row.workspacePath, id);
|
|
20683
20714
|
let patchMd = null;
|
|
20684
20715
|
try {
|
|
20685
|
-
patchMd = await fs45.readFile(
|
|
20716
|
+
patchMd = await fs45.readFile(path54.join(dir, "patch.md"), "utf-8");
|
|
20686
20717
|
} catch {
|
|
20687
20718
|
}
|
|
20688
20719
|
let scoreJson = null;
|
|
20689
20720
|
try {
|
|
20690
|
-
const raw = await fs45.readFile(
|
|
20721
|
+
const raw = await fs45.readFile(path54.join(dir, "score.json"), "utf-8");
|
|
20691
20722
|
scoreJson = JSON.parse(raw);
|
|
20692
20723
|
} catch {
|
|
20693
20724
|
}
|
|
@@ -20698,17 +20729,17 @@ function createEvolutionRoutes() {
|
|
|
20698
20729
|
}
|
|
20699
20730
|
let subCliLog = null;
|
|
20700
20731
|
try {
|
|
20701
|
-
subCliLog = await fs45.readFile(
|
|
20732
|
+
subCliLog = await fs45.readFile(path54.join(dir, "sub-cli.log"), "utf-8");
|
|
20702
20733
|
} catch {
|
|
20703
20734
|
}
|
|
20704
20735
|
let skipReasonMd = null;
|
|
20705
20736
|
try {
|
|
20706
|
-
skipReasonMd = await fs45.readFile(
|
|
20737
|
+
skipReasonMd = await fs45.readFile(path54.join(dir, ".skip.md"), "utf-8");
|
|
20707
20738
|
} catch {
|
|
20708
20739
|
}
|
|
20709
20740
|
let snapshotSummary = null;
|
|
20710
20741
|
try {
|
|
20711
|
-
const raw = await fs45.readFile(
|
|
20742
|
+
const raw = await fs45.readFile(path54.join(dir, "source-snapshot.json"), "utf-8");
|
|
20712
20743
|
const parsed = JSON.parse(raw);
|
|
20713
20744
|
const msgs = parsed.rawMessages ?? [];
|
|
20714
20745
|
const firstUser = msgs.find((m) => m.role === "user");
|
|
@@ -21370,14 +21401,14 @@ function createWebChannel(deps) {
|
|
|
21370
21401
|
return findActiveSessionId(sm, accountId, prefix, activeOverrides2, "full") ?? void 0;
|
|
21371
21402
|
}
|
|
21372
21403
|
function resolveWorkspace(account, override) {
|
|
21373
|
-
let
|
|
21404
|
+
let path74 = account.workspacePath;
|
|
21374
21405
|
if (override && override !== account.workspacePath) {
|
|
21375
21406
|
if (account.accessLevel !== "full") {
|
|
21376
21407
|
return { ok: false, error: "workspace override requires a full-access token" };
|
|
21377
21408
|
}
|
|
21378
|
-
|
|
21409
|
+
path74 = override;
|
|
21379
21410
|
}
|
|
21380
|
-
const resolved = resolveAccountWorkspace({ ...account, workspacePath:
|
|
21411
|
+
const resolved = resolveAccountWorkspace({ ...account, workspacePath: path74 });
|
|
21381
21412
|
if (!resolved)
|
|
21382
21413
|
return { ok: false, error: "workspace not found" };
|
|
21383
21414
|
return { ok: true, path: resolved };
|
|
@@ -21777,7 +21808,7 @@ var init_session_types = __esm({
|
|
|
21777
21808
|
// ../server/dist/routes/halo-city.js
|
|
21778
21809
|
import { Hono as Hono10 } from "hono";
|
|
21779
21810
|
import fs46 from "node:fs";
|
|
21780
|
-
import
|
|
21811
|
+
import path55 from "node:path";
|
|
21781
21812
|
import Database6 from "better-sqlite3";
|
|
21782
21813
|
function scanSkills2(dir) {
|
|
21783
21814
|
let names;
|
|
@@ -21788,7 +21819,7 @@ function scanSkills2(dir) {
|
|
|
21788
21819
|
}
|
|
21789
21820
|
const out = [];
|
|
21790
21821
|
for (const entry of names) {
|
|
21791
|
-
const skillMd =
|
|
21822
|
+
const skillMd = path55.join(dir, entry, "SKILL.md");
|
|
21792
21823
|
let stat;
|
|
21793
21824
|
try {
|
|
21794
21825
|
stat = fs46.statSync(skillMd);
|
|
@@ -21886,10 +21917,10 @@ function snapshotWorkspace(sm, wsPath, label) {
|
|
|
21886
21917
|
messageCount: meta.messageCount
|
|
21887
21918
|
};
|
|
21888
21919
|
});
|
|
21889
|
-
const wsSkills = scanSkills2(
|
|
21920
|
+
const wsSkills = scanSkills2(path55.join(wsPath, ".halo", "skills"));
|
|
21890
21921
|
return {
|
|
21891
21922
|
path: wsPath,
|
|
21892
|
-
key:
|
|
21923
|
+
key: path55.basename(wsPath) || wsPath,
|
|
21893
21924
|
label,
|
|
21894
21925
|
sessions,
|
|
21895
21926
|
counts,
|
|
@@ -21907,7 +21938,7 @@ function roReader(rawPath) {
|
|
|
21907
21938
|
const cached = _roReaders.get(wsPath);
|
|
21908
21939
|
if (cached)
|
|
21909
21940
|
return cached;
|
|
21910
|
-
const dbPath =
|
|
21941
|
+
const dbPath = path55.join(wsPath, ".halo", "halo.db");
|
|
21911
21942
|
if (!fs46.existsSync(dbPath))
|
|
21912
21943
|
return null;
|
|
21913
21944
|
try {
|
|
@@ -21984,12 +22015,12 @@ function snapshotWorkspaceReadonly(wsPath, label) {
|
|
|
21984
22015
|
});
|
|
21985
22016
|
return {
|
|
21986
22017
|
path: wsPath,
|
|
21987
|
-
key:
|
|
22018
|
+
key: path55.basename(wsPath) || wsPath,
|
|
21988
22019
|
label,
|
|
21989
22020
|
sessions,
|
|
21990
22021
|
counts,
|
|
21991
22022
|
totalSessions: counts.total,
|
|
21992
|
-
skills: scanSkills2(
|
|
22023
|
+
skills: scanSkills2(path55.join(wsPath, ".halo", "skills"))
|
|
21993
22024
|
};
|
|
21994
22025
|
}
|
|
21995
22026
|
function readonlySessionCounts(wsPath, limit) {
|
|
@@ -22052,11 +22083,11 @@ function discoverWorkspaces(registry2) {
|
|
|
22052
22083
|
}
|
|
22053
22084
|
};
|
|
22054
22085
|
for (const { workspacePath } of registry2.list())
|
|
22055
|
-
add(workspacePath,
|
|
22086
|
+
add(workspacePath, path55.basename(workspacePath));
|
|
22056
22087
|
try {
|
|
22057
22088
|
const rows = getChannelDb().select().from(channelAccounts).all();
|
|
22058
22089
|
for (const row of rows)
|
|
22059
|
-
add(row.workspacePath,
|
|
22090
|
+
add(row.workspacePath, path55.basename(row.workspacePath));
|
|
22060
22091
|
} catch {
|
|
22061
22092
|
}
|
|
22062
22093
|
return out;
|
|
@@ -22075,7 +22106,7 @@ function createShowRoutes(registry2) {
|
|
|
22075
22106
|
return a.response;
|
|
22076
22107
|
const { account } = a;
|
|
22077
22108
|
const globalView = account.accessLevel === "full" || account.accessLevel === "observer";
|
|
22078
|
-
const targets = globalView ? discoverWorkspaces(registry2) : /* @__PURE__ */ new Map([[account.workspacePath,
|
|
22109
|
+
const targets = globalView ? discoverWorkspaces(registry2) : /* @__PURE__ */ new Map([[account.workspacePath, path55.basename(account.workspacePath)]]);
|
|
22079
22110
|
const workspaces = [];
|
|
22080
22111
|
for (const [wsPath, label] of targets) {
|
|
22081
22112
|
try {
|
|
@@ -22304,7 +22335,7 @@ var init_commands3 = __esm({
|
|
|
22304
22335
|
|
|
22305
22336
|
// ../server/dist/routes/agentcore.js
|
|
22306
22337
|
import { Hono as Hono13 } from "hono";
|
|
22307
|
-
import
|
|
22338
|
+
import path56 from "node:path";
|
|
22308
22339
|
import fs47 from "node:fs";
|
|
22309
22340
|
function sanitizeRuntimeId(runtimeSessionId) {
|
|
22310
22341
|
return runtimeSessionId.replace(/[^a-zA-Z0-9_-]/g, "-").slice(0, 80);
|
|
@@ -22313,7 +22344,7 @@ function haloSessionId(runtimeSessionId) {
|
|
|
22313
22344
|
return `agentcore_${sanitizeRuntimeId(runtimeSessionId)}`;
|
|
22314
22345
|
}
|
|
22315
22346
|
function userWorkspace(base, runtimeSessionId) {
|
|
22316
|
-
const dir =
|
|
22347
|
+
const dir = path56.join(base, "users", sanitizeRuntimeId(runtimeSessionId));
|
|
22317
22348
|
fs47.mkdirSync(dir, { recursive: true });
|
|
22318
22349
|
return dir;
|
|
22319
22350
|
}
|
|
@@ -22668,7 +22699,7 @@ var init_agentcore = __esm({
|
|
|
22668
22699
|
|
|
22669
22700
|
// ../server/dist/ws/file-watcher.js
|
|
22670
22701
|
import fs48 from "node:fs";
|
|
22671
|
-
import
|
|
22702
|
+
import path57 from "node:path";
|
|
22672
22703
|
function enqueueNativeOp(op) {
|
|
22673
22704
|
const result = nativeOpChain.then(op);
|
|
22674
22705
|
nativeOpChain = result.catch(() => {
|
|
@@ -22676,12 +22707,12 @@ function enqueueNativeOp(op) {
|
|
|
22676
22707
|
return result;
|
|
22677
22708
|
}
|
|
22678
22709
|
function isUnwatchablePath(absPath) {
|
|
22679
|
-
const norm =
|
|
22680
|
-
if (norm === "/" || norm ===
|
|
22710
|
+
const norm = path57.resolve(absPath);
|
|
22711
|
+
if (norm === "/" || norm === path57.parse(norm).root)
|
|
22681
22712
|
return "filesystem root";
|
|
22682
22713
|
const banned = ["/System", "/Library", "/private", "/usr", "/bin", "/sbin", "/etc"];
|
|
22683
22714
|
for (const b of banned) {
|
|
22684
|
-
if (norm === b || norm.startsWith(b +
|
|
22715
|
+
if (norm === b || norm.startsWith(b + path57.sep))
|
|
22685
22716
|
return `system path ${b}`;
|
|
22686
22717
|
}
|
|
22687
22718
|
return null;
|
|
@@ -22821,10 +22852,10 @@ var init_file_watcher = __esm({
|
|
|
22821
22852
|
const root = this.workspaceRoot;
|
|
22822
22853
|
if (!root)
|
|
22823
22854
|
return;
|
|
22824
|
-
const raw =
|
|
22855
|
+
const raw = path57.relative(root, absPath);
|
|
22825
22856
|
if (!raw || raw.startsWith(".."))
|
|
22826
22857
|
return;
|
|
22827
|
-
const rel = raw.split(
|
|
22858
|
+
const rel = raw.split(path57.sep).join("/");
|
|
22828
22859
|
if (IS_WIN32 && rel.split("/").some((seg) => IGNORED_SEGMENT_SET.has(seg)))
|
|
22829
22860
|
return;
|
|
22830
22861
|
let action;
|
|
@@ -22912,7 +22943,7 @@ var init_file_watcher = __esm({
|
|
|
22912
22943
|
|
|
22913
22944
|
// ../server/dist/ws/git-dir-watcher.js
|
|
22914
22945
|
import fs49 from "node:fs";
|
|
22915
|
-
import
|
|
22946
|
+
import path58 from "node:path";
|
|
22916
22947
|
var GitDirWatcher;
|
|
22917
22948
|
var init_git_dir_watcher = __esm({
|
|
22918
22949
|
"../server/dist/ws/git-dir-watcher.js"() {
|
|
@@ -22936,7 +22967,7 @@ var init_git_dir_watcher = __esm({
|
|
|
22936
22967
|
return;
|
|
22937
22968
|
this.stop();
|
|
22938
22969
|
this.workspaceRoot = workspaceRoot;
|
|
22939
|
-
const gitDir =
|
|
22970
|
+
const gitDir = path58.join(workspaceRoot, ".git");
|
|
22940
22971
|
if (fs49.existsSync(gitDir)) {
|
|
22941
22972
|
this.watchGitDir(gitDir);
|
|
22942
22973
|
} else {
|
|
@@ -23001,7 +23032,7 @@ var init_git_dir_watcher = __esm({
|
|
|
23001
23032
|
const root = this.workspaceRoot;
|
|
23002
23033
|
if (!root)
|
|
23003
23034
|
return;
|
|
23004
|
-
const gitDir =
|
|
23035
|
+
const gitDir = path58.join(root, ".git");
|
|
23005
23036
|
if (!fs49.existsSync(gitDir))
|
|
23006
23037
|
return;
|
|
23007
23038
|
this.closeWatcher();
|
|
@@ -23399,7 +23430,7 @@ var init_terminal_manager = __esm({
|
|
|
23399
23430
|
});
|
|
23400
23431
|
|
|
23401
23432
|
// ../server/dist/ws/handler.js
|
|
23402
|
-
import
|
|
23433
|
+
import path59 from "node:path";
|
|
23403
23434
|
function setupWebSocketHandler(deps) {
|
|
23404
23435
|
const { wss: wss2, registry: registry2 } = deps;
|
|
23405
23436
|
const clients = /* @__PURE__ */ new Set();
|
|
@@ -23422,7 +23453,7 @@ function setupWebSocketHandler(deps) {
|
|
|
23422
23453
|
ackedChatIds.add(id);
|
|
23423
23454
|
}
|
|
23424
23455
|
function resolveProjectPath2(projectId) {
|
|
23425
|
-
if (
|
|
23456
|
+
if (path59.isAbsolute(projectId))
|
|
23426
23457
|
return projectId;
|
|
23427
23458
|
return null;
|
|
23428
23459
|
}
|
|
@@ -24023,11 +24054,11 @@ var init_handler2 = __esm({
|
|
|
24023
24054
|
import Database7 from "better-sqlite3";
|
|
24024
24055
|
import { drizzle as drizzle5 } from "drizzle-orm/better-sqlite3";
|
|
24025
24056
|
import { sqliteTable as sqliteTable5, text as text5, integer as integer5 } from "drizzle-orm/sqlite-core";
|
|
24026
|
-
import
|
|
24057
|
+
import path60 from "node:path";
|
|
24027
24058
|
import fs50 from "node:fs";
|
|
24028
24059
|
function createCronDb(globalDir2) {
|
|
24029
24060
|
fs50.mkdirSync(globalDir2, { recursive: true });
|
|
24030
|
-
const dbPath =
|
|
24061
|
+
const dbPath = path60.join(globalDir2, "cron.db");
|
|
24031
24062
|
const sqlite = new Database7(dbPath);
|
|
24032
24063
|
sqlite.pragma("journal_mode = WAL");
|
|
24033
24064
|
sqlite.exec(CREATE_SQL4);
|
|
@@ -24228,7 +24259,7 @@ var init_dispatcher = __esm({
|
|
|
24228
24259
|
// ../server/dist/cron/runner.js
|
|
24229
24260
|
import { spawn as spawn3, execFileSync } from "node:child_process";
|
|
24230
24261
|
import fs51 from "node:fs";
|
|
24231
|
-
import
|
|
24262
|
+
import path61 from "node:path";
|
|
24232
24263
|
import { homedir as homedir23 } from "node:os";
|
|
24233
24264
|
import { Cron } from "croner";
|
|
24234
24265
|
import { eq as eq14, lt as lt5 } from "drizzle-orm";
|
|
@@ -24306,7 +24337,7 @@ function sessionKeyFor(workspacePath, sessionId) {
|
|
|
24306
24337
|
try {
|
|
24307
24338
|
ws = fs51.realpathSync(workspacePath);
|
|
24308
24339
|
} catch {
|
|
24309
|
-
ws =
|
|
24340
|
+
ws = path61.resolve(workspacePath);
|
|
24310
24341
|
}
|
|
24311
24342
|
return `${ws}
|
|
24312
24343
|
${sessionId}`;
|
|
@@ -24315,10 +24346,10 @@ function setCronSessionRegistry(r) {
|
|
|
24315
24346
|
_sessionRegistry = r;
|
|
24316
24347
|
}
|
|
24317
24348
|
function logsDir() {
|
|
24318
|
-
return
|
|
24349
|
+
return path61.join(homedir23(), ".halo", "global", "logs", "cron");
|
|
24319
24350
|
}
|
|
24320
24351
|
function logPathFor(runId) {
|
|
24321
|
-
return
|
|
24352
|
+
return path61.join(logsDir(), `${runId}.log`);
|
|
24322
24353
|
}
|
|
24323
24354
|
function newRunId() {
|
|
24324
24355
|
return `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -24786,7 +24817,7 @@ function pruneOldLogs() {
|
|
|
24786
24817
|
return;
|
|
24787
24818
|
const cutoff = Date.now() - LOG_RETENTION_DAYS * DAY_MS2;
|
|
24788
24819
|
for (const name of fs51.readdirSync(dir)) {
|
|
24789
|
-
const p =
|
|
24820
|
+
const p = path61.join(dir, name);
|
|
24790
24821
|
try {
|
|
24791
24822
|
const stat = fs51.statSync(p);
|
|
24792
24823
|
if (stat.mtimeMs < cutoff)
|
|
@@ -25133,7 +25164,7 @@ var init_cron = __esm({
|
|
|
25133
25164
|
|
|
25134
25165
|
// ../server/dist/extensions/registry.js
|
|
25135
25166
|
import fs53 from "node:fs";
|
|
25136
|
-
import
|
|
25167
|
+
import path62 from "node:path";
|
|
25137
25168
|
function isExtensionId(id) {
|
|
25138
25169
|
return ID_RE.test(id);
|
|
25139
25170
|
}
|
|
@@ -25199,17 +25230,17 @@ function parseManifest(raw, dirName, entryExists) {
|
|
|
25199
25230
|
...m.license !== void 0 ? { license: m.license } : {}
|
|
25200
25231
|
};
|
|
25201
25232
|
}
|
|
25202
|
-
function readExtensionDir(dir, id =
|
|
25233
|
+
function readExtensionDir(dir, id = path62.basename(dir)) {
|
|
25203
25234
|
let raw;
|
|
25204
25235
|
try {
|
|
25205
|
-
raw = JSON.parse(fs53.readFileSync(
|
|
25236
|
+
raw = JSON.parse(fs53.readFileSync(path62.join(dir, MANIFEST_FILE), "utf-8"));
|
|
25206
25237
|
} catch (err) {
|
|
25207
25238
|
const code = err.code;
|
|
25208
25239
|
return { id, error: code === "ENOENT" ? `${MANIFEST_FILE} missing` : `${MANIFEST_FILE} unreadable: ${err instanceof Error ? err.message : String(err)}` };
|
|
25209
25240
|
}
|
|
25210
25241
|
const parsed = parseManifest(raw, id, (entry) => {
|
|
25211
25242
|
try {
|
|
25212
|
-
return fs53.statSync(
|
|
25243
|
+
return fs53.statSync(path62.join(dir, entry)).isFile();
|
|
25213
25244
|
} catch {
|
|
25214
25245
|
return false;
|
|
25215
25246
|
}
|
|
@@ -25239,7 +25270,7 @@ function scanExtensions() {
|
|
|
25239
25270
|
errors.push({ id: entry.name, error: "directory name is not a valid extension id" });
|
|
25240
25271
|
continue;
|
|
25241
25272
|
}
|
|
25242
|
-
const result = readExtensionDir(
|
|
25273
|
+
const result = readExtensionDir(path62.join(root, entry.name));
|
|
25243
25274
|
if ("error" in result)
|
|
25244
25275
|
errors.push(result);
|
|
25245
25276
|
else
|
|
@@ -25278,7 +25309,7 @@ var init_registry2 = __esm({
|
|
|
25278
25309
|
|
|
25279
25310
|
// ../server/dist/extensions/install.js
|
|
25280
25311
|
import fs54 from "node:fs";
|
|
25281
|
-
import
|
|
25312
|
+
import path63 from "node:path";
|
|
25282
25313
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
25283
25314
|
import JSZip2 from "jszip";
|
|
25284
25315
|
function safeEntryPath(name) {
|
|
@@ -25309,26 +25340,26 @@ async function unpackZip(zipBuf, dest) {
|
|
|
25309
25340
|
const perm = entry.unixPermissions;
|
|
25310
25341
|
if (typeof perm === "number" && (perm & S_IFMT) === S_IFLNK)
|
|
25311
25342
|
throw new ExtensionInstallError(`zip entry is a symlink: ${entry.name}`);
|
|
25312
|
-
const abs =
|
|
25343
|
+
const abs = path63.join(dest, rel);
|
|
25313
25344
|
if (entry.dir) {
|
|
25314
25345
|
fs54.mkdirSync(abs, { recursive: true });
|
|
25315
25346
|
continue;
|
|
25316
25347
|
}
|
|
25317
|
-
fs54.mkdirSync(
|
|
25348
|
+
fs54.mkdirSync(path63.dirname(abs), { recursive: true });
|
|
25318
25349
|
fs54.writeFileSync(abs, await entry.async("nodebuffer"));
|
|
25319
25350
|
}
|
|
25320
25351
|
}
|
|
25321
25352
|
function stripWrapperDir(dir) {
|
|
25322
|
-
if (fs54.existsSync(
|
|
25353
|
+
if (fs54.existsSync(path63.join(dir, MANIFEST_FILE)))
|
|
25323
25354
|
return;
|
|
25324
25355
|
const children = fs54.readdirSync(dir, { withFileTypes: true });
|
|
25325
25356
|
if (children.length !== 1 || !children[0].isDirectory())
|
|
25326
25357
|
return;
|
|
25327
|
-
const inner =
|
|
25328
|
-
if (!fs54.existsSync(
|
|
25358
|
+
const inner = path63.join(dir, children[0].name);
|
|
25359
|
+
if (!fs54.existsSync(path63.join(inner, MANIFEST_FILE)))
|
|
25329
25360
|
return;
|
|
25330
25361
|
for (const name of fs54.readdirSync(inner)) {
|
|
25331
|
-
fs54.renameSync(
|
|
25362
|
+
fs54.renameSync(path63.join(inner, name), path63.join(dir, name));
|
|
25332
25363
|
}
|
|
25333
25364
|
fs54.rmdirSync(inner);
|
|
25334
25365
|
}
|
|
@@ -25338,14 +25369,14 @@ function rand() {
|
|
|
25338
25369
|
async function installExtensionZip(zipBuf, expectId) {
|
|
25339
25370
|
const root = extensionsRoot();
|
|
25340
25371
|
fs54.mkdirSync(root, { recursive: true });
|
|
25341
|
-
const stage =
|
|
25372
|
+
const stage = path63.join(root, `.tmp-unpack-${rand()}`);
|
|
25342
25373
|
fs54.mkdirSync(stage);
|
|
25343
25374
|
try {
|
|
25344
25375
|
await unpackZip(zipBuf, stage);
|
|
25345
25376
|
stripWrapperDir(stage);
|
|
25346
25377
|
let manifestId;
|
|
25347
25378
|
try {
|
|
25348
|
-
const raw = JSON.parse(fs54.readFileSync(
|
|
25379
|
+
const raw = JSON.parse(fs54.readFileSync(path63.join(stage, MANIFEST_FILE), "utf-8"));
|
|
25349
25380
|
manifestId = typeof raw.id === "string" ? raw.id : "";
|
|
25350
25381
|
} catch (err) {
|
|
25351
25382
|
throw new ExtensionInstallError(`${MANIFEST_FILE} missing or unreadable at the zip root: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -25357,8 +25388,8 @@ async function installExtensionZip(zipBuf, expectId) {
|
|
|
25357
25388
|
const verdict = readExtensionDir(stage, manifestId);
|
|
25358
25389
|
if ("error" in verdict)
|
|
25359
25390
|
throw new ExtensionInstallError(`invalid extension: ${verdict.error}`);
|
|
25360
|
-
const target =
|
|
25361
|
-
const old =
|
|
25391
|
+
const target = path63.join(root, manifestId);
|
|
25392
|
+
const old = path63.join(root, `.old-${manifestId}-${rand()}`);
|
|
25362
25393
|
const hadOld = fs54.existsSync(target);
|
|
25363
25394
|
if (hadOld)
|
|
25364
25395
|
fs54.renameSync(target, old);
|
|
@@ -25383,7 +25414,7 @@ async function installExtensionZip(zipBuf, expectId) {
|
|
|
25383
25414
|
function uninstallExtension(id) {
|
|
25384
25415
|
if (!isExtensionId(id))
|
|
25385
25416
|
throw new ExtensionInstallError(`"${id}" is not a valid extension id`);
|
|
25386
|
-
const dir =
|
|
25417
|
+
const dir = path63.join(extensionsRoot(), id);
|
|
25387
25418
|
if (!fs54.existsSync(dir))
|
|
25388
25419
|
return false;
|
|
25389
25420
|
fs54.rmSync(dir, { recursive: true, force: true });
|
|
@@ -25666,17 +25697,17 @@ function passwordStrengthError(pw) {
|
|
|
25666
25697
|
}
|
|
25667
25698
|
function authMiddleware() {
|
|
25668
25699
|
return async (c, next) => {
|
|
25669
|
-
const
|
|
25670
|
-
if (PUBLIC_PATHS.some((p) =>
|
|
25700
|
+
const path74 = c.req.path;
|
|
25701
|
+
if (PUBLIC_PATHS.some((p) => path74 === p || path74.startsWith(p + "?"))) {
|
|
25671
25702
|
return next();
|
|
25672
25703
|
}
|
|
25673
|
-
if (EXTENSION_ASSET_PATH.test(
|
|
25704
|
+
if (EXTENSION_ASSET_PATH.test(path74)) {
|
|
25674
25705
|
return next();
|
|
25675
25706
|
}
|
|
25676
25707
|
const token = getCookie(c, COOKIE_NAME);
|
|
25677
25708
|
const payload = validateToken(token);
|
|
25678
25709
|
if (!payload) {
|
|
25679
|
-
if (!
|
|
25710
|
+
if (!path74.startsWith("/api/")) {
|
|
25680
25711
|
return next();
|
|
25681
25712
|
}
|
|
25682
25713
|
return c.json({ error: "Unauthorized" }, 401);
|
|
@@ -25711,7 +25742,7 @@ var init_auth = __esm({
|
|
|
25711
25742
|
// ../server/dist/routes/extensions.js
|
|
25712
25743
|
import { Hono as Hono16 } from "hono";
|
|
25713
25744
|
import fs56 from "node:fs";
|
|
25714
|
-
import
|
|
25745
|
+
import path64 from "node:path";
|
|
25715
25746
|
import { Readable as Readable2 } from "node:stream";
|
|
25716
25747
|
function assetMime(fileName) {
|
|
25717
25748
|
const ext = fileName.split(".").pop()?.toLowerCase() ?? "";
|
|
@@ -25729,12 +25760,12 @@ function resolveAsset(id, version, rest) {
|
|
|
25729
25760
|
let dir;
|
|
25730
25761
|
let real;
|
|
25731
25762
|
try {
|
|
25732
|
-
dir = fs56.realpathSync(
|
|
25733
|
-
real = fs56.realpathSync(
|
|
25763
|
+
dir = fs56.realpathSync(path64.join(extensionsRoot(), id));
|
|
25764
|
+
real = fs56.realpathSync(path64.join(dir, ...segments));
|
|
25734
25765
|
} catch {
|
|
25735
25766
|
return null;
|
|
25736
25767
|
}
|
|
25737
|
-
if (real !== dir && !real.startsWith(dir +
|
|
25768
|
+
if (real !== dir && !real.startsWith(dir + path64.sep))
|
|
25738
25769
|
return null;
|
|
25739
25770
|
try {
|
|
25740
25771
|
if (!fs56.statSync(real).isFile())
|
|
@@ -26096,7 +26127,7 @@ var init_ticker = __esm({
|
|
|
26096
26127
|
});
|
|
26097
26128
|
|
|
26098
26129
|
// ../server/dist/evolution/spawn.js
|
|
26099
|
-
import
|
|
26130
|
+
import path65 from "node:path";
|
|
26100
26131
|
import { spawn as spawn4 } from "node:child_process";
|
|
26101
26132
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
26102
26133
|
var __dirname2, WRAPPER_PATH, realEvoSpawner;
|
|
@@ -26104,8 +26135,8 @@ var init_spawn = __esm({
|
|
|
26104
26135
|
"../server/dist/evolution/spawn.js"() {
|
|
26105
26136
|
"use strict";
|
|
26106
26137
|
init_child_env();
|
|
26107
|
-
__dirname2 =
|
|
26108
|
-
WRAPPER_PATH =
|
|
26138
|
+
__dirname2 = path65.dirname(fileURLToPath2(import.meta.url));
|
|
26139
|
+
WRAPPER_PATH = path65.resolve(__dirname2, "evo-wrapper.js");
|
|
26109
26140
|
realEvoSpawner = (mode, id) => {
|
|
26110
26141
|
const child = spawn4(process.execPath, [WRAPPER_PATH, `--mode=${mode}`, `--id=${id}`], {
|
|
26111
26142
|
detached: true,
|
|
@@ -27584,7 +27615,7 @@ var init_cdn = __esm({
|
|
|
27584
27615
|
|
|
27585
27616
|
// ../server/dist/channels/wechat/send-media.js
|
|
27586
27617
|
import fs58 from "node:fs/promises";
|
|
27587
|
-
import
|
|
27618
|
+
import path66 from "node:path";
|
|
27588
27619
|
function inferKind(filePath) {
|
|
27589
27620
|
const cls = classifyMedia(filePath);
|
|
27590
27621
|
if (cls === "image")
|
|
@@ -27634,7 +27665,7 @@ async function sendMediaFile(params) {
|
|
|
27634
27665
|
aesKeyBase64,
|
|
27635
27666
|
fileSizeCiphertext: prep.filesize,
|
|
27636
27667
|
fileSize: prep.rawsize,
|
|
27637
|
-
fileName:
|
|
27668
|
+
fileName: path66.basename(filePath)
|
|
27638
27669
|
});
|
|
27639
27670
|
const clientId = `halo-media-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
27640
27671
|
const body = {
|
|
@@ -27798,7 +27829,7 @@ var init_login = __esm({
|
|
|
27798
27829
|
|
|
27799
27830
|
// ../server/dist/channels/wechat/handler.js
|
|
27800
27831
|
import fs59 from "node:fs";
|
|
27801
|
-
import
|
|
27832
|
+
import path67 from "node:path";
|
|
27802
27833
|
import QRCode from "qrcode";
|
|
27803
27834
|
function wxRoute(fromUserId, contextToken, contextTokenAt) {
|
|
27804
27835
|
return (prev) => {
|
|
@@ -28219,7 +28250,7 @@ async function handleSlashCommand(args) {
|
|
|
28219
28250
|
await reply(login.message);
|
|
28220
28251
|
return true;
|
|
28221
28252
|
}
|
|
28222
|
-
const tmpPath =
|
|
28253
|
+
const tmpPath = path67.join(tempDir(), `halo-qr-${login.sessionKey}.png`);
|
|
28223
28254
|
await QRCode.toFile(tmpPath, login.qrcodeUrl, { width: 256, margin: 2 });
|
|
28224
28255
|
await sendMediaFile({
|
|
28225
28256
|
baseUrl: account.baseUrl,
|
|
@@ -28308,7 +28339,7 @@ var init_handler4 = __esm({
|
|
|
28308
28339
|
|
|
28309
28340
|
// ../server/dist/routes/wechat.js
|
|
28310
28341
|
import { Hono as Hono18 } from "hono";
|
|
28311
|
-
import
|
|
28342
|
+
import path68 from "node:path";
|
|
28312
28343
|
import fs60 from "node:fs";
|
|
28313
28344
|
function createWechatRoutes(deps) {
|
|
28314
28345
|
const { db, channel } = deps;
|
|
@@ -28334,7 +28365,7 @@ function createWechatRoutes(deps) {
|
|
|
28334
28365
|
return c.json({ error: "sessionKey required" }, 400);
|
|
28335
28366
|
if (!body.workspacePath)
|
|
28336
28367
|
return c.json({ error: "workspacePath required" }, 400);
|
|
28337
|
-
if (!
|
|
28368
|
+
if (!path68.isAbsolute(body.workspacePath))
|
|
28338
28369
|
return c.json({ error: "workspacePath must be absolute" }, 400);
|
|
28339
28370
|
const levelError = accessLevelError(body.accessLevel, CHAT_ACCESS_LEVELS);
|
|
28340
28371
|
if (levelError)
|
|
@@ -28712,10 +28743,10 @@ function createWebRoutes(deps) {
|
|
|
28712
28743
|
const filePath = c.req.query("path");
|
|
28713
28744
|
if (!filePath)
|
|
28714
28745
|
return c.json({ error: "path required" }, 400);
|
|
28715
|
-
const
|
|
28716
|
-
const resolved =
|
|
28717
|
-
const root =
|
|
28718
|
-
if (resolved !== root && !resolved.startsWith(root +
|
|
28746
|
+
const path74 = await import("node:path");
|
|
28747
|
+
const resolved = path74.default.resolve(account.workspacePath, filePath);
|
|
28748
|
+
const root = path74.default.resolve(account.workspacePath);
|
|
28749
|
+
if (resolved !== root && !resolved.startsWith(root + path74.default.sep)) {
|
|
28719
28750
|
return c.json({ error: "path traversal not allowed" }, 403);
|
|
28720
28751
|
}
|
|
28721
28752
|
let real;
|
|
@@ -28726,7 +28757,7 @@ function createWebRoutes(deps) {
|
|
|
28726
28757
|
} catch {
|
|
28727
28758
|
return c.json({ error: "file not found" }, 404);
|
|
28728
28759
|
}
|
|
28729
|
-
if (real !== realRoot && !real.startsWith(realRoot +
|
|
28760
|
+
if (real !== realRoot && !real.startsWith(realRoot + path74.default.sep)) {
|
|
28730
28761
|
return c.json({ error: "path traversal not allowed" }, 403);
|
|
28731
28762
|
}
|
|
28732
28763
|
if (isHiddenWorkspacePath(real, realRoot)) {
|
|
@@ -28735,7 +28766,7 @@ function createWebRoutes(deps) {
|
|
|
28735
28766
|
const stat = fs61.statSync(real);
|
|
28736
28767
|
if (stat.isDirectory())
|
|
28737
28768
|
return c.json({ error: "cannot serve directory" }, 400);
|
|
28738
|
-
const ext =
|
|
28769
|
+
const ext = path74.default.extname(real).toLowerCase();
|
|
28739
28770
|
const nonImageMimes = {
|
|
28740
28771
|
".mp4": "video/mp4",
|
|
28741
28772
|
".webm": "video/webm",
|
|
@@ -28743,7 +28774,7 @@ function createWebRoutes(deps) {
|
|
|
28743
28774
|
".txt": "text/plain"
|
|
28744
28775
|
};
|
|
28745
28776
|
const contentType = imageMimeFromExt(ext) || nonImageMimes[ext] || "application/octet-stream";
|
|
28746
|
-
const fileName =
|
|
28777
|
+
const fileName = path74.default.basename(resolved);
|
|
28747
28778
|
const data = fs61.readFileSync(real);
|
|
28748
28779
|
c.header("content-type", contentType);
|
|
28749
28780
|
c.header("content-disposition", `inline; filename="${fileName}"`);
|
|
@@ -28965,8 +28996,8 @@ async function authTest(botToken) {
|
|
|
28965
28996
|
}
|
|
28966
28997
|
async function uploadFile(args) {
|
|
28967
28998
|
const fs65 = await import("node:fs");
|
|
28968
|
-
const
|
|
28969
|
-
const filename = args.filename ??
|
|
28999
|
+
const path74 = await import("node:path");
|
|
29000
|
+
const filename = args.filename ?? path74.basename(args.filePath);
|
|
28970
29001
|
const stat = fs65.statSync(args.filePath);
|
|
28971
29002
|
if (!stat.isFile())
|
|
28972
29003
|
throw new Error(`[slack:uploadFile] not a regular file: ${args.filePath}`);
|
|
@@ -29130,7 +29161,7 @@ var init_api2 = __esm({
|
|
|
29130
29161
|
});
|
|
29131
29162
|
|
|
29132
29163
|
// ../server/dist/channels/slack/handler.js
|
|
29133
|
-
import
|
|
29164
|
+
import path69 from "node:path";
|
|
29134
29165
|
import { WebSocket } from "ws";
|
|
29135
29166
|
function slashToBang(text6, commandNames) {
|
|
29136
29167
|
if (commandNames.length === 0)
|
|
@@ -29261,7 +29292,7 @@ function startSlackChannel(deps) {
|
|
|
29261
29292
|
const route = bridge.getRoute(sessionId);
|
|
29262
29293
|
if (!account || !route)
|
|
29263
29294
|
return;
|
|
29264
|
-
const resolved =
|
|
29295
|
+
const resolved = path69.resolve(filePath);
|
|
29265
29296
|
await sendMediaOrReport({
|
|
29266
29297
|
filePath,
|
|
29267
29298
|
account,
|
|
@@ -29904,9 +29935,9 @@ async function replyMessage(args) {
|
|
|
29904
29935
|
}
|
|
29905
29936
|
async function uploadImage(args) {
|
|
29906
29937
|
const fs65 = await import("node:fs");
|
|
29907
|
-
const
|
|
29938
|
+
const path74 = await import("node:path");
|
|
29908
29939
|
const buf = fs65.readFileSync(args.filePath);
|
|
29909
|
-
const filename =
|
|
29940
|
+
const filename = path74.basename(args.filePath);
|
|
29910
29941
|
const send = async (token) => {
|
|
29911
29942
|
const form = new FormData();
|
|
29912
29943
|
form.append("image_type", "message");
|
|
@@ -29923,9 +29954,9 @@ async function uploadImage(args) {
|
|
|
29923
29954
|
}
|
|
29924
29955
|
async function uploadFile2(args) {
|
|
29925
29956
|
const fs65 = await import("node:fs");
|
|
29926
|
-
const
|
|
29957
|
+
const path74 = await import("node:path");
|
|
29927
29958
|
const buf = fs65.readFileSync(args.filePath);
|
|
29928
|
-
const filename = args.filename ??
|
|
29959
|
+
const filename = args.filename ?? path74.basename(args.filePath);
|
|
29929
29960
|
const send = async (token) => {
|
|
29930
29961
|
const form = new FormData();
|
|
29931
29962
|
form.append("file_type", args.fileType);
|
|
@@ -29992,7 +30023,7 @@ var init_api3 = __esm({
|
|
|
29992
30023
|
});
|
|
29993
30024
|
|
|
29994
30025
|
// ../server/dist/channels/feishu/handler.js
|
|
29995
|
-
import
|
|
30026
|
+
import path70 from "node:path";
|
|
29996
30027
|
import * as Lark from "@larksuiteoapi/node-sdk";
|
|
29997
30028
|
function buildSessionPrefixForThread2(chatId, rootId) {
|
|
29998
30029
|
return sessionPrefix("feishu", `${chatId}:${rootId}`);
|
|
@@ -30195,7 +30226,7 @@ function startFeishuChannel(deps) {
|
|
|
30195
30226
|
const route = bridge.getRoute(sessionId);
|
|
30196
30227
|
if (!account || !route)
|
|
30197
30228
|
return;
|
|
30198
|
-
const resolved =
|
|
30229
|
+
const resolved = path70.resolve(filePath);
|
|
30199
30230
|
await sendMediaOrReport({
|
|
30200
30231
|
filePath,
|
|
30201
30232
|
account,
|
|
@@ -30362,7 +30393,7 @@ async function replyToInbound(args) {
|
|
|
30362
30393
|
async function sendFeishuMedia(args) {
|
|
30363
30394
|
const { account, inboundMessageId, isP2P, chatId, filePath } = args;
|
|
30364
30395
|
const cls = classifyMedia(filePath);
|
|
30365
|
-
const ext =
|
|
30396
|
+
const ext = path70.extname(filePath).toLowerCase();
|
|
30366
30397
|
if (cls === "image") {
|
|
30367
30398
|
const { imageKey } = await uploadImage({ appId: account.appId, appSecret: account.appSecret, filePath });
|
|
30368
30399
|
await replyToInboundRaw({
|
|
@@ -30751,7 +30782,7 @@ var init_event_adapter5 = __esm({
|
|
|
30751
30782
|
});
|
|
30752
30783
|
|
|
30753
30784
|
// ../server/dist/channels/wecom/handler.js
|
|
30754
|
-
import
|
|
30785
|
+
import path71 from "node:path";
|
|
30755
30786
|
import fs62 from "node:fs/promises";
|
|
30756
30787
|
import { WSClient as WSClient2, generateReqId } from "@wecom/aibot-node-sdk";
|
|
30757
30788
|
function pickConversation(body) {
|
|
@@ -30882,13 +30913,13 @@ async function replyText(wsClient, route, text6) {
|
|
|
30882
30913
|
}
|
|
30883
30914
|
async function sendWecomMedia(args) {
|
|
30884
30915
|
const { wsClient, route, filePath } = args;
|
|
30885
|
-
const ext =
|
|
30916
|
+
const ext = path71.extname(filePath).toLowerCase();
|
|
30886
30917
|
const cls = classifyMedia(filePath);
|
|
30887
30918
|
const type = cls === "image" && [".png", ".jpg", ".jpeg", ".gif"].includes(ext) ? "image" : cls === "video" && ext === ".mp4" ? "video" : "file";
|
|
30888
30919
|
const buf = await fs62.readFile(filePath);
|
|
30889
30920
|
if (buf.length > MAX_WECOM_DOWNLOAD_BYTES)
|
|
30890
30921
|
throw new Error("file exceeds 20MB");
|
|
30891
|
-
const { media_id: mediaId } = await wsClient.uploadMedia(buf, { type, filename:
|
|
30922
|
+
const { media_id: mediaId } = await wsClient.uploadMedia(buf, { type, filename: path71.basename(filePath) });
|
|
30892
30923
|
if (route.reqId)
|
|
30893
30924
|
await wsClient.replyMedia({ headers: { req_id: route.reqId } }, type, mediaId);
|
|
30894
30925
|
else
|
|
@@ -30933,7 +30964,7 @@ function startWecomChannel(deps) {
|
|
|
30933
30964
|
const wsClient = states.get(accountId)?.wsClient;
|
|
30934
30965
|
if (!account || !route || !wsClient)
|
|
30935
30966
|
return;
|
|
30936
|
-
const resolved =
|
|
30967
|
+
const resolved = path71.resolve(filePath);
|
|
30937
30968
|
await sendMediaOrReport({
|
|
30938
30969
|
filePath,
|
|
30939
30970
|
account,
|
|
@@ -31342,7 +31373,7 @@ import { compress } from "hono/compress";
|
|
|
31342
31373
|
import { serve } from "@hono/node-server";
|
|
31343
31374
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
31344
31375
|
import { WebSocketServer } from "ws";
|
|
31345
|
-
import
|
|
31376
|
+
import path72 from "node:path";
|
|
31346
31377
|
import fs63 from "node:fs";
|
|
31347
31378
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
31348
31379
|
import { homedir as homedir24 } from "node:os";
|
|
@@ -31350,9 +31381,9 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
|
31350
31381
|
function findProjectRoot() {
|
|
31351
31382
|
let dir = process.cwd();
|
|
31352
31383
|
for (let i = 0; i < 32; i++) {
|
|
31353
|
-
if (fs63.existsSync(
|
|
31384
|
+
if (fs63.existsSync(path72.join(dir, "pnpm-workspace.yaml")))
|
|
31354
31385
|
return dir;
|
|
31355
|
-
const parent =
|
|
31386
|
+
const parent = path72.dirname(dir);
|
|
31356
31387
|
if (parent === dir)
|
|
31357
31388
|
break;
|
|
31358
31389
|
dir = parent;
|
|
@@ -31361,7 +31392,7 @@ function findProjectRoot() {
|
|
|
31361
31392
|
return process.cwd();
|
|
31362
31393
|
}
|
|
31363
31394
|
function acquireSingleInstanceLock(lockFile) {
|
|
31364
|
-
fs63.mkdirSync(
|
|
31395
|
+
fs63.mkdirSync(path72.dirname(lockFile), { recursive: true });
|
|
31365
31396
|
const fd = fs63.openSync(lockFile, fs63.constants.O_RDWR | fs63.constants.O_CREAT, 420);
|
|
31366
31397
|
const result = spawnSync3("flock", ["-n", "3"], {
|
|
31367
31398
|
stdio: ["ignore", "ignore", "ignore", fd]
|
|
@@ -31418,7 +31449,7 @@ function isProcessAlive(pid) {
|
|
|
31418
31449
|
}
|
|
31419
31450
|
}
|
|
31420
31451
|
function readGitSha() {
|
|
31421
|
-
if (!fs63.existsSync(
|
|
31452
|
+
if (!fs63.existsSync(path72.join(PROJECT_ROOT, "pnpm-workspace.yaml")) || !fs63.existsSync(path72.join(PROJECT_ROOT, ".git")))
|
|
31422
31453
|
return null;
|
|
31423
31454
|
try {
|
|
31424
31455
|
const rev = spawnSync3("git", ["rev-parse", "--short", "HEAD"], { cwd: PROJECT_ROOT, encoding: "utf-8" });
|
|
@@ -31439,14 +31470,14 @@ function applySandboxPaths() {
|
|
|
31439
31470
|
}
|
|
31440
31471
|
function resolveFrontendDir() {
|
|
31441
31472
|
if (process.env.HALO_FRONTEND_DIR)
|
|
31442
|
-
return
|
|
31443
|
-
const bundled =
|
|
31444
|
-
if (fs63.existsSync(
|
|
31473
|
+
return path72.resolve(process.env.HALO_FRONTEND_DIR);
|
|
31474
|
+
const bundled = path72.resolve(__dirname3, "..", "admin-out");
|
|
31475
|
+
if (fs63.existsSync(path72.join(bundled, "index.html")))
|
|
31445
31476
|
return bundled;
|
|
31446
|
-
const sibling =
|
|
31447
|
-
if (fs63.existsSync(
|
|
31477
|
+
const sibling = path72.resolve(__dirname3, "..", "..", "admin", "out");
|
|
31478
|
+
if (fs63.existsSync(path72.join(sibling, "index.html")))
|
|
31448
31479
|
return sibling;
|
|
31449
|
-
return
|
|
31480
|
+
return path72.resolve(PROJECT_ROOT, "packages", "admin", "out");
|
|
31450
31481
|
}
|
|
31451
31482
|
async function gracefulShutdown(signal) {
|
|
31452
31483
|
console.log(`[Server] Received ${signal}, shutting down gracefully...`);
|
|
@@ -31518,34 +31549,24 @@ var init_dist2 = __esm({
|
|
|
31518
31549
|
init_sandbox();
|
|
31519
31550
|
init_init();
|
|
31520
31551
|
init_git_ssh();
|
|
31521
|
-
__dirname3 =
|
|
31552
|
+
__dirname3 = path72.dirname(fileURLToPath3(import.meta.url));
|
|
31522
31553
|
PORT = config.server.port;
|
|
31523
|
-
HALO_VERSION = "1.5.
|
|
31554
|
+
HALO_VERSION = "1.5.7";
|
|
31524
31555
|
PROJECT_ROOT = findProjectRoot();
|
|
31525
|
-
HALO_HOME4 =
|
|
31556
|
+
HALO_HOME4 = path72.join(homedir24(), ".halo");
|
|
31526
31557
|
GIT_SHA = readGitSha();
|
|
31527
|
-
if (!fs63.existsSync(
|
|
31558
|
+
if (!fs63.existsSync(path72.join(HALO_HOME4, "global", ".template-version"))) {
|
|
31528
31559
|
process.stderr.write("\x1B[31m[Server] ~/.halo/global/ not initialized. Run `halo setup` first.\x1B[0m\n");
|
|
31529
31560
|
process.exit(1);
|
|
31530
31561
|
}
|
|
31531
|
-
|
|
31532
|
-
const seedVersion = readSeedVersion(HALO_HOME4);
|
|
31533
|
-
if (seedVersion > 0 && seedVersion < TEMPLATE_VERSION) {
|
|
31534
|
-
console.log(`[Server] Templates outdated (v${seedVersion} \u2192 v${TEMPLATE_VERSION}), refreshing ~/.halo/global/`);
|
|
31535
|
-
try {
|
|
31536
|
-
ensureHaloHome(HALO_HOME4);
|
|
31537
|
-
} catch (err) {
|
|
31538
|
-
console.error(`[Server] Template refresh failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
31539
|
-
}
|
|
31540
|
-
}
|
|
31541
|
-
}
|
|
31562
|
+
refreshTemplatesIfOutdated(HALO_HOME4, "Server");
|
|
31542
31563
|
AGENTCORE = config.server.runtimeMode === "agentcore";
|
|
31543
31564
|
if (!AGENTCORE && (!config.server.password && !config.server.passwordEnvPlaintext || !config.server.jwtSecret)) {
|
|
31544
31565
|
process.stderr.write("\x1B[31m[Server] admin password not configured. Run `halo setup` to set one, or set the HALO_PASSWORD env.\x1B[0m\n");
|
|
31545
31566
|
process.exit(1);
|
|
31546
31567
|
}
|
|
31547
31568
|
if (!AGENTCORE)
|
|
31548
|
-
acquireSingleInstanceLock(
|
|
31569
|
+
acquireSingleInstanceLock(path72.join(HALO_HOME4, "global", "server.lock"));
|
|
31549
31570
|
commandRegistry.assertDispatchCommands(DISPATCH_COMMANDS);
|
|
31550
31571
|
await initObservability();
|
|
31551
31572
|
initLogger();
|
|
@@ -31607,11 +31628,11 @@ var init_dist2 = __esm({
|
|
|
31607
31628
|
app.route("/api", extensionRoutes);
|
|
31608
31629
|
if (!AGENTCORE)
|
|
31609
31630
|
start();
|
|
31610
|
-
channelDb = createChannelDb(
|
|
31631
|
+
channelDb = createChannelDb(path72.join(HALO_HOME4, "secrets"));
|
|
31611
31632
|
setChannelDb(channelDb);
|
|
31612
|
-
setEvoDb(createEvoDb(
|
|
31613
|
-
setCronDb(createCronDb(
|
|
31614
|
-
setRunsDb(createRunsDb(
|
|
31633
|
+
setEvoDb(createEvoDb(path72.join(HALO_HOME4, "global")));
|
|
31634
|
+
setCronDb(createCronDb(path72.join(HALO_HOME4, "global")));
|
|
31635
|
+
setRunsDb(createRunsDb(path72.join(HALO_HOME4, "global")));
|
|
31615
31636
|
setEvoSpawner(realEvoSpawner);
|
|
31616
31637
|
if (!AGENTCORE) {
|
|
31617
31638
|
startEvoTicker();
|
|
@@ -31626,7 +31647,7 @@ var init_dist2 = __esm({
|
|
|
31626
31647
|
setCronSessionRegistry(registry);
|
|
31627
31648
|
if (OWNS_RUNTIMES) {
|
|
31628
31649
|
for (const ws of listRunningWorkspaces()) {
|
|
31629
|
-
if (!fs63.existsSync(
|
|
31650
|
+
if (!fs63.existsSync(path72.join(ws, ".halo")))
|
|
31630
31651
|
continue;
|
|
31631
31652
|
if (!claimWorkspaceRuntime(ws))
|
|
31632
31653
|
continue;
|
|
@@ -31656,9 +31677,9 @@ var init_dist2 = __esm({
|
|
|
31656
31677
|
console.log(`[Server] AgentCore runtime mode \u2014 workspace: ${config.server.agentcoreWorkspace}`);
|
|
31657
31678
|
}
|
|
31658
31679
|
FRONTEND_DIR = resolveFrontendDir();
|
|
31659
|
-
app.use("/*", serveStatic({ root:
|
|
31680
|
+
app.use("/*", serveStatic({ root: path72.relative(process.cwd(), FRONTEND_DIR) }));
|
|
31660
31681
|
app.get("/*", (c) => {
|
|
31661
|
-
const indexPath =
|
|
31682
|
+
const indexPath = path72.join(FRONTEND_DIR, "index.html");
|
|
31662
31683
|
try {
|
|
31663
31684
|
const html = fs63.readFileSync(indexPath, "utf-8");
|
|
31664
31685
|
return c.html(html);
|
|
@@ -32450,11 +32471,11 @@ process.emitWarning = (warning, ...args) => {
|
|
|
32450
32471
|
|
|
32451
32472
|
// src/index.ts
|
|
32452
32473
|
init_server_supervisor();
|
|
32453
|
-
import
|
|
32474
|
+
import path73 from "node:path";
|
|
32454
32475
|
import fs64 from "node:fs";
|
|
32455
32476
|
import { homedir as homedir25 } from "node:os";
|
|
32456
32477
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
32457
|
-
var VERSION = "1.5.
|
|
32478
|
+
var VERSION = "1.5.7";
|
|
32458
32479
|
var HELP_TOP = `Usage: halo <command> [options]
|
|
32459
32480
|
|
|
32460
32481
|
Commands:
|
|
@@ -32713,8 +32734,8 @@ async function cmdSetup(argv = []) {
|
|
|
32713
32734
|
const { buildBindProviderPlan: buildBindProviderPlan2, KEEP_CURRENT: KEEP_CURRENT2, AWS_CHAIN_PROVIDER: AWS_CHAIN_PROVIDER2 } = await Promise.resolve().then(() => (init_setup_bind_provider(), setup_bind_provider_exports));
|
|
32714
32735
|
const { promptText: promptText2, promptPassword: promptPassword2, promptSelect: promptSelect2, promptMultiSelect: promptMultiSelect2 } = await Promise.resolve().then(() => (init_setup_prompts(), setup_prompts_exports));
|
|
32715
32736
|
const nonInteractive = argv.includes("--non-interactive") || argv.includes("-y");
|
|
32716
|
-
const haloHome2 =
|
|
32717
|
-
const globalDir2 =
|
|
32737
|
+
const haloHome2 = path73.join(homedir25(), ".halo");
|
|
32738
|
+
const globalDir2 = path73.join(haloHome2, "global");
|
|
32718
32739
|
ensureHaloHome2(haloHome2);
|
|
32719
32740
|
process.stderr.write(`[setup] ${haloHome2}/ ready
|
|
32720
32741
|
`);
|
|
@@ -33057,7 +33078,7 @@ async function cmdUpgrade() {
|
|
|
33057
33078
|
`);
|
|
33058
33079
|
process.exit(1);
|
|
33059
33080
|
}
|
|
33060
|
-
const broken = verifyNativeModules2(
|
|
33081
|
+
const broken = verifyNativeModules2(path73.join(rootDir, PKG));
|
|
33061
33082
|
if (broken.length > 0) {
|
|
33062
33083
|
process.stderr.write(
|
|
33063
33084
|
`
|
|
@@ -33088,7 +33109,7 @@ halo: upgrade failed (npm exited ${install.status}). ${hint}
|
|
|
33088
33109
|
async function cmdAgents(flags) {
|
|
33089
33110
|
const { initRuntime: initRuntime2, listAgents: listAgents2 } = await Promise.resolve().then(() => (init_harness(), harness_exports));
|
|
33090
33111
|
await initRuntime2();
|
|
33091
|
-
const workspace =
|
|
33112
|
+
const workspace = path73.resolve(flags.workspace ?? process.cwd());
|
|
33092
33113
|
const agents = await listAgents2(workspace);
|
|
33093
33114
|
if (agents.length === 0) {
|
|
33094
33115
|
process.stderr.write("No agents found.\n");
|
|
@@ -33104,7 +33125,7 @@ async function cmdAgents(flags) {
|
|
|
33104
33125
|
async function cmdSessions(flags) {
|
|
33105
33126
|
const { initRuntime: initRuntime2, listSessions: listSessions2 } = await Promise.resolve().then(() => (init_harness(), harness_exports));
|
|
33106
33127
|
await initRuntime2();
|
|
33107
|
-
const workspace =
|
|
33128
|
+
const workspace = path73.resolve(flags.workspace ?? process.cwd());
|
|
33108
33129
|
const sessions = listSessions2(workspace);
|
|
33109
33130
|
if (sessions.length === 0) {
|
|
33110
33131
|
process.stderr.write("No sessions found.\n");
|
|
@@ -33217,8 +33238,8 @@ ${stdinContent}` : stdinContent;
|
|
|
33217
33238
|
harness.destroy();
|
|
33218
33239
|
}
|
|
33219
33240
|
}
|
|
33220
|
-
var SERVER_LOCK_PATH =
|
|
33221
|
-
var SERVER_LOG_PATH =
|
|
33241
|
+
var SERVER_LOCK_PATH = path73.join(homedir25(), ".halo", "global", "server.lock");
|
|
33242
|
+
var SERVER_LOG_PATH = path73.join(homedir25(), ".halo", "logs", "server.log");
|
|
33222
33243
|
function readServerPid() {
|
|
33223
33244
|
try {
|
|
33224
33245
|
const txt = fs64.readFileSync(SERVER_LOCK_PATH, "utf-8").trim();
|
|
@@ -33308,7 +33329,7 @@ async function cmdServerStart(argv, _unused) {
|
|
|
33308
33329
|
return;
|
|
33309
33330
|
}
|
|
33310
33331
|
const { spawn: spawn5 } = await import("node:child_process");
|
|
33311
|
-
fs64.mkdirSync(
|
|
33332
|
+
fs64.mkdirSync(path73.dirname(SERVER_LOG_PATH), { recursive: true });
|
|
33312
33333
|
const out = fs64.openSync(SERVER_LOG_PATH, "a");
|
|
33313
33334
|
const child = spawn5(process.argv[0], [process.argv[1], "server", "start"], {
|
|
33314
33335
|
detached: true,
|
|
@@ -33428,7 +33449,7 @@ function exitMissingSetup() {
|
|
|
33428
33449
|
process.exit(1);
|
|
33429
33450
|
}
|
|
33430
33451
|
function isHaloHomeReady() {
|
|
33431
|
-
return fs64.existsSync(
|
|
33452
|
+
return fs64.existsSync(path73.join(homedir25(), ".halo", "global", ".template-version"));
|
|
33432
33453
|
}
|
|
33433
33454
|
async function main2() {
|
|
33434
33455
|
const argv = process.argv.slice(2);
|