@syengup/friday-channel-next 0.0.13 → 0.0.14
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 +9 -3
- package/install.sh +13 -3
- package/package.json +10 -10
- package/dist/index.js +0 -176
package/install.js
CHANGED
|
@@ -46,13 +46,19 @@ function isRunningFromNpmPackage() {
|
|
|
46
46
|
|
|
47
47
|
// --------------- prerequisites ---------------
|
|
48
48
|
|
|
49
|
-
const required = ["
|
|
49
|
+
const required = ["node", "openclaw"];
|
|
50
50
|
const missing = required.filter((c) => !has(c));
|
|
51
51
|
if (missing.length) {
|
|
52
52
|
missing.forEach((c) => err(`${c} is required but not found. Install it first.`));
|
|
53
53
|
process.exit(1);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
const PKG = has("pnpm") ? "pnpm" : has("npm") ? "npm" : null;
|
|
57
|
+
if (!PKG) {
|
|
58
|
+
err("pnpm or npm is required but not found. Install one first.");
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
56
62
|
if (!existsSync(OPENCLAW_CONFIG)) {
|
|
57
63
|
err(`OpenClaw config not found at ${OPENCLAW_CONFIG}`);
|
|
58
64
|
err("Make sure OpenClaw is installed and has been run at least once.");
|
|
@@ -88,10 +94,10 @@ process.chdir(PLUGIN_DIR);
|
|
|
88
94
|
// --------------- install + build ---------------
|
|
89
95
|
|
|
90
96
|
log("Installing dependencies...");
|
|
91
|
-
execSync(
|
|
97
|
+
execSync(`${PKG} install`, { stdio: "inherit" });
|
|
92
98
|
|
|
93
99
|
log("Building TypeScript...");
|
|
94
|
-
execSync(
|
|
100
|
+
execSync(`${PKG} run build`, { stdio: "inherit" });
|
|
95
101
|
|
|
96
102
|
// --------------- configure OpenClaw ---------------
|
|
97
103
|
|
package/install.sh
CHANGED
|
@@ -22,13 +22,23 @@ err() { printf " ${RED}X${NC} %s\\n" "$1" >&2; }
|
|
|
22
22
|
trap 'err "Install failed."' ERR
|
|
23
23
|
|
|
24
24
|
# Check prerequisites
|
|
25
|
-
for cmd in
|
|
25
|
+
for cmd in node git openclaw; do
|
|
26
26
|
if ! command -v "$cmd" &>/dev/null; then
|
|
27
27
|
err "$cmd is required but not found. Install it first."
|
|
28
28
|
exit 1
|
|
29
29
|
fi
|
|
30
30
|
done
|
|
31
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
|
+
|
|
32
42
|
if [ ! -f "$OPENCLAW_CONFIG" ]; then
|
|
33
43
|
err "OpenClaw config not found at $OPENCLAW_CONFIG"
|
|
34
44
|
err "Make sure OpenClaw is installed and has been run at least once."
|
|
@@ -48,10 +58,10 @@ fi
|
|
|
48
58
|
cd "$PLUGIN_DIR"
|
|
49
59
|
|
|
50
60
|
log "Installing dependencies..."
|
|
51
|
-
|
|
61
|
+
$PKG install
|
|
52
62
|
|
|
53
63
|
log "Building TypeScript..."
|
|
54
|
-
|
|
64
|
+
$PKG run build
|
|
55
65
|
|
|
56
66
|
# Step 2: Configure OpenClaw
|
|
57
67
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syengup/friday-channel-next",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "OpenClaw Friday Next Apple channel plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -11,6 +11,14 @@
|
|
|
11
11
|
"tsconfig.json",
|
|
12
12
|
"openclaw.plugin.json"
|
|
13
13
|
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -p tsconfig.json",
|
|
16
|
+
"test": "npm run test:unit && npm run test:e2e",
|
|
17
|
+
"test:unit": "vitest run",
|
|
18
|
+
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
19
|
+
"test:smoke": "node scripts/e2e-smoke.mjs",
|
|
20
|
+
"test:msg-live": "node scripts/message-roundtrip-live.mjs"
|
|
21
|
+
},
|
|
14
22
|
"bin": {
|
|
15
23
|
"friday-channel-next": "./install.js",
|
|
16
24
|
"install-friday-next": "./install.js"
|
|
@@ -56,13 +64,5 @@
|
|
|
56
64
|
"typescript": "^6.0.3",
|
|
57
65
|
"vitest": "^4.1.5",
|
|
58
66
|
"zod": "^4.3.6"
|
|
59
|
-
},
|
|
60
|
-
"scripts": {
|
|
61
|
-
"build": "tsc -p tsconfig.json",
|
|
62
|
-
"test": "pnpm test:unit && pnpm test:e2e",
|
|
63
|
-
"test:unit": "vitest run",
|
|
64
|
-
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
65
|
-
"test:smoke": "node scripts/e2e-smoke.mjs",
|
|
66
|
-
"test:msg-live": "node scripts/message-roundtrip-live.mjs"
|
|
67
67
|
}
|
|
68
|
-
}
|
|
68
|
+
}
|
package/dist/index.js
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
|
|
2
|
-
import { fridayNextChannelPlugin } from "./src/channel.js";
|
|
3
|
-
import { setFridayNextRuntime } from "./src/runtime.js";
|
|
4
|
-
import { resolveFridayNextConfig } from "./src/config.js";
|
|
5
|
-
import { getHostOpenClawConfigSnapshot } from "./src/host-config.js";
|
|
6
|
-
import { registerFridayNextHttpRoutes } from "./src/http/server.js";
|
|
7
|
-
import { getFridayNextRuntime } from "./src/runtime.js";
|
|
8
|
-
import { sseEmitter } from "./src/sse/emitter.js";
|
|
9
|
-
import { forwardAgentEventRaw, getLastRegisteredFridayDeviceId, resolveFridayDeviceIdForSessionKey, } from "./src/friday-session.js";
|
|
10
|
-
import { setFridayAgentForwardRuntime } from "./src/agent-forward-runtime.js";
|
|
11
|
-
import { getOpenClawAgentRunContext } from "./src/agent-run-context-bridge.js";
|
|
12
|
-
export { fridayNextChannelPlugin } from "./src/channel.js";
|
|
13
|
-
export { setFridayNextRuntime } from "./src/runtime.js";
|
|
14
|
-
/** `api.on` returns void — register tool hooks at most once per process. */
|
|
15
|
-
let fridayNextToolHooksRegistered = false;
|
|
16
|
-
let disposeAgentEventListener = null;
|
|
17
|
-
/** Avoid duplicate `registerHttpRoute` when gateway re-invokes `registerFull`. */
|
|
18
|
-
let fridayNextPluginHttpRegistered = false;
|
|
19
|
-
function deviceIdFromToolContext(ctx) {
|
|
20
|
-
if (ctx.runId) {
|
|
21
|
-
const d = sseEmitter.getDeviceIdByRunId(ctx.runId);
|
|
22
|
-
if (d)
|
|
23
|
-
return d;
|
|
24
|
-
}
|
|
25
|
-
const sk = typeof ctx.sessionKey === "string" && ctx.sessionKey.trim()
|
|
26
|
-
? ctx.sessionKey.trim()
|
|
27
|
-
: (ctx.runId ? getOpenClawAgentRunContext(ctx.runId)?.sessionKey?.trim() : undefined) ?? "";
|
|
28
|
-
if (sk) {
|
|
29
|
-
const d = resolveFridayDeviceIdForSessionKey(sk);
|
|
30
|
-
if (d)
|
|
31
|
-
return d;
|
|
32
|
-
}
|
|
33
|
-
const sole = sseEmitter.getSoleConnectedDeviceId();
|
|
34
|
-
if (sole)
|
|
35
|
-
return sole;
|
|
36
|
-
const last = getLastRegisteredFridayDeviceId();
|
|
37
|
-
if (last)
|
|
38
|
-
return last;
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
function isFridaySessionKey(sk) {
|
|
42
|
-
return /^friday-next-/i.test(sk) || /^agent:main:friday-next-/i.test(sk);
|
|
43
|
-
}
|
|
44
|
-
function shouldForwardToolEventToFriday(ctx) {
|
|
45
|
-
if (ctx.runId) {
|
|
46
|
-
if (sseEmitter.getDeviceIdByRunId(ctx.runId))
|
|
47
|
-
return true;
|
|
48
|
-
const runSk = getOpenClawAgentRunContext(ctx.runId)?.sessionKey?.trim() ?? "";
|
|
49
|
-
if (runSk) {
|
|
50
|
-
if (resolveFridayDeviceIdForSessionKey(runSk))
|
|
51
|
-
return true;
|
|
52
|
-
if (isFridaySessionKey(runSk))
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
const sk = typeof ctx.sessionKey === "string" ? ctx.sessionKey.trim() : "";
|
|
57
|
-
if (sk) {
|
|
58
|
-
if (resolveFridayDeviceIdForSessionKey(sk))
|
|
59
|
-
return true;
|
|
60
|
-
if (isFridaySessionKey(sk))
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
export default defineChannelPluginEntry({
|
|
66
|
-
id: "friday-next",
|
|
67
|
-
name: "Friday Next",
|
|
68
|
-
description: "Friday Next Apple 应用通道",
|
|
69
|
-
plugin: fridayNextChannelPlugin,
|
|
70
|
-
setRuntime: setFridayNextRuntime,
|
|
71
|
-
registerFull: (api) => {
|
|
72
|
-
setFridayAgentForwardRuntime(api);
|
|
73
|
-
if (!fridayNextPluginHttpRegistered) {
|
|
74
|
-
fridayNextPluginHttpRegistered = true;
|
|
75
|
-
registerFridayNextHttpRoutes(api);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
const cfg = resolveFridayNextConfig(getHostOpenClawConfigSnapshot(getFridayNextRuntime().config));
|
|
79
|
-
sseEmitter.setBacklogLimit(cfg.sseBacklogPerDevice);
|
|
80
|
-
}
|
|
81
|
-
disposeAgentEventListener?.();
|
|
82
|
-
disposeAgentEventListener = api.runtime.events.onAgentEvent((evt) => {
|
|
83
|
-
forwardAgentEventRaw({
|
|
84
|
-
runId: evt.runId,
|
|
85
|
-
seq: evt.seq,
|
|
86
|
-
ts: evt.ts,
|
|
87
|
-
stream: evt.stream,
|
|
88
|
-
data: evt.data,
|
|
89
|
-
sessionKey: evt.sessionKey,
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
if (fridayNextToolHooksRegistered) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
fridayNextToolHooksRegistered = true;
|
|
96
|
-
api.on("subagent_delivery_target", (event) => {
|
|
97
|
-
if (!event.expectsCompletionMessage)
|
|
98
|
-
return;
|
|
99
|
-
const ch = event.requesterOrigin?.channel?.trim().toLowerCase();
|
|
100
|
-
if (ch !== "friday-next")
|
|
101
|
-
return;
|
|
102
|
-
const sk = event.requesterSessionKey?.trim();
|
|
103
|
-
if (!sk)
|
|
104
|
-
return;
|
|
105
|
-
const raw = resolveFridayDeviceIdForSessionKey(sk);
|
|
106
|
-
if (!raw)
|
|
107
|
-
return;
|
|
108
|
-
const to = raw.toUpperCase();
|
|
109
|
-
return {
|
|
110
|
-
origin: {
|
|
111
|
-
channel: "friday-next",
|
|
112
|
-
accountId: event.requesterOrigin?.accountId?.trim() || "default",
|
|
113
|
-
to,
|
|
114
|
-
},
|
|
115
|
-
};
|
|
116
|
-
});
|
|
117
|
-
api.on("before_tool_call", (event, ctx) => {
|
|
118
|
-
if (!shouldForwardToolEventToFriday(ctx))
|
|
119
|
-
return;
|
|
120
|
-
const deviceId = deviceIdFromToolContext(ctx);
|
|
121
|
-
const runId = ctx.runId ?? "(unknown)";
|
|
122
|
-
const logLine = (detail) => {
|
|
123
|
-
const ts = new Date().toISOString();
|
|
124
|
-
console.error(`[Friday-HOOK] [${ts}] [TOOL_CALL] toolName=${event.toolName} runId=${runId} deviceId=${deviceId ?? "(unknown)"} detail=${detail}`);
|
|
125
|
-
};
|
|
126
|
-
if (!deviceId) {
|
|
127
|
-
logLine("SKIP_no_deviceId");
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
logLine("START");
|
|
131
|
-
sseEmitter.broadcastToolEvent(deviceId.toUpperCase(), runId, {
|
|
132
|
-
type: "tool-hook",
|
|
133
|
-
data: {
|
|
134
|
-
when: "before",
|
|
135
|
-
runId,
|
|
136
|
-
deviceId: deviceId.toUpperCase(),
|
|
137
|
-
sessionKey: ctx.sessionKey,
|
|
138
|
-
toolName: event.toolName,
|
|
139
|
-
params: event.params,
|
|
140
|
-
ts: Date.now(),
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
api.on("after_tool_call", (event, ctx) => {
|
|
145
|
-
if (!shouldForwardToolEventToFriday(ctx))
|
|
146
|
-
return;
|
|
147
|
-
const deviceId = deviceIdFromToolContext(ctx);
|
|
148
|
-
const runId = ctx.runId ?? "(unknown)";
|
|
149
|
-
const logLine = (detail) => {
|
|
150
|
-
const ts = new Date().toISOString();
|
|
151
|
-
console.error(`[Friday-HOOK] [${ts}] [TOOL_DONE] toolName=${event.toolName} runId=${runId} deviceId=${deviceId ?? "(unknown)"} detail=${detail}`);
|
|
152
|
-
};
|
|
153
|
-
if (!deviceId) {
|
|
154
|
-
logLine("SKIP_no_deviceId");
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
logLine("END");
|
|
158
|
-
const normalizedDeviceId = deviceId.toUpperCase();
|
|
159
|
-
sseEmitter.broadcastToolEvent(normalizedDeviceId, runId, {
|
|
160
|
-
type: "tool-hook",
|
|
161
|
-
data: {
|
|
162
|
-
when: "after",
|
|
163
|
-
runId,
|
|
164
|
-
deviceId: normalizedDeviceId,
|
|
165
|
-
sessionKey: ctx.sessionKey,
|
|
166
|
-
toolName: event.toolName,
|
|
167
|
-
toolCallId: event.toolCallId,
|
|
168
|
-
error: event.error ?? null,
|
|
169
|
-
result: event.result,
|
|
170
|
-
durationMs: event.durationMs ?? null,
|
|
171
|
-
ts: Date.now(),
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
|
-
});
|
|
175
|
-
},
|
|
176
|
-
});
|