@syengup/friday-channel-next 0.0.37 → 0.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +10 -4
- package/index.ts +10 -4
- package/install.js +132 -257
- package/package.json +1 -1
- package/dist/attachments/0768c9b1-53b0-44df-83e8-be15c4ea188f.jpg +0 -0
- package/dist/attachments/0a379d01-116b-4da1-bf15-77cb2cbb0093.jpg +0 -0
- package/dist/attachments/181caab2-64a7-4004-a057-225a144f949e.mp3 +0 -0
- package/dist/attachments/19662331-e527-47d2-bc0e-0e19a7a91419.jpg +0 -0
- package/dist/attachments/26a23b2b-52df-4572-a5e1-15b34fb87e44.jpg +0 -0
- package/dist/attachments/2f9282c5-8db4-4c4a-a060-e65104f6f9ff.jpg +0 -0
- package/dist/attachments/3929ec3d-ea15-4de6-96bc-97e8b0b658a7.jpg +0 -0
- package/dist/attachments/403c0cbc-4e3c-4146-a3be-ff3746ee7cda.jpg +0 -0
- package/dist/attachments/441977f5-0f7b-4aa2-841a-1d63e787ea53.jpg +0 -0
- package/dist/attachments/453e8aa2-76e3-498d-8d6f-d7b96d6bf45b.jpg +0 -0
- package/dist/attachments/538cde71-d26e-4d3d-b901-e8dd905e668c.mp3 +0 -0
- package/dist/attachments/55c7f628-4ba2-4252-aa4b-4f3eb6045a8a.mp3 +0 -0
- package/dist/attachments/5f7683f5-8194-4698-b077-31d209525379.jpg +0 -0
- package/dist/attachments/60614a35-8f44-4197-b783-2f58f5a72ac8.jpeg +0 -0
- package/dist/attachments/62830489-8814-48b1-851c-3845e514f35e.mp3 +0 -0
- package/dist/attachments/66f4a62d-1531-4f38-a531-7456f9edf221.png +0 -0
- package/dist/attachments/6735d749-769e-483a-9b84-43b9338a720b.png +0 -0
- package/dist/attachments/6d1766b1-05e4-4b04-b3c8-1c25e9d182a1.png +0 -0
- package/dist/attachments/782b077b-06e3-484b-baf5-33e7160234ed.png +0 -0
- package/dist/attachments/7ad638b2-1f56-4d93-9ad8-b40346e0650f.jpg +0 -0
- package/dist/attachments/89f6fb15-e652-4111-a60c-baa414659052.png +0 -0
- package/dist/attachments/8a88b14f-442f-45fb-b01d-e51bab8f800d.mp3 +0 -0
- package/dist/attachments/92292034-9cf6-4f26-8d77-fddca3deb638.png +0 -0
- package/dist/attachments/92c2b414-d33d-4d93-bcb6-013da7bec9a4.jpg +0 -0
- package/dist/attachments/9664f69e-3c05-45ca-9a52-f2d0b9f9bf7e.jpg +0 -0
- package/dist/attachments/977d28c1-43c0-40e0-95e3-defe0f41afe8.jpg +0 -0
- package/dist/attachments/9df40f1a-c6e1-4177-8a03-06757a30b19e.png +0 -0
- package/dist/attachments/a68e6815-6163-4421-a70f-34493aa9a217.jpg +0 -0
- package/dist/attachments/aab32fea-6d99-47ec-ab1f-2340f31312eb.jpg +0 -0
- package/dist/attachments/ab403224-2fb1-49c1-8738-ea194ab65d44.png +0 -0
- package/dist/attachments/ac3da190-d6ee-4038-a673-8b893035a687.png +0 -0
- package/dist/attachments/af02be9c-87f7-4c5a-9969-7db32039bb58.png +0 -0
- package/dist/attachments/b011d42a-00e5-4f77-86bc-08da6112e6e1.mp3 +0 -0
- package/dist/attachments/b7d7df40-c627-4b1f-9b09-167b88545c25.mp3 +0 -0
- package/dist/attachments/c5e9bf09-a718-422c-bcb3-94c173e3755b.mp3 +0 -0
- package/dist/attachments/d5449e13-1995-44ba-9392-ecbfe5f9876f.jpg +0 -0
- package/dist/attachments/ea0069f5-01cf-4ea1-985e-3a1e426399c3.png +0 -0
- package/dist/attachments/f3989ff2-7b70-4a80-a896-74a6b197f7d8.png +0 -0
- package/dist/attachments/f64a4a14-e3aa-4eed-a8d9-1603f04baa5b.jpg +0 -0
- package/dist/src/http/handlers/device-token.d.ts +0 -2
- package/dist/src/http/handlers/device-token.js +0 -43
- package/dist/src/http/handlers/import.d.ts +0 -7
- package/dist/src/http/handlers/import.js +0 -69
- package/dist/src/http/handlers/info.d.ts +0 -2
- package/dist/src/http/handlers/info.js +0 -13
- package/dist/src/http/handlers/messages-list.d.ts +0 -7
- package/dist/src/http/handlers/messages-list.js +0 -44
- package/dist/src/http/handlers/pair.d.ts +0 -2
- package/dist/src/http/handlers/pair.js +0 -39
- package/dist/src/http/handlers/sessions-list.d.ts +0 -8
- package/dist/src/http/handlers/sessions-list.js +0 -24
- package/dist/src/http/handlers/sessions-messages-get.d.ts +0 -2
- package/dist/src/http/handlers/sessions-messages-get.js +0 -55
- package/dist/src/http/handlers/sessions-messages-post.d.ts +0 -2
- package/dist/src/http/handlers/sessions-messages-post.js +0 -92
- package/dist/src/http/handlers/sessions-messages.d.ts +0 -2
- package/dist/src/http/handlers/sessions-messages.js +0 -135
- package/dist/src/http/handlers/sync.d.ts +0 -7
- package/dist/src/http/handlers/sync.js +0 -56
- package/dist/src/push/apns.d.ts +0 -15
- package/dist/src/push/apns.js +0 -56
- package/dist/src/push/device-tokens.d.ts +0 -3
- package/dist/src/push/device-tokens.js +0 -39
- package/dist/src/sync/account-identity.d.ts +0 -14
- package/dist/src/sync/account-identity.js +0 -101
- package/dist/src/sync/archive.d.ts +0 -9
- package/dist/src/sync/archive.js +0 -25
- package/dist/src/sync/database.d.ts +0 -66
- package/dist/src/sync/database.js +0 -364
- package/dist/src/sync/init.d.ts +0 -3
- package/dist/src/sync/init.js +0 -14
- package/dist/src/sync/installation-id.d.ts +0 -1
- package/dist/src/sync/installation-id.js +0 -41
- package/dist/src/sync/message-accumulator.d.ts +0 -29
- package/dist/src/sync/message-accumulator.js +0 -188
- package/dist/src/sync/message-store.d.ts +0 -68
- package/dist/src/sync/message-store.js +0 -262
- package/dist/src/sync/push-store.d.ts +0 -5
- package/dist/src/sync/push-store.js +0 -54
- package/dist/src/sync/session-key.d.ts +0 -12
- package/dist/src/sync/session-key.js +0 -47
- package/dist/src/sync/sync-state.d.ts +0 -5
- package/dist/src/sync/sync-state.js +0 -54
- package/dist/src/sync/transcript-archive.d.ts +0 -13
- package/dist/src/sync/transcript-archive.js +0 -37
- package/dist/src/sync/transcript-store.d.ts +0 -35
- package/dist/src/sync/transcript-store.js +0 -221
- package/dist/src/sync/translate.d.ts +0 -42
- package/dist/src/sync/translate.js +0 -171
package/dist/index.js
CHANGED
|
@@ -14,8 +14,13 @@ export { setFridayNextRuntime } from "./src/runtime.js";
|
|
|
14
14
|
/** `api.on` returns void — register tool hooks at most once per process. */
|
|
15
15
|
let fridayNextToolHooksRegistered = false;
|
|
16
16
|
let disposeAgentEventListener = null;
|
|
17
|
-
/**
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Track the last `api` instance on which HTTP routes were registered.
|
|
19
|
+
* When the health-monitor restarts the plugin, `registerFull` receives a fresh `api` whose
|
|
20
|
+
* old routes are gone — we must re-register. A WeakRef lets us distinguish "same api,
|
|
21
|
+
* re-entered" (skip) from "new api after restart" (re-register).
|
|
22
|
+
*/
|
|
23
|
+
let lastApiRoutesRegistered = null;
|
|
19
24
|
function deviceIdFromToolContext(ctx) {
|
|
20
25
|
if (ctx.runId) {
|
|
21
26
|
const d = sseEmitter.getDeviceIdByRunId(ctx.runId);
|
|
@@ -70,8 +75,9 @@ export default defineChannelPluginEntry({
|
|
|
70
75
|
setRuntime: setFridayNextRuntime,
|
|
71
76
|
registerFull: (api) => {
|
|
72
77
|
setFridayAgentForwardRuntime(api);
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
const sameApi = lastApiRoutesRegistered?.deref() === api;
|
|
79
|
+
if (!sameApi) {
|
|
80
|
+
lastApiRoutesRegistered = new WeakRef(api);
|
|
75
81
|
registerFridayNextHttpRoutes(api);
|
|
76
82
|
}
|
|
77
83
|
else {
|
package/index.ts
CHANGED
|
@@ -23,8 +23,13 @@ export { setFridayNextRuntime } from "./src/runtime.js";
|
|
|
23
23
|
/** `api.on` returns void — register tool hooks at most once per process. */
|
|
24
24
|
let fridayNextToolHooksRegistered = false;
|
|
25
25
|
let disposeAgentEventListener: (() => void) | null = null;
|
|
26
|
-
/**
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Track the last `api` instance on which HTTP routes were registered.
|
|
28
|
+
* When the health-monitor restarts the plugin, `registerFull` receives a fresh `api` whose
|
|
29
|
+
* old routes are gone — we must re-register. A WeakRef lets us distinguish "same api,
|
|
30
|
+
* re-entered" (skip) from "new api after restart" (re-register).
|
|
31
|
+
*/
|
|
32
|
+
let lastApiRoutesRegistered: WeakRef<OpenClawPluginApi> | null = null;
|
|
28
33
|
|
|
29
34
|
function deviceIdFromToolContext(ctx: PluginHookToolContext): string | null {
|
|
30
35
|
if (ctx.runId) {
|
|
@@ -77,8 +82,9 @@ export default defineChannelPluginEntry({
|
|
|
77
82
|
setRuntime: setFridayNextRuntime,
|
|
78
83
|
registerFull: (api: OpenClawPluginApi) => {
|
|
79
84
|
setFridayAgentForwardRuntime(api);
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
const sameApi = lastApiRoutesRegistered?.deref() === api;
|
|
86
|
+
if (!sameApi) {
|
|
87
|
+
lastApiRoutesRegistered = new WeakRef(api);
|
|
82
88
|
registerFridayNextHttpRoutes(api);
|
|
83
89
|
} else {
|
|
84
90
|
const cfg = resolveFridayNextConfig(getHostOpenClawConfigSnapshot(getFridayNextRuntime().config));
|
package/install.js
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
|
-
import {
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { homedir, networkInterfaces } from "node:os";
|
|
5
|
-
import {
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
-
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = dirname(__filename);
|
|
5
|
+
import { join } from "node:path";
|
|
10
6
|
|
|
11
7
|
const sudoUser = process.env.SUDO_USER;
|
|
12
8
|
|
|
13
9
|
function realHome() {
|
|
14
10
|
if (!sudoUser) return homedir();
|
|
15
|
-
// Under sudo, homedir() may return /root. Check if HOME was preserved.
|
|
16
11
|
const current = homedir();
|
|
17
12
|
if (current !== "/root" && current !== "/var/root" && existsSync(current)) return current;
|
|
18
|
-
// Resolve the real user's home
|
|
19
13
|
try {
|
|
20
14
|
const h = execSync(`sh -c 'echo ~${sudoUser}'`, { encoding: "utf8" }).trim();
|
|
21
15
|
if (h && !h.startsWith("~") && existsSync(h)) return h;
|
|
@@ -27,30 +21,18 @@ function realHome() {
|
|
|
27
21
|
}
|
|
28
22
|
|
|
29
23
|
const USER_HOME = realHome();
|
|
30
|
-
const PLUGIN_DIR = process.argv[2] || join(USER_HOME, ".openclaw", "extensions", "friday-channel-next");
|
|
31
24
|
const OPENCLAW_CONFIG = join(USER_HOME, ".openclaw", "openclaw.json");
|
|
32
|
-
const REPO_URL = process.env.FRIDAY_NEXT_REPO || "https://github.com/SyengUp/openclaw-fridaynext-channel.git";
|
|
33
25
|
|
|
34
26
|
const G = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
35
27
|
const Y = (s) => `\x1b[33m${s}\x1b[0m`;
|
|
36
28
|
const R = (s) => `\x1b[31m${s}\x1b[0m`;
|
|
37
|
-
function log(msg) {
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
function warn(msg) {
|
|
41
|
-
console.log(` ${Y("!")} ${msg}`);
|
|
42
|
-
}
|
|
43
|
-
function err(msg) {
|
|
44
|
-
console.error(` ${R("X")} ${msg}`);
|
|
45
|
-
}
|
|
29
|
+
function log(msg) { console.log(` ${msg}`); }
|
|
30
|
+
function warn(msg) { console.log(` ${Y("!")} ${msg}`); }
|
|
31
|
+
function err(msg) { console.error(` ${R("X")} ${msg}`); }
|
|
46
32
|
|
|
47
33
|
function has(cmd) {
|
|
48
|
-
try {
|
|
49
|
-
|
|
50
|
-
return true;
|
|
51
|
-
} catch {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
34
|
+
try { execSync(`${cmd} --version`, { stdio: "ignore" }); return true; }
|
|
35
|
+
catch { return false; }
|
|
54
36
|
}
|
|
55
37
|
|
|
56
38
|
let openclawCmd = "openclaw";
|
|
@@ -58,7 +40,6 @@ let openclawCmd = "openclaw";
|
|
|
58
40
|
function hasOpenclaw() {
|
|
59
41
|
if (has("openclaw")) return true;
|
|
60
42
|
if (!sudoUser) return false;
|
|
61
|
-
// Under sudo, openclaw isn't in root's PATH — run via the real user.
|
|
62
43
|
try {
|
|
63
44
|
execSync(`sudo -u "${sudoUser}" openclaw --version`, { stdio: "ignore" });
|
|
64
45
|
openclawCmd = `sudo -u "${sudoUser}" openclaw`;
|
|
@@ -67,16 +48,6 @@ function hasOpenclaw() {
|
|
|
67
48
|
return false;
|
|
68
49
|
}
|
|
69
50
|
|
|
70
|
-
// Running from an npm/npx package when we have the full source (index.ts + package.json)
|
|
71
|
-
// and are NOT already inside the target plugin dir.
|
|
72
|
-
function isRunningFromNpmPackage() {
|
|
73
|
-
return (
|
|
74
|
-
resolve(__dirname) !== resolve(PLUGIN_DIR) &&
|
|
75
|
-
existsSync(join(__dirname, "package.json")) &&
|
|
76
|
-
existsSync(join(__dirname, "index.ts"))
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
51
|
// --------------- prerequisites ---------------
|
|
81
52
|
|
|
82
53
|
if (sudoUser) {
|
|
@@ -84,15 +55,12 @@ if (sudoUser) {
|
|
|
84
55
|
warn("If possible, run without sudo: npx -y @syengup/friday-channel-next");
|
|
85
56
|
}
|
|
86
57
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
err("Could not find openclaw even via the real user's PATH.");
|
|
94
|
-
err(`Check that openclaw is installed under ${USER_HOME}.`);
|
|
95
|
-
}
|
|
58
|
+
if (!has("node")) {
|
|
59
|
+
err("node is required but not found. Install it first.");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
if (!hasOpenclaw()) {
|
|
63
|
+
err("openclaw is required but not found. Install OpenClaw first: https://docs.openclaw.ai");
|
|
96
64
|
process.exit(1);
|
|
97
65
|
}
|
|
98
66
|
|
|
@@ -113,219 +81,149 @@ if (missing.length) {
|
|
|
113
81
|
err(`OpenClaw version ${m[0]} is too old.`);
|
|
114
82
|
err(`Friday Next channel requires OpenClaw 2026.5.12 or above.`);
|
|
115
83
|
err(`Please update: ${openclawCmd} update`);
|
|
116
|
-
err(`请先升级 OpenClaw 至 2026.5.12 或以上版本:${openclawCmd} update`);
|
|
117
84
|
process.exit(1);
|
|
118
85
|
}
|
|
119
86
|
}
|
|
120
87
|
} catch {
|
|
121
|
-
// If version check itself fails, don't block — continue with a warning
|
|
122
88
|
warn("Could not determine OpenClaw version — continuing anyway.");
|
|
123
89
|
}
|
|
124
90
|
}
|
|
125
91
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
92
|
+
// --------------- install via openclaw plugins ---------------
|
|
93
|
+
|
|
94
|
+
log("Installing Friday Next channel via openclaw plugins...");
|
|
95
|
+
let installed = false;
|
|
131
96
|
|
|
132
|
-
// Auto-detect best registry (measure latency; fall back to npmmirror if slow/unreachable)
|
|
133
|
-
let registryFlag = "";
|
|
134
97
|
try {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
98
|
+
// --dangerously-force-unsafe-install needed for child_process in device-approve / nodes-approve
|
|
99
|
+
const out = execSync(
|
|
100
|
+
`${openclawCmd} plugins install --dangerously-force-unsafe-install @syengup/friday-channel-next@latest`,
|
|
101
|
+
{ encoding: "utf8", stdio: "pipe", timeout: 120000 }
|
|
102
|
+
);
|
|
103
|
+
if (out.trim()) console.log(out.trim());
|
|
104
|
+
installed = true;
|
|
105
|
+
log("Plugin registered with install record — auto-upgrade enabled.");
|
|
106
|
+
} catch (e) {
|
|
107
|
+
const msg = (e.stderr || e.stdout || e.message || "").toString();
|
|
108
|
+
warn("openclaw plugins install failed: " + msg.trim().split("\n").pop());
|
|
109
|
+
warn("Falling back to manual install...");
|
|
144
110
|
}
|
|
145
111
|
|
|
146
|
-
|
|
147
|
-
err(`OpenClaw config not found at ${OPENCLAW_CONFIG}`);
|
|
148
|
-
err("Make sure OpenClaw is installed and has been run at least once.");
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
112
|
+
// --------------- fallback: manual install ---------------
|
|
151
113
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
cpSync(__dirname, PLUGIN_DIR, {
|
|
157
|
-
recursive: true,
|
|
158
|
-
filter: (src) => {
|
|
159
|
-
const rel = relative(__dirname, src);
|
|
160
|
-
if (rel === "") return true; // root dir
|
|
161
|
-
const top = rel.split(sep)[0];
|
|
162
|
-
return ![".git", "node_modules", "dist", "attachments", ".claude"].includes(top);
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
} else if (existsSync(PLUGIN_DIR)) {
|
|
166
|
-
log(`Plugin directory found: ${PLUGIN_DIR}`);
|
|
167
|
-
if (existsSync(join(PLUGIN_DIR, ".git"))) {
|
|
168
|
-
try {
|
|
169
|
-
log("Pulling latest changes...");
|
|
170
|
-
execSync("git fetch origin && git checkout -f origin/main", { cwd: PLUGIN_DIR, stdio: "pipe" });
|
|
171
|
-
log("Updated to latest version.");
|
|
172
|
-
} catch {
|
|
173
|
-
warn("Could not update from git — continuing with existing source.");
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
} else {
|
|
177
|
-
if (!has("git")) {
|
|
178
|
-
err("git is required for installation from GitHub. Install git first or use npx @openclaw/friday-channel-next.");
|
|
114
|
+
if (!installed) {
|
|
115
|
+
const PKG = has("npm") ? "npm" : has("pnpm") ? "pnpm" : null;
|
|
116
|
+
if (!PKG) {
|
|
117
|
+
err("npm is required for manual install. Install Node.js first.");
|
|
179
118
|
process.exit(1);
|
|
180
119
|
}
|
|
181
|
-
log(`Cloning plugin to ${PLUGIN_DIR} ...`);
|
|
182
|
-
execSync(`git clone "${REPO_URL}" "${PLUGIN_DIR}"`, { stdio: "inherit" });
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
process.chdir(PLUGIN_DIR);
|
|
186
120
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
} catch {
|
|
193
|
-
err("Dependency installation failed.");
|
|
194
|
-
err("Check your network connection and try again.");
|
|
195
|
-
if (sudoUser) err("If running under sudo, ensure the real user can access the package manager.");
|
|
196
|
-
process.exit(1);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
log("Building TypeScript...");
|
|
200
|
-
try {
|
|
201
|
-
execSync(`${PKG} run build`, { stdio: "inherit" });
|
|
202
|
-
} catch {
|
|
203
|
-
err("TypeScript build failed.");
|
|
204
|
-
err("Check the compilation errors above and make sure the package is not corrupted.");
|
|
205
|
-
process.exit(1);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// --------------- configure OpenClaw ---------------
|
|
209
|
-
|
|
210
|
-
log("Configuring OpenClaw...");
|
|
121
|
+
if (!existsSync(OPENCLAW_CONFIG)) {
|
|
122
|
+
err(`OpenClaw config not found at ${OPENCLAW_CONFIG}`);
|
|
123
|
+
err("Run openclaw at least once before installing plugins.");
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
211
126
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
config = JSON.parse(readFileSync(OPENCLAW_CONFIG, "utf8"));
|
|
215
|
-
} catch {
|
|
216
|
-
err(`Failed to read ${OPENCLAW_CONFIG}.`);
|
|
217
|
-
err("The file may be missing or corrupted. Verify OpenClaw is installed correctly.");
|
|
218
|
-
process.exit(1);
|
|
219
|
-
}
|
|
127
|
+
// Configure OpenClaw
|
|
128
|
+
log("Configuring OpenClaw...");
|
|
220
129
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
130
|
+
let config;
|
|
131
|
+
try {
|
|
132
|
+
config = JSON.parse(readFileSync(OPENCLAW_CONFIG, "utf8"));
|
|
133
|
+
} catch {
|
|
134
|
+
err(`Failed to read ${OPENCLAW_CONFIG}.`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
227
137
|
|
|
228
|
-
if (!config.plugins
|
|
229
|
-
if (!config.plugins.
|
|
230
|
-
config.plugins.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
console.log(" + Enabled friday-next in plugins.entries");
|
|
235
|
-
}
|
|
138
|
+
if (!config.plugins) config.plugins = {};
|
|
139
|
+
if (!Array.isArray(config.plugins.allow)) config.plugins.allow = [];
|
|
140
|
+
if (!config.plugins.allow.includes("friday-next")) {
|
|
141
|
+
config.plugins.allow.push("friday-next");
|
|
142
|
+
console.log(" + Added friday-next to plugins.allow");
|
|
143
|
+
}
|
|
236
144
|
|
|
237
|
-
if (!config.plugins.
|
|
238
|
-
config.plugins.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (!config.plugins.entries["
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
config.plugins.entries["canvas"].enabled = true;
|
|
246
|
-
console.log(" + Enabled canvas in plugins.entries");
|
|
247
|
-
}
|
|
145
|
+
if (!config.plugins.entries) config.plugins.entries = {};
|
|
146
|
+
if (!config.plugins.entries["friday-next"]) {
|
|
147
|
+
config.plugins.entries["friday-next"] = { enabled: true };
|
|
148
|
+
console.log(" + Added friday-next to plugins.entries (enabled)");
|
|
149
|
+
} else if (!config.plugins.entries["friday-next"].enabled) {
|
|
150
|
+
config.plugins.entries["friday-next"].enabled = true;
|
|
151
|
+
console.log(" + Enabled friday-next in plugins.entries");
|
|
152
|
+
}
|
|
248
153
|
|
|
249
|
-
if (!config.
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
console.log(" + Added friday-next channel config (auth defaults to gateway token)");
|
|
253
|
-
} else {
|
|
254
|
-
if (!config.channels["friday-next"].enabled) {
|
|
255
|
-
config.channels["friday-next"].enabled = true;
|
|
256
|
-
console.log(" + Enabled friday-next channel");
|
|
154
|
+
if (!config.plugins.allow.includes("canvas")) {
|
|
155
|
+
config.plugins.allow.push("canvas");
|
|
156
|
+
console.log(" + Added canvas to plugins.allow");
|
|
257
157
|
}
|
|
258
|
-
if (!config.
|
|
259
|
-
config.
|
|
260
|
-
console.log(" +
|
|
158
|
+
if (!config.plugins.entries["canvas"]) {
|
|
159
|
+
config.plugins.entries["canvas"] = { enabled: true };
|
|
160
|
+
console.log(" + Added canvas to plugins.entries (enabled)");
|
|
161
|
+
} else if (!config.plugins.entries["canvas"].enabled) {
|
|
162
|
+
config.plugins.entries["canvas"].enabled = true;
|
|
163
|
+
console.log(" + Enabled canvas in plugins.entries");
|
|
261
164
|
}
|
|
262
|
-
}
|
|
263
165
|
|
|
264
|
-
if (!config.
|
|
265
|
-
if (config.
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
if (!config.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
"
|
|
276
|
-
|
|
277
|
-
"canvas.a2ui.push",
|
|
278
|
-
"canvas.a2ui.reset",
|
|
279
|
-
"canvas.a2ui.pushJSONL",
|
|
280
|
-
]) {
|
|
281
|
-
if (!config.gateway.nodes.allowCommands.includes(cmd)) {
|
|
282
|
-
config.gateway.nodes.allowCommands.push(cmd);
|
|
283
|
-
console.log(" + Added " + cmd + " to gateway.nodes.allowCommands");
|
|
166
|
+
if (!config.channels) config.channels = {};
|
|
167
|
+
if (!config.channels["friday-next"]) {
|
|
168
|
+
config.channels["friday-next"] = { enabled: true, transport: "http+sse" };
|
|
169
|
+
console.log(" + Added friday-next channel config");
|
|
170
|
+
} else {
|
|
171
|
+
if (!config.channels["friday-next"].enabled) {
|
|
172
|
+
config.channels["friday-next"].enabled = true;
|
|
173
|
+
console.log(" + Enabled friday-next channel");
|
|
174
|
+
}
|
|
175
|
+
if (!config.channels["friday-next"].transport) {
|
|
176
|
+
config.channels["friday-next"].transport = "http+sse";
|
|
177
|
+
console.log(" + Set friday-next transport to http+sse");
|
|
178
|
+
}
|
|
284
179
|
}
|
|
285
|
-
}
|
|
286
180
|
|
|
287
|
-
|
|
288
|
-
if (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
if (!mainAgent) {
|
|
292
|
-
mainAgent = { id: "main" };
|
|
293
|
-
config.agents.list.push(mainAgent);
|
|
294
|
-
}
|
|
295
|
-
if (!mainAgent.tools) mainAgent.tools = {};
|
|
296
|
-
if (!Array.isArray(mainAgent.tools.alsoAllow)) mainAgent.tools.alsoAllow = [];
|
|
297
|
-
for (const tool of ["canvas", "nodes"]) {
|
|
298
|
-
if (!mainAgent.tools.alsoAllow.includes(tool)) {
|
|
299
|
-
mainAgent.tools.alsoAllow.push(tool);
|
|
300
|
-
console.log(" + Added " + tool + " to agent 'main' tools.alsoAllow");
|
|
181
|
+
if (!config.gateway) config.gateway = {};
|
|
182
|
+
if (config.gateway.bind !== "lan") {
|
|
183
|
+
config.gateway.bind = "lan";
|
|
184
|
+
console.log(" + Set gateway.bind to lan");
|
|
301
185
|
}
|
|
302
|
-
}
|
|
303
|
-
if (Array.isArray(
|
|
304
|
-
for (const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
186
|
+
if (!config.gateway.nodes) config.gateway.nodes = {};
|
|
187
|
+
if (!Array.isArray(config.gateway.nodes.allowCommands)) config.gateway.nodes.allowCommands = [];
|
|
188
|
+
for (const cmd of [
|
|
189
|
+
"canvas.navigate", "canvas.present", "canvas.hide", "canvas.eval",
|
|
190
|
+
"canvas.snapshot", "canvas.a2ui.push", "canvas.a2ui.reset", "canvas.a2ui.pushJSONL",
|
|
191
|
+
]) {
|
|
192
|
+
if (!config.gateway.nodes.allowCommands.includes(cmd)) {
|
|
193
|
+
config.gateway.nodes.allowCommands.push(cmd);
|
|
194
|
+
console.log(" + Added " + cmd + " to gateway.nodes.allowCommands");
|
|
309
195
|
}
|
|
310
196
|
}
|
|
311
|
-
}
|
|
312
197
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
198
|
+
if (!config.agents) config.agents = {};
|
|
199
|
+
if (!Array.isArray(config.agents.list)) config.agents.list = [];
|
|
200
|
+
let mainAgent = config.agents.list.find((a) => a.id === "main");
|
|
201
|
+
if (!mainAgent) { mainAgent = { id: "main" }; config.agents.list.push(mainAgent); }
|
|
202
|
+
if (!mainAgent.tools) mainAgent.tools = {};
|
|
203
|
+
if (!Array.isArray(mainAgent.tools.alsoAllow)) mainAgent.tools.alsoAllow = [];
|
|
204
|
+
for (const tool of ["canvas", "nodes"]) {
|
|
205
|
+
if (!mainAgent.tools.alsoAllow.includes(tool)) {
|
|
206
|
+
mainAgent.tools.alsoAllow.push(tool);
|
|
207
|
+
console.log(" + Added " + tool + " to agent 'main' tools.alsoAllow");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (Array.isArray(mainAgent.tools.deny)) {
|
|
211
|
+
for (const tool of ["canvas", "nodes"]) {
|
|
212
|
+
const idx = mainAgent.tools.deny.indexOf(tool);
|
|
213
|
+
if (idx !== -1) { mainAgent.tools.deny.splice(idx, 1); console.log(" - Removed " + tool + " from agent 'main' tools.deny"); }
|
|
214
|
+
}
|
|
215
|
+
}
|
|
321
216
|
|
|
322
|
-
if (sudoUser) {
|
|
323
217
|
try {
|
|
324
|
-
|
|
325
|
-
log("
|
|
218
|
+
writeFileSync(OPENCLAW_CONFIG, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
219
|
+
console.log(" Config updated.");
|
|
326
220
|
} catch {
|
|
327
|
-
|
|
221
|
+
err(`Failed to write ${OPENCLAW_CONFIG}.`);
|
|
222
|
+
process.exit(1);
|
|
328
223
|
}
|
|
224
|
+
|
|
225
|
+
warn("Manual install complete, but auto-upgrade is not available.");
|
|
226
|
+
warn("To enable auto-upgrade, run: openclaw plugins install --dangerously-force-unsafe-install @syengup/friday-channel-next");
|
|
329
227
|
}
|
|
330
228
|
|
|
331
229
|
// --------------- restart gateway ---------------
|
|
@@ -337,8 +235,7 @@ try {
|
|
|
337
235
|
} catch (e) {
|
|
338
236
|
if (e.stdout?.trim()) console.log(e.stdout.trim());
|
|
339
237
|
if (e.stderr?.trim()) console.error(e.stderr.trim());
|
|
340
|
-
warn("Gateway restart failed
|
|
341
|
-
warn("Check 'openclaw gateway status' and restart manually: openclaw gateway restart");
|
|
238
|
+
warn("Gateway restart failed. Restart manually: openclaw gateway restart");
|
|
342
239
|
}
|
|
343
240
|
|
|
344
241
|
// --------------- verify ---------------
|
|
@@ -353,6 +250,9 @@ function getLanIp() {
|
|
|
353
250
|
return "127.0.0.1";
|
|
354
251
|
}
|
|
355
252
|
|
|
253
|
+
let config;
|
|
254
|
+
try { config = JSON.parse(readFileSync(OPENCLAW_CONFIG, "utf8")); } catch { config = {}; }
|
|
255
|
+
|
|
356
256
|
const gatewayPort = config.gateway?.port || 18789;
|
|
357
257
|
const gatewayToken = config.gateway?.auth?.token || "(not set)";
|
|
358
258
|
const bindMode = config.gateway?.bind || "localhost";
|
|
@@ -387,32 +287,18 @@ async function verifyGateway(url, token, retries = 6) {
|
|
|
387
287
|
warn("Plugin responded but ok=false — " + JSON.stringify(data));
|
|
388
288
|
return false;
|
|
389
289
|
} catch {
|
|
390
|
-
|
|
391
|
-
if (i < 3) {
|
|
392
|
-
warn(`Plugin routes not registered yet, retrying (${i}/${retries})...`);
|
|
393
|
-
} else if (i < retries) {
|
|
394
|
-
warn(`Gateway is up but plugin routes missing — may need config reload, retrying (${i}/${retries})...`);
|
|
395
|
-
} else {
|
|
396
|
-
warn("Gateway is running but plugin routes were not loaded. Check plugin config in openclaw.json.");
|
|
397
|
-
}
|
|
290
|
+
if (i < retries) warn(`Plugin routes not registered yet, retrying (${i}/${retries})...`);
|
|
398
291
|
continue;
|
|
399
292
|
}
|
|
400
293
|
}
|
|
401
|
-
if (res.status === 401) {
|
|
402
|
-
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
if (res.status === 404) {
|
|
406
|
-
warn("Route /friday-next/status not found — plugin may not be loaded.");
|
|
407
|
-
return false;
|
|
408
|
-
}
|
|
294
|
+
if (res.status === 401) { warn("Auth token mismatch — check gateway.auth.token."); return false; }
|
|
295
|
+
if (res.status === 404) { warn("Route not found — plugin may not be loaded."); return false; }
|
|
409
296
|
if (i < retries) warn(`Gateway responded ${res.status}, retrying (${i}/${retries})...`);
|
|
410
297
|
} catch {
|
|
411
|
-
// Connection refused / timeout — gateway not running yet
|
|
412
298
|
if (i < retries) warn(`Gateway not reachable, retrying (${i}/${retries})...`);
|
|
413
299
|
}
|
|
414
300
|
}
|
|
415
|
-
warn("Gateway verification timed out
|
|
301
|
+
warn("Gateway verification timed out.");
|
|
416
302
|
return false;
|
|
417
303
|
}
|
|
418
304
|
|
|
@@ -428,9 +314,7 @@ if (verified) {
|
|
|
428
314
|
log("Installation complete! Friday Next channel is now active.");
|
|
429
315
|
} else {
|
|
430
316
|
warn("Installation complete, but gateway verification failed.");
|
|
431
|
-
warn("Check 'openclaw gateway status' and restart
|
|
432
|
-
warn("Also ensure OpenClaw is updated to 2026.5.7 or above: openclaw update");
|
|
433
|
-
warn("同时请确认 OpenClaw 已升级至 2026.5.7 或以上版本:openclaw update");
|
|
317
|
+
warn("Check 'openclaw gateway status' and restart if needed.");
|
|
434
318
|
}
|
|
435
319
|
log("");
|
|
436
320
|
|
|
@@ -450,11 +334,7 @@ try {
|
|
|
450
334
|
log("If QR scan doesn't work, enter manually:");
|
|
451
335
|
log("若二维码无法使用,请手动输入:");
|
|
452
336
|
qrShown = true;
|
|
453
|
-
} catch {
|
|
454
|
-
// qrcode-terminal not available, fall through to manual-only
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// --------------- manual input ---------------
|
|
337
|
+
} catch {}
|
|
458
338
|
|
|
459
339
|
if (!qrShown) {
|
|
460
340
|
log(BOLD_YELLOW("Input the URL and Token below into your FridayNext app to connect."));
|
|
@@ -478,13 +358,8 @@ const ip = new URL(gatewayUrl).hostname;
|
|
|
478
358
|
const ipType = classifyIp(ip);
|
|
479
359
|
if (ipType === "tailscale") {
|
|
480
360
|
log("This is a Tailscale network URL (" + ip + ").");
|
|
481
|
-
log("Accessible from your Tailnet devices.");
|
|
482
361
|
} else if (ipType === "private") {
|
|
483
362
|
log("This is a LOCAL network URL (" + ip + ", bind=" + bindMode + ").");
|
|
484
|
-
log("If you need public access, configure HTTPS, Tailscale, or a reverse proxy.");
|
|
485
|
-
} else if (ipType === "loopback") {
|
|
486
|
-
log("This is a LOOPBACK URL (" + ip + ").");
|
|
487
|
-
log("Only accessible from this machine.");
|
|
488
363
|
} else {
|
|
489
364
|
log("This URL appears to be publicly accessible (" + ip + ").");
|
|
490
365
|
}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|