@electric-agent/studio 1.0.0
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/bridge/daytona.d.ts +35 -0
- package/dist/bridge/daytona.d.ts.map +1 -0
- package/dist/bridge/daytona.js +146 -0
- package/dist/bridge/daytona.js.map +1 -0
- package/dist/bridge/docker-stdio.d.ts +30 -0
- package/dist/bridge/docker-stdio.d.ts.map +1 -0
- package/dist/bridge/docker-stdio.js +141 -0
- package/dist/bridge/docker-stdio.js.map +1 -0
- package/dist/bridge/hosted.d.ts +28 -0
- package/dist/bridge/hosted.d.ts.map +1 -0
- package/dist/bridge/hosted.js +113 -0
- package/dist/bridge/hosted.js.map +1 -0
- package/dist/bridge/index.d.ts +6 -0
- package/dist/bridge/index.d.ts.map +1 -0
- package/dist/bridge/index.js +5 -0
- package/dist/bridge/index.js.map +1 -0
- package/dist/bridge/sprites.d.ts +32 -0
- package/dist/bridge/sprites.d.ts.map +1 -0
- package/dist/bridge/sprites.js +138 -0
- package/dist/bridge/sprites.js.map +1 -0
- package/dist/bridge/types.d.ts +97 -0
- package/dist/bridge/types.d.ts.map +1 -0
- package/dist/bridge/types.js +2 -0
- package/dist/bridge/types.js.map +1 -0
- package/dist/client/assets/OpenSauceOne-Bold-BeiFYFR5.woff2 +0 -0
- package/dist/client/assets/OpenSauceOne-ExtraBold-DO6BqiNe.woff2 +0 -0
- package/dist/client/assets/OpenSauceOne-Light-NEdTeQp-.woff2 +0 -0
- package/dist/client/assets/OpenSauceOne-Medium-Cu5cjAHY.woff2 +0 -0
- package/dist/client/assets/OpenSauceOne-Regular-BivIUdzJ.woff2 +0 -0
- package/dist/client/assets/SourceCodePro-Regular-CoIbWt_c.woff2 +0 -0
- package/dist/client/assets/index-CK__1-6e.css +1 -0
- package/dist/client/assets/index-DKL-jl7t.js +241 -0
- package/dist/client/favicon.ico +0 -0
- package/dist/client/img/brand/favicon.png +0 -0
- package/dist/client/img/brand/favicon.svg +4 -0
- package/dist/client/img/brand/icon.svg +4 -0
- package/dist/client/img/brand/logo.inverse.svg +13 -0
- package/dist/client/img/brand/logo.svg +13 -0
- package/dist/client/index.html +16 -0
- package/dist/electric-api.d.ts +14 -0
- package/dist/electric-api.d.ts.map +1 -0
- package/dist/electric-api.js +70 -0
- package/dist/electric-api.js.map +1 -0
- package/dist/gate.d.ts +28 -0
- package/dist/gate.d.ts.map +1 -0
- package/dist/gate.js +72 -0
- package/dist/gate.js.map +1 -0
- package/dist/git.d.ts +30 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +115 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/project-utils.d.ts +9 -0
- package/dist/project-utils.d.ts.map +1 -0
- package/dist/project-utils.js +17 -0
- package/dist/project-utils.js.map +1 -0
- package/dist/sandbox/daytona-push.d.ts +3 -0
- package/dist/sandbox/daytona-push.d.ts.map +1 -0
- package/dist/sandbox/daytona-push.js +56 -0
- package/dist/sandbox/daytona-push.js.map +1 -0
- package/dist/sandbox/daytona-registry.d.ts +41 -0
- package/dist/sandbox/daytona-registry.d.ts.map +1 -0
- package/dist/sandbox/daytona-registry.js +127 -0
- package/dist/sandbox/daytona-registry.js.map +1 -0
- package/dist/sandbox/daytona.d.ts +41 -0
- package/dist/sandbox/daytona.d.ts.map +1 -0
- package/dist/sandbox/daytona.js +282 -0
- package/dist/sandbox/daytona.js.map +1 -0
- package/dist/sandbox/docker.d.ts +29 -0
- package/dist/sandbox/docker.d.ts.map +1 -0
- package/dist/sandbox/docker.js +465 -0
- package/dist/sandbox/docker.js.map +1 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +4 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/sprites-bootstrap.d.ts +26 -0
- package/dist/sandbox/sprites-bootstrap.d.ts.map +1 -0
- package/dist/sandbox/sprites-bootstrap.js +127 -0
- package/dist/sandbox/sprites-bootstrap.js.map +1 -0
- package/dist/sandbox/sprites.d.ts +55 -0
- package/dist/sandbox/sprites.d.ts.map +1 -0
- package/dist/sandbox/sprites.js +323 -0
- package/dist/sandbox/sprites.js.map +1 -0
- package/dist/sandbox/types.d.ts +73 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +5 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/server.d.ts +26 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1266 -0
- package/dist/server.js.map +1 -0
- package/dist/sessions.d.ts +46 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +66 -0
- package/dist/sessions.js.map +1 -0
- package/dist/streams.d.ts +34 -0
- package/dist/streams.d.ts.map +1 -0
- package/dist/streams.js +42 -0
- package/dist/streams.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionBridge implementation that communicates with a Sprites sandbox
|
|
3
|
+
* via the Sprites SDK session API (stdin/stdout NDJSON).
|
|
4
|
+
*
|
|
5
|
+
* The server bridges between the Durable Stream (for UI events) and
|
|
6
|
+
* the Sprites session (for agent communication). The agent inside the
|
|
7
|
+
* sprite uses the stdio adapter — the bridge relays events to the stream.
|
|
8
|
+
*/
|
|
9
|
+
import * as readline from "node:readline";
|
|
10
|
+
import { DurableStream } from "@durable-streams/client";
|
|
11
|
+
const SPRITES_SESSION_ID = "agent-session";
|
|
12
|
+
export class SpritesStdioBridge {
|
|
13
|
+
sessionId;
|
|
14
|
+
streamUrl;
|
|
15
|
+
streamHeaders;
|
|
16
|
+
sprite;
|
|
17
|
+
writer;
|
|
18
|
+
agentEventCallbacks = [];
|
|
19
|
+
completeCallbacks = [];
|
|
20
|
+
closed = false;
|
|
21
|
+
cmd = null;
|
|
22
|
+
constructor(sessionId, connection, sprite) {
|
|
23
|
+
this.sessionId = sessionId;
|
|
24
|
+
this.streamUrl = connection.url;
|
|
25
|
+
this.streamHeaders = connection.headers;
|
|
26
|
+
this.sprite = sprite;
|
|
27
|
+
this.writer = new DurableStream({
|
|
28
|
+
url: connection.url,
|
|
29
|
+
headers: connection.headers,
|
|
30
|
+
contentType: "application/json",
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async emit(event) {
|
|
34
|
+
if (this.closed)
|
|
35
|
+
return;
|
|
36
|
+
const msg = { source: "server", ...event };
|
|
37
|
+
await this.writer.append(JSON.stringify(msg));
|
|
38
|
+
}
|
|
39
|
+
async sendCommand(cmd) {
|
|
40
|
+
if (this.closed || !this.cmd)
|
|
41
|
+
return;
|
|
42
|
+
const line = JSON.stringify({ type: "command", ...cmd });
|
|
43
|
+
this.cmd.stdin.write(`${line}\n`);
|
|
44
|
+
}
|
|
45
|
+
async sendGateResponse(gate, value) {
|
|
46
|
+
if (this.closed || !this.cmd)
|
|
47
|
+
return;
|
|
48
|
+
const line = JSON.stringify({ type: "gate_response", gate, ...value });
|
|
49
|
+
this.cmd.stdin.write(`${line}\n`);
|
|
50
|
+
}
|
|
51
|
+
onAgentEvent(cb) {
|
|
52
|
+
this.agentEventCallbacks.push(cb);
|
|
53
|
+
}
|
|
54
|
+
onComplete(cb) {
|
|
55
|
+
this.completeCallbacks.push(cb);
|
|
56
|
+
}
|
|
57
|
+
async start() {
|
|
58
|
+
if (this.closed)
|
|
59
|
+
return;
|
|
60
|
+
// Create a persistent session in the sprite so we can reconnect if needed
|
|
61
|
+
this.cmd = this.sprite.createSession("bash", [
|
|
62
|
+
"-c",
|
|
63
|
+
"source /etc/profile.d/npm-global.sh 2>/dev/null; source /etc/profile.d/electric-agent.sh && electric-agent headless",
|
|
64
|
+
], { detachable: true, sessionId: SPRITES_SESSION_ID });
|
|
65
|
+
console.log(`[sprites-bridge] Agent started: session=${this.sessionId}`);
|
|
66
|
+
// Read stdout line by line (NDJSON)
|
|
67
|
+
const rl = readline.createInterface({
|
|
68
|
+
input: this.cmd.stdout,
|
|
69
|
+
terminal: false,
|
|
70
|
+
});
|
|
71
|
+
rl.on("line", (line) => {
|
|
72
|
+
if (this.closed)
|
|
73
|
+
return;
|
|
74
|
+
const trimmed = line.trim();
|
|
75
|
+
if (!trimmed)
|
|
76
|
+
return;
|
|
77
|
+
let event;
|
|
78
|
+
try {
|
|
79
|
+
event = JSON.parse(trimmed);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
console.log(`[sprites-bridge] Non-JSON stdout: ${trimmed}`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Write to Durable Stream for UI
|
|
86
|
+
const msg = { source: "agent", ...event };
|
|
87
|
+
this.writer.append(JSON.stringify(msg)).catch(() => { });
|
|
88
|
+
// Dispatch to callbacks
|
|
89
|
+
for (const cb of this.agentEventCallbacks) {
|
|
90
|
+
try {
|
|
91
|
+
cb(event);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Swallow callback errors
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Detect session_end
|
|
98
|
+
if (event.type === "session_end" && "success" in event) {
|
|
99
|
+
const success = event.success;
|
|
100
|
+
for (const cb of this.completeCallbacks) {
|
|
101
|
+
try {
|
|
102
|
+
cb(success);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Swallow callback errors
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
// Log stderr
|
|
111
|
+
const stderrRl = readline.createInterface({
|
|
112
|
+
input: this.cmd.stderr,
|
|
113
|
+
terminal: false,
|
|
114
|
+
});
|
|
115
|
+
stderrRl.on("line", (line) => {
|
|
116
|
+
if (!this.closed) {
|
|
117
|
+
console.error(`[sprites-bridge:stderr] ${line}`);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
// Handle process exit
|
|
121
|
+
this.cmd.on("exit", (code) => {
|
|
122
|
+
console.log(`[sprites-bridge] Agent process exited: code=${code} session=${this.sessionId}`);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
close() {
|
|
126
|
+
this.closed = true;
|
|
127
|
+
if (this.cmd) {
|
|
128
|
+
try {
|
|
129
|
+
this.cmd.kill();
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Process may already be dead
|
|
133
|
+
}
|
|
134
|
+
this.cmd = null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=sprites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprites.js","sourceRoot":"","sources":["../../src/bridge/sprites.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAMvD,MAAM,kBAAkB,GAAG,eAAe,CAAA;AAE1C,MAAM,OAAO,kBAAkB;IACrB,SAAS,CAAQ;IACjB,SAAS,CAAQ;IACjB,aAAa,CAAwB;IAEtC,MAAM,CAAQ;IACd,MAAM,CAAe;IACrB,mBAAmB,GAAwC,EAAE,CAAA;IAC7D,iBAAiB,GAAsC,EAAE,CAAA;IACzD,MAAM,GAAG,KAAK,CAAA;IACd,GAAG,GAAyB,IAAI,CAAA;IAExC,YAAY,SAAiB,EAAE,UAAgC,EAAE,MAAc;QAC9E,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1B,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,CAAA;QAC/B,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,OAAO,CAAA;QACvC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QAEpB,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,CAAC;YAC/B,GAAG,EAAE,UAAU,CAAC,GAAG;YACnB,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,WAAW,EAAE,kBAAkB;SAC/B,CAAC,CAAA;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAkB;QAC5B,IAAI,IAAI,CAAC,MAAM;YAAE,OAAM;QACvB,MAAM,GAAG,GAAkB,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAA;QACzD,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IAC9C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,GAA4B;QAC7C,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,OAAM;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,GAAG,EAAE,CAAC,CAAA;QACxD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAA;IAClC,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,IAAY,EAAE,KAA8B;QAClE,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,OAAM;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,CAAC,CAAA;QACtE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAA;IAClC,CAAC;IAED,YAAY,CAAC,EAAgC;QAC5C,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAClC,CAAC;IAED,UAAU,CAAC,EAA8B;QACxC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAChC,CAAC;IAED,KAAK,CAAC,KAAK;QACV,IAAI,IAAI,CAAC,MAAM;YAAE,OAAM;QAEvB,0EAA0E;QAC1E,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CACnC,MAAM,EACN;YACC,IAAI;YACJ,qHAAqH;SACrH,EACD,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,kBAAkB,EAAE,CACnD,CAAA;QAED,OAAO,CAAC,GAAG,CAAC,2CAA2C,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;QAExE,oCAAoC;QACpC,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;YACnC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM;YACtB,QAAQ,EAAE,KAAK;SACf,CAAC,CAAA;QAEF,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACtB,IAAI,IAAI,CAAC,MAAM;gBAAE,OAAM;YACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;YAC3B,IAAI,CAAC,OAAO;gBAAE,OAAM;YAEpB,IAAI,KAAkB,CAAA;YACtB,IAAI,CAAC;gBACJ,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAA;YAC3C,CAAC;YAAC,MAAM,CAAC;gBACR,OAAO,CAAC,GAAG,CAAC,qCAAqC,OAAO,EAAE,CAAC,CAAA;gBAC3D,OAAM;YACP,CAAC;YAED,iCAAiC;YACjC,MAAM,GAAG,GAAkB,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAA;YACxD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAEvD,wBAAwB;YACxB,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBAC3C,IAAI,CAAC;oBACJ,EAAE,CAAC,KAAK,CAAC,CAAA;gBACV,CAAC;gBAAC,MAAM,CAAC;oBACR,0BAA0B;gBAC3B,CAAC;YACF,CAAC;YAED,qBAAqB;YACrB,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,IAAI,SAAS,IAAI,KAAK,EAAE,CAAC;gBACxD,MAAM,OAAO,GAAI,KAA4C,CAAC,OAAO,CAAA;gBACrE,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;oBACzC,IAAI,CAAC;wBACJ,EAAE,CAAC,OAAO,CAAC,CAAA;oBACZ,CAAC;oBAAC,MAAM,CAAC;wBACR,0BAA0B;oBAC3B,CAAC;gBACF,CAAC;YACF,CAAC;QACF,CAAC,CAAC,CAAA;QAEF,aAAa;QACb,MAAM,QAAQ,GAAG,QAAQ,CAAC,eAAe,CAAC;YACzC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM;YACtB,QAAQ,EAAE,KAAK;SACf,CAAC,CAAA;QACF,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBAClB,OAAO,CAAC,KAAK,CAAC,2BAA2B,IAAI,EAAE,CAAC,CAAA;YACjD,CAAC;QACF,CAAC,CAAC,CAAA;QAEF,sBAAsB;QACtB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC5B,OAAO,CAAC,GAAG,CAAC,+CAA+C,IAAI,YAAY,IAAI,CAAC,SAAS,EAAE,CAAC,CAAA;QAC7F,CAAC,CAAC,CAAA;IACH,CAAC;IAED,KAAK;QACJ,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QAClB,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACd,IAAI,CAAC;gBACJ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;YAChB,CAAC;YAAC,MAAM,CAAC;gBACR,8BAA8B;YAC/B,CAAC;YACD,IAAI,CAAC,GAAG,GAAG,IAAI,CAAA;QAChB,CAAC;IACF,CAAC;CACD"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { EngineEvent } from "@electric-agent/protocol";
|
|
2
|
+
/**
|
|
3
|
+
* Bidirectional communication bridge between the web server and a sandbox.
|
|
4
|
+
*
|
|
5
|
+
* All messages flow through a single Durable Stream. Messages are tagged
|
|
6
|
+
* with a `source` field to distinguish server-originated vs agent-originated:
|
|
7
|
+
*
|
|
8
|
+
* source: "server" — commands and gate responses from the web server
|
|
9
|
+
* source: "agent" — engine events from the sandbox
|
|
10
|
+
*
|
|
11
|
+
* The bridge handles filtering so consumers only see relevant messages.
|
|
12
|
+
*/
|
|
13
|
+
export interface SessionBridge {
|
|
14
|
+
/** The session this bridge is associated with */
|
|
15
|
+
readonly sessionId: string;
|
|
16
|
+
/**
|
|
17
|
+
* Full stream URL for client SSE subscription.
|
|
18
|
+
* The React client subscribes to this for real-time event display.
|
|
19
|
+
*/
|
|
20
|
+
readonly streamUrl: string;
|
|
21
|
+
/**
|
|
22
|
+
* Headers required for stream access (e.g., Authorization).
|
|
23
|
+
* Needed by the React client for SSE subscription.
|
|
24
|
+
*/
|
|
25
|
+
readonly streamHeaders: Record<string, string>;
|
|
26
|
+
/**
|
|
27
|
+
* Emit a server-originated event to the stream.
|
|
28
|
+
* These are visible to UI subscribers (e.g., user_message, gate_resolved).
|
|
29
|
+
*/
|
|
30
|
+
emit(event: EngineEvent): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Send a command to the sandbox.
|
|
33
|
+
* The sandbox's headless adapter filters for these.
|
|
34
|
+
*/
|
|
35
|
+
sendCommand(cmd: Record<string, unknown>): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Send a gate response to the sandbox.
|
|
38
|
+
* Resolves a pending gate in the headless adapter.
|
|
39
|
+
*/
|
|
40
|
+
sendGateResponse(gate: string, value: Record<string, unknown>): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Register a callback for agent-originated events.
|
|
43
|
+
* The bridge filters stream messages and dispatches only `source: "agent"` events.
|
|
44
|
+
* Multiple callbacks can be registered.
|
|
45
|
+
*/
|
|
46
|
+
onAgentEvent(cb: (event: EngineEvent) => void): void;
|
|
47
|
+
/**
|
|
48
|
+
* Register a callback for session completion.
|
|
49
|
+
* Fired when a `session_end` event is received from the agent.
|
|
50
|
+
*/
|
|
51
|
+
onComplete(cb: (success: boolean) => void): void;
|
|
52
|
+
/**
|
|
53
|
+
* Start listening for agent events on the stream.
|
|
54
|
+
* Must be called after registering callbacks.
|
|
55
|
+
* Returns a promise that resolves when the subscription is active.
|
|
56
|
+
*/
|
|
57
|
+
start(): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Close the bridge and release resources.
|
|
60
|
+
* Cancels any active subscriptions.
|
|
61
|
+
*/
|
|
62
|
+
close(): void;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A stream message with source tagging for the bidirectional protocol.
|
|
66
|
+
*/
|
|
67
|
+
export interface StreamMessage {
|
|
68
|
+
source: "agent" | "server";
|
|
69
|
+
[key: string]: unknown;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Server-originated command message.
|
|
73
|
+
*/
|
|
74
|
+
export interface ServerCommand extends StreamMessage {
|
|
75
|
+
source: "server";
|
|
76
|
+
type: "command";
|
|
77
|
+
[key: string]: unknown;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Server-originated gate response message.
|
|
81
|
+
*/
|
|
82
|
+
export interface ServerGateResponse extends StreamMessage {
|
|
83
|
+
source: "server";
|
|
84
|
+
type: "gate_response";
|
|
85
|
+
gate: string;
|
|
86
|
+
[key: string]: unknown;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Agent-originated event message (EngineEvent + source tag).
|
|
90
|
+
*/
|
|
91
|
+
export interface AgentEvent extends StreamMessage {
|
|
92
|
+
source: "agent";
|
|
93
|
+
type: string;
|
|
94
|
+
ts: string;
|
|
95
|
+
[key: string]: unknown;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/bridge/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,aAAa;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAE1B;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAE1B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE9C;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEvC;;;OAGG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAExD;;;OAGG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE7E;;;;OAIG;IACH,YAAY,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI,CAAA;IAEpD;;;OAGG;IACH,UAAU,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAA;IAEhD;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAEtB;;;OAGG;IACH,KAAK,IAAI,IAAI,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,MAAM,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,aAAc,SAAQ,aAAa;IACnD,MAAM,EAAE,QAAQ,CAAA;IAChB,IAAI,EAAE,SAAS,CAAA;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACxD,MAAM,EAAE,QAAQ,CAAA;IAChB,IAAI,EAAE,eAAe,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,UAAW,SAAQ,aAAa;IAChD,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/bridge/types.ts"],"names":[],"mappings":""}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@font-face{font-family:OpenSauceOne;font-style:normal;font-weight:300;src:url(/assets/OpenSauceOne-Light-NEdTeQp-.woff2) format("woff2")}@font-face{font-family:OpenSauceOne;font-style:normal;font-weight:400;src:url(/assets/OpenSauceOne-Regular-BivIUdzJ.woff2) format("woff2")}@font-face{font-family:OpenSauceOne;font-style:normal;font-weight:500;src:url(/assets/OpenSauceOne-Medium-Cu5cjAHY.woff2) format("woff2")}@font-face{font-family:OpenSauceOne;font-style:normal;font-weight:600;src:url(/assets/OpenSauceOne-Bold-BeiFYFR5.woff2) format("woff2")}@font-face{font-family:OpenSauceOne;font-style:normal;font-weight:700;src:url(/assets/OpenSauceOne-ExtraBold-DO6BqiNe.woff2) format("woff2")}@font-face{font-family:SourceCodePro;font-style:normal;font-weight:400;src:url(/assets/SourceCodePro-Regular-CoIbWt_c.woff2) format("woff2")}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}:root{--bg: #1b1b1f;--bg-surface: #202127;--bg-hover: #2a2a32;--border: #3a3a44;--text: rgba(255, 255, 245, .92);--text-muted: rgba(235, 235, 245, .68);--text-subtle: rgba(235, 235, 245, .46);--brand-1: #d0bcff;--brand-2: #998fe7;--brand-3: #7e78db;--electric-color: #00d2a0;--tanstack-db-color: #ff8c3b;--durable-streams-color: #75fbfd;--green: #3fb950;--yellow: #d29922;--red: #f85149;--purple: #d0bcff;--blue: #9ecbff;--orange: #ff8c3b;--cyan: #75fbfd;--font-sans: OpenSauceOne, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono: SourceCodePro, ui-monospace, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--sh-keyword: #d0bcff;--sh-string: #3fb950;--sh-number: #ff8c3b;--sh-comment: rgba(235, 235, 245, .38);--sh-class: #d29922;--sh-identifier: #9ecbff;--sh-property: #75fbfd;--sh-sign: rgba(235, 235, 245, .5);--sh-entity: #f85149;--sh-jsxliterals: rgba(255, 255, 245, .92);--sidebar-width: 240px;--topbar-height: 48px;--footer-height: 60px}html,body,#root{height:100%;width:100%;background:var(--bg);color:var(--text);font-family:var(--font-sans);font-size:15px;line-height:1.6}*{scrollbar-width:thin;scrollbar-color:var(--border) transparent}*::-webkit-scrollbar{width:6px;height:6px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}*::-webkit-scrollbar-thumb:hover{background:var(--text-subtle)}html[data-font-size=large],html[data-font-size=large] body,html[data-font-size=large] #root{font-size:16px}html[data-font-size=large] .console-entry,html[data-font-size=large] .tool-inline summary,html[data-font-size=large] .thinking-inline summary,html[data-font-size=large] .tool-inline-agent,html[data-font-size=large] .tool-inline-name,html[data-font-size=large] .tool-inline-command,html[data-font-size=large] .action-group-header,html[data-font-size=large] .action-item,html[data-font-size=large] .session-item-name,html[data-font-size=large] .tab-btn,html[data-font-size=large] .session-header{font-size:14px}html[data-font-size=large] .hero-subtitle{font-size:18px}html[data-font-size=large] .hero-prompt .prompt-bar textarea,html[data-font-size=large] .prompt-bar textarea{font-size:16px}html[data-font-size=large] .tool-inline-body pre,html[data-font-size=large] .thinking-body pre{font-size:13px}html[data-font-size=large] .duration,html[data-font-size=large] .session-item-meta,html[data-font-size=large] .action-group-count,html[data-font-size=large] .status-badge,html[data-font-size=large] .settings-section-label,html[data-font-size=large] .sidebar-section-label{font-size:12px}html[data-font-size=larger],html[data-font-size=larger] body,html[data-font-size=larger] #root{font-size:17px}html[data-font-size=larger] .console-entry,html[data-font-size=larger] .tool-inline summary,html[data-font-size=larger] .thinking-inline summary,html[data-font-size=larger] .tool-inline-agent,html[data-font-size=larger] .tool-inline-name,html[data-font-size=larger] .tool-inline-command,html[data-font-size=larger] .action-group-header,html[data-font-size=larger] .action-item,html[data-font-size=larger] .session-item-name,html[data-font-size=larger] .tab-btn,html[data-font-size=larger] .session-header{font-size:15px}html[data-font-size=larger] .hero-subtitle{font-size:19px}html[data-font-size=larger] .hero-prompt .prompt-bar textarea,html[data-font-size=larger] .prompt-bar textarea{font-size:17px}html[data-font-size=larger] .tool-inline-body pre,html[data-font-size=larger] .thinking-body pre{font-size:14px}html[data-font-size=larger] .duration,html[data-font-size=larger] .session-item-meta,html[data-font-size=larger] .action-group-count,html[data-font-size=larger] .status-badge,html[data-font-size=larger] .settings-section-label,html[data-font-size=larger] .sidebar-section-label{font-size:13px}html[data-font-size=larger] .btn,html[data-font-size=larger] .modal-btn,html[data-font-size=larger] .prompt-bar button{font-size:15px}.app-shell{display:grid;grid-template-columns:var(--sidebar-width) 1fr;height:100vh;overflow:hidden;transition:grid-template-columns .2s ease;position:relative}.app-shell.sidebar-collapsed{--sidebar-width: 64px}.sidebar{display:flex;flex-direction:column;height:100%;background:var(--bg-surface);border-right:1px solid var(--border);overflow:hidden;transition:width .2s ease}.sidebar-header{display:flex;align-items:center;gap:8px;padding:0 16px;border-bottom:1px solid var(--border);height:var(--topbar-height);flex-shrink:0}.sidebar-icon{width:24px;height:24px;flex-shrink:0}.sidebar-brand{font-size:15px;font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden}.global-settings-btn{position:absolute;top:8px;right:12px;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border:none;background:none;color:var(--text-subtle);cursor:pointer;border-radius:4px;z-index:50;transition:color .15s,background .15s}.global-settings-btn:hover{color:var(--text);background:var(--bg-hover)}.sidebar-collapse{padding:0 8px;flex-shrink:0;border-top:1px solid var(--border);height:var(--footer-height);display:flex;align-items:center;box-sizing:border-box}.sidebar-collapse-btn{display:flex;align-items:center;gap:8px;width:100%;height:32px;padding:0 16px;border:none;background:none;color:var(--text-subtle);cursor:pointer;border-radius:4px;font-size:13px;transition:color .15s,background .15s}.sidebar-collapse-btn:hover{color:var(--text);background:var(--bg-hover)}.sidebar-collapse-btn svg{width:16px;height:16px;flex-shrink:0}.sidebar-collapse-label{white-space:nowrap;overflow:hidden;opacity:1;max-width:120px;transition:opacity .15s ease,max-width .2s ease}.sidebar-collapsed .sidebar-collapse-btn{gap:0}.sidebar-collapsed .sidebar-collapse-label{opacity:0;max-width:0;display:none}.sidebar-collapsed .sidebar-brand,.sidebar-collapsed .sidebar-section-label{display:none}.sidebar-collapsed .session-item{gap:0}.sidebar-collapsed .session-item-details,.sidebar-collapsed .session-item-delete,.sidebar-collapsed .session-item:hover .session-item-delete{opacity:0;width:0;overflow:hidden;pointer-events:none}.sidebar-section-label{font-size:11px;color:var(--text-subtle);text-transform:uppercase;letter-spacing:.05em;padding:8px 12px 4px}.sidebar-sessions{flex:1;overflow-y:auto;padding:0 4px}.session-content{display:flex;flex-direction:column;flex:1;overflow:hidden}.session-header{display:flex;align-items:center;gap:8px;padding:0 52px 0 16px;border-bottom:1px solid var(--border);height:var(--topbar-height);flex-shrink:0;font-size:13px;position:relative}.session-header-name{font-weight:600;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.session-header-status{font-size:11px;margin-left:auto;flex-shrink:0}.session-header-action{font-size:12px;font-family:var(--font-mono);cursor:pointer;color:var(--text-muted);background:transparent;border:1px solid var(--border);border-radius:6px;padding:4px 10px;transition:color .15s,background .15s,border-color .15s;flex-shrink:0;text-decoration:none;line-height:1.4}.session-header-action:hover{color:var(--text);background:var(--bg-hover);border-color:var(--text-subtle)}.session-header-action:disabled{opacity:.5;cursor:not-allowed}.session-header-action.primary{border-color:var(--brand-3);color:var(--brand-1)}.session-header-action.primary:hover{background:var(--brand-2);border-color:var(--brand-2);color:#fff}.session-initializing{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;color:var(--text-muted);font-size:15px}.session-initializing-spinner{width:28px;height:28px;border:3px solid var(--border);border-top-color:var(--brand-1);border-radius:50%;animation:spin .8s linear infinite}.main-content{display:flex;flex-direction:column;height:100%;overflow:hidden}.console{flex:1;overflow-y:auto;padding:16px;position:relative}.jump-to-bottom{position:sticky;bottom:8px;left:50%;transform:translate(-50%);display:block;margin:0 auto;padding:6px 16px;font-size:11px;font-family:var(--font-mono);color:var(--text);background:var(--bg-surface);border:1px solid var(--border);border-radius:16px;cursor:pointer;z-index:10;opacity:.9;transition:opacity .15s}.jump-to-bottom:hover{opacity:1;background:var(--bg-hover)}.prompt-bar{display:flex;align-items:center;gap:8px;padding:8px 16px;border-top:1px solid var(--border);height:var(--footer-height);box-sizing:border-box;flex-shrink:0}.prompt-bar textarea{flex:1;padding:10px 14px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:var(--font-sans);font-size:15px;line-height:1.5;resize:none;min-height:44px;max-height:200px}.prompt-bar textarea:focus{outline:none;border-color:var(--brand-2)}.prompt-bar textarea::placeholder{color:var(--text-subtle)}.hero{display:flex;flex-direction:column;align-items:center;justify-content:center;flex:1;padding:0 24px;text-align:center}.hero-logo{height:64px;margin-bottom:16px}.hero-subtitle{font-size:17px;font-weight:500;color:var(--text-muted);margin-bottom:36px}.hero-prompt{width:100%;max-width:640px}.hero-prompt .prompt-bar{border-top:none;padding:0;gap:0;background:var(--bg-surface);border:1px solid var(--border);border-radius:14px;overflow:hidden;align-items:center}.hero-prompt .prompt-bar textarea{border:none;border-radius:0;background:transparent;min-height:52px;font-size:15px;padding:14px}.hero-prompt .prompt-bar textarea:focus{border:none}.hero-prompt .prompt-bar button{border:none;border-radius:0 13px 13px 0;min-height:52px;padding:8px 24px;flex-shrink:0;align-self:stretch}.console-entry{display:flex;align-items:baseline;gap:0;padding:3px 0;font-family:var(--font-mono);font-size:13px;line-height:1.6}.console a{color:var(--brand-1);text-decoration:none}.console a:hover{text-decoration:underline}.console-entry .prefix{font-weight:600;margin-right:6px}.console-entry .prefix.plan{color:var(--brand-1)}.console-entry .prefix.approve{color:var(--brand-2)}.console-entry .prefix.task{color:var(--blue)}.console-entry .prefix.build{color:var(--brand-2)}.console-entry .prefix.fix{color:var(--yellow)}.console-entry .prefix.done{color:var(--green)}.console-entry .prefix.error{color:var(--red)}.console-entry .prefix.debug{color:var(--text-subtle)}.duration{margin-left:auto;font-family:var(--font-mono);font-size:11px;color:var(--text-subtle);white-space:nowrap;flex-shrink:0}.user-message{padding:3px 0;margin:0}.tool-inline{margin:0;padding:0}.tool-inline summary{display:flex;align-items:center;gap:6px;padding:3px 0;cursor:pointer;font-family:var(--font-mono);font-size:13px;color:var(--text-subtle);-webkit-user-select:none;user-select:none;list-style:none;line-height:1.6}.tool-inline summary::-webkit-details-marker{display:none}.tool-inline summary:hover .tool-inline-name{text-decoration:underline}.tool-inline summary:hover .tool-inline-summary{text-decoration:underline;color:var(--text-muted)}.tool-inline-agent{font-weight:600;color:var(--blue);font-size:13px}.tool-inline-name{font-weight:600;color:var(--brand-1);font-size:13px}.tool-inline-summary{color:var(--text-subtle);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:600px}.tool-inline-command{color:var(--text-muted);font-family:var(--font-mono);font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.spinner-inline{width:10px;height:10px;border:1.5px solid var(--border);border-top-color:var(--brand-1);border-radius:50%;animation:spin .8s linear infinite;flex-shrink:0}@keyframes spin{to{transform:rotate(360deg)}}.tool-inline-body{padding:8px 0 8px 16px;border-left:2px solid var(--border);margin:2px 0 4px 6px}.tool-inline-body pre{font-family:var(--font-mono);font-size:12px;line-height:1.5;color:var(--text-muted);white-space:pre-wrap;word-break:break-all;max-height:400px;overflow-y:auto}.tool-inline-body .section-label{font-size:11px;font-weight:600;color:var(--text-subtle);text-transform:uppercase;letter-spacing:.05em;margin:8px 0 4px}.tool-inline-body .section-label:first-child{margin-top:0}.thinking-inline{margin:0;padding:0}.thinking-inline summary{display:flex;align-items:center;gap:6px;padding:3px 0;cursor:pointer;font-family:var(--font-mono);font-size:13px;color:var(--text-subtle);-webkit-user-select:none;user-select:none;list-style:none;line-height:1.6}.thinking-inline summary::-webkit-details-marker{display:none}.thinking-inline summary:hover .thinking-label,.thinking-inline summary:hover .thinking-preview{text-decoration:underline;color:var(--text-muted)}.thinking-label{color:var(--brand-2);font-size:13px;font-weight:600;flex-shrink:0}.thinking-inline summary:hover .thinking-label{color:var(--brand-2)}.thinking-preview{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-subtle);max-width:600px}.thinking-body{padding:8px 0 8px 16px;border-left:2px solid var(--border);margin:2px 0 4px 6px}.thinking-body pre{font-family:var(--font-mono);font-size:12px;line-height:1.5;color:var(--text-muted);white-space:pre-wrap;word-break:break-word;max-height:400px;overflow-y:auto}.waiting-indicator{gap:6px;color:var(--text-subtle);animation:fade-pulse 2s ease-in-out infinite}.waiting-label{font-style:italic}@keyframes fade-pulse{0%,to{opacity:1}50%{opacity:.5}}.action-group{margin:4px 0;border:1px solid var(--border);border-radius:8px;overflow:hidden}.action-group-header{display:flex;align-items:center;gap:8px;padding:8px 12px;background:var(--bg-surface);font-family:var(--font-mono);font-size:13px;color:var(--text-muted);cursor:pointer;-webkit-user-select:none;user-select:none}.action-group-header:hover{background:var(--bg-hover)}.action-group-title{font-weight:600}.action-group-count{color:var(--text-subtle);font-size:11px}.action-group-toggle{margin-left:auto;color:var(--text-subtle);font-size:10px}.action-group-list{list-style:none}.action-item{display:flex;align-items:center;gap:8px;padding:5px 12px;font-family:var(--font-mono);font-size:13px;cursor:pointer;transition:background .1s;border-top:1px solid var(--border)}.action-item:hover{background:var(--bg-hover)}.action-item.expanded{background:var(--bg-surface)}.status-icon{width:14px;height:14px;flex-shrink:0;display:flex;align-items:center;justify-content:center}.status-icon-pending{width:8px;height:8px;border-radius:50%;border:1.5px solid var(--text-subtle)}.status-icon-running{width:10px;height:10px;border:1.5px solid var(--border);border-top-color:var(--brand-1);border-radius:50%;animation:spin .8s linear infinite}.status-icon-done{color:var(--green);font-size:13px;line-height:1}.status-icon-failed{color:var(--red);font-size:13px;line-height:1}.action-item-name{font-weight:600;color:var(--brand-1);white-space:nowrap}.action-item-summary{color:var(--text-subtle);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.action-item-duration{margin-left:auto;font-size:11px;color:var(--text-subtle);flex-shrink:0}.action-item-detail{padding:8px 12px 8px 34px;border-top:1px solid var(--border);background:var(--bg)}.todo-list{list-style:none;padding:0;margin:0}.todo-item{display:flex;align-items:center;gap:8px;padding:3px 0;font-family:var(--font-mono);font-size:13px;line-height:1.6;color:var(--text-muted)}.todo-status-icon{width:16px;text-align:center;flex-shrink:0;font-size:14px}.todo-status-done{color:var(--green)}.todo-status-progress{color:var(--brand-1)}.todo-status-pending{color:var(--text-subtle)}.todo-content{flex:1}.todo-priority{font-size:11px;padding:1px 6px;border-radius:4px;background:#ffffff0f;color:var(--text-subtle);flex-shrink:0}.gate-prompt{margin:8px 0;padding:16px;border:1px solid var(--border);border-radius:8px;background:var(--bg-surface)}.gate-prompt h3{font-family:var(--font-sans);font-size:15px;font-weight:600;margin-bottom:8px;color:var(--brand-1)}.gate-prompt .gate-summary{color:var(--text-muted);font-size:13px;font-family:var(--font-sans);margin-bottom:12px}.gate-plan{margin:8px 0}.gate-plan-body{padding:4px 0}.gate-plan-actions{display:flex;gap:8px;margin-top:12px;padding:12px 0;border-top:1px solid var(--border)}.gate-prompt .question{margin-bottom:8px}.gate-prompt .question label{display:block;font-family:var(--font-sans);font-size:13px;color:var(--text-muted);margin-bottom:4px}.gate-prompt .question input,.gate-prompt .question select{width:100%;padding:6px 10px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-family:var(--font-mono);font-size:13px}.gate-prompt .question select{appearance:none;-webkit-appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:30px;cursor:pointer}.gate-prompt .question select:hover{border-color:var(--text-subtle)}.gate-prompt .question input:focus,.gate-prompt .question textarea:focus,.gate-prompt .question select:focus{outline:none;border-color:var(--brand-2)}.gate-prompt .question textarea{width:100%;padding:6px 10px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-family:var(--font-mono);font-size:13px;resize:vertical}.gate-actions{display:flex;gap:8px;margin-top:12px}.gate-btn{padding:6px 16px;border-radius:6px;border:1px solid var(--border);background:var(--bg);color:var(--text-muted);font-family:var(--font-mono);font-size:13px;cursor:pointer;transition:background .15s,border-color .15s}.gate-btn:hover{background:var(--bg-hover)}.gate-btn:disabled{opacity:.5;cursor:not-allowed}.gate-btn-primary{background:transparent;border-color:var(--brand-3);color:var(--brand-1);font-weight:600}.gate-btn-primary:hover{background:var(--brand-2);border-color:var(--brand-2);color:#fff}.gate-btn-danger{border-color:var(--red);color:var(--red)}.gate-btn-danger:hover{background:#f851491a}.gate-continue{display:flex;align-items:center;gap:12px;margin:4px 0;padding:8px 12px;border:1px solid var(--border);border-radius:8px;background:var(--bg-surface);font-family:var(--font-mono);font-size:13px}.gate-continue-text{color:var(--text-muted);flex:1}.gate-continue .gate-btn{padding:4px 12px;font-size:12px}.gate-radio-group{display:flex;gap:12px;margin-top:4px;padding:4px 0}.gate-radio{display:inline-flex;align-items:center;gap:6px;font-family:var(--font-mono);font-size:13px;color:var(--text);cursor:pointer;line-height:1.4;padding:4px 10px;border-radius:6px;border:1px solid var(--border);transition:background .15s,border-color .15s}.gate-radio:hover{background:var(--bg-hover)}.gate-radio:has(input:checked){border-color:var(--brand-2);background:var(--bg-hover)}.gate-radio input[type=radio],.gate-radio input[type=checkbox]{width:auto;margin:0;vertical-align:middle;accent-color:var(--brand-2)}.gate-option-group{display:flex;gap:8px;margin:8px 0}.gate-option{flex:1;display:flex;flex-direction:column;gap:4px;padding:10px 12px;border:1px solid var(--border);border-radius:8px;background:transparent;cursor:pointer;text-align:left;transition:background .15s,border-color .15s}.gate-option:hover{background:var(--bg-hover)}.gate-option.active{border-color:var(--brand-2);background:var(--bg-hover)}.gate-option:disabled{opacity:.5;cursor:not-allowed}.gate-option.selected{border-color:var(--green);opacity:1}.gate-option-title{font-family:var(--font-mono);font-size:13px;font-weight:600;color:var(--text)}.gate-option-desc{font-size:11px;color:var(--text-subtle);line-height:1.3}.gate-answered{margin:0}.gate-answered-header{display:flex;align-items:center;gap:0;padding:3px 0;font-family:var(--font-mono);font-size:13px;line-height:1.6}.gate-answered-header .prefix{font-weight:600;margin-right:6px}.gate-resolved-label{color:var(--text-subtle)}.gate-answered .gate-prompt,.gate-answered .gate-plan,.gate-answered .gate-continue{opacity:.65}.gate-continue-decision{color:var(--text-muted);font-style:italic}.gate-config-summary{background:#ffffff0a;border:1px solid rgba(255,255,255,.1);border-radius:6px;padding:8px 10px;margin:6px 0;font-family:var(--font-mono);font-size:12px;line-height:1.6;word-break:break-all;color:var(--text-muted)}.gate-config-summary a{color:var(--brand-1);word-break:break-all}.gate-answer-summary{font-family:var(--font-mono);font-size:13px;color:var(--text-muted);padding:6px 10px;margin:8px 0;background:#ffffff0a;border:1px solid rgba(255,255,255,.1);border-radius:6px}.gate-option-group-vert{display:flex;flex-direction:column;gap:6px;margin:8px 0}.gate-option-group-vert .gate-option{flex:none}.markdown{font-family:var(--font-sans);font-size:14px;line-height:1.7;color:var(--text);word-wrap:break-word}.markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{color:var(--text);font-weight:600;margin-top:1.2em;margin-bottom:.4em;line-height:1.3}.markdown h1{font-size:1.4em}.markdown h2{font-size:1.2em}.markdown h3{font-size:1.1em}.markdown h4{font-size:1em}.markdown h1:first-child,.markdown h2:first-child,.markdown h3:first-child{margin-top:0}.markdown p{margin-bottom:.6em}.markdown p:last-child{margin-bottom:0}.markdown ul,.markdown ol{padding-left:1.5em;margin-bottom:.6em}.markdown li{margin-bottom:.2em}.markdown li>p{margin-bottom:.2em}.markdown code{font-family:var(--font-mono);font-size:.9em;padding:.15em .4em;background:var(--bg-hover);border-radius:4px;color:var(--brand-1)}.markdown pre{margin:.6em 0;padding:12px 16px;background:var(--bg);border:1px solid var(--border);border-radius:6px;overflow-x:auto;font-family:var(--font-mono);font-size:13px;line-height:1.5}.markdown pre code{padding:0;background:none;border-radius:0;color:var(--text-muted);font-size:inherit}.markdown blockquote{margin:.6em 0;padding:4px 12px;border-left:3px solid var(--brand-2);color:var(--text-muted)}.markdown blockquote p{margin-bottom:.2em}.markdown table{width:100%;border-collapse:collapse;margin:.6em 0;font-size:13px}.markdown th,.markdown td{padding:6px 12px;border:1px solid var(--border);text-align:left}.markdown th{background:var(--bg-surface);font-weight:600;color:var(--text)}.markdown td{color:var(--text-muted)}.markdown hr{border:none;border-top:1px solid var(--border);margin:1em 0}.markdown a{color:var(--brand-1);text-decoration:none}.markdown a:hover{text-decoration:underline}.markdown strong{color:var(--text);font-weight:600}.markdown img{max-width:100%;border-radius:4px}.markdown-inline{font-family:var(--font-mono);font-size:13px;line-height:1.6;color:var(--text-muted)}.markdown-inline p{margin-bottom:.3em}.markdown-inline p:last-child{margin-bottom:0}.markdown-inline pre{font-size:12px;margin:.4em 0}.markdown-inline a{color:var(--brand-1);text-decoration:none}.markdown-inline a:hover{text-decoration:underline}.btn{padding:6px 16px;border-radius:6px;border:1px solid var(--border);background:var(--bg-surface);color:var(--text);font-size:13px;cursor:pointer;transition:background .15s}.btn:hover{background:var(--bg-hover)}.btn:disabled{opacity:.5;cursor:not-allowed}.btn-primary{background:var(--brand-3);border-color:var(--brand-3);color:#fff;font-weight:600}.btn-primary:hover{background:var(--brand-2);border-color:var(--brand-2)}.btn-danger{border-color:var(--red);color:var(--red)}.btn-danger:hover{background:#f851491a}.prompt-bar button{padding:6px 14px;min-height:36px;border-radius:8px;border:1px solid var(--border);background:var(--bg-surface);color:var(--text);font-size:13px;cursor:pointer;transition:background .15s;flex-shrink:0}.prompt-bar button:hover{background:var(--bg-hover)}.prompt-bar button.primary{background:var(--brand-2);border-color:var(--brand-2);color:#fff;font-weight:600}.prompt-bar button.primary:hover{background:var(--brand-1);border-color:var(--brand-1)}.prompt-bar button.danger{border-color:var(--red);color:var(--red)}.prompt-bar button:disabled{opacity:.5;cursor:not-allowed}.tab-bar{display:flex;align-items:stretch;gap:0;border-bottom:1px solid var(--border);padding:0 16px;height:var(--topbar-height);flex-shrink:0}.tab-btn{display:flex;align-items:center;padding:0 16px;border:none;background:none;color:var(--text-subtle);font-size:13px;font-family:var(--font-mono);cursor:pointer;border-bottom:2px solid transparent;transition:color .15s,border-color .15s;margin-bottom:-1px}.tab-btn:hover{color:var(--text-muted)}.tab-bar-toggle{display:flex;align-items:center;justify-content:center;margin-left:auto;padding:6px 8px;border:none;background:none;color:var(--text-subtle);cursor:pointer;border-radius:4px}.tab-bar-toggle:hover{color:var(--text);background:var(--bg-hover)}.tab-btn.active{color:var(--brand-1);border-bottom-color:var(--brand-1)}.status-badge{display:inline-block;font-size:11px;padding:1px 8px;border-radius:10px;font-family:var(--font-mono);line-height:1.6}.status-badge-running{background:var(--cyan);color:var(--bg)}.status-badge-complete{background:var(--green);color:var(--bg)}.status-badge-error{background:var(--red);color:var(--bg)}.status-badge-cancelled{background:var(--text-subtle);color:var(--bg)}.settings-panel{margin:4px 0;padding:8px 0 8px 16px;border-left:2px solid var(--brand-2)}.settings-header{display:flex;align-items:center;gap:8px;margin-bottom:6px}.settings-title{font-family:var(--font-mono);font-size:13px;font-weight:600;color:var(--brand-1)}.settings-status{font-family:var(--font-mono);font-size:11px;padding:1px 6px;border-radius:8px}.settings-status.active{color:var(--green);border:1px solid var(--green)}.settings-status.missing{color:var(--yellow);border:1px solid var(--yellow)}.settings-field label{display:block;font-family:var(--font-mono);font-size:12px;color:var(--text-muted);margin-bottom:4px}.settings-input-row{display:flex;gap:6px}.settings-input-row input{flex:1;padding:4px 8px;background:var(--bg-surface);border:1px solid var(--border);border-radius:4px;color:var(--text);font-family:var(--font-mono);font-size:12px}.settings-input-row input:focus{outline:none;border-color:var(--brand-2)}.settings-input-row button{padding:4px 12px;border-radius:4px;border:1px solid var(--border);background:var(--bg-surface);color:var(--text-muted);font-family:var(--font-mono);font-size:12px;cursor:pointer;transition:background .15s}.settings-input-row button.primary{background:transparent;border-color:var(--brand-3);color:var(--brand-1);font-weight:600}.settings-input-row button.primary:hover{background:var(--brand-2);border-color:var(--brand-2)}.settings-input-row button:disabled{opacity:.5;cursor:not-allowed}.settings-divider{border-top:1px solid var(--border);margin:16px 0 12px}.settings-section-label{font-family:var(--font-mono);font-size:11px;color:var(--text-subtle);text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px}.settings-error{font-family:var(--font-mono);font-size:12px;color:var(--red);margin-top:4px}.skeleton{background:linear-gradient(90deg,var(--bg-surface) 25%,var(--bg-hover) 50%,var(--bg-surface) 75%);background-size:200% 100%;animation:skeleton-shimmer 1.5s ease-in-out infinite;border-radius:4px}@keyframes skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.skeleton-line{height:14px;margin-bottom:8px}.skeleton-block{height:60px;margin-bottom:8px}.session-avatar{width:32px;height:32px;margin:4px;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;font-family:var(--font-mono);letter-spacing:.5px;border-radius:50%;background:var(--bg-hover);color:var(--text);box-shadow:0 0 0 2px transparent,0 0 0 4px transparent}.session-avatar-running{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 4px var(--cyan)}.session-avatar-complete{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 4px var(--green)}.session-avatar-error{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 4px var(--red)}.session-avatar-cancelled{box-shadow:0 0 0 2px var(--bg-surface),0 0 0 4px var(--text-subtle)}.session-item-pending{opacity:.5;pointer-events:none}.session-avatar-pending{background:var(--border);color:transparent;animation:pulse-fade 1.5s ease-in-out infinite}@keyframes pulse-fade{0%,to{opacity:.4}50%{opacity:.8}}.new-project-avatar{background:transparent;outline:1.5px dashed var(--text-subtle);outline-offset:-1.5px;color:var(--text-subtle);font-size:16px;font-weight:400}.session-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:6px;cursor:pointer;transition:background .1s,gap .2s ease;margin-bottom:1px;height:48px;box-sizing:border-box;overflow:hidden}.session-item:hover,.session-item.active{background:var(--bg-hover)}.session-item-details{flex:1;min-width:0;overflow:hidden;opacity:1;transition:opacity .15s ease,width .2s ease}.session-item-name{font-size:13px;font-weight:500;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.session-item-meta{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--text-subtle)}.session-item-delete{opacity:0;padding:4px 6px;border:none;background:none;color:var(--text-subtle);font-size:22px;cursor:pointer;border-radius:4px;line-height:1;flex-shrink:0;overflow:hidden;transition:color .1s,opacity .1s,width .2s ease}.session-item:hover .session-item-delete{opacity:1}.session-item-delete:hover{color:var(--red)}.modal-overlay{position:fixed;inset:0;background:#0009;display:flex;align-items:center;justify-content:center;z-index:100}.modal-card{background:var(--bg-surface);border:1px solid var(--border);border-radius:12px;padding:24px;max-width:400px;width:90%}.modal-title{font-size:16px;font-weight:600;color:var(--text);margin-bottom:8px}.modal-body{font-size:14px;color:var(--text-muted);line-height:1.6;margin-bottom:20px}.modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}.modal-btn{padding:8px 16px;border-radius:6px;border:1px solid var(--border);background:var(--bg-hover);color:var(--text);font-size:13px;font-family:var(--font-sans);cursor:pointer;transition:background .15s}.modal-btn:hover{background:var(--border)}.modal-btn-danger{background:var(--red);border-color:var(--red);color:#fff;font-weight:600}.modal-btn-danger:hover{background:#d63a33;border-color:#d63a33}.toast-container{font-family:var(--font-mono);font-size:13px}.git-status-badge{display:inline-flex;align-items:center;gap:4px;font-family:var(--font-mono);font-size:11px;padding:2px 8px;border-radius:10px;border:1px solid var(--border);color:var(--text-subtle);cursor:default}.git-status-badge:before{content:"";width:6px;height:6px;border-radius:50%;background:var(--green);flex-shrink:0}.repo-picker-filter{margin-top:12px}.repo-picker-filter input{width:100%;box-sizing:border-box;padding:8px 12px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-family:var(--font-mono);font-size:13px}.repo-picker-filter input:focus{outline:none;border-color:var(--brand-2)}.repo-picker-filter input::placeholder{color:var(--text-subtle)}.repo-picker-list{max-height:300px;overflow-y:auto;margin-top:12px;border:1px solid var(--border);border-radius:6px}.repo-picker-item{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;font-size:13px;font-family:var(--font-mono);cursor:pointer;border-bottom:1px solid var(--border);transition:background .1s}.repo-picker-item:last-child{border-bottom:none}.repo-picker-item:hover{background:var(--bg-hover);color:var(--text)}.repo-picker-item-name{color:var(--text-muted)}.repo-picker-item-date{font-size:11px;color:var(--text-subtle)}.repo-picker-new-branch{display:flex;gap:8px;padding:8px 12px;align-items:center}.repo-picker-new-branch input{flex:1;padding:6px 10px;background:var(--bg);border:1px solid var(--border);border-radius:6px;color:var(--text);font-family:var(--font-mono);font-size:13px}.repo-picker-new-branch input:focus{outline:none;border-color:var(--brand-2)}.repo-picker-new-branch input::placeholder{color:var(--text-subtle)}.hero-resume-btn{margin-top:12px;padding:8px 20px;border-radius:6px;border:1px solid var(--border);background:transparent;color:var(--text-muted);font-size:13px;cursor:pointer;transition:background .15s,color .15s}.hero-resume-btn:hover{background:var(--bg-hover);color:var(--text)}.hero-resume-btn:disabled{opacity:.5;cursor:not-allowed}.modal-btn-primary{background:var(--brand-3);border-color:var(--brand-3);color:#fff}.modal-btn-primary:hover{background:var(--brand-2)}.modal-btn-primary:disabled{opacity:.5;cursor:not-allowed}.font-size-options{display:flex;gap:6px}.font-size-option{flex:1;padding:8px 12px;border-radius:6px;border:1px solid var(--border);background:var(--bg);color:var(--text-muted);font-family:var(--font-sans);font-size:13px;cursor:pointer;transition:background .15s,border-color .15s,color .15s}.font-size-option:hover{background:var(--bg-hover);color:var(--text)}.font-size-option.active{border-color:var(--brand-3);color:var(--brand-1);background:#7e78db1a}@media(max-width:768px){.app-shell{grid-template-columns:1fr}.sidebar{position:fixed;top:0;left:0;bottom:0;width:280px;z-index:200;transform:translate(-100%);transition:transform .25s ease}.sidebar.mobile-open{transform:translate(0)}.sidebar-backdrop{display:block;position:fixed;inset:0;background:#00000080;z-index:199}.sidebar-collapse{display:none}.app-shell.sidebar-collapsed .sidebar-brand,.app-shell.sidebar-collapsed .sidebar-section-label{display:block}.app-shell.sidebar-collapsed .session-item{gap:8px}.app-shell.sidebar-collapsed .session-item-details,.app-shell.sidebar-collapsed .session-item-delete,.app-shell.sidebar-collapsed .session-item:hover .session-item-delete{opacity:1;width:auto;overflow:visible;pointer-events:auto}.app-shell.sidebar-collapsed .sidebar-collapse-label{opacity:1;max-width:120px;display:inline}.mobile-hamburger{display:flex;align-items:center;justify-content:center;width:42px;height:42px;border:none;background:none;color:var(--text-muted);cursor:pointer;border-radius:6px;flex-shrink:0;-webkit-tap-highlight-color:transparent}.mobile-hamburger:hover{color:var(--text);background:var(--bg-hover)}.session-header{padding:0 8px;gap:6px}.session-header-name{font-size:14px;min-width:0;flex:1}.session-header .session-header-cost,.session-header .session-header-actions-group{display:none}.session-header-overflow{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;background:none;color:var(--text-muted);cursor:pointer;border-radius:6px;flex-shrink:0;-webkit-tap-highlight-color:transparent}.session-header-overflow:hover{color:var(--text);background:var(--bg-hover)}.session-header-overflow-menu{position:absolute;top:calc(var(--topbar-height) - 4px);right:8px;background:var(--bg-surface);border:1px solid var(--border);border-radius:8px;padding:6px;z-index:100;min-width:180px;box-shadow:0 8px 24px #0006}.session-header-overflow-menu-item{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;border:none;background:none;color:var(--text-muted);font-size:14px;font-family:var(--font-mono);cursor:pointer;border-radius:6px;text-decoration:none;-webkit-tap-highlight-color:transparent}.session-header-overflow-menu-item:hover{background:var(--bg-hover);color:var(--text)}.mobile-preview-bar{display:flex;align-items:center;justify-content:center;padding:8px 12px;background:var(--bg-surface);border-bottom:1px solid var(--border);flex-shrink:0}.mobile-preview-link{display:inline-flex;align-items:center;gap:6px;padding:10px 20px;font-size:14px;font-family:var(--font-mono);color:var(--brand-1);background:transparent;border:1px solid var(--brand-3);border-radius:8px;text-decoration:none;-webkit-tap-highlight-color:transparent;transition:color .15s,background .15s,border-color .15s}.mobile-preview-link:hover{background:var(--brand-2);border-color:var(--brand-2);color:#fff}.console{padding:8px}.tool-inline-summary,.thinking-preview{max-width:200px}.tool-inline-command{max-width:200px;overflow:hidden;text-overflow:ellipsis}.tool-inline-body{padding:6px 0 6px 10px;margin-left:4px}.tool-inline-body pre{max-height:250px}.prompt-bar{padding:6px 8px;gap:6px;height:auto;min-height:var(--footer-height)}.prompt-bar textarea{padding:10px 12px;min-height:42px;font-size:16px}.prompt-bar button{padding:8px 14px;min-height:40px;font-size:14px}.mobile-home-topbar{display:flex;align-items:center;padding:6px 10px;height:52px;flex-shrink:0;border-bottom:1px solid var(--border);gap:8px}.mobile-topbar-logo{height:26px}.hero{padding:0 16px;justify-content:flex-start;padding-top:8vh}.hero-logo{height:48px;margin-bottom:12px}.hero-subtitle{font-size:15px;margin-bottom:24px;white-space:nowrap}.hero-prompt{max-width:100%}.hero-prompt .prompt-bar{border-radius:12px}.hero-prompt .prompt-bar textarea{min-height:48px;font-size:16px;padding:12px}.hero-prompt .prompt-bar button{min-height:48px;padding:8px 18px;font-size:15px;border-radius:0 11px 11px 0}.hero-resume-btn{width:100%;padding:12px 20px;font-size:15px}.gate-prompt{padding:12px}.gate-prompt .question input,.gate-prompt .question textarea,.gate-prompt .question select{font-size:15px;padding:10px 12px}.gate-actions{flex-direction:column}.gate-actions .gate-btn{width:100%;padding:10px 16px;text-align:center}.gate-plan-actions{flex-wrap:wrap}.gate-plan-actions .gate-btn{flex:1;min-width:0;padding:10px 12px;text-align:center}.gate-btn kbd{display:none}.gate-continue{flex-wrap:wrap;gap:8px;padding:10px 12px}.gate-continue-text{width:100%;flex:none}.gate-continue .gate-btn{flex:1;text-align:center;padding:8px 12px}.gate-option-group{flex-direction:column}.gate-option{padding:12px}.modal-card{width:95%;max-width:none;max-height:90vh;overflow-y:auto;border-radius:14px}.modal-actions{flex-direction:column-reverse}.modal-actions .modal-btn{width:100%;text-align:center;padding:10px 16px}.settings-input-row{flex-direction:column;gap:8px}.settings-input-row input{font-size:15px;padding:10px 12px}.settings-input-row button{width:100%;padding:8px 12px;text-align:center}.repo-picker-item{padding:14px;min-height:48px}.repo-picker-new-branch{flex-direction:column}.repo-picker-new-branch input{font-size:14px;padding:10px 12px}.global-settings-btn{top:8px;right:8px;width:40px;height:40px}.global-settings-btn svg{width:20px;height:20px}.jump-to-bottom{padding:10px 20px;font-size:13px}.action-item-summary{max-width:150px}.action-item-detail{padding:8px 12px 8px 24px}.markdown pre{padding:10px 12px;font-size:12px}.markdown table{display:block;overflow-x:auto}}@media(min-width:769px){.mobile-hamburger,.mobile-home-topbar,.sidebar-backdrop,.session-header-overflow,.session-header-overflow-menu,.mobile-preview-bar,.mobile-topbar-logo{display:none}}
|