safeclaw 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +82 -79
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -8,15 +8,16 @@ var __export = (target, all) => {
|
|
|
8
8
|
import { Command } from "commander";
|
|
9
9
|
|
|
10
10
|
// src/lib/version.ts
|
|
11
|
-
var VERSION = "0.1.
|
|
11
|
+
var VERSION = "0.1.3";
|
|
12
12
|
|
|
13
13
|
// src/server/index.ts
|
|
14
14
|
import Fastify from "fastify";
|
|
15
15
|
import fastifyStatic from "@fastify/static";
|
|
16
16
|
import fastifyCors from "@fastify/cors";
|
|
17
|
-
import
|
|
17
|
+
import fs8 from "fs";
|
|
18
18
|
|
|
19
19
|
// src/lib/paths.ts
|
|
20
|
+
import fs from "fs";
|
|
20
21
|
import path from "path";
|
|
21
22
|
import os from "os";
|
|
22
23
|
var HOME = os.homedir();
|
|
@@ -33,7 +34,9 @@ var OPENCLAW_DEVICE_AUTH_JSON = path.join(OPENCLAW_IDENTITY_DIR, "device-auth.js
|
|
|
33
34
|
var OPENCLAW_EXEC_APPROVALS_PATH = path.join(OPENCLAW_DIR, "exec-approvals.json");
|
|
34
35
|
function getPublicDir() {
|
|
35
36
|
const currentDir = path.dirname(new URL(import.meta.url).pathname);
|
|
36
|
-
|
|
37
|
+
const bundledPath = path.resolve(currentDir, "..", "public");
|
|
38
|
+
const devPath = path.resolve(currentDir, "..", "..", "public");
|
|
39
|
+
return fs.existsSync(bundledPath) ? bundledPath : devPath;
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
// src/server/socket.ts
|
|
@@ -44,7 +47,7 @@ import Database from "better-sqlite3";
|
|
|
44
47
|
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
45
48
|
|
|
46
49
|
// src/lib/config.ts
|
|
47
|
-
import
|
|
50
|
+
import fs2 from "fs";
|
|
48
51
|
|
|
49
52
|
// ../../packages/shared/dist/schemas.js
|
|
50
53
|
import { z } from "zod";
|
|
@@ -279,25 +282,25 @@ var DEFAULT_CONFIG = {
|
|
|
279
282
|
userId: null
|
|
280
283
|
};
|
|
281
284
|
function ensureDataDir() {
|
|
282
|
-
if (!
|
|
283
|
-
|
|
285
|
+
if (!fs2.existsSync(SAFECLAW_DIR)) {
|
|
286
|
+
fs2.mkdirSync(SAFECLAW_DIR, { recursive: true });
|
|
284
287
|
}
|
|
285
|
-
if (!
|
|
286
|
-
|
|
288
|
+
if (!fs2.existsSync(LOGS_DIR)) {
|
|
289
|
+
fs2.mkdirSync(LOGS_DIR, { recursive: true });
|
|
287
290
|
}
|
|
288
291
|
}
|
|
289
292
|
function readConfig() {
|
|
290
293
|
ensureDataDir();
|
|
291
|
-
if (!
|
|
292
|
-
|
|
294
|
+
if (!fs2.existsSync(CONFIG_PATH)) {
|
|
295
|
+
fs2.writeFileSync(CONFIG_PATH, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
293
296
|
return DEFAULT_CONFIG;
|
|
294
297
|
}
|
|
295
|
-
const raw = JSON.parse(
|
|
298
|
+
const raw = JSON.parse(fs2.readFileSync(CONFIG_PATH, "utf-8"));
|
|
296
299
|
return safeClawConfigSchema.parse(raw);
|
|
297
300
|
}
|
|
298
301
|
function writeConfig(config) {
|
|
299
302
|
ensureDataDir();
|
|
300
|
-
|
|
303
|
+
fs2.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
301
304
|
}
|
|
302
305
|
function resetConfig() {
|
|
303
306
|
writeConfig(DEFAULT_CONFIG);
|
|
@@ -423,9 +426,9 @@ import { eq as eq4, desc as desc3 } from "drizzle-orm";
|
|
|
423
426
|
|
|
424
427
|
// src/lib/logger.ts
|
|
425
428
|
import pino from "pino";
|
|
426
|
-
import
|
|
427
|
-
if (!
|
|
428
|
-
|
|
429
|
+
import fs3 from "fs";
|
|
430
|
+
if (!fs3.existsSync(LOGS_DIR)) {
|
|
431
|
+
fs3.mkdirSync(LOGS_DIR, { recursive: true });
|
|
429
432
|
}
|
|
430
433
|
function createLogger(consoleLevel = "info") {
|
|
431
434
|
return pino({
|
|
@@ -454,19 +457,19 @@ function setVerbose(verbose) {
|
|
|
454
457
|
}
|
|
455
458
|
|
|
456
459
|
// src/lib/openclaw-config.ts
|
|
457
|
-
import
|
|
460
|
+
import fs4 from "fs";
|
|
458
461
|
function readOpenClawConfig() {
|
|
459
|
-
if (!
|
|
462
|
+
if (!fs4.existsSync(OPENCLAW_CONFIG_PATH)) {
|
|
460
463
|
return null;
|
|
461
464
|
}
|
|
462
|
-
const raw = JSON.parse(
|
|
465
|
+
const raw = JSON.parse(fs4.readFileSync(OPENCLAW_CONFIG_PATH, "utf-8"));
|
|
463
466
|
return openClawConfigSchema.parse(raw);
|
|
464
467
|
}
|
|
465
468
|
function writeOpenClawConfig(updates) {
|
|
466
469
|
const current = readOpenClawConfig();
|
|
467
470
|
if (!current) return null;
|
|
468
471
|
const merged = deepMerge(current, updates);
|
|
469
|
-
|
|
472
|
+
fs4.writeFileSync(OPENCLAW_CONFIG_PATH, JSON.stringify(merged, null, 2));
|
|
470
473
|
return merged;
|
|
471
474
|
}
|
|
472
475
|
function deepMerge(target, source) {
|
|
@@ -486,11 +489,11 @@ function deepMerge(target, source) {
|
|
|
486
489
|
// src/lib/openclaw-client.ts
|
|
487
490
|
import { EventEmitter } from "events";
|
|
488
491
|
import crypto from "crypto";
|
|
489
|
-
import
|
|
492
|
+
import fs5 from "fs";
|
|
490
493
|
import { WebSocket } from "ws";
|
|
491
494
|
function readDeviceIdentity() {
|
|
492
495
|
try {
|
|
493
|
-
const raw =
|
|
496
|
+
const raw = fs5.readFileSync(OPENCLAW_DEVICE_JSON, "utf-8");
|
|
494
497
|
const data = JSON.parse(raw);
|
|
495
498
|
if (!data.deviceId || !data.publicKeyPem || !data.privateKeyPem) return null;
|
|
496
499
|
return {
|
|
@@ -1008,7 +1011,7 @@ var OpenClawClient = class extends EventEmitter {
|
|
|
1008
1011
|
|
|
1009
1012
|
// src/services/session-watcher.ts
|
|
1010
1013
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
1011
|
-
import
|
|
1014
|
+
import fs6 from "fs";
|
|
1012
1015
|
import path2 from "path";
|
|
1013
1016
|
var MAX_CONTENT_PREVIEW = 10 * 1024;
|
|
1014
1017
|
var SessionWatcher = class extends EventEmitter2 {
|
|
@@ -1027,7 +1030,7 @@ var SessionWatcher = class extends EventEmitter2 {
|
|
|
1027
1030
|
start() {
|
|
1028
1031
|
if (this.destroyed) return;
|
|
1029
1032
|
const agentsDir = path2.join(OPENCLAW_DIR, "agents");
|
|
1030
|
-
if (!
|
|
1033
|
+
if (!fs6.existsSync(agentsDir)) {
|
|
1031
1034
|
logger.debug("OpenClaw agents directory not found, will retry");
|
|
1032
1035
|
}
|
|
1033
1036
|
this.scanForSessions();
|
|
@@ -1035,8 +1038,8 @@ var SessionWatcher = class extends EventEmitter2 {
|
|
|
1035
1038
|
if (!this.destroyed) this.scanForSessions();
|
|
1036
1039
|
}, 1e4);
|
|
1037
1040
|
try {
|
|
1038
|
-
if (
|
|
1039
|
-
this.agentsDirWatcher =
|
|
1041
|
+
if (fs6.existsSync(agentsDir)) {
|
|
1042
|
+
this.agentsDirWatcher = fs6.watch(agentsDir, { recursive: true }, () => {
|
|
1040
1043
|
if (!this.destroyed) this.scanForSessions();
|
|
1041
1044
|
});
|
|
1042
1045
|
}
|
|
@@ -1064,10 +1067,10 @@ var SessionWatcher = class extends EventEmitter2 {
|
|
|
1064
1067
|
}
|
|
1065
1068
|
scanForSessions() {
|
|
1066
1069
|
const agentsDir = path2.join(OPENCLAW_DIR, "agents");
|
|
1067
|
-
if (!
|
|
1070
|
+
if (!fs6.existsSync(agentsDir)) return;
|
|
1068
1071
|
try {
|
|
1069
|
-
const agentNames =
|
|
1070
|
-
const stat =
|
|
1072
|
+
const agentNames = fs6.readdirSync(agentsDir).filter((name) => {
|
|
1073
|
+
const stat = fs6.statSync(path2.join(agentsDir, name));
|
|
1071
1074
|
return stat.isDirectory();
|
|
1072
1075
|
});
|
|
1073
1076
|
for (const agentName of agentNames) {
|
|
@@ -1079,11 +1082,11 @@ var SessionWatcher = class extends EventEmitter2 {
|
|
|
1079
1082
|
}
|
|
1080
1083
|
discoverSessionFiles(agentName) {
|
|
1081
1084
|
const sessionsDir = path2.join(OPENCLAW_DIR, "agents", agentName, "sessions");
|
|
1082
|
-
if (!
|
|
1085
|
+
if (!fs6.existsSync(sessionsDir)) return;
|
|
1083
1086
|
const sessionsJsonPath = path2.join(sessionsDir, "sessions.json");
|
|
1084
|
-
if (
|
|
1087
|
+
if (fs6.existsSync(sessionsJsonPath)) {
|
|
1085
1088
|
try {
|
|
1086
|
-
const raw =
|
|
1089
|
+
const raw = fs6.readFileSync(sessionsJsonPath, "utf-8");
|
|
1087
1090
|
const sessionsData = JSON.parse(raw);
|
|
1088
1091
|
const sessions2 = sessionsData.sessions ?? [];
|
|
1089
1092
|
for (const session of sessions2) {
|
|
@@ -1095,7 +1098,7 @@ var SessionWatcher = class extends EventEmitter2 {
|
|
|
1095
1098
|
}
|
|
1096
1099
|
}
|
|
1097
1100
|
try {
|
|
1098
|
-
const files =
|
|
1101
|
+
const files = fs6.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl"));
|
|
1099
1102
|
for (const file of files) {
|
|
1100
1103
|
const filePath = path2.join(sessionsDir, file);
|
|
1101
1104
|
const sessionId = path2.basename(file, ".jsonl");
|
|
@@ -1106,8 +1109,8 @@ var SessionWatcher = class extends EventEmitter2 {
|
|
|
1106
1109
|
}
|
|
1107
1110
|
watchSessionFile(filePath, sessionId, agentName) {
|
|
1108
1111
|
if (this.watchedFiles.has(filePath)) return;
|
|
1109
|
-
if (!
|
|
1110
|
-
const stat =
|
|
1112
|
+
if (!fs6.existsSync(filePath)) return;
|
|
1113
|
+
const stat = fs6.statSync(filePath);
|
|
1111
1114
|
const watched = {
|
|
1112
1115
|
path: filePath,
|
|
1113
1116
|
position: stat.size,
|
|
@@ -1117,7 +1120,7 @@ var SessionWatcher = class extends EventEmitter2 {
|
|
|
1117
1120
|
agentName
|
|
1118
1121
|
};
|
|
1119
1122
|
try {
|
|
1120
|
-
watched.watcher =
|
|
1123
|
+
watched.watcher = fs6.watch(filePath, () => {
|
|
1121
1124
|
if (!this.destroyed) {
|
|
1122
1125
|
this.readNewEntries(watched);
|
|
1123
1126
|
}
|
|
@@ -1131,13 +1134,13 @@ var SessionWatcher = class extends EventEmitter2 {
|
|
|
1131
1134
|
}
|
|
1132
1135
|
readNewEntries(watched) {
|
|
1133
1136
|
try {
|
|
1134
|
-
const stat =
|
|
1137
|
+
const stat = fs6.statSync(watched.path);
|
|
1135
1138
|
if (stat.size <= watched.position) return;
|
|
1136
|
-
const fd =
|
|
1139
|
+
const fd = fs6.openSync(watched.path, "r");
|
|
1137
1140
|
const bufferSize = stat.size - watched.position;
|
|
1138
1141
|
const buffer = Buffer.alloc(bufferSize);
|
|
1139
|
-
|
|
1140
|
-
|
|
1142
|
+
fs6.readSync(fd, buffer, 0, bufferSize, watched.position);
|
|
1143
|
+
fs6.closeSync(fd);
|
|
1141
1144
|
watched.position = stat.size;
|
|
1142
1145
|
const text2 = buffer.toString("utf-8");
|
|
1143
1146
|
const lines = text2.split("\n").filter((l) => l.trim());
|
|
@@ -1691,11 +1694,11 @@ function createExecApprovalService(client, io2, timeoutMs) {
|
|
|
1691
1694
|
}
|
|
1692
1695
|
|
|
1693
1696
|
// src/lib/exec-approvals-config.ts
|
|
1694
|
-
import
|
|
1697
|
+
import fs7 from "fs";
|
|
1695
1698
|
function readExecApprovalsConfig() {
|
|
1696
1699
|
try {
|
|
1697
|
-
if (!
|
|
1698
|
-
const raw =
|
|
1700
|
+
if (!fs7.existsSync(OPENCLAW_EXEC_APPROVALS_PATH)) return null;
|
|
1701
|
+
const raw = fs7.readFileSync(OPENCLAW_EXEC_APPROVALS_PATH, "utf-8");
|
|
1699
1702
|
return JSON.parse(raw);
|
|
1700
1703
|
} catch (err) {
|
|
1701
1704
|
logger.warn({ err }, "Failed to read exec-approvals.json");
|
|
@@ -1703,7 +1706,7 @@ function readExecApprovalsConfig() {
|
|
|
1703
1706
|
}
|
|
1704
1707
|
}
|
|
1705
1708
|
function writeExecApprovalsConfig(config) {
|
|
1706
|
-
|
|
1709
|
+
fs7.writeFileSync(
|
|
1707
1710
|
OPENCLAW_EXEC_APPROVALS_PATH,
|
|
1708
1711
|
JSON.stringify(config, null, 2)
|
|
1709
1712
|
);
|
|
@@ -3423,7 +3426,7 @@ async function createAppServer(port) {
|
|
|
3423
3426
|
await app.register(fastifyCors, { origin: "*" });
|
|
3424
3427
|
await registerRoutes(app);
|
|
3425
3428
|
const publicDir = getPublicDir();
|
|
3426
|
-
if (
|
|
3429
|
+
if (fs8.existsSync(publicDir) && fs8.readdirSync(publicDir).filter((f) => f !== ".gitkeep").length > 0) {
|
|
3427
3430
|
await app.register(fastifyStatic, {
|
|
3428
3431
|
root: publicDir,
|
|
3429
3432
|
prefix: "/",
|
|
@@ -3685,7 +3688,7 @@ Permission denied for port ${port}.
|
|
|
3685
3688
|
}
|
|
3686
3689
|
|
|
3687
3690
|
// src/commands/reset.ts
|
|
3688
|
-
import
|
|
3691
|
+
import fs9 from "fs";
|
|
3689
3692
|
import readline from "readline/promises";
|
|
3690
3693
|
import pc3 from "picocolors";
|
|
3691
3694
|
async function resetCommand(options) {
|
|
@@ -3704,12 +3707,12 @@ async function resetCommand(options) {
|
|
|
3704
3707
|
}
|
|
3705
3708
|
}
|
|
3706
3709
|
console.log(pc3.bold("Resetting SafeClaw..."));
|
|
3707
|
-
if (
|
|
3708
|
-
|
|
3710
|
+
if (fs9.existsSync(DB_PATH)) {
|
|
3711
|
+
fs9.unlinkSync(DB_PATH);
|
|
3709
3712
|
const walPath = DB_PATH + "-wal";
|
|
3710
3713
|
const shmPath = DB_PATH + "-shm";
|
|
3711
|
-
if (
|
|
3712
|
-
if (
|
|
3714
|
+
if (fs9.existsSync(walPath)) fs9.unlinkSync(walPath);
|
|
3715
|
+
if (fs9.existsSync(shmPath)) fs9.unlinkSync(shmPath);
|
|
3713
3716
|
console.log(pc3.green(" Database deleted."));
|
|
3714
3717
|
} else {
|
|
3715
3718
|
console.log(pc3.dim(" No database found, skipping."));
|
|
@@ -3722,11 +3725,11 @@ async function resetCommand(options) {
|
|
|
3722
3725
|
}
|
|
3723
3726
|
|
|
3724
3727
|
// src/commands/status.ts
|
|
3725
|
-
import
|
|
3728
|
+
import fs10 from "fs";
|
|
3726
3729
|
import Database3 from "better-sqlite3";
|
|
3727
3730
|
import pc4 from "picocolors";
|
|
3728
3731
|
async function statusCommand(options) {
|
|
3729
|
-
const exists =
|
|
3732
|
+
const exists = fs10.existsSync(SAFECLAW_DIR);
|
|
3730
3733
|
if (!exists) {
|
|
3731
3734
|
if (options.json) {
|
|
3732
3735
|
console.log(JSON.stringify({ initialized: false }, null, 2));
|
|
@@ -3740,7 +3743,7 @@ async function statusCommand(options) {
|
|
|
3740
3743
|
const config = readConfig();
|
|
3741
3744
|
let logCount = 0;
|
|
3742
3745
|
let activityCount = 0;
|
|
3743
|
-
const dbExists =
|
|
3746
|
+
const dbExists = fs10.existsSync(DB_PATH);
|
|
3744
3747
|
if (dbExists) {
|
|
3745
3748
|
try {
|
|
3746
3749
|
const sqlite = new Database3(DB_PATH, { readonly: true });
|
|
@@ -3754,14 +3757,14 @@ async function statusCommand(options) {
|
|
|
3754
3757
|
activityCount = -1;
|
|
3755
3758
|
}
|
|
3756
3759
|
}
|
|
3757
|
-
const openclawConfigExists =
|
|
3760
|
+
const openclawConfigExists = fs10.existsSync(OPENCLAW_CONFIG_PATH);
|
|
3758
3761
|
if (options.json) {
|
|
3759
3762
|
const data = {
|
|
3760
3763
|
version: VERSION,
|
|
3761
3764
|
initialized: true,
|
|
3762
3765
|
dataDir: SAFECLAW_DIR,
|
|
3763
3766
|
database: dbExists ? "exists" : "not_found",
|
|
3764
|
-
config:
|
|
3767
|
+
config: fs10.existsSync(CONFIG_PATH) ? "exists" : "not_found",
|
|
3765
3768
|
port: config.port,
|
|
3766
3769
|
autoOpenBrowser: config.autoOpenBrowser,
|
|
3767
3770
|
premium: config.premium,
|
|
@@ -3779,7 +3782,7 @@ async function statusCommand(options) {
|
|
|
3779
3782
|
` ${pc4.dim("Database:")} ${dbExists ? pc4.green("exists") : pc4.red("not found")}`
|
|
3780
3783
|
);
|
|
3781
3784
|
console.log(
|
|
3782
|
-
` ${pc4.dim("Config:")} ${
|
|
3785
|
+
` ${pc4.dim("Config:")} ${fs10.existsSync(CONFIG_PATH) ? pc4.green("exists") : pc4.red("not found")}`
|
|
3783
3786
|
);
|
|
3784
3787
|
console.log(` ${pc4.dim("Port:")} ${config.port}`);
|
|
3785
3788
|
console.log(` ${pc4.dim("Auto-open:")} ${config.autoOpenBrowser ? "Yes" : "No"}`);
|
|
@@ -3797,7 +3800,7 @@ async function statusCommand(options) {
|
|
|
3797
3800
|
}
|
|
3798
3801
|
|
|
3799
3802
|
// src/commands/doctor.ts
|
|
3800
|
-
import
|
|
3803
|
+
import fs11 from "fs";
|
|
3801
3804
|
import net from "net";
|
|
3802
3805
|
import Database4 from "better-sqlite3";
|
|
3803
3806
|
import pc5 from "picocolors";
|
|
@@ -3819,7 +3822,7 @@ function checkNodeVersion() {
|
|
|
3819
3822
|
function checkDataDir() {
|
|
3820
3823
|
try {
|
|
3821
3824
|
ensureDataDir();
|
|
3822
|
-
|
|
3825
|
+
fs11.accessSync(SAFECLAW_DIR, fs11.constants.W_OK);
|
|
3823
3826
|
return {
|
|
3824
3827
|
name: "Data directory writable",
|
|
3825
3828
|
status: "pass",
|
|
@@ -3834,7 +3837,7 @@ function checkDataDir() {
|
|
|
3834
3837
|
}
|
|
3835
3838
|
}
|
|
3836
3839
|
function checkDatabase() {
|
|
3837
|
-
if (!
|
|
3840
|
+
if (!fs11.existsSync(DB_PATH)) {
|
|
3838
3841
|
return {
|
|
3839
3842
|
name: "Database",
|
|
3840
3843
|
status: "warn",
|
|
@@ -3877,7 +3880,7 @@ function checkDatabase() {
|
|
|
3877
3880
|
}
|
|
3878
3881
|
}
|
|
3879
3882
|
function checkConfig() {
|
|
3880
|
-
if (!
|
|
3883
|
+
if (!fs11.existsSync(CONFIG_PATH)) {
|
|
3881
3884
|
return {
|
|
3882
3885
|
name: "Config file",
|
|
3883
3886
|
status: "warn",
|
|
@@ -3919,14 +3922,14 @@ async function checkPort() {
|
|
|
3919
3922
|
};
|
|
3920
3923
|
}
|
|
3921
3924
|
function checkOpenClawConfig() {
|
|
3922
|
-
if (!
|
|
3925
|
+
if (!fs11.existsSync(OPENCLAW_DIR)) {
|
|
3923
3926
|
return {
|
|
3924
3927
|
name: "OpenClaw directory",
|
|
3925
3928
|
status: "warn",
|
|
3926
3929
|
message: `${OPENCLAW_DIR} not found`
|
|
3927
3930
|
};
|
|
3928
3931
|
}
|
|
3929
|
-
if (!
|
|
3932
|
+
if (!fs11.existsSync(OPENCLAW_CONFIG_PATH)) {
|
|
3930
3933
|
return {
|
|
3931
3934
|
name: "OpenClaw config",
|
|
3932
3935
|
status: "warn",
|
|
@@ -3958,7 +3961,7 @@ function isPortInUse(port) {
|
|
|
3958
3961
|
});
|
|
3959
3962
|
}
|
|
3960
3963
|
async function checkOpenClawGateway() {
|
|
3961
|
-
if (!
|
|
3964
|
+
if (!fs11.existsSync(OPENCLAW_CONFIG_PATH)) {
|
|
3962
3965
|
return {
|
|
3963
3966
|
name: "OpenClaw gateway",
|
|
3964
3967
|
status: "warn",
|
|
@@ -3966,7 +3969,7 @@ async function checkOpenClawGateway() {
|
|
|
3966
3969
|
};
|
|
3967
3970
|
}
|
|
3968
3971
|
try {
|
|
3969
|
-
const raw = JSON.parse(
|
|
3972
|
+
const raw = JSON.parse(fs11.readFileSync(OPENCLAW_CONFIG_PATH, "utf-8"));
|
|
3970
3973
|
const port = raw?.gateway?.port ?? 18789;
|
|
3971
3974
|
const reachable = await isPortInUse(port);
|
|
3972
3975
|
if (reachable) {
|
|
@@ -3991,10 +3994,10 @@ async function checkOpenClawGateway() {
|
|
|
3991
3994
|
}
|
|
3992
3995
|
function checkLogDir() {
|
|
3993
3996
|
try {
|
|
3994
|
-
if (!
|
|
3995
|
-
|
|
3997
|
+
if (!fs11.existsSync(LOGS_DIR)) {
|
|
3998
|
+
fs11.mkdirSync(LOGS_DIR, { recursive: true });
|
|
3996
3999
|
}
|
|
3997
|
-
|
|
4000
|
+
fs11.accessSync(LOGS_DIR, fs11.constants.W_OK);
|
|
3998
4001
|
return {
|
|
3999
4002
|
name: "Log directory writable",
|
|
4000
4003
|
status: "pass",
|
|
@@ -4136,14 +4139,14 @@ async function configSetCommand(key, value) {
|
|
|
4136
4139
|
}
|
|
4137
4140
|
|
|
4138
4141
|
// src/commands/logs.ts
|
|
4139
|
-
import
|
|
4142
|
+
import fs12 from "fs";
|
|
4140
4143
|
import pc7 from "picocolors";
|
|
4141
4144
|
async function logsCommand(options) {
|
|
4142
4145
|
if (options.clear) {
|
|
4143
4146
|
await clearLogs();
|
|
4144
4147
|
return;
|
|
4145
4148
|
}
|
|
4146
|
-
if (!
|
|
4149
|
+
if (!fs12.existsSync(DEBUG_LOG_PATH)) {
|
|
4147
4150
|
console.log(
|
|
4148
4151
|
pc7.yellow("No log file found.") + " Run " + pc7.cyan("safeclaw start") + " to generate logs."
|
|
4149
4152
|
);
|
|
@@ -4156,7 +4159,7 @@ async function logsCommand(options) {
|
|
|
4156
4159
|
}
|
|
4157
4160
|
}
|
|
4158
4161
|
async function tailLogs(lineCount) {
|
|
4159
|
-
const content =
|
|
4162
|
+
const content = fs12.readFileSync(DEBUG_LOG_PATH, "utf-8");
|
|
4160
4163
|
const lines = content.split("\n").filter(Boolean);
|
|
4161
4164
|
const tail = lines.slice(-lineCount);
|
|
4162
4165
|
if (tail.length === 0) {
|
|
@@ -4174,23 +4177,23 @@ async function tailLogs(lineCount) {
|
|
|
4174
4177
|
async function followLogs() {
|
|
4175
4178
|
console.log(pc7.dim(`Following ${DEBUG_LOG_PATH} (Ctrl+C to stop)
|
|
4176
4179
|
`));
|
|
4177
|
-
if (
|
|
4178
|
-
const content =
|
|
4180
|
+
if (fs12.existsSync(DEBUG_LOG_PATH)) {
|
|
4181
|
+
const content = fs12.readFileSync(DEBUG_LOG_PATH, "utf-8");
|
|
4179
4182
|
const lines = content.split("\n").filter(Boolean);
|
|
4180
4183
|
const tail = lines.slice(-20);
|
|
4181
4184
|
for (const line of tail) {
|
|
4182
4185
|
process.stdout.write(line + "\n");
|
|
4183
4186
|
}
|
|
4184
4187
|
}
|
|
4185
|
-
let position =
|
|
4186
|
-
const watcher =
|
|
4188
|
+
let position = fs12.existsSync(DEBUG_LOG_PATH) ? fs12.statSync(DEBUG_LOG_PATH).size : 0;
|
|
4189
|
+
const watcher = fs12.watch(DEBUG_LOG_PATH, () => {
|
|
4187
4190
|
try {
|
|
4188
|
-
const stat =
|
|
4191
|
+
const stat = fs12.statSync(DEBUG_LOG_PATH);
|
|
4189
4192
|
if (stat.size > position) {
|
|
4190
|
-
const fd =
|
|
4193
|
+
const fd = fs12.openSync(DEBUG_LOG_PATH, "r");
|
|
4191
4194
|
const buffer = Buffer.alloc(stat.size - position);
|
|
4192
|
-
|
|
4193
|
-
|
|
4195
|
+
fs12.readSync(fd, buffer, 0, buffer.length, position);
|
|
4196
|
+
fs12.closeSync(fd);
|
|
4194
4197
|
process.stdout.write(buffer.toString("utf-8"));
|
|
4195
4198
|
position = stat.size;
|
|
4196
4199
|
} else if (stat.size < position) {
|
|
@@ -4208,11 +4211,11 @@ async function followLogs() {
|
|
|
4208
4211
|
});
|
|
4209
4212
|
}
|
|
4210
4213
|
async function clearLogs() {
|
|
4211
|
-
if (!
|
|
4214
|
+
if (!fs12.existsSync(DEBUG_LOG_PATH)) {
|
|
4212
4215
|
console.log(pc7.dim("No log file to clear."));
|
|
4213
4216
|
return;
|
|
4214
4217
|
}
|
|
4215
|
-
|
|
4218
|
+
fs12.writeFileSync(DEBUG_LOG_PATH, "");
|
|
4216
4219
|
console.log(pc7.green("Log file cleared."));
|
|
4217
4220
|
}
|
|
4218
4221
|
|
package/package.json
CHANGED