@syengup/friday-channel-next 0.0.20 → 0.0.21
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/install.js +25 -0
- package/package.json +1 -2
- package/install.sh +0 -298
package/install.js
CHANGED
|
@@ -219,6 +219,31 @@ if (config.gateway.bind !== "lan") {
|
|
|
219
219
|
console.log(" + Set gateway.bind to lan");
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
// Ensure canvas and nodes are in agent tools.alsoAllow
|
|
223
|
+
if (!config.agents) config.agents = {};
|
|
224
|
+
if (!Array.isArray(config.agents.list)) config.agents.list = [];
|
|
225
|
+
if (config.agents.list.length === 0) config.agents.list.push({ id: "main" });
|
|
226
|
+
for (const agent of config.agents.list) {
|
|
227
|
+
if (!agent.tools) agent.tools = {};
|
|
228
|
+
if (!Array.isArray(agent.tools.alsoAllow)) agent.tools.alsoAllow = [];
|
|
229
|
+
for (const tool of ["canvas", "nodes"]) {
|
|
230
|
+
if (!agent.tools.alsoAllow.includes(tool)) {
|
|
231
|
+
agent.tools.alsoAllow.push(tool);
|
|
232
|
+
console.log(" + Added " + tool + " to agent '" + (agent.id || "?") + "' tools.alsoAllow");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Remove canvas and nodes from deny list if present
|
|
236
|
+
if (Array.isArray(agent.tools.deny)) {
|
|
237
|
+
for (const tool of ["canvas", "nodes"]) {
|
|
238
|
+
const idx = agent.tools.deny.indexOf(tool);
|
|
239
|
+
if (idx !== -1) {
|
|
240
|
+
agent.tools.deny.splice(idx, 1);
|
|
241
|
+
console.log(" - Removed " + tool + " from agent '" + (agent.id || "?") + "' tools.deny");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
222
247
|
try {
|
|
223
248
|
writeFileSync(OPENCLAW_CONFIG, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
224
249
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syengup/friday-channel-next",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"description": "OpenClaw Friday Next Apple channel plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"index.ts",
|
|
8
8
|
"src/",
|
|
9
9
|
"install.js",
|
|
10
|
-
"install.sh",
|
|
11
10
|
"tsconfig.json",
|
|
12
11
|
"openclaw.plugin.json"
|
|
13
12
|
],
|
package/install.sh
DELETED
|
@@ -1,298 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
|
|
3
|
-
# Friday Next plugin installer — one-click setup for the friday-next channel
|
|
4
|
-
# Usage:
|
|
5
|
-
# ./install.sh [plugin-dir]
|
|
6
|
-
# curl -fsSL https://raw.githubusercontent.com/SyengUp/openclaw-fridaynext-channel/main/install.sh | bash
|
|
7
|
-
|
|
8
|
-
set -e
|
|
9
|
-
|
|
10
|
-
PLUGIN_DIR="${1:-$HOME/.openclaw/extensions/friday-channel-next}"
|
|
11
|
-
OPENCLAW_CONFIG="$HOME/.openclaw/openclaw.json"
|
|
12
|
-
|
|
13
|
-
RED='\033[0;31m'
|
|
14
|
-
GREEN='\033[0;32m'
|
|
15
|
-
YELLOW='\033[1;33m'
|
|
16
|
-
NC='\033[0m'
|
|
17
|
-
|
|
18
|
-
log() { printf " %s\\n" "$1"; }
|
|
19
|
-
warn() { printf " ${YELLOW}!${NC} %s\\n" "$1"; }
|
|
20
|
-
err() { printf " ${RED}X${NC} %s\\n" "$1" >&2; }
|
|
21
|
-
|
|
22
|
-
trap 'err "Install failed."' ERR
|
|
23
|
-
|
|
24
|
-
# Check prerequisites
|
|
25
|
-
for cmd in node git openclaw; do
|
|
26
|
-
if ! command -v "$cmd" &>/dev/null; then
|
|
27
|
-
err "$cmd is required but not found. Install it first."
|
|
28
|
-
exit 1
|
|
29
|
-
fi
|
|
30
|
-
done
|
|
31
|
-
|
|
32
|
-
# Auto-detect package manager (prefer pnpm, fall back to npm)
|
|
33
|
-
if command -v pnpm &>/dev/null; then
|
|
34
|
-
PKG="pnpm"
|
|
35
|
-
elif command -v npm &>/dev/null; then
|
|
36
|
-
PKG="npm"
|
|
37
|
-
else
|
|
38
|
-
err "pnpm or npm is required but not found. Install one first."
|
|
39
|
-
exit 1
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
# Auto-detect best registry (measure latency; fall back to npmmirror if slow/unreachable)
|
|
43
|
-
TIME=$(curl -s -o /dev/null -w '%{time_total}' --connect-timeout 2 --max-time 4 https://registry.npmjs.org/ 2>/dev/null || echo "999")
|
|
44
|
-
case "$TIME" in
|
|
45
|
-
0.*) ;; # under 1s — fast enough
|
|
46
|
-
*)
|
|
47
|
-
warn "Default registry slow/unreachable, using https://registry.npmmirror.com"
|
|
48
|
-
REGISTRY="--registry=https://registry.npmmirror.com"
|
|
49
|
-
;;
|
|
50
|
-
esac
|
|
51
|
-
|
|
52
|
-
if [ ! -f "$OPENCLAW_CONFIG" ]; then
|
|
53
|
-
err "OpenClaw config not found at $OPENCLAW_CONFIG"
|
|
54
|
-
err "Make sure OpenClaw is installed and has been run at least once."
|
|
55
|
-
exit 1
|
|
56
|
-
fi
|
|
57
|
-
|
|
58
|
-
# Step 1: Clone (if needed), install deps, and build
|
|
59
|
-
|
|
60
|
-
if [ -d "$PLUGIN_DIR" ]; then
|
|
61
|
-
log "Plugin directory found: $PLUGIN_DIR"
|
|
62
|
-
else
|
|
63
|
-
log "Cloning plugin to $PLUGIN_DIR ..."
|
|
64
|
-
REPO_URL="${FRIDAY_NEXT_REPO:-https://github.com/SyengUp/openclaw-fridaynext-channel.git}"
|
|
65
|
-
git clone "$REPO_URL" "$PLUGIN_DIR"
|
|
66
|
-
fi
|
|
67
|
-
|
|
68
|
-
cd "$PLUGIN_DIR"
|
|
69
|
-
|
|
70
|
-
log "Installing dependencies..."
|
|
71
|
-
$PKG install $REGISTRY
|
|
72
|
-
|
|
73
|
-
log "Building TypeScript..."
|
|
74
|
-
$PKG run build
|
|
75
|
-
|
|
76
|
-
# Step 2: Configure OpenClaw
|
|
77
|
-
|
|
78
|
-
log "Configuring OpenClaw..."
|
|
79
|
-
|
|
80
|
-
node --input-type=module -e '
|
|
81
|
-
import fs from "node:fs";
|
|
82
|
-
|
|
83
|
-
const configPath = process.argv[1];
|
|
84
|
-
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
85
|
-
|
|
86
|
-
if (!config.plugins) config.plugins = {};
|
|
87
|
-
if (!Array.isArray(config.plugins.allow)) config.plugins.allow = [];
|
|
88
|
-
if (!config.plugins.allow.includes("friday-next")) {
|
|
89
|
-
config.plugins.allow.push("friday-next");
|
|
90
|
-
console.log(" + Added friday-next to plugins.allow");
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (!config.plugins.entries) config.plugins.entries = {};
|
|
94
|
-
if (!config.plugins.entries["friday-next"]) {
|
|
95
|
-
config.plugins.entries["friday-next"] = { enabled: true };
|
|
96
|
-
console.log(" + Added friday-next to plugins.entries (enabled)");
|
|
97
|
-
} else if (!config.plugins.entries["friday-next"].enabled) {
|
|
98
|
-
config.plugins.entries["friday-next"].enabled = true;
|
|
99
|
-
console.log(" + Enabled friday-next in plugins.entries");
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (!config.channels) config.channels = {};
|
|
103
|
-
if (!config.channels["friday-next"]) {
|
|
104
|
-
config.channels["friday-next"] = { enabled: true, transport: "http+sse" };
|
|
105
|
-
console.log(" + Added friday-next channel config (auth defaults to gateway token)");
|
|
106
|
-
} else {
|
|
107
|
-
if (!config.channels["friday-next"].enabled) {
|
|
108
|
-
config.channels["friday-next"].enabled = true;
|
|
109
|
-
console.log(" + Enabled friday-next channel");
|
|
110
|
-
}
|
|
111
|
-
if (!config.channels["friday-next"].transport) {
|
|
112
|
-
config.channels["friday-next"].transport = "http+sse";
|
|
113
|
-
console.log(" + Set friday-next transport to http+sse");
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (!config.gateway) config.gateway = {};
|
|
118
|
-
if (config.gateway.bind !== "lan") {
|
|
119
|
-
config.gateway.bind = "lan";
|
|
120
|
-
console.log(" + Set gateway.bind to lan");
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
124
|
-
console.log(" Config updated.");
|
|
125
|
-
' "$OPENCLAW_CONFIG"
|
|
126
|
-
|
|
127
|
-
# Step 3: Restart gateway
|
|
128
|
-
|
|
129
|
-
log "Restarting OpenClaw gateway..."
|
|
130
|
-
openclaw gateway restart
|
|
131
|
-
|
|
132
|
-
# Verify gateway is up
|
|
133
|
-
log "Verifying gateway..."
|
|
134
|
-
VERIFY_LOG=$(mktemp)
|
|
135
|
-
node --input-type=module -e '
|
|
136
|
-
import { readFileSync } from "node:fs";
|
|
137
|
-
import { networkInterfaces } from "node:os";
|
|
138
|
-
import http from "node:http";
|
|
139
|
-
|
|
140
|
-
const config = JSON.parse(readFileSync(process.argv[1], "utf8"));
|
|
141
|
-
|
|
142
|
-
function getLanIp() {
|
|
143
|
-
const nets = networkInterfaces();
|
|
144
|
-
for (const name of Object.keys(nets)) {
|
|
145
|
-
for (const net of nets[name]) {
|
|
146
|
-
if (net.family === "IPv4" && !net.internal) return net.address;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
return "127.0.0.1";
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const port = config.gateway?.port || 18789;
|
|
153
|
-
const token = config.gateway?.auth?.token || "";
|
|
154
|
-
const bind = config.gateway?.bind || "localhost";
|
|
155
|
-
const host = bind === "lan" ? getLanIp() : "127.0.0.1";
|
|
156
|
-
|
|
157
|
-
let ok = false;
|
|
158
|
-
async function verifyGateway() {
|
|
159
|
-
for (let i = 1; i <= 6; i++) {
|
|
160
|
-
await new Promise((r) => setTimeout(r, 1000));
|
|
161
|
-
try {
|
|
162
|
-
const res = await new Promise((resolve, reject) => {
|
|
163
|
-
const req = http.request(
|
|
164
|
-
{ hostname: host, port, path: "/friday-next/status", method: "GET",
|
|
165
|
-
headers: { authorization: "Bearer " + token }, timeout: 5000 },
|
|
166
|
-
(res) => { let body = ""; res.on("data", (c) => body += c); res.on("end", () => resolve({ status: res.statusCode, body })); },
|
|
167
|
-
);
|
|
168
|
-
req.on("error", reject);
|
|
169
|
-
req.on("timeout", () => { req.destroy(); reject(new Error("timeout")); });
|
|
170
|
-
req.end();
|
|
171
|
-
});
|
|
172
|
-
if (res.status === 200) {
|
|
173
|
-
try {
|
|
174
|
-
const data = JSON.parse(res.body);
|
|
175
|
-
if (data.ok) {
|
|
176
|
-
console.log(" Gateway verified OK (friday-next " + data.version + ", " + data.connections + " connections).");
|
|
177
|
-
ok = true;
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
console.log(" ! Plugin responded but ok=false — " + JSON.stringify(data));
|
|
181
|
-
return;
|
|
182
|
-
} catch {
|
|
183
|
-
if (i < 3) {
|
|
184
|
-
console.log(" ! Plugin routes not registered yet, retrying (" + i + "/6)...");
|
|
185
|
-
} else if (i < 6) {
|
|
186
|
-
console.log(" ! Gateway is up but plugin routes missing — may need config reload, retrying (" + i + "/6)...");
|
|
187
|
-
} else {
|
|
188
|
-
console.log(" ! Gateway is running but plugin routes were not loaded. Check plugin config in openclaw.json.");
|
|
189
|
-
}
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
if (res.status === 401) {
|
|
194
|
-
console.log(" ! Auth token mismatch — check gateway.auth.token in openclaw.json.");
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
if (res.status === 404) {
|
|
198
|
-
console.log(" ! Route /friday-next/status not found — plugin may not be loaded.");
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
if (i < 6) console.log(" ! Gateway responded " + res.status + ", retrying (" + i + "/6)...");
|
|
202
|
-
} catch {
|
|
203
|
-
if (i < 6) console.log(" ! Gateway not reachable, retrying (" + i + "/6)...");
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
console.log(" ! Gateway verification timed out — check '\''openclaw gateway status'\'' manually.");
|
|
207
|
-
}
|
|
208
|
-
await verifyGateway();
|
|
209
|
-
console.log(ok ? "VERIFY_OK" : "VERIFY_FAIL");
|
|
210
|
-
' "$OPENCLAW_CONFIG" 2>&1 | tee "$VERIFY_LOG"
|
|
211
|
-
if grep -q "VERIFY_OK" "$VERIFY_LOG"; then
|
|
212
|
-
VERIFY_PASS=1
|
|
213
|
-
else
|
|
214
|
-
VERIFY_PASS=0
|
|
215
|
-
fi
|
|
216
|
-
rm -f "$VERIFY_LOG"
|
|
217
|
-
|
|
218
|
-
# Show connection info
|
|
219
|
-
node --input-type=module -e '
|
|
220
|
-
import { readFileSync } from "node:fs";
|
|
221
|
-
import { networkInterfaces } from "node:os";
|
|
222
|
-
|
|
223
|
-
const config = JSON.parse(readFileSync(process.argv[1], "utf8"));
|
|
224
|
-
|
|
225
|
-
function getLanIp() {
|
|
226
|
-
const nets = networkInterfaces();
|
|
227
|
-
for (const name of Object.keys(nets)) {
|
|
228
|
-
for (const net of nets[name]) {
|
|
229
|
-
if (net.family === "IPv4" && !net.internal) return net.address;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
return "127.0.0.1";
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const port = config.gateway?.port || 18789;
|
|
236
|
-
const token = config.gateway?.auth?.token || "(not set)";
|
|
237
|
-
const bind = config.gateway?.bind || "localhost";
|
|
238
|
-
const host = bind === "lan" ? getLanIp() : "127.0.0.1";
|
|
239
|
-
|
|
240
|
-
const YB = "\x1b[1;33m", N = "\x1b[0m";
|
|
241
|
-
const qrPayload = JSON.stringify({ url: "http://" + host + ":" + port, token: token });
|
|
242
|
-
let qrShown = false;
|
|
243
|
-
try {
|
|
244
|
-
const { createRequire } = await import("node:module");
|
|
245
|
-
const qrcode = createRequire(import.meta.url)("qrcode-terminal");
|
|
246
|
-
console.log("");
|
|
247
|
-
console.log(YB + "Scan below to auto-fill URL & Token in FridayNext app:" + N);
|
|
248
|
-
console.log(YB + "扫描下方二维码自动填入 URL 和 Token:" + N);
|
|
249
|
-
console.log("");
|
|
250
|
-
qrcode.generate(qrPayload, { small: true });
|
|
251
|
-
console.log("");
|
|
252
|
-
console.log("If QR scan does not work, enter manually:");
|
|
253
|
-
console.log("若二维码无法使用,请手动输入:");
|
|
254
|
-
qrShown = true;
|
|
255
|
-
} catch {}
|
|
256
|
-
if (!qrShown) {
|
|
257
|
-
console.log("");
|
|
258
|
-
console.log(YB + "Input the URL and Token below into your FridayNext app to connect." + N);
|
|
259
|
-
console.log(YB + "请将下方 URL 和 Token 输入至 FridayNext App 完成连接。" + N);
|
|
260
|
-
}
|
|
261
|
-
console.log("");
|
|
262
|
-
console.log("Gateway URL: " + YB + "http://" + host + ":" + port + N);
|
|
263
|
-
console.log("Bearer Token: " + YB + token + N);
|
|
264
|
-
console.log("");
|
|
265
|
-
function classifyIp(ip) {
|
|
266
|
-
var p = ip.split(".").map(Number);
|
|
267
|
-
if (p[0] === 100 && p[1] >= 64 && p[1] <= 127) return "tailscale";
|
|
268
|
-
if (p[0] === 127) return "loopback";
|
|
269
|
-
if (p[0] === 10) return "private";
|
|
270
|
-
if (p[0] === 172 && p[1] >= 16 && p[1] <= 31) return "private";
|
|
271
|
-
if (p[0] === 192 && p[1] === 168) return "private";
|
|
272
|
-
if (p[0] === 169 && p[1] === 254) return "private";
|
|
273
|
-
return "public";
|
|
274
|
-
}
|
|
275
|
-
if (classifyIp(host) === "tailscale") {
|
|
276
|
-
console.log("This is a Tailscale network URL (" + host + ").");
|
|
277
|
-
console.log("Accessible from your Tailnet devices.");
|
|
278
|
-
} else if (classifyIp(host) === "private") {
|
|
279
|
-
console.log("This is a LOCAL network URL (" + host + ", bind=" + bind + ").");
|
|
280
|
-
console.log("If you need public access, configure HTTPS, Tailscale, or a reverse proxy.");
|
|
281
|
-
} else if (classifyIp(host) === "loopback") {
|
|
282
|
-
console.log("This is a LOOPBACK URL (" + host + ").");
|
|
283
|
-
console.log("Only accessible from this machine.");
|
|
284
|
-
} else {
|
|
285
|
-
console.log("This URL appears to be publicly accessible (" + host + ").");
|
|
286
|
-
}
|
|
287
|
-
' "$OPENCLAW_CONFIG"
|
|
288
|
-
|
|
289
|
-
log "--------------------------------------------------"
|
|
290
|
-
if [ "$VERIFY_PASS" = "1" ]; then
|
|
291
|
-
log "Installation complete! Friday Next channel is now active."
|
|
292
|
-
else
|
|
293
|
-
warn "Installation complete, but gateway verification failed."
|
|
294
|
-
warn "Check 'openclaw gateway status' and restart the gateway if needed."
|
|
295
|
-
warn "Also ensure OpenClaw is updated to 2026.5.7 or above: openclaw update"
|
|
296
|
-
warn "同时请确认 OpenClaw 已升级至 2026.5.7 或以上版本:openclaw update"
|
|
297
|
-
fi
|
|
298
|
-
log "--------------------------------------------------"
|