@syengup/friday-channel-next 0.0.43 → 0.0.45

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.
@@ -1,29 +1,20 @@
1
1
  import { readdirSync } from "node:fs";
2
- import { join, dirname } from "node:path";
3
- import { fileURLToPath } from "node:url";
2
+ import { join } from "node:path";
4
3
  let cache = null;
5
4
  function resolveOpenClawDist() {
6
- // Walk up from the gateway-resolved SDK module to find the dist directory.
7
- // import.meta.resolve is available in Node 20.6+.
8
- try {
9
- const corePath = fileURLToPath(import.meta.resolve("openclaw/plugin-sdk/core"));
10
- return dirname(dirname(corePath)); // dist/plugin-sdk/core.js → dist/
11
- }
12
- catch {
13
- for (const root of [
14
- join(process.env.APPDATA ?? "", "npm/node_modules/openclaw/dist"),
15
- "/opt/homebrew/lib/node_modules/openclaw/dist",
16
- "/home/linuxbrew/.linuxbrew/lib/node_modules/openclaw/dist",
17
- "/usr/local/lib/node_modules/openclaw/dist",
18
- ]) {
19
- try {
20
- readdirSync(root);
21
- return root;
22
- }
23
- catch { }
5
+ for (const root of [
6
+ join(process.env.APPDATA ?? "", "npm/node_modules/openclaw/dist"),
7
+ "/opt/homebrew/lib/node_modules/openclaw/dist",
8
+ "/home/linuxbrew/.linuxbrew/lib/node_modules/openclaw/dist",
9
+ "/usr/local/lib/node_modules/openclaw/dist",
10
+ ]) {
11
+ try {
12
+ readdirSync(root);
13
+ return root;
24
14
  }
25
- throw new Error("OpenClaw dist directory not found");
15
+ catch { }
26
16
  }
17
+ throw new Error("OpenClaw dist directory not found");
27
18
  }
28
19
  export async function loadNodePairingModule() {
29
20
  if (cache)
@@ -32,9 +23,24 @@ export async function loadNodePairingModule() {
32
23
  const file = readdirSync(dist).find((f) => f.startsWith("node-pairing-") && f.endsWith(".js") && !f.includes("authz"));
33
24
  if (!file)
34
25
  throw new Error("node-pairing module not found in OpenClaw dist");
35
- // ESM import() correctly resolves named exports (listNodePairing, approveNodePairing)
36
- // unlike createRequire which exposes the minified export names (r, t).
37
- cache = await import(join(dist, file));
26
+ // ESM import() returns the minified export names (r, t, …) because the
27
+ // bundled module uses `export { listNodePairing as r, … }`. Resolve the
28
+ // correct functions by Function.name, which preserves the original name.
29
+ const mod = await import(join(dist, file));
30
+ let listNodePairing;
31
+ let approveNodePairing;
32
+ for (const value of Object.values(mod)) {
33
+ if (typeof value === "function") {
34
+ if (value.name === "listNodePairing")
35
+ listNodePairing = value;
36
+ else if (value.name === "approveNodePairing")
37
+ approveNodePairing = value;
38
+ }
39
+ }
40
+ if (!listNodePairing || !approveNodePairing) {
41
+ throw new Error("node-pairing module did not export expected functions");
42
+ }
43
+ cache = { listNodePairing, approveNodePairing };
38
44
  return cache;
39
45
  }
40
46
  /** Vitest-only: inject mock pairing functions. */
package/install.js CHANGED
@@ -89,15 +89,14 @@ if (!hasOpenclaw()) {
89
89
  }
90
90
  }
91
91
 
92
- // --------------- install via openclaw plugins ---------------
92
+ // --------------- install plugin package ---------------
93
93
 
94
- log("Installing Friday Next channel via openclaw plugins...");
94
+ log("Installing Friday Next channel plugin...");
95
95
  let installed = false;
96
96
 
97
97
  try {
98
- // --dangerously-force-unsafe-install needed for child_process in device-approve / nodes-approve
99
98
  const out = execSync(
100
- `${openclawCmd} plugins install --dangerously-force-unsafe-install @syengup/friday-channel-next@latest`,
99
+ `${openclawCmd} plugins install @syengup/friday-channel-next@latest`,
101
100
  { encoding: "utf8", stdio: "pipe", timeout: 120000 }
102
101
  );
103
102
  if (out.trim()) console.log(out.trim());
@@ -117,113 +116,104 @@ if (!installed) {
117
116
  err("npm is required for manual install. Install Node.js first.");
118
117
  process.exit(1);
119
118
  }
119
+ warn("Manual install complete, but auto-upgrade is NOT available.");
120
+ warn("To enable auto-upgrade later, run: openclaw plugins install @syengup/friday-channel-next");
121
+ }
120
122
 
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
- }
126
-
127
- // Configure OpenClaw
128
- log("Configuring OpenClaw...");
123
+ // --------------- configure OpenClaw ---------------
129
124
 
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
- }
125
+ log("Configuring OpenClaw...");
137
126
 
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
- }
127
+ let config;
128
+ try {
129
+ config = JSON.parse(readFileSync(OPENCLAW_CONFIG, "utf8"));
130
+ } catch {
131
+ err(`Failed to read ${OPENCLAW_CONFIG}.`);
132
+ err("Make sure OpenClaw is installed and has been run at least once.");
133
+ process.exit(1);
134
+ }
144
135
 
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
- }
136
+ let configChanged = false;
153
137
 
154
- if (!config.plugins.allow.includes("canvas")) {
155
- config.plugins.allow.push("canvas");
156
- console.log(" + Added canvas to plugins.allow");
138
+ function setConfig(path, value) {
139
+ const keys = path.split(".");
140
+ let obj = config;
141
+ for (let i = 0; i < keys.length - 1; i++) {
142
+ if (!obj[keys[i]] || typeof obj[keys[i]] !== "object" || Array.isArray(obj[keys[i]])) {
143
+ obj[keys[i]] = {};
144
+ }
145
+ obj = obj[keys[i]];
157
146
  }
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");
147
+ const last = keys[keys.length - 1];
148
+ if (JSON.stringify(obj[last]) !== JSON.stringify(value)) {
149
+ obj[last] = value;
150
+ configChanged = true;
164
151
  }
152
+ }
165
153
 
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
- }
179
- }
154
+ function ensureArrayContains(arr, item) {
155
+ if (!arr.includes(item)) { arr.push(item); configChanged = true; }
156
+ }
180
157
 
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");
185
- }
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");
195
- }
196
- }
158
+ // Plugins
159
+ if (!config.plugins) config.plugins = {};
160
+ if (!Array.isArray(config.plugins.allow)) config.plugins.allow = [];
161
+ ensureArrayContains(config.plugins.allow, "friday-next");
162
+ ensureArrayContains(config.plugins.allow, "canvas");
163
+
164
+ if (!config.plugins.entries) config.plugins.entries = {};
165
+ for (const id of ["friday-next", "canvas"]) {
166
+ if (!config.plugins.entries[id]) { config.plugins.entries[id] = { enabled: true }; configChanged = true; }
167
+ else if (!config.plugins.entries[id].enabled) { config.plugins.entries[id].enabled = true; configChanged = true; }
168
+ }
169
+
170
+ // Channel
171
+ if (!config.channels) config.channels = {};
172
+ if (!config.channels["friday-next"]) { config.channels["friday-next"] = { enabled: true, transport: "http+sse" }; configChanged = true; }
173
+ else {
174
+ if (!config.channels["friday-next"].enabled) { config.channels["friday-next"].enabled = true; configChanged = true; }
175
+ if (!config.channels["friday-next"].transport) { config.channels["friday-next"].transport = "http+sse"; configChanged = true; }
176
+ }
177
+
178
+ // Gateway bind + nodes
179
+ if (!config.gateway) config.gateway = {};
180
+ if (config.gateway.bind !== "lan") { config.gateway.bind = "lan"; configChanged = true; }
181
+ if (!config.gateway.nodes) config.gateway.nodes = {};
182
+ if (!Array.isArray(config.gateway.nodes.allowCommands)) config.gateway.nodes.allowCommands = [];
183
+ for (const cmd of [
184
+ "canvas.navigate", "canvas.present", "canvas.hide", "canvas.eval",
185
+ "canvas.snapshot", "canvas.a2ui.push", "canvas.a2ui.reset", "canvas.a2ui.pushJSONL",
186
+ ]) {
187
+ ensureArrayContains(config.gateway.nodes.allowCommands, cmd);
188
+ }
197
189
 
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 = [];
190
+ // Agent tools
191
+ if (!config.agents) config.agents = {};
192
+ if (!Array.isArray(config.agents.list)) config.agents.list = [];
193
+ let mainAgent = config.agents.list.find((a) => a.id === "main");
194
+ if (!mainAgent) { mainAgent = { id: "main" }; config.agents.list.push(mainAgent); configChanged = true; }
195
+ if (!mainAgent.tools) mainAgent.tools = {};
196
+ if (!Array.isArray(mainAgent.tools.alsoAllow)) mainAgent.tools.alsoAllow = [];
197
+ for (const tool of ["canvas", "nodes"]) {
198
+ ensureArrayContains(mainAgent.tools.alsoAllow, tool);
199
+ }
200
+ if (Array.isArray(mainAgent.tools.deny)) {
204
201
  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
- }
202
+ const idx = mainAgent.tools.deny.indexOf(tool);
203
+ if (idx !== -1) { mainAgent.tools.deny.splice(idx, 1); configChanged = true; }
215
204
  }
205
+ }
216
206
 
207
+ if (configChanged) {
217
208
  try {
218
209
  writeFileSync(OPENCLAW_CONFIG, JSON.stringify(config, null, 2) + "\n", "utf8");
219
- console.log(" Config updated.");
210
+ log("openclaw.json updated.");
220
211
  } catch {
221
212
  err(`Failed to write ${OPENCLAW_CONFIG}.`);
222
213
  process.exit(1);
223
214
  }
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");
215
+ } else {
216
+ log("openclaw.json already configured.");
227
217
  }
228
218
 
229
219
  // --------------- restart gateway ---------------
@@ -250,7 +240,6 @@ function getLanIp() {
250
240
  return "127.0.0.1";
251
241
  }
252
242
 
253
- let config;
254
243
  try { config = JSON.parse(readFileSync(OPENCLAW_CONFIG, "utf8")); } catch { config = {}; }
255
244
 
256
245
  const gatewayPort = config.gateway?.port || 18789;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syengup/friday-channel-next",
3
- "version": "0.0.43",
3
+ "version": "0.0.45",
4
4
  "description": "OpenClaw Friday Next Apple channel plugin",
5
5
  "type": "module",
6
6
  "files": [
@@ -1,26 +1,18 @@
1
1
  import { readdirSync } from "node:fs";
2
- import { join, dirname } from "node:path";
3
- import { fileURLToPath } from "node:url";
2
+ import { join } from "node:path";
4
3
 
5
4
  let cache: { listNodePairing: Function; approveNodePairing: Function } | null = null;
6
5
 
7
6
  function resolveOpenClawDist(): string {
8
- // Walk up from the gateway-resolved SDK module to find the dist directory.
9
- // import.meta.resolve is available in Node 20.6+.
10
- try {
11
- const corePath = fileURLToPath(import.meta.resolve("openclaw/plugin-sdk/core"));
12
- return dirname(dirname(corePath)); // dist/plugin-sdk/core.js → dist/
13
- } catch {
14
- for (const root of [
15
- join(process.env.APPDATA ?? "", "npm/node_modules/openclaw/dist"),
16
- "/opt/homebrew/lib/node_modules/openclaw/dist",
17
- "/home/linuxbrew/.linuxbrew/lib/node_modules/openclaw/dist",
18
- "/usr/local/lib/node_modules/openclaw/dist",
19
- ]) {
20
- try { readdirSync(root); return root; } catch {}
21
- }
22
- throw new Error("OpenClaw dist directory not found");
7
+ for (const root of [
8
+ join(process.env.APPDATA ?? "", "npm/node_modules/openclaw/dist"),
9
+ "/opt/homebrew/lib/node_modules/openclaw/dist",
10
+ "/home/linuxbrew/.linuxbrew/lib/node_modules/openclaw/dist",
11
+ "/usr/local/lib/node_modules/openclaw/dist",
12
+ ]) {
13
+ try { readdirSync(root); return root; } catch {}
23
14
  }
15
+ throw new Error("OpenClaw dist directory not found");
24
16
  }
25
17
 
26
18
  export async function loadNodePairingModule(): Promise<{
@@ -33,10 +25,24 @@ export async function loadNodePairingModule(): Promise<{
33
25
  (f) => f.startsWith("node-pairing-") && f.endsWith(".js") && !f.includes("authz"),
34
26
  );
35
27
  if (!file) throw new Error("node-pairing module not found in OpenClaw dist");
36
- // ESM import() correctly resolves named exports (listNodePairing, approveNodePairing)
37
- // unlike createRequire which exposes the minified export names (r, t).
38
- cache = await import(join(dist, file));
39
- return cache!;
28
+
29
+ // ESM import() returns the minified export names (r, t, …) because the
30
+ // bundled module uses `export { listNodePairing as r, … }`. Resolve the
31
+ // correct functions by Function.name, which preserves the original name.
32
+ const mod = await import(join(dist, file));
33
+ let listNodePairing: Function | undefined;
34
+ let approveNodePairing: Function | undefined;
35
+ for (const value of Object.values(mod)) {
36
+ if (typeof value === "function") {
37
+ if (value.name === "listNodePairing") listNodePairing = value;
38
+ else if (value.name === "approveNodePairing") approveNodePairing = value;
39
+ }
40
+ }
41
+ if (!listNodePairing || !approveNodePairing) {
42
+ throw new Error("node-pairing module did not export expected functions");
43
+ }
44
+ cache = { listNodePairing, approveNodePairing };
45
+ return cache;
40
46
  }
41
47
 
42
48
  /** Vitest-only: inject mock pairing functions. */