@zythum02/fello-server 0.1.29 → 0.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -2
- package/out/renderer/assets/{_baseUniq-BApwm7pv.js → _baseUniq-DNNr8R6Z.js} +1 -1
- package/out/renderer/assets/{arc-yKenDsmO.js → arc-fZlBtxL9.js} +1 -1
- package/out/renderer/assets/{architectureDiagram-Q4EWVU46-C31yFVWH.js → architectureDiagram-Q4EWVU46-k4E5eOG6.js} +5 -5
- package/out/renderer/assets/{blockDiagram-DXYQGD6D-6liCvTXv.js → blockDiagram-DXYQGD6D-DUXfUO2U.js} +6 -6
- package/out/renderer/assets/{c4Diagram-AHTNJAMY-Co_b_6bH.js → c4Diagram-AHTNJAMY-Chff2Ong.js} +2 -2
- package/out/renderer/assets/{channel-Dc_jjyUr.js → channel-C3mo-Wfq.js} +1 -1
- package/out/renderer/assets/{chunk-4BX2VUAB-Cg18SQei.js → chunk-4BX2VUAB-DGQRb5sN.js} +1 -1
- package/out/renderer/assets/{chunk-4TB4RGXK-CvSqwINq.js → chunk-4TB4RGXK-BSCZx5Py.js} +5 -5
- package/out/renderer/assets/{chunk-55IACEB6-CfBiPWtx.js → chunk-55IACEB6-BVIv0C3q.js} +1 -1
- package/out/renderer/assets/{chunk-EDXVE4YY-DMjVfNdS.js → chunk-EDXVE4YY-DPmCmhx8.js} +1 -1
- package/out/renderer/assets/{chunk-FMBD7UC4-BbpFqyFG.js → chunk-FMBD7UC4-DM66-_hG.js} +1 -1
- package/out/renderer/assets/{chunk-OYMX7WX6-Cf724x--.js → chunk-OYMX7WX6-Tff_uZlx.js} +3 -3
- package/out/renderer/assets/{chunk-QZHKN3VN-4ZNIwknr.js → chunk-QZHKN3VN-C86eKqSd.js} +1 -1
- package/out/renderer/assets/{chunk-YZCP3GAM-D1j7xGGR.js → chunk-YZCP3GAM-CHuoIosP.js} +1 -1
- package/out/renderer/assets/{classDiagram-6PBFFD2Q-OFMeoPav.js → classDiagram-6PBFFD2Q-pm-iptmM.js} +6 -6
- package/out/renderer/assets/{classDiagram-v2-HSJHXN6E-OFMeoPav.js → classDiagram-v2-HSJHXN6E-pm-iptmM.js} +6 -6
- package/out/renderer/assets/{clone-Cm3RO2Zl.js → clone-5TzmfoWe.js} +1 -1
- package/out/renderer/assets/{cose-bilkent-S5V4N54A-lCfWcP6y.js → cose-bilkent-S5V4N54A-DVrDSw12.js} +1 -1
- package/out/renderer/assets/{dagre-KV5264BT-4I0h4wyh.js → dagre-KV5264BT-DdjpmydK.js} +6 -6
- package/out/renderer/assets/{diagram-5BDNPKRD-C1mEpAlt.js → diagram-5BDNPKRD-CdTSROj9.js} +6 -6
- package/out/renderer/assets/{diagram-G4DWMVQ6-C_g_DZm9.js → diagram-G4DWMVQ6-DQ1x-vhi.js} +6 -6
- package/out/renderer/assets/{diagram-MMDJMWI5-Di6wZV6-.js → diagram-MMDJMWI5-40ryNdvI.js} +5 -5
- package/out/renderer/assets/{diagram-TYMM5635-aF8hIDx1.js → diagram-TYMM5635-tf8FuJg1.js} +5 -5
- package/out/renderer/assets/{erDiagram-SMLLAGMA-Bk9QFZ27.js → erDiagram-SMLLAGMA-BciRZ0dO.js} +4 -4
- package/out/renderer/assets/{flowDiagram-DWJPFMVM-Dfg0LLup.js → flowDiagram-DWJPFMVM-CYDqfzx3.js} +6 -6
- package/out/renderer/assets/{ganttDiagram-T4ZO3ILL-lTjaJTs0.js → ganttDiagram-T4ZO3ILL-CRhxy6fZ.js} +2 -2
- package/out/renderer/assets/{gitGraphDiagram-UUTBAWPF-C74WBszH.js → gitGraphDiagram-UUTBAWPF-BadxOCq2.js} +6 -6
- package/out/renderer/assets/{graph-DGEX1eV1.js → graph-B3RLQ95r.js} +2 -2
- package/out/renderer/assets/{highlighted-body-OFNGDK62-DQWoSdTY.js → highlighted-body-OFNGDK62-CrGFRrSX.js} +1 -1
- package/out/renderer/assets/{index-BZzw3jIU.js → index-B1oSpSBX.js} +2137 -950
- package/out/renderer/assets/index-COLJTco3.css +382 -0
- package/out/renderer/assets/{infoDiagram-42DDH7IO-CR4ZLAM1.js → infoDiagram-42DDH7IO-DLMGtQF0.js} +4 -4
- package/out/renderer/assets/{ishikawaDiagram-UXIWVN3A-uXL-4FGw.js → ishikawaDiagram-UXIWVN3A-D8djsZeF.js} +1 -1
- package/out/renderer/assets/{journeyDiagram-VCZTEJTY-Ds2OL3Lo.js → journeyDiagram-VCZTEJTY-567Gpkxf.js} +4 -4
- package/out/renderer/assets/{kanban-definition-6JOO6SKY-CZ1CZVyP.js → kanban-definition-6JOO6SKY-DPjxCDrA.js} +2 -2
- package/out/renderer/assets/{layout-CNGveWdi.js → layout-CGQjv10p.js} +4 -4
- package/out/renderer/assets/{linear-CnHAiAJ3.js → linear-S4Y_UBCp.js} +1 -1
- package/out/renderer/assets/{min-D63AfN0e.js → min-DpKM6qkq.js} +2 -2
- package/out/renderer/assets/{mindmap-definition-QFDTVHPH-C3U3xkIJ.js → mindmap-definition-QFDTVHPH-BtxeumQc.js} +3 -3
- package/out/renderer/assets/{pieDiagram-DEJITSTG-C8AxK_-F.js → pieDiagram-DEJITSTG-n1UTGYDH.js} +6 -6
- package/out/renderer/assets/{quadrantDiagram-34T5L4WZ-BdiZmi7w.js → quadrantDiagram-34T5L4WZ-DXaOIoV-.js} +2 -2
- package/out/renderer/assets/{requirementDiagram-MS252O5E-BHIfl5Tz.js → requirementDiagram-MS252O5E-CTmWVt-P.js} +3 -3
- package/out/renderer/assets/{sankeyDiagram-XADWPNL6-SthTR8cL.js → sankeyDiagram-XADWPNL6-BXOndA46.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-FGHM5R23-COKEbCYM.js → sequenceDiagram-FGHM5R23-C5v5_yv_.js} +3 -3
- package/out/renderer/assets/{stateDiagram-FHFEXIEX-7zRGBf7O.js → stateDiagram-FHFEXIEX-D6Vd4_MM.js} +8 -8
- package/out/renderer/assets/{stateDiagram-v2-QKLJ7IA2-BqHJ_ZBX.js → stateDiagram-v2-QKLJ7IA2-De00f0TU.js} +4 -4
- package/out/renderer/assets/{timeline-definition-GMOUNBTQ-AvZAT5J-.js → timeline-definition-GMOUNBTQ-DxOCmdWf.js} +2 -2
- package/out/renderer/assets/{vennDiagram-DHZGUBPP-oSTndBDY.js → vennDiagram-DHZGUBPP-VNGucDZS.js} +1 -1
- package/out/renderer/assets/{wardley-RL74JXVD-C8hIuf19.js → wardley-RL74JXVD-BbxXQNlq.js} +3 -3
- package/out/renderer/assets/{wardleyDiagram-NUSXRM2D-Dv2kSOMM.js → wardleyDiagram-NUSXRM2D-BqldBvm5.js} +5 -5
- package/out/renderer/assets/{xychartDiagram-5P7HB3ND-J9z4uuMK.js → xychartDiagram-5P7HB3ND-BrCeeMZz.js} +2 -2
- package/out/renderer/index.html +2 -2
- package/out/server/main.js +210 -165
- package/package.json +1 -1
- package/out/renderer/assets/index-Cv3lJTlc.css +0 -382
package/out/server/main.js
CHANGED
|
@@ -3319,7 +3319,7 @@ import { createServer } from "http";
|
|
|
3319
3319
|
import { WebSocketServer } from "ws";
|
|
3320
3320
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
3321
3321
|
import { networkInterfaces } from "os";
|
|
3322
|
-
import { dirname, join as
|
|
3322
|
+
import { dirname as dirname2, join as join5 } from "path";
|
|
3323
3323
|
import { fileURLToPath } from "url";
|
|
3324
3324
|
import { readFile as readFile4, stat as stat2 } from "fs/promises";
|
|
3325
3325
|
|
|
@@ -3389,6 +3389,146 @@ async function serveProjectFile(projectCwd, relativePath) {
|
|
|
3389
3389
|
}
|
|
3390
3390
|
}
|
|
3391
3391
|
|
|
3392
|
+
// src/backend/automation/store.ts
|
|
3393
|
+
import { join as join4, dirname } from "path";
|
|
3394
|
+
import { homedir as homedir2 } from "os";
|
|
3395
|
+
import {
|
|
3396
|
+
mkdirSync as mkdirSync3,
|
|
3397
|
+
writeFileSync as writeFileSync3,
|
|
3398
|
+
readFileSync as readFileSync3,
|
|
3399
|
+
readdirSync as readdirSync2,
|
|
3400
|
+
rmSync as rmSync3,
|
|
3401
|
+
existsSync as existsSync2,
|
|
3402
|
+
statSync as statSync2
|
|
3403
|
+
} from "fs";
|
|
3404
|
+
var AUTOMATIONS_DIR = join4(homedir2(), ".fello", "automations");
|
|
3405
|
+
mkdirSync3(AUTOMATIONS_DIR, { recursive: true });
|
|
3406
|
+
var store = {
|
|
3407
|
+
scheduleDir(scheduleId) {
|
|
3408
|
+
return join4(AUTOMATIONS_DIR, scheduleId);
|
|
3409
|
+
},
|
|
3410
|
+
scheduleConfigPath(scheduleId) {
|
|
3411
|
+
return join4(this.scheduleDir(scheduleId), "schedule.json");
|
|
3412
|
+
},
|
|
3413
|
+
tasksDir(scheduleId) {
|
|
3414
|
+
return join4(this.scheduleDir(scheduleId), "tasks");
|
|
3415
|
+
},
|
|
3416
|
+
taskDir(scheduleId, taskId) {
|
|
3417
|
+
return join4(this.tasksDir(scheduleId), taskId);
|
|
3418
|
+
},
|
|
3419
|
+
taskMetaPath(scheduleId, taskId) {
|
|
3420
|
+
return join4(this.taskDir(scheduleId, taskId), "task.json");
|
|
3421
|
+
},
|
|
3422
|
+
listSchedules() {
|
|
3423
|
+
if (!existsSync2(AUTOMATIONS_DIR)) return [];
|
|
3424
|
+
const dirs = readdirSync2(AUTOMATIONS_DIR);
|
|
3425
|
+
const list = [];
|
|
3426
|
+
for (const dir of dirs) {
|
|
3427
|
+
try {
|
|
3428
|
+
const raw = JSON.parse(readFileSync3(this.scheduleConfigPath(dir), "utf-8"));
|
|
3429
|
+
list.push(raw);
|
|
3430
|
+
} catch {
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
list.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
3434
|
+
return list;
|
|
3435
|
+
},
|
|
3436
|
+
getSchedule(scheduleId) {
|
|
3437
|
+
try {
|
|
3438
|
+
return JSON.parse(readFileSync3(this.scheduleConfigPath(scheduleId), "utf-8"));
|
|
3439
|
+
} catch {
|
|
3440
|
+
return null;
|
|
3441
|
+
}
|
|
3442
|
+
},
|
|
3443
|
+
saveSchedule(schedule) {
|
|
3444
|
+
const dir = this.scheduleDir(schedule.id);
|
|
3445
|
+
mkdirSync3(dir, { recursive: true });
|
|
3446
|
+
mkdirSync3(this.tasksDir(schedule.id), { recursive: true });
|
|
3447
|
+
writeFileSync3(this.scheduleConfigPath(schedule.id), JSON.stringify(schedule, null, 2));
|
|
3448
|
+
},
|
|
3449
|
+
deleteSchedule(scheduleId) {
|
|
3450
|
+
const dir = this.scheduleDir(scheduleId);
|
|
3451
|
+
if (existsSync2(dir)) {
|
|
3452
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
3453
|
+
}
|
|
3454
|
+
},
|
|
3455
|
+
listTasks(scheduleId) {
|
|
3456
|
+
const dir = this.tasksDir(scheduleId);
|
|
3457
|
+
if (!existsSync2(dir)) return [];
|
|
3458
|
+
const dirs = readdirSync2(dir);
|
|
3459
|
+
const list = [];
|
|
3460
|
+
for (const d of dirs) {
|
|
3461
|
+
try {
|
|
3462
|
+
const raw = JSON.parse(readFileSync3(this.taskMetaPath(scheduleId, d), "utf-8"));
|
|
3463
|
+
list.push(raw);
|
|
3464
|
+
} catch {
|
|
3465
|
+
}
|
|
3466
|
+
}
|
|
3467
|
+
list.sort((a, b) => b.startedAt - a.startedAt);
|
|
3468
|
+
return list;
|
|
3469
|
+
},
|
|
3470
|
+
getTask(scheduleId, taskId) {
|
|
3471
|
+
try {
|
|
3472
|
+
return JSON.parse(readFileSync3(this.taskMetaPath(scheduleId, taskId), "utf-8"));
|
|
3473
|
+
} catch {
|
|
3474
|
+
return null;
|
|
3475
|
+
}
|
|
3476
|
+
},
|
|
3477
|
+
saveTask(scheduleId, task) {
|
|
3478
|
+
const dir = this.taskDir(scheduleId, task.id);
|
|
3479
|
+
mkdirSync3(dir, { recursive: true });
|
|
3480
|
+
writeFileSync3(this.taskMetaPath(scheduleId, task.id), JSON.stringify(task, null, 2));
|
|
3481
|
+
},
|
|
3482
|
+
deleteTask(scheduleId, taskId) {
|
|
3483
|
+
const dir = this.taskDir(scheduleId, taskId);
|
|
3484
|
+
if (existsSync2(dir)) {
|
|
3485
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
3486
|
+
}
|
|
3487
|
+
},
|
|
3488
|
+
listTaskFiles(scheduleId, taskId) {
|
|
3489
|
+
const dir = this.taskDir(scheduleId, taskId);
|
|
3490
|
+
if (!existsSync2(dir)) return [];
|
|
3491
|
+
const entries = readdirSync2(dir);
|
|
3492
|
+
return entries.filter((f) => f !== "task.json").map((f) => {
|
|
3493
|
+
const fullPath = join4(dir, f);
|
|
3494
|
+
const s = statSync2(fullPath);
|
|
3495
|
+
if (s.isDirectory()) {
|
|
3496
|
+
return this._listDirRecursive(fullPath, f);
|
|
3497
|
+
}
|
|
3498
|
+
return f;
|
|
3499
|
+
}).flat().sort();
|
|
3500
|
+
},
|
|
3501
|
+
_listDirRecursive(dir, prefix) {
|
|
3502
|
+
const result = [];
|
|
3503
|
+
const entries = readdirSync2(dir);
|
|
3504
|
+
for (const entry of entries) {
|
|
3505
|
+
const full = join4(dir, entry);
|
|
3506
|
+
const s = statSync2(full);
|
|
3507
|
+
if (s.isDirectory()) {
|
|
3508
|
+
result.push(...this._listDirRecursive(full, join4(prefix, entry)));
|
|
3509
|
+
} else {
|
|
3510
|
+
result.push(join4(prefix, entry));
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
return result;
|
|
3514
|
+
},
|
|
3515
|
+
readTaskFile(scheduleId, taskId, filePath, encoding) {
|
|
3516
|
+
const base = this.taskDir(scheduleId, taskId);
|
|
3517
|
+
const fullPath = join4(base, filePath);
|
|
3518
|
+
if (!fullPath.startsWith(base + "/") && fullPath !== base) throw new Error("Invalid file path");
|
|
3519
|
+
if (!existsSync2(fullPath)) throw new Error("File not found");
|
|
3520
|
+
if (encoding === "base64") return readFileSync3(fullPath).toString("base64");
|
|
3521
|
+
return readFileSync3(fullPath, "utf-8");
|
|
3522
|
+
},
|
|
3523
|
+
writeTaskFile(scheduleId, taskId, filePath, content) {
|
|
3524
|
+
const base = this.taskDir(scheduleId, taskId);
|
|
3525
|
+
const fullPath = join4(base, filePath);
|
|
3526
|
+
if (!fullPath.startsWith(base + "/") && fullPath !== base) throw new Error("Invalid file path");
|
|
3527
|
+
mkdirSync3(dirname(fullPath), { recursive: true });
|
|
3528
|
+
writeFileSync3(fullPath, content);
|
|
3529
|
+
}
|
|
3530
|
+
};
|
|
3531
|
+
|
|
3392
3532
|
// src/backend/utils.ts
|
|
3393
3533
|
import { relative as relative2, resolve as resolve3, isAbsolute as isAbsolute2 } from "path";
|
|
3394
3534
|
function toPosixPath(p) {
|
|
@@ -3460,7 +3600,7 @@ function extractErrorMessage(error) {
|
|
|
3460
3600
|
|
|
3461
3601
|
// src/backend/webui.ts
|
|
3462
3602
|
import * as mimeTypes2 from "mime-types";
|
|
3463
|
-
var __dirname =
|
|
3603
|
+
var __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
3464
3604
|
var httpServer = null;
|
|
3465
3605
|
var wss = null;
|
|
3466
3606
|
var currentToken = null;
|
|
@@ -3573,17 +3713,33 @@ async function startWebUI(options) {
|
|
|
3573
3713
|
res.end(result.body);
|
|
3574
3714
|
return;
|
|
3575
3715
|
}
|
|
3716
|
+
if (url.pathname.startsWith("/automation/")) {
|
|
3717
|
+
const pathParts = url.pathname.split("/");
|
|
3718
|
+
const scheduleId = pathParts[2] || "";
|
|
3719
|
+
const taskId = pathParts[4] || "";
|
|
3720
|
+
const relativePath = decodeURIComponent(pathParts.slice(5).join("/") || "");
|
|
3721
|
+
if (!scheduleId || pathParts[3] !== "task" || !taskId || !relativePath) {
|
|
3722
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
3723
|
+
res.end("Bad Request");
|
|
3724
|
+
return;
|
|
3725
|
+
}
|
|
3726
|
+
const taskDir = store.taskDir(scheduleId, taskId);
|
|
3727
|
+
const result = await serveProjectFile(taskDir, relativePath);
|
|
3728
|
+
res.writeHead(result.status, { "Content-Type": result.mimeType });
|
|
3729
|
+
res.end(result.body);
|
|
3730
|
+
return;
|
|
3731
|
+
}
|
|
3576
3732
|
try {
|
|
3577
3733
|
const isFile = url.pathname !== "/" && !url.pathname.endsWith("/");
|
|
3578
3734
|
let reqPath = url.pathname;
|
|
3579
3735
|
if (!isFile) {
|
|
3580
3736
|
reqPath = "/index.html";
|
|
3581
3737
|
}
|
|
3582
|
-
const baseDir =
|
|
3583
|
-
let filePath =
|
|
3738
|
+
const baseDir = join5(__dirname, "../renderer");
|
|
3739
|
+
let filePath = join5(baseDir, reqPath);
|
|
3584
3740
|
let s = await stat2(filePath).catch(() => null);
|
|
3585
3741
|
if (!s || s.isDirectory()) {
|
|
3586
|
-
filePath =
|
|
3742
|
+
filePath = join5(baseDir, "index.html");
|
|
3587
3743
|
}
|
|
3588
3744
|
const mime = mimeTypes2.lookup(filePath) || "application/octet-stream";
|
|
3589
3745
|
const content = await readFile4(filePath);
|
|
@@ -3689,15 +3845,15 @@ function getWebUIUrl(addressInfo) {
|
|
|
3689
3845
|
|
|
3690
3846
|
// src/backend/socket-server.ts
|
|
3691
3847
|
import { createServer as createServer2 } from "http";
|
|
3692
|
-
import { dirname as
|
|
3693
|
-
import { mkdirSync as
|
|
3848
|
+
import { dirname as dirname3 } from "path";
|
|
3849
|
+
import { mkdirSync as mkdirSync4, existsSync as existsSync3, unlinkSync } from "fs";
|
|
3694
3850
|
function isWindowsPipePath(p) {
|
|
3695
3851
|
return /^\\\\.\\pipe\\/i.test(p);
|
|
3696
3852
|
}
|
|
3697
3853
|
async function startSocketServer(socketPath) {
|
|
3698
3854
|
if (!isWindowsPipePath(socketPath)) {
|
|
3699
|
-
|
|
3700
|
-
if (
|
|
3855
|
+
mkdirSync4(dirname3(socketPath), { recursive: true });
|
|
3856
|
+
if (existsSync3(socketPath)) {
|
|
3701
3857
|
unlinkSync(socketPath);
|
|
3702
3858
|
}
|
|
3703
3859
|
}
|
|
@@ -3750,7 +3906,7 @@ async function startSocketServer(socketPath) {
|
|
|
3750
3906
|
server.close();
|
|
3751
3907
|
server.closeAllConnections?.();
|
|
3752
3908
|
if (!isWindowsPipePath(socketPath)) {
|
|
3753
|
-
if (
|
|
3909
|
+
if (existsSync3(socketPath)) {
|
|
3754
3910
|
try {
|
|
3755
3911
|
unlinkSync(socketPath);
|
|
3756
3912
|
} catch {
|
|
@@ -3814,7 +3970,7 @@ var skillDetailSchema = z3.object({
|
|
|
3814
3970
|
|
|
3815
3971
|
// src/backend/ilink/ilink-bridge.ts
|
|
3816
3972
|
import { readFile as readFile5, writeFile as writeFile2, mkdir, rm } from "fs/promises";
|
|
3817
|
-
import { join as
|
|
3973
|
+
import { join as join6 } from "path";
|
|
3818
3974
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3819
3975
|
|
|
3820
3976
|
// src/backend/ilink/ilink-crypto.ts
|
|
@@ -3990,10 +4146,10 @@ var ILinkClient = class {
|
|
|
3990
4146
|
};
|
|
3991
4147
|
|
|
3992
4148
|
// src/backend/ilink/ilink-bridge.ts
|
|
3993
|
-
var ILINK_DIR =
|
|
3994
|
-
var CREDENTIALS_PATH =
|
|
3995
|
-
var CURSOR_PATH =
|
|
3996
|
-
var ACTIVE_SESSION_PATH =
|
|
4149
|
+
var ILINK_DIR = join6(FELLO_DIR, "ilink");
|
|
4150
|
+
var CREDENTIALS_PATH = join6(ILINK_DIR, "credentials.json");
|
|
4151
|
+
var CURSOR_PATH = join6(ILINK_DIR, "cursor.json");
|
|
4152
|
+
var ACTIVE_SESSION_PATH = join6(ILINK_DIR, "active-session.json");
|
|
3997
4153
|
async function ensureDir() {
|
|
3998
4154
|
await mkdir(ILINK_DIR, { recursive: true });
|
|
3999
4155
|
}
|
|
@@ -4429,145 +4585,6 @@ var ILinkBridge = class _ILinkBridge {
|
|
|
4429
4585
|
}
|
|
4430
4586
|
};
|
|
4431
4587
|
|
|
4432
|
-
// src/backend/automation/store.ts
|
|
4433
|
-
import { join as join6, dirname as dirname3 } from "path";
|
|
4434
|
-
import { homedir as homedir2 } from "os";
|
|
4435
|
-
import {
|
|
4436
|
-
mkdirSync as mkdirSync4,
|
|
4437
|
-
writeFileSync as writeFileSync3,
|
|
4438
|
-
readFileSync as readFileSync3,
|
|
4439
|
-
readdirSync as readdirSync2,
|
|
4440
|
-
rmSync as rmSync3,
|
|
4441
|
-
existsSync as existsSync3,
|
|
4442
|
-
statSync as statSync2
|
|
4443
|
-
} from "fs";
|
|
4444
|
-
var AUTOMATIONS_DIR = join6(homedir2(), ".fello", "automations");
|
|
4445
|
-
mkdirSync4(AUTOMATIONS_DIR, { recursive: true });
|
|
4446
|
-
var store = {
|
|
4447
|
-
scheduleDir(scheduleId) {
|
|
4448
|
-
return join6(AUTOMATIONS_DIR, scheduleId);
|
|
4449
|
-
},
|
|
4450
|
-
scheduleConfigPath(scheduleId) {
|
|
4451
|
-
return join6(this.scheduleDir(scheduleId), "schedule.json");
|
|
4452
|
-
},
|
|
4453
|
-
tasksDir(scheduleId) {
|
|
4454
|
-
return join6(this.scheduleDir(scheduleId), "tasks");
|
|
4455
|
-
},
|
|
4456
|
-
taskDir(scheduleId, taskId) {
|
|
4457
|
-
return join6(this.tasksDir(scheduleId), taskId);
|
|
4458
|
-
},
|
|
4459
|
-
taskMetaPath(scheduleId, taskId) {
|
|
4460
|
-
return join6(this.taskDir(scheduleId, taskId), "task.json");
|
|
4461
|
-
},
|
|
4462
|
-
listSchedules() {
|
|
4463
|
-
if (!existsSync3(AUTOMATIONS_DIR)) return [];
|
|
4464
|
-
const dirs = readdirSync2(AUTOMATIONS_DIR);
|
|
4465
|
-
const list = [];
|
|
4466
|
-
for (const dir of dirs) {
|
|
4467
|
-
try {
|
|
4468
|
-
const raw = JSON.parse(readFileSync3(this.scheduleConfigPath(dir), "utf-8"));
|
|
4469
|
-
list.push(raw);
|
|
4470
|
-
} catch {
|
|
4471
|
-
}
|
|
4472
|
-
}
|
|
4473
|
-
list.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
4474
|
-
return list;
|
|
4475
|
-
},
|
|
4476
|
-
getSchedule(scheduleId) {
|
|
4477
|
-
try {
|
|
4478
|
-
return JSON.parse(readFileSync3(this.scheduleConfigPath(scheduleId), "utf-8"));
|
|
4479
|
-
} catch {
|
|
4480
|
-
return null;
|
|
4481
|
-
}
|
|
4482
|
-
},
|
|
4483
|
-
saveSchedule(schedule) {
|
|
4484
|
-
const dir = this.scheduleDir(schedule.id);
|
|
4485
|
-
mkdirSync4(dir, { recursive: true });
|
|
4486
|
-
mkdirSync4(this.tasksDir(schedule.id), { recursive: true });
|
|
4487
|
-
writeFileSync3(this.scheduleConfigPath(schedule.id), JSON.stringify(schedule, null, 2));
|
|
4488
|
-
},
|
|
4489
|
-
deleteSchedule(scheduleId) {
|
|
4490
|
-
const dir = this.scheduleDir(scheduleId);
|
|
4491
|
-
if (existsSync3(dir)) {
|
|
4492
|
-
rmSync3(dir, { recursive: true, force: true });
|
|
4493
|
-
}
|
|
4494
|
-
},
|
|
4495
|
-
listTasks(scheduleId) {
|
|
4496
|
-
const dir = this.tasksDir(scheduleId);
|
|
4497
|
-
if (!existsSync3(dir)) return [];
|
|
4498
|
-
const dirs = readdirSync2(dir);
|
|
4499
|
-
const list = [];
|
|
4500
|
-
for (const d of dirs) {
|
|
4501
|
-
try {
|
|
4502
|
-
const raw = JSON.parse(readFileSync3(this.taskMetaPath(scheduleId, d), "utf-8"));
|
|
4503
|
-
list.push(raw);
|
|
4504
|
-
} catch {
|
|
4505
|
-
}
|
|
4506
|
-
}
|
|
4507
|
-
list.sort((a, b) => b.startedAt - a.startedAt);
|
|
4508
|
-
return list;
|
|
4509
|
-
},
|
|
4510
|
-
getTask(scheduleId, taskId) {
|
|
4511
|
-
try {
|
|
4512
|
-
return JSON.parse(readFileSync3(this.taskMetaPath(scheduleId, taskId), "utf-8"));
|
|
4513
|
-
} catch {
|
|
4514
|
-
return null;
|
|
4515
|
-
}
|
|
4516
|
-
},
|
|
4517
|
-
saveTask(scheduleId, task) {
|
|
4518
|
-
const dir = this.taskDir(scheduleId, task.id);
|
|
4519
|
-
mkdirSync4(dir, { recursive: true });
|
|
4520
|
-
writeFileSync3(this.taskMetaPath(scheduleId, task.id), JSON.stringify(task, null, 2));
|
|
4521
|
-
},
|
|
4522
|
-
deleteTask(scheduleId, taskId) {
|
|
4523
|
-
const dir = this.taskDir(scheduleId, taskId);
|
|
4524
|
-
if (existsSync3(dir)) {
|
|
4525
|
-
rmSync3(dir, { recursive: true, force: true });
|
|
4526
|
-
}
|
|
4527
|
-
},
|
|
4528
|
-
listTaskFiles(scheduleId, taskId) {
|
|
4529
|
-
const dir = this.taskDir(scheduleId, taskId);
|
|
4530
|
-
if (!existsSync3(dir)) return [];
|
|
4531
|
-
const entries = readdirSync2(dir);
|
|
4532
|
-
return entries.filter((f) => f !== "task.json").map((f) => {
|
|
4533
|
-
const fullPath = join6(dir, f);
|
|
4534
|
-
const s = statSync2(fullPath);
|
|
4535
|
-
if (s.isDirectory()) {
|
|
4536
|
-
return this._listDirRecursive(fullPath, f);
|
|
4537
|
-
}
|
|
4538
|
-
return f;
|
|
4539
|
-
}).flat().sort();
|
|
4540
|
-
},
|
|
4541
|
-
_listDirRecursive(dir, prefix) {
|
|
4542
|
-
const result = [];
|
|
4543
|
-
const entries = readdirSync2(dir);
|
|
4544
|
-
for (const entry of entries) {
|
|
4545
|
-
const full = join6(dir, entry);
|
|
4546
|
-
const s = statSync2(full);
|
|
4547
|
-
if (s.isDirectory()) {
|
|
4548
|
-
result.push(...this._listDirRecursive(full, join6(prefix, entry)));
|
|
4549
|
-
} else {
|
|
4550
|
-
result.push(join6(prefix, entry));
|
|
4551
|
-
}
|
|
4552
|
-
}
|
|
4553
|
-
return result;
|
|
4554
|
-
},
|
|
4555
|
-
readTaskFile(scheduleId, taskId, filePath) {
|
|
4556
|
-
const base = this.taskDir(scheduleId, taskId);
|
|
4557
|
-
const fullPath = join6(base, filePath);
|
|
4558
|
-
if (!fullPath.startsWith(base + "/") && fullPath !== base) throw new Error("Invalid file path");
|
|
4559
|
-
if (!existsSync3(fullPath)) throw new Error("File not found");
|
|
4560
|
-
return readFileSync3(fullPath, "utf-8");
|
|
4561
|
-
},
|
|
4562
|
-
writeTaskFile(scheduleId, taskId, filePath, content) {
|
|
4563
|
-
const base = this.taskDir(scheduleId, taskId);
|
|
4564
|
-
const fullPath = join6(base, filePath);
|
|
4565
|
-
if (!fullPath.startsWith(base + "/") && fullPath !== base) throw new Error("Invalid file path");
|
|
4566
|
-
mkdirSync4(dirname3(fullPath), { recursive: true });
|
|
4567
|
-
writeFileSync3(fullPath, content);
|
|
4568
|
-
}
|
|
4569
|
-
};
|
|
4570
|
-
|
|
4571
4588
|
// src/backend/automation/scheduler.ts
|
|
4572
4589
|
import { CronJob } from "cron";
|
|
4573
4590
|
|
|
@@ -4828,7 +4845,11 @@ async function setupSkillsServer(taskDir) {
|
|
|
4828
4845
|
const socketPath = join8(TEMP_DIR, `auto-${randomUUID4()}.socket`);
|
|
4829
4846
|
const server = await startSocketServer(socketPath);
|
|
4830
4847
|
server.registry("skills/catalog", async () => {
|
|
4831
|
-
return getSkillsCatalog({ projectRoot: taskDir }).map(({ id, name, description }) => ({
|
|
4848
|
+
return getSkillsCatalog({ projectRoot: taskDir }).map(({ id, name, description }) => ({
|
|
4849
|
+
id,
|
|
4850
|
+
name,
|
|
4851
|
+
description
|
|
4852
|
+
}));
|
|
4832
4853
|
});
|
|
4833
4854
|
server.registry("skills/detail", async (payload) => {
|
|
4834
4855
|
const { id } = payload;
|
|
@@ -4849,9 +4870,18 @@ async function setupSkillsServer(taskDir) {
|
|
|
4849
4870
|
supportingFiles = listSkillFiles(skill.id, { projectRoot: taskDir });
|
|
4850
4871
|
} catch {
|
|
4851
4872
|
}
|
|
4852
|
-
return {
|
|
4873
|
+
return {
|
|
4874
|
+
id: skill.id,
|
|
4875
|
+
name: skill.name,
|
|
4876
|
+
description: skill.description,
|
|
4877
|
+
instructions: body,
|
|
4878
|
+
root_path: skillDir,
|
|
4879
|
+
supporting_files: supportingFiles
|
|
4880
|
+
};
|
|
4853
4881
|
});
|
|
4854
|
-
const catalogData = getSkillsCatalog({ projectRoot: taskDir }).map(
|
|
4882
|
+
const catalogData = getSkillsCatalog({ projectRoot: taskDir }).map(
|
|
4883
|
+
({ id, name, description }) => ({ id, name, description })
|
|
4884
|
+
);
|
|
4855
4885
|
const catalogFile = join8(TEMP_DIR, `auto-catalog-${randomUUID4()}.json`);
|
|
4856
4886
|
fs2.writeFileSync(catalogFile, JSON.stringify(catalogData), "utf8");
|
|
4857
4887
|
const mcpServer = {
|
|
@@ -4879,7 +4909,13 @@ async function executeTask(scheduleId) {
|
|
|
4879
4909
|
runningTasks.add(scheduleId);
|
|
4880
4910
|
const taskId = String(Date.now());
|
|
4881
4911
|
const startedAt = Date.now();
|
|
4882
|
-
const task = {
|
|
4912
|
+
const task = {
|
|
4913
|
+
id: taskId,
|
|
4914
|
+
scheduleId,
|
|
4915
|
+
startedAt,
|
|
4916
|
+
completedAt: null,
|
|
4917
|
+
status: "running"
|
|
4918
|
+
};
|
|
4883
4919
|
store.saveTask(scheduleId, task);
|
|
4884
4920
|
sendEvent?.("task-update", { scheduleId, task });
|
|
4885
4921
|
const notifications = [];
|
|
@@ -4893,7 +4929,10 @@ async function executeTask(scheduleId) {
|
|
|
4893
4929
|
...notification,
|
|
4894
4930
|
update: {
|
|
4895
4931
|
...notification.update,
|
|
4896
|
-
_meta: {
|
|
4932
|
+
_meta: {
|
|
4933
|
+
...notification.update?._meta,
|
|
4934
|
+
fello: { receivedAt: Date.now(), displayId: `auto-${notifications.length}` }
|
|
4935
|
+
}
|
|
4897
4936
|
}
|
|
4898
4937
|
});
|
|
4899
4938
|
},
|
|
@@ -4917,7 +4956,12 @@ async function executeTask(scheduleId) {
|
|
|
4917
4956
|
const promptContent = [{ type: "text", text: schedule.prompt }];
|
|
4918
4957
|
await bridge.sendPrompt({ sessionId, prompt: promptContent });
|
|
4919
4958
|
const messages = reduceNotificationsToMessages(notifications);
|
|
4920
|
-
store.writeTaskFile(
|
|
4959
|
+
store.writeTaskFile(
|
|
4960
|
+
scheduleId,
|
|
4961
|
+
taskId,
|
|
4962
|
+
"README.md",
|
|
4963
|
+
generateReadme(schedule, messages, startedAt)
|
|
4964
|
+
);
|
|
4921
4965
|
store.writeTaskFile(scheduleId, taskId, "conversation.json", JSON.stringify(messages, null, 2));
|
|
4922
4966
|
await bridge.kill();
|
|
4923
4967
|
skillsServer?.stop();
|
|
@@ -5002,7 +5046,8 @@ function reduceNotificationsToMessages(notifications) {
|
|
|
5002
5046
|
function generateReadme(schedule, messages, startedAt) {
|
|
5003
5047
|
const lines = [];
|
|
5004
5048
|
lines.push(`# ${schedule.name}`);
|
|
5005
|
-
|
|
5049
|
+
const locale = storageOps.getSettings().i18n?.language;
|
|
5050
|
+
lines.push(`> Run at ${new Date(startedAt).toLocaleString(locale)}`);
|
|
5006
5051
|
lines.push("");
|
|
5007
5052
|
for (const msg of messages) {
|
|
5008
5053
|
if (msg.role === "user" || msg.role === "assistant") {
|
|
@@ -5046,7 +5091,7 @@ function scheduleCron(schedule) {
|
|
|
5046
5091
|
cronJob.start();
|
|
5047
5092
|
const next = getNextRun(schedule);
|
|
5048
5093
|
console.log(
|
|
5049
|
-
`[Automation] Scheduled "${schedule.name}" (${schedule.cron.expr}) next: ${next ? new Date(next).toLocaleString() : "?"}`
|
|
5094
|
+
`[Automation] Scheduled "${schedule.name}" (${schedule.cron.expr}) next: ${next ? new Date(next).toLocaleString(storageOps.getSettings().i18n?.language) : "?"}`
|
|
5050
5095
|
);
|
|
5051
5096
|
} catch (err) {
|
|
5052
5097
|
console.error(`[Automation] Failed to schedule "${schedule.name}":`, err);
|
|
@@ -7465,8 +7510,8 @@ var backendHandlers = {
|
|
|
7465
7510
|
async getTaskFiles({ scheduleId, taskId }) {
|
|
7466
7511
|
return store.listTaskFiles(scheduleId, taskId);
|
|
7467
7512
|
},
|
|
7468
|
-
async readTaskFile({ scheduleId, taskId, filePath }) {
|
|
7469
|
-
return store.readTaskFile(scheduleId, taskId, filePath);
|
|
7513
|
+
async readTaskFile({ scheduleId, taskId, filePath, encoding }) {
|
|
7514
|
+
return store.readTaskFile(scheduleId, taskId, filePath, encoding);
|
|
7470
7515
|
},
|
|
7471
7516
|
async getTaskFileSystemPath({ scheduleId, taskId, filePath }) {
|
|
7472
7517
|
const base = store.taskDir(scheduleId, taskId);
|
|
@@ -7480,7 +7525,7 @@ var backendHandlers = {
|
|
|
7480
7525
|
};
|
|
7481
7526
|
|
|
7482
7527
|
// package.json
|
|
7483
|
-
var version = "0.1.
|
|
7528
|
+
var version = "0.1.32";
|
|
7484
7529
|
|
|
7485
7530
|
// src/server/main.ts
|
|
7486
7531
|
var port;
|