@chrysb/alphaclaw 0.4.3 → 0.4.5
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/lib/public/js/components/file-tree.js +37 -8
- package/lib/public/js/components/gateway.js +74 -42
- package/lib/public/js/components/icons.js +13 -0
- package/lib/public/js/components/usage-tab/overview-section.js +100 -26
- package/lib/public/js/lib/api.js +31 -0
- package/lib/server/constants.js +22 -26
- package/lib/server/db/usage/index.js +35 -0
- package/lib/server/db/usage/pricing.js +82 -0
- package/lib/server/db/usage/schema.js +87 -0
- package/lib/server/db/usage/sessions.js +217 -0
- package/lib/server/db/usage/shared.js +139 -0
- package/lib/server/db/usage/summary.js +280 -0
- package/lib/server/db/usage/timeseries.js +64 -0
- package/lib/server/{watchdog-db.js → db/watchdog/index.js} +1 -18
- package/lib/server/db/watchdog/schema.js +21 -0
- package/lib/server/{webhooks-db.js → db/webhooks/index.js} +1 -22
- package/lib/server/db/webhooks/schema.js +25 -0
- package/lib/server/gmail-push.js +102 -6
- package/lib/server/gmail-watch.js +5 -20
- package/lib/server/helpers.js +5 -21
- package/lib/server/routes/browse/index.js +29 -0
- package/lib/server/routes/google.js +2 -10
- package/lib/server/routes/telegram.js +3 -14
- package/lib/server/routes/usage.js +1 -5
- package/lib/server/routes/webhooks.js +2 -6
- package/lib/server/utils/boolean.js +22 -0
- package/lib/server/utils/json.js +31 -0
- package/lib/server/utils/network.js +5 -0
- package/lib/server/utils/number.js +8 -0
- package/lib/server/utils/shell.js +16 -0
- package/lib/server/webhook-middleware.js +1 -2
- package/lib/server.js +3 -3
- package/package.json +1 -1
- package/lib/server/usage-db.js +0 -838
|
@@ -156,6 +156,35 @@ const registerBrowseRoutes = ({ app, fs, kRootDir }) => {
|
|
|
156
156
|
}
|
|
157
157
|
});
|
|
158
158
|
|
|
159
|
+
app.get("/api/browse/download", (req, res) => {
|
|
160
|
+
const resolvedPath = resolveSafePath(
|
|
161
|
+
req.query.path,
|
|
162
|
+
kRootResolved,
|
|
163
|
+
kRootWithSep,
|
|
164
|
+
kRootDisplayName,
|
|
165
|
+
);
|
|
166
|
+
if (!resolvedPath.ok) {
|
|
167
|
+
return res.status(400).json({ ok: false, error: resolvedPath.error });
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
const stats = fs.statSync(resolvedPath.absolutePath);
|
|
171
|
+
if (!stats.isFile()) {
|
|
172
|
+
return res.status(400).json({ ok: false, error: "Path is not a file" });
|
|
173
|
+
}
|
|
174
|
+
const fileName = path.basename(resolvedPath.relativePath || resolvedPath.absolutePath);
|
|
175
|
+
return res.download(resolvedPath.absolutePath, fileName, (error) => {
|
|
176
|
+
if (!error || res.headersSent) return;
|
|
177
|
+
return res
|
|
178
|
+
.status(500)
|
|
179
|
+
.json({ ok: false, error: error.message || "Could not download file" });
|
|
180
|
+
});
|
|
181
|
+
} catch (error) {
|
|
182
|
+
return res
|
|
183
|
+
.status(500)
|
|
184
|
+
.json({ ok: false, error: error.message || "Could not download file" });
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
|
|
159
188
|
app.get("/api/browse/git-summary", async (req, res) => {
|
|
160
189
|
try {
|
|
161
190
|
const envRepoSlug = parseGithubRepoSlug(
|
|
@@ -12,16 +12,8 @@ const {
|
|
|
12
12
|
} = require("../google-state");
|
|
13
13
|
const { syncBootstrapPromptFiles } = require("../onboarding/workspace");
|
|
14
14
|
const { installGogCliSkill } = require("../gog-skill");
|
|
15
|
-
|
|
16
|
-
const quoteShellArg = (
|
|
17
|
-
|
|
18
|
-
const parseJsonSafe = (raw, fallbackValue) => {
|
|
19
|
-
try {
|
|
20
|
-
return JSON.parse(String(raw || ""));
|
|
21
|
-
} catch {
|
|
22
|
-
return fallbackValue;
|
|
23
|
-
}
|
|
24
|
-
};
|
|
15
|
+
const { parseJsonSafe } = require("../utils/json");
|
|
16
|
+
const { quoteShellArg } = require("../utils/shell");
|
|
25
17
|
|
|
26
18
|
const uniqueServiceLabels = (scopes) =>
|
|
27
19
|
Array.from(
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
const { OPENCLAW_DIR } = require("../constants");
|
|
3
3
|
const { isDebugEnabled } = require("../helpers");
|
|
4
|
+
const { parseBooleanValue } = require("../utils/boolean");
|
|
5
|
+
const { quoteShellArg } = require("../utils/shell");
|
|
4
6
|
const topicRegistry = require("../topic-registry");
|
|
5
7
|
const { syncConfigForTelegram } = require("../telegram-workspace");
|
|
6
|
-
|
|
7
|
-
const parseBooleanValue = (value, fallbackValue = false) => {
|
|
8
|
-
if (typeof value === "boolean") return value;
|
|
9
|
-
if (typeof value === "number") return value !== 0;
|
|
10
|
-
if (typeof value === "string") {
|
|
11
|
-
const normalized = value.trim().toLowerCase();
|
|
12
|
-
if (["true", "1", "yes", "on"].includes(normalized)) return true;
|
|
13
|
-
if (["false", "0", "no", "off", ""].includes(normalized)) return false;
|
|
14
|
-
}
|
|
15
|
-
return fallbackValue;
|
|
16
|
-
};
|
|
17
8
|
const resolveGroupId = (req) => {
|
|
18
9
|
const body = req.body || {};
|
|
19
10
|
const rawGroupId = body.groupId ?? body.chatId;
|
|
@@ -53,13 +44,11 @@ const normalizeGitSyncMessagePart = (value) =>
|
|
|
53
44
|
.replace(/\s+/g, " ")
|
|
54
45
|
.trim();
|
|
55
46
|
|
|
56
|
-
const quoteShellArg = (value) => `'${String(value || "").replace(/'/g, `'\"'\"'`)}'`;
|
|
57
|
-
|
|
58
47
|
const buildTelegramGitSyncCommand = (action, target = "") => {
|
|
59
48
|
const safeAction = normalizeGitSyncMessagePart(action);
|
|
60
49
|
const safeTarget = normalizeGitSyncMessagePart(target);
|
|
61
50
|
const message = `telegram workspace: ${safeAction} ${safeTarget}`.trim();
|
|
62
|
-
return `alphaclaw git-sync -m ${quoteShellArg(message)}`;
|
|
51
|
+
return `alphaclaw git-sync -m ${quoteShellArg(message, { strategy: "single" })}`;
|
|
63
52
|
};
|
|
64
53
|
|
|
65
54
|
const registerTelegramRoutes = ({
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
const topicRegistry = require("../topic-registry");
|
|
2
|
+
const { parsePositiveInt } = require("../utils/number");
|
|
2
3
|
|
|
3
4
|
const kSummaryCacheTtlMs = 60 * 1000;
|
|
4
5
|
const kClientTimeZoneHeader = "x-client-timezone";
|
|
5
6
|
|
|
6
|
-
const parsePositiveInt = (value, fallbackValue) => {
|
|
7
|
-
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
8
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallbackValue;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
7
|
const createSummaryCache = () => new Map();
|
|
12
8
|
const toTitleLabel = (value) => {
|
|
13
9
|
const raw = String(value || "").trim();
|
|
@@ -5,15 +5,11 @@ const {
|
|
|
5
5
|
deleteWebhook,
|
|
6
6
|
validateWebhookName,
|
|
7
7
|
} = require("../webhooks");
|
|
8
|
+
const { isTruthyFlag } = require("../utils/boolean");
|
|
8
9
|
|
|
9
10
|
const isFiniteInteger = (value) =>
|
|
10
11
|
Number.isFinite(value) && Number.isInteger(value);
|
|
11
|
-
const parseBooleanFlag = (value) =>
|
|
12
|
-
const normalized = String(value == null ? "" : value)
|
|
13
|
-
.trim()
|
|
14
|
-
.toLowerCase();
|
|
15
|
-
return ["1", "true", "yes", "on"].includes(normalized);
|
|
16
|
-
};
|
|
12
|
+
const parseBooleanFlag = (value) => isTruthyFlag(value);
|
|
17
13
|
|
|
18
14
|
const buildHealth = ({ totalCount, errorCount }) => {
|
|
19
15
|
if (!totalCount || totalCount <= 0) return "green";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const isTruthyFlag = (value) =>
|
|
2
|
+
["1", "true", "yes", "on"].includes(
|
|
3
|
+
String(value ?? "")
|
|
4
|
+
.trim()
|
|
5
|
+
.toLowerCase(),
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
const parseBooleanValue = (value, fallbackValue = false) => {
|
|
9
|
+
if (typeof value === "boolean") return value;
|
|
10
|
+
if (typeof value === "number") return value !== 0;
|
|
11
|
+
if (typeof value === "string") {
|
|
12
|
+
const normalized = value.trim().toLowerCase();
|
|
13
|
+
if (["true", "1", "yes", "on"].includes(normalized)) return true;
|
|
14
|
+
if (["false", "0", "no", "off", ""].includes(normalized)) return false;
|
|
15
|
+
}
|
|
16
|
+
return fallbackValue;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
isTruthyFlag,
|
|
21
|
+
parseBooleanValue,
|
|
22
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const parseJsonSafe = (rawValue, fallbackValue = null, options = {}) => {
|
|
2
|
+
const shouldTrim = options?.trim === true;
|
|
3
|
+
const text = shouldTrim
|
|
4
|
+
? String(rawValue ?? "").trim()
|
|
5
|
+
: String(rawValue ?? "");
|
|
6
|
+
if (!text) return fallbackValue;
|
|
7
|
+
try {
|
|
8
|
+
return JSON.parse(text);
|
|
9
|
+
} catch {
|
|
10
|
+
return fallbackValue;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const parseJsonObjectFromNoisyOutput = (rawValue) => {
|
|
15
|
+
const text = String(rawValue ?? "");
|
|
16
|
+
const firstBrace = text.indexOf("{");
|
|
17
|
+
const lastBrace = text.lastIndexOf("}");
|
|
18
|
+
if (firstBrace === -1 || lastBrace === -1 || lastBrace <= firstBrace) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(text.slice(firstBrace, lastBrace + 1));
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
parseJsonSafe,
|
|
30
|
+
parseJsonObjectFromNoisyOutput,
|
|
31
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const quoteShellArg = (value, options = {}) => {
|
|
2
|
+
const strategy = String(options?.strategy || "double").trim().toLowerCase();
|
|
3
|
+
const normalizedValue = String(value || "");
|
|
4
|
+
|
|
5
|
+
if (strategy === "single") {
|
|
6
|
+
return `'${normalizedValue.replace(/'/g, `'\"'\"'`)}'`;
|
|
7
|
+
}
|
|
8
|
+
if (strategy === "double") {
|
|
9
|
+
return `"${normalizedValue.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
10
|
+
}
|
|
11
|
+
throw new Error(`Unsupported shell quote strategy: ${strategy}`);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
quoteShellArg,
|
|
16
|
+
};
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
const http = require("http");
|
|
2
2
|
const https = require("https");
|
|
3
3
|
const { URL } = require("url");
|
|
4
|
+
const { normalizeIp } = require("./utils/network");
|
|
4
5
|
|
|
5
6
|
const kRedactedHeaderKeys = new Set(["authorization", "cookie", "x-webhook-token"]);
|
|
6
7
|
const kGmailDedupeTtlMs = 24 * 60 * 60 * 1000;
|
|
7
8
|
const kGmailDedupeCleanupIntervalMs = 60 * 1000;
|
|
8
9
|
|
|
9
|
-
const normalizeIp = (ip) => String(ip || "").replace(/^::ffff:/, "");
|
|
10
|
-
|
|
11
10
|
const sanitizeHeaders = (headers) => {
|
|
12
11
|
const sanitized = {};
|
|
13
12
|
for (const [key, value] of Object.entries(headers || {})) {
|
package/lib/server.js
CHANGED
|
@@ -30,19 +30,19 @@ const {
|
|
|
30
30
|
getRequestById,
|
|
31
31
|
getHookSummaries,
|
|
32
32
|
deleteRequestsByHook,
|
|
33
|
-
} = require("./server/webhooks
|
|
33
|
+
} = require("./server/db/webhooks");
|
|
34
34
|
const {
|
|
35
35
|
initWatchdogDb,
|
|
36
36
|
insertWatchdogEvent,
|
|
37
37
|
getRecentEvents,
|
|
38
|
-
} = require("./server/watchdog
|
|
38
|
+
} = require("./server/db/watchdog");
|
|
39
39
|
const {
|
|
40
40
|
initUsageDb,
|
|
41
41
|
getDailySummary,
|
|
42
42
|
getSessionsList,
|
|
43
43
|
getSessionDetail,
|
|
44
44
|
getSessionTimeSeries,
|
|
45
|
-
} = require("./server/usage
|
|
45
|
+
} = require("./server/db/usage");
|
|
46
46
|
const { createWebhookMiddleware } = require("./server/webhook-middleware");
|
|
47
47
|
const {
|
|
48
48
|
readEnvFile,
|