sparkecoder 0.1.68 → 0.1.69
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/agent/index.d.ts +3 -3
- package/dist/agent/index.js +38 -6
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +107 -16
- package/dist/cli.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/{index-Dm6wGcYv.d.ts → index-DqaHLgSC.d.ts} +19 -19
- package/dist/index.d.ts +5 -5
- package/dist/index.js +107 -16
- package/dist/index.js.map +1 -1
- package/dist/{schema-XcP0dedO.d.ts → schema-Bq4tID-f.d.ts} +3 -3
- package/dist/{search-CCffrVJE.d.ts → search-BRnGaIl-.d.ts} +7 -7
- package/dist/server/index.js +107 -16
- package/dist/server/index.js.map +1 -1
- package/dist/tools/index.d.ts +2 -2
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/web/.next/server/app/index.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__c71f29f9._.js +3 -3
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_2b3a5919._.js +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_38156da8._.js +1 -1
- package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/{static/chunks/4e673433173ad456.js → standalone/web/.next/static/chunks/2cafc7cb79454d33.js} +3 -3
- package/web/.next/standalone/web/.next/static/chunks/{515f0c0bd6087843.js → b6ec74cad9ffd3ee.js} +3 -3
- package/web/.next/standalone/web/.next/static/chunks/{31208ade542a0fcb.js → fc39a194539da104.js} +3 -3
- package/web/.next/standalone/web/.next/static/{chunks/4e673433173ad456.js → static/chunks/2cafc7cb79454d33.js} +3 -3
- package/web/.next/standalone/web/.next/static/static/chunks/{515f0c0bd6087843.js → b6ec74cad9ffd3ee.js} +3 -3
- package/web/.next/{static/chunks/31208ade542a0fcb.js → standalone/web/.next/static/static/chunks/fc39a194539da104.js} +3 -3
- package/web/.next/standalone/web/src/components/chat-interface.tsx +14 -0
- package/web/.next/standalone/web/src/lib/api.ts +89 -16
- package/web/.next/{standalone/web/.next/static/static/chunks/4e673433173ad456.js → static/chunks/2cafc7cb79454d33.js} +3 -3
- package/web/.next/static/chunks/{515f0c0bd6087843.js → b6ec74cad9ffd3ee.js} +3 -3
- package/web/.next/{standalone/web/.next/static/static/chunks/31208ade542a0fcb.js → static/chunks/fc39a194539da104.js} +3 -3
- /package/web/.next/standalone/web/.next/static/{6Dlxqhgk8Mki7q7L-gDbl → XB638PEDChQhwk6wSMrSh}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{6Dlxqhgk8Mki7q7L-gDbl → XB638PEDChQhwk6wSMrSh}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{6Dlxqhgk8Mki7q7L-gDbl → XB638PEDChQhwk6wSMrSh}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{6Dlxqhgk8Mki7q7L-gDbl → XB638PEDChQhwk6wSMrSh}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{6Dlxqhgk8Mki7q7L-gDbl → XB638PEDChQhwk6wSMrSh}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/static/{6Dlxqhgk8Mki7q7L-gDbl → XB638PEDChQhwk6wSMrSh}/_ssgManifest.js +0 -0
- /package/web/.next/static/{6Dlxqhgk8Mki7q7L-gDbl → XB638PEDChQhwk6wSMrSh}/_buildManifest.js +0 -0
- /package/web/.next/static/{6Dlxqhgk8Mki7q7L-gDbl → XB638PEDChQhwk6wSMrSh}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{6Dlxqhgk8Mki7q7L-gDbl → XB638PEDChQhwk6wSMrSh}/_ssgManifest.js +0 -0
|
@@ -85,7 +85,7 @@ declare const sessions: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
85
85
|
tableName: "sessions";
|
|
86
86
|
dataType: "string";
|
|
87
87
|
columnType: "SQLiteText";
|
|
88
|
-
data: "
|
|
88
|
+
data: "active" | "waiting" | "completed" | "error";
|
|
89
89
|
driverParam: string;
|
|
90
90
|
notNull: true;
|
|
91
91
|
hasDefault: true;
|
|
@@ -391,7 +391,7 @@ declare const toolExecutions: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
391
391
|
tableName: "tool_executions";
|
|
392
392
|
dataType: "string";
|
|
393
393
|
columnType: "SQLiteText";
|
|
394
|
-
data: "
|
|
394
|
+
data: "completed" | "error" | "pending" | "approved" | "rejected";
|
|
395
395
|
driverParam: string;
|
|
396
396
|
notNull: true;
|
|
397
397
|
hasDefault: true;
|
|
@@ -967,7 +967,7 @@ declare const activeStreams: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
|
|
|
967
967
|
tableName: "active_streams";
|
|
968
968
|
dataType: "string";
|
|
969
969
|
columnType: "SQLiteText";
|
|
970
|
-
data: "
|
|
970
|
+
data: "active" | "error" | "finished";
|
|
971
971
|
driverParam: string;
|
|
972
972
|
notNull: true;
|
|
973
973
|
hasDefault: true;
|
|
@@ -15,12 +15,12 @@ interface BashToolOptions {
|
|
|
15
15
|
}
|
|
16
16
|
declare function createBashTool(options: BashToolOptions): ai.Tool<{
|
|
17
17
|
background: boolean;
|
|
18
|
-
input?: string | undefined;
|
|
19
18
|
id?: string | undefined;
|
|
19
|
+
input?: string | undefined;
|
|
20
20
|
command?: string | undefined;
|
|
21
21
|
kill?: boolean | undefined;
|
|
22
22
|
tail?: number | undefined;
|
|
23
|
-
key?: "
|
|
23
|
+
key?: "Enter" | "Escape" | "Up" | "Down" | "Left" | "Right" | "Tab" | "C-c" | "C-d" | "y" | "n" | undefined;
|
|
24
24
|
}, {
|
|
25
25
|
success: boolean;
|
|
26
26
|
id: string;
|
|
@@ -41,7 +41,7 @@ declare function createBashTool(options: BashToolOptions): ai.Tool<{
|
|
|
41
41
|
success: boolean;
|
|
42
42
|
id: string;
|
|
43
43
|
output: string;
|
|
44
|
-
status: "
|
|
44
|
+
status: "running" | "stopped" | "unknown";
|
|
45
45
|
message: string;
|
|
46
46
|
error?: undefined;
|
|
47
47
|
exitCode?: undefined;
|
|
@@ -49,7 +49,7 @@ declare function createBashTool(options: BashToolOptions): ai.Tool<{
|
|
|
49
49
|
success: boolean;
|
|
50
50
|
id: string;
|
|
51
51
|
output: string;
|
|
52
|
-
status: "
|
|
52
|
+
status: "running" | "stopped" | "unknown";
|
|
53
53
|
message?: undefined;
|
|
54
54
|
error?: undefined;
|
|
55
55
|
exitCode?: undefined;
|
|
@@ -66,7 +66,7 @@ declare function createBashTool(options: BashToolOptions): ai.Tool<{
|
|
|
66
66
|
id: string;
|
|
67
67
|
output: string;
|
|
68
68
|
exitCode: number;
|
|
69
|
-
status: "
|
|
69
|
+
status: "completed" | "error" | "running" | "stopped";
|
|
70
70
|
message?: undefined;
|
|
71
71
|
error?: undefined;
|
|
72
72
|
} | {
|
|
@@ -116,8 +116,8 @@ interface WriteFileToolOptions {
|
|
|
116
116
|
onProgress?: (progress: WriteFileProgress) => void;
|
|
117
117
|
}
|
|
118
118
|
declare function createWriteFileTool(options: WriteFileToolOptions): ai.Tool<{
|
|
119
|
-
path: string;
|
|
120
119
|
mode: "full" | "str_replace";
|
|
120
|
+
path: string;
|
|
121
121
|
content?: string | undefined;
|
|
122
122
|
old_string?: string | undefined;
|
|
123
123
|
new_string?: string | undefined;
|
|
@@ -218,8 +218,8 @@ interface SearchToolOptions {
|
|
|
218
218
|
* Progress is streamed back to the UI so users can see exploration happening.
|
|
219
219
|
*/
|
|
220
220
|
declare function createSearchTool(options: SearchToolOptions): ai.Tool<{
|
|
221
|
-
context: string;
|
|
222
221
|
query: string;
|
|
222
|
+
context: string;
|
|
223
223
|
}, {
|
|
224
224
|
success: boolean;
|
|
225
225
|
error: string;
|
package/dist/server/index.js
CHANGED
|
@@ -1785,10 +1785,15 @@ import WebSocket from "ws";
|
|
|
1785
1785
|
import { EventEmitter } from "events";
|
|
1786
1786
|
function getOrCreateProxy(sessionId, port) {
|
|
1787
1787
|
const existing = activeProxies.get(sessionId);
|
|
1788
|
-
if (existing)
|
|
1788
|
+
if (existing) {
|
|
1789
|
+
console.log(`[BROWSER-WS] Reusing existing proxy for session ${sessionId} (connected=${existing.connected})`);
|
|
1790
|
+
return existing;
|
|
1791
|
+
}
|
|
1792
|
+
console.log(`[BROWSER-WS] Creating new proxy for session ${sessionId} on port ${port} (active proxies: ${activeProxies.size})`);
|
|
1789
1793
|
const proxy = new BrowserStreamProxy(port);
|
|
1790
1794
|
activeProxies.set(sessionId, proxy);
|
|
1791
1795
|
proxy.on("close", () => {
|
|
1796
|
+
console.log(`[BROWSER-WS] Proxy closed for session ${sessionId}, removing from registry`);
|
|
1792
1797
|
activeProxies.delete(sessionId);
|
|
1793
1798
|
});
|
|
1794
1799
|
proxy.connect();
|
|
@@ -1800,8 +1805,11 @@ function getProxy(sessionId) {
|
|
|
1800
1805
|
function destroyProxy(sessionId) {
|
|
1801
1806
|
const proxy = activeProxies.get(sessionId);
|
|
1802
1807
|
if (proxy) {
|
|
1808
|
+
console.log(`[BROWSER-WS] destroyProxy() called for session ${sessionId}`);
|
|
1803
1809
|
proxy.destroy();
|
|
1804
1810
|
activeProxies.delete(sessionId);
|
|
1811
|
+
} else {
|
|
1812
|
+
console.log(`[BROWSER-WS] destroyProxy() called but no proxy exists for session ${sessionId}`);
|
|
1805
1813
|
}
|
|
1806
1814
|
}
|
|
1807
1815
|
var RECONNECT_DELAY_MS, MAX_RECONNECT_ATTEMPTS, FRAME_THROTTLE_MS, BrowserStreamProxy, activeProxies;
|
|
@@ -1832,18 +1840,22 @@ var init_stream_proxy = __esm({
|
|
|
1832
1840
|
}
|
|
1833
1841
|
connect() {
|
|
1834
1842
|
if (this.destroyed) return;
|
|
1843
|
+
console.log(`[BROWSER-WS] connect() called for port ${this.port}`);
|
|
1835
1844
|
this.doConnect();
|
|
1836
1845
|
}
|
|
1837
1846
|
doConnect() {
|
|
1838
1847
|
if (this.destroyed) return;
|
|
1839
1848
|
const url = `ws://localhost:${this.port}`;
|
|
1849
|
+
console.log(`[BROWSER-WS] Attempting WebSocket connection to ${url} (attempt ${this.reconnectAttempts + 1}/${MAX_RECONNECT_ATTEMPTS})`);
|
|
1840
1850
|
try {
|
|
1841
1851
|
this.ws = new WebSocket(url);
|
|
1842
|
-
} catch {
|
|
1852
|
+
} catch (err) {
|
|
1853
|
+
console.warn(`[BROWSER-WS] WebSocket constructor threw for ${url}:`, err);
|
|
1843
1854
|
this.scheduleReconnect();
|
|
1844
1855
|
return;
|
|
1845
1856
|
}
|
|
1846
1857
|
this.ws.on("open", () => {
|
|
1858
|
+
console.log(`[BROWSER-WS] Connected to ${url} (after ${this.reconnectAttempts} retries)`);
|
|
1847
1859
|
this.reconnectAttempts = 0;
|
|
1848
1860
|
this._connected = true;
|
|
1849
1861
|
this.emit("status", {
|
|
@@ -1855,12 +1867,14 @@ var init_stream_proxy = __esm({
|
|
|
1855
1867
|
try {
|
|
1856
1868
|
const msg = JSON.parse(typeof raw === "string" ? raw : raw.toString("utf8"));
|
|
1857
1869
|
this.handleMessage(msg);
|
|
1858
|
-
} catch {
|
|
1870
|
+
} catch (err) {
|
|
1871
|
+
console.warn(`[BROWSER-WS] Malformed message from ${url}:`, err);
|
|
1859
1872
|
}
|
|
1860
1873
|
});
|
|
1861
|
-
this.ws.on("close", () => {
|
|
1874
|
+
this.ws.on("close", (code, reason) => {
|
|
1862
1875
|
const wasConnected = this._connected;
|
|
1863
1876
|
this._connected = false;
|
|
1877
|
+
console.log(`[BROWSER-WS] Connection closed: code=${code} reason="${reason?.toString() || ""}" wasConnected=${wasConnected} destroyed=${this.destroyed}`);
|
|
1864
1878
|
if (wasConnected) {
|
|
1865
1879
|
this.emit("status", { connected: false, screencasting: false });
|
|
1866
1880
|
}
|
|
@@ -1868,14 +1882,26 @@ var init_stream_proxy = __esm({
|
|
|
1868
1882
|
this.scheduleReconnect();
|
|
1869
1883
|
}
|
|
1870
1884
|
});
|
|
1871
|
-
this.ws.on("error", () => {
|
|
1885
|
+
this.ws.on("error", (err) => {
|
|
1886
|
+
console.warn(`[BROWSER-WS] WebSocket error on port ${this.port}:`, err.message);
|
|
1872
1887
|
});
|
|
1873
1888
|
}
|
|
1889
|
+
frameCount = 0;
|
|
1890
|
+
throttledCount = 0;
|
|
1891
|
+
lastFrameLogTime = 0;
|
|
1874
1892
|
handleMessage(msg) {
|
|
1875
1893
|
if (msg.type === "frame") {
|
|
1876
1894
|
const now = Date.now();
|
|
1877
|
-
if (now - this.lastFrameTime < FRAME_THROTTLE_MS)
|
|
1895
|
+
if (now - this.lastFrameTime < FRAME_THROTTLE_MS) {
|
|
1896
|
+
this.throttledCount++;
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1878
1899
|
this.lastFrameTime = now;
|
|
1900
|
+
this.frameCount++;
|
|
1901
|
+
if (now - this.lastFrameLogTime > 5e3) {
|
|
1902
|
+
console.log(`[BROWSER-WS] Frame stats: emitted=${this.frameCount} throttled=${this.throttledCount} listeners=${this.listenerCount("frame")} dataSize=${msg.data?.length ?? 0}`);
|
|
1903
|
+
this.lastFrameLogTime = now;
|
|
1904
|
+
}
|
|
1879
1905
|
const frame = {
|
|
1880
1906
|
data: msg.data,
|
|
1881
1907
|
metadata: msg.metadata ?? {
|
|
@@ -1891,21 +1917,26 @@ var init_stream_proxy = __esm({
|
|
|
1891
1917
|
this._latestFrame = frame;
|
|
1892
1918
|
this.emit("frame", frame);
|
|
1893
1919
|
} else if (msg.type === "status") {
|
|
1920
|
+
console.log(`[BROWSER-WS] Status message received:`, JSON.stringify(msg));
|
|
1894
1921
|
this.emit("status", {
|
|
1895
1922
|
connected: msg.connected ?? true,
|
|
1896
1923
|
screencasting: msg.screencasting ?? true,
|
|
1897
1924
|
viewportWidth: msg.viewportWidth,
|
|
1898
1925
|
viewportHeight: msg.viewportHeight
|
|
1899
1926
|
});
|
|
1927
|
+
} else {
|
|
1928
|
+
console.log(`[BROWSER-WS] Unknown message type: ${msg.type}`);
|
|
1900
1929
|
}
|
|
1901
1930
|
}
|
|
1902
1931
|
scheduleReconnect() {
|
|
1903
1932
|
if (this.destroyed || this.reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
1933
|
+
console.log(`[BROWSER-WS] Giving up reconnection: destroyed=${this.destroyed} attempts=${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS}`);
|
|
1904
1934
|
this.emit("close");
|
|
1905
1935
|
return;
|
|
1906
1936
|
}
|
|
1907
1937
|
this.reconnectAttempts++;
|
|
1908
1938
|
const delay = this.reconnectAttempts <= 5 ? RECONNECT_DELAY_MS : RECONNECT_DELAY_MS * (this.reconnectAttempts - 4);
|
|
1939
|
+
console.log(`[BROWSER-WS] Scheduling reconnect in ${delay}ms (attempt ${this.reconnectAttempts}/${MAX_RECONNECT_ATTEMPTS})`);
|
|
1909
1940
|
this.reconnectTimer = setTimeout(() => this.doConnect(), delay);
|
|
1910
1941
|
}
|
|
1911
1942
|
/**
|
|
@@ -1917,6 +1948,7 @@ var init_stream_proxy = __esm({
|
|
|
1917
1948
|
}
|
|
1918
1949
|
}
|
|
1919
1950
|
destroy() {
|
|
1951
|
+
console.log(`[BROWSER-WS] Destroying proxy for port ${this.port} (emitted ${this.frameCount} frames, throttled ${this.throttledCount})`);
|
|
1920
1952
|
this.destroyed = true;
|
|
1921
1953
|
if (this.reconnectTimer) {
|
|
1922
1954
|
clearTimeout(this.reconnectTimer);
|
|
@@ -8063,11 +8095,19 @@ var cleanupInterval = setInterval(() => {
|
|
|
8063
8095
|
}
|
|
8064
8096
|
}, 6e4);
|
|
8065
8097
|
cleanupInterval.unref();
|
|
8098
|
+
var publishCount = 0;
|
|
8099
|
+
var lastPublishLog = 0;
|
|
8066
8100
|
var publisher = {
|
|
8067
8101
|
connect: async () => {
|
|
8068
8102
|
},
|
|
8069
8103
|
publish: async (channel, message) => {
|
|
8070
8104
|
const subscribers = channels.get(channel);
|
|
8105
|
+
publishCount++;
|
|
8106
|
+
const now = Date.now();
|
|
8107
|
+
if (now - lastPublishLog > 1e4) {
|
|
8108
|
+
console.log(`[ResumableStream] Publish stats: total=${publishCount}, channels=${channels.size}, store=${store.size}`);
|
|
8109
|
+
lastPublishLog = now;
|
|
8110
|
+
}
|
|
8071
8111
|
if (subscribers) {
|
|
8072
8112
|
for (const callback of subscribers) {
|
|
8073
8113
|
setImmediate(() => callback(message));
|
|
@@ -8106,9 +8146,12 @@ var subscriber = {
|
|
|
8106
8146
|
channels.set(channel, /* @__PURE__ */ new Set());
|
|
8107
8147
|
}
|
|
8108
8148
|
channels.get(channel).add(callback);
|
|
8149
|
+
console.log(`[ResumableStream] Subscribe to channel "${channel}" (total subscribers: ${channels.get(channel).size})`);
|
|
8109
8150
|
},
|
|
8110
8151
|
unsubscribe: async (channel) => {
|
|
8152
|
+
const count = channels.get(channel)?.size ?? 0;
|
|
8111
8153
|
channels.delete(channel);
|
|
8154
|
+
console.log(`[ResumableStream] Unsubscribe from channel "${channel}" (removed ${count} subscribers)`);
|
|
8112
8155
|
}
|
|
8113
8156
|
};
|
|
8114
8157
|
var streamContext = createResumableStreamContext({
|
|
@@ -8294,19 +8337,28 @@ function createAgentStreamProducer(sessionId, prompt, streamId, attachments) {
|
|
|
8294
8337
|
const toolCallStarts = /* @__PURE__ */ new Set();
|
|
8295
8338
|
const abortController = new AbortController();
|
|
8296
8339
|
streamAbortControllers.set(streamId, abortController);
|
|
8340
|
+
let sseEventCount = 0;
|
|
8341
|
+
let sseBrowserFrameCount = 0;
|
|
8342
|
+
let sseWriteErrors = 0;
|
|
8297
8343
|
const writeSSE = async (data) => {
|
|
8298
8344
|
if (writerClosed) return;
|
|
8299
8345
|
try {
|
|
8346
|
+
sseEventCount++;
|
|
8300
8347
|
await writer.write(`data: ${data}
|
|
8301
8348
|
|
|
8302
8349
|
`);
|
|
8303
8350
|
} catch (err) {
|
|
8351
|
+
sseWriteErrors++;
|
|
8352
|
+
if (sseWriteErrors === 1) {
|
|
8353
|
+
console.log(`[SSE:${streamId}] Writer closed (client disconnected). Total events sent: ${sseEventCount}, browser frames: ${sseBrowserFrameCount}`);
|
|
8354
|
+
}
|
|
8304
8355
|
writerClosed = true;
|
|
8305
8356
|
}
|
|
8306
8357
|
};
|
|
8307
8358
|
const safeClose = async () => {
|
|
8308
8359
|
if (writerClosed) return;
|
|
8309
8360
|
try {
|
|
8361
|
+
console.log(`[SSE:${streamId}] Stream closing. Total events: ${sseEventCount}, browser frames: ${sseBrowserFrameCount}, write errors: ${sseWriteErrors}`);
|
|
8310
8362
|
writerClosed = true;
|
|
8311
8363
|
await writer.close();
|
|
8312
8364
|
} catch {
|
|
@@ -8429,35 +8481,47 @@ ${prompt}` });
|
|
|
8429
8481
|
const browserPort = progress.data?.browserStreamPort;
|
|
8430
8482
|
const browserClosed = progress.data?.browserClosed;
|
|
8431
8483
|
if (progress.toolName === "bash" && browserClosed) {
|
|
8432
|
-
console.log(`[BROWSER-STREAM] agent-browser close detected, destroying proxy`);
|
|
8484
|
+
console.log(`[BROWSER-STREAM:${streamId}] agent-browser close detected, destroying proxy for session ${sessionId}`);
|
|
8433
8485
|
destroyProxy(sessionId);
|
|
8434
8486
|
} else if (progress.toolName === "bash" && browserPort) {
|
|
8435
|
-
console.log(`[BROWSER-STREAM] agent-browser command detected, ensuring proxy on port ${browserPort}`);
|
|
8487
|
+
console.log(`[BROWSER-STREAM:${streamId}] agent-browser command detected, ensuring proxy on port ${browserPort} for session ${sessionId}`);
|
|
8436
8488
|
const proxy = getOrCreateProxy(sessionId, browserPort);
|
|
8489
|
+
console.log(`[BROWSER-STREAM:${streamId}] Proxy state: connected=${proxy.connected}, frameListeners=${proxy.listenerCount("frame")}, statusListeners=${proxy.listenerCount("status")}`);
|
|
8437
8490
|
if (!sessionRecorders.has(sessionId)) {
|
|
8438
8491
|
const recorder = new FrameRecorder(sessionId);
|
|
8439
8492
|
recorder.start();
|
|
8440
8493
|
sessionRecorders.set(sessionId, recorder);
|
|
8441
8494
|
}
|
|
8442
8495
|
if (proxy.listenerCount("frame") === 0) {
|
|
8496
|
+
console.log(`[BROWSER-STREAM:${streamId}] Attaching frame+status listeners to proxy`);
|
|
8443
8497
|
proxy.on("frame", (frame) => {
|
|
8498
|
+
sseBrowserFrameCount++;
|
|
8499
|
+
if (sseBrowserFrameCount === 1) {
|
|
8500
|
+
console.log(`[BROWSER-STREAM:${streamId}] First browser frame received! dataSize=${frame.data?.length ?? 0} writerClosed=${writerClosed}`);
|
|
8501
|
+
} else if (sseBrowserFrameCount % 50 === 0) {
|
|
8502
|
+
console.log(`[BROWSER-STREAM:${streamId}] Browser frame #${sseBrowserFrameCount} (writerClosed=${writerClosed})`);
|
|
8503
|
+
}
|
|
8444
8504
|
const rec = sessionRecorders.get(sessionId);
|
|
8445
8505
|
rec?.addFrame(frame);
|
|
8446
8506
|
writeSSE(JSON.stringify({
|
|
8447
8507
|
type: "browser-frame",
|
|
8448
8508
|
data: frame.data,
|
|
8449
8509
|
metadata: frame.metadata
|
|
8450
|
-
})).catch(() => {
|
|
8510
|
+
})).catch((err) => {
|
|
8511
|
+
console.warn(`[BROWSER-STREAM:${streamId}] Failed to send browser-frame via SSE:`, err);
|
|
8451
8512
|
});
|
|
8452
8513
|
});
|
|
8453
8514
|
proxy.on("status", (s) => {
|
|
8454
|
-
console.log(`[BROWSER-STREAM]
|
|
8515
|
+
console.log(`[BROWSER-STREAM:${streamId}] Browser status event: connected=${s.connected} screencasting=${s.screencasting} viewport=${s.viewportWidth}x${s.viewportHeight}`);
|
|
8455
8516
|
writeSSE(JSON.stringify({
|
|
8456
8517
|
type: "browser-status",
|
|
8457
8518
|
...s
|
|
8458
|
-
})).catch(() => {
|
|
8519
|
+
})).catch((err) => {
|
|
8520
|
+
console.warn(`[BROWSER-STREAM:${streamId}] Failed to send browser-status via SSE:`, err);
|
|
8459
8521
|
});
|
|
8460
8522
|
});
|
|
8523
|
+
} else {
|
|
8524
|
+
console.log(`[BROWSER-STREAM:${streamId}] Frame listeners already attached (count=${proxy.listenerCount("frame")}), skipping`);
|
|
8461
8525
|
}
|
|
8462
8526
|
}
|
|
8463
8527
|
},
|
|
@@ -8647,14 +8711,17 @@ ${prompt}` });
|
|
|
8647
8711
|
}
|
|
8648
8712
|
await messageQueries.create(id, { role: "user", content: userMessageContent });
|
|
8649
8713
|
const streamId = `stream_${id}_${nanoid6(10)}`;
|
|
8714
|
+
console.log(`[STREAM] Creating stream ${streamId} for session ${id}`);
|
|
8650
8715
|
await activeStreamQueries.create(id, streamId);
|
|
8651
8716
|
const stream = await streamContext.resumableStream(
|
|
8652
8717
|
streamId,
|
|
8653
8718
|
createAgentStreamProducer(id, prompt, streamId, streamAttachments)
|
|
8654
8719
|
);
|
|
8655
8720
|
if (!stream) {
|
|
8721
|
+
console.error(`[STREAM] Failed to create resumable stream ${streamId}`);
|
|
8656
8722
|
return c.json({ error: "Failed to create stream" }, 500);
|
|
8657
8723
|
}
|
|
8724
|
+
console.log(`[STREAM] Stream ${streamId} created successfully`);
|
|
8658
8725
|
const encodedStream = stream.pipeThrough(new TextEncoderStream());
|
|
8659
8726
|
return new Response(encodedStream, {
|
|
8660
8727
|
headers: {
|
|
@@ -8683,17 +8750,20 @@ agents.get("/:id/watch", async (c) => {
|
|
|
8683
8750
|
}
|
|
8684
8751
|
streamId = activeStream.streamId;
|
|
8685
8752
|
}
|
|
8753
|
+
console.log(`[STREAM] Watch request for session ${sessionId}, streamId=${streamId}, resumeAt=${resumeAt || "none"}`);
|
|
8686
8754
|
const stream = await streamContext.resumeExistingStream(
|
|
8687
8755
|
streamId,
|
|
8688
8756
|
resumeAt ? parseInt(resumeAt, 10) : void 0
|
|
8689
8757
|
);
|
|
8690
8758
|
if (!stream) {
|
|
8759
|
+
console.log(`[STREAM] Watch failed \u2014 stream ${streamId} is no longer active`);
|
|
8691
8760
|
return c.json({
|
|
8692
8761
|
error: "Stream is no longer active",
|
|
8693
8762
|
streamId,
|
|
8694
8763
|
hint: "The stream may have finished. Check /agents/:id/approvals or start a new run."
|
|
8695
8764
|
}, 422);
|
|
8696
8765
|
}
|
|
8766
|
+
console.log(`[STREAM] Client watching stream ${streamId}`);
|
|
8697
8767
|
const encodedStream = stream.pipeThrough(new TextEncoderStream());
|
|
8698
8768
|
return new Response(encodedStream, {
|
|
8699
8769
|
headers: {
|
|
@@ -8855,19 +8925,28 @@ agents.post(
|
|
|
8855
8925
|
const toolCallStarts = /* @__PURE__ */ new Set();
|
|
8856
8926
|
const abortController = new AbortController();
|
|
8857
8927
|
streamAbortControllers.set(streamId, abortController);
|
|
8928
|
+
let sseEventCount = 0;
|
|
8929
|
+
let sseBrowserFrameCount = 0;
|
|
8930
|
+
let sseWriteErrors = 0;
|
|
8858
8931
|
const writeSSE = async (data) => {
|
|
8859
8932
|
if (writerClosed) return;
|
|
8860
8933
|
try {
|
|
8934
|
+
sseEventCount++;
|
|
8861
8935
|
await writer.write(`data: ${data}
|
|
8862
8936
|
|
|
8863
8937
|
`);
|
|
8864
8938
|
} catch (err) {
|
|
8939
|
+
sseWriteErrors++;
|
|
8940
|
+
if (sseWriteErrors === 1) {
|
|
8941
|
+
console.log(`[SSE:${streamId}] Writer closed (client disconnected). Total events sent: ${sseEventCount}, browser frames: ${sseBrowserFrameCount}`);
|
|
8942
|
+
}
|
|
8865
8943
|
writerClosed = true;
|
|
8866
8944
|
}
|
|
8867
8945
|
};
|
|
8868
8946
|
const safeClose = async () => {
|
|
8869
8947
|
if (writerClosed) return;
|
|
8870
8948
|
try {
|
|
8949
|
+
console.log(`[SSE:${streamId}] Stream closing. Total events: ${sseEventCount}, browser frames: ${sseBrowserFrameCount}, write errors: ${sseWriteErrors}`);
|
|
8871
8950
|
writerClosed = true;
|
|
8872
8951
|
await writer.close();
|
|
8873
8952
|
} catch {
|
|
@@ -8927,35 +9006,47 @@ agents.post(
|
|
|
8927
9006
|
const browserPort = progress.data?.browserStreamPort;
|
|
8928
9007
|
const browserClosed = progress.data?.browserClosed;
|
|
8929
9008
|
if (progress.toolName === "bash" && browserClosed) {
|
|
8930
|
-
console.log(`[BROWSER-STREAM] agent-browser close detected`);
|
|
9009
|
+
console.log(`[BROWSER-STREAM:${streamId}] agent-browser close detected, destroying proxy for session ${session.id}`);
|
|
8931
9010
|
destroyProxy(session.id);
|
|
8932
9011
|
} else if (progress.toolName === "bash" && browserPort) {
|
|
8933
|
-
console.log(`[BROWSER-STREAM] agent-browser command detected, port ${browserPort}`);
|
|
9012
|
+
console.log(`[BROWSER-STREAM:${streamId}] agent-browser command detected, port ${browserPort} for session ${session.id}`);
|
|
8934
9013
|
const proxy = getOrCreateProxy(session.id, browserPort);
|
|
9014
|
+
console.log(`[BROWSER-STREAM:${streamId}] Proxy state: connected=${proxy.connected}, frameListeners=${proxy.listenerCount("frame")}, statusListeners=${proxy.listenerCount("status")}`);
|
|
8935
9015
|
if (!sessionRecorders.has(session.id)) {
|
|
8936
9016
|
const recorder = new FrameRecorder(session.id);
|
|
8937
9017
|
recorder.start();
|
|
8938
9018
|
sessionRecorders.set(session.id, recorder);
|
|
8939
9019
|
}
|
|
8940
9020
|
if (proxy.listenerCount("frame") === 0) {
|
|
9021
|
+
console.log(`[BROWSER-STREAM:${streamId}] Attaching frame+status listeners to proxy`);
|
|
8941
9022
|
proxy.on("frame", (frame) => {
|
|
9023
|
+
sseBrowserFrameCount++;
|
|
9024
|
+
if (sseBrowserFrameCount === 1) {
|
|
9025
|
+
console.log(`[BROWSER-STREAM:${streamId}] First browser frame received! dataSize=${frame.data?.length ?? 0} writerClosed=${writerClosed}`);
|
|
9026
|
+
} else if (sseBrowserFrameCount % 50 === 0) {
|
|
9027
|
+
console.log(`[BROWSER-STREAM:${streamId}] Browser frame #${sseBrowserFrameCount} (writerClosed=${writerClosed})`);
|
|
9028
|
+
}
|
|
8942
9029
|
const rec = sessionRecorders.get(session.id);
|
|
8943
9030
|
rec?.addFrame(frame);
|
|
8944
9031
|
writeSSE(JSON.stringify({
|
|
8945
9032
|
type: "browser-frame",
|
|
8946
9033
|
data: frame.data,
|
|
8947
9034
|
metadata: frame.metadata
|
|
8948
|
-
})).catch(() => {
|
|
9035
|
+
})).catch((err) => {
|
|
9036
|
+
console.warn(`[BROWSER-STREAM:${streamId}] Failed to send browser-frame via SSE:`, err);
|
|
8949
9037
|
});
|
|
8950
9038
|
});
|
|
8951
9039
|
proxy.on("status", (s) => {
|
|
8952
|
-
console.log(`[BROWSER-STREAM]
|
|
9040
|
+
console.log(`[BROWSER-STREAM:${streamId}] Browser status event: connected=${s.connected} screencasting=${s.screencasting} viewport=${s.viewportWidth}x${s.viewportHeight}`);
|
|
8953
9041
|
writeSSE(JSON.stringify({
|
|
8954
9042
|
type: "browser-status",
|
|
8955
9043
|
...s
|
|
8956
|
-
})).catch(() => {
|
|
9044
|
+
})).catch((err) => {
|
|
9045
|
+
console.warn(`[BROWSER-STREAM:${streamId}] Failed to send browser-status via SSE:`, err);
|
|
8957
9046
|
});
|
|
8958
9047
|
});
|
|
9048
|
+
} else {
|
|
9049
|
+
console.log(`[BROWSER-STREAM:${streamId}] Frame listeners already attached (count=${proxy.listenerCount("frame")}), skipping`);
|
|
8959
9050
|
}
|
|
8960
9051
|
}
|
|
8961
9052
|
},
|