@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/main.js
CHANGED
|
@@ -1044,10 +1044,7 @@ PLISTEOF`);
|
|
|
1044
1044
|
}
|
|
1045
1045
|
async function startOpenClawServices() {
|
|
1046
1046
|
try {
|
|
1047
|
-
|
|
1048
|
-
await execAsync3(`sudo launchctl kickstart system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1049
|
-
} catch {
|
|
1050
|
-
}
|
|
1047
|
+
await execAsync3(`sudo launchctl kickstart system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1051
1048
|
return {
|
|
1052
1049
|
success: true,
|
|
1053
1050
|
message: "OpenClaw gateway started"
|
|
@@ -1062,10 +1059,7 @@ async function startOpenClawServices() {
|
|
|
1062
1059
|
}
|
|
1063
1060
|
async function stopOpenClawServices() {
|
|
1064
1061
|
try {
|
|
1065
|
-
|
|
1066
|
-
await execAsync3(`sudo launchctl kill SIGTERM system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1067
|
-
} catch {
|
|
1068
|
-
}
|
|
1062
|
+
await execAsync3(`sudo launchctl kill SIGTERM system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1069
1063
|
return {
|
|
1070
1064
|
success: true,
|
|
1071
1065
|
message: "OpenClaw gateway stopped"
|
|
@@ -1080,10 +1074,7 @@ async function stopOpenClawServices() {
|
|
|
1080
1074
|
}
|
|
1081
1075
|
async function restartOpenClawServices() {
|
|
1082
1076
|
try {
|
|
1083
|
-
|
|
1084
|
-
await execAsync3(`sudo launchctl kickstart -k system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1085
|
-
} catch {
|
|
1086
|
-
}
|
|
1077
|
+
await execAsync3(`sudo launchctl kickstart -k system/${OPENCLAW_GATEWAY_LABEL}`);
|
|
1087
1078
|
return {
|
|
1088
1079
|
success: true,
|
|
1089
1080
|
message: "OpenClaw gateway restarted"
|
|
@@ -1166,15 +1157,29 @@ function getOpenClawStatusSync() {
|
|
|
1166
1157
|
async function getOpenClawDashboardUrl() {
|
|
1167
1158
|
try {
|
|
1168
1159
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
1169
|
-
const
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
)
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1160
|
+
const configPath = path22.join(agentHome, ".openclaw", "openclaw.json");
|
|
1161
|
+
let raw;
|
|
1162
|
+
try {
|
|
1163
|
+
raw = await fs32.readFile(configPath, "utf-8");
|
|
1164
|
+
} catch (err) {
|
|
1165
|
+
if (err.code === "EACCES") {
|
|
1166
|
+
const agentUsername = path22.basename(agentHome);
|
|
1167
|
+
const { stdout } = await execAsync3(
|
|
1168
|
+
`sudo -H -u ${agentUsername} cat "${configPath}"`,
|
|
1169
|
+
{ cwd: "/" }
|
|
1170
|
+
);
|
|
1171
|
+
raw = stdout;
|
|
1172
|
+
} else {
|
|
1173
|
+
return { success: false, error: `Cannot read openclaw.json: ${err.message}` };
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
const config = JSON.parse(raw);
|
|
1177
|
+
const port = config.gateway?.port;
|
|
1178
|
+
const token = config.gateway?.auth?.token;
|
|
1179
|
+
if (!port || !token) {
|
|
1180
|
+
return { success: false, error: "Gateway port or auth token not found in openclaw.json" };
|
|
1177
1181
|
}
|
|
1182
|
+
const url = `http://127.0.0.1:${port}/?token=${token}`;
|
|
1178
1183
|
return { success: true, url };
|
|
1179
1184
|
} catch (error) {
|
|
1180
1185
|
return { success: false, error: `Failed to get dashboard URL: ${error.message}` };
|
|
@@ -1761,7 +1766,7 @@ var init_secret_sync = __esm({
|
|
|
1761
1766
|
});
|
|
1762
1767
|
|
|
1763
1768
|
// libs/shield-daemon/src/main.ts
|
|
1764
|
-
import * as
|
|
1769
|
+
import * as fs24 from "node:fs";
|
|
1765
1770
|
|
|
1766
1771
|
// libs/shield-daemon/src/config/index.ts
|
|
1767
1772
|
init_paths();
|
|
@@ -1769,7 +1774,7 @@ init_defaults();
|
|
|
1769
1774
|
init_loader();
|
|
1770
1775
|
|
|
1771
1776
|
// libs/shield-daemon/src/server.ts
|
|
1772
|
-
import * as
|
|
1777
|
+
import * as fs23 from "node:fs";
|
|
1773
1778
|
import Fastify from "fastify";
|
|
1774
1779
|
import cors from "@fastify/cors";
|
|
1775
1780
|
import fastifyStatic from "@fastify/static";
|
|
@@ -2141,11 +2146,24 @@ function getOpenClawConfigPath() {
|
|
|
2141
2146
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
2142
2147
|
return path8.join(agentHome, ".openclaw", "openclaw.json");
|
|
2143
2148
|
}
|
|
2144
|
-
function
|
|
2149
|
+
function readOpenClawConfig() {
|
|
2145
2150
|
const configPath = getOpenClawConfigPath();
|
|
2146
2151
|
try {
|
|
2147
2152
|
if (fs8.existsSync(configPath)) {
|
|
2148
|
-
|
|
2153
|
+
try {
|
|
2154
|
+
return JSON.parse(fs8.readFileSync(configPath, "utf-8"));
|
|
2155
|
+
} catch (err) {
|
|
2156
|
+
if (err.code === "EACCES") {
|
|
2157
|
+
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
2158
|
+
const agentUsername = path8.basename(agentHome);
|
|
2159
|
+
const raw = execSync6(
|
|
2160
|
+
`sudo -H -u ${agentUsername} cat "${configPath}"`,
|
|
2161
|
+
{ encoding: "utf-8", cwd: "/", stdio: ["pipe", "pipe", "pipe"] }
|
|
2162
|
+
);
|
|
2163
|
+
return JSON.parse(raw);
|
|
2164
|
+
}
|
|
2165
|
+
throw err;
|
|
2166
|
+
}
|
|
2149
2167
|
}
|
|
2150
2168
|
} catch {
|
|
2151
2169
|
console.warn("[OpenClawConfig] Failed to read openclaw.json, starting fresh");
|
|
@@ -2163,7 +2181,7 @@ function writeConfig(config) {
|
|
|
2163
2181
|
const agentUsername = path8.basename(agentHome);
|
|
2164
2182
|
execSync6(
|
|
2165
2183
|
`sudo -H -u ${agentUsername} tee "${configPath}" > /dev/null`,
|
|
2166
|
-
{ input: JSON.stringify(config, null, 2), stdio: ["pipe", "pipe", "pipe"] }
|
|
2184
|
+
{ input: JSON.stringify(config, null, 2), stdio: ["pipe", "pipe", "pipe"], cwd: "/" }
|
|
2167
2185
|
);
|
|
2168
2186
|
} else {
|
|
2169
2187
|
throw err;
|
|
@@ -2171,27 +2189,30 @@ function writeConfig(config) {
|
|
|
2171
2189
|
}
|
|
2172
2190
|
}
|
|
2173
2191
|
function addSkillEntry(slug) {
|
|
2174
|
-
const config =
|
|
2192
|
+
const config = readOpenClawConfig();
|
|
2175
2193
|
if (!config.skills) {
|
|
2176
2194
|
config.skills = {};
|
|
2177
2195
|
}
|
|
2178
2196
|
if (!config.skills.entries) {
|
|
2179
2197
|
config.skills.entries = {};
|
|
2180
2198
|
}
|
|
2181
|
-
config.skills.entries[slug]
|
|
2199
|
+
const existing = config.skills.entries[slug] ?? {};
|
|
2200
|
+
config.skills.entries[slug] = { ...existing, enabled: true };
|
|
2182
2201
|
writeConfig(config);
|
|
2183
2202
|
console.log(`[OpenClawConfig] Added skill entry: ${slug}`);
|
|
2184
2203
|
}
|
|
2185
2204
|
function removeSkillEntry(slug) {
|
|
2186
|
-
const config =
|
|
2205
|
+
const config = readOpenClawConfig();
|
|
2187
2206
|
if (config.skills?.entries?.[slug]) {
|
|
2188
|
-
|
|
2207
|
+
const existing = config.skills.entries[slug];
|
|
2208
|
+
delete existing.env;
|
|
2209
|
+
config.skills.entries[slug] = { ...existing, enabled: false };
|
|
2189
2210
|
writeConfig(config);
|
|
2190
|
-
console.log(`[OpenClawConfig]
|
|
2211
|
+
console.log(`[OpenClawConfig] Disabled skill entry: ${slug}`);
|
|
2191
2212
|
}
|
|
2192
2213
|
}
|
|
2193
2214
|
function syncOpenClawFromPolicies(policies) {
|
|
2194
|
-
const config =
|
|
2215
|
+
const config = readOpenClawConfig();
|
|
2195
2216
|
if (!config.skills) config.skills = {};
|
|
2196
2217
|
const allowBundled = [];
|
|
2197
2218
|
for (const p of policies) {
|
|
@@ -2439,35 +2460,35 @@ var ANALYSIS_TIMEOUT = 4 * 6e4;
|
|
|
2439
2460
|
var SEARCH_CACHE_TTL = 6e4;
|
|
2440
2461
|
var DETAIL_CACHE_TTL = 5 * 6e4;
|
|
2441
2462
|
var SHORT_TIMEOUT = 1e4;
|
|
2442
|
-
async function convexAction(
|
|
2463
|
+
async function convexAction(path24, args, timeout) {
|
|
2443
2464
|
const res = await fetch(`${CONVEX_BASE}/api/action`, {
|
|
2444
2465
|
method: "POST",
|
|
2445
2466
|
signal: AbortSignal.timeout(timeout),
|
|
2446
2467
|
headers: { "Content-Type": "application/json" },
|
|
2447
|
-
body: JSON.stringify({ path:
|
|
2468
|
+
body: JSON.stringify({ path: path24, args, format: "json" })
|
|
2448
2469
|
});
|
|
2449
2470
|
if (!res.ok) {
|
|
2450
|
-
throw new Error(`Convex action ${
|
|
2471
|
+
throw new Error(`Convex action ${path24} returned ${res.status}`);
|
|
2451
2472
|
}
|
|
2452
2473
|
const body = await res.json();
|
|
2453
2474
|
if (body.status === "error") {
|
|
2454
|
-
throw new Error(`Convex action ${
|
|
2475
|
+
throw new Error(`Convex action ${path24}: ${body.errorMessage ?? "unknown error"}`);
|
|
2455
2476
|
}
|
|
2456
2477
|
return body.value;
|
|
2457
2478
|
}
|
|
2458
|
-
async function convexQuery(
|
|
2479
|
+
async function convexQuery(path24, args, timeout) {
|
|
2459
2480
|
const res = await fetch(`${CONVEX_BASE}/api/query`, {
|
|
2460
2481
|
method: "POST",
|
|
2461
2482
|
signal: AbortSignal.timeout(timeout),
|
|
2462
2483
|
headers: { "Content-Type": "application/json" },
|
|
2463
|
-
body: JSON.stringify({ path:
|
|
2484
|
+
body: JSON.stringify({ path: path24, args, format: "json" })
|
|
2464
2485
|
});
|
|
2465
2486
|
if (!res.ok) {
|
|
2466
|
-
throw new Error(`Convex query ${
|
|
2487
|
+
throw new Error(`Convex query ${path24} returned ${res.status}`);
|
|
2467
2488
|
}
|
|
2468
2489
|
const body = await res.json();
|
|
2469
2490
|
if (body.status === "error") {
|
|
2470
|
-
throw new Error(`Convex query ${
|
|
2491
|
+
throw new Error(`Convex query ${path24}: ${body.errorMessage ?? "unknown error"}`);
|
|
2471
2492
|
}
|
|
2472
2493
|
return body.value;
|
|
2473
2494
|
}
|
|
@@ -2669,9 +2690,9 @@ function inlineImagesInMarkdown(markdown, files) {
|
|
|
2669
2690
|
const mime = isImageExt(file.name);
|
|
2670
2691
|
if (mime && file.content.startsWith("data:")) {
|
|
2671
2692
|
imageMap.set(file.name, file.content);
|
|
2672
|
-
const
|
|
2673
|
-
if (
|
|
2674
|
-
imageMap.set(
|
|
2693
|
+
const basename6 = file.name.split("/").pop() ?? "";
|
|
2694
|
+
if (basename6 && !imageMap.has(basename6)) {
|
|
2695
|
+
imageMap.set(basename6, file.content);
|
|
2675
2696
|
}
|
|
2676
2697
|
}
|
|
2677
2698
|
}
|
|
@@ -3197,10 +3218,10 @@ function emitSecurityWarning(warning) {
|
|
|
3197
3218
|
function emitSecurityCritical(issue) {
|
|
3198
3219
|
daemonEvents.broadcast("security:critical", { message: issue });
|
|
3199
3220
|
}
|
|
3200
|
-
function emitApiRequest(method,
|
|
3221
|
+
function emitApiRequest(method, path24, statusCode, duration, requestBody, responseBody) {
|
|
3201
3222
|
daemonEvents.broadcast("api:request", {
|
|
3202
3223
|
method,
|
|
3203
|
-
path:
|
|
3224
|
+
path: path24,
|
|
3204
3225
|
statusCode,
|
|
3205
3226
|
duration,
|
|
3206
3227
|
...requestBody !== void 0 && { requestBody },
|
|
@@ -3455,26 +3476,16 @@ function scanSkills() {
|
|
|
3455
3476
|
}
|
|
3456
3477
|
function detectOpenClawMismatches() {
|
|
3457
3478
|
try {
|
|
3458
|
-
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
3459
|
-
const configPath = path11.join(agentHome, ".openclaw", "openclaw.json");
|
|
3460
|
-
if (!fs11.existsSync(configPath)) return;
|
|
3461
|
-
const raw = fs11.readFileSync(configPath, "utf-8");
|
|
3462
|
-
const config = JSON.parse(raw);
|
|
3463
|
-
if (!config.skills?.entries) return;
|
|
3464
3479
|
const approved = loadApprovedSkills();
|
|
3465
3480
|
const approvedNames = new Set(approved.map((a) => a.name));
|
|
3466
|
-
const
|
|
3467
|
-
|
|
3468
|
-
for (const name of entries) {
|
|
3481
|
+
const config = readOpenClawConfig();
|
|
3482
|
+
if (!config.skills?.entries) return;
|
|
3483
|
+
for (const name of Object.keys(config.skills.entries)) {
|
|
3469
3484
|
if (!approvedNames.has(name)) {
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
console.log(`[SkillsWatcher] Removed stale openclaw.json entry: ${name}`);
|
|
3485
|
+
removeSkillEntry(name);
|
|
3486
|
+
console.log(`[SkillsWatcher] Disabled stale openclaw.json entry: ${name}`);
|
|
3473
3487
|
}
|
|
3474
3488
|
}
|
|
3475
|
-
if (changed) {
|
|
3476
|
-
fs11.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
3477
|
-
}
|
|
3478
3489
|
} catch {
|
|
3479
3490
|
}
|
|
3480
3491
|
}
|
|
@@ -4030,16 +4041,16 @@ var PROTECTED_ROUTES = [
|
|
|
4030
4041
|
{ method: "POST", path: "/api/skills/install" },
|
|
4031
4042
|
{ method: "GET", path: "/api/openclaw/dashboard-url" }
|
|
4032
4043
|
];
|
|
4033
|
-
function isProtectedRoute(method,
|
|
4044
|
+
function isProtectedRoute(method, path24) {
|
|
4034
4045
|
return PROTECTED_ROUTES.some(
|
|
4035
|
-
(route) => route.method === method &&
|
|
4046
|
+
(route) => route.method === method && path24.startsWith(route.path)
|
|
4036
4047
|
);
|
|
4037
4048
|
}
|
|
4038
4049
|
function createAuthHook() {
|
|
4039
4050
|
return async (request2, reply) => {
|
|
4040
4051
|
const method = request2.method;
|
|
4041
|
-
const
|
|
4042
|
-
if (!isProtectedRoute(method,
|
|
4052
|
+
const path24 = request2.url.split("?")[0];
|
|
4053
|
+
if (!isProtectedRoute(method, path24)) {
|
|
4043
4054
|
return;
|
|
4044
4055
|
}
|
|
4045
4056
|
if (!isAuthenticated(request2)) {
|
|
@@ -7538,19 +7549,50 @@ async function agencoRoutes(app) {
|
|
|
7538
7549
|
}
|
|
7539
7550
|
|
|
7540
7551
|
// libs/shield-daemon/src/routes/skills.ts
|
|
7541
|
-
import * as
|
|
7542
|
-
import * as
|
|
7552
|
+
import * as fs17 from "node:fs";
|
|
7553
|
+
import * as path17 from "node:path";
|
|
7543
7554
|
import { execSync as execSync9 } from "node:child_process";
|
|
7544
|
-
import { parseSkillMd as
|
|
7555
|
+
import { parseSkillMd as parseSkillMd3, stripEnvFromSkillMd as stripEnvFromSkillMd2 } from "@agenshield/sandbox";
|
|
7545
7556
|
|
|
7546
7557
|
// libs/shield-daemon/src/services/skill-lifecycle.ts
|
|
7547
7558
|
import * as fs14 from "node:fs";
|
|
7548
7559
|
import * as path14 from "node:path";
|
|
7549
7560
|
import { execSync as execSync8 } from "node:child_process";
|
|
7550
|
-
function
|
|
7551
|
-
|
|
7552
|
-
fs14.mkdirSync(
|
|
7561
|
+
function sudoMkdir(dir, agentUsername) {
|
|
7562
|
+
try {
|
|
7563
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
7564
|
+
} catch (err) {
|
|
7565
|
+
if (err.code === "EACCES") {
|
|
7566
|
+
execSync8(`sudo -H -u ${agentUsername} /bin/mkdir -p "${dir}"`, { cwd: "/", stdio: "pipe" });
|
|
7567
|
+
} else {
|
|
7568
|
+
throw err;
|
|
7569
|
+
}
|
|
7570
|
+
}
|
|
7571
|
+
}
|
|
7572
|
+
function sudoWriteFile(filePath, content, agentUsername, mode) {
|
|
7573
|
+
try {
|
|
7574
|
+
fs14.writeFileSync(filePath, content, { mode });
|
|
7575
|
+
} catch (err) {
|
|
7576
|
+
if (err.code === "EACCES") {
|
|
7577
|
+
execSync8(
|
|
7578
|
+
`sudo -H -u ${agentUsername} tee "${filePath}" > /dev/null`,
|
|
7579
|
+
{ input: content, cwd: "/", stdio: ["pipe", "pipe", "pipe"] }
|
|
7580
|
+
);
|
|
7581
|
+
if (mode) {
|
|
7582
|
+
try {
|
|
7583
|
+
execSync8(`sudo -H -u ${agentUsername} chmod ${mode.toString(8)} "${filePath}"`, { cwd: "/", stdio: "pipe" });
|
|
7584
|
+
} catch {
|
|
7585
|
+
}
|
|
7586
|
+
}
|
|
7587
|
+
} else {
|
|
7588
|
+
throw err;
|
|
7589
|
+
}
|
|
7553
7590
|
}
|
|
7591
|
+
}
|
|
7592
|
+
function createSkillWrapper(name, binDir) {
|
|
7593
|
+
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
7594
|
+
const agentUsername = path14.basename(agentHome);
|
|
7595
|
+
sudoMkdir(binDir, agentUsername);
|
|
7554
7596
|
const wrapperPath = path14.join(binDir, name);
|
|
7555
7597
|
const wrapperContent = `#!/bin/bash
|
|
7556
7598
|
# ${name} skill wrapper - policy-enforced execution
|
|
@@ -7558,7 +7600,7 @@ function createSkillWrapper(name, binDir) {
|
|
|
7558
7600
|
if ! /bin/pwd > /dev/null 2>&1; then cd ~ 2>/dev/null || cd /; fi
|
|
7559
7601
|
exec /opt/agenshield/bin/shield-client skill run "${name}" "$@"
|
|
7560
7602
|
`;
|
|
7561
|
-
|
|
7603
|
+
sudoWriteFile(wrapperPath, wrapperContent, agentUsername, 493);
|
|
7562
7604
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
7563
7605
|
try {
|
|
7564
7606
|
execSync8(`chown root:${socketGroup} "${wrapperPath}"`, { stdio: "pipe" });
|
|
@@ -7603,8 +7645,8 @@ function removeSkillPolicy(name) {
|
|
|
7603
7645
|
}
|
|
7604
7646
|
|
|
7605
7647
|
// libs/shield-daemon/src/routes/marketplace.ts
|
|
7606
|
-
import * as
|
|
7607
|
-
import * as
|
|
7648
|
+
import * as fs16 from "node:fs";
|
|
7649
|
+
import * as path16 from "node:path";
|
|
7608
7650
|
|
|
7609
7651
|
// libs/shield-broker/dist/index.js
|
|
7610
7652
|
import { exec as exec4 } from "node:child_process";
|
|
@@ -7880,6 +7922,175 @@ async function uninstallSkillViaBroker(slug, options = {}) {
|
|
|
7880
7922
|
return result;
|
|
7881
7923
|
}
|
|
7882
7924
|
|
|
7925
|
+
// libs/shield-daemon/src/routes/marketplace.ts
|
|
7926
|
+
import { stripEnvFromSkillMd } from "@agenshield/sandbox";
|
|
7927
|
+
|
|
7928
|
+
// libs/shield-daemon/src/services/skill-deps.ts
|
|
7929
|
+
import * as fs15 from "node:fs";
|
|
7930
|
+
import * as path15 from "node:path";
|
|
7931
|
+
import { parseSkillMd as parseSkillMd2, extractSkillInfo } from "@agenshield/sandbox";
|
|
7932
|
+
import { execWithProgress as execWithProgress3 } from "@agenshield/sandbox";
|
|
7933
|
+
var SUPPORTED_KINDS = /* @__PURE__ */ new Set(["brew", "npm", "pip"]);
|
|
7934
|
+
var SAFE_PACKAGE_RE = /^[a-zA-Z0-9@/_.\-]+$/;
|
|
7935
|
+
function findSkillMdRecursive(dir, depth = 0) {
|
|
7936
|
+
if (depth > 3) return null;
|
|
7937
|
+
try {
|
|
7938
|
+
for (const name of ["SKILL.md", "skill.md", "README.md", "readme.md"]) {
|
|
7939
|
+
const candidate = path15.join(dir, name);
|
|
7940
|
+
if (fs15.existsSync(candidate)) return candidate;
|
|
7941
|
+
}
|
|
7942
|
+
const entries = fs15.readdirSync(dir, { withFileTypes: true });
|
|
7943
|
+
for (const entry of entries) {
|
|
7944
|
+
if (!entry.isDirectory()) continue;
|
|
7945
|
+
const found = findSkillMdRecursive(path15.join(dir, entry.name), depth + 1);
|
|
7946
|
+
if (found) return found;
|
|
7947
|
+
}
|
|
7948
|
+
} catch {
|
|
7949
|
+
}
|
|
7950
|
+
return null;
|
|
7951
|
+
}
|
|
7952
|
+
async function executeSkillInstallSteps(options) {
|
|
7953
|
+
const { slug, skillDir, agentHome, agentUsername, onLog } = options;
|
|
7954
|
+
const installed = [];
|
|
7955
|
+
const errors = [];
|
|
7956
|
+
const skillMdPath = findSkillMdRecursive(skillDir);
|
|
7957
|
+
if (!skillMdPath) {
|
|
7958
|
+
return { success: true, installed, errors };
|
|
7959
|
+
}
|
|
7960
|
+
let content;
|
|
7961
|
+
try {
|
|
7962
|
+
content = fs15.readFileSync(skillMdPath, "utf-8");
|
|
7963
|
+
} catch {
|
|
7964
|
+
return { success: true, installed, errors };
|
|
7965
|
+
}
|
|
7966
|
+
const parsed = parseSkillMd2(content);
|
|
7967
|
+
if (!parsed) {
|
|
7968
|
+
return { success: true, installed, errors };
|
|
7969
|
+
}
|
|
7970
|
+
const info = extractSkillInfo(parsed.metadata);
|
|
7971
|
+
const installSteps = info.installSteps;
|
|
7972
|
+
if (!Array.isArray(installSteps) || installSteps.length === 0) {
|
|
7973
|
+
return { success: true, installed, errors };
|
|
7974
|
+
}
|
|
7975
|
+
onLog(`Found ${installSteps.length} dependency install step(s) for ${slug}`);
|
|
7976
|
+
for (const step of installSteps) {
|
|
7977
|
+
const kind = step.kind;
|
|
7978
|
+
const stepId = step.id || kind;
|
|
7979
|
+
if (!SUPPORTED_KINDS.has(kind)) {
|
|
7980
|
+
errors.push(`Unsupported install kind "${kind}" (step: ${stepId})`);
|
|
7981
|
+
continue;
|
|
7982
|
+
}
|
|
7983
|
+
try {
|
|
7984
|
+
switch (kind) {
|
|
7985
|
+
case "brew": {
|
|
7986
|
+
const formula = step.formula;
|
|
7987
|
+
if (!formula) {
|
|
7988
|
+
errors.push(`Brew step "${stepId}" missing formula`);
|
|
7989
|
+
break;
|
|
7990
|
+
}
|
|
7991
|
+
if (!SAFE_PACKAGE_RE.test(formula)) {
|
|
7992
|
+
errors.push(`Unsafe brew formula name: ${formula}`);
|
|
7993
|
+
break;
|
|
7994
|
+
}
|
|
7995
|
+
onLog(`Installing brew formula: ${formula}`);
|
|
7996
|
+
const brewCmd = [
|
|
7997
|
+
`export HOME="${agentHome}"`,
|
|
7998
|
+
`export PATH="${agentHome}/homebrew/bin:${agentHome}/bin:$PATH"`,
|
|
7999
|
+
`brew install ${formula}`
|
|
8000
|
+
].join(" && ");
|
|
8001
|
+
await execWithProgress3(
|
|
8002
|
+
`sudo -H -u ${agentUsername} /bin/bash --norc --noprofile -c '${brewCmd}'`,
|
|
8003
|
+
onLog,
|
|
8004
|
+
{ timeout: 12e4, cwd: "/" }
|
|
8005
|
+
);
|
|
8006
|
+
installed.push(formula);
|
|
8007
|
+
break;
|
|
8008
|
+
}
|
|
8009
|
+
case "npm": {
|
|
8010
|
+
const pkg = step["package"];
|
|
8011
|
+
if (!pkg) {
|
|
8012
|
+
errors.push(`npm step "${stepId}" missing package`);
|
|
8013
|
+
break;
|
|
8014
|
+
}
|
|
8015
|
+
if (!SAFE_PACKAGE_RE.test(pkg)) {
|
|
8016
|
+
errors.push(`Unsafe npm package name: ${pkg}`);
|
|
8017
|
+
break;
|
|
8018
|
+
}
|
|
8019
|
+
onLog(`Installing npm package: ${pkg}`);
|
|
8020
|
+
const npmCmd = [
|
|
8021
|
+
`export HOME="${agentHome}"`,
|
|
8022
|
+
`export PATH="${agentHome}/bin:$PATH"`,
|
|
8023
|
+
`source "${agentHome}/.nvm/nvm.sh" 2>/dev/null || true`,
|
|
8024
|
+
`npm install -g ${pkg}`
|
|
8025
|
+
].join(" && ");
|
|
8026
|
+
await execWithProgress3(
|
|
8027
|
+
`sudo -H -u ${agentUsername} /bin/bash --norc --noprofile -c '${npmCmd}'`,
|
|
8028
|
+
onLog,
|
|
8029
|
+
{ timeout: 6e4, cwd: "/" }
|
|
8030
|
+
);
|
|
8031
|
+
installed.push(pkg);
|
|
8032
|
+
break;
|
|
8033
|
+
}
|
|
8034
|
+
case "pip": {
|
|
8035
|
+
const pkg = step["package"];
|
|
8036
|
+
if (!pkg) {
|
|
8037
|
+
errors.push(`pip step "${stepId}" missing package`);
|
|
8038
|
+
break;
|
|
8039
|
+
}
|
|
8040
|
+
if (!SAFE_PACKAGE_RE.test(pkg)) {
|
|
8041
|
+
errors.push(`Unsafe pip package name: ${pkg}`);
|
|
8042
|
+
break;
|
|
8043
|
+
}
|
|
8044
|
+
onLog(`Installing pip package: ${pkg}`);
|
|
8045
|
+
const pipCmd = [
|
|
8046
|
+
`export HOME="${agentHome}"`,
|
|
8047
|
+
`export PATH="${agentHome}/bin:$PATH"`,
|
|
8048
|
+
`pip install ${pkg}`
|
|
8049
|
+
].join(" && ");
|
|
8050
|
+
await execWithProgress3(
|
|
8051
|
+
`sudo -H -u ${agentUsername} /bin/bash --norc --noprofile -c '${pipCmd}'`,
|
|
8052
|
+
onLog,
|
|
8053
|
+
{ timeout: 6e4, cwd: "/" }
|
|
8054
|
+
);
|
|
8055
|
+
installed.push(pkg);
|
|
8056
|
+
break;
|
|
8057
|
+
}
|
|
8058
|
+
}
|
|
8059
|
+
} catch (err) {
|
|
8060
|
+
const msg = `Failed to install ${kind} dep (step: ${stepId}): ${err.message}`;
|
|
8061
|
+
onLog(msg);
|
|
8062
|
+
errors.push(msg);
|
|
8063
|
+
}
|
|
8064
|
+
}
|
|
8065
|
+
const requiredBins = info.bins;
|
|
8066
|
+
if (requiredBins.length > 0) {
|
|
8067
|
+
onLog(`Verifying required binaries: ${requiredBins.join(", ")}`);
|
|
8068
|
+
for (const bin of requiredBins) {
|
|
8069
|
+
try {
|
|
8070
|
+
const checkCmd = [
|
|
8071
|
+
`export HOME="${agentHome}"`,
|
|
8072
|
+
`export PATH="${agentHome}/homebrew/bin:${agentHome}/bin:$PATH"`,
|
|
8073
|
+
`source "${agentHome}/.nvm/nvm.sh" 2>/dev/null || true`,
|
|
8074
|
+
`which ${bin}`
|
|
8075
|
+
].join(" && ");
|
|
8076
|
+
await execWithProgress3(
|
|
8077
|
+
`sudo -H -u ${agentUsername} /bin/bash --norc --noprofile -c '${checkCmd}'`,
|
|
8078
|
+
() => {
|
|
8079
|
+
},
|
|
8080
|
+
{ timeout: 5e3, cwd: "/" }
|
|
8081
|
+
);
|
|
8082
|
+
} catch {
|
|
8083
|
+
errors.push(`Required binary "${bin}" not found in agent PATH after install`);
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
}
|
|
8087
|
+
return {
|
|
8088
|
+
success: errors.length === 0,
|
|
8089
|
+
installed,
|
|
8090
|
+
errors
|
|
8091
|
+
};
|
|
8092
|
+
}
|
|
8093
|
+
|
|
7883
8094
|
// libs/shield-daemon/src/routes/marketplace.ts
|
|
7884
8095
|
var installInProgress = /* @__PURE__ */ new Set();
|
|
7885
8096
|
function isInstallInProgress(slug) {
|
|
@@ -8134,7 +8345,7 @@ async function marketplaceRoutes(app) {
|
|
|
8134
8345
|
error: "Critical vulnerability detected",
|
|
8135
8346
|
analysis: analysisResult
|
|
8136
8347
|
});
|
|
8137
|
-
return { success: false, name: slug, analysis: analysisResult, logs };
|
|
8348
|
+
return { success: false, name: slug, analysis: analysisResult, logs, depsSuccess: void 0 };
|
|
8138
8349
|
}
|
|
8139
8350
|
emitSkillInstallProgress(slug, "download", "Downloading skill files");
|
|
8140
8351
|
const skill = await getMarketplaceSkill(slug);
|
|
@@ -8144,7 +8355,7 @@ async function marketplaceRoutes(app) {
|
|
|
8144
8355
|
name: slug,
|
|
8145
8356
|
error: "No files available for installation"
|
|
8146
8357
|
});
|
|
8147
|
-
return { success: false, name: slug, analysis: analysisResult, logs };
|
|
8358
|
+
return { success: false, name: slug, analysis: analysisResult, logs, depsSuccess: void 0 };
|
|
8148
8359
|
}
|
|
8149
8360
|
const publisher = skill.author;
|
|
8150
8361
|
logs.push("Downloaded skill files");
|
|
@@ -8153,18 +8364,23 @@ async function marketplaceRoutes(app) {
|
|
|
8153
8364
|
throw new Error("Skills directory not configured");
|
|
8154
8365
|
}
|
|
8155
8366
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
8156
|
-
const
|
|
8367
|
+
const agentUsername = path16.basename(agentHome);
|
|
8368
|
+
const binDir = path16.join(agentHome, "bin");
|
|
8157
8369
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
8158
|
-
skillDir =
|
|
8370
|
+
skillDir = path16.join(skillsDir2, slug);
|
|
8159
8371
|
emitSkillInstallProgress(slug, "approve", "Pre-approving skill");
|
|
8160
8372
|
addToApprovedList(slug, publisher);
|
|
8161
8373
|
logs.push("Skill pre-approved");
|
|
8162
8374
|
emitSkillInstallProgress(slug, "copy", "Writing skill files");
|
|
8163
8375
|
const brokerAvailable = await isBrokerAvailable();
|
|
8164
8376
|
if (brokerAvailable) {
|
|
8377
|
+
const sanitizedFiles = files.map((f) => ({
|
|
8378
|
+
name: f.name,
|
|
8379
|
+
content: /SKILL\.md$/i.test(f.name) ? stripEnvFromSkillMd(f.content) : f.content
|
|
8380
|
+
}));
|
|
8165
8381
|
const brokerResult = await installSkillViaBroker(
|
|
8166
8382
|
slug,
|
|
8167
|
-
|
|
8383
|
+
sanitizedFiles,
|
|
8168
8384
|
{ createWrapper: true, agentHome, socketGroup }
|
|
8169
8385
|
);
|
|
8170
8386
|
if (!brokerResult.installed) {
|
|
@@ -8183,18 +8399,45 @@ async function marketplaceRoutes(app) {
|
|
|
8183
8399
|
}
|
|
8184
8400
|
} else {
|
|
8185
8401
|
console.log(`[Marketplace] Broker unavailable, installing ${slug} directly`);
|
|
8186
|
-
|
|
8402
|
+
sudoMkdir(skillDir, agentUsername);
|
|
8187
8403
|
for (const file of files) {
|
|
8188
|
-
const filePath =
|
|
8189
|
-
const fileDir =
|
|
8404
|
+
const filePath = path16.join(skillDir, file.name);
|
|
8405
|
+
const fileDir = path16.dirname(filePath);
|
|
8190
8406
|
if (fileDir !== skillDir) {
|
|
8191
|
-
|
|
8407
|
+
sudoMkdir(fileDir, agentUsername);
|
|
8192
8408
|
}
|
|
8193
|
-
|
|
8409
|
+
const content = /SKILL\.md$/i.test(file.name) ? stripEnvFromSkillMd(file.content) : file.content;
|
|
8410
|
+
sudoWriteFile(filePath, content, agentUsername);
|
|
8194
8411
|
}
|
|
8195
8412
|
createSkillWrapper(slug, binDir);
|
|
8196
8413
|
logs.push(`Files written directly: ${files.length} files`);
|
|
8197
|
-
logs.push(`Wrapper created: ${
|
|
8414
|
+
logs.push(`Wrapper created: ${path16.join(binDir, slug)}`);
|
|
8415
|
+
}
|
|
8416
|
+
let depsSuccess = true;
|
|
8417
|
+
emitSkillInstallProgress(slug, "deps", "Installing skill dependencies");
|
|
8418
|
+
try {
|
|
8419
|
+
const depsResult = await executeSkillInstallSteps({
|
|
8420
|
+
slug,
|
|
8421
|
+
skillDir,
|
|
8422
|
+
agentHome,
|
|
8423
|
+
agentUsername,
|
|
8424
|
+
onLog: (msg) => emitSkillInstallProgress(slug, "deps", msg)
|
|
8425
|
+
});
|
|
8426
|
+
if (depsResult.installed.length > 0) {
|
|
8427
|
+
logs.push(`Dependencies installed: ${depsResult.installed.join(", ")}`);
|
|
8428
|
+
}
|
|
8429
|
+
if (depsResult.errors.length > 0) {
|
|
8430
|
+
depsSuccess = false;
|
|
8431
|
+
for (const err of depsResult.errors) {
|
|
8432
|
+
emitSkillInstallProgress(slug, "warning", `Dependency warning: ${err}`);
|
|
8433
|
+
logs.push(`Dependency warning: ${err}`);
|
|
8434
|
+
}
|
|
8435
|
+
}
|
|
8436
|
+
} catch (err) {
|
|
8437
|
+
depsSuccess = false;
|
|
8438
|
+
const msg = `Dependency installation failed: ${err.message}`;
|
|
8439
|
+
emitSkillInstallProgress(slug, "warning", msg);
|
|
8440
|
+
logs.push(msg);
|
|
8198
8441
|
}
|
|
8199
8442
|
addSkillEntry(slug);
|
|
8200
8443
|
addSkillPolicy(slug);
|
|
@@ -8206,13 +8449,14 @@ async function marketplaceRoutes(app) {
|
|
|
8206
8449
|
logs.push("Integrity hash recorded");
|
|
8207
8450
|
}
|
|
8208
8451
|
installInProgress.delete(slug);
|
|
8209
|
-
|
|
8452
|
+
const depsWarnings = depsSuccess ? void 0 : logs.filter((l) => l.startsWith("Dependency"));
|
|
8453
|
+
daemonEvents.broadcast("skills:installed", { name: slug, analysis: analysisResult, depsWarnings });
|
|
8210
8454
|
logs.push("Installation complete");
|
|
8211
|
-
return { success: true, name: slug, analysis: analysisResult, logs };
|
|
8455
|
+
return { success: true, name: slug, analysis: analysisResult, logs, depsSuccess };
|
|
8212
8456
|
} catch (err) {
|
|
8213
8457
|
try {
|
|
8214
|
-
if (skillDir &&
|
|
8215
|
-
|
|
8458
|
+
if (skillDir && fs16.existsSync(skillDir)) {
|
|
8459
|
+
fs16.rmSync(skillDir, { recursive: true, force: true });
|
|
8216
8460
|
}
|
|
8217
8461
|
removeFromApprovedList(slug);
|
|
8218
8462
|
} catch {
|
|
@@ -8221,7 +8465,7 @@ async function marketplaceRoutes(app) {
|
|
|
8221
8465
|
installInProgress.delete(slug);
|
|
8222
8466
|
daemonEvents.broadcast("skills:install_failed", { name: slug, error: errorMsg });
|
|
8223
8467
|
console.error("[Marketplace] Install failed:", errorMsg);
|
|
8224
|
-
return { success: false, name: slug, analysis: analysisResult, logs: [...logs, `Error: ${errorMsg}`] };
|
|
8468
|
+
return { success: false, name: slug, analysis: analysisResult, logs: [...logs, `Error: ${errorMsg}`], depsSuccess: void 0 };
|
|
8225
8469
|
} finally {
|
|
8226
8470
|
installInProgress.delete(slug);
|
|
8227
8471
|
}
|
|
@@ -8245,17 +8489,17 @@ async function marketplaceRoutes(app) {
|
|
|
8245
8489
|
}
|
|
8246
8490
|
|
|
8247
8491
|
// libs/shield-daemon/src/routes/skills.ts
|
|
8248
|
-
function
|
|
8492
|
+
function findSkillMdRecursive2(dir, depth = 0) {
|
|
8249
8493
|
if (depth > 3) return null;
|
|
8250
8494
|
try {
|
|
8251
8495
|
for (const name of ["SKILL.md", "skill.md", "README.md", "readme.md"]) {
|
|
8252
|
-
const candidate =
|
|
8253
|
-
if (
|
|
8496
|
+
const candidate = path17.join(dir, name);
|
|
8497
|
+
if (fs17.existsSync(candidate)) return candidate;
|
|
8254
8498
|
}
|
|
8255
|
-
const entries =
|
|
8499
|
+
const entries = fs17.readdirSync(dir, { withFileTypes: true });
|
|
8256
8500
|
for (const entry of entries) {
|
|
8257
8501
|
if (!entry.isDirectory()) continue;
|
|
8258
|
-
const found =
|
|
8502
|
+
const found = findSkillMdRecursive2(path17.join(dir, entry.name), depth + 1);
|
|
8259
8503
|
if (found) return found;
|
|
8260
8504
|
}
|
|
8261
8505
|
} catch {
|
|
@@ -8264,10 +8508,10 @@ function findSkillMdRecursive(dir, depth = 0) {
|
|
|
8264
8508
|
}
|
|
8265
8509
|
function readSkillMetadata(skillDir) {
|
|
8266
8510
|
try {
|
|
8267
|
-
const mdPath =
|
|
8511
|
+
const mdPath = findSkillMdRecursive2(skillDir);
|
|
8268
8512
|
if (!mdPath) return {};
|
|
8269
|
-
const content =
|
|
8270
|
-
const parsed =
|
|
8513
|
+
const content = fs17.readFileSync(mdPath, "utf-8");
|
|
8514
|
+
const parsed = parseSkillMd3(content);
|
|
8271
8515
|
const meta = parsed?.metadata;
|
|
8272
8516
|
return {
|
|
8273
8517
|
description: meta?.description,
|
|
@@ -8325,7 +8569,7 @@ async function skillsRoutes(app) {
|
|
|
8325
8569
|
let onDiskNames = [];
|
|
8326
8570
|
if (skillsDir2) {
|
|
8327
8571
|
try {
|
|
8328
|
-
onDiskNames =
|
|
8572
|
+
onDiskNames = fs17.readdirSync(skillsDir2, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
8329
8573
|
} catch {
|
|
8330
8574
|
}
|
|
8331
8575
|
}
|
|
@@ -8335,14 +8579,14 @@ async function skillsRoutes(app) {
|
|
|
8335
8579
|
const data = [
|
|
8336
8580
|
// Approved → active (with metadata from SKILL.md + cached analysis)
|
|
8337
8581
|
...approved.map((a) => {
|
|
8338
|
-
const meta = skillsDir2 ? readSkillMetadata(
|
|
8582
|
+
const meta = skillsDir2 ? readSkillMetadata(path17.join(skillsDir2, a.name)) : {};
|
|
8339
8583
|
const cached = getCachedAnalysis2(a.name);
|
|
8340
8584
|
const dlMeta = getDownloadedSkillMeta(a.name);
|
|
8341
8585
|
return {
|
|
8342
8586
|
name: a.name,
|
|
8343
8587
|
source: "user",
|
|
8344
8588
|
status: "active",
|
|
8345
|
-
path:
|
|
8589
|
+
path: path17.join(skillsDir2 ?? "", a.name),
|
|
8346
8590
|
publisher: a.publisher,
|
|
8347
8591
|
description: meta.description,
|
|
8348
8592
|
version: meta.version,
|
|
@@ -8369,12 +8613,12 @@ async function skillsRoutes(app) {
|
|
|
8369
8613
|
}),
|
|
8370
8614
|
// Workspace: on disk but not approved or untrusted
|
|
8371
8615
|
...workspaceNames.map((name) => {
|
|
8372
|
-
const meta = skillsDir2 ? readSkillMetadata(
|
|
8616
|
+
const meta = skillsDir2 ? readSkillMetadata(path17.join(skillsDir2, name)) : {};
|
|
8373
8617
|
return {
|
|
8374
8618
|
name,
|
|
8375
8619
|
source: "workspace",
|
|
8376
8620
|
status: "workspace",
|
|
8377
|
-
path:
|
|
8621
|
+
path: path17.join(skillsDir2 ?? "", name),
|
|
8378
8622
|
description: meta.description,
|
|
8379
8623
|
version: meta.version,
|
|
8380
8624
|
author: meta.author,
|
|
@@ -8405,7 +8649,7 @@ async function skillsRoutes(app) {
|
|
|
8405
8649
|
let isWorkspace = false;
|
|
8406
8650
|
if (!entry && !uEntry && skillsDir2) {
|
|
8407
8651
|
try {
|
|
8408
|
-
isWorkspace =
|
|
8652
|
+
isWorkspace = fs17.existsSync(path17.join(skillsDir2, name));
|
|
8409
8653
|
} catch {
|
|
8410
8654
|
}
|
|
8411
8655
|
}
|
|
@@ -8423,13 +8667,13 @@ async function skillsRoutes(app) {
|
|
|
8423
8667
|
analysis: buildFullAnalysis(name, dlMeta?.analysis || getCachedAnalysis2(name))
|
|
8424
8668
|
};
|
|
8425
8669
|
} else if (entry) {
|
|
8426
|
-
const meta = skillsDir2 ? readSkillMetadata(
|
|
8670
|
+
const meta = skillsDir2 ? readSkillMetadata(path17.join(skillsDir2, name)) : {};
|
|
8427
8671
|
const cached = getCachedAnalysis2(name);
|
|
8428
8672
|
summary = {
|
|
8429
8673
|
name,
|
|
8430
8674
|
source: "user",
|
|
8431
8675
|
status: "active",
|
|
8432
|
-
path: skillsDir2 ?
|
|
8676
|
+
path: skillsDir2 ? path17.join(skillsDir2, name) : "",
|
|
8433
8677
|
publisher: entry.publisher,
|
|
8434
8678
|
description: meta.description,
|
|
8435
8679
|
version: meta.version,
|
|
@@ -8438,12 +8682,12 @@ async function skillsRoutes(app) {
|
|
|
8438
8682
|
analysis: buildFullAnalysis(name, dlMeta?.analysis || cached)
|
|
8439
8683
|
};
|
|
8440
8684
|
} else if (isWorkspace) {
|
|
8441
|
-
const meta = skillsDir2 ? readSkillMetadata(
|
|
8685
|
+
const meta = skillsDir2 ? readSkillMetadata(path17.join(skillsDir2, name)) : {};
|
|
8442
8686
|
summary = {
|
|
8443
8687
|
name,
|
|
8444
8688
|
source: "workspace",
|
|
8445
8689
|
status: "workspace",
|
|
8446
|
-
path: skillsDir2 ?
|
|
8690
|
+
path: skillsDir2 ? path17.join(skillsDir2, name) : "",
|
|
8447
8691
|
description: meta.description,
|
|
8448
8692
|
version: meta.version,
|
|
8449
8693
|
author: meta.author,
|
|
@@ -8468,11 +8712,11 @@ async function skillsRoutes(app) {
|
|
|
8468
8712
|
return reply.code(404).send({ error: `Skill "${name}" not found` });
|
|
8469
8713
|
}
|
|
8470
8714
|
let content = "";
|
|
8471
|
-
const dirToRead = summary.path || (skillsDir2 ?
|
|
8715
|
+
const dirToRead = summary.path || (skillsDir2 ? path17.join(skillsDir2, name) : "");
|
|
8472
8716
|
if (dirToRead) {
|
|
8473
8717
|
try {
|
|
8474
|
-
const mdPath =
|
|
8475
|
-
if (mdPath) content =
|
|
8718
|
+
const mdPath = findSkillMdRecursive2(dirToRead);
|
|
8719
|
+
if (mdPath) content = fs17.readFileSync(mdPath, "utf-8");
|
|
8476
8720
|
} catch {
|
|
8477
8721
|
}
|
|
8478
8722
|
}
|
|
@@ -8510,14 +8754,14 @@ async function skillsRoutes(app) {
|
|
|
8510
8754
|
if (!content) {
|
|
8511
8755
|
const skillsDir2 = getSkillsDir();
|
|
8512
8756
|
const possibleDirs = [
|
|
8513
|
-
skillsDir2 ?
|
|
8757
|
+
skillsDir2 ? path17.join(skillsDir2, name) : null
|
|
8514
8758
|
].filter(Boolean);
|
|
8515
8759
|
for (const dir of possibleDirs) {
|
|
8516
8760
|
try {
|
|
8517
|
-
const mdPath =
|
|
8761
|
+
const mdPath = findSkillMdRecursive2(dir);
|
|
8518
8762
|
if (mdPath) {
|
|
8519
|
-
content =
|
|
8520
|
-
const parsed =
|
|
8763
|
+
content = fs17.readFileSync(mdPath, "utf-8");
|
|
8764
|
+
const parsed = parseSkillMd3(content);
|
|
8521
8765
|
if (parsed?.metadata && !metadata) {
|
|
8522
8766
|
metadata = parsed.metadata;
|
|
8523
8767
|
}
|
|
@@ -8532,7 +8776,7 @@ async function skillsRoutes(app) {
|
|
|
8532
8776
|
const skillFile = localFiles.find((f) => /skill\.md/i.test(f.name));
|
|
8533
8777
|
if (skillFile?.content) {
|
|
8534
8778
|
content = skillFile.content;
|
|
8535
|
-
const parsed =
|
|
8779
|
+
const parsed = parseSkillMd3(content);
|
|
8536
8780
|
if (parsed?.metadata && !metadata) {
|
|
8537
8781
|
metadata = parsed.metadata;
|
|
8538
8782
|
}
|
|
@@ -8547,7 +8791,7 @@ async function skillsRoutes(app) {
|
|
|
8547
8791
|
const skillFile = freshFiles.find((f) => /skill\.md/i.test(f.name));
|
|
8548
8792
|
if (skillFile?.content) {
|
|
8549
8793
|
content = skillFile.content;
|
|
8550
|
-
const parsed =
|
|
8794
|
+
const parsed = parseSkillMd3(content);
|
|
8551
8795
|
if (parsed?.metadata && !metadata) {
|
|
8552
8796
|
metadata = parsed.metadata;
|
|
8553
8797
|
}
|
|
@@ -8701,10 +8945,10 @@ async function skillsRoutes(app) {
|
|
|
8701
8945
|
return reply.code(500).send({ error: "Skills directory not configured" });
|
|
8702
8946
|
}
|
|
8703
8947
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
8704
|
-
const binDir =
|
|
8948
|
+
const binDir = path17.join(agentHome, "bin");
|
|
8705
8949
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
8706
|
-
const skillDir =
|
|
8707
|
-
const isInstalled =
|
|
8950
|
+
const skillDir = path17.join(skillsDir2, name);
|
|
8951
|
+
const isInstalled = fs17.existsSync(skillDir);
|
|
8708
8952
|
if (isInstalled) {
|
|
8709
8953
|
try {
|
|
8710
8954
|
const brokerAvailable = await isBrokerAvailable();
|
|
@@ -8714,7 +8958,7 @@ async function skillsRoutes(app) {
|
|
|
8714
8958
|
agentHome
|
|
8715
8959
|
});
|
|
8716
8960
|
} else {
|
|
8717
|
-
|
|
8961
|
+
fs17.rmSync(skillDir, { recursive: true, force: true });
|
|
8718
8962
|
removeSkillWrapper(name, binDir);
|
|
8719
8963
|
}
|
|
8720
8964
|
removeSkillEntry(name);
|
|
@@ -8759,11 +9003,11 @@ async function skillsRoutes(app) {
|
|
|
8759
9003
|
}
|
|
8760
9004
|
}
|
|
8761
9005
|
} else {
|
|
8762
|
-
|
|
9006
|
+
fs17.mkdirSync(skillDir, { recursive: true });
|
|
8763
9007
|
for (const file of files) {
|
|
8764
|
-
const filePath =
|
|
8765
|
-
|
|
8766
|
-
|
|
9008
|
+
const filePath = path17.join(skillDir, file.name);
|
|
9009
|
+
fs17.mkdirSync(path17.dirname(filePath), { recursive: true });
|
|
9010
|
+
fs17.writeFileSync(filePath, file.content, "utf-8");
|
|
8767
9011
|
}
|
|
8768
9012
|
try {
|
|
8769
9013
|
execSync9(`chown -R root:${socketGroup} "${skillDir}"`, { stdio: "pipe" });
|
|
@@ -8781,8 +9025,8 @@ async function skillsRoutes(app) {
|
|
|
8781
9025
|
return reply.send({ success: true, action: "enabled", name });
|
|
8782
9026
|
} catch (err) {
|
|
8783
9027
|
try {
|
|
8784
|
-
if (
|
|
8785
|
-
|
|
9028
|
+
if (fs17.existsSync(skillDir)) {
|
|
9029
|
+
fs17.rmSync(skillDir, { recursive: true, force: true });
|
|
8786
9030
|
}
|
|
8787
9031
|
removeFromApprovedList(name);
|
|
8788
9032
|
} catch {
|
|
@@ -8808,7 +9052,7 @@ async function skillsRoutes(app) {
|
|
|
8808
9052
|
const skillMdFile = files.find((f) => f.name === "SKILL.md");
|
|
8809
9053
|
let metadata;
|
|
8810
9054
|
if (skillMdFile) {
|
|
8811
|
-
const parsed =
|
|
9055
|
+
const parsed = parseSkillMd3(skillMdFile.content);
|
|
8812
9056
|
metadata = parsed?.metadata;
|
|
8813
9057
|
}
|
|
8814
9058
|
const analysis = analyzeSkill(name, combinedContent, metadata);
|
|
@@ -8820,16 +9064,18 @@ async function skillsRoutes(app) {
|
|
|
8820
9064
|
return reply.code(500).send({ error: "Skills directory not configured" });
|
|
8821
9065
|
}
|
|
8822
9066
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
8823
|
-
const
|
|
9067
|
+
const agentUsername = path17.basename(agentHome);
|
|
9068
|
+
const binDir = path17.join(agentHome, "bin");
|
|
8824
9069
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
8825
|
-
const skillDir =
|
|
9070
|
+
const skillDir = path17.join(skillsDir2, name);
|
|
8826
9071
|
try {
|
|
8827
9072
|
addToApprovedList(name, publisher);
|
|
8828
|
-
|
|
9073
|
+
sudoMkdir(skillDir, agentUsername);
|
|
8829
9074
|
for (const file of files) {
|
|
8830
|
-
const filePath =
|
|
8831
|
-
|
|
8832
|
-
|
|
9075
|
+
const filePath = path17.join(skillDir, file.name);
|
|
9076
|
+
sudoMkdir(path17.dirname(filePath), agentUsername);
|
|
9077
|
+
const content = /SKILL\.md$/i.test(file.name) ? stripEnvFromSkillMd2(file.content) : file.content;
|
|
9078
|
+
sudoWriteFile(filePath, content, agentUsername);
|
|
8833
9079
|
}
|
|
8834
9080
|
try {
|
|
8835
9081
|
execSync9(`chown -R root:${socketGroup} "${skillDir}"`, { stdio: "pipe" });
|
|
@@ -8843,8 +9089,8 @@ async function skillsRoutes(app) {
|
|
|
8843
9089
|
return reply.send({ success: true, name, analysis });
|
|
8844
9090
|
} catch (err) {
|
|
8845
9091
|
try {
|
|
8846
|
-
if (
|
|
8847
|
-
|
|
9092
|
+
if (fs17.existsSync(skillDir)) {
|
|
9093
|
+
fs17.rmSync(skillDir, { recursive: true, force: true });
|
|
8848
9094
|
}
|
|
8849
9095
|
removeFromApprovedList(name);
|
|
8850
9096
|
} catch {
|
|
@@ -8878,9 +9124,9 @@ async function skillsRoutes(app) {
|
|
|
8878
9124
|
}
|
|
8879
9125
|
try {
|
|
8880
9126
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
8881
|
-
const binDir =
|
|
9127
|
+
const binDir = path17.join(agentHome, "bin");
|
|
8882
9128
|
const socketGroup = process.env["AGENSHIELD_SOCKET_GROUP"] || "ash_default";
|
|
8883
|
-
const skillDir =
|
|
9129
|
+
const skillDir = path17.join(getSkillsDir(), name);
|
|
8884
9130
|
addToApprovedList(name, meta.author);
|
|
8885
9131
|
const brokerAvailable = await isBrokerAvailable();
|
|
8886
9132
|
if (brokerAvailable) {
|
|
@@ -8898,11 +9144,11 @@ async function skillsRoutes(app) {
|
|
|
8898
9144
|
}
|
|
8899
9145
|
}
|
|
8900
9146
|
} else {
|
|
8901
|
-
|
|
9147
|
+
fs17.mkdirSync(skillDir, { recursive: true });
|
|
8902
9148
|
for (const file of files) {
|
|
8903
|
-
const filePath =
|
|
8904
|
-
|
|
8905
|
-
|
|
9149
|
+
const filePath = path17.join(skillDir, file.name);
|
|
9150
|
+
fs17.mkdirSync(path17.dirname(filePath), { recursive: true });
|
|
9151
|
+
fs17.writeFileSync(filePath, file.content, "utf-8");
|
|
8906
9152
|
}
|
|
8907
9153
|
try {
|
|
8908
9154
|
execSync9(`chown -R root:${socketGroup} "${skillDir}"`, { stdio: "pipe" });
|
|
@@ -8914,7 +9160,7 @@ async function skillsRoutes(app) {
|
|
|
8914
9160
|
addSkillEntry(name);
|
|
8915
9161
|
addSkillPolicy(name);
|
|
8916
9162
|
syncOpenClawFromPolicies(loadConfig().policies);
|
|
8917
|
-
const unblockHash = computeSkillHash(
|
|
9163
|
+
const unblockHash = computeSkillHash(path17.join(getSkillsDir(), name));
|
|
8918
9164
|
if (unblockHash) updateApprovedHash(name, unblockHash);
|
|
8919
9165
|
console.log(`[Skills] Unblocked and installed skill: ${name}`);
|
|
8920
9166
|
return reply.send({ success: true, message: `Skill "${name}" approved and installed` });
|
|
@@ -8945,7 +9191,7 @@ async function skillsRoutes(app) {
|
|
|
8945
9191
|
const skillMdFile = files.find((f) => /skill\.md/i.test(f.name));
|
|
8946
9192
|
if (skillMdFile) {
|
|
8947
9193
|
try {
|
|
8948
|
-
const parsed =
|
|
9194
|
+
const parsed = parseSkillMd3(skillMdFile.content);
|
|
8949
9195
|
if (parsed?.metadata) {
|
|
8950
9196
|
parsedDescription = parsedDescription || parsed.metadata.description;
|
|
8951
9197
|
parsedVersion = parsedVersion || parsed.metadata.version;
|
|
@@ -8974,10 +9220,10 @@ async function skillsRoutes(app) {
|
|
|
8974
9220
|
|
|
8975
9221
|
// libs/shield-daemon/src/routes/exec.ts
|
|
8976
9222
|
init_paths();
|
|
8977
|
-
import * as
|
|
8978
|
-
import * as
|
|
9223
|
+
import * as fs18 from "node:fs";
|
|
9224
|
+
import * as path18 from "node:path";
|
|
8979
9225
|
function getAllowedCommandsPath2() {
|
|
8980
|
-
return
|
|
9226
|
+
return path18.join(getSystemConfigDir(), "allowed-commands.json");
|
|
8981
9227
|
}
|
|
8982
9228
|
var BIN_DIRS = [
|
|
8983
9229
|
"/usr/bin",
|
|
@@ -8990,22 +9236,22 @@ var binCache = null;
|
|
|
8990
9236
|
var BIN_CACHE_TTL = 6e4;
|
|
8991
9237
|
var VALID_NAME = /^[a-zA-Z0-9_-]+$/;
|
|
8992
9238
|
function loadConfig2() {
|
|
8993
|
-
if (!
|
|
9239
|
+
if (!fs18.existsSync(getAllowedCommandsPath2())) {
|
|
8994
9240
|
return { version: "1.0.0", commands: [] };
|
|
8995
9241
|
}
|
|
8996
9242
|
try {
|
|
8997
|
-
const content =
|
|
9243
|
+
const content = fs18.readFileSync(getAllowedCommandsPath2(), "utf-8");
|
|
8998
9244
|
return JSON.parse(content);
|
|
8999
9245
|
} catch {
|
|
9000
9246
|
return { version: "1.0.0", commands: [] };
|
|
9001
9247
|
}
|
|
9002
9248
|
}
|
|
9003
9249
|
function saveConfig2(config) {
|
|
9004
|
-
const dir =
|
|
9005
|
-
if (!
|
|
9006
|
-
|
|
9250
|
+
const dir = path18.dirname(getAllowedCommandsPath2());
|
|
9251
|
+
if (!fs18.existsSync(dir)) {
|
|
9252
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
9007
9253
|
}
|
|
9008
|
-
|
|
9254
|
+
fs18.writeFileSync(getAllowedCommandsPath2(), JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
9009
9255
|
}
|
|
9010
9256
|
function scanSystemBins() {
|
|
9011
9257
|
const pathDirs = (process.env.PATH ?? "").split(":").filter(Boolean);
|
|
@@ -9014,13 +9260,13 @@ function scanSystemBins() {
|
|
|
9014
9260
|
const results = [];
|
|
9015
9261
|
for (const dir of allDirs) {
|
|
9016
9262
|
try {
|
|
9017
|
-
if (!
|
|
9018
|
-
const entries =
|
|
9263
|
+
if (!fs18.existsSync(dir)) continue;
|
|
9264
|
+
const entries = fs18.readdirSync(dir);
|
|
9019
9265
|
for (const entry of entries) {
|
|
9020
9266
|
if (seen.has(entry)) continue;
|
|
9021
|
-
const fullPath =
|
|
9267
|
+
const fullPath = path18.join(dir, entry);
|
|
9022
9268
|
try {
|
|
9023
|
-
const stat =
|
|
9269
|
+
const stat = fs18.statSync(fullPath);
|
|
9024
9270
|
if (stat.isFile() && (stat.mode & 73) !== 0) {
|
|
9025
9271
|
seen.add(entry);
|
|
9026
9272
|
results.push({ name: entry, path: fullPath });
|
|
@@ -9073,7 +9319,7 @@ async function execRoutes(app) {
|
|
|
9073
9319
|
};
|
|
9074
9320
|
}
|
|
9075
9321
|
for (const p of paths) {
|
|
9076
|
-
if (!
|
|
9322
|
+
if (!path18.isAbsolute(p)) {
|
|
9077
9323
|
return {
|
|
9078
9324
|
success: false,
|
|
9079
9325
|
error: {
|
|
@@ -9569,18 +9815,18 @@ async function secretsRoutes(app) {
|
|
|
9569
9815
|
}
|
|
9570
9816
|
|
|
9571
9817
|
// libs/shield-daemon/src/routes/fs.ts
|
|
9572
|
-
import * as
|
|
9573
|
-
import * as
|
|
9818
|
+
import * as fs19 from "node:fs";
|
|
9819
|
+
import * as path19 from "node:path";
|
|
9574
9820
|
import * as os6 from "node:os";
|
|
9575
9821
|
var MAX_ENTRIES = 200;
|
|
9576
9822
|
async function fsRoutes(app) {
|
|
9577
9823
|
app.get("/fs/browse", async (request2) => {
|
|
9578
9824
|
const dirPath = request2.query.path || os6.homedir();
|
|
9579
9825
|
const showHidden = request2.query.showHidden === "true";
|
|
9580
|
-
const resolvedPath =
|
|
9826
|
+
const resolvedPath = path19.resolve(dirPath);
|
|
9581
9827
|
let dirents;
|
|
9582
9828
|
try {
|
|
9583
|
-
dirents =
|
|
9829
|
+
dirents = fs19.readdirSync(resolvedPath, { withFileTypes: true });
|
|
9584
9830
|
} catch {
|
|
9585
9831
|
return { success: true, data: { entries: [] } };
|
|
9586
9832
|
}
|
|
@@ -9589,7 +9835,7 @@ async function fsRoutes(app) {
|
|
|
9589
9835
|
if (!showHidden && dirent.name.startsWith(".")) continue;
|
|
9590
9836
|
entries.push({
|
|
9591
9837
|
name: dirent.name,
|
|
9592
|
-
path:
|
|
9838
|
+
path: path19.join(resolvedPath, dirent.name),
|
|
9593
9839
|
type: dirent.isDirectory() ? "directory" : "file"
|
|
9594
9840
|
});
|
|
9595
9841
|
if (entries.length >= MAX_ENTRIES) break;
|
|
@@ -9603,8 +9849,8 @@ async function fsRoutes(app) {
|
|
|
9603
9849
|
}
|
|
9604
9850
|
|
|
9605
9851
|
// libs/shield-daemon/src/services/activity-log.ts
|
|
9606
|
-
import * as
|
|
9607
|
-
import * as
|
|
9852
|
+
import * as fs20 from "node:fs";
|
|
9853
|
+
import * as path20 from "node:path";
|
|
9608
9854
|
init_paths();
|
|
9609
9855
|
var ACTIVITY_FILE = "activity.jsonl";
|
|
9610
9856
|
var MAX_SIZE_BYTES = 100 * 1024 * 1024;
|
|
@@ -9622,12 +9868,12 @@ var ActivityLog = class {
|
|
|
9622
9868
|
writeCount = 0;
|
|
9623
9869
|
unsubscribe;
|
|
9624
9870
|
constructor() {
|
|
9625
|
-
this.filePath =
|
|
9871
|
+
this.filePath = path20.join(getConfigDir(), ACTIVITY_FILE);
|
|
9626
9872
|
}
|
|
9627
9873
|
/** Read historical events from the JSONL file, newest first */
|
|
9628
9874
|
getHistory(limit = 500) {
|
|
9629
|
-
if (!
|
|
9630
|
-
const content =
|
|
9875
|
+
if (!fs20.existsSync(this.filePath)) return [];
|
|
9876
|
+
const content = fs20.readFileSync(this.filePath, "utf-8");
|
|
9631
9877
|
const lines = content.split("\n").filter(Boolean);
|
|
9632
9878
|
const events = [];
|
|
9633
9879
|
for (const line of lines) {
|
|
@@ -9652,7 +9898,7 @@ var ActivityLog = class {
|
|
|
9652
9898
|
}
|
|
9653
9899
|
append(event) {
|
|
9654
9900
|
const line = JSON.stringify(event) + "\n";
|
|
9655
|
-
|
|
9901
|
+
fs20.appendFileSync(this.filePath, line, "utf-8");
|
|
9656
9902
|
this.writeCount++;
|
|
9657
9903
|
if (this.writeCount % PRUNE_INTERVAL === 0) {
|
|
9658
9904
|
this.rotate();
|
|
@@ -9660,7 +9906,7 @@ var ActivityLog = class {
|
|
|
9660
9906
|
}
|
|
9661
9907
|
rotate() {
|
|
9662
9908
|
try {
|
|
9663
|
-
const stat =
|
|
9909
|
+
const stat = fs20.statSync(this.filePath);
|
|
9664
9910
|
if (stat.size > MAX_SIZE_BYTES) {
|
|
9665
9911
|
this.truncateBySize();
|
|
9666
9912
|
}
|
|
@@ -9670,15 +9916,15 @@ var ActivityLog = class {
|
|
|
9670
9916
|
}
|
|
9671
9917
|
/** Keep newest half of lines when file exceeds size limit */
|
|
9672
9918
|
truncateBySize() {
|
|
9673
|
-
const content =
|
|
9919
|
+
const content = fs20.readFileSync(this.filePath, "utf-8");
|
|
9674
9920
|
const lines = content.split("\n").filter(Boolean);
|
|
9675
9921
|
const keep = lines.slice(Math.floor(lines.length / 2));
|
|
9676
|
-
|
|
9922
|
+
fs20.writeFileSync(this.filePath, keep.join("\n") + "\n", "utf-8");
|
|
9677
9923
|
}
|
|
9678
9924
|
/** Remove entries older than 24 hours */
|
|
9679
9925
|
pruneOldEntries() {
|
|
9680
|
-
if (!
|
|
9681
|
-
const content =
|
|
9926
|
+
if (!fs20.existsSync(this.filePath)) return;
|
|
9927
|
+
const content = fs20.readFileSync(this.filePath, "utf-8");
|
|
9682
9928
|
const lines = content.split("\n").filter(Boolean);
|
|
9683
9929
|
const cutoff = Date.now() - MAX_AGE_MS;
|
|
9684
9930
|
const kept = lines.filter((line) => {
|
|
@@ -9690,7 +9936,7 @@ var ActivityLog = class {
|
|
|
9690
9936
|
}
|
|
9691
9937
|
});
|
|
9692
9938
|
if (kept.length < lines.length) {
|
|
9693
|
-
|
|
9939
|
+
fs20.writeFileSync(this.filePath, kept.join("\n") + "\n", "utf-8");
|
|
9694
9940
|
}
|
|
9695
9941
|
}
|
|
9696
9942
|
};
|
|
@@ -9831,11 +10077,11 @@ function normalizeUrlTarget(url) {
|
|
|
9831
10077
|
const trimmed = url.trim();
|
|
9832
10078
|
try {
|
|
9833
10079
|
const parsed = new URL(trimmed);
|
|
9834
|
-
let
|
|
9835
|
-
if (
|
|
9836
|
-
|
|
10080
|
+
let path24 = parsed.pathname;
|
|
10081
|
+
if (path24.length > 1) {
|
|
10082
|
+
path24 = path24.replace(/\/+$/, "");
|
|
9837
10083
|
}
|
|
9838
|
-
return `${parsed.protocol}//${parsed.host}${
|
|
10084
|
+
return `${parsed.protocol}//${parsed.host}${path24}${parsed.search}`;
|
|
9839
10085
|
} catch {
|
|
9840
10086
|
return trimmed.replace(/\/+$/, "");
|
|
9841
10087
|
}
|
|
@@ -10121,8 +10367,8 @@ function matchCommandPattern(pattern, target) {
|
|
|
10121
10367
|
const firstSpace = target.indexOf(" ");
|
|
10122
10368
|
const cmd = firstSpace >= 0 ? target.slice(0, firstSpace) : target;
|
|
10123
10369
|
if (cmd.startsWith("/")) {
|
|
10124
|
-
const
|
|
10125
|
-
normalizedTarget = firstSpace >= 0 ?
|
|
10370
|
+
const basename6 = cmd.split("/").pop() || cmd;
|
|
10371
|
+
normalizedTarget = firstSpace >= 0 ? basename6 + target.slice(firstSpace) : basename6;
|
|
10126
10372
|
}
|
|
10127
10373
|
if (trimmed.endsWith(":*")) {
|
|
10128
10374
|
const prefix = trimmed.slice(0, -2);
|
|
@@ -10173,8 +10419,8 @@ function determineNetworkAccess(_config, matchedPolicy, target) {
|
|
|
10173
10419
|
if (matchedPolicy?.networkAccess) return matchedPolicy.networkAccess;
|
|
10174
10420
|
const cleanTarget = target.startsWith("fork:") ? target.slice(5) : target;
|
|
10175
10421
|
const cmdPart = cleanTarget.split(" ")[0] || "";
|
|
10176
|
-
const
|
|
10177
|
-
if (!NETWORK_COMMANDS.has(
|
|
10422
|
+
const basename6 = cmdPart.includes("/") ? cmdPart.split("/").pop() : cmdPart;
|
|
10423
|
+
if (!NETWORK_COMMANDS.has(basename6.toLowerCase())) return "none";
|
|
10178
10424
|
return "proxy";
|
|
10179
10425
|
}
|
|
10180
10426
|
async function buildSandboxConfig(config, matchedPolicy, _context, target) {
|
|
@@ -10475,22 +10721,22 @@ async function registerRoutes(app) {
|
|
|
10475
10721
|
}
|
|
10476
10722
|
|
|
10477
10723
|
// libs/shield-daemon/src/static.ts
|
|
10478
|
-
import * as
|
|
10479
|
-
import * as
|
|
10724
|
+
import * as fs21 from "node:fs";
|
|
10725
|
+
import * as path21 from "node:path";
|
|
10480
10726
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
10481
10727
|
var __filename = fileURLToPath2(import.meta.url);
|
|
10482
|
-
var __dirname =
|
|
10728
|
+
var __dirname = path21.dirname(__filename);
|
|
10483
10729
|
function getUiAssetsPath() {
|
|
10484
|
-
const pkgRootPath =
|
|
10485
|
-
if (
|
|
10730
|
+
const pkgRootPath = path21.join(__dirname, "..", "ui-assets");
|
|
10731
|
+
if (fs21.existsSync(pkgRootPath)) {
|
|
10486
10732
|
return pkgRootPath;
|
|
10487
10733
|
}
|
|
10488
|
-
const bundledPath =
|
|
10489
|
-
if (
|
|
10734
|
+
const bundledPath = path21.join(__dirname, "ui-assets");
|
|
10735
|
+
if (fs21.existsSync(bundledPath)) {
|
|
10490
10736
|
return bundledPath;
|
|
10491
10737
|
}
|
|
10492
|
-
const devPath =
|
|
10493
|
-
if (
|
|
10738
|
+
const devPath = path21.join(__dirname, "..", "..", "..", "dist", "apps", "shield-ui");
|
|
10739
|
+
if (fs21.existsSync(devPath)) {
|
|
10494
10740
|
return devPath;
|
|
10495
10741
|
}
|
|
10496
10742
|
return null;
|
|
@@ -10580,8 +10826,8 @@ async function startServer(config) {
|
|
|
10580
10826
|
startSecurityWatcher(1e4);
|
|
10581
10827
|
const agentHome = process.env["AGENSHIELD_AGENT_HOME"] || "/Users/ash_default_agent";
|
|
10582
10828
|
const skillsDir2 = `${agentHome}/.openclaw/skills`;
|
|
10583
|
-
if (!
|
|
10584
|
-
|
|
10829
|
+
if (!fs23.existsSync(skillsDir2)) {
|
|
10830
|
+
fs23.mkdirSync(skillsDir2, { recursive: true, mode: 493 });
|
|
10585
10831
|
console.log(`[Daemon] Created skills directory: ${skillsDir2}`);
|
|
10586
10832
|
}
|
|
10587
10833
|
startSkillsWatcher(skillsDir2, {
|
|
@@ -10632,10 +10878,10 @@ async function main() {
|
|
|
10632
10878
|
ensureConfigDir();
|
|
10633
10879
|
const config = loadConfig();
|
|
10634
10880
|
const pidPath = getPidPath();
|
|
10635
|
-
|
|
10881
|
+
fs24.writeFileSync(pidPath, process.pid.toString(), "utf-8");
|
|
10636
10882
|
const cleanup = () => {
|
|
10637
|
-
if (
|
|
10638
|
-
|
|
10883
|
+
if (fs24.existsSync(pidPath)) {
|
|
10884
|
+
fs24.unlinkSync(pidPath);
|
|
10639
10885
|
}
|
|
10640
10886
|
process.exit(0);
|
|
10641
10887
|
};
|