@syengup/friday-channel-next 0.1.36 → 0.1.37
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 +1 -1
- package/dist/src/agent/dispatch-bridge.d.ts +1 -1
- package/dist/src/agent/node-pairing-bridge.d.ts +11 -8
- package/dist/src/agent/node-pairing-bridge.js +6 -2
- package/dist/src/agent/subagent-registry.js +0 -3
- package/dist/src/channel-actions.js +3 -1
- package/dist/src/channel.js +0 -2
- package/dist/src/collect-message-media-paths.js +10 -1
- package/dist/src/friday-session.js +34 -10
- package/dist/src/history/normalize-message.js +22 -8
- package/dist/src/http/handlers/agent-config.js +10 -4
- package/dist/src/http/handlers/cancel.js +4 -2
- package/dist/src/http/handlers/device-approve.js +3 -1
- package/dist/src/http/handlers/files-download.js +6 -8
- package/dist/src/http/handlers/files.js +1 -1
- package/dist/src/http/handlers/health.js +18 -4
- package/dist/src/http/handlers/history-messages.js +1 -1
- package/dist/src/http/handlers/history-sessions.js +5 -3
- package/dist/src/http/handlers/messages.js +25 -11
- package/dist/src/http/handlers/models-list.js +1 -1
- package/dist/src/http/handlers/nodes-approve.js +1 -6
- package/dist/src/http/handlers/plugin-info.js +1 -1
- package/dist/src/http/server.js +4 -2
- package/dist/src/link-preview/og-parse.js +3 -1
- package/dist/src/plugin-install-info.js +4 -1
- package/dist/src/session/session-manager.js +9 -3
- package/dist/src/session-usage-store.js +3 -1
- package/dist/src/skills-discovery.d.ts +5 -4
- package/dist/src/skills-discovery.js +27 -22
- package/dist/src/sse/offline-queue.js +4 -1
- package/dist/src/tool-catalog.js +2 -3
- package/dist/src/upgrade-runtime.d.ts +1 -1
- package/dist/src/version.js +3 -1
- package/index.ts +43 -35
- package/install.js +131 -43
- package/package.json +10 -1
- package/src/agent/abort-run.ts +2 -3
- package/src/agent/dispatch-bridge.ts +2 -1
- package/src/agent/media-bridge.ts +9 -2
- package/src/agent/node-pairing-bridge.ts +29 -15
- package/src/agent/run-usage-accumulator.ts +4 -2
- package/src/agent/subagent-registry.ts +0 -4
- package/src/agent-run-context-bridge.ts +3 -1
- package/src/channel-actions.test.ts +10 -4
- package/src/channel-actions.ts +3 -1
- package/src/channel.outbound.test.ts +18 -4
- package/src/channel.ts +121 -123
- package/src/collect-message-media-paths.ts +15 -6
- package/src/config.ts +1 -4
- package/src/e2e/agents-list.e2e.test.ts +9 -2
- package/src/e2e/attachments-inbound.e2e.test.ts +5 -1
- package/src/e2e/attachments-outbound.e2e.test.ts +7 -2
- package/src/e2e/auto-approve.integration.test.ts +13 -7
- package/src/e2e/cancel-reconnect-errors.e2e.test.ts +18 -3
- package/src/e2e/connect-and-connected.e2e.test.ts +5 -1
- package/src/e2e/offline-replay.e2e.test.ts +17 -3
- package/src/e2e/send-text.e2e.test.ts +11 -2
- package/src/e2e/slash-commands.e2e.test.ts +5 -1
- package/src/e2e/status-cors-auth.e2e.test.ts +11 -2
- package/src/e2e/subagent-smoke.e2e.test.ts +68 -28
- package/src/e2e/subagent.e2e.test.ts +136 -53
- package/src/e2e/tool-lifecycle.e2e.test.ts +5 -1
- package/src/friday-session.forward-agent.test.ts +44 -12
- package/src/friday-session.ts +44 -20
- package/src/history/normalize-message.test.ts +35 -8
- package/src/history/normalize-message.ts +24 -12
- package/src/history/read-transcript.ts +1 -4
- package/src/http/handlers/agent-config.test.ts +10 -3
- package/src/http/handlers/agent-config.ts +22 -8
- package/src/http/handlers/agents-list.test.ts +1 -5
- package/src/http/handlers/cancel.test.ts +12 -3
- package/src/http/handlers/cancel.ts +4 -2
- package/src/http/handlers/device-approve.test.ts +12 -3
- package/src/http/handlers/device-approve.ts +33 -21
- package/src/http/handlers/files-download.ts +17 -13
- package/src/http/handlers/files.test.ts +8 -2
- package/src/http/handlers/files.ts +21 -7
- package/src/http/handlers/health.test.ts +43 -11
- package/src/http/handlers/health.ts +22 -6
- package/src/http/handlers/history-messages.test.ts +51 -9
- package/src/http/handlers/history-messages.ts +4 -1
- package/src/http/handlers/history-sessions.test.ts +46 -9
- package/src/http/handlers/history-sessions.ts +5 -3
- package/src/http/handlers/history-set-title.test.ts +14 -5
- package/src/http/handlers/link-preview.test.ts +57 -16
- package/src/http/handlers/link-preview.ts +4 -1
- package/src/http/handlers/messages.test.ts +12 -8
- package/src/http/handlers/messages.ts +57 -19
- package/src/http/handlers/models-list.ts +14 -8
- package/src/http/handlers/nodes-approve.test.ts +15 -4
- package/src/http/handlers/nodes-approve.ts +38 -40
- package/src/http/handlers/plugin-info.ts +5 -6
- package/src/http/handlers/plugin-upgrade.ts +4 -1
- package/src/http/handlers/sse.ts +3 -1
- package/src/http/server.ts +9 -6
- package/src/link-preview/og-parse.test.ts +6 -2
- package/src/link-preview/og-parse.ts +10 -3
- package/src/link-preview/preview-service.ts +4 -1
- package/src/link-preview/ssrf-guard.test.ts +72 -15
- package/src/link-preview/ssrf-guard.ts +2 -1
- package/src/media-fetch.test.ts +7 -2
- package/src/media-fetch.ts +1 -2
- package/src/openclaw.d.ts +16 -9
- package/src/plugin-install-info.ts +20 -9
- package/src/run-metadata.ts +2 -1
- package/src/session/session-manager.ts +19 -11
- package/src/session-usage-snapshot.ts +3 -1
- package/src/session-usage-store.ts +3 -1
- package/src/skills-discovery.test.ts +14 -10
- package/src/skills-discovery.ts +43 -27
- package/src/sse/emitter.test.ts +1 -1
- package/src/sse/emitter.ts +9 -3
- package/src/sse/offline-queue.ts +17 -8
- package/src/test-support/app-simulator.ts +17 -3
- package/src/test-support/mock-dispatch.ts +17 -4
- package/src/thinking-levels.ts +3 -1
- package/src/tool-catalog.ts +16 -7
- package/src/upgrade-runtime.ts +4 -2
- package/src/version.ts +5 -1
- package/tsconfig.json +1 -1
package/src/sse/offline-queue.ts
CHANGED
|
@@ -21,7 +21,9 @@ export function setOfflineQueueBaseDirForTest(dir: string | null): void {
|
|
|
21
21
|
export function resolveFridayNextEventsQueueDir(): string {
|
|
22
22
|
if (testQueueBaseDir) return testQueueBaseDir;
|
|
23
23
|
try {
|
|
24
|
-
const cfg = resolveFridayNextConfig(
|
|
24
|
+
const cfg = resolveFridayNextConfig(
|
|
25
|
+
getHostOpenClawConfigSnapshot(getFridayNextRuntime().config),
|
|
26
|
+
);
|
|
25
27
|
return path.join(path.dirname(cfg.historyDir), "events-queue");
|
|
26
28
|
} catch {
|
|
27
29
|
return path.join(os.homedir(), ".openclaw", "friday-next", "events-queue");
|
|
@@ -71,7 +73,13 @@ export class FridaySseOfflineQueue {
|
|
|
71
73
|
return this.scanMaxId(deviceId.trim().toUpperCase());
|
|
72
74
|
}
|
|
73
75
|
|
|
74
|
-
append(
|
|
76
|
+
append(
|
|
77
|
+
deviceId: string,
|
|
78
|
+
id: number,
|
|
79
|
+
event: string,
|
|
80
|
+
data: Record<string, unknown>,
|
|
81
|
+
backlogLimit: number,
|
|
82
|
+
): void {
|
|
75
83
|
if (event === "connected") return;
|
|
76
84
|
this.ensureDir();
|
|
77
85
|
const file = this.devicePath(deviceId);
|
|
@@ -119,7 +127,12 @@ export class FridaySseOfflineQueue {
|
|
|
119
127
|
if (!line.trim()) continue;
|
|
120
128
|
try {
|
|
121
129
|
const o = JSON.parse(line) as PersistedSseEntry;
|
|
122
|
-
if (
|
|
130
|
+
if (
|
|
131
|
+
typeof o.id === "number" &&
|
|
132
|
+
typeof o.event === "string" &&
|
|
133
|
+
o.data &&
|
|
134
|
+
typeof o.data === "object"
|
|
135
|
+
) {
|
|
123
136
|
all.push(o);
|
|
124
137
|
}
|
|
125
138
|
} catch {
|
|
@@ -128,11 +141,7 @@ export class FridaySseOfflineQueue {
|
|
|
128
141
|
}
|
|
129
142
|
if (all.length <= keep) return;
|
|
130
143
|
const slice = all.slice(-keep);
|
|
131
|
-
fs.writeFileSync(
|
|
132
|
-
file,
|
|
133
|
-
slice.map((e) => JSON.stringify(e) + "\n").join(""),
|
|
134
|
-
"utf8",
|
|
135
|
-
);
|
|
144
|
+
fs.writeFileSync(file, slice.map((e) => JSON.stringify(e) + "\n").join(""), "utf8");
|
|
136
145
|
}
|
|
137
146
|
}
|
|
138
147
|
|
|
@@ -68,7 +68,9 @@ class MockRes extends Writable {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
function createRouteHarness() {
|
|
71
|
-
let routeHandler:
|
|
71
|
+
let routeHandler:
|
|
72
|
+
| ((req: Readable & { method?: string; url?: string }, res: Writable) => Promise<boolean>)
|
|
73
|
+
| null = null;
|
|
72
74
|
const fakeApi = {
|
|
73
75
|
logger: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} },
|
|
74
76
|
registerHttpRoute(route: { handler: (req: never, res: never) => Promise<boolean> }) {
|
|
@@ -193,7 +195,14 @@ export function createAppSimulator(opts?: { deviceId?: string; token?: string })
|
|
|
193
195
|
});
|
|
194
196
|
return { status: res.statusCode, body: jsonBody(res) };
|
|
195
197
|
},
|
|
196
|
-
async uploadFiles(
|
|
198
|
+
async uploadFiles(
|
|
199
|
+
parts: Array<{
|
|
200
|
+
name: string;
|
|
201
|
+
filename: string;
|
|
202
|
+
contentType: string;
|
|
203
|
+
content: string | Buffer;
|
|
204
|
+
}>,
|
|
205
|
+
) {
|
|
197
206
|
const boundary = "----friday-next-e2e-boundary";
|
|
198
207
|
const chunks: Buffer[] = [];
|
|
199
208
|
for (const part of parts) {
|
|
@@ -235,7 +244,12 @@ export function createAppSimulator(opts?: { deviceId?: string; token?: string })
|
|
|
235
244
|
const res = await request({ method: "OPTIONS", path, headers: { origin } });
|
|
236
245
|
return { status: res.statusCode, headers: res.headers };
|
|
237
246
|
},
|
|
238
|
-
async rawRequest(arg: {
|
|
247
|
+
async rawRequest(arg: {
|
|
248
|
+
method: string;
|
|
249
|
+
path: string;
|
|
250
|
+
headers?: Headers;
|
|
251
|
+
body?: string | Buffer;
|
|
252
|
+
}) {
|
|
239
253
|
const res = await request(arg);
|
|
240
254
|
return { status: res.statusCode, body: res.body.toString("utf-8"), headers: res.headers };
|
|
241
255
|
},
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
__setMockFridayDispatchForTests,
|
|
3
|
+
__resetMockFridayDispatchForTests,
|
|
4
|
+
} from "../agent/dispatch-bridge.js";
|
|
2
5
|
import { forwardAgentEventRaw } from "../friday-session.js";
|
|
3
6
|
|
|
4
|
-
type DispatchArg = Parameters<typeof __setMockFridayDispatchForTests>[0] extends (
|
|
7
|
+
type DispatchArg = Parameters<typeof __setMockFridayDispatchForTests>[0] extends (
|
|
8
|
+
arg: infer A,
|
|
9
|
+
) => unknown
|
|
5
10
|
? A
|
|
6
11
|
: never;
|
|
7
12
|
|
|
@@ -133,12 +138,20 @@ export class MockDispatchScript {
|
|
|
133
138
|
|
|
134
139
|
block(text: string, mediaUrls: string[] = [], audioAsVoice = false): this {
|
|
135
140
|
this.steps.push(async (_args, callbacks) => {
|
|
136
|
-
await callbacks.deliver?.(
|
|
141
|
+
await callbacks.deliver?.(
|
|
142
|
+
{ text, mediaUrls, audioAsVoice } as never,
|
|
143
|
+
{ kind: "block" } as never,
|
|
144
|
+
);
|
|
137
145
|
});
|
|
138
146
|
return this;
|
|
139
147
|
}
|
|
140
148
|
|
|
141
|
-
deliverFinal(payload: {
|
|
149
|
+
deliverFinal(payload: {
|
|
150
|
+
text: string;
|
|
151
|
+
mediaUrls?: string[];
|
|
152
|
+
audioAsVoice?: boolean;
|
|
153
|
+
isError?: boolean;
|
|
154
|
+
}): this {
|
|
142
155
|
this.steps.push(async (_args, callbacks) => {
|
|
143
156
|
await callbacks.deliver?.(payload as never, { kind: "final" } as never);
|
|
144
157
|
});
|
package/src/thinking-levels.ts
CHANGED
|
@@ -53,7 +53,9 @@ export function resolveModelThinking(
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/** Resolves thinking levels for a full `provider/model` ref (or bare model id). */
|
|
56
|
-
export function resolveModelThinkingForRef(
|
|
56
|
+
export function resolveModelThinkingForRef(
|
|
57
|
+
modelRef: string | undefined | null,
|
|
58
|
+
): ResolvedModelThinking {
|
|
57
59
|
if (!modelRef) return { levels: BASE_THINKING_LEVELS };
|
|
58
60
|
const split = splitModelRef(modelRef);
|
|
59
61
|
return resolveModelThinking(split.provider, split.modelId);
|
package/src/tool-catalog.ts
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
|
|
16
16
|
import fs from "node:fs";
|
|
17
17
|
import path from "node:path";
|
|
18
|
-
import { getFridayAgentForwardRuntime } from "./agent-forward-runtime.js";
|
|
19
18
|
import { resolveOpenClawRoot } from "./skills-discovery.js";
|
|
20
19
|
import { normalizeAgentId } from "./agent-id.js";
|
|
21
20
|
|
|
@@ -38,7 +37,11 @@ interface CoreCatalogResult {
|
|
|
38
37
|
profiles: Array<{ id: string; label: string }>;
|
|
39
38
|
groups: CoreCatalogGroup[];
|
|
40
39
|
}
|
|
41
|
-
type BuildFn = (params: {
|
|
40
|
+
type BuildFn = (params: {
|
|
41
|
+
cfg: unknown;
|
|
42
|
+
agentId?: string;
|
|
43
|
+
includePlugins?: boolean;
|
|
44
|
+
}) => CoreCatalogResult;
|
|
42
45
|
|
|
43
46
|
let cachedBuildFn: BuildFn | null | undefined;
|
|
44
47
|
|
|
@@ -127,7 +130,8 @@ async function locateBuildFn(): Promise<BuildFn | null> {
|
|
|
127
130
|
if (!content.includes("function buildToolsCatalogResult")) continue;
|
|
128
131
|
try {
|
|
129
132
|
const mod = (await import(path.join(distDir, file))) as Record<string, unknown>;
|
|
130
|
-
if (typeof mod.buildToolsCatalogResult === "function")
|
|
133
|
+
if (typeof mod.buildToolsCatalogResult === "function")
|
|
134
|
+
return mod.buildToolsCatalogResult as BuildFn;
|
|
131
135
|
} catch {
|
|
132
136
|
// unreadable/non-importable candidate → keep scanning
|
|
133
137
|
}
|
|
@@ -172,8 +176,9 @@ function readStringArray(value: unknown): string[] {
|
|
|
172
176
|
|
|
173
177
|
/** Read an agent's `tools` config block from the host config. */
|
|
174
178
|
function findAgentTools(cfg: unknown, agentId: string): AgentToolsConfigShape | undefined {
|
|
175
|
-
const list = (
|
|
176
|
-
?.
|
|
179
|
+
const list = (
|
|
180
|
+
(cfg as Record<string, unknown> | undefined)?.agents as Record<string, unknown> | undefined
|
|
181
|
+
)?.list as Array<Record<string, unknown>> | undefined;
|
|
177
182
|
if (!Array.isArray(list)) return undefined;
|
|
178
183
|
const entry = list.find((a) => a && typeof a === "object" && normalizeAgentId(a.id) === agentId);
|
|
179
184
|
return entry?.tools as AgentToolsConfigShape | undefined;
|
|
@@ -183,7 +188,10 @@ function findAgentTools(cfg: unknown, agentId: string): AgentToolsConfigShape |
|
|
|
183
188
|
* The agent's full tool catalog with per-tool effective state, or null if the core
|
|
184
189
|
* catalog builder can't be located.
|
|
185
190
|
*/
|
|
186
|
-
export async function buildAgentToolsCatalog(
|
|
191
|
+
export async function buildAgentToolsCatalog(
|
|
192
|
+
cfg: unknown,
|
|
193
|
+
agentId: string,
|
|
194
|
+
): Promise<AgentToolsCatalog | null> {
|
|
187
195
|
const build = await loadBuildFn();
|
|
188
196
|
if (!build) return null;
|
|
189
197
|
// Snapshot the channel registry so we can undo the build's `surface:"channel"` re-pin
|
|
@@ -214,7 +222,8 @@ export async function buildAgentToolsCatalog(cfg: unknown, agentId: string): Pro
|
|
|
214
222
|
}
|
|
215
223
|
|
|
216
224
|
const tools = findAgentTools(cfg, agentId);
|
|
217
|
-
const profile =
|
|
225
|
+
const profile =
|
|
226
|
+
typeof tools?.profile === "string" && tools.profile.trim() ? tools.profile.trim() : null;
|
|
218
227
|
const allow = new Set(readStringArray(tools?.allow));
|
|
219
228
|
const alsoAllow = new Set(readStringArray(tools?.alsoAllow));
|
|
220
229
|
const deny = new Set(readStringArray(tools?.deny));
|
package/src/upgrade-runtime.ts
CHANGED
|
@@ -28,7 +28,7 @@ export type UpgradeRuntime = {
|
|
|
28
28
|
/** Mutate the config file; `afterWrite: { mode: "restart" }` triggers a safe gateway restart. */
|
|
29
29
|
mutateConfigFile: (params: {
|
|
30
30
|
afterWrite: ConfigAfterWrite;
|
|
31
|
-
mutate: (draft: unknown) => unknown
|
|
31
|
+
mutate: (draft: unknown) => unknown;
|
|
32
32
|
}) => Promise<unknown>;
|
|
33
33
|
/**
|
|
34
34
|
* Filesystem path of THIS loaded plugin (`api.source`). Used to infer the install
|
|
@@ -42,7 +42,9 @@ let upgradeRuntime: UpgradeRuntime | null = null;
|
|
|
42
42
|
|
|
43
43
|
export function setUpgradeRuntime(api: OpenClawPluginApi): void {
|
|
44
44
|
const runtime = api.runtime as unknown as {
|
|
45
|
-
system?: {
|
|
45
|
+
system?: {
|
|
46
|
+
runCommandWithTimeout?: (argv: string[], opts: unknown) => Promise<SpawnResultLike>;
|
|
47
|
+
};
|
|
46
48
|
config: {
|
|
47
49
|
current: () => unknown;
|
|
48
50
|
mutateConfigFile?: (params: unknown) => Promise<unknown>;
|
package/src/version.ts
CHANGED
|
@@ -22,7 +22,11 @@ function resolvePluginVersion(): string {
|
|
|
22
22
|
const path = fileURLToPath(new URL(rel, import.meta.url));
|
|
23
23
|
const raw = readFileSync(path, "utf8");
|
|
24
24
|
const pkg = JSON.parse(raw) as { name?: string; version?: string };
|
|
25
|
-
if (
|
|
25
|
+
if (
|
|
26
|
+
pkg.name === "@syengup/friday-channel-next" &&
|
|
27
|
+
typeof pkg.version === "string" &&
|
|
28
|
+
pkg.version
|
|
29
|
+
) {
|
|
26
30
|
return pkg.version;
|
|
27
31
|
}
|
|
28
32
|
} catch {
|
package/tsconfig.json
CHANGED