@agenshield/daemon 0.7.0 → 0.7.1
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/index.js +437 -191
- package/main.js +441 -195
- package/package.json +5 -5
- package/routes/marketplace.d.ts.map +1 -1
- package/routes/skills.d.ts.map +1 -1
- package/services/openclaw-config.d.ts +19 -0
- package/services/openclaw-config.d.ts.map +1 -1
- package/services/skill-deps.d.ts +29 -0
- package/services/skill-deps.d.ts.map +1 -0
- package/services/skill-lifecycle.d.ts +8 -0
- package/services/skill-lifecycle.d.ts.map +1 -1
- package/ui-assets/assets/{index-aFHqLzyo.js → index-DJILlJ1g.js} +24 -24
- package/ui-assets/index.html +1 -1
- package/watchers/skills.d.ts.map +1 -1
package/index.js
CHANGED
|
@@ -1046,10 +1046,7 @@ PLISTEOF`);
|
|
|
1046
1046
|
}
|
|
1047
1047
|
async function startOpenClawServices() {
|
|
1048
1048
|
try {
|
|
1049
|
-
|
|
1050
|
-
await execAsync3(`sudo launchctl kickstart system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1051
|
-
} catch {
|
|
1052
|
-
}
|
|
1049
|
+
await execAsync3(`sudo launchctl kickstart system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1053
1050
|
return {
|
|
1054
1051
|
success: true,
|
|
1055
1052
|
message: "OpenClaw gateway started"
|
|
@@ -1064,10 +1061,7 @@ async function startOpenClawServices() {
|
|
|
1064
1061
|
}
|
|
1065
1062
|
async function stopOpenClawServices() {
|
|
1066
1063
|
try {
|
|
1067
|
-
|
|
1068
|
-
await execAsync3(`sudo launchctl kill SIGTERM system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1069
|
-
} catch {
|
|
1070
|
-
}
|
|
1064
|
+
await execAsync3(`sudo launchctl kill SIGTERM system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1071
1065
|
return {
|
|
1072
1066
|
success: true,
|
|
1073
1067
|
message: "OpenClaw gateway stopped"
|
|
@@ -1082,10 +1076,7 @@ async function stopOpenClawServices() {
|
|
|
1082
1076
|
}
|
|
1083
1077
|
async function restartOpenClawServices() {
|
|
1084
1078
|
try {
|
|
1085
|
-
|
|
1086
|
-
await execAsync3(`sudo launchctl kickstart -k system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1087
|
-
} catch {
|
|
1088
|
-
}
|
|
1079
|
+
await execAsync3(`sudo launchctl kickstart -k system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1089
1080
|
return {
|
|
1090
1081
|
success: true,
|
|
1091
1082
|
message: "OpenClaw gateway restarted"
|
|
@@ -1168,15 +1159,29 @@ function getOpenClawStatusSync() {
|
|
|
1168
1159
|
async function getOpenClawDashboardUrl() {
|
|
1169
1160
|
try {
|
|
1170
1161
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
1171
|
-
const
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
)
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1162
|
+
const configPath = path22.join(agentHome, ".openclaw", "openclaw.json");
|
|
1163
|
+
let raw;
|
|
1164
|
+
try {
|
|
1165
|
+
raw = await fs32.readFile(configPath, "utf-8");
|
|
1166
|
+
} catch (err) {
|
|
1167
|
+
if (err.code === "EACCES") {
|
|
1168
|
+
const agentUsername = path22.basename(agentHome);
|
|
1169
|
+
const { stdout } = await execAsync3(
|
|
1170
|
+
`sudo -H -u ${agentUsername} cat "${configPath}"`,
|
|
1171
|
+
{ cwd: "/" }
|
|
1172
|
+
);
|
|
1173
|
+
raw = stdout;
|
|
1174
|
+
} else {
|
|
1175
|
+
return { success: false, error: `Cannot read openclaw.json: ${err.message}` };
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
const config = JSON.parse(raw);
|
|
1179
|
+
const port = config.gateway?.port;
|
|
1180
|
+
const token = config.gateway?.auth?.token;
|
|
1181
|
+
if (!port || !token) {
|
|
1182
|
+
return { success: false, error: "Gateway port or auth token not found in openclaw.json" };
|
|
1179
1183
|
}
|
|
1184
|
+
const url = `http://127.0.0.1:${port}/?token=${token}`;
|
|
1180
1185
|
return { success: true, url };
|
|
1181
1186
|
} catch (error) {
|
|
1182
1187
|
return { success: false, error: `Failed to get dashboard URL: ${error.message}` };
|
|
@@ -1766,7 +1771,7 @@ var init_secret_sync = __esm({
|
|
|
1766
1771
|
});
|
|
1767
1772
|
|
|
1768
1773
|
// libs/shield-daemon/src/server.ts
|
|
1769
|
-
import * as
|
|
1774
|
+
import * as fs23 from "node:fs";
|
|
1770
1775
|
import Fastify from "fastify";
|
|
1771
1776
|
import cors from "@fastify/cors";
|
|
1772
1777
|
import fastifyStatic from "@fastify/static";
|
|
@@ -2150,11 +2155,24 @@ function getOpenClawConfigPath() {
|
|
|
2150
2155
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
2151
2156
|
return path8.join(agentHome, ".openclaw", "openclaw.json");
|
|
2152
2157
|
}
|
|
2153
|
-
function
|
|
2158
|
+
function readOpenClawConfig() {
|
|
2154
2159
|
const configPath = getOpenClawConfigPath();
|
|
2155
2160
|
try {
|
|
2156
2161
|
if (fs8.existsSync(configPath)) {
|
|
2157
|
-
|
|
2162
|
+
try {
|
|
2163
|
+
return JSON.parse(fs8.readFileSync(configPath, "utf-8"));
|
|
2164
|
+
} catch (err) {
|
|
2165
|
+
if (err.code === "EACCES") {
|
|
2166
|
+
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
2167
|
+
const agentUsername = path8.basename(agentHome);
|
|
2168
|
+
const raw = execSync6(
|
|
2169
|
+
`sudo -H -u ${agentUsername} cat "${configPath}"`,
|
|
2170
|
+
{ encoding: "utf-8", cwd: "/", stdio: ["pipe", "pipe", "pipe"] }
|
|
2171
|
+
);
|
|
2172
|
+
return JSON.parse(raw);
|
|
2173
|
+
}
|
|
2174
|
+
throw err;
|
|
2175
|
+
}
|
|
2158
2176
|
}
|
|
2159
2177
|
} catch {
|
|
2160
2178
|
console.warn("[OpenClawConfig] Failed to read openclaw.json, starting fresh");
|
|
@@ -2172,7 +2190,7 @@ function writeConfig(config) {
|
|
|
2172
2190
|
const agentUsername = path8.basename(agentHome);
|
|
2173
2191
|
execSync6(
|
|
2174
2192
|
`sudo -H -u ${agentUsername} tee "${configPath}" > /dev/null`,
|
|
2175
|
-
{ input: JSON.stringify(config, null, 2), stdio: ["pipe", "pipe", "pipe"] }
|
|
2193
|
+
{ input: JSON.stringify(config, null, 2), stdio: ["pipe", "pipe", "pipe"], cwd: "/" }
|
|
2176
2194
|
);
|
|
2177
2195
|
} else {
|
|
2178
2196
|
throw err;
|
|
@@ -2180,27 +2198,30 @@ function writeConfig(config) {
|
|
|
2180
2198
|
}
|
|
2181
2199
|
}
|
|
2182
2200
|
function addSkillEntry(slug) {
|
|
2183
|
-
const config =
|
|
2201
|
+
const config = readOpenClawConfig();
|
|
2184
2202
|
if (!config.skills) {
|
|
2185
2203
|
config.skills = {};
|
|
2186
2204
|
}
|
|
2187
2205
|
if (!config.skills.entries) {
|
|
2188
2206
|
config.skills.entries = {};
|
|
2189
2207
|
}
|
|
2190
|
-
config.skills.entries[slug]
|
|
2208
|
+
const existing = config.skills.entries[slug] ?? {};
|
|
2209
|
+
config.skills.entries[slug] = { ...existing, enabled: true };
|
|
2191
2210
|
writeConfig(config);
|
|
2192
2211
|
console.log(`[OpenClawConfig] Added skill entry: ${slug}`);
|
|
2193
2212
|
}
|
|
2194
2213
|
function removeSkillEntry(slug) {
|
|
2195
|
-
const config =
|
|
2214
|
+
const config = readOpenClawConfig();
|
|
2196
2215
|
if (config.skills?.entries?.[slug]) {
|
|
2197
|
-
|
|
2216
|
+
const existing = config.skills.entries[slug];
|
|
2217
|
+
delete existing.env;
|
|
2218
|
+
config.skills.entries[slug] = { ...existing, enabled: false };
|
|
2198
2219
|
writeConfig(config);
|
|
2199
|
-
console.log(`[OpenClawConfig]
|
|
2220
|
+
console.log(`[OpenClawConfig] Disabled skill entry: ${slug}`);
|
|
2200
2221
|
}
|
|
2201
2222
|
}
|
|
2202
2223
|
function syncOpenClawFromPolicies(policies) {
|
|
2203
|
-
const config =
|
|
2224
|
+
const config = readOpenClawConfig();
|
|
2204
2225
|
if (!config.skills) config.skills = {};
|
|
2205
2226
|
const allowBundled = [];
|
|
2206
2227
|
for (const p of policies) {
|
|
@@ -2448,35 +2469,35 @@ var ANALYSIS_TIMEOUT = 4 * 6e4;
|
|
|
2448
2469
|
var SEARCH_CACHE_TTL = 6e4;
|
|
2449
2470
|
var DETAIL_CACHE_TTL = 5 * 6e4;
|
|
2450
2471
|
var SHORT_TIMEOUT = 1e4;
|
|
2451
|
-
async function convexAction(
|
|
2472
|
+
async function convexAction(path24, args, timeout) {
|
|
2452
2473
|
const res = await fetch(`${CONVEX_BASE}/api/action`, {
|
|
2453
2474
|
method: "POST",
|
|
2454
2475
|
signal: AbortSignal.timeout(timeout),
|
|
2455
2476
|
headers: { "Content-Type": "application/json" },
|
|
2456
|
-
body: JSON.stringify({ path:
|
|
2477
|
+
body: JSON.stringify({ path: path24, args, format: "json" })
|
|
2457
2478
|
});
|
|
2458
2479
|
if (!res.ok) {
|
|
2459
|
-
throw new Error(`Convex action ${
|
|
2480
|
+
throw new Error(`Convex action ${path24} returned ${res.status}`);
|
|
2460
2481
|
}
|
|
2461
2482
|
const body = await res.json();
|
|
2462
2483
|
if (body.status === "error") {
|
|
2463
|
-
throw new Error(`Convex action ${
|
|
2484
|
+
throw new Error(`Convex action ${path24}: ${body.errorMessage ?? "unknown error"}`);
|
|
2464
2485
|
}
|
|
2465
2486
|
return body.value;
|
|
2466
2487
|
}
|
|
2467
|
-
async function convexQuery(
|
|
2488
|
+
async function convexQuery(path24, args, timeout) {
|
|
2468
2489
|
const res = await fetch(`${CONVEX_BASE}/api/query`, {
|
|
2469
2490
|
method: "POST",
|
|
2470
2491
|
signal: AbortSignal.timeout(timeout),
|
|
2471
2492
|
headers: { "Content-Type": "application/json" },
|
|
2472
|
-
body: JSON.stringify({ path:
|
|
2493
|
+
body: JSON.stringify({ path: path24, args, format: "json" })
|
|
2473
2494
|
});
|
|
2474
2495
|
if (!res.ok) {
|
|
2475
|
-
throw new Error(`Convex query ${
|
|
2496
|
+
throw new Error(`Convex query ${path24} returned ${res.status}`);
|
|
2476
2497
|
}
|
|
2477
2498
|
const body = await res.json();
|
|
2478
2499
|
if (body.status === "error") {
|
|
2479
|
-
throw new Error(`Convex query ${
|
|
2500
|
+
throw new Error(`Convex query ${path24}: ${body.errorMessage ?? "unknown error"}`);
|
|
2480
2501
|
}
|
|
2481
2502
|
return body.value;
|
|
2482
2503
|
}
|
|
@@ -2678,9 +2699,9 @@ function inlineImagesInMarkdown(markdown, files) {
|
|
|
2678
2699
|
const mime = isImageExt(file.name);
|
|
2679
2700
|
if (mime && file.content.startsWith("data:")) {
|
|
2680
2701
|
imageMap.set(file.name, file.content);
|
|
2681
|
-
const
|
|
2682
|
-
if (
|
|
2683
|
-
imageMap.set(
|
|
2702
|
+
const basename6 = file.name.split("/").pop() ?? "";
|
|
2703
|
+
if (basename6 && !imageMap.has(basename6)) {
|
|
2704
|
+
imageMap.set(basename6, file.content);
|
|
2684
2705
|
}
|
|
2685
2706
|
}
|
|
2686
2707
|
}
|
|
@@ -3206,10 +3227,10 @@ function emitSecurityWarning(warning) {
|
|
|
3206
3227
|
function emitSecurityCritical(issue) {
|
|
3207
3228
|
daemonEvents.broadcast("security:critical", { message: issue });
|
|
3208
3229
|
}
|
|
3209
|
-
function emitApiRequest(method,
|
|
3230
|
+
function emitApiRequest(method, path24, statusCode, duration, requestBody, responseBody) {
|
|
3210
3231
|
daemonEvents.broadcast("api:request", {
|
|
3211
3232
|
method,
|
|
3212
|
-
path:
|
|
3233
|
+
path: path24,
|
|
3213
3234
|
statusCode,
|
|
3214
3235
|
duration,
|
|
3215
3236
|
...requestBody !== void 0 && { requestBody },
|
|
@@ -3464,26 +3485,16 @@ function scanSkills() {
|
|
|
3464
3485
|
}
|
|
3465
3486
|
function detectOpenClawMismatches() {
|
|
3466
3487
|
try {
|
|
3467
|
-
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
3468
|
-
const configPath = path11.join(agentHome, ".openclaw", "openclaw.json");
|
|
3469
|
-
if (!fs11.existsSync(configPath)) return;
|
|
3470
|
-
const raw = fs11.readFileSync(configPath, "utf-8");
|
|
3471
|
-
const config = JSON.parse(raw);
|
|
3472
|
-
if (!config.skills?.entries) return;
|
|
3473
3488
|
const approved = loadApprovedSkills();
|
|
3474
3489
|
const approvedNames = new Set(approved.map((a) => a.name));
|
|
3475
|
-
const
|
|
3476
|
-
|
|
3477
|
-
for (const name of entries) {
|
|
3490
|
+
const config = readOpenClawConfig();
|
|
3491
|
+
if (!config.skills?.entries) return;
|
|
3492
|
+
for (const name of Object.keys(config.skills.entries)) {
|
|
3478
3493
|
if (!approvedNames.has(name)) {
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
console.log(`[SkillsWatcher] Removed stale openclaw.json entry: ${name}`);
|
|
3494
|
+
removeSkillEntry(name);
|
|
3495
|
+
console.log(`[SkillsWatcher] Disabled stale openclaw.json entry: ${name}`);
|
|
3482
3496
|
}
|
|
3483
3497
|
}
|
|
3484
|
-
if (changed) {
|
|
3485
|
-
fs11.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
3486
|
-
}
|
|
3487
3498
|
} catch {
|
|
3488
3499
|
}
|
|
3489
3500
|
}
|
|
@@ -4042,16 +4053,16 @@ var PROTECTED_ROUTES = [
|
|
|
4042
4053
|
{ method: "POST", path: "/api/skills/install" },
|
|
4043
4054
|
{ method: "GET", path: "/api/openclaw/dashboard-url" }
|
|
4044
4055
|
];
|
|
4045
|
-
function isProtectedRoute(method,
|
|
4056
|
+
function isProtectedRoute(method, path24) {
|
|
4046
4057
|
return PROTECTED_ROUTES.some(
|
|
4047
|
-
(route) => route.method === method &&
|
|
4058
|
+
(route) => route.method === method && path24.startsWith(route.path)
|
|
4048
4059
|
);
|
|
4049
4060
|
}
|
|
4050
4061
|
function createAuthHook() {
|
|
4051
4062
|
return async (request2, reply) => {
|
|
4052
4063
|
const method = request2.method;
|
|
4053
|
-
const
|
|
4054
|
-
if (!isProtectedRoute(method,
|
|
4064
|
+
const path24 = request2.url.split("?")[0];
|
|
4065
|
+
if (!isProtectedRoute(method, path24)) {
|
|
4055
4066
|
return;
|
|
4056
4067
|
}
|
|
4057
4068
|
if (!isAuthenticated(request2)) {
|
|
@@ -7550,19 +7561,50 @@ async function agencoRoutes(app) {
|
|
|
7550
7561
|
}
|
|
7551
7562
|
|
|
7552
7563
|
// libs/shield-daemon/src/routes/skills.ts
|
|
7553
|
-
import * as
|
|
7554
|
-
import * as
|
|
7564
|
+
import * as fs17 from "node:fs";
|
|
7565
|
+
import * as path17 from "node:path";
|
|
7555
7566
|
import { execSync as execSync9 } from "node:child_process";
|
|
7556
|
-
import { parseSkillMd as
|
|
7567
|
+
import { parseSkillMd as parseSkillMd3, stripEnvFromSkillMd as stripEnvFromSkillMd2 } from "@agenshield/sandbox";
|
|
7557
7568
|
|
|
7558
7569
|
// libs/shield-daemon/src/services/skill-lifecycle.ts
|
|
7559
7570
|
import * as fs14 from "node:fs";
|
|
7560
7571
|
import * as path14 from "node:path";
|
|
7561
7572
|
import { execSync as execSync8 } from "node:child_process";
|
|
7562
|
-
function
|
|
7563
|
-
|
|
7564
|
-
fs14.mkdirSync(
|
|
7573
|
+
function sudoMkdir(dir, agentUsername) {
|
|
7574
|
+
try {
|
|
7575
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
7576
|
+
} catch (err) {
|
|
7577
|
+
if (err.code === "EACCES") {
|
|
7578
|
+
execSync8(`sudo -H -u ${agentUsername} /bin/mkdir -p "${dir}"`, { cwd: "/", stdio: "pipe" });
|
|
7579
|
+
} else {
|
|
7580
|
+
throw err;
|
|
7581
|
+
}
|
|
7582
|
+
}
|
|
7583
|
+
}
|
|
7584
|
+
function sudoWriteFile(filePath, content, agentUsername, mode) {
|
|
7585
|
+
try {
|
|
7586
|
+
fs14.writeFileSync(filePath, content, { mode });
|
|
7587
|
+
} catch (err) {
|
|
7588
|
+
if (err.code === "EACCES") {
|
|
7589
|
+
execSync8(
|
|
7590
|
+
`sudo -H -u ${agentUsername} tee "${filePath}" > /dev/null`,
|
|
7591
|
+
{ input: content, cwd: "/", stdio: ["pipe", "pipe", "pipe"] }
|
|
7592
|
+
);
|
|
7593
|
+
if (mode) {
|
|
7594
|
+
try {
|
|
7595
|
+
execSync8(`sudo -H -u ${agentUsername} chmod ${mode.toString(8)} "${filePath}"`, { cwd: "/", stdio: "pipe" });
|
|
7596
|
+
} catch {
|
|
7597
|
+
}
|
|
7598
|
+
}
|
|
7599
|
+
} else {
|
|
7600
|
+
throw err;
|
|
7601
|
+
}
|
|
7565
7602
|
}
|
|
7603
|
+
}
|
|
7604
|
+
function createSkillWrapper(name, binDir) {
|
|
7605
|
+
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
7606
|
+
const agentUsername = path14.basename(agentHome);
|
|
7607
|
+
sudoMkdir(binDir, agentUsername);
|
|
7566
7608
|
const wrapperPath = path14.join(binDir, name);
|
|
7567
7609
|
const wrapperContent = `#!/bin/bash
|
|
7568
7610
|
# ${name} skill wrapper - policy-enforced execution
|
|
@@ -7570,7 +7612,7 @@ function createSkillWrapper(name, binDir) {
|
|
|
7570
7612
|
if ! /bin/pwd > /dev/null 2>&1; then cd ~ 2>/dev/null || cd /; fi
|
|
7571
7613
|
exec /opt/agenshield/bin/shield-client skill run "${name}" "$@"
|
|
7572
7614
|
`;
|
|
7573
|
-
|
|
7615
|
+
sudoWriteFile(wrapperPath, wrapperContent, agentUsername, 493);
|
|
7574
7616
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
7575
7617
|
try {
|
|
7576
7618
|
execSync8(`chown root:${socketGroup} "${wrapperPath}"`, { stdio: "pipe" });
|
|
@@ -7615,8 +7657,8 @@ function removeSkillPolicy(name) {
|
|
|
7615
7657
|
}
|
|
7616
7658
|
|
|
7617
7659
|
// libs/shield-daemon/src/routes/marketplace.ts
|
|
7618
|
-
import * as
|
|
7619
|
-
import * as
|
|
7660
|
+
import * as fs16 from "node:fs";
|
|
7661
|
+
import * as path16 from "node:path";
|
|
7620
7662
|
|
|
7621
7663
|
// libs/shield-broker/dist/index.js
|
|
7622
7664
|
import { exec as exec4 } from "node:child_process";
|
|
@@ -7892,6 +7934,175 @@ async function uninstallSkillViaBroker(slug, options = {}) {
|
|
|
7892
7934
|
return result;
|
|
7893
7935
|
}
|
|
7894
7936
|
|
|
7937
|
+
// libs/shield-daemon/src/routes/marketplace.ts
|
|
7938
|
+
import { stripEnvFromSkillMd } from "@agenshield/sandbox";
|
|
7939
|
+
|
|
7940
|
+
// libs/shield-daemon/src/services/skill-deps.ts
|
|
7941
|
+
import * as fs15 from "node:fs";
|
|
7942
|
+
import * as path15 from "node:path";
|
|
7943
|
+
import { parseSkillMd as parseSkillMd2, extractSkillInfo } from "@agenshield/sandbox";
|
|
7944
|
+
import { execWithProgress as execWithProgress3 } from "@agenshield/sandbox";
|
|
7945
|
+
var SUPPORTED_KINDS = /* @__PURE__ */ new Set(["brew", "npm", "pip"]);
|
|
7946
|
+
var SAFE_PACKAGE_RE = /^[a-zA-Z0-9@/_.\-]+$/;
|
|
7947
|
+
function findSkillMdRecursive(dir, depth = 0) {
|
|
7948
|
+
if (depth > 3) return null;
|
|
7949
|
+
try {
|
|
7950
|
+
for (const name of ["SKILL.md", "skill.md", "README.md", "readme.md"]) {
|
|
7951
|
+
const candidate = path15.join(dir, name);
|
|
7952
|
+
if (fs15.existsSync(candidate)) return candidate;
|
|
7953
|
+
}
|
|
7954
|
+
const entries = fs15.readdirSync(dir, { withFileTypes: true });
|
|
7955
|
+
for (const entry of entries) {
|
|
7956
|
+
if (!entry.isDirectory()) continue;
|
|
7957
|
+
const found = findSkillMdRecursive(path15.join(dir, entry.name), depth + 1);
|
|
7958
|
+
if (found) return found;
|
|
7959
|
+
}
|
|
7960
|
+
} catch {
|
|
7961
|
+
}
|
|
7962
|
+
return null;
|
|
7963
|
+
}
|
|
7964
|
+
async function executeSkillInstallSteps(options) {
|
|
7965
|
+
const { slug, skillDir, agentHome, agentUsername, onLog } = options;
|
|
7966
|
+
const installed = [];
|
|
7967
|
+
const errors = [];
|
|
7968
|
+
const skillMdPath = findSkillMdRecursive(skillDir);
|
|
7969
|
+
if (!skillMdPath) {
|
|
7970
|
+
return { success: true, installed, errors };
|
|
7971
|
+
}
|
|
7972
|
+
let content;
|
|
7973
|
+
try {
|
|
7974
|
+
content = fs15.readFileSync(skillMdPath, "utf-8");
|
|
7975
|
+
} catch {
|
|
7976
|
+
return { success: true, installed, errors };
|
|
7977
|
+
}
|
|
7978
|
+
const parsed = parseSkillMd2(content);
|
|
7979
|
+
if (!parsed) {
|
|
7980
|
+
return { success: true, installed, errors };
|
|
7981
|
+
}
|
|
7982
|
+
const info = extractSkillInfo(parsed.metadata);
|
|
7983
|
+
const installSteps = info.installSteps;
|
|
7984
|
+
if (!Array.isArray(installSteps) || installSteps.length === 0) {
|
|
7985
|
+
return { success: true, installed, errors };
|
|
7986
|
+
}
|
|
7987
|
+
onLog(`Found ${installSteps.length} dependency install step(s) for ${slug}`);
|
|
7988
|
+
for (const step of installSteps) {
|
|
7989
|
+
const kind = step.kind;
|
|
7990
|
+
const stepId = step.id || kind;
|
|
7991
|
+
if (!SUPPORTED_KINDS.has(kind)) {
|
|
7992
|
+
errors.push(`Unsupported install kind "${kind}" (step: ${stepId})`);
|
|
7993
|
+
continue;
|
|
7994
|
+
}
|
|
7995
|
+
try {
|
|
7996
|
+
switch (kind) {
|
|
7997
|
+
case "brew": {
|
|
7998
|
+
const formula = step.formula;
|
|
7999
|
+
if (!formula) {
|
|
8000
|
+
errors.push(`Brew step "${stepId}" missing formula`);
|
|
8001
|
+
break;
|
|
8002
|
+
}
|
|
8003
|
+
if (!SAFE_PACKAGE_RE.test(formula)) {
|
|
8004
|
+
errors.push(`Unsafe brew formula name: ${formula}`);
|
|
8005
|
+
break;
|
|
8006
|
+
}
|
|
8007
|
+
onLog(`Installing brew formula: ${formula}`);
|
|
8008
|
+
const brewCmd = [
|
|
8009
|
+
`export HOME="${agentHome}"`,
|
|
8010
|
+
`export PATH="${agentHome}/homebrew/bin:${agentHome}/bin:$PATH"`,
|
|
8011
|
+
`brew install ${formula}`
|
|
8012
|
+
].join(" && ");
|
|
8013
|
+
await execWithProgress3(
|
|
8014
|
+
`sudo -H -u ${agentUsername} /bin/bash --norc --noprofile -c '${brewCmd}'`,
|
|
8015
|
+
onLog,
|
|
8016
|
+
{ timeout: 12e4, cwd: "/" }
|
|
8017
|
+
);
|
|
8018
|
+
installed.push(formula);
|
|
8019
|
+
break;
|
|
8020
|
+
}
|
|
8021
|
+
case "npm": {
|
|
8022
|
+
const pkg = step["package"];
|
|
8023
|
+
if (!pkg) {
|
|
8024
|
+
errors.push(`npm step "${stepId}" missing package`);
|
|
8025
|
+
break;
|
|
8026
|
+
}
|
|
8027
|
+
if (!SAFE_PACKAGE_RE.test(pkg)) {
|
|
8028
|
+
errors.push(`Unsafe npm package name: ${pkg}`);
|
|
8029
|
+
break;
|
|
8030
|
+
}
|
|
8031
|
+
onLog(`Installing npm package: ${pkg}`);
|
|
8032
|
+
const npmCmd = [
|
|
8033
|
+
`export HOME="${agentHome}"`,
|
|
8034
|
+
`export PATH="${agentHome}/bin:$PATH"`,
|
|
8035
|
+
`source "${agentHome}/.nvm/nvm.sh" 2>/dev/null || true`,
|
|
8036
|
+
`npm install -g ${pkg}`
|
|
8037
|
+
].join(" && ");
|
|
8038
|
+
await execWithProgress3(
|
|
8039
|
+
`sudo -H -u ${agentUsername} /bin/bash --norc --noprofile -c '${npmCmd}'`,
|
|
8040
|
+
onLog,
|
|
8041
|
+
{ timeout: 6e4, cwd: "/" }
|
|
8042
|
+
);
|
|
8043
|
+
installed.push(pkg);
|
|
8044
|
+
break;
|
|
8045
|
+
}
|
|
8046
|
+
case "pip": {
|
|
8047
|
+
const pkg = step["package"];
|
|
8048
|
+
if (!pkg) {
|
|
8049
|
+
errors.push(`pip step "${stepId}" missing package`);
|
|
8050
|
+
break;
|
|
8051
|
+
}
|
|
8052
|
+
if (!SAFE_PACKAGE_RE.test(pkg)) {
|
|
8053
|
+
errors.push(`Unsafe pip package name: ${pkg}`);
|
|
8054
|
+
break;
|
|
8055
|
+
}
|
|
8056
|
+
onLog(`Installing pip package: ${pkg}`);
|
|
8057
|
+
const pipCmd = [
|
|
8058
|
+
`export HOME="${agentHome}"`,
|
|
8059
|
+
`export PATH="${agentHome}/bin:$PATH"`,
|
|
8060
|
+
`pip install ${pkg}`
|
|
8061
|
+
].join(" && ");
|
|
8062
|
+
await execWithProgress3(
|
|
8063
|
+
`sudo -H -u ${agentUsername} /bin/bash --norc --noprofile -c '${pipCmd}'`,
|
|
8064
|
+
onLog,
|
|
8065
|
+
{ timeout: 6e4, cwd: "/" }
|
|
8066
|
+
);
|
|
8067
|
+
installed.push(pkg);
|
|
8068
|
+
break;
|
|
8069
|
+
}
|
|
8070
|
+
}
|
|
8071
|
+
} catch (err) {
|
|
8072
|
+
const msg = `Failed to install ${kind} dep (step: ${stepId}): ${err.message}`;
|
|
8073
|
+
onLog(msg);
|
|
8074
|
+
errors.push(msg);
|
|
8075
|
+
}
|
|
8076
|
+
}
|
|
8077
|
+
const requiredBins = info.bins;
|
|
8078
|
+
if (requiredBins.length > 0) {
|
|
8079
|
+
onLog(`Verifying required binaries: ${requiredBins.join(", ")}`);
|
|
8080
|
+
for (const bin of requiredBins) {
|
|
8081
|
+
try {
|
|
8082
|
+
const checkCmd = [
|
|
8083
|
+
`export HOME="${agentHome}"`,
|
|
8084
|
+
`export PATH="${agentHome}/homebrew/bin:${agentHome}/bin:$PATH"`,
|
|
8085
|
+
`source "${agentHome}/.nvm/nvm.sh" 2>/dev/null || true`,
|
|
8086
|
+
`which ${bin}`
|
|
8087
|
+
].join(" && ");
|
|
8088
|
+
await execWithProgress3(
|
|
8089
|
+
`sudo -H -u ${agentUsername} /bin/bash --norc --noprofile -c '${checkCmd}'`,
|
|
8090
|
+
() => {
|
|
8091
|
+
},
|
|
8092
|
+
{ timeout: 5e3, cwd: "/" }
|
|
8093
|
+
);
|
|
8094
|
+
} catch {
|
|
8095
|
+
errors.push(`Required binary "${bin}" not found in agent PATH after install`);
|
|
8096
|
+
}
|
|
8097
|
+
}
|
|
8098
|
+
}
|
|
8099
|
+
return {
|
|
8100
|
+
success: errors.length === 0,
|
|
8101
|
+
installed,
|
|
8102
|
+
errors
|
|
8103
|
+
};
|
|
8104
|
+
}
|
|
8105
|
+
|
|
7895
8106
|
// libs/shield-daemon/src/routes/marketplace.ts
|
|
7896
8107
|
var installInProgress = /* @__PURE__ */ new Set();
|
|
7897
8108
|
function isInstallInProgress(slug) {
|
|
@@ -8146,7 +8357,7 @@ async function marketplaceRoutes(app) {
|
|
|
8146
8357
|
error: "Critical vulnerability detected",
|
|
8147
8358
|
analysis: analysisResult
|
|
8148
8359
|
});
|
|
8149
|
-
return { success: false, name: slug, analysis: analysisResult, logs };
|
|
8360
|
+
return { success: false, name: slug, analysis: analysisResult, logs, depsSuccess: void 0 };
|
|
8150
8361
|
}
|
|
8151
8362
|
emitSkillInstallProgress(slug, "download", "Downloading skill files");
|
|
8152
8363
|
const skill = await getMarketplaceSkill(slug);
|
|
@@ -8156,7 +8367,7 @@ async function marketplaceRoutes(app) {
|
|
|
8156
8367
|
name: slug,
|
|
8157
8368
|
error: "No files available for installation"
|
|
8158
8369
|
});
|
|
8159
|
-
return { success: false, name: slug, analysis: analysisResult, logs };
|
|
8370
|
+
return { success: false, name: slug, analysis: analysisResult, logs, depsSuccess: void 0 };
|
|
8160
8371
|
}
|
|
8161
8372
|
const publisher = skill.author;
|
|
8162
8373
|
logs.push("Downloaded skill files");
|
|
@@ -8165,18 +8376,23 @@ async function marketplaceRoutes(app) {
|
|
|
8165
8376
|
throw new Error("Skills directory not configured");
|
|
8166
8377
|
}
|
|
8167
8378
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
8168
|
-
const
|
|
8379
|
+
const agentUsername = path16.basename(agentHome);
|
|
8380
|
+
const binDir = path16.join(agentHome, "bin");
|
|
8169
8381
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
8170
|
-
skillDir =
|
|
8382
|
+
skillDir = path16.join(skillsDir2, slug);
|
|
8171
8383
|
emitSkillInstallProgress(slug, "approve", "Pre-approving skill");
|
|
8172
8384
|
addToApprovedList(slug, publisher);
|
|
8173
8385
|
logs.push("Skill pre-approved");
|
|
8174
8386
|
emitSkillInstallProgress(slug, "copy", "Writing skill files");
|
|
8175
8387
|
const brokerAvailable = await isBrokerAvailable();
|
|
8176
8388
|
if (brokerAvailable) {
|
|
8389
|
+
const sanitizedFiles = files.map((f) => ({
|
|
8390
|
+
name: f.name,
|
|
8391
|
+
content: /SKILL\.md$/i.test(f.name) ? stripEnvFromSkillMd(f.content) : f.content
|
|
8392
|
+
}));
|
|
8177
8393
|
const brokerResult = await installSkillViaBroker(
|
|
8178
8394
|
slug,
|
|
8179
|
-
|
|
8395
|
+
sanitizedFiles,
|
|
8180
8396
|
{ createWrapper: true, agentHome, socketGroup }
|
|
8181
8397
|
);
|
|
8182
8398
|
if (!brokerResult.installed) {
|
|
@@ -8195,18 +8411,45 @@ async function marketplaceRoutes(app) {
|
|
|
8195
8411
|
}
|
|
8196
8412
|
} else {
|
|
8197
8413
|
console.log(`[Marketplace] Broker unavailable, installing ${slug} directly`);
|
|
8198
|
-
|
|
8414
|
+
sudoMkdir(skillDir, agentUsername);
|
|
8199
8415
|
for (const file of files) {
|
|
8200
|
-
const filePath =
|
|
8201
|
-
const fileDir =
|
|
8416
|
+
const filePath = path16.join(skillDir, file.name);
|
|
8417
|
+
const fileDir = path16.dirname(filePath);
|
|
8202
8418
|
if (fileDir !== skillDir) {
|
|
8203
|
-
|
|
8419
|
+
sudoMkdir(fileDir, agentUsername);
|
|
8204
8420
|
}
|
|
8205
|
-
|
|
8421
|
+
const content = /SKILL\.md$/i.test(file.name) ? stripEnvFromSkillMd(file.content) : file.content;
|
|
8422
|
+
sudoWriteFile(filePath, content, agentUsername);
|
|
8206
8423
|
}
|
|
8207
8424
|
createSkillWrapper(slug, binDir);
|
|
8208
8425
|
logs.push(`Files written directly: ${files.length} files`);
|
|
8209
|
-
logs.push(`Wrapper created: ${
|
|
8426
|
+
logs.push(`Wrapper created: ${path16.join(binDir, slug)}`);
|
|
8427
|
+
}
|
|
8428
|
+
let depsSuccess = true;
|
|
8429
|
+
emitSkillInstallProgress(slug, "deps", "Installing skill dependencies");
|
|
8430
|
+
try {
|
|
8431
|
+
const depsResult = await executeSkillInstallSteps({
|
|
8432
|
+
slug,
|
|
8433
|
+
skillDir,
|
|
8434
|
+
agentHome,
|
|
8435
|
+
agentUsername,
|
|
8436
|
+
onLog: (msg) => emitSkillInstallProgress(slug, "deps", msg)
|
|
8437
|
+
});
|
|
8438
|
+
if (depsResult.installed.length > 0) {
|
|
8439
|
+
logs.push(`Dependencies installed: ${depsResult.installed.join(", ")}`);
|
|
8440
|
+
}
|
|
8441
|
+
if (depsResult.errors.length > 0) {
|
|
8442
|
+
depsSuccess = false;
|
|
8443
|
+
for (const err of depsResult.errors) {
|
|
8444
|
+
emitSkillInstallProgress(slug, "warning", `Dependency warning: ${err}`);
|
|
8445
|
+
logs.push(`Dependency warning: ${err}`);
|
|
8446
|
+
}
|
|
8447
|
+
}
|
|
8448
|
+
} catch (err) {
|
|
8449
|
+
depsSuccess = false;
|
|
8450
|
+
const msg = `Dependency installation failed: ${err.message}`;
|
|
8451
|
+
emitSkillInstallProgress(slug, "warning", msg);
|
|
8452
|
+
logs.push(msg);
|
|
8210
8453
|
}
|
|
8211
8454
|
addSkillEntry(slug);
|
|
8212
8455
|
addSkillPolicy(slug);
|
|
@@ -8218,13 +8461,14 @@ async function marketplaceRoutes(app) {
|
|
|
8218
8461
|
logs.push("Integrity hash recorded");
|
|
8219
8462
|
}
|
|
8220
8463
|
installInProgress.delete(slug);
|
|
8221
|
-
|
|
8464
|
+
const depsWarnings = depsSuccess ? void 0 : logs.filter((l) => l.startsWith("Dependency"));
|
|
8465
|
+
daemonEvents.broadcast("skills:installed", { name: slug, analysis: analysisResult, depsWarnings });
|
|
8222
8466
|
logs.push("Installation complete");
|
|
8223
|
-
return { success: true, name: slug, analysis: analysisResult, logs };
|
|
8467
|
+
return { success: true, name: slug, analysis: analysisResult, logs, depsSuccess };
|
|
8224
8468
|
} catch (err) {
|
|
8225
8469
|
try {
|
|
8226
|
-
if (skillDir &&
|
|
8227
|
-
|
|
8470
|
+
if (skillDir && fs16.existsSync(skillDir)) {
|
|
8471
|
+
fs16.rmSync(skillDir, { recursive: true, force: true });
|
|
8228
8472
|
}
|
|
8229
8473
|
removeFromApprovedList(slug);
|
|
8230
8474
|
} catch {
|
|
@@ -8233,7 +8477,7 @@ async function marketplaceRoutes(app) {
|
|
|
8233
8477
|
installInProgress.delete(slug);
|
|
8234
8478
|
daemonEvents.broadcast("skills:install_failed", { name: slug, error: errorMsg });
|
|
8235
8479
|
console.error("[Marketplace] Install failed:", errorMsg);
|
|
8236
|
-
return { success: false, name: slug, analysis: analysisResult, logs: [...logs, `Error: ${errorMsg}`] };
|
|
8480
|
+
return { success: false, name: slug, analysis: analysisResult, logs: [...logs, `Error: ${errorMsg}`], depsSuccess: void 0 };
|
|
8237
8481
|
} finally {
|
|
8238
8482
|
installInProgress.delete(slug);
|
|
8239
8483
|
}
|
|
@@ -8257,17 +8501,17 @@ async function marketplaceRoutes(app) {
|
|
|
8257
8501
|
}
|
|
8258
8502
|
|
|
8259
8503
|
// libs/shield-daemon/src/routes/skills.ts
|
|
8260
|
-
function
|
|
8504
|
+
function findSkillMdRecursive2(dir, depth = 0) {
|
|
8261
8505
|
if (depth > 3) return null;
|
|
8262
8506
|
try {
|
|
8263
8507
|
for (const name of ["SKILL.md", "skill.md", "README.md", "readme.md"]) {
|
|
8264
|
-
const candidate =
|
|
8265
|
-
if (
|
|
8508
|
+
const candidate = path17.join(dir, name);
|
|
8509
|
+
if (fs17.existsSync(candidate)) return candidate;
|
|
8266
8510
|
}
|
|
8267
|
-
const entries =
|
|
8511
|
+
const entries = fs17.readdirSync(dir, { withFileTypes: true });
|
|
8268
8512
|
for (const entry of entries) {
|
|
8269
8513
|
if (!entry.isDirectory()) continue;
|
|
8270
|
-
const found =
|
|
8514
|
+
const found = findSkillMdRecursive2(path17.join(dir, entry.name), depth + 1);
|
|
8271
8515
|
if (found) return found;
|
|
8272
8516
|
}
|
|
8273
8517
|
} catch {
|
|
@@ -8276,10 +8520,10 @@ function findSkillMdRecursive(dir, depth = 0) {
|
|
|
8276
8520
|
}
|
|
8277
8521
|
function readSkillMetadata(skillDir) {
|
|
8278
8522
|
try {
|
|
8279
|
-
const mdPath =
|
|
8523
|
+
const mdPath = findSkillMdRecursive2(skillDir);
|
|
8280
8524
|
if (!mdPath) return {};
|
|
8281
|
-
const content =
|
|
8282
|
-
const parsed =
|
|
8525
|
+
const content = fs17.readFileSync(mdPath, "utf-8");
|
|
8526
|
+
const parsed = parseSkillMd3(content);
|
|
8283
8527
|
const meta = parsed?.metadata;
|
|
8284
8528
|
return {
|
|
8285
8529
|
description: meta?.description,
|
|
@@ -8337,7 +8581,7 @@ async function skillsRoutes(app) {
|
|
|
8337
8581
|
let onDiskNames = [];
|
|
8338
8582
|
if (skillsDir2) {
|
|
8339
8583
|
try {
|
|
8340
|
-
onDiskNames =
|
|
8584
|
+
onDiskNames = fs17.readdirSync(skillsDir2, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
8341
8585
|
} catch {
|
|
8342
8586
|
}
|
|
8343
8587
|
}
|
|
@@ -8347,14 +8591,14 @@ async function skillsRoutes(app) {
|
|
|
8347
8591
|
const data = [
|
|
8348
8592
|
// Approved → active (with metadata from SKILL.md + cached analysis)
|
|
8349
8593
|
...approved.map((a) => {
|
|
8350
|
-
const meta = skillsDir2 ? readSkillMetadata(
|
|
8594
|
+
const meta = skillsDir2 ? readSkillMetadata(path17.join(skillsDir2, a.name)) : {};
|
|
8351
8595
|
const cached = getCachedAnalysis2(a.name);
|
|
8352
8596
|
const dlMeta = getDownloadedSkillMeta(a.name);
|
|
8353
8597
|
return {
|
|
8354
8598
|
name: a.name,
|
|
8355
8599
|
source: "user",
|
|
8356
8600
|
status: "active",
|
|
8357
|
-
path:
|
|
8601
|
+
path: path17.join(skillsDir2 ?? "", a.name),
|
|
8358
8602
|
publisher: a.publisher,
|
|
8359
8603
|
description: meta.description,
|
|
8360
8604
|
version: meta.version,
|
|
@@ -8381,12 +8625,12 @@ async function skillsRoutes(app) {
|
|
|
8381
8625
|
}),
|
|
8382
8626
|
// Workspace: on disk but not approved or untrusted
|
|
8383
8627
|
...workspaceNames.map((name) => {
|
|
8384
|
-
const meta = skillsDir2 ? readSkillMetadata(
|
|
8628
|
+
const meta = skillsDir2 ? readSkillMetadata(path17.join(skillsDir2, name)) : {};
|
|
8385
8629
|
return {
|
|
8386
8630
|
name,
|
|
8387
8631
|
source: "workspace",
|
|
8388
8632
|
status: "workspace",
|
|
8389
|
-
path:
|
|
8633
|
+
path: path17.join(skillsDir2 ?? "", name),
|
|
8390
8634
|
description: meta.description,
|
|
8391
8635
|
version: meta.version,
|
|
8392
8636
|
author: meta.author,
|
|
@@ -8417,7 +8661,7 @@ async function skillsRoutes(app) {
|
|
|
8417
8661
|
let isWorkspace = false;
|
|
8418
8662
|
if (!entry && !uEntry && skillsDir2) {
|
|
8419
8663
|
try {
|
|
8420
|
-
isWorkspace =
|
|
8664
|
+
isWorkspace = fs17.existsSync(path17.join(skillsDir2, name));
|
|
8421
8665
|
} catch {
|
|
8422
8666
|
}
|
|
8423
8667
|
}
|
|
@@ -8435,13 +8679,13 @@ async function skillsRoutes(app) {
|
|
|
8435
8679
|
analysis: buildFullAnalysis(name, dlMeta?.analysis || getCachedAnalysis2(name))
|
|
8436
8680
|
};
|
|
8437
8681
|
} else if (entry) {
|
|
8438
|
-
const meta = skillsDir2 ? readSkillMetadata(
|
|
8682
|
+
const meta = skillsDir2 ? readSkillMetadata(path17.join(skillsDir2, name)) : {};
|
|
8439
8683
|
const cached = getCachedAnalysis2(name);
|
|
8440
8684
|
summary = {
|
|
8441
8685
|
name,
|
|
8442
8686
|
source: "user",
|
|
8443
8687
|
status: "active",
|
|
8444
|
-
path: skillsDir2 ?
|
|
8688
|
+
path: skillsDir2 ? path17.join(skillsDir2, name) : "",
|
|
8445
8689
|
publisher: entry.publisher,
|
|
8446
8690
|
description: meta.description,
|
|
8447
8691
|
version: meta.version,
|
|
@@ -8450,12 +8694,12 @@ async function skillsRoutes(app) {
|
|
|
8450
8694
|
analysis: buildFullAnalysis(name, dlMeta?.analysis || cached)
|
|
8451
8695
|
};
|
|
8452
8696
|
} else if (isWorkspace) {
|
|
8453
|
-
const meta = skillsDir2 ? readSkillMetadata(
|
|
8697
|
+
const meta = skillsDir2 ? readSkillMetadata(path17.join(skillsDir2, name)) : {};
|
|
8454
8698
|
summary = {
|
|
8455
8699
|
name,
|
|
8456
8700
|
source: "workspace",
|
|
8457
8701
|
status: "workspace",
|
|
8458
|
-
path: skillsDir2 ?
|
|
8702
|
+
path: skillsDir2 ? path17.join(skillsDir2, name) : "",
|
|
8459
8703
|
description: meta.description,
|
|
8460
8704
|
version: meta.version,
|
|
8461
8705
|
author: meta.author,
|
|
@@ -8480,11 +8724,11 @@ async function skillsRoutes(app) {
|
|
|
8480
8724
|
return reply.code(404).send({ error: `Skill "${name}" not found` });
|
|
8481
8725
|
}
|
|
8482
8726
|
let content = "";
|
|
8483
|
-
const dirToRead = summary.path || (skillsDir2 ?
|
|
8727
|
+
const dirToRead = summary.path || (skillsDir2 ? path17.join(skillsDir2, name) : "");
|
|
8484
8728
|
if (dirToRead) {
|
|
8485
8729
|
try {
|
|
8486
|
-
const mdPath =
|
|
8487
|
-
if (mdPath) content =
|
|
8730
|
+
const mdPath = findSkillMdRecursive2(dirToRead);
|
|
8731
|
+
if (mdPath) content = fs17.readFileSync(mdPath, "utf-8");
|
|
8488
8732
|
} catch {
|
|
8489
8733
|
}
|
|
8490
8734
|
}
|
|
@@ -8522,14 +8766,14 @@ async function skillsRoutes(app) {
|
|
|
8522
8766
|
if (!content) {
|
|
8523
8767
|
const skillsDir2 = getSkillsDir();
|
|
8524
8768
|
const possibleDirs = [
|
|
8525
|
-
skillsDir2 ?
|
|
8769
|
+
skillsDir2 ? path17.join(skillsDir2, name) : null
|
|
8526
8770
|
].filter(Boolean);
|
|
8527
8771
|
for (const dir of possibleDirs) {
|
|
8528
8772
|
try {
|
|
8529
|
-
const mdPath =
|
|
8773
|
+
const mdPath = findSkillMdRecursive2(dir);
|
|
8530
8774
|
if (mdPath) {
|
|
8531
|
-
content =
|
|
8532
|
-
const parsed =
|
|
8775
|
+
content = fs17.readFileSync(mdPath, "utf-8");
|
|
8776
|
+
const parsed = parseSkillMd3(content);
|
|
8533
8777
|
if (parsed?.metadata && !metadata) {
|
|
8534
8778
|
metadata = parsed.metadata;
|
|
8535
8779
|
}
|
|
@@ -8544,7 +8788,7 @@ async function skillsRoutes(app) {
|
|
|
8544
8788
|
const skillFile = localFiles.find((f) => /skill\.md/i.test(f.name));
|
|
8545
8789
|
if (skillFile?.content) {
|
|
8546
8790
|
content = skillFile.content;
|
|
8547
|
-
const parsed =
|
|
8791
|
+
const parsed = parseSkillMd3(content);
|
|
8548
8792
|
if (parsed?.metadata && !metadata) {
|
|
8549
8793
|
metadata = parsed.metadata;
|
|
8550
8794
|
}
|
|
@@ -8559,7 +8803,7 @@ async function skillsRoutes(app) {
|
|
|
8559
8803
|
const skillFile = freshFiles.find((f) => /skill\.md/i.test(f.name));
|
|
8560
8804
|
if (skillFile?.content) {
|
|
8561
8805
|
content = skillFile.content;
|
|
8562
|
-
const parsed =
|
|
8806
|
+
const parsed = parseSkillMd3(content);
|
|
8563
8807
|
if (parsed?.metadata && !metadata) {
|
|
8564
8808
|
metadata = parsed.metadata;
|
|
8565
8809
|
}
|
|
@@ -8713,10 +8957,10 @@ async function skillsRoutes(app) {
|
|
|
8713
8957
|
return reply.code(500).send({ error: "Skills directory not configured" });
|
|
8714
8958
|
}
|
|
8715
8959
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
8716
|
-
const binDir =
|
|
8960
|
+
const binDir = path17.join(agentHome, "bin");
|
|
8717
8961
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
8718
|
-
const skillDir =
|
|
8719
|
-
const isInstalled =
|
|
8962
|
+
const skillDir = path17.join(skillsDir2, name);
|
|
8963
|
+
const isInstalled = fs17.existsSync(skillDir);
|
|
8720
8964
|
if (isInstalled) {
|
|
8721
8965
|
try {
|
|
8722
8966
|
const brokerAvailable = await isBrokerAvailable();
|
|
@@ -8726,7 +8970,7 @@ async function skillsRoutes(app) {
|
|
|
8726
8970
|
agentHome
|
|
8727
8971
|
});
|
|
8728
8972
|
} else {
|
|
8729
|
-
|
|
8973
|
+
fs17.rmSync(skillDir, { recursive: true, force: true });
|
|
8730
8974
|
removeSkillWrapper(name, binDir);
|
|
8731
8975
|
}
|
|
8732
8976
|
removeSkillEntry(name);
|
|
@@ -8771,11 +9015,11 @@ async function skillsRoutes(app) {
|
|
|
8771
9015
|
}
|
|
8772
9016
|
}
|
|
8773
9017
|
} else {
|
|
8774
|
-
|
|
9018
|
+
fs17.mkdirSync(skillDir, { recursive: true });
|
|
8775
9019
|
for (const file of files) {
|
|
8776
|
-
const filePath =
|
|
8777
|
-
|
|
8778
|
-
|
|
9020
|
+
const filePath = path17.join(skillDir, file.name);
|
|
9021
|
+
fs17.mkdirSync(path17.dirname(filePath), { recursive: true });
|
|
9022
|
+
fs17.writeFileSync(filePath, file.content, "utf-8");
|
|
8779
9023
|
}
|
|
8780
9024
|
try {
|
|
8781
9025
|
execSync9(`chown -R root:${socketGroup} "${skillDir}"`, { stdio: "pipe" });
|
|
@@ -8793,8 +9037,8 @@ async function skillsRoutes(app) {
|
|
|
8793
9037
|
return reply.send({ success: true, action: "enabled", name });
|
|
8794
9038
|
} catch (err) {
|
|
8795
9039
|
try {
|
|
8796
|
-
if (
|
|
8797
|
-
|
|
9040
|
+
if (fs17.existsSync(skillDir)) {
|
|
9041
|
+
fs17.rmSync(skillDir, { recursive: true, force: true });
|
|
8798
9042
|
}
|
|
8799
9043
|
removeFromApprovedList(name);
|
|
8800
9044
|
} catch {
|
|
@@ -8820,7 +9064,7 @@ async function skillsRoutes(app) {
|
|
|
8820
9064
|
const skillMdFile = files.find((f) => f.name === "SKILL.md");
|
|
8821
9065
|
let metadata;
|
|
8822
9066
|
if (skillMdFile) {
|
|
8823
|
-
const parsed =
|
|
9067
|
+
const parsed = parseSkillMd3(skillMdFile.content);
|
|
8824
9068
|
metadata = parsed?.metadata;
|
|
8825
9069
|
}
|
|
8826
9070
|
const analysis = analyzeSkill(name, combinedContent, metadata);
|
|
@@ -8832,16 +9076,18 @@ async function skillsRoutes(app) {
|
|
|
8832
9076
|
return reply.code(500).send({ error: "Skills directory not configured" });
|
|
8833
9077
|
}
|
|
8834
9078
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
8835
|
-
const
|
|
9079
|
+
const agentUsername = path17.basename(agentHome);
|
|
9080
|
+
const binDir = path17.join(agentHome, "bin");
|
|
8836
9081
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
8837
|
-
const skillDir =
|
|
9082
|
+
const skillDir = path17.join(skillsDir2, name);
|
|
8838
9083
|
try {
|
|
8839
9084
|
addToApprovedList(name, publisher);
|
|
8840
|
-
|
|
9085
|
+
sudoMkdir(skillDir, agentUsername);
|
|
8841
9086
|
for (const file of files) {
|
|
8842
|
-
const filePath =
|
|
8843
|
-
|
|
8844
|
-
|
|
9087
|
+
const filePath = path17.join(skillDir, file.name);
|
|
9088
|
+
sudoMkdir(path17.dirname(filePath), agentUsername);
|
|
9089
|
+
const content = /SKILL\.md$/i.test(file.name) ? stripEnvFromSkillMd2(file.content) : file.content;
|
|
9090
|
+
sudoWriteFile(filePath, content, agentUsername);
|
|
8845
9091
|
}
|
|
8846
9092
|
try {
|
|
8847
9093
|
execSync9(`chown -R root:${socketGroup} "${skillDir}"`, { stdio: "pipe" });
|
|
@@ -8855,8 +9101,8 @@ async function skillsRoutes(app) {
|
|
|
8855
9101
|
return reply.send({ success: true, name, analysis });
|
|
8856
9102
|
} catch (err) {
|
|
8857
9103
|
try {
|
|
8858
|
-
if (
|
|
8859
|
-
|
|
9104
|
+
if (fs17.existsSync(skillDir)) {
|
|
9105
|
+
fs17.rmSync(skillDir, { recursive: true, force: true });
|
|
8860
9106
|
}
|
|
8861
9107
|
removeFromApprovedList(name);
|
|
8862
9108
|
} catch {
|
|
@@ -8890,9 +9136,9 @@ async function skillsRoutes(app) {
|
|
|
8890
9136
|
}
|
|
8891
9137
|
try {
|
|
8892
9138
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
8893
|
-
const binDir =
|
|
9139
|
+
const binDir = path17.join(agentHome, "bin");
|
|
8894
9140
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
8895
|
-
const skillDir =
|
|
9141
|
+
const skillDir = path17.join(getSkillsDir(), name);
|
|
8896
9142
|
addToApprovedList(name, meta.author);
|
|
8897
9143
|
const brokerAvailable = await isBrokerAvailable();
|
|
8898
9144
|
if (brokerAvailable) {
|
|
@@ -8910,11 +9156,11 @@ async function skillsRoutes(app) {
|
|
|
8910
9156
|
}
|
|
8911
9157
|
}
|
|
8912
9158
|
} else {
|
|
8913
|
-
|
|
9159
|
+
fs17.mkdirSync(skillDir, { recursive: true });
|
|
8914
9160
|
for (const file of files) {
|
|
8915
|
-
const filePath =
|
|
8916
|
-
|
|
8917
|
-
|
|
9161
|
+
const filePath = path17.join(skillDir, file.name);
|
|
9162
|
+
fs17.mkdirSync(path17.dirname(filePath), { recursive: true });
|
|
9163
|
+
fs17.writeFileSync(filePath, file.content, "utf-8");
|
|
8918
9164
|
}
|
|
8919
9165
|
try {
|
|
8920
9166
|
execSync9(`chown -R root:${socketGroup} "${skillDir}"`, { stdio: "pipe" });
|
|
@@ -8926,7 +9172,7 @@ async function skillsRoutes(app) {
|
|
|
8926
9172
|
addSkillEntry(name);
|
|
8927
9173
|
addSkillPolicy(name);
|
|
8928
9174
|
syncOpenClawFromPolicies(loadConfig().policies);
|
|
8929
|
-
const unblockHash = computeSkillHash(
|
|
9175
|
+
const unblockHash = computeSkillHash(path17.join(getSkillsDir(), name));
|
|
8930
9176
|
if (unblockHash) updateApprovedHash(name, unblockHash);
|
|
8931
9177
|
console.log(`[Skills] Unblocked and installed skill: ${name}`);
|
|
8932
9178
|
return reply.send({ success: true, message: `Skill "${name}" approved and installed` });
|
|
@@ -8957,7 +9203,7 @@ async function skillsRoutes(app) {
|
|
|
8957
9203
|
const skillMdFile = files.find((f) => /skill\.md/i.test(f.name));
|
|
8958
9204
|
if (skillMdFile) {
|
|
8959
9205
|
try {
|
|
8960
|
-
const parsed =
|
|
9206
|
+
const parsed = parseSkillMd3(skillMdFile.content);
|
|
8961
9207
|
if (parsed?.metadata) {
|
|
8962
9208
|
parsedDescription = parsedDescription || parsed.metadata.description;
|
|
8963
9209
|
parsedVersion = parsedVersion || parsed.metadata.version;
|
|
@@ -8986,10 +9232,10 @@ async function skillsRoutes(app) {
|
|
|
8986
9232
|
|
|
8987
9233
|
// libs/shield-daemon/src/routes/exec.ts
|
|
8988
9234
|
init_paths();
|
|
8989
|
-
import * as
|
|
8990
|
-
import * as
|
|
9235
|
+
import * as fs18 from "node:fs";
|
|
9236
|
+
import * as path18 from "node:path";
|
|
8991
9237
|
function getAllowedCommandsPath2() {
|
|
8992
|
-
return
|
|
9238
|
+
return path18.join(getSystemConfigDir(), "allowed-commands.json");
|
|
8993
9239
|
}
|
|
8994
9240
|
var BIN_DIRS = [
|
|
8995
9241
|
"/usr/bin",
|
|
@@ -9002,22 +9248,22 @@ var binCache = null;
|
|
|
9002
9248
|
var BIN_CACHE_TTL = 6e4;
|
|
9003
9249
|
var VALID_NAME = /^[a-zA-Z0-9_-]+$/;
|
|
9004
9250
|
function loadConfig2() {
|
|
9005
|
-
if (!
|
|
9251
|
+
if (!fs18.existsSync(getAllowedCommandsPath2())) {
|
|
9006
9252
|
return { version: "1.0.0", commands: [] };
|
|
9007
9253
|
}
|
|
9008
9254
|
try {
|
|
9009
|
-
const content =
|
|
9255
|
+
const content = fs18.readFileSync(getAllowedCommandsPath2(), "utf-8");
|
|
9010
9256
|
return JSON.parse(content);
|
|
9011
9257
|
} catch {
|
|
9012
9258
|
return { version: "1.0.0", commands: [] };
|
|
9013
9259
|
}
|
|
9014
9260
|
}
|
|
9015
9261
|
function saveConfig2(config) {
|
|
9016
|
-
const dir =
|
|
9017
|
-
if (!
|
|
9018
|
-
|
|
9262
|
+
const dir = path18.dirname(getAllowedCommandsPath2());
|
|
9263
|
+
if (!fs18.existsSync(dir)) {
|
|
9264
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
9019
9265
|
}
|
|
9020
|
-
|
|
9266
|
+
fs18.writeFileSync(getAllowedCommandsPath2(), JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
9021
9267
|
}
|
|
9022
9268
|
function scanSystemBins() {
|
|
9023
9269
|
const pathDirs = (process.env.PATH ?? "").split(":").filter(Boolean);
|
|
@@ -9026,13 +9272,13 @@ function scanSystemBins() {
|
|
|
9026
9272
|
const results = [];
|
|
9027
9273
|
for (const dir of allDirs) {
|
|
9028
9274
|
try {
|
|
9029
|
-
if (!
|
|
9030
|
-
const entries =
|
|
9275
|
+
if (!fs18.existsSync(dir)) continue;
|
|
9276
|
+
const entries = fs18.readdirSync(dir);
|
|
9031
9277
|
for (const entry of entries) {
|
|
9032
9278
|
if (seen.has(entry)) continue;
|
|
9033
|
-
const fullPath =
|
|
9279
|
+
const fullPath = path18.join(dir, entry);
|
|
9034
9280
|
try {
|
|
9035
|
-
const stat =
|
|
9281
|
+
const stat = fs18.statSync(fullPath);
|
|
9036
9282
|
if (stat.isFile() && (stat.mode & 73) !== 0) {
|
|
9037
9283
|
seen.add(entry);
|
|
9038
9284
|
results.push({ name: entry, path: fullPath });
|
|
@@ -9085,7 +9331,7 @@ async function execRoutes(app) {
|
|
|
9085
9331
|
};
|
|
9086
9332
|
}
|
|
9087
9333
|
for (const p of paths) {
|
|
9088
|
-
if (!
|
|
9334
|
+
if (!path18.isAbsolute(p)) {
|
|
9089
9335
|
return {
|
|
9090
9336
|
success: false,
|
|
9091
9337
|
error: {
|
|
@@ -9581,18 +9827,18 @@ async function secretsRoutes(app) {
|
|
|
9581
9827
|
}
|
|
9582
9828
|
|
|
9583
9829
|
// libs/shield-daemon/src/routes/fs.ts
|
|
9584
|
-
import * as
|
|
9585
|
-
import * as
|
|
9830
|
+
import * as fs19 from "node:fs";
|
|
9831
|
+
import * as path19 from "node:path";
|
|
9586
9832
|
import * as os6 from "node:os";
|
|
9587
9833
|
var MAX_ENTRIES = 200;
|
|
9588
9834
|
async function fsRoutes(app) {
|
|
9589
9835
|
app.get("/fs/browse", async (request2) => {
|
|
9590
9836
|
const dirPath = request2.query.path || os6.homedir();
|
|
9591
9837
|
const showHidden = request2.query.showHidden === "true";
|
|
9592
|
-
const resolvedPath =
|
|
9838
|
+
const resolvedPath = path19.resolve(dirPath);
|
|
9593
9839
|
let dirents;
|
|
9594
9840
|
try {
|
|
9595
|
-
dirents =
|
|
9841
|
+
dirents = fs19.readdirSync(resolvedPath, { withFileTypes: true });
|
|
9596
9842
|
} catch {
|
|
9597
9843
|
return { success: true, data: { entries: [] } };
|
|
9598
9844
|
}
|
|
@@ -9601,7 +9847,7 @@ async function fsRoutes(app) {
|
|
|
9601
9847
|
if (!showHidden && dirent.name.startsWith(".")) continue;
|
|
9602
9848
|
entries.push({
|
|
9603
9849
|
name: dirent.name,
|
|
9604
|
-
path:
|
|
9850
|
+
path: path19.join(resolvedPath, dirent.name),
|
|
9605
9851
|
type: dirent.isDirectory() ? "directory" : "file"
|
|
9606
9852
|
});
|
|
9607
9853
|
if (entries.length >= MAX_ENTRIES) break;
|
|
@@ -9615,8 +9861,8 @@ async function fsRoutes(app) {
|
|
|
9615
9861
|
}
|
|
9616
9862
|
|
|
9617
9863
|
// libs/shield-daemon/src/services/activity-log.ts
|
|
9618
|
-
import * as
|
|
9619
|
-
import * as
|
|
9864
|
+
import * as fs20 from "node:fs";
|
|
9865
|
+
import * as path20 from "node:path";
|
|
9620
9866
|
init_paths();
|
|
9621
9867
|
var ACTIVITY_FILE = "activity.jsonl";
|
|
9622
9868
|
var MAX_SIZE_BYTES = 100 * 1024 * 1024;
|
|
@@ -9634,12 +9880,12 @@ var ActivityLog = class {
|
|
|
9634
9880
|
writeCount = 0;
|
|
9635
9881
|
unsubscribe;
|
|
9636
9882
|
constructor() {
|
|
9637
|
-
this.filePath =
|
|
9883
|
+
this.filePath = path20.join(getConfigDir(), ACTIVITY_FILE);
|
|
9638
9884
|
}
|
|
9639
9885
|
/** Read historical events from the JSONL file, newest first */
|
|
9640
9886
|
getHistory(limit = 500) {
|
|
9641
|
-
if (!
|
|
9642
|
-
const content =
|
|
9887
|
+
if (!fs20.existsSync(this.filePath)) return [];
|
|
9888
|
+
const content = fs20.readFileSync(this.filePath, "utf-8");
|
|
9643
9889
|
const lines = content.split("\n").filter(Boolean);
|
|
9644
9890
|
const events = [];
|
|
9645
9891
|
for (const line of lines) {
|
|
@@ -9664,7 +9910,7 @@ var ActivityLog = class {
|
|
|
9664
9910
|
}
|
|
9665
9911
|
append(event) {
|
|
9666
9912
|
const line = JSON.stringify(event) + "\n";
|
|
9667
|
-
|
|
9913
|
+
fs20.appendFileSync(this.filePath, line, "utf-8");
|
|
9668
9914
|
this.writeCount++;
|
|
9669
9915
|
if (this.writeCount % PRUNE_INTERVAL === 0) {
|
|
9670
9916
|
this.rotate();
|
|
@@ -9672,7 +9918,7 @@ var ActivityLog = class {
|
|
|
9672
9918
|
}
|
|
9673
9919
|
rotate() {
|
|
9674
9920
|
try {
|
|
9675
|
-
const stat =
|
|
9921
|
+
const stat = fs20.statSync(this.filePath);
|
|
9676
9922
|
if (stat.size > MAX_SIZE_BYTES) {
|
|
9677
9923
|
this.truncateBySize();
|
|
9678
9924
|
}
|
|
@@ -9682,15 +9928,15 @@ var ActivityLog = class {
|
|
|
9682
9928
|
}
|
|
9683
9929
|
/** Keep newest half of lines when file exceeds size limit */
|
|
9684
9930
|
truncateBySize() {
|
|
9685
|
-
const content =
|
|
9931
|
+
const content = fs20.readFileSync(this.filePath, "utf-8");
|
|
9686
9932
|
const lines = content.split("\n").filter(Boolean);
|
|
9687
9933
|
const keep = lines.slice(Math.floor(lines.length / 2));
|
|
9688
|
-
|
|
9934
|
+
fs20.writeFileSync(this.filePath, keep.join("\n") + "\n", "utf-8");
|
|
9689
9935
|
}
|
|
9690
9936
|
/** Remove entries older than 24 hours */
|
|
9691
9937
|
pruneOldEntries() {
|
|
9692
|
-
if (!
|
|
9693
|
-
const content =
|
|
9938
|
+
if (!fs20.existsSync(this.filePath)) return;
|
|
9939
|
+
const content = fs20.readFileSync(this.filePath, "utf-8");
|
|
9694
9940
|
const lines = content.split("\n").filter(Boolean);
|
|
9695
9941
|
const cutoff = Date.now() - MAX_AGE_MS;
|
|
9696
9942
|
const kept = lines.filter((line) => {
|
|
@@ -9702,7 +9948,7 @@ var ActivityLog = class {
|
|
|
9702
9948
|
}
|
|
9703
9949
|
});
|
|
9704
9950
|
if (kept.length < lines.length) {
|
|
9705
|
-
|
|
9951
|
+
fs20.writeFileSync(this.filePath, kept.join("\n") + "\n", "utf-8");
|
|
9706
9952
|
}
|
|
9707
9953
|
}
|
|
9708
9954
|
};
|
|
@@ -9843,11 +10089,11 @@ function normalizeUrlTarget(url) {
|
|
|
9843
10089
|
const trimmed = url.trim();
|
|
9844
10090
|
try {
|
|
9845
10091
|
const parsed = new URL(trimmed);
|
|
9846
|
-
let
|
|
9847
|
-
if (
|
|
9848
|
-
|
|
10092
|
+
let path24 = parsed.pathname;
|
|
10093
|
+
if (path24.length > 1) {
|
|
10094
|
+
path24 = path24.replace(/\/+$/, "");
|
|
9849
10095
|
}
|
|
9850
|
-
return `${parsed.protocol}//${parsed.host}${
|
|
10096
|
+
return `${parsed.protocol}//${parsed.host}${path24}${parsed.search}`;
|
|
9851
10097
|
} catch {
|
|
9852
10098
|
return trimmed.replace(/\/+$/, "");
|
|
9853
10099
|
}
|
|
@@ -10133,8 +10379,8 @@ function matchCommandPattern(pattern, target) {
|
|
|
10133
10379
|
const firstSpace = target.indexOf(" ");
|
|
10134
10380
|
const cmd = firstSpace >= 0 ? target.slice(0, firstSpace) : target;
|
|
10135
10381
|
if (cmd.startsWith("/")) {
|
|
10136
|
-
const
|
|
10137
|
-
normalizedTarget = firstSpace >= 0 ?
|
|
10382
|
+
const basename6 = cmd.split("/").pop() || cmd;
|
|
10383
|
+
normalizedTarget = firstSpace >= 0 ? basename6 + target.slice(firstSpace) : basename6;
|
|
10138
10384
|
}
|
|
10139
10385
|
if (trimmed.endsWith(":*")) {
|
|
10140
10386
|
const prefix = trimmed.slice(0, -2);
|
|
@@ -10185,8 +10431,8 @@ function determineNetworkAccess(_config, matchedPolicy, target) {
|
|
|
10185
10431
|
if (matchedPolicy?.networkAccess) return matchedPolicy.networkAccess;
|
|
10186
10432
|
const cleanTarget = target.startsWith("fork:") ? target.slice(5) : target;
|
|
10187
10433
|
const cmdPart = cleanTarget.split(" ")[0] || "";
|
|
10188
|
-
const
|
|
10189
|
-
if (!NETWORK_COMMANDS.has(
|
|
10434
|
+
const basename6 = cmdPart.includes("/") ? cmdPart.split("/").pop() : cmdPart;
|
|
10435
|
+
if (!NETWORK_COMMANDS.has(basename6.toLowerCase())) return "none";
|
|
10190
10436
|
return "proxy";
|
|
10191
10437
|
}
|
|
10192
10438
|
async function buildSandboxConfig(config, matchedPolicy, _context, target) {
|
|
@@ -10487,22 +10733,22 @@ async function registerRoutes(app) {
|
|
|
10487
10733
|
}
|
|
10488
10734
|
|
|
10489
10735
|
// libs/shield-daemon/src/static.ts
|
|
10490
|
-
import * as
|
|
10491
|
-
import * as
|
|
10736
|
+
import * as fs21 from "node:fs";
|
|
10737
|
+
import * as path21 from "node:path";
|
|
10492
10738
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
10493
10739
|
var __filename = fileURLToPath2(import.meta.url);
|
|
10494
|
-
var __dirname =
|
|
10740
|
+
var __dirname = path21.dirname(__filename);
|
|
10495
10741
|
function getUiAssetsPath() {
|
|
10496
|
-
const pkgRootPath =
|
|
10497
|
-
if (
|
|
10742
|
+
const pkgRootPath = path21.join(__dirname, "..", "ui-assets");
|
|
10743
|
+
if (fs21.existsSync(pkgRootPath)) {
|
|
10498
10744
|
return pkgRootPath;
|
|
10499
10745
|
}
|
|
10500
|
-
const bundledPath =
|
|
10501
|
-
if (
|
|
10746
|
+
const bundledPath = path21.join(__dirname, "ui-assets");
|
|
10747
|
+
if (fs21.existsSync(bundledPath)) {
|
|
10502
10748
|
return bundledPath;
|
|
10503
10749
|
}
|
|
10504
|
-
const devPath =
|
|
10505
|
-
if (
|
|
10750
|
+
const devPath = path21.join(__dirname, "..", "..", "..", "dist", "apps", "shield-ui");
|
|
10751
|
+
if (fs21.existsSync(devPath)) {
|
|
10506
10752
|
return devPath;
|
|
10507
10753
|
}
|
|
10508
10754
|
return null;
|
|
@@ -10592,8 +10838,8 @@ async function startServer(config) {
|
|
|
10592
10838
|
startSecurityWatcher(1e4);
|
|
10593
10839
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
10594
10840
|
const skillsDir2 = `${agentHome}/.openclaw/skills`;
|
|
10595
|
-
if (!
|
|
10596
|
-
|
|
10841
|
+
if (!fs23.existsSync(skillsDir2)) {
|
|
10842
|
+
fs23.mkdirSync(skillsDir2, { recursive: true, mode: 493 });
|
|
10597
10843
|
console.log(`[Daemon] Created skills directory: ${skillsDir2}`);
|
|
10598
10844
|
}
|
|
10599
10845
|
startSkillsWatcher(skillsDir2, {
|