@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.
Files changed (120) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/src/agent/dispatch-bridge.d.ts +1 -1
  3. package/dist/src/agent/node-pairing-bridge.d.ts +11 -8
  4. package/dist/src/agent/node-pairing-bridge.js +6 -2
  5. package/dist/src/agent/subagent-registry.js +0 -3
  6. package/dist/src/channel-actions.js +3 -1
  7. package/dist/src/channel.js +0 -2
  8. package/dist/src/collect-message-media-paths.js +10 -1
  9. package/dist/src/friday-session.js +34 -10
  10. package/dist/src/history/normalize-message.js +22 -8
  11. package/dist/src/http/handlers/agent-config.js +10 -4
  12. package/dist/src/http/handlers/cancel.js +4 -2
  13. package/dist/src/http/handlers/device-approve.js +3 -1
  14. package/dist/src/http/handlers/files-download.js +6 -8
  15. package/dist/src/http/handlers/files.js +1 -1
  16. package/dist/src/http/handlers/health.js +18 -4
  17. package/dist/src/http/handlers/history-messages.js +1 -1
  18. package/dist/src/http/handlers/history-sessions.js +5 -3
  19. package/dist/src/http/handlers/messages.js +25 -11
  20. package/dist/src/http/handlers/models-list.js +1 -1
  21. package/dist/src/http/handlers/nodes-approve.js +1 -6
  22. package/dist/src/http/handlers/plugin-info.js +1 -1
  23. package/dist/src/http/server.js +4 -2
  24. package/dist/src/link-preview/og-parse.js +3 -1
  25. package/dist/src/plugin-install-info.js +4 -1
  26. package/dist/src/session/session-manager.js +9 -3
  27. package/dist/src/session-usage-store.js +3 -1
  28. package/dist/src/skills-discovery.d.ts +5 -4
  29. package/dist/src/skills-discovery.js +27 -22
  30. package/dist/src/sse/offline-queue.js +4 -1
  31. package/dist/src/tool-catalog.js +2 -3
  32. package/dist/src/upgrade-runtime.d.ts +1 -1
  33. package/dist/src/version.js +3 -1
  34. package/index.ts +43 -35
  35. package/install.js +131 -43
  36. package/package.json +10 -1
  37. package/src/agent/abort-run.ts +2 -3
  38. package/src/agent/dispatch-bridge.ts +2 -1
  39. package/src/agent/media-bridge.ts +9 -2
  40. package/src/agent/node-pairing-bridge.ts +29 -15
  41. package/src/agent/run-usage-accumulator.ts +4 -2
  42. package/src/agent/subagent-registry.ts +0 -4
  43. package/src/agent-run-context-bridge.ts +3 -1
  44. package/src/channel-actions.test.ts +10 -4
  45. package/src/channel-actions.ts +3 -1
  46. package/src/channel.outbound.test.ts +18 -4
  47. package/src/channel.ts +121 -123
  48. package/src/collect-message-media-paths.ts +15 -6
  49. package/src/config.ts +1 -4
  50. package/src/e2e/agents-list.e2e.test.ts +9 -2
  51. package/src/e2e/attachments-inbound.e2e.test.ts +5 -1
  52. package/src/e2e/attachments-outbound.e2e.test.ts +7 -2
  53. package/src/e2e/auto-approve.integration.test.ts +13 -7
  54. package/src/e2e/cancel-reconnect-errors.e2e.test.ts +18 -3
  55. package/src/e2e/connect-and-connected.e2e.test.ts +5 -1
  56. package/src/e2e/offline-replay.e2e.test.ts +17 -3
  57. package/src/e2e/send-text.e2e.test.ts +11 -2
  58. package/src/e2e/slash-commands.e2e.test.ts +5 -1
  59. package/src/e2e/status-cors-auth.e2e.test.ts +11 -2
  60. package/src/e2e/subagent-smoke.e2e.test.ts +68 -28
  61. package/src/e2e/subagent.e2e.test.ts +136 -53
  62. package/src/e2e/tool-lifecycle.e2e.test.ts +5 -1
  63. package/src/friday-session.forward-agent.test.ts +44 -12
  64. package/src/friday-session.ts +44 -20
  65. package/src/history/normalize-message.test.ts +35 -8
  66. package/src/history/normalize-message.ts +24 -12
  67. package/src/history/read-transcript.ts +1 -4
  68. package/src/http/handlers/agent-config.test.ts +10 -3
  69. package/src/http/handlers/agent-config.ts +22 -8
  70. package/src/http/handlers/agents-list.test.ts +1 -5
  71. package/src/http/handlers/cancel.test.ts +12 -3
  72. package/src/http/handlers/cancel.ts +4 -2
  73. package/src/http/handlers/device-approve.test.ts +12 -3
  74. package/src/http/handlers/device-approve.ts +33 -21
  75. package/src/http/handlers/files-download.ts +17 -13
  76. package/src/http/handlers/files.test.ts +8 -2
  77. package/src/http/handlers/files.ts +21 -7
  78. package/src/http/handlers/health.test.ts +43 -11
  79. package/src/http/handlers/health.ts +22 -6
  80. package/src/http/handlers/history-messages.test.ts +51 -9
  81. package/src/http/handlers/history-messages.ts +4 -1
  82. package/src/http/handlers/history-sessions.test.ts +46 -9
  83. package/src/http/handlers/history-sessions.ts +5 -3
  84. package/src/http/handlers/history-set-title.test.ts +14 -5
  85. package/src/http/handlers/link-preview.test.ts +57 -16
  86. package/src/http/handlers/link-preview.ts +4 -1
  87. package/src/http/handlers/messages.test.ts +12 -8
  88. package/src/http/handlers/messages.ts +57 -19
  89. package/src/http/handlers/models-list.ts +14 -8
  90. package/src/http/handlers/nodes-approve.test.ts +15 -4
  91. package/src/http/handlers/nodes-approve.ts +38 -40
  92. package/src/http/handlers/plugin-info.ts +5 -6
  93. package/src/http/handlers/plugin-upgrade.ts +4 -1
  94. package/src/http/handlers/sse.ts +3 -1
  95. package/src/http/server.ts +9 -6
  96. package/src/link-preview/og-parse.test.ts +6 -2
  97. package/src/link-preview/og-parse.ts +10 -3
  98. package/src/link-preview/preview-service.ts +4 -1
  99. package/src/link-preview/ssrf-guard.test.ts +72 -15
  100. package/src/link-preview/ssrf-guard.ts +2 -1
  101. package/src/media-fetch.test.ts +7 -2
  102. package/src/media-fetch.ts +1 -2
  103. package/src/openclaw.d.ts +16 -9
  104. package/src/plugin-install-info.ts +20 -9
  105. package/src/run-metadata.ts +2 -1
  106. package/src/session/session-manager.ts +19 -11
  107. package/src/session-usage-snapshot.ts +3 -1
  108. package/src/session-usage-store.ts +3 -1
  109. package/src/skills-discovery.test.ts +14 -10
  110. package/src/skills-discovery.ts +43 -27
  111. package/src/sse/emitter.test.ts +1 -1
  112. package/src/sse/emitter.ts +9 -3
  113. package/src/sse/offline-queue.ts +17 -8
  114. package/src/test-support/app-simulator.ts +17 -3
  115. package/src/test-support/mock-dispatch.ts +17 -4
  116. package/src/thinking-levels.ts +3 -1
  117. package/src/tool-catalog.ts +16 -7
  118. package/src/upgrade-runtime.ts +4 -2
  119. package/src/version.ts +5 -1
  120. package/tsconfig.json +1 -1
@@ -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(getHostOpenClawConfigSnapshot(getFridayNextRuntime().config));
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(deviceId: string, id: number, event: string, data: Record<string, unknown>, backlogLimit: number): void {
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 (typeof o.id === "number" && typeof o.event === "string" && o.data && typeof o.data === "object") {
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: ((req: Readable & { method?: string; url?: string }, res: Writable) => Promise<boolean>) | null = null;
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(parts: Array<{ name: string; filename: string; contentType: string; content: string | Buffer }>) {
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: { method: string; path: string; headers?: Headers; body?: string | Buffer }) {
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 { __setMockFridayDispatchForTests, __resetMockFridayDispatchForTests } from "../agent/dispatch-bridge.js";
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 (arg: infer A) => unknown
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?.({ text, mediaUrls, audioAsVoice } as never, { kind: "block" } as never);
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: { text: string; mediaUrls?: string[]; audioAsVoice?: boolean; isError?: boolean }): this {
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
  });
@@ -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(modelRef: string | undefined | null): ResolvedModelThinking {
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);
@@ -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: { cfg: unknown; agentId?: string; includePlugins?: boolean }) => CoreCatalogResult;
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") return mod.buildToolsCatalogResult as BuildFn;
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 = ((cfg as Record<string, unknown> | undefined)?.agents as Record<string, unknown> | undefined)
176
- ?.list as Array<Record<string, unknown>> | undefined;
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(cfg: unknown, agentId: string): Promise<AgentToolsCatalog | null> {
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 = (typeof tools?.profile === "string" && tools.profile.trim()) ? tools.profile.trim() : null;
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));
@@ -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 | void;
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?: { runCommandWithTimeout?: (argv: string[], opts: unknown) => Promise<SpawnResultLike> };
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 (pkg.name === "@syengup/friday-channel-next" && typeof pkg.version === "string" && pkg.version) {
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
@@ -14,4 +14,4 @@
14
14
  },
15
15
  "include": ["index.ts", "src/**/*.ts", "src/**/*.d.ts"],
16
16
  "exclude": ["src/e2e/**", "src/**/*.test.ts", "src/test-support/**", "scripts/**"]
17
- }
17
+ }